@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,360 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file typography-tokens.ts
|
|
3
|
+
* @description MD3 Expressive Typography Token Definitions.
|
|
4
|
+
*
|
|
5
|
+
* Port of `androidx.compose.material3.tokens.TypographyTokens` (Kotlin class).
|
|
6
|
+
*
|
|
7
|
+
* ### Memory Optimization
|
|
8
|
+
* All 30 `TextStyle` properties are implemented as **lazy getters** — they are
|
|
9
|
+
* computed on first access and cached, rather than being computed eagerly at
|
|
10
|
+
* construction time. This reduces the instantiation cost of `TypographyTokens`.
|
|
11
|
+
*
|
|
12
|
+
* ### Variable Font Axes
|
|
13
|
+
* Supports customizable CSS `font-variation-settings` via {@link FontVariationAxes}.
|
|
14
|
+
* - Default `ROND` value is `100` (maximum roundness of Google Sans Flex).
|
|
15
|
+
* - Other axes remain at font defaults unless explicitly overridden.
|
|
16
|
+
*
|
|
17
|
+
* @example Basic usage (default tokens)
|
|
18
|
+
* ```ts
|
|
19
|
+
* const tokens = new TypographyTokens();
|
|
20
|
+
* const style = tokens.BodyLarge; // { fontSize, fontWeight, ... }
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @example Custom font family
|
|
24
|
+
* ```ts
|
|
25
|
+
* const tokens = new TypographyTokens({ fontFamily: "'Inter', sans-serif" });
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @example Custom ROND axis (partial roundness)
|
|
29
|
+
* ```ts
|
|
30
|
+
* const tokens = new TypographyTokens({ fontVariationAxes: { ROND: 50 } });
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import { TypeScaleTokens } from "./type-scale-tokens";
|
|
35
|
+
|
|
36
|
+
// ─── Font Variation ───────────────────────────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Configurable axes for CSS `font-variation-settings`.
|
|
40
|
+
*
|
|
41
|
+
* Each key maps to a named variable font axis. Any axis not specified falls
|
|
42
|
+
* back to the font's own default value.
|
|
43
|
+
*
|
|
44
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/font-variation-settings
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* const axes: FontVariationAxes = { ROND: 100, wght: 600 };
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export interface FontVariationAxes {
|
|
52
|
+
/**
|
|
53
|
+
* Roundness axis of Google Sans Flex Variable Font.
|
|
54
|
+
* Range: `0` (sharp corners) – `100` (fully rounded).
|
|
55
|
+
* @default 100
|
|
56
|
+
*/
|
|
57
|
+
ROND?: number;
|
|
58
|
+
/**
|
|
59
|
+
* Weight axis. Overrides `font-weight` via variation settings.
|
|
60
|
+
* @default font default
|
|
61
|
+
*/
|
|
62
|
+
wght?: number;
|
|
63
|
+
/**
|
|
64
|
+
* Width axis. Controls glyph condensation/expansion.
|
|
65
|
+
* @default font default
|
|
66
|
+
*/
|
|
67
|
+
wdth?: number;
|
|
68
|
+
/** Any additional named variation axis supported by the font. */
|
|
69
|
+
[axis: string]: number | undefined;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Default font variation axes for MD3 Expressive.
|
|
74
|
+
* Sets `ROND` to `100` for maximum roundness; all other axes use font defaults.
|
|
75
|
+
*/
|
|
76
|
+
export const DEFAULT_FONT_VARIATION_AXES: Readonly<FontVariationAxes> =
|
|
77
|
+
Object.freeze({ ROND: 100 });
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Serializes a {@link FontVariationAxes} map into a CSS `font-variation-settings` string.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```ts
|
|
84
|
+
* serializeFontVariationAxes({ ROND: 100, wght: 700 });
|
|
85
|
+
* // → '"ROND" 100, "wght" 700'
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export function serializeFontVariationAxes(axes: FontVariationAxes): string {
|
|
89
|
+
return Object.entries(axes)
|
|
90
|
+
.filter(([, v]) => v !== undefined)
|
|
91
|
+
.map(([k, v]) => `"${k}" ${v}`)
|
|
92
|
+
.join(", ");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Pre-computed default `font-variation-settings` string.
|
|
97
|
+
* Equivalent to `'"ROND" 100'`.
|
|
98
|
+
*/
|
|
99
|
+
export const MD3_EXPRESSIVE_FONT_VARIATION: string = serializeFontVariationAxes(
|
|
100
|
+
DEFAULT_FONT_VARIATION_AXES,
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
// ─── TextStyle ────────────────────────────────────────────────────────────────
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Web equivalent of Compose's `TextStyle`.
|
|
107
|
+
*
|
|
108
|
+
* All properties are readonly and map directly to CSS font properties.
|
|
109
|
+
* The `fontVariationSettings` field carries the serialized variable-font axes.
|
|
110
|
+
*/
|
|
111
|
+
export interface TextStyle {
|
|
112
|
+
/** CSS `font-family` value. */
|
|
113
|
+
readonly fontFamily: string;
|
|
114
|
+
/** CSS `font-weight` numeric value (e.g. `400`, `700`). */
|
|
115
|
+
readonly fontWeight: number;
|
|
116
|
+
/** CSS `font-size` in `rem` units. */
|
|
117
|
+
readonly fontSize: string;
|
|
118
|
+
/** CSS `line-height` in `rem` units. */
|
|
119
|
+
readonly lineHeight: string;
|
|
120
|
+
/** CSS `letter-spacing` in `px` units. */
|
|
121
|
+
readonly letterSpacing: string;
|
|
122
|
+
/**
|
|
123
|
+
* CSS `font-variation-settings` string.
|
|
124
|
+
* @example '"ROND" 100'
|
|
125
|
+
* @example '"ROND" 50, "wght" 600'
|
|
126
|
+
*/
|
|
127
|
+
readonly fontVariationSettings: string;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ─── TypographyTokens Options ─────────────────────────────────────────────────
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Constructor options for {@link TypographyTokens}.
|
|
134
|
+
*/
|
|
135
|
+
export interface TypographyTokensOptions {
|
|
136
|
+
/**
|
|
137
|
+
* Custom CSS `font-family` string. When provided, overrides the default
|
|
138
|
+
* Google Sans Flex font for all token styles.
|
|
139
|
+
*
|
|
140
|
+
* @example "'Roboto', sans-serif"
|
|
141
|
+
*/
|
|
142
|
+
fontFamily?: string;
|
|
143
|
+
/**
|
|
144
|
+
* Variable font axes to apply via `font-variation-settings`.
|
|
145
|
+
* Merged on top of {@link DEFAULT_FONT_VARIATION_AXES}.
|
|
146
|
+
* Provide only the axes you want to override.
|
|
147
|
+
*
|
|
148
|
+
* @example { ROND: 0 } // sharp corners
|
|
149
|
+
*/
|
|
150
|
+
fontVariationAxes?: FontVariationAxes;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ─── Internal factory ─────────────────────────────────────────────────────────
|
|
154
|
+
|
|
155
|
+
type TokenRecord = Record<string, string | number>;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Creates a frozen {@link TextStyle} from the {@link TypeScaleTokens} lookup
|
|
159
|
+
* using the given token prefix (e.g. `"BodyLarge"`).
|
|
160
|
+
*
|
|
161
|
+
* @internal
|
|
162
|
+
*/
|
|
163
|
+
function buildStyle(
|
|
164
|
+
prefix: string,
|
|
165
|
+
fontFamily: string | undefined,
|
|
166
|
+
fontVariationSettings: string,
|
|
167
|
+
): TextStyle {
|
|
168
|
+
const t = TypeScaleTokens as TokenRecord;
|
|
169
|
+
return Object.freeze({
|
|
170
|
+
fontFamily: fontFamily ?? (t[`${prefix}Font`] as string),
|
|
171
|
+
fontWeight: t[`${prefix}Weight`] as number,
|
|
172
|
+
fontSize: t[`${prefix}Size`] as string,
|
|
173
|
+
lineHeight: t[`${prefix}LineHeight`] as string,
|
|
174
|
+
letterSpacing: t[`${prefix}Tracking`] as string,
|
|
175
|
+
fontVariationSettings,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// ─── TypographyTokens ─────────────────────────────────────────────────────────
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* MD3 Expressive Typography Token class.
|
|
183
|
+
*
|
|
184
|
+
* Port of `internal class TypographyTokens(val fontFamily: FontFamily? = null)`
|
|
185
|
+
* from `androidx.compose.material3.tokens.TypographyTokens`.
|
|
186
|
+
*
|
|
187
|
+
* Provides 30 pre-defined {@link TextStyle} properties (15 baseline + 15 emphasized),
|
|
188
|
+
* each implemented as a **lazy getter** — computed once on first access, then cached.
|
|
189
|
+
*
|
|
190
|
+
* ### Customization
|
|
191
|
+
* Pass {@link TypographyTokensOptions} to the constructor to override:
|
|
192
|
+
* - `fontFamily` — swap the typeface
|
|
193
|
+
* - `fontVariationAxes` — control variable font axes (e.g., `ROND`)
|
|
194
|
+
*
|
|
195
|
+
* @example Default
|
|
196
|
+
* ```ts
|
|
197
|
+
* const tokens = new TypographyTokens();
|
|
198
|
+
* ```
|
|
199
|
+
*
|
|
200
|
+
* @example Custom font + half-rounded
|
|
201
|
+
* ```ts
|
|
202
|
+
* const tokens = new TypographyTokens({
|
|
203
|
+
* fontFamily: "'Inter', sans-serif",
|
|
204
|
+
* fontVariationAxes: { ROND: 50 },
|
|
205
|
+
* });
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
export class TypographyTokens {
|
|
209
|
+
readonly #fontFamily: string | undefined;
|
|
210
|
+
readonly #fontVariationSettings: string;
|
|
211
|
+
|
|
212
|
+
constructor(options: TypographyTokensOptions | string = {}) {
|
|
213
|
+
// Support legacy string signature: new TypographyTokens("'Inter', sans-serif")
|
|
214
|
+
if (typeof options === "string") {
|
|
215
|
+
this.#fontFamily = options;
|
|
216
|
+
this.#fontVariationSettings = MD3_EXPRESSIVE_FONT_VARIATION;
|
|
217
|
+
} else {
|
|
218
|
+
this.#fontFamily = options.fontFamily;
|
|
219
|
+
const axes: FontVariationAxes = options.fontVariationAxes
|
|
220
|
+
? { ...DEFAULT_FONT_VARIATION_AXES, ...options.fontVariationAxes }
|
|
221
|
+
: DEFAULT_FONT_VARIATION_AXES;
|
|
222
|
+
this.#fontVariationSettings = serializeFontVariationAxes(axes);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Helper to lazily build + cache a style on first access
|
|
227
|
+
#cache: Map<string, TextStyle> = new Map();
|
|
228
|
+
#get(prefix: string): TextStyle {
|
|
229
|
+
let style = this.#cache.get(prefix);
|
|
230
|
+
if (!style) {
|
|
231
|
+
style = buildStyle(prefix, this.#fontFamily, this.#fontVariationSettings);
|
|
232
|
+
this.#cache.set(prefix, style);
|
|
233
|
+
}
|
|
234
|
+
return style;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// ─── Baseline Styles (15) ──────────────────────────────────────────────────
|
|
238
|
+
/** Display Large – `57px`, weight 400 */
|
|
239
|
+
get DisplayLarge(): TextStyle {
|
|
240
|
+
return this.#get("DisplayLarge");
|
|
241
|
+
}
|
|
242
|
+
/** Display Medium – `45px`, weight 400 */
|
|
243
|
+
get DisplayMedium(): TextStyle {
|
|
244
|
+
return this.#get("DisplayMedium");
|
|
245
|
+
}
|
|
246
|
+
/** Display Small – `36px`, weight 400 */
|
|
247
|
+
get DisplaySmall(): TextStyle {
|
|
248
|
+
return this.#get("DisplaySmall");
|
|
249
|
+
}
|
|
250
|
+
/** Headline Large – `32px`, weight 400 */
|
|
251
|
+
get HeadlineLarge(): TextStyle {
|
|
252
|
+
return this.#get("HeadlineLarge");
|
|
253
|
+
}
|
|
254
|
+
/** Headline Medium – `28px`, weight 400 */
|
|
255
|
+
get HeadlineMedium(): TextStyle {
|
|
256
|
+
return this.#get("HeadlineMedium");
|
|
257
|
+
}
|
|
258
|
+
/** Headline Small – `24px`, weight 400 */
|
|
259
|
+
get HeadlineSmall(): TextStyle {
|
|
260
|
+
return this.#get("HeadlineSmall");
|
|
261
|
+
}
|
|
262
|
+
/** Title Large – `22px`, weight 400 */
|
|
263
|
+
get TitleLarge(): TextStyle {
|
|
264
|
+
return this.#get("TitleLarge");
|
|
265
|
+
}
|
|
266
|
+
/** Title Medium – `16px`, weight 500 */
|
|
267
|
+
get TitleMedium(): TextStyle {
|
|
268
|
+
return this.#get("TitleMedium");
|
|
269
|
+
}
|
|
270
|
+
/** Title Small – `14px`, weight 500 */
|
|
271
|
+
get TitleSmall(): TextStyle {
|
|
272
|
+
return this.#get("TitleSmall");
|
|
273
|
+
}
|
|
274
|
+
/** Body Large – `16px`, weight 400 */
|
|
275
|
+
get BodyLarge(): TextStyle {
|
|
276
|
+
return this.#get("BodyLarge");
|
|
277
|
+
}
|
|
278
|
+
/** Body Medium – `14px`, weight 400 */
|
|
279
|
+
get BodyMedium(): TextStyle {
|
|
280
|
+
return this.#get("BodyMedium");
|
|
281
|
+
}
|
|
282
|
+
/** Body Small – `12px`, weight 400 */
|
|
283
|
+
get BodySmall(): TextStyle {
|
|
284
|
+
return this.#get("BodySmall");
|
|
285
|
+
}
|
|
286
|
+
/** Label Large – `14px`, weight 500 */
|
|
287
|
+
get LabelLarge(): TextStyle {
|
|
288
|
+
return this.#get("LabelLarge");
|
|
289
|
+
}
|
|
290
|
+
/** Label Medium – `12px`, weight 500 */
|
|
291
|
+
get LabelMedium(): TextStyle {
|
|
292
|
+
return this.#get("LabelMedium");
|
|
293
|
+
}
|
|
294
|
+
/** Label Small – `11px`, weight 500 */
|
|
295
|
+
get LabelSmall(): TextStyle {
|
|
296
|
+
return this.#get("LabelSmall");
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// ─── Emphasized Styles (15) – MD3 Expressive ──────────────────────────────
|
|
300
|
+
/** Display Large Emphasized – `57px`, weight 800 */
|
|
301
|
+
get DisplayLargeEmphasized(): TextStyle {
|
|
302
|
+
return this.#get("DisplayLargeEmphasized");
|
|
303
|
+
}
|
|
304
|
+
/** Display Medium Emphasized – `45px`, weight 800 */
|
|
305
|
+
get DisplayMediumEmphasized(): TextStyle {
|
|
306
|
+
return this.#get("DisplayMediumEmphasized");
|
|
307
|
+
}
|
|
308
|
+
/** Display Small Emphasized – `36px`, weight 800 */
|
|
309
|
+
get DisplaySmallEmphasized(): TextStyle {
|
|
310
|
+
return this.#get("DisplaySmallEmphasized");
|
|
311
|
+
}
|
|
312
|
+
/** Headline Large Emphasized – `32px`, weight 800 */
|
|
313
|
+
get HeadlineLargeEmphasized(): TextStyle {
|
|
314
|
+
return this.#get("HeadlineLargeEmphasized");
|
|
315
|
+
}
|
|
316
|
+
/** Headline Medium Emphasized – `28px`, weight 800 */
|
|
317
|
+
get HeadlineMediumEmphasized(): TextStyle {
|
|
318
|
+
return this.#get("HeadlineMediumEmphasized");
|
|
319
|
+
}
|
|
320
|
+
/** Headline Small Emphasized – `24px`, weight 800 */
|
|
321
|
+
get HeadlineSmallEmphasized(): TextStyle {
|
|
322
|
+
return this.#get("HeadlineSmallEmphasized");
|
|
323
|
+
}
|
|
324
|
+
/** Title Large Emphasized – `22px`, weight 700 */
|
|
325
|
+
get TitleLargeEmphasized(): TextStyle {
|
|
326
|
+
return this.#get("TitleLargeEmphasized");
|
|
327
|
+
}
|
|
328
|
+
/** Title Medium Emphasized – `16px`, weight 700 */
|
|
329
|
+
get TitleMediumEmphasized(): TextStyle {
|
|
330
|
+
return this.#get("TitleMediumEmphasized");
|
|
331
|
+
}
|
|
332
|
+
/** Title Small Emphasized – `14px`, weight 700 */
|
|
333
|
+
get TitleSmallEmphasized(): TextStyle {
|
|
334
|
+
return this.#get("TitleSmallEmphasized");
|
|
335
|
+
}
|
|
336
|
+
/** Body Large Emphasized – `16px`, weight 700 */
|
|
337
|
+
get BodyLargeEmphasized(): TextStyle {
|
|
338
|
+
return this.#get("BodyLargeEmphasized");
|
|
339
|
+
}
|
|
340
|
+
/** Body Medium Emphasized – `14px`, weight 700 */
|
|
341
|
+
get BodyMediumEmphasized(): TextStyle {
|
|
342
|
+
return this.#get("BodyMediumEmphasized");
|
|
343
|
+
}
|
|
344
|
+
/** Body Small Emphasized – `12px`, weight 700 */
|
|
345
|
+
get BodySmallEmphasized(): TextStyle {
|
|
346
|
+
return this.#get("BodySmallEmphasized");
|
|
347
|
+
}
|
|
348
|
+
/** Label Large Emphasized – `14px`, weight 800 */
|
|
349
|
+
get LabelLargeEmphasized(): TextStyle {
|
|
350
|
+
return this.#get("LabelLargeEmphasized");
|
|
351
|
+
}
|
|
352
|
+
/** Label Medium Emphasized – `12px`, weight 800 */
|
|
353
|
+
get LabelMediumEmphasized(): TextStyle {
|
|
354
|
+
return this.#get("LabelMediumEmphasized");
|
|
355
|
+
}
|
|
356
|
+
/** Label Small Emphasized – `11px`, weight 800 */
|
|
357
|
+
get LabelSmallEmphasized(): TextStyle {
|
|
358
|
+
return this.#get("LabelSmallEmphasized");
|
|
359
|
+
}
|
|
360
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/* MD3 Expressive Typography - Google Sans Flex Variable Font */
|
|
2
|
+
|
|
3
|
+
@font-face {
|
|
4
|
+
font-family: "Google Sans Flex";
|
|
5
|
+
src: url("../../assets/fonts/GoogleSansFlex-VariableFont.woff2")
|
|
6
|
+
format("woff2");
|
|
7
|
+
font-weight: 100 1000;
|
|
8
|
+
font-style: normal;
|
|
9
|
+
font-display: swap;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Applies Google Sans Flex with ROND axis at 100 (maximum roundness)
|
|
14
|
+
* as required by MD3 Expressive design spec.
|
|
15
|
+
*
|
|
16
|
+
* Usage: Add this class to any element or the root element to apply
|
|
17
|
+
* the MD3 Expressive typography defaults.
|
|
18
|
+
*/
|
|
19
|
+
.font-md3-expressive {
|
|
20
|
+
font-family: "Google Sans Flex", system-ui, sans-serif;
|
|
21
|
+
font-variation-settings: "ROND" 100;
|
|
22
|
+
}
|