diff --git a/src/internal/base-component/__tests__/use-base-component.test.tsx b/src/internal/base-component/__tests__/use-base-component.test.tsx
index ed893b5..8c711ae 100644
--- a/src/internal/base-component/__tests__/use-base-component.test.tsx
+++ b/src/internal/base-component/__tests__/use-base-component.test.tsx
@@ -1,14 +1,13 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { render } from "@testing-library/react";
-import { expect, test, vi } from "vitest";
+import { afterEach, expect, test, vi } from "vitest";
-import { COMPONENT_METADATA_KEY } from "@cloudscape-design/component-toolkit/internal";
+import { COMPONENT_METADATA_KEY, useComponentMetrics } from "@cloudscape-design/component-toolkit/internal";
import useBaseComponent, {
InternalBaseComponentProps,
} from "../../../../lib/components/internal/base-component/use-base-component";
-import { useTelemetry } from "../../../../lib/components/internal/base-component/use-telemetry";
import { PACKAGE_VERSION } from "../../../../lib/components/internal/environment";
type InternalDemoProps = InternalBaseComponentProps;
@@ -16,24 +15,39 @@ function InternalDemo({ __internalRootRef }: InternalDemoProps) {
return
Internal Demo Component
;
}
+declare global {
+ interface Node {
+ [COMPONENT_METADATA_KEY]?: { name: string; version: string };
+ }
+}
+
function Demo({ variant }: { variant: string }) {
const baseComponentProps = useBaseComponent("DemoComponent", { props: { variant } });
return ;
}
-vi.mock("../../../../lib/components/internal/base-component/use-telemetry", () => {
- return { useTelemetry: vi.fn(() => null) };
+vi.mock("@cloudscape-design/component-toolkit/internal", async (importOriginal) => {
+ return { ...(await importOriginal()), useComponentMetrics: vi.fn(() => {}) };
+});
+
+afterEach(() => {
+ vi.resetAllMocks();
});
test("should attach the metadata to the returned root DOM node", () => {
const { container } = render();
- const rootNode: any = container.firstChild;
- expect(rootNode[COMPONENT_METADATA_KEY]?.name).toBe("DemoComponent");
- expect(rootNode[COMPONENT_METADATA_KEY]?.version).toBe(PACKAGE_VERSION);
+ const rootNode = container.firstChild;
+ expect(rootNode![COMPONENT_METADATA_KEY]!.name).toBe("DemoComponent");
+ expect(rootNode![COMPONENT_METADATA_KEY]!.version).toBe(PACKAGE_VERSION);
});
test("should call the useTelemetry hook passing down the given component name and its props", () => {
- vi.resetAllMocks();
render();
- expect(useTelemetry).toHaveBeenCalledWith("DemoComponent", { props: { variant: "default" } });
+ expect(useComponentMetrics).toHaveBeenCalledWith(
+ "DemoComponent",
+ expect.objectContaining({ packageVersion: PACKAGE_VERSION }),
+ {
+ props: { variant: "default" },
+ },
+ );
});
diff --git a/src/internal/base-component/use-base-component.ts b/src/internal/base-component/use-base-component.ts
index 700b9cd..538b6e1 100644
--- a/src/internal/base-component/use-base-component.ts
+++ b/src/internal/base-component/use-base-component.ts
@@ -7,11 +7,13 @@ import {
ComponentConfiguration,
initAwsUiVersions,
useComponentMetadata,
+ useComponentMetrics,
+ useFocusVisible,
} from "@cloudscape-design/component-toolkit/internal";
-import { PACKAGE_SOURCE, PACKAGE_VERSION } from "../environment";
-import useFocusVisible from "../utils/focus-visible";
-import { useTelemetry } from "./use-telemetry";
+import { PACKAGE_SOURCE, PACKAGE_VERSION, THEME } from "../environment";
+import { getVisualTheme } from "../utils/get-visual-theme";
+import { useVisualRefresh } from "./use-visual-refresh";
initAwsUiVersions(PACKAGE_SOURCE, PACKAGE_VERSION);
@@ -25,8 +27,14 @@ export interface InternalBaseComponentProps {
* root DOM node and emits the telemetry for this component.
*/
export default function useBaseComponent(componentName: string, config?: ComponentConfiguration) {
- useTelemetry(componentName, config);
+ const isVisualRefresh = useVisualRefresh();
+ const theme = getVisualTheme(THEME, isVisualRefresh);
+ useComponentMetrics(componentName, { packageSource: PACKAGE_SOURCE, packageVersion: PACKAGE_VERSION, theme }, config);
useFocusVisible();
- const elementRef = useComponentMetadata(componentName, PACKAGE_VERSION);
+ const elementRef = useComponentMetadata(componentName, {
+ packageName: PACKAGE_SOURCE,
+ version: PACKAGE_VERSION,
+ theme,
+ });
return { __internalRootRef: elementRef };
}
diff --git a/src/internal/base-component/use-telemetry.ts b/src/internal/base-component/use-telemetry.ts
deleted file mode 100644
index 3327ce4..0000000
--- a/src/internal/base-component/use-telemetry.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-
-import { ComponentConfiguration, useComponentMetrics } from "@cloudscape-design/component-toolkit/internal";
-
-import { PACKAGE_SOURCE, PACKAGE_VERSION, THEME } from "../environment";
-import { getVisualTheme } from "../utils/get-visual-theme";
-import { useVisualRefresh } from "./use-visual-refresh";
-
-export function useTelemetry(componentName: string, config?: ComponentConfiguration) {
- const isVisualRefresh = useVisualRefresh();
- const theme = getVisualTheme(THEME, isVisualRefresh);
- useComponentMetrics(componentName, { packageSource: PACKAGE_SOURCE, packageVersion: PACKAGE_VERSION, theme }, config);
-}
diff --git a/src/internal/utils/__tests__/focus-visible.test.tsx b/src/internal/utils/__tests__/focus-visible.test.tsx
deleted file mode 100644
index f310d23..0000000
--- a/src/internal/utils/__tests__/focus-visible.test.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-import { cleanup, fireEvent, render } from "@testing-library/react";
-import { afterEach, describe, expect, test, vi } from "vitest";
-
-import useFocusVisible from "../../../../lib/components/internal/utils/focus-visible";
-
-function Fixture() {
- useFocusVisible();
- return ;
-}
-
-describe("Focus visible", () => {
- afterEach(() => {
- cleanup();
- });
-
- test("should disable focus by default", () => {
- render();
- expect(document.body).not.toHaveAttribute("data-awsui-focus-visible");
- });
-
- [
- { key: "Shift", keyCode: 16 },
- { key: "Alt", keyCode: 17 },
- { key: "Control", keyCode: 18 },
- { key: "Meta", keyCode: 91 },
- ].forEach((key) => {
- test(`should not enable focus when ${key.key} key is pressed`, () => {
- render();
- fireEvent.keyDown(document.body, key);
- expect(document.body).not.toHaveAttribute("data-awsui-focus-visible");
- });
- });
-
- test(`should enable focus when shift-tab is pressed`, () => {
- render();
- fireEvent.keyDown(document.body, { key: "Tab", keyCode: 65, shiftKey: true });
- expect(document.body).toHaveAttribute("data-awsui-focus-visible", "true");
- });
-
- test("should enable focus when keyboard interaction happened", () => {
- render();
- fireEvent.keyDown(document.body);
- expect(document.body).toHaveAttribute("data-awsui-focus-visible", "true");
- });
-
- test("should disable focus when mouse is used after keyboard", () => {
- render();
- fireEvent.keyDown(document.body);
- fireEvent.mouseDown(document.body);
- expect(document.body).not.toHaveAttribute("data-awsui-focus-visible");
- });
-
- test("should work with multiple components", () => {
- render(
- <>
-
-
- >,
- );
- fireEvent.keyDown(document.body);
- expect(document.body).toHaveAttribute("data-awsui-focus-visible", "true");
- });
-
- test("should add listeners only once", () => {
- vi.spyOn(document, "addEventListener");
- vi.spyOn(document, "removeEventListener");
- const { rerender } = render(
- <>
-
-
- >,
- );
- expect(document.addEventListener).toHaveBeenCalledTimes(2);
- expect(document.removeEventListener).toHaveBeenCalledTimes(0);
- rerender();
- expect(document.removeEventListener).toHaveBeenCalledTimes(0);
- rerender();
- expect(document.removeEventListener).toHaveBeenCalledTimes(2);
- });
-
- test("should initialize late components with updated state", () => {
- const { rerender } = render();
- fireEvent.keyDown(document.body);
- expect(document.body).toHaveAttribute("data-awsui-focus-visible", "true");
- rerender();
- expect(document.body).toHaveAttribute("data-awsui-focus-visible", "true");
- });
-});
diff --git a/src/internal/utils/focus-visible.ts b/src/internal/utils/focus-visible.ts
deleted file mode 100644
index faee34e..0000000
--- a/src/internal/utils/focus-visible.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
-// SPDX-License-Identifier: Apache-2.0
-import { useEffect } from "react";
-
-import { KeyCode } from "../keycode";
-
-export function isModifierKey(event: KeyboardEvent) {
- // we do not want to highlight focused element
- // when special keys are pressed
- return [KeyCode.shift, KeyCode.alt, KeyCode.control, KeyCode.meta].indexOf(event.keyCode) > -1;
-}
-
-function setIsKeyboard(active: boolean) {
- if (active) {
- document.body.setAttribute("data-awsui-focus-visible", "true");
- } else {
- document.body.removeAttribute("data-awsui-focus-visible");
- }
-}
-
-function handleMousedown() {
- return setIsKeyboard(false);
-}
-
-function handleKeydown(event: KeyboardEvent) {
- if (!isModifierKey(event)) {
- setIsKeyboard(true);
- }
-}
-
-let componentsCount = 0;
-
-function addListeners() {
- document.addEventListener("mousedown", handleMousedown);
- document.addEventListener("keydown", handleKeydown);
-}
-
-function removeListeners() {
- document.removeEventListener("mousedown", handleMousedown);
- document.removeEventListener("keydown", handleKeydown);
-}
-
-export default function useFocusVisible() {
- useEffect(() => {
- if (componentsCount === 0) {
- addListeners();
- }
- componentsCount++;
- return () => {
- componentsCount--;
- if (componentsCount === 0) {
- removeListeners();
- }
- };
- }, []);
-}