@cloudscape-design/components 3.0.1270 → 3.0.1272

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 (181) hide show
  1. package/app-layout/visual-refresh-toolbar/toolbar/index.js +1 -1
  2. package/app-layout/visual-refresh-toolbar/toolbar/index.js.map +1 -1
  3. package/app-layout/visual-refresh-toolbar/toolbar/trigger-button/index.d.ts +1 -1
  4. package/app-layout/visual-refresh-toolbar/toolbar/trigger-button/index.d.ts.map +1 -1
  5. package/app-layout/visual-refresh-toolbar/toolbar/trigger-button/index.js +1 -2
  6. package/app-layout/visual-refresh-toolbar/toolbar/trigger-button/index.js.map +1 -1
  7. package/app-layout/visual-refresh-toolbar/toolbar/trigger-button/styles.css.js +6 -7
  8. package/app-layout/visual-refresh-toolbar/toolbar/trigger-button/styles.scoped.css +20 -26
  9. package/app-layout/visual-refresh-toolbar/toolbar/trigger-button/styles.selectors.js +6 -7
  10. package/button/styles.css.js +22 -22
  11. package/button/styles.scoped.css +78 -78
  12. package/button/styles.selectors.js +22 -22
  13. package/help-panel/styles.css.js +6 -6
  14. package/help-panel/styles.scoped.css +70 -70
  15. package/help-panel/styles.selectors.js +6 -6
  16. package/i18n/messages/all.all.js +1 -1
  17. package/i18n/messages/all.all.json +1 -1
  18. package/i18n/messages/all.ar.js +1 -1
  19. package/i18n/messages/all.ar.json +1 -1
  20. package/i18n/messages/all.de.js +1 -1
  21. package/i18n/messages/all.de.json +1 -1
  22. package/i18n/messages/all.en-GB.js +1 -1
  23. package/i18n/messages/all.en-GB.json +1 -1
  24. package/i18n/messages/all.en.js +1 -1
  25. package/i18n/messages/all.en.json +1 -1
  26. package/i18n/messages/all.es.js +1 -1
  27. package/i18n/messages/all.es.json +1 -1
  28. package/i18n/messages/all.fr.js +1 -1
  29. package/i18n/messages/all.fr.json +1 -1
  30. package/i18n/messages/all.id.js +1 -1
  31. package/i18n/messages/all.id.json +1 -1
  32. package/i18n/messages/all.it.js +1 -1
  33. package/i18n/messages/all.it.json +1 -1
  34. package/i18n/messages/all.ja.js +1 -1
  35. package/i18n/messages/all.ja.json +1 -1
  36. package/i18n/messages/all.ko.js +1 -1
  37. package/i18n/messages/all.ko.json +1 -1
  38. package/i18n/messages/all.pt-BR.js +1 -1
  39. package/i18n/messages/all.pt-BR.json +1 -1
  40. package/i18n/messages/all.tr.js +1 -1
  41. package/i18n/messages/all.tr.json +1 -1
  42. package/i18n/messages/all.zh-CN.js +1 -1
  43. package/i18n/messages/all.zh-CN.json +1 -1
  44. package/i18n/messages/all.zh-TW.js +1 -1
  45. package/i18n/messages/all.zh-TW.json +1 -1
  46. package/i18n/messages-types.d.ts +18 -0
  47. package/i18n/messages-types.d.ts.map +1 -1
  48. package/i18n/messages-types.js.map +1 -1
  49. package/internal/base-component/styles.scoped.css +63 -4
  50. package/internal/components/token-list/styles.css.js +10 -10
  51. package/internal/components/token-list/styles.scoped.css +25 -25
  52. package/internal/components/token-list/styles.selectors.js +10 -10
  53. package/internal/environment.js +2 -2
  54. package/internal/environment.json +2 -2
  55. package/internal/generated/styles/tokens.d.ts +17 -3
  56. package/internal/generated/styles/tokens.js +17 -3
  57. package/internal/generated/theming/index.cjs +417 -9
  58. package/internal/generated/theming/index.cjs.d.ts +189 -0
  59. package/internal/generated/theming/index.d.ts +189 -0
  60. package/internal/generated/theming/index.js +417 -9
  61. package/internal/keycode.d.ts +3 -1
  62. package/internal/keycode.d.ts.map +1 -1
  63. package/internal/keycode.js +5 -0
  64. package/internal/keycode.js.map +1 -1
  65. package/internal/manifest.json +1 -1
  66. package/internal/utils/handle-key.d.ts +22 -1
  67. package/internal/utils/handle-key.d.ts.map +1 -1
  68. package/internal/utils/handle-key.js +62 -4
  69. package/internal/utils/handle-key.js.map +1 -1
  70. package/item-card/styles.css.js +14 -14
  71. package/item-card/styles.scoped.css +52 -52
  72. package/item-card/styles.selectors.js +14 -14
  73. package/link/styles.css.js +21 -21
  74. package/link/styles.scoped.css +81 -81
  75. package/link/styles.selectors.js +21 -21
  76. package/package.json +1 -1
  77. package/prompt-input/components/menu-dropdown.d.ts +33 -0
  78. package/prompt-input/components/menu-dropdown.d.ts.map +1 -0
  79. package/prompt-input/components/menu-dropdown.js +48 -0
  80. package/prompt-input/components/menu-dropdown.js.map +1 -0
  81. package/prompt-input/components/textarea-mode.d.ts +15 -0
  82. package/prompt-input/components/textarea-mode.d.ts.map +1 -0
  83. package/prompt-input/components/textarea-mode.js +8 -0
  84. package/prompt-input/components/textarea-mode.js.map +1 -0
  85. package/prompt-input/components/token-mode.d.ts +61 -0
  86. package/prompt-input/components/token-mode.d.ts.map +1 -0
  87. package/prompt-input/components/token-mode.js +37 -0
  88. package/prompt-input/components/token-mode.js.map +1 -0
  89. package/prompt-input/core/caret-controller.d.ts +73 -0
  90. package/prompt-input/core/caret-controller.d.ts.map +1 -0
  91. package/prompt-input/core/caret-controller.js +396 -0
  92. package/prompt-input/core/caret-controller.js.map +1 -0
  93. package/prompt-input/core/caret-spot-utils.d.ts +6 -0
  94. package/prompt-input/core/caret-spot-utils.d.ts.map +1 -0
  95. package/prompt-input/core/caret-spot-utils.js +52 -0
  96. package/prompt-input/core/caret-spot-utils.js.map +1 -0
  97. package/prompt-input/core/caret-utils.d.ts +25 -0
  98. package/prompt-input/core/caret-utils.d.ts.map +1 -0
  99. package/prompt-input/core/caret-utils.js +183 -0
  100. package/prompt-input/core/caret-utils.js.map +1 -0
  101. package/prompt-input/core/constants.d.ts +14 -0
  102. package/prompt-input/core/constants.d.ts.map +1 -0
  103. package/prompt-input/core/constants.js +18 -0
  104. package/prompt-input/core/constants.js.map +1 -0
  105. package/prompt-input/core/dom-utils.d.ts +60 -0
  106. package/prompt-input/core/dom-utils.d.ts.map +1 -0
  107. package/prompt-input/core/dom-utils.js +252 -0
  108. package/prompt-input/core/dom-utils.js.map +1 -0
  109. package/prompt-input/core/event-handlers.d.ts +68 -0
  110. package/prompt-input/core/event-handlers.d.ts.map +1 -0
  111. package/prompt-input/core/event-handlers.js +678 -0
  112. package/prompt-input/core/event-handlers.js.map +1 -0
  113. package/prompt-input/core/menu-state.d.ts +62 -0
  114. package/prompt-input/core/menu-state.d.ts.map +1 -0
  115. package/prompt-input/core/menu-state.js +168 -0
  116. package/prompt-input/core/menu-state.js.map +1 -0
  117. package/prompt-input/core/token-operations.d.ts +21 -0
  118. package/prompt-input/core/token-operations.d.ts.map +1 -0
  119. package/prompt-input/core/token-operations.js +273 -0
  120. package/prompt-input/core/token-operations.js.map +1 -0
  121. package/prompt-input/core/token-renderer.d.ts +26 -0
  122. package/prompt-input/core/token-renderer.d.ts.map +1 -0
  123. package/prompt-input/core/token-renderer.js +230 -0
  124. package/prompt-input/core/token-renderer.js.map +1 -0
  125. package/prompt-input/core/token-utils.d.ts +22 -0
  126. package/prompt-input/core/token-utils.d.ts.map +1 -0
  127. package/prompt-input/core/token-utils.js +262 -0
  128. package/prompt-input/core/token-utils.js.map +1 -0
  129. package/prompt-input/core/trigger-utils.d.ts +18 -0
  130. package/prompt-input/core/trigger-utils.d.ts.map +1 -0
  131. package/prompt-input/core/trigger-utils.js +174 -0
  132. package/prompt-input/core/trigger-utils.js.map +1 -0
  133. package/prompt-input/core/type-guards.d.ts +13 -0
  134. package/prompt-input/core/type-guards.d.ts.map +1 -0
  135. package/prompt-input/core/type-guards.js +36 -0
  136. package/prompt-input/core/type-guards.js.map +1 -0
  137. package/prompt-input/index.d.ts +1 -1
  138. package/prompt-input/index.d.ts.map +1 -1
  139. package/prompt-input/index.js.map +1 -1
  140. package/prompt-input/interfaces.d.ts +356 -7
  141. package/prompt-input/interfaces.d.ts.map +1 -1
  142. package/prompt-input/interfaces.js.map +1 -1
  143. package/prompt-input/internal.d.ts +1 -1
  144. package/prompt-input/internal.d.ts.map +1 -1
  145. package/prompt-input/internal.js +195 -61
  146. package/prompt-input/internal.js.map +1 -1
  147. package/prompt-input/styles.css.js +26 -17
  148. package/prompt-input/styles.scoped.css +152 -39
  149. package/prompt-input/styles.selectors.js +26 -17
  150. package/prompt-input/test-classes/styles.css.js +7 -6
  151. package/prompt-input/test-classes/styles.scoped.css +10 -6
  152. package/prompt-input/test-classes/styles.selectors.js +7 -6
  153. package/prompt-input/tokens/use-shortcuts.d.ts +37 -0
  154. package/prompt-input/tokens/use-shortcuts.d.ts.map +1 -0
  155. package/prompt-input/tokens/use-shortcuts.js +89 -0
  156. package/prompt-input/tokens/use-shortcuts.js.map +1 -0
  157. package/prompt-input/tokens/use-token-mode.d.ts +78 -0
  158. package/prompt-input/tokens/use-token-mode.d.ts.map +1 -0
  159. package/prompt-input/tokens/use-token-mode.js +817 -0
  160. package/prompt-input/tokens/use-token-mode.js.map +1 -0
  161. package/prompt-input/utils/insert-text-content-editable.d.ts +10 -0
  162. package/prompt-input/utils/insert-text-content-editable.d.ts.map +1 -0
  163. package/prompt-input/utils/insert-text-content-editable.js +133 -0
  164. package/prompt-input/utils/insert-text-content-editable.js.map +1 -0
  165. package/tabs/styles.css.js +30 -30
  166. package/tabs/styles.scoped.css +55 -55
  167. package/tabs/styles.selectors.js +30 -30
  168. package/test-utils/dom/hotspot/index.js +1 -2
  169. package/test-utils/dom/hotspot/index.js.map +1 -1
  170. package/test-utils/dom/prompt-input/index.d.ts +53 -1
  171. package/test-utils/dom/prompt-input/index.js +121 -13
  172. package/test-utils/dom/prompt-input/index.js.map +1 -1
  173. package/test-utils/dom/s3-resource-selector/index.js +2 -3
  174. package/test-utils/dom/s3-resource-selector/index.js.map +1 -1
  175. package/test-utils/selectors/hotspot/index.js +1 -2
  176. package/test-utils/selectors/hotspot/index.js.map +1 -1
  177. package/test-utils/selectors/prompt-input/index.d.ts +30 -0
  178. package/test-utils/selectors/prompt-input/index.js +53 -7
  179. package/test-utils/selectors/prompt-input/index.js.map +1 -1
  180. package/test-utils/selectors/s3-resource-selector/index.js +2 -3
  181. package/test-utils/selectors/s3-resource-selector/index.js.map +1 -1
