diff --git a/common/changes/@itwin/appui-react/change-selection-count-padding_2024-07-26-16-49.json b/common/changes/@itwin/appui-react/change-selection-count-padding_2024-07-26-16-49.json
new file mode 100644
index 00000000000..8f52a9b4ae0
--- /dev/null
+++ b/common/changes/@itwin/appui-react/change-selection-count-padding_2024-07-26-16-49.json
@@ -0,0 +1,10 @@
+{
+ "changes": [
+ {
+ "packageName": "@itwin/appui-react",
+ "comment": "Adjust SelectionCount padding values.",
+ "type": "none"
+ }
+ ],
+ "packageName": "@itwin/appui-react"
+}
\ No newline at end of file
diff --git a/common/changes/@itwin/appui-react/fix-893_2024-07-31-08-02.json b/common/changes/@itwin/appui-react/fix-893_2024-07-31-08-02.json
new file mode 100644
index 00000000000..f83dcd14ae1
--- /dev/null
+++ b/common/changes/@itwin/appui-react/fix-893_2024-07-31-08-02.json
@@ -0,0 +1,10 @@
+{
+ "changes": [
+ {
+ "packageName": "@itwin/appui-react",
+ "comment": "Fix an issue where styles of complex shorthand properties were not copied correctly to a popout window.",
+ "type": "none"
+ }
+ ],
+ "packageName": "@itwin/appui-react"
+}
\ No newline at end of file
diff --git a/common/changes/@itwin/appui-react/link-discussions_2024-07-31-12-45.json b/common/changes/@itwin/appui-react/link-discussions_2024-07-31-12-45.json
new file mode 100644
index 00000000000..3393c35368c
--- /dev/null
+++ b/common/changes/@itwin/appui-react/link-discussions_2024-07-31-12-45.json
@@ -0,0 +1,10 @@
+{
+ "changes": [
+ {
+ "packageName": "@itwin/appui-react",
+ "comment": "",
+ "type": "none"
+ }
+ ],
+ "packageName": "@itwin/appui-react"
+}
\ No newline at end of file
diff --git a/docs/changehistory/NextVersion.md b/docs/changehistory/NextVersion.md
index 1eda19c281b..5e1f7a6ca6c 100644
--- a/docs/changehistory/NextVersion.md
+++ b/docs/changehistory/NextVersion.md
@@ -219,15 +219,17 @@ Table of contents:
- Bump `AccuDrawWidget`, `SheetNavigationAid`, `StandardRotationNavigationAid` components to `@public`. [#888](https://github.com/iTwin/appui/pull/888)
- No more transitions when toggling themes. [#905](https://github.com/iTwin/appui/pull/905)
- Updated `ToolSettingsPopup` to not rely on event propagation for cancellation. [#928](https://github.com/iTwin/appui/pull/928)
+- Adjusted `SelectionCount` styling to improve its visuals in various scenarios. [#936](https://github.com/iTwin/appui/pull/936)
### Fixes
- Fixed `AccuDrawInputField` to correctly specify keyboard event modifiers in `UiFramework.keyboardShortcuts.processKey()`. [#894](https://github.com/iTwin/appui/pull/894)
- Fixed icon alignment and warning status color of notification manager in `MessageCenterField` component. [#901](https://github.com/iTwin/appui/pull/901)
- Fixed the unintentional "flying-in" of floating elements like Tooltips and ComboBox menus when the page first loads. [#905](https://github.com/iTwin/appui/pull/905)
+- Fixed standard content tools throwing uncaught exception with transient elements. [#934](https://github.com/iTwin/appui/pull/934)
- Fixed `ToolAssistanceField` icon size. [#937](https://github.com/iTwin/appui/pull/937)
- Fixed [mixed-decls](https://sass-lang.com/documentation/breaking-changes/mixed-decls/) Sass warnings. [#939](https://github.com/iTwin/appui/pull/939)
-- Fixed standard content tools throwing uncaught exception with transient elements. [#934](https://github.com/iTwin/appui/pull/934)
+- Fixed an issue where styles of complex shorthand properties were not copied correctly to a popout window. [#940](https://github.com/iTwin/appui/pull/940)
## @itwin/components-react
diff --git a/e2e-tests/tests/popout-widget.test.ts b/e2e-tests/tests/popout-widget.test.ts
index 251b86f2231..66702e058fd 100644
--- a/e2e-tests/tests/popout-widget.test.ts
+++ b/e2e-tests/tests/popout-widget.test.ts
@@ -2,7 +2,7 @@
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
-import { test, expect, Locator, BrowserContext } from "@playwright/test";
+import { test, expect, Locator } from "@playwright/test";
import assert from "assert";
import {
WidgetState,
@@ -23,7 +23,7 @@ test.describe("popout widget", () => {
await page.goto(`${baseURL}?frontstage=appui-test-providers:WidgetApi`);
});
- test("should popout a widget", async ({ context, page }) => {
+ test("should popout a widget", async ({ page }) => {
const widget = floatingWidgetLocator({
page,
id: "appui-test-providers:ViewAttributesWidget",
@@ -31,14 +31,14 @@ test.describe("popout widget", () => {
const tab = tabLocator(page, "View Attributes");
await expect(tab).toBeVisible();
- const popoutPage = await popoutWidget(context, widget);
+ const popoutPage = await popoutWidget(widget);
await expect(popoutPage).toHaveTitle(/View Attributes/);
await expect(tab).not.toBeVisible();
expect(await popoutPage.title()).toEqual("View Attributes");
});
- test("should apply styles to popout", async ({ context, page }) => {
+ test("should apply styles to popout", async ({ page }) => {
const widget = floatingWidgetLocator({
page,
id: "appui-test-providers:ViewAttributesWidget",
@@ -46,18 +46,17 @@ test.describe("popout widget", () => {
const tab = tabLocator(page, "View Attributes");
await expect(tab).toBeVisible();
- const popoutPage = await popoutWidget(context, widget);
+ const popoutPage = await popoutWidget(widget);
await expect(popoutPage.locator("body")).toHaveScreenshot();
});
test("should float a popout widget (after frontstage change)", async ({
- context,
page,
}) => {
const tab = tabLocator(page, "View Attributes");
const widget = widgetLocator({ tab });
- const popoutPage = await popoutWidget(context, widget);
+ const popoutPage = await popoutWidget(widget);
await expect.poll(async () => popoutPage.isClosed()).toBe(false);
await openFrontstage(page, "appui-test-app:main-stage");
@@ -77,7 +76,7 @@ test.describe("popout widget", () => {
const tab = tabLocator(page, "WT-2");
const widget = widgetLocator({ tab });
- const popoutPage = await popoutWidget(context, widget);
+ const popoutPage = await popoutWidget(widget);
await expect.poll(async () => popoutPage.isClosed()).toBe(false);
await openFrontstage(page, "appui-test-app:main-stage");
@@ -90,12 +89,12 @@ test.describe("popout widget", () => {
await expect(locator).toBeVisible();
});
- test("should maintain popout widget bounds", async ({ context, page }) => {
+ test("should maintain popout widget bounds", async ({ page }) => {
const tab = tabLocator(page, "View Attributes");
const widget = widgetLocator({ tab });
// Popout the widget w/ default size.
- let popoutPage = await popoutWidget(context, widget);
+ let popoutPage = await popoutWidget(widget);
await expect(popoutPage).toHaveTitle(/View Attributes/);
const size = popoutPage.viewportSize();
@@ -114,7 +113,7 @@ test.describe("popout widget", () => {
await tab.click();
await expect(tab).toHaveClass(/nz-active/);
- popoutPage = await popoutWidget(context, widget);
+ popoutPage = await popoutWidget(widget);
expect(popoutPage.viewportSize()).toEqual({
height: 400,
width: 300,
@@ -128,7 +127,7 @@ test.describe("popout widget", () => {
const tab = tabLocator(page, "View Attributes");
const widget = widgetLocator({ tab });
- let popoutPage = await popoutWidget(context, widget);
+ let popoutPage = await popoutWidget(widget);
await expect(popoutPage).toHaveTitle(/View Attributes/);
// Update widget size and close the popout.
@@ -150,24 +149,20 @@ test.describe("popout widget", () => {
await page.reload();
- popoutPage = await popoutWidget(context, widget);
+ popoutPage = await popoutWidget(widget);
expect(popoutPage.viewportSize()).toEqual({
height: 400,
width: 300,
});
});
- test("should close a popout (when floating a widget)", async ({
- context,
- page,
- }) => {
+ test("should close a popout (when floating a widget)", async ({ page }) => {
const widget = floatingWidgetLocator({
page,
id: "appui-test-providers:ViewAttributesWidget",
});
- const popoutPage = await popoutWidget(context, widget);
- await popoutPage.waitForLoadState(); // TODO: childWindow is only added after 'load' event
+ const popoutPage = await popoutWidget(widget);
await expect.poll(async () => popoutPage.isClosed()).toBe(false);
await setWidgetState(
@@ -178,10 +173,7 @@ test.describe("popout widget", () => {
await expect.poll(async () => popoutPage.isClosed()).toBe(true);
});
- test("should unmount when popped out widget is closed", async ({
- context,
- page,
- }) => {
+ test("should unmount when popped out widget is closed", async ({ page }) => {
const id = "appui-test-providers:PopoutMountUnmountWidget";
const widget = floatingWidgetLocator({
page,
@@ -189,7 +181,7 @@ test.describe("popout widget", () => {
});
await expect(widget).toBeVisible();
const widgetLifecycle = trackWidgetLifecycle(page, id);
- const popoutPage = await popoutWidget(context, widget);
+ const popoutPage = await popoutWidget(widget);
await expect.poll(async () => popoutPage.isClosed()).toBe(false);
await popoutPage.close();
@@ -199,7 +191,20 @@ test.describe("popout widget", () => {
});
});
-async function popoutWidget(context: BrowserContext, widget: Locator) {
+test("should copy styles", async ({ baseURL, page }) => {
+ assert(baseURL);
+ await page.goto(`${baseURL}?frontstage=appui-test-app:TestPopout`);
+
+ const tab = tabLocator(page, "Widget 1");
+ const widget = widgetLocator({ tab });
+
+ const popoutPage = await popoutWidget(widget);
+ const borders = popoutPage.locator("#border-test");
+ await expect(borders).toHaveScreenshot();
+});
+
+async function popoutWidget(widget: Locator) {
+ const context = widget.page().context();
const popoutButton = popoutButtonLocator(widget);
const [popoutPage] = await Promise.all([
context.waitForEvent("page"),
diff --git a/e2e-tests/tests/popout-widget.test.ts-snapshots/should-copy-styles-1-chromium-linux.png b/e2e-tests/tests/popout-widget.test.ts-snapshots/should-copy-styles-1-chromium-linux.png
new file mode 100644
index 00000000000..9f570f0977b
Binary files /dev/null and b/e2e-tests/tests/popout-widget.test.ts-snapshots/should-copy-styles-1-chromium-linux.png differ
diff --git a/e2e-tests/tests/settings/ui-settings-page.test.ts-snapshots/ui-settings-page-test-1-chromium-linux.png b/e2e-tests/tests/settings/ui-settings-page.test.ts-snapshots/ui-settings-page-test-1-chromium-linux.png
index 1b836bfd56f..33f47fae19d 100644
Binary files a/e2e-tests/tests/settings/ui-settings-page.test.ts-snapshots/ui-settings-page-test-1-chromium-linux.png and b/e2e-tests/tests/settings/ui-settings-page.test.ts-snapshots/ui-settings-page-test-1-chromium-linux.png differ
diff --git a/e2e-tests/tests/stage-panel.test.ts b/e2e-tests/tests/stage-panel.test.ts
index cdf2b595189..7de9b7db59d 100644
--- a/e2e-tests/tests/stage-panel.test.ts
+++ b/e2e-tests/tests/stage-panel.test.ts
@@ -65,7 +65,7 @@ test.describe("WidgetApi", () => {
test("should initialize defaults", async ({ baseURL, page }) => {
assert(baseURL);
- await page.goto(`${baseURL}?frontstage=appui-test-providers:TestFrontstage`);
+ await page.goto(`${baseURL}?frontstage=appui-test-app:TestPanel`);
const panel = panelLocator({ page, side: "left" });
await expect(panel).toBeVisible();
@@ -74,9 +74,7 @@ test("should initialize defaults", async ({ baseURL, page }) => {
test("should initialize size", async ({ baseURL, page }) => {
assert(baseURL);
- await page.goto(
- `${baseURL}?frontstage=appui-test-providers:TestFrontstage&size=500`
- );
+ await page.goto(`${baseURL}?frontstage=appui-test-app:TestPanel&size=500`);
const panel = panelLocator({ page, side: "left" });
await expect(panel).toBeVisible();
@@ -86,7 +84,7 @@ test("should initialize size", async ({ baseURL, page }) => {
test("should initialize minimized", async ({ baseURL, page }) => {
assert(baseURL);
await page.goto(
- `${baseURL}?frontstage=appui-test-providers:TestFrontstage&defaultState=${StagePanelState.Minimized}`
+ `${baseURL}?frontstage=appui-test-app:TestPanel&defaultState=${StagePanelState.Minimized}`
);
const panel = panelLocator({ page, side: "left" });
@@ -97,9 +95,7 @@ test("should initialize minimized", async ({ baseURL, page }) => {
test("should initialize resizable", async ({ baseURL, page }) => {
assert(baseURL);
- await page.goto(
- `${baseURL}?frontstage=appui-test-providers:TestFrontstage&resizable=0`
- );
+ await page.goto(`${baseURL}?frontstage=appui-test-app:TestPanel&resizable=0`);
const panel = panelLocator({ page, side: "left" });
const handle = handleLocator(panel);
@@ -108,7 +104,7 @@ test("should initialize resizable", async ({ baseURL, page }) => {
test("should resize (single panel)", async ({ baseURL, page }) => {
assert(baseURL);
- await page.goto(`${baseURL}?frontstage=appui-test-providers:TestFrontstage`);
+ await page.goto(`${baseURL}?frontstage=appui-test-app:TestPanel`);
const panel = panelLocator({ page, side: "left" });
const handle = handleLocator(panel);
diff --git a/test-apps/appui-test-app/appui-test-providers/src/appui-test-providers.ts b/test-apps/appui-test-app/appui-test-providers/src/appui-test-providers.ts
index bf535d8e0d5..06b483e42a9 100644
--- a/test-apps/appui-test-app/appui-test-providers/src/appui-test-providers.ts
+++ b/test-apps/appui-test-app/appui-test-providers/src/appui-test-providers.ts
@@ -23,7 +23,6 @@ export * from "./ui/frontstages/CustomFrontstageProvider";
export * from "./ui/frontstages/PopoutWindowsFrontstage";
export * from "./ui/frontstages/registerCustomFrontstage";
export * from "./ui/frontstages/SynchronizedFloatingViewport";
-export * from "./ui/frontstages/TestFrontstageProvider";
export * from "./ui/frontstages/WidgetApiStage";
export * from "./ui/ViewportContent";
diff --git a/test-apps/appui-test-app/standalone/src/frontend/appui/frontstages/TestPanelFrontstage.tsx b/test-apps/appui-test-app/standalone/src/frontend/appui/frontstages/TestPanelFrontstage.tsx
new file mode 100644
index 00000000000..595d957583f
--- /dev/null
+++ b/test-apps/appui-test-app/standalone/src/frontend/appui/frontstages/TestPanelFrontstage.tsx
@@ -0,0 +1,43 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
+ * See LICENSE.md in the project root for license terms and full copyright notice.
+ *--------------------------------------------------------------------------------------------*/
+import * as React from "react";
+import { Frontstage } from "@itwin/appui-react";
+import { createTestFrontstage } from "./createTestFrontstage";
+
+/** Used in e2e tests to test different panel configurations. */
+export const createTestPanelFrontstage = () => {
+ {
+ const urlParams = new URLSearchParams(window.location.search);
+ const size = urlParams.get("size");
+ const defaultState = urlParams.get("defaultState");
+ const resizable = urlParams.get("resizable");
+
+ const frontstage = createTestFrontstage({
+ id: "appui-test-app:TestPanel",
+ });
+
+ return {
+ ...frontstage,
+ leftPanel: {
+ sizeSpec: size ? Number(size) : undefined,
+ defaultState: defaultState ? Number(defaultState) : undefined,
+ resizable: resizable ? Boolean(Number(resizable)) : undefined,
+ sections: {
+ start: [
+ {
+ id: "widget-1",
+ label: "Widget 1",
+ content: (
+ <>
+ Frontstage provided widget: widget-1
+ >
+ ),
+ },
+ ],
+ },
+ },
+ } satisfies Frontstage;
+ }
+};
diff --git a/test-apps/appui-test-app/standalone/src/frontend/appui/frontstages/TestPopoutFrontstage.scss b/test-apps/appui-test-app/standalone/src/frontend/appui/frontstages/TestPopoutFrontstage.scss
new file mode 100644
index 00000000000..0b64c0b4c0a
--- /dev/null
+++ b/test-apps/appui-test-app/standalone/src/frontend/appui/frontstages/TestPopoutFrontstage.scss
@@ -0,0 +1,11 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
+ * See LICENSE.md in the project root for license terms and full copyright notice.
+ *--------------------------------------------------------------------------------------------*/
+#border-test {
+ --border-color: red;
+ border: 5px solid var(--border-color);
+ border-bottom: 5px solid blue;
+ height: 20px;
+ width: 100px;
+}
diff --git a/test-apps/appui-test-app/standalone/src/frontend/appui/frontstages/TestPopoutFrontstage.tsx b/test-apps/appui-test-app/standalone/src/frontend/appui/frontstages/TestPopoutFrontstage.tsx
new file mode 100644
index 00000000000..641baa2777f
--- /dev/null
+++ b/test-apps/appui-test-app/standalone/src/frontend/appui/frontstages/TestPopoutFrontstage.tsx
@@ -0,0 +1,50 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
+ * See LICENSE.md in the project root for license terms and full copyright notice.
+ *--------------------------------------------------------------------------------------------*/
+import "./TestPopoutFrontstage.scss";
+import * as React from "react";
+import { Frontstage } from "@itwin/appui-react";
+import { createTestFrontstage } from "./createTestFrontstage";
+
+export const createTestPopoutFrontstage = () => {
+ {
+ const frontstage = createTestFrontstage({
+ id: "appui-test-app:TestPopout",
+ });
+
+ return {
+ ...frontstage,
+ leftPanel: {
+ sections: {
+ start: [
+ {
+ id: "widget-1",
+ label: "Widget 1",
+ canPopout: true,
+ content: (
+ <>
+
Widget 1 content
+
+ >
+ ),
+ },
+ ],
+ },
+ },
+ } satisfies Frontstage;
+ }
+};
+
+(() => {
+ const sheet = new CSSStyleSheet();
+ // Shorthand `border` property from `adoptedStyleSheets` will not be copied to a popout widget correctly.
+ sheet.replaceSync(`
+ #border-test {
+ --border-top-color: yellow;
+ border-top: 5px solid var(--border-top-color);
+ border-right: 5px solid green;
+ }
+ `);
+ document.adoptedStyleSheets.push(sheet);
+})();
diff --git a/test-apps/appui-test-app/appui-test-providers/src/ui/frontstages/TestFrontstageProvider.tsx b/test-apps/appui-test-app/standalone/src/frontend/appui/frontstages/createTestFrontstage.tsx
similarity index 64%
rename from test-apps/appui-test-app/appui-test-providers/src/ui/frontstages/TestFrontstageProvider.tsx
rename to test-apps/appui-test-app/standalone/src/frontend/appui/frontstages/createTestFrontstage.tsx
index 80d72cbb72e..fc2879f7818 100644
--- a/test-apps/appui-test-app/appui-test-providers/src/ui/frontstages/TestFrontstageProvider.tsx
+++ b/test-apps/appui-test-app/standalone/src/frontend/appui/frontstages/createTestFrontstage.tsx
@@ -3,13 +3,16 @@
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
import * as React from "react";
-import { ContentGroup } from "@itwin/appui-react";
+import { ContentGroup, Frontstage } from "@itwin/appui-react";
import { StandardContentLayouts } from "@itwin/appui-abstract";
+interface CreateTestFrontstageArgs {
+ id: string;
+}
+
/** Used in e2e tests to test different configurations. */
-export const testFrontstageProvider = (() => {
+export const createTestFrontstage = ({ id }: CreateTestFrontstageArgs) => {
{
- const id = "appui-test-providers:TestFrontstage";
const contentGroup = new ContentGroup({
id: "test-group",
layout: StandardContentLayouts.singleView,
@@ -33,32 +36,22 @@ export const testFrontstageProvider = (() => {
],
});
- const urlParams = new URLSearchParams(window.location.search);
- const size = urlParams.get("size");
- const defaultState = urlParams.get("defaultState");
- const resizable = urlParams.get("resizable");
return {
id,
version: Math.random(),
contentGroup,
leftPanel: {
- sizeSpec: size ? Number(size) : undefined,
- defaultState: defaultState ? Number(defaultState) : undefined,
- resizable: resizable ? Boolean(Number(resizable)) : undefined,
sections: {
start: [
{
id: "widget-1",
label: "Widget 1",
- content: (
- <>
- Frontstage provided widget: widget-1
- >
- ),
+ canPopout: true,
+ content: <>Widget 1 content>,
},
],
},
},
- };
+ } satisfies Frontstage;
}
-})();
+};
diff --git a/test-apps/appui-test-app/standalone/src/frontend/index.tsx b/test-apps/appui-test-app/standalone/src/frontend/index.tsx
index 596f2040226..92b2da0ea69 100644
--- a/test-apps/appui-test-app/standalone/src/frontend/index.tsx
+++ b/test-apps/appui-test-app/standalone/src/frontend/index.tsx
@@ -102,7 +102,6 @@ import {
previewFeaturesToggleProvider,
registerCustomFrontstage,
SynchronizedFloatingViewportStage,
- testFrontstageProvider,
WidgetApiStage,
WidgetContentProvider,
} from "@itwin/appui-test-providers";
@@ -122,6 +121,8 @@ import {
createElementStackingFrontstage,
createElementStackingProvider,
} from "./appui/frontstages/ElementStacking";
+import { createTestPanelFrontstage } from "./appui/frontstages/TestPanelFrontstage";
+import { createTestPopoutFrontstage } from "./appui/frontstages/TestPopoutFrontstage";
// Initialize my application gateway configuration for the frontend
RpcConfiguration.developmentMode = true;
@@ -278,6 +279,7 @@ export class SampleAppIModelApp {
public static async initialize() {
// eslint-disable-next-line deprecation/deprecation
await UiFramework.initialize(undefined, undefined);
+ UiFramework.visibility.autoHideUi = false;
IModelApp.toolAdmin.defaultToolId = SelectionTool.toolId;
@@ -389,7 +391,8 @@ export class SampleAppIModelApp {
CustomContentFrontstage.register(AppUiTestProviders.localizationNamespace);
WidgetApiStage.register(AppUiTestProviders.localizationNamespace);
ContentLayoutStage.register(AppUiTestProviders.localizationNamespace);
- UiFramework.frontstages.addFrontstage(testFrontstageProvider);
+ UiFramework.frontstages.addFrontstage(createTestPanelFrontstage());
+ UiFramework.frontstages.addFrontstage(createTestPopoutFrontstage());
registerCustomFrontstage();
SynchronizedFloatingViewportStage.register(
AppUiTestProviders.localizationNamespace
diff --git a/ui/appui-react/src/appui-react/childwindow/CopyStyles.ts b/ui/appui-react/src/appui-react/childwindow/CopyStyles.ts
index 7319b1caf46..53fd78b5ad6 100644
--- a/ui/appui-react/src/appui-react/childwindow/CopyStyles.ts
+++ b/ui/appui-react/src/appui-react/childwindow/CopyStyles.ts
@@ -2,39 +2,35 @@
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
-/**
- * Copies the source CSS into the destination
- * @param targetDoc - target document
- * @param sourceDoc - source document
+
+/** Copies the CSS style sheets from source document into the target document.
* @internal
*/
export function copyStyles(
targetDoc: Document,
sourceDoc: Document = document
) {
- const stylesheets = sourceDoc.adoptedStyleSheets
- ? Array.from([...sourceDoc.styleSheets, ...sourceDoc.adoptedStyleSheets])
- : Array.from(sourceDoc.styleSheets);
+ const styleSheets = Array.from(sourceDoc.styleSheets);
+ styleSheets.forEach(({ ownerNode }) => {
+ // Copy `link` and `style` elements.
+ if (!ownerNode) return;
+ const clonedNode = targetDoc.importNode(ownerNode, true);
+ targetDoc.head.appendChild(clonedNode);
+ });
- stylesheets.forEach((stylesheet) => {
- const css = stylesheet;
- if (stylesheet.href) {
- const newStyleElement = targetDoc.createElement("link");
- newStyleElement.rel = "stylesheet";
- newStyleElement.href = stylesheet.href;
- targetDoc.head.appendChild(newStyleElement);
- } else {
- if (css && css.cssRules && css.cssRules.length > 0) {
- const newStyleElement = targetDoc.createElement("style");
- Array.from(css.cssRules).forEach((rule) => {
- newStyleElement.appendChild(targetDoc.createTextNode(rule.cssText));
- });
- targetDoc.head.appendChild(newStyleElement);
- }
- }
+ const adoptedStyleSheets = Array.from(sourceDoc.adoptedStyleSheets ?? []);
+ adoptedStyleSheets.forEach((styleSheet) => {
+ // Adopted stylesheet have no ownerNode and can't be shared between multiple documents.
+ if (!targetDoc.defaultView) return;
+ const newStyleSheet = new targetDoc.defaultView.CSSStyleSheet();
+ Array.from(styleSheet.cssRules).forEach((rule, index) => {
+ // `cssText` might not serialize complex shorthand properties correctly: https://github.com/iTwin/appui/issues/893
+ newStyleSheet.insertRule(rule.cssText, index);
+ });
+ targetDoc.adoptedStyleSheets.push(newStyleSheet);
});
- // copy sprites
+ // Copy sprites.
const svgSymbolParent = sourceDoc.getElementById("__SVG_SPRITE_NODE__");
if (svgSymbolParent) {
targetDoc.body.appendChild(svgSymbolParent.cloneNode(true));
diff --git a/ui/appui-react/src/appui-react/preview/PreviewFeatures.tsx b/ui/appui-react/src/appui-react/preview/PreviewFeatures.tsx
index b2847b5777c..71d904d8e81 100644
--- a/ui/appui-react/src/appui-react/preview/PreviewFeatures.tsx
+++ b/ui/appui-react/src/appui-react/preview/PreviewFeatures.tsx
@@ -47,17 +47,24 @@ interface KnownPreviewFeatures {
* Discuss or upvote this feature: https://github.com/iTwin/appui/discussions/723
*/
widgetActionDropdown: { threshold: number };
- /** If `true`, the [[Toolbar]] component will be replaced by a new iTwinUI based toolbar. */
+ /** If `true`, the [[Toolbar]] component will be replaced by a new iTwinUI based toolbar.
+ *
+ * Discuss or upvote this feature: https://github.com/iTwin/appui/discussions/924
+ */
newToolbars: boolean;
/** If `true`, popout widgets will not be rendered in a separate element tree, instead widget content will be re-parented to a popout content container.
* Alternatively, an array of widget ids can be specified to only re-parent specific widgets.
* @note Use {@link useTransientState} to save and restore DOM transient state when re-parenting widgets.
* @note There is a known limitation where iTwinUI v2 popover elements will be rendered in the main window. Prefer using iTwinUI v3 when using this feature.
+ *
+ * Discuss or upvote this feature: https://github.com/iTwin/appui/discussions/925
*/
reparentPopoutWidgets: boolean | WidgetDef["id"][];
/** If `true`, additional UI elements are rendered to allow the end user of the layout to control widget visibility.
* Alternatively, an array of widget ids can be specified to only control specific widgets.
* @note Use {@link UiItemsManager} APIs to manage what widgets are available to the end-user.
+ *
+ * Discuss or upvote this feature: https://github.com/iTwin/appui/discussions/859
*/
controlWidgetVisibility: boolean | WidgetDef["id"][];
}
diff --git a/ui/appui-react/src/appui-react/statusbar/StatusBar.scss b/ui/appui-react/src/appui-react/statusbar/StatusBar.scss
index ad973ddd2a6..e23f62255a7 100644
--- a/ui/appui-react/src/appui-react/statusbar/StatusBar.scss
+++ b/ui/appui-react/src/appui-react/statusbar/StatusBar.scss
@@ -21,7 +21,7 @@
}
}
-.uifw-statusbar-space-between {
+.uifw-statusBar-space-between {
width: 100%;
height: 100%;
display: flex;
@@ -29,29 +29,29 @@
justify-content: space-between;
}
-.uifw-statusbar-left {
+.uifw-statusBar-left {
display: flex;
flex-direction: row;
justify-content: flex-start;
}
-.uifw-statusbar-center {
+.uifw-statusBar-center {
display: flex;
flex-direction: row;
justify-content: center;
}
-.uifw-statusbar-right {
+.uifw-statusBar-right {
display: flex;
flex-direction: row;
justify-content: flex-end;
}
-.uifw-statusbar-docked {
+.uifw-statusBar-docked {
width: 100%;
background-color: var(--iui-color-background);
- .uifw-statusbar-item-container {
+ .uifw-statusBar-item-container {
@include for-medium-desktop-up {
padding-left: var(--iui-size-m);
}
@@ -67,20 +67,20 @@
&:has(.uifw-statusBar-separator) {
padding-left: 0;
- + .uifw-statusbar-item-container {
+ + .uifw-statusBar-item-container {
padding-left: 0;
}
}
}
- .uifw-statusbar-left .uifw-statusbar-item-container {
+ .uifw-statusBar-left .uifw-statusBar-item-container {
&:first-child {
padding-left: 0;
}
}
}
-.uifw-statusbar-item-container {
+.uifw-statusBar-item-container {
height: 100%;
display: flex;
flex-direction: row;
diff --git a/ui/appui-react/src/appui-react/statusbar/StatusBar.tsx b/ui/appui-react/src/appui-react/statusbar/StatusBar.tsx
index 7394b6564f5..dc47a4a2ed7 100644
--- a/ui/appui-react/src/appui-react/statusbar/StatusBar.tsx
+++ b/ui/appui-react/src/appui-react/statusbar/StatusBar.tsx
@@ -64,7 +64,7 @@ export function StatusBarSpaceBetween(props: CommonDivProps) {
return (
);
}
@@ -77,7 +77,7 @@ export function StatusBarLeftSection(props: CommonDivProps) {
return (
);
}
@@ -90,7 +90,7 @@ export function StatusBarCenterSection(props: CommonDivProps) {
return (
);
}
@@ -103,7 +103,7 @@ export function StatusBarRightSection(props: CommonDivProps) {
return (
);
}
diff --git a/ui/appui-react/src/appui-react/statusbar/StatusBarComposer.tsx b/ui/appui-react/src/appui-react/statusbar/StatusBarComposer.tsx
index 6ea202a818a..afc7157e878 100644
--- a/ui/appui-react/src/appui-react/statusbar/StatusBarComposer.tsx
+++ b/ui/appui-react/src/appui-react/statusbar/StatusBarComposer.tsx
@@ -39,6 +39,7 @@ import {
import { StatusBarItemsManager } from "./StatusBarItemsManager";
import { useDefaultStatusBarItems } from "./useDefaultStatusBarItems";
import { useUiItemsProviderStatusBarItems } from "./useUiItemsProviderStatusBarItems";
+import { StatusBarCornerComponentContext } from "./StatusBarCornerComponentContext";
/** Private function to generate a value that will allow the proper order to be maintained when items are placed in overflow panel */
function getCombinedSectionItemPriority(item: StatusBarItem) {
@@ -82,7 +83,7 @@ export function DockedStatusBarItem(props: StatusBarItemProps) {
const { onResize } = useStatusBarEntry();
const ref = useResizeObserver(onResize);
const className = classnames(
- "uifw-statusbar-item-container",
+ "uifw-statusBar-item-container",
props.className
);
return (
@@ -344,6 +345,11 @@ export function StatusBarComposer(props: StatusBarComposerProps) {
const combinedItems = combineItems(defaultItems, addonItems);
return sortItems(combinedItems);
}, [defaultItems, addonItems]);
+ const itemsNotInOverflow = React.useMemo(() => {
+ return statusBarItems.filter(
+ (item) => !isItemInOverflow(item.id, overflown)
+ );
+ }, [overflown, statusBarItems]);
const calculateOverflow = React.useCallback(() => {
const widths = verifiedMapEntries(entryWidths.current);
@@ -432,18 +438,31 @@ export function StatusBarComposer(props: StatusBarComposerProps) {
providerId={providerId}
section={getSectionName(section)}
>
- {isStatusBarCustomItem(item) && item.content}
- {isStatusBarActionItem(item) && (
-
- )}
- {isStatusBarLabelItem(item) && (
-
- )}
+
+ {isStatusBarCustomItem(item) && item.content}
+ {isStatusBarActionItem(item) && (
+
+ )}
+ {isStatusBarLabelItem(item) && (
+
+ )}
+
);
},
- [handleEntryResize]
+ [handleEntryResize, itemsNotInOverflow, overflown]
);
const getSectionItems = React.useCallback(
@@ -530,7 +549,7 @@ export function StatusBarComposer(props: StatusBarComposerProps) {
[getOverflowItems]
);
- const containerClassName = classnames("uifw-statusbar-docked", className);
+ const containerClassName = classnames("uifw-statusBar-docked", className);
return (
(undefined);
diff --git a/ui/appui-react/src/appui-react/statusfields/SelectionCount.scss b/ui/appui-react/src/appui-react/statusfields/SelectionCount.scss
index cd45b2dc17c..a6d1d5b4ba1 100644
--- a/ui/appui-react/src/appui-react/statusfields/SelectionCount.scss
+++ b/ui/appui-react/src/appui-react/statusfields/SelectionCount.scss
@@ -6,9 +6,18 @@
gap: var(--iui-size-2xs);
display: flex;
align-items: center;
- padding: 0 var(--iui-size-2xs) 0 var(--iui-size-2xs);
+ min-width: var(--iui-size-2xl);
+ padding-left: var(--iui-size-2xs);
.icon {
color: var(--iui-color-icon);
}
+
+ &.uifw-left-corner {
+ margin-left: var(--iui-size-m);
+ }
+
+ &.uifw-right-corner {
+ margin-right: var(--iui-size-m);
+ }
}
diff --git a/ui/appui-react/src/appui-react/statusfields/SelectionCount.tsx b/ui/appui-react/src/appui-react/statusfields/SelectionCount.tsx
index fbf6afa7400..bc98a4bc741 100644
--- a/ui/appui-react/src/appui-react/statusfields/SelectionCount.tsx
+++ b/ui/appui-react/src/appui-react/statusfields/SelectionCount.tsx
@@ -6,12 +6,13 @@
* @module StatusBar
*/
+import * as React from "react";
import type { IModelConnection } from "@itwin/core-frontend";
import type { CommonProps } from "@itwin/core-react";
import { Icon } from "@itwin/core-react";
import { SvgCursor } from "@itwin/itwinui-icons-react";
import classnames from "classnames";
-import * as React from "react";
+import { StatusBarCornerComponentContext } from "../statusbar/StatusBarCornerComponentContext";
import "./SelectionCount.scss";
/** Properties for the [[SelectionCountField]] component.
@@ -27,8 +28,11 @@ export interface SelectionCountFieldProps extends CommonProps {
* @beta
*/
export function SelectionCountField(props: SelectionCountFieldProps) {
+ const cornerContext = React.useContext(StatusBarCornerComponentContext);
const className = classnames(
"uifw-statusFields-selectionCount",
+ cornerContext === "left-corner" && "uifw-left-corner",
+ cornerContext === "right-corner" && "uifw-right-corner",
props.className
);
return (
diff --git a/ui/appui-react/src/appui-react/ui-items-provider/StandardStatusbarItemsProvider.tsx b/ui/appui-react/src/appui-react/ui-items-provider/StandardStatusbarItemsProvider.tsx
index b7a87282901..124a1f45982 100644
--- a/ui/appui-react/src/appui-react/ui-items-provider/StandardStatusbarItemsProvider.tsx
+++ b/ui/appui-react/src/appui-react/ui-items-provider/StandardStatusbarItemsProvider.tsx
@@ -12,8 +12,7 @@ import type { StatusBarItem } from "../statusbar/StatusBarItem";
import { UiItemsManager } from "./UiItemsManager";
import { BaseUiItemsProvider } from "./BaseUiItemsProvider";
-/**
- * Provide standard statusbar fields for the SimpleStatusbarWidget
+/** Provide standard status bar fields.
* @public
*/
export class StandardStatusbarItemsProvider extends BaseUiItemsProvider {
diff --git a/ui/appui-react/src/appui-react/ui-items-provider/StandardStatusbarUiItemsProvider.tsx b/ui/appui-react/src/appui-react/ui-items-provider/StandardStatusbarUiItemsProvider.tsx
index 9ce8811b04b..68e2697cc52 100644
--- a/ui/appui-react/src/appui-react/ui-items-provider/StandardStatusbarUiItemsProvider.tsx
+++ b/ui/appui-react/src/appui-react/ui-items-provider/StandardStatusbarUiItemsProvider.tsx
@@ -20,9 +20,8 @@ import type { UiItemsProvider } from "./UiItemsProvider";
import type { StatusBarItem } from "../statusbar/StatusBarItem";
import { StatusBarSection } from "../statusbar/StatusBarItem";
-/**
- * Defines what items to include from the provider. If any items are
- * specified then only those items will be added to statusbar.
+/** Defines what items to include from the provider.
+ * @note When this object is used, only explicitly enabled items will be added to the status bar. I.e. `{ messageCenter: true }` will only add message center field to the statusbar.
* @public
*/
export interface DefaultStatusbarItems {
@@ -38,8 +37,7 @@ export interface DefaultStatusbarItems {
selectionInfo?: boolean;
}
-/**
- * Provide standard statusbar fields for the SimpleStatusbarWidget
+/** Provide standard status bar fields.
* @beta
*/
export class StandardStatusbarUiItemsProvider implements UiItemsProvider {
@@ -47,6 +45,7 @@ export class StandardStatusbarUiItemsProvider implements UiItemsProvider {
return "appui-react:StandardStatusbarUiItemsProvider";
}
+ /** Creates a provider. If the `defaultItems` argument is not set, all default fields are added. Otherwise, only the fields that are set to `true` are added. */
constructor(private _defaultItems?: DefaultStatusbarItems) {}
public provideStatusBarItems(
diff --git a/ui/appui-react/src/test/statusbar/StatusBar.test.tsx b/ui/appui-react/src/test/statusbar/StatusBar.test.tsx
index 0be8f7eabb3..11b45205a09 100644
--- a/ui/appui-react/src/test/statusbar/StatusBar.test.tsx
+++ b/ui/appui-react/src/test/statusbar/StatusBar.test.tsx
@@ -65,7 +65,7 @@ describe("StatusBar", () => {
Hello
);
expect(
- container.querySelectorAll("div.uifw-statusbar-space-between").length
+ container.querySelectorAll("div.uifw-statusBar-space-between").length
).toEqual(1);
});
@@ -74,7 +74,7 @@ describe("StatusBar", () => {
Hello
);
expect(
- container.querySelectorAll("div.uifw-statusbar-left").length
+ container.querySelectorAll("div.uifw-statusBar-left").length
).toEqual(1);
});
@@ -83,7 +83,7 @@ describe("StatusBar", () => {
Hello
);
expect(
- container.querySelectorAll("div.uifw-statusbar-center").length
+ container.querySelectorAll("div.uifw-statusBar-center").length
).toEqual(1);
});
@@ -92,7 +92,7 @@ describe("StatusBar", () => {
Hello
);
expect(
- container.querySelectorAll("div.uifw-statusbar-right").length
+ container.querySelectorAll("div.uifw-statusBar-right").length
).toEqual(1);
});
});
diff --git a/ui/appui-react/src/test/statusbar/StatusBarComposer.test.tsx b/ui/appui-react/src/test/statusbar/StatusBarComposer.test.tsx
index fa09b7515bd..94e218fd8c8 100644
--- a/ui/appui-react/src/test/statusbar/StatusBarComposer.test.tsx
+++ b/ui/appui-react/src/test/statusbar/StatusBarComposer.test.tsx
@@ -129,7 +129,7 @@ describe("StatusBarComposer", () => {
render();
expect(screen.getByRole("presentation")).to.satisfy(
- childStructure(".uifw-statusbar-space-between")
+ childStructure(".uifw-statusBar-space-between")
);
});
@@ -158,13 +158,13 @@ describe("StatusBarComposer", () => {
render();
expect(screen.getByTestId("item1").parentElement).to.satisfy(
- selectorMatches(".uifw-statusbar-left .uifw-statusbar-item-container")
+ selectorMatches(".uifw-statusBar-left .uifw-statusBar-item-container")
);
expect(screen.getByTestId("item2").parentElement).to.satisfy(
- selectorMatches(".uifw-statusbar-center .uifw-statusbar-item-container")
+ selectorMatches(".uifw-statusBar-center .uifw-statusBar-item-container")
);
expect(screen.getByTestId("item3").parentElement).to.satisfy(
- selectorMatches(".uifw-statusbar-right .uifw-statusbar-item-container")
+ selectorMatches(".uifw-statusBar-right .uifw-statusBar-item-container")
);
});
@@ -181,7 +181,7 @@ describe("StatusBarComposer", () => {
const { rerender } = render();
expect(screen.getByTestId("item1").parentElement).to.satisfy(
- selectorMatches(".uifw-statusbar-left .uifw-statusbar-item-container")
+ selectorMatches(".uifw-statusBar-left .uifw-statusBar-item-container")
);
const items2: StatusBarItem[] = [
@@ -197,7 +197,7 @@ describe("StatusBarComposer", () => {
expect(screen.queryByTestId("item1")).toEqual(null);
expect(screen.getByTestId("item2").parentElement).to.satisfy(
- selectorMatches(".uifw-statusbar-center .uifw-statusbar-item-container")
+ selectorMatches(".uifw-statusBar-center .uifw-statusBar-item-container")
);
});
@@ -253,7 +253,7 @@ describe("StatusBarComposer", () => {
expect(screen.queryByTestId("item1")).toEqual(null);
expect(screen.getByTestId("item2").parentElement).to.satisfy(
- selectorMatches(".uifw-statusbar-left .uifw-statusbar-item-container")
+ selectorMatches(".uifw-statusBar-left .uifw-statusBar-item-container")
);
});
@@ -297,9 +297,9 @@ describe("StatusBarComposer", () => {
await waitFor(() =>
expect(screen.getByRole("presentation")).to.satisfy(
childStructure([
- ".uifw-statusbar-left .uifw-statusbar-item-container:only-child",
- ".uifw-statusbar-center .icon-visibility-hide-2",
- ".uifw-statusbar-center .icon-hand-2",
+ ".uifw-statusBar-left .uifw-statusBar-item-container:only-child",
+ ".uifw-statusBar-center .icon-visibility-hide-2",
+ ".uifw-statusBar-center .icon-hand-2",
])
)
);
@@ -308,7 +308,7 @@ describe("StatusBarComposer", () => {
await waitFor(() =>
expect(screen.getByRole("presentation")).to.satisfy(
- childStructure(".uifw-statusbar-center:empty")
+ childStructure(".uifw-statusBar-center:empty")
)
);
});
@@ -351,10 +351,10 @@ describe("StatusBarComposer", () => {
expect(screen.getByRole("presentation")).to.satisfy(
childStructure([
- ".uifw-statusbar-left .uifw-statusbar-item-container:only-child",
- ".uifw-statusbar-center .icon-visibility-hide-2",
- ".uifw-statusbar-center .icon-hand-2",
- ".uifw-statusbar-center .icon-hand-2-condition",
+ ".uifw-statusBar-left .uifw-statusBar-item-container:only-child",
+ ".uifw-statusBar-center .icon-visibility-hide-2",
+ ".uifw-statusBar-center .icon-hand-2",
+ ".uifw-statusBar-center .icon-hand-2-condition",
])
);
@@ -362,7 +362,7 @@ describe("StatusBarComposer", () => {
await waitFor(() => {
expect(screen.getByRole("presentation")).to.not.satisfy(
- childStructure([".uifw-statusbar-center .icon-hand-2-condition"])
+ childStructure([".uifw-statusBar-center .icon-hand-2-condition"])
);
});
@@ -370,7 +370,7 @@ describe("StatusBarComposer", () => {
await waitFor(() =>
expect(screen.getByRole("presentation")).to.satisfy(
- childStructure(".uifw-statusbar-center:empty")
+ childStructure(".uifw-statusBar-center:empty")
)
);
});
@@ -409,9 +409,9 @@ describe("StatusBarComposer", () => {
expect(screen.getByRole("presentation")).to.satisfy(
childStructure([
- ".main-test :not(.uifw-statusbar-left).left-test > .uifw-statusbar-item-container",
- ".main-test :not(.uifw-statusbar-center).center-test > .uifw-statusbar-item-container",
- ".main-test :not(.uifw-statusbar-right).right-test > .uifw-statusbar-item-container",
+ ".main-test :not(.uifw-statusBar-left).left-test > .uifw-statusBar-item-container",
+ ".main-test :not(.uifw-statusBar-center).center-test > .uifw-statusBar-item-container",
+ ".main-test :not(.uifw-statusBar-right).right-test > .uifw-statusBar-item-container",
])
);
});
@@ -436,9 +436,9 @@ describe("StatusBarComposer", () => {
// make sure we have enough size to render without overflow
vi.spyOn(Element.prototype, "getBoundingClientRect").mockImplementation(
function (this: HTMLElement) {
- if (this.classList.contains("uifw-statusbar-docked")) {
+ if (this.classList.contains("uifw-statusBar-docked")) {
return DOMRect.fromRect({ width: 1000 });
- } else if (this.classList.contains("uifw-statusbar-item-container")) {
+ } else if (this.classList.contains("uifw-statusBar-item-container")) {
return DOMRect.fromRect({ width: 40 });
} else if (this instanceof HTMLButtonElement) {
return DOMRect.fromRect({ width: 40 });
@@ -466,7 +466,7 @@ describe("StatusBarComposer", () => {
const wrapper = render();
expect(
- wrapper.container.querySelectorAll(".uifw-statusbar-item-container")
+ wrapper.container.querySelectorAll(".uifw-statusBar-item-container")
).toHaveLength(1);
const uiProvider = new TestUiProvider();
@@ -474,7 +474,7 @@ describe("StatusBarComposer", () => {
UiItemsManager.register(uiProvider);
});
expect(
- wrapper.container.querySelectorAll(".uifw-statusbar-item-container")
+ wrapper.container.querySelectorAll(".uifw-statusBar-item-container")
).toHaveLength(5);
await wrapper.findByText("visible");
@@ -486,7 +486,7 @@ describe("StatusBarComposer", () => {
UiItemsManager.unregister(uiProvider.id);
});
expect(
- wrapper.container.querySelectorAll(".uifw-statusbar-item-container")
+ wrapper.container.querySelectorAll(".uifw-statusBar-item-container")
).toHaveLength(1);
wrapper.unmount();
});
@@ -509,9 +509,9 @@ describe("StatusBarComposer", () => {
// make sure we have enough size to render without overflow
vi.spyOn(Element.prototype, "getBoundingClientRect").mockImplementation(
function (this: HTMLElement) {
- if (this.classList.contains("uifw-statusbar-docked")) {
+ if (this.classList.contains("uifw-statusBar-docked")) {
return DOMRect.fromRect({ width: 1600 });
- } else if (this.classList.contains("uifw-statusbar-item-container")) {
+ } else if (this.classList.contains("uifw-statusBar-item-container")) {
return DOMRect.fromRect({ width: 40 });
} else if (this instanceof HTMLButtonElement) {
return DOMRect.fromRect({ width: 40 });
@@ -545,7 +545,7 @@ describe("StatusBarComposer", () => {
const wrapper = render();
expect(
- wrapper.container.querySelectorAll(".uifw-statusbar-item-container")
+ wrapper.container.querySelectorAll(".uifw-statusBar-item-container")
).toHaveLength(1);
const uiProvider = new TestUiProvider(true);
@@ -553,14 +553,14 @@ describe("StatusBarComposer", () => {
UiItemsManager.register(uiProvider);
});
expect(
- wrapper.container.querySelectorAll(".uifw-statusbar-item-container")
+ wrapper.container.querySelectorAll(".uifw-statusBar-item-container")
).toHaveLength(5);
act(() => {
UiItemsManager.unregister(uiProvider.id);
});
expect(
- wrapper.container.querySelectorAll(".uifw-statusbar-item-container")
+ wrapper.container.querySelectorAll(".uifw-statusBar-item-container")
).toHaveLength(1);
wrapper.unmount();
});
@@ -568,9 +568,9 @@ describe("StatusBarComposer", () => {
it("will render 4 items without overflow", () => {
vi.spyOn(Element.prototype, "getBoundingClientRect").mockImplementation(
function (this: HTMLElement) {
- if (this.classList.contains("uifw-statusbar-docked")) {
+ if (this.classList.contains("uifw-statusBar-docked")) {
return DOMRect.fromRect({ width: 168 }); // 4*42
- } else if (this.classList.contains("uifw-statusbar-item-container")) {
+ } else if (this.classList.contains("uifw-statusBar-item-container")) {
return DOMRect.fromRect({ width: 40 });
} else if (this instanceof HTMLButtonElement) {
return DOMRect.fromRect({ width: 40 });
@@ -620,7 +620,7 @@ describe("StatusBarComposer", () => {
expect(renderedComponent).toBeTruthy();
expect(
renderedComponent.container.querySelectorAll(
- ".uifw-statusbar-item-container"
+ ".uifw-statusBar-item-container"
)
).lengthOf(4);
@@ -656,7 +656,7 @@ describe("StatusBarComposer", () => {
);
expect(
renderedComponent.container.querySelectorAll(
- ".uifw-statusbar-item-container"
+ ".uifw-statusBar-item-container"
)
).lengthOf(3);
});
@@ -664,9 +664,9 @@ describe("StatusBarComposer", () => {
it("will render 1 item with overflow - 4 in overflow panel", async () => {
vi.spyOn(Element.prototype, "getBoundingClientRect").mockImplementation(
function (this: HTMLElement) {
- if (this.classList.contains("uifw-statusbar-docked")) {
+ if (this.classList.contains("uifw-statusBar-docked")) {
return DOMRect.fromRect({ width: 84 }); // 2*42
- } else if (this.classList.contains("uifw-statusbar-item-container")) {
+ } else if (this.classList.contains("uifw-statusBar-item-container")) {
return DOMRect.fromRect({ width: 40 });
} else if (this instanceof HTMLButtonElement) {
return DOMRect.fromRect({ width: 40 });
@@ -721,7 +721,7 @@ describe("StatusBarComposer", () => {
expect(renderedComponent).toBeTruthy();
expect(
renderedComponent.container.querySelectorAll(
- ".uifw-statusbar-item-container"
+ ".uifw-statusBar-item-container"
)
).lengthOf(1);
const overflow = renderedComponent.getByRole("button");
@@ -731,12 +731,12 @@ describe("StatusBarComposer", () => {
"uifw-statusbar-overflow-panel"
);
expect(
- containerInPortal.querySelectorAll(".uifw-statusbar-item-container")
+ containerInPortal.querySelectorAll(".uifw-statusBar-item-container")
).lengthOf(4);
fireEvent.click(overflow);
expect(
renderedComponent.container.querySelectorAll(
- ".uifw-statusbar-item-container"
+ ".uifw-statusBar-item-container"
)
).lengthOf(1);
});