tempest-react-sdk 0.66.0 → 0.67.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/dist/components/BottomSheet/BottomSheet.cjs +1 -1
  2. package/dist/components/BottomSheet/BottomSheet.cjs.map +1 -1
  3. package/dist/components/BottomSheet/BottomSheet.js +31 -40
  4. package/dist/components/BottomSheet/BottomSheet.js.map +1 -1
  5. package/dist/components/Combobox/Combobox.cjs +1 -1
  6. package/dist/components/Combobox/Combobox.cjs.map +1 -1
  7. package/dist/components/Combobox/Combobox.js +94 -73
  8. package/dist/components/Combobox/Combobox.js.map +1 -1
  9. package/dist/components/Combobox/Combobox.module.cjs +1 -1
  10. package/dist/components/Combobox/Combobox.module.cjs.map +1 -1
  11. package/dist/components/Combobox/Combobox.module.js +4 -3
  12. package/dist/components/Combobox/Combobox.module.js.map +1 -1
  13. package/dist/components/ContextMenu/ContextMenu.cjs +1 -1
  14. package/dist/components/ContextMenu/ContextMenu.cjs.map +1 -1
  15. package/dist/components/ContextMenu/ContextMenu.js +80 -83
  16. package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
  17. package/dist/components/Drawer/Drawer.cjs +1 -1
  18. package/dist/components/Drawer/Drawer.cjs.map +1 -1
  19. package/dist/components/Drawer/Drawer.js +43 -46
  20. package/dist/components/Drawer/Drawer.js.map +1 -1
  21. package/dist/components/DropdownMenu/DropdownMenu.cjs +1 -1
  22. package/dist/components/DropdownMenu/DropdownMenu.cjs.map +1 -1
  23. package/dist/components/DropdownMenu/DropdownMenu.js +129 -105
  24. package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
  25. package/dist/components/DropdownMenu/DropdownMenu.module.cjs +1 -1
  26. package/dist/components/DropdownMenu/DropdownMenu.module.cjs.map +1 -1
  27. package/dist/components/DropdownMenu/DropdownMenu.module.js +12 -11
  28. package/dist/components/DropdownMenu/DropdownMenu.module.js.map +1 -1
  29. package/dist/components/HoverCard/HoverCard.cjs +1 -1
  30. package/dist/components/HoverCard/HoverCard.cjs.map +1 -1
  31. package/dist/components/HoverCard/HoverCard.js +54 -29
  32. package/dist/components/HoverCard/HoverCard.js.map +1 -1
  33. package/dist/components/HoverCard/HoverCard.module.cjs +1 -1
  34. package/dist/components/HoverCard/HoverCard.module.cjs.map +1 -1
  35. package/dist/components/HoverCard/HoverCard.module.js +4 -3
  36. package/dist/components/HoverCard/HoverCard.module.js.map +1 -1
  37. package/dist/components/Lightbox/Lightbox.cjs +1 -1
  38. package/dist/components/Lightbox/Lightbox.cjs.map +1 -1
  39. package/dist/components/Lightbox/Lightbox.js +86 -89
  40. package/dist/components/Lightbox/Lightbox.js.map +1 -1
  41. package/dist/components/Menubar/Menubar.cjs +1 -1
  42. package/dist/components/Menubar/Menubar.cjs.map +1 -1
  43. package/dist/components/Menubar/Menubar.js +86 -65
  44. package/dist/components/Menubar/Menubar.js.map +1 -1
  45. package/dist/components/Menubar/Menubar.module.cjs +1 -1
  46. package/dist/components/Menubar/Menubar.module.cjs.map +1 -1
  47. package/dist/components/Menubar/Menubar.module.js +4 -3
  48. package/dist/components/Menubar/Menubar.module.js.map +1 -1
  49. package/dist/components/Modal/Modal.cjs +1 -1
  50. package/dist/components/Modal/Modal.cjs.map +1 -1
  51. package/dist/components/Modal/Modal.js +44 -51
  52. package/dist/components/Modal/Modal.js.map +1 -1
  53. package/dist/components/MultiSelect/MultiSelect.cjs +1 -1
  54. package/dist/components/MultiSelect/MultiSelect.cjs.map +1 -1
  55. package/dist/components/MultiSelect/MultiSelect.js +113 -96
  56. package/dist/components/MultiSelect/MultiSelect.js.map +1 -1
  57. package/dist/components/MultiSelect/MultiSelect.module.cjs +1 -1
  58. package/dist/components/MultiSelect/MultiSelect.module.cjs.map +1 -1
  59. package/dist/components/MultiSelect/MultiSelect.module.js +4 -3
  60. package/dist/components/MultiSelect/MultiSelect.module.js.map +1 -1
  61. package/dist/components/NavigationMenu/NavigationMenu.cjs +1 -1
  62. package/dist/components/NavigationMenu/NavigationMenu.cjs.map +1 -1
  63. package/dist/components/NavigationMenu/NavigationMenu.js +83 -61
  64. package/dist/components/NavigationMenu/NavigationMenu.js.map +1 -1
  65. package/dist/components/NavigationMenu/NavigationMenu.module.cjs +1 -1
  66. package/dist/components/NavigationMenu/NavigationMenu.module.cjs.map +1 -1
  67. package/dist/components/NavigationMenu/NavigationMenu.module.js +4 -3
  68. package/dist/components/NavigationMenu/NavigationMenu.module.js.map +1 -1
  69. package/dist/components/Popover/Popover.cjs +1 -1
  70. package/dist/components/Popover/Popover.cjs.map +1 -1
  71. package/dist/components/Popover/Popover.js +57 -36
  72. package/dist/components/Popover/Popover.js.map +1 -1
  73. package/dist/components/Popover/Popover.module.cjs +1 -1
  74. package/dist/components/Popover/Popover.module.cjs.map +1 -1
  75. package/dist/components/Popover/Popover.module.js +7 -6
  76. package/dist/components/Popover/Popover.module.js.map +1 -1
  77. package/dist/components/Portal/anchor-position.cjs +2 -0
  78. package/dist/components/Portal/anchor-position.cjs.map +1 -0
  79. package/dist/components/Portal/anchor-position.js +99 -0
  80. package/dist/components/Portal/anchor-position.js.map +1 -0
  81. package/dist/components/Portal/escape-layer.cjs +2 -0
  82. package/dist/components/Portal/escape-layer.cjs.map +1 -0
  83. package/dist/components/Portal/escape-layer.js +30 -0
  84. package/dist/components/Portal/escape-layer.js.map +1 -0
  85. package/dist/components/Portal/tab-bridge.cjs +2 -0
  86. package/dist/components/Portal/tab-bridge.cjs.map +1 -0
  87. package/dist/components/Portal/tab-bridge.js +39 -0
  88. package/dist/components/Portal/tab-bridge.js.map +1 -0
  89. package/dist/components/Tooltip/Tooltip.cjs +1 -1
  90. package/dist/components/Tooltip/Tooltip.cjs.map +1 -1
  91. package/dist/components/Tooltip/Tooltip.js +43 -29
  92. package/dist/components/Tooltip/Tooltip.js.map +1 -1
  93. package/dist/components/Tooltip/Tooltip.module.cjs +1 -1
  94. package/dist/components/Tooltip/Tooltip.module.cjs.map +1 -1
  95. package/dist/components/Tooltip/Tooltip.module.js +4 -3
  96. package/dist/components/Tooltip/Tooltip.module.js.map +1 -1
  97. package/dist/hooks/use-focus-trap.cjs +1 -1
  98. package/dist/hooks/use-focus-trap.cjs.map +1 -1
  99. package/dist/hooks/use-focus-trap.js +2 -2
  100. package/dist/hooks/use-focus-trap.js.map +1 -1
  101. package/dist/hooks/use-sortable.cjs +1 -1
  102. package/dist/hooks/use-sortable.cjs.map +1 -1
  103. package/dist/hooks/use-sortable.js +3 -3
  104. package/dist/hooks/use-sortable.js.map +1 -1
  105. package/dist/http/describe-api-error.cjs +1 -1
  106. package/dist/http/describe-api-error.cjs.map +1 -1
  107. package/dist/http/describe-api-error.js +4 -2
  108. package/dist/http/describe-api-error.js.map +1 -1
  109. package/dist/styles/actions.css +3 -0
  110. package/dist/styles/advanced.css +1 -0
  111. package/dist/styles/component/Combobox.css +1 -0
  112. package/dist/styles/component/DropdownMenu.css +1 -0
  113. package/dist/styles/component/HoverCard.css +1 -0
  114. package/dist/styles/component/Menubar.css +1 -0
  115. package/dist/styles/component/MultiSelect.css +1 -0
  116. package/dist/styles/component/NavigationMenu.css +1 -0
  117. package/dist/styles/component/Popover.css +1 -0
  118. package/dist/styles/component/Tooltip.css +1 -0
  119. package/dist/styles/forms.css +2 -0
  120. package/dist/styles/navigation.css +2 -0
  121. package/dist/styles.css +1 -1
  122. package/dist/tempest-react-sdk.cjs +1 -1
  123. package/dist/tempest-react-sdk.d.ts +147 -13
  124. package/dist/tempest-react-sdk.js +134 -134
  125. package/package.json +1 -1
