@nyaruka/temba-components 0.129.9 → 0.129.10
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/CHANGELOG.md +10 -0
- package/demo/test-colorpicker.html +30 -0
- package/dist/temba-components.js +867 -915
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/events.js.map +1 -1
- package/out-tsc/src/form/ArrayEditor.js +45 -56
- package/out-tsc/src/form/ArrayEditor.js.map +1 -1
- package/out-tsc/src/form/BaseListEditor.js +4 -3
- package/out-tsc/src/form/BaseListEditor.js.map +1 -1
- package/out-tsc/src/form/Checkbox.js +77 -24
- package/out-tsc/src/form/Checkbox.js.map +1 -1
- package/out-tsc/src/form/ColorPicker.js +28 -40
- package/out-tsc/src/form/ColorPicker.js.map +1 -1
- package/out-tsc/src/form/Completion.js +44 -53
- package/out-tsc/src/form/Completion.js.map +1 -1
- package/out-tsc/src/form/Compose.js +7 -8
- package/out-tsc/src/form/Compose.js.map +1 -1
- package/out-tsc/src/form/ContactSearch.js +3 -4
- package/out-tsc/src/form/ContactSearch.js.map +1 -1
- package/out-tsc/src/form/DatePicker.js +29 -36
- package/out-tsc/src/form/DatePicker.js.map +1 -1
- package/out-tsc/src/form/{FormField.js → FieldElement.js} +78 -50
- package/out-tsc/src/form/FieldElement.js.map +1 -0
- package/out-tsc/src/form/FieldRenderer.js +2 -1
- package/out-tsc/src/form/FieldRenderer.js.map +1 -1
- package/out-tsc/src/form/ImagePicker.js +122 -126
- package/out-tsc/src/form/ImagePicker.js.map +1 -1
- package/out-tsc/src/form/KeyValueEditor.js +41 -37
- package/out-tsc/src/form/KeyValueEditor.js.map +1 -1
- package/out-tsc/src/form/MessageEditor.js +55 -63
- package/out-tsc/src/form/MessageEditor.js.map +1 -1
- package/out-tsc/src/form/TembaSlider.js +3 -3
- package/out-tsc/src/form/TembaSlider.js.map +1 -1
- package/out-tsc/src/form/TemplateEditor.js +3 -3
- package/out-tsc/src/form/TemplateEditor.js.map +1 -1
- package/out-tsc/src/form/TextInput.js +22 -26
- package/out-tsc/src/form/TextInput.js.map +1 -1
- package/out-tsc/src/form/select/Select.js +9 -15
- package/out-tsc/src/form/select/Select.js.map +1 -1
- package/out-tsc/src/form/select/UserSelect.js +8 -9
- package/out-tsc/src/form/select/UserSelect.js.map +1 -1
- package/out-tsc/src/form/select/WorkspaceSelect.js +7 -8
- package/out-tsc/src/form/select/WorkspaceSelect.js.map +1 -1
- package/out-tsc/src/live/ContactChat.js +32 -40
- package/out-tsc/src/live/ContactChat.js.map +1 -1
- package/out-tsc/src/live/ContactFieldEditor.js.map +1 -1
- package/out-tsc/temba-modules.js +3 -2
- package/out-tsc/temba-modules.js.map +1 -1
- package/out-tsc/test/temba-checkbox.test.js +16 -0
- package/out-tsc/test/temba-checkbox.test.js.map +1 -1
- package/out-tsc/test/temba-integration-markdown.test.js +2 -4
- package/out-tsc/test/temba-integration-markdown.test.js.map +1 -1
- package/out-tsc/test/temba-slider.test.js +0 -1
- package/out-tsc/test/temba-slider.test.js.map +1 -1
- package/package.json +1 -1
- package/screenshots/truth/actions/call_llm/editor/information-extraction.png +0 -0
- package/screenshots/truth/actions/call_llm/editor/sentiment-analysis.png +0 -0
- package/screenshots/truth/actions/call_llm/editor/summarization.png +0 -0
- package/screenshots/truth/actions/call_llm/editor/translation-task.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/cleanup-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/long-descriptive-group-names.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/many-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/multiple-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/remove-from-all-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/single-group.png +0 -0
- package/screenshots/truth/checkbox/checkbox-label-background-hover.png +0 -0
- package/screenshots/truth/checkbox/checkbox-no-label-no-background-hover.png +0 -0
- package/screenshots/truth/checkbox/checkbox-with-help-text.png +0 -0
- package/screenshots/truth/checkbox/checked.png +0 -0
- package/screenshots/truth/checkbox/default.png +0 -0
- package/screenshots/truth/colorpicker/default.png +0 -0
- package/screenshots/truth/colorpicker/focused.png +0 -0
- package/screenshots/truth/colorpicker/initialized.png +0 -0
- package/screenshots/truth/colorpicker/selected.png +0 -0
- package/screenshots/truth/field-renderer/checkbox-checked.png +0 -0
- package/screenshots/truth/field-renderer/checkbox-unchecked.png +0 -0
- package/screenshots/truth/field-renderer/checkbox-with-errors.png +0 -0
- package/screenshots/truth/integration/checkbox-markdown-errors.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/basic-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/custom-input-and-result-name.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/many-categories.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/minimal-categories.png +0 -0
- package/screenshots/truth/run-list/basic.png +0 -0
- package/src/events.ts +5 -6
- package/src/form/ArrayEditor.ts +45 -57
- package/src/form/BaseListEditor.ts +4 -4
- package/src/form/Checkbox.ts +81 -24
- package/src/form/ColorPicker.ts +31 -43
- package/src/form/Completion.ts +49 -56
- package/src/form/Compose.ts +8 -8
- package/src/form/ContactSearch.ts +3 -4
- package/src/form/DatePicker.ts +32 -38
- package/src/form/{FormField.ts → FieldElement.ts} +105 -52
- package/src/form/FieldRenderer.ts +2 -1
- package/src/form/ImagePicker.ts +107 -110
- package/src/form/KeyValueEditor.ts +43 -39
- package/src/form/MessageEditor.ts +61 -67
- package/src/form/TembaSlider.ts +3 -3
- package/src/form/TemplateEditor.ts +3 -3
- package/src/form/TextInput.ts +25 -28
- package/src/form/select/Select.ts +12 -17
- package/src/form/select/UserSelect.ts +10 -11
- package/src/form/select/WorkspaceSelect.ts +9 -10
- package/src/live/ContactChat.ts +32 -41
- package/src/live/ContactFieldEditor.ts +2 -2
- package/temba-modules.ts +3 -2
- package/test/temba-checkbox.test.ts +26 -0
- package/test/temba-integration-markdown.test.ts +2 -4
- package/test/temba-slider.test.ts +0 -1
- package/test-assets/contacts/history.json +7 -20
- package/out-tsc/src/form/FormElement.js +0 -67
- package/out-tsc/src/form/FormElement.js.map +0 -1
- package/out-tsc/src/form/FormField.js.map +0 -1
- package/out-tsc/test/temba-formfield.test.js +0 -94
- package/out-tsc/test/temba-formfield.test.js.map +0 -1
- package/src/form/FormElement.ts +0 -69
- package/test/temba-formfield.test.ts +0 -121
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { TemplateResult, css, html } from 'lit';
|
|
2
2
|
import { property } from 'lit/decorators.js';
|
|
3
3
|
import { ifDefined } from 'lit-html/directives/if-defined.js';
|
|
4
|
-
import {
|
|
4
|
+
import { FieldElement } from './FieldElement';
|
|
5
5
|
import { Completion } from './Completion';
|
|
6
6
|
import { MediaPicker } from './MediaPicker';
|
|
7
7
|
import { Attachment } from '../interfaces';
|
|
@@ -12,9 +12,10 @@ import { Icon } from '../Icons';
|
|
|
12
12
|
* MessageEditor is a composed component that combines temba-completion and temba-media-picker
|
|
13
13
|
* for editing messages with text completion and file attachments
|
|
14
14
|
*/
|
|
15
|
-
export class MessageEditor extends
|
|
15
|
+
export class MessageEditor extends FieldElement {
|
|
16
16
|
static get styles() {
|
|
17
17
|
return css`
|
|
18
|
+
${super.styles}
|
|
18
19
|
:host {
|
|
19
20
|
display: block;
|
|
20
21
|
}
|
|
@@ -130,9 +131,6 @@ export class MessageEditor extends FormElement {
|
|
|
130
131
|
@property({ type: String })
|
|
131
132
|
name = '';
|
|
132
133
|
|
|
133
|
-
@property({ type: String })
|
|
134
|
-
value = '';
|
|
135
|
-
|
|
136
134
|
@property({ type: String })
|
|
137
135
|
placeholder = '';
|
|
138
136
|
|
|
@@ -373,77 +371,73 @@ export class MessageEditor extends FormElement {
|
|
|
373
371
|
}
|
|
374
372
|
|
|
375
373
|
public render(): TemplateResult {
|
|
374
|
+
return this.renderField();
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
protected renderWidget(): TemplateResult {
|
|
376
378
|
const hasAttachments = this.hasStaticAttachments();
|
|
377
379
|
|
|
378
380
|
return html`
|
|
379
|
-
<
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
381
|
+
<div
|
|
382
|
+
class=${getClasses({
|
|
383
|
+
'message-editor-container': true,
|
|
384
|
+
highlight: this.pendingDrop,
|
|
385
|
+
'has-attachments': hasAttachments
|
|
386
|
+
})}
|
|
387
|
+
@dragenter=${this.handleDragEnter}
|
|
388
|
+
@dragover=${this.handleDragOver}
|
|
389
|
+
@dragleave=${this.handleDragLeave}
|
|
390
|
+
@drop=${this.handleDrop}
|
|
385
391
|
>
|
|
386
|
-
<div
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
392
|
+
<div class="completion-wrapper">
|
|
393
|
+
<temba-completion
|
|
394
|
+
name=${this.name}
|
|
395
|
+
.value=${this.value}
|
|
396
|
+
placeholder=${this.placeholder}
|
|
397
|
+
?textarea=${this.textarea}
|
|
398
|
+
?autogrow=${this.autogrow}
|
|
399
|
+
?session=${this.session}
|
|
400
|
+
?submitOnEnter=${this.submitOnEnter}
|
|
401
|
+
?gsm=${this.gsm}
|
|
402
|
+
?disableCompletion=${this.disableCompletion}
|
|
403
|
+
maxlength=${ifDefined(this.maxLength)}
|
|
404
|
+
counter=${ifDefined(this.counter)}
|
|
405
|
+
minHeight=${ifDefined(this.minHeight)}
|
|
406
|
+
widgetOnly
|
|
407
|
+
@change=${this.handleCompletionChange}
|
|
408
|
+
></temba-completion>
|
|
409
|
+
</div>
|
|
410
|
+
|
|
411
|
+
<div class="media-wrapper ">
|
|
412
|
+
<temba-media-picker
|
|
413
|
+
.accept=${this.accept}
|
|
414
|
+
.max=${this.maxAttachments}
|
|
415
|
+
.endpoint=${this.endpoint}
|
|
416
|
+
@change=${this.handleMediaChange}
|
|
417
|
+
ignoreDrops
|
|
418
|
+
></temba-media-picker>
|
|
419
|
+
</div>
|
|
420
|
+
<temba-icon
|
|
421
|
+
class="attachment-icon"
|
|
422
|
+
name=${Icon.attachment}
|
|
423
|
+
size="1.2"
|
|
424
|
+
@click=${this.handleAttachmentIconClick}
|
|
425
|
+
></temba-icon>
|
|
426
|
+
|
|
427
|
+
<div class="drop-overlay"></div>
|
|
428
|
+
|
|
429
|
+
<!-- Hidden media picker for handling uploads when no attachments are shown -->
|
|
430
|
+
${!hasAttachments
|
|
431
|
+
? html`<temba-media-picker
|
|
432
|
+
style="display: none;"
|
|
418
433
|
.accept=${this.accept}
|
|
419
434
|
.max=${this.maxAttachments}
|
|
420
435
|
.endpoint=${this.endpoint}
|
|
421
436
|
@change=${this.handleMediaChange}
|
|
422
437
|
ignoreDrops
|
|
423
|
-
></temba-media-picker
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
class="attachment-icon"
|
|
427
|
-
name=${Icon.attachment}
|
|
428
|
-
size="1.2"
|
|
429
|
-
@click=${this.handleAttachmentIconClick}
|
|
430
|
-
></temba-icon>
|
|
431
|
-
|
|
432
|
-
<div class="drop-overlay"></div>
|
|
433
|
-
|
|
434
|
-
<!-- Hidden media picker for handling uploads when no attachments are shown -->
|
|
435
|
-
${!hasAttachments
|
|
436
|
-
? html`<temba-media-picker
|
|
437
|
-
style="display: none;"
|
|
438
|
-
.accept=${this.accept}
|
|
439
|
-
.max=${this.maxAttachments}
|
|
440
|
-
.endpoint=${this.endpoint}
|
|
441
|
-
@change=${this.handleMediaChange}
|
|
442
|
-
ignoreDrops
|
|
443
|
-
></temba-media-picker>`
|
|
444
|
-
: ''}
|
|
445
|
-
</div>
|
|
446
|
-
</temba-field>
|
|
438
|
+
></temba-media-picker>`
|
|
439
|
+
: ''}
|
|
440
|
+
</div>
|
|
447
441
|
`;
|
|
448
442
|
}
|
|
449
443
|
}
|
package/src/form/TembaSlider.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { css, html, TemplateResult } from 'lit';
|
|
2
2
|
import { styleMap } from 'lit-html/directives/style-map.js';
|
|
3
3
|
import { property } from 'lit/decorators.js';
|
|
4
|
-
import {
|
|
4
|
+
import { FieldElement } from './FieldElement';
|
|
5
5
|
import { getClasses } from '../utils';
|
|
6
6
|
|
|
7
|
-
export class TembaSlider extends
|
|
7
|
+
export class TembaSlider extends FieldElement {
|
|
8
8
|
static get styles() {
|
|
9
9
|
return css`
|
|
10
10
|
:host {
|
|
@@ -142,7 +142,7 @@ export class TembaSlider extends FormElement {
|
|
|
142
142
|
this.requestUpdate();
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
public
|
|
145
|
+
public renderWidget(): TemplateResult {
|
|
146
146
|
return html` <div class="${getClasses({ grabbed: this.grabbed })}">
|
|
147
147
|
<div
|
|
148
148
|
style=${styleMap({ left: this.circleX + 'px' })}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { property } from 'lit/decorators.js';
|
|
2
|
-
import { FormElement } from './FormElement';
|
|
3
2
|
import { TemplateResult, html, css, LitElement } from 'lit';
|
|
4
3
|
import { CustomEventType } from '../interfaces';
|
|
5
4
|
import { MediaPicker } from './MediaPicker';
|
|
6
5
|
import { getClasses } from '../utils';
|
|
6
|
+
import { FieldElement } from './FieldElement';
|
|
7
7
|
|
|
8
8
|
interface Component {
|
|
9
9
|
name: string;
|
|
@@ -28,7 +28,7 @@ interface Template {
|
|
|
28
28
|
base_translation: Translation;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
export class TemplateEditor extends
|
|
31
|
+
export class TemplateEditor extends FieldElement {
|
|
32
32
|
static shadowRootOptions = {
|
|
33
33
|
...LitElement.shadowRootOptions,
|
|
34
34
|
delegatesFocus: true
|
|
@@ -457,7 +457,7 @@ export class TemplateEditor extends FormElement {
|
|
|
457
457
|
</div>`;
|
|
458
458
|
}
|
|
459
459
|
|
|
460
|
-
public
|
|
460
|
+
public renderWidget(): TemplateResult {
|
|
461
461
|
let content = null;
|
|
462
462
|
if (this.translation) {
|
|
463
463
|
content = this.renderComponents(this.translation.components);
|
package/src/form/TextInput.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { TemplateResult, html, css } from 'lit';
|
|
|
2
2
|
import { property } from 'lit/decorators.js';
|
|
3
3
|
import { ifDefined } from 'lit-html/directives/if-defined.js';
|
|
4
4
|
import { styleMap } from 'lit-html/directives/style-map.js';
|
|
5
|
-
import {
|
|
5
|
+
import { FieldElement } from './FieldElement';
|
|
6
6
|
import { Modax } from '../layout/Modax';
|
|
7
7
|
import { sanitizeUnintendedUnicode } from '../utils';
|
|
8
8
|
import { CharCount } from '../display/CharCount';
|
|
@@ -13,9 +13,10 @@ export enum InputType {
|
|
|
13
13
|
Number = 'number'
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
export class TextInput extends
|
|
16
|
+
export class TextInput extends FieldElement {
|
|
17
17
|
static get styles() {
|
|
18
18
|
return css`
|
|
19
|
+
${super.styles}
|
|
19
20
|
.input-container {
|
|
20
21
|
border-radius: var(--curvature-widget);
|
|
21
22
|
cursor: var(--input-cursor);
|
|
@@ -368,9 +369,15 @@ export class TextInput extends FormElement {
|
|
|
368
369
|
|
|
369
370
|
// TODO make this a formelement and have contactsearch set the root
|
|
370
371
|
public render(): TemplateResult {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
372
|
+
return this.renderField();
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
protected renderWidget() {
|
|
376
|
+
const containerStyle: any = {};
|
|
377
|
+
if (this.counter) {
|
|
378
|
+
containerStyle['--counter-background'] =
|
|
379
|
+
'var(--color-widget-border, transparent)';
|
|
380
|
+
}
|
|
374
381
|
|
|
375
382
|
const clear =
|
|
376
383
|
this.clearable && this.inputElement && this.inputElement.value
|
|
@@ -474,31 +481,21 @@ export class TextInput extends FormElement {
|
|
|
474
481
|
}
|
|
475
482
|
|
|
476
483
|
return html`
|
|
477
|
-
<
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
.errors=${this.errors}
|
|
482
|
-
.widgetOnly=${this.widgetOnly}
|
|
483
|
-
.hideLabel=${this.hideLabel}
|
|
484
|
-
.disabled=${this.disabled}
|
|
484
|
+
<div
|
|
485
|
+
class="input-container"
|
|
486
|
+
style=${styleMap(containerStyle)}
|
|
487
|
+
@click=${this.handleContainerClick}
|
|
485
488
|
>
|
|
486
|
-
<
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
489
|
+
<slot name="prefix"></slot>
|
|
490
|
+
|
|
491
|
+
${input} ${clear}
|
|
492
|
+
<slot name="type" class="type-icon"
|
|
493
|
+
>${this.type === InputType.Number
|
|
494
|
+
? html`<temba-icon name="number"></temba-icon>`
|
|
495
|
+
: null}</slot
|
|
490
496
|
>
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
${input} ${clear}
|
|
494
|
-
<slot name="type" class="type-icon"
|
|
495
|
-
>${this.type === InputType.Number
|
|
496
|
-
? html`<temba-icon name="number"></temba-icon>`
|
|
497
|
-
: null}</slot
|
|
498
|
-
>
|
|
499
|
-
<slot></slot>
|
|
500
|
-
</div>
|
|
501
|
-
</temba-field>
|
|
497
|
+
<slot></slot>
|
|
498
|
+
</div>
|
|
502
499
|
`;
|
|
503
500
|
}
|
|
504
501
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
2
|
-
import { TemplateResult, html, css
|
|
2
|
+
import { TemplateResult, html, css } from 'lit';
|
|
3
3
|
import { property, state } from 'lit/decorators.js';
|
|
4
4
|
import {
|
|
5
5
|
getUrl,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
import '../../display/Options';
|
|
12
12
|
import '../../list/SortableList';
|
|
13
13
|
import { EventHandler } from '../../RapidElement';
|
|
14
|
-
import {
|
|
14
|
+
import { FieldElement } from '../../form/FieldElement';
|
|
15
15
|
|
|
16
16
|
import { lru } from 'tiny-lru';
|
|
17
17
|
import { CompletionOption, CustomEventType, Position } from '../../interfaces';
|
|
@@ -35,11 +35,13 @@ export interface SelectOption {
|
|
|
35
35
|
arbitrary?: boolean;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
export class Select<T extends SelectOption> extends
|
|
38
|
+
export class Select<T extends SelectOption> extends FieldElement {
|
|
39
39
|
private hiddenInputs: HTMLInputElement[] = [];
|
|
40
40
|
|
|
41
|
-
static get styles()
|
|
41
|
+
static get styles() {
|
|
42
42
|
return css`
|
|
43
|
+
${super.styles}
|
|
44
|
+
|
|
43
45
|
:host {
|
|
44
46
|
--transition-speed: 0;
|
|
45
47
|
font-family: var(--font-family);
|
|
@@ -1660,7 +1662,7 @@ export class Select<T extends SelectOption> extends FormElement {
|
|
|
1660
1662
|
}
|
|
1661
1663
|
}
|
|
1662
1664
|
|
|
1663
|
-
|
|
1665
|
+
protected renderWidget(): TemplateResult {
|
|
1664
1666
|
const placeholder = this.values.length === 0 ? this.placeholder : '';
|
|
1665
1667
|
|
|
1666
1668
|
// Single unified placeholder - shows when empty and (not focused OR not searchable)
|
|
@@ -1845,16 +1847,6 @@ export class Select<T extends SelectOption> extends FormElement {
|
|
|
1845
1847
|
${placeholderElement}`}`;
|
|
1846
1848
|
|
|
1847
1849
|
return html`
|
|
1848
|
-
|
|
1849
|
-
<temba-field
|
|
1850
|
-
name=${this.name}
|
|
1851
|
-
.label=${this.label}
|
|
1852
|
-
.helpText=${this.helpText}
|
|
1853
|
-
.errors=${this.errors}
|
|
1854
|
-
.widgetOnly=${this.widgetOnly}
|
|
1855
|
-
.hideErrors=${this.hideErrors}
|
|
1856
|
-
?disabled=${this.disabled}
|
|
1857
|
-
>
|
|
1858
1850
|
<slot></slot>
|
|
1859
1851
|
<div class="wrapper-bg">
|
|
1860
1852
|
|
|
@@ -1948,7 +1940,10 @@ export class Select<T extends SelectOption> extends FormElement {
|
|
|
1948
1940
|
: null
|
|
1949
1941
|
}
|
|
1950
1942
|
</temba-options>
|
|
1951
|
-
|
|
1952
|
-
|
|
1943
|
+
`;
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
public render(): TemplateResult {
|
|
1947
|
+
return this.renderField();
|
|
1953
1948
|
}
|
|
1954
1949
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { css,
|
|
1
|
+
import { css, html, TemplateResult } from 'lit';
|
|
2
2
|
import { Select, SelectOption } from './Select';
|
|
3
3
|
import { property } from 'lit/decorators.js';
|
|
4
4
|
import { getFullName } from '../../display/TembaUser';
|
|
@@ -10,16 +10,15 @@ export interface UserOption extends SelectOption {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export class UserSelect extends Select<UserOption> {
|
|
13
|
-
static get styles()
|
|
14
|
-
return
|
|
15
|
-
super.styles
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
];
|
|
13
|
+
static get styles() {
|
|
14
|
+
return css`
|
|
15
|
+
${super.styles}
|
|
16
|
+
|
|
17
|
+
:host {
|
|
18
|
+
width: 150px;
|
|
19
|
+
display: block;
|
|
20
|
+
}
|
|
21
|
+
`;
|
|
23
22
|
}
|
|
24
23
|
|
|
25
24
|
@property({ type: String })
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { css,
|
|
1
|
+
import { css, html, TemplateResult } from 'lit';
|
|
2
2
|
import { Select, SelectOption } from './Select';
|
|
3
3
|
import { property } from 'lit/decorators.js';
|
|
4
4
|
import { getScrollParent } from '../../utils';
|
|
@@ -10,15 +10,14 @@ export interface WorkspaceOption extends SelectOption {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export class WorkspaceSelect extends Select<WorkspaceOption> {
|
|
13
|
-
static get styles()
|
|
14
|
-
return
|
|
15
|
-
super.styles
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
];
|
|
13
|
+
static get styles() {
|
|
14
|
+
return css`
|
|
15
|
+
${super.styles}
|
|
16
|
+
|
|
17
|
+
:host {
|
|
18
|
+
border: 0px solid blue;
|
|
19
|
+
}
|
|
20
|
+
`;
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
@property({ type: String })
|
package/src/live/ContactChat.ts
CHANGED
|
@@ -22,11 +22,11 @@ import {
|
|
|
22
22
|
AirtimeTransferredEvent,
|
|
23
23
|
CallEvent,
|
|
24
24
|
ChannelEvent,
|
|
25
|
+
ChatStartedEvent,
|
|
25
26
|
ContactEvent,
|
|
26
27
|
ContactGroupsEvent,
|
|
27
28
|
ContactHistoryPage,
|
|
28
29
|
ContactLanguageChangedEvent,
|
|
29
|
-
FlowEvent,
|
|
30
30
|
MsgEvent,
|
|
31
31
|
NameChangedEvent,
|
|
32
32
|
OptInEvent,
|
|
@@ -51,36 +51,35 @@ export const BODY_SNIPPET_LENGTH = 250;
|
|
|
51
51
|
*/
|
|
52
52
|
|
|
53
53
|
export enum Events {
|
|
54
|
-
|
|
55
|
-
MESSAGE_RECEIVED = 'msg_received',
|
|
54
|
+
AIRTIME_TRANSFERRED = 'airtime_transferred',
|
|
56
55
|
BROADCAST_CREATED = 'broadcast_created',
|
|
57
|
-
IVR_CREATED = 'ivr_created',
|
|
58
56
|
CALL_CREATED = 'call_created',
|
|
57
|
+
CALL_MISSED = 'call_missed',
|
|
59
58
|
CALL_RECEIVED = 'call_received',
|
|
59
|
+
CHAT_STARTED = 'chat_started',
|
|
60
60
|
CONTACT_FIELD_CHANGED = 'contact_field_changed',
|
|
61
61
|
CONTACT_GROUPS_CHANGED = 'contact_groups_changed',
|
|
62
|
+
CONTACT_LANGUAGE_CHANGED = 'contact_language_changed',
|
|
62
63
|
CONTACT_NAME_CHANGED = 'contact_name_changed',
|
|
63
64
|
CONTACT_URNS_CHANGED = 'contact_urns_changed',
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
IVR_CREATED = 'ivr_created',
|
|
66
|
+
MSG_CREATED = 'msg_created',
|
|
67
|
+
MSG_RECEIVED = 'msg_received',
|
|
67
68
|
NOTE_CREATED = 'note_created',
|
|
69
|
+
OPTIN_REQUESTED = 'optin_requested',
|
|
70
|
+
OPTIN_STARTED = 'optin_started',
|
|
71
|
+
OPTIN_STOPPED = 'optin_stopped',
|
|
72
|
+
RUN_ENDED = 'run_ended',
|
|
73
|
+
RUN_STARTED = 'run_started',
|
|
68
74
|
TICKET_ASSIGNED = 'ticket_assigned',
|
|
69
|
-
TICKET_NOTE_ADDED = 'ticket_note_added',
|
|
70
75
|
TICKET_CLOSED = 'ticket_closed',
|
|
76
|
+
TICKET_NOTE_ADDED = 'ticket_note_added',
|
|
71
77
|
TICKET_OPENED = 'ticket_opened',
|
|
72
78
|
TICKET_REOPENED = 'ticket_reopened',
|
|
73
79
|
TICKET_TOPIC_CHANGED = 'ticket_topic_changed',
|
|
74
|
-
OPTIN_STARTED = 'optin_started',
|
|
75
|
-
OPTIN_STOPPED = 'optin_stopped',
|
|
76
|
-
OPTIN_REQUESTED = 'optin_requested',
|
|
77
|
-
RUN_STARTED = 'run_started',
|
|
78
|
-
RUN_ENDED = 'run_ended',
|
|
79
80
|
|
|
80
81
|
// deprecated
|
|
81
|
-
|
|
82
|
-
FLOW_ENTERED = 'flow_entered',
|
|
83
|
-
FLOW_EXITED = 'flow_exited'
|
|
82
|
+
CHANNEL_EVENT = 'channel_event'
|
|
84
83
|
}
|
|
85
84
|
|
|
86
85
|
const renderInfoList = (singular: string, plural: string, items: any[]) => {
|
|
@@ -123,18 +122,6 @@ const renderChannelEvent = (event: ChannelEvent): string => {
|
|
|
123
122
|
}
|
|
124
123
|
};
|
|
125
124
|
|
|
126
|
-
const renderFlowEvent = (event: FlowEvent): string => {
|
|
127
|
-
let verb = 'Interrupted';
|
|
128
|
-
if (event.status !== 'I') {
|
|
129
|
-
if (event.type === Events.FLOW_ENTERED) {
|
|
130
|
-
verb = 'Started';
|
|
131
|
-
} else {
|
|
132
|
-
verb = 'Completed';
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
return `${verb} [**${event.flow.name}**](/flow/editor/${event.flow.uuid}/)`;
|
|
136
|
-
};
|
|
137
|
-
|
|
138
125
|
const renderRunEvent = (event: RunEvent): string => {
|
|
139
126
|
let verb = 'Started';
|
|
140
127
|
if (event.type === Events.RUN_ENDED) {
|
|
@@ -150,6 +137,14 @@ const renderRunEvent = (event: RunEvent): string => {
|
|
|
150
137
|
return `${verb} [**${event.flow.name}**](/flow/editor/${event.flow.uuid}/)`;
|
|
151
138
|
};
|
|
152
139
|
|
|
140
|
+
const renderChatStartedEvent = (event: ChatStartedEvent): string => {
|
|
141
|
+
if (event.params) {
|
|
142
|
+
return `Chat referral`;
|
|
143
|
+
} else {
|
|
144
|
+
return `Chat started`;
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
153
148
|
const renderUpdateEvent = (event: UpdateFieldEvent): string => {
|
|
154
149
|
return event.value
|
|
155
150
|
? `Updated **${event.field.name}** to **${event.value.text}**`
|
|
@@ -227,9 +222,11 @@ export const renderContactLanguageChangedEvent = (
|
|
|
227
222
|
|
|
228
223
|
export const renderCallEvent = (event: CallEvent): string => {
|
|
229
224
|
if (event.type === Events.CALL_CREATED) {
|
|
230
|
-
return `Call
|
|
225
|
+
return `Call started`;
|
|
226
|
+
} else if (event.type === Events.CALL_MISSED) {
|
|
227
|
+
return `Call missed`;
|
|
231
228
|
} else if (event.type === Events.CALL_RECEIVED) {
|
|
232
|
-
return `Call
|
|
229
|
+
return `Call answered`;
|
|
233
230
|
}
|
|
234
231
|
};
|
|
235
232
|
|
|
@@ -665,13 +662,6 @@ export class ContactChat extends ContactStoreElement {
|
|
|
665
662
|
text: `Topic changed to **${(event as TicketEvent).topic.name}**`
|
|
666
663
|
};
|
|
667
664
|
break;
|
|
668
|
-
case Events.FLOW_ENTERED:
|
|
669
|
-
case Events.FLOW_EXITED:
|
|
670
|
-
message = {
|
|
671
|
-
type: MessageType.Inline,
|
|
672
|
-
text: renderFlowEvent(event as FlowEvent)
|
|
673
|
-
};
|
|
674
|
-
break;
|
|
675
665
|
case Events.RUN_STARTED:
|
|
676
666
|
case Events.RUN_ENDED:
|
|
677
667
|
message = {
|
|
@@ -710,22 +700,23 @@ export class ContactChat extends ContactStoreElement {
|
|
|
710
700
|
};
|
|
711
701
|
break;
|
|
712
702
|
case Events.CALL_CREATED:
|
|
703
|
+
case Events.CALL_MISSED:
|
|
713
704
|
case Events.CALL_RECEIVED:
|
|
714
705
|
message = {
|
|
715
706
|
type: MessageType.Inline,
|
|
716
707
|
text: renderCallEvent(event as CallEvent)
|
|
717
708
|
};
|
|
718
709
|
break;
|
|
719
|
-
case Events.
|
|
710
|
+
case Events.CHANNEL_EVENT:
|
|
720
711
|
message = {
|
|
721
712
|
type: MessageType.Inline,
|
|
722
|
-
text:
|
|
713
|
+
text: renderChannelEvent(event as ChannelEvent)
|
|
723
714
|
};
|
|
724
715
|
break;
|
|
725
|
-
case Events.
|
|
716
|
+
case Events.CHAT_STARTED:
|
|
726
717
|
message = {
|
|
727
718
|
type: MessageType.Inline,
|
|
728
|
-
text:
|
|
719
|
+
text: renderChatStartedEvent(event as ChatStartedEvent)
|
|
729
720
|
};
|
|
730
721
|
break;
|
|
731
722
|
case Events.CONTACT_LANGUAGE_CHANGED:
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { css, html, TemplateResult } from 'lit';
|
|
2
2
|
import { property } from 'lit/decorators.js';
|
|
3
|
-
import { FormElement } from '../form/FormElement';
|
|
4
3
|
import { CustomEventType } from '../interfaces';
|
|
5
4
|
import { RapidElement } from '../RapidElement';
|
|
6
5
|
import { InputType, TextInput } from '../form/TextInput';
|
|
7
6
|
import { Icon } from '../Icons';
|
|
8
7
|
import { getClasses, WebResponse } from '../utils';
|
|
9
8
|
import { Select } from '../form/select/Select';
|
|
9
|
+
import { FieldElement } from '../form/FieldElement';
|
|
10
10
|
|
|
11
11
|
enum Status {
|
|
12
12
|
Success = 'success',
|
|
@@ -380,7 +380,7 @@ export class ContactFieldEditor extends RapidElement {
|
|
|
380
380
|
public handleSubmit() {
|
|
381
381
|
const input = this.shadowRoot.querySelector(
|
|
382
382
|
'temba-textinput, temba-datepicker'
|
|
383
|
-
) as
|
|
383
|
+
) as FieldElement;
|
|
384
384
|
|
|
385
385
|
if (input.value !== this.value) {
|
|
386
386
|
this.dirty = true;
|
package/temba-modules.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { Completion } from './src/form/Completion';
|
|
|
6
6
|
import { Modax } from './src/layout/Modax';
|
|
7
7
|
import { Dialog } from './src/layout/Dialog';
|
|
8
8
|
import { Button } from './src/display/Button';
|
|
9
|
-
import {
|
|
9
|
+
import { FieldElement } from './src/form/FieldElement';
|
|
10
10
|
import { Loading } from './src/display/Loading';
|
|
11
11
|
import { CharCount } from './src/display/CharCount';
|
|
12
12
|
import { Options } from './src/display/Options';
|
|
@@ -103,7 +103,8 @@ addCustomElement('temba-field-manager', FieldManager);
|
|
|
103
103
|
addCustomElement('temba-urn', ContactUrn);
|
|
104
104
|
addCustomElement('temba-content-menu', ContentMenu);
|
|
105
105
|
|
|
106
|
-
|
|
106
|
+
// Note: FieldElement is a base class and not directly instantiated as a custom element
|
|
107
|
+
export { FieldElement };
|
|
107
108
|
addCustomElement('temba-dialog', Dialog);
|
|
108
109
|
addCustomElement('temba-modax', Modax);
|
|
109
110
|
addCustomElement('temba-charcount', CharCount);
|
|
@@ -165,4 +165,30 @@ describe('temba-checkbox', () => {
|
|
|
165
165
|
data = new FormData(form);
|
|
166
166
|
expect(data.get('my-cb')).to.equal('5');
|
|
167
167
|
});
|
|
168
|
+
|
|
169
|
+
it('aligns help text with label when both are present', async () => {
|
|
170
|
+
const el: Checkbox = await fixture(html`
|
|
171
|
+
<temba-checkbox
|
|
172
|
+
label="Checkbox with help"
|
|
173
|
+
help_text="This help text should align with the label text"
|
|
174
|
+
>
|
|
175
|
+
</temba-checkbox>
|
|
176
|
+
`);
|
|
177
|
+
|
|
178
|
+
expect(el.label).to.equal('Checkbox with help');
|
|
179
|
+
expect(el.helpText).to.equal(
|
|
180
|
+
'This help text should align with the label text'
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
// Verify help text element exists and has proper alignment styles
|
|
184
|
+
const helpTextEl = el.shadowRoot.querySelector(
|
|
185
|
+
'.checkbox-help-text'
|
|
186
|
+
) as HTMLElement;
|
|
187
|
+
expect(helpTextEl).to.not.be.null;
|
|
188
|
+
expect(helpTextEl.textContent.trim()).to.equal(
|
|
189
|
+
'This help text should align with the label text'
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
await assertScreenshot('checkbox/checkbox-with-help-text', getClip(el));
|
|
193
|
+
});
|
|
168
194
|
});
|
|
@@ -16,10 +16,8 @@ describe('FormElement markdown integration', () => {
|
|
|
16
16
|
|
|
17
17
|
await checkbox.updateComplete;
|
|
18
18
|
|
|
19
|
-
// Check that errors are rendered with markdown
|
|
20
|
-
const errorElements = checkbox.shadowRoot
|
|
21
|
-
.querySelectorAll('temba-field')[0]
|
|
22
|
-
.shadowRoot.querySelectorAll('.alert-error');
|
|
19
|
+
// Check that errors are rendered with markdown directly in checkbox shadow root
|
|
20
|
+
const errorElements = checkbox.shadowRoot.querySelectorAll('.alert-error');
|
|
23
21
|
expect(errorElements.length).to.equal(2);
|
|
24
22
|
|
|
25
23
|
// First error should have bold text and link
|