Skip to content

Commit ed47661

Browse files
authored
fix(ui): tooltip positioning issues (#6439)
1 parent e682cb1 commit ed47661

File tree

31 files changed

+416
-418
lines changed

31 files changed

+416
-418
lines changed

packages/richtext-lexical/src/field/Field.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,14 @@ const _RichText: React.FC<
8484
width,
8585
}}
8686
>
87+
<FieldLabel
88+
CustomLabel={CustomLabel}
89+
label={label}
90+
required={required}
91+
{...(labelProps || {})}
92+
/>
8793
<div className={`${baseClass}__wrap`}>
8894
<FieldError CustomError={CustomError} path={path} {...(errorProps || {})} />
89-
<FieldLabel
90-
CustomLabel={CustomLabel}
91-
label={label}
92-
required={required}
93-
{...(labelProps || {})}
94-
/>
9595
<ErrorBoundary fallbackRender={fallbackRender} onReset={() => {}}>
9696
<LexicalProvider
9797
editorConfig={editorConfig}

packages/richtext-lexical/src/field/features/blocks/component/index.scss

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,6 @@
106106
line-height: unset;
107107
}
108108

109-
&__error-wrap {
110-
position: relative;
111-
}
112-
113109
&__rows {
114110
display: flex;
115111
flex-direction: column;

packages/richtext-lexical/src/field/index.scss

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
@import '../scss/styles.scss';
22

33
.rich-text-lexical {
4-
display: flex;
5-
64
.errorBoundary {
75
pre {
86
text-wrap: unset;

packages/richtext-slate/src/field/RichText.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -315,14 +315,14 @@ const RichTextField: React.FC<
315315
width,
316316
}}
317317
>
318+
<FieldLabel
319+
CustomLabel={CustomLabel}
320+
label={label}
321+
required={required}
322+
{...(labelProps || {})}
323+
/>
318324
<div className={`${baseClass}__wrap`}>
319325
<FieldError CustomError={CustomError} path={path} {...(errorProps || {})} />
320-
<FieldLabel
321-
CustomLabel={CustomLabel}
322-
label={label}
323-
required={required}
324-
{...(labelProps || {})}
325-
/>
326326
<Slate
327327
editor={editor}
328328
key={JSON.stringify({ initialValue, path })} // makes sure slate is completely re-rendered when initialValue changes, bypassing the slate-internal value memoization. That way, external changes to the form will update the editor

packages/ui/src/elements/Tooltip/index.scss

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
opacity: 0;
77
background-color: var(--theme-elevation-800);
88
position: absolute;
9-
z-index: 2;
9+
z-index: 3;
1010
left: 50%;
1111
padding: base(0.2) base(0.4);
1212
color: var(--theme-elevation-0);
@@ -52,8 +52,9 @@
5252
}
5353
}
5454

55+
5556
&--position-top {
56-
bottom: 100%;
57+
top: calc(var(--base) * -0.6 - 13px);
5758
transform: translate3d(-50%, calc(var(--caret-size) * -1), 0);
5859

5960
&::after {
@@ -62,8 +63,9 @@
6263
}
6364
}
6465

