mirror of
https://github.com/codex-team/editor.js
synced 2024-05-08 01:16:46 +02:00
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:
parent
320a30afcc
commit
913ad0c8dc
|
@ -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 🤩
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
6
types/configs/popover.d.ts
vendored
6
types/configs/popover.d.ts
vendored
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue