@fluentui/react-positioning 9.23.1 → 9.23.3

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 (26) hide show
  1. package/CHANGELOG.md +23 -2
  2. package/lib/createPositionManager.js +18 -6
  3. package/lib/createPositionManager.js.map +1 -1
  4. package/lib/hooks/useSafeZoneArea/SafeZoneArea.js +51 -110
  5. package/lib/hooks/useSafeZoneArea/SafeZoneArea.js.map +1 -1
  6. package/lib/hooks/useSafeZoneArea/SafeZoneArea.styles.js +2 -2
  7. package/lib/hooks/useSafeZoneArea/SafeZoneArea.styles.js.map +1 -1
  8. package/lib/hooks/useSafeZoneArea/SafeZoneArea.styles.raw.js +2 -2
  9. package/lib/hooks/useSafeZoneArea/SafeZoneArea.styles.raw.js.map +1 -1
  10. package/lib/hooks/useSafeZoneArea/computeOutsideClipPath.js +3 -6
  11. package/lib/hooks/useSafeZoneArea/computeOutsideClipPath.js.map +1 -1
  12. package/lib/hooks/useSafeZoneArea/getSafeZonePoints.js +72 -0
  13. package/lib/hooks/useSafeZoneArea/getSafeZonePoints.js.map +1 -0
  14. package/lib-commonjs/createPositionManager.cjs +18 -6
  15. package/lib-commonjs/createPositionManager.cjs.map +1 -1
  16. package/lib-commonjs/hooks/useSafeZoneArea/SafeZoneArea.cjs +53 -121
  17. package/lib-commonjs/hooks/useSafeZoneArea/SafeZoneArea.cjs.map +1 -1
  18. package/lib-commonjs/hooks/useSafeZoneArea/SafeZoneArea.styles.cjs +2 -2
  19. package/lib-commonjs/hooks/useSafeZoneArea/SafeZoneArea.styles.cjs.map +1 -1
  20. package/lib-commonjs/hooks/useSafeZoneArea/SafeZoneArea.styles.raw.cjs +2 -2
  21. package/lib-commonjs/hooks/useSafeZoneArea/SafeZoneArea.styles.raw.cjs.map +1 -1
  22. package/lib-commonjs/hooks/useSafeZoneArea/computeOutsideClipPath.cjs +2 -5
  23. package/lib-commonjs/hooks/useSafeZoneArea/computeOutsideClipPath.cjs.map +1 -1
  24. package/lib-commonjs/hooks/useSafeZoneArea/getSafeZonePoints.cjs +82 -0
  25. package/lib-commonjs/hooks/useSafeZoneArea/getSafeZonePoints.cjs.map +1 -0
  26. package/package.json +10 -7
package/CHANGELOG.md CHANGED
@@ -1,12 +1,33 @@
1
1
  # Change Log - @fluentui/react-positioning
2
2
 
