@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.
- package/README.md +81 -0
- package/dist/components/layout/resizable-panels/index.cjs +226 -0
- package/dist/components/layout/resizable-panels/index.cjs.map +1 -0
- package/dist/components/layout/resizable-panels/index.d.cts +59 -0
- package/dist/components/layout/resizable-panels/index.d.ts +59 -0
- package/dist/components/layout/resizable-panels/index.js +224 -0
- package/dist/components/layout/resizable-panels/index.js.map +1 -0
- package/dist/components/layout/resizable-panels/resizable-panels.css +121 -0
- package/dist/components/layout/resizable-panels/resizable-panels.utils.cjs +107 -0
- package/dist/components/layout/resizable-panels/resizable-panels.utils.cjs.map +1 -0
- package/dist/components/layout/resizable-panels/resizable-panels.utils.js +105 -0
- package/dist/components/layout/resizable-panels/resizable-panels.utils.js.map +1 -0
- package/dist/components/overlays/dropdown-menu/dropdown-menu-content.cjs +13 -1
- package/dist/components/overlays/dropdown-menu/dropdown-menu-content.cjs.map +1 -1
- package/dist/components/overlays/dropdown-menu/dropdown-menu-content.js +13 -1
- package/dist/components/overlays/dropdown-menu/dropdown-menu-content.js.map +1 -1
- package/dist/components/overlays/popout/index.cjs +7 -1
- package/dist/components/overlays/popout/index.cjs.map +1 -1
- package/dist/components/overlays/popout/index.js +8 -3
- package/dist/components/overlays/popout/index.js.map +1 -1
- package/dist/index.cjs +51 -47
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- 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
|
-
}, [
|
|
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
|
-
}, [
|
|
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":"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"}
|
|
@@ -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/
|
|
39
|
-
const require_index$30 = require("./components/layout/section
|
|
40
|
-
const require_index$31 = require("./components/layout/
|
|
41
|
-
const require_index$32 = require("./components/layout/
|
|
42
|
-
const require_index$33 = require("./components/
|
|
43
|
-
const require_index$34 = require("./components/navigation/
|
|
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$
|
|
46
|
-
const require_index$
|
|
47
|
-
const require_index$
|
|
48
|
-
const require_index$
|
|
49
|
-
const require_index$
|
|
50
|
-
const require_index$
|
|
51
|
-
const require_index$
|
|
52
|
-
const require_index$
|
|
53
|
-
const require_index$
|
|
54
|
-
const require_index$
|
|
55
|
-
const require_index$
|
|
56
|
-
const require_index$
|
|
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$
|
|
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$
|
|
68
|
-
const require_index$
|
|
69
|
-
const require_index$
|
|
70
|
-
exports.Accordion = require_index$
|
|
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$
|
|
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$
|
|
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$
|
|
97
|
-
exports.CommandDialog = require_index$
|
|
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$
|
|
101
|
-
exports.Drawer = require_index$
|
|
102
|
-
exports.DropdownMenu = require_index$
|
|
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$
|
|
119
|
-
exports.Notification = require_index$
|
|
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$
|
|
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$
|
|
126
|
-
exports.Popover = require_index$
|
|
127
|
-
exports.Portal = require_index$
|
|
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$
|
|
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.
|
|
133
|
-
exports.
|
|
134
|
-
exports.
|
|
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$
|
|
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$
|
|
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$
|
|
143
|
-
exports.TabsTab = require_index$
|
|
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$
|
|
152
|
-
exports.Transition = require_index$
|
|
153
|
-
exports.TreeView = require_index$
|
|
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 };
|