@elliemae/ds-floating-context 3.61.5-rc.1 → 3.70.0-next.10

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 (50) hide show
  1. package/dist/cjs/DSFloatingContext.js +58 -27
  2. package/dist/cjs/DSFloatingContext.js.map +2 -2
  3. package/dist/cjs/hooks/useFloatingClickOutside.js +60 -0
  4. package/dist/cjs/hooks/useFloatingClickOutside.js.map +7 -0
  5. package/dist/cjs/hooks/useFloatingEscape.js +74 -0
  6. package/dist/cjs/hooks/useFloatingEscape.js.map +7 -0
  7. package/dist/cjs/hooks/useFloatingResizeObserver.js +46 -0
  8. package/dist/cjs/hooks/useFloatingResizeObserver.js.map +7 -0
  9. package/dist/cjs/hooks/useLatestRef.js +41 -0
  10. package/dist/cjs/hooks/useLatestRef.js.map +7 -0
  11. package/dist/cjs/hooks/useResolvedReference.js +52 -0
  12. package/dist/cjs/hooks/useResolvedReference.js.map +7 -0
  13. package/dist/cjs/package.json +4 -1
  14. package/dist/cjs/react-desc-prop-types.js +13 -2
  15. package/dist/cjs/react-desc-prop-types.js.map +2 -2
  16. package/dist/cjs/typescript-testing/typescript-floating-context-valid.js +5 -1
  17. package/dist/cjs/typescript-testing/typescript-floating-context-valid.js.map +2 -2
  18. package/dist/cjs/useComputedPositionStyles.js +4 -2
  19. package/dist/cjs/useComputedPositionStyles.js.map +2 -2
  20. package/dist/cjs/utils/computePosition.js +2 -2
  21. package/dist/cjs/utils/computePosition.js.map +2 -2
  22. package/dist/esm/DSFloatingContext.js +59 -28
  23. package/dist/esm/DSFloatingContext.js.map +2 -2
  24. package/dist/esm/hooks/useFloatingClickOutside.js +30 -0
  25. package/dist/esm/hooks/useFloatingClickOutside.js.map +7 -0
  26. package/dist/esm/hooks/useFloatingEscape.js +44 -0
  27. package/dist/esm/hooks/useFloatingEscape.js.map +7 -0
  28. package/dist/esm/hooks/useFloatingResizeObserver.js +16 -0
  29. package/dist/esm/hooks/useFloatingResizeObserver.js.map +7 -0
  30. package/dist/esm/hooks/useLatestRef.js +11 -0
  31. package/dist/esm/hooks/useLatestRef.js.map +7 -0
  32. package/dist/esm/hooks/useResolvedReference.js +22 -0
  33. package/dist/esm/hooks/useResolvedReference.js.map +7 -0
  34. package/dist/esm/package.json +4 -1
  35. package/dist/esm/react-desc-prop-types.js +13 -2
  36. package/dist/esm/react-desc-prop-types.js.map +2 -2
  37. package/dist/esm/typescript-testing/typescript-floating-context-valid.js +5 -1
  38. package/dist/esm/typescript-testing/typescript-floating-context-valid.js.map +2 -2
  39. package/dist/esm/useComputedPositionStyles.js +4 -2
  40. package/dist/esm/useComputedPositionStyles.js.map +2 -2
  41. package/dist/esm/utils/computePosition.js +2 -2
  42. package/dist/esm/utils/computePosition.js.map +2 -2
  43. package/dist/types/DSFloatingContext.d.ts +1 -1
  44. package/dist/types/hooks/useFloatingClickOutside.d.ts +20 -0
  45. package/dist/types/hooks/useFloatingEscape.d.ts +19 -0
  46. package/dist/types/hooks/useFloatingResizeObserver.d.ts +11 -0
  47. package/dist/types/hooks/useLatestRef.d.ts +7 -0
  48. package/dist/types/hooks/useResolvedReference.d.ts +19 -0
  49. package/dist/types/react-desc-prop-types.d.ts +19 -0
  50. package/package.json +6 -6
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/typescript-testing/typescript-floating-context-valid.tsx"],
4
- "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable @typescript-eslint/no-unused-vars, no-unused-vars */\nimport React from 'react';\nimport { FloatingWrapper } from '../index.js';\nimport type { DSHookFloatingContextT } from '../index.js';\n\n// test we expose the namespace and the namespace follows our deliverable conventions\ntype ComponentPropsForApp = DSHookFloatingContextT.Props;\ntype ComponentPropsInternals = DSHookFloatingContextT.InternalProps;\ntype ComponentPropsDefaultProps = DSHookFloatingContextT.DefaultProps;\ntype ComponentPropsOptionalProps = DSHookFloatingContextT.OptionalProps;\n\nconst testOptionalProps: ComponentPropsOptionalProps = {};\n\n// difference Props and InternalProps is that InternalProps has all the default props filled in\n// Props allows for partial defaults\nconst testPartialDefaults: Partial<ComponentPropsDefaultProps> = {\n withoutAnimation: false,\n withoutPortal: false,\n animationDuration: 300,\n};\n\n// InternalProps requires all defaults to be filled in\nconst testCompleteDefaults: Required<ComponentPropsDefaultProps> = {\n withoutAnimation: false,\n withoutPortal: false,\n animationDuration: 300,\n placement: 'top',\n customOffset: [10, 10],\n portalDOMContainer: document.body,\n};\n\nconst testInternalProps: ComponentPropsInternals = {\n ...testOptionalProps,\n ...testCompleteDefaults,\n};\n\nconst testInternalPropsAsSyntax = {\n ...testOptionalProps,\n ...testCompleteDefaults,\n} as ComponentPropsInternals;\n\n// using the explicit type definition, if there is an error, it will be marked on the key that is wrong\nconst testExplicitDefinition: ComponentPropsForApp = {\n animationDuration: 300,\n withoutAnimation: false,\n withoutPortal: false,\n placement: 'top',\n customOffset: [10, 10],\n portalDOMContainer: document.body,\n ...testOptionalProps,\n};\n\n// using the \"as\" syntax, if there is an error, it will be marking the whole object as wrong because it is not compatible with the type\nconst testInferedTypeCompatibility = {\n ...testOptionalProps,\n ...testPartialDefaults,\n animationDuration: 300,\n} as ComponentPropsForApp;\n\nconst testDefinitionAsConst = {\n animationDuration: 300,\n withoutAnimation: false,\n withoutPortal: false,\n placement: 'top',\n portalDOMContainer: document.body,\n} as const;\n\nconst ExampleUsageComponent = () => (\n <>\n {/* works with explicitly casted props, all syntaxes */}\n <FloatingWrapper\n {...testExplicitDefinition}\n innerRef={React.createRef<HTMLDivElement>()}\n isOpen\n floatingStyles={{}}\n >\n <div>Content</div>\n </FloatingWrapper>\n <FloatingWrapper\n {...testInferedTypeCompatibility}\n innerRef={React.createRef<HTMLDivElement>()}\n isOpen\n floatingStyles={{}}\n >\n <div>Content</div>\n </FloatingWrapper>\n <FloatingWrapper {...testDefinitionAsConst} innerRef={React.createRef<HTMLDivElement>()} isOpen floatingStyles={{}}>\n <div>Content</div>\n </FloatingWrapper>\n {/* works with inline values */}\n </>\n);\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;AAAA,YAAuB;ACoErB;AAnEF,mBAAkB;AAClB,eAAgC;AAShC,MAAM,oBAAiD,CAAC;AAIxD,MAAM,sBAA2D;AAAA,EAC/D,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,mBAAmB;AACrB;AAGA,MAAM,uBAA6D;AAAA,EACjE,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,mBAAmB;AAAA,EACnB,WAAW;AAAA,EACX,cAAc,CAAC,IAAI,EAAE;AAAA,EACrB,oBAAoB,SAAS;AAC/B;AAEA,MAAM,oBAA6C;AAAA,EACjD,GAAG;AAAA,EACH,GAAG;AACL;AAEA,MAAM,4BAA4B;AAAA,EAChC,GAAG;AAAA,EACH,GAAG;AACL;AAGA,MAAM,yBAA+C;AAAA,EACnD,mBAAmB;AAAA,EACnB,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,WAAW;AAAA,EACX,cAAc,CAAC,IAAI,EAAE;AAAA,EACrB,oBAAoB,SAAS;AAAA,EAC7B,GAAG;AACL;AAGA,MAAM,+BAA+B;AAAA,EACnC,GAAG;AAAA,EACH,GAAG;AAAA,EACH,mBAAmB;AACrB;AAEA,MAAM,wBAAwB;AAAA,EAC5B,mBAAmB;AAAA,EACnB,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,WAAW;AAAA,EACX,oBAAoB,SAAS;AAC/B;AAEA,MAAM,wBAAwB,MAC5B,4EAEE;AAAA;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,UAAU,aAAAA,QAAM,UAA0B;AAAA,MAC1C,QAAM;AAAA,MACN,gBAAgB,CAAC;AAAA,MAEjB,sDAAC,SAAI,qBAAO;AAAA;AAAA,EACd;AAAA,EACA;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,UAAU,aAAAA,QAAM,UAA0B;AAAA,MAC1C,QAAM;AAAA,MACN,gBAAgB,CAAC;AAAA,MAEjB,sDAAC,SAAI,qBAAO;AAAA;AAAA,EACd;AAAA,EACA,4CAAC,4BAAiB,GAAG,uBAAuB,UAAU,aAAAA,QAAM,UAA0B,GAAG,QAAM,MAAC,gBAAgB,CAAC,GAC/G,sDAAC,SAAI,qBAAO,GACd;AAAA,GAEF;",
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable @typescript-eslint/no-unused-vars, no-unused-vars */\nimport React from 'react';\nimport { FloatingWrapper } from '../index.js';\nimport type { DSHookFloatingContextT } from '../index.js';\n\n// test we expose the namespace and the namespace follows our deliverable conventions\ntype ComponentPropsForApp = DSHookFloatingContextT.Props;\ntype ComponentPropsInternals = DSHookFloatingContextT.InternalProps;\ntype ComponentPropsDefaultProps = DSHookFloatingContextT.DefaultProps;\ntype ComponentPropsOptionalProps = DSHookFloatingContextT.OptionalProps;\n\nconst testOptionalProps: ComponentPropsOptionalProps = {};\n\n// difference Props and InternalProps is that InternalProps has all the default props filled in\n// Props allows for partial defaults\nconst testPartialDefaults: Partial<ComponentPropsDefaultProps> = {\n withoutAnimation: false,\n withoutPortal: false,\n animationDuration: 300,\n};\n\n// InternalProps requires all defaults to be filled in\nconst testCompleteDefaults: Required<ComponentPropsDefaultProps> = {\n withoutAnimation: false,\n withoutPortal: false,\n animationDuration: 300,\n placement: 'top',\n customOffset: [10, 10],\n portalDOMContainer: document.body,\n closeOnEscape: false,\n returnFocusToReference: false,\n};\n\nconst testInternalProps: ComponentPropsInternals = {\n ...testOptionalProps,\n ...testCompleteDefaults,\n};\n\nconst testInternalPropsAsSyntax = {\n ...testOptionalProps,\n ...testCompleteDefaults,\n} as ComponentPropsInternals;\n\n// using the explicit type definition, if there is an error, it will be marked on the key that is wrong\nconst testExplicitDefinition: ComponentPropsForApp = {\n animationDuration: 300,\n withoutAnimation: false,\n withoutPortal: false,\n placement: 'top',\n customOffset: [10, 10],\n portalDOMContainer: document.body,\n closeOnEscape: false,\n returnFocusToReference: false,\n ...testOptionalProps,\n};\n\n// using the \"as\" syntax, if there is an error, it will be marking the whole object as wrong because it is not compatible with the type\nconst testInferedTypeCompatibility = {\n ...testOptionalProps,\n ...testPartialDefaults,\n animationDuration: 300,\n} as ComponentPropsForApp;\n\nconst testDefinitionAsConst = {\n animationDuration: 300,\n withoutAnimation: false,\n withoutPortal: false,\n placement: 'top',\n portalDOMContainer: document.body,\n} as const;\n\nconst ExampleUsageComponent = () => (\n <>\n {/* works with explicitly casted props, all syntaxes */}\n <FloatingWrapper\n {...testExplicitDefinition}\n innerRef={React.createRef<HTMLDivElement>()}\n isOpen\n floatingStyles={{}}\n >\n <div>Content</div>\n </FloatingWrapper>\n <FloatingWrapper\n {...testInferedTypeCompatibility}\n innerRef={React.createRef<HTMLDivElement>()}\n isOpen\n floatingStyles={{}}\n >\n <div>Content</div>\n </FloatingWrapper>\n <FloatingWrapper {...testDefinitionAsConst} innerRef={React.createRef<HTMLDivElement>()} isOpen floatingStyles={{}}>\n <div>Content</div>\n </FloatingWrapper>\n {/* works with inline values */}\n </>\n);\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;AAAA,YAAuB;ACwErB;AAvEF,mBAAkB;AAClB,eAAgC;AAShC,MAAM,oBAAiD,CAAC;AAIxD,MAAM,sBAA2D;AAAA,EAC/D,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,mBAAmB;AACrB;AAGA,MAAM,uBAA6D;AAAA,EACjE,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,mBAAmB;AAAA,EACnB,WAAW;AAAA,EACX,cAAc,CAAC,IAAI,EAAE;AAAA,EACrB,oBAAoB,SAAS;AAAA,EAC7B,eAAe;AAAA,EACf,wBAAwB;AAC1B;AAEA,MAAM,oBAA6C;AAAA,EACjD,GAAG;AAAA,EACH,GAAG;AACL;AAEA,MAAM,4BAA4B;AAAA,EAChC,GAAG;AAAA,EACH,GAAG;AACL;AAGA,MAAM,yBAA+C;AAAA,EACnD,mBAAmB;AAAA,EACnB,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,WAAW;AAAA,EACX,cAAc,CAAC,IAAI,EAAE;AAAA,EACrB,oBAAoB,SAAS;AAAA,EAC7B,eAAe;AAAA,EACf,wBAAwB;AAAA,EACxB,GAAG;AACL;AAGA,MAAM,+BAA+B;AAAA,EACnC,GAAG;AAAA,EACH,GAAG;AAAA,EACH,mBAAmB;AACrB;AAEA,MAAM,wBAAwB;AAAA,EAC5B,mBAAmB;AAAA,EACnB,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,WAAW;AAAA,EACX,oBAAoB,SAAS;AAC/B;AAEA,MAAM,wBAAwB,MAC5B,4EAEE;AAAA;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,UAAU,aAAAA,QAAM,UAA0B;AAAA,MAC1C,QAAM;AAAA,MACN,gBAAgB,CAAC;AAAA,MAEjB,sDAAC,SAAI,qBAAO;AAAA;AAAA,EACd;AAAA,EACA;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,UAAU,aAAAA,QAAM,UAA0B;AAAA,MAC1C,QAAM;AAAA,MACN,gBAAgB,CAAC;AAAA,MAEjB,sDAAC,SAAI,qBAAO;AAAA;AAAA,EACd;AAAA,EACA,4CAAC,4BAAiB,GAAG,uBAAuB,UAAU,aAAAA,QAAM,UAA0B,GAAG,QAAM,MAAC,gBAAgB,CAAC,GAC/G,sDAAC,SAAI,qBAAO,GACd;AAAA,GAEF;",
6
6
  "names": ["React"]
