@flogeez/angular-tiptap-editor 0.3.1 → 0.3.3
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/README.md +229 -54
- package/fesm2022/flogeez-angular-tiptap-editor.mjs +241 -189
- package/fesm2022/flogeez-angular-tiptap-editor.mjs.map +1 -1
- package/index.d.ts +64 -7
- package/package.json +1 -1
|
@@ -2338,7 +2338,20 @@ class EditorCommandsService {
|
|
|
2338
2338
|
}
|
|
2339
2339
|
// Méthode pour vider le contenu
|
|
2340
2340
|
clearContent(editor) {
|
|
2341
|
-
editor.chain().focus().
|
|
2341
|
+
editor.chain().focus().setContent("", true).run(); // ✅ Forcer l'émission de l'événement
|
|
2342
|
+
}
|
|
2343
|
+
// Méthodes de base de l'éditeur
|
|
2344
|
+
focus(editor) {
|
|
2345
|
+
editor.chain().focus().run();
|
|
2346
|
+
}
|
|
2347
|
+
blur(editor) {
|
|
2348
|
+
editor.chain().blur().run();
|
|
2349
|
+
}
|
|
2350
|
+
setContent(editor, content, emitUpdate = true) {
|
|
2351
|
+
editor.chain().focus().setContent(content, emitUpdate).run();
|
|
2352
|
+
}
|
|
2353
|
+
setEditable(editor, editable) {
|
|
2354
|
+
editor.setEditable(editable);
|
|
2342
2355
|
}
|
|
2343
2356
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: EditorCommandsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2344
2357
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: EditorCommandsService, providedIn: "root" }); }
|
|
@@ -3497,7 +3510,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
3497
3510
|
`, styles: [".tiptap-toolbar{display:flex;align-items:center;gap:4px;padding:4px 8px;background:#f8f9fa;border-bottom:1px solid #e2e8f0;flex-wrap:wrap;min-height:32px;position:relative}.toolbar-group{display:flex;align-items:center;gap:2px;padding:0 4px}.toolbar-separator{width:1px;height:24px;background:#e2e8f0;margin:0 4px}@media (max-width: 768px){.tiptap-toolbar{padding:6px 8px;gap:2px}.toolbar-group{gap:1px}}@keyframes toolbarSlideIn{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.tiptap-toolbar{animation:toolbarSlideIn .3s cubic-bezier(.4,0,.2,1)}\n"] }]
|
|
3498
3511
|
}], ctorParameters: () => [{ type: EditorCommandsService }] });
|
|
3499
3512
|
|
|
3500
|
-
const DEFAULT_SLASH_COMMANDS = [
|
|
3513
|
+
const DEFAULT_SLASH_COMMANDS$1 = [
|
|
3501
3514
|
{
|
|
3502
3515
|
title: "Titre 1",
|
|
3503
3516
|
description: "Grand titre de section",
|
|
@@ -3634,7 +3647,7 @@ class TiptapSlashCommandsComponent {
|
|
|
3634
3647
|
constructor() {
|
|
3635
3648
|
this.editor = input.required();
|
|
3636
3649
|
this.config = input({
|
|
3637
|
-
commands: DEFAULT_SLASH_COMMANDS,
|
|
3650
|
+
commands: DEFAULT_SLASH_COMMANDS$1,
|
|
3638
3651
|
});
|
|
3639
3652
|
// Output pour l'upload d'image
|
|
3640
3653
|
this.imageUploadRequested = output();
|
|
@@ -3647,7 +3660,7 @@ class TiptapSlashCommandsComponent {
|
|
|
3647
3660
|
// Signal pour l'index sélectionné
|
|
3648
3661
|
this.selectedIndex = signal(0);
|
|
3649
3662
|
this.commands = computed(() => {
|
|
3650
|
-
const configCommands = this.config().commands || DEFAULT_SLASH_COMMANDS;
|
|
3663
|
+
const configCommands = this.config().commands || DEFAULT_SLASH_COMMANDS$1;
|
|
3651
3664
|
// Remplacer la commande image par une version qui utilise l'output
|
|
3652
3665
|
return configCommands.map((command) => {
|
|
3653
3666
|
if (command.icon === "image") {
|
|
@@ -4367,6 +4380,178 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
4367
4380
|
}]
|
|
4368
4381
|
}] });
|
|
4369
4382
|
|
|
4383
|
+
/**
|
|
4384
|
+
* Clés des commandes dans l'ordre de création
|
|
4385
|
+
*/
|
|
4386
|
+
const SLASH_COMMAND_KEYS = [
|
|
4387
|
+
"heading1",
|
|
4388
|
+
"heading2",
|
|
4389
|
+
"heading3",
|
|
4390
|
+
"bulletList",
|
|
4391
|
+
"orderedList",
|
|
4392
|
+
"blockquote",
|
|
4393
|
+
"code",
|
|
4394
|
+
"image",
|
|
4395
|
+
"horizontalRule",
|
|
4396
|
+
"table",
|
|
4397
|
+
];
|
|
4398
|
+
/**
|
|
4399
|
+
* Factory function pour créer les slash commands traduits
|
|
4400
|
+
*/
|
|
4401
|
+
function createI18nSlashCommands(i18nService) {
|
|
4402
|
+
const slashCommands = i18nService.slashCommands();
|
|
4403
|
+
return [
|
|
4404
|
+
{
|
|
4405
|
+
title: slashCommands.heading1.title,
|
|
4406
|
+
description: slashCommands.heading1.description,
|
|
4407
|
+
icon: "format_h1",
|
|
4408
|
+
keywords: slashCommands.heading1.keywords,
|
|
4409
|
+
command: (editor) => editor.chain().focus().toggleHeading({ level: 1 }).run(),
|
|
4410
|
+
},
|
|
4411
|
+
{
|
|
4412
|
+
title: slashCommands.heading2.title,
|
|
4413
|
+
description: slashCommands.heading2.description,
|
|
4414
|
+
icon: "format_h2",
|
|
4415
|
+
keywords: slashCommands.heading2.keywords,
|
|
4416
|
+
command: (editor) => editor.chain().focus().toggleHeading({ level: 2 }).run(),
|
|
4417
|
+
},
|
|
4418
|
+
{
|
|
4419
|
+
title: slashCommands.heading3.title,
|
|
4420
|
+
description: slashCommands.heading3.description,
|
|
4421
|
+
icon: "format_h3",
|
|
4422
|
+
keywords: slashCommands.heading3.keywords,
|
|
4423
|
+
command: (editor) => editor.chain().focus().toggleHeading({ level: 3 }).run(),
|
|
4424
|
+
},
|
|
4425
|
+
{
|
|
4426
|
+
title: slashCommands.bulletList.title,
|
|
4427
|
+
description: slashCommands.bulletList.description,
|
|
4428
|
+
icon: "format_list_bulleted",
|
|
4429
|
+
keywords: slashCommands.bulletList.keywords,
|
|
4430
|
+
command: (editor) => editor.chain().focus().toggleBulletList().run(),
|
|
4431
|
+
},
|
|
4432
|
+
{
|
|
4433
|
+
title: slashCommands.orderedList.title,
|
|
4434
|
+
description: slashCommands.orderedList.description,
|
|
4435
|
+
icon: "format_list_numbered",
|
|
4436
|
+
keywords: slashCommands.orderedList.keywords,
|
|
4437
|
+
command: (editor) => editor.chain().focus().toggleOrderedList().run(),
|
|
4438
|
+
},
|
|
4439
|
+
{
|
|
4440
|
+
title: slashCommands.blockquote.title,
|
|
4441
|
+
description: slashCommands.blockquote.description,
|
|
4442
|
+
icon: "format_quote",
|
|
4443
|
+
keywords: slashCommands.blockquote.keywords,
|
|
4444
|
+
command: (editor) => editor.chain().focus().toggleBlockquote().run(),
|
|
4445
|
+
},
|
|
4446
|
+
{
|
|
4447
|
+
title: slashCommands.code.title,
|
|
4448
|
+
description: slashCommands.code.description,
|
|
4449
|
+
icon: "code",
|
|
4450
|
+
keywords: slashCommands.code.keywords,
|
|
4451
|
+
command: (editor) => editor.chain().focus().toggleCodeBlock().run(),
|
|
4452
|
+
},
|
|
4453
|
+
{
|
|
4454
|
+
title: slashCommands.image.title,
|
|
4455
|
+
description: slashCommands.image.description,
|
|
4456
|
+
icon: "image",
|
|
4457
|
+
keywords: slashCommands.image.keywords,
|
|
4458
|
+
command: (editor) => {
|
|
4459
|
+
// Créer un input file temporaire pour sélectionner une image
|
|
4460
|
+
const input = document.createElement("input");
|
|
4461
|
+
input.type = "file";
|
|
4462
|
+
input.accept = "image/*";
|
|
4463
|
+
input.style.display = "none";
|
|
4464
|
+
input.addEventListener("change", async (e) => {
|
|
4465
|
+
const file = e.target.files?.[0];
|
|
4466
|
+
if (file && file.type.startsWith("image/")) {
|
|
4467
|
+
try {
|
|
4468
|
+
// Utiliser la méthode de compression unifiée
|
|
4469
|
+
const canvas = document.createElement("canvas");
|
|
4470
|
+
const ctx = canvas.getContext("2d");
|
|
4471
|
+
const img = new Image();
|
|
4472
|
+
img.onload = () => {
|
|
4473
|
+
// Vérifier les dimensions (max 1920x1080)
|
|
4474
|
+
const maxWidth = 1920;
|
|
4475
|
+
const maxHeight = 1080;
|
|
4476
|
+
let { width, height } = img;
|
|
4477
|
+
// Redimensionner si nécessaire
|
|
4478
|
+
if (width > maxWidth || height > maxHeight) {
|
|
4479
|
+
const ratio = Math.min(maxWidth / width, maxHeight / height);
|
|
4480
|
+
width *= ratio;
|
|
4481
|
+
height *= ratio;
|
|
4482
|
+
}
|
|
4483
|
+
canvas.width = width;
|
|
4484
|
+
canvas.height = height;
|
|
4485
|
+
// Dessiner l'image redimensionnée
|
|
4486
|
+
ctx?.drawImage(img, 0, 0, width, height);
|
|
4487
|
+
// Convertir en base64 avec compression
|
|
4488
|
+
canvas.toBlob((blob) => {
|
|
4489
|
+
if (blob) {
|
|
4490
|
+
const reader = new FileReader();
|
|
4491
|
+
reader.onload = (e) => {
|
|
4492
|
+
const base64 = e.target?.result;
|
|
4493
|
+
if (base64) {
|
|
4494
|
+
// Utiliser setResizableImage avec toutes les propriétés
|
|
4495
|
+
editor
|
|
4496
|
+
.chain()
|
|
4497
|
+
.focus()
|
|
4498
|
+
.setResizableImage({
|
|
4499
|
+
src: base64,
|
|
4500
|
+
alt: file.name,
|
|
4501
|
+
title: `${file.name} (${Math.round(width)}×${Math.round(height)})`,
|
|
4502
|
+
width: Math.round(width),
|
|
4503
|
+
height: Math.round(height),
|
|
4504
|
+
})
|
|
4505
|
+
.run();
|
|
4506
|
+
}
|
|
4507
|
+
};
|
|
4508
|
+
reader.readAsDataURL(blob);
|
|
4509
|
+
}
|
|
4510
|
+
}, file.type, 0.8 // qualité de compression
|
|
4511
|
+
);
|
|
4512
|
+
};
|
|
4513
|
+
img.onerror = () => {
|
|
4514
|
+
console.error(i18nService.editor().imageLoadError);
|
|
4515
|
+
};
|
|
4516
|
+
img.src = URL.createObjectURL(file);
|
|
4517
|
+
}
|
|
4518
|
+
catch (error) {
|
|
4519
|
+
console.error("Error uploading image:", error);
|
|
4520
|
+
}
|
|
4521
|
+
}
|
|
4522
|
+
document.body.removeChild(input);
|
|
4523
|
+
});
|
|
4524
|
+
document.body.appendChild(input);
|
|
4525
|
+
input.click();
|
|
4526
|
+
},
|
|
4527
|
+
},
|
|
4528
|
+
{
|
|
4529
|
+
title: slashCommands.horizontalRule.title,
|
|
4530
|
+
description: slashCommands.horizontalRule.description,
|
|
4531
|
+
icon: "horizontal_rule",
|
|
4532
|
+
keywords: slashCommands.horizontalRule.keywords,
|
|
4533
|
+
command: (editor) => editor.chain().focus().setHorizontalRule().run(),
|
|
4534
|
+
},
|
|
4535
|
+
{
|
|
4536
|
+
title: slashCommands.table.title,
|
|
4537
|
+
description: slashCommands.table.description,
|
|
4538
|
+
icon: "table_view",
|
|
4539
|
+
keywords: slashCommands.table.keywords,
|
|
4540
|
+
command: (editor) => editor.chain().focus().insertTable({ rows: 3, cols: 3 }).run(),
|
|
4541
|
+
},
|
|
4542
|
+
];
|
|
4543
|
+
}
|
|
4544
|
+
/**
|
|
4545
|
+
* Fonction utilitaire pour filtrer les slash commands selon les commandes actives
|
|
4546
|
+
*/
|
|
4547
|
+
function filterSlashCommands(activeCommands, i18nService) {
|
|
4548
|
+
const allCommands = createI18nSlashCommands(i18nService);
|
|
4549
|
+
return allCommands.filter((command, index) => {
|
|
4550
|
+
const commandKey = SLASH_COMMAND_KEYS[index];
|
|
4551
|
+
return commandKey && activeCommands.has(commandKey);
|
|
4552
|
+
});
|
|
4553
|
+
}
|
|
4554
|
+
|
|
4370
4555
|
// Configuration par défaut de la toolbar
|
|
4371
4556
|
const DEFAULT_TOOLBAR_CONFIG = {
|
|
4372
4557
|
bold: true,
|
|
@@ -4436,6 +4621,9 @@ const DEFAULT_CELL_MENU_CONFIG = {
|
|
|
4436
4621
|
mergeCells: true,
|
|
4437
4622
|
splitCell: true,
|
|
4438
4623
|
};
|
|
4624
|
+
const DEFAULT_SLASH_COMMANDS = {
|
|
4625
|
+
commands: [], // Sera rempli par filterSlashCommands
|
|
4626
|
+
};
|
|
4439
4627
|
class AngularTiptapEditorComponent {
|
|
4440
4628
|
constructor() {
|
|
4441
4629
|
// Nouveaux inputs avec signal
|
|
@@ -4469,12 +4657,18 @@ class AngularTiptapEditorComponent {
|
|
|
4469
4657
|
this.editorBlur = output();
|
|
4470
4658
|
// ViewChild avec signal
|
|
4471
4659
|
this.editorElement = viewChild.required("editorElement");
|
|
4472
|
-
// Signals pour l'état interne
|
|
4473
|
-
this.
|
|
4474
|
-
this.
|
|
4475
|
-
this.
|
|
4476
|
-
this.
|
|
4477
|
-
this.
|
|
4660
|
+
// Signals privés pour l'état interne
|
|
4661
|
+
this._editor = signal(null);
|
|
4662
|
+
this._characterCount = signal(0);
|
|
4663
|
+
this._wordCount = signal(0);
|
|
4664
|
+
this._isDragOver = signal(false);
|
|
4665
|
+
this._editorFullyInitialized = signal(false);
|
|
4666
|
+
// Accès en lecture seule aux signaux
|
|
4667
|
+
this.editor = this._editor.asReadonly();
|
|
4668
|
+
this.characterCount = this._characterCount.asReadonly();
|
|
4669
|
+
this.wordCount = this._wordCount.asReadonly();
|
|
4670
|
+
this.isDragOver = this._isDragOver.asReadonly();
|
|
4671
|
+
this.editorFullyInitialized = this._editorFullyInitialized.asReadonly();
|
|
4478
4672
|
// Computed pour les états de l'éditeur
|
|
4479
4673
|
this.isEditorReady = computed(() => this.editor() !== null);
|
|
4480
4674
|
// Computed pour la configuration de la toolbar
|
|
@@ -4520,12 +4714,21 @@ class AngularTiptapEditorComponent {
|
|
|
4520
4714
|
...this.imageUpload(),
|
|
4521
4715
|
}));
|
|
4522
4716
|
// Computed pour la configuration des slash commands
|
|
4523
|
-
this.slashCommandsConfigComputed = computed(() =>
|
|
4717
|
+
this.slashCommandsConfigComputed = computed(() => {
|
|
4718
|
+
const config = this.slashCommandsConfig();
|
|
4719
|
+
if (config) {
|
|
4720
|
+
return config;
|
|
4721
|
+
}
|
|
4722
|
+
// Configuration par défaut avec toutes les commandes
|
|
4723
|
+
const allCommands = filterSlashCommands(new Set(SLASH_COMMAND_KEYS), this.i18nService);
|
|
4724
|
+
return { commands: allCommands };
|
|
4725
|
+
});
|
|
4524
4726
|
this._destroyRef = inject(DestroyRef);
|
|
4525
4727
|
// NgControl pour gérer les FormControls
|
|
4526
4728
|
this.ngControl = inject(NgControl, { self: true, optional: true });
|
|
4527
4729
|
this.i18nService = inject(TiptapI18nService);
|
|
4528
4730
|
this.imageService = inject(ImageService);
|
|
4731
|
+
this.editorCommandsService = inject(EditorCommandsService);
|
|
4529
4732
|
// Effet pour gérer le changement de langue
|
|
4530
4733
|
effect(() => {
|
|
4531
4734
|
const locale = this.locale();
|
|
@@ -4566,7 +4769,7 @@ class AngularTiptapEditorComponent {
|
|
|
4566
4769
|
const currentEditor = this.editor();
|
|
4567
4770
|
const isEditable = this.editable();
|
|
4568
4771
|
if (currentEditor) {
|
|
4569
|
-
|
|
4772
|
+
this.editorCommandsService.setEditable(currentEditor, isEditable);
|
|
4570
4773
|
}
|
|
4571
4774
|
});
|
|
4572
4775
|
// Effect pour la détection du survol des tables
|
|
@@ -4588,7 +4791,7 @@ class AngularTiptapEditorComponent {
|
|
|
4588
4791
|
if (currentEditor) {
|
|
4589
4792
|
currentEditor.destroy();
|
|
4590
4793
|
}
|
|
4591
|
-
this.
|
|
4794
|
+
this._editorFullyInitialized.set(false);
|
|
4592
4795
|
}
|
|
4593
4796
|
initEditor() {
|
|
4594
4797
|
const extensions = [
|
|
@@ -4666,7 +4869,7 @@ class AngularTiptapEditorComponent {
|
|
|
4666
4869
|
// Marquer l'éditeur comme complètement initialisé après un court délai
|
|
4667
4870
|
// pour s'assurer que tous les plugins et extensions sont prêts
|
|
4668
4871
|
setTimeout(() => {
|
|
4669
|
-
this.
|
|
4872
|
+
this._editorFullyInitialized.set(true);
|
|
4670
4873
|
}, 100);
|
|
4671
4874
|
},
|
|
4672
4875
|
onFocus: ({ editor, event }) => {
|
|
@@ -4681,13 +4884,13 @@ class AngularTiptapEditorComponent {
|
|
|
4681
4884
|
},
|
|
4682
4885
|
});
|
|
4683
4886
|
// Stocker la référence de l'éditeur immédiatement
|
|
4684
|
-
this.
|
|
4887
|
+
this._editor.set(newEditor);
|
|
4685
4888
|
}
|
|
4686
4889
|
updateCharacterCount(editor) {
|
|
4687
4890
|
if (this.showCharacterCount() && editor.storage["characterCount"]) {
|
|
4688
4891
|
const storage = editor.storage["characterCount"];
|
|
4689
|
-
this.
|
|
4690
|
-
this.
|
|
4892
|
+
this._characterCount.set(storage.characters());
|
|
4893
|
+
this._wordCount.set(storage.words());
|
|
4691
4894
|
}
|
|
4692
4895
|
}
|
|
4693
4896
|
// Méthodes pour l'upload d'images
|
|
@@ -4721,12 +4924,12 @@ class AngularTiptapEditorComponent {
|
|
|
4721
4924
|
onDragOver(event) {
|
|
4722
4925
|
event.preventDefault();
|
|
4723
4926
|
event.stopPropagation();
|
|
4724
|
-
this.
|
|
4927
|
+
this._isDragOver.set(true);
|
|
4725
4928
|
}
|
|
4726
4929
|
onDrop(event) {
|
|
4727
4930
|
event.preventDefault();
|
|
4728
4931
|
event.stopPropagation();
|
|
4729
|
-
this.
|
|
4932
|
+
this._isDragOver.set(false);
|
|
4730
4933
|
const files = event.dataTransfer?.files;
|
|
4731
4934
|
if (files && files.length > 0) {
|
|
4732
4935
|
const file = files[0];
|
|
@@ -4757,22 +4960,33 @@ class AngularTiptapEditorComponent {
|
|
|
4757
4960
|
return this.editor()?.getText() || "";
|
|
4758
4961
|
}
|
|
4759
4962
|
setContent(content, emitUpdate = true) {
|
|
4760
|
-
this.editor()
|
|
4963
|
+
const editor = this.editor();
|
|
4964
|
+
if (editor) {
|
|
4965
|
+
this.editorCommandsService.setContent(editor, content, emitUpdate);
|
|
4966
|
+
}
|
|
4761
4967
|
}
|
|
4762
4968
|
focus() {
|
|
4763
|
-
this.editor()
|
|
4969
|
+
const editor = this.editor();
|
|
4970
|
+
if (editor) {
|
|
4971
|
+
this.editorCommandsService.focus(editor);
|
|
4972
|
+
}
|
|
4764
4973
|
}
|
|
4765
4974
|
blur() {
|
|
4766
|
-
this.editor()
|
|
4975
|
+
const editor = this.editor();
|
|
4976
|
+
if (editor) {
|
|
4977
|
+
this.editorCommandsService.blur(editor);
|
|
4978
|
+
}
|
|
4767
4979
|
}
|
|
4768
4980
|
clearContent() {
|
|
4769
4981
|
const editor = this.editor();
|
|
4770
4982
|
if (editor) {
|
|
4771
|
-
|
|
4772
|
-
// Mettre à jour les compteurs après avoir vidé le contenu
|
|
4773
|
-
this.updateCharacterCount(editor);
|
|
4983
|
+
this.editorCommandsService.clearContent(editor);
|
|
4774
4984
|
}
|
|
4775
4985
|
}
|
|
4986
|
+
// Méthode publique pour obtenir l'éditeur
|
|
4987
|
+
getEditor() {
|
|
4988
|
+
return this.editor();
|
|
4989
|
+
}
|
|
4776
4990
|
setupFormControlSubscription() {
|
|
4777
4991
|
const control = this.ngControl?.control;
|
|
4778
4992
|
if (control) {
|
|
@@ -4791,7 +5005,7 @@ class AngularTiptapEditorComponent {
|
|
|
4791
5005
|
setDisabledState(isDisabled) {
|
|
4792
5006
|
const currentEditor = this.editor();
|
|
4793
5007
|
if (currentEditor) {
|
|
4794
|
-
|
|
5008
|
+
this.editorCommandsService.setEditable(currentEditor, !isDisabled);
|
|
4795
5009
|
}
|
|
4796
5010
|
}
|
|
4797
5011
|
onEditorClick(event) {
|
|
@@ -5000,168 +5214,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
5000
5214
|
`, styles: [".tiptap-editor{border:2px solid #e2e8f0;border-radius:8px;background:#fff;overflow:hidden;transition:border-color .2s ease}.tiptap-editor:focus-within{border-color:#3182ce}.tiptap-content{padding:16px;min-height:var(--editor-min-height, 200px);height:var(--editor-height, auto);max-height:var(--editor-max-height, none);overflow-y:var(--editor-overflow, visible);outline:none;position:relative}.tiptap-content.drag-over{background:#f0f8ff;border:2px dashed #3182ce}.character-count{padding:8px 16px;font-size:12px;color:#718096;text-align:right;border-top:1px solid #e2e8f0;background:#f8f9fa}.image-upload-container{position:relative;display:inline-block}:host ::ng-deep .ProseMirror{outline:none;line-height:1.6;color:#2d3748;min-height:100%;height:100%;word-wrap:break-word;overflow-wrap:break-word}:host ::ng-deep .ProseMirror h1{font-size:2em;font-weight:700;margin-top:0;margin-bottom:.5em}:host ::ng-deep .ProseMirror h2{font-size:1.5em;font-weight:700;margin-top:1em;margin-bottom:.5em}:host ::ng-deep .ProseMirror h3{font-size:1.25em;font-weight:700;margin-top:1em;margin-bottom:.5em}:host ::ng-deep .ProseMirror p{margin:.5em 0}:host ::ng-deep .ProseMirror ul,:host ::ng-deep .ProseMirror ol{padding-left:2em;margin:.5em 0}:host ::ng-deep .ProseMirror blockquote{border-left:4px solid #e2e8f0;margin:1em 0;font-style:italic;background:#f8f9fa;padding:.5em 1em;border-radius:0 4px 4px 0}:host ::ng-deep .ProseMirror code{background:#f1f5f9;padding:.2em .4em;border-radius:3px;font-family:Monaco,Consolas,monospace;font-size:.9em}:host ::ng-deep .ProseMirror pre{background:#1a202c;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;margin:1em 0}:host ::ng-deep .ProseMirror pre code{background:none;color:inherit;padding:0}:host ::ng-deep .ProseMirror p.is-editor-empty:first-child:before{content:attr(data-placeholder);color:#a0aec0;pointer-events:none;float:left;height:0}:host ::ng-deep .ProseMirror[contenteditable=false]{pointer-events:none}:host ::ng-deep .ProseMirror[contenteditable=false] img{cursor:default;pointer-events:none}:host ::ng-deep .ProseMirror[contenteditable=false] img:hover{transform:none;box-shadow:0 2px 8px #0000001a}:host ::ng-deep .ProseMirror[contenteditable=false] img.ProseMirror-selectednode{outline:none}:host ::ng-deep .ProseMirror img{position:relative;display:inline-block;max-width:100%;height:auto;cursor:pointer;transition:all .2s ease;border:2px solid transparent;border-radius:8px}:host ::ng-deep .ProseMirror img:hover{border-color:#e2e8f0;box-shadow:0 2px 4px #0000001a}:host ::ng-deep .ProseMirror img.ProseMirror-selectednode{border-color:#3182ce;box-shadow:0 0 0 3px #3182ce1a;transition:all .2s ease}:host ::ng-deep .ProseMirror .tiptap-image{max-width:100%;height:auto;border-radius:16px;box-shadow:0 4px 20px #00000014;margin:.5em 0;cursor:pointer;transition:all .3s cubic-bezier(.4,0,.2,1);display:block;filter:brightness(1) contrast(1)}:host ::ng-deep .ProseMirror .tiptap-image:hover{box-shadow:0 8px 30px #0000001f;filter:brightness(1.02) contrast(1.02)}:host ::ng-deep .ProseMirror .tiptap-image.ProseMirror-selectednode{outline:2px solid #6366f1;outline-offset:2px;border-radius:16px;box-shadow:0 0 0 4px #6366f11a}:host ::ng-deep .image-container{margin:.5em 0;text-align:center;border-radius:16px;overflow:hidden;transition:all .3s cubic-bezier(.4,0,.2,1)}:host ::ng-deep .image-container.image-align-left{text-align:left}:host ::ng-deep .image-container.image-align-center{text-align:center}:host ::ng-deep .image-container.image-align-right{text-align:right}:host ::ng-deep .image-container img{display:inline-block;max-width:100%;height:auto;border-radius:16px}:host ::ng-deep .resizable-image-container{position:relative;display:inline-block;margin:.5em 0}:host ::ng-deep .resize-controls{position:absolute;inset:0;pointer-events:none;z-index:1000}:host ::ng-deep .resize-handle{position:absolute;width:12px;height:12px;background:#3b82f6;border:2px solid white;border-radius:50%;pointer-events:all;cursor:pointer;z-index:1001;transition:all .15s ease;box-shadow:0 2px 6px #0003}:host ::ng-deep .resize-handle:hover{background:#2563eb;box-shadow:0 3px 8px #0000004d}:host ::ng-deep .resize-handle:active{background:#1d4ed8}:host ::ng-deep .resize-handle-n:hover,:host ::ng-deep .resize-handle-s:hover{transform:translate(-50%) scale(1.2)}:host ::ng-deep .resize-handle-w:hover,:host ::ng-deep .resize-handle-e:hover{transform:translateY(-50%) scale(1.2)}:host ::ng-deep .resize-handle-n:active,:host ::ng-deep .resize-handle-s:active{transform:translate(-50%) scale(.9)}:host ::ng-deep .resize-handle-w:active,:host ::ng-deep .resize-handle-e:active{transform:translateY(-50%) scale(.9)}:host ::ng-deep .resize-handle-nw:hover,:host ::ng-deep .resize-handle-ne:hover,:host ::ng-deep .resize-handle-sw:hover,:host ::ng-deep .resize-handle-se:hover{transform:scale(1.2)}:host ::ng-deep .resize-handle-nw:active,:host ::ng-deep .resize-handle-ne:active,:host ::ng-deep .resize-handle-sw:active,:host ::ng-deep .resize-handle-se:active{transform:scale(.9)}:host ::ng-deep .resize-handle-nw{top:0;left:-6px;cursor:nw-resize}:host ::ng-deep .resize-handle-n{top:0;left:50%;transform:translate(-50%);cursor:n-resize}:host ::ng-deep .resize-handle-ne{top:0;right:-6px;cursor:ne-resize}:host ::ng-deep .resize-handle-w{top:50%;left:-6px;transform:translateY(-50%);cursor:w-resize}:host ::ng-deep .resize-handle-e{top:50%;right:-6px;transform:translateY(-50%);cursor:e-resize}:host ::ng-deep .resize-handle-sw{bottom:0;left:-6px;cursor:sw-resize}:host ::ng-deep .resize-handle-s{bottom:0;left:50%;transform:translate(-50%);cursor:s-resize}:host ::ng-deep .resize-handle-se{bottom:0;right:-6px;cursor:se-resize}:host ::ng-deep body.resizing{-webkit-user-select:none;user-select:none;cursor:crosshair}:host ::ng-deep body.resizing .ProseMirror{pointer-events:none}:host ::ng-deep body.resizing .ProseMirror .tiptap-image{pointer-events:none}:host ::ng-deep .image-size-info{position:absolute;bottom:-20px;left:50%;transform:translate(-50%);background:#000c;color:#fff;padding:2px 6px;border-radius:3px;font-size:11px;white-space:nowrap;opacity:0;transition:opacity .2s ease}:host ::ng-deep .image-container:hover .image-size-info{opacity:1}:host ::ng-deep .ProseMirror table{border-collapse:separate;border-spacing:0;margin:0;table-layout:fixed;width:100%;border-radius:8px;overflow:hidden}:host ::ng-deep .ProseMirror table td,:host ::ng-deep .ProseMirror table th{border:none;border-right:1px solid #e2e8f0;border-bottom:1px solid #e2e8f0;box-sizing:border-box;min-width:1em;padding:8px 12px;position:relative;vertical-align:top;background:#fff}:host ::ng-deep .ProseMirror table td:first-child,:host ::ng-deep .ProseMirror table th:first-child{border-left:1px solid #e2e8f0}:host ::ng-deep .ProseMirror table tr:first-child td,:host ::ng-deep .ProseMirror table tr:first-child th{border-top:1px solid #e2e8f0}:host ::ng-deep .ProseMirror table tr:first-child th:first-child{border-top-left-radius:8px}:host ::ng-deep .ProseMirror table tr:first-child th:last-child{border-top-right-radius:8px}:host ::ng-deep .ProseMirror table tr:last-child td:first-child{border-bottom-left-radius:8px}:host ::ng-deep .ProseMirror table tr:last-child td:last-child{border-bottom-right-radius:8px}:host ::ng-deep .ProseMirror table th{background:#f8f9fa;font-weight:600;color:#374151}:host ::ng-deep .ProseMirror table .selectedCell:after{background:#c8c8ff66;content:\"\";inset:0;pointer-events:none;position:absolute;z-index:2}:host ::ng-deep .ProseMirror table .column-resize-handle{position:absolute;right:-2px;top:0;bottom:0;width:4px;background-color:#6366f1;opacity:0;transition:opacity .2s ease}:host ::ng-deep .ProseMirror table:hover .column-resize-handle{opacity:1}:host ::ng-deep .ProseMirror table .column-resize-handle:hover{background-color:#4f46e5}:host ::ng-deep .ProseMirror .tableWrapper{overflow-x:auto;margin:1em 0;border-radius:8px}:host ::ng-deep .ProseMirror .tableWrapper table{margin:0;border-radius:8px;min-width:600px;overflow:hidden}:host ::ng-deep .ProseMirror table p{margin:0}:host ::ng-deep .ProseMirror table .selectedCell{background-color:#6366f11a}:host ::ng-deep .ProseMirror table th{background-color:#f8f9fa;font-weight:600;color:#374151;text-align:left}:host ::ng-deep .ProseMirror table tbody tr:nth-child(2n){background-color:#fafbfc}:host ::ng-deep .ProseMirror table tbody tr:hover{background-color:#f1f5f9}\n"] }]
|
|
5001
5215
|
}], ctorParameters: () => [] });
|
|
5002
5216
|
|
|
5003
|
-
/**
|
|
5004
|
-
* Factory function pour créer les slash commands traduits
|
|
5005
|
-
*/
|
|
5006
|
-
function createI18nSlashCommands(i18nService) {
|
|
5007
|
-
const slashCommands = i18nService.slashCommands();
|
|
5008
|
-
return [
|
|
5009
|
-
{
|
|
5010
|
-
title: slashCommands.heading1.title,
|
|
5011
|
-
description: slashCommands.heading1.description,
|
|
5012
|
-
icon: "format_h1",
|
|
5013
|
-
keywords: slashCommands.heading1.keywords,
|
|
5014
|
-
command: (editor) => editor.chain().focus().toggleHeading({ level: 1 }).run(),
|
|
5015
|
-
},
|
|
5016
|
-
{
|
|
5017
|
-
title: slashCommands.heading2.title,
|
|
5018
|
-
description: slashCommands.heading2.description,
|
|
5019
|
-
icon: "format_h2",
|
|
5020
|
-
keywords: slashCommands.heading2.keywords,
|
|
5021
|
-
command: (editor) => editor.chain().focus().toggleHeading({ level: 2 }).run(),
|
|
5022
|
-
},
|
|
5023
|
-
{
|
|
5024
|
-
title: slashCommands.heading3.title,
|
|
5025
|
-
description: slashCommands.heading3.description,
|
|
5026
|
-
icon: "format_h3",
|
|
5027
|
-
keywords: slashCommands.heading3.keywords,
|
|
5028
|
-
command: (editor) => editor.chain().focus().toggleHeading({ level: 3 }).run(),
|
|
5029
|
-
},
|
|
5030
|
-
{
|
|
5031
|
-
title: slashCommands.bulletList.title,
|
|
5032
|
-
description: slashCommands.bulletList.description,
|
|
5033
|
-
icon: "format_list_bulleted",
|
|
5034
|
-
keywords: slashCommands.bulletList.keywords,
|
|
5035
|
-
command: (editor) => editor.chain().focus().toggleBulletList().run(),
|
|
5036
|
-
},
|
|
5037
|
-
{
|
|
5038
|
-
title: slashCommands.orderedList.title,
|
|
5039
|
-
description: slashCommands.orderedList.description,
|
|
5040
|
-
icon: "format_list_numbered",
|
|
5041
|
-
keywords: slashCommands.orderedList.keywords,
|
|
5042
|
-
command: (editor) => editor.chain().focus().toggleOrderedList().run(),
|
|
5043
|
-
},
|
|
5044
|
-
{
|
|
5045
|
-
title: slashCommands.blockquote.title,
|
|
5046
|
-
description: slashCommands.blockquote.description,
|
|
5047
|
-
icon: "format_quote",
|
|
5048
|
-
keywords: slashCommands.blockquote.keywords,
|
|
5049
|
-
command: (editor) => editor.chain().focus().toggleBlockquote().run(),
|
|
5050
|
-
},
|
|
5051
|
-
{
|
|
5052
|
-
title: slashCommands.code.title,
|
|
5053
|
-
description: slashCommands.code.description,
|
|
5054
|
-
icon: "code",
|
|
5055
|
-
keywords: slashCommands.code.keywords,
|
|
5056
|
-
command: (editor) => editor.chain().focus().toggleCodeBlock().run(),
|
|
5057
|
-
},
|
|
5058
|
-
{
|
|
5059
|
-
title: slashCommands.image.title,
|
|
5060
|
-
description: slashCommands.image.description,
|
|
5061
|
-
icon: "image",
|
|
5062
|
-
keywords: slashCommands.image.keywords,
|
|
5063
|
-
command: (editor) => {
|
|
5064
|
-
// Créer un input file temporaire pour sélectionner une image
|
|
5065
|
-
const input = document.createElement("input");
|
|
5066
|
-
input.type = "file";
|
|
5067
|
-
input.accept = "image/*";
|
|
5068
|
-
input.style.display = "none";
|
|
5069
|
-
input.addEventListener("change", async (e) => {
|
|
5070
|
-
const file = e.target.files?.[0];
|
|
5071
|
-
if (file && file.type.startsWith("image/")) {
|
|
5072
|
-
try {
|
|
5073
|
-
// Utiliser la méthode de compression unifiée
|
|
5074
|
-
const canvas = document.createElement("canvas");
|
|
5075
|
-
const ctx = canvas.getContext("2d");
|
|
5076
|
-
const img = new Image();
|
|
5077
|
-
img.onload = () => {
|
|
5078
|
-
// Vérifier les dimensions (max 1920x1080)
|
|
5079
|
-
const maxWidth = 1920;
|
|
5080
|
-
const maxHeight = 1080;
|
|
5081
|
-
let { width, height } = img;
|
|
5082
|
-
// Redimensionner si nécessaire
|
|
5083
|
-
if (width > maxWidth || height > maxHeight) {
|
|
5084
|
-
const ratio = Math.min(maxWidth / width, maxHeight / height);
|
|
5085
|
-
width *= ratio;
|
|
5086
|
-
height *= ratio;
|
|
5087
|
-
}
|
|
5088
|
-
canvas.width = width;
|
|
5089
|
-
canvas.height = height;
|
|
5090
|
-
// Dessiner l'image redimensionnée
|
|
5091
|
-
ctx?.drawImage(img, 0, 0, width, height);
|
|
5092
|
-
// Convertir en base64 avec compression
|
|
5093
|
-
canvas.toBlob((blob) => {
|
|
5094
|
-
if (blob) {
|
|
5095
|
-
const reader = new FileReader();
|
|
5096
|
-
reader.onload = (e) => {
|
|
5097
|
-
const base64 = e.target?.result;
|
|
5098
|
-
if (base64) {
|
|
5099
|
-
// Utiliser setResizableImage avec toutes les propriétés
|
|
5100
|
-
editor
|
|
5101
|
-
.chain()
|
|
5102
|
-
.focus()
|
|
5103
|
-
.setResizableImage({
|
|
5104
|
-
src: base64,
|
|
5105
|
-
alt: file.name,
|
|
5106
|
-
title: `${file.name} (${Math.round(width)}×${Math.round(height)})`,
|
|
5107
|
-
width: Math.round(width),
|
|
5108
|
-
height: Math.round(height),
|
|
5109
|
-
})
|
|
5110
|
-
.run();
|
|
5111
|
-
}
|
|
5112
|
-
};
|
|
5113
|
-
reader.readAsDataURL(blob);
|
|
5114
|
-
}
|
|
5115
|
-
}, file.type, 0.8 // qualité de compression
|
|
5116
|
-
);
|
|
5117
|
-
};
|
|
5118
|
-
img.onerror = () => {
|
|
5119
|
-
console.error(i18nService.editor().imageLoadError);
|
|
5120
|
-
};
|
|
5121
|
-
img.src = URL.createObjectURL(file);
|
|
5122
|
-
}
|
|
5123
|
-
catch (error) {
|
|
5124
|
-
console.error("Error uploading image:", error);
|
|
5125
|
-
}
|
|
5126
|
-
}
|
|
5127
|
-
document.body.removeChild(input);
|
|
5128
|
-
});
|
|
5129
|
-
document.body.appendChild(input);
|
|
5130
|
-
input.click();
|
|
5131
|
-
},
|
|
5132
|
-
},
|
|
5133
|
-
{
|
|
5134
|
-
title: slashCommands.horizontalRule.title,
|
|
5135
|
-
description: slashCommands.horizontalRule.description,
|
|
5136
|
-
icon: "horizontal_rule",
|
|
5137
|
-
keywords: slashCommands.horizontalRule.keywords,
|
|
5138
|
-
command: (editor) => editor.chain().focus().setHorizontalRule().run(),
|
|
5139
|
-
},
|
|
5140
|
-
{
|
|
5141
|
-
title: slashCommands.table.title,
|
|
5142
|
-
description: slashCommands.table.description,
|
|
5143
|
-
icon: "table_view",
|
|
5144
|
-
keywords: slashCommands.table.keywords,
|
|
5145
|
-
command: (editor) => editor.chain().focus().insertTable({ rows: 3, cols: 3 }).run(),
|
|
5146
|
-
},
|
|
5147
|
-
];
|
|
5148
|
-
}
|
|
5149
|
-
/**
|
|
5150
|
-
* Mapping des clés de commandes pour la compatibilité
|
|
5151
|
-
*/
|
|
5152
|
-
const SLASH_COMMAND_KEYS = {
|
|
5153
|
-
heading1: "heading1",
|
|
5154
|
-
heading2: "heading2",
|
|
5155
|
-
heading3: "heading3",
|
|
5156
|
-
bulletList: "bulletList",
|
|
5157
|
-
orderedList: "orderedList",
|
|
5158
|
-
blockquote: "blockquote",
|
|
5159
|
-
code: "code",
|
|
5160
|
-
image: "image",
|
|
5161
|
-
horizontalRule: "horizontalRule",
|
|
5162
|
-
table: "table",
|
|
5163
|
-
};
|
|
5164
|
-
|
|
5165
5217
|
/*
|
|
5166
5218
|
* Public API Surface of tiptap-editor
|
|
5167
5219
|
*/
|
|
@@ -5171,5 +5223,5 @@ const SLASH_COMMAND_KEYS = {
|
|
|
5171
5223
|
* Generated bundle index. Do not edit.
|
|
5172
5224
|
*/
|
|
5173
5225
|
|
|
5174
|
-
export { AngularTiptapEditorComponent, DEFAULT_BUBBLE_MENU_CONFIG, DEFAULT_CELL_MENU_CONFIG, DEFAULT_IMAGE_BUBBLE_MENU_CONFIG, DEFAULT_SLASH_COMMANDS, DEFAULT_TABLE_MENU_CONFIG, DEFAULT_TOOLBAR_CONFIG, NoopValueAccessorDirective, TiptapI18nService, createI18nSlashCommands };
|
|
5226
|
+
export { AngularTiptapEditorComponent, DEFAULT_BUBBLE_MENU_CONFIG, DEFAULT_CELL_MENU_CONFIG, DEFAULT_IMAGE_BUBBLE_MENU_CONFIG, DEFAULT_SLASH_COMMANDS$1 as DEFAULT_SLASH_COMMANDS, DEFAULT_TABLE_MENU_CONFIG, DEFAULT_TOOLBAR_CONFIG, EditorCommandsService, ImageService, NoopValueAccessorDirective, SLASH_COMMAND_KEYS, TiptapI18nService, createI18nSlashCommands, filterSlashCommands };
|
|
5175
5227
|
//# sourceMappingURL=flogeez-angular-tiptap-editor.mjs.map
|