Skip to content

Commit

Permalink
Merge pull request #351 from simenko/fix/582503-styled-tooltip
Browse files Browse the repository at this point in the history
Fix/582503 styled tooltip
  • Loading branch information
FlorianRappl authored Oct 8, 2021
2 parents 92725bf + d4b1643 commit 5ce2b09
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 53 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Precise UI Changelog

## 2.1.1

- Fix Flyout styling when extended with styled components
- Remove dead code in Tooltip component

## 2.1.0

- Flyout component reimplemented using Popper.js (556349)
Expand Down
Binary file modified integration/__image_snapshots__/Flyout_3-snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "precise-ui",
"version": "2.1.0",
"version": "2.1.1",
"description": "Precise UI React component library powered by Styled Components.",
"keywords": [
"react",
Expand Down
45 changes: 29 additions & 16 deletions src/components/Flyout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ const FlyoutBody = styled.div(
${getFontStyle({ size: 'medium' })}
z-index: 100;
position: absolute;
width: fit-conent;
box-shadow: 0 2px 6px 0 rgba(75, 78, 82, 0.2);
box-shadow: 0 2qpx 6px 0 rgba(75, 78, 82, 0.2);
border: 1px solid ${theme.ui4};
overflow: visible;
&[data-popper-reference-hidden='true'] {
Expand Down Expand Up @@ -95,20 +94,33 @@ const FlyoutContent = styled.div<FlyoutContentProps>(
FlyoutContent.displayName = 'FlyoutContent';

const FlyoutInt: React.FC<FlyoutProps & WithClickOutsideFCProps> = props => {
const [controlled] = useState<boolean>(props.open !== undefined);
const [visible, setVisible] = useState<boolean>(Boolean(props.open));
const {
position,
defaultPosition,
offset,
open,
outsideClickEvent,
onChange,
children,
content,
theme,
...restProps
} = props;

const [controlled] = useState<boolean>(open !== undefined);
const [visible, setVisible] = useState<boolean>(Boolean(open));
const [referenceElement, setReferenceElement] = useState<HTMLDivElement | undefined>();
const [popperElement, setPopperElement] = useState<HTMLDivElement | undefined>();
const [arrowElement, setArrowElement] = useState<HTMLDivElement | undefined>();

const popperModifiers: Array<Modifier<unknown>> = [
{ name: 'hide' },
{ name: 'flip', enabled: !props.position },
{ name: 'flip', enabled: !position },
{ name: 'arrow', options: { element: arrowElement } },
{ name: 'offset', options: { offset: [0, props.offset || 4 + flyout.arrowSize / 2] } },
{ name: 'offset', options: { offset: [0, offset || 4 + flyout.arrowSize / 2] } },
];

if (!props.position) {
if (!position) {
popperModifiers.push({
name: 'preventOverflow',
options: {
Expand All @@ -118,35 +130,35 @@ const FlyoutInt: React.FC<FlyoutProps & WithClickOutsideFCProps> = props => {
}

const { styles, attributes } = usePopper(referenceElement, popperElement, {
placement: mapFlyoutPositionToPopperPlacement(props.position || props.defaultPosition),
placement: mapFlyoutPositionToPopperPlacement(position || defaultPosition),
modifiers: popperModifiers,
});

useEffect(() => setVisible(Boolean(props.open)), [props.open]);
useEffect(() => changeVisibility(false), [props.outsideClickEvent]);
useEffect(() => setVisible(Boolean(open)), [open]);
useEffect(() => changeVisibility(false), [outsideClickEvent]);

const onClick = () => changeVisibility(!visible);

const changeVisibility = (nextVisibility: boolean) => {
if (controlled || nextVisibility === visible) {
return;
}
typeof props.onChange === 'function' && props.onChange({ open: nextVisibility });
typeof onChange === 'function' && onChange({ open: nextVisibility });
setVisible(nextVisibility);
};

return (
<FlyoutContainer>
<FlyoutTarget onClick={onClick} ref={setReferenceElement}>
{props.children}
{children}
</FlyoutTarget>
{visible && props.content && (
<FlyoutBody ref={setPopperElement} style={styles.popper} {...attributes.popper}>
{visible && content && (
<FlyoutBody ref={setPopperElement} style={styles.popper} {...attributes.popper} {...restProps}>
{/* Normally a styled component gets the theme from context. But some other component
may pass a customized theme as a prop. See example at Tooltip component */}
<FlyoutContent theme={props.theme}>{props.content}</FlyoutContent>
<FlyoutContent theme={theme}>{content}</FlyoutContent>
<FlyoutArrow
theme={props.theme}
theme={theme}
ref={setArrowElement}
style={calculateArrowStyleOverrides(attributes.popper, styles.arrow)}
/>
Expand All @@ -155,6 +167,7 @@ const FlyoutInt: React.FC<FlyoutProps & WithClickOutsideFCProps> = props => {
</FlyoutContainer>
);
};

FlyoutInt.displayName = 'FlyoutInt';

export const Flyout = withClickOutsideFC<FlyoutProps>(FlyoutInt);
Expand Down
35 changes: 0 additions & 35 deletions src/components/Tooltip/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ const TooltipContainer = styled.div`

export interface TooltipState {
controlled: boolean;
targetRect: ClientRect;
dirtyFlag: boolean;
open: boolean;
}

Expand All @@ -28,46 +26,15 @@ export class Tooltip extends React.Component<TooltipProps, TooltipState> {
this.state = {
controlled: props.open !== undefined,
open: props.open || false,
// Typing error here looks like a bug, so 'any' makes sense
targetRect: { top: 0, right: 0, bottom: 0, left: 0, width: 0, height: 0 } as any,
dirtyFlag: false,
};
}

componentDidMount() {
this.updateMeasurements();
}

UNSAFE_componentWillReceiveProps(nextProps: TooltipProps) {
if (this.state.controlled && nextProps.open !== undefined) {
this.setOpen(nextProps.open);
}
}

componentDidUpdate() {
const { dirtyFlag } = this.state;

if (dirtyFlag) {
this.updateMeasurements();
this.setState({
dirtyFlag: false,
});
}
}

private updateMeasurements() {
if (this.targetContainer) {
const targetRect = this.targetContainer.getBoundingClientRect();
this.setState({
targetRect,
});
}
}

private setTargetRef = (el: HTMLDivElement | null) => {
this.targetContainer = el;
};

private setOpen(open: boolean) {
const { onChange } = this.props;

Expand All @@ -77,7 +44,6 @@ export class Tooltip extends React.Component<TooltipProps, TooltipState> {

this.setState({
open,
dirtyFlag: open === true,
});
}

Expand All @@ -103,7 +69,6 @@ export class Tooltip extends React.Component<TooltipProps, TooltipState> {

return (
<TooltipContainer
ref={this.setTargetRef}
onFocus={this.onMouseOver}
onBlur={this.onMouseOut}
onMouseOver={this.onMouseOver}
Expand Down

0 comments on commit 5ce2b09

Please sign in to comment.