diff --git a/src/components/dt-base.js b/src/components/dt-base.js index 5f30338..85fc39c 100644 --- a/src/components/dt-base.js +++ b/src/components/dt-base.js @@ -18,6 +18,7 @@ export default class DtBase extends LitElement { `, ]; } + static get properties() { return { /** diff --git a/src/components/form/dt-church-health-circle/dt-church-health-circle.js b/src/components/form/dt-church-health-circle/dt-church-health-circle.js index 91a432f..5e29863 100644 --- a/src/components/form/dt-church-health-circle/dt-church-health-circle.js +++ b/src/components/form/dt-church-health-circle/dt-church-health-circle.js @@ -5,6 +5,7 @@ import { DtMultiSelect } from '../dt-multi-select/dt-multi-select.js'; import './dt-church-health-circle-icon.js'; import '../dt-toggle/dt-toggle.js'; + export class DtChurchHealthCircle extends DtMultiSelect { static get styles() { return [ @@ -63,6 +64,9 @@ export class DtChurchHealthCircle extends DtMultiSelect { .health-circle--disabled dt-church-health-icon { cursor: not-allowed; } + .health-circle--readonly dt-church-health-icon { + cursor: not-allowed; + } dt-church-health-icon { position: absolute; @@ -81,6 +85,12 @@ export class DtChurchHealthCircle extends DtMultiSelect { transform: rotate(var(--az)) translate(var(--radius)) rotate(calc(-1 * var(--az))); } + + .corner-button{ + position: absolute; + top: 0; + right: 0; + } `, css` dt-toggle::part(root) { @@ -170,6 +180,7 @@ export class DtChurchHealthCircle extends DtMultiSelect { 'health-circle': true, 'health-circle--committed': this.isCommited, 'health-circle--disabled': this.disabled, + 'health-circle--readonly': this.readonly, })} >
@@ -181,7 +192,7 @@ export class DtChurchHealthCircle extends DtMultiSelect { .active=${(this.value || []).indexOf(key) !== -1} .style="--i: ${index + 1}" .missingIcon="${this.missingIcon}" - ?disabled=${this.disabled} + ?disabled=${this.disabled || this.readonly} data-value="${key}" @change="${this.handleIconClick}" > @@ -191,7 +202,9 @@ export class DtChurchHealthCircle extends DtMultiSelect { ${this.renderIconLoading()} ${this.renderIconSaved()}
- + + ${!this.readonly + ? html` - + ` + : + null} ${this.renderError()} + ${this.readonly && !this.disabled + ? html` +
+ +
`:null} `; } diff --git a/src/components/form/dt-church-health-circle/dt-church-health-circle.stories.js b/src/components/form/dt-church-health-circle/dt-church-health-circle.stories.js index 778dffe..c7e5ae6 100644 --- a/src/components/form/dt-church-health-circle/dt-church-health-circle.stories.js +++ b/src/components/form/dt-church-health-circle/dt-church-health-circle.stories.js @@ -156,8 +156,7 @@ export default { error: '', onChange: action('on-change'), }, - render: args => { - return html` + render: args => html`
- `; - }, + `, }; export const Empty = {}; @@ -222,6 +221,21 @@ export const Disabled = { }, }; +export const ReadOnly = { + args: { + value: ['church_bible'], + readonly: true, + }, +}; + +export const ReadOnlyDisabled = { + args: { + value: ['church_bible'], + readonly: true, + disabled: true, + }, +}; + export const PrivateField = { args: { private: true, @@ -288,11 +302,11 @@ export const ApiSettings = { ], settings: null, }, -};*/ +}; */ /* export const ApiGroup = { args: { groupId: 3, group: null, }, -};*/ +}; */ diff --git a/src/components/form/dt-connection/dt-connection.js b/src/components/form/dt-connection/dt-connection.js index 2e3c12f..1058b26 100644 --- a/src/components/form/dt-connection/dt-connection.js +++ b/src/components/form/dt-connection/dt-connection.js @@ -217,6 +217,8 @@ export class DtConnection extends DtTags { .filter(i => !i.delete) .map( opt => html` + ${!this.readonly + ? html`
x -
- `, + ` + : + html`
+ ${opt.link + ? html`${opt.label}` + : html`
${opt.label}
`} +
`} + `, ); } @@ -281,10 +289,12 @@ export class DtConnection extends DtTags { } render() { - const optionListStyles = this.optionListStyles; + const {optionListStyles} = this; return html` ${this.labelTemplate()} + ${!this.readonly + ? html`
+ ${this._renderSelectedOptions()} +
`} `; } } diff --git a/src/components/form/dt-connection/dt-connection.stories.js b/src/components/form/dt-connection/dt-connection.stories.js index dba9610..78cb707 100644 --- a/src/components/form/dt-connection/dt-connection.stories.js +++ b/src/components/form/dt-connection/dt-connection.stories.js @@ -135,6 +135,7 @@ export default { placeholder, value, disabled, + readonly, required, requiredMessage, icon, @@ -160,6 +161,7 @@ export default { .options="${options}" .value="${value}" ?disabled=${disabled} + ?readonly=${readonly} ?required=${required} requiredMessage="${ifDefined(requiredMessage)}" icon="${ifDefined(icon)}" @@ -277,6 +279,31 @@ export const Disabled = { disabled: true, }, }; +export const ReadOnly = { + args: { + value: [basicOptions[1], + { + id: 2, + label: 'test', + }], + options: basicOptions, + readonly: true, + }, +}; + +export const ReadOnlyDisabled = { + args: { + value: [basicOptions[1], + { + id: 2, + label: 'test', + }], + options: basicOptions, + readonly: true, + disabled: true, + }, +}; + export const PrivateField = { args: { private: true, diff --git a/src/components/form/dt-date/dt-date.js b/src/components/form/dt-date/dt-date.js index 028e215..ac3f55f 100644 --- a/src/components/form/dt-date/dt-date.js +++ b/src/components/form/dt-date/dt-date.js @@ -218,6 +218,7 @@ export class DtDate extends DtFormBase { }; return classes; } + get fieldContainerClasses() { return { 'field-container': true, @@ -232,9 +233,17 @@ export class DtDate extends DtFormBase { this.timestamp = new Date(this.value).getTime(); } + let readonlyValue = this.value; + if (this.value) { + const [y, m, d] = this.value.split('-'); + readonlyValue = `${m}/${d}/${y}`; + } + return html` ${this.labelTemplate()} + ${!this.readonly + ? html`
${this.renderIcons()} -
+
` + : + html`
+ ${readonlyValue} +
`} `; } diff --git a/src/components/form/dt-date/dt-date.stories.js b/src/components/form/dt-date/dt-date.stories.js index 95d47c0..478e95d 100644 --- a/src/components/form/dt-date/dt-date.stories.js +++ b/src/components/form/dt-date/dt-date.stories.js @@ -45,6 +45,7 @@ export default { value = '', timestamp, disabled = false, + readonly = false, required = false, requiredMessage, icon = 'https://cdn-icons-png.flaticon.com/512/1077/1077114.png', @@ -64,6 +65,7 @@ export default { value=${ifDefined(value)} timestamp=${ifDefined(timestamp)} ?disabled=${disabled} + ?readonly=${readonly} ?required=${required} requiredMessage=${ifDefined(requiredMessage)} icon=${ifDefined(icon)} @@ -121,6 +123,21 @@ export const Disabled = { }, }; +export const ReadOnly = { + args: { + value: '2020-01-01', + readonly: true, + }, +}; + +export const ReadOnlyDisabled = { + args: { + value: '2020-01-01', + readonly: true, + disabled: true, + }, +}; + export const PrivateField = { args: { private: true, diff --git a/src/components/form/dt-datetime/dt-datetime.js b/src/components/form/dt-datetime/dt-datetime.js index a7070f4..5014a09 100644 --- a/src/components/form/dt-datetime/dt-datetime.js +++ b/src/components/form/dt-datetime/dt-datetime.js @@ -35,9 +35,24 @@ export class DtDatetime extends DtDate { this.timestamp = new Date(this.value).getTime(); } + let readonlyValue = this.value; + if (this.value) { + const dateObj = new Date(this.value); + readonlyValue = new Intl.DateTimeFormat('en-US', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit', + hour12: true + }).format(dateObj); + } + return html` ${this.labelTemplate()} + ${!this.readonly + ? html`
${this.renderIcons()} -
+
` + : + html`
+ ${readonlyValue} +
`} `; } } diff --git a/src/components/form/dt-datetime/dt-datetime.stories.js b/src/components/form/dt-datetime/dt-datetime.stories.js index ba859bd..7bce445 100644 --- a/src/components/form/dt-datetime/dt-datetime.stories.js +++ b/src/components/form/dt-datetime/dt-datetime.stories.js @@ -45,6 +45,7 @@ export default { value = '', timestamp, disabled = false, + readonly = false, required = false, requiredMessage, icon = 'https://cdn-icons-png.flaticon.com/512/1077/1077114.png', @@ -64,6 +65,7 @@ export default { value=${ifDefined(value)} timestamp=${ifDefined(timestamp)} ?disabled=${disabled} + ?readonly=${readonly} ?required=${required} requiredMessage=${ifDefined(requiredMessage)} icon=${ifDefined(icon)} @@ -121,6 +123,21 @@ export const Disabled = { }, }; +export const ReadOnly = { + args: { + value: '2023-07-21T17:00', + readonly: true, + }, +}; + +export const ReadOnlyDisabled = { + args: { + value: '2023-07-21T17:00', + readonly: true, + disabled: true, + }, +}; + export const PrivateField = { args: { private: true, diff --git a/src/components/form/dt-file-upload/dt-file-upload.js b/src/components/form/dt-file-upload/dt-file-upload.js index 40677c6..6ec3109 100644 --- a/src/components/form/dt-file-upload/dt-file-upload.js +++ b/src/components/form/dt-file-upload/dt-file-upload.js @@ -721,7 +721,7 @@ export class DtFileUpload extends DtFormBase { if (file.name) { const parts = file.name.split('.'); if (parts.length > 1) { - const ext = '.' + parts.pop().toLowerCase(); + const ext = `.${ parts.pop().toLowerCase()}`; if (mapping[ext]) { return mapping[ext]; } @@ -1258,7 +1258,7 @@ export class DtFileUpload extends DtFormBase { if (this._isStandaloneMode()) { // Standalone mode: use direct URL if available - const url = file.url; + const {url} = file; if (!url) return; const fileKey = file.key || file; const fileName = @@ -1278,8 +1278,8 @@ export class DtFileUpload extends DtFormBase { new CustomEvent('dt:download-file', { bubbles: true, detail: { - fileKey: fileKey, - fileName: fileName, + fileKey, + fileName, metaKey: this.metaKey || '', }, }), @@ -1298,8 +1298,8 @@ export class DtFileUpload extends DtFormBase { const event = new CustomEvent('dt:download-file', { bubbles: true, detail: { - fileKey: fileKey, - fileName: fileName, + fileKey, + fileName, metaKey: this.metaKey, onSuccess: () => { // Download triggered successfully @@ -1372,6 +1372,21 @@ export class DtFileUpload extends DtFormBase { ? html`${iconContent}` : html``} ${this.label} + ${this.readonly && !this.disabled + ? html` + + + `:null} `; } @@ -1384,6 +1399,8 @@ export class DtFileUpload extends DtFormBase { return html`
${this.labelTemplate()} + ${!this.readonly + ? html`
` : null} ${this.label} + ${this.readonly && !this.disabled + ? html` + + + `:null} `; } + switchReadOnly() { + this.readonly = false; + } + _errorClasses() { return { 'error-container': true, diff --git a/src/components/form/dt-location-map/dt-location-map-item.js b/src/components/form/dt-location-map/dt-location-map-item.js index ec388d3..6cb44ba 100644 --- a/src/components/form/dt-location-map/dt-location-map-item.js +++ b/src/components/form/dt-location-map/dt-location-map-item.js @@ -17,6 +17,7 @@ export default class DtLocationMapItem extends DtBase { googleToken: { type: String, attribute: 'google-token' }, metadata: { type: Object }, disabled: { type: Boolean }, + readonly: { type: Boolean }, open: { type: Boolean, state: true, @@ -237,6 +238,26 @@ export default class DtLocationMapItem extends DtBase { color: var(--dt-text-placeholder-color, #999); cursor: not-allowed; } + + button.link-style { + background: none; + border: none; + padding: 0; + color: var(--primary-color, #0a84ff); + text-decoration: underline; + cursor: pointer; + font: inherit; + } + + .location-item-wrapper { + display: inline-flex; + align-items: center; + } + .location-item-wrapper dt-icon { + color: var(--primary-color, #0a84ff); + line-height: 0; + vertical-align: middle; + padding-left: .5rem; `, css` /* === Inline Icons === */ @@ -726,6 +747,8 @@ export default class DtLocationMapItem extends DtBase { const existingValue = !!this.metadata?.label; const hasGeometry = this.metadata?.lat && this.metadata?.lng; return html` + ${!this.readonly + ? html`
` : null} ${this.renderIconSaved(hasGeometry)} -
+
` + : + html`${existingValue ? + html`
+ + +
` : null} + `} + ` : null} ${this.label} - ${!this.open && (this.limit == 0 || this.locations.length < this.limit) + ${this.readonly && !this.disabled + ? html` + + + `:null} + ${!this.readonly && !this.open && (this.limit == 0 || this.locations.length < this.limit) ? html` -
+
` + : + html`
+ ${opt.label} +
`} `, ); } render() { - const optionListStyles = this.optionListStyles; + const {optionListStyles} = this; return html` ${this.labelTemplate()} + ${!this.readonly + ? html`
${this.renderIconInvalid()} ${this.renderError()} -
+
` + : + html`
+ ${this._renderSelectedOptions()} +
`} `; } } diff --git a/src/components/form/dt-location/dt-location.stories.js b/src/components/form/dt-location/dt-location.stories.js index e199398..61486d1 100644 --- a/src/components/form/dt-location/dt-location.stories.js +++ b/src/components/form/dt-location/dt-location.stories.js @@ -124,6 +124,7 @@ export default { placeholder, value, disabled, + readonly, required, requiredMessage, icon, @@ -148,6 +149,7 @@ export default { .filters="${filters}" .value="${value}" ?disabled=${disabled} + ?readonly=${readonly} ?required=${required} requiredMessage="${ifDefined(requiredMessage)}" icon="${ifDefined(icon)}" @@ -231,6 +233,24 @@ export const Disabled = { disabled: true, }, }; + +export const ReadOnly = { + args: { + value: [basicOptions[1]], + options: basicOptions, + readonly: true, + }, +}; + +export const ReadOnlyDisabled = { + args: { + value: [basicOptions[1]], + options: basicOptions, + readonly: true, + disabled: true, + }, +}; + export const PrivateField = { args: { private: true, diff --git a/src/components/form/dt-multi-select-button-group/dt-multi-select-button-group.js b/src/components/form/dt-multi-select-button-group/dt-multi-select-button-group.js index 50d3c52..1785310 100644 --- a/src/components/form/dt-multi-select-button-group/dt-multi-select-button-group.js +++ b/src/components/form/dt-multi-select-button-group/dt-multi-select-button-group.js @@ -73,6 +73,14 @@ export class DtMultiSelectButtonGroup extends DtFormBase { .invalid ~ .error-container { border-top-width: 1px; } + + .item-wrapper { + display: flex; + align-items: center; + } + .item-wrapper .icon { + margin-left: .5rem; + } `, ]; } @@ -168,7 +176,7 @@ export class DtMultiSelectButtonGroup extends DtFormBase { context=${context} .value=${opt.id} @click="${this._clickOption}" - ?disabled="${this.disabled}" + ?disabled="${this.disabled || this.readonly}" ?outline="${outline}" role="button" value="${opt.id}" @@ -216,6 +224,8 @@ export class DtMultiSelectButtonGroup extends DtFormBase { render() { return html` ${this.labelTemplate()} + ${!this.readonly + ? html`
${this.renderIcons()} -
- `; + ` + : + html`
+ ${this.options + .filter(opt => (this.value ?? []) + .includes(opt.id)) + .map( + opt => html` +
+ ${opt.label} + ${opt.icon + ? html`${this.iconAltText}` + : null} +
`)} +
` + }` } } diff --git a/src/components/form/dt-multi-select-button-group/dt-multi-select-button-group.stories.js b/src/components/form/dt-multi-select-button-group/dt-multi-select-button-group.stories.js index e6c1b52..a6fed59 100644 --- a/src/components/form/dt-multi-select-button-group/dt-multi-select-button-group.stories.js +++ b/src/components/form/dt-multi-select-button-group/dt-multi-select-button-group.stories.js @@ -85,6 +85,7 @@ export default { options, value = [], disabled = false, + readonly = false, required = false, requiredMessage, icon = 'https://cdn-icons-png.flaticon.com/512/1077/1077114.png', @@ -104,6 +105,7 @@ export default { .options=${options} .value=${value} ?disabled=${disabled} + ?readonly=${readonly} ?required=${required} requiredMessage=${ifDefined(requiredMessage)} icon=${ifDefined(icon)} @@ -158,6 +160,23 @@ export const Disabled = { }, }; +export const ReadOnly = { + args: { + value: ['opt1', 'opt2', 'opt7'], + options: basicOptions, + readonly: true, + }, +}; + +export const ReadOnlyDisabled = { + args: { + value: ['opt2'], + options: basicOptions, + readonly: true, + disabled: true, + }, +}; + export const PrivateField = { args: { private: true, diff --git a/src/components/form/dt-multi-select/dt-multi-select.js b/src/components/form/dt-multi-select/dt-multi-select.js index 6e83d1f..a7670e8 100644 --- a/src/components/form/dt-multi-select/dt-multi-select.js +++ b/src/components/form/dt-multi-select/dt-multi-select.js @@ -408,6 +408,8 @@ export class DtMultiSelect extends HasOptionsList(DtFormBase) { .filter(val => val.charAt(0) !== '-') .map( val => html` + ${!this.readonly + ? html`
x -
+ ` + : + html`
+ ${this.options.find(option => option.id === val).label} +
`} `, ) ); @@ -461,10 +467,12 @@ export class DtMultiSelect extends HasOptionsList(DtFormBase) { } render() { - const optionListStyles = this.optionListStyles; + const {optionListStyles} = this; return html` ${this.labelTemplate()} + ${!this.readonly + ? html`
${this.renderIcons()} -
+ ` + : + html`
+ ${this._renderSelectedOptions()} +
`} `; } } diff --git a/src/components/form/dt-multi-select/dt-multi-select.stories.js b/src/components/form/dt-multi-select/dt-multi-select.stories.js index 9e31180..a605e80 100644 --- a/src/components/form/dt-multi-select/dt-multi-select.stories.js +++ b/src/components/form/dt-multi-select/dt-multi-select.stories.js @@ -84,6 +84,7 @@ export default { placeholder = 'Select Options', value = [], disabled = false, + readonly = false, required = false, requiredMessage, icon = 'https://cdn-icons-png.flaticon.com/512/1077/1077114.png', @@ -105,6 +106,7 @@ export default { .options=${options} .value=${value} ?disabled=${disabled} + ?readonly=${readonly} ?required=${required} requiredMessage=${ifDefined(requiredMessage)} icon=${ifDefined(icon)} @@ -203,6 +205,23 @@ export const Disabled = { }, }; +export const ReadOnly = { + args: { + value: ['opt1', 'opt2'], + options: basicOptions, + readonly: true, + }, +}; + +export const ReadOnlyDisabled = { + args: { + value: ['opt2'], + options: basicOptions, + readonly: true, + disabled: true, + }, +}; + export const PrivateField = { args: { private: true, diff --git a/src/components/form/dt-multi-text-groups/dt-multi-text-groups.js b/src/components/form/dt-multi-text-groups/dt-multi-text-groups.js index d05be02..f839583 100644 --- a/src/components/form/dt-multi-text-groups/dt-multi-text-groups.js +++ b/src/components/form/dt-multi-text-groups/dt-multi-text-groups.js @@ -138,9 +138,9 @@ export class DtMultiTextGroups extends DtMultiText { verified: false, value: '', tempKey: Date.now().toString(), - type: group.id, + group: group.id, }; - if (this.value[0]?.type) { + if (this.value[0]?.group) { this.value = [...this.value, newValue]; } else { @@ -161,6 +161,7 @@ export class DtMultiTextGroups extends DtMultiText { _removeItem(e) { const keyToRemove = e.currentTarget.dataset.key; + console.log(e.currentTarget); if (keyToRemove) { const event = new CustomEvent('change', { bubbles: true, @@ -178,9 +179,9 @@ export class DtMultiTextGroups extends DtMultiText { .map(x => { const item = { ...x }; // add `delete` prop to clicked item - if (x.meta_id === keyToRemove || x.tempKey === keyToRemove) { + if (x.key === keyToRemove || x.tempKey === keyToRemove) { item.delete = true; - this.activeGroup = item.type; + this.activeGroup = item.group; } return item; }); @@ -208,8 +209,8 @@ export class DtMultiTextGroups extends DtMultiText { // update this item's value in the list this.value = this.value.map(x => { - if (x.meta_id === key || x.tempKey === key) { - this.activeGroup = x.type; + if (x.key === key || x.tempKey === key) { + this.activeGroup = x.group; return { ...x, @@ -330,7 +331,7 @@ export class DtMultiTextGroups extends DtMultiText { return html`
${when( - (this.value[0]?.type) || (!this.groups && itemCount > 1), + (this.value[0]?.group) || (!this.groups && itemCount > 1), () => html` + `: + html`
` : ''} - + `} `; } + + render() { + return html` + ${this.labelTemplate()} + + ${!this.readonly + ? html` +
+ ${this._renderInputFields()} ${this.renderIcons()} +
` + : + html` + + ${this.value ? repeat(this.groups, group => html`

${group.label}

+ +
+ ${repeat( + (this.value || []).filter(item => item.group === group.id), + item => html`
${item.value}
` + )} +
` + ) : html` +
+ No items to show. +
+ `}` + } + `; + } } window.customElements.define('dt-multi-text-groups', DtMultiTextGroups); diff --git a/src/components/form/dt-multi-text-groups/dt-multi-text-groups.stories.js b/src/components/form/dt-multi-text-groups/dt-multi-text-groups.stories.js index 25147b2..deb0683 100644 --- a/src/components/form/dt-multi-text-groups/dt-multi-text-groups.stories.js +++ b/src/components/form/dt-multi-text-groups/dt-multi-text-groups.stories.js @@ -44,6 +44,7 @@ export default { value = '', placeholder, disabled = false, + readonly = false, required = false, requiredMessage, icon = 'https://cdn-icons-png.flaticon.com/512/1077/1077114.png', @@ -66,6 +67,7 @@ export default { placeholder=${placeholder} type=${type} ?disabled=${disabled} + ?readonly=${readonly} ?required=${required} requiredMessage=${requiredMessage} icon="${icon}" @@ -168,6 +170,61 @@ export const Disabled = { } } +export const ReadOnly = { + args: { + groups: [ + { id: 'one', label: 'Group 1' }, + { id: 'two', label: 'Group 2' } + ], + readonly: true, + value: [ + { + value: 'Lorem Ipsum', + key: 'comm_channel_1', + group: 'one' + }, + { + value: 'Lorem Ipsu2', + key: 'comm_channel_2', + group: 'two' + }, + { + value: 'Lorem Ipsum', + key: 'comm_channel_3', + group: 'two' + } + ], + } +} + +export const ReadOnlyDisabled = { + args: { + groups: [ + { id: 'one', label: 'Group 1' }, + { id: 'two', label: 'Group 2' } + ], + readonly: true, + disabled: true, + value: [ + { + value: 'Lorem Ipsum', + key: 'comm_channel_1', + group: 'one' + }, + { + value: 'Lorem Ipsum', + key: 'comm_channel_2', + group: 'two' + }, + { + value: 'Lorem Ipsum2', + key: 'comm_channel_3', + group: 'two' + } + ], + } +} + export const privateField = { args: { groups: [ diff --git a/src/components/form/dt-multi-text-groups/dt-multi-text-groups.test.js b/src/components/form/dt-multi-text-groups/dt-multi-text-groups.test.js index c92225e..8dfdfb9 100644 --- a/src/components/form/dt-multi-text-groups/dt-multi-text-groups.test.js +++ b/src/components/form/dt-multi-text-groups/dt-multi-text-groups.test.js @@ -9,7 +9,7 @@ describe('DtMultiTextGroups', () => { const el = await fixture( html`` ); @@ -22,13 +22,13 @@ describe('DtMultiTextGroups', () => { const el = await fixture( html`` : null} ${this.label} - + ${this.readonly && !this.disabled + ? html` + + + `: + html` - + `} `; } @@ -458,9 +473,34 @@ export class DtMultiText extends DtText { render() { return html` ${this.labelTemplate()} + + ${!this.readonly + ? html`
${this._renderInputFields()} ${this.renderIcons()} -
+ ` + : + html`
+ ${repeat( + this.value || [], + opt => + { + if (this.type === 'email') { + return html`
+ ${opt.value} + +
`; + } + if (this.type === 'tel') { + return html`
+ ${opt.value} + +
`; + } + return html`
${opt.value}
`; + } + )} +
`} `; } } diff --git a/src/components/form/dt-multi-text/dt-multi-text.stories.js b/src/components/form/dt-multi-text/dt-multi-text.stories.js index 43672d8..717d2aa 100644 --- a/src/components/form/dt-multi-text/dt-multi-text.stories.js +++ b/src/components/form/dt-multi-text/dt-multi-text.stories.js @@ -65,6 +65,7 @@ export default { placeholder, type, disabled, + readonly, required, requiredMessage, icon, @@ -86,6 +87,7 @@ export default { placeholder="${ifDefined(placeholder)}" type="${ifDefined(type)}" ?disabled=${disabled} + ?readonly=${readonly} ?required=${required} requiredMessage="${ifDefined(requiredMessage)}" icon="${ifDefined(icon)}" @@ -157,6 +159,41 @@ export const Disabled = { }, }; +export const ReadOnly = { + args: { + readonly: true, + value: [ + { + value: 'email@test.com', + key: 'comm_channel_1', + }, + { + value: 'example@example.com', + key: 'comm_channel_2', + } + ], + type: 'email', + }, +}; + +export const ReadOnlyDisabled = { + args: { + readonly: true, + disabled: true, + value: [ + { + value: '+5-987-654-3210', + key: 'comm_channel_1', + }, + { + value: '+1 123 456 7890', + key: 'comm_channel_2', + } + ], + type: 'tel', + }, +}; + export const PrivateField = { args: { private: true, diff --git a/src/components/form/dt-number/dt-number.js b/src/components/form/dt-number/dt-number.js index c18fede..37d68cd 100644 --- a/src/components/form/dt-number/dt-number.js +++ b/src/components/form/dt-number/dt-number.js @@ -167,6 +167,8 @@ export class DtNumberField extends DtFormBase { return html` ${this.labelTemplate()} + ${!this.readonly + ? html`
${this.renderIcons()} -
+ ` + : + html`
+ ${this.value} +
`} `; } } diff --git a/src/components/form/dt-number/dt-number.stories.js b/src/components/form/dt-number/dt-number.stories.js index 4944ea3..6617592 100644 --- a/src/components/form/dt-number/dt-number.stories.js +++ b/src/components/form/dt-number/dt-number.stories.js @@ -47,6 +47,7 @@ export default { min, max, disabled = false, + readonly = false, required = false, requiredMessage, icon = 'https://cdn-icons-png.flaticon.com/512/1077/1077114.png', @@ -67,6 +68,7 @@ export default { min=${ifDefined(min)} max=${ifDefined(max)} ?disabled=${disabled} + ?readonly=${readonly} ?required=${required} requiredMessage=${ifDefined(requiredMessage)} icon="${ifDefined(icon)}" @@ -112,6 +114,21 @@ export const Disabled = { }, }; +export const ReadOnly = { + args: { + readonly: true, + value: 42, + }, +}; + +export const ReadOnlyDisabled = { + args: { + readonly: true, + disabled: true, + value: 42, + }, +}; + export const PrivateField = { args: { private: true, diff --git a/src/components/form/dt-single-select/dt-single-select.js b/src/components/form/dt-single-select/dt-single-select.js index 4d3ad74..193b81b 100644 --- a/src/components/form/dt-single-select/dt-single-select.js +++ b/src/components/form/dt-single-select/dt-single-select.js @@ -224,6 +224,8 @@ export class DtSingleSelect extends DtFormBase { return html` ${this.labelTemplate()} + ${!this.readonly + ? html`
${this.renderIcons()} -
+ ` + : + html`
+ ${(this.options || []).find(i => i.id === this.value)?.label || ''} +
`} `; } } diff --git a/src/components/form/dt-single-select/dt-single-select.stories.js b/src/components/form/dt-single-select/dt-single-select.stories.js index 268e78c..95ae587 100644 --- a/src/components/form/dt-single-select/dt-single-select.stories.js +++ b/src/components/form/dt-single-select/dt-single-select.stories.js @@ -85,6 +85,7 @@ export default { placeholder = 'Select Option', value, disabled = false, + readonly = false, required = false, requiredMessage, icon = 'https://cdn-icons-png.flaticon.com/512/1077/1077114.png', @@ -105,6 +106,7 @@ export default { .options=${options} value=${ifDefined(value)} ?disabled=${disabled} + ?readonly=${readonly} ?required=${required} requiredMessage=${ifDefined(requiredMessage)} icon=${ifDefined(icon)} @@ -178,6 +180,23 @@ export const Disabled = { }, }; +export const ReadOnly = { + args: { + value: 'opt2', + options: basicOptions, + readonly: true, + }, +}; + +export const ReadOnlyDisabled = { + args: { + value: 'opt2', + options: basicOptions, + readonly: true, + disabled: true, + }, +}; + export const PrivateField = { args: { private: true, diff --git a/src/components/form/dt-tags/dt-tags.js b/src/components/form/dt-tags/dt-tags.js index a6b0699..07f00e2 100644 --- a/src/components/form/dt-tags/dt-tags.js +++ b/src/components/form/dt-tags/dt-tags.js @@ -263,6 +263,8 @@ export class DtTags extends DtMultiSelect { ); } return html` + ${!this.readonly + ? html`
x -
+ ` + : + html`
+ ${label} +
`} `; }); } render() { - const optionListStyles = this.optionListStyles; + const {optionListStyles} = this; return html` ${this.labelTemplate()} + ${!this.readonly + ? html`
+ ${this._renderSelectedOptions()} +
`} `; } } diff --git a/src/components/form/dt-tags/dt-tags.stories.js b/src/components/form/dt-tags/dt-tags.stories.js index 2477b3d..f8cf75e 100644 --- a/src/components/form/dt-tags/dt-tags.stories.js +++ b/src/components/form/dt-tags/dt-tags.stories.js @@ -113,6 +113,7 @@ export default { placeholder, value, disabled, + readonly, required, requiredMessage, icon, @@ -137,6 +138,7 @@ export default { .options="${options}" .value="${value}" ?disabled="${disabled}" + ?readonly="${readonly}" ?required="${required}" requiredMessage="${requiredMessage}" icon="${icon}" @@ -254,6 +256,23 @@ export const Disabled = { }, }; +export const ReadOnly = { + args: { + value: ['qui est esse', 'opt8'], + options: basicOptions, + readonly: true, + }, +}; + +export const ReadOnlyDisabled = { + args: { + value: ['qui est esse', 'opt8'], + options: basicOptions, + readonly: true, + disabled: true, + }, +}; + export const PrivateField = { args: { private: true, diff --git a/src/components/form/dt-text/dt-text.js b/src/components/form/dt-text/dt-text.js index 5f0be74..d267f3e 100644 --- a/src/components/form/dt-text/dt-text.js +++ b/src/components/form/dt-text/dt-text.js @@ -159,6 +159,8 @@ export class DtText extends DtFormBase { return html` ${this.labelTemplate()} + ${!this.readonly + ? html`
${this.renderIcons()} -
+ ` + : + html`
+ ${this.value || ''} +
`} `; } } diff --git a/src/components/form/dt-text/dt-text.stories.js b/src/components/form/dt-text/dt-text.stories.js index d087e73..a744b24 100644 --- a/src/components/form/dt-text/dt-text.stories.js +++ b/src/components/form/dt-text/dt-text.stories.js @@ -47,6 +47,7 @@ export default { label = 'Field Name', value, disabled = false, + readonly = false, required = false, requiredMessage, icon = 'https://cdn-icons-png.flaticon.com/512/1077/1077114.png', @@ -67,6 +68,7 @@ export default { value=${ifDefined(value)} type=${ifDefined(type)} ?disabled=${disabled} + ?readonly=${readonly} ?required=${required} requiredMessage=${ifDefined(requiredMessage)} icon="${ifDefined(icon)}" @@ -112,6 +114,21 @@ export const Disabled = { }, }; +export const ReadOnly = { + args: { + readonly: true, + value: 'Lorem Ipsum', + }, +}; + +export const ReadOnlyDisabled = { + args: { + readonly: true, + disabled: true, + value: 'Lorem Ipsum', + }, +}; + export const PrivateField = { args: { private: true, diff --git a/src/components/form/dt-textarea/dt-textarea.js b/src/components/form/dt-textarea/dt-textarea.js index 06e8b52..cd589ad 100644 --- a/src/components/form/dt-textarea/dt-textarea.js +++ b/src/components/form/dt-textarea/dt-textarea.js @@ -144,6 +144,8 @@ export class DtTextArea extends DtFormBase { return html` ${this.labelTemplate()} + ${!this.readonly + ? html`
${this.renderIcons()} -
+ ` + : + html`
+ ${this.value || ''} +
`} `; } } diff --git a/src/components/form/dt-textarea/dt-textarea.stories.js b/src/components/form/dt-textarea/dt-textarea.stories.js index 8fc807a..a8e2394 100644 --- a/src/components/form/dt-textarea/dt-textarea.stories.js +++ b/src/components/form/dt-textarea/dt-textarea.stories.js @@ -43,6 +43,7 @@ export default { label = 'Field Name', value, disabled = false, + readonly = false, required = false, requiredMessage, icon = 'https://cdn-icons-png.flaticon.com/512/1077/1077114.png', @@ -61,6 +62,7 @@ export default { label=${ifDefined(label)} value=${ifDefined(value)} ?disabled=${disabled} + ?readonly=${readonly} ?required=${required} requiredMessage=${ifDefined(requiredMessage)} icon="${ifDefined(icon)}" @@ -106,6 +108,21 @@ export const Disabled = { }, }; +export const ReadOnly = { + args: { + readonly: true, + value: 'Lorem Ipsum', + }, +}; + +export const ReadOnlyDisabled = { + args: { + readonly: true, + disabled: true, + value: 'Lorem Ipsum', + }, +}; + export const PrivateField = { args: { private: true, diff --git a/src/components/form/dt-toggle/dt-toggle.js b/src/components/form/dt-toggle/dt-toggle.js index de909f2..8eff6e6 100644 --- a/src/components/form/dt-toggle/dt-toggle.js +++ b/src/components/form/dt-toggle/dt-toggle.js @@ -229,7 +229,7 @@ export class DtToggle extends DtFormBase { class="toggle-input" .checked=${this.checked || 0} @click=${this.onChange} - ?disabled=${this.disabled} + ?disabled=${this.disabled || this.readonly} /> ${this.icons ? html` ${check} ${cross} ` : html``} diff --git a/src/components/form/dt-toggle/dt-toggle.stories.js b/src/components/form/dt-toggle/dt-toggle.stories.js index 82d5a89..551275a 100644 --- a/src/components/form/dt-toggle/dt-toggle.stories.js +++ b/src/components/form/dt-toggle/dt-toggle.stories.js @@ -43,6 +43,7 @@ export default { name = 'field-name', label = 'Field Name', disabled = false, + readonly = false, checked = false, icons = false, required = false, @@ -64,6 +65,7 @@ export default { ?checked=${checked} ?icons=${icons} ?disabled=${disabled} + ?readonly=${readonly} ?required=${required} requiredMessage=${ifDefined(requiredMessage)} icon="${ifDefined(icon)}" @@ -115,6 +117,21 @@ export const Disabled = { }, }; +export const ReadOnly = { + args: { + checked: false, + readonly: true, + }, +}; + +export const ReadOnlyDisabled = { + args: { + checked: false, + readonly: true, + disabled: true, + }, +}; + export const DisabledOn = { args: { checked: true, diff --git a/src/components/form/dt-users-connection/dt-users-connection.js b/src/components/form/dt-users-connection/dt-users-connection.js index 5e962c9..628e303 100644 --- a/src/components/form/dt-users-connection/dt-users-connection.js +++ b/src/components/form/dt-users-connection/dt-users-connection.js @@ -238,6 +238,8 @@ export class DtUsersConnection extends DtTags { .filter(i => !i.delete) .map( opt => html` + ${!this.readonly + ? html`
x -
+ ` + : + html`
+ ${opt.link + ? html`${opt.label}` + : html`
${opt.label}
`} +
`} `, ); } diff --git a/src/components/form/dt-users-connection/dt-users-connection.stories.js b/src/components/form/dt-users-connection/dt-users-connection.stories.js index afb42c6..b789fed 100644 --- a/src/components/form/dt-users-connection/dt-users-connection.stories.js +++ b/src/components/form/dt-users-connection/dt-users-connection.stories.js @@ -109,6 +109,7 @@ export default { value, open, disabled, + readonly, required, requiredMessage, icon, @@ -135,6 +136,7 @@ export default { .value="${value}" .open="${open}" ?disabled=${disabled} + ?readonly=${readonly} ?required=${required} requiredMessage="${ifDefined(requiredMessage)}" icon="${ifDefined(icon)}" @@ -229,6 +231,32 @@ export const Disabled = { disabled: true, }, }; + +export const ReadOnly = { + args: { + value: [basicOptions[1], { + id: 2, + label: 'test', + link: '/#opt2', + }], + options: basicOptions, + readonly: true, + }, +}; + +export const ReadOnlyDisabled = { + args: { + value: [basicOptions[1], { + id: 2, + label: 'test', + link: '/#opt2', + }], + options: basicOptions, + readonly: true, + disabled: true, + }, +}; + export const PrivateField = { args: { private: true, diff --git a/src/components/kitchen-sink.stories.js b/src/components/kitchen-sink.stories.js index 5571a74..c09e92c 100644 --- a/src/components/kitchen-sink.stories.js +++ b/src/components/kitchen-sink.stories.js @@ -1,6 +1,7 @@ import { html } from 'lit'; import { ifDefined } from 'lit/directives/if-defined.js'; import { argTypes } from '../stories-theme.js'; +import sampleImage from '../../assets/dt-caret.png'; import './layout/dt-tile/dt-tile.js'; import './form/dt-label/dt-label.js'; @@ -22,10 +23,15 @@ import './form/dt-connection/dt-connection.js'; import './form/dt-users-connection/dt-users-connection.js'; import './form/dt-file-upload/dt-file-upload.js'; +// Sample image used for Storybook previews (local asset). +const SAMPLE_IMAGE_URL = sampleImage; +const SAMPLE_THUMBNAIL_URL = sampleImage; + const options = [ { id: 'opt1', label: 'Option 1', + icon: 'https://cdn-icons-png.flaticon.com/512/1077/1077114.png', }, { id: 'opt2', @@ -111,42 +117,76 @@ export default { @@ -154,16 +194,20 @@ export default { @@ -172,6 +216,7 @@ export default { name="toggleField" label="Boolean Field" ?disabled=${args.disabled} + ?readonly=${args.readonly} error="${ifDefined(args.error)}" > @@ -181,6 +226,7 @@ export default { value="opt1" options="${JSON.stringify(options)}" ?disabled=${args.disabled} + ?readonly=${args.readonly} error="${ifDefined(args.error)}" > @@ -190,6 +236,7 @@ export default { value="${JSON.stringify(options.slice(0, 2).map(o => o.id))}" options="${JSON.stringify(options)}" ?disabled=${args.disabled} + ?readonly=${args.readonly} error="${ifDefined(args.error)}" > @@ -199,6 +246,7 @@ export default { value="${JSON.stringify(options.slice(0, 2).map(o => o.id))}" options="${JSON.stringify(options)}" ?disabled=${args.disabled} + ?readonly=${args.readonly} error="${ifDefined(args.error)}" > @@ -207,35 +255,81 @@ export default { value="${JSON.stringify(['personal'])}" options="${JSON.stringify(tags)}" ?disabled=${args.disabled} + ?readonly=${args.readonly} error="${ifDefined(args.error)}" > @@ -245,6 +339,7 @@ export default { label="Button" context="primary" ?disabled=${args.disabled} + ?readonly=${args.readonly} error="${ifDefined(args.error)}" >Click Me @@ -259,6 +354,12 @@ export const Disabled = { }, }; +export const ReadOnly = { + args: { + readonly: true, + }, +}; + export const Error = { args: { error: 'Custom error message', diff --git a/src/services/componentService.js b/src/services/componentService.js index 5330a86..9e5b97b 100644 --- a/src/services/componentService.js +++ b/src/services/componentService.js @@ -302,9 +302,9 @@ export default class ComponentService { new CustomEvent('dt:post:update', { detail: { response: apiResponse, - field: field, + field, value: apiValue, - component: component, + component, }, }), ); @@ -355,9 +355,9 @@ export default class ComponentService { new CustomEvent('dt:post:update', { detail: { response: apiResponse, - field: field, + field, value: apiValue, - component: component, + component, }, }), ); @@ -855,10 +855,10 @@ export default class ComponentService { } // Handle object arrays - const getObjectKey = obj => { + const getObjectKey = obj => // Use stringified object as key to ensure uniqueness - return JSON.stringify(obj); - }; + JSON.stringify(obj) + ; const value1Map = new Map(value1.map(item => [getObjectKey(item), item])); const value2Map = new Map(value2.map(item => [getObjectKey(item), item])); diff --git a/src/services/googleGeocodeService.js b/src/services/googleGeocodeService.js index 2458eed..eb7b13a 100644 --- a/src/services/googleGeocodeService.js +++ b/src/services/googleGeocodeService.js @@ -9,6 +9,7 @@ export default class GoogleGeocodeService { document.body.appendChild(script); } } + /** * Search places via Mapbox API * @param query @@ -71,8 +72,8 @@ export default class GoogleGeocodeService { async _getPlaceSuggestionsRest(query, language = 'en') { // Legacy failed; fallback to Places v1 REST const url = - 'https://places.googleapis.com/v1/places:autocomplete?key=' + - encodeURIComponent(this.token); + `https://places.googleapis.com/v1/places:autocomplete?key=${ + encodeURIComponent(this.token)}`; const body = { input: query, // language,