@m3-baseui/react-tailwind 4.0.0 → 5.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.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as _base_ui_react from '@base-ui/react';
|
|
2
2
|
import * as react from 'react';
|
|
3
3
|
import * as _m3_baseui_core from '@m3-baseui/core';
|
|
4
|
-
export { IconButtonProps, IconButtonVariant } from '@m3-baseui/core';
|
|
4
|
+
export { IconButtonProps, IconButtonShape, IconButtonSize, IconButtonVariant, IconButtonWidth } from '@m3-baseui/core';
|
|
5
5
|
import * as tailwind_variants from 'tailwind-variants';
|
|
6
6
|
import * as tailwind_variants_dist_config_js from 'tailwind-variants/dist/config.js';
|
|
7
7
|
|
|
@@ -12,9 +12,9 @@ declare const iconButton: tailwind_variants.TVReturnType<{
|
|
|
12
12
|
tonal: string[];
|
|
13
13
|
outlined: string[];
|
|
14
14
|
};
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
toggle: {
|
|
16
|
+
on: string;
|
|
17
|
+
off: string;
|
|
18
18
|
};
|
|
19
19
|
size: {
|
|
20
20
|
xs: string;
|
|
@@ -28,6 +28,10 @@ declare const iconButton: tailwind_variants.TVReturnType<{
|
|
|
28
28
|
default: string;
|
|
29
29
|
wide: string;
|
|
30
30
|
};
|
|
31
|
+
shape: {
|
|
32
|
+
round: string;
|
|
33
|
+
square: string;
|
|
34
|
+
};
|
|
31
35
|
}, undefined, string[], tailwind_variants_dist_config_js.TVConfig<{
|
|
32
36
|
variant: {
|
|
33
37
|
standard: string[];
|
|
@@ -35,9 +39,9 @@ declare const iconButton: tailwind_variants.TVReturnType<{
|
|
|
35
39
|
tonal: string[];
|
|
36
40
|
outlined: string[];
|
|
37
41
|
};
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
toggle: {
|
|
43
|
+
on: string;
|
|
44
|
+
off: string;
|
|
41
45
|
};
|
|
42
46
|
size: {
|
|
43
47
|
xs: string;
|
|
@@ -51,6 +55,10 @@ declare const iconButton: tailwind_variants.TVReturnType<{
|
|
|
51
55
|
default: string;
|
|
52
56
|
wide: string;
|
|
53
57
|
};
|
|
58
|
+
shape: {
|
|
59
|
+
round: string;
|
|
60
|
+
square: string;
|
|
61
|
+
};
|
|
54
62
|
}, {
|
|
55
63
|
variant: {
|
|
56
64
|
standard: string[];
|
|
@@ -58,9 +66,9 @@ declare const iconButton: tailwind_variants.TVReturnType<{
|
|
|
58
66
|
tonal: string[];
|
|
59
67
|
outlined: string[];
|
|
60
68
|
};
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
69
|
+
toggle: {
|
|
70
|
+
on: string;
|
|
71
|
+
off: string;
|
|
64
72
|
};
|
|
65
73
|
size: {
|
|
66
74
|
xs: string;
|
|
@@ -74,6 +82,10 @@ declare const iconButton: tailwind_variants.TVReturnType<{
|
|
|
74
82
|
default: string;
|
|
75
83
|
wide: string;
|
|
76
84
|
};
|
|
85
|
+
shape: {
|
|
86
|
+
round: string;
|
|
87
|
+
square: string;
|
|
88
|
+
};
|
|
77
89
|
}>, {
|
|
78
90
|
variant: {
|
|
79
91
|
standard: string[];
|
|
@@ -81,9 +93,9 @@ declare const iconButton: tailwind_variants.TVReturnType<{
|
|
|
81
93
|
tonal: string[];
|
|
82
94
|
outlined: string[];
|
|
83
95
|
};
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
96
|
+
toggle: {
|
|
97
|
+
on: string;
|
|
98
|
+
off: string;
|
|
87
99
|
};
|
|
88
100
|
size: {
|
|
89
101
|
xs: string;
|
|
@@ -97,6 +109,10 @@ declare const iconButton: tailwind_variants.TVReturnType<{
|
|
|
97
109
|
default: string;
|
|
98
110
|
wide: string;
|
|
99
111
|
};
|
|
112
|
+
shape: {
|
|
113
|
+
round: string;
|
|
114
|
+
square: string;
|
|
115
|
+
};
|
|
100
116
|
}, undefined, tailwind_variants.TVReturnType<{
|
|
101
117
|
variant: {
|
|
102
118
|
standard: string[];
|
|
@@ -104,9 +120,9 @@ declare const iconButton: tailwind_variants.TVReturnType<{
|
|
|
104
120
|
tonal: string[];
|
|
105
121
|
outlined: string[];
|
|
106
122
|
};
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
123
|
+
toggle: {
|
|
124
|
+
on: string;
|
|
125
|
+
off: string;
|
|
110
126
|
};
|
|
111
127
|
size: {
|
|
112
128
|
xs: string;
|
|
@@ -120,6 +136,10 @@ declare const iconButton: tailwind_variants.TVReturnType<{
|
|
|
120
136
|
default: string;
|
|
121
137
|
wide: string;
|
|
122
138
|
};
|
|
139
|
+
shape: {
|
|
140
|
+
round: string;
|
|
141
|
+
square: string;
|
|
142
|
+
};
|
|
123
143
|
}, undefined, string[], tailwind_variants_dist_config_js.TVConfig<{
|
|
124
144
|
variant: {
|
|
125
145
|
standard: string[];
|
|
@@ -127,9 +147,9 @@ declare const iconButton: tailwind_variants.TVReturnType<{
|
|
|
127
147
|
tonal: string[];
|
|
128
148
|
outlined: string[];
|
|
129
149
|
};
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
150
|
+
toggle: {
|
|
151
|
+
on: string;
|
|
152
|
+
off: string;
|
|
133
153
|
};
|
|
134
154
|
size: {
|
|
135
155
|
xs: string;
|
|
@@ -143,6 +163,10 @@ declare const iconButton: tailwind_variants.TVReturnType<{
|
|
|
143
163
|
default: string;
|
|
144
164
|
wide: string;
|
|
145
165
|
};
|
|
166
|
+
shape: {
|
|
167
|
+
round: string;
|
|
168
|
+
square: string;
|
|
169
|
+
};
|
|
146
170
|
}, {
|
|
147
171
|
variant: {
|
|
148
172
|
standard: string[];
|
|
@@ -150,9 +174,9 @@ declare const iconButton: tailwind_variants.TVReturnType<{
|
|
|
150
174
|
tonal: string[];
|
|
151
175
|
outlined: string[];
|
|
152
176
|
};
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
177
|
+
toggle: {
|
|
178
|
+
on: string;
|
|
179
|
+
off: string;
|
|
156
180
|
};
|
|
157
181
|
size: {
|
|
158
182
|
xs: string;
|
|
@@ -166,6 +190,10 @@ declare const iconButton: tailwind_variants.TVReturnType<{
|
|
|
166
190
|
default: string;
|
|
167
191
|
wide: string;
|
|
168
192
|
};
|
|
193
|
+
shape: {
|
|
194
|
+
round: string;
|
|
195
|
+
square: string;
|
|
196
|
+
};
|
|
169
197
|
}>, unknown, unknown, undefined>>;
|
|
170
198
|
declare const IconButton: react.ForwardRefExoticComponent<_m3_baseui_core.IconButtonOwnProps & Omit<react.ButtonHTMLAttributes<HTMLButtonElement>, "color"> & {
|
|
171
199
|
render?: _base_ui_react.useRender.RenderProp;
|
|
@@ -1,6 +1,47 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { createIconButton } from '@m3-baseui/core';
|
|
3
|
-
import { tv } from 'tailwind-variants';
|
|
2
|
+
import { createIconButton, toToggle } from '@m3-baseui/core';
|
|
3
|
+
import { tv as tv$1 } from 'tailwind-variants';
|
|
4
|
+
|
|
5
|
+
// src/components/icon-button/icon-button.ts
|
|
6
|
+
var TYPESCALE = [
|
|
7
|
+
"display-large",
|
|
8
|
+
"display-medium",
|
|
9
|
+
"display-small",
|
|
10
|
+
"headline-large",
|
|
11
|
+
"headline-medium",
|
|
12
|
+
"headline-small",
|
|
13
|
+
"title-large",
|
|
14
|
+
"title-medium",
|
|
15
|
+
"title-small",
|
|
16
|
+
"body-large",
|
|
17
|
+
"body-medium",
|
|
18
|
+
"body-small",
|
|
19
|
+
"label-large",
|
|
20
|
+
"label-medium",
|
|
21
|
+
"label-small"
|
|
22
|
+
];
|
|
23
|
+
var SHAPE = [
|
|
24
|
+
"none",
|
|
25
|
+
"extra-small",
|
|
26
|
+
"small",
|
|
27
|
+
"medium",
|
|
28
|
+
"large",
|
|
29
|
+
"large-increased",
|
|
30
|
+
"extra-large",
|
|
31
|
+
"extra-large-increased",
|
|
32
|
+
"full"
|
|
33
|
+
];
|
|
34
|
+
var tv = (options, config) => tv$1(options, {
|
|
35
|
+
...config,
|
|
36
|
+
twMergeConfig: {
|
|
37
|
+
extend: {
|
|
38
|
+
classGroups: {
|
|
39
|
+
"font-size": [{ text: [...TYPESCALE] }],
|
|
40
|
+
rounded: [{ rounded: [...SHAPE] }]
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
});
|
|
4
45
|
|
|
5
46
|
// src/components/icon-button/icon-button.ts
|
|
6
47
|
var WIDTHS = {
|
|
@@ -22,6 +63,35 @@ var widthCompounds = Object.entries(WIDTHS).flatMap(
|
|
|
22
63
|
class: klass
|
|
23
64
|
}))
|
|
24
65
|
);
|
|
66
|
+
var SQUARE_CORNER = {
|
|
67
|
+
xs: "rounded-medium",
|
|
68
|
+
// 12dp
|
|
69
|
+
s: "rounded-medium",
|
|
70
|
+
// 12dp
|
|
71
|
+
m: "rounded-large",
|
|
72
|
+
// 16dp
|
|
73
|
+
l: "rounded-extra-large",
|
|
74
|
+
// 28dp
|
|
75
|
+
xl: "rounded-extra-large"
|
|
76
|
+
// 28dp
|
|
77
|
+
};
|
|
78
|
+
var squareShapeCompounds = Object.keys(SQUARE_CORNER).map(
|
|
79
|
+
(size) => ({ shape: "square", size, class: SQUARE_CORNER[size] })
|
|
80
|
+
);
|
|
81
|
+
var selectedShapeCompounds = [
|
|
82
|
+
...Object.keys(SQUARE_CORNER).map((size) => ({
|
|
83
|
+
shape: "round",
|
|
84
|
+
toggle: "on",
|
|
85
|
+
size,
|
|
86
|
+
class: SQUARE_CORNER[size]
|
|
87
|
+
})),
|
|
88
|
+
...Object.keys(SQUARE_CORNER).map((size) => ({
|
|
89
|
+
shape: "square",
|
|
90
|
+
toggle: "on",
|
|
91
|
+
size,
|
|
92
|
+
class: "rounded-full"
|
|
93
|
+
}))
|
|
94
|
+
];
|
|
25
95
|
var iconButton = tv({
|
|
26
96
|
base: [
|
|
27
97
|
"relative inline-flex items-center justify-center shrink-0",
|
|
@@ -29,7 +99,9 @@ var iconButton = tv({
|
|
|
29
99
|
// The state layer is already rounded (before:rounded-[inherit]); the ripple
|
|
30
100
|
// self-clips.
|
|
31
101
|
"rounded-full cursor-pointer select-none border-0 bg-transparent",
|
|
32
|
-
|
|
102
|
+
// Motion: Compose uses DefaultEffects (critically-damped spring, no bounce)
|
|
103
|
+
// for the shape/color transitions — spring-effects-default here.
|
|
104
|
+
"transition-[box-shadow,background-color,color,border-color,border-radius] duration-200 ease-spring-effects-default",
|
|
33
105
|
// State layer overlay
|
|
34
106
|
"before:absolute before:inset-0 before:rounded-[inherit] before:bg-current before:opacity-0 before:pointer-events-none",
|
|
35
107
|
"before:transition-opacity before:duration-100",
|
|
@@ -40,14 +112,14 @@ var iconButton = tv({
|
|
|
40
112
|
// Focus ring (M3: 3px secondary, 2px offset)
|
|
41
113
|
"focus-visible:outline-[3px] focus-visible:outline-offset-2 focus-visible:outline-secondary",
|
|
42
114
|
// Disabled: no interaction, no state layer. Per-variant disabled colors
|
|
43
|
-
// (container on-surface/
|
|
115
|
+
// (container on-surface/10, icon on-surface/38) live on each variant.
|
|
44
116
|
"disabled:pointer-events-none disabled:before:opacity-0",
|
|
45
117
|
"data-[disabled]:pointer-events-none data-[disabled]:before:opacity-0"
|
|
46
118
|
],
|
|
47
119
|
variants: {
|
|
48
120
|
// Disabled icon is on-surface/38 for every variant; filled/tonal disabled
|
|
49
|
-
// container is on-surface/
|
|
50
|
-
//
|
|
121
|
+
// container is on-surface/10 (DisabledContainerOpacity); outlined disabled
|
|
122
|
+
// outline stays outline-variant (Expressive DisabledOutlineColor).
|
|
51
123
|
variant: {
|
|
52
124
|
standard: [
|
|
53
125
|
"text-on-surface-variant",
|
|
@@ -55,68 +127,93 @@ var iconButton = tv({
|
|
|
55
127
|
],
|
|
56
128
|
filled: [
|
|
57
129
|
"bg-primary text-on-primary",
|
|
58
|
-
"disabled:bg-on-surface/
|
|
59
|
-
"data-[disabled]:bg-on-surface/
|
|
130
|
+
"disabled:bg-on-surface/10 disabled:text-on-surface/38",
|
|
131
|
+
"data-[disabled]:bg-on-surface/10 data-[disabled]:text-on-surface/38"
|
|
60
132
|
],
|
|
61
133
|
tonal: [
|
|
62
134
|
"bg-secondary-container text-on-secondary-container",
|
|
63
|
-
"disabled:bg-on-surface/
|
|
64
|
-
"data-[disabled]:bg-on-surface/
|
|
135
|
+
"disabled:bg-on-surface/10 disabled:text-on-surface/38",
|
|
136
|
+
"data-[disabled]:bg-on-surface/10 data-[disabled]:text-on-surface/38"
|
|
65
137
|
],
|
|
66
138
|
outlined: [
|
|
67
|
-
"border border-outline text-on-surface-variant",
|
|
68
|
-
"disabled:border-
|
|
69
|
-
"data-[disabled]:border-
|
|
139
|
+
"border border-outline-variant text-on-surface-variant",
|
|
140
|
+
"disabled:border-outline-variant disabled:text-on-surface/38",
|
|
141
|
+
"data-[disabled]:border-outline-variant data-[disabled]:text-on-surface/38"
|
|
70
142
|
]
|
|
71
143
|
},
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
144
|
+
// Toggle state, string-keyed so a plain (non-toggle) button — `toggle`
|
|
145
|
+
// unset — fires neither compound below (a boolean variant would default to
|
|
146
|
+
// `off` in tailwind-variants and wrongly apply the unselected look).
|
|
147
|
+
toggle: {
|
|
148
|
+
on: "",
|
|
149
|
+
off: ""
|
|
75
150
|
},
|
|
76
151
|
// Container height + icon size per M3 Expressive size. Width comes from the
|
|
77
|
-
// (size, width) compound variants below.
|
|
152
|
+
// (size, width) compound variants below. The pressed corner morph
|
|
153
|
+
// (PressedContainerShape: XS·S small 8 / M medium 12 / L·XL large 16) rides
|
|
154
|
+
// on data-[pressed]/active so its attribute-selector specificity wins over
|
|
155
|
+
// the resting `rounded-*`.
|
|
78
156
|
size: {
|
|
79
|
-
xs: "h-8 [&>svg]:size-5",
|
|
80
|
-
s: "h-10 [&>svg]:size-6",
|
|
81
|
-
m: "h-14 [&>svg]:size-6",
|
|
82
|
-
l: "h-24 [&>svg]:size-8",
|
|
83
|
-
xl: "h-[136px] [&>svg]:size-10"
|
|
157
|
+
xs: "h-8 [&>svg]:size-5 data-[pressed]:rounded-small active:rounded-small",
|
|
158
|
+
s: "h-10 [&>svg]:size-6 data-[pressed]:rounded-small active:rounded-small",
|
|
159
|
+
m: "h-14 [&>svg]:size-6 data-[pressed]:rounded-medium active:rounded-medium",
|
|
160
|
+
l: "h-24 [&>svg]:size-8 data-[pressed]:rounded-large active:rounded-large",
|
|
161
|
+
xl: "h-[136px] [&>svg]:size-10 data-[pressed]:rounded-large active:rounded-large"
|
|
84
162
|
},
|
|
85
163
|
width: {
|
|
86
164
|
narrow: "",
|
|
87
165
|
default: "",
|
|
88
166
|
wide: ""
|
|
167
|
+
},
|
|
168
|
+
// round = full circle; the square corner is size-specific (compounds below).
|
|
169
|
+
shape: {
|
|
170
|
+
round: "rounded-full",
|
|
171
|
+
square: ""
|
|
89
172
|
}
|
|
90
173
|
},
|
|
91
174
|
compoundVariants: [
|
|
92
175
|
...widthCompounds,
|
|
93
|
-
|
|
94
|
-
|
|
176
|
+
...squareShapeCompounds,
|
|
177
|
+
...selectedShapeCompounds,
|
|
178
|
+
// ---- Outlined border width (OutlinedOutlineWidth: L 2 / XL 3 dp) ------
|
|
179
|
+
{ variant: "outlined", size: "l", class: "border-2" },
|
|
180
|
+
{ variant: "outlined", size: "xl", class: "border-[3px]" },
|
|
181
|
+
// ---- Toggle colors (Selected*/Unselected* tokens) ---------------------
|
|
182
|
+
// standard: unselected = on-surface-variant (base); selected = primary.
|
|
183
|
+
{ variant: "standard", toggle: "on", class: "text-primary" },
|
|
184
|
+
// filled: base = default & selected look (primary/on-primary); unselected =
|
|
185
|
+
// surface-container + on-surface-variant (was surface-container-highest+primary).
|
|
95
186
|
{
|
|
96
|
-
variant: "
|
|
97
|
-
|
|
98
|
-
class: "bg-surface-container
|
|
187
|
+
variant: "filled",
|
|
188
|
+
toggle: "off",
|
|
189
|
+
class: "bg-surface-container text-on-surface-variant"
|
|
99
190
|
},
|
|
191
|
+
// tonal: base = default & unselected look (secondary-container); selected =
|
|
192
|
+
// secondary + on-secondary (was left at the variant default — the "selection
|
|
193
|
+
// not visible" bug this issue fixes).
|
|
194
|
+
{ variant: "tonal", toggle: "on", class: "bg-secondary text-on-secondary" },
|
|
195
|
+
// outlined: selected fills with the inverse surface (base = unselected).
|
|
100
196
|
{
|
|
101
197
|
variant: "outlined",
|
|
102
|
-
|
|
198
|
+
toggle: "on",
|
|
103
199
|
class: [
|
|
104
200
|
"bg-inverse-surface text-inverse-on-surface border-transparent",
|
|
105
|
-
// M3 disabled + selected: faint on-surface/
|
|
201
|
+
// M3 disabled + selected: faint on-surface/10 container, no outline
|
|
106
202
|
// (icon falls back to on-surface/38 from the variant). NOT transparent.
|
|
107
|
-
"disabled:bg-on-surface/
|
|
108
|
-
"data-[disabled]:bg-on-surface/
|
|
203
|
+
"disabled:bg-on-surface/10 disabled:border-transparent",
|
|
204
|
+
"data-[disabled]:bg-on-surface/10 data-[disabled]:border-transparent"
|
|
109
205
|
]
|
|
110
206
|
}
|
|
111
207
|
],
|
|
112
208
|
defaultVariants: {
|
|
113
209
|
variant: "standard",
|
|
114
210
|
size: "s",
|
|
115
|
-
width: "default"
|
|
211
|
+
width: "default",
|
|
212
|
+
shape: "round"
|
|
116
213
|
}
|
|
117
214
|
});
|
|
118
215
|
var IconButton = createIconButton(
|
|
119
|
-
({ variant, selected, size, width }) => iconButton({ variant,
|
|
216
|
+
({ variant, selected, size, width, shape }) => iconButton({ variant, size, width, shape, toggle: toToggle(selected) })
|
|
120
217
|
);
|
|
121
218
|
|
|
122
219
|
export { IconButton, iconButton };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/icon-button/icon-button.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * icon-button.ts — tailwind-variants resolver for the M3 Icon Button.\n *\n * 40×40 circular target with a centered icon. The `selected` variant supports\n * toggle icon buttons; when `selected` is undefined the variant's default\n * (filled/active) look is used. Emits the same DOM + ripple as the VE build.\n */\nimport { createIconButton } from '@m3-baseui/core';\nimport { tv } from 'tailwind-variants';\n\n// M3 Expressive container widths (px) per size × width. Tailwind v4's dynamic\n// spacing scale resolves any integer (e.g. w-13 = 52px, w-46 = 184px).\nconst WIDTHS = {\n xs: { narrow: 'w-7', default: 'w-8', wide: 'w-10' }, // 28 / 32 / 40\n s: { narrow: 'w-8', default: 'w-10', wide: 'w-13' }, // 32 / 40 / 52\n m: { narrow: 'w-12', default: 'w-14', wide: 'w-18' }, // 48 / 56 / 72\n l: { narrow: 'w-16', default: 'w-24', wide: 'w-32' }, // 64 / 96 / 128\n xl: { narrow: 'w-26', default: 'w-34', wide: 'w-46' }, // 104 / 136 / 184\n} as const;\n\nconst widthCompounds = Object.entries(WIDTHS).flatMap(([size, w]) =>\n Object.entries(w).map(([width, klass]) => ({\n size: size as keyof typeof WIDTHS,\n width: width as 'narrow' | 'default' | 'wide',\n class: klass,\n })),\n);\n\nexport const iconButton = tv({\n base: [\n 'relative inline-flex items-center justify-center shrink-0',\n // No `overflow-hidden`: it would clip the 48dp touch target on small sizes.\n // The state layer is already rounded (before:rounded-[inherit]); the ripple\n // self-clips.\n 'rounded-full cursor-pointer select-none border-0 bg-transparent',\n 'transition-[box-shadow,background-color,color] duration-200 ease-standard',\n // State layer overlay\n 'before:absolute before:inset-0 before:rounded-[inherit] before:bg-current before:opacity-0 before:pointer-events-none',\n 'before:transition-opacity before:duration-100',\n 'hover:before:opacity-[var(--md-sys-state-hover)]',\n 'focus-visible:before:opacity-[var(--md-sys-state-focus)]',\n 'active:before:opacity-[var(--md-sys-state-pressed)]',\n 'data-[pressed]:before:opacity-[var(--md-sys-state-pressed)]',\n // Focus ring (M3: 3px secondary, 2px offset)\n 'focus-visible:outline-[3px] focus-visible:outline-offset-2 focus-visible:outline-secondary',\n // Disabled: no interaction, no state layer. Per-variant disabled colors\n // (container on-surface/12, icon on-surface/38) live on each variant.\n 'disabled:pointer-events-none disabled:before:opacity-0',\n 'data-[disabled]:pointer-events-none data-[disabled]:before:opacity-0',\n ],\n variants: {\n // Disabled icon is on-surface/38 for every variant; filled/tonal disabled\n // container is on-surface/12; outlined disabled outline is on-surface/12\n // (material-web parity).\n variant: {\n standard: [\n 'text-on-surface-variant',\n 'disabled:text-on-surface/38 data-[disabled]:text-on-surface/38',\n ],\n filled: [\n 'bg-primary text-on-primary',\n 'disabled:bg-on-surface/12 disabled:text-on-surface/38',\n 'data-[disabled]:bg-on-surface/12 data-[disabled]:text-on-surface/38',\n ],\n tonal: [\n 'bg-secondary-container text-on-secondary-container',\n 'disabled:bg-on-surface/12 disabled:text-on-surface/38',\n 'data-[disabled]:bg-on-surface/12 data-[disabled]:text-on-surface/38',\n ],\n outlined: [\n 'border border-outline text-on-surface-variant',\n 'disabled:border-on-surface/12 disabled:text-on-surface/38',\n 'data-[disabled]:border-on-surface/12 data-[disabled]:text-on-surface/38',\n ],\n },\n selected: {\n true: '',\n false: '',\n },\n // Container height + icon size per M3 Expressive size. Width comes from the\n // (size, width) compound variants below.\n size: {\n xs: 'h-8 [&>svg]:size-5',\n s: 'h-10 [&>svg]:size-6',\n m: 'h-14 [&>svg]:size-6',\n l: 'h-24 [&>svg]:size-8',\n xl: 'h-[136px] [&>svg]:size-10',\n },\n width: {\n narrow: '',\n default: '',\n wide: '',\n },\n },\n compoundVariants: [\n ...widthCompounds,\n { variant: 'standard', selected: true, class: 'text-primary' },\n { variant: 'filled', selected: false, class: 'bg-surface-container-highest text-primary' },\n {\n variant: 'tonal',\n selected: false,\n class: 'bg-surface-container-highest text-on-surface-variant',\n },\n {\n variant: 'outlined',\n selected: true,\n class: [\n 'bg-inverse-surface text-inverse-on-surface border-transparent',\n // M3 disabled + selected: faint on-surface/12 container, no outline\n // (icon falls back to on-surface/38 from the variant). NOT transparent.\n 'disabled:bg-on-surface/12 disabled:border-transparent',\n 'data-[disabled]:bg-on-surface/12 data-[disabled]:border-transparent',\n ],\n },\n ],\n defaultVariants: {\n variant: 'standard',\n size: 's',\n width: 'default',\n },\n});\n\nexport const IconButton = createIconButton(({ variant, selected, size, width }) =>\n iconButton({ variant, selected, size, width }),\n);\nexport type { IconButtonProps, IconButtonVariant } from '@m3-baseui/core';\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/tv.ts","../../../src/components/icon-button/icon-button.ts"],"names":["baseTv"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * tv.ts — a tailwind-variants factory pre-configured for the M3 typescale and\n * shape scale.\n *\n * The Tailwind v4 preset exposes the 15 typescale roles as `text-<role>`\n * font-size utilities (e.g. `text-body-small`, `text-label-large`) and the\n * shape scale as `rounded-<role>` border-radius utilities (e.g. `rounded-small`,\n * `rounded-extra-large`). Stock tailwind-merge does not know these custom names,\n * so it (a) groups the typescale names with `text-<color>` and drops one when a\n * slot sets both a color *and* a typescale, and (b) fails to see two custom\n * `rounded-<role>` classes as conflicting, so a later corner override never\n * dedupes the resting one (both survive, and CSS source order — not intent —\n * decides). Either way token compliance / shape morph silently breaks.\n *\n * Teaching tailwind-merge that the typescale names belong to `font-size` and the\n * shape names belong to `rounded` keeps color and type independent and makes the\n * corner utilities override one another as expected.\n */\nimport { type TV, tv as baseTv } from 'tailwind-variants';\n\nconst TYPESCALE = [\n 'display-large',\n 'display-medium',\n 'display-small',\n 'headline-large',\n 'headline-medium',\n 'headline-small',\n 'title-large',\n 'title-medium',\n 'title-small',\n 'body-large',\n 'body-medium',\n 'body-small',\n 'label-large',\n 'label-medium',\n 'label-small',\n] as const;\n\n// M3 shape scale exposed as `rounded-<role>` (see @m3-baseui/tokens theme.css\n// `--radius-*`). `none` / `full` overlap stock Tailwind and are harmless to\n// re-list; the intermediate roles are what stock tailwind-merge misses.\nconst SHAPE = [\n 'none',\n 'extra-small',\n 'small',\n 'medium',\n 'large',\n 'large-increased',\n 'extra-large',\n 'extra-large-increased',\n 'full',\n] as const;\n\nexport const tv: TV = (options, config) =>\n baseTv(options, {\n ...config,\n twMergeConfig: {\n extend: {\n classGroups: {\n 'font-size': [{ text: [...TYPESCALE] }],\n rounded: [{ rounded: [...SHAPE] }],\n },\n },\n },\n });\n","/**\n * icon-button.ts — tailwind-variants resolver for the M3 (Expressive) Icon Button.\n *\n * Emits the same DOM + `data-*` state as the vanilla-extract build (drop-in\n * compatible); only the class strings differ. The `rounded-<role>` corner\n * utilities come from the Tailwind v4 `@theme` preset in\n * `@m3-baseui/tokens/theme.css`; the configured `tv` helper teaches\n * tailwind-merge to dedupe them so a morph override drops the resting corner.\n *\n * M3 Expressive: five sizes (XS 32 → XL 136 dp) drive height / icon size and\n * (with `width`) the container width; `shape` picks the resting corner\n * (round=full circle vs a size-specific square), the corner morphs smaller on\n * press, and toggle buttons (`selected`) swap to the opposite shape\n * (round↔square) plus the Selected/Unselected color set.\n */\nimport { createIconButton, toToggle } from '@m3-baseui/core';\nimport { tv } from '../../tv';\n\n// M3 Expressive container widths (px) per size × width. Tailwind v4's dynamic\n// spacing scale resolves any integer (e.g. w-13 = 52px, w-46 = 184px).\nconst WIDTHS = {\n xs: { narrow: 'w-7', default: 'w-8', wide: 'w-10' }, // 28 / 32 / 40\n s: { narrow: 'w-8', default: 'w-10', wide: 'w-13' }, // 32 / 40 / 52\n m: { narrow: 'w-12', default: 'w-14', wide: 'w-18' }, // 48 / 56 / 72\n l: { narrow: 'w-16', default: 'w-24', wide: 'w-32' }, // 64 / 96 / 128\n xl: { narrow: 'w-26', default: 'w-34', wide: 'w-46' }, // 104 / 136 / 184\n} as const;\n\nconst widthCompounds = Object.entries(WIDTHS).flatMap(([size, w]) =>\n Object.entries(w).map(([width, klass]) => ({\n size: size as keyof typeof WIDTHS,\n width: width as 'narrow' | 'default' | 'wide',\n class: klass,\n })),\n);\n\n// Resting square corner (ContainerShapeSquare) per size bucket.\nconst SQUARE_CORNER = {\n xs: 'rounded-medium', // 12dp\n s: 'rounded-medium', // 12dp\n m: 'rounded-large', // 16dp\n l: 'rounded-extra-large', // 28dp\n xl: 'rounded-extra-large', // 28dp\n} as const;\n\n// Resting square corner: `shape: square` maps to the size-specific corner.\nconst squareShapeCompounds = (Object.keys(SQUARE_CORNER) as (keyof typeof SQUARE_CORNER)[]).map(\n (size) => ({ shape: 'square' as const, size, class: SQUARE_CORNER[size] }),\n);\n\n// Selected shape morph (Expressive's signature behavior). Listed after the\n// resting corner so tailwind-merge keeps these: a selected `round` container\n// morphs to the square corner; a selected `square` container morphs to `full`.\nconst selectedShapeCompounds = [\n ...(Object.keys(SQUARE_CORNER) as (keyof typeof SQUARE_CORNER)[]).map((size) => ({\n shape: 'round' as const,\n toggle: 'on' as const,\n size,\n class: SQUARE_CORNER[size],\n })),\n ...(Object.keys(SQUARE_CORNER) as (keyof typeof SQUARE_CORNER)[]).map((size) => ({\n shape: 'square' as const,\n toggle: 'on' as const,\n size,\n class: 'rounded-full',\n })),\n];\n\nexport const iconButton = tv({\n base: [\n 'relative inline-flex items-center justify-center shrink-0',\n // No `overflow-hidden`: it would clip the 48dp touch target on small sizes.\n // The state layer is already rounded (before:rounded-[inherit]); the ripple\n // self-clips.\n 'rounded-full cursor-pointer select-none border-0 bg-transparent',\n // Motion: Compose uses DefaultEffects (critically-damped spring, no bounce)\n // for the shape/color transitions — spring-effects-default here.\n 'transition-[box-shadow,background-color,color,border-color,border-radius] duration-200 ease-spring-effects-default',\n // State layer overlay\n 'before:absolute before:inset-0 before:rounded-[inherit] before:bg-current before:opacity-0 before:pointer-events-none',\n 'before:transition-opacity before:duration-100',\n 'hover:before:opacity-[var(--md-sys-state-hover)]',\n 'focus-visible:before:opacity-[var(--md-sys-state-focus)]',\n 'active:before:opacity-[var(--md-sys-state-pressed)]',\n 'data-[pressed]:before:opacity-[var(--md-sys-state-pressed)]',\n // Focus ring (M3: 3px secondary, 2px offset)\n 'focus-visible:outline-[3px] focus-visible:outline-offset-2 focus-visible:outline-secondary',\n // Disabled: no interaction, no state layer. Per-variant disabled colors\n // (container on-surface/10, icon on-surface/38) live on each variant.\n 'disabled:pointer-events-none disabled:before:opacity-0',\n 'data-[disabled]:pointer-events-none data-[disabled]:before:opacity-0',\n ],\n variants: {\n // Disabled icon is on-surface/38 for every variant; filled/tonal disabled\n // container is on-surface/10 (DisabledContainerOpacity); outlined disabled\n // outline stays outline-variant (Expressive DisabledOutlineColor).\n variant: {\n standard: [\n 'text-on-surface-variant',\n 'disabled:text-on-surface/38 data-[disabled]:text-on-surface/38',\n ],\n filled: [\n 'bg-primary text-on-primary',\n 'disabled:bg-on-surface/10 disabled:text-on-surface/38',\n 'data-[disabled]:bg-on-surface/10 data-[disabled]:text-on-surface/38',\n ],\n tonal: [\n 'bg-secondary-container text-on-secondary-container',\n 'disabled:bg-on-surface/10 disabled:text-on-surface/38',\n 'data-[disabled]:bg-on-surface/10 data-[disabled]:text-on-surface/38',\n ],\n outlined: [\n 'border border-outline-variant text-on-surface-variant',\n 'disabled:border-outline-variant disabled:text-on-surface/38',\n 'data-[disabled]:border-outline-variant data-[disabled]:text-on-surface/38',\n ],\n },\n // Toggle state, string-keyed so a plain (non-toggle) button — `toggle`\n // unset — fires neither compound below (a boolean variant would default to\n // `off` in tailwind-variants and wrongly apply the unselected look).\n toggle: {\n on: '',\n off: '',\n },\n // Container height + icon size per M3 Expressive size. Width comes from the\n // (size, width) compound variants below. The pressed corner morph\n // (PressedContainerShape: XS·S small 8 / M medium 12 / L·XL large 16) rides\n // on data-[pressed]/active so its attribute-selector specificity wins over\n // the resting `rounded-*`.\n size: {\n xs: 'h-8 [&>svg]:size-5 data-[pressed]:rounded-small active:rounded-small',\n s: 'h-10 [&>svg]:size-6 data-[pressed]:rounded-small active:rounded-small',\n m: 'h-14 [&>svg]:size-6 data-[pressed]:rounded-medium active:rounded-medium',\n l: 'h-24 [&>svg]:size-8 data-[pressed]:rounded-large active:rounded-large',\n xl: 'h-[136px] [&>svg]:size-10 data-[pressed]:rounded-large active:rounded-large',\n },\n width: {\n narrow: '',\n default: '',\n wide: '',\n },\n // round = full circle; the square corner is size-specific (compounds below).\n shape: {\n round: 'rounded-full',\n square: '',\n },\n },\n compoundVariants: [\n ...widthCompounds,\n ...squareShapeCompounds,\n ...selectedShapeCompounds,\n // ---- Outlined border width (OutlinedOutlineWidth: L 2 / XL 3 dp) ------\n { variant: 'outlined', size: 'l', class: 'border-2' },\n { variant: 'outlined', size: 'xl', class: 'border-[3px]' },\n // ---- Toggle colors (Selected*/Unselected* tokens) ---------------------\n // standard: unselected = on-surface-variant (base); selected = primary.\n { variant: 'standard', toggle: 'on', class: 'text-primary' },\n // filled: base = default & selected look (primary/on-primary); unselected =\n // surface-container + on-surface-variant (was surface-container-highest+primary).\n {\n variant: 'filled',\n toggle: 'off',\n class: 'bg-surface-container text-on-surface-variant',\n },\n // tonal: base = default & unselected look (secondary-container); selected =\n // secondary + on-secondary (was left at the variant default — the \"selection\n // not visible\" bug this issue fixes).\n { variant: 'tonal', toggle: 'on', class: 'bg-secondary text-on-secondary' },\n // outlined: selected fills with the inverse surface (base = unselected).\n {\n variant: 'outlined',\n toggle: 'on',\n class: [\n 'bg-inverse-surface text-inverse-on-surface border-transparent',\n // M3 disabled + selected: faint on-surface/10 container, no outline\n // (icon falls back to on-surface/38 from the variant). NOT transparent.\n 'disabled:bg-on-surface/10 disabled:border-transparent',\n 'data-[disabled]:bg-on-surface/10 data-[disabled]:border-transparent',\n ],\n },\n ],\n defaultVariants: {\n variant: 'standard',\n size: 's',\n width: 'default',\n shape: 'round',\n },\n});\n\nexport const IconButton = createIconButton(({ variant, selected, size, width, shape }) =>\n iconButton({ variant, size, width, shape, toggle: toToggle(selected) }),\n);\nexport type {\n IconButtonProps,\n IconButtonVariant,\n IconButtonSize,\n IconButtonWidth,\n IconButtonShape,\n} from '@m3-baseui/core';\n"]}
|
package/dist/index.js
CHANGED
|
@@ -231,14 +231,45 @@ var widthCompounds = Object.entries(WIDTHS).flatMap(
|
|
|
231
231
|
class: klass
|
|
232
232
|
}))
|
|
233
233
|
);
|
|
234
|
-
var
|
|
234
|
+
var SQUARE_CORNER = {
|
|
235
|
+
xs: "rounded-medium",
|
|
236
|
+
// 12dp
|
|
237
|
+
s: "rounded-medium",
|
|
238
|
+
// 12dp
|
|
239
|
+
m: "rounded-large",
|
|
240
|
+
// 16dp
|
|
241
|
+
l: "rounded-extra-large",
|
|
242
|
+
// 28dp
|
|
243
|
+
xl: "rounded-extra-large"
|
|
244
|
+
// 28dp
|
|
245
|
+
};
|
|
246
|
+
var squareShapeCompounds = Object.keys(SQUARE_CORNER).map(
|
|
247
|
+
(size) => ({ shape: "square", size, class: SQUARE_CORNER[size] })
|
|
248
|
+
);
|
|
249
|
+
var selectedShapeCompounds = [
|
|
250
|
+
...Object.keys(SQUARE_CORNER).map((size) => ({
|
|
251
|
+
shape: "round",
|
|
252
|
+
toggle: "on",
|
|
253
|
+
size,
|
|
254
|
+
class: SQUARE_CORNER[size]
|
|
255
|
+
})),
|
|
256
|
+
...Object.keys(SQUARE_CORNER).map((size) => ({
|
|
257
|
+
shape: "square",
|
|
258
|
+
toggle: "on",
|
|
259
|
+
size,
|
|
260
|
+
class: "rounded-full"
|
|
261
|
+
}))
|
|
262
|
+
];
|
|
263
|
+
var iconButton = tv({
|
|
235
264
|
base: [
|
|
236
265
|
"relative inline-flex items-center justify-center shrink-0",
|
|
237
266
|
// No `overflow-hidden`: it would clip the 48dp touch target on small sizes.
|
|
238
267
|
// The state layer is already rounded (before:rounded-[inherit]); the ripple
|
|
239
268
|
// self-clips.
|
|
240
269
|
"rounded-full cursor-pointer select-none border-0 bg-transparent",
|
|
241
|
-
|
|
270
|
+
// Motion: Compose uses DefaultEffects (critically-damped spring, no bounce)
|
|
271
|
+
// for the shape/color transitions — spring-effects-default here.
|
|
272
|
+
"transition-[box-shadow,background-color,color,border-color,border-radius] duration-200 ease-spring-effects-default",
|
|
242
273
|
// State layer overlay
|
|
243
274
|
"before:absolute before:inset-0 before:rounded-[inherit] before:bg-current before:opacity-0 before:pointer-events-none",
|
|
244
275
|
"before:transition-opacity before:duration-100",
|
|
@@ -249,14 +280,14 @@ var iconButton = tv$1({
|
|
|
249
280
|
// Focus ring (M3: 3px secondary, 2px offset)
|
|
250
281
|
"focus-visible:outline-[3px] focus-visible:outline-offset-2 focus-visible:outline-secondary",
|
|
251
282
|
// Disabled: no interaction, no state layer. Per-variant disabled colors
|
|
252
|
-
// (container on-surface/
|
|
283
|
+
// (container on-surface/10, icon on-surface/38) live on each variant.
|
|
253
284
|
"disabled:pointer-events-none disabled:before:opacity-0",
|
|
254
285
|
"data-[disabled]:pointer-events-none data-[disabled]:before:opacity-0"
|
|
255
286
|
],
|
|
256
287
|
variants: {
|
|
257
288
|
// Disabled icon is on-surface/38 for every variant; filled/tonal disabled
|
|
258
|
-
// container is on-surface/
|
|
259
|
-
//
|
|
289
|
+
// container is on-surface/10 (DisabledContainerOpacity); outlined disabled
|
|
290
|
+
// outline stays outline-variant (Expressive DisabledOutlineColor).
|
|
260
291
|
variant: {
|
|
261
292
|
standard: [
|
|
262
293
|
"text-on-surface-variant",
|
|
@@ -264,68 +295,93 @@ var iconButton = tv$1({
|
|
|
264
295
|
],
|
|
265
296
|
filled: [
|
|
266
297
|
"bg-primary text-on-primary",
|
|
267
|
-
"disabled:bg-on-surface/
|
|
268
|
-
"data-[disabled]:bg-on-surface/
|
|
298
|
+
"disabled:bg-on-surface/10 disabled:text-on-surface/38",
|
|
299
|
+
"data-[disabled]:bg-on-surface/10 data-[disabled]:text-on-surface/38"
|
|
269
300
|
],
|
|
270
301
|
tonal: [
|
|
271
302
|
"bg-secondary-container text-on-secondary-container",
|
|
272
|
-
"disabled:bg-on-surface/
|
|
273
|
-
"data-[disabled]:bg-on-surface/
|
|
303
|
+
"disabled:bg-on-surface/10 disabled:text-on-surface/38",
|
|
304
|
+
"data-[disabled]:bg-on-surface/10 data-[disabled]:text-on-surface/38"
|
|
274
305
|
],
|
|
275
306
|
outlined: [
|
|
276
|
-
"border border-outline text-on-surface-variant",
|
|
277
|
-
"disabled:border-
|
|
278
|
-
"data-[disabled]:border-
|
|
307
|
+
"border border-outline-variant text-on-surface-variant",
|
|
308
|
+
"disabled:border-outline-variant disabled:text-on-surface/38",
|
|
309
|
+
"data-[disabled]:border-outline-variant data-[disabled]:text-on-surface/38"
|
|
279
310
|
]
|
|
280
311
|
},
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
312
|
+
// Toggle state, string-keyed so a plain (non-toggle) button — `toggle`
|
|
313
|
+
// unset — fires neither compound below (a boolean variant would default to
|
|
314
|
+
// `off` in tailwind-variants and wrongly apply the unselected look).
|
|
315
|
+
toggle: {
|
|
316
|
+
on: "",
|
|
317
|
+
off: ""
|
|
284
318
|
},
|
|
285
319
|
// Container height + icon size per M3 Expressive size. Width comes from the
|
|
286
|
-
// (size, width) compound variants below.
|
|
320
|
+
// (size, width) compound variants below. The pressed corner morph
|
|
321
|
+
// (PressedContainerShape: XS·S small 8 / M medium 12 / L·XL large 16) rides
|
|
322
|
+
// on data-[pressed]/active so its attribute-selector specificity wins over
|
|
323
|
+
// the resting `rounded-*`.
|
|
287
324
|
size: {
|
|
288
|
-
xs: "h-8 [&>svg]:size-5",
|
|
289
|
-
s: "h-10 [&>svg]:size-6",
|
|
290
|
-
m: "h-14 [&>svg]:size-6",
|
|
291
|
-
l: "h-24 [&>svg]:size-8",
|
|
292
|
-
xl: "h-[136px] [&>svg]:size-10"
|
|
325
|
+
xs: "h-8 [&>svg]:size-5 data-[pressed]:rounded-small active:rounded-small",
|
|
326
|
+
s: "h-10 [&>svg]:size-6 data-[pressed]:rounded-small active:rounded-small",
|
|
327
|
+
m: "h-14 [&>svg]:size-6 data-[pressed]:rounded-medium active:rounded-medium",
|
|
328
|
+
l: "h-24 [&>svg]:size-8 data-[pressed]:rounded-large active:rounded-large",
|
|
329
|
+
xl: "h-[136px] [&>svg]:size-10 data-[pressed]:rounded-large active:rounded-large"
|
|
293
330
|
},
|
|
294
331
|
width: {
|
|
295
332
|
narrow: "",
|
|
296
333
|
default: "",
|
|
297
334
|
wide: ""
|
|
335
|
+
},
|
|
336
|
+
// round = full circle; the square corner is size-specific (compounds below).
|
|
337
|
+
shape: {
|
|
338
|
+
round: "rounded-full",
|
|
339
|
+
square: ""
|
|
298
340
|
}
|
|
299
341
|
},
|
|
300
342
|
compoundVariants: [
|
|
301
343
|
...widthCompounds,
|
|
302
|
-
|
|
303
|
-
|
|
344
|
+
...squareShapeCompounds,
|
|
345
|
+
...selectedShapeCompounds,
|
|
346
|
+
// ---- Outlined border width (OutlinedOutlineWidth: L 2 / XL 3 dp) ------
|
|
347
|
+
{ variant: "outlined", size: "l", class: "border-2" },
|
|
348
|
+
{ variant: "outlined", size: "xl", class: "border-[3px]" },
|
|
349
|
+
// ---- Toggle colors (Selected*/Unselected* tokens) ---------------------
|
|
350
|
+
// standard: unselected = on-surface-variant (base); selected = primary.
|
|
351
|
+
{ variant: "standard", toggle: "on", class: "text-primary" },
|
|
352
|
+
// filled: base = default & selected look (primary/on-primary); unselected =
|
|
353
|
+
// surface-container + on-surface-variant (was surface-container-highest+primary).
|
|
304
354
|
{
|
|
305
|
-
variant: "
|
|
306
|
-
|
|
307
|
-
class: "bg-surface-container
|
|
355
|
+
variant: "filled",
|
|
356
|
+
toggle: "off",
|
|
357
|
+
class: "bg-surface-container text-on-surface-variant"
|
|
308
358
|
},
|
|
359
|
+
// tonal: base = default & unselected look (secondary-container); selected =
|
|
360
|
+
// secondary + on-secondary (was left at the variant default — the "selection
|
|
361
|
+
// not visible" bug this issue fixes).
|
|
362
|
+
{ variant: "tonal", toggle: "on", class: "bg-secondary text-on-secondary" },
|
|
363
|
+
// outlined: selected fills with the inverse surface (base = unselected).
|
|
309
364
|
{
|
|
310
365
|
variant: "outlined",
|
|
311
|
-
|
|
366
|
+
toggle: "on",
|
|
312
367
|
class: [
|
|
313
368
|
"bg-inverse-surface text-inverse-on-surface border-transparent",
|
|
314
|
-
// M3 disabled + selected: faint on-surface/
|
|
369
|
+
// M3 disabled + selected: faint on-surface/10 container, no outline
|
|
315
370
|
// (icon falls back to on-surface/38 from the variant). NOT transparent.
|
|
316
|
-
"disabled:bg-on-surface/
|
|
317
|
-
"data-[disabled]:bg-on-surface/
|
|
371
|
+
"disabled:bg-on-surface/10 disabled:border-transparent",
|
|
372
|
+
"data-[disabled]:bg-on-surface/10 data-[disabled]:border-transparent"
|
|
318
373
|
]
|
|
319
374
|
}
|
|
320
375
|
],
|
|
321
376
|
defaultVariants: {
|
|
322
377
|
variant: "standard",
|
|
323
378
|
size: "s",
|
|
324
|
-
width: "default"
|
|
379
|
+
width: "default",
|
|
380
|
+
shape: "round"
|
|
325
381
|
}
|
|
326
382
|
});
|
|
327
383
|
var IconButton = createIconButton(
|
|
328
|
-
({ variant, selected, size, width }) => iconButton({ variant,
|
|
384
|
+
({ variant, selected, size, width, shape }) => iconButton({ variant, size, width, shape, toggle: toToggle(selected) })
|
|
329
385
|
);
|
|
330
386
|
var switchTv = tv$1({
|
|
331
387
|
slots: {
|