Grid selection
This commit is contained in:
@@ -1,14 +1,15 @@
|
||||
import { Menu, Portal } from '@mantine/core';
|
||||
import { Menu, Portal } from '@mantine/core';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { type MantineBetterMenuInstanceItem, useMantineBetterMenus } from './Store';
|
||||
|
||||
export function MenuRenderer() {
|
||||
const { menus, providerID, setInstanceState } = useMantineBetterMenus((s) => ({
|
||||
const { menus, providerID, setInstanceState, width } = useMantineBetterMenus((s) => ({
|
||||
menus: s.menus,
|
||||
providerID: s.providerID,
|
||||
setInstanceState: s.setInstanceState,
|
||||
setState: s.setState
|
||||
setState: s.setState,
|
||||
width: s.width,
|
||||
}));
|
||||
|
||||
return (
|
||||
@@ -18,7 +19,7 @@ export function MenuRenderer() {
|
||||
return (
|
||||
<Menu
|
||||
shadow="md"
|
||||
width={200}
|
||||
width={width ?? '300'}
|
||||
{...m.menuProps}
|
||||
key={`bmm_menu_${providerID}_${menuIndex}`}
|
||||
onClose={() => {
|
||||
@@ -68,8 +69,47 @@ const MenuItemRenderer = ({ children, label, ...props }: MantineBetterMenuInstan
|
||||
return <Menu.Divider />;
|
||||
}
|
||||
|
||||
if (props.items && props.items.length > 0) {
|
||||
return (
|
||||
<Menu.Sub>
|
||||
<Menu.Sub.Target>
|
||||
<Menu.Sub.Item
|
||||
{...props}
|
||||
disabled={loading}
|
||||
onClick={(e) => {
|
||||
props.onClick?.(e);
|
||||
if (props.onClickAsync) {
|
||||
setLoading(true);
|
||||
props.onClickAsync().finally(() => setLoading(false));
|
||||
}
|
||||
}}
|
||||
styles={{
|
||||
itemLabel: {
|
||||
overflow: 'auto',
|
||||
wordWrap: 'break-word',
|
||||
},
|
||||
...props.styles,
|
||||
}}
|
||||
>
|
||||
{children ?? label}
|
||||
</Menu.Sub.Item>
|
||||
</Menu.Sub.Target>
|
||||
<Menu.Sub.Dropdown>
|
||||
{React.Children.toArray(
|
||||
props.items.map((subitem, subitemIndex) => (
|
||||
<MenuItemRenderer
|
||||
key={`bmm_subitem_${subitem?.id ?? ''}${subitemIndex}`}
|
||||
{...subitem}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</Menu.Sub.Dropdown>
|
||||
</Menu.Sub>
|
||||
);
|
||||
}
|
||||
|
||||
if (!props.onClick && !props.onClickAsync) {
|
||||
return <Menu.Label {...(props as Record<string,unknown>)}> {children ?? label}</Menu.Label>;
|
||||
return <Menu.Label {...(props as Record<string, unknown>)}> {children ?? label}</Menu.Label>;
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -77,12 +117,19 @@ const MenuItemRenderer = ({ children, label, ...props }: MantineBetterMenuInstan
|
||||
{...props}
|
||||
disabled={loading}
|
||||
onClick={(e) => {
|
||||
props.onClick?.(e );
|
||||
props.onClick?.(e);
|
||||
if (props.onClickAsync) {
|
||||
setLoading(true);
|
||||
props.onClickAsync().finally(() => setLoading(false));
|
||||
}
|
||||
}}
|
||||
styles={{
|
||||
itemLabel: {
|
||||
overflow: 'auto',
|
||||
wordWrap: 'break-word',
|
||||
},
|
||||
...props.styles,
|
||||
}}
|
||||
>
|
||||
{children ?? label}
|
||||
</Menu.Item>
|
||||
|
||||
@@ -11,12 +11,15 @@ export interface MantineBetterMenuInstance {
|
||||
menuProps?: MenuProps;
|
||||
renderer?: ReactNode;
|
||||
visible: boolean;
|
||||
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
export interface MantineBetterMenuInstanceItem extends Partial<MenuItemProps> {
|
||||
id?: string;
|
||||
isDivider?: boolean;
|
||||
items?: Array<MantineBetterMenuInstanceItem>;
|
||||
label?: string;
|
||||
onClick?: (e?: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
||||
onClickAsync?: () => Promise<void>;
|
||||
@@ -28,6 +31,7 @@ export interface MantineBetterMenuInstanceItem extends Partial<MenuItemProps> {
|
||||
export interface MenuStoreProps {
|
||||
menus?: Array<MantineBetterMenuInstance>;
|
||||
providerID?: string;
|
||||
width?: number;
|
||||
}
|
||||
|
||||
export type MenuStoreState = MenuStoreProps & MenuStoreStateOnly;
|
||||
@@ -44,61 +48,62 @@ export interface MenuStoreStateOnly {
|
||||
show: (id: string, options?: Partial<MantineBetterMenuInstance>) => void;
|
||||
}
|
||||
|
||||
const { Provider:MantineBetterMenusStoreProvider, useStore:useMantineBetterMenus } = createSyncStore<MenuStoreState, MenuStoreProps>(
|
||||
(set, get) => ({
|
||||
hide: (id: string) => {
|
||||
const s = get();
|
||||
s.setInstanceState(id, 'visible', false);
|
||||
},
|
||||
menus: [],
|
||||
setInstanceState: (id, key, value) => {
|
||||
//@ts-expect-error Type instantiation is excessively deep and possibly infinite.
|
||||
set(
|
||||
produce((state: MenuStoreState) => {
|
||||
const idx = state?.menus?.findIndex((m: MantineBetterMenuInstance) => m.id === id);
|
||||
if (idx >= 0) {
|
||||
state.menus[idx][key] = value;
|
||||
}
|
||||
})
|
||||
);
|
||||
},
|
||||
setState: (key, value) => {
|
||||
set(
|
||||
produce((state) => {
|
||||
state[key] = value;
|
||||
})
|
||||
);
|
||||
},
|
||||
show: (id: string, options?: Partial<Omit<MantineBetterMenuInstance, 'id'>>) => {
|
||||
const s = get();
|
||||
const menuIndex = s.menus.findIndex((m) => m.id === id);
|
||||
const menu: Partial<MantineBetterMenuInstance> = s.menus[menuIndex]
|
||||
? { ...s.menus[menuIndex] }
|
||||
: {};
|
||||
|
||||
Object.assign(menu, options);
|
||||
menu.id = menu.id ?? id;
|
||||
menu.visible = !(menu.visible ?? false);
|
||||
|
||||
if (menuIndex < 0) {
|
||||
s.setState('menus', [...s.menus, menu as MantineBetterMenuInstance]);
|
||||
} else {
|
||||
const { Provider: MantineBetterMenusStoreProvider, useStore: useMantineBetterMenus } =
|
||||
createSyncStore<MenuStoreState, MenuStoreProps>(
|
||||
(set, get) => ({
|
||||
hide: (id: string) => {
|
||||
const s = get();
|
||||
s.setInstanceState(id, 'visible', false);
|
||||
},
|
||||
menus: [],
|
||||
setInstanceState: (id, key, value) => {
|
||||
//@ts-expect-error Type instantiation is excessively deep and possibly infinite.
|
||||
set(
|
||||
produce((state: MenuStoreState) => {
|
||||
if (!state.menus) {
|
||||
state.menus = [];
|
||||
const idx = state?.menus?.findIndex((m: MantineBetterMenuInstance) => m.id === id);
|
||||
if (idx >= 0) {
|
||||
state.menus[idx][key] = value;
|
||||
}
|
||||
state.menus[menuIndex] = { ...state.menus[menuIndex], ...menu };
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
}),
|
||||
(props) => {
|
||||
return {
|
||||
providerID: props.providerID ?? `MenuStore-${getUUID()}`
|
||||
};
|
||||
}
|
||||
);
|
||||
},
|
||||
setState: (key, value) => {
|
||||
set(
|
||||
produce((state) => {
|
||||
state[key] = value;
|
||||
})
|
||||
);
|
||||
},
|
||||
show: (id: string, options?: Partial<Omit<MantineBetterMenuInstance, 'id'>>) => {
|
||||
const s = get();
|
||||
const menuIndex = s.menus.findIndex((m) => m.id === id);
|
||||
const menu: Partial<MantineBetterMenuInstance> = s.menus[menuIndex]
|
||||
? { ...s.menus[menuIndex] }
|
||||
: {};
|
||||
|
||||
export { MantineBetterMenusStoreProvider,useMantineBetterMenus };
|
||||
Object.assign(menu, options);
|
||||
menu.id = menu.id ?? id;
|
||||
menu.visible = !(menu.visible ?? false);
|
||||
|
||||
if (menuIndex < 0) {
|
||||
s.setState('menus', [...s.menus, menu as MantineBetterMenuInstance]);
|
||||
} else {
|
||||
set(
|
||||
produce((state: MenuStoreState) => {
|
||||
if (!state.menus) {
|
||||
state.menus = [];
|
||||
}
|
||||
state.menus[menuIndex] = { ...state.menus[menuIndex], ...menu };
|
||||
})
|
||||
);
|
||||
}
|
||||
},
|
||||
}),
|
||||
(props) => {
|
||||
return {
|
||||
providerID: props.providerID ?? `MenuStore-${getUUID()}`,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
export { MantineBetterMenusStoreProvider, useMantineBetterMenus };
|
||||
|
||||
Reference in New Issue
Block a user