+
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions lib/components/Floating.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
flip,
offset,
type Placement,
safePolygon,
shift,
size,
useClick,
Expand Down Expand Up @@ -66,6 +67,12 @@ type Props = {
* @default 200
*/
hoverDelay: number;
/**
* Content will not close if the mouse moves out of the children while
* trying to move into the content.
* - Works only if used `hoverOpen` prop.
*/
hoverSafePolygon: boolean;
/**
* Whitelisted classes.
* Used to allow to add some secured classes,
Expand Down Expand Up @@ -115,6 +122,7 @@ export function Floating(props: Props) {
disabled,
hoverDelay,
hoverOpen,
hoverSafePolygon,
handleOpen,
onMounted,
placement,
Expand Down Expand Up @@ -172,6 +180,11 @@ export function Floating(props: Props) {
const hover = useHover(context, {
enabled: !disabled,
restMs: hoverDelay || 200,
handleClose: hoverSafePolygon
? safePolygon({
requireIntent: false,
})
: null,
});

const openHandled = handleOpen !== undefined;
Expand Down
96 changes: 77 additions & 19 deletions lib/components/MenuBar.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { classes } from '@common/react';
import { type ReactNode, useRef } from 'react';
import { type BooleanLike, classes } from '@common/react';
import {
type PropsWithChildren,
type ReactNode,
useRef,
useState,
} from 'react';
import { Box, type BoxProps } from './Box';
import { Floating } from './Floating';
import { Icon } from './Icon';

type MenuBarDropdownProps = {
disabled?: boolean;
display: any;
display: ReactNode;
onMouseOver: () => void;
onOutsideClick: () => void;
open: boolean;
Expand All @@ -31,6 +36,7 @@ function MenuBarButton(props: MenuBarDropdownProps) {

return (
<Floating
placement="bottom-start"
allowedOutsideClasses=".Menubar_inner"
content={
<div
Expand All @@ -47,6 +53,7 @@ function MenuBarButton(props: MenuBarDropdownProps) {
<Box
className={classes([
'MenuBar__MenuBarButton',
disabled && 'MenuBar__disabled',
'MenuBar__font',
'MenuBar__hover',
className,
Expand Down Expand Up @@ -118,53 +125,104 @@ function MenuDropdown(props: MenuBarItemProps) {

MenuBar.Dropdown = MenuDropdown;

function MenuItemToggle(props) {
const { value, displayText, onClick, checked } = props;
type MenuItemProps = Partial<{
value: any;
displayText: ReactNode;
disabled: BooleanLike;
onClick: (value: any) => void;
}>;

function MenuItem(props: MenuItemProps) {
const { value, disabled, displayText, onClick } = props;

return (
<Box
className={classes([
'MenuBar__font',
disabled && 'MenuBar__disabled',
'MenuBar__MenuItem',
'MenuBar__MenuItemToggle',
'MenuBar__hover',
])}
onClick={() => onClick(value)}
onClick={() => onClick?.(value)}
>
<div className="MenuBar__MenuItemToggle__check">
<Icon name={checked ? 'check' : ''} size={1.3} />
</div>
{displayText}
</Box>
);
}

MenuDropdown.MenuItemToggle = MenuItemToggle;
MenuDropdown.MenuItem = MenuItem;

type MenuItemProps = Partial<{
value: any;
displayText: string;
onClick: (value: any) => void;
}>;
type MenuItemToggleProps = MenuItemProps & Partial<{ checked: BooleanLike }>;

function MenuItem(props: MenuItemProps) {
const { value, displayText, onClick } = props;
function MenuItemToggle(props: MenuItemToggleProps) {
const { value, disabled, displayText, onClick, checked } = props;

return (
<Box
className={classes([
'MenuBar__font',
disabled && 'MenuBar__disabled',
'MenuBar__MenuItem',
'MenuBar__MenuItemToggle',
'MenuBar__hover',
])}
onClick={() => onClick?.(value)}
>
<div className="MenuBar__MenuItemToggle__check">
<Icon name={checked ? 'check' : ''} size={1.3} />
</div>
{displayText}
</Box>
);
}

MenuDropdown.MenuItem = MenuItem;
MenuDropdown.MenuItemToggle = MenuItemToggle;

type MenuItemSubmenuProps = PropsWithChildren<
Omit<MenuItemProps, 'value' | 'onClick'> & Partial<{ openWidth: string }>
>;

function MenuItemSubmenu(props: MenuItemSubmenuProps) {
const { displayText, disabled, openWidth, children } = props;
const [open, setOpen] = useState(false);
return (
<Floating
hoverOpen
hoverDelay={250}
hoverSafePolygon
contentOffset={0}
disabled={disabled}
placement="right-start"
onOpenChange={setOpen}
content={
<div
className="MenuBar__menu"
style={{
width: openWidth,
}}
>
{children}
</div>
}
>
<Box
className={classes([
'MenuBar__font',
disabled && 'MenuBar__disabled',
'MenuBar__MenuItem',
'MenuBar__MenuItemSubmenu',
open && 'MenuBar__MenuItemSubmenu__Open',
'MenuBar__hover',
])}
>
{displayText}
<Icon name="chevron-right" />
</Box>
</Floating>
);
}

MenuDropdown.Submenu = MenuItemSubmenu;

function Separator() {
return <div className="MenuBar__Separator" />;
Expand Down
23 changes: 23 additions & 0 deletions stories/components/MenuBar.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const Default: StoryObj<StoryProps> = {
const [openMenuBar, setOpenMenuBar] = useState<string | null>(null);
const [openOnHover, setOpenOnHover] = useState(false);
const [checkbox, setCheckbox] = useState(false);
const { openWidth } = args;

const menuBarProps = {
openMenuBar: openMenuBar,
Expand All @@ -58,6 +59,28 @@ export const Default: StoryObj<StoryProps> = {
displayText="Open File"
onClick={closeMenu}
/>
<MenuBar.Dropdown.Submenu
displayText="Open Recent"
openWidth={openWidth}
>
<MenuBar.Dropdown.MenuItem
displayText="/foo.js"
onClick={closeMenu}
/>
<MenuBar.Dropdown.MenuItem
displayText="/bar.ts"
onClick={closeMenu}
/>
<MenuBar.Dropdown.MenuItem
displayText="/baz.tsx"
onClick={closeMenu}
/>
<MenuBar.Dropdown.Separator />
<MenuBar.Dropdown.MenuItem
displayText="Clear Recently Opened"
onClick={closeMenu}
/>
</MenuBar.Dropdown.Submenu>
<MenuBar.Dropdown.MenuItem displayText="Save" onClick={closeMenu} />
<MenuBar.Dropdown.MenuItem
displayText="Save As"
Expand Down
18 changes: 18 additions & 0 deletions styles/components/MenuBar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,21 @@
font-family: var(--menu-bar-font-family);
font-size: base.em(12px);
line-height: base.em(17px);

&.MenuBar__disabled {
color: hsl(from currentColor h s l / 0.2);
}
}

.MenuBar__hover {
&:hover {
background-color: hsl(from var(--menu-bar-background) h s calc(l + 20));
transition: background-color 0ms;
}

&.MenuBar__disabled {
background-color: var(--menu-bar-background);
}
}

.MenuBar__MenuBarButton {
Expand Down Expand Up @@ -49,6 +57,16 @@
padding-left: var(--space-sm);
}

.MenuBar__MenuItemSubmenu {
display: flex;
justify-content: space-between;
align-items: center;
}

.MenuBar__MenuItemSubmenu__Open {
background-color: hsl(from var(--menu-bar-background) h s calc(l + 20));
}

.MenuBar__over {
top: auto;
bottom: 100%;
Expand Down
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载