Skip to content
Open
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
8 changes: 2 additions & 6 deletions packages/graphic-walker/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
"postinstall-postinstall": "^2.1.0",
"rbush": "^3.0.1",
"re-resizable": "^6.9.8",
"react-color": "^2.19.3",
"react-colorful": "^5.6.1",
"react-dropzone": "^14.2.3",
"react-error-boundary": "^4.0.11",
"react-i18next": "^11.18.6",
Expand Down Expand Up @@ -131,13 +131,10 @@
"@types/rbush": "^3.0.3",
"@types/react": "*",
"@types/react-beautiful-dnd": "^13.1.2",
"@types/react-color": "^3.0.6",
"@types/react-dom": "*",
"@types/styled-components": "^5.1.26",
"@types/topojson-client": "^3.1.1",
"@vercel/analytics": "^0.1.8",
"@vitejs/plugin-react": "^3.1.0",
"styled-components": "^5.3.6",
"ts-json-schema-generator": "^1.5.0",
"ts-patch": "^3.1.2",
"ts-xor": "^1.3.0",
Expand All @@ -147,7 +144,6 @@
},
"peerDependencies": {
"react": ">=17.0.0 <19.0.0",
"react-dom": ">=17.0.0 <19.0.0",
"styled-components": "^5.3.6"
"react-dom": ">=17.0.0 <19.0.0"
}
}
212 changes: 115 additions & 97 deletions packages/graphic-walker/src/components/actionMenu/list.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import React, { Fragment, memo, type ComponentProps, type ReactElement, createContext, useState, useContext, useMemo, useEffect } from 'react';
import { ChevronRightIcon } from '@heroicons/react/24/outline';
import styled from 'styled-components';
import { Transition } from '@headlessui/react';
import { Separator } from '../ui/separator';

function classNames(...classes: string[]) {
return classes.filter(Boolean).join(' ');
}
import { cn } from '@/utils';

