Files
spacedrive/packages/ui/src/DropdownMenu.tsx
Jamie Pine 0ccc038900 More important docs! (#2317)
* docs

* docs

* doc

* revert

* revert

* move actions to arch

* docs

* docssss

* typo

* duplicate

* fix date

* x

* jobs

* jobs

* Update jobs.mdx

Co-authored-by: 0xBA5E64 <26796481+0xBA5E64@users.noreply.github.com>

* Update jobs.mdx

Co-authored-by: 0xBA5E64 <26796481+0xBA5E64@users.noreply.github.com>

* Update libraries.mdx

Co-authored-by: 0xBA5E64 <26796481+0xBA5E64@users.noreply.github.com>

* Update spaces.mdx

Co-authored-by: 0xBA5E64 <26796481+0xBA5E64@users.noreply.github.com>

* Update spaces.mdx

Co-authored-by: 0xBA5E64 <26796481+0xBA5E64@users.noreply.github.com>

* Update spaces.mdx

Co-authored-by: 0xBA5E64 <26796481+0xBA5E64@users.noreply.github.com>

* Update introduction.mdx

Co-authored-by: 0xBA5E64 <26796481+0xBA5E64@users.noreply.github.com>

* Update clouds.mdx

Co-authored-by: 0xBA5E64 <26796481+0xBA5E64@users.noreply.github.com>

* Update clouds.mdx

Co-authored-by: 0xBA5E64 <26796481+0xBA5E64@users.noreply.github.com>

* Update clouds.mdx

Co-authored-by: 0xBA5E64 <26796481+0xBA5E64@users.noreply.github.com>

* Update importing-photos.mdx

Co-authored-by: 0xBA5E64 <26796481+0xBA5E64@users.noreply.github.com>

* Update interface.mdx

Co-authored-by: 0xBA5E64 <26796481+0xBA5E64@users.noreply.github.com>

* Update jobs.mdx

Co-authored-by: 0xBA5E64 <26796481+0xBA5E64@users.noreply.github.com>

* Update library-setup.mdx

Co-authored-by: 0xBA5E64 <26796481+0xBA5E64@users.noreply.github.com>

* Update locations.mdx

Co-authored-by: 0xBA5E64 <26796481+0xBA5E64@users.noreply.github.com>

* Update quick-preview.mdx

Co-authored-by: 0xBA5E64 <26796481+0xBA5E64@users.noreply.github.com>

* Update quick-preview.mdx

Co-authored-by: 0xBA5E64 <26796481+0xBA5E64@users.noreply.github.com>

* changes

* stuff

* fix

* rag stuff wip

* Update docs/product/guides/importing-photos.mdx

Co-authored-by: 0xBA5E64 <26796481+0xBA5E64@users.noreply.github.com>

* del

* fixed typos/changed wording for some docs

---------

Co-authored-by: Utku <74243531+utkubakir@users.noreply.github.com>
Co-authored-by: 0xBA5E64 <26796481+0xBA5E64@users.noreply.github.com>
Co-authored-by: myung03 <matthewyungisworking@gmail.com>
2024-05-15 00:47:00 +00:00

175 lines
3.7 KiB
TypeScript

'use client';
import * as RadixDM from '@radix-ui/react-dropdown-menu';
import clsx from 'clsx';
import React, {
ContextType,
createContext,
PropsWithChildren,
ReactNode,
Suspense,
useCallback,
useContext,
useRef,
useState
} from 'react';
import { Link } from 'react-router-dom';
import {
contextMenuClassNames,
ContextMenuDivItem,
contextMenuItemClassNames,
ContextMenuItemProps,
contextMenuSeparatorClassNames
} from './ContextMenu';
interface DropdownMenuProps
extends RadixDM.MenuContentProps,
Pick<RadixDM.DropdownMenuProps, 'onOpenChange'> {
trigger: React.ReactNode;
triggerClassName?: string;
alignToTrigger?: boolean;
}
const DropdownMenuContext = createContext<boolean | null>(null);
export const useDropdownMenuContext = <T extends boolean>({ suspense }: { suspense?: T } = {}) => {
const ctx = useContext(DropdownMenuContext);
if (suspense && ctx === null) throw new Error('DropdownMenuContext.Provider not found!');
return ctx as T extends true
? NonNullable<ContextType<typeof DropdownMenuContext>>
: NonNullable<ContextType<typeof DropdownMenuContext>> | undefined;
};
const Root = (props: PropsWithChildren<DropdownMenuProps>) => {
const {
alignToTrigger,
onOpenChange,
trigger,
triggerClassName,
asChild = true,
className,
children,
...contentProps
} = props;
const [width, setWidth] = useState<number>();
const measureRef = useCallback(
(ref: HTMLButtonElement | null) => {
alignToTrigger && ref && setWidth(ref.getBoundingClientRect().width);
},
[alignToTrigger]
);
return (
<RadixDM.Root onOpenChange={onOpenChange}>
<RadixDM.Trigger ref={measureRef} className={triggerClassName} asChild={asChild}>
{trigger}
</RadixDM.Trigger>
<RadixDM.Portal>
<Suspense fallback={null}>
<RadixDM.Content
className={clsx(
contextMenuClassNames,
width && '!min-w-0 max-w-none',
className
)}
align="start"
style={{ width }}
{...contentProps}
>
<DropdownMenuContext.Provider value={true}>
{children}
</DropdownMenuContext.Provider>
</RadixDM.Content>
</Suspense>
</RadixDM.Portal>
</RadixDM.Root>
);
};
const Separator = (props: { className?: string }) => (
<RadixDM.Separator className={clsx(contextMenuSeparatorClassNames, props.className)} />
);
const SubMenu = ({
label,
icon,
iconProps,
keybind,
variant,
className,
...props
}: RadixDM.MenuSubContentProps & ContextMenuItemProps & { trigger?: ReactNode }) => {
return (
<RadixDM.Sub>
<RadixDM.SubTrigger className={contextMenuItemClassNames}>
{props.trigger || (
<ContextMenuDivItem
rightArrow
{...{ label, icon, iconProps, keybind, variant }}
/>
)}
</RadixDM.SubTrigger>
<RadixDM.Portal>
<Suspense fallback={null}>
<RadixDM.SubContent
className={clsx(contextMenuClassNames, className)}
{...props}
/>
</Suspense>
</RadixDM.Portal>
</RadixDM.Sub>
);
};
interface DropdownItemProps extends ContextMenuItemProps {
to?: string;
selected?: boolean;
}
const Item = ({
icon,
iconProps,
label,
children,
keybind,
variant,
className,
selected,
to,
...props
}: DropdownItemProps & RadixDM.MenuItemProps) => {
const ref = useRef<HTMLDivElement>(null);
const renderInner = (
// to style this, pass in variant
<ContextMenuDivItem
className={clsx(selected && 'bg-accent text-white')}
{...{ icon, iconProps, label, keybind, variant, children }}
/>
);
return (
<RadixDM.Item ref={ref} className={clsx(contextMenuItemClassNames, className)} {...props}>
{to ? (
<Link to={to} onClick={() => ref.current?.click()}>
{renderInner}
</Link>
) : (
renderInner
)}
</RadixDM.Item>
);
};
export const DropdownMenu = {
Root,
Item,
Separator,
SubMenu
};