@theseam/ui-common 0.4.25 → 0.4.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/esm2020/data-filters/filters/data-filter-search/data-filter-search.component.mjs +1 -1
  2. package/esm2020/data-filters/filters/data-filter-text/data-filter-text.component.mjs +1 -1
  3. package/esm2020/datatable/datatable-column-preferences/datatable-column-preferences.component.mjs +1 -1
  4. package/esm2020/form-field/input.directive.mjs +8 -4
  5. package/esm2020/framework/schema-form-controls/schema-form-input/schema-form-input.component.mjs +1 -1
  6. package/esm2020/framework/schema-form-controls/schema-form-number/schema-form-number.component.mjs +1 -1
  7. package/esm2020/framework/schema-form-controls/schema-form-select/schema-form-select.component.mjs +2 -2
  8. package/esm2020/framework/schema-form-controls/schema-form-tel/schema-form-tel.component.mjs +2 -2
  9. package/esm2020/google-maps/google-maps-places-autocomplete/google-maps-places-autocomplete.component.mjs +1 -1
  10. package/esm2020/rich-text/public-api.mjs +5 -0
  11. package/esm2020/rich-text/rich-text/rich-text.component.mjs +594 -0
  12. package/esm2020/rich-text/rich-text.module.mjs +32 -0
  13. package/esm2020/rich-text/theseam-ui-common-rich-text.mjs +5 -0
  14. package/esm2020/rich-text/utils/models.mjs +24 -0
  15. package/esm2020/rich-text/utils/utils.mjs +123 -0
  16. package/esm2020/tel-input/tel-input/tel-input.component.mjs +2 -2
  17. package/esm2020/utils/is-null-or-undefined-or-empty.mjs +4 -0
  18. package/esm2020/utils/not-null-or-undefined-or-empty.mjs +4 -0
  19. package/esm2020/utils/public-api.mjs +3 -1
  20. package/fesm2015/theseam-ui-common-data-filters.mjs +2 -2
  21. package/fesm2015/theseam-ui-common-data-filters.mjs.map +1 -1
  22. package/fesm2015/theseam-ui-common-datatable.mjs +1 -1
  23. package/fesm2015/theseam-ui-common-datatable.mjs.map +1 -1
  24. package/fesm2015/theseam-ui-common-form-field.mjs +7 -3
  25. package/fesm2015/theseam-ui-common-form-field.mjs.map +1 -1
  26. package/fesm2015/theseam-ui-common-framework.mjs +4 -4
  27. package/fesm2015/theseam-ui-common-framework.mjs.map +1 -1
  28. package/fesm2015/theseam-ui-common-google-maps.mjs +1 -1
  29. package/fesm2015/theseam-ui-common-google-maps.mjs.map +1 -1
  30. package/fesm2015/theseam-ui-common-rich-text.mjs +767 -0
  31. package/fesm2015/theseam-ui-common-rich-text.mjs.map +1 -0
  32. package/fesm2015/theseam-ui-common-tel-input.mjs +1 -1
  33. package/fesm2015/theseam-ui-common-tel-input.mjs.map +1 -1
  34. package/fesm2015/theseam-ui-common-utils.mjs +9 -1
  35. package/fesm2015/theseam-ui-common-utils.mjs.map +1 -1
  36. package/fesm2020/theseam-ui-common-data-filters.mjs +2 -2
  37. package/fesm2020/theseam-ui-common-data-filters.mjs.map +1 -1
  38. package/fesm2020/theseam-ui-common-datatable.mjs +1 -1
  39. package/fesm2020/theseam-ui-common-datatable.mjs.map +1 -1
  40. package/fesm2020/theseam-ui-common-form-field.mjs +7 -3
  41. package/fesm2020/theseam-ui-common-form-field.mjs.map +1 -1
  42. package/fesm2020/theseam-ui-common-framework.mjs +4 -4
  43. package/fesm2020/theseam-ui-common-framework.mjs.map +1 -1
  44. package/fesm2020/theseam-ui-common-google-maps.mjs +1 -1
  45. package/fesm2020/theseam-ui-common-google-maps.mjs.map +1 -1
  46. package/fesm2020/theseam-ui-common-rich-text.mjs +773 -0
  47. package/fesm2020/theseam-ui-common-rich-text.mjs.map +1 -0
  48. package/fesm2020/theseam-ui-common-tel-input.mjs +1 -1
  49. package/fesm2020/theseam-ui-common-tel-input.mjs.map +1 -1
  50. package/fesm2020/theseam-ui-common-utils.mjs +9 -1
  51. package/fesm2020/theseam-ui-common-utils.mjs.map +1 -1
  52. package/form-field/input.directive.d.ts +2 -1
  53. package/package.json +9 -1
  54. package/rich-text/index.d.ts +5 -0
  55. package/rich-text/public-api.d.ts +4 -0
  56. package/rich-text/rich-text/rich-text.component.d.ts +194 -0
  57. package/rich-text/rich-text.module.d.ts +10 -0
  58. package/rich-text/utils/models.d.ts +343 -0
  59. package/rich-text/utils/utils.d.ts +14 -0
  60. package/styles/vendor/quill/_quill.scss +162 -10
  61. package/utils/is-null-or-undefined-or-empty.d.ts +1 -0
  62. package/utils/not-null-or-undefined-or-empty.d.ts +1 -0
  63. package/utils/public-api.d.ts +2 -0
