feat: Add bottom toolbar positions to ToolbarUsage and render them in the standard layout#1542
feat: Add bottom toolbar positions to ToolbarUsage and render them in the standard layout#1542jason-crow wants to merge 1 commit intomasterfrom
Conversation
35d2fe6 to
812ca11
Compare
812ca11 to
7e4f092
Compare
… the standard layout Add BottomContentManipulation and BottomViewNavigation values to ToolbarUsage enum. The standard layout now auto-renders bottom toolbars when UiItemsProviders return items with these usages, removing the need for custom overlay components. Closes #1541
7e4f092 to
5283160
Compare
There was a problem hiding this comment.
Pull request overview
This PR extends AppUI’s standard frontstage toolbar system to support bottom-left and bottom-right toolbars by adding new ToolbarUsage enum values and plumbing them through FrontstageConfig/FrontstageDef, composers, layout rendering, styling, and tests.
Changes:
- Added
BottomContentManipulation/BottomViewNavigationtoolbar usages and updatedToolbarComposerplacement helpers accordingly. - Extended frontstage configuration/definition to support bottom toolbar widget defs and render them in the standard layout.
- Introduced bottom toolbar composer components + styling and added unit tests and API/changeset updates.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| ui/appui-react/src/test/widgets/BottomToolWidgetComposer.test.tsx | Adds unit coverage for the new bottom toolbar composers. |
| ui/appui-react/src/test/widget-panels/Toolbars.test.tsx | Extends layout tests to cover bottom toolbar rendering behavior. |
| ui/appui-react/src/appui-react/widgets/BottomViewToolWidgetComposer.tsx | Adds a preconfigured bottom-right toolbar composer. |
| ui/appui-react/src/appui-react/widgets/BottomToolWidgetComposer.tsx | Introduces the base bottom toolbar composer with opacity/visibility behavior. |
| ui/appui-react/src/appui-react/widgets/BottomContentToolWidgetComposer.tsx | Adds a preconfigured bottom-left toolbar composer. |
| ui/appui-react/src/appui-react/widget-panels/Toolbars.tsx | Renders bottom toolbars from the active FrontstageDef in the standard layout. |
| ui/appui-react/src/appui-react/widget-panels/Toolbars.scss | Updates CSS grid/layout to add and position bottom toolbar areas. |
| ui/appui-react/src/appui-react/toolbar/ToolbarItem.ts | Extends ToolbarUsage enum with bottom toolbar values. |
| ui/appui-react/src/appui-react/toolbar/ToolbarComposer.tsx | Updates expansion direction and alignment logic for new bottom usages. |
| ui/appui-react/src/appui-react/frontstage/FrontstageDef.tsx | Adds WidgetDef fields/getters and config initialization for bottom toolbars. |
| ui/appui-react/src/appui-react/frontstage/FrontstageConfig.ts | Adds optional bottom toolbar widget config properties. |
| ui/appui-react/src/appui-react.ts | Exports the new bottom toolbar composer components. |
| common/api/summary/appui-react.exports.csv | Updates API summary exports for the new public symbols. |
| common/api/appui-react.api.md | Updates API extractor output to include new exports/usages. |
| .changeset/bottom-toolbar-positions.md | Adds a minor changeset documenting the feature. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| import "../widget-panels/Toolbars.scss"; | ||
| import * as React from "react"; |
There was a problem hiding this comment.
BottomToolWidgetComposer imports ../widget-panels/Toolbars.scss, which also contains styling for WidgetPanelsToolbars and the overall center-content grid. This creates an unnecessary cross-module coupling and can pull unrelated layout CSS into bundles wherever the composer is used. Consider extracting the bottom toolbar area styles into a dedicated SCSS file (e.g., BottomToolWidgetComposer.scss) and importing that instead.
| /** Contains tools to Create Update and Delete content - rendered in bottom left of content area. */ | ||
| BottomContentManipulation = 2, | ||
| /** Manipulate view/camera - rendered in bottom right of content area. */ |
There was a problem hiding this comment.
The new enum doc comment reads awkwardly: "Create Update and Delete" should be lowercased and punctuated (e.g., "create, update, and delete") for clarity and consistency with the surrounding comments.
|
|
||
| .uifw-bottom-toolArea { | ||
| display: grid; | ||
| grid-gap: 6px; | ||
| grid-template-areas: | ||
| "vtools ." | ||
| "vtools htools"; | ||
| grid-template-columns: auto 1fr; | ||
| grid-template-rows: 1fr auto; | ||
| align-items: end; | ||
| justify-items: start; | ||
| } | ||
|
|
||
| .uifw-bottom-toolArea_vertical { | ||
| grid-area: vtools; | ||
| display: inline-flex; | ||
| flex-direction: column; | ||
| } | ||
|
|
||
| .uifw-bottom-toolArea_horizontal { | ||
| grid-area: htools; | ||
| min-width: 0; | ||
| } | ||
|
|
||
| .uifw-bottom-toolArea_right { | ||
| margin-left: auto; | ||
|
|
||
| .uifw-bottom-toolArea { | ||
| justify-items: end; | ||
| } |
There was a problem hiding this comment.
The .uifw-bottom-toolArea* styles are nested under .uifw-widgetPanels-toolbars, so BottomToolWidgetComposer will only be styled when rendered as a descendant of WidgetPanelsToolbars. Since BottomToolWidgetComposer is exported as a public component, consider moving these rules to a top-level selector (or a dedicated SCSS file imported by the composer) so it renders correctly when used outside the standard layout.
| .uifw-bottom-toolArea { | |
| display: grid; | |
| grid-gap: 6px; | |
| grid-template-areas: | |
| "vtools ." | |
| "vtools htools"; | |
| grid-template-columns: auto 1fr; | |
| grid-template-rows: 1fr auto; | |
| align-items: end; | |
| justify-items: start; | |
| } | |
| .uifw-bottom-toolArea_vertical { | |
| grid-area: vtools; | |
| display: inline-flex; | |
| flex-direction: column; | |
| } | |
| .uifw-bottom-toolArea_horizontal { | |
| grid-area: htools; | |
| min-width: 0; | |
| } | |
| .uifw-bottom-toolArea_right { | |
| margin-left: auto; | |
| .uifw-bottom-toolArea { | |
| justify-items: end; | |
| } | |
| } | |
| .uifw-bottom-toolArea { | |
| display: grid; | |
| grid-gap: 6px; | |
| grid-template-areas: | |
| "vtools ." | |
| "vtools htools"; | |
| grid-template-columns: auto 1fr; | |
| grid-template-rows: 1fr auto; | |
| align-items: end; | |
| justify-items: start; | |
| } | |
| .uifw-bottom-toolArea_vertical { | |
| grid-area: vtools; | |
| display: inline-flex; | |
| flex-direction: column; | |
| } | |
| .uifw-bottom-toolArea_horizontal { | |
| grid-area: htools; | |
| min-width: 0; | |
| } | |
| .uifw-bottom-toolArea_right { | |
| margin-left: auto; | |
| .uifw-bottom-toolArea { | |
| justify-items: end; |
| grid-template-columns: 1fr 1fr; | ||
| grid-template-rows: auto 1fr auto; | ||
|
|
There was a problem hiding this comment.
grid-template-rows: auto 1fr auto combined with putting the existing .nz-tools-widget instances in grid-row: 1 risks breaking layout: .nz-tools-widget (ToolsArea/NavigationArea) is styled with height: 100% and relies on spanning the full content height. In an auto first row this can either force the first row to consume the full height (pushing the bottom toolbars row out of view) or prevent the tools widget from spanning full height. Consider keeping the toolbars overlay in a single grid row and anchoring bottom toolbars via align-self: end (or similar), or otherwise ensure the top .nz-tools-widget elements still span the full available height while leaving room for the bottom toolbars.
|
As discussed internally, I'm closing #1474 in favor of this PR. Closed PR implements the capability in a non-breaking manner and allows for easy extension/usage by custom layouts at the expense of being less discoverable. We've agreed to ensure that AppUI handles the |
| /** Manipulate view/camera - in AppUI this is in top right of content area. */ | ||
| ViewNavigation = 1, | ||
| /** Contains tools to Create Update and Delete content - rendered in bottom left of content area. */ | ||
| BottomContentManipulation = 2, |
There was a problem hiding this comment.
Should we avoid placement keywords, like "Bottom"?
The "usage" should naturally help with grouping related toolbar items based on their behavior.
I went with "ViewSettings" in #1474, but other suggestions are welcome.
Alternatively, we could introduce an explicit "placement" property, however that is basically re-implementing #1474
| public get viewNavigation(): WidgetDef | undefined { | ||
| return this._viewNavigation; | ||
| } | ||
| public get bottomContentManipulation(): WidgetDef | undefined { |
There was a problem hiding this comment.
I'm wondering if these APIs are useful on the FrontstageDef? E.g. is there a cuse-case for existing frontstageDef.viewNavigation?
| ContentManipulation = 0, | ||
| /** Manipulate view/camera - in AppUI this is in top right of content area. */ | ||
| ViewNavigation = 1, | ||
| /** Contains tools to Create Update and Delete content - rendered in bottom left of content area. */ |
There was a problem hiding this comment.
The enum itself should clearly be marked as non-exhaustive - new values might be added in the future.
| const frontstageDef = useActiveFrontstageDef(); | ||
| const tools = frontstageDef?.contentManipulation?.reactNode; | ||
| const navigation = frontstageDef?.viewNavigation?.reactNode; | ||
| const bottomTools = frontstageDef?.bottomContentManipulation?.reactNode; |
There was a problem hiding this comment.
frontstageDef?.initialConfig can be used, if we get rid of bottomContentManipulation
Summary
Adds
BottomContentManipulationandBottomViewNavigationvalues to theToolbarUsageenum, and extends the frontstage system to support bottom toolbar positions using the sameFrontstageDef/WidgetDef/reactNodearchitecture as the existing top toolbars.Closes #1541
What's Changed
ToolbarUsageenum — AddedBottomContentManipulation = 2andBottomViewNavigation = 3ToolbarComposer— UpdatedtoExpandsTo()andtoPanelAlignment()helpers to handle the new usages (bottom toolbars expand upward; bottom-right aligns to end)FrontstageConfig— Added optionalbottomContentManipulationandbottomViewNavigationWidgetConfigproperties, mirroringcontentManipulationandviewNavigationFrontstageDef— Added correspondingWidgetDefproperties with initialization from configBottomToolWidgetComposer— New component analogous toToolWidgetComposerbut for bottom toolbars (L-shaped grid, no corner item, proximity-based opacity, UI visibility)BottomContentToolWidgetComposer— Pre-configured composer forBottomContentManipulation(analogous toContentToolWidgetComposer)BottomViewToolWidgetComposer— Pre-configured composer forBottomViewNavigation(analogous toViewToolWidgetComposer)WidgetPanelsToolbars— Renders bottom toolbars viafrontstageDef?.bottomContentManipulation?.reactNodeandfrontstageDef?.bottomViewNavigation?.reactNode— same pattern as top toolbarsToolbars.scss— Extended the CSS grid with a bottom row; bottom tool area uses an L-shaped grid ("vtools ." / "vtools htools") mirroring the topToolsAreapattern but anchored to the bottomappui-react.api.mdupdated with new exports@itwin/appui-reactArchitecture
The bottom toolbars follow the exact same architecture as the top toolbars:
Consumer Experience