@@ -0,0 +1,252 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { isHTMLElement } from '../../internal/utils/dom';
4
+ import { getOwnerSelection } from './caret-controller';
5
+ import { ElementType, SPECIAL_CHARS } from './constants';
6
+ import { isBRElement, isTextNode } from './type-guards';
7
+ import styles from '../styles.css.js';
8
+ /** Reads the data-type attribute from an element and returns it as a typed ElementType. */
9
+ export function getTokenType(element) {
10
+ const value = element.getAttribute('data-type');
11
+ switch (value) {
12
+ case ElementType.Reference:
13
+ case ElementType.Pinned:
14
+ case ElementType.CaretSpotBefore:
15
+ case ElementType.CaretSpotAfter:
16
+ case ElementType.Trigger:
17
+ case ElementType.TrailingBreak:
18
+ return value;
19
+ default:
20
+ return null;
21
+ }
22
+ }
23
+ /** Checks if a token type represents a reference element (inline or pinned). */
24
+ export function isReferenceElementType(tokenType) {
25
+ return tokenType === ElementType.Reference || tokenType === ElementType.Pinned;
26
+ }
27
+ /** Inserts a node immediately after a reference node in the DOM. */
28
+ export function insertAfter(newNode, referenceNode) {
29
+ const parent = referenceNode.parentNode;
30
+ if (!parent) {
31
+ return;
32
+ }
33
+ if (referenceNode.nextSibling) {
34
+ parent.insertBefore(newNode, referenceNode.nextSibling);
35
+ }
36
+ else {
37
+ parent.appendChild(newNode);
38
+ }
39
+ }
40
+ /** Creates a styled paragraph element for the contentEditable container. */
41
+ export function createParagraph(ownerDoc = document) {
42
+ const p = ownerDoc.createElement('p');
43
+ p.className = styles.paragraph;
44
+ return p;
45
+ }
46
+ /** Creates a trailing BR element used as a placeholder in empty paragraphs. */
47
+ export function createTrailingBreak(ownerDoc = document) {
48
+ const br = ownerDoc.createElement('br');
49
+ br.setAttribute('data-id', ElementType.TrailingBreak);
50
+ return br;
51
+ }
52
+ let idCounter = 0;
53
+ /**
54
+ * Generates a unique ID for DOM elements outside of React context.
55
+ * Uses the same format as component-toolkit's useRandomId hook, but as a plain
56
+ * function since token IDs are generated during DOM manipulation (not in React renders).
57
+ */
58
+ export function generateTokenId() {
59
+ return `${idCounter++}-${Date.now()}-${Math.round(Math.random() * 10000)}`;
60
+ }
61
+ /** Strips zero-width characters used for cursor positioning. */
62
+ export function stripZeroWidthCharacters(text) {
63
+ return text.replace(new RegExp(SPECIAL_CHARS.ZERO_WIDTH_CHARACTER, 'g'), '');
64
+ }
65
+ function buildTokenSelector(options) {
66
+ const { tokenType = [], tokenId } = options;
67
+ const types = Array.isArray(tokenType) ? tokenType : [tokenType];
68
+ let selector = types.length > 0 ? types.map(type => `[data-type="${type}"]`).join(', ') : '';
69
+ if (tokenId) {
70
+ selector += `[data-id="${tokenId}"]`;
71
+ }
72
+ return selector;
73
+ }
74
+ /** Finds the first element matching the given token type and/or token ID within a container. */
75
+ export function findElement(container, options) {
76
+ const selector = buildTokenSelector(options);
77
+ return selector ? container.querySelector(selector) : null;
78
+ }
79
+ /** Returns all paragraph elements within a container. */
80
+ export function findAllParagraphs(container) {
81
+ return Array.from(container.querySelectorAll('p'));
82
+ }
83
+ /** Checks if an element has no meaningful content (ignoring whitespace and trailing BRs). */
84
+ export function isElementEffectivelyEmpty(element) {
85
+ if (element.childNodes.length === 0) {
86
+ return true;
87
+ }
88
+ for (const child of Array.from(element.childNodes)) {
89
+ if (isTextNode(child)) {
90
+ if (child.textContent && child.textContent.trim() !== '') {
91
+ return false;
92
+ }
93
+ }
94
+ else if (isBRElement(child)) {
95
+ continue;
96
+ }
97
+ else {
98
+ return false;
99
+ }
100
+ }
101
+ return true;
102
+ }
103
+ export function hasOnlyTrailingBR(paragraph) {
104
+ return paragraph.childNodes.length === 1 && isBRElement(paragraph.firstChild);
105
+ }
106
+ export function isEmptyState(element) {
107
+ const paragraphs = findAllParagraphs(element);
108
+ return paragraphs.length === 0 || (paragraphs.length === 1 && hasOnlyTrailingBR(paragraphs[0]));
109
+ }
110
+ /** Resets the element to a single empty paragraph with a trailing BR. */
111
+ export function setEmptyState(element) {
112
+ const paragraphs = findAllParagraphs(element);
113
+ if (paragraphs.length === 1 && hasOnlyTrailingBR(paragraphs[0])) {
114
+ return;
115
+ }
116
+ element.textContent = '';
117
+ const p = createParagraph();
118
+ p.appendChild(createTrailingBreak());
119
+ element.appendChild(p);
120
+ }
121
+ /** Checks if a token type represents a caret spot element. */
122
+ export function isCaretSpotType(tokenType) {
123
+ return tokenType === ElementType.CaretSpotBefore || tokenType === ElementType.CaretSpotAfter;
124
+ }
125
+ /**
126
+ * Finds the adjacent sibling node in the given direction and checks if it's a reference token.
127
+ * @param container the node where the cursor currently sits
128
+ * @param offset cursor offset within the container
129
+ * @param direction which direction to look
130
+ */
131
+ export function findAdjacentToken(container, offset, direction) {
132
+ var _a;
133
+ let sibling = null;
134
+ if (isTextNode(container)) {
135
+ const isAtBoundary = direction === 'backward' ? offset === 0 : offset === (((_a = container.textContent) === null || _a === void 0 ? void 0 : _a.length) || 0);
136
+ if (isAtBoundary) {
137
+ sibling = direction === 'backward' ? container.previousSibling : container.nextSibling;
138
+ }
139
+ }
140
+ else if (isHTMLElement(container)) {
141
+ if (direction === 'backward') {
142
+ sibling = offset > 0 ? container.childNodes[offset - 1] : container.previousSibling;
143
+ }
144
+ else {
145
+ sibling = offset < container.childNodes.length ? container.childNodes[offset] : container.nextSibling;
146
+ }
147
+ }
148
+ const siblingType = isHTMLElement(sibling) ? getTokenType(sibling) : null;
149
+ const isReferenceToken = isReferenceElementType(siblingType);
150
+ return { sibling, isReferenceToken };
151
+ }
152
+ /**
153
+ * When the caret lands immediately after a trigger element (e.g. at offset 0 of the
154
+ * next text node, or at the paragraph-level offset right after the trigger), nudge it
155
+ * inside the trigger's text node so that `findActiveTrigger` detects it correctly.
156
+ * @param cancelledIds Set of trigger IDs that are cancelled — caret won't be nudged into these.
157
+ */
158
+ export function normalizeCaretIntoTrigger(editableElement, cancelledIds) {
159
+ var _a, _b;
160
+ const selection = getOwnerSelection(editableElement);
161
+ if (!(selection === null || selection === void 0 ? void 0 : selection.rangeCount)) {
162
+ return;
163
+ }
164
+ const range = selection.getRangeAt(0);
165
+ if (!range.collapsed) {
166
+ return;
167
+ }
168
+ let triggerElement = null;
169
+ if (isTextNode(range.startContainer) && range.startOffset === 0) {
170
+ const prevSibling = range.startContainer.previousSibling;
171
+ if (isHTMLElement(prevSibling) && getTokenType(prevSibling) === ElementType.Trigger) {
172
+ // Only nudge when the text node is empty — a non-empty node means the
173
+ // cursor is legitimately positioned at the start of user text.
174
+ if (!range.startContainer.textContent) {
175
+ triggerElement = prevSibling;
176
+ }
177
+ }
178
+ // Caret at offset 0 inside a trigger's own text node means the cursor is
179
+ // right before the trigger symbol. Nudge it to the end of whatever precedes
180
+ // this trigger — either the previous trigger or a text node boundary.
181
+ const parent = range.startContainer.parentElement;
182
+ if (!triggerElement && parent && getTokenType(parent) === ElementType.Trigger) {
183
+ const paragraph = parent.parentElement;
184
+ if (paragraph) {
185
+ const idx = Array.from(paragraph.childNodes).indexOf(parent);
186
+ if (idx > 0) {
187
+ range.setStart(paragraph, idx);
188
+ range.collapse(true);
189
+ }
190
+ }
191
+ return;
192
+ }
193
+ }
194
+ else if (range.startContainer === editableElement || isHTMLElement(range.startContainer)) {
195
+ const container = range.startContainer;
196
+ const childNodes = Array.from(container.childNodes);
197
+ const nodeBeforeCaret = childNodes[range.startOffset - 1];
198
+ if (isHTMLElement(nodeBeforeCaret) && getTokenType(nodeBeforeCaret) === ElementType.Trigger) {
199
+ triggerElement = nodeBeforeCaret;
200
+ }
201
+ }
202
+ if (triggerElement && !(cancelledIds === null || cancelledIds === void 0 ? void 0 : cancelledIds.has(triggerElement.id))) {
203
+ const triggerTextNode = triggerElement.childNodes[0];
204
+ if (isTextNode(triggerTextNode)) {
205
+ range.setStart(triggerTextNode, (_b = (_a = triggerTextNode.textContent) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0);
206
+ range.collapse(true);
207
+ }
208
+ }
209
+ }
210
+ /**
211
+ * Scrolls the caret into view within a scrollable contentEditable element.
212
+ * Inserts a temporary span at the selection to measure position, scrolls if
213
+ * needed, then removes the span.
214
+ */
215
+ export function scrollCaretIntoView(element) {
216
+ var _a, _b, _c, _d, _e;
217
+ if (element.scrollHeight <= element.clientHeight) {
218
+ return;
219
+ }
220
+ const selection = getOwnerSelection(element);
221
+ if (!(selection === null || selection === void 0 ? void 0 : selection.rangeCount)) {
222
+ return;
223
+ }
224
+ const ownerDoc = (_a = element.ownerDocument) !== null && _a !== void 0 ? _a : document;
225
+ const range = selection.getRangeAt(0);
226
+ const tempSpan = ownerDoc.createElement('span');
227
+ range.insertNode(tempSpan);
228
+ const spanRect = tempSpan.getBoundingClientRect();
229
+ const elementRect = element.getBoundingClientRect();
230
+ const isOutOfView = spanRect.top < elementRect.top ||
231
+ spanRect.bottom > elementRect.bottom ||
232
+ spanRect.left < elementRect.left ||
233
+ spanRect.right > elementRect.right;
234
+ if (isOutOfView) {
235
+ tempSpan.scrollIntoView({ block: 'nearest', inline: 'nearest' });
236
+ }
237
+ // Remove the span and merge the split text nodes back together.
238
+ // insertNode splits a text node into [before, span, after]. After removing
239
+ // the span, merge "after" into "before" to restore the original text node.
240
+ const prev = tempSpan.previousSibling;
241
+ const next = tempSpan.nextSibling;
242
+ tempSpan.remove();
243
+ if (prev && next && prev.nodeType === Node.TEXT_NODE && next.nodeType === Node.TEXT_NODE) {
244
+ const mergeOffset = (_c = (_b = prev.textContent) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0;
245
+ prev.textContent = ((_d = prev.textContent) !== null && _d !== void 0 ? _d : '') + ((_e = next.textContent) !== null && _e !== void 0 ? _e : '');
246
+ next.remove();
247
+ // Place the caret at the merge point
248
+ range.setStart(prev, mergeOffset);
249
+ range.collapse(true);
250
+ }
251
+ }
252
+ //# sourceMappingURL=dom-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom-utils.js","sourceRoot":"","sources":["../../../../src/prompt-input/core/dom-utils.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,sCAAsC;AAEtC,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAExD,OAAO,MAAM,MAAM,kBAAkB,CAAC;AAEtC,2FAA2F;AAC3F,MAAM,UAAU,YAAY,CAAC,OAAoB;IAC/C,MAAM,KAAK,GAAG,OAAO,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;IAChD,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,WAAW,CAAC,SAAS,CAAC;QAC3B,KAAK,WAAW,CAAC,MAAM,CAAC;QACxB,KAAK,WAAW,CAAC,eAAe,CAAC;QACjC,KAAK,WAAW,CAAC,cAAc,CAAC;QAChC,KAAK,WAAW,CAAC,OAAO,CAAC;QACzB,KAAK,WAAW,CAAC,aAAa;YAC5B,OAAO,KAAK,CAAC;QACf;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC;AACD,gFAAgF;AAChF,MAAM,UAAU,sBAAsB,CAAC,SAAsC;IAC3E,OAAO,SAAS,KAAK,WAAW,CAAC,SAAS,IAAI,SAAS,KAAK,WAAW,CAAC,MAAM,CAAC;AACjF,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,WAAW,CAAC,OAAa,EAAE,aAAmB;IAC5D,MAAM,MAAM,GAAG,aAAa,CAAC,UAAU,CAAC;IACxC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO;IACT,CAAC;IAED,IAAI,aAAa,CAAC,WAAW,EAAE,CAAC;QAC9B,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IAC1D,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;AACH,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,eAAe,CAAC,WAAqB,QAAQ;IAC3D,MAAM,CAAC,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;IACtC,CAAC,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;IAC/B,OAAO,CAAC,CAAC;AACX,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,mBAAmB,CAAC,WAAqB,QAAQ;IAC/D,MAAM,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IACxC,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,WAAW,CAAC,aAAa,CAAC,CAAC;IACtD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,IAAI,SAAS,GAAG,CAAC,CAAC;AAElB;;;;GAIG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO,GAAG,SAAS,EAAE,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,EAAE,CAAC;AAC7E,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,wBAAwB,CAAC,IAAY;IACnD,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,aAAa,CAAC,oBAAoB,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;AAC/E,CAAC;AAOD,SAAS,kBAAkB,CAAC,OAA0B;IACpD,MAAM,EAAE,SAAS,GAAG,EAAE,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IAC5C,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAEjE,IAAI,QAAQ,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,eAAe,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE7F,IAAI,OAAO,EAAE,CAAC;QACZ,QAAQ,IAAI,aAAa,OAAO,IAAI,CAAC;IACvC,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,WAAW,CAAC,SAAsB,EAAE,OAA0B;IAC5E,MAAM,QAAQ,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC7C,OAAO,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,aAAa,CAAc,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1E,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,iBAAiB,CAAC,SAAyC;IACzE,OAAO,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAuB,GAAG,CAAC,CAAC,CAAC;AAC3E,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,yBAAyB,CAAC,OAAoB;IAC5D,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QACnD,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YACtB,IAAI,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;gBACzD,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;aAAM,IAAI,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,SAAS;QACX,CAAC;aAAM,CAAC;YACN,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,SAAsB;IACtD,OAAO,SAAS,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,IAAI,WAAW,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;AAChF,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAoB;IAC/C,MAAM,UAAU,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC9C,OAAO,UAAU,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,IAAI,iBAAiB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClG,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,aAAa,CAAC,OAAoB;IAChD,MAAM,UAAU,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAE9C,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,IAAI,iBAAiB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,OAAO;IACT,CAAC;IAED,OAAO,CAAC,WAAW,GAAG,EAAE,CAAC;IACzB,MAAM,CAAC,GAAG,eAAe,EAAE,CAAC;IAC5B,CAAC,CAAC,WAAW,CAAC,mBAAmB,EAAE,CAAC,CAAC;IACrC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AACzB,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,eAAe,CAAC,SAAsC;IACpE,OAAO,SAAS,KAAK,WAAW,CAAC,eAAe,IAAI,SAAS,KAAK,WAAW,CAAC,cAAc,CAAC;AAC/F,CAAC;AAOD;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAC/B,SAAe,EACf,MAAc,EACd,SAAiC;;IAEjC,IAAI,OAAO,GAAgB,IAAI,CAAC;IAEhC,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1B,MAAM,YAAY,GAAG,SAAS,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAA,MAAA,SAAS,CAAC,WAAW,0CAAE,MAAM,KAAI,CAAC,CAAC,CAAC;QAE/G,IAAI,YAAY,EAAE,CAAC;YACjB,OAAO,GAAG,SAAS,KAAK,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC;QACzF,CAAC;IACH,CAAC;SAAM,IAAI,aAAa,CAAC,SAAS,CAAC,EAAE,CAAC;QACpC,IAAI,SAAS,KAAK,UAAU,EAAE,CAAC;YAC7B,OAAO,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC;QACtF,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC;QACxG,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1E,MAAM,gBAAgB,GAAG,sBAAsB,CAAC,WAAW,CAAC,CAAC;IAE7D,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC;AACvC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB,CAAC,eAA4B,EAAE,YAA0B;;IAChG,MAAM,SAAS,GAAG,iBAAiB,CAAC,eAAe,CAAC,CAAC;IACrD,IAAI,CAAC,CAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,UAAU,CAAA,EAAE,CAAC;QAC3B,OAAO;IACT,CAAC;IAED,MAAM,KAAK,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IACtC,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;QACrB,OAAO;IACT,CAAC;IAED,IAAI,cAAc,GAAuB,IAAI,CAAC;IAE9C,IAAI,UAAU,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,KAAK,CAAC,WAAW,KAAK,CAAC,EAAE,CAAC;QAChE,MAAM,WAAW,GAAG,KAAK,CAAC,cAAc,CAAC,eAAe,CAAC;QACzD,IAAI,aAAa,CAAC,WAAW,CAAC,IAAI,YAAY,CAAC,WAAW,CAAC,KAAK,WAAW,CAAC,OAAO,EAAE,CAAC;YACpF,sEAAsE;YACtE,+DAA+D;YAC/D,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC;gBACtC,cAAc,GAAG,WAAW,CAAC;YAC/B,CAAC;QACH,CAAC;QAED,yEAAyE;QACzE,4EAA4E;QAC5E,sEAAsE;QACtE,MAAM,MAAM,GAAG,KAAK,CAAC,cAAc,CAAC,aAAa,CAAC;QAClD,IAAI,CAAC,cAAc,IAAI,MAAM,IAAI,YAAY,CAAC,MAAM,CAAC,KAAK,WAAW,CAAC,OAAO,EAAE,CAAC;YAC9E,MAAM,SAAS,GAAG,MAAM,CAAC,aAAa,CAAC;YACvC,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;gBAC7D,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;oBACZ,KAAK,CAAC,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;oBAC/B,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;gBACvB,CAAC;YACH,CAAC;YACD,OAAO;QACT,CAAC;IACH,CAAC;SAAM,IAAI,KAAK,CAAC,cAAc,KAAK,eAAe,IAAI,aAAa,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC;QAC3F,MAAM,SAAS,GAAG,KAAK,CAAC,cAA6B,CAAC;QACtD,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACpD,MAAM,eAAe,GAAG,UAAU,CAAC,KAAK,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC;QAE1D,IAAI,aAAa,CAAC,eAAe,CAAC,IAAI,YAAY,CAAC,eAAe,CAAC,KAAK,WAAW,CAAC,OAAO,EAAE,CAAC;YAC5F,cAAc,GAAG,eAAe,CAAC;QACnC,CAAC;IACH,CAAC;IAED,IAAI,cAAc,IAAI,CAAC,CAAA,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAE,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC,CAAA,EAAE,CAAC;QAC5D,MAAM,eAAe,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACrD,IAAI,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;YAChC,KAAK,CAAC,QAAQ,CAAC,eAAe,EAAE,MAAA,MAAA,eAAe,CAAC,WAAW,0CAAE,MAAM,mCAAI,CAAC,CAAC,CAAC;YAC1E,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAoB;;IACtD,IAAI,OAAO,CAAC,YAAY,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;QACjD,OAAO;IACT,CAAC;IAED,MAAM,SAAS,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC7C,IAAI,CAAC,CAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,UAAU,CAAA,EAAE,CAAC;QAC3B,OAAO;IACT,CAAC;IAED,MAAM,QAAQ,GAAG,MAAA,OAAO,CAAC,aAAa,mCAAI,QAAQ,CAAC;IACnD,MAAM,KAAK,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAEtC,MAAM,QAAQ,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAChD,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAE3B,MAAM,QAAQ,GAAG,QAAQ,CAAC,qBAAqB,EAAE,CAAC;IAClD,MAAM,WAAW,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAEpD,MAAM,WAAW,GACf,QAAQ,CAAC,GAAG,GAAG,WAAW,CAAC,GAAG;QAC9B,QAAQ,CAAC,MAAM,GAAG,WAAW,CAAC,MAAM;QACpC,QAAQ,CAAC,IAAI,GAAG,WAAW,CAAC,IAAI;QAChC,QAAQ,CAAC,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC;IAErC,IAAI,WAAW,EAAE,CAAC;QAChB,QAAQ,CAAC,cAAc,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,gEAAgE;IAChE,2EAA2E;IAC3E,2EAA2E;IAC3E,MAAM,IAAI,GAAG,QAAQ,CAAC,eAAe,CAAC;IACtC,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,CAAC;IAElB,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,SAAS,EAAE,CAAC;QACzF,MAAM,WAAW,GAAG,MAAA,MAAA,IAAI,CAAC,WAAW,0CAAE,MAAM,mCAAI,CAAC,CAAC;QAClD,IAAI,CAAC,WAAW,GAAG,CAAC,MAAA,IAAI,CAAC,WAAW,mCAAI,EAAE,CAAC,GAAG,CAAC,MAAA,IAAI,CAAC,WAAW,mCAAI,EAAE,CAAC,CAAC;QACvE,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,qCAAqC;QACrC,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QAClC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;AACH,CAAC","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { isHTMLElement } from '../../internal/utils/dom';\nimport { getOwnerSelection } from './caret-controller';\nimport { ElementType, SPECIAL_CHARS } from './constants';\nimport { isBRElement, isTextNode } from './type-guards';\n\nimport styles from '../styles.css.js';\n\n/** Reads the data-type attribute from an element and returns it as a typed ElementType. */\nexport function getTokenType(element: HTMLElement): ElementType | null {\n const value = element.getAttribute('data-type');\n switch (value) {\n case ElementType.Reference:\n case ElementType.Pinned:\n case ElementType.CaretSpotBefore:\n case ElementType.CaretSpotAfter:\n case ElementType.Trigger:\n case ElementType.TrailingBreak:\n return value;\n default:\n return null;\n }\n}\n/** Checks if a token type represents a reference element (inline or pinned). */\nexport function isReferenceElementType(tokenType: ElementType | string | null): boolean {\n return tokenType === ElementType.Reference || tokenType === ElementType.Pinned;\n}\n\n/** Inserts a node immediately after a reference node in the DOM. */\nexport function insertAfter(newNode: Node, referenceNode: Node): void {\n const parent = referenceNode.parentNode;\n if (!parent) {\n return;\n }\n\n if (referenceNode.nextSibling) {\n parent.insertBefore(newNode, referenceNode.nextSibling);\n } else {\n parent.appendChild(newNode);\n }\n}\n\n/** Creates a styled paragraph element for the contentEditable container. */\nexport function createParagraph(ownerDoc: Document = document): HTMLParagraphElement {\n const p = ownerDoc.createElement('p');\n p.className = styles.paragraph;\n return p;\n}\n\n/** Creates a trailing BR element used as a placeholder in empty paragraphs. */\nexport function createTrailingBreak(ownerDoc: Document = document): HTMLBRElement {\n const br = ownerDoc.createElement('br');\n br.setAttribute('data-id', ElementType.TrailingBreak);\n return br;\n}\n\nlet idCounter = 0;\n\n/**\n * Generates a unique ID for DOM elements outside of React context.\n * Uses the same format as component-toolkit's useRandomId hook, but as a plain\n * function since token IDs are generated during DOM manipulation (not in React renders).\n */\nexport function generateTokenId(): string {\n return `${idCounter++}-${Date.now()}-${Math.round(Math.random() * 10000)}`;\n}\n\n/** Strips zero-width characters used for cursor positioning. */\nexport function stripZeroWidthCharacters(text: string): string {\n return text.replace(new RegExp(SPECIAL_CHARS.ZERO_WIDTH_CHARACTER, 'g'), '');\n}\n\ninterface TokenQueryOptions {\n tokenType?: string | string[];\n tokenId?: string;\n}\n\nfunction buildTokenSelector(options: TokenQueryOptions): string {\n const { tokenType = [], tokenId } = options;\n const types = Array.isArray(tokenType) ? tokenType : [tokenType];\n\n let selector = types.length > 0 ? types.map(type => `[data-type=\"${type}\"]`).join(', ') : '';\n\n if (tokenId) {\n selector += `[data-id=\"${tokenId}\"]`;\n }\n\n return selector;\n}\n\n/** Finds the first element matching the given token type and/or token ID within a container. */\nexport function findElement(container: HTMLElement, options: TokenQueryOptions): HTMLElement | null {\n const selector = buildTokenSelector(options);\n return selector ? container.querySelector<HTMLElement>(selector) : null;\n}\n\n/** Returns all paragraph elements within a container. */\nexport function findAllParagraphs(container: HTMLElement | DocumentFragment): HTMLParagraphElement[] {\n return Array.from(container.querySelectorAll<HTMLParagraphElement>('p'));\n}\n\n/** Checks if an element has no meaningful content (ignoring whitespace and trailing BRs). */\nexport function isElementEffectivelyEmpty(element: HTMLElement): boolean {\n if (element.childNodes.length === 0) {\n return true;\n }\n\n for (const child of Array.from(element.childNodes)) {\n if (isTextNode(child)) {\n if (child.textContent && child.textContent.trim() !== '') {\n return false;\n }\n } else if (isBRElement(child)) {\n continue;\n } else {\n return false;\n }\n }\n return true;\n}\n\nexport function hasOnlyTrailingBR(paragraph: HTMLElement): boolean {\n return paragraph.childNodes.length === 1 && isBRElement(paragraph.firstChild);\n}\n\nexport function isEmptyState(element: HTMLElement): boolean {\n const paragraphs = findAllParagraphs(element);\n return paragraphs.length === 0 || (paragraphs.length === 1 && hasOnlyTrailingBR(paragraphs[0]));\n}\n\n/** Resets the element to a single empty paragraph with a trailing BR. */\nexport function setEmptyState(element: HTMLElement): void {\n const paragraphs = findAllParagraphs(element);\n\n if (paragraphs.length === 1 && hasOnlyTrailingBR(paragraphs[0])) {\n return;\n }\n\n element.textContent = '';\n const p = createParagraph();\n p.appendChild(createTrailingBreak());\n element.appendChild(p);\n}\n\n/** Checks if a token type represents a caret spot element. */\nexport function isCaretSpotType(tokenType: ElementType | string | null): boolean {\n return tokenType === ElementType.CaretSpotBefore || tokenType === ElementType.CaretSpotAfter;\n}\n\nexport interface AdjacentTokenResult {\n sibling: Node | null;\n isReferenceToken: boolean;\n}\n\n/**\n * Finds the adjacent sibling node in the given direction and checks if it's a reference token.\n * @param container the node where the cursor currently sits\n * @param offset cursor offset within the container\n * @param direction which direction to look\n */\nexport function findAdjacentToken(\n container: Node,\n offset: number,\n direction: 'backward' | 'forward'\n): AdjacentTokenResult {\n let sibling: Node | null = null;\n\n if (isTextNode(container)) {\n const isAtBoundary = direction === 'backward' ? offset === 0 : offset === (container.textContent?.length || 0);\n\n if (isAtBoundary) {\n sibling = direction === 'backward' ? container.previousSibling : container.nextSibling;\n }\n } else if (isHTMLElement(container)) {\n if (direction === 'backward') {\n sibling = offset > 0 ? container.childNodes[offset - 1] : container.previousSibling;\n } else {\n sibling = offset < container.childNodes.length ? container.childNodes[offset] : container.nextSibling;\n }\n }\n\n const siblingType = isHTMLElement(sibling) ? getTokenType(sibling) : null;\n const isReferenceToken = isReferenceElementType(siblingType);\n\n return { sibling, isReferenceToken };\n}\n\n/**\n * When the caret lands immediately after a trigger element (e.g. at offset 0 of the\n * next text node, or at the paragraph-level offset right after the trigger), nudge it\n * inside the trigger's text node so that `findActiveTrigger` detects it correctly.\n * @param cancelledIds Set of trigger IDs that are cancelled — caret won't be nudged into these.\n */\nexport function normalizeCaretIntoTrigger(editableElement: HTMLElement, cancelledIds?: Set<string>): void {\n const selection = getOwnerSelection(editableElement);\n if (!selection?.rangeCount) {\n return;\n }\n\n const range = selection.getRangeAt(0);\n if (!range.collapsed) {\n return;\n }\n\n let triggerElement: HTMLElement | null = null;\n\n if (isTextNode(range.startContainer) && range.startOffset === 0) {\n const prevSibling = range.startContainer.previousSibling;\n if (isHTMLElement(prevSibling) && getTokenType(prevSibling) === ElementType.Trigger) {\n // Only nudge when the text node is empty — a non-empty node means the\n // cursor is legitimately positioned at the start of user text.\n if (!range.startContainer.textContent) {\n triggerElement = prevSibling;\n }\n }\n\n // Caret at offset 0 inside a trigger's own text node means the cursor is\n // right before the trigger symbol. Nudge it to the end of whatever precedes\n // this trigger — either the previous trigger or a text node boundary.\n const parent = range.startContainer.parentElement;\n if (!triggerElement && parent && getTokenType(parent) === ElementType.Trigger) {\n const paragraph = parent.parentElement;\n if (paragraph) {\n const idx = Array.from(paragraph.childNodes).indexOf(parent);\n if (idx > 0) {\n range.setStart(paragraph, idx);\n range.collapse(true);\n }\n }\n return;\n }\n } else if (range.startContainer === editableElement || isHTMLElement(range.startContainer)) {\n const container = range.startContainer as HTMLElement;\n const childNodes = Array.from(container.childNodes);\n const nodeBeforeCaret = childNodes[range.startOffset - 1];\n\n if (isHTMLElement(nodeBeforeCaret) && getTokenType(nodeBeforeCaret) === ElementType.Trigger) {\n triggerElement = nodeBeforeCaret;\n }\n }\n\n if (triggerElement && !cancelledIds?.has(triggerElement.id)) {\n const triggerTextNode = triggerElement.childNodes[0];\n if (isTextNode(triggerTextNode)) {\n range.setStart(triggerTextNode, triggerTextNode.textContent?.length ?? 0);\n range.collapse(true);\n }\n }\n}\n\n/**\n * Scrolls the caret into view within a scrollable contentEditable element.\n * Inserts a temporary span at the selection to measure position, scrolls if\n * needed, then removes the span.\n */\nexport function scrollCaretIntoView(element: HTMLElement): void {\n if (element.scrollHeight <= element.clientHeight) {\n return;\n }\n\n const selection = getOwnerSelection(element);\n if (!selection?.rangeCount) {\n return;\n }\n\n const ownerDoc = element.ownerDocument ?? document;\n const range = selection.getRangeAt(0);\n\n const tempSpan = ownerDoc.createElement('span');\n range.insertNode(tempSpan);\n\n const spanRect = tempSpan.getBoundingClientRect();\n const elementRect = element.getBoundingClientRect();\n\n const isOutOfView =\n spanRect.top < elementRect.top ||\n spanRect.bottom > elementRect.bottom ||\n spanRect.left < elementRect.left ||\n spanRect.right > elementRect.right;\n\n if (isOutOfView) {\n tempSpan.scrollIntoView({ block: 'nearest', inline: 'nearest' });\n }\n\n // Remove the span and merge the split text nodes back together.\n // insertNode splits a text node into [before, span, after]. After removing\n // the span, merge \"after\" into \"before\" to restore the original text node.\n const prev = tempSpan.previousSibling;\n const next = tempSpan.nextSibling;\n tempSpan.remove();\n\n if (prev && next && prev.nodeType === Node.TEXT_NODE && next.nodeType === Node.TEXT_NODE) {\n const mergeOffset = prev.textContent?.length ?? 0;\n prev.textContent = (prev.textContent ?? '') + (next.textContent ?? '');\n next.remove();\n // Place the caret at the merge point\n range.setStart(prev, mergeOffset);\n range.collapse(true);\n }\n}\n"]}
@@ -0,0 +1,68 @@
1
+ import { PromptInputProps } from '../interfaces';
2
+ import { EditableState } from '../tokens/use-token-mode';
3
+ import { CaretController } from './caret-controller';
4
+ import { MenuItemsHandlers, MenuItemsState } from './menu-state';
5
+ /** Configuration for the unified keyboard event handler. */
6
+ export interface KeyboardHandlerProps {
7
+ editableElement: HTMLDivElement | null;
8
+ editableState: EditableState;
9
+ caretController: CaretController | null;
10
+ tokens?: readonly PromptInputProps.InputToken[];
11
+ tokensToText?: (tokens: readonly PromptInputProps.InputToken[]) => string;
12
+ disabled?: boolean;
13
+ readOnly?: boolean;
14
+ i18nStrings?: PromptInputProps.I18nStrings;
15
+ announceTokenOperation?: (message: string) => void;
16
+ getMenuOpen: () => boolean;
17
+ getMenuItemsState: () => MenuItemsState | null;
18
+ getMenuItemsHandlers: () => MenuItemsHandlers | null;
19
+ getMenuStatusType?: () => PromptInputProps.MenuDefinition['statusType'];
20
+ closeMenu: () => void;
21
+ onAction?: (detail: PromptInputProps.ActionDetail) => void;
22
+ onChange: (detail: {
23
+ value: string;
24
+ tokens: PromptInputProps.InputToken[];
25
+ }) => void;
26
+ markTokensAsSent: (tokens: readonly PromptInputProps.InputToken[]) => void;
27
+ onKeyDown?: PromptInputProps['onKeyDown'];
28
+ }
29
+ /** Handles all keyboard events for the editable element. */
30
+ export declare function handleEditableKeyDown(event: React.KeyboardEvent<HTMLDivElement>, props: KeyboardHandlerProps): void;
31
+ /** Splits the current paragraph at the caret position, creating a new paragraph below. */
32
+ export declare function splitParagraphAtCaret(editableElement: HTMLDivElement, caretController: CaretController | null, suppressInputEvent?: boolean): void;
33
+ /** Handles Backspace/Delete when adjacent to a reference token. Returns true if handled. */
34
+ export declare function handleReferenceTokenDeletion(event: React.KeyboardEvent<HTMLDivElement>, isBackspace: boolean, editableElement: HTMLDivElement, state: EditableState, announceTokenOperation: ((message: string) => void) | undefined, i18nStrings: PromptInputProps.I18nStrings | undefined, caretController: CaretController | null, tokens?: readonly PromptInputProps.InputToken[], emitChange?: (newTokens: PromptInputProps.InputToken[], caretPosition: number) => void): boolean;
35
+ /** Handles inline-start (backward) arrow key — plain navigation or shift+selection across references. */
36
+ export declare function handleInlineStart(event: React.KeyboardEvent<HTMLDivElement>, caretController: CaretController | null, announceTokenOperation?: (message: string) => void): void;
37
+ /** Handles inline-end (forward) arrow key — plain navigation or shift+selection across references. */
38
+ export declare function handleInlineEnd(event: React.KeyboardEvent<HTMLDivElement>, caretController: CaretController | null, announceTokenOperation?: (message: string) => void): void;
39
+ /** Handles space key after a closed trigger element, inserting the space outside the trigger. */
40
+ export declare function handleSpaceAfterClosedTrigger(event: React.KeyboardEvent<HTMLDivElement>, editableElement: HTMLDivElement, menuOpen: boolean, caretController: CaretController | null): boolean;
41
+ export type MergeDirection = 'forward' | 'backward';
42
+ interface MergeParagraphsParams {
43
+ direction: MergeDirection;
44
+ editableElement: HTMLDivElement;
45
+ tokens: readonly PromptInputProps.InputToken[];
46
+ currentParagraphIndex: number;
47
+ tokensToText?: (tokens: readonly PromptInputProps.InputToken[]) => string;
48
+ onChange: (detail: {
49
+ value: string;
50
+ tokens: PromptInputProps.InputToken[];
51
+ }) => void;
52
+ caretController?: CaretController | null;
53
+ }
54
+ /** Merges two adjacent paragraphs by removing the break token between them. */
55
+ export declare function mergeParagraphs(params: MergeParagraphsParams): boolean;
56
+ /** Handles Backspace at the start of a paragraph by merging with the previous one. */
57
+ export declare function handleBackspaceAtParagraphStart(event: React.KeyboardEvent<HTMLDivElement>, editableElement: HTMLDivElement, tokens: readonly PromptInputProps.InputToken[], tokensToText: ((tokens: readonly PromptInputProps.InputToken[]) => string) | undefined, onChange: (detail: {
58
+ value: string;
59
+ tokens: PromptInputProps.InputToken[];
60
+ }) => void, caretController: CaretController | null): boolean;
61
+ /** Handles Delete at the end of a paragraph by merging with the next one. */
62
+ export declare function handleDeleteAtParagraphEnd(event: React.KeyboardEvent<HTMLDivElement>, editableElement: HTMLDivElement, tokens: readonly PromptInputProps.InputToken[], tokensToText: ((tokens: readonly PromptInputProps.InputToken[]) => string) | undefined, onChange: (detail: {
63
+ value: string;
64
+ tokens: PromptInputProps.InputToken[];
65
+ }) => void, caretController: CaretController | null): boolean;
66
+ /** Handles copy/cut events on the contentEditable element. */
67
+ export declare function handleClipboardEvent(event: React.ClipboardEvent, editableElement: HTMLElement, isCut: boolean): void;
68
+ export {};
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-handlers.d.ts","sourceRoot":"","sources":["../../../../src/prompt-input/core/event-handlers.ts"],"names":[],"mappings":"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"}