@api-client/ui 0.5.6 → 0.5.8

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 (82) hide show
  1. package/.cursor/rules/html-and-css-best-practices.mdc +63 -0
  2. package/.cursor/rules/lit-best-practices.mdc +78 -0
  3. package/.github/instructions/html-and-css-best-practices.instructions.md +70 -0
  4. package/.github/instructions/lit-best-practices.instructions.md +86 -0
  5. package/build/src/elements/currency/currency-picker.d.ts +10 -0
  6. package/build/src/elements/currency/currency-picker.d.ts.map +1 -0
  7. package/build/src/elements/currency/currency-picker.js +27 -0
  8. package/build/src/elements/currency/currency-picker.js.map +1 -0
  9. package/build/src/elements/currency/internals/Picker.d.ts +311 -0
  10. package/build/src/elements/currency/internals/Picker.d.ts.map +1 -0
  11. package/build/src/elements/currency/internals/Picker.js +857 -0
  12. package/build/src/elements/currency/internals/Picker.js.map +1 -0
  13. package/build/src/elements/currency/internals/Picker.styles.d.ts +3 -0
  14. package/build/src/elements/currency/internals/Picker.styles.d.ts.map +1 -0
  15. package/build/src/elements/currency/internals/Picker.styles.js +58 -0
  16. package/build/src/elements/currency/internals/Picker.styles.js.map +1 -0
  17. package/build/src/elements/mention-textarea/internals/MentionTextArea.d.ts +216 -0
  18. package/build/src/elements/mention-textarea/internals/MentionTextArea.d.ts.map +1 -0
  19. package/build/src/elements/mention-textarea/internals/MentionTextArea.js +1037 -0
  20. package/build/src/elements/mention-textarea/internals/MentionTextArea.js.map +1 -0
  21. package/build/src/elements/mention-textarea/internals/MentionTextArea.styles.d.ts +3 -0
  22. package/build/src/elements/mention-textarea/internals/MentionTextArea.styles.d.ts.map +1 -0
  23. package/build/src/elements/mention-textarea/internals/MentionTextArea.styles.js +274 -0
  24. package/build/src/elements/mention-textarea/internals/MentionTextArea.styles.js.map +1 -0
  25. package/build/src/elements/mention-textarea/ui-mention-textarea.d.ts +13 -0
  26. package/build/src/elements/mention-textarea/ui-mention-textarea.d.ts.map +1 -0
  27. package/build/src/elements/mention-textarea/ui-mention-textarea.js +28 -0
  28. package/build/src/elements/mention-textarea/ui-mention-textarea.js.map +1 -0
  29. package/build/src/md/button/internals/base.d.ts +1 -0
  30. package/build/src/md/button/internals/base.d.ts.map +1 -1
  31. package/build/src/md/button/internals/base.js +7 -0
  32. package/build/src/md/button/internals/base.js.map +1 -1
  33. package/build/src/md/chip/internals/Chip.styles.d.ts.map +1 -1
  34. package/build/src/md/chip/internals/Chip.styles.js +2 -0
  35. package/build/src/md/chip/internals/Chip.styles.js.map +1 -1
  36. package/build/src/md/date-picker/internals/DatePicker.styles.d.ts.map +1 -1
  37. package/build/src/md/date-picker/internals/DatePicker.styles.js +73 -0
  38. package/build/src/md/date-picker/internals/DatePicker.styles.js.map +1 -1
  39. package/build/src/md/date-picker/internals/DatePickerCalendar.d.ts +164 -51
  40. package/build/src/md/date-picker/internals/DatePickerCalendar.d.ts.map +1 -1
  41. package/build/src/md/date-picker/internals/DatePickerCalendar.js +660 -368
  42. package/build/src/md/date-picker/internals/DatePickerCalendar.js.map +1 -1
  43. package/build/src/md/date-picker/ui-date-picker-input.d.ts +65 -13
  44. package/build/src/md/date-picker/ui-date-picker-input.d.ts.map +1 -1
  45. package/build/src/md/date-picker/ui-date-picker-input.js +143 -76
  46. package/build/src/md/date-picker/ui-date-picker-input.js.map +1 -1
  47. package/build/src/md/date-picker/ui-date-picker-modal-input.d.ts +76 -17
  48. package/build/src/md/date-picker/ui-date-picker-modal-input.d.ts.map +1 -1
  49. package/build/src/md/date-picker/ui-date-picker-modal-input.js +192 -127
  50. package/build/src/md/date-picker/ui-date-picker-modal-input.js.map +1 -1
  51. package/build/src/md/date-picker/ui-date-picker-modal.d.ts +63 -15
  52. package/build/src/md/date-picker/ui-date-picker-modal.d.ts.map +1 -1
  53. package/build/src/md/date-picker/ui-date-picker-modal.js +143 -64
  54. package/build/src/md/date-picker/ui-date-picker-modal.js.map +1 -1
  55. package/demo/elements/currency/index.html +91 -0
  56. package/demo/elements/currency/index.ts +272 -0
  57. package/demo/elements/index.html +6 -0
  58. package/demo/elements/mention-textarea/index.html +19 -0
  59. package/demo/elements/mention-textarea/index.ts +205 -0
  60. package/demo/md/date-picker/date-picker.ts +138 -103
  61. package/package.json +2 -2
  62. package/src/elements/currency/currency-picker.ts +14 -0
  63. package/src/elements/currency/internals/Picker.styles.ts +58 -0
  64. package/src/elements/currency/internals/Picker.ts +846 -0
  65. package/src/elements/mention-textarea/internals/MentionTextArea.styles.ts +274 -0
  66. package/src/elements/mention-textarea/internals/MentionTextArea.ts +1036 -0
  67. package/src/elements/mention-textarea/ui-mention-textarea.ts +18 -0
  68. package/src/md/button/internals/base.ts +7 -0
  69. package/src/md/chip/internals/Chip.styles.ts +2 -0
  70. package/src/md/date-picker/internals/DatePicker.styles.ts +73 -0
  71. package/src/md/date-picker/internals/DatePickerCalendar.ts +643 -309
  72. package/src/md/date-picker/ui-date-picker-input.ts +110 -49
  73. package/src/md/date-picker/ui-date-picker-modal-input.ts +168 -99
  74. package/src/md/date-picker/ui-date-picker-modal.ts +136 -53
  75. package/test/README.md +3 -2
  76. package/test/elements/currency/CurrencyPicker.accessibility.test.ts +328 -0
  77. package/test/elements/currency/CurrencyPicker.core.test.ts +318 -0
  78. package/test/elements/currency/CurrencyPicker.integration.test.ts +482 -0
  79. package/test/elements/currency/CurrencyPicker.test.ts +486 -0
  80. package/test/elements/mention-textarea/MentionTextArea.basic.test.ts +63 -0
  81. package/test/elements/mention-textarea/MentionTextArea.test.ts +321 -0
  82. package/tsconfig.json +1 -1