66+
6567
&--position-bottom {
66-
top: 100%;
68+
bottom: calc(var(--base) * -0.6 - 13px);
6769
transform: translate3d(-50%, var(--caret-size), 0);
6870

6971
&::after {

packages/ui/src/elements/Tooltip/index.tsx

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ export type Props = {
1111
className?: string
1212
delay?: number
1313
show?: boolean
14+
/**
15+
* If the tooltip position should not change depending on if the toolbar is outside the boundingRef. @default false
16+
*/
17+
staticPositioning?: boolean
1418
}
1519

1620
export const Tooltip: React.FC<Props> = (props) => {
@@ -21,18 +25,22 @@ export const Tooltip: React.FC<Props> = (props) => {
2125
className,
2226
delay = 350,
2327
show: showFromProps = true,
28+
staticPositioning = false,
2429
} = props
2530

2631
const [show, setShow] = React.useState(showFromProps)
2732
const [position, setPosition] = React.useState<'bottom' | 'top'>('top')
2833

2934
const getTitleAttribute = (content) => (typeof content === 'string' ? content : '')
3035

31-
const [ref, intersectionEntry] = useIntersect({
32-
root: boundingRef?.current || null,
33-
rootMargin: '-145px 0px 0px 100px',
34-
threshold: 0,
35-
})
36+
const [ref, intersectionEntry] = useIntersect(
37+
{
38+
root: boundingRef?.current || null,
39+
rootMargin: '-145px 0px 0px 100px',
40+
threshold: 0,
41+
},
42+
staticPositioning,
43+
)
3644

3745
useEffect(() => {
3846
let timerId: NodeJS.Timeout
@@ -52,22 +60,25 @@ export const Tooltip: React.FC<Props> = (props) => {
5260
}, [showFromProps, delay])
5361

5462
useEffect(() => {
63+
if (staticPositioning) return
5564
setPosition(intersectionEntry?.isIntersecting ? 'top' : 'bottom')
56-
}, [intersectionEntry])
65+
}, [intersectionEntry, staticPositioning])
5766

67+
// The first aside is always on top. The purpose of that is that it can reliably be used for the interaction observer (as it's not moving around), to calculate the position of the actual tooltip.
5868
return (
5969
<React.Fragment>
60-
<aside
61-
aria-hidden="true"
62-
className={['tooltip', className, `tooltip--caret-${alignCaret}`, 'tooltip--position-top']
63-
.filter(Boolean)
64-
.join(' ')}
65-
ref={ref}
66-
title={getTitleAttribute(children)}
67-
>
68-
<div className="tooltip-content">{children}</div>
69-
</aside>
70-
70+
{!staticPositioning && (
71+
<aside
72+
aria-hidden="true"
73+
className={['tooltip', className, `tooltip--caret-${alignCaret}`, 'tooltip--position-top']
74+
.filter(Boolean)
75+
.join(' ')}
76+
ref={ref}
77+
style={{ opacity: '0' }}
78+
>
79+
<div className="tooltip-content">{children}</div>
80+
</aside>
81+
)}
7182
<aside
7283
className={[
7384
'tooltip',

packages/ui/src/fields/Array/index.scss

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,6 @@
5454
}
5555
}
5656

57-
&__error-wrap {
58-
position: relative;
59-
}
60-
6157
&__row-header {
6258
display: flex;
6359
align-items: center;

packages/ui/src/fields/Array/index.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -202,11 +202,7 @@ export const _ArrayField: React.FC<ArrayFieldProps> = (props) => {
202202
.join(' ')}
203203
id={`field-${path.replace(/\./g, '__')}`}
204204
>
205-
{showError && (
206-
<div className={`${baseClass}__error-wrap`}>
207-
<FieldError CustomError={CustomError} path={path} {...(errorProps || {})} />
208-
</div>
209-
)}
205+
{showError && <FieldError CustomError={CustomError} path={path} {...(errorProps || {})} />}
210206
<header className={`${baseClass}__header`}>
211207
<div className={`${baseClass}__header-wrap`}>
212208
<div className={`${baseClass}__header-content`}>

packages/ui/src/fields/Blocks/index.scss

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,6 @@
7575
line-height: unset;
7676
}
7777

78-
&__error-wrap {
79-
position: relative;
80-
}
81-
8278
&__rows {
8379
display: flex;
8480
flex-direction: column;

packages/ui/src/fields/Blocks/index.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -215,11 +215,7 @@ const _BlocksField: React.FC<BlocksFieldProps> = (props) => {
215215
.join(' ')}
216216
id={`field-${path.replace(/\./g, '__')}`}
217217
>
218-
{showError && (
219-
<div className={`${baseClass}__error-wrap`}>
220-
<FieldError CustomError={CustomError} path={path} {...(errorProps || {})} />
221-
</div>
222-
)}
218+
{showError && <FieldError CustomError={CustomError} path={path} {...(errorProps || {})} />}
223219
<header className={`${baseClass}__header`}>
224220
<div className={`${baseClass}__header-wrap`}>
225221
<div className={`${baseClass}__heading-with-error`}>

0 commit comments

Comments
 (0)