@flexiui/svelte-rich-text 0.0.32 → 0.0.34
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/dist/RichText.svelte
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { TableKit } from "@tiptap/extension-table";
|
|
5
5
|
import { CellSelection } from "prosemirror-tables";
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
import { NodeLineHeight } from "./extensions/NodeLineHeight";
|
|
8
8
|
import { MediaGridExtension } from "./extensions/MediaGrid/MediaGrid";
|
|
9
9
|
import { MediaGridItemExtension } from "./extensions/MediaGrid/MediaGridItem";
|
|
10
10
|
import {
|
|
@@ -50,6 +50,21 @@
|
|
|
50
50
|
onSelectionUpdate?: (params: any) => void;
|
|
51
51
|
onPaste?: (params: any) => void;
|
|
52
52
|
};
|
|
53
|
+
config?: {
|
|
54
|
+
editorBgColor?: string;
|
|
55
|
+
editorRadius?: string;
|
|
56
|
+
toolbarStickyPosition?: number;
|
|
57
|
+
toolbarZIndex?: number;
|
|
58
|
+
toolbarBgColor?: string;
|
|
59
|
+
toolbarPadding?: string;
|
|
60
|
+
toolbarGap?: string;
|
|
61
|
+
docMaxWidth?: string;
|
|
62
|
+
docPadding?: string;
|
|
63
|
+
docBg?: string;
|
|
64
|
+
docMarginInline?: string;
|
|
65
|
+
docMarginBlock?: string;
|
|
66
|
+
docRadius?: string;
|
|
67
|
+
};
|
|
53
68
|
}
|
|
54
69
|
|
|
55
70
|
let {
|
|
@@ -72,9 +87,30 @@
|
|
|
72
87
|
onSelectionUpdate: () => {},
|
|
73
88
|
onPaste: () => {},
|
|
74
89
|
},
|
|
90
|
+
config,
|
|
75
91
|
}: Props = $props();
|
|
76
92
|
|
|
77
93
|
let editor = $state() as Readable<Editor>;
|
|
94
|
+
const defaultEditorConfig = {
|
|
95
|
+
editorBgColor: "transparent",
|
|
96
|
+
editorRadius: "12px",
|
|
97
|
+
toolbarStickyPosition: 0,
|
|
98
|
+
toolbarBgColor: "#242424",
|
|
99
|
+
toolbarZIndex: 10,
|
|
100
|
+
toolbarPadding: "8px",
|
|
101
|
+
toolbarGap: "5px",
|
|
102
|
+
docMaxWidth: "1024px",
|
|
103
|
+
docPadding: "2rem",
|
|
104
|
+
docBg: "transparent",
|
|
105
|
+
docMarginInline: "auto",
|
|
106
|
+
docMarginBlock: "2rem",
|
|
107
|
+
docRadius: "0",
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
let editorConfig = $state({
|
|
111
|
+
...defaultEditorConfig,
|
|
112
|
+
...(config ?? {}),
|
|
113
|
+
});
|
|
78
114
|
|
|
79
115
|
const extensions = [
|
|
80
116
|
// Color.configure({ types: [TextStyle.name, ListItem.name] }),
|
|
@@ -244,61 +280,67 @@
|
|
|
244
280
|
onMount(() => {
|
|
245
281
|
editor = createEditor({
|
|
246
282
|
extensions,
|
|
247
|
-
content
|
|
283
|
+
content:
|
|
284
|
+
'<h2 style="line-height: 1;"><span style="font-size: 22px;">Aquí tens algunes expressions bàsiques en català. Llegeix-les, escolta-les i repeteix-les.</span></h2><table class="fl-table-editable" style="min-width: 75px;"><colgroup><col style="min-width: 25px;"><col style="min-width: 25px;"><col style="min-width: 25px;"></colgroup><tbody><tr><th class="fl-cell-editable" colspan="1" rowspan="1"><p></p></th><th class="fl-cell-editable" colspan="1" rowspan="1"><p></p></th><th class="fl-cell-editable" colspan="1" rowspan="1"><p></p></th></tr><tr><td class="fl-cell-editable" colspan="1" rowspan="1"><p></p></td><td class="fl-cell-editable" colspan="1" rowspan="1"><p></p></td><td class="fl-cell-editable" colspan="1" rowspan="1"><p></p></td></tr><tr><td class="fl-cell-editable" colspan="1" rowspan="1"><p></p></td><td class="fl-cell-editable" colspan="1" rowspan="1"><p></p></td><td class="fl-cell-editable" colspan="1" rowspan="1"><p></p></td></tr></tbody></table><ul><li><p style="line-height: 1.5;">Hola!</p></li><li><p style="line-height: 1.5;">Com estàs?</p></li><li><p style="line-height: 1.5;">Com et dius?</p></li><li><p style="line-height: 1.5;">Com es diu agua en català?</p></li><li><p style="line-height: 1.5;">Què vol dir rentadora?</p></li><li><p style="line-height: 1.5;">Com s\'escriu bolígraf?</p></li><li><p style="line-height: 1.5;">Com es pronuncia aquesta paraula?</p></li><li><p style="line-height: 1.5;">M\'ho pots repetir, si us plau?</p></li><li><p style="line-height: 1.5;">A poc a poc, si us plau.</p></li><li><p style="line-height: 1.5;">Com?</p></li><li><p style="line-height: 1.5;">No t\'entenc.</p></li><li><p style="line-height: 1.5;">Gràcies.</p></li><li><p style="line-height: 1.5;">De res.</p></li><li><p style="line-height: 1.5;">Perdona.</p></li><li><p style="line-height: 1.5;">I tant!</p></li><li><p style="line-height: 1.5;">Edited</p></li></ul><pre><code>const name = "Alex";\nconsole.log(`Hello ${name}`)</code></pre><media-grid-component class="fl-media-grid" data-cols="3" data-gap="1.5rem" data-show-indicator="false" data-indicator-type="numeric"><div data-type="grid-item" class="fl-grid-item"><img src="https://img2.rtve.es/n/16848600?w=1600"></div><div data-type="grid-item" class="fl-grid-item"><img src="https://img2.rtve.es/n/16848600?w=1600"></div><div data-type="grid-item" class="fl-grid-item"><img src="https://img2.rtve.es/n/16848600?w=1600"></div></media-grid-component><audio-player class="audio-player" src="https://pub-503cb197f1134814ac02f257b9cde1c1.r2.dev/uploads/audio-festa-major.mp3" controls="true" data-color-play="#333" data-color-bar="#888" data-max-width="100%" data-id="fl-audio-4i336em9v43"></audio-player><blockquote><p>- Hola! Com estàs?<br>- Molt bé, i tu?</p></blockquote><audio-player class="audio-player" src="https://pub-503cb197f1134814ac02f257b9cde1c1.r2.dev/uploads/dictat-buscar-habitatge.mp3" controls="true" data-color-play="#333" data-color-bar="#888" data-max-width="100%" data-id="fl-audio-4i336em9v43"></audio-player><blockquote><p>- Com et dius?<br>- Em dic Sara, i tu?</p></blockquote><audio-player class="audio-player" src="https://pub-503cb197f1134814ac02f257b9cde1c1.r2.dev/uploads/dictat-buscar-habitatge.mp3" controls="true" data-color-play="#333" data-color-bar="#888" data-max-width="100%" data-id="fl-audio-4i336em9v43"></audio-player><blockquote><p>Com es diu mesa en català?</p></blockquote><audio-player class="audio-player" src="https://pub-503cb197f1134814ac02f257b9cde1c1.r2.dev/uploads/dictat-buscar-habitatge.mp3" controls="true" data-color-play="#333" data-color-bar="#888" data-max-width="100%" data-id="fl-audio-4i336em9v43"></audio-player><blockquote><p>Què vol dir rentadora?</p></blockquote><audio-player class="audio-player" src="https://pub-503cb197f1134814ac02f257b9cde1c1.r2.dev/uploads/dictat-buscar-habitatge.mp3" controls="true" data-color-play="#333" data-color-bar="#888" data-max-width="100%" data-id="fl-audio-4i336em9v43"></audio-player><blockquote><p>Com s\'escriu bolígraf?</p></blockquote><audio-player class="audio-player" src="https://pub-503cb197f1134814ac02f257b9cde1c1.r2.dev/uploads/dictat-buscar-habitatge.mp3" controls="true" data-color-play="#333" data-color-bar="#888" data-max-width="100%" data-id="fl-audio-4i336em9v43"></audio-player><blockquote><p>Com es pronuncia això?</p></blockquote><audio-player class="audio-player" src="https://pub-503cb197f1134814ac02f257b9cde1c1.r2.dev/uploads/dictat-buscar-habitatge.mp3" controls="true" data-color-play="#333" data-color-bar="#888" data-max-width="100%" data-id="fl-audio-4i336em9v43"></audio-player><blockquote><p>- No t\'entenc. A poc a poc, si us plau.<br>- Ostres, perdona.</p></blockquote><audio-player class="audio-player" src="https://pub-503cb197f1134814ac02f257b9cde1c1.r2.dev/uploads/dictat-buscar-habitatge.mp3" controls="true" data-color-play="#333" data-color-bar="#888" data-max-width="100%" data-id="fl-audio-4i336em9v43"></audio-player><blockquote><p>- Com? M\'ho pots repetir, si us plau?<br>- Sí, i tant!</p></blockquote><audio-player class="audio-player" src="https://pub-503cb197f1134814ac02f257b9cde1c1.r2.dev/uploads/dictat-buscar-habitatge.mp3" controls="true" data-color-play="#333" data-color-bar="#888" data-max-width="100%" data-id="fl-audio-4i336em9v43"></audio-player><blockquote><p>- Gràcies.<br>- De res!</p></blockquote>',
|
|
248
285
|
editorProps: {
|
|
249
286
|
attributes: {
|
|
250
|
-
class: "fl-rich-text-content-
|
|
287
|
+
class: "fl-rich-text-content-doc",
|
|
251
288
|
},
|
|
252
289
|
handleKeyDown: (view, event) => {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
290
|
+
if (event.key === "Enter" && !event.ctrlKey) {
|
|
291
|
+
enterPressed = true;
|
|
292
|
+
|
|
293
|
+
setTimeout(() => {
|
|
294
|
+
enterPressed = false;
|
|
295
|
+
const { from } = view.state.selection;
|
|
296
|
+
|
|
297
|
+
// Obtener el nodo de ProseMirror en la posición actual
|
|
298
|
+
const pos = view.state.doc.resolve(from);
|
|
299
|
+
const nodeBefore = pos.node(pos.depth);
|
|
300
|
+
const parentNode = pos.node(pos.depth - 1);
|
|
301
|
+
|
|
302
|
+
// console.log("Node type:", nodeBefore.type.name);
|
|
303
|
+
// console.log("Parent node type:", parentNode?.type.name);
|
|
304
|
+
|
|
305
|
+
// Solo ejecutar si estamos en un párrafo Y el padre no es una lista
|
|
306
|
+
const isInList =
|
|
307
|
+
parentNode?.type.name === "listItem" ||
|
|
308
|
+
parentNode?.type.name === "bulletList" ||
|
|
309
|
+
parentNode?.type.name === "orderedList";
|
|
310
|
+
|
|
311
|
+
if (nodeBefore.type.name === "paragraph" && !isInList) {
|
|
312
|
+
const domAtPos = view.domAtPos(from);
|
|
313
|
+
let element = domAtPos.node;
|
|
314
|
+
|
|
315
|
+
if (element.nodeType === Node.TEXT_NODE) {
|
|
316
|
+
element = element.parentElement;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (element instanceof HTMLElement) {
|
|
320
|
+
const computedSize =
|
|
321
|
+
window.getComputedStyle(element).fontSize;
|
|
322
|
+
const computedLineHeight =
|
|
323
|
+
window.getComputedStyle(element).lineHeight;
|
|
324
|
+
// console.log({ computedSize, computedLineHeight });
|
|
325
|
+
|
|
326
|
+
const lineHeightPx = parseFloat(
|
|
327
|
+
computedLineHeight.replace("px", "")
|
|
328
|
+
);
|
|
329
|
+
const fontSizePx = parseFloat(computedSize.replace("px", ""));
|
|
330
|
+
|
|
331
|
+
const lineHeightUnitless = lineHeightPx / fontSizePx;
|
|
332
|
+
|
|
333
|
+
// console.log(lineHeightUnitless.toFixed(2)); // ej: "x.xx"
|
|
334
|
+
|
|
335
|
+
fontSize = Math.round(Number(computedSize.replace("px", "")));
|
|
336
|
+
$editor.chain().focus().unsetFontSize().run();
|
|
337
|
+
|
|
338
|
+
$editor.chain().focus().unsetNodeLineHeight().run();
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}, 200);
|
|
342
|
+
}
|
|
343
|
+
},
|
|
302
344
|
},
|
|
303
345
|
onTransaction: ({ editor, transaction }) => {
|
|
304
346
|
editorEvents.onTransaction({ editor, transaction });
|
|
@@ -323,11 +365,12 @@
|
|
|
323
365
|
// Obtener el font-size computado
|
|
324
366
|
if (element instanceof HTMLElement) {
|
|
325
367
|
const computedSize = window.getComputedStyle(element).fontSize;
|
|
326
|
-
const computedLineHeight =
|
|
368
|
+
const computedLineHeight =
|
|
369
|
+
window.getComputedStyle(element).lineHeight;
|
|
327
370
|
// console.log("Get element font size:", computedSize);
|
|
328
371
|
// console.log("Get element line height:", computedLineHeight);
|
|
329
|
-
const lineHeightPx = parseFloat(computedLineHeight.replace("px", ""))
|
|
330
|
-
const fontSizePx = parseFloat(computedSize.replace("px", ""))
|
|
372
|
+
const lineHeightPx = parseFloat(computedLineHeight.replace("px", ""));
|
|
373
|
+
const fontSizePx = parseFloat(computedSize.replace("px", ""));
|
|
331
374
|
const lineHeightUnitless = lineHeightPx / fontSizePx;
|
|
332
375
|
|
|
333
376
|
// console.log(lineHeightUnitless.toFixed(2)); // ej: "x.xx"
|
|
@@ -349,8 +392,6 @@
|
|
|
349
392
|
} else {
|
|
350
393
|
lineHeight = Number(lineHeightUnitless.toFixed(2));
|
|
351
394
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
395
|
}
|
|
355
396
|
},
|
|
356
397
|
|
|
@@ -499,9 +540,7 @@
|
|
|
499
540
|
}
|
|
500
541
|
|
|
501
542
|
function handleRangeInput(e: any) {
|
|
502
|
-
|
|
503
|
-
$editor.commands.setNodeLineHeight(lineHeight.toString())
|
|
504
|
-
|
|
543
|
+
$editor.commands.setNodeLineHeight(lineHeight.toString());
|
|
505
544
|
}
|
|
506
545
|
|
|
507
546
|
function addAudio() {
|
|
@@ -511,37 +550,54 @@
|
|
|
511
550
|
alert("Please enter a valid URL");
|
|
512
551
|
return;
|
|
513
552
|
}
|
|
514
|
-
|
|
515
|
-
$editor.chain().focus().setAudio({ src, controls: true }).run()
|
|
516
|
-
|
|
553
|
+
|
|
554
|
+
$editor.chain().focus().setAudio({ src, controls: true }).run();
|
|
517
555
|
}
|
|
518
556
|
|
|
519
557
|
function addImage() {
|
|
520
|
-
const previousSrc = $editor.getAttributes("image").src;
|
|
558
|
+
const previousSrc = $editor.getAttributes("image").src;
|
|
521
559
|
const src = window.prompt("Enter the URL of the image:", previousSrc);
|
|
522
560
|
|
|
523
561
|
if (!src) {
|
|
524
562
|
alert("Please enter a valid URL");
|
|
525
563
|
return;
|
|
526
564
|
}
|
|
527
|
-
|
|
528
|
-
$editor.chain().focus().setImage({ src }).run()
|
|
529
|
-
|
|
565
|
+
|
|
566
|
+
$editor.chain().focus().setImage({ src }).run();
|
|
530
567
|
}
|
|
531
568
|
|
|
532
569
|
function addMediaGrid() {
|
|
533
|
-
|
|
534
|
-
$editor.chain().focus().insertGrid({ cols: 2 }).run()
|
|
535
|
-
|
|
570
|
+
$editor.chain().focus().insertGrid({ cols: 2 }).run();
|
|
536
571
|
}
|
|
537
572
|
|
|
538
|
-
function addTable(){
|
|
539
|
-
$editor
|
|
573
|
+
function addTable() {
|
|
574
|
+
$editor
|
|
575
|
+
.chain()
|
|
576
|
+
.focus()
|
|
577
|
+
.insertTable({ rows: 3, cols: 3, withHeaderRow: true })
|
|
578
|
+
.run();
|
|
540
579
|
}
|
|
541
580
|
</script>
|
|
542
581
|
|
|
543
|
-
<div
|
|
544
|
-
|
|
582
|
+
<div
|
|
583
|
+
class="fl-rich-text {className}"
|
|
584
|
+
class:editable
|
|
585
|
+
style="
|
|
586
|
+
--fl-editor-radius: {editorConfig.editorRadius};
|
|
587
|
+
--fl-editor-bg: {editorConfig.editorBgColor};
|
|
588
|
+
--fl-toolbar-sticky-position: {editorConfig.toolbarStickyPosition}px;
|
|
589
|
+
--fl-toolbar-z-index: {editorConfig.toolbarZIndex};
|
|
590
|
+
--fl-toolbar-padding: {editorConfig.toolbarPadding};
|
|
591
|
+
--fl-toolbar-gap: {editorConfig.toolbarGap};
|
|
592
|
+
--fl-toolbar-bg: {editorConfig.toolbarBgColor};
|
|
593
|
+
--fl-doc-max-width: {editorConfig.docMaxWidth};
|
|
594
|
+
--fl-doc-padding: {editorConfig.docPadding};
|
|
595
|
+
--fl-doc-bg: {editorConfig.docBg};
|
|
596
|
+
--fl-doc-margin-inline: {editorConfig.docMarginInline};
|
|
597
|
+
--fl-doc-margin-block: {editorConfig.docMarginBlock};
|
|
598
|
+
--fl-doc-radius: {editorConfig.docRadius};
|
|
599
|
+
"
|
|
600
|
+
>
|
|
545
601
|
{#if editor}
|
|
546
602
|
<header class="fl-rich-text-toolbar">
|
|
547
603
|
<!-- Undo/Redo -->
|
|
@@ -871,35 +927,80 @@
|
|
|
871
927
|
<!-- Font size editor -->
|
|
872
928
|
<div role="group" class="fl-rich-text-toolbar-group">
|
|
873
929
|
<div class="fl-font-size-editor">
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
930
|
+
<button
|
|
931
|
+
type="button"
|
|
932
|
+
aria-label="Decrease font size"
|
|
933
|
+
onclick={decrementFontSize}
|
|
934
|
+
class="fl-font-size-editor-button"
|
|
935
|
+
>
|
|
936
|
+
<svg
|
|
937
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
938
|
+
width="24"
|
|
939
|
+
height="24"
|
|
940
|
+
viewBox="0 0 24 24"
|
|
941
|
+
fill="none"
|
|
942
|
+
stroke="currentColor"
|
|
943
|
+
stroke-width="2"
|
|
944
|
+
stroke-linecap="round"
|
|
945
|
+
stroke-linejoin="round"
|
|
946
|
+
class="icon icon-tabler icons-tabler-outline icon-tabler-minus"
|
|
947
|
+
><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path
|
|
948
|
+
d="M5 12l14 0"
|
|
949
|
+
/></svg
|
|
881
950
|
>
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
951
|
+
</button>
|
|
952
|
+
<input type="text" bind:value={fontSize} />
|
|
953
|
+
<button
|
|
954
|
+
type="button"
|
|
955
|
+
aria-label="Increase font size"
|
|
956
|
+
onclick={incrementFontSize}
|
|
957
|
+
class="fl-font-size-editor-button"
|
|
958
|
+
>
|
|
959
|
+
<svg
|
|
960
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
961
|
+
width="24"
|
|
962
|
+
height="24"
|
|
963
|
+
viewBox="0 0 24 24"
|
|
964
|
+
fill="none"
|
|
965
|
+
stroke="currentColor"
|
|
966
|
+
stroke-width="2"
|
|
967
|
+
stroke-linecap="round"
|
|
968
|
+
stroke-linejoin="round"
|
|
969
|
+
class="icon icon-tabler icons-tabler-outline icon-tabler-plus"
|
|
970
|
+
><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path
|
|
971
|
+
d="M12 5l0 14"
|
|
972
|
+
/><path d="M5 12l14 0" /></svg
|
|
890
973
|
>
|
|
974
|
+
</button>
|
|
891
975
|
</div>
|
|
892
976
|
</div>
|
|
893
977
|
|
|
894
978
|
<!-- Line height -->
|
|
895
979
|
<div role="group" class="fl-rich-text-toolbar-group">
|
|
896
|
-
<button
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
980
|
+
<button
|
|
981
|
+
class="fl-font-size-button"
|
|
982
|
+
aria-label="Line height"
|
|
983
|
+
type="button"
|
|
984
|
+
onclick={(e) =>
|
|
985
|
+
toogleDropdown(e.currentTarget, "line-height-dropdown")}
|
|
901
986
|
>
|
|
902
|
-
<svg
|
|
987
|
+
<svg
|
|
988
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
989
|
+
width="16"
|
|
990
|
+
height="16"
|
|
991
|
+
viewBox="0 0 24 24"
|
|
992
|
+
fill="none"
|
|
993
|
+
stroke="currentColor"
|
|
994
|
+
stroke-width="2"
|
|
995
|
+
stroke-linecap="round"
|
|
996
|
+
stroke-linejoin="round"
|
|
997
|
+
class="icon icon-tabler icons-tabler-outline icon-tabler-line-height"
|
|
998
|
+
><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path
|
|
999
|
+
d="M3 8l3 -3l3 3"
|
|
1000
|
+
/><path d="M3 16l3 3l3 -3" /><path d="M6 5l0 14" /><path
|
|
1001
|
+
d="M13 6l7 0"
|
|
1002
|
+
/><path d="M13 12l7 0" /><path d="M13 18l7 0" /></svg
|
|
1003
|
+
>
|
|
903
1004
|
|
|
904
1005
|
<svg
|
|
905
1006
|
class="toogle-dropdown-button-icon"
|
|
@@ -1224,7 +1325,17 @@
|
|
|
1224
1325
|
aria-label="Image"
|
|
1225
1326
|
class:is-active={$editor.isActive("image")}
|
|
1226
1327
|
>
|
|
1227
|
-
<svg
|
|
1328
|
+
<svg
|
|
1329
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
1330
|
+
width="24"
|
|
1331
|
+
height="24"
|
|
1332
|
+
viewBox="0 0 24 24"
|
|
1333
|
+
fill="currentColor"
|
|
1334
|
+
class="icon icon-tabler icons-tabler-filled icon-tabler-photo"
|
|
1335
|
+
><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path
|
|
1336
|
+
d="M8.813 11.612c.457 -.38 .918 -.38 1.386 .011l.108 .098l4.986 4.986l.094 .083a1 1 0 0 0 1.403 -1.403l-.083 -.094l-1.292 -1.293l.292 -.293l.106 -.095c.457 -.38 .918 -.38 1.386 .011l.108 .098l4.674 4.675a4 4 0 0 1 -3.775 3.599l-.206 .005h-12a4 4 0 0 1 -3.98 -3.603l6.687 -6.69l.106 -.095zm9.187 -9.612a4 4 0 0 1 3.995 3.8l.005 .2v9.585l-3.293 -3.292l-.15 -.137c-1.256 -1.095 -2.85 -1.097 -4.096 -.017l-.154 .14l-.307 .306l-2.293 -2.292l-.15 -.137c-1.256 -1.095 -2.85 -1.097 -4.096 -.017l-.154 .14l-5.307 5.306v-9.585a4 4 0 0 1 3.8 -3.995l.2 -.005h12zm-2.99 5l-.127 .007a1 1 0 0 0 0 1.986l.117 .007l.127 -.007a1 1 0 0 0 0 -1.986l-.117 -.007z"
|
|
1337
|
+
/></svg
|
|
1338
|
+
>
|
|
1228
1339
|
</button>
|
|
1229
1340
|
<!-- Audio -->
|
|
1230
1341
|
<button
|
|
@@ -1233,7 +1344,7 @@
|
|
|
1233
1344
|
aria-label="Audio"
|
|
1234
1345
|
class:is-active={$editor.isActive("audio")}
|
|
1235
1346
|
>
|
|
1236
|
-
|
|
1347
|
+
Audio
|
|
1237
1348
|
</button>
|
|
1238
1349
|
</div>
|
|
1239
1350
|
|
|
@@ -1246,7 +1357,23 @@
|
|
|
1246
1357
|
aria-label="Media grid"
|
|
1247
1358
|
class:is-active={$editor.isActive("MediaGridComponent")}
|
|
1248
1359
|
>
|
|
1249
|
-
<svg
|
|
1360
|
+
<svg
|
|
1361
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
1362
|
+
width="24"
|
|
1363
|
+
height="24"
|
|
1364
|
+
viewBox="0 0 24 24"
|
|
1365
|
+
fill="currentColor"
|
|
1366
|
+
class="icon icon-tabler icons-tabler-filled icon-tabler-layout-grid"
|
|
1367
|
+
><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path
|
|
1368
|
+
d="M9 3a2 2 0 0 1 2 2v4a2 2 0 0 1 -2 2h-4a2 2 0 0 1 -2 -2v-4a2 2 0 0 1 2 -2z"
|
|
1369
|
+
/><path
|
|
1370
|
+
d="M19 3a2 2 0 0 1 2 2v4a2 2 0 0 1 -2 2h-4a2 2 0 0 1 -2 -2v-4a2 2 0 0 1 2 -2z"
|
|
1371
|
+
/><path
|
|
1372
|
+
d="M9 13a2 2 0 0 1 2 2v4a2 2 0 0 1 -2 2h-4a2 2 0 0 1 -2 -2v-4a2 2 0 0 1 2 -2z"
|
|
1373
|
+
/><path
|
|
1374
|
+
d="M19 13a2 2 0 0 1 2 2v4a2 2 0 0 1 -2 2h-4a2 2 0 0 1 -2 -2v-4a2 2 0 0 1 2 -2z"
|
|
1375
|
+
/></svg
|
|
1376
|
+
>
|
|
1250
1377
|
</button>
|
|
1251
1378
|
<!-- Table -->
|
|
1252
1379
|
<button
|
|
@@ -1255,7 +1382,21 @@
|
|
|
1255
1382
|
aria-label="Table"
|
|
1256
1383
|
class:is-active={$editor.isActive("table")}
|
|
1257
1384
|
>
|
|
1258
|
-
<svg
|
|
1385
|
+
<svg
|
|
1386
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
1387
|
+
width="24"
|
|
1388
|
+
height="24"
|
|
1389
|
+
viewBox="0 0 24 24"
|
|
1390
|
+
fill="none"
|
|
1391
|
+
stroke="currentColor"
|
|
1392
|
+
stroke-width="2"
|
|
1393
|
+
stroke-linecap="round"
|
|
1394
|
+
stroke-linejoin="round"
|
|
1395
|
+
class="icon icon-tabler icons-tabler-outline icon-tabler-table"
|
|
1396
|
+
><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path
|
|
1397
|
+
d="M3 5a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v14a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-14"
|
|
1398
|
+
/><path d="M3 10h18" /><path d="M10 3v18" /></svg
|
|
1399
|
+
>
|
|
1259
1400
|
</button>
|
|
1260
1401
|
</div>
|
|
1261
1402
|
|
|
@@ -1906,12 +2047,18 @@
|
|
|
1906
2047
|
{/if}
|
|
1907
2048
|
</div>
|
|
1908
2049
|
{:else if activeDropdownType === "line-height-dropdown"}
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
2050
|
+
<div class="fl-range-element">
|
|
2051
|
+
<span class="fl-range-element-value">
|
|
2052
|
+
{lineHeight.toFixed(2)}
|
|
2053
|
+
</span>
|
|
2054
|
+
<input
|
|
2055
|
+
oninput={handleRangeInput}
|
|
2056
|
+
type="range"
|
|
2057
|
+
min="0.5"
|
|
2058
|
+
max="4"
|
|
2059
|
+
step="0.05"
|
|
2060
|
+
bind:value={lineHeight}
|
|
2061
|
+
/>
|
|
2062
|
+
</div>
|
|
1916
2063
|
{/if}
|
|
1917
2064
|
</div>
|
|
@@ -1,2 +1,19 @@
|
|
|
1
1
|
import { Node } from '@tiptap/core';
|
|
2
|
+
interface InsertGridOptions {
|
|
3
|
+
cols?: number;
|
|
4
|
+
}
|
|
5
|
+
declare module '@tiptap/core' {
|
|
6
|
+
interface Commands<ReturnType> {
|
|
7
|
+
MediaGridComponent: {
|
|
8
|
+
/**
|
|
9
|
+
* Añade un elemento de audio personalizado
|
|
10
|
+
* @example
|
|
11
|
+
* editor.commands.setAudio({ src: '/audio.mp3', controls: true })
|
|
12
|
+
*/
|
|
13
|
+
insertGrid: (options?: InsertGridOptions) => ReturnType;
|
|
14
|
+
addGridItem: () => ReturnType;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
2
18
|
export declare const MediaGridExtension: Node<any, any>;
|
|
19
|
+
export {};
|
|
@@ -19,43 +19,43 @@ export const MediaGridExtension = Node.create({
|
|
|
19
19
|
},
|
|
20
20
|
cols: {
|
|
21
21
|
default: 2,
|
|
22
|
-
parseHTML: element =>
|
|
22
|
+
parseHTML: element => {
|
|
23
|
+
return element.dataset.cols;
|
|
24
|
+
},
|
|
23
25
|
renderHTML: attrs => ({ 'data-cols': attrs.cols }),
|
|
24
26
|
},
|
|
25
27
|
gap: {
|
|
26
28
|
default: '1rem',
|
|
27
|
-
parseHTML: element => element.
|
|
29
|
+
parseHTML: element => element.dataset.gap,
|
|
28
30
|
renderHTML: attrs => ({ 'data-gap': attrs.gap }),
|
|
29
31
|
},
|
|
30
32
|
showIndicator: {
|
|
31
33
|
default: false,
|
|
32
|
-
parseHTML: element => element.
|
|
34
|
+
parseHTML: element => element.dataset.showIndicator,
|
|
33
35
|
renderHTML: attrs => ({ 'data-show-indicator': attrs.showIndicator }),
|
|
34
36
|
},
|
|
35
37
|
indicatorType: {
|
|
36
38
|
default: 'numeric', // 'numeric' | 'alphabetic'
|
|
37
|
-
parseHTML: element => element.
|
|
39
|
+
parseHTML: element => element.dataset.indicatorType,
|
|
38
40
|
renderHTML: attrs => ({ 'data-indicator-type': attrs.indicatorType }),
|
|
39
41
|
}
|
|
40
42
|
};
|
|
41
43
|
},
|
|
42
44
|
parseHTML() {
|
|
43
|
-
return [
|
|
45
|
+
return [
|
|
46
|
+
{
|
|
47
|
+
tag: 'media-grid-component',
|
|
48
|
+
}
|
|
49
|
+
];
|
|
44
50
|
},
|
|
45
51
|
renderHTML({ HTMLAttributes }) {
|
|
46
|
-
return ['
|
|
52
|
+
return ['media-grid-component', mergeAttributes(HTMLAttributes), 0];
|
|
47
53
|
},
|
|
48
54
|
addCommands() {
|
|
49
55
|
return {
|
|
50
56
|
insertGrid: (options) => ({ tr, state, dispatch }) => {
|
|
51
57
|
const { schema } = state;
|
|
52
58
|
const cols = options?.cols || 2;
|
|
53
|
-
// const items = Array.from({ length: cols }, () =>
|
|
54
|
-
// schema.nodes.gridItem.create(
|
|
55
|
-
// null,
|
|
56
|
-
// schema.nodes.image.create({ src: 'https://placehold.co/800x400' })
|
|
57
|
-
// )
|
|
58
|
-
// )
|
|
59
59
|
const items = Array.from({ length: cols }, () => schema.nodes.gridItem.create() // 👈 sin contenido
|
|
60
60
|
);
|
|
61
61
|
const grid = this.type.create({ cols }, items);
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
const { node, updateAttributes, selected, getPos, editor }: NodeViewProps = $props();
|
|
7
7
|
|
|
8
|
+
console.log(node);
|
|
8
9
|
let cols = $state(node.attrs.cols || 2);
|
|
9
10
|
let gap = $state(node.attrs.gap || 1);
|
|
10
11
|
let showIndicator = $state(node.attrs.showIndicator || false);
|
|
@@ -101,7 +102,7 @@
|
|
|
101
102
|
oninput={handleShowIndicatorChange}
|
|
102
103
|
type="checkbox"
|
|
103
104
|
id="show-indicator"
|
|
104
|
-
|
|
105
|
+
checked={showIndicator}
|
|
105
106
|
/>
|
|
106
107
|
Show indicators
|
|
107
108
|
</label>
|
package/dist/styles.css
CHANGED
|
@@ -6,9 +6,21 @@
|
|
|
6
6
|
--gray-1: #f0f0f0;
|
|
7
7
|
--gray-2: #e0e0e0;
|
|
8
8
|
--gray-3: #c0c0c0;
|
|
9
|
-
|
|
10
|
-
--toolbar-padding: 6px;
|
|
9
|
+
|
|
11
10
|
--fl-editor-radius: 12px;
|
|
11
|
+
--fl-editor-bg: #242424;
|
|
12
|
+
--fl-toolbar-sticky-position: 0;
|
|
13
|
+
--fl-toolbar-z-index: 10;
|
|
14
|
+
--fl-toolbar-padding: 6px;
|
|
15
|
+
--fl-toolbar-gap: 5px;
|
|
16
|
+
--fl-toolbar-bg: #242424;
|
|
17
|
+
|
|
18
|
+
--fl-doc-max-width: 1024px;
|
|
19
|
+
--fl-doc-padding: 2rem;
|
|
20
|
+
--fl-doc-bg: transparent;
|
|
21
|
+
--fl-doc-margin-inline: auto;
|
|
22
|
+
--fl-doc-margin-block: 2rem;
|
|
23
|
+
--fl-doc-radius: 0;
|
|
12
24
|
}
|
|
13
25
|
|
|
14
26
|
/* Basic editor styles */
|
|
@@ -252,9 +264,18 @@
|
|
|
252
264
|
flex-direction: column;
|
|
253
265
|
text-align: left;
|
|
254
266
|
min-height: 56px;
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
267
|
+
box-sizing: border-box;
|
|
268
|
+
width: 100%;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.fl-rich-text-content-doc {
|
|
272
|
+
padding: var(--fl-doc-padding, 2rem);
|
|
273
|
+
background: var(--fl-doc-bg, transparent);
|
|
274
|
+
border-radius: var(--fl-doc-radius, 12px);
|
|
275
|
+
width: 100%;
|
|
276
|
+
max-width: var(--fl-doc-max-width, 1024px);
|
|
277
|
+
margin-inline: var(--fl-doc-margin-inline, auto);
|
|
278
|
+
margin-block: var(--fl-doc-margin-block, 2rem);
|
|
258
279
|
}
|
|
259
280
|
|
|
260
281
|
.fl-toolbar-dropdown-panel {
|
|
@@ -265,7 +286,7 @@
|
|
|
265
286
|
backdrop-filter: blur(42px);
|
|
266
287
|
border-radius: 14px;
|
|
267
288
|
min-width: auto;
|
|
268
|
-
z-index:
|
|
289
|
+
z-index: 1000;
|
|
269
290
|
box-sizing: border-box;
|
|
270
291
|
|
|
271
292
|
&.fl-toolbar-dropdown-panel--table {
|
|
@@ -296,7 +317,7 @@
|
|
|
296
317
|
width: 100%;
|
|
297
318
|
height: 100%;
|
|
298
319
|
min-height: 56px;
|
|
299
|
-
background-color: var(--fl-bg
|
|
320
|
+
background-color: var(--fl-editor-bg, #242424);
|
|
300
321
|
color: var(--text-color);
|
|
301
322
|
box-sizing: border-box;
|
|
302
323
|
border-radius: var(--fl-editor-radius);
|
|
@@ -307,10 +328,10 @@
|
|
|
307
328
|
flex-wrap: nowrap;
|
|
308
329
|
overflow: auto;
|
|
309
330
|
align-items: center;
|
|
310
|
-
gap: var(--toolbar-gap);
|
|
311
|
-
padding: var(--toolbar-padding);
|
|
331
|
+
gap: var(--fl-toolbar-gap);
|
|
332
|
+
padding: var(--fl-toolbar-padding);
|
|
312
333
|
position: sticky;
|
|
313
|
-
top: var(--sticky-position, 0);
|
|
334
|
+
top: var(--fl-toolbar-sticky-position, 0);
|
|
314
335
|
z-index: var(--fl-toolbar-z-index, 10);
|
|
315
336
|
background: var(--fl-toolbar-bg, #242424);
|
|
316
337
|
border-radius: var(--fl-editor-radius);
|
|
@@ -319,7 +340,7 @@
|
|
|
319
340
|
.fl-rich-text-toolbar-group {
|
|
320
341
|
display: flex;
|
|
321
342
|
flex-wrap: nowrap;
|
|
322
|
-
gap: var(--toolbar-gap);
|
|
343
|
+
gap: var(--fl-toolbar-gap);
|
|
323
344
|
|
|
324
345
|
button {
|
|
325
346
|
padding: 8px 8px;
|
|
@@ -374,7 +395,7 @@
|
|
|
374
395
|
font-weight: 500;
|
|
375
396
|
border: none;
|
|
376
397
|
padding: 0px;
|
|
377
|
-
font-size:
|
|
398
|
+
font-size: 11px;
|
|
378
399
|
border-radius: 3px;
|
|
379
400
|
outline: 1px dashed #818181;
|
|
380
401
|
scale: 1.1;
|
|
@@ -571,8 +592,8 @@
|
|
|
571
592
|
position: absolute;
|
|
572
593
|
left: 10px;
|
|
573
594
|
top: 10px;
|
|
574
|
-
width:
|
|
575
|
-
height:
|
|
595
|
+
width: 26px;
|
|
596
|
+
height: 26px;
|
|
576
597
|
display: flex;
|
|
577
598
|
align-items: center;
|
|
578
599
|
justify-content: center;
|
|
@@ -580,7 +601,10 @@
|
|
|
580
601
|
border-radius: 100%;
|
|
581
602
|
color: #fff;
|
|
582
603
|
font-weight: 600;
|
|
583
|
-
font-size:
|
|
604
|
+
font-size: 16px;
|
|
605
|
+
text-align: center;
|
|
606
|
+
font-family: monospace;
|
|
607
|
+
text-transform: uppercase;
|
|
584
608
|
}
|
|
585
609
|
}
|
|
586
610
|
|