@nyaruka/temba-components 0.123.0 → 0.124.1

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 (146) hide show
  1. package/.github/copilot-instructions.md +22 -4
  2. package/CHANGELOG.md +21 -0
  3. package/TEST_OPTIMIZATION.md +158 -0
  4. package/demo/alert/example.html +65 -0
  5. package/demo/button/example.html +71 -0
  6. package/demo/chart/example.html +56 -0
  7. package/demo/checkbox/example.html +72 -0
  8. package/demo/compose/example.html +72 -0
  9. package/demo/data/images/gus.png +0 -0
  10. package/demo/data/images/purrington.jpg +0 -0
  11. package/demo/data/server/opened-tickets.json +40 -0
  12. package/demo/data/server/response-time.json +27 -0
  13. package/demo/datepicker/example.html +69 -0
  14. package/demo/dialog/example.html +107 -0
  15. package/demo/dropdown/example.html +99 -0
  16. package/demo/index.html +152 -430
  17. package/demo/misc/example.html +72 -0
  18. package/demo/progress/example.html +59 -0
  19. package/demo/select/drag-and-drop.html +142 -0
  20. package/demo/select/example.html +82 -0
  21. package/demo/select/multi.html +73 -0
  22. package/demo/slider/example.html +59 -0
  23. package/demo/sortable-list/example.html +99 -0
  24. package/demo/styles.css +183 -0
  25. package/demo/tabs/example.html +91 -0
  26. package/demo/textinput/completion.html +56 -0
  27. package/demo/textinput/example.html +61 -0
  28. package/dist/temba-components.js +323 -191
  29. package/dist/temba-components.js.map +1 -1
  30. package/out-tsc/src/chart/TembaChart.js +19 -16
  31. package/out-tsc/src/chart/TembaChart.js.map +1 -1
  32. package/out-tsc/src/fields/FieldManager.js +27 -34
  33. package/out-tsc/src/fields/FieldManager.js.map +1 -1
  34. package/out-tsc/src/flow/Editor.js +1 -1
  35. package/out-tsc/src/flow/Editor.js.map +1 -1
  36. package/out-tsc/src/list/SortableList.js +257 -60
  37. package/out-tsc/src/list/SortableList.js.map +1 -1
  38. package/out-tsc/src/omnibox/Omnibox.js +1 -1
  39. package/out-tsc/src/omnibox/Omnibox.js.map +1 -1
  40. package/out-tsc/src/select/Select.js +198 -38
  41. package/out-tsc/src/select/Select.js.map +1 -1
  42. package/out-tsc/src/thumbnail/Thumbnail.js +1 -1
  43. package/out-tsc/src/thumbnail/Thumbnail.js.map +1 -1
  44. package/out-tsc/src/webchat/WebChat.js +5 -2
  45. package/out-tsc/src/webchat/WebChat.js.map +1 -1
  46. package/out-tsc/test/temba-chart.test.js +1 -1
  47. package/out-tsc/test/temba-chart.test.js.map +1 -1
  48. package/out-tsc/test/temba-compose.test.js +6 -30
  49. package/out-tsc/test/temba-compose.test.js.map +1 -1
  50. package/out-tsc/test/temba-contact-chat.test.js +1 -2
  51. package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
  52. package/out-tsc/test/temba-dropdown.test.js +1 -1
  53. package/out-tsc/test/temba-dropdown.test.js.map +1 -1
  54. package/out-tsc/test/temba-flow-editor-node.test.js +273 -0
  55. package/out-tsc/test/temba-flow-editor-node.test.js.map +1 -0
  56. package/out-tsc/test/temba-flow-editor.test.js +244 -0
  57. package/out-tsc/test/temba-flow-editor.test.js.map +1 -0
  58. package/out-tsc/test/temba-flow-plumber.test.js +145 -0
  59. package/out-tsc/test/temba-flow-plumber.test.js.map +1 -0
  60. package/out-tsc/test/temba-flow-render.test.js +171 -0
  61. package/out-tsc/test/temba-flow-render.test.js.map +1 -0
  62. package/out-tsc/test/temba-omnibox.test.js +6 -3
  63. package/out-tsc/test/temba-omnibox.test.js.map +1 -1
  64. package/out-tsc/test/temba-select.test.js +183 -53
  65. package/out-tsc/test/temba-select.test.js.map +1 -1
  66. package/out-tsc/test/temba-sortable-list.test.js +91 -15
  67. package/out-tsc/test/temba-sortable-list.test.js.map +1 -1
  68. package/out-tsc/test/temba-toast.test.js +1 -2
  69. package/out-tsc/test/temba-toast.test.js.map +1 -1
  70. package/out-tsc/test/temba-utils-index.test.js +2 -2
  71. package/out-tsc/test/temba-utils-index.test.js.map +1 -1
  72. package/out-tsc/test/temba-webchat-lightbox-fix.test.js +42 -0
  73. package/out-tsc/test/temba-webchat-lightbox-fix.test.js.map +1 -0
  74. package/out-tsc/test/utils.test.js +58 -0
  75. package/out-tsc/test/utils.test.js.map +1 -1
  76. package/package.json +2 -3
  77. package/screenshots/truth/flow/editor-basic.png +0 -0
  78. package/screenshots/truth/list/fields-dragging.png +0 -0
  79. package/screenshots/truth/list/sortable-dragging.png +0 -0
  80. package/screenshots/truth/list/sortable-dropped.png +0 -0
  81. package/screenshots/truth/list/sortable.png +0 -0
  82. package/screenshots/truth/omnibox/selected.png +0 -0
  83. package/screenshots/truth/select/disabled-multi-selection.png +0 -0
  84. package/screenshots/truth/select/disabled-selection.png +0 -0
  85. package/screenshots/truth/select/disabled.png +0 -0
  86. package/screenshots/truth/select/embedded.png +0 -0
  87. package/screenshots/truth/select/empty-options.png +0 -0
  88. package/screenshots/truth/select/expression-selected.png +0 -0
  89. package/screenshots/truth/select/expressions.png +0 -0
  90. package/screenshots/truth/select/functions.png +0 -0
  91. package/screenshots/truth/select/local-options.png +0 -0
  92. package/screenshots/truth/select/multi-reorder-final.png +0 -0
  93. package/screenshots/truth/select/multi-reorder-initial.png +0 -0
  94. package/screenshots/truth/select/multi-with-endpoint.png +0 -0
  95. package/screenshots/truth/select/multiple-initial-values.png +0 -0
  96. package/screenshots/truth/select/remote-options.png +0 -0
  97. package/screenshots/truth/select/search-enabled.png +0 -0
  98. package/screenshots/truth/select/search-multi-no-matches.png +0 -0
  99. package/screenshots/truth/select/search-selected-focus.png +0 -0
  100. package/screenshots/truth/select/search-selected.png +0 -0
  101. package/screenshots/truth/select/search-with-selected.png +0 -0
  102. package/screenshots/truth/select/searching.png +0 -0
  103. package/screenshots/truth/select/selected-multi-maxitems-reached.png +0 -0
  104. package/screenshots/truth/select/selected-multi.png +0 -0
  105. package/screenshots/truth/select/selected-single.png +0 -0
  106. package/screenshots/truth/select/selection-clearable.png +0 -0
  107. package/screenshots/truth/select/static-initial-value.png +0 -0
  108. package/screenshots/truth/select/static-initial-via-selected.png +0 -0
  109. package/screenshots/truth/select/truncated-selection.png +0 -0
  110. package/screenshots/truth/select/with-placeholder.png +0 -0
  111. package/screenshots/truth/select/without-placeholder.png +0 -0
  112. package/screenshots/truth/templates/default.png +0 -0
  113. package/screenshots/truth/templates/unapproved.png +0 -0
  114. package/screenshots/truth/webchat/connected-state.png +0 -0
  115. package/src/chart/TembaChart.ts +20 -16
  116. package/src/fields/FieldManager.ts +30 -38
  117. package/src/flow/Editor.ts +1 -1
  118. package/src/list/SortableList.ts +291 -67
  119. package/src/omnibox/Omnibox.ts +1 -1
  120. package/src/select/Select.ts +213 -42
  121. package/src/thumbnail/Thumbnail.ts +1 -1
  122. package/src/webchat/WebChat.ts +5 -2
  123. package/test/temba-chart.test.ts +1 -1
  124. package/test/temba-compose.test.ts +11 -38
  125. package/test/temba-contact-chat.test.ts +4 -6
  126. package/test/temba-dropdown.test.ts +1 -1
  127. package/test/temba-flow-editor-node.test.ts +344 -0
  128. package/test/temba-flow-editor.test.ts +301 -0
  129. package/test/temba-flow-plumber.test.ts +189 -0
  130. package/test/temba-flow-render.test.ts +220 -0
  131. package/test/temba-omnibox.test.ts +7 -3
  132. package/test/temba-select.test.ts +247 -79
  133. package/test/temba-sortable-list.test.ts +108 -15
  134. package/test/temba-toast.test.ts +2 -2
  135. package/test/temba-utils-index.test.ts +2 -2
  136. package/test/temba-webchat-lightbox-fix.test.ts +57 -0
  137. package/test/utils.test.ts +88 -0
  138. package/web-test-runner.config.mjs +4 -2
  139. package/.storybook/main.js +0 -14
  140. package/.storybook/preview-head.html +0 -1
  141. package/.storybook/preview.js +0 -17
  142. package/demo/agents.html +0 -147
  143. package/demo/old.html +0 -573
  144. package/demo/remote.html +0 -3
  145. package/screenshots/truth/compose/attachments-with-files-focused.png +0 -0
  146. package/stories/temba-checkbox.stories.md +0 -37
