From df29b38c352236791057c726d2669549fceb42f6 Mon Sep 17 00:00:00 2001 From: p-sw Date: Sun, 30 Jun 2024 15:03:06 +0900 Subject: [PATCH] feat: upgrade Popover to latest version --- src/docs/components/Popover.mdx | 13 +-- src/pswui/components/Popover.tsx | 138 +++++++++++++++++++++++++------ 2 files changed, 123 insertions(+), 28 deletions(-) diff --git a/src/docs/components/Popover.mdx b/src/docs/components/Popover.mdx index b853a03..5ff55ef 100644 --- a/src/docs/components/Popover.mdx +++ b/src/docs/components/Popover.mdx @@ -43,7 +43,7 @@ import { Popover, PopoverTrigger, PopoverContent } from "@components/popover" {/* content of popover */} - ``` > Note: @@ -69,10 +69,13 @@ import { Popover, PopoverTrigger, PopoverContent } from "@components/popover" #### Variants -| Prop | Type | Default | Description | -|:---------|:-------------------------------------------------------------------------|:-----------------|:--------------------------------| -| `anchor` | `` `${"top" \| "middle" \| "bottom"}${"Left" \| "Center" \| "Right"}` `` | `"bottomCenter"` | Position of Popover content | -| `offset` | `"sm" \| "md" \| "lg"` | `"md"` | Gap between trigger and popover | +| Prop | Type | Default | Description | +|:------------|:-------------------------------|:-----------|:------------------------------------| +| `direction` | `"row" \| "col"` | `"col"` | Main axis of aligning popover | +| `position` | `"start" \| "end"` | `"end"` | Position of popover | +| `anchor` | `"start" \| "middle" \| "end"` | `"middle"` | Reference point of aligning popover | +| `align` | `"start" \| "middle" \| "end"` | `"middle"` | Position of reference point | +| `offset` | `"sm" \| "md" \| "lg"` | `"md"` | Gap between trigger and popover | #### Special diff --git a/src/pswui/components/Popover.tsx b/src/pswui/components/Popover.tsx index de29b7b..80de2b6 100644 --- a/src/pswui/components/Popover.tsx +++ b/src/pswui/components/Popover.tsx @@ -1,5 +1,5 @@ +import { type AsChild, Slot, type VariantProps, vcn } from "@pswui-lib"; import React, { useContext, useEffect, useRef } from "react"; -import { AsChild, Slot, VariantProps, vcn } from "@pswui-lib"; interface IPopoverContext { opened: boolean; @@ -56,24 +56,23 @@ const popoverColors = { const [popoverContentVariant, resolvePopoverContentVariantProps] = vcn({ base: `absolute transition-all duration-150 border rounded-lg p-0.5 [&>*]:w-full ${popoverColors.background} ${popoverColors.border}`, variants: { + direction: { + row: "", + col: "", + }, anchor: { - topLeft: - "bottom-[calc(100%+var(--popover-offset))] right-[calc(100%+var(--popover-offset))] origin-bottom-right", - topCenter: - "bottom-[calc(100%+var(--popover-offset))] left-1/2 -translate-x-1/2 origin-bottom-center", - topRight: - "bottom-[calc(100%+var(--popover-offset))] left-[calc(100%+var(--popover-offset))] origin-bottom-left", - middleLeft: "top-1/2 translate-y-1/2 right-full origin-right", - middleCenter: - "top-1/2 translate-y-1/2 left-1/2 -translate-x-1/2 origin-center", - middleRight: - "top-1/2 translate-y-1/2 left-[calc(100%+var(--popover-offset))] origin-left", - bottomLeft: - "top-[calc(100%+var(--popover-offset))] right-[calc(100%+var(--popover-offset))] origin-top-right", - bottomCenter: - "top-[calc(100%+var(--popover-offset))] left-1/2 -translate-x-1/2 origin-top-center", - bottomRight: - "top-[calc(100%+var(--popover-offset))] left-[calc(100%+var(--popover-offset))] origin-top-left", + start: "", + middle: "", + end: "", + }, + align: { + start: "", + middle: "", + end: "", + }, + position: { + start: "", + end: "", }, offset: { sm: "[--popover-offset:2px]", @@ -81,15 +80,104 @@ const [popoverContentVariant, resolvePopoverContentVariantProps] = vcn({ lg: "[--popover-offset:8px]", }, opened: { - true: "opacity-1 scale-100", - false: "opacity-0 scale-75", + true: "opacity-1 scale-100 pointer-events-auto select-auto touch-auto", + false: "opacity-0 scale-75 pointer-events-none select-none touch-none", }, }, defaults: { - anchor: "bottomCenter", + direction: "col", + anchor: "middle", + align: "middle", + position: "end", opened: false, offset: "md", }, + dynamics: [ + function originClass({ direction, anchor, position }) { + switch (`${direction} ${position} ${anchor}` as const) { + // left + case "row start start": + return "origin-top-right"; + case "row start middle": + return "origin-right"; + case "row start end": + return "origin-bottom-right"; + // right + case "row end start": + return "origin-top-left"; + case "row end middle": + return "origin-left"; + case "row end end": + return "origin-bottom-left"; + // top + case "col start start": + return "origin-bottom-left"; + case "col start middle": + return "origin-bottom"; + case "col start end": + return "origin-bottom-right"; + // bottom + case "col end start": + return "origin-top-left"; + case "col end middle": + return "origin-top"; + case "col end end": + return "origin-top-right"; + } + }, + function basePositionClass({ position, direction }) { + switch (`${direction} ${position}` as const) { + case "col start": + return "bottom-[calc(100%+var(--popover-offset))]"; + case "col end": + return "top-[calc(100%+var(--popover-offset))]"; + case "row start": + return "right-[calc(100%+var(--popover-offset))]"; + case "row end": + return "left-[calc(100%+var(--popover-offset))]"; + } + }, + function directionPositionClass({ direction, anchor, align }) { + switch (`${direction} ${anchor} ${align}` as const) { + case "col start start": + return "left-0"; + case "col start middle": + return "left-1/2"; + case "col start end": + return "left-full"; + case "col middle start": + return "left-0 -translate-x-1/2"; + case "col middle middle": + return "left-1/2 -translate-x-1/2"; + case "col middle end": + return "right-0 translate-x-1/2"; + case "col end start": + return "right-full"; + case "col end middle": + return "right-1/2"; + case "col end end": + return "right-0"; + case "row start start": + return "top-0"; + case "row start middle": + return "top-1/2"; + case "row start end": + return "top-full"; + case "row middle start": + return "top-0 -translate-y-1/2"; + case "row middle middle": + return "top-1/2 -translate-y-1/2"; + case "row middle end": + return "bottom-0 translate-y-1/2"; + case "row end start": + return "bottom-full"; + case "row end middle": + return "bottom-1/2"; + case "row end end": + return "bottom-0"; + } + }, + ], }); interface PopoverContentProps @@ -119,7 +207,7 @@ const PopoverContent = React.forwardRef( return () => { document.removeEventListener("mousedown", handleOutsideClick); }; - }, [internalRef, setState]); + }, [setState]); return (
( })} ref={(el) => { internalRef.current = el; - typeof ref === "function" ? ref(el) : ref && (ref.current = el); + if (typeof ref === "function") { + ref(el); + } else if (ref) { + ref.current = el; + } }} > {children}