@cloudscape-design/components 3.0.1269 → 3.0.1271

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 (203) hide show
  1. package/app-layout/visual-refresh-toolbar/state/use-feature-notifications.d.ts.map +1 -1
  2. package/app-layout/visual-refresh-toolbar/state/use-feature-notifications.js +13 -0
  3. package/app-layout/visual-refresh-toolbar/state/use-feature-notifications.js.map +1 -1
  4. package/app-layout/visual-refresh-toolbar/toolbar/index.js +1 -1
  5. package/app-layout/visual-refresh-toolbar/toolbar/index.js.map +1 -1
  6. package/app-layout/visual-refresh-toolbar/toolbar/trigger-button/index.d.ts +1 -1
  7. package/app-layout/visual-refresh-toolbar/toolbar/trigger-button/index.d.ts.map +1 -1
  8. package/app-layout/visual-refresh-toolbar/toolbar/trigger-button/index.js +1 -2
  9. package/app-layout/visual-refresh-toolbar/toolbar/trigger-button/index.js.map +1 -1
  10. package/app-layout/visual-refresh-toolbar/toolbar/trigger-button/styles.css.js +6 -7
  11. package/app-layout/visual-refresh-toolbar/toolbar/trigger-button/styles.scoped.css +20 -26
  12. package/app-layout/visual-refresh-toolbar/toolbar/trigger-button/styles.selectors.js +6 -7
  13. package/button/styles.css.js +22 -22
  14. package/button/styles.scoped.css +78 -78
  15. package/button/styles.selectors.js +22 -22
  16. package/date-input/internal.d.ts.map +1 -1
  17. package/date-input/internal.js +7 -5
  18. package/date-input/internal.js.map +1 -1
  19. package/help-panel/styles.css.js +6 -6
  20. package/help-panel/styles.scoped.css +70 -70
  21. package/help-panel/styles.selectors.js +6 -6
  22. package/i18n/messages/all.all.js +1 -1
  23. package/i18n/messages/all.all.json +1 -1
  24. package/i18n/messages/all.ar.js +1 -1
  25. package/i18n/messages/all.ar.json +1 -1
  26. package/i18n/messages/all.de.js +1 -1
  27. package/i18n/messages/all.de.json +1 -1
  28. package/i18n/messages/all.en-GB.js +1 -1
  29. package/i18n/messages/all.en-GB.json +1 -1
  30. package/i18n/messages/all.en.js +1 -1
  31. package/i18n/messages/all.en.json +1 -1
  32. package/i18n/messages/all.es.js +1 -1
  33. package/i18n/messages/all.es.json +1 -1
  34. package/i18n/messages/all.fr.js +1 -1
  35. package/i18n/messages/all.fr.json +1 -1
  36. package/i18n/messages/all.id.js +1 -1
  37. package/i18n/messages/all.id.json +1 -1
  38. package/i18n/messages/all.it.js +1 -1
  39. package/i18n/messages/all.it.json +1 -1
  40. package/i18n/messages/all.ja.js +1 -1
  41. package/i18n/messages/all.ja.json +1 -1
  42. package/i18n/messages/all.ko.js +1 -1
  43. package/i18n/messages/all.ko.json +1 -1
  44. package/i18n/messages/all.pt-BR.js +1 -1
  45. package/i18n/messages/all.pt-BR.json +1 -1
  46. package/i18n/messages/all.tr.js +1 -1
  47. package/i18n/messages/all.tr.json +1 -1
  48. package/i18n/messages/all.zh-CN.js +1 -1
  49. package/i18n/messages/all.zh-CN.json +1 -1
  50. package/i18n/messages/all.zh-TW.js +1 -1
  51. package/i18n/messages/all.zh-TW.json +1 -1
  52. package/i18n/messages-types.d.ts +18 -0
  53. package/i18n/messages-types.d.ts.map +1 -1
  54. package/i18n/messages-types.js.map +1 -1
  55. package/internal/base-component/styles.scoped.css +63 -4
  56. package/internal/components/token-list/styles.css.js +10 -10
  57. package/internal/components/token-list/styles.scoped.css +25 -25
  58. package/internal/components/token-list/styles.selectors.js +10 -10
  59. package/internal/context/reset-contexts-for-modal.d.ts.map +1 -1
  60. package/internal/context/reset-contexts-for-modal.js +3 -1
  61. package/internal/context/reset-contexts-for-modal.js.map +1 -1
  62. package/internal/context/token-inline-context.d.ts +6 -0
  63. package/internal/context/token-inline-context.d.ts.map +1 -0
  64. package/internal/context/token-inline-context.js +11 -0
  65. package/internal/context/token-inline-context.js.map +1 -0
  66. package/internal/environment.js +2 -2
  67. package/internal/environment.json +2 -2
  68. package/internal/generated/styles/tokens.d.ts +17 -3
  69. package/internal/generated/styles/tokens.js +17 -3
  70. package/internal/generated/theming/index.cjs +417 -9
  71. package/internal/generated/theming/index.cjs.d.ts +189 -0
  72. package/internal/generated/theming/index.d.ts +189 -0
  73. package/internal/generated/theming/index.js +417 -9
  74. package/internal/keycode.d.ts +3 -1
  75. package/internal/keycode.d.ts.map +1 -1
  76. package/internal/keycode.js +5 -0
  77. package/internal/keycode.js.map +1 -1
  78. package/internal/manifest.json +1 -1
  79. package/internal/utils/handle-key.d.ts +22 -1
  80. package/internal/utils/handle-key.d.ts.map +1 -1
  81. package/internal/utils/handle-key.js +62 -4
  82. package/internal/utils/handle-key.js.map +1 -1
  83. package/link/internal.d.ts.map +1 -1
  84. package/link/internal.js +3 -1
  85. package/link/internal.js.map +1 -1
  86. package/link/styles.css.js +21 -20
  87. package/link/styles.scoped.css +83 -80
  88. package/link/styles.selectors.js +21 -20
  89. package/package.json +1 -1
  90. package/popover/internal.d.ts.map +1 -1
  91. package/popover/internal.js +3 -1
  92. package/popover/internal.js.map +1 -1
  93. package/popover/styles.css.js +58 -57
  94. package/popover/styles.scoped.css +92 -89
  95. package/popover/styles.selectors.js +58 -57
  96. package/prompt-input/components/menu-dropdown.d.ts +33 -0
  97. package/prompt-input/components/menu-dropdown.d.ts.map +1 -0
  98. package/prompt-input/components/menu-dropdown.js +48 -0
  99. package/prompt-input/components/menu-dropdown.js.map +1 -0
  100. package/prompt-input/components/textarea-mode.d.ts +15 -0
  101. package/prompt-input/components/textarea-mode.d.ts.map +1 -0
  102. package/prompt-input/components/textarea-mode.js +8 -0
  103. package/prompt-input/components/textarea-mode.js.map +1 -0
  104. package/prompt-input/components/token-mode.d.ts +61 -0
  105. package/prompt-input/components/token-mode.d.ts.map +1 -0
  106. package/prompt-input/components/token-mode.js +37 -0
  107. package/prompt-input/components/token-mode.js.map +1 -0
  108. package/prompt-input/core/caret-controller.d.ts +73 -0
  109. package/prompt-input/core/caret-controller.d.ts.map +1 -0
  110. package/prompt-input/core/caret-controller.js +396 -0
  111. package/prompt-input/core/caret-controller.js.map +1 -0
  112. package/prompt-input/core/caret-spot-utils.d.ts +6 -0
  113. package/prompt-input/core/caret-spot-utils.d.ts.map +1 -0
  114. package/prompt-input/core/caret-spot-utils.js +52 -0
  115. package/prompt-input/core/caret-spot-utils.js.map +1 -0
  116. package/prompt-input/core/caret-utils.d.ts +25 -0
  117. package/prompt-input/core/caret-utils.d.ts.map +1 -0
  118. package/prompt-input/core/caret-utils.js +183 -0
  119. package/prompt-input/core/caret-utils.js.map +1 -0
  120. package/prompt-input/core/constants.d.ts +14 -0
  121. package/prompt-input/core/constants.d.ts.map +1 -0
  122. package/prompt-input/core/constants.js +18 -0
  123. package/prompt-input/core/constants.js.map +1 -0
  124. package/prompt-input/core/dom-utils.d.ts +60 -0
  125. package/prompt-input/core/dom-utils.d.ts.map +1 -0
  126. package/prompt-input/core/dom-utils.js +252 -0
  127. package/prompt-input/core/dom-utils.js.map +1 -0
  128. package/prompt-input/core/event-handlers.d.ts +68 -0
  129. package/prompt-input/core/event-handlers.d.ts.map +1 -0
  130. package/prompt-input/core/event-handlers.js +678 -0
  131. package/prompt-input/core/event-handlers.js.map +1 -0
  132. package/prompt-input/core/menu-state.d.ts +62 -0
  133. package/prompt-input/core/menu-state.d.ts.map +1 -0
  134. package/prompt-input/core/menu-state.js +168 -0
  135. package/prompt-input/core/menu-state.js.map +1 -0
  136. package/prompt-input/core/token-operations.d.ts +21 -0
  137. package/prompt-input/core/token-operations.d.ts.map +1 -0
  138. package/prompt-input/core/token-operations.js +273 -0
  139. package/prompt-input/core/token-operations.js.map +1 -0
  140. package/prompt-input/core/token-renderer.d.ts +26 -0
  141. package/prompt-input/core/token-renderer.d.ts.map +1 -0
  142. package/prompt-input/core/token-renderer.js +230 -0
  143. package/prompt-input/core/token-renderer.js.map +1 -0
  144. package/prompt-input/core/token-utils.d.ts +22 -0
  145. package/prompt-input/core/token-utils.d.ts.map +1 -0
  146. package/prompt-input/core/token-utils.js +262 -0
  147. package/prompt-input/core/token-utils.js.map +1 -0
  148. package/prompt-input/core/trigger-utils.d.ts +18 -0
  149. package/prompt-input/core/trigger-utils.d.ts.map +1 -0
  150. package/prompt-input/core/trigger-utils.js +174 -0
  151. package/prompt-input/core/trigger-utils.js.map +1 -0
  152. package/prompt-input/core/type-guards.d.ts +13 -0
  153. package/prompt-input/core/type-guards.d.ts.map +1 -0
  154. package/prompt-input/core/type-guards.js +36 -0
  155. package/prompt-input/core/type-guards.js.map +1 -0
  156. package/prompt-input/index.d.ts +1 -1
  157. package/prompt-input/index.d.ts.map +1 -1
  158. package/prompt-input/index.js.map +1 -1
  159. package/prompt-input/interfaces.d.ts +356 -7
  160. package/prompt-input/interfaces.d.ts.map +1 -1
  161. package/prompt-input/interfaces.js.map +1 -1
  162. package/prompt-input/internal.d.ts +1 -1
  163. package/prompt-input/internal.d.ts.map +1 -1
  164. package/prompt-input/internal.js +195 -61
  165. package/prompt-input/internal.js.map +1 -1
  166. package/prompt-input/styles.css.js +26 -17
  167. package/prompt-input/styles.scoped.css +152 -39
  168. package/prompt-input/styles.selectors.js +26 -17
  169. package/prompt-input/test-classes/styles.css.js +7 -6
  170. package/prompt-input/test-classes/styles.scoped.css +10 -6
  171. package/prompt-input/test-classes/styles.selectors.js +7 -6
  172. package/prompt-input/tokens/use-shortcuts.d.ts +37 -0
  173. package/prompt-input/tokens/use-shortcuts.d.ts.map +1 -0
  174. package/prompt-input/tokens/use-shortcuts.js +89 -0
  175. package/prompt-input/tokens/use-shortcuts.js.map +1 -0
  176. package/prompt-input/tokens/use-token-mode.d.ts +78 -0
  177. package/prompt-input/tokens/use-token-mode.d.ts.map +1 -0
  178. package/prompt-input/tokens/use-token-mode.js +817 -0
  179. package/prompt-input/tokens/use-token-mode.js.map +1 -0
  180. package/prompt-input/utils/insert-text-content-editable.d.ts +10 -0
  181. package/prompt-input/utils/insert-text-content-editable.d.ts.map +1 -0
  182. package/prompt-input/utils/insert-text-content-editable.js +133 -0
  183. package/prompt-input/utils/insert-text-content-editable.js.map +1 -0
  184. package/tabs/styles.css.js +30 -30
  185. package/tabs/styles.scoped.css +55 -55
  186. package/tabs/styles.selectors.js +30 -30
  187. package/test-utils/dom/hotspot/index.js +1 -2
  188. package/test-utils/dom/hotspot/index.js.map +1 -1
  189. package/test-utils/dom/prompt-input/index.d.ts +53 -1
  190. package/test-utils/dom/prompt-input/index.js +121 -13
  191. package/test-utils/dom/prompt-input/index.js.map +1 -1
  192. package/test-utils/dom/s3-resource-selector/index.js +2 -3
  193. package/test-utils/dom/s3-resource-selector/index.js.map +1 -1
  194. package/test-utils/selectors/hotspot/index.js +1 -2
  195. package/test-utils/selectors/hotspot/index.js.map +1 -1
  196. package/test-utils/selectors/prompt-input/index.d.ts +30 -0
  197. package/test-utils/selectors/prompt-input/index.js +53 -7
  198. package/test-utils/selectors/prompt-input/index.js.map +1 -1
  199. package/test-utils/selectors/s3-resource-selector/index.js +2 -3
  200. package/test-utils/selectors/s3-resource-selector/index.js.map +1 -1
  201. package/token/internal.d.ts.map +1 -1
  202. package/token/internal.js +17 -15
  203. package/token/internal.js.map +1 -1
