diff --git a/__mocks__/@juggle/resize-observer.ts b/__mocks__/@juggle/resize-observer.ts
deleted file mode 100644
index c2a2571..0000000
--- a/__mocks__/@juggle/resize-observer.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-
-/* eslint-env es6 */
-/* eslint-disable header/header */
-import { ResizeObserver, ResizeObserverEntry } from '@juggle/resize-observer';
-
-const callbackField = Symbol();
-
-const mockObserve = jest.fn(function (this: MockResizeObserver, el: HTMLElement) {
- // JSDOM does not support CSS. This mock allows to set element sizes via inline styles
- // and they will be passed into the handlers
- const { width, height } = el.style;
- const size = { inlineSize: parseInt(width) || 0, blockSize: parseInt(height) || 0 };
- const cb = this[callbackField];
- cb([{ borderBoxSize: [size], contentBoxSize: [size], target: el }], this);
-});
-const mockUnobserve = jest.fn();
-const mockDisconnect = jest.fn();
-
-class MockResizeObserver implements ResizeObserver {
- [callbackField]: (...args: any[]) => void;
-
- constructor(cb: (...args: any[]) => void) {
- this[callbackField] = cb;
- }
-
- get observe() {
- return mockObserve;
- }
-
- get unobserve() {
- return mockUnobserve;
- }
-
- get disconnect() {
- return mockDisconnect;
- }
-}
-
-export { ResizeObserverEntry };
-export { MockResizeObserver as ResizeObserver };
diff --git a/package-lock.json b/package-lock.json
index 9c3c95e..7c277c7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,7 +8,6 @@
"name": "@cloudscape-design/component-toolkit",
"version": "1.0.0-beta",
"dependencies": {
- "@juggle/resize-observer": "^3.3.1",
"tslib": "^2.3.1"
},
"devDependencies": {
@@ -2728,11 +2727,6 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
- "node_modules/@juggle/resize-observer": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz",
- "integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA=="
- },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -17802,11 +17796,6 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
- "@juggle/resize-observer": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz",
- "integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA=="
- },
"@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
diff --git a/package.json b/package.json
index ea35ec7..56ef413 100644
--- a/package.json
+++ b/package.json
@@ -40,7 +40,6 @@
"prepare": "husky"
},
"dependencies": {
- "@juggle/resize-observer": "^3.3.1",
"tslib": "^2.3.1"
},
"devDependencies": {
diff --git a/src/container-queries/__tests__/use-container-query-pure.test.tsx b/src/container-queries/__tests__/use-container-query-pure.test.tsx
new file mode 100644
index 0000000..5e1a501
--- /dev/null
+++ b/src/container-queries/__tests__/use-container-query-pure.test.tsx
@@ -0,0 +1,29 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+import React from 'react';
+import { render } from '@testing-library/react';
+import { ContainerQueryEntry } from '../interfaces';
+import useContainerQuery from '../use-container-query';
+
+function TestComponent({ mapFn = () => '' }: { mapFn?: (entry: ContainerQueryEntry) => string }) {
+ const [value, ref] = useContainerQuery(mapFn);
+ return
;
+}
+
+test('should work in JSDOM environment without any mocks', () => {
+ // making sure this API does not exist
+ expect(typeof ResizeObserver).toBe('undefined');
+ const mapFn = jest.fn(() => '');
+ const component = render();
+ expect(mapFn).toHaveBeenCalledWith(
+ {
+ target: component.getByTestId('test'),
+ contentBoxWidth: 0,
+ contentBoxHeight: 0,
+ borderBoxWidth: 0,
+ borderBoxHeight: 0,
+ },
+ null
+ );
+});
diff --git a/src/container-queries/__tests__/use-container-query.test.tsx b/src/container-queries/__tests__/use-container-query.test.tsx
index 07f1747..c3fc1ef 100644
--- a/src/container-queries/__tests__/use-container-query.test.tsx
+++ b/src/container-queries/__tests__/use-container-query.test.tsx
@@ -4,8 +4,8 @@
import React from 'react';
import { render } from '@testing-library/react';
import useContainerQuery from '../use-container-query';
-import { ResizeObserver } from '@juggle/resize-observer';
import { ContainerQueryEntry } from '../interfaces';
+import '../../internal/container-queries/__tests__/resize-observer-mock';
function TestComponent({ mapFn = () => '' }: { mapFn?: (entry: ContainerQueryEntry) => string }) {
const [value, ref] = useContainerQuery(mapFn);
diff --git a/src/internal/container-queries/__tests__/resize-observer-mock.ts b/src/internal/container-queries/__tests__/resize-observer-mock.ts
new file mode 100644
index 0000000..fd4da19
--- /dev/null
+++ b/src/internal/container-queries/__tests__/resize-observer-mock.ts
@@ -0,0 +1,66 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+/**
+ * Mock ResizeObserver for Jest tests
+ *
+ * This module provides a mock implementation of the native ResizeObserver API
+ * for use in Jest test environments where ResizeObserver may not be available.
+ */
+
+const mockObserve = jest.fn();
+const mockUnobserve = jest.fn();
+const mockDisconnect = jest.fn();
+
+// Create the ResizeObserver mock constructor
+global.ResizeObserver = jest.fn().mockImplementation(() => ({
+ observe: mockObserve,
+ unobserve: mockUnobserve,
+ disconnect: mockDisconnect,
+}));
+
+// Mock the prototype methods for backward compatibility with tests that access prototype
+Object.defineProperty(global.ResizeObserver, 'prototype', {
+ value: {
+ observe: mockObserve,
+ unobserve: mockUnobserve,
+ disconnect: mockDisconnect,
+ },
+ writable: false,
+});
+
+/**
+ * Mock getBoundingClientRect to return dimensions based on CSS styles
+ *
+ * In JSDOM test environments, getBoundingClientRect() returns all zeros because
+ * JSDOM doesn't perform actual layout calculations. This mock extracts width/height
+ * from computed CSS styles to provide realistic dimensions for ResizeObserver tests.
+ *
+ * Only mock in browser environments (not SSR tests where Element is undefined).
+ */
+if (typeof Element !== 'undefined') {
+ Element.prototype.getBoundingClientRect = jest.fn(function () {
+ const style = window.getComputedStyle(this);
+ const width = parseFloat(style.width) || 0;
+ const height = parseFloat(style.height) || 0;
+
+ return {
+ width,
+ height,
+ top: 0,
+ left: 0,
+ bottom: height,
+ right: width,
+ x: 0,
+ y: 0,
+ toJSON: () => ({}),
+ };
+ });
+}
+
+// Export the mock functions for test access if needed
+module.exports = {
+ mockObserve,
+ mockUnobserve,
+ mockDisconnect,
+};
diff --git a/src/internal/container-queries/__tests__/use-resize-observer.test.tsx b/src/internal/container-queries/__tests__/use-resize-observer.test.tsx
index 06feb6e..9c2c38d 100644
--- a/src/internal/container-queries/__tests__/use-resize-observer.test.tsx
+++ b/src/internal/container-queries/__tests__/use-resize-observer.test.tsx
@@ -4,8 +4,8 @@
import React, { useState, useRef } from 'react';
import { render } from '@testing-library/react';
import { useResizeObserver } from '../use-resize-observer';
-import { ResizeObserver } from '@juggle/resize-observer';
import { ContainerQueryEntry } from '../interfaces';
+import './resize-observer-mock';
function TestComponent({ mapFn = () => '' }: { mapFn?: (entry: ContainerQueryEntry) => string }) {
const ref = useRef(null);
diff --git a/src/internal/container-queries/use-resize-observer.ts b/src/internal/container-queries/use-resize-observer.ts
index 4118a44..9dfcb72 100644
--- a/src/internal/container-queries/use-resize-observer.ts
+++ b/src/internal/container-queries/use-resize-observer.ts
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
import { unstable_batchedUpdates } from 'react-dom';
-import { ResizeObserver, ResizeObserverEntry } from '@juggle/resize-observer';
import { useEffect, useLayoutEffect } from 'react';
import { ContainerQueryEntry, ElementReference } from './interfaces';
import { useStableCallback } from '../stable-callback';
@@ -42,7 +41,8 @@ export function useResizeObserver(elementRef: ElementReference, onObserve: (entr
() => {
const element = typeof elementRef === 'function' ? elementRef() : elementRef?.current;
if (element) {
- onObserve(convertResizeObserverEntry(new ResizeObserverEntry(element)));
+ const rect = element.getBoundingClientRect();
+ onObserve(convertElementToEntry(element, rect));
}
},
// This effect is only needed for the first render to provide a synchronous update.
@@ -52,7 +52,7 @@ export function useResizeObserver(elementRef: ElementReference, onObserve: (entr
useEffect(() => {
const element = typeof elementRef === 'function' ? elementRef() : elementRef?.current;
- if (element) {
+ if (element && typeof ResizeObserver !== 'undefined') {
let connected = true;
const observer = new ResizeObserver(entries => {
// Prevent observe notifications on already unmounted component.
@@ -80,3 +80,19 @@ function convertResizeObserverEntry(entry: ResizeObserverEntry): ContainerQueryE
borderBoxHeight: entry.borderBoxSize[0].blockSize,
};
}
+
+function convertElementToEntry(element: Element, rect: DOMRect): ContainerQueryEntry {
+ const computedStyle = window.getComputedStyle(element);
+ const paddingLeft = parseFloat(computedStyle.paddingLeft) || 0;
+ const paddingRight = parseFloat(computedStyle.paddingRight) || 0;
+ const paddingTop = parseFloat(computedStyle.paddingTop) || 0;
+ const paddingBottom = parseFloat(computedStyle.paddingBottom) || 0;
+
+ return {
+ target: element,
+ contentBoxWidth: rect.width - paddingLeft - paddingRight,
+ contentBoxHeight: rect.height - paddingTop - paddingBottom,
+ borderBoxWidth: rect.width,
+ borderBoxHeight: rect.height,
+ };
+}