@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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FieldRenderer.js","sourceRoot":"","sources":["../../../src/form/FieldRenderer.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, TemplateResult } from 'lit';\nimport {\n FieldConfig,\n TextFieldConfig,\n TextareaFieldConfig,\n SelectFieldConfig,\n CheckboxFieldConfig,\n MessageEditorFieldConfig,\n KeyValueFieldConfig,\n ArrayFieldConfig\n} from '../flow/types';\n\n/**\n * FieldRenderer provides a consistent way to render field configurations\n * into web components across different contexts (NodeEditor, ArrayEditor, etc.)\n */\nexport class FieldRenderer {\n /**\n * Renders a field based on its configuration\n * @param fieldName - The name of the field\n * @param config - The field configuration\n * @param value - The current value of the field\n * @param context - Additional context for rendering\n * @returns A TemplateResult for the rendered field\n */\n static renderField(\n fieldName: string,\n config: FieldConfig,\n value: any,\n context: FieldRenderContext = {}\n ): TemplateResult {\n /*const {\n errors = [],\n onChange,\n showLabel = true,\n flavor,\n extraClasses = '',\n style = ''\n } = context;*/\n switch (config.type) {\n case 'text':\n return FieldRenderer.renderTextInput(fieldName, config, value, context);\n\n case 'textarea':\n return FieldRenderer.renderTextarea(\n fieldName,\n config as TextareaFieldConfig,\n value,\n context\n );\n\n case 'select':\n return FieldRenderer.renderSelect(\n fieldName,\n config as SelectFieldConfig,\n value,\n context\n );\n\n case 'checkbox':\n return FieldRenderer.renderCheckbox(\n fieldName,\n config as CheckboxFieldConfig,\n value,\n context\n );\n\n case 'key-value':\n return FieldRenderer.renderKeyValue(\n fieldName,\n config as KeyValueFieldConfig,\n value,\n context\n );\n\n case 'array':\n return FieldRenderer.renderArray(\n fieldName,\n config as ArrayFieldConfig,\n value,\n context\n );\n\n case 'message-editor':\n return FieldRenderer.renderMessageEditor(\n fieldName,\n config as MessageEditorFieldConfig,\n value,\n context\n );\n\n default:\n return html`<div>Unsupported field type: ${(config as any).type}</div>`;\n }\n }\n\n private static renderTextInput(\n fieldName: string,\n config: TextFieldConfig,\n value: any,\n context: FieldRenderContext\n ): TemplateResult {\n const {\n errors = [],\n onChange,\n showLabel = true,\n extraClasses,\n style\n } = context;\n\n // If field supports expression evaluation, use temba-completion\n if (config.evaluated) {\n return html`<temba-completion\n name=\"${fieldName}\"\n label=\"${showLabel ? config.label : ''}\"\n ?required=\"${config.required}\"\n .errors=\"${errors}\"\n .value=\"${value || ''}\"\n placeholder=\"${config.placeholder || ''}\"\n expressions=\"session\"\n .helpText=\"${config.helpText || ''}\"\n class=\"${extraClasses}\"\n style=\"${style}\"\n @input=\"${onChange || (() => {})}\"\n ></temba-completion>`;\n }\n\n return html`<temba-textinput\n name=\"${fieldName}\"\n label=\"${showLabel ? config.label : ''}\"\n ?required=\"${config.required}\"\n .errors=\"${errors}\"\n .value=\"${value || ''}\"\n placeholder=\"${config.placeholder || ''}\"\n .helpText=\"${config.helpText || ''}\"\n class=\"${extraClasses}\"\n style=\"${style}\"\n @input=\"${onChange || (() => {})}\"\n ></temba-textinput>`;\n }\n\n private static renderTextarea(\n fieldName: string,\n config: TextareaFieldConfig,\n value: any,\n context: FieldRenderContext\n ): TemplateResult {\n const {\n errors = [],\n onChange,\n showLabel = true,\n extraClasses,\n style\n } = context;\n\n const minHeightStyle = config.minHeight\n ? `--textarea-min-height: ${config.minHeight}px;`\n : '';\n const combinedStyle = `${minHeightStyle}${style}`;\n\n // If field supports expression evaluation, use temba-completion\n if (config.evaluated) {\n return html`<temba-completion\n name=\"${fieldName}\"\n label=\"${showLabel ? config.label : ''}\"\n ?required=\"${config.required}\"\n .errors=\"${errors}\"\n .value=\"${value || ''}\"\n placeholder=\"${config.placeholder || ''}\"\n textarea\n expressions=\"session\"\n .helpText=\"${config.helpText || ''}\"\n class=\"${extraClasses}\"\n style=\"${combinedStyle}\"\n @input=\"${onChange || (() => {})}\"\n ></temba-completion>`;\n }\n\n return html`<temba-textinput\n name=\"${fieldName}\"\n label=\"${showLabel ? config.label : ''}\"\n ?required=\"${config.required}\"\n .errors=\"${errors}\"\n .value=\"${value || ''}\"\n placeholder=\"${config.placeholder || ''}\"\n textarea\n .rows=\"${config.rows || 3}\"\n .helpText=\"${config.helpText || ''}\"\n class=\"${extraClasses}\"\n style=\"${combinedStyle}\"\n @input=\"${onChange || (() => {})}\"\n ></temba-textinput>`;\n }\n\n private static renderSelect(\n fieldName: string,\n config: SelectFieldConfig,\n value: any,\n context: FieldRenderContext\n ): TemplateResult {\n const {\n errors = [],\n onChange,\n showLabel = true,\n flavor,\n extraClasses,\n style\n } = context;\n\n // Ensure proper value handling for multi vs single select\n const normalizedValue = (() => {\n if (config.multi) {\n // Multi-select: ensure we have an array and convert strings to option objects\n const valueArray = Array.isArray(value) ? value : value ? [value] : [];\n return valueArray.map((val) => {\n if (typeof val === 'string') {\n // Convert string values to option objects\n return { name: val, value: val };\n }\n return val;\n });\n } else {\n // Single select: use the value as-is\n return value || '';\n }\n })();\n\n if (typeof normalizedValue === 'string') {\n return html`<temba-select\n name=\"${fieldName}\"\n ?required=\"${config.required}\"\n .errors=\"${errors}\"\n value=\"${config.multi ? '' : normalizedValue}\"\n .values=\"${config.multi ? normalizedValue : undefined}\"\n ?multi=\"${config.multi}\"\n ?searchable=\"${config.searchable}\"\n ?tags=\"${config.tags}\"\n ?emails=\"${config.emails}\"\n ?clearable=\"${config.clearable || false}\"\n label=\"${showLabel ? config.label : ''}\"\n placeholder=\"${config.placeholder || ''}\"\n maxItems=\"${config.maxItems || 0}\"\n valueKey=\"${config.valueKey || 'value'}\"\n nameKey=\"${config.nameKey || 'name'}\"\n endpoint=\"${config.endpoint || ''}\"\n .helpText=\"${config.helpText || ''}\"\n flavor=\"${flavor || config.flavor || 'small'}\"\n class=\"${extraClasses}\"\n style=\"${style}\"\n .getName=${config.getName}\n .createArbitraryOption=${config.createArbitraryOption}\n ?allowCreate=\"${config.allowCreate || false}\"\n @change=\"${onChange || (() => {})}\"\n >\n ${config.options?.map((option: any) => {\n if (typeof option === 'string') {\n return html`<temba-option\n name=\"${option}\"\n value=\"${option}\"\n ></temba-option>`;\n } else {\n return html`<temba-option\n name=\"${option.label || option.name}\"\n value=\"${option.value}\"\n ></temba-option>`;\n }\n })}\n </temba-select>`;\n }\n\n return html`<temba-select\n name=\"${fieldName}\"\n label=\"${showLabel ? config.label : ''}\"\n ?required=\"${config.required}\"\n .errors=\"${errors}\"\n .values=\"${normalizedValue}\"\n ?multi=\"${config.multi}\"\n ?searchable=\"${config.searchable}\"\n ?tags=\"${config.tags}\"\n ?emails=\"${config.emails}\"\n ?clearable=\"${config.clearable || false}\"\n placeholder=\"${config.placeholder || ''}\"\n maxItems=\"${config.maxItems || 0}\"\n valueKey=\"${config.valueKey || 'value'}\"\n nameKey=\"${config.nameKey || 'name'}\"\n endpoint=\"${config.endpoint || ''}\"\n .helpText=\"${config.helpText || ''}\"\n flavor=\"${flavor || config.flavor || 'small'}\"\n class=\"${extraClasses}\"\n style=\"${style}\"\n .getName=${config.getName}\n .createArbitraryOption=${config.createArbitraryOption}\n ?allowCreate=\"${config.allowCreate || false}\"\n @change=\"${onChange || (() => {})}\"\n >\n ${config.options?.map((option: any) => {\n if (typeof option === 'string') {\n return html`<temba-option\n name=\"${option}\"\n value=\"${option}\"\n ></temba-option>`;\n } else {\n return html`<temba-option\n name=\"${option.label || option.name}\"\n value=\"${option.value}\"\n ></temba-option>`;\n }\n })}\n </temba-select>`;\n }\n\n private static renderCheckbox(\n fieldName: string,\n config: CheckboxFieldConfig,\n value: any,\n context: FieldRenderContext\n ): TemplateResult {\n const { errors = [], onChange, extraClasses, style } = context;\n\n return html`<div class=\"form-field\">\n <temba-checkbox\n name=\"${fieldName}\"\n label=\"${config.label}\"\n .helpText=\"${config.helpText || ''}\"\n ?required=\"${config.required}\"\n .errors=\"${errors}\"\n ?checked=\"${value || false}\"\n size=\"${config.size || 1.2}\"\n animateChange=\"${config.animateChange || 'pulse'}\"\n class=\"${extraClasses}\"\n style=\"${style}\"\n @change=\"${onChange || (() => {})}\"\n ></temba-checkbox>\n ${errors.length\n ? html`<div class=\"field-errors\">${errors.join(', ')}</div>`\n : ''}\n </div>`;\n }\n\n private static renderKeyValue(\n fieldName: string,\n config: KeyValueFieldConfig,\n value: any,\n context: FieldRenderContext\n ): TemplateResult {\n const {\n errors = [],\n onChange,\n showLabel = true,\n extraClasses,\n style\n } = context;\n\n return html`<div class=\"form-field\">\n ${showLabel ? html`<label>${config.label}</label>` : ''}\n <temba-key-value-editor\n name=\"${fieldName}\"\n .value=\"${value || []}\"\n .sortable=\"${config.sortable}\"\n .keyPlaceholder=\"${config.keyPlaceholder || 'Key'}\"\n .valuePlaceholder=\"${config.valuePlaceholder || 'Value'}\"\n .minRows=\"${config.minRows || 0}\"\n class=\"${extraClasses}\"\n style=\"${style}\"\n @change=\"${onChange || (() => {})}\"\n ></temba-key-value-editor>\n ${errors.length\n ? html`<div class=\"field-errors\">${errors.join(', ')}</div>`\n : ''}\n </div>`;\n }\n\n private static renderArray(\n fieldName: string,\n config: ArrayFieldConfig,\n value: any,\n context: FieldRenderContext\n ): TemplateResult {\n const {\n errors = [],\n onChange,\n showLabel = true,\n extraClasses,\n style\n } = context;\n\n return html`<div class=\"form-field\">\n ${showLabel ? html`<label>${config.label}</label>` : ''}\n <temba-array-editor\n .value=\"${value || []}\"\n .itemConfig=\"${config.itemConfig}\"\n .sortable=\"${config.sortable}\"\n .itemLabel=\"${config.itemLabel || 'Item'}\"\n .minItems=\"${config.minItems || 0}\"\n .maxItems=\"${config.maxItems || 0}\"\n .onItemChange=\"${config.onItemChange}\"\n .isEmptyItemFn=\"${config.isEmptyItem}\"\n class=\"${extraClasses}\"\n style=\"${style}\"\n @change=\"${onChange || (() => {})}\"\n ></temba-array-editor>\n ${errors.length\n ? html`<div class=\"field-errors\">${errors.join(', ')}</div>`\n : ''}\n </div>`;\n }\n\n private static renderMessageEditor(\n fieldName: string,\n config: MessageEditorFieldConfig,\n value: any,\n context: FieldRenderContext\n ): TemplateResult {\n const {\n errors = [],\n onChange,\n showLabel = true,\n extraClasses,\n style,\n additionalData = {}\n } = context;\n\n return html`<temba-message-editor\n name=\"${fieldName}\"\n label=\"${showLabel ? config.label : ''}\"\n ?required=\"${config.required}\"\n .errors=\"${errors}\"\n .value=\"${value || ''}\"\n .attachments=\"${additionalData.attachments || []}\"\n placeholder=\"${config.placeholder || ''}\"\n .helpText=\"${config.helpText || ''}\"\n ?autogrow=\"${config.autogrow}\"\n ?gsm=\"${config.gsm}\"\n ?disableCompletion=\"${config.disableCompletion}\"\n counter=\"${config.counter || ''}\"\n accept=\"${config.accept || ''}\"\n endpoint=\"${config.endpoint || ''}\"\n max-attachments=\"${config.maxAttachments || 3}\"\n minHeight=\"${config.minHeight || 60}\"\n class=\"${extraClasses}\"\n style=\"${style}\"\n @change=\"${onChange || (() => {})}\"\n ></temba-message-editor>`;\n }\n}\n\n/**\n * Context object for field rendering that provides additional options\n */\nexport interface FieldRenderContext {\n /** Array of error messages for the field */\n errors?: string[];\n /** Change event handler */\n onChange?: (event: Event) => void;\n /** Whether to show the field label */\n showLabel?: boolean;\n /** Flavor for components that support it (like temba-select) */\n flavor?: string;\n /** Additional CSS classes to apply */\n extraClasses?: string;\n /** Additional CSS styles to apply */\n style?: string;\n /** Additional data needed for specific field types */\n additionalData?: Record<string, any>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"FieldRenderer.js","sourceRoot":"","sources":["../../../src/form/FieldRenderer.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, TemplateResult } from 'lit';\nimport {\n FieldConfig,\n TextFieldConfig,\n TextareaFieldConfig,\n SelectFieldConfig,\n CheckboxFieldConfig,\n MessageEditorFieldConfig,\n KeyValueFieldConfig,\n ArrayFieldConfig\n} from '../flow/types';\n\n/**\n * FieldRenderer provides a consistent way to render field configurations\n * into web components across different contexts (NodeEditor, ArrayEditor, etc.)\n */\nexport class FieldRenderer {\n /**\n * Renders a field based on its configuration\n * @param fieldName - The name of the field\n * @param config - The field configuration\n * @param value - The current value of the field\n * @param context - Additional context for rendering\n * @returns A TemplateResult for the rendered field\n */\n static renderField(\n fieldName: string,\n config: FieldConfig,\n value: any,\n context: FieldRenderContext = {}\n ): TemplateResult {\n /*const {\n errors = [],\n onChange,\n showLabel = true,\n flavor,\n extraClasses = '',\n style = ''\n } = context;*/\n switch (config.type) {\n case 'text':\n return FieldRenderer.renderTextInput(fieldName, config, value, context);\n\n case 'textarea':\n return FieldRenderer.renderTextarea(\n fieldName,\n config as TextareaFieldConfig,\n value,\n context\n );\n\n case 'select':\n return FieldRenderer.renderSelect(\n fieldName,\n config as SelectFieldConfig,\n value,\n context\n );\n\n case 'checkbox':\n return FieldRenderer.renderCheckbox(\n fieldName,\n config as CheckboxFieldConfig,\n value,\n context\n );\n\n case 'key-value':\n return FieldRenderer.renderKeyValue(\n fieldName,\n config as KeyValueFieldConfig,\n value,\n context\n );\n\n case 'array':\n return FieldRenderer.renderArray(\n fieldName,\n config as ArrayFieldConfig,\n value,\n context\n );\n\n case 'message-editor':\n return FieldRenderer.renderMessageEditor(\n fieldName,\n config as MessageEditorFieldConfig,\n value,\n context\n );\n\n default:\n return html`<div>Unsupported field type: ${(config as any).type}</div>`;\n }\n }\n\n private static renderTextInput(\n fieldName: string,\n config: TextFieldConfig,\n value: any,\n context: FieldRenderContext\n ): TemplateResult {\n const {\n errors = [],\n onChange,\n showLabel = true,\n extraClasses,\n style\n } = context;\n\n // If field supports expression evaluation, use temba-completion\n if (config.evaluated) {\n return html`<temba-completion\n name=\"${fieldName}\"\n label=\"${showLabel ? config.label : ''}\"\n ?required=\"${config.required}\"\n .errors=\"${errors}\"\n .value=\"${value || ''}\"\n placeholder=\"${config.placeholder || ''}\"\n expressions=\"session\"\n .helpText=\"${config.helpText || ''}\"\n class=\"${extraClasses}\"\n style=\"${style}\"\n @input=\"${onChange || (() => {})}\"\n ></temba-completion>`;\n }\n\n return html`<temba-textinput\n name=\"${fieldName}\"\n label=\"${showLabel ? config.label : ''}\"\n ?required=\"${config.required}\"\n .errors=\"${errors}\"\n .value=\"${value || ''}\"\n placeholder=\"${config.placeholder || ''}\"\n .helpText=\"${config.helpText || ''}\"\n class=\"${extraClasses}\"\n style=\"${style}\"\n @input=\"${onChange || (() => {})}\"\n ></temba-textinput>`;\n }\n\n private static renderTextarea(\n fieldName: string,\n config: TextareaFieldConfig,\n value: any,\n context: FieldRenderContext\n ): TemplateResult {\n const {\n errors = [],\n onChange,\n showLabel = true,\n extraClasses,\n style\n } = context;\n\n const minHeightStyle = config.minHeight\n ? `--textarea-min-height: ${config.minHeight}px;`\n : '';\n const combinedStyle = `${minHeightStyle}${style}`;\n\n // If field supports expression evaluation, use temba-completion\n if (config.evaluated) {\n return html`<temba-completion\n name=\"${fieldName}\"\n label=\"${showLabel ? config.label : ''}\"\n ?required=\"${config.required}\"\n .errors=\"${errors}\"\n .value=\"${value || ''}\"\n placeholder=\"${config.placeholder || ''}\"\n textarea\n expressions=\"session\"\n .helpText=\"${config.helpText || ''}\"\n class=\"${extraClasses}\"\n style=\"${combinedStyle}\"\n @input=\"${onChange || (() => {})}\"\n ></temba-completion>`;\n }\n\n return html`<temba-textinput\n name=\"${fieldName}\"\n label=\"${showLabel ? config.label : ''}\"\n ?required=\"${config.required}\"\n .errors=\"${errors}\"\n .value=\"${value || ''}\"\n placeholder=\"${config.placeholder || ''}\"\n textarea\n .rows=\"${config.rows || 3}\"\n .helpText=\"${config.helpText || ''}\"\n class=\"${extraClasses}\"\n style=\"${combinedStyle}\"\n @input=\"${onChange || (() => {})}\"\n ></temba-textinput>`;\n }\n\n private static renderSelect(\n fieldName: string,\n config: SelectFieldConfig,\n value: any,\n context: FieldRenderContext\n ): TemplateResult {\n const {\n errors = [],\n onChange,\n showLabel = true,\n flavor,\n extraClasses,\n style\n } = context;\n\n // Ensure proper value handling for multi vs single select\n const normalizedValue = (() => {\n if (config.multi) {\n // Multi-select: ensure we have an array and convert strings to option objects\n const valueArray = Array.isArray(value) ? value : value ? [value] : [];\n return valueArray.map((val) => {\n if (typeof val === 'string') {\n // Convert string values to option objects\n return { name: val, value: val };\n }\n return val;\n });\n } else {\n // Single select: use the value as-is\n return value || '';\n }\n })();\n\n if (typeof normalizedValue === 'string') {\n return html`<temba-select\n name=\"${fieldName}\"\n ?required=\"${config.required}\"\n .errors=\"${errors}\"\n value=\"${config.multi ? '' : normalizedValue}\"\n .values=\"${config.multi ? normalizedValue : undefined}\"\n ?multi=\"${config.multi}\"\n ?searchable=\"${config.searchable}\"\n ?tags=\"${config.tags}\"\n ?emails=\"${config.emails}\"\n ?clearable=\"${config.clearable || false}\"\n label=\"${showLabel ? config.label : ''}\"\n placeholder=\"${config.placeholder || ''}\"\n maxItems=\"${config.maxItems || 0}\"\n valueKey=\"${config.valueKey || 'value'}\"\n nameKey=\"${config.nameKey || 'name'}\"\n endpoint=\"${config.endpoint || ''}\"\n .helpText=\"${config.helpText || ''}\"\n flavor=\"${flavor || config.flavor || 'small'}\"\n class=\"${extraClasses}\"\n style=\"${style}\"\n .getName=${config.getName}\n .createArbitraryOption=${config.createArbitraryOption}\n ?allowCreate=\"${config.allowCreate || false}\"\n @change=\"${onChange || (() => {})}\"\n >\n ${config.options?.map((option: any) => {\n if (typeof option === 'string') {\n return html`<temba-option\n name=\"${option}\"\n value=\"${option}\"\n ></temba-option>`;\n } else {\n return html`<temba-option\n name=\"${option.label || option.name}\"\n value=\"${option.value}\"\n ></temba-option>`;\n }\n })}\n </temba-select>`;\n }\n\n return html`<temba-select\n name=\"${fieldName}\"\n label=\"${showLabel ? config.label : ''}\"\n ?required=\"${config.required}\"\n .errors=\"${errors}\"\n .values=\"${normalizedValue}\"\n ?multi=\"${config.multi}\"\n ?searchable=\"${config.searchable}\"\n ?tags=\"${config.tags}\"\n ?emails=\"${config.emails}\"\n ?clearable=\"${config.clearable || false}\"\n placeholder=\"${config.placeholder || ''}\"\n maxItems=\"${config.maxItems || 0}\"\n valueKey=\"${config.valueKey || 'value'}\"\n nameKey=\"${config.nameKey || 'name'}\"\n endpoint=\"${config.endpoint || ''}\"\n .helpText=\"${config.helpText || ''}\"\n flavor=\"${flavor || config.flavor || 'small'}\"\n class=\"${extraClasses}\"\n style=\"${style}\"\n .getName=${config.getName}\n .createArbitraryOption=${config.createArbitraryOption}\n ?allowCreate=\"${config.allowCreate || false}\"\n @change=\"${onChange || (() => {})}\"\n >\n ${config.options?.map((option: any) => {\n if (typeof option === 'string') {\n return html`<temba-option\n name=\"${option}\"\n value=\"${option}\"\n ></temba-option>`;\n } else {\n return html`<temba-option\n name=\"${option.label || option.name}\"\n value=\"${option.value}\"\n ></temba-option>`;\n }\n })}\n </temba-select>`;\n }\n\n private static renderCheckbox(\n fieldName: string,\n config: CheckboxFieldConfig,\n value: any,\n context: FieldRenderContext\n ): TemplateResult {\n const { errors = [], onChange, extraClasses, style } = context;\n\n return html`<div class=\"form-field\">\n <temba-checkbox\n name=\"${fieldName}\"\n label=\"${config.label}\"\n .helpText=\"${config.helpText || ''}\"\n ?required=\"${config.required}\"\n .errors=\"${errors}\"\n ?checked=\"${value || false}\"\n size=\"${config.size || 1.2}\"\n animateChange=\"${config.animateChange || 'pulse'}\"\n class=\"${extraClasses}\"\n style=\"${style}\"\n @change=\"${onChange || (() => {})}\"\n ></temba-checkbox>\n ${errors.length\n ? html`<div class=\"field-errors\">${errors.join(', ')}</div>`\n : ''}\n </div>`;\n }\n\n private static renderKeyValue(\n fieldName: string,\n config: KeyValueFieldConfig,\n value: any,\n context: FieldRenderContext\n ): TemplateResult {\n const {\n errors = [],\n onChange,\n showLabel = true,\n extraClasses,\n style\n } = context;\n\n return html`<div class=\"form-field\">\n ${showLabel ? html`<label>${config.label}</label>` : ''}\n <temba-key-value-editor\n name=\"${fieldName}\"\n .value=\"${value || []}\"\n .sortable=\"${config.sortable}\"\n .keyPlaceholder=\"${config.keyPlaceholder || 'Key'}\"\n .valuePlaceholder=\"${config.valuePlaceholder || 'Value'}\"\n .minRows=\"${config.minRows || 0}\"\n class=\"${extraClasses}\"\n style=\"${style}\"\n @change=\"${onChange || (() => {})}\"\n ></temba-key-value-editor>\n ${errors.length\n ? html`<div class=\"field-errors\">${errors.join(', ')}</div>`\n : ''}\n </div>`;\n }\n\n private static renderArray(\n fieldName: string,\n config: ArrayFieldConfig,\n value: any,\n context: FieldRenderContext\n ): TemplateResult {\n const {\n errors = [],\n onChange,\n showLabel = true,\n extraClasses,\n style\n } = context;\n\n return html`<div class=\"form-field\">\n <temba-array-editor\n name=\"${fieldName}\"\n .label=\"${showLabel ? config.label : ''}\"\n .value=\"${value || []}\"\n .itemConfig=\"${config.itemConfig}\"\n .sortable=\"${config.sortable}\"\n .itemLabel=\"${config.itemLabel || 'Item'}\"\n .minItems=\"${config.minItems || 0}\"\n .maxItems=\"${config.maxItems || 0}\"\n .onItemChange=\"${config.onItemChange}\"\n .isEmptyItemFn=\"${config.isEmptyItem}\"\n class=\"${extraClasses}\"\n style=\"${style}\"\n @change=\"${onChange || (() => {})}\"\n ></temba-array-editor>\n ${errors.length\n ? html`<div class=\"field-errors\">${errors.join(', ')}</div>`\n : ''}\n </div>`;\n }\n\n private static renderMessageEditor(\n fieldName: string,\n config: MessageEditorFieldConfig,\n value: any,\n context: FieldRenderContext\n ): TemplateResult {\n const {\n errors = [],\n onChange,\n showLabel = true,\n extraClasses,\n style,\n additionalData = {}\n } = context;\n\n return html`<temba-message-editor\n name=\"${fieldName}\"\n label=\"${showLabel ? config.label : ''}\"\n ?required=\"${config.required}\"\n .errors=\"${errors}\"\n .value=\"${value || ''}\"\n .attachments=\"${additionalData.attachments || []}\"\n placeholder=\"${config.placeholder || ''}\"\n .helpText=\"${config.helpText || ''}\"\n ?autogrow=\"${config.autogrow}\"\n ?gsm=\"${config.gsm}\"\n ?disableCompletion=\"${config.disableCompletion}\"\n counter=\"${config.counter || ''}\"\n accept=\"${config.accept || ''}\"\n endpoint=\"${config.endpoint || ''}\"\n max-attachments=\"${config.maxAttachments || 3}\"\n minHeight=\"${config.minHeight || 60}\"\n class=\"${extraClasses}\"\n style=\"${style}\"\n @change=\"${onChange || (() => {})}\"\n ></temba-message-editor>`;\n }\n}\n\n/**\n * Context object for field rendering that provides additional options\n */\nexport interface FieldRenderContext {\n /** Array of error messages for the field */\n errors?: string[];\n /** Change event handler */\n onChange?: (event: Event) => void;\n /** Whether to show the field label */\n showLabel?: boolean;\n /** Flavor for components that support it (like temba-select) */\n flavor?: string;\n /** Additional CSS classes to apply */\n extraClasses?: string;\n /** Additional CSS styles to apply */\n style?: string;\n /** Additional data needed for specific field types */\n additionalData?: Record<string, any>;\n}\n"]}
|
|
@@ -4,14 +4,128 @@ import { html, css } from 'lit';
|
|
|
4
4
|
import { CroppieCSS } from './CroppieCSS';
|
|
5
5
|
import { property } from 'lit/decorators.js';
|
|
6
6
|
import { Icon } from '../Icons';
|
|
7
|
-
import {
|
|
8
|
-
export class ImagePicker extends
|
|
7
|
+
import { FieldElement } from './FieldElement';
|
|
8
|
+
export class ImagePicker extends FieldElement {
|
|
9
9
|
constructor() {
|
|
10
10
|
super(...arguments);
|
|
11
11
|
this.shape = 'square';
|
|
12
12
|
this.showCroppie = false;
|
|
13
13
|
this.uploadReader = new FileReader();
|
|
14
14
|
}
|
|
15
|
+
static get styles() {
|
|
16
|
+
return css `
|
|
17
|
+
${super.styles}
|
|
18
|
+
${CroppieCSS}
|
|
19
|
+
|
|
20
|
+
.croppie {
|
|
21
|
+
max-width: 400px;
|
|
22
|
+
border: 0px solid #ccc;
|
|
23
|
+
border-radius: 0.5em;
|
|
24
|
+
overflow: hidden;
|
|
25
|
+
background: #fff;
|
|
26
|
+
margin-top: -20%;
|
|
27
|
+
box-shadow: 0 0 15px 5px rgba(0, 0, 0, 0.1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.croppie .controls {
|
|
31
|
+
display: flex;
|
|
32
|
+
align-items: center;
|
|
33
|
+
flex-direction: row;
|
|
34
|
+
justify-content: center;
|
|
35
|
+
position: absolute;
|
|
36
|
+
z-index: 1;
|
|
37
|
+
width: 400px;
|
|
38
|
+
margin-top: -42px;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.toggle {
|
|
42
|
+
height: 110px;
|
|
43
|
+
width: 110px;
|
|
44
|
+
cursor: pointer;
|
|
45
|
+
display: flex;
|
|
46
|
+
align-items: center;
|
|
47
|
+
justify-content: center;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.circle .toggle {
|
|
51
|
+
border-radius: 50%;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.toggle.set {
|
|
55
|
+
box-shadow: rgba(0, 0, 0, 0.1) 0px 3px 7px 0px,
|
|
56
|
+
rgba(0, 0, 0, 0.2) 0px 1px 2px 0px, inset 0 0 0 5px rgba(0, 0, 0, 0.1);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.toggle.set:hover {
|
|
60
|
+
box-shadow: rgba(0, 0, 0, 0.1) 0px 3px 7px 0px,
|
|
61
|
+
rgba(0, 0, 0, 0.2) 0px 1px 2px 0px, inset 0 0 0 5px rgba(0, 0, 0, 0.2);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.toggle temba-icon {
|
|
65
|
+
color: rgba(0, 0, 0, 0.2);
|
|
66
|
+
padding: 5px;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
toggle:hover temba-icon {
|
|
70
|
+
color: rgba(0, 0, 0, 0.8);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.toggle.set temba-icon {
|
|
74
|
+
border-radius: 50%;
|
|
75
|
+
margin-right: -90%;
|
|
76
|
+
margin-bottom: -50%;
|
|
77
|
+
background: rgba(240, 240, 240, 1);
|
|
78
|
+
box-shadow: rgba(0, 0, 0, 0.2) 0px 1px 2px 0px;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.toggle.set:hover temba-icon {
|
|
82
|
+
background: #fff;
|
|
83
|
+
color: var(--color-primary-dark);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.circle .toggle.set temba-icon {
|
|
87
|
+
margin-right: -70%;
|
|
88
|
+
margin-bottom: -70%;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.hidden {
|
|
92
|
+
display: none;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.controls temba-icon {
|
|
96
|
+
margin: 0em 0.75em;
|
|
97
|
+
background: rgba(255, 255, 255, 0.8);
|
|
98
|
+
border-radius: 50%;
|
|
99
|
+
padding: 6px;
|
|
100
|
+
transition: all 0.1s ease-in-out;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.controls {
|
|
104
|
+
pointer-events: none;
|
|
105
|
+
display: flex;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.controls temba-icon {
|
|
109
|
+
pointer-events: all;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.controls temba-icon.close {
|
|
113
|
+
color: rgba(0, 0, 0, 0.2);
|
|
114
|
+
background: rgba(255, 255, 255, 0.2);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.controls temba-icon.submit {
|
|
118
|
+
color: rgba(0, 0, 0, 0.2);
|
|
119
|
+
box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.1);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.controls temba-icon:hover {
|
|
123
|
+
color: white;
|
|
124
|
+
cursor: pointer;
|
|
125
|
+
background: var(--color-primary-dark);
|
|
126
|
+
}
|
|
127
|
+
`;
|
|
128
|
+
}
|
|
15
129
|
firstUpdated(changed) {
|
|
16
130
|
super.firstUpdated(changed);
|
|
17
131
|
const picker = this;
|
|
@@ -86,18 +200,9 @@ export class ImagePicker extends FormElement {
|
|
|
86
200
|
}
|
|
87
201
|
input.value = '';
|
|
88
202
|
}
|
|
89
|
-
|
|
203
|
+
renderWidget() {
|
|
90
204
|
return html `
|
|
91
|
-
|
|
92
|
-
<temba-field
|
|
93
|
-
name=${this.name}
|
|
94
|
-
label=${this.label}
|
|
95
|
-
.helpText=${this.helpText}
|
|
96
|
-
.errors=${this.errors}
|
|
97
|
-
.widgetOnly=${this.widgetOnly}
|
|
98
|
-
.helpAlways=${true}
|
|
99
|
-
?disabled=${this.disabled}
|
|
100
|
-
>
|
|
205
|
+
<div class="wrapper ${this.shape} ${this.label ? 'label' : ''}">
|
|
101
206
|
<input class='hidden' type="file" accept="image/*" capture="camera" id="file" name="file" @change=${this.handleFileChanged}/>
|
|
102
207
|
<div class='toggle ${this.url ? 'set' : ''} ${this.showCroppie ? 'hidden' : ''}' @click=${this.handleToggleClicked} style="background: ${this.url
|
|
103
208
|
? `url('${this.url}') center / contain no-repeat`
|
|
@@ -114,122 +219,13 @@ export class ImagePicker extends FormElement {
|
|
|
114
219
|
<temba-icon class="submit" size="1" name=${Icon.submit} @click=${this.saveResult}></temba-icon>
|
|
115
220
|
</div>
|
|
116
221
|
</temba-mask>
|
|
117
|
-
</
|
|
118
|
-
</div>
|
|
222
|
+
</div>
|
|
119
223
|
`;
|
|
120
224
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
${CroppieCSS}
|
|
124
|
-
|
|
125
|
-
.croppie {
|
|
126
|
-
max-width: 400px;
|
|
127
|
-
border: 0px solid #ccc;
|
|
128
|
-
border-radius: 0.5em;
|
|
129
|
-
overflow: hidden;
|
|
130
|
-
background: #fff;
|
|
131
|
-
margin-top: -20%;
|
|
132
|
-
box-shadow: 0 0 15px 5px rgba(0, 0, 0, 0.1);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
.croppie .controls {
|
|
136
|
-
display: flex;
|
|
137
|
-
align-items: center;
|
|
138
|
-
flex-direction: row;
|
|
139
|
-
justify-content: center;
|
|
140
|
-
position: absolute;
|
|
141
|
-
z-index: 1;
|
|
142
|
-
width: 400px;
|
|
143
|
-
margin-top: -42px;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
.toggle {
|
|
147
|
-
height: 110px;
|
|
148
|
-
width: 110px;
|
|
149
|
-
cursor: pointer;
|
|
150
|
-
display: flex;
|
|
151
|
-
align-items: center;
|
|
152
|
-
justify-content: center;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
.circle .toggle {
|
|
156
|
-
border-radius: 50%;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
.toggle.set {
|
|
160
|
-
box-shadow: rgba(0, 0, 0, 0.1) 0px 3px 7px 0px,
|
|
161
|
-
rgba(0, 0, 0, 0.2) 0px 1px 2px 0px, inset 0 0 0 5px rgba(0, 0, 0, 0.1);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
.toggle.set:hover {
|
|
165
|
-
box-shadow: rgba(0, 0, 0, 0.1) 0px 3px 7px 0px,
|
|
166
|
-
rgba(0, 0, 0, 0.2) 0px 1px 2px 0px, inset 0 0 0 5px rgba(0, 0, 0, 0.2);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
.toggle temba-icon {
|
|
170
|
-
color: rgba(0, 0, 0, 0.2);
|
|
171
|
-
padding: 5px;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
toggle:hover temba-icon {
|
|
175
|
-
color: rgba(0, 0, 0, 0.8);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
.toggle.set temba-icon {
|
|
179
|
-
border-radius: 50%;
|
|
180
|
-
margin-right: -90%;
|
|
181
|
-
margin-bottom: -50%;
|
|
182
|
-
background: rgba(240, 240, 240, 1);
|
|
183
|
-
box-shadow: rgba(0, 0, 0, 0.2) 0px 1px 2px 0px;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
.toggle.set:hover temba-icon {
|
|
187
|
-
background: #fff;
|
|
188
|
-
color: var(--color-primary-dark);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
.circle .toggle.set temba-icon {
|
|
192
|
-
margin-right: -70%;
|
|
193
|
-
margin-bottom: -70%;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
.hidden {
|
|
197
|
-
display: none;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
.controls temba-icon {
|
|
201
|
-
margin: 0em 0.75em;
|
|
202
|
-
background: rgba(255, 255, 255, 0.8);
|
|
203
|
-
border-radius: 50%;
|
|
204
|
-
padding: 6px;
|
|
205
|
-
transition: all 0.1s ease-in-out;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
.controls {
|
|
209
|
-
pointer-events: none;
|
|
210
|
-
display: flex;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
.controls temba-icon {
|
|
214
|
-
pointer-events: all;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
.controls temba-icon.close {
|
|
218
|
-
color: rgba(0, 0, 0, 0.2);
|
|
219
|
-
background: rgba(255, 255, 255, 0.2);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
.controls temba-icon.submit {
|
|
223
|
-
color: rgba(0, 0, 0, 0.2);
|
|
224
|
-
box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.1);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
.controls temba-icon:hover {
|
|
228
|
-
color: white;
|
|
229
|
-
cursor: pointer;
|
|
230
|
-
background: var(--color-primary-dark);
|
|
225
|
+
render() {
|
|
226
|
+
return this.renderField();
|
|
231
227
|
}
|
|
232
|
-
|
|
228
|
+
}
|
|
233
229
|
__decorate([
|
|
234
230
|
property({ type: String })
|
|
235
231
|
], ImagePicker.prototype, "tempImage", void 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImagePicker.js","sourceRoot":"","sources":["../../../src/form/ImagePicker.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-this-alias */\nimport { html, css, PropertyValueMap } from 'lit';\nimport { CroppieCSS } from './CroppieCSS';\nimport { property } from 'lit/decorators.js';\nimport { Icon } from '../Icons';\nimport { FormElement } from './FormElement';\n\nexport class ImagePicker extends FormElement {\n static styles = css`\n ${CroppieCSS}\n\n .croppie {\n max-width: 400px;\n border: 0px solid #ccc;\n border-radius: 0.5em;\n overflow: hidden;\n background: #fff;\n margin-top: -20%;\n box-shadow: 0 0 15px 5px rgba(0, 0, 0, 0.1);\n }\n\n .croppie .controls {\n display: flex;\n align-items: center;\n flex-direction: row;\n justify-content: center;\n position: absolute;\n z-index: 1;\n width: 400px;\n margin-top: -42px;\n }\n\n .toggle {\n height: 110px;\n width: 110px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .circle .toggle {\n border-radius: 50%;\n }\n\n .toggle.set {\n box-shadow: rgba(0, 0, 0, 0.1) 0px 3px 7px 0px,\n rgba(0, 0, 0, 0.2) 0px 1px 2px 0px, inset 0 0 0 5px rgba(0, 0, 0, 0.1);\n }\n\n .toggle.set:hover {\n box-shadow: rgba(0, 0, 0, 0.1) 0px 3px 7px 0px,\n rgba(0, 0, 0, 0.2) 0px 1px 2px 0px, inset 0 0 0 5px rgba(0, 0, 0, 0.2);\n }\n\n .toggle temba-icon {\n color: rgba(0, 0, 0, 0.2);\n padding: 5px;\n }\n\n toggle:hover temba-icon {\n color: rgba(0, 0, 0, 0.8);\n }\n\n .toggle.set temba-icon {\n border-radius: 50%;\n margin-right: -90%;\n margin-bottom: -50%;\n background: rgba(240, 240, 240, 1);\n box-shadow: rgba(0, 0, 0, 0.2) 0px 1px 2px 0px;\n }\n\n .toggle.set:hover temba-icon {\n background: #fff;\n color: var(--color-primary-dark);\n }\n\n .circle .toggle.set temba-icon {\n margin-right: -70%;\n margin-bottom: -70%;\n }\n\n .hidden {\n display: none;\n }\n\n .controls temba-icon {\n margin: 0em 0.75em;\n background: rgba(255, 255, 255, 0.8);\n border-radius: 50%;\n padding: 6px;\n transition: all 0.1s ease-in-out;\n }\n\n .controls {\n pointer-events: none;\n display: flex;\n }\n\n .controls temba-icon {\n pointer-events: all;\n }\n\n .controls temba-icon.close {\n color: rgba(0, 0, 0, 0.2);\n background: rgba(255, 255, 255, 0.2);\n }\n\n .controls temba-icon.submit {\n color: rgba(0, 0, 0, 0.2);\n box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.1);\n }\n\n .controls temba-icon:hover {\n color: white;\n cursor: pointer;\n background: var(--color-primary-dark);\n }\n `;\n\n @property({ type: String })\n tempImage: string;\n\n @property({ type: String })\n url: string;\n\n @property({ type: String })\n shape = 'square';\n\n @property({ type: Boolean, attribute: false })\n showCroppie = false;\n\n uploadReader = new FileReader();\n croppie: any;\n\n protected firstUpdated(\n changed: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.firstUpdated(changed);\n const picker = this;\n\n this.uploadReader.onload = function () {\n picker.launchCroppie(picker.uploadReader.result as any);\n };\n }\n\n public updated(changed: Map<string, any>): void {\n super.updated(changed);\n if (changed.has('url')) {\n this.setAttribute('url', this.url);\n }\n }\n\n private closeCroppie() {\n this.showCroppie = false;\n const wrapper = this.shadowRoot.querySelector('.croppie .embed');\n if (wrapper.firstChild) {\n wrapper.removeChild(wrapper.firstChild);\n }\n }\n\n private launchCroppie(url: string) {\n const wrapper = this.shadowRoot.querySelector('.croppie .embed');\n if (wrapper.firstChild) {\n wrapper.removeChild(wrapper.firstChild);\n }\n this.showCroppie = true;\n const ele = document.createElement('div');\n wrapper.appendChild(ele);\n\n const Croppie = (window as any).Croppie;\n this.croppie = new Croppie(ele, {\n enableExif: true,\n viewport: {\n width: 300,\n height: 300,\n type: this.shape\n },\n boundary: {\n width: 400,\n height: 400\n }\n });\n\n this.croppie.bind({ url });\n }\n\n private saveResult() {\n const picker = this;\n this.croppie\n .result({\n type: 'blob',\n size: 'viewport',\n format: 'webp',\n quality: 1,\n circle: false\n })\n .then(function (resp: any) {\n const blob = resp;\n picker.url = URL.createObjectURL(blob);\n\n // const blob = dataURItoBlob(resp);\n const fd = new FormData();\n fd.append(picker.name, blob, 'filename.webp');\n\n picker.value = fd;\n picker.closeCroppie();\n });\n }\n\n private handleToggleClicked() {\n const fileInput = this.shadowRoot.querySelector('#file');\n (fileInput as any).click();\n }\n\n private handleFileChanged(e: Event) {\n const input = e.target as any;\n if (input.files.length > 0) {\n this.uploadReader.readAsDataURL(input.files[0]);\n }\n input.value = '';\n }\n\n protected render() {\n return html`\n <div class=\"wrapper ${this.shape} ${this.label ? 'label' : ''}\">\n <temba-field\n name=${this.name}\n label=${this.label}\n .helpText=${this.helpText}\n .errors=${this.errors}\n .widgetOnly=${this.widgetOnly}\n .helpAlways=${true}\n ?disabled=${this.disabled}\n >\n <input class='hidden' type=\"file\" accept=\"image/*\" capture=\"camera\" id=\"file\" name=\"file\" @change=${\n this.handleFileChanged\n }/>\n <div class='toggle ${this.url ? 'set' : ''} ${\n this.showCroppie ? 'hidden' : ''\n }' @click=${this.handleToggleClicked} style=\"background: ${\n this.url\n ? `url('${this.url}') center / contain no-repeat`\n : 'rgba(0, 0, 0, 0.1)'\n }\">\n <temba-icon name=${Icon.upload_image} size=\"1.5\"></temba-icon>\n </div>\n \n <temba-mask ?show=${this.showCroppie} class=\"${\n this.showCroppie ? 'editing' : ''\n }\">\n <div class='croppie'>\n <div class='embed'></div>\n <div class='controls'>\n <temba-icon class=\"close\" size=\"1\" name=${Icon.close} @click=${\n this.closeCroppie\n }></temba-icon>\n <div style=\"flex-grow:1\"></div>\n <temba-icon class=\"submit\" size=\"1\" name=${Icon.submit} @click=${\n this.saveResult\n }></temba-icon>\n </div>\n </temba-mask>\n </temba-field>\n </div>\n `;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ImagePicker.js","sourceRoot":"","sources":["../../../src/form/ImagePicker.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-this-alias */\nimport { html, css, PropertyValueMap } from 'lit';\nimport { CroppieCSS } from './CroppieCSS';\nimport { property } from 'lit/decorators.js';\nimport { Icon } from '../Icons';\nimport { FieldElement } from './FieldElement';\n\nexport class ImagePicker extends FieldElement {\n static get styles() {\n return css`\n ${super.styles}\n ${CroppieCSS}\n\n .croppie {\n max-width: 400px;\n border: 0px solid #ccc;\n border-radius: 0.5em;\n overflow: hidden;\n background: #fff;\n margin-top: -20%;\n box-shadow: 0 0 15px 5px rgba(0, 0, 0, 0.1);\n }\n\n .croppie .controls {\n display: flex;\n align-items: center;\n flex-direction: row;\n justify-content: center;\n position: absolute;\n z-index: 1;\n width: 400px;\n margin-top: -42px;\n }\n\n .toggle {\n height: 110px;\n width: 110px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .circle .toggle {\n border-radius: 50%;\n }\n\n .toggle.set {\n box-shadow: rgba(0, 0, 0, 0.1) 0px 3px 7px 0px,\n rgba(0, 0, 0, 0.2) 0px 1px 2px 0px, inset 0 0 0 5px rgba(0, 0, 0, 0.1);\n }\n\n .toggle.set:hover {\n box-shadow: rgba(0, 0, 0, 0.1) 0px 3px 7px 0px,\n rgba(0, 0, 0, 0.2) 0px 1px 2px 0px, inset 0 0 0 5px rgba(0, 0, 0, 0.2);\n }\n\n .toggle temba-icon {\n color: rgba(0, 0, 0, 0.2);\n padding: 5px;\n }\n\n toggle:hover temba-icon {\n color: rgba(0, 0, 0, 0.8);\n }\n\n .toggle.set temba-icon {\n border-radius: 50%;\n margin-right: -90%;\n margin-bottom: -50%;\n background: rgba(240, 240, 240, 1);\n box-shadow: rgba(0, 0, 0, 0.2) 0px 1px 2px 0px;\n }\n\n .toggle.set:hover temba-icon {\n background: #fff;\n color: var(--color-primary-dark);\n }\n\n .circle .toggle.set temba-icon {\n margin-right: -70%;\n margin-bottom: -70%;\n }\n\n .hidden {\n display: none;\n }\n\n .controls temba-icon {\n margin: 0em 0.75em;\n background: rgba(255, 255, 255, 0.8);\n border-radius: 50%;\n padding: 6px;\n transition: all 0.1s ease-in-out;\n }\n\n .controls {\n pointer-events: none;\n display: flex;\n }\n\n .controls temba-icon {\n pointer-events: all;\n }\n\n .controls temba-icon.close {\n color: rgba(0, 0, 0, 0.2);\n background: rgba(255, 255, 255, 0.2);\n }\n\n .controls temba-icon.submit {\n color: rgba(0, 0, 0, 0.2);\n box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.1);\n }\n\n .controls temba-icon:hover {\n color: white;\n cursor: pointer;\n background: var(--color-primary-dark);\n }\n `;\n }\n\n @property({ type: String })\n tempImage: string;\n\n @property({ type: String })\n url: string;\n\n @property({ type: String })\n shape = 'square';\n\n @property({ type: Boolean, attribute: false })\n showCroppie = false;\n\n uploadReader = new FileReader();\n croppie: any;\n\n protected firstUpdated(\n changed: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.firstUpdated(changed);\n const picker = this;\n\n this.uploadReader.onload = function () {\n picker.launchCroppie(picker.uploadReader.result as any);\n };\n }\n\n public updated(changed: Map<string, any>): void {\n super.updated(changed);\n if (changed.has('url')) {\n this.setAttribute('url', this.url);\n }\n }\n\n private closeCroppie() {\n this.showCroppie = false;\n const wrapper = this.shadowRoot.querySelector('.croppie .embed');\n if (wrapper.firstChild) {\n wrapper.removeChild(wrapper.firstChild);\n }\n }\n\n private launchCroppie(url: string) {\n const wrapper = this.shadowRoot.querySelector('.croppie .embed');\n if (wrapper.firstChild) {\n wrapper.removeChild(wrapper.firstChild);\n }\n this.showCroppie = true;\n const ele = document.createElement('div');\n wrapper.appendChild(ele);\n\n const Croppie = (window as any).Croppie;\n this.croppie = new Croppie(ele, {\n enableExif: true,\n viewport: {\n width: 300,\n height: 300,\n type: this.shape\n },\n boundary: {\n width: 400,\n height: 400\n }\n });\n\n this.croppie.bind({ url });\n }\n\n private saveResult() {\n const picker = this;\n this.croppie\n .result({\n type: 'blob',\n size: 'viewport',\n format: 'webp',\n quality: 1,\n circle: false\n })\n .then(function (resp: any) {\n const blob = resp;\n picker.url = URL.createObjectURL(blob);\n\n // const blob = dataURItoBlob(resp);\n const fd = new FormData();\n fd.append(picker.name, blob, 'filename.webp');\n\n picker.value = fd;\n picker.closeCroppie();\n });\n }\n\n private handleToggleClicked() {\n const fileInput = this.shadowRoot.querySelector('#file');\n (fileInput as any).click();\n }\n\n private handleFileChanged(e: Event) {\n const input = e.target as any;\n if (input.files.length > 0) {\n this.uploadReader.readAsDataURL(input.files[0]);\n }\n input.value = '';\n }\n\n protected renderWidget() {\n return html`\n <div class=\"wrapper ${this.shape} ${this.label ? 'label' : ''}\">\n <input class='hidden' type=\"file\" accept=\"image/*\" capture=\"camera\" id=\"file\" name=\"file\" @change=${\n this.handleFileChanged\n }/>\n <div class='toggle ${this.url ? 'set' : ''} ${\n this.showCroppie ? 'hidden' : ''\n }' @click=${this.handleToggleClicked} style=\"background: ${\n this.url\n ? `url('${this.url}') center / contain no-repeat`\n : 'rgba(0, 0, 0, 0.1)'\n }\">\n <temba-icon name=${Icon.upload_image} size=\"1.5\"></temba-icon>\n </div>\n \n <temba-mask ?show=${this.showCroppie} class=\"${\n this.showCroppie ? 'editing' : ''\n }\">\n <div class='croppie'>\n <div class='embed'></div>\n <div class='controls'>\n <temba-icon class=\"close\" size=\"1\" name=${Icon.close} @click=${\n this.closeCroppie\n }></temba-icon>\n <div style=\"flex-grow:1\"></div>\n <temba-icon class=\"submit\" size=\"1\" name=${Icon.submit} @click=${\n this.saveResult\n }></temba-icon>\n </div>\n </temba-mask>\n </div>\n `;\n }\n\n public render() {\n return this.renderField();\n }\n}\n"]}
|
|
@@ -158,49 +158,53 @@ let KeyValueEditor = class KeyValueEditor extends BaseListEditor {
|
|
|
158
158
|
getContainerClass() {
|
|
159
159
|
return 'key-value-editor';
|
|
160
160
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
display: flex;
|
|
165
|
-
flex-direction: column;
|
|
166
|
-
gap: 8px;
|
|
167
|
-
}
|
|
161
|
+
static get styles() {
|
|
162
|
+
return css `
|
|
163
|
+
${super.styles}
|
|
168
164
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
165
|
+
.key-value-editor {
|
|
166
|
+
display: flex;
|
|
167
|
+
flex-direction: column;
|
|
168
|
+
gap: 8px;
|
|
169
|
+
}
|
|
175
170
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
color: #666;
|
|
183
|
-
cursor: pointer;
|
|
184
|
-
display: flex;
|
|
185
|
-
align-items: center;
|
|
186
|
-
justify-content: center;
|
|
187
|
-
font-size: 18px;
|
|
188
|
-
}
|
|
171
|
+
.row {
|
|
172
|
+
display: grid;
|
|
173
|
+
grid-template-columns: 1fr 1fr auto;
|
|
174
|
+
align-items: center;
|
|
175
|
+
column-gap: 6px;
|
|
176
|
+
}
|
|
189
177
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
178
|
+
.remove-btn {
|
|
179
|
+
width: 32px;
|
|
180
|
+
height: 32px;
|
|
181
|
+
border: 1px solid #ccc;
|
|
182
|
+
border-radius: 4px;
|
|
183
|
+
background: #f8f8f8;
|
|
184
|
+
color: #666;
|
|
185
|
+
cursor: pointer;
|
|
186
|
+
display: flex;
|
|
187
|
+
align-items: center;
|
|
188
|
+
justify-content: center;
|
|
189
|
+
font-size: 18px;
|
|
190
|
+
}
|
|
193
191
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
192
|
+
.remove-btn:hover:not(:disabled) {
|
|
193
|
+
background: #f0f0f0;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.remove-btn:disabled {
|
|
197
|
+
opacity: 0.5;
|
|
198
|
+
cursor: not-allowed;
|
|
199
|
+
}
|
|
198
200
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
201
|
+
.remove-btn-spacer {
|
|
202
|
+
width: 32px;
|
|
203
|
+
height: 32px;
|
|
204
|
+
}
|
|
205
|
+
`;
|
|
202
206
|
}
|
|
203
|
-
|
|
207
|
+
};
|
|
204
208
|
__decorate([
|
|
205
209
|
property({ type: String })
|
|
206
210
|
], KeyValueEditor.prototype, "keyPlaceholder", void 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KeyValueEditor.js","sourceRoot":"","sources":["../../../src/form/KeyValueEditor.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, css, TemplateResult } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { BaseListEditor, ListItem } from './BaseListEditor';\n\ninterface KeyValueItem extends ListItem {\n key: string;\n value: string;\n}\n\n@customElement('temba-key-value-editor')\nexport class KeyValueEditor extends BaseListEditor<KeyValueItem> {\n @property({ type: String })\n keyPlaceholder = 'Key';\n\n @property({ type: String })\n valuePlaceholder = 'Value';\n\n @property({ type: Boolean })\n showValidation = true;\n\n @state()\n private keyErrors: { [index: number]: string } = {};\n\n // Configure to maintain empty items\n maintainEmptyItem = true;\n\n constructor() {\n super();\n this._items = [];\n }\n\n // External API uses array format to preserve duplicate keys\n @property({ type: Array })\n get value(): KeyValueItem[] {\n return this._items.filter(\n ({ key, value }) => key.trim() !== '' || value.trim() !== ''\n );\n }\n\n set value(newValue: KeyValueItem[] | Record<string, string>) {\n if (Array.isArray(newValue)) {\n this._items = [...newValue];\n } else {\n // Convert Record to array format\n this._items = Object.entries(newValue || {}).map(([key, value]) => ({\n key,\n value: typeof value === 'string' ? value : String(value)\n }));\n }\n this.requestUpdate();\n }\n\n // Implement abstract methods\n isEmptyItem(item: KeyValueItem): boolean {\n return item.key.trim() === '' && item.value.trim() === '';\n }\n\n createEmptyItem(): KeyValueItem {\n return { key: '', value: '' };\n }\n\n // Override cleanItems to return array format to preserve duplicate keys\n protected cleanItems(items: KeyValueItem[]): KeyValueItem[] {\n return items.filter(\n ({ key, value }) => key.trim() !== '' || value.trim() !== ''\n );\n }\n\n // Method to convert to Record format for final form submission\n toRecord(): Record<string, string> {\n const result: Record<string, string> = {};\n this._items.forEach(({ key, value }) => {\n if (key.trim() !== '' || value.trim() !== '') {\n result[key] = value;\n }\n });\n return result;\n }\n\n // Method to validate and set key errors for duplicates and empty keys with values\n validateKeys(): boolean {\n const newKeyErrors: { [index: number]: string } = {};\n\n // Check for empty keys with values\n this._items.forEach(({ key, value }, index) => {\n if (key.trim() === '' && value.trim() !== '') {\n newKeyErrors[index] = 'Key is required when value is provided';\n }\n });\n\n // Check for duplicate keys (only non-empty ones)\n const nonEmptyKeys = this._items\n .map(({ key }, index) => ({ key: key.trim(), index }))\n .filter(({ key }) => key !== '');\n\n const keyCount = new Map<string, number[]>();\n nonEmptyKeys.forEach(({ key, index }) => {\n if (!keyCount.has(key)) {\n keyCount.set(key, []);\n }\n keyCount.get(key)!.push(index);\n });\n\n // Mark duplicate keys with errors\n keyCount.forEach((indices, key) => {\n if (indices.length > 1) {\n indices.forEach((index) => {\n // Only show duplicate error if there's no empty key error already\n if (!newKeyErrors[index]) {\n newKeyErrors[index] = `Duplicate key \"${key}\"`;\n }\n });\n }\n });\n\n this.keyErrors = newKeyErrors;\n return Object.keys(newKeyErrors).length === 0;\n }\n\n // Clear key errors\n clearKeyErrors(): void {\n this.keyErrors = {};\n }\n\n // Override updateValue to emit array format and validate keys\n protected updateValue(newValue: KeyValueItem[]) {\n this._items = newValue;\n\n // Clear errors and re-validate when items change\n this.clearKeyErrors();\n this.validateKeys();\n\n this.dispatchEvent(\n new CustomEvent('change', {\n detail: { value: this.cleanItems(newValue) },\n bubbles: true\n })\n );\n this.requestUpdate();\n }\n\n private handleKeyChange(index: number, newKey: string) {\n const items = this.displayItems;\n const currentItem = items[index];\n\n // Clear any existing error for this key when it's modified\n if (this.keyErrors[index]) {\n const newKeyErrors = { ...this.keyErrors };\n delete newKeyErrors[index];\n this.keyErrors = newKeyErrors;\n }\n\n this.handleItemChange(index, {\n key: newKey,\n value: currentItem.value\n });\n }\n\n private handleValueChange(index: number, newValue: string) {\n const items = this.displayItems;\n const currentItem = items[index];\n\n // Clear any existing error for this key when value is modified\n if (this.keyErrors[index]) {\n const newKeyErrors = { ...this.keyErrors };\n delete newKeyErrors[index];\n this.keyErrors = newKeyErrors;\n }\n\n this.handleItemChange(index, {\n key: currentItem.key,\n value: newValue\n });\n }\n\n renderItem(item: KeyValueItem, index: number): TemplateResult {\n const canRemove = this.canRemoveItem(index);\n const keyError =\n this.showValidation && this.keyErrors[index] ? this.keyErrors[index] : '';\n\n return html`\n <div class=\"row\">\n <temba-textinput\n .value=${item.key}\n .placeholder=${this.keyPlaceholder}\n .errors=${keyError ? [keyError] : []}\n @change=${(e: any) => this.handleKeyChange(index, e.target.value)}\n ></temba-textinput>\n <temba-textinput\n .value=${item.value}\n .placeholder=${this.valuePlaceholder}\n @change=${(e: any) => this.handleValueChange(index, e.target.value)}\n ></temba-textinput>\n ${canRemove\n ? html`\n <button class=\"remove-btn\" @click=${() => this.removeItem(index)}>\n ×\n </button>\n `\n : html`<div class=\"remove-btn-spacer\"></div>`}\n </div>\n `;\n }\n\n protected getContainerClass(): string {\n return 'key-value-editor';\n }\n\n static styles = css`\n .key-value-editor {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .row {\n display: grid;\n grid-template-columns: 1fr 1fr auto;\n align-items: center;\n column-gap: 6px;\n }\n\n .remove-btn {\n width: 32px;\n height: 32px;\n border: 1px solid #ccc;\n border-radius: 4px;\n background: #f8f8f8;\n color: #666;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n }\n\n .remove-btn:hover:not(:disabled) {\n background: #f0f0f0;\n }\n\n .remove-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .remove-btn-spacer {\n width: 32px;\n height: 32px;\n }\n `;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"KeyValueEditor.js","sourceRoot":"","sources":["../../../src/form/KeyValueEditor.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, css, TemplateResult } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { BaseListEditor, ListItem } from './BaseListEditor';\n\ninterface KeyValueItem extends ListItem {\n key: string;\n value: string;\n}\n\n@customElement('temba-key-value-editor')\nexport class KeyValueEditor extends BaseListEditor<KeyValueItem> {\n @property({ type: String })\n keyPlaceholder = 'Key';\n\n @property({ type: String })\n valuePlaceholder = 'Value';\n\n @property({ type: Boolean })\n showValidation = true;\n\n @state()\n private keyErrors: { [index: number]: string } = {};\n\n // Configure to maintain empty items\n maintainEmptyItem = true;\n\n constructor() {\n super();\n this._items = [];\n }\n\n // External API uses array format to preserve duplicate keys\n @property({ type: Array })\n get value(): KeyValueItem[] | any[] {\n return this._items.filter(\n ({ key, value }) => key.trim() !== '' || value.trim() !== ''\n );\n }\n\n set value(newValue: KeyValueItem[] | Record<string, string> | any) {\n if (Array.isArray(newValue)) {\n this._items = [...newValue];\n } else {\n // Convert Record to array format\n this._items = Object.entries(newValue || {}).map(([key, value]) => ({\n key,\n value: typeof value === 'string' ? value : String(value)\n }));\n }\n this.requestUpdate();\n }\n\n // Implement abstract methods\n isEmptyItem(item: KeyValueItem): boolean {\n return item.key.trim() === '' && item.value.trim() === '';\n }\n\n createEmptyItem(): KeyValueItem {\n return { key: '', value: '' };\n }\n\n // Override cleanItems to return array format to preserve duplicate keys\n protected cleanItems(items: KeyValueItem[]): KeyValueItem[] {\n return items.filter(\n ({ key, value }) => key.trim() !== '' || value.trim() !== ''\n );\n }\n\n // Method to convert to Record format for final form submission\n toRecord(): Record<string, string> {\n const result: Record<string, string> = {};\n this._items.forEach(({ key, value }) => {\n if (key.trim() !== '' || value.trim() !== '') {\n result[key] = value;\n }\n });\n return result;\n }\n\n // Method to validate and set key errors for duplicates and empty keys with values\n validateKeys(): boolean {\n const newKeyErrors: { [index: number]: string } = {};\n\n // Check for empty keys with values\n this._items.forEach(({ key, value }, index) => {\n if (key.trim() === '' && value.trim() !== '') {\n newKeyErrors[index] = 'Key is required when value is provided';\n }\n });\n\n // Check for duplicate keys (only non-empty ones)\n const nonEmptyKeys = this._items\n .map(({ key }, index) => ({ key: key.trim(), index }))\n .filter(({ key }) => key !== '');\n\n const keyCount = new Map<string, number[]>();\n nonEmptyKeys.forEach(({ key, index }) => {\n if (!keyCount.has(key)) {\n keyCount.set(key, []);\n }\n keyCount.get(key)!.push(index);\n });\n\n // Mark duplicate keys with errors\n keyCount.forEach((indices, key) => {\n if (indices.length > 1) {\n indices.forEach((index) => {\n // Only show duplicate error if there's no empty key error already\n if (!newKeyErrors[index]) {\n newKeyErrors[index] = `Duplicate key \"${key}\"`;\n }\n });\n }\n });\n\n this.keyErrors = newKeyErrors;\n return Object.keys(newKeyErrors).length === 0;\n }\n\n // Clear key errors\n clearKeyErrors(): void {\n this.keyErrors = {};\n }\n\n // Override updateValue to emit array format and validate keys\n protected updateValue(newValue: KeyValueItem[]) {\n this._items = newValue;\n\n // Clear errors and re-validate when items change\n this.clearKeyErrors();\n this.validateKeys();\n\n this.dispatchEvent(\n new CustomEvent('change', {\n detail: { value: this.cleanItems(newValue) },\n bubbles: true\n })\n );\n this.requestUpdate();\n }\n\n private handleKeyChange(index: number, newKey: string) {\n const items = this.displayItems;\n const currentItem = items[index];\n\n // Clear any existing error for this key when it's modified\n if (this.keyErrors[index]) {\n const newKeyErrors = { ...this.keyErrors };\n delete newKeyErrors[index];\n this.keyErrors = newKeyErrors;\n }\n\n this.handleItemChange(index, {\n key: newKey,\n value: currentItem.value\n });\n }\n\n private handleValueChange(index: number, newValue: string) {\n const items = this.displayItems;\n const currentItem = items[index];\n\n // Clear any existing error for this key when value is modified\n if (this.keyErrors[index]) {\n const newKeyErrors = { ...this.keyErrors };\n delete newKeyErrors[index];\n this.keyErrors = newKeyErrors;\n }\n\n this.handleItemChange(index, {\n key: currentItem.key,\n value: newValue\n });\n }\n\n renderItem(item: KeyValueItem, index: number): TemplateResult {\n const canRemove = this.canRemoveItem(index);\n const keyError =\n this.showValidation && this.keyErrors[index] ? this.keyErrors[index] : '';\n\n return html`\n <div class=\"row\">\n <temba-textinput\n .value=${item.key}\n .placeholder=${this.keyPlaceholder}\n .errors=${keyError ? [keyError] : []}\n @change=${(e: any) => this.handleKeyChange(index, e.target.value)}\n ></temba-textinput>\n <temba-textinput\n .value=${item.value}\n .placeholder=${this.valuePlaceholder}\n @change=${(e: any) => this.handleValueChange(index, e.target.value)}\n ></temba-textinput>\n ${canRemove\n ? html`\n <button class=\"remove-btn\" @click=${() => this.removeItem(index)}>\n ×\n </button>\n `\n : html`<div class=\"remove-btn-spacer\"></div>`}\n </div>\n `;\n }\n\n protected getContainerClass(): string {\n return 'key-value-editor';\n }\n\n static get styles() {\n return css`\n ${super.styles}\n\n .key-value-editor {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .row {\n display: grid;\n grid-template-columns: 1fr 1fr auto;\n align-items: center;\n column-gap: 6px;\n }\n\n .remove-btn {\n width: 32px;\n height: 32px;\n border: 1px solid #ccc;\n border-radius: 4px;\n background: #f8f8f8;\n color: #666;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n }\n\n .remove-btn:hover:not(:disabled) {\n background: #f0f0f0;\n }\n\n .remove-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .remove-btn-spacer {\n width: 32px;\n height: 32px;\n }\n `;\n }\n}\n"]}
|