@via-profit/ui-kit 0.12.0 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@
4
4
 
5
5
  ## Не выпущено
6
6
 
7
+ ## 0.12.1 — 2026-11-06
8
+
9
+ ### Исправлено
10
+
11
+ - **Popper**: автоматически закрывается при удалении элемента привязки из DOM или при передаче `anchorElement={null}`.
12
+
7
13
  ## 0.12.0 — 2026-11-05
8
14
 
9
15
  ### Добавлено
@@ -16,7 +16,7 @@ export interface PopperProps extends React.HTMLAttributes<HTMLDivElement> {
16
16
  readonly isOpen: boolean;
17
17
  /**
18
18
  * The HTML element to which the popper will be attached and positioned relative to.
19
- * While it is `null`, the popper stays hidden even if `isOpen` is `true`.
19
+ * The popper closes if the element is removed from the DOM or becomes `null`.
20
20
  *
21
21
  * @required
22
22
  * @example
package/Popper/Popper.js CHANGED
@@ -33,11 +33,29 @@ const react_1 = __importDefault(require("react"));
33
33
  const react_dom_1 = __importDefault(require("react-dom"));
34
34
  const PopperContainer_1 = __importDefault(require("./PopperContainer"));
35
35
  const usePopper_1 = require("./usePopper");
36
+ const getServerAnchorConnected = () => false;
36
37
  __exportStar(require("./usePopper"), exports);
37
38
  exports.PORTAL_ID = 'ui-kit-portal';
38
39
  const Popper = (props, ref) => {
39
40
  const { isOpen, children, anchorElement, zIndex, overrides, anchorPos = 'auto', positionStrategy = 'fixed', viewportMargin = 30, autoFlip = false, alternativePlacements, offset = 0, onAnchorPosChanged } = props, nativeProps = __rest(props, ["isOpen", "children", "anchorElement", "zIndex", "overrides", "anchorPos", "positionStrategy", "viewportMargin", "autoFlip", "alternativePlacements", "offset", "onAnchorPosChanged"]);
40
41
  const [domLoaded, setDomLoaded] = react_1.default.useState(false);
42
+ const subscribeToAnchor = react_1.default.useCallback((onChange) => {
43
+ if (!isOpen || !anchorElement) {
44
+ return () => { };
45
+ }
46
+ const observer = new MutationObserver(onChange);
47
+ const options = { childList: true, subtree: true };
48
+ observer.observe(anchorElement.ownerDocument, options);
49
+ // Mutations inside a shadow root are not reported by the document observer.
50
+ let root = anchorElement.getRootNode();
51
+ while (root instanceof ShadowRoot) {
52
+ observer.observe(root, options);
53
+ root = root.host.getRootNode();
54
+ }
55
+ return () => observer.disconnect();
56
+ }, [isOpen, anchorElement]);
57
+ const getAnchorConnected = react_1.default.useCallback(() => isOpen && Boolean(anchorElement === null || anchorElement === void 0 ? void 0 : anchorElement.isConnected), [isOpen, anchorElement]);
58
+ const canOpen = react_1.default.useSyncExternalStore(subscribeToAnchor, getAnchorConnected, getServerAnchorConnected);
41
59
  const { actualPlacement, style, popperRef, isVisible } = (0, usePopper_1.usePopper)({
42
60
  anchorElement,
43
61
  anchorPos,
@@ -46,7 +64,7 @@ const Popper = (props, ref) => {
46
64
  offset,
47
65
  viewportMargin,
48
66
  alternativePlacements,
49
- isOpen,
67
+ isOpen: canOpen,
50
68
  });
51
69
  const overridesMap = react_1.default.useMemo(() => ({
52
70
  Container: (overrides === null || overrides === void 0 ? void 0 : overrides.Container) || PopperContainer_1.default,
@@ -111,7 +129,7 @@ const Popper = (props, ref) => {
111
129
  popperRef,
112
130
  ref,
113
131
  ]);
114
- if (!isOpen) {
132
+ if (!canOpen) {
115
133
  return null;
116
134
  }
117
135
  if (positionStrategy === 'fixed') {
@@ -380,7 +380,7 @@ const usePopper = (props) => {
380
380
  ]);
381
381
  // #region Calculate Position
382
382
  const calculatePosition = react_1.default.useCallback(() => {
383
- if (!anchorElement || !popperRef.current) {
383
+ if (!(anchorElement === null || anchorElement === void 0 ? void 0 : anchorElement.isConnected) || !popperRef.current) {
384
384
  return;
385
385
  }
386
386
  const anchorRect = anchorElement.getBoundingClientRect();
@@ -13,11 +13,29 @@ import React from 'react';
13
13
  import ReactDOM from 'react-dom';
14
14
  import Container from './PopperContainer';
15
15
  import { usePopper } from './usePopper';
16
+ const getServerAnchorConnected = () => false;
16
17
  export * from './usePopper';
17
18
  export const PORTAL_ID = 'ui-kit-portal';
18
19
  const Popper = (props, ref) => {
19
20
  const { isOpen, children, anchorElement, zIndex, overrides, anchorPos = 'auto', positionStrategy = 'fixed', viewportMargin = 30, autoFlip = false, alternativePlacements, offset = 0, onAnchorPosChanged } = props, nativeProps = __rest(props, ["isOpen", "children", "anchorElement", "zIndex", "overrides", "anchorPos", "positionStrategy", "viewportMargin", "autoFlip", "alternativePlacements", "offset", "onAnchorPosChanged"]);
20
21
  const [domLoaded, setDomLoaded] = React.useState(false);
22
+ const subscribeToAnchor = React.useCallback((onChange) => {
23
+ if (!isOpen || !anchorElement) {
24
+ return () => { };
25
+ }
26
+ const observer = new MutationObserver(onChange);
27
+ const options = { childList: true, subtree: true };
28
+ observer.observe(anchorElement.ownerDocument, options);
29
+ // Mutations inside a shadow root are not reported by the document observer.
30
+ let root = anchorElement.getRootNode();
31
+ while (root instanceof ShadowRoot) {
32
+ observer.observe(root, options);
33
+ root = root.host.getRootNode();
34
+ }
35
+ return () => observer.disconnect();
36
+ }, [isOpen, anchorElement]);
37
+ const getAnchorConnected = React.useCallback(() => isOpen && Boolean(anchorElement === null || anchorElement === void 0 ? void 0 : anchorElement.isConnected), [isOpen, anchorElement]);
38
+ const canOpen = React.useSyncExternalStore(subscribeToAnchor, getAnchorConnected, getServerAnchorConnected);
21
39
  const { actualPlacement, style, popperRef, isVisible } = usePopper({
22
40
  anchorElement,
23
41
  anchorPos,
@@ -26,7 +44,7 @@ const Popper = (props, ref) => {
26
44
  offset,
27
45
  viewportMargin,
28
46
  alternativePlacements,
29
- isOpen,
47
+ isOpen: canOpen,
30
48
  });
31
49
  const overridesMap = React.useMemo(() => ({
32
50
  Container: (overrides === null || overrides === void 0 ? void 0 : overrides.Container) || Container,
@@ -91,7 +109,7 @@ const Popper = (props, ref) => {
91
109
  popperRef,
92
110
  ref,
93
111
  ]);
94
- if (!isOpen) {
112
+ if (!canOpen) {
95
113
  return null;
96
114
  }
97
115
  if (positionStrategy === 'fixed') {
@@ -373,7 +373,7 @@ export const usePopper = (props) => {
373
373
  ]);
374
374
  // #region Calculate Position
375
375
  const calculatePosition = React.useCallback(() => {
376
- if (!anchorElement || !popperRef.current) {
376
+ if (!(anchorElement === null || anchorElement === void 0 ? void 0 : anchorElement.isConnected) || !popperRef.current) {
377
377
  return;
378
378
  }
379
379
  const anchorRect = anchorElement.getBoundingClientRect();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@via-profit/ui-kit",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
4
4
  "description": "UI Kit",
5
5
  "repository": {
6
6
  "type": "git",