JGuang

应用外壳

AppShell · Mantine Core

交互预览
npm install @mantine/core@9.7.1 @mantine/hooks@9.7.1

应用外壳

Mantine Core 的独立组件,请不要替换为 JGuang UI/Base UI 的同名 API。

安装

npm install @mantine/core@9.7.1 @mantine/hooks@9.7.1

入口引入 @mantine/core/styles.css,并在根组件使用 MantineProvider;通过 forceColorScheme 同步深浅色主题。

使用与验证

在左侧选择组件,在预览中操作它的状态;使用“查看代码”检查真实源码。安装后执行类型检查和构建,再验证键盘焦点、手机布局与深浅色主题。

来源

https://github.com/mantinedev/mantine/tree/f0e2bc6d28b0f0b8aaefb5b859937bf77f539df7 MIT 许可证;不包括付费内容。下方提供上游英文参考内容,中文使用指南已适配;上游详细参考暂保留英文。


版本与兼容性

固定的 Mantine Core 9.7.1 要求 React 和 React DOM 满足 ^19.2.0,并配套 @mantine/hooks@9.7.1。此条件来自实际 npm 包的 peerDependencies。React 18 或其他不兼容版本不能强行安装;先向项目负责人说明升级影响并确认方案,不使用 --force/--legacy-peer-deps 掩盖冲突。入口的原生 Provider 开启 theme.respectReducedMotion,并用 forceColorScheme 控制深浅色。

适用场景

组合应用头部、导航和主内容区域。

本地示例使用的原生参数

以下参数由本地、经过类型检查的 JSX 示例提取,按所属组件区分。不是全部属性清单;完整签名和继承关系见下方固定源码参考。

组件参数说明
AppShell.header应用头部布局配置。
AppShell.navbar应用导航布局配置。
AppShell.padding应用内容内边距配置。
AppShell.style本地样式或布局对象。
AppShell.Header.pMantine 内边距样式参数。
AppShell.Navbar.pMantine 内边距样式参数。

交互与状态检查

当前场景:默认。切换支持的禁用、错误或只读场景后检查真实行为;无此原生状态的组件不会被强行添加统一属性。验证键盘焦点和退出方式,修改值后按原生回调签名连接业务状态。

业务接入边界

固定布局区域相对于预览 iframe 的可视窗口定位。真实应用需配置响应式断点与导航收起状态。

宿主配置

先安装固定版本 @mantine/core 和 @mantine/hooks,在入口引入 @mantine/core/styles.css,并使用 MantineProvider。示例的 theme 和 variant 是 JGuang 编写的宿主参数,不是所有原生组件都接受的统一 API;通过 forceColorScheme 同步应用主题。源码面板中的原生实现仅供阅读,使用 npm 导出,不要单独复制内部实现。此批只覆盖 Core,不包括日期、图表和表单扩展包。上游详细说明保留英文,不宣称全文中文化。

可运行用法

以下代码使用资源原生 API;不是把其他设计系统的同名组件替换进来。

import { useState } from 'react';
import * as M from '@mantine/core';
import '@mantine/core/styles.css';


function ComponentPreview({ variant = 'Default' }: { variant?: string }) {
const content = <M.Text>Build something beautiful / 构建美好的界面</M.Text>;
return <M.AppShell header={{ height: 50 }} navbar={{ width: 110, breakpoint: "sm" }} padding="sm" style={{ width: "100%", minHeight: 280 }}><M.AppShell.Header p="sm">App header</M.AppShell.Header><M.AppShell.Navbar p="sm">Navigation</M.AppShell.Navbar><M.AppShell.Main>{content}</M.AppShell.Main></M.AppShell>;
}
export default function Example({ variant = 'Default', theme = 'light' }: { variant?: string; theme?: 'light' | 'dark' }) {
return <M.MantineProvider forceColorScheme={theme} theme={{ respectReducedMotion: true }}><ComponentPreview variant={variant} /></M.MantineProvider>;
}

