Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/microsoft/fluentui into u…
Browse files Browse the repository at this point in the history
…sers/srmukher/HBC_multi_legend
  • Loading branch information
srmukher committed Dec 27, 2024
2 parents 5d4b991 + fc4f676 commit 32cc743
Show file tree
Hide file tree
Showing 426 changed files with 10,209 additions and 1,887 deletions.
1 change: 1 addition & 0 deletions apps/perf-test-react-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@fluentui/scripts-perf-test-flamegrill": "*",
"@fluentui/react-avatar": "*",
"@fluentui/react-button": "*",
"@fluentui/react-color-picker-preview": "*",
"@fluentui/react-components": "*",
"@fluentui/react-field": "*",
"@fluentui/react-persona": "*",
Expand Down
18 changes: 18 additions & 0 deletions apps/perf-test-react-components/src/scenarios/ColorPicker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import * as React from 'react';
import { ColorPicker, ColorArea, ColorSlider, AlphaSlider } from '@fluentui/react-color-picker-preview';
import { FluentProvider } from '@fluentui/react-provider';
import { webLightTheme } from '@fluentui/react-theme';

const Scenario = () => (
<ColorPicker color={{ h: 109, s: 1, v: 0.91 }}>
<ColorArea />
<ColorSlider />
<AlphaSlider />
</ColorPicker>
);

Scenario.decorator = (props: { children: React.ReactNode }) => (
<FluentProvider theme={webLightTheme}>{props.children}</FluentProvider>
);

export default Scenario;
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import * as React from 'react';
import {
Button,
makeStyles,
SpinButton,
Menu,
MenuTrigger,
MenuPopover,
MenuList,
MenuItem,
PositioningImperativeRef,
useMergedRefs,
Checkbox,
RadioGroup,
Field,
Radio,
PositioningProps,
} from '@fluentui/react-components';

const useStyles = makeStyles({
boundary: {
border: '2px dashed red',
width: '300px',
height: '300px',
overflow: 'auto',
resize: 'both',
},
trigger: {
display: 'block',
width: '150px',
margin: '200px auto',
},
});

const ResizableBoundary = React.forwardRef<
HTMLDivElement,
{
onResize: ResizeObserverCallback;
children: React.ReactNode;
}
>(({ onResize, children }, ref) => {
const containerRef = React.useRef<HTMLDivElement | null>(null);

React.useEffect(() => {
if (containerRef.current) {
const resizeObserver = new ResizeObserver(onResize);
resizeObserver.observe(containerRef.current);

return () => {
resizeObserver.disconnect();
};
}
}, [onResize]);

const styles = useStyles();

return (
<div ref={useMergedRefs(ref, containerRef)} className={styles.boundary}>
{children}
</div>
);
});

export const CoverTargetForSmallViewport = () => {
const styles = useStyles();
const [boundaryRef, setBoundaryRef] = React.useState<HTMLDivElement | null>(null);

const [menuItemCount, setMenuItemCount] = React.useState(6);

const positioningRef = React.useRef<PositioningImperativeRef>(null);

const [open, setOpen] = React.useState(false);
const [menuPosition, setMenuPosition] = React.useState<PositioningProps['position']>('above');

return (
<>
<div>
<Checkbox label="Open" checked={open} onChange={(e, data) => setOpen(data.checked as boolean)} />{' '}
<Field label="Menu position">
<RadioGroup
value={menuPosition}
onChange={(_, data) => setMenuPosition(data.value as PositioningProps['position'])}
>
<Radio value="above" label="above" />
<Radio value="after" label="after" />
</RadioGroup>
</Field>
<Field label="Menu Item Count">
<SpinButton value={menuItemCount} onChange={(_e, { value }) => value && setMenuItemCount(value)} />
</Field>
</div>
<ResizableBoundary
ref={setBoundaryRef}
onResize={() => {
positioningRef.current?.updatePosition();
}}
>
<Menu
open={open}
positioning={{
positioningRef,
overflowBoundary: boundaryRef,
flipBoundary: boundaryRef,
autoSize: true,
shiftToCoverTarget: true,
position: menuPosition,
}}
>
<MenuTrigger disableButtonEnhancement>
<Button className={styles.trigger}>Open Menu</Button>
</MenuTrigger>
<MenuPopover>
<MenuList>
{Array.from({ length: menuItemCount }, (_, i) => (
<MenuItem>Item {i}</MenuItem>
))}
</MenuList>
</MenuPopover>
</Menu>
</ResizableBoundary>
</>
);
};

