From 7ac6e5a0bab1791ddf26960c3827c0515202bbf0 Mon Sep 17 00:00:00 2001 From: Segun Adebayo Date: Wed, 17 Nov 2021 22:34:35 +0400 Subject: [PATCH] feat(tooltip): make tooltip interactive --- .../machines/src/tooltip/tooltip.connect.ts | 18 ++++++++++ packages/machines/src/tooltip/tooltip.dom.ts | 8 +++++ .../machines/src/tooltip/tooltip.machine.ts | 33 ++++++++++++++++--- .../machines/src/tooltip/tooltip.types.ts | 32 ++++++++++++++++++ shared/reset.ts | 1 - 5 files changed, 86 insertions(+), 6 deletions(-) diff --git a/packages/machines/src/tooltip/tooltip.connect.ts b/packages/machines/src/tooltip/tooltip.connect.ts index cef3c2227f..15bada3a6c 100644 --- a/packages/machines/src/tooltip/tooltip.connect.ts +++ b/packages/machines/src/tooltip/tooltip.connect.ts @@ -70,6 +70,24 @@ export function tooltipConnect( tooltipProps: normalize.element({ 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 + }, } } diff --git a/packages/machines/src/tooltip/tooltip.dom.ts b/packages/machines/src/tooltip/tooltip.dom.ts index e492a2c50d..79df01dce9 100644 --- a/packages/machines/src/tooltip/tooltip.dom.ts +++ b/packages/machines/src/tooltip/tooltip.dom.ts @@ -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 + }, } diff --git a/packages/machines/src/tooltip/tooltip.machine.ts b/packages/machines/src/tooltip/tooltip.machine.ts index 2c74c8f3e7..3a76d8e973 100644 --- a/packages/machines/src/tooltip/tooltip.machine.ts +++ b/packages/machines/src/tooltip/tooltip.machine.ts @@ -18,6 +18,7 @@ export const tooltipMachine = createMachine { send("POINTER_LOCK_CHANGE") }) }, @@ -120,7 +130,7 @@ export const tooltipMachine = createMachine { const selector = "[data-controls=tooltip][data-expanded]" if (isElement(event.target) && event.target.closest(selector)) return @@ -128,7 +138,7 @@ export const tooltipMachine = createMachine { if (event.key === "Escape" || event.key === "Esc") { send("ESCAPE") @@ -151,12 +161,25 @@ export const tooltipMachine = createMachine 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, diff --git a/packages/machines/src/tooltip/tooltip.types.ts b/packages/machines/src/tooltip/tooltip.types.ts index fbd4259268..f0ffc0e190 100644 --- a/packages/machines/src/tooltip/tooltip.types.ts +++ b/packages/machines/src/tooltip/tooltip.types.ts @@ -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 = { diff --git a/shared/reset.ts b/shared/reset.ts index a9a06084f1..fc91693847 100644 --- a/shared/reset.ts +++ b/shared/reset.ts @@ -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);