可用状态与示例

默认

示例遵循 Mantine 原生 API。支持多状态的输入组件可将示例中的 variant 改为 Disabled、Invalid 或 Read only;这些只是示例标签,不是新增的组件属性。改造时保留组件要求的数据、受控值、store 和复合子组件结构。

Examples

This page contains documentation only. All AppShell components have a fixed position; examples are included in a separate documentation section.

Usage

AppShell is a layout component that can be used to create a common Header / Navbar / Footer / Aside layout pattern. All AppShell components have position: fixed styling, so they do not scroll with the page.

Basic AppShell example with header and navbar. The navbar is hidden on mobile by default and can be toggled with the burger button.

import { AppShell, Burger } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';

function Demo() {
  const [opened, { toggle }] = useDisclosure();

  return (
    <AppShell
      padding="md"
      header={{ height: 60 }}
      navbar={{
        width: 300,
        breakpoint: 'sm',
        collapsed: { mobile: !opened },
      }}
    >
      <AppShell.Header>
        <Burger
          opened={opened}
          onClick={toggle}
          hiddenFrom="sm"
          size="sm"
        />

        <div>Logo</div>
      </AppShell.Header>

      <AppShell.Navbar>Navbar</AppShell.Navbar>

      <AppShell.Main>Main</AppShell.Main>
    </AppShell>
  );
}

AppShell components

  • AppShell – root component that wraps all other sections and configures the overall layout.
  • AppShell.Header – fixed header at the top, controlled by the header prop.
  • AppShell.Navbar – fixed navbar on the left, controlled by the navbar prop.
  • AppShell.Aside – fixed aside on the right, controlled by the aside prop.
  • AppShell.Footer – fixed footer at the bottom, controlled by the footer prop.
  • AppShell.Main – main content area, statically positioned and offset by the other sections.
  • AppShell.Section – utility for grouping content inside AppShell.Navbar or AppShell.Aside, useful for scrollable areas.

Configuration

The AppShell component accepts header, footer, navbar, and aside props to configure the corresponding sections. You must set these props if you want to use the corresponding components. For example, to use the AppShell.Header component, you need to set the header prop on the AppShell component.

header and footer configuration objects share the same type:

interface Configuration {
  /** Height of the section: number, string or
   ** object with breakpoints as keys and height as values */
  height: AppShellSize | AppShellResponsiveSize;

  /** When collapsed is true, the section is hidden
   ** from the viewport and doesn't affect the AppShell.Main offset */
  collapsed?: boolean;

  /** Controls whether AppShell.Main should be offset by this section.
   ** Useful for scenarios like hiding a header based on scroll position. */
  offset?: boolean;
}

navbar and aside configuration objects type:

interface Configuration {
  /** Width of the section: number, string, or
   ** object with breakpoints as keys and widths as values */
  width: AppShellSize | AppShellResponsiveSize;

  /** Breakpoint at which the section switches to mobile mode.
   ** In mobile mode, the section always has 100% width and its
   ** collapsed state is controlled by `collapsed.mobile`
   ** instead of `collapsed.desktop` */
  breakpoint: MantineBreakpoint | (string & {}) | number;

  /** Determines whether the section should be collapsed */
  collapsed?: { desktop?: boolean; mobile?: boolean };
}

layout prop

layout prop controls how AppShell.Header/AppShell.Footer and AppShell.Navbar/AppShell.Aside are positioned relative to each other. It accepts alt and default values:

  • alt – AppShell.Navbar/AppShell.Aside extends the full viewport height, while AppShell.Header/AppShell.Footer width equals the viewport width minus the width of AppShell.Navbar and AppShell.Aside (example)
  • default – AppShell.Navbar/AppShell.Aside height equals the viewport height minus AppShell.Header/AppShell.Footer height, and AppShell.Header/AppShell.Footer spans the full viewport width (example)

Resizable sections

