@puzzle-ui/ui 0.1.0 → 0.2.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.
Files changed (25) hide show
  1. package/README.md +81 -0
  2. package/dist/components/layout/resizable-panels/index.cjs +226 -0
  3. package/dist/components/layout/resizable-panels/index.cjs.map +1 -0
  4. package/dist/components/layout/resizable-panels/index.d.cts +59 -0
  5. package/dist/components/layout/resizable-panels/index.d.ts +59 -0
  6. package/dist/components/layout/resizable-panels/index.js +224 -0
  7. package/dist/components/layout/resizable-panels/index.js.map +1 -0
  8. package/dist/components/layout/resizable-panels/resizable-panels.css +121 -0
  9. package/dist/components/layout/resizable-panels/resizable-panels.utils.cjs +107 -0
  10. package/dist/components/layout/resizable-panels/resizable-panels.utils.cjs.map +1 -0
  11. package/dist/components/layout/resizable-panels/resizable-panels.utils.js +105 -0
  12. package/dist/components/layout/resizable-panels/resizable-panels.utils.js.map +1 -0
  13. package/dist/components/overlays/dropdown-menu/dropdown-menu-content.cjs +13 -1
  14. package/dist/components/overlays/dropdown-menu/dropdown-menu-content.cjs.map +1 -1
  15. package/dist/components/overlays/dropdown-menu/dropdown-menu-content.js +13 -1
  16. package/dist/components/overlays/dropdown-menu/dropdown-menu-content.js.map +1 -1
  17. package/dist/components/overlays/popout/index.cjs +7 -1
  18. package/dist/components/overlays/popout/index.cjs.map +1 -1
  19. package/dist/components/overlays/popout/index.js +8 -3
  20. package/dist/components/overlays/popout/index.js.map +1 -1
  21. package/dist/index.cjs +51 -47
  22. package/dist/index.d.cts +2 -1
  23. package/dist/index.d.ts +2 -1
  24. package/dist/index.js +2 -1
  25. package/package.json +5 -5
@@ -1,4 +1,5 @@
1
1
  "use client";
2
+ const require_index = require("../popout/index.cjs");
2
3
  const require_dropdown_menu_context = require("./dropdown-menu.context.cjs");
3
4
  const require_dropdown_menu_utils = require("./dropdown-menu.utils.cjs");
4
5
  let _puzzle_ui_core = require("@puzzle-ui/core");
@@ -10,19 +11,30 @@ const DropdownMenuContent = ({ children, id, className, style, maxHeight = "min(
10
11
  const menuRef = (0, react.useRef)(null);
11
12
  const typeaheadRef = (0, react.useRef)("");
12
13
  const typeaheadTimerRef = (0, react.useRef)(null);
14
+ const initialFocusDoneRef = (0, react.useRef)(false);
15
+ const positioned = require_index.usePopoutPositioned();
13
16
  (0, react.useEffect)(() => {
17
+ if (!context.open) initialFocusDoneRef.current = false;
14
18
  typeaheadRef.current = "";
15
19
  if (typeaheadTimerRef.current !== null) {
16
20
  clearTimeout(typeaheadTimerRef.current);
17
21
  typeaheadTimerRef.current = null;
18
22
  }
23
+ }, [context.open]);
24
+ (0, react.useEffect)(() => {
19
25
  if (!context.open) return;
20
26
  const menu = menuRef.current;
21
27
  if (!menu) return;
28
+ if (!positioned || initialFocusDoneRef.current) return;
29
+ initialFocusDoneRef.current = true;
22
30
  const items = require_dropdown_menu_utils.getEnabledMenuItems(menu);
23
31
  const target = context.focusPositionRef.current === "last" ? items[items.length - 1] : items[0];
24
32
  require_dropdown_menu_utils.focusElement(target ?? menu);
25
- }, [context.open, context.focusPositionRef]);
33
+ }, [
34
+ context.open,
35
+ context.focusPositionRef,
36
+ positioned
37
+ ]);
26
38
  (0, react.useEffect)(() => () => {
27
39
  if (typeaheadTimerRef.current !== null) clearTimeout(typeaheadTimerRef.current);
28
40
  }, []);
