Skip to content

Commit 9fae9e3

Browse files
gabrieljablonskidanielbarion
authored andcommitted
improve how data changes are handled
1 parent 5308a5c commit 9fae9e3

File tree

5 files changed

+35
-56
lines changed

5 files changed

+35
-56
lines changed

src/components/Tooltip/Tooltip.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ const Tooltip = ({
175175
strategy: positionStrategy,
176176
}).then((computedStylesData) => {
177177
if (!mounted) {
178-
// invalidate computed positions after unmount
178+
// invalidate computed positions after remount
179179
return
180180
}
181181
setCalculatingPosition(false)

src/components/Tooltip/TooltipTypes.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export type DataAttribute =
2727
export interface ITooltip {
2828
className?: string
2929
classNameArrow?: string
30-
content?: string | number
30+
content?: string
3131
html?: string
3232
place?: PlacesType
3333
offset?: number

src/components/TooltipController/TooltipController.tsx

Lines changed: 30 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type {
77
VariantType,
88
WrapperType,
99
DataAttribute,
10+
ITooltip,
1011
} from 'components/Tooltip/TooltipTypes'
1112
import { useTooltip } from 'components/TooltipProvider'
1213
import type { ITooltipController } from './TooltipControllerTypes'
@@ -46,10 +47,11 @@ const TooltipController = ({
4647
const getDataAttributesFromAnchorElement = (elementReference: HTMLElement) => {
4748
const dataAttributes = elementReference?.getAttributeNames().reduce((acc, name) => {
4849
if (name.startsWith('data-tooltip-')) {
49-
acc[name] = elementReference?.getAttribute(name) ?? null
50+
const parsedAttribute = name.replace(/^data-tooltip-/, '') as DataAttribute
51+
acc[parsedAttribute] = elementReference?.getAttribute(name) ?? null
5052
}
5153
return acc
52-
}, {} as Record<string, string | null>)
54+
}, {} as Record<DataAttribute, string | null>)
5355

5456
return dataAttributes
5557
}
@@ -63,51 +65,43 @@ const TooltipController = ({
6365
},
6466
content: (value) => {
6567
setIsHtmlContent(false)
66-
setTooltipContent(value ?? '')
68+
setTooltipContent(value ?? content)
6769
},
6870
html: (value) => {
6971
setIsHtmlContent(true)
70-
setTooltipContent(value ?? '')
72+
setTooltipContent(value ?? html)
7173
},
7274
variant: (value) => {
7375
setTooltipVariant((value as VariantType) ?? variant)
7476
},
7577
offset: (value) => {
76-
setTooltipOffset(Number(value) ?? offset)
78+
setTooltipOffset(value === null ? offset : Number(value))
7779
},
7880
wrapper: (value) => {
79-
setTooltipWrapper((value as WrapperType) ?? wrapper)
81+
setTooltipWrapper((value as WrapperType) ?? 'div')
8082
},
8183
events: (value) => {
82-
const parsedEvents = value?.split(' ')
83-
setTooltipEvents((parsedEvents as EventsType[]) ?? events)
84+
const parsed = value?.split(' ') as EventsType[]
85+
setTooltipEvents(parsed ?? events)
8486
},
8587
'position-strategy': (value) => {
8688
setTooltipPositionStrategy((value as PositionStrategy) ?? positionStrategy)
8789
},
8890
'delay-show': (value) => {
89-
setTooltipDelayShow(Number(value) ?? delayShow)
91+
setTooltipDelayShow(value === null ? delayShow : Number(value))
9092
},
9193
'delay-hide': (value) => {
92-
setTooltipDelayHide(Number(value) ?? delayHide)
94+
setTooltipDelayHide(value === null ? delayHide : Number(value))
9395
},
9496
}
97+
// reset unset data attributes to default values
98+
// without this, data attributes from the last active anchor will still be used
99+
Object.values(handleDataAttributes).forEach((handler) => handler(null))
95100
Object.entries(dataAttributes).forEach(([key, value]) => {
96-
const formattedKey = key.replace(/^data-tooltip-/, '') as DataAttribute
97-
handleDataAttributes[formattedKey]?.(value)
101+
handleDataAttributes[key as DataAttribute]?.(value)
98102
})
99103
}
100104

101-
const getElementSpecificAttributeKeyAndValueParsed = ({
102-
element,
103-
attributeName,
104-
}: {
105-
element: HTMLElement
106-
attributeName: string
107-
}) => {
108-
return { [attributeName]: element.getAttribute(attributeName) }
109-
}
110-
111105
useEffect(() => {
112106
if (content) {
113107
setTooltipContent(content)
@@ -130,42 +124,35 @@ const TooltipController = ({
130124
return () => {}
131125
}
132126

133-
// do not check for subtree and childrens, we only want to know attribute changes
134-
// to stay watching `data-attributes` from anchor element
135-
const observerConfig = { attributes: true, childList: false, subtree: false }
136-
137127
const observerCallback: MutationCallback = (mutationList) => {
138128
mutationList.forEach((mutation) => {
139-
if (!activeAnchor.current) {
140-
return
141-
}
142-
if (mutation.type !== 'attributes' || !mutation.attributeName) {
129+
if (
130+
!activeAnchor.current ||
131+
mutation.type !== 'attributes' ||
132+
!mutation.attributeName?.startsWith('data-tooltip-')
133+
) {
143134
return
144135
}
145-
const attributeKeyAndValue = getElementSpecificAttributeKeyAndValueParsed({
146-
element: activeAnchor.current,
147-
attributeName: mutation.attributeName,
148-
})
149-
applyAllDataAttributesFromAnchorElement(attributeKeyAndValue)
136+
// make sure to get all set attributes, since all unset attributes are reset
137+
const dataAttributes = getDataAttributesFromAnchorElement(activeAnchor.current)
138+
applyAllDataAttributesFromAnchorElement(dataAttributes)
150139
})
151140
}
152141

153142
// Create an observer instance linked to the callback function
154143
const observer = new MutationObserver(observerCallback)
155144

156-
elementRefs.forEach((ref) => {
157-
if (!ref.current) {
158-
return
159-
}
160-
// Start observing the target nodes for configured mutations
161-
observer.observe(ref.current, observerConfig)
162-
})
145+
// do not check for subtree and childrens, we only want to know attribute changes
146+
// to stay watching `data-attributes-*` from anchor element
147+
const observerConfig = { attributes: true, childList: false, subtree: false }
163148

164149
const element = activeAnchor.current ?? anchorById
165150

166151
if (element) {
167152
const dataAttributes = getDataAttributesFromAnchorElement(element)
168153
applyAllDataAttributesFromAnchorElement(dataAttributes)
154+
// Start observing the target node for configured mutations
155+
observer.observe(element, observerConfig)
169156
}
170157

171158
return () => {
@@ -174,15 +161,7 @@ const TooltipController = ({
174161
}
175162
}, [anchorRefs, activeAnchor, anchorId])
176163

177-
useEffect(() => {
178-
if (!activeAnchor.current) {
179-
return
180-
}
181-
const dataAttributes = getDataAttributesFromAnchorElement(activeAnchor.current)
182-
applyAllDataAttributesFromAnchorElement(dataAttributes)
183-
}, [activeAnchor])
184-
185-
const props = {
164+
const props: ITooltip = {
186165
id,
187166
anchorId,
188167
className,

src/components/TooltipController/TooltipControllerTypes.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import type {
1212
export interface ITooltipController {
1313
className?: string
1414
classNameArrow?: string
15-
content?: string | number
15+
content?: string
1616
html?: string
1717
place?: PlacesType
1818
offset?: number
@@ -33,7 +33,7 @@ export interface ITooltipController {
3333
declare module 'react' {
3434
interface HTMLAttributes<T> extends AriaAttributes, DOMAttributes<T> {
3535
'data-tooltip-place'?: PlacesType
36-
'data-tooltip-content'?: string | number
36+
'data-tooltip-content'?: string
3737
'data-tooltip-html'?: string
3838
'data-tooltip-variant'?: VariantType
3939
'data-tooltip-offset'?: number

src/components/TooltipProvider/TooltipProviderTypes.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { MutableRefObject, ReactElement, RefObject } from 'react'
2-
import type { ITooltipController } from '../TooltipController/TooltipControllerTypes'
2+
import type { ITooltipController } from 'components/TooltipController/TooltipControllerTypes'
33

44
export type AnchorRef = RefObject<HTMLElement>
55

0 commit comments

Comments
 (0)