Use the useAppShellResize hook together with the resize prop to let the user resize AppShell.Navbar/AppShell.Aside horizontally and AppShell.Header/AppShell.Footer vertically – with a mouse, touch, or keyboard. Only the sections passed to useAppShellResize get a resize handle, the section configuration objects (navbar={{ width, breakpoint }} etc.) do not change:

import { AppShell, useAppShellResize } from '@mantine/core';

function Demo() {
  const resize = useAppShellResize({
    navbar: { min: 200, max: 500 },
    header: { min: 48, max: 120 },
  });

  return (
    <AppShell
      header={{ height: 60 }}
      navbar={{ width: 300, breakpoint: 'sm' }}
      resize={resize}
    >
      <AppShell.Header>Header</AppShell.Header>
      <AppShell.Navbar>Navbar</AppShell.Navbar>
      <AppShell.Main>Main</AppShell.Main>
    </AppShell>
  );
}

In this example, navbar and header are passed to useAppShellResize, so AppShell.Navbar and AppShell.Header render a resize handle – AppShell.Aside and AppShell.Footer keep their configured size even if they are used elsewhere in the same AppShell. See the resizable app shell example for a full demo that includes a reset button.

Note that when the resize prop is set (same as with mode="static"), the --app-shell-* CSS variables are defined on the AppShell root element instead of :root, so they can only be read from elements rendered inside the AppShell.

useAppShellResize hook

The hook accepts an object with the following properties:

interface UseAppShellResizeInput {
  /** `AppShell.Navbar` resize options, the section is resizable when set */
  navbar?: AppShellResizeSectionOptions;

  /** `AppShell.Aside` resize options, the section is resizable when set */
  aside?: AppShellResizeSectionOptions;

  /** `AppShell.Header` resize options, the section is resizable when set */
  header?: AppShellResizeSectionOptions;

  /** `AppShell.Footer` resize options, the section is resizable when set */
  footer?: AppShellResizeSectionOptions;

  /** Sizes applied to sections that have not been resized yet, usually restored from storage */
  initialSizes?: AppShellResizeSizes;

  /** Called on every pointer move during a resize */
  onResize?: (sizes: AppShellResizeSizes) => void;

  /** Called when a resize is committed */
  onResizeEnd?: (sizes: AppShellResizeSizes) => void;

  /** Called when a section is dragged across its `collapseThreshold` */
  onCollapseChange?: (section: AppShellResizeSection, collapsed: boolean) => void;
}

Each section option (navbar, aside, header, footer) accepts the same shape:

interface AppShellResizeSectionOptions {
  /** Minimum size, in the same units as the section `width`/`height` configuration @default 0 */
  min?: number;

  /** Maximum size, in the same units as the section `width`/`height` configuration @default viewport size */
  max?: number;

  /** Size below which `onCollapseChange` reports the section as collapsed */
  collapseThreshold?: number;

  /** `aria-label` of the resize handle @default 'Resize navbar' | 'Resize aside' | 'Resize header' | 'Resize footer' */
  label?: string;
}

Note that the effective maximum is always the smaller of max and the current viewport size – a max larger than the viewport has no effect.

Resize handles are rendered as role="separator" elements with an English aria-label by default (Resize navbar, Resize aside, Resize header, Resize footer). Use the label option to localize it or to describe the section more precisely, for example navbar: { min: 200, max: 500, label: 'Sidebar width' }.

useAppShellResize returns a controller for every section (navbar, aside, header, footer) with the following shape:

interface AppShellResizeSectionController {
  /** `true` when the section was configured as resizable */
  enabled: boolean;

  /** Current size override, `undefined` when the section has not been resized */
  size: number | undefined;

  /** `true` while the section is being resized */
  active: boolean;

  /** Sets the section size, does not call `onResize`/`onResizeEnd` */
  setSize: (size: number) => void;

  /** Clears the size override, the section returns to the size defined in its configuration */
  reset: () => void;
}

