diff --git a/src/components/block-tunes/block-tune-delete.ts b/src/components/block-tunes/block-tune-delete.ts index a759310c..183bd7dc 100644 --- a/src/components/block-tunes/block-tune-delete.ts +++ b/src/components/block-tunes/block-tune-delete.ts @@ -72,6 +72,9 @@ export default class DeleteTune implements BlockTune { label: this.api.i18n.t('Delete'), onClick: (item, e): void => this.handleClick(e), name: 'delete', + confirmation: { + label: 'Click to delete', + }, }; } @@ -85,36 +88,36 @@ export default class DeleteTune implements BlockTune { * if block is not waiting the confirmation, subscribe on block-settings-closing event to reset * otherwise delete block */ - if (!this.needConfirmation) { - this.setConfirmation(true); - const button = (event.target as HTMLElement) - .closest('.' + Popover.CSS.item) - .querySelector('.' + Popover.CSS.itemIcon); + // if (!this.needConfirmation) { + // this.setConfirmation(true); + // const button = (event.target as HTMLElement) + // .closest('.' + Popover.CSS.item) + // .querySelector('.' + Popover.CSS.itemIcon); - button.classList.add(this.CSS.buttonDelete); - button.classList.add(this.CSS.buttonConfirm); + // button.classList.add(this.CSS.buttonDelete); + // button.classList.add(this.CSS.buttonConfirm); - /** - * Subscribe on event. - * When toolbar block settings is closed but block deletion is not confirmed, - * then reset confirmation state - */ - this.api.events.on('block-settings-closed', this.resetConfirmation); - } else { - /** - * Unsubscribe from block-settings closing event - */ - this.api.events.off('block-settings-closed', this.resetConfirmation); + // /** + // * Subscribe on event. + // * When toolbar block settings is closed but block deletion is not confirmed, + // * then reset confirmation state + // */ + // this.api.events.on('block-settings-closed', this.resetConfirmation); + // } else { + /** + * Unsubscribe from block-settings closing event + */ + // this.api.events.off('block-settings-closed', this.resetConfirmation); - this.api.blocks.delete(); - this.api.toolbar.close(); - this.api.tooltip.hide(); + this.api.blocks.delete(); + this.api.toolbar.close(); + this.api.tooltip.hide(); - /** - * Prevent firing ui~documentClicked that can drop currentBlock pointer - */ - event.stopPropagation(); - } + /** + * Prevent firing ui~documentClicked that can drop currentBlock pointer + */ + event.stopPropagation(); + // } } /** diff --git a/src/components/utils/popover.ts b/src/components/utils/popover.ts index 49416194..4b02e0de 100644 --- a/src/components/utils/popover.ts +++ b/src/components/utils/popover.ts @@ -48,6 +48,13 @@ export interface PopoverItem { * True if popover should close once item is activated */ closeOnActivate?: boolean; + + /** + * If action requires confirmation, first click on the item will turn it into object specified in this field. + * Second click will perform the action. + */ + confirmation?: boolean | Partial; + } /** @@ -146,6 +153,7 @@ export default class Popover extends EventsDispatcher { itemLabel: string; itemIcon: string; itemSecondaryLabel: string; + itemConfirmation: string; noFoundMessage: string; noFoundMessageShown: string; popoverOverlay: string; @@ -162,6 +170,7 @@ export default class Popover extends EventsDispatcher { itemFlippable: 'ce-popover__item--flippable', itemFocused: 'ce-popover__item--focused', itemActive: 'ce-popover__item--active', + itemConfirmation: 'ce-popover__item--confirmation', itemLabel: 'ce-popover__item-label', itemIcon: 'ce-popover__item-icon', itemSecondaryLabel: 'ce-popover__item-secondary-label', @@ -184,6 +193,11 @@ export default class Popover extends EventsDispatcher { */ private api: API; + /** + * Reference to popover item that was clicked but requires second click to confirm action + */ + private itemAwaitngConfirmation = null; + /** * Creates the Popover * @@ -286,6 +300,8 @@ export default class Popover extends EventsDispatcher { this.isShown = false; this.nodes.wrapper.classList.remove(this.className + '--opened-top'); + + this.cleanUpConfirmationState(); } /** @@ -460,6 +476,12 @@ export default class Popover extends EventsDispatcher { const itemIndex = Array.from(allItems).indexOf(itemEl); const clickedItem = this.items[itemIndex]; + const ignoreClick = this.handleConfirmation(itemEl, clickedItem); + + if (ignoreClick) { + return; + } + clickedItem.onClick(clickedItem, event); if (clickedItem.closeOnActivate) { @@ -467,6 +489,57 @@ export default class Popover extends EventsDispatcher { } } + /** + * Handles case when item needs confirmation before calling onClick callback. + * Returns true if click should be ignored. + * + * @param itemEl - clicked HTML element + * @param clickedItem - corresponding popover item + */ + private handleConfirmation(itemEl: HTMLElement, clickedItem: PopoverItem): boolean { + if (this.itemAwaitngConfirmation !== clickedItem && clickedItem.confirmation) { + /** + * Item requires confirmation. + * If configured, item's label, icon and other params should be replaced with values defined for confirmation state. + * Click is ignored. + */ + this.itemAwaitngConfirmation = clickedItem; + + const itemData = { + ...clickedItem, + ...clickedItem.confirmation as PopoverItem, + confirmation: false, + }; + const confirmationStateItemEl = this.createItem(itemData); + + confirmationStateItemEl.classList.add(Popover.CSS.itemConfirmation); + itemEl.parentElement.replaceChild(confirmationStateItemEl, itemEl); + + return true; + } + + /** + * If item requiring confirmation is clicked for the second time or any other item is clicked, + * get rid of confirmation state on item + */ + this.cleanUpConfirmationState(); + } + + /** + * If popover contains an item in confirmation state, bring it to default state + */ + private cleanUpConfirmationState(): void { + if (!this.itemAwaitngConfirmation) { + return; + } + const defaultStateItemEl = this.createItem(this.itemAwaitngConfirmation); + const confirmationStateItemEl = this.nodes.wrapper.querySelector(`.${Popover.CSS.itemConfirmation}`); + + confirmationStateItemEl.parentElement.replaceChild(defaultStateItemEl, confirmationStateItemEl); + defaultStateItemEl.classList.remove(Popover.CSS.itemConfirmation); + this.itemAwaitngConfirmation = null; + } + /** * Creates Flipper instance to be able to leaf tools */ diff --git a/src/styles/popover.css b/src/styles/popover.css index 31d62326..076e7617 100644 --- a/src/styles/popover.css +++ b/src/styles/popover.css @@ -76,6 +76,25 @@ @apply --button-active; } + &--confirmation { + background: var(--color-confirm); + + @media (--can-hover) { + &:hover { + background: #ce4343; + } + } + + .ce-popover__item-icon { + color: var(--color-confirm); + } + + .ce-popover__item-label { + color: white; + } + + } + &-icon { @apply --tool-icon; } diff --git a/src/styles/variables.css b/src/styles/variables.css index 41e97471..e8be603a 100644 --- a/src/styles/variables.css +++ b/src/styles/variables.css @@ -106,7 +106,7 @@ --button-active: { background: rgba(56, 138, 229, 0.1); - color: #388AE5; + color: var(--color-active-icon); }; /**