@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.
Files changed (118) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/demo/test-colorpicker.html +30 -0
  3. package/dist/temba-components.js +867 -915
  4. package/dist/temba-components.js.map +1 -1
  5. package/out-tsc/src/events.js.map +1 -1
  6. package/out-tsc/src/form/ArrayEditor.js +45 -56
  7. package/out-tsc/src/form/ArrayEditor.js.map +1 -1
  8. package/out-tsc/src/form/BaseListEditor.js +4 -3
  9. package/out-tsc/src/form/BaseListEditor.js.map +1 -1
  10. package/out-tsc/src/form/Checkbox.js +77 -24
  11. package/out-tsc/src/form/Checkbox.js.map +1 -1
  12. package/out-tsc/src/form/ColorPicker.js +28 -40
  13. package/out-tsc/src/form/ColorPicker.js.map +1 -1
  14. package/out-tsc/src/form/Completion.js +44 -53
  15. package/out-tsc/src/form/Completion.js.map +1 -1
  16. package/out-tsc/src/form/Compose.js +7 -8
  17. package/out-tsc/src/form/Compose.js.map +1 -1
  18. package/out-tsc/src/form/ContactSearch.js +3 -4
  19. package/out-tsc/src/form/ContactSearch.js.map +1 -1
  20. package/out-tsc/src/form/DatePicker.js +29 -36
  21. package/out-tsc/src/form/DatePicker.js.map +1 -1
  22. package/out-tsc/src/form/{FormField.js → FieldElement.js} +78 -50
  23. package/out-tsc/src/form/FieldElement.js.map +1 -0
  24. package/out-tsc/src/form/FieldRenderer.js +2 -1
  25. package/out-tsc/src/form/FieldRenderer.js.map +1 -1
  26. package/out-tsc/src/form/ImagePicker.js +122 -126
  27. package/out-tsc/src/form/ImagePicker.js.map +1 -1
  28. package/out-tsc/src/form/KeyValueEditor.js +41 -37
  29. package/out-tsc/src/form/KeyValueEditor.js.map +1 -1
  30. package/out-tsc/src/form/MessageEditor.js +55 -63
  31. package/out-tsc/src/form/MessageEditor.js.map +1 -1
  32. package/out-tsc/src/form/TembaSlider.js +3 -3
  33. package/out-tsc/src/form/TembaSlider.js.map +1 -1
  34. package/out-tsc/src/form/TemplateEditor.js +3 -3
  35. package/out-tsc/src/form/TemplateEditor.js.map +1 -1
  36. package/out-tsc/src/form/TextInput.js +22 -26
  37. package/out-tsc/src/form/TextInput.js.map +1 -1
  38. package/out-tsc/src/form/select/Select.js +9 -15
  39. package/out-tsc/src/form/select/Select.js.map +1 -1
  40. package/out-tsc/src/form/select/UserSelect.js +8 -9
  41. package/out-tsc/src/form/select/UserSelect.js.map +1 -1
  42. package/out-tsc/src/form/select/WorkspaceSelect.js +7 -8
  43. package/out-tsc/src/form/select/WorkspaceSelect.js.map +1 -1
  44. package/out-tsc/src/live/ContactChat.js +32 -40
  45. package/out-tsc/src/live/ContactChat.js.map +1 -1
  46. package/out-tsc/src/live/ContactFieldEditor.js.map +1 -1
  47. package/out-tsc/temba-modules.js +3 -2
  48. package/out-tsc/temba-modules.js.map +1 -1
  49. package/out-tsc/test/temba-checkbox.test.js +16 -0
  50. package/out-tsc/test/temba-checkbox.test.js.map +1 -1
  51. package/out-tsc/test/temba-integration-markdown.test.js +2 -4
  52. package/out-tsc/test/temba-integration-markdown.test.js.map +1 -1
  53. package/out-tsc/test/temba-slider.test.js +0 -1
  54. package/out-tsc/test/temba-slider.test.js.map +1 -1
  55. package/package.json +1 -1
  56. package/screenshots/truth/actions/call_llm/editor/information-extraction.png +0 -0
  57. package/screenshots/truth/actions/call_llm/editor/sentiment-analysis.png +0 -0
  58. package/screenshots/truth/actions/call_llm/editor/summarization.png +0 -0
  59. package/screenshots/truth/actions/call_llm/editor/translation-task.png +0 -0
  60. package/screenshots/truth/actions/remove_contact_groups/editor/cleanup-groups.png +0 -0
  61. package/screenshots/truth/actions/remove_contact_groups/editor/long-descriptive-group-names.png +0 -0
  62. package/screenshots/truth/actions/remove_contact_groups/editor/many-groups.png +0 -0
  63. package/screenshots/truth/actions/remove_contact_groups/editor/multiple-groups.png +0 -0
  64. package/screenshots/truth/actions/remove_contact_groups/editor/remove-from-all-groups.png +0 -0
  65. package/screenshots/truth/actions/remove_contact_groups/editor/single-group.png +0 -0
  66. package/screenshots/truth/checkbox/checkbox-label-background-hover.png +0 -0
  67. package/screenshots/truth/checkbox/checkbox-no-label-no-background-hover.png +0 -0
  68. package/screenshots/truth/checkbox/checkbox-with-help-text.png +0 -0
  69. package/screenshots/truth/checkbox/checked.png +0 -0
  70. package/screenshots/truth/checkbox/default.png +0 -0
  71. package/screenshots/truth/colorpicker/default.png +0 -0
  72. package/screenshots/truth/colorpicker/focused.png +0 -0
  73. package/screenshots/truth/colorpicker/initialized.png +0 -0
  74. package/screenshots/truth/colorpicker/selected.png +0 -0
  75. package/screenshots/truth/field-renderer/checkbox-checked.png +0 -0
  76. package/screenshots/truth/field-renderer/checkbox-unchecked.png +0 -0
  77. package/screenshots/truth/field-renderer/checkbox-with-errors.png +0 -0
  78. package/screenshots/truth/integration/checkbox-markdown-errors.png +0 -0
  79. package/screenshots/truth/nodes/split_by_llm_categorize/editor/basic-categorization.png +0 -0
  80. package/screenshots/truth/nodes/split_by_llm_categorize/editor/custom-input-and-result-name.png +0 -0
  81. package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
  82. package/screenshots/truth/nodes/split_by_llm_categorize/editor/many-categories.png +0 -0
  83. package/screenshots/truth/nodes/split_by_llm_categorize/editor/minimal-categories.png +0 -0
  84. package/screenshots/truth/run-list/basic.png +0 -0
  85. package/src/events.ts +5 -6
  86. package/src/form/ArrayEditor.ts +45 -57
  87. package/src/form/BaseListEditor.ts +4 -4
  88. package/src/form/Checkbox.ts +81 -24
  89. package/src/form/ColorPicker.ts +31 -43
  90. package/src/form/Completion.ts +49 -56
  91. package/src/form/Compose.ts +8 -8
  92. package/src/form/ContactSearch.ts +3 -4
  93. package/src/form/DatePicker.ts +32 -38
  94. package/src/form/{FormField.ts → FieldElement.ts} +105 -52
  95. package/src/form/FieldRenderer.ts +2 -1
  96. package/src/form/ImagePicker.ts +107 -110
  97. package/src/form/KeyValueEditor.ts +43 -39
  98. package/src/form/MessageEditor.ts +61 -67
  99. package/src/form/TembaSlider.ts +3 -3
  100. package/src/form/TemplateEditor.ts +3 -3
  101. package/src/form/TextInput.ts +25 -28
  102. package/src/form/select/Select.ts +12 -17
  103. package/src/form/select/UserSelect.ts +10 -11
  104. package/src/form/select/WorkspaceSelect.ts +9 -10
  105. package/src/live/ContactChat.ts +32 -41
  106. package/src/live/ContactFieldEditor.ts +2 -2
  107. package/temba-modules.ts +3 -2
  108. package/test/temba-checkbox.test.ts +26 -0
  109. package/test/temba-integration-markdown.test.ts +2 -4
  110. package/test/temba-slider.test.ts +0 -1
  111. package/test-assets/contacts/history.json +7 -20
  112. package/out-tsc/src/form/FormElement.js +0 -67
  113. package/out-tsc/src/form/FormElement.js.map +0 -1
  114. package/out-tsc/src/form/FormField.js.map +0 -1
  115. package/out-tsc/test/temba-formfield.test.js +0 -94
  116. package/out-tsc/test/temba-formfield.test.js.map +0 -1
  117. package/src/form/FormElement.ts +0 -69
  118. package/test/temba-formfield.test.ts +0 -121
@@ -2,18 +2,17 @@ import { __decorate } from "tslib";
2
2
  import { css, html } from 'lit';
3
3
  import { property } from 'lit/decorators.js';
4
4
  import { ifDefined } from 'lit-html/directives/if-defined.js';
5
- import { FormElement } from './FormElement';
5
+ import { FieldElement } from './FieldElement';
6
6
  import { getClasses } from '../utils';
7
7
  import { Icon } from '../Icons';
8
8
  /**
9
9
  * MessageEditor is a composed component that combines temba-completion and temba-media-picker
10
10
  * for editing messages with text completion and file attachments
11
11
  */