as well as sizes – current size overrides of all sections, and resetAll() – clears size overrides of all sections. setSize, reset, and resetAll never call onResize/onResizeEnd. The returned object also carries a few fields used internally by AppShell to wire up the resize handles (options, activeSection, startResize, previewResize, endResize, initCollapse, reportCollapse) – you do not need to use them directly.

Keyboard shortcuts

Every resize handle is focusable and supports the following keys. Keys for the section's other axis (for example, ArrowUp/ArrowDown on AppShell.Navbar) are ignored:

Arrow key, Home, and End presses commit the size immediately, so they trigger onResizeEnd, not onResize. Double-clicking a handle resets the section, same as calling reset().

Responsive sizes and reset

Once a section is resized, it stops following its configured width/height – including a responsive { base, sm, ... } object – until reset() is called. Calling reset() (or double-clicking the handle) returns the section to the value currently defined in its width/height configuration.

Persisting sizes

Combine useAppShellResize with use-local-storage to remember sizes between visits:

const [sizes, setSizes] = useLocalStorage<AppShellResizeSizes>({
  key: 'app-shell-sizes',
  defaultValue: {},
});

const resize = useAppShellResize({
  navbar: { min: 200, max: 500 },
  initialSizes: sizes,
  onResizeEnd: setSizes,
});

initialSizes is applied to a section only until that section is first resized. This is what makes the pattern above work with useLocalStorage – its stored value is only available after the initial render (getInitialValueInEffect: true by default), and by the time it arrives the section has not been touched yet, so it is still picked up.

reset() and resetAll() never call onResize/onResizeEnd, so calling them does not clear a size that was already written to storage by a previous onResizeEnd call – clear the stored value yourself in whatever reset handler your application uses alongside reset()/resetAll().

Drag-to-collapse

Set collapseThreshold on a section to have onCollapseChange report when a drag crosses that size:

const resize = useAppShellResize({
  navbar: { min: 200, max: 500, collapseThreshold: 120 },
  onCollapseChange: (section, collapsed) => {
    if (section === 'navbar') {
      setNavbarCollapsed(collapsed);
    }
  },
});

onCollapseChange only reports the crossing – your application still owns the collapsed prop of AppShell.Navbar/AppShell.Aside/AppShell.Header/AppShell.Footer. Note that a collapsed AppShell.Navbar/AppShell.Aside moves its resize handle off screen together with the rest of the section, so pair drag-to-collapse with a Burger (or another control) rather than relying on the handle as the way to bring the section back.

Hiding the resize handle

Resize handles are hidden below the AppShell.Navbar/AppShell.Aside breakpoint, and while the corresponding section is collapsed.

Height configuration

The height property in header and footer configuration objects works as follows:

  • If you pass a number, the value will be converted to rem and used as the height at all viewport sizes.
  • To change height based on viewport width, use an object with breakpoints as keys and height as values. This works the same way as style props.

Example with height as a number: height is converted to rem, and height remains the same at all viewport sizes:

import { AppShell } from '@mantine/core';

function Demo() {
  return (
    <AppShell header={{ height: 48 }}>
      <AppShell.Header>Header</AppShell.Header>
    </AppShell>
  );
}

Example with height as an object with breakpoints:

  • height is 48 when viewport width is < theme.breakpoints.sm
  • height is 60 when viewport width is >= theme.breakpoints.sm and < theme.breakpoints.lg
  • height is 76 when viewport width is >= theme.breakpoints.lg
import { AppShell } from '@mantine/core';

function Demo() {
  return (
    <AppShell header={{ height: { base: 48, sm: 60, lg: 76 } }}>
      <AppShell.Header>Header</AppShell.Header>
    </AppShell>
  );
}

Width configuration

The width property in navbar and aside configuration objects works as follows:

  • If you pass a number, the value will be converted to rem and used as the width when the viewport is larger than breakpoint.
  • To change width based on viewport width, use an object with breakpoints as keys and width as values. This works the same way as style props. Note that width is always 100% when the viewport is smaller than breakpoint.

