@solidev/data 1.1.0 → 1.1.2
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/AGENTS.md +21 -2
- package/fesm2022/solidev-data-mdedit.mjs +27 -112
- package/fesm2022/solidev-data-mdedit.mjs.map +1 -1
- package/fesm2022/solidev-data-richedit.mjs +31 -139
- package/fesm2022/solidev-data-richedit.mjs.map +1 -1
- package/fesm2022/solidev-data.mjs +288 -11
- package/fesm2022/solidev-data.mjs.map +1 -1
- package/package.json +1 -1
- package/types/solidev-data-mdedit.d.ts +13 -64
- package/types/solidev-data-richedit.d.ts +8 -65
- package/types/solidev-data.d.ts +180 -8
package/AGENTS.md
CHANGED
|
@@ -373,6 +373,13 @@ Notes worth knowing:
|
|
|
373
373
|
|
|
374
374
|
### 7.1 Long text — `<data-richedit>` and `<data-mdedit>`
|
|
375
375
|
|
|
376
|
+
**They are not dispedit editors.** `dispedit` lives in the primary entry point and
|
|
377
|
+
cannot import a secondary one, so use these components directly. For the
|
|
378
|
+
read-only half, point a dispedit at the rendered `…_html` column with
|
|
379
|
+
`[viewer]="'html'"` — that renders trusted HTML, and covers markdown too
|
|
380
|
+
wherever the rendered form is stored alongside the source. It does **not** sanitize: use it
|
|
381
|
+
only on HTML your own editor produced.
|
|
382
|
+
|
|
376
383
|
Two editors live in their own entry points, so they are only pulled in if imported:
|
|
377
384
|
|
|
378
385
|
```html
|
|
@@ -383,8 +390,16 @@ Two editors live in their own entry points, so they are only pulled in if import
|
|
|
383
390
|
<data-mdedit [model]="thing" field="notes" toolbar="light">Notes</data-mdedit>
|
|
384
391
|
```
|
|
385
392
|
|
|
386
|
-
Same inputs on both (`model`, `field`, `mode`, `edit`, `editable`,
|
|
387
|
-
`hideButton`, `fc`, `toolbar`), one output (`changed`).
|
|
393
|
+
Same inputs on both (`model`, `field`, `htmlField`, `mode`, `edit`, `editable`,
|
|
394
|
+
`hideLabel`, `hideButton`, `fc`, `form`, `toolbar`), one output (`changed`).
|
|
395
|
+
|
|
396
|
+
- **They show the value first.** In `dd` mode a click on the value or the label
|
|
397
|
+
reveals the editor, exactly like dispedit; `[editable]="false"` forbids it.
|
|
398
|
+
`inline` and `form` show the editor straight away.
|
|
399
|
+
- **`field` names a pair.** Given `field="description"` they edit
|
|
400
|
+
`description_src` and display `description_html` when the model declares them,
|
|
401
|
+
and fall back to `description` for both when it does not. `[htmlField]`
|
|
402
|
+
overrides the display half.
|
|
388
403
|
|
|
389
404
|
- **They do not auto-save.** Unlike dispedit, the value reaches the API only when
|
|
390
405
|
the built-in save button runs `save()`, and only in `mode="dd"`. In `inline` and
|
|
@@ -394,6 +409,10 @@ Same inputs on both (`model`, `field`, `mode`, `edit`, `editable`, `hideLabel`,
|
|
|
394
409
|
- **No extra install.** `prosemirror-*` and `@codemirror/*` are ordinary peer
|
|
395
410
|
dependencies, so npm brings them in with the library. Neither reaches the
|
|
396
411
|
application bundle unless its entry point is imported.
|
|
412
|
+
- **Rendering a `…_html` column elsewhere** needs `SafeHtmlPipe` from
|
|
413
|
+
`@solidev/data`: `<div [innerHTML]="thing.notes_html | safeHtml"></div>`.
|
|
414
|
+
Angular's sanitizer drops the inline styles the editor writes, so a plain
|
|
415
|
+
`[innerHTML]` renders alignment and colours away. Server-produced HTML only.
|
|
397
416
|
- **Testing needs `installEditorDomShims()`** from `@solidev/data`, called in
|
|
398
417
|
`beforeEach` — jsdom has no layout engine and both editors measure the document.
|
|
399
418
|
Then `await fixture.whenStable()`, since both mount in `afterNextRender`.
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input,
|
|
2
|
+
import { input, signal, computed, viewChild, inject, DestroyRef, afterRenderEffect, Component } from '@angular/core';
|
|
3
3
|
import { NgTemplateOutlet } from '@angular/common';
|
|
4
|
-
import { FormControl } from '@angular/forms';
|
|
5
4
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
6
|
-
import {
|
|
5
|
+
import { FieldEditorBase, SafeHtmlPipe } from '@solidev/data';
|
|
7
6
|
import { EditorState, EditorSelection, Compartment } from '@codemirror/state';
|
|
8
7
|
import { EditorView, keymap, placeholder } from '@codemirror/view';
|
|
9
|
-
import { firstValueFrom } from 'rxjs';
|
|
10
8
|
import { markdown, markdownLanguage } from '@codemirror/lang-markdown';
|
|
11
9
|
import { history, historyKeymap, defaultKeymap } from '@codemirror/commands';
|
|
12
10
|
import { HighlightStyle, syntaxHighlighting, syntaxTree } from '@codemirror/language';
|
|
@@ -437,71 +435,18 @@ const NOTHING_ACTIVE = {
|
|
|
437
435
|
* <data-mdedit [model]="thing" field="description">Description</data-mdedit>
|
|
438
436
|
* ```
|
|
439
437
|
*/
|
|
440
|
-
class MdeditComponent {
|
|
441
|
-
/** Id tying the label to the editor. */
|
|
442
|
-
inputId = uniqueId('data-mdedit');
|
|
443
|
-
/** Id of the label element, wired to the editor through `aria-labelledby`. */
|
|
444
|
-
labelId = `${this.inputId}-label`;
|
|
445
|
-
/** Model instance holding the field. */
|
|
446
|
-
model = input(/* @ts-ignore */
|
|
447
|
-
...(ngDevMode ? [undefined, { debugName: "model" }] : /* istanbul ignore next */ []));
|
|
448
|
-
/** Name of the markdown field to edit. */
|
|
449
|
-
field = input(/* @ts-ignore */
|
|
450
|
-
...(ngDevMode ? [undefined, { debugName: "field" }] : /* istanbul ignore next */ []));
|
|
451
|
-
/** Whether {@link toggleEdit} is allowed to enable editing. */
|
|
452
|
-
editable = input(true, /* @ts-ignore */
|
|
453
|
-
...(ngDevMode ? [{ debugName: "editable" }] : /* istanbul ignore next */ []));
|
|
454
|
-
/** Whether the editor is currently enabled. Defaults to true. */
|
|
455
|
-
edit = model(true, /* @ts-ignore */
|
|
456
|
-
...(ngDevMode ? [{ debugName: "edit" }] : /* istanbul ignore next */ []));
|
|
457
|
-
/**
|
|
458
|
-
* Layout, and whether {@link save} persists.
|
|
459
|
-
*
|
|
460
|
-
* `dd` renders a `<dt>`/`<dd>` block and is the only mode that saves to the
|
|
461
|
-
* API; `inline` and `form` render a label plus the editor and leave saving to
|
|
462
|
-
* the caller.
|
|
463
|
-
*/
|
|
464
|
-
mode = input('dd', /* @ts-ignore */
|
|
465
|
-
...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
|
|
466
|
-
/** Hide label (for inline forms). */
|
|
467
|
-
hideLabel = input(false, /* @ts-ignore */
|
|
468
|
-
...(ngDevMode ? [{ debugName: "hideLabel" }] : /* istanbul ignore next */ []));
|
|
469
|
-
/**
|
|
470
|
-
* Hide the built-in save button, for callers driving persistence themselves
|
|
471
|
-
* from the {@link changed} output.
|
|
472
|
-
*/
|
|
473
|
-
hideButton = input(false, /* @ts-ignore */
|
|
474
|
-
...(ngDevMode ? [{ debugName: "hideButton" }] : /* istanbul ignore next */ []));
|
|
475
|
-
/**
|
|
476
|
-
* Form control backing the editor.
|
|
477
|
-
*
|
|
478
|
-
* When supplied, the component uses it as-is and skips its own setup — no
|
|
479
|
-
* field manager lookup, no seeding from the model, and no {@link changed}
|
|
480
|
-
* emissions. When absent, one is created and wired up from `[model]` and
|
|
481
|
-
* `[field]`.
|
|
482
|
-
*/
|
|
483
|
-
fc = input(/* @ts-ignore */
|
|
484
|
-
...(ngDevMode ? [undefined, { debugName: "fc" }] : /* istanbul ignore next */ []));
|
|
438
|
+
class MdeditComponent extends FieldEditorBase {
|
|
485
439
|
/** Toolbar preset name from {@link MdEditToolbars}, or an explicit toolbar. */
|
|
486
440
|
toolbar = input('default', /* @ts-ignore */
|
|
487
441
|
...(ngDevMode ? [{ debugName: "toolbar" }] : /* istanbul ignore next */ []));
|
|
488
442
|
/** Text shown while the document is empty. */
|
|
489
443
|
placeholder = input('', /* @ts-ignore */
|
|
490
444
|
...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
|
|
491
|
-
/** Emits the markdown source on every change. Only wired for an internal `fc`. */
|
|
492
|
-
changed = output();
|
|
493
|
-
/** Field manager for {@link field}; only resolved when `fc` is created here. */
|
|
494
|
-
manager;
|
|
495
|
-
/** Whether the manager declares the field required. */
|
|
496
|
-
required = signal(false, /* @ts-ignore */
|
|
497
|
-
...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
|
|
498
445
|
/** Markdown constructs under the cursor, driving `aria-pressed`. */
|
|
499
446
|
active = signal(NOTHING_ACTIVE, /* @ts-ignore */
|
|
500
447
|
...(ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []));
|
|
501
448
|
/** Heading levels offered by the dropdown. */
|
|
502
449
|
headingLevels = HEADING_LEVELS;
|
|
503
|
-
/** The control actually in use: the supplied `[fc]`, or the internal one. */
|
|
504
|
-
control;
|
|
505
450
|
/** Toolbar resolved from {@link toolbar}, as entries the template can render. */
|
|
506
451
|
groups = computed(() => {
|
|
507
452
|
const requested = this.toolbar();
|
|
@@ -518,36 +463,23 @@ class MdeditComponent {
|
|
|
518
463
|
readOnly = new Compartment();
|
|
519
464
|
view;
|
|
520
465
|
constructor() {
|
|
521
|
-
|
|
522
|
-
//
|
|
523
|
-
|
|
466
|
+
super();
|
|
467
|
+
// Not afterNextRender: the host element only exists while the editor is
|
|
468
|
+
// showing, so toggling out of the read-only view and back in has to mount
|
|
469
|
+
// again. afterRenderEffect re-runs as the host signal changes, and like
|
|
470
|
+
// afterNextRender it never runs under SSR.
|
|
471
|
+
afterRenderEffect(() => this.syncView());
|
|
524
472
|
this.destroyRef.onDestroy(() => this.view?.destroy());
|
|
525
473
|
}
|
|
526
474
|
/**
|
|
527
|
-
*
|
|
528
|
-
*
|
|
529
|
-
*
|
|
475
|
+
* Wire the resolved control to the editor, in both directions.
|
|
476
|
+
*
|
|
477
|
+
* The base picks the control (`[fc]`, `[form]`, or its own) and seeds it;
|
|
478
|
+
* this adds the CodeMirror half.
|
|
530
479
|
*/
|
|
531
480
|
ngOnInit() {
|
|
532
|
-
|
|
533
|
-
if (
|
|
534
|
-
this.control = supplied;
|
|
535
|
-
}
|
|
536
|
-
else {
|
|
537
|
-
this.control = new FormControl('');
|
|
538
|
-
const model = this.model();
|
|
539
|
-
const field = this.field();
|
|
540
|
-
if (model && field) {
|
|
541
|
-
this.manager = model.FM(field);
|
|
542
|
-
this.required.set(this.manager?.required ?? false);
|
|
543
|
-
this.control.setValue(asText(fieldValues(model)[field]), { emitEvent: false });
|
|
544
|
-
}
|
|
545
|
-
if (this.edit()) {
|
|
546
|
-
this.control.enable();
|
|
547
|
-
}
|
|
548
|
-
else {
|
|
549
|
-
this.control.disable();
|
|
550
|
-
}
|
|
481
|
+
super.ngOnInit();
|
|
482
|
+
if (!this.fc()) {
|
|
551
483
|
this.control.valueChanges
|
|
552
484
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
553
485
|
.subscribe((value) => this.changed.emit(value));
|
|
@@ -559,20 +491,6 @@ class MdeditComponent {
|
|
|
559
491
|
this.control.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((value) => this.applyValue(value));
|
|
560
492
|
this.control.statusChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => this.applyEditable());
|
|
561
493
|
}
|
|
562
|
-
/**
|
|
563
|
-
* Switch between read-only and editing by enabling or disabling the control.
|
|
564
|
-
* Forces read-only when `[editable]` is false.
|
|
565
|
-
*/
|
|
566
|
-
toggleEdit() {
|
|
567
|
-
if (this.editable() && !this.edit()) {
|
|
568
|
-
this.control.enable();
|
|
569
|
-
this.edit.set(true);
|
|
570
|
-
}
|
|
571
|
-
else {
|
|
572
|
-
this.control.disable();
|
|
573
|
-
this.edit.set(false);
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
494
|
/**
|
|
577
495
|
* Run a toolbar command against the editor and hand focus back, so a click
|
|
578
496
|
* on the toolbar does not take the caret out of the document.
|
|
@@ -589,22 +507,19 @@ class MdeditComponent {
|
|
|
589
507
|
this.run(setHeading(Number(value)));
|
|
590
508
|
}
|
|
591
509
|
/**
|
|
592
|
-
*
|
|
593
|
-
* mode only.
|
|
510
|
+
* Build or tear down the CodeMirror view, following the host element.
|
|
594
511
|
*
|
|
595
|
-
*
|
|
596
|
-
*
|
|
597
|
-
*
|
|
512
|
+
* Toggling back to the read-only view removes the host, which would leave a
|
|
513
|
+
* detached view behind and make the next mount a no-op. The control keeps the
|
|
514
|
+
* value across the round trip, so a fresh view is seeded correctly.
|
|
598
515
|
*/
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
516
|
+
syncView() {
|
|
517
|
+
if (!this.host()) {
|
|
518
|
+
this.view?.destroy();
|
|
519
|
+
this.view = undefined;
|
|
603
520
|
return;
|
|
604
|
-
model.setFV(field, this.control.value);
|
|
605
|
-
if (this.mode() === 'dd') {
|
|
606
|
-
await firstValueFrom(model.update([field], { updateModel: true }));
|
|
607
521
|
}
|
|
522
|
+
this.mount();
|
|
608
523
|
}
|
|
609
524
|
/** Build the CodeMirror view inside the host element. */
|
|
610
525
|
mount() {
|
|
@@ -653,12 +568,12 @@ class MdeditComponent {
|
|
|
653
568
|
this.view?.dispatch({ effects: this.readOnly.reconfigure(readOnlyExtension(this.control.disabled)) });
|
|
654
569
|
}
|
|
655
570
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: MdeditComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
656
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: MdeditComponent, isStandalone: true, selector: "data-mdedit", inputs: {
|
|
571
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: MdeditComponent, isStandalone: true, selector: "data-mdedit", inputs: { toolbar: { classPropertyName: "toolbar", publicName: "toolbar", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "host", first: true, predicate: ["editorHost"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<ng-template #editorTemplate>\n @if (!showEditor()) {\n <!--\n Read-only: the rendered HTML twin of the source, injected as trusted\n markup. See SafeHtmlPipe.\n -->\n <div\n class=\"editable data-mdedit__view\"\n role=\"button\"\n tabindex=\"0\"\n (click)=\"toggleEdit()\"\n (keydown.enter)=\"toggleEdit()\"\n (keydown.space)=\"$event.preventDefault(); toggleEdit()\"\n [innerHTML]=\"displayValue() | safeHtml\"\n ></div>\n } @else {\n <ng-container [ngTemplateOutlet]=\"editorBody\"></ng-container>\n }\n</ng-template>\n<ng-template #editorBody>\n @if (groups().length) {\n <div class=\"btn-toolbar data-mdedit__toolbar\" role=\"toolbar\" aria-label=\"Mise en forme du markdown\">\n @for (group of groups(); track $index) {\n <div class=\"btn-group btn-group-sm me-1\">\n @for (entry of group; track entry.label) {\n @if (entry.kind === \"button\") {\n <button\n type=\"button\"\n class=\"btn btn-sm btn-outline-secondary\"\n [class.active]=\"active()[entry.active]\"\n [attr.aria-pressed]=\"active()[entry.active]\"\n [attr.aria-label]=\"entry.label\"\n [title]=\"entry.label\"\n (click)=\"run(entry.command)\"\n >\n <i class=\"bi {{ entry.icon }}\" aria-hidden=\"true\"></i>\n </button>\n } @else {\n <select\n #headingSelect\n class=\"form-select form-select-sm data-mdedit__headings\"\n [attr.aria-label]=\"entry.label\"\n [title]=\"entry.label\"\n [value]=\"active().heading\"\n (change)=\"setHeadingLevel(headingSelect.value)\"\n >\n @for (level of headingLevels; track level.level) {\n <option [value]=\"level.level\">{{ level.label }}</option>\n }\n </select>\n }\n }\n </div>\n }\n </div>\n }\n <div #editorHost class=\"data-mdedit__host\" [attr.id]=\"inputId\"></div>\n @if (!hideButton()) {\n <button class=\"btn btn-primary btn-sm w-100 mt-1\" (click)=\"save()\">\n <i class=\"bi bi-save me-2\"></i>\n Enregistrer\n </button>\n }\n</ng-template>\n<ng-template #titleTpl>\n <ng-content></ng-content>\n</ng-template>\n<!-- Dd display-->\n@if (mode() === \"dd\") {\n @if (!hideLabel()) {\n <dt [class.required]=\"required()\">\n <span\n class=\"editable\"\n [attr.id]=\"labelId\"\n (click)=\"toggleEdit()\"\n role=\"button\"\n tabindex=\"0\"\n (keydown.enter)=\"toggleEdit()\"\n (keydown.space)=\"$event.preventDefault(); toggleEdit()\"\n >\n <ng-container [ngTemplateOutlet]=\"titleTpl\"></ng-container>\n </span>\n </dt>\n }\n <dd [class.mb-0]=\"hideLabel()\">\n <ng-container [ngTemplateOutlet]=\"editorTemplate\"></ng-container>\n </dd>\n}\n<!-- Inline display-->\n@if (mode() === \"inline\") {\n @if (!hideLabel()) {\n <label [class.required]=\"required()\" [attr.id]=\"labelId\" [attr.for]=\"inputId\">\n <ng-container [ngTemplateOutlet]=\"titleTpl\"></ng-container>\n </label>\n }\n <ng-container [ngTemplateOutlet]=\"editorTemplate\"></ng-container>\n}\n<!-- Form display-->\n@if (mode() === \"form\") {\n @if (!hideLabel()) {\n <label [class.required]=\"required()\" [attr.id]=\"labelId\" [attr.for]=\"inputId\">\n <ng-container [ngTemplateOutlet]=\"titleTpl\"></ng-container>\n </label>\n }\n <ng-container [ngTemplateOutlet]=\"editorTemplate\"></ng-container>\n}\n", styles: [".data-mdedit__toolbar{flex-wrap:wrap;gap:.25rem 0;margin-bottom:.25rem}.data-mdedit__headings{width:auto}.data-mdedit__host .cm-editor{height:100%}.data-mdedit__view>*:first-child{margin-top:0}.data-mdedit__view>*:last-child{margin-bottom:0}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: SafeHtmlPipe, name: "safeHtml" }] });
|
|
657
572
|
}
|
|
658
573
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: MdeditComponent, decorators: [{
|
|
659
574
|
type: Component,
|
|
660
|
-
args: [{ selector: 'data-mdedit', imports: [NgTemplateOutlet], template: "<ng-template #editorTemplate>\n @if (
|
|
661
|
-
}], ctorParameters: () => [], propDecorators: {
|
|
575
|
+
args: [{ selector: 'data-mdedit', imports: [NgTemplateOutlet, SafeHtmlPipe], template: "<ng-template #editorTemplate>\n @if (!showEditor()) {\n <!--\n Read-only: the rendered HTML twin of the source, injected as trusted\n markup. See SafeHtmlPipe.\n -->\n <div\n class=\"editable data-mdedit__view\"\n role=\"button\"\n tabindex=\"0\"\n (click)=\"toggleEdit()\"\n (keydown.enter)=\"toggleEdit()\"\n (keydown.space)=\"$event.preventDefault(); toggleEdit()\"\n [innerHTML]=\"displayValue() | safeHtml\"\n ></div>\n } @else {\n <ng-container [ngTemplateOutlet]=\"editorBody\"></ng-container>\n }\n</ng-template>\n<ng-template #editorBody>\n @if (groups().length) {\n <div class=\"btn-toolbar data-mdedit__toolbar\" role=\"toolbar\" aria-label=\"Mise en forme du markdown\">\n @for (group of groups(); track $index) {\n <div class=\"btn-group btn-group-sm me-1\">\n @for (entry of group; track entry.label) {\n @if (entry.kind === \"button\") {\n <button\n type=\"button\"\n class=\"btn btn-sm btn-outline-secondary\"\n [class.active]=\"active()[entry.active]\"\n [attr.aria-pressed]=\"active()[entry.active]\"\n [attr.aria-label]=\"entry.label\"\n [title]=\"entry.label\"\n (click)=\"run(entry.command)\"\n >\n <i class=\"bi {{ entry.icon }}\" aria-hidden=\"true\"></i>\n </button>\n } @else {\n <select\n #headingSelect\n class=\"form-select form-select-sm data-mdedit__headings\"\n [attr.aria-label]=\"entry.label\"\n [title]=\"entry.label\"\n [value]=\"active().heading\"\n (change)=\"setHeadingLevel(headingSelect.value)\"\n >\n @for (level of headingLevels; track level.level) {\n <option [value]=\"level.level\">{{ level.label }}</option>\n }\n </select>\n }\n }\n </div>\n }\n </div>\n }\n <div #editorHost class=\"data-mdedit__host\" [attr.id]=\"inputId\"></div>\n @if (!hideButton()) {\n <button class=\"btn btn-primary btn-sm w-100 mt-1\" (click)=\"save()\">\n <i class=\"bi bi-save me-2\"></i>\n Enregistrer\n </button>\n }\n</ng-template>\n<ng-template #titleTpl>\n <ng-content></ng-content>\n</ng-template>\n<!-- Dd display-->\n@if (mode() === \"dd\") {\n @if (!hideLabel()) {\n <dt [class.required]=\"required()\">\n <span\n class=\"editable\"\n [attr.id]=\"labelId\"\n (click)=\"toggleEdit()\"\n role=\"button\"\n tabindex=\"0\"\n (keydown.enter)=\"toggleEdit()\"\n (keydown.space)=\"$event.preventDefault(); toggleEdit()\"\n >\n <ng-container [ngTemplateOutlet]=\"titleTpl\"></ng-container>\n </span>\n </dt>\n }\n <dd [class.mb-0]=\"hideLabel()\">\n <ng-container [ngTemplateOutlet]=\"editorTemplate\"></ng-container>\n </dd>\n}\n<!-- Inline display-->\n@if (mode() === \"inline\") {\n @if (!hideLabel()) {\n <label [class.required]=\"required()\" [attr.id]=\"labelId\" [attr.for]=\"inputId\">\n <ng-container [ngTemplateOutlet]=\"titleTpl\"></ng-container>\n </label>\n }\n <ng-container [ngTemplateOutlet]=\"editorTemplate\"></ng-container>\n}\n<!-- Form display-->\n@if (mode() === \"form\") {\n @if (!hideLabel()) {\n <label [class.required]=\"required()\" [attr.id]=\"labelId\" [attr.for]=\"inputId\">\n <ng-container [ngTemplateOutlet]=\"titleTpl\"></ng-container>\n </label>\n }\n <ng-container [ngTemplateOutlet]=\"editorTemplate\"></ng-container>\n}\n", styles: [".data-mdedit__toolbar{flex-wrap:wrap;gap:.25rem 0;margin-bottom:.25rem}.data-mdedit__headings{width:auto}.data-mdedit__host .cm-editor{height:100%}.data-mdedit__view>*:first-child{margin-top:0}.data-mdedit__view>*:last-child{margin-bottom:0}\n"] }]
|
|
576
|
+
}], ctorParameters: () => [], propDecorators: { toolbar: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolbar", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], host: [{ type: i0.ViewChild, args: ['editorHost', { isSignal: true }] }] } });
|
|
662
577
|
|
|
663
578
|
/**
|
|
664
579
|
* Generated bundle index. Do not edit.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"solidev-data-mdedit.mjs","sources":["../../../projects/data/mdedit/cm/markdown-theme.ts","../../../projects/data/mdedit/cm/markdown-setup.ts","../../../projects/data/mdedit/cm/toolbar-commands.ts","../../../projects/data/mdedit/mdedit.component.ts","../../../projects/data/mdedit/mdedit.component.html","../../../projects/data/mdedit/solidev-data-mdedit.ts"],"sourcesContent":["import { HighlightStyle, syntaxHighlighting } from '@codemirror/language';\nimport { Extension } from '@codemirror/state';\nimport { EditorView } from '@codemirror/view';\nimport { tags } from '@lezer/highlight';\n\n/**\n * Syntax highlighting for the markdown *source*.\n *\n * The point of `mdedit` is that the markup stays on screen: `**bold**` keeps\n * its asterisks, a heading keeps its `#`. What this style does is make the\n * source read like the document it describes — headings get bigger, `**bold**`\n * renders bold, code turns monospace — while the markers themselves\n * ({@link tags.processingInstruction}, {@link tags.meta}) are dimmed so they\n * stay visible but recede.\n *\n * Colours come from Bootstrap CSS variables so the editor follows the host\n * theme, including its dark mode, without shipping a palette of its own.\n */\nexport const markdownHighlightStyle = HighlightStyle.define([\n { tag: tags.heading1, fontSize: '1.6em', fontWeight: 'bold', lineHeight: '1.4' },\n { tag: tags.heading2, fontSize: '1.4em', fontWeight: 'bold', lineHeight: '1.4' },\n { tag: tags.heading3, fontSize: '1.25em', fontWeight: 'bold' },\n { tag: tags.heading4, fontSize: '1.15em', fontWeight: 'bold' },\n { tag: tags.heading5, fontSize: '1.05em', fontWeight: 'bold' },\n { tag: tags.heading6, fontSize: '1em', fontWeight: 'bold' },\n { tag: tags.strong, fontWeight: 'bold' },\n { tag: tags.emphasis, fontStyle: 'italic' },\n { tag: tags.strikethrough, textDecoration: 'line-through' },\n { tag: tags.link, textDecoration: 'underline' },\n { tag: tags.url, color: 'var(--bs-link-color, #0d6efd)', textDecoration: 'underline' },\n {\n tag: tags.monospace,\n fontFamily: 'var(--bs-font-monospace, monospace)',\n backgroundColor: 'var(--bs-tertiary-bg, rgba(0, 0, 0, 0.05))',\n },\n { tag: tags.quote, color: 'var(--bs-secondary-color, #6c757d)', fontStyle: 'italic' },\n { tag: tags.contentSeparator, fontWeight: 'bold', color: 'var(--bs-secondary-color, #6c757d)' },\n { tag: tags.list, color: 'var(--bs-emphasis-color, #000)' },\n // The markup itself: `#`, `*`, `>`, backticks, list bullets. Dimmed rather\n // than hidden -- this is a source editor, not a WYSIWYG.\n { tag: tags.processingInstruction, color: 'var(--bs-secondary-color, #6c757d)' },\n { tag: tags.meta, color: 'var(--bs-secondary-color, #6c757d)' },\n]);\n\n/**\n * Editor chrome: a box that matches Bootstrap's `.form-control`, including its\n * focus ring, so an `mdedit` sits in a form without looking foreign.\n */\nexport const markdownTheme = EditorView.theme({\n '&': {\n fontSize: 'inherit',\n color: 'var(--bs-body-color, #212529)',\n backgroundColor: 'var(--bs-body-bg, #fff)',\n border: 'var(--bs-border-width, 1px) solid var(--bs-border-color, #dee2e6)',\n borderRadius: 'var(--bs-border-radius, 0.375rem)',\n },\n '&.cm-focused': {\n outline: 'none',\n borderColor: 'var(--bs-primary-border-subtle, #86b7fe)',\n boxShadow: '0 0 0 0.25rem rgba(var(--bs-primary-rgb, 13, 110, 253), 0.25)',\n },\n '.cm-content': {\n fontFamily: 'var(--bs-body-font-family, system-ui, sans-serif)',\n padding: '0.5rem 0.75rem',\n minHeight: '8rem',\n caretColor: 'var(--bs-body-color, #212529)',\n },\n '.cm-line': {\n padding: '0',\n },\n '.cm-placeholder': {\n color: 'var(--bs-secondary-color, #6c757d)',\n },\n '&.cm-editor.cm-readonly .cm-content, &.cm-editor:not(.cm-focused) .cm-content': {\n caretColor: 'transparent',\n },\n});\n\n/**\n * The whole visual layer — chrome plus source highlighting — as one extension,\n * which is what {@link markdownSetup} installs.\n */\nexport function markdownStyling(): Extension {\n return [markdownTheme, syntaxHighlighting(markdownHighlightStyle)];\n}\n","import { markdown, markdownLanguage } from '@codemirror/lang-markdown';\nimport { defaultKeymap, history, historyKeymap } from '@codemirror/commands';\nimport { Compartment, EditorState, Extension } from '@codemirror/state';\nimport { EditorView, keymap, placeholder as cmPlaceholder } from '@codemirror/view';\nimport { markdownStyling } from './markdown-theme';\n\n/** Options accepted by {@link markdownSetup}. */\nexport interface MarkdownSetupOptions {\n /**\n * Compartment the read-only extensions are installed in, so the caller can\n * flip editability later with `compartment.reconfigure(readOnlyExtension(v))`.\n * Create one per editor instance — compartments are not shareable.\n */\n readOnly?: Compartment;\n /** Whether the editor starts read-only. */\n readOnlyInitially?: boolean;\n /** Text shown while the document is empty. */\n placeholder?: string;\n /** Called with the full markdown source after every document change. */\n onChange?: (doc: string) => void;\n /** Called after every state update, for toolbar active-state tracking. */\n onStateChange?: (state: EditorState) => void;\n /** Id of the element labelling the editor, wired as `aria-labelledby`. */\n labelledBy?: string;\n}\n\n/**\n * The extensions that make an `EditorView` behave as a markdown source editor.\n *\n * Deliberately not CodeMirror's `basicSetup`: this edits prose, so there are no\n * line numbers, no fold gutter and no bracket matching — just markdown parsing,\n * history, wrapping, and the styling from {@link markdownStyling}.\n *\n * The markdown dialect is `markdownLanguage`, i.e. GFM: tables, strikethrough\n * and task lists parse. Fenced code blocks are recognised but their content is\n * not highlighted per-language; that would need `@codemirror/language-data` and\n * its lazily loaded grammars, which is out of scope here.\n */\nexport function markdownSetup(options: MarkdownSetupOptions = {}): Extension[] {\n const extensions: Extension[] = [\n history(),\n // Our bindings come first so undo/redo and the markdown list-continuation\n // keys win over the language's own defaults.\n keymap.of([...historyKeymap, ...defaultKeymap]),\n markdown({ base: markdownLanguage, addKeymap: true }),\n EditorView.lineWrapping,\n markdownStyling(),\n ];\n if (options.placeholder) {\n extensions.push(cmPlaceholder(options.placeholder));\n }\n if (options.labelledBy) {\n extensions.push(EditorView.contentAttributes.of({ 'aria-labelledby': options.labelledBy }));\n }\n const { onChange, onStateChange } = options;\n if (onChange || onStateChange) {\n extensions.push(\n EditorView.updateListener.of((update) => {\n if (onChange && update.docChanged) {\n onChange(update.state.doc.toString());\n }\n if (onStateChange && (update.docChanged || update.selectionSet || update.focusChanged)) {\n onStateChange(update.state);\n }\n }),\n );\n }\n if (options.readOnly) {\n extensions.push(options.readOnly.of(readOnlyExtension(options.readOnlyInitially ?? false)));\n } else if (options.readOnlyInitially) {\n extensions.push(readOnlyExtension(true));\n }\n return extensions;\n}\n\n/**\n * Read-only state for a given editability, meant to be reconfigured into the\n * compartment passed to {@link markdownSetup}.\n *\n * Both facets are needed: `EditorState.readOnly` stops commands from changing\n * the document, `EditorView.editable` takes `contenteditable` off the DOM node\n * so the caret and the browser's own editing affordances go away too.\n */\nexport function readOnlyExtension(readOnly: boolean): Extension {\n return [EditorState.readOnly.of(readOnly), EditorView.editable.of(!readOnly)];\n}\n","import { syntaxTree } from '@codemirror/language';\nimport { ChangeSpec, EditorSelection, EditorState, Line, StateCommand } from '@codemirror/state';\n\n/**\n * Markdown editing commands, written as CodeMirror `StateCommand`s.\n *\n * A `StateCommand` only needs `{state, dispatch}`, which an `EditorView`\n * satisfies — so these drive the toolbar buttons in the browser, and can be\n * exercised in a spec against a bare `EditorState`, with no DOM at all. They\n * rewrite the markdown source, since that is what the user sees and edits.\n */\n\n/**\n * Lines touched by the selection, in document order and without duplicates.\n *\n * Selection ranges are sorted and non-overlapping, so tracking the last line\n * number emitted is enough to keep a line from being rewritten twice when two\n * cursors sit on it.\n */\nfunction selectedLines(state: EditorState): Line[] {\n const lines: Line[] = [];\n let last = -1;\n for (const range of state.selection.ranges) {\n for (let pos = range.from; pos <= range.to;) {\n const line = state.doc.lineAt(pos);\n if (line.number > last) {\n lines.push(line);\n last = line.number;\n }\n pos = line.to + 1;\n }\n }\n return lines;\n}\n\n/**\n * Toggle a symmetric inline delimiter — `**` for bold, `*` for italic, `~~` for\n * strikethrough, `` ` `` for code.\n *\n * Wraps the selection, or unwraps it when the delimiters are already there,\n * whether they sit just outside the selection (the usual case after a previous\n * toggle) or inside it (the user selected them along with the text). On an\n * empty selection it inserts the pair and leaves the cursor between the two\n * halves, so typing continues inside the mark.\n */\nexport function toggleInlineMark(delim: string): StateCommand {\n const len = delim.length;\n return ({ state, dispatch }) => {\n const transaction = state.changeByRange((range) => {\n if (\n !range.empty &&\n state.sliceDoc(range.from - len, range.from) === delim &&\n state.sliceDoc(range.to, range.to + len) === delim\n ) {\n return {\n changes: [\n { from: range.from - len, to: range.from },\n { from: range.to, to: range.to + len },\n ],\n range: EditorSelection.range(range.from - len, range.to - len),\n };\n }\n const text = state.sliceDoc(range.from, range.to);\n if (text.length >= 2 * len && text.startsWith(delim) && text.endsWith(delim)) {\n return {\n changes: [\n { from: range.from, to: range.from + len },\n { from: range.to - len, to: range.to },\n ],\n range: EditorSelection.range(range.from, range.to - 2 * len),\n };\n }\n return {\n changes: [\n { from: range.from, insert: delim },\n { from: range.to, insert: delim },\n ],\n range: range.empty\n ? EditorSelection.cursor(range.from + len)\n : EditorSelection.range(range.from + len, range.to + len),\n };\n });\n dispatch(state.update(transaction, { scrollIntoView: true, userEvent: 'input' }));\n return true;\n };\n}\n\n/** Toggle `**bold**` around the selection. */\nexport const toggleBold = toggleInlineMark('**');\n/** Toggle `*italic*` around the selection. */\nexport const toggleItalic = toggleInlineMark('*');\n/** Toggle `~~strikethrough~~` around the selection (GFM). */\nexport const toggleStrikethrough = toggleInlineMark('~~');\n/** Toggle `` `code` `` around the selection. */\nexport const toggleInlineCode = toggleInlineMark('`');\n\n/** Leading ATX heading markup, e.g. `### `. */\nconst HEADING = /^#{1,6} */;\n\n/**\n * Set the heading level of every selected line, `0` meaning plain paragraph.\n *\n * This sets rather than toggles: picking \"Heading 2\" twice leaves an `h2`, and\n * the way back to a paragraph is `setHeading(0)` — which is what the toolbar's\n * \"Paragraphe\" entry does. Returns false when nothing would change, as a\n * CodeMirror command should.\n */\nexport function setHeading(level: number): StateCommand {\n const prefix = level > 0 ? `${'#'.repeat(level)} ` : '';\n return ({ state, dispatch }) => {\n const changes: ChangeSpec[] = [];\n for (const line of selectedLines(state)) {\n const current = HEADING.exec(line.text)?.[0] ?? '';\n if (current === prefix) continue;\n changes.push({ from: line.from, to: line.from + current.length, insert: prefix });\n }\n if (!changes.length) return false;\n dispatch(state.update({ changes, userEvent: 'input' }));\n return true;\n };\n}\n\n/**\n * Add a line prefix to every selected line, or strip it when all of them\n * already have it.\n *\n * `prefixFor` receives the index of the line within the selection, which is\n * what lets ordered lists number themselves.\n */\nfunction toggleLinePrefix(match: RegExp, prefixFor: (index: number) => string): StateCommand {\n return ({ state, dispatch }) => {\n const lines = selectedLines(state);\n if (!lines.length) return false;\n const strip = lines.every((line) => match.test(line.text));\n const changes: ChangeSpec[] = [];\n lines.forEach((line, index) => {\n const found = match.exec(line.text);\n if (strip) {\n if (found) changes.push({ from: line.from, to: line.from + found[0].length });\n } else if (!found) {\n changes.push({ from: line.from, insert: prefixFor(index) });\n }\n });\n if (!changes.length) return false;\n dispatch(state.update({ changes, userEvent: 'input' }));\n return true;\n };\n}\n\n/** Toggle `> ` blockquote markers on the selected lines. */\nexport const toggleQuote = toggleLinePrefix(/^> ?/, () => '> ');\n/** Toggle `- ` bullets on the selected lines; `*` and `+` bullets count as set. */\nexport const toggleBulletList = toggleLinePrefix(/^[-*+] /, () => '- ');\n/** Toggle `1. ` numbering on the selected lines, renumbering from one. */\nexport const toggleOrderedList = toggleLinePrefix(/^\\d+\\. /, (index) => `${index + 1}. `);\n\n/**\n * Turn the selection into a link.\n *\n * With text selected it becomes `[text](url)` and the `url` placeholder is left\n * selected, ready to be typed over. With no selection the whole\n * `[text](url)` skeleton is inserted and `text` is selected instead.\n */\nexport const insertLink: StateCommand = ({ state, dispatch }) => {\n const transaction = state.changeByRange((range) => {\n if (range.empty) {\n return {\n changes: { from: range.from, insert: '[text](url)' },\n range: EditorSelection.range(range.from + 1, range.from + 5),\n };\n }\n const text = state.sliceDoc(range.from, range.to);\n // '[' + text + '](' puts the url placeholder here.\n const urlFrom = range.from + text.length + 3;\n return {\n changes: { from: range.from, to: range.to, insert: `[${text}](url)` },\n range: EditorSelection.range(urlFrom, urlFrom + 3),\n };\n });\n dispatch(state.update(transaction, { scrollIntoView: true, userEvent: 'input' }));\n return true;\n};\n\n/** What the toolbar needs to know to render its buttons pressed or not. */\nexport interface MarkdownActiveState {\n bold: boolean;\n italic: boolean;\n strike: boolean;\n code: boolean;\n quote: boolean;\n bulletList: boolean;\n orderedList: boolean;\n link: boolean;\n /** Heading level under the cursor, `0` outside any heading. */\n heading: number;\n}\n\n/** Lezer node names, per markdown construct, as produced by `@lezer/markdown`. */\nconst ACTIVE_NODES: Record<Exclude<keyof MarkdownActiveState, 'heading'>, string> = {\n bold: 'StrongEmphasis',\n italic: 'Emphasis',\n strike: 'Strikethrough',\n code: 'InlineCode',\n quote: 'Blockquote',\n bulletList: 'BulletList',\n orderedList: 'OrderedList',\n link: 'Link',\n};\n\n/**\n * Which markdown constructs the cursor currently sits in.\n *\n * Read from the syntax tree rather than by matching the raw text, so nesting\n * and escapes are handled by the parser. Drives `aria-pressed` on the toolbar.\n */\nexport function markdownActive(state: EditorState): MarkdownActiveState {\n const active: MarkdownActiveState = {\n bold: false,\n italic: false,\n strike: false,\n code: false,\n quote: false,\n bulletList: false,\n orderedList: false,\n link: false,\n heading: 0,\n };\n // -1 biases the lookup towards the node ending at the cursor, so a mark stays\n // reported as active with the caret just after its closing delimiter.\n let node = syntaxTree(state).resolveInner(state.selection.main.head, -1);\n const names = Object.entries(ACTIVE_NODES) as [keyof typeof ACTIVE_NODES, string][];\n for (;;) {\n const heading = /^ATXHeading([1-6])$/.exec(node.name);\n if (heading && !active.heading) {\n active.heading = Number(heading[1]);\n }\n for (const [key, nodeName] of names) {\n if (node.name === nodeName) active[key] = true;\n }\n const parent = node.parent;\n if (!parent) return active;\n node = parent;\n }\n}\n","import {\n afterNextRender,\n Component,\n DestroyRef,\n ElementRef,\n computed,\n inject,\n input,\n model,\n OnInit,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { FormControl } from '@angular/forms';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { asText, BaseFieldManager, DataModel, fieldValues, uniqueId } from '@solidev/data';\nimport { Compartment, EditorState, StateCommand } from '@codemirror/state';\nimport { EditorView } from '@codemirror/view';\nimport { firstValueFrom } from 'rxjs';\nimport { markdownSetup, readOnlyExtension } from './cm/markdown-setup';\nimport {\n insertLink,\n markdownActive,\n MarkdownActiveState,\n setHeading,\n toggleBold,\n toggleBulletList,\n toggleInlineCode,\n toggleItalic,\n toggleOrderedList,\n toggleQuote,\n toggleStrikethrough,\n} from './cm/toolbar-commands';\n\n/** A button the `mdedit` toolbar knows how to render. */\nexport type MdToolbarItem =\n 'bold' | 'italic' | 'strike' | 'code' | 'quote' | 'bullet_list' | 'ordered_list' | 'link' | 'heading';\n\n/** Toolbar layout: groups of items, rendered as Bootstrap button groups. */\nexport type MdToolbar = MdToolbarItem[][];\n\n/**\n * Named toolbar presets for {@link MdeditComponent}, selectable through its\n * `toolbar` input.\n *\n * - `default`: marks, a heading dropdown, quote and code, lists, links.\n * - `light`: a reduced set — bold, italic, bullets, links.\n * - `none`: empty; the component hides the toolbar entirely for this value.\n *\n * An `MdToolbar` can also be passed directly when neither preset fits.\n */\nexport const MdEditToolbars: Record<string, MdToolbar> = {\n default: [['bold', 'italic', 'strike'], ['heading'], ['quote', 'code'], ['bullet_list', 'ordered_list'], ['link']],\n light: [['bold', 'italic'], ['bullet_list'], ['link']],\n none: [],\n};\n\n/** What a plain toolbar button needs: an icon, a label, a command, a state. */\ninterface MdButtonDefinition {\n icon: string;\n label: string;\n command: StateCommand;\n active: Exclude<keyof MarkdownActiveState, 'heading'>;\n}\n\nconst BUTTONS: Record<Exclude<MdToolbarItem, 'heading'>, MdButtonDefinition> = {\n bold: { icon: 'bi-type-bold', label: 'Gras', command: toggleBold, active: 'bold' },\n italic: { icon: 'bi-type-italic', label: 'Italique', command: toggleItalic, active: 'italic' },\n strike: { icon: 'bi-type-strikethrough', label: 'Barré', command: toggleStrikethrough, active: 'strike' },\n code: { icon: 'bi-code', label: 'Code', command: toggleInlineCode, active: 'code' },\n quote: { icon: 'bi-blockquote-left', label: 'Citation', command: toggleQuote, active: 'quote' },\n bullet_list: { icon: 'bi-list-ul', label: 'Liste à puces', command: toggleBulletList, active: 'bulletList' },\n ordered_list: { icon: 'bi-list-ol', label: 'Liste numérotée', command: toggleOrderedList, active: 'orderedList' },\n link: { icon: 'bi-link-45deg', label: 'Lien', command: insertLink, active: 'link' },\n};\n\n/** A resolved toolbar entry, ready for the template to render. */\nexport type MdToolbarEntry = ({ kind: 'button' } & MdButtonDefinition) | { kind: 'heading'; label: string };\n\n/** Levels offered by the heading dropdown; 0 puts the line back to a paragraph. */\nconst HEADING_LEVELS = [\n { level: 0, label: 'Paragraphe' },\n { level: 1, label: 'Titre 1' },\n { level: 2, label: 'Titre 2' },\n { level: 3, label: 'Titre 3' },\n { level: 4, label: 'Titre 4' },\n];\n\n/** Everything off, the state of an editor that has not reported yet. */\nconst NOTHING_ACTIVE: MarkdownActiveState = {\n bold: false,\n italic: false,\n strike: false,\n code: false,\n quote: false,\n bulletList: false,\n orderedList: false,\n link: false,\n heading: 0,\n};\n\n@Component({\n selector: 'data-mdedit',\n imports: [NgTemplateOutlet],\n templateUrl: './mdedit.component.html',\n styleUrls: ['./mdedit.component.sass'],\n})\n/**\n * Markdown source editor for a model field, built on CodeMirror 6.\n *\n * Shipped as a separate entry point (`@solidev/data/mdedit`) so consumers who\n * do not edit markdown never pull CodeMirror in. The markup stays on screen and\n * stays editable — this is a *source* editor that styles itself as it goes\n * (headings bigger, `**bold**` actually bold), not a WYSIWYG hiding the syntax\n * and not a split preview. The flavour is GFM.\n *\n * The external contract matches {@link RicheditComponent} so the two are\n * interchangeable in a form: same `dd` / `inline` / `form` modes, same explicit\n * save (persisting only in `dd` mode), same `[fc]` escape hatch.\n *\n * @example\n * ```html\n * <data-mdedit [model]=\"thing\" field=\"description\">Description</data-mdedit>\n * ```\n */\nexport class MdeditComponent<FT, T extends DataModel> implements OnInit {\n /** Id tying the label to the editor. */\n public readonly inputId = uniqueId('data-mdedit');\n /** Id of the label element, wired to the editor through `aria-labelledby`. */\n public readonly labelId = `${this.inputId}-label`;\n\n /** Model instance holding the field. */\n public model = input<T>();\n /** Name of the markdown field to edit. */\n public field = input<string>();\n /** Whether {@link toggleEdit} is allowed to enable editing. */\n public editable = input(true);\n /** Whether the editor is currently enabled. Defaults to true. */\n public edit = model(true);\n /**\n * Layout, and whether {@link save} persists.\n *\n * `dd` renders a `<dt>`/`<dd>` block and is the only mode that saves to the\n * API; `inline` and `form` render a label plus the editor and leave saving to\n * the caller.\n */\n public mode = input<'dd' | 'inline' | 'form'>('dd');\n /** Hide label (for inline forms). */\n public hideLabel = input(false);\n /**\n * Hide the built-in save button, for callers driving persistence themselves\n * from the {@link changed} output.\n */\n public hideButton = input(false);\n /**\n * Form control backing the editor.\n *\n * When supplied, the component uses it as-is and skips its own setup — no\n * field manager lookup, no seeding from the model, and no {@link changed}\n * emissions. When absent, one is created and wired up from `[model]` and\n * `[field]`.\n */\n public fc = input<FormControl<string | null>>();\n /** Toolbar preset name from {@link MdEditToolbars}, or an explicit toolbar. */\n public toolbar = input<'none' | 'default' | 'light' | MdToolbar>('default');\n /** Text shown while the document is empty. */\n public placeholder = input('');\n /** Emits the markdown source on every change. Only wired for an internal `fc`. */\n public changed = output<string | null>();\n\n /** Field manager for {@link field}; only resolved when `fc` is created here. */\n public manager?: BaseFieldManager<FT>;\n /** Whether the manager declares the field required. */\n public readonly required = signal(false);\n /** Markdown constructs under the cursor, driving `aria-pressed`. */\n public readonly active = signal<MarkdownActiveState>(NOTHING_ACTIVE);\n /** Heading levels offered by the dropdown. */\n public readonly headingLevels = HEADING_LEVELS;\n /** The control actually in use: the supplied `[fc]`, or the internal one. */\n public control!: FormControl<string | null>;\n\n /** Toolbar resolved from {@link toolbar}, as entries the template can render. */\n public readonly groups = computed<MdToolbarEntry[][]>(() => {\n const requested = this.toolbar();\n const layout = typeof requested === 'string' ? (MdEditToolbars[requested] ?? []) : requested;\n return layout.map((group) =>\n group.map((item) =>\n item === 'heading'\n ? { kind: 'heading' as const, label: 'Niveau de titre' }\n : { kind: 'button' as const, ...BUTTONS[item] },\n ),\n );\n });\n\n private readonly host = viewChild<ElementRef<HTMLElement>>('editorHost');\n private readonly destroyRef = inject(DestroyRef);\n /** Holds the read-only extensions, so editability can be reconfigured live. */\n private readonly readOnly = new Compartment();\n private view?: EditorView;\n\n constructor() {\n // The view touches the DOM, so it is only built once there is one --\n // nothing happens under SSR, where afterNextRender does not run.\n afterNextRender(() => this.mount());\n this.destroyRef.onDestroy(() => this.view?.destroy());\n }\n\n /**\n * Resolve the control — unless a `[fc]` was given, build one seeded from the\n * model field, enabled per `[edit]`, and relaying changes to {@link changed} —\n * then keep the editor and the control in step.\n */\n public ngOnInit(): void {\n const supplied = this.fc();\n if (supplied) {\n this.control = supplied;\n } else {\n this.control = new FormControl<string | null>('');\n const model = this.model();\n const field = this.field();\n if (model && field) {\n this.manager = model.FM(field);\n this.required.set(this.manager?.required ?? false);\n this.control.setValue(asText(fieldValues(model)[field]), { emitEvent: false });\n }\n if (this.edit()) {\n this.control.enable();\n } else {\n this.control.disable();\n }\n this.control.valueChanges\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe((value) => this.changed.emit(value));\n }\n // A value set from outside is pushed into the document, and enable() /\n // disable() flips the read-only compartment. Both are no-ops when they\n // already match, which is what keeps the editor -> control -> editor round\n // trip from looping.\n this.control.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((value) => this.applyValue(value));\n this.control.statusChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => this.applyEditable());\n }\n\n /**\n * Switch between read-only and editing by enabling or disabling the control.\n * Forces read-only when `[editable]` is false.\n */\n public toggleEdit(): void {\n if (this.editable() && !this.edit()) {\n this.control.enable();\n this.edit.set(true);\n } else {\n this.control.disable();\n this.edit.set(false);\n }\n }\n\n /**\n * Run a toolbar command against the editor and hand focus back, so a click\n * on the toolbar does not take the caret out of the document.\n */\n public run(command: StateCommand): void {\n const view = this.view;\n if (!view) return;\n command(view);\n view.focus();\n }\n\n /** Apply the heading level picked in the dropdown to the current line(s). */\n public setHeadingLevel(value: string): void {\n this.run(setHeading(Number(value)));\n }\n\n /**\n * Write the editor content back to the model field, and persist it in `dd`\n * mode only.\n *\n * In `inline` / `form` modes the model is updated in memory but no request is\n * sent, leaving the save to the surrounding form. Does nothing without both a\n * `[model]` and a `[field]`.\n */\n public async save(): Promise<void> {\n const model = this.model();\n const field = this.field();\n if (!model || !field) return;\n model.setFV(field, this.control.value);\n if (this.mode() === 'dd') {\n await firstValueFrom(model.update([field], { updateModel: true }));\n }\n }\n\n /** Build the CodeMirror view inside the host element. */\n private mount(): void {\n const host = this.host()?.nativeElement;\n if (!host || this.view) return;\n this.view = new EditorView({\n parent: host,\n state: EditorState.create({\n doc: this.control.value ?? '',\n extensions: markdownSetup({\n readOnly: this.readOnly,\n readOnlyInitially: this.control.disabled,\n placeholder: this.placeholder(),\n labelledBy: this.labelId,\n onChange: (doc) => this.pushToControl(doc),\n onStateChange: (state) => this.active.set(markdownActive(state)),\n }),\n }),\n });\n }\n\n /**\n * Push a document into the control, unless it is already there.\n *\n * `setValue` emits even when the value is unchanged, so without this guard an\n * external `setValue` would come back through the editor as a second\n * `valueChanges` — and a second {@link changed} emission for one edit.\n */\n private pushToControl(doc: string): void {\n if (doc === (this.control.value ?? '')) return;\n this.control.setValue(doc);\n }\n\n /** Push a control value into the document, unless it is already there. */\n private applyValue(value: string | null): void {\n const view = this.view;\n if (!view) return;\n const next = value ?? '';\n if (next === view.state.doc.toString()) return;\n view.dispatch({ changes: { from: 0, to: view.state.doc.length, insert: next } });\n }\n\n /** Mirror the control's enabled/disabled status onto the editor. */\n private applyEditable(): void {\n this.view?.dispatch({ effects: this.readOnly.reconfigure(readOnlyExtension(this.control.disabled)) });\n }\n}\n","<ng-template #editorTemplate>\n @if (edit() && groups().length) {\n <div class=\"btn-toolbar data-mdedit__toolbar\" role=\"toolbar\" aria-label=\"Mise en forme du markdown\">\n @for (group of groups(); track $index) {\n <div class=\"btn-group btn-group-sm me-1\">\n @for (entry of group; track entry.label) {\n @if (entry.kind === \"button\") {\n <button\n type=\"button\"\n class=\"btn btn-sm btn-outline-secondary\"\n [class.active]=\"active()[entry.active]\"\n [attr.aria-pressed]=\"active()[entry.active]\"\n [attr.aria-label]=\"entry.label\"\n [title]=\"entry.label\"\n (click)=\"run(entry.command)\"\n >\n <i class=\"bi {{ entry.icon }}\" aria-hidden=\"true\"></i>\n </button>\n } @else {\n <select\n #headingSelect\n class=\"form-select form-select-sm data-mdedit__headings\"\n [attr.aria-label]=\"entry.label\"\n [title]=\"entry.label\"\n [value]=\"active().heading\"\n (change)=\"setHeadingLevel(headingSelect.value)\"\n >\n @for (level of headingLevels; track level.level) {\n <option [value]=\"level.level\">{{ level.label }}</option>\n }\n </select>\n }\n }\n </div>\n }\n </div>\n }\n <div #editorHost class=\"data-mdedit__host\" [attr.id]=\"inputId\"></div>\n @if (edit() && !hideButton()) {\n <button class=\"btn btn-primary btn-sm w-100 mt-1\" (click)=\"save()\">\n <i class=\"bi bi-save me-2\"></i>\n Enregistrer\n </button>\n }\n</ng-template>\n<ng-template #titleTpl>\n <ng-content></ng-content>\n</ng-template>\n<!-- Dd display-->\n@if (mode() === \"dd\") {\n @if (!hideLabel()) {\n <dt [class.required]=\"required()\">\n <span\n class=\"editable\"\n [attr.id]=\"labelId\"\n (click)=\"toggleEdit()\"\n role=\"button\"\n tabindex=\"0\"\n (keydown.enter)=\"toggleEdit()\"\n (keydown.space)=\"$event.preventDefault(); toggleEdit()\"\n >\n <ng-container [ngTemplateOutlet]=\"titleTpl\"></ng-container>\n </span>\n </dt>\n }\n <dd [class.mb-0]=\"hideLabel()\">\n <ng-container [ngTemplateOutlet]=\"editorTemplate\"></ng-container>\n </dd>\n}\n<!-- Inline display-->\n@if (mode() === \"inline\") {\n @if (!hideLabel()) {\n <label [class.required]=\"required()\" [attr.id]=\"labelId\" [attr.for]=\"inputId\">\n <ng-container [ngTemplateOutlet]=\"titleTpl\"></ng-container>\n </label>\n }\n <ng-container [ngTemplateOutlet]=\"editorTemplate\"></ng-container>\n}\n<!-- Form display-->\n@if (mode() === \"form\") {\n @if (!hideLabel()) {\n <label [class.required]=\"required()\" [attr.id]=\"labelId\" [attr.for]=\"inputId\">\n <ng-container [ngTemplateOutlet]=\"titleTpl\"></ng-container>\n </label>\n }\n <ng-container [ngTemplateOutlet]=\"editorTemplate\"></ng-container>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["cmPlaceholder"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"solidev-data-mdedit.mjs","sources":["../../../projects/data/mdedit/cm/markdown-theme.ts","../../../projects/data/mdedit/cm/markdown-setup.ts","../../../projects/data/mdedit/cm/toolbar-commands.ts","../../../projects/data/mdedit/mdedit.component.ts","../../../projects/data/mdedit/mdedit.component.html","../../../projects/data/mdedit/solidev-data-mdedit.ts"],"sourcesContent":["import { HighlightStyle, syntaxHighlighting } from '@codemirror/language';\nimport { Extension } from '@codemirror/state';\nimport { EditorView } from '@codemirror/view';\nimport { tags } from '@lezer/highlight';\n\n/**\n * Syntax highlighting for the markdown *source*.\n *\n * The point of `mdedit` is that the markup stays on screen: `**bold**` keeps\n * its asterisks, a heading keeps its `#`. What this style does is make the\n * source read like the document it describes — headings get bigger, `**bold**`\n * renders bold, code turns monospace — while the markers themselves\n * ({@link tags.processingInstruction}, {@link tags.meta}) are dimmed so they\n * stay visible but recede.\n *\n * Colours come from Bootstrap CSS variables so the editor follows the host\n * theme, including its dark mode, without shipping a palette of its own.\n */\nexport const markdownHighlightStyle = HighlightStyle.define([\n { tag: tags.heading1, fontSize: '1.6em', fontWeight: 'bold', lineHeight: '1.4' },\n { tag: tags.heading2, fontSize: '1.4em', fontWeight: 'bold', lineHeight: '1.4' },\n { tag: tags.heading3, fontSize: '1.25em', fontWeight: 'bold' },\n { tag: tags.heading4, fontSize: '1.15em', fontWeight: 'bold' },\n { tag: tags.heading5, fontSize: '1.05em', fontWeight: 'bold' },\n { tag: tags.heading6, fontSize: '1em', fontWeight: 'bold' },\n { tag: tags.strong, fontWeight: 'bold' },\n { tag: tags.emphasis, fontStyle: 'italic' },\n { tag: tags.strikethrough, textDecoration: 'line-through' },\n { tag: tags.link, textDecoration: 'underline' },\n { tag: tags.url, color: 'var(--bs-link-color, #0d6efd)', textDecoration: 'underline' },\n {\n tag: tags.monospace,\n fontFamily: 'var(--bs-font-monospace, monospace)',\n backgroundColor: 'var(--bs-tertiary-bg, rgba(0, 0, 0, 0.05))',\n },\n { tag: tags.quote, color: 'var(--bs-secondary-color, #6c757d)', fontStyle: 'italic' },\n { tag: tags.contentSeparator, fontWeight: 'bold', color: 'var(--bs-secondary-color, #6c757d)' },\n { tag: tags.list, color: 'var(--bs-emphasis-color, #000)' },\n // The markup itself: `#`, `*`, `>`, backticks, list bullets. Dimmed rather\n // than hidden -- this is a source editor, not a WYSIWYG.\n { tag: tags.processingInstruction, color: 'var(--bs-secondary-color, #6c757d)' },\n { tag: tags.meta, color: 'var(--bs-secondary-color, #6c757d)' },\n]);\n\n/**\n * Editor chrome: a box that matches Bootstrap's `.form-control`, including its\n * focus ring, so an `mdedit` sits in a form without looking foreign.\n */\nexport const markdownTheme = EditorView.theme({\n '&': {\n fontSize: 'inherit',\n color: 'var(--bs-body-color, #212529)',\n backgroundColor: 'var(--bs-body-bg, #fff)',\n border: 'var(--bs-border-width, 1px) solid var(--bs-border-color, #dee2e6)',\n borderRadius: 'var(--bs-border-radius, 0.375rem)',\n },\n '&.cm-focused': {\n outline: 'none',\n borderColor: 'var(--bs-primary-border-subtle, #86b7fe)',\n boxShadow: '0 0 0 0.25rem rgba(var(--bs-primary-rgb, 13, 110, 253), 0.25)',\n },\n '.cm-content': {\n fontFamily: 'var(--bs-body-font-family, system-ui, sans-serif)',\n padding: '0.5rem 0.75rem',\n minHeight: '8rem',\n caretColor: 'var(--bs-body-color, #212529)',\n },\n '.cm-line': {\n padding: '0',\n },\n '.cm-placeholder': {\n color: 'var(--bs-secondary-color, #6c757d)',\n },\n '&.cm-editor.cm-readonly .cm-content, &.cm-editor:not(.cm-focused) .cm-content': {\n caretColor: 'transparent',\n },\n});\n\n/**\n * The whole visual layer — chrome plus source highlighting — as one extension,\n * which is what {@link markdownSetup} installs.\n */\nexport function markdownStyling(): Extension {\n return [markdownTheme, syntaxHighlighting(markdownHighlightStyle)];\n}\n","import { markdown, markdownLanguage } from '@codemirror/lang-markdown';\nimport { defaultKeymap, history, historyKeymap } from '@codemirror/commands';\nimport { Compartment, EditorState, Extension } from '@codemirror/state';\nimport { EditorView, keymap, placeholder as cmPlaceholder } from '@codemirror/view';\nimport { markdownStyling } from './markdown-theme';\n\n/** Options accepted by {@link markdownSetup}. */\nexport interface MarkdownSetupOptions {\n /**\n * Compartment the read-only extensions are installed in, so the caller can\n * flip editability later with `compartment.reconfigure(readOnlyExtension(v))`.\n * Create one per editor instance — compartments are not shareable.\n */\n readOnly?: Compartment;\n /** Whether the editor starts read-only. */\n readOnlyInitially?: boolean;\n /** Text shown while the document is empty. */\n placeholder?: string;\n /** Called with the full markdown source after every document change. */\n onChange?: (doc: string) => void;\n /** Called after every state update, for toolbar active-state tracking. */\n onStateChange?: (state: EditorState) => void;\n /** Id of the element labelling the editor, wired as `aria-labelledby`. */\n labelledBy?: string;\n}\n\n/**\n * The extensions that make an `EditorView` behave as a markdown source editor.\n *\n * Deliberately not CodeMirror's `basicSetup`: this edits prose, so there are no\n * line numbers, no fold gutter and no bracket matching — just markdown parsing,\n * history, wrapping, and the styling from {@link markdownStyling}.\n *\n * The markdown dialect is `markdownLanguage`, i.e. GFM: tables, strikethrough\n * and task lists parse. Fenced code blocks are recognised but their content is\n * not highlighted per-language; that would need `@codemirror/language-data` and\n * its lazily loaded grammars, which is out of scope here.\n */\nexport function markdownSetup(options: MarkdownSetupOptions = {}): Extension[] {\n const extensions: Extension[] = [\n history(),\n // Our bindings come first so undo/redo and the markdown list-continuation\n // keys win over the language's own defaults.\n keymap.of([...historyKeymap, ...defaultKeymap]),\n markdown({ base: markdownLanguage, addKeymap: true }),\n EditorView.lineWrapping,\n markdownStyling(),\n ];\n if (options.placeholder) {\n extensions.push(cmPlaceholder(options.placeholder));\n }\n if (options.labelledBy) {\n extensions.push(EditorView.contentAttributes.of({ 'aria-labelledby': options.labelledBy }));\n }\n const { onChange, onStateChange } = options;\n if (onChange || onStateChange) {\n extensions.push(\n EditorView.updateListener.of((update) => {\n if (onChange && update.docChanged) {\n onChange(update.state.doc.toString());\n }\n if (onStateChange && (update.docChanged || update.selectionSet || update.focusChanged)) {\n onStateChange(update.state);\n }\n }),\n );\n }\n if (options.readOnly) {\n extensions.push(options.readOnly.of(readOnlyExtension(options.readOnlyInitially ?? false)));\n } else if (options.readOnlyInitially) {\n extensions.push(readOnlyExtension(true));\n }\n return extensions;\n}\n\n/**\n * Read-only state for a given editability, meant to be reconfigured into the\n * compartment passed to {@link markdownSetup}.\n *\n * Both facets are needed: `EditorState.readOnly` stops commands from changing\n * the document, `EditorView.editable` takes `contenteditable` off the DOM node\n * so the caret and the browser's own editing affordances go away too.\n */\nexport function readOnlyExtension(readOnly: boolean): Extension {\n return [EditorState.readOnly.of(readOnly), EditorView.editable.of(!readOnly)];\n}\n","import { syntaxTree } from '@codemirror/language';\nimport { ChangeSpec, EditorSelection, EditorState, Line, StateCommand } from '@codemirror/state';\n\n/**\n * Markdown editing commands, written as CodeMirror `StateCommand`s.\n *\n * A `StateCommand` only needs `{state, dispatch}`, which an `EditorView`\n * satisfies — so these drive the toolbar buttons in the browser, and can be\n * exercised in a spec against a bare `EditorState`, with no DOM at all. They\n * rewrite the markdown source, since that is what the user sees and edits.\n */\n\n/**\n * Lines touched by the selection, in document order and without duplicates.\n *\n * Selection ranges are sorted and non-overlapping, so tracking the last line\n * number emitted is enough to keep a line from being rewritten twice when two\n * cursors sit on it.\n */\nfunction selectedLines(state: EditorState): Line[] {\n const lines: Line[] = [];\n let last = -1;\n for (const range of state.selection.ranges) {\n for (let pos = range.from; pos <= range.to;) {\n const line = state.doc.lineAt(pos);\n if (line.number > last) {\n lines.push(line);\n last = line.number;\n }\n pos = line.to + 1;\n }\n }\n return lines;\n}\n\n/**\n * Toggle a symmetric inline delimiter — `**` for bold, `*` for italic, `~~` for\n * strikethrough, `` ` `` for code.\n *\n * Wraps the selection, or unwraps it when the delimiters are already there,\n * whether they sit just outside the selection (the usual case after a previous\n * toggle) or inside it (the user selected them along with the text). On an\n * empty selection it inserts the pair and leaves the cursor between the two\n * halves, so typing continues inside the mark.\n */\nexport function toggleInlineMark(delim: string): StateCommand {\n const len = delim.length;\n return ({ state, dispatch }) => {\n const transaction = state.changeByRange((range) => {\n if (\n !range.empty &&\n state.sliceDoc(range.from - len, range.from) === delim &&\n state.sliceDoc(range.to, range.to + len) === delim\n ) {\n return {\n changes: [\n { from: range.from - len, to: range.from },\n { from: range.to, to: range.to + len },\n ],\n range: EditorSelection.range(range.from - len, range.to - len),\n };\n }\n const text = state.sliceDoc(range.from, range.to);\n if (text.length >= 2 * len && text.startsWith(delim) && text.endsWith(delim)) {\n return {\n changes: [\n { from: range.from, to: range.from + len },\n { from: range.to - len, to: range.to },\n ],\n range: EditorSelection.range(range.from, range.to - 2 * len),\n };\n }\n return {\n changes: [\n { from: range.from, insert: delim },\n { from: range.to, insert: delim },\n ],\n range: range.empty\n ? EditorSelection.cursor(range.from + len)\n : EditorSelection.range(range.from + len, range.to + len),\n };\n });\n dispatch(state.update(transaction, { scrollIntoView: true, userEvent: 'input' }));\n return true;\n };\n}\n\n/** Toggle `**bold**` around the selection. */\nexport const toggleBold = toggleInlineMark('**');\n/** Toggle `*italic*` around the selection. */\nexport const toggleItalic = toggleInlineMark('*');\n/** Toggle `~~strikethrough~~` around the selection (GFM). */\nexport const toggleStrikethrough = toggleInlineMark('~~');\n/** Toggle `` `code` `` around the selection. */\nexport const toggleInlineCode = toggleInlineMark('`');\n\n/** Leading ATX heading markup, e.g. `### `. */\nconst HEADING = /^#{1,6} */;\n\n/**\n * Set the heading level of every selected line, `0` meaning plain paragraph.\n *\n * This sets rather than toggles: picking \"Heading 2\" twice leaves an `h2`, and\n * the way back to a paragraph is `setHeading(0)` — which is what the toolbar's\n * \"Paragraphe\" entry does. Returns false when nothing would change, as a\n * CodeMirror command should.\n */\nexport function setHeading(level: number): StateCommand {\n const prefix = level > 0 ? `${'#'.repeat(level)} ` : '';\n return ({ state, dispatch }) => {\n const changes: ChangeSpec[] = [];\n for (const line of selectedLines(state)) {\n const current = HEADING.exec(line.text)?.[0] ?? '';\n if (current === prefix) continue;\n changes.push({ from: line.from, to: line.from + current.length, insert: prefix });\n }\n if (!changes.length) return false;\n dispatch(state.update({ changes, userEvent: 'input' }));\n return true;\n };\n}\n\n/**\n * Add a line prefix to every selected line, or strip it when all of them\n * already have it.\n *\n * `prefixFor` receives the index of the line within the selection, which is\n * what lets ordered lists number themselves.\n */\nfunction toggleLinePrefix(match: RegExp, prefixFor: (index: number) => string): StateCommand {\n return ({ state, dispatch }) => {\n const lines = selectedLines(state);\n if (!lines.length) return false;\n const strip = lines.every((line) => match.test(line.text));\n const changes: ChangeSpec[] = [];\n lines.forEach((line, index) => {\n const found = match.exec(line.text);\n if (strip) {\n if (found) changes.push({ from: line.from, to: line.from + found[0].length });\n } else if (!found) {\n changes.push({ from: line.from, insert: prefixFor(index) });\n }\n });\n if (!changes.length) return false;\n dispatch(state.update({ changes, userEvent: 'input' }));\n return true;\n };\n}\n\n/** Toggle `> ` blockquote markers on the selected lines. */\nexport const toggleQuote = toggleLinePrefix(/^> ?/, () => '> ');\n/** Toggle `- ` bullets on the selected lines; `*` and `+` bullets count as set. */\nexport const toggleBulletList = toggleLinePrefix(/^[-*+] /, () => '- ');\n/** Toggle `1. ` numbering on the selected lines, renumbering from one. */\nexport const toggleOrderedList = toggleLinePrefix(/^\\d+\\. /, (index) => `${index + 1}. `);\n\n/**\n * Turn the selection into a link.\n *\n * With text selected it becomes `[text](url)` and the `url` placeholder is left\n * selected, ready to be typed over. With no selection the whole\n * `[text](url)` skeleton is inserted and `text` is selected instead.\n */\nexport const insertLink: StateCommand = ({ state, dispatch }) => {\n const transaction = state.changeByRange((range) => {\n if (range.empty) {\n return {\n changes: { from: range.from, insert: '[text](url)' },\n range: EditorSelection.range(range.from + 1, range.from + 5),\n };\n }\n const text = state.sliceDoc(range.from, range.to);\n // '[' + text + '](' puts the url placeholder here.\n const urlFrom = range.from + text.length + 3;\n return {\n changes: { from: range.from, to: range.to, insert: `[${text}](url)` },\n range: EditorSelection.range(urlFrom, urlFrom + 3),\n };\n });\n dispatch(state.update(transaction, { scrollIntoView: true, userEvent: 'input' }));\n return true;\n};\n\n/** What the toolbar needs to know to render its buttons pressed or not. */\nexport interface MarkdownActiveState {\n bold: boolean;\n italic: boolean;\n strike: boolean;\n code: boolean;\n quote: boolean;\n bulletList: boolean;\n orderedList: boolean;\n link: boolean;\n /** Heading level under the cursor, `0` outside any heading. */\n heading: number;\n}\n\n/** Lezer node names, per markdown construct, as produced by `@lezer/markdown`. */\nconst ACTIVE_NODES: Record<Exclude<keyof MarkdownActiveState, 'heading'>, string> = {\n bold: 'StrongEmphasis',\n italic: 'Emphasis',\n strike: 'Strikethrough',\n code: 'InlineCode',\n quote: 'Blockquote',\n bulletList: 'BulletList',\n orderedList: 'OrderedList',\n link: 'Link',\n};\n\n/**\n * Which markdown constructs the cursor currently sits in.\n *\n * Read from the syntax tree rather than by matching the raw text, so nesting\n * and escapes are handled by the parser. Drives `aria-pressed` on the toolbar.\n */\nexport function markdownActive(state: EditorState): MarkdownActiveState {\n const active: MarkdownActiveState = {\n bold: false,\n italic: false,\n strike: false,\n code: false,\n quote: false,\n bulletList: false,\n orderedList: false,\n link: false,\n heading: 0,\n };\n // -1 biases the lookup towards the node ending at the cursor, so a mark stays\n // reported as active with the caret just after its closing delimiter.\n let node = syntaxTree(state).resolveInner(state.selection.main.head, -1);\n const names = Object.entries(ACTIVE_NODES) as [keyof typeof ACTIVE_NODES, string][];\n for (;;) {\n const heading = /^ATXHeading([1-6])$/.exec(node.name);\n if (heading && !active.heading) {\n active.heading = Number(heading[1]);\n }\n for (const [key, nodeName] of names) {\n if (node.name === nodeName) active[key] = true;\n }\n const parent = node.parent;\n if (!parent) return active;\n node = parent;\n }\n}\n","import {\n afterRenderEffect,\n Component,\n DestroyRef,\n ElementRef,\n computed,\n inject,\n input,\n signal,\n viewChild,\n} from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { DataModel, FieldEditorBase, SafeHtmlPipe } from '@solidev/data';\nimport { Compartment, EditorState, StateCommand } from '@codemirror/state';\nimport { EditorView } from '@codemirror/view';\nimport { markdownSetup, readOnlyExtension } from './cm/markdown-setup';\nimport {\n insertLink,\n markdownActive,\n MarkdownActiveState,\n setHeading,\n toggleBold,\n toggleBulletList,\n toggleInlineCode,\n toggleItalic,\n toggleOrderedList,\n toggleQuote,\n toggleStrikethrough,\n} from './cm/toolbar-commands';\n\n/** A button the `mdedit` toolbar knows how to render. */\nexport type MdToolbarItem =\n 'bold' | 'italic' | 'strike' | 'code' | 'quote' | 'bullet_list' | 'ordered_list' | 'link' | 'heading';\n\n/** Toolbar layout: groups of items, rendered as Bootstrap button groups. */\nexport type MdToolbar = MdToolbarItem[][];\n\n/**\n * Named toolbar presets for {@link MdeditComponent}, selectable through its\n * `toolbar` input.\n *\n * - `default`: marks, a heading dropdown, quote and code, lists, links.\n * - `light`: a reduced set — bold, italic, bullets, links.\n * - `none`: empty; the component hides the toolbar entirely for this value.\n *\n * An `MdToolbar` can also be passed directly when neither preset fits.\n */\nexport const MdEditToolbars: Record<string, MdToolbar> = {\n default: [['bold', 'italic', 'strike'], ['heading'], ['quote', 'code'], ['bullet_list', 'ordered_list'], ['link']],\n light: [['bold', 'italic'], ['bullet_list'], ['link']],\n none: [],\n};\n\n/** What a plain toolbar button needs: an icon, a label, a command, a state. */\ninterface MdButtonDefinition {\n icon: string;\n label: string;\n command: StateCommand;\n active: Exclude<keyof MarkdownActiveState, 'heading'>;\n}\n\nconst BUTTONS: Record<Exclude<MdToolbarItem, 'heading'>, MdButtonDefinition> = {\n bold: { icon: 'bi-type-bold', label: 'Gras', command: toggleBold, active: 'bold' },\n italic: { icon: 'bi-type-italic', label: 'Italique', command: toggleItalic, active: 'italic' },\n strike: { icon: 'bi-type-strikethrough', label: 'Barré', command: toggleStrikethrough, active: 'strike' },\n code: { icon: 'bi-code', label: 'Code', command: toggleInlineCode, active: 'code' },\n quote: { icon: 'bi-blockquote-left', label: 'Citation', command: toggleQuote, active: 'quote' },\n bullet_list: { icon: 'bi-list-ul', label: 'Liste à puces', command: toggleBulletList, active: 'bulletList' },\n ordered_list: { icon: 'bi-list-ol', label: 'Liste numérotée', command: toggleOrderedList, active: 'orderedList' },\n link: { icon: 'bi-link-45deg', label: 'Lien', command: insertLink, active: 'link' },\n};\n\n/** A resolved toolbar entry, ready for the template to render. */\nexport type MdToolbarEntry = ({ kind: 'button' } & MdButtonDefinition) | { kind: 'heading'; label: string };\n\n/** Levels offered by the heading dropdown; 0 puts the line back to a paragraph. */\nconst HEADING_LEVELS = [\n { level: 0, label: 'Paragraphe' },\n { level: 1, label: 'Titre 1' },\n { level: 2, label: 'Titre 2' },\n { level: 3, label: 'Titre 3' },\n { level: 4, label: 'Titre 4' },\n];\n\n/** Everything off, the state of an editor that has not reported yet. */\nconst NOTHING_ACTIVE: MarkdownActiveState = {\n bold: false,\n italic: false,\n strike: false,\n code: false,\n quote: false,\n bulletList: false,\n orderedList: false,\n link: false,\n heading: 0,\n};\n\n@Component({\n selector: 'data-mdedit',\n imports: [NgTemplateOutlet, SafeHtmlPipe],\n templateUrl: './mdedit.component.html',\n styleUrls: ['./mdedit.component.sass'],\n})\n/**\n * Markdown source editor for a model field, built on CodeMirror 6.\n *\n * Shipped as a separate entry point (`@solidev/data/mdedit`) so consumers who\n * do not edit markdown never pull CodeMirror in. The markup stays on screen and\n * stays editable — this is a *source* editor that styles itself as it goes\n * (headings bigger, `**bold**` actually bold), not a WYSIWYG hiding the syntax\n * and not a split preview. The flavour is GFM.\n *\n * The external contract matches {@link RicheditComponent} so the two are\n * interchangeable in a form: same `dd` / `inline` / `form` modes, same explicit\n * save (persisting only in `dd` mode), same `[fc]` escape hatch.\n *\n * @example\n * ```html\n * <data-mdedit [model]=\"thing\" field=\"description\">Description</data-mdedit>\n * ```\n */\nexport class MdeditComponent<FT, T extends DataModel> extends FieldEditorBase<FT, T> {\n /** Toolbar preset name from {@link MdEditToolbars}, or an explicit toolbar. */\n public toolbar = input<'none' | 'default' | 'light' | MdToolbar>('default');\n /** Text shown while the document is empty. */\n public placeholder = input('');\n /** Markdown constructs under the cursor, driving `aria-pressed`. */\n public readonly active = signal<MarkdownActiveState>(NOTHING_ACTIVE);\n /** Heading levels offered by the dropdown. */\n public readonly headingLevels = HEADING_LEVELS;\n\n /** Toolbar resolved from {@link toolbar}, as entries the template can render. */\n public readonly groups = computed<MdToolbarEntry[][]>(() => {\n const requested = this.toolbar();\n const layout = typeof requested === 'string' ? (MdEditToolbars[requested] ?? []) : requested;\n return layout.map((group) =>\n group.map((item) =>\n item === 'heading'\n ? { kind: 'heading' as const, label: 'Niveau de titre' }\n : { kind: 'button' as const, ...BUTTONS[item] },\n ),\n );\n });\n\n private readonly host = viewChild<ElementRef<HTMLElement>>('editorHost');\n private readonly destroyRef = inject(DestroyRef);\n /** Holds the read-only extensions, so editability can be reconfigured live. */\n private readonly readOnly = new Compartment();\n private view?: EditorView;\n\n constructor() {\n super();\n // Not afterNextRender: the host element only exists while the editor is\n // showing, so toggling out of the read-only view and back in has to mount\n // again. afterRenderEffect re-runs as the host signal changes, and like\n // afterNextRender it never runs under SSR.\n afterRenderEffect(() => this.syncView());\n this.destroyRef.onDestroy(() => this.view?.destroy());\n }\n\n /**\n * Wire the resolved control to the editor, in both directions.\n *\n * The base picks the control (`[fc]`, `[form]`, or its own) and seeds it;\n * this adds the CodeMirror half.\n */\n public override ngOnInit(): void {\n super.ngOnInit();\n if (!this.fc()) {\n this.control.valueChanges\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe((value) => this.changed.emit(value));\n }\n // A value set from outside is pushed into the document, and enable() /\n // disable() flips the read-only compartment. Both are no-ops when they\n // already match, which is what keeps the editor -> control -> editor round\n // trip from looping.\n this.control.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((value) => this.applyValue(value));\n this.control.statusChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => this.applyEditable());\n }\n\n /**\n * Run a toolbar command against the editor and hand focus back, so a click\n * on the toolbar does not take the caret out of the document.\n */\n public run(command: StateCommand): void {\n const view = this.view;\n if (!view) return;\n command(view);\n view.focus();\n }\n\n /** Apply the heading level picked in the dropdown to the current line(s). */\n public setHeadingLevel(value: string): void {\n this.run(setHeading(Number(value)));\n }\n\n /**\n * Build or tear down the CodeMirror view, following the host element.\n *\n * Toggling back to the read-only view removes the host, which would leave a\n * detached view behind and make the next mount a no-op. The control keeps the\n * value across the round trip, so a fresh view is seeded correctly.\n */\n private syncView(): void {\n if (!this.host()) {\n this.view?.destroy();\n this.view = undefined;\n return;\n }\n this.mount();\n }\n\n /** Build the CodeMirror view inside the host element. */\n private mount(): void {\n const host = this.host()?.nativeElement;\n if (!host || this.view) return;\n this.view = new EditorView({\n parent: host,\n state: EditorState.create({\n doc: this.control.value ?? '',\n extensions: markdownSetup({\n readOnly: this.readOnly,\n readOnlyInitially: this.control.disabled,\n placeholder: this.placeholder(),\n labelledBy: this.labelId,\n onChange: (doc) => this.pushToControl(doc),\n onStateChange: (state) => this.active.set(markdownActive(state)),\n }),\n }),\n });\n }\n\n /**\n * Push a document into the control, unless it is already there.\n *\n * `setValue` emits even when the value is unchanged, so without this guard an\n * external `setValue` would come back through the editor as a second\n * `valueChanges` — and a second {@link changed} emission for one edit.\n */\n private pushToControl(doc: string): void {\n if (doc === (this.control.value ?? '')) return;\n this.control.setValue(doc);\n }\n\n /** Push a control value into the document, unless it is already there. */\n private applyValue(value: string | null): void {\n const view = this.view;\n if (!view) return;\n const next = value ?? '';\n if (next === view.state.doc.toString()) return;\n view.dispatch({ changes: { from: 0, to: view.state.doc.length, insert: next } });\n }\n\n /** Mirror the control's enabled/disabled status onto the editor. */\n private applyEditable(): void {\n this.view?.dispatch({ effects: this.readOnly.reconfigure(readOnlyExtension(this.control.disabled)) });\n }\n}\n","<ng-template #editorTemplate>\n @if (!showEditor()) {\n <!--\n Read-only: the rendered HTML twin of the source, injected as trusted\n markup. See SafeHtmlPipe.\n -->\n <div\n class=\"editable data-mdedit__view\"\n role=\"button\"\n tabindex=\"0\"\n (click)=\"toggleEdit()\"\n (keydown.enter)=\"toggleEdit()\"\n (keydown.space)=\"$event.preventDefault(); toggleEdit()\"\n [innerHTML]=\"displayValue() | safeHtml\"\n ></div>\n } @else {\n <ng-container [ngTemplateOutlet]=\"editorBody\"></ng-container>\n }\n</ng-template>\n<ng-template #editorBody>\n @if (groups().length) {\n <div class=\"btn-toolbar data-mdedit__toolbar\" role=\"toolbar\" aria-label=\"Mise en forme du markdown\">\n @for (group of groups(); track $index) {\n <div class=\"btn-group btn-group-sm me-1\">\n @for (entry of group; track entry.label) {\n @if (entry.kind === \"button\") {\n <button\n type=\"button\"\n class=\"btn btn-sm btn-outline-secondary\"\n [class.active]=\"active()[entry.active]\"\n [attr.aria-pressed]=\"active()[entry.active]\"\n [attr.aria-label]=\"entry.label\"\n [title]=\"entry.label\"\n (click)=\"run(entry.command)\"\n >\n <i class=\"bi {{ entry.icon }}\" aria-hidden=\"true\"></i>\n </button>\n } @else {\n <select\n #headingSelect\n class=\"form-select form-select-sm data-mdedit__headings\"\n [attr.aria-label]=\"entry.label\"\n [title]=\"entry.label\"\n [value]=\"active().heading\"\n (change)=\"setHeadingLevel(headingSelect.value)\"\n >\n @for (level of headingLevels; track level.level) {\n <option [value]=\"level.level\">{{ level.label }}</option>\n }\n </select>\n }\n }\n </div>\n }\n </div>\n }\n <div #editorHost class=\"data-mdedit__host\" [attr.id]=\"inputId\"></div>\n @if (!hideButton()) {\n <button class=\"btn btn-primary btn-sm w-100 mt-1\" (click)=\"save()\">\n <i class=\"bi bi-save me-2\"></i>\n Enregistrer\n </button>\n }\n</ng-template>\n<ng-template #titleTpl>\n <ng-content></ng-content>\n</ng-template>\n<!-- Dd display-->\n@if (mode() === \"dd\") {\n @if (!hideLabel()) {\n <dt [class.required]=\"required()\">\n <span\n class=\"editable\"\n [attr.id]=\"labelId\"\n (click)=\"toggleEdit()\"\n role=\"button\"\n tabindex=\"0\"\n (keydown.enter)=\"toggleEdit()\"\n (keydown.space)=\"$event.preventDefault(); toggleEdit()\"\n >\n <ng-container [ngTemplateOutlet]=\"titleTpl\"></ng-container>\n </span>\n </dt>\n }\n <dd [class.mb-0]=\"hideLabel()\">\n <ng-container [ngTemplateOutlet]=\"editorTemplate\"></ng-container>\n </dd>\n}\n<!-- Inline display-->\n@if (mode() === \"inline\") {\n @if (!hideLabel()) {\n <label [class.required]=\"required()\" [attr.id]=\"labelId\" [attr.for]=\"inputId\">\n <ng-container [ngTemplateOutlet]=\"titleTpl\"></ng-container>\n </label>\n }\n <ng-container [ngTemplateOutlet]=\"editorTemplate\"></ng-container>\n}\n<!-- Form display-->\n@if (mode() === \"form\") {\n @if (!hideLabel()) {\n <label [class.required]=\"required()\" [attr.id]=\"labelId\" [attr.for]=\"inputId\">\n <ng-container [ngTemplateOutlet]=\"titleTpl\"></ng-container>\n </label>\n }\n <ng-container [ngTemplateOutlet]=\"editorTemplate\"></ng-container>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["cmPlaceholder"],"mappings":"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"}
|