Skip to content
This repository has been archived by the owner on Oct 23, 2024. It is now read-only.

Commit

Permalink
Replace useAnchor in TourPoint component with react-tiny-popover
Browse files Browse the repository at this point in the history
  • Loading branch information
Boughtmanatee5 committed Mar 10, 2023
1 parent 882726c commit b607541
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 86 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
"react": "*",
"react-dom": "*",
"react-is": "^17.0.2",
"react-tiny-popover": "^7.2.3",
"rollup": "^2.79.1",
"rollup-plugin-multi-input": "^1.3.3",
"rollup-plugin-terser": "^7.0.2",
Expand All @@ -101,6 +102,7 @@
"polished": "^4.2.2",
"react": "^16.13.1 || ^17.0.0",
"react-dom": "^16.13.1 || ^17.0.0",
"react-tiny-popover": "^7.2.3",
"styled-components": "^5.3.6"
},
"resolutions": {
Expand Down
195 changes: 118 additions & 77 deletions src/components/TourPoint/TourPoint.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,44 @@
import React, {
cloneElement,
useContext,
useRef,
MouseEvent,
} from 'react';

import type { Props } from './TourPoint.types';
import React, { cloneElement, useContext, MouseEvent } from 'react';

import type { Props, Attach } from './TourPoint.types';
import { Footer, Steps, TourPointStyled } from './TourPoint.style';
import { TourContext } from './TourPoint.context';
import { Motion } from './TourPoint.motion';
import { Caret, buildClipPaths } from './Caret';

import { Header, Paragraph } from '../../typography';
import { Button } from '../Button/Button';
import { capitalize } from '../../utils';
import {
Anchor,
useAnchor,
} from '../../utils/hooks/useAnchor/useAnchor';
import { usePortal, capitalize } from '../../utils';
Popover,
PopoverAlign,
PopoverPosition,
} from 'react-tiny-popover';

TourPoint.Motion = Motion;

const lessThan = (a: number, b: number) => a < b && a;
const greaterThan = (a: number, b: number) => a > b || a;

type compareFn = (nextIndex, totalSteps) => number | boolean;

