@bug-on/md3-react 0.1.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/README.md +215 -0
- package/dist/assets/fonts/GoogleSansFlex-VariableFont.woff2 +0 -0
- package/dist/assets/fonts/MaterialSymbolsOutlined-VariableFont_FILL,GRAD,opsz,wght.ttf +0 -0
- package/dist/assets/fonts/MaterialSymbolsRounded-VariableFont_FILL,GRAD,opsz,wght.ttf +0 -0
- package/dist/assets/fonts/MaterialSymbolsSharp-VariableFont_FILL,GRAD,opsz,wght.ttf +0 -0
- package/dist/assets/loading-indicator.svg +19 -0
- package/dist/assets/material-symbols-cdn.css +65 -0
- package/dist/assets/material-symbols-self-hosted.css +109 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/useMediaQuery.d.ts +11 -0
- package/dist/hooks/useRipple.d.ts +26 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.js +9059 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +8929 -0
- package/dist/index.mjs.map +1 -0
- package/dist/lib/material-symbols-preconnect.d.ts +42 -0
- package/dist/lib/theme-utils.d.ts +63 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/material-symbols-cdn.css +65 -0
- package/dist/material-symbols-self-hosted.css +109 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/md3.d.ts +14 -0
- package/dist/typography.css +22 -0
- package/dist/ui/badge.d.ts +125 -0
- package/dist/ui/button-group.d.ts +59 -0
- package/dist/ui/button.d.ts +148 -0
- package/dist/ui/card.d.ts +62 -0
- package/dist/ui/checkbox.d.ts +82 -0
- package/dist/ui/chip.d.ts +110 -0
- package/dist/ui/code-block.d.ts +14 -0
- package/dist/ui/dialog.d.ts +111 -0
- package/dist/ui/divider.d.ts +164 -0
- package/dist/ui/drawer.d.ts +39 -0
- package/dist/ui/dropdown.d.ts +29 -0
- package/dist/ui/fab-menu.d.ts +204 -0
- package/dist/ui/fab.d.ts +162 -0
- package/dist/ui/icon-button.d.ts +131 -0
- package/dist/ui/icon.d.ts +88 -0
- package/dist/ui/loading-indicator.d.ts +42 -0
- package/dist/ui/navigation-rail.d.ts +29 -0
- package/dist/ui/progress-indicator/circular.d.ts +3 -0
- package/dist/ui/progress-indicator/hooks.d.ts +3 -0
- package/dist/ui/progress-indicator/index.d.ts +21 -0
- package/dist/ui/progress-indicator/linear-flat.d.ts +10 -0
- package/dist/ui/progress-indicator/linear-wavy.d.ts +18 -0
- package/dist/ui/progress-indicator/linear.d.ts +3 -0
- package/dist/ui/progress-indicator/types.d.ts +151 -0
- package/dist/ui/progress-indicator/utils.d.ts +3 -0
- package/dist/ui/radio-button.d.ts +106 -0
- package/dist/ui/ripple.d.ts +126 -0
- package/dist/ui/scroll-area.d.ts +27 -0
- package/dist/ui/shared/constants.d.ts +86 -0
- package/dist/ui/shared/touch-target.d.ts +38 -0
- package/dist/ui/snackbar/index.d.ts +6 -0
- package/dist/ui/snackbar/snackbar.d.ts +196 -0
- package/dist/ui/switch/index.d.ts +7 -0
- package/dist/ui/switch/switch.d.ts +30 -0
- package/dist/ui/switch/switch.stories.d.ts +48 -0
- package/dist/ui/switch/switch.tokens.d.ts +67 -0
- package/dist/ui/switch/switch.types.d.ts +59 -0
- package/dist/ui/tabs/index.d.ts +10 -0
- package/dist/ui/tabs/tab.d.ts +43 -0
- package/dist/ui/tabs/tabs-content.d.ts +36 -0
- package/dist/ui/tabs/tabs-list.d.ts +40 -0
- package/dist/ui/tabs/tabs.d.ts +60 -0
- package/dist/ui/tabs/tabs.tokens.d.ts +94 -0
- package/dist/ui/tabs/tabs.types.d.ts +172 -0
- package/dist/ui/text-field/index.d.ts +11 -0
- package/dist/ui/text-field/subcomponents/active-indicator.d.ts +24 -0
- package/dist/ui/text-field/subcomponents/floating-label.d.ts +43 -0
- package/dist/ui/text-field/subcomponents/leading-icon.d.ts +23 -0
- package/dist/ui/text-field/subcomponents/outline-container.d.ts +42 -0
- package/dist/ui/text-field/subcomponents/prefix-suffix.d.ts +24 -0
- package/dist/ui/text-field/subcomponents/supporting-text.d.ts +37 -0
- package/dist/ui/text-field/subcomponents/trailing-icon.d.ts +41 -0
- package/dist/ui/text-field/text-field.d.ts +49 -0
- package/dist/ui/text-field/text-field.tokens.d.ts +76 -0
- package/dist/ui/text-field/text-field.types.d.ts +126 -0
- package/dist/ui/theme-provider/index.d.ts +18 -0
- package/dist/ui/toc.d.ts +74 -0
- package/dist/ui/tooltip/index.d.ts +8 -0
- package/dist/ui/tooltip/plain-tooltip.d.ts +2 -0
- package/dist/ui/tooltip/rich-tooltip.d.ts +2 -0
- package/dist/ui/tooltip/tooltip-box.d.ts +2 -0
- package/dist/ui/tooltip/tooltip-caret-shape.d.ts +9 -0
- package/dist/ui/tooltip/tooltip.tokens.d.ts +26 -0
- package/dist/ui/tooltip/tooltip.types.d.ts +56 -0
- package/dist/ui/tooltip/use-tooltip-position.d.ts +8 -0
- package/dist/ui/tooltip/use-tooltip-state.d.ts +2 -0
- package/dist/ui/typography/index.d.ts +16 -0
- package/dist/ui/typography/type-scale-tokens.d.ts +162 -0
- package/dist/ui/typography/typography-key-tokens.d.ts +40 -0
- package/dist/ui/typography/typography-tokens.d.ts +220 -0
- package/dist/ui/typography/typography.d.ts +265 -0
- package/package.json +80 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { ProgressIndicatorProps } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* Thanh tiến trình (Progress Indicator) theo nguyên tắc Material Design 3 Expressive.
|
|
5
|
+
* Hỗ trợ linh hoạt 2 loại hình hiển thị: Linear (Đường thẳng) và Circular (Hình tròn),
|
|
6
|
+
* cùng với thiết kế Wavy (Lượn sóng) động rất mềm mại.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* // Determinate Flat Linear
|
|
11
|
+
* <ProgressIndicator variant="linear" value={60} aria-label="Loading profile..." />
|
|
12
|
+
*
|
|
13
|
+
* // Indeterminate Wavy Linear
|
|
14
|
+
* <ProgressIndicator variant="linear" shape="wavy" aria-label="Connecting to server..." />
|
|
15
|
+
*
|
|
16
|
+
* // Determinate Flat Circular
|
|
17
|
+
* <ProgressIndicator variant="circular" value={45} size={48} aria-label="Syncing..." />
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare const ProgressIndicator: React.ForwardRefExoticComponent<ProgressIndicatorProps & React.RefAttributes<HTMLDivElement>>;
|
|
21
|
+
export type { CircularProgressProps, LinearProgressProps, ProgressIndicatorProps, } from "./types";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export declare const WavyLinearTrack: React.NamedExoticComponent<{
|
|
3
|
+
trackHeight: number;
|
|
4
|
+
svgHeight: number;
|
|
5
|
+
amplitude: number;
|
|
6
|
+
wavelength: number;
|
|
7
|
+
indeterminateWavelength: number;
|
|
8
|
+
activeColor: string;
|
|
9
|
+
trackColor: string;
|
|
10
|
+
value?: number;
|
|
11
|
+
isRtl: boolean;
|
|
12
|
+
gapSize: number;
|
|
13
|
+
waveSpeed: number;
|
|
14
|
+
crawlerSpeed: number;
|
|
15
|
+
determinateAnimation: "md3" | "continuous";
|
|
16
|
+
indeterminateAnimation: "md3" | "continuous";
|
|
17
|
+
trackShape: "flat" | "wavy";
|
|
18
|
+
}>;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import type * as React from "react";
|
|
2
|
+
export interface ProgressBaseProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "children"> {
|
|
3
|
+
/**
|
|
4
|
+
* Giá trị phần trăm tiến trình hiện tại (từ 0 đến 100).
|
|
5
|
+
* Nếu truyền giá trị này, tiến trình sẽ hiển thị ở trạng thái Determinate.
|
|
6
|
+
* Nếu bỏ trống (undefined), tiến trình sẽ tự động ở trạng thái Indeterminate.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* <ProgressIndicator value={45} aria-label="Loading profile..." />
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
value?: number;
|
|
14
|
+
/**
|
|
15
|
+
* Nhan đề mô tả mục đích của thanh tiến trình dành cho screen readers (bắt buộc).
|
|
16
|
+
*/
|
|
17
|
+
"aria-label": string;
|
|
18
|
+
/**
|
|
19
|
+
* Độ dày của track (đường nền) của thanh tiến trình (đơn vị: px).
|
|
20
|
+
* - Với Linear: là chiều cao của thanh.
|
|
21
|
+
* - Với Circular: là độ dày của viền hình tròn.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* trackHeight={8} // Dày hơn bình thường
|
|
25
|
+
*/
|
|
26
|
+
trackHeight?: number;
|
|
27
|
+
/**
|
|
28
|
+
* Màu sắc của phần tiến trình (phần đã hoàn thành).
|
|
29
|
+
* Mặc định mượn màu `currentColor` của thẻ wrap, để dễ dàng tuỳ biến qua utility class.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* color="var(--md-sys-color-primary)" // Sử dụng custom token
|
|
33
|
+
*/
|
|
34
|
+
color?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Màu sắc của thanh nền (phần chưa hoàn thành).
|
|
37
|
+
* 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ế.
|
|
38
|
+
*/
|
|
39
|
+
trackColor?: string;
|
|
40
|
+
}
|
|
41
|
+
export interface LinearProgressProps extends ProgressBaseProps {
|
|
42
|
+
/** Phân loại component sang kiểu dáng Linear (đường thẳng ngang). */
|
|
43
|
+
variant: "linear";
|
|
44
|
+
/**
|
|
45
|
+
* Hình dáng của vạch tiến trình (phần đã hoàn thành).
|
|
46
|
+
* - `flat`: Đường nét liền phẳng (mặc định)
|
|
47
|
+
* - `wavy`: Đường lượn sóng động
|
|
48
|
+
*/
|
|
49
|
+
shape?: "flat" | "wavy";
|
|
50
|
+
/**
|
|
51
|
+
* Hình dáng của thanh nền chờ (track).
|
|
52
|
+
* - `flat`: Đường nét liền phẳng (mặc định)
|
|
53
|
+
* - `wavy`: Đường lượn sóng cố định hoặc động
|
|
54
|
+
*/
|
|
55
|
+
trackShape?: "flat" | "wavy";
|
|
56
|
+
/**
|
|
57
|
+
* Biên độ sóng (áp dụng khi `shape` hoặc `trackShape` là "wavy").
|
|
58
|
+
* Chỉ định độ lượn cao thấp của con sóng.
|
|
59
|
+
*/
|
|
60
|
+
amplitude?: number;
|
|
61
|
+
/**
|
|
62
|
+
* Chiều dài một nhịp sóng (áp dụng khi `shape` là "wavy" theo determinate).
|
|
63
|
+
* Khoảng cách giữa 2 đỉnh sóng kề nhau.
|
|
64
|
+
*/
|
|
65
|
+
wavelength?: number;
|
|
66
|
+
/**
|
|
67
|
+
* Nhịp sóng dành riêng cho trạng thái chạy liên tục (Indeterminate Wavy).
|
|
68
|
+
*/
|
|
69
|
+
indeterminateWavelength?: number;
|
|
70
|
+
/**
|
|
71
|
+
* Khoảng hở kết dính giữa cụm vạch đang chạy và thanh nền.
|
|
72
|
+
* Cho phép truyền \`0\` để hai thanh chạm sát vào nhau liền mạch.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```tsx
|
|
76
|
+
* <ProgressIndicator variant="linear" shape="wavy" gapSize={0} /> // Sóng chạm track liền nét
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
gapSize?: number;
|
|
80
|
+
/**
|
|
81
|
+
* Tốc độ dao động vỗ của sóng (Multiplier). Mặc định là \`1\`.
|
|
82
|
+
* Tăng giá trị (VD: 1.5, 2) để sóng dao động nhanh hơn.
|
|
83
|
+
*/
|
|
84
|
+
waveSpeed?: number;
|
|
85
|
+
/**
|
|
86
|
+
* Tốc độ lướt / cuộn dải màu dọc trên track (Crawler) đối với trạng thái Indeterminate.
|
|
87
|
+
* Mặc định là \`1\`.
|
|
88
|
+
*/
|
|
89
|
+
crawlerSpeed?: number;
|
|
90
|
+
/**
|
|
91
|
+
* 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%).
|
|
92
|
+
* - `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).
|
|
93
|
+
* - `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.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```tsx
|
|
97
|
+
* <ProgressIndicator variant="linear" shape="wavy" determinateAnimation="continuous" />
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
determinateAnimation?: "md3" | "continuous";
|
|
101
|
+
/**
|
|
102
|
+
* Kiểu kịch bản tịnh tiến cho thanh Indeterminate.
|
|
103
|
+
* - `md3`: Render 2 vạch song song vọt tới & co giãn mô phỏng vật lý (Chuẩn Google MD3).
|
|
104
|
+
* - `continuous`: Vạch không ngắt quãng mà tràn lướt vòng lặp mượt mà.
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```tsx
|
|
108
|
+
* <ProgressIndicator variant="linear" indeterminateAnimation="continuous" />
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
indeterminateAnimation?: "md3" | "continuous";
|
|
112
|
+
/**
|
|
113
|
+
* Bật/tắt dấm chấm điểm báo kết thúc ở cuối track (Stop Indicator).
|
|
114
|
+
* - `true`: Luôn thấy một chấm tròn bé xíu ở cuối đường đi
|
|
115
|
+
* - `false`: Tắt hoàn toàn
|
|
116
|
+
* - `"auto"`: Chấm tròn chỉ hiển thị và hòa trộn khi progress đạt 100%
|
|
117
|
+
*/
|
|
118
|
+
showStopIndicator?: boolean | "auto";
|
|
119
|
+
}
|
|
120
|
+
export interface CircularProgressProps extends ProgressBaseProps {
|
|
121
|
+
/** Phân loại component sang kiểu dáng Circular (hình tròn khép kín). */
|
|
122
|
+
variant: "circular";
|
|
123
|
+
/**
|
|
124
|
+
* Đường kính hiển thị của vòng biểu đồ, đơn vị px.
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```tsx
|
|
128
|
+
* <ProgressIndicator variant="circular" size={48} aria-label="Loading..." />
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
size?: number;
|
|
132
|
+
/**
|
|
133
|
+
* Phong cách nét vẽ của đường viền trong trạng thái trượt.
|
|
134
|
+
* - `flat`: Đường nét cứng, vuốt tròn hai đầu stroke.
|
|
135
|
+
* - `wavy`: Vệt màu chuyển động rung tạo hình răng cưa/gợn sóng.
|
|
136
|
+
*/
|
|
137
|
+
shape?: "flat" | "wavy";
|
|
138
|
+
/**
|
|
139
|
+
* Biên độ gợn của trạng thái `wavy` cho vòng tròn.
|
|
140
|
+
*/
|
|
141
|
+
amplitude?: number;
|
|
142
|
+
/** Bước sóng bao trọn chu vi hình tròn. */
|
|
143
|
+
wavelength?: number;
|
|
144
|
+
/** Khoảng hở khe đứt ngang nối đỉnh nét vẽ. */
|
|
145
|
+
gapSize?: number;
|
|
146
|
+
/**
|
|
147
|
+
* Xoay nhanh hay chậm theo số nhân cho Crawler Circular quay Indeterminate.
|
|
148
|
+
*/
|
|
149
|
+
crawlerSpeed?: number;
|
|
150
|
+
}
|
|
151
|
+
export type ProgressIndicatorProps = LinearProgressProps | CircularProgressProps;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare function easeInOutCubic(x: number): number;
|
|
2
|
+
export declare function generateWavyCircularPath(center: number, radius: number, amplitude: number, wavelength: number): string;
|
|
3
|
+
export declare function getSinePath(startX: number, endX: number, phase: number, wl: number, amp: number): string;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file radio-button.tsx
|
|
3
|
+
* MD3 Expressive RadioButton — single-select with RadioGroup support.
|
|
4
|
+
* Spec: https://m3.material.io/components/radio-button/overview
|
|
5
|
+
*/
|
|
6
|
+
import * as React from "react";
|
|
7
|
+
/**
|
|
8
|
+
* Color variant for `RadioButton`.
|
|
9
|
+
* - `"primary"` — standard selection (default)
|
|
10
|
+
* - `"error"` — error/invalid state
|
|
11
|
+
*/
|
|
12
|
+
export type RadioButtonColors = "primary" | "error";
|
|
13
|
+
/** Props for `RadioButton`. */
|
|
14
|
+
export interface RadioButtonProps {
|
|
15
|
+
/** Whether this radio is selected. */
|
|
16
|
+
selected?: boolean;
|
|
17
|
+
/** Initial selected state (uncontrolled). @default false */
|
|
18
|
+
defaultSelected?: boolean;
|
|
19
|
+
/** Called when user clicks. Pass `null` to disable interaction. */
|
|
20
|
+
onClick?: (() => void) | null;
|
|
21
|
+
/** Disables the radio — visual disabled state + no interaction. @default false */
|
|
22
|
+
disabled?: boolean;
|
|
23
|
+
/** Color variant. @default "primary" */
|
|
24
|
+
color?: RadioButtonColors;
|
|
25
|
+
/** Error state — changes colors to `m3-error`. @default false */
|
|
26
|
+
error?: boolean;
|
|
27
|
+
/** Adjacent label text. Renders a `<label>` wrapper. */
|
|
28
|
+
label?: string;
|
|
29
|
+
/** Value used for form submission. */
|
|
30
|
+
value?: string;
|
|
31
|
+
/** Name for grouping (used in RadioGroup context). */
|
|
32
|
+
name?: string;
|
|
33
|
+
/** ID for the hidden `<input>`. Auto-generated when `label` is set. */
|
|
34
|
+
id?: string;
|
|
35
|
+
/** Extra class names on the outermost wrapper. */
|
|
36
|
+
className?: string;
|
|
37
|
+
/** ARIA label for the radio when no visible label exists. */
|
|
38
|
+
"aria-label"?: string;
|
|
39
|
+
"aria-labelledby"?: string;
|
|
40
|
+
"aria-describedby"?: string;
|
|
41
|
+
/** Whether the radio is required for form submission. */
|
|
42
|
+
required?: boolean;
|
|
43
|
+
/** Ref to the hidden `<input type="radio">`. */
|
|
44
|
+
ref?: React.Ref<HTMLInputElement>;
|
|
45
|
+
}
|
|
46
|
+
/** Props for `RadioGroup`. */
|
|
47
|
+
export interface RadioGroupProps {
|
|
48
|
+
/** The name attribute shared across all child RadioButtons. */
|
|
49
|
+
name: string;
|
|
50
|
+
/** The currently selected value (controlled). */
|
|
51
|
+
value?: string;
|
|
52
|
+
/** Default value (uncontrolled). */
|
|
53
|
+
defaultValue?: string;
|
|
54
|
+
/** Called when selection changes. */
|
|
55
|
+
onValueChange?: (value: string) => void;
|
|
56
|
+
/** Disables all radio buttons in the group. */
|
|
57
|
+
disabled?: boolean;
|
|
58
|
+
/** Error state for the entire group. */
|
|
59
|
+
error?: boolean;
|
|
60
|
+
/** Label for the group (renders as visually hidden or visible heading). */
|
|
61
|
+
label?: string;
|
|
62
|
+
/** ID of an external element that labels this group. */
|
|
63
|
+
"aria-labelledby"?: string;
|
|
64
|
+
/** Direction of layout. @default "vertical" */
|
|
65
|
+
orientation?: "horizontal" | "vertical";
|
|
66
|
+
/** Whether at least one radio in the group must be selected. */
|
|
67
|
+
required?: boolean;
|
|
68
|
+
children: React.ReactNode;
|
|
69
|
+
className?: string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* MD3 Expressive RadioButton component.
|
|
73
|
+
*
|
|
74
|
+
* Single-select control. Supports standalone (controlled/uncontrolled) and
|
|
75
|
+
* `RadioGroup` context. Animated per MD3 spec: inner dot radius morph,
|
|
76
|
+
* outer ring color transition, state layer, and ripple.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```tsx
|
|
80
|
+
* <RadioButton selected={isSelected} onClick={() => setSelected(true)} label="Option A" />
|
|
81
|
+
*
|
|
82
|
+
* <RadioGroup name="plan" value={plan} onValueChange={setPlan}>
|
|
83
|
+
* <RadioButton value="free" label="Free" />
|
|
84
|
+
* <RadioButton value="pro" label="Pro" />
|
|
85
|
+
* </RadioGroup>
|
|
86
|
+
* ```
|
|
87
|
+
* @see https://m3.material.io/components/radio-button/overview
|
|
88
|
+
*/
|
|
89
|
+
export declare const RadioButton: React.NamedExoticComponent<Omit<RadioButtonProps, "ref"> & React.RefAttributes<HTMLInputElement>>;
|
|
90
|
+
/**
|
|
91
|
+
* MD3 Expressive RadioGroup component.
|
|
92
|
+
*
|
|
93
|
+
* Groups multiple `RadioButton` components under a shared `name` with keyboard
|
|
94
|
+
* navigation (Arrow keys with wrapping) and ARIA `radiogroup` semantics.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```tsx
|
|
98
|
+
* <RadioGroup name="theme" value={theme} onValueChange={setTheme} label="Theme">
|
|
99
|
+
* <RadioButton value="light" label="Light" />
|
|
100
|
+
* <RadioButton value="dark" label="Dark" />
|
|
101
|
+
* <RadioButton value="system" label="System" />
|
|
102
|
+
* </RadioGroup>
|
|
103
|
+
* ```
|
|
104
|
+
* @see https://m3.material.io/components/radio-button/overview
|
|
105
|
+
*/
|
|
106
|
+
export declare const RadioGroup: React.NamedExoticComponent<RadioGroupProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Represents a single ripple wave instance with position and size metadata.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```tsx
|
|
7
|
+
* const ripple: RippleOrigin = { id: Date.now(), x: 50, y: 30, size: 200 };
|
|
8
|
+
* ```
|
|
9
|
+
*/
|
|
10
|
+
export interface RippleOrigin {
|
|
11
|
+
/** Unique identifier used as React key and for removal. */
|
|
12
|
+
id: number;
|
|
13
|
+
/** X coordinate of the pointer event relative to the container's left edge (px). */
|
|
14
|
+
x: number;
|
|
15
|
+
/** Y coordinate of the pointer event relative to the container's top edge (px). */
|
|
16
|
+
y: number;
|
|
17
|
+
/**
|
|
18
|
+
* Diameter of the ripple circle (px).
|
|
19
|
+
* Typically `Math.hypot(width, height) * 2` to ensure it fills the container.
|
|
20
|
+
*/
|
|
21
|
+
size: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Props for the `Ripple` presentation component.
|
|
25
|
+
*/
|
|
26
|
+
export interface RippleProps {
|
|
27
|
+
/** Active ripple instances to render. Managed by the parent via `useRipple`. */
|
|
28
|
+
ripples: RippleOrigin[];
|
|
29
|
+
/** Called when a ripple's exit animation completes — remove it from state. */
|
|
30
|
+
onRippleDone: (id: number) => void;
|
|
31
|
+
/**
|
|
32
|
+
* Completely disables the ripple effect.
|
|
33
|
+
* Use this when the parent element is disabled or interaction is not desired.
|
|
34
|
+
* @default false
|
|
35
|
+
*/
|
|
36
|
+
disabled?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* When `true`, the ripple respects the user's OS-level
|
|
39
|
+
* `prefers-reduced-motion` accessibility setting and renders nothing if active.
|
|
40
|
+
*
|
|
41
|
+
* Set to `false` to always show ripples regardless of system preference.
|
|
42
|
+
* @default true
|
|
43
|
+
*/
|
|
44
|
+
respectSystemMotion?: boolean;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* MD3 Expressive Ripple — animated touch-feedback wave layer.
|
|
48
|
+
*
|
|
49
|
+
* Renders absolutely-positioned ripple circles inside an `overflow-hidden`
|
|
50
|
+
* container. Must be placed as a direct child of the interactive element.
|
|
51
|
+
*
|
|
52
|
+
* @remarks
|
|
53
|
+
* - The parent element **must** have `overflow: hidden` and `position: relative`
|
|
54
|
+
* (or equivalent) for clipping to work correctly.
|
|
55
|
+
* - Set `disabled` to `true` on parent's disabled state to avoid stale ripples.
|
|
56
|
+
* - The ripple color is `currentColor` at 12% opacity — matching MD3 state layer spec.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```tsx
|
|
60
|
+
* const { ripples, onPointerDown, removeRipple } = useRippleState();
|
|
61
|
+
*
|
|
62
|
+
* <button onPointerDown={onPointerDown} className="relative overflow-hidden">
|
|
63
|
+
* <Ripple ripples={ripples} onRippleDone={removeRipple} />
|
|
64
|
+
* Click me
|
|
65
|
+
* </button>
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* @see {@link useRippleState} for the state management hook
|
|
69
|
+
* @see https://m3.material.io/foundations/interaction/states/overview
|
|
70
|
+
*/
|
|
71
|
+
export declare function Ripple({ ripples, onRippleDone, disabled, respectSystemMotion, }: RippleProps): import("react/jsx-runtime").JSX.Element | null;
|
|
72
|
+
/**
|
|
73
|
+
* Options for configuring `useRippleState` behaviour.
|
|
74
|
+
*/
|
|
75
|
+
export interface UseRippleStateOptions {
|
|
76
|
+
/**
|
|
77
|
+
* When `true`, the ripple is suppressed — `onPointerDown` becomes a no-op.
|
|
78
|
+
* Use this to sync the ripple with the parent element's `disabled` state.
|
|
79
|
+
* @default false
|
|
80
|
+
*/
|
|
81
|
+
disabled?: boolean;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* `useRippleState` — state manager for MD3 Expressive ripple waves.
|
|
85
|
+
*
|
|
86
|
+
* Tracks active ripple instances and provides pointer event handlers.
|
|
87
|
+
* Pair with the `<Ripple>` component for rendering.
|
|
88
|
+
*
|
|
89
|
+
* @remarks
|
|
90
|
+
* This hook only manages ripple *state* (coordinates, size, lifecycle).
|
|
91
|
+
* The actual animation is handled by `<Ripple>` via Framer Motion.
|
|
92
|
+
* Respecting `prefers-reduced-motion` is handled by `<Ripple>` itself.
|
|
93
|
+
*
|
|
94
|
+
* @param options - Configuration options. See {@link UseRippleStateOptions}.
|
|
95
|
+
* @returns `{ ripples, onPointerDown, removeRipple }` — bind to the interactive element.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```tsx
|
|
99
|
+
* function MyButton({ disabled, children }) {
|
|
100
|
+
* const { ripples, onPointerDown, removeRipple } = useRippleState({ disabled });
|
|
101
|
+
*
|
|
102
|
+
* return (
|
|
103
|
+
* <button
|
|
104
|
+
* disabled={disabled}
|
|
105
|
+
* onPointerDown={onPointerDown}
|
|
106
|
+
* className="relative overflow-hidden"
|
|
107
|
+
* >
|
|
108
|
+
* <Ripple ripples={ripples} onRippleDone={removeRipple} disabled={disabled} />
|
|
109
|
+
* {children}
|
|
110
|
+
* </button>
|
|
111
|
+
* );
|
|
112
|
+
* }
|
|
113
|
+
* ```
|
|
114
|
+
*
|
|
115
|
+
* @see {@link Ripple} for the rendering component
|
|
116
|
+
*/
|
|
117
|
+
export declare function useRippleState(options?: UseRippleStateOptions): {
|
|
118
|
+
ripples: RippleOrigin[];
|
|
119
|
+
onPointerDown: (e: React.PointerEvent<HTMLElement>) => void;
|
|
120
|
+
removeRipple: (id: number) => void;
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* @deprecated Use `useRippleState` instead. This alias will be removed in a future version.
|
|
124
|
+
* @see {@link useRippleState}
|
|
125
|
+
*/
|
|
126
|
+
export declare const useRipple: typeof useRippleState;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as RadixScrollArea from "@radix-ui/react-scroll-area";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
/** Radix accepts hover/scroll/always/auto. We add 'none' as a UI-only hide. */
|
|
4
|
+
export type ScrollAreaType = "hover" | "scroll" | "always" | "none";
|
|
5
|
+
export type ScrollAreaOrientation = "vertical" | "horizontal" | "both";
|
|
6
|
+
export interface ScrollAreaProps extends Omit<React.ComponentPropsWithoutRef<typeof RadixScrollArea.Root>, "type"> {
|
|
7
|
+
/**
|
|
8
|
+
* Controls when the scrollbars are visible.
|
|
9
|
+
* - `hover`: Show on hover (default, recommended for desktop)
|
|
10
|
+
* - `scroll`: Show only while scrolling (recommended for mobile)
|
|
11
|
+
* - `always`: Always visible
|
|
12
|
+
* - `none`: Never visible
|
|
13
|
+
*/
|
|
14
|
+
type?: ScrollAreaType;
|
|
15
|
+
/**
|
|
16
|
+
* The scrollbar orientation to render.
|
|
17
|
+
* @default "vertical"
|
|
18
|
+
*/
|
|
19
|
+
orientation?: ScrollAreaOrientation;
|
|
20
|
+
/** Delay in ms before scrollbars hide when `type` is `hover` or `scroll`. */
|
|
21
|
+
scrollHideDelay?: number;
|
|
22
|
+
/** Extra classes applied to the inner viewport element. */
|
|
23
|
+
viewportClassName?: string;
|
|
24
|
+
}
|
|
25
|
+
declare const ScrollArea: React.ForwardRefExoticComponent<ScrollAreaProps & React.RefAttributes<HTMLDivElement>>;
|
|
26
|
+
declare const ScrollAreaScrollbar: React.ForwardRefExoticComponent<Omit<RadixScrollArea.ScrollAreaScrollbarProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
27
|
+
export { ScrollArea, ScrollAreaScrollbar };
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file shared/constants.ts
|
|
3
|
+
*
|
|
4
|
+
* Shared animation constants for MD3 Expressive UI components.
|
|
5
|
+
* Centralises spring transition configs and motion variant objects to avoid
|
|
6
|
+
* duplication across button, icon-button, FAB, and other interactive components.
|
|
7
|
+
*
|
|
8
|
+
* @see https://m3.material.io/foundations/animation/overview
|
|
9
|
+
*/
|
|
10
|
+
import type { Target, TargetAndTransition, Transition } from "motion/react";
|
|
11
|
+
/**
|
|
12
|
+
* Fast critically-damped spring — used for border-radius morphing.
|
|
13
|
+
*
|
|
14
|
+
* - Duration: 200ms
|
|
15
|
+
* - Bounce: 0 (no overshoot → prevents negative radius jitter)
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* <m.button transition={{ borderRadius: SPRING_TRANSITION_FAST }}>...</m.button>
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare const SPRING_TRANSITION_FAST: Transition;
|
|
23
|
+
/**
|
|
24
|
+
* Standard critically-damped spring — used for icon/content scale animations.
|
|
25
|
+
*
|
|
26
|
+
* - Duration: 300ms
|
|
27
|
+
* - Bounce: 0 (no overshoot)
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```tsx
|
|
31
|
+
* <m.span transition={SPRING_TRANSITION}>...</m.span>
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare const SPRING_TRANSITION: Transition;
|
|
35
|
+
/**
|
|
36
|
+
* Framer Motion variants for animating icon spans in/out.
|
|
37
|
+
*
|
|
38
|
+
* Scale from near-zero → 1 on enter; back to near-zero on exit.
|
|
39
|
+
* The near-zero value (0.01) avoids the SMIL freeze bug on Chromium
|
|
40
|
+
* that occurs when an element starts at exactly `scale(0)`.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```tsx
|
|
44
|
+
* <AnimatePresence mode="wait">
|
|
45
|
+
* {loading ? (
|
|
46
|
+
* <m.span key="loading" {...ICON_SPAN_VARIANTS} transition={SPRING_TRANSITION}>
|
|
47
|
+
* <LoadingIndicator />
|
|
48
|
+
* </m.span>
|
|
49
|
+
* ) : (
|
|
50
|
+
* <m.span key="icon" {...ICON_SPAN_VARIANTS} transition={SPRING_TRANSITION}>
|
|
51
|
+
* {icon}
|
|
52
|
+
* </m.span>
|
|
53
|
+
* )}
|
|
54
|
+
* </AnimatePresence>
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export declare const ICON_SPAN_VARIANTS: {
|
|
58
|
+
initial: Target;
|
|
59
|
+
animate: TargetAndTransition;
|
|
60
|
+
exit: TargetAndTransition;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* MD3 Standard easing curve — used for label float, active indicator expand.
|
|
64
|
+
* cubic-bezier(0.2, 0, 0, 1)
|
|
65
|
+
*
|
|
66
|
+
* @see https://m3.material.io/foundations/animation/easing-and-duration
|
|
67
|
+
*/
|
|
68
|
+
export declare const MD3_STANDARD_EASING: [number, number, number, number];
|
|
69
|
+
/**
|
|
70
|
+
* Duration for floating label transition: 150ms.
|
|
71
|
+
* Used when label moves between inline position ↔ floated position.
|
|
72
|
+
*/
|
|
73
|
+
export declare const MD3_LABEL_FLOAT_DURATION = 0.15;
|
|
74
|
+
/**
|
|
75
|
+
* Duration for active indicator expand/collapse: 200ms.
|
|
76
|
+
* Used for the bottom border (filled) and outline (outlined) on focus.
|
|
77
|
+
*/
|
|
78
|
+
export declare const MD3_INDICATOR_DURATION = 0.2;
|
|
79
|
+
/**
|
|
80
|
+
* Duration for supporting text / error text appear/disappear: 120ms.
|
|
81
|
+
*/
|
|
82
|
+
export declare const MD3_SUPPORTING_DURATION = 0.12;
|
|
83
|
+
/**
|
|
84
|
+
* Duration for trailing icon appear/disappear (clear button, password toggle): 100ms.
|
|
85
|
+
*/
|
|
86
|
+
export declare const MD3_ICON_SWAP_DURATION = 0.1;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file shared/touch-target.tsx
|
|
3
|
+
*
|
|
4
|
+
* Invisible 48×48dp touch-target expander for small interactive elements.
|
|
5
|
+
*
|
|
6
|
+
* WCAG 2.5.5 (Level AA) requires interactive targets to be at least 44×44 CSS pixels.
|
|
7
|
+
* MD3 specifies a minimum 48dp touch target for all interactive components.
|
|
8
|
+
* For button sizes XS (32dp) and SM (40dp) that are smaller than this minimum,
|
|
9
|
+
* an invisible absolutely-positioned `<span>` is overlaid to extend the
|
|
10
|
+
* effective tap area without affecting visual layout.
|
|
11
|
+
*
|
|
12
|
+
* @see https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html
|
|
13
|
+
* @see https://m3.material.io/foundations/accessible-design/accessibility-basics
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Invisible 48×48dp touch area expander — satisfies WCAG 2.5.5 + MD3 spec.
|
|
17
|
+
*
|
|
18
|
+
* Place as a direct child of any interactive element whose visual size is
|
|
19
|
+
* smaller than 48dp (e.g. `xs`/`sm` buttons and icon buttons).
|
|
20
|
+
* The parent element **must** have `position: relative`.
|
|
21
|
+
*
|
|
22
|
+
* @remarks
|
|
23
|
+
* - Hidden from assistive technologies via `aria-hidden="true"`.
|
|
24
|
+
* - `pointer-events: none` ensures it does not intercept click events.
|
|
25
|
+
* - Centred with `left: 50% / top: 50%` + negative translate for symmetry.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```tsx
|
|
29
|
+
* // Used inside a 32dp XS button:
|
|
30
|
+
* <button className="relative h-8 w-auto ...">
|
|
31
|
+
* <TouchTarget />
|
|
32
|
+
* Label
|
|
33
|
+
* </button>
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* @see https://m3.material.io/components/buttons/specs (Touch target section)
|
|
37
|
+
*/
|
|
38
|
+
export declare function TouchTarget(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file snackbar/index.ts
|
|
3
|
+
* Barrel re-export for the MD3 Expressive Snackbar component system.
|
|
4
|
+
*/
|
|
5
|
+
export type { SnackbarData, SnackbarDuration, SnackbarHostProps, SnackbarProps, SnackbarResult, SnackbarVisuals, UseSnackbarStateReturn, } from "./snackbar";
|
|
6
|
+
export { Snackbar, SnackbarHost, SnackbarProvider, useSnackbar, useSnackbarState, } from "./snackbar";
|