@nucleux/popover 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -84,7 +84,8 @@ var PopoverTrigger = React__namespace.forwardRef(
84
84
  );
85
85
  PopoverTrigger.displayName = "PopoverTrigger";
86
86
  var PopoverContent = React__namespace.forwardRef(
87
- ({ align = "start", className, ...props }, ref) => {
87
+ ({ align, alignItems, className, ...props }, ref) => {
88
+ if (align == null && alignItems != null) align = alignItems;
88
89
  const { open, contentId } = usePopover("PopoverContent");
89
90
  if (!open) return null;
90
91
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -94,7 +95,7 @@ var PopoverContent = React__namespace.forwardRef(
94
95
  id: contentId,
95
96
  className: utils.cn(
96
97
  "absolute top-full z-50 mt-2 min-w-[12rem] rounded-lg border border-border bg-background p-4 text-foreground shadow-md outline-none animate-nx-fade-in",
97
- align === "end" ? "right-0" : "left-0",
98
+ (align ?? "start") === "end" ? "right-0" : "left-0",
98
99
  className
99
100
  ),
100
101
  ...props
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.tsx"],"names":["React","jsx","cn"],"mappings":"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","file":"index.cjs","sourcesContent":["import * as React from \"react\";\nimport { cn } from \"@nucleux/utils\";\n\ninterface PopoverContextValue {\n open: boolean;\n setOpen: (open: boolean) => void;\n contentId: string;\n}\nconst PopoverContext = React.createContext<PopoverContextValue | null>(null);\n\nfunction usePopover(component: string) {\n const ctx = React.useContext(PopoverContext);\n if (!ctx) throw new Error(`<${component}> must be used inside <Popover>`);\n return ctx;\n}\n\nexport interface PopoverProps {\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n children: React.ReactNode;\n}\n\n/**\n * A click-triggered popover. Compose PopoverTrigger + PopoverContent. Closes on\n * outside click or Escape. Content is positioned relative to the trigger.\n */\nexport function Popover({ open, defaultOpen = false, onOpenChange, children }: PopoverProps) {\n const [internal, setInternal] = React.useState(defaultOpen);\n const isControlled = open != null;\n const value = isControlled ? open : internal;\n const contentId = React.useId();\n const containerRef = React.useRef<HTMLDivElement>(null);\n\n const setOpen = React.useCallback(\n (next: boolean) => {\n if (!isControlled) setInternal(next);\n onOpenChange?.(next);\n },\n [isControlled, onOpenChange],\n );\n\n React.useEffect(() => {\n if (!value) return;\n const onDown = (e: MouseEvent) => {\n if (!containerRef.current?.contains(e.target as Node)) setOpen(false);\n };\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") setOpen(false);\n };\n document.addEventListener(\"mousedown\", onDown);\n document.addEventListener(\"keydown\", onKey);\n return () => {\n document.removeEventListener(\"mousedown\", onDown);\n document.removeEventListener(\"keydown\", onKey);\n };\n }, [value, setOpen]);\n\n return (\n <PopoverContext.Provider value={{ open: value, setOpen, contentId }}>\n <div ref={containerRef} className=\"relative inline-block\">\n {children}\n </div>\n </PopoverContext.Provider>\n );\n}\n\nexport const PopoverTrigger = React.forwardRef<HTMLButtonElement, React.ButtonHTMLAttributes<HTMLButtonElement>>(\n ({ onClick, type = \"button\", ...props }, ref) => {\n const { open, setOpen, contentId } = usePopover(\"PopoverTrigger\");\n return (\n <button\n ref={ref}\n type={type}\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n aria-controls={open ? contentId : undefined}\n onClick={(e) => {\n onClick?.(e);\n setOpen(!open);\n }}\n {...props}\n />\n );\n },\n);\nPopoverTrigger.displayName = \"PopoverTrigger\";\n\nexport interface PopoverContentProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Horizontal alignment relative to the trigger. */\n align?: \"start\" | \"end\";\n}\n\nexport const PopoverContent = React.forwardRef<HTMLDivElement, PopoverContentProps>(\n ({ align = \"start\", className, ...props }, ref) => {\n const { open, contentId } = usePopover(\"PopoverContent\");\n if (!open) return null;\n return (\n <div\n ref={ref}\n id={contentId}\n className={cn(\n \"absolute top-full z-50 mt-2 min-w-[12rem] rounded-lg border border-border bg-background p-4 text-foreground shadow-md outline-none animate-nx-fade-in\",\n align === \"end\" ? \"right-0\" : \"left-0\",\n className,\n )}\n {...props}\n />\n );\n },\n);\nPopoverContent.displayName = \"PopoverContent\";\n"]}
1
+ {"version":3,"sources":["../src/index.tsx"],"names":["React","jsx","cn"],"mappings":"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","file":"index.cjs","sourcesContent":["import * as React from \"react\";\nimport { cn } from \"@nucleux/utils\";\n\ninterface PopoverContextValue {\n open: boolean;\n setOpen: (open: boolean) => void;\n contentId: string;\n}\nconst PopoverContext = React.createContext<PopoverContextValue | null>(null);\n\nfunction usePopover(component: string) {\n const ctx = React.useContext(PopoverContext);\n if (!ctx) throw new Error(`<${component}> must be used inside <Popover>`);\n return ctx;\n}\n\nexport interface PopoverProps {\n /** Whether the popover is open (controlled). */\n open?: boolean;\n /** Initial open state (uncontrolled). */\n defaultOpen?: boolean;\n /** Called when the popover requests to open or close. */\n onOpenChange?: (open: boolean) => void;\n children: React.ReactNode;\n}\n\n/**\n * A click-triggered popover. Compose PopoverTrigger + PopoverContent. Closes on\n * outside click or Escape. Content is positioned relative to the trigger.\n */\nexport function Popover({ open, defaultOpen = false, onOpenChange, children }: PopoverProps) {\n const [internal, setInternal] = React.useState(defaultOpen);\n const isControlled = open != null;\n const value = isControlled ? open : internal;\n const contentId = React.useId();\n const containerRef = React.useRef<HTMLDivElement>(null);\n\n const setOpen = React.useCallback(\n (next: boolean) => {\n if (!isControlled) setInternal(next);\n onOpenChange?.(next);\n },\n [isControlled, onOpenChange],\n );\n\n React.useEffect(() => {\n if (!value) return;\n const onDown = (e: MouseEvent) => {\n if (!containerRef.current?.contains(e.target as Node)) setOpen(false);\n };\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") setOpen(false);\n };\n document.addEventListener(\"mousedown\", onDown);\n document.addEventListener(\"keydown\", onKey);\n return () => {\n document.removeEventListener(\"mousedown\", onDown);\n document.removeEventListener(\"keydown\", onKey);\n };\n }, [value, setOpen]);\n\n return (\n <PopoverContext.Provider value={{ open: value, setOpen, contentId }}>\n <div ref={containerRef} className=\"relative inline-block\">\n {children}\n </div>\n </PopoverContext.Provider>\n );\n}\n\nexport interface PopoverTriggerProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Additional classes merged onto the trigger button. */\n className?: string;\n /** Button type. Defaults to \"button\". */\n type?: \"button\" | \"submit\" | \"reset\";\n}\n\n/** Button that toggles the popover; place inside Popover. */\nexport const PopoverTrigger = React.forwardRef<HTMLButtonElement, PopoverTriggerProps>(\n ({ onClick, type = \"button\", ...props }, ref) => {\n const { open, setOpen, contentId } = usePopover(\"PopoverTrigger\");\n return (\n <button\n ref={ref}\n type={type}\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n aria-controls={open ? contentId : undefined}\n onClick={(e) => {\n onClick?.(e);\n setOpen(!open);\n }}\n {...props}\n />\n );\n },\n);\nPopoverTrigger.displayName = \"PopoverTrigger\";\n\nexport interface PopoverContentProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Horizontal alignment relative to the trigger. */\n align?: \"start\" | \"end\";\n /**\n * Alias of `align` (CSS flex vocabulary). Deprecated — use `align`.\n * @deprecated Use `align` instead. Alias kept so agents reaching for the\n * CSS property name are caught; it maps 1:1.\n */\n alignItems?: \"start\" | \"end\";\n}\n\nexport const PopoverContent = React.forwardRef<HTMLDivElement, PopoverContentProps>(\n ({ align, alignItems, className, ...props }, ref) => {\n // `alignItems` is a deprecated alias of `align` (CSS flex vocabulary).\n if (align == null && alignItems != null) align = alignItems;\n const { open, contentId } = usePopover(\"PopoverContent\");\n if (!open) return null;\n return (\n <div\n ref={ref}\n id={contentId}\n className={cn(\n \"absolute top-full z-50 mt-2 min-w-[12rem] rounded-lg border border-border bg-background p-4 text-foreground shadow-md outline-none animate-nx-fade-in\",\n (align ?? \"start\") === \"end\" ? \"right-0\" : \"left-0\",\n className,\n )}\n {...props}\n />\n );\n },\n);\nPopoverContent.displayName = \"PopoverContent\";\n"]}
package/dist/index.d.cts CHANGED
@@ -1,8 +1,11 @@
1
1
  import * as React from 'react';
