@bug-on/md3-react 2.0.1 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @file bottom-app-bar.tsx
3
+ * MD3 Expressive Bottom App Bar.
4
+ *
5
+ * Fixed to bottom of screen. Contains action icons and optional FAB.
6
+ * Height: 80px | Background: surface-container | Elevation: Level2 (always)
7
+ *
8
+ * @see docs/m3/app-bars/BottomAppBarTokens.kt
9
+ */
10
+ import type { BottomAppBarProps } from "./app-bar.types";
11
+ /**
12
+ * MD3 Expressive Bottom App Bar.
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * // With FAB
17
+ * <BottomAppBar
18
+ * actions={
19
+ * <>
20
+ * <IconButton aria-label="Check"><Icon>check_box</Icon></IconButton>
21
+ * <IconButton aria-label="Brush"><Icon>brush</Icon></IconButton>
22
+ * </>
23
+ * }
24
+ * floatingActionButton={<FAB aria-label="Compose">...</FAB>}
25
+ * />
26
+ *
27
+ * // Auto-hide on scroll
28
+ * <BottomAppBar scrollBehavior="hidden" actions={...} />
29
+ * ```
30
+ */
31
+ export declare function BottomAppBar({ actions, floatingActionButton, scrollBehavior, scrollElement, className, }: BottomAppBarProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @file docked-toolbar.tsx
3
+ * MD3 Expressive Docked Toolbar.
4
+ *
5
+ * Secondary navigation component. NOT an App Bar.
6
+ * Usually appears directly below the main App Bar.
7
+ * Height: 64px | Background: surface-container
8
+ * Typical content: chips, segmented buttons, filter actions.
9
+ *
10
+ * @see docs/m3/app-bars/DockedToolbarTokens.kt
11
+ */
12
+ import type { DockedToolbarProps } from "./app-bar.types";
13
+ /**
14
+ * MD3 Expressive Docked Toolbar.
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * <DockedToolbar aria-label="Filter options">
19
+ * <Chip label="All" selected onClick={() => setFilter('all')} />
20
+ * <Chip label="Unread" onClick={() => setFilter('unread')} />
21
+ * <Chip label="Starred" onClick={() => setFilter('starred')} />
22
+ * </DockedToolbar>
23
+ * ```
24
+ */
25
+ export declare function DockedToolbar({ children, "aria-label": ariaLabel, className, }: DockedToolbarProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @file use-app-bar-scroll.ts
3
+ * MD3 Expressive App Bar — Scroll behavior hook.
4
+ *
5
+ * Tracks scroll state for App Bar behaviors:
6
+ * - `pinned`: background color change only
7
+ * - `enterAlways`: hide/show based on scroll direction
8
+ * - `exitUntilCollapsed`: drives collapse fraction (0 = expanded, 1 = collapsed)
9
+ */
10
+ import * as React from "react";
11
+ import type { AppBarScrollBehavior, UseAppBarScrollReturn } from "../app-bar.types";
12
+ interface UseAppBarScrollOptions {
13
+ /** Ref to the scrollable container. Defaults to `window`. */
14
+ scrollElement?: React.RefObject<HTMLElement | null>;
15
+ /** Scroll behavior mode. @default "pinned" */
16
+ behavior?: AppBarScrollBehavior;
17
+ /** Collapsed height in px — used for `exitUntilCollapsed`. @default 64 */
18
+ collapsedHeight?: number;
19
+ /** Expanded height in px — used for `exitUntilCollapsed`. @default 112 */
20
+ expandedHeight?: number;
21
+ }
22
+ /**
23
+ * Tracks scroll position and derives App Bar state for all three behaviors.
24
+ *
25
+ * @example
26
+ * ```tsx
27
+ * // pinned (color change only)
28
+ * const { isScrolled } = useAppBarScroll({ behavior: 'pinned' });
29
+ *
30
+ * // enterAlways (hide/show)
31
+ * const { isHidden } = useAppBarScroll({ behavior: 'enterAlways' });
32
+ *
33
+ * // exitUntilCollapsed (collapse animation)
34
+ * const { collapsedFraction } = useAppBarScroll({
35
+ * behavior: 'exitUntilCollapsed',
36
+ * collapsedHeight: 64,
37
+ * expandedHeight: 112,
38
+ * });
39
+ * ```
40
+ */
41
+ export declare function useAppBarScroll({ scrollElement, behavior, collapsedHeight, expandedHeight, }?: UseAppBarScrollOptions): UseAppBarScrollReturn;
42
+ export {};
@@ -0,0 +1,37 @@
1
+ /**
2
+ * @file use-flexible-app-bar.ts
3
+ * Shared animation hook for MediumFlexibleAppBar and LargeFlexibleAppBar.
4
+ *
5
+ * Extracts common scroll-driven animation state to avoid duplication.
6
+ */
7
+ import type { MotionValue } from "motion/react";
8
+ import type { RefObject } from "react";
9
+ import type { AppBarColors } from "../app-bar.types";
10
+ interface UseFlexibleAppBarOptions {
11
+ collapsedHeight: number;
12
+ expandedHeight: number;
13
+ scrollElement?: RefObject<HTMLElement | null>;
14
+ colors?: AppBarColors;
15
+ /** [start, end] progress range where large title fades from 1 → 0 */
16
+ largeTitleFadeRange: [number, number];
17
+ /** [start, end] progress range where small title fades from 0 → 1 */
18
+ smallTitleFadeRange: [number, number];
19
+ /** [start, end] progress range where subtitle fades from 1 → 0 */
20
+ subtitleFadeRange: [number, number];
21
+ /** [start, end] progress range where headerContent fades from 1 → 0 */
22
+ headerContentFadeRange: [number, number];
23
+ /** [expanded, collapsed] Y offset for large title */
24
+ largeTitleYRange: [number, number];
25
+ }
26
+ export interface FlexibleAppBarAnimationState {
27
+ height: MotionValue<number>;
28
+ currentBg: string;
29
+ cssTransition: string | undefined;
30
+ largeTitleOpacity: MotionValue<number>;
31
+ largeTitleY: MotionValue<number>;
32
+ smallTitleOpacity: MotionValue<number>;
33
+ subtitleOpacity: MotionValue<number>;
34
+ headerContentOpacity: MotionValue<number>;
35
+ }
36
+ export declare function useFlexibleAppBar({ collapsedHeight, expandedHeight, scrollElement, colors, largeTitleFadeRange, smallTitleFadeRange, subtitleFadeRange, headerContentFadeRange, largeTitleYRange, }: UseFlexibleAppBarOptions): FlexibleAppBarAnimationState;
37
+ export {};
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @file index.ts
3
+ * MD3 Expressive App Bar — Public API exports.
4
+ *
5
+ * Components:
6
+ * - SmallAppBar: Single-row, 64px height, TitleLarge
7
+ * - MediumFlexibleAppBar: Collapsible, HeadlineMedium → TitleLarge
8
+ * - LargeFlexibleAppBar: Collapsible, DisplaySmall → TitleLarge
9
+ * - SearchAppBar: Pill search bar with layoutId for SearchView transition
10
+ * - SearchView: Full-screen search overlay
11
+ * - SearchViewContainer: Wraps SearchView with AnimatePresence
12
+ * - BottomAppBar: Fixed bottom nav with optional FAB
13
+ * - DockedToolbar: Secondary navigation bar
14
+ * - AppBarRow: Horizontal actions with overflow
15
+ * - AppBarColumn: Vertical actions with overflow
16
+ * - AppBarOverflowIndicator: More-vert dropdown trigger
17
+ *
18
+ * Hook:
19
+ * - useAppBarScroll: Drives scroll-based behavior (pinned / enterAlways / exitUntilCollapsed)
20
+ *
21
+ * Tokens:
22
+ * - AppBarTokens: Dimensional tokens (heights, spacing)
23
+ * - appBarTypography: Typography class strings
24
+ * - APP_BAR_COLORS: CSS custom property color references
25
+ * - Animation constants (APP_BAR_COLOR_TRANSITION, etc.)
26
+ */
27
+ export { APP_BAR_BOTTOM_SPRING, APP_BAR_COLOR_TRANSITION, APP_BAR_COLORS, APP_BAR_ENTER_ALWAYS_SPRING, APP_BAR_TITLE_FADE, AppBarTokens, appBarTypography, SEARCH_VIEW_SPRING, } from "./app-bar.tokens";
28
+ export type { AppBarColors, AppBarColumnProps, AppBarItem, AppBarItemType, AppBarMenuState, AppBarOverflowIndicatorProps, AppBarRowProps, AppBarScrollBehavior, BaseAppBarProps, BottomAppBarProps, DockedToolbarProps, FlexibleAppBarProps, SearchAppBarProps, SearchBarVariant, SearchViewProps, SmallAppBarProps, TitleAlignment, UseAppBarScrollReturn, } from "./app-bar.types";
29
+ export { AppBarColumn } from "./app-bar-column";
30
+ export { AppBarOverflowIndicator } from "./app-bar-overflow-indicator";
31
+ export { AppBarRow } from "./app-bar-row";
32
+ export { BottomAppBar } from "./bottom-app-bar";
33
+ export { DockedToolbar } from "./docked-toolbar";
34
+ export { useAppBarScroll } from "./hooks/use-app-bar-scroll";
35
+ export { LargeFlexibleAppBar } from "./large-flexible-app-bar";
36
+ export { MediumFlexibleAppBar } from "./medium-flexible-app-bar";
37
+ export { SearchAppBar } from "./search-app-bar";
38
+ export { SearchView, SearchViewContainer } from "./search-view";
39
+ export { SmallAppBar } from "./small-app-bar";
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @file large-flexible-app-bar.tsx
3
+ * MD3 Expressive Large Flexible App Bar.
4
+ *
5
+ * Like MediumFlexibleAppBar but with larger typography.
6
+ * Expanded height: 120px (no subtitle) / 152px (with subtitle)
7
+ * Collapsed height: 64px
8
+ * Title crossfade: DisplaySmall (expanded) ↔ TitleLarge (collapsed)
9
+ *
10
+ * @see docs/m3/app-bars/AppBarLargeFlexibleTokens.kt
11
+ */
12
+ import type { FlexibleAppBarProps } from "./app-bar.types";
13
+ /**
14
+ * MD3 Expressive Large Flexible App Bar.
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * <LargeFlexibleAppBar
19
+ * title="Discover"
20
+ * subtitle="Trending today"
21
+ * navigationIcon={<IconButton aria-label="Open menu"><Icon>menu</Icon></IconButton>}
22
+ * headerContent={<img src="/banner.jpg" alt="" className="rounded-xl h-20 w-full object-cover" />}
23
+ * />
24
+ * ```
25
+ */
26
+ export declare function LargeFlexibleAppBar({ title, subtitle, titleAlignment, navigationIcon, actions, colors, scrollElement, headerContent, collapsedHeight, expandedHeight, className, }: FlexibleAppBarProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @file medium-flexible-app-bar.tsx
3
+ * MD3 Expressive Medium Flexible App Bar.
4
+ *
5
+ * Two-row layout in expanded state, collapses to single row on scroll.
6
+ * Expanded height: 112px (no subtitle) / 136px (with subtitle)
7
+ * Collapsed height: 64px
8
+ * Title crossfade: HeadlineMedium (expanded) ↔ TitleLarge (collapsed)
9
+ *
10
+ * Supports `exitUntilCollapsed` scroll behavior only.
11
+ *
12
+ * @see docs/m3/app-bars/AppBarMediumFlexibleTokens.kt
13
+ */
14
+ import type { FlexibleAppBarProps } from "./app-bar.types";
15
+ /**
16
+ * MD3 Expressive Medium Flexible App Bar.
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * <MediumFlexibleAppBar
21
+ * title="Settings"
22
+ * subtitle="Manage your preferences"
23
+ * navigationIcon={<IconButton aria-label="Go back"><Icon>arrow_back</Icon></IconButton>}
24
+ * actions={<IconButton aria-label="More options"><Icon>more_vert</Icon></IconButton>}
25
+ * />
26
+ * ```
27
+ */
28
+ export declare function MediumFlexibleAppBar({ title, subtitle, titleAlignment, navigationIcon, actions, colors, scrollElement, headerContent, collapsedHeight, expandedHeight, className, }: FlexibleAppBarProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @file search-app-bar.tsx
3
+ * MD3 Expressive Search App Bar.
4
+ *
5
+ * New variant in MD3 Expressive (May 2025).
6
+ * Replaces the title area with a pill-shaped search bar.
7
+ * Uses Framer Motion layoutId to enable shared element transition with <SearchView>.
8
+ *
9
+ * @see docs/m3/app-bars/AppBar.kt — SearchAppBar
10
+ */
11
+ import type { SearchAppBarProps } from "./app-bar.types";
12
+ /**
13
+ * MD3 Expressive Search App Bar.
14
+ *
15
+ * When the search bar is clicked, callers should open a `<SearchView>` overlay.
16
+ * Uses Framer Motion `layoutId` (via `searchBarId`) for a smooth shared-element
17
+ * transition between this bar and the search view.
18
+ *
19
+ * @example
20
+ * ```tsx
21
+ * const [searchOpen, setSearchOpen] = useState(false);
22
+ *
23
+ * <SearchAppBar
24
+ * searchBarId="main-search"
25
+ * searchPlaceholder="Search messages..."
26
+ * onSearchFocus={() => setSearchOpen(true)}
27
+ * trailingSearchActions={
28
+ * <IconButton aria-label="Voice search"><Icon>mic</Icon></IconButton>
29
+ * }
30
+ * externalActions={<Avatar src={user.avatar} />}
31
+ * />
32
+ *
33
+ * <AnimatePresence>
34
+ * {searchOpen && (
35
+ * <SearchView
36
+ * searchBarId="main-search"
37
+ * onClose={() => setSearchOpen(false)}
38
+ * />
39
+ * )}
40
+ * </AnimatePresence>
41
+ * ```
42
+ */
43
+ export declare function SearchAppBar({ searchPlaceholder, searchValue, onSearchFocus, leadingSearchIcon, trailingSearchActions, externalActions, navigationIcon, colors, scrollBehavior, scrollElement, searchBarId, className, }: SearchAppBarProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * @file search-view.tsx
3
+ * MD3 Expressive Search View.
4
+ *
5
+ * Full-screen overlay activated when a SearchAppBar's search bar is clicked.
6
+ * Shares a Framer Motion `layoutId` with the SearchAppBar search bar for a
7
+ * smooth shared element transition.
8
+ *
9
+ * Usage pattern:
10
+ * ```tsx
11
+ * const [open, setOpen] = useState(false);
12
+ *
13
+ * // In render:
14
+ * <SearchAppBar searchBarId="main" onSearchFocus={() => setOpen(true)} />
15
+ * <AnimatePresence>
16
+ * {open && <SearchView searchBarId="main" onClose={() => setOpen(false)} />}
17
+ * </AnimatePresence>
18
+ * ```
19
+ *
20
+ * Design notes:
21
+ * - The SearchView is intentionally separate from SearchAppBar to allow consumers
22
+ * to customize the results/suggestions content without coupling.
23
+ * - The `searchBarId` prop must match between SearchAppBar and SearchView to
24
+ * enable the shared element transition.
25
+ * - Focus is moved to the search input when the view opens.
26
+ * - Escape key closes the view and returns focus to the search bar.
27
+ */
28
+ import type { SearchViewProps } from "./app-bar.types";
29
+ /**
30
+ * MD3 Expressive Search View.
31
+ *
32
+ * Renders a full-screen search overlay with a shared element transition
33
+ * from the triggering `<SearchAppBar>` search bar.
34
+ *
35
+ * Mount/unmount this component via `<AnimatePresence>` in the consumer.
36
+ */
37
+ export declare function SearchView({ searchBarId, value, onChange, onClose, placeholder, children, leadingIcon, trailingAction, className, }: SearchViewProps): import("react/jsx-runtime").JSX.Element;
38
+ /**
39
+ * Convenience wrapper that handles the AnimatePresence + open state.
40
+ *
41
+ * @example
42
+ * ```tsx
43
+ * <SearchBar
44
+ * isOpen={searchOpen}
45
+ * onClose={() => setSearchOpen(false)}
46
+ * searchBarId="main-search"
47
+ * >
48
+ * <SearchResultsList results={results} />
49
+ * </SearchBar>
50
+ * ```
51
+ */
52
+ export declare function SearchViewContainer({ isOpen, ...props }: SearchViewProps & {
53
+ isOpen: boolean;
54
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * @file small-app-bar.tsx
3
+ * MD3 Expressive Small App Bar.
4
+ *
5
+ * Single-row layout: [navigationIcon][title + subtitle][actions]
6
+ * Height: 64px | Title: TitleLarge (22sp) | Subtitle: LabelMedium (12sp)
7
+ *
8
+ * Scroll behaviors:
9
+ * - pinned: changes background color surface → surface-container
10
+ * - enterAlways: slides up when scrolling down, slides down when scrolling up
11
+ *
12
+ * @see docs/m3/app-bars/AppBarSmallTokens.kt
13
+ */
14
+ import type { SmallAppBarProps } from "./app-bar.types";
15
+ /**
16
+ * MD3 Expressive Small App Bar.
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * // Left-aligned (default)
21
+ * <SmallAppBar
22
+ * title="Inbox"
23
+ * navigationIcon={<IconButton aria-label="Go back"><Icon>arrow_back</Icon></IconButton>}
24
+ * actions={<IconButton aria-label="Search"><Icon>search</Icon></IconButton>}
25
+ * scrollBehavior="pinned"
26
+ * />
27
+ *
28
+ * // Center-aligned with subtitle
29
+ * <SmallAppBar
30
+ * title="Profile"
31
+ * subtitle="@username"
32
+ * titleAlignment="center"
33
+ * scrollBehavior="enterAlways"
34
+ * />
35
+ * ```
36
+ */
37
+ export declare function SmallAppBar({ title, subtitle, titleAlignment, navigationIcon, actions, colors, scrollBehavior, scrollElement, className, }: SmallAppBarProps): import("react/jsx-runtime").JSX.Element;
@@ -146,6 +146,7 @@ export declare namespace SnackbarHost {
146
146
  interface SnackbarContextValue {
147
147
  showSnackbar: (visuals: SnackbarVisuals) => Promise<SnackbarResult>;
148
148
  }
149
+ export declare const SnackbarContext: React.Context<SnackbarContextValue | null>;
149
150
  /**
150
151
  * MD3 SnackbarProvider — context provider for imperative snackbar API.
151
152
  *
@@ -1,5 +1,7 @@
1
1
  import { type ReactNode } from "react";
2
2
  import { type ThemeMode } from "../../lib/theme-utils";
3
+ import { Typography } from "../typography/typography";
4
+ import { type FontVariationAxes } from "../typography/typography-tokens";
3
5
  interface ThemeContextValue {
4
6
  sourceColor: string;
5
7
  setSourceColor: (color: string) => void;
@@ -11,8 +13,36 @@ export interface MD3ThemeProviderProps {
11
13
  sourceColor?: string;
12
14
  defaultMode?: ThemeMode;
13
15
  persistToLocalStorage?: boolean;
16
+ /**
17
+ * A fully custom `Typography` instance.
18
+ * When provided, `fontFamily` and `fontVariationAxes` are ignored.
19
+ */
20
+ typography?: Typography;
21
+ /**
22
+ * Override the CSS `font-family` for all typography styles.
23
+ * Ignored when `typography` prop is provided.
24
+ * @example "'Inter', sans-serif"
25
+ */
26
+ fontFamily?: string;
27
+ /**
28
+ * Variable font axes applied globally via `font-variation-settings`.
29
+ * Merged on top of defaults (`ROND: 100`). Ignored when `typography` is provided.
30
+ * @example { ROND: 50 }
31
+ */
32
+ fontVariationAxes?: FontVariationAxes;
33
+ /**
34
+ * When `true`, mounts `SnackbarHost` inside the provider and exposes
35
+ * `useSnackbar()` to all descendants — no separate `<SnackbarProvider>` needed.
36
+ *
37
+ * Opt-in, default `false`. For advanced usage (e.g., scoped snackbars or
38
+ * custom host positioning), keep this `false` and use `<SnackbarProvider>`
39
+ * or `<SnackbarHost>` directly.
40
+ *
41
+ * @default false
42
+ */
43
+ enableSnackbar?: boolean;
14
44
  }
15
- export declare function MD3ThemeProvider({ children, sourceColor: initialSourceColor, defaultMode, persistToLocalStorage, }: MD3ThemeProviderProps): import("react/jsx-runtime").JSX.Element;
45
+ export declare function MD3ThemeProvider({ children, sourceColor: initialSourceColor, defaultMode, persistToLocalStorage, typography: typographyProp, fontFamily, fontVariationAxes, enableSnackbar, }: MD3ThemeProviderProps): import("react/jsx-runtime").JSX.Element;
16
46
  export declare function useTheme(): ThemeContextValue;
17
47
  export declare function useThemeMode(): Pick<ThemeContextValue, "mode" | "setMode">;
18
48
  export {};
package/dist/ui/toc.d.ts CHANGED
@@ -14,6 +14,7 @@
14
14
  * (~100px) and early deactivation (~80% from bottom) so the active item changes
15
15
  * before the section scrolls off-screen.
16
16
  */
17
+ import { type ScrollAreaProps } from "./scroll-area";
17
18
  /**
18
19
  * A single entry in the Table of Contents.
19
20
  *
@@ -45,6 +46,11 @@ export interface TableOfContentsProps {
45
46
  * Use this to control positioning (e.g. sticky, fixed) from the consumer.
46
47
  */
47
48
  className?: string;
49
+ /**
50
+ * Configuration for the internal ScrollArea.
51
+ * @default { type: "hover" }
52
+ */
53
+ scrollAreaProps?: Omit<ScrollAreaProps, "children">;
48
54
  }
49
55
  /**
50
56
  * Table of Contents sidebar component.
@@ -71,4 +77,4 @@ export interface TableOfContentsProps {
71
77
  *
72
78
  * @see https://m3.material.io/foundations/content-design/navigation
73
79
  */
74
- export declare function TableOfContents({ items, className }: TableOfContentsProps): import("react/jsx-runtime").JSX.Element;
80
+ export declare function TableOfContents({ items, className, scrollAreaProps, }: TableOfContentsProps): import("react/jsx-runtime").JSX.Element;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bug-on/md3-react",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
4
4
  "description": "Material Design 3 Expressive React components",
5
5
  "author": "Bug Ổn",
6
6
  "license": "MIT",