@nyaruka/temba-components 0.129.9 → 0.129.11
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 +23 -0
- package/demo/data/flows/sample-flow.json +96 -56
- package/demo/test-colorpicker.html +30 -0
- package/dist/temba-components.js +896 -934
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/events.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +9 -6
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_channel.js +1 -1
- package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_field.js +1 -1
- package/out-tsc/src/flow/actions/set_contact_field.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_language.js +1 -1
- package/out-tsc/src/flow/actions/set_contact_language.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_status.js +1 -1
- package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -1
- package/out-tsc/src/flow/config.js +2 -8
- package/out-tsc/src/flow/config.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_llm.js +101 -0
- package/out-tsc/src/flow/nodes/split_by_llm.js.map +1 -0
- package/out-tsc/src/flow/nodes/split_by_llm_categorize.js +4 -89
- package/out-tsc/src/flow/nodes/split_by_llm_categorize.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_subflow.js +123 -3
- package/out-tsc/src/flow/nodes/split_by_subflow.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_ticket.js +115 -13
- package/out-tsc/src/flow/nodes/split_by_ticket.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_webhook.js +160 -12
- package/out-tsc/src/flow/nodes/split_by_webhook.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 +73 -99
- package/out-tsc/src/live/ContactChat.js.map +1 -1
- package/out-tsc/src/live/ContactFieldEditor.js.map +1 -1
- package/out-tsc/src/utils.js +115 -0
- package/out-tsc/src/utils.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/nodes/split_by_llm.test.js +174 -0
- package/out-tsc/test/nodes/split_by_llm.test.js.map +1 -0
- 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/add_contact_groups/editor/descriptive-group-names.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/long-group-names.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/many-groups.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/multiple-groups.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/single-group.png +0 -0
- 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/actions/send_email/editor/complex-business-email.png +0 -0
- package/screenshots/truth/actions/send_email/editor/empty-body.png +0 -0
- package/screenshots/truth/actions/send_email/editor/empty-subject.png +0 -0
- package/screenshots/truth/actions/send_email/editor/long-subject.png +0 -0
- package/screenshots/truth/actions/send_email/editor/multiline-body.png +0 -0
- package/screenshots/truth/actions/send_email/editor/multiple-recipients.png +0 -0
- package/screenshots/truth/actions/send_email/editor/simple-email.png +0 -0
- package/screenshots/truth/actions/send_email/editor/with-expressions.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/long-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/multiline-text-with-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/simple-text.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-with-linebreaks.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-with-many-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-with-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-without-quick-replies.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-whitespace-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/compose/attachments-tab.png +0 -0
- package/screenshots/truth/compose/attachments-with-files.png +0 -0
- package/screenshots/truth/compose/intial-text.png +0 -0
- package/screenshots/truth/compose/no-counter.png +0 -0
- package/screenshots/truth/compose/wraps-text-and-spaces.png +0 -0
- package/screenshots/truth/compose/wraps-text-and-url.png +0 -0
- package/screenshots/truth/compose/wraps-text-no-spaces.png +0 -0
- package/screenshots/truth/contacts/chat-failure.png +0 -0
- package/screenshots/truth/contacts/chat-for-active-contact.png +0 -0
- package/screenshots/truth/contacts/chat-sends-attachments-only.png +0 -0
- package/screenshots/truth/contacts/chat-sends-text-and-attachments.png +0 -0
- package/screenshots/truth/contacts/chat-sends-text-only.png +0 -0
- package/screenshots/truth/counter/summary.png +0 -0
- package/screenshots/truth/counter/text.png +0 -0
- package/screenshots/truth/counter/unicode-variables.png +0 -0
- package/screenshots/truth/counter/unicode.png +0 -0
- package/screenshots/truth/counter/variable.png +0 -0
- package/screenshots/truth/datepicker/date-truncated-time.png +0 -0
- package/screenshots/truth/datepicker/date.png +0 -0
- package/screenshots/truth/datepicker/initial-timezone.png +0 -0
- package/screenshots/truth/datepicker/range-picker-editing-start.png +0 -0
- package/screenshots/truth/datepicker/updated-keyboard-date.png +0 -0
- package/screenshots/truth/dialog/focused.png +0 -0
- package/screenshots/truth/dropdown/right-edge-collision.png +0 -0
- package/screenshots/truth/editor/router.png +0 -0
- package/screenshots/truth/editor/send_msg.png +0 -0
- package/screenshots/truth/editor/set_contact_language.png +0 -0
- package/screenshots/truth/editor/set_contact_name.png +0 -0
- package/screenshots/truth/editor/set_run_result.png +0 -0
- package/screenshots/truth/editor/wait.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/field-renderer/context-comparison.png +0 -0
- package/screenshots/truth/field-renderer/key-value-with-label.png +0 -0
- package/screenshots/truth/field-renderer/message-editor-with-label.png +0 -0
- package/screenshots/truth/field-renderer/select-multi.png +0 -0
- package/screenshots/truth/field-renderer/select-no-label.png +0 -0
- package/screenshots/truth/field-renderer/select-with-label.png +0 -0
- package/screenshots/truth/field-renderer/text-evaluated.png +0 -0
- package/screenshots/truth/field-renderer/text-no-label.png +0 -0
- package/screenshots/truth/field-renderer/text-with-errors.png +0 -0
- package/screenshots/truth/field-renderer/text-with-label.png +0 -0
- package/screenshots/truth/field-renderer/textarea-evaluated.png +0 -0
- package/screenshots/truth/field-renderer/textarea-with-label.png +0 -0
- package/screenshots/truth/integration/checkbox-markdown-errors.png +0 -0
- package/screenshots/truth/list/fields-dragging.png +0 -0
- package/screenshots/truth/list/fields-filtered.png +0 -0
- package/screenshots/truth/list/fields-hovered.png +0 -0
- package/screenshots/truth/list/fields.png +0 -0
- package/screenshots/truth/list/items-selected.png +0 -0
- package/screenshots/truth/list/items-updated.png +0 -0
- package/screenshots/truth/list/items.png +0 -0
- package/screenshots/truth/menu/menu-focused-with items.png +0 -0
- package/screenshots/truth/menu/menu-refresh-1.png +0 -0
- package/screenshots/truth/menu/menu-refresh-2.png +0 -0
- package/screenshots/truth/menu/menu-submenu.png +0 -0
- package/screenshots/truth/menu/menu-tasks-nextup.png +0 -0
- package/screenshots/truth/menu/menu-tasks.png +0 -0
- package/screenshots/truth/message-editor/autogrow-initial-content.png +0 -0
- package/screenshots/truth/message-editor/default.png +0 -0
- package/screenshots/truth/message-editor/drag-highlight.png +0 -0
- package/screenshots/truth/message-editor/filtered-attachments.png +0 -0
- package/screenshots/truth/message-editor/with-completion.png +0 -0
- package/screenshots/truth/message-editor/with-properties.png +0 -0
- package/screenshots/truth/modax/form.png +0 -0
- package/screenshots/truth/modax/simple.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/editor/information-extraction.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/editor/sentiment-analysis.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/editor/summarization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/editor/translation-task.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/information-extraction.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/sentiment-analysis.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/summarization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/translation-task.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/nodes/split_by_random/editor/ab-test-multiple-variants.png +0 -0
- package/screenshots/truth/nodes/split_by_random/editor/sampling-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/editor/three-way-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/editor/two-bucket-split.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/basic-digits-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/phone-number-collection.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/single-digit-with-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/verification-code.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/basic-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/custom-result-name.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/no-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/short-timeout.png +0 -0
- package/screenshots/truth/omnibox/selected.png +0 -0
- package/screenshots/truth/options/block.png +0 -0
- package/screenshots/truth/run-list/basic.png +0 -0
- package/screenshots/truth/select/disabled-multi-selection.png +0 -0
- package/screenshots/truth/select/disabled-selection.png +0 -0
- package/screenshots/truth/select/disabled.png +0 -0
- package/screenshots/truth/select/embedded.png +0 -0
- package/screenshots/truth/select/empty-options.png +0 -0
- package/screenshots/truth/select/expression-selected.png +0 -0
- package/screenshots/truth/select/expressions.png +0 -0
- package/screenshots/truth/select/functions.png +0 -0
- package/screenshots/truth/select/local-options.png +0 -0
- package/screenshots/truth/select/multi-with-endpoint.png +0 -0
- package/screenshots/truth/select/multiple-initial-values.png +0 -0
- package/screenshots/truth/select/remote-options.png +0 -0
- package/screenshots/truth/select/search-enabled.png +0 -0
- package/screenshots/truth/select/search-multi-no-matches.png +0 -0
- package/screenshots/truth/select/search-selected-focus.png +0 -0
- package/screenshots/truth/select/search-selected.png +0 -0
- package/screenshots/truth/select/search-with-selected.png +0 -0
- package/screenshots/truth/select/searching.png +0 -0
- package/screenshots/truth/select/selected-multi-maxitems-reached.png +0 -0
- package/screenshots/truth/select/selected-multi.png +0 -0
- package/screenshots/truth/select/selected-single.png +0 -0
- package/screenshots/truth/select/selection-clearable.png +0 -0
- package/screenshots/truth/select/static-initial-value.png +0 -0
- package/screenshots/truth/select/static-initial-via-selected.png +0 -0
- package/screenshots/truth/select/truncated-selection.png +0 -0
- package/screenshots/truth/select/with-placeholder.png +0 -0
- package/screenshots/truth/select/without-placeholder.png +0 -0
- package/screenshots/truth/slider/update-slider-on-circle-dragged.png +0 -0
- package/screenshots/truth/templates/default.png +0 -0
- package/screenshots/truth/templates/unapproved.png +0 -0
- package/screenshots/truth/textinput/autogrow-initial.png +0 -0
- package/screenshots/truth/textinput/input-disabled.png +0 -0
- package/screenshots/truth/textinput/input-focused.png +0 -0
- package/screenshots/truth/textinput/input-form.png +0 -0
- package/screenshots/truth/textinput/input-inserted.png +0 -0
- package/screenshots/truth/textinput/input-placeholder.png +0 -0
- package/screenshots/truth/textinput/input-updated.png +0 -0
- package/screenshots/truth/textinput/input.png +0 -0
- package/screenshots/truth/textinput/textarea-focused.png +0 -0
- package/screenshots/truth/textinput/textarea.png +0 -0
- package/src/events.ts +9 -8
- package/src/flow/Editor.ts +6 -3
- package/src/flow/actions/set_contact_channel.ts +1 -1
- package/src/flow/actions/set_contact_field.ts +1 -1
- package/src/flow/actions/set_contact_language.ts +1 -1
- package/src/flow/actions/set_contact_status.ts +1 -1
- package/src/flow/config.ts +2 -8
- package/src/flow/nodes/split_by_llm.ts +119 -0
- package/src/flow/nodes/split_by_llm_categorize.ts +13 -116
- package/src/flow/nodes/split_by_subflow.ts +153 -3
- package/src/flow/nodes/split_by_ticket.ts +135 -12
- package/src/flow/nodes/split_by_webhook.ts +187 -12
- 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 +81 -92
- package/src/live/ContactFieldEditor.ts +2 -2
- package/src/store/flow-definition.d.ts +2 -1
- package/src/utils.ts +192 -0
- package/temba-modules.ts +3 -2
- package/test/nodes/split_by_llm.test.ts +232 -0
- 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/test-assets/style.css +36 -234
- package/web-dev-server.config.mjs +26 -0
- package/web-test-runner.config.mjs +1 -1
- package/out-tsc/src/flow/actions/call_llm.js +0 -64
- package/out-tsc/src/flow/actions/call_llm.js.map +0 -1
- package/out-tsc/src/flow/actions/call_webhook.js +0 -131
- package/out-tsc/src/flow/actions/call_webhook.js.map +0 -1
- package/out-tsc/src/flow/actions/enter_flow.js +0 -14
- package/out-tsc/src/flow/actions/enter_flow.js.map +0 -1
- package/out-tsc/src/flow/actions/open_ticket.js +0 -73
- package/out-tsc/src/flow/actions/open_ticket.js.map +0 -1
- 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/actions/call_llm.test.js +0 -103
- package/out-tsc/test/actions/call_llm.test.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/flow/actions/call_llm.ts +0 -66
- package/src/flow/actions/call_webhook.ts +0 -143
- package/src/flow/actions/enter_flow.ts +0 -15
- package/src/flow/actions/open_ticket.ts +0 -83
- package/src/form/FormElement.ts +0 -69
- package/test/actions/call_llm.test.ts +0 -137
- package/test/temba-formfield.test.ts +0 -121
package/src/form/DatePicker.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { TemplateResult, html, css, PropertyValueMap } from 'lit';
|
|
2
2
|
import { property } from 'lit/decorators.js';
|
|
3
|
-
import {
|
|
3
|
+
import { FieldElement } from './FieldElement';
|
|
4
4
|
import { getClasses } from '../utils';
|
|
5
5
|
import { DateTime } from 'luxon';
|
|
6
6
|
|
|
7
|
-
export class DatePicker extends
|
|
7
|
+
export class DatePicker extends FieldElement {
|
|
8
8
|
static get styles() {
|
|
9
9
|
return css`
|
|
10
|
+
${super.styles}
|
|
10
11
|
:host {
|
|
11
12
|
display: block;
|
|
12
13
|
}
|
|
@@ -205,7 +206,7 @@ export class DatePicker extends FormElement {
|
|
|
205
206
|
this.shadowRoot.querySelector('input').focus();
|
|
206
207
|
}
|
|
207
208
|
|
|
208
|
-
|
|
209
|
+
protected renderWidget(): TemplateResult {
|
|
209
210
|
const classes = getClasses({ unset: !this.value });
|
|
210
211
|
|
|
211
212
|
let dateWidgetValue = null;
|
|
@@ -216,42 +217,35 @@ export class DatePicker extends FormElement {
|
|
|
216
217
|
}
|
|
217
218
|
|
|
218
219
|
return html`
|
|
219
|
-
<
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
<div class="input-wrapper">
|
|
232
|
-
<input
|
|
233
|
-
class=${classes}
|
|
234
|
-
name=${this.label}
|
|
235
|
-
value=${dateWidgetValue}
|
|
236
|
-
type="${this.time ? 'datetime-local' : 'date'}"
|
|
237
|
-
@change=${this.handleChange}
|
|
238
|
-
min=${this.min || undefined}
|
|
239
|
-
max=${this.max || undefined}
|
|
240
|
-
/>
|
|
241
|
-
</div>
|
|
242
|
-
${this.time
|
|
243
|
-
? html`
|
|
244
|
-
<div class="tz-wrapper">
|
|
245
|
-
<div class="tz">
|
|
246
|
-
<div class="label">Time Zone</div>
|
|
247
|
-
<div class="zone">${this.timezoneFriendly}</div>
|
|
248
|
-
</div>
|
|
249
|
-
</div>
|
|
250
|
-
`
|
|
251
|
-
: null}
|
|
252
|
-
<slot name="postfix"></slot>
|
|
220
|
+
<div class="container" @click=${this.handleClicked}>
|
|
221
|
+
<slot name="prefix"></slot>
|
|
222
|
+
<div class="input-wrapper">
|
|
223
|
+
<input
|
|
224
|
+
class=${classes}
|
|
225
|
+
name=${this.label}
|
|
226
|
+
value=${dateWidgetValue}
|
|
227
|
+
type="${this.time ? 'datetime-local' : 'date'}"
|
|
228
|
+
@change=${this.handleChange}
|
|
229
|
+
min=${this.min || undefined}
|
|
230
|
+
max=${this.max || undefined}
|
|
231
|
+
/>
|
|
253
232
|
</div>
|
|
254
|
-
|
|
233
|
+
${this.time
|
|
234
|
+
? html`
|
|
235
|
+
<div class="tz-wrapper">
|
|
236
|
+
<div class="tz">
|
|
237
|
+
<div class="label">Time Zone</div>
|
|
238
|
+
<div class="zone">${this.timezoneFriendly}</div>
|
|
239
|
+
</div>
|
|
240
|
+
</div>
|
|
241
|
+
`
|
|
242
|
+
: null}
|
|
243
|
+
<slot name="postfix"></slot>
|
|
244
|
+
</div>
|
|
255
245
|
`;
|
|
256
246
|
}
|
|
247
|
+
|
|
248
|
+
public render(): TemplateResult {
|
|
249
|
+
return this.renderField();
|
|
250
|
+
}
|
|
257
251
|
}
|
|
@@ -1,12 +1,65 @@
|
|
|
1
|
-
import { TemplateResult, html, css
|
|
1
|
+
import { TemplateResult, html, css } from 'lit';
|
|
2
2
|
import { property } from 'lit/decorators.js';
|
|
3
|
+
import { RapidElement } from '../RapidElement';
|
|
3
4
|
import { renderMarkdownInline } from '../markdown';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
7
|
+
* FieldElement is a base class for form components that provides built-in
|
|
8
|
+
* field wrapper functionality, eliminating the need for manual temba-field embedding.
|
|
9
|
+
*
|
|
10
|
+
* Components extending this class only need to implement renderWidget() with their
|
|
11
|
+
* specific widget content, and the field wrapper (label, errors, help text) is
|
|
12
|
+
* automatically handled.
|
|
8
13
|
*/
|
|
9
|
-
export class
|
|
14
|
+
export abstract class FieldElement extends RapidElement {
|
|
15
|
+
@property({ type: String })
|
|
16
|
+
name = '';
|
|
17
|
+
|
|
18
|
+
@property({ type: String, attribute: 'help_text' })
|
|
19
|
+
helpText: string;
|
|
20
|
+
|
|
21
|
+
@property({ type: Boolean, attribute: 'widget_only' })
|
|
22
|
+
widgetOnly: boolean;
|
|
23
|
+
|
|
24
|
+
@property({ type: Array })
|
|
25
|
+
errors: string[];
|
|
26
|
+
|
|
27
|
+
// Use @property with custom getter/setter to handle both attribute and programmatic access
|
|
28
|
+
private _value: any = '';
|
|
29
|
+
|
|
30
|
+
@property({ type: String })
|
|
31
|
+
public get value() {
|
|
32
|
+
return this._value;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public set value(value) {
|
|
36
|
+
this._value = value;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@property({ attribute: false })
|
|
40
|
+
inputRoot: HTMLElement = this;
|
|
41
|
+
|
|
42
|
+
@property({ type: Boolean })
|
|
43
|
+
disabled = false;
|
|
44
|
+
|
|
45
|
+
static formAssociated = true;
|
|
46
|
+
|
|
47
|
+
protected internals: ElementInternals;
|
|
48
|
+
|
|
49
|
+
@property({ type: Boolean })
|
|
50
|
+
hideErrors = false;
|
|
51
|
+
|
|
52
|
+
@property({ type: Boolean, attribute: 'hide_label' })
|
|
53
|
+
hideLabel: boolean;
|
|
54
|
+
|
|
55
|
+
@property({ type: String })
|
|
56
|
+
label: string;
|
|
57
|
+
|
|
58
|
+
constructor() {
|
|
59
|
+
super();
|
|
60
|
+
this.internals = this.attachInternals();
|
|
61
|
+
}
|
|
62
|
+
|
|
10
63
|
static get styles() {
|
|
11
64
|
return css`
|
|
12
65
|
:host {
|
|
@@ -29,19 +82,6 @@ export class FormField extends LitElement {
|
|
|
29
82
|
line-height: normal;
|
|
30
83
|
color: var(--color-text-help);
|
|
31
84
|
margin-left: var(--help-text-margin-left);
|
|
32
|
-
margin-top: -16px;
|
|
33
|
-
opacity: 0;
|
|
34
|
-
transition: opacity ease-in-out 100ms, margin-top ease-in-out 200ms;
|
|
35
|
-
pointer-events: none;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.help-text.help-always {
|
|
39
|
-
opacity: 1;
|
|
40
|
-
margin-top: 6px;
|
|
41
|
-
margin-left: var(--help-text-margin-left);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
.field:focus-within .help-text {
|
|
45
85
|
margin-top: 6px;
|
|
46
86
|
opacity: 1;
|
|
47
87
|
}
|
|
@@ -151,36 +191,13 @@ export class FormField extends LitElement {
|
|
|
151
191
|
`;
|
|
152
192
|
}
|
|
153
193
|
|
|
154
|
-
|
|
155
|
-
hideLabel = false;
|
|
156
|
-
|
|
157
|
-
@property({ type: Boolean, attribute: 'widget_only' })
|
|
158
|
-
widgetOnly = false;
|
|
159
|
-
|
|
160
|
-
@property({ type: Array, attribute: false })
|
|
161
|
-
errors: string[] = [];
|
|
162
|
-
|
|
163
|
-
@property({ type: Boolean })
|
|
164
|
-
hideErrors = false;
|
|
165
|
-
|
|
166
|
-
@property({ type: String, attribute: 'help_text' })
|
|
167
|
-
helpText = '';
|
|
168
|
-
|
|
169
|
-
@property({ type: Boolean, attribute: 'help_always' })
|
|
170
|
-
helpAlways = true;
|
|
171
|
-
|
|
172
|
-
@property({ type: String })
|
|
173
|
-
label = '';
|
|
174
|
-
|
|
175
|
-
@property({ type: String })
|
|
176
|
-
name = '';
|
|
177
|
-
|
|
178
|
-
@property({ type: Boolean })
|
|
179
|
-
disabled = false;
|
|
180
|
-
|
|
181
|
-
updated(changedProperties: Map<string | number | symbol, unknown>): void {
|
|
194
|
+
updated(changedProperties: Map<string, any>): void {
|
|
182
195
|
super.updated(changedProperties);
|
|
183
196
|
|
|
197
|
+
if (changedProperties.has('value')) {
|
|
198
|
+
this.internals.setFormValue(this.value);
|
|
199
|
+
}
|
|
200
|
+
|
|
184
201
|
if (
|
|
185
202
|
changedProperties.has('errors') ||
|
|
186
203
|
changedProperties.has('hideErrors')
|
|
@@ -191,7 +208,36 @@ export class FormField extends LitElement {
|
|
|
191
208
|
}
|
|
192
209
|
}
|
|
193
210
|
|
|
194
|
-
|
|
211
|
+
get form() {
|
|
212
|
+
return this.internals.form;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
public setValue(value: any) {
|
|
216
|
+
this.value = this.serializeValue(value);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
public getDeserializedValue(): any {
|
|
220
|
+
if (!this.value || this.value === '') {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
return JSON.parse(this.value);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
public serializeValue(value: any): string {
|
|
227
|
+
return JSON.stringify(value);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Abstract method that components must implement to render their specific widget content.
|
|
232
|
+
* This replaces the need to manually embed temba-field.
|
|
233
|
+
*/
|
|
234
|
+
protected abstract renderWidget(): TemplateResult;
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Renders the complete field including label, widget, errors, and help text.
|
|
238
|
+
* Components can override this for custom layouts, but typically should just implement renderWidget().
|
|
239
|
+
*/
|
|
240
|
+
protected renderField(): TemplateResult {
|
|
195
241
|
const hasErrors = !this.hideErrors && this.errors && this.errors.length > 0;
|
|
196
242
|
const errors = hasErrors
|
|
197
243
|
? this.errors.map((error: string) => {
|
|
@@ -203,7 +249,9 @@ export class FormField extends LitElement {
|
|
|
203
249
|
|
|
204
250
|
if (this.widgetOnly) {
|
|
205
251
|
return html`
|
|
206
|
-
<div class="${this.disabled ? 'disabled' : ''}"
|
|
252
|
+
<div class="${this.disabled ? 'disabled' : ''}">
|
|
253
|
+
${this.renderWidget()}
|
|
254
|
+
</div>
|
|
207
255
|
${errors}
|
|
208
256
|
`;
|
|
209
257
|
}
|
|
@@ -221,13 +269,10 @@ export class FormField extends LitElement {
|
|
|
221
269
|
>
|
|
222
270
|
`
|
|
223
271
|
: null}
|
|
224
|
-
<div class="widget">
|
|
225
|
-
<slot></slot>
|
|
226
|
-
${errors}
|
|
227
|
-
</div>
|
|
272
|
+
<div class="widget">${this.renderWidget()} ${errors}</div>
|
|
228
273
|
${this.helpText && this.helpText !== 'None'
|
|
229
274
|
? html`
|
|
230
|
-
<div class="help-text
|
|
275
|
+
<div class="help-text">
|
|
231
276
|
${renderMarkdownInline(this.helpText)}
|
|
232
277
|
</div>
|
|
233
278
|
`
|
|
@@ -235,4 +280,12 @@ export class FormField extends LitElement {
|
|
|
235
280
|
</div>
|
|
236
281
|
`;
|
|
237
282
|
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Main render method that automatically provides field wrapper functionality.
|
|
286
|
+
* Components extending FieldElement should not override this unless they need custom field layouts.
|
|
287
|
+
*/
|
|
288
|
+
public render(): TemplateResult {
|
|
289
|
+
return this.renderField();
|
|
290
|
+
}
|
|
238
291
|
}
|
|
@@ -385,8 +385,9 @@ export class FieldRenderer {
|
|
|
385
385
|
} = context;
|
|
386
386
|
|
|
387
387
|
return html`<div class="form-field">
|
|
388
|
-
${showLabel ? html`<label>${config.label}</label>` : ''}
|
|
389
388
|
<temba-array-editor
|
|
389
|
+
name="${fieldName}"
|
|
390
|
+
.label="${showLabel ? config.label : ''}"
|
|
390
391
|
.value="${value || []}"
|
|
391
392
|
.itemConfig="${config.itemConfig}"
|
|
392
393
|
.sortable="${config.sortable}"
|
package/src/form/ImagePicker.ts
CHANGED
|
@@ -3,120 +3,123 @@ import { html, css, PropertyValueMap } from 'lit';
|
|
|
3
3
|
import { CroppieCSS } from './CroppieCSS';
|
|
4
4
|
import { property } from 'lit/decorators.js';
|
|
5
5
|
import { Icon } from '../Icons';
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
export class ImagePicker extends
|
|
9
|
-
static styles
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
6
|
+
import { FieldElement } from './FieldElement';
|
|
7
|
+
|
|
8
|
+
export class ImagePicker extends FieldElement {
|
|
9
|
+
static get styles() {
|
|
10
|
+
return css`
|
|
11
|
+
${super.styles}
|
|
12
|
+
${CroppieCSS}
|
|
13
|
+
|
|
14
|
+
.croppie {
|
|
15
|
+
max-width: 400px;
|
|
16
|
+
border: 0px solid #ccc;
|
|
17
|
+
border-radius: 0.5em;
|
|
18
|
+
overflow: hidden;
|
|
19
|
+
background: #fff;
|
|
20
|
+
margin-top: -20%;
|
|
21
|
+
box-shadow: 0 0 15px 5px rgba(0, 0, 0, 0.1);
|
|
22
|
+
}
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
.croppie .controls {
|
|
25
|
+
display: flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
flex-direction: row;
|
|
28
|
+
justify-content: center;
|
|
29
|
+
position: absolute;
|
|
30
|
+
z-index: 1;
|
|
31
|
+
width: 400px;
|
|
32
|
+
margin-top: -42px;
|
|
33
|
+
}
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
.toggle {
|
|
36
|
+
height: 110px;
|
|
37
|
+
width: 110px;
|
|
38
|
+
cursor: pointer;
|
|
39
|
+
display: flex;
|
|
40
|
+
align-items: center;
|
|
41
|
+
justify-content: center;
|
|
42
|
+
}
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
.circle .toggle {
|
|
45
|
+
border-radius: 50%;
|
|
46
|
+
}
|
|
45
47
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
.toggle.set {
|
|
49
|
+
box-shadow: rgba(0, 0, 0, 0.1) 0px 3px 7px 0px,
|
|
50
|
+
rgba(0, 0, 0, 0.2) 0px 1px 2px 0px, inset 0 0 0 5px rgba(0, 0, 0, 0.1);
|
|
51
|
+
}
|
|
50
52
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
.toggle.set:hover {
|
|
54
|
+
box-shadow: rgba(0, 0, 0, 0.1) 0px 3px 7px 0px,
|
|
55
|
+
rgba(0, 0, 0, 0.2) 0px 1px 2px 0px, inset 0 0 0 5px rgba(0, 0, 0, 0.2);
|
|
56
|
+
}
|
|
55
57
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
.toggle temba-icon {
|
|
59
|
+
color: rgba(0, 0, 0, 0.2);
|
|
60
|
+
padding: 5px;
|
|
61
|
+
}
|
|
60
62
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
toggle:hover temba-icon {
|
|
64
|
+
color: rgba(0, 0, 0, 0.8);
|
|
65
|
+
}
|
|
64
66
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
.toggle.set temba-icon {
|
|
68
|
+
border-radius: 50%;
|
|
69
|
+
margin-right: -90%;
|
|
70
|
+
margin-bottom: -50%;
|
|
71
|
+
background: rgba(240, 240, 240, 1);
|
|
72
|
+
box-shadow: rgba(0, 0, 0, 0.2) 0px 1px 2px 0px;
|
|
73
|
+
}
|
|
72
74
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
.toggle.set:hover temba-icon {
|
|
76
|
+
background: #fff;
|
|
77
|
+
color: var(--color-primary-dark);
|
|
78
|
+
}
|
|
77
79
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
.circle .toggle.set temba-icon {
|
|
81
|
+
margin-right: -70%;
|
|
82
|
+
margin-bottom: -70%;
|
|
83
|
+
}
|
|
82
84
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
.hidden {
|
|
86
|
+
display: none;
|
|
87
|
+
}
|
|
86
88
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
89
|
+
.controls temba-icon {
|
|
90
|
+
margin: 0em 0.75em;
|
|
91
|
+
background: rgba(255, 255, 255, 0.8);
|
|
92
|
+
border-radius: 50%;
|
|
93
|
+
padding: 6px;
|
|
94
|
+
transition: all 0.1s ease-in-out;
|
|
95
|
+
}
|
|
94
96
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
.controls {
|
|
98
|
+
pointer-events: none;
|
|
99
|
+
display: flex;
|
|
100
|
+
}
|
|
99
101
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
.controls temba-icon {
|
|
103
|
+
pointer-events: all;
|
|
104
|
+
}
|
|
103
105
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
.controls temba-icon.close {
|
|
107
|
+
color: rgba(0, 0, 0, 0.2);
|
|
108
|
+
background: rgba(255, 255, 255, 0.2);
|
|
109
|
+
}
|
|
108
110
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
.controls temba-icon.submit {
|
|
112
|
+
color: rgba(0, 0, 0, 0.2);
|
|
113
|
+
box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.1);
|
|
114
|
+
}
|
|
113
115
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
116
|
+
.controls temba-icon:hover {
|
|
117
|
+
color: white;
|
|
118
|
+
cursor: pointer;
|
|
119
|
+
background: var(--color-primary-dark);
|
|
120
|
+
}
|
|
121
|
+
`;
|
|
122
|
+
}
|
|
120
123
|
|
|
121
124
|
@property({ type: String })
|
|
122
125
|
tempImage: string;
|
|
@@ -221,18 +224,9 @@ export class ImagePicker extends FormElement {
|
|
|
221
224
|
input.value = '';
|
|
222
225
|
}
|
|
223
226
|
|
|
224
|
-
protected
|
|
227
|
+
protected renderWidget() {
|
|
225
228
|
return html`
|
|
226
|
-
|
|
227
|
-
<temba-field
|
|
228
|
-
name=${this.name}
|
|
229
|
-
label=${this.label}
|
|
230
|
-
.helpText=${this.helpText}
|
|
231
|
-
.errors=${this.errors}
|
|
232
|
-
.widgetOnly=${this.widgetOnly}
|
|
233
|
-
.helpAlways=${true}
|
|
234
|
-
?disabled=${this.disabled}
|
|
235
|
-
>
|
|
229
|
+
<div class="wrapper ${this.shape} ${this.label ? 'label' : ''}">
|
|
236
230
|
<input class='hidden' type="file" accept="image/*" capture="camera" id="file" name="file" @change=${
|
|
237
231
|
this.handleFileChanged
|
|
238
232
|
}/>
|
|
@@ -261,8 +255,11 @@ export class ImagePicker extends FormElement {
|
|
|
261
255
|
}></temba-icon>
|
|
262
256
|
</div>
|
|
263
257
|
</temba-mask>
|
|
264
|
-
</
|
|
265
|
-
</div>
|
|
258
|
+
</div>
|
|
266
259
|
`;
|
|
267
260
|
}
|
|
261
|
+
|
|
262
|
+
public render() {
|
|
263
|
+
return this.renderField();
|
|
264
|
+
}
|
|
268
265
|
}
|
|
@@ -31,13 +31,13 @@ export class KeyValueEditor extends BaseListEditor<KeyValueItem> {
|
|
|
31
31
|
|
|
32
32
|
// External API uses array format to preserve duplicate keys
|
|
33
33
|
@property({ type: Array })
|
|
34
|
-
get value(): KeyValueItem[] {
|
|
34
|
+
get value(): KeyValueItem[] | any[] {
|
|
35
35
|
return this._items.filter(
|
|
36
36
|
({ key, value }) => key.trim() !== '' || value.trim() !== ''
|
|
37
37
|
);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
set value(newValue: KeyValueItem[] | Record<string, string>) {
|
|
40
|
+
set value(newValue: KeyValueItem[] | Record<string, string> | any) {
|
|
41
41
|
if (Array.isArray(newValue)) {
|
|
42
42
|
this._items = [...newValue];
|
|
43
43
|
} else {
|
|
@@ -206,46 +206,50 @@ export class KeyValueEditor extends BaseListEditor<KeyValueItem> {
|
|
|
206
206
|
return 'key-value-editor';
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
-
static styles
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
flex-direction: column;
|
|
213
|
-
gap: 8px;
|
|
214
|
-
}
|
|
209
|
+
static get styles() {
|
|
210
|
+
return css`
|
|
211
|
+
${super.styles}
|
|
215
212
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
}
|
|
213
|
+
.key-value-editor {
|
|
214
|
+
display: flex;
|
|
215
|
+
flex-direction: column;
|
|
216
|
+
gap: 8px;
|
|
217
|
+
}
|
|
222
218
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
color: #666;
|
|
230
|
-
cursor: pointer;
|
|
231
|
-
display: flex;
|
|
232
|
-
align-items: center;
|
|
233
|
-
justify-content: center;
|
|
234
|
-
font-size: 18px;
|
|
235
|
-
}
|
|
219
|
+
.row {
|
|
220
|
+
display: grid;
|
|
221
|
+
grid-template-columns: 1fr 1fr auto;
|
|
222
|
+
align-items: center;
|
|
223
|
+
column-gap: 6px;
|
|
224
|
+
}
|
|
236
225
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
226
|
+
.remove-btn {
|
|
227
|
+
width: 32px;
|
|
228
|
+
height: 32px;
|
|
229
|
+
border: 1px solid #ccc;
|
|
230
|
+
border-radius: 4px;
|
|
231
|
+
background: #f8f8f8;
|
|
232
|
+
color: #666;
|
|
233
|
+
cursor: pointer;
|
|
234
|
+
display: flex;
|
|
235
|
+
align-items: center;
|
|
236
|
+
justify-content: center;
|
|
237
|
+
font-size: 18px;
|
|
238
|
+
}
|
|
240
239
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
}
|
|
240
|
+
.remove-btn:hover:not(:disabled) {
|
|
241
|
+
background: #f0f0f0;
|
|
242
|
+
}
|
|
245
243
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
244
|
+
.remove-btn:disabled {
|
|
245
|
+
opacity: 0.5;
|
|
246
|
+
cursor: not-allowed;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.remove-btn-spacer {
|
|
250
|
+
width: 32px;
|
|
251
|
+
height: 32px;
|
|
252
|
+
}
|
|
253
|
+
`;
|
|
254
|
+
}
|
|
251
255
|
}
|