2
2
 
3
3
  interface PopoverProps {
4
+ /** Whether the popover is open (controlled). */
4
5
  open?: boolean;
6
+ /** Initial open state (uncontrolled). */
5
7
  defaultOpen?: boolean;
8
+ /** Called when the popover requests to open or close. */
6
9
  onOpenChange?: (open: boolean) => void;
7
10
  children: React.ReactNode;
8
11
  }
@@ -11,11 +14,24 @@ interface PopoverProps {
11
14
  * outside click or Escape. Content is positioned relative to the trigger.
12
15
  */
13
16
  declare function Popover({ open, defaultOpen, onOpenChange, children }: PopoverProps): React.JSX.Element;
14
- declare const PopoverTrigger: React.ForwardRefExoticComponent<React.ButtonHTMLAttributes<HTMLButtonElement> & React.RefAttributes<HTMLButtonElement>>;
17
+ interface PopoverTriggerProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
18
+ /** Additional classes merged onto the trigger button. */
19
+ className?: string;
20
+ /** Button type. Defaults to "button". */
21
+ type?: "button" | "submit" | "reset";
22
+ }
23
+ /** Button that toggles the popover; place inside Popover. */
24
+ declare const PopoverTrigger: React.ForwardRefExoticComponent<PopoverTriggerProps & React.RefAttributes<HTMLButtonElement>>;
15
25
  interface PopoverContentProps extends React.HTMLAttributes<HTMLDivElement> {
16
26
  /** Horizontal alignment relative to the trigger. */
17
27
  align?: "start" | "end";
28
+ /**
29
+ * Alias of `align` (CSS flex vocabulary). Deprecated — use `align`.
30
+ * @deprecated Use `align` instead. Alias kept so agents reaching for the
31
+ * CSS property name are caught; it maps 1:1.
32
+ */
33
+ alignItems?: "start" | "end";
18
34
  }
