@atlaskit/spotlight 0.4.1 → 0.5.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.
Files changed (38) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/cjs/controllers/context.js +73 -5
  3. package/dist/cjs/index.js +8 -1
  4. package/dist/cjs/ui/UNSAFE_update-on-change/index.js +59 -0
  5. package/dist/cjs/ui/card/caret/index.js +2 -2
  6. package/dist/cjs/ui/card/index.js +2 -2
  7. package/dist/cjs/ui/popover-content/index.js +42 -8
  8. package/dist/cjs/utils/use-focus-within/index.js +51 -0
  9. package/dist/cjs/utils/use-on-escape/index.js +40 -0
  10. package/dist/es2019/controllers/context.js +27 -4
  11. package/dist/es2019/index.js +2 -1
  12. package/dist/es2019/ui/UNSAFE_update-on-change/index.js +53 -0
  13. package/dist/es2019/ui/card/caret/index.js +2 -2
  14. package/dist/es2019/ui/card/index.js +2 -2
  15. package/dist/es2019/ui/popover-content/index.js +36 -9
  16. package/dist/es2019/utils/use-focus-within/index.js +40 -0
  17. package/dist/es2019/utils/use-on-escape/index.js +31 -0
  18. package/dist/esm/controllers/context.js +73 -5
  19. package/dist/esm/index.js +2 -1
  20. package/dist/esm/ui/UNSAFE_update-on-change/index.js +53 -0
  21. package/dist/esm/ui/card/caret/index.js +2 -2
  22. package/dist/esm/ui/card/index.js +2 -2
  23. package/dist/esm/ui/popover-content/index.js +42 -9
  24. package/dist/esm/utils/use-focus-within/index.js +44 -0
  25. package/dist/esm/utils/use-on-escape/index.js +34 -0
  26. package/dist/types/controllers/context.d.ts +14 -5
  27. package/dist/types/index.d.ts +1 -0
  28. package/dist/types/ui/UNSAFE_update-on-change/index.d.ts +6 -0
  29. package/dist/types/ui/popover-content/index.d.ts +2 -1
  30. package/dist/types/utils/use-focus-within/index.d.ts +2 -0
  31. package/dist/types/utils/use-on-escape/index.d.ts +1 -0
  32. package/dist/types-ts4.5/controllers/context.d.ts +14 -5
  33. package/dist/types-ts4.5/index.d.ts +1 -0
  34. package/dist/types-ts4.5/ui/UNSAFE_update-on-change/index.d.ts +6 -0
  35. package/dist/types-ts4.5/ui/popover-content/index.d.ts +2 -1
  36. package/dist/types-ts4.5/utils/use-focus-within/index.d.ts +2 -0
  37. package/dist/types-ts4.5/utils/use-on-escape/index.d.ts +1 -0
  38. package/package.json +7 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @atlaskit/spotlight
2
2
 
3
+ ## 0.5.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`4f9f525caaa13`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/4f9f525caaa13) -
8
+ Implement 'dismiss on escape key press' functionality. Escape will cause the current spotlight to
9
+ call the `dismiss` function passed to `PopoverContent`. Implementation of the `dismiss` function
10
+ is up to the consumer of the package.
11
+ - Updated dependencies
12
+
13
+ ## 0.5.0
14
+
15
+ ### Minor Changes
16
+
17
+ - [`72526321aecd0`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/72526321aecd0) -
18
+ Create UNSAFE_UpdateOnChange component to test strategies for recalculating PopoverContent
19
+ position when the DOM changes.
20
+
3
21
  ## 0.4.1
4
22
 
5
23
  ### Patch Changes
@@ -10,21 +10,53 @@ exports.SpotlightContextProvider = exports.SpotlightContext = void 0;
10
10
  var _react = _interopRequireWildcard(require("react"));
11
11
  var React = _react;
12
12
  var _runtime = require("@compiled/react/runtime");
13
+ var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
14
+ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
13
15
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
14
16
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
15
17
  // eslint-disable-next-line @repo/internal/react/consistent-types-definitions
16
18
 
17
19
  // eslint-disable-next-line @repo/internal/react/require-jsdoc
18
20
  var SpotlightContext = exports.SpotlightContext = /*#__PURE__*/(0, _react.createContext)({
19
- placement: 'bottom-end',
20
- setPlacement: function setPlacement() {
21
- return undefined;
21
+ card: {
22
+ placement: 'bottom-end',
23
+ setPlacement: function setPlacement() {
24
+ return undefined;
25
+ }
22
26
  },
23
27
  heading: {
24
28
  id: '',
25
29
  setId: function setId() {
26
30
  return undefined;
27
31
  }
32
+ },
33
+ popoverContent: {
34
+ ref: undefined,
35
+ setRef: function setRef() {
36
+ return undefined;
37
+ },
38
+ update: function update() {
39
+ return function () {
40
+ return new Promise(function () {
41
+ return null;
42
+ });
43
+ };
44
+ },
45
+ setUpdate: function setUpdate() {
46
+ return function () {
47
+ return new Promise(function () {
48
+ return null;
49
+ });
50
+ };
51
+ },
52
+ dismiss: function dismiss() {
53
+ return undefined;
54
+ },
55
+ setDismiss: function setDismiss() {
56
+ return function () {
57
+ return undefined;
58
+ };
59
+ }
28
60
  }
29
61
  });
30
62
 
@@ -40,13 +72,49 @@ var SpotlightContextProvider = exports.SpotlightContextProvider = function Spotl
40
72
  _useState4 = (0, _slicedToArray2.default)(_useState3, 2),
41
73
  headingId = _useState4[0],
42
74
  setHeadingId = _useState4[1];
75
+ var _useState5 = (0, _react.useState)(function () {
76
+ return /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
77
+ return _regenerator.default.wrap(function _callee$(_context) {
78
+ while (1) switch (_context.prev = _context.next) {
79
+ case 0:
80
+ return _context.abrupt("return", undefined);
81
+ case 1:
82
+ case "end":
83
+ return _context.stop();
84
+ }
85
+ }, _callee);
86
+ }));
87
+ }),
88
+ _useState6 = (0, _slicedToArray2.default)(_useState5, 2),
89
+ update = _useState6[0],
90
+ setUpdate = _useState6[1];
91
+ var _useState7 = (0, _react.useState)(),
92
+ _useState8 = (0, _slicedToArray2.default)(_useState7, 2),
93
+ ref = _useState8[0],
94
+ setRef = _useState8[1];
95
+ var _useState9 = (0, _react.useState)(function () {
96
+ return undefined;
97
+ }),
98
+ _useState0 = (0, _slicedToArray2.default)(_useState9, 2),
99
+ dismiss = _useState0[0],
100
+ setDismiss = _useState0[1];
43
101
  return /*#__PURE__*/React.createElement(SpotlightContext.Provider, {
44
102
  value: {
45
- placement: placement,
46
- setPlacement: setPlacement,
103
+ card: {
104
+ placement: placement,
105
+ setPlacement: setPlacement
106
+ },
47
107
  heading: {
48
108
  id: headingId,
49
109
  setId: setHeadingId
110
+ },
111
+ popoverContent: {
112
+ ref: ref,
113
+ setRef: setRef,
114
+ update: update,
115
+ setUpdate: setUpdate,
116
+ dismiss: dismiss,
117
+ setDismiss: setDismiss
50
118
  }
51
119
  }
52
120
  }, children);
