Skip to content
Merged
Show file tree
Hide file tree
Changes from 21 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 @@ -29,7 +29,7 @@ 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 { Icon } from "@stratakit/mui";
import { MyAppFrontend } from "../../frontendApi/MyAppFrontend";
import { TreeRendererWithFilterAction } from "./TreeRendererWithFilterAction";

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" component="div">
<Link component="button" type="button" onClick={action}>
{label}
</Anchor>
</Text>
</Link>
</Typography>
))}
/>
);
Expand All @@ -146,9 +146,15 @@ function MessageWithLink({ linkLabel, scrollToElement, message }: MessageWithLin
return (
<div>
{firstPart}{" "}
<Anchor onClick={scrollToElement} render={<button />}>
<Link
component="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
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ import {
useRef,
useState,
} from "react";
import { Description, IconButton, Spinner, Text, TextBox, VisuallyHidden } from "@stratakit/bricks";
import { DropdownMenu, unstable_Popover as Popover, Tree } from "@stratakit/structures";
import { CircularProgress, FormHelperText, IconButton, Menu, TextField, Typography } from "@mui/material";
import { Icon } from "@stratakit/mui";
import { unstable_Popover as Popover, Tree } from "@stratakit/structures";
import { useTranslation } from "../LocalizationContext.js";
import { TreeActionBase } from "./TreeAction.js";
import { useTreeNodeRenameContext } from "./TreeNodeRenameAction.js";
Expand Down Expand Up @@ -187,32 +188,22 @@ export const StrataKitTreeNodeRenderer: FC<PropsWithRef<TreeNodeRendererProps &
}}
/>
</Popover>
<DropdownMenu.Provider
open={contextMenuProps !== undefined}
setOpen={(open) => {
if (!open) {
setContextMenuProps(undefined);
}
<Menu
open={!!contextMenuProps}
onClose={() => setContextMenuProps(undefined)}
onContextMenu={(e) => {
e.preventDefault();
setContextMenuProps(undefined);
}}
key={`${node.id}-${contextMenuProps?.position.x ?? ""}-${contextMenuProps?.position.y ?? ""}`}
anchorReference="anchorPosition"
anchorPosition={
contextMenuProps ? { top: contextMenuProps.position.y, left: contextMenuProps.position.x } : undefined
}
aria-label={translate("more")}
onClick={() => setContextMenuProps(undefined)}
>
{contextMenuProps ? (
<DropdownMenu.Button
render={(renderProps) => (
<div style={{ position: "fixed", top: contextMenuProps.position.y, left: contextMenuProps.position.x }}>
<VisuallyHidden {...renderProps}>{translate("more")}</VisuallyHidden>
</div>
)}
/>
) : null}
{/* `autoFocus` prop is coming from ariakit and is not native HTML `autoFocus` prop. */}
{/* `focusable` is needed for `autoFocus` to work. StrataKit exposes only `autoFocus` and does not set `focusable` internally. */}
{/* eslint-disable jsx-a11y/no-autofocus */}
{/* @ts-expect-error focusable is passed through */}
<DropdownMenu.Content focusable autoFocus={true}>
{contextMenuProps?.actions}
</DropdownMenu.Content>
</DropdownMenu.Provider>
{contextMenuProps?.actions}
</Menu>
</>
);
}),
Expand All @@ -225,15 +216,14 @@ export const PlaceholderNode: FC<
>
> = memo(
forwardRef<HTMLElement, Pick<StrataKitTreeItemProps, "style" | "aria-level" | "aria-posinset" | "aria-setsize">>(
// eslint-disable-next-line @typescript-eslint/no-shadow
function PlaceholderNode({ ...props }, forwardedRef) {
const translate = useTranslation();
return (
<Tree.Item
{...props}
ref={forwardedRef}
label={translate("loading")}
unstable_decorations={<Spinner size={"small"} title={translate("loading")} />}
unstable_decorations={<CircularProgress size={20} title={translate("loading")} />}
/>
);
},
Expand Down Expand Up @@ -288,37 +278,37 @@ function LabelEditor({
return (
<div key={initialLabel} className="phr-node-label-editor">
<div className="phr-node-label-editor-input-row">
<TextBox.Root style={{ width: "100%" }} className={hasError ? "with-error" : undefined}>
<TextBox.Input
id={inputId}
ref={inputRef}
aria-label={translate("newLabel")}
value={newLabelValue}
onChange={(event) => {
setNewLabelValue(event.target.value);
setHasError(false);
}}
onKeyUp={(event) => {
if (event.key === "Enter") {
handleLabelChange();
} else if (event.key === "Escape") {
cancelLabelChange();
}
}}
/>
</TextBox.Root>
<IconButton icon={dismissSvg} label={translate("cancel")} onClick={cancelLabelChange} />
<IconButton
icon={checkmarkSvg}
label={translate("confirm")}
onClick={handleLabelChange}
disabled={!canRename}
<TextField
fullWidth
error={hasError}
size="small"
id={inputId}
inputRef={inputRef}
slotProps={{ htmlInput: { "aria-label": translate("newLabel") } }}
value={newLabelValue}
Comment thread
MartynasStrazdas marked this conversation as resolved.
onChange={(event) => {
setNewLabelValue(event.target.value);
setHasError(false);
}}
onKeyUp={(event) => {
if (event.key === "Enter") {
handleLabelChange();
} else if (event.key === "Escape") {
cancelLabelChange();
}
}}
/>
<IconButton aria-label={translate("cancel")} onClick={cancelLabelChange} size="small">
<Icon href={dismissSvg} />
</IconButton>
<IconButton aria-label={translate("confirm")} onClick={handleLabelChange} disabled={!canRename} size="small">
<Icon href={checkmarkSvg} />
</IconButton>
</div>
{labelValidationHint !== undefined ? (
<Description id={inputId} tone={hasError ? "critical" : "neutral"} style={{ display: "flex" }}>
<Text variant="caption-lg">{labelValidationHint}</Text>
</Description>
<FormHelperText error={hasError} style={{ display: "flex" }}>
<Typography variant="caption">{labelValidationHint}</Typography>
</FormHelperText>
) : undefined}
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import axe from "axe-core";
import { expect } from "vitest";
import { render } from "vitest-browser-react";
import { Root } from "@stratakit/foundations";
import { Root } from "@stratakit/mui";
import { LocalizationContextProvider } from "../../presentation-hierarchies-react/LocalizationContext.js";
import localeEn from "../../public/locales/en/PresentationHierarchies_1.0.json" with { type: "json" };

Expand Down
Loading
Loading