mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-09 13:15:51 +08:00
feat(editor): add date grouping configurations (#12679)
https://github.com/user-attachments/assets/d5578060-2c8c-47a5-ba65-ef2e9430518b This PR adds the ability to group-by date with configuration which an example is shown in the image below:  <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Date-based grouping modes (relative, day, week Sun/Mon, month, year), a date group renderer, and quick lookup for group-by configs by name. * **Improvements** * Enhanced group settings: date sub‑modes, week‑start, per‑group visibility, Hide All/Show All, date sort order, improved drag/drop and reorder. * Consistent popup placement/middleware, nested popup positioning, per‑item close-on-select, and enforced minimum menu heights. * UI: empty groups now display "No <property>"; views defensively handle null/hidden groups. * **Tests** * Added unit tests for date-key sorting and comparison. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Norkz <richardlora557@gmail.com> Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
This commit is contained in:
+22
-3
@@ -4,7 +4,6 @@ import {
|
||||
popMenu,
|
||||
type PopupTarget,
|
||||
popupTargetFromElement,
|
||||
subMenuMiddleware,
|
||||
} from '@blocksuite/affine-components/context-menu';
|
||||
import { SignalWatcher } from '@blocksuite/global/lit';
|
||||
import {
|
||||
@@ -13,6 +12,7 @@ import {
|
||||
DeleteIcon,
|
||||
} from '@blocksuite/icons/lit';
|
||||
import { ShadowlessElement } from '@blocksuite/std';
|
||||
import { autoPlacement, offset, shift } from '@floating-ui/dom';
|
||||
import { computed, type ReadonlySignal } from '@preact/signals-core';
|
||||
import { css, html } from 'lit';
|
||||
import { property } from 'lit/decorators.js';
|
||||
@@ -99,6 +99,11 @@ export class FilterConditionView extends SignalWatcher(ShadowlessElement) {
|
||||
return;
|
||||
}
|
||||
const handler = popMenu(target, {
|
||||
middleware: [
|
||||
autoPlacement({ allowedPlacements: ['bottom-start'] }),
|
||||
offset({ mainAxis: 4, crossAxis: 0 }),
|
||||
shift({ crossAxis: true }),
|
||||
],
|
||||
options: {
|
||||
items: [
|
||||
menu.group({
|
||||
@@ -107,7 +112,7 @@ export class FilterConditionView extends SignalWatcher(ShadowlessElement) {
|
||||
name: fn.label,
|
||||
postfix: ArrowRightSmallIcon(),
|
||||
select: ele => {
|
||||
popMenu(popupTargetFromElement(ele), {
|
||||
const subHandler = popMenu(popupTargetFromElement(ele), {
|
||||
options: {
|
||||
items: [
|
||||
menu.group({
|
||||
@@ -117,8 +122,18 @@ export class FilterConditionView extends SignalWatcher(ShadowlessElement) {
|
||||
}),
|
||||
],
|
||||
},
|
||||
middleware: subMenuMiddleware,
|
||||
middleware: [
|
||||
autoPlacement({
|
||||
allowedPlacements: ['bottom-start'],
|
||||
}),
|
||||
offset({ mainAxis: 4, crossAxis: 0 }),
|
||||
shift({ crossAxis: true }),
|
||||
],
|
||||
});
|
||||
// allow submenu height and width to adjust to content
|
||||
subHandler.menu.menuElement.style.minHeight = 'fit-content';
|
||||
subHandler.menu.menuElement.style.maxHeight = 'fit-content';
|
||||
subHandler.menu.menuElement.style.minWidth = '200px';
|
||||
return false;
|
||||
},
|
||||
}),
|
||||
@@ -142,6 +157,10 @@ export class FilterConditionView extends SignalWatcher(ShadowlessElement) {
|
||||
],
|
||||
},
|
||||
});
|
||||
// allow main menu height and width to adjust to calendar size
|
||||
handler.menu.menuElement.style.minHeight = 'fit-content';
|
||||
handler.menu.menuElement.style.maxHeight = 'fit-content';
|
||||
handler.menu.menuElement.style.minWidth = '200px';
|
||||
};
|
||||
|
||||
@property({ attribute: false })
|
||||
|
||||
+67
-72
@@ -1,10 +1,8 @@
|
||||
import {
|
||||
menu,
|
||||
popFilterableSimpleMenu,
|
||||
popMenu,
|
||||
type PopupTarget,
|
||||
popupTargetFromElement,
|
||||
subMenuMiddleware,
|
||||
} from '@blocksuite/affine-components/context-menu';
|
||||
import { SignalWatcher } from '@blocksuite/global/lit';
|
||||
import {
|
||||
@@ -17,6 +15,7 @@ import {
|
||||
PlusIcon,
|
||||
} from '@blocksuite/icons/lit';
|
||||
import { ShadowlessElement } from '@blocksuite/std';
|
||||
import { type Middleware, offset } from '@floating-ui/dom';
|
||||
import { computed, type ReadonlySignal } from '@preact/signals-core';
|
||||
import { css, html } from 'lit';
|
||||
import { property, state } from 'lit/decorators.js';
|
||||
@@ -208,66 +207,64 @@ export class FilterRootView extends SignalWatcher(ShadowlessElement) {
|
||||
if (!filter) {
|
||||
return;
|
||||
}
|
||||
popFilterableSimpleMenu(popupTargetFromElement(target), [
|
||||
menu.action({
|
||||
name: filter.type === 'filter' ? 'Turn into group' : 'Wrap in group',
|
||||
prefix: ConvertIcon(),
|
||||
onHover: hover => {
|
||||
this.containerClass = hover
|
||||
? { index: i, class: 'hover-style' }
|
||||
: undefined;
|
||||
},
|
||||
hide: () => getDepth(filter) > 3,
|
||||
select: () => {
|
||||
this.onChange({
|
||||
type: 'group',
|
||||
op: 'and',
|
||||
conditions: [this.filterGroup.value],
|
||||
});
|
||||
},
|
||||
}),
|
||||
menu.action({
|
||||
name: 'Duplicate',
|
||||
prefix: DuplicateIcon(),
|
||||
onHover: hover => {
|
||||
this.containerClass = hover
|
||||
? { index: i, class: 'hover-style' }
|
||||
: undefined;
|
||||
},
|
||||
select: () => {
|
||||
const conditions = [...this.filterGroup.value.conditions];
|
||||
conditions.splice(
|
||||
i + 1,
|
||||
0,
|
||||
JSON.parse(JSON.stringify(conditions[i]))
|
||||
);
|
||||
this.onChange({ ...this.filterGroup.value, conditions: conditions });
|
||||
},
|
||||
}),
|
||||
menu.group({
|
||||
name: '',
|
||||
const handler = popMenu(popupTargetFromElement(target), {
|
||||
placement: 'bottom-end',
|
||||
middleware: [offset({ mainAxis: 12, crossAxis: 0 })],
|
||||
options: {
|
||||
items: [
|
||||
menu.action({
|
||||
name: 'Delete',
|
||||
prefix: DeleteIcon(),
|
||||
class: { 'delete-item': true },
|
||||
onHover: hover => {
|
||||
this.containerClass = hover
|
||||
? { index: i, class: 'delete-style' }
|
||||
: undefined;
|
||||
},
|
||||
name:
|
||||
filter.type === 'filter' ? 'Turn into group' : 'Wrap in group',
|
||||
prefix: ConvertIcon(),
|
||||
hide: () => getDepth(filter) > 3,
|
||||
select: () => {
|
||||
const conditions = [...this.filterGroup.value.conditions];
|
||||
conditions.splice(i, 1);
|
||||
this.onChange({
|
||||
...this.filterGroup.value,
|
||||
conditions,
|
||||
type: 'group',
|
||||
op: 'and',
|
||||
conditions: [this.filterGroup.value],
|
||||
});
|
||||
},
|
||||
}),
|
||||
menu.action({
|
||||
name: 'Duplicate',
|
||||
prefix: DuplicateIcon(),
|
||||
select: () => {
|
||||
const conditions = [...this.filterGroup.value.conditions];
|
||||
conditions.splice(
|
||||
i + 1,
|
||||
0,
|
||||
JSON.parse(JSON.stringify(conditions[i]))
|
||||
);
|
||||
this.onChange({
|
||||
...this.filterGroup.value,
|
||||
conditions: conditions,
|
||||
});
|
||||
},
|
||||
}),
|
||||
menu.group({
|
||||
name: '',
|
||||
items: [
|
||||
menu.action({
|
||||
name: 'Delete',
|
||||
prefix: DeleteIcon(),
|
||||
class: { 'delete-item': true },
|
||||
select: () => {
|
||||
const conditions = [...this.filterGroup.value.conditions];
|
||||
conditions.splice(i, 1);
|
||||
this.onChange({
|
||||
...this.filterGroup.value,
|
||||
conditions,
|
||||
});
|
||||
},
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
]);
|
||||
},
|
||||
});
|
||||
handler.menu.menuElement.style.minWidth = '200px';
|
||||
handler.menu.menuElement.style.maxWidth = 'fit-content';
|
||||
handler.menu.menuElement.style.minHeight = 'fit-content';
|
||||
}
|
||||
|
||||
private deleteFilter(i: number) {
|
||||
@@ -378,16 +375,20 @@ export const popFilterRoot = (
|
||||
props: {
|
||||
filterTrait: FilterTrait;
|
||||
onBack: () => void;
|
||||
onClose?: () => void;
|
||||
dataViewLogic: DataViewUILogicBase;
|
||||
}
|
||||
},
|
||||
middleware?: Array<Middleware | null | undefined | false>
|
||||
) => {
|
||||
const filterTrait = props.filterTrait;
|
||||
const view = filterTrait.view;
|
||||
popMenu(target, {
|
||||
const handler = popMenu(target, {
|
||||
middleware,
|
||||
options: {
|
||||
title: {
|
||||
text: 'Filters',
|
||||
onBack: props.onBack,
|
||||
onClose: props.onClose,
|
||||
},
|
||||
items: [
|
||||
menu.group({
|
||||
@@ -409,23 +410,16 @@ export const popFilterRoot = (
|
||||
prefix: PlusIcon(),
|
||||
select: ele => {
|
||||
const value = filterTrait.filter$.value;
|
||||
popCreateFilter(
|
||||
popupTargetFromElement(ele),
|
||||
{
|
||||
vars: view.vars$,
|
||||
onSelect: filter => {
|
||||
filterTrait.filterSet({
|
||||
...value,
|
||||
conditions: [...value.conditions, filter],
|
||||
});
|
||||
props.dataViewLogic.eventTrace(
|
||||
'CreateDatabaseFilter',
|
||||
{}
|
||||
);
|
||||
},
|
||||
popCreateFilter(popupTargetFromElement(ele), {
|
||||
vars: view.vars$,
|
||||
onSelect: filter => {
|
||||
filterTrait.filterSet({
|
||||
...value,
|
||||
conditions: [...value.conditions, filter],
|
||||
});
|
||||
props.dataViewLogic.eventTrace('CreateDatabaseFilter', {});
|
||||
},
|
||||
{ middleware: subMenuMiddleware }
|
||||
);
|
||||
});
|
||||
return false;
|
||||
},
|
||||
}),
|
||||
@@ -434,4 +428,5 @@ export const popFilterRoot = (
|
||||
],
|
||||
},
|
||||
});
|
||||
handler.menu.menuElement.style.minHeight = '550px';
|
||||
};
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
PlusIcon,
|
||||
} from '@blocksuite/icons/lit';
|
||||
import { ShadowlessElement } from '@blocksuite/std';
|
||||
import type { Middleware } from '@floating-ui/dom';
|
||||
import { computed } from '@preact/signals-core';
|
||||
import { css, html } from 'lit';
|
||||
import { property } from 'lit/decorators.js';
|
||||
@@ -203,11 +204,14 @@ export const popSortRoot = (
|
||||
title?: {
|
||||
text: string;
|
||||
onBack?: () => void;
|
||||
onClose?: () => void;
|
||||
};
|
||||
}
|
||||
},
|
||||
middleware?: Array<Middleware | null | undefined | false>
|
||||
) => {
|
||||
const sortUtils = props.sortUtils;
|
||||
popMenu(target, {
|
||||
const handler = popMenu(target, {
|
||||
middleware,
|
||||
options: {
|
||||
title: props.title,
|
||||
items: [
|
||||
@@ -237,4 +241,5 @@ export const popSortRoot = (
|
||||
],
|
||||
},
|
||||
});
|
||||
handler.menu.menuElement.style.minHeight = '550px';
|
||||
};
|
||||
|
||||
+166
-43
@@ -18,6 +18,7 @@ import {
|
||||
MoreHorizontalIcon,
|
||||
SortIcon,
|
||||
} from '@blocksuite/icons/lit';
|
||||
import { autoPlacement, offset, shift } from '@floating-ui/dom';
|
||||
import { css, html } from 'lit';
|
||||
import { styleMap } from 'lit/directives/style-map.js';
|
||||
|
||||
@@ -97,7 +98,8 @@ declare global {
|
||||
const createSettingMenus = (
|
||||
target: PopupTarget,
|
||||
dataViewLogic: DataViewUILogicBase,
|
||||
reopen: () => void
|
||||
reopen: () => void,
|
||||
closeMenu: () => void
|
||||
) => {
|
||||
const view = dataViewLogic.view;
|
||||
const settingItems: MenuConfig[] = [];
|
||||
@@ -105,15 +107,25 @@ const createSettingMenus = (
|
||||
menu.action({
|
||||
name: 'Properties',
|
||||
prefix: InfoIcon(),
|
||||
closeOnSelect: false,
|
||||
postfix: html` <div style="font-size: 14px;">
|
||||
${view.properties$.value.length} shown
|
||||
</div>
|
||||
${ArrowRightSmallIcon()}`,
|
||||
select: () => {
|
||||
popPropertiesSetting(target, {
|
||||
view: view,
|
||||
onBack: reopen,
|
||||
});
|
||||
popPropertiesSetting(
|
||||
target,
|
||||
{
|
||||
view: view,
|
||||
onBack: reopen,
|
||||
onClose: closeMenu,
|
||||
},
|
||||
[
|
||||
autoPlacement({ allowedPlacements: ['bottom-start', 'top-start'] }),
|
||||
offset({ mainAxis: 15, crossAxis: -162 }),
|
||||
shift({ crossAxis: true }),
|
||||
]
|
||||
);
|
||||
},
|
||||
})
|
||||
);
|
||||
@@ -124,6 +136,7 @@ const createSettingMenus = (
|
||||
menu.action({
|
||||
name: 'Filter',
|
||||
prefix: FilterIcon(),
|
||||
closeOnSelect: false,
|
||||
postfix: html` <div style="font-size: 14px;">
|
||||
${filterCount === 0
|
||||
? ''
|
||||
@@ -134,28 +147,66 @@ const createSettingMenus = (
|
||||
${ArrowRightSmallIcon()}`,
|
||||
select: () => {
|
||||
if (!filterTrait.filter$.value.conditions.length) {
|
||||
popCreateFilter(target, {
|
||||
vars: view.vars$,
|
||||
onBack: reopen,
|
||||
onSelect: filter => {
|
||||
filterTrait.filterSet({
|
||||
...(filterTrait.filter$.value ?? emptyFilterGroup),
|
||||
conditions: [...filterTrait.filter$.value.conditions, filter],
|
||||
});
|
||||
popFilterRoot(target, {
|
||||
filterTrait: filterTrait,
|
||||
onBack: reopen,
|
||||
dataViewLogic: dataViewLogic,
|
||||
});
|
||||
dataViewLogic.eventTrace('CreateDatabaseFilter', {});
|
||||
popCreateFilter(
|
||||
target,
|
||||
{
|
||||
vars: view.vars$,
|
||||
onBack: reopen,
|
||||
onClose: closeMenu,
|
||||
onSelect: filter => {
|
||||
filterTrait.filterSet({
|
||||
...(filterTrait.filter$.value ?? emptyFilterGroup),
|
||||
conditions: [
|
||||
...filterTrait.filter$.value.conditions,
|
||||
filter,
|
||||
],
|
||||
});
|
||||
popFilterRoot(
|
||||
target,
|
||||
{
|
||||
filterTrait: filterTrait,
|
||||
onBack: reopen,
|
||||
onClose: closeMenu,
|
||||
dataViewLogic: dataViewLogic,
|
||||
},
|
||||
[
|
||||
autoPlacement({
|
||||
allowedPlacements: ['bottom-start', 'top-start'],
|
||||
}),
|
||||
offset({ mainAxis: 15, crossAxis: -162 }),
|
||||
shift({ crossAxis: true }),
|
||||
]
|
||||
);
|
||||
dataViewLogic.eventTrace('CreateDatabaseFilter', {});
|
||||
},
|
||||
},
|
||||
});
|
||||
{
|
||||
middleware: [
|
||||
autoPlacement({
|
||||
allowedPlacements: ['bottom-start', 'top-start'],
|
||||
}),
|
||||
offset({ mainAxis: 15, crossAxis: -162 }),
|
||||
shift({ crossAxis: true }),
|
||||
],
|
||||
}
|
||||
);
|
||||
} else {
|
||||
popFilterRoot(target, {
|
||||
filterTrait: filterTrait,
|
||||
onBack: reopen,
|
||||
dataViewLogic: dataViewLogic,
|
||||
});
|
||||
popFilterRoot(
|
||||
target,
|
||||
{
|
||||
filterTrait: filterTrait,
|
||||
onBack: reopen,
|
||||
onClose: closeMenu,
|
||||
dataViewLogic: dataViewLogic,
|
||||
},
|
||||
[
|
||||
autoPlacement({
|
||||
allowedPlacements: ['bottom-start', 'top-start'],
|
||||
}),
|
||||
offset({ mainAxis: 15, crossAxis: -162 }),
|
||||
shift({ crossAxis: true }),
|
||||
]
|
||||
);
|
||||
}
|
||||
},
|
||||
})
|
||||
@@ -168,6 +219,7 @@ const createSettingMenus = (
|
||||
menu.action({
|
||||
name: 'Sort',
|
||||
prefix: SortIcon(),
|
||||
closeOnSelect: false,
|
||||
postfix: html` <div style="font-size: 14px;">
|
||||
${sortCount === 0
|
||||
? ''
|
||||
@@ -183,18 +235,42 @@ const createSettingMenus = (
|
||||
dataViewLogic.eventTrace
|
||||
);
|
||||
if (!sortList.length) {
|
||||
popCreateSort(target, {
|
||||
sortUtils: sortUtils,
|
||||
onBack: reopen,
|
||||
});
|
||||
} else {
|
||||
popSortRoot(target, {
|
||||
sortUtils: sortUtils,
|
||||
title: {
|
||||
text: 'Sort',
|
||||
popCreateSort(
|
||||
target,
|
||||
{
|
||||
sortUtils: sortUtils,
|
||||
onBack: reopen,
|
||||
onClose: closeMenu,
|
||||
},
|
||||
});
|
||||
{
|
||||
middleware: [
|
||||
autoPlacement({
|
||||
allowedPlacements: ['bottom-start', 'top-start'],
|
||||
}),
|
||||
offset({ mainAxis: 15, crossAxis: -162 }),
|
||||
shift({ crossAxis: true }),
|
||||
],
|
||||
}
|
||||
);
|
||||
} else {
|
||||
popSortRoot(
|
||||
target,
|
||||
{
|
||||
sortUtils: sortUtils,
|
||||
title: {
|
||||
text: 'Sort',
|
||||
onBack: reopen,
|
||||
onClose: closeMenu,
|
||||
},
|
||||
},
|
||||
[
|
||||
autoPlacement({
|
||||
allowedPlacements: ['bottom-start', 'top-start'],
|
||||
}),
|
||||
offset({ mainAxis: 15, crossAxis: -162 }),
|
||||
shift({ crossAxis: true }),
|
||||
]
|
||||
);
|
||||
}
|
||||
},
|
||||
})
|
||||
@@ -206,6 +282,7 @@ const createSettingMenus = (
|
||||
menu.action({
|
||||
name: 'Group',
|
||||
prefix: GroupingIcon(),
|
||||
closeOnSelect: false,
|
||||
postfix: html` <div style="font-size: 14px;">
|
||||
${groupTrait.property$.value?.name$.value ?? ''}
|
||||
</div>
|
||||
@@ -213,12 +290,37 @@ const createSettingMenus = (
|
||||
select: () => {
|
||||
const groupBy = groupTrait.property$.value;
|
||||
if (!groupBy) {
|
||||
popSelectGroupByProperty(target, groupTrait, {
|
||||
onSelect: () => popGroupSetting(target, groupTrait, reopen),
|
||||
onBack: reopen,
|
||||
});
|
||||
popSelectGroupByProperty(
|
||||
target,
|
||||
groupTrait,
|
||||
{
|
||||
onSelect: () =>
|
||||
popGroupSetting(target, groupTrait, reopen, closeMenu, [
|
||||
autoPlacement({
|
||||
allowedPlacements: ['bottom-start', 'top-start'],
|
||||
}),
|
||||
offset({ mainAxis: 15, crossAxis: -162 }),
|
||||
shift({ crossAxis: true }),
|
||||
]),
|
||||
onBack: reopen,
|
||||
onClose: closeMenu,
|
||||
},
|
||||
[
|
||||
autoPlacement({
|
||||
allowedPlacements: ['bottom-start', 'top-start'],
|
||||
}),
|
||||
offset({ mainAxis: 15, crossAxis: -162 }),
|
||||
shift({ crossAxis: true }),
|
||||
]
|
||||
);
|
||||
} else {
|
||||
popGroupSetting(target, groupTrait, reopen);
|
||||
popGroupSetting(target, groupTrait, reopen, closeMenu, [
|
||||
autoPlacement({
|
||||
allowedPlacements: ['bottom-start', 'top-start'],
|
||||
}),
|
||||
offset({ mainAxis: 15, crossAxis: -162 }),
|
||||
shift({ crossAxis: true }),
|
||||
]);
|
||||
}
|
||||
},
|
||||
})
|
||||
@@ -308,7 +410,7 @@ export const popViewOptions = (
|
||||
></affine-menu-button>`;
|
||||
};
|
||||
});
|
||||
popMenu(target, {
|
||||
const subHandler = popMenu(target, {
|
||||
options: {
|
||||
title: {
|
||||
onBack: reopen,
|
||||
@@ -338,7 +440,15 @@ export const popViewOptions = (
|
||||
// }),
|
||||
],
|
||||
},
|
||||
middleware: [
|
||||
autoPlacement({
|
||||
allowedPlacements: ['bottom-start', 'top-start'],
|
||||
}),
|
||||
offset({ mainAxis: 15, crossAxis: -162 }),
|
||||
shift({ crossAxis: true }),
|
||||
],
|
||||
});
|
||||
subHandler.menu.menuElement.style.minHeight = '550px';
|
||||
},
|
||||
prefix: LayoutIcon(),
|
||||
}),
|
||||
@@ -348,7 +458,9 @@ export const popViewOptions = (
|
||||
|
||||
items.push(
|
||||
menu.group({
|
||||
items: createSettingMenus(target, dataViewLogic, reopen),
|
||||
items: createSettingMenus(target, dataViewLogic, reopen, () =>
|
||||
handler.close()
|
||||
),
|
||||
})
|
||||
);
|
||||
items.push(
|
||||
@@ -357,6 +469,7 @@ export const popViewOptions = (
|
||||
menu.action({
|
||||
name: 'Duplicate',
|
||||
prefix: DuplicateIcon(),
|
||||
closeOnSelect: false,
|
||||
select: () => {
|
||||
view.duplicate();
|
||||
},
|
||||
@@ -364,6 +477,7 @@ export const popViewOptions = (
|
||||
menu.action({
|
||||
name: 'Delete',
|
||||
prefix: DeleteIcon(),
|
||||
closeOnSelect: false,
|
||||
select: () => {
|
||||
view.delete();
|
||||
},
|
||||
@@ -372,13 +486,22 @@ export const popViewOptions = (
|
||||
],
|
||||
})
|
||||
);
|
||||
popMenu(target, {
|
||||
let handler: ReturnType<typeof popMenu>;
|
||||
handler = popMenu(target, {
|
||||
options: {
|
||||
title: {
|
||||
text: 'View settings',
|
||||
onClose: () => handler.close(),
|
||||
},
|
||||
items,
|
||||
onClose: onClose,
|
||||
},
|
||||
middleware: [
|
||||
autoPlacement({ allowedPlacements: ['bottom-start'] }),
|
||||
offset({ mainAxis: 15, crossAxis: -162 }),
|
||||
shift({ crossAxis: true }),
|
||||
],
|
||||
});
|
||||
handler.menu.menuElement.style.minHeight = '550px';
|
||||
return handler;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user