From 17b19e83fa95b62a9234a4ac26b25287a0795bfd Mon Sep 17 00:00:00 2001 From: Mark Provo Kluit Date: Sat, 19 Sep 2026 18:57:47 +0200 Subject: [PATCH 1/6] feat(material): add separate components for leading buttons in app bar --- .changeset/cyan-laws-bow.md | 5 +++ .../app-bar/MaterialAppBar.module.css | 10 +++-- .../app-bar/MaterialAppBar.stories.tsx | 13 +++--- .../src/components/app-bar/MaterialAppBar.tsx | 44 ++++--------------- .../app-bar/MaterialAppBarBackButton.tsx | 37 ++++++++++++++++ .../material/src/components/app-bar/index.ts | 4 +- .../MaterialNavigationRail.module.css | 19 -------- .../MaterialNavigationRail.tsx | 9 ---- packages/material/src/layouts/index.ts | 2 + .../MaterialNavigationRailLayout.tsx | 41 ++++++++++++----- ...ialNavigationRailLayoutMenuButton.test.tsx | 42 ++++++++++++++++++ ...MaterialNavigationRailLayoutMenuButton.tsx | 29 ++++++++++++ 12 files changed, 170 insertions(+), 85 deletions(-) create mode 100644 .changeset/cyan-laws-bow.md create mode 100644 packages/material/src/components/app-bar/MaterialAppBarBackButton.tsx create mode 100644 packages/material/src/layouts/navigation-rail-layout/MaterialNavigationRailLayoutMenuButton.test.tsx create mode 100644 packages/material/src/layouts/navigation-rail-layout/MaterialNavigationRailLayoutMenuButton.tsx diff --git a/.changeset/cyan-laws-bow.md b/.changeset/cyan-laws-bow.md new file mode 100644 index 00000000..afdfc4ad --- /dev/null +++ b/.changeset/cyan-laws-bow.md @@ -0,0 +1,5 @@ +--- +'@solidmaterial/material': minor +--- + +Add separate components for leading buttons in app bar diff --git a/packages/material/src/components/app-bar/MaterialAppBar.module.css b/packages/material/src/components/app-bar/MaterialAppBar.module.css index 0b471c89..7421fec0 100644 --- a/packages/material/src/components/app-bar/MaterialAppBar.module.css +++ b/packages/material/src/components/app-bar/MaterialAppBar.module.css @@ -99,12 +99,12 @@ padding-inline: var(--md-comp-app-bar-leading-space) var(--md-comp-app-bar-trailing-space); /* Align small text with text in appendix if there is no leading icon button */ - &:not(:has(.back-button)) { + &:not(:has(.leading-button:not(:empty))) { grid-template-columns: auto min-content; padding-inline-start: var(--md-user-spacing-md); } - .back-button { + .leading-button { --sm-icon-button-icon-color: var(--md-comp-app-bar-leading-icon-color); &:dir(rtl) { @@ -138,7 +138,7 @@ gap: var(--md-comp-app-bar-icon-button-space); } - .back-button, + .leading-button, .trailing-buttons { display: grid; place-items: center; @@ -146,6 +146,10 @@ grid-auto-columns: minmax(48px, auto); height: 48px; } + + .leading-button:empty { + display: none; + } } .app-bar-background { diff --git a/packages/material/src/components/app-bar/MaterialAppBar.stories.tsx b/packages/material/src/components/app-bar/MaterialAppBar.stories.tsx index 0f01dea1..b7d930ab 100644 --- a/packages/material/src/components/app-bar/MaterialAppBar.stories.tsx +++ b/packages/material/src/components/app-bar/MaterialAppBar.stories.tsx @@ -1,12 +1,13 @@ import type { Component } from 'solid-js'; import { createJSXDecorator } from 'storybook-solidjs-vite'; -import { fn } from 'storybook/test'; import preview from '../../../.storybook/preview'; +import { MaterialNavigationRailLayoutMenuButton } from '../../layouts/navigation-rail-layout/MaterialNavigationRailLayoutMenuButton'; import { MaterialIconButton } from '../icon-button/MaterialIconButton'; import { MaterialAppBar } from './MaterialAppBar'; +import { MaterialAppBarBackButton } from './MaterialAppBarBackButton'; import CalendarTodayFillIcon from '@solidmaterial/icons/400/outlined/calendar_today-fill.svg'; import MapFillIcon from '@solidmaterial/icons/400/outlined/map-fill.svg'; @@ -66,8 +67,7 @@ export const Example = meta.story({ variant: 'large', title: 'Title', subtitle: 'Subtitle', - leadingButtonAriaLabel: 'Go back', - onNavigate: fn(), + leadingButton: , trailingButtons: } /> } }); @@ -113,8 +113,7 @@ export const LeadingButtonBack = meta.story({ args: { variant: 'small', title: 'Title', - leadingButtonAriaLabel: 'Go back', - onNavigate: fn() + leadingButton: } }); @@ -122,9 +121,7 @@ export const LeadingButtonMenu = meta.story({ args: { variant: 'small', title: 'Title', - leadingButtonType: 'menu', - leadingButtonAriaLabel: 'Open menu', - onNavigate: fn() + leadingButton: } }); diff --git a/packages/material/src/components/app-bar/MaterialAppBar.tsx b/packages/material/src/components/app-bar/MaterialAppBar.tsx index 8eb24aa0..0e60d3be 100644 --- a/packages/material/src/components/app-bar/MaterialAppBar.tsx +++ b/packages/material/src/components/app-bar/MaterialAppBar.tsx @@ -1,34 +1,28 @@ import type { JSX, VoidComponent } from 'solid-js'; import { createViewportObserver } from '@solid-primitives/intersection-observer'; -import { Match, Show, Switch, createMemo, createSignal, onCleanup, onMount } from 'solid-js'; +import { Match, Show, Switch, createSignal, onCleanup, onMount } from 'solid-js'; -import { MaterialIconButton } from '../icon-button/MaterialIconButton'; import { H1, H2 } from '../typography/Typography'; import styles from './MaterialAppBar.module.css'; -import ArrowBackIcon from '@solidmaterial/icons/400/outlined/arrow_back.svg'; -import ArrowBackIosNewIcon from '@solidmaterial/icons/400/outlined/arrow_back_ios_new.svg'; -import MenuIcon from '@solidmaterial/icons/400/outlined/menu.svg'; - export type MaterialAppBarVariant = 'small' | 'medium' | 'large'; -export type MaterialLeadingButtonType = 'back' | 'menu'; - export interface MaterialAppBarProps { variant: MaterialAppBarVariant; title: string; subtitle?: string; center?: boolean; - leadingButtonType?: MaterialLeadingButtonType; - leadingButtonAriaLabel?: string; + /** + * A leading button, placed in front of the title and subtitle + * + * Use this prop to render a {@link MaterialAppBarBackButton} or {@link MaterialNavigationRailLayoutMenuButton}. + */ + leadingButton?: JSX.Element; trailingButtons?: JSX.Element; - onNavigate?: (event: PointerEvent) => void; } -const isIOS = () => /iphone|ipad/iu.test(globalThis.navigator.userAgent); - export const MaterialAppBar: VoidComponent = props => { const [intersectionRatio, setIntersectionRatio] = createSignal(1); @@ -59,32 +53,12 @@ export const MaterialAppBar: VoidComponent = props => { const appBarTextOpacity = () => (hasAppendixContent() ? (0.4 - Math.min(0.4, intersectionRatio())) / 0.4 : 1); const appendixTextOpacity = () => (Math.max(0.5, intersectionRatio()) - 0.5) / 0.5; - const leadingButtonType = createMemo(() => props.leadingButtonType ?? 'back'); - return ( <> - -
- - - }> - - - - - - - - } - ariaLabel={props.leadingButtonAriaLabel} - onClick={(event: PointerEvent) => props.onNavigate?.(event)} - /> -
+ +
{props.leadingButton}
/iphone|ipad/iu.test(globalThis.navigator.userAgent); + +export interface MaterialAppBarBackButtonProps { + ariaLabel?: string; + title?: string; + onClick?: (event: PointerEvent) => void; +} + +/** + * Render a back button for an app bar + * + * Should be used in the `leadingButton` prop of the {@link MaterialAppBar}. + */ +export const MaterialAppBarBackButton: VoidComponent = props => { + return ( + }> + + + } + ariaLabel={props.ariaLabel} + title={props.title} + onClick={(event: PointerEvent) => props.onClick?.(event)} + /> + ); +}; diff --git a/packages/material/src/components/app-bar/index.ts b/packages/material/src/components/app-bar/index.ts index 6b5cbe76..72c6cd19 100644 --- a/packages/material/src/components/app-bar/index.ts +++ b/packages/material/src/components/app-bar/index.ts @@ -1,2 +1,4 @@ export { MaterialAppBar } from './MaterialAppBar'; -export type { MaterialAppBarProps, MaterialAppBarVariant, MaterialLeadingButtonType } from './MaterialAppBar'; +export type { MaterialAppBarProps, MaterialAppBarVariant } from './MaterialAppBar'; +export { MaterialAppBarBackButton } from './MaterialAppBarBackButton'; +export type { MaterialAppBarBackButtonProps } from './MaterialAppBarBackButton'; diff --git a/packages/material/src/components/navigation-rail/MaterialNavigationRail.module.css b/packages/material/src/components/navigation-rail/MaterialNavigationRail.module.css index 24da9334..9490ae6a 100644 --- a/packages/material/src/components/navigation-rail/MaterialNavigationRail.module.css +++ b/packages/material/src/components/navigation-rail/MaterialNavigationRail.module.css @@ -38,10 +38,6 @@ &[data-always-expanded] { &[data-show] { - .fixed-menu-button { - visibility: hidden; - } - /** * If modal and always expanded, keep width fixed and instead * animate translate from -100% to 0% @@ -77,21 +73,6 @@ sm-icon-button { margin: 12px 8px; } - - .fixed-menu-button { - position: absolute; - top: 0; - left: 20px; - - /** - * When the navigation rail is hidden on small screens, its pointer events - * are disabled above so that the user can click on elements which are found - * on the left side of the screen (and 'behind' the expanded rail). - * - * Except for the absolutely-positioned menu button, which remains visible. - */ - pointer-events: all; - } } /* Rail containing FAB and items */ diff --git a/packages/material/src/components/navigation-rail/MaterialNavigationRail.tsx b/packages/material/src/components/navigation-rail/MaterialNavigationRail.tsx index 640da0b7..bfac880c 100644 --- a/packages/material/src/components/navigation-rail/MaterialNavigationRail.tsx +++ b/packages/material/src/components/navigation-rail/MaterialNavigationRail.tsx @@ -130,15 +130,6 @@ export const MaterialNavigationRail: VoidComponent
- -
- -
-
); }; diff --git a/packages/material/src/layouts/index.ts b/packages/material/src/layouts/index.ts index ad2fff0e..ea971fd5 100644 --- a/packages/material/src/layouts/index.ts +++ b/packages/material/src/layouts/index.ts @@ -11,4 +11,6 @@ export { MaterialListDetailLayout } from './canonical-layouts/list-detail-layout export { MaterialNavigationBarLayout } from './navigation-bar-layout/MaterialNavigationBarLayout'; export { MaterialNavigationLayout } from './navigation-layout/MaterialNavigationLayout'; export { MaterialNavigationRailLayout } from './navigation-rail-layout/MaterialNavigationRailLayout'; +export { MaterialNavigationRailLayoutMenuButton } from './navigation-rail-layout/MaterialNavigationRailLayoutMenuButton'; +export type { MaterialNavigationRailLayoutMenuButtonProps } from './navigation-rail-layout/MaterialNavigationRailLayoutMenuButton'; export { MaterialPane } from './pane/MaterialPane'; diff --git a/packages/material/src/layouts/navigation-rail-layout/MaterialNavigationRailLayout.tsx b/packages/material/src/layouts/navigation-rail-layout/MaterialNavigationRailLayout.tsx index f4d58b80..81fc3f65 100644 --- a/packages/material/src/layouts/navigation-rail-layout/MaterialNavigationRailLayout.tsx +++ b/packages/material/src/layouts/navigation-rail-layout/MaterialNavigationRailLayout.tsx @@ -1,7 +1,7 @@ import type { Accessor, Context, FlowComponent } from 'solid-js'; import { createElementSize } from '@solid-primitives/resize-observer'; -import { createContext, createEffect, createSignal } from 'solid-js'; +import { createContext, createEffect, createMemo, createSignal } from 'solid-js'; import type { MaterialNavigationLayoutProps } from '../navigation-layout/MaterialNavigationLayout.types'; @@ -15,12 +15,22 @@ import styles from './MaterialNavigationRailLayout.module.css'; export const MaterialNavigationLayoutRailWidthContext: Context | undefined> = createContext>(); +export const MaterialNavigationRailMenuContext: Context< + [Accessor, Accessor, (event: PointerEvent) => void] +> = createContext<[Accessor, Accessor, (event: PointerEvent) => void]>([ + () => false, + () => false, + () => { + // Empty + } +]); + export const MaterialNavigationRailLayout: FlowComponent = props => { const numberOfItemsForRail = () => props.items.length + (props.secondary?.items.length ?? 0); const hasManyItemsForRail = () => Breakpoints.isCompactHeight() && (props.fab ? numberOfItemsForRail() > 3 : numberOfItemsForRail() > 4); - const showRail = () => props.show !== false && !shouldShowBar(props.items.length, props.preferSpace); + const showRail = createMemo(() => props.show !== false && !shouldShowBar(props.items.length, props.preferSpace)); const [target, setTarget] = createSignal(); const elementSize = createElementSize(target); @@ -39,6 +49,20 @@ export const MaterialNavigationRailLayout: FlowComponent setIsExpanded(expanded => !expanded); + const isModal = createMemo( + () => + Breakpoints.isCompactWidth() || + Breakpoints.isMediumWidth() || + (Breakpoints.isExpandedWidth() && props.preferSpace === 'horizontal') || + hasManyItemsForRail() + ); + + const isHideWhenCollapsed = createMemo(() => Breakpoints.isCompactWidth() || hasManyItemsForRail()); + + const isHiddenWhenCollapsed = createMemo( + () => props.menuButton !== undefined && showRail() && isModal() && isHideWhenCollapsed() + ); + return (
@@ -49,20 +73,17 @@ export const MaterialNavigationRailLayout: FlowComponent
- {props.children} + + {props.children} +
); diff --git a/packages/material/src/layouts/navigation-rail-layout/MaterialNavigationRailLayoutMenuButton.test.tsx b/packages/material/src/layouts/navigation-rail-layout/MaterialNavigationRailLayoutMenuButton.test.tsx new file mode 100644 index 00000000..c6f8dbdf --- /dev/null +++ b/packages/material/src/layouts/navigation-rail-layout/MaterialNavigationRailLayoutMenuButton.test.tsx @@ -0,0 +1,42 @@ +import { render } from '@solidjs/testing-library'; +import { describe, expect, it, vi } from 'vitest'; +import { page } from 'vitest/browser'; + +import { MaterialTheme } from '../../styling/material-theme/MaterialTheme'; + +import { MaterialNavigationRailMenuContext } from './MaterialNavigationRailLayout'; +import { MaterialNavigationRailLayoutMenuButton } from './MaterialNavigationRailLayoutMenuButton'; + +describe('MaterialNavigationRailLayoutMenuButton', () => { + describe('Visual', () => { + it('renders a button when rail is modal and hidden when collapsed', async () => { + const { baseElement } = render( + () => ( + true, () => false, vi.fn()]}> + + + ), + { wrapper: MaterialTheme } + ); + const screen = page.elementLocator(baseElement); + + const button = screen.getByRole('switch', { name: 'Menu button' }); + await expect.element(button).toBeVisible(); + }); + + it('renders nothing when rail is not modal or hidden when collapsed', async () => { + const { baseElement } = render( + () => ( + false, () => false, vi.fn()]}> + + + ), + { wrapper: MaterialTheme } + ); + const screen = page.elementLocator(baseElement); + + const button = screen.getByRole('switch', { name: 'Menu button' }); + await expect.element(button).not.toBeInTheDocument(); + }); + }); +}); diff --git a/packages/material/src/layouts/navigation-rail-layout/MaterialNavigationRailLayoutMenuButton.tsx b/packages/material/src/layouts/navigation-rail-layout/MaterialNavigationRailLayoutMenuButton.tsx new file mode 100644 index 00000000..97848200 --- /dev/null +++ b/packages/material/src/layouts/navigation-rail-layout/MaterialNavigationRailLayoutMenuButton.tsx @@ -0,0 +1,29 @@ +import type { VoidComponent } from 'solid-js'; + +import { Show, useContext } from 'solid-js'; + +import type { MaterialNavigationMenuButton } from '../../components/navigation-rail/MaterialNavigationRailMenuButton'; + +import { MaterialNavigationRailMenuButton } from '../../components/navigation-rail/MaterialNavigationRailMenuButton'; + +import { MaterialNavigationRailMenuContext } from './MaterialNavigationRailLayout'; + +export type MaterialNavigationRailLayoutMenuButtonProps = MaterialNavigationMenuButton; + +/** + * Render a menu button to show or hide a navigation rail if that rail + * is modal and hidden (when collapsed), otherwise renders nothing + * + * Should be used in the `leadingButton` prop of the {@link MaterialAppBar}. + */ +export const MaterialNavigationRailLayoutMenuButton: VoidComponent< + MaterialNavigationRailLayoutMenuButtonProps +> = props => { + const [isRailMenuButtonVisible, isRailExpanded, onClickMenuButton] = useContext(MaterialNavigationRailMenuContext); + + return ( + + + + ); +}; From 4d4e04f443912ee7a67ac3b9b549e2412ad30165 Mon Sep 17 00:00:00 2001 From: Mark Provo Kluit Date: Sat, 19 Sep 2026 19:02:21 +0200 Subject: [PATCH 2/6] refactor(calculator): use new component for back button in app bar --- .changeset/forty-kiwis-jump.md | 5 +++++ apps/calculator/src/routes/about.tsx | 8 ++++++-- apps/calculator/src/routes/settings.tsx | 8 ++++++-- 3 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 .changeset/forty-kiwis-jump.md diff --git a/.changeset/forty-kiwis-jump.md b/.changeset/forty-kiwis-jump.md new file mode 100644 index 00000000..0e34b54d --- /dev/null +++ b/.changeset/forty-kiwis-jump.md @@ -0,0 +1,5 @@ +--- +'@solidmaterial/calculator': patch +--- + +Use new component for back button in app bar diff --git a/apps/calculator/src/routes/about.tsx b/apps/calculator/src/routes/about.tsx index cb23a44c..70ef947c 100644 --- a/apps/calculator/src/routes/about.tsx +++ b/apps/calculator/src/routes/about.tsx @@ -5,7 +5,7 @@ import favIconUrl from '/assets/favicon.svg?url&no-inline'; // import { MetaProvider, Title } from '@solidjs/meta'; import { useNavigate } from '@solidjs/router'; -import { MaterialAppBar } from '@solidmaterial/material/components/app-bar'; +import { MaterialAppBar, MaterialAppBarBackButton } from '@solidmaterial/material/components/app-bar'; import { H2, H3 } from '@solidmaterial/material/components/typography'; import { MaterialBodyLayout, MaterialPane } from '@solidmaterial/material/layouts'; @@ -24,7 +24,11 @@ const RouteAbout: Component = () => { - + } + />
logo