7
7
  }
@@ -50,7 +50,8 @@ const useComputedPositionStyles = (config) => {
50
50
  const [floatingStyles, setFloatingStyles] = (0, import_react.useState)({
51
51
  position: "absolute",
52
52
  zIndex: 3e3,
53
- visibility: "hidden",
53
+ opacity: 0,
54
+ pointerEvents: "none",
54
55
  willChange: "transform"
55
56
  });
56
57
  const [hasComputedOnce, setHasComputedOnce] = (0, import_react.useState)(false);
@@ -99,7 +100,8 @@ const useComputedPositionStyles = (config) => {
99
100
  const resetVisibilityOnly = (0, import_react.useCallback)(() => {
100
101
  setFloatingStyles((prev) => ({
101
102
  ...prev,
102
- visibility: "hidden"
103
+ opacity: 0,
104
+ pointerEvents: "none"
103
105
  }));
104
106
  }, []);
105
107
  return (0, import_react.useMemo)(
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/useComputedPositionStyles.tsx", "../../../../../scripts/build/transpile/react-shim.js"],
4
- "sourcesContent": ["/* eslint-disable max-statements */\nimport { useLayoutEffect, useMemo, useRef, useState, useCallback } from 'react';\nimport { debounce } from 'lodash-es';\nimport { type CSSProperties } from 'styled-components';\nimport { computePosition } from './utils/computePosition.js';\nimport type { DSHookFloatingContextT } from './react-desc-prop-types.js';\nimport type { PopoverArrowT } from './parts/PopoverArrow.js';\n\ntype UseComputedPositionStylesT = {\n /** Prevent computing when closed (optimization + avoids unnecessary frames) */\n preventComputing?: boolean;\n reference: Element | null;\n floating: HTMLElement | null;\n placement: DSHookFloatingContextT.PopperPlacementsT;\n placementOrderPreference?: DSHookFloatingContextT.PopperPlacementsT[];\n customOffset: [number, number];\n withoutPortal: boolean;\n /** Debounce ms for scroll/resize/observer events */\n debounceMs?: number;\n};\n\nexport const useComputedPositionStyles = (config: UseComputedPositionStylesT) => {\n const {\n reference,\n floating,\n placement,\n placementOrderPreference,\n customOffset,\n withoutPortal,\n preventComputing = false,\n debounceMs = 150,\n } = config;\n\n const [arrowStyles, setArrowStyles] = useState<PopoverArrowT>({ style: { left: 0 }, placement: 'top' });\n\n // Important: do not initialize top/left to (0,0); keep hidden until the first computation\n const [floatingStyles, setFloatingStyles] = useState<CSSProperties>({\n position: 'absolute',\n zIndex: 3000,\n visibility: 'hidden',\n willChange: 'transform',\n });\n\n const [hasComputedOnce, setHasComputedOnce] = useState(false);\n\n const canCompute = reference !== null && floating !== null && !preventComputing;\n\n const updateStyles = useCallback(() => {\n if (!canCompute) return;\n\n const { coordsStyle, finalPlacement, coordsArrow } = computePosition({\n reference,\n floating,\n placement,\n placementOrderPreference,\n customOffset,\n withoutPortal,\n });\n\n // Do not touch visibility here; it is managed outside depending on open/hasComputedOnce\n setFloatingStyles((prev) => ({\n position: 'absolute',\n zIndex: 3000,\n ...prev,\n ...coordsStyle,\n }));\n setArrowStyles({ style: coordsArrow, placement: finalPlacement });\n setHasComputedOnce(true);\n }, [canCompute, reference, floating, placement, placementOrderPreference, customOffset, withoutPortal]);\n\n // Store latest update function in a ref to keep debounced stable\n const mutableUpdateStyles = useRef(updateStyles);\n mutableUpdateStyles.current = updateStyles;\n\n const debouncedUpdateStyles = useMemo(() => {\n const d = debounce(() => {\n mutableUpdateStyles.current();\n }, debounceMs);\n return d;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [debounceMs]);\n\n // Clean up debounce on unmount\n useLayoutEffect(\n () => () => {\n debouncedUpdateStyles.cancel();\n },\n [debouncedUpdateStyles],\n );\n\n // Recalculate BEFORE paint when dependencies change\n useLayoutEffect(() => {\n if (canCompute) {\n mutableUpdateStyles.current();\n }\n }, [canCompute, reference, floating, placement, placementOrderPreference, customOffset, withoutPortal]);\n\n const forceUpdatePosition = useCallback(() => {\n mutableUpdateStyles.current();\n }, []);\n\n // Do not reset coordinates when closing; just hide\n const resetVisibilityOnly = useCallback(() => {\n setFloatingStyles((prev) => ({\n ...prev,\n visibility: 'hidden',\n }));\n }, []);\n\n return useMemo(\n () => ({\n arrowStyles,\n floatingStyles,\n hasComputedOnce,\n updateStyles: forceUpdatePosition,\n debouncedUpdateStyles,\n mutableUpdateStyles,\n resetVisibilityOnly,\n }),\n [arrowStyles, floatingStyles, hasComputedOnce, forceUpdatePosition, debouncedUpdateStyles, resetVisibilityOnly],\n );\n};\n", "import * as React from 'react';\nexport { React };\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADCvB,mBAAwE;AACxE,uBAAyB;AAEzB,6BAAgC;AAiBzB,MAAM,4BAA4B,CAAC,WAAuC;AAC/E,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,mBAAmB;AAAA,IACnB,aAAa;AAAA,EACf,IAAI;AAEJ,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAwB,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,WAAW,MAAM,CAAC;AAGtG,QAAM,CAAC,gBAAgB,iBAAiB,QAAI,uBAAwB;AAAA,IAClE,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,YAAY;AAAA,EACd,CAAC;AAED,QAAM,CAAC,iBAAiB,kBAAkB,QAAI,uBAAS,KAAK;AAE5D,QAAM,aAAa,cAAc,QAAQ,aAAa,QAAQ,CAAC;AAE/D,QAAM,mBAAe,0BAAY,MAAM;AACrC,QAAI,CAAC,WAAY;AAEjB,UAAM,EAAE,aAAa,gBAAgB,YAAY,QAAI,wCAAgB;AAAA,MACnE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAGD,sBAAkB,CAAC,UAAU;AAAA,MAC3B,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,GAAG;AAAA,MACH,GAAG;AAAA,IACL,EAAE;AACF,mBAAe,EAAE,OAAO,aAAa,WAAW,eAAe,CAAC;AAChE,uBAAmB,IAAI;AAAA,EACzB,GAAG,CAAC,YAAY,WAAW,UAAU,WAAW,0BAA0B,cAAc,aAAa,CAAC;AAGtG,QAAM,0BAAsB,qBAAO,YAAY;AAC/C,sBAAoB,UAAU;AAE9B,QAAM,4BAAwB,sBAAQ,MAAM;AAC1C,UAAM,QAAI,2BAAS,MAAM;AACvB,0BAAoB,QAAQ;AAAA,IAC9B,GAAG,UAAU;AACb,WAAO;AAAA,EAET,GAAG,CAAC,UAAU,CAAC;AAGf;AAAA,IACE,MAAM,MAAM;AACV,4BAAsB,OAAO;AAAA,IAC/B;AAAA,IACA,CAAC,qBAAqB;AAAA,EACxB;AAGA,oCAAgB,MAAM;AACpB,QAAI,YAAY;AACd,0BAAoB,QAAQ;AAAA,IAC9B;AAAA,EACF,GAAG,CAAC,YAAY,WAAW,UAAU,WAAW,0BAA0B,cAAc,aAAa,CAAC;AAEtG,QAAM,0BAAsB,0BAAY,MAAM;AAC5C,wBAAoB,QAAQ;AAAA,EAC9B,GAAG,CAAC,CAAC;AAGL,QAAM,0BAAsB,0BAAY,MAAM;AAC5C,sBAAkB,CAAC,UAAU;AAAA,MAC3B,GAAG;AAAA,MACH,YAAY;AAAA,IACd,EAAE;AAAA,EACJ,GAAG,CAAC,CAAC;AAEL,aAAO;AAAA,IACL,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA,cAAc;AAAA,MACd;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,CAAC,aAAa,gBAAgB,iBAAiB,qBAAqB,uBAAuB,mBAAmB;AAAA,EAChH;AACF;",
4
+ "sourcesContent": ["/* eslint-disable max-statements */\nimport { useLayoutEffect, useMemo, useRef, useState, useCallback } from 'react';\nimport { debounce } from 'lodash-es';\nimport { type CSSProperties } from 'styled-components';\nimport { computePosition } from './utils/computePosition.js';\nimport type { DSHookFloatingContextT } from './react-desc-prop-types.js';\nimport type { PopoverArrowT } from './parts/PopoverArrow.js';\n\ntype UseComputedPositionStylesT = {\n /** Prevent computing when closed (optimization + avoids unnecessary frames) */\n preventComputing?: boolean;\n reference: Element | null;\n floating: HTMLElement | null;\n placement: DSHookFloatingContextT.PopperPlacementsT;\n placementOrderPreference?: DSHookFloatingContextT.PopperPlacementsT[];\n customOffset: [number, number];\n withoutPortal: boolean;\n /** Debounce ms for scroll/resize/observer events */\n debounceMs?: number;\n};\n\nexport const useComputedPositionStyles = (config: UseComputedPositionStylesT) => {\n const {\n reference,\n floating,\n placement,\n placementOrderPreference,\n customOffset,\n withoutPortal,\n preventComputing = false,\n debounceMs = 150,\n } = config;\n\n const [arrowStyles, setArrowStyles] = useState<PopoverArrowT>({ style: { left: 0 }, placement: 'top' });\n\n // Initial state: invisible (opacity:0) but FOCUSABLE.\n // We intentionally use opacity instead of visibility:hidden \u2014 `visibility:hidden` blocks\n // programmatic focus on descendants (including React's `autoFocus` attribute on inputs),\n // which causes a race on first-open: the floating content's autoFocus fires before the\n // position-computation useLayoutEffect can flip visibility to `visible`, so the focus\n // silently no-ops. Opacity:0 keeps the element invisible while letting `.focus()` work.\n // pointer-events:none prevents accidental clicks on the still-unpositioned (0,0) area.\n const [floatingStyles, setFloatingStyles] = useState<CSSProperties>({\n position: 'absolute',\n zIndex: 3000,\n opacity: 0,\n pointerEvents: 'none',\n willChange: 'transform',\n });\n\n const [hasComputedOnce, setHasComputedOnce] = useState(false);\n\n const canCompute = reference !== null && floating !== null && !preventComputing;\n\n const updateStyles = useCallback(() => {\n if (!canCompute) return;\n\n const { coordsStyle, finalPlacement, coordsArrow } = computePosition({\n reference,\n floating,\n placement,\n placementOrderPreference,\n customOffset,\n withoutPortal,\n });\n\n // Do not touch visibility here; it is managed outside depending on open/hasComputedOnce\n setFloatingStyles((prev) => ({\n position: 'absolute',\n zIndex: 3000,\n ...prev,\n ...coordsStyle,\n }));\n setArrowStyles({ style: coordsArrow, placement: finalPlacement });\n setHasComputedOnce(true);\n }, [canCompute, reference, floating, placement, placementOrderPreference, customOffset, withoutPortal]);\n\n // Store latest update function in a ref to keep debounced stable\n const mutableUpdateStyles = useRef(updateStyles);\n mutableUpdateStyles.current = updateStyles;\n\n const debouncedUpdateStyles = useMemo(() => {\n const d = debounce(() => {\n mutableUpdateStyles.current();\n }, debounceMs);\n return d;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [debounceMs]);\n\n // Clean up debounce on unmount\n useLayoutEffect(\n () => () => {\n debouncedUpdateStyles.cancel();\n },\n [debouncedUpdateStyles],\n );\n\n // Recalculate BEFORE paint when dependencies change\n useLayoutEffect(() => {\n if (canCompute) {\n mutableUpdateStyles.current();\n }\n }, [canCompute, reference, floating, placement, placementOrderPreference, customOffset, withoutPortal]);\n\n const forceUpdatePosition = useCallback(() => {\n mutableUpdateStyles.current();\n }, []);\n\n // Do not reset coordinates when closing; just hide via opacity (keeps element focusable\n // if anything inside needs to remain focusable during animations).\n const resetVisibilityOnly = useCallback(() => {\n setFloatingStyles((prev) => ({\n ...prev,\n opacity: 0,\n pointerEvents: 'none',\n }));\n }, []);\n\n return useMemo(\n () => ({\n arrowStyles,\n floatingStyles,\n hasComputedOnce,\n updateStyles: forceUpdatePosition,\n debouncedUpdateStyles,\n mutableUpdateStyles,\n resetVisibilityOnly,\n }),\n [arrowStyles, floatingStyles, hasComputedOnce, forceUpdatePosition, debouncedUpdateStyles, resetVisibilityOnly],\n );\n};\n", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADCvB,mBAAwE;AACxE,uBAAyB;AAEzB,6BAAgC;AAiBzB,MAAM,4BAA4B,CAAC,WAAuC;AAC/E,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,mBAAmB;AAAA,IACnB,aAAa;AAAA,EACf,IAAI;AAEJ,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAwB,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,WAAW,MAAM,CAAC;AAStG,QAAM,CAAC,gBAAgB,iBAAiB,QAAI,uBAAwB;AAAA,IAClE,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,eAAe;AAAA,IACf,YAAY;AAAA,EACd,CAAC;AAED,QAAM,CAAC,iBAAiB,kBAAkB,QAAI,uBAAS,KAAK;AAE5D,QAAM,aAAa,cAAc,QAAQ,aAAa,QAAQ,CAAC;AAE/D,QAAM,mBAAe,0BAAY,MAAM;AACrC,QAAI,CAAC,WAAY;AAEjB,UAAM,EAAE,aAAa,gBAAgB,YAAY,QAAI,wCAAgB;AAAA,MACnE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAGD,sBAAkB,CAAC,UAAU;AAAA,MAC3B,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,GAAG;AAAA,MACH,GAAG;AAAA,IACL,EAAE;AACF,mBAAe,EAAE,OAAO,aAAa,WAAW,eAAe,CAAC;AAChE,uBAAmB,IAAI;AAAA,EACzB,GAAG,CAAC,YAAY,WAAW,UAAU,WAAW,0BAA0B,cAAc,aAAa,CAAC;AAGtG,QAAM,0BAAsB,qBAAO,YAAY;AAC/C,sBAAoB,UAAU;AAE9B,QAAM,4BAAwB,sBAAQ,MAAM;AAC1C,UAAM,QAAI,2BAAS,MAAM;AACvB,0BAAoB,QAAQ;AAAA,IAC9B,GAAG,UAAU;AACb,WAAO;AAAA,EAET,GAAG,CAAC,UAAU,CAAC;AAGf;AAAA,IACE,MAAM,MAAM;AACV,4BAAsB,OAAO;AAAA,IAC/B;AAAA,IACA,CAAC,qBAAqB;AAAA,EACxB;AAGA,oCAAgB,MAAM;AACpB,QAAI,YAAY;AACd,0BAAoB,QAAQ;AAAA,IAC9B;AAAA,EACF,GAAG,CAAC,YAAY,WAAW,UAAU,WAAW,0BAA0B,cAAc,aAAa,CAAC;AAEtG,QAAM,0BAAsB,0BAAY,MAAM;AAC5C,wBAAoB,QAAQ;AAAA,EAC9B,GAAG,CAAC,CAAC;AAIL,QAAM,0BAAsB,0BAAY,MAAM;AAC5C,sBAAkB,CAAC,UAAU;AAAA,MAC3B,GAAG;AAAA,MACH,SAAS;AAAA,MACT,eAAe;AAAA,IACjB,EAAE;AAAA,EACJ,GAAG,CAAC,CAAC;AAEL,aAAO;AAAA,IACL,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA,cAAc;AAAA,MACd;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,CAAC,aAAa,gBAAgB,iBAAiB,qBAAqB,uBAAuB,mBAAmB;AAAA,EAChH;AACF;",
6
6
  "names": []
7
7
  }
@@ -75,8 +75,8 @@ const computePosition = (props) => {
75
75
  y += window.scrollY;
76
76
  } else {
77
77
  const op = (0, import_floatingPositioning.getOffsetParentData)(floating);
78
- x = x - op.left + op.scrollLeft;
79
- y = y - op.top + op.scrollTop;
78
+ x = x + clippingRect.left - op.left + op.scrollLeft;
79
+ y = y + clippingRect.top - op.top + op.scrollTop;
80
80
  }
81
81
  ({ x, y } = (0, import_floatingPositioning.applyShift)(x, y, overflows));
82
82
  const coordsArrow = (0, import_getArrowOffset.getArrowOffsetDynamic)({
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/utils/computePosition.ts", "../../../../../../scripts/build/transpile/react-shim.js"],
4
- "sourcesContent": ["/* eslint-disable max-lines */\n/* eslint-disable no-nested-ternary */\n/* eslint-disable complexity */\n/* eslint-disable max-statements */\n/* eslint-disable @typescript-eslint/no-use-before-define */\n/* eslint-disable max-params */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable arrow-body-style */\nimport type { DSHookFloatingContextT } from '../react-desc-prop-types.js';\nimport { getExpandedFallbackPlacements } from './getExpandedFallbackPlacements.js';\nimport { getArrowOffsetDynamic } from './getArrowOffset.js';\nimport { detectOverflow } from './detectOverflow.js';\nimport {\n applyShift,\n adjustForFixedParent,\n expandWithVariations,\n fits,\n getClippingParent,\n getOverflowScore,\n getOffsetParentData,\n getViewportRect,\n type RectLike,\n type OverflowOffsets,\n} from './floatingPositioning.js';\n\ninterface ComputePositionProps {\n reference: Element;\n floating: HTMLElement;\n placement: DSHookFloatingContextT.PopperPlacementsT;\n placementOrderPreference?: DSHookFloatingContextT.PopperPlacementsT[];\n customOffset: [number, number];\n withoutPortal: boolean;\n}\n\nexport const computePosition = (props: ComputePositionProps) => {\n const { reference, floating, placement, placementOrderPreference, customOffset, withoutPortal } = props;\n\n // When WITHOUT portal: only apply fixed-parent offsets (absolute parents scroll and must NOT be treated as fixed)\n const parentOffsets = withoutPortal ? adjustForFixedParent(reference) : { top: 0, left: 0 };\n\n const referenceRect = reference.getBoundingClientRect();\n const floatingRect = floating.getBoundingClientRect();\n\n const fallbackPlacements = placementOrderPreference || getExpandedFallbackPlacements(placement);\n\n const placements = expandWithVariations(\n [placement].concat(fallbackPlacements as DSHookFloatingContextT.PopperPlacementsT[]),\n );\n\n // Boundary selection:\n // - Portal => viewport (inset by body padding for Storybook)\n // - No portal => nearest clipping/scroll container (fallback viewport rect)\n const clippingParent = withoutPortal ? getClippingParent(reference) : null;\n const clippingRect: RectLike = clippingParent ? clippingParent.getBoundingClientRect() : getViewportRect();\n\n // Best-fit selection:\n // 1) choose first placement that fully fits\n // 2) otherwise choose placement with smallest max overflow, tie-break by total overflow\n let bestPlacement = placement;\n let bestOverflows: OverflowOffsets | null = null;\n let bestScore = { total: Number.POSITIVE_INFINITY, maxSide: Number.POSITIVE_INFINITY };\n\n for (let i = 0; i < placements.length; i += 1) {\n const currentPlacement = placements[i];\n\n const overflows = detectOverflow(referenceRect, floatingRect, currentPlacement, customOffset, clippingRect);\n\n if (fits(overflows)) {\n bestPlacement = currentPlacement;\n bestOverflows = overflows;\n break;\n }\n\n const score = getOverflowScore(overflows);\n\n const isBetter =\n score.maxSide < bestScore.maxSide || (score.maxSide === bestScore.maxSide && score.total < bestScore.total);\n\n if (isBetter) {\n bestPlacement = currentPlacement;\n bestOverflows = overflows;\n bestScore = score;\n }\n }\n\n const finalPlacement = bestPlacement;\n\n const overflows =\n bestOverflows ?? detectOverflow(referenceRect, floatingRect, finalPlacement, customOffset, clippingRect);\n\n // Convert overflow -> coordinates.\n // detectOverflow uses viewport/clipping-rect coordinates.\n //\n // - If tooltip is rendered IN A PORTAL (withoutPortal === false) and is positioned with `position: absolute`,\n // convert viewport coords to page coords by adding window.scrollX/Y.\n //\n // - If tooltip is rendered WITHOUT portal, convert viewport coords to offsetParent coords\n // (subtract offsetParent rect, add its scroll).\n let x = -overflows.left - parentOffsets.left;\n let y = -overflows.top - parentOffsets.top;\n\n if (!withoutPortal) {\n x += window.scrollX;\n y += window.scrollY;\n } else {\n const op = getOffsetParentData(floating);\n x = x - op.left + op.scrollLeft;\n y = y - op.top + op.scrollTop;\n }\n\n // Always shift back inside boundary\n ({ x, y } = applyShift(x, y, overflows));\n\n const coordsArrow = getArrowOffsetDynamic({\n placement: finalPlacement,\n referenceRect,\n floatingRect,\n x,\n y,\n withoutPortal,\n parentOffsets,\n floatingEl: floating,\n arrowPadding: 12,\n });\n\n return {\n coordsStyle: {\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n top: 0,\n left: 0,\n },\n finalPlacement,\n coordsArrow,\n };\n};\n", "import * as React from 'react';\nexport { React };\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADSvB,2CAA8C;AAC9C,4BAAsC;AACtC,4BAA+B;AAC/B,iCAWO;AAWA,MAAM,kBAAkB,CAAC,UAAgC;AAC9D,QAAM,EAAE,WAAW,UAAU,WAAW,0BAA0B,cAAc,cAAc,IAAI;AAGlG,QAAM,gBAAgB,oBAAgB,iDAAqB,SAAS,IAAI,EAAE,KAAK,GAAG,MAAM,EAAE;AAE1F,QAAM,gBAAgB,UAAU,sBAAsB;AACtD,QAAM,eAAe,SAAS,sBAAsB;AAEpD,QAAM,qBAAqB,gCAA4B,oEAA8B,SAAS;AAE9F,QAAM,iBAAa;AAAA,IACjB,CAAC,SAAS,EAAE,OAAO,kBAAgE;AAAA,EACrF;AAKA,QAAM,iBAAiB,oBAAgB,8CAAkB,SAAS,IAAI;AACtE,QAAM,eAAyB,iBAAiB,eAAe,sBAAsB,QAAI,4CAAgB;AAKzG,MAAI,gBAAgB;AACpB,MAAI,gBAAwC;AAC5C,MAAI,YAAY,EAAE,OAAO,OAAO,mBAAmB,SAAS,OAAO,kBAAkB;AAErF,WAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK,GAAG;AAC7C,UAAM,mBAAmB,WAAW,CAAC;AAErC,UAAMA,iBAAY,sCAAe,eAAe,cAAc,kBAAkB,cAAc,YAAY;AAE1G,YAAI,iCAAKA,UAAS,GAAG;AACnB,sBAAgB;AAChB,sBAAgBA;AAChB;AAAA,IACF;AAEA,UAAM,YAAQ,6CAAiBA,UAAS;AAExC,UAAM,WACJ,MAAM,UAAU,UAAU,WAAY,MAAM,YAAY,UAAU,WAAW,MAAM,QAAQ,UAAU;AAEvG,QAAI,UAAU;AACZ,sBAAgB;AAChB,sBAAgBA;AAChB,kBAAY;AAAA,IACd;AAAA,EACF;AAEA,QAAM,iBAAiB;AAEvB,QAAM,YACJ,qBAAiB,sCAAe,eAAe,cAAc,gBAAgB,cAAc,YAAY;AAUzG,MAAI,IAAI,CAAC,UAAU,OAAO,cAAc;AACxC,MAAI,IAAI,CAAC,UAAU,MAAM,cAAc;AAEvC,MAAI,CAAC,eAAe;AAClB,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd,OAAO;AACL,UAAM,SAAK,gDAAoB,QAAQ;AACvC,QAAI,IAAI,GAAG,OAAO,GAAG;AACrB,QAAI,IAAI,GAAG,MAAM,GAAG;AAAA,EACtB;AAGA,GAAC,EAAE,GAAG,EAAE,QAAI,uCAAW,GAAG,GAAG,SAAS;AAEtC,QAAM,kBAAc,6CAAsB;AAAA,IACxC,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB,CAAC;AAED,SAAO;AAAA,IACL,aAAa;AAAA,MACX,WAAW,eAAe,KAAK,MAAM,CAAC,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC;AAAA,MAC3D,KAAK;AAAA,MACL,MAAM;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["/* eslint-disable max-lines */\n/* eslint-disable no-nested-ternary */\n/* eslint-disable complexity */\n/* eslint-disable max-statements */\n/* eslint-disable @typescript-eslint/no-use-before-define */\n/* eslint-disable max-params */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable arrow-body-style */\nimport type { DSHookFloatingContextT } from '../react-desc-prop-types.js';\nimport { getExpandedFallbackPlacements } from './getExpandedFallbackPlacements.js';\nimport { getArrowOffsetDynamic } from './getArrowOffset.js';\nimport { detectOverflow } from './detectOverflow.js';\nimport {\n applyShift,\n adjustForFixedParent,\n expandWithVariations,\n fits,\n getClippingParent,\n getOverflowScore,\n getOffsetParentData,\n getViewportRect,\n type RectLike,\n type OverflowOffsets,\n} from './floatingPositioning.js';\n\ninterface ComputePositionProps {\n reference: Element;\n floating: HTMLElement;\n placement: DSHookFloatingContextT.PopperPlacementsT;\n placementOrderPreference?: DSHookFloatingContextT.PopperPlacementsT[];\n customOffset: [number, number];\n withoutPortal: boolean;\n}\n\nexport const computePosition = (props: ComputePositionProps) => {\n const { reference, floating, placement, placementOrderPreference, customOffset, withoutPortal } = props;\n\n // When WITHOUT portal: only apply fixed-parent offsets (absolute parents scroll and must NOT be treated as fixed)\n const parentOffsets = withoutPortal ? adjustForFixedParent(reference) : { top: 0, left: 0 };\n\n const referenceRect = reference.getBoundingClientRect();\n const floatingRect = floating.getBoundingClientRect();\n\n const fallbackPlacements = placementOrderPreference || getExpandedFallbackPlacements(placement);\n\n const placements = expandWithVariations(\n [placement].concat(fallbackPlacements as DSHookFloatingContextT.PopperPlacementsT[]),\n );\n\n // Boundary selection:\n // - Portal => viewport (inset by body padding for Storybook)\n // - No portal => nearest clipping/scroll container (fallback viewport rect)\n const clippingParent = withoutPortal ? getClippingParent(reference) : null;\n const clippingRect: RectLike = clippingParent ? clippingParent.getBoundingClientRect() : getViewportRect();\n\n // Best-fit selection:\n // 1) choose first placement that fully fits\n // 2) otherwise choose placement with smallest max overflow, tie-break by total overflow\n let bestPlacement = placement;\n let bestOverflows: OverflowOffsets | null = null;\n let bestScore = { total: Number.POSITIVE_INFINITY, maxSide: Number.POSITIVE_INFINITY };\n\n for (let i = 0; i < placements.length; i += 1) {\n const currentPlacement = placements[i];\n\n const overflows = detectOverflow(referenceRect, floatingRect, currentPlacement, customOffset, clippingRect);\n\n if (fits(overflows)) {\n bestPlacement = currentPlacement;\n bestOverflows = overflows;\n break;\n }\n\n const score = getOverflowScore(overflows);\n\n const isBetter =\n score.maxSide < bestScore.maxSide || (score.maxSide === bestScore.maxSide && score.total < bestScore.total);\n\n if (isBetter) {\n bestPlacement = currentPlacement;\n bestOverflows = overflows;\n bestScore = score;\n }\n }\n\n const finalPlacement = bestPlacement;\n\n const overflows =\n bestOverflows ?? detectOverflow(referenceRect, floatingRect, finalPlacement, customOffset, clippingRect);\n\n // Convert overflow -> coordinates.\n // detectOverflow uses viewport/clipping-rect coordinates.\n //\n // - If tooltip is rendered IN A PORTAL (withoutPortal === false) and is positioned with `position: absolute`,\n // convert viewport coords to page coords by adding window.scrollX/Y.\n //\n // - If tooltip is rendered WITHOUT portal, convert viewport coords to offsetParent coords\n // (subtract offsetParent rect, add its scroll).\n let x = -overflows.left - parentOffsets.left;\n let y = -overflows.top - parentOffsets.top;\n\n if (!withoutPortal) {\n x += window.scrollX;\n y += window.scrollY;\n } else {\n // clippingRect.top/left may be non-zero (e.g. a scroll container below the viewport top).\n // The overflow values already subtracted it; add it back so we convert pure viewport coords\n // to offset-parent-relative coords: viewportCoord - offsetParent.top + offsetParent.scrollTop\n const op = getOffsetParentData(floating);\n x = x + clippingRect.left - op.left + op.scrollLeft;\n y = y + clippingRect.top - op.top + op.scrollTop;\n }\n\n // Always shift back inside boundary\n ({ x, y } = applyShift(x, y, overflows));\n\n const coordsArrow = getArrowOffsetDynamic({\n placement: finalPlacement,\n referenceRect,\n floatingRect,\n x,\n y,\n withoutPortal,\n parentOffsets,\n floatingEl: floating,\n arrowPadding: 12,\n });\n\n return {\n coordsStyle: {\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n top: 0,\n left: 0,\n },\n finalPlacement,\n coordsArrow,\n };\n};\n", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADSvB,2CAA8C;AAC9C,4BAAsC;AACtC,4BAA+B;AAC/B,iCAWO;AAWA,MAAM,kBAAkB,CAAC,UAAgC;AAC9D,QAAM,EAAE,WAAW,UAAU,WAAW,0BAA0B,cAAc,cAAc,IAAI;AAGlG,QAAM,gBAAgB,oBAAgB,iDAAqB,SAAS,IAAI,EAAE,KAAK,GAAG,MAAM,EAAE;AAE1F,QAAM,gBAAgB,UAAU,sBAAsB;AACtD,QAAM,eAAe,SAAS,sBAAsB;AAEpD,QAAM,qBAAqB,gCAA4B,oEAA8B,SAAS;AAE9F,QAAM,iBAAa;AAAA,IACjB,CAAC,SAAS,EAAE,OAAO,kBAAgE;AAAA,EACrF;AAKA,QAAM,iBAAiB,oBAAgB,8CAAkB,SAAS,IAAI;AACtE,QAAM,eAAyB,iBAAiB,eAAe,sBAAsB,QAAI,4CAAgB;AAKzG,MAAI,gBAAgB;AACpB,MAAI,gBAAwC;AAC5C,MAAI,YAAY,EAAE,OAAO,OAAO,mBAAmB,SAAS,OAAO,kBAAkB;AAErF,WAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK,GAAG;AAC7C,UAAM,mBAAmB,WAAW,CAAC;AAErC,UAAMA,iBAAY,sCAAe,eAAe,cAAc,kBAAkB,cAAc,YAAY;AAE1G,YAAI,iCAAKA,UAAS,GAAG;AACnB,sBAAgB;AAChB,sBAAgBA;AAChB;AAAA,IACF;AAEA,UAAM,YAAQ,6CAAiBA,UAAS;AAExC,UAAM,WACJ,MAAM,UAAU,UAAU,WAAY,MAAM,YAAY,UAAU,WAAW,MAAM,QAAQ,UAAU;AAEvG,QAAI,UAAU;AACZ,sBAAgB;AAChB,sBAAgBA;AAChB,kBAAY;AAAA,IACd;AAAA,EACF;AAEA,QAAM,iBAAiB;AAEvB,QAAM,YACJ,qBAAiB,sCAAe,eAAe,cAAc,gBAAgB,cAAc,YAAY;AAUzG,MAAI,IAAI,CAAC,UAAU,OAAO,cAAc;AACxC,MAAI,IAAI,CAAC,UAAU,MAAM,cAAc;AAEvC,MAAI,CAAC,eAAe;AAClB,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd,OAAO;AAIL,UAAM,SAAK,gDAAoB,QAAQ;AACvC,QAAI,IAAI,aAAa,OAAO,GAAG,OAAO,GAAG;AACzC,QAAI,IAAI,aAAa,MAAM,GAAG,MAAM,GAAG;AAAA,EACzC;AAGA,GAAC,EAAE,GAAG,EAAE,QAAI,uCAAW,GAAG,GAAG,SAAS;AAEtC,QAAM,kBAAc,6CAAsB;AAAA,IACxC,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB,CAAC;AAED,SAAO;AAAA,IACL,aAAa;AAAA,MACX,WAAW,eAAe,KAAK,MAAM,CAAC,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC;AAAA,MAC3D,KAAK;AAAA,MACL,MAAM;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;",
6
6
  "names": ["overflows"]
7
7
  }
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import React2, { useMemo, useEffect } from "react";
2
+ import React2, { useMemo } from "react";
3
3
  import {
4
4
  useMemoMergePropsWithDefault,
5
5
  useValidateTypescriptPropTypes,
@@ -9,8 +9,17 @@ import { useHeadlessTooltip } from "@elliemae/ds-hooks-headless-tooltip";
9
9
  import { defaultProps, DSFloatingContextPropTypes } from "./react-desc-prop-types.js";
10
10
  import { useComputedPositionStyles } from "./useComputedPositionStyles.js";
11
11
  import { usePositionObserver } from "./utils/positionObserver.js";
12
+ import { useLatestRef } from "./hooks/useLatestRef.js";
13
+ import { useResolvedReference } from "./hooks/useResolvedReference.js";
14
+ import { useFloatingClickOutside } from "./hooks/useFloatingClickOutside.js";
15
+ import { useFloatingEscape } from "./hooks/useFloatingEscape.js";
16
+ import { useFloatingResizeObserver } from "./hooks/useFloatingResizeObserver.js";
12
17
  const useFloatingContext = (props = {}) => {
13
- const propsWithDefault = useMemoMergePropsWithDefault(props, defaultProps);
18
+ const { onClickOutside, onEscape, onOpen, onClose, externalReferenceElement, ...stableProps } = props;
19
+ const propsWithDefault = useMemoMergePropsWithDefault(
20
+ stableProps,
21
+ defaultProps
22
+ );
14
23
  useValidateTypescriptPropTypes(propsWithDefault, DSFloatingContextPropTypes, "FloatingContext");
15
24
  const {
16
25
  withoutPortal,
@@ -20,10 +29,14 @@ const useFloatingContext = (props = {}) => {
20
29
  placement,
21
30
  customOffset,
22
31
  placementOrderPreference,
23
- onOpen,
24
- onClose,
25
- externallyControlledIsOpen
32
+ externallyControlledIsOpen,
33
+ closeOnEscape,
34
+ returnFocusToReference
26
35
  } = propsWithDefault;
36
+ const onClickOutsideRef = useLatestRef(onClickOutside);
37
+ const onEscapeRef = useLatestRef(onEscape);
38
+ const onOpenRef = useLatestRef(onOpen);
39
+ const onCloseRef = useLatestRef(onClose);
27
40
  const [internalIsOpen, setInternalIsOpen] = React2.useState(false);
28
41
  const isOpen = useMemo(
29
42
  () => externallyControlledIsOpen !== void 0 ? externallyControlledIsOpen : internalIsOpen,
@@ -31,14 +44,24 @@ const useFloatingContext = (props = {}) => {
31
44
  );
32
45
  const handleOpen = React2.useCallback(() => {
33
46
  setInternalIsOpen(true);
34
- onOpen?.();
35
- }, [onOpen]);
47
+ onOpenRef.current?.();
48
+ }, [onOpenRef]);
36
49
  const handleClose = React2.useCallback(() => {
37
50
  setInternalIsOpen(false);
38
- onClose?.();
39
- }, [onClose]);
51
+ onCloseRef.current?.();
52
+ }, [onCloseRef]);
40
53
  const tooltipHelpers = useHeadlessTooltip({ onOpen: handleOpen, onClose: handleClose });
41
- const { setReferenceElement, referenceElement, hideTooltip, showTooltip } = tooltipHelpers;
54
+ const {
55
+ setReferenceElement: setInternalReferenceElement,
56
+ referenceElement: internalReferenceElement,
57
+ hideTooltip,
58
+ showTooltip
59
+ } = tooltipHelpers;
60
+ const { referenceElement, setReferenceElement } = useResolvedReference({
61
+ externalReferenceElement,
62
+ internalReferenceElement,
63
+ setInternalReferenceElement
64
+ });
42
65
  const [floating, setFloating] = React2.useState(null);
43
66
  const { arrowStyles, floatingStyles, hasComputedOnce, updateStyles, debouncedUpdateStyles, mutableUpdateStyles } = useComputedPositionStyles({
44
67
  reference: referenceElement,
@@ -50,30 +73,38 @@ const useFloatingContext = (props = {}) => {
50
73
  preventComputing: !isOpen,
51
74
  debounceMs: 150
52
75
  });
53
- useEffect(() => {
54
- if (!isOpen) return;
55
- const observers = [];
56
- if (floating) {
57
- const roFloating = new ResizeObserver(() => {
58
- mutableUpdateStyles.current();
59
- });
60
- roFloating.observe(floating);
61
- observers.push(roFloating);
62
- }
63
- return () => observers.forEach((o) => o.disconnect());
64
- }, [isOpen, floating, updateStyles, mutableUpdateStyles]);
76
+ useFloatingResizeObserver({
77
+ enabled: isOpen,
78
+ floating,
79
+ onResize: () => mutableUpdateStyles.current()
80
+ });
65
81
  const onObservedMovement = React2.useCallback(() => {
66
82
  if (!isOpen) return;
67
83
  debouncedUpdateStyles();
68
84
  }, [isOpen, debouncedUpdateStyles]);
69
85
  usePositionObserver(referenceElement, onObservedMovement);
70
- const computedFloatingStyles = useMemo(
71
- () => ({
86
+ useFloatingClickOutside({
87
+ enabled: isOpen,
88
+ floating,
89
+ reference: referenceElement,
90
+ callbackRef: onClickOutsideRef
91
+ });
92
+ useFloatingEscape({
93
+ enabled: isOpen && closeOnEscape,
94
+ floating,
95
+ reference: referenceElement,
96
+ onEscapeRef,
97
+ handleClose,
98
+ returnFocusToReference
99
+ });
100
+ const computedFloatingStyles = useMemo(() => {
101
+ const isInteractive = isOpen && hasComputedOnce;
102
+ return {
72
103
  ...floatingStyles,
73
- visibility: isOpen && hasComputedOnce ? "visible" : "hidden"
74
- }),
75
- [floatingStyles, hasComputedOnce, isOpen]
76
- );
104
+ opacity: isInteractive ? 1 : 0,
105
+ pointerEvents: isInteractive ? "auto" : "none"
106
+ };
107
+ }, [floatingStyles, hasComputedOnce, isOpen]);
77
108
  const refs = useMemo(
78
109
  () => ({
79
110
  setReference: setReferenceElement,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../scripts/build/transpile/react-shim.js", "../../src/DSFloatingContext.tsx"],
4
- "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable max-lines */\n/* eslint-disable consistent-return */\n/* eslint-disable max-statements */\nimport React, { useMemo, useEffect } from 'react';\nimport {\n useMemoMergePropsWithDefault,\n useValidateTypescriptPropTypes,\n describe,\n type ValidationMap,\n} from '@elliemae/ds-props-helpers';\nimport { useHeadlessTooltip } from '@elliemae/ds-hooks-headless-tooltip';\nimport type { DSHookFloatingContextT } from './react-desc-prop-types.js';\nimport { defaultProps, DSFloatingContextPropTypes } from './react-desc-prop-types.js';\nimport { useComputedPositionStyles } from './useComputedPositionStyles.js';\nimport { usePositionObserver } from './utils/positionObserver.js';\n\nconst useFloatingContext = (props: DSHookFloatingContextT.Props = {}) => {\n const propsWithDefault = useMemoMergePropsWithDefault<DSHookFloatingContextT.InternalProps>(props, defaultProps);\n useValidateTypescriptPropTypes(propsWithDefault, DSFloatingContextPropTypes, 'FloatingContext');\n\n const {\n withoutPortal,\n withoutAnimation,\n portalDOMContainer,\n animationDuration,\n placement,\n customOffset,\n placementOrderPreference,\n onOpen,\n onClose,\n externallyControlledIsOpen,\n } = propsWithDefault;\n\n const [internalIsOpen, setInternalIsOpen] = React.useState<boolean>(false);\n const isOpen = useMemo(\n () => (externallyControlledIsOpen !== undefined ? externallyControlledIsOpen : internalIsOpen),\n [externallyControlledIsOpen, internalIsOpen],\n );\n\n const handleOpen = React.useCallback(() => {\n setInternalIsOpen(true);\n onOpen?.();\n }, [onOpen]);\n\n const handleClose = React.useCallback(() => {\n setInternalIsOpen(false);\n onClose?.();\n }, [onClose]);\n\n const tooltipHelpers = useHeadlessTooltip({ onOpen: handleOpen, onClose: handleClose });\n const { setReferenceElement, referenceElement, hideTooltip, showTooltip } = tooltipHelpers;\n\n // Anchor and floating refs\n const [floating, setFloating] = React.useState<HTMLElement | null>(null);\n\n // Compute position (skip when closed)\n const { arrowStyles, floatingStyles, hasComputedOnce, updateStyles, debouncedUpdateStyles, mutableUpdateStyles } =\n useComputedPositionStyles({\n reference: referenceElement,\n floating,\n placement,\n placementOrderPreference,\n customOffset,\n withoutPortal,\n preventComputing: !isOpen,\n debounceMs: 150,\n });\n\n useEffect(() => {\n if (!isOpen) return;\n\n const observers: ResizeObserver[] = [];\n\n if (floating) {\n const roFloating = new ResizeObserver(() => {\n mutableUpdateStyles.current();\n });\n roFloating.observe(floating);\n observers.push(roFloating);\n }\n\n return () => observers.forEach((o) => o.disconnect());\n }, [isOpen, floating, updateStyles, mutableUpdateStyles]);\n\n const onObservedMovement = React.useCallback(() => {\n if (!isOpen) return;\n debouncedUpdateStyles();\n }, [isOpen, debouncedUpdateStyles]);\n usePositionObserver(referenceElement, onObservedMovement);\n\n // Expose visibility: only visible if open and already computed at least once\n const computedFloatingStyles = useMemo<React.CSSProperties>(\n () => ({\n ...floatingStyles,\n visibility: isOpen && hasComputedOnce ? 'visible' : 'hidden',\n }),\n [floatingStyles, hasComputedOnce, isOpen],\n );\n\n const refs = useMemo(\n () => ({\n setReference: setReferenceElement,\n setFloating,\n floating,\n reference: referenceElement,\n }),\n [setReferenceElement, floating, referenceElement],\n );\n\n const handlers = useMemo(\n () => ({\n onMouseEnter: tooltipHelpers.onMouseEnter,\n onMouseLeave: tooltipHelpers.onMouseLeave,\n onFocus: tooltipHelpers.onFocus,\n onBlur: tooltipHelpers.onBlur,\n }),\n [tooltipHelpers.onBlur, tooltipHelpers.onFocus, tooltipHelpers.onMouseEnter, tooltipHelpers.onMouseLeave],\n );\n\n return useMemo(\n () => ({\n refs,\n floatingStyles: computedFloatingStyles,\n handlers,\n isOpen,\n arrowStyles,\n hideTooltip,\n showTooltip,\n context: {\n withoutPortal,\n withoutAnimation,\n portalDOMContainer,\n animationDuration,\n },\n mutableUpdateStyles,\n forceUpdatePosition: updateStyles,\n }),\n [\n refs,\n computedFloatingStyles,\n handlers,\n isOpen,\n arrowStyles,\n hideTooltip,\n showTooltip,\n withoutPortal,\n withoutAnimation,\n portalDOMContainer,\n animationDuration,\n mutableUpdateStyles,\n updateStyles,\n ],\n );\n};\n\nuseFloatingContext.displayName = 'FloatingContext';\nconst UseFloatingContextWithSchema = describe(useFloatingContext);\nUseFloatingContextWithSchema.propTypes =\n DSFloatingContextPropTypes as unknown as ValidationMap<DSHookFloatingContextT.Props>;\n\nexport { useFloatingContext, UseFloatingContextWithSchema };\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable max-statements */\nimport React, { useMemo } from 'react';\nimport {\n useMemoMergePropsWithDefault,\n useValidateTypescriptPropTypes,\n describe,\n type ValidationMap,\n} from '@elliemae/ds-props-helpers';\nimport { useHeadlessTooltip } from '@elliemae/ds-hooks-headless-tooltip';\nimport type { DSHookFloatingContextT } from './react-desc-prop-types.js';\nimport { defaultProps, DSFloatingContextPropTypes } from './react-desc-prop-types.js';\nimport { useComputedPositionStyles } from './useComputedPositionStyles.js';\nimport { usePositionObserver } from './utils/positionObserver.js';\nimport { useLatestRef } from './hooks/useLatestRef.js';\nimport { useResolvedReference } from './hooks/useResolvedReference.js';\nimport { useFloatingClickOutside } from './hooks/useFloatingClickOutside.js';\nimport { useFloatingEscape } from './hooks/useFloatingEscape.js';\nimport { useFloatingResizeObserver } from './hooks/useFloatingResizeObserver.js';\n\nconst useFloatingContext = (props: DSHookFloatingContextT.Props = {}) => {\n // Extract unstable callback refs BEFORE useMemoMergePropsWithDefault.\n // useMemoMergePropsWithDefault compares with fast-deep-equal which compares functions by\n // reference; an inline callback from the consumer would invalidate propsWithDefault on every\n // render, which in turn would invalidate the destructured `customOffset` array and re-trigger\n // the position-computation useLayoutEffect on every render \u2192 infinite loop.\n const { onClickOutside, onEscape, onOpen, onClose, externalReferenceElement, ...stableProps } = props;\n\n const propsWithDefault = useMemoMergePropsWithDefault<DSHookFloatingContextT.InternalProps>(\n stableProps,\n defaultProps,\n );\n useValidateTypescriptPropTypes(propsWithDefault, DSFloatingContextPropTypes, 'FloatingContext');\n\n const {\n withoutPortal,\n withoutAnimation,\n portalDOMContainer,\n animationDuration,\n placement,\n customOffset,\n placementOrderPreference,\n externallyControlledIsOpen,\n closeOnEscape,\n returnFocusToReference,\n } = propsWithDefault;\n\n // Latest-refs for consumer callbacks (see useLatestRef docs).\n const onClickOutsideRef = useLatestRef(onClickOutside);\n const onEscapeRef = useLatestRef(onEscape);\n const onOpenRef = useLatestRef(onOpen);\n const onCloseRef = useLatestRef(onClose);\n\n // Open/close state \u2014 externally controlled when `externallyControlledIsOpen` is provided.\n const [internalIsOpen, setInternalIsOpen] = React.useState(false);\n const isOpen = useMemo(\n () => (externallyControlledIsOpen !== undefined ? externallyControlledIsOpen : internalIsOpen),\n [externallyControlledIsOpen, internalIsOpen],\n );\n\n const handleOpen = React.useCallback(() => {\n setInternalIsOpen(true);\n onOpenRef.current?.();\n }, [onOpenRef]);\n\n const handleClose = React.useCallback(() => {\n setInternalIsOpen(false);\n onCloseRef.current?.();\n }, [onCloseRef]);\n\n // Headless tooltip exposes show/hide helpers + manages its own internal state.\n const tooltipHelpers = useHeadlessTooltip({ onOpen: handleOpen, onClose: handleClose });\n const {\n setReferenceElement: setInternalReferenceElement,\n referenceElement: internalReferenceElement,\n hideTooltip,\n showTooltip,\n } = tooltipHelpers;\n\n // Reference element resolution: external takes precedence over internal.\n const { referenceElement, setReferenceElement } = useResolvedReference({\n externalReferenceElement,\n internalReferenceElement,\n setInternalReferenceElement,\n });\n\n // Anchor and floating refs\n const [floating, setFloating] = React.useState<HTMLElement | null>(null);\n\n // Compute position (skip when closed)\n const { arrowStyles, floatingStyles, hasComputedOnce, updateStyles, debouncedUpdateStyles, mutableUpdateStyles } =\n useComputedPositionStyles({\n reference: referenceElement,\n floating,\n placement,\n placementOrderPreference,\n customOffset,\n withoutPortal,\n preventComputing: !isOpen,\n debounceMs: 150,\n });\n\n // Re-compute position when the floating element's size changes (e.g. async content).\n useFloatingResizeObserver({\n enabled: isOpen,\n floating,\n onResize: () => mutableUpdateStyles.current(),\n });\n\n // Re-compute position when the reference element moves in the viewport.\n const onObservedMovement = React.useCallback(() => {\n if (!isOpen) return;\n debouncedUpdateStyles();\n }, [isOpen, debouncedUpdateStyles]);\n usePositionObserver(referenceElement, onObservedMovement);\n\n // Click-outside dismissal (opt-in via `onClickOutside`).\n useFloatingClickOutside({\n enabled: isOpen,\n floating,\n reference: referenceElement,\n callbackRef: onClickOutsideRef,\n });\n\n // Escape dismissal (opt-in via `closeOnEscape`).\n useFloatingEscape({\n enabled: isOpen && closeOnEscape,\n floating,\n reference: referenceElement,\n onEscapeRef,\n handleClose,\n returnFocusToReference,\n });\n\n // Expose visibility via opacity (NOT visibility:hidden \u2014 that blocks programmatic focus,\n // breaking autoFocus on first-open before the position-computation effect can run).\n // When `externalReferenceElement` is provided, computation runs on the first useLayoutEffect\n // (reference is known synchronously), so the popper becomes interactive in the same commit.\n const computedFloatingStyles = useMemo<React.CSSProperties>(() => {\n const isInteractive = isOpen && hasComputedOnce;\n return {\n ...floatingStyles,\n opacity: isInteractive ? 1 : 0,\n pointerEvents: isInteractive ? 'auto' : 'none',\n };\n }, [floatingStyles, hasComputedOnce, isOpen]);\n\n const refs = useMemo(\n () => ({\n setReference: setReferenceElement,\n setFloating,\n floating,\n reference: referenceElement,\n }),\n [setReferenceElement, floating, referenceElement],\n );\n\n const handlers = useMemo(\n () => ({\n onMouseEnter: tooltipHelpers.onMouseEnter,\n onMouseLeave: tooltipHelpers.onMouseLeave,\n onFocus: tooltipHelpers.onFocus,\n onBlur: tooltipHelpers.onBlur,\n }),\n [tooltipHelpers.onBlur, tooltipHelpers.onFocus, tooltipHelpers.onMouseEnter, tooltipHelpers.onMouseLeave],\n );\n\n return useMemo(\n () => ({\n refs,\n floatingStyles: computedFloatingStyles,\n handlers,\n isOpen,\n arrowStyles,\n hideTooltip,\n showTooltip,\n context: {\n withoutPortal,\n withoutAnimation,\n portalDOMContainer,\n animationDuration,\n },\n mutableUpdateStyles,\n forceUpdatePosition: updateStyles,\n }),\n [\n refs,\n computedFloatingStyles,\n handlers,\n isOpen,\n arrowStyles,\n hideTooltip,\n showTooltip,\n withoutPortal,\n withoutAnimation,\n portalDOMContainer,\n animationDuration,\n mutableUpdateStyles,\n updateStyles,\n ],\n );\n};\n\nuseFloatingContext.displayName = 'FloatingContext';\nconst UseFloatingContextWithSchema = describe(useFloatingContext);\nUseFloatingContextWithSchema.propTypes =\n DSFloatingContextPropTypes as unknown as ValidationMap<DSHookFloatingContextT.Props>;\n\nexport { useFloatingContext, UseFloatingContextWithSchema };\n"],
5
+ "mappings": "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",
6
6
  "names": ["React"]
7
7
  }
@@ -0,0 +1,30 @@
1
+ import * as React from "react";
2
+ import { useEffect } from "react";
3
+ const useFloatingClickOutside = ({
4
+ enabled,
5
+ floating,
6
+ reference,
7
+ callbackRef
8
+ }) => {
9
+ useEffect(() => {
10
+ if (!enabled || !floating || !reference) return void 0;
11
+ const listener = (event) => {
12
+ const cb = callbackRef.current;
13
+ if (!cb) return;
14
+ const target = event.target;
15
+ if (!target) return;
16
+ if (floating.contains(target) || reference.contains(target)) return;
17
+ cb(event);
18
+ };
19
+ document.addEventListener("mousedown", listener, true);
20
+ document.addEventListener("touchstart", listener, true);
21
+ return () => {
22
+ document.removeEventListener("mousedown", listener, true);
23
+ document.removeEventListener("touchstart", listener, true);
24
+ };
25
+ }, [enabled, floating, reference, callbackRef]);
26
+ };
27
+ export {
28
+ useFloatingClickOutside
29
+ };
30
+ //# sourceMappingURL=useFloatingClickOutside.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/hooks/useFloatingClickOutside.ts"],
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import { useEffect, type MutableRefObject } from 'react';\n\ninterface UseFloatingClickOutsideParams {\n enabled: boolean;\n floating: HTMLElement | null;\n reference: Element | null;\n /**\n * Latest-ref of the click-outside callback. Passed as a ref (rather than a value)\n * so consumers can pass inline functions without re-attaching listeners on every render.\n * Use `useLatestRef(onClickOutside)` to construct it.\n */\n callbackRef: MutableRefObject<((event: MouseEvent | TouchEvent) => void) | undefined>;\n}\n\n/**\n * Attaches mousedown/touchstart listeners on the document that fire when the click target\n * is outside BOTH the floating element and the reference element.\n *\n * Only active when `enabled === true` and both elements exist.\n */\nexport const useFloatingClickOutside = ({\n enabled,\n floating,\n reference,\n callbackRef,\n}: UseFloatingClickOutsideParams) => {\n useEffect(() => {\n if (!enabled || !floating || !reference) return undefined;\n\n const listener = (event: MouseEvent | TouchEvent) => {\n const cb = callbackRef.current;\n if (!cb) return;\n const target = event.target as Node | null;\n if (!target) return;\n if (floating.contains(target) || reference.contains(target)) return;\n cb(event);\n };\n\n document.addEventListener('mousedown', listener, true);\n document.addEventListener('touchstart', listener, true);\n return () => {\n document.removeEventListener('mousedown', listener, true);\n document.removeEventListener('touchstart', listener, true);\n };\n }, [enabled, floating, reference, callbackRef]);\n};\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACAvB,SAAS,iBAAwC;AAoB1C,MAAM,0BAA0B,CAAC;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAqC;AACnC,YAAU,MAAM;AACd,QAAI,CAAC,WAAW,CAAC,YAAY,CAAC,UAAW,QAAO;AAEhD,UAAM,WAAW,CAAC,UAAmC;AACnD,YAAM,KAAK,YAAY;AACvB,UAAI,CAAC,GAAI;AACT,YAAM,SAAS,MAAM;AACrB,UAAI,CAAC,OAAQ;AACb,UAAI,SAAS,SAAS,MAAM,KAAK,UAAU,SAAS,MAAM,EAAG;AAC7D,SAAG,KAAK;AAAA,IACV;AAEA,aAAS,iBAAiB,aAAa,UAAU,IAAI;AACrD,aAAS,iBAAiB,cAAc,UAAU,IAAI;AACtD,WAAO,MAAM;AACX,eAAS,oBAAoB,aAAa,UAAU,IAAI;AACxD,eAAS,oBAAoB,cAAc,UAAU,IAAI;AAAA,IAC3D;AAAA,EACF,GAAG,CAAC,SAAS,UAAU,WAAW,WAAW,CAAC;AAChD;",
6
+ "names": []
7
+ }
@@ -0,0 +1,44 @@
1
+ import * as React from "react";
2
+ import { useCallback, useEffect } from "react";
3
+ const useFloatingEscape = ({
4
+ enabled,
5
+ floating,
6
+ reference,
7
+ onEscapeRef,
8
+ handleClose,
9
+ returnFocusToReference
10
+ }) => {
11
+ const isFocusWithinFloatingScope = useCallback(
12
+ (active) => {
13
+ if (!active) return false;
14
+ if (floating && floating.contains(active)) return true;
15
+ if (!reference) return false;
16
+ return reference === active || reference.contains(active);
17
+ },
18
+ [floating, reference]
19
+ );
20
+ useEffect(() => {
21
+ if (!enabled) return void 0;
22
+ const listener = (event) => {
23
+ if (event.key !== "Escape") return;
24
+ if (!isFocusWithinFloatingScope(document.activeElement)) return;
25
+ const cb = onEscapeRef.current;
26
+ if (cb) {
27
+ cb(event);
28
+ } else {
29
+ handleClose();
30
+ }
31
+ if (returnFocusToReference && reference instanceof HTMLElement) {
32
+ reference.focus();
33
+ }
34
+ };
35
+ document.addEventListener("keydown", listener, true);
36
+ return () => {
37
+ document.removeEventListener("keydown", listener, true);
38
+ };
39
+ }, [enabled, handleClose, isFocusWithinFloatingScope, onEscapeRef, reference, returnFocusToReference]);
40
+ };
41
+ export {
42
+ useFloatingEscape
43
+ };
44
+ //# sourceMappingURL=useFloatingEscape.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/hooks/useFloatingEscape.ts"],
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import { useCallback, useEffect, type MutableRefObject } from 'react';\n\ninterface UseFloatingEscapeParams {\n enabled: boolean;\n floating: HTMLElement | null;\n reference: Element | null;\n /** Latest-ref of the consumer's onEscape callback. Construct with `useLatestRef(onEscape)`. */\n onEscapeRef: MutableRefObject<((event: KeyboardEvent) => void) | undefined>;\n /** Fallback close handler invoked when no `onEscape` is provided. */\n handleClose: () => void;\n /** When true, calls `reference.focus()` after the escape close. */\n returnFocusToReference: boolean;\n}\n\n/**\n * Listens for `Escape` on the document and dismisses the floating element when focus is\n * within the floating element or on the reference element. Outside that scope the event is\n * ignored \u2014 we don't hijack Escape for unrelated UI on the page.\n */\nexport const useFloatingEscape = ({\n enabled,\n floating,\n reference,\n onEscapeRef,\n handleClose,\n returnFocusToReference,\n}: UseFloatingEscapeParams) => {\n const isFocusWithinFloatingScope = useCallback(\n (active: Element | null): boolean => {\n if (!active) return false;\n if (floating && floating.contains(active)) return true;\n if (!reference) return false;\n return reference === active || reference.contains(active);\n },\n [floating, reference],\n );\n\n useEffect(() => {\n if (!enabled) return undefined;\n\n const listener = (event: KeyboardEvent) => {\n if (event.key !== 'Escape') return;\n if (!isFocusWithinFloatingScope(document.activeElement)) return;\n\n const cb = onEscapeRef.current;\n if (cb) {\n cb(event);\n } else {\n handleClose();\n }\n if (returnFocusToReference && reference instanceof HTMLElement) {\n reference.focus();\n }\n };\n\n document.addEventListener('keydown', listener, true);\n return () => {\n document.removeEventListener('keydown', listener, true);\n };\n }, [enabled, handleClose, isFocusWithinFloatingScope, onEscapeRef, reference, returnFocusToReference]);\n};\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACAvB,SAAS,aAAa,iBAAwC;AAmBvD,MAAM,oBAAoB,CAAC;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAA+B;AAC7B,QAAM,6BAA6B;AAAA,IACjC,CAAC,WAAoC;AACnC,UAAI,CAAC,OAAQ,QAAO;AACpB,UAAI,YAAY,SAAS,SAAS,MAAM,EAAG,QAAO;AAClD,UAAI,CAAC,UAAW,QAAO;AACvB,aAAO,cAAc,UAAU,UAAU,SAAS,MAAM;AAAA,IAC1D;AAAA,IACA,CAAC,UAAU,SAAS;AAAA,EACtB;AAEA,YAAU,MAAM;AACd,QAAI,CAAC,QAAS,QAAO;AAErB,UAAM,WAAW,CAAC,UAAyB;AACzC,UAAI,MAAM,QAAQ,SAAU;AAC5B,UAAI,CAAC,2BAA2B,SAAS,aAAa,EAAG;AAEzD,YAAM,KAAK,YAAY;AACvB,UAAI,IAAI;AACN,WAAG,KAAK;AAAA,MACV,OAAO;AACL,oBAAY;AAAA,MACd;AACA,UAAI,0BAA0B,qBAAqB,aAAa;AAC9D,kBAAU,MAAM;AAAA,MAClB;AAAA,IACF;AAEA,aAAS,iBAAiB,WAAW,UAAU,IAAI;AACnD,WAAO,MAAM;AACX,eAAS,oBAAoB,WAAW,UAAU,IAAI;AAAA,IACxD;AAAA,EACF,GAAG,CAAC,SAAS,aAAa,4BAA4B,aAAa,WAAW,sBAAsB,CAAC;AACvG;",
6
+ "names": []
7
+ }
@@ -0,0 +1,16 @@
1
+ import * as React from "react";
2
+ import { useEffect } from "react";
3
+ const useFloatingResizeObserver = ({ enabled, floating, onResize }) => {
4
+ useEffect(() => {
5
+ if (!enabled || !floating) return void 0;
6
+ const observer = new ResizeObserver(() => {
7
+ onResize();
8
+ });
9
+ observer.observe(floating);
10
+ return () => observer.disconnect();
11
+ }, [enabled, floating, onResize]);
12
+ };
13
+ export {
14
+ useFloatingResizeObserver
15
+ };
16
+ //# sourceMappingURL=useFloatingResizeObserver.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/hooks/useFloatingResizeObserver.ts"],
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import { useEffect } from 'react';\n\ninterface UseFloatingResizeObserverParams {\n enabled: boolean;\n floating: HTMLElement | null;\n onResize: () => void;\n}\n\n/**\n * Observes the floating element's size and calls `onResize` when its bounding box changes.\n * Used to re-run position computation when the floating content reflows (e.g. async-loaded data).\n */\nexport const useFloatingResizeObserver = ({ enabled, floating, onResize }: UseFloatingResizeObserverParams) => {\n useEffect(() => {\n if (!enabled || !floating) return undefined;\n\n const observer = new ResizeObserver(() => {\n onResize();\n });\n observer.observe(floating);\n\n return () => observer.disconnect();\n }, [enabled, floating, onResize]);\n};\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACAvB,SAAS,iBAAiB;AAYnB,MAAM,4BAA4B,CAAC,EAAE,SAAS,UAAU,SAAS,MAAuC;AAC7G,YAAU,MAAM;AACd,QAAI,CAAC,WAAW,CAAC,SAAU,QAAO;AAElC,UAAM,WAAW,IAAI,eAAe,MAAM;AACxC,eAAS;AAAA,IACX,CAAC;AACD,aAAS,QAAQ,QAAQ;AAEzB,WAAO,MAAM,SAAS,WAAW;AAAA,EACnC,GAAG,CAAC,SAAS,UAAU,QAAQ,CAAC;AAClC;",
6
+ "names": []
7
+ }
@@ -0,0 +1,11 @@
1
+ import * as React from "react";
2
+ import { useRef } from "react";
3
+ const useLatestRef = (value) => {
4
+ const ref = useRef(value);
5
+ ref.current = value;
6
+ return ref;
7
+ };
8
+ export {
9
+ useLatestRef
10
+ };
11
+ //# sourceMappingURL=useLatestRef.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/hooks/useLatestRef.ts"],
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import { useRef } from 'react';\n\n/**\n * Latest-ref pattern: keeps the value in a ref that's updated on every render.\n * Use this when an effect/listener needs to read the latest value of a prop or callback\n * without including it in the effect's dependency array \u2014 avoids re-attaching listeners\n * (and infinite loops via deep-equal comparators) when consumers pass inline callbacks.\n */\nexport const useLatestRef = <T>(value: T) => {\n const ref = useRef(value);\n ref.current = value;\n return ref;\n};\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACAvB,SAAS,cAAc;AAQhB,MAAM,eAAe,CAAI,UAAa;AAC3C,QAAM,MAAM,OAAO,KAAK;AACxB,MAAI,UAAU;AACd,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -0,0 +1,22 @@
1
+ import * as React from "react";
2
+ import { useCallback } from "react";
3
+ const useResolvedReference = ({
4
+ externalReferenceElement,
5
+ internalReferenceElement,
6
+ setInternalReferenceElement
7
+ }) => {
8
+ const hasExternalReference = externalReferenceElement !== void 0;
9
+ const referenceElement = hasExternalReference ? externalReferenceElement : internalReferenceElement;
10
+ const setReferenceElement = useCallback(
11
+ (el) => {
12
+ if (hasExternalReference) return;
13
+ setInternalReferenceElement(el);
14
+ },
15
+ [hasExternalReference, setInternalReferenceElement]
16
+ );
17
+ return { referenceElement, setReferenceElement };
18
+ };
19
+ export {
20
+ useResolvedReference
21
+ };
22
+ //# sourceMappingURL=useResolvedReference.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/hooks/useResolvedReference.ts"],
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import { useCallback } from 'react';\n\ninterface UseResolvedReferenceParams {\n externalReferenceElement: Element | null | undefined;\n internalReferenceElement: Element | null;\n setInternalReferenceElement: (el: Element | null) => void;\n}\n\n/**\n * Resolves the active reference element for the floating context.\n *\n * - When `externalReferenceElement` is provided (anything other than `undefined`, including `null`),\n * it is used as the source of truth. `setReference` becomes a no-op so consumers that mistakenly\n * call `refs.setReference()` don't desynchronize the two sources.\n * - Otherwise the internally-managed state is used, populated by the consumer via `refs.setReference()`\n * (typically as a callback ref: `innerRef={refs.setReference}`).\n */\nexport const useResolvedReference = ({\n externalReferenceElement,\n internalReferenceElement,\n setInternalReferenceElement,\n}: UseResolvedReferenceParams) => {\n const hasExternalReference = externalReferenceElement !== undefined;\n const referenceElement = hasExternalReference ? externalReferenceElement : internalReferenceElement;\n\n const setReferenceElement = useCallback(\n (el: Element | null) => {\n if (hasExternalReference) return;\n setInternalReferenceElement(el);\n },\n [hasExternalReference, setInternalReferenceElement],\n );\n\n return { referenceElement, setReferenceElement };\n};\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACAvB,SAAS,mBAAmB;AAiBrB,MAAM,uBAAuB,CAAC;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AACF,MAAkC;AAChC,QAAM,uBAAuB,6BAA6B;AAC1D,QAAM,mBAAmB,uBAAuB,2BAA2B;AAE3E,QAAM,sBAAsB;AAAA,IAC1B,CAAC,OAAuB;AACtB,UAAI,qBAAsB;AAC1B,kCAA4B,EAAE;AAAA,IAChC;AAAA,IACA,CAAC,sBAAsB,2BAA2B;AAAA,EACpD;AAEA,SAAO,EAAE,kBAAkB,oBAAoB;AACjD;",
6
+ "names": []
7
+ }
@@ -3,5 +3,8 @@
3
3
  "sideEffects": [
4
4
  "*.css",
5
5
  "*.scss"
6
- ]
6
+ ],
7
+ "publishConfig": {
8
+ "access": "public"
9
+ }
7
10
  }
@@ -5,7 +5,9 @@ const defaultProps = {
5
5
  animationDuration: 300,
6
6
  withoutPortal: false,
7
7
  placement: "top",
8
- customOffset: [0, 12]
8
+ customOffset: [0, 12],
9
+ closeOnEscape: false,
10
+ returnFocusToReference: false
9
11
  };
10
12
  const DSFloatingContextPropTypes = {
11
13
  withoutPortal: PropTypes.bool.description("If true, the tooltip will not be rendered inside a portal.").defaultValue(false),
@@ -45,7 +47,16 @@ const DSFloatingContextPropTypes = {
45
47
  onClose: PropTypes.func.description("Callback when the tooltip is closed."),
46
48
  externallyControlledIsOpen: PropTypes.bool.description(
47
49
  "If true, the context open/close state will be controlled externally."
48
- )
50
+ ),
51
+ externalReferenceElement: PropTypes.instanceOf(Element).description(
52
+ "Pre-resolved reference element. When provided, used as the source of truth for positioning, avoiding the need for a follow-up refs.setReference() effect and the visibility:hidden race on open."
53
+ ),
54
+ onClickOutside: PropTypes.func.description(
55
+ "Called on mousedown/touchstart outside both the floating element and the reference element while open."
56
+ ),
57
+ closeOnEscape: PropTypes.bool.description("If true, listens for Escape on the floating element and calls onEscape (or onClose).").defaultValue(false),
58
+ onEscape: PropTypes.func.description("Called when Escape is pressed while focus is within the floating element."),
59
+ returnFocusToReference: PropTypes.bool.description("If true, returns focus to the reference element after Escape-close.").defaultValue(false)
49
60
  };
50
61
  export {
51
62
  DSFloatingContextPropTypes,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../scripts/build/transpile/react-shim.js", "../../src/react-desc-prop-types.ts"],
4
- "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable @typescript-eslint/no-empty-interface */\nimport type { DSPropTypesSchema } from '@elliemae/ds-props-helpers';\nimport { PropTypes } from '@elliemae/ds-props-helpers';\nexport declare namespace DSHookFloatingContextT {\n export interface DefaultProps {\n withoutPortal: boolean;\n withoutAnimation: boolean;\n portalDOMContainer?: HTMLElement;\n animationDuration: number;\n placement: PopperPlacementsT;\n customOffset: [number, number];\n }\n\n export interface OptionalProps {\n placementOrderPreference?: PopperPlacementsT[];\n onOpen?: () => void;\n onClose?: () => void;\n externallyControlledIsOpen?: boolean;\n }\n export interface Props extends Partial<DefaultProps>, OptionalProps {}\n\n export interface InternalProps extends DefaultProps, OptionalProps {}\n\n export type PopperPlacementsT =\n | 'top-start'\n | 'top'\n | 'top-end'\n | 'right-start'\n | 'right'\n | 'right-end'\n | 'bottom-end'\n | 'bottom'\n | 'bottom-start'\n | 'left-end'\n | 'left'\n | 'left-start';\n}\n\nexport const defaultProps: DSHookFloatingContextT.DefaultProps = {\n withoutAnimation: false,\n animationDuration: 300,\n withoutPortal: false,\n placement: 'top',\n customOffset: [0, 12],\n};\n\nexport const DSFloatingContextPropTypes: DSPropTypesSchema<DSHookFloatingContextT.Props> = {\n withoutPortal: PropTypes.bool\n .description('If true, the tooltip will not be rendered inside a portal.')\n .defaultValue(false),\n withoutAnimation: PropTypes.bool.description('If true, the tooltip will not have an animation.').defaultValue(false),\n portalDOMContainer: PropTypes.instanceOf(HTMLElement)\n .description('The DOM element where the tooltip will be rendered.')\n .defaultValue('the first \"main\" landmark available in the document or the body if no \"main\" is found'),\n animationDuration: PropTypes.number.description('The duration of the animation in milliseconds.').defaultValue(300),\n placement: PropTypes.oneOf([\n 'top-start',\n 'top',\n 'top-end',\n 'right-start',\n 'right',\n 'right-end',\n 'bottom-end',\n 'bottom',\n 'bottom-start',\n 'left-end',\n 'left',\n 'left-start',\n ])\n .description('The placement of the tooltip.')\n .defaultValue('top'),\n customOffset: PropTypes.arrayOf(PropTypes.number)\n .description('The custom offset of the tooltip.')\n .defaultValue([12, 12]),\n placementOrderPreference: PropTypes.oneOfType([\n PropTypes.tuple([PropTypes.oneOf(['top-start'])]),\n PropTypes.tuple([PropTypes.oneOf(['top'])]),\n PropTypes.tuple([PropTypes.oneOf(['top-end'])]),\n PropTypes.tuple([PropTypes.oneOf(['right-start'])]),\n PropTypes.tuple([PropTypes.oneOf(['right'])]),\n PropTypes.tuple([PropTypes.oneOf(['right-end'])]),\n PropTypes.tuple([PropTypes.oneOf(['bottom-end'])]),\n PropTypes.tuple([PropTypes.oneOf(['bottom'])]),\n PropTypes.tuple([PropTypes.oneOf(['bottom-start'])]),\n PropTypes.tuple([PropTypes.oneOf(['left-end'])]),\n PropTypes.tuple([PropTypes.oneOf(['left'])]),\n PropTypes.tuple([PropTypes.oneOf(['left-start'])]),\n ]).description('The order of the placement preference.'),\n onOpen: PropTypes.func.description('Callback when the tooltip is opened.'),\n onClose: PropTypes.func.description('Callback when the tooltip is closed.'),\n externallyControlledIsOpen: PropTypes.bool.description(\n 'If true, the context open/close state will be controlled externally.',\n ),\n};\n"],
5
- "mappings": "AAAA,YAAY,WAAW;ACEvB,SAAS,iBAAiB;AAoCnB,MAAM,eAAoD;AAAA,EAC/D,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,eAAe;AAAA,EACf,WAAW;AAAA,EACX,cAAc,CAAC,GAAG,EAAE;AACtB;AAEO,MAAM,6BAA8E;AAAA,EACzF,eAAe,UAAU,KACtB,YAAY,4DAA4D,EACxE,aAAa,KAAK;AAAA,EACrB,kBAAkB,UAAU,KAAK,YAAY,kDAAkD,EAAE,aAAa,KAAK;AAAA,EACnH,oBAAoB,UAAU,WAAW,WAAW,EACjD,YAAY,qDAAqD,EACjE,aAAa,uFAAuF;AAAA,EACvG,mBAAmB,UAAU,OAAO,YAAY,gDAAgD,EAAE,aAAa,GAAG;AAAA,EAClH,WAAW,UAAU,MAAM;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC,EACE,YAAY,+BAA+B,EAC3C,aAAa,KAAK;AAAA,EACrB,cAAc,UAAU,QAAQ,UAAU,MAAM,EAC7C,YAAY,mCAAmC,EAC/C,aAAa,CAAC,IAAI,EAAE,CAAC;AAAA,EACxB,0BAA0B,UAAU,UAAU;AAAA,IAC5C,UAAU,MAAM,CAAC,UAAU,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;AAAA,IAChD,UAAU,MAAM,CAAC,UAAU,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AAAA,IAC1C,UAAU,MAAM,CAAC,UAAU,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;AAAA,IAC9C,UAAU,MAAM,CAAC,UAAU,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;AAAA,IAClD,UAAU,MAAM,CAAC,UAAU,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;AAAA,IAC5C,UAAU,MAAM,CAAC,UAAU,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;AAAA,IAChD,UAAU,MAAM,CAAC,UAAU,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;AAAA,IACjD,UAAU,MAAM,CAAC,UAAU,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;AAAA,IAC7C,UAAU,MAAM,CAAC,UAAU,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;AAAA,IACnD,UAAU,MAAM,CAAC,UAAU,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;AAAA,IAC/C,UAAU,MAAM,CAAC,UAAU,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;AAAA,IAC3C,UAAU,MAAM,CAAC,UAAU,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;AAAA,EACnD,CAAC,EAAE,YAAY,wCAAwC;AAAA,EACvD,QAAQ,UAAU,KAAK,YAAY,sCAAsC;AAAA,EACzE,SAAS,UAAU,KAAK,YAAY,sCAAsC;AAAA,EAC1E,4BAA4B,UAAU,KAAK;AAAA,IACzC;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable @typescript-eslint/no-empty-interface */\nimport type { DSPropTypesSchema } from '@elliemae/ds-props-helpers';\nimport { PropTypes } from '@elliemae/ds-props-helpers';\nexport declare namespace DSHookFloatingContextT {\n export interface DefaultProps {\n withoutPortal: boolean;\n withoutAnimation: boolean;\n portalDOMContainer?: HTMLElement;\n animationDuration: number;\n placement: PopperPlacementsT;\n customOffset: [number, number];\n closeOnEscape: boolean;\n returnFocusToReference: boolean;\n }\n\n export interface OptionalProps {\n placementOrderPreference?: PopperPlacementsT[];\n onOpen?: () => void;\n onClose?: () => void;\n externallyControlledIsOpen?: boolean;\n /**\n * Pre-resolved reference element. When provided, the hook uses this as the\n * source of truth for positioning and ignores its internal reference state.\n * Eliminates the need for a follow-up `refs.setReference(...)` effect and\n * removes the visibility:hidden race that breaks programmatic focus on open.\n */\n externalReferenceElement?: Element | null;\n /**\n * Called when the user clicks/taps outside both the floating element and\n * the reference element while the floating is open.\n */\n onClickOutside?: (event: MouseEvent | TouchEvent) => void;\n /**\n * Called when Escape is pressed while focus is within the floating element.\n * Only fires when `closeOnEscape` is true.\n */\n onEscape?: (event: KeyboardEvent) => void;\n }\n export interface Props extends Partial<DefaultProps>, OptionalProps {}\n\n export interface InternalProps extends DefaultProps, OptionalProps {}\n\n export type PopperPlacementsT =\n | 'top-start'\n | 'top'\n | 'top-end'\n | 'right-start'\n | 'right'\n | 'right-end'\n | 'bottom-end'\n | 'bottom'\n | 'bottom-start'\n | 'left-end'\n | 'left'\n | 'left-start';\n}\n\nexport const defaultProps: DSHookFloatingContextT.DefaultProps = {\n withoutAnimation: false,\n animationDuration: 300,\n withoutPortal: false,\n placement: 'top',\n customOffset: [0, 12],\n closeOnEscape: false,\n returnFocusToReference: false,\n};\n\nexport const DSFloatingContextPropTypes: DSPropTypesSchema<DSHookFloatingContextT.Props> = {\n withoutPortal: PropTypes.bool\n .description('If true, the tooltip will not be rendered inside a portal.')\n .defaultValue(false),\n withoutAnimation: PropTypes.bool.description('If true, the tooltip will not have an animation.').defaultValue(false),\n portalDOMContainer: PropTypes.instanceOf(HTMLElement)\n .description('The DOM element where the tooltip will be rendered.')\n .defaultValue('the first \"main\" landmark available in the document or the body if no \"main\" is found'),\n animationDuration: PropTypes.number.description('The duration of the animation in milliseconds.').defaultValue(300),\n placement: PropTypes.oneOf([\n 'top-start',\n 'top',\n 'top-end',\n 'right-start',\n 'right',\n 'right-end',\n 'bottom-end',\n 'bottom',\n 'bottom-start',\n 'left-end',\n 'left',\n 'left-start',\n ])\n .description('The placement of the tooltip.')\n .defaultValue('top'),\n customOffset: PropTypes.arrayOf(PropTypes.number)\n .description('The custom offset of the tooltip.')\n .defaultValue([12, 12]),\n placementOrderPreference: PropTypes.oneOfType([\n PropTypes.tuple([PropTypes.oneOf(['top-start'])]),\n PropTypes.tuple([PropTypes.oneOf(['top'])]),\n PropTypes.tuple([PropTypes.oneOf(['top-end'])]),\n PropTypes.tuple([PropTypes.oneOf(['right-start'])]),\n PropTypes.tuple([PropTypes.oneOf(['right'])]),\n PropTypes.tuple([PropTypes.oneOf(['right-end'])]),\n PropTypes.tuple([PropTypes.oneOf(['bottom-end'])]),\n PropTypes.tuple([PropTypes.oneOf(['bottom'])]),\n PropTypes.tuple([PropTypes.oneOf(['bottom-start'])]),\n PropTypes.tuple([PropTypes.oneOf(['left-end'])]),\n PropTypes.tuple([PropTypes.oneOf(['left'])]),\n PropTypes.tuple([PropTypes.oneOf(['left-start'])]),\n ]).description('The order of the placement preference.'),\n onOpen: PropTypes.func.description('Callback when the tooltip is opened.'),\n onClose: PropTypes.func.description('Callback when the tooltip is closed.'),\n externallyControlledIsOpen: PropTypes.bool.description(\n 'If true, the context open/close state will be controlled externally.',\n ),\n externalReferenceElement: PropTypes.instanceOf(Element).description(\n 'Pre-resolved reference element. When provided, used as the source of truth for positioning, ' +\n 'avoiding the need for a follow-up refs.setReference() effect and the visibility:hidden race on open.',\n ),\n onClickOutside: PropTypes.func.description(\n 'Called on mousedown/touchstart outside both the floating element and the reference element while open.',\n ),\n closeOnEscape: PropTypes.bool\n .description('If true, listens for Escape on the floating element and calls onEscape (or onClose).')\n .defaultValue(false),\n onEscape: PropTypes.func.description('Called when Escape is pressed while focus is within the floating element.'),\n returnFocusToReference: PropTypes.bool\n .description('If true, returns focus to the reference element after Escape-close.')\n .defaultValue(false),\n};\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACEvB,SAAS,iBAAiB;AAuDnB,MAAM,eAAoD;AAAA,EAC/D,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,eAAe;AAAA,EACf,WAAW;AAAA,EACX,cAAc,CAAC,GAAG,EAAE;AAAA,EACpB,eAAe;AAAA,EACf,wBAAwB;AAC1B;AAEO,MAAM,6BAA8E;AAAA,EACzF,eAAe,UAAU,KACtB,YAAY,4DAA4D,EACxE,aAAa,KAAK;AAAA,EACrB,kBAAkB,UAAU,KAAK,YAAY,kDAAkD,EAAE,aAAa,KAAK;AAAA,EACnH,oBAAoB,UAAU,WAAW,WAAW,EACjD,YAAY,qDAAqD,EACjE,aAAa,uFAAuF;AAAA,EACvG,mBAAmB,UAAU,OAAO,YAAY,gDAAgD,EAAE,aAAa,GAAG;AAAA,EAClH,WAAW,UAAU,MAAM;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC,EACE,YAAY,+BAA+B,EAC3C,aAAa,KAAK;AAAA,EACrB,cAAc,UAAU,QAAQ,UAAU,MAAM,EAC7C,YAAY,mCAAmC,EAC/C,aAAa,CAAC,IAAI,EAAE,CAAC;AAAA,EACxB,0BAA0B,UAAU,UAAU;AAAA,IAC5C,UAAU,MAAM,CAAC,UAAU,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;AAAA,IAChD,UAAU,MAAM,CAAC,UAAU,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AAAA,IAC1C,UAAU,MAAM,CAAC,UAAU,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;AAAA,IAC9C,UAAU,MAAM,CAAC,UAAU,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;AAAA,IAClD,UAAU,MAAM,CAAC,UAAU,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;AAAA,IAC5C,UAAU,MAAM,CAAC,UAAU,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;AAAA,IAChD,UAAU,MAAM,CAAC,UAAU,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;AAAA,IACjD,UAAU,MAAM,CAAC,UAAU,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;AAAA,IAC7C,UAAU,MAAM,CAAC,UAAU,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;AAAA,IACnD,UAAU,MAAM,CAAC,UAAU,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;AAAA,IAC/C,UAAU,MAAM,CAAC,UAAU,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;AAAA,IAC3C,UAAU,MAAM,CAAC,UAAU,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;AAAA,EACnD,CAAC,EAAE,YAAY,wCAAwC;AAAA,EACvD,QAAQ,UAAU,KAAK,YAAY,sCAAsC;AAAA,EACzE,SAAS,UAAU,KAAK,YAAY,sCAAsC;AAAA,EAC1E,4BAA4B,UAAU,KAAK;AAAA,IACzC;AAAA,EACF;AAAA,EACA,0BAA0B,UAAU,WAAW,OAAO,EAAE;AAAA,IACtD;AAAA,EAEF;AAAA,EACA,gBAAgB,UAAU,KAAK;AAAA,IAC7B;AAAA,EACF;AAAA,EACA,eAAe,UAAU,KACtB,YAAY,sFAAsF,EAClG,aAAa,KAAK;AAAA,EACrB,UAAU,UAAU,KAAK,YAAY,2EAA2E;AAAA,EAChH,wBAAwB,UAAU,KAC/B,YAAY,qEAAqE,EACjF,aAAa,KAAK;AACvB;",
6
6
  "names": []
7
7
  }