@@ -1 +1 @@
1
- {"version":3,"file":"dropdown-menu-content.cjs","names":["useDropdownMenuContext","useRef","getEnabledMenuItems","findNextMenuItemIndex","findMenuItemIndexByText","cn"],"sources":["../../../../src/components/overlays/dropdown-menu/dropdown-menu-content.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, type KeyboardEvent } from \"react\";\n\nimport { cn } from \"@puzzle-ui/core\";\n\nimport { useDropdownMenuContext } from \"./dropdown-menu.context\";\nimport {\n findMenuItemIndexByText,\n findNextMenuItemIndex,\n focusElement,\n getEnabledMenuItems,\n} from \"./dropdown-menu.utils\";\n\nimport type { DropdownMenuContentProps } from \"./dropdown-menu.types\";\n\nconst DropdownMenuContent = ({\n children,\n id,\n className,\n style,\n maxHeight = \"min(24rem, calc(100dvh - 2rem))\",\n onKeyDown,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n ...contentProps\n}: DropdownMenuContentProps) => {\n const context = useDropdownMenuContext();\n const menuRef = useRef<HTMLDivElement | null>(null);\n const typeaheadRef = useRef(\"\");\n const typeaheadTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n typeaheadRef.current = \"\";\n\n if (typeaheadTimerRef.current !== null) {\n clearTimeout(typeaheadTimerRef.current);\n typeaheadTimerRef.current = null;\n }\n\n if (!context.open) {\n return;\n }\n\n const menu = menuRef.current;\n\n if (!menu) {\n return;\n }\n\n const items = getEnabledMenuItems(menu);\n const target =\n context.focusPositionRef.current === \"last\"\n ? items[items.length - 1]\n : items[0];\n\n focusElement(target ?? menu);\n }, [context.open, context.focusPositionRef]);\n\n useEffect(\n () => () => {\n if (typeaheadTimerRef.current !== null) {\n clearTimeout(typeaheadTimerRef.current);\n }\n },\n [],\n );\n\n const focusIndex = (items: HTMLElement[], index: number) => {\n if (index >= 0 && index < items.length) {\n focusElement(items[index]);\n }\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n if (event.defaultPrevented) {\n return;\n }\n\n const menu = menuRef.current;\n\n if (!menu) {\n return;\n }\n\n if (event.key === \"Tab\") {\n const ownerDocument = event.currentTarget.ownerDocument;\n const trigger = context.triggerRef.current;\n const tabbableSelector = [\n \"a[href]\",\n \"area[href]\",\n \"button:not([disabled])\",\n \"input:not([disabled]):not([type='hidden'])\",\n \"select:not([disabled])\",\n \"textarea:not([disabled])\",\n \"iframe\",\n \"object\",\n \"embed\",\n \"summary\",\n \"audio[controls]\",\n \"video[controls]\",\n \"[contenteditable='true']\",\n \"[tabindex]:not([tabindex='-1'])\",\n ].join(\",\");\n const tabbableElements = Array.from(\n ownerDocument.querySelectorAll<HTMLElement>(tabbableSelector),\n ).filter((element) => {\n if (\n element === menu ||\n menu.contains(element) ||\n element.hidden ||\n element.tabIndex < 0 ||\n element.getAttribute(\"aria-disabled\") === \"true\" ||\n element.closest(\"[hidden], [inert], [aria-hidden='true']\")\n ) {\n return false;\n }\n\n const computedStyle = ownerDocument.defaultView?.getComputedStyle(\n element,\n );\n\n return (\n computedStyle?.display !== \"none\" &&\n computedStyle?.visibility !== \"hidden\"\n );\n });\n const triggerIndex = trigger ? tabbableElements.indexOf(trigger) : -1;\n const direction = event.shiftKey ? -1 : 1;\n const targetIndex = triggerIndex + direction;\n const target =\n triggerIndex >= 0 && tabbableElements.length > 0\n ? tabbableElements[\n (targetIndex + tabbableElements.length) % tabbableElements.length\n ]\n : undefined;\n\n context.changeOpen(false);\n\n if (target) {\n event.preventDefault();\n focusElement(target);\n }\n\n return;\n }\n\n const items = getEnabledMenuItems(menu);\n const activeIndex = items.indexOf(\n menu.ownerDocument.activeElement as HTMLElement,\n );\n\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n const direction = event.key === \"ArrowDown\" ? 1 : -1;\n const startIndex =\n activeIndex < 0 ? (direction === 1 ? -1 : 0) : activeIndex;\n const nextIndex = findNextMenuItemIndex(\n items.map(() => ({ disabled: false })),\n startIndex,\n direction,\n );\n focusIndex(items, nextIndex);\n return;\n }\n\n if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n focusIndex(items, event.key === \"Home\" ? 0 : items.length - 1);\n return;\n }\n\n if (\n event.key.length !== 1 ||\n event.key === \" \" ||\n event.ctrlKey ||\n event.metaKey ||\n event.altKey\n ) {\n return;\n }\n\n event.preventDefault();\n\n const nextBuffer = `${typeaheadRef.current}${event.key}`;\n const repeatedCharacter = [...nextBuffer].every(\n (character) =>\n character.toLocaleLowerCase() === nextBuffer[0].toLocaleLowerCase(),\n );\n const query = repeatedCharacter ? event.key : nextBuffer;\n typeaheadRef.current = query;\n\n if (typeaheadTimerRef.current !== null) {\n clearTimeout(typeaheadTimerRef.current);\n }\n\n typeaheadTimerRef.current = setTimeout(() => {\n typeaheadRef.current = \"\";\n typeaheadTimerRef.current = null;\n }, 500);\n\n const nextIndex = findMenuItemIndexByText(\n items.map((item) => ({\n text:\n item.dataset.textValue ??\n item.querySelector(\".puzzle-dropdown-menu__item-label\")?.textContent ??\n item.textContent ??\n \"\",\n })),\n query,\n activeIndex,\n );\n\n focusIndex(items, nextIndex);\n };\n\n return (\n <div\n {...contentProps}\n ref={menuRef}\n id={id ?? context.contentId}\n className={cn(\"puzzle-dropdown-menu__content\", className)}\n role=\"menu\"\n aria-orientation=\"vertical\"\n aria-label={ariaLabel}\n aria-labelledby={\n ariaLabel ? undefined : (ariaLabelledBy ?? context.triggerId)\n }\n tabIndex={-1}\n data-state={context.open ? \"open\" : \"closed\"}\n style={{ ...style, maxHeight }}\n onKeyDown={handleKeyDown}\n >\n {children}\n </div>\n );\n};\n\nexport { DropdownMenuContent };\n"],"mappings":"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"}
1
+ {"version":3,"file":"dropdown-menu-content.cjs","names":["useDropdownMenuContext","useRef","usePopoutPositioned","getEnabledMenuItems","findNextMenuItemIndex","findMenuItemIndexByText","cn"],"sources":["../../../../src/components/overlays/dropdown-menu/dropdown-menu-content.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, type KeyboardEvent } from \"react\";\n\nimport { cn } from \"@puzzle-ui/core\";\n\nimport { usePopoutPositioned } from \"../popout\";\n\nimport { useDropdownMenuContext } from \"./dropdown-menu.context\";\nimport {\n findMenuItemIndexByText,\n findNextMenuItemIndex,\n focusElement,\n getEnabledMenuItems,\n} from \"./dropdown-menu.utils\";\n\nimport type { DropdownMenuContentProps } from \"./dropdown-menu.types\";\n\nconst DropdownMenuContent = ({\n children,\n id,\n className,\n style,\n maxHeight = \"min(24rem, calc(100dvh - 2rem))\",\n onKeyDown,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n ...contentProps\n}: DropdownMenuContentProps) => {\n const context = useDropdownMenuContext();\n const menuRef = useRef<HTMLDivElement | null>(null);\n const typeaheadRef = useRef(\"\");\n const typeaheadTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const initialFocusDoneRef = useRef(false);\n const positioned = usePopoutPositioned();\n\n useEffect(() => {\n if (!context.open) {\n initialFocusDoneRef.current = false;\n }\n\n typeaheadRef.current = \"\";\n\n if (typeaheadTimerRef.current !== null) {\n clearTimeout(typeaheadTimerRef.current);\n typeaheadTimerRef.current = null;\n }\n }, [context.open]);\n\n useEffect(() => {\n if (!context.open) {\n return;\n }\n\n const menu = menuRef.current;\n\n if (!menu) {\n return;\n }\n\n if (!positioned || initialFocusDoneRef.current) {\n return;\n }\n\n initialFocusDoneRef.current = true;\n\n const items = getEnabledMenuItems(menu);\n const target =\n context.focusPositionRef.current === \"last\"\n ? items[items.length - 1]\n : items[0];\n\n focusElement(target ?? menu);\n }, [context.open, context.focusPositionRef, positioned]);\n\n useEffect(\n () => () => {\n if (typeaheadTimerRef.current !== null) {\n clearTimeout(typeaheadTimerRef.current);\n }\n },\n [],\n );\n\n const focusIndex = (items: HTMLElement[], index: number) => {\n if (index >= 0 && index < items.length) {\n focusElement(items[index]);\n }\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n if (event.defaultPrevented) {\n return;\n }\n\n const menu = menuRef.current;\n\n if (!menu) {\n return;\n }\n\n if (event.key === \"Tab\") {\n const ownerDocument = event.currentTarget.ownerDocument;\n const trigger = context.triggerRef.current;\n const tabbableSelector = [\n \"a[href]\",\n \"area[href]\",\n \"button:not([disabled])\",\n \"input:not([disabled]):not([type='hidden'])\",\n \"select:not([disabled])\",\n \"textarea:not([disabled])\",\n \"iframe\",\n \"object\",\n \"embed\",\n \"summary\",\n \"audio[controls]\",\n \"video[controls]\",\n \"[contenteditable='true']\",\n \"[tabindex]:not([tabindex='-1'])\",\n ].join(\",\");\n const tabbableElements = Array.from(\n ownerDocument.querySelectorAll<HTMLElement>(tabbableSelector),\n ).filter((element) => {\n if (\n element === menu ||\n menu.contains(element) ||\n element.hidden ||\n element.tabIndex < 0 ||\n element.getAttribute(\"aria-disabled\") === \"true\" ||\n element.closest(\"[hidden], [inert], [aria-hidden='true']\")\n ) {\n return false;\n }\n\n const computedStyle = ownerDocument.defaultView?.getComputedStyle(\n element,\n );\n\n return (\n computedStyle?.display !== \"none\" &&\n computedStyle?.visibility !== \"hidden\"\n );\n });\n const triggerIndex = trigger ? tabbableElements.indexOf(trigger) : -1;\n const direction = event.shiftKey ? -1 : 1;\n const targetIndex = triggerIndex + direction;\n const target =\n triggerIndex >= 0 && tabbableElements.length > 0\n ? tabbableElements[\n (targetIndex + tabbableElements.length) % tabbableElements.length\n ]\n : undefined;\n\n context.changeOpen(false);\n\n if (target) {\n event.preventDefault();\n focusElement(target);\n }\n\n return;\n }\n\n const items = getEnabledMenuItems(menu);\n const activeIndex = items.indexOf(\n menu.ownerDocument.activeElement as HTMLElement,\n );\n\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n const direction = event.key === \"ArrowDown\" ? 1 : -1;\n const startIndex =\n activeIndex < 0 ? (direction === 1 ? -1 : 0) : activeIndex;\n const nextIndex = findNextMenuItemIndex(\n items.map(() => ({ disabled: false })),\n startIndex,\n direction,\n );\n focusIndex(items, nextIndex);\n return;\n }\n\n if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n focusIndex(items, event.key === \"Home\" ? 0 : items.length - 1);\n return;\n }\n\n if (\n event.key.length !== 1 ||\n event.key === \" \" ||\n event.ctrlKey ||\n event.metaKey ||\n event.altKey\n ) {\n return;\n }\n\n event.preventDefault();\n\n const nextBuffer = `${typeaheadRef.current}${event.key}`;\n const repeatedCharacter = [...nextBuffer].every(\n (character) =>\n character.toLocaleLowerCase() === nextBuffer[0].toLocaleLowerCase(),\n );\n const query = repeatedCharacter ? event.key : nextBuffer;\n typeaheadRef.current = query;\n\n if (typeaheadTimerRef.current !== null) {\n clearTimeout(typeaheadTimerRef.current);\n }\n\n typeaheadTimerRef.current = setTimeout(() => {\n typeaheadRef.current = \"\";\n typeaheadTimerRef.current = null;\n }, 500);\n\n const nextIndex = findMenuItemIndexByText(\n items.map((item) => ({\n text:\n item.dataset.textValue ??\n item.querySelector(\".puzzle-dropdown-menu__item-label\")?.textContent ??\n item.textContent ??\n \"\",\n })),\n query,\n activeIndex,\n );\n\n focusIndex(items, nextIndex);\n };\n\n return (\n <div\n {...contentProps}\n ref={menuRef}\n id={id ?? context.contentId}\n className={cn(\"puzzle-dropdown-menu__content\", className)}\n role=\"menu\"\n aria-orientation=\"vertical\"\n aria-label={ariaLabel}\n aria-labelledby={\n ariaLabel ? undefined : (ariaLabelledBy ?? context.triggerId)\n }\n tabIndex={-1}\n data-state={context.open ? \"open\" : \"closed\"}\n style={{ ...style, maxHeight }}\n onKeyDown={handleKeyDown}\n >\n {children}\n </div>\n );\n};\n\nexport { DropdownMenuContent };\n"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  "use client";
2
+ import { usePopoutPositioned } from "../popout/index.js";
2
3
  import { useDropdownMenuContext } from "./dropdown-menu.context.js";
3
4
  import { findMenuItemIndexByText, findNextMenuItemIndex, focusElement, getEnabledMenuItems } from "./dropdown-menu.utils.js";
4
5
  import { cn } from "@puzzle-ui/core";
@@ -10,19 +11,30 @@ const DropdownMenuContent = ({ children, id, className, style, maxHeight = "min(
10
11
  const menuRef = useRef(null);
11
12
  const typeaheadRef = useRef("");
12
13
  const typeaheadTimerRef = useRef(null);
14
+ const initialFocusDoneRef = useRef(false);
15
+ const positioned = usePopoutPositioned();
13
16
  useEffect(() => {
17
+ if (!context.open) initialFocusDoneRef.current = false;
14
18
  typeaheadRef.current = "";
15
19
  if (typeaheadTimerRef.current !== null) {
16
20
  clearTimeout(typeaheadTimerRef.current);
17
21
  typeaheadTimerRef.current = null;
18
22
  }
23
+ }, [context.open]);
24
+ useEffect(() => {
19
25
  if (!context.open) return;
20
26
  const menu = menuRef.current;
21
27
  if (!menu) return;
28
+ if (!positioned || initialFocusDoneRef.current) return;
29
+ initialFocusDoneRef.current = true;
22
30
  const items = getEnabledMenuItems(menu);
23
31
  const target = context.focusPositionRef.current === "last" ? items[items.length - 1] : items[0];
24
32
  focusElement(target ?? menu);
25
- }, [context.open, context.focusPositionRef]);
33
+ }, [
34
+ context.open,
35
+ context.focusPositionRef,
36
+ positioned
37
+ ]);
26
38
  useEffect(() => () => {
27
39
  if (typeaheadTimerRef.current !== null) clearTimeout(typeaheadTimerRef.current);
28
40
  }, []);
@@ -1 +1 @@
1
- {"version":3,"file":"dropdown-menu-content.js","names":[],"sources":["../../../../src/components/overlays/dropdown-menu/dropdown-menu-content.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, type KeyboardEvent } from \"react\";\n\nimport { cn } from \"@puzzle-ui/core\";\n\nimport { useDropdownMenuContext } from \"./dropdown-menu.context\";\nimport {\n findMenuItemIndexByText,\n findNextMenuItemIndex,\n focusElement,\n getEnabledMenuItems,\n} from \"./dropdown-menu.utils\";\n\nimport type { DropdownMenuContentProps } from \"./dropdown-menu.types\";\n\nconst DropdownMenuContent = ({\n children,\n id,\n className,\n style,\n maxHeight = \"min(24rem, calc(100dvh - 2rem))\",\n onKeyDown,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n ...contentProps\n}: DropdownMenuContentProps) => {\n const context = useDropdownMenuContext();\n const menuRef = useRef<HTMLDivElement | null>(null);\n const typeaheadRef = useRef(\"\");\n const typeaheadTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n typeaheadRef.current = \"\";\n\n if (typeaheadTimerRef.current !== null) {\n clearTimeout(typeaheadTimerRef.current);\n typeaheadTimerRef.current = null;\n }\n\n if (!context.open) {\n return;\n }\n\n const menu = menuRef.current;\n\n if (!menu) {\n return;\n }\n\n const items = getEnabledMenuItems(menu);\n const target =\n context.focusPositionRef.current === \"last\"\n ? items[items.length - 1]\n : items[0];\n\n focusElement(target ?? menu);\n }, [context.open, context.focusPositionRef]);\n\n useEffect(\n () => () => {\n if (typeaheadTimerRef.current !== null) {\n clearTimeout(typeaheadTimerRef.current);\n }\n },\n [],\n );\n\n const focusIndex = (items: HTMLElement[], index: number) => {\n if (index >= 0 && index < items.length) {\n focusElement(items[index]);\n }\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n if (event.defaultPrevented) {\n return;\n }\n\n const menu = menuRef.current;\n\n if (!menu) {\n return;\n }\n\n if (event.key === \"Tab\") {\n const ownerDocument = event.currentTarget.ownerDocument;\n const trigger = context.triggerRef.current;\n const tabbableSelector = [\n \"a[href]\",\n \"area[href]\",\n \"button:not([disabled])\",\n \"input:not([disabled]):not([type='hidden'])\",\n \"select:not([disabled])\",\n \"textarea:not([disabled])\",\n \"iframe\",\n \"object\",\n \"embed\",\n \"summary\",\n \"audio[controls]\",\n \"video[controls]\",\n \"[contenteditable='true']\",\n \"[tabindex]:not([tabindex='-1'])\",\n ].join(\",\");\n const tabbableElements = Array.from(\n ownerDocument.querySelectorAll<HTMLElement>(tabbableSelector),\n ).filter((element) => {\n if (\n element === menu ||\n menu.contains(element) ||\n element.hidden ||\n element.tabIndex < 0 ||\n element.getAttribute(\"aria-disabled\") === \"true\" ||\n element.closest(\"[hidden], [inert], [aria-hidden='true']\")\n ) {\n return false;\n }\n\n const computedStyle = ownerDocument.defaultView?.getComputedStyle(\n element,\n );\n\n return (\n computedStyle?.display !== \"none\" &&\n computedStyle?.visibility !== \"hidden\"\n );\n });\n const triggerIndex = trigger ? tabbableElements.indexOf(trigger) : -1;\n const direction = event.shiftKey ? -1 : 1;\n const targetIndex = triggerIndex + direction;\n const target =\n triggerIndex >= 0 && tabbableElements.length > 0\n ? tabbableElements[\n (targetIndex + tabbableElements.length) % tabbableElements.length\n ]\n : undefined;\n\n context.changeOpen(false);\n\n if (target) {\n event.preventDefault();\n focusElement(target);\n }\n\n return;\n }\n\n const items = getEnabledMenuItems(menu);\n const activeIndex = items.indexOf(\n menu.ownerDocument.activeElement as HTMLElement,\n );\n\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n const direction = event.key === \"ArrowDown\" ? 1 : -1;\n const startIndex =\n activeIndex < 0 ? (direction === 1 ? -1 : 0) : activeIndex;\n const nextIndex = findNextMenuItemIndex(\n items.map(() => ({ disabled: false })),\n startIndex,\n direction,\n );\n focusIndex(items, nextIndex);\n return;\n }\n\n if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n focusIndex(items, event.key === \"Home\" ? 0 : items.length - 1);\n return;\n }\n\n if (\n event.key.length !== 1 ||\n event.key === \" \" ||\n event.ctrlKey ||\n event.metaKey ||\n event.altKey\n ) {\n return;\n }\n\n event.preventDefault();\n\n const nextBuffer = `${typeaheadRef.current}${event.key}`;\n const repeatedCharacter = [...nextBuffer].every(\n (character) =>\n character.toLocaleLowerCase() === nextBuffer[0].toLocaleLowerCase(),\n );\n const query = repeatedCharacter ? event.key : nextBuffer;\n typeaheadRef.current = query;\n\n if (typeaheadTimerRef.current !== null) {\n clearTimeout(typeaheadTimerRef.current);\n }\n\n typeaheadTimerRef.current = setTimeout(() => {\n typeaheadRef.current = \"\";\n typeaheadTimerRef.current = null;\n }, 500);\n\n const nextIndex = findMenuItemIndexByText(\n items.map((item) => ({\n text:\n item.dataset.textValue ??\n item.querySelector(\".puzzle-dropdown-menu__item-label\")?.textContent ??\n item.textContent ??\n \"\",\n })),\n query,\n activeIndex,\n );\n\n focusIndex(items, nextIndex);\n };\n\n return (\n <div\n {...contentProps}\n ref={menuRef}\n id={id ?? context.contentId}\n className={cn(\"puzzle-dropdown-menu__content\", className)}\n role=\"menu\"\n aria-orientation=\"vertical\"\n aria-label={ariaLabel}\n aria-labelledby={\n ariaLabel ? undefined : (ariaLabelledBy ?? context.triggerId)\n }\n tabIndex={-1}\n data-state={context.open ? \"open\" : \"closed\"}\n style={{ ...style, maxHeight }}\n onKeyDown={handleKeyDown}\n >\n {children}\n </div>\n );\n};\n\nexport { DropdownMenuContent };\n"],"mappings":"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"}
1
+ {"version":3,"file":"dropdown-menu-content.js","names":[],"sources":["../../../../src/components/overlays/dropdown-menu/dropdown-menu-content.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, type KeyboardEvent } from \"react\";\n\nimport { cn } from \"@puzzle-ui/core\";\n\nimport { usePopoutPositioned } from \"../popout\";\n\nimport { useDropdownMenuContext } from \"./dropdown-menu.context\";\nimport {\n findMenuItemIndexByText,\n findNextMenuItemIndex,\n focusElement,\n getEnabledMenuItems,\n} from \"./dropdown-menu.utils\";\n\nimport type { DropdownMenuContentProps } from \"./dropdown-menu.types\";\n\nconst DropdownMenuContent = ({\n children,\n id,\n className,\n style,\n maxHeight = \"min(24rem, calc(100dvh - 2rem))\",\n onKeyDown,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n ...contentProps\n}: DropdownMenuContentProps) => {\n const context = useDropdownMenuContext();\n const menuRef = useRef<HTMLDivElement | null>(null);\n const typeaheadRef = useRef(\"\");\n const typeaheadTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const initialFocusDoneRef = useRef(false);\n const positioned = usePopoutPositioned();\n\n useEffect(() => {\n if (!context.open) {\n initialFocusDoneRef.current = false;\n }\n\n typeaheadRef.current = \"\";\n\n if (typeaheadTimerRef.current !== null) {\n clearTimeout(typeaheadTimerRef.current);\n typeaheadTimerRef.current = null;\n }\n }, [context.open]);\n\n useEffect(() => {\n if (!context.open) {\n return;\n }\n\n const menu = menuRef.current;\n\n if (!menu) {\n return;\n }\n\n if (!positioned || initialFocusDoneRef.current) {\n return;\n }\n\n initialFocusDoneRef.current = true;\n\n const items = getEnabledMenuItems(menu);\n const target =\n context.focusPositionRef.current === \"last\"\n ? items[items.length - 1]\n : items[0];\n\n focusElement(target ?? menu);\n }, [context.open, context.focusPositionRef, positioned]);\n\n useEffect(\n () => () => {\n if (typeaheadTimerRef.current !== null) {\n clearTimeout(typeaheadTimerRef.current);\n }\n },\n [],\n );\n\n const focusIndex = (items: HTMLElement[], index: number) => {\n if (index >= 0 && index < items.length) {\n focusElement(items[index]);\n }\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n if (event.defaultPrevented) {\n return;\n }\n\n const menu = menuRef.current;\n\n if (!menu) {\n return;\n }\n\n if (event.key === \"Tab\") {\n const ownerDocument = event.currentTarget.ownerDocument;\n const trigger = context.triggerRef.current;\n const tabbableSelector = [\n \"a[href]\",\n \"area[href]\",\n \"button:not([disabled])\",\n \"input:not([disabled]):not([type='hidden'])\",\n \"select:not([disabled])\",\n \"textarea:not([disabled])\",\n \"iframe\",\n \"object\",\n \"embed\",\n \"summary\",\n \"audio[controls]\",\n \"video[controls]\",\n \"[contenteditable='true']\",\n \"[tabindex]:not([tabindex='-1'])\",\n ].join(\",\");\n const tabbableElements = Array.from(\n ownerDocument.querySelectorAll<HTMLElement>(tabbableSelector),\n ).filter((element) => {\n if (\n element === menu ||\n menu.contains(element) ||\n element.hidden ||\n element.tabIndex < 0 ||\n element.getAttribute(\"aria-disabled\") === \"true\" ||\n element.closest(\"[hidden], [inert], [aria-hidden='true']\")\n ) {\n return false;\n }\n\n const computedStyle = ownerDocument.defaultView?.getComputedStyle(\n element,\n );\n\n return (\n computedStyle?.display !== \"none\" &&\n computedStyle?.visibility !== \"hidden\"\n );\n });\n const triggerIndex = trigger ? tabbableElements.indexOf(trigger) : -1;\n const direction = event.shiftKey ? -1 : 1;\n const targetIndex = triggerIndex + direction;\n const target =\n triggerIndex >= 0 && tabbableElements.length > 0\n ? tabbableElements[\n (targetIndex + tabbableElements.length) % tabbableElements.length\n ]\n : undefined;\n\n context.changeOpen(false);\n\n if (target) {\n event.preventDefault();\n focusElement(target);\n }\n\n return;\n }\n\n const items = getEnabledMenuItems(menu);\n const activeIndex = items.indexOf(\n menu.ownerDocument.activeElement as HTMLElement,\n );\n\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n const direction = event.key === \"ArrowDown\" ? 1 : -1;\n const startIndex =\n activeIndex < 0 ? (direction === 1 ? -1 : 0) : activeIndex;\n const nextIndex = findNextMenuItemIndex(\n items.map(() => ({ disabled: false })),\n startIndex,\n direction,\n );\n focusIndex(items, nextIndex);\n return;\n }\n\n if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n focusIndex(items, event.key === \"Home\" ? 0 : items.length - 1);\n return;\n }\n\n if (\n event.key.length !== 1 ||\n event.key === \" \" ||\n event.ctrlKey ||\n event.metaKey ||\n event.altKey\n ) {\n return;\n }\n\n event.preventDefault();\n\n const nextBuffer = `${typeaheadRef.current}${event.key}`;\n const repeatedCharacter = [...nextBuffer].every(\n (character) =>\n character.toLocaleLowerCase() === nextBuffer[0].toLocaleLowerCase(),\n );\n const query = repeatedCharacter ? event.key : nextBuffer;\n typeaheadRef.current = query;\n\n if (typeaheadTimerRef.current !== null) {\n clearTimeout(typeaheadTimerRef.current);\n }\n\n typeaheadTimerRef.current = setTimeout(() => {\n typeaheadRef.current = \"\";\n typeaheadTimerRef.current = null;\n }, 500);\n\n const nextIndex = findMenuItemIndexByText(\n items.map((item) => ({\n text:\n item.dataset.textValue ??\n item.querySelector(\".puzzle-dropdown-menu__item-label\")?.textContent ??\n item.textContent ??\n \"\",\n })),\n query,\n activeIndex,\n );\n\n focusIndex(items, nextIndex);\n };\n\n return (\n <div\n {...contentProps}\n ref={menuRef}\n id={id ?? context.contentId}\n className={cn(\"puzzle-dropdown-menu__content\", className)}\n role=\"menu\"\n aria-orientation=\"vertical\"\n aria-label={ariaLabel}\n aria-labelledby={\n ariaLabel ? undefined : (ariaLabelledBy ?? context.triggerId)\n }\n tabIndex={-1}\n data-state={context.open ? \"open\" : \"closed\"}\n style={{ ...style, maxHeight }}\n onKeyDown={handleKeyDown}\n >\n {children}\n </div>\n );\n};\n\nexport { DropdownMenuContent };\n"],"mappings":"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"}
@@ -9,6 +9,8 @@ let react_jsx_runtime = require("react/jsx-runtime");
9
9
  let react_dom = require("react-dom");
10
10
  let _puzzle_ui_theme_scope_context = require("@puzzle-ui/theme/scope-context");
11
11
  // src/components/overlays/popout/index.tsx
12
+ const PopoutPositionedContext = (0, react.createContext)(true);
13
+ const usePopoutPositioned = () => (0, react.useContext)(PopoutPositionedContext);
12
14
  const setRef = (ref, value) => {
13
15
  if (typeof ref === "function") ref(value);
14
16
  else if (ref) ref.current = value;
@@ -181,10 +183,14 @@ const Popout = ({ trigger, children, position = "bottom", align = "start", actio
181
183
  style: contentStyle,
182
184
  onPointerEnter: action === "hover" ? cancelDebouncedClose : void 0,
183
185
  onPointerLeave: action === "hover" ? scheduleClose : void 0,
184
- children
186
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PopoutPositionedContext.Provider, {
187
+ value: isPositioned,
188
+ children
189
+ })
185
190
  })
186
191
  }), portalContainer)] });