Example with width as a number: width is converted to rem, and width remains the same at viewport sizes larger than breakpoint. The width is 100% when viewport width is less than breakpoint:

import { AppShell } from '@mantine/core';

function Demo() {
  return (
    <AppShell navbar={{ width: 48, breakpoint: 'sm' }}>
      <AppShell.Navbar>Navbar</AppShell.Navbar>
    </AppShell>
  );
}

Example with width as an object with breakpoints:

  • width is 100% when viewport width is < theme.breakpoints.sm
  • width is 200 when viewport width is >= theme.breakpoints.sm and < theme.breakpoints.lg
  • width is 300 when viewport width is >= theme.breakpoints.lg
import { AppShell } from '@mantine/core';

function Demo() {
  return (
    <AppShell
      navbar={{ width: { sm: 200, lg: 300 }, breakpoint: 'sm' }}
    >
      <AppShell.Navbar>Navbar</AppShell.Navbar>
    </AppShell>
  );
}

padding prop

The padding prop controls the padding of the AppShell.Main component. It's important to use this prop instead of setting padding directly on AppShell.Main because this padding is also used to calculate offsets for the AppShell.Header, AppShell.Navbar, AppShell.Aside, and AppShell.Footer components.

The padding prop works the same way as style props and accepts numbers, strings, and objects with breakpoints as keys and padding values. You can reference theme.spacing values or use any valid CSS value.

Example with static padding prop:

import { AppShell } from '@mantine/core';

function Demo() {
  return <AppShell padding="md">{/* AppShell content */}</AppShell>;
}

Example with responsive padding prop:

  • padding is 10 when viewport width is < theme.breakpoints.sm
  • padding is 15 when viewport width is >= theme.breakpoints.sm and < theme.breakpoints.lg
  • padding is theme.spacing.xl when viewport width is >= theme.breakpoints.lg
import { AppShell } from '@mantine/core';

function Demo() {
  return (
    <AppShell padding={{ base: 10, sm: 15, lg: 'xl' }}>
      {/* AppShell content */}
    </AppShell>
  );
}

Header offset configuration

The header prop includes an offset property that allows you to control whether the AppShell.Main component is offset by the header's height. This is particularly useful when you want to collapse the AppShell.Header based on scroll position. For example, you can use the use-headroom hook to hide the header when the user scrolls down and show it when they scroll up (example).

import { AppShell, rem } from '@mantine/core';
import { useHeadroom } from '@mantine/hooks';

function Demo() {
  const { pinned } = useHeadroom({ fixedAt: 120 });

  return (
    <AppShell
      header={{ height: 60, collapsed: !pinned, offset: false }}
      padding="md"
    >
      <AppShell.Header>Header</AppShell.Header>

      <AppShell.Main
        pt={`calc(${rem(60)} + var(--mantine-spacing-md))`}
      >
        {/* Content */}
      </AppShell.Main>
    </AppShell>
  );
}

Collapsed navbar/aside configuration

The navbar and aside props include a collapsed property that accepts an object with the format { mobile: boolean; desktop: boolean }. This allows you to configure the collapsed state differently based on viewport width.

Example with separate collapsed states for mobile and desktop:

import { AppShell, Button } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';

export function CollapseDesktop() {
  const [mobileOpened, { toggle: toggleMobile }] = useDisclosure();
  const [desktopOpened, { toggle: toggleDesktop }] =
    useDisclosure(true);

  return (
    <AppShell
      padding="md"
      header={{ height: 60 }}
      navbar={{
        width: 300,
        breakpoint: 'sm',
        collapsed: { mobile: !mobileOpened, desktop: !desktopOpened },
      }}
    >
      <AppShell.Header>Header</AppShell.Header>
      <AppShell.Navbar>Navbar</AppShell.Navbar>
      <AppShell.Main>
        <Button onClick={toggleDesktop} visibleFrom="sm">
          Toggle navbar
        </Button>
        <Button onClick={toggleMobile} hiddenFrom="sm">
          Toggle navbar
        </Button>
      </AppShell.Main>
    </AppShell>
  );
}