@@ -1,2 +1,2 @@
1
- const e=require("../../utils/cn.cjs"),t=require("./BottomSheet.module.cjs"),n=require("../Portal/portal-host.cjs");let r=require("react"),i=require("react/jsx-runtime"),a=require("react-dom");function o({open:o,onClose:s,title:c,showHandle:l=!0,dismissOnBackdrop:u=!0,dismissOnEsc:d=!0,className:f,children:p,...m}){(0,r.useEffect)(()=>{if(!o||!d)return;let e=e=>{e.key===`Escape`&&s()};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[o,d,s]),(0,r.useEffect)(()=>{if(!o)return;let e=document.body.style.overflow;return document.body.style.overflow=`hidden`,()=>{document.body.style.overflow=e}},[o]);let h=n.usePortalHost();return!o||!h?null:(0,a.createPortal)((0,i.jsxs)(`div`,{className:t.default.root,role:`dialog`,"aria-modal":`true`,children:[(0,i.jsx)(`div`,{className:t.default.backdrop,onClick:()=>u&&s(),"aria-hidden":`true`}),(0,i.jsxs)(`div`,{className:e.cn(t.default.sheet,f),...m,children:[l&&(0,i.jsx)(`button`,{type:`button`,className:t.default.handle,"aria-label":`Arrastar para fechar`,onClick:s,children:(0,i.jsx)(`span`,{className:t.default.handleBar})}),c&&(0,i.jsx)(`div`,{className:t.default.title,children:c}),(0,i.jsx)(`div`,{className:t.default.body,children:p})]})]}),h)}exports.BottomSheet=o;
1
+ const e=require("../../utils/cn.cjs"),t=require("../Portal/escape-layer.cjs"),n=require("./BottomSheet.module.cjs"),r=require("../Portal/portal-host.cjs");let i=require("react"),a=require("react/jsx-runtime"),o=require("react-dom");function s({open:s,onClose:c,title:l,showHandle:u=!0,dismissOnBackdrop:d=!0,dismissOnEsc:f=!0,className:p,children:m,...h}){t.useEscapeLayer(s,f?c:null),(0,i.useEffect)(()=>{if(!s)return;let e=document.body.style.overflow;return document.body.style.overflow=`hidden`,()=>{document.body.style.overflow=e}},[s]);let g=r.usePortalHost();return!s||!g?null:(0,o.createPortal)((0,a.jsxs)(`div`,{className:n.default.root,role:`dialog`,"aria-modal":`true`,children:[(0,a.jsx)(`div`,{className:n.default.backdrop,onClick:()=>d&&c(),"aria-hidden":`true`}),(0,a.jsxs)(`div`,{className:e.cn(n.default.sheet,p),...h,children:[u&&(0,a.jsx)(`button`,{type:`button`,className:n.default.handle,"aria-label":`Arrastar para fechar`,onClick:c,children:(0,a.jsx)(`span`,{className:n.default.handleBar})}),l&&(0,a.jsx)(`div`,{className:n.default.title,children:l}),(0,a.jsx)(`div`,{className:n.default.body,children:m})]})]}),g)}exports.BottomSheet=s;
2
2
  //# sourceMappingURL=BottomSheet.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"BottomSheet.cjs","names":[],"sources":["../../../src/components/BottomSheet/BottomSheet.tsx"],"sourcesContent":["import { useEffect } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./BottomSheet.module.css\";\nimport { usePortalHost } from \"../Portal/portal-host\";\n\nexport interface BottomSheetProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n /** Controlled open state. */\n open: boolean;\n /** Fires when user dismisses (backdrop click, Esc, swipe). */\n onClose: () => void;\n /** Optional title rendered at the top of the sheet. */\n title?: ReactNode;\n /** Show a drag handle indicator at the top. Default `true`. */\n showHandle?: boolean;\n /** When `true`, clicking the backdrop closes the sheet. Default `true`. */\n dismissOnBackdrop?: boolean;\n /** When `true`, pressing Esc closes the sheet. Default `true`. */\n dismissOnEsc?: boolean;\n children?: ReactNode;\n}\n\n/**\n * Slide-up modal panel — mobile-style sheet anchored to the bottom edge.\n * Uses portal + safe-area padding + scroll lock.\n *\n * @example\n * <BottomSheet open={open} onClose={() => setOpen(false)} title=\"Filters\">\n * <FilterForm />\n * </BottomSheet>\n */\nexport function BottomSheet({\n open,\n onClose,\n title,\n showHandle = true,\n dismissOnBackdrop = true,\n dismissOnEsc = true,\n className,\n children,\n ...props\n}: BottomSheetProps) {\n useEffect(() => {\n if (!open || !dismissOnEsc) return;\n const handler = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") onClose();\n };\n window.addEventListener(\"keydown\", handler);\n return () => window.removeEventListener(\"keydown\", handler);\n }, [open, dismissOnEsc, onClose]);\n\n useEffect(() => {\n if (!open) return;\n const previous = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = previous;\n };\n }, [open]);\n\n const portalHost = usePortalHost();\n\n if (!open || !portalHost) return null;\n\n return createPortal(\n <div className={styles.root} role=\"dialog\" aria-modal=\"true\">\n <div\n className={styles.backdrop}\n onClick={() => dismissOnBackdrop && onClose()}\n aria-hidden=\"true\"\n />\n <div className={cn(styles.sheet, className)} {...props}>\n {showHandle && (\n <button\n type=\"button\"\n className={styles.handle}\n aria-label=\"Arrastar para fechar\"\n onClick={onClose}\n >\n <span className={styles.handleBar} />\n </button>\n )}\n {title && <div className={styles.title}>{title}</div>}\n <div className={styles.body}>{children}</div>\n </div>\n </div>,\n portalHost,\n );\n}\n"],"mappings":"gMAgCA,SAAgB,EAAY,CACxB,OACA,UACA,QACA,aAAa,GACb,oBAAoB,GACpB,eAAe,GACf,YACA,WACA,GAAG,GACc,EACjB,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,CAAC,GAAQ,CAAC,EAAc,OAC5B,IAAM,EAAW,GAAqB,CAC9B,EAAE,MAAQ,UAAU,EAAQ,CACpC,EAEA,OADA,OAAO,iBAAiB,UAAW,CAAO,MAC7B,OAAO,oBAAoB,UAAW,CAAO,CAC9D,EAAG,CAAC,EAAM,EAAc,CAAO,CAAC,GAEhC,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,CAAC,EAAM,OACX,IAAM,EAAW,SAAS,KAAK,MAAM,SAErC,MADA,UAAS,KAAK,MAAM,SAAW,aAClB,CACT,SAAS,KAAK,MAAM,SAAW,CACnC,CACJ,EAAG,CAAC,CAAI,CAAC,EAET,IAAM,EAAa,EAAA,cAAc,EAIjC,MAFI,CAAC,GAAQ,CAAC,EAAmB,MAEjC,EAAO,EAAA,aAAA,EACH,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,KAAM,KAAK,SAAS,aAAW,OAAtD,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,UAAW,EAAA,QAAO,SAClB,YAAe,GAAqB,EAAQ,EAC5C,cAAY,MACf,CAAA,GACD,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,MAAO,CAAS,EAAG,GAAI,EAAjD,SAAA,CACK,IACG,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,QAAO,OAClB,aAAW,uBACX,QAAS,EAET,UAAA,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,SAAY,CAAA,CAChC,CAAA,EAEX,IAAS,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,MAAQ,SAAA,CAAW,CAAA,GACpD,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,KAAO,UAAc,CAAA,CAC3C,CACJ,CAAA,CAAA,CACL,CAAA,EAAA,CACJ,CACJ"}
1
+ {"version":3,"file":"BottomSheet.cjs","names":[],"sources":["../../../src/components/BottomSheet/BottomSheet.tsx"],"sourcesContent":["import { useEffect } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { useEscapeLayer } from \"@/components/Portal/escape-layer\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./BottomSheet.module.css\";\nimport { usePortalHost } from \"../Portal/portal-host\";\n\nexport interface BottomSheetProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n /** Controlled open state. */\n open: boolean;\n /** Fires when user dismisses (backdrop click, Esc, swipe). */\n onClose: () => void;\n /** Optional title rendered at the top of the sheet. */\n title?: ReactNode;\n /** Show a drag handle indicator at the top. Default `true`. */\n showHandle?: boolean;\n /** When `true`, clicking the backdrop closes the sheet. Default `true`. */\n dismissOnBackdrop?: boolean;\n /** When `true`, pressing Esc closes the sheet. Default `true`. */\n dismissOnEsc?: boolean;\n children?: ReactNode;\n}\n\n/**\n * Slide-up modal panel — mobile-style sheet anchored to the bottom edge.\n * Uses portal + safe-area padding + scroll lock.\n *\n * @example\n * <BottomSheet open={open} onClose={() => setOpen(false)} title=\"Filters\">\n * <FilterForm />\n * </BottomSheet>\n */\nexport function BottomSheet({\n open,\n onClose,\n title,\n showHandle = true,\n dismissOnBackdrop = true,\n dismissOnEsc = true,\n className,\n children,\n ...props\n}: BottomSheetProps) {\n useEscapeLayer(open, dismissOnEsc ? onClose : null);\n\n useEffect(() => {\n if (!open) return;\n const previous = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = previous;\n };\n }, [open]);\n\n const portalHost = usePortalHost();\n\n if (!open || !portalHost) return null;\n\n return createPortal(\n <div className={styles.root} role=\"dialog\" aria-modal=\"true\">\n <div\n className={styles.backdrop}\n onClick={() => dismissOnBackdrop && onClose()}\n aria-hidden=\"true\"\n />\n <div className={cn(styles.sheet, className)} {...props}>\n {showHandle && (\n <button\n type=\"button\"\n className={styles.handle}\n aria-label=\"Arrastar para fechar\"\n onClick={onClose}\n >\n <span className={styles.handleBar} />\n </button>\n )}\n {title && <div className={styles.title}>{title}</div>}\n <div className={styles.body}>{children}</div>\n </div>\n </div>,\n portalHost,\n );\n}\n"],"mappings":"wOAiCA,SAAgB,EAAY,CACxB,OACA,UACA,QACA,aAAa,GACb,oBAAoB,GACpB,eAAe,GACf,YACA,WACA,GAAG,GACc,CACjB,EAAA,eAAe,EAAM,EAAe,EAAU,IAAI,GAElD,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,CAAC,EAAM,OACX,IAAM,EAAW,SAAS,KAAK,MAAM,SAErC,MADA,UAAS,KAAK,MAAM,SAAW,aAClB,CACT,SAAS,KAAK,MAAM,SAAW,CACnC,CACJ,EAAG,CAAC,CAAI,CAAC,EAET,IAAM,EAAa,EAAA,cAAc,EAIjC,MAFI,CAAC,GAAQ,CAAC,EAAmB,MAEjC,EAAO,EAAA,aAAA,EACH,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,KAAM,KAAK,SAAS,aAAW,OAAtD,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,UAAW,EAAA,QAAO,SAClB,YAAe,GAAqB,EAAQ,EAC5C,cAAY,MACf,CAAA,GACD,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,MAAO,CAAS,EAAG,GAAI,EAAjD,SAAA,CACK,IACG,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,QAAO,OAClB,aAAW,uBACX,QAAS,EAET,UAAA,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,SAAY,CAAA,CAChC,CAAA,EAEX,IAAS,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,MAAQ,SAAA,CAAW,CAAA,GACpD,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,KAAO,UAAc,CAAA,CAC3C,CACJ,CAAA,CAAA,CACL,CAAA,EAAA,CACJ,CACJ"}
@@ -1,61 +1,52 @@
1
1
  import { cn as e } from "../../utils/cn.js";
2
- import t from "./BottomSheet.module.js";
3
- import { usePortalHost as n } from "../Portal/portal-host.js";
4
- import { useEffect as r } from "react";
5
- import { jsx as i, jsxs as a } from "react/jsx-runtime";
6
- import { createPortal as o } from "react-dom";
2
+ import { useEscapeLayer as t } from "../Portal/escape-layer.js";
3
+ import n from "./BottomSheet.module.js";
4
+ import { usePortalHost as r } from "../Portal/portal-host.js";
5
+ import { useEffect as i } from "react";
6
+ import { jsx as a, jsxs as o } from "react/jsx-runtime";
7
+ import { createPortal as s } from "react-dom";
7
8
  //#region src/components/BottomSheet/BottomSheet.tsx
8
- function s({ open: s, onClose: c, title: l, showHandle: u = !0, dismissOnBackdrop: d = !0, dismissOnEsc: f = !0, className: p, children: m, ...h }) {
9
- r(() => {
10
- if (!s || !f) return;
11
- let e = (e) => {
12
- e.key === "Escape" && c();
13
- };
14
- return window.addEventListener("keydown", e), () => window.removeEventListener("keydown", e);
15
- }, [
16
- s,
17
- f,
18
- c
19
- ]), r(() => {
20
- if (!s) return;
9
+ function c({ open: c, onClose: l, title: u, showHandle: d = !0, dismissOnBackdrop: f = !0, dismissOnEsc: p = !0, className: m, children: h, ...g }) {
10
+ t(c, p ? l : null), i(() => {
11
+ if (!c) return;
21
12
  let e = document.body.style.overflow;
22
13
  return document.body.style.overflow = "hidden", () => {
23
14
  document.body.style.overflow = e;
24
15
  };
25
- }, [s]);
26
- let g = n();
27
- return !s || !g ? null : o(/* @__PURE__ */ a("div", {
28
- className: t.root,
16
+ }, [c]);
17
+ let _ = r();
18
+ return !c || !_ ? null : s(/* @__PURE__ */ o("div", {
19
+ className: n.root,
29
20
  role: "dialog",
30
21
  "aria-modal": "true",
31
- children: [/* @__PURE__ */ i("div", {
32
- className: t.backdrop,
33
- onClick: () => d && c(),
22
+ children: [/* @__PURE__ */ a("div", {
23
+ className: n.backdrop,
24
+ onClick: () => f && l(),
34
25
  "aria-hidden": "true"
35
- }), /* @__PURE__ */ a("div", {
36
- className: e(t.sheet, p),
37
- ...h,
26
+ }), /* @__PURE__ */ o("div", {
27
+ className: e(n.sheet, m),
28
+ ...g,
38
29
  children: [
39
- u && /* @__PURE__ */ i("button", {
30
+ d && /* @__PURE__ */ a("button", {
40
31
  type: "button",
41
- className: t.handle,
32
+ className: n.handle,
42
33
  "aria-label": "Arrastar para fechar",
43
- onClick: c,
44
- children: /* @__PURE__ */ i("span", { className: t.handleBar })
34
+ onClick: l,
35
+ children: /* @__PURE__ */ a("span", { className: n.handleBar })
45
36
  }),
46
- l && /* @__PURE__ */ i("div", {
47
- className: t.title,
48
- children: l
37
+ u && /* @__PURE__ */ a("div", {
38
+ className: n.title,
39
+ children: u
49
40
  }),
50
- /* @__PURE__ */ i("div", {
51
- className: t.body,
52
- children: m
41
+ /* @__PURE__ */ a("div", {
42
+ className: n.body,
43
+ children: h
53
44
  })
54
45
  ]
55
46
  })]
56
- }), g);
47
+ }), _);
57
48
  }
58
49
  //#endregion
59
- export { s as BottomSheet };
50
+ export { c as BottomSheet };
60
51
 
61
52
  //# sourceMappingURL=BottomSheet.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"BottomSheet.js","names":[],"sources":["../../../src/components/BottomSheet/BottomSheet.tsx"],"sourcesContent":["import { useEffect } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./BottomSheet.module.css\";\nimport { usePortalHost } from \"../Portal/portal-host\";\n\nexport interface BottomSheetProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n /** Controlled open state. */\n open: boolean;\n /** Fires when user dismisses (backdrop click, Esc, swipe). */\n onClose: () => void;\n /** Optional title rendered at the top of the sheet. */\n title?: ReactNode;\n /** Show a drag handle indicator at the top. Default `true`. */\n showHandle?: boolean;\n /** When `true`, clicking the backdrop closes the sheet. Default `true`. */\n dismissOnBackdrop?: boolean;\n /** When `true`, pressing Esc closes the sheet. Default `true`. */\n dismissOnEsc?: boolean;\n children?: ReactNode;\n}\n\n/**\n * Slide-up modal panel — mobile-style sheet anchored to the bottom edge.\n * Uses portal + safe-area padding + scroll lock.\n *\n * @example\n * <BottomSheet open={open} onClose={() => setOpen(false)} title=\"Filters\">\n * <FilterForm />\n * </BottomSheet>\n */\nexport function BottomSheet({\n open,\n onClose,\n title,\n showHandle = true,\n dismissOnBackdrop = true,\n dismissOnEsc = true,\n className,\n children,\n ...props\n}: BottomSheetProps) {\n useEffect(() => {\n if (!open || !dismissOnEsc) return;\n const handler = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") onClose();\n };\n window.addEventListener(\"keydown\", handler);\n return () => window.removeEventListener(\"keydown\", handler);\n }, [open, dismissOnEsc, onClose]);\n\n useEffect(() => {\n if (!open) return;\n const previous = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = previous;\n };\n }, [open]);\n\n const portalHost = usePortalHost();\n\n if (!open || !portalHost) return null;\n\n return createPortal(\n <div className={styles.root} role=\"dialog\" aria-modal=\"true\">\n <div\n className={styles.backdrop}\n onClick={() => dismissOnBackdrop && onClose()}\n aria-hidden=\"true\"\n />\n <div className={cn(styles.sheet, className)} {...props}>\n {showHandle && (\n <button\n type=\"button\"\n className={styles.handle}\n aria-label=\"Arrastar para fechar\"\n onClick={onClose}\n >\n <span className={styles.handleBar} />\n </button>\n )}\n {title && <div className={styles.title}>{title}</div>}\n <div className={styles.body}>{children}</div>\n </div>\n </div>,\n portalHost,\n );\n}\n"],"mappings":";;;;;;;AAgCA,SAAgB,EAAY,EACxB,SACA,YACA,UACA,gBAAa,IACb,uBAAoB,IACpB,kBAAe,IACf,cACA,aACA,GAAG,KACc;CAUjB,AATA,QAAgB;EACZ,IAAI,CAAC,KAAQ,CAAC,GAAc;EAC5B,IAAM,KAAW,MAAqB;GAClC,AAAI,EAAE,QAAQ,YAAU,EAAQ;EACpC;EAEA,OADA,OAAO,iBAAiB,WAAW,CAAO,SAC7B,OAAO,oBAAoB,WAAW,CAAO;CAC9D,GAAG;EAAC;EAAM;EAAc;CAAO,CAAC,GAEhC,QAAgB;EACZ,IAAI,CAAC,GAAM;EACX,IAAM,IAAW,SAAS,KAAK,MAAM;EAErC,OADA,SAAS,KAAK,MAAM,WAAW,gBAClB;GACT,SAAS,KAAK,MAAM,WAAW;EACnC;CACJ,GAAG,CAAC,CAAI,CAAC;CAET,IAAM,IAAa,EAAc;CAIjC,OAFI,CAAC,KAAQ,CAAC,IAAmB,OAE1B,EACH,kBAAC,OAAD;EAAK,WAAW,EAAO;EAAM,MAAK;EAAS,cAAW;EAAtD,UAAA,CACI,kBAAC,OAAD;GACI,WAAW,EAAO;GAClB,eAAe,KAAqB,EAAQ;GAC5C,eAAY;EACf,CAAA,GACD,kBAAC,OAAD;GAAK,WAAW,EAAG,EAAO,OAAO,CAAS;GAAG,GAAI;GAAjD,UAAA;IACK,KACG,kBAAC,UAAD;KACI,MAAK;KACL,WAAW,EAAO;KAClB,cAAW;KACX,SAAS;KAET,UAAA,kBAAC,QAAD,EAAM,WAAW,EAAO,UAAY,CAAA;IAChC,CAAA;IAEX,KAAS,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAQ,UAAA;IAAW,CAAA;IACpD,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAO;IAAc,CAAA;GAC3C;EACJ,CAAA,CAAA;CACL,CAAA,GAAA,CACJ;AACJ"}
1
+ {"version":3,"file":"BottomSheet.js","names":[],"sources":["../../../src/components/BottomSheet/BottomSheet.tsx"],"sourcesContent":["import { useEffect } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { useEscapeLayer } from \"@/components/Portal/escape-layer\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./BottomSheet.module.css\";\nimport { usePortalHost } from \"../Portal/portal-host\";\n\nexport interface BottomSheetProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n /** Controlled open state. */\n open: boolean;\n /** Fires when user dismisses (backdrop click, Esc, swipe). */\n onClose: () => void;\n /** Optional title rendered at the top of the sheet. */\n title?: ReactNode;\n /** Show a drag handle indicator at the top. Default `true`. */\n showHandle?: boolean;\n /** When `true`, clicking the backdrop closes the sheet. Default `true`. */\n dismissOnBackdrop?: boolean;\n /** When `true`, pressing Esc closes the sheet. Default `true`. */\n dismissOnEsc?: boolean;\n children?: ReactNode;\n}\n\n/**\n * Slide-up modal panel — mobile-style sheet anchored to the bottom edge.\n * Uses portal + safe-area padding + scroll lock.\n *\n * @example\n * <BottomSheet open={open} onClose={() => setOpen(false)} title=\"Filters\">\n * <FilterForm />\n * </BottomSheet>\n */\nexport function BottomSheet({\n open,\n onClose,\n title,\n showHandle = true,\n dismissOnBackdrop = true,\n dismissOnEsc = true,\n className,\n children,\n ...props\n}: BottomSheetProps) {\n useEscapeLayer(open, dismissOnEsc ? onClose : null);\n\n useEffect(() => {\n if (!open) return;\n const previous = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = previous;\n };\n }, [open]);\n\n const portalHost = usePortalHost();\n\n if (!open || !portalHost) return null;\n\n return createPortal(\n <div className={styles.root} role=\"dialog\" aria-modal=\"true\">\n <div\n className={styles.backdrop}\n onClick={() => dismissOnBackdrop && onClose()}\n aria-hidden=\"true\"\n />\n <div className={cn(styles.sheet, className)} {...props}>\n {showHandle && (\n <button\n type=\"button\"\n className={styles.handle}\n aria-label=\"Arrastar para fechar\"\n onClick={onClose}\n >\n <span className={styles.handleBar} />\n </button>\n )}\n {title && <div className={styles.title}>{title}</div>}\n <div className={styles.body}>{children}</div>\n </div>\n </div>,\n portalHost,\n );\n}\n"],"mappings":";;;;;;;;AAiCA,SAAgB,EAAY,EACxB,SACA,YACA,UACA,gBAAa,IACb,uBAAoB,IACpB,kBAAe,IACf,cACA,aACA,GAAG,KACc;CAGjB,AAFA,EAAe,GAAM,IAAe,IAAU,IAAI,GAElD,QAAgB;EACZ,IAAI,CAAC,GAAM;EACX,IAAM,IAAW,SAAS,KAAK,MAAM;EAErC,OADA,SAAS,KAAK,MAAM,WAAW,gBAClB;GACT,SAAS,KAAK,MAAM,WAAW;EACnC;CACJ,GAAG,CAAC,CAAI,CAAC;CAET,IAAM,IAAa,EAAc;CAIjC,OAFI,CAAC,KAAQ,CAAC,IAAmB,OAE1B,EACH,kBAAC,OAAD;EAAK,WAAW,EAAO;EAAM,MAAK;EAAS,cAAW;EAAtD,UAAA,CACI,kBAAC,OAAD;GACI,WAAW,EAAO;GAClB,eAAe,KAAqB,EAAQ;GAC5C,eAAY;EACf,CAAA,GACD,kBAAC,OAAD;GAAK,WAAW,EAAG,EAAO,OAAO,CAAS;GAAG,GAAI;GAAjD,UAAA;IACK,KACG,kBAAC,UAAD;KACI,MAAK;KACL,WAAW,EAAO;KAClB,cAAW;KACX,SAAS;KAET,UAAA,kBAAC,QAAD,EAAM,WAAW,EAAO,UAAY,CAAA;IAChC,CAAA;IAEX,KAAS,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAQ,UAAA;IAAW,CAAA;IACpD,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAO;IAAc,CAAA;GAC3C;EACJ,CAAA,CAAA;CACL,CAAA,GAAA,CACJ;AACJ"}
@@ -1,2 +1,2 @@
1
- const e=require("../../utils/cn.cjs"),t=require("./Combobox.module.cjs");let n=require("react"),r=require("react/jsx-runtime");function i(e,t){return!t||e.label.toLowerCase().includes(t.toLowerCase())}function a({options:a,value:o,onChange:s,label:c,placeholder:l=`Selecione`,helperText:u,error:d,disabled:f,filter:p=i,emptyMessage:m=`Nenhuma opção encontrada`,className:h}){let g=(0,n.useId)(),_=(0,n.useRef)(null),v=(0,n.useRef)(null),[y,b]=(0,n.useState)(!1),[x,S]=(0,n.useState)(``),[C,w]=(0,n.useState)(0),T=(0,n.useMemo)(()=>a.find(e=>e.value===o)?.label??``,[a,o]),E=(0,n.useMemo)(()=>a.filter(e=>p(e,x)),[a,p,x]),D=(0,n.useCallback)(()=>{b(!1),S(``),w(0)},[]),O=(0,n.useCallback)(e=>{e.disabled||(s(e.value),D())},[s,D]);return(0,n.useEffect)(()=>{if(!y)return;let e=e=>{_.current&&!_.current.contains(e.target)&&D()};return window.addEventListener(`mousedown`,e),()=>window.removeEventListener(`mousedown`,e)},[y,D]),(0,r.jsxs)(`div`,{ref:_,className:e.cn(t.default.wrapper,d&&t.default.error,h),children:[c&&(0,r.jsx)(`label`,{htmlFor:g,className:t.default.label,children:c}),(0,r.jsxs)(`div`,{className:t.default.field,children:[(0,r.jsx)(`input`,{id:g,ref:v,type:`text`,role:`combobox`,"aria-expanded":y,"aria-controls":`${g}-listbox`,"aria-autocomplete":`list`,className:t.default.input,placeholder:l,disabled:f,value:y?x:T,onFocus:()=>b(!0),onChange:e=>{S(e.target.value),b(!0),w(0)},onKeyDown:e=>{if(e.key===`ArrowDown`)e.preventDefault(),b(!0),w(e=>Math.min(E.length-1,e+1));else if(e.key===`ArrowUp`)e.preventDefault(),w(e=>Math.max(0,e-1));else if(e.key===`Enter`){e.preventDefault();let t=E[C];t&&O(t)}else e.key===`Escape`&&D()}}),(0,r.jsx)(`span`,{className:t.default.caret,"aria-hidden":!0,children:`▾`})]}),y&&(0,r.jsx)(`ul`,{id:`${g}-listbox`,role:`listbox`,className:t.default.menu,children:E.length===0?(0,r.jsx)(`li`,{className:t.default.empty,children:m}):E.map((n,i)=>(0,r.jsx)(`li`,{role:`option`,"aria-selected":n.value===o,className:e.cn(t.default.option,i===C&&t.default.active,n.value===o&&t.default.selected),onMouseEnter:()=>w(i),onMouseDown:e=>{e.preventDefault(),O(n)},children:n.label},n.value))}),d?(0,r.jsx)(`span`,{className:t.default.errorText,children:d}):u?(0,r.jsx)(`span`,{className:t.default.helper,children:u}):null]})}exports.Combobox=a;
1
+ const e=require("../../utils/cn.cjs"),t=require("../Portal/Portal.cjs"),n=require("../Portal/anchor-position.cjs"),r=require("./Combobox.module.cjs");let i=require("react"),a=require("react/jsx-runtime");var o=4;function s(e,t){return!t||e.label.toLowerCase().includes(t.toLowerCase())}function c({options:c,value:l,onChange:u,label:d,placeholder:f=`Selecione`,helperText:p,error:m,disabled:h,filter:g=s,emptyMessage:_=`Nenhuma opção encontrada`,portal:v=!0,className:y}){let b=(0,i.useId)(),x=(0,i.useRef)(null),S=(0,i.useRef)(null),[C,w]=(0,i.useState)(!1),[T,E]=(0,i.useState)(``),[D,O]=(0,i.useState)(0),[k,A]=(0,i.useState)(null),[j,M]=(0,i.useState)(null),N=n.useAnchorPosition({anchor:k,floating:j,side:`bottom`,align:`start`,offset:o,enabled:v&&C,matchWidth:!0}),P=(0,i.useMemo)(()=>c.find(e=>e.value===l)?.label??``,[c,l]),F=(0,i.useMemo)(()=>c.filter(e=>g(e,T)),[c,g,T]),I=(0,i.useCallback)(()=>{w(!1),E(``),O(0)},[]),L=(0,i.useCallback)(e=>{e.disabled||(u(e.value),I())},[u,I]);(0,i.useEffect)(()=>{if(!C)return;let e=e=>{let t=e.target;x.current?.contains(t)||j?.contains(t)||I()};return window.addEventListener(`mousedown`,e),()=>window.removeEventListener(`mousedown`,e)},[C,I,j]);let R=e=>{if(e.key===`ArrowDown`)e.preventDefault(),w(!0),O(e=>Math.min(F.length-1,e+1));else if(e.key===`ArrowUp`)e.preventDefault(),O(e=>Math.max(0,e-1));else if(e.key===`Enter`){e.preventDefault();let t=F[D];t&&L(t)}else e.key===`Escape`&&(C&&e.preventDefault(),I())},z=(0,a.jsx)(`ul`,{ref:M,id:`${b}-listbox`,role:`listbox`,className:e.cn(r.default.menu,v&&r.default.portalled),style:N,children:F.length===0?(0,a.jsx)(`li`,{className:r.default.empty,children:_}):F.map((t,n)=>(0,a.jsx)(`li`,{role:`option`,"aria-selected":t.value===l,className:e.cn(r.default.option,n===D&&r.default.active,t.value===l&&r.default.selected),onMouseEnter:()=>O(n),onMouseDown:e=>{e.preventDefault(),L(t)},children:t.label},t.value))});return(0,a.jsxs)(`div`,{ref:x,className:e.cn(r.default.wrapper,m&&r.default.error,y),children:[d&&(0,a.jsx)(`label`,{htmlFor:b,className:r.default.label,children:d}),(0,a.jsxs)(`div`,{ref:A,className:r.default.field,children:[(0,a.jsx)(`input`,{id:b,ref:S,type:`text`,role:`combobox`,"aria-expanded":C,"aria-controls":`${b}-listbox`,"aria-autocomplete":`list`,className:r.default.input,placeholder:f,disabled:h,value:C?T:P,onFocus:()=>w(!0),onChange:e=>{E(e.target.value),w(!0),O(0)},onKeyDown:R}),(0,a.jsx)(`span`,{className:r.default.caret,"aria-hidden":!0,children:`▾`})]}),C&&(v?(0,a.jsx)(t.Portal,{children:z}):z),m?(0,a.jsx)(`span`,{className:r.default.errorText,children:m}):p?(0,a.jsx)(`span`,{className:r.default.helper,children:p}):null]})}exports.Combobox=c;
2
2
  //# sourceMappingURL=Combobox.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Combobox.cjs","names":[],"sources":["../../../src/components/Combobox/Combobox.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — options/value/onChange\n * plus the shared field contract (label, placeholder, helperText, error, disabled,\n * className) and the three combobox-specific knobs: filter, emptyMessage. The body\n * is the listbox — open state, active descendant, type-ahead and the ARIA wiring —\n * and those cannot be separated without passing the same active index back and\n * forth.\n */\nimport { useCallback, useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Combobox.module.css\";\n\nexport interface ComboboxOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\nexport interface ComboboxProps {\n options: ComboboxOption[];\n value: string;\n onChange: (value: string) => void;\n label?: string;\n placeholder?: string;\n helperText?: string;\n error?: string;\n disabled?: boolean;\n /** Custom filter — return true to keep the option. Default is case-insensitive substring match on label. */\n filter?: (option: ComboboxOption, query: string) => boolean;\n /** Message shown when no option matches. */\n emptyMessage?: string;\n className?: string;\n}\n\nfunction defaultFilter(option: ComboboxOption, query: string): boolean {\n if (!query) return true;\n return option.label.toLowerCase().includes(query.toLowerCase());\n}\n\n/**\n * Combobox — text input with a filterable dropdown of options.\n *\n * Selecting an option fires `onChange(value)`. Typing filters the list.\n * Keyboard: ArrowUp/ArrowDown to navigate, Enter to select, Esc to close.\n */\nexport function Combobox({\n options,\n value,\n onChange,\n label,\n placeholder = \"Selecione\",\n helperText,\n error,\n disabled,\n filter = defaultFilter,\n emptyMessage = \"Nenhuma opção encontrada\",\n className,\n}: ComboboxProps) {\n const id = useId();\n const rootRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n const [activeIndex, setActiveIndex] = useState(0);\n\n const selectedLabel = useMemo(\n () => options.find((o) => o.value === value)?.label ?? \"\",\n [options, value],\n );\n\n const filtered = useMemo(\n () => options.filter((o) => filter(o, query)),\n [options, filter, query],\n );\n\n const closeAndReset = useCallback((): void => {\n setOpen(false);\n setQuery(\"\");\n setActiveIndex(0);\n }, []);\n\n const handleSelect = useCallback(\n (option: ComboboxOption): void => {\n if (option.disabled) return;\n onChange(option.value);\n closeAndReset();\n },\n [onChange, closeAndReset],\n );\n\n useEffect(() => {\n if (!open) return;\n const onDown = (event: MouseEvent): void => {\n if (rootRef.current && !rootRef.current.contains(event.target as Node)) {\n closeAndReset();\n }\n };\n window.addEventListener(\"mousedown\", onDown);\n return () => window.removeEventListener(\"mousedown\", onDown);\n }, [open, closeAndReset]);\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>): void => {\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n setOpen(true);\n setActiveIndex((current) => Math.min(filtered.length - 1, current + 1));\n } else if (event.key === \"ArrowUp\") {\n event.preventDefault();\n setActiveIndex((current) => Math.max(0, current - 1));\n } else if (event.key === \"Enter\") {\n event.preventDefault();\n const option = filtered[activeIndex];\n if (option) handleSelect(option);\n } else if (event.key === \"Escape\") {\n closeAndReset();\n }\n };\n\n return (\n <div ref={rootRef} className={cn(styles.wrapper, error && styles.error, className)}>\n {label && (\n <label htmlFor={id} className={styles.label}>\n {label}\n </label>\n )}\n <div className={styles.field}>\n <input\n id={id}\n ref={inputRef}\n type=\"text\"\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={`${id}-listbox`}\n aria-autocomplete=\"list\"\n className={styles.input}\n placeholder={placeholder}\n disabled={disabled}\n value={open ? query : selectedLabel}\n onFocus={() => setOpen(true)}\n onChange={(event) => {\n setQuery(event.target.value);\n setOpen(true);\n setActiveIndex(0);\n }}\n onKeyDown={handleKeyDown}\n />\n <span className={styles.caret} aria-hidden>\n ▾\n </span>\n </div>\n {open && (\n <ul id={`${id}-listbox`} role=\"listbox\" className={styles.menu}>\n {filtered.length === 0 ? (\n <li className={styles.empty}>{emptyMessage}</li>\n ) : (\n filtered.map((option, index) => (\n <li\n key={option.value}\n role=\"option\"\n aria-selected={option.value === value}\n className={cn(\n styles.option,\n index === activeIndex && styles.active,\n option.value === value && styles.selected,\n )}\n onMouseEnter={() => setActiveIndex(index)}\n onMouseDown={(event) => {\n event.preventDefault();\n handleSelect(option);\n }}\n >\n {option.label}\n </li>\n ))\n )}\n </ul>\n )}\n {error ? (\n <span className={styles.errorText}>{error}</span>\n ) : helperText ? (\n <span className={styles.helper}>{helperText}</span>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Combobox.cjs","names":[],"sources":["../../../src/components/Combobox/Combobox.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — options/value/onChange\n * plus the shared field contract (label, placeholder, helperText, error, disabled,\n * className) and the combobox-specific knobs: filter, emptyMessage, portal. The body\n * is the listbox — open state, active descendant, type-ahead and the ARIA wiring —\n * and those cannot be separated without passing the same active index back and\n * forth.\n */\nimport { useCallback, useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { Portal } from \"@/components/Portal\";\nimport { useAnchorPosition } from \"@/components/Portal/anchor-position\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Combobox.module.css\";\n\nexport interface ComboboxOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\nexport interface ComboboxProps {\n options: ComboboxOption[];\n value: string;\n onChange: (value: string) => void;\n label?: string;\n placeholder?: string;\n helperText?: string;\n error?: string;\n disabled?: boolean;\n /** Custom filter — return true to keep the option. Default is case-insensitive substring match on label. */\n filter?: (option: ComboboxOption, query: string) => boolean;\n /** Message shown when no option matches. */\n emptyMessage?: string;\n /**\n * Render the list in a portal, positioned under the field. Default `true`.\n *\n * In flow, an ancestor with `overflow` other than `visible` clips the list —\n * in the last row of a `DataTable` none of it was visible (measured in Chrome\n * at 1440 px). In a portal it escapes the clip, takes the field's width,\n * flips above the field when there is no room below, and follows it on\n * scroll, resize and when the field or the list changes size.\n */\n portal?: boolean;\n className?: string;\n}\n\n/** Gap between field and list, in px — the in-flow CSS uses the same 4 px. */\nconst LIST_OFFSET = 4;\n\nfunction defaultFilter(option: ComboboxOption, query: string): boolean {\n if (!query) return true;\n return option.label.toLowerCase().includes(query.toLowerCase());\n}\n\n/**\n * Combobox — text input with a filterable dropdown of options.\n *\n * Selecting an option fires `onChange(value)`. Typing filters the list.\n * Keyboard: ArrowUp/ArrowDown to navigate, Enter to select, Esc to close.\n */\nexport function Combobox({\n options,\n value,\n onChange,\n label,\n placeholder = \"Selecione\",\n helperText,\n error,\n disabled,\n filter = defaultFilter,\n emptyMessage = \"Nenhuma opção encontrada\",\n portal = true,\n className,\n}: ComboboxProps) {\n const id = useId();\n const rootRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n const [activeIndex, setActiveIndex] = useState(0);\n const [fieldNode, setFieldNode] = useState<HTMLDivElement | null>(null);\n const [listNode, setListNode] = useState<HTMLUListElement | null>(null);\n const floatingStyle = useAnchorPosition({\n anchor: fieldNode,\n floating: listNode,\n side: \"bottom\",\n align: \"start\",\n offset: LIST_OFFSET,\n enabled: portal && open,\n matchWidth: true,\n });\n\n const selectedLabel = useMemo(\n () => options.find((o) => o.value === value)?.label ?? \"\",\n [options, value],\n );\n\n const filtered = useMemo(\n () => options.filter((o) => filter(o, query)),\n [options, filter, query],\n );\n\n const closeAndReset = useCallback((): void => {\n setOpen(false);\n setQuery(\"\");\n setActiveIndex(0);\n }, []);\n\n const handleSelect = useCallback(\n (option: ComboboxOption): void => {\n if (option.disabled) return;\n onChange(option.value);\n closeAndReset();\n },\n [onChange, closeAndReset],\n );\n\n /**\n * Close on a press outside both the field and the list.\n *\n * The list is checked on its own because in a portal it is not inside the\n * field's wrapper: a press on its scrollbar, or on the empty message, would\n * otherwise count as outside and close it.\n */\n useEffect(() => {\n if (!open) return;\n const onDown = (event: MouseEvent): void => {\n const target = event.target as Node;\n if (rootRef.current?.contains(target) || listNode?.contains(target)) return;\n closeAndReset();\n };\n window.addEventListener(\"mousedown\", onDown);\n return () => window.removeEventListener(\"mousedown\", onDown);\n }, [open, closeAndReset, listNode]);\n\n /**\n * Keyboard model of the input.\n *\n * `Escape` calls `preventDefault()` only while the list is open: that marks the\n * key as consumed, so an enclosing `Modal` or `Drawer` stays open and the next\n * `Escape` reaches it. With the list closed the key is left alone and dismisses\n * the enclosing layer, as the user expects.\n */\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>): void => {\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n setOpen(true);\n setActiveIndex((current) => Math.min(filtered.length - 1, current + 1));\n } else if (event.key === \"ArrowUp\") {\n event.preventDefault();\n setActiveIndex((current) => Math.max(0, current - 1));\n } else if (event.key === \"Enter\") {\n event.preventDefault();\n const option = filtered[activeIndex];\n if (option) handleSelect(option);\n } else if (event.key === \"Escape\") {\n if (open) event.preventDefault();\n closeAndReset();\n }\n };\n\n const list = (\n <ul\n ref={setListNode}\n id={`${id}-listbox`}\n role=\"listbox\"\n className={cn(styles.menu, portal && styles.portalled)}\n style={floatingStyle}\n >\n {filtered.length === 0 ? (\n <li className={styles.empty}>{emptyMessage}</li>\n ) : (\n filtered.map((option, index) => (\n <li\n key={option.value}\n role=\"option\"\n aria-selected={option.value === value}\n className={cn(\n styles.option,\n index === activeIndex && styles.active,\n option.value === value && styles.selected,\n )}\n onMouseEnter={() => setActiveIndex(index)}\n onMouseDown={(event) => {\n event.preventDefault();\n handleSelect(option);\n }}\n >\n {option.label}\n </li>\n ))\n )}\n </ul>\n );\n\n return (\n <div ref={rootRef} className={cn(styles.wrapper, error && styles.error, className)}>\n {label && (\n <label htmlFor={id} className={styles.label}>\n {label}\n </label>\n )}\n <div ref={setFieldNode} className={styles.field}>\n <input\n id={id}\n ref={inputRef}\n type=\"text\"\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={`${id}-listbox`}\n aria-autocomplete=\"list\"\n className={styles.input}\n placeholder={placeholder}\n disabled={disabled}\n value={open ? query : selectedLabel}\n onFocus={() => setOpen(true)}\n onChange={(event) => {\n setQuery(event.target.value);\n setOpen(true);\n setActiveIndex(0);\n }}\n onKeyDown={handleKeyDown}\n />\n <span className={styles.caret} aria-hidden>\n ▾\n </span>\n </div>\n {open && (portal ? <Portal>{list}</Portal> : list)}\n {error ? (\n <span className={styles.errorText}>{error}</span>\n ) : helperText ? (\n <span className={styles.helper}>{helperText}</span>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,98 +1,119 @@
1
1
  import { cn as e } from "../../utils/cn.js";
2
- import t from "./Combobox.module.js";
3
- import { useCallback as n, useEffect as r, useId as i, useMemo as a, useRef as o, useState as s } from "react";
4
- import { jsx as c, jsxs as l } from "react/jsx-runtime";
2
+ import { Portal as t } from "../Portal/Portal.js";
3
+ import { useAnchorPosition as n } from "../Portal/anchor-position.js";
4
+ import r from "./Combobox.module.js";
5
+ import { useCallback as i, useEffect as a, useId as o, useMemo as s, useRef as c, useState as l } from "react";
6
+ import { jsx as u, jsxs as d } from "react/jsx-runtime";
5
7
  //#region src/components/Combobox/Combobox.tsx
6
- function u(e, t) {
8
+ var f = 4;
9
+ function p(e, t) {
7
10
  return !t || e.label.toLowerCase().includes(t.toLowerCase());
8
11
  }
9
- function d({ options: d, value: f, onChange: p, label: m, placeholder: h = "Selecione", helperText: g, error: _, disabled: v, filter: y = u, emptyMessage: b = "Nenhuma opção encontrada", className: x }) {
10
- let S = i(), C = o(null), w = o(null), [T, E] = s(!1), [D, O] = s(""), [k, A] = s(0), j = a(() => d.find((e) => e.value === f)?.label ?? "", [d, f]), M = a(() => d.filter((e) => y(e, D)), [
11
- d,
12
- y,
13
- D
14
- ]), N = n(() => {
15
- E(!1), O(""), A(0);
16
- }, []), P = n((e) => {
17
- e.disabled || (p(e.value), N());
18
- }, [p, N]);
19
- return r(() => {
20
- if (!T) return;
12
+ function m({ options: m, value: h, onChange: g, label: _, placeholder: v = "Selecione", helperText: y, error: b, disabled: x, filter: S = p, emptyMessage: C = "Nenhuma opção encontrada", portal: w = !0, className: T }) {
13
+ let E = o(), D = c(null), O = c(null), [k, A] = l(!1), [j, M] = l(""), [N, P] = l(0), [F, I] = l(null), [L, R] = l(null), z = n({
14
+ anchor: F,
15
+ floating: L,
16
+ side: "bottom",
17
+ align: "start",
18
+ offset: f,
19
+ enabled: w && k,
20
+ matchWidth: !0
21
+ }), B = s(() => m.find((e) => e.value === h)?.label ?? "", [m, h]), V = s(() => m.filter((e) => S(e, j)), [
22
+ m,
23
+ S,
24
+ j
25
+ ]), H = i(() => {
26
+ A(!1), M(""), P(0);
27
+ }, []), U = i((e) => {
28
+ e.disabled || (g(e.value), H());
29
+ }, [g, H]);
30
+ a(() => {
31
+ if (!k) return;
21
32
  let e = (e) => {
22
- C.current && !C.current.contains(e.target) && N();
33
+ let t = e.target;
34
+ D.current?.contains(t) || L?.contains(t) || H();
23
35
  };
24
36
  return window.addEventListener("mousedown", e), () => window.removeEventListener("mousedown", e);
25
- }, [T, N]), /* @__PURE__ */ l("div", {
26
- ref: C,
27
- className: e(t.wrapper, _ && t.error, x),
37
+ }, [
38
+ k,
39
+ H,
40
+ L
41
+ ]);
42
+ let W = (e) => {
43
+ if (e.key === "ArrowDown") e.preventDefault(), A(!0), P((e) => Math.min(V.length - 1, e + 1));
44
+ else if (e.key === "ArrowUp") e.preventDefault(), P((e) => Math.max(0, e - 1));
45
+ else if (e.key === "Enter") {
46
+ e.preventDefault();
47
+ let t = V[N];
48
+ t && U(t);
49
+ } else e.key === "Escape" && (k && e.preventDefault(), H());
50
+ }, G = /* @__PURE__ */ u("ul", {
51
+ ref: R,
52
+ id: `${E}-listbox`,
53
+ role: "listbox",
54
+ className: e(r.menu, w && r.portalled),
55
+ style: z,
56
+ children: V.length === 0 ? /* @__PURE__ */ u("li", {
57
+ className: r.empty,
58
+ children: C
59
+ }) : V.map((t, n) => /* @__PURE__ */ u("li", {
60
+ role: "option",
61
+ "aria-selected": t.value === h,
62
+ className: e(r.option, n === N && r.active, t.value === h && r.selected),
63
+ onMouseEnter: () => P(n),
64
+ onMouseDown: (e) => {
65
+ e.preventDefault(), U(t);
66
+ },
67
+ children: t.label
68
+ }, t.value))
69
+ });
70
+ return /* @__PURE__ */ d("div", {
71
+ ref: D,
72
+ className: e(r.wrapper, b && r.error, T),
28
73
  children: [
29
- m && /* @__PURE__ */ c("label", {
30
- htmlFor: S,
31
- className: t.label,
32
- children: m
74
+ _ && /* @__PURE__ */ u("label", {
75
+ htmlFor: E,
76
+ className: r.label,
77
+ children: _
33
78
  }),
34
- /* @__PURE__ */ l("div", {
35
- className: t.field,
36
- children: [/* @__PURE__ */ c("input", {
37
- id: S,
38
- ref: w,
79
+ /* @__PURE__ */ d("div", {
80
+ ref: I,
81
+ className: r.field,
82
+ children: [/* @__PURE__ */ u("input", {
83
+ id: E,
84
+ ref: O,
39
85
  type: "text",
40
86
  role: "combobox",
41
- "aria-expanded": T,
42
- "aria-controls": `${S}-listbox`,
87
+ "aria-expanded": k,
88
+ "aria-controls": `${E}-listbox`,
43
89
  "aria-autocomplete": "list",
44
- className: t.input,
45
- placeholder: h,
46
- disabled: v,
47
- value: T ? D : j,
48
- onFocus: () => E(!0),
90
+ className: r.input,
91
+ placeholder: v,
92
+ disabled: x,
93
+ value: k ? j : B,
94
+ onFocus: () => A(!0),
49
95
  onChange: (e) => {
50
- O(e.target.value), E(!0), A(0);
96
+ M(e.target.value), A(!0), P(0);
51
97
  },
52
- onKeyDown: (e) => {
53
- if (e.key === "ArrowDown") e.preventDefault(), E(!0), A((e) => Math.min(M.length - 1, e + 1));
54
- else if (e.key === "ArrowUp") e.preventDefault(), A((e) => Math.max(0, e - 1));
55
- else if (e.key === "Enter") {
56
- e.preventDefault();
57
- let t = M[k];
58
- t && P(t);
59
- } else e.key === "Escape" && N();
60
- }
61
- }), /* @__PURE__ */ c("span", {
62
- className: t.caret,
98
+ onKeyDown: W
99
+ }), /* @__PURE__ */ u("span", {
100
+ className: r.caret,
63
101
  "aria-hidden": !0,
64
102
  children: "▾"
65
103
  })]
66
104
  }),
67
- T && /* @__PURE__ */ c("ul", {
68
- id: `${S}-listbox`,
69
- role: "listbox",
70
- className: t.menu,
71
- children: M.length === 0 ? /* @__PURE__ */ c("li", {
72
- className: t.empty,
73
- children: b
74
- }) : M.map((n, r) => /* @__PURE__ */ c("li", {
75
- role: "option",
76
- "aria-selected": n.value === f,
77
- className: e(t.option, r === k && t.active, n.value === f && t.selected),
78
- onMouseEnter: () => A(r),
79
- onMouseDown: (e) => {
80
- e.preventDefault(), P(n);
81
- },
82
- children: n.label
83
- }, n.value))
84
- }),
85
- _ ? /* @__PURE__ */ c("span", {
86
- className: t.errorText,
87
- children: _
88
- }) : g ? /* @__PURE__ */ c("span", {
89
- className: t.helper,
90
- children: g
105
+ k && (w ? /* @__PURE__ */ u(t, { children: G }) : G),
106
+ b ? /* @__PURE__ */ u("span", {
107
+ className: r.errorText,
108
+ children: b
109
+ }) : y ? /* @__PURE__ */ u("span", {
110
+ className: r.helper,
111
+ children: y
91
112
  }) : null
92
113
  ]
93
114
  });
94
115
  }
95
116
  //#endregion
96
- export { d as Combobox };
117
+ export { m as Combobox };
97
118
 
98
119
  //# sourceMappingURL=Combobox.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Combobox.js","names":[],"sources":["../../../src/components/Combobox/Combobox.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — options/value/onChange\n * plus the shared field contract (label, placeholder, helperText, error, disabled,\n * className) and the three combobox-specific knobs: filter, emptyMessage. The body\n * is the listbox — open state, active descendant, type-ahead and the ARIA wiring —\n * and those cannot be separated without passing the same active index back and\n * forth.\n */\nimport { useCallback, useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Combobox.module.css\";\n\nexport interface ComboboxOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\nexport interface ComboboxProps {\n options: ComboboxOption[];\n value: string;\n onChange: (value: string) => void;\n label?: string;\n placeholder?: string;\n helperText?: string;\n error?: string;\n disabled?: boolean;\n /** Custom filter — return true to keep the option. Default is case-insensitive substring match on label. */\n filter?: (option: ComboboxOption, query: string) => boolean;\n /** Message shown when no option matches. */\n emptyMessage?: string;\n className?: string;\n}\n\nfunction defaultFilter(option: ComboboxOption, query: string): boolean {\n if (!query) return true;\n return option.label.toLowerCase().includes(query.toLowerCase());\n}\n\n/**\n * Combobox — text input with a filterable dropdown of options.\n *\n * Selecting an option fires `onChange(value)`. Typing filters the list.\n * Keyboard: ArrowUp/ArrowDown to navigate, Enter to select, Esc to close.\n */\nexport function Combobox({\n options,\n value,\n onChange,\n label,\n placeholder = \"Selecione\",\n helperText,\n error,\n disabled,\n filter = defaultFilter,\n emptyMessage = \"Nenhuma opção encontrada\",\n className,\n}: ComboboxProps) {\n const id = useId();\n const rootRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n const [activeIndex, setActiveIndex] = useState(0);\n\n const selectedLabel = useMemo(\n () => options.find((o) => o.value === value)?.label ?? \"\",\n [options, value],\n );\n\n const filtered = useMemo(\n () => options.filter((o) => filter(o, query)),\n [options, filter, query],\n );\n\n const closeAndReset = useCallback((): void => {\n setOpen(false);\n setQuery(\"\");\n setActiveIndex(0);\n }, []);\n\n const handleSelect = useCallback(\n (option: ComboboxOption): void => {\n if (option.disabled) return;\n onChange(option.value);\n closeAndReset();\n },\n [onChange, closeAndReset],\n );\n\n useEffect(() => {\n if (!open) return;\n const onDown = (event: MouseEvent): void => {\n if (rootRef.current && !rootRef.current.contains(event.target as Node)) {\n closeAndReset();\n }\n };\n window.addEventListener(\"mousedown\", onDown);\n return () => window.removeEventListener(\"mousedown\", onDown);\n }, [open, closeAndReset]);\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>): void => {\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n setOpen(true);\n setActiveIndex((current) => Math.min(filtered.length - 1, current + 1));\n } else if (event.key === \"ArrowUp\") {\n event.preventDefault();\n setActiveIndex((current) => Math.max(0, current - 1));\n } else if (event.key === \"Enter\") {\n event.preventDefault();\n const option = filtered[activeIndex];\n if (option) handleSelect(option);\n } else if (event.key === \"Escape\") {\n closeAndReset();\n }\n };\n\n return (\n <div ref={rootRef} className={cn(styles.wrapper, error && styles.error, className)}>\n {label && (\n <label htmlFor={id} className={styles.label}>\n {label}\n </label>\n )}\n <div className={styles.field}>\n <input\n id={id}\n ref={inputRef}\n type=\"text\"\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={`${id}-listbox`}\n aria-autocomplete=\"list\"\n className={styles.input}\n placeholder={placeholder}\n disabled={disabled}\n value={open ? query : selectedLabel}\n onFocus={() => setOpen(true)}\n onChange={(event) => {\n setQuery(event.target.value);\n setOpen(true);\n setActiveIndex(0);\n }}\n onKeyDown={handleKeyDown}\n />\n <span className={styles.caret} aria-hidden>\n ▾\n </span>\n </div>\n {open && (\n <ul id={`${id}-listbox`} role=\"listbox\" className={styles.menu}>\n {filtered.length === 0 ? (\n <li className={styles.empty}>{emptyMessage}</li>\n ) : (\n filtered.map((option, index) => (\n <li\n key={option.value}\n role=\"option\"\n aria-selected={option.value === value}\n className={cn(\n styles.option,\n index === activeIndex && styles.active,\n option.value === value && styles.selected,\n )}\n onMouseEnter={() => setActiveIndex(index)}\n onMouseDown={(event) => {\n event.preventDefault();\n handleSelect(option);\n }}\n >\n {option.label}\n </li>\n ))\n )}\n </ul>\n )}\n {error ? (\n <span className={styles.errorText}>{error}</span>\n ) : helperText ? (\n <span className={styles.helper}>{helperText}</span>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Combobox.js","names":[],"sources":["../../../src/components/Combobox/Combobox.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — options/value/onChange\n * plus the shared field contract (label, placeholder, helperText, error, disabled,\n * className) and the combobox-specific knobs: filter, emptyMessage, portal. The body\n * is the listbox — open state, active descendant, type-ahead and the ARIA wiring —\n * and those cannot be separated without passing the same active index back and\n * forth.\n */\nimport { useCallback, useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { Portal } from \"@/components/Portal\";\nimport { useAnchorPosition } from \"@/components/Portal/anchor-position\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Combobox.module.css\";\n\nexport interface ComboboxOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\nexport interface ComboboxProps {\n options: ComboboxOption[];\n value: string;\n onChange: (value: string) => void;\n label?: string;\n placeholder?: string;\n helperText?: string;\n error?: string;\n disabled?: boolean;\n /** Custom filter — return true to keep the option. Default is case-insensitive substring match on label. */\n filter?: (option: ComboboxOption, query: string) => boolean;\n /** Message shown when no option matches. */\n emptyMessage?: string;\n /**\n * Render the list in a portal, positioned under the field. Default `true`.\n *\n * In flow, an ancestor with `overflow` other than `visible` clips the list —\n * in the last row of a `DataTable` none of it was visible (measured in Chrome\n * at 1440 px). In a portal it escapes the clip, takes the field's width,\n * flips above the field when there is no room below, and follows it on\n * scroll, resize and when the field or the list changes size.\n */\n portal?: boolean;\n className?: string;\n}\n\n/** Gap between field and list, in px — the in-flow CSS uses the same 4 px. */\nconst LIST_OFFSET = 4;\n\nfunction defaultFilter(option: ComboboxOption, query: string): boolean {\n if (!query) return true;\n return option.label.toLowerCase().includes(query.toLowerCase());\n}\n\n/**\n * Combobox — text input with a filterable dropdown of options.\n *\n * Selecting an option fires `onChange(value)`. Typing filters the list.\n * Keyboard: ArrowUp/ArrowDown to navigate, Enter to select, Esc to close.\n */\nexport function Combobox({\n options,\n value,\n onChange,\n label,\n placeholder = \"Selecione\",\n helperText,\n error,\n disabled,\n filter = defaultFilter,\n emptyMessage = \"Nenhuma opção encontrada\",\n portal = true,\n className,\n}: ComboboxProps) {\n const id = useId();\n const rootRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n const [activeIndex, setActiveIndex] = useState(0);\n const [fieldNode, setFieldNode] = useState<HTMLDivElement | null>(null);\n const [listNode, setListNode] = useState<HTMLUListElement | null>(null);\n const floatingStyle = useAnchorPosition({\n anchor: fieldNode,\n floating: listNode,\n side: \"bottom\",\n align: \"start\",\n offset: LIST_OFFSET,\n enabled: portal && open,\n matchWidth: true,\n });\n\n const selectedLabel = useMemo(\n () => options.find((o) => o.value === value)?.label ?? \"\",\n [options, value],\n );\n\n const filtered = useMemo(\n () => options.filter((o) => filter(o, query)),\n [options, filter, query],\n );\n\n const closeAndReset = useCallback((): void => {\n setOpen(false);\n setQuery(\"\");\n setActiveIndex(0);\n }, []);\n\n const handleSelect = useCallback(\n (option: ComboboxOption): void => {\n if (option.disabled) return;\n onChange(option.value);\n closeAndReset();\n },\n [onChange, closeAndReset],\n );\n\n /**\n * Close on a press outside both the field and the list.\n *\n * The list is checked on its own because in a portal it is not inside the\n * field's wrapper: a press on its scrollbar, or on the empty message, would\n * otherwise count as outside and close it.\n */\n useEffect(() => {\n if (!open) return;\n const onDown = (event: MouseEvent): void => {\n const target = event.target as Node;\n if (rootRef.current?.contains(target) || listNode?.contains(target)) return;\n closeAndReset();\n };\n window.addEventListener(\"mousedown\", onDown);\n return () => window.removeEventListener(\"mousedown\", onDown);\n }, [open, closeAndReset, listNode]);\n\n /**\n * Keyboard model of the input.\n *\n * `Escape` calls `preventDefault()` only while the list is open: that marks the\n * key as consumed, so an enclosing `Modal` or `Drawer` stays open and the next\n * `Escape` reaches it. With the list closed the key is left alone and dismisses\n * the enclosing layer, as the user expects.\n */\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>): void => {\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n setOpen(true);\n setActiveIndex((current) => Math.min(filtered.length - 1, current + 1));\n } else if (event.key === \"ArrowUp\") {\n event.preventDefault();\n setActiveIndex((current) => Math.max(0, current - 1));\n } else if (event.key === \"Enter\") {\n event.preventDefault();\n const option = filtered[activeIndex];\n if (option) handleSelect(option);\n } else if (event.key === \"Escape\") {\n if (open) event.preventDefault();\n closeAndReset();\n }\n };\n\n const list = (\n <ul\n ref={setListNode}\n id={`${id}-listbox`}\n role=\"listbox\"\n className={cn(styles.menu, portal && styles.portalled)}\n style={floatingStyle}\n >\n {filtered.length === 0 ? (\n <li className={styles.empty}>{emptyMessage}</li>\n ) : (\n filtered.map((option, index) => (\n <li\n key={option.value}\n role=\"option\"\n aria-selected={option.value === value}\n className={cn(\n styles.option,\n index === activeIndex && styles.active,\n option.value === value && styles.selected,\n )}\n onMouseEnter={() => setActiveIndex(index)}\n onMouseDown={(event) => {\n event.preventDefault();\n handleSelect(option);\n }}\n >\n {option.label}\n </li>\n ))\n )}\n </ul>\n );\n\n return (\n <div ref={rootRef} className={cn(styles.wrapper, error && styles.error, className)}>\n {label && (\n <label htmlFor={id} className={styles.label}>\n {label}\n </label>\n )}\n <div ref={setFieldNode} className={styles.field}>\n <input\n id={id}\n ref={inputRef}\n type=\"text\"\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={`${id}-listbox`}\n aria-autocomplete=\"list\"\n className={styles.input}\n placeholder={placeholder}\n disabled={disabled}\n value={open ? query : selectedLabel}\n onFocus={() => setOpen(true)}\n onChange={(event) => {\n setQuery(event.target.value);\n setOpen(true);\n setActiveIndex(0);\n }}\n onKeyDown={handleKeyDown}\n />\n <span className={styles.caret} aria-hidden>\n ▾\n </span>\n </div>\n {open && (portal ? <Portal>{list}</Portal> : list)}\n {error ? (\n <span className={styles.errorText}>{error}</span>\n ) : helperText ? (\n <span className={styles.helper}>{helperText}</span>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
1
  require("../../styles/component/Combobox.css");
2
- var e=`tempest_wrapper_TNvle`,t=`tempest_label_KVkZO`,n=`tempest_field_BenH0`,r=`tempest_input_-HTv1`,i=`tempest_caret_jRplQ`,a=`tempest_menu_zPQG3`,o=`tempest_option_vhhn5`,s=`tempest_active_XCgtX`,c=`tempest_selected_T6nm2`,l=`tempest_empty_Ahw5K`,u=`tempest_helper_OzB7V`,d=`tempest_errorText_X18sQ`,f=`tempest_error_bnVuM`,p={wrapper:e,label:t,field:n,input:r,caret:i,menu:a,option:o,active:s,selected:c,empty:l,helper:u,errorText:d,error:f};exports.active=s,exports.caret=i,exports.default=p,exports.empty=l,exports.error=f,exports.errorText=d,exports.field=n,exports.helper=u,exports.input=r,exports.label=t,exports.menu=a,exports.option=o,exports.selected=c,exports.wrapper=e;
2
+ var e=`tempest_wrapper_TNvle`,t=`tempest_label_KVkZO`,n=`tempest_field_BenH0`,r=`tempest_input_-HTv1`,i=`tempest_caret_jRplQ`,a=`tempest_menu_zPQG3`,o=`tempest_option_vhhn5`,s=`tempest_active_XCgtX`,c=`tempest_selected_T6nm2`,l=`tempest_empty_Ahw5K`,u=`tempest_helper_OzB7V`,d=`tempest_errorText_X18sQ`,f=`tempest_error_bnVuM`,p=`tempest_portalled_C9jFy`,m={wrapper:e,label:t,field:n,input:r,caret:i,menu:a,option:o,active:s,selected:c,empty:l,helper:u,errorText:d,error:f,portalled:p};exports.active=s,exports.caret=i,exports.default=m,exports.empty=l,exports.error=f,exports.errorText=d,exports.field=n,exports.helper=u,exports.input=r,exports.label=t,exports.menu=a,exports.option=o,exports.portalled=p,exports.selected=c,exports.wrapper=e;
3
3
  //# sourceMappingURL=Combobox.module.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Combobox.module.cjs","names":[],"sources":["../../../src/components/Combobox/Combobox.module.css"],"sourcesContent":[".wrapper {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n width: 100%;\n font-family: var(--tempest-font-sans);\n position: relative;\n}\n\n.label {\n font-size: var(--tempest-text-sm);\n font-weight: var(--tempest-weight-semibold);\n color: var(--tempest-text);\n line-height: var(--tempest-leading-snug);\n}\n\n.field {\n position: relative;\n display: flex;\n align-items: center;\n}\n\n.input {\n width: 100%;\n height: var(--tempest-control-height-md);\n padding: 0 32px 0 var(--tempest-control-padding-md);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-control-radius);\n background-color: var(--tempest-bg);\n color: var(--tempest-text);\n font-family: inherit;\n font-size: var(--tempest-control-font-md);\n box-shadow: var(--tempest-shadow-xs);\n transition: var(--tempest-transition-color), var(--tempest-transition-shadow);\n}\n\n.input::placeholder {\n color: var(--tempest-text-subtle);\n}\n\n.input:focus {\n outline: none;\n border-color: var(--tempest-primary);\n box-shadow: 0 0 0 var(--tempest-focus-ring-width) var(--tempest-focus-ring-color);\n}\n\n.input:disabled {\n background-color: var(--tempest-surface);\n cursor: not-allowed;\n}\n\n.caret {\n position: absolute;\n right: 12px;\n pointer-events: none;\n color: var(--tempest-text-muted);\n}\n\n.menu {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n right: 0;\n z-index: var(--tempest-z-dropdown);\n background-color: var(--tempest-bg);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n box-shadow: var(--tempest-shadow-lg);\n max-height: 280px;\n overflow-y: auto;\n padding: var(--tempest-space-1);\n list-style: none;\n margin: 0;\n}\n\n.option {\n display: flex;\n align-items: center;\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border-radius: var(--tempest-radius-sm);\n cursor: pointer;\n color: var(--tempest-text);\n font-size: var(--tempest-text-base);\n line-height: var(--tempest-leading-snug);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .option:hover {\n background-color: var(--tempest-surface);\n }\n}\n\n.option.active {\n background-color: var(--tempest-primary-soft);\n color: var(--tempest-primary-on-soft);\n}\n\n.option.selected {\n font-weight: var(--tempest-weight-semibold);\n}\n\n.empty {\n padding: var(--tempest-space-3);\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-sm);\n text-align: center;\n}\n\n.helper {\n font-size: var(--tempest-text-xs);\n color: var(--tempest-text-muted);\n}\n\n.errorText {\n font-size: var(--tempest-text-xs);\n color: var(--tempest-danger);\n}\n\n.wrapper.error .input {\n border-color: var(--tempest-danger);\n}\n"],"mappings":";"}
1
+ {"version":3,"file":"Combobox.module.cjs","names":[],"sources":["../../../src/components/Combobox/Combobox.module.css"],"sourcesContent":[".wrapper {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n width: 100%;\n font-family: var(--tempest-font-sans);\n position: relative;\n}\n\n.label {\n font-size: var(--tempest-text-sm);\n font-weight: var(--tempest-weight-semibold);\n color: var(--tempest-text);\n line-height: var(--tempest-leading-snug);\n}\n\n.field {\n position: relative;\n display: flex;\n align-items: center;\n}\n\n.input {\n width: 100%;\n height: var(--tempest-control-height-md);\n padding: 0 32px 0 var(--tempest-control-padding-md);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-control-radius);\n background-color: var(--tempest-bg);\n color: var(--tempest-text);\n font-family: inherit;\n font-size: var(--tempest-control-font-md);\n box-shadow: var(--tempest-shadow-xs);\n transition: var(--tempest-transition-color), var(--tempest-transition-shadow);\n}\n\n.input::placeholder {\n color: var(--tempest-text-subtle);\n}\n\n.input:focus {\n outline: none;\n border-color: var(--tempest-primary);\n box-shadow: 0 0 0 var(--tempest-focus-ring-width) var(--tempest-focus-ring-color);\n}\n\n.input:disabled {\n background-color: var(--tempest-surface);\n cursor: not-allowed;\n}\n\n.caret {\n position: absolute;\n right: 12px;\n pointer-events: none;\n color: var(--tempest-text-muted);\n}\n\n.menu {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n right: 0;\n z-index: var(--tempest-z-dropdown);\n background-color: var(--tempest-bg);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n box-shadow: var(--tempest-shadow-lg);\n max-height: 280px;\n overflow-y: auto;\n padding: var(--tempest-space-1);\n list-style: none;\n margin: 0;\n}\n\n.option {\n display: flex;\n align-items: center;\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border-radius: var(--tempest-radius-sm);\n cursor: pointer;\n color: var(--tempest-text);\n font-size: var(--tempest-text-base);\n line-height: var(--tempest-leading-snug);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .option:hover {\n background-color: var(--tempest-surface);\n }\n}\n\n.option.active {\n background-color: var(--tempest-primary-soft);\n color: var(--tempest-primary-on-soft);\n}\n\n.option.selected {\n font-weight: var(--tempest-weight-semibold);\n}\n\n.empty {\n padding: var(--tempest-space-3);\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-sm);\n text-align: center;\n}\n\n.helper {\n font-size: var(--tempest-text-xs);\n color: var(--tempest-text-muted);\n}\n\n.errorText {\n font-size: var(--tempest-text-xs);\n color: var(--tempest-danger);\n}\n\n.wrapper.error .input {\n border-color: var(--tempest-danger);\n}\n\n.portalled {\n font-family: var(--tempest-font-sans);\n right: auto;\n z-index: var(--tempest-z-popover);\n}\n"],"mappings":";"}
@@ -1,6 +1,6 @@
1
1
  import "../../styles/component/Combobox.css";
2
2
  //#region src/components/Combobox/Combobox.module.css
3
- var e = "tempest_wrapper_TNvle", t = "tempest_label_KVkZO", n = "tempest_field_BenH0", r = "tempest_input_-HTv1", i = "tempest_caret_jRplQ", a = "tempest_menu_zPQG3", o = "tempest_option_vhhn5", s = "tempest_active_XCgtX", c = "tempest_selected_T6nm2", l = "tempest_empty_Ahw5K", u = "tempest_helper_OzB7V", d = "tempest_errorText_X18sQ", f = "tempest_error_bnVuM", p = {
3
+ var e = "tempest_wrapper_TNvle", t = "tempest_label_KVkZO", n = "tempest_field_BenH0", r = "tempest_input_-HTv1", i = "tempest_caret_jRplQ", a = "tempest_menu_zPQG3", o = "tempest_option_vhhn5", s = "tempest_active_XCgtX", c = "tempest_selected_T6nm2", l = "tempest_empty_Ahw5K", u = "tempest_helper_OzB7V", d = "tempest_errorText_X18sQ", f = "tempest_error_bnVuM", p = "tempest_portalled_C9jFy", m = {
4
4
  wrapper: e,
5
5
  label: t,
6
6
  field: n,
@@ -13,9 +13,10 @@ var e = "tempest_wrapper_TNvle", t = "tempest_label_KVkZO", n = "tempest_field_B
13
13
  empty: l,
14
14
  helper: u,
15
15
  errorText: d,
16
- error: f
16
+ error: f,
17
+ portalled: p
17
18
  };
18
19
  //#endregion
19
- export { s as active, i as caret, p as default, l as empty, f as error, d as errorText, n as field, u as helper, r as input, t as label, a as menu, o as option, c as selected, e as wrapper };
20
+ export { s as active, i as caret, m as default, l as empty, f as error, d as errorText, n as field, u as helper, r as input, t as label, a as menu, o as option, p as portalled, c as selected, e as wrapper };
20
21
 
21
22
  //# sourceMappingURL=Combobox.module.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Combobox.module.js","names":[],"sources":["../../../src/components/Combobox/Combobox.module.css"],"sourcesContent":[".wrapper {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n width: 100%;\n font-family: var(--tempest-font-sans);\n position: relative;\n}\n\n.label {\n font-size: var(--tempest-text-sm);\n font-weight: var(--tempest-weight-semibold);\n color: var(--tempest-text);\n line-height: var(--tempest-leading-snug);\n}\n\n.field {\n position: relative;\n display: flex;\n align-items: center;\n}\n\n.input {\n width: 100%;\n height: var(--tempest-control-height-md);\n padding: 0 32px 0 var(--tempest-control-padding-md);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-control-radius);\n background-color: var(--tempest-bg);\n color: var(--tempest-text);\n font-family: inherit;\n font-size: var(--tempest-control-font-md);\n box-shadow: var(--tempest-shadow-xs);\n transition: var(--tempest-transition-color), var(--tempest-transition-shadow);\n}\n\n.input::placeholder {\n color: var(--tempest-text-subtle);\n}\n\n.input:focus {\n outline: none;\n border-color: var(--tempest-primary);\n box-shadow: 0 0 0 var(--tempest-focus-ring-width) var(--tempest-focus-ring-color);\n}\n\n.input:disabled {\n background-color: var(--tempest-surface);\n cursor: not-allowed;\n}\n\n.caret {\n position: absolute;\n right: 12px;\n pointer-events: none;\n color: var(--tempest-text-muted);\n}\n\n.menu {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n right: 0;\n z-index: var(--tempest-z-dropdown);\n background-color: var(--tempest-bg);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n box-shadow: var(--tempest-shadow-lg);\n max-height: 280px;\n overflow-y: auto;\n padding: var(--tempest-space-1);\n list-style: none;\n margin: 0;\n}\n\n.option {\n display: flex;\n align-items: center;\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border-radius: var(--tempest-radius-sm);\n cursor: pointer;\n color: var(--tempest-text);\n font-size: var(--tempest-text-base);\n line-height: var(--tempest-leading-snug);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .option:hover {\n background-color: var(--tempest-surface);\n }\n}\n\n.option.active {\n background-color: var(--tempest-primary-soft);\n color: var(--tempest-primary-on-soft);\n}\n\n.option.selected {\n font-weight: var(--tempest-weight-semibold);\n}\n\n.empty {\n padding: var(--tempest-space-3);\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-sm);\n text-align: center;\n}\n\n.helper {\n font-size: var(--tempest-text-xs);\n color: var(--tempest-text-muted);\n}\n\n.errorText {\n font-size: var(--tempest-text-xs);\n color: var(--tempest-danger);\n}\n\n.wrapper.error .input {\n border-color: var(--tempest-danger);\n}\n"],"mappings":";"}
1
+ {"version":3,"file":"Combobox.module.js","names":[],"sources":["../../../src/components/Combobox/Combobox.module.css"],"sourcesContent":[".wrapper {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n width: 100%;\n font-family: var(--tempest-font-sans);\n position: relative;\n}\n\n.label {\n font-size: var(--tempest-text-sm);\n font-weight: var(--tempest-weight-semibold);\n color: var(--tempest-text);\n line-height: var(--tempest-leading-snug);\n}\n\n.field {\n position: relative;\n display: flex;\n align-items: center;\n}\n\n.input {\n width: 100%;\n height: var(--tempest-control-height-md);\n padding: 0 32px 0 var(--tempest-control-padding-md);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-control-radius);\n background-color: var(--tempest-bg);\n color: var(--tempest-text);\n font-family: inherit;\n font-size: var(--tempest-control-font-md);\n box-shadow: var(--tempest-shadow-xs);\n transition: var(--tempest-transition-color), var(--tempest-transition-shadow);\n}\n\n.input::placeholder {\n color: var(--tempest-text-subtle);\n}\n\n.input:focus {\n outline: none;\n border-color: var(--tempest-primary);\n box-shadow: 0 0 0 var(--tempest-focus-ring-width) var(--tempest-focus-ring-color);\n}\n\n.input:disabled {\n background-color: var(--tempest-surface);\n cursor: not-allowed;\n}\n\n.caret {\n position: absolute;\n right: 12px;\n pointer-events: none;\n color: var(--tempest-text-muted);\n}\n\n.menu {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n right: 0;\n z-index: var(--tempest-z-dropdown);\n background-color: var(--tempest-bg);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-lg);\n box-shadow: var(--tempest-shadow-lg);\n max-height: 280px;\n overflow-y: auto;\n padding: var(--tempest-space-1);\n list-style: none;\n margin: 0;\n}\n\n.option {\n display: flex;\n align-items: center;\n padding: var(--tempest-space-2) var(--tempest-space-3);\n border-radius: var(--tempest-radius-sm);\n cursor: pointer;\n color: var(--tempest-text);\n font-size: var(--tempest-text-base);\n line-height: var(--tempest-leading-snug);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .option:hover {\n background-color: var(--tempest-surface);\n }\n}\n\n.option.active {\n background-color: var(--tempest-primary-soft);\n color: var(--tempest-primary-on-soft);\n}\n\n.option.selected {\n font-weight: var(--tempest-weight-semibold);\n}\n\n.empty {\n padding: var(--tempest-space-3);\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-sm);\n text-align: center;\n}\n\n.helper {\n font-size: var(--tempest-text-xs);\n color: var(--tempest-text-muted);\n}\n\n.errorText {\n font-size: var(--tempest-text-xs);\n color: var(--tempest-danger);\n}\n\n.wrapper.error .input {\n border-color: var(--tempest-danger);\n}\n\n.portalled {\n font-family: var(--tempest-font-sans);\n right: auto;\n z-index: var(--tempest-z-popover);\n}\n"],"mappings":";"}
@@ -1,2 +1,2 @@
1
- const e=require("../../utils/cn.cjs"),t=require("../Portal/Portal.cjs"),n=require("./ContextMenu.module.cjs");let r=require("react"),i=require("react/jsx-runtime");var a=10;function o(e){return`separator`in e&&e.separator===!0}function s({items:s,children:l,className:u,trigger:d=`contextmenu`,longPressDelay:f=500,viewportMargin:p=8}){let[m,h]=(0,r.useState)(!1),[g,_]=(0,r.useState)({x:0,y:0}),[v,y]=(0,r.useState)(-1),b=(0,r.useId)(),[x,S]=(0,r.useState)(null),C=(0,r.useRef)([]),w=(0,r.useRef)(null),T=(0,r.useRef)(null),E=s.map((e,t)=>!o(e)&&!e.disabled?t:-1).filter(e=>e!==-1),D=(0,r.useCallback)(()=>{h(!1),y(-1)},[]),O=(0,r.useCallback)(e=>{_(e),y(-1),h(!0)},[]),k=(0,r.useCallback)(()=>{w.current!==null&&(clearTimeout(w.current),w.current=null),T.current=null},[]);(0,r.useEffect)(()=>k,[k]);let A=e=>{d!==`click`&&(e.preventDefault(),O({x:e.clientX,y:e.clientY}))},j=e=>{d!==`contextmenu`&&O({x:e.clientX,y:e.clientY})},M=e=>{if(f<=0||e.pointerType===`mouse`)return;let t={x:e.clientX,y:e.clientY};T.current=t,k(),T.current=t,w.current=setTimeout(()=>{w.current=null,T.current=null,c(),O(t)},f)},N=e=>{let t=T.current;t&&w.current!==null&&Math.hypot(e.clientX-t.x,e.clientY-t.y)>a&&k()};(0,r.useEffect)(()=>{if(!m)return;let e=e=>{if(e.key===`Escape`){D();return}let t=t=>{e.preventDefault(),y(t),C.current[t]?.focus()};if(E.length===0)return;let n=E.indexOf(v);e.key===`ArrowDown`&&t(E[(n+1)%E.length]??-1),e.key===`ArrowUp`&&t(E[(n-1+E.length)%E.length]??-1),e.key===`Home`&&t(E[0]??-1),e.key===`End`&&t(E[E.length-1]??-1)},t=e=>{x&&!x.contains(e.target)&&D()};return window.addEventListener(`keydown`,e),window.addEventListener(`mousedown`,t),window.addEventListener(`resize`,D),window.addEventListener(`scroll`,D,!0),()=>{window.removeEventListener(`keydown`,e),window.removeEventListener(`mousedown`,t),window.removeEventListener(`resize`,D),window.removeEventListener(`scroll`,D,!0)}},[m,v,E,D,x]),(0,r.useLayoutEffect)(()=>{if(!m||!x)return;x.focus({preventScroll:!0});let{offsetWidth:e,offsetHeight:t}=x;if(e===0&&t===0)return;let n=window.innerWidth-e-p,r=window.innerHeight-t-p,i=Math.max(p,Math.min(g.x,n)),a=Math.max(p,Math.min(g.y,r));(i!==g.x||a!==g.y)&&_({x:i,y:a})},[m,x,g.x,g.y,p]);let P=e=>{e.onSelect?.(),D()};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(`span`,{className:n.default.root,onContextMenu:A,onClick:j,onPointerDown:M,onPointerMove:N,onPointerUp:k,onPointerCancel:k,children:l}),m&&(0,i.jsx)(t.Portal,{children:(0,i.jsx)(`ul`,{ref:S,id:b,role:`menu`,"aria-orientation":`vertical`,tabIndex:-1,className:e.cn(n.default.menu,u),style:{top:g.y,left:g.x},children:s.map((t,r)=>o(t)?(0,i.jsx)(`li`,{role:`separator`,className:n.default.separator,"aria-hidden":!0},`separator-${r}`):(0,i.jsx)(`li`,{role:`none`,children:(0,i.jsx)(`button`,{ref:e=>{C.current[r]=e},type:`button`,role:`menuitem`,className:e.cn(n.default.item,t.danger&&n.default.danger,v===r&&n.default.active),disabled:t.disabled,onClick:()=>P(t),onMouseEnter:()=>y(r),children:t.label})},`item-${r}`))})})]})}function c(){typeof window>`u`||window.addEventListener(`click`,e=>{e.preventDefault(),e.stopPropagation()},{capture:!0,once:!0})}exports.ContextMenu=s;
1
+ const e=require("../../utils/cn.cjs"),t=require("../Portal/escape-layer.cjs"),n=require("../Portal/Portal.cjs"),r=require("./ContextMenu.module.cjs");let i=require("react"),a=require("react/jsx-runtime");var o=10;function s(e){return`separator`in e&&e.separator===!0}function c({items:c,children:u,className:d,trigger:f=`contextmenu`,longPressDelay:p=500,viewportMargin:m=8}){let[h,g]=(0,i.useState)(!1),[_,v]=(0,i.useState)({x:0,y:0}),[y,b]=(0,i.useState)(-1),x=(0,i.useId)(),[S,C]=(0,i.useState)(null),w=(0,i.useRef)([]),T=(0,i.useRef)(null),E=(0,i.useRef)(null),D=c.map((e,t)=>!s(e)&&!e.disabled?t:-1).filter(e=>e!==-1),O=(0,i.useCallback)(()=>{g(!1),b(-1)},[]),k=(0,i.useCallback)(e=>{v(e),b(-1),g(!0)},[]),A=(0,i.useCallback)(()=>{T.current!==null&&(clearTimeout(T.current),T.current=null),E.current=null},[]);(0,i.useEffect)(()=>A,[A]);let j=e=>{f!==`click`&&(e.preventDefault(),k({x:e.clientX,y:e.clientY}))},M=e=>{f!==`contextmenu`&&k({x:e.clientX,y:e.clientY})},N=e=>{if(p<=0||e.pointerType===`mouse`)return;let t={x:e.clientX,y:e.clientY};E.current=t,A(),E.current=t,T.current=setTimeout(()=>{T.current=null,E.current=null,l(),k(t)},p)},P=e=>{let t=E.current;t&&T.current!==null&&Math.hypot(e.clientX-t.x,e.clientY-t.y)>o&&A()};t.useEscapeLayer(h,O),(0,i.useEffect)(()=>{if(!h)return;let e=e=>{let t=t=>{e.preventDefault(),b(t),w.current[t]?.focus()};if(D.length===0)return;let n=D.indexOf(y);e.key===`ArrowDown`&&t(D[(n+1)%D.length]??-1),e.key===`ArrowUp`&&t(D[(n-1+D.length)%D.length]??-1),e.key===`Home`&&t(D[0]??-1),e.key===`End`&&t(D[D.length-1]??-1)},t=e=>{S&&!S.contains(e.target)&&O()};return window.addEventListener(`keydown`,e),window.addEventListener(`mousedown`,t),window.addEventListener(`resize`,O),window.addEventListener(`scroll`,O,!0),()=>{window.removeEventListener(`keydown`,e),window.removeEventListener(`mousedown`,t),window.removeEventListener(`resize`,O),window.removeEventListener(`scroll`,O,!0)}},[h,y,D,O,S]),(0,i.useLayoutEffect)(()=>{if(!h||!S)return;S.focus({preventScroll:!0});let{offsetWidth:e,offsetHeight:t}=S;if(e===0&&t===0)return;let n=window.innerWidth-e-m,r=window.innerHeight-t-m,i=Math.max(m,Math.min(_.x,n)),a=Math.max(m,Math.min(_.y,r));(i!==_.x||a!==_.y)&&v({x:i,y:a})},[h,S,_.x,_.y,m]);let F=e=>{e.onSelect?.(),O()};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(`span`,{className:r.default.root,onContextMenu:j,onClick:M,onPointerDown:N,onPointerMove:P,onPointerUp:A,onPointerCancel:A,children:u}),h&&(0,a.jsx)(n.Portal,{children:(0,a.jsx)(`ul`,{ref:C,id:x,role:`menu`,"aria-orientation":`vertical`,tabIndex:-1,className:e.cn(r.default.menu,d),style:{top:_.y,left:_.x},children:c.map((t,n)=>s(t)?(0,a.jsx)(`li`,{role:`separator`,className:r.default.separator,"aria-hidden":!0},`separator-${n}`):(0,a.jsx)(`li`,{role:`none`,children:(0,a.jsx)(`button`,{ref:e=>{w.current[n]=e},type:`button`,role:`menuitem`,className:e.cn(r.default.item,t.danger&&r.default.danger,y===n&&r.default.active),disabled:t.disabled,onClick:()=>F(t),onMouseEnter:()=>b(n),children:t.label})},`item-${n}`))})})]})}function l(){typeof window>`u`||window.addEventListener(`click`,e=>{e.preventDefault(),e.stopPropagation()},{capture:!0,once:!0})}exports.ContextMenu=c;
2
2
  //# sourceMappingURL=ContextMenu.cjs.map