3
- <!-- This log was last generated on Tue, 11 Aug 2026 17:16:02 GMT and should not be manually modified. -->
3
+ <!-- This log was last generated on Wed, 23 Sep 2026 09:03:15 GMT and should not be manually modified. -->
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## [9.23.3](https://github.com/microsoft/fluentui/tree/@fluentui/react-positioning_v9.23.3)
8
+
9
+ Wed, 23 Sep 2026 09:03:15 GMT
10
+ [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-positioning_v9.23.2..@fluentui/react-positioning_v9.23.3)
11
+
12
+ ### Patches
13
+
14
+ - fix: improve safe zone hit testing and avoid rerenders during pointer movement ([PR #36708](https://github.com/microsoft/fluentui/pull/36708) by jakubmiskech@microsoft.com)
15
+
16
+ ## [9.23.2](https://github.com/microsoft/fluentui/tree/@fluentui/react-positioning_v9.23.2)
17
+
18
+ Tue, 22 Sep 2026 11:25:39 GMT
19
+ [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-positioning_v9.23.1..@fluentui/react-positioning_v9.23.2)
20
+
21
+ ### Patches
22
+
23
+ - fix: remove unused react-dom and @types/react-dom peer dependencies, mark @types/react as optional, require use-sync-external-store ^1.4.0 for react 19 support ([PR #36559](https://github.com/microsoft/fluentui/pull/36559) by martinhochel@microsoft.com)
24
+ - Treat unavailable positioning geometry as indeterminate when reporting visibility flags. ([PR #36758](https://github.com/microsoft/fluentui/pull/36758) by bernardo.sunderhus@gmail.com)
25
+ - Bump @fluentui/react-shared-contexts to v9.26.4 ([commit](https://github.com/microsoft/fluentui/commit/undefined) by beachball)
26
+ - Bump @fluentui/react-utilities to v9.26.7 ([commit](https://github.com/microsoft/fluentui/commit/undefined) by beachball)
27
+
7
28
  ## [9.23.1](https://github.com/microsoft/fluentui/tree/@fluentui/react-positioning_v9.23.1)
8
29
 
9
- Tue, 11 Aug 2026 17:16:02 GMT
30
+ Tue, 11 Aug 2026 17:20:14 GMT
10
31
  [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-positioning_v9.23.0..@fluentui/react-positioning_v9.23.1)
11
32
 
12
33
  ### Patches
@@ -4,6 +4,10 @@ import { debounce, writeArrowUpdates, writeContainerUpdates } from "./utils/inde
4
4
  import { listScrollParents } from "./utils/listScrollParents.js";
5
5
  import { POSITIONING_END_EVENT } from "./constants.js";
6
6
  import { createResizeObserver } from "./utils/createResizeObserver.js";
7
+ function isLayoutViewportUnavailable(container) {
8
+ const { clientWidth, clientHeight } = container.ownerDocument.documentElement;
9
+ return clientWidth === 0 && clientHeight === 0;
10
+ }
7
11
  /**
8
12
  * @internal
9
13
  * @returns manager that handles positioning out of the react lifecycle
@@ -68,19 +72,27 @@ import { createResizeObserver } from "./utils/createResizeObserver.js";
68
72
  middleware,
69
73
  strategy
70
74
  }).then(({ x, y, middlewareData, placement: computedPlacement })=>{
71
- var _middlewareData_hide, _middlewareData_hide1;
75
+ var _positioningMiddlewareData_hide, _positioningMiddlewareData_hide1;
72
76
  // Promise can still resolve after destruction
73
77
  // early return to avoid applying outdated position
74
78
  if (isDestroyed) {
75
79
  return;
76
80
  }
81
+ const positioningMiddlewareData = isLayoutViewportUnavailable(container) ? {
82
+ ...middlewareData,
83
+ hide: {
84
+ ...middlewareData.hide,
85
+ escaped: false,
86
+ referenceHidden: false
87
+ }
88
+ } : middlewareData;
77
89
  writeArrowUpdates({
78
90
  arrow,
79
- middlewareData
91
+ middlewareData: positioningMiddlewareData
80
92
  });
81
93
  writeContainerUpdates({
82
94
  container,
83
- middlewareData,
95
+ middlewareData: positioningMiddlewareData,
84
96
  placement: computedPlacement,
85
97
  coordinates: {
86
98
  x,
@@ -90,15 +102,15 @@ import { createResizeObserver } from "./utils/createResizeObserver.js";
90
102
  strategy,
91
103
  useTransform
92
104
  });
93
- var _middlewareData_hide_escaped, _middlewareData_hide_referenceHidden;
105
+ var _positioningMiddlewareData_hide_escaped, _positioningMiddlewareData_hide_referenceHidden;
94
106
  container.dispatchEvent(new CustomEvent(POSITIONING_END_EVENT, {
95
107
  detail: {
96
108
  // Cast from Floating UI's Placement to the Fluent-owned PositioningPlacement.
97
109
  // These are equivalent string unions; the cast avoids leaking @floating-ui/dom
98
110
  // types into the public API surface.
99
111
  placement: computedPlacement,
100
- escaped: (_middlewareData_hide_escaped = (_middlewareData_hide = middlewareData.hide) === null || _middlewareData_hide === void 0 ? void 0 : _middlewareData_hide.escaped) !== null && _middlewareData_hide_escaped !== void 0 ? _middlewareData_hide_escaped : false,
101
- referenceHidden: (_middlewareData_hide_referenceHidden = (_middlewareData_hide1 = middlewareData.hide) === null || _middlewareData_hide1 === void 0 ? void 0 : _middlewareData_hide1.referenceHidden) !== null && _middlewareData_hide_referenceHidden !== void 0 ? _middlewareData_hide_referenceHidden : false
112
+ escaped: (_positioningMiddlewareData_hide_escaped = (_positioningMiddlewareData_hide = positioningMiddlewareData.hide) === null || _positioningMiddlewareData_hide === void 0 ? void 0 : _positioningMiddlewareData_hide.escaped) !== null && _positioningMiddlewareData_hide_escaped !== void 0 ? _positioningMiddlewareData_hide_escaped : false,
113
+ referenceHidden: (_positioningMiddlewareData_hide_referenceHidden = (_positioningMiddlewareData_hide1 = positioningMiddlewareData.hide) === null || _positioningMiddlewareData_hide1 === void 0 ? void 0 : _positioningMiddlewareData_hide1.referenceHidden) !== null && _positioningMiddlewareData_hide_referenceHidden !== void 0 ? _positioningMiddlewareData_hide_referenceHidden : false
102
114
  }
103
115
  }));
104
116
  }).catch((err)=>{
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/createPositionManager.ts"],"sourcesContent":["import { computePosition } from '@floating-ui/dom';\nimport type { Middleware, Placement, Strategy } from '@floating-ui/dom';\nimport { isHTMLElement } from '@fluentui/react-utilities';\nimport type { OnPositioningEndEventDetail, PositionManager, PositioningPlacement, TargetElement } from './types';\nimport { debounce, writeArrowUpdates, writeContainerUpdates } from './utils';\nimport { listScrollParents } from './utils/listScrollParents';\nimport { POSITIONING_END_EVENT } from './constants';\nimport { createResizeObserver } from './utils/createResizeObserver';\n\ninterface PositionManagerOptions {\n /**\n * The positioned element\n */\n container: HTMLElement;\n /**\n * Element that the container will be anchored to\n */\n target: TargetElement;\n /**\n * Arrow that points from the container to the target\n */\n arrow: HTMLElement | null;\n /**\n * The value of the css `position` property\n * @default absolute\n */\n strategy: Strategy;\n /**\n * [Floating UI middleware](https://floating-ui.com/docs/middleware)\n */\n middleware: Middleware[];\n /**\n * [Floating UI placement](https://floating-ui.com/docs/computePosition#placement)\n */\n placement?: Placement;\n /**\n * Modifies whether popover is positioned using transform.\n * @default true\n */\n useTransform?: boolean;\n /**\n * Disables the resize observer that updates position on target or dimension change\n */\n disableUpdateOnResize?: boolean;\n}\n\n/**\n * @internal\n * @returns manager that handles positioning out of the react lifecycle\n */\nexport function createPositionManager(options: PositionManagerOptions): PositionManager {\n let isDestroyed = false;\n const {\n container,\n target,\n arrow,\n strategy,\n middleware,\n placement,\n useTransform = true,\n disableUpdateOnResize = false,\n } = options;\n const targetWindow = container.ownerDocument.defaultView;\n if (!target || !container || !targetWindow) {\n return {\n updatePosition: () => undefined,\n dispose: () => undefined,\n };\n }\n\n // When the dimensions of the target or the container change - trigger a position update\n const resizeObserver = disableUpdateOnResize\n ? null\n : createResizeObserver(targetWindow, entries => {\n // If content rect dimensions to go 0 -> very likely that `display: none` is being used to hide the element\n // In this case don't update and let users update imperatively\n const shouldUpdateOnResize = entries.every(entry => {\n return entry.contentRect.width > 0 && entry.contentRect.height > 0;\n });\n\n if (shouldUpdateOnResize) {\n updatePosition();\n }\n });\n\n let isFirstUpdate = true;\n const scrollParents: Set<HTMLElement> = new Set<HTMLElement>();\n\n // When the container is first resolved, set position `fixed` to avoid scroll jumps.\n // Without this scroll jumps can occur when the element is rendered initially and receives focus\n Object.assign(container.style, { position: 'fixed', left: 0, top: 0, margin: 0 });\n\n const forceUpdate = () => {\n // debounced update can still occur afterwards\n // early return to avoid memory leaks\n if (isDestroyed) {\n return;\n }\n\n if (isFirstUpdate) {\n listScrollParents(container).forEach(scrollParent => scrollParents.add(scrollParent));\n if (isHTMLElement(target)) {\n listScrollParents(target).forEach(scrollParent => scrollParents.add(scrollParent));\n }\n\n scrollParents.forEach(scrollParent => {\n scrollParent.addEventListener('scroll', updatePosition, { passive: true });\n });\n\n resizeObserver?.observe(container);\n if (isHTMLElement(target)) {\n resizeObserver?.observe(target);\n }\n\n isFirstUpdate = false;\n }\n\n Object.assign(container.style, { position: strategy });\n computePosition(target, container, { placement, middleware, strategy })\n .then(({ x, y, middlewareData, placement: computedPlacement }) => {\n // Promise can still resolve after destruction\n // early return to avoid applying outdated position\n if (isDestroyed) {\n return;\n }\n\n writeArrowUpdates({ arrow, middlewareData });\n writeContainerUpdates({\n container,\n middlewareData,\n placement: computedPlacement,\n coordinates: { x, y },\n lowPPI: (targetWindow?.devicePixelRatio || 1) <= 1,\n strategy,\n useTransform,\n });\n\n container.dispatchEvent(\n new CustomEvent<OnPositioningEndEventDetail>(POSITIONING_END_EVENT, {\n detail: {\n // Cast from Floating UI's Placement to the Fluent-owned PositioningPlacement.\n // These are equivalent string unions; the cast avoids leaking @floating-ui/dom\n // types into the public API surface.\n placement: computedPlacement satisfies PositioningPlacement,\n escaped: middlewareData.hide?.escaped ?? false,\n referenceHidden: middlewareData.hide?.referenceHidden ?? false,\n },\n }),\n );\n })\n .catch(err => {\n // https://github.com/floating-ui/floating-ui/issues/1845\n // FIXME for node > 14\n // node 15 introduces promise rejection which means that any components\n // tests need to be `it('', async () => {})` otherwise there can be race conditions with\n // JSDOM being torn down before this promise is resolved so globals like `window` and `document` don't exist\n // Unless all tests that ever use `usePositioning` are turned into async tests, any logging during testing\n // will actually be counter productive\n if (process.env.NODE_ENV === 'development') {\n // eslint-disable-next-line no-console\n console.error('[usePositioning]: Failed to calculate position', err);\n }\n });\n };\n\n const updatePosition = debounce(() => forceUpdate());\n\n const dispose = () => {\n isDestroyed = true;\n\n if (targetWindow) {\n targetWindow.removeEventListener('scroll', updatePosition);\n targetWindow.removeEventListener('resize', updatePosition);\n }\n\n scrollParents.forEach(scrollParent => {\n scrollParent.removeEventListener('scroll', updatePosition);\n });\n scrollParents.clear();\n\n resizeObserver?.disconnect();\n };\n\n if (targetWindow) {\n targetWindow.addEventListener('scroll', updatePosition, { passive: true });\n targetWindow.addEventListener('resize', updatePosition);\n }\n\n // Update the position on initialization\n updatePosition();\n\n return {\n updatePosition,\n dispose,\n };\n}\n"],"names":["computePosition","isHTMLElement","debounce","writeArrowUpdates","writeContainerUpdates","listScrollParents","POSITIONING_END_EVENT","createResizeObserver","createPositionManager","options","isDestroyed","container","target","arrow","strategy","middleware","placement","useTransform","disableUpdateOnResize","targetWindow","ownerDocument","defaultView","updatePosition","undefined","dispose","resizeObserver","entries","shouldUpdateOnResize","every","entry","contentRect","width","height","isFirstUpdate","scrollParents","Set","Object","assign","style","position","left","top","margin","forceUpdate","forEach","scrollParent","add","addEventListener","passive","observe","then","x","y","middlewareData","computedPlacement","coordinates","lowPPI","devicePixelRatio","dispatchEvent","CustomEvent","detail","escaped","hide","referenceHidden","catch","err","process","env","NODE_ENV","console","error","removeEventListener","clear","disconnect"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/createPositionManager.ts"],"sourcesContent":["import { computePosition } from '@floating-ui/dom';\nimport type { Middleware, Placement, Strategy } from '@floating-ui/dom';\nimport { isHTMLElement } from '@fluentui/react-utilities';\nimport type { OnPositioningEndEventDetail, PositionManager, PositioningPlacement, TargetElement } from './types';\nimport { debounce, writeArrowUpdates, writeContainerUpdates } from './utils';\nimport { listScrollParents } from './utils/listScrollParents';\nimport { POSITIONING_END_EVENT } from './constants';\nimport { createResizeObserver } from './utils/createResizeObserver';\n\ninterface PositionManagerOptions {\n /**\n * The positioned element\n */\n container: HTMLElement;\n /**\n * Element that the container will be anchored to\n */\n target: TargetElement;\n /**\n * Arrow that points from the container to the target\n */\n arrow: HTMLElement | null;\n /**\n * The value of the css `position` property\n * @default absolute\n */\n strategy: Strategy;\n /**\n * [Floating UI middleware](https://floating-ui.com/docs/middleware)\n */\n middleware: Middleware[];\n /**\n * [Floating UI placement](https://floating-ui.com/docs/computePosition#placement)\n */\n placement?: Placement;\n /**\n * Modifies whether popover is positioned using transform.\n * @default true\n */\n useTransform?: boolean;\n /**\n * Disables the resize observer that updates position on target or dimension change\n */\n disableUpdateOnResize?: boolean;\n}\n\nfunction isLayoutViewportUnavailable(container: HTMLElement): boolean {\n const { clientWidth, clientHeight } = container.ownerDocument.documentElement;\n\n return clientWidth === 0 && clientHeight === 0;\n}\n\n/**\n * @internal\n * @returns manager that handles positioning out of the react lifecycle\n */\nexport function createPositionManager(options: PositionManagerOptions): PositionManager {\n let isDestroyed = false;\n const {\n container,\n target,\n arrow,\n strategy,\n middleware,\n placement,\n useTransform = true,\n disableUpdateOnResize = false,\n } = options;\n const targetWindow = container.ownerDocument.defaultView;\n if (!target || !container || !targetWindow) {\n return {\n updatePosition: () => undefined,\n dispose: () => undefined,\n };\n }\n\n // When the dimensions of the target or the container change - trigger a position update\n const resizeObserver = disableUpdateOnResize\n ? null\n : createResizeObserver(targetWindow, entries => {\n // If content rect dimensions to go 0 -> very likely that `display: none` is being used to hide the element\n // In this case don't update and let users update imperatively\n const shouldUpdateOnResize = entries.every(entry => {\n return entry.contentRect.width > 0 && entry.contentRect.height > 0;\n });\n\n if (shouldUpdateOnResize) {\n updatePosition();\n }\n });\n\n let isFirstUpdate = true;\n const scrollParents: Set<HTMLElement> = new Set<HTMLElement>();\n\n // When the container is first resolved, set position `fixed` to avoid scroll jumps.\n // Without this scroll jumps can occur when the element is rendered initially and receives focus\n Object.assign(container.style, { position: 'fixed', left: 0, top: 0, margin: 0 });\n\n const forceUpdate = () => {\n // debounced update can still occur afterwards\n // early return to avoid memory leaks\n if (isDestroyed) {\n return;\n }\n\n if (isFirstUpdate) {\n listScrollParents(container).forEach(scrollParent => scrollParents.add(scrollParent));\n if (isHTMLElement(target)) {\n listScrollParents(target).forEach(scrollParent => scrollParents.add(scrollParent));\n }\n\n scrollParents.forEach(scrollParent => {\n scrollParent.addEventListener('scroll', updatePosition, { passive: true });\n });\n\n resizeObserver?.observe(container);\n if (isHTMLElement(target)) {\n resizeObserver?.observe(target);\n }\n\n isFirstUpdate = false;\n }\n\n Object.assign(container.style, { position: strategy });\n computePosition(target, container, { placement, middleware, strategy })\n .then(({ x, y, middlewareData, placement: computedPlacement }) => {\n // Promise can still resolve after destruction\n // early return to avoid applying outdated position\n if (isDestroyed) {\n return;\n }\n\n const positioningMiddlewareData = isLayoutViewportUnavailable(container)\n ? {\n ...middlewareData,\n hide: { ...middlewareData.hide, escaped: false, referenceHidden: false },\n }\n : middlewareData;\n\n writeArrowUpdates({ arrow, middlewareData: positioningMiddlewareData });\n writeContainerUpdates({\n container,\n middlewareData: positioningMiddlewareData,\n placement: computedPlacement,\n coordinates: { x, y },\n lowPPI: (targetWindow?.devicePixelRatio || 1) <= 1,\n strategy,\n useTransform,\n });\n\n container.dispatchEvent(\n new CustomEvent<OnPositioningEndEventDetail>(POSITIONING_END_EVENT, {\n detail: {\n // Cast from Floating UI's Placement to the Fluent-owned PositioningPlacement.\n // These are equivalent string unions; the cast avoids leaking @floating-ui/dom\n // types into the public API surface.\n placement: computedPlacement satisfies PositioningPlacement,\n escaped: positioningMiddlewareData.hide?.escaped ?? false,\n referenceHidden: positioningMiddlewareData.hide?.referenceHidden ?? false,\n },\n }),\n );\n })\n .catch(err => {\n // https://github.com/floating-ui/floating-ui/issues/1845\n // FIXME for node > 14\n // node 15 introduces promise rejection which means that any components\n // tests need to be `it('', async () => {})` otherwise there can be race conditions with\n // JSDOM being torn down before this promise is resolved so globals like `window` and `document` don't exist\n // Unless all tests that ever use `usePositioning` are turned into async tests, any logging during testing\n // will actually be counter productive\n if (process.env.NODE_ENV === 'development') {\n // eslint-disable-next-line no-console\n console.error('[usePositioning]: Failed to calculate position', err);\n }\n });\n };\n\n const updatePosition = debounce(() => forceUpdate());\n\n const dispose = () => {\n isDestroyed = true;\n\n if (targetWindow) {\n targetWindow.removeEventListener('scroll', updatePosition);\n targetWindow.removeEventListener('resize', updatePosition);\n }\n\n scrollParents.forEach(scrollParent => {\n scrollParent.removeEventListener('scroll', updatePosition);\n });\n scrollParents.clear();\n\n resizeObserver?.disconnect();\n };\n\n if (targetWindow) {\n targetWindow.addEventListener('scroll', updatePosition, { passive: true });\n targetWindow.addEventListener('resize', updatePosition);\n }\n\n // Update the position on initialization\n updatePosition();\n\n return {\n updatePosition,\n dispose,\n };\n}\n"],"names":["computePosition","isHTMLElement","debounce","writeArrowUpdates","writeContainerUpdates","listScrollParents","POSITIONING_END_EVENT","createResizeObserver","isLayoutViewportUnavailable","container","clientWidth","clientHeight","ownerDocument","documentElement","createPositionManager","options","isDestroyed","target","arrow","strategy","middleware","placement","useTransform","disableUpdateOnResize","targetWindow","defaultView","updatePosition","undefined","dispose","resizeObserver","entries","shouldUpdateOnResize","every","entry","contentRect","width","height","isFirstUpdate","scrollParents","Set","Object","assign","style","position","left","top","margin","forceUpdate","forEach","scrollParent","add","addEventListener","passive","observe","then","x","y","middlewareData","computedPlacement","positioningMiddlewareData","hide","escaped","referenceHidden","coordinates","lowPPI","devicePixelRatio","dispatchEvent","CustomEvent","detail","catch","err","process","env","NODE_ENV","console","error","removeEventListener","clear","disconnect"],"mappings":"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"}
@@ -8,34 +8,13 @@ import { getMouseAnchor } from "./getMouseAnchor.js";
8
8
  import { pointsToSvgPath } from "./pointsToSvgPath.js";
9
9
  import { useStyles } from "./SafeZoneArea.styles.js";
10
10
  import { computeOutsideClipPath } from "./computeOutsideClipPath.js";
11
- // ---
12
- const EMPTY_RECT = {
13
- top: 0,
14
- right: 0,
15
- bottom: 0,
16
- left: 0,
17
- width: 0,
18
- height: 0,
19
- x: 0,
20
- y: 0,
21
- toJSON () {
22
- return '';
23
- }
24
- };
25
- export function isSameRect(a, b) {
26
- return a.top === b.top && a.right === b.right && a.bottom === b.bottom && a.left === b.left && a.width === b.width && a.height === b.height;
27
- }
28
- export function isSameCoordinates(a, b) {
29
- return a[0] === b[0] && a[1] === b[1];
30
- }
11
+ import { getSafeZonePoints } from "./getSafeZonePoints.js";
31
12
  // ---
32
13
  /**
33
14
  * A component that renders a safe zone area with SVG shapes. Uses `useSyncExternalStore` to manage its active state
34
15
  * to avoid causing re-renders in `useSafeZoneArea()` as the hook might be used in host components like `Menu`.
35
16
  *
36
- * Draws two shapes:
37
- * - a triangle that points to the target element which is an actual safe zone
38
- * - a rectangle for a clip path that clips out the target element
17
+ * Draws a polygon from the mouse to the facing edges of the container and clips out the target element.
39
18
  *
40
19
  * @internal
41
20
  */ export const SafeZoneArea = /*#__PURE__*/ React.memo((props)=>{
@@ -44,114 +23,76 @@ export function isSameCoordinates(a, b) {
44
23
  const styles = useStyles();
45
24
  const active = useSyncExternalStore(stateStore.subscribe, stateStore.isActive);
46
25
  const svgRef = React.useRef(null);
47
- const [state, setState] = React.useState(()=>({
48
- containerRect: EMPTY_RECT,
49
- targetRect: EMPTY_RECT,
50
- mouseCoordinates: [
51
- 0,
52
- 0
53
- ]
54
- }));
26
+ const safeZoneRef = React.useRef(null);
27
+ const clipPathRef = React.useRef(null);
28
+ const rectDebugRef = React.useRef(null);
55
29
  React.useImperativeHandle(props.imperativeRef, ()=>({
56
- updateSVG (newState) {
57
- setState((prevState)=>{
58
- // Heads up!
59
- // A small optimization to avoid unnecessary re-renders
60
- if (isSameRect(prevState.containerRect, newState.containerRect) && isSameRect(prevState.targetRect, newState.targetRect) && isSameCoordinates(prevState.mouseCoordinates, newState.mouseCoordinates)) {
61
- return prevState;
62
- }
63
- return newState;
30
+ updateSVG ({ containerRect, targetRect, mouseCoordinates }) {
31
+ var _safeZoneRef_current, _clipPathRef_current, _rectDebugRef_current;
32
+ const topOffset = Math.min(targetRect.top, containerRect.top);
33
+ const leftOffset = Math.min(targetRect.left, containerRect.left);
34
+ const bottomOffset = Math.max(targetRect.bottom, containerRect.bottom);
35
+ const rightOffset = Math.max(targetRect.right, containerRect.right);
36
+ const containerCorners = getRectCorners(containerRect, [
37
+ leftOffset,
38
+ topOffset
39
+ ]);
40
+ const targetCorners = getRectCorners(targetRect, [
41
+ leftOffset,
42
+ topOffset
43
+ ]);
44
+ // SVG coordinates are relative to its top-left corner.
45
+ const relativeMouseCoordinates = [
46
+ mouseCoordinates[0] - leftOffset,
47
+ mouseCoordinates[1] - topOffset
48
+ ];
49
+ const mouseAnchor = getMouseAnchor(containerCorners.topLeft, containerCorners.bottomRight, relativeMouseCoordinates);
50
+ const svgWidth = rightOffset - leftOffset;
51
+ const svgHeight = bottomOffset - topOffset;
52
+ const clipPath = computeOutsideClipPath(svgWidth, svgHeight, {
53
+ x: targetCorners.topLeft[0],
54
+ y: targetCorners.topLeft[1],
55
+ width: targetRect.width,
56
+ height: targetRect.height
64
57
  });
58
+ if (svgRef.current) {
59
+ svgRef.current.style.width = `${svgWidth}px`;
60
+ svgRef.current.style.height = `${svgHeight}px`;
61
+ svgRef.current.style.transform = `translate(${leftOffset}px, ${topOffset}px)`;
62
+ }
63
+ const safeZonePoints = getSafeZonePoints(mouseAnchor, containerCorners);
64
+ (_safeZoneRef_current = safeZoneRef.current) === null || _safeZoneRef_current === void 0 ? void 0 : _safeZoneRef_current.setAttribute('d', safeZonePoints.length > 0 ? pointsToSvgPath(safeZonePoints) : '');
65
+ (_clipPathRef_current = clipPathRef.current) === null || _clipPathRef_current === void 0 ? void 0 : _clipPathRef_current.setAttribute('d', clipPath);
66
+ (_rectDebugRef_current = rectDebugRef.current) === null || _rectDebugRef_current === void 0 ? void 0 : _rectDebugRef_current.setAttribute('d', clipPath);
65
67
  }
66
68
  }), []);
67
- const { containerRect, targetRect, mouseCoordinates } = state;
68
- const topOffset = Math.min(targetRect.top, containerRect.top);
69
- const leftOffset = Math.min(targetRect.left, containerRect.left);
70
- const bottomOffset = Math.max(targetRect.bottom, containerRect.bottom);
71
- const rightOffset = Math.max(targetRect.right, containerRect.right);
72
- // ---
73
- const containerCorners = getRectCorners(containerRect, [
74
- leftOffset,
75
- topOffset
76
- ]);
77
- const targetCorners = getRectCorners(targetRect, [
78
- leftOffset,
79
- topOffset
80
- ]);
81
- // Heads up!
82
- // The SVG coordinate system starts at the top-left corner of the SVG element,
83
- // so we need to adjust the mouse coordinates relative to the SVG's top-left corner.
84
- const relativeMouseCoordinates = [
85
- mouseCoordinates[0] - leftOffset,
86
- mouseCoordinates[1] - topOffset
87
- ];
88
- const mouseAnchor = getMouseAnchor(containerCorners.topLeft, containerCorners.bottomRight, relativeMouseCoordinates);
89
- const triangleA = [
90
- mouseAnchor,
91
- containerCorners.topLeft,
92
- containerCorners.topRight
93
- ];
94
- const triangleB = [
95
- mouseAnchor,
96
- containerCorners.topRight,
97
- containerCorners.bottomRight
98
- ];
99
- const triangleC = [
100
- mouseAnchor,
101
- containerCorners.bottomRight,
102
- containerCorners.bottomLeft
103
- ];
104
- const triangleD = [
105
- mouseAnchor,
106
- containerCorners.bottomLeft,
107
- containerCorners.topLeft
108
- ];
109
- const svgWidth = rightOffset - leftOffset;
110
- const svgHeight = bottomOffset - topOffset;
111
- const clipPath = computeOutsideClipPath(svgWidth, svgHeight, {
112
- x: targetCorners.topLeft[0],
113
- y: targetCorners.topLeft[1],
114
- width: targetRect.width,
115
- height: targetRect.height
116
- }, {
117
- x: containerCorners.topLeft[0],
118
- y: containerCorners.topLeft[1],
119
- width: containerRect.width,
120
- height: containerRect.height
121
- });
122
69
  return /*#__PURE__*/ React.createElement("div", {
123
70
  className: mergeClasses(styles.wrapper, active && styles.wrapperActive),
124
71
  "data-safe-zone": ""
125
- }, active ? /*#__PURE__*/ React.createElement("svg", {
72
+ }, /*#__PURE__*/ React.createElement("svg", {
126
73
  "aria-hidden": true,
127
74
  className: styles.svg,
128
75
  xmlns: "http://www.w3.org/2000/svg",
129
76
  ref: svgRef,
130
77
  style: {
131
- width: `${svgWidth}px`,
132
- height: `${svgHeight}px`,
133
- transform: `translate(${leftOffset}px, ${topOffset}px)`
78
+ width: 0,
79
+ height: 0,
80
+ transform: 'translate(0px, 0px)'
134
81
  }
135
82
  }, /*#__PURE__*/ React.createElement("g", {
136
- className: mergeClasses(styles.triangle, debug && styles.triangleDebug),
83
+ className: mergeClasses(styles.safeZone, debug && styles.safeZoneDebug),
137
84
  clipPath: `url(#${clipPathId})`,
138
85
  onMouseEnter: onMouseEnter,
139
86
  onMouseMove: onMouseMove,
140
87
  onMouseLeave: onMouseLeave
141
88
  }, /*#__PURE__*/ React.createElement("path", {
142
- d: pointsToSvgPath(triangleA)
143
- }), /*#__PURE__*/ React.createElement("path", {
144
- d: pointsToSvgPath(triangleB)
145
- }), /*#__PURE__*/ React.createElement("path", {
146
- d: pointsToSvgPath(triangleC)
147
- }), /*#__PURE__*/ React.createElement("path", {
148
- d: pointsToSvgPath(triangleD)
89
+ ref: safeZoneRef
149
90
  })), /*#__PURE__*/ React.createElement("clipPath", {
150
91
  id: clipPathId
151
92
  }, /*#__PURE__*/ React.createElement("path", {
152
- d: clipPath
93
+ ref: clipPathRef
153
94
  })), debug && /*#__PURE__*/ React.createElement("path", {
154
- className: styles.rectDebug,
155
- d: clipPath
156
- })) : null);
95
+ ref: rectDebugRef,
96
+ className: styles.rectDebug
97
+ })));
157
98
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/hooks/useSafeZoneArea/SafeZoneArea.tsx"],"sourcesContent":["'use client';\n\nimport { mergeClasses } from '@griffel/react';\nimport { useId } from '@fluentui/react-utilities';\nimport type { JSXElement } from '@fluentui/react-utilities';\nimport * as React from 'react';\nimport { useSyncExternalStore } from 'use-sync-external-store/shim';\n\nimport type { createSafeZoneAreaStateStore } from './createSafeZoneAreaStateStore';\nimport { getRectCorners } from './getRectCorners';\nimport { getMouseAnchor } from './getMouseAnchor';\nimport { pointsToSvgPath } from './pointsToSvgPath';\nimport { useStyles } from './SafeZoneArea.styles';\nimport type { Point } from './types';\nimport { computeOutsideClipPath } from './computeOutsideClipPath';\n\nexport type SafeZoneAreaImperativeHandle = {\n updateSVG: (options: { containerRect: DOMRect; targetRect: DOMRect; mouseCoordinates: Point }) => void;\n};\n\nexport type SafeZoneAreaProps = {\n /** Enables debug mode: makes drawn shapes visible. */\n debug: boolean;\n\n /** A reference to the SafeZoneArea imperative handle. */\n imperativeRef: React.Ref<SafeZoneAreaImperativeHandle>;\n\n // eslint-disable-next-line @nx/workspace-consistent-callback-type\n onMouseEnter: (e: React.MouseEvent) => void;\n // eslint-disable-next-line @nx/workspace-consistent-callback-type\n onMouseMove: (e: React.MouseEvent) => void;\n // eslint-disable-next-line @nx/workspace-consistent-callback-type\n onMouseLeave: (e: React.MouseEvent) => void;\n\n stateStore: ReturnType<typeof createSafeZoneAreaStateStore>;\n};\n\n/**\n * @internal\n */\ntype SafeZoneAreaState = {\n containerRect: DOMRect;\n targetRect: DOMRect;\n mouseCoordinates: Point;\n};\n\n// ---\n\nconst EMPTY_RECT: DOMRect = {\n top: 0,\n right: 0,\n bottom: 0,\n left: 0,\n width: 0,\n height: 0,\n x: 0,\n y: 0,\n toJSON() {\n return '';\n },\n};\n\nexport function isSameRect(a: DOMRect, b: DOMRect): boolean {\n return (\n a.top === b.top &&\n a.right === b.right &&\n a.bottom === b.bottom &&\n a.left === b.left &&\n a.width === b.width &&\n a.height === b.height\n );\n}\n\nexport function isSameCoordinates(a: Point, b: Point): boolean {\n return a[0] === b[0] && a[1] === b[1];\n}\n\n// ---\n\n/**\n * A component that renders a safe zone area with SVG shapes. Uses `useSyncExternalStore` to manage its active state\n * to avoid causing re-renders in `useSafeZoneArea()` as the hook might be used in host components like `Menu`.\n *\n * Draws two shapes:\n * - a triangle that points to the target element which is an actual safe zone\n * - a rectangle for a clip path that clips out the target element\n *\n * @internal\n */\nexport const SafeZoneArea = React.memo((props: SafeZoneAreaProps): JSXElement => {\n const { debug, onMouseEnter, onMouseMove, onMouseLeave, stateStore } = props;\n\n const clipPathId = useId();\n const styles = useStyles();\n\n const active = useSyncExternalStore(stateStore.subscribe, stateStore.isActive);\n const svgRef = React.useRef<SVGSVGElement>(null);\n\n const [state, setState] = React.useState<SafeZoneAreaState>(() => ({\n containerRect: EMPTY_RECT,\n targetRect: EMPTY_RECT,\n mouseCoordinates: [0, 0],\n }));\n\n React.useImperativeHandle(\n props.imperativeRef,\n () => ({\n updateSVG(newState) {\n setState(prevState => {\n // Heads up!\n // A small optimization to avoid unnecessary re-renders\n if (\n isSameRect(prevState.containerRect, newState.containerRect) &&\n isSameRect(prevState.targetRect, newState.targetRect) &&\n isSameCoordinates(prevState.mouseCoordinates, newState.mouseCoordinates)\n ) {\n return prevState;\n }\n\n return newState;\n });\n },\n }),\n [],\n );\n\n const { containerRect, targetRect, mouseCoordinates } = state;\n\n const topOffset = Math.min(targetRect.top, containerRect.top);\n const leftOffset = Math.min(targetRect.left, containerRect.left);\n const bottomOffset = Math.max(targetRect.bottom, containerRect.bottom);\n const rightOffset = Math.max(targetRect.right, containerRect.right);\n\n // ---\n\n const containerCorners = getRectCorners(containerRect, [leftOffset, topOffset]);\n const targetCorners = getRectCorners(targetRect, [leftOffset, topOffset]);\n\n // Heads up!\n // The SVG coordinate system starts at the top-left corner of the SVG element,\n // so we need to adjust the mouse coordinates relative to the SVG's top-left corner.\n const relativeMouseCoordinates: Point = [mouseCoordinates[0] - leftOffset, mouseCoordinates[1] - topOffset];\n const mouseAnchor = getMouseAnchor(containerCorners.topLeft, containerCorners.bottomRight, relativeMouseCoordinates);\n\n const triangleA = [mouseAnchor, containerCorners.topLeft, containerCorners.topRight];\n const triangleB = [mouseAnchor, containerCorners.topRight, containerCorners.bottomRight];\n const triangleC = [mouseAnchor, containerCorners.bottomRight, containerCorners.bottomLeft];\n const triangleD = [mouseAnchor, containerCorners.bottomLeft, containerCorners.topLeft];\n\n const svgWidth = rightOffset - leftOffset;\n const svgHeight = bottomOffset - topOffset;\n\n const clipPath = computeOutsideClipPath(\n svgWidth,\n svgHeight,\n {\n x: targetCorners.topLeft[0],\n y: targetCorners.topLeft[1],\n width: targetRect.width,\n height: targetRect.height,\n },\n {\n x: containerCorners.topLeft[0],\n y: containerCorners.topLeft[1],\n width: containerRect.width,\n height: containerRect.height,\n },\n );\n\n return (\n <div className={mergeClasses(styles.wrapper, active && styles.wrapperActive)} data-safe-zone=\"\">\n {active ? (\n <svg\n aria-hidden\n className={styles.svg}\n xmlns=\"http://www.w3.org/2000/svg\"\n ref={svgRef}\n style={{\n width: `${svgWidth}px`,\n height: `${svgHeight}px`,\n transform: `translate(${leftOffset}px, ${topOffset}px)`,\n }}\n >\n <g\n className={mergeClasses(styles.triangle, debug && styles.triangleDebug)}\n clipPath={`url(#${clipPathId})`}\n onMouseEnter={onMouseEnter}\n onMouseMove={onMouseMove}\n onMouseLeave={onMouseLeave}\n >\n <path d={pointsToSvgPath(triangleA)} />\n <path d={pointsToSvgPath(triangleB)} />\n <path d={pointsToSvgPath(triangleC)} />\n <path d={pointsToSvgPath(triangleD)} />\n </g>\n\n <clipPath id={clipPathId}>\n <path d={clipPath} />\n </clipPath>\n\n {debug && <path className={styles.rectDebug} d={clipPath} />}\n </svg>\n ) : null}\n </div>\n );\n});\n"],"names":["mergeClasses","useId","React","useSyncExternalStore","getRectCorners","getMouseAnchor","pointsToSvgPath","useStyles","computeOutsideClipPath","EMPTY_RECT","top","right","bottom","left","width","height","x","y","toJSON","isSameRect","a","b","isSameCoordinates","SafeZoneArea","memo","props","debug","onMouseEnter","onMouseMove","onMouseLeave","stateStore","clipPathId","styles","active","subscribe","isActive","svgRef","useRef","state","setState","useState","containerRect","targetRect","mouseCoordinates","useImperativeHandle","imperativeRef","updateSVG","newState","prevState","topOffset","Math","min","leftOffset","bottomOffset","max","rightOffset","containerCorners","targetCorners","relativeMouseCoordinates","mouseAnchor","topLeft","bottomRight","triangleA","topRight","triangleB","triangleC","bottomLeft","triangleD","svgWidth","svgHeight","clipPath","div","className","wrapper","wrapperActive","data-safe-zone","svg","aria-hidden","xmlns","ref","style","transform","g","triangle","triangleDebug","path","d","id","rectDebug"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/hooks/useSafeZoneArea/SafeZoneArea.tsx"],"sourcesContent":["'use client';\n\nimport { mergeClasses } from '@griffel/react';\nimport { useId } from '@fluentui/react-utilities';\nimport type { JSXElement } from '@fluentui/react-utilities';\nimport * as React from 'react';\nimport { useSyncExternalStore } from 'use-sync-external-store/shim';\n\nimport type { createSafeZoneAreaStateStore } from './createSafeZoneAreaStateStore';\nimport { getRectCorners } from './getRectCorners';\nimport { getMouseAnchor } from './getMouseAnchor';\nimport { pointsToSvgPath } from './pointsToSvgPath';\nimport { useStyles } from './SafeZoneArea.styles';\nimport type { Point } from './types';\nimport { computeOutsideClipPath } from './computeOutsideClipPath';\nimport { getSafeZonePoints } from './getSafeZonePoints';\n\nexport type SafeZoneAreaImperativeHandle = {\n updateSVG: (options: { containerRect: DOMRect; targetRect: DOMRect; mouseCoordinates: Point }) => void;\n};\n\nexport type SafeZoneAreaProps = {\n /** Enables debug mode: makes drawn shapes visible. */\n debug: boolean;\n\n /** A reference to the SafeZoneArea imperative handle. */\n imperativeRef: React.Ref<SafeZoneAreaImperativeHandle>;\n\n // eslint-disable-next-line @nx/workspace-consistent-callback-type\n onMouseEnter: (e: React.MouseEvent) => void;\n // eslint-disable-next-line @nx/workspace-consistent-callback-type\n onMouseMove: (e: React.MouseEvent) => void;\n // eslint-disable-next-line @nx/workspace-consistent-callback-type\n onMouseLeave: (e: React.MouseEvent) => void;\n\n stateStore: ReturnType<typeof createSafeZoneAreaStateStore>;\n};\n\n// ---\n\n/**\n * A component that renders a safe zone area with SVG shapes. Uses `useSyncExternalStore` to manage its active state\n * to avoid causing re-renders in `useSafeZoneArea()` as the hook might be used in host components like `Menu`.\n *\n * Draws a polygon from the mouse to the facing edges of the container and clips out the target element.\n *\n * @internal\n */\nexport const SafeZoneArea = React.memo((props: SafeZoneAreaProps): JSXElement => {\n const { debug, onMouseEnter, onMouseMove, onMouseLeave, stateStore } = props;\n\n const clipPathId = useId();\n const styles = useStyles();\n\n const active = useSyncExternalStore(stateStore.subscribe, stateStore.isActive);\n const svgRef = React.useRef<SVGSVGElement>(null);\n const safeZoneRef = React.useRef<SVGPathElement>(null);\n const clipPathRef = React.useRef<SVGPathElement>(null);\n const rectDebugRef = React.useRef<SVGPathElement>(null);\n\n React.useImperativeHandle(\n props.imperativeRef,\n () => ({\n updateSVG({ containerRect, targetRect, mouseCoordinates }) {\n const topOffset = Math.min(targetRect.top, containerRect.top);\n const leftOffset = Math.min(targetRect.left, containerRect.left);\n const bottomOffset = Math.max(targetRect.bottom, containerRect.bottom);\n const rightOffset = Math.max(targetRect.right, containerRect.right);\n\n const containerCorners = getRectCorners(containerRect, [leftOffset, topOffset]);\n const targetCorners = getRectCorners(targetRect, [leftOffset, topOffset]);\n\n // SVG coordinates are relative to its top-left corner.\n const relativeMouseCoordinates: Point = [mouseCoordinates[0] - leftOffset, mouseCoordinates[1] - topOffset];\n const mouseAnchor = getMouseAnchor(\n containerCorners.topLeft,\n containerCorners.bottomRight,\n relativeMouseCoordinates,\n );\n\n const svgWidth = rightOffset - leftOffset;\n const svgHeight = bottomOffset - topOffset;\n const clipPath = computeOutsideClipPath(svgWidth, svgHeight, {\n x: targetCorners.topLeft[0],\n y: targetCorners.topLeft[1],\n width: targetRect.width,\n height: targetRect.height,\n });\n\n if (svgRef.current) {\n svgRef.current.style.width = `${svgWidth}px`;\n svgRef.current.style.height = `${svgHeight}px`;\n svgRef.current.style.transform = `translate(${leftOffset}px, ${topOffset}px)`;\n }\n\n const safeZonePoints = getSafeZonePoints(mouseAnchor, containerCorners);\n safeZoneRef.current?.setAttribute('d', safeZonePoints.length > 0 ? pointsToSvgPath(safeZonePoints) : '');\n clipPathRef.current?.setAttribute('d', clipPath);\n rectDebugRef.current?.setAttribute('d', clipPath);\n },\n }),\n [],\n );\n\n return (\n <div className={mergeClasses(styles.wrapper, active && styles.wrapperActive)} data-safe-zone=\"\">\n <svg\n aria-hidden\n className={styles.svg}\n xmlns=\"http://www.w3.org/2000/svg\"\n ref={svgRef}\n style={{ width: 0, height: 0, transform: 'translate(0px, 0px)' }}\n >\n <g\n className={mergeClasses(styles.safeZone, debug && styles.safeZoneDebug)}\n clipPath={`url(#${clipPathId})`}\n onMouseEnter={onMouseEnter}\n onMouseMove={onMouseMove}\n onMouseLeave={onMouseLeave}\n >\n <path ref={safeZoneRef} />\n </g>\n\n <clipPath id={clipPathId}>\n <path ref={clipPathRef} />\n </clipPath>\n\n {debug && <path ref={rectDebugRef} className={styles.rectDebug} />}\n </svg>\n </div>\n );\n});\n"],"names":["mergeClasses","useId","React","useSyncExternalStore","getRectCorners","getMouseAnchor","pointsToSvgPath","useStyles","computeOutsideClipPath","getSafeZonePoints","SafeZoneArea","memo","props","debug","onMouseEnter","onMouseMove","onMouseLeave","stateStore","clipPathId","styles","active","subscribe","isActive","svgRef","useRef","safeZoneRef","clipPathRef","rectDebugRef","useImperativeHandle","imperativeRef","updateSVG","containerRect","targetRect","mouseCoordinates","topOffset","Math","min","top","leftOffset","left","bottomOffset","max","bottom","rightOffset","right","containerCorners","targetCorners","relativeMouseCoordinates","mouseAnchor","topLeft","bottomRight","svgWidth","svgHeight","clipPath","x","y","width","height","current","style","transform","safeZonePoints","setAttribute","length","div","className","wrapper","wrapperActive","data-safe-zone","svg","aria-hidden","xmlns","ref","g","safeZone","safeZoneDebug","path","id","rectDebug"],"mappings":"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"}
@@ -19,10 +19,10 @@ export const useStyles = /*#__PURE__*/__styles({
19
19
  Bhzewxz: "f15twtuk",
20
20
  oyh7mz: ["f1vgc2s3", "f1e31b4d"]
21
21
  },
22
- triangle: {
22
+ safeZone: {
23
23
  Bkecrkj: "f1cguypg"
24
24
  },
25
- triangleDebug: {
25
+ safeZoneDebug: {
26
26
  Bceei9c: "f7116n6",
27
27
  Bkfmm31: "f1xab38x"
28
28
  },
@@ -1 +1 @@
1
- {"version":3,"names":["__styles","tokens","useStyles","wrapper","mc9l5x","Bqenvij","a9b677","Bkecrkj","wrapperActive","svg","Bkfmm31","qhf8xq","Bhzewxz","oyh7mz","triangle","triangleDebug","Bceei9c","rectDebug","d"],"sources":["SafeZoneArea.styles.js"],"sourcesContent":["'use client';\nimport { makeStyles } from \"@griffel/react\";\nimport { tokens } from \"@fluentui/react-theme\";\nexport const useStyles = makeStyles({\n wrapper: {\n display: 'none',\n height: 0,\n width: 0,\n pointerEvents: 'none'\n },\n wrapperActive: {\n display: 'block'\n },\n svg: {\n fill: 'transparent',\n pointerEvents: 'none',\n position: 'fixed',\n top: 0,\n left: 0\n },\n triangle: {\n pointerEvents: 'auto'\n },\n triangleDebug: {\n cursor: 'crosshair',\n fill: `color-mix(in srgb, ${tokens.colorPaletteGreenBackground3} 20%, transparent)`\n },\n rectDebug: {\n fill: `color-mix(in srgb, ${tokens.colorPaletteRedBackground3} 20%, transparent)`\n }\n});\n"],"mappings":"AAAA,YAAY;;AACZ,SAAAA,QAAA,QAA2B,gBAAgB;AAC3C,SAASC,MAAM,QAAQ,uBAAuB;AAC9C,OAAO,MAAMC,SAAS,gBAAGF,QAAA;EAAAG,OAAA;IAAAC,MAAA;IAAAC,OAAA;IAAAC,MAAA;IAAAC,OAAA;EAAA;EAAAC,aAAA;IAAAJ,MAAA;EAAA;EAAAK,GAAA;IAAAC,OAAA;IAAAH,OAAA;IAAAI,MAAA;IAAAC,OAAA;IAAAC,MAAA;EAAA;EAAAC,QAAA;IAAAP,OAAA;EAAA;EAAAQ,aAAA;IAAAC,OAAA;IAAAN,OAAA;EAAA;EAAAO,SAAA;IAAAP,OAAA;EAAA;AAAA;EAAAQ,CAAA;AAAA,CA2BxB,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["__styles","tokens","useStyles","wrapper","mc9l5x","Bqenvij","a9b677","Bkecrkj","wrapperActive","svg","Bkfmm31","qhf8xq","Bhzewxz","oyh7mz","safeZone","safeZoneDebug","Bceei9c","rectDebug","d"],"sources":["SafeZoneArea.styles.js"],"sourcesContent":["'use client';\nimport { makeStyles } from \"@griffel/react\";\nimport { tokens } from \"@fluentui/react-theme\";\nexport const useStyles = makeStyles({\n wrapper: {\n display: 'none',\n height: 0,\n width: 0,\n pointerEvents: 'none'\n },\n wrapperActive: {\n display: 'block'\n },\n svg: {\n fill: 'transparent',\n pointerEvents: 'none',\n position: 'fixed',\n top: 0,\n left: 0\n },\n safeZone: {\n pointerEvents: 'auto'\n },\n safeZoneDebug: {\n cursor: 'crosshair',\n fill: `color-mix(in srgb, ${tokens.colorPaletteGreenBackground3} 20%, transparent)`\n },\n rectDebug: {\n fill: `color-mix(in srgb, ${tokens.colorPaletteRedBackground3} 20%, transparent)`\n }\n});\n"],"mappings":"AAAA,YAAY;;AACZ,SAAAA,QAAA,QAA2B,gBAAgB;AAC3C,SAASC,MAAM,QAAQ,uBAAuB;AAC9C,OAAO,MAAMC,SAAS,gBAAGF,QAAA;EAAAG,OAAA;IAAAC,MAAA;IAAAC,OAAA;IAAAC,MAAA;IAAAC,OAAA;EAAA;EAAAC,aAAA;IAAAJ,MAAA;EAAA;EAAAK,GAAA;IAAAC,OAAA;IAAAH,OAAA;IAAAI,MAAA;IAAAC,OAAA;IAAAC,MAAA;EAAA;EAAAC,QAAA;IAAAP,OAAA;EAAA;EAAAQ,aAAA;IAAAC,OAAA;IAAAN,OAAA;EAAA;EAAAO,SAAA;IAAAP,OAAA;EAAA;AAAA;EAAAQ,CAAA;AAAA,CA2BxB,CAAC","ignoreList":[]}
@@ -18,10 +18,10 @@ export const useStyles = makeStyles({
18
18
  top: 0,
19
19
  left: 0
20
20
  },
21
- triangle: {
21
+ safeZone: {
22
22
  pointerEvents: 'auto'
23
23
  },
24
- triangleDebug: {
24
+ safeZoneDebug: {
25
25
  cursor: 'crosshair',
26
26
  fill: `color-mix(in srgb, ${tokens.colorPaletteGreenBackground3} 20%, transparent)`
27
27
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/hooks/useSafeZoneArea/SafeZoneArea.styles.ts"],"sourcesContent":["'use client';\n\nimport { makeStyles } from '@griffel/react';\nimport { tokens } from '@fluentui/react-theme';\n\nexport const useStyles = makeStyles({\n wrapper: {\n display: 'none',\n height: 0,\n width: 0,\n pointerEvents: 'none',\n },\n wrapperActive: {\n display: 'block',\n },\n svg: {\n fill: 'transparent',\n pointerEvents: 'none',\n position: 'fixed',\n top: 0,\n left: 0,\n },\n triangle: {\n pointerEvents: 'auto',\n },\n triangleDebug: {\n cursor: 'crosshair',\n fill: `color-mix(in srgb, ${tokens.colorPaletteGreenBackground3} 20%, transparent)`,\n },\n rectDebug: {\n fill: `color-mix(in srgb, ${tokens.colorPaletteRedBackground3} 20%, transparent)`,\n },\n});\n"],"names":["makeStyles","tokens","useStyles","wrapper","display","height","width","pointerEvents","wrapperActive","svg","fill","position","top","left","triangle","triangleDebug","cursor","colorPaletteGreenBackground3","rectDebug","colorPaletteRedBackground3"],"mappings":"AAAA;AAEA,SAASA,UAAU,QAAQ,iBAAiB;AAC5C,SAASC,MAAM,QAAQ,wBAAwB;AAE/C,OAAO,MAAMC,YAAYF,WAAW;IAClCG,SAAS;QACPC,SAAS;QACTC,QAAQ;QACRC,OAAO;QACPC,eAAe;IACjB;IACAC,eAAe;QACbJ,SAAS;IACX;IACAK,KAAK;QACHC,MAAM;QACNH,eAAe;QACfI,UAAU;QACVC,KAAK;QACLC,MAAM;IACR;IACAC,UAAU;QACRP,eAAe;IACjB;IACAQ,eAAe;QACbC,QAAQ;QACRN,MAAM,CAAC,mBAAmB,EAAET,OAAOgB,4BAA4B,CAAC,kBAAkB,CAAC;IACrF;IACAC,WAAW;QACTR,MAAM,CAAC,mBAAmB,EAAET,OAAOkB,0BAA0B,CAAC,kBAAkB,CAAC;IACnF;AACF,GAAG"}
1
+ {"version":3,"sources":["../src/hooks/useSafeZoneArea/SafeZoneArea.styles.ts"],"sourcesContent":["'use client';\n\nimport { makeStyles } from '@griffel/react';\nimport { tokens } from '@fluentui/react-theme';\n\nexport const useStyles = makeStyles({\n wrapper: {\n display: 'none',\n height: 0,\n width: 0,\n pointerEvents: 'none',\n },\n wrapperActive: {\n display: 'block',\n },\n svg: {\n fill: 'transparent',\n pointerEvents: 'none',\n position: 'fixed',\n top: 0,\n left: 0,\n },\n safeZone: {\n pointerEvents: 'auto',\n },\n safeZoneDebug: {\n cursor: 'crosshair',\n fill: `color-mix(in srgb, ${tokens.colorPaletteGreenBackground3} 20%, transparent)`,\n },\n rectDebug: {\n fill: `color-mix(in srgb, ${tokens.colorPaletteRedBackground3} 20%, transparent)`,\n },\n});\n"],"names":["makeStyles","tokens","useStyles","wrapper","display","height","width","pointerEvents","wrapperActive","svg","fill","position","top","left","safeZone","safeZoneDebug","cursor","colorPaletteGreenBackground3","rectDebug","colorPaletteRedBackground3"],"mappings":"AAAA;AAEA,SAASA,UAAU,QAAQ,iBAAiB;AAC5C,SAASC,MAAM,QAAQ,wBAAwB;AAE/C,OAAO,MAAMC,YAAYF,WAAW;IAClCG,SAAS;QACPC,SAAS;QACTC,QAAQ;QACRC,OAAO;QACPC,eAAe;IACjB;IACAC,eAAe;QACbJ,SAAS;IACX;IACAK,KAAK;QACHC,MAAM;QACNH,eAAe;QACfI,UAAU;QACVC,KAAK;QACLC,MAAM;IACR;IACAC,UAAU;QACRP,eAAe;IACjB;IACAQ,eAAe;QACbC,QAAQ;QACRN,MAAM,CAAC,mBAAmB,EAAET,OAAOgB,4BAA4B,CAAC,kBAAkB,CAAC;IACrF;IACAC,WAAW;QACTR,MAAM,CAAC,mBAAmB,EAAET,OAAOkB,0BAA0B,CAAC,kBAAkB,CAAC;IACnF;AACF,GAAG"}
@@ -13,15 +13,12 @@ function drawRectangle(rect) {
13
13
  return pathData;
14
14
  }
15
15
  /**
16
- * Computes a clip path that covers the area outside multiple rectangles.
16
+ * Computes a clip path that covers the area outside a rectangle.
17
17
  *
18
18
  * @internal
19
- */ export function computeOutsideClipPath(svgWidth, svgHeight, targetRect, containerRect) {
19
+ */ export function computeOutsideClipPath(svgWidth, svgHeight, targetRect) {
20
20
  let pathData = `M 0,0 H ${svgWidth} V ${svgHeight} H 0 Z `;
21
- // For each rectangle, add a subpath that "cuts out" the rectangle
22
- // The trick is to draw each rectangle in the counterclockwise direction
23
- // which creates a "hole" in the main path
21
+ // Draw the rectangle counterclockwise to create a hole in the main path.
24
22
  pathData += drawRectangle(targetRect);
25
- pathData += drawRectangle(containerRect);
26
23
  return pathData;
27
24
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/hooks/useSafeZoneArea/computeOutsideClipPath.ts"],"sourcesContent":["function drawRectangle(rect: { x: number; y: number; width: number; height: number }): string {\n if (rect.width <= 0 || rect.height <= 0) {\n return '';\n }\n\n let pathData = '';\n\n // Creates a subpath moving in counterclockwise direction to create a hole\n\n pathData += `M ${rect.x},${rect.y} `;\n pathData += `V ${rect.y + rect.height} `; // Down to bottom-left\n pathData += `H ${rect.x + rect.width} `; // Right to bottom-right\n pathData += `V ${rect.y} `; // Up to top-right\n pathData += `H ${rect.x} `; // Left to top-left (closing)\n pathData += `Z `; // Close path\n\n return pathData;\n}\n\n/**\n * Computes a clip path that covers the area outside multiple rectangles.\n *\n * @internal\n */\nexport function computeOutsideClipPath(\n svgWidth: number,\n svgHeight: number,\n targetRect: { x: number; y: number; width: number; height: number },\n containerRect: { x: number; y: number; width: number; height: number },\n): string {\n let pathData = `M 0,0 H ${svgWidth} V ${svgHeight} H 0 Z `;\n\n // For each rectangle, add a subpath that \"cuts out\" the rectangle\n // The trick is to draw each rectangle in the counterclockwise direction\n // which creates a \"hole\" in the main path\n\n pathData += drawRectangle(targetRect);\n pathData += drawRectangle(containerRect);\n\n return pathData;\n}\n"],"names":["drawRectangle","rect","width","height","pathData","x","y","computeOutsideClipPath","svgWidth","svgHeight","targetRect","containerRect"],"mappings":"AAAA,SAASA,cAAcC,IAA6D;IAClF,IAAIA,KAAKC,KAAK,IAAI,KAAKD,KAAKE,MAAM,IAAI,GAAG;QACvC,OAAO;IACT;IAEA,IAAIC,WAAW;IAEf,0EAA0E;IAE1EA,YAAY,CAAC,EAAE,EAAEH,KAAKI,CAAC,CAAC,CAAC,EAAEJ,KAAKK,CAAC,CAAC,CAAC,CAAC;IACpCF,YAAY,CAAC,EAAE,EAAEH,KAAKK,CAAC,GAAGL,KAAKE,MAAM,CAAC,CAAC,CAAC,EAAE,sBAAsB;IAChEC,YAAY,CAAC,EAAE,EAAEH,KAAKI,CAAC,GAAGJ,KAAKC,KAAK,CAAC,CAAC,CAAC,EAAE,wBAAwB;IACjEE,YAAY,CAAC,EAAE,EAAEH,KAAKK,CAAC,CAAC,CAAC,CAAC,EAAE,kBAAkB;IAC9CF,YAAY,CAAC,EAAE,EAAEH,KAAKI,CAAC,CAAC,CAAC,CAAC,EAAE,6BAA6B;IACzDD,YAAY,CAAC,EAAE,CAAC,EAAE,aAAa;IAE/B,OAAOA;AACT;AAEA;;;;CAIC,GACD,OAAO,SAASG,uBACdC,QAAgB,EAChBC,SAAiB,EACjBC,UAAmE,EACnEC,aAAsE;IAEtE,IAAIP,WAAW,CAAC,QAAQ,EAAEI,SAAS,GAAG,EAAEC,UAAU,OAAO,CAAC;IAE1D,kEAAkE;IAClE,wEAAwE;IACxE,0CAA0C;IAE1CL,YAAYJ,cAAcU;IAC1BN,YAAYJ,cAAcW;IAE1B,OAAOP;AACT"}
1
+ {"version":3,"sources":["../src/hooks/useSafeZoneArea/computeOutsideClipPath.ts"],"sourcesContent":["function drawRectangle(rect: { x: number; y: number; width: number; height: number }): string {\n if (rect.width <= 0 || rect.height <= 0) {\n return '';\n }\n\n let pathData = '';\n\n // Creates a subpath moving in counterclockwise direction to create a hole\n\n pathData += `M ${rect.x},${rect.y} `;\n pathData += `V ${rect.y + rect.height} `; // Down to bottom-left\n pathData += `H ${rect.x + rect.width} `; // Right to bottom-right\n pathData += `V ${rect.y} `; // Up to top-right\n pathData += `H ${rect.x} `; // Left to top-left (closing)\n pathData += `Z `; // Close path\n\n return pathData;\n}\n\n/**\n * Computes a clip path that covers the area outside a rectangle.\n *\n * @internal\n */\nexport function computeOutsideClipPath(\n svgWidth: number,\n svgHeight: number,\n targetRect: { x: number; y: number; width: number; height: number },\n): string {\n let pathData = `M 0,0 H ${svgWidth} V ${svgHeight} H 0 Z `;\n\n // Draw the rectangle counterclockwise to create a hole in the main path.\n\n pathData += drawRectangle(targetRect);\n\n return pathData;\n}\n"],"names":["drawRectangle","rect","width","height","pathData","x","y","computeOutsideClipPath","svgWidth","svgHeight","targetRect"],"mappings":"AAAA,SAASA,cAAcC,IAA6D;IAClF,IAAIA,KAAKC,KAAK,IAAI,KAAKD,KAAKE,MAAM,IAAI,GAAG;QACvC,OAAO;IACT;IAEA,IAAIC,WAAW;IAEf,0EAA0E;IAE1EA,YAAY,CAAC,EAAE,EAAEH,KAAKI,CAAC,CAAC,CAAC,EAAEJ,KAAKK,CAAC,CAAC,CAAC,CAAC;IACpCF,YAAY,CAAC,EAAE,EAAEH,KAAKK,CAAC,GAAGL,KAAKE,MAAM,CAAC,CAAC,CAAC,EAAE,sBAAsB;IAChEC,YAAY,CAAC,EAAE,EAAEH,KAAKI,CAAC,GAAGJ,KAAKC,KAAK,CAAC,CAAC,CAAC,EAAE,wBAAwB;IACjEE,YAAY,CAAC,EAAE,EAAEH,KAAKK,CAAC,CAAC,CAAC,CAAC,EAAE,kBAAkB;IAC9CF,YAAY,CAAC,EAAE,EAAEH,KAAKI,CAAC,CAAC,CAAC,CAAC,EAAE,6BAA6B;IACzDD,YAAY,CAAC,EAAE,CAAC,EAAE,aAAa;IAE/B,OAAOA;AACT;AAEA;;;;CAIC,GACD,OAAO,SAASG,uBACdC,QAAgB,EAChBC,SAAiB,EACjBC,UAAmE;IAEnE,IAAIN,WAAW,CAAC,QAAQ,EAAEI,SAAS,GAAG,EAAEC,UAAU,OAAO,CAAC;IAE1D,yEAAyE;IAEzEL,YAAYJ,cAAcU;IAE1B,OAAON;AACT"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Returns the mouse anchor and the container corners facing it.
3
+ *
4
+ * @internal
5
+ */ export function getSafeZonePoints(mouseAnchor, containerCorners) {
6
+ const { topLeft, topRight, bottomRight, bottomLeft } = containerCorners;
7
+ const isAbove = mouseAnchor[1] < topLeft[1];
8
+ const isBelow = mouseAnchor[1] > bottomLeft[1];
9
+ const isLeft = mouseAnchor[0] < topLeft[0];
10
+ const isRight = mouseAnchor[0] > topRight[0];
11
+ if (isAbove) {
12
+ if (isLeft) {
13
+ return [
14
+ mouseAnchor,
15
+ bottomLeft,
16
+ topLeft,
17
+ topRight
18
+ ];
19
+ }
20
+ if (isRight) {
21
+ return [
22
+ mouseAnchor,
23
+ topLeft,
24
+ topRight,
25
+ bottomRight
26
+ ];
27
+ }
28
+ return [
29
+ mouseAnchor,
30
+ topLeft,
31
+ topRight
32
+ ];
33
+ }
34
+ if (isBelow) {
35
+ if (isLeft) {
36
+ return [
37
+ mouseAnchor,
38
+ topLeft,
39
+ bottomLeft,
40
+ bottomRight
41
+ ];
42
+ }
43
+ if (isRight) {
44
+ return [
45
+ mouseAnchor,
46
+ topRight,
47
+ bottomRight,
48
+ bottomLeft
49
+ ];
50
+ }
51
+ return [
52
+ mouseAnchor,
53
+ bottomRight,
54
+ bottomLeft
55
+ ];
56
+ }
57
+ if (isLeft) {
58
+ return [
59
+ mouseAnchor,
60
+ bottomLeft,
61
+ topLeft
62
+ ];
63
+ }
64
+ if (isRight) {
65
+ return [
66
+ mouseAnchor,
67
+ topRight,
68
+ bottomRight
69
+ ];
70
+ }
71
+ return [];
72
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/useSafeZoneArea/getSafeZonePoints.ts"],"sourcesContent":["import type { Point } from './types';\n\ntype RectCorners = Record<'topLeft' | 'topRight' | 'bottomRight' | 'bottomLeft', Point>;\n\n/**\n * Returns the mouse anchor and the container corners facing it.\n *\n * @internal\n */\nexport function getSafeZonePoints(mouseAnchor: Point, containerCorners: RectCorners): Point[] {\n const { topLeft, topRight, bottomRight, bottomLeft } = containerCorners;\n const isAbove = mouseAnchor[1] < topLeft[1];\n const isBelow = mouseAnchor[1] > bottomLeft[1];\n const isLeft = mouseAnchor[0] < topLeft[0];\n const isRight = mouseAnchor[0] > topRight[0];\n\n if (isAbove) {\n if (isLeft) {\n return [mouseAnchor, bottomLeft, topLeft, topRight];\n }\n\n if (isRight) {\n return [mouseAnchor, topLeft, topRight, bottomRight];\n }\n\n return [mouseAnchor, topLeft, topRight];\n }\n\n if (isBelow) {\n if (isLeft) {\n return [mouseAnchor, topLeft, bottomLeft, bottomRight];\n }\n\n if (isRight) {\n return [mouseAnchor, topRight, bottomRight, bottomLeft];\n }\n\n return [mouseAnchor, bottomRight, bottomLeft];\n }\n\n if (isLeft) {\n return [mouseAnchor, bottomLeft, topLeft];\n }\n\n if (isRight) {\n return [mouseAnchor, topRight, bottomRight];\n }\n\n return [];\n}\n"],"names":["getSafeZonePoints","mouseAnchor","containerCorners","topLeft","topRight","bottomRight","bottomLeft","isAbove","isBelow","isLeft","isRight"],"mappings":"AAIA;;;;CAIC,GACD,OAAO,SAASA,kBAAkBC,WAAkB,EAAEC,gBAA6B;IACjF,MAAM,EAAEC,OAAO,EAAEC,QAAQ,EAAEC,WAAW,EAAEC,UAAU,EAAE,GAAGJ;IACvD,MAAMK,UAAUN,WAAW,CAAC,EAAE,GAAGE,OAAO,CAAC,EAAE;IAC3C,MAAMK,UAAUP,WAAW,CAAC,EAAE,GAAGK,UAAU,CAAC,EAAE;IAC9C,MAAMG,SAASR,WAAW,CAAC,EAAE,GAAGE,OAAO,CAAC,EAAE;IAC1C,MAAMO,UAAUT,WAAW,CAAC,EAAE,GAAGG,QAAQ,CAAC,EAAE;IAE5C,IAAIG,SAAS;QACX,IAAIE,QAAQ;YACV,OAAO;gBAACR;gBAAaK;gBAAYH;gBAASC;aAAS;QACrD;QAEA,IAAIM,SAAS;YACX,OAAO;gBAACT;gBAAaE;gBAASC;gBAAUC;aAAY;QACtD;QAEA,OAAO;YAACJ;YAAaE;YAASC;SAAS;IACzC;IAEA,IAAII,SAAS;QACX,IAAIC,QAAQ;YACV,OAAO;gBAACR;gBAAaE;gBAASG;gBAAYD;aAAY;QACxD;QAEA,IAAIK,SAAS;YACX,OAAO;gBAACT;gBAAaG;gBAAUC;gBAAaC;aAAW;QACzD;QAEA,OAAO;YAACL;YAAaI;YAAaC;SAAW;IAC/C;IAEA,IAAIG,QAAQ;QACV,OAAO;YAACR;YAAaK;YAAYH;SAAQ;IAC3C;IAEA,IAAIO,SAAS;QACX,OAAO;YAACT;YAAaG;YAAUC;SAAY;IAC7C;IAEA,OAAO,EAAE;AACX"}
@@ -14,6 +14,10 @@ const _index = require("./utils/index.cjs");
14
14
  const _listScrollParents = require("./utils/listScrollParents.cjs");
15
15
  const _constants = require("./constants.cjs");
16
16
  const _createResizeObserver = require("./utils/createResizeObserver.cjs");
17
+ function isLayoutViewportUnavailable(container) {
18
+ const { clientWidth, clientHeight } = container.ownerDocument.documentElement;
19
+ return clientWidth === 0 && clientHeight === 0;
20
+ }
17
21
  function createPositionManager(options) {
18
22
  let isDestroyed = false;
19
23
  const { container, target, arrow, strategy, middleware, placement, useTransform = true, disableUpdateOnResize = false } = options;
@@ -75,19 +79,27 @@ function createPositionManager(options) {
75
79
  middleware,
76
80
  strategy
77
81
  }).then(({ x, y, middlewareData, placement: computedPlacement })=>{
78
- var _middlewareData_hide, _middlewareData_hide1;
82
+ var _positioningMiddlewareData_hide, _positioningMiddlewareData_hide1;
79
83
  // Promise can still resolve after destruction
80
84
  // early return to avoid applying outdated position
81
85
  if (isDestroyed) {
82
86
  return;
83
87
  }
88
+ const positioningMiddlewareData = isLayoutViewportUnavailable(container) ? {
89
+ ...middlewareData,
90
+ hide: {
91
+ ...middlewareData.hide,
92
+ escaped: false,
93
+ referenceHidden: false
94
+ }
95
+ } : middlewareData;
84
96
  (0, _index.writeArrowUpdates)({
85
97
  arrow,
86
- middlewareData
98
+ middlewareData: positioningMiddlewareData
87
99
  });
88
100
  (0, _index.writeContainerUpdates)({
89
101
  container,
90
- middlewareData,
102
+ middlewareData: positioningMiddlewareData,
91
103
  placement: computedPlacement,
92
104
  coordinates: {
93
105
  x,
@@ -97,15 +109,15 @@ function createPositionManager(options) {
97
109
  strategy,
98
110
  useTransform
99
111
  });
100
- var _middlewareData_hide_escaped, _middlewareData_hide_referenceHidden;
112
+ var _positioningMiddlewareData_hide_escaped, _positioningMiddlewareData_hide_referenceHidden;
101
113
  container.dispatchEvent(new CustomEvent(_constants.POSITIONING_END_EVENT, {
102
114
  detail: {
103
115
  // Cast from Floating UI's Placement to the Fluent-owned PositioningPlacement.
104
116
  // These are equivalent string unions; the cast avoids leaking @floating-ui/dom
105
117
  // types into the public API surface.
106
118
  placement: computedPlacement,
107
- escaped: (_middlewareData_hide_escaped = (_middlewareData_hide = middlewareData.hide) === null || _middlewareData_hide === void 0 ? void 0 : _middlewareData_hide.escaped) !== null && _middlewareData_hide_escaped !== void 0 ? _middlewareData_hide_escaped : false,
108
- referenceHidden: (_middlewareData_hide_referenceHidden = (_middlewareData_hide1 = middlewareData.hide) === null || _middlewareData_hide1 === void 0 ? void 0 : _middlewareData_hide1.referenceHidden) !== null && _middlewareData_hide_referenceHidden !== void 0 ? _middlewareData_hide_referenceHidden : false
119
+ escaped: (_positioningMiddlewareData_hide_escaped = (_positioningMiddlewareData_hide = positioningMiddlewareData.hide) === null || _positioningMiddlewareData_hide === void 0 ? void 0 : _positioningMiddlewareData_hide.escaped) !== null && _positioningMiddlewareData_hide_escaped !== void 0 ? _positioningMiddlewareData_hide_escaped : false,
120
+ referenceHidden: (_positioningMiddlewareData_hide_referenceHidden = (_positioningMiddlewareData_hide1 = positioningMiddlewareData.hide) === null || _positioningMiddlewareData_hide1 === void 0 ? void 0 : _positioningMiddlewareData_hide1.referenceHidden) !== null && _positioningMiddlewareData_hide_referenceHidden !== void 0 ? _positioningMiddlewareData_hide_referenceHidden : false
109
121
  }
110
122
  }));
111
123
  }).catch((err)=>{
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/createPositionManager.ts"],"sourcesContent":["import { computePosition } from '@floating-ui/dom';\nimport type { Middleware, Placement, Strategy } from '@floating-ui/dom';\nimport { isHTMLElement } from '@fluentui/react-utilities';\nimport type { OnPositioningEndEventDetail, PositionManager, PositioningPlacement, TargetElement } from './types';\nimport { debounce, writeArrowUpdates, writeContainerUpdates } from './utils';\nimport { listScrollParents } from './utils/listScrollParents';\nimport { POSITIONING_END_EVENT } from './constants';\nimport { createResizeObserver } from './utils/createResizeObserver';\n\ninterface PositionManagerOptions {\n /**\n * The positioned element\n */\n container: HTMLElement;\n /**\n * Element that the container will be anchored to\n */\n target: TargetElement;\n /**\n * Arrow that points from the container to the target\n */\n arrow: HTMLElement | null;\n /**\n * The value of the css `position` property\n * @default absolute\n */\n strategy: Strategy;\n /**\n * [Floating UI middleware](https://floating-ui.com/docs/middleware)\n */\n middleware: Middleware[];\n /**\n * [Floating UI placement](https://floating-ui.com/docs/computePosition#placement)\n */\n placement?: Placement;\n /**\n * Modifies whether popover is positioned using transform.\n * @default true\n */\n useTransform?: boolean;\n /**\n * Disables the resize observer that updates position on target or dimension change\n */\n disableUpdateOnResize?: boolean;\n}\n\n/**\n * @internal\n * @returns manager that handles positioning out of the react lifecycle\n */\nexport function createPositionManager(options: PositionManagerOptions): PositionManager {\n let isDestroyed = false;\n const {\n container,\n target,\n arrow,\n strategy,\n middleware,\n placement,\n useTransform = true,\n disableUpdateOnResize = false,\n } = options;\n const targetWindow = container.ownerDocument.defaultView;\n if (!target || !container || !targetWindow) {\n return {\n updatePosition: () => undefined,\n dispose: () => undefined,\n };\n }\n\n // When the dimensions of the target or the container change - trigger a position update\n const resizeObserver = disableUpdateOnResize\n ? null\n : createResizeObserver(targetWindow, entries => {\n // If content rect dimensions to go 0 -> very likely that `display: none` is being used to hide the element\n // In this case don't update and let users update imperatively\n const shouldUpdateOnResize = entries.every(entry => {\n return entry.contentRect.width > 0 && entry.contentRect.height > 0;\n });\n\n if (shouldUpdateOnResize) {\n updatePosition();\n }\n });\n\n let isFirstUpdate = true;\n const scrollParents: Set<HTMLElement> = new Set<HTMLElement>();\n\n // When the container is first resolved, set position `fixed` to avoid scroll jumps.\n // Without this scroll jumps can occur when the element is rendered initially and receives focus\n Object.assign(container.style, { position: 'fixed', left: 0, top: 0, margin: 0 });\n\n const forceUpdate = () => {\n // debounced update can still occur afterwards\n // early return to avoid memory leaks\n if (isDestroyed) {\n return;\n }\n\n if (isFirstUpdate) {\n listScrollParents(container).forEach(scrollParent => scrollParents.add(scrollParent));\n if (isHTMLElement(target)) {\n listScrollParents(target).forEach(scrollParent => scrollParents.add(scrollParent));\n }\n\n scrollParents.forEach(scrollParent => {\n scrollParent.addEventListener('scroll', updatePosition, { passive: true });\n });\n\n resizeObserver?.observe(container);\n if (isHTMLElement(target)) {\n resizeObserver?.observe(target);\n }\n\n isFirstUpdate = false;\n }\n\n Object.assign(container.style, { position: strategy });\n computePosition(target, container, { placement, middleware, strategy })\n .then(({ x, y, middlewareData, placement: computedPlacement }) => {\n // Promise can still resolve after destruction\n // early return to avoid applying outdated position\n if (isDestroyed) {\n return;\n }\n\n writeArrowUpdates({ arrow, middlewareData });\n writeContainerUpdates({\n container,\n middlewareData,\n placement: computedPlacement,\n coordinates: { x, y },\n lowPPI: (targetWindow?.devicePixelRatio || 1) <= 1,\n strategy,\n useTransform,\n });\n\n container.dispatchEvent(\n new CustomEvent<OnPositioningEndEventDetail>(POSITIONING_END_EVENT, {\n detail: {\n // Cast from Floating UI's Placement to the Fluent-owned PositioningPlacement.\n // These are equivalent string unions; the cast avoids leaking @floating-ui/dom\n // types into the public API surface.\n placement: computedPlacement satisfies PositioningPlacement,\n escaped: middlewareData.hide?.escaped ?? false,\n referenceHidden: middlewareData.hide?.referenceHidden ?? false,\n },\n }),\n );\n })\n .catch(err => {\n // https://github.com/floating-ui/floating-ui/issues/1845\n // FIXME for node > 14\n // node 15 introduces promise rejection which means that any components\n // tests need to be `it('', async () => {})` otherwise there can be race conditions with\n // JSDOM being torn down before this promise is resolved so globals like `window` and `document` don't exist\n // Unless all tests that ever use `usePositioning` are turned into async tests, any logging during testing\n // will actually be counter productive\n if (process.env.NODE_ENV === 'development') {\n // eslint-disable-next-line no-console\n console.error('[usePositioning]: Failed to calculate position', err);\n }\n });\n };\n\n const updatePosition = debounce(() => forceUpdate());\n\n const dispose = () => {\n isDestroyed = true;\n\n if (targetWindow) {\n targetWindow.removeEventListener('scroll', updatePosition);\n targetWindow.removeEventListener('resize', updatePosition);\n }\n\n scrollParents.forEach(scrollParent => {\n scrollParent.removeEventListener('scroll', updatePosition);\n });\n scrollParents.clear();\n\n resizeObserver?.disconnect();\n };\n\n if (targetWindow) {\n targetWindow.addEventListener('scroll', updatePosition, { passive: true });\n targetWindow.addEventListener('resize', updatePosition);\n }\n\n // Update the position on initialization\n updatePosition();\n\n return {\n updatePosition,\n dispose,\n };\n}\n"],"names":["computePosition","isHTMLElement","debounce","writeArrowUpdates","writeContainerUpdates","listScrollParents","POSITIONING_END_EVENT","createResizeObserver","createPositionManager","options","isDestroyed","container","target","arrow","strategy","middleware","placement","useTransform","disableUpdateOnResize","targetWindow","ownerDocument","defaultView","updatePosition","undefined","dispose","resizeObserver","entries","shouldUpdateOnResize","every","entry","contentRect","width","height","isFirstUpdate","scrollParents","Set","Object","assign","style","position","left","top","margin","forceUpdate","forEach","scrollParent","add","addEventListener","passive","observe","then","x","y","middlewareData","computedPlacement","coordinates","lowPPI","devicePixelRatio","dispatchEvent","CustomEvent","detail","escaped","hide","referenceHidden","catch","err","process","env","NODE_ENV","console","error","removeEventListener","clear","disconnect"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/createPositionManager.ts"],"sourcesContent":["import { computePosition } from '@floating-ui/dom';\nimport type { Middleware, Placement, Strategy } from '@floating-ui/dom';\nimport { isHTMLElement } from '@fluentui/react-utilities';\nimport type { OnPositioningEndEventDetail, PositionManager, PositioningPlacement, TargetElement } from './types';\nimport { debounce, writeArrowUpdates, writeContainerUpdates } from './utils';\nimport { listScrollParents } from './utils/listScrollParents';\nimport { POSITIONING_END_EVENT } from './constants';\nimport { createResizeObserver } from './utils/createResizeObserver';\n\ninterface PositionManagerOptions {\n /**\n * The positioned element\n */\n container: HTMLElement;\n /**\n * Element that the container will be anchored to\n */\n target: TargetElement;\n /**\n * Arrow that points from the container to the target\n */\n arrow: HTMLElement | null;\n /**\n * The value of the css `position` property\n * @default absolute\n */\n strategy: Strategy;\n /**\n * [Floating UI middleware](https://floating-ui.com/docs/middleware)\n */\n middleware: Middleware[];\n /**\n * [Floating UI placement](https://floating-ui.com/docs/computePosition#placement)\n */\n placement?: Placement;\n /**\n * Modifies whether popover is positioned using transform.\n * @default true\n */\n useTransform?: boolean;\n /**\n * Disables the resize observer that updates position on target or dimension change\n */\n disableUpdateOnResize?: boolean;\n}\n\nfunction isLayoutViewportUnavailable(container: HTMLElement): boolean {\n const { clientWidth, clientHeight } = container.ownerDocument.documentElement;\n\n return clientWidth === 0 && clientHeight === 0;\n}\n\n/**\n * @internal\n * @returns manager that handles positioning out of the react lifecycle\n */\nexport function createPositionManager(options: PositionManagerOptions): PositionManager {\n let isDestroyed = false;\n const {\n container,\n target,\n arrow,\n strategy,\n middleware,\n placement,\n useTransform = true,\n disableUpdateOnResize = false,\n } = options;\n const targetWindow = container.ownerDocument.defaultView;\n if (!target || !container || !targetWindow) {\n return {\n updatePosition: () => undefined,\n dispose: () => undefined,\n };\n }\n\n // When the dimensions of the target or the container change - trigger a position update\n const resizeObserver = disableUpdateOnResize\n ? null\n : createResizeObserver(targetWindow, entries => {\n // If content rect dimensions to go 0 -> very likely that `display: none` is being used to hide the element\n // In this case don't update and let users update imperatively\n const shouldUpdateOnResize = entries.every(entry => {\n return entry.contentRect.width > 0 && entry.contentRect.height > 0;\n });\n\n if (shouldUpdateOnResize) {\n updatePosition();\n }\n });\n\n let isFirstUpdate = true;\n const scrollParents: Set<HTMLElement> = new Set<HTMLElement>();\n\n // When the container is first resolved, set position `fixed` to avoid scroll jumps.\n // Without this scroll jumps can occur when the element is rendered initially and receives focus\n Object.assign(container.style, { position: 'fixed', left: 0, top: 0, margin: 0 });\n\n const forceUpdate = () => {\n // debounced update can still occur afterwards\n // early return to avoid memory leaks\n if (isDestroyed) {\n return;\n }\n\n if (isFirstUpdate) {\n listScrollParents(container).forEach(scrollParent => scrollParents.add(scrollParent));\n if (isHTMLElement(target)) {\n listScrollParents(target).forEach(scrollParent => scrollParents.add(scrollParent));\n }\n\n scrollParents.forEach(scrollParent => {\n scrollParent.addEventListener('scroll', updatePosition, { passive: true });\n });\n\n resizeObserver?.observe(container);\n if (isHTMLElement(target)) {\n resizeObserver?.observe(target);\n }\n\n isFirstUpdate = false;\n }\n\n Object.assign(container.style, { position: strategy });\n computePosition(target, container, { placement, middleware, strategy })\n .then(({ x, y, middlewareData, placement: computedPlacement }) => {\n // Promise can still resolve after destruction\n // early return to avoid applying outdated position\n if (isDestroyed) {\n return;\n }\n\n const positioningMiddlewareData = isLayoutViewportUnavailable(container)\n ? {\n ...middlewareData,\n hide: { ...middlewareData.hide, escaped: false, referenceHidden: false },\n }\n : middlewareData;\n\n writeArrowUpdates({ arrow, middlewareData: positioningMiddlewareData });\n writeContainerUpdates({\n container,\n middlewareData: positioningMiddlewareData,\n placement: computedPlacement,\n coordinates: { x, y },\n lowPPI: (targetWindow?.devicePixelRatio || 1) <= 1,\n strategy,\n useTransform,\n });\n\n container.dispatchEvent(\n new CustomEvent<OnPositioningEndEventDetail>(POSITIONING_END_EVENT, {\n detail: {\n // Cast from Floating UI's Placement to the Fluent-owned PositioningPlacement.\n // These are equivalent string unions; the cast avoids leaking @floating-ui/dom\n // types into the public API surface.\n placement: computedPlacement satisfies PositioningPlacement,\n escaped: positioningMiddlewareData.hide?.escaped ?? false,\n referenceHidden: positioningMiddlewareData.hide?.referenceHidden ?? false,\n },\n }),\n );\n })\n .catch(err => {\n // https://github.com/floating-ui/floating-ui/issues/1845\n // FIXME for node > 14\n // node 15 introduces promise rejection which means that any components\n // tests need to be `it('', async () => {})` otherwise there can be race conditions with\n // JSDOM being torn down before this promise is resolved so globals like `window` and `document` don't exist\n // Unless all tests that ever use `usePositioning` are turned into async tests, any logging during testing\n // will actually be counter productive\n if (process.env.NODE_ENV === 'development') {\n // eslint-disable-next-line no-console\n console.error('[usePositioning]: Failed to calculate position', err);\n }\n });\n };\n\n const updatePosition = debounce(() => forceUpdate());\n\n const dispose = () => {\n isDestroyed = true;\n\n if (targetWindow) {\n targetWindow.removeEventListener('scroll', updatePosition);\n targetWindow.removeEventListener('resize', updatePosition);\n }\n\n scrollParents.forEach(scrollParent => {\n scrollParent.removeEventListener('scroll', updatePosition);\n });\n scrollParents.clear();\n\n resizeObserver?.disconnect();\n };\n\n if (targetWindow) {\n targetWindow.addEventListener('scroll', updatePosition, { passive: true });\n targetWindow.addEventListener('resize', updatePosition);\n }\n\n // Update the position on initialization\n updatePosition();\n\n return {\n updatePosition,\n dispose,\n };\n}\n"],"names":["computePosition","isHTMLElement","debounce","writeArrowUpdates","writeContainerUpdates","listScrollParents","POSITIONING_END_EVENT","createResizeObserver","isLayoutViewportUnavailable","container","clientWidth","clientHeight","ownerDocument","documentElement","createPositionManager","options","isDestroyed","target","arrow","strategy","middleware","placement","useTransform","disableUpdateOnResize","targetWindow","defaultView","updatePosition","undefined","dispose","resizeObserver","entries","shouldUpdateOnResize","every","entry","contentRect","width","height","isFirstUpdate","scrollParents","Set","Object","assign","style","position","left","top","margin","forceUpdate","forEach","scrollParent","add","addEventListener","passive","observe","then","x","y","middlewareData","computedPlacement","positioningMiddlewareData","hide","escaped","referenceHidden","coordinates","lowPPI","devicePixelRatio","dispatchEvent","CustomEvent","detail","catch","err","process","env","NODE_ENV","console","error","removeEventListener","clear","disconnect"],"mappings":";;;;+BAwDgBc;;;;;;qBAxDgB,mBAAmB;gCAErB,4BAA4B;uBAES,mBAAU;mCAC3C,+BAA4B;2BACxB,iBAAc;sCACf,kCAA+B;AAuCpE,SAASN,4BAA4BC,SAAsB;IACzD,MAAM,EAAEC,WAAW,EAAEC,YAAY,EAAE,GAAGF,UAAUG,aAAa,CAACC,eAAe;IAE7E,OAAOH,gBAAgB,KAAKC,iBAAiB;AAC/C;AAMO,+BAA+BI,OAA+B;IACnE,IAAIC,cAAc;IAClB,MAAM,EACJP,SAAS,EACTQ,MAAM,EACNC,KAAK,EACLC,QAAQ,EACRC,UAAU,EACVC,SAAS,EACTC,eAAe,IAAI,EACnBC,wBAAwB,KAAK,EAC9B,GAAGR;IACJ,MAAMS,eAAef,UAAUG,aAAa,CAACa,WAAW;IACxD,IAAI,CAACR,UAAU,CAACR,aAAa,CAACe,cAAc;QAC1C,OAAO;YACLE,gBAAgB,IAAMC;YACtBC,SAAS,IAAMD;QACjB;IACF;IAEA,wFAAwF;IACxF,MAAME,iBAAiBN,wBACnB,WACAhB,0CAAAA,EAAqBiB,cAAcM,CAAAA;QACjC,2GAA2G;QAC3G,8DAA8D;QAC9D,MAAMC,uBAAuBD,QAAQE,KAAK,CAACC,CAAAA;YACzC,OAAOA,MAAMC,WAAW,CAACC,KAAK,GAAG,KAAKF,MAAMC,WAAW,CAACE,MAAM,GAAG;QACnE;QAEA,IAAIL,sBAAsB;YACxBL;QACF;IACF;IAEJ,IAAIW,gBAAgB;IACpB,MAAMC,gBAAkC,IAAIC;IAE5C,oFAAoF;IACpF,gGAAgG;IAChGC,OAAOC,MAAM,CAAChC,UAAUiC,KAAK,EAAE;QAAEC,UAAU;QAASC,MAAM;QAAGC,KAAK;QAAGC,QAAQ;IAAE;IAE/E,MAAMC,cAAc;QAClB,8CAA8C;QAC9C,qCAAqC;QACrC,IAAI/B,aAAa;YACf;QACF;QAEA,IAAIqB,eAAe;gBACjBhC,oCAAAA,EAAkBI,WAAWuC,OAAO,CAACC,CAAAA,eAAgBX,cAAcY,GAAG,CAACD;YACvE,QAAIhD,6BAAAA,EAAcgB,SAAS;oBACzBZ,oCAAAA,EAAkBY,QAAQ+B,OAAO,CAACC,CAAAA,eAAgBX,cAAcY,GAAG,CAACD;YACtE;YAEAX,cAAcU,OAAO,CAACC,CAAAA;gBACpBA,aAAaE,gBAAgB,CAAC,UAAUzB,gBAAgB;oBAAE0B,SAAS;gBAAK;YAC1E;YAEAvB,mBAAAA,QAAAA,mBAAAA,KAAAA,IAAAA,KAAAA,IAAAA,eAAgBwB,OAAO,CAAC5C;YACxB,QAAIR,6BAAAA,EAAcgB,SAAS;gBACzBY,mBAAAA,QAAAA,mBAAAA,KAAAA,IAAAA,KAAAA,IAAAA,eAAgBwB,OAAO,CAACpC;YAC1B;YAEAoB,gBAAgB;QAClB;QAEAG,OAAOC,MAAM,CAAChC,UAAUiC,KAAK,EAAE;YAAEC,UAAUxB;QAAS;YACpDnB,oBAAAA,EAAgBiB,QAAQR,WAAW;YAAEY;YAAWD;YAAYD;QAAS,GAClEmC,IAAI,CAAC,CAAC,EAAEC,CAAC,EAAEC,CAAC,EAAEC,cAAc,EAAEpC,WAAWqC,iBAAiB,EAAE;gBAgC5CC,iCACQA;YAhCvB,8CAA8C;YAC9C,mDAAmD;YACnD,IAAI3C,aAAa;gBACf;YACF;YAEA,MAAM2C,4BAA4BnD,4BAA4BC,aAC1D;gBACE,GAAGgD,cAAc;gBACjBG,MAAM;oBAAE,GAAGH,eAAeG,IAAI;oBAAEC,SAAS;oBAAOC,iBAAiB;gBAAM;YACzE,IACAL;gBAEJtD,wBAAAA,EAAkB;gBAAEe;gBAAOuC,gBAAgBE;YAA0B;gBACrEvD,4BAAAA,EAAsB;gBACpBK;gBACAgD,gBAAgBE;gBAChBtC,WAAWqC;gBACXK,aAAa;oBAAER;oBAAGC;gBAAE;gBACpBQ,QAASxC,CAAAA,CAAAA,iBAAAA,QAAAA,iBAAAA,KAAAA,IAAAA,KAAAA,IAAAA,aAAcyC,gBAAAA,AAAgB,KAAI,CAAA,KAAM;gBACjD9C;gBACAG;YACF;gBASeqC,yCACQA;YARvBlD,UAAUyD,aAAa,CACrB,IAAIC,YAAyC7D,gCAAAA,EAAuB;gBAClE8D,QAAQ;oBACN,8EAA8E;oBAC9E,+EAA+E;oBAC/E,qCAAqC;oBACrC/C,WAAWqC;oBACXG,SAASF,2CAAAA,CAAAA,kCAAAA,0BAA0BC,IAAAA,AAAI,MAAA,QAA9BD,oCAAAA,KAAAA,IAAAA,KAAAA,IAAAA,gCAAgCE,OAAAA,AAAO,MAAA,QAAvCF,4CAAAA,KAAAA,IAAAA,0CAA2C;oBACpDG,iBAAiBH,CAAAA,kDAAAA,CAAAA,mCAAAA,0BAA0BC,IAAI,AAAJA,MAAI,QAA9BD,qCAAAA,KAAAA,IAAAA,KAAAA,IAAAA,iCAAgCG,eAAAA,AAAe,MAAA,QAA/CH,oDAAAA,KAAAA,IAAAA,kDAAmD;gBACtE;YACF;QAEJ,GACCU,KAAK,CAACC,CAAAA;YACL,yDAAyD;YACzD,sBAAsB;YACtB,uEAAuE;YACvE,wFAAwF;YACxF,4GAA4G;YAC5G,0GAA0G;YAC1G,sCAAsC;YACtC,IAAIC,QAAQC,GAAG,CAACC,QAAQ,KAAK,eAAe;gBAC1C,sCAAsC;gBACtCC,QAAQC,KAAK,CAAC,kDAAkDL;YAClE;QACF;IACJ;IAEA,MAAM5C,qBAAiBxB,eAAAA,EAAS,IAAM6C;IAEtC,MAAMnB,UAAU;QACdZ,cAAc;QAEd,IAAIQ,cAAc;YAChBA,aAAaoD,mBAAmB,CAAC,UAAUlD;YAC3CF,aAAaoD,mBAAmB,CAAC,UAAUlD;QAC7C;QAEAY,cAAcU,OAAO,CAACC,CAAAA;YACpBA,aAAa2B,mBAAmB,CAAC,UAAUlD;QAC7C;QACAY,cAAcuC,KAAK;QAEnBhD,mBAAAA,QAAAA,mBAAAA,KAAAA,IAAAA,KAAAA,IAAAA,eAAgBiD,UAAU;IAC5B;IAEA,IAAItD,cAAc;QAChBA,aAAa2B,gBAAgB,CAAC,UAAUzB,gBAAgB;YAAE0B,SAAS;QAAK;QACxE5B,aAAa2B,gBAAgB,CAAC,UAAUzB;IAC1C;IAEA,wCAAwC;IACxCA;IAEA,OAAO;QACLA;QACAE;IACF;AACF"}
@@ -3,21 +3,10 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- function _export(target, all) {
7
- for(var name in all)Object.defineProperty(target, name, {
8
- enumerable: true,
9
- get: all[name]
10
- });
11
- }
12
- _export(exports, {
13
- SafeZoneArea: function() {
6
+ Object.defineProperty(exports, "SafeZoneArea", {
7
+ enumerable: true,
8
+ get: function() {
14
9
  return SafeZoneArea;
15
- },
16
- isSameCoordinates: function() {
17
- return isSameCoordinates;
18
- },
19
- isSameRect: function() {
20
- return isSameRect;
21
10
  }
22
11
  });
23
12
  const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
@@ -30,140 +19,83 @@ const _getMouseAnchor = require("./getMouseAnchor.cjs");
30
19
  const _pointsToSvgPath = require("./pointsToSvgPath.cjs");
31
20
  const _SafeZoneAreastyles = require("./SafeZoneArea.styles.cjs");
32
21
  const _computeOutsideClipPath = require("./computeOutsideClipPath.cjs");
33
- // ---
34
- const EMPTY_RECT = {
35
- top: 0,
36
- right: 0,
37
- bottom: 0,
38
- left: 0,
39
- width: 0,
40
- height: 0,
41
- x: 0,
42
- y: 0,
43
- toJSON () {
44
- return '';
45
- }
46
- };
47
- function isSameRect(a, b) {
48
- return a.top === b.top && a.right === b.right && a.bottom === b.bottom && a.left === b.left && a.width === b.width && a.height === b.height;
49
- }
50
- function isSameCoordinates(a, b) {
51
- return a[0] === b[0] && a[1] === b[1];
52
- }
22
+ const _getSafeZonePoints = require("./getSafeZonePoints.cjs");
53
23
  const SafeZoneArea = /*#__PURE__*/ _react1.memo((props)=>{
54
24
  const { debug, onMouseEnter, onMouseMove, onMouseLeave, stateStore } = props;
55
25
  const clipPathId = (0, _reactutilities.useId)();
56
26
  const styles = (0, _SafeZoneAreastyles.useStyles)();
57
27
  const active = (0, _shim.useSyncExternalStore)(stateStore.subscribe, stateStore.isActive);
58
28
  const svgRef = _react1.useRef(null);
59
- const [state, setState] = _react1.useState(()=>({
60
- containerRect: EMPTY_RECT,
61
- targetRect: EMPTY_RECT,
62
- mouseCoordinates: [
63
- 0,
64
- 0
65
- ]
66
- }));
29
+ const safeZoneRef = _react1.useRef(null);
30
+ const clipPathRef = _react1.useRef(null);
31
+ const rectDebugRef = _react1.useRef(null);
67
32
  _react1.useImperativeHandle(props.imperativeRef, ()=>({
68
- updateSVG (newState) {
69
- setState((prevState)=>{
70
- // Heads up!
71
- // A small optimization to avoid unnecessary re-renders
72
- if (isSameRect(prevState.containerRect, newState.containerRect) && isSameRect(prevState.targetRect, newState.targetRect) && isSameCoordinates(prevState.mouseCoordinates, newState.mouseCoordinates)) {
73
- return prevState;
74
- }
75
- return newState;
33
+ updateSVG ({ containerRect, targetRect, mouseCoordinates }) {
34
+ var _safeZoneRef_current, _clipPathRef_current, _rectDebugRef_current;
35
+ const topOffset = Math.min(targetRect.top, containerRect.top);
36
+ const leftOffset = Math.min(targetRect.left, containerRect.left);
37
+ const bottomOffset = Math.max(targetRect.bottom, containerRect.bottom);
38
+ const rightOffset = Math.max(targetRect.right, containerRect.right);
39
+ const containerCorners = (0, _getRectCorners.getRectCorners)(containerRect, [
40
+ leftOffset,
41
+ topOffset
42
+ ]);
43
+ const targetCorners = (0, _getRectCorners.getRectCorners)(targetRect, [
44
+ leftOffset,
45
+ topOffset
46
+ ]);
47
+ // SVG coordinates are relative to its top-left corner.
48
+ const relativeMouseCoordinates = [
49
+ mouseCoordinates[0] - leftOffset,
50
+ mouseCoordinates[1] - topOffset
51
+ ];
52
+ const mouseAnchor = (0, _getMouseAnchor.getMouseAnchor)(containerCorners.topLeft, containerCorners.bottomRight, relativeMouseCoordinates);
53
+ const svgWidth = rightOffset - leftOffset;
54
+ const svgHeight = bottomOffset - topOffset;
55
+ const clipPath = (0, _computeOutsideClipPath.computeOutsideClipPath)(svgWidth, svgHeight, {
56
+ x: targetCorners.topLeft[0],
57
+ y: targetCorners.topLeft[1],
58
+ width: targetRect.width,
59
+ height: targetRect.height
76
60
  });
61
+ if (svgRef.current) {
62
+ svgRef.current.style.width = `${svgWidth}px`;
63
+ svgRef.current.style.height = `${svgHeight}px`;
64
+ svgRef.current.style.transform = `translate(${leftOffset}px, ${topOffset}px)`;
65
+ }
66
+ const safeZonePoints = (0, _getSafeZonePoints.getSafeZonePoints)(mouseAnchor, containerCorners);
67
+ (_safeZoneRef_current = safeZoneRef.current) === null || _safeZoneRef_current === void 0 ? void 0 : _safeZoneRef_current.setAttribute('d', safeZonePoints.length > 0 ? (0, _pointsToSvgPath.pointsToSvgPath)(safeZonePoints) : '');
68
+ (_clipPathRef_current = clipPathRef.current) === null || _clipPathRef_current === void 0 ? void 0 : _clipPathRef_current.setAttribute('d', clipPath);
69
+ (_rectDebugRef_current = rectDebugRef.current) === null || _rectDebugRef_current === void 0 ? void 0 : _rectDebugRef_current.setAttribute('d', clipPath);
77
70
  }
78
71
  }), []);
79
- const { containerRect, targetRect, mouseCoordinates } = state;
80
- const topOffset = Math.min(targetRect.top, containerRect.top);
81
- const leftOffset = Math.min(targetRect.left, containerRect.left);
82
- const bottomOffset = Math.max(targetRect.bottom, containerRect.bottom);
83
- const rightOffset = Math.max(targetRect.right, containerRect.right);
84
- // ---
85
- const containerCorners = (0, _getRectCorners.getRectCorners)(containerRect, [
86
- leftOffset,
87
- topOffset
88
- ]);
89
- const targetCorners = (0, _getRectCorners.getRectCorners)(targetRect, [
90
- leftOffset,
91
- topOffset
92
- ]);
93
- // Heads up!
94
- // The SVG coordinate system starts at the top-left corner of the SVG element,
95
- // so we need to adjust the mouse coordinates relative to the SVG's top-left corner.
96
- const relativeMouseCoordinates = [
97
- mouseCoordinates[0] - leftOffset,
98
- mouseCoordinates[1] - topOffset
99
- ];
100
- const mouseAnchor = (0, _getMouseAnchor.getMouseAnchor)(containerCorners.topLeft, containerCorners.bottomRight, relativeMouseCoordinates);
101
- const triangleA = [
102
- mouseAnchor,
103
- containerCorners.topLeft,
104
- containerCorners.topRight
105
- ];
106
- const triangleB = [
107
- mouseAnchor,
108
- containerCorners.topRight,
109
- containerCorners.bottomRight
110
- ];
111
- const triangleC = [
112
- mouseAnchor,
113
- containerCorners.bottomRight,
114
- containerCorners.bottomLeft
115
- ];
116
- const triangleD = [
117
- mouseAnchor,
118
- containerCorners.bottomLeft,
119
- containerCorners.topLeft
120
- ];
121
- const svgWidth = rightOffset - leftOffset;
122
- const svgHeight = bottomOffset - topOffset;
123
- const clipPath = (0, _computeOutsideClipPath.computeOutsideClipPath)(svgWidth, svgHeight, {
124
- x: targetCorners.topLeft[0],
125
- y: targetCorners.topLeft[1],
126
- width: targetRect.width,
127
- height: targetRect.height
128
- }, {
129
- x: containerCorners.topLeft[0],
130
- y: containerCorners.topLeft[1],
131
- width: containerRect.width,
132
- height: containerRect.height
133
- });
134
72
  return /*#__PURE__*/ _react1.createElement("div", {
135
73
  className: (0, _react.mergeClasses)(styles.wrapper, active && styles.wrapperActive),
136
74
  "data-safe-zone": ""
137
- }, active ? /*#__PURE__*/ _react1.createElement("svg", {
75
+ }, /*#__PURE__*/ _react1.createElement("svg", {
138
76
  "aria-hidden": true,
139
77
  className: styles.svg,
140
78
  xmlns: "http://www.w3.org/2000/svg",
141
79
  ref: svgRef,
142
80
  style: {
143
- width: `${svgWidth}px`,
144
- height: `${svgHeight}px`,
145
- transform: `translate(${leftOffset}px, ${topOffset}px)`
81
+ width: 0,
82
+ height: 0,
83
+ transform: 'translate(0px, 0px)'
146
84
  }
147
85
  }, /*#__PURE__*/ _react1.createElement("g", {
148
- className: (0, _react.mergeClasses)(styles.triangle, debug && styles.triangleDebug),
86
+ className: (0, _react.mergeClasses)(styles.safeZone, debug && styles.safeZoneDebug),
149
87
  clipPath: `url(#${clipPathId})`,
150
88
  onMouseEnter: onMouseEnter,
151
89
  onMouseMove: onMouseMove,
152
90
  onMouseLeave: onMouseLeave
153
91
  }, /*#__PURE__*/ _react1.createElement("path", {
154
- d: (0, _pointsToSvgPath.pointsToSvgPath)(triangleA)
155
- }), /*#__PURE__*/ _react1.createElement("path", {
156
- d: (0, _pointsToSvgPath.pointsToSvgPath)(triangleB)
157
- }), /*#__PURE__*/ _react1.createElement("path", {
158
- d: (0, _pointsToSvgPath.pointsToSvgPath)(triangleC)
159
- }), /*#__PURE__*/ _react1.createElement("path", {
160
- d: (0, _pointsToSvgPath.pointsToSvgPath)(triangleD)
92
+ ref: safeZoneRef
161
93
  })), /*#__PURE__*/ _react1.createElement("clipPath", {
162
94
  id: clipPathId
163
95
  }, /*#__PURE__*/ _react1.createElement("path", {
164
- d: clipPath
96
+ ref: clipPathRef
165
97
  })), debug && /*#__PURE__*/ _react1.createElement("path", {
166
- className: styles.rectDebug,
167
- d: clipPath
168
- })) : null);
98
+ ref: rectDebugRef,
99
+ className: styles.rectDebug
100
+ })));
169
101
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/hooks/useSafeZoneArea/SafeZoneArea.tsx"],"sourcesContent":["'use client';\n\nimport { mergeClasses } from '@griffel/react';\nimport { useId } from '@fluentui/react-utilities';\nimport type { JSXElement } from '@fluentui/react-utilities';\nimport * as React from 'react';\nimport { useSyncExternalStore } from 'use-sync-external-store/shim';\n\nimport type { createSafeZoneAreaStateStore } from './createSafeZoneAreaStateStore';\nimport { getRectCorners } from './getRectCorners';\nimport { getMouseAnchor } from './getMouseAnchor';\nimport { pointsToSvgPath } from './pointsToSvgPath';\nimport { useStyles } from './SafeZoneArea.styles';\nimport type { Point } from './types';\nimport { computeOutsideClipPath } from './computeOutsideClipPath';\n\nexport type SafeZoneAreaImperativeHandle = {\n updateSVG: (options: { containerRect: DOMRect; targetRect: DOMRect; mouseCoordinates: Point }) => void;\n};\n\nexport type SafeZoneAreaProps = {\n /** Enables debug mode: makes drawn shapes visible. */\n debug: boolean;\n\n /** A reference to the SafeZoneArea imperative handle. */\n imperativeRef: React.Ref<SafeZoneAreaImperativeHandle>;\n\n // eslint-disable-next-line @nx/workspace-consistent-callback-type\n onMouseEnter: (e: React.MouseEvent) => void;\n // eslint-disable-next-line @nx/workspace-consistent-callback-type\n onMouseMove: (e: React.MouseEvent) => void;\n // eslint-disable-next-line @nx/workspace-consistent-callback-type\n onMouseLeave: (e: React.MouseEvent) => void;\n\n stateStore: ReturnType<typeof createSafeZoneAreaStateStore>;\n};\n\n/**\n * @internal\n */\ntype SafeZoneAreaState = {\n containerRect: DOMRect;\n targetRect: DOMRect;\n mouseCoordinates: Point;\n};\n\n// ---\n\nconst EMPTY_RECT: DOMRect = {\n top: 0,\n right: 0,\n bottom: 0,\n left: 0,\n width: 0,\n height: 0,\n x: 0,\n y: 0,\n toJSON() {\n return '';\n },\n};\n\nexport function isSameRect(a: DOMRect, b: DOMRect): boolean {\n return (\n a.top === b.top &&\n a.right === b.right &&\n a.bottom === b.bottom &&\n a.left === b.left &&\n a.width === b.width &&\n a.height === b.height\n );\n}\n\nexport function isSameCoordinates(a: Point, b: Point): boolean {\n return a[0] === b[0] && a[1] === b[1];\n}\n\n// ---\n\n/**\n * A component that renders a safe zone area with SVG shapes. Uses `useSyncExternalStore` to manage its active state\n * to avoid causing re-renders in `useSafeZoneArea()` as the hook might be used in host components like `Menu`.\n *\n * Draws two shapes:\n * - a triangle that points to the target element which is an actual safe zone\n * - a rectangle for a clip path that clips out the target element\n *\n * @internal\n */\nexport const SafeZoneArea = React.memo((props: SafeZoneAreaProps): JSXElement => {\n const { debug, onMouseEnter, onMouseMove, onMouseLeave, stateStore } = props;\n\n const clipPathId = useId();\n const styles = useStyles();\n\n const active = useSyncExternalStore(stateStore.subscribe, stateStore.isActive);\n const svgRef = React.useRef<SVGSVGElement>(null);\n\n const [state, setState] = React.useState<SafeZoneAreaState>(() => ({\n containerRect: EMPTY_RECT,\n targetRect: EMPTY_RECT,\n mouseCoordinates: [0, 0],\n }));\n\n React.useImperativeHandle(\n props.imperativeRef,\n () => ({\n updateSVG(newState) {\n setState(prevState => {\n // Heads up!\n // A small optimization to avoid unnecessary re-renders\n if (\n isSameRect(prevState.containerRect, newState.containerRect) &&\n isSameRect(prevState.targetRect, newState.targetRect) &&\n isSameCoordinates(prevState.mouseCoordinates, newState.mouseCoordinates)\n ) {\n return prevState;\n }\n\n return newState;\n });\n },\n }),\n [],\n );\n\n const { containerRect, targetRect, mouseCoordinates } = state;\n\n const topOffset = Math.min(targetRect.top, containerRect.top);\n const leftOffset = Math.min(targetRect.left, containerRect.left);\n const bottomOffset = Math.max(targetRect.bottom, containerRect.bottom);\n const rightOffset = Math.max(targetRect.right, containerRect.right);\n\n // ---\n\n const containerCorners = getRectCorners(containerRect, [leftOffset, topOffset]);\n const targetCorners = getRectCorners(targetRect, [leftOffset, topOffset]);\n\n // Heads up!\n // The SVG coordinate system starts at the top-left corner of the SVG element,\n // so we need to adjust the mouse coordinates relative to the SVG's top-left corner.\n const relativeMouseCoordinates: Point = [mouseCoordinates[0] - leftOffset, mouseCoordinates[1] - topOffset];\n const mouseAnchor = getMouseAnchor(containerCorners.topLeft, containerCorners.bottomRight, relativeMouseCoordinates);\n\n const triangleA = [mouseAnchor, containerCorners.topLeft, containerCorners.topRight];\n const triangleB = [mouseAnchor, containerCorners.topRight, containerCorners.bottomRight];\n const triangleC = [mouseAnchor, containerCorners.bottomRight, containerCorners.bottomLeft];\n const triangleD = [mouseAnchor, containerCorners.bottomLeft, containerCorners.topLeft];\n\n const svgWidth = rightOffset - leftOffset;\n const svgHeight = bottomOffset - topOffset;\n\n const clipPath = computeOutsideClipPath(\n svgWidth,\n svgHeight,\n {\n x: targetCorners.topLeft[0],\n y: targetCorners.topLeft[1],\n width: targetRect.width,\n height: targetRect.height,\n },\n {\n x: containerCorners.topLeft[0],\n y: containerCorners.topLeft[1],\n width: containerRect.width,\n height: containerRect.height,\n },\n );\n\n return (\n <div className={mergeClasses(styles.wrapper, active && styles.wrapperActive)} data-safe-zone=\"\">\n {active ? (\n <svg\n aria-hidden\n className={styles.svg}\n xmlns=\"http://www.w3.org/2000/svg\"\n ref={svgRef}\n style={{\n width: `${svgWidth}px`,\n height: `${svgHeight}px`,\n transform: `translate(${leftOffset}px, ${topOffset}px)`,\n }}\n >\n <g\n className={mergeClasses(styles.triangle, debug && styles.triangleDebug)}\n clipPath={`url(#${clipPathId})`}\n onMouseEnter={onMouseEnter}\n onMouseMove={onMouseMove}\n onMouseLeave={onMouseLeave}\n >\n <path d={pointsToSvgPath(triangleA)} />\n <path d={pointsToSvgPath(triangleB)} />\n <path d={pointsToSvgPath(triangleC)} />\n <path d={pointsToSvgPath(triangleD)} />\n </g>\n\n <clipPath id={clipPathId}>\n <path d={clipPath} />\n </clipPath>\n\n {debug && <path className={styles.rectDebug} d={clipPath} />}\n </svg>\n ) : null}\n </div>\n );\n});\n"],"names":["mergeClasses","useId","React","useSyncExternalStore","getRectCorners","getMouseAnchor","pointsToSvgPath","useStyles","computeOutsideClipPath","EMPTY_RECT","top","right","bottom","left","width","height","x","y","toJSON","isSameRect","a","b","isSameCoordinates","SafeZoneArea","memo","props","debug","onMouseEnter","onMouseMove","onMouseLeave","stateStore","clipPathId","styles","active","subscribe","isActive","svgRef","useRef","state","setState","useState","containerRect","targetRect","mouseCoordinates","useImperativeHandle","imperativeRef","updateSVG","newState","prevState","topOffset","Math","min","leftOffset","bottomOffset","max","rightOffset","containerCorners","targetCorners","relativeMouseCoordinates","mouseAnchor","topLeft","bottomRight","triangleA","topRight","triangleB","triangleC","bottomLeft","triangleD","svgWidth","svgHeight","clipPath","div","className","wrapper","wrapperActive","data-safe-zone","svg","aria-hidden","xmlns","ref","style","transform","g","triangle","triangleDebug","path","d","id","rectDebug"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/hooks/useSafeZoneArea/SafeZoneArea.tsx"],"sourcesContent":["'use client';\n\nimport { mergeClasses } from '@griffel/react';\nimport { useId } from '@fluentui/react-utilities';\nimport type { JSXElement } from '@fluentui/react-utilities';\nimport * as React from 'react';\nimport { useSyncExternalStore } from 'use-sync-external-store/shim';\n\nimport type { createSafeZoneAreaStateStore } from './createSafeZoneAreaStateStore';\nimport { getRectCorners } from './getRectCorners';\nimport { getMouseAnchor } from './getMouseAnchor';\nimport { pointsToSvgPath } from './pointsToSvgPath';\nimport { useStyles } from './SafeZoneArea.styles';\nimport type { Point } from './types';\nimport { computeOutsideClipPath } from './computeOutsideClipPath';\nimport { getSafeZonePoints } from './getSafeZonePoints';\n\nexport type SafeZoneAreaImperativeHandle = {\n updateSVG: (options: { containerRect: DOMRect; targetRect: DOMRect; mouseCoordinates: Point }) => void;\n};\n\nexport type SafeZoneAreaProps = {\n /** Enables debug mode: makes drawn shapes visible. */\n debug: boolean;\n\n /** A reference to the SafeZoneArea imperative handle. */\n imperativeRef: React.Ref<SafeZoneAreaImperativeHandle>;\n\n // eslint-disable-next-line @nx/workspace-consistent-callback-type\n onMouseEnter: (e: React.MouseEvent) => void;\n // eslint-disable-next-line @nx/workspace-consistent-callback-type\n onMouseMove: (e: React.MouseEvent) => void;\n // eslint-disable-next-line @nx/workspace-consistent-callback-type\n onMouseLeave: (e: React.MouseEvent) => void;\n\n stateStore: ReturnType<typeof createSafeZoneAreaStateStore>;\n};\n\n// ---\n\n/**\n * A component that renders a safe zone area with SVG shapes. Uses `useSyncExternalStore` to manage its active state\n * to avoid causing re-renders in `useSafeZoneArea()` as the hook might be used in host components like `Menu`.\n *\n * Draws a polygon from the mouse to the facing edges of the container and clips out the target element.\n *\n * @internal\n */\nexport const SafeZoneArea = React.memo((props: SafeZoneAreaProps): JSXElement => {\n const { debug, onMouseEnter, onMouseMove, onMouseLeave, stateStore } = props;\n\n const clipPathId = useId();\n const styles = useStyles();\n\n const active = useSyncExternalStore(stateStore.subscribe, stateStore.isActive);\n const svgRef = React.useRef<SVGSVGElement>(null);\n const safeZoneRef = React.useRef<SVGPathElement>(null);\n const clipPathRef = React.useRef<SVGPathElement>(null);\n const rectDebugRef = React.useRef<SVGPathElement>(null);\n\n React.useImperativeHandle(\n props.imperativeRef,\n () => ({\n updateSVG({ containerRect, targetRect, mouseCoordinates }) {\n const topOffset = Math.min(targetRect.top, containerRect.top);\n const leftOffset = Math.min(targetRect.left, containerRect.left);\n const bottomOffset = Math.max(targetRect.bottom, containerRect.bottom);\n const rightOffset = Math.max(targetRect.right, containerRect.right);\n\n const containerCorners = getRectCorners(containerRect, [leftOffset, topOffset]);\n const targetCorners = getRectCorners(targetRect, [leftOffset, topOffset]);\n\n // SVG coordinates are relative to its top-left corner.\n const relativeMouseCoordinates: Point = [mouseCoordinates[0] - leftOffset, mouseCoordinates[1] - topOffset];\n const mouseAnchor = getMouseAnchor(\n containerCorners.topLeft,\n containerCorners.bottomRight,\n relativeMouseCoordinates,\n );\n\n const svgWidth = rightOffset - leftOffset;\n const svgHeight = bottomOffset - topOffset;\n const clipPath = computeOutsideClipPath(svgWidth, svgHeight, {\n x: targetCorners.topLeft[0],\n y: targetCorners.topLeft[1],\n width: targetRect.width,\n height: targetRect.height,\n });\n\n if (svgRef.current) {\n svgRef.current.style.width = `${svgWidth}px`;\n svgRef.current.style.height = `${svgHeight}px`;\n svgRef.current.style.transform = `translate(${leftOffset}px, ${topOffset}px)`;\n }\n\n const safeZonePoints = getSafeZonePoints(mouseAnchor, containerCorners);\n safeZoneRef.current?.setAttribute('d', safeZonePoints.length > 0 ? pointsToSvgPath(safeZonePoints) : '');\n clipPathRef.current?.setAttribute('d', clipPath);\n rectDebugRef.current?.setAttribute('d', clipPath);\n },\n }),\n [],\n );\n\n return (\n <div className={mergeClasses(styles.wrapper, active && styles.wrapperActive)} data-safe-zone=\"\">\n <svg\n aria-hidden\n className={styles.svg}\n xmlns=\"http://www.w3.org/2000/svg\"\n ref={svgRef}\n style={{ width: 0, height: 0, transform: 'translate(0px, 0px)' }}\n >\n <g\n className={mergeClasses(styles.safeZone, debug && styles.safeZoneDebug)}\n clipPath={`url(#${clipPathId})`}\n onMouseEnter={onMouseEnter}\n onMouseMove={onMouseMove}\n onMouseLeave={onMouseLeave}\n >\n <path ref={safeZoneRef} />\n </g>\n\n <clipPath id={clipPathId}>\n <path ref={clipPathRef} />\n </clipPath>\n\n {debug && <path ref={rectDebugRef} className={styles.rectDebug} />}\n </svg>\n </div>\n );\n});\n"],"names":["mergeClasses","useId","React","useSyncExternalStore","getRectCorners","getMouseAnchor","pointsToSvgPath","useStyles","computeOutsideClipPath","getSafeZonePoints","SafeZoneArea","memo","props","debug","onMouseEnter","onMouseMove","onMouseLeave","stateStore","clipPathId","styles","active","subscribe","isActive","svgRef","useRef","safeZoneRef","clipPathRef","rectDebugRef","useImperativeHandle","imperativeRef","updateSVG","containerRect","targetRect","mouseCoordinates","topOffset","Math","min","top","leftOffset","left","bottomOffset","max","bottom","rightOffset","right","containerCorners","targetCorners","relativeMouseCoordinates","mouseAnchor","topLeft","bottomRight","svgWidth","svgHeight","clipPath","x","y","width","height","current","style","transform","safeZonePoints","setAttribute","length","div","className","wrapper","wrapperActive","data-safe-zone","svg","aria-hidden","xmlns","ref","g","safeZone","safeZoneDebug","path","id","rectDebug"],"mappings":"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"}
@@ -30,10 +30,10 @@ const useStyles = /*#__PURE__*/ (0, _react.__styles)({
30
30
  "f1e31b4d"
31
31
  ]
32
32
  },
33
- triangle: {
33
+ safeZone: {
34
34
  Bkecrkj: "f1cguypg"
35
35
  },
36
- triangleDebug: {
36
+ safeZoneDebug: {
37
37
  Bceei9c: "f7116n6",
38
38
  Bkfmm31: "f1xab38x"
39
39
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["SafeZoneArea.styles.js"],"sourcesContent":["'use client';\nimport { makeStyles } from \"@griffel/react\";\nimport { tokens } from \"@fluentui/react-theme\";\nexport const useStyles = makeStyles({\n wrapper: {\n display: 'none',\n height: 0,\n width: 0,\n pointerEvents: 'none'\n },\n wrapperActive: {\n display: 'block'\n },\n svg: {\n fill: 'transparent',\n pointerEvents: 'none',\n position: 'fixed',\n top: 0,\n left: 0\n },\n triangle: {\n pointerEvents: 'auto'\n },\n triangleDebug: {\n cursor: 'crosshair',\n fill: `color-mix(in srgb, ${tokens.colorPaletteGreenBackground3} 20%, transparent)`\n },\n rectDebug: {\n fill: `color-mix(in srgb, ${tokens.colorPaletteRedBackground3} 20%, transparent)`\n }\n});\n"],"names":["__styles","tokens","useStyles","wrapper","mc9l5x","Bqenvij","a9b677","Bkecrkj","wrapperActive","svg","Bkfmm31","qhf8xq","Bhzewxz","oyh7mz","triangle","triangleDebug","Bceei9c","rectDebug","d"],"mappings":"AAAA,YAAY;;;;;+BAGCE,SAAS;;;;;;uBAFK,gBAAgB;AAEpC,kBAAe,WAAA,OAAGF,eAAA,EAAA;IAAAG,OAAA,EAAA;QAAAC,MAAA,EAAA;QAAAC,OAAA,EAAA;QAAAC,MAAA,EAAA;QAAAC,OAAA,EAAA;IAAA;IAAAC,aAAA,EAAA;QAAAJ,MAAA,EAAA;IAAA;IAAAK,GAAA,EAAA;QAAAC,OAAA,EAAA;QAAAH,OAAA,EAAA;QAAAI,MAAA,EAAA;QAAAC,OAAA,EAAA;QAAAC,MAAA,EAAA;YAAA;YAAA;SAAA;IAAA;IAAAC,QAAA,EAAA;QAAAP,OAAA,EAAA;IAAA;IAAAQ,aAAA,EAAA;QAAAC,OAAA,EAAA;QAAAN,OAAA,EAAA;IAAA;IAAAO,SAAA,EAAA;QAAAP,OAAA,EAAA;IAAA;AAAA,GAAA;IAAAQ,CAAA,EAAA;QAAA;QAAA;QAAA;QAAA;QAAA;QAAA;QAAA;QAAA;QAAA;QAAA;QAAA;QAAA;QAAA;QAAA;KAAA;AAAA,CA2BxB,CAAC"}
1
+ {"version":3,"sources":["SafeZoneArea.styles.js"],"sourcesContent":["'use client';\nimport { makeStyles } from \"@griffel/react\";\nimport { tokens } from \"@fluentui/react-theme\";\nexport const useStyles = makeStyles({\n wrapper: {\n display: 'none',\n height: 0,\n width: 0,\n pointerEvents: 'none'\n },\n wrapperActive: {\n display: 'block'\n },\n svg: {\n fill: 'transparent',\n pointerEvents: 'none',\n position: 'fixed',\n top: 0,\n left: 0\n },\n safeZone: {\n pointerEvents: 'auto'\n },\n safeZoneDebug: {\n cursor: 'crosshair',\n fill: `color-mix(in srgb, ${tokens.colorPaletteGreenBackground3} 20%, transparent)`\n },\n rectDebug: {\n fill: `color-mix(in srgb, ${tokens.colorPaletteRedBackground3} 20%, transparent)`\n }\n});\n"],"names":["__styles","tokens","useStyles","wrapper","mc9l5x","Bqenvij","a9b677","Bkecrkj","wrapperActive","svg","Bkfmm31","qhf8xq","Bhzewxz","oyh7mz","safeZone","safeZoneDebug","Bceei9c","rectDebug","d"],"mappings":"AAAA,YAAY;;;;;+BAGCE,SAAS;;;;;;uBAFK,gBAAgB;AAEpC,kBAAe,WAAA,OAAGF,eAAA,EAAA;IAAAG,OAAA,EAAA;QAAAC,MAAA,EAAA;QAAAC,OAAA,EAAA;QAAAC,MAAA,EAAA;QAAAC,OAAA,EAAA;IAAA;IAAAC,aAAA,EAAA;QAAAJ,MAAA,EAAA;IAAA;IAAAK,GAAA,EAAA;QAAAC,OAAA,EAAA;QAAAH,OAAA,EAAA;QAAAI,MAAA,EAAA;QAAAC,OAAA,EAAA;QAAAC,MAAA,EAAA;YAAA;YAAA;SAAA;IAAA;IAAAC,QAAA,EAAA;QAAAP,OAAA,EAAA;IAAA;IAAAQ,aAAA,EAAA;QAAAC,OAAA,EAAA;QAAAN,OAAA,EAAA;IAAA;IAAAO,SAAA,EAAA;QAAAP,OAAA,EAAA;IAAA;AAAA,GAAA;IAAAQ,CAAA,EAAA;QAAA;QAAA;QAAA;QAAA;QAAA;QAAA;QAAA;QAAA;QAAA;QAAA;QAAA;QAAA;QAAA;QAAA;KAAA;AAAA,CA2BxB,CAAC"}
@@ -28,10 +28,10 @@ const useStyles = (0, _react.makeStyles)({
28
28
  top: 0,
29
29
  left: 0
30
30
  },
31
- triangle: {
31
+ safeZone: {
32
32
  pointerEvents: 'auto'
33
33
  },
34
- triangleDebug: {
34
+ safeZoneDebug: {
35
35
  cursor: 'crosshair',
36
36
  fill: `color-mix(in srgb, ${_reacttheme.tokens.colorPaletteGreenBackground3} 20%, transparent)`
37
37
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/hooks/useSafeZoneArea/SafeZoneArea.styles.ts"],"sourcesContent":["'use client';\n\nimport { makeStyles } from '@griffel/react';\nimport { tokens } from '@fluentui/react-theme';\n\nexport const useStyles = makeStyles({\n wrapper: {\n display: 'none',\n height: 0,\n width: 0,\n pointerEvents: 'none',\n },\n wrapperActive: {\n display: 'block',\n },\n svg: {\n fill: 'transparent',\n pointerEvents: 'none',\n position: 'fixed',\n top: 0,\n left: 0,\n },\n triangle: {\n pointerEvents: 'auto',\n },\n triangleDebug: {\n cursor: 'crosshair',\n fill: `color-mix(in srgb, ${tokens.colorPaletteGreenBackground3} 20%, transparent)`,\n },\n rectDebug: {\n fill: `color-mix(in srgb, ${tokens.colorPaletteRedBackground3} 20%, transparent)`,\n },\n});\n"],"names":["makeStyles","tokens","useStyles","wrapper","display","height","width","pointerEvents","wrapperActive","svg","fill","position","top","left","triangle","triangleDebug","cursor","colorPaletteGreenBackground3","rectDebug","colorPaletteRedBackground3"],"mappings":"AAAA;;;;;+BAKaE;;;;;;uBAHc,iBAAiB;4BACrB,wBAAwB;AAExC,sBAAkBF,iBAAAA,EAAW;IAClCG,SAAS;QACPC,SAAS;QACTC,QAAQ;QACRC,OAAO;QACPC,eAAe;IACjB;IACAC,eAAe;QACbJ,SAAS;IACX;IACAK,KAAK;QACHC,MAAM;QACNH,eAAe;QACfI,UAAU;QACVC,KAAK;QACLC,MAAM;IACR;IACAC,UAAU;QACRP,eAAe;IACjB;IACAQ,eAAe;QACbC,QAAQ;QACRN,MAAM,CAAC,mBAAmB,EAAET,kBAAAA,CAAOgB,4BAA4B,CAAC,kBAAkB,CAAC;IACrF;IACAC,WAAW;QACTR,MAAM,CAAC,mBAAmB,EAAET,kBAAAA,CAAOkB,0BAA0B,CAAC,kBAAkB,CAAC;IACnF;AACF,GAAG"}
1
+ {"version":3,"sources":["../src/hooks/useSafeZoneArea/SafeZoneArea.styles.ts"],"sourcesContent":["'use client';\n\nimport { makeStyles } from '@griffel/react';\nimport { tokens } from '@fluentui/react-theme';\n\nexport const useStyles = makeStyles({\n wrapper: {\n display: 'none',\n height: 0,\n width: 0,\n pointerEvents: 'none',\n },\n wrapperActive: {\n display: 'block',\n },\n svg: {\n fill: 'transparent',\n pointerEvents: 'none',\n position: 'fixed',\n top: 0,\n left: 0,\n },\n safeZone: {\n pointerEvents: 'auto',\n },\n safeZoneDebug: {\n cursor: 'crosshair',\n fill: `color-mix(in srgb, ${tokens.colorPaletteGreenBackground3} 20%, transparent)`,\n },\n rectDebug: {\n fill: `color-mix(in srgb, ${tokens.colorPaletteRedBackground3} 20%, transparent)`,\n },\n});\n"],"names":["makeStyles","tokens","useStyles","wrapper","display","height","width","pointerEvents","wrapperActive","svg","fill","position","top","left","safeZone","safeZoneDebug","cursor","colorPaletteGreenBackground3","rectDebug","colorPaletteRedBackground3"],"mappings":"AAAA;;;;;+BAKaE;;;;;;uBAHc,iBAAiB;4BACrB,wBAAwB;AAExC,sBAAkBF,iBAAAA,EAAW;IAClCG,SAAS;QACPC,SAAS;QACTC,QAAQ;QACRC,OAAO;QACPC,eAAe;IACjB;IACAC,eAAe;QACbJ,SAAS;IACX;IACAK,KAAK;QACHC,MAAM;QACNH,eAAe;QACfI,UAAU;QACVC,KAAK;QACLC,MAAM;IACR;IACAC,UAAU;QACRP,eAAe;IACjB;IACAQ,eAAe;QACbC,QAAQ;QACRN,MAAM,CAAC,mBAAmB,EAAET,kBAAAA,CAAOgB,4BAA4B,CAAC,kBAAkB,CAAC;IACrF;IACAC,WAAW;QACTR,MAAM,CAAC,mBAAmB,EAAET,kBAAAA,CAAOkB,0BAA0B,CAAC,kBAAkB,CAAC;IACnF;AACF,GAAG"}
@@ -22,12 +22,9 @@ function drawRectangle(rect) {
22
22
  pathData += `Z `; // Close path
23
23
  return pathData;
24
24
  }
25
- function computeOutsideClipPath(svgWidth, svgHeight, targetRect, containerRect) {
25
+ function computeOutsideClipPath(svgWidth, svgHeight, targetRect) {
26
26
  let pathData = `M 0,0 H ${svgWidth} V ${svgHeight} H 0 Z `;
27
- // For each rectangle, add a subpath that "cuts out" the rectangle
28
- // The trick is to draw each rectangle in the counterclockwise direction
29
- // which creates a "hole" in the main path
27
+ // Draw the rectangle counterclockwise to create a hole in the main path.
30
28
  pathData += drawRectangle(targetRect);
31
- pathData += drawRectangle(containerRect);
32
29
  return pathData;
33
30
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/hooks/useSafeZoneArea/computeOutsideClipPath.ts"],"sourcesContent":["function drawRectangle(rect: { x: number; y: number; width: number; height: number }): string {\n if (rect.width <= 0 || rect.height <= 0) {\n return '';\n }\n\n let pathData = '';\n\n // Creates a subpath moving in counterclockwise direction to create a hole\n\n pathData += `M ${rect.x},${rect.y} `;\n pathData += `V ${rect.y + rect.height} `; // Down to bottom-left\n pathData += `H ${rect.x + rect.width} `; // Right to bottom-right\n pathData += `V ${rect.y} `; // Up to top-right\n pathData += `H ${rect.x} `; // Left to top-left (closing)\n pathData += `Z `; // Close path\n\n return pathData;\n}\n\n/**\n * Computes a clip path that covers the area outside multiple rectangles.\n *\n * @internal\n */\nexport function computeOutsideClipPath(\n svgWidth: number,\n svgHeight: number,\n targetRect: { x: number; y: number; width: number; height: number },\n containerRect: { x: number; y: number; width: number; height: number },\n): string {\n let pathData = `M 0,0 H ${svgWidth} V ${svgHeight} H 0 Z `;\n\n // For each rectangle, add a subpath that \"cuts out\" the rectangle\n // The trick is to draw each rectangle in the counterclockwise direction\n // which creates a \"hole\" in the main path\n\n pathData += drawRectangle(targetRect);\n pathData += drawRectangle(containerRect);\n\n return pathData;\n}\n"],"names":["drawRectangle","rect","width","height","pathData","x","y","computeOutsideClipPath","svgWidth","svgHeight","targetRect","containerRect"],"mappings":";;;;;;;eAwBgBO;;;AAxBhB,SAASP,cAAcC,IAA6D;IAClF,IAAIA,KAAKC,KAAK,IAAI,KAAKD,KAAKE,MAAM,IAAI,GAAG;QACvC,OAAO;IACT;IAEA,IAAIC,WAAW;IAEf,0EAA0E;IAE1EA,YAAY,CAAC,EAAE,EAAEH,KAAKI,CAAC,CAAC,CAAC,EAAEJ,KAAKK,CAAC,CAAC,CAAC,CAAC;IACpCF,YAAY,CAAC,EAAE,EAAEH,KAAKK,CAAC,GAAGL,KAAKE,MAAM,CAAC,CAAC,CAAC,EAAE,sBAAsB;IAChEC,YAAY,CAAC,EAAE,EAAEH,KAAKI,CAAC,GAAGJ,KAAKC,KAAK,CAAC,CAAC,CAAC,EAAE,wBAAwB;IACjEE,YAAY,CAAC,EAAE,EAAEH,KAAKK,CAAC,CAAC,CAAC,CAAC,EAAE,kBAAkB;IAC9CF,YAAY,CAAC,EAAE,EAAEH,KAAKI,CAAC,CAAC,CAAC,CAAC,EAAE,6BAA6B;IACzDD,YAAY,CAAC,EAAE,CAAC,EAAE,aAAa;IAE/B,OAAOA;AACT;AAOO,gCACLI,QAAgB,EAChBC,SAAiB,EACjBC,UAAmE,EACnEC,aAAsE;IAEtE,IAAIP,WAAW,CAAC,QAAQ,EAAEI,SAAS,GAAG,EAAEC,UAAU,OAAO,CAAC;IAE1D,kEAAkE;IAClE,wEAAwE;IACxE,0CAA0C;IAE1CL,YAAYJ,cAAcU;IAC1BN,YAAYJ,cAAcW;IAE1B,OAAOP;AACT"}
1
+ {"version":3,"sources":["../src/hooks/useSafeZoneArea/computeOutsideClipPath.ts"],"sourcesContent":["function drawRectangle(rect: { x: number; y: number; width: number; height: number }): string {\n if (rect.width <= 0 || rect.height <= 0) {\n return '';\n }\n\n let pathData = '';\n\n // Creates a subpath moving in counterclockwise direction to create a hole\n\n pathData += `M ${rect.x},${rect.y} `;\n pathData += `V ${rect.y + rect.height} `; // Down to bottom-left\n pathData += `H ${rect.x + rect.width} `; // Right to bottom-right\n pathData += `V ${rect.y} `; // Up to top-right\n pathData += `H ${rect.x} `; // Left to top-left (closing)\n pathData += `Z `; // Close path\n\n return pathData;\n}\n\n/**\n * Computes a clip path that covers the area outside a rectangle.\n *\n * @internal\n */\nexport function computeOutsideClipPath(\n svgWidth: number,\n svgHeight: number,\n targetRect: { x: number; y: number; width: number; height: number },\n): string {\n let pathData = `M 0,0 H ${svgWidth} V ${svgHeight} H 0 Z `;\n\n // Draw the rectangle counterclockwise to create a hole in the main path.\n\n pathData += drawRectangle(targetRect);\n\n return pathData;\n}\n"],"names":["drawRectangle","rect","width","height","pathData","x","y","computeOutsideClipPath","svgWidth","svgHeight","targetRect"],"mappings":";;;;;;;;;;AAAA,SAASA,cAAcC,IAA6D;IAClF,IAAIA,KAAKC,KAAK,IAAI,KAAKD,KAAKE,MAAM,IAAI,GAAG;QACvC,OAAO;IACT;IAEA,IAAIC,WAAW;IAEf,0EAA0E;IAE1EA,YAAY,CAAC,EAAE,EAAEH,KAAKI,CAAC,CAAC,CAAC,EAAEJ,KAAKK,CAAC,CAAC,CAAC,CAAC;IACpCF,YAAY,CAAC,EAAE,EAAEH,KAAKK,CAAC,GAAGL,KAAKE,MAAM,CAAC,CAAC,CAAC,EAAE,sBAAsB;IAChEC,YAAY,CAAC,EAAE,EAAEH,KAAKI,CAAC,GAAGJ,KAAKC,KAAK,CAAC,CAAC,CAAC,EAAE,wBAAwB;IACjEE,YAAY,CAAC,EAAE,EAAEH,KAAKK,CAAC,CAAC,CAAC,CAAC,EAAE,kBAAkB;IAC9CF,YAAY,CAAC,EAAE,EAAEH,KAAKI,CAAC,CAAC,CAAC,CAAC,EAAE,6BAA6B;IACzDD,YAAY,CAAC,EAAE,CAAC,EAAE,aAAa;IAE/B,OAAOA;AACT;AAOO,SAASG,uBACdC,QAAgB,EAChBC,SAAiB,EACjBC,UAAmE;IAEnE,IAAIN,WAAW,CAAC,QAAQ,EAAEI,SAAS,GAAG,EAAEC,UAAU,OAAO,CAAC;IAE1D,yEAAyE;IAEzEL,YAAYJ,cAAcU;IAE1B,OAAON;AACT"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Returns the mouse anchor and the container corners facing it.
3
+ *
4
+ * @internal
5
+ */ "use strict";
6
+ Object.defineProperty(exports, "__esModule", {
7
+ value: true
8
+ });
9
+ Object.defineProperty(exports, "getSafeZonePoints", {
10
+ enumerable: true,
11
+ get: function() {
12
+ return getSafeZonePoints;
13
+ }
14
+ });
15
+ function getSafeZonePoints(mouseAnchor, containerCorners) {
16
+ const { topLeft, topRight, bottomRight, bottomLeft } = containerCorners;
17
+ const isAbove = mouseAnchor[1] < topLeft[1];
18
+ const isBelow = mouseAnchor[1] > bottomLeft[1];
19
+ const isLeft = mouseAnchor[0] < topLeft[0];
20
+ const isRight = mouseAnchor[0] > topRight[0];
21
+ if (isAbove) {
22
+ if (isLeft) {
23
+ return [
24
+ mouseAnchor,
25
+ bottomLeft,
26
+ topLeft,
27
+ topRight
28
+ ];
29
+ }
30
+ if (isRight) {
31
+ return [
32
+ mouseAnchor,
33
+ topLeft,
34
+ topRight,
35
+ bottomRight
36
+ ];
37
+ }
38
+ return [
39
+ mouseAnchor,
40
+ topLeft,
41
+ topRight
42
+ ];
43
+ }
44
+ if (isBelow) {
45
+ if (isLeft) {
46
+ return [
47
+ mouseAnchor,
48
+ topLeft,
49
+ bottomLeft,
50
+ bottomRight
51
+ ];
52
+ }
53
+ if (isRight) {
54
+ return [
55
+ mouseAnchor,
56
+ topRight,
57
+ bottomRight,
58
+ bottomLeft
59
+ ];
60
+ }
61
+ return [
62
+ mouseAnchor,
63
+ bottomRight,
64
+ bottomLeft
65
+ ];
66
+ }
67
+ if (isLeft) {
68
+ return [
69
+ mouseAnchor,
70
+ bottomLeft,
71
+ topLeft
72
+ ];
73
+ }
74
+ if (isRight) {
75
+ return [
76
+ mouseAnchor,
77
+ topRight,
78
+ bottomRight
79
+ ];
80
+ }
81
+ return [];
82
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/useSafeZoneArea/getSafeZonePoints.ts"],"sourcesContent":["import type { Point } from './types';\n\ntype RectCorners = Record<'topLeft' | 'topRight' | 'bottomRight' | 'bottomLeft', Point>;\n\n/**\n * Returns the mouse anchor and the container corners facing it.\n *\n * @internal\n */\nexport function getSafeZonePoints(mouseAnchor: Point, containerCorners: RectCorners): Point[] {\n const { topLeft, topRight, bottomRight, bottomLeft } = containerCorners;\n const isAbove = mouseAnchor[1] < topLeft[1];\n const isBelow = mouseAnchor[1] > bottomLeft[1];\n const isLeft = mouseAnchor[0] < topLeft[0];\n const isRight = mouseAnchor[0] > topRight[0];\n\n if (isAbove) {\n if (isLeft) {\n return [mouseAnchor, bottomLeft, topLeft, topRight];\n }\n\n if (isRight) {\n return [mouseAnchor, topLeft, topRight, bottomRight];\n }\n\n return [mouseAnchor, topLeft, topRight];\n }\n\n if (isBelow) {\n if (isLeft) {\n return [mouseAnchor, topLeft, bottomLeft, bottomRight];\n }\n\n if (isRight) {\n return [mouseAnchor, topRight, bottomRight, bottomLeft];\n }\n\n return [mouseAnchor, bottomRight, bottomLeft];\n }\n\n if (isLeft) {\n return [mouseAnchor, bottomLeft, topLeft];\n }\n\n if (isRight) {\n return [mouseAnchor, topRight, bottomRight];\n }\n\n return [];\n}\n"],"names":["getSafeZonePoints","mouseAnchor","containerCorners","topLeft","topRight","bottomRight","bottomLeft","isAbove","isBelow","isLeft","isRight"],"mappings":"AAIA;;;;CAIC,GACD;;;;+BAAgBA;;;;;;AAAT,2BAA2BC,WAAkB,EAAEC,gBAA6B;IACjF,MAAM,EAAEC,OAAO,EAAEC,QAAQ,EAAEC,WAAW,EAAEC,UAAU,EAAE,GAAGJ;IACvD,MAAMK,UAAUN,WAAW,CAAC,EAAE,GAAGE,OAAO,CAAC,EAAE;IAC3C,MAAMK,UAAUP,WAAW,CAAC,EAAE,GAAGK,UAAU,CAAC,EAAE;IAC9C,MAAMG,SAASR,WAAW,CAAC,EAAE,GAAGE,OAAO,CAAC,EAAE;IAC1C,MAAMO,UAAUT,WAAW,CAAC,EAAE,GAAGG,QAAQ,CAAC,EAAE;IAE5C,IAAIG,SAAS;QACX,IAAIE,QAAQ;YACV,OAAO;gBAACR;gBAAaK;gBAAYH;gBAASC;aAAS;QACrD;QAEA,IAAIM,SAAS;YACX,OAAO;gBAACT;gBAAaE;gBAASC;gBAAUC;aAAY;QACtD;QAEA,OAAO;YAACJ;YAAaE;YAASC;SAAS;IACzC;IAEA,IAAII,SAAS;QACX,IAAIC,QAAQ;YACV,OAAO;gBAACR;gBAAaE;gBAASG;gBAAYD;aAAY;QACxD;QAEA,IAAIK,SAAS;YACX,OAAO;gBAACT;gBAAaG;gBAAUC;gBAAaC;aAAW;QACzD;QAEA,OAAO;YAACL;YAAaI;YAAaC;SAAW;IAC/C;IAEA,IAAIG,QAAQ;QACV,OAAO;YAACR;YAAaK;YAAYH;SAAQ;IAC3C;IAEA,IAAIO,SAAS;QACX,OAAO;YAACT;YAAaG;YAAUC;SAAY;IAC7C;IAEA,OAAO,EAAE;AACX"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluentui/react-positioning",
3
- "version": "9.23.1",
3
+ "version": "9.23.3",
4
4
  "description": "A react wrapper around Popper.js for Fluent UI",
5
5
  "main": "lib-commonjs/index.cjs",
6
6
  "module": "lib/index.js",
@@ -14,18 +14,21 @@
14
14
  "dependencies": {
15
15
  "@floating-ui/devtools": "^0.2.3",
16
16
  "@floating-ui/dom": "^1.6.12",
17
- "@fluentui/react-shared-contexts": "^9.26.3",
17
+ "@fluentui/react-shared-contexts": "^9.26.4",
18
18
  "@fluentui/react-theme": "^9.2.2",
19
- "@fluentui/react-utilities": "^9.26.6",
19
+ "@fluentui/react-utilities": "^9.26.7",
20
20
  "@griffel/react": "^1.5.32",
21
21
  "@swc/helpers": "^0.5.1",
22
- "use-sync-external-store": "^1.2.0"
22
+ "use-sync-external-store": "^1.4.0"
23
23
  },
24
24
  "peerDependencies": {
25
25
  "@types/react": ">=16.14.0 <20.0.0",
26
- "@types/react-dom": ">=16.9.0 <20.0.0",
27
- "react": ">=16.14.0 <20.0.0",
28
- "react-dom": ">=16.14.0 <20.0.0"
26
+ "react": ">=16.14.0 <20.0.0"
27
+ },
28
+ "peerDependenciesMeta": {
29
+ "@types/react": {
30
+ "optional": true
31
+ }
29
32
  },
30
33
  "beachball": {
31
34
  "disallowedChangeTypes": [