Skip to content

Commit

Permalink
feat(tooltip): make tooltip interactive
Browse files Browse the repository at this point in the history
  • Loading branch information
segunadebayo committed Nov 17, 2021
1 parent 130998f commit 7ac6e5a
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 6 deletions.
18 changes: 18 additions & 0 deletions packages/machines/src/tooltip/tooltip.connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,24 @@ export function tooltipConnect<T extends PropTypes = ReactPropTypes>(
tooltipProps: normalize.element<T>({
role: "tooltip",
id: tooltipId,
onPointerEnter() {
send("TOOLTIP_POINTER_ENTER")
},
onPointerLeave() {
send("TOOLTIP_POINTER_LEAVE")
},
style: {
pointerEvents: ctx.interactive ? "auto" : "none",
},
}),

setupPortal() {
const doc = dom.getDoc(ctx)
const exist = dom.getPortalEl(ctx)
if (exist) return exist
const portal = dom.createPortalEl(ctx)
doc.body.appendChild(portal)
return portal
},
}
}
8 changes: 8 additions & 0 deletions packages/machines/src/tooltip/tooltip.dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,16 @@ export const dom = {

getTriggerId: (ctx: Ctx) => `tooltip-${ctx.id}-trigger`,
getTooltipId: (ctx: Ctx) => `tooltip-${ctx.id}-content`,
portalId: "tooltip-portal",

getTriggerEl: (ctx: Ctx) => dom.getDoc(ctx).getElementById(dom.getTriggerId(ctx)),
getTooltipEl: (ctx: Ctx) => dom.getDoc(ctx).getElementById(dom.getTooltipId(ctx)),
getScrollParent: (ctx: Ctx) => getScrollParent(dom.getTriggerEl(ctx)),
getPortalEl: (ctx: Ctx) => dom.getDoc(ctx).getElementById(dom.portalId),

createPortalEl: (ctx: Ctx) => {
const portal = dom.getDoc(ctx).createElement("tooltip-portal")
portal.id = dom.portalId
return portal
},
}
33 changes: 28 additions & 5 deletions packages/machines/src/tooltip/tooltip.machine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const tooltipMachine = createMachine<TooltipMachineContext, TooltipMachin
openDelay: 700,
closeDelay: 300,
closeOnPointerDown: true,
interactive: true,
},
states: {
unknown: {
Expand All @@ -30,7 +31,7 @@ export const tooltipMachine = createMachine<TooltipMachineContext, TooltipMachin
},

closed: {
entry: "clearGlobalId",
entry: ["clearGlobalId", "invokeOnClose"],
on: {
FOCUS: "open",
POINTER_ENTER: [
Expand Down Expand Up @@ -61,7 +62,7 @@ export const tooltipMachine = createMachine<TooltipMachineContext, TooltipMachin

open: {
activities: ["trackEscapeKey", "trackPointermoveForSafari", "trackWindowScroll", "trackPointerlockChange"],
entry: "setGlobalId",
entry: ["setGlobalId", "invokeOnOpen"],
on: {
POINTER_LEAVE: [
{
Expand All @@ -74,6 +75,10 @@ export const tooltipMachine = createMachine<TooltipMachineContext, TooltipMachin
ESCAPE: "closed",
SCROLL: "closed",
POINTER_LOCK_CHANGE: "closed",
TOOLTIP_POINTER_LEAVE: {
guard: "isInteractive",
target: "closing",
},
POINTER_DOWN: {
guard: "closeOnPointerDown",
target: "closed",
Expand All @@ -89,14 +94,19 @@ export const tooltipMachine = createMachine<TooltipMachineContext, TooltipMachin
},
on: {
FORCE_CLOSE: "closed",
POINTER_ENTER: "open",
TOOLTIP_POINTER_ENTER: {
guard: "isInteractive",
target: "open",
},
},
},
},
},
{
activities: {
trackPointerlockChange(ctx, _evt, { send }) {
return addPointerlockChangeListener(dom.getDoc(ctx), function onLockChange() {
return addPointerlockChangeListener(dom.getDoc(ctx), () => {
send("POINTER_LOCK_CHANGE")
})
},
Expand All @@ -120,15 +130,15 @@ export const tooltipMachine = createMachine<TooltipMachineContext, TooltipMachin
},
trackPointermoveForSafari(ctx, _evt, { send }) {
if (!isSafari()) return noop
const doc = ctx.doc ?? document
const doc = dom.getDoc(ctx)
return addPointerEvent(doc, "pointermove", (event) => {
const selector = "[data-controls=tooltip][data-expanded]"
if (isElement(event.target) && event.target.closest(selector)) return
send("POINTER_LEAVE")
})
},
trackEscapeKey(ctx, _evt, { send }) {
const doc = ctx.doc ?? document
const doc = dom.getDoc(ctx)
return addDomEvent(doc, "keydown", (event) => {
if (event.key === "Escape" || event.key === "Esc") {
send("ESCAPE")
Expand All @@ -151,12 +161,25 @@ export const tooltipMachine = createMachine<TooltipMachineContext, TooltipMachin
tooltipStore.setId(null)
}
},
invokeOnOpen(ctx, evt) {
const omit = ["TOOLTIP_POINTER_ENTER", "POINTER_ENTER"]
if (!omit.includes(evt.type)) {
ctx.onOpen?.()
}
},
invokeOnClose(ctx, evt) {
const omit = ["SETUP"]
if (!omit.includes(evt.type)) {
ctx.onClose?.()
}
},
},
guards: {
closeOnPointerDown: (ctx) => ctx.closeOnPointerDown,
noVisibleTooltip: () => tooltipStore.id === null,
isVisible: (ctx) => ctx.id === tooltipStore.id,
isDisabled: (ctx) => !!ctx.disabled,
isInteractive: (ctx) => ctx.interactive,
},
delays: {
OPEN_DELAY: (ctx) => ctx.openDelay,
Expand Down
32 changes: 32 additions & 0 deletions packages/machines/src/tooltip/tooltip.types.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,42 @@
export type TooltipMachineContext = {
/**
* The owner document of the tooltip.
*/
doc?: Document
/**
* The `id` of the tooltip.
*/
id: string
/**
* Whether the tooltip is disabled.
*/
disabled?: boolean
/**
* The open delay of the tooltip.
*/
openDelay: number
/**
* The close delay of the tooltip.
*/
closeDelay: number
/**
* Whether to close the tooltip on pointerdown.
*/
closeOnPointerDown: boolean
/**
* Whether the tooltip's content is interactive.
* In this mode, the tooltip will remain open when user hovers over the content.
* @see https://www.w3.org/TR/WCAG21/#content-on-hover-or-focus
*/
interactive: boolean
/**
* Function called when the tooltip is opened.
*/
onOpen?: VoidFunction
/**
* Function called when the tooltip is closed.
*/
onClose?: VoidFunction
}

export type TooltipMachineState = {
Expand Down
1 change: 0 additions & 1 deletion shared/reset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@ injectGlobal`
[data-tooltip] {
z-index: 1;
pointer-events: none;
position: absolute;
padding: 0.25em 0.5em;
box-shadow: 2px 2px 10px hsla(0, 0%, 0%, 0.1);
Expand Down

0 comments on commit 7ac6e5a

Please sign in to comment.