add element for multiple text string item

This commit is contained in:
Mads Rasmussen
2023-01-23 15:16:00 +01:00
parent c381474b2c
commit dbae5cb615
4 changed files with 174 additions and 62 deletions

View File

@@ -0,0 +1,143 @@
import { css, html, nothing } from 'lit';
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
import { customElement, property, query } from 'lit/decorators.js';
import { FormControlMixin } from '@umbraco-ui/uui-base/lib/mixins';
import { UUIInputEvent } from '@umbraco-ui/uui-input';
import { UUIInputElement } from '@umbraco-ui/uui';
import { UmbLitElement } from '@umbraco-cms/element';
import { UmbModalService, UMB_MODAL_SERVICE_CONTEXT_TOKEN } from 'src/core/modal';
import { UmbChangeEvent } from 'src/core/events/change.event';
import { UmbDeleteEvent } from 'src/core/events/delete.event';
import { UmbInputEvent } from 'src/core/events/input.event';
import { elementUpdated } from '@open-wc/testing';
/**
* @element umb-input-multiple-text-string-item
*/
@customElement('umb-input-multiple-text-string-item')
export class UmbInputMultipleTextStringItemElement extends FormControlMixin(UmbLitElement) {
static styles = [
UUITextStyles,
css`
:host {
display: flex;
align-items: center;
margin-bottom: var(--uui-size-space-3);
gap: var(--uui-size-space-3);
}
#input {
flex: 1;
}
`,
];
/**
* Disables the input
* @type {boolean}
* @attr
* @default false
*/
@property({ type: Boolean, reflect: true })
disabled = false;
/**
* Disables the input
* @type {boolean}
* @attr
* @default false
*/
@property({ type: Boolean, reflect: true })
readonly = false;
/**
* Makes the input required
* @type {boolean}
* @attr
* @default false
*/
@property({ type: Boolean, reflect: true })
required = false;
@query('#input')
protected _input?: UUIInputElement;
private _modalService?: UmbModalService;
constructor() {
super();
this.consumeContext(UMB_MODAL_SERVICE_CONTEXT_TOKEN, (modalService) => {
this._modalService = modalService;
});
}
#onDelete() {
const modalHandler = this._modalService?.confirm({
headline: `Delete ${this._value || 'item'}`,
content: 'Are you sure you want to delete this item?',
color: 'danger',
confirmLabel: 'Delete',
});
modalHandler?.onClose().then(({ confirmed }: any) => {
if (confirmed) this.dispatchEvent(new UmbDeleteEvent());
});
}
#onInput(event: UUIInputEvent) {
event.stopPropagation();
const target = event.currentTarget as UUIInputElement;
this._value = target.value as string;
this.dispatchEvent(new UmbInputEvent());
}
#onChange(event: UUIInputEvent) {
event.stopPropagation();
const target = event.currentTarget as UUIInputElement;
this._value = target.value as string;
this.dispatchEvent(new UmbChangeEvent());
}
public async focus() {
await this.updateComplete;
this._input?.focus();
}
protected getFormElement() {
return undefined;
}
render() {
return html`
${this.disabled || this.readonly ? nothing : html`<uui-icon name="umb:navigation"></uui-icon>`}
<uui-input
id="input"
value="${this._value}"
@input="${this.#onInput}"
@change="${this.#onChange}"
?disabled=${this.disabled}
?readonly=${this.readonly}></uui-input>
${this.readonly
? nothing
: html`<uui-button
label="Delete ${this._value}"
look="primary"
color="danger"
@click="${this.#onDelete}"
?disabled=${this.disabled}
compact>
<uui-icon name="umb:trash"></uui-icon>
</uui-button>`}
`;
}
}
export default UmbInputMultipleTextStringItemElement;
declare global {
interface HTMLElementTagNameMap {
'umb-input-multiple-text-string-item': UmbInputMultipleTextStringItemElement;
}
}

View File