@@ -7,7 +7,7 @@ import { RapidElement } from '../RapidElement';
7
7
  * A simple list that can be sorted by dragging
8
8
  */
9
9
  // how far we have to drag before it starts
10
- const DRAG_THRESHOLD = 5;
10
+ const DRAG_THRESHOLD = 2;
11
11
  export class SortableList extends RapidElement {
12
12
  static get styles() {
13
13
  return css `
@@ -17,18 +17,54 @@ export class SortableList extends RapidElement {
17
17
 
18
18
  .container {
19
19
  user-select: none;
20
+ position: relative;
21
+ }
22
+
23
+ .container.horizontal {
24
+ display: flex;
25
+ flex-wrap: wrap;
26
+ align-items: center;
20
27
  }
21
28
 
22
29
  .dragging {
23
30
  background: var(--color-selection);
24
31
  }
25
32
 
33
+ .dragged-item {
34
+ opacity: 0;
35
+ pointer-events: none;
36
+ }
37
+
26
38
  .sortable {
27
39
  transition: all 300ms ease-in-out;
28
40
  display: flex;
29
41
  padding: 0.4em 0;
30
42
  }
31
43
 
44
+ .container.horizontal .sortable {
45
+ padding: 0;
46
+ margin-right: 0.25em;
47
+ margin-bottom: 0.25em;
48
+ }
49
+
50
+ .drop-indicator {
51
+ position: absolute;
52
+ background: var(--color-primary-dark, #1c7cd6);
53
+ z-index: 1000;
54
+ pointer-events: none;
55
+ }
56
+
57
+ .container.horizontal .drop-indicator {
58
+ width: 2px;
59
+ margin-top: -5px;
60
+ padding-bottom: 10px;
61
+ }
62
+
63
+ .container:not(.horizontal) .drop-indicator {
64
+ height: 2px;
65
+ left: 0;
66
+ }
67
+
32
68
  .sortable:hover temba-icon {
33
69
  opacity: 1;
34
70
  cursor: move;
@@ -36,8 +72,14 @@ export class SortableList extends RapidElement {
36
72
 
37
73
  .ghost {
38
74
  position: absolute;
39
- opacity: 0.5;
75
+ opacity: 0.7;
40
76
  transition: none;
77
+ background: var(--color-background, white);
78
+ border: 1px solid var(--color-primary, #1c7cd6);
79
+ border-radius: 4px;
80
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
81
+ pointer-events: none;
82
+ z-index: 999;
41
83
  }
42
84
 
43
85
  .slot {
@@ -57,13 +99,19 @@ export class SortableList extends RapidElement {
57
99
  }
58
100
  constructor() {
59
101
  super();
102
+ this.horizontal = false;
60
103
  this.ghostElement = null;
61
104
  this.downEle = null;
62
105
  this.xOffset = 0;
63
106
  this.yOffset = 0;
64
107
  this.yDown = 0;
108
+ this.xDown = 0;
65
109
  this.draggingIdx = -1;
66
110
  this.draggingEle = null;
111
+ this.dropIndicator = null;
112
+ this.pendingDropIndex = -1;
113
+ this.pendingTargetElement = null;
114
+ this.clickBlocker = null;
67
115
  this.handleMouseMove = this.handleMouseMove.bind(this);
68
116
  this.handleMouseUp = this.handleMouseUp.bind(this);
69
117
  this.handleMouseDown = this.handleMouseDown.bind(this);
@@ -71,109 +119,249 @@ export class SortableList extends RapidElement {
71
119
  firstUpdated(_changedProperties) {
72
120
  super.firstUpdated(_changedProperties);
73
121
  }
74
- getIds() {
122
+ getSortableElements() {
75
123
  return this.shadowRoot
76
124
  .querySelector('slot')
77
125
  .assignedElements()
78
- .map((ele) => ele.id);
126
+ .filter((ele) => ele.classList.contains('sortable'));
127
+ }
128
+ getIds() {
129
+ return this.getSortableElements().map((ele) => ele.id);
79
130
  }
80
131
  getRowIndex(id) {
81
- return this.shadowRoot
82
- .querySelector('slot')
83
- .assignedElements()
84
- .findIndex((ele) => ele.id === id);
132
+ return this.getSortableElements().findIndex((ele) => ele.id === id);
85
133
  }
86
- getOverlappingElement(mouseY) {
87
- const ghostRect = this.ghostElement.getBoundingClientRect();
88
- const ele = this.shadowRoot
89
- .querySelector('slot')
90
- .assignedElements()
91
- .find((otherEle) => {
92
- const rect = otherEle.getBoundingClientRect();
93
- // don't return ourselves
94
- if (otherEle.id === this.ghostElement.id) {
95
- return false;
134
+ getDropTargetInfo(mouseX, mouseY) {
135
+ const elements = this.getSortableElements().filter((ele) => { var _a; return ele.id !== ((_a = this.draggingEle) === null || _a === void 0 ? void 0 : _a.id); });
136
+ if (elements.length === 0)
137
+ return null;
138
+ if (this.horizontal) {
139
+ // For horizontal layout, find the insertion point based on mouse X position
140
+ for (let i = 0; i < elements.length; i++) {
141
+ const ele = elements[i];
142
+ const rect = ele.getBoundingClientRect();
143
+ const centerX = rect.left + rect.width / 2;
144
+ if (mouseX < centerX) {
145
+ // Insert before this element
146
+ return { element: ele, insertAfter: false };
147
+ }
96
148
  }
97
- if (mouseY > this.yDown) {
98
- // moving down
99
- return ghostRect.top < rect.bottom && ghostRect.bottom > rect.bottom;
149
+ // If we're past all elements, insert after the last one
150
+ return {
151
+ element: elements[elements.length - 1],
152
+ insertAfter: true
153
+ };
154
+ }
155
+ else {
156
+ // For vertical layout, find the insertion point based on mouse Y position
157
+ for (let i = 0; i < elements.length; i++) {
158
+ const ele = elements[i];
159
+ const rect = ele.getBoundingClientRect();
160
+ const centerY = rect.top + rect.height / 2;
161
+ if (mouseY < centerY) {
162
+ // Insert before this element
163
+ return { element: ele, insertAfter: false };
164
+ }
165
+ }
166
+ // If we're past all elements, insert after the last one
167
+ return {
168
+ element: elements[elements.length - 1],
169
+ insertAfter: true
170
+ };
171
+ }
172
+ }
173
+ showDropIndicator(targetElement, insertAfter) {
174
+ this.hideDropIndicator();
175
+ if (!targetElement)
176
+ return;
177
+ const container = this.shadowRoot.querySelector('.container');
178
+ this.dropIndicator = document.createElement('div');
179
+ this.dropIndicator.className = 'drop-indicator';
180
+ const targetRect = targetElement.getBoundingClientRect();
181
+ const containerRect = container.getBoundingClientRect();
182
+ if (this.horizontal) {
183
+ // For horizontal layout, show vertical line
184
+ this.dropIndicator.style.height = targetRect.height + 'px';
185
+ this.dropIndicator.style.top = targetRect.top - containerRect.top + 'px';
186
+ if (insertAfter) {
187
+ // Show line after target
188
+ this.dropIndicator.style.left =
189
+ targetRect.right - containerRect.left + 'px';
190
+ }
191
+ else {
192
+ // Show line before target
193
+ this.dropIndicator.style.left =
194
+ targetRect.left - containerRect.left + 'px';
195
+ }
196
+ }
197
+ else {
198
+ // For vertical layout, show horizontal line
199
+ this.dropIndicator.style.width = targetRect.width + 'px';
200
+ this.dropIndicator.style.left =
201
+ targetRect.left - containerRect.left + 'px';
202
+ if (insertAfter) {
203
+ // Show line after target
204
+ this.dropIndicator.style.top =
205
+ targetRect.bottom - containerRect.top + 'px';
100
206
  }
101
207
  else {
102
- // moving up
103
- return rect.top < ghostRect.bottom && rect.bottom > ghostRect.bottom;
208
+ // Show line before target
209
+ this.dropIndicator.style.top =
210
+ targetRect.top - containerRect.top + 'px';
104
211
  }
105
- });
106
- return ele;
212
+ }
213
+ container.appendChild(this.dropIndicator);
214
+ }
215
+ hideDropIndicator() {
216
+ if (this.dropIndicator) {
217
+ this.dropIndicator.remove();
218
+ this.dropIndicator = null;
219
+ }
107
220
  }
108
221
  handleMouseDown(event) {
109
222
  let ele = event.target;
110
223
  ele = ele.closest('.sortable');
111
224
  if (ele) {
225
+ event.preventDefault();
226
+ event.stopPropagation();
112
227
  this.downEle = ele;
113
228
  this.draggingId = ele.id;
114
229
  this.draggingIdx = this.getRowIndex(ele.id);
115
230
  this.draggingEle = ele;
116
- this.xOffset = event.clientX - ele.offsetLeft;
117
- this.yOffset = event.clientY - ele.offsetTop;
231
+ // Use getBoundingClientRect for accurate offsets
232
+ const rect = ele.getBoundingClientRect();
233
+ this.xOffset = event.clientX - rect.left;
234
+ this.yOffset = event.clientY - rect.top;
118
235
  this.yDown = event.clientY;
236
+ this.xDown = event.clientX;
119
237
  document.addEventListener('mousemove', this.handleMouseMove);
120
238
  document.addEventListener('mouseup', this.handleMouseUp);
121
239
  }
122
240
  }
123
241
  handleMouseMove(event) {
124
- const scrollTop = this.shadowRoot
125
- .querySelector('slot')
126
- .assignedElements()[0].parentElement.scrollTop;
127
242
  if (!this.ghostElement &&
128
243
  this.downEle &&
129
- Math.abs(event.clientY - this.yDown) > DRAG_THRESHOLD) {
244
+ (Math.abs(event.clientY - this.yDown) > DRAG_THRESHOLD ||
245
+ Math.abs(event.clientX - this.xDown) > DRAG_THRESHOLD)) {
130
246
  this.fireCustomEvent(CustomEventType.DragStart, {
131
247
  id: this.downEle.id
132
248
  });
133
249
  this.ghostElement = this.downEle.cloneNode(true);
134
250
  this.ghostElement.classList.add('ghost');
135
- const computedStyle = getComputedStyle(this.downEle);
136
- this.ghostElement.style.width =
137
- this.downEle.clientWidth -
138
- parseFloat(computedStyle.paddingLeft) -
139
- parseFloat(computedStyle.paddingRight) +
140
- 'px';
141
- const container = this.shadowRoot.querySelector('.container');
142
- container.appendChild(this.ghostElement);
143
- this.downEle = null;
251
+ // dim the original element while dragging
252
+ this.downEle.style.pointerEvents = 'none';
253
+ this.downEle.style.opacity = '0.5';
254
+ const rect = this.downEle.getBoundingClientRect();
255
+ this.ghostElement.style.transition = 'transform 300ms linear';
256
+ this.ghostElement.style.width = rect.width + 'px';
257
+ this.ghostElement.style.height = rect.height + 'px';
258
+ this.ghostElement.style.position = 'fixed';
259
+ this.ghostElement.style.left = event.clientX - this.xOffset + 'px';
260
+ this.ghostElement.style.top = event.clientY - this.yOffset + 'px';
261
+ this.ghostElement.style.pointerEvents = 'none';
262
+ this.ghostElement.style.border =
263
+ '1px solid var(--color-primary, #1c7cd6)';
264
+ this.ghostElement.style.zIndex = '99999';
265
+ this.ghostElement.style.background = '#fff';
266
+ this.ghostElement.style.opacity = '0.7';
267
+ this.ghostElement.style.boxShadow = '0 2px 8px rgba(0, 0, 0, 0.2)';
268
+ this.ghostElement.style.borderRadius = 'var(--curvature)';
269
+ // allow component to customize the ghost node
270
+ if (this.prepareGhost) {
271
+ this.prepareGhost(this.ghostElement);
272
+ }
273
+ document.body.appendChild(this.ghostElement);
274
+ // this.downEle = null;
275
+ // Add global click blocker when drag starts
276
+ if (!this.clickBlocker) {
277
+ this.clickBlocker = (e) => {
278
+ e.stopPropagation();
279
+ e.preventDefault();
280
+ };
281
+ // Use capture phase to intercept clicks before they reach any elements
282
+ document.addEventListener('click', this.clickBlocker, true);
283
+ }
144
284
  }
145
285
  if (this.ghostElement) {
146
286
  this.ghostElement.style.left = event.clientX - this.xOffset + 'px';
147
- this.ghostElement.style.top =
148
- event.clientY - this.yOffset - scrollTop + 'px';
149
- const other = this.getOverlappingElement(event.clientY);
150
- if (other) {
151
- const otherIdx = this.getRowIndex(other.id);
152
- const dragId = this.ghostElement.id;
153
- const otherId = other.id;
154
- this.fireCustomEvent(CustomEventType.OrderChanged, {
155
- from: dragId,
156
- to: otherId,
157
- fromIdx: this.draggingIdx,
158
- toIdx: otherIdx
159
- });
160
- // TODO: Dont do swapping, just send the full order?
161
- this.draggingIdx = otherIdx;
162
- this.draggingId = otherId;
287
+ this.ghostElement.style.top = event.clientY - this.yOffset + 'px';
288
+ const targetInfo = this.getDropTargetInfo(event.clientX, event.clientY);
289
+ if (targetInfo) {
290
+ const { element: targetElement, insertAfter } = targetInfo;
291
+ const targetIdx = this.getRowIndex(targetElement.id);
292
+ const originalDragIdx = this.getRowIndex(this.draggingEle.id);
293
+ // Calculate the intended drop index
294
+ let dropIdx = targetIdx;
295
+ if (insertAfter) {
296
+ dropIdx += 1;
297
+ }
298
+ // Adjust dropIdx if dragging forward in the list
299
+ if (originalDragIdx < dropIdx) {
300
+ dropIdx -= 1;
301
+ }
302
+ // Store pending drop info but don't fire event yet
303
+ this.dropTargetId = targetElement.id;
304
+ this.pendingDropIndex = dropIdx;
305
+ this.pendingTargetElement = targetElement;
306
+ // Show drop indicator
307
+ this.showDropIndicator(targetElement, insertAfter);
308
+ }
309
+ else {
310
+ this.hideDropIndicator();
311
+ this.dropTargetId = null;
312
+ this.pendingDropIndex = -1;
313
+ this.pendingTargetElement = null;
163
314
  }
164
315
  }
165
316
  }
166
- handleMouseUp() {
167
- if (this.draggingId) {
317
+ handleMouseUp(evt) {
318
+ if (this.draggingId && this.ghostElement) {
319
+ evt.preventDefault();
320
+ evt.stopPropagation();
321
+ // restore visibility of the dragged item
322
+ if (this.downEle) {
323
+ this.downEle.style.pointerEvents = '';
324
+ this.downEle.style.opacity = '1';
325
+ }
326
+ // fire the order changed event only when dropped if we have a valid drop position
327
+ if (this.pendingDropIndex >= 0 && this.pendingTargetElement) {
328
+ const originalDragIdx = this.getRowIndex(this.draggingEle.id);
329
+ // use swap-based logic - report which indexes need to be swapped
330
+ const fromIdx = originalDragIdx;
331
+ const toIdx = this.pendingDropIndex;
332
+ // only fire if the position actually changed
333
+ if (fromIdx !== toIdx) {
334
+ this.fireCustomEvent(CustomEventType.OrderChanged, {
335
+ swap: [fromIdx, toIdx]
336
+ });
337
+ }
338
+ }
168
339
  this.fireCustomEvent(CustomEventType.DragStop, {
169
340
  id: this.draggingId
170
341
  });
171
342
  this.draggingId = null;
343
+ this.dropTargetId = null;
172
344
  this.downEle = null;
345
+ this.pendingDropIndex = -1;
346
+ this.pendingTargetElement = null;
173
347
  if (this.ghostElement) {
174
- this.ghostElement.remove();
348
+ // Remove from body if present
349
+ if (this.ghostElement.parentNode) {
350
+ this.ghostElement.parentNode.removeChild(this.ghostElement);
351
+ }
175
352
  this.ghostElement = null;
176
353
  }
354
+ this.hideDropIndicator();
355
+ // Keep the click blocker active for a short time after drop
356
+ if (this.clickBlocker) {
357
+ // We'll clean it up after a timeout
358
+ setTimeout(() => {
359
+ if (this.clickBlocker) {
360
+ document.removeEventListener('click', this.clickBlocker, true);
361
+ this.clickBlocker = null;
362
+ }
363
+ }, 100);
364
+ }
177
365
  }
178
366
  document.removeEventListener('mousemove', this.handleMouseMove);
179
367
  document.removeEventListener('mouseup', this.handleMouseUp);
@@ -181,7 +369,7 @@ export class SortableList extends RapidElement {
181
369
  }
182
370
  render() {
183
371
  return html `
184
- <div class="container">
372
+ <div class="container ${this.horizontal ? 'horizontal' : ''}">
185
373
  <slot @mousedown=${this.handleMouseDown}></slot>
186
374
  </div>
187
375
  `;
@@ -190,4 +378,13 @@ export class SortableList extends RapidElement {
190
378
  __decorate([
191
379
  property({ type: String })
192
380
  ], SortableList.prototype, "draggingId", void 0);
381
+ __decorate([
382
+ property({ type: Boolean })
383
+ ], SortableList.prototype, "horizontal", void 0);
384
+ __decorate([
385
+ property({ type: String })
386
+ ], SortableList.prototype, "dropTargetId", void 0);
387
+ __decorate([
388
+ property({ attribute: false })
389
+ ], SortableList.prototype, "prepareGhost", void 0);
193
390
  //# sourceMappingURL=SortableList.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SortableList.js","sourceRoot":"","sources":["../../../src/list/SortableList.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, PropertyValueMap, TemplateResult } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { CustomEventType } from '../interfaces';\nimport { RapidElement } from '../RapidElement';\n\n/**\n * A simple list that can be sorted by dragging\n */\n\n// how far we have to drag before it starts\nconst DRAG_THRESHOLD = 5;\nexport class SortableList extends RapidElement {\n static get styles() {\n return css`\n :host {\n margin: auto;\n }\n\n .container {\n user-select: none;\n }\n\n .dragging {\n background: var(--color-selection);\n }\n\n .sortable {\n transition: all 300ms ease-in-out;\n display: flex;\n padding: 0.4em 0;\n }\n\n .sortable:hover temba-icon {\n opacity: 1;\n cursor: move;\n }\n\n .ghost {\n position: absolute;\n opacity: 0.5;\n transition: none;\n }\n\n .slot {\n flex-grow: 1;\n }\n\n slot > * {\n user-select: none;\n }\n\n temba-icon {\n opacity: 0.1;\n padding: 0.2em 0.5em;\n transition: all 300ms ease-in-out;\n }\n `;\n }\n\n @property({ type: String })\n draggingId: string;\n\n ghostElement: HTMLDivElement = null;\n downEle: HTMLDivElement = null;\n xOffset = 0;\n yOffset = 0;\n yDown = 0;\n\n draggingIdx = -1;\n draggingEle = null;\n\n public constructor() {\n super();\n this.handleMouseMove = this.handleMouseMove.bind(this);\n this.handleMouseUp = this.handleMouseUp.bind(this);\n this.handleMouseDown = this.handleMouseDown.bind(this);\n }\n\n protected firstUpdated(\n _changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.firstUpdated(_changedProperties);\n }\n\n public getIds() {\n return this.shadowRoot\n .querySelector('slot')\n .assignedElements()\n .map((ele) => ele.id);\n }\n\n private getRowIndex(id: string): number {\n return this.shadowRoot\n .querySelector('slot')\n .assignedElements()\n .findIndex((ele) => ele.id === id);\n }\n\n private getOverlappingElement(mouseY: number): HTMLDivElement {\n const ghostRect = this.ghostElement.getBoundingClientRect();\n\n const ele = this.shadowRoot\n .querySelector('slot')\n .assignedElements()\n .find((otherEle) => {\n const rect = otherEle.getBoundingClientRect();\n\n // don't return ourselves\n if (otherEle.id === this.ghostElement.id) {\n return false;\n }\n\n if (mouseY > this.yDown) {\n // moving down\n return ghostRect.top < rect.bottom && ghostRect.bottom > rect.bottom;\n } else {\n // moving up\n return rect.top < ghostRect.bottom && rect.bottom > ghostRect.bottom;\n }\n });\n return ele as HTMLDivElement;\n }\n\n private handleMouseDown(event: MouseEvent) {\n let ele = event.target as HTMLDivElement;\n ele = ele.closest('.sortable');\n if (ele) {\n this.downEle = ele;\n this.draggingId = ele.id;\n this.draggingIdx = this.getRowIndex(ele.id);\n this.draggingEle = ele;\n\n this.xOffset = event.clientX - ele.offsetLeft;\n this.yOffset = event.clientY - ele.offsetTop;\n this.yDown = event.clientY;\n\n document.addEventListener('mousemove', this.handleMouseMove);\n document.addEventListener('mouseup', this.handleMouseUp);\n }\n }\n\n private handleMouseMove(event: MouseEvent) {\n const scrollTop = this.shadowRoot\n .querySelector('slot')\n .assignedElements()[0].parentElement.scrollTop;\n\n if (\n !this.ghostElement &&\n this.downEle &&\n Math.abs(event.clientY - this.yDown) > DRAG_THRESHOLD\n ) {\n this.fireCustomEvent(CustomEventType.DragStart, {\n id: this.downEle.id\n });\n\n this.ghostElement = this.downEle.cloneNode(true) as HTMLDivElement;\n this.ghostElement.classList.add('ghost');\n\n const computedStyle = getComputedStyle(this.downEle);\n\n this.ghostElement.style.width =\n this.downEle.clientWidth -\n parseFloat(computedStyle.paddingLeft) -\n parseFloat(computedStyle.paddingRight) +\n 'px';\n const container = this.shadowRoot.querySelector('.container');\n\n container.appendChild(this.ghostElement);\n\n this.downEle = null;\n }\n\n if (this.ghostElement) {\n this.ghostElement.style.left = event.clientX - this.xOffset + 'px';\n this.ghostElement.style.top =\n event.clientY - this.yOffset - scrollTop + 'px';\n\n const other = this.getOverlappingElement(event.clientY);\n if (other) {\n const otherIdx = this.getRowIndex(other.id);\n const dragId = this.ghostElement.id;\n const otherId = other.id;\n\n this.fireCustomEvent(CustomEventType.OrderChanged, {\n from: dragId,\n to: otherId,\n fromIdx: this.draggingIdx,\n toIdx: otherIdx\n });\n\n // TODO: Dont do swapping, just send the full order?\n this.draggingIdx = otherIdx;\n this.draggingId = otherId;\n }\n }\n }\n\n private handleMouseUp() {\n if (this.draggingId) {\n this.fireCustomEvent(CustomEventType.DragStop, {\n id: this.draggingId\n });\n\n this.draggingId = null;\n this.downEle = null;\n\n if (this.ghostElement) {\n this.ghostElement.remove();\n this.ghostElement = null;\n }\n }\n document.removeEventListener('mousemove', this.handleMouseMove);\n document.removeEventListener('mouseup', this.handleMouseUp);\n this.dispatchEvent(new Event('change'));\n }\n\n public render(): TemplateResult {\n return html`\n <div class=\"container\">\n <slot @mousedown=${this.handleMouseDown}></slot>\n </div>\n `;\n }\n}\n"]}
