Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
f68e3ba
initial
MartynasStrazdas Jul 2, 2026
8141849
Merge branch 'next' into mast/move-to-MUI
MartynasStrazdas Jul 3, 2026
be2238d
adjustments to context menu
MartynasStrazdas Jul 3, 2026
f1fd456
update button sizes
MartynasStrazdas Jul 3, 2026
19ee22d
Merge branch 'next' into mast/move-to-MUI
MartynasStrazdas Jul 3, 2026
44aa53e
fix context window behavior
MartynasStrazdas Jul 9, 2026
7bfd1cd
change
MartynasStrazdas Jul 9, 2026
f9514b1
Merge branch 'next' into mast/move-to-MUI
MartynasStrazdas Jul 9, 2026
7eb4597
fixes
MartynasStrazdas Jul 9, 2026
9364d1d
fixes
MartynasStrazdas Jul 9, 2026
cf198d2
update to use catalog
MartynasStrazdas Jul 9, 2026
6724fc8
lock file update
MartynasStrazdas Jul 9, 2026
ac9cc23
rerender all component tests
MartynasStrazdas Jul 9, 2026
1653e5b
fixes
MartynasStrazdas Jul 9, 2026
ee6683d
Merge branch 'next' into mast/move-to-MUI
MartynasStrazdas Jul 9, 2026
2c66480
test: update visual regression screenshots
imodeljs-admin Jul 9, 2026
57a5253
define our own onClick
MartynasStrazdas Jul 9, 2026
af2fe9d
use Menu for context window
MartynasStrazdas Jul 10, 2026
5d3d9a2
Merge branch 'next' into mast/move-to-MUI
MartynasStrazdas Jul 10, 2026
b69f666
test: update visual regression screenshots
imodeljs-admin Jul 10, 2026
fceb885
chore: add types for @stratakit/mui in tsconfig files
MartynasStrazdas Jul 13, 2026
70ea14d
fix lint issues because of the addition of types from stratakit
MartynasStrazdas Jul 13, 2026
d358a13
format
MartynasStrazdas Jul 13, 2026
35a90f4
test: update visual regression screenshots
imodeljs-admin Jul 13, 2026
666055e
spinner size adjustment
MartynasStrazdas Jul 13, 2026
d3ff108
remove itwin ui from test app stateless tree
MartynasStrazdas Jul 13, 2026
6801de9
Merge branch 'next' into mast/move-to-MUI
MartynasStrazdas Jul 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/early-facts-hide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@itwin/presentation-hierarchies-react": minor
Comment thread
MartynasStrazdas marked this conversation as resolved.
---

Moved the package to use `@mui/material` and `@stratakit/mui`.

**Breaking:** Removed `@stratakit/foundations`, `@stratakit/icons` optional peer dependencies. Added `@mui/material` and `@stratakit/mui` as optional peer dependencies.
Comment thread
MartynasStrazdas marked this conversation as resolved.
3 changes: 2 additions & 1 deletion apps/test-app/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@
"@itwin/unified-selection": "workspace:*",
"@itwin/unified-selection-react": "workspace:*",
"@rolldown/plugin-babel": "catalog:build-tools",
"@stratakit/foundations": "catalog:stratakit",
"@mui/material": "catalog:stratakit",
"@stratakit/icons": "catalog:stratakit",
"@stratakit/mui": "catalog:stratakit",
"@stratakit/structures": "catalog:stratakit",
"@tanstack/react-table": "^8.21.3",
"@test-app/common": "workspace:*",
Expand Down
11 changes: 2 additions & 9 deletions apps/test-app/frontend/src/components/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { createECSchemaProvider, createECSqlQueryExecutor, createIModelKey } fro
import { createCachingECClassHierarchyInspector } from "@itwin/presentation-shared";
import { createHiliteSetProvider, enableUnifiedSelectionSyncWithIModel } from "@itwin/unified-selection";
import { UnifiedSelectionContextProvider } from "@itwin/unified-selection-react";
import { Root } from "@stratakit/foundations";
import { Root } from "@stratakit/mui";
import { MyAppFrontend } from "../../frontendApi/MyAppFrontend";
import { IModelSelector } from "../imodel-selector/IModelSelector";
import { PropertiesWidget } from "../properties-widget/PropertiesWidget";
Expand Down Expand Up @@ -166,14 +166,7 @@ export function App() {
}, [state.imodel]);

