Skip to content

Commit

Permalink
fix(styling): better support of auto width on drop menu
Browse files Browse the repository at this point in the history
- now every menu control/plugin will have much better support of `width: auto` (resized by its content), the side effect is that we no longer have a fixed width provided and user must pay attention to final width  and in that use case we also added `maxWidth`
  • Loading branch information
ghiscoding committed Nov 26, 2021
1 parent d15022b commit 8a48dd2
Show file tree
Hide file tree
Showing 27 changed files with 260 additions and 228 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,6 @@ export class Example12 {
formatter: () => `<div class="button-style margin-auto" style="width: 35px; margin-top: -1px;"><span class="mdi mdi-chevron-down mdi-22px color-primary"></span></div>`,
cellMenu: {
hideCloseButton: false,
width: 175,
commandTitle: 'Commands',
commandItems: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,6 @@ export class Example14 {
formatter: () => `<div class="button-style margin-auto" style="width: 35px; margin-top: -1px;"><span class="mdi mdi-chevron-down mdi-22px color-primary"></span></div>`,
cellMenu: {
hideCloseButton: false,
width: 175,
commandTitle: 'Commands',
commandItems: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const gridOptionsMock = {
autoAlignSideOffset: 0,
hideMenuOnScroll: true,
maxHeight: 'none',
maxWidth: 'none',
width: 175,
onExtensionRegistered: jest.fn(),
onCommand: () => { },
Expand Down Expand Up @@ -156,7 +157,6 @@ describe('CellMenu Plugin', () => {
autoAdjustDropOffset: 0,
autoAlignSideOffset: 0,
hideMenuOnScroll: true,
maxHeight: 'none',
width: 'auto',
});
});
Expand Down Expand Up @@ -273,11 +273,11 @@ describe('CellMenu Plugin', () => {
expect(cellMenuElm.classList.contains('dropright'));
expect(commandListElm.querySelectorAll('.slick-cell-menu-item').length).toBe(5);
expect(removeExtraSpaces(document.body.innerHTML)).toBe(removeExtraSpaces(
`<div style="display: block; width: auto; max-height: none; top: 0px; left: 0px;" class="slick-cell-menu slickgrid12345 dropdown dropright" aria-expanded="true">
<button class="close" type="button" data-dismiss="slick-cell-menu" aria-label="Close">
<span class="close" aria-hidden="true">×</span>
</button>
`<div class="slick-cell-menu slickgrid12345 dropdown dropright" style="display: block; width: auto; top: 0px; left: 0px;" aria-expanded="true">
<div class="slick-cell-menu-command-list">
<div class="command-header with-close no-title">
<button class="close" type="button" data-dismiss="slick-cell-menu" aria-label="Close">×</button>
</div>
<li class="slick-cell-menu-item orange" data-command="command1">
<div class="slick-cell-menu-icon"></div>
<span class="slick-cell-menu-content">Command 1</span>
Expand Down Expand Up @@ -328,7 +328,7 @@ describe('CellMenu Plugin', () => {

it('should expect a Cell Menu to be created when cell is clicked with a list of commands defined but without "Command 1" when "itemVisibilityOverride" and "itemUsabilityOverride" return false', () => {
plugin.dispose();
plugin.init();
plugin.init({ maxHeight: 290 });
(columnsMock[3].cellMenu.commandItems[1] as MenuCommandItem).itemVisibilityOverride = () => false;
(columnsMock[3].cellMenu.commandItems[1] as MenuCommandItem).itemUsabilityOverride = () => false;
gridStub.onClick.notify({ cell: 3, row: 1, grid: gridStub }, eventData, gridStub);
Expand All @@ -341,6 +341,7 @@ describe('CellMenu Plugin', () => {
const commandIconElm1 = commandItemElm1.querySelector('.slick-cell-menu-icon') as HTMLDivElement;

expect(closeBtnElm).toBeTruthy();
expect(cellMenuElm.style.maxHeight).toBe('290px');
expect(commandListElm.querySelectorAll('.slick-cell-menu-item').length).toBe(4);
expect(commandItemElm1.classList.contains('orange')).toBeTruthy();
expect(commandIconElm1.className).toBe('slick-cell-menu-icon');
Expand All @@ -350,7 +351,7 @@ describe('CellMenu Plugin', () => {

it('should create a Cell Menu and a 2nd button item usability callback returns false and expect button to be disabled', () => {
plugin.dispose();
plugin.init();
plugin.init({ maxWidth: 310 });
(columnsMock[3].cellMenu.commandItems[1] as MenuCommandItem).itemVisibilityOverride = () => true;
(columnsMock[3].cellMenu.commandItems[1] as MenuCommandItem).itemUsabilityOverride = () => false;
gridStub.onClick.notify({ cell: 3, row: 1, grid: gridStub }, eventData, gridStub);
Expand All @@ -363,6 +364,7 @@ describe('CellMenu Plugin', () => {
const commandIconElm1 = commandItemElm1.querySelector('.slick-cell-menu-icon') as HTMLDivElement;

expect(closeBtnElm).toBeTruthy();
expect(cellMenuElm.style.maxWidth).toBe('310px');
expect(commandListElm.querySelectorAll('.slick-cell-menu-item').length).toBe(5);
expect(commandItemElm1.classList.contains('orange')).toBeTruthy();
expect(commandIconElm1.className).toBe('slick-cell-menu-icon');
Expand Down Expand Up @@ -662,11 +664,11 @@ describe('CellMenu Plugin', () => {

expect(optionListElm.querySelectorAll('.slick-cell-menu-item').length).toBe(5);
expect(removeExtraSpaces(document.body.innerHTML)).toBe(removeExtraSpaces(
`<div style="display: block; width: auto; max-height: none; top: 0px; left: 0px;" class="slick-cell-menu slickgrid12345 dropdown dropright" aria-expanded="true">
<button class="close" type="button" data-dismiss="slick-cell-menu" aria-label="Close">
<span class="close" aria-hidden="true">×</span>
</button>
`<div class="slick-cell-menu slickgrid12345 dropdown dropright" style="display: block; width: auto; top: 0px; left: 0px;" aria-expanded="true">
<div class="slick-cell-menu-option-list">
<div class="option-header with-close no-title">
<button class="close" type="button" data-dismiss="slick-cell-menu" aria-label="Close">×</button>
</div>
<li class="slick-cell-menu-item purple" data-option="option1">
<div class="slick-cell-menu-icon"></div>
<span class="slick-cell-menu-content">Option 1</span>
Expand Down
23 changes: 12 additions & 11 deletions packages/common/src/extensions/__tests__/slickContextMenu.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,6 @@ describe('ContextMenu Plugin', () => {
autoAlignSideOffset: 0,
commandItems: [],
hideMenuOnScroll: false,
maxHeight: 'none',
width: 'auto',
optionShownOverColumnIds: [],
commandShownOverColumnIds: [],
Expand Down Expand Up @@ -304,11 +303,11 @@ describe('ContextMenu Plugin', () => {
expect(contextMenuElm.classList.contains('dropright'));
expect(commandListElm.querySelectorAll('.slick-context-menu-item').length).toBe(5);
expect(removeExtraSpaces(document.body.innerHTML)).toBe(removeExtraSpaces(
`<div style="display: block; width: auto; max-height: none; top: 0px; left: 0px;" class="slick-context-menu slickgrid12345 dropdown dropright" aria-expanded="true">
<button class="close" type="button" data-dismiss="slick-context-menu" aria-label="Close">
<span class="close" aria-hidden="true">×</span>
</button>
`<div class="slick-context-menu slickgrid12345 dropdown dropright" style="display: block; width: auto; top: 0px; left: 0px;" aria-expanded="true">
<div class="slick-context-menu-command-list">
<div class="command-header with-close no-title">
<button class="close" type="button" data-dismiss="slick-context-menu" aria-label="Close">×</button>
</div>
<li class="slick-context-menu-item orange" data-command="command1">
<div class="slick-context-menu-icon"></div>
<span class="slick-context-menu-content">Command 1</span>
Expand Down Expand Up @@ -415,7 +414,7 @@ describe('ContextMenu Plugin', () => {

it('should create a Context Menu and a 2nd item is "disabled" and expect button to be disabled', () => {
plugin.dispose();
plugin.init({ commandItems: deepCopy(commandItemsMock) });
plugin.init({ commandItems: deepCopy(commandItemsMock), maxHeight: 290 });
(gridOptionsMock.contextMenu.commandItems[1] as MenuCommandItem).disabled = true;
gridStub.onContextMenu.notify({ grid: gridStub }, eventData, gridStub);

Expand All @@ -424,14 +423,15 @@ describe('ContextMenu Plugin', () => {
const commandItemElm2 = commandListElm.querySelector('[data-command="command2"]') as HTMLDivElement;
const commandContentElm2 = commandItemElm2.querySelector('.slick-context-menu-content') as HTMLDivElement;

expect(contextMenuElm.style.maxHeight).toBe('290px');
expect(commandListElm.querySelectorAll('.slick-context-menu-item').length).toBe(5);
expect(commandContentElm2.textContent).toBe('Command 2');
expect(commandItemElm2.classList.contains('slick-context-menu-item-disabled')).toBeTruthy();
});

it('should create a Context Menu and expect button to be disabled when command property is hidden', () => {
plugin.dispose();
plugin.init({ commandItems: deepCopy(commandItemsMock) });
plugin.init({ commandItems: deepCopy(commandItemsMock), maxWidth: 310 });
(gridOptionsMock.contextMenu.commandItems[1] as MenuCommandItem).hidden = true;
gridStub.onContextMenu.notify({ grid: gridStub }, eventData, gridStub);

Expand All @@ -440,6 +440,7 @@ describe('ContextMenu Plugin', () => {
const commandItemElm2 = commandListElm.querySelector('[data-command="command2"]') as HTMLDivElement;
const commandContentElm2 = commandItemElm2.querySelector('.slick-context-menu-content') as HTMLDivElement;

expect(contextMenuElm.style.maxWidth).toBe('310px');
expect(commandListElm.querySelectorAll('.slick-context-menu-item').length).toBe(5);
expect(commandContentElm2.textContent).toBe('Command 2');
expect(commandItemElm2.classList.contains('slick-context-menu-item-hidden')).toBeTruthy();
Expand Down Expand Up @@ -1226,11 +1227,11 @@ describe('ContextMenu Plugin', () => {

expect(optionListElm.querySelectorAll('.slick-context-menu-item').length).toBe(5);
expect(removeExtraSpaces(document.body.innerHTML)).toBe(removeExtraSpaces(
`<div style="display: block; width: auto; max-height: none; top: 0px; left: 0px;" class="slick-context-menu slickgrid12345 dropdown dropright" aria-expanded="true">
<button class="close" type="button" data-dismiss="slick-context-menu" aria-label="Close">
<span class="close" aria-hidden="true">×</span>
</button>
`<div class="slick-context-menu slickgrid12345 dropdown dropright" style="display: block; width: auto; top: 0px; left: 0px;" aria-expanded="true">
<div class="slick-context-menu-option-list">
<div class="option-header with-close no-title">
<button class="close" type="button" data-dismiss="slick-context-menu" aria-label="Close">×</button>
</div>
<li class="slick-context-menu-item purple" data-option="option1">
<div class="slick-context-menu-icon"></div>
<span class="slick-context-menu-content">Option 1</span>
Expand Down
5 changes: 1 addition & 4 deletions packages/common/src/extensions/extensionCommonUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,10 @@ export function addCloseButtomElement(this: SlickColumnPicker | SlickGridMenu, m
const context: any = this;
const closePickerButtonElm = createDomElement('button', {
type: 'button', className: 'close',
innerHTML: '&times;',
dataset: { dismiss: context instanceof SlickColumnPicker ? 'slick-columnpicker' : 'slick-grid-menu' }
});
closePickerButtonElm.setAttribute('aria-label', 'Close');

const closeSpanElm = createDomElement('span', { className: 'close', innerHTML: '&times;' });
closeSpanElm.setAttribute('aria-hidden', 'true');
closePickerButtonElm.appendChild(closeSpanElm);
menuElm.appendChild(closePickerButtonElm);
}

Expand Down
18 changes: 10 additions & 8 deletions packages/common/src/extensions/menuBaseClass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ export class MenuBaseClass<M extends CellMenu | ContextMenu | GridMenu | HeaderM
protected _addonOptions: M = {} as unknown as M;
protected _bindEventService: BindingEventService;
protected _camelPluginName = '';
protected _commandTitleElm?: HTMLDivElement;
protected _commandTitleElm?: HTMLSpanElement;
protected _eventHandler: SlickEventHandler;
protected _gridUid = '';
protected _menuElm?: HTMLDivElement | null;
protected _menuCssPrefix = '';
protected _optionTitleElm?: HTMLDivElement;
protected _optionTitleElm?: HTMLSpanElement;

/** Constructor of the SlickGrid 3rd party plugin, it can optionally receive options */
constructor(
Expand Down Expand Up @@ -119,15 +119,17 @@ export class MenuBaseClass<M extends CellMenu | ContextMenu | GridMenu | HeaderM
itemClickCallback: (event: DOMMouseEvent<HTMLDivElement>, type: MenuType, item: ExtractMenuType<ExtendableItemTypes, MenuType>, columnDef?: Column) => void
) {
if (args && commandOrOptionItems && menuOptions) {
const menuHeaderElm = this._menuElm?.querySelector(`.${itemType}-header`) ?? createDomElement('div', { className: `${itemType}-header` });
// user could pass a title on top of the Commands/Options section
const titleProp = itemType === 'command' ? 'commandTitle' : 'optionTitle';
const titleProp: 'commandTitle' | 'optionTitle' = `${itemType}Title`;
if ((menuOptions as CellMenu | ContextMenu)?.[titleProp]) {
this[`_${itemType}TitleElm`] = createDomElement('div', {
className: 'title',
textContent: (menuOptions as never)[titleProp],
});
commandOrOptionMenuElm.appendChild(this[`_${itemType}TitleElm`]!);
this[`_${itemType}TitleElm`] = createDomElement('span', { className: 'title', textContent: (menuOptions as never)[titleProp] });
menuHeaderElm.appendChild(this[`_${itemType}TitleElm`]!);
menuHeaderElm.classList.add('with-title');
} else {
menuHeaderElm.classList.add('no-title');
}
commandOrOptionMenuElm.appendChild(menuHeaderElm);
for (const item of commandOrOptionItems) {
this.populateSingleCommandOrOptionItem(itemType, menuOptions, commandOrOptionMenuElm, item, args, itemClickCallback);
}
Expand Down
28 changes: 17 additions & 11 deletions packages/common/src/extensions/menuFromCellBaseClass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,35 +80,38 @@ export class MenuFromCellBaseClass<M extends CellMenu | ContextMenu> extends Men
}
}

const maxHeight = isNaN(this.addonOptions.maxHeight as any) ? this.addonOptions.maxHeight : `${this.addonOptions.maxHeight ?? 0}px`;

// create a new Menu
this._menuElm = createDomElement('div', {
className: `${this._menuCssPrefix} ${this.gridUid}`,
style: {
display: 'none',
left: `${event.pageX}px`, top: `${event.pageY + 5}px`,
width: findWidthOrDefault(this.addonOptions?.width),
}
});
this._menuElm.classList.add(this._menuCssPrefix);
this._menuElm.classList.add(this.gridUid);

const maxHeight = isNaN(this.addonOptions.maxHeight as any) ? this.addonOptions.maxHeight : `${this.addonOptions.maxHeight ?? 0}px`;
const maxWidth = isNaN(this.addonOptions.maxWidth as any) ? this.addonOptions.maxWidth : `${this.addonOptions.maxWidth ?? 0}px`;

if (maxHeight) {
this._menuElm.style.maxHeight = maxHeight as string;
}
if (maxWidth) {
this._menuElm.style.maxWidth = maxWidth as string;
}

const closeButtonElm = createDomElement('button', { className: 'close', type: 'button', dataset: { dismiss: this._menuCssPrefix } });
const closeButtonElm = createDomElement('button', { className: 'close', type: 'button', innerHTML: '&times;', dataset: { dismiss: this._menuCssPrefix } });
closeButtonElm.setAttribute('aria-label', 'Close');

const closeSpanElm = createDomElement('span', { className: 'close', innerHTML: '&times;' });
closeSpanElm.setAttribute('aria-hidden', 'true');
closeButtonElm.appendChild(closeSpanElm);

// -- Option List section
if (!(this.addonOptions as CellMenu | ContextMenu).hideOptionSection && isColumnOptionAllowed && optionItems.length > 0) {
const optionMenuElm = createDomElement('div', { className: `${this._menuCssPrefix}-option-list` });
if (!this.addonOptions.hideCloseButton) {
this._bindEventService.bind(closeButtonElm, 'click', ((e: DOMMouseEvent<HTMLDivElement>) => this.handleCloseButtonClicked(e)) as EventListener);
this._menuElm.appendChild(closeButtonElm);
const optionMenuHeaderElm = createDomElement('div', { className: 'option-header' });
optionMenuHeaderElm?.appendChild(closeButtonElm);
optionMenuElm.appendChild(optionMenuHeaderElm);
optionMenuHeaderElm.classList.add('with-close');
}
this._menuElm.appendChild(optionMenuElm);
this.populateCommandOrOptionItems(
Expand All @@ -126,7 +129,10 @@ export class MenuFromCellBaseClass<M extends CellMenu | ContextMenu> extends Men
const commandMenuElm = createDomElement('div', { className: `${this._menuCssPrefix}-command-list` });
if (!this.addonOptions.hideCloseButton && (!isColumnOptionAllowed || optionItems.length === 0 || (this.addonOptions as CellMenu | ContextMenu).hideOptionSection)) {
this._bindEventService.bind(closeButtonElm, 'click', ((e: DOMMouseEvent<HTMLDivElement>) => this.handleCloseButtonClicked(e)) as EventListener);
this._menuElm.appendChild(closeButtonElm);
const commandMenuHeaderElm = createDomElement('div', { className: 'command-header' });
commandMenuHeaderElm?.appendChild(closeButtonElm);
commandMenuElm.appendChild(commandMenuHeaderElm);
commandMenuHeaderElm.classList.add('with-close');
}
this._menuElm.appendChild(commandMenuElm);
this.populateCommandOrOptionItems(
Expand Down
1 change: 0 additions & 1 deletion packages/common/src/extensions/slickCellMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ export class SlickCellMenu extends MenuFromCellBaseClass<CellMenu> {
autoAdjustDropOffset: 0,
autoAlignSideOffset: 0,
hideMenuOnScroll: true,
maxHeight: 'none',
width: 'auto',
} as unknown as CellMenuOption;
pluginName: 'CellMenu' = 'CellMenu';
Expand Down
1 change: 0 additions & 1 deletion packages/common/src/extensions/slickContextMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ export class SlickContextMenu extends MenuFromCellBaseClass<ContextMenu> {
autoAdjustDropOffset: 0,
autoAlignSideOffset: 0,
hideMenuOnScroll: false,
maxHeight: 'none',
width: 'auto',
optionShownOverColumnIds: [],
commandShownOverColumnIds: [],
Expand Down
Loading

0 comments on commit 8a48dd2

Please sign in to comment.