diff --git a/src/components/Floater/Arrow.tsx b/src/components/Floater/Arrow.tsx
index f2df769..ae357ae 100644
--- a/src/components/Floater/Arrow.tsx
+++ b/src/components/Floater/Arrow.tsx
@@ -8,37 +8,54 @@ interface Props {
styles: Styles;
}
+/**
+ * FloaterArrow component renders a customizable arrow for tooltips/popovers
+ * @param props Component properties
+ * @returns React component
+ */
export default function FloaterArrow(props: Props) {
const { arrowRef, placement, styles } = props;
-
const {
- arrow: { color, display, length, position, spread },
+ arrow: { color, display, length, position, rounded, spread },
} = styles;
+
+ const [direction] = placement.split('-');
+ const isVertical = direction === 'top' || direction === 'bottom';
+
const arrowStyles: React.CSSProperties = { display, position };
- let points;
- let x = spread;
- let y = length;
-
- if (placement.startsWith('top')) {
- points = `0,0 ${x / 2},${y} ${x},0`;
- } else if (placement.startsWith('bottom')) {
- points = `${x},${y} ${x / 2},0 0,${y}`;
- } else if (placement.startsWith('left')) {
- y = spread;
- x = length;
- points = `0,0 ${x},${y / 2} 0,${y}`;
- } else if (placement.startsWith('right')) {
- y = spread;
- x = length;
- points = `${x},${y} ${x},0 0,${y / 2}`;
+ const baseRadius = isVertical ? spread / 8 : length / 8;
+ const r = rounded ? baseRadius : 0;
+
+ const webkitMask = isVertical
+ ? `linear-gradient(0deg,#0000 calc(${r}px/sqrt(2)),#000 0),
+ radial-gradient(${r}px at 50% calc(100% - ${r}px*sqrt(2)),#000 98%,#0000 101%)`
+ : `linear-gradient(-90deg,#0000 calc(${r}px/sqrt(2)),#000 0),
+ radial-gradient(${r}px at calc(100% - ${r}px*sqrt(2)) 50%,#000 98%,#0000 101%)`;
+
+ const clipPath = isVertical ? 'polygon(50% 100%,100% 0,0 0)' : 'polygon(100% 50%,0 100%,0 0)';
+
+ let scales: string | undefined;
+
+ if (direction === 'bottom') {
+ scales = '1 -1';
+ } else if (direction === 'right') {
+ scales = '-1 1';
}
return (
-
-
-
+
);
}
diff --git a/src/modules/styles.ts b/src/modules/styles.ts
index 645ca51..2080888 100644
--- a/src/modules/styles.ts
+++ b/src/modules/styles.ts
@@ -18,6 +18,7 @@ export default function getStyles(styles?: PartialDeep): Styles {
length: 16,
position: 'absolute',
spread: 32,
+ rounded: false,
},
close: {
backgroundColor: 'transparent',
diff --git a/src/types/common.ts b/src/types/common.ts
index d1352f5..0d3f8a8 100644
--- a/src/types/common.ts
+++ b/src/types/common.ts
@@ -7,27 +7,19 @@ import {
} from 'react';
import { PartialDeep, RequireExactlyOne, ValueOf } from 'type-fest';
-import { PopperInstance, PopperModifiers, PopperPlacement } from './popper';
-
import { STATUS } from '../literals';
+import { PopperInstance, PopperModifiers, PopperPlacement } from './popper';
+
export type Action = 'open' | 'close';
export type CloseFunction = MouseEventHandler;
+export type FloaterComponent = FunctionComponent | ReactElement;
export type Placement = PopperPlacement | 'center';
-export type SelectorOrElement = string | null | HTMLElement;
-export type Statuses = ValueOf;
-
-export interface CustomComponentProps {
- closeFn: CloseFunction;
-}
+export type Props = RequireExactlyOne;
-export interface LogOptions {
- data: any;
- debug?: boolean;
- title: string;
-}
+export type SelectorOrElement = string | null | HTMLElement;
-export type FloaterComponent = FunctionComponent | ReactElement;
+export type Statuses = ValueOf;
export interface BaseProps {
/**
@@ -121,7 +113,15 @@ export interface BaseProps {
};
}
-export type Props = RequireExactlyOne;
+export interface CustomComponentProps {
+ closeFn: CloseFunction;
+}
+
+export interface LogOptions {
+ data: any;
+ debug?: boolean;
+ title: string;
+}
export interface State {
currentPlacement: Placement;
@@ -133,6 +133,7 @@ export interface State {
export interface Styles {
arrow: CSSProperties & {
length: number;
+ rounded: boolean;
spread: number;
};
close: CSSProperties;
diff --git a/test/__snapshots__/index.spec.tsx.snap b/test/__snapshots__/index.spec.tsx.snap
index 2221a8b..d7025ed 100644
--- a/test/__snapshots__/index.spec.tsx.snap
+++ b/test/__snapshots__/index.spec.tsx.snap
@@ -24,20 +24,8 @@ exports[`ReactFloater > with \`component\` as element > should show the floater
-
-
+ style="display: inline-flex; position: absolute; background-color: rgb(255, 255, 255); height: 16px; width: 32px; clip-path: polygon(50% 100%,100% 0,0 0); scale: 1 -1; left: 0px; transform: translate(8px, 0px); top: 0px;"
+ />
`;
@@ -66,20 +54,8 @@ exports[`ReactFloater > with \`component\` as function > should show the floater
-
-
+ style="display: inline-flex; position: absolute; background-color: rgb(255, 255, 255); height: 16px; width: 32px; clip-path: polygon(50% 100%,100% 0,0 0); scale: 1 -1; left: 0px; transform: translate(8px, 0px); top: 0px;"
+ />
`;
@@ -132,20 +108,8 @@ exports[`ReactFloater > with \`placement\` left > should show the floater with c
-
-
+ style="display: inline-flex; position: absolute; background-color: rgb(255, 255, 255); height: 32px; width: 16px; clip-path: polygon(100% 50%,0 100%,0 0); top: 0px; transform: translate(0px, 8px); right: 0px;"
+ />
`;
@@ -173,20 +137,8 @@ exports[`ReactFloater > with \`placement\` right > should show the floater with
-
-
+ style="display: inline-flex; position: absolute; background-color: rgb(255, 255, 255); height: 32px; width: 16px; clip-path: polygon(100% 50%,0 100%,0 0); scale: -1 1; top: 0px; transform: translate(0px, 8px); left: 0px;"
+ />
`;
@@ -214,20 +166,8 @@ exports[`ReactFloater > with \`placement\` top > should show the floater with cl
-
-
+ style="display: inline-flex; position: absolute; background-color: rgb(255, 255, 255); height: 16px; width: 32px; clip-path: polygon(50% 100%,100% 0,0 0); left: 0px; transform: translate(8px, 0px); bottom: 0px;"
+ />
`;
@@ -288,20 +228,8 @@ exports[`ReactFloater > with \`title\`, \`footer\` and \`closeBtn\` > should ren
-
-
+ style="display: inline-flex; position: absolute; background-color: rgb(255, 255, 255); height: 16px; width: 32px; clip-path: polygon(50% 100%,100% 0,0 0); scale: 1 -1; left: 0px; transform: translate(8px, 0px); top: 0px;"
+ />
`;