withBorder prop

The withBorder prop is available on AppShell and associated sections: AppShell.Header, AppShell.Navbar, AppShell.Aside and AppShell.Footer. By default, withBorder prop is true – all components have a border on the side that is adjacent to the AppShell.Main component. For example, AppShell.Header is located at the top of the page – it has a border on the bottom side, AppShell.Navbar is located on the left side of the page – it has a border on the right side.

To remove the border from all components, set withBorder={false} on the AppShell:

import { AppShell } from '@mantine/core';

// None of the components will have a border
function Demo() {
  return (
    <AppShell withBorder={false}>{/* AppShell content */}</AppShell>
  );
}

To remove the border from a specific component, set withBorder={false} on that component:

import { AppShell } from '@mantine/core';

function Demo() {
  return (
    <AppShell>
      <AppShell.Header withBorder={false}>Header</AppShell.Header>
    </AppShell>
  );
}

zIndex prop

The zIndex prop is available on AppShell and its associated sections: AppShell.Header, AppShell.Navbar, AppShell.Aside, and AppShell.Footer. By default, all sections have a z-index of 100.

To change the z-index of all sections, set the zIndex prop on the AppShell component:

import { AppShell } from '@mantine/core';

// All sections will have z-index of 200
function Demo() {
  return <AppShell zIndex={200}>{/* AppShell content */}</AppShell>;
}

To change z-index of a specific section, set zIndex prop on that section:

import { AppShell } from '@mantine/core';

// AppShell.Header has z-index of 100
// AppShell.Navbar and AppShell.Aside have z-index of 300
function Demo() {
  return (
    <AppShell>
      <AppShell.Header zIndex={100}>Header</AppShell.Header>
      <AppShell.Navbar zIndex={300}>Navbar</AppShell.Navbar>
      <AppShell.Aside zIndex={300}>Aside</AppShell.Aside>
    </AppShell>
  );
}

Control transitions

Use the transitionDuration and transitionTimingFunction props on the AppShell component to control section animations:

import { AppShell } from '@mantine/core';

function Demo() {
  return (
    <AppShell
      transitionDuration={500}
      transitionTimingFunction="ease"
    >
      {/* AppShell content */}
    </AppShell>
  );
}

disabled prop

Set the disabled prop on the AppShell component to prevent all sections except AppShell.Main from rendering. This is useful when you want to hide the shell on certain pages of your application.

import { AppShell } from '@mantine/core';

function Demo() {
  return <AppShell disabled>{/* AppShell content */}</AppShell>;
}

AppShell.Section component

AppShell.Section is used to create organized areas within AppShell.Navbar and AppShell.Aside. Since these components are flexbox containers with flex-direction: column, the AppShell.Section component with the grow prop will expand to fill the available space and can be made scrollable by setting component={ScrollArea}.

In the following example:

  • The first and last sections (header and footer) take only the space needed for their content
  • The middle section with grow takes all the remaining space and becomes scrollable when content exceeds the available height
import { AppShell, ScrollArea } from '@mantine/core';

function Demo() {
  return (
    <AppShell navbar={{ width: 300, breakpoint: 0 }}>
      <AppShell.Navbar>
        <AppShell.Section>Navbar header</AppShell.Section>
        <AppShell.Section grow component={ScrollArea}>
          Navbar main section that will expand to fill available space
        </AppShell.Section>
        <AppShell.Section>
          Navbar footer – always at the bottom
        </AppShell.Section>
      </AppShell.Navbar>
      <AppShell.Main>Main</AppShell.Main>
    </AppShell>
  );
}

Semantic elements

Important: do not use a <main> element inside AppShell.Main, as only one <main> element is allowed per page.