@@ -3,10 +3,14 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
import { customElement, property, state } from 'lit/decorators.js';
import { repeat } from 'lit/directives/repeat.js';
import { FormControlMixin } from '@umbraco-ui/uui-base/lib/mixins';
import { UUIInputElement, UUIInputEvent } from '@umbraco-ui/uui-input';
import UmbInputMultipleTextStringItemElement from '../input-multiple-text-string-item/input-multiple-text-string-item.element';
import { UmbLitElement } from '@umbraco-cms/element';
import { UmbModalService, UMB_MODAL_SERVICE_CONTEXT_TOKEN } from 'src/core/modal';
import { UmbChangeEvent } from 'src/core/events/change.event';
import { UmbDeleteEvent } from 'src/core/events/delete.event';
import '../input-multiple-text-string-item/input-multiple-text-string-item.element';
import { UmbInputEvent } from 'src/core/events/input.event';
export type MultipleTextStringValue = Array<MultipleTextStringValueItem>;
@@ -22,17 +26,6 @@ export class UmbInputMultipleTextStringElement extends FormControlMixin(UmbLitEl
static styles = [
UUITextStyles,
css`
.item {
display: flex;
align-items: center;
margin-bottom: var(--uui-size-space-3);
gap: var(--uui-size-space-3);
}
.item #text-field {
flex: 1;
}
#action {
display: block;
}
@@ -93,8 +86,6 @@ export class UmbInputMultipleTextStringElement extends FormControlMixin(UmbLitEl
@property({ type: Boolean, reflect: true })
readonly = false;
private _modalService?: UmbModalService;
constructor() {
super();
@@ -108,10 +99,6 @@ export class UmbInputMultipleTextStringElement extends FormControlMixin(UmbLitEl
() => this.maxMessage,
() => !!this.max && this._items.length > this.max
);
this.consumeContext(UMB_MODAL_SERVICE_CONTEXT_TOKEN, (modalService) => {
this._modalService = modalService;
});
}
@state()
@@ -137,23 +124,9 @@ export class UmbInputMultipleTextStringElement extends FormControlMixin(UmbLitEl
this.#focusNewItem();
}
#onDelete(index: number) {
const item = this._items[index];
const modalHandler = this._modalService?.confirm({
headline: `Delete ${item.value || 'item'}`,
content: 'Are you sure you want to delete this item?',
color: 'danger',
confirmLabel: 'Delete',
});
modalHandler?.onClose().then(({ confirmed }: any) => {
if (confirmed) this.#deleteItem(index);
});
}
#onInput(event: UUIInputEvent, currentIndex: number) {
const target = event.currentTarget as UUIInputElement;
#onInput(event: UmbInputEvent, currentIndex: number) {
event.stopPropagation();
const target = event.currentTarget as UmbInputMultipleTextStringItemElement;
const value = target.value as string;
this._items = this._items.map((item, index) => (index === currentIndex ? { value } : item));
this.dispatchEvent(new UmbChangeEvent());
@@ -161,12 +134,15 @@ export class UmbInputMultipleTextStringElement extends FormControlMixin(UmbLitEl
async #focusNewItem() {
await this.updateComplete;
const inputs = this.shadowRoot?.querySelectorAll('uui-input') as NodeListOf<UUIInputElement>;
const inputs = this.shadowRoot?.querySelectorAll(
'umb-input-multiple-text-string-item'
) as NodeListOf<UmbInputMultipleTextStringItemElement>;
const lastInput = inputs[inputs.length - 1];
lastInput.focus();
}
#deleteItem(itemIndex: number) {
#deleteItem(event: UmbDeleteEvent, itemIndex: number) {
event.stopPropagation();
this._items = this._items.filter((item, index) => index !== itemIndex);
this.dispatchEvent(new UmbChangeEvent());
}
@@ -195,34 +171,16 @@ export class UmbInputMultipleTextStringElement extends FormControlMixin(UmbLitEl
${repeat(
this._items,
(item, index) => index,
(item, index) => html`${this._renderItem(item, index)}`
(item, index) =>
html`<umb-input-multiple-text-string-item
value=${item.value}
@input=${(event: UmbInputEvent) => this.#onInput(event, index)}
@delete="${(event: UmbDeleteEvent) => this.#deleteItem(event, index)}"
?disabled=${this.disabled}
?readonly=${this.readonly}></umb-input-multiple-text-string-item>`
)}
`;
}
private _renderItem(item: MultipleTextStringValueItem, index: number) {
return html`<div class="item">
${this.disabled || this.readonly ? nothing : html`<uui-icon name="umb:navigation"></uui-icon>`}
<uui-input
id="text-field"
value="${item.value}"
@input="${(event: UUIInputEvent) => this.#onInput(event, index)}"
?disabled=${this.disabled}
?readonly=${this.readonly}></uui-input>
${this.readonly
? nothing
: html`<uui-button
label="Delete ${item.value}"
look="primary"
color="danger"
@click="${() => this.#onDelete(index)}"
?disabled=${this.disabled}
compact>
<uui-icon name="umb:trash"></uui-icon>
</uui-button>`}
</div>`;
}
}
export default UmbInputMultipleTextStringElement;

View File

@@ -0,0 +1,5 @@
export class UmbDeleteEvent extends Event {
public constructor() {
super('delete', { bubbles: true, composed: false, cancelable: false });
}
}

View File

@@ -0,0 +1,6 @@
export class UmbInputEvent extends Event {
public constructor() {
// mimics the native input event
super('input', { bubbles: true, composed: true, cancelable: false });
}
}