mirror of
https://github.com/codex-team/editor.js
synced 2024-05-19 14:56: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
|
# Changelog
|
||||||
|
|
||||||
|
|
||||||
|
### 2.26.1
|
||||||
|
- `Improvement` — *Menu Config* — Now it becomes possible to create toggle groups.
|
||||||
|
|
||||||
### 2.26.0
|
### 2.26.0
|
||||||
|
|
||||||
- `New` — *UI* — Block Tunes became vertical just like the Toolbox 🤩
|
- `New` — *UI* — Block Tunes became vertical just like the Toolbox 🤩
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@editorjs/editorjs",
|
"name": "@editorjs/editorjs",
|
||||||
"version": "2.26.0",
|
"version": "2.26.1",
|
||||||
"description": "Editor.js — Native JS, based on API and Open Source",
|
"description": "Editor.js — Native JS, based on API and Open Source",
|
||||||
"main": "dist/editor.js",
|
"main": "dist/editor.js",
|
||||||
"types": "./types/index.d.ts",
|
"types": "./types/index.d.ts",
|
||||||
|
|
|
@ -491,16 +491,54 @@ export default class Popover extends EventsDispatcher<PopoverEvent> {
|
||||||
}
|
}
|
||||||
clickedItem.onActivate(clickedItem, event);
|
clickedItem.onActivate(clickedItem, event);
|
||||||
|
|
||||||
if (clickedItem.toggle) {
|
this.toggleIfNeeded(itemIndex, allItems);
|
||||||
clickedItem.isActive = !clickedItem.isActive;
|
|
||||||
itemEl.classList.toggle(Popover.CSS.itemActive);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clickedItem.closeOnActivate) {
|
if (clickedItem.closeOnActivate) {
|
||||||
this.hide();
|
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.
|
* Enables confirmation state for specified item.
|
||||||
* Replaces item element in popover so that is becomes highlighted in a special way
|
* 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');
|
.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;
|
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