<DataTable head={['Component', 'Root HTML element']} data={[ [<Code>AppShell.Header</Code>, <Code>header</Code>], [<Code>AppShell.Footer</Code>, <Code>footer</Code>], [<Code>AppShell.Main</Code>, <Code>main</Code>], [<Code>AppShell.Navbar</Code>, <Code>nav</Code>], [<Code>AppShell.Aside</Code>, <Code>aside</Code>], [<Code>AppShell.Section</Code>, <Code>div</Code>], ]} />

CSS variables

<DataTable head={['Variable', 'Description']} data={[ [<Code>--app-shell-navbar-width</Code>, 'Navbar width'], [<Code>--app-shell-navbar-offset</Code>, 'Navbar offset'], [<Code>--app-shell-aside-width</Code>, 'Aside width'], [<Code>--app-shell-aside-offset</Code>, 'Aside offset'], [<Code>--app-shell-header-height</Code>, 'Header height'], [<Code>--app-shell-header-offset</Code>, 'Header offset'], [<Code>--app-shell-footer-height</Code>, 'Footer height'], [<Code>--app-shell-footer-offset</Code>, 'Footer offset'], ]} />

Example of using CSS variables in styles:

.main {
  min-height: calc(100dvh - var(--app-shell-header-height));
}

These variables are defined on :root by default, but on the AppShell root element when the resize prop is set or mode="static" is used – in these cases they are not available to elements rendered outside of the AppShell, for example, in a Modal or Drawer rendered within a Portal.

源码参数参考

以下实现签名和类型从本地固定版本源码生成。保留可选属性、原生继承类型、联合分支和 never 限制;不会将其他设计系统的 API 混入。forwardRef 实现中的 ref 属于 React 引用,不是新增业务属性。此区域是原始类型参考,不是上游说明的全文翻译。

AppShell(_props)
export type AppShellStylesNames =
  | 'root'
  | 'navbar'
  | 'main'
  | 'header'
  | 'footer'
  | 'aside'
  | 'section'
  | 'resizeHandle';

export type AppShellCssVariables = {
  root:
    | '--app-shell-transition-duration'
    | '--app-shell-transition-timing-function'
    | '--app-shell-resize-handle-size';
};

export interface AppShellProps
  extends BoxProps, StylesApiProps<AppShellFactory>, ElementProps<'div'> {
  /** If set, the associated components have a border @default true */
  withBorder?: boolean;

  /** Padding of the main section. Important: use `padding` prop instead of `p`. @default 0 */
  padding?: MantineSpacing | AppShellResponsiveSize;

  /** `Navbar` configuration, controls width, breakpoints and collapsed state. Required if you use `Navbar` component. */
  navbar?: AppShellNavbarConfiguration;

  /** `Aside` configuration, controls width, breakpoints and collapsed state. Required if you use `Aside` component. */
  aside?: AppShellAsideConfiguration;

  /** `Header` configuration, controls height, offset and collapsed state. Required if you use `Header` component. */
  header?: AppShellHeaderConfiguration;

  /** `Footer` configuration, controls height, offset and collapsed state. Required if you use `Footer` component. */
  footer?: AppShellFooterConfiguration;

  /** Duration of all transitions in ms @default 200 */
  transitionDuration?: number;

  /** Timing function of all transitions @default ease */
  transitionTimingFunction?: React.CSSProperties['transitionTimingFunction'];

  /** `z-index` of all associated elements @default 100 */
  zIndex?: string | number;

  /** Determines how `Navbar`/`Aside` are arranged relative to `Header`/`Footer` */
  layout?: 'default' | 'alt';

  /** If set, `Navbar`, `Aside`, `Header` and `Footer` components are hidden */
  disabled?: boolean;

  /** If set, `Header` and `Footer` components include styles to offset scrollbars. Based on `react-remove-scroll`. @default true */
  offsetScrollbars?: boolean;

  /** Determines positioning mode of all sections @default 'fixed' */
  mode?: 'fixed' | 'static';

  /** `useAppShellResize` hook instance, enables resizing of the sections configured in the hook */
  resize?: AppShellResizeController;
}