187
192
  };
188
193
  exports.Popout = Popout;
194
+ exports.usePopoutPositioned = usePopoutPositioned;
189
195
 
190
196
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["useThemeScope","useState","useRef","useCallback","useMemo","debounce","useFloatingPosition","registerOverlay","cloneElement","cn","createPortal","Transition"],"sources":["../../../../src/components/overlays/popout/index.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n cloneElement,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type HTMLAttributes,\n type MouseEvent,\n type PointerEvent,\n type ReactElement,\n type ReactNode,\n type Ref,\n type RefAttributes,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport { cn, debounce } from \"@puzzle-ui/core\";\nimport { useThemeScope } from \"@puzzle-ui/theme/scope-context\";\n\nimport { Transition } from \"../../utilities/transition\";\nimport { registerOverlay } from \"../overlay-stack\";\nimport { useFloatingPosition } from \"../floating-position\";\n\nimport \"./popout.css\";\n\ntype PopoutPosition = \"top\" | \"right\" | \"bottom\" | \"left\";\n\ntype PopoutAlignment = \"start\" | \"center\" | \"end\";\n\ntype PopoutAction = \"hover\" | \"click\" | \"down\";\n\ntype PopoutTriggerProps = HTMLAttributes<HTMLElement> &\n RefAttributes<HTMLElement>;\n\ntype PopoutProps = {\n trigger: ReactElement<PopoutTriggerProps>;\n children: ReactNode;\n position?: PopoutPosition;\n align?: PopoutAlignment;\n action?: PopoutAction;\n offset?: number;\n collisionPadding?: number;\n exitDelay?: number;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n closeOnOutsideClick?: boolean;\n closeOnEscape?: boolean;\n toggleOnClick?: boolean;\n matchTriggerWidth?: boolean;\n className?: string;\n contentClassName?: string;\n};\n\nconst setRef = <T,>(ref: Ref<T> | undefined, value: T | null): void => {\n if (typeof ref === \"function\") {\n ref(value);\n } else if (ref) {\n ref.current = value;\n }\n};\n\nconst Popout = ({\n trigger,\n children,\n position = \"bottom\",\n align = \"start\",\n action = \"click\",\n offset = 8,\n collisionPadding = 8,\n exitDelay = 150,\n open,\n defaultOpen = false,\n onOpenChange,\n closeOnOutsideClick = true,\n closeOnEscape = true,\n toggleOnClick = false,\n matchTriggerWidth = false,\n className,\n contentClassName,\n}: PopoutProps) => {\n const themeScope = useThemeScope();\n\n const [internalOpen, setInternalOpen] = useState(defaultOpen);\n const [mounted, setMounted] = useState(false);\n\n const [anchorElement, setAnchorElement] = useState<HTMLElement | null>(null);\n\n const [portalContainer, setPortalContainer] = useState<HTMLElement | null>(\n null,\n );\n\n const [contentElement, setContentElement] = useState<HTMLDivElement | null>(\n null,\n );\n\n const anchorRef = useRef<HTMLElement | null>(null);\n const contentRef = useRef<HTMLDivElement | null>(null);\n const pointerDocumentRef = useRef<Document | null>(null);\n\n const isOpen = open ?? internalOpen;\n\n const changeOpenState = useCallback(\n (nextOpen: boolean) => {\n if (open === undefined) {\n setInternalOpen(nextOpen);\n }\n\n onOpenChange?.(nextOpen);\n },\n [open, onOpenChange],\n );\n\n const debouncedClose = useMemo(\n () => debounce(() => changeOpenState(false), Math.max(0, exitDelay)),\n [changeOpenState, exitDelay],\n );\n\n const cancelDebouncedClose = useCallback(() => {\n debouncedClose.cancel();\n }, [debouncedClose]);\n\n const scheduleClose = useCallback(() => {\n if (exitDelay > 0) {\n debouncedClose();\n } else {\n changeOpenState(false);\n }\n }, [debouncedClose, exitDelay, changeOpenState]);\n\n const removePointerListeners = useCallback((handler: EventListener) => {\n const ownerDocument = pointerDocumentRef.current;\n\n if (!ownerDocument) {\n return;\n }\n\n ownerDocument.removeEventListener(\"pointerup\", handler);\n ownerDocument.removeEventListener(\"pointercancel\", handler);\n\n pointerDocumentRef.current = null;\n }, []);\n\n const handleDocumentPointerUp = useCallback(() => {\n removePointerListeners(handleDocumentPointerUp);\n debouncedClose();\n }, [debouncedClose, removePointerListeners]);\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n return () => {\n debouncedClose.cancel();\n removePointerListeners(handleDocumentPointerUp);\n };\n }, [debouncedClose, handleDocumentPointerUp, removePointerListeners]);\n\n const handleTriggerRef = useCallback(\n (node: HTMLElement | null) => {\n anchorRef.current = node;\n setAnchorElement(node);\n\n setPortalContainer(\n themeScope\n ? themeScope.portalTarget\n : (node?.ownerDocument.body ?? null),\n );\n\n setRef(trigger.props.ref, node);\n },\n [trigger, themeScope],\n );\n\n const handleContentRef = useCallback((node: HTMLDivElement | null) => {\n contentRef.current = node;\n setContentElement(node);\n }, []);\n\n const {\n style: positionStyle,\n placement,\n isPositioned,\n } = useFloatingPosition({\n anchor: anchorElement,\n content: contentElement,\n enabled: mounted && isOpen,\n position,\n align,\n offset,\n collisionPadding,\n matchTriggerWidth,\n });\n\n // Outside click\n useEffect(() => {\n if (!isOpen || !closeOnOutsideClick || !portalContainer) {\n return;\n }\n\n const ownerDocument = anchorElement?.ownerDocument;\n const ownerWindow = ownerDocument?.defaultView;\n\n if (!ownerDocument || !ownerWindow) {\n return;\n }\n\n const handlePointerDown = (event: globalThis.PointerEvent) => {\n const target = event.target;\n\n if (!(target instanceof ownerWindow.Node)) {\n return;\n }\n\n if (\n anchorRef.current?.contains(target) ||\n contentRef.current?.contains(target)\n ) {\n return;\n }\n\n cancelDebouncedClose();\n changeOpenState(false);\n };\n\n ownerDocument.addEventListener(\"pointerdown\", handlePointerDown);\n\n return () => {\n ownerDocument.removeEventListener(\"pointerdown\", handlePointerDown);\n };\n }, [\n isOpen,\n closeOnOutsideClick,\n portalContainer,\n anchorElement,\n cancelDebouncedClose,\n changeOpenState,\n ]);\n\n // Escape: only the topmost registered overlay handles the key.\n useEffect(() => {\n if (!isOpen || !portalContainer || !anchorElement) {\n return;\n }\n\n const ownerDocument = anchorElement.ownerDocument;\n\n return registerOverlay(ownerDocument, () => {\n if (!closeOnEscape) {\n return;\n }\n\n cancelDebouncedClose();\n changeOpenState(false);\n\n if (contentRef.current?.contains(ownerDocument.activeElement)) {\n anchorRef.current?.focus({ preventScroll: true });\n }\n });\n }, [\n isOpen,\n portalContainer,\n anchorElement,\n closeOnEscape,\n cancelDebouncedClose,\n changeOpenState,\n ]);\n\n const handlePointerEnter = (event: PointerEvent<HTMLElement>) => {\n trigger.props.onPointerEnter?.(event);\n\n if (action !== \"hover\") {\n return;\n }\n\n cancelDebouncedClose();\n changeOpenState(true);\n };\n\n const handlePointerLeave = (event: PointerEvent<HTMLElement>) => {\n trigger.props.onPointerLeave?.(event);\n\n if (action !== \"hover\") {\n return;\n }\n\n scheduleClose();\n };\n\n const handlePointerUp = (event: PointerEvent<HTMLElement>) => {\n trigger.props.onPointerUp?.(event);\n };\n\n const handlePointerDown = (event: PointerEvent<HTMLElement>) => {\n trigger.props.onPointerDown?.(event);\n\n if (action !== \"down\" || event.defaultPrevented) {\n return;\n }\n\n changeOpenState(true);\n\n const ownerDocument = event.currentTarget.ownerDocument;\n\n removePointerListeners(handleDocumentPointerUp);\n\n pointerDocumentRef.current = ownerDocument;\n\n ownerDocument.addEventListener(\"pointerup\", handleDocumentPointerUp);\n ownerDocument.addEventListener(\"pointercancel\", handleDocumentPointerUp);\n };\n\n const handleClick = (event: MouseEvent<HTMLElement>) => {\n trigger.props.onClick?.(event);\n\n if (action !== \"click\" || event.defaultPrevented) {\n return;\n }\n\n changeOpenState(toggleOnClick ? !isOpen : true);\n };\n\n const triggerElement = cloneElement(trigger, {\n ref: handleTriggerRef,\n className: cn(trigger.props.className, className),\n onPointerEnter: handlePointerEnter,\n onPointerLeave: handlePointerLeave,\n onPointerDown: handlePointerDown,\n onPointerUp: handlePointerUp,\n onClick: handleClick,\n });\n\n if (!mounted) {\n return triggerElement;\n }\n\n const contentStyle: CSSProperties = {\n ...(positionStyle ?? {}),\n visibility: isPositioned ? \"visible\" : \"hidden\",\n pointerEvents: isOpen && isPositioned ? \"auto\" : \"none\",\n };\n\n return (\n <>\n {triggerElement}\n\n {portalContainer &&\n createPortal(\n <Transition\n visible={isOpen}\n template=\"fade\"\n duration={200}\n unmountOnExit\n >\n <div\n ref={handleContentRef}\n className={cn(\"puzzle-popout__content\", contentClassName)}\n data-placement={placement}\n style={contentStyle}\n onPointerEnter={\n action === \"hover\" ? cancelDebouncedClose : undefined\n }\n onPointerLeave={action === \"hover\" ? scheduleClose : undefined}\n >\n {children}\n </div>\n </Transition>,\n portalContainer,\n )}\n </>\n );\n};\n\nexport {\n Popout,\n type PopoutProps,\n type PopoutPosition,\n type PopoutAlignment,\n type PopoutAction,\n type PopoutTriggerProps,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["createContext","useContext","useThemeScope","useState","useRef","useCallback","useMemo","debounce","useFloatingPosition","registerOverlay","cloneElement","cn","createPortal","Transition"],"sources":["../../../../src/components/overlays/popout/index.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n cloneElement,\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type HTMLAttributes,\n type MouseEvent,\n type PointerEvent,\n type ReactElement,\n type ReactNode,\n type Ref,\n type RefAttributes,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport { cn, debounce } from \"@puzzle-ui/core\";\nimport { useThemeScope } from \"@puzzle-ui/theme/scope-context\";\n\nimport { Transition } from \"../../utilities/transition\";\nimport { registerOverlay } from \"../overlay-stack\";\nimport { useFloatingPosition } from \"../floating-position\";\n\nimport \"./popout.css\";\n\n// Content is hidden, and therefore unfocusable, until it has been positioned.\nconst PopoutPositionedContext = createContext(true);\n\nconst usePopoutPositioned = (): boolean => useContext(PopoutPositionedContext);\n\ntype PopoutPosition = \"top\" | \"right\" | \"bottom\" | \"left\";\n\ntype PopoutAlignment = \"start\" | \"center\" | \"end\";\n\ntype PopoutAction = \"hover\" | \"click\" | \"down\";\n\ntype PopoutTriggerProps = HTMLAttributes<HTMLElement> &\n RefAttributes<HTMLElement>;\n\ntype PopoutProps = {\n trigger: ReactElement<PopoutTriggerProps>;\n children: ReactNode;\n position?: PopoutPosition;\n align?: PopoutAlignment;\n action?: PopoutAction;\n offset?: number;\n collisionPadding?: number;\n exitDelay?: number;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n closeOnOutsideClick?: boolean;\n closeOnEscape?: boolean;\n toggleOnClick?: boolean;\n matchTriggerWidth?: boolean;\n className?: string;\n contentClassName?: string;\n};\n\nconst setRef = <T,>(ref: Ref<T> | undefined, value: T | null): void => {\n if (typeof ref === \"function\") {\n ref(value);\n } else if (ref) {\n ref.current = value;\n }\n};\n\nconst Popout = ({\n trigger,\n children,\n position = \"bottom\",\n align = \"start\",\n action = \"click\",\n offset = 8,\n collisionPadding = 8,\n exitDelay = 150,\n open,\n defaultOpen = false,\n onOpenChange,\n closeOnOutsideClick = true,\n closeOnEscape = true,\n toggleOnClick = false,\n matchTriggerWidth = false,\n className,\n contentClassName,\n}: PopoutProps) => {\n const themeScope = useThemeScope();\n\n const [internalOpen, setInternalOpen] = useState(defaultOpen);\n const [mounted, setMounted] = useState(false);\n\n const [anchorElement, setAnchorElement] = useState<HTMLElement | null>(null);\n\n const [portalContainer, setPortalContainer] = useState<HTMLElement | null>(\n null,\n );\n\n const [contentElement, setContentElement] = useState<HTMLDivElement | null>(\n null,\n );\n\n const anchorRef = useRef<HTMLElement | null>(null);\n const contentRef = useRef<HTMLDivElement | null>(null);\n const pointerDocumentRef = useRef<Document | null>(null);\n\n const isOpen = open ?? internalOpen;\n\n const changeOpenState = useCallback(\n (nextOpen: boolean) => {\n if (open === undefined) {\n setInternalOpen(nextOpen);\n }\n\n onOpenChange?.(nextOpen);\n },\n [open, onOpenChange],\n );\n\n const debouncedClose = useMemo(\n () => debounce(() => changeOpenState(false), Math.max(0, exitDelay)),\n [changeOpenState, exitDelay],\n );\n\n const cancelDebouncedClose = useCallback(() => {\n debouncedClose.cancel();\n }, [debouncedClose]);\n\n const scheduleClose = useCallback(() => {\n if (exitDelay > 0) {\n debouncedClose();\n } else {\n changeOpenState(false);\n }\n }, [debouncedClose, exitDelay, changeOpenState]);\n\n const removePointerListeners = useCallback((handler: EventListener) => {\n const ownerDocument = pointerDocumentRef.current;\n\n if (!ownerDocument) {\n return;\n }\n\n ownerDocument.removeEventListener(\"pointerup\", handler);\n ownerDocument.removeEventListener(\"pointercancel\", handler);\n\n pointerDocumentRef.current = null;\n }, []);\n\n const handleDocumentPointerUp = useCallback(() => {\n removePointerListeners(handleDocumentPointerUp);\n debouncedClose();\n }, [debouncedClose, removePointerListeners]);\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n return () => {\n debouncedClose.cancel();\n removePointerListeners(handleDocumentPointerUp);\n };\n }, [debouncedClose, handleDocumentPointerUp, removePointerListeners]);\n\n const handleTriggerRef = useCallback(\n (node: HTMLElement | null) => {\n anchorRef.current = node;\n setAnchorElement(node);\n\n setPortalContainer(\n themeScope\n ? themeScope.portalTarget\n : (node?.ownerDocument.body ?? null),\n );\n\n setRef(trigger.props.ref, node);\n },\n [trigger, themeScope],\n );\n\n const handleContentRef = useCallback((node: HTMLDivElement | null) => {\n contentRef.current = node;\n setContentElement(node);\n }, []);\n\n const {\n style: positionStyle,\n placement,\n isPositioned,\n } = useFloatingPosition({\n anchor: anchorElement,\n content: contentElement,\n enabled: mounted && isOpen,\n position,\n align,\n offset,\n collisionPadding,\n matchTriggerWidth,\n });\n\n // Outside click\n useEffect(() => {\n if (!isOpen || !closeOnOutsideClick || !portalContainer) {\n return;\n }\n\n const ownerDocument = anchorElement?.ownerDocument;\n const ownerWindow = ownerDocument?.defaultView;\n\n if (!ownerDocument || !ownerWindow) {\n return;\n }\n\n const handlePointerDown = (event: globalThis.PointerEvent) => {\n const target = event.target;\n\n if (!(target instanceof ownerWindow.Node)) {\n return;\n }\n\n if (\n anchorRef.current?.contains(target) ||\n contentRef.current?.contains(target)\n ) {\n return;\n }\n\n cancelDebouncedClose();\n changeOpenState(false);\n };\n\n ownerDocument.addEventListener(\"pointerdown\", handlePointerDown);\n\n return () => {\n ownerDocument.removeEventListener(\"pointerdown\", handlePointerDown);\n };\n }, [\n isOpen,\n closeOnOutsideClick,\n portalContainer,\n anchorElement,\n cancelDebouncedClose,\n changeOpenState,\n ]);\n\n // Escape: only the topmost registered overlay handles the key.\n useEffect(() => {\n if (!isOpen || !portalContainer || !anchorElement) {\n return;\n }\n\n const ownerDocument = anchorElement.ownerDocument;\n\n return registerOverlay(ownerDocument, () => {\n if (!closeOnEscape) {\n return;\n }\n\n cancelDebouncedClose();\n changeOpenState(false);\n\n if (contentRef.current?.contains(ownerDocument.activeElement)) {\n anchorRef.current?.focus({ preventScroll: true });\n }\n });\n }, [\n isOpen,\n portalContainer,\n anchorElement,\n closeOnEscape,\n cancelDebouncedClose,\n changeOpenState,\n ]);\n\n const handlePointerEnter = (event: PointerEvent<HTMLElement>) => {\n trigger.props.onPointerEnter?.(event);\n\n if (action !== \"hover\") {\n return;\n }\n\n cancelDebouncedClose();\n changeOpenState(true);\n };\n\n const handlePointerLeave = (event: PointerEvent<HTMLElement>) => {\n trigger.props.onPointerLeave?.(event);\n\n if (action !== \"hover\") {\n return;\n }\n\n scheduleClose();\n };\n\n const handlePointerUp = (event: PointerEvent<HTMLElement>) => {\n trigger.props.onPointerUp?.(event);\n };\n\n const handlePointerDown = (event: PointerEvent<HTMLElement>) => {\n trigger.props.onPointerDown?.(event);\n\n if (action !== \"down\" || event.defaultPrevented) {\n return;\n }\n\n changeOpenState(true);\n\n const ownerDocument = event.currentTarget.ownerDocument;\n\n removePointerListeners(handleDocumentPointerUp);\n\n pointerDocumentRef.current = ownerDocument;\n\n ownerDocument.addEventListener(\"pointerup\", handleDocumentPointerUp);\n ownerDocument.addEventListener(\"pointercancel\", handleDocumentPointerUp);\n };\n\n const handleClick = (event: MouseEvent<HTMLElement>) => {\n trigger.props.onClick?.(event);\n\n if (action !== \"click\" || event.defaultPrevented) {\n return;\n }\n\n changeOpenState(toggleOnClick ? !isOpen : true);\n };\n\n const triggerElement = cloneElement(trigger, {\n ref: handleTriggerRef,\n className: cn(trigger.props.className, className),\n onPointerEnter: handlePointerEnter,\n onPointerLeave: handlePointerLeave,\n onPointerDown: handlePointerDown,\n onPointerUp: handlePointerUp,\n onClick: handleClick,\n });\n\n if (!mounted) {\n return triggerElement;\n }\n\n const contentStyle: CSSProperties = {\n ...(positionStyle ?? {}),\n visibility: isPositioned ? \"visible\" : \"hidden\",\n pointerEvents: isOpen && isPositioned ? \"auto\" : \"none\",\n };\n\n return (\n <>\n {triggerElement}\n\n {portalContainer &&\n createPortal(\n <Transition\n visible={isOpen}\n template=\"fade\"\n duration={200}\n unmountOnExit\n >\n <div\n ref={handleContentRef}\n className={cn(\"puzzle-popout__content\", contentClassName)}\n data-placement={placement}\n style={contentStyle}\n onPointerEnter={\n action === \"hover\" ? cancelDebouncedClose : undefined\n }\n onPointerLeave={action === \"hover\" ? scheduleClose : undefined}\n >\n <PopoutPositionedContext.Provider value={isPositioned}>\n {children}\n </PopoutPositionedContext.Provider>\n </div>\n </Transition>,\n portalContainer,\n )}\n </>\n );\n};\n\nexport {\n Popout,\n usePopoutPositioned,\n type PopoutProps,\n type PopoutPosition,\n type PopoutAlignment,\n type PopoutAction,\n type PopoutTriggerProps,\n};\n"],"mappings":";;;;;;;;;;;AAgCA,MAAM,2BAAA,GAA0BA,MAAAA,cAAAA,CAAc,IAAI;AAElD,MAAM,6BAAA,GAAqCC,MAAAA,WAAAA,CAAW,uBAAuB;AA+B7E,MAAM,UAAc,KAAyB,UAA0B;CACrE,IAAI,OAAO,QAAQ,YACjB,IAAI,KAAK;MACJ,IAAI,KACT,IAAI,UAAU;AAElB;AAEA,MAAM,UAAU,EACd,SACA,UACA,WAAW,UACX,QAAQ,SACR,SAAS,SACT,SAAS,GACT,mBAAmB,GACnB,YAAY,KACZ,MACA,cAAc,OACd,cACA,sBAAsB,MACtB,gBAAgB,MAChB,gBAAgB,OAChB,oBAAoB,OACpB,WACA,uBACiB;CACjB,MAAM,cAAA,GAAaC,+BAAAA,cAAAA,CAAc;CAEjC,MAAM,CAAC,cAAc,oBAAA,GAAmBC,MAAAA,SAAAA,CAAS,WAAW;CAC5D,MAAM,CAAC,SAAS,eAAA,GAAcA,MAAAA,SAAAA,CAAS,KAAK;CAE5C,MAAM,CAAC,eAAe,qBAAA,GAAoBA,MAAAA,SAAAA,CAA6B,IAAI;CAE3E,MAAM,CAAC,iBAAiB,uBAAA,GAAsBA,MAAAA,SAAAA,CAC5C,IACF;CAEA,MAAM,CAAC,gBAAgB,sBAAA,GAAqBA,MAAAA,SAAAA,CAC1C,IACF;CAEA,MAAM,aAAA,GAAYC,MAAAA,OAAAA,CAA2B,IAAI;CACjD,MAAM,cAAA,GAAaA,MAAAA,OAAAA,CAA8B,IAAI;CACrD,MAAM,sBAAA,GAAqBA,MAAAA,OAAAA,CAAwB,IAAI;CAEvD,MAAM,SAAS,QAAQ;CAEvB,MAAM,mBAAA,GAAkBC,MAAAA,YAAAA,EACrB,aAAsB;EACrB,IAAI,SAAS,KAAA,GACX,gBAAgB,QAAQ;EAG1B,eAAe,QAAQ;CACzB,GACA,CAAC,MAAM,YAAY,CACrB;CAEA,MAAM,kBAAA,GAAiBC,MAAAA,QAAAA,QAAAA,GACfC,gBAAAA,SAAAA,OAAe,gBAAgB,KAAK,GAAG,KAAK,IAAI,GAAG,SAAS,CAAC,GACnE,CAAC,iBAAiB,SAAS,CAC7B;CAEA,MAAM,wBAAA,GAAuBF,MAAAA,YAAAA,OAAkB;EAC7C,eAAe,OAAO;CACxB,GAAG,CAAC,cAAc,CAAC;CAEnB,MAAM,iBAAA,GAAgBA,MAAAA,YAAAA,OAAkB;EACtC,IAAI,YAAY,GACd,eAAe;OAEf,gBAAgB,KAAK;CAEzB,GAAG;EAAC;EAAgB;EAAW;CAAe,CAAC;CAE/C,MAAM,0BAAA,GAAyBA,MAAAA,YAAAA,EAAa,YAA2B;EACrE,MAAM,gBAAgB,mBAAmB;EAEzC,IAAI,CAAC,eACH;EAGF,cAAc,oBAAoB,aAAa,OAAO;EACtD,cAAc,oBAAoB,iBAAiB,OAAO;EAE1D,mBAAmB,UAAU;CAC/B,GAAG,CAAC,CAAC;CAEL,MAAM,2BAAA,GAA0BA,MAAAA,YAAAA,OAAkB;EAChD,uBAAuB,uBAAuB;EAC9C,eAAe;CACjB,GAAG,CAAC,gBAAgB,sBAAsB,CAAC;CAE3C,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,WAAW,IAAI;CACjB,GAAG,CAAC,CAAC;CAEL,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,aAAa;GACX,eAAe,OAAO;GACtB,uBAAuB,uBAAuB;EAChD;CACF,GAAG;EAAC;EAAgB;EAAyB;CAAsB,CAAC;CAEpE,MAAM,oBAAA,GAAmBA,MAAAA,YAAAA,EACtB,SAA6B;EAC5B,UAAU,UAAU;EACpB,iBAAiB,IAAI;EAErB,mBACE,aACI,WAAW,eACV,MAAM,cAAc,QAAQ,IACnC;EAEA,OAAO,QAAQ,MAAM,KAAK,IAAI;CAChC,GACA,CAAC,SAAS,UAAU,CACtB;CAEA,MAAM,oBAAA,GAAmBA,MAAAA,YAAAA,EAAa,SAAgC;EACpE,WAAW,UAAU;EACrB,kBAAkB,IAAI;CACxB,GAAG,CAAC,CAAC;CAEL,MAAM,EACJ,OAAO,eACP,WACA,iBACEG,8BAAAA,oBAAoB;EACtB,QAAQ;EACR,SAAS;EACT,SAAS,WAAW;EACpB;EACA;EACA;EACA;EACA;CACF,CAAC;CAGD,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,IAAI,CAAC,UAAU,CAAC,uBAAuB,CAAC,iBACtC;EAGF,MAAM,gBAAgB,eAAe;EACrC,MAAM,cAAc,eAAe;EAEnC,IAAI,CAAC,iBAAiB,CAAC,aACrB;EAGF,MAAM,qBAAqB,UAAmC;GAC5D,MAAM,SAAS,MAAM;GAErB,IAAI,EAAE,kBAAkB,YAAY,OAClC;GAGF,IACE,UAAU,SAAS,SAAS,MAAM,KAClC,WAAW,SAAS,SAAS,MAAM,GAEnC;GAGF,qBAAqB;GACrB,gBAAgB,KAAK;EACvB;EAEA,cAAc,iBAAiB,eAAe,iBAAiB;EAE/D,aAAa;GACX,cAAc,oBAAoB,eAAe,iBAAiB;EACpE;CACF,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAGD,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,IAAI,CAAC,UAAU,CAAC,mBAAmB,CAAC,eAClC;EAGF,MAAM,gBAAgB,cAAc;EAEpC,OAAOC,gBAAAA,gBAAgB,qBAAqB;GAC1C,IAAI,CAAC,eACH;GAGF,qBAAqB;GACrB,gBAAgB,KAAK;GAErB,IAAI,WAAW,SAAS,SAAS,cAAc,aAAa,GAC1D,UAAU,SAAS,MAAM,EAAE,eAAe,KAAK,CAAC;EAEpD,CAAC;CACH,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,sBAAsB,UAAqC;EAC/D,QAAQ,MAAM,iBAAiB,KAAK;EAEpC,IAAI,WAAW,SACb;EAGF,qBAAqB;EACrB,gBAAgB,IAAI;CACtB;CAEA,MAAM,sBAAsB,UAAqC;EAC/D,QAAQ,MAAM,iBAAiB,KAAK;EAEpC,IAAI,WAAW,SACb;EAGF,cAAc;CAChB;CAEA,MAAM,mBAAmB,UAAqC;EAC5D,QAAQ,MAAM,cAAc,KAAK;CACnC;CAEA,MAAM,qBAAqB,UAAqC;EAC9D,QAAQ,MAAM,gBAAgB,KAAK;EAEnC,IAAI,WAAW,UAAU,MAAM,kBAC7B;EAGF,gBAAgB,IAAI;EAEpB,MAAM,gBAAgB,MAAM,cAAc;EAE1C,uBAAuB,uBAAuB;EAE9C,mBAAmB,UAAU;EAE7B,cAAc,iBAAiB,aAAa,uBAAuB;EACnE,cAAc,iBAAiB,iBAAiB,uBAAuB;CACzE;CAEA,MAAM,eAAe,UAAmC;EACtD,QAAQ,MAAM,UAAU,KAAK;EAE7B,IAAI,WAAW,WAAW,MAAM,kBAC9B;EAGF,gBAAgB,gBAAgB,CAAC,SAAS,IAAI;CAChD;CAEA,MAAM,kBAAA,GAAiBC,MAAAA,aAAAA,CAAa,SAAS;EAC3C,KAAK;EACL,YAAA,GAAWC,gBAAAA,GAAAA,CAAG,QAAQ,MAAM,WAAW,SAAS;EAChD,gBAAgB;EAChB,gBAAgB;EAChB,eAAe;EACf,aAAa;EACb,SAAS;CACX,CAAC;CAED,IAAI,CAAC,SACH,OAAO;CAGT,MAAM,eAA8B;EAClC,GAAI,iBAAiB,CAAC;EACtB,YAAY,eAAe,YAAY;EACvC,eAAe,UAAU,eAAe,SAAS;CACnD;CAEA,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA,CACG,gBAEA,oBAAA,GACCC,UAAAA,aAAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAACC,cAAAA,YAAD;EACE,SAAS;EACT,UAAS;EACT,UAAU;EACV,eAAA;EAEA,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;GACE,KAAK;GACL,YAAA,GAAWF,gBAAAA,GAAAA,CAAG,0BAA0B,gBAAgB;GACxD,kBAAgB;GAChB,OAAO;GACP,gBACE,WAAW,UAAU,uBAAuB,KAAA;GAE9C,gBAAgB,WAAW,UAAU,gBAAgB,KAAA;GAErD,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,wBAAwB,UAAzB;IAAkC,OAAO;IACtC;GAC+B,CAAA;EAC/B,CAAA;CACK,CAAA,GACZ,eACF,CACF,EAAA,CAAA;AAEN"}
@@ -4,11 +4,13 @@ import { registerOverlay } from "../overlay-stack/index.js";
4
4
  import { useFloatingPosition } from "../floating-position/use-floating-position.js";
