@atlaskit/react-ufo 3.13.10 → 3.13.12

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.
@@ -0,0 +1,20 @@
1
+ ---
2
+ description:
3
+ globs:
4
+ alwaysApply: true
5
+ ---
6
+ ## Code Comments Rule
7
+
8
+ When adding comments to code, ensure comments explain the code's purpose and behavior within the context of the codebase, not the context of the current change request or prompt. Comments should be written as if they were part of the original codebase and should be suitable for committing directly without any reference to the specific modification being made.
9
+
10
+ **Good examples:**
11
+ - "Ensures a single instance exists across the entire application"
12
+ - "Returns existing instance if already initialized"
13
+ - "Handles edge case where network request fails"
14
+ **Avoid:**
15
+ - "I will change this to use globalThis"
16
+ - "Moving this from local variable to global"
17
+ - "As requested, updating the implementation"
18
+ - References to "this change" or "this modification"
19
+
20
+ Comments should focus on explaining WHY the code exists and WHAT it does, not HOW it came to be implemented during the current session.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @atlaskit/ufo-interaction-ignore
2
2
 
3
+ ## 3.13.12
4
+
5
+ ### Patch Changes
6
+
7
+ - [#161803](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/161803)
8
+ [`71ce852a73a06`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/71ce852a73a06) -
9
+ AFO-3919 make DefaultInteractionID global singleton
10
+
11
+ ## 3.13.11
12
+
13
+ ### Patch Changes
14
+
15
+ - [#161290](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/161290)
16
+ [`26388d9d5e089`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/26388d9d5e089) -
17
+ AFO-3919 fix pre-existing UFOLoadHold not registering to new interaction
18
+
3
19
  ## 3.13.10
4
20
 
5
21
  ### Patch Changes
@@ -1,20 +1,76 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
3
4
  Object.defineProperty(exports, "__esModule", {
4
5
  value: true
5
6
  });
6
- exports.useInteractionId = exports.getInteractionId = exports.default = exports.DefaultInteractionID = void 0;
7
+ exports.useInteractionId = exports.subscribeToInteractionIdChanges = exports.getInteractionId = exports.default = exports.DefaultInteractionID = void 0;
8
+ var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
9
+ var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
10
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
7
11
  var _react = require("react");
12
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
8
13
  // Same structure as react's useRef.
9
14
  // This allows modals to use a ref to scope their value
10
15
  // const id = useRef(null);
11
16
  // <InteractionIDContext.Provider value={id}>...<
12
17
 
13
- // The default InteractionID object is a global singleton
14
- // It's the one that holds the root value used in routing,
15
- // and is overwritten when we have new interactions start.
16
- var DefaultInteractionID = exports.DefaultInteractionID = {
17
- current: null
18
+ // Subscription system for interaction ID changes
19
+
20
+ var listeners = new Set();
21
+
22
+ // Observable interaction ID implementation
23
+ var ObservableInteractionID = /*#__PURE__*/function () {
24
+ function ObservableInteractionID() {
25
+ (0, _classCallCheck2.default)(this, ObservableInteractionID);
26
+ (0, _defineProperty2.default)(this, "_current", null);
27
+ }
28
+ return (0, _createClass2.default)(ObservableInteractionID, [{
29
+ key: "current",
30
+ get: function get() {
31
+ return this._current;
32
+ },
33
+ set: function set(newId) {
34
+ var oldId = this._current;
35
+ this._current = newId;
36
+
37
+ // Notify all listeners if the ID actually changed and feature flag is enabled
38
+ if (oldId !== newId && (0, _platformFeatureFlags.fg)('platform_ufo_hold_cross_interaction')) {
39
+ listeners.forEach(function (listener) {
40
+ return listener(newId);
41
+ });
42
+ }
43
+ }
44
+ }]);
45
+ }(); // Type declaration for globalThis extension
46
+ // Ensures a single DefaultInteractionID instance exists across the entire application,
47
+ // even when the module is loaded multiple times in different contexts
48
+ var initializeGlobalDefaultInteractionID = function initializeGlobalDefaultInteractionID() {
49
+ // Return existing instance if already initialized
50
+ if (globalThis.__UFO_DEFAULT_INTERACTION_ID__) {
51
+ return globalThis.__UFO_DEFAULT_INTERACTION_ID__;
52
+ }
53
+
54
+ // Create and store new instance globally
55
+ var instance = new ObservableInteractionID();
56
+ globalThis.__UFO_DEFAULT_INTERACTION_ID__ = instance;
57
+ return instance;
58
+ };
59
+
60
+ // The default InteractionID object is a global singleton stored in globalThis.
61
+ // It holds the root value used in routing and is updated when new interactions start.
62
+ var DefaultInteractionID = exports.DefaultInteractionID = initializeGlobalDefaultInteractionID();
63
+
64
+ // Subscription functions
65
+ var subscribeToInteractionIdChanges = exports.subscribeToInteractionIdChanges = function subscribeToInteractionIdChanges(listener) {
66
+ if (!(0, _platformFeatureFlags.fg)('platform_ufo_hold_cross_interaction')) {
67
+ // Return a no-op unsubscribe function when feature flag is disabled
68
+ return function () {};
69
+ }
70
+ listeners.add(listener);
71
+ return function () {
72
+ listeners.delete(listener);
73
+ };
18
74
  };
19
75
 
20
76
  // We use a context to allow modals to have their own lifecycle
@@ -6,12 +6,41 @@ Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
8
  exports.default = UFOLoadHold;
9
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
9
10
  var _react = _interopRequireWildcard(require("react"));
11
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
10
12
  var _interactionContext = _interopRequireDefault(require("../interaction-context"));
13
+ var _interactionIdContext = _interopRequireWildcard(require("../interaction-id-context"));
11
14
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
12
15
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
13
16
  var useLayoutEffectSAFE = typeof window === 'undefined' ? _react.useEffect : _react.useLayoutEffect;
14
17
 
18
+ /**
19
+ * Custom hook to track changes to the interaction ID.
20
+ * Uses a subscription system when feature flag is enabled, otherwise returns the current value.
21
+ */
22
+ function useInteractionIdValue() {
23
+ var interactionId = (0, _react.useContext)(_interactionIdContext.default);
24
+ var _useState = (0, _react.useState)((interactionId === null || interactionId === void 0 ? void 0 : interactionId.current) || null),
25
+ _useState2 = (0, _slicedToArray2.default)(_useState, 2),
26
+ currentId = _useState2[0],
27
+ setCurrentId = _useState2[1];
28
+ useLayoutEffectSAFE(function () {
29
+ if ((0, _platformFeatureFlags.fg)('platform_ufo_hold_cross_interaction')) {
30
+ // New subscription-based approach
31
+ setCurrentId((interactionId === null || interactionId === void 0 ? void 0 : interactionId.current) || null);
32
+ var unsubscribe = (0, _interactionIdContext.subscribeToInteractionIdChanges)(function (newId) {
33
+ setCurrentId(newId);
34
+ });
35
+ return unsubscribe;
36
+ } else {
37
+ // Legacy behavior - just return the current value without subscription
38
+ setCurrentId((interactionId === null || interactionId === void 0 ? void 0 : interactionId.current) || null);
39
+ }
40
+ }, [interactionId]);
41
+ return currentId;
42
+ }
43
+
15
44
  /**
16
45
  * Render this whenever you're loading.
17
46
  *
@@ -64,6 +93,8 @@ function UFOLoadHold(_ref) {
64
93
  hold = _ref$hold === void 0 ? true : _ref$hold,
65
94
  _ref$experimental = _ref.experimental,
66
95
  experimental = _ref$experimental === void 0 ? false : _ref$experimental;
96
+ var currentInteractionId = useInteractionIdValue();
97
+
67
98
  // react-18: useId instead
68
99
  var context = (0, _react.useContext)(_interactionContext.default);
69
100
  useLayoutEffectSAFE(function () {
@@ -73,7 +104,7 @@ function UFOLoadHold(_ref) {
73
104
  }
74
105
  return context.hold(name);
75
106
  }
76
- }, [hold, context, name]);
107
+ }, [hold, context, name, currentInteractionId]);
77
108
 
78
109
  // react-18: can return children directly
79
110
  return children != null ? /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, children) : null;
@@ -1,15 +1,65 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
1
2
  import { createContext } from 'react';
3
+ import { fg } from '@atlaskit/platform-feature-flags';
2
4
 
3
5
  // Same structure as react's useRef.
4
6
  // This allows modals to use a ref to scope their value
5
7
  // const id = useRef(null);
6
8
  // <InteractionIDContext.Provider value={id}>...<
7
9
 
8
- // The default InteractionID object is a global singleton
9
- // It's the one that holds the root value used in routing,
10
- // and is overwritten when we have new interactions start.
11
- export const DefaultInteractionID = {
12
- current: null
10
+ // Subscription system for interaction ID changes
11
+
12
+ const listeners = new Set();
13
+
14
+ // Observable interaction ID implementation
15
+ class ObservableInteractionID {
16
+ constructor() {
17
+ _defineProperty(this, "_current", null);
18
+ }
19
+ get current() {
20
+ return this._current;
21
+ }
22
+ set current(newId) {
23
+ const oldId = this._current;
24
+ this._current = newId;
25
+
26
+ // Notify all listeners if the ID actually changed and feature flag is enabled
27
+ if (oldId !== newId && fg('platform_ufo_hold_cross_interaction')) {
28
+ listeners.forEach(listener => listener(newId));
29
+ }
30
+ }
31
+ }
32
+
33
+ // Type declaration for globalThis extension
34
+
35
+ // Ensures a single DefaultInteractionID instance exists across the entire application,
36
+ // even when the module is loaded multiple times in different contexts
37
+ const initializeGlobalDefaultInteractionID = () => {
38
+ // Return existing instance if already initialized
39
+ if (globalThis.__UFO_DEFAULT_INTERACTION_ID__) {
40
+ return globalThis.__UFO_DEFAULT_INTERACTION_ID__;
41
+ }
42
+
43
+ // Create and store new instance globally
44
+ const instance = new ObservableInteractionID();
45
+ globalThis.__UFO_DEFAULT_INTERACTION_ID__ = instance;
46
+ return instance;
47
+ };
48
+
49
+ // The default InteractionID object is a global singleton stored in globalThis.
50
+ // It holds the root value used in routing and is updated when new interactions start.
51
+ export const DefaultInteractionID = initializeGlobalDefaultInteractionID();
52
+
53
+ // Subscription functions
54
+ export const subscribeToInteractionIdChanges = listener => {
55
+ if (!fg('platform_ufo_hold_cross_interaction')) {
56
+ // Return a no-op unsubscribe function when feature flag is disabled
57
+ return () => {};
58
+ }
59
+ listeners.add(listener);
60
+ return () => {
61
+ listeners.delete(listener);
62
+ };
13
63
  };
14
64
 
15
65
  // We use a context to allow modals to have their own lifecycle
@@ -1,7 +1,32 @@
1
- import React, { useContext, useEffect, useLayoutEffect } from 'react';
1
+ import React, { useContext, useEffect, useLayoutEffect, useState } from 'react';
2
+ import { fg } from '@atlaskit/platform-feature-flags';
2
3
  import UFOInteractionContext from '../interaction-context';
4
+ import UFOInteractionIDContext, { subscribeToInteractionIdChanges } from '../interaction-id-context';
3
5
  const useLayoutEffectSAFE = typeof window === 'undefined' ? useEffect : useLayoutEffect;
4
6
 
7
+ /**
8
+ * Custom hook to track changes to the interaction ID.
9
+ * Uses a subscription system when feature flag is enabled, otherwise returns the current value.
10
+ */
11
+ function useInteractionIdValue() {
12
+ const interactionId = useContext(UFOInteractionIDContext);
13
+ const [currentId, setCurrentId] = useState((interactionId === null || interactionId === void 0 ? void 0 : interactionId.current) || null);
14
+ useLayoutEffectSAFE(() => {
15
+ if (fg('platform_ufo_hold_cross_interaction')) {
16
+ // New subscription-based approach
17
+ setCurrentId((interactionId === null || interactionId === void 0 ? void 0 : interactionId.current) || null);
18
+ const unsubscribe = subscribeToInteractionIdChanges(newId => {
19
+ setCurrentId(newId);
20
+ });
21
+ return unsubscribe;
22
+ } else {
23
+ // Legacy behavior - just return the current value without subscription
24
+ setCurrentId((interactionId === null || interactionId === void 0 ? void 0 : interactionId.current) || null);
25
+ }
26
+ }, [interactionId]);
27
+ return currentId;
28
+ }
29
+
5
30
  /**
6
31
  * Render this whenever you're loading.
7
32
  *
@@ -53,6 +78,8 @@ export default function UFOLoadHold({
53
78
  hold = true,
54
79
  experimental = false
55
80
  }) {
81
+ const currentInteractionId = useInteractionIdValue();
82
+
56
83
  // react-18: useId instead
57
84
  const context = useContext(UFOInteractionContext);
58
85
  useLayoutEffectSAFE(() => {
@@ -62,7 +89,7 @@ export default function UFOLoadHold({
62
89
  }
63
90
  return context.hold(name);
64
91
  }
65
- }, [hold, context, name]);
92
+ }, [hold, context, name, currentInteractionId]);
66
93
 
67
94
  // react-18: can return children directly
68
95
  return children != null ? /*#__PURE__*/React.createElement(React.Fragment, null, children) : null;
@@ -1,15 +1,70 @@
1
+ import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
2
+ import _createClass from "@babel/runtime/helpers/createClass";
3
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
1
4
  import { createContext } from 'react';
5
+ import { fg } from '@atlaskit/platform-feature-flags';
2
6
 
3
7
  // Same structure as react's useRef.
4
8
  // This allows modals to use a ref to scope their value
5
9
  // const id = useRef(null);
6
10
  // <InteractionIDContext.Provider value={id}>...<
7
11
 
8
- // The default InteractionID object is a global singleton
9
- // It's the one that holds the root value used in routing,
10
- // and is overwritten when we have new interactions start.
11
- export var DefaultInteractionID = {
12
- current: null
12
+ // Subscription system for interaction ID changes
13
+
14
+ var listeners = new Set();
15
+
16
+ // Observable interaction ID implementation
17
+ var ObservableInteractionID = /*#__PURE__*/function () {
18
+ function ObservableInteractionID() {
19
+ _classCallCheck(this, ObservableInteractionID);
20
+ _defineProperty(this, "_current", null);
21
+ }
22
+ return _createClass(ObservableInteractionID, [{
23
+ key: "current",
24
+ get: function get() {
25
+ return this._current;
26
+ },
27
+ set: function set(newId) {
28
+ var oldId = this._current;
29
+ this._current = newId;
30
+
31
+ // Notify all listeners if the ID actually changed and feature flag is enabled
32
+ if (oldId !== newId && fg('platform_ufo_hold_cross_interaction')) {
33
+ listeners.forEach(function (listener) {
34
+ return listener(newId);
35
+ });
36
+ }
37
+ }
38
+ }]);
39
+ }(); // Type declaration for globalThis extension
40
+ // Ensures a single DefaultInteractionID instance exists across the entire application,
41
+ // even when the module is loaded multiple times in different contexts
42
+ var initializeGlobalDefaultInteractionID = function initializeGlobalDefaultInteractionID() {
43
+ // Return existing instance if already initialized
44
+ if (globalThis.__UFO_DEFAULT_INTERACTION_ID__) {
45
+ return globalThis.__UFO_DEFAULT_INTERACTION_ID__;
46
+ }
47
+
48
+ // Create and store new instance globally
49
+ var instance = new ObservableInteractionID();
50
+ globalThis.__UFO_DEFAULT_INTERACTION_ID__ = instance;
51
+ return instance;
52
+ };
53
+
54
+ // The default InteractionID object is a global singleton stored in globalThis.
55
+ // It holds the root value used in routing and is updated when new interactions start.
56
+ export var DefaultInteractionID = initializeGlobalDefaultInteractionID();
57
+
58
+ // Subscription functions
59
+ export var subscribeToInteractionIdChanges = function subscribeToInteractionIdChanges(listener) {
60
+ if (!fg('platform_ufo_hold_cross_interaction')) {
61
+ // Return a no-op unsubscribe function when feature flag is disabled
62
+ return function () {};
63
+ }
64
+ listeners.add(listener);
65
+ return function () {
66
+ listeners.delete(listener);
67
+ };
13
68
  };
14
69
 
15
70
  // We use a context to allow modals to have their own lifecycle
@@ -1,7 +1,36 @@
1
- import React, { useContext, useEffect, useLayoutEffect } from 'react';
1
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
+ import React, { useContext, useEffect, useLayoutEffect, useState } from 'react';
3
+ import { fg } from '@atlaskit/platform-feature-flags';
2
4
  import UFOInteractionContext from '../interaction-context';
5
+ import UFOInteractionIDContext, { subscribeToInteractionIdChanges } from '../interaction-id-context';
3
6
  var useLayoutEffectSAFE = typeof window === 'undefined' ? useEffect : useLayoutEffect;
4
7
 
8
+ /**
9
+ * Custom hook to track changes to the interaction ID.
10
+ * Uses a subscription system when feature flag is enabled, otherwise returns the current value.
11
+ */
12
+ function useInteractionIdValue() {
13
+ var interactionId = useContext(UFOInteractionIDContext);
14
+ var _useState = useState((interactionId === null || interactionId === void 0 ? void 0 : interactionId.current) || null),
15
+ _useState2 = _slicedToArray(_useState, 2),
16
+ currentId = _useState2[0],
17
+ setCurrentId = _useState2[1];
18
+ useLayoutEffectSAFE(function () {
19
+ if (fg('platform_ufo_hold_cross_interaction')) {
20
+ // New subscription-based approach
21
+ setCurrentId((interactionId === null || interactionId === void 0 ? void 0 : interactionId.current) || null);
22
+ var unsubscribe = subscribeToInteractionIdChanges(function (newId) {
23
+ setCurrentId(newId);
24
+ });
25
+ return unsubscribe;
26
+ } else {
27
+ // Legacy behavior - just return the current value without subscription
28
+ setCurrentId((interactionId === null || interactionId === void 0 ? void 0 : interactionId.current) || null);
29
+ }
30
+ }, [interactionId]);
31
+ return currentId;
32
+ }
33
+
5
34
  /**
6
35
  * Render this whenever you're loading.
7
36
  *
@@ -54,6 +83,8 @@ export default function UFOLoadHold(_ref) {
54
83
  hold = _ref$hold === void 0 ? true : _ref$hold,
55
84
  _ref$experimental = _ref.experimental,
56
85
  experimental = _ref$experimental === void 0 ? false : _ref$experimental;
86
+ var currentInteractionId = useInteractionIdValue();
87
+
57
88
  // react-18: useId instead
58
89
  var context = useContext(UFOInteractionContext);
59
90
  useLayoutEffectSAFE(function () {
@@ -63,7 +94,7 @@ export default function UFOLoadHold(_ref) {
63
94
  }
64
95
  return context.hold(name);
65
96
  }
66
- }, [hold, context, name]);
97
+ }, [hold, context, name, currentInteractionId]);
67
98
 
68
99
  // react-18: can return children directly
69
100
  return children != null ? /*#__PURE__*/React.createElement(React.Fragment, null, children) : null;
@@ -2,7 +2,12 @@
2
2
  export type InteractionIDContextType = {
3
3
  current: string | null;
4
4
  };
5
+ type InteractionIDListener = (newId: string | null) => void;
6
+ declare global {
7
+ var __UFO_DEFAULT_INTERACTION_ID__: InteractionIDContextType | undefined;
8
+ }
5
9
  export declare const DefaultInteractionID: InteractionIDContextType;
10
+ export declare const subscribeToInteractionIdChanges: (listener: InteractionIDListener) => (() => void);
6
11
  declare const _default: import("react").Context<InteractionIDContextType>;
7
12
  export default _default;
8
13
  export declare const getInteractionId: () => InteractionIDContextType;
@@ -2,7 +2,12 @@
2
2
  export type InteractionIDContextType = {
3
3
  current: string | null;
4
4
  };
5
+ type InteractionIDListener = (newId: string | null) => void;
6
+ declare global {
7
+ var __UFO_DEFAULT_INTERACTION_ID__: InteractionIDContextType | undefined;
8
+ }
5
9
  export declare const DefaultInteractionID: InteractionIDContextType;
10
+ export declare const subscribeToInteractionIdChanges: (listener: InteractionIDListener) => (() => void);
6
11
  declare const _default: import("react").Context<InteractionIDContextType>;
7
12
  export default _default;
8
13
  export declare const getInteractionId: () => InteractionIDContextType;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/react-ufo",
3
- "version": "3.13.10",
3
+ "version": "3.13.12",
4
4
  "description": "Parts of React UFO that are publicly available",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -168,6 +168,9 @@
168
168
  },
169
169
  "platform_ufo_v3_add_start_entry": {
170
170
  "type": "boolean"
171
+ },
172
+ "platform_ufo_hold_cross_interaction": {
173
+ "type": "boolean"
171
174
  }
172
175
  }
173
176
  }