@tedi-design-system/angular 8.1.0-rc.5 → 8.1.0-rc.7

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.
@@ -0,0 +1,129 @@
1
+ import * as _tedi_design_system_angular_tedi from '@tedi-design-system/angular/tedi';
2
+ import { FormFieldControl } from '@tedi-design-system/angular/tedi';
3
+ import * as _angular_core from '@angular/core';
4
+ import { OnInit } from '@angular/core';
5
+ import { ControlValueAccessor, FormControl } from '@angular/forms';
6
+ import { QuillModules } from 'ngx-quill';
7
+ import Quill from 'quill';
8
+
9
+ declare const TEXT_EDITOR_DEFAULT_MODULES: QuillModules;
10
+ /**
11
+ * Rich text editor built on ngx-quill. The value is Quill HTML.
12
+ *
13
+ * Requires Quill's stylesheets in the global styles file:
14
+ *
15
+ * @example
16
+ * ```scss
17
+ * @forward 'quill/dist/quill.core.css';
18
+ * @forward 'quill/dist/quill.snow.css';
19
+ * ```
20
+ */
21
+ declare class TextEditorComponent implements OnInit, ControlValueAccessor, FormFieldControl<string> {
22
+ private readonly renderer;
23
+ private readonly translationService;
24
+ private readonly fieldContext;
25
+ /**
26
+ * Editor contents as Quill HTML. Supports two-way binding; with reactive or
27
+ * template-driven forms bind the control instead.
28
+ */
29
+ value: _angular_core.ModelSignal<string>;
30
+ /**
31
+ * Id set on the editing area. Quill's editing area is a `contenteditable`
32
+ * div, which `<label for>` cannot target, so pair this with `ariaLabelledby`
33
+ * rather than relying on a label's `for`.
34
+ */
35
+ inputId: _angular_core.InputSignal<string>;
36
+ /**
37
+ * Id of the element labelling the editor, usually your own `<label>`.
38
+ */
39
+ ariaLabelledby: _angular_core.InputSignal<string | undefined>;
40
+ /**
41
+ * Accessible name, for when there is no visible label. Ignored when
42
+ * `ariaLabelledby` is set.
43
+ */
44
+ ariaLabel: _angular_core.InputSignal<string | undefined>;
45
+ /**
46
+ * Forces the error state on. Combines with the state derived from the bound
47
+ * control, so `false` does not switch a derived error off.
48
+ */
49
+ readonly invalidInput: _angular_core.InputSignal<boolean>;
50
+ /**
51
+ * Marks the editor as required for assistive technology. Combines with the
52
+ * bound control's `Validators.required`.
53
+ */
54
+ readonly requiredInput: _angular_core.InputSignal<boolean>;
55
+ /**
56
+ * Placeholder shown while the editor is empty. Not translated.
57
+ */
58
+ placeholder: _angular_core.InputSignal<string>;
59
+ /**
60
+ * Quill module configuration. Replaces the default toolbar rather than
61
+ * extending it. Tab is always left to the browser so the editor can be tabbed
62
+ * out of; pass an explicit `keyboard.bindings.tab` to override that.
63
+ */
64
+ modules: _angular_core.InputSignal<QuillModules>;
65
+ /**
66
+ * Rows the editing area rests at, and the fewest it can ever show.
67
+ *
68
+ * @default 10
69
+ */
70
+ minRows: _angular_core.InputSignal<number>;
71
+ readonly focused: _angular_core.WritableSignal<boolean>;
72
+ /**
73
+ * `quill-editor` is itself a `ControlValueAccessor`, so the cleanest bridge to
74
+ * it is a control of our own rather than reaching into the Quill instance.
75
+ */
76
+ protected readonly innerControl: FormControl<string>;
77
+ private readonly editorRoot;
78
+ private readonly toolbar;
79
+ private readonly formDisabled;
80
+ private onChange;
81
+ private onTouched;
82
+ private readonly derived;
83
+ readonly describedBy: _tedi_design_system_angular_tedi.ControlDescribedBy;
84
+ readonly touched: _angular_core.Signal<boolean>;
85
+ readonly dirty: _angular_core.Signal<boolean>;
86
+ readonly disabled: _angular_core.Signal<boolean>;
87
+ readonly invalid: _angular_core.Signal<boolean>;
88
+ readonly required: _angular_core.Signal<boolean>;
89
+ /**
90
+ * `tedi-form-field`'s counter measures the control's value, which here is
91
+ * Quill markup — a short sentence would blow a generous limit on tags alone.
92
+ * Report what the user can see instead.
93
+ */
94
+ readonly characterCount: _angular_core.Signal<number>;
95
+ /**
96
+ * Quill's own Tab handling is disabled by default, but a caller-supplied
97
+ * binding of the same name still wins.
98
+ */
99
+ readonly resolvedModules: _angular_core.Signal<QuillModules>;
100
+ constructor();
101
+ ngOnInit(): void;
102
+ handleEditorCreated: (quill: Quill) => void;
103
+ handleBlur(): void;
104
+ setDescribedBy(ids: string[]): void;
105
+ reset(): void;
106
+ focus(): void;
107
+ writeValue(value: string | null): void;
108
+ registerOnChange(fn: (value: string) => void): void;
109
+ registerOnTouched(fn: () => void): void;
110
+ setDisabledState(isDisabled: boolean): void;
111
+ /**
112
+ * Names the toolbar controls and gives them a hover tooltip. Quill's own
113
+ * `aria-label` is the untranslated format string, and it leaves the pickers
114
+ * nameless entirely, so both attributes are rewritten from the translations.
115
+ * Re-runs on a language change.
116
+ */
117
+ private syncToolbarLabels;
118
+ /**
119
+ * Mirrors identity, name and state onto `.ql-editor`. Quill gives it no role
120
+ * of its own, so without this it is exposed as a nameless `generic` node and
121
+ * none of these attributes reach assistive technology.
122
+ */
123
+ private syncEditorAttributes;
124
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TextEditorComponent, never>;
125
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TextEditorComponent, "tedi-text-editor", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "inputId": { "alias": "inputId"; "required": true; "isSignal": true; }; "ariaLabelledby": { "alias": "ariaLabelledby"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "invalidInput": { "alias": "invalid"; "required": false; "isSignal": true; }; "requiredInput": { "alias": "required"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "modules": { "alias": "modules"; "required": false; "isSignal": true; }; "minRows": { "alias": "minRows"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; }, never, never, true, never>;
126
+ }
127
+
128
+ export { TEXT_EDITOR_DEFAULT_MODULES, TextEditorComponent };
129
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sources":["../../../src/community/text-editor/text-editor.component.ts"],"mappings":";;;;;;;;;;;;;;;;;AA8JG;AACH;AA0BE;AACA,cAAQ,mBAAS,YAAoD,MAAA,EAAA,oBAAA,EAAA,gBAAA;AACrE;AAIA;;;AAGG;AACH;AACA;;;;AAIG;AACH;AACA;;AAEG;AACH;AACA;;;AAGG;AACH;AACA;;;AAGG;;AAGH;;;AAGG;;AAGH;;AAEG;AACH;AACA;;;;AAIG;AACH;AACA;;;;AAIG;AACH;;AAIA,aAAA,aAAA,CAAA,WAAA;;;AAGG;AACH;AAIA;AACA,qCAA4D,WAAA;AAC5D;;;AAIA;;;0BAIc,gCAAA,CAAA,kBAAsB;sBAEnB,aAAA,CAAA,MAAA;oBAID,aAAA,CAAA,MAAA;uBAOC,aAAA,CAAA,MAAA;AAIjB,sBAAA,aAAA,CAAA,MAAA;;;;AAIG;;AAGH;;;AAGG;;;8BA+CK,aAAA,CAAA,MAAA,CAAA,YAAA;AAIR;;AAaA,iCAA4B,KAAA;;;AAiB5B;;AAQA;AAIA;AAIA;;;;;AAKG;AACH;AAyBA;;;;AAIG;AACH;;;AA4BD,iBAAAA,aAAA,CAAA,oBAAA,CAAA,mBAAA;;;;;;","names":["i0"]}
@@ -0,0 +1,378 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, Renderer2, model, input, signal, computed, untracked, effect, forwardRef, ChangeDetectionStrategy, ViewEncapsulation, Component } from '@angular/core';
3
+ import * as i1 from '@angular/forms';
4
+ import { FormControl, ReactiveFormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
5
+ import { TediTranslationService, TEDI_FIELD_CONTEXT, deriveControlState, controlDescribedBy, TEDI_FORM_FIELD_CONTROL } from '@tedi-design-system/angular/tedi';
6
+ import { QuillEditorComponent } from 'ngx-quill';
7
+
8
+ const TEXT_EDITOR_DEFAULT_MODULES = {
9
+ toolbar: [
10
+ [
11
+ "bold",
12
+ "italic",
13
+ "underline",
14
+ { align: "justify" },
15
+ { list: "bullet" },
16
+ { list: "ordered" },
17
+ { indent: "-1" },
18
+ { indent: "+1" },
19
+ { background: [] },
20
+ { color: [] },
21
+ "clean",
22
+ ],
23
+ ],
24
+ };
25
+ /**
26
+ * Quill binds Tab to "insert a tab character" and, inside a list, to indent and
27
+ * outdent. All three swallow the key and leave the user unable to tab out of the
28
+ * editor, which is a keyboard trap (WCAG 2.1.2). Quill skips any binding whose
29
+ * value is `null`, so nulling them lets Tab fall through to the browser's normal
30
+ * focus move. List indenting stays available from the toolbar`.
31
+ */
32
+ const NO_KEYBOARD_TRAP_BINDINGS = {
33
+ tab: null,
34
+ indent: null,
35
+ outdent: null,
36
+ };
37
+ /**
38
+ * Translation key per toolbar control, keyed by Quill's format name and, where
39
+ * one format drives several buttons, its value. Quill names the buttons itself
40
+ * but only from the raw format (`aria-label="indent: +1"`), so every control
41
+ * listed here is relabelled; anything absent keeps Quill's own name.
42
+ */
43
+ const TOOLBAR_LABEL_KEYS = {
44
+ bold: "text-editor.bold",
45
+ italic: "text-editor.italic",
46
+ underline: "text-editor.underline",
47
+ strike: "text-editor.strike",
48
+ blockquote: "text-editor.blockquote",
49
+ link: "text-editor.link",
50
+ clean: "text-editor.clean",
51
+ color: "text-editor.color",
52
+ background: "text-editor.background",
53
+ align: "text-editor.align.left",
54
+ "align:center": "text-editor.align.center",
55
+ "align:right": "text-editor.align.right",
56
+ "align:justify": "text-editor.align.justify",
57
+ "list:bullet": "text-editor.list.bullet",
58
+ "list:ordered": "text-editor.list.ordered",
59
+ "indent:+1": "text-editor.indent.increase",
60
+ "indent:-1": "text-editor.indent.decrease",
61
+ };
62
+ const STRUCTURAL_TOOLBAR_CLASSES = new Set([
63
+ "ql-picker",
64
+ "ql-color-picker",
65
+ "ql-icon-picker",
66
+ "ql-expanded",
67
+ "ql-active",
68
+ ]);
69
+ /**
70
+ * Quill tags a control with `ql-<format>` alongside its structural classes, and
71
+ * puts the discriminating value in `value` where one format drives several
72
+ * buttons. Left align is given an empty value, so it falls back to the bare
73
+ * format name.
74
+ */
75
+ function toolbarLabelKey(control) {
76
+ const format = Array.from(control.classList).find((name) => name.startsWith("ql-") && !STRUCTURAL_TOOLBAR_CLASSES.has(name));
77
+ if (!format)
78
+ return undefined;
79
+ const value = control.getAttribute("value");
80
+ const base = format.slice("ql-".length);
81
+ return TOOLBAR_LABEL_KEYS[value ? `${base}:${value}` : base];
82
+ }
83
+ const SERIALIZED_ENTITIES = {
84
+ "&amp;": "&",
85
+ "&lt;": "<",
86
+ "&gt;": ">",
87
+ "&quot;": '"',
88
+ "&#39;": "'",
89
+ "&nbsp;": "\u00a0",
90
+ };
91
+ /**
92
+ * Length of the text a reader actually sees, with the markup stripped. Parsed
93
+ * rather than regex-stripped so entities (`&nbsp;`) count as the one character
94
+ * they render as; a `DOMParser` document is inert, so nothing in the markup
95
+ * runs or loads.
96
+ */
97
+ function visibleTextLength(html) {
98
+ if (!html)
99
+ return 0;
100
+ if (typeof DOMParser === "undefined") {
101
+ return html
102
+ .replace(/<[^>]*>/g, "")
103
+ .replace(/&(?:amp|lt|gt|quot|nbsp|#39);/g, (entity) => SERIALIZED_ENTITIES[entity]).length;
104
+ }
105
+ const text = new DOMParser().parseFromString(html, "text/html").body.textContent ?? "";
106
+ return text.length;
107
+ }
108
+ /**
109
+ * Rich text editor built on ngx-quill. The value is Quill HTML.
110
+ *
111
+ * Requires Quill's stylesheets in the global styles file:
112
+ *
113
+ * @example
114
+ * ```scss
115
+ * @forward 'quill/dist/quill.core.css';
116
+ * @forward 'quill/dist/quill.snow.css';
117
+ * ```
118
+ */
119
+ class TextEditorComponent {
120
+ renderer = inject(Renderer2);
121
+ translationService = inject(TediTranslationService);
122
+ fieldContext = inject(TEDI_FIELD_CONTEXT, {
123
+ optional: true,
124
+ });
125
+ /**
126
+ * Editor contents as Quill HTML. Supports two-way binding; with reactive or
127
+ * template-driven forms bind the control instead.
128
+ */
129
+ value = model("", ...(ngDevMode ? [{ debugName: "value" }] : []));
130
+ /**
131
+ * Id set on the editing area. Quill's editing area is a `contenteditable`
132
+ * div, which `<label for>` cannot target, so pair this with `ariaLabelledby`
133
+ * rather than relying on a label's `for`.
134
+ */
135
+ inputId = input.required(...(ngDevMode ? [{ debugName: "inputId" }] : []));
136
+ /**
137
+ * Id of the element labelling the editor, usually your own `<label>`.
138
+ */
139
+ ariaLabelledby = input(...(ngDevMode ? [undefined, { debugName: "ariaLabelledby" }] : []));
140
+ /**
141
+ * Accessible name, for when there is no visible label. Ignored when
142
+ * `ariaLabelledby` is set.
143
+ */
144
+ ariaLabel = input(...(ngDevMode ? [undefined, { debugName: "ariaLabel" }] : []));
145
+ /**
146
+ * Forces the error state on. Combines with the state derived from the bound
147
+ * control, so `false` does not switch a derived error off.
148
+ */
149
+ // eslint-disable-next-line @angular-eslint/no-input-rename
150
+ invalidInput = input(false, ...(ngDevMode ? [{ debugName: "invalidInput", alias: "invalid" }] : [{ alias: "invalid" }]));
151
+ /**
152
+ * Marks the editor as required for assistive technology. Combines with the
153
+ * bound control's `Validators.required`.
154
+ */
155
+ // eslint-disable-next-line @angular-eslint/no-input-rename
156
+ requiredInput = input(false, ...(ngDevMode ? [{ debugName: "requiredInput", alias: "required" }] : [{ alias: "required" }]));
157
+ /**
158
+ * Placeholder shown while the editor is empty. Not translated.
159
+ */
160
+ placeholder = input("", ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
161
+ /**
162
+ * Quill module configuration. Replaces the default toolbar rather than
163
+ * extending it. Tab is always left to the browser so the editor can be tabbed
164
+ * out of; pass an explicit `keyboard.bindings.tab` to override that.
165
+ */
166
+ modules = input(TEXT_EDITOR_DEFAULT_MODULES, ...(ngDevMode ? [{ debugName: "modules" }] : []));
167
+ /**
168
+ * Rows the editing area rests at, and the fewest it can ever show.
169
+ *
170
+ * @default 10
171
+ */
172
+ minRows = input(10, ...(ngDevMode ? [{ debugName: "minRows" }] : []));
173
+ focused = signal(false, ...(ngDevMode ? [{ debugName: "focused" }] : []));
174
+ /**
175
+ * `quill-editor` is itself a `ControlValueAccessor`, so the cleanest bridge to
176
+ * it is a control of our own rather than reaching into the Quill instance.
177
+ */
178
+ innerControl = new FormControl("", {
179
+ nonNullable: true,
180
+ });
181
+ editorRoot = signal(null, ...(ngDevMode ? [{ debugName: "editorRoot" }] : []));
182
+ toolbar = signal(null, ...(ngDevMode ? [{ debugName: "toolbar" }] : []));
183
+ formDisabled = signal(false, ...(ngDevMode ? [{ debugName: "formDisabled" }] : []));
184
+ onChange = () => { };
185
+ onTouched = () => { };
186
+ derived = deriveControlState();
187
+ describedBy = controlDescribedBy();
188
+ touched = this.derived.touched;
189
+ dirty = this.derived.dirty;
190
+ disabled = computed(() => this.formDisabled() || (this.fieldContext?.disabled() ?? false), ...(ngDevMode ? [{ debugName: "disabled" }] : []));
191
+ invalid = computed(() => this.invalidInput() ||
192
+ this.derived.invalid() ||
193
+ (this.fieldContext?.invalid() ?? false), ...(ngDevMode ? [{ debugName: "invalid" }] : []));
194
+ required = computed(() => this.requiredInput() || this.derived.required(), ...(ngDevMode ? [{ debugName: "required" }] : []));
195
+ /**
196
+ * `tedi-form-field`'s counter measures the control's value, which here is
197
+ * Quill markup — a short sentence would blow a generous limit on tags alone.
198
+ * Report what the user can see instead.
199
+ */
200
+ characterCount = computed(() => visibleTextLength(this.value()), ...(ngDevMode ? [{ debugName: "characterCount" }] : []));
201
+ /**
202
+ * Quill's own Tab handling is disabled by default, but a caller-supplied
203
+ * binding of the same name still wins.
204
+ */
205
+ resolvedModules = computed(() => {
206
+ // An explicit `[modules]="undefined"` binding overrides the input default,
207
+ // so fall back here rather than trusting it.
208
+ const modules = this.modules() ?? TEXT_EDITOR_DEFAULT_MODULES;
209
+ const keyboard = typeof modules.keyboard === "object" && modules.keyboard !== null
210
+ ? modules.keyboard
211
+ : undefined;
212
+ return {
213
+ ...modules,
214
+ keyboard: {
215
+ ...keyboard,
216
+ bindings: { ...NO_KEYBOARD_TRAP_BINDINGS, ...keyboard?.bindings },
217
+ },
218
+ };
219
+ }, ...(ngDevMode ? [{ debugName: "resolvedModules" }] : []));
220
+ constructor() {
221
+ this.innerControl.valueChanges.subscribe((html) => {
222
+ const next = html ?? "";
223
+ if (untracked(this.value) === next)
224
+ return;
225
+ this.value.set(next);
226
+ this.onChange(next);
227
+ });
228
+ effect(() => {
229
+ const next = this.value();
230
+ if (this.innerControl.value !== next) {
231
+ this.innerControl.setValue(next, { emitEvent: false });
232
+ }
233
+ });
234
+ effect(() => {
235
+ const disabled = this.disabled();
236
+ if (disabled === this.innerControl.disabled)
237
+ return;
238
+ if (disabled)
239
+ this.innerControl.disable({ emitEvent: false });
240
+ else
241
+ this.innerControl.enable({ emitEvent: false });
242
+ });
243
+ this.syncEditorAttributes();
244
+ this.syncToolbarLabels();
245
+ }
246
+ ngOnInit() {
247
+ this.derived.connect();
248
+ }
249
+ handleEditorCreated = (quill) => {
250
+ this.editorRoot.set(quill.root);
251
+ this.toolbar.set(quill.getModule("toolbar")
252
+ ?.container ?? null);
253
+ };
254
+ handleBlur() {
255
+ this.focused.set(false);
256
+ this.onTouched();
257
+ }
258
+ setDescribedBy(ids) {
259
+ this.describedBy.set(ids);
260
+ }
261
+ reset() {
262
+ if (this.disabled())
263
+ return;
264
+ this.value.set("");
265
+ this.onChange("");
266
+ this.onTouched();
267
+ }
268
+ focus() {
269
+ if (this.disabled())
270
+ return;
271
+ this.editorRoot()?.focus();
272
+ }
273
+ writeValue(value) {
274
+ this.value.set(value ?? "");
275
+ }
276
+ registerOnChange(fn) {
277
+ this.onChange = fn;
278
+ }
279
+ registerOnTouched(fn) {
280
+ this.onTouched = fn;
281
+ }
282
+ setDisabledState(isDisabled) {
283
+ this.formDisabled.set(isDisabled);
284
+ }
285
+ /**
286
+ * Names the toolbar controls and gives them a hover tooltip. Quill's own
287
+ * `aria-label` is the untranslated format string, and it leaves the pickers
288
+ * nameless entirely, so both attributes are rewritten from the translations.
289
+ * Re-runs on a language change.
290
+ */
291
+ syncToolbarLabels() {
292
+ effect(() => {
293
+ const toolbar = this.toolbar();
294
+ if (!toolbar)
295
+ return;
296
+ const controls = Array.from(toolbar.querySelectorAll("button, .ql-picker"));
297
+ for (const control of controls) {
298
+ const key = toolbarLabelKey(control);
299
+ if (!key)
300
+ continue;
301
+ const label = this.translationService.translate(key);
302
+ // A picker's own node is a `span`; the focusable, hoverable part is its
303
+ // label child, so that is what has to carry the name and the tooltip.
304
+ const target = control.querySelector(".ql-picker-label") ?? control;
305
+ this.renderer.setAttribute(target, "title", label);
306
+ this.renderer.setAttribute(target, "aria-label", label);
307
+ }
308
+ });
309
+ }
310
+ /**
311
+ * Mirrors identity, name and state onto `.ql-editor`. Quill gives it no role
312
+ * of its own, so without this it is exposed as a nameless `generic` node and
313
+ * none of these attributes reach assistive technology.
314
+ */
315
+ syncEditorAttributes() {
316
+ effect(() => {
317
+ const editor = this.editorRoot();
318
+ if (!editor)
319
+ return;
320
+ const labelledby = this.ariaLabelledby();
321
+ const invalid = this.invalid();
322
+ const attributes = {
323
+ id: this.inputId(),
324
+ role: "textbox",
325
+ "aria-multiline": "true",
326
+ "aria-labelledby": labelledby ?? null,
327
+ "aria-label": labelledby ? null : (this.ariaLabel() ?? null),
328
+ "aria-describedby": this.describedBy.attribute(),
329
+ "aria-required": this.required() ? "true" : null,
330
+ "aria-invalid": invalid ? "true" : null,
331
+ };
332
+ for (const [name, attributeValue] of Object.entries(attributes)) {
333
+ if (attributeValue === null) {
334
+ this.renderer.removeAttribute(editor, name);
335
+ }
336
+ else {
337
+ this.renderer.setAttribute(editor, name, attributeValue);
338
+ }
339
+ }
340
+ });
341
+ }
342
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: TextEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
343
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.24", type: TextEditorComponent, isStandalone: true, selector: "tedi-text-editor", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, inputId: { classPropertyName: "inputId", publicName: "inputId", isSignal: true, isRequired: true, transformFunction: null }, ariaLabelledby: { classPropertyName: "ariaLabelledby", publicName: "ariaLabelledby", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, invalidInput: { classPropertyName: "invalidInput", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, requiredInput: { classPropertyName: "requiredInput", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, modules: { classPropertyName: "modules", publicName: "modules", isSignal: true, isRequired: false, transformFunction: null }, minRows: { classPropertyName: "minRows", publicName: "minRows", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { properties: { "style.--_tedi-text-editor-min-rows": "minRows()" }, classAttribute: "tedi-text-editor" }, providers: [
344
+ {
345
+ provide: NG_VALUE_ACCESSOR,
346
+ useExisting: forwardRef(() => TextEditorComponent),
347
+ multi: true,
348
+ },
349
+ {
350
+ provide: TEDI_FORM_FIELD_CONTROL,
351
+ useExisting: forwardRef(() => TextEditorComponent),
352
+ },
353
+ ], ngImport: i0, template: "<quill-editor\n [formControl]=\"innerControl\"\n [modules]=\"resolvedModules()\"\n [placeholder]=\"placeholder()\"\n [class.tedi-text-editor__editor--disabled]=\"disabled()\"\n [class.tedi-text-editor__editor--error]=\"invalid()\"\n [class.tedi-text-editor__editor--focused]=\"focused()\"\n class=\"tedi-text-editor__editor\"\n (onEditorCreated)=\"handleEditorCreated($event)\"\n (onFocus)=\"focused.set(true)\"\n (onBlur)=\"handleBlur()\"\n/>\n", styles: [".tedi-text-editor,.tedi-text-editor .tedi-text-editor__editor{display:block}.tedi-text-editor__editor{--_border-radius: var(--form-field-radius);--_border-color: var(--form-input-border-default);--_color: var(--form-input-text-filled);--_background-color: var(--form-input-background-default);--_placeholder-color: var(--form-input-text-placeholder);width:100%;color:var(--_color);border:1px solid var(--_border-color);border-radius:var(--_border-radius)}.tedi-text-editor__editor.tedi-text-editor__editor--focused:not(.tedi-text-editor__editor--error,.tedi-text-editor__editor--disabled){border-color:var(--form-input-border-hover);box-shadow:inset 0 0 0 1px var(--form-input-border-hover),0 0 0 1px var(--form-input-border-hover)}.tedi-text-editor__editor:hover{--_border-color: var(--form-input-border-hover)}.tedi-text-editor__editor--disabled{--_border-color: var(--form-input-border-disabled);color:var(--form-input-text-disabled);pointer-events:none;background-color:var(--form-input-background-disabled)}.tedi-text-editor__editor--error:not(.tedi-text-editor__editor--disabled){--_border-color: var(--form-general-feedback-error-border)}.tedi-text-editor__editor--error:not(.tedi-text-editor__editor--disabled).tedi-text-editor__editor--focused:not(.tedi-text-editor__editor--error,.tedi-text-editor__editor--disabled){border-color:var(--form-general-feedback-error-border);box-shadow:inset 0 0 0 1px var(--form-general-feedback-error-border),0 0 0 1px var(--form-general-feedback-error-border)}.tedi-text-editor__editor .ql-toolbar.ql-snow{border:0;border-bottom:1px solid var(--_border-color)}.tedi-text-editor__editor .ql-container.ql-snow{border:0}.tedi-text-editor__editor .ql-toolbar .ql-formats{display:inline-flex;flex-wrap:wrap;gap:.5rem;align-items:center}.tedi-text-editor__editor .ql-toolbar .ql-formats>button,.tedi-text-editor__editor .ql-toolbar .ql-formats>.ql-picker,.tedi-text-editor__editor .ql-toolbar .ql-formats>.ql-picker>[role=button]{border-radius:var(--tedi-radius-02-default)}.tedi-text-editor__editor .ql-toolbar .ql-formats>button:hover,.tedi-text-editor__editor .ql-toolbar .ql-formats>.ql-picker:hover,.tedi-text-editor__editor .ql-toolbar .ql-formats>.ql-picker>[role=button]:hover{background-color:var(--general-surface-hover)}.tedi-text-editor__editor .ql-toolbar .ql-formats>button.ql-active,.tedi-text-editor__editor .ql-toolbar .ql-formats>.ql-picker.ql-active,.tedi-text-editor__editor .ql-toolbar .ql-formats>.ql-picker>[role=button].ql-active{background-color:var(--general-icon-background-brand-primary)}.tedi-text-editor__editor .ql-toolbar .ql-formats .ql-stroke{stroke:var(--general-icon-brand)}.tedi-text-editor__editor .ql-toolbar .ql-formats .ql-active .ql-stroke{stroke:var(--general-icon-white)}.tedi-text-editor__editor .ql-toolbar .ql-formats .ql-picker.ql-expanded>.ql-picker-label{color:var(--general-icon-white);background-color:var(--general-icon-background-brand-primary);border-color:transparent}.tedi-text-editor__editor .ql-toolbar .ql-formats .ql-picker.ql-expanded>.ql-picker-label .ql-stroke{stroke:var(--general-icon-white)}.tedi-text-editor__editor .ql-toolbar .ql-formats .ql-picker.ql-expanded>.ql-picker-label .ql-fill{fill:var(--general-icon-white)}.tedi-text-editor__editor .ql-toolbar .ql-formats .ql-picker.ql-expanded>.ql-picker-options{background-color:var(--card-background-primary);border-color:var(--general-border-primary);border-radius:var(--tedi-radius-02-default);box-shadow:0 1px 5px 0 var(--tedi-alpha-20)}.tedi-text-editor__editor .ql-toolbar .ql-color-picker .ql-picker-item.ql-selected,.tedi-text-editor__editor .ql-toolbar .ql-color-picker .ql-picker-item:hover{border-color:var(--general-border-brand)}.tedi-text-editor__editor .ql-container .ql-editor{--_font-size: var(--body-regular-size);--_line-height: var(--body-regular-line-height);--_padding-y: var(--form-field-padding-y-md-default);--_padding-x: var(--form-field-padding-x-md-default);--_form-field-outer-gap: var(--form-field-outer-spacing);min-height:calc(var(--_tedi-text-editor-min-rows) * 1lh + 2 * var(--_padding-y));padding:var(--_padding-y) var(--_padding-x);font-family:var(--family-default);font-size:var(--_font-size);line-height:var(--_line-height);resize:vertical;border-radius:var(--_border-radius)}.tedi-text-editor__editor .ql-editor.ql-blank:before{font-style:normal;color:var(--_placeholder-color)}\n"], dependencies: [{ kind: "component", type: QuillEditorComponent, selector: "quill-editor" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
354
+ }
355
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: TextEditorComponent, decorators: [{
356
+ type: Component,
357
+ args: [{ selector: "tedi-text-editor", standalone: true, imports: [QuillEditorComponent, ReactiveFormsModule], providers: [
358
+ {
359
+ provide: NG_VALUE_ACCESSOR,
360
+ useExisting: forwardRef(() => TextEditorComponent),
361
+ multi: true,
362
+ },
363
+ {
364
+ provide: TEDI_FORM_FIELD_CONTROL,
365
+ useExisting: forwardRef(() => TextEditorComponent),
366
+ },
367
+ ], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: {
368
+ class: "tedi-text-editor",
369
+ "[style.--_tedi-text-editor-min-rows]": "minRows()",
370
+ }, template: "<quill-editor\n [formControl]=\"innerControl\"\n [modules]=\"resolvedModules()\"\n [placeholder]=\"placeholder()\"\n [class.tedi-text-editor__editor--disabled]=\"disabled()\"\n [class.tedi-text-editor__editor--error]=\"invalid()\"\n [class.tedi-text-editor__editor--focused]=\"focused()\"\n class=\"tedi-text-editor__editor\"\n (onEditorCreated)=\"handleEditorCreated($event)\"\n (onFocus)=\"focused.set(true)\"\n (onBlur)=\"handleBlur()\"\n/>\n", styles: [".tedi-text-editor,.tedi-text-editor .tedi-text-editor__editor{display:block}.tedi-text-editor__editor{--_border-radius: var(--form-field-radius);--_border-color: var(--form-input-border-default);--_color: var(--form-input-text-filled);--_background-color: var(--form-input-background-default);--_placeholder-color: var(--form-input-text-placeholder);width:100%;color:var(--_color);border:1px solid var(--_border-color);border-radius:var(--_border-radius)}.tedi-text-editor__editor.tedi-text-editor__editor--focused:not(.tedi-text-editor__editor--error,.tedi-text-editor__editor--disabled){border-color:var(--form-input-border-hover);box-shadow:inset 0 0 0 1px var(--form-input-border-hover),0 0 0 1px var(--form-input-border-hover)}.tedi-text-editor__editor:hover{--_border-color: var(--form-input-border-hover)}.tedi-text-editor__editor--disabled{--_border-color: var(--form-input-border-disabled);color:var(--form-input-text-disabled);pointer-events:none;background-color:var(--form-input-background-disabled)}.tedi-text-editor__editor--error:not(.tedi-text-editor__editor--disabled){--_border-color: var(--form-general-feedback-error-border)}.tedi-text-editor__editor--error:not(.tedi-text-editor__editor--disabled).tedi-text-editor__editor--focused:not(.tedi-text-editor__editor--error,.tedi-text-editor__editor--disabled){border-color:var(--form-general-feedback-error-border);box-shadow:inset 0 0 0 1px var(--form-general-feedback-error-border),0 0 0 1px var(--form-general-feedback-error-border)}.tedi-text-editor__editor .ql-toolbar.ql-snow{border:0;border-bottom:1px solid var(--_border-color)}.tedi-text-editor__editor .ql-container.ql-snow{border:0}.tedi-text-editor__editor .ql-toolbar .ql-formats{display:inline-flex;flex-wrap:wrap;gap:.5rem;align-items:center}.tedi-text-editor__editor .ql-toolbar .ql-formats>button,.tedi-text-editor__editor .ql-toolbar .ql-formats>.ql-picker,.tedi-text-editor__editor .ql-toolbar .ql-formats>.ql-picker>[role=button]{border-radius:var(--tedi-radius-02-default)}.tedi-text-editor__editor .ql-toolbar .ql-formats>button:hover,.tedi-text-editor__editor .ql-toolbar .ql-formats>.ql-picker:hover,.tedi-text-editor__editor .ql-toolbar .ql-formats>.ql-picker>[role=button]:hover{background-color:var(--general-surface-hover)}.tedi-text-editor__editor .ql-toolbar .ql-formats>button.ql-active,.tedi-text-editor__editor .ql-toolbar .ql-formats>.ql-picker.ql-active,.tedi-text-editor__editor .ql-toolbar .ql-formats>.ql-picker>[role=button].ql-active{background-color:var(--general-icon-background-brand-primary)}.tedi-text-editor__editor .ql-toolbar .ql-formats .ql-stroke{stroke:var(--general-icon-brand)}.tedi-text-editor__editor .ql-toolbar .ql-formats .ql-active .ql-stroke{stroke:var(--general-icon-white)}.tedi-text-editor__editor .ql-toolbar .ql-formats .ql-picker.ql-expanded>.ql-picker-label{color:var(--general-icon-white);background-color:var(--general-icon-background-brand-primary);border-color:transparent}.tedi-text-editor__editor .ql-toolbar .ql-formats .ql-picker.ql-expanded>.ql-picker-label .ql-stroke{stroke:var(--general-icon-white)}.tedi-text-editor__editor .ql-toolbar .ql-formats .ql-picker.ql-expanded>.ql-picker-label .ql-fill{fill:var(--general-icon-white)}.tedi-text-editor__editor .ql-toolbar .ql-formats .ql-picker.ql-expanded>.ql-picker-options{background-color:var(--card-background-primary);border-color:var(--general-border-primary);border-radius:var(--tedi-radius-02-default);box-shadow:0 1px 5px 0 var(--tedi-alpha-20)}.tedi-text-editor__editor .ql-toolbar .ql-color-picker .ql-picker-item.ql-selected,.tedi-text-editor__editor .ql-toolbar .ql-color-picker .ql-picker-item:hover{border-color:var(--general-border-brand)}.tedi-text-editor__editor .ql-container .ql-editor{--_font-size: var(--body-regular-size);--_line-height: var(--body-regular-line-height);--_padding-y: var(--form-field-padding-y-md-default);--_padding-x: var(--form-field-padding-x-md-default);--_form-field-outer-gap: var(--form-field-outer-spacing);min-height:calc(var(--_tedi-text-editor-min-rows) * 1lh + 2 * var(--_padding-y));padding:var(--_padding-y) var(--_padding-x);font-family:var(--family-default);font-size:var(--_font-size);line-height:var(--_line-height);resize:vertical;border-radius:var(--_border-radius)}.tedi-text-editor__editor .ql-editor.ql-blank:before{font-style:normal;color:var(--_placeholder-color)}\n"] }]
371
+ }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: true }] }], ariaLabelledby: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabelledby", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], invalidInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], requiredInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], modules: [{ type: i0.Input, args: [{ isSignal: true, alias: "modules", required: false }] }], minRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "minRows", required: false }] }] } });
372
+
373
+ /**
374
+ * Generated bundle index. Do not edit.
375
+ */
376
+
377
+ export { TEXT_EDITOR_DEFAULT_MODULES, TextEditorComponent };
378
+ //# sourceMappingURL=tedi-design-system-angular-community-text-editor.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tedi-design-system-angular-community-text-editor.mjs","sources":["../../src/community/text-editor/text-editor.component.ts","../../src/community/text-editor/text-editor.component.html","../../src/community/text-editor/tedi-design-system-angular-community-text-editor.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n effect,\n forwardRef,\n inject,\n input,\n model,\n OnInit,\n Renderer2,\n signal,\n untracked,\n ViewEncapsulation,\n} from \"@angular/core\";\nimport {\n ControlValueAccessor,\n FormControl,\n NG_VALUE_ACCESSOR,\n ReactiveFormsModule,\n} from \"@angular/forms\";\nimport {\n controlDescribedBy,\n deriveControlState,\n FormFieldControl,\n TEDI_FIELD_CONTEXT,\n TEDI_FORM_FIELD_CONTROL,\n TediTranslationService,\n} from \"@tedi-design-system/angular/tedi\";\nimport { QuillEditorComponent, QuillModules } from \"ngx-quill\";\nimport type Quill from \"quill\";\n\nexport const TEXT_EDITOR_DEFAULT_MODULES: QuillModules = {\n toolbar: [\n [\n \"bold\",\n \"italic\",\n \"underline\",\n { align: \"justify\" },\n { list: \"bullet\" },\n { list: \"ordered\" },\n { indent: \"-1\" },\n { indent: \"+1\" },\n { background: [] },\n { color: [] },\n \"clean\",\n ],\n ],\n};\n\n/**\n * Quill binds Tab to \"insert a tab character\" and, inside a list, to indent and\n * outdent. All three swallow the key and leave the user unable to tab out of the\n * editor, which is a keyboard trap (WCAG 2.1.2). Quill skips any binding whose\n * value is `null`, so nulling them lets Tab fall through to the browser's normal\n * focus move. List indenting stays available from the toolbar`.\n */\nconst NO_KEYBOARD_TRAP_BINDINGS = {\n tab: null,\n indent: null,\n outdent: null,\n};\n\n/**\n * Translation key per toolbar control, keyed by Quill's format name and, where\n * one format drives several buttons, its value. Quill names the buttons itself\n * but only from the raw format (`aria-label=\"indent: +1\"`), so every control\n * listed here is relabelled; anything absent keeps Quill's own name.\n */\nconst TOOLBAR_LABEL_KEYS: Record<string, string> = {\n bold: \"text-editor.bold\",\n italic: \"text-editor.italic\",\n underline: \"text-editor.underline\",\n strike: \"text-editor.strike\",\n blockquote: \"text-editor.blockquote\",\n link: \"text-editor.link\",\n clean: \"text-editor.clean\",\n color: \"text-editor.color\",\n background: \"text-editor.background\",\n align: \"text-editor.align.left\",\n \"align:center\": \"text-editor.align.center\",\n \"align:right\": \"text-editor.align.right\",\n \"align:justify\": \"text-editor.align.justify\",\n \"list:bullet\": \"text-editor.list.bullet\",\n \"list:ordered\": \"text-editor.list.ordered\",\n \"indent:+1\": \"text-editor.indent.increase\",\n \"indent:-1\": \"text-editor.indent.decrease\",\n};\n\nconst STRUCTURAL_TOOLBAR_CLASSES = new Set([\n \"ql-picker\",\n \"ql-color-picker\",\n \"ql-icon-picker\",\n \"ql-expanded\",\n \"ql-active\",\n]);\n\n/**\n * Quill tags a control with `ql-<format>` alongside its structural classes, and\n * puts the discriminating value in `value` where one format drives several\n * buttons. Left align is given an empty value, so it falls back to the bare\n * format name.\n */\nfunction toolbarLabelKey(control: HTMLElement): string | undefined {\n const format = Array.from(control.classList).find(\n (name) => name.startsWith(\"ql-\") && !STRUCTURAL_TOOLBAR_CLASSES.has(name),\n );\n if (!format) return undefined;\n\n const value = control.getAttribute(\"value\");\n const base = format.slice(\"ql-\".length);\n\n return TOOLBAR_LABEL_KEYS[value ? `${base}:${value}` : base];\n}\n\nconst SERIALIZED_ENTITIES: Record<string, string> = {\n \"&amp;\": \"&\",\n \"&lt;\": \"<\",\n \"&gt;\": \">\",\n \"&quot;\": '\"',\n \"&#39;\": \"'\",\n \"&nbsp;\": \"\\u00a0\",\n};\n\n/**\n * Length of the text a reader actually sees, with the markup stripped. Parsed\n * rather than regex-stripped so entities (`&nbsp;`) count as the one character\n * they render as; a `DOMParser` document is inert, so nothing in the markup\n * runs or loads.\n */\nfunction visibleTextLength(html: string): number {\n if (!html) return 0;\n\n if (typeof DOMParser === \"undefined\") {\n return html\n .replace(/<[^>]*>/g, \"\")\n .replace(\n /&(?:amp|lt|gt|quot|nbsp|#39);/g,\n (entity) => SERIALIZED_ENTITIES[entity],\n ).length;\n }\n\n const text =\n new DOMParser().parseFromString(html, \"text/html\").body.textContent ?? \"\";\n\n return text.length;\n}\n\n/**\n * Rich text editor built on ngx-quill. The value is Quill HTML.\n *\n * Requires Quill's stylesheets in the global styles file:\n *\n * @example\n * ```scss\n * @forward 'quill/dist/quill.core.css';\n * @forward 'quill/dist/quill.snow.css';\n * ```\n */\n@Component({\n selector: \"tedi-text-editor\",\n standalone: true,\n imports: [QuillEditorComponent, ReactiveFormsModule],\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => TextEditorComponent),\n multi: true,\n },\n {\n provide: TEDI_FORM_FIELD_CONTROL,\n useExisting: forwardRef(() => TextEditorComponent),\n },\n ],\n templateUrl: \"./text-editor.component.html\",\n styleUrl: \"./text-editor.component.scss\",\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n class: \"tedi-text-editor\",\n \"[style.--_tedi-text-editor-min-rows]\": \"minRows()\",\n },\n})\nexport class TextEditorComponent\n implements OnInit, ControlValueAccessor, FormFieldControl<string> {\n private readonly renderer = inject(Renderer2);\n private readonly translationService = inject(TediTranslationService);\n private readonly fieldContext = inject(TEDI_FIELD_CONTEXT, {\n optional: true,\n });\n\n /**\n * Editor contents as Quill HTML. Supports two-way binding; with reactive or\n * template-driven forms bind the control instead.\n */\n value = model<string>(\"\");\n /**\n * Id set on the editing area. Quill's editing area is a `contenteditable`\n * div, which `<label for>` cannot target, so pair this with `ariaLabelledby`\n * rather than relying on a label's `for`.\n */\n inputId = input.required<string>();\n /**\n * Id of the element labelling the editor, usually your own `<label>`.\n */\n ariaLabelledby = input<string>();\n /**\n * Accessible name, for when there is no visible label. Ignored when\n * `ariaLabelledby` is set.\n */\n ariaLabel = input<string>();\n /**\n * Forces the error state on. Combines with the state derived from the bound\n * control, so `false` does not switch a derived error off.\n */\n // eslint-disable-next-line @angular-eslint/no-input-rename\n readonly invalidInput = input<boolean>(false, { alias: \"invalid\" });\n /**\n * Marks the editor as required for assistive technology. Combines with the\n * bound control's `Validators.required`.\n */\n // eslint-disable-next-line @angular-eslint/no-input-rename\n readonly requiredInput = input<boolean>(false, { alias: \"required\" });\n /**\n * Placeholder shown while the editor is empty. Not translated.\n */\n placeholder = input<string>(\"\");\n /**\n * Quill module configuration. Replaces the default toolbar rather than\n * extending it. Tab is always left to the browser so the editor can be tabbed\n * out of; pass an explicit `keyboard.bindings.tab` to override that.\n */\n modules = input<QuillModules>(TEXT_EDITOR_DEFAULT_MODULES);\n /**\n * Rows the editing area rests at, and the fewest it can ever show.\n *\n * @default 10\n */\n minRows = input<number>(10);\n\n readonly focused = signal(false);\n\n /**\n * `quill-editor` is itself a `ControlValueAccessor`, so the cleanest bridge to\n * it is a control of our own rather than reaching into the Quill instance.\n */\n protected readonly innerControl = new FormControl<string>(\"\", {\n nonNullable: true,\n });\n\n private readonly editorRoot = signal<HTMLElement | null>(null);\n private readonly toolbar = signal<HTMLElement | null>(null);\n private readonly formDisabled = signal(false);\n private onChange: (value: string) => void = () => { };\n private onTouched: () => void = () => { };\n\n private readonly derived = deriveControlState();\n readonly describedBy = controlDescribedBy();\n\n readonly touched = this.derived.touched;\n readonly dirty = this.derived.dirty;\n\n readonly disabled = computed(\n () => this.formDisabled() || (this.fieldContext?.disabled() ?? false),\n );\n\n readonly invalid = computed(\n () =>\n this.invalidInput() ||\n this.derived.invalid() ||\n (this.fieldContext?.invalid() ?? false),\n );\n\n readonly required = computed(\n () => this.requiredInput() || this.derived.required(),\n );\n\n /**\n * `tedi-form-field`'s counter measures the control's value, which here is\n * Quill markup — a short sentence would blow a generous limit on tags alone.\n * Report what the user can see instead.\n */\n readonly characterCount = computed(() => visibleTextLength(this.value()));\n\n /**\n * Quill's own Tab handling is disabled by default, but a caller-supplied\n * binding of the same name still wins.\n */\n readonly resolvedModules = computed<QuillModules>(() => {\n // An explicit `[modules]=\"undefined\"` binding overrides the input default,\n // so fall back here rather than trusting it.\n const modules = this.modules() ?? TEXT_EDITOR_DEFAULT_MODULES;\n const keyboard =\n typeof modules.keyboard === \"object\" && modules.keyboard !== null\n ? modules.keyboard\n : undefined;\n\n return {\n ...modules,\n keyboard: {\n ...keyboard,\n bindings: { ...NO_KEYBOARD_TRAP_BINDINGS, ...keyboard?.bindings },\n },\n };\n });\n\n constructor() {\n this.innerControl.valueChanges.subscribe((html) => {\n const next = html ?? \"\";\n if (untracked(this.value) === next) return;\n\n this.value.set(next);\n this.onChange(next);\n });\n\n effect(() => {\n const next = this.value();\n if (this.innerControl.value !== next) {\n this.innerControl.setValue(next, { emitEvent: false });\n }\n });\n\n effect(() => {\n const disabled = this.disabled();\n if (disabled === this.innerControl.disabled) return;\n\n if (disabled) this.innerControl.disable({ emitEvent: false });\n else this.innerControl.enable({ emitEvent: false });\n });\n\n this.syncEditorAttributes();\n this.syncToolbarLabels();\n }\n\n ngOnInit() {\n this.derived.connect();\n }\n\n handleEditorCreated = (quill: Quill): void => {\n this.editorRoot.set(quill.root);\n this.toolbar.set(\n (quill.getModule(\"toolbar\") as { container?: HTMLElement } | undefined)\n ?.container ?? null,\n );\n };\n\n handleBlur() {\n this.focused.set(false);\n this.onTouched();\n }\n\n setDescribedBy(ids: string[]) {\n this.describedBy.set(ids);\n }\n\n reset() {\n if (this.disabled()) return;\n\n this.value.set(\"\");\n this.onChange(\"\");\n this.onTouched();\n }\n\n focus() {\n if (this.disabled()) return;\n this.editorRoot()?.focus();\n }\n\n writeValue(value: string | null): void {\n this.value.set(value ?? \"\");\n }\n\n registerOnChange(fn: (value: string) => void): void {\n this.onChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this.formDisabled.set(isDisabled);\n }\n\n /**\n * Names the toolbar controls and gives them a hover tooltip. Quill's own\n * `aria-label` is the untranslated format string, and it leaves the pickers\n * nameless entirely, so both attributes are rewritten from the translations.\n * Re-runs on a language change.\n */\n private syncToolbarLabels() {\n effect(() => {\n const toolbar = this.toolbar();\n if (!toolbar) return;\n\n const controls = Array.from(\n toolbar.querySelectorAll<HTMLElement>(\"button, .ql-picker\"),\n );\n\n for (const control of controls) {\n const key = toolbarLabelKey(control);\n if (!key) continue;\n\n const label = this.translationService.translate(key);\n // A picker's own node is a `span`; the focusable, hoverable part is its\n // label child, so that is what has to carry the name and the tooltip.\n const target =\n control.querySelector<HTMLElement>(\".ql-picker-label\") ?? control;\n\n this.renderer.setAttribute(target, \"title\", label);\n this.renderer.setAttribute(target, \"aria-label\", label);\n }\n });\n }\n\n /**\n * Mirrors identity, name and state onto `.ql-editor`. Quill gives it no role\n * of its own, so without this it is exposed as a nameless `generic` node and\n * none of these attributes reach assistive technology.\n */\n private syncEditorAttributes() {\n effect(() => {\n const editor = this.editorRoot();\n if (!editor) return;\n\n const labelledby = this.ariaLabelledby();\n const invalid = this.invalid();\n\n const attributes: Record<string, string | null> = {\n id: this.inputId(),\n role: \"textbox\",\n \"aria-multiline\": \"true\",\n \"aria-labelledby\": labelledby ?? null,\n \"aria-label\": labelledby ? null : (this.ariaLabel() ?? null),\n \"aria-describedby\": this.describedBy.attribute(),\n \"aria-required\": this.required() ? \"true\" : null,\n \"aria-invalid\": invalid ? \"true\" : null,\n };\n\n for (const [name, attributeValue] of Object.entries(attributes)) {\n if (attributeValue === null) {\n this.renderer.removeAttribute(editor, name);\n } else {\n this.renderer.setAttribute(editor, name, attributeValue);\n }\n }\n });\n }\n}\n","<quill-editor\n [formControl]=\"innerControl\"\n [modules]=\"resolvedModules()\"\n [placeholder]=\"placeholder()\"\n [class.tedi-text-editor__editor--disabled]=\"disabled()\"\n [class.tedi-text-editor__editor--error]=\"invalid()\"\n [class.tedi-text-editor__editor--focused]=\"focused()\"\n class=\"tedi-text-editor__editor\"\n (onEditorCreated)=\"handleEditorCreated($event)\"\n (onFocus)=\"focused.set(true)\"\n (onBlur)=\"handleBlur()\"\n/>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}