5
5
  import "./popout.css";
6
6
  import { cn, debounce } from "@puzzle-ui/core";
7
- import { cloneElement, useCallback, useEffect, useMemo, useRef, useState } from "react";
7
+ import { cloneElement, createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
8
8
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
9
9
  import { createPortal } from "react-dom";
10
10
  import { useThemeScope } from "@puzzle-ui/theme/scope-context";
11
11
  // src/components/overlays/popout/index.tsx
12
+ const PopoutPositionedContext = createContext(true);
13
+ const usePopoutPositioned = () => useContext(PopoutPositionedContext);
12
14
  const setRef = (ref, value) => {
13
15
  if (typeof ref === "function") ref(value);
14
16
  else if (ref) ref.current = value;
@@ -181,10 +183,13 @@ const Popout = ({ trigger, children, position = "bottom", align = "start", actio
181
183
  style: contentStyle,
182
184
  onPointerEnter: action === "hover" ? cancelDebouncedClose : void 0,
183
185
  onPointerLeave: action === "hover" ? scheduleClose : void 0,
184
- children
186
+ children: /* @__PURE__ */ jsx(PopoutPositionedContext.Provider, {
187
+ value: isPositioned,
188
+ children
189
+ })
185
190
  })
186
191
  }), portalContainer)] });