package/dist/cjs/index.js CHANGED
@@ -99,6 +99,12 @@ Object.defineProperty(exports, "SpotlightStepCount", {
99
99
  return _stepCount.SpotlightStepCount;
100
100
  }
101
101
  });
102
+ Object.defineProperty(exports, "UNSAFE_UpdateOnChange", {
103
+ enumerable: true,
104
+ get: function get() {
105
+ return _UNSAFE_updateOnChange.UNSAFE_UpdateOnChange;
106
+ }
107
+ });
102
108
  var _card = require("./ui/card");
103
109
  var _body = require("./ui/body");
104
110
  var _header = require("./ui/header");
@@ -114,4 +120,5 @@ var _showMoreControl = require("./ui/show-more-control");
114
120
  var _media = require("./ui/media");
115
121
  var _popoverProvider = require("./ui/popover-provider");
116
122
  var _popoverContent = require("./ui/popover-content");
117
- var _popoverTarget = require("./ui/popover-target");
123
+ var _popoverTarget = require("./ui/popover-target");
124
+ var _UNSAFE_updateOnChange = require("./ui/UNSAFE_update-on-change");
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.UNSAFE_UpdateOnChange = void 0;
7
+ var _react = require("react");
8
+ var _browserApis = require("@atlaskit/browser-apis");
9
+ var _context = require("../../controllers/context");
10
+ var defaultOptions = {
11
+ childList: true,
12
+ subtree: true
13
+ };
14
+ var UNSAFE_UpdateOnChange = exports.UNSAFE_UpdateOnChange = function UNSAFE_UpdateOnChange(_ref) {
15
+ var _ref$selectors = _ref.selectors,
16
+ selectors = _ref$selectors === void 0 ? ['body'] : _ref$selectors,
17
+ _ref$options = _ref.options,
18
+ options = _ref$options === void 0 ? defaultOptions : _ref$options;
19
+ var _useContext = (0, _react.useContext)(_context.SpotlightContext),
20
+ popoverContent = _useContext.popoverContent;
21
+ var update = popoverContent.update;
22
+ (0, _react.useEffect)(function () {
23
+ if (!update || selectors.length === 0) {
24
+ return;
25
+ }
26
+ var doc = (0, _browserApis.getDocument)();
27
+ if (!doc) {
28
+ return;
29
+ }
30
+ var elements = new Set();
31
+ selectors.forEach(function (selector) {
32
+ var element = doc.querySelector(selector);
33
+ if (!element) {
34
+ return;
35
+ }
36
+ elements.add(element);
37
+ });
38
+ if (elements.size === 0) {
39
+ return;
40
+ }
41
+ var observers = [];
42
+ elements.forEach(function (element) {
43
+ var observer = new MutationObserver(function (mutations) {
44
+ if (mutations.length === 0) {
45
+ return;
46
+ }
47
+ update();
48
+ });
49
+ observer.observe(element, options);
50
+ observers.push(observer);
51
+ });
52
+ return function () {
53
+ observers.forEach(function (observer) {
54
+ return observer.disconnect();
55
+ });
56
+ };
57
+ }, [selectors, options, update]);
58
+ return null;
59
+ };
@@ -34,10 +34,10 @@ var styles = {
34
34
  var Caret = exports.Caret = /*#__PURE__*/(0, _react.forwardRef)(function (_ref, ref) {
35
35
  var testId = _ref.testId;
36
36
  var _useContext = (0, _react.useContext)(_context.SpotlightContext),
37
- placement = _useContext.placement;
37
+ card = _useContext.card;
38
38
  return /*#__PURE__*/React.createElement("div", {
39
39
  "data-testid": testId,
40
40
  ref: ref,
41
- className: (0, _runtime.ax)([styles.root, styles[placement]])
41
+ className: (0, _runtime.ax)([styles.root, styles[card.placement]])
42
42
  });
43
43
  });
@@ -41,13 +41,13 @@ var SpotlightCard = exports.SpotlightCard = /*#__PURE__*/(0, _react.forwardRef)(
41
41
  var children = _ref.children,
42
42
  testId = _ref.testId;
43
43
  var _useContext = (0, _react.useContext)(_context.SpotlightContext),
44
- placement = _useContext.placement;
44
+ card = _useContext.card;
45
45
  return /*#__PURE__*/React.createElement("div", {
46
46
  "data-testid": testId,
47
47
  ref: ref,
48
48
  className: (0, _runtime.ax)([styles.root])
49
49
  }, /*#__PURE__*/React.createElement(_caret.Caret, null), /*#__PURE__*/React.createElement(_compiled.Box, {
50
50
  backgroundColor: "color.background.neutral.bold",
51
- xcss: (0, _css.cx)(styles.card, placementStyles[placement])
51
+ xcss: (0, _css.cx)(styles.card, placementStyles[card.placement])
52
52
  }, children));
53
53
  });
@@ -1,6 +1,7 @@
1
1
  /* index.tsx generated by @compiled/babel-plugin v0.38.1 */
2
2
  "use strict";
3
3
 
4
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
5
  var _typeof = require("@babel/runtime/helpers/typeof");