1
+ {"version":3,"file":"SortableList.js","sourceRoot":"","sources":["../../../src/list/SortableList.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, PropertyValueMap, TemplateResult } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { CustomEventType } from '../interfaces';\nimport { RapidElement } from '../RapidElement';\n\n/**\n * A simple list that can be sorted by dragging\n */\n\n// how far we have to drag before it starts\nconst DRAG_THRESHOLD = 2;\nexport class SortableList extends RapidElement {\n static get styles() {\n return css`\n :host {\n margin: auto;\n }\n\n .container {\n user-select: none;\n position: relative;\n }\n\n .container.horizontal {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n }\n\n .dragging {\n background: var(--color-selection);\n }\n\n .dragged-item {\n opacity: 0;\n pointer-events: none;\n }\n\n .sortable {\n transition: all 300ms ease-in-out;\n display: flex;\n padding: 0.4em 0;\n }\n\n .container.horizontal .sortable {\n padding: 0;\n margin-right: 0.25em;\n margin-bottom: 0.25em;\n }\n\n .drop-indicator {\n position: absolute;\n background: var(--color-primary-dark, #1c7cd6);\n z-index: 1000;\n pointer-events: none;\n }\n\n .container.horizontal .drop-indicator {\n width: 2px;\n margin-top: -5px;\n padding-bottom: 10px;\n }\n\n .container:not(.horizontal) .drop-indicator {\n height: 2px;\n left: 0;\n }\n\n .sortable:hover temba-icon {\n opacity: 1;\n cursor: move;\n }\n\n .ghost {\n position: absolute;\n opacity: 0.7;\n transition: none;\n background: var(--color-background, white);\n border: 1px solid var(--color-primary, #1c7cd6);\n border-radius: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n pointer-events: none;\n z-index: 999;\n }\n\n .slot {\n flex-grow: 1;\n }\n\n slot > * {\n user-select: none;\n }\n\n temba-icon {\n opacity: 0.1;\n padding: 0.2em 0.5em;\n transition: all 300ms ease-in-out;\n }\n `;\n }\n\n @property({ type: String })\n draggingId: string;\n\n @property({ type: Boolean })\n horizontal: boolean = false;\n\n @property({ type: String })\n dropTargetId: string;\n\n /**\n * Optional callback to allow parent components to customize the ghost node.\n * Called after the ghost node is cloned but before it is appended to the DOM.\n */\n @property({ attribute: false })\n prepareGhost?: (ghost: HTMLElement) => void;\n\n ghostElement: HTMLDivElement = null;\n downEle: HTMLDivElement = null;\n xOffset = 0;\n yOffset = 0;\n yDown = 0;\n xDown = 0;\n\n draggingIdx = -1;\n draggingEle = null;\n dropIndicator: HTMLDivElement = null;\n pendingDropIndex = -1;\n pendingTargetElement: HTMLElement = null;\n\n private clickBlocker: ((e: MouseEvent) => void) | null = null;\n\n public constructor() {\n super();\n this.handleMouseMove = this.handleMouseMove.bind(this);\n this.handleMouseUp = this.handleMouseUp.bind(this);\n this.handleMouseDown = this.handleMouseDown.bind(this);\n }\n\n protected firstUpdated(\n _changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.firstUpdated(_changedProperties);\n }\n\n private getSortableElements(): Element[] {\n return this.shadowRoot\n .querySelector('slot')\n .assignedElements()\n .filter((ele) => ele.classList.contains('sortable'));\n }\n\n public getIds() {\n return this.getSortableElements().map((ele) => ele.id);\n }\n\n private getRowIndex(id: string): number {\n return this.getSortableElements().findIndex((ele) => ele.id === id);\n }\n\n private getDropTargetInfo(\n mouseX: number,\n mouseY: number\n ): { element: HTMLDivElement; insertAfter: boolean } | null {\n const elements = this.getSortableElements().filter(\n (ele) => ele.id !== this.draggingEle?.id\n );\n\n if (elements.length === 0) return null;\n\n if (this.horizontal) {\n // For horizontal layout, find the insertion point based on mouse X position\n for (let i = 0; i < elements.length; i++) {\n const ele = elements[i];\n const rect = ele.getBoundingClientRect();\n const centerX = rect.left + rect.width / 2;\n\n if (mouseX < centerX) {\n // Insert before this element\n return { element: ele as HTMLDivElement, insertAfter: false };\n }\n }\n // If we're past all elements, insert after the last one\n return {\n element: elements[elements.length - 1] as HTMLDivElement,\n insertAfter: true\n };\n } else {\n // For vertical layout, find the insertion point based on mouse Y position\n for (let i = 0; i < elements.length; i++) {\n const ele = elements[i];\n const rect = ele.getBoundingClientRect();\n const centerY = rect.top + rect.height / 2;\n\n if (mouseY < centerY) {\n // Insert before this element\n return { element: ele as HTMLDivElement, insertAfter: false };\n }\n }\n // If we're past all elements, insert after the last one\n return {\n element: elements[elements.length - 1] as HTMLDivElement,\n insertAfter: true\n };\n }\n }\n\n private showDropIndicator(targetElement: HTMLElement, insertAfter: boolean) {\n this.hideDropIndicator();\n\n if (!targetElement) return;\n\n const container = this.shadowRoot.querySelector('.container');\n this.dropIndicator = document.createElement('div');\n this.dropIndicator.className = 'drop-indicator';\n\n const targetRect = targetElement.getBoundingClientRect();\n const containerRect = container.getBoundingClientRect();\n\n if (this.horizontal) {\n // For horizontal layout, show vertical line\n this.dropIndicator.style.height = targetRect.height + 'px';\n this.dropIndicator.style.top = targetRect.top - containerRect.top + 'px';\n\n if (insertAfter) {\n // Show line after target\n this.dropIndicator.style.left =\n targetRect.right - containerRect.left + 'px';\n } else {\n // Show line before target\n this.dropIndicator.style.left =\n targetRect.left - containerRect.left + 'px';\n }\n } else {\n // For vertical layout, show horizontal line\n this.dropIndicator.style.width = targetRect.width + 'px';\n this.dropIndicator.style.left =\n targetRect.left - containerRect.left + 'px';\n\n if (insertAfter) {\n // Show line after target\n this.dropIndicator.style.top =\n targetRect.bottom - containerRect.top + 'px';\n } else {\n // Show line before target\n this.dropIndicator.style.top =\n targetRect.top - containerRect.top + 'px';\n }\n }\n\n container.appendChild(this.dropIndicator);\n }\n\n private hideDropIndicator() {\n if (this.dropIndicator) {\n this.dropIndicator.remove();\n this.dropIndicator = null;\n }\n }\n\n private handleMouseDown(event: MouseEvent) {\n let ele = event.target as HTMLDivElement;\n ele = ele.closest('.sortable');\n if (ele) {\n event.preventDefault();\n event.stopPropagation();\n\n this.downEle = ele;\n this.draggingId = ele.id;\n this.draggingIdx = this.getRowIndex(ele.id);\n this.draggingEle = ele;\n\n // Use getBoundingClientRect for accurate offsets\n const rect = ele.getBoundingClientRect();\n this.xOffset = event.clientX - rect.left;\n this.yOffset = event.clientY - rect.top;\n this.yDown = event.clientY;\n this.xDown = event.clientX;\n\n document.addEventListener('mousemove', this.handleMouseMove);\n document.addEventListener('mouseup', this.handleMouseUp);\n }\n }\n\n private handleMouseMove(event: MouseEvent) {\n if (\n !this.ghostElement &&\n this.downEle &&\n (Math.abs(event.clientY - this.yDown) > DRAG_THRESHOLD ||\n Math.abs(event.clientX - this.xDown) > DRAG_THRESHOLD)\n ) {\n this.fireCustomEvent(CustomEventType.DragStart, {\n id: this.downEle.id\n });\n\n this.ghostElement = this.downEle.cloneNode(true) as HTMLDivElement;\n this.ghostElement.classList.add('ghost');\n\n // dim the original element while dragging\n this.downEle.style.pointerEvents = 'none';\n this.downEle.style.opacity = '0.5';\n\n const rect = this.downEle.getBoundingClientRect();\n this.ghostElement.style.transition = 'transform 300ms linear';\n\n this.ghostElement.style.width = rect.width + 'px';\n this.ghostElement.style.height = rect.height + 'px';\n this.ghostElement.style.position = 'fixed';\n this.ghostElement.style.left = event.clientX - this.xOffset + 'px';\n this.ghostElement.style.top = event.clientY - this.yOffset + 'px';\n this.ghostElement.style.pointerEvents = 'none';\n this.ghostElement.style.border =\n '1px solid var(--color-primary, #1c7cd6)';\n this.ghostElement.style.zIndex = '99999';\n this.ghostElement.style.background = '#fff';\n this.ghostElement.style.opacity = '0.7';\n this.ghostElement.style.boxShadow = '0 2px 8px rgba(0, 0, 0, 0.2)';\n this.ghostElement.style.borderRadius = 'var(--curvature)';\n\n // allow component to customize the ghost node\n if (this.prepareGhost) {\n this.prepareGhost(this.ghostElement);\n }\n\n document.body.appendChild(this.ghostElement);\n\n // this.downEle = null;\n\n // Add global click blocker when drag starts\n if (!this.clickBlocker) {\n this.clickBlocker = (e: MouseEvent) => {\n e.stopPropagation();\n e.preventDefault();\n };\n // Use capture phase to intercept clicks before they reach any elements\n document.addEventListener('click', this.clickBlocker, true);\n }\n }\n\n if (this.ghostElement) {\n this.ghostElement.style.left = event.clientX - this.xOffset + 'px';\n this.ghostElement.style.top = event.clientY - this.yOffset + 'px';\n\n const targetInfo = this.getDropTargetInfo(event.clientX, event.clientY);\n if (targetInfo) {\n const { element: targetElement, insertAfter } = targetInfo;\n const targetIdx = this.getRowIndex(targetElement.id);\n const originalDragIdx = this.getRowIndex(this.draggingEle.id);\n\n // Calculate the intended drop index\n let dropIdx = targetIdx;\n if (insertAfter) {\n dropIdx += 1;\n }\n\n // Adjust dropIdx if dragging forward in the list\n if (originalDragIdx < dropIdx) {\n dropIdx -= 1;\n }\n\n // Store pending drop info but don't fire event yet\n this.dropTargetId = targetElement.id;\n this.pendingDropIndex = dropIdx;\n this.pendingTargetElement = targetElement;\n\n // Show drop indicator\n this.showDropIndicator(targetElement, insertAfter);\n } else {\n this.hideDropIndicator();\n this.dropTargetId = null;\n this.pendingDropIndex = -1;\n this.pendingTargetElement = null;\n }\n }\n }\n\n private handleMouseUp(evt: MouseEvent) {\n if (this.draggingId && this.ghostElement) {\n evt.preventDefault();\n evt.stopPropagation();\n\n // restore visibility of the dragged item\n\n if (this.downEle) {\n this.downEle.style.pointerEvents = '';\n this.downEle.style.opacity = '1';\n }\n\n // fire the order changed event only when dropped if we have a valid drop position\n if (this.pendingDropIndex >= 0 && this.pendingTargetElement) {\n const originalDragIdx = this.getRowIndex(this.draggingEle.id);\n\n // use swap-based logic - report which indexes need to be swapped\n const fromIdx = originalDragIdx;\n const toIdx = this.pendingDropIndex;\n\n // only fire if the position actually changed\n if (fromIdx !== toIdx) {\n this.fireCustomEvent(CustomEventType.OrderChanged, {\n swap: [fromIdx, toIdx]\n });\n }\n }\n\n this.fireCustomEvent(CustomEventType.DragStop, {\n id: this.draggingId\n });\n\n this.draggingId = null;\n this.dropTargetId = null;\n this.downEle = null;\n this.pendingDropIndex = -1;\n this.pendingTargetElement = null;\n\n if (this.ghostElement) {\n // Remove from body if present\n if (this.ghostElement.parentNode) {\n this.ghostElement.parentNode.removeChild(this.ghostElement);\n }\n this.ghostElement = null;\n }\n\n this.hideDropIndicator();\n\n // Keep the click blocker active for a short time after drop\n if (this.clickBlocker) {\n // We'll clean it up after a timeout\n setTimeout(() => {\n if (this.clickBlocker) {\n document.removeEventListener('click', this.clickBlocker, true);\n this.clickBlocker = null;\n }\n }, 100);\n }\n }\n document.removeEventListener('mousemove', this.handleMouseMove);\n document.removeEventListener('mouseup', this.handleMouseUp);\n this.dispatchEvent(new Event('change'));\n }\n\n public render(): TemplateResult {\n return html`\n <div class=\"container ${this.horizontal ? 'horizontal' : ''}\">\n <slot @mousedown=${this.handleMouseDown}></slot>\n </div>\n `;\n }\n}\n"]}
@@ -72,7 +72,7 @@ export class Omnibox extends Select {
72
72
  renderSelectedItemDefault(option) {
73
73
  return html `
74
74
  <div
75
- style="flex:1 1 auto; display: flex; align-items: stretch; color: var(--color-text-dark); font-size: 12px;"
75
+ style="flex:1 1 auto; text-overflow:ellipsis; overflow:hidden; white-space:nowrap; display: flex; align-items: stretch; color: var(--color-text-dark); font-size: 12px;"
76
76
  >
77
77
  <div style="align-self: center; padding: 0px 7px; color: #bbb">
78
78
  ${this.getIcon(option)}
@@ -1 +1 @@
1
- {"version":3,"file":"Omnibox.js","sourceRoot":"","sources":["../../../src/omnibox/Omnibox.ts"],"names":[],"mappings":"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","sourcesContent":["import { TemplateResult, html, PropertyValues } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { styleMap } from 'lit-html/directives/style-map.js';\nimport { Select, SelectOption } from '../select/Select';\nimport { Icon } from '../vectoricon';\n\nenum OmniType {\n Group = 'group',\n Contact = 'contact'\n}\n\nexport interface OmniOption extends SelectOption {\n id: string;\n name: string;\n type: OmniType;\n urn?: string;\n count?: number;\n contact?: string;\n scheme?: string;\n}\n\nconst postNameStyle = {\n color: 'var(--color-text-dark)',\n padding: '0px 6px',\n fontSize: '12px'\n};\n\nexport class Omnibox extends Select<OmniOption> {\n @property({ type: String })\n valueKey = 'uuid';\n\n @property({ type: Boolean })\n groups = false;\n\n @property({ type: Boolean })\n contacts = false;\n\n @property({ type: String })\n placeholder = 'Select recipients';\n\n @property({ type: Boolean })\n multi = true;\n\n @property({ type: Boolean })\n searchable = true;\n\n @property({ type: Boolean })\n searchOnFocus = true;\n\n @property({ type: Boolean })\n queryParam = 'search';\n\n public update(changes: PropertyValues): void {\n super.update(changes);\n\n if (\n (changes.has('groups') || changes.has('contacts')) &&\n (this.groups || this.contacts)\n ) {\n let types = '&types=';\n if (this.groups) {\n types += 'g';\n }\n\n if (this.contacts) {\n types += 'c';\n }\n\n this.endpoint = this.endpoint + types;\n }\n }\n\n /** An option in the drop down */\n public renderOptionDefault(option: OmniOption): TemplateResult {\n return html`\n <div style=\"display:flex;\">\n <div style=\"margin-right: 8px\">${this.getIcon(option)}</div>\n <div style=\"flex: 1\">${option.name}</div>\n <div\n style=\"background: rgba(50, 50, 50, 0.15); margin-left: 5px; display: flex; align-items: center; border-radius: 4px\"\n >\n ${this.getPostName(option)}\n </div>\n </div>\n `;\n }\n\n private getPostName(option: OmniOption): TemplateResult {\n const style = { ...postNameStyle };\n\n if (option.urn && option.type === OmniType.Contact) {\n if (option.urn !== option.name) {\n return html`<div style=${styleMap(style)}>${option.urn}</div>`;\n }\n }\n\n if (option.type === OmniType.Group) {\n return html`\n <div style=${styleMap(style)}>${option.count.toLocaleString()}</div>\n `;\n }\n\n return null;\n }\n\n /** Selection in the multi-select select box */\n public renderSelectedItemDefault(option: OmniOption): TemplateResult {\n return html`\n <div\n style=\"flex:1 1 auto; display: flex; align-items: stretch; color: var(--color-text-dark); font-size: 12px;\"\n >\n <div style=\"align-self: center; padding: 0px 7px; color: #bbb\">\n ${this.getIcon(option)}\n </div>\n <div\n class=\"name\"\n style=\"align-self: center; padding: 0px; font-size: 12px;\"\n >\n ${option.name}\n </div>\n <div\n style=\"background: rgba(100, 100, 100, 0.05); border-left: 1px solid rgba(100, 100, 100, 0.1); margin-left: 12px; display: flex; align-items: center\"\n >\n ${this.getPostName(option)}\n </div>\n </div>\n `;\n }\n\n private getIcon(option: OmniOption): TemplateResult {\n if (option.type === OmniType.Group) {\n return html`<temba-icon name=\"${Icon.group}\"></temba-icon>`;\n }\n\n if (option.type === OmniType.Contact) {\n return html`<temba-icon name=\"${Icon.contact}\"></temba-icon>`;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"Omnibox.js","sourceRoot":"","sources":["../../../src/omnibox/Omnibox.ts"],"names":[],"mappings":"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","sourcesContent":["import { TemplateResult, html, PropertyValues } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { styleMap } from 'lit-html/directives/style-map.js';\nimport { Select, SelectOption } from '../select/Select';\nimport { Icon } from '../vectoricon';\n\nenum OmniType {\n Group = 'group',\n Contact = 'contact'\n}\n\nexport interface OmniOption extends SelectOption {\n id: string;\n name: string;\n type: OmniType;\n urn?: string;\n count?: number;\n contact?: string;\n scheme?: string;\n}\n\nconst postNameStyle = {\n color: 'var(--color-text-dark)',\n padding: '0px 6px',\n fontSize: '12px'\n};\n\nexport class Omnibox extends Select<OmniOption> {\n @property({ type: String })\n valueKey = 'uuid';\n\n @property({ type: Boolean })\n groups = false;\n\n @property({ type: Boolean })\n contacts = false;\n\n @property({ type: String })\n placeholder = 'Select recipients';\n\n @property({ type: Boolean })\n multi = true;\n\n @property({ type: Boolean })\n searchable = true;\n\n @property({ type: Boolean })\n searchOnFocus = true;\n\n @property({ type: Boolean })\n queryParam = 'search';\n\n public update(changes: PropertyValues): void {\n super.update(changes);\n\n if (\n (changes.has('groups') || changes.has('contacts')) &&\n (this.groups || this.contacts)\n ) {\n let types = '&types=';\n if (this.groups) {\n types += 'g';\n }\n\n if (this.contacts) {\n types += 'c';\n }\n\n this.endpoint = this.endpoint + types;\n }\n }\n\n /** An option in the drop down */\n public renderOptionDefault(option: OmniOption): TemplateResult {\n return html`\n <div style=\"display:flex;\">\n <div style=\"margin-right: 8px\">${this.getIcon(option)}</div>\n <div style=\"flex: 1\">${option.name}</div>\n <div\n style=\"background: rgba(50, 50, 50, 0.15); margin-left: 5px; display: flex; align-items: center; border-radius: 4px\"\n >\n ${this.getPostName(option)}\n </div>\n </div>\n `;\n }\n\n private getPostName(option: OmniOption): TemplateResult {\n const style = { ...postNameStyle };\n\n if (option.urn && option.type === OmniType.Contact) {\n if (option.urn !== option.name) {\n return html`<div style=${styleMap(style)}>${option.urn}</div>`;\n }\n }\n\n if (option.type === OmniType.Group) {\n return html`\n <div style=${styleMap(style)}>${option.count.toLocaleString()}</div>\n `;\n }\n\n return null;\n }\n\n /** Selection in the multi-select select box */\n public renderSelectedItemDefault(option: OmniOption): TemplateResult {\n return html`\n <div\n style=\"flex:1 1 auto; text-overflow:ellipsis; overflow:hidden; white-space:nowrap; display: flex; align-items: stretch; color: var(--color-text-dark); font-size: 12px;\"\n >\n <div style=\"align-self: center; padding: 0px 7px; color: #bbb\">\n ${this.getIcon(option)}\n </div>\n <div\n class=\"name\"\n style=\"align-self: center; padding: 0px; font-size: 12px;\"\n >\n ${option.name}\n </div>\n <div\n style=\"background: rgba(100, 100, 100, 0.05); border-left: 1px solid rgba(100, 100, 100, 0.1); margin-left: 12px; display: flex; align-items: center\"\n >\n ${this.getPostName(option)}\n </div>\n </div>\n `;\n }\n\n private getIcon(option: OmniOption): TemplateResult {\n if (option.type === OmniType.Group) {\n return html`<temba-icon name=\"${Icon.group}\"></temba-icon>`;\n }\n\n if (option.type === OmniType.Contact) {\n return html`<temba-icon name=\"${Icon.contact}\"></temba-icon>`;\n }\n }\n}\n"]}