187
192
  };
188
- export { Popout };
193
+ export { Popout, usePopoutPositioned };
189
194
 
190
195
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/overlays/popout/index.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n cloneElement,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type HTMLAttributes,\n type MouseEvent,\n type PointerEvent,\n type ReactElement,\n type ReactNode,\n type Ref,\n type RefAttributes,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport { cn, debounce } from \"@puzzle-ui/core\";\nimport { useThemeScope } from \"@puzzle-ui/theme/scope-context\";\n\nimport { Transition } from \"../../utilities/transition\";\nimport { registerOverlay } from \"../overlay-stack\";\nimport { useFloatingPosition } from \"../floating-position\";\n\nimport \"./popout.css\";\n\ntype PopoutPosition = \"top\" | \"right\" | \"bottom\" | \"left\";\n\ntype PopoutAlignment = \"start\" | \"center\" | \"end\";\n\ntype PopoutAction = \"hover\" | \"click\" | \"down\";\n\ntype PopoutTriggerProps = HTMLAttributes<HTMLElement> &\n RefAttributes<HTMLElement>;\n\ntype PopoutProps = {\n trigger: ReactElement<PopoutTriggerProps>;\n children: ReactNode;\n position?: PopoutPosition;\n align?: PopoutAlignment;\n action?: PopoutAction;\n offset?: number;\n collisionPadding?: number;\n exitDelay?: number;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n closeOnOutsideClick?: boolean;\n closeOnEscape?: boolean;\n toggleOnClick?: boolean;\n matchTriggerWidth?: boolean;\n className?: string;\n contentClassName?: string;\n};\n\nconst setRef = <T,>(ref: Ref<T> | undefined, value: T | null): void => {\n if (typeof ref === \"function\") {\n ref(value);\n } else if (ref) {\n ref.current = value;\n }\n};\n\nconst Popout = ({\n trigger,\n children,\n position = \"bottom\",\n align = \"start\",\n action = \"click\",\n offset = 8,\n collisionPadding = 8,\n exitDelay = 150,\n open,\n defaultOpen = false,\n onOpenChange,\n closeOnOutsideClick = true,\n closeOnEscape = true,\n toggleOnClick = false,\n matchTriggerWidth = false,\n className,\n contentClassName,\n}: PopoutProps) => {\n const themeScope = useThemeScope();\n\n const [internalOpen, setInternalOpen] = useState(defaultOpen);\n const [mounted, setMounted] = useState(false);\n\n const [anchorElement, setAnchorElement] = useState<HTMLElement | null>(null);\n\n const [portalContainer, setPortalContainer] = useState<HTMLElement | null>(\n null,\n );\n\n const [contentElement, setContentElement] = useState<HTMLDivElement | null>(\n null,\n );\n\n const anchorRef = useRef<HTMLElement | null>(null);\n const contentRef = useRef<HTMLDivElement | null>(null);\n const pointerDocumentRef = useRef<Document | null>(null);\n\n const isOpen = open ?? internalOpen;\n\n const changeOpenState = useCallback(\n (nextOpen: boolean) => {\n if (open === undefined) {\n setInternalOpen(nextOpen);\n }\n\n onOpenChange?.(nextOpen);\n },\n [open, onOpenChange],\n );\n\n const debouncedClose = useMemo(\n () => debounce(() => changeOpenState(false), Math.max(0, exitDelay)),\n [changeOpenState, exitDelay],\n );\n\n const cancelDebouncedClose = useCallback(() => {\n debouncedClose.cancel();\n }, [debouncedClose]);\n\n const scheduleClose = useCallback(() => {\n if (exitDelay > 0) {\n debouncedClose();\n } else {\n changeOpenState(false);\n }\n }, [debouncedClose, exitDelay, changeOpenState]);\n\n const removePointerListeners = useCallback((handler: EventListener) => {\n const ownerDocument = pointerDocumentRef.current;\n\n if (!ownerDocument) {\n return;\n }\n\n ownerDocument.removeEventListener(\"pointerup\", handler);\n ownerDocument.removeEventListener(\"pointercancel\", handler);\n\n pointerDocumentRef.current = null;\n }, []);\n\n const handleDocumentPointerUp = useCallback(() => {\n removePointerListeners(handleDocumentPointerUp);\n debouncedClose();\n }, [debouncedClose, removePointerListeners]);\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n return () => {\n debouncedClose.cancel();\n removePointerListeners(handleDocumentPointerUp);\n };\n }, [debouncedClose, handleDocumentPointerUp, removePointerListeners]);\n\n const handleTriggerRef = useCallback(\n (node: HTMLElement | null) => {\n anchorRef.current = node;\n setAnchorElement(node);\n\n setPortalContainer(\n themeScope\n ? themeScope.portalTarget\n : (node?.ownerDocument.body ?? null),\n );\n\n setRef(trigger.props.ref, node);\n },\n [trigger, themeScope],\n );\n\n const handleContentRef = useCallback((node: HTMLDivElement | null) => {\n contentRef.current = node;\n setContentElement(node);\n }, []);\n\n const {\n style: positionStyle,\n placement,\n isPositioned,\n } = useFloatingPosition({\n anchor: anchorElement,\n content: contentElement,\n enabled: mounted && isOpen,\n position,\n align,\n offset,\n collisionPadding,\n matchTriggerWidth,\n });\n\n // Outside click\n useEffect(() => {\n if (!isOpen || !closeOnOutsideClick || !portalContainer) {\n return;\n }\n\n const ownerDocument = anchorElement?.ownerDocument;\n const ownerWindow = ownerDocument?.defaultView;\n\n if (!ownerDocument || !ownerWindow) {\n return;\n }\n\n const handlePointerDown = (event: globalThis.PointerEvent) => {\n const target = event.target;\n\n if (!(target instanceof ownerWindow.Node)) {\n return;\n }\n\n if (\n anchorRef.current?.contains(target) ||\n contentRef.current?.contains(target)\n ) {\n return;\n }\n\n cancelDebouncedClose();\n changeOpenState(false);\n };\n\n ownerDocument.addEventListener(\"pointerdown\", handlePointerDown);\n\n return () => {\n ownerDocument.removeEventListener(\"pointerdown\", handlePointerDown);\n };\n }, [\n isOpen,\n closeOnOutsideClick,\n portalContainer,\n anchorElement,\n cancelDebouncedClose,\n changeOpenState,\n ]);\n\n // Escape: only the topmost registered overlay handles the key.\n useEffect(() => {\n if (!isOpen || !portalContainer || !anchorElement) {\n return;\n }\n\n const ownerDocument = anchorElement.ownerDocument;\n\n return registerOverlay(ownerDocument, () => {\n if (!closeOnEscape) {\n return;\n }\n\n cancelDebouncedClose();\n changeOpenState(false);\n\n if (contentRef.current?.contains(ownerDocument.activeElement)) {\n anchorRef.current?.focus({ preventScroll: true });\n }\n });\n }, [\n isOpen,\n portalContainer,\n anchorElement,\n closeOnEscape,\n cancelDebouncedClose,\n changeOpenState,\n ]);\n\n const handlePointerEnter = (event: PointerEvent<HTMLElement>) => {\n trigger.props.onPointerEnter?.(event);\n\n if (action !== \"hover\") {\n return;\n }\n\n cancelDebouncedClose();\n changeOpenState(true);\n };\n\n const handlePointerLeave = (event: PointerEvent<HTMLElement>) => {\n trigger.props.onPointerLeave?.(event);\n\n if (action !== \"hover\") {\n return;\n }\n\n scheduleClose();\n };\n\n const handlePointerUp = (event: PointerEvent<HTMLElement>) => {\n trigger.props.onPointerUp?.(event);\n };\n\n const handlePointerDown = (event: PointerEvent<HTMLElement>) => {\n trigger.props.onPointerDown?.(event);\n\n if (action !== \"down\" || event.defaultPrevented) {\n return;\n }\n\n changeOpenState(true);\n\n const ownerDocument = event.currentTarget.ownerDocument;\n\n removePointerListeners(handleDocumentPointerUp);\n\n pointerDocumentRef.current = ownerDocument;\n\n ownerDocument.addEventListener(\"pointerup\", handleDocumentPointerUp);\n ownerDocument.addEventListener(\"pointercancel\", handleDocumentPointerUp);\n };\n\n const handleClick = (event: MouseEvent<HTMLElement>) => {\n trigger.props.onClick?.(event);\n\n if (action !== \"click\" || event.defaultPrevented) {\n return;\n }\n\n changeOpenState(toggleOnClick ? !isOpen : true);\n };\n\n const triggerElement = cloneElement(trigger, {\n ref: handleTriggerRef,\n className: cn(trigger.props.className, className),\n onPointerEnter: handlePointerEnter,\n onPointerLeave: handlePointerLeave,\n onPointerDown: handlePointerDown,\n onPointerUp: handlePointerUp,\n onClick: handleClick,\n });\n\n if (!mounted) {\n return triggerElement;\n }\n\n const contentStyle: CSSProperties = {\n ...(positionStyle ?? {}),\n visibility: isPositioned ? \"visible\" : \"hidden\",\n pointerEvents: isOpen && isPositioned ? \"auto\" : \"none\",\n };\n\n return (\n <>\n {triggerElement}\n\n {portalContainer &&\n createPortal(\n <Transition\n visible={isOpen}\n template=\"fade\"\n duration={200}\n unmountOnExit\n >\n <div\n ref={handleContentRef}\n className={cn(\"puzzle-popout__content\", contentClassName)}\n data-placement={placement}\n style={contentStyle}\n onPointerEnter={\n action === \"hover\" ? cancelDebouncedClose : undefined\n }\n onPointerLeave={action === \"hover\" ? scheduleClose : undefined}\n >\n {children}\n </div>\n </Transition>,\n portalContainer,\n )}\n </>\n );\n};\n\nexport {\n Popout,\n type PopoutProps,\n type PopoutPosition,\n type PopoutAlignment,\n type PopoutAction,\n type PopoutTriggerProps,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/overlays/popout/index.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n cloneElement,\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type HTMLAttributes,\n type MouseEvent,\n type PointerEvent,\n type ReactElement,\n type ReactNode,\n type Ref,\n type RefAttributes,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport { cn, debounce } from \"@puzzle-ui/core\";\nimport { useThemeScope } from \"@puzzle-ui/theme/scope-context\";\n\nimport { Transition } from \"../../utilities/transition\";\nimport { registerOverlay } from \"../overlay-stack\";\nimport { useFloatingPosition } from \"../floating-position\";\n\nimport \"./popout.css\";\n\n// Content is hidden, and therefore unfocusable, until it has been positioned.\nconst PopoutPositionedContext = createContext(true);\n\nconst usePopoutPositioned = (): boolean => useContext(PopoutPositionedContext);\n\ntype PopoutPosition = \"top\" | \"right\" | \"bottom\" | \"left\";\n\ntype PopoutAlignment = \"start\" | \"center\" | \"end\";\n\ntype PopoutAction = \"hover\" | \"click\" | \"down\";\n\ntype PopoutTriggerProps = HTMLAttributes<HTMLElement> &\n RefAttributes<HTMLElement>;\n\ntype PopoutProps = {\n trigger: ReactElement<PopoutTriggerProps>;\n children: ReactNode;\n position?: PopoutPosition;\n align?: PopoutAlignment;\n action?: PopoutAction;\n offset?: number;\n collisionPadding?: number;\n exitDelay?: number;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n closeOnOutsideClick?: boolean;\n closeOnEscape?: boolean;\n toggleOnClick?: boolean;\n matchTriggerWidth?: boolean;\n className?: string;\n contentClassName?: string;\n};\n\nconst setRef = <T,>(ref: Ref<T> | undefined, value: T | null): void => {\n if (typeof ref === \"function\") {\n ref(value);\n } else if (ref) {\n ref.current = value;\n }\n};\n\nconst Popout = ({\n trigger,\n children,\n position = \"bottom\",\n align = \"start\",\n action = \"click\",\n offset = 8,\n collisionPadding = 8,\n exitDelay = 150,\n open,\n defaultOpen = false,\n onOpenChange,\n closeOnOutsideClick = true,\n closeOnEscape = true,\n toggleOnClick = false,\n matchTriggerWidth = false,\n className,\n contentClassName,\n}: PopoutProps) => {\n const themeScope = useThemeScope();\n\n const [internalOpen, setInternalOpen] = useState(defaultOpen);\n const [mounted, setMounted] = useState(false);\n\n const [anchorElement, setAnchorElement] = useState<HTMLElement | null>(null);\n\n const [portalContainer, setPortalContainer] = useState<HTMLElement | null>(\n null,\n );\n\n const [contentElement, setContentElement] = useState<HTMLDivElement | null>(\n null,\n );\n\n const anchorRef = useRef<HTMLElement | null>(null);\n const contentRef = useRef<HTMLDivElement | null>(null);\n const pointerDocumentRef = useRef<Document | null>(null);\n\n const isOpen = open ?? internalOpen;\n\n const changeOpenState = useCallback(\n (nextOpen: boolean) => {\n if (open === undefined) {\n setInternalOpen(nextOpen);\n }\n\n onOpenChange?.(nextOpen);\n },\n [open, onOpenChange],\n );\n\n const debouncedClose = useMemo(\n () => debounce(() => changeOpenState(false), Math.max(0, exitDelay)),\n [changeOpenState, exitDelay],\n );\n\n const cancelDebouncedClose = useCallback(() => {\n debouncedClose.cancel();\n }, [debouncedClose]);\n\n const scheduleClose = useCallback(() => {\n if (exitDelay > 0) {\n debouncedClose();\n } else {\n changeOpenState(false);\n }\n }, [debouncedClose, exitDelay, changeOpenState]);\n\n const removePointerListeners = useCallback((handler: EventListener) => {\n const ownerDocument = pointerDocumentRef.current;\n\n if (!ownerDocument) {\n return;\n }\n\n ownerDocument.removeEventListener(\"pointerup\", handler);\n ownerDocument.removeEventListener(\"pointercancel\", handler);\n\n pointerDocumentRef.current = null;\n }, []);\n\n const handleDocumentPointerUp = useCallback(() => {\n removePointerListeners(handleDocumentPointerUp);\n debouncedClose();\n }, [debouncedClose, removePointerListeners]);\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n return () => {\n debouncedClose.cancel();\n removePointerListeners(handleDocumentPointerUp);\n };\n }, [debouncedClose, handleDocumentPointerUp, removePointerListeners]);\n\n const handleTriggerRef = useCallback(\n (node: HTMLElement | null) => {\n anchorRef.current = node;\n setAnchorElement(node);\n\n setPortalContainer(\n themeScope\n ? themeScope.portalTarget\n : (node?.ownerDocument.body ?? null),\n );\n\n setRef(trigger.props.ref, node);\n },\n [trigger, themeScope],\n );\n\n const handleContentRef = useCallback((node: HTMLDivElement | null) => {\n contentRef.current = node;\n setContentElement(node);\n }, []);\n\n const {\n style: positionStyle,\n placement,\n isPositioned,\n } = useFloatingPosition({\n anchor: anchorElement,\n content: contentElement,\n enabled: mounted && isOpen,\n position,\n align,\n offset,\n collisionPadding,\n matchTriggerWidth,\n });\n\n // Outside click\n useEffect(() => {\n if (!isOpen || !closeOnOutsideClick || !portalContainer) {\n return;\n }\n\n const ownerDocument = anchorElement?.ownerDocument;\n const ownerWindow = ownerDocument?.defaultView;\n\n if (!ownerDocument || !ownerWindow) {\n return;\n }\n\n const handlePointerDown = (event: globalThis.PointerEvent) => {\n const target = event.target;\n\n if (!(target instanceof ownerWindow.Node)) {\n return;\n }\n\n if (\n anchorRef.current?.contains(target) ||\n contentRef.current?.contains(target)\n ) {\n return;\n }\n\n cancelDebouncedClose();\n changeOpenState(false);\n };\n\n ownerDocument.addEventListener(\"pointerdown\", handlePointerDown);\n\n return () => {\n ownerDocument.removeEventListener(\"pointerdown\", handlePointerDown);\n };\n }, [\n isOpen,\n closeOnOutsideClick,\n portalContainer,\n anchorElement,\n cancelDebouncedClose,\n changeOpenState,\n ]);\n\n // Escape: only the topmost registered overlay handles the key.\n useEffect(() => {\n if (!isOpen || !portalContainer || !anchorElement) {\n return;\n }\n\n const ownerDocument = anchorElement.ownerDocument;\n\n return registerOverlay(ownerDocument, () => {\n if (!closeOnEscape) {\n return;\n }\n\n cancelDebouncedClose();\n changeOpenState(false);\n\n if (contentRef.current?.contains(ownerDocument.activeElement)) {\n anchorRef.current?.focus({ preventScroll: true });\n }\n });\n }, [\n isOpen,\n portalContainer,\n anchorElement,\n closeOnEscape,\n cancelDebouncedClose,\n changeOpenState,\n ]);\n\n const handlePointerEnter = (event: PointerEvent<HTMLElement>) => {\n trigger.props.onPointerEnter?.(event);\n\n if (action !== \"hover\") {\n return;\n }\n\n cancelDebouncedClose();\n changeOpenState(true);\n };\n\n const handlePointerLeave = (event: PointerEvent<HTMLElement>) => {\n trigger.props.onPointerLeave?.(event);\n\n if (action !== \"hover\") {\n return;\n }\n\n scheduleClose();\n };\n\n const handlePointerUp = (event: PointerEvent<HTMLElement>) => {\n trigger.props.onPointerUp?.(event);\n };\n\n const handlePointerDown = (event: PointerEvent<HTMLElement>) => {\n trigger.props.onPointerDown?.(event);\n\n if (action !== \"down\" || event.defaultPrevented) {\n return;\n }\n\n changeOpenState(true);\n\n const ownerDocument = event.currentTarget.ownerDocument;\n\n removePointerListeners(handleDocumentPointerUp);\n\n pointerDocumentRef.current = ownerDocument;\n\n ownerDocument.addEventListener(\"pointerup\", handleDocumentPointerUp);\n ownerDocument.addEventListener(\"pointercancel\", handleDocumentPointerUp);\n };\n\n const handleClick = (event: MouseEvent<HTMLElement>) => {\n trigger.props.onClick?.(event);\n\n if (action !== \"click\" || event.defaultPrevented) {\n return;\n }\n\n changeOpenState(toggleOnClick ? !isOpen : true);\n };\n\n const triggerElement = cloneElement(trigger, {\n ref: handleTriggerRef,\n className: cn(trigger.props.className, className),\n onPointerEnter: handlePointerEnter,\n onPointerLeave: handlePointerLeave,\n onPointerDown: handlePointerDown,\n onPointerUp: handlePointerUp,\n onClick: handleClick,\n });\n\n if (!mounted) {\n return triggerElement;\n }\n\n const contentStyle: CSSProperties = {\n ...(positionStyle ?? {}),\n visibility: isPositioned ? \"visible\" : \"hidden\",\n pointerEvents: isOpen && isPositioned ? \"auto\" : \"none\",\n };\n\n return (\n <>\n {triggerElement}\n\n {portalContainer &&\n createPortal(\n <Transition\n visible={isOpen}\n template=\"fade\"\n duration={200}\n unmountOnExit\n >\n <div\n ref={handleContentRef}\n className={cn(\"puzzle-popout__content\", contentClassName)}\n data-placement={placement}\n style={contentStyle}\n onPointerEnter={\n action === \"hover\" ? cancelDebouncedClose : undefined\n }\n onPointerLeave={action === \"hover\" ? scheduleClose : undefined}\n >\n <PopoutPositionedContext.Provider value={isPositioned}>\n {children}\n </PopoutPositionedContext.Provider>\n </div>\n </Transition>,\n portalContainer,\n )}\n </>\n );\n};\n\nexport {\n Popout,\n usePopoutPositioned,\n type PopoutProps,\n type PopoutPosition,\n type PopoutAlignment,\n type PopoutAction,\n type PopoutTriggerProps,\n};\n"],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -35,25 +35,26 @@ const require_index$25 = require("./components/layout/breadcrumbs/index.cjs");
35
35
  const require_index$26 = require("./components/layout/collapsable-sidebar/index.cjs");
