@atlassian/clientside-extensions-components 4.0.2 → 5.1.0-5a180d69-mdyn784a

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 (95) hide show
  1. package/dist/cjs/ExtensionPoint.js +1 -1
  2. package/dist/cjs/ExtensionPoint.js.map +1 -1
  3. package/dist/cjs/ExtensionPointInfo.js +27 -20
  4. package/dist/cjs/ExtensionPointInfo.js.map +1 -1
  5. package/dist/cjs/ExtensionsObservable.js +1 -1
  6. package/dist/cjs/ExtensionsObservable.js.map +1 -1
  7. package/dist/cjs/handlers/AsyncPanelHandler.js +1 -1
  8. package/dist/cjs/handlers/AsyncPanelHandler.js.map +1 -1
  9. package/dist/cjs/handlers/ButtonHandler.js +2 -2
  10. package/dist/cjs/handlers/ButtonHandler.js.map +1 -1
  11. package/dist/cjs/handlers/LinkHandler.js +2 -2
  12. package/dist/cjs/handlers/LinkHandler.js.map +1 -1
  13. package/dist/cjs/handlers/ModalHandler.js +5 -5
  14. package/dist/cjs/handlers/ModalHandler.js.map +1 -1
  15. package/dist/cjs/handlers/PanelHandler.js +1 -1
  16. package/dist/cjs/handlers/PanelHandler.js.map +1 -1
  17. package/dist/cjs/handlers/SectionHandler.js +1 -2
  18. package/dist/cjs/handlers/SectionHandler.js.map +1 -1
  19. package/dist/cjs/index.js +10 -10
  20. package/dist/cjs/index.js.map +1 -1
  21. package/dist/cjs/renderElementAsReact.js +4 -3
  22. package/dist/cjs/renderElementAsReact.js.map +1 -1
  23. package/dist/cjs/styled.js +17 -47
  24. package/dist/cjs/styled.js.map +1 -1
  25. package/dist/cjs/types.js +1 -2
  26. package/dist/cjs/types.js.map +1 -1
  27. package/dist/cjs/useExtensions.js +1 -1
  28. package/dist/cjs/useExtensions.js.map +1 -1
  29. package/dist/cjs/useWebPanelRenderer.js.map +1 -1
  30. package/dist/esm/ExtensionPoint.js.map +1 -1
  31. package/dist/esm/ExtensionPointInfo.js +26 -19
  32. package/dist/esm/ExtensionPointInfo.js.map +1 -1
  33. package/dist/esm/ExtensionsObservable.js.map +1 -1
  34. package/dist/esm/handlers/AsyncPanelHandler.js.map +1 -1
  35. package/dist/esm/handlers/ButtonHandler.js.map +1 -1
  36. package/dist/esm/handlers/LinkHandler.js.map +1 -1
  37. package/dist/esm/handlers/ModalHandler.js +5 -5
  38. package/dist/esm/handlers/ModalHandler.js.map +1 -1
  39. package/dist/esm/handlers/PanelHandler.js.map +1 -1
  40. package/dist/esm/handlers/SectionHandler.js +0 -1
  41. package/dist/esm/handlers/SectionHandler.js.map +1 -1
  42. package/dist/esm/renderElementAsReact.js +3 -2
  43. package/dist/esm/renderElementAsReact.js.map +1 -1
  44. package/dist/esm/styled.js +14 -44
  45. package/dist/esm/styled.js.map +1 -1
  46. package/dist/esm/useExtensions.js.map +1 -1
  47. package/dist/esm/useWebPanelRenderer.js.map +1 -1
  48. package/dist/types/ExtensionPointInfo.d.ts +1 -1
  49. package/dist/types/ExtensionPointInfo.d.ts.map +1 -1
  50. package/dist/types/ExtensionsObservable.d.ts.map +1 -1
  51. package/dist/types/debug/types.d.ts +1 -1
  52. package/dist/types/debug/types.d.ts.map +1 -1
  53. package/dist/types/debug/useDebug.d.ts.map +1 -1
  54. package/dist/types/debug/useDiscovery.d.ts.map +1 -1
  55. package/dist/types/debug/useLogging.d.ts.map +1 -1
  56. package/dist/types/debug/useValidation.d.ts.map +1 -1
  57. package/dist/types/handlers/AsyncPanelHandler.d.ts +1 -1
  58. package/dist/types/handlers/AsyncPanelHandler.d.ts.map +1 -1
  59. package/dist/types/handlers/ButtonHandler.d.ts +2 -0
  60. package/dist/types/handlers/ButtonHandler.d.ts.map +1 -1
  61. package/dist/types/handlers/LinkHandler.d.ts +2 -0
  62. package/dist/types/handlers/LinkHandler.d.ts.map +1 -1
  63. package/dist/types/handlers/ModalHandler.d.ts +2 -1
  64. package/dist/types/handlers/ModalHandler.d.ts.map +1 -1
  65. package/dist/types/handlers/SectionHandler.d.ts +6 -1
  66. package/dist/types/handlers/SectionHandler.d.ts.map +1 -1
  67. package/dist/types/renderElementAsReact.d.ts +2 -1
  68. package/dist/types/renderElementAsReact.d.ts.map +1 -1
  69. package/dist/types/styled.d.ts +33 -14
  70. package/dist/types/styled.d.ts.map +1 -1
  71. package/dist/types/types.d.ts +4 -4
  72. package/dist/types/types.d.ts.map +1 -1
  73. package/dist/types/useExtensions.d.ts.map +1 -1
  74. package/lib/ExtensionPoint.test.tsx +1 -1
  75. package/lib/ExtensionPointInfo.test.tsx +1 -1
  76. package/lib/ExtensionPointInfo.tsx +51 -24
  77. package/lib/ExtensionsObservable.test.ts +1 -1
  78. package/lib/__snapshots__/ExtensionPointInfo.test.tsx.snap +203 -124
  79. package/lib/debug/useDebug.test.ts +2 -2
  80. package/lib/debug/useDiscovery.test.ts +2 -2
  81. package/lib/debug/useLogging.test.ts +2 -2
  82. package/lib/debug/useValidation.test.ts +2 -2
  83. package/lib/handlers/ButtonHandler.test.tsx +5 -1
  84. package/lib/handlers/ButtonHandler.tsx +3 -1
  85. package/lib/handlers/LinkHandler.test.tsx +5 -1
  86. package/lib/handlers/LinkHandler.tsx +1 -0
  87. package/lib/handlers/ModalHandler.test.tsx +9 -7
  88. package/lib/handlers/ModalHandler.tsx +11 -9
  89. package/lib/handlers/SectionHandler.test.tsx +1 -1
  90. package/lib/handlers/SectionHandler.tsx +5 -1
  91. package/lib/renderElementAsReact.test.tsx +7 -6
  92. package/lib/renderElementAsReact.tsx +12 -3
  93. package/lib/styled.ts +15 -46
  94. package/lib/useExtensions.test.ts +49 -43
  95. package/package.json +25 -24