19
35
  declare const PopoverContent: React.ForwardRefExoticComponent<PopoverContentProps & React.RefAttributes<HTMLDivElement>>;
20
36
 
21
- export { Popover, PopoverContent, type PopoverContentProps, type PopoverProps, PopoverTrigger };
37
+ export { Popover, PopoverContent, type PopoverContentProps, type PopoverProps, PopoverTrigger, type PopoverTriggerProps };
package/dist/index.d.ts CHANGED
@@ -1,8 +1,11 @@
1
1
  import * as React from 'react';
2
2
 
3
3
  interface PopoverProps {
4
+ /** Whether the popover is open (controlled). */
4
5
  open?: boolean;
6
+ /** Initial open state (uncontrolled). */
5
7
  defaultOpen?: boolean;
8
+ /** Called when the popover requests to open or close. */
6
9
  onOpenChange?: (open: boolean) => void;
7
10
  children: React.ReactNode;
8
11
  }
@@ -11,11 +14,24 @@ interface PopoverProps {
11
14
  * outside click or Escape. Content is positioned relative to the trigger.
12
15
  */
13
16
  declare function Popover({ open, defaultOpen, onOpenChange, children }: PopoverProps): React.JSX.Element;
14
- declare const PopoverTrigger: React.ForwardRefExoticComponent<React.ButtonHTMLAttributes<HTMLButtonElement> & React.RefAttributes<HTMLButtonElement>>;
17
+ interface PopoverTriggerProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
18
+ /** Additional classes merged onto the trigger button. */
19
+ className?: string;
20
+ /** Button type. Defaults to "button". */
21
+ type?: "button" | "submit" | "reset";
22
+ }
23
+ /** Button that toggles the popover; place inside Popover. */
24
+ declare const PopoverTrigger: React.ForwardRefExoticComponent<PopoverTriggerProps & React.RefAttributes<HTMLButtonElement>>;
15
25
  interface PopoverContentProps extends React.HTMLAttributes<HTMLDivElement> {
16
26
  /** Horizontal alignment relative to the trigger. */
17
27
  align?: "start" | "end";
28
+ /**
29
+ * Alias of `align` (CSS flex vocabulary). Deprecated — use `align`.
30
+ * @deprecated Use `align` instead. Alias kept so agents reaching for the
31
+ * CSS property name are caught; it maps 1:1.
32
+ */
33
+ alignItems?: "start" | "end";
18
34
  }