5
6
  Object.defineProperty(exports, "__esModule", {
6
7
  value: true
@@ -10,8 +11,11 @@ require("./index.compiled.css");
10
11
  var _react = _interopRequireWildcard(require("react"));
11
12
  var React = _react;
12
13
  var _runtime = require("@compiled/react/runtime");
14
+ var _mergeRefs = _interopRequireDefault(require("@atlaskit/ds-lib/merge-refs"));
13
15
  var _popper = require("@atlaskit/popper");
14
16
  var _context = require("../../controllers/context");
17
+ var _useFocusWithin = require("../../utils/use-focus-within");
18
+ var _useOnEscape = require("../../utils/use-on-escape");
15
19
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
16
20
  var styles = {
17
21
  root: "_1pby1fw0"
@@ -22,7 +26,7 @@ var styles = {
22
26
  * the caret extending beyond the bounding box (by roughly 2px). So, apply an offset to ensure
23
27
  * the caret points to the very edge of the target element.
24
28
  *
25
- * Note: `@atlaskit/popper` maps the offset to to the placement, so we only need to define `[0, 2]` and
29
+ * Note: `@atlaskit/popper` maps the offset to the placement, so we only need to define `[0, 2]` and
26
30
  * the offset will get correctly rotated depending on the placement.
27
31
  */
28
32
  var offset = [0, 2];
@@ -55,27 +59,57 @@ var PopoverContent = exports.PopoverContent = function PopoverContent(_ref) {
55
59
  placement = _ref.placement,
56
60
  _ref$isVisible = _ref.isVisible,
57
61
  isVisible = _ref$isVisible === void 0 ? true : _ref$isVisible,
62
+ dismiss = _ref.dismiss,
58
63
  testId = _ref.testId;
64
+ var updateRef = (0, _react.useRef)(function () {
65
+ return new Promise(function () {
66
+ return undefined;
67
+ });
68
+ });
69
+ var ref = (0, _react.useRef)();
59
70
  var _useContext = (0, _react.useContext)(_context.SpotlightContext),
60
- setPlacement = _useContext.setPlacement,
61
- heading = _useContext.heading;
71
+ heading = _useContext.heading,
72
+ popoverContent = _useContext.popoverContent,
73
+ card = _useContext.card;
74
+ var focusWithin = (0, _useFocusWithin.useFocusWithin)(popoverContent.ref);
75
+ (0, _react.useEffect)(function () {
76
+ popoverContent.setRef(ref);
77
+ }, [ref, popoverContent]);
78
+ (0, _react.useEffect)(function () {
79
+ card.setPlacement(placement);
80
+ }, [placement, card]);
62
81
  (0, _react.useEffect)(function () {
63
- setPlacement(placement);
64
- }, [placement, setPlacement]);
82
+ if (updateRef.current) {
83
+ popoverContent.setUpdate(function () {
84
+ return updateRef.current;
85
+ });
86
+ }
87
+ }, [popoverContent]);
88
+ (0, _useOnEscape.useOnEscape)(function (event) {
89
+ if (!focusWithin) {
90
+ return;
91
+ }
92
+ if (!dismiss) {
93
+ return;
94
+ }
95
+ dismiss(event);
96
+ });
65
97
  return /*#__PURE__*/React.createElement(_popper.Popper, {
66
98
  offset: offset,
67
99
  placement: popperPlacementMap[placement]
68
100
  }, function (_ref2) {
69
- var ref = _ref2.ref,
70
- style = _ref2.style;
101
+ var localRef = _ref2.ref,
102
+ style = _ref2.style,
103
+ update = _ref2.update;
71
104
  if (!isVisible) {
72
105
  return;
73
106
  }
107
+ updateRef.current = update;
74
108
  return /*#__PURE__*/React.createElement("div", {
75
109
  role: "dialog",
76
110
  "data-testid": testId,
77
111
  "aria-labelledby": heading.id,
78
- ref: ref
112
+ ref: (0, _mergeRefs.default)([ref, localRef])
79
113
  // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
80
114
  ,
81
115
  style: style,
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.useFocusWithin = void 0;
8
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
9
+ var _react = require("react");
10
+ var _bindEventListener = require("bind-event-listener");
11
+ var _browserApis = require("@atlaskit/browser-apis");
12
+ var useFocusWithin = exports.useFocusWithin = function useFocusWithin(ref) {
13
+ var _useState = (0, _react.useState)(null),
14
+ _useState2 = (0, _slicedToArray2.default)(_useState, 2),
15
+ active = _useState2[0],
16
+ setActive = _useState2[1];
17
+ var updateFocusedElement = (0, _react.useCallback)(function () {
18
+ var doc = (0, _browserApis.getDocument)();
19
+ var activeElement = (doc === null || doc === void 0 ? void 0 : doc.activeElement) || null;
20
+ if (!ref || !ref.current) {
21
+ setActive(null);
22
+ return;
23
+ }
24
+ if (!activeElement) {
25
+ setActive(null);
26
+ return;
27
+ }
28
+
29
+ // Check if the focused element is within the ref element
30
+ if (!ref.current.contains(activeElement)) {
31
+ setActive(null);
32
+ return;
33
+ }
34
+ setActive(activeElement);
35
+ }, [ref]);
36
+ (0, _react.useEffect)(function () {
37
+ var doc = (0, _browserApis.getDocument)();
38
+ if (!doc) {
39
+ return;
40
+ }
41
+ updateFocusedElement();
42
+ var unbindFocusIn = (0, _bindEventListener.bind)(doc, {
43
+ type: 'focusin',
44
+ listener: updateFocusedElement
45
+ });
46
+ return function () {
47
+ unbindFocusIn();
48
+ };
49
+ }, [updateFocusedElement]);
50
+ return active;
51
+ };
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useOnEscape = void 0;
7
+ var _react = require("react");
8
+ var _bindEventListener = require("bind-event-listener");
9
+ var _browserApis = require("@atlaskit/browser-apis");
10
+ var onKeyDown = function onKeyDown(event, _ref) {
11
+ var onEscape = _ref.onEscape;
12
+ switch (event.key) {
13
+ case 'Escape':
14
+ onEscape();
15
+ break;
16
+ default:
17
+ break;
18
+ }
19
+ };
20
+ var useOnEscape = exports.useOnEscape = function useOnEscape(_onEscape) {
21
+ (0, _react.useEffect)(function () {
22
+ var doc = (0, _browserApis.getDocument)();
23
+ if (!doc) {
24
+ return;
25
+ }
26
+ var unbindFocusIn = (0, _bindEventListener.bind)(doc, {
27
+ type: 'keydown',
28
+ listener: function listener(event) {
29
+ return onKeyDown(event, {
30
+ onEscape: function onEscape() {
31
+ return _onEscape(event);
32
+ }
33
+ });
34
+ }
35
+ });
36
+ return function () {
37
+ unbindFocusIn();
38
+ };
39
+ }, [_onEscape]);
40
+ };
@@ -7,11 +7,21 @@ import { createContext, useId, useState } from 'react';
7
7
 
8
8
  // eslint-disable-next-line @repo/internal/react/require-jsdoc
9
9
  export const SpotlightContext = /*#__PURE__*/createContext({
10
- placement: 'bottom-end',
11
- setPlacement: () => undefined,
10
+ card: {
11
+ placement: 'bottom-end',
12
+ setPlacement: () => undefined
13
+ },
12
14
  heading: {
13
15
  id: '',
14
16
  setId: () => undefined
17
+ },
18
+ popoverContent: {
19
+ ref: undefined,
20
+ setRef: () => undefined,
21
+ update: () => () => new Promise(() => null),
22
+ setUpdate: () => () => new Promise(() => null),
23
+ dismiss: () => undefined,
24
+ setDismiss: () => () => undefined
15
25
  }
16
26
  });
17
27
 
@@ -22,13 +32,26 @@ export const SpotlightContextProvider = ({
22
32
  const id = useId();
23
33
  const [placement, setPlacement] = useState('bottom-end');
24
34
  const [headingId, setHeadingId] = useState(`${id}-heading`);
35
+ const [update, setUpdate] = useState(() => async () => undefined);
36
+ const [ref, setRef] = useState();
37
+ const [dismiss, setDismiss] = useState(() => undefined);
25
38
  return /*#__PURE__*/React.createElement(SpotlightContext.Provider, {
26
39
  value: {
27
- placement,
28
- setPlacement,
40
+ card: {
41
+ placement,
42
+ setPlacement
43
+ },
29
44
  heading: {
30
45
  id: headingId,
31
46
  setId: setHeadingId
47
+ },
48
+ popoverContent: {
49
+ ref,
50
+ setRef,
51
+ update,
52
+ setUpdate,
53
+ dismiss,
54
+ setDismiss
32
55
  }
33
56
  }
34
57
  }, children);
@@ -13,4 +13,5 @@ export { SpotlightShowMoreControl } from './ui/show-more-control';
13
13
  export { SpotlightMedia } from './ui/media';
14
14
  export { PopoverProvider } from './ui/popover-provider';
15
15
  export { PopoverContent } from './ui/popover-content';
16
- export { PopoverTarget } from './ui/popover-target';
16
+ export { PopoverTarget } from './ui/popover-target';
17
+ export { UNSAFE_UpdateOnChange } from './ui/UNSAFE_update-on-change';
@@ -0,0 +1,53 @@
1
+ import { useContext, useEffect } from 'react';
2
+ import { getDocument } from '@atlaskit/browser-apis';
3
+ import { SpotlightContext } from '../../controllers/context';
4
+ const defaultOptions = {
5
+ childList: true,
6
+ subtree: true
7
+ };
8
+ export const UNSAFE_UpdateOnChange = ({
9
+ selectors = ['body'],
10
+ options = defaultOptions
11
+ }) => {
12
+ const {
13
+ popoverContent
14
+ } = useContext(SpotlightContext);
15
+ const {
16
+ update
17
+ } = popoverContent;
18
+ useEffect(() => {
19
+ if (!update || selectors.length === 0) {
20
+ return;
21
+ }
22
+ const doc = getDocument();
23
+ if (!doc) {
24
+ return;
25
+ }
26
+ const elements = new Set();
27
+ selectors.forEach(selector => {
28
+ const element = doc.querySelector(selector);
29
+ if (!element) {
30
+ return;
31
+ }
32
+ elements.add(element);
33
+ });
34
+ if (elements.size === 0) {
35
+ return;
36
+ }
37
+ const observers = [];
38
+ elements.forEach(element => {
39
+ const observer = new MutationObserver(mutations => {
40
+ if (mutations.length === 0) {
41
+ return;
42
+ }
43
+ update();
44
+ });
45
+ observer.observe(element, options);
46
+ observers.push(observer);
47
+ });
48
+ return () => {
49
+ observers.forEach(observer => observer.disconnect());
50
+ };
51
+ }, [selectors, options, update]);
52
+ return null;
53
+ };
@@ -27,11 +27,11 @@ export const Caret = /*#__PURE__*/forwardRef(({
27
27
  testId
28
28
  }, ref) => {
29
29
  const {
30
- placement
30
+ card
31
31
  } = useContext(SpotlightContext);
32
32
  return /*#__PURE__*/React.createElement("div", {
33
33
  "data-testid": testId,
34
34
  ref: ref,
35
- className: ax([styles.root, styles[placement]])
35
+ className: ax([styles.root, styles[card.placement]])
36
36
  });
37
37
  });
@@ -34,7 +34,7 @@ export const SpotlightCard = /*#__PURE__*/forwardRef(({
34
34
  testId
35
35
  }, ref) => {
36
36
  const {
37
- placement
37
+ card
38
38
  } = useContext(SpotlightContext);
39
39
  return /*#__PURE__*/React.createElement("div", {
40
40
  "data-testid": testId,
@@ -42,6 +42,6 @@ export const SpotlightCard = /*#__PURE__*/forwardRef(({
42
42
  className: ax([styles.root])
43
43
  }, /*#__PURE__*/React.createElement(Caret, null), /*#__PURE__*/React.createElement(Box, {
44
44
  backgroundColor: "color.background.neutral.bold",
45
- xcss: cx(styles.card, placementStyles[placement])
45
+ xcss: cx(styles.card, placementStyles[card.placement])
46
46
  }, children));
47
47
  });
@@ -2,9 +2,12 @@
2
2
  import "./index.compiled.css";
3
3
  import * as React from 'react';
4
4
  import { ax, ix } from "@compiled/react/runtime";
5
- import { useContext, useEffect } from 'react';
5
+ import { useContext, useEffect, useRef } from 'react';
6
+ import mergeRefs from '@atlaskit/ds-lib/merge-refs';
6
7
  import { Popper } from '@atlaskit/popper';
7
8
  import { SpotlightContext } from '../../controllers/context';
9
+ import { useFocusWithin } from '../../utils/use-focus-within';
10
+ import { useOnEscape } from '../../utils/use-on-escape';
8
11
  const styles = {
9
12
  root: "_1pby1fw0"
10
13
  };
@@ -14,7 +17,7 @@ const styles = {
14
17
  * the caret extending beyond the bounding box (by roughly 2px). So, apply an offset to ensure
15
18
  * the caret points to the very edge of the target element.
16
19
  *
17
- * Note: `@atlaskit/popper` maps the offset to to the placement, so we only need to define `[0, 2]` and
20
+ * Note: `@atlaskit/popper` maps the offset to the placement, so we only need to define `[0, 2]` and
18
21
  * the offset will get correctly rotated depending on the placement.
19
22
  */
20
23
  const offset = [0, 2];
@@ -46,30 +49,54 @@ export const PopoverContent = ({
46
49
  children,
47
50
  placement,
48
51
  isVisible = true,
52
+ dismiss,
49
53
  testId
50
54
  }) => {
55
+ const updateRef = useRef(() => new Promise(() => undefined));
56
+ const ref = useRef();
51
57
  const {
52
- setPlacement,
53
- heading
58
+ heading,
59
+ popoverContent,
60
+ card
54
61
  } = useContext(SpotlightContext);
62
+ const focusWithin = useFocusWithin(popoverContent.ref);
55
63
  useEffect(() => {
56
- setPlacement(placement);
57
- }, [placement, setPlacement]);
64
+ popoverContent.setRef(ref);
65
+ }, [ref, popoverContent]);
66
+ useEffect(() => {
67
+ card.setPlacement(placement);
68
+ }, [placement, card]);
69
+ useEffect(() => {
70
+ if (updateRef.current) {
71
+ popoverContent.setUpdate(() => updateRef.current);
72
+ }
73
+ }, [popoverContent]);
74
+ useOnEscape(event => {
75
+ if (!focusWithin) {
76
+ return;
77
+ }
78
+ if (!dismiss) {
79
+ return;
80
+ }
81
+ dismiss(event);
82
+ });
58
83
  return /*#__PURE__*/React.createElement(Popper, {
59
84
  offset: offset,
60
85
  placement: popperPlacementMap[placement]
61
86
  }, ({
62
- ref,
63
- style
87
+ ref: localRef,
88
+ style,
89
+ update
64
90
  }) => {
65
91
  if (!isVisible) {
66
92
  return;
67
93
  }
94
+ updateRef.current = update;
68
95
  return /*#__PURE__*/React.createElement("div", {
69
96
  role: "dialog",
70
97
  "data-testid": testId,
71
98
  "aria-labelledby": heading.id,
72
- ref: ref
99
+ ref: mergeRefs([ref, localRef])
73
100
  // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
74
101
  ,
75
102
  style: style,
@@ -0,0 +1,40 @@
1
+ import { useCallback, useEffect, useState } from 'react';
2
+ import { bind } from 'bind-event-listener';
3
+ import { getDocument } from '@atlaskit/browser-apis';
4
+ export const useFocusWithin = ref => {
5
+ const [active, setActive] = useState(null);
6
+ const updateFocusedElement = useCallback(() => {
7
+ const doc = getDocument();
8
+ const activeElement = (doc === null || doc === void 0 ? void 0 : doc.activeElement) || null;
9
+ if (!ref || !ref.current) {
10
+ setActive(null);
11
+ return;
12
+ }
13
+ if (!activeElement) {
14
+ setActive(null);
15
+ return;
16
+ }
17
+
18
+ // Check if the focused element is within the ref element
19
+ if (!ref.current.contains(activeElement)) {
20
+ setActive(null);
21
+ return;
22
+ }
23
+ setActive(activeElement);
24
+ }, [ref]);
25
+ useEffect(() => {
26
+ const doc = getDocument();
27
+ if (!doc) {
28
+ return;
29
+ }
30
+ updateFocusedElement();
31
+ const unbindFocusIn = bind(doc, {
32
+ type: 'focusin',
33
+ listener: updateFocusedElement
34
+ });
35
+ return () => {
36
+ unbindFocusIn();
37
+ };
38
+ }, [updateFocusedElement]);
39
+ return active;
40
+ };
@@ -0,0 +1,31 @@
1
+ import { useEffect } from 'react';
2
+ import { bind } from 'bind-event-listener';
3
+ import { getDocument } from '@atlaskit/browser-apis';
4
+ const onKeyDown = (event, {
5
+ onEscape
6
+ }) => {
7
+ switch (event.key) {
8
+ case 'Escape':
9
+ onEscape();
10
+ break;
11
+ default:
12
+ break;
13
+ }
14
+ };
15
+ export const useOnEscape = onEscape => {
16
+ useEffect(() => {
17
+ const doc = getDocument();
18
+ if (!doc) {
19
+ return;
20
+ }
21
+ const unbindFocusIn = bind(doc, {
22
+ type: 'keydown',
23
+ listener: event => onKeyDown(event, {
24
+ onEscape: () => onEscape(event)
25
+ })
26
+ });
27
+ return () => {
28
+ unbindFocusIn();
29
+ };
30
+ }, [onEscape]);
31
+ };
@@ -1,22 +1,54 @@
1
1
  /* context.tsx generated by @compiled/babel-plugin v0.38.1 */
2
+ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
3
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
3
4
  import * as React from 'react';
4
5
  import { ax, ix } from "@compiled/react/runtime";
6
+ import _regeneratorRuntime from "@babel/runtime/regenerator";
5
7
  import { createContext, useId, useState } from 'react';
6
8
 
7
9
  // eslint-disable-next-line @repo/internal/react/consistent-types-definitions
8
10
 
9
11
  // eslint-disable-next-line @repo/internal/react/require-jsdoc
10
12
  export var SpotlightContext = /*#__PURE__*/createContext({
11
- placement: 'bottom-end',
12
- setPlacement: function setPlacement() {
13
- return undefined;
13
+ card: {
14
+ placement: 'bottom-end',
15
+ setPlacement: function setPlacement() {
16
+ return undefined;
17
+ }
14
18
  },
15
19
  heading: {
16
20
  id: '',
17
21
  setId: function setId() {
18
22
  return undefined;
19
23
  }
24
+ },
25
+ popoverContent: {
26
+ ref: undefined,
27
+ setRef: function setRef() {
28
+ return undefined;
29
+ },
30
+ update: function update() {
31
+ return function () {
32
+ return new Promise(function () {
33
+ return null;
34
+ });
35
+ };
36
+ },
37
+ setUpdate: function setUpdate() {
38
+ return function () {
39
+ return new Promise(function () {
40
+ return null;
41
+ });
42
+ };
43
+ },
44
+ dismiss: function dismiss() {
45
+ return undefined;
46
+ },
47
+ setDismiss: function setDismiss() {
48
+ return function () {
49
+ return undefined;
50
+ };
51
+ }
20
52
  }
21
53
  });
22
54
 
@@ -32,13 +64,49 @@ export var SpotlightContextProvider = function SpotlightContextProvider(_ref) {
32
64
  _useState4 = _slicedToArray(_useState3, 2),
33
65
  headingId = _useState4[0],
34
66
  setHeadingId = _useState4[1];
67
+ var _useState5 = useState(function () {
68
+ return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
69
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
70
+ while (1) switch (_context.prev = _context.next) {
71
+ case 0:
72
+ return _context.abrupt("return", undefined);
73
+ case 1:
74
+ case "end":
75
+ return _context.stop();
76
+ }
77
+ }, _callee);
78
+ }));
79
+ }),
80
+ _useState6 = _slicedToArray(_useState5, 2),
81
+ update = _useState6[0],
82
+ setUpdate = _useState6[1];
83
+ var _useState7 = useState(),
84
+ _useState8 = _slicedToArray(_useState7, 2),
85
+ ref = _useState8[0],
86
+ setRef = _useState8[1];
87
+ var _useState9 = useState(function () {
88
+ return undefined;
89
+ }),
90
+ _useState0 = _slicedToArray(_useState9, 2),
91
+ dismiss = _useState0[0],
92
+ setDismiss = _useState0[1];
35
93
  return /*#__PURE__*/React.createElement(SpotlightContext.Provider, {
36
94
  value: {
37
- placement: placement,
38
- setPlacement: setPlacement,
95
+ card: {
96
+ placement: placement,
97
+ setPlacement: setPlacement
98
+ },
39
99
  heading: {
40
100
  id: headingId,
41
101
  setId: setHeadingId
102
+ },
103
+ popoverContent: {
104
+ ref: ref,
105
+ setRef: setRef,
106
+ update: update,
107
+ setUpdate: setUpdate,
108
+ dismiss: dismiss,
109
+ setDismiss: setDismiss
42
110
  }
43
111
  }
44
112
  }, children);
package/dist/esm/index.js CHANGED
@@ -13,4 +13,5 @@ export { SpotlightShowMoreControl } from './ui/show-more-control';
13
13
  export { SpotlightMedia } from './ui/media';
14
14
  export { PopoverProvider } from './ui/popover-provider';
15
15
  export { PopoverContent } from './ui/popover-content';
16
- export { PopoverTarget } from './ui/popover-target';
16
+ export { PopoverTarget } from './ui/popover-target';
17
+ export { UNSAFE_UpdateOnChange } from './ui/UNSAFE_update-on-change';
@@ -0,0 +1,53 @@
1
+ import { useContext, useEffect } from 'react';
2
+ import { getDocument } from '@atlaskit/browser-apis';
3
+ import { SpotlightContext } from '../../controllers/context';
4
+ var defaultOptions = {
5
+ childList: true,
6
+ subtree: true
7
+ };
8
+ export var UNSAFE_UpdateOnChange = function UNSAFE_UpdateOnChange(_ref) {
9
+ var _ref$selectors = _ref.selectors,
10
+ selectors = _ref$selectors === void 0 ? ['body'] : _ref$selectors,
11
+ _ref$options = _ref.options,
12
+ options = _ref$options === void 0 ? defaultOptions : _ref$options;
13
+ var _useContext = useContext(SpotlightContext),
14
+ popoverContent = _useContext.popoverContent;
15
+ var update = popoverContent.update;
16
+ useEffect(function () {
17
+ if (!update || selectors.length === 0) {
18
+ return;
19
+ }
20
+ var doc = getDocument();
21
+ if (!doc) {
22
+ return;
23
+ }
24
+ var elements = new Set();
25
+ selectors.forEach(function (selector) {
26
+ var element = doc.querySelector(selector);
27
+ if (!element) {
28
+ return;
29
+ }
30
+ elements.add(element);
31
+ });
32
+ if (elements.size === 0) {
33
+ return;
34
+ }
35
+ var observers = [];
36
+ elements.forEach(function (element) {
37
+ var observer = new MutationObserver(function (mutations) {
38
+ if (mutations.length === 0) {
39
+ return;
40
+ }
41
+ update();
42
+ });
43
+ observer.observe(element, options);
44
+ observers.push(observer);
45
+ });
46
+ return function () {
47
+ observers.forEach(function (observer) {
48
+ return observer.disconnect();
49
+ });
50
+ };
51
+ }, [selectors, options, update]);
52
+ return null;
53
+ };
@@ -26,10 +26,10 @@ var styles = {
26
26
  export var Caret = /*#__PURE__*/forwardRef(function (_ref, ref) {
27
27
  var testId = _ref.testId;
28
28
  var _useContext = useContext(SpotlightContext),
29
- placement = _useContext.placement;
29
+ card = _useContext.card;
30
30
  return /*#__PURE__*/React.createElement("div", {
31
31
  "data-testid": testId,
32
32
  ref: ref,
33
- className: ax([styles.root, styles[placement]])
33
+ className: ax([styles.root, styles[card.placement]])
34
34
  });
35
35
  });
@@ -33,13 +33,13 @@ export var SpotlightCard = /*#__PURE__*/forwardRef(function (_ref, ref) {
33
33
  var children = _ref.children,
34
34
  testId = _ref.testId;
35
35
  var _useContext = useContext(SpotlightContext),
36
- placement = _useContext.placement;
36
+ card = _useContext.card;
37
37
  return /*#__PURE__*/React.createElement("div", {
38
38
  "data-testid": testId,
39
39
  ref: ref,
40
40
  className: ax([styles.root])
41
41
  }, /*#__PURE__*/React.createElement(Caret, null), /*#__PURE__*/React.createElement(Box, {
42
42
  backgroundColor: "color.background.neutral.bold",
43
- xcss: cx(styles.card, placementStyles[placement])
43
+ xcss: cx(styles.card, placementStyles[card.placement])
44
44
  }, children));
45
45
  });
@@ -2,9 +2,12 @@
2
2
  import "./index.compiled.css";
3
3
  import * as React from 'react';
4
4
  import { ax, ix } from "@compiled/react/runtime";
5
- import { useContext, useEffect } from 'react';
5
+ import { useContext, useEffect, useRef } from 'react';
6
+ import mergeRefs from '@atlaskit/ds-lib/merge-refs';
6
7
  import { Popper } from '@atlaskit/popper';
7
8
  import { SpotlightContext } from '../../controllers/context';
9
+ import { useFocusWithin } from '../../utils/use-focus-within';
10
+ import { useOnEscape } from '../../utils/use-on-escape';
8
11
  var styles = {
9
12
  root: "_1pby1fw0"
10
13
  };
@@ -14,7 +17,7 @@ var styles = {
14
17
  * the caret extending beyond the bounding box (by roughly 2px). So, apply an offset to ensure
15
18
  * the caret points to the very edge of the target element.
16
19
  *
17
- * Note: `@atlaskit/popper` maps the offset to to the placement, so we only need to define `[0, 2]` and
20
+ * Note: `@atlaskit/popper` maps the offset to the placement, so we only need to define `[0, 2]` and
18
21
  * the offset will get correctly rotated depending on the placement.
19
22
  */
20
23
  var offset = [0, 2];
@@ -47,27 +50,57 @@ export var PopoverContent = function PopoverContent(_ref) {
47
50
  placement = _ref.placement,
48
51
  _ref$isVisible = _ref.isVisible,
49
52
  isVisible = _ref$isVisible === void 0 ? true : _ref$isVisible,
53
+ dismiss = _ref.dismiss,
50
54
  testId = _ref.testId;
55
+ var updateRef = useRef(function () {
56
+ return new Promise(function () {
57
+ return undefined;
58
+ });
59
+ });
60
+ var ref = useRef();
51
61
  var _useContext = useContext(SpotlightContext),
52
- setPlacement = _useContext.setPlacement,
53
- heading = _useContext.heading;
62
+ heading = _useContext.heading,
63
+ popoverContent = _useContext.popoverContent,
64
+ card = _useContext.card;
65
+ var focusWithin = useFocusWithin(popoverContent.ref);
66
+ useEffect(function () {
67
+ popoverContent.setRef(ref);
68
+ }, [ref, popoverContent]);
69
+ useEffect(function () {
70
+ card.setPlacement(placement);
71
+ }, [placement, card]);
54
72
  useEffect(function () {
55
- setPlacement(placement);
56
- }, [placement, setPlacement]);
73
+ if (updateRef.current) {
74
+ popoverContent.setUpdate(function () {
75
+ return updateRef.current;
76
+ });
77
+ }
78
+ }, [popoverContent]);
79
+ useOnEscape(function (event) {
80
+ if (!focusWithin) {
81
+ return;
82
+ }
83
+ if (!dismiss) {
84
+ return;
85
+ }
86
+ dismiss(event);
87
+ });
57
88
  return /*#__PURE__*/React.createElement(Popper, {
58
89
  offset: offset,
59
90
  placement: popperPlacementMap[placement]
60
91
  }, function (_ref2) {
61
- var ref = _ref2.ref,
62
- style = _ref2.style;
92
+ var localRef = _ref2.ref,
93
+ style = _ref2.style,
94
+ update = _ref2.update;
63
95
  if (!isVisible) {
64
96
  return;
65
97
  }
98
+ updateRef.current = update;
66
99
  return /*#__PURE__*/React.createElement("div", {
67
100
  role: "dialog",
68
101
  "data-testid": testId,
69
102
  "aria-labelledby": heading.id,
70
- ref: ref
103
+ ref: mergeRefs([ref, localRef])
71
104
  // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
72
105
  ,
73
106
  style: style,
@@ -0,0 +1,44 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
+ import { useCallback, useEffect, useState } from 'react';
3
+ import { bind } from 'bind-event-listener';
4
+ import { getDocument } from '@atlaskit/browser-apis';
5
+ export var useFocusWithin = function useFocusWithin(ref) {
6
+ var _useState = useState(null),
7
+ _useState2 = _slicedToArray(_useState, 2),
8
+ active = _useState2[0],
9
+ setActive = _useState2[1];
10
+ var updateFocusedElement = useCallback(function () {
11
+ var doc = getDocument();
12
+ var activeElement = (doc === null || doc === void 0 ? void 0 : doc.activeElement) || null;
13
+ if (!ref || !ref.current) {
14
+ setActive(null);
15
+ return;
16
+ }
17
+ if (!activeElement) {
18
+ setActive(null);
19
+ return;
20
+ }
21
+
22
+ // Check if the focused element is within the ref element
23
+ if (!ref.current.contains(activeElement)) {
24
+ setActive(null);
25
+ return;
26
+ }
27
+ setActive(activeElement);
28
+ }, [ref]);
29
+ useEffect(function () {
30
+ var doc = getDocument();
31
+ if (!doc) {
32
+ return;
33
+ }
34
+ updateFocusedElement();
35
+ var unbindFocusIn = bind(doc, {
36
+ type: 'focusin',
37
+ listener: updateFocusedElement
38
+ });
39
+ return function () {
40
+ unbindFocusIn();
41
+ };
42
+ }, [updateFocusedElement]);
43
+ return active;
44
+ };
@@ -0,0 +1,34 @@
1
+ import { useEffect } from 'react';
2
+ import { bind } from 'bind-event-listener';
3
+ import { getDocument } from '@atlaskit/browser-apis';
4
+ var onKeyDown = function onKeyDown(event, _ref) {
5
+ var onEscape = _ref.onEscape;
6
+ switch (event.key) {
7
+ case 'Escape':
8
+ onEscape();
9
+ break;
10
+ default:
11
+ break;
12
+ }
13
+ };
14
+ export var useOnEscape = function useOnEscape(_onEscape) {
15
+ useEffect(function () {
16
+ var doc = getDocument();
17
+ if (!doc) {
18
+ return;
19
+ }
20
+ var unbindFocusIn = bind(doc, {
21
+ type: 'keydown',
22
+ listener: function listener(event) {
23
+ return onKeyDown(event, {
24
+ onEscape: function onEscape() {
25
+ return _onEscape(event);
26
+ }
27
+ });
28
+ }
29
+ });
30
+ return function () {
31
+ unbindFocusIn();
32
+ };
33
+ }, [_onEscape]);
34
+ };
@@ -2,18 +2,27 @@
2
2
  * @jsxRuntime classic
3
3
  * @jsx jsx
4
4
  */
5
- import { type Dispatch, type ReactNode, type SetStateAction } from 'react';
5
+ import { type Dispatch, type MutableRefObject, type ReactNode, type SetStateAction } from 'react';
6
6
  import type { Placement } from '../types';
7
- interface SpotlightContextType {
8
- placement: Placement;
9
- setPlacement: Dispatch<SetStateAction<Placement>>;
7
+ export interface SpotlightContextType {
8
+ card: {
9
+ placement: Placement;
10
+ setPlacement: Dispatch<SetStateAction<Placement>>;
11
+ };
10
12
  heading: {
11
13
  id: string;
12
14
  setId: Dispatch<SetStateAction<string>>;
13
15
  };
16
+ popoverContent: {
17
+ ref: MutableRefObject<HTMLDivElement | undefined> | undefined;
18
+ setRef: Dispatch<SetStateAction<MutableRefObject<HTMLDivElement | undefined> | undefined>>;
19
+ update: () => () => Promise<any>;
20
+ setUpdate: Dispatch<SetStateAction<() => () => Promise<any>>>;
21
+ dismiss: () => void;
22
+ setDismiss: Dispatch<SetStateAction<() => void>>;
23
+ };
14
24
  }
15
25
  export declare const SpotlightContext: import("react").Context<SpotlightContextType>;
16
26
  export declare const SpotlightContextProvider: ({ children }: {
17
27
  children: ReactNode;
18
28
  }) => JSX.Element;
19
- export {};
@@ -15,3 +15,4 @@ export { PopoverProvider } from './ui/popover-provider';
15
15
  export { PopoverContent, type PopoverContentProps } from './ui/popover-content';
16
16
  export { PopoverTarget } from './ui/popover-target';
17
17
  export { type Placement } from './types';
18
+ export { UNSAFE_UpdateOnChange } from './ui/UNSAFE_update-on-change';
@@ -0,0 +1,6 @@
1
+ interface UpdateOnChangeProps {
2
+ selectors?: string[];
3
+ options?: MutationObserverInit;
4
+ }
5
+ export declare const UNSAFE_UpdateOnChange: ({ selectors, options, }: UpdateOnChangeProps) => null;
6
+ export {};
@@ -13,6 +13,7 @@ export interface PopoverContentProps {
13
13
  testId?: string;
14
14
  placement: Placement;
15
15
  isVisible?: boolean;
16
+ dismiss?: (event: KeyboardEvent) => void;
16
17
  children: ReactNode;
17
18
  }
18
19
  /**
@@ -20,4 +21,4 @@ export interface PopoverContentProps {
20
21
  *
21
22
  * A `PopoverContent` is the element that is shown as a popover.
22
23
  */
23
- export declare const PopoverContent: ({ children, placement, isVisible, testId, }: PopoverContentProps) => JSX.Element;
24
+ export declare const PopoverContent: ({ children, placement, isVisible, dismiss, testId, }: PopoverContentProps) => JSX.Element;
@@ -0,0 +1,2 @@
1
+ import { type MutableRefObject } from 'react';
2
+ export declare const useFocusWithin: (ref: MutableRefObject<HTMLDivElement | undefined> | undefined) => Element | null;
@@ -0,0 +1 @@
1
+ export declare const useOnEscape: (onEscape: (event: KeyboardEvent) => void) => void;
@@ -2,18 +2,27 @@
2
2
  * @jsxRuntime classic
3
3
  * @jsx jsx
4
4
  */
5
- import { type Dispatch, type ReactNode, type SetStateAction } from 'react';
5
+ import { type Dispatch, type MutableRefObject, type ReactNode, type SetStateAction } from 'react';
6
6
  import type { Placement } from '../types';
7
- interface SpotlightContextType {
8
- placement: Placement;
9
- setPlacement: Dispatch<SetStateAction<Placement>>;
7
+ export interface SpotlightContextType {
8
+ card: {
9
+ placement: Placement;
10
+ setPlacement: Dispatch<SetStateAction<Placement>>;
11
+ };
10
12
  heading: {
11
13
  id: string;
12
14
  setId: Dispatch<SetStateAction<string>>;
13
15
  };
16
+ popoverContent: {
17
+ ref: MutableRefObject<HTMLDivElement | undefined> | undefined;
18
+ setRef: Dispatch<SetStateAction<MutableRefObject<HTMLDivElement | undefined> | undefined>>;
19
+ update: () => () => Promise<any>;
20
+ setUpdate: Dispatch<SetStateAction<() => () => Promise<any>>>;
21
+ dismiss: () => void;
22
+ setDismiss: Dispatch<SetStateAction<() => void>>;
23
+ };
14
24
  }
15
25
  export declare const SpotlightContext: import("react").Context<SpotlightContextType>;
16
26
  export declare const SpotlightContextProvider: ({ children }: {
17
27
  children: ReactNode;
18
28
  }) => JSX.Element;
19
- export {};
@@ -15,3 +15,4 @@ export { PopoverProvider } from './ui/popover-provider';
15
15
  export { PopoverContent, type PopoverContentProps } from './ui/popover-content';
16
16
  export { PopoverTarget } from './ui/popover-target';
17
17
  export { type Placement } from './types';
18
+ export { UNSAFE_UpdateOnChange } from './ui/UNSAFE_update-on-change';
@@ -0,0 +1,6 @@
1
+ interface UpdateOnChangeProps {
2
+ selectors?: string[];
3
+ options?: MutationObserverInit;
4
+ }
5
+ export declare const UNSAFE_UpdateOnChange: ({ selectors, options, }: UpdateOnChangeProps) => null;
6
+ export {};
@@ -13,6 +13,7 @@ export interface PopoverContentProps {
13
13
  testId?: string;
14
14
  placement: Placement;
15
15
  isVisible?: boolean;
16
+ dismiss?: (event: KeyboardEvent) => void;
16
17
  children: ReactNode;
17
18
  }
18
19
  /**
@@ -20,4 +21,4 @@ export interface PopoverContentProps {
20
21
  *
21
22
  * A `PopoverContent` is the element that is shown as a popover.
22
23
  */
23
- export declare const PopoverContent: ({ children, placement, isVisible, testId, }: PopoverContentProps) => JSX.Element;
24
+ export declare const PopoverContent: ({ children, placement, isVisible, dismiss, testId, }: PopoverContentProps) => JSX.Element;
@@ -0,0 +1,2 @@
1
+ import { type MutableRefObject } from 'react';
2
+ export declare const useFocusWithin: (ref: MutableRefObject<HTMLDivElement | undefined> | undefined) => Element | null;
@@ -0,0 +1 @@
1
+ export declare const useOnEscape: (onEscape: (event: KeyboardEvent) => void) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/spotlight",
3
- "version": "0.4.1",
3
+ "version": "0.5.1",
4
4
  "description": "A spotlight introduces users to various points of interest across Atlassian through focused messages or multi-step tours.",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -26,17 +26,20 @@
26
26
  ],
27
27
  "atlaskit:src": "src/index.tsx",
28
28
  "dependencies": {
29
- "@atlaskit/button": "^23.4.0",
29
+ "@atlaskit/browser-apis": "^0.0.1",
30
+ "@atlaskit/button": "^23.5.0",
30
31
  "@atlaskit/css": "^0.14.0",
32
+ "@atlaskit/ds-lib": "^5.1.0",
31
33
  "@atlaskit/heading": "^5.2.0",
32
- "@atlaskit/icon": "^28.3.0",
34
+ "@atlaskit/icon": "^28.5.0",
33
35
  "@atlaskit/image": "^3.0.0",
34
36
  "@atlaskit/popper": "^7.1.0",
35
37
  "@atlaskit/primitives": "^14.15.0",
36
38
  "@atlaskit/tokens": "^6.4.0",
37
39
  "@atlaskit/visually-hidden": "^3.0.0",
38
40
  "@babel/runtime": "^7.0.0",
39
- "@compiled/react": "^0.18.3"
41
+ "@compiled/react": "^0.18.3",
42
+ "bind-event-listener": "^3.0.0"
40
43
  },
41
44
  "peerDependencies": {
42
45
  "react": "^18.2.0"