export function TourPoint({
active = true,
alt = null,
attach = 'left',
active,
content,
children,
// legacy
attach,
positions,
align,
style,
src,
alt = '',
title,
onClose,
confirmation = 'Got it',
dismission = 'Dismiss',
content,
getStepsTranslation,
onClose,
src,
step,
style,
title,
step = 0,
...props
}: Props) {
const {
Expand All @@ -47,23 +48,32 @@ export function TourPoint({
steps,
} = useContext(TourContext);

const ref = useRef(null);
const refAnchor = useRef(null);
const childrenClone = cloneElement(children, { ref });
const propsAnchor = useAnchor(ref, attach, active);
let pos = positions;
let alignment = align;
let clipPaths = {};
let margin = {};
const marginSize = '1rem';
if (attach && !positions) {
[pos, alignment] = convertAttachToPositionAlign(attach);
clipPaths = buildClipPaths(attach);
const [side] = attach.split('-');
const marginSide = 'margin' + capitalize(side);
margin = { [marginSide]: marginSize };
}

const Image = src && <img src={src} alt={alt} />;
const Title = title && <Header size="3">{title}</Header>;

const Content = slotProgressive(content, <Paragraph size="1" />);

function stepFn(direction, increment = 0, compare = null) {
const next = compare ? compare(index + increment, steps) : null;
function stepFn(direction, increment = 0, compare?: compareFn) {
const next = compare
? compare((index || 0) + increment, steps)
: null;

return (event: MouseEvent) => {
if (automated) {
onClose?.(event, { direction });
indexSet(next);
indexSet?.(next);
}
};
}
Expand All @@ -82,58 +92,89 @@ export function TourPoint({
<Button variant="minimalTransparent" onClick={dismiss} />
);

const clipPath = buildClipPaths(attach);

const side = attach.split('-')[0] || attach;
const marginSide = 'margin' + capitalize(side);
const margin = '1rem';

const zIndex = style?.zIndex || 6000;

const childrenPortal = usePortal(
<Anchor zIndex={zIndex} {...propsAnchor}>
<Motion attach={attach}>
<TourPointStyled
style={{
...style,
...clipPath,
[marginSide]: margin,
}}
ref={refAnchor}
{...props}
>
{Image}
{Title}
{Content}

<Footer>
{steps && (
<Steps onClick={stepBack}>
{getStepsTranslation
? getStepsTranslation({
currentStep: step,
totalSteps: steps,
})
: `Step ${step} of ${steps}`}
</Steps>
)}
{Dismiss}
{Confirm}
</Footer>
<Caret attach={attach} />
</TourPointStyled>
</Motion>
</Anchor>
);

return (
<>
{childrenClone}
{childrenPortal}
</>
<Motion attach={attach}>
<Popover
isOpen={!!active}
positions={pos}
align={alignment}
containerStyle={{
// Added so this is rendered on the same plane as useAnchor currently is.
// This should be removed once useAnchor is totally deprecated.
zIndex: '5000',
}}
content={
<TourPointStyled
style={{
...style,
...clipPaths,
...margin,
}}
{...props}
>
{Image}
{Title}
{Content}
<Footer>
{steps && (
<Steps onClick={stepBack}>
{getStepsTranslation
? getStepsTranslation({
currentStep: step,
totalSteps: steps,
})
: `Step ${step} of ${steps}`}
</Steps>
)}
{Dismiss}
{Confirm}
</Footer>
<Caret attach={attach} />
</TourPointStyled>
}
>
{children}
</Popover>
</Motion>
);
}

function convertAttachToPositionAlign(
attach: Attach
): [PopoverPosition[], PopoverAlign] {
const [side, placement] = attach.split('-');

let position: PopoverPosition = 'right';
switch (side) {
case 'bottom':
position = 'top';
break;
case 'right':
position = 'left';
break;
case 'top':
position = 'bottom';
break;
default:
break;
}

let align: PopoverAlign = 'center';
switch (placement) {
case 'top':
case 'left':
align = 'start';
break;
case 'bottom':
case 'right':
align = 'end';
default:
break;
}

return [[position], align];
}

function slotProgressive(children, Wrapper) {
const ProgressiveElement =
typeof children === 'string' || typeof children === 'number'
Expand Down
20 changes: 11 additions & 9 deletions src/components/TourPoint/TourPoint.types.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import {
CSSProperties,
ReactElement,
ReactNode,
MouseEvent,
} from 'react';
import { CSSProperties, ReactNode, MouseEvent } from 'react';
import { PopoverAlign, PopoverPosition } from 'react-tiny-popover';
export interface Props {
id?: string;
active?: boolean;
Expand All @@ -18,7 +14,7 @@ export interface Props {
* [default = 'left']
*/
attach?: Attach;
children?: ReactElement;
children?: JSX.Element;
confirmation?: ReactNode;
content?: ReactNode;
dismission?: ReactNode;
Expand All @@ -28,7 +24,7 @@ export interface Props {
* The address or URL of the a media resource that is to be considered.
*/
src?: HTMLImageElement['src'];
step?: number | null;
step: number;
style?: CSSProperties;
title?: HTMLElement['title'];
getStepsTranslation?: ({
Expand All @@ -38,11 +34,17 @@ export interface Props {
currentStep: number;
totalSteps: number;
}) => string;

/**
* react-tiny-popover props not yet implemented
*/
positions?: PopoverPosition[];
align?: PopoverAlign;
}

type StepEvent = { direction: 'back' | 'next' | 'dismiss' };

type Attach =
export type Attach =
| 'right'
| 'right-top'
| 'right-bottom'
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -13490,6 +13490,11 @@ react-syntax-highlighter@^15.4.5:
prismjs "^1.27.0"
refractor "^3.6.0"

react-tiny-popover@^7.2.3:
version "7.2.3"
resolved "https://registry.yarnpkg.com/react-tiny-popover/-/react-tiny-popover-7.2.3.tgz#5130b2162a117c646c8448218306ac90c56d6cc8"
integrity sha512-Gcufxg7kZMVMWAEveMDZEt1cwhP+x/2uVmYAV52Cp2ZBxXabUkAlzWrRlwKEiqjBVkFtIgBmycb1fGNX38/5hA==

react@*:
version "17.0.1"
resolved "https://registry.yarnpkg.com/react/-/react-17.0.1.tgz#6e0600416bd57574e3f86d92edba3d9008726127"
Expand Down

0 comments on commit b607541

Please sign in to comment.