19
35
  declare const PopoverContent: React.ForwardRefExoticComponent<PopoverContentProps & React.RefAttributes<HTMLDivElement>>;
20
36
 
21
- export { Popover, PopoverContent, type PopoverContentProps, type PopoverProps, PopoverTrigger };
37
+ export { Popover, PopoverContent, type PopoverContentProps, type PopoverProps, PopoverTrigger, type PopoverTriggerProps };
package/dist/index.js CHANGED
@@ -62,7 +62,8 @@ var PopoverTrigger = React.forwardRef(
62
62
  );
63
63
  PopoverTrigger.displayName = "PopoverTrigger";
64
64
  var PopoverContent = React.forwardRef(
65
- ({ align = "start", className, ...props }, ref) => {
65
+ ({ align, alignItems, className, ...props }, ref) => {
66
+ if (align == null && alignItems != null) align = alignItems;
66
67
  const { open, contentId } = usePopover("PopoverContent");
67
68
  if (!open) return null;
68
69
  return /* @__PURE__ */ jsx(
@@ -72,7 +73,7 @@ var PopoverContent = React.forwardRef(
72
73
  id: contentId,
73
74
  className: cn(
74
75
  "absolute top-full z-50 mt-2 min-w-[12rem] rounded-lg border border-border bg-background p-4 text-foreground shadow-md outline-none animate-nx-fade-in",
75
- align === "end" ? "right-0" : "left-0",
76
+ (align ?? "start") === "end" ? "right-0" : "left-0",
76
77
  className
77
78
  ),
78
79
  ...props
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import * as React from \"react\";\nimport { cn } from \"@nucleux/utils\";\n\ninterface PopoverContextValue {\n open: boolean;\n setOpen: (open: boolean) => void;\n contentId: string;\n}\nconst PopoverContext = React.createContext<PopoverContextValue | null>(null);\n\nfunction usePopover(component: string) {\n const ctx = React.useContext(PopoverContext);\n if (!ctx) throw new Error(`<${component}> must be used inside <Popover>`);\n return ctx;\n}\n\nexport interface PopoverProps {\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n children: React.ReactNode;\n}\n\n/**\n * A click-triggered popover. Compose PopoverTrigger + PopoverContent. Closes on\n * outside click or Escape. Content is positioned relative to the trigger.\n */\nexport function Popover({ open, defaultOpen = false, onOpenChange, children }: PopoverProps) {\n const [internal, setInternal] = React.useState(defaultOpen);\n const isControlled = open != null;\n const value = isControlled ? open : internal;\n const contentId = React.useId();\n const containerRef = React.useRef<HTMLDivElement>(null);\n\n const setOpen = React.useCallback(\n (next: boolean) => {\n if (!isControlled) setInternal(next);\n onOpenChange?.(next);\n },\n [isControlled, onOpenChange],\n );\n\n React.useEffect(() => {\n if (!value) return;\n const onDown = (e: MouseEvent) => {\n if (!containerRef.current?.contains(e.target as Node)) setOpen(false);\n };\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") setOpen(false);\n };\n document.addEventListener(\"mousedown\", onDown);\n document.addEventListener(\"keydown\", onKey);\n return () => {\n document.removeEventListener(\"mousedown\", onDown);\n document.removeEventListener(\"keydown\", onKey);\n };\n }, [value, setOpen]);\n\n return (\n <PopoverContext.Provider value={{ open: value, setOpen, contentId }}>\n <div ref={containerRef} className=\"relative inline-block\">\n {children}\n </div>\n </PopoverContext.Provider>\n );\n}\n\nexport const PopoverTrigger = React.forwardRef<HTMLButtonElement, React.ButtonHTMLAttributes<HTMLButtonElement>>(\n ({ onClick, type = \"button\", ...props }, ref) => {\n const { open, setOpen, contentId } = usePopover(\"PopoverTrigger\");\n return (\n <button\n ref={ref}\n type={type}\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n aria-controls={open ? contentId : undefined}\n onClick={(e) => {\n onClick?.(e);\n setOpen(!open);\n }}\n {...props}\n />\n );\n },\n);\nPopoverTrigger.displayName = \"PopoverTrigger\";\n\nexport interface PopoverContentProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Horizontal alignment relative to the trigger. */\n align?: \"start\" | \"end\";\n}\n\nexport const PopoverContent = React.forwardRef<HTMLDivElement, PopoverContentProps>(\n ({ align = \"start\", className, ...props }, ref) => {\n const { open, contentId } = usePopover(\"PopoverContent\");\n if (!open) return null;\n return (\n <div\n ref={ref}\n id={contentId}\n className={cn(\n \"absolute top-full z-50 mt-2 min-w-[12rem] rounded-lg border border-border bg-background p-4 text-foreground shadow-md outline-none animate-nx-fade-in\",\n align === \"end\" ? \"right-0\" : \"left-0\",\n className,\n )}\n {...props}\n />\n );\n },\n);\nPopoverContent.displayName = \"PopoverContent\";\n"]}
1
+ {"version":3,"sources":["../src/index.tsx"],"names":[],"mappings":";;;;;AAQA,IAAM,cAAA,GAAuB,oBAA0C,IAAI,CAAA;AAE3E,SAAS,WAAW,SAAA,EAAmB;AACrC,EAAA,MAAM,GAAA,GAAY,iBAAW,cAAc,CAAA;AAC3C,EAAA,IAAI,CAAC,GAAA,EAAK,MAAM,IAAI,KAAA,CAAM,CAAA,CAAA,EAAI,SAAS,CAAA,+BAAA,CAAiC,CAAA;AACxE,EAAA,OAAO,GAAA;AACT;AAgBO,SAAS,QAAQ,EAAE,IAAA,EAAM,cAAc,KAAA,EAAO,YAAA,EAAc,UAAS,EAAiB;AAC3F,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAU,eAAS,WAAW,CAAA;AAC1D,EAAA,MAAM,eAAe,IAAA,IAAQ,IAAA;AAC7B,EAAA,MAAM,KAAA,GAAQ,eAAe,IAAA,GAAO,QAAA;AACpC,EAAA,MAAM,YAAkB,KAAA,CAAA,KAAA,EAAM;AAC9B,EAAA,MAAM,YAAA,GAAqB,aAAuB,IAAI,CAAA;AAEtD,EAAA,MAAM,OAAA,GAAgB,KAAA,CAAA,WAAA;AAAA,IACpB,CAAC,IAAA,KAAkB;AACjB,MAAA,IAAI,CAAC,YAAA,EAAc,WAAA,CAAY,IAAI,CAAA;AACnC,MAAA,YAAA,GAAe,IAAI,CAAA;AAAA,IACrB,CAAA;AAAA,IACA,CAAC,cAAc,YAAY;AAAA,GAC7B;AAEA,EAAM,gBAAU,MAAM;AACpB,IAAA,IAAI,CAAC,KAAA,EAAO;AACZ,IAAA,MAAM,MAAA,GAAS,CAAC,CAAA,KAAkB;AAChC,MAAA,IAAI,CAAC,aAAa,OAAA,EAAS,QAAA,CAAS,EAAE,MAAc,CAAA,UAAW,KAAK,CAAA;AAAA,IACtE,CAAA;AACA,IAAA,MAAM,KAAA,GAAQ,CAAC,CAAA,KAAqB;AAClC,MAAA,IAAI,CAAA,CAAE,GAAA,KAAQ,QAAA,EAAU,OAAA,CAAQ,KAAK,CAAA;AAAA,IACvC,CAAA;AACA,IAAA,QAAA,CAAS,gBAAA,CAAiB,aAAa,MAAM,CAAA;AAC7C,IAAA,QAAA,CAAS,gBAAA,CAAiB,WAAW,KAAK,CAAA;AAC1C,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CAAS,mBAAA,CAAoB,aAAa,MAAM,CAAA;AAChD,MAAA,QAAA,CAAS,mBAAA,CAAoB,WAAW,KAAK,CAAA;AAAA,IAC/C,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,KAAA,EAAO,OAAO,CAAC,CAAA;AAEnB,EAAA,2BACG,cAAA,CAAe,QAAA,EAAf,EAAwB,KAAA,EAAO,EAAE,MAAM,KAAA,EAAO,OAAA,EAAS,SAAA,EAAU,EAChE,8BAAC,KAAA,EAAA,EAAI,GAAA,EAAK,cAAc,SAAA,EAAU,uBAAA,EAC/B,UACH,CAAA,EACF,CAAA;AAEJ;AAUO,IAAM,cAAA,GAAuB,KAAA,CAAA,UAAA;AAAA,EAClC,CAAC,EAAE,OAAA,EAAS,IAAA,GAAO,UAAU,GAAG,KAAA,IAAS,GAAA,KAAQ;AAC/C,IAAA,MAAM,EAAE,IAAA,EAAM,OAAA,EAAS,SAAA,EAAU,GAAI,WAAW,gBAAgB,CAAA;AAChE,IAAA,uBACE,GAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,IAAA;AAAA,QACA,eAAA,EAAc,QAAA;AAAA,QACd,eAAA,EAAe,IAAA;AAAA,QACf,eAAA,EAAe,OAAO,SAAA,GAAY,MAAA;AAAA,QAClC,OAAA,EAAS,CAAC,CAAA,KAAM;AACd,UAAA,OAAA,GAAU,CAAC,CAAA;AACX,UAAA,OAAA,CAAQ,CAAC,IAAI,CAAA;AAAA,QACf,CAAA;AAAA,QACC,GAAG;AAAA;AAAA,KACN;AAAA,EAEJ;AACF;AACA,cAAA,CAAe,WAAA,GAAc,gBAAA;AAatB,IAAM,cAAA,GAAuB,KAAA,CAAA,UAAA;AAAA,EAClC,CAAC,EAAE,KAAA,EAAO,UAAA,EAAY,WAAW,GAAG,KAAA,IAAS,GAAA,KAAQ;AAEnD,IAAA,IAAI,KAAA,IAAS,IAAA,IAAQ,UAAA,IAAc,IAAA,EAAM,KAAA,GAAQ,UAAA;AACjD,IAAA,MAAM,EAAE,IAAA,EAAM,SAAA,EAAU,GAAI,WAAW,gBAAgB,CAAA;AACvD,IAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,IAAA,uBACE,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,EAAA,EAAI,SAAA;AAAA,QACJ,SAAA,EAAW,EAAA;AAAA,UACT,uJAAA;AAAA,UAAA,CACC,KAAA,IAAS,OAAA,MAAa,KAAA,GAAQ,SAAA,GAAY,QAAA;AAAA,UAC3C;AAAA,SACF;AAAA,QACC,GAAG;AAAA;AAAA,KACN;AAAA,EAEJ;AACF;AACA,cAAA,CAAe,WAAA,GAAc,gBAAA","file":"index.js","sourcesContent":["import * as React from \"react\";\nimport { cn } from \"@nucleux/utils\";\n\ninterface PopoverContextValue {\n open: boolean;\n setOpen: (open: boolean) => void;\n contentId: string;\n}\nconst PopoverContext = React.createContext<PopoverContextValue | null>(null);\n\nfunction usePopover(component: string) {\n const ctx = React.useContext(PopoverContext);\n if (!ctx) throw new Error(`<${component}> must be used inside <Popover>`);\n return ctx;\n}\n\nexport interface PopoverProps {\n /** Whether the popover is open (controlled). */\n open?: boolean;\n /** Initial open state (uncontrolled). */\n defaultOpen?: boolean;\n /** Called when the popover requests to open or close. */\n onOpenChange?: (open: boolean) => void;\n children: React.ReactNode;\n}\n\n/**\n * A click-triggered popover. Compose PopoverTrigger + PopoverContent. Closes on\n * outside click or Escape. Content is positioned relative to the trigger.\n */\nexport function Popover({ open, defaultOpen = false, onOpenChange, children }: PopoverProps) {\n const [internal, setInternal] = React.useState(defaultOpen);\n const isControlled = open != null;\n const value = isControlled ? open : internal;\n const contentId = React.useId();\n const containerRef = React.useRef<HTMLDivElement>(null);\n\n const setOpen = React.useCallback(\n (next: boolean) => {\n if (!isControlled) setInternal(next);\n onOpenChange?.(next);\n },\n [isControlled, onOpenChange],\n );\n\n React.useEffect(() => {\n if (!value) return;\n const onDown = (e: MouseEvent) => {\n if (!containerRef.current?.contains(e.target as Node)) setOpen(false);\n };\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") setOpen(false);\n };\n document.addEventListener(\"mousedown\", onDown);\n document.addEventListener(\"keydown\", onKey);\n return () => {\n document.removeEventListener(\"mousedown\", onDown);\n document.removeEventListener(\"keydown\", onKey);\n };\n }, [value, setOpen]);\n\n return (\n <PopoverContext.Provider value={{ open: value, setOpen, contentId }}>\n <div ref={containerRef} className=\"relative inline-block\">\n {children}\n </div>\n </PopoverContext.Provider>\n );\n}\n\nexport interface PopoverTriggerProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Additional classes merged onto the trigger button. */\n className?: string;\n /** Button type. Defaults to \"button\". */\n type?: \"button\" | \"submit\" | \"reset\";\n}\n\n/** Button that toggles the popover; place inside Popover. */\nexport const PopoverTrigger = React.forwardRef<HTMLButtonElement, PopoverTriggerProps>(\n ({ onClick, type = \"button\", ...props }, ref) => {\n const { open, setOpen, contentId } = usePopover(\"PopoverTrigger\");\n return (\n <button\n ref={ref}\n type={type}\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n aria-controls={open ? contentId : undefined}\n onClick={(e) => {\n onClick?.(e);\n setOpen(!open);\n }}\n {...props}\n />\n );\n },\n);\nPopoverTrigger.displayName = \"PopoverTrigger\";\n\nexport interface PopoverContentProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Horizontal alignment relative to the trigger. */\n align?: \"start\" | \"end\";\n /**\n * Alias of `align` (CSS flex vocabulary). Deprecated — use `align`.\n * @deprecated Use `align` instead. Alias kept so agents reaching for the\n * CSS property name are caught; it maps 1:1.\n */\n alignItems?: \"start\" | \"end\";\n}\n\nexport const PopoverContent = React.forwardRef<HTMLDivElement, PopoverContentProps>(\n ({ align, alignItems, className, ...props }, ref) => {\n // `alignItems` is a deprecated alias of `align` (CSS flex vocabulary).\n if (align == null && alignItems != null) align = alignItems;\n const { open, contentId } = usePopover(\"PopoverContent\");\n if (!open) return null;\n return (\n <div\n ref={ref}\n id={contentId}\n className={cn(\n \"absolute top-full z-50 mt-2 min-w-[12rem] rounded-lg border border-border bg-background p-4 text-foreground shadow-md outline-none animate-nx-fade-in\",\n (align ?? \"start\") === \"end\" ? \"right-0\" : \"left-0\",\n className,\n )}\n {...props}\n />\n );\n },\n);\nPopoverContent.displayName = \"PopoverContent\";\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nucleux/popover",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.cjs",
@@ -22,7 +22,7 @@
22
22
  "react-dom": ">=18"
23
23
  },
24
24
  "dependencies": {
25
- "@nucleux/utils": "0.3.0"
25
+ "@nucleux/utils": "0.5.0"
26
26
  },
27
27
  "devDependencies": {
28
28
  "tsup": "^8.3.5",