36
36
  const require_index$27 = require("./components/layout/container/index.cjs");
37
37
  const require_index$28 = require("./components/layout/page-layout/index.cjs");
38
- const require_index$29 = require("./components/layout/section/index.cjs");
39
- const require_index$30 = require("./components/layout/section-stack/index.cjs");
40
- const require_index$31 = require("./components/layout/sidebar/index.cjs");
41
- const require_index$32 = require("./components/layout/stack/index.cjs");
42
- const require_index$33 = require("./components/navigation/accordion/index.cjs");
43
- const require_index$34 = require("./components/navigation/carousel/index.cjs");
38
+ const require_index$29 = require("./components/layout/resizable-panels/index.cjs");
39
+ const require_index$30 = require("./components/layout/section/index.cjs");
40
+ const require_index$31 = require("./components/layout/section-stack/index.cjs");
41
+ const require_index$32 = require("./components/layout/sidebar/index.cjs");
42
+ const require_index$33 = require("./components/layout/stack/index.cjs");
43
+ const require_index$34 = require("./components/navigation/accordion/index.cjs");
44
+ const require_index$35 = require("./components/navigation/carousel/index.cjs");
44
45
  const require_controller = require("./components/navigation/carousel/controller.cjs");
45
- const require_index$35 = require("./components/navigation/link/index.cjs");
46
- const require_index$36 = require("./components/navigation/tabs/index.cjs");
47
- const require_index$37 = require("./components/navigation/tree-view/index.cjs");
48
- const require_index$38 = require("./components/overlays/backdrop/index.cjs");
49
- const require_index$39 = require("./components/overlays/command/index.cjs");
50
- const require_index$40 = require("./components/overlays/dialog/index.cjs");
51
- const require_index$41 = require("./components/overlays/drawer/index.cjs");
52
- const require_index$42 = require("./components/overlays/dropdown-menu/index.cjs");
53
- const require_index$43 = require("./components/overlays/notification/index.cjs");
54
- const require_index$44 = require("./components/overlays/popout/index.cjs");
55
- const require_index$45 = require("./components/overlays/portal/index.cjs");
56
- const require_index$46 = require("./components/overlays/popover/index.cjs");
46
+ const require_index$36 = require("./components/navigation/link/index.cjs");
47
+ const require_index$37 = require("./components/navigation/tabs/index.cjs");
48
+ const require_index$38 = require("./components/navigation/tree-view/index.cjs");
49
+ const require_index$39 = require("./components/overlays/backdrop/index.cjs");
50
+ const require_index$40 = require("./components/overlays/command/index.cjs");
51
+ const require_index$41 = require("./components/overlays/dialog/index.cjs");
52
+ const require_index$42 = require("./components/overlays/drawer/index.cjs");
53
+ const require_index$43 = require("./components/overlays/dropdown-menu/index.cjs");
54
+ const require_index$44 = require("./components/overlays/notification/index.cjs");
55
+ const require_index$45 = require("./components/overlays/popout/index.cjs");
56
+ const require_index$46 = require("./components/overlays/portal/index.cjs");
57
+ const require_index$47 = require("./components/overlays/popover/index.cjs");
57
58
  const require_dropdown_menu_content = require("./components/overlays/dropdown-menu/dropdown-menu-content.cjs");