diff --git a/apps/calculator/src/routes/settings.tsx b/apps/calculator/src/routes/settings.tsx index dbb58f38..4d6f6f7f 100644 --- a/apps/calculator/src/routes/settings.tsx +++ b/apps/calculator/src/routes/settings.tsx @@ -3,7 +3,7 @@ import type { Component, VoidComponent } from 'solid-js'; import { MetaProvider, Title } from '@solidjs/meta'; import { useNavigate } from '@solidjs/router'; -import { MaterialAppBar } from '@solidmaterial/material/components/app-bar'; +import { MaterialAppBar, MaterialAppBarBackButton } from '@solidmaterial/material/components/app-bar'; import { MaterialButton } from '@solidmaterial/material/components/button'; import { MaterialDialog } from '@solidmaterial/material/components/dialog'; import { MaterialIcon } from '@solidmaterial/material/components/icon'; @@ -99,7 +99,11 @@ const RouteSettings: Component = () => { - + } + />

Theme From c02d7e548de87bfeeeff4919afb3c0df9746a305 Mon Sep 17 00:00:00 2001 From: Mark Provo Kluit Date: Sun, 20 Sep 2026 13:34:33 +0200 Subject: [PATCH 3/6] refactor(landing-page): use new component for back button in app bar --- .changeset/seven-pans-speak.md | 5 +++++ .../src/examples/calculator/Calculator.tsx | 5 ++--- .../src/examples/todo-list/TodoList.tsx | 5 ++--- apps/landing-page/src/routes/get-started.tsx | 13 ++++++------- 4 files changed, 15 insertions(+), 13 deletions(-) create mode 100644 .changeset/seven-pans-speak.md diff --git a/.changeset/seven-pans-speak.md b/.changeset/seven-pans-speak.md new file mode 100644 index 00000000..0854c55f --- /dev/null +++ b/.changeset/seven-pans-speak.md @@ -0,0 +1,5 @@ +--- +'@solidmaterial/landing-page': patch +--- + +Use new component for back button in app bar diff --git a/apps/landing-page/src/examples/calculator/Calculator.tsx b/apps/landing-page/src/examples/calculator/Calculator.tsx index 8abd052a..98455f50 100644 --- a/apps/landing-page/src/examples/calculator/Calculator.tsx +++ b/apps/landing-page/src/examples/calculator/Calculator.tsx @@ -1,7 +1,7 @@ import type { VoidComponent } from 'solid-js'; import { useNavigate } from '@solidjs/router'; -import { MaterialAppBar } from '@solidmaterial/material/components/app-bar'; +import { MaterialAppBar, MaterialAppBarBackButton } from '@solidmaterial/material/components/app-bar'; import { MaterialIconButton } from '@solidmaterial/material/components/icon-button'; import { Breakpoints } from '@solidmaterial/material/utils'; import { createSignal } from 'solid-js'; @@ -31,7 +31,7 @@ export const Calculator: VoidComponent = props => { } trailingButtons={ = props => { target="_blank" /> } - onNavigate={navigateBackToList} />
diff --git a/apps/landing-page/src/examples/todo-list/TodoList.tsx b/apps/landing-page/src/examples/todo-list/TodoList.tsx index 955a5818..a6796c78 100644 --- a/apps/landing-page/src/examples/todo-list/TodoList.tsx +++ b/apps/landing-page/src/examples/todo-list/TodoList.tsx @@ -1,7 +1,7 @@ import type { VoidComponent } from 'solid-js'; import { useNavigate } from '@solidjs/router'; -import { MaterialAppBar } from '@solidmaterial/material/components/app-bar'; +import { MaterialAppBar, MaterialAppBarBackButton } from '@solidmaterial/material/components/app-bar'; import { MaterialButton } from '@solidmaterial/material/components/button'; import { MaterialCheckbox } from '@solidmaterial/material/components/checkbox'; import { MaterialIconButton } from '@solidmaterial/material/components/icon-button'; @@ -68,8 +68,7 @@ export const TodoList: VoidComponent = props => { } />
diff --git a/apps/landing-page/src/routes/get-started.tsx b/apps/landing-page/src/routes/get-started.tsx index 936292d1..9ca99fa2 100644 --- a/apps/landing-page/src/routes/get-started.tsx +++ b/apps/landing-page/src/routes/get-started.tsx @@ -1,10 +1,13 @@ import type { Component } from 'solid-js'; import { MetaProvider, Title } from '@solidjs/meta'; -import { useNavigate } from '@solidjs/router'; import { MaterialAppBar } from '@solidmaterial/material/components/app-bar'; import { H2, H3, Span } from '@solidmaterial/material/components/typography'; -import { MaterialBodyLayout, MaterialPane } from '@solidmaterial/material/layouts'; +import { + MaterialBodyLayout, + MaterialNavigationRailLayoutMenuButton, + MaterialPane +} from '@solidmaterial/material/layouts'; import { Breakpoints } from '@solidmaterial/material/utils'; import { createSignal } from 'solid-js'; @@ -22,9 +25,6 @@ import { PromptBlock } from '../components/prompt-block/PromptBlock'; import styles from './get-started.module.css'; const PageGetStarted: Component = () => { - const navigate = useNavigate(); - const navigateBackToList = () => navigate('..', { state: { transition: 'top-level' } }); - const isMobile = () => Breakpoints.isCompactWidth(); const [activeTab, setActiveTab] = createSignal<'pnpm' | 'yarn' | 'npm'>('pnpm'); @@ -39,8 +39,7 @@ const PageGetStarted: Component = () => { } />
From 6b54ab25c8493cb6f9da4ffa9a5f9acc90d84df1 Mon Sep 17 00:00:00 2001 From: Mark Provo Kluit Date: Sun, 20 Sep 2026 14:46:28 +0200 Subject: [PATCH 4/6] feat(landing-page): add app bars with menu button to pages --- .changeset/long-horses-rule.md | 5 ++ .../src/routes/components/[[name]].module.css | 19 ++++-- .../src/routes/components/[[name]].tsx | 66 +++++++++++-------- .../src/routes/examples/[[name]].module.css | 7 ++ .../src/routes/examples/[[name]].tsx | 20 ++++-- apps/landing-page/src/routes/index.tsx | 7 +- 6 files changed, 87 insertions(+), 37 deletions(-) create mode 100644 .changeset/long-horses-rule.md diff --git a/.changeset/long-horses-rule.md b/.changeset/long-horses-rule.md new file mode 100644 index 00000000..dcb4879e --- /dev/null +++ b/.changeset/long-horses-rule.md @@ -0,0 +1,5 @@ +--- +'@solidmaterial/landing-page': minor +--- + +Add app bars with menu button to pages diff --git a/apps/landing-page/src/routes/components/[[name]].module.css b/apps/landing-page/src/routes/components/[[name]].module.css index 51c60fac..b32ddb94 100644 --- a/apps/landing-page/src/routes/components/[[name]].module.css +++ b/apps/landing-page/src/routes/components/[[name]].module.css @@ -1,11 +1,20 @@ .list-pane { --md-comp-pane-container-color: var(--md-sys-color-surface-container-low); - h1 { - margin-block-end: var(--md-user-spacing-md); - } + --md-comp-app-bar-container-color: transparent; + + aside { + h1 { + margin-block-end: var(--md-user-spacing-md); + } - sm-list + h1 { - margin-block-start: var(--md-user-spacing-xl); + sm-list + h1 { + margin-block-start: var(--md-user-spacing-xl); + } } } + +/* Adjust app bar container color when it's not the only pane */ +sm-body-layout:not(:has(> :only-child)) .list-pane { + --md-comp-app-bar-on-scroll-container-color: var(--md-comp-pane-container-color); +} diff --git a/apps/landing-page/src/routes/components/[[name]].tsx b/apps/landing-page/src/routes/components/[[name]].tsx index 0896fac7..dc335d3c 100644 --- a/apps/landing-page/src/routes/components/[[name]].tsx +++ b/apps/landing-page/src/routes/components/[[name]].tsx @@ -2,8 +2,13 @@ import type { Component } from 'solid-js'; import { MetaProvider, Title } from '@solidjs/meta'; import { useParams } from '@solidjs/router'; +import { MaterialAppBar } from '@solidmaterial/material/components/app-bar'; import { H1 } from '@solidmaterial/material/components/typography'; -import { MaterialListDetailLayout, MaterialPane } from '@solidmaterial/material/layouts'; +import { + MaterialListDetailLayout, + MaterialNavigationRailLayoutMenuButton, + MaterialPane +} from '@solidmaterial/material/layouts'; import { Show, createMemo } from 'solid-js'; import { EmptyState } from '../../components/empty-state/EmptyState'; @@ -43,32 +48,39 @@ const PageComponents: Component = () => { - +
+ } + /> + +
diff --git a/apps/landing-page/src/routes/examples/[[name]].module.css b/apps/landing-page/src/routes/examples/[[name]].module.css index fcce6644..44db75d0 100644 --- a/apps/landing-page/src/routes/examples/[[name]].module.css +++ b/apps/landing-page/src/routes/examples/[[name]].module.css @@ -1,3 +1,10 @@ .list-pane { --md-comp-pane-container-color: var(--md-sys-color-surface-container-low); + + --md-comp-app-bar-container-color: transparent; +} + +/* Adjust app bar container color when it's not the only pane */ +sm-body-layout:not(:has(> :only-child)) .list-pane { + --md-comp-app-bar-on-scroll-container-color: var(--md-comp-pane-container-color); } diff --git a/apps/landing-page/src/routes/examples/[[name]].tsx b/apps/landing-page/src/routes/examples/[[name]].tsx index 6ff770ee..fb605215 100644 --- a/apps/landing-page/src/routes/examples/[[name]].tsx +++ b/apps/landing-page/src/routes/examples/[[name]].tsx @@ -3,7 +3,12 @@ import type { ParentComponent } from 'solid-js'; import { MetaProvider, Title } from '@solidjs/meta'; import { useParams } from '@solidjs/router'; -import { MaterialListDetailLayout, MaterialPane } from '@solidmaterial/material/layouts'; +import { MaterialAppBar } from '@solidmaterial/material/components/app-bar'; +import { + MaterialListDetailLayout, + MaterialNavigationRailLayoutMenuButton, + MaterialPane +} from '@solidmaterial/material/layouts'; import { Show, createMemo } from 'solid-js'; import { Dynamic } from 'solid-js/web'; @@ -33,9 +38,16 @@ const PageExamples: ParentComponent = () => { } > - +
+ } + /> + +
{ } trailingButtons={ <> Date: Sun, 20 Sep 2026 14:50:22 +0200 Subject: [PATCH 5/6] fix(landing-page): fix unstable text reflow in hero section Avoid unstable text reflow in hero section when changing the orientation on mobile. --- .changeset/green-rice-melt.md | 5 +++++ .../src/pages/home/sections/hero/SectionHero.module.css | 6 ++++++ 2 files changed, 11 insertions(+) create mode 100644 .changeset/green-rice-melt.md diff --git a/.changeset/green-rice-melt.md b/.changeset/green-rice-melt.md new file mode 100644 index 00000000..a45f68f9 --- /dev/null +++ b/.changeset/green-rice-melt.md @@ -0,0 +1,5 @@ +--- +'@solidmaterial/landing-page': patch +--- + +Avoid unstable text reflow in hero section when changing the orientation on mobile diff --git a/apps/landing-page/src/pages/home/sections/hero/SectionHero.module.css b/apps/landing-page/src/pages/home/sections/hero/SectionHero.module.css index 1eb71e5a..43b17fc0 100644 --- a/apps/landing-page/src/pages/home/sections/hero/SectionHero.module.css +++ b/apps/landing-page/src/pages/home/sections/hero/SectionHero.module.css @@ -12,6 +12,12 @@ transition-duration: var(--md-sys-motion-duration-spatial-fast); transition-timing-function: var(--md-sys-motion-spring-spatial-fast); + /* Avoid unstable text reflow when changing the orientation on mobile */ + @media (width < 600px) or (height < 480px) { + transition-duration: var(--md-sys-motion-duration-standard-spatial-fast); + transition-timing-function: var(--md-sys-motion-spring-standard-spatial-fast); + } + padding: var(--md-user-spacing-4xl); gap: var(--md-user-spacing-2xl); From 71f09c3f8a0f2828a97311cad7e5f01b0fcff110 Mon Sep 17 00:00:00 2001 From: Mark Provo Kluit Date: Sun, 20 Sep 2026 14:54:02 +0200 Subject: [PATCH 6/6] fix(material): fix modal hidden navigation rail blinking when navigating --- .changeset/tricky-keys-act.md | 5 +++++ .../navigation-rail/MaterialNavigationRail.module.css | 7 +++++++ .../MaterialNavigationRailLayout.module.css | 7 ------- 3 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 .changeset/tricky-keys-act.md diff --git a/.changeset/tricky-keys-act.md b/.changeset/tricky-keys-act.md new file mode 100644 index 00000000..28be0c7a --- /dev/null +++ b/.changeset/tricky-keys-act.md @@ -0,0 +1,5 @@ +--- +'@solidmaterial/material': patch +--- + +Fix modal hidden navigation rail blinking when navigating to a page diff --git a/packages/material/src/components/navigation-rail/MaterialNavigationRail.module.css b/packages/material/src/components/navigation-rail/MaterialNavigationRail.module.css index 9490ae6a..27beb551 100644 --- a/packages/material/src/components/navigation-rail/MaterialNavigationRail.module.css +++ b/packages/material/src/components/navigation-rail/MaterialNavigationRail.module.css @@ -25,6 +25,13 @@ .container { position: relative; + /** + * Make the rail part of the view transition (although it has no actual + * view transition) so that the rail, when it is modal, does not get + * temporily painted below the panes (which do have an actual view transition) + */ + view-transition-name: md-nav-rail; + &[data-modal] { position: fixed; left: 0; diff --git a/packages/material/src/layouts/navigation-rail-layout/MaterialNavigationRailLayout.module.css b/packages/material/src/layouts/navigation-rail-layout/MaterialNavigationRailLayout.module.css index 136d83b6..55e18996 100644 --- a/packages/material/src/layouts/navigation-rail-layout/MaterialNavigationRailLayout.module.css +++ b/packages/material/src/layouts/navigation-rail-layout/MaterialNavigationRailLayout.module.css @@ -16,13 +16,6 @@ z-index: 2; content-visibility: visible; - /** - * Make the rail part of the view transition (although it has no actual - * view transition) so that the rail, when it is modal, does not get - * temporily painted below the panes (which do have an actual view transition) - */ - view-transition-name: md-nav-rail; - /* Prevents collapsed navigation rail to be modal */ &[data-show]:has(sm-navigation-rail[data-modal]:not([data-always-expanded])) { min-width: var(--md-comp-nav-rail-container-width);