CoverTargetForSmallViewport.parameters = {
docs: {
description: {
story:
"`shiftToCoverTarget` is a positioning option that allows the positioned element to shift and cover the target element when there isn't enough space available to fit it.",
},
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export { MatchTargetSize } from './MatchTargetSize.stories';
export { DisableTransform } from './PositioningDisableTransform.stories';
export { ListenToUpdates } from './PositioningListenToUpdates.stories';
export { AutoSizeForSmallViewport } from './PositioningAutoSize.stories';
export { CoverTargetForSmallViewport } from './PositioningShiftToCoverTarget.stories';
export { FallbackPositions } from './PositioningFallbackPositions.stories';

export default {
Expand Down
1 change: 1 addition & 0 deletions apps/vr-tests-react-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"@fluentui/react-card": "*",
"@fluentui/react-charts-preview": "*",
"@fluentui/react-checkbox": "*",
"@fluentui/react-color-picker-preview": "*",
"@fluentui/react-combobox": "*",
"@fluentui/react-context-selector": "*",
"@fluentui/react-datepicker-compat": "*",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import * as React from 'react';
import type { Meta } from '@storybook/react';
import { ColorPicker } from '@fluentui/react-color-picker-preview';
import { SampleColorPicker } from './utils';
import { Steps } from 'storywright';

import { DARK_MODE, getStoryVariant, HIGH_CONTRAST, RTL, withStoryWrightSteps } from '../../utilities';

export default {
title: 'ColorPicker Converged',
decorators: [
story => withStoryWrightSteps({ story, steps: new Steps().snapshot('default', { cropTo: '.testWrapper' }).end() }),
],
} satisfies Meta<typeof ColorPicker>;

export const Default = () => <SampleColorPicker color={{ h: 109, s: 1, v: 0.91 }} />;

export const DefaultDarkMode = getStoryVariant(Default, DARK_MODE);

export const DefaultHighContrast = getStoryVariant(Default, HIGH_CONTRAST);

export const DefaultRTL = getStoryVariant(Default, RTL);

export const Shape = () => (
<>
<SampleColorPicker color={{ h: 195, s: 0.85, v: 0.93 }} shape="square" />
<SampleColorPicker color={{ h: 195, s: 0.85, v: 0.913 }} shape="rounded" />
</>
);
Shape.storyName = 'shape';
16 changes: 16 additions & 0 deletions apps/vr-tests-react-components/src/stories/ColorPicker/utils.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as React from 'react';
import {
ColorPicker,
ColorArea,
AlphaSlider,
ColorSlider,
type ColorPickerProps,
} from '@fluentui/react-color-picker-preview';

export const SampleColorPicker = (props: ColorPickerProps) => (
<ColorPicker {...props}>
<ColorArea />
<ColorSlider />
<AlphaSlider />
</ColorPicker>
);
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,102 @@ const TargetDisplayNone = () => {
);
};

const ShiftToCoverTargetWithAutoSize = () => {
const styles = useStyles();
const [overflowBoundary, setOverflowBoundary] = React.useState<HTMLDivElement | null>(null);
const { containerRef, targetRef } = usePositioning({
position: 'below',
overflowBoundary,
shiftToCoverTarget: true,
autoSize: true,
});

return (
<div
ref={setOverflowBoundary}
className={styles.boundary}
style={{
display: 'flex',
flexDirection: 'column',
height: 200,
padding: '10px 50px',
position: 'relative',
}}
>
<button ref={targetRef}>Target</button>
<Box ref={containerRef} style={{ overflow: 'auto', border: '3px solid green' }}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. In fermentum et sollicitudin ac orci phasellus egestas. Facilisi cras fermentum odio eu feugiat
pretium nibh ipsum consequat. Praesent semper feugiat nibh sed pulvinar proin gravida hendrerit lectus. Porta
nibh venenatis cras sed felis eget. Enim sed faucibus turpis in. Non blandit massa enim nec dui nunc mattis. Ut
eu sem integer vitae justo.
</Box>
</div>
);
};

const ShiftToCoverTargetAsyncContentHorizontal = () => {
const styles = useStyles();
const [overflowBoundary, setOverflowBoundary] = React.useState<HTMLDivElement | null>(null);
const { containerRef, targetRef } = usePositioning({
position: 'after',
overflowBoundary,
shiftToCoverTarget: true,
autoSize: true,
});

return (
<div
ref={setOverflowBoundary}
className={styles.boundary}
style={{
height: 200,
width: 300,
padding: '50px 50px',
boxSizing: 'border-box',
position: 'relative',
}}
>
<button ref={targetRef}>Target</button>
<Box ref={containerRef} style={{ overflow: 'auto', border: '3px solid green', padding: 0 }}>
<Box style={{ maxWidth: 180 }}>
<AsyncFloatingContent />
</Box>
</Box>
</div>
);
};

const ShiftToCoverTargetAsyncContent = () => {
const styles = useStyles();
const [overflowBoundary, setOverflowBoundary] = React.useState<HTMLDivElement | null>(null);
const { containerRef, targetRef } = usePositioning({
position: 'below',
overflowBoundary,
shiftToCoverTarget: true,
autoSize: true,
});

return (
<div
ref={setOverflowBoundary}
className={styles.boundary}
style={{
display: 'flex',
flexDirection: 'column',
height: 200,
padding: '10px 50px',
position: 'relative',
}}
>
<button ref={targetRef}>Target</button>
<Box ref={containerRef} style={{ overflow: 'auto', border: '3px solid green' }}>
<AsyncFloatingContent />
</Box>
</div>
);
};

export default {
title: 'Positioning',

Expand Down Expand Up @@ -1033,3 +1129,32 @@ export const _TargetDisplayNone = () => (
</StoryWright>
);
_TargetDisplayNone.storyName = 'Target display none';

export const _ShiftToCoverTargetWithAutoSize = () => <ShiftToCoverTargetWithAutoSize />;
_ShiftToCoverTargetWithAutoSize.storyName = 'shiftToCoverTarget with autoSize';

export const _ShiftToCoverTargetAsyncContent = () => (
<StoryWright
steps={new Steps()
.click('#load-content')
.wait('#full-content')
.snapshot('floating element is within the boundary')
.end()}
>
<ShiftToCoverTargetAsyncContent />
</StoryWright>
);
_ShiftToCoverTargetAsyncContent.storyName = 'shiftToCoverTarget with autoSize and async content';

export const _ShiftToCoverTargetHorizontal = () => (
<StoryWright
steps={new Steps()
.click('#load-content')
.wait('#full-content')
.snapshot('floating element is within the boundary')
.end()}
>
<ShiftToCoverTargetAsyncContentHorizontal />
</StoryWright>
);
_ShiftToCoverTargetHorizontal.storyName = 'shiftToCoverTarget with autoSize and async content - horizontal';
Loading

0 comments on commit 32cc743

Please sign in to comment.