feat: Add toggle group support (#2195)

* Add toggle group support

* Update version and changelog

* Fix

* Simplify

* Update test/cypress/tests/utils/popover.spec.ts

Co-authored-by: Peter Savchenko <specc.dev@gmail.com>

Co-authored-by: Peter Savchenko <specc.dev@gmail.com>
This commit is contained in:
Tatiana Fomina 2022-12-01 21:58:58 +04:00 committed by GitHub
parent 320a30afcc
commit 913ad0c8dc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 125 additions and 7 deletions

View file

@ -1,6 +1,9 @@
# Changelog
### 2.26.1
- `Improvement`*Menu Config* — Now it becomes possible to create toggle groups.
### 2.26.0
- `New`*UI* — Block Tunes became vertical just like the Toolbox 🤩

View file

@ -1,6 +1,6 @@
{
"name": "@editorjs/editorjs",
"version": "2.26.0",
"version": "2.26.1",
"description": "Editor.js — Native JS, based on API and Open Source",
"main": "dist/editor.js",
"types": "./types/index.d.ts",

View file

@ -491,16 +491,54 @@ export default class Popover extends EventsDispatcher<PopoverEvent> {
}
clickedItem.onActivate(clickedItem, event);
if (clickedItem.toggle) {
clickedItem.isActive = !clickedItem.isActive;
itemEl.classList.toggle(Popover.CSS.itemActive);
}
this.toggleIfNeeded(itemIndex, allItems);
if (clickedItem.closeOnActivate) {
this.hide();
}
}
/**
* - Toggles item active state, if the item has property 'toggle' set to true.
*
* - Performs radiobutton-like behavior if the item has property 'toggle' set to string key.
* (All the other items with the same key get unactive, and the item gets active)
*
* @param index - clicked item index
* @param itemEls - array of html elements representing popover items
*/
private toggleIfNeeded(index: number, itemEls: Element[]): void {
const clickedItem = this.items[index];
if (clickedItem.toggle === true) {
clickedItem.isActive = !clickedItem.isActive;
itemEls[index].classList.toggle(Popover.CSS.itemActive);
return;
}
if (typeof clickedItem.toggle === 'string') {
const itemsInToggleGroup = this.items.filter(item => item.toggle === clickedItem.toggle);
/** If there's only one item in toggle group, toggle it */
if (itemsInToggleGroup.length === 1) {
clickedItem.isActive = !clickedItem.isActive;
itemEls[index].classList.toggle(Popover.CSS.itemActive);
return;
}
/** Set clicked item as active and the rest items with same toggle key value as inactive */
itemsInToggleGroup.forEach((item: PopoverItem) => {
const i = this.items.indexOf(item);
const newState = item === clickedItem;
item.isActive = newState;
itemEls[i].classList.toggle(Popover.CSS.itemActive, newState);
});
}
}
/**
* Enables confirmation state for specified item.
* Replaces item element in popover so that is becomes highlighted in a special way

View file

@ -185,4 +185,79 @@ describe('Popover', () => {
.should('have.class', 'ce-popover__item--active');
});
});
it('should perform radiobutton-like behavior among the items that have toggle property value set to the same string value', () => {
const items: PopoverItem[] = [
{
icon: 'Icon 1',
label: 'Label 1',
toggle: 'group-name',
name: 'testItem1',
isActive: true,
onActivate: (): void => {},
},
{
icon: 'Icon 2',
label: 'Label 2',
toggle: 'group-name',
name: 'testItem2',
onActivate: (): void => {},
},
];
const popover = new Popover({
items,
filterLabel: '',
nothingFoundLabel: '',
scopeElement: null,
});
cy.document().then(doc => {
doc.body.append(popover.getElement());
/** Check first item is active */
cy.get('[data-item-name=testItem1]')
.should('have.class', 'ce-popover__item--active');
/** Check second item is not active */
cy.get('[data-item-name=testItem2]')
.should('not.have.class', 'ce-popover__item--active');
/* Click second item and check it became active */
cy.get('[data-item-name=testItem2]')
.click()
.should('have.class', 'ce-popover__item--active');
/** Check first item became not active */
cy.get('[data-item-name=testItem1]')
.should('not.have.class', 'ce-popover__item--active');
});
});
it('should toggle item if it is the only item in toggle group', () => {
const items: PopoverItem[] = [
{
icon: 'Icon',
label: 'Label',
toggle: 'key',
name: 'testItem',
onActivate: (): void => {},
},
];
const popover = new Popover({
items,
filterLabel: '',
nothingFoundLabel: '',
scopeElement: null,
});
cy.document().then(doc => {
doc.body.append(popover.getElement());
/* Check item has active class */
cy.get('[data-item-name=testItem]')
.click()
.should('have.class', 'ce-popover__item--active');
});
});
});

View file

@ -39,9 +39,11 @@ interface PopoverItemBase {
name?: string;
/**
* True if item should be highlighted once activated
* Defines whether item should toggle on click.
* Can be represented as boolean value or a string key.
* In case of string, works like radio buttons group and highlights as inactive any other item that has same toggle key value.
*/
toggle?: boolean;
toggle?: boolean | string;
}
/**