12
- export class MessageEditor extends FormElement {
12
+ export class MessageEditor extends FieldElement {
13
13
  constructor() {
14
14
  super(...arguments);
15
15
  this.name = '';
16
- this.value = '';
17
16
  this.placeholder = '';
18
17
  this.textarea = true;
19
18
  this.autogrow = true;
@@ -28,6 +27,7 @@ export class MessageEditor extends FormElement {
28
27
  }
29
28
  static get styles() {
30
29
  return css `
30
+ ${super.styles}
31
31
  :host {
32
32
  display: block;
33
33
  }
@@ -292,85 +292,77 @@ export class MessageEditor extends FormElement {
292
292
  }
293
293
  }
294
294
  render() {
295
+ return this.renderField();
296
+ }
297
+ renderWidget() {
295
298
  const hasAttachments = this.hasStaticAttachments();
296
299
  return html `
297
- <temba-field
298
- name=${this.name}
299
- .label=${this.label}
300
- .helpText=${this.helpText}
301
- .errors=${this.errors}
302
- .widgetOnly=${this.widgetOnly}
303
- >
304
- <div
305
- class=${getClasses({
300
+ <div
301
+ class=${getClasses({
306
302
  'message-editor-container': true,
307
303
  highlight: this.pendingDrop,
308
304
  'has-attachments': hasAttachments
309
305
  })}
310
- @dragenter=${this.handleDragEnter}
311
- @dragover=${this.handleDragOver}
312
- @dragleave=${this.handleDragLeave}
313
- @drop=${this.handleDrop}
314
- >
315
- <div class="completion-wrapper">
316
- <temba-completion
317
- name=${this.name}
318
- .value=${this.value}
319
- placeholder=${this.placeholder}
320
- ?textarea=${this.textarea}
321
- ?autogrow=${this.autogrow}
322
- ?session=${this.session}
323
- ?submitOnEnter=${this.submitOnEnter}
324
- ?gsm=${this.gsm}
325
- ?disableCompletion=${this.disableCompletion}
326
- maxlength=${ifDefined(this.maxLength)}
327
- counter=${ifDefined(this.counter)}
328
- minHeight=${ifDefined(this.minHeight)}
329
- widgetOnly
330
- @change=${this.handleCompletionChange}
331
- ></temba-completion>
332
- </div>
306
+ @dragenter=${this.handleDragEnter}
307
+ @dragover=${this.handleDragOver}
308
+ @dragleave=${this.handleDragLeave}
309
+ @drop=${this.handleDrop}
310
+ >
311
+ <div class="completion-wrapper">
312
+ <temba-completion
313
+ name=${this.name}
314
+ .value=${this.value}
315
+ placeholder=${this.placeholder}
316
+ ?textarea=${this.textarea}
317
+ ?autogrow=${this.autogrow}
318
+ ?session=${this.session}
319
+ ?submitOnEnter=${this.submitOnEnter}
320
+ ?gsm=${this.gsm}
321
+ ?disableCompletion=${this.disableCompletion}
322
+ maxlength=${ifDefined(this.maxLength)}
323
+ counter=${ifDefined(this.counter)}
324
+ minHeight=${ifDefined(this.minHeight)}
325
+ widgetOnly
326
+ @change=${this.handleCompletionChange}
327
+ ></temba-completion>
328
+ </div>
329
+
330
+ <div class="media-wrapper ">
331
+ <temba-media-picker
332
+ .accept=${this.accept}
333
+ .max=${this.maxAttachments}
334
+ .endpoint=${this.endpoint}
335
+ @change=${this.handleMediaChange}
336
+ ignoreDrops
337
+ ></temba-media-picker>
338
+ </div>
339
+ <temba-icon
340
+ class="attachment-icon"
341
+ name=${Icon.attachment}
342
+ size="1.2"
343
+ @click=${this.handleAttachmentIconClick}
344
+ ></temba-icon>
345
+
346
+ <div class="drop-overlay"></div>
333
347
 
334
- <div class="media-wrapper ">
335
- <temba-media-picker
348
+ <!-- Hidden media picker for handling uploads when no attachments are shown -->
349
+ ${!hasAttachments
350
+ ? html `<temba-media-picker
351
+ style="display: none;"
336
352
  .accept=${this.accept}
337
353
  .max=${this.maxAttachments}
338
354
  .endpoint=${this.endpoint}
339
355
  @change=${this.handleMediaChange}
340
356
  ignoreDrops
341
- ></temba-media-picker>
342
- </div>
343
- <temba-icon
344
- class="attachment-icon"
345
- name=${Icon.attachment}
346
- size="1.2"
347
- @click=${this.handleAttachmentIconClick}
348
- ></temba-icon>
349
-
350
- <div class="drop-overlay"></div>
351
-
352
- <!-- Hidden media picker for handling uploads when no attachments are shown -->
353
- ${!hasAttachments
354
- ? html `<temba-media-picker
355
- style="display: none;"
356
- .accept=${this.accept}
357
- .max=${this.maxAttachments}
358
- .endpoint=${this.endpoint}
359
- @change=${this.handleMediaChange}
360
- ignoreDrops
361
- ></temba-media-picker>`
357
+ ></temba-media-picker>`
362
358
  : ''}
363
- </div>
364
- </temba-field>
359
+ </div>
365
360
  `;
366
361
  }
367
362
  }
368
363
  __decorate([
369
364
  property({ type: String })
370
365
  ], MessageEditor.prototype, "name", void 0);
371
- __decorate([
372
- property({ type: String })
373
- ], MessageEditor.prototype, "value", void 0);
374
366
  __decorate([
375
367
  property({ type: String })
376
368
  ], MessageEditor.prototype, "placeholder", void 0);
@@ -1 +1 @@
1
- {"version":3,"file":"MessageEditor.js","sourceRoot":"","sources":["../../../src/form/MessageEditor.ts"],"names":[],"mappings":"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","sourcesContent":["import { TemplateResult, css, html } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { ifDefined } from 'lit-html/directives/if-defined.js';\nimport { FormElement } from './FormElement';\nimport { Completion } from './Completion';\nimport { MediaPicker } from './MediaPicker';\nimport { Attachment } from '../interfaces';\nimport { getClasses } from '../utils';\nimport { Icon } from '../Icons';\n\n/**\n * MessageEditor is a composed component that combines temba-completion and temba-media-picker\n * for editing messages with text completion and file attachments\n */\nexport class MessageEditor extends FormElement {\n static get styles() {\n return css`\n :host {\n display: block;\n }\n\n .message-editor-container {\n border: 1px solid var(--color-widget-border);\n border-radius: var(--curvature-widget);\n background: #fff;\n position: relative;\n transition: border-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out;\n }\n\n .message-editor-container:focus-within {\n border-color: var(--color-focus);\n box-shadow: var(--widget-box-shadow-focused);\n }\n\n .message-editor-container.highlight {\n border-color: rgba(156, 222, 106, 0.88);\n }\n\n /* Hide the completion field border since we draw our own */\n .message-editor-container temba-completion::part(field) {\n border: none;\n box-shadow: none;\n border-radius: 0;\n }\n\n .message-editor-container temba-completion {\n --widget-box-shadow: none;\n --widget-box-shadow-focused: none;\n --widget-box-shadow-focused: none;\n --color-widget-border: transparent;\n --color-focus: transparent;\n }\n\n .completion-wrapper {\n }\n\n .media-wrapper {\n padding: 4px 8px;\n background: rgba(0, 0, 0, 0.03);\n border-top: 1px solid var(--color-widget-border);\n border-radius: 0 0 var(--curvature-widget) var(--curvature-widget);\n box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.05);\n margin-top: 3px;\n display: none;\n }\n .has-attachments .media-wrapper {\n display: flex;\n }\n\n /* Override media picker styles to integrate better */\n .media-wrapper temba-media-picker {\n --color-widget-border: transparent;\n }\n\n .media-wrapper .attachments-list {\n padding: 0.2em 0;\n }\n\n .drop-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(210, 243, 184, 0.5);\n border-radius: var(--curvature-widget);\n display: flex;\n align-items: center;\n justify-content: center;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.2s ease-in-out;\n z-index: 10;\n }\n\n .message-editor-container.highlight .drop-overlay {\n opacity: 1;\n }\n\n .drop-message {\n background: rgba(0, 0, 0, 0.8);\n color: white;\n padding: 12px 24px;\n border-radius: var(--curvature);\n font-weight: 500;\n }\n\n .attachment-icon {\n position: absolute;\n bottom: 4px;\n right: 4px;\n color: var(--color-text-dark);\n cursor: pointer;\n padding: 6px;\n border-radius: var(--curvature);\n transition: background-color 0.2s ease-in-out;\n display: block;\n }\n\n .has-attachments .attachment-icon {\n display: none;\n }\n\n .attachment-icon:hover {\n background-color: rgba(0, 0, 0, 0.05);\n }\n `;\n }\n\n @property({ type: String })\n name = '';\n\n @property({ type: String })\n value = '';\n\n @property({ type: String })\n placeholder = '';\n\n @property({ type: Boolean })\n textarea = true;\n\n @property({ type: Boolean })\n autogrow = true;\n\n @property({ type: Number })\n minHeight = 60;\n\n @property({ type: Number })\n maxLength: number;\n\n @property({ type: Boolean })\n session: boolean;\n\n @property({ type: Boolean })\n submitOnEnter = false;\n\n @property({ type: Boolean })\n gsm: boolean;\n\n @property({ type: Boolean })\n disableCompletion: boolean;\n\n @property({ type: String })\n counter: string;\n\n @property({ type: Array })\n attachments: (Attachment | string)[] = [];\n\n @property({ type: String })\n accept = '';\n\n @property({ type: Number, attribute: 'max-attachments' })\n maxAttachments = 3;\n\n @property({ type: String })\n endpoint = '';\n\n @property({ type: Boolean, attribute: false })\n pendingDrop = false;\n\n @property({ type: Boolean, attribute: false })\n uploading = false;\n\n private completionElement: Completion;\n private mediaPickerElement: MediaPicker;\n\n public firstUpdated(changes: Map<string, any>) {\n super.firstUpdated(changes);\n\n this.completionElement = this.shadowRoot.querySelector(\n 'temba-completion'\n ) as Completion;\n\n // Get the visible media picker (either in media-wrapper or the hidden one)\n this.mediaPickerElement = this.shadowRoot.querySelector(\n 'temba-media-picker'\n ) as MediaPicker;\n\n // Set up proper attachment filtering and parsing\n this.parseAndFilterAttachments();\n }\n\n /**\n * Parse attachments and filter out runtime attachments for media picker\n */\n private parseAndFilterAttachments() {\n if (!this.attachments) return;\n\n // Filter out runtime attachments (those without '/' in content type)\n const staticAttachments = this.attachments.filter((attachment) => {\n if (typeof attachment === 'string') {\n const [contentType] = attachment.split(':');\n return contentType.includes('/');\n }\n return true;\n });\n\n // Convert string attachments to Attachment objects for media picker\n const mediaAttachments = staticAttachments.map((attachment) => {\n if (typeof attachment === 'string') {\n // split into content type and URL\n // e.g. \"image/jpeg:http://example.com/image.jpg\"\n const colonIndex = attachment.indexOf(':');\n const contentType = attachment.substring(0, colonIndex);\n const url = attachment.substring(colonIndex + 1);\n return {\n content_type: contentType,\n url: url,\n filename: this.getFilenameFromUrl(url),\n size: 0\n } as Attachment;\n }\n return attachment;\n });\n\n if (this.mediaPickerElement) {\n this.mediaPickerElement.attachments = mediaAttachments;\n }\n }\n\n /**\n * Check if there are any static attachments (excluding runtime attachments)\n */\n private hasStaticAttachments(): boolean {\n if (!this.attachments || this.attachments.length === 0) return false;\n\n return this.attachments.some((attachment) => {\n if (typeof attachment === 'string') {\n const [contentType] = attachment.split(':');\n return contentType.includes('/');\n }\n return true;\n });\n }\n\n private getFilenameFromUrl(url: string): string {\n try {\n const urlObj = new URL(url);\n const pathname = urlObj.pathname;\n return pathname.substring(pathname.lastIndexOf('/') + 1) || 'attachment';\n } catch {\n return 'attachment';\n }\n }\n\n private handleCompletionChange(event: Event) {\n event.stopPropagation();\n const completion = event.target as Completion;\n this.value = completion.value;\n this.fireEvent('change');\n }\n\n private handleMediaChange(event: Event) {\n event.stopPropagation();\n const mediaPicker = event.target as MediaPicker;\n // Convert media picker attachments back to the format expected by the form\n const formattedAttachments = mediaPicker.attachments.map((attachment) => {\n return `${attachment.content_type}:${attachment.url}`;\n });\n\n // Merge with any runtime attachments that were filtered out\n const runtimeAttachments = (this.attachments || []).filter((attachment) => {\n if (typeof attachment === 'string') {\n const [contentType] = attachment.split(':');\n return !contentType.includes('/');\n }\n return false;\n }) as string[];\n\n this.attachments = [...runtimeAttachments, ...formattedAttachments];\n this.fireEvent('change');\n }\n\n private handleDragEnter(evt: DragEvent): void {\n this.highlight(evt);\n }\n\n private handleDragOver(evt: DragEvent): void {\n this.highlight(evt);\n }\n\n private handleDragLeave(evt: DragEvent): void {\n this.unhighlight(evt);\n }\n\n private handleDrop(evt: DragEvent): void {\n this.unhighlight(evt);\n\n // Forward to media picker\n if (this.mediaPickerElement) {\n const files = [...evt.dataTransfer.files];\n this.mediaPickerElement.uploadFiles(files);\n }\n }\n\n private handleAttachmentIconClick(): void {\n // Trigger the file picker on the media picker\n if (this.mediaPickerElement) {\n const uploadInput = this.mediaPickerElement.shadowRoot.querySelector(\n '#upload-input'\n ) as HTMLInputElement;\n if (uploadInput) {\n uploadInput.click();\n }\n }\n }\n\n private highlight(evt: DragEvent): void {\n evt.preventDefault();\n evt.stopPropagation();\n\n // Always allow highlight for testing purposes, but in real usage check media picker\n this.pendingDrop = true;\n }\n\n private unhighlight(evt: DragEvent): void {\n evt.preventDefault();\n evt.stopPropagation();\n this.pendingDrop = false;\n }\n\n public updated(changedProperties: Map<string, any>) {\n super.updated(changedProperties);\n\n if (changedProperties.has('attachments')) {\n // Re-query media picker since the DOM structure may have changed\n this.mediaPickerElement = this.shadowRoot.querySelector(\n 'temba-media-picker'\n ) as MediaPicker;\n }\n\n if (changedProperties.has('uploading')) {\n this.dispatchEvent(\n new CustomEvent('loading', {\n detail: { loading: this.uploading }\n })\n );\n }\n }\n\n public focus() {\n super.focus();\n if (this.completionElement) {\n this.completionElement.focus();\n }\n }\n\n public click() {\n super.click();\n if (this.completionElement) {\n this.completionElement.click();\n }\n }\n\n public render(): TemplateResult {\n const hasAttachments = this.hasStaticAttachments();\n\n return html`\n <temba-field\n name=${this.name}\n .label=${this.label}\n .helpText=${this.helpText}\n .errors=${this.errors}\n .widgetOnly=${this.widgetOnly}\n >\n <div\n class=${getClasses({\n 'message-editor-container': true,\n highlight: this.pendingDrop,\n 'has-attachments': hasAttachments\n })}\n @dragenter=${this.handleDragEnter}\n @dragover=${this.handleDragOver}\n @dragleave=${this.handleDragLeave}\n @drop=${this.handleDrop}\n >\n <div class=\"completion-wrapper\">\n <temba-completion\n name=${this.name}\n .value=${this.value}\n placeholder=${this.placeholder}\n ?textarea=${this.textarea}\n ?autogrow=${this.autogrow}\n ?session=${this.session}\n ?submitOnEnter=${this.submitOnEnter}\n ?gsm=${this.gsm}\n ?disableCompletion=${this.disableCompletion}\n maxlength=${ifDefined(this.maxLength)}\n counter=${ifDefined(this.counter)}\n minHeight=${ifDefined(this.minHeight)}\n widgetOnly\n @change=${this.handleCompletionChange}\n ></temba-completion>\n </div>\n\n <div class=\"media-wrapper \">\n <temba-media-picker\n .accept=${this.accept}\n .max=${this.maxAttachments}\n .endpoint=${this.endpoint}\n @change=${this.handleMediaChange}\n ignoreDrops\n ></temba-media-picker>\n </div>\n <temba-icon\n class=\"attachment-icon\"\n name=${Icon.attachment}\n size=\"1.2\"\n @click=${this.handleAttachmentIconClick}\n ></temba-icon>\n\n <div class=\"drop-overlay\"></div>\n\n <!-- Hidden media picker for handling uploads when no attachments are shown -->\n ${!hasAttachments\n ? html`<temba-media-picker\n style=\"display: none;\"\n .accept=${this.accept}\n .max=${this.maxAttachments}\n .endpoint=${this.endpoint}\n @change=${this.handleMediaChange}\n ignoreDrops\n ></temba-media-picker>`\n : ''}\n </div>\n </temba-field>\n `;\n }\n}\n"]}
1
+ {"version":3,"file":"MessageEditor.js","sourceRoot":"","sources":["../../../src/form/MessageEditor.ts"],"names":[],"mappings":"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","sourcesContent":["import { TemplateResult, css, html } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { ifDefined } from 'lit-html/directives/if-defined.js';\nimport { FieldElement } from './FieldElement';\nimport { Completion } from './Completion';\nimport { MediaPicker } from './MediaPicker';\nimport { Attachment } from '../interfaces';\nimport { getClasses } from '../utils';\nimport { Icon } from '../Icons';\n\n/**\n * MessageEditor is a composed component that combines temba-completion and temba-media-picker\n * for editing messages with text completion and file attachments\n */\nexport class MessageEditor extends FieldElement {\n static get styles() {\n return css`\n ${super.styles}\n :host {\n display: block;\n }\n\n .message-editor-container {\n border: 1px solid var(--color-widget-border);\n border-radius: var(--curvature-widget);\n background: #fff;\n position: relative;\n transition: border-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out;\n }\n\n .message-editor-container:focus-within {\n border-color: var(--color-focus);\n box-shadow: var(--widget-box-shadow-focused);\n }\n\n .message-editor-container.highlight {\n border-color: rgba(156, 222, 106, 0.88);\n }\n\n /* Hide the completion field border since we draw our own */\n .message-editor-container temba-completion::part(field) {\n border: none;\n box-shadow: none;\n border-radius: 0;\n }\n\n .message-editor-container temba-completion {\n --widget-box-shadow: none;\n --widget-box-shadow-focused: none;\n --widget-box-shadow-focused: none;\n --color-widget-border: transparent;\n --color-focus: transparent;\n }\n\n .completion-wrapper {\n }\n\n .media-wrapper {\n padding: 4px 8px;\n background: rgba(0, 0, 0, 0.03);\n border-top: 1px solid var(--color-widget-border);\n border-radius: 0 0 var(--curvature-widget) var(--curvature-widget);\n box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.05);\n margin-top: 3px;\n display: none;\n }\n .has-attachments .media-wrapper {\n display: flex;\n }\n\n /* Override media picker styles to integrate better */\n .media-wrapper temba-media-picker {\n --color-widget-border: transparent;\n }\n\n .media-wrapper .attachments-list {\n padding: 0.2em 0;\n }\n\n .drop-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(210, 243, 184, 0.5);\n border-radius: var(--curvature-widget);\n display: flex;\n align-items: center;\n justify-content: center;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.2s ease-in-out;\n z-index: 10;\n }\n\n .message-editor-container.highlight .drop-overlay {\n opacity: 1;\n }\n\n .drop-message {\n background: rgba(0, 0, 0, 0.8);\n color: white;\n padding: 12px 24px;\n border-radius: var(--curvature);\n font-weight: 500;\n }\n\n .attachment-icon {\n position: absolute;\n bottom: 4px;\n right: 4px;\n color: var(--color-text-dark);\n cursor: pointer;\n padding: 6px;\n border-radius: var(--curvature);\n transition: background-color 0.2s ease-in-out;\n display: block;\n }\n\n .has-attachments .attachment-icon {\n display: none;\n }\n\n .attachment-icon:hover {\n background-color: rgba(0, 0, 0, 0.05);\n }\n `;\n }\n\n @property({ type: String })\n name = '';\n\n @property({ type: String })\n placeholder = '';\n\n @property({ type: Boolean })\n textarea = true;\n\n @property({ type: Boolean })\n autogrow = true;\n\n @property({ type: Number })\n minHeight = 60;\n\n @property({ type: Number })\n maxLength: number;\n\n @property({ type: Boolean })\n session: boolean;\n\n @property({ type: Boolean })\n submitOnEnter = false;\n\n @property({ type: Boolean })\n gsm: boolean;\n\n @property({ type: Boolean })\n disableCompletion: boolean;\n\n @property({ type: String })\n counter: string;\n\n @property({ type: Array })\n attachments: (Attachment | string)[] = [];\n\n @property({ type: String })\n accept = '';\n\n @property({ type: Number, attribute: 'max-attachments' })\n maxAttachments = 3;\n\n @property({ type: String })\n endpoint = '';\n\n @property({ type: Boolean, attribute: false })\n pendingDrop = false;\n\n @property({ type: Boolean, attribute: false })\n uploading = false;\n\n private completionElement: Completion;\n private mediaPickerElement: MediaPicker;\n\n public firstUpdated(changes: Map<string, any>) {\n super.firstUpdated(changes);\n\n this.completionElement = this.shadowRoot.querySelector(\n 'temba-completion'\n ) as Completion;\n\n // Get the visible media picker (either in media-wrapper or the hidden one)\n this.mediaPickerElement = this.shadowRoot.querySelector(\n 'temba-media-picker'\n ) as MediaPicker;\n\n // Set up proper attachment filtering and parsing\n this.parseAndFilterAttachments();\n }\n\n /**\n * Parse attachments and filter out runtime attachments for media picker\n */\n private parseAndFilterAttachments() {\n if (!this.attachments) return;\n\n // Filter out runtime attachments (those without '/' in content type)\n const staticAttachments = this.attachments.filter((attachment) => {\n if (typeof attachment === 'string') {\n const [contentType] = attachment.split(':');\n return contentType.includes('/');\n }\n return true;\n });\n\n // Convert string attachments to Attachment objects for media picker\n const mediaAttachments = staticAttachments.map((attachment) => {\n if (typeof attachment === 'string') {\n // split into content type and URL\n // e.g. \"image/jpeg:http://example.com/image.jpg\"\n const colonIndex = attachment.indexOf(':');\n const contentType = attachment.substring(0, colonIndex);\n const url = attachment.substring(colonIndex + 1);\n return {\n content_type: contentType,\n url: url,\n filename: this.getFilenameFromUrl(url),\n size: 0\n } as Attachment;\n }\n return attachment;\n });\n\n if (this.mediaPickerElement) {\n this.mediaPickerElement.attachments = mediaAttachments;\n }\n }\n\n /**\n * Check if there are any static attachments (excluding runtime attachments)\n */\n private hasStaticAttachments(): boolean {\n if (!this.attachments || this.attachments.length === 0) return false;\n\n return this.attachments.some((attachment) => {\n if (typeof attachment === 'string') {\n const [contentType] = attachment.split(':');\n return contentType.includes('/');\n }\n return true;\n });\n }\n\n private getFilenameFromUrl(url: string): string {\n try {\n const urlObj = new URL(url);\n const pathname = urlObj.pathname;\n return pathname.substring(pathname.lastIndexOf('/') + 1) || 'attachment';\n } catch {\n return 'attachment';\n }\n }\n\n private handleCompletionChange(event: Event) {\n event.stopPropagation();\n const completion = event.target as Completion;\n this.value = completion.value;\n this.fireEvent('change');\n }\n\n private handleMediaChange(event: Event) {\n event.stopPropagation();\n const mediaPicker = event.target as MediaPicker;\n // Convert media picker attachments back to the format expected by the form\n const formattedAttachments = mediaPicker.attachments.map((attachment) => {\n return `${attachment.content_type}:${attachment.url}`;\n });\n\n // Merge with any runtime attachments that were filtered out\n const runtimeAttachments = (this.attachments || []).filter((attachment) => {\n if (typeof attachment === 'string') {\n const [contentType] = attachment.split(':');\n return !contentType.includes('/');\n }\n return false;\n }) as string[];\n\n this.attachments = [...runtimeAttachments, ...formattedAttachments];\n this.fireEvent('change');\n }\n\n private handleDragEnter(evt: DragEvent): void {\n this.highlight(evt);\n }\n\n private handleDragOver(evt: DragEvent): void {\n this.highlight(evt);\n }\n\n private handleDragLeave(evt: DragEvent): void {\n this.unhighlight(evt);\n }\n\n private handleDrop(evt: DragEvent): void {\n this.unhighlight(evt);\n\n // Forward to media picker\n if (this.mediaPickerElement) {\n const files = [...evt.dataTransfer.files];\n this.mediaPickerElement.uploadFiles(files);\n }\n }\n\n private handleAttachmentIconClick(): void {\n // Trigger the file picker on the media picker\n if (this.mediaPickerElement) {\n const uploadInput = this.mediaPickerElement.shadowRoot.querySelector(\n '#upload-input'\n ) as HTMLInputElement;\n if (uploadInput) {\n uploadInput.click();\n }\n }\n }\n\n private highlight(evt: DragEvent): void {\n evt.preventDefault();\n evt.stopPropagation();\n\n // Always allow highlight for testing purposes, but in real usage check media picker\n this.pendingDrop = true;\n }\n\n private unhighlight(evt: DragEvent): void {\n evt.preventDefault();\n evt.stopPropagation();\n this.pendingDrop = false;\n }\n\n public updated(changedProperties: Map<string, any>) {\n super.updated(changedProperties);\n\n if (changedProperties.has('attachments')) {\n // Re-query media picker since the DOM structure may have changed\n this.mediaPickerElement = this.shadowRoot.querySelector(\n 'temba-media-picker'\n ) as MediaPicker;\n }\n\n if (changedProperties.has('uploading')) {\n this.dispatchEvent(\n new CustomEvent('loading', {\n detail: { loading: this.uploading }\n })\n );\n }\n }\n\n public focus() {\n super.focus();\n if (this.completionElement) {\n this.completionElement.focus();\n }\n }\n\n public click() {\n super.click();\n if (this.completionElement) {\n this.completionElement.click();\n }\n }\n\n public render(): TemplateResult {\n return this.renderField();\n }\n\n protected renderWidget(): TemplateResult {\n const hasAttachments = this.hasStaticAttachments();\n\n return html`\n <div\n class=${getClasses({\n 'message-editor-container': true,\n highlight: this.pendingDrop,\n 'has-attachments': hasAttachments\n })}\n @dragenter=${this.handleDragEnter}\n @dragover=${this.handleDragOver}\n @dragleave=${this.handleDragLeave}\n @drop=${this.handleDrop}\n >\n <div class=\"completion-wrapper\">\n <temba-completion\n name=${this.name}\n .value=${this.value}\n placeholder=${this.placeholder}\n ?textarea=${this.textarea}\n ?autogrow=${this.autogrow}\n ?session=${this.session}\n ?submitOnEnter=${this.submitOnEnter}\n ?gsm=${this.gsm}\n ?disableCompletion=${this.disableCompletion}\n maxlength=${ifDefined(this.maxLength)}\n counter=${ifDefined(this.counter)}\n minHeight=${ifDefined(this.minHeight)}\n widgetOnly\n @change=${this.handleCompletionChange}\n ></temba-completion>\n </div>\n\n <div class=\"media-wrapper \">\n <temba-media-picker\n .accept=${this.accept}\n .max=${this.maxAttachments}\n .endpoint=${this.endpoint}\n @change=${this.handleMediaChange}\n ignoreDrops\n ></temba-media-picker>\n </div>\n <temba-icon\n class=\"attachment-icon\"\n name=${Icon.attachment}\n size=\"1.2\"\n @click=${this.handleAttachmentIconClick}\n ></temba-icon>\n\n <div class=\"drop-overlay\"></div>\n\n <!-- Hidden media picker for handling uploads when no attachments are shown -->\n ${!hasAttachments\n ? html`<temba-media-picker\n style=\"display: none;\"\n .accept=${this.accept}\n .max=${this.maxAttachments}\n .endpoint=${this.endpoint}\n @change=${this.handleMediaChange}\n ignoreDrops\n ></temba-media-picker>`\n : ''}\n </div>\n `;\n }\n}\n"]}
@@ -2,9 +2,9 @@ import { __decorate } from "tslib";
2
2
  import { css, html } from 'lit';
3
3
  import { styleMap } from 'lit-html/directives/style-map.js';
4
4
  import { property } from 'lit/decorators.js';
5
- import { FormElement } from './FormElement';
5
+ import { FieldElement } from './FieldElement';
6
6
  import { getClasses } from '../utils';
7
- export class TembaSlider extends FormElement {
7
+ export class TembaSlider extends FieldElement {
8
8
  constructor() {
9
9
  super(...arguments);
10
10
  this.range = false;
@@ -128,7 +128,7 @@ export class TembaSlider extends FormElement {
128
128
  this.circleX = pctAsPixels + (pre ? pre.offsetWidth : 0);
129
129
  this.requestUpdate();
130
130
  }
131
- render() {
131
+ renderWidget() {
132
132
  return html ` <div class="${getClasses({ grabbed: this.grabbed })}">
133
133
  <div
134
134
  style=${styleMap({ left: this.circleX + 'px' })}
@@ -1 +1 @@
1
- {"version":3,"file":"TembaSlider.js","sourceRoot":"","sources":["../../../src/form/TembaSlider.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, TemplateResult } from 'lit';\nimport { styleMap } from 'lit-html/directives/style-map.js';\nimport { property } from 'lit/decorators.js';\nimport { FormElement } from './FormElement';\nimport { getClasses } from '../utils';\n\nexport class TembaSlider extends FormElement {\n static get styles() {\n return css`\n :host {\n display: block;\n }\n\n .track {\n height: 2px;\n border-top: 0.5em solid #fff;\n border-bottom: 0.5em solid #fff;\n background: #ddd;\n flex-grow: 1;\n }\n\n .circle {\n margin-bottom: -1.05em;\n margin-left: -0.5em;\n width: 0.75em;\n height: 0.75em;\n border: 2px solid #999;\n border-radius: 999px;\n position: relative;\n background: #fff;\n box-shadow: 0 0 0 4px rgb(255, 255, 255);\n transition: transform 200ms ease-in-out;\n }\n\n .grabbed .track {\n cursor: pointer;\n }\n\n :hover .circle {\n border-color: #777;\n cursor: pointer;\n }\n\n .grabbed .circle {\n border-color: var(--color-primary-dark);\n background: #fff;\n }\n\n .grabbed .circle {\n transform: scale(1.2);\n }\n\n .wrapper {\n display: flex;\n align-items: center;\n }\n\n .pre,\n .post {\n font-size: 0.9em;\n color: #999;\n padding: 0em 1em;\n }\n `;\n }\n\n @property({ type: Boolean })\n range = false;\n\n @property({ type: Number })\n min = 0;\n\n @property({ type: Number })\n max = 100;\n\n circleX = 0;\n grabbed = false;\n\n public firstUpdated(changes: Map<string, any>) {\n super.firstUpdated(changes);\n this.handleMouseMove = this.handleMouseMove.bind(this);\n this.handleMouseUp = this.handleMouseUp.bind(this);\n }\n\n public updated(changedProperties: Map<string, any>): void {\n if (changedProperties.has('value')) {\n this.updateCircle();\n }\n }\n\n public updateValue(evt: MouseEvent) {\n const track = this.shadowRoot.querySelector('.track') as HTMLDivElement;\n const left = evt.pageX - track.offsetLeft;\n const pct = left / track.offsetWidth;\n\n const range = this.max - this.min;\n const pctAsValue = range * pct + this.min;\n this.value =\n '' + Math.max(this.min, Math.min(Math.round(pctAsValue), this.max));\n }\n\n public handleMouseMove(evt: MouseEvent) {\n if (this.grabbed) {\n this.updateValue(evt);\n }\n }\n\n public handleTrackDown(evt: MouseEvent) {\n this.grabbed = true;\n document.addEventListener('mousemove', this.handleMouseMove);\n document.addEventListener('mouseup', this.handleMouseUp);\n document.querySelector('html').classList.add('dragging');\n this.updateValue(evt);\n this.requestUpdate();\n }\n\n public handleMouseUp(evt: MouseEvent) {\n this.grabbed = false;\n this.updateValue(evt);\n this.requestUpdate();\n\n document.removeEventListener('mousemove', this.handleMouseMove);\n document.removeEventListener('mouseup', this.handleMouseUp);\n document.querySelector('html').classList.remove('dragging');\n }\n\n public updateCircle() {\n const track = this.shadowRoot.querySelector('.track') as HTMLDivElement;\n const pre = this.shadowRoot.querySelector('.pre') as HTMLDivElement;\n const range = this.max - this.min;\n let cValue = parseInt(this.value);\n if (!cValue || cValue < this.min) {\n cValue = this.min;\n } else if (cValue > this.max) {\n cValue = this.max;\n }\n this.value = '' + cValue;\n const pct = (cValue - this.min) / range;\n const pctAsPixels = track.offsetWidth * pct;\n\n this.circleX = pctAsPixels + (pre ? pre.offsetWidth : 0);\n this.requestUpdate();\n }\n\n public render(): TemplateResult {\n return html` <div class=\"${getClasses({ grabbed: this.grabbed })}\">\n <div\n style=${styleMap({ left: this.circleX + 'px' })}\n class=\"circle\"\n @mousedown=${this.handleTrackDown}\n ></div>\n <div class=\"wrapper\">\n ${this.range ? html`<div class=\"pre\">${this.min}</div>` : null}\n <div class=\"track\" @mousedown=${this.handleTrackDown}></div>\n ${this.range ? html`<div class=\"post\">${this.max}</div>` : null}\n </div>\n </div>`;\n }\n}\n"]}
1
+ {"version":3,"file":"TembaSlider.js","sourceRoot":"","sources":["../../../src/form/TembaSlider.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, TemplateResult } from 'lit';\nimport { styleMap } from 'lit-html/directives/style-map.js';\nimport { property } from 'lit/decorators.js';\nimport { FieldElement } from './FieldElement';\nimport { getClasses } from '../utils';\n\nexport class TembaSlider extends FieldElement {\n static get styles() {\n return css`\n :host {\n display: block;\n }\n\n .track {\n height: 2px;\n border-top: 0.5em solid #fff;\n border-bottom: 0.5em solid #fff;\n background: #ddd;\n flex-grow: 1;\n }\n\n .circle {\n margin-bottom: -1.05em;\n margin-left: -0.5em;\n width: 0.75em;\n height: 0.75em;\n border: 2px solid #999;\n border-radius: 999px;\n position: relative;\n background: #fff;\n box-shadow: 0 0 0 4px rgb(255, 255, 255);\n transition: transform 200ms ease-in-out;\n }\n\n .grabbed .track {\n cursor: pointer;\n }\n\n :hover .circle {\n border-color: #777;\n cursor: pointer;\n }\n\n .grabbed .circle {\n border-color: var(--color-primary-dark);\n background: #fff;\n }\n\n .grabbed .circle {\n transform: scale(1.2);\n }\n\n .wrapper {\n display: flex;\n align-items: center;\n }\n\n .pre,\n .post {\n font-size: 0.9em;\n color: #999;\n padding: 0em 1em;\n }\n `;\n }\n\n @property({ type: Boolean })\n range = false;\n\n @property({ type: Number })\n min = 0;\n\n @property({ type: Number })\n max = 100;\n\n circleX = 0;\n grabbed = false;\n\n public firstUpdated(changes: Map<string, any>) {\n super.firstUpdated(changes);\n this.handleMouseMove = this.handleMouseMove.bind(this);\n this.handleMouseUp = this.handleMouseUp.bind(this);\n }\n\n public updated(changedProperties: Map<string, any>): void {\n if (changedProperties.has('value')) {\n this.updateCircle();\n }\n }\n\n public updateValue(evt: MouseEvent) {\n const track = this.shadowRoot.querySelector('.track') as HTMLDivElement;\n const left = evt.pageX - track.offsetLeft;\n const pct = left / track.offsetWidth;\n\n const range = this.max - this.min;\n const pctAsValue = range * pct + this.min;\n this.value =\n '' + Math.max(this.min, Math.min(Math.round(pctAsValue), this.max));\n }\n\n public handleMouseMove(evt: MouseEvent) {\n if (this.grabbed) {\n this.updateValue(evt);\n }\n }\n\n public handleTrackDown(evt: MouseEvent) {\n this.grabbed = true;\n document.addEventListener('mousemove', this.handleMouseMove);\n document.addEventListener('mouseup', this.handleMouseUp);\n document.querySelector('html').classList.add('dragging');\n this.updateValue(evt);\n this.requestUpdate();\n }\n\n public handleMouseUp(evt: MouseEvent) {\n this.grabbed = false;\n this.updateValue(evt);\n this.requestUpdate();\n\n document.removeEventListener('mousemove', this.handleMouseMove);\n document.removeEventListener('mouseup', this.handleMouseUp);\n document.querySelector('html').classList.remove('dragging');\n }\n\n public updateCircle() {\n const track = this.shadowRoot.querySelector('.track') as HTMLDivElement;\n const pre = this.shadowRoot.querySelector('.pre') as HTMLDivElement;\n const range = this.max - this.min;\n let cValue = parseInt(this.value);\n if (!cValue || cValue < this.min) {\n cValue = this.min;\n } else if (cValue > this.max) {\n cValue = this.max;\n }\n this.value = '' + cValue;\n const pct = (cValue - this.min) / range;\n const pctAsPixels = track.offsetWidth * pct;\n\n this.circleX = pctAsPixels + (pre ? pre.offsetWidth : 0);\n this.requestUpdate();\n }\n\n public renderWidget(): TemplateResult {\n return html` <div class=\"${getClasses({ grabbed: this.grabbed })}\">\n <div\n style=${styleMap({ left: this.circleX + 'px' })}\n class=\"circle\"\n @mousedown=${this.handleTrackDown}\n ></div>\n <div class=\"wrapper\">\n ${this.range ? html`<div class=\"pre\">${this.min}</div>` : null}\n <div class=\"track\" @mousedown=${this.handleTrackDown}></div>\n ${this.range ? html`<div class=\"post\">${this.max}</div>` : null}\n </div>\n </div>`;\n }\n}\n"]}
@@ -1,10 +1,10 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { property } from 'lit/decorators.js';
3
- import { FormElement } from './FormElement';
4
3
  import { html, css, LitElement } from 'lit';
5
4
  import { CustomEventType } from '../interfaces';
6
5
  import { getClasses } from '../utils';
7
- export class TemplateEditor extends FormElement {
6
+ import { FieldElement } from './FieldElement';
7
+ export class TemplateEditor extends FieldElement {
8
8
  constructor() {
9
9
  super(...arguments);
10
10
  this.pickersLoading = {};
@@ -373,7 +373,7 @@ export class TemplateEditor extends FormElement {
373
373
  <div class="buttons">${buttons}</div>
374
374
  </div>`;
375
375
  }
376
- render() {
376
+ renderWidget() {
377
377
  let content = null;
378
378
  if (this.translation) {
379
379
  content = this.renderComponents(this.translation.components);
@@ -1 +1 @@
1
- {"version":3,"file":"TemplateEditor.js","sourceRoot":"","sources":["../../../src/form/TemplateEditor.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAkB,IAAI,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAyBtC,MAAM,OAAO,cAAe,SAAQ,WAAW;IAA/C;;QAgJE,mBAAc,GAA+B,EAAE,CAAC;QAEhD,yBAAoB,GAAiC,EAAE,CAAC;IAyT1D,CAAC;IArcC,MAAM,KAAK,MAAM;QACf,OAAO,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA+GT,CAAC;IACJ,CAAC;IA6BM,OAAO,CAAC,OAAyB;QACtC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACvB,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC,oBAAoB,GAAG,EAAE,CAAC;YAC/B,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC;YAE7C,+CAA+C;YAC/C,IAAI,IAAI,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACrC,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE;oBAChD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;oBAClC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACrB,kCAAkC;wBAClC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;4BACjC,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;wBAC1C,CAAC;oBACH,CAAC;gBACH,CAAC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAEO,qBAAqB,CAAC,KAAkB;QAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC;QACnC,IAAI,CAAC,gBAAgB,GAAI,KAAK,CAAC,MAAc,CAAC,MAAM,CAAC,CAAC,CAAa,CAAC;QACpE,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,gBAAgB,GAAG,EAAE,CAAC;YAC3B,IAAI,CAAC,oBAAoB,GAAG,EAAE,CAAC;QACjC,CAAC;QAED,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC1B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,gBAAgB,CAAC,gBAAgB,CAAC;YAC1D,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;gBACrB,IAAI,CAAC,SAAS,GAAG,IAAI,KAAK,CACxB,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,MAAM,CAC1C,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACb,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;YACtB,CAAC;QACH,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;YACxB,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;QACtB,CAAC;QAED,IAAI,CAAC,eAAe,CAAC,eAAe,CAAC,cAAc,EAAE;YACnD,QAAQ,EAAE,IAAI,CAAC,gBAAgB;YAC/B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,SAAS,EAAE,IAAI,CAAC,gBAAgB;SACjC,CAAC,CAAC;IACL,CAAC;IAEO,uBAAuB,CAAC,KAAkB;QAChD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAqB,CAAC;QAC1C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;QACpD,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC;QAClD,IAAI,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC;IAEO,wBAAwB,CAAC,KAAkB;QACjD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAqB,CAAC;QAC1C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;QAEpD,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnC,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;QACpC,CAAC;aAAM,CAAC;YACN,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;YACxC,IAAI,UAAU,CAAC,GAAG,IAAI,UAAU,CAAC,YAAY,EAAE,CAAC;gBAC9C,IAAI,CAAC,gBAAgB,CACnB,KAAK,CACN,GAAG,GAAG,UAAU,CAAC,YAAY,IAAI,UAAU,CAAC,GAAG,EAAE,CAAC;YACrD,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;YACpC,CAAC;QACH,CAAC;QACD,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACzB,IAAI,CAAC,aAAa,CAAC,kBAAkB,CAAC,CAAC;IACzC,CAAC;IAEO,qBAAqB,CAAC,KAAiB;QAC7C,MAAM,MAAM,GAAG,KAAK,CAAC,MAA0B,CAAC;QAChD,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;QAC7D,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QAEnD,oCAAoC;QACpC,IAAI,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;QACzB,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC;QACzB,CAAC;QAED,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,GAAG,KAAK,CAAC;QAC7C,IAAI,CAAC,iBAAiB,EAAE,CAAC;IAC3B,CAAC;IAEO,iBAAiB;QACvB,IAAI,CAAC,eAAe,CAAC,eAAe,CAAC,cAAc,EAAE;YACnD,QAAQ,EAAE,IAAI,CAAC,gBAAgB;YAC/B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,SAAS,EAAE,IAAI,CAAC,gBAAgB;SACjC,CAAC,CAAC;IACL,CAAC;IAEO,eAAe,CAAC,SAAoB;;QAC1C,mDAAmD;QACnD,MAAM,aAAa,GAAG,IAAI,MAAM,CAC9B,MAAM,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAC3D,GAAG,CACJ,CAAC;QAEF,IAAI,SAAS,GAAG,IAAI,CAAC;QAErB,IAAI,KAAK,GAAG,EAAE,CAAC;QACf,IAAI,SAAS,CAAC,OAAO,IAAI,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7D,KAAK,GAAG,CAAA,MAAA,SAAS,CAAC,OAAO,0CAAE,KAAK,CAAC,aAAa,CAAC,KAAI,EAAE,CAAC;QACxD,CAAC;QACD,MAAM,aAAa,GAAG,IAAI,CAAC,gBAAgB,IAAI,EAAE,CAAC;QAClD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;gBACpC,IAAI,KAAK,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;oBACpB,OAAO,IAAI,CAAA,sBAAsB,IAAI,SAAS,CAAC;gBACjD,CAAC;gBACD,MAAM,aAAa,GAAG,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;gBAEhD,OAAO,IAAI,CAAA;;;kBAGD,aAAa,GAAG,aAAa,CAAC,MAAM;oBAC1C,CAAC,CAAC,aAAa,CAAC,aAAa,CAAC;oBAC9B,CAAC,CAAC,IAAI;mBACC,IAAI,CAAC,qBAAqB;kBAC3B,SAAS,CAAC,IAAI;mBACb,aAAa;2BACL,IAAI;6BACF,CAAC;YACxB,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,aAAa,EAAE,EAAE;gBACnE,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;gBAC/D,IACE,YAAY,CAAC,IAAI,KAAK,OAAO;oBAC7B,YAAY,CAAC,IAAI,KAAK,UAAU;oBAChC,YAAY,CAAC,IAAI,KAAK,OAAO;oBAC7B,YAAY,CAAC,IAAI,KAAK,OAAO,EAC7B,CAAC;oBACD,IAAI,WAAW,GAAG,EAAE,CAAC;oBACrB,IAAI,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,EAAE,CAAC;wBACzC,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;wBAC9D,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;wBAC9B,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;wBACrC,WAAW,GAAG,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC,CAAC;oBACxC,CAAC;oBAED,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;oBAEnD,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,GAAG,GAAG,CAAC;oBACvC,IAAI,KAAK,GACP,aAAa,GAAG,aAAa,CAAC,MAAM;wBAClC,CAAC,CAAC,aAAa,CAAC,aAAa,CAAC;wBAC9B,CAAC,CAAC,IAAI,CAAC;oBAEX,IAAI,KAAK,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;wBACtC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;oBACrC,CAAC;oBAED,OAAO,IAAI,CAAA;cACP,IAAI,CAAC,oBAAoB,CAAC,aAAa,CAAC;wBACxC,CAAC,CAAC,IAAI,CAAA;sBACE,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE;4BAC3C,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;;;;;;;;gCAQd,MAAM;8BACR,aAAa;8BACb,KAAK;+BACJ,IAAI,CAAC,qBAAqB;;;;;+BAK1B,GAAG,EAAE;4BACZ,IAAI,CAAC,oBAAoB,CAAC,aAAa,CAAC,GAAG,KAAK,CAAC;4BACjD,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC;4BAC1C,IAAI,CAAC,aAAa,EAAE,CAAC;wBACvB,CAAC;;;;yBAIE;wBACX,CAAC,CAAC,IAAI,CAAA;;4BAEQ,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;;;;;;gBAMnC,WAAW,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO;4BAC9B,CAAC,CAAC,mCAAmC;4BACrC,CAAC,CAAC,EAAE;;;gCAGM,YAAY,CAAC,IAAI,KAAK,UAAU;4BACxC,CAAC,CAAC,iBAAiB;4BACnB,CAAC,CAAC,YAAY,CAAC,IAAI,GAAG,IAAI;;8BAEpB,aAAa;yCACF,YAAY,CAAC,IAAI;oCACtB,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;uCACxB,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC;gCAC9C,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC;;;wBAGhD,WAAW,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO;4BACnC,CAAC,CAAC,IAAI,CAAA,UAAU,YAAY,CAAC,IAAI,cAAc;4BAC/C,CAAC,CAAC,EAAE;;;;;+BAKG,GAAG,EAAE;4BACZ,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC;4BAC1C,IAAI,CAAC,oBAAoB,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC;4BAChD,IAAI,CAAC,aAAa,EAAE,CAAC;wBACvB,CAAC;;;;iBAIN;WACN,CAAC;gBACJ,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;QAED,OAAO,IAAI,CAAA,wBAAwB,SAAS,SAAS,CAAC;IACxD,CAAC;IAEM,gBAAgB,CAAC,UAAuB;QAC7C,MAAM,UAAU,GAAG,UAAU;aAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;aAClD,GAAG,CACF,CAAC,SAAS,EAAE,EAAE,CACZ,IAAI,CAAA,eAAe,SAAS,CAAC,MAAM,CAAC;cAChC,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC;iBAC5B,CACV,CAAC;QACJ,MAAM,gBAAgB,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAClD,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAChC,CAAC;QACF,MAAM,OAAO,GACX,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC5E,OAAO,IAAI,CAAA,qBAAqB,UAAU;;UAEpC,OAAO;;aAEJ,CAAC;IACZ,CAAC;IAEM,aAAa,CAAC,UAAU;QAC7B,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE;YAC3C,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;gBACtB,OAAO,IAAI,CAAA;;mCAEgB,SAAS,CAAC,OAAO;cACtC,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC;;SAEpC,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,OAAO,IAAI,CAAA;gCACa,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC;SACtD,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;QACH,OAAO,IAAI,CAAA;;6BAEc,OAAO;WACzB,CAAC;IACV,CAAC;IAEM,MAAM;QACX,IAAI,OAAO,GAAG,IAAI,CAAC;QACnB,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;QAC/D,CAAC;aAAM,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACjC,OAAO,GAAG,IAAI,CAAA;;aAEP,CAAC;QACV,CAAC;QAED,OAAO,IAAI,CAAA;;;;uBAIQ,CAAC,IAAI,CAAC,WAAW;sBAClB,IAAI,CAAC,WAAW;;;mBAGnB,IAAI,CAAC,QAAQ;sBACV,IAAI,CAAC,GAAG;0BACJ,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,KAAK,UAAU;;mCAEnC,IAAI,CAAC,YAAY;oBAChC,IAAI,CAAC,qBAAqB;;;UAGpC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAA,0BAA0B,OAAO,QAAQ,CAAC,CAAC,CAAC,IAAI;;KAEnE,CAAC;IACJ,CAAC;;AAzcM,gCAAiB,GAAG;IACzB,GAAG,UAAU,CAAC,iBAAiB;IAC/B,cAAc,EAAE,IAAI;CACrB,AAHuB,CAGtB;AAsHF;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;2CACf;AAIZ;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;gDACV;AAGjB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;wDACA;AAI3B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;iDACN;AAGpB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;wDACC;AAG3B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;mDACpB;AAGzB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;mDACP","sourcesContent":["import { property } from 'lit/decorators.js';\nimport { FormElement } from './FormElement';\nimport { TemplateResult, html, css, LitElement } from 'lit';\nimport { CustomEventType } from '../interfaces';\nimport { MediaPicker } from './MediaPicker';\nimport { getClasses } from '../utils';\n\ninterface Component {\n name: string;\n type: string;\n content: string;\n variables: { [key: string]: number };\n}\n\ninterface Translation {\n locale: string;\n status: string;\n channel: { uuid: string; name: string };\n components: Component[];\n variables: { type: string }[];\n}\n\ninterface Template {\n created_on: string;\n modified_on: string;\n name: string;\n uuid: string;\n base_translation: Translation;\n}\n\nexport class TemplateEditor extends FormElement {\n static shadowRootOptions = {\n ...LitElement.shadowRootOptions,\n delegatesFocus: true\n };\n\n static get styles() {\n return css`\n .component {\n background: #fff;\n border: 1px solid var(--color-widget-border);\n border-radius: var(--curvature);\n padding: 1em;\n margin-top: 1em;\n }\n\n .content {\n }\n\n .picker {\n margin-bottom: 0.5em;\n display: block;\n }\n .param {\n display: flex;\n margin-bottom: 0.5em;\n align-items: center;\n }\n label {\n margin-right: 0.5em;\n }\n\n .content span {\n margin-right: 0.25em;\n }\n\n .error-message {\n padding-left: 0.5em;\n padding-bottom: 1em;\n }\n\n .variable {\n display: inline-block;\n margin: 0.25em 0em;\n margin-right: 0.25em;\n }\n\n .button-wrapper {\n background: #f9f9f9;\n border-radius: var(--curvature);\n padding: 0.5em;\n display: flex;\n flex-direction: column;\n }\n\n .button-header {\n font-weight: normal;\n margin-left: 0.25em;\n margin-bottom: -0.5em;\n font-size: 0.9em;\n color: #777;\n }\n\n .buttons {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n margin-bottom: 1em;\n }\n\n .button {\n background: #fff;\n padding: 0.3em 1em;\n border: 1px solid #e6e6e6;\n border-radius: var(--curvature);\n min-height: 23px;\n display: flex;\n flex-direction: row;\n align-items: center;\n margin-right: 0.5em;\n margin-top: 0.5em;\n align-items: center;\n }\n\n .button .content {\n margin-bottom: 0;\n }\n\n .button .display {\n margin-right: 0.5em;\n background: #f9f9f9;\n padding: 0.25em 1em;\n border-radius: var(--curvature);\n }\n\n .variable {\n --temba-textinput-padding: 5px 5px;\n --temba-textinput-font-size: 0.9em;\n line-height: initial;\n }\n\n .template {\n background: #fff;\n border-radius: var(--curvature);\n border: 1px solid var(--color-widget-border);\n padding: 1em;\n line-height: 2.2em;\n max-height: 50vh;\n overflow-y: auto;\n overflow-x: hidden;\n padding-bottom: 0;\n }\n\n .label {\n font-size: 0.9em;\n color: #777;\n margin-left: 0.25em;\n }\n `;\n }\n\n @property({ type: String })\n url: string;\n\n // initial template uuid\n @property({ type: String })\n template: string;\n\n @property({ type: Object })\n selectedTemplate: Template;\n\n // initial variables, not reflected back\n @property({ type: Array })\n variables: string[];\n\n @property({ type: Array })\n currentVariables: string[];\n\n @property({ type: Object, attribute: false })\n translation: Translation;\n\n @property({ type: Boolean })\n translating: boolean;\n\n pickersLoading: { [key: number]: boolean } = {};\n\n textInputAttachments: { [index: number]: boolean } = {};\n\n public updated(changes: Map<string, any>): void {\n super.updated(changes);\n if (changes.has('template')) {\n this.textInputAttachments = {};\n this.currentVariables = this.variables || [];\n\n // check if our variables should be a textinput\n if (this.currentVariables.length > 0) {\n this.currentVariables.forEach((variable, index) => {\n const split = variable.split(':');\n if (split.length > 1) {\n // we have a generary content type\n if (split[0].indexOf('/') === -1) {\n this.textInputAttachments[index] = true;\n }\n }\n });\n }\n }\n }\n\n private handleTemplateChanged(event: CustomEvent) {\n const prev = this.selectedTemplate;\n this.selectedTemplate = (event.target as any).values[0] as Template;\n if (prev) {\n this.currentVariables = [];\n this.textInputAttachments = {};\n }\n\n if (this.selectedTemplate) {\n this.translation = this.selectedTemplate.base_translation;\n if (this.translation) {\n this.variables = new Array(\n (this.translation.variables || []).length\n ).fill('');\n } else {\n this.variables = [];\n }\n } else {\n this.translation = null;\n this.variables = [];\n }\n\n this.fireCustomEvent(CustomEventType.ContextChanged, {\n template: this.selectedTemplate,\n translation: this.translation,\n variables: this.currentVariables\n });\n }\n\n private handleAttachmentLoading(event: CustomEvent) {\n const media = event.target as MediaPicker;\n const index = parseInt(media.getAttribute('index'));\n this.pickersLoading[index] = event.detail.loading;\n this.requestUpdate();\n }\n\n private handleAttachmentsChanged(event: CustomEvent) {\n const media = event.target as MediaPicker;\n const index = parseInt(media.getAttribute('index'));\n\n if (media.attachments.length === 0) {\n this.currentVariables[index] = '';\n } else {\n const attachment = media.attachments[0];\n if (attachment.url && attachment.content_type) {\n this.currentVariables[\n index\n ] = `${attachment.content_type}:${attachment.url}`;\n } else {\n this.currentVariables[index] = ``;\n }\n }\n this.fireContentChange();\n this.requestUpdate('currentVariables');\n }\n\n private handleVariableChanged(event: InputEvent) {\n const target = event.target as HTMLInputElement;\n const variableIndex = parseInt(target.getAttribute('index'));\n const prefix = target.getAttribute('prefix') || '';\n\n // add our prefix if we have a value\n let value = target.value;\n if (value) {\n value = prefix + value;\n }\n\n this.currentVariables[variableIndex] = value;\n this.fireContentChange();\n }\n\n private fireContentChange() {\n this.fireCustomEvent(CustomEventType.ContentChanged, {\n template: this.selectedTemplate,\n translation: this.translation,\n variables: this.currentVariables\n });\n }\n\n private renderVariables(component: Component) {\n // create a regex match based on the variable names\n const variableRegex = new RegExp(\n `{{(${Object.keys(component.variables || []).join('|')})}}`,\n 'g'\n );\n\n let variables = null;\n\n let parts = [];\n if (component.content && component.content.trim().length > 0) {\n parts = component.content?.split(variableRegex) || [];\n }\n const currVariables = this.currentVariables || [];\n if (parts.length > 0) {\n variables = parts.map((part, index) => {\n if (index % 2 === 0) {\n return html`<span class=\"text\">${part}</span>`;\n }\n const variableIndex = component.variables[part];\n\n return html`<temba-completion\n class=\"variable\"\n type=\"text\"\n value=${variableIndex < currVariables.length\n ? currVariables[variableIndex]\n : null}\n @keyup=${this.handleVariableChanged}\n name=\"${component.name}\"\n index=\"${variableIndex}\"\n placeholder=\"{{${part}}}\"\n ></temba-completion>`;\n });\n } else {\n variables = Object.values(component.variables).map((variableIndex) => {\n const variableSpec = this.translation.variables[variableIndex];\n if (\n variableSpec.type === 'image' ||\n variableSpec.type === 'document' ||\n variableSpec.type === 'audio' ||\n variableSpec.type === 'video'\n ) {\n let attachments = [];\n if (this.currentVariables[variableIndex]) {\n const parts = this.currentVariables[variableIndex].split(':');\n const content_type = parts[0];\n const url = parts.slice(1).join(':');\n attachments = [{ url, content_type }];\n }\n\n const loading = this.pickersLoading[variableIndex];\n\n const prefix = variableSpec.type + ':';\n let value =\n variableIndex < currVariables.length\n ? currVariables[variableIndex]\n : null;\n\n if (value && value.startsWith(prefix)) {\n value = value.slice(prefix.length);\n }\n\n return html`\n ${this.textInputAttachments[variableIndex]\n ? html` <div class=\"label\">\n ${variableSpec.type.charAt(0).toUpperCase() +\n variableSpec.type.slice(1)}\n URL\n </div>\n <div\n style=\"display:flex;align-items:center;margin-bottom:1em;\"\n >\n <temba-completion\n style=\"flex-grow:1; margin-right:1em;\"\n prefix=\"${prefix}\"\n index=${variableIndex}\n value=${value}\n @keyup=${this.handleVariableChanged}\n ></temba-completion>\n <temba-icon\n name=\"close\"\n clickable\n @click=${() => {\n this.textInputAttachments[variableIndex] = false;\n this.currentVariables[variableIndex] = '';\n this.requestUpdate();\n }}\n >\n </temba-icon>\n <div></div>\n </div>`\n : html`\n <div\n class=${getClasses({ loading })}\n style=\"\n display: flex; \n align-items: center; \n border-radius: var(--curvature);\n margin-bottom: 0.5em;\n ${attachments.length === 0 && !loading\n ? `background-color:rgba(0,0,0,.04);`\n : ``}\"\n >\n <temba-media-picker\n accept=\"${variableSpec.type === 'document'\n ? 'application/pdf'\n : variableSpec.type + '/*'}\"\n max=\"1\"\n index=${variableIndex}\n icon=\"attachment_${variableSpec.type}\"\n attachments=${JSON.stringify(attachments)}\n @temba-loading=${this.handleAttachmentLoading.bind(this)}\n @change=${this.handleAttachmentsChanged.bind(this)}\n ></temba-media-picker>\n <div style=\"flex-grow:1\">\n ${attachments.length == 0 && !loading\n ? html`Attach ${variableSpec.type} to continue`\n : ''}\n </div>\n <temba-icon\n clickable\n name=\"edit\"\n @click=${() => {\n this.currentVariables[variableIndex] = '';\n this.textInputAttachments[variableIndex] = true;\n this.requestUpdate();\n }}\n style=\"margin-right:1em\"\n ></temba-icon>\n </div>\n `}\n `;\n }\n });\n }\n\n return html`<div class=\"content\">${variables}</div> `;\n }\n\n public renderComponents(components: Component[]): TemplateResult {\n const nonButtons = components\n .filter((comp) => !comp.type.startsWith('button/'))\n .map(\n (component) =>\n html`<div class=\"${component['name']}\">\n ${this.renderVariables(component)}\n </div>`\n );\n const buttonComponents = components.filter((comp) =>\n comp.type.startsWith('button/')\n );\n const buttons =\n buttonComponents.length > 0 ? this.renderButtons(buttonComponents) : null;\n return html`<div class=\"main\">${nonButtons}</div>\n <div class=\"buttons\">\n ${buttons}\n <div></div>\n </div>`;\n }\n\n public renderButtons(components): TemplateResult {\n const buttons = components.map((component) => {\n if (component.display) {\n return html`\n <div class=\"button\">\n <div class=\"display\">${component.display}</div>\n ${this.renderVariables(component)}\n </div>\n `;\n } else {\n return html`\n <div class=\"button\">${this.renderVariables(component)}</div>\n `;\n }\n });\n return html`<div class=\"button-wrapper\">\n <div class=\"button-header\">Template Buttons</div>\n <div class=\"buttons\">${buttons}</div>\n </div>`;\n }\n\n public render(): TemplateResult {\n let content = null;\n if (this.translation) {\n content = this.renderComponents(this.translation.components);\n } else if (this.selectedTemplate) {\n content = html`<div class=\"error-message\">\n This template currently has no approved translations.\n </div>`;\n }\n\n return html`\n <div>\n <temba-select\n searchable\n ?clearable=${!this.translating}\n ?disabled=${this.translating}\n valuekey=\"uuid\"\n class=\"picker\"\n value=\"${this.template}\"\n endpoint=\"${this.url}\"\n shouldExclude=${(template) => template.status !== 'approved'}\n placeholder=\"Select a template\"\n @temba-content-changed=${this.swallowEvent}\n @change=${this.handleTemplateChanged}\n >\n </temba-select>\n ${content ? html` <div class=\"template\">${content}</div>` : null}\n </div>\n `;\n }\n}\n"]}
1
+ {"version":3,"file":"TemplateEditor.js","sourceRoot":"","sources":["../../../src/form/TemplateEditor.ts"],"names":[],"mappings":"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","sourcesContent":["import { property } from 'lit/decorators.js';\nimport { TemplateResult, html, css, LitElement } from 'lit';\nimport { CustomEventType } from '../interfaces';\nimport { MediaPicker } from './MediaPicker';\nimport { getClasses } from '../utils';\nimport { FieldElement } from './FieldElement';\n\ninterface Component {\n name: string;\n type: string;\n content: string;\n variables: { [key: string]: number };\n}\n\ninterface Translation {\n locale: string;\n status: string;\n channel: { uuid: string; name: string };\n components: Component[];\n variables: { type: string }[];\n}\n\ninterface Template {\n created_on: string;\n modified_on: string;\n name: string;\n uuid: string;\n base_translation: Translation;\n}\n\nexport class TemplateEditor extends FieldElement {\n static shadowRootOptions = {\n ...LitElement.shadowRootOptions,\n delegatesFocus: true\n };\n\n static get styles() {\n return css`\n .component {\n background: #fff;\n border: 1px solid var(--color-widget-border);\n border-radius: var(--curvature);\n padding: 1em;\n margin-top: 1em;\n }\n\n .content {\n }\n\n .picker {\n margin-bottom: 0.5em;\n display: block;\n }\n .param {\n display: flex;\n margin-bottom: 0.5em;\n align-items: center;\n }\n label {\n margin-right: 0.5em;\n }\n\n .content span {\n margin-right: 0.25em;\n }\n\n .error-message {\n padding-left: 0.5em;\n padding-bottom: 1em;\n }\n\n .variable {\n display: inline-block;\n margin: 0.25em 0em;\n margin-right: 0.25em;\n }\n\n .button-wrapper {\n background: #f9f9f9;\n border-radius: var(--curvature);\n padding: 0.5em;\n display: flex;\n flex-direction: column;\n }\n\n .button-header {\n font-weight: normal;\n margin-left: 0.25em;\n margin-bottom: -0.5em;\n font-size: 0.9em;\n color: #777;\n }\n\n .buttons {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n margin-bottom: 1em;\n }\n\n .button {\n background: #fff;\n padding: 0.3em 1em;\n border: 1px solid #e6e6e6;\n border-radius: var(--curvature);\n min-height: 23px;\n display: flex;\n flex-direction: row;\n align-items: center;\n margin-right: 0.5em;\n margin-top: 0.5em;\n align-items: center;\n }\n\n .button .content {\n margin-bottom: 0;\n }\n\n .button .display {\n margin-right: 0.5em;\n background: #f9f9f9;\n padding: 0.25em 1em;\n border-radius: var(--curvature);\n }\n\n .variable {\n --temba-textinput-padding: 5px 5px;\n --temba-textinput-font-size: 0.9em;\n line-height: initial;\n }\n\n .template {\n background: #fff;\n border-radius: var(--curvature);\n border: 1px solid var(--color-widget-border);\n padding: 1em;\n line-height: 2.2em;\n max-height: 50vh;\n overflow-y: auto;\n overflow-x: hidden;\n padding-bottom: 0;\n }\n\n .label {\n font-size: 0.9em;\n color: #777;\n margin-left: 0.25em;\n }\n `;\n }\n\n @property({ type: String })\n url: string;\n\n // initial template uuid\n @property({ type: String })\n template: string;\n\n @property({ type: Object })\n selectedTemplate: Template;\n\n // initial variables, not reflected back\n @property({ type: Array })\n variables: string[];\n\n @property({ type: Array })\n currentVariables: string[];\n\n @property({ type: Object, attribute: false })\n translation: Translation;\n\n @property({ type: Boolean })\n translating: boolean;\n\n pickersLoading: { [key: number]: boolean } = {};\n\n textInputAttachments: { [index: number]: boolean } = {};\n\n public updated(changes: Map<string, any>): void {\n super.updated(changes);\n if (changes.has('template')) {\n this.textInputAttachments = {};\n this.currentVariables = this.variables || [];\n\n // check if our variables should be a textinput\n if (this.currentVariables.length > 0) {\n this.currentVariables.forEach((variable, index) => {\n const split = variable.split(':');\n if (split.length > 1) {\n // we have a generary content type\n if (split[0].indexOf('/') === -1) {\n this.textInputAttachments[index] = true;\n }\n }\n });\n }\n }\n }\n\n private handleTemplateChanged(event: CustomEvent) {\n const prev = this.selectedTemplate;\n this.selectedTemplate = (event.target as any).values[0] as Template;\n if (prev) {\n this.currentVariables = [];\n this.textInputAttachments = {};\n }\n\n if (this.selectedTemplate) {\n this.translation = this.selectedTemplate.base_translation;\n if (this.translation) {\n this.variables = new Array(\n (this.translation.variables || []).length\n ).fill('');\n } else {\n this.variables = [];\n }\n } else {\n this.translation = null;\n this.variables = [];\n }\n\n this.fireCustomEvent(CustomEventType.ContextChanged, {\n template: this.selectedTemplate,\n translation: this.translation,\n variables: this.currentVariables\n });\n }\n\n private handleAttachmentLoading(event: CustomEvent) {\n const media = event.target as MediaPicker;\n const index = parseInt(media.getAttribute('index'));\n this.pickersLoading[index] = event.detail.loading;\n this.requestUpdate();\n }\n\n private handleAttachmentsChanged(event: CustomEvent) {\n const media = event.target as MediaPicker;\n const index = parseInt(media.getAttribute('index'));\n\n if (media.attachments.length === 0) {\n this.currentVariables[index] = '';\n } else {\n const attachment = media.attachments[0];\n if (attachment.url && attachment.content_type) {\n this.currentVariables[\n index\n ] = `${attachment.content_type}:${attachment.url}`;\n } else {\n this.currentVariables[index] = ``;\n }\n }\n this.fireContentChange();\n this.requestUpdate('currentVariables');\n }\n\n private handleVariableChanged(event: InputEvent) {\n const target = event.target as HTMLInputElement;\n const variableIndex = parseInt(target.getAttribute('index'));\n const prefix = target.getAttribute('prefix') || '';\n\n // add our prefix if we have a value\n let value = target.value;\n if (value) {\n value = prefix + value;\n }\n\n this.currentVariables[variableIndex] = value;\n this.fireContentChange();\n }\n\n private fireContentChange() {\n this.fireCustomEvent(CustomEventType.ContentChanged, {\n template: this.selectedTemplate,\n translation: this.translation,\n variables: this.currentVariables\n });\n }\n\n private renderVariables(component: Component) {\n // create a regex match based on the variable names\n const variableRegex = new RegExp(\n `{{(${Object.keys(component.variables || []).join('|')})}}`,\n 'g'\n );\n\n let variables = null;\n\n let parts = [];\n if (component.content && component.content.trim().length > 0) {\n parts = component.content?.split(variableRegex) || [];\n }\n const currVariables = this.currentVariables || [];\n if (parts.length > 0) {\n variables = parts.map((part, index) => {\n if (index % 2 === 0) {\n return html`<span class=\"text\">${part}</span>`;\n }\n const variableIndex = component.variables[part];\n\n return html`<temba-completion\n class=\"variable\"\n type=\"text\"\n value=${variableIndex < currVariables.length\n ? currVariables[variableIndex]\n : null}\n @keyup=${this.handleVariableChanged}\n name=\"${component.name}\"\n index=\"${variableIndex}\"\n placeholder=\"{{${part}}}\"\n ></temba-completion>`;\n });\n } else {\n variables = Object.values(component.variables).map((variableIndex) => {\n const variableSpec = this.translation.variables[variableIndex];\n if (\n variableSpec.type === 'image' ||\n variableSpec.type === 'document' ||\n variableSpec.type === 'audio' ||\n variableSpec.type === 'video'\n ) {\n let attachments = [];\n if (this.currentVariables[variableIndex]) {\n const parts = this.currentVariables[variableIndex].split(':');\n const content_type = parts[0];\n const url = parts.slice(1).join(':');\n attachments = [{ url, content_type }];\n }\n\n const loading = this.pickersLoading[variableIndex];\n\n const prefix = variableSpec.type + ':';\n let value =\n variableIndex < currVariables.length\n ? currVariables[variableIndex]\n : null;\n\n if (value && value.startsWith(prefix)) {\n value = value.slice(prefix.length);\n }\n\n return html`\n ${this.textInputAttachments[variableIndex]\n ? html` <div class=\"label\">\n ${variableSpec.type.charAt(0).toUpperCase() +\n variableSpec.type.slice(1)}\n URL\n </div>\n <div\n style=\"display:flex;align-items:center;margin-bottom:1em;\"\n >\n <temba-completion\n style=\"flex-grow:1; margin-right:1em;\"\n prefix=\"${prefix}\"\n index=${variableIndex}\n value=${value}\n @keyup=${this.handleVariableChanged}\n ></temba-completion>\n <temba-icon\n name=\"close\"\n clickable\n @click=${() => {\n this.textInputAttachments[variableIndex] = false;\n this.currentVariables[variableIndex] = '';\n this.requestUpdate();\n }}\n >\n </temba-icon>\n <div></div>\n </div>`\n : html`\n <div\n class=${getClasses({ loading })}\n style=\"\n display: flex; \n align-items: center; \n border-radius: var(--curvature);\n margin-bottom: 0.5em;\n ${attachments.length === 0 && !loading\n ? `background-color:rgba(0,0,0,.04);`\n : ``}\"\n >\n <temba-media-picker\n accept=\"${variableSpec.type === 'document'\n ? 'application/pdf'\n : variableSpec.type + '/*'}\"\n max=\"1\"\n index=${variableIndex}\n icon=\"attachment_${variableSpec.type}\"\n attachments=${JSON.stringify(attachments)}\n @temba-loading=${this.handleAttachmentLoading.bind(this)}\n @change=${this.handleAttachmentsChanged.bind(this)}\n ></temba-media-picker>\n <div style=\"flex-grow:1\">\n ${attachments.length == 0 && !loading\n ? html`Attach ${variableSpec.type} to continue`\n : ''}\n </div>\n <temba-icon\n clickable\n name=\"edit\"\n @click=${() => {\n this.currentVariables[variableIndex] = '';\n this.textInputAttachments[variableIndex] = true;\n this.requestUpdate();\n }}\n style=\"margin-right:1em\"\n ></temba-icon>\n </div>\n `}\n `;\n }\n });\n }\n\n return html`<div class=\"content\">${variables}</div> `;\n }\n\n public renderComponents(components: Component[]): TemplateResult {\n const nonButtons = components\n .filter((comp) => !comp.type.startsWith('button/'))\n .map(\n (component) =>\n html`<div class=\"${component['name']}\">\n ${this.renderVariables(component)}\n </div>`\n );\n const buttonComponents = components.filter((comp) =>\n comp.type.startsWith('button/')\n );\n const buttons =\n buttonComponents.length > 0 ? this.renderButtons(buttonComponents) : null;\n return html`<div class=\"main\">${nonButtons}</div>\n <div class=\"buttons\">\n ${buttons}\n <div></div>\n </div>`;\n }\n\n public renderButtons(components): TemplateResult {\n const buttons = components.map((component) => {\n if (component.display) {\n return html`\n <div class=\"button\">\n <div class=\"display\">${component.display}</div>\n ${this.renderVariables(component)}\n </div>\n `;\n } else {\n return html`\n <div class=\"button\">${this.renderVariables(component)}</div>\n `;\n }\n });\n return html`<div class=\"button-wrapper\">\n <div class=\"button-header\">Template Buttons</div>\n <div class=\"buttons\">${buttons}</div>\n </div>`;\n }\n\n public renderWidget(): TemplateResult {\n let content = null;\n if (this.translation) {\n content = this.renderComponents(this.translation.components);\n } else if (this.selectedTemplate) {\n content = html`<div class=\"error-message\">\n This template currently has no approved translations.\n </div>`;\n }\n\n return html`\n <div>\n <temba-select\n searchable\n ?clearable=${!this.translating}\n ?disabled=${this.translating}\n valuekey=\"uuid\"\n class=\"picker\"\n value=\"${this.template}\"\n endpoint=\"${this.url}\"\n shouldExclude=${(template) => template.status !== 'approved'}\n placeholder=\"Select a template\"\n @temba-content-changed=${this.swallowEvent}\n @change=${this.handleTemplateChanged}\n >\n </temba-select>\n ${content ? html` <div class=\"template\">${content}</div>` : null}\n </div>\n `;\n }\n}\n"]}
@@ -3,7 +3,7 @@ import { html, css } from 'lit';
3
3
  import { property } from 'lit/decorators.js';
4
4
  import { ifDefined } from 'lit-html/directives/if-defined.js';
5
5
  import { styleMap } from 'lit-html/directives/style-map.js';
6
- import { FormElement } from './FormElement';
6
+ import { FieldElement } from './FieldElement';
7
7
  import { sanitizeUnintendedUnicode } from '../utils';
8
8
  export var InputType;
9
9
  (function (InputType) {
@@ -11,9 +11,10 @@ export var InputType;
11
11
  InputType["Password"] = "password";
12
12
  InputType["Number"] = "number";
13
13
  })(InputType || (InputType = {}));
14
- export class TextInput extends FormElement {
14
+ export class TextInput extends FieldElement {
15
15
  static get styles() {
16
16
  return css `
17
+ ${super.styles}
17
18
  .input-container {
18
19
  border-radius: var(--curvature-widget);
19
20
  cursor: var(--input-cursor);
@@ -296,9 +297,14 @@ export class TextInput extends FormElement {
296
297
  }
297
298
  // TODO make this a formelement and have contactsearch set the root
298
299
  render() {
299
- const containerStyle = {
300
- height: `${this.textarea ? '100%' : 'auto'}`
301
- };
300
+ return this.renderField();
301
+ }
302
+ renderWidget() {
303
+ const containerStyle = {};
304
+ if (this.counter) {
305
+ containerStyle['--counter-background'] =
306
+ 'var(--color-widget-border, transparent)';
307
+ }
302
308
  const clear = this.clearable && this.inputElement && this.inputElement.value
303
309
  ? html `<temba-icon
304
310
  name="x"
@@ -389,31 +395,21 @@ export class TextInput extends FormElement {
389
395
  }
390
396
  }
391
397
  return html `
392
- <temba-field
393
- name=${this.name}
394
- .label="${this.label}"
395
- .helpText="${this.helpText}"
396
- .errors=${this.errors}
397
- .widgetOnly=${this.widgetOnly}
398
- .hideLabel=${this.hideLabel}
399
- .disabled=${this.disabled}
398
+ <div
399
+ class="input-container"
400
+ style=${styleMap(containerStyle)}
401
+ @click=${this.handleContainerClick}
400
402
  >
401
- <div
402
- class="input-container"
403
- style=${styleMap(containerStyle)}
404
- @click=${this.handleContainerClick}
405
- >
406
- <slot name="prefix"></slot>
403
+ <slot name="prefix"></slot>
407
404
 
408
- ${input} ${clear}
409
- <slot name="type" class="type-icon"
410
- >${this.type === InputType.Number
405
+ ${input} ${clear}
406
+ <slot name="type" class="type-icon"
407
+ >${this.type === InputType.Number
411
408
  ? html `<temba-icon name="number"></temba-icon>`
412
409
  : null}</slot
413
- >
414
- <slot></slot>
415
- </div>
416
- </temba-field>
410
+ >
411
+ <slot></slot>
412
+ </div>
417
413
  `;
418
414
  }
419
415
  }