@@ -0,0 +1,767 @@
1
+ import { __awaiter } from 'tslib';
2
+ import { coerceBooleanProperty } from '@angular/cdk/coercion';
3
+ import * as i0 from '@angular/core';
4
+ import { InjectionToken, forwardRef, EventEmitter, Component, Optional, Inject, Input, Output, ViewChild, HostListener, NgModule } from '@angular/core';
5
+ import * as i2 from '@angular/forms';
6
+ import { NG_VALUE_ACCESSOR, FormControl, ReactiveFormsModule } from '@angular/forms';
7
+ import 'quill-mention';
8
+ import { BehaviorSubject, filter, shareReplay, Subject, combineLatest, map, switchMap, startWith, of, tap, take, lastValueFrom } from 'rxjs';
9
+ import { isNullOrUndefined, notNullOrUndefined, notNullOrUndefinedOrEmpty } from '@theseam/ui-common/utils';
10
+ import * as i1 from '@angular/common';
11
+ import { CommonModule } from '@angular/common';
12
+ import * as i3 from 'ngx-quill';
13
+ import { QuillModule } from 'ngx-quill';
14
+
15
+ const HTML_ENTITY_REGEX = /<[^>]+>/gm;
16
+ const THESEAM_QUILL_TOOLBAR_OPTIONS_DEFAULT = [
17
+ ['bold', 'italic', 'underline', 'strike'],
18
+ [{ header: [0, 1, 2, 3, 4, 5] }],
19
+ [{ list: 'ordered' }, { list: 'bullet' }],
20
+ [{ align: [] }],
21
+ ['link'],
22
+ ['clean'],
23
+ ];
24
+ const THESEAM_QUILL_MENTION_OPTIONS_DEFAULT = {
25
+ spaceAfterInsert: false,
26
+ positioningStrategy: 'fixed',
27
+ dataAttributes: ['type']
28
+ };
29
+ const THESEAM_QUILL_MODULES_DEFAULT = {
30
+ toolbar: THESEAM_QUILL_TOOLBAR_OPTIONS_DEFAULT
31
+ };
32
+ const THESEAM_QUILL_FORMATS_DEFAULT = [
33
+ 'align',
34
+ 'bold',
35
+ 'header',
36
+ 'indent',
37
+ 'italic',
38
+ 'link',
39
+ 'list',
40
+ 'size',
41
+ 'strike',
42
+ 'underline',
43
+ 'mention'
44
+ ];
45
+ const THESEAM_QUILL_EDITOR_CONFIG_DEFAULT = {
46
+ format: 'html',
47
+ modules: THESEAM_QUILL_MODULES_DEFAULT,
48
+ formats: THESEAM_QUILL_FORMATS_DEFAULT,
49
+ linkPlaceholder: 'https://google.com',
50
+ customToolbarPosition: 'top',
51
+ sanitize: false,
52
+ strict: true,
53
+ customOptions: [],
54
+ customModules: [],
55
+ preserveWhitespace: false,
56
+ trimOnValidation: false,
57
+ compareValues: false,
58
+ filterNull: false
59
+ };
60
+ const THESEAM_QUILL_EDITOR_CONFIG = new InjectionToken('TheSeamQuillEditorConfig');
61
+ const defaultHtmlCharacterCounterFn = (value, format) => {
62
+ if (format === 'html') {
63
+ return value.replace(HTML_ENTITY_REGEX, ' ').replace(/\s\s+/g, ' ').trim().length;
64
+ }
65
+ else if (format === 'text') {
66
+ return value.replace(/\s\s+/g, ' ').trim().length;
67
+ }
68
+ else {
69
+ console.warn(`Format ${format} not supported!`);
70
+ return 0;
71
+ }
72
+ };
73
+ function isMentionMenuOption(value) {
74
+ if (isNullOrUndefined(value) || typeof value !== 'object') {
75
+ return false;
76
+ }
77
+ return Object.prototype.hasOwnProperty.call(value, 'id');
78
+ }
79
+ const defaultMentionSearchFn = (source, textAfter, mentionChar) => {
80
+ return source.filter(u => {
81
+ if (!isMentionMenuOption(u) || u.searchIgnore === true) {
82
+ return true;
83
+ }
84
+ return u.value.toLowerCase().includes(textAfter.toLowerCase());
85
+ });
86
+ };
87
+ const defaultMentionRenderListFn = (source, searchFn, emptyListItem, textAfter, renderList, mentionChar) => {
88
+ let list = searchFn(source, textAfter, mentionChar);
89
+ if (list.length === 0 && notNullOrUndefined(emptyListItem)) {
90
+ list.push(emptyListItem);
91
+ }
92
+ else {
93
+ let reduceIdx = 0;
94
+ list = list.reduce((acc, mention) => {
95
+ const previousMenuItem = acc[reduceIdx - 1];
96
+ const previousMenuItemGroupName = isMentionMenuOption(previousMenuItem) ? previousMenuItem.groupName : undefined;
97
+ if (isMentionMenuOption(mention)
98
+ && notNullOrUndefinedOrEmpty(mention.groupName)
99
+ && mention.groupName !== previousMenuItemGroupName) {
100
+ acc.push({
101
+ value: mention.groupName,
102
+ disabled: true,
103
+ type: 'groupName'
104
+ });
105
+ reduceIdx++;
106
+ }
107
+ if (!isMentionMenuOption(mention)) {
108
+ mention.disabled = true;
109
+ }
110
+ acc.push(mention);
111
+ reduceIdx++;
112
+ return acc;
113
+ }, []);
114
+ }
115
+ renderList(list, textAfter);
116
+ };
117
+ // Keeping this as an example for a custom menu item.
118
+ // There doesn't appear to be a better way of passing in a custom template.
119
+ // export const defaultMentionRenderItem = (item: TheSeamQuillMentionListItem) => {
120
+ // if (item.type === 'groupName') {
121
+ // const text = document.createElement('div')
122
+ // text.setAttribute('class', 'small text-black-50')
123
+ // text.innerText = item.value
124
+ // return text.outerHTML
125
+ // }
126
+ // else if (item.type === 'divider') {
127
+ // const div = document.createElement('hr')
128
+ // div.setAttribute('class', 'my-2')
129
+ // return div.outerHTML
130
+ // }
131
+ // else {
132
+ // return item.value
133
+ // }
134
+ // }
135
+
136
+ const RICH_TEXT_VALUE_ACCESSOR = {
137
+ provide: NG_VALUE_ACCESSOR,
138
+ useExisting: forwardRef(() => RichTextComponent),
139
+ multi: true
140
+ };
141
+ class RichTextComponent {
142
+ get required() {
143
+ return this._required;
144
+ }
145
+ set required(value) {
146
+ if (notNullOrUndefined(value)) {
147
+ this._required = coerceBooleanProperty(value);
148
+ }
149
+ }
150
+ /** @default '' (empty string) */
151
+ get placeholder() {
152
+ return this._placeholder;
153
+ }
154
+ set placeholder(value) {
155
+ if (notNullOrUndefined(value)) {
156
+ this._placeholder = value;
157
+ }
158
+ }
159
+ /**
160
+ * Initial rows visible in text area, set using `height` and `minHeight`.
161
+ *
162
+ * NOTE: Resizable editors will not be able to size below the height calculated from this value.
163
+ *
164
+ * @default 5
165
+ */
166
+ get rows() {
167
+ return this._rows;
168
+ }
169
+ set rows(value) {
170
+ if (notNullOrUndefined(value)) {
171
+ this._rows = value;
172
+ this._pollCalculatedRowHeight.next();
173
+ }
174
+ }
175
+ /**
176
+ * When `true`, text area can be resized vertically.
177
+ *
178
+ * @default true
179
+ */
180
+ get resizable() {
181
+ return this._resizable;
182
+ }
183
+ set resizable(value) {
184
+ if (notNullOrUndefined(value)) {
185
+ this._resizable = coerceBooleanProperty(value);
186
+ }
187
+ }
188
+ /** @default false */
189
+ get readOnly() {
190
+ return this._readOnly;
191
+ }
192
+ set readOnly(value) {
193
+ if (notNullOrUndefined(value)) {
194
+ this._readOnly = coerceBooleanProperty(value);
195
+ }
196
+ }
197
+ // TODO: fix bug where initial html value is rendered in plain text
198
+ /**
199
+ * When `true`, overrides all other provided settings to present the editor
200
+ * as a standard textbox.
201
+ *
202
+ * NOTE: For the moment, `<p></p>` tags are still allowed, triggered by the `Enter` key.
203
+ * https://github.com/slab/quill/issues/1432
204
+ *
205
+ * @default false
206
+ */
207
+ get disableRichText() {
208
+ return this._disableRichText;
209
+ }
210
+ set disableRichText(value) {
211
+ if (notNullOrUndefined(value)) {
212
+ this._disableRichText = coerceBooleanProperty(value);
213
+ this._updateQuillConfig();
214
+ }
215
+ }
216
+ /**
217
+ * When `true`, displays a character counter at the bottom of the editor.
218
+ * Character counter text is determined by values provided in `minLength`
219
+ * and `maxLength`.
220
+ *
221
+ * The default count algorithm strips out html entities and replaces them
222
+ * with spaces to get the string length. To override this behavior, pass
223
+ * a custom function to `characterCounterFn`.
224
+ *
225
+ * To override default character counter display, pass a custom template to `characterCountTpl`.
226
+ *
227
+ * @default false
228
+ */
229
+ get displayCharacterCounter() {
230
+ return this._displayCharacterCounter;
231
+ }
232
+ set displayCharacterCounter(value) {
233
+ if (notNullOrUndefined(value)) {
234
+ this._displayCharacterCounter = coerceBooleanProperty(value);
235
+ }
236
+ }
237
+ get minLength() {
238
+ return this._minLength;
239
+ }
240
+ set minLength(value) {
241
+ if (notNullOrUndefined(value)) {
242
+ this._minLength = value;
243
+ }
244
+ }
245
+ get maxLength() {
246
+ return this._maxLength;
247
+ }
248
+ set maxLength(value) {
249
+ if (notNullOrUndefined(value)) {
250
+ this._maxLength = value;
251
+ }
252
+ }
253
+ /**
254
+ * Set to override default character counter display.
255
+ *
256
+ * Template context includes variables `minLength`, `maxLength`, and `characterCount`.
257
+ */
258
+ get characterCounterTpl() {
259
+ return this._characterCounterTpl;
260
+ }
261
+ set characterCounterTpl(value) {
262
+ if (notNullOrUndefined(value)) {
263
+ this._characterCounterTpl = value;
264
+ }
265
+ }
266
+ /**
267
+ * Set to override default counter function, which strips html entities and
268
+ * replaces them with a space.
269
+ */
270
+ get characterCounterFn() {
271
+ return this._characterCounterFn;
272
+ }
273
+ set characterCounterFn(value) {
274
+ if (notNullOrUndefined(value)) {
275
+ this._characterCounterFn = value;
276
+ }
277
+ }
278
+ /**
279
+ * If `true`, component will configure the Quill editor with the quill-mentions extension
280
+ * and listen for values passed to `mentionItems` to populate the mentions menu.
281
+ *
282
+ * @default false
283
+ */
284
+ get useMentions() {
285
+ return this._useMentions;
286
+ }
287
+ set useMentions(value) {
288
+ if (notNullOrUndefined(value)) {
289
+ this._useMentions = coerceBooleanProperty(value);
290
+ this._updateQuillConfig();
291
+ }
292
+ }
293
+ /**
294
+ * List of users, user groups, or other entities to display in mentions menu.
295
+ * Minimum required properties are `id` (unique) and `value`, which acts as the label.
296
+ *
297
+ * By default, the menu is triggered by typing the `@` symbol into the text area.
298
+ */
299
+ get mentionItems() {
300
+ return this._mentionItems.value;
301
+ }
302
+ set mentionItems(value) {
303
+ if (notNullOrUndefined(value)) {
304
+ this._mentionItems.next(value);
305
+ }
306
+ }
307
+ /**
308
+ * Set to override default search function when user is typing a mention.
309
+ */
310
+ get mentionSearchFn() {
311
+ return this._mentionSearchFn;
312
+ }
313
+ set mentionSearchFn(value) {
314
+ if (notNullOrUndefined(value)) {
315
+ this._mentionSearchFn = value;
316
+ }
317
+ }
318
+ /**
319
+ * Set to override default render function for mentions list.
320
+ *
321
+ * Function should call `renderList`.
322
+ */
323
+ get mentionRenderListFn() {
324
+ return this._mentionRenderListFn;
325
+ }
326
+ set mentionRenderListFn(value) {
327
+ if (notNullOrUndefined(value)) {
328
+ this._mentionRenderListFn = value;
329
+ }
330
+ }
331
+ /**
332
+ * Set to override default text shown while mention items are loading.
333
+ *
334
+ * @default 'Loading...'
335
+ */
336
+ get mentionListLoadingText() {
337
+ return this._mentionListLoadingText;
338
+ }
339
+ set mentionListLoadingText(value) {
340
+ if (notNullOrUndefined(value)) {
341
+ this._mentionListLoadingText = value;
342
+ }
343
+ }
344
+ /**
345
+ * Set to override default text shown when a mention search returns no items.
346
+ *
347
+ * @default 'No matches found.'
348
+ */
349
+ get mentionListEmptyText() {
350
+ return this._mentionListEmptyText;
351
+ }
352
+ set mentionListEmptyText(value) {
353
+ if (notNullOrUndefined(value)) {
354
+ this._mentionListEmptyText = value;
355
+ }
356
+ }
357
+ get mentionListEmptyItem() {
358
+ return {
359
+ id: 'undefined',
360
+ value: this.mentionListEmptyText,
361
+ disabled: true,
362
+ emptyList: true
363
+ };
364
+ }
365
+ get quillEditor() {
366
+ return this._quillEditor;
367
+ }
368
+ set quillEditor(value) {
369
+ this._quillEditor = value;
370
+ // setTimeout because full html isn't available until the next tick
371
+ setTimeout(() => {
372
+ this._pollCalculatedRowHeight.next();
373
+ }, 0);
374
+ }
375
+ _handleKeydown(event) {
376
+ var _a, _b;
377
+ if (event.code === 'Escape') {
378
+ const qlEditor = (_b = (_a = this._quillEditor) === null || _a === void 0 ? void 0 : _a.editorElem) === null || _b === void 0 ? void 0 : _b.querySelector('.ql-editor');
379
+ if (notNullOrUndefined(qlEditor) && qlEditor === document.activeElement && qlEditor instanceof HTMLElement) {
380
+ event.preventDefault();
381
+ event.stopImmediatePropagation();
382
+ qlEditor.blur();
383
+ }
384
+ }
385
+ }
386
+ constructor(_renderer, _customConfig) {
387
+ this._renderer = _renderer;
388
+ this._customConfig = _customConfig;
389
+ this.formControl = new FormControl(null);
390
+ this._required = false;
391
+ this._placeholder = '';
392
+ this._rows = 5;
393
+ this._resizable = true;
394
+ this._readOnly = false;
395
+ this._disableRichText = false;
396
+ this._displayCharacterCounter = false;
397
+ this._characterCounterTpl = null;
398
+ this._characterCounterFn = defaultHtmlCharacterCounterFn;
399
+ this._useMentions = false;
400
+ this._mentionItems = new BehaviorSubject(undefined);
401
+ this.mentionItems$ = this._mentionItems.asObservable().pipe(filter(mentions => notNullOrUndefined(mentions) && mentions.length > 0), shareReplay({ bufferSize: 1, refCount: true }));
402
+ this._mentionSearchFn = defaultMentionSearchFn;
403
+ this._mentionRenderListFn = defaultMentionRenderListFn;
404
+ this._mentionListLoadingText = 'Loading...';
405
+ this._mentionListEmptyText = 'No matches found.';
406
+ this.quillEditorCreated = new EventEmitter();
407
+ this.quillEditorChanged = new EventEmitter();
408
+ this.quillContentChanged = new EventEmitter();
409
+ this.quillSelectionChanged = new EventEmitter();
410
+ this.quillFocus = new EventEmitter();
411
+ this.quillBlur = new EventEmitter();
412
+ this.mentionsUpdated = new EventEmitter();
413
+ this._isWritingValue = false;
414
+ this._pollCalculatedRowHeight = new Subject();
415
+ this._configSet = new BehaviorSubject(false);
416
+ this.configSet$ = this._configSet.asObservable();
417
+ this._stylesSet = new BehaviorSubject(false);
418
+ this._templateSet = new BehaviorSubject(false);
419
+ this._config = new BehaviorSubject(undefined);
420
+ this.config$ = this._config.asObservable();
421
+ this._selectedMentions = new BehaviorSubject([]);
422
+ this.selectedMentions$ = this._selectedMentions.asObservable();
423
+ this.initialized$ = combineLatest([
424
+ this._configSet.asObservable(),
425
+ this._stylesSet.asObservable(),
426
+ this._templateSet.asObservable(),
427
+ ]).pipe(map(sets => sets.findIndex(s => !s) === -1));
428
+ this.characterCount$ = this.initialized$.pipe(filter(i => i), switchMap(() => {
429
+ if (notNullOrUndefined(this.formControl)) {
430
+ return this.formControl.valueChanges.pipe(startWith(this.formControl.value), map(v => { var _a; return this.characterCounterFn(v || '', (_a = this._config.value) === null || _a === void 0 ? void 0 : _a.format); }));
431
+ }
432
+ return of(0);
433
+ }));
434
+ this.selectedMentions$.pipe(tap(mentions => this.mentionsUpdated.emit(mentions))).subscribe();
435
+ }
436
+ ngOnInit() {
437
+ // TODO: test this more
438
+ // ignore quill initial valueChange event, to keep functionality in line with other inputs
439
+ let initialEmitComplete = false;
440
+ this._configSet.pipe(filter(s => s), switchMap(() => this.formControl.valueChanges.pipe(
441
+ // skip(1),
442
+ take(1), tap(() => initialEmitComplete = true)))).subscribe();
443
+ this.formControl.valueChanges.pipe(filter(() => !this._isWritingValue && initialEmitComplete), tap(value => this.value = value)).subscribe();
444
+ this._pollCalculatedRowHeight.asObservable().pipe(tap(() => {
445
+ this._stylesSet.next(false);
446
+ const calculatedRowsHeight = `${this.rows * 1.5}rem`;
447
+ if (notNullOrUndefined(this.rows) && notNullOrUndefined(this._quillEditor)) {
448
+ const editorEl = this._quillEditor.elementRef.nativeElement.querySelector('.ql-editor');
449
+ if (notNullOrUndefined(editorEl)) {
450
+ this._renderer.setStyle(editorEl, 'height', calculatedRowsHeight);
451
+ this._renderer.setStyle(editorEl, 'min-height', calculatedRowsHeight);
452
+ }
453
+ }
454
+ this._stylesSet.next(true);
455
+ })).subscribe();
456
+ this._buildQuillConfig();
457
+ }
458
+ ngAfterViewInit() {
459
+ if (isNullOrUndefined(this.characterCounterTpl)) {
460
+ this.characterCounterTpl = this.defaultCharacterCounterTpl || null;
461
+ }
462
+ this._templateSet.next(true);
463
+ }
464
+ ngOnDestroy() {
465
+ var _a;
466
+ // hacky way to ensure mentions menu gets destroyed when component is destroyed
467
+ const mentionModule = (_a = this._quillEditor) === null || _a === void 0 ? void 0 : _a.quillEditor.getModule('mention');
468
+ const hideMentionList = mentionModule === null || mentionModule === void 0 ? void 0 : mentionModule.hideMentionList;
469
+ if (hideMentionList && typeof hideMentionList === 'function') {
470
+ hideMentionList.call(mentionModule);
471
+ }
472
+ }
473
+ _buildQuillConfig() {
474
+ var _a;
475
+ this._configSet.next(false);
476
+ const config = Object.assign({}, THESEAM_QUILL_EDITOR_CONFIG_DEFAULT);
477
+ if (this.disableRichText) {
478
+ config.format = 'text';
479
+ config.formats = [];
480
+ config.modules = {
481
+ toolbar: false
482
+ };
483
+ }
484
+ else {
485
+ config.format = this._getConfigOrDefault('format');
486
+ config.formats = this._getConfigOrDefault('formats');
487
+ config.modules = Object.assign({}, this._getConfigOrDefault('modules'));
488
+ }
489
+ if (this.useMentions) {
490
+ const mentionModules = Object.assign(Object.assign({}, config.modules), { mention: Object.assign(Object.assign(Object.assign({}, THESEAM_QUILL_MENTION_OPTIONS_DEFAULT), { renderLoading: () => this.mentionListLoadingText, source: (searchTerm, renderList, mentionChar) => __awaiter(this, void 0, void 0, function* () {
491
+ // this function is called every time the menu is triggered,
492
+ // so it will always have the latest value from mentionItems$
493
+ const mentionsAsync = yield lastValueFrom(this.mentionItems$.pipe(take(1)));
494
+ if (notNullOrUndefined(mentionsAsync)) {
495
+ this.mentionRenderListFn(mentionsAsync, this.mentionSearchFn, this.mentionListEmptyItem, searchTerm, renderList, mentionChar);
496
+ }
497
+ }) }), (_a = config.modules) === null || _a === void 0 ? void 0 : _a.mention) });
498
+ config.modules = mentionModules;
499
+ }
500
+ config.theme = this._getConfigOrDefault('theme');
501
+ config.debug = this._getConfigOrDefault('debug');
502
+ config.customToolbarPosition = this._getConfigOrDefault('customToolbarPosition');
503
+ config.sanitize = this._getConfigOrDefault('sanitize');
504
+ config.styles = this._getConfigOrDefault('styles');
505
+ config.strict = this._getConfigOrDefault('strict');
506
+ config.scrollingContainer = this._getConfigOrDefault('scrollingContainer');
507
+ config.bounds = this._getConfigOrDefault('bounds');
508
+ config.customOptions = this._getConfigOrDefault('customOptions');
509
+ config.customModules = this._getConfigOrDefault('customModules');
510
+ config.trackChanges = this._getConfigOrDefault('trackChanges');
511
+ config.preserveWhitespace = this._getConfigOrDefault('preserveWhitespace');
512
+ config.classes = this._getConfigOrDefault('classes');
513
+ config.trimOnValidation = this._getConfigOrDefault('trimOnValidation');
514
+ config.linkPlaceholder = this._getConfigOrDefault('linkPlaceholder');
515
+ config.compareValues = this._getConfigOrDefault('compareValues');
516
+ config.filterNull = this._getConfigOrDefault('filterNull');
517
+ config.debounceTime = this._getConfigOrDefault('debounceTime');
518
+ this._config.next(config);
519
+ // setTimeout bc ngx-quill library doesn't listen for input changes,
520
+ // so we must destroy and create the component each time config is updated
521
+ setTimeout(() => {
522
+ this._configSet.next(true);
523
+ }, 0);
524
+ }
525
+ _getConfigOrDefault(prop) {
526
+ if (this._customConfig && Object.prototype.hasOwnProperty.call(this._customConfig, prop)) {
527
+ return this._customConfig[prop];
528
+ }
529
+ return THESEAM_QUILL_EDITOR_CONFIG_DEFAULT[prop];
530
+ }
531
+ _updateQuillConfig() {
532
+ if (this._configSet.value) {
533
+ this._buildQuillConfig();
534
+ }
535
+ }
536
+ // Not usable, bc config has to be set immediately, potentially before mentions populate.
537
+ // To set customDataAttributes, provide a custom config.
538
+ // private _getCustomDataAttributes(mentions: TheSeamQuillMentionMenuOption[]): string[] {
539
+ // return mentions.reduce((acc, mention) => {
540
+ // const keys = Object.keys(mention)
541
+ // keys.forEach(key => {
542
+ // if (acc.findIndex(a => a === key) === -1) {
543
+ // acc.push(key)
544
+ // }
545
+ // })
546
+ // return acc
547
+ // }, <string[]>[] satisfies string[])
548
+ // }
549
+ get value() {
550
+ return this._value;
551
+ }
552
+ set value(value) {
553
+ this._value = value;
554
+ if (this.onChange) {
555
+ this.onChange(value);
556
+ }
557
+ if (this.onTouched) {
558
+ this.onTouched();
559
+ }
560
+ }
561
+ writeValue(value) {
562
+ this._isWritingValue = true;
563
+ this.formControl.setValue(value);
564
+ this.value = value;
565
+ this._isWritingValue = false;
566
+ }
567
+ registerOnChange(fn) {
568
+ this.onChange = fn;
569
+ }
570
+ registerOnTouched(fn) {
571
+ this.onTouched = fn;
572
+ }
573
+ setDisabledState(isDisabled) {
574
+ this.readOnly = isDisabled;
575
+ }
576
+ _onEditorCreated(event) {
577
+ this.quillEditorCreated.emit(event);
578
+ }
579
+ _onEditorChanged(event) {
580
+ this.quillEditorChanged.emit(event);
581
+ }
582
+ _onContentChanged(event) {
583
+ this.quillContentChanged.emit(event);
584
+ this._updateMentionsFromDelta(event.content);
585
+ }
586
+ _onSelectionChanged(event) {
587
+ this.quillSelectionChanged.emit(event);
588
+ }
589
+ _onFocus(event) {
590
+ this.quillFocus.emit(event);
591
+ }
592
+ _onBlur(event) {
593
+ this.quillBlur.emit(event);
594
+ if (this.onTouched) {
595
+ this.onTouched();
596
+ }
597
+ }
598
+ /**
599
+ * Hacky way to track mention inserts/deletes
600
+ */
601
+ _updateMentionsFromDelta(content) {
602
+ if (notNullOrUndefined(content.ops)) {
603
+ const contentMentionIds = content.ops.map(o => { var _a, _b; return (_b = (_a = o.insert) === null || _a === void 0 ? void 0 : _a.mention) === null || _b === void 0 ? void 0 : _b.id; }).filter(notNullOrUndefined);
604
+ const selectedMentions = [...this._selectedMentions.value];
605
+ const mentionOptions = [...this._mentionItems.value || []];
606
+ const newMentions = contentMentionIds.reduce((acc, mentionId) => {
607
+ const insertMention = mentionOptions.find(m => isMentionMenuOption(m) && m.id === mentionId);
608
+ if (notNullOrUndefined(insertMention)) {
609
+ acc.push(insertMention);
610
+ }
611
+ else {
612
+ console.warn('Mention addition failed! Selected mention option not found:', mentionId);
613
+ }
614
+ return acc;
615
+ }, []);
616
+ let emitUpdate = false;
617
+ if (selectedMentions.length !== newMentions.length) {
618
+ // if the length has changed, we know an update occurred
619
+ emitUpdate = true;
620
+ }
621
+ else {
622
+ // otherwise, test ids for old and new items to see if we need to emit a change
623
+ const selectedMentionIds = this._selectedMentions.value.map(m => m.id);
624
+ const newMentionIds = newMentions.map(m => m.id);
625
+ if (selectedMentionIds.findIndex(m => !newMentionIds.includes(m)) !== -1 ||
626
+ newMentionIds.findIndex(m => !selectedMentionIds.includes(m)) !== -1) {
627
+ emitUpdate = true;
628
+ }
629
+ }
630
+ if (emitUpdate) {
631
+ this._selectedMentions.next(newMentions);
632
+ }
633
+ }
634
+ }
635
+ }
636
+ RichTextComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: RichTextComponent, deps: [{ token: i0.Renderer2 }, { token: THESEAM_QUILL_EDITOR_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Component });
637
+ RichTextComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.7", type: RichTextComponent, selector: "seam-rich-text", inputs: { val: ["value", "val"], required: "required", placeholder: "placeholder", rows: "rows", resizable: "resizable", disableRichText: "disableRichText", displayCharacterCounter: "displayCharacterCounter", minLength: "minLength", maxLength: "maxLength", characterCounterTpl: "characterCounterTpl", characterCounterFn: "characterCounterFn", useMentions: "useMentions", mentionItems: "mentionItems", mentionSearchFn: "mentionSearchFn", mentionRenderListFn: "mentionRenderListFn", mentionListLoadingText: "mentionListLoadingText", mentionListEmptyText: "mentionListEmptyText" }, outputs: { quillEditorCreated: "quillEditorCreated", quillEditorChanged: "quillEditorChanged", quillContentChanged: "quillContentChanged", quillSelectionChanged: "quillSelectionChanged", quillFocus: "quillFocus", quillBlur: "quillBlur", mentionsUpdated: "mentionsUpdated" }, host: { listeners: { "keydown": "_handleKeydown($event)" } }, providers: [
638
+ RICH_TEXT_VALUE_ACCESSOR
639
+ ], viewQueries: [{ propertyName: "quillEditor", first: true, predicate: ["quillEditor"], descendants: true }, { propertyName: "defaultCharacterCounterTpl", first: true, predicate: ["characterCounter"], descendants: true }], ngImport: i0, template: "<div class=\"editor\" *ngIf=\"configSet$ | async\" [class.initializing]=\"!(initialized$ | async)\">\n <ng-container *ngIf=\"config$ | async as config\">\n <quill-editor\n #quillEditor\n seamInput\n [class.disabled]=\"readOnly\"\n [attr.disabled]=\"readOnly\"\n [formControl]=\"formControl\"\n [placeholder]=\"placeholder\"\n [readOnly]=\"readOnly\"\n [required]=\"required\"\n [minLength]=\"minLength\"\n [maxLength]=\"maxLength\"\n [format]=\"config.format\"\n [theme]=\"config.theme\"\n [modules]=\"config.modules\"\n [debug]=\"config.debug\"\n [formats]=\"config.formats\"\n [customToolbarPosition]=\"config.customToolbarPosition\"\n [sanitize]=\"config.sanitize\"\n [styles]=\"config.styles\"\n [strict]=\"config.strict\"\n [scrollingContainer]=\"config.scrollingContainer\"\n [bounds]=\"config.bounds\"\n [customOptions]=\"config.customOptions\"\n [customModules]=\"config.customModules\"\n [trackChanges]=\"config.trackChanges\"\n [preserveWhitespace]=\"config.preserveWhitespace\"\n [classes]=\"config.classes\"\n [trimOnValidation]=\"config.trimOnValidation\"\n [linkPlaceholder]=\"config.linkPlaceholder\"\n [compareValues]=\"config.compareValues\"\n [filterNull]=\"config.filterNull\"\n [debounceTime]=\"config.debounceTime\"\n [class.can-resize]=\"resizable\"\n (onEditorCreated)=\"_onEditorCreated($event)\"\n (onEditorChanged)=\"_onEditorChanged($event)\"\n (onContentChanged)=\"_onContentChanged($event)\"\n (onSelectionChanged)=\"_onSelectionChanged($event)\"\n (onFocus)=\"_onFocus($event)\"\n (onBlur)=\"_onBlur($event)\"></quill-editor>\n <ng-container *ngIf=\"displayCharacterCounter\">\n <ng-container\n [ngTemplateOutlet]=\"characterCounterTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: characterCount$ | async, minLength: minLength, maxLength: maxLength, characterCount: characterCount$ | async }\"></ng-container>\n </ng-container>\n </ng-container>\n</div>\n\n<ng-template #characterCounter let-implicit let-minLength=\"minLength\" let-maxLength=\"maxLength\" let-characterCount=\"characterCount\">\n <div class=\"small text-black-50 text-right\">\n <ng-container *ngIf=\"characterCount || characterCount === 0\">\n Character Count:\n <span [class.text-danger]=\"characterCount && ((maxLength && characterCount > maxLength) || (minLength && characterCount < minLength))\">\n {{ characterCount | number }}\n </span>\n <ng-container *ngIf=\"maxLength\">\n / {{ maxLength }}\n </ng-container>\n <span *ngIf=\"minLength\" class=\"font-italic\">\n (minimum {{ minLength }} expected)\n </span>\n </ng-container>\n </div>\n</ng-template>\n", styles: [":host .editor{position:relative}:host .editor.initializing:before{content:\"\";position:absolute;top:0;left:0;width:100%;height:100%;background:#f8f9fa;z-index:1}:host quill-editor.can-resize ::ng-deep .ql-editor{overflow:auto;resize:vertical}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: i3.QuillEditorComponent, selector: "quill-editor" }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i1.DecimalPipe, name: "number" }] });
640
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: RichTextComponent, decorators: [{
641
+ type: Component,
642
+ args: [{ selector: 'seam-rich-text', providers: [
643
+ RICH_TEXT_VALUE_ACCESSOR
644
+ ], template: "<div class=\"editor\" *ngIf=\"configSet$ | async\" [class.initializing]=\"!(initialized$ | async)\">\n <ng-container *ngIf=\"config$ | async as config\">\n <quill-editor\n #quillEditor\n seamInput\n [class.disabled]=\"readOnly\"\n [attr.disabled]=\"readOnly\"\n [formControl]=\"formControl\"\n [placeholder]=\"placeholder\"\n [readOnly]=\"readOnly\"\n [required]=\"required\"\n [minLength]=\"minLength\"\n [maxLength]=\"maxLength\"\n [format]=\"config.format\"\n [theme]=\"config.theme\"\n [modules]=\"config.modules\"\n [debug]=\"config.debug\"\n [formats]=\"config.formats\"\n [customToolbarPosition]=\"config.customToolbarPosition\"\n [sanitize]=\"config.sanitize\"\n [styles]=\"config.styles\"\n [strict]=\"config.strict\"\n [scrollingContainer]=\"config.scrollingContainer\"\n [bounds]=\"config.bounds\"\n [customOptions]=\"config.customOptions\"\n [customModules]=\"config.customModules\"\n [trackChanges]=\"config.trackChanges\"\n [preserveWhitespace]=\"config.preserveWhitespace\"\n [classes]=\"config.classes\"\n [trimOnValidation]=\"config.trimOnValidation\"\n [linkPlaceholder]=\"config.linkPlaceholder\"\n [compareValues]=\"config.compareValues\"\n [filterNull]=\"config.filterNull\"\n [debounceTime]=\"config.debounceTime\"\n [class.can-resize]=\"resizable\"\n (onEditorCreated)=\"_onEditorCreated($event)\"\n (onEditorChanged)=\"_onEditorChanged($event)\"\n (onContentChanged)=\"_onContentChanged($event)\"\n (onSelectionChanged)=\"_onSelectionChanged($event)\"\n (onFocus)=\"_onFocus($event)\"\n (onBlur)=\"_onBlur($event)\"></quill-editor>\n <ng-container *ngIf=\"displayCharacterCounter\">\n <ng-container\n [ngTemplateOutlet]=\"characterCounterTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: characterCount$ | async, minLength: minLength, maxLength: maxLength, characterCount: characterCount$ | async }\"></ng-container>\n </ng-container>\n </ng-container>\n</div>\n\n<ng-template #characterCounter let-implicit let-minLength=\"minLength\" let-maxLength=\"maxLength\" let-characterCount=\"characterCount\">\n <div class=\"small text-black-50 text-right\">\n <ng-container *ngIf=\"characterCount || characterCount === 0\">\n Character Count:\n <span [class.text-danger]=\"characterCount && ((maxLength && characterCount > maxLength) || (minLength && characterCount < minLength))\">\n {{ characterCount | number }}\n </span>\n <ng-container *ngIf=\"maxLength\">\n / {{ maxLength }}\n </ng-container>\n <span *ngIf=\"minLength\" class=\"font-italic\">\n (minimum {{ minLength }} expected)\n </span>\n </ng-container>\n </div>\n</ng-template>\n", styles: [":host .editor{position:relative}:host .editor.initializing:before{content:\"\";position:absolute;top:0;left:0;width:100%;height:100%;background:#f8f9fa;z-index:1}:host quill-editor.can-resize ::ng-deep .ql-editor{overflow:auto;resize:vertical}\n"] }]
645
+ }], ctorParameters: function () {
646
+ return [{ type: i0.Renderer2 }, { type: undefined, decorators: [{
647
+ type: Optional
648
+ }, {
649
+ type: Inject,
650
+ args: [THESEAM_QUILL_EDITOR_CONFIG]
651
+ }] }];
652
+ }, propDecorators: { val: [{
653
+ type: Input,
654
+ args: ['value']
655
+ }], required: [{
656
+ type: Input
657
+ }], placeholder: [{
658
+ type: Input
659
+ }], rows: [{
660
+ type: Input
661
+ }], resizable: [{
662
+ type: Input
663
+ }], disableRichText: [{
664
+ type: Input
665
+ }], displayCharacterCounter: [{
666
+ type: Input
667
+ }], minLength: [{
668
+ type: Input
669
+ }], maxLength: [{
670
+ type: Input
671
+ }], characterCounterTpl: [{
672
+ type: Input
673
+ }], characterCounterFn: [{
674
+ type: Input
675
+ }], useMentions: [{
676
+ type: Input
677
+ }], mentionItems: [{
678
+ type: Input
679
+ }], mentionSearchFn: [{
680
+ type: Input
681
+ }], mentionRenderListFn: [{
682
+ type: Input
683
+ }], mentionListLoadingText: [{
684
+ type: Input
685
+ }], mentionListEmptyText: [{
686
+ type: Input
687
+ }], quillEditorCreated: [{
688
+ type: Output
689
+ }], quillEditorChanged: [{
690
+ type: Output
691
+ }], quillContentChanged: [{
692
+ type: Output
693
+ }], quillSelectionChanged: [{
694
+ type: Output
695
+ }], quillFocus: [{
696
+ type: Output
697
+ }], quillBlur: [{
698
+ type: Output
699
+ }], mentionsUpdated: [{
700
+ type: Output
701
+ }], quillEditor: [{
702
+ type: ViewChild,
703
+ args: ['quillEditor']
704
+ }], defaultCharacterCounterTpl: [{
705
+ type: ViewChild,
706
+ args: ['characterCounter']
707
+ }], _handleKeydown: [{
708
+ type: HostListener,
709
+ args: ['keydown', ['$event']]
710
+ }] } });
711
+
712
+ const THESEAM_QUILL_FORMATS = [
713
+ 'align',
714
+ 'background',
715
+ 'blockquote',
716
+ 'bold',
717
+ 'code-block',
718
+ 'code',
719
+ 'color',
720
+ 'direction',
721
+ 'font',
722
+ 'header',
723
+ 'image',
724
+ 'indent',
725
+ 'italic',
726
+ 'link',
727
+ 'list',
728
+ 'script',
729
+ 'size',
730
+ 'strike',
731
+ 'underline',
732
+ 'video',
733
+ 'mention'
734
+ ];
735
+
736
+ class TheSeamRichTextModule {
737
+ }
738
+ TheSeamRichTextModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: TheSeamRichTextModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
739
+ TheSeamRichTextModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.7", ngImport: i0, type: TheSeamRichTextModule, declarations: [RichTextComponent], imports: [CommonModule,
740
+ ReactiveFormsModule,
741
+ QuillModule], exports: [RichTextComponent] });
742
+ TheSeamRichTextModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: TheSeamRichTextModule, imports: [CommonModule,
743
+ ReactiveFormsModule,
744
+ QuillModule] });
745
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: TheSeamRichTextModule, decorators: [{
746
+ type: NgModule,
747
+ args: [{
748
+ declarations: [
749
+ RichTextComponent,
750
+ ],
751
+ imports: [
752
+ CommonModule,
753
+ ReactiveFormsModule,
754
+ QuillModule
755
+ ],
756
+ exports: [
757
+ RichTextComponent,
758
+ ]
759
+ }]
760
+ }] });
761
+
762
+ /**
763
+ * Generated bundle index. Do not edit.
764
+ */
765
+
766
+ export { HTML_ENTITY_REGEX, RICH_TEXT_VALUE_ACCESSOR, RichTextComponent, THESEAM_QUILL_EDITOR_CONFIG, THESEAM_QUILL_EDITOR_CONFIG_DEFAULT, THESEAM_QUILL_FORMATS, THESEAM_QUILL_FORMATS_DEFAULT, THESEAM_QUILL_MENTION_OPTIONS_DEFAULT, THESEAM_QUILL_MODULES_DEFAULT, THESEAM_QUILL_TOOLBAR_OPTIONS_DEFAULT, TheSeamRichTextModule, defaultHtmlCharacterCounterFn, defaultMentionRenderListFn, defaultMentionSearchFn, isMentionMenuOption };
767
+ //# sourceMappingURL=theseam-ui-common-rich-text.mjs.map