export type AppShellFactory = Factory<{
  props: AppShellProps;
  ref: HTMLDivElement;
  stylesNames: AppShellStylesNames;
  vars: AppShellCssVariables;
  staticComponents: {
    Navbar: typeof AppShellNavbar;
    Header: typeof AppShellHeader;
    Main: typeof AppShellMain;
    Aside: typeof AppShellAside;
    Footer: typeof AppShellFooter;
    Section: typeof AppShellSection;
  };
}>;

export type Mod = Record<string, any> | string;

export type BoxMod = Mod | Mod[] | BoxMod[];

export interface BoxProps extends MantineStyleProps {
  /** Class added to the root element, if applicable */
  className?: string | undefined;

  /** Inline style added to root component element, can subscribe to theme defined on MantineProvider */
  style?: MantineStyleProp;

  /** CSS variables defined on root component element */
  __vars?: CssVarsProp;

  /** `size` property passed down the HTML element */
  __size?: string;

  /** Breakpoint above which the component is hidden with `display: none` */
  hiddenFrom?: MantineBreakpoint;

  /** Breakpoint below which the component is hidden with `display: none` */
  visibleFrom?: MantineBreakpoint;

  /** Determines whether component should be hidden in light color scheme with `display: none` */
  lightHidden?: boolean;

  /** Determines whether component should be hidden in dark color scheme with `display: none` */
  darkHidden?: boolean;

  /** Element modifiers transformed into `data-` attributes, for example, `{ 'data-size': 'xl' }`, falsy values are removed */
  mod?: BoxMod;
}

export type ElementProps<
  ElementType extends React.ElementType,
  PropsToOmit extends string = never,
> = Omit<React.ComponentProps<ElementType>, 'style' | PropsToOmit>;

export interface CSSProperties extends React.CSSProperties {
  [key: string]: any;
}

type MantineStyle = CSSProperties | ((theme: MantineTheme) => CSSProperties);

export type MantineStyleProp = MantineStyle | MantineStyle[] | MantineStyleProp[] | undefined;

export type CssVariable = `--${string}`;

export type CssVariables<Variable extends string = CssVariable> = Partial<Record<Variable, string>>;

export type CssVars<Variable extends string = CssVariable> =
  | CssVariables<Variable>
  | ((theme: MantineTheme) => CssVariables<Variable>)
  | CssVars<Variable>[];

export type CssVarsProp<Variable extends string = CssVariable> =
  | CssVars<Variable>
  | CssVars<Variable>[];

原生与外部类型

以下外部类型仍由 React 或资源自身依赖定义,没有手工展开为虚构属性。实际可用类型以安装版本的 TypeScript 检查为准。

Factory<{
  props: AppShellProps;
  ref: HTMLDivElement;
  stylesNames: AppShellStylesNames;
  vars: AppShellCssVariables;
  staticComponents: {
    Navbar: typeof AppShellNavbar;
    Header: typeof AppShellHeader;
    Main: typeof AppShellMain;
    Aside: typeof AppShellAside;
    Footer: typeof AppShellFooter;
    Section: typeof AppShellSection;
  };
}>
MantineStyleProps
React.CSSProperties
MantineTheme
Partial<Record<Variable, string>>
Record<Variable, string>
Variable
MantineBreakpoint
Record<string, any>
StylesApiProps<AppShellFactory>
React.ElementType
Omit<React.ComponentProps<ElementType>, 'style' | PropsToOmit>
React.ComponentProps<ElementType>
ElementType
PropsToOmit
MantineSpacing
AppShellResponsiveSize
AppShellNavbarConfiguration
AppShellAsideConfiguration
AppShellHeaderConfiguration
AppShellFooterConfiguration
AppShellResizeController
HTMLDivElement