@bug-on/md3-react 2.0.3 → 3.0.0
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.
- package/.turbo/turbo-build.log +33 -0
- package/CHANGELOG.md +55 -0
- package/dist/index.css.d.ts +2 -0
- package/dist/index.d.mts +6127 -0
- package/dist/index.d.ts +6127 -71
- package/dist/index.js +1653 -614
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1566 -547
- package/dist/index.mjs.map +1 -1
- package/dist/material-symbols-cdn.css.d.ts +2 -0
- package/dist/material-symbols-self-hosted.css.d.ts +2 -0
- package/dist/typography.css.d.ts +2 -0
- package/package.json +22 -19
- package/scripts/copy-assets.js +82 -0
- package/src/assets/fonts/GoogleSansFlex-VariableFont.woff2 +0 -0
- package/src/assets/fonts/MaterialSymbolsOutlined-VariableFont_FILL,GRAD,opsz,wght.ttf +0 -0
- package/src/assets/fonts/MaterialSymbolsRounded-VariableFont_FILL,GRAD,opsz,wght.ttf +0 -0
- package/src/assets/fonts/MaterialSymbolsSharp-VariableFont_FILL,GRAD,opsz,wght.ttf +0 -0
- package/src/assets/loading-indicator.svg +19 -0
- package/src/assets/material-symbols-cdn.css +65 -0
- package/src/assets/material-symbols-self-hosted.css +90 -0
- package/src/css.d.ts +20 -0
- package/src/hooks/useClickOutside.ts +37 -0
- package/src/hooks/useMediaQuery.ts +28 -0
- package/src/hooks/useRipple.ts +88 -0
- package/src/index.css +23 -0
- package/src/index.ts +349 -0
- package/src/lib/material-symbols-preconnect.tsx +82 -0
- package/src/lib/theme-utils.ts +180 -0
- package/src/lib/utils.ts +6 -0
- package/src/test/button.test.tsx +59 -0
- package/src/test/icon.test.tsx +91 -0
- package/src/test/loading-indicator.test.tsx +128 -0
- package/src/test/progress-indicator.test.tsx +306 -0
- package/src/test/setup.ts +80 -0
- package/src/test/typography.test.tsx +206 -0
- package/src/types/index.ts +7 -0
- package/src/types/md3.ts +31 -0
- package/src/ui/Text.tsx +60 -0
- package/src/ui/__snapshots__/divider.test.tsx.snap +63 -0
- package/src/ui/app-bar/app-bar-column.tsx +99 -0
- package/src/ui/app-bar/app-bar-item-button.tsx +71 -0
- package/src/ui/app-bar/app-bar-items.test.tsx +89 -0
- package/src/ui/app-bar/app-bar-overflow-indicator.tsx +108 -0
- package/src/ui/app-bar/app-bar-row.tsx +104 -0
- package/src/ui/app-bar/app-bar.test.tsx +87 -0
- package/src/ui/app-bar/app-bar.tokens.ts +223 -0
- package/src/ui/app-bar/app-bar.types.ts +441 -0
- package/src/ui/app-bar/bottom-app-bar.test.tsx +42 -0
- package/src/ui/app-bar/bottom-app-bar.tsx +84 -0
- package/src/ui/app-bar/docked-toolbar.test.tsx +34 -0
- package/src/ui/app-bar/docked-toolbar.tsx +54 -0
- package/src/ui/app-bar/flexible-app-bar.test.tsx +75 -0
- package/src/ui/app-bar/hooks/use-app-bar-scroll.ts +110 -0
- package/src/ui/app-bar/hooks/use-flexible-app-bar.ts +123 -0
- package/{dist/ui/app-bar/index.d.ts → src/ui/app-bar/index.ts} +35 -2
- package/src/ui/app-bar/large-flexible-app-bar.tsx +165 -0
- package/src/ui/app-bar/medium-flexible-app-bar.tsx +167 -0
- package/src/ui/app-bar/search-app-bar.test.tsx +49 -0
- package/src/ui/app-bar/search-app-bar.tsx +176 -0
- package/src/ui/app-bar/search-view.tsx +227 -0
- package/src/ui/app-bar/small-app-bar.test.tsx +48 -0
- package/src/ui/app-bar/small-app-bar.tsx +203 -0
- package/src/ui/badge.test.tsx +345 -0
- package/src/ui/badge.tsx +282 -0
- package/src/ui/button-group.test.tsx +71 -0
- package/src/ui/button-group.tsx +350 -0
- package/src/ui/button.test.tsx +297 -0
- package/src/ui/button.tsx +669 -0
- package/src/ui/card.test.tsx +187 -0
- package/src/ui/card.tsx +259 -0
- package/src/ui/checkbox.test.tsx +423 -0
- package/src/ui/checkbox.tsx +525 -0
- package/src/ui/chip.test.tsx +292 -0
- package/src/ui/chip.tsx +548 -0
- package/src/ui/code-block.tsx +219 -0
- package/src/ui/dialog.test.tsx +300 -0
- package/src/ui/dialog.tsx +384 -0
- package/src/ui/divider.test.tsx +314 -0
- package/src/ui/divider.tsx +412 -0
- package/src/ui/drawer.tsx +240 -0
- package/src/ui/fab-menu.test.tsx +494 -0
- package/src/ui/fab-menu.tsx +739 -0
- package/src/ui/fab.test.tsx +232 -0
- package/src/ui/fab.tsx +505 -0
- package/src/ui/icon-button.test.tsx +515 -0
- package/src/ui/icon-button.tsx +525 -0
- package/src/ui/icon.test.tsx +197 -0
- package/src/ui/icon.tsx +179 -0
- package/src/ui/loading-indicator.test.tsx +73 -0
- package/src/ui/loading-indicator.tsx +312 -0
- package/src/ui/menu/context-menu.tsx +275 -0
- package/src/ui/menu/index.ts +77 -0
- package/src/ui/menu/menu-animations.ts +102 -0
- package/src/ui/menu/menu-context.tsx +99 -0
- package/src/ui/menu/menu-divider.tsx +47 -0
- package/src/ui/menu/menu-group.tsx +200 -0
- package/src/ui/menu/menu-item.tsx +294 -0
- package/src/ui/menu/menu-tokens.ts +208 -0
- package/src/ui/menu/menu-types.ts +313 -0
- package/src/ui/menu/menu.test.tsx +624 -0
- package/src/ui/menu/menu.tsx +289 -0
- package/src/ui/menu/sub-menu.tsx +223 -0
- package/src/ui/menu/vertical-menu.tsx +382 -0
- package/src/ui/navigation-rail.test.tsx +404 -0
- package/src/ui/navigation-rail.tsx +604 -0
- package/src/ui/progress-indicator/circular.tsx +248 -0
- package/src/ui/progress-indicator/hooks.ts +51 -0
- package/{dist/ui/progress-indicator/index.d.ts → src/ui/progress-indicator/index.tsx} +20 -2
- package/src/ui/progress-indicator/linear-flat.tsx +83 -0
- package/src/ui/progress-indicator/linear-wavy.tsx +243 -0
- package/src/ui/progress-indicator/linear.tsx +143 -0
- package/src/ui/progress-indicator/types.ts +158 -0
- package/src/ui/progress-indicator/utils.ts +73 -0
- package/src/ui/radio-button.test.tsx +407 -0
- package/src/ui/radio-button.tsx +551 -0
- package/src/ui/ripple.test.tsx +72 -0
- package/src/ui/ripple.tsx +234 -0
- package/src/ui/scroll-area.test.tsx +58 -0
- package/src/ui/scroll-area.tsx +139 -0
- package/src/ui/search/animated-placeholder.tsx +145 -0
- package/src/ui/search/hooks/use-search-keyboard.test.ts +202 -0
- package/src/ui/search/hooks/use-search-keyboard.ts +104 -0
- package/src/ui/search/hooks/use-search-view-focus.test.ts +96 -0
- package/src/ui/search/hooks/use-search-view-focus.ts +24 -0
- package/src/ui/search/index.ts +44 -0
- package/src/ui/search/search-bar.tsx +220 -0
- package/src/ui/search/search-context.tsx +42 -0
- package/src/ui/search/search-view-docked.tsx +194 -0
- package/src/ui/search/search-view-fullscreen.tsx +247 -0
- package/src/ui/search/search.test.tsx +233 -0
- package/src/ui/search/search.tokens.ts +134 -0
- package/src/ui/search/search.tsx +131 -0
- package/src/ui/search/search.types.ts +154 -0
- package/src/ui/search/trailing-action.tsx +49 -0
- package/src/ui/shared/constants.ts +122 -0
- package/{dist/ui/shared/touch-target.d.ts → src/ui/shared/touch-target.tsx} +13 -1
- package/src/ui/slider/hooks/useSliderMath.ts +195 -0
- package/{dist/ui/slider/index.d.ts → src/ui/slider/index.ts} +12 -1
- package/src/ui/slider/range-slider.tsx +561 -0
- package/src/ui/slider/slider-thumb.tsx +379 -0
- package/src/ui/slider/slider-track.tsx +912 -0
- package/src/ui/slider/slider.tokens.ts +189 -0
- package/src/ui/slider/slider.tsx +259 -0
- package/src/ui/slider/slider.types.ts +288 -0
- package/src/ui/snackbar/index.ts +20 -0
- package/src/ui/snackbar/snackbar.test.tsx +338 -0
- package/src/ui/snackbar/snackbar.tsx +476 -0
- package/{dist/ui/switch/index.d.ts → src/ui/switch/index.ts} +1 -0
- package/src/ui/switch/switch.stories.tsx +309 -0
- package/src/ui/switch/switch.test.tsx +243 -0
- package/src/ui/switch/switch.tokens.ts +89 -0
- package/src/ui/switch/switch.tsx +504 -0
- package/src/ui/switch/switch.types.ts +62 -0
- package/{dist/ui/tabs/index.d.ts → src/ui/tabs/index.ts} +8 -1
- package/src/ui/tabs/tab.tsx +407 -0
- package/src/ui/tabs/tabs-content.tsx +89 -0
- package/src/ui/tabs/tabs-list.tsx +146 -0
- package/src/ui/tabs/tabs.test.tsx +290 -0
- package/src/ui/tabs/tabs.tokens.ts +121 -0
- package/src/ui/tabs/tabs.tsx +229 -0
- package/src/ui/tabs/tabs.types.ts +185 -0
- package/{dist/ui/text-field/index.d.ts → src/ui/text-field/index.ts} +8 -1
- package/src/ui/text-field/subcomponents/active-indicator.tsx +67 -0
- package/src/ui/text-field/subcomponents/floating-label.tsx +161 -0
- package/src/ui/text-field/subcomponents/leading-icon.tsx +46 -0
- package/src/ui/text-field/subcomponents/outline-container.tsx +170 -0
- package/src/ui/text-field/subcomponents/prefix-suffix.tsx +59 -0
- package/src/ui/text-field/subcomponents/supporting-text.tsx +145 -0
- package/src/ui/text-field/subcomponents/trailing-icon.tsx +199 -0
- package/src/ui/text-field/text-field.test.tsx +454 -0
- package/src/ui/text-field/text-field.tokens.ts +104 -0
- package/src/ui/text-field/text-field.tsx +548 -0
- package/src/ui/text-field/text-field.types.ts +180 -0
- package/src/ui/theme-provider/index.tsx +190 -0
- package/src/ui/toc.test.tsx +108 -0
- package/src/ui/toc.tsx +172 -0
- package/src/ui/tooltip/plain-tooltip.tsx +63 -0
- package/src/ui/tooltip/rich-tooltip.tsx +94 -0
- package/src/ui/tooltip/tooltip-box.tsx +266 -0
- package/src/ui/tooltip/tooltip-caret-shape.tsx +68 -0
- package/src/ui/tooltip/tooltip.tokens.ts +26 -0
- package/src/ui/tooltip/tooltip.types.ts +70 -0
- package/src/ui/tooltip/use-tooltip-position.ts +208 -0
- package/src/ui/tooltip/use-tooltip-state.ts +41 -0
- package/src/ui/typography/__tests__/typography.test.tsx +170 -0
- package/{dist/ui/typography/index.d.ts → src/ui/typography/index.ts} +21 -3
- package/src/ui/typography/type-scale-tokens.ts +205 -0
- package/src/ui/typography/typography-key-tokens.ts +43 -0
- package/src/ui/typography/typography-tokens.ts +360 -0
- package/src/ui/typography/typography.css +22 -0
- package/src/ui/typography/typography.tsx +559 -0
- package/test-render.tsx +4 -0
- package/test-shadow.html +26 -0
- package/test_output.txt +164 -0
- package/test_output_v2.txt +5 -0
- package/tsconfig.build.json +10 -0
- package/tsconfig.json +18 -0
- package/tsup.config.ts +20 -0
- package/vitest.config.ts +11 -0
- package/dist/hooks/useClickOutside.d.ts +0 -8
- package/dist/hooks/useMediaQuery.d.ts +0 -11
- package/dist/hooks/useRipple.d.ts +0 -26
- package/dist/lib/material-symbols-preconnect.d.ts +0 -42
- package/dist/lib/theme-utils.d.ts +0 -63
- package/dist/lib/utils.d.ts +0 -2
- package/dist/types/index.d.ts +0 -1
- package/dist/types/md3.d.ts +0 -14
- package/dist/ui/app-bar/app-bar-column.d.ts +0 -28
- package/dist/ui/app-bar/app-bar-item-button.d.ts +0 -16
- package/dist/ui/app-bar/app-bar-overflow-indicator.d.ts +0 -18
- package/dist/ui/app-bar/app-bar-row.d.ts +0 -36
- package/dist/ui/app-bar/app-bar.tokens.d.ts +0 -184
- package/dist/ui/app-bar/app-bar.types.d.ts +0 -392
- package/dist/ui/app-bar/bottom-app-bar.d.ts +0 -31
- package/dist/ui/app-bar/docked-toolbar.d.ts +0 -25
- package/dist/ui/app-bar/hooks/use-app-bar-scroll.d.ts +0 -42
- package/dist/ui/app-bar/hooks/use-flexible-app-bar.d.ts +0 -37
- package/dist/ui/app-bar/large-flexible-app-bar.d.ts +0 -26
- package/dist/ui/app-bar/medium-flexible-app-bar.d.ts +0 -28
- package/dist/ui/app-bar/search-app-bar.d.ts +0 -43
- package/dist/ui/app-bar/search-view.d.ts +0 -54
- package/dist/ui/app-bar/small-app-bar.d.ts +0 -37
- package/dist/ui/badge.d.ts +0 -125
- package/dist/ui/button-group.d.ts +0 -59
- package/dist/ui/button.d.ts +0 -148
- package/dist/ui/card.d.ts +0 -62
- package/dist/ui/checkbox.d.ts +0 -82
- package/dist/ui/chip.d.ts +0 -110
- package/dist/ui/code-block.d.ts +0 -14
- package/dist/ui/dialog.d.ts +0 -111
- package/dist/ui/divider.d.ts +0 -164
- package/dist/ui/drawer.d.ts +0 -39
- package/dist/ui/dropdown.d.ts +0 -29
- package/dist/ui/fab-menu.d.ts +0 -204
- package/dist/ui/fab.d.ts +0 -162
- package/dist/ui/icon-button.d.ts +0 -131
- package/dist/ui/icon.d.ts +0 -88
- package/dist/ui/loading-indicator.d.ts +0 -42
- package/dist/ui/navigation-rail.d.ts +0 -29
- package/dist/ui/progress-indicator/circular.d.ts +0 -3
- package/dist/ui/progress-indicator/hooks.d.ts +0 -3
- package/dist/ui/progress-indicator/linear-flat.d.ts +0 -10
- package/dist/ui/progress-indicator/linear-wavy.d.ts +0 -18
- package/dist/ui/progress-indicator/linear.d.ts +0 -3
- package/dist/ui/progress-indicator/types.d.ts +0 -151
- package/dist/ui/progress-indicator/utils.d.ts +0 -3
- package/dist/ui/radio-button.d.ts +0 -106
- package/dist/ui/ripple.d.ts +0 -126
- package/dist/ui/scroll-area.d.ts +0 -27
- package/dist/ui/search/animated-placeholder.d.ts +0 -54
- package/dist/ui/search/hooks/use-search-keyboard.d.ts +0 -32
- package/dist/ui/search/hooks/use-search-view-focus.d.ts +0 -6
- package/dist/ui/search/index.d.ts +0 -27
- package/dist/ui/search/search-bar.d.ts +0 -32
- package/dist/ui/search/search-context.d.ts +0 -24
- package/dist/ui/search/search-view-docked.d.ts +0 -25
- package/dist/ui/search/search-view-fullscreen.d.ts +0 -36
- package/dist/ui/search/search.d.ts +0 -50
- package/dist/ui/search/search.tokens.d.ts +0 -112
- package/dist/ui/search/search.types.d.ts +0 -131
- package/dist/ui/search/trailing-action.d.ts +0 -9
- package/dist/ui/shared/constants.d.ts +0 -86
- package/dist/ui/slider/hooks/useSliderMath.d.ts +0 -101
- package/dist/ui/slider/range-slider.d.ts +0 -47
- package/dist/ui/slider/slider-thumb.d.ts +0 -33
- package/dist/ui/slider/slider-track.d.ts +0 -25
- package/dist/ui/slider/slider.d.ts +0 -60
- package/dist/ui/slider/slider.tokens.d.ts +0 -151
- package/dist/ui/slider/slider.types.d.ts +0 -259
- package/dist/ui/snackbar/index.d.ts +0 -6
- package/dist/ui/snackbar/snackbar.d.ts +0 -197
- package/dist/ui/switch/switch.d.ts +0 -30
- package/dist/ui/switch/switch.stories.d.ts +0 -48
- package/dist/ui/switch/switch.tokens.d.ts +0 -67
- package/dist/ui/switch/switch.types.d.ts +0 -59
- package/dist/ui/tabs/tab.d.ts +0 -43
- package/dist/ui/tabs/tabs-content.d.ts +0 -36
- package/dist/ui/tabs/tabs-list.d.ts +0 -40
- package/dist/ui/tabs/tabs.d.ts +0 -60
- package/dist/ui/tabs/tabs.tokens.d.ts +0 -94
- package/dist/ui/tabs/tabs.types.d.ts +0 -172
- package/dist/ui/text-field/subcomponents/active-indicator.d.ts +0 -24
- package/dist/ui/text-field/subcomponents/floating-label.d.ts +0 -43
- package/dist/ui/text-field/subcomponents/leading-icon.d.ts +0 -23
- package/dist/ui/text-field/subcomponents/outline-container.d.ts +0 -42
- package/dist/ui/text-field/subcomponents/prefix-suffix.d.ts +0 -24
- package/dist/ui/text-field/subcomponents/supporting-text.d.ts +0 -37
- package/dist/ui/text-field/subcomponents/trailing-icon.d.ts +0 -41
- package/dist/ui/text-field/text-field.d.ts +0 -49
- package/dist/ui/text-field/text-field.tokens.d.ts +0 -76
- package/dist/ui/text-field/text-field.types.d.ts +0 -126
- package/dist/ui/theme-provider/index.d.ts +0 -48
- package/dist/ui/toc.d.ts +0 -80
- package/dist/ui/tooltip/plain-tooltip.d.ts +0 -2
- package/dist/ui/tooltip/rich-tooltip.d.ts +0 -2
- package/dist/ui/tooltip/tooltip-box.d.ts +0 -2
- package/dist/ui/tooltip/tooltip-caret-shape.d.ts +0 -9
- package/dist/ui/tooltip/tooltip.tokens.d.ts +0 -26
- package/dist/ui/tooltip/tooltip.types.d.ts +0 -56
- package/dist/ui/tooltip/use-tooltip-position.d.ts +0 -8
- package/dist/ui/tooltip/use-tooltip-state.d.ts +0 -2
- package/dist/ui/typography/type-scale-tokens.d.ts +0 -162
- package/dist/ui/typography/typography-key-tokens.d.ts +0 -40
- package/dist/ui/typography/typography-tokens.d.ts +0 -220
- package/dist/ui/typography/typography.d.ts +0 -265
- /package/{dist/hooks/index.d.ts → src/hooks/index.ts} +0 -0
- /package/{dist/ui/tooltip/index.d.ts → src/ui/tooltip/index.ts} +0 -0
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file typography.tsx
|
|
3
|
+
* @description MD3 Expressive Typography System for React.
|
|
4
|
+
*
|
|
5
|
+
* Port of `androidx.compose.material3.Typography` (Kotlin `@Immutable` class).
|
|
6
|
+
*
|
|
7
|
+
* Provides 30 {@link TextStyle} definitions via the React Context API, mirroring
|
|
8
|
+
* the Compose `LocalTypography` / `MaterialTheme.typography` pattern.
|
|
9
|
+
*
|
|
10
|
+
* ### Memory & Performance Optimizations
|
|
11
|
+
* - The `Typography` class delegates all property access to a `TypographyTokens`
|
|
12
|
+
* instance that uses **lazy getters**, so styles are computed only on first use.
|
|
13
|
+
* - `TypographyProvider` memoizes the context value via `useMemo` to prevent
|
|
14
|
+
* unnecessary re-renders downstream.
|
|
15
|
+
*
|
|
16
|
+
* @example Wrap your application
|
|
17
|
+
* ```tsx
|
|
18
|
+
* <TypographyProvider>
|
|
19
|
+
* <App />
|
|
20
|
+
* </TypographyProvider>
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @example Consume in a component
|
|
24
|
+
* ```tsx
|
|
25
|
+
* const typography = useTypography();
|
|
26
|
+
* <p style={typography.bodyLarge}>Hello</p>
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @example Via token key
|
|
30
|
+
* ```tsx
|
|
31
|
+
* const style = typography.fromToken(TypographyKeyTokens.BodyLarge);
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @example Custom font + half-rounded corners
|
|
35
|
+
* ```tsx
|
|
36
|
+
* <TypographyProvider
|
|
37
|
+
* fontFamily="'Roboto', sans-serif"
|
|
38
|
+
* fontVariationAxes={{ ROND: 50 }}
|
|
39
|
+
* >
|
|
40
|
+
* <App />
|
|
41
|
+
* </TypographyProvider>
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
import { createContext, type ReactNode, useContext, useMemo } from "react";
|
|
46
|
+
import { TypographyKeyTokens } from "./typography-key-tokens";
|
|
47
|
+
import {
|
|
48
|
+
type FontVariationAxes,
|
|
49
|
+
type TextStyle,
|
|
50
|
+
TypographyTokens,
|
|
51
|
+
} from "./typography-tokens";
|
|
52
|
+
|
|
53
|
+
// ─── Typography Class ─────────────────────────────────────────────────────────
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* MD3 Expressive Typography — port of Compose's `@Immutable class Typography(...)`.
|
|
57
|
+
*
|
|
58
|
+
* All 30 style properties are **readonly** and lazily resolved from the
|
|
59
|
+
* underlying {@link TypographyTokens} instance. Use {@link Typography.copy}
|
|
60
|
+
* to create a customized variant without mutating the original.
|
|
61
|
+
*
|
|
62
|
+
* @example Default
|
|
63
|
+
* ```ts
|
|
64
|
+
* const typography = new Typography();
|
|
65
|
+
* const style = typography.displayLarge; // lazy — computed on first access
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* @example Custom tokens
|
|
69
|
+
* ```ts
|
|
70
|
+
* const typography = new Typography(
|
|
71
|
+
* new TypographyTokens({ fontFamily: "'Inter', sans-serif", fontVariationAxes: { ROND: 0 } })
|
|
72
|
+
* );
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export class Typography {
|
|
76
|
+
readonly #tokens: TypographyTokens;
|
|
77
|
+
|
|
78
|
+
constructor(tokens: TypographyTokens = defaultTokens) {
|
|
79
|
+
this.#tokens = tokens;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// ─── Baseline Styles ────────────────────────────────────────────────────────
|
|
83
|
+
|
|
84
|
+
/** Display Large text style (`57px`, weight `400`). */
|
|
85
|
+
get displayLarge(): TextStyle {
|
|
86
|
+
return this.#tokens.DisplayLarge;
|
|
87
|
+
}
|
|
88
|
+
/** Display Medium text style (`45px`, weight `400`). */
|
|
89
|
+
get displayMedium(): TextStyle {
|
|
90
|
+
return this.#tokens.DisplayMedium;
|
|
91
|
+
}
|
|
92
|
+
/** Display Small text style (`36px`, weight `400`). */
|
|
93
|
+
get displaySmall(): TextStyle {
|
|
94
|
+
return this.#tokens.DisplaySmall;
|
|
95
|
+
}
|
|
96
|
+
/** Headline Large text style (`32px`, weight `400`). */
|
|
97
|
+
get headlineLarge(): TextStyle {
|
|
98
|
+
return this.#tokens.HeadlineLarge;
|
|
99
|
+
}
|
|
100
|
+
/** Headline Medium text style (`28px`, weight `400`). */
|
|
101
|
+
get headlineMedium(): TextStyle {
|
|
102
|
+
return this.#tokens.HeadlineMedium;
|
|
103
|
+
}
|
|
104
|
+
/** Headline Small text style (`24px`, weight `400`). */
|
|
105
|
+
get headlineSmall(): TextStyle {
|
|
106
|
+
return this.#tokens.HeadlineSmall;
|
|
107
|
+
}
|
|
108
|
+
/** Title Large text style (`22px`, weight `400`). */
|
|
109
|
+
get titleLarge(): TextStyle {
|
|
110
|
+
return this.#tokens.TitleLarge;
|
|
111
|
+
}
|
|
112
|
+
/** Title Medium text style (`16px`, weight `500`). */
|
|
113
|
+
get titleMedium(): TextStyle {
|
|
114
|
+
return this.#tokens.TitleMedium;
|
|
115
|
+
}
|
|
116
|
+
/** Title Small text style (`14px`, weight `500`). */
|
|
117
|
+
get titleSmall(): TextStyle {
|
|
118
|
+
return this.#tokens.TitleSmall;
|
|
119
|
+
}
|
|
120
|
+
/** Body Large text style (`16px`, weight `400`). */
|
|
121
|
+
get bodyLarge(): TextStyle {
|
|
122
|
+
return this.#tokens.BodyLarge;
|
|
123
|
+
}
|
|
124
|
+
/** Body Medium text style (`14px`, weight `400`). */
|
|
125
|
+
get bodyMedium(): TextStyle {
|
|
126
|
+
return this.#tokens.BodyMedium;
|
|
127
|
+
}
|
|
128
|
+
/** Body Small text style (`12px`, weight `400`). */
|
|
129
|
+
get bodySmall(): TextStyle {
|
|
130
|
+
return this.#tokens.BodySmall;
|
|
131
|
+
}
|
|
132
|
+
/** Label Large text style (`14px`, weight `500`). */
|
|
133
|
+
get labelLarge(): TextStyle {
|
|
134
|
+
return this.#tokens.LabelLarge;
|
|
135
|
+
}
|
|
136
|
+
/** Label Medium text style (`12px`, weight `500`). */
|
|
137
|
+
get labelMedium(): TextStyle {
|
|
138
|
+
return this.#tokens.LabelMedium;
|
|
139
|
+
}
|
|
140
|
+
/** Label Small text style (`11px`, weight `500`). */
|
|
141
|
+
get labelSmall(): TextStyle {
|
|
142
|
+
return this.#tokens.LabelSmall;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ─── Emphasized Styles (MD3 Expressive) ─────────────────────────────────────
|
|
146
|
+
|
|
147
|
+
/** Display Large Emphasized text style (`57px`, weight `800`). */
|
|
148
|
+
get displayLargeEmphasized(): TextStyle {
|
|
149
|
+
return this.#tokens.DisplayLargeEmphasized;
|
|
150
|
+
}
|
|
151
|
+
/** Display Medium Emphasized text style (`45px`, weight `800`). */
|
|
152
|
+
get displayMediumEmphasized(): TextStyle {
|
|
153
|
+
return this.#tokens.DisplayMediumEmphasized;
|
|
154
|
+
}
|
|
155
|
+
/** Display Small Emphasized text style (`36px`, weight `800`). */
|
|
156
|
+
get displaySmallEmphasized(): TextStyle {
|
|
157
|
+
return this.#tokens.DisplaySmallEmphasized;
|
|
158
|
+
}
|
|
159
|
+
/** Headline Large Emphasized text style (`32px`, weight `800`). */
|
|
160
|
+
get headlineLargeEmphasized(): TextStyle {
|
|
161
|
+
return this.#tokens.HeadlineLargeEmphasized;
|
|
162
|
+
}
|
|
163
|
+
/** Headline Medium Emphasized text style (`28px`, weight `800`). */
|
|
164
|
+
get headlineMediumEmphasized(): TextStyle {
|
|
165
|
+
return this.#tokens.HeadlineMediumEmphasized;
|
|
166
|
+
}
|
|
167
|
+
/** Headline Small Emphasized text style (`24px`, weight `800`). */
|
|
168
|
+
get headlineSmallEmphasized(): TextStyle {
|
|
169
|
+
return this.#tokens.HeadlineSmallEmphasized;
|
|
170
|
+
}
|
|
171
|
+
/** Title Large Emphasized text style (`22px`, weight `700`). */
|
|
172
|
+
get titleLargeEmphasized(): TextStyle {
|
|
173
|
+
return this.#tokens.TitleLargeEmphasized;
|
|
174
|
+
}
|
|
175
|
+
/** Title Medium Emphasized text style (`16px`, weight `700`). */
|
|
176
|
+
get titleMediumEmphasized(): TextStyle {
|
|
177
|
+
return this.#tokens.TitleMediumEmphasized;
|
|
178
|
+
}
|
|
179
|
+
/** Title Small Emphasized text style (`14px`, weight `700`). */
|
|
180
|
+
get titleSmallEmphasized(): TextStyle {
|
|
181
|
+
return this.#tokens.TitleSmallEmphasized;
|
|
182
|
+
}
|
|
183
|
+
/** Body Large Emphasized text style (`16px`, weight `700`). */
|
|
184
|
+
get bodyLargeEmphasized(): TextStyle {
|
|
185
|
+
return this.#tokens.BodyLargeEmphasized;
|
|
186
|
+
}
|
|
187
|
+
/** Body Medium Emphasized text style (`14px`, weight `700`). */
|
|
188
|
+
get bodyMediumEmphasized(): TextStyle {
|
|
189
|
+
return this.#tokens.BodyMediumEmphasized;
|
|
190
|
+
}
|
|
191
|
+
/** Body Small Emphasized text style (`12px`, weight `700`). */
|
|
192
|
+
get bodySmallEmphasized(): TextStyle {
|
|
193
|
+
return this.#tokens.BodySmallEmphasized;
|
|
194
|
+
}
|
|
195
|
+
/** Label Large Emphasized text style (`14px`, weight `800`). */
|
|
196
|
+
get labelLargeEmphasized(): TextStyle {
|
|
197
|
+
return this.#tokens.LabelLargeEmphasized;
|
|
198
|
+
}
|
|
199
|
+
/** Label Medium Emphasized text style (`12px`, weight `800`). */
|
|
200
|
+
get labelMediumEmphasized(): TextStyle {
|
|
201
|
+
return this.#tokens.LabelMediumEmphasized;
|
|
202
|
+
}
|
|
203
|
+
/** Label Small Emphasized text style (`11px`, weight `800`). */
|
|
204
|
+
get labelSmallEmphasized(): TextStyle {
|
|
205
|
+
return this.#tokens.LabelSmallEmphasized;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// ─── Methods ─────────────────────────────────────────────────────────────────
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Returns the `TextStyle` corresponding to the given {@link TypographyKeyTokens}.
|
|
212
|
+
*
|
|
213
|
+
* Port of `internal fun Typography.fromToken(value: TypographyKeyTokens): TextStyle`.
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* ```ts
|
|
217
|
+
* const style = typography.fromToken(TypographyKeyTokens.BodyLarge);
|
|
218
|
+
* ```
|
|
219
|
+
*/
|
|
220
|
+
fromToken(value: TypographyKeyTokens): TextStyle {
|
|
221
|
+
return this[TOKEN_TO_PROP[value]];
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Creates a new `Typography` instance with the specified property overrides
|
|
226
|
+
* merged on top of the current instance's styles.
|
|
227
|
+
*
|
|
228
|
+
* Port of Compose's `fun Typography.copy(...)`.
|
|
229
|
+
*
|
|
230
|
+
* Unlike a shallow `Object.assign`, this method preserves the lazy-getter
|
|
231
|
+
* architecture — overridden styles are stored separately and looked up first
|
|
232
|
+
* on each property access, while non-overridden styles continue to be
|
|
233
|
+
* resolved from the underlying {@link TypographyTokens}.
|
|
234
|
+
*
|
|
235
|
+
* @param overrides - Map of camelCase property names to partial `TextStyle` overrides.
|
|
236
|
+
* @returns A new `Typography` instance. The original is never mutated.
|
|
237
|
+
*
|
|
238
|
+
* @example
|
|
239
|
+
* ```ts
|
|
240
|
+
* const custom = typography.copy({ bodyLarge: { fontSize: "2rem" } });
|
|
241
|
+
* custom.bodyLarge.fontSize; // "2rem"
|
|
242
|
+
* custom.bodySmall.fontSize; // original token value — untouched
|
|
243
|
+
* ```
|
|
244
|
+
*/
|
|
245
|
+
copy(
|
|
246
|
+
overrides: Partial<Record<TypographyStyleKey, Partial<TextStyle>>>,
|
|
247
|
+
): Typography {
|
|
248
|
+
return new OverriddenTypography(this.#tokens, this, overrides);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// ─── TypographyStyleKey ───────────────────────────────────────────────────────
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Union of all camelCase property names on {@link Typography} that return a
|
|
256
|
+
* {@link TextStyle}. Used as the key type for `copy()` overrides and the
|
|
257
|
+
* `OverriddenTypography` resolver.
|
|
258
|
+
*/
|
|
259
|
+
type TypographyStyleKey = {
|
|
260
|
+
[K in keyof Typography]: Typography[K] extends TextStyle ? K : never;
|
|
261
|
+
}[keyof Typography];
|
|
262
|
+
|
|
263
|
+
// ─── OverriddenTypography ─────────────────────────────────────────────────────
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Internal subclass used by {@link Typography.copy}.
|
|
267
|
+
*
|
|
268
|
+
* Holds a map of explicit style overrides. Each getter checks for an override
|
|
269
|
+
* first; if none exists, it falls through to the parent {@link Typography}.
|
|
270
|
+
*
|
|
271
|
+
* @internal
|
|
272
|
+
*/
|
|
273
|
+
class OverriddenTypography extends Typography {
|
|
274
|
+
readonly #base: Typography;
|
|
275
|
+
readonly #overrides: Partial<Record<TypographyStyleKey, Partial<TextStyle>>>;
|
|
276
|
+
|
|
277
|
+
constructor(
|
|
278
|
+
tokens: TypographyTokens,
|
|
279
|
+
base: Typography,
|
|
280
|
+
overrides: Partial<Record<TypographyStyleKey, Partial<TextStyle>>>,
|
|
281
|
+
) {
|
|
282
|
+
super(tokens);
|
|
283
|
+
this.#base = base;
|
|
284
|
+
this.#overrides = overrides;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
#resolve(key: TypographyStyleKey): TextStyle {
|
|
288
|
+
const override = this.#overrides[key];
|
|
289
|
+
const base = (this.#base as unknown as Record<string, TextStyle>)[key];
|
|
290
|
+
return override ? { ...base, ...override } : base;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// ─── Baseline
|
|
294
|
+
override get displayLarge() {
|
|
295
|
+
return this.#resolve("displayLarge");
|
|
296
|
+
}
|
|
297
|
+
override get displayMedium() {
|
|
298
|
+
return this.#resolve("displayMedium");
|
|
299
|
+
}
|
|
300
|
+
override get displaySmall() {
|
|
301
|
+
return this.#resolve("displaySmall");
|
|
302
|
+
}
|
|
303
|
+
override get headlineLarge() {
|
|
304
|
+
return this.#resolve("headlineLarge");
|
|
305
|
+
}
|
|
306
|
+
override get headlineMedium() {
|
|
307
|
+
return this.#resolve("headlineMedium");
|
|
308
|
+
}
|
|
309
|
+
override get headlineSmall() {
|
|
310
|
+
return this.#resolve("headlineSmall");
|
|
311
|
+
}
|
|
312
|
+
override get titleLarge() {
|
|
313
|
+
return this.#resolve("titleLarge");
|
|
314
|
+
}
|
|
315
|
+
override get titleMedium() {
|
|
316
|
+
return this.#resolve("titleMedium");
|
|
317
|
+
}
|
|
318
|
+
override get titleSmall() {
|
|
319
|
+
return this.#resolve("titleSmall");
|
|
320
|
+
}
|
|
321
|
+
override get bodyLarge() {
|
|
322
|
+
return this.#resolve("bodyLarge");
|
|
323
|
+
}
|
|
324
|
+
override get bodyMedium() {
|
|
325
|
+
return this.#resolve("bodyMedium");
|
|
326
|
+
}
|
|
327
|
+
override get bodySmall() {
|
|
328
|
+
return this.#resolve("bodySmall");
|
|
329
|
+
}
|
|
330
|
+
override get labelLarge() {
|
|
331
|
+
return this.#resolve("labelLarge");
|
|
332
|
+
}
|
|
333
|
+
override get labelMedium() {
|
|
334
|
+
return this.#resolve("labelMedium");
|
|
335
|
+
}
|
|
336
|
+
override get labelSmall() {
|
|
337
|
+
return this.#resolve("labelSmall");
|
|
338
|
+
}
|
|
339
|
+
// ─── Emphasized
|
|
340
|
+
override get displayLargeEmphasized() {
|
|
341
|
+
return this.#resolve("displayLargeEmphasized");
|
|
342
|
+
}
|
|
343
|
+
override get displayMediumEmphasized() {
|
|
344
|
+
return this.#resolve("displayMediumEmphasized");
|
|
345
|
+
}
|
|
346
|
+
override get displaySmallEmphasized() {
|
|
347
|
+
return this.#resolve("displaySmallEmphasized");
|
|
348
|
+
}
|
|
349
|
+
override get headlineLargeEmphasized() {
|
|
350
|
+
return this.#resolve("headlineLargeEmphasized");
|
|
351
|
+
}
|
|
352
|
+
override get headlineMediumEmphasized() {
|
|
353
|
+
return this.#resolve("headlineMediumEmphasized");
|
|
354
|
+
}
|
|
355
|
+
override get headlineSmallEmphasized() {
|
|
356
|
+
return this.#resolve("headlineSmallEmphasized");
|
|
357
|
+
}
|
|
358
|
+
override get titleLargeEmphasized() {
|
|
359
|
+
return this.#resolve("titleLargeEmphasized");
|
|
360
|
+
}
|
|
361
|
+
override get titleMediumEmphasized() {
|
|
362
|
+
return this.#resolve("titleMediumEmphasized");
|
|
363
|
+
}
|
|
364
|
+
override get titleSmallEmphasized() {
|
|
365
|
+
return this.#resolve("titleSmallEmphasized");
|
|
366
|
+
}
|
|
367
|
+
override get bodyLargeEmphasized() {
|
|
368
|
+
return this.#resolve("bodyLargeEmphasized");
|
|
369
|
+
}
|
|
370
|
+
override get bodyMediumEmphasized() {
|
|
371
|
+
return this.#resolve("bodyMediumEmphasized");
|
|
372
|
+
}
|
|
373
|
+
override get bodySmallEmphasized() {
|
|
374
|
+
return this.#resolve("bodySmallEmphasized");
|
|
375
|
+
}
|
|
376
|
+
override get labelLargeEmphasized() {
|
|
377
|
+
return this.#resolve("labelLargeEmphasized");
|
|
378
|
+
}
|
|
379
|
+
override get labelMediumEmphasized() {
|
|
380
|
+
return this.#resolve("labelMediumEmphasized");
|
|
381
|
+
}
|
|
382
|
+
override get labelSmallEmphasized() {
|
|
383
|
+
return this.#resolve("labelSmallEmphasized");
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// ─── Token → Property lookup (avoids recreating the map on every fromToken call) ──
|
|
388
|
+
|
|
389
|
+
type TypographyProp = {
|
|
390
|
+
[K in keyof Typography]: Typography[K] extends TextStyle ? K : never;
|
|
391
|
+
}[keyof Typography];
|
|
392
|
+
|
|
393
|
+
const TOKEN_TO_PROP: Record<TypographyKeyTokens, TypographyProp> = {
|
|
394
|
+
[TypographyKeyTokens.DisplayLarge]: "displayLarge",
|
|
395
|
+
[TypographyKeyTokens.DisplayMedium]: "displayMedium",
|
|
396
|
+
[TypographyKeyTokens.DisplaySmall]: "displaySmall",
|
|
397
|
+
[TypographyKeyTokens.HeadlineLarge]: "headlineLarge",
|
|
398
|
+
[TypographyKeyTokens.HeadlineMedium]: "headlineMedium",
|
|
399
|
+
[TypographyKeyTokens.HeadlineSmall]: "headlineSmall",
|
|
400
|
+
[TypographyKeyTokens.TitleLarge]: "titleLarge",
|
|
401
|
+
[TypographyKeyTokens.TitleMedium]: "titleMedium",
|
|
402
|
+
[TypographyKeyTokens.TitleSmall]: "titleSmall",
|
|
403
|
+
[TypographyKeyTokens.BodyLarge]: "bodyLarge",
|
|
404
|
+
[TypographyKeyTokens.BodyMedium]: "bodyMedium",
|
|
405
|
+
[TypographyKeyTokens.BodySmall]: "bodySmall",
|
|
406
|
+
[TypographyKeyTokens.LabelLarge]: "labelLarge",
|
|
407
|
+
[TypographyKeyTokens.LabelMedium]: "labelMedium",
|
|
408
|
+
[TypographyKeyTokens.LabelSmall]: "labelSmall",
|
|
409
|
+
[TypographyKeyTokens.DisplayLargeEmphasized]: "displayLargeEmphasized",
|
|
410
|
+
[TypographyKeyTokens.DisplayMediumEmphasized]: "displayMediumEmphasized",
|
|
411
|
+
[TypographyKeyTokens.DisplaySmallEmphasized]: "displaySmallEmphasized",
|
|
412
|
+
[TypographyKeyTokens.HeadlineLargeEmphasized]: "headlineLargeEmphasized",
|
|
413
|
+
[TypographyKeyTokens.HeadlineMediumEmphasized]: "headlineMediumEmphasized",
|
|
414
|
+
[TypographyKeyTokens.HeadlineSmallEmphasized]: "headlineSmallEmphasized",
|
|
415
|
+
[TypographyKeyTokens.TitleLargeEmphasized]: "titleLargeEmphasized",
|
|
416
|
+
[TypographyKeyTokens.TitleMediumEmphasized]: "titleMediumEmphasized",
|
|
417
|
+
[TypographyKeyTokens.TitleSmallEmphasized]: "titleSmallEmphasized",
|
|
418
|
+
[TypographyKeyTokens.BodyLargeEmphasized]: "bodyLargeEmphasized",
|
|
419
|
+
[TypographyKeyTokens.BodyMediumEmphasized]: "bodyMediumEmphasized",
|
|
420
|
+
[TypographyKeyTokens.BodySmallEmphasized]: "bodySmallEmphasized",
|
|
421
|
+
[TypographyKeyTokens.LabelLargeEmphasized]: "labelLargeEmphasized",
|
|
422
|
+
[TypographyKeyTokens.LabelMediumEmphasized]: "labelMediumEmphasized",
|
|
423
|
+
[TypographyKeyTokens.LabelSmallEmphasized]: "labelSmallEmphasized",
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
// ─── React Context API ────────────────────────────────────────────────────────
|
|
427
|
+
|
|
428
|
+
/** Singleton default token instance (shared; never mutated). */
|
|
429
|
+
const defaultTokens = new TypographyTokens();
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Default {@link Typography} instance used as the context fallback when no
|
|
433
|
+
* `TypographyProvider` is present in the tree.
|
|
434
|
+
*
|
|
435
|
+
* Mirrors `private val LocalTypography = staticCompositionLocalOf { Typography() }`.
|
|
436
|
+
*/
|
|
437
|
+
const defaultTypography = new Typography();
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* React context that holds the current {@link Typography} instance.
|
|
441
|
+
*
|
|
442
|
+
* Port of `internal val LocalTypography = staticCompositionLocalOf { Typography() }`.
|
|
443
|
+
*
|
|
444
|
+
* @internal — Prefer {@link useTypography} and {@link TypographyProvider}.
|
|
445
|
+
*/
|
|
446
|
+
export const TypographyContext = createContext<Typography>(defaultTypography);
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* React hook to access the current {@link Typography} from the nearest
|
|
450
|
+
* {@link TypographyProvider} in the tree. Falls back to the default
|
|
451
|
+
* googleapis Typography when no provider is present.
|
|
452
|
+
*
|
|
453
|
+
* @returns The current `Typography` instance.
|
|
454
|
+
*
|
|
455
|
+
* @example
|
|
456
|
+
* ```tsx
|
|
457
|
+
* const typography = useTypography();
|
|
458
|
+
* <p style={typography.bodyLarge}>Hello</p>
|
|
459
|
+
* ```
|
|
460
|
+
*/
|
|
461
|
+
export function useTypography(): Typography {
|
|
462
|
+
return useContext(TypographyContext);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// ─── TypographyProvider ───────────────────────────────────────────────────────
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Props for {@link TypographyProvider}.
|
|
469
|
+
*/
|
|
470
|
+
export interface TypographyProviderProps {
|
|
471
|
+
/** The child tree that will have access to the provided typography. */
|
|
472
|
+
children: ReactNode;
|
|
473
|
+
/**
|
|
474
|
+
* A fully custom {@link Typography} instance.
|
|
475
|
+
* When provided, `fontFamily` and `fontVariationAxes` are ignored.
|
|
476
|
+
*/
|
|
477
|
+
typography?: Typography;
|
|
478
|
+
/**
|
|
479
|
+
* Shorthand to override the CSS `font-family` for all typography styles.
|
|
480
|
+
* Ignored when `typography` is provided.
|
|
481
|
+
*
|
|
482
|
+
* @example "'Roboto', sans-serif"
|
|
483
|
+
*/
|
|
484
|
+
fontFamily?: string;
|
|
485
|
+
/**
|
|
486
|
+
* Variable font axes to apply globally via `font-variation-settings`.
|
|
487
|
+
* Merged on top of the defaults (`ROND: 100`). Only the axes you specify
|
|
488
|
+
* will be overridden; unspecified axes retain font defaults.
|
|
489
|
+
* Ignored when `typography` is provided.
|
|
490
|
+
*
|
|
491
|
+
* @example { ROND: 50 } // half-rounded
|
|
492
|
+
* @example { ROND: 0 } // sharp corners
|
|
493
|
+
*/
|
|
494
|
+
fontVariationAxes?: FontVariationAxes;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Typography Provider component.
|
|
499
|
+
*
|
|
500
|
+
* Port of `CompositionLocalProvider(LocalTypography provides typography)`.
|
|
501
|
+
* Wrap your application (or a subtree) to provide MD3 Expressive typography
|
|
502
|
+
* to all descendant components that call {@link useTypography}.
|
|
503
|
+
*
|
|
504
|
+
* The context value is **memoized** — it is only re-computed when `typography`,
|
|
505
|
+
* `fontFamily`, or `fontVariationAxes` change, preventing unnecessary re-renders.
|
|
506
|
+
*
|
|
507
|
+
* @example Default (Google Sans Flex, ROND = 100)
|
|
508
|
+
* ```tsx
|
|
509
|
+
* <TypographyProvider>
|
|
510
|
+
* <App />
|
|
511
|
+
* </TypographyProvider>
|
|
512
|
+
* ```
|
|
513
|
+
*
|
|
514
|
+
* @example Custom font
|
|
515
|
+
* ```tsx
|
|
516
|
+
* <TypographyProvider fontFamily="'Inter', sans-serif">
|
|
517
|
+
* <App />
|
|
518
|
+
* </TypographyProvider>
|
|
519
|
+
* ```
|
|
520
|
+
*
|
|
521
|
+
* @example Partially rounded corners (ROND = 50)
|
|
522
|
+
* ```tsx
|
|
523
|
+
* <TypographyProvider fontVariationAxes={{ ROND: 50 }}>
|
|
524
|
+
* <App />
|
|
525
|
+
* </TypographyProvider>
|
|
526
|
+
* ```
|
|
527
|
+
*
|
|
528
|
+
* @example Fully sharp (ROND = 0) with a custom font
|
|
529
|
+
* ```tsx
|
|
530
|
+
* <TypographyProvider
|
|
531
|
+
* fontFamily="'Outfit', sans-serif"
|
|
532
|
+
* fontVariationAxes={{ ROND: 0 }}
|
|
533
|
+
* >
|
|
534
|
+
* <App />
|
|
535
|
+
* </TypographyProvider>
|
|
536
|
+
* ```
|
|
537
|
+
*/
|
|
538
|
+
export function TypographyProvider({
|
|
539
|
+
children,
|
|
540
|
+
typography,
|
|
541
|
+
fontFamily,
|
|
542
|
+
fontVariationAxes,
|
|
543
|
+
}: TypographyProviderProps) {
|
|
544
|
+
const value = useMemo<Typography>(() => {
|
|
545
|
+
if (typography) return typography;
|
|
546
|
+
if (fontFamily || fontVariationAxes) {
|
|
547
|
+
return new Typography(
|
|
548
|
+
new TypographyTokens({ fontFamily, fontVariationAxes }),
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
return defaultTypography;
|
|
552
|
+
}, [typography, fontFamily, fontVariationAxes]);
|
|
553
|
+
|
|
554
|
+
return (
|
|
555
|
+
<TypographyContext.Provider value={value}>
|
|
556
|
+
{children}
|
|
557
|
+
</TypographyContext.Provider>
|
|
558
|
+
);
|
|
559
|
+
}
|
package/test-render.tsx
ADDED
package/test-shadow.html
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<style>
|
|
5
|
+
.outer {
|
|
6
|
+
width: 200px;
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
gap: 2px;
|
|
10
|
+
box-shadow: 0px 4px 8px rgba(0,0,0,0.5);
|
|
11
|
+
border-radius: 16px;
|
|
12
|
+
overflow: hidden;
|
|
13
|
+
}
|
|
14
|
+
.inner {
|
|
15
|
+
background: white;
|
|
16
|
+
height: 100px;
|
|
17
|
+
}
|
|
18
|
+
</style>
|
|
19
|
+
</head>
|
|
20
|
+
<body style="background: #ccc; padding: 50px;">
|
|
21
|
+
<div class="outer">
|
|
22
|
+
<div class="inner" style="border-radius: 16px 16px 8px 8px;"></div>
|
|
23
|
+
<div class="inner" style="border-radius: 4px 4px 12px 12px;"></div>
|
|
24
|
+
</div>
|
|
25
|
+
</body>
|
|
26
|
+
</html>
|