Skip to content

Commit d9a116c

Browse files
authored
Merge pull request #1893 from silx-kit/abstract-menu
Add generic `Menu` component
2 parents 822ddfb + b3604f2 commit d9a116c

File tree

7 files changed

+117
-129
lines changed

7 files changed

+117
-129
lines changed

apps/storybook/src/LineAspectMenu.stories.tsx

Lines changed: 0 additions & 31 deletions
This file was deleted.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { Menu } from '@h5web/lib';
2+
import { type Meta, type StoryObj } from '@storybook/react-vite';
3+
import { MdIcecream } from 'react-icons/md';
4+
5+
const meta = {
6+
title: 'Toolbar/Menu',
7+
component: Menu,
8+
} satisfies Meta<typeof Menu>;
9+
10+
export default meta;
11+
type Story = StoryObj<typeof Menu>;
12+
13+
export const Default = {
14+
render: (args) => {
15+
return (
16+
<Menu {...args}>
17+
<div style={{ padding: '0.25rem 0.5rem' }}>Radio group, etc.</div>
18+
</Menu>
19+
);
20+
},
21+
args: {
22+
label: 'Icecream',
23+
Icon: MdIcecream,
24+
},
25+
} satisfies Story;

packages/app/src/vis-packs/core/line/LineToolbar.tsx

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import {
22
ComplexVisTypeSelector,
3+
CurveType,
34
DomainWidget,
45
ExportMenu,
5-
LineAspectMenu,
6+
Interpolation,
7+
Menu,
8+
RadioGroup,
69
ScaleSelector,
710
Separator,
811
ToggleBtn,
@@ -14,9 +17,9 @@ import {
1417
type ExportEntry,
1518
} from '@h5web/shared/vis-models';
1619
import { AXIS_SCALE_TYPES } from '@h5web/shared/vis-utils';
17-
import { MdGridOn } from 'react-icons/md';
20+
import { MdAutoGraph, MdGridOn } from 'react-icons/md';
1821

19-
import { INTERACTIONS_WITH_AXIAL_ZOOM } from '../utils';
22+
import { CURVE_TYPE_LABELS, INTERACTIONS_WITH_AXIAL_ZOOM } from '../utils';
2023
import { type LineConfig } from './config';
2124
import ErrorsIcon from './ErrorsIcon';
2225

@@ -111,12 +114,23 @@ function LineToolbar(props: Props) {
111114
onToggle={toggleGrid}
112115
/>
113116

114-
<LineAspectMenu
115-
curveType={curveType}
116-
onCurveTypeChanged={setCurveType}
117-
interpolation={interpolation}
118-
onInterpolationChanged={setInterpolation}
119-
/>
117+
<Menu label="Aspect" Icon={MdAutoGraph}>
118+
<RadioGroup
119+
name="curvetype"
120+
value={curveType}
121+
options={Object.values(CurveType)}
122+
optionsLabels={CURVE_TYPE_LABELS}
123+
onValueChanged={setCurveType}
124+
/>
125+
<RadioGroup
126+
name="interpolation"
127+
label="Interpolation"
128+
options={Object.values(Interpolation)}
129+
disabled={curveType === CurveType.GlyphsOnly}
130+
value={interpolation}
131+
onValueChanged={setInterpolation}
132+
/>
133+
</Menu>
120134

121135
{exportEntries && exportEntries.length > 0 && (
122136
<>

packages/app/src/vis-packs/core/utils.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { type DimensionMapping, type InteractionInfo } from '@h5web/lib';
1+
import {
2+
CurveType,
3+
type DimensionMapping,
4+
type InteractionInfo,
5+
} from '@h5web/lib';
26
import {
37
isBigIntTypedArray,
48
isIntegerType,
@@ -29,6 +33,12 @@ export const INTERACTIONS_WITH_AXIAL_ZOOM = [
2933
{ shortcut: 'Ctrl+Shift+Drag', description: 'Select to zoom in Y' },
3034
];
3135

36+
export const CURVE_TYPE_LABELS: Record<CurveType, string> = {
37+
[CurveType.LineOnly]: 'Line',
38+
[CurveType.GlyphsOnly]: 'Points',
39+
[CurveType.LineAndGlyphs]: 'Both',
40+
};
41+
3242
export function getBaseArray<T extends ArrayValue | undefined>(
3343
value: T,
3444
rawDims: number[],

packages/lib/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export { default as LinkBtn } from './toolbar/controls/LinkBtn';
1616
export { default as ToggleBtn } from './toolbar/controls/ToggleBtn';
1717
export { default as ToggleGroup } from './toolbar/controls/ToggleGroup/ToggleGroup';
1818
export { default as RadioGroup } from './toolbar/controls/RadioGroup';
19+
export { default as Menu } from './toolbar/controls/Menu';
1920
export { default as DomainWidget } from './toolbar/controls/DomainWidget/DomainWidget';
2021
export { default as DomainSlider } from './toolbar/controls/DomainWidget/DomainSlider';
2122
export { default as DomainControls } from './toolbar/controls/DomainWidget/DomainControls';
@@ -27,7 +28,6 @@ export { default as Selector } from './toolbar/controls/Selector/Selector';
2728
export { default as InteractionHelp } from './toolbar/controls/InteractionHelp';
2829
export { default as NotationToggleGroup } from './toolbar/controls/NotationToggleGroup';
2930
export { default as Histogram } from './toolbar/controls/Histogram/Histogram';
30-
export { default as LineAspectMenu } from './toolbar/controls/LineAspectMenu';
3131
export type { ToolbarProps } from './toolbar/Toolbar';
3232
export type { DomainWidgetProps } from './toolbar/controls/DomainWidget/DomainWidget';
3333
export type { DomainSliderProps } from './toolbar/controls/DomainWidget/DomainSlider';

packages/lib/src/toolbar/controls/LineAspectMenu.tsx

Lines changed: 0 additions & 87 deletions
This file was deleted.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { useClick, useInteractions } from '@floating-ui/react';
2+
import { type ComponentType, type PropsWithChildren, useId } from 'react';
3+
4+
import toolbarStyles from '../Toolbar.module.css';
5+
import Btn from './Btn';
6+
import { useFloatingDismiss, useFloatingMenu } from './hooks';
7+
8+
interface Props {
9+
label: string;
10+
Icon?: ComponentType<{ className: string }>;
11+
}
12+
13+
function Menu(props: PropsWithChildren<Props>) {
14+
const { label, Icon, children } = props;
15+
16+
const { context, refs, floatingStyles } = useFloatingMenu();
17+
const { floatingId, open: isOpen } = context;
18+
19+
const referenceId = useId();
20+
21+
const { getReferenceProps, getFloatingProps } = useInteractions([
22+
useClick(context),
23+
useFloatingDismiss(context),
24+
]);
25+
26+
return (
27+
<>
28+
<Btn
29+
ref={refs.setReference}
30+
id={referenceId}
31+
label={label}
32+
Icon={Icon}
33+
withArrow
34+
aria-haspopup="menu"
35+
aria-expanded={isOpen}
36+
aria-controls={(isOpen && floatingId) || undefined}
37+
{...getReferenceProps()}
38+
/>
39+
40+
{isOpen && (
41+
<div
42+
ref={refs.setFloating}
43+
id={floatingId}
44+
className={toolbarStyles.menu}
45+
style={floatingStyles}
46+
role="menu"
47+
aria-labelledby={referenceId}
48+
{...getFloatingProps()}
49+
>
50+
{children}
51+
</div>
52+
)}
53+
</>
54+
);
55+
}
56+
57+
export default Menu;

0 commit comments

Comments
 (0)