return (
<ThemeProvider
theme={"light"}
future={{ themeBridge: true }}
as={Root}
colorScheme={"light"}
synchronizeColorScheme
density="dense"
>
<ThemeProvider theme={"light"} future={{ themeBridge: true }} as={Root} colorScheme={"light"}>
<UnifiedSelectionContextProvider storage={MyAppFrontend.selectionStorage}>
<div className="app">
<div className="app-header">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { debounceTime, Subject } from "rxjs";
import { BeEvent } from "@itwin/core-bentley";
import { IModelApp } from "@itwin/core-frontend";
import { Button, Flex, ProgressRadial, SearchBox, Text, ToggleSwitch } from "@itwin/itwinui-react";
import { DefaultContentDisplayTypes, KeySet } from "@itwin/presentation-common";
import { PresentationInstanceFilter, PresentationInstanceFilterDialog } from "@itwin/presentation-components";
import {
Expand All @@ -29,7 +28,8 @@ import { ModelsTreeDefinition } from "@itwin/presentation-models-tree";
import { createCachingECClassHierarchyInspector } from "@itwin/presentation-shared";
import { Selectable, Selectables } from "@itwin/unified-selection";
import { useUnifiedSelectionContext } from "@itwin/unified-selection-react";
import { Icon } from "@stratakit/foundations";
import { Button, CircularProgress, Stack, Switch, TextField, Typography } from "@mui/material";
import { Icon } from "@stratakit/mui";
import { MyAppFrontend } from "../../frontendApi/MyAppFrontend";
import { TreeRendererWithFilterAction } from "./TreeRendererWithFilterAction";

Expand Down Expand Up @@ -123,7 +123,7 @@ function Tree({
throw new Error("Unified selection context is not available");
}

const { isReloading, setFormatter, ...treeProps } = useIModelUnifiedSelectionTree({
const { setFormatter, ...treeProps } = useIModelUnifiedSelectionTree({
selectionStorage: unifiedSelectionContext.storage,
sourceName: "StatelessTreeV2",
imodelAccess,
Expand Down Expand Up @@ -198,17 +198,18 @@ function Tree({

if (!treeProps.treeRendererProps) {
return (
<Flex alignItems="center" justifyContent="center" flexDirection="column" style={{ height: "100%" }}>
<Text isMuted> Loading </Text>
</Flex>
<Stack style={{ alignItems: "center", justifyContent: "center", height: "100%", gap: 8 }}>
<CircularProgress size={32} />
<Typography color="text.secondary">Loading</Typography>
</Stack>
);
}

if (treeProps.treeRendererProps.rootNodes.length === 0 && searchText) {
return (
<Flex alignItems="center" justifyContent="center" flexDirection="column" style={{ height: "100%" }}>
<Text isMuted>There are no nodes matching search text {searchText}</Text>
</Flex>
<Stack style={{ alignItems: "center", justifyContent: "center", height: "100%" }}>
<Typography color="text.secondary">There are no nodes matching search text {searchText}</Typography>
</Stack>
);
}

Expand All @@ -224,43 +225,11 @@ function Tree({
);
};

const renderLoadingOverlay = () => {
if (treeProps.rootErrorRendererProps !== undefined || treeProps.treeRendererProps !== undefined || !isReloading) {
return <></>;
}
return (
<div
style={{
position: "absolute",
zIndex: 1000,
height: "inherit",
width: "100%",
overflow: "hidden",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
<div
style={{
position: "absolute",
opacity: 0.5,
pointerEvents: "none",
width: "100%",
height: "100%",
backgroundColor: "var(--iui-color-background-backdrop)",
}}
/>
<ProgressRadial size="large" indeterminate />
</div>
);
};

return (
<Flex flexDirection="column" style={{ width, height }}>
<Flex style={{ width: "100%", padding: "0.5rem" }}>
<Stack style={{ width, height }}>
<Stack direction="row" spacing={1} style={{ width: "100%", padding: "0.5rem" }}>
<DebouncedSearchBox onChange={setSearchText} />
<ToggleSwitch onChange={toggleFormatter} checked={shouldUseCustomFormatter} />
<Switch onChange={toggleFormatter} checked={shouldUseCustomFormatter} />
{imodel.isBriefcaseConnection() ? (
<Button onClick={() => void removeSelectedElements(imodel)}>Delete</Button>
) : null}
Expand All @@ -279,9 +248,8 @@ function Tree({
>
Rename selected node
</Button>
</Flex>
</Stack>
{renderContent()}
{renderLoadingOverlay()}
<PresentationInstanceFilterDialog
imodel={imodel}
isOpen={!!filteringOptions}
Expand All @@ -298,11 +266,11 @@ function Tree({
propertiesSource={propertiesSource}
initialFilter={getInitialFilter}
/>
</Flex>
</Stack>
);
}

type SearchBoxProps = ComponentPropsWithoutRef<typeof SearchBox>;
type SearchBoxProps = ComponentPropsWithoutRef<typeof TextField>;

function DebouncedSearchBox({
onChange,
Expand All @@ -312,12 +280,7 @@ function DebouncedSearchBox({
return debounced(onChange, 500);
}, [onChange]);

return (
<SearchBox
{...props}
inputProps={{ ...props.inputProps, value: undefined, onChange: (e) => handleChange(e.currentTarget.value) }}
/>
);
return <TextField {...props} placeholder="Search..." onChange={(e) => handleChange(e.currentTarget.value)} />;
}

function debounced<TArgs>(callback: (args: TArgs) => void, delay: number) {
Expand Down
3 changes: 2 additions & 1 deletion apps/test-app/frontend/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"esModuleInterop": true,
"isolatedModules": true,
"rootDir": ".",
"noEmit": true
"noEmit": true,
"types": ["@stratakit/mui/types.d.ts"]
},
"include": ["src", "vite.config.mts"]
}
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,9 @@ export interface TreeActionBaseAttributes {
}

// @alpha (undocumented)
type TreeActionBaseProps = ComponentPropsWithoutRef<typeof Tree.ItemAction> & TreeActionBaseAttributes;
type TreeActionBaseProps = Omit<ComponentPropsWithoutRef<typeof Tree.ItemAction>, "onClick"> & TreeActionBaseAttributes & {
onClick: () => void;
};

// @alpha
export function TreeErrorRenderer(input: TreeErrorRendererProps): JSX.Element;
Expand Down
14 changes: 7 additions & 7 deletions packages/hierarchies-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
"@itwin/presentation-hierarchies": "workspace:*",
"@itwin/presentation-shared": "workspace:*",
"@itwin/unified-selection": "workspace:^",
"@stratakit/bricks": "catalog:stratakit",
"@stratakit/icons": "catalog:stratakit",
"@stratakit/structures": "catalog:stratakit",
"@tanstack/react-virtual": "^3.13.24",
"classnames": "catalog:react",
Expand All @@ -76,25 +76,25 @@
"rxjs": "catalog:rxjs"
},
"peerDependencies": {
"@stratakit/foundations": "^0.4.7",
"@stratakit/icons": "^0.3.1",
"@mui/material": "^9.0.0",
"@stratakit/mui": "^0.5.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@stratakit/foundations": {
"@mui/material": {
"optional": true
},
"@stratakit/icons": {
"@stratakit/mui": {
"optional": true
}
},
"devDependencies": {
"@itwin/build-tools": "catalog:build-tools",
"@itwin/eslint-plugin": "catalog:build-tools",
"@mui/material": "catalog:stratakit",
"@rolldown/plugin-babel": "catalog:build-tools",
"@stratakit/foundations": "catalog:stratakit",
"@stratakit/icons": "catalog:stratakit",
"@stratakit/mui": "catalog:stratakit",
"@testing-library/dom": "catalog:test-tools",
"@testing-library/react": "catalog:test-tools",
"@testing-library/user-event": "catalog:test-tools",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/

import { Anchor, Text } from "@stratakit/bricks";
import { Link, Typography } from "@mui/material";
import { unstable_ErrorRegion as ErrorRegion } from "@stratakit/structures";
import { MAX_LIMIT_OVERRIDE } from "../internal/Utils.js";
import { useTranslation } from "../LocalizationContext.js";
Expand Down Expand Up @@ -123,11 +123,11 @@ function ErrorItemContainer({ treeNode, message, actions, scrollToElement }: Err
actions={actions
?.filter(({ condition }) => condition())
.map(({ label, action }) => (
<Text key={label} variant="body-sm">
<Anchor onClick={action} render={<button />}>
<Typography key={label} variant="caption" render={<div />}>
<Link render={<button type="button" />} onClick={action}>
{label}
</Anchor>
</Text>
</Link>
</Typography>
))}
/>
);
Expand All @@ -146,9 +146,14 @@ function MessageWithLink({ linkLabel, scrollToElement, message }: MessageWithLin
return (
<div>
{firstPart}{" "}
<Anchor onClick={scrollToElement} render={<button />}>
<Link
render={<button type="button" />}
onClick={scrollToElement}
variant="caption"
style={{ verticalAlign: "baseline" }}
>
{linkLabel}
</Anchor>
</Link>
{secondPart ? " " : ""}
{secondPart ? secondPart : null}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/

import { Button, Text } from "@stratakit/bricks";
import { Icon } from "@stratakit/foundations";
import { Button, Typography } from "@mui/material";
import { Icon } from "@stratakit/mui";
import { useTranslation } from "../LocalizationContext.js";

import errorSvg from "@stratakit/icons/status-error.svg";
Expand Down Expand Up @@ -73,14 +73,14 @@ function RootErrorContainer({ actions, message }: RootErrorContainerProps) {
}}
>
<Icon href={errorSvg} size="large" />
<Text variant={"body-sm"} style={{ textAlign: "center" }}>
<Typography variant="caption" style={{ textAlign: "center" }}>
{message}
</Text>
</Typography>
{actions
?.filter(({ condition }) => condition())
.map((action) => {
return (
<Button key={action.label} onClick={() => action.action()}>
<Button key={action.label} onClick={() => action.action()} size="small">
{action.label}
</Button>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
*--------------------------------------------------------------------------------------------*/

import { memo } from "react";
import { DropdownMenu, Tree } from "@stratakit/structures";
import { ListItemIcon, MenuItem, Typography } from "@mui/material";
import { Icon } from "@stratakit/mui";
import { Tree } from "@stratakit/structures";

import type { ComponentPropsWithoutRef, NamedExoticComponent } from "react";

Expand All @@ -30,7 +32,11 @@ export interface TreeActionBaseAttributes {
}

/** @alpha */
export type TreeActionBaseProps = ComponentPropsWithoutRef<typeof Tree.ItemAction> & TreeActionBaseAttributes;
export type TreeActionBaseProps = Omit<ComponentPropsWithoutRef<typeof Tree.ItemAction>, "onClick"> &
TreeActionBaseAttributes & {
/** Callback invoked when the action is clicked. */
onClick: () => void;
};

/**
* Base component used to render tree actions. It is designed to allow rendering same action in different contexts: inline, dropdown, context menu.
Expand Down Expand Up @@ -63,7 +69,13 @@ export const TreeActionBase: NamedExoticComponent<TreeActionBaseProps> = memo(fu
}

if (variant === "context-menu") {
return <DropdownMenu.Item {...actionProps} />;
const { label, icon, onClick } = actionProps;
return (
<MenuItem dense onClick={onClick}>
{icon ? <ListItemIcon>{typeof icon === "string" ? <Icon href={icon} /> : icon}</ListItemIcon> : null}
<Typography variant="caption">{label}</Typography>
</MenuItem>
);
}

return <Tree.ItemAction {...actionProps} dot={dot} visible={variant === "inline" ? visible : undefined} />;
Expand Down
Loading