@@ -0,0 +1,1037 @@
1
+ import { __esDecorate, __runInitializers } from "tslib";
2
+ import { html, LitElement, nothing } from 'lit';
3
+ import { property, query, state } from 'lit/decorators.js';
4
+ import { classMap } from 'lit/directives/class-map.js';
5
+ import { ifDefined } from 'lit/directives/if-defined.js';
6
+ import reactive from '../../../decorators/reactive.js';
7
+ import '../../../md/chip/ui-chip.js';
8
+ /**
9
+ * A NodeFilter mask that includes text nodes and elements.
10
+ * It is used with the NodeWalker
11
+ */
12
+ const ShowMask = NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT;
13
+ let MentionTextArea = (() => {
14
+ let _classSuper = LitElement;
15
+ let _instanceExtraInitializers = [];
16
+ let _label_decorators;
17
+ let _label_initializers = [];
18
+ let _label_extraInitializers = [];
19
+ let _supportingText_decorators;
20
+ let _supportingText_initializers = [];
21
+ let _supportingText_extraInitializers = [];
22
+ let _disabled_decorators;
23
+ let _disabled_initializers = [];
24
+ let _disabled_extraInitializers = [];
25
+ let _invalid_decorators;
26
+ let _invalid_initializers = [];
27
+ let _invalid_extraInitializers = [];
28
+ let _name_decorators;
29
+ let _name_initializers = [];
30
+ let _name_extraInitializers = [];
31
+ let _required_decorators;
32
+ let _required_initializers = [];
33
+ let _required_extraInitializers = [];
34
+ let _placeholder_decorators;
35
+ let _placeholder_initializers = [];
36
+ let _placeholder_extraInitializers = [];
37
+ let _set_value_decorators;
38
+ let _suggestions_decorators;
39
+ let _suggestions_initializers = [];
40
+ let _suggestions_extraInitializers = [];
41
+ let _mentionTrigger_decorators;
42
+ let _mentionTrigger_initializers = [];
43
+ let _mentionTrigger_extraInitializers = [];
44
+ let _minQueryLength_decorators;
45
+ let _minQueryLength_initializers = [];
46
+ let _minQueryLength_extraInitializers = [];
47
+ let _editorElement_decorators;
48
+ let _editorElement_initializers = [];
49
+ let _editorElement_extraInitializers = [];
50
+ let _suggestionsPopover_decorators;
51
+ let _suggestionsPopover_initializers = [];
52
+ let _suggestionsPopover_extraInitializers = [];
53
+ let _isShowingSuggestions_decorators;
54
+ let _isShowingSuggestions_initializers = [];
55
+ let _isShowingSuggestions_extraInitializers = [];
56
+ let _filteredSuggestions_decorators;
57
+ let _filteredSuggestions_initializers = [];
58
+ let _filteredSuggestions_extraInitializers = [];
59
+ let _selectedSuggestionIndex_decorators;
60
+ let _selectedSuggestionIndex_initializers = [];
61
+ let _selectedSuggestionIndex_extraInitializers = [];
62
+ let _hasContent_decorators;
63
+ let _hasContent_initializers = [];
64
+ let _hasContent_extraInitializers = [];
65
+ let _isLabelFloating_decorators;
66
+ let _isLabelFloating_initializers = [];
67
+ let _isLabelFloating_extraInitializers = [];
68
+ let _isEditorFocus_decorators;
69
+ let _isEditorFocus_initializers = [];
70
+ let _isEditorFocus_extraInitializers = [];
71
+ return class MentionTextArea extends _classSuper {
72
+ static {
73
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
74
+ _label_decorators = [property({ type: String })];
75
+ _supportingText_decorators = [property({ type: String, attribute: 'supporting-text' })];
76
+ _disabled_decorators = [property({ type: Boolean, reflect: true })];
77
+ _invalid_decorators = [property({ type: Boolean, reflect: true })];
78
+ _name_decorators = [property({ type: String })];
79
+ _required_decorators = [property({ type: Boolean })];
80
+ _placeholder_decorators = [property({ type: String })];
81
+ _set_value_decorators = [property({ type: String })];
82
+ _suggestions_decorators = [property({ type: Array, attribute: false })];
83
+ _mentionTrigger_decorators = [property({ type: String, attribute: 'mention-trigger' })];
84
+ _minQueryLength_decorators = [property({ type: Number, attribute: 'min-query-length' })];
85
+ _editorElement_decorators = [query('.editor')];
86
+ _suggestionsPopover_decorators = [query('.suggestions-popover')];
87
+ _isShowingSuggestions_decorators = [state(), reactive()];
88
+ _filteredSuggestions_decorators = [reactive()];
89
+ _selectedSuggestionIndex_decorators = [state()];
90
+ _hasContent_decorators = [state()];
91
+ _isLabelFloating_decorators = [state()];
92
+ _isEditorFocus_decorators = [state()];
93
+ __esDecorate(this, null, _label_decorators, { kind: "accessor", name: "label", static: false, private: false, access: { has: obj => "label" in obj, get: obj => obj.label, set: (obj, value) => { obj.label = value; } }, metadata: _metadata }, _label_initializers, _label_extraInitializers);
94
+ __esDecorate(this, null, _supportingText_decorators, { kind: "accessor", name: "supportingText", static: false, private: false, access: { has: obj => "supportingText" in obj, get: obj => obj.supportingText, set: (obj, value) => { obj.supportingText = value; } }, metadata: _metadata }, _supportingText_initializers, _supportingText_extraInitializers);
95
+ __esDecorate(this, null, _disabled_decorators, { kind: "accessor", name: "disabled", static: false, private: false, access: { has: obj => "disabled" in obj, get: obj => obj.disabled, set: (obj, value) => { obj.disabled = value; } }, metadata: _metadata }, _disabled_initializers, _disabled_extraInitializers);
96
+ __esDecorate(this, null, _invalid_decorators, { kind: "accessor", name: "invalid", static: false, private: false, access: { has: obj => "invalid" in obj, get: obj => obj.invalid, set: (obj, value) => { obj.invalid = value; } }, metadata: _metadata }, _invalid_initializers, _invalid_extraInitializers);
97
+ __esDecorate(this, null, _name_decorators, { kind: "accessor", name: "name", static: false, private: false, access: { has: obj => "name" in obj, get: obj => obj.name, set: (obj, value) => { obj.name = value; } }, metadata: _metadata }, _name_initializers, _name_extraInitializers);
98
+ __esDecorate(this, null, _required_decorators, { kind: "accessor", name: "required", static: false, private: false, access: { has: obj => "required" in obj, get: obj => obj.required, set: (obj, value) => { obj.required = value; } }, metadata: _metadata }, _required_initializers, _required_extraInitializers);
99
+ __esDecorate(this, null, _placeholder_decorators, { kind: "accessor", name: "placeholder", static: false, private: false, access: { has: obj => "placeholder" in obj, get: obj => obj.placeholder, set: (obj, value) => { obj.placeholder = value; } }, metadata: _metadata }, _placeholder_initializers, _placeholder_extraInitializers);
100
+ __esDecorate(this, null, _set_value_decorators, { kind: "setter", name: "value", static: false, private: false, access: { has: obj => "value" in obj, set: (obj, value) => { obj.value = value; } }, metadata: _metadata }, null, _instanceExtraInitializers);
101
+ __esDecorate(this, null, _suggestions_decorators, { kind: "accessor", name: "suggestions", static: false, private: false, access: { has: obj => "suggestions" in obj, get: obj => obj.suggestions, set: (obj, value) => { obj.suggestions = value; } }, metadata: _metadata }, _suggestions_initializers, _suggestions_extraInitializers);
102
+ __esDecorate(this, null, _mentionTrigger_decorators, { kind: "accessor", name: "mentionTrigger", static: false, private: false, access: { has: obj => "mentionTrigger" in obj, get: obj => obj.mentionTrigger, set: (obj, value) => { obj.mentionTrigger = value; } }, metadata: _metadata }, _mentionTrigger_initializers, _mentionTrigger_extraInitializers);
103
+ __esDecorate(this, null, _minQueryLength_decorators, { kind: "accessor", name: "minQueryLength", static: false, private: false, access: { has: obj => "minQueryLength" in obj, get: obj => obj.minQueryLength, set: (obj, value) => { obj.minQueryLength = value; } }, metadata: _metadata }, _minQueryLength_initializers, _minQueryLength_extraInitializers);
104
+ __esDecorate(this, null, _editorElement_decorators, { kind: "accessor", name: "editorElement", static: false, private: false, access: { has: obj => "editorElement" in obj, get: obj => obj.editorElement, set: (obj, value) => { obj.editorElement = value; } }, metadata: _metadata }, _editorElement_initializers, _editorElement_extraInitializers);
105
+ __esDecorate(this, null, _suggestionsPopover_decorators, { kind: "accessor", name: "suggestionsPopover", static: false, private: false, access: { has: obj => "suggestionsPopover" in obj, get: obj => obj.suggestionsPopover, set: (obj, value) => { obj.suggestionsPopover = value; } }, metadata: _metadata }, _suggestionsPopover_initializers, _suggestionsPopover_extraInitializers);
106
+ __esDecorate(this, null, _isShowingSuggestions_decorators, { kind: "accessor", name: "isShowingSuggestions", static: false, private: false, access: { has: obj => "isShowingSuggestions" in obj, get: obj => obj.isShowingSuggestions, set: (obj, value) => { obj.isShowingSuggestions = value; } }, metadata: _metadata }, _isShowingSuggestions_initializers, _isShowingSuggestions_extraInitializers);
107
+ __esDecorate(this, null, _filteredSuggestions_decorators, { kind: "accessor", name: "filteredSuggestions", static: false, private: false, access: { has: obj => "filteredSuggestions" in obj, get: obj => obj.filteredSuggestions, set: (obj, value) => { obj.filteredSuggestions = value; } }, metadata: _metadata }, _filteredSuggestions_initializers, _filteredSuggestions_extraInitializers);
108
+ __esDecorate(this, null, _selectedSuggestionIndex_decorators, { kind: "accessor", name: "selectedSuggestionIndex", static: false, private: false, access: { has: obj => "selectedSuggestionIndex" in obj, get: obj => obj.selectedSuggestionIndex, set: (obj, value) => { obj.selectedSuggestionIndex = value; } }, metadata: _metadata }, _selectedSuggestionIndex_initializers, _selectedSuggestionIndex_extraInitializers);
109
+ __esDecorate(this, null, _hasContent_decorators, { kind: "accessor", name: "hasContent", static: false, private: false, access: { has: obj => "hasContent" in obj, get: obj => obj.hasContent, set: (obj, value) => { obj.hasContent = value; } }, metadata: _metadata }, _hasContent_initializers, _hasContent_extraInitializers);
110
+ __esDecorate(this, null, _isLabelFloating_decorators, { kind: "accessor", name: "isLabelFloating", static: false, private: false, access: { has: obj => "isLabelFloating" in obj, get: obj => obj.isLabelFloating, set: (obj, value) => { obj.isLabelFloating = value; } }, metadata: _metadata }, _isLabelFloating_initializers, _isLabelFloating_extraInitializers);
111
+ __esDecorate(this, null, _isEditorFocus_decorators, { kind: "accessor", name: "isEditorFocus", static: false, private: false, access: { has: obj => "isEditorFocus" in obj, get: obj => obj.isEditorFocus, set: (obj, value) => { obj.isEditorFocus = value; } }, metadata: _metadata }, _isEditorFocus_initializers, _isEditorFocus_extraInitializers);
112
+ if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
113
+ }
114
+ /**
115
+ * Shadow root configuration for the component.
116
+ * Uses 'open' mode for accessibility and delegates focus to enable proper focus management.
117
+ */
118
+ static shadowRootOptions = {
119
+ mode: 'open',
120
+ delegatesFocus: true,
121
+ };
122
+ #label_accessor_storage = (__runInitializers(this, _instanceExtraInitializers), __runInitializers(this, _label_initializers, ''
123
+ /**
124
+ * Supporting text displayed below the input
125
+ */
126
+ ));
127
+ /**
128
+ * The label text displayed as placeholder/floating label
129
+ */
130
+ get label() { return this.#label_accessor_storage; }
131
+ set label(value) { this.#label_accessor_storage = value; }
132
+ #supportingText_accessor_storage = (__runInitializers(this, _label_extraInitializers), __runInitializers(this, _supportingText_initializers, ''
133
+ /**
134
+ * Whether the component is disabled
135
+ */
136
+ ));
137
+ /**
138
+ * Supporting text displayed below the input
139
+ */
140
+ get supportingText() { return this.#supportingText_accessor_storage; }
141
+ set supportingText(value) { this.#supportingText_accessor_storage = value; }
142
+ #disabled_accessor_storage = (__runInitializers(this, _supportingText_extraInitializers), __runInitializers(this, _disabled_initializers, false
143
+ /**
144
+ * Whether the component is in an invalid state
145
+ */
146
+ ));
147
+ /**
148
+ * Whether the component is disabled
149
+ */
150
+ get disabled() { return this.#disabled_accessor_storage; }
151
+ set disabled(value) { this.#disabled_accessor_storage = value; }
152
+ #invalid_accessor_storage = (__runInitializers(this, _disabled_extraInitializers), __runInitializers(this, _invalid_initializers, false
153
+ /**
154
+ * The name attribute for form integration
155
+ */
156
+ ));
157
+ /**
158
+ * Whether the component is in an invalid state
159
+ */
160
+ get invalid() { return this.#invalid_accessor_storage; }
161
+ set invalid(value) { this.#invalid_accessor_storage = value; }
162
+ #name_accessor_storage = (__runInitializers(this, _invalid_extraInitializers), __runInitializers(this, _name_initializers, ''
163
+ /**
164
+ * Whether the input is required
165
+ */
166
+ ));
167
+ /**
168
+ * The name attribute for form integration
169
+ */
170
+ get name() { return this.#name_accessor_storage; }
171
+ set name(value) { this.#name_accessor_storage = value; }
172
+ #required_accessor_storage = (__runInitializers(this, _name_extraInitializers), __runInitializers(this, _required_initializers, false
173
+ /**
174
+ * Placeholder text shown when input is empty
175
+ */
176
+ ));
177
+ /**
178
+ * Whether the input is required
179
+ */
180
+ get required() { return this.#required_accessor_storage; }
181
+ set required(value) { this.#required_accessor_storage = value; }
182
+ #placeholder_accessor_storage = (__runInitializers(this, _required_extraInitializers), __runInitializers(this, _placeholder_initializers, ''));
183
+ /**
184
+ * Placeholder text shown when input is empty
185
+ */
186
+ get placeholder() { return this.#placeholder_accessor_storage; }
187
+ set placeholder(value) { this.#placeholder_accessor_storage = value; }
188
+ get value() {
189
+ return this._value;
190
+ }
191
+ set value(newValue) {
192
+ const oldValue = this._value;
193
+ if (newValue === this._value)
194
+ return; // No change, skip update
195
+ this._value = newValue;
196
+ this.requestUpdate('value', oldValue);
197
+ // Only sync editor from value when set externally and element is ready
198
+ if (this.editorElement) {
199
+ this.syncEditorFromValue();
200
+ }
201
+ }
202
+ #suggestions_accessor_storage = (__runInitializers(this, _placeholder_extraInitializers), __runInitializers(this, _suggestions_initializers, []
203
+ /**
204
+ * Character that triggers mention suggestions (default: '@')
205
+ */
206
+ ));
207
+ /**
208
+ * Available suggestions for mentions
209
+ */
210
+ get suggestions() { return this.#suggestions_accessor_storage; }
211
+ set suggestions(value) { this.#suggestions_accessor_storage = value; }
212
+ #mentionTrigger_accessor_storage = (__runInitializers(this, _suggestions_extraInitializers), __runInitializers(this, _mentionTrigger_initializers, '@'
213
+ /**
214
+ * Minimum characters after trigger to show suggestions
215
+ */
216
+ ));
217
+ /**
218
+ * Character that triggers mention suggestions (default: '@')
219
+ */
220
+ get mentionTrigger() { return this.#mentionTrigger_accessor_storage; }
221
+ set mentionTrigger(value) { this.#mentionTrigger_accessor_storage = value; }
222
+ #minQueryLength_accessor_storage = (__runInitializers(this, _mentionTrigger_extraInitializers), __runInitializers(this, _minQueryLength_initializers, 0));
223
+ /**
224
+ * Minimum characters after trigger to show suggestions
225
+ */
226
+ get minQueryLength() { return this.#minQueryLength_accessor_storage; }
227
+ set minQueryLength(value) { this.#minQueryLength_accessor_storage = value; }
228
+ #editorElement_accessor_storage = (__runInitializers(this, _minQueryLength_extraInitializers), __runInitializers(this, _editorElement_initializers, void 0));
229
+ get editorElement() { return this.#editorElement_accessor_storage; }
230
+ set editorElement(value) { this.#editorElement_accessor_storage = value; }
231
+ #suggestionsPopover_accessor_storage = (__runInitializers(this, _editorElement_extraInitializers), __runInitializers(this, _suggestionsPopover_initializers, void 0));
232
+ get suggestionsPopover() { return this.#suggestionsPopover_accessor_storage; }
233
+ set suggestionsPopover(value) { this.#suggestionsPopover_accessor_storage = value; }
234
+ #isShowingSuggestions_accessor_storage = (__runInitializers(this, _suggestionsPopover_extraInitializers), __runInitializers(this, _isShowingSuggestions_initializers, false));
235
+ get isShowingSuggestions() { return this.#isShowingSuggestions_accessor_storage; }
236
+ set isShowingSuggestions(value) { this.#isShowingSuggestions_accessor_storage = value; }
237
+ #filteredSuggestions_accessor_storage = (__runInitializers(this, _isShowingSuggestions_extraInitializers), __runInitializers(this, _filteredSuggestions_initializers, []));
238
+ get filteredSuggestions() { return this.#filteredSuggestions_accessor_storage; }
239
+ set filteredSuggestions(value) { this.#filteredSuggestions_accessor_storage = value; }
240
+ #selectedSuggestionIndex_accessor_storage = (__runInitializers(this, _filteredSuggestions_extraInitializers), __runInitializers(this, _selectedSuggestionIndex_initializers, 0));
241
+ get selectedSuggestionIndex() { return this.#selectedSuggestionIndex_accessor_storage; }
242
+ set selectedSuggestionIndex(value) { this.#selectedSuggestionIndex_accessor_storage = value; }
243
+ #hasContent_accessor_storage = (__runInitializers(this, _selectedSuggestionIndex_extraInitializers), __runInitializers(this, _hasContent_initializers, false));
244
+ get hasContent() { return this.#hasContent_accessor_storage; }
245
+ set hasContent(value) { this.#hasContent_accessor_storage = value; }
246
+ #isLabelFloating_accessor_storage = (__runInitializers(this, _hasContent_extraInitializers), __runInitializers(this, _isLabelFloating_initializers, false));
247
+ get isLabelFloating() { return this.#isLabelFloating_accessor_storage; }
248
+ set isLabelFloating(value) { this.#isLabelFloating_accessor_storage = value; }
249
+ #isEditorFocus_accessor_storage = (__runInitializers(this, _isLabelFloating_extraInitializers), __runInitializers(this, _isEditorFocus_initializers, false));
250
+ get isEditorFocus() { return this.#isEditorFocus_accessor_storage; }
251
+ set isEditorFocus(value) { this.#isEditorFocus_accessor_storage = value; }
252
+ currentMentionQuery = (__runInitializers(this, _isEditorFocus_extraInitializers), '');
253
+ currentMentionStart = -1;
254
+ mentionMap = new Map();
255
+ mutationObserver;
256
+ _value = ''; // Internal value storage
257
+ connectedCallback() {
258
+ super.connectedCallback();
259
+ // Setup mutation observer to watch for changes in the editor
260
+ this.mutationObserver = new MutationObserver(() => {
261
+ this.syncValueFromEditor();
262
+ });
263
+ }
264
+ disconnectedCallback() {
265
+ super.disconnectedCallback();
266
+ this.mutationObserver?.disconnect();
267
+ }
268
+ firstUpdated() {
269
+ // Start observing mutations in the editor
270
+ if (this.editorElement && this.mutationObserver) {
271
+ this.mutationObserver.observe(this.editorElement, {
272
+ childList: true,
273
+ subtree: true,
274
+ characterData: true,
275
+ });
276
+ }
277
+ // Setup initial content
278
+ this.updateComplete.then(() => {
279
+ this.syncEditorFromValue();
280
+ });
281
+ }
282
+ willUpdate(changedProperties) {
283
+ super.willUpdate(changedProperties);
284
+ // No need to sync editor from value here since setter handles it
285
+ if (changedProperties.has('suggestions')) {
286
+ this.updateFilteredSuggestions();
287
+ }
288
+ if (changedProperties.has('selectedSuggestionIndex')) {
289
+ const index = this.selectedSuggestionIndex;
290
+ if (index >= 0) {
291
+ this.suggestionsPopover?.querySelector(`.suggestion-item:nth-child(${index + 1})`)?.scrollIntoView({
292
+ behavior: 'smooth',
293
+ block: 'nearest',
294
+ });
295
+ }
296
+ }
297
+ }
298
+ /**
299
+ * Sets the caret position at the beginning of a specific text node
300
+ */
301
+ setCaretPositionAtTextNode(textNode, offset = 0) {
302
+ const selection = window.getSelection();
303
+ if (!selection)
304
+ return;
305
+ const range = document.createRange();
306
+ range.setStart(textNode, offset);
307
+ range.setEnd(textNode, offset);
308
+ selection.removeAllRanges();
309
+ selection.addRange(range);
310
+ }
311
+ /**
312
+ * Synchronizes the value property from the editor content
313
+ */
314
+ syncValueFromEditor() {
315
+ const newValue = this.getValueFromEditor();
316
+ if (newValue !== this._value) {
317
+ // Update internal value directly to avoid triggering setter
318
+ this._value = newValue;
319
+ this.requestUpdate('value');
320
+ this.dispatchEvent(new Event('input', { bubbles: true }));
321
+ }
322
+ this.updateContentState();
323
+ }
324
+ /**
325
+ * Gets the value from editor content, converting chips to @{mention} format
326
+ */
327
+ getValueFromEditor() {
328
+ const childNodes = Array.from(this.editorElement.childNodes);
329
+ let result = '';
330
+ for (const node of childNodes) {
331
+ if (node.nodeType === Node.TEXT_NODE) {
332
+ result += node.textContent || '';
333
+ }
334
+ else if (node.nodeType === Node.ELEMENT_NODE) {
335
+ const element = node;
336
+ if (element.classList.contains('mention-chip')) {
337
+ const mentionId = element.getAttribute('data-mention-id');
338
+ if (mentionId) {
339
+ result += `@{${mentionId}}`;
340
+ }
341
+ }
342
+ else {
343
+ result += element.textContent || '';
344
+ }
345
+ }
346
+ }
347
+ return result;
348
+ }
349
+ /**
350
+ * Synchronizes the editor content from the value property
351
+ */
352
+ syncEditorFromValue() {
353
+ if (!this.editorElement)
354
+ return;
355
+ const fragments = this.parseValueToFragments(this._value);
356
+ this.editorElement.innerHTML = '';
357
+ for (const fragment of fragments) {
358
+ if (fragment.type === 'text') {
359
+ this.editorElement.appendChild(document.createTextNode(fragment.content));
360
+ }
361
+ else if (fragment.type === 'mention') {
362
+ if (fragment.mentionId) {
363
+ let mention = this.mentionMap.get(fragment.mentionId);
364
+ // If mention not in map, try to find it in suggestions
365
+ if (!mention) {
366
+ mention = this.suggestions.find((s) => s.id === fragment.mentionId);
367
+ if (mention) {
368
+ // Add to map for future use
369
+ this.mentionMap.set(mention.id, mention);
370
+ }
371
+ }
372
+ if (mention) {
373
+ const chipElement = this.createMentionChip(mention);
374
+ this.editorElement.appendChild(chipElement);
375
+ }
376
+ else {
377
+ // Fallback to text if mention not found anywhere
378
+ this.editorElement.appendChild(document.createTextNode(`@{${fragment.mentionId}}`));
379
+ }
380
+ }
381
+ }
382
+ }
383
+ this.updateContentState();
384
+ }
385
+ /**
386
+ * Parses value string into text and mention fragments
387
+ */
388
+ parseValueToFragments(value) {
389
+ const fragments = [];
390
+ const mentionRegex = /@\{([^}]+)\}/g;
391
+ let lastIndex = 0;
392
+ let match;
393
+ while ((match = mentionRegex.exec(value)) !== null) {
394
+ // Add text before mention
395
+ if (match.index > lastIndex) {
396
+ fragments.push({
397
+ type: 'text',
398
+ content: value.substring(lastIndex, match.index),
399
+ });
400
+ }
401
+ // Add mention
402
+ fragments.push({
403
+ type: 'mention',
404
+ content: match[0],
405
+ mentionId: match[1],
406
+ });
407
+ lastIndex = mentionRegex.lastIndex;
408
+ }
409
+ // Add remaining text
410
+ if (lastIndex < value.length) {
411
+ fragments.push({
412
+ type: 'text',
413
+ content: value.substring(lastIndex),
414
+ });
415
+ }
416
+ return fragments;
417
+ }
418
+ /**
419
+ * Creates a mention chip element
420
+ */
421
+ createMentionChip(mention) {
422
+ const wrapper = document.createElement('span');
423
+ wrapper.className = 'mention-chip';
424
+ wrapper.setAttribute('data-mention-id', mention.id);
425
+ wrapper.setAttribute('contenteditable', 'false');
426
+ const chip = document.createElement('ui-chip');
427
+ chip.setAttribute('type', 'input');
428
+ chip.setAttribute('removable', 'true');
429
+ chip.textContent = mention.label;
430
+ chip.addEventListener('remove', () => {
431
+ this.removeMention(wrapper, mention);
432
+ });
433
+ wrapper.appendChild(chip);
434
+ return wrapper;
435
+ }
436
+ /**
437
+ * Updates content state flags
438
+ */
439
+ updateContentState() {
440
+ const hasAnyContent = this.editorElement.childNodes.length > 0 && (this.editorElement.textContent?.trim().length || 0) > 0;
441
+ this.hasContent = hasAnyContent;
442
+ this.isLabelFloating = hasAnyContent || this.isShowingSuggestions || this.isEditorFocus;
443
+ }
444
+ /**
445
+ * Handles input events in the editor
446
+ */
447
+ handleEditorInput(event) {
448
+ event.stopPropagation();
449
+ // Check for mention trigger
450
+ this.checkForMentionTrigger();
451
+ // Sync value
452
+ this.syncValueFromEditor();
453
+ }
454
+ /**
455
+ * Handles keydown events in the editor
456
+ */
457
+ handleEditorKeyDown(event) {
458
+ if (this.isShowingSuggestions) {
459
+ this.handleSuggestionKeyDown(event);
460
+ }
461
+ }
462
+ /**
463
+ * Handles keydown events when suggestions are visible
464
+ */
465
+ handleSuggestionKeyDown(event) {
466
+ switch (event.key) {
467
+ case 'ArrowUp':
468
+ event.preventDefault();
469
+ this.selectedSuggestionIndex = Math.max(0, this.selectedSuggestionIndex - 1);
470
+ break;
471
+ case 'ArrowDown':
472
+ event.preventDefault();
473
+ this.selectedSuggestionIndex = Math.min(this.filteredSuggestions.length - 1, this.selectedSuggestionIndex + 1);
474
+ break;
475
+ case 'Enter':
476
+ case 'Tab':
477
+ event.preventDefault();
478
+ this.selectSuggestion(this.filteredSuggestions[this.selectedSuggestionIndex]);
479
+ break;
480
+ case 'Escape':
481
+ event.preventDefault();
482
+ this.hideSuggestions();
483
+ break;
484
+ }
485
+ }
486
+ /**
487
+ * Handles focus events
488
+ */
489
+ handleEditorFocus() {
490
+ this.isEditorFocus = true;
491
+ this.updateContentState();
492
+ }
493
+ /**
494
+ * Handles blur events
495
+ */
496
+ handleEditorBlur(event) {
497
+ // Don't hide suggestions if focus moved to suggestions popover
498
+ if (event.relatedTarget && this.suggestionsPopover?.contains(event.relatedTarget)) {
499
+ return;
500
+ }
501
+ this.isEditorFocus = false;
502
+ this.hideSuggestions();
503
+ this.updateContentState();
504
+ this.dispatchEvent(new Event('change', { bubbles: true }));
505
+ }
506
+ handleEditorPaste(event) {
507
+ // Prevent default paste behavior to handle mentions properly
508
+ event.preventDefault();
509
+ const pastedContent = event.clipboardData?.getData('text/plain');
510
+ if (!pastedContent)
511
+ return;
512
+ const selection = window.getSelection();
513
+ if (!selection || selection.rangeCount === 0)
514
+ return;
515
+ // Get the current range
516
+ let range;
517
+ if ('getComposedRanges' in selection && typeof selection.getComposedRanges === 'function' && this.shadowRoot) {
518
+ const composedRanges = selection.getComposedRanges({ shadowRoots: [this.shadowRoot] });
519
+ if (composedRanges.length === 0)
520
+ return;
521
+ range = composedRanges[0];
522
+ }
523
+ else {
524
+ range = selection.getRangeAt(0);
525
+ }
526
+ // Convert StaticRange to Range if needed for deleteContents
527
+ let workingRange;
528
+ if (range instanceof StaticRange) {
529
+ workingRange = document.createRange();
530
+ workingRange.setStart(range.startContainer, range.startOffset);
531
+ workingRange.setEnd(range.endContainer, range.endOffset);
532
+ }
533
+ else {
534
+ workingRange = range;
535
+ }
536
+ // Delete the current selection (if any)
537
+ workingRange.deleteContents();
538
+ // Insert the pasted text at the current position
539
+ const textNode = document.createTextNode(pastedContent);
540
+ workingRange.insertNode(textNode);
541
+ // Position cursor at the end of the inserted text
542
+ workingRange.setStartAfter(textNode);
543
+ workingRange.setEndAfter(textNode);
544
+ selection.removeAllRanges();
545
+ selection.addRange(workingRange);
546
+ // Hide suggestions if showing
547
+ this.hideSuggestions();
548
+ // Sync value and trigger events
549
+ this.syncValueFromEditor();
550
+ }
551
+ /**
552
+ * Checks if the current caret position indicates a mention trigger
553
+ */
554
+ checkForMentionTrigger() {
555
+ const selection = window.getSelection();
556
+ if (!selection || selection.rangeCount === 0) {
557
+ this.hideSuggestions();
558
+ return;
559
+ }
560
+ // Use getComposedRanges() for shadow DOM support, fallback to getRangeAt()
561
+ let range;
562
+ if ('getComposedRanges' in selection && typeof selection.getComposedRanges === 'function' && this.shadowRoot) {
563
+ const composedRanges = selection.getComposedRanges({ shadowRoots: [this.shadowRoot] });
564
+ if (composedRanges.length === 0) {
565
+ this.hideSuggestions();
566
+ return;
567
+ }
568
+ range = composedRanges[0];
569
+ }
570
+ else {
571
+ range = selection.getRangeAt(0);
572
+ }
573
+ const caretContainer = range.startContainer;
574
+ const caretOffset = range.startOffset;
575
+ // Ensure the caret is within our editor element
576
+ if (!this.editorElement.contains(caretContainer)) {
577
+ this.hideSuggestions();
578
+ return;
579
+ }
580
+ // Only look for triggers in text nodes
581
+ if (caretContainer.nodeType !== Node.TEXT_NODE) {
582
+ this.hideSuggestions();
583
+ return;
584
+ }
585
+ const textContent = caretContainer.textContent || '';
586
+ // Look backwards from caret to find mention trigger
587
+ let mentionStart = -1;
588
+ for (let i = caretOffset - 1; i >= 0; i--) {
589
+ const char = textContent[i];
590
+ if (char === this.mentionTrigger) {
591
+ mentionStart = i;
592
+ break;
593
+ }
594
+ if (char === ' ' || char === '\n') {
595
+ break;
596
+ }
597
+ }
598
+ if (mentionStart >= 0) {
599
+ const query = textContent.substring(mentionStart + 1, caretOffset);
600
+ if (query.length >= this.minQueryLength) {
601
+ this.currentMentionQuery = query;
602
+ this.currentMentionStart = this.getGlobalTextPosition(caretContainer, mentionStart);
603
+ this.showSuggestions();
604
+ this.updateFilteredSuggestions();
605
+ }
606
+ else {
607
+ this.hideSuggestions();
608
+ }
609
+ }
610
+ else {
611
+ this.hideSuggestions();
612
+ }
613
+ }
614
+ walkerNodeFilter(node) {
615
+ if (node.nodeType === Node.TEXT_NODE) {
616
+ return NodeFilter.FILTER_ACCEPT;
617
+ }
618
+ else if (node.nodeType === Node.ELEMENT_NODE) {
619
+ const element = node;
620
+ if (element.classList.contains('mention-chip')) {
621
+ // Accept mention chips as single characters
622
+ return NodeFilter.FILTER_ACCEPT;
623
+ }
624
+ else if (element.parentElement?.classList.contains('mention-chip')) {
625
+ // It's a chip, ignore the entire tree
626
+ return NodeFilter.FILTER_REJECT;
627
+ }
628
+ }
629
+ return NodeFilter.FILTER_SKIP;
630
+ }
631
+ /**
632
+ * Gets the global text position within the editor for a position within a text node
633
+ */
634
+ getGlobalTextPosition(textNode, offsetInNode) {
635
+ let position = 0;
636
+ const walker = document.createTreeWalker(this.editorElement, ShowMask, this.walkerNodeFilter);
637
+ let node = walker.nextNode();
638
+ while (node && node !== textNode) {
639
+ if (node.nodeType === Node.TEXT_NODE) {
640
+ position += node.textContent?.length || 0;
641
+ }
642
+ else if (node.nodeType === Node.ELEMENT_NODE) {
643
+ const element = node;
644
+ if (element.classList?.contains('mention-chip')) {
645
+ position += 1; // Count chip as 1 character
646
+ }
647
+ }
648
+ node = walker.nextNode();
649
+ }
650
+ return position + offsetInNode;
651
+ }
652
+ /**
653
+ * Finds the DOM node and offset that corresponds to a global text position
654
+ */
655
+ findNodeAtGlobalPosition(globalPosition) {
656
+ let currentPosition = 0;
657
+ const walker = document.createTreeWalker(this.editorElement, ShowMask, this.walkerNodeFilter);
658
+ let node = walker.nextNode();
659
+ while (node) {
660
+ if (node.nodeType === Node.TEXT_NODE) {
661
+ const textLength = node.textContent?.length || 0;
662
+ if (currentPosition + textLength >= globalPosition) {
663
+ return {
664
+ node,
665
+ offset: globalPosition - currentPosition,
666
+ };
667
+ }
668
+ currentPosition += textLength;
669
+ }
670
+ else if (node.nodeType === Node.ELEMENT_NODE) {
671
+ const element = node;
672
+ if (element.classList?.contains('mention-chip')) {
673
+ if (currentPosition === globalPosition) {
674
+ // Position is right before the chip
675
+ const parentNode = element.parentNode;
676
+ if (parentNode) {
677
+ return {
678
+ node: parentNode,
679
+ offset: Array.from(parentNode.childNodes).indexOf(element),
680
+ };
681
+ }
682
+ }
683
+ currentPosition += 1; // Count chip as 1 character
684
+ }
685
+ }
686
+ node = walker.nextNode();
687
+ }
688
+ // Position is beyond the end, return the last position
689
+ const lastChild = this.editorElement.lastChild;
690
+ if (lastChild) {
691
+ if (lastChild.nodeType === Node.TEXT_NODE) {
692
+ return {
693
+ node: lastChild,
694
+ offset: lastChild.textContent?.length || 0,
695
+ };
696
+ }
697
+ else {
698
+ return {
699
+ node: this.editorElement,
700
+ offset: this.editorElement.childNodes.length,
701
+ };
702
+ }
703
+ }
704
+ return null;
705
+ }
706
+ /**
707
+ * Shows the suggestions popover
708
+ */
709
+ showSuggestions() {
710
+ if (!this.isShowingSuggestions) {
711
+ this.isShowingSuggestions = true;
712
+ this.selectedSuggestionIndex = 0;
713
+ this.updateContentState();
714
+ // Use Popover API to show the popover
715
+ this.updateComplete.then(() => {
716
+ if (this.suggestionsPopover) {
717
+ this.suggestionsPopover.showPopover();
718
+ this.positionSuggestions();
719
+ }
720
+ });
721
+ }
722
+ }
723
+ /**
724
+ * Hides the suggestions popover
725
+ */
726
+ hideSuggestions() {
727
+ if (this.isShowingSuggestions) {
728
+ this.isShowingSuggestions = false;
729
+ this.currentMentionQuery = '';
730
+ this.currentMentionStart = -1;
731
+ this.updateContentState();
732
+ // Use Popover API to hide the popover
733
+ if (this.suggestionsPopover) {
734
+ this.suggestionsPopover.hidePopover();
735
+ }
736
+ }
737
+ }
738
+ /**
739
+ * Updates filtered suggestions based on current query
740
+ */
741
+ updateFilteredSuggestions() {
742
+ if (!this.currentMentionQuery) {
743
+ this.filteredSuggestions = this.suggestions.slice(0, 10); // Limit to 10
744
+ return;
745
+ }
746
+ const query = this.currentMentionQuery.toLowerCase();
747
+ this.filteredSuggestions = this.suggestions
748
+ .filter((suggestion) => suggestion.label.toLowerCase().includes(query) ||
749
+ suggestion.description?.toLowerCase().includes(query) ||
750
+ suggestion.suffix?.toLowerCase().includes(query))
751
+ .slice(0, 10); // Limit to 10
752
+ // Reset selection if needed
753
+ if (this.selectedSuggestionIndex >= this.filteredSuggestions.length) {
754
+ this.selectedSuggestionIndex = 0;
755
+ }
756
+ }
757
+ /**
758
+ * Positions the suggestions popover using the Popover API anchor positioning
759
+ */
760
+ positionSuggestions() {
761
+ if (!this.suggestionsPopover)
762
+ return;
763
+ const selection = window.getSelection();
764
+ if (!selection || selection.rangeCount === 0)
765
+ return;
766
+ // Use getComposedRanges() for shadow DOM support, fallback to getRangeAt()
767
+ let range;
768
+ if ('getComposedRanges' in selection && typeof selection.getComposedRanges === 'function' && this.shadowRoot) {
769
+ const composedRanges = selection.getComposedRanges({ shadowRoots: [this.shadowRoot] });
770
+ if (composedRanges.length === 0)
771
+ return;
772
+ range = composedRanges[0];
773
+ }
774
+ else {
775
+ range = selection.getRangeAt(0);
776
+ }
777
+ // Convert StaticRange to Range if needed for getBoundingClientRect
778
+ let workingRange;
779
+ if (range instanceof StaticRange) {
780
+ workingRange = document.createRange();
781
+ workingRange.setStart(range.startContainer, range.startOffset);
782
+ workingRange.setEnd(range.endContainer, range.endOffset);
783
+ }
784
+ else {
785
+ workingRange = range;
786
+ }
787
+ const rect = workingRange.getBoundingClientRect();
788
+ // Position suggestions below the caret using manual positioning as fallback
789
+ // The Popover API will handle proper layering and overflow handling
790
+ this.suggestionsPopover.style.left = `${rect.left}px`;
791
+ this.suggestionsPopover.style.top = `${rect.bottom + 4}px`;
792
+ }
793
+ /**
794
+ * Selects a suggestion and inserts it as a mention
795
+ */
796
+ selectSuggestion(suggestion) {
797
+ if (!suggestion)
798
+ return;
799
+ // Add to mention map
800
+ this.mentionMap.set(suggestion.id, suggestion);
801
+ // Find the position where the mention trigger starts
802
+ const mentionStart = this.currentMentionStart;
803
+ // Find the DOM node and offset for the mention start position
804
+ const mentionStartInfo = this.findNodeAtGlobalPosition(mentionStart);
805
+ if (!mentionStartInfo) {
806
+ // Fallback: insert at the end
807
+ const chip = this.createMentionChip(suggestion);
808
+ const afterTextNode = document.createTextNode('');
809
+ this.editorElement.appendChild(chip);
810
+ this.editorElement.appendChild(afterTextNode);
811
+ this.setCaretPositionAtTextNode(afterTextNode, 0);
812
+ this.hideSuggestions();
813
+ this.syncValueFromEditor();
814
+ this.dispatchEvent(new CustomEvent('mention-insert', {
815
+ detail: {
816
+ suggestion,
817
+ trigger: this.mentionTrigger + this.currentMentionQuery,
818
+ position: mentionStart,
819
+ },
820
+ bubbles: true,
821
+ }));
822
+ return;
823
+ }
824
+ // If the target is not a text node, insert at the container level
825
+ if (mentionStartInfo.node.nodeType !== Node.TEXT_NODE) {
826
+ const chip = this.createMentionChip(suggestion);
827
+ const container = mentionStartInfo.node;
828
+ const beforeNode = container.childNodes[mentionStartInfo.offset];
829
+ // Create an empty text node for caret positioning
830
+ const afterTextNode = document.createTextNode('');
831
+ if (beforeNode) {
832
+ container.insertBefore(chip, beforeNode);
833
+ container.insertBefore(afterTextNode, beforeNode);
834
+ }
835
+ else {
836
+ container.appendChild(chip);
837
+ container.appendChild(afterTextNode);
838
+ }
839
+ // Position caret at the beginning of the after text node
840
+ this.setCaretPositionAtTextNode(afterTextNode, 0);
841
+ this.hideSuggestions();
842
+ this.syncValueFromEditor();
843
+ this.dispatchEvent(new CustomEvent('mention-insert', {
844
+ detail: {
845
+ suggestion,
846
+ trigger: this.mentionTrigger + this.currentMentionQuery,
847
+ position: mentionStart,
848
+ },
849
+ bubbles: true,
850
+ }));
851
+ return;
852
+ }
853
+ // We have a text node - split it and insert the chip
854
+ const textNode = mentionStartInfo.node;
855
+ const splitOffset = mentionStartInfo.offset;
856
+ // Create the mention chip
857
+ const chip = this.createMentionChip(suggestion);
858
+ // Split the text node at the mention start position
859
+ const beforeText = textNode.textContent?.substring(0, splitOffset) || '';
860
+ const afterText = textNode.textContent?.substring(splitOffset + 1) || ''; // +1 to skip the trigger
861
+ // Replace the original text node with the split content
862
+ const parentNode = textNode.parentNode;
863
+ if (parentNode) {
864
+ // Create new text nodes - always create afterTextNode even if empty
865
+ const beforeTextNode = beforeText ? document.createTextNode(beforeText) : null;
866
+ const afterTextNode = document.createTextNode(afterText); // Always create, even if empty
867
+ // Insert the nodes in order
868
+ if (beforeTextNode) {
869
+ parentNode.insertBefore(beforeTextNode, textNode);
870
+ }
871
+ parentNode.insertBefore(chip, textNode);
872
+ parentNode.insertBefore(afterTextNode, textNode);
873
+ // Remove the original text node
874
+ parentNode.removeChild(textNode);
875
+ // Position caret at the beginning of the after text node
876
+ this.setCaretPositionAtTextNode(afterTextNode, 0);
877
+ }
878
+ else {
879
+ // Fallback: append to editor and create a text node for caret positioning
880
+ const afterTextNode = document.createTextNode('');
881
+ this.editorElement.appendChild(chip);
882
+ this.editorElement.appendChild(afterTextNode);
883
+ this.setCaretPositionAtTextNode(afterTextNode, 0);
884
+ }
885
+ // Hide suggestions
886
+ this.hideSuggestions();
887
+ // Sync value and dispatch events
888
+ this.syncValueFromEditor();
889
+ this.dispatchEvent(new CustomEvent('mention-insert', {
890
+ detail: {
891
+ suggestion,
892
+ trigger: this.mentionTrigger + this.currentMentionQuery,
893
+ position: mentionStart,
894
+ },
895
+ bubbles: true,
896
+ }));
897
+ }
898
+ /**
899
+ * Removes a mention chip
900
+ */
901
+ removeMention(chipElement, mention) {
902
+ const position = this.getElementPosition(chipElement);
903
+ chipElement.remove();
904
+ this.syncValueFromEditor();
905
+ this.dispatchEvent(new CustomEvent('mention-remove', {
906
+ detail: {
907
+ suggestion: mention,
908
+ position,
909
+ },
910
+ bubbles: true,
911
+ }));
912
+ }
913
+ /**
914
+ * Gets the text position of an element
915
+ */
916
+ getElementPosition(element) {
917
+ let position = 0;
918
+ let currentNode = this.editorElement.firstChild;
919
+ while (currentNode && currentNode !== element) {
920
+ if (currentNode.nodeType === Node.TEXT_NODE) {
921
+ position += currentNode.textContent?.length || 0;
922
+ }
923
+ else if (currentNode.nodeType === Node.ELEMENT_NODE) {
924
+ const element = currentNode;
925
+ if (element.classList?.contains('mention-chip')) {
926
+ position += 1; // Count chip as 1 character
927
+ }
928
+ }
929
+ currentNode = currentNode.nextSibling;
930
+ }
931
+ return position;
932
+ }
933
+ /**
934
+ * Handles clicking on a suggestion
935
+ */
936
+ handleSuggestionClick(suggestion, event) {
937
+ event.preventDefault();
938
+ this.selectSuggestion(suggestion);
939
+ this.focus();
940
+ }
941
+ /**
942
+ * Renders a suggestion item
943
+ */
944
+ renderSuggestion(suggestion, index) {
945
+ const isSelected = index === this.selectedSuggestionIndex;
946
+ const classes = classMap({
947
+ 'suggestion-item': true,
948
+ 'selected': isSelected,
949
+ });
950
+ return html `
951
+ <button
952
+ class="${classes}"
953
+ @click="${(e) => this.handleSuggestionClick(suggestion, e)}"
954
+ @mouseenter="${() => (this.selectedSuggestionIndex = index)}"
955
+ >
956
+ <div class="suggestion-content">
957
+ <div class="suggestion-headline">${suggestion.label}</div>
958
+ ${suggestion.description
959
+ ? html ` <div class="suggestion-supporting-text">${suggestion.description}</div> `
960
+ : nothing}
961
+ </div>
962
+ ${suggestion.suffix ? html ` <div class="suggestion-suffix">${suggestion.suffix}</div> ` : nothing}
963
+ </button>
964
+ `;
965
+ }
966
+ /**
967
+ * Renders the suggestions popover
968
+ */
969
+ renderSuggestions() {
970
+ return html `
971
+ <div class="suggestions-popover" popover="manual">
972
+ ${this.isShowingSuggestions && this.filteredSuggestions.length > 0
973
+ ? this.filteredSuggestions.map((suggestion, index) => this.renderSuggestion(suggestion, index))
974
+ : nothing}
975
+ </div>
976
+ `;
977
+ }
978
+ render() {
979
+ const surfaceClasses = classMap({
980
+ 'surface': true,
981
+ 'has-content': this.hasContent,
982
+ });
983
+ const labelClasses = classMap({
984
+ label: true,
985
+ floating: this.isLabelFloating,
986
+ });
987
+ return html `
988
+ <div class="${surfaceClasses}">
989
+ <div class="container"></div>
990
+ <div class="content">
991
+ <div class="body">
992
+ ${this.label ? html `<div class="${labelClasses}">${this.label}</div>` : nothing}
993
+ <div
994
+ class="editor"
995
+ contenteditable="${!this.disabled}"
996
+ data-placeholder="${ifDefined(this.placeholder)}"
997
+ @input="${this.handleEditorInput}"
998
+ @keydown="${this.handleEditorKeyDown}"
999
+ @focus="${this.handleEditorFocus}"
1000
+ @blur="${this.handleEditorBlur}"
1001
+ @paste="${this.handleEditorPaste}"
1002
+ role="textbox"
1003
+ aria-label="${ifDefined(this.label)}"
1004
+ aria-multiline="true"
1005
+ aria-required="${this.required}"
1006
+ aria-invalid="${this.invalid}"
1007
+ tabindex="${this.disabled ? -1 : 0}"
1008
+ ></div>
1009
+ </div>
1010
+ </div>
1011
+ ${this.renderSuggestions()}
1012
+ </div>
1013
+ ${this.supportingText ? html ` <div class="supporting-text">${this.supportingText}</div> ` : nothing}
1014
+ `;
1015
+ }
1016
+ };
1017
+ })();
1018
+ /**
1019
+ * A material design textarea component that supports @mentions with suggestions.
1020
+ *
1021
+ * Features:
1022
+ * - Material Design styling
1023
+ * - @mention triggers with customizable suggestions
1024
+ * - Inline pill/chip rendering for mentions
1025
+ * - Proper caret management
1026
+ * - Keyboard navigation for suggestions
1027
+ * - Overflow container support
1028
+ * - Generic design for extensibility
1029
+ * - Accessibility support
1030
+ *
1031
+ * @fires mention-insert - When a mention is inserted
1032
+ * @fires mention-remove - When a mention is removed
1033
+ * @fires input - When the input value changes
1034
+ * @fires change - When the input loses focus and value has changed
1035
+ */
1036
+ export default MentionTextArea;
1037
+ //# sourceMappingURL=MentionTextArea.js.map