@@ -0,0 +1,396 @@
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 { ElementType } from './constants';
5
+ import { findAllParagraphs, findElement, getTokenType, isEmptyState, isReferenceElementType, stripZeroWidthCharacters, } from './dom-utils';
6
+ import { isBreakTextToken, isTextNode, isTextToken, isTriggerToken } from './type-guards';
7
+ /** Returns the Selection from the element's owning window, supporting iframe contexts. */
8
+ export function getOwnerSelection(element) {
9
+ var _a, _b;
10
+ return ((_b = (_a = element.ownerDocument) === null || _a === void 0 ? void 0 : _a.defaultView) !== null && _b !== void 0 ? _b : window).getSelection();
11
+ }
12
+ /** Logical lengths for each token type, used for cursor position calculations. */
13
+ export const TOKEN_LENGTHS = {
14
+ REFERENCE: 1,
15
+ LINE_BREAK: 1,
16
+ trigger: (filterText) => 1 + filterText.length,
17
+ text: (content) => content.length,
18
+ };
19
+ /** Calculates the logical cursor position after a given token index. */
20
+ export function calculateTokenPosition(tokens, upToIndex) {
21
+ let pos = 0;
22
+ for (let i = 0; i <= upToIndex && i < tokens.length; i++) {
23
+ const token = tokens[i];
24
+ if (isTextToken(token)) {
25
+ pos += TOKEN_LENGTHS.text(token.value);
26
+ }
27
+ else if (isBreakTextToken(token)) {
28
+ pos += TOKEN_LENGTHS.LINE_BREAK;
29
+ }
30
+ else if (isTriggerToken(token)) {
31
+ pos += TOKEN_LENGTHS.trigger(token.value);
32
+ }
33
+ else {
34
+ pos += TOKEN_LENGTHS.REFERENCE;
35
+ }
36
+ }
37
+ return pos;
38
+ }
39
+ /** Calculates the total logical length of all tokens. */
40
+ export function calculateTotalTokenLength(tokens) {
41
+ return tokens.length === 0 ? 0 : calculateTokenPosition(tokens, tokens.length - 1);
42
+ }
43
+ /**
44
+ * Manages caret positioning within a contentEditable element.
45
+ * Translates between logical token positions and DOM Range/Selection API.
46
+ */
47
+ export class CaretController {
48
+ constructor(element) {
49
+ this.element = element;
50
+ this.state = { start: 0, end: undefined, isValid: false };
51
+ }
52
+ get ownerDoc() {
53
+ var _a;
54
+ return (_a = this.element.ownerDocument) !== null && _a !== void 0 ? _a : document;
55
+ }
56
+ /**
57
+ * Creates a DOM Range from resolved start/end locations and applies it to the given selection.
58
+ * Returns the created Range for further use (e.g. scroll-into-view checks).
59
+ */
60
+ applyRange(ownerDocument, selection, startLocation, endLocation) {
61
+ const range = ownerDocument.createRange();
62
+ range.setStart(startLocation.node, startLocation.offset);
63
+ if (endLocation) {
64
+ range.setEnd(endLocation.node, endLocation.offset);
65
+ }
66
+ else {
67
+ range.collapse(true);
68
+ }
69
+ selection.removeAllRanges();
70
+ selection.addRange(range);
71
+ return range;
72
+ }
73
+ /** Returns the logical length of a DOM node based on its token type. */
74
+ getNodeLength(node) {
75
+ const tokenType = isHTMLElement(node) ? getTokenType(node) : null;
76
+ if (isTextNode(node) || tokenType === ElementType.Trigger) {
77
+ return TOKEN_LENGTHS.text(node.textContent || '');
78
+ }
79
+ else if (tokenType && isReferenceElementType(tokenType)) {
80
+ return TOKEN_LENGTHS.REFERENCE;
81
+ }
82
+ return 0;
83
+ }
84
+ /** Returns the current logical caret position from the DOM selection. */
85
+ getPosition() {
86
+ const selection = getOwnerSelection(this.element);
87
+ if (!(selection === null || selection === void 0 ? void 0 : selection.rangeCount)) {
88
+ return 0;
89
+ }
90
+ const range = selection.getRangeAt(0);
91
+ if (!this.element.contains(range.startContainer)) {
92
+ return 0;
93
+ }
94
+ return this.calculatePositionFromRange(range, false);
95
+ }
96
+ /** Finds the trigger element at the current caret position, if any. */
97
+ findActiveTrigger() {
98
+ const selection = getOwnerSelection(this.element);
99
+ if (!(selection === null || selection === void 0 ? void 0 : selection.rangeCount)) {
100
+ return null;
101
+ }
102
+ const range = selection.getRangeAt(0);
103
+ if (!range.collapsed) {
104
+ return null;
105
+ }
106
+ let node = range.startContainer;
107
+ // Walk up from cursor to find a trigger ancestor
108
+ while (node && node !== this.element) {
109
+ if (isHTMLElement(node) && getTokenType(node) === ElementType.Trigger) {
110
+ if (isTextNode(range.startContainer) && range.startContainer.parentElement === node) {
111
+ // Caret must be after the trigger character (offset > 0) to be considered "in" the trigger
112
+ if (range.startOffset > 0) {
113
+ return node;
114
+ }
115
+ }
116
+ else {
117
+ return node;
118
+ }
119
+ }
120
+ node = node.parentNode;
121
+ }
122
+ // Also check: cursor at offset 0 of a text node right after a trigger
123
+ if (isTextNode(range.startContainer) && range.startOffset === 0) {
124
+ const prevSibling = range.startContainer.previousSibling;
125
+ if (isHTMLElement(prevSibling) && getTokenType(prevSibling) === ElementType.Trigger) {
126
+ return prevSibling;
127
+ }
128
+ }
129
+ return null;
130
+ }
131
+ /**
132
+ * Sets the caret to a logical position, or creates a selection range if end is provided.
133
+ * Handles smart positioning around atomic reference tokens and scrolls into view.
134
+ * @param start logical start position
135
+ * @param end optional logical end position for range selection
136
+ */
137
+ setPosition(start, end) {
138
+ var _a;
139
+ const ownerDocument = this.ownerDoc;
140
+ if (ownerDocument.activeElement !== this.element) {
141
+ this.element.focus();
142
+ }
143
+ const startLocation = this.findDOMLocation(start);
144
+ if (!startLocation) {
145
+ return;
146
+ }
147
+ const selection = getOwnerSelection(this.element);
148
+ if (!selection) {
149
+ return;
150
+ }
151
+ const endLocation = end !== undefined && end !== start ? ((_a = this.findDOMLocation(end)) !== null && _a !== void 0 ? _a : undefined) : undefined;
152
+ this.applyRange(ownerDocument, selection, startLocation, endLocation);
153
+ this.state = { start, end, isValid: true };
154
+ ownerDocument.dispatchEvent(new Event('selectionchange'));
155
+ }
156
+ /** Captures the current caret/selection state for later restoration. */
157
+ capture() {
158
+ const selection = getOwnerSelection(this.element);
159
+ if (!(selection === null || selection === void 0 ? void 0 : selection.rangeCount)) {
160
+ this.state = { start: 0, end: undefined, isValid: false };
161
+ return;
162
+ }
163
+ const range = selection.getRangeAt(0);
164
+ if (!this.element.contains(range.startContainer)) {
165
+ this.state = { start: 0, end: undefined, isValid: false };
166
+ return;
167
+ }
168
+ const start = this.calculatePositionFromRange(range, false);
169
+ const end = range.collapsed ? undefined : this.calculatePositionFromRange(range, true);
170
+ this.state = { start, end, isValid: true };
171
+ }
172
+ /** Returns the captured caret start position, or null if no valid capture exists. */
173
+ getSavedPosition() {
174
+ return this.state.isValid ? this.state.start : null;
175
+ }
176
+ /** Restores the caret to the previously captured state. */
177
+ restore(offset = 0) {
178
+ if (!this.state.isValid || this.ownerDoc.activeElement !== this.element) {
179
+ return;
180
+ }
181
+ this.setPosition(this.state.start + offset, this.state.end !== undefined ? this.state.end + offset : undefined);
182
+ }
183
+ /** Overrides the captured state so the next restore() positions to a calculated location.
184
+ * Currently used only in tests — consider removing if no production use case emerges.
185
+ */
186
+ setCapturedPosition(start, end) {
187
+ this.state = { start, end, isValid: true };
188
+ }
189
+ /** Selects all content in the element. */
190
+ selectAll() {
191
+ const selection = getOwnerSelection(this.element);
192
+ if (!selection) {
193
+ return;
194
+ }
195
+ if (isEmptyState(this.element)) {
196
+ return;
197
+ }
198
+ if (this.ownerDoc.activeElement !== this.element) {
199
+ this.element.focus();
200
+ }
201
+ const paragraphs = findAllParagraphs(this.element);
202
+ if (paragraphs.length === 0) {
203
+ return;
204
+ }
205
+ const firstP = paragraphs[0];
206
+ const lastP = paragraphs[paragraphs.length - 1];
207
+ const range = this.ownerDoc.createRange();
208
+ range.setStart(firstP, 0);
209
+ range.setEnd(lastP, lastP.childNodes.length);
210
+ selection.removeAllRanges();
211
+ selection.addRange(range);
212
+ }
213
+ /** Positions the caret at the end of a text node. */
214
+ positionAfterText(textNode) {
215
+ var _a;
216
+ const range = this.ownerDoc.createRange();
217
+ range.setStart(textNode, ((_a = textNode.textContent) === null || _a === void 0 ? void 0 : _a.length) || 0);
218
+ range.collapse(true);
219
+ const selection = getOwnerSelection(this.element);
220
+ if (selection) {
221
+ selection.removeAllRanges();
222
+ selection.addRange(range);
223
+ }
224
+ }
225
+ /** Moves the caret forward by a logical offset. */
226
+ moveForward(offset) {
227
+ const currentPos = this.getPosition();
228
+ this.setPosition(currentPos + offset);
229
+ }
230
+ /** Moves the caret backward by a logical offset, clamped to 0. */
231
+ moveBackward(offset) {
232
+ const currentPos = this.getPosition();
233
+ this.setPosition(Math.max(0, currentPos - offset));
234
+ }
235
+ calculatePositionFromRange(range, useEnd) {
236
+ const paragraphs = findAllParagraphs(this.element);
237
+ if (paragraphs.length === 0) {
238
+ return 0;
239
+ }
240
+ const container = useEnd ? range.endContainer : range.startContainer;
241
+ const offset = useEnd ? range.endOffset : range.startOffset;
242
+ let position = 0;
243
+ for (let pIndex = 0; pIndex < paragraphs.length; pIndex++) {
244
+ const p = paragraphs[pIndex];
245
+ if (pIndex > 0) {
246
+ position += TOKEN_LENGTHS.LINE_BREAK;
247
+ }
248
+ if (!p.contains(container)) {
249
+ position += this.countParagraphContent(p);
250
+ }
251
+ else {
252
+ position += this.countUpToCursor(p, container, offset);
253
+ break;
254
+ }
255
+ }
256
+ return position;
257
+ }
258
+ findDOMLocation(position) {
259
+ var _a;
260
+ const paragraphs = findAllParagraphs(this.element);
261
+ let caretPos = 0;
262
+ for (let pIndex = 0; pIndex < paragraphs.length; pIndex++) {
263
+ const p = paragraphs[pIndex];
264
+ if (pIndex > 0) {
265
+ caretPos += TOKEN_LENGTHS.LINE_BREAK;
266
+ if (caretPos >= position) {
267
+ return { node: p, offset: 0 };
268
+ }
269
+ }
270
+ const paragraphLength = this.countParagraphContent(p);
271
+ if (caretPos + paragraphLength >= position) {
272
+ return this.findLocationInParagraph(p, position - caretPos);
273
+ }
274
+ caretPos += paragraphLength;
275
+ }
276
+ const lastP = paragraphs[paragraphs.length - 1];
277
+ if ((lastP === null || lastP === void 0 ? void 0 : lastP.lastChild) && isTextNode(lastP.lastChild)) {
278
+ return { node: lastP.lastChild, offset: ((_a = lastP.lastChild.textContent) === null || _a === void 0 ? void 0 : _a.length) || 0 };
279
+ }
280
+ return lastP ? { node: lastP, offset: lastP.childNodes.length } : null;
281
+ }
282
+ /** Resolves a DOM location for a specific child node at the given offset within a paragraph. */
283
+ resolveChildLocation(p, child, offsetInChild) {
284
+ if (isTextNode(child)) {
285
+ return { node: child, offset: offsetInChild };
286
+ }
287
+ if (!isHTMLElement(child)) {
288
+ return { node: p, offset: Array.from(p.childNodes).indexOf(child) };
289
+ }
290
+ const tokenType = getTokenType(child);
291
+ const childIndex = Array.from(p.childNodes).indexOf(child);
292
+ if (tokenType === ElementType.Trigger) {
293
+ if (offsetInChild === 0) {
294
+ return { node: p, offset: childIndex };
295
+ }
296
+ const triggerTextNode = child.childNodes[0];
297
+ if (triggerTextNode && isTextNode(triggerTextNode)) {
298
+ return { node: triggerTextNode, offset: offsetInChild };
299
+ }
300
+ return { node: p, offset: childIndex };
301
+ }
302
+ if (isReferenceElementType(tokenType)) {
303
+ if (offsetInChild === 0) {
304
+ return { node: p, offset: childIndex };
305
+ }
306
+ const nextSibling = child.nextSibling;
307
+ if (nextSibling) {
308
+ return isTextNode(nextSibling) ? { node: nextSibling, offset: 0 } : { node: p, offset: childIndex + 1 };
309
+ }
310
+ return { node: p, offset: p.childNodes.length };
311
+ }
312
+ return { node: p, offset: childIndex };
313
+ }
314
+ findLocationInParagraph(p, targetOffset) {
315
+ var _a;
316
+ let offsetInParagraph = 0;
317
+ for (const child of Array.from(p.childNodes)) {
318
+ const childLength = this.getNodeLength(child);
319
+ if (offsetInParagraph + childLength >= targetOffset) {
320
+ return this.resolveChildLocation(p, child, targetOffset - offsetInParagraph);
321
+ }
322
+ offsetInParagraph += childLength;
323
+ }
324
+ if (p.lastChild && isTextNode(p.lastChild)) {
325
+ return { node: p.lastChild, offset: ((_a = p.lastChild.textContent) === null || _a === void 0 ? void 0 : _a.length) || 0 };
326
+ }
327
+ return { node: p, offset: p.childNodes.length };
328
+ }
329
+ countParagraphContent(p) {
330
+ let count = 0;
331
+ for (const child of Array.from(p.childNodes)) {
332
+ count += this.getNodeLength(child);
333
+ }
334
+ return count;
335
+ }
336
+ countUpToCursor(p, container, offset) {
337
+ if (container === p) {
338
+ let count = 0;
339
+ for (let i = 0; i < offset && i < p.childNodes.length; i++) {
340
+ count += this.getNodeLength(p.childNodes[i]);
341
+ }
342
+ return count;
343
+ }
344
+ let count = 0;
345
+ for (const child of Array.from(p.childNodes)) {
346
+ if (child === container || child.contains(container)) {
347
+ if (isTextNode(child)) {
348
+ return count + offset;
349
+ }
350
+ if (isHTMLElement(child)) {
351
+ const tokenType = getTokenType(child);
352
+ if (tokenType === ElementType.Trigger) {
353
+ const triggerTextNode = child.childNodes[0];
354
+ if (triggerTextNode && isTextNode(triggerTextNode) && triggerTextNode === container) {
355
+ return count + offset;
356
+ }
357
+ }
358
+ else if (isReferenceElementType(tokenType)) {
359
+ const caretSpotBefore = findElement(child, { tokenType: ElementType.CaretSpotBefore });
360
+ const caretSpotAfter = findElement(child, { tokenType: ElementType.CaretSpotAfter });
361
+ const caretInBefore = caretSpotBefore && (caretSpotBefore === container || caretSpotBefore.contains(container));
362
+ const caretInAfter = caretSpotAfter && (caretSpotAfter === container || caretSpotAfter.contains(container));
363
+ if (caretInBefore) {
364
+ // Caret is in the before-spot: any typed text counts from the start of the reference
365
+ const beforeContent = stripZeroWidthCharacters(caretSpotBefore.textContent || '');
366
+ if (beforeContent && isTextNode(container)) {
367
+ return count + offset;
368
+ }
369
+ // No real content — caret is logically before the reference
370
+ return count;
371
+ }
372
+ else if (caretInAfter) {
373
+ // Caret is in the after-spot: position is after the reference (count it first)
374
+ count += TOKEN_LENGTHS.REFERENCE;
375
+ const afterContent = stripZeroWidthCharacters(caretSpotAfter.textContent || '');
376
+ if (afterContent && isTextNode(container)) {
377
+ // offset - 1 because the zero-width character occupies position 0
378
+ const contentOffset = Math.max(0, offset - 1);
379
+ return count + contentOffset;
380
+ }
381
+ // No real content — caret is logically after the reference
382
+ return count;
383
+ }
384
+ else {
385
+ return count + TOKEN_LENGTHS.REFERENCE;
386
+ }
387
+ }
388
+ }
389
+ return count + this.getNodeLength(child);
390
+ }
391
+ count += this.getNodeLength(child);
392
+ }
393
+ return count;
394
+ }
395
+ }
396
+ //# sourceMappingURL=caret-controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caret-controller.js","sourceRoot":"","sources":["../../../../src/prompt-input/core/caret-controller.ts"],"names":[],"mappings":"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","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 { PromptInputProps } from '../interfaces';\nimport { ElementType } from './constants';\nimport {\n findAllParagraphs,\n findElement,\n getTokenType,\n isEmptyState,\n isReferenceElementType,\n stripZeroWidthCharacters,\n} from './dom-utils';\nimport { isBreakTextToken, isTextNode, isTextToken, isTriggerToken } from './type-guards';\n\n/** Returns the Selection from the element's owning window, supporting iframe contexts. */\nexport function getOwnerSelection(element: Node): Selection | null {\n return (element.ownerDocument?.defaultView ?? window).getSelection();\n}\n\n/** Logical lengths for each token type, used for cursor position calculations. */\nexport const TOKEN_LENGTHS = {\n REFERENCE: 1,\n LINE_BREAK: 1,\n trigger: (filterText: string) => 1 + filterText.length,\n text: (content: string) => content.length,\n} as const;\n\n/** Calculates the logical cursor position after a given token index. */\nexport function calculateTokenPosition(tokens: readonly PromptInputProps.InputToken[], upToIndex: number): number {\n let pos = 0;\n for (let i = 0; i <= upToIndex && i < tokens.length; i++) {\n const token = tokens[i];\n if (isTextToken(token)) {\n pos += TOKEN_LENGTHS.text(token.value);\n } else if (isBreakTextToken(token)) {\n pos += TOKEN_LENGTHS.LINE_BREAK;\n } else if (isTriggerToken(token)) {\n pos += TOKEN_LENGTHS.trigger(token.value);\n } else {\n pos += TOKEN_LENGTHS.REFERENCE;\n }\n }\n return pos;\n}\n\n/** Calculates the total logical length of all tokens. */\nexport function calculateTotalTokenLength(tokens: readonly PromptInputProps.InputToken[]): number {\n return tokens.length === 0 ? 0 : calculateTokenPosition(tokens, tokens.length - 1);\n}\n\ninterface CaretState {\n start: number;\n end: number | undefined;\n isValid: boolean;\n}\n\n/** A resolved position within the DOM: a node and an offset into it. */\ninterface DOMLocation {\n node: Node;\n offset: number;\n}\n\n/**\n * Manages caret positioning within a contentEditable element.\n * Translates between logical token positions and DOM Range/Selection API.\n */\nexport class CaretController {\n private element: HTMLElement;\n private state: CaretState;\n\n constructor(element: HTMLElement) {\n this.element = element;\n this.state = { start: 0, end: undefined, isValid: false };\n }\n\n private get ownerDoc(): Document {\n return this.element.ownerDocument ?? document;\n }\n\n /**\n * Creates a DOM Range from resolved start/end locations and applies it to the given selection.\n * Returns the created Range for further use (e.g. scroll-into-view checks).\n */\n applyRange(\n ownerDocument: Document,\n selection: Selection,\n startLocation: DOMLocation,\n endLocation?: DOMLocation\n ): Range {\n const range = ownerDocument.createRange();\n range.setStart(startLocation.node, startLocation.offset);\n\n if (endLocation) {\n range.setEnd(endLocation.node, endLocation.offset);\n } else {\n range.collapse(true);\n }\n\n selection.removeAllRanges();\n selection.addRange(range);\n return range;\n }\n\n /** Returns the logical length of a DOM node based on its token type. */\n private getNodeLength(node: Node): number {\n const tokenType = isHTMLElement(node) ? getTokenType(node) : null;\n\n if (isTextNode(node) || tokenType === ElementType.Trigger) {\n return TOKEN_LENGTHS.text(node.textContent || '');\n } else if (tokenType && isReferenceElementType(tokenType)) {\n return TOKEN_LENGTHS.REFERENCE;\n }\n\n return 0;\n }\n\n /** Returns the current logical caret position from the DOM selection. */\n getPosition(): number {\n const selection = getOwnerSelection(this.element);\n if (!selection?.rangeCount) {\n return 0;\n }\n\n const range = selection.getRangeAt(0);\n if (!this.element.contains(range.startContainer)) {\n return 0;\n }\n\n return this.calculatePositionFromRange(range, false);\n }\n\n /** Finds the trigger element at the current caret position, if any. */\n findActiveTrigger(): HTMLElement | null {\n const selection = getOwnerSelection(this.element);\n if (!selection?.rangeCount) {\n return null;\n }\n\n const range = selection.getRangeAt(0);\n if (!range.collapsed) {\n return null;\n }\n\n let node: Node | null = range.startContainer;\n\n // Walk up from cursor to find a trigger ancestor\n while (node && node !== this.element) {\n if (isHTMLElement(node) && getTokenType(node) === ElementType.Trigger) {\n if (isTextNode(range.startContainer) && range.startContainer.parentElement === node) {\n // Caret must be after the trigger character (offset > 0) to be considered \"in\" the trigger\n if (range.startOffset > 0) {\n return node;\n }\n } else {\n return node;\n }\n }\n node = node.parentNode;\n }\n\n // Also check: cursor at offset 0 of a text node right after a trigger\n if (isTextNode(range.startContainer) && range.startOffset === 0) {\n const prevSibling = range.startContainer.previousSibling;\n if (isHTMLElement(prevSibling) && getTokenType(prevSibling) === ElementType.Trigger) {\n return prevSibling;\n }\n }\n\n return null;\n }\n\n /**\n * Sets the caret to a logical position, or creates a selection range if end is provided.\n * Handles smart positioning around atomic reference tokens and scrolls into view.\n * @param start logical start position\n * @param end optional logical end position for range selection\n */\n setPosition(start: number, end?: number): void {\n const ownerDocument = this.ownerDoc;\n if (ownerDocument.activeElement !== this.element) {\n this.element.focus();\n }\n\n const startLocation = this.findDOMLocation(start);\n\n if (!startLocation) {\n return;\n }\n\n const selection = getOwnerSelection(this.element);\n if (!selection) {\n return;\n }\n\n const endLocation = end !== undefined && end !== start ? (this.findDOMLocation(end) ?? undefined) : undefined;\n\n this.applyRange(ownerDocument, selection, startLocation, endLocation);\n\n this.state = { start, end, isValid: true };\n\n ownerDocument.dispatchEvent(new Event('selectionchange'));\n }\n\n /** Captures the current caret/selection state for later restoration. */\n capture(): void {\n const selection = getOwnerSelection(this.element);\n if (!selection?.rangeCount) {\n this.state = { start: 0, end: undefined, isValid: false };\n return;\n }\n\n const range = selection.getRangeAt(0);\n if (!this.element.contains(range.startContainer)) {\n this.state = { start: 0, end: undefined, isValid: false };\n return;\n }\n\n const start = this.calculatePositionFromRange(range, false);\n const end = range.collapsed ? undefined : this.calculatePositionFromRange(range, true);\n\n this.state = { start, end, isValid: true };\n }\n\n /** Returns the captured caret start position, or null if no valid capture exists. */\n getSavedPosition(): number | null {\n return this.state.isValid ? this.state.start : null;\n }\n\n /** Restores the caret to the previously captured state. */\n restore(offset = 0): void {\n if (!this.state.isValid || this.ownerDoc.activeElement !== this.element) {\n return;\n }\n\n this.setPosition(this.state.start + offset, this.state.end !== undefined ? this.state.end + offset : undefined);\n }\n\n /** Overrides the captured state so the next restore() positions to a calculated location.\n * Currently used only in tests — consider removing if no production use case emerges.\n */\n setCapturedPosition(start: number, end?: number): void {\n this.state = { start, end, isValid: true };\n }\n\n /** Selects all content in the element. */\n selectAll(): void {\n const selection = getOwnerSelection(this.element);\n if (!selection) {\n return;\n }\n\n if (isEmptyState(this.element)) {\n return;\n }\n\n if (this.ownerDoc.activeElement !== this.element) {\n this.element.focus();\n }\n\n const paragraphs = findAllParagraphs(this.element);\n if (paragraphs.length === 0) {\n return;\n }\n\n const firstP = paragraphs[0];\n const lastP = paragraphs[paragraphs.length - 1];\n\n const range = this.ownerDoc.createRange();\n range.setStart(firstP, 0);\n range.setEnd(lastP, lastP.childNodes.length);\n selection.removeAllRanges();\n selection.addRange(range);\n }\n\n /** Positions the caret at the end of a text node. */\n positionAfterText(textNode: Text): void {\n const range = this.ownerDoc.createRange();\n range.setStart(textNode, textNode.textContent?.length || 0);\n range.collapse(true);\n\n const selection = getOwnerSelection(this.element);\n if (selection) {\n selection.removeAllRanges();\n selection.addRange(range);\n }\n }\n\n /** Moves the caret forward by a logical offset. */\n moveForward(offset: number): void {\n const currentPos = this.getPosition();\n this.setPosition(currentPos + offset);\n }\n\n /** Moves the caret backward by a logical offset, clamped to 0. */\n moveBackward(offset: number): void {\n const currentPos = this.getPosition();\n this.setPosition(Math.max(0, currentPos - offset));\n }\n\n private calculatePositionFromRange(range: Range, useEnd: boolean): number {\n const paragraphs = findAllParagraphs(this.element);\n if (paragraphs.length === 0) {\n return 0;\n }\n\n const container = useEnd ? range.endContainer : range.startContainer;\n const offset = useEnd ? range.endOffset : range.startOffset;\n\n let position = 0;\n\n for (let pIndex = 0; pIndex < paragraphs.length; pIndex++) {\n const p = paragraphs[pIndex];\n if (pIndex > 0) {\n position += TOKEN_LENGTHS.LINE_BREAK;\n }\n\n if (!p.contains(container)) {\n position += this.countParagraphContent(p);\n } else {\n position += this.countUpToCursor(p, container, offset);\n break;\n }\n }\n\n return position;\n }\n\n private findDOMLocation(position: number): DOMLocation | null {\n const paragraphs = findAllParagraphs(this.element);\n let caretPos = 0;\n\n for (let pIndex = 0; pIndex < paragraphs.length; pIndex++) {\n const p = paragraphs[pIndex];\n\n if (pIndex > 0) {\n caretPos += TOKEN_LENGTHS.LINE_BREAK;\n if (caretPos >= position) {\n return { node: p, offset: 0 };\n }\n }\n\n const paragraphLength = this.countParagraphContent(p);\n\n if (caretPos + paragraphLength >= position) {\n return this.findLocationInParagraph(p, position - caretPos);\n }\n\n caretPos += paragraphLength;\n }\n\n const lastP = paragraphs[paragraphs.length - 1];\n if (lastP?.lastChild && isTextNode(lastP.lastChild)) {\n return { node: lastP.lastChild, offset: lastP.lastChild.textContent?.length || 0 };\n }\n return lastP ? { node: lastP, offset: lastP.childNodes.length } : null;\n }\n\n /** Resolves a DOM location for a specific child node at the given offset within a paragraph. */\n private resolveChildLocation(p: HTMLElement, child: ChildNode, offsetInChild: number): DOMLocation {\n if (isTextNode(child)) {\n return { node: child, offset: offsetInChild };\n }\n\n if (!isHTMLElement(child)) {\n return { node: p, offset: Array.from(p.childNodes).indexOf(child) };\n }\n\n const tokenType = getTokenType(child);\n const childIndex = Array.from(p.childNodes).indexOf(child);\n\n if (tokenType === ElementType.Trigger) {\n if (offsetInChild === 0) {\n return { node: p, offset: childIndex };\n }\n const triggerTextNode = child.childNodes[0];\n if (triggerTextNode && isTextNode(triggerTextNode)) {\n return { node: triggerTextNode, offset: offsetInChild };\n }\n return { node: p, offset: childIndex };\n }\n\n if (isReferenceElementType(tokenType)) {\n if (offsetInChild === 0) {\n return { node: p, offset: childIndex };\n }\n const nextSibling = child.nextSibling;\n if (nextSibling) {\n return isTextNode(nextSibling) ? { node: nextSibling, offset: 0 } : { node: p, offset: childIndex + 1 };\n }\n return { node: p, offset: p.childNodes.length };\n }\n\n return { node: p, offset: childIndex };\n }\n\n private findLocationInParagraph(p: HTMLElement, targetOffset: number): DOMLocation | null {\n let offsetInParagraph = 0;\n\n for (const child of Array.from(p.childNodes)) {\n const childLength = this.getNodeLength(child);\n\n if (offsetInParagraph + childLength >= targetOffset) {\n return this.resolveChildLocation(p, child, targetOffset - offsetInParagraph);\n }\n\n offsetInParagraph += childLength;\n }\n\n if (p.lastChild && isTextNode(p.lastChild)) {\n return { node: p.lastChild, offset: p.lastChild.textContent?.length || 0 };\n }\n return { node: p, offset: p.childNodes.length };\n }\n\n private countParagraphContent(p: Element): number {\n let count = 0;\n for (const child of Array.from(p.childNodes)) {\n count += this.getNodeLength(child);\n }\n return count;\n }\n\n private countUpToCursor(p: Element, container: Node, offset: number): number {\n if (container === p) {\n let count = 0;\n for (let i = 0; i < offset && i < p.childNodes.length; i++) {\n count += this.getNodeLength(p.childNodes[i]);\n }\n return count;\n }\n\n let count = 0;\n for (const child of Array.from(p.childNodes)) {\n if (child === container || child.contains(container)) {\n if (isTextNode(child)) {\n return count + offset;\n }\n\n if (isHTMLElement(child)) {\n const tokenType = getTokenType(child);\n\n if (tokenType === ElementType.Trigger) {\n const triggerTextNode = child.childNodes[0];\n if (triggerTextNode && isTextNode(triggerTextNode) && triggerTextNode === container) {\n return count + offset;\n }\n } else if (isReferenceElementType(tokenType)) {\n const caretSpotBefore = findElement(child, { tokenType: ElementType.CaretSpotBefore });\n const caretSpotAfter = findElement(child, { tokenType: ElementType.CaretSpotAfter });\n\n const caretInBefore =\n caretSpotBefore && (caretSpotBefore === container || caretSpotBefore.contains(container));\n const caretInAfter = caretSpotAfter && (caretSpotAfter === container || caretSpotAfter.contains(container));\n\n if (caretInBefore) {\n // Caret is in the before-spot: any typed text counts from the start of the reference\n const beforeContent = stripZeroWidthCharacters(caretSpotBefore!.textContent || '');\n if (beforeContent && isTextNode(container)) {\n return count + offset;\n }\n // No real content — caret is logically before the reference\n return count;\n } else if (caretInAfter) {\n // Caret is in the after-spot: position is after the reference (count it first)\n count += TOKEN_LENGTHS.REFERENCE;\n const afterContent = stripZeroWidthCharacters(caretSpotAfter!.textContent || '');\n if (afterContent && isTextNode(container)) {\n // offset - 1 because the zero-width character occupies position 0\n const contentOffset = Math.max(0, offset - 1);\n return count + contentOffset;\n }\n // No real content — caret is logically after the reference\n return count;\n } else {\n return count + TOKEN_LENGTHS.REFERENCE;\n }\n }\n }\n return count + this.getNodeLength(child);\n }\n count += this.getNodeLength(child);\n }\n\n return count;\n }\n}\n"]}
@@ -0,0 +1,6 @@
1
+ import { PortalContainer } from './token-renderer';
2
+ export interface TextExtractionResult {
3
+ movedTextNode: Text | null;
4
+ }
5
+ /** Extracts typed text from caret spots, moving it to the paragraph level. */
6
+ export declare function extractTextFromCaretSpots(portalContainers: Map<string, PortalContainer>, trackCaret: boolean): TextExtractionResult;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caret-spot-utils.d.ts","sourceRoot":"","sources":["../../../../src/prompt-input/core/caret-spot-utils.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,IAAI,GAAG,IAAI,CAAC;CAC5B;AA+BD,8EAA8E;AAC9E,wBAAgB,yBAAyB,CACvC,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,EAC9C,UAAU,EAAE,OAAO,GAClB,oBAAoB,CAoBtB"}
@@ -0,0 +1,52 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { getOwnerSelection } from './caret-controller';
4
+ import { ElementType, SPECIAL_CHARS } from './constants';
5
+ import { insertAfter, stripZeroWidthCharacters } from './dom-utils';
6
+ /** Extracts typed text from a caret-spot, moving it to the paragraph level. */
7
+ function extractFromSpot(spot, trackCaret) {
8
+ var _a, _b;
9
+ const extraText = stripZeroWidthCharacters(spot.textContent || '');
10
+ if (!extraText) {
11
+ return null;
12
+ }
13
+ let caretWasHere = false;
14
+ if (trackCaret) {
15
+ const selection = getOwnerSelection(spot);
16
+ if ((selection === null || selection === void 0 ? void 0 : selection.rangeCount) && spot.contains(selection.getRangeAt(0).startContainer)) {
17
+ caretWasHere = true;
18
+ }
19
+ }
20
+ const textNode = ((_a = spot.ownerDocument) !== null && _a !== void 0 ? _a : document).createTextNode(extraText);
21
+ const wrapper = spot.parentElement;
22
+ const isBefore = spot.getAttribute('data-type') === ElementType.CaretSpotBefore;
23
+ if (isBefore) {
24
+ (_b = wrapper.parentNode) === null || _b === void 0 ? void 0 : _b.insertBefore(textNode, wrapper);
25
+ }
26
+ else {
27
+ insertAfter(textNode, wrapper);
28
+ }
29
+ spot.textContent = SPECIAL_CHARS.ZERO_WIDTH_CHARACTER;
30
+ return caretWasHere ? textNode : null;
31
+ }
32
+ /** Extracts typed text from caret spots, moving it to the paragraph level. */
33
+ export function extractTextFromCaretSpots(portalContainers, trackCaret) {
34
+ let movedTextNode = null;
35
+ for (const container of portalContainers.values()) {
36
+ const wrapper = container.element.parentElement;
37
+ if (!wrapper) {
38
+ continue;
39
+ }
40
+ for (const child of Array.from(wrapper.children)) {
41
+ const type = child.getAttribute('data-type');
42
+ if (type === ElementType.CaretSpotBefore || type === ElementType.CaretSpotAfter) {
43
+ const result = extractFromSpot(child, trackCaret);
44
+ if (result) {
45
+ movedTextNode = result;
46
+ }
47
+ }
48
+ }
49
+ }
50
+ return { movedTextNode };
51
+ }
52
+ //# sourceMappingURL=caret-spot-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caret-spot-utils.js","sourceRoot":"","sources":["../../../../src/prompt-input/core/caret-spot-utils.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,sCAAsC;AAEtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAOpE,+EAA+E;AAC/E,SAAS,eAAe,CAAC,IAAiB,EAAE,UAAmB;;IAC7D,MAAM,SAAS,GAAG,wBAAwB,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;IACnE,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,SAAS,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,CAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,UAAU,KAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,EAAE,CAAC;YACnF,YAAY,GAAG,IAAI,CAAC;QACtB,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,CAAC,MAAA,IAAI,CAAC,aAAa,mCAAI,QAAQ,CAAC,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;IAC5E,MAAM,OAAO,GAAG,IAAI,CAAC,aAAc,CAAC;IACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,KAAK,WAAW,CAAC,eAAe,CAAC;IAEhF,IAAI,QAAQ,EAAE,CAAC;QACb,MAAA,OAAO,CAAC,UAAU,0CAAE,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACtD,CAAC;SAAM,CAAC;QACN,WAAW,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACjC,CAAC;IAED,IAAI,CAAC,WAAW,GAAG,aAAa,CAAC,oBAAoB,CAAC;IACtD,OAAO,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;AACxC,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,yBAAyB,CACvC,gBAA8C,EAC9C,UAAmB;IAEnB,IAAI,aAAa,GAAgB,IAAI,CAAC;IAEtC,KAAK,MAAM,SAAS,IAAI,gBAAgB,CAAC,MAAM,EAAE,EAAE,CAAC;QAClD,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,aAAa,CAAC;QAChD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,SAAS;QACX,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YACjD,MAAM,IAAI,GAAG,KAAK,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;YAC7C,IAAI,IAAI,KAAK,WAAW,CAAC,eAAe,IAAI,IAAI,KAAK,WAAW,CAAC,cAAc,EAAE,CAAC;gBAChF,MAAM,MAAM,GAAG,eAAe,CAAC,KAAoB,EAAE,UAAU,CAAC,CAAC;gBACjE,IAAI,MAAM,EAAE,CAAC;oBACX,aAAa,GAAG,MAAM,CAAC;gBACzB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,aAAa,EAAE,CAAC;AAC3B,CAAC","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { getOwnerSelection } from './caret-controller';\nimport { ElementType, SPECIAL_CHARS } from './constants';\nimport { insertAfter, stripZeroWidthCharacters } from './dom-utils';\nimport { PortalContainer } from './token-renderer';\n\nexport interface TextExtractionResult {\n movedTextNode: Text | null;\n}\n\n/** Extracts typed text from a caret-spot, moving it to the paragraph level. */\nfunction extractFromSpot(spot: HTMLElement, trackCaret: boolean): Text | null {\n const extraText = stripZeroWidthCharacters(spot.textContent || '');\n if (!extraText) {\n return null;\n }\n\n let caretWasHere = false;\n if (trackCaret) {\n const selection = getOwnerSelection(spot);\n if (selection?.rangeCount && spot.contains(selection.getRangeAt(0).startContainer)) {\n caretWasHere = true;\n }\n }\n\n const textNode = (spot.ownerDocument ?? document).createTextNode(extraText);\n const wrapper = spot.parentElement!;\n const isBefore = spot.getAttribute('data-type') === ElementType.CaretSpotBefore;\n\n if (isBefore) {\n wrapper.parentNode?.insertBefore(textNode, wrapper);\n } else {\n insertAfter(textNode, wrapper);\n }\n\n spot.textContent = SPECIAL_CHARS.ZERO_WIDTH_CHARACTER;\n return caretWasHere ? textNode : null;\n}\n\n/** Extracts typed text from caret spots, moving it to the paragraph level. */\nexport function extractTextFromCaretSpots(\n portalContainers: Map<string, PortalContainer>,\n trackCaret: boolean\n): TextExtractionResult {\n let movedTextNode: Text | null = null;\n\n for (const container of portalContainers.values()) {\n const wrapper = container.element.parentElement;\n if (!wrapper) {\n continue;\n }\n for (const child of Array.from(wrapper.children)) {\n const type = child.getAttribute('data-type');\n if (type === ElementType.CaretSpotBefore || type === ElementType.CaretSpotAfter) {\n const result = extractFromSpot(child as HTMLElement, trackCaret);\n if (result) {\n movedTextNode = result;\n }\n }\n }\n }\n\n return { movedTextNode };\n}\n"]}
@@ -0,0 +1,25 @@
1
+ /** Updates the mouse-down tracking flag used to skip selection normalization during drag. */
2
+ export declare function setMouseDown(value: boolean): void;
3
+ /** Returns whether the mouse is currently pressed. */
4
+ export declare function getMouseDown(): boolean;
5
+ /**
6
+ * Checks whether a node is inside a reference element's internals or directly
7
+ * on the contentEditable div (not inside a paragraph). These are non-typeable
8
+ * positions where the caret should not rest.
9
+ */
10
+ export declare function isNonTypeablePosition(node: Node | null): boolean;
11
+ /**
12
+ * Finds the reference wrapper element that contains the given node, if any.
13
+ * Returns null if the node is not inside a reference element.
14
+ */
15
+ export declare function findContainingReference(node: Node | null): HTMLElement | null;
16
+ /**
17
+ * Moves a collapsed caret out of non-typeable positions into the parent paragraph.
18
+ * Handles caret inside reference element internals (caret spots, token container)
19
+ * and caret on the contentEditable div itself (clicking on padding).
20
+ * Some browsers (notably Firefox) may place the caret in these positions on focus
21
+ * or imprecise clicks.
22
+ */
23
+ export declare function normalizeCollapsedCaret(selection: Selection | null): void;
24
+ /** Adjusts non-collapsed selection boundaries to exclude caret spot elements. */
25
+ export declare function normalizeSelection(selection: Selection | null, skipCaretSpots?: boolean): void;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caret-utils.d.ts","sourceRoot":"","sources":["../../../../src/prompt-input/core/caret-utils.ts"],"names":[],"mappings":"AAYA,6FAA6F;AAC7F,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAEjD;AAED,sDAAsD;AACtD,wBAAgB,YAAY,IAAI,OAAO,CAEtC;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,OAAO,CAgBhE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,WAAW,GAAG,IAAI,CAW7E;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,GAAG,IAAI,CA0DzE;AAED,iFAAiF;AACjF,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,EAAE,cAAc,GAAE,OAAe,GAAG,IAAI,CAyFrG"}