@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,143 @@
|
|
|
1
|
+
import { domMax, LazyMotion } from "motion/react";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cn } from "../../lib/utils";
|
|
4
|
+
import { useMergedRef } from "./hooks";
|
|
5
|
+
import { FlatLinearTrack } from "./linear-flat";
|
|
6
|
+
import { WavyLinearTrack } from "./linear-wavy";
|
|
7
|
+
import type { LinearProgressProps } from "./types";
|
|
8
|
+
|
|
9
|
+
export const LinearProgress = React.forwardRef<
|
|
10
|
+
HTMLDivElement,
|
|
11
|
+
LinearProgressProps
|
|
12
|
+
>(
|
|
13
|
+
(
|
|
14
|
+
{
|
|
15
|
+
value,
|
|
16
|
+
shape = "flat",
|
|
17
|
+
trackShape,
|
|
18
|
+
trackHeight = 4,
|
|
19
|
+
amplitude,
|
|
20
|
+
wavelength = 40,
|
|
21
|
+
indeterminateWavelength = 20,
|
|
22
|
+
waveSpeed = 1,
|
|
23
|
+
crawlerSpeed = 1,
|
|
24
|
+
determinateAnimation = "md3",
|
|
25
|
+
indeterminateAnimation = "continuous",
|
|
26
|
+
gapSize = 4,
|
|
27
|
+
showStopIndicator = "auto",
|
|
28
|
+
color,
|
|
29
|
+
trackColor,
|
|
30
|
+
className,
|
|
31
|
+
"aria-label": ariaLabel,
|
|
32
|
+
...restProps
|
|
33
|
+
},
|
|
34
|
+
ref,
|
|
35
|
+
) => {
|
|
36
|
+
const isDeterminate = value !== undefined;
|
|
37
|
+
const clampedValue = isDeterminate ? Math.min(100, Math.max(0, value)) : 0;
|
|
38
|
+
|
|
39
|
+
const containerRef = React.useRef<HTMLDivElement>(null);
|
|
40
|
+
const mergedRef = useMergedRef(ref, containerRef);
|
|
41
|
+
const [isRtl, setIsRtl] = React.useState(false);
|
|
42
|
+
|
|
43
|
+
React.useEffect(() => {
|
|
44
|
+
if (containerRef.current) {
|
|
45
|
+
const dir = getComputedStyle(containerRef.current).direction;
|
|
46
|
+
setIsRtl(dir === "rtl");
|
|
47
|
+
}
|
|
48
|
+
}, []);
|
|
49
|
+
|
|
50
|
+
const isWavy = shape === "wavy";
|
|
51
|
+
const resolvedTrackShape = trackShape ?? shape;
|
|
52
|
+
|
|
53
|
+
const effectiveAmplitude = React.useMemo(() => amplitude ?? 3, [amplitude]);
|
|
54
|
+
const svgHeight = React.useMemo(
|
|
55
|
+
() => (isWavy ? trackHeight + effectiveAmplitude * 2 : trackHeight),
|
|
56
|
+
[isWavy, trackHeight, effectiveAmplitude],
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const shouldShowStop = React.useMemo(
|
|
60
|
+
() =>
|
|
61
|
+
isDeterminate &&
|
|
62
|
+
resolvedTrackShape === "flat" &&
|
|
63
|
+
(showStopIndicator === true ||
|
|
64
|
+
(showStopIndicator === "auto" && isDeterminate)),
|
|
65
|
+
[isDeterminate, resolvedTrackShape, showStopIndicator],
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
const stopSize = React.useMemo(
|
|
69
|
+
() => Math.max(2, trackHeight > 4 ? 4 : trackHeight / 2),
|
|
70
|
+
[trackHeight],
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
const stopOffset = (trackHeight - stopSize) / 2;
|
|
74
|
+
|
|
75
|
+
const activeColor = color || "var(--md-sys-color-indicator-active)";
|
|
76
|
+
const bgTrackColor = trackColor || "var(--md-sys-color-indicator-track)";
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<LazyMotion features={domMax} strict>
|
|
80
|
+
<div
|
|
81
|
+
ref={mergedRef}
|
|
82
|
+
role="progressbar"
|
|
83
|
+
aria-label={ariaLabel}
|
|
84
|
+
aria-valuenow={isDeterminate ? clampedValue : undefined}
|
|
85
|
+
aria-valuemin={0}
|
|
86
|
+
aria-valuemax={100}
|
|
87
|
+
className={cn(
|
|
88
|
+
"relative flex w-full flex-col justify-center",
|
|
89
|
+
className,
|
|
90
|
+
)}
|
|
91
|
+
style={{ height: svgHeight }}
|
|
92
|
+
{...restProps}
|
|
93
|
+
>
|
|
94
|
+
{isWavy ? (
|
|
95
|
+
<WavyLinearTrack
|
|
96
|
+
trackHeight={trackHeight}
|
|
97
|
+
svgHeight={svgHeight}
|
|
98
|
+
amplitude={effectiveAmplitude}
|
|
99
|
+
wavelength={wavelength}
|
|
100
|
+
indeterminateWavelength={indeterminateWavelength}
|
|
101
|
+
activeColor={activeColor}
|
|
102
|
+
trackColor={bgTrackColor}
|
|
103
|
+
value={isDeterminate ? clampedValue : undefined}
|
|
104
|
+
isRtl={isRtl}
|
|
105
|
+
gapSize={gapSize}
|
|
106
|
+
waveSpeed={waveSpeed}
|
|
107
|
+
crawlerSpeed={crawlerSpeed}
|
|
108
|
+
determinateAnimation={determinateAnimation}
|
|
109
|
+
indeterminateAnimation={indeterminateAnimation}
|
|
110
|
+
trackShape={resolvedTrackShape}
|
|
111
|
+
/>
|
|
112
|
+
) : (
|
|
113
|
+
<FlatLinearTrack
|
|
114
|
+
trackHeight={trackHeight}
|
|
115
|
+
activeColor={activeColor}
|
|
116
|
+
trackColor={bgTrackColor}
|
|
117
|
+
value={isDeterminate ? clampedValue : undefined}
|
|
118
|
+
isRtl={isRtl}
|
|
119
|
+
gapSize={gapSize}
|
|
120
|
+
crawlerSpeed={crawlerSpeed}
|
|
121
|
+
/>
|
|
122
|
+
)}
|
|
123
|
+
|
|
124
|
+
{shouldShowStop && (
|
|
125
|
+
<div
|
|
126
|
+
aria-hidden="true"
|
|
127
|
+
className="absolute rounded-full"
|
|
128
|
+
style={{
|
|
129
|
+
width: stopSize,
|
|
130
|
+
height: stopSize,
|
|
131
|
+
backgroundColor: "var(--md-sys-color-indicator-stop)",
|
|
132
|
+
top: svgHeight / 2 - stopSize / 2,
|
|
133
|
+
...(isRtl ? { left: stopOffset } : { right: stopOffset }),
|
|
134
|
+
}}
|
|
135
|
+
/>
|
|
136
|
+
)}
|
|
137
|
+
</div>
|
|
138
|
+
</LazyMotion>
|
|
139
|
+
);
|
|
140
|
+
},
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
LinearProgress.displayName = "LinearProgress";
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import type * as React from "react";
|
|
2
|
+
|
|
3
|
+
export interface ProgressBaseProps
|
|
4
|
+
extends Omit<React.HTMLAttributes<HTMLDivElement>, "children"> {
|
|
5
|
+
/**
|
|
6
|
+
* Giá trị phần trăm tiến trình hiện tại (từ 0 đến 100).
|
|
7
|
+
* Nếu truyền giá trị này, tiến trình sẽ hiển thị ở trạng thái Determinate.
|
|
8
|
+
* Nếu bỏ trống (undefined), tiến trình sẽ tự động ở trạng thái Indeterminate.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* <ProgressIndicator value={45} aria-label="Loading profile..." />
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
value?: number;
|
|
16
|
+
/**
|
|
17
|
+
* Nhan đề mô tả mục đích của thanh tiến trình dành cho screen readers (bắt buộc).
|
|
18
|
+
*/
|
|
19
|
+
"aria-label": string;
|
|
20
|
+
/**
|
|
21
|
+
* Độ dày của track (đường nền) của thanh tiến trình (đơn vị: px).
|
|
22
|
+
* - Với Linear: là chiều cao của thanh.
|
|
23
|
+
* - Với Circular: là độ dày của viền hình tròn.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* trackHeight={8} // Dày hơn bình thường
|
|
27
|
+
*/
|
|
28
|
+
trackHeight?: number;
|
|
29
|
+
/**
|
|
30
|
+
* Màu sắc của phần tiến trình (phần đã hoàn thành).
|
|
31
|
+
* Mặc định mượn màu `currentColor` của thẻ wrap, để dễ dàng tuỳ biến qua utility class.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* color="var(--md-sys-color-primary)" // Sử dụng custom token
|
|
35
|
+
*/
|
|
36
|
+
color?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Màu sắc của thanh nền (phần chưa hoàn thành).
|
|
39
|
+
* Mặc định sử dụng màu được tính toán từ bề mặt hoặc transparency để tạo sự tinh tế.
|
|
40
|
+
*/
|
|
41
|
+
trackColor?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface LinearProgressProps extends ProgressBaseProps {
|
|
45
|
+
/** Phân loại component sang kiểu dáng Linear (đường thẳng ngang). */
|
|
46
|
+
variant: "linear";
|
|
47
|
+
/**
|
|
48
|
+
* Hình dáng của vạch tiến trình (phần đã hoàn thành).
|
|
49
|
+
* - `flat`: Đường nét liền phẳng (mặc định)
|
|
50
|
+
* - `wavy`: Đường lượn sóng động
|
|
51
|
+
*/
|
|
52
|
+
shape?: "flat" | "wavy";
|
|
53
|
+
/**
|
|
54
|
+
* Hình dáng của thanh nền chờ (track).
|
|
55
|
+
* - `flat`: Đường nét liền phẳng (mặc định)
|
|
56
|
+
* - `wavy`: Đường lượn sóng cố định hoặc động
|
|
57
|
+
*/
|
|
58
|
+
trackShape?: "flat" | "wavy";
|
|
59
|
+
/**
|
|
60
|
+
* Biên độ sóng (áp dụng khi `shape` hoặc `trackShape` là "wavy").
|
|
61
|
+
* Chỉ định độ lượn cao thấp của con sóng.
|
|
62
|
+
*/
|
|
63
|
+
amplitude?: number;
|
|
64
|
+
/**
|
|
65
|
+
* Chiều dài một nhịp sóng (áp dụng khi `shape` là "wavy" theo determinate).
|
|
66
|
+
* Khoảng cách giữa 2 đỉnh sóng kề nhau.
|
|
67
|
+
*/
|
|
68
|
+
wavelength?: number;
|
|
69
|
+
/**
|
|
70
|
+
* Nhịp sóng dành riêng cho trạng thái chạy liên tục (Indeterminate Wavy).
|
|
71
|
+
*/
|
|
72
|
+
indeterminateWavelength?: number;
|
|
73
|
+
/**
|
|
74
|
+
* Khoảng hở kết dính giữa cụm vạch đang chạy và thanh nền.
|
|
75
|
+
* Cho phép truyền \`0\` để hai thanh chạm sát vào nhau liền mạch.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```tsx
|
|
79
|
+
* <ProgressIndicator variant="linear" shape="wavy" gapSize={0} /> // Sóng chạm track liền nét
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
gapSize?: number;
|
|
83
|
+
/**
|
|
84
|
+
* Tốc độ dao động vỗ của sóng (Multiplier). Mặc định là \`1\`.
|
|
85
|
+
* Tăng giá trị (VD: 1.5, 2) để sóng dao động nhanh hơn.
|
|
86
|
+
*/
|
|
87
|
+
waveSpeed?: number;
|
|
88
|
+
/**
|
|
89
|
+
* Tốc độ lướt / cuộn dải màu dọc trên track (Crawler) đối với trạng thái Indeterminate.
|
|
90
|
+
* Mặc định là \`1\`.
|
|
91
|
+
*/
|
|
92
|
+
crawlerSpeed?: number;
|
|
93
|
+
/**
|
|
94
|
+
* Cấu hình hiệu ứng gợn khi thanh determinate ở mức xấp xỉ mép viền (<= 10% hoặc >= 90%).
|
|
95
|
+
* - `md3`: Tự động ép phẳng biên độ sóng thành số 0 một cách mềm mại (Chuẩn Google MD3).
|
|
96
|
+
* - `continuous`: Bỏ qua các ràng buộc ép phẳng, con sóng vẫn gợn lấp lóa trên mọi giá trị phần trăm.
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```tsx
|
|
100
|
+
* <ProgressIndicator variant="linear" shape="wavy" determinateAnimation="continuous" />
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
determinateAnimation?: "md3" | "continuous";
|
|
104
|
+
/**
|
|
105
|
+
* Kiểu kịch bản tịnh tiến cho thanh Indeterminate.
|
|
106
|
+
* - `md3`: Render 2 vạch song song vọt tới & co giãn mô phỏng vật lý (Chuẩn Google MD3).
|
|
107
|
+
* - `continuous`: Vạch không ngắt quãng mà tràn lướt vòng lặp mượt mà.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```tsx
|
|
111
|
+
* <ProgressIndicator variant="linear" indeterminateAnimation="continuous" />
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
indeterminateAnimation?: "md3" | "continuous";
|
|
115
|
+
/**
|
|
116
|
+
* Bật/tắt dấm chấm điểm báo kết thúc ở cuối track (Stop Indicator).
|
|
117
|
+
* - `true`: Luôn thấy một chấm tròn bé xíu ở cuối đường đi
|
|
118
|
+
* - `false`: Tắt hoàn toàn
|
|
119
|
+
* - `"auto"`: Chấm tròn chỉ hiển thị và hòa trộn khi progress đạt 100%
|
|
120
|
+
*/
|
|
121
|
+
showStopIndicator?: boolean | "auto";
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface CircularProgressProps extends ProgressBaseProps {
|
|
125
|
+
/** Phân loại component sang kiểu dáng Circular (hình tròn khép kín). */
|
|
126
|
+
variant: "circular";
|
|
127
|
+
/**
|
|
128
|
+
* Đường kính hiển thị của vòng biểu đồ, đơn vị px.
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```tsx
|
|
132
|
+
* <ProgressIndicator variant="circular" size={48} aria-label="Loading..." />
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
size?: number;
|
|
136
|
+
/**
|
|
137
|
+
* Phong cách nét vẽ của đường viền trong trạng thái trượt.
|
|
138
|
+
* - `flat`: Đường nét cứng, vuốt tròn hai đầu stroke.
|
|
139
|
+
* - `wavy`: Vệt màu chuyển động rung tạo hình răng cưa/gợn sóng.
|
|
140
|
+
*/
|
|
141
|
+
shape?: "flat" | "wavy";
|
|
142
|
+
/**
|
|
143
|
+
* Biên độ gợn của trạng thái `wavy` cho vòng tròn.
|
|
144
|
+
*/
|
|
145
|
+
amplitude?: number;
|
|
146
|
+
/** Bước sóng bao trọn chu vi hình tròn. */
|
|
147
|
+
wavelength?: number;
|
|
148
|
+
/** Khoảng hở khe đứt ngang nối đỉnh nét vẽ. */
|
|
149
|
+
gapSize?: number;
|
|
150
|
+
/**
|
|
151
|
+
* Xoay nhanh hay chậm theo số nhân cho Crawler Circular quay Indeterminate.
|
|
152
|
+
*/
|
|
153
|
+
crawlerSpeed?: number;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export type ProgressIndicatorProps =
|
|
157
|
+
| LinearProgressProps
|
|
158
|
+
| CircularProgressProps;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export function easeInOutCubic(x: number): number {
|
|
2
|
+
return x < 0.5 ? 4 * x * x * x : 1 - (-2 * x + 2) ** 3 / 2;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function generateWavyCircularPath(
|
|
6
|
+
center: number,
|
|
7
|
+
radius: number,
|
|
8
|
+
amplitude: number,
|
|
9
|
+
wavelength: number,
|
|
10
|
+
): string {
|
|
11
|
+
const circumference = 2 * Math.PI * radius;
|
|
12
|
+
const numWaves = Math.max(
|
|
13
|
+
3,
|
|
14
|
+
Math.round(circumference / Math.max(1, wavelength)),
|
|
15
|
+
);
|
|
16
|
+
const steps = numWaves * 4;
|
|
17
|
+
const dt = (2 * Math.PI) / steps;
|
|
18
|
+
|
|
19
|
+
const rAt = (t: number) => radius + amplitude * Math.sin(numWaves * t);
|
|
20
|
+
const drAt = (t: number) => amplitude * numWaves * Math.cos(numWaves * t);
|
|
21
|
+
const xAt = (t: number) => center + rAt(t) * Math.cos(t);
|
|
22
|
+
const yAt = (t: number) => center + rAt(t) * Math.sin(t);
|
|
23
|
+
const dxAt = (t: number) => drAt(t) * Math.cos(t) - rAt(t) * Math.sin(t);
|
|
24
|
+
const dyAt = (t: number) => drAt(t) * Math.sin(t) + rAt(t) * Math.cos(t);
|
|
25
|
+
|
|
26
|
+
let d = "";
|
|
27
|
+
const tStart = 0;
|
|
28
|
+
|
|
29
|
+
for (let i = 0; i < steps; i++) {
|
|
30
|
+
const t0 = tStart + i * dt;
|
|
31
|
+
const t1 = tStart + (i + 1) * dt;
|
|
32
|
+
|
|
33
|
+
const scale = dt / 3;
|
|
34
|
+
const cp1x = xAt(t0) + scale * dxAt(t0);
|
|
35
|
+
const cp1y = yAt(t0) + scale * dyAt(t0);
|
|
36
|
+
const cp2x = xAt(t1) - scale * dxAt(t1);
|
|
37
|
+
const cp2y = yAt(t1) - scale * dyAt(t1);
|
|
38
|
+
|
|
39
|
+
if (i === 0) d += `M ${xAt(t0).toFixed(2)} ${yAt(t0).toFixed(2)}`;
|
|
40
|
+
d += ` C ${cp1x.toFixed(2)} ${cp1y.toFixed(2)}, ${cp2x.toFixed(2)} ${cp2y.toFixed(2)}, ${xAt(t1).toFixed(2)} ${yAt(t1).toFixed(2)}`;
|
|
41
|
+
}
|
|
42
|
+
d += " Z";
|
|
43
|
+
return d;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function getSinePath(
|
|
47
|
+
startX: number,
|
|
48
|
+
endX: number,
|
|
49
|
+
phase: number,
|
|
50
|
+
wl: number,
|
|
51
|
+
amp: number,
|
|
52
|
+
) {
|
|
53
|
+
if (startX >= endX) return "";
|
|
54
|
+
let d = "";
|
|
55
|
+
const step = amp === 0 ? Math.max(10, endX - startX) : 1;
|
|
56
|
+
|
|
57
|
+
const yStart = Math.sin(((startX + phase) / wl) * 2 * Math.PI) * amp;
|
|
58
|
+
d += `M ${startX.toFixed(2)} ${yStart.toFixed(2)}`;
|
|
59
|
+
|
|
60
|
+
let nextX = Math.ceil(startX / step) * step;
|
|
61
|
+
if (nextX === startX) nextX += step;
|
|
62
|
+
|
|
63
|
+
while (nextX < endX) {
|
|
64
|
+
const y = Math.sin(((nextX + phase) / wl) * 2 * Math.PI) * amp;
|
|
65
|
+
d += ` L ${nextX.toFixed(2)} ${y.toFixed(2)}`;
|
|
66
|
+
nextX += step;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const yEnd = Math.sin(((endX + phase) / wl) * 2 * Math.PI) * amp;
|
|
70
|
+
d += ` L ${endX.toFixed(2)} ${yEnd.toFixed(2)}`;
|
|
71
|
+
|
|
72
|
+
return d;
|
|
73
|
+
}
|