@@ -6,7 +6,11 @@ import type { FunctionComponent } from 'react';
6
6
 
7
7
  import { LinkHandler } from './LinkHandler';
8
8
 
9
- const TestComponent: FunctionComponent<{ url: string; attributes?: object }> = ({ url, attributes, children }) => {
9
+ const TestComponent: FunctionComponent<{ url: string; attributes?: object; children?: React.ReactNode }> = ({
10
+ url,
11
+ attributes,
12
+ children,
13
+ }) => {
10
14
  return (
11
15
  // eslint-disable-next-line react/jsx-props-no-spreading
12
16
  <LinkHandler href={url} {...attributes}>
@@ -5,6 +5,7 @@ import type { OnClickHandler } from './types';
5
5
 
6
6
  export interface LinkHandlerProps extends Partial<OnClickHandler> {
7
7
  href: string;
8
+ children?: React.ReactNode;
8
9
  }
9
10
 
10
11
  export const LinkHandler: FunctionComponent<LinkHandlerProps> = ({
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable jest/no-commented-out-tests */
2
2
  /* eslint-disable react/jsx-boolean-value */
3
3
  import * as React from 'react';
4
- import { render, fireEvent } from '@testing-library/react';
4
+ import { render, fireEvent, waitFor } from '@testing-library/react';
5
5
 
6
6
  import type { ModalExtension } from '@atlassian/clientside-extensions';
7
7
  import type { FunctionComponent } from 'react';
@@ -53,14 +53,15 @@ describe('ModalHandler', () => {
53
53
  });
54
54
 
55
55
  describe('ModalHandler', () => {
56
- it('should receive an isOpen prop to set the modal as open', () => {
56
+ it('should receive an isOpen prop to set the modal as open', async () => {
57
57
  const { rerender, queryByRole } = render(<TestComponent isOpen={false} />);
58
58
 
59
59
  expect(queryByRole('dialog')).toBeFalsy();
60
60
 
61
61
  rerender(<TestComponent isOpen={true} />);
62
-
63
- expect(queryByRole('dialog')).toBeTruthy();
62
+ await waitFor(() => {
63
+ expect(queryByRole('dialog')).toBeTruthy();
64
+ });
64
65
  });
65
66
 
66
67
  it('should provide a closeModal API method to extension that executes a provided onClose prop to close the modal', () => {
@@ -262,14 +263,15 @@ describe('ModalHandler', () => {
262
263
  expect(queryByText(modalButtonText)).toBeTruthy();
263
264
  });
264
265
 
265
- it('should receive an isOpen prop to set the modal as open', () => {
266
+ it('should receive an isOpen prop to set the modal as open', async () => {
266
267
  const { queryByRole, queryByText } = render(<TestComponentWithActionHandler>{modalButtonText}</TestComponentWithActionHandler>);
267
268
 
268
269
  expect(queryByRole('dialog')).toBeFalsy();
269
270
 
270
271
  queryByText(modalButtonText)?.click();
271
-
272
- expect(queryByRole('dialog')).toBeTruthy();
272
+ await waitFor(() => {
273
+ expect(queryByRole('dialog')).toBeTruthy();
274
+ });
273
275
  });
274
276
  });
275
277
  });
@@ -1,10 +1,11 @@
1
- import type { FunctionComponent } from 'react';
2
- import React, { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
- import ModalDialog, { ModalTransition, ModalBody, ModalHeader, ModalFooter, ModalTitle } from '@atlaskit/modal-dialog';
4
- import LoadingButton from '@atlaskit/button/loading-button';
1
+ import Button from '@atlaskit/button/new';
2
+ import type { KeyboardOrMouseEvent } from '@atlaskit/modal-dialog';
3
+ import ModalDialog, { ModalBody, ModalFooter, ModalHeader, ModalTitle, ModalTransition } from '@atlaskit/modal-dialog';
5
4
  import { ModalExtension } from '@atlassian/clientside-extensions';
6
- import type { OnClickHandler } from './types';
5
+ import type { FunctionComponent, ReactNode } from 'react';
6
+ import React, { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react';
7
7
  import { ButtonHandler } from './ButtonHandler';
8
+ import type { OnClickHandler } from './types';
8
9
 
9
10
  const ModalInnerBody: FunctionComponent<{ modalApi: ModalExtension.Api }> = ({ modalApi }) => {
10
11
  const ref = useRef<HTMLDivElement>(null);
@@ -56,7 +57,7 @@ export const ModalHandler: FunctionComponent<ModalHandlerProps> = ({
56
57
  const stackIndex = __disableFocusLock ? 1 : 0;
57
58
 
58
59
  const onCloseHandler = useCallback(
59
- (e) => {
60
+ (e: KeyboardOrMouseEvent) => {
60
61
  const closeResult = modalApi.getOnCloseCallback()(e);
61
62
  // prevent closing of modal if "closeRequest" is "false"
62
63
  if (closeResult !== false) {
@@ -70,9 +71,9 @@ export const ModalHandler: FunctionComponent<ModalHandlerProps> = ({
70
71
  () =>
71
72
  actions.map(({ testId, isLoading, text, onClick, isDisabled }, index) => (
72
73
  // eslint-disable-next-line react/no-array-index-key
73
- <LoadingButton key={index} isLoading={isLoading} testId={testId} isDisabled={isDisabled} onClick={onClick}>
74
+ <Button key={index} isLoading={isLoading} testId={testId} isDisabled={isDisabled} onClick={onClick}>
74
75
  {text}
75
- </LoadingButton>
76
+ </Button>
76
77
  )),
77
78
  [actions],
78
79
  );
@@ -81,7 +82,7 @@ export const ModalHandler: FunctionComponent<ModalHandlerProps> = ({
81
82
  <Wrapper>
82
83
  {isOpen && (
83
84
  <ModalDialog testId="client-extensions-modal" width={modalApi.getWidth()} onClose={onCloseHandler} stackIndex={stackIndex}>
84
- <ModalHeader>
85
+ <ModalHeader hasCloseButton>
85
86
  <ModalTitle appearance={modalApi.getAppearance()}>{modalApi.getTitle()}</ModalTitle>
86
87
  </ModalHeader>
87
88
  <ModalBody>
@@ -95,6 +96,7 @@ export const ModalHandler: FunctionComponent<ModalHandlerProps> = ({
95
96
  };
96
97
 
97
98
  export interface ModalWithActionHandlerProps extends Omit<OnClickHandler, 'onAction'> {
99
+ children?: ReactNode;
98
100
  render: ModalExtension.ModalRenderExtension;
99
101
  __withoutTransition?: boolean;
100
102
  __disableFocusLock?: boolean;
@@ -4,7 +4,7 @@ import { render } from '@testing-library/react';
4
4
 
5
5
  import { SectionHandler } from './SectionHandler';
6
6
 
7
- const TestComponent: FunctionComponent = ({ children }) => {
7
+ const TestComponent: FunctionComponent<{ children: React.ReactNode }> = ({ children }) => {
8
8
  return <SectionHandler>{children}</SectionHandler>;
9
9
  };
10
10
 
@@ -2,6 +2,10 @@ import React from 'react';
2
2
  import type { FunctionComponent } from 'react';
3
3
 
4
4
  // eslint-disable-next-line import/prefer-default-export
5
- export const SectionHandler: FunctionComponent = ({ children }) => {
5
+ interface SectionHandlerProps {
6
+ children: React.ReactNode;
7
+ }
8
+
9
+ export const SectionHandler: FunctionComponent<SectionHandlerProps> = ({ children }) => {
6
10
  return <>{children}</>;
7
11
  };
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { queryByTestId } from '@testing-library/dom';
2
+ import { queryByTestId, findByTestId } from '@testing-library/dom';
3
3
 
4
4
  import type { MountableExtension } from '@atlassian/clientside-extensions';
5
5
  import renderElementAsReact from './renderElementAsReact';
@@ -8,6 +8,7 @@ import renderElementAsReact from './renderElementAsReact';
8
8
  interface TestProps {
9
9
  name?: string;
10
10
  value?: number;
11
+ children?: React.ReactNode;
11
12
  }
12
13
  /* eslint-enable react/no-unused-prop-types */
13
14
 
@@ -27,7 +28,7 @@ describe('renderElementAsReact', () => {
27
28
  },
28
29
  };
29
30
 
30
- const TestComponent: React.FC<TestProps> = (props) => (
31
+ const TestComponent = (props: unknown) => (
31
32
  <div data-testid="test-component">
32
33
  <h2>A test content</h2>
33
34
  <p data-testid="test-props">{JSON.stringify(props)}</p>
@@ -39,7 +40,7 @@ describe('renderElementAsReact', () => {
39
40
  });
40
41
 
41
42
  it('should use the renderApi to mount and unmount the given react component', () => {
42
- const getTestComponent = () => queryByTestId(testContainer, 'test-component') as HTMLElement;
43
+ const getTestComponent = () => queryByTestId(testContainer, 'test-component');
43
44
 
44
45
  renderElementAsReact(testRenderAPI, TestComponent);
45
46
 
@@ -50,7 +51,7 @@ describe('renderElementAsReact', () => {
50
51
 
51
52
  // rendered using onMount
52
53
  expect(getTestComponent()).toBeTruthy();
53
- expect(getTestComponent().textContent).toMatch('A test content');
54
+ expect(getTestComponent()?.textContent).toMatch('A test content');
54
55
 
55
56
  onUnmountCallback(testContainer);
56
57
 
@@ -58,7 +59,7 @@ describe('renderElementAsReact', () => {
58
59
  expect(getTestComponent()).toBeFalsy();
59
60
  });
60
61
 
61
- it('should receive additional props to assing to the given react component', () => {
62
+ it('should receive additional props to assing to the given react component', async () => {
62
63
  const testProps: TestProps = {
63
64
  name: 'Meaning of life',
64
65
  value: 42,
@@ -67,7 +68,7 @@ describe('renderElementAsReact', () => {
67
68
  renderElementAsReact(testRenderAPI, TestComponent, testProps);
68
69
  onMountCallback(testContainer);
69
70
 
70
- const testPropsElement = queryByTestId(testContainer, 'test-props') as HTMLElement;
71
+ const testPropsElement = await findByTestId(testContainer, 'test-props');
71
72
 
72
73
  // props applied to the component when rendering
73
74
  expect(testPropsElement).toBeTruthy();
@@ -1,13 +1,22 @@
1
1
  import ReactDOM from 'react-dom';
2
2
  import type { ComponentType } from 'react';
3
- import React from 'react';
3
+ import React, { StrictMode } from 'react';
4
4
  import type { MountableExtension } from '@atlassian/clientside-extensions';
5
5
 
6
- function renderElementAsReact<PropsT>(renderApi: MountableExtension, RenderElement: ComponentType<PropsT>, additionalProps?: PropsT) {
6
+ function renderElementAsReact<PropsT extends React.JSX.IntrinsicAttributes>(
7
+ renderApi: MountableExtension,
8
+ RenderElement: ComponentType<PropsT>,
9
+ additionalProps?: unknown,
10
+ ) {
7
11
  renderApi
8
12
  .onMount((element) => {
9
13
  // eslint-disable-next-line react/jsx-props-no-spreading
10
- ReactDOM.render(<RenderElement {...(additionalProps as PropsT)} />, element);
14
+ ReactDOM.render(
15
+ <StrictMode>
16
+ <RenderElement {...(additionalProps as PropsT)} />
17
+ </StrictMode>,
18
+ element,
19
+ );
11
20
  })
12
21
  .onUnmount((element) => {
13
22
  ReactDOM.unmountComponentAtNode(element);
package/lib/styled.ts CHANGED
@@ -1,8 +1,8 @@
1
+ import { token } from '@atlaskit/tokens';
1
2
  import styled from '@emotion/styled';
2
- import { keyframes } from '@emotion/core';
3
- import * as colors from '@atlaskit/theme/colors';
4
- import { themed } from '@atlaskit/theme/components';
5
- import { gridSize } from '@atlaskit/theme/constants';
3
+ import { keyframes } from '@emotion/react';
4
+
5
+ export const GRID_SIZE = 8;
6
6
 
7
7
  export const BlinkerContainer = styled.span`
8
8
  position: relative;
@@ -18,10 +18,11 @@ const blinkAnimation = keyframes`
18
18
  }
19
19
  `;
20
20
 
21
+ /* eslint-disable-next-line @atlaskit/design-system/ensure-design-token-usage */
21
22
  export const Blinker = styled.button`
22
23
  height: 22px;
23
24
  width: 22px;
24
- background: rgba(7, 71, 166, 0.5);
25
+ background: ${token('color.background.input')};
25
26
  border-radius: 50%;
26
27
  animation: ${blinkAnimation} 1s ease-in-out infinite;
27
28
  animation-direction: alternate;
@@ -45,72 +46,40 @@ export const Blinker = styled.button`
45
46
  // AK doesn't provide a plain Table styled component.
46
47
  // Using AK theme to be compatible with their dark mode.
47
48
  // Styles copied from: https://bitbucket.org/atlassian/atlassian-frontend/src/master/packages/design-system/dynamic-table/src/styled/
48
- const rowTheme = {
49
- focusOutline: themed({ light: colors.B100, dark: colors.B100 }),
50
- borderColor: themed({ light: colors.N40, dark: colors.DN50 }),
51
- highlightedBackground: themed({ light: colors.N20, dark: colors.DN50 }),
52
- hoverBackground: themed({ light: colors.N10, dark: colors.DN40 }),
53
- hoverHighlightedBackground: themed({ light: colors.N30, dark: colors.DN60 }),
54
- };
55
-
56
- const headTheme = {
57
- focusOutline: themed({ light: colors.B100, dark: colors.B100 }),
58
- borderColor: themed({ light: colors.N40, dark: colors.DN50 }),
59
- textColor: themed({ light: colors.N300, dark: colors.DN300 }),
60
- };
61
-
62
49
  export const Table = styled.table`
63
50
  border-collapse: collapse;
64
51
  width: 100%;
65
52
  `;
66
53
 
67
54
  export const HeadRow = styled.tr`
68
- border-bottom: 2px solid ${headTheme.borderColor};
55
+ border-bottom: 1px solid ${token('color.border')};
69
56
  `;
70
57
 
71
58
  export const HeadCell = styled.th`
72
- padding: ${gridSize() / 2}px ${gridSize}px;
73
- &:first-of-type {
74
- padding-left: 0;
75
- }
76
- &:last-of-type {
77
- padding-right: 0;
78
- }
59
+ padding: ${GRID_SIZE / 2}px ${GRID_SIZE}px;
79
60
  border: none;
80
- color: ${headTheme.textColor};
61
+ color: ${token('color.text')};
81
62
  box-sizing: border-box;
82
63
  font-size: 12px;
83
64
  font-weight: bold;
84
65
  position: relative;
85
66
  text-align: left;
86
67
  vertical-align: top;
87
- &:focus {
88
- outline: solid 2px ${headTheme.focusOutline};
89
- }
90
68
  `;
91
69
 
92
- const outlineWidth = '2px';
93
-
94
70
  export const TableRow = styled.tr`
95
- border-bottom: 2px solid ${rowTheme.borderColor};
71
+ border-bottom: 1px solid ${token('color.border')};
96
72
  &:hover {
97
- background-color: ${rowTheme.hoverBackground};
98
- }
99
- &:focus {
100
- outline: ${outlineWidth} solid ${rowTheme.focusOutline};
101
- outline-offset: -${outlineWidth};
73
+ background-color: ${token('color.background.neutral.subtle.hovered')};
102
74
  }
103
75
  `;
104
76
 
105
77
  export const TableCell = styled.td`
106
78
  border: none;
107
- padding: ${gridSize() / 1.2}px ${gridSize}px;
79
+ padding: ${GRID_SIZE / 1.2}px ${GRID_SIZE}px;
108
80
  text-align: left;
81
+ `;
109
82
 
110
- &:first-of-type {
111
- padding-left: 0;
112
- }
113
- &:last-of-type {
114
- padding-right: 0;
115
- }
83
+ export const HeadingWrapper = styled.div`
84
+ margin-top: 30px;
116
85
  `;
@@ -1,5 +1,5 @@
1
- import { mocked } from 'ts-jest/utils';
2
- import { act, renderHook } from '@testing-library/react-hooks';
1
+ import { mocked } from 'jest-mock';
2
+ import { act, renderHook, waitFor } from '@testing-library/react';
3
3
  import type { Context, ExtensionAPI, ExtensionAttributes, ExtensionDescriptor } from '@atlassian/clientside-extensions-registry';
4
4
  import registry from '@atlassian/clientside-extensions-registry';
5
5
  import * as debug from '@atlassian/clientside-extensions-debug';
@@ -27,7 +27,6 @@ type MockSubjectPayload = {
27
27
  type MockLocationObserver = (payload: MockSubjectPayload) => void;
28
28
 
29
29
  type ExtensionDescriptorWithContextInAttributes = ExtensionDescriptor<ExtensionAttributes & { context: Context<{}> }>;
30
- type UseExtensionsAllReturnType = ReturnType<typeof useExtensionsAll>;
31
30
 
32
31
  function applyAttributesProvider(descriptor: ExtensionDescriptor) {
33
32
  const { attributesProvider, ...restDescriptor } = descriptor;
@@ -288,7 +287,7 @@ describe('useExtensionsAll hook', () => {
288
287
  onAction: () => updateAttributes({ label: 'a new fake label' }),
289
288
  }),
290
289
  };
291
- const { result, waitForNextUpdate } = renderHook(() => useExtensionsAll('fake-location', null, options));
290
+ const { result } = renderHook(() => useExtensionsAll('fake-location', null, options));
292
291
 
293
292
  act(() => {
294
293
  locationObserver({ descriptors: [changeAttributesExtension], loadingState: false });
@@ -299,11 +298,12 @@ describe('useExtensionsAll hook', () => {
299
298
  const [testExtension] = extensions as ExtensionDescriptor<ExtensionAttributes & { onAction: () => void }>[];
300
299
  testExtension.attributes.onAction();
301
300
  });
302
- await waitForNextUpdate();
303
301
 
304
- const [extensionsUpdated] = result.current;
305
- const [testExtensionChanged] = extensionsUpdated;
306
- expect(testExtensionChanged.attributes.label).toBe('a new fake label');
302
+ await waitFor(() => {
303
+ const [extensionsUpdated] = result.current;
304
+ const [testExtensionChanged] = extensionsUpdated;
305
+ expect(testExtensionChanged.attributes.label).toBe('a new fake label');
306
+ });
307
307
  });
308
308
 
309
309
  it('should catch errors when calling update attributes API', () => {
@@ -344,7 +344,8 @@ describe('useExtensionsAll hook', () => {
344
344
  message: expect.stringContaining('Updating attributes for extension fake-1 failed'),
345
345
  }),
346
346
  );
347
- expect(result.error).toBeFalsy();
347
+ // The hook should not throw an error, so we just verify it renders successfully
348
+ expect(result.current).toBeDefined();
348
349
  });
349
350
 
350
351
  it('should add new attributes when using `updateAttributes` function', async () => {
@@ -364,7 +365,7 @@ describe('useExtensionsAll hook', () => {
364
365
  },
365
366
  };
366
367
 
367
- const { result, waitForNextUpdate } = renderHook(() => useExtensions('fake-location', null, options));
368
+ const { result } = renderHook(() => useExtensions('fake-location', null, options));
368
369
 
369
370
  // First render
370
371
  act(() => {
@@ -380,10 +381,11 @@ describe('useExtensionsAll hook', () => {
380
381
  beforeIcon: 'my-icon',
381
382
  }),
382
383
  );
383
- await waitForNextUpdate();
384
384
 
385
- const [extensionSecondRender] = result.current;
386
- expect(extensionSecondRender.attributes).toHaveProperty('beforeIcon', 'my-icon');
385
+ await waitFor(() => {
386
+ const [extensionSecondRender] = result.current;
387
+ expect(extensionSecondRender.attributes).toHaveProperty('beforeIcon', 'my-icon');
388
+ });
387
389
  });
388
390
 
389
391
  it('should extend the existing attributes when using `updateAttributes` function with a functional update', async () => {
@@ -411,7 +413,7 @@ describe('useExtensionsAll hook', () => {
411
413
  },
412
414
  };
413
415
 
414
- const { result, waitForNextUpdate } = renderHook(() => useExtensions('fake-location', null, options));
416
+ const { result } = renderHook(() => useExtensions('fake-location', null, options));
415
417
 
416
418
  // First render
417
419
  act(() => {
@@ -432,12 +434,12 @@ describe('useExtensionsAll hook', () => {
432
434
  }),
433
435
  );
434
436
 
435
- await waitForNextUpdate();
436
-
437
- expect(result.current[0].attributes).toEqual({
438
- type: 'button',
439
- label: 'bar',
440
- counter: 1,
437
+ await waitFor(() => {
438
+ expect(result.current[0].attributes).toEqual({
439
+ type: 'button',
440
+ label: 'bar',
441
+ counter: 1,
442
+ });
441
443
  });
442
444
 
443
445
  // Second update with manual attributes merge
@@ -451,12 +453,12 @@ describe('useExtensionsAll hook', () => {
451
453
  }),
452
454
  );
453
455
 
454
- await waitForNextUpdate();
455
-
456
- expect(result.current[0].attributes).toEqual({
457
- type: 'button',
458
- label: 'baz',
459
- counter: 2,
456
+ await waitFor(() => {
457
+ expect(result.current[0].attributes).toEqual({
458
+ type: 'button',
459
+ label: 'baz',
460
+ counter: 2,
461
+ });
460
462
  });
461
463
 
462
464
  // Third update with auto-merge
@@ -466,12 +468,12 @@ describe('useExtensionsAll hook', () => {
466
468
  })),
467
469
  );
468
470
 
469
- await waitForNextUpdate();
470
-
471
- expect(result.current[0].attributes).toEqual({
472
- type: 'button',
473
- label: 'baz',
474
- counter: 4,
471
+ await waitFor(() => {
472
+ expect(result.current[0].attributes).toEqual({
473
+ type: 'button',
474
+ label: 'baz',
475
+ counter: 4,
476
+ });
475
477
  });
476
478
  });
477
479
 
@@ -599,9 +601,9 @@ describe('useExtensionsAll hook', () => {
599
601
  });
600
602
 
601
603
  it('should throw an error if no context schema is provided when providing context', () => {
602
- const { result } = renderHook(() => useExtensionsAll('fake-location', { info: 'test-info' }, { attributeValidator }));
603
-
604
- expect(result.error).toEqual(Error('No context validator specified for extension point "fake-location"'));
604
+ expect(() => {
605
+ renderHook(() => useExtensionsAll('fake-location', { info: 'test-info' }, { attributeValidator }));
606
+ }).toThrow('No context validator specified for extension point "fake-location"');
605
607
  });
606
608
 
607
609
  it('should call the attributes provider only once when passed context did not changed', () => {
@@ -621,9 +623,11 @@ describe('useExtensionsAll hook', () => {
621
623
  }),
622
624
  };
623
625
 
624
- const { result, rerender } = renderHook<{ context: Context<{}> }, UseExtensionsAllReturnType>(({ context }) =>
625
- useExtensionsAll('fake-location', context, options),
626
- );
626
+ const { result, rerender } = renderHook(({ context }) => useExtensionsAll('fake-location', context, options), {
627
+ initialProps: {
628
+ context: stableContext,
629
+ },
630
+ });
627
631
 
628
632
  // First call
629
633
  rerender({
@@ -656,11 +660,11 @@ describe('useExtensionsAll hook', () => {
656
660
  });
657
661
 
658
662
  it('should call the attributes provider twice when passed context did changed', () => {
659
- const firstContext = {
663
+ const firstContext: Context<{}> = {
660
664
  foo: 'bar',
661
665
  };
662
666
 
663
- const secondContext = {
667
+ const secondContext: Context<{}> = {
664
668
  biz: 'baz',
665
669
  };
666
670
 
@@ -676,9 +680,11 @@ describe('useExtensionsAll hook', () => {
676
680
  }),
677
681
  };
678
682
 
679
- const { result, rerender } = renderHook<{ context: Context<{}> }, UseExtensionsAllReturnType>(({ context }) =>
680
- useExtensionsAll('fake-location', context, options),
681
- );
683
+ const { result, rerender } = renderHook(({ context }) => useExtensionsAll('fake-location', context, options), {
684
+ initialProps: {
685
+ context: firstContext,
686
+ },
687
+ });
682
688
 
683
689
  // First update
684
690
  rerender({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlassian/clientside-extensions-components",
3
- "version": "4.0.2",
3
+ "version": "5.1.0-5a180d69-mdyn784a",
4
4
  "description": "React components to assist in the authoring of extension points that work at product runtime.",
5
5
  "license": "BSD-3-Clause",
6
6
  "homepage": "https://bitbucket.org/atlassian/atlassian-clientside-extensions#readme",
@@ -53,7 +53,7 @@
53
53
  ],
54
54
  "publishConfig": {
55
55
  "access": "public",
56
- "registry": "https://registry.npmjs.org/"
56
+ "registry": "https://packages.atlassian.com/api/npm/npm-public/"
57
57
  },
58
58
  "scripts": {
59
59
  "prepublish": "yarn build",
@@ -66,39 +66,40 @@
66
66
  "test:watch": "jest --watch"
67
67
  },
68
68
  "dependencies": {
69
- "@atlaskit/button": "17.12.0",
70
- "@atlaskit/modal-dialog": "12.10.11",
71
- "@atlaskit/theme": "12.7.0",
72
- "@atlassian/clientside-extensions": "^4.0.2",
73
- "@atlassian/clientside-extensions-base": "^4.0.2",
74
- "@atlassian/clientside-extensions-debug": "^4.0.2",
75
- "@atlassian/clientside-extensions-registry": "^4.0.2",
76
- "@atlassian/clientside-extensions-schema": "^4.0.2",
77
- "@emotion/core": "^10.1.1",
78
- "@emotion/styled": "^10.0.27",
69
+ "@atlaskit/button": "23.3.1",
70
+ "@atlaskit/heading": "5.2.3",
71
+ "@atlaskit/modal-dialog": "14.3.2",
72
+ "@atlaskit/tokens": "5.6.2",
73
+ "@atlassian/clientside-extensions": "^5.1.0-5a180d69-mdyn784a",
74
+ "@atlassian/clientside-extensions-base": "^5.1.0-5a180d69-mdyn784a",
75
+ "@atlassian/clientside-extensions-debug": "^5.1.0-5a180d69-mdyn784a",
76
+ "@atlassian/clientside-extensions-registry": "^5.1.0-5a180d69-mdyn784a",
77
+ "@atlassian/clientside-extensions-schema": "^5.1.0-5a180d69-mdyn784a",
78
+ "@emotion/react": "^11.13.5",
79
+ "@emotion/styled": "^11.13.5",
79
80
  "lodash.isequal": "^4.5.0",
80
- "react-scroll": "^1.8.1",
81
+ "react-scroll": "^1.8.10",
81
82
  "tslib": "^2.2.0"
82
83
  },
83
84
  "peerDependencies": {
84
- "react": "^16.9",
85
- "react-dom": "^16.9"
85
+ "react": "^18.0.0",
86
+ "react-dom": "^18.0.0"
86
87
  },
87
88
  "devDependencies": {
88
89
  "@testing-library/dom": "8.11.1",
89
90
  "@testing-library/jest-dom": "5.15.1",
90
- "@testing-library/react": "12.1.2",
91
- "@testing-library/react-hooks": "7.0.2",
91
+ "@testing-library/react": "16.3.0",
92
92
  "@types/lodash.isequal": "4.5.5",
93
- "@types/react": "16.14.21",
94
- "@types/react-scroll": "1.8.3",
93
+ "@types/react": "18.3.1",
94
+ "@types/react-scroll": "^1.8.10",
95
95
  "jest": "27.3.1",
96
- "react": "16.14.0",
97
- "react-dom": "16.14.0",
98
- "ts-jest": "27.0.7"
96
+ "jest-mock": "30.0.5",
97
+ "react": "18.3.1",
98
+ "react-dom": "18.3.1",
99
+ "ts-jest": "29.4.1"
99
100
  },
100
101
  "engines": {
101
- "node": ">=20.16.0"
102
+ "node": ">=20.18.1"
102
103
  },
103
- "gitHead": "2d552dc8d3b5d2c9583a19324d5b7459f5db6afa"
104
+ "gitHead": "5a180d69885a02ac1d96b980893b6a5c77e9459a"
104
105
  }