Skip to content

Commit 00491d8

Browse files
committed
feat(YfmTable): update color picker for cell background [2]
1 parent 7689553 commit 00491d8

11 files changed

Lines changed: 218 additions & 122 deletions

File tree

demo/src/stories/examples/yfm-table-dnd/YfmTableDnD.stories.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export const Story: StoryObj<typeof component> = {
77
mobile: false,
88
dnd: true,
99
headerRows: true,
10+
cellBackground: true,
1011
},
1112
};
1213
Story.storyName = "YFM Table D'n'D";

demo/src/stories/examples/yfm-table-dnd/YfmTableDnD.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ export type YfmTableDnDDemoProps = {
1010
mobile: boolean;
1111
dnd: boolean;
1212
headerRows: boolean;
13+
cellBackground: boolean;
1314
};
1415

1516
export const YfmTableDnDDemo = memo<YfmTableDnDDemoProps>(function YfmTableDnDDemo({
1617
mobile,
1718
dnd,
1819
headerRows,
20+
cellBackground,
1921
}) {
2022
const editor = useMarkdownEditor(
2123
{
@@ -32,6 +34,7 @@ export const YfmTableDnDDemo = memo<YfmTableDnDDemoProps>(function YfmTableDnDDe
3234
yfmTable: {
3335
dnd,
3436
headerRows,
37+
cellBackground,
3538
},
3639
},
3740
},
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import {useEffect, useRef} from 'react';
2+
3+
import {ChevronRight, BucketPaint as ColorPalette} from '@gravity-ui/icons';
4+
import {Icon, Menu, Popup, sp} from '@gravity-ui/uikit';
5+
6+
import {i18n} from 'src/i18n/yfm-table';
7+
import {useBooleanState, useElementState} from 'src/react-utils';
8+
9+
import {CellBgPalette} from '../CellBgPalette';
10+
11+
const CLOSE_DELAY = 120;
12+
13+
export type CellBgMenuItemProps = {
14+
qa?: string;
15+
currentCellBg?: string | null;
16+
onCellBgChange: (color: string | null) => void;
17+
};
18+
19+
export const CellBgMenuItem: React.FC<CellBgMenuItemProps> = function YfmTableCellBgMenuItem({
20+
qa,
21+
currentCellBg,
22+
onCellBgChange,
23+
}) {
24+
const [anchorElement, setAnchorElement] = useElementState<HTMLDivElement>();
25+
const closeTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
26+
const [open, openPopup, closePopup] = useBooleanState(false);
27+
28+
const cancelClose = () => {
29+
if (closeTimer.current) {
30+
clearTimeout(closeTimer.current);
31+
closeTimer.current = null;
32+
}
33+
};
34+
const scheduleClose = () => {
35+
cancelClose();
36+
closeTimer.current = setTimeout(closePopup, CLOSE_DELAY);
37+
};
38+
39+
useEffect(() => () => cancelClose(), []);
40+
41+
return (
42+
<Menu.Item
43+
qa={qa}
44+
ref={setAnchorElement}
45+
iconStart={<Icon data={ColorPalette} />}
46+
iconEnd={<Icon data={ChevronRight} />}
47+
onClick={() => {
48+
cancelClose();
49+
openPopup();
50+
}}
51+
extraProps={{
52+
onMouseEnter: () => {
53+
cancelClose();
54+
openPopup();
55+
},
56+
onMouseLeave: scheduleClose,
57+
}}
58+
>
59+
{i18n('cells.bg')}
60+
<Popup
61+
open={open}
62+
hasArrow={false}
63+
placement="right-start"
64+
anchorElement={anchorElement}
65+
>
66+
<div onMouseEnter={cancelClose} onMouseLeave={scheduleClose} className={sp({p: 2})}>
67+
<CellBgPalette value={currentCellBg} onSelect={onCellBgChange} />
68+
</div>
69+
</Popup>
70+
</Menu.Item>
71+
);
72+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './CellBgMenuItem';

packages/editor/src/extensions/yfm/YfmTable/plugins/YfmTableControls/components/CellBgPalette/CellBgPalette.scss

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,32 @@ $color-map: (
1818
gap: 0;
1919

2020
&__item {
21+
display: flex;
22+
justify-content: center;
23+
align-items: center;
24+
25+
font: inherit;
2126
cursor: pointer;
2227

28+
color: inherit;
29+
border: 0;
2330
border-radius: var(--g-border-radius-m);
31+
background: transparent;
32+
33+
appearance: none;
2434

2535
&:hover {
2636
background: var(--g-color-base-generic);
2737
}
38+
39+
&:focus {
40+
outline: none;
41+
}
42+
43+
&:focus-visible {
44+
outline: 1px solid var(--g-color-line-focus);
45+
outline-offset: -1px;
46+
}
2847
}
2948

3049
&__swatch {

packages/editor/src/extensions/yfm/YfmTable/plugins/YfmTableControls/components/CellBgPalette/CellBgPalette.tsx

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {Check} from '@gravity-ui/icons';
2-
import {Box, Icon, Tooltip} from '@gravity-ui/uikit';
2+
import {Icon, Tooltip, spacing} from '@gravity-ui/uikit';
33

44
import {cn} from 'src/classname';
55
import {i18n} from 'src/i18n/yfm-table';
@@ -40,22 +40,36 @@ export const CellBgPalette: React.FC<CellBgPaletteProps> = function YfmTableCell
4040
placement={isTopRow ? 'top' : 'bottom'}
4141
content={i18n(swatch.i18nKey)}
4242
>
43-
<Box className={b('item')} spacing={{p: 1}}>
44-
<button
45-
type="button"
43+
<button
44+
type="button"
45+
className={spacing({p: 1}, b('item'))}
46+
aria-label={i18n(swatch.i18nKey)}
47+
aria-pressed={isSelected}
48+
onClick={() => handleClick(swatch.value)}
49+
// Parent Menu.Item listens for Enter/Space and re-opens its popup,
50+
// shadowing the button's native activation. Handle the keys here
51+
// and stop propagation so the swatch is actually selected.
52+
onKeyDown={(e) => {
53+
if (e.key === 'Enter' || e.key === ' ') {
54+
e.preventDefault();
55+
e.stopPropagation();
56+
handleClick(swatch.value);
57+
}
58+
}}
59+
>
60+
<span
4661
className={b('swatch', {
4762
none: swatch.value === NO_COLOR_VALUE,
4863
color: swatch.value || undefined,
4964
})}
50-
onClick={() => handleClick(swatch.value)}
5165
>
5266
{isSelected && (
5367
<span className={b('check')}>
5468
<Icon data={Check} size={16} />
5569
</span>
5670
)}
57-
</button>
58-
</Box>
71+
</span>
72+
</button>
5973
</Tooltip>
6074
);
6175
})}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './CellBgPalette';

packages/editor/src/extensions/yfm/YfmTable/plugins/YfmTableControls/components/FloatingMenu/FloatingMenu.tsx

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ export type FloatingMenuProps = {
2222
dirtype: 'row' | 'column';
2323
canDrag: boolean;
2424
anchorElement: ReferenceType;
25-
dropdownItems: DropdownMenuProps<unknown>['items'];
25+
dropdownItems?: DropdownMenuProps<unknown>['items'];
26+
children?: React.ReactNode;
2627
switcherMouseProps?: Pick<
2728
ButtonButtonProps,
2829
'onMouseDown' | 'onMouseMove' | 'onMouseUp' | 'onMouseLeave'
@@ -31,8 +32,15 @@ export type FloatingMenuProps = {
3132
};
3233

3334
export const FloatingMenu: React.FC<FloatingMenuProps> = function YfmTableFloatingMenu(props) {
34-
const {dirtype, canDrag, anchorElement, dropdownItems, switcherMouseProps, onOpenToggle} =
35-
props;
35+
const {
36+
dirtype,
37+
canDrag,
38+
anchorElement,
39+
dropdownItems,
40+
children,
41+
switcherMouseProps,
42+
onOpenToggle,
43+
} = props;
3644

3745
const [isMenuOpened, setMenuOpened] = useState(false);
3846
const [isHovered, setHovered, unsetHovered] = useBooleanState(false);
@@ -102,7 +110,9 @@ export const FloatingMenu: React.FC<FloatingMenuProps> = function YfmTableFloati
102110
}}
103111
menuProps={{qa: `g-md-yfm-table-${dirtype}-menu`}}
104112
items={dropdownItems}
105-
/>
113+
>
114+
{children}
115+
</DropdownMenu>
106116
</FloatingPopup>
107117
);
108118
};

0 commit comments

Comments
 (0)