export interface IActionMenuItem {
icon?: ReactElement;
Expand All @@ -16,41 +12,6 @@ export interface IActionMenuItem {
onPress?: () => void;
}

const List = styled.div`
display: grid;
grid-template-columns: max-content 1fr max-content;
& > div {
/* row */
display: contents;
> * {
background: inherit;
cursor: pointer;
width: 100%;
height: 100%;
display: flex;
align-items: center;
overflow: hidden;
padding-block: 0.2rem;
padding-inline: 0.2rem;
&:first-child {
padding-left: 0.4rem;
}
}
> *:first-child {
border-top-left-radius: calc(var(--radius) - 4px);
border-bottom-left-radius: calc(var(--radius) - 4px);
}
> *:last-child {
border-top-right-radius: calc(var(--radius) - 4px);
border-bottom-right-radius: calc(var(--radius) - 4px);
}
&[aria-disabled='true'] > * {
opacity: 0.5;
cursor: default;
}
}
`;

interface IActionMenuRootContext {
path: number[];
setPath: (path: number[]) => void;
Expand Down Expand Up @@ -92,62 +53,119 @@ const ActionMenuItem = memo<IActionMenuItemProps>(function ActionMenuItem({ item
}, [children.length, hover, focus, ctx, basePath]);

return (
<div
tabIndex={disabled ? undefined : 0}
role="button"
aria-haspopup={children.length ? 'menu' : undefined}
aria-disabled={disabled}
className={classNames(
active ? 'bg-accent text-accent-foreground' : 'text-foreground',
disabled ? 'text-muted-foreground' : 'cursor-pointer',
'transition-colors text-xs'
)}
onClick={(e) => {
if (disabled || children.length) {
e.stopPropagation();
e.preventDefault();
return;
}
if (!disabled) {
onPress?.();
ctx.onDismiss();
}
}}
onFocus={() => {
if (!disabled) {
setFocus(true);
}
if (children.length && !expanded) {
ctx.setPath(path);
}
}}
onBlur={() => {
setFocus(false);
}}
onMouseEnter={() => {
setHover(true);
if (children.length && !expanded && !disabled) {
ctx.setPath(path);
}
}}
onMouseLeave={() => {
setHover(false);
}}
onKeyDown={(e) => {
if (disabled || children.length) {
return;
}
if (e.key === 'Enter' || e.key === 'Space') {
onPress?.();
ctx.onDismiss();
}
}}
>
<div aria-hidden="true">{icon}</div>
<div>
<>
<div
tabIndex={disabled ? undefined : 0}
role="button"
aria-haspopup={children.length ? 'menu' : undefined}
aria-disabled={disabled}
className={cn(
'flex items-center overflow-hidden py-1 px-1 pl-2 bg-inherit cursor-pointer w-full h-full rounded-l-[calc(var(--radius)-4px)]',
active ? 'bg-accent text-accent-foreground' : 'text-foreground',
disabled ? 'text-muted-foreground opacity-50 cursor-default' : 'cursor-pointer',
'transition-colors text-xs'
)}
onClick={(e) => {
if (disabled || children.length) {
e.stopPropagation();
e.preventDefault();
return;
}
if (!disabled) {
onPress?.();
ctx.onDismiss();
}
}}
onFocus={() => {
if (!disabled) {
setFocus(true);
}
if (children.length && !expanded) {
ctx.setPath(path);
}
}}
onBlur={() => {
setFocus(false);
}}
onMouseEnter={() => {
setHover(true);
if (children.length && !expanded && !disabled) {
ctx.setPath(path);
}
}}
onMouseLeave={() => {
setHover(false);
}}
onKeyDown={(e) => {
if (disabled || children.length) {
return;
}
if (e.key === 'Enter' || e.key === 'Space') {
onPress?.();
ctx.onDismiss();
}
}}
>
{icon}
</div>
<div
className={cn(
'flex items-center overflow-hidden py-1 px-1 bg-inherit cursor-pointer w-full h-full',
active ? 'bg-accent text-accent-foreground' : 'text-foreground',
disabled ? 'text-muted-foreground opacity-50 cursor-default' : 'cursor-pointer',
'transition-colors text-xs'
)}
onClick={(e) => {
if (disabled || children.length) {
e.stopPropagation();
e.preventDefault();
return;
}
if (!disabled) {
onPress?.();
ctx.onDismiss();
}
}}
onMouseEnter={() => {
setHover(true);
if (children.length && !expanded && !disabled) {
ctx.setPath(path);
}
}}
onMouseLeave={() => {
setHover(false);
}}
>
<span className="truncate self-start">{label}</span>
</div>
<div aria-hidden="true" className="relative">
<div
className={cn(
'flex items-center overflow-hidden py-1 px-1 bg-inherit cursor-pointer w-full h-full relative rounded-r-[calc(var(--radius)-4px)]',
active ? 'bg-accent text-accent-foreground' : 'text-foreground',
disabled ? 'text-muted-foreground opacity-50 cursor-default' : 'cursor-pointer',
'transition-colors text-xs'
)}
onClick={(e) => {
if (disabled || children.length) {
e.stopPropagation();
e.preventDefault();
return;
}
if (!disabled) {
onPress?.();
ctx.onDismiss();
}
}}
onMouseEnter={() => {
setHover(true);
if (children.length && !expanded && !disabled) {
ctx.setPath(path);
}
}}
onMouseLeave={() => {
setHover(false);
}}
>
{children.length > 0 && (
<>
<ChevronRightIcon className="w-4 h-4" aria-hidden="true" />
Expand All @@ -171,7 +189,7 @@ const ActionMenuItem = memo<IActionMenuItemProps>(function ActionMenuItem({ item
</>
)}
</div>
</div>
</>
);
});

Expand All @@ -186,11 +204,11 @@ const MenuItemList = memo<IActionMenuItemListProps>(function ActionMenuItemList(
<div className="p-1 -mx-px">
{title && <header className="px-3 py-1 mb-1.5 text-xs font-medium truncate">{title}</header>}
{title && <Separator orientation="horizontal" className="-mx-1 my-1" />}
<List>
<div className="grid grid-cols-[max-content_1fr_max-content]">
{items.map((item, index) => (
<ActionMenuItem key={index} item={item} path={[...path, index]} />
))}
</List>
</div>
</div>
);
});
Expand Down
18 changes: 6 additions & 12 deletions packages/graphic-walker/src/components/clickMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
import React, { useCallback, useMemo, useRef, useState } from 'react';
import styled from 'styled-components';
import { Transition } from '@headlessui/react';
import React, { useCallback, useState } from 'react';

const MenuContainer = styled.div`
min-width: 100px;
position: absolute;
z-index: 99;
cursor: pointer;
padding: 4px;
`;
interface ClickMenuProps {
x: number;
y: number;
Expand All @@ -27,9 +18,12 @@ const ClickMenu: React.FC<ClickMenuProps> = (props) => {
const top = y - (rect?.top ?? 0);
return (
<div ref={containerCb}>
<MenuContainer className="shadow-lg text-sm border rounded-md bg-popover text-popover-foreground border-border" style={{ left, top }}>
<div
className="z-[99] p-1 cursor-pointer absolute min-w-[100px] shadow-lg text-sm border rounded-md bg-popover text-popover-foreground border-border"
style={{ left, top }}
>
{children}
</MenuContainer>
</div>
</div>
);
};
Expand Down
26 changes: 0 additions & 26 deletions packages/graphic-walker/src/components/color-picker.ts

This file was deleted.

29 changes: 29 additions & 0 deletions packages/graphic-walker/src/components/color-picker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { HexColorPicker, HexColorInput } from 'react-colorful';
import React from 'react';

export const StyledPicker = (props: { color: string; onChange: (color: string) => void; presetColors?: string[] }) => {
return (
<div className="flex flex-col gap-2 p-2 bg-background rounded-md border shadow">
<div className="h-min">
<HexColorPicker color={props.color} onChange={props.onChange} />
</div>
<HexColorInput
className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
color={props.color}
onChange={props.onChange}
/>
{props.presetColors && (
<div className="flex flex-wrap gap-1">
{props.presetColors.map((color) => (
<div
key={color}
className="w-6 h-6 rounded-full cursor-pointer"
style={{ backgroundColor: color }}
onClick={() => props.onChange(color)}
/>
))}
</div>
)}
</div>
);
};
Loading