58
59
  const require_dropdown_menu_trigger = require("./components/overlays/dropdown-menu/dropdown-menu-trigger.cjs");
59
60
  const require_dropdown_menu_items = require("./components/overlays/dropdown-menu/dropdown-menu-items.cjs");
@@ -61,18 +62,18 @@ const require_dropdown_menu_radio = require("./components/overlays/dropdown-menu
61
62
  const require_target = require("./components/overlays/portal/target.cjs");
62
63
  const require_notification_provider = require("./components/overlays/notification/notification-provider.cjs");
63
64
  const require_use_notification = require("./components/overlays/notification/use-notification.cjs");
64
- const require_index$47 = require("./components/overlays/tooltip/index.cjs");
65
+ const require_index$48 = require("./components/overlays/tooltip/index.cjs");
65
66
  const require_text = require("./components/typography/text.cjs");
66
67
  const require_heading = require("./components/typography/heading.cjs");
67
- const require_index$48 = require("./components/utilities/preview/index.cjs");
68
- const require_index$49 = require("./components/utilities/scroll-lock/index.cjs");
69
- const require_index$50 = require("./components/utilities/transition/index.cjs");
70
- exports.Accordion = require_index$33.Accordion;
68
+ const require_index$49 = require("./components/utilities/preview/index.cjs");
69
+ const require_index$50 = require("./components/utilities/scroll-lock/index.cjs");
70
+ const require_index$51 = require("./components/utilities/transition/index.cjs");
71
+ exports.Accordion = require_index$34.Accordion;
71
72
  exports.Alert = require_index$3.Alert;
72
73
  exports.AppBar = require_index$22.AppBar;
73
74
  exports.Autocomplete = require_index$11.Autocomplete;
74
75
  exports.Avatar = require_index$4.Avatar;
75
- exports.Backdrop = require_index$38.Backdrop;
76
+ exports.Backdrop = require_index$39.Backdrop;
76
77
  exports.Background = require_index$23.Background;
77
78
  exports.Badge = require_index$5.Badge;
78
79
  exports.BottomNavigation = require_index$24.BottomNavigation;
@@ -88,18 +89,18 @@ exports.CardFooter = require_index$6.CardFooter;
88
89
  exports.CardHeader = require_index$6.CardHeader;
89
90
  exports.CardMedia = require_index$6.CardMedia;
90
91
  exports.CardTitle = require_index$6.CardTitle;
91
- exports.Carousel = require_index$34.Carousel;
92
+ exports.Carousel = require_index$35.Carousel;
92
93
  exports.CarouselController = require_controller.CarouselController;
93
94
  exports.Checkbox = require_index$12.Checkbox;
94
95
  exports.CircularProgress = require_circular_progress.CircularProgress;
95
96
  exports.CollapsableSidebar = require_index$26.CollapsableSidebar;
96
- exports.Command = require_index$39.Command;
97
- exports.CommandDialog = require_index$39.CommandDialog;
97
+ exports.Command = require_index$40.Command;
98
+ exports.CommandDialog = require_index$40.CommandDialog;
98
99
  exports.Container = require_index$27.Container;
99
100
  exports.DatePicker = require_index$13.DatePicker;
100
- exports.Dialog = require_index$40.Dialog;
101
- exports.Drawer = require_index$41.Drawer;
102
- exports.DropdownMenu = require_index$42.DropdownMenu;
101
+ exports.Dialog = require_index$41.Dialog;
102
+ exports.Drawer = require_index$42.Drawer;
103
+ exports.DropdownMenu = require_index$43.DropdownMenu;
103
104
  exports.DropdownMenuCheckboxItem = require_dropdown_menu_items.DropdownMenuCheckboxItem;
104
105
  exports.DropdownMenuContent = require_dropdown_menu_content.DropdownMenuContent;
105
106
  exports.DropdownMenuGroup = require_dropdown_menu_items.DropdownMenuGroup;
@@ -115,32 +116,35 @@ exports.Heading = require_heading.Heading;
115
116
  exports.Image = require_index$7.Image;
116
117
  exports.Label = require_index$16.Label;
117
118
  exports.LinearProgress = require_linear_progress.LinearProgress;
118
- exports.Link = require_index$35.Link;
119
- exports.Notification = require_index$43.Notification;
119
+ exports.Link = require_index$36.Link;
120
+ exports.Notification = require_index$44.Notification;
120
121
  exports.NotificationProvider = require_notification_provider.NotificationProvider;
121
- exports.NotificationViewport = require_index$43.NotificationViewport;
122
+ exports.NotificationViewport = require_index$44.NotificationViewport;
122
123
  exports.NumberInput = require_number_input.NumberInput;
123
124
  exports.PageLayout = require_index$28.PageLayout;
124
125
  exports.Paper = require_index$8.Paper;
125
- exports.Popout = require_index$44.Popout;
126
- exports.Popover = require_index$46.Popover;
127
- exports.Portal = require_index$45.Portal;
126
+ exports.Popout = require_index$45.Popout;
127
+ exports.Popover = require_index$47.Popover;
128
+ exports.Portal = require_index$46.Portal;
128
129
  exports.PortalTarget = require_target.PortalTarget;
129
- exports.Preview = require_index$48.Preview;
130
+ exports.Preview = require_index$49.Preview;
130
131
  exports.Radio = require_index$17.Radio;
131
132
  exports.RadioGroup = require_index$17.RadioGroup;
132
- exports.ScrollLock = require_index$49.ScrollLock;
133
- exports.Section = require_index$29.Section;
134
- exports.SectionStack = require_index$30.SectionStack;
133
+ exports.ResizableHandle = require_index$29.ResizableHandle;
134
+ exports.ResizablePanel = require_index$29.ResizablePanel;
135
+ exports.ResizablePanels = require_index$29.ResizablePanels;
136
+ exports.ScrollLock = require_index$50.ScrollLock;
137
+ exports.Section = require_index$30.Section;
138
+ exports.SectionStack = require_index$31.SectionStack;
135
139
  exports.Select = require_index$18.Select;
136
- exports.Sidebar = require_index$31.Sidebar;
140
+ exports.Sidebar = require_index$32.Sidebar;
137
141
  exports.Skeleton = require_index$9.Skeleton;
138
142
  exports.Slider = require_index$19.Slider;
139
- exports.Stack = require_index$32.Stack;
143
+ exports.Stack = require_index$33.Stack;
140
144
  exports.Stepper = require_index$20.Stepper;
141
145
  exports.Switch = require_index$21.Switch;
142
- exports.Tabs = require_index$36.Tabs;
143
- exports.TabsTab = require_index$36.TabsTab;
146
+ exports.Tabs = require_index$37.Tabs;
147
+ exports.TabsTab = require_index$37.TabsTab;
144
148
  exports.Text = require_text.Text;
145
149
  exports.TextAreaInput = require_text_area_input.TextAreaInput;
146
150
  exports.TextEditor = require_index$10.TextEditor;
@@ -148,8 +152,8 @@ exports.TextEditorToolbar = require_text_editor_toolbar.TextEditorToolbar;
148
152
  exports.TextInput = require_text_input.TextInput;
149
153
  exports.TextRenderer = require_text_renderer.TextRenderer;
150
154
  exports.ToggleGroup = require_index$2.ToggleGroup;
151
- exports.Tooltip = require_index$47.Tooltip;
152
- exports.Transition = require_index$50.Transition;
153
- exports.TreeView = require_index$37.TreeView;
155
+ exports.Tooltip = require_index$48.Tooltip;
156
+ exports.Transition = require_index$51.Transition;
157
+ exports.TreeView = require_index$38.TreeView;
154
158
  exports.useCarouselContext = require_controller.useCarouselContext;
155
159
  exports.useNotification = require_use_notification.useNotification;
package/dist/index.d.cts CHANGED
@@ -46,6 +46,7 @@ import { BreadcrumbItem, Breadcrumbs, BreadcrumbsProps } from "./components/layo
46
46
  import { CollapsableSidebar, CollapsableSidebarEntry, CollapsableSidebarExpansion, CollapsableSidebarGroup, CollapsableSidebarItem, CollapsableSidebarProps, SidebarItemBase, WithClickHandler, WithLink } from "./components/layout/collapsable-sidebar/index.cjs";
47
47
  import { Container, ContainerProps } from "./components/layout/container/index.cjs";
48
48
  import { PageLayout, PageLayoutProps, SidebarPlacement } from "./components/layout/page-layout/index.cjs";
49
+ import { ResizableHandle, ResizableHandleProps, ResizablePanel, ResizablePanelProps, ResizablePanels, ResizablePanelsOrientation, ResizablePanelsProps } from "./components/layout/resizable-panels/index.cjs";
49
50
  import { Section } from "./components/layout/section/index.cjs";
50
51
  import { SectionProps, SectionTheme } from "./components/layout/section/types.cjs";
51
52
  import { SectionStack, SectionStackProps } from "./components/layout/section-stack/index.cjs";
@@ -82,4 +83,4 @@ import { Heading, HeadingLevel, HeadingProps } from "./components/typography/hea
82
83
  import { Preview, PreviewAlign, PreviewDevice, PreviewJustify, PreviewProps } from "./components/utilities/preview/index.cjs";
83
84
  import { ScrollLock, ScrollLockProps } from "./components/utilities/scroll-lock/index.cjs";
84
85
  import { Transition, TransitionPhase, TransitionProps, TransitionTemplate } from "./components/utilities/transition/index.cjs";
85
- export { Accordion, type AccordionItemData, type AccordionItemId, type AccordionProps, type AccordionType, type AccordionValue, Alert, type AlertProps, type AlertSeverity, type AlertVariant, type AnchorOrigin, type AnchorOverlap, AppBar, type AppBarNavigationItem, type AppBarProps, Autocomplete, type AutocompleteInputChangeReason, type AutocompleteMultipleProps, type AutocompleteOption, type AutocompleteOptionRenderState, type AutocompleteProps, type AutocompleteSingleProps, type AutocompleteSize, type AutocompleteValue, Avatar, type AvatarProps, type AvatarShape, Backdrop, type BackdropProps, Background, type BackgroundFade, type BackgroundMeshColors, type BackgroundPattern, type BackgroundProps, Badge, type BadgeColor, type BadgeProps, BottomNavigation, BottomNavigationItem, type BottomNavigationItemProps, type BottomNavigationProps, type BreadcrumbItem, Breadcrumbs, type BreadcrumbsProps, Button, ButtonGroup, type ButtonGroupProps, type ButtonProps, type ButtonSize, type ButtonVariant, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardMedia, type CardOrientation, type CardPartProps, type CardProps, type CardSize, CardTitle, type CardVariant, Carousel, type CarouselAlignment, type CarouselAlignmentConfig, type CarouselButtonAlignment, type CarouselContextValue, CarouselController, type CarouselControllerProps, type CarouselPagerAlignment, type CarouselProps, Checkbox, type CheckboxProps, type CheckboxSize, CircularProgress, type CircularProgressProps, type CircularProgressSize, CollapsableSidebar, type CollapsableSidebarEntry, type CollapsableSidebarExpansion, type CollapsableSidebarGroup, type CollapsableSidebarItem, type CollapsableSidebarProps, Command, CommandDialog, type CommandDialogProps, type CommandItem, type CommandProps, Container, type ContainerProps, DatePicker, type DatePickerProps, type DatePickerSize, Dialog, type DialogProps, Drawer, type DrawerProps, CompoundDropdownMenu as DropdownMenu, type DropdownMenuAlignment, DropdownMenuCheckboxItem, type DropdownMenuCheckboxItemProps, type DropdownMenuCheckedState, DropdownMenuContent, type DropdownMenuContentProps, DropdownMenuGroup, type DropdownMenuGroupProps, DropdownMenuItem, type DropdownMenuItemProps, type DropdownMenuItemVariant, DropdownMenuLabel, type DropdownMenuLabelProps, type DropdownMenuPosition, type DropdownMenuProps, DropdownMenuRadioGroup, type DropdownMenuRadioGroupProps, DropdownMenuRadioItem, type DropdownMenuRadioItemProps, DropdownMenuSeparator, type DropdownMenuSeparatorProps, DropdownMenuTrigger, type DropdownMenuTriggerProps, FileUpload, type FileUploadItem, type FileUploadProps, type FileUploadRejection, type FileUploadRejectionCode, type FileUploadStatus, type FileUploadUploadContext, type FileUploadUploadHandler, FormField, type FormFieldProps, Heading, type HeadingLevel, type HeadingProps, Image, type ImageFit, type ImagePlaceholder, type ImageProps, type ImageRadius, type ImageSource, type ImageSourceData, type ImageSourceSet, Label, type LabelProps, LinearProgress, type LinearProgressProps, Link, type LinkProps, Notification, type NotificationAction, type NotificationInput, type NotificationItem, type NotificationOptions, type NotificationPosition, type NotificationProps, NotificationProvider, type NotificationProviderProps, type NotificationSeverity, NotificationViewport, type NotificationViewportProps, NumberInput, type NumberInputProps, PageLayout, type PageLayoutProps, type PagerAlignmentConfig, Paper, type PaperProps, Popout, type PopoutAction, type PopoutAlignment, type PopoutPosition, type PopoutProps, type PopoutTriggerProps, Popover, type PopoverProps, Portal, type PortalProps, PortalTarget, type PortalTargetProps, Preview, type PreviewAlign, type PreviewDevice, type PreviewJustify, type PreviewProps, type ProgressProps, Radio, RadioGroup, type RadioGroupOrientation, type RadioGroupProps, type RadioGroupSize, type RadioProps, type ResponsiveDirection, ScrollLock, type ScrollLockProps, Section, type SectionProps, SectionStack, type SectionStackProps, type SectionTheme, Select, type SelectMultipleProps, type SelectOption, type SelectProps, type SelectSingleProps, type SelectSize, Sidebar, type SidebarItemBase, type SidebarPlacement, type SidebarProps, Skeleton, type SkeletonProps, type SkeletonRadius, Slider, type SliderMark, type SliderProps, type SliderSize, Stack, type StackCrossAlignment, type StackMainAlignment, type StackProps, Stepper, type StepperOrientation, type StepperProps, type StepperStepProps, Switch, type SwitchProps, type SwitchSize, Tabs, type TabsPosition, type TabsProps, TabsTab, type TabsTabProps, Text, type TextAlign, TextAreaInput, type TextAreaInputProps, type TextBlock, type TextBlockType, type TextBlockVariant, type TextDocument, TextEditor, type TextEditorProps, TextEditorToolbar, type TextEditorToolbarProps, type TextInline, TextInput, type TextInputProps, type TextInputType, type TextListType, type TextMark, type TextPoint, type TextProps, TextRenderer, type TextRendererProps, type TextSelection, type TextType, ToggleGroup, type ToggleGroupItemProps, type ToggleGroupMultipleProps, type ToggleGroupOrientation, type ToggleGroupProps, type ToggleGroupSingleProps, type ToggleGroupSize, Tooltip, type TooltipArrowSide, type TooltipContentProps, type TooltipProps, Transition, type TransitionPhase, type TransitionProps, type TransitionTemplate, TreeView, type TreeViewItem, type TreeViewItemState, type TreeViewProps, type TreeViewSelectionMode, type TreeViewSize, type WithClickHandler, type WithLink, useCarouselContext, useNotification };
86
+ export { Accordion, type AccordionItemData, type AccordionItemId, type AccordionProps, type AccordionType, type AccordionValue, Alert, type AlertProps, type AlertSeverity, type AlertVariant, type AnchorOrigin, type AnchorOverlap, AppBar, type AppBarNavigationItem, type AppBarProps, Autocomplete, type AutocompleteInputChangeReason, type AutocompleteMultipleProps, type AutocompleteOption, type AutocompleteOptionRenderState, type AutocompleteProps, type AutocompleteSingleProps, type AutocompleteSize, type AutocompleteValue, Avatar, type AvatarProps, type AvatarShape, Backdrop, type BackdropProps, Background, type BackgroundFade, type BackgroundMeshColors, type BackgroundPattern, type BackgroundProps, Badge, type BadgeColor, type BadgeProps, BottomNavigation, BottomNavigationItem, type BottomNavigationItemProps, type BottomNavigationProps, type BreadcrumbItem, Breadcrumbs, type BreadcrumbsProps, Button, ButtonGroup, type ButtonGroupProps, type ButtonProps, type ButtonSize, type ButtonVariant, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardMedia, type CardOrientation, type CardPartProps, type CardProps, type CardSize, CardTitle, type CardVariant, Carousel, type CarouselAlignment, type CarouselAlignmentConfig, type CarouselButtonAlignment, type CarouselContextValue, CarouselController, type CarouselControllerProps, type CarouselPagerAlignment, type CarouselProps, Checkbox, type CheckboxProps, type CheckboxSize, CircularProgress, type CircularProgressProps, type CircularProgressSize, CollapsableSidebar, type CollapsableSidebarEntry, type CollapsableSidebarExpansion, type CollapsableSidebarGroup, type CollapsableSidebarItem, type CollapsableSidebarProps, Command, CommandDialog, type CommandDialogProps, type CommandItem, type CommandProps, Container, type ContainerProps, DatePicker, type DatePickerProps, type DatePickerSize, Dialog, type DialogProps, Drawer, type DrawerProps, CompoundDropdownMenu as DropdownMenu, type DropdownMenuAlignment, DropdownMenuCheckboxItem, type DropdownMenuCheckboxItemProps, type DropdownMenuCheckedState, DropdownMenuContent, type DropdownMenuContentProps, DropdownMenuGroup, type DropdownMenuGroupProps, DropdownMenuItem, type DropdownMenuItemProps, type DropdownMenuItemVariant, DropdownMenuLabel, type DropdownMenuLabelProps, type DropdownMenuPosition, type DropdownMenuProps, DropdownMenuRadioGroup, type DropdownMenuRadioGroupProps, DropdownMenuRadioItem, type DropdownMenuRadioItemProps, DropdownMenuSeparator, type DropdownMenuSeparatorProps, DropdownMenuTrigger, type DropdownMenuTriggerProps, FileUpload, type FileUploadItem, type FileUploadProps, type FileUploadRejection, type FileUploadRejectionCode, type FileUploadStatus, type FileUploadUploadContext, type FileUploadUploadHandler, FormField, type FormFieldProps, Heading, type HeadingLevel, type HeadingProps, Image, type ImageFit, type ImagePlaceholder, type ImageProps, type ImageRadius, type ImageSource, type ImageSourceData, type ImageSourceSet, Label, type LabelProps, LinearProgress, type LinearProgressProps, Link, type LinkProps, Notification, type NotificationAction, type NotificationInput, type NotificationItem, type NotificationOptions, type NotificationPosition, type NotificationProps, NotificationProvider, type NotificationProviderProps, type NotificationSeverity, NotificationViewport, type NotificationViewportProps, NumberInput, type NumberInputProps, PageLayout, type PageLayoutProps, type PagerAlignmentConfig, Paper, type PaperProps, Popout, type PopoutAction, type PopoutAlignment, type PopoutPosition, type PopoutProps, type PopoutTriggerProps, Popover, type PopoverProps, Portal, type PortalProps, PortalTarget, type PortalTargetProps, Preview, type PreviewAlign, type PreviewDevice, type PreviewJustify, type PreviewProps, type ProgressProps, Radio, RadioGroup, type RadioGroupOrientation, type RadioGroupProps, type RadioGroupSize, type RadioProps, ResizableHandle, type ResizableHandleProps, ResizablePanel, type ResizablePanelProps, ResizablePanels, type ResizablePanelsOrientation, type ResizablePanelsProps, type ResponsiveDirection, ScrollLock, type ScrollLockProps, Section, type SectionProps, SectionStack, type SectionStackProps, type SectionTheme, Select, type SelectMultipleProps, type SelectOption, type SelectProps, type SelectSingleProps, type SelectSize, Sidebar, type SidebarItemBase, type SidebarPlacement, type SidebarProps, Skeleton, type SkeletonProps, type SkeletonRadius, Slider, type SliderMark, type SliderProps, type SliderSize, Stack, type StackCrossAlignment, type StackMainAlignment, type StackProps, Stepper, type StepperOrientation, type StepperProps, type StepperStepProps, Switch, type SwitchProps, type SwitchSize, Tabs, type TabsPosition, type TabsProps, TabsTab, type TabsTabProps, Text, type TextAlign, TextAreaInput, type TextAreaInputProps, type TextBlock, type TextBlockType, type TextBlockVariant, type TextDocument, TextEditor, type TextEditorProps, TextEditorToolbar, type TextEditorToolbarProps, type TextInline, TextInput, type TextInputProps, type TextInputType, type TextListType, type TextMark, type TextPoint, type TextProps, TextRenderer, type TextRendererProps, type TextSelection, type TextType, ToggleGroup, type ToggleGroupItemProps, type ToggleGroupMultipleProps, type ToggleGroupOrientation, type ToggleGroupProps, type ToggleGroupSingleProps, type ToggleGroupSize, Tooltip, type TooltipArrowSide, type TooltipContentProps, type TooltipProps, Transition, type TransitionPhase, type TransitionProps, type TransitionTemplate, TreeView, type TreeViewItem, type TreeViewItemState, type TreeViewProps, type TreeViewSelectionMode, type TreeViewSize, type WithClickHandler, type WithLink, useCarouselContext, useNotification };