diff --git a/packages/console/src/components/ActionMenu/index.tsx b/packages/console/src/components/ActionMenu/index.tsx
index c8937af61..93903b262 100644
--- a/packages/console/src/components/ActionMenu/index.tsx
+++ b/packages/console/src/components/ActionMenu/index.tsx
@@ -2,7 +2,7 @@ import classNames from 'classnames';
import type { ReactNode } from 'react';
import { useRef, useState } from 'react';
-import type { HorizontalAlignment } from '@/hooks/use-position';
+import type { HorizontalAlignment } from '@/types/positioning';
import type { Props as ButtonProps } from '../Button';
import Dropdown from '../Dropdown';
diff --git a/packages/console/src/components/Dropdown/index.tsx b/packages/console/src/components/Dropdown/index.tsx
index 84f8770a1..6c952167e 100644
--- a/packages/console/src/components/Dropdown/index.tsx
+++ b/packages/console/src/components/Dropdown/index.tsx
@@ -3,8 +3,8 @@ import type { ReactNode, RefObject } from 'react';
import { useRef } from 'react';
import ReactModal from 'react-modal';
-import type { HorizontalAlignment } from '@/hooks/use-position';
import usePosition from '@/hooks/use-position';
+import type { HorizontalAlignment } from '@/types/positioning';
import { onKeyDownHandler } from '@/utilities/a11y';
import * as styles from './index.module.scss';
diff --git a/packages/console/src/components/FormField/index.tsx b/packages/console/src/components/FormField/index.tsx
index f672d7ad4..f101db946 100644
--- a/packages/console/src/components/FormField/index.tsx
+++ b/packages/console/src/components/FormField/index.tsx
@@ -29,7 +29,7 @@ const FormField = ({ title, children, isRequired, className, tip, headlineClassN
{typeof title === 'string' ? t(title) : title}
{tip && (
-
+
diff --git a/packages/console/src/components/Tip/TipBubble/index.module.scss b/packages/console/src/components/Tip/TipBubble/index.module.scss
index 5f8ab299b..4f3de85fc 100644
--- a/packages/console/src/components/Tip/TipBubble/index.module.scss
+++ b/packages/console/src/components/Tip/TipBubble/index.module.scss
@@ -1,15 +1,19 @@
@use '@/scss/underscore' as _;
.tipBubble {
- position: relative;
+ position: absolute;
border-radius: 8px;
background: var(--color-tooltip-background);
color: var(--color-tooltip-text);
- box-shadow: var(--shadow-1);
+ box-shadow: var(--shadow-2);
padding: _.unit(2) _.unit(3);
font: var(--font-body-medium);
max-width: 300px;
+ &.invisible {
+ opacity: 0%;
+ }
+
a {
color: #cabeff;
@@ -18,8 +22,7 @@
}
}
- &::after {
- content: '';
+ .arrow {
display: block;
position: absolute;
width: 10px;
@@ -29,34 +32,29 @@
transform: translate(-50%, -50%) rotate(45deg);
}
- &.top::after {
- top: 100%;
+ &.top {
+ .arrow {
+ top: 100%;
+ }
}
- &.right::after {
- top: 50%;
- left: 0%;
+ &.right {
+ .arrow {
+ top: 50%;
+ left: 0%;
+ }
}
- &.bottom::after {
- top: 0%;
+ &.bottom {
+ .arrow {
+ top: 0%;
+ }
}
- &.left::after {
- top: 50%;
- left: 100%;
- }
-
- &.start::after {
- left: _.unit(10);
- }
-
-
- &.center::after {
- left: 50%;
- }
-
- &.end::after {
- right: _.unit(7.5);
+ &.left {
+ .arrow {
+ top: 50%;
+ left: 100%;
+ }
}
}
diff --git a/packages/console/src/components/Tip/TipBubble/index.tsx b/packages/console/src/components/Tip/TipBubble/index.tsx
index c2c2cd0af..2540527df 100644
--- a/packages/console/src/components/Tip/TipBubble/index.tsx
+++ b/packages/console/src/components/Tip/TipBubble/index.tsx
@@ -1,41 +1,64 @@
import { conditional } from '@silverhand/essentials';
import classNames from 'classnames';
import { forwardRef } from 'react';
-import type { ForwardedRef, ReactNode, HTMLProps } from 'react';
+import type { ForwardedRef, ReactNode, HTMLProps, RefObject } from 'react';
-import type { HorizontalAlignment } from '@/hooks/use-position';
+import type { HorizontalAlignment, Position } from '@/types/positioning';
import * as styles from './index.module.scss';
-export type TipBubblePosition = 'top' | 'right' | 'bottom' | 'left';
+export type TipBubblePlacement = 'top' | 'right' | 'bottom' | 'left';
type Props = HTMLProps & {
children: ReactNode;
- position?: TipBubblePosition;
+ position?: Position;
+ anchorRef: RefObject;
+ placement?: TipBubblePlacement;
horizontalAlignment?: HorizontalAlignment;
className?: string;
};
-const supportHorizontalAlignmentPositions = new Set(['top', 'bottom']);
+const supportHorizontalAlignmentPlacements = new Set(['top', 'bottom']);
const TipBubble = (
- { children, position = 'bottom', horizontalAlignment = 'center', className, ...rest }: Props,
+ {
+ children,
+ position,
+ placement = 'bottom',
+ horizontalAlignment = 'center',
+ className,
+ anchorRef,
+ ...rest
+ }: Props,
reference: ForwardedRef
) => {
+ if (!anchorRef.current) {
+ return null;
+ }
+
+ const anchorRect = anchorRef.current.getBoundingClientRect();
+
+ const arrowPosition = conditional(
+ supportHorizontalAlignmentPlacements.has(placement) &&
+ position && {
+ left: anchorRect.x + anchorRect.width / 2 - Number(position.left),
+ }
+ );
+
return (
);
};
diff --git a/packages/console/src/components/Tip/TipBubble/utils.ts b/packages/console/src/components/Tip/TipBubble/utils.ts
index fd416d9a2..9c0ad6aa4 100644
--- a/packages/console/src/components/Tip/TipBubble/utils.ts
+++ b/packages/console/src/components/Tip/TipBubble/utils.ts
@@ -1,9 +1,9 @@
-import type { HorizontalAlignment, VerticalAlignment } from '@/hooks/use-position';
+import type { HorizontalAlignment, VerticalAlignment } from '@/types/positioning';
-import type { TipBubblePosition } from '.';
+import type { TipBubblePlacement } from '.';
-export const getVerticalOffset = (position: TipBubblePosition) => {
- switch (position) {
+export const getVerticalOffset = (placement: TipBubblePlacement) => {
+ switch (placement) {
case 'top':
return -16;
case 'bottom':
@@ -14,10 +14,10 @@ export const getVerticalOffset = (position: TipBubblePosition) => {
};
export const getHorizontalOffset = (
- tooltipPosition: TipBubblePosition,
+ placement: TipBubblePlacement,
horizontalAlignment: HorizontalAlignment
): number => {
- if (tooltipPosition === 'top' || tooltipPosition === 'bottom') {
+ if (placement === 'top' || placement === 'bottom') {
switch (horizontalAlignment) {
case 'start':
return -32;
@@ -27,12 +27,12 @@ export const getHorizontalOffset = (
return 0;
}
} else {
- return tooltipPosition === 'left' ? -32 : 32;
+ return placement === 'left' ? -32 : 32;
}
};
-export const getVerticalAlignment = (position: TipBubblePosition): VerticalAlignment => {
- switch (position) {
+export const getVerticalAlignment = (placement: TipBubblePlacement): VerticalAlignment => {
+ switch (placement) {
case 'top':
return 'top';
case 'bottom':
@@ -43,10 +43,10 @@ export const getVerticalAlignment = (position: TipBubblePosition): VerticalAlign
};
export const getHorizontalAlignment = (
- position: TipBubblePosition,
+ placement: TipBubblePlacement,
fallback: HorizontalAlignment
): HorizontalAlignment => {
- switch (position) {
+ switch (placement) {
case 'right':
return 'start';
case 'left':
diff --git a/packages/console/src/components/Tip/ToggleTip/index.module.scss b/packages/console/src/components/Tip/ToggleTip/index.module.scss
index 0c0816adb..d9a91ab64 100644
--- a/packages/console/src/components/Tip/ToggleTip/index.module.scss
+++ b/packages/console/src/components/Tip/ToggleTip/index.module.scss
@@ -1,16 +1,15 @@
@use '@/scss/underscore' as _;
-.content {
- box-shadow: var(--shadow-2);
- position: absolute;
-
- &:focus {
- outline: none;
- }
-}
-
.overlay {
background: transparent;
position: fixed;
inset: 0;
+
+ .content {
+ position: relative;
+
+ &:focus {
+ outline: none;
+ }
+ }
}
diff --git a/packages/console/src/components/Tip/ToggleTip/index.tsx b/packages/console/src/components/Tip/ToggleTip/index.tsx
index da46eab14..42bce18df 100644
--- a/packages/console/src/components/Tip/ToggleTip/index.tsx
+++ b/packages/console/src/components/Tip/ToggleTip/index.tsx
@@ -2,11 +2,11 @@ import type { ReactNode } from 'react';
import { useCallback, useState, useRef } from 'react';
import ReactModal from 'react-modal';
-import type { HorizontalAlignment } from '@/hooks/use-position';
import usePosition from '@/hooks/use-position';
+import type { HorizontalAlignment } from '@/types/positioning';
import { onKeyDownHandler } from '@/utilities/a11y';
-import type { TipBubblePosition } from '../TipBubble';
+import type { TipBubblePlacement } from '../TipBubble';
import TipBubble from '../TipBubble';
import {
getVerticalAlignment,
@@ -20,7 +20,7 @@ export type Props = {
children: ReactNode;
className?: string;
anchorClassName?: string;
- position?: TipBubblePosition;
+ placement?: TipBubblePlacement;
horizontalAlign?: HorizontalAlignment;
content?: ((closeTip: () => void) => ReactNode) | ReactNode;
};
@@ -29,11 +29,11 @@ const ToggleTip = ({
children,
className,
anchorClassName,
- position = 'top',
+ placement = 'top',
horizontalAlign = 'center',
content,
}: Props) => {
- const overlayRef = useRef(null);
+ const tipBubbleRef = useRef(null);
const anchorRef = useRef(null);
const [isOpen, setIsOpen] = useState(false);
@@ -47,14 +47,14 @@ const ToggleTip = ({
positionState,
mutate,
} = usePosition({
- verticalAlign: getVerticalAlignment(position),
- horizontalAlign: getHorizontalAlignment(position, horizontalAlign),
+ verticalAlign: getVerticalAlignment(placement),
+ horizontalAlign: getHorizontalAlignment(placement, horizontalAlign),
offset: {
- vertical: getVerticalOffset(position),
- horizontal: getHorizontalOffset(position, horizontalAlign),
+ vertical: getVerticalOffset(placement),
+ horizontal: getHorizontalOffset(placement, horizontalAlign),
},
anchorRef,
- overlayRef,
+ overlayRef: tipBubbleRef,
});
return (
@@ -77,20 +77,16 @@ const ToggleTip = ({
shouldCloseOnOverlayClick
shouldCloseOnEsc
isOpen={isOpen}
- style={{
- content: {
- ...(!layoutPosition && { opacity: 0 }),
- ...layoutPosition,
- },
- }}
className={styles.content}
overlayClassName={styles.overlay}
onRequestClose={onClose}
onAfterOpen={mutate}
>
diff --git a/packages/console/src/components/Tip/Tooltip/index.module.scss b/packages/console/src/components/Tip/Tooltip/index.module.scss
index bc2af8bca..2e1ddb9ff 100644
--- a/packages/console/src/components/Tip/Tooltip/index.module.scss
+++ b/packages/console/src/components/Tip/Tooltip/index.module.scss
@@ -1,9 +1,5 @@
@use '@/scss/underscore' as _;
-.tooltip {
- position: absolute;
-
- .content {
- @include _.multi-line-ellipsis(6);
- }
+.content {
+ @include _.multi-line-ellipsis(6);
}
diff --git a/packages/console/src/components/Tip/Tooltip/index.tsx b/packages/console/src/components/Tip/Tooltip/index.tsx
index c9aa037dc..4d6be04c5 100644
--- a/packages/console/src/components/Tip/Tooltip/index.tsx
+++ b/packages/console/src/components/Tip/Tooltip/index.tsx
@@ -2,11 +2,11 @@ import type { ReactNode } from 'react';
import { useEffect, useLayoutEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
-import type { HorizontalAlignment } from '@/hooks/use-position';
import usePosition from '@/hooks/use-position';
+import type { HorizontalAlignment } from '@/types/positioning';
import TipBubble from '../TipBubble';
-import type { TipBubblePosition } from '../TipBubble';
+import type { TipBubblePlacement } from '../TipBubble';
import {
getVerticalAlignment,
getHorizontalAlignment,
@@ -18,7 +18,7 @@ import * as styles from './index.module.scss';
type Props = {
className?: string;
isKeepOpen?: boolean;
- position?: TipBubblePosition;
+ placement?: TipBubblePlacement;
horizontalAlign?: HorizontalAlignment;
anchorClassName?: string;
children?: ReactNode;
@@ -28,7 +28,7 @@ type Props = {
const Tooltip = ({
className,
isKeepOpen = false,
- position = 'top',
+ placement = 'top',
horizontalAlign = 'center',
anchorClassName,
children,
@@ -38,16 +38,12 @@ const Tooltip = ({
const anchorRef = useRef(null);
const tooltipRef = useRef(null);
- const {
- position: layoutPosition,
- positionState,
- mutate,
- } = usePosition({
- verticalAlign: getVerticalAlignment(position),
- horizontalAlign: getHorizontalAlignment(position, horizontalAlign),
+ const { position, positionState, mutate } = usePosition({
+ verticalAlign: getVerticalAlignment(placement),
+ horizontalAlign: getHorizontalAlignment(placement, horizontalAlign),
offset: {
- vertical: getVerticalOffset(position),
- horizontal: getHorizontalOffset(position, horizontalAlign),
+ vertical: getVerticalOffset(placement),
+ horizontal: getHorizontalOffset(placement, horizontalAlign),
},
anchorRef,
overlayRef: tooltipRef,
@@ -132,17 +128,16 @@ const Tooltip = ({
{tooltipDom &&
content &&
createPortal(
- ,
+
+ {content}
+ ,
tooltipDom
)}
>
diff --git a/packages/console/src/hooks/use-position.ts b/packages/console/src/hooks/use-position.ts
index d7d5d0885..a4910aea9 100644
--- a/packages/console/src/hooks/use-position.ts
+++ b/packages/console/src/hooks/use-position.ts
@@ -1,14 +1,7 @@
import type { RefObject } from 'react';
import { useCallback, useEffect, useState } from 'react';
-export type VerticalAlignment = 'top' | 'middle' | 'bottom';
-
-export type HorizontalAlignment = 'start' | 'center' | 'end';
-
-type Offset = {
- vertical: number;
- horizontal: number;
-};
+import type { HorizontalAlignment, Offset, Position, VerticalAlignment } from '@/types/positioning';
type Props = {
verticalAlign: VerticalAlignment;
@@ -18,11 +11,6 @@ type Props = {
overlayRef: RefObject;
};
-type Position = {
- top: number;
- left: number;
-};
-
// Leave space for box-shadow effect.
const windowSafePadding = 12;
diff --git a/packages/console/src/pages/Applications/components/GuideHeader/index.tsx b/packages/console/src/pages/Applications/components/GuideHeader/index.tsx
index 3ec1a9b32..f59163cd3 100644
--- a/packages/console/src/pages/Applications/components/GuideHeader/index.tsx
+++ b/packages/console/src/pages/Applications/components/GuideHeader/index.tsx
@@ -63,7 +63,7 @@ const GuideHeader = ({ appName, selectedSdk, isCompact = false, onClose }: Props
/>
diff --git a/packages/console/src/types/positioning.ts b/packages/console/src/types/positioning.ts
new file mode 100644
index 000000000..a56b8d52c
--- /dev/null
+++ b/packages/console/src/types/positioning.ts
@@ -0,0 +1,13 @@
+export type Position = {
+ top: number;
+ left: number;
+};
+
+export type Offset = {
+ horizontal: number;
+ vertical: number;
+};
+
+export type HorizontalAlignment = 'start' | 'center' | 'end';
+
+export type VerticalAlignment = 'top' | 'middle' | 'bottom';