@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.
- package/.github/copilot-instructions.md +22 -4
- package/CHANGELOG.md +21 -0
- package/TEST_OPTIMIZATION.md +158 -0
- package/demo/alert/example.html +65 -0
- package/demo/button/example.html +71 -0
- package/demo/chart/example.html +56 -0
- package/demo/checkbox/example.html +72 -0
- package/demo/compose/example.html +72 -0
- package/demo/data/images/gus.png +0 -0
- package/demo/data/images/purrington.jpg +0 -0
- package/demo/data/server/opened-tickets.json +40 -0
- package/demo/data/server/response-time.json +27 -0
- package/demo/datepicker/example.html +69 -0
- package/demo/dialog/example.html +107 -0
- package/demo/dropdown/example.html +99 -0
- package/demo/index.html +152 -430
- package/demo/misc/example.html +72 -0
- package/demo/progress/example.html +59 -0
- package/demo/select/drag-and-drop.html +142 -0
- package/demo/select/example.html +82 -0
- package/demo/select/multi.html +73 -0
- package/demo/slider/example.html +59 -0
- package/demo/sortable-list/example.html +99 -0
- package/demo/styles.css +183 -0
- package/demo/tabs/example.html +91 -0
- package/demo/textinput/completion.html +56 -0
- package/demo/textinput/example.html +61 -0
- package/dist/temba-components.js +323 -191
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/chart/TembaChart.js +19 -16
- package/out-tsc/src/chart/TembaChart.js.map +1 -1
- package/out-tsc/src/fields/FieldManager.js +27 -34
- package/out-tsc/src/fields/FieldManager.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +1 -1
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/list/SortableList.js +257 -60
- package/out-tsc/src/list/SortableList.js.map +1 -1
- package/out-tsc/src/omnibox/Omnibox.js +1 -1
- package/out-tsc/src/omnibox/Omnibox.js.map +1 -1
- package/out-tsc/src/select/Select.js +198 -38
- package/out-tsc/src/select/Select.js.map +1 -1
- package/out-tsc/src/thumbnail/Thumbnail.js +1 -1
- package/out-tsc/src/thumbnail/Thumbnail.js.map +1 -1
- package/out-tsc/src/webchat/WebChat.js +5 -2
- package/out-tsc/src/webchat/WebChat.js.map +1 -1
- package/out-tsc/test/temba-chart.test.js +1 -1
- package/out-tsc/test/temba-chart.test.js.map +1 -1
- package/out-tsc/test/temba-compose.test.js +6 -30
- package/out-tsc/test/temba-compose.test.js.map +1 -1
- package/out-tsc/test/temba-contact-chat.test.js +1 -2
- package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
- package/out-tsc/test/temba-dropdown.test.js +1 -1
- package/out-tsc/test/temba-dropdown.test.js.map +1 -1
- package/out-tsc/test/temba-flow-editor-node.test.js +273 -0
- package/out-tsc/test/temba-flow-editor-node.test.js.map +1 -0
- package/out-tsc/test/temba-flow-editor.test.js +244 -0
- package/out-tsc/test/temba-flow-editor.test.js.map +1 -0
- package/out-tsc/test/temba-flow-plumber.test.js +145 -0
- package/out-tsc/test/temba-flow-plumber.test.js.map +1 -0
- package/out-tsc/test/temba-flow-render.test.js +171 -0
- package/out-tsc/test/temba-flow-render.test.js.map +1 -0
- package/out-tsc/test/temba-omnibox.test.js +6 -3
- package/out-tsc/test/temba-omnibox.test.js.map +1 -1
- package/out-tsc/test/temba-select.test.js +183 -53
- package/out-tsc/test/temba-select.test.js.map +1 -1
- package/out-tsc/test/temba-sortable-list.test.js +91 -15
- package/out-tsc/test/temba-sortable-list.test.js.map +1 -1
- package/out-tsc/test/temba-toast.test.js +1 -2
- package/out-tsc/test/temba-toast.test.js.map +1 -1
- package/out-tsc/test/temba-utils-index.test.js +2 -2
- package/out-tsc/test/temba-utils-index.test.js.map +1 -1
- package/out-tsc/test/temba-webchat-lightbox-fix.test.js +42 -0
- package/out-tsc/test/temba-webchat-lightbox-fix.test.js.map +1 -0
- package/out-tsc/test/utils.test.js +58 -0
- package/out-tsc/test/utils.test.js.map +1 -1
- package/package.json +2 -3
- package/screenshots/truth/flow/editor-basic.png +0 -0
- package/screenshots/truth/list/fields-dragging.png +0 -0
- package/screenshots/truth/list/sortable-dragging.png +0 -0
- package/screenshots/truth/list/sortable-dropped.png +0 -0
- package/screenshots/truth/list/sortable.png +0 -0
- package/screenshots/truth/omnibox/selected.png +0 -0
- package/screenshots/truth/select/disabled-multi-selection.png +0 -0
- package/screenshots/truth/select/disabled-selection.png +0 -0
- package/screenshots/truth/select/disabled.png +0 -0
- package/screenshots/truth/select/embedded.png +0 -0
- package/screenshots/truth/select/empty-options.png +0 -0
- package/screenshots/truth/select/expression-selected.png +0 -0
- package/screenshots/truth/select/expressions.png +0 -0
- package/screenshots/truth/select/functions.png +0 -0
- package/screenshots/truth/select/local-options.png +0 -0
- package/screenshots/truth/select/multi-reorder-final.png +0 -0
- package/screenshots/truth/select/multi-reorder-initial.png +0 -0
- package/screenshots/truth/select/multi-with-endpoint.png +0 -0
- package/screenshots/truth/select/multiple-initial-values.png +0 -0
- package/screenshots/truth/select/remote-options.png +0 -0
- package/screenshots/truth/select/search-enabled.png +0 -0
- package/screenshots/truth/select/search-multi-no-matches.png +0 -0
- package/screenshots/truth/select/search-selected-focus.png +0 -0
- package/screenshots/truth/select/search-selected.png +0 -0
- package/screenshots/truth/select/search-with-selected.png +0 -0
- package/screenshots/truth/select/searching.png +0 -0
- package/screenshots/truth/select/selected-multi-maxitems-reached.png +0 -0
- package/screenshots/truth/select/selected-multi.png +0 -0
- package/screenshots/truth/select/selected-single.png +0 -0
- package/screenshots/truth/select/selection-clearable.png +0 -0
- package/screenshots/truth/select/static-initial-value.png +0 -0
- package/screenshots/truth/select/static-initial-via-selected.png +0 -0
- package/screenshots/truth/select/truncated-selection.png +0 -0
- package/screenshots/truth/select/with-placeholder.png +0 -0
- package/screenshots/truth/select/without-placeholder.png +0 -0
- package/screenshots/truth/templates/default.png +0 -0
- package/screenshots/truth/templates/unapproved.png +0 -0
- package/screenshots/truth/webchat/connected-state.png +0 -0
- package/src/chart/TembaChart.ts +20 -16
- package/src/fields/FieldManager.ts +30 -38
- package/src/flow/Editor.ts +1 -1
- package/src/list/SortableList.ts +291 -67
- package/src/omnibox/Omnibox.ts +1 -1
- package/src/select/Select.ts +213 -42
- package/src/thumbnail/Thumbnail.ts +1 -1
- package/src/webchat/WebChat.ts +5 -2
- package/test/temba-chart.test.ts +1 -1
- package/test/temba-compose.test.ts +11 -38
- package/test/temba-contact-chat.test.ts +4 -6
- package/test/temba-dropdown.test.ts +1 -1
- package/test/temba-flow-editor-node.test.ts +344 -0
- package/test/temba-flow-editor.test.ts +301 -0
- package/test/temba-flow-plumber.test.ts +189 -0
- package/test/temba-flow-render.test.ts +220 -0
- package/test/temba-omnibox.test.ts +7 -3
- package/test/temba-select.test.ts +247 -79
- package/test/temba-sortable-list.test.ts +108 -15
- package/test/temba-toast.test.ts +2 -2
- package/test/temba-utils-index.test.ts +2 -2
- package/test/temba-webchat-lightbox-fix.test.ts +57 -0
- package/test/utils.test.ts +88 -0
- package/web-test-runner.config.mjs +4 -2
- package/.storybook/main.js +0 -14
- package/.storybook/preview-head.html +0 -1
- package/.storybook/preview.js +0 -17
- package/demo/agents.html +0 -147
- package/demo/old.html +0 -573
- package/demo/remote.html +0 -3
- package/screenshots/truth/compose/attachments-with-files-focused.png +0 -0
- package/stories/temba-checkbox.stories.md +0 -37
package/src/select/Select.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
postJSON
|
|
10
10
|
} from '../utils';
|
|
11
11
|
import '../options/Options';
|
|
12
|
+
import '../list/SortableList';
|
|
12
13
|
import { EventHandler } from '../RapidElement';
|
|
13
14
|
import { FormElement } from '../FormElement';
|
|
14
15
|
|
|
@@ -76,7 +77,7 @@ export class Select<T extends SelectOption> extends FormElement {
|
|
|
76
77
|
background: rgba(100, 100, 100, 0.05);
|
|
77
78
|
}
|
|
78
79
|
|
|
79
|
-
.selected-item.multi .remove-item {
|
|
80
|
+
. selected-item.multi .remove-item {
|
|
80
81
|
display: none;
|
|
81
82
|
}
|
|
82
83
|
|
|
@@ -112,7 +113,7 @@ export class Select<T extends SelectOption> extends FormElement {
|
|
|
112
113
|
padding-top: 1px;
|
|
113
114
|
box-shadow: var(--widget-box-shadow);
|
|
114
115
|
position: relative;
|
|
115
|
-
min-height: var(--temba-select-min-height, 2.
|
|
116
|
+
min-height: var(--temba-select-min-height, 2.4em);
|
|
116
117
|
}
|
|
117
118
|
|
|
118
119
|
temba-icon.select-open:hover,
|
|
@@ -148,7 +149,7 @@ export class Select<T extends SelectOption> extends FormElement {
|
|
|
148
149
|
flex-direction: row;
|
|
149
150
|
align-items: stretch;
|
|
150
151
|
user-select: none;
|
|
151
|
-
padding: var(--temba-select-selected-padding);
|
|
152
|
+
padding: var(--temba-select-selected-padding, 0px 4px);
|
|
152
153
|
}
|
|
153
154
|
|
|
154
155
|
.searchable .selected {
|
|
@@ -207,6 +208,18 @@ export class Select<T extends SelectOption> extends FormElement {
|
|
|
207
208
|
background: rgba(100, 100, 100, 0.3);
|
|
208
209
|
}
|
|
209
210
|
|
|
211
|
+
.multi .selected-item.sortable {
|
|
212
|
+
cursor: move;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.multi .selected-item.dragging {
|
|
216
|
+
opacity: 0.5;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.multi temba-sortable-list {
|
|
220
|
+
margin: 0 !important;
|
|
221
|
+
}
|
|
222
|
+
|
|
210
223
|
input {
|
|
211
224
|
font-size: 13px;
|
|
212
225
|
width: 0px;
|
|
@@ -225,16 +238,15 @@ export class Select<T extends SelectOption> extends FormElement {
|
|
|
225
238
|
border: 0px solid purple !important;
|
|
226
239
|
}
|
|
227
240
|
|
|
228
|
-
.input-wrapper {
|
|
229
|
-
min-width: 1px;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
241
|
.input-wrapper:focus-within {
|
|
233
242
|
min-width: 1px;
|
|
234
243
|
}
|
|
235
244
|
|
|
236
245
|
.input-wrapper {
|
|
246
|
+
min-width: 1px;
|
|
237
247
|
margin-left: 6px;
|
|
248
|
+
margin-right: -6px;
|
|
249
|
+
display: flex;
|
|
238
250
|
}
|
|
239
251
|
|
|
240
252
|
.multi .input-wrapper {
|
|
@@ -274,9 +286,9 @@ export class Select<T extends SelectOption> extends FormElement {
|
|
|
274
286
|
box-shadow: none !important;
|
|
275
287
|
}
|
|
276
288
|
|
|
277
|
-
.input-wrapper {
|
|
278
|
-
|
|
279
|
-
|
|
289
|
+
.multi .input-wrapper {
|
|
290
|
+
flex-shrink: 0;
|
|
291
|
+
min-width: 100px;
|
|
280
292
|
}
|
|
281
293
|
|
|
282
294
|
.input-wrapper .searchbox {
|
|
@@ -291,6 +303,7 @@ export class Select<T extends SelectOption> extends FormElement {
|
|
|
291
303
|
color: var(--color-placeholder);
|
|
292
304
|
display: none;
|
|
293
305
|
line-height: var(--temba-select-selected-line-height);
|
|
306
|
+
margin-left: 6px;
|
|
294
307
|
}
|
|
295
308
|
|
|
296
309
|
.footer {
|
|
@@ -332,6 +345,10 @@ export class Select<T extends SelectOption> extends FormElement {
|
|
|
332
345
|
pointer-events: none;
|
|
333
346
|
padding: 0px;
|
|
334
347
|
}
|
|
348
|
+
|
|
349
|
+
.ghost .remove-item {
|
|
350
|
+
display: none !important;
|
|
351
|
+
}
|
|
335
352
|
`;
|
|
336
353
|
}
|
|
337
354
|
|
|
@@ -515,6 +532,9 @@ export class Select<T extends SelectOption> extends FormElement {
|
|
|
515
532
|
@property({ type: Boolean })
|
|
516
533
|
allowAnchor: boolean = true;
|
|
517
534
|
|
|
535
|
+
@property({ type: String })
|
|
536
|
+
draggingId: string;
|
|
537
|
+
|
|
518
538
|
private alphaSort = (a: any, b: any) => {
|
|
519
539
|
// by default, all endpoint values are sorted by name
|
|
520
540
|
if (this.endpoint) {
|
|
@@ -538,6 +558,7 @@ export class Select<T extends SelectOption> extends FormElement {
|
|
|
538
558
|
this.renderSelectedItemDefault = this.renderSelectedItemDefault.bind(this);
|
|
539
559
|
this.prepareOptionsDefault = this.prepareOptionsDefault.bind(this);
|
|
540
560
|
this.isMatchDefault = this.isMatchDefault.bind(this);
|
|
561
|
+
this.handleOrderChanged = this.handleOrderChanged.bind(this);
|
|
541
562
|
}
|
|
542
563
|
|
|
543
564
|
public prepareOptionsDefault(options: T[]): T[] {
|
|
@@ -1339,8 +1360,13 @@ export class Select<T extends SelectOption> extends FormElement {
|
|
|
1339
1360
|
}
|
|
1340
1361
|
|
|
1341
1362
|
private handleContainerClick(event: MouseEvent) {
|
|
1342
|
-
|
|
1343
|
-
|
|
1363
|
+
if (this.disabled) {
|
|
1364
|
+
// prevent opening dropdown right after drag-and-drop
|
|
1365
|
+
event.stopPropagation();
|
|
1366
|
+
event.preventDefault();
|
|
1367
|
+
return;
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1344
1370
|
this.focused = true;
|
|
1345
1371
|
if ((event.target as any).tagName !== 'INPUT') {
|
|
1346
1372
|
const input = this.shadowRoot.querySelector('input');
|
|
@@ -1376,6 +1402,9 @@ export class Select<T extends SelectOption> extends FormElement {
|
|
|
1376
1402
|
}
|
|
1377
1403
|
|
|
1378
1404
|
private handleArrowClick(event: MouseEvent): void {
|
|
1405
|
+
if (this.disabled) {
|
|
1406
|
+
return;
|
|
1407
|
+
}
|
|
1379
1408
|
if (this.isOpen()) {
|
|
1380
1409
|
event.preventDefault();
|
|
1381
1410
|
event.stopPropagation();
|
|
@@ -1391,7 +1420,16 @@ export class Select<T extends SelectOption> extends FormElement {
|
|
|
1391
1420
|
// special case for icons on any option type
|
|
1392
1421
|
const icon = (option as any).icon;
|
|
1393
1422
|
return html`
|
|
1394
|
-
<div
|
|
1423
|
+
<div
|
|
1424
|
+
class="option-name"
|
|
1425
|
+
style="flex: 1 1 auto;
|
|
1426
|
+
align-self: center;
|
|
1427
|
+
white-space: nowrap;
|
|
1428
|
+
overflow: hidden;
|
|
1429
|
+
text-overflow: ellipsis;
|
|
1430
|
+
padding: 2px 8px;
|
|
1431
|
+
display: flex;"
|
|
1432
|
+
>
|
|
1395
1433
|
${icon
|
|
1396
1434
|
? html`<temba-icon
|
|
1397
1435
|
name="${icon}"
|
|
@@ -1458,6 +1496,18 @@ export class Select<T extends SelectOption> extends FormElement {
|
|
|
1458
1496
|
const idx = this.values.indexOf(valueToRemove);
|
|
1459
1497
|
if (idx > -1) {
|
|
1460
1498
|
this.values.splice(idx, 1);
|
|
1499
|
+
|
|
1500
|
+
// Also remove the 'selected' attribute from the corresponding temba-option element
|
|
1501
|
+
const valueToMatch = this.getValue(valueToRemove);
|
|
1502
|
+
for (const child of this.children) {
|
|
1503
|
+
if (child.tagName === 'TEMBA-OPTION') {
|
|
1504
|
+
const childValue = child.getAttribute('value');
|
|
1505
|
+
if (childValue === valueToMatch) {
|
|
1506
|
+
child.removeAttribute('selected');
|
|
1507
|
+
break;
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1461
1511
|
}
|
|
1462
1512
|
this.requestUpdate('values', oldValues);
|
|
1463
1513
|
this.infoText = '';
|
|
@@ -1487,6 +1537,30 @@ export class Select<T extends SelectOption> extends FormElement {
|
|
|
1487
1537
|
);
|
|
1488
1538
|
}
|
|
1489
1539
|
|
|
1540
|
+
private handleOrderChanged(event: CustomEvent): void {
|
|
1541
|
+
const detail = event.detail;
|
|
1542
|
+
|
|
1543
|
+
// Handle new swap-based format
|
|
1544
|
+
if (detail.swap && Array.isArray(detail.swap) && detail.swap.length === 2) {
|
|
1545
|
+
const [fromIdx, toIdx] = detail.swap;
|
|
1546
|
+
|
|
1547
|
+
// Only reorder if the indexes are different and valid
|
|
1548
|
+
if (
|
|
1549
|
+
fromIdx !== toIdx &&
|
|
1550
|
+
fromIdx >= 0 &&
|
|
1551
|
+
toIdx >= 0 &&
|
|
1552
|
+
fromIdx < this.values.length &&
|
|
1553
|
+
toIdx < this.values.length
|
|
1554
|
+
) {
|
|
1555
|
+
const oldValues = [...this.values];
|
|
1556
|
+
// Move the item from fromIdx to toIdx
|
|
1557
|
+
const movedItem = this.values.splice(fromIdx, 1)[0];
|
|
1558
|
+
this.values.splice(toIdx, 0, movedItem);
|
|
1559
|
+
this.requestUpdate('values', oldValues);
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1490
1564
|
public render(): TemplateResult {
|
|
1491
1565
|
const placeholder = this.values.length === 0 ? this.placeholder : '';
|
|
1492
1566
|
const placeholderDiv = html`
|
|
@@ -1571,35 +1645,132 @@ export class Select<T extends SelectOption> extends FormElement {
|
|
|
1571
1645
|
: null
|
|
1572
1646
|
}
|
|
1573
1647
|
${!this.multi && !this.resolving ? input : null}
|
|
1574
|
-
${
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1648
|
+
${
|
|
1649
|
+
this.multi && this.values.length > 1
|
|
1650
|
+
? html`
|
|
1651
|
+
<temba-sortable-list
|
|
1652
|
+
horizontal
|
|
1653
|
+
@temba-order-changed=${this.handleOrderChanged}
|
|
1654
|
+
.prepareGhost=${(item: any) => {
|
|
1655
|
+
item.style.transform = 'scale(1)';
|
|
1656
|
+
item.querySelector('.remove-item').style.display =
|
|
1657
|
+
'none';
|
|
1658
|
+
}}
|
|
1659
|
+
>
|
|
1660
|
+
${this.values.map(
|
|
1661
|
+
(selected: any, index: number) => html`
|
|
1662
|
+
<div
|
|
1663
|
+
class="selected-item sortable ${index ===
|
|
1664
|
+
this.selectedIndex
|
|
1665
|
+
? 'focused'
|
|
1666
|
+
: ''} ${this.draggingId === `selected-${index}`
|
|
1667
|
+
? 'dragging'
|
|
1668
|
+
: ''}"
|
|
1669
|
+
id="selected-${index}"
|
|
1670
|
+
style="
|
|
1671
|
+
vertical-align: middle;
|
|
1672
|
+
background: rgba(100,100,100,0.1);
|
|
1673
|
+
user-select: none;
|
|
1674
|
+
border-radius: 2px;
|
|
1675
|
+
align-items: center;
|
|
1676
|
+
flex-direction: row;
|
|
1677
|
+
flex-wrap: nowrap;
|
|
1678
|
+
margin: 2px 2px;
|
|
1679
|
+
display: flex;
|
|
1680
|
+
overflow: hidden;
|
|
1681
|
+
color: var(--color-widget-text);
|
|
1682
|
+
line-height: var(--temba-select-selected-line-height);
|
|
1683
|
+
--icon-color: var(--color-text-dark);
|
|
1684
|
+
${index === this.selectedIndex
|
|
1685
|
+
? 'background: rgba(100,100,100,0.3);'
|
|
1686
|
+
: ''}
|
|
1687
|
+
${this.draggingId === `selected-${index}`
|
|
1688
|
+
? 'opacity: 0.5;'
|
|
1689
|
+
: ''}
|
|
1690
|
+
"
|
|
1691
|
+
>
|
|
1692
|
+
${this.multi
|
|
1693
|
+
? html`
|
|
1694
|
+
<div
|
|
1695
|
+
class="remove-item"
|
|
1696
|
+
style="
|
|
1697
|
+
cursor: pointer;
|
|
1698
|
+
display: inline-block;
|
|
1699
|
+
padding: 3px 6px;
|
|
1700
|
+
border-right: 1px solid rgba(100,100,100,0.2);
|
|
1701
|
+
margin: 0;
|
|
1702
|
+
background: rgba(100,100,100,0.05);
|
|
1703
|
+
margin-top:1px;
|
|
1704
|
+
"
|
|
1705
|
+
@click=${(evt: MouseEvent) => {
|
|
1706
|
+
evt.preventDefault();
|
|
1707
|
+
evt.stopPropagation();
|
|
1708
|
+
this.handleRemoveSelection(selected);
|
|
1709
|
+
}}
|
|
1710
|
+
>
|
|
1711
|
+
<temba-icon
|
|
1712
|
+
name="${Icon.delete_small}"
|
|
1713
|
+
size="1"
|
|
1714
|
+
></temba-icon>
|
|
1715
|
+
</div>
|
|
1716
|
+
`
|
|
1717
|
+
: null}
|
|
1718
|
+
${this.renderSelectedItem(selected)}
|
|
1719
|
+
</div>
|
|
1720
|
+
`
|
|
1721
|
+
)}
|
|
1722
|
+
</temba-sortable-list>
|
|
1723
|
+
`
|
|
1724
|
+
: this.values.map(
|
|
1725
|
+
(selected: any, index: number) => html`
|
|
1726
|
+
<div
|
|
1727
|
+
class="selected-item ${index === this.selectedIndex
|
|
1728
|
+
? 'focused'
|
|
1729
|
+
: ''}"
|
|
1730
|
+
style="
|
|
1731
|
+
display: flex;
|
|
1732
|
+
overflow: hidden;
|
|
1733
|
+
color: var(--color-widget-text);
|
|
1734
|
+
line-height: var(--temba-select-selected-line-height);
|
|
1735
|
+
--icon-color: var(--color-text-dark);
|
|
1736
|
+
${index === this.selectedIndex
|
|
1737
|
+
? 'background: rgba(100,100,100,0.3);'
|
|
1738
|
+
: ''}
|
|
1739
|
+
"
|
|
1740
|
+
>
|
|
1741
|
+
${this.multi
|
|
1742
|
+
? html`
|
|
1743
|
+
<div
|
|
1744
|
+
class="remove-item"
|
|
1745
|
+
style="
|
|
1746
|
+
cursor: pointer;
|
|
1747
|
+
display: inline-block;
|
|
1748
|
+
padding: 3px 6px;
|
|
1749
|
+
border-right: 1px solid rgba(100,100,100,0.2);
|
|
1750
|
+
margin: 0;
|
|
1751
|
+
background: rgba(100,100,100,0.05);
|
|
1752
|
+
margin-top:1px;
|
|
1753
|
+
"
|
|
1754
|
+
@click=${(evt: MouseEvent) => {
|
|
1755
|
+
evt.preventDefault();
|
|
1756
|
+
evt.stopPropagation();
|
|
1757
|
+
this.handleRemoveSelection(selected);
|
|
1758
|
+
}}
|
|
1759
|
+
>
|
|
1760
|
+
<temba-icon
|
|
1761
|
+
name="${Icon.delete_small}"
|
|
1762
|
+
size="1"
|
|
1763
|
+
></temba-icon>
|
|
1764
|
+
</div>
|
|
1765
|
+
`
|
|
1766
|
+
: null}
|
|
1767
|
+
${!this.input || this.multi
|
|
1768
|
+
? this.renderSelectedItem(selected)
|
|
1769
|
+
: null}
|
|
1770
|
+
</div>
|
|
1771
|
+
`
|
|
1772
|
+
)
|
|
1773
|
+
}
|
|
1603
1774
|
${this.multi ? input : null}
|
|
1604
1775
|
</div>
|
|
1605
1776
|
|
|
@@ -118,7 +118,7 @@ export class Thumbnail extends RapidElement {
|
|
|
118
118
|
@property({ type: Boolean, attribute: false })
|
|
119
119
|
zoom: boolean;
|
|
120
120
|
|
|
121
|
-
@property({ type: String, attribute:
|
|
121
|
+
@property({ type: String, attribute: true })
|
|
122
122
|
contentType: string;
|
|
123
123
|
|
|
124
124
|
protected updated(
|
package/src/webchat/WebChat.ts
CHANGED
|
@@ -398,8 +398,11 @@ export class WebChat extends LitElement {
|
|
|
398
398
|
super.firstUpdated(changed);
|
|
399
399
|
this.chat = this.shadowRoot.querySelector('temba-chat');
|
|
400
400
|
|
|
401
|
-
|
|
402
|
-
document.querySelector('
|
|
401
|
+
// Only create lightbox if one doesn't already exist
|
|
402
|
+
if (!document.querySelector('temba-lightbox')) {
|
|
403
|
+
const lightbox = document.createElement('temba-lightbox');
|
|
404
|
+
document.querySelector('body').appendChild(lightbox);
|
|
405
|
+
}
|
|
403
406
|
}
|
|
404
407
|
|
|
405
408
|
private handleReconnect() {
|
package/test/temba-chart.test.ts
CHANGED
|
@@ -127,7 +127,7 @@ describe('temba-chart', () => {
|
|
|
127
127
|
await chart.updateComplete;
|
|
128
128
|
|
|
129
129
|
// Wait for the chart to be created after data is set
|
|
130
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
130
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
131
131
|
|
|
132
132
|
expect(chart.chart).to.exist;
|
|
133
133
|
const tickCallback = chart.chart.options.scales.y.ticks.callback;
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { assert, expect } from '@open-wc/testing';
|
|
2
2
|
import { Compose } from '../src/compose/Compose';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
assertScreenshot,
|
|
5
|
+
getClip,
|
|
6
|
+
getComponent,
|
|
7
|
+
getValidAttachments,
|
|
8
|
+
getValidText,
|
|
9
|
+
updateComponent
|
|
10
|
+
} from './utils.test';
|
|
4
11
|
import { DEFAULT_MEDIA_ENDPOINT } from '../src/utils';
|
|
5
12
|
import { Attachment } from '../src/interfaces';
|
|
6
13
|
|
|
@@ -17,16 +24,6 @@ const getCompose = async (attrs: any = {}, width = 500, height = 500) => {
|
|
|
17
24
|
return compose;
|
|
18
25
|
};
|
|
19
26
|
|
|
20
|
-
export const updateComponent = async (
|
|
21
|
-
compose: Compose,
|
|
22
|
-
text?: string,
|
|
23
|
-
attachments?: Attachment[]
|
|
24
|
-
): Promise<void> => {
|
|
25
|
-
compose.initialText = text ? text : '';
|
|
26
|
-
compose.currentAttachments = attachments ? attachments : [];
|
|
27
|
-
await compose.updateComplete;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
27
|
const getInitialValue = (
|
|
31
28
|
text?: string,
|
|
32
29
|
attachments?: Attachment[],
|
|
@@ -48,31 +45,6 @@ const getComposeValue = (value: any): string => {
|
|
|
48
45
|
return JSON.stringify(value);
|
|
49
46
|
};
|
|
50
47
|
|
|
51
|
-
export const getValidText = () => {
|
|
52
|
-
return 'sà-wàd-dee!';
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
// valid = attachments that are uploaded sent to the server when the user clicks send
|
|
56
|
-
export const getValidAttachments = (numFiles = 2): Attachment[] => {
|
|
57
|
-
const attachments = [];
|
|
58
|
-
let index = 1;
|
|
59
|
-
while (index <= numFiles) {
|
|
60
|
-
const s = 's' + index;
|
|
61
|
-
const attachment = {
|
|
62
|
-
uuid: s,
|
|
63
|
-
content_type: 'image/png',
|
|
64
|
-
type: 'image/png',
|
|
65
|
-
filename: 'name_' + s,
|
|
66
|
-
url: 'url_' + s,
|
|
67
|
-
size: 1024,
|
|
68
|
-
error: null
|
|
69
|
-
} as Attachment;
|
|
70
|
-
attachments.push(attachment);
|
|
71
|
-
index++;
|
|
72
|
-
}
|
|
73
|
-
return attachments;
|
|
74
|
-
};
|
|
75
|
-
|
|
76
48
|
// for a test width of 500, return a string that is 60+ chars with spaces
|
|
77
49
|
// to test that line breaks / word wrapping works as expected
|
|
78
50
|
const getValidText_Long_WithSpaces = () => {
|
|
@@ -179,10 +151,11 @@ describe('temba-compose attachments', () => {
|
|
|
179
151
|
const tabs = compose.getTabs();
|
|
180
152
|
tabs.focusTab('Attachments');
|
|
181
153
|
|
|
182
|
-
|
|
154
|
+
// todo: this test is weirdly inconsistent
|
|
155
|
+
/* await assertScreenshot(
|
|
183
156
|
'compose/attachments-with-files-focused',
|
|
184
157
|
getClip(compose)
|
|
185
|
-
)
|
|
158
|
+
);*/
|
|
186
159
|
});
|
|
187
160
|
|
|
188
161
|
it('serializes attachments', async () => {
|
|
@@ -7,17 +7,15 @@ import {
|
|
|
7
7
|
clearMockPosts,
|
|
8
8
|
getClip,
|
|
9
9
|
getComponent,
|
|
10
|
+
getValidAttachments,
|
|
11
|
+
getValidText,
|
|
10
12
|
loadStore,
|
|
11
13
|
mockAPI,
|
|
12
14
|
mockGET,
|
|
13
15
|
mockNow,
|
|
14
|
-
mockPOST
|
|
15
|
-
} from '../test/utils.test';
|
|
16
|
-
import {
|
|
17
|
-
getValidAttachments,
|
|
18
|
-
getValidText,
|
|
16
|
+
mockPOST,
|
|
19
17
|
updateComponent
|
|
20
|
-
} from '
|
|
18
|
+
} from '../test/utils.test';
|
|
21
19
|
|
|
22
20
|
import { expect, oneEvent } from '@open-wc/testing';
|
|
23
21
|
|
|
@@ -5,7 +5,7 @@ import { assertScreenshot, getClip, getComponent } from './utils.test';
|
|
|
5
5
|
const TAG = 'temba-dropdown';
|
|
6
6
|
|
|
7
7
|
// Helper function to wait for stable rendering
|
|
8
|
-
const waitForStableRender = async (dropdown: Dropdown, timeoutMs =
|
|
8
|
+
const waitForStableRender = async (dropdown: Dropdown, timeoutMs = 100) => {
|
|
9
9
|
await dropdown.updateComplete;
|
|
10
10
|
// Double wait to ensure any async positioning is complete
|
|
11
11
|
await new Promise((resolve) => setTimeout(resolve, timeoutMs));
|