@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":"events.js","sourceRoot":"","sources":["../../src/events.ts"],"names":[],"mappings":"","sourcesContent":["import { Msg, ObjectReference, User } from './interfaces';\n\nexport interface EventGroup {\n type: string;\n events: ContactEvent[];\n open: boolean;\n}\n\nexport interface ContactEvent {\n uuid?: string;\n type: string;\n created_on: string;\n created_by?: User;\n}\n\nexport interface ChannelEvent extends ContactEvent {\n channel_event_type: string;\n duration: number;\n\n event: {\n type: string;\n channel: { uuid: string; name: string };\n duration?: number;\n optin?: {\n uuid: string;\n name: string;\n };\n };\n}\n\nexport interface ContactLanguageChangedEvent extends ContactEvent {\n language: string;\n step_uuid: string;\n session_uuid: string;\n}\n\nexport interface OptInEvent extends ContactEvent {\n optin: {\n uuid: string;\n name: string;\n };\n}\n\nexport interface CallEvent extends ContactEvent {\n call
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/events.ts"],"names":[],"mappings":"","sourcesContent":["import { Msg, ObjectReference, User } from './interfaces';\n\nexport interface EventGroup {\n type: string;\n events: ContactEvent[];\n open: boolean;\n}\n\nexport interface ContactEvent {\n uuid?: string;\n type: string;\n created_on: string;\n created_by?: User;\n}\n\nexport interface ChannelEvent extends ContactEvent {\n channel_event_type: string;\n duration: number;\n\n event: {\n type: string;\n channel: { uuid: string; name: string };\n duration?: number;\n optin?: {\n uuid: string;\n name: string;\n };\n };\n}\n\nexport interface ContactLanguageChangedEvent extends ContactEvent {\n language: string;\n step_uuid: string;\n session_uuid: string;\n}\n\nexport interface OptInEvent extends ContactEvent {\n optin: {\n uuid: string;\n name: string;\n };\n}\n\nexport interface CallEvent extends ContactEvent {\n call?: {\n uuid: string;\n urn: string;\n };\n}\n\nexport interface ChatStartedEvent extends ContactEvent {\n params?: object;\n}\n\nexport interface MsgEvent extends ContactEvent {\n msg: Msg;\n status: string;\n failed_reason?: string;\n failed_reason_display?: string;\n logs_url: string;\n recipient_count?: number;\n created_by?: User;\n optin?: ObjectReference;\n}\n\nexport interface RunEvent extends ContactEvent {\n flow: ObjectReference;\n status: string;\n}\n\nexport interface URNsChangedEvent extends ContactEvent {\n urns: string[];\n}\n\nexport interface TicketEvent extends ContactEvent {\n note?: string;\n assignee?: User;\n ticket: {\n uuid: string;\n topic?: ObjectReference;\n closed_on?: string;\n opened_on?: string;\n };\n topic?: ObjectReference;\n created_by?: User;\n}\n\nexport interface NameChangedEvent extends ContactEvent {\n name: string;\n}\n\nexport interface UpdateFieldEvent extends ContactEvent {\n field: { key: string; name: string };\n value: { text: string };\n}\n\nexport interface ContactGroupsEvent extends ContactEvent {\n groups_added: ObjectReference[];\n groups_removed: ObjectReference[];\n}\n\nexport interface AirtimeTransferredEvent extends ContactEvent {\n sender: string;\n recipient: string;\n currency: string;\n amount: string;\n}\n\nexport type CallStartedEvent = ContactEvent;\n\nexport interface ContactHistoryPage {\n has_older: boolean;\n recent_only: boolean;\n next_before: number;\n next_after: number;\n start_date: Date;\n events: ContactEvent[];\n}\n"]}
|
|
@@ -73,7 +73,7 @@ let TembaArrayEditor = class TembaArrayEditor extends BaseListEditor {
|
|
|
73
73
|
}
|
|
74
74
|
return currentValue;
|
|
75
75
|
}
|
|
76
|
-
|
|
76
|
+
renderArrayField(itemIndex, fieldName, config) {
|
|
77
77
|
const computedValue = this.computeFieldValue(itemIndex, fieldName, config);
|
|
78
78
|
// Use FieldRenderer for consistent field rendering
|
|
79
79
|
return FieldRenderer.renderField(fieldName, config, computedValue, {
|
|
@@ -120,7 +120,7 @@ let TembaArrayEditor = class TembaArrayEditor extends BaseListEditor {
|
|
|
120
120
|
<div class="item-fields">
|
|
121
121
|
${Object.entries(this.itemConfig).map(([fieldName, config]) => html `
|
|
122
122
|
<div class="field">
|
|
123
|
-
${this.
|
|
123
|
+
${this.renderArrayField(index, fieldName, config)}
|
|
124
124
|
</div>
|
|
125
125
|
`)}
|
|
126
126
|
${canRemove
|
|
@@ -140,70 +140,59 @@ let TembaArrayEditor = class TembaArrayEditor extends BaseListEditor {
|
|
|
140
140
|
getContainerClass() {
|
|
141
141
|
return 'array-editor';
|
|
142
142
|
}
|
|
143
|
-
|
|
144
|
-
return
|
|
145
|
-
|
|
146
|
-
Add ${this.itemLabel}
|
|
147
|
-
</button>
|
|
148
|
-
`;
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
TembaArrayEditor.styles = css `
|
|
152
|
-
.array-editor {
|
|
153
|
-
}
|
|
143
|
+
static get styles() {
|
|
144
|
+
return css `
|
|
145
|
+
${super.styles}
|
|
154
146
|
|
|
155
|
-
|
|
156
|
-
|
|
147
|
+
.array-editor {
|
|
148
|
+
}
|
|
157
149
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
justify-content: space-between;
|
|
161
|
-
align-items: center;
|
|
162
|
-
}
|
|
150
|
+
.array-item {
|
|
151
|
+
}
|
|
163
152
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
153
|
+
.item-header {
|
|
154
|
+
display: flex;
|
|
155
|
+
justify-content: space-between;
|
|
156
|
+
align-items: center;
|
|
157
|
+
}
|
|
168
158
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
}
|
|
159
|
+
.item-title {
|
|
160
|
+
font-weight: 600;
|
|
161
|
+
color: #333;
|
|
162
|
+
}
|
|
174
163
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
164
|
+
.item-fields {
|
|
165
|
+
display: flex;
|
|
166
|
+
gap: 12px;
|
|
167
|
+
align-items: center;
|
|
168
|
+
}
|
|
178
169
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
font-weight: 500;
|
|
183
|
-
color: #555;
|
|
184
|
-
font-size: 14px;
|
|
185
|
-
}
|
|
170
|
+
.field {
|
|
171
|
+
flex: 1;
|
|
172
|
+
}
|
|
186
173
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
174
|
+
.add-btn,
|
|
175
|
+
.remove-btn {
|
|
176
|
+
padding: 8px;
|
|
177
|
+
border: 1px solid #ccc;
|
|
178
|
+
border-radius: 4px;
|
|
179
|
+
background: white;
|
|
180
|
+
cursor: pointer;
|
|
181
|
+
font-size: 14px;
|
|
182
|
+
}
|
|
196
183
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
184
|
+
.add-btn:hover,
|
|
185
|
+
.remove-btn:hover {
|
|
186
|
+
background: #f8f8f8;
|
|
187
|
+
}
|
|
201
188
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
189
|
+
.remove-btn {
|
|
190
|
+
background: #fefefe;
|
|
191
|
+
color: #999;
|
|
192
|
+
}
|
|
193
|
+
`;
|
|
205
194
|
}
|
|
206
|
-
|
|
195
|
+
};
|
|
207
196
|
__decorate([
|
|
208
197
|
property({ type: Object })
|
|
209
198
|
], TembaArrayEditor.prototype, "itemConfig", void 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ArrayEditor.js","sourceRoot":"","sources":["../../../src/form/ArrayEditor.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, css, TemplateResult } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { FieldConfig, SelectFieldConfig } from '../flow/types';\nimport { BaseListEditor, ListItem } from './BaseListEditor';\nimport { FieldRenderer } from './FieldRenderer';\n\n@customElement('temba-array-editor')\nexport class TembaArrayEditor extends BaseListEditor<ListItem> {\n @property({ type: Object })\n itemConfig: Record<string, FieldConfig> = {};\n\n @property({ type: String })\n itemLabel = 'Item';\n\n @property({ type: Function })\n onItemChange?: (\n itemIndex: number,\n field: string,\n value: any,\n allItems: any[]\n ) => any[];\n\n @property({ type: Function })\n isEmptyItemFn?: (item: any) => boolean;\n\n @property({ type: Boolean })\n maintainEmptyItem = true; // Enable by default for better UX\n\n constructor() {\n super();\n this._items = [];\n }\n\n // External API\n @property({ type: Array })\n get value(): any[] {\n return [...this._items];\n }\n\n set value(newValue: any[]) {\n this._items = newValue || [];\n this.requestUpdate();\n }\n\n // Implement abstract methods\n isEmptyItem(item: ListItem): boolean {\n // Use configurable function if provided\n if (this.isEmptyItemFn) {\n return this.isEmptyItemFn(item);\n }\n\n // Default behavior: check if all values are empty\n const values = Object.values(item);\n if (values.length === 0) {\n return true;\n }\n\n return values.every(\n (value) => value === undefined || value === null || value === ''\n );\n }\n\n // Override cleanItems to be more permissive for form data\n protected cleanItems(items: ListItem[]): any {\n // For runtime attachments, keep items that have at least one non-empty field\n return items.filter((item) => {\n const values = Object.values(item);\n return (\n values.length > 0 &&\n values.some(\n (value) => value !== undefined && value !== null && value !== ''\n )\n );\n });\n }\n\n createEmptyItem(): ListItem {\n return {};\n }\n\n protected handleFieldChange(\n itemIndex: number,\n fieldName: string,\n newValue: any\n ) {\n let updatedItems: any[];\n\n if (this.onItemChange) {\n updatedItems = this.onItemChange(\n itemIndex,\n fieldName,\n newValue,\n this._items\n );\n } else {\n updatedItems = [...this._items];\n updatedItems[itemIndex] = {\n ...updatedItems[itemIndex],\n [fieldName]: newValue\n };\n }\n\n this.updateValue(updatedItems);\n }\n\n private computeFieldValue(\n itemIndex: number,\n fieldName: string,\n config: FieldConfig\n ): any {\n const item = this._items[itemIndex] || {};\n const currentValue = item[fieldName];\n\n if (config.computeValue) {\n return config.computeValue(item, currentValue);\n }\n\n // For select fields, ensure we return the right type\n if (config.type === 'select') {\n const selectConfig = config as SelectFieldConfig;\n if (currentValue === undefined || currentValue === null) {\n return selectConfig.multi ? [] : '';\n }\n }\n\n return currentValue;\n }\n\n private renderField(\n itemIndex: number,\n fieldName: string,\n config: FieldConfig\n ): TemplateResult {\n const computedValue = this.computeFieldValue(itemIndex, fieldName, config);\n\n // Use FieldRenderer for consistent field rendering\n return FieldRenderer.renderField(fieldName, config, computedValue, {\n showLabel: false, // ArrayEditor doesn't show labels for individual fields\n flavor: 'small', // ArrayEditor uses small flavor\n extraClasses: 'form-control',\n onChange: (e: Event) => {\n let value: any;\n const target = e.target as any;\n\n // Handle different field types and their change events\n if (config.type === 'select') {\n // For temba-select, extract the correct value\n if (target.tagName === 'TEMBA-SELECT') {\n if (target.multi || target.emails || target.tags) {\n value = target.values || [];\n } else {\n // Single select: extract value from first selected option\n const values = target.values || [];\n value =\n values.length > 0 && values[0]\n ? values[0].value !== undefined\n ? values[0].value\n : values[0]\n : '';\n }\n } else {\n value = target.value;\n }\n } else {\n // For other field types, use the target value directly\n value = target.value;\n }\n\n this.handleFieldChange(itemIndex, fieldName, value);\n }\n });\n }\n\n renderItem(item: ListItem, index: number): TemplateResult {\n const canRemove = this.canRemoveItem(index);\n\n return html`\n <div class=\"array-item\">\n <div class=\"item-fields\">\n ${Object.entries(this.itemConfig).map(\n ([fieldName, config]) => html`\n <div class=\"field\">\n ${this.renderField(index, fieldName, config)}\n </div>\n `\n )}\n ${canRemove\n ? html`\n <button\n @click=${() => this.removeItem(index)}\n class=\"remove-btn\"\n >\n <temba-icon name=\"x\"></temba-icon>\n </button>\n `\n : ''}\n </div>\n </div>\n `;\n }\n\n protected getContainerClass(): string {\n return 'array-editor';\n }\n\n protected renderAddButton(): TemplateResult {\n return html`\n <button class=\"add-btn\" @click=${() => this.addItem()}>\n Add ${this.itemLabel}\n </button>\n `;\n }\n\n static styles = css`\n .array-editor {\n }\n\n .array-item {\n }\n\n .item-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n\n .item-title {\n font-weight: 600;\n color: #333;\n }\n\n .item-fields {\n display: flex;\n gap: 12px;\n align-items: center;\n }\n\n .field {\n flex: 1;\n }\n\n .field label {\n display: block;\n margin-bottom: 4px;\n font-weight: 500;\n color: #555;\n font-size: 14px;\n }\n\n .add-btn,\n .remove-btn {\n padding: 8px;\n border: 1px solid #ccc;\n border-radius: 4px;\n background: white;\n cursor: pointer;\n font-size: 14px;\n }\n\n .add-btn:hover,\n .remove-btn:hover {\n background: #f8f8f8;\n }\n\n .remove-btn {\n background: #fefefe;\n color: #999;\n }\n `;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ArrayEditor.js","sourceRoot":"","sources":["../../../src/form/ArrayEditor.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, css, TemplateResult } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { FieldConfig, SelectFieldConfig } from '../flow/types';\nimport { BaseListEditor, ListItem } from './BaseListEditor';\nimport { FieldRenderer } from './FieldRenderer';\n\n@customElement('temba-array-editor')\nexport class TembaArrayEditor extends BaseListEditor<ListItem> {\n @property({ type: Object })\n itemConfig: Record<string, FieldConfig> = {};\n\n @property({ type: String })\n itemLabel = 'Item';\n\n @property({ type: Function })\n onItemChange?: (\n itemIndex: number,\n field: string,\n value: any,\n allItems: any[]\n ) => any[];\n\n @property({ type: Function })\n isEmptyItemFn?: (item: any) => boolean;\n\n @property({ type: Boolean })\n maintainEmptyItem = true; // Enable by default for better UX\n\n constructor() {\n super();\n this._items = [];\n }\n\n // External API\n @property({ type: Array })\n get value(): any[] {\n return [...this._items];\n }\n\n set value(newValue: any[]) {\n this._items = newValue || [];\n this.requestUpdate();\n }\n\n // Implement abstract methods\n isEmptyItem(item: ListItem): boolean {\n // Use configurable function if provided\n if (this.isEmptyItemFn) {\n return this.isEmptyItemFn(item);\n }\n\n // Default behavior: check if all values are empty\n const values = Object.values(item);\n if (values.length === 0) {\n return true;\n }\n\n return values.every(\n (value) => value === undefined || value === null || value === ''\n );\n }\n\n // Override cleanItems to be more permissive for form data\n protected cleanItems(items: ListItem[]): any {\n // For runtime attachments, keep items that have at least one non-empty field\n return items.filter((item) => {\n const values = Object.values(item);\n return (\n values.length > 0 &&\n values.some(\n (value) => value !== undefined && value !== null && value !== ''\n )\n );\n });\n }\n\n createEmptyItem(): ListItem {\n return {};\n }\n\n protected handleFieldChange(\n itemIndex: number,\n fieldName: string,\n newValue: any\n ) {\n let updatedItems: any[];\n\n if (this.onItemChange) {\n updatedItems = this.onItemChange(\n itemIndex,\n fieldName,\n newValue,\n this._items\n );\n } else {\n updatedItems = [...this._items];\n updatedItems[itemIndex] = {\n ...updatedItems[itemIndex],\n [fieldName]: newValue\n };\n }\n\n this.updateValue(updatedItems);\n }\n\n private computeFieldValue(\n itemIndex: number,\n fieldName: string,\n config: FieldConfig\n ): any {\n const item = this._items[itemIndex] || {};\n const currentValue = item[fieldName];\n\n if (config.computeValue) {\n return config.computeValue(item, currentValue);\n }\n\n // For select fields, ensure we return the right type\n if (config.type === 'select') {\n const selectConfig = config as SelectFieldConfig;\n if (currentValue === undefined || currentValue === null) {\n return selectConfig.multi ? [] : '';\n }\n }\n\n return currentValue;\n }\n\n private renderArrayField(\n itemIndex: number,\n fieldName: string,\n config: FieldConfig\n ): TemplateResult {\n const computedValue = this.computeFieldValue(itemIndex, fieldName, config);\n\n // Use FieldRenderer for consistent field rendering\n return FieldRenderer.renderField(fieldName, config, computedValue, {\n showLabel: false, // ArrayEditor doesn't show labels for individual fields\n flavor: 'small', // ArrayEditor uses small flavor\n extraClasses: 'form-control',\n onChange: (e: Event) => {\n let value: any;\n const target = e.target as any;\n\n // Handle different field types and their change events\n if (config.type === 'select') {\n // For temba-select, extract the correct value\n if (target.tagName === 'TEMBA-SELECT') {\n if (target.multi || target.emails || target.tags) {\n value = target.values || [];\n } else {\n // Single select: extract value from first selected option\n const values = target.values || [];\n value =\n values.length > 0 && values[0]\n ? values[0].value !== undefined\n ? values[0].value\n : values[0]\n : '';\n }\n } else {\n value = target.value;\n }\n } else {\n // For other field types, use the target value directly\n value = target.value;\n }\n\n this.handleFieldChange(itemIndex, fieldName, value);\n }\n });\n }\n\n renderItem(item: ListItem, index: number): TemplateResult {\n const canRemove = this.canRemoveItem(index);\n\n return html`\n <div class=\"array-item\">\n <div class=\"item-fields\">\n ${Object.entries(this.itemConfig).map(\n ([fieldName, config]) => html`\n <div class=\"field\">\n ${this.renderArrayField(index, fieldName, config)}\n </div>\n `\n )}\n ${canRemove\n ? html`\n <button\n @click=${() => this.removeItem(index)}\n class=\"remove-btn\"\n >\n <temba-icon name=\"x\"></temba-icon>\n </button>\n `\n : ''}\n </div>\n </div>\n `;\n }\n\n protected getContainerClass(): string {\n return 'array-editor';\n }\n\n static get styles() {\n return css`\n ${super.styles}\n\n .array-editor {\n }\n\n .array-item {\n }\n\n .item-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n\n .item-title {\n font-weight: 600;\n color: #333;\n }\n\n .item-fields {\n display: flex;\n gap: 12px;\n align-items: center;\n }\n\n .field {\n flex: 1;\n }\n\n .add-btn,\n .remove-btn {\n padding: 8px;\n border: 1px solid #ccc;\n border-radius: 4px;\n background: white;\n cursor: pointer;\n font-size: 14px;\n }\n\n .add-btn:hover,\n .remove-btn:hover {\n background: #f8f8f8;\n }\n\n .remove-btn {\n background: #fefefe;\n color: #999;\n }\n `;\n }\n}\n"]}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { __decorate } from "tslib";
|
|
2
|
-
import {
|
|
2
|
+
import { html } from 'lit';
|
|
3
3
|
import { property } from 'lit/decorators.js';
|
|
4
|
-
|
|
4
|
+
import { FieldElement } from './FieldElement';
|
|
5
|
+
export class BaseListEditor extends FieldElement {
|
|
5
6
|
constructor() {
|
|
6
7
|
super(...arguments);
|
|
7
8
|
this._items = [];
|
|
@@ -24,7 +25,7 @@ export class BaseListEditor extends LitElement {
|
|
|
24
25
|
}
|
|
25
26
|
return !this.maxItems || this._items.length < this.maxItems;
|
|
26
27
|
}
|
|
27
|
-
|
|
28
|
+
renderWidget() {
|
|
28
29
|
const items = this.displayItems;
|
|
29
30
|
return html `
|
|
30
31
|
<div class=${this.getContainerClass()}>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseListEditor.js","sourceRoot":"","sources":["../../../src/form/BaseListEditor.ts"],"names":[],"mappings":";AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"BaseListEditor.js","sourceRoot":"","sources":["../../../src/form/BaseListEditor.ts"],"names":[],"mappings":"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","sourcesContent":["import { TemplateResult, html } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { FieldElement } from './FieldElement';\n\nexport interface ListItem {\n [key: string]: any;\n}\n\nexport interface ListEditorConfig {\n // Determines if empty items should be automatically maintained\n maintainEmptyItem?: boolean;\n // Function to check if an item is considered empty\n isEmptyItem?: (item: ListItem) => boolean;\n // Function to create a new empty item\n createEmptyItem?: () => ListItem;\n // Function to clean items before emitting (e.g., filter out empty items)\n cleanItems?: (items: ListItem[]) => ListItem[];\n // Minimum number of items to maintain\n minItems?: number;\n // Maximum number of items allowed\n maxItems?: number;\n}\n\nexport abstract class BaseListEditor<\n T extends ListItem = ListItem\n> extends FieldElement {\n @property({ attribute: false })\n protected _items: T[] = [];\n\n @property({ type: Number })\n minItems = 0;\n\n @property({ type: Number })\n maxItems?: number;\n\n @property({ type: Boolean })\n maintainEmptyItem = false;\n\n // Abstract methods that must be implemented by subclasses\n abstract isEmptyItem(item: T): boolean;\n abstract createEmptyItem(): T;\n abstract renderItem(item: T, index: number): TemplateResult;\n\n // Optional methods that subclasses can override\n protected getContainerClass(): string {\n return 'base-list-editor';\n }\n\n protected renderAddButton(): TemplateResult {\n return html`\n <button class=\"add-btn\" @click=${() => this.addItem()}>Add Item</button>\n `;\n }\n\n protected shouldShowAddButton(): boolean {\n // Never show add button when maintaining empty items (auto-add behavior)\n if (this.maintainEmptyItem) {\n return false;\n }\n\n return !this.maxItems || this._items.length < this.maxItems;\n }\n\n renderWidget(): TemplateResult {\n const items = this.displayItems;\n return html`\n <div class=${this.getContainerClass()}>\n <div\n class=\"list-items\"\n style=\"display: grid; grid-template-columns: 1fr; gap: 8px;\"\n >\n ${items.map((item, index) => this.renderItem(item, index))}\n </div>\n ${this.shouldShowAddButton() ? this.renderAddButton() : ''}\n </div>\n `;\n }\n\n // Optional method for cleaning items before emission (can return any type)\n protected cleanItems(items: T[]): any {\n if (!this.maintainEmptyItem) {\n return items;\n }\n // Filter out empty items for the emitted value\n return items.filter((item) => !this.isEmptyItem(item));\n }\n\n // Get the items to display (may include empty items for UI)\n protected get displayItems(): T[] {\n const items = [...this._items];\n\n if (this.maintainEmptyItem) {\n const hasEmptyItem = items.some((item) => this.isEmptyItem(item));\n // Only add empty item if we haven't reached maxItems and don't already have an empty item\n if (!hasEmptyItem && (!this.maxItems || items.length < this.maxItems)) {\n items.push(this.createEmptyItem());\n }\n }\n\n return items;\n }\n\n // Handle changes to an item\n protected handleItemChange(index: number, newItem: T) {\n const updatedItems = [...this._items];\n updatedItems[index] = newItem;\n this.updateValue(updatedItems);\n }\n\n // Handle field changes within an item (for complex items)\n protected handleFieldChange(\n index: number,\n fieldName: string,\n fieldValue: any\n ) {\n const updatedItems = [...this._items];\n\n // If editing beyond the current array (auto-generated empty row), check maxItems\n if (index >= this._items.length) {\n if (this.maxItems && this._items.length >= this.maxItems) {\n // Don't allow adding new items if we've reached maxItems\n return;\n }\n // Extend the array to include the new item\n while (updatedItems.length <= index) {\n updatedItems.push(this.createEmptyItem());\n }\n }\n\n const currentItem = updatedItems[index] || this.createEmptyItem();\n\n updatedItems[index] = {\n ...currentItem,\n [fieldName]: fieldValue\n };\n\n this.updateValue(updatedItems);\n }\n\n // Add a new item\n protected addItem(item?: T) {\n if (this.maxItems && this._items.length >= this.maxItems) {\n return;\n }\n\n const newItem = item || this.createEmptyItem();\n const updatedItems = [...this._items, newItem];\n this.updateValue(updatedItems);\n }\n\n // Remove an item\n protected removeItem(index: number) {\n if (this._items.length <= this.minItems) {\n return;\n }\n\n const updatedItems = this._items.filter((_, i) => i !== index);\n this.updateValue(updatedItems);\n }\n\n // Check if an item can be removed\n protected canRemoveItem(index: number): boolean {\n const item = this.displayItems[index];\n\n // Can't remove if it would go below minimum\n if (this._items.length <= this.minItems) {\n return false;\n }\n\n // Can't remove empty items if we're maintaining them\n if (this.maintainEmptyItem && this.isEmptyItem(item)) {\n return false;\n }\n\n return true;\n }\n\n // Update the value and emit change event\n protected updateValue(newValue: T[]) {\n this._items = newValue;\n this.dispatchEvent(\n new CustomEvent('change', {\n detail: { value: this.cleanItems(newValue) },\n bubbles: true\n })\n );\n }\n\n // Utility method for subclasses to check if two items are equal\n protected itemsEqual(item1: T, item2: T): boolean {\n return JSON.stringify(item1) === JSON.stringify(item2);\n }\n}\n"]}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { __decorate } from "tslib";
|
|
2
2
|
import { html, css } from 'lit';
|
|
3
|
-
import {
|
|
3
|
+
import { FieldElement } from './FieldElement';
|
|
4
4
|
import { property } from 'lit/decorators.js';
|
|
5
5
|
import { Icon } from '../Icons';
|
|
6
|
-
|
|
6
|
+
import { renderMarkdownInline } from '../markdown';
|
|
7
|
+
export class Checkbox extends FieldElement {
|
|
7
8
|
constructor() {
|
|
8
9
|
super(...arguments);
|
|
9
10
|
this.name = '';
|
|
@@ -13,6 +14,8 @@ export class Checkbox extends FormElement {
|
|
|
13
14
|
}
|
|
14
15
|
static get styles() {
|
|
15
16
|
return css `
|
|
17
|
+
${super.styles}
|
|
18
|
+
|
|
16
19
|
:host {
|
|
17
20
|
color: var(--color-text);
|
|
18
21
|
display: inline-block;
|
|
@@ -31,25 +34,45 @@ export class Checkbox extends FormElement {
|
|
|
31
34
|
background: var(--checkbox-hover-bg, #f9f9f9);
|
|
32
35
|
}
|
|
33
36
|
|
|
34
|
-
temba-field {
|
|
35
|
-
--help-text-margin-left: 24px;
|
|
36
|
-
cursor: pointer;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
37
|
.checkbox-container {
|
|
40
38
|
cursor: pointer;
|
|
41
39
|
display: flex;
|
|
40
|
+
align-items: flex-start;
|
|
42
41
|
user-select: none;
|
|
43
42
|
-webkit-user-select: none;
|
|
44
43
|
}
|
|
45
44
|
|
|
45
|
+
.checkbox-container temba-icon {
|
|
46
|
+
align-self: flex-start;
|
|
47
|
+
vertical-align: top;
|
|
48
|
+
line-height: 1;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.label-and-help {
|
|
52
|
+
flex-grow: 1;
|
|
53
|
+
margin-left: 8px;
|
|
54
|
+
}
|
|
55
|
+
|
|
46
56
|
.checkbox-label {
|
|
47
57
|
font-family: var(--font-family);
|
|
48
58
|
padding: 0px;
|
|
49
|
-
margin
|
|
59
|
+
margin: 0px;
|
|
50
60
|
font-size: 14px;
|
|
51
61
|
line-height: 19px;
|
|
52
|
-
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.checkbox-help-text {
|
|
65
|
+
font-family: var(--font-family);
|
|
66
|
+
font-size: var(--help-text-size, 0.85em);
|
|
67
|
+
line-height: normal;
|
|
68
|
+
color: var(--color-text-help);
|
|
69
|
+
margin-top: 4px;
|
|
70
|
+
opacity: 1;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* Checkbox help text should align with the checkbox icon, not indented */
|
|
74
|
+
.help-text {
|
|
75
|
+
margin-left: 0;
|
|
53
76
|
}
|
|
54
77
|
|
|
55
78
|
.far {
|
|
@@ -103,7 +126,7 @@ export class Checkbox extends FormElement {
|
|
|
103
126
|
this.handleClick();
|
|
104
127
|
super.click();
|
|
105
128
|
}
|
|
106
|
-
|
|
129
|
+
renderWidget() {
|
|
107
130
|
const icon = html `<temba-icon
|
|
108
131
|
name="${this.checked
|
|
109
132
|
? Icon.checkbox_checked
|
|
@@ -112,28 +135,58 @@ export class Checkbox extends FormElement {
|
|
|
112
135
|
: Icon.checkbox}"
|
|
113
136
|
size="${this.size}"
|
|
114
137
|
animatechange="${this.animateChange}"
|
|
115
|
-
|
|
138
|
+
></temba-icon>`;
|
|
116
139
|
return html `
|
|
117
|
-
<div
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
?disabled=${this.disabled}
|
|
125
|
-
@click=${this.handleClick}
|
|
126
|
-
>
|
|
127
|
-
<div class="checkbox-container ${this.disabled ? 'disabled' : ''}">
|
|
128
|
-
${icon}
|
|
140
|
+
<div
|
|
141
|
+
class="wrapper ${this.label ? 'label' : ''}"
|
|
142
|
+
@click=${this.handleClick}
|
|
143
|
+
>
|
|
144
|
+
<div class="checkbox-container ${this.disabled ? 'disabled' : ''}">
|
|
145
|
+
${icon}
|
|
146
|
+
<div class="label-and-help">
|
|
129
147
|
${this.label && String(this.label).trim()
|
|
130
148
|
? html `<div class="checkbox-label">${this.label}</div>`
|
|
131
149
|
: null}
|
|
150
|
+
${this.helpText && this.helpText !== 'None'
|
|
151
|
+
? html ` <div class="checkbox-help-text">${this.helpText}</div> `
|
|
152
|
+
: null}
|
|
132
153
|
</div>
|
|
133
|
-
</
|
|
154
|
+
</div>
|
|
134
155
|
</div>
|
|
135
156
|
`;
|
|
136
157
|
}
|
|
158
|
+
renderField() {
|
|
159
|
+
// Use standard FieldElement behavior but skip the field label since checkbox renders its own inline
|
|
160
|
+
const hasErrors = !this.hideErrors && this.errors && this.errors.length > 0;
|
|
161
|
+
const errors = hasErrors
|
|
162
|
+
? this.errors.map((error) => {
|
|
163
|
+
return html `
|
|
164
|
+
<div class="alert-error">${renderMarkdownInline(error)}</div>
|
|
165
|
+
`;
|
|
166
|
+
})
|
|
167
|
+
: [];
|
|
168
|
+
if (this.widgetOnly) {
|
|
169
|
+
return html `
|
|
170
|
+
<div class="${this.disabled ? 'disabled' : ''}">
|
|
171
|
+
${this.renderWidget()}
|
|
172
|
+
</div>
|
|
173
|
+
${errors}
|
|
174
|
+
`;
|
|
175
|
+
}
|
|
176
|
+
// This matches FieldElement.renderField() but without the field label
|
|
177
|
+
return html `
|
|
178
|
+
<div
|
|
179
|
+
class="field ${this.disabled ? 'disabled' : ''} ${hasErrors
|
|
180
|
+
? 'has-error'
|
|
181
|
+
: ''}"
|
|
182
|
+
>
|
|
183
|
+
<div class="widget">${this.renderWidget()} ${errors}</div>
|
|
184
|
+
</div>
|
|
185
|
+
`;
|
|
186
|
+
}
|
|
187
|
+
render() {
|
|
188
|
+
return this.renderField();
|
|
189
|
+
}
|
|
137
190
|
}
|
|
138
191
|
__decorate([
|
|
139
192
|
property({ type: String })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Checkbox.js","sourceRoot":"","sources":["../../../src/form/Checkbox.ts"],"names":[],"mappings":";AAAA,OAAO,EAAkB,IAAI,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAChD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"Checkbox.js","sourceRoot":"","sources":["../../../src/form/Checkbox.ts"],"names":[],"mappings":"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","sourcesContent":["import { TemplateResult, html, css } from 'lit';\nimport { FieldElement } from './FieldElement';\nimport { property } from 'lit/decorators.js';\nimport { Icon } from '../Icons';\nimport { renderMarkdownInline } from '../markdown';\n\nexport class Checkbox extends FieldElement {\n static get styles() {\n return css`\n ${super.styles}\n\n :host {\n color: var(--color-text);\n display: inline-block;\n }\n\n :host([label]) {\n width: 100%;\n }\n\n .wrapper.label {\n padding: var(--checkbox-padding, 10px);\n border-radius: var(--curvature);\n }\n\n .wrapper.label:hover {\n background: var(--checkbox-hover-bg, #f9f9f9);\n }\n\n .checkbox-container {\n cursor: pointer;\n display: flex;\n align-items: flex-start;\n user-select: none;\n -webkit-user-select: none;\n }\n\n .checkbox-container temba-icon {\n align-self: flex-start;\n vertical-align: top;\n line-height: 1;\n }\n\n .label-and-help {\n flex-grow: 1;\n margin-left: 8px;\n }\n\n .checkbox-label {\n font-family: var(--font-family);\n padding: 0px;\n margin: 0px;\n font-size: 14px;\n line-height: 19px;\n }\n\n .checkbox-help-text {\n font-family: var(--font-family);\n font-size: var(--help-text-size, 0.85em);\n line-height: normal;\n color: var(--color-text-help);\n margin-top: 4px;\n opacity: 1;\n }\n\n /* Checkbox help text should align with the checkbox icon, not indented */\n .help-text {\n margin-left: 0;\n }\n\n .far {\n height: 16px;\n margin-top: 1px;\n }\n\n .disabled {\n cursor: not-allowed;\n --icon-color: #ccc;\n }\n `;\n }\n\n @property({ type: String })\n name = '';\n\n @property({ type: Boolean })\n checked: boolean;\n\n @property({ type: Boolean })\n partial: boolean;\n\n @property({ type: Boolean })\n disabled = false;\n\n @property({ type: Number })\n size = 1.2;\n\n @property({ type: String })\n animateChange = 'pulse';\n\n public connectedCallback() {\n super.connectedCallback();\n }\n\n public updated(changes: Map<string, any>) {\n super.updated(changes);\n\n // Normalize label property changes\n if (changes.has('label')) {\n // Normalize whitespace labels to empty string for proper behavior\n if (\n this.label &&\n typeof this.label === 'string' &&\n this.label.trim() === ''\n ) {\n this.label = '';\n }\n // Ensure undefined labels remain as null to match test expectations\n if (this.label === undefined) {\n this.label = null;\n }\n }\n\n if (changes.has('checked') || changes.has('value')) {\n if (this.checked || this.partial) {\n this.internals.setFormValue(this.value || '1');\n } else {\n this.internals.setFormValue(undefined);\n }\n this.fireEvent('change');\n }\n }\n\n public serializeValue(value: any): string {\n return value;\n }\n\n private handleClick(): void {\n if (!this.disabled) {\n this.checked = !this.checked;\n }\n }\n\n public click(): void {\n this.handleClick();\n super.click();\n }\n\n protected renderWidget(): TemplateResult {\n const icon = html`<temba-icon\n name=\"${this.checked\n ? Icon.checkbox_checked\n : this.partial\n ? Icon.checkbox_partial\n : Icon.checkbox}\"\n size=\"${this.size}\"\n animatechange=\"${this.animateChange}\"\n ></temba-icon>`;\n\n return html`\n <div\n class=\"wrapper ${this.label ? 'label' : ''}\"\n @click=${this.handleClick}\n >\n <div class=\"checkbox-container ${this.disabled ? 'disabled' : ''}\">\n ${icon}\n <div class=\"label-and-help\">\n ${this.label && String(this.label).trim()\n ? html`<div class=\"checkbox-label\">${this.label}</div>`\n : null}\n ${this.helpText && this.helpText !== 'None'\n ? html` <div class=\"checkbox-help-text\">${this.helpText}</div> `\n : null}\n </div>\n </div>\n </div>\n `;\n }\n\n protected renderField(): TemplateResult {\n // Use standard FieldElement behavior but skip the field label since checkbox renders its own inline\n const hasErrors = !this.hideErrors && this.errors && this.errors.length > 0;\n const errors = hasErrors\n ? this.errors.map((error: string) => {\n return html`\n <div class=\"alert-error\">${renderMarkdownInline(error)}</div>\n `;\n })\n : [];\n\n if (this.widgetOnly) {\n return html`\n <div class=\"${this.disabled ? 'disabled' : ''}\">\n ${this.renderWidget()}\n </div>\n ${errors}\n `;\n }\n\n // This matches FieldElement.renderField() but without the field label\n return html`\n <div\n class=\"field ${this.disabled ? 'disabled' : ''} ${hasErrors\n ? 'has-error'\n : ''}\"\n >\n <div class=\"widget\">${this.renderWidget()} ${errors}</div>\n </div>\n `;\n }\n\n public render(): TemplateResult {\n return this.renderField();\n }\n}\n"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { __decorate } from "tslib";
|
|
2
2
|
import { html, css } from 'lit';
|
|
3
|
-
import {
|
|
3
|
+
import { FieldElement } from './FieldElement';
|
|
4
4
|
import { property } from 'lit/decorators.js';
|
|
5
5
|
import { getClasses, hslToHex } from '../utils';
|
|
6
|
-
export class ColorPicker extends
|
|
6
|
+
export class ColorPicker extends FieldElement {
|
|
7
7
|
constructor() {
|
|
8
8
|
super(...arguments);
|
|
9
9
|
this.expanded = false;
|
|
@@ -16,6 +16,8 @@ export class ColorPicker extends FormElement {
|
|
|
16
16
|
}
|
|
17
17
|
static get styles() {
|
|
18
18
|
return css `
|
|
19
|
+
${super.styles}
|
|
20
|
+
|
|
19
21
|
:host {
|
|
20
22
|
color: var(--color-text);
|
|
21
23
|
display: inline-block;
|
|
@@ -30,11 +32,6 @@ export class ColorPicker extends FormElement {
|
|
|
30
32
|
width: 5em;
|
|
31
33
|
}
|
|
32
34
|
|
|
33
|
-
temba-field {
|
|
34
|
-
display: block;
|
|
35
|
-
width: 100%;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
35
|
.wrapper {
|
|
39
36
|
border: 1px solid var(--color-widget-border);
|
|
40
37
|
padding: calc(var(--curvature) / 2);
|
|
@@ -197,46 +194,37 @@ export class ColorPicker extends FormElement {
|
|
|
197
194
|
serializeValue(value) {
|
|
198
195
|
return value;
|
|
199
196
|
}
|
|
200
|
-
|
|
197
|
+
renderWidget() {
|
|
201
198
|
return html `
|
|
202
|
-
<
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
.hideLabel=${this.hideLabel}
|
|
208
|
-
.disabled=${this.disabled}
|
|
209
|
-
>
|
|
210
|
-
<div style="display:flex" tabindex="0">
|
|
211
|
-
<div class=${getClasses({ wrapper: true, expanded: this.expanded })}>
|
|
212
|
-
<div class=${getClasses({ 'picker-wrapper': true })}>
|
|
213
|
-
<div
|
|
214
|
-
class=${getClasses({
|
|
199
|
+
<div style="display:flex" tabindex="0">
|
|
200
|
+
<div class=${getClasses({ wrapper: true, expanded: this.expanded })}>
|
|
201
|
+
<div class=${getClasses({ 'picker-wrapper': true })}>
|
|
202
|
+
<div
|
|
203
|
+
class=${getClasses({
|
|
215
204
|
preview: true,
|
|
216
205
|
selecting: this.selecting
|
|
217
206
|
})}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
</div>
|
|
223
|
-
<div
|
|
224
|
-
class="color-picker"
|
|
225
|
-
tabindex="0"
|
|
226
|
-
@blur=${this.handleBlur}
|
|
227
|
-
@mousemove=${this.handleMouseMove}
|
|
228
|
-
@mouseout=${this.handleMouseOut}
|
|
229
|
-
@click=${this.handleColorClick}
|
|
230
|
-
></div>
|
|
207
|
+
style="color:${this.labelColor};background:${this.previewColor}"
|
|
208
|
+
@click=${this.handlePreviewClick}
|
|
209
|
+
>
|
|
210
|
+
${this.label}
|
|
231
211
|
</div>
|
|
232
|
-
<
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
212
|
+
<div
|
|
213
|
+
class="color-picker"
|
|
214
|
+
tabindex="0"
|
|
215
|
+
@blur=${this.handleBlur}
|
|
216
|
+
@mousemove=${this.handleMouseMove}
|
|
217
|
+
@mouseout=${this.handleMouseOut}
|
|
218
|
+
@click=${this.handleColorClick}
|
|
219
|
+
></div>
|
|
237
220
|
</div>
|
|
221
|
+
<temba-textinput
|
|
222
|
+
value=${this.hex}
|
|
223
|
+
@input=${this.handleHexInput}
|
|
224
|
+
placeholder="#000000"
|
|
225
|
+
></temba-textinput>
|
|
238
226
|
</div>
|
|
239
|
-
</
|
|
227
|
+
</div>
|
|
240
228
|
`;
|
|
241
229
|
}
|
|
242
230
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ColorPicker.js","sourceRoot":"","sources":["../../../src/form/ColorPicker.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, css, PropertyValueMap } from 'lit';\nimport { FormElement } from './FormElement';\nimport { property } from 'lit/decorators.js';\nimport { getClasses, hslToHex } from '../utils';\nimport { TextInput } from './TextInput';\n\nexport class ColorPicker extends FormElement {\n @property({ type: Boolean })\n expanded = false;\n\n @property({ type: String })\n previewColor = '#ffffff';\n\n @property({ type: String })\n labelColor = '#ffffffee';\n\n @property({ type: Boolean })\n selecting = false;\n\n @property({ type: Number }) hue: number;\n @property({ type: Number }) saturation = 100;\n @property({ type: Number }) lightness = 50;\n @property({ type: String }) hex = '';\n\n static get styles() {\n return css`\n :host {\n color: var(--color-text);\n display: inline-block;\n --curvature: 0.55em;\n width: 100%;\n\n --temba-textinput-padding: 0.4em;\n }\n\n temba-textinput {\n margin-left: 0.3em;\n width: 5em;\n }\n\n temba-field {\n display: block;\n width: 100%;\n }\n\n .wrapper {\n border: 1px solid var(--color-widget-border);\n padding: calc(var(--curvature) / 2);\n border-radius: calc(var(--curvature) * 1.5);\n transition: all calc(var(--transition-speed) * 2) var(--bounce);\n\n display: flex;\n flex-grow: 0;\n }\n\n .picker-wrapper {\n display: flex;\n flex-direction: row;\n align-items: stretch;\n transition: all calc(var(--transition-speed) * 2) var(--bounce);\n flex-grow: 0;\n }\n\n .preview {\n width: initial;\n border-radius: var(--curvature);\n padding: 0.2em 0.5em;\n font-weight: 400;\n border: 2px solid rgba(0, 0, 0, 0.1);\n white-space: nowrap;\n cursor: pointer;\n transition: transform calc(var(--transition-speed) * 0.5) var(--bounce);\n }\n\n .preview.selecting {\n transform: scale(1.05);\n }\n\n .wrapper.expanded {\n flex-grow: 1 !important;\n }\n\n .wrapper.expanded .picker-wrapper {\n flex-grow: 1 !important;\n }\n\n .wrapper.expanded .preview {\n pointer-events: none;\n }\n\n .wrapper.expanded .color-picker {\n margin-left: calc(var(--curvature) / 2);\n }\n\n .wrapper.expanded temba-textinput {\n display: block;\n }\n\n .color-picker {\n border-radius: var(--curvature);\n cursor: pointer;\n transition: all calc(var(--transition-speed) * 2) var(--bounce);\n flex-grow: 1;\n position: relative;\n width: 100%;\n height: 100%;\n background-image: linear-gradient(\n to bottom,\n rgba(0, 0, 0, 0) 60%,\n rgba(0, 0, 0, 0.5) 90%,\n rgba(0, 0, 0, 1)\n ),\n linear-gradient(\n to top,\n rgba(255, 255, 255, 0) 60%,\n rgba(255, 255, 255, 0.8) 90%,\n rgba(255, 255, 255, 1)\n ),\n linear-gradient(\n to right,\n hsla(0, 100%, 50%, 1),\n hsla(60, 100%, 50%, 1),\n hsla(120, 100%, 50%, 1),\n hsla(180, 100%, 50%, 1),\n hsla(240, 100%, 50%, 1),\n hsla(300, 100%, 50%, 1),\n hsla(360, 100%, 50%, 1)\n );\n mix-blend-mode: multiply;\n }\n\n .color-picker:focus {\n outline: none;\n }\n `;\n }\n\n protected firstUpdated(\n _changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.firstUpdated(_changedProperties);\n }\n\n public updated(changed: Map<string, any>): void {\n super.updated(changed);\n\n if (changed.has('value')) {\n this.previewColor = this.value || '#9c9c9c';\n this.hex = this.value;\n }\n\n if (changed.has('selecting')) {\n if (this.selecting) {\n window.setTimeout(() => {\n this.selecting = false;\n }, 100);\n }\n }\n\n if (changed.has('previewLabel') && this.hue) {\n this.hex = hslToHex(this.hue, this.saturation, this.lightness);\n }\n }\n\n private handleBlur() {\n if (this.expanded) {\n this.expanded = false;\n }\n }\n\n private handleMouseOut() {\n this.previewColor = this.value;\n this.hex = this.value;\n }\n\n private handleMouseMove(event: MouseEvent) {\n if (this.expanded) {\n const rect = (event.target as HTMLElement).getBoundingClientRect();\n const x = event.clientX - rect.left;\n const y = event.clientY - rect.top;\n this.hue = (x / rect.width) * 360;\n this.lightness = 100 - (y / rect.height) * 100;\n this.previewColor = `hsla(${this.hue}, ${this.saturation}%, ${this.lightness}%, 1)`;\n this.hex = hslToHex(this.hue, this.saturation, this.lightness);\n }\n }\n\n private handlePreviewClick() {\n this.expanded = !this.expanded;\n this.selecting = true;\n (this.shadowRoot.querySelector('.color-picker') as HTMLDivElement).focus();\n }\n\n private handleColorClick(event: MouseEvent) {\n if (this.expanded) {\n const rect = (event.target as HTMLElement).getBoundingClientRect();\n const x = event.clientX - rect.left;\n const y = event.clientY - rect.top;\n this.hue = (x / rect.width) * 360;\n this.lightness = 100 - (y / rect.height) * 100;\n this.previewColor = `hsla(${this.hue}, ${this.saturation}%, ${this.lightness}%, 1)`;\n this.value = this.hex;\n this.selecting = true;\n this.expanded = false;\n }\n\n if (!this.expanded) {\n //\n }\n }\n\n private handleHexInput(event: InputEvent) {\n const hex = (event.target as TextInput).value;\n if (hex.startsWith('#')) {\n this.previewColor = hex;\n this.value = hex;\n }\n }\n\n public serializeValue(value: any): string {\n return value;\n }\n\n public render() {\n return html`\n <temba-field\n name=${this.name}\n .helpText=${this.helpText}\n .errors=${this.errors}\n .widgetOnly=${this.widgetOnly}\n .hideLabel=${this.hideLabel}\n .disabled=${this.disabled}\n >\n <div style=\"display:flex\" tabindex=\"0\">\n <div class=${getClasses({ wrapper: true, expanded: this.expanded })}>\n <div class=${getClasses({ 'picker-wrapper': true })}>\n <div\n class=${getClasses({\n preview: true,\n selecting: this.selecting\n })}\n style=\"color:${this.labelColor};background:${this.previewColor}\"\n @click=${this.handlePreviewClick}\n >\n ${this.label}\n </div>\n <div\n class=\"color-picker\"\n tabindex=\"0\"\n @blur=${this.handleBlur}\n @mousemove=${this.handleMouseMove}\n @mouseout=${this.handleMouseOut}\n @click=${this.handleColorClick}\n ></div>\n </div>\n <temba-textinput\n value=${this.hex}\n @input=${this.handleHexInput}\n placeholder=\"#000000\"\n ></temba-textinput>\n </div>\n </div>\n </temba-field>\n `;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ColorPicker.js","sourceRoot":"","sources":["../../../src/form/ColorPicker.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, css, PropertyValueMap } from 'lit';\nimport { FieldElement } from './FieldElement';\nimport { property } from 'lit/decorators.js';\nimport { getClasses, hslToHex } from '../utils';\nimport { TextInput } from './TextInput';\n\nexport class ColorPicker extends FieldElement {\n @property({ type: Boolean })\n expanded = false;\n\n @property({ type: String })\n previewColor = '#ffffff';\n\n @property({ type: String })\n labelColor = '#ffffffee';\n\n @property({ type: Boolean })\n selecting = false;\n\n @property({ type: Number }) hue: number;\n @property({ type: Number }) saturation = 100;\n @property({ type: Number }) lightness = 50;\n @property({ type: String }) hex = '';\n\n static get styles() {\n return css`\n ${super.styles}\n\n :host {\n color: var(--color-text);\n display: inline-block;\n --curvature: 0.55em;\n width: 100%;\n\n --temba-textinput-padding: 0.4em;\n }\n\n temba-textinput {\n margin-left: 0.3em;\n width: 5em;\n }\n\n .wrapper {\n border: 1px solid var(--color-widget-border);\n padding: calc(var(--curvature) / 2);\n border-radius: calc(var(--curvature) * 1.5);\n transition: all calc(var(--transition-speed) * 2) var(--bounce);\n\n display: flex;\n flex-grow: 0;\n }\n\n .picker-wrapper {\n display: flex;\n flex-direction: row;\n align-items: stretch;\n transition: all calc(var(--transition-speed) * 2) var(--bounce);\n flex-grow: 0;\n }\n\n .preview {\n width: initial;\n border-radius: var(--curvature);\n padding: 0.2em 0.5em;\n font-weight: 400;\n border: 2px solid rgba(0, 0, 0, 0.1);\n white-space: nowrap;\n cursor: pointer;\n transition: transform calc(var(--transition-speed) * 0.5) var(--bounce);\n }\n\n .preview.selecting {\n transform: scale(1.05);\n }\n\n .wrapper.expanded {\n flex-grow: 1 !important;\n }\n\n .wrapper.expanded .picker-wrapper {\n flex-grow: 1 !important;\n }\n\n .wrapper.expanded .preview {\n pointer-events: none;\n }\n\n .wrapper.expanded .color-picker {\n margin-left: calc(var(--curvature) / 2);\n }\n\n .wrapper.expanded temba-textinput {\n display: block;\n }\n\n .color-picker {\n border-radius: var(--curvature);\n cursor: pointer;\n transition: all calc(var(--transition-speed) * 2) var(--bounce);\n flex-grow: 1;\n position: relative;\n width: 100%;\n height: 100%;\n background-image: linear-gradient(\n to bottom,\n rgba(0, 0, 0, 0) 60%,\n rgba(0, 0, 0, 0.5) 90%,\n rgba(0, 0, 0, 1)\n ),\n linear-gradient(\n to top,\n rgba(255, 255, 255, 0) 60%,\n rgba(255, 255, 255, 0.8) 90%,\n rgba(255, 255, 255, 1)\n ),\n linear-gradient(\n to right,\n hsla(0, 100%, 50%, 1),\n hsla(60, 100%, 50%, 1),\n hsla(120, 100%, 50%, 1),\n hsla(180, 100%, 50%, 1),\n hsla(240, 100%, 50%, 1),\n hsla(300, 100%, 50%, 1),\n hsla(360, 100%, 50%, 1)\n );\n mix-blend-mode: multiply;\n }\n\n .color-picker:focus {\n outline: none;\n }\n `;\n }\n\n protected firstUpdated(\n _changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.firstUpdated(_changedProperties);\n }\n\n public updated(changed: Map<string, any>): void {\n super.updated(changed);\n\n if (changed.has('value')) {\n this.previewColor = this.value || '#9c9c9c';\n this.hex = this.value;\n }\n\n if (changed.has('selecting')) {\n if (this.selecting) {\n window.setTimeout(() => {\n this.selecting = false;\n }, 100);\n }\n }\n\n if (changed.has('previewLabel') && this.hue) {\n this.hex = hslToHex(this.hue, this.saturation, this.lightness);\n }\n }\n\n private handleBlur() {\n if (this.expanded) {\n this.expanded = false;\n }\n }\n\n private handleMouseOut() {\n this.previewColor = this.value;\n this.hex = this.value;\n }\n\n private handleMouseMove(event: MouseEvent) {\n if (this.expanded) {\n const rect = (event.target as HTMLElement).getBoundingClientRect();\n const x = event.clientX - rect.left;\n const y = event.clientY - rect.top;\n this.hue = (x / rect.width) * 360;\n this.lightness = 100 - (y / rect.height) * 100;\n this.previewColor = `hsla(${this.hue}, ${this.saturation}%, ${this.lightness}%, 1)`;\n this.hex = hslToHex(this.hue, this.saturation, this.lightness);\n }\n }\n\n private handlePreviewClick() {\n this.expanded = !this.expanded;\n this.selecting = true;\n (this.shadowRoot.querySelector('.color-picker') as HTMLDivElement).focus();\n }\n\n private handleColorClick(event: MouseEvent) {\n if (this.expanded) {\n const rect = (event.target as HTMLElement).getBoundingClientRect();\n const x = event.clientX - rect.left;\n const y = event.clientY - rect.top;\n this.hue = (x / rect.width) * 360;\n this.lightness = 100 - (y / rect.height) * 100;\n this.previewColor = `hsla(${this.hue}, ${this.saturation}%, ${this.lightness}%, 1)`;\n this.value = this.hex;\n this.selecting = true;\n this.expanded = false;\n }\n\n if (!this.expanded) {\n //\n }\n }\n\n private handleHexInput(event: InputEvent) {\n const hex = (event.target as TextInput).value;\n if (hex.startsWith('#')) {\n this.previewColor = hex;\n this.value = hex;\n }\n }\n\n public serializeValue(value: any): string {\n return value;\n }\n\n protected renderWidget() {\n return html`\n <div style=\"display:flex\" tabindex=\"0\">\n <div class=${getClasses({ wrapper: true, expanded: this.expanded })}>\n <div class=${getClasses({ 'picker-wrapper': true })}>\n <div\n class=${getClasses({\n preview: true,\n selecting: this.selecting\n })}\n style=\"color:${this.labelColor};background:${this.previewColor}\"\n @click=${this.handlePreviewClick}\n >\n ${this.label}\n </div>\n <div\n class=\"color-picker\"\n tabindex=\"0\"\n @blur=${this.handleBlur}\n @mousemove=${this.handleMouseMove}\n @mouseout=${this.handleMouseOut}\n @click=${this.handleColorClick}\n ></div>\n </div>\n <temba-textinput\n value=${this.hex}\n @input=${this.handleHexInput}\n placeholder=\"#000000\"\n ></temba-textinput>\n </div>\n </div>\n `;\n }\n}\n"]}
|