@tinybigui/react 0.4.2 → 0.6.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/dist/index.cjs +682 -365
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +324 -181
- package/dist/index.d.ts +324 -181
- package/dist/index.js +682 -365
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1118,81 +1118,113 @@ var IconButtonHeadless = React.forwardRef(
|
|
|
1118
1118
|
tabIndex = 0,
|
|
1119
1119
|
onMouseDown,
|
|
1120
1120
|
type,
|
|
1121
|
-
|
|
1121
|
+
isSelected,
|
|
1122
|
+
isToggle = false,
|
|
1123
|
+
isDisabled = false,
|
|
1122
1124
|
"aria-label": ariaLabel,
|
|
1123
1125
|
title,
|
|
1124
1126
|
...props
|
|
1125
1127
|
}, forwardedRef) => {
|
|
1126
1128
|
const internalRef = React.useRef(null);
|
|
1127
1129
|
const ref = forwardedRef ?? internalRef;
|
|
1128
|
-
const { buttonProps } = reactAria.useButton(
|
|
1130
|
+
const { buttonProps, isPressed } = reactAria.useButton(
|
|
1129
1131
|
{
|
|
1130
1132
|
...props,
|
|
1131
|
-
// Ensure element type is 'button' for proper semantics
|
|
1132
1133
|
elementType: "button",
|
|
1133
|
-
|
|
1134
|
-
|
|
1134
|
+
"aria-label": ariaLabel,
|
|
1135
|
+
isDisabled
|
|
1135
1136
|
},
|
|
1136
1137
|
ref
|
|
1137
1138
|
);
|
|
1139
|
+
const { isHovered, hoverProps } = reactAria.useHover({ isDisabled });
|
|
1140
|
+
const { isFocusVisible, focusProps } = reactAria.useFocusRing();
|
|
1138
1141
|
const domProps = utils.filterDOMProps(props);
|
|
1139
|
-
const mergedProps = utils.mergeProps(
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
+
const mergedProps = utils.mergeProps(buttonProps, hoverProps, focusProps, domProps, {
|
|
1143
|
+
tabIndex,
|
|
1144
|
+
className,
|
|
1145
|
+
onMouseDown,
|
|
1146
|
+
type: type ?? "button",
|
|
1147
|
+
...title && { title },
|
|
1148
|
+
// aria-pressed only when acting as a toggle button
|
|
1149
|
+
...isToggle && { "aria-pressed": isSelected ?? false }
|
|
1150
|
+
});
|
|
1151
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1152
|
+
"button",
|
|
1142
1153
|
{
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1154
|
+
...mergedProps,
|
|
1155
|
+
ref,
|
|
1156
|
+
type: type === "submit" ? "submit" : type === "reset" ? "reset" : "button",
|
|
1157
|
+
...getInteractionDataAttributes({
|
|
1158
|
+
isHovered,
|
|
1159
|
+
isFocusVisible,
|
|
1160
|
+
isPressed,
|
|
1161
|
+
...isToggle ? { isSelected: isSelected ?? false } : {},
|
|
1162
|
+
isDisabled
|
|
1163
|
+
}),
|
|
1164
|
+
"data-toggle": isToggle ? "" : void 0,
|
|
1165
|
+
children
|
|
1151
1166
|
}
|
|
1152
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1153
|
-
);
|
|
1154
|
-
return (
|
|
1155
|
-
// eslint-disable-next-line react/button-has-type
|
|
1156
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", { ...mergedProps, ref, type: type ?? "button", children })
|
|
1157
1167
|
);
|
|
1158
1168
|
}
|
|
1159
1169
|
);
|
|
1160
1170
|
IconButtonHeadless.displayName = "IconButtonHeadless";
|
|
1161
|
-
var
|
|
1171
|
+
var iconButtonRootVariants = classVarianceAuthority.cva(
|
|
1162
1172
|
[
|
|
1163
|
-
//
|
|
1164
|
-
"relative inline-flex items-center justify-center
|
|
1165
|
-
"
|
|
1166
|
-
|
|
1167
|
-
//
|
|
1168
|
-
//
|
|
1169
|
-
//
|
|
1173
|
+
// Layout
|
|
1174
|
+
"relative inline-flex items-center justify-center",
|
|
1175
|
+
"cursor-pointer select-none",
|
|
1176
|
+
"overflow-hidden",
|
|
1177
|
+
// Corner radius driven by CSS variable — set per shape×size in compoundVariants.
|
|
1178
|
+
// Fallback 9999px is only reached if both shape and size props are absent,
|
|
1179
|
+
// which cannot happen in normal usage.
|
|
1180
|
+
"rounded-[var(--ib-radius,9999px)]",
|
|
1181
|
+
// Split MD3 transition via the existing btn-transition utility:
|
|
1182
|
+
// border-radius → emphasized-decelerate (no overshoot, no sharp-corner flash)
|
|
1183
|
+
// color/bg/border/opacity → standard-fast-effects (no overshoot on effects)
|
|
1184
|
+
// This is identical to the approach used by Button/connected ButtonGroup and is
|
|
1185
|
+
// the standard fix for the 9999px overshoot problem documented in styles.css.
|
|
1170
1186
|
"btn-transition",
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
"
|
|
1174
|
-
"
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
"
|
|
1178
|
-
"
|
|
1187
|
+
// Background + border + text driven from CSS role variables
|
|
1188
|
+
"bg-[var(--ib-bg,transparent)]",
|
|
1189
|
+
"border border-[var(--ib-border,transparent)]",
|
|
1190
|
+
"text-[var(--ib-fg,currentColor)]",
|
|
1191
|
+
// Toggle: off state (data-toggle present but data-selected absent)
|
|
1192
|
+
// Uses doubly-chained selector to beat single-chain specificity of defaults
|
|
1193
|
+
"data-[toggle]:bg-[var(--ib-bg-off,var(--ib-bg,transparent))]",
|
|
1194
|
+
"data-[toggle]:text-[var(--ib-fg-off,var(--ib-fg,currentColor))]",
|
|
1195
|
+
// Selected state
|
|
1196
|
+
"data-[selected]:bg-[var(--ib-bg-on,var(--ib-bg,transparent))]",
|
|
1197
|
+
"data-[selected]:text-[var(--ib-fg-on,var(--ib-fg,currentColor))]",
|
|
1198
|
+
"data-[selected]:border-transparent",
|
|
1199
|
+
// Press shape-morph: radius collapses to --ib-radius-press on press
|
|
1200
|
+
// (only has visual effect when --ib-radius-press differs from --ib-radius)
|
|
1201
|
+
"data-[pressed]:rounded-[var(--ib-radius-press,var(--ib-radius,9999px))]",
|
|
1202
|
+
// Focus ring (outline, not a state layer — stays outside overflow-hidden
|
|
1203
|
+
// because it's drawn as outline on the root element itself)
|
|
1204
|
+
"outline-none",
|
|
1205
|
+
"group-data-[focus-visible]/icon-button:outline-2",
|
|
1206
|
+
"group-data-[focus-visible]/icon-button:outline-offset-2",
|
|
1207
|
+
"group-data-[focus-visible]/icon-button:outline-secondary",
|
|
1208
|
+
// Disabled — content opacity 38%, container handled per variant via CSS vars
|
|
1209
|
+
"data-[disabled]:cursor-not-allowed data-[disabled]:pointer-events-none",
|
|
1210
|
+
"data-[disabled]:text-on-surface/38"
|
|
1211
|
+
// Filled/tonal/outlined-selected backgrounds collapse to on-surface/12 — set
|
|
1212
|
+
// via compoundVariants on the root for variants that have a container.
|
|
1213
|
+
// For variants with transparent bg (standard, outlined-unselected) we do nothing.
|
|
1179
1214
|
],
|
|
1180
1215
|
{
|
|
1181
1216
|
variants: {
|
|
1182
1217
|
/**
|
|
1183
|
-
*
|
|
1218
|
+
* Visual style variant (MD3 icon button types)
|
|
1184
1219
|
*/
|
|
1185
1220
|
variant: {
|
|
1186
|
-
standard: "
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
tonal: "",
|
|
1191
|
-
// Container background
|
|
1192
|
-
outlined: "bg-transparent border border-outline"
|
|
1221
|
+
standard: "",
|
|
1222
|
+
filled: "data-[disabled]:bg-on-surface/12",
|
|
1223
|
+
tonal: "data-[disabled]:bg-on-surface/12",
|
|
1224
|
+
outlined: ""
|
|
1193
1225
|
},
|
|
1194
1226
|
/**
|
|
1195
|
-
* Color scheme
|
|
1227
|
+
* Color scheme — sets CSS role variables via compoundVariants.
|
|
1196
1228
|
*/
|
|
1197
1229
|
color: {
|
|
1198
1230
|
primary: "",
|
|
@@ -1201,180 +1233,400 @@ var iconButtonVariants = classVarianceAuthority.cva(
|
|
|
1201
1233
|
error: ""
|
|
1202
1234
|
},
|
|
1203
1235
|
/**
|
|
1204
|
-
*
|
|
1236
|
+
* Size tier (M3 Expressive 5-tier)
|
|
1205
1237
|
*/
|
|
1206
1238
|
size: {
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
medium: "h-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
// 48×48px
|
|
1239
|
+
xsmall: "h-8",
|
|
1240
|
+
small: "h-10",
|
|
1241
|
+
medium: "h-14",
|
|
1242
|
+
large: "h-24",
|
|
1243
|
+
xlarge: "h-[8.5rem]"
|
|
1213
1244
|
},
|
|
1214
1245
|
/**
|
|
1215
|
-
*
|
|
1246
|
+
* Width variant — adjusts container width
|
|
1216
1247
|
*/
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1248
|
+
width: {
|
|
1249
|
+
narrow: "",
|
|
1250
|
+
default: "",
|
|
1251
|
+
wide: ""
|
|
1220
1252
|
},
|
|
1221
1253
|
/**
|
|
1222
|
-
*
|
|
1254
|
+
* Shape — base values only; per-size radii set via compoundVariants below.
|
|
1255
|
+
*
|
|
1256
|
+
* round: --ib-radius = half the container height (true circle), set per size.
|
|
1257
|
+
* --ib-radius-press = square corner for that size (set per size).
|
|
1258
|
+
* Morph distance is small (e.g. 28px → 16px for medium), so the
|
|
1259
|
+
* emphasized-decelerate curve from btn-transition produces a smooth,
|
|
1260
|
+
* non-overshooting transition. The old 9999px fallback caused the
|
|
1261
|
+
* spring to overshoot below 0 = sharp-corner flash.
|
|
1262
|
+
* square: --ib-radius = size-tiered MD3 corner, set per size. No press morph.
|
|
1223
1263
|
*/
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1264
|
+
shape: {
|
|
1265
|
+
round: [],
|
|
1266
|
+
square: []
|
|
1227
1267
|
}
|
|
1228
1268
|
},
|
|
1229
|
-
/**
|
|
1230
|
-
* Compound variants - combinations of variant + color + selected
|
|
1231
|
-
*/
|
|
1232
1269
|
compoundVariants: [
|
|
1233
|
-
//
|
|
1234
|
-
//
|
|
1235
|
-
//
|
|
1236
|
-
{
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
},
|
|
1270
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
1271
|
+
// SIZE × WIDTH — container width
|
|
1272
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
1273
|
+
{ size: "xsmall", width: "narrow", className: "w-6" },
|
|
1274
|
+
{ size: "xsmall", width: "default", className: "w-8" },
|
|
1275
|
+
{ size: "xsmall", width: "wide", className: "w-10" },
|
|
1276
|
+
{ size: "small", width: "narrow", className: "w-8" },
|
|
1277
|
+
{ size: "small", width: "default", className: "w-10" },
|
|
1278
|
+
{ size: "small", width: "wide", className: "w-13" },
|
|
1279
|
+
{ size: "medium", width: "narrow", className: "w-12" },
|
|
1280
|
+
{ size: "medium", width: "default", className: "w-14" },
|
|
1281
|
+
{ size: "medium", width: "wide", className: "w-18" },
|
|
1282
|
+
{ size: "large", width: "narrow", className: "w-18" },
|
|
1283
|
+
{ size: "large", width: "default", className: "w-24" },
|
|
1284
|
+
{ size: "large", width: "wide", className: "w-32" },
|
|
1285
|
+
{ size: "xlarge", width: "narrow", className: "w-24" },
|
|
1286
|
+
{ size: "xlarge", width: "default", className: "w-[8.5rem]" },
|
|
1287
|
+
{ size: "xlarge", width: "wide", className: "w-42" },
|
|
1288
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
1289
|
+
// SHAPE × SIZE — corner radii for both round and square shapes
|
|
1290
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
1291
|
+
//
|
|
1292
|
+
// Round rest radius = half container height (true circle).
|
|
1293
|
+
// Using the exact half-height keeps the morph distance small, so the
|
|
1294
|
+
// no-overshoot emphasized-decelerate curve in btn-transition produces a
|
|
1295
|
+
// smooth animation. Using 9999px was the original cause of the sharp-
|
|
1296
|
+
// corner flash (the spring overshoots below 0 before settling).
|
|
1297
|
+
//
|
|
1298
|
+
// xsmall h-8 = 32px → half = 16px = 1rem
|
|
1299
|
+
// small h-10 = 40px → half = 20px = 1.25rem
|
|
1300
|
+
// medium h-14 = 56px → half = 28px = 1.75rem
|
|
1301
|
+
// large h-24 = 96px → half = 48px = 3rem
|
|
1302
|
+
// xlarge h-34 = 136px → half = 68px = 4.25rem
|
|
1303
|
+
//
|
|
1304
|
+
// Round press-morph target = MD3 square corner for that size tier.
|
|
1305
|
+
// Square rest radius = same MD3 corner (no morph).
|
|
1306
|
+
// ── round: rest radius (half height) ──────────────────────────────────
|
|
1307
|
+
{ shape: "round", size: "xsmall", className: "[--ib-radius:1rem]" },
|
|
1308
|
+
{ shape: "round", size: "small", className: "[--ib-radius:1.25rem]" },
|
|
1309
|
+
{ shape: "round", size: "medium", className: "[--ib-radius:1.75rem]" },
|
|
1310
|
+
{ shape: "round", size: "large", className: "[--ib-radius:3rem]" },
|
|
1311
|
+
{ shape: "round", size: "xlarge", className: "[--ib-radius:4.25rem]" },
|
|
1312
|
+
// ── round: press-morph target (square corner for that size) ───────────
|
|
1313
|
+
{ shape: "round", size: "xsmall", className: "[--ib-radius-press:0.75rem]" },
|
|
1314
|
+
{ shape: "round", size: "small", className: "[--ib-radius-press:0.75rem]" },
|
|
1315
|
+
{ shape: "round", size: "medium", className: "[--ib-radius-press:1rem]" },
|
|
1316
|
+
{ shape: "round", size: "large", className: "[--ib-radius-press:1.75rem]" },
|
|
1317
|
+
{ shape: "round", size: "xlarge", className: "[--ib-radius-press:1.75rem]" },
|
|
1318
|
+
// ── square: rest radius (MD3 shape scale) ─────────────────────────────
|
|
1319
|
+
// xsmall / small → 12px (0.75rem), medium → 16px (1rem), large / xlarge → 28px (1.75rem)
|
|
1320
|
+
{ shape: "square", size: "xsmall", className: "[--ib-radius:0.75rem]" },
|
|
1321
|
+
{ shape: "square", size: "small", className: "[--ib-radius:0.75rem]" },
|
|
1322
|
+
{ shape: "square", size: "medium", className: "[--ib-radius:1rem]" },
|
|
1323
|
+
{ shape: "square", size: "large", className: "[--ib-radius:1.75rem]" },
|
|
1324
|
+
{ shape: "square", size: "xlarge", className: "[--ib-radius:1.75rem]" },
|
|
1325
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
1326
|
+
// VARIANT × COLOR — CSS role variable assignments
|
|
1327
|
+
// Only variant × color (design-time decisions); no state variants here.
|
|
1328
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
1329
|
+
// ── STANDARD ──────────────────────────────────────────────────────────
|
|
1330
|
+
// Non-toggle standard: transparent bg, on-surface-variant fg
|
|
1331
|
+
// Selected: primary fg
|
|
1332
|
+
// State layer: on-surface-variant (unselected) / primary (selected)
|
|
1241
1333
|
{
|
|
1242
1334
|
variant: "standard",
|
|
1243
|
-
selected: true,
|
|
1244
|
-
className: "text-primary"
|
|
1245
|
-
},
|
|
1246
|
-
// ====================
|
|
1247
|
-
// FILLED VARIANTS (UNSELECTED)
|
|
1248
|
-
// ====================
|
|
1249
|
-
{
|
|
1250
|
-
variant: "filled",
|
|
1251
1335
|
color: "primary",
|
|
1252
|
-
|
|
1253
|
-
|
|
1336
|
+
className: [
|
|
1337
|
+
"[--ib-bg:transparent]",
|
|
1338
|
+
"[--ib-fg:var(--color-on-surface-variant)]",
|
|
1339
|
+
"[--ib-fg-on:var(--color-primary)]",
|
|
1340
|
+
"[--ib-sl:var(--color-on-surface-variant)]",
|
|
1341
|
+
// toggle-off same as non-toggle
|
|
1342
|
+
"[--ib-bg-off:transparent]",
|
|
1343
|
+
"[--ib-fg-off:var(--color-on-surface-variant)]",
|
|
1344
|
+
// toggle-on: selected
|
|
1345
|
+
"[--ib-bg-on:transparent]"
|
|
1346
|
+
]
|
|
1254
1347
|
},
|
|
1255
1348
|
{
|
|
1256
|
-
variant: "
|
|
1349
|
+
variant: "standard",
|
|
1257
1350
|
color: "secondary",
|
|
1258
|
-
|
|
1259
|
-
|
|
1351
|
+
className: [
|
|
1352
|
+
"[--ib-bg:transparent]",
|
|
1353
|
+
"[--ib-fg:var(--color-on-surface-variant)]",
|
|
1354
|
+
"[--ib-fg-on:var(--color-secondary)]",
|
|
1355
|
+
"[--ib-sl:var(--color-on-surface-variant)]",
|
|
1356
|
+
"[--ib-bg-off:transparent]",
|
|
1357
|
+
"[--ib-fg-off:var(--color-on-surface-variant)]",
|
|
1358
|
+
"[--ib-bg-on:transparent]"
|
|
1359
|
+
]
|
|
1260
1360
|
},
|
|
1261
1361
|
{
|
|
1262
|
-
variant: "
|
|
1362
|
+
variant: "standard",
|
|
1263
1363
|
color: "tertiary",
|
|
1264
|
-
|
|
1265
|
-
|
|
1364
|
+
className: [
|
|
1365
|
+
"[--ib-bg:transparent]",
|
|
1366
|
+
"[--ib-fg:var(--color-on-surface-variant)]",
|
|
1367
|
+
"[--ib-fg-on:var(--color-tertiary)]",
|
|
1368
|
+
"[--ib-sl:var(--color-on-surface-variant)]",
|
|
1369
|
+
"[--ib-bg-off:transparent]",
|
|
1370
|
+
"[--ib-fg-off:var(--color-on-surface-variant)]",
|
|
1371
|
+
"[--ib-bg-on:transparent]"
|
|
1372
|
+
]
|
|
1266
1373
|
},
|
|
1267
1374
|
{
|
|
1268
|
-
variant: "
|
|
1375
|
+
variant: "standard",
|
|
1269
1376
|
color: "error",
|
|
1270
|
-
|
|
1271
|
-
|
|
1377
|
+
className: [
|
|
1378
|
+
"[--ib-bg:transparent]",
|
|
1379
|
+
"[--ib-fg:var(--color-on-surface-variant)]",
|
|
1380
|
+
"[--ib-fg-on:var(--color-error)]",
|
|
1381
|
+
"[--ib-sl:var(--color-on-surface-variant)]",
|
|
1382
|
+
"[--ib-bg-off:transparent]",
|
|
1383
|
+
"[--ib-fg-off:var(--color-on-surface-variant)]",
|
|
1384
|
+
"[--ib-bg-on:transparent]"
|
|
1385
|
+
]
|
|
1272
1386
|
},
|
|
1273
|
-
//
|
|
1274
|
-
//
|
|
1275
|
-
//
|
|
1387
|
+
// ── FILLED ────────────────────────────────────────────────────────────
|
|
1388
|
+
// Non-toggle: bg primary / fg on-primary
|
|
1389
|
+
// Toggle off: bg surface-container-highest / fg primary
|
|
1390
|
+
// Toggle on (selected): bg primary / fg on-primary
|
|
1391
|
+
// State layer: on-primary (non-toggle / selected), primary (toggle-off)
|
|
1276
1392
|
{
|
|
1277
1393
|
variant: "filled",
|
|
1278
1394
|
color: "primary",
|
|
1279
|
-
|
|
1280
|
-
|
|
1395
|
+
className: [
|
|
1396
|
+
"[--ib-bg:var(--color-primary)]",
|
|
1397
|
+
"[--ib-fg:var(--color-on-primary)]",
|
|
1398
|
+
"[--ib-sl:var(--color-on-primary)]",
|
|
1399
|
+
"[--ib-bg-off:var(--color-surface-container-highest)]",
|
|
1400
|
+
"[--ib-fg-off:var(--color-primary)]",
|
|
1401
|
+
"[--ib-bg-on:var(--color-primary)]",
|
|
1402
|
+
"[--ib-fg-on:var(--color-on-primary)]"
|
|
1403
|
+
]
|
|
1281
1404
|
},
|
|
1282
1405
|
{
|
|
1283
1406
|
variant: "filled",
|
|
1284
1407
|
color: "secondary",
|
|
1285
|
-
|
|
1286
|
-
|
|
1408
|
+
className: [
|
|
1409
|
+
"[--ib-bg:var(--color-secondary)]",
|
|
1410
|
+
"[--ib-fg:var(--color-on-secondary)]",
|
|
1411
|
+
"[--ib-sl:var(--color-on-secondary)]",
|
|
1412
|
+
"[--ib-bg-off:var(--color-surface-container-highest)]",
|
|
1413
|
+
"[--ib-fg-off:var(--color-secondary)]",
|
|
1414
|
+
"[--ib-bg-on:var(--color-secondary)]",
|
|
1415
|
+
"[--ib-fg-on:var(--color-on-secondary)]"
|
|
1416
|
+
]
|
|
1287
1417
|
},
|
|
1288
1418
|
{
|
|
1289
1419
|
variant: "filled",
|
|
1290
1420
|
color: "tertiary",
|
|
1291
|
-
|
|
1292
|
-
|
|
1421
|
+
className: [
|
|
1422
|
+
"[--ib-bg:var(--color-tertiary)]",
|
|
1423
|
+
"[--ib-fg:var(--color-on-tertiary)]",
|
|
1424
|
+
"[--ib-sl:var(--color-on-tertiary)]",
|
|
1425
|
+
"[--ib-bg-off:var(--color-surface-container-highest)]",
|
|
1426
|
+
"[--ib-fg-off:var(--color-tertiary)]",
|
|
1427
|
+
"[--ib-bg-on:var(--color-tertiary)]",
|
|
1428
|
+
"[--ib-fg-on:var(--color-on-tertiary)]"
|
|
1429
|
+
]
|
|
1293
1430
|
},
|
|
1294
1431
|
{
|
|
1295
1432
|
variant: "filled",
|
|
1296
1433
|
color: "error",
|
|
1297
|
-
|
|
1298
|
-
|
|
1434
|
+
className: [
|
|
1435
|
+
"[--ib-bg:var(--color-error)]",
|
|
1436
|
+
"[--ib-fg:var(--color-on-error)]",
|
|
1437
|
+
"[--ib-sl:var(--color-on-error)]",
|
|
1438
|
+
"[--ib-bg-off:var(--color-surface-container-highest)]",
|
|
1439
|
+
"[--ib-fg-off:var(--color-error)]",
|
|
1440
|
+
"[--ib-bg-on:var(--color-error)]",
|
|
1441
|
+
"[--ib-fg-on:var(--color-on-error)]"
|
|
1442
|
+
]
|
|
1299
1443
|
},
|
|
1300
|
-
//
|
|
1301
|
-
//
|
|
1302
|
-
//
|
|
1444
|
+
// ── TONAL ─────────────────────────────────────────────────────────────
|
|
1445
|
+
// Non-toggle: bg secondary-container / fg on-secondary-container
|
|
1446
|
+
// Toggle off: bg surface-container-highest / fg on-surface-variant
|
|
1447
|
+
// Toggle on (selected): bg secondary-container / fg on-secondary-container
|
|
1303
1448
|
{
|
|
1304
1449
|
variant: "tonal",
|
|
1305
1450
|
color: "primary",
|
|
1306
|
-
|
|
1307
|
-
|
|
1451
|
+
className: [
|
|
1452
|
+
"[--ib-bg:var(--color-secondary-container)]",
|
|
1453
|
+
"[--ib-fg:var(--color-on-secondary-container)]",
|
|
1454
|
+
"[--ib-sl:var(--color-on-secondary-container)]",
|
|
1455
|
+
"[--ib-bg-off:var(--color-surface-container-highest)]",
|
|
1456
|
+
"[--ib-fg-off:var(--color-on-surface-variant)]",
|
|
1457
|
+
"[--ib-bg-on:var(--color-secondary-container)]",
|
|
1458
|
+
"[--ib-fg-on:var(--color-on-secondary-container)]"
|
|
1459
|
+
]
|
|
1308
1460
|
},
|
|
1309
1461
|
{
|
|
1310
1462
|
variant: "tonal",
|
|
1311
1463
|
color: "secondary",
|
|
1312
|
-
|
|
1313
|
-
|
|
1464
|
+
className: [
|
|
1465
|
+
"[--ib-bg:var(--color-secondary-container)]",
|
|
1466
|
+
"[--ib-fg:var(--color-on-secondary-container)]",
|
|
1467
|
+
"[--ib-sl:var(--color-on-secondary-container)]",
|
|
1468
|
+
"[--ib-bg-off:var(--color-surface-container-highest)]",
|
|
1469
|
+
"[--ib-fg-off:var(--color-on-surface-variant)]",
|
|
1470
|
+
"[--ib-bg-on:var(--color-secondary-container)]",
|
|
1471
|
+
"[--ib-fg-on:var(--color-on-secondary-container)]"
|
|
1472
|
+
]
|
|
1314
1473
|
},
|
|
1315
1474
|
{
|
|
1316
1475
|
variant: "tonal",
|
|
1317
1476
|
color: "tertiary",
|
|
1318
|
-
|
|
1319
|
-
|
|
1477
|
+
className: [
|
|
1478
|
+
"[--ib-bg:var(--color-tertiary-container)]",
|
|
1479
|
+
"[--ib-fg:var(--color-on-tertiary-container)]",
|
|
1480
|
+
"[--ib-sl:var(--color-on-tertiary-container)]",
|
|
1481
|
+
"[--ib-bg-off:var(--color-surface-container-highest)]",
|
|
1482
|
+
"[--ib-fg-off:var(--color-on-surface-variant)]",
|
|
1483
|
+
"[--ib-bg-on:var(--color-tertiary-container)]",
|
|
1484
|
+
"[--ib-fg-on:var(--color-on-tertiary-container)]"
|
|
1485
|
+
]
|
|
1320
1486
|
},
|
|
1321
1487
|
{
|
|
1322
1488
|
variant: "tonal",
|
|
1323
1489
|
color: "error",
|
|
1324
|
-
|
|
1325
|
-
|
|
1490
|
+
className: [
|
|
1491
|
+
"[--ib-bg:var(--color-error-container)]",
|
|
1492
|
+
"[--ib-fg:var(--color-on-error-container)]",
|
|
1493
|
+
"[--ib-sl:var(--color-on-error-container)]",
|
|
1494
|
+
"[--ib-bg-off:var(--color-surface-container-highest)]",
|
|
1495
|
+
"[--ib-fg-off:var(--color-on-surface-variant)]",
|
|
1496
|
+
"[--ib-bg-on:var(--color-error-container)]",
|
|
1497
|
+
"[--ib-fg-on:var(--color-on-error-container)]"
|
|
1498
|
+
]
|
|
1326
1499
|
},
|
|
1327
|
-
//
|
|
1328
|
-
//
|
|
1329
|
-
//
|
|
1500
|
+
// ── OUTLINED ──────────────────────────────────────────────────────────
|
|
1501
|
+
// Non-toggle: transparent bg, border-outline, on-surface-variant fg
|
|
1502
|
+
// Toggle off: same as non-toggle
|
|
1503
|
+
// Toggle on (selected): inverse-surface bg, inverse-on-surface fg, no border
|
|
1504
|
+
// Disabled: border becomes on-surface/12 (set via Tailwind utility on root)
|
|
1330
1505
|
{
|
|
1331
|
-
variant: "
|
|
1332
|
-
|
|
1333
|
-
className:
|
|
1506
|
+
variant: "outlined",
|
|
1507
|
+
color: "primary",
|
|
1508
|
+
className: [
|
|
1509
|
+
"[--ib-bg:transparent]",
|
|
1510
|
+
"[--ib-fg:var(--color-on-surface-variant)]",
|
|
1511
|
+
"[--ib-sl:var(--color-on-surface-variant)]",
|
|
1512
|
+
"[--ib-border:var(--color-outline)]",
|
|
1513
|
+
"[--ib-bg-off:transparent]",
|
|
1514
|
+
"[--ib-fg-off:var(--color-on-surface-variant)]",
|
|
1515
|
+
"[--ib-bg-on:var(--color-inverse-surface)]",
|
|
1516
|
+
"[--ib-fg-on:var(--color-inverse-on-surface)]",
|
|
1517
|
+
// Disabled outlined border
|
|
1518
|
+
"data-[disabled]:border-on-surface/12"
|
|
1519
|
+
]
|
|
1334
1520
|
},
|
|
1335
|
-
// ====================
|
|
1336
|
-
// OUTLINED VARIANTS (UNSELECTED)
|
|
1337
|
-
// ====================
|
|
1338
1521
|
{
|
|
1339
1522
|
variant: "outlined",
|
|
1340
|
-
|
|
1341
|
-
className:
|
|
1523
|
+
color: "secondary",
|
|
1524
|
+
className: [
|
|
1525
|
+
"[--ib-bg:transparent]",
|
|
1526
|
+
"[--ib-fg:var(--color-on-surface-variant)]",
|
|
1527
|
+
"[--ib-sl:var(--color-on-surface-variant)]",
|
|
1528
|
+
"[--ib-border:var(--color-outline)]",
|
|
1529
|
+
"[--ib-bg-off:transparent]",
|
|
1530
|
+
"[--ib-fg-off:var(--color-on-surface-variant)]",
|
|
1531
|
+
"[--ib-bg-on:var(--color-inverse-surface)]",
|
|
1532
|
+
"[--ib-fg-on:var(--color-inverse-on-surface)]",
|
|
1533
|
+
"data-[disabled]:border-on-surface/12"
|
|
1534
|
+
]
|
|
1342
1535
|
},
|
|
1343
|
-
// ====================
|
|
1344
|
-
// OUTLINED VARIANTS (SELECTED - uses inverse colors)
|
|
1345
|
-
// ====================
|
|
1346
1536
|
{
|
|
1347
1537
|
variant: "outlined",
|
|
1348
|
-
|
|
1349
|
-
className:
|
|
1538
|
+
color: "tertiary",
|
|
1539
|
+
className: [
|
|
1540
|
+
"[--ib-bg:transparent]",
|
|
1541
|
+
"[--ib-fg:var(--color-on-surface-variant)]",
|
|
1542
|
+
"[--ib-sl:var(--color-on-surface-variant)]",
|
|
1543
|
+
"[--ib-border:var(--color-outline)]",
|
|
1544
|
+
"[--ib-bg-off:transparent]",
|
|
1545
|
+
"[--ib-fg-off:var(--color-on-surface-variant)]",
|
|
1546
|
+
"[--ib-bg-on:var(--color-inverse-surface)]",
|
|
1547
|
+
"[--ib-fg-on:var(--color-inverse-on-surface)]",
|
|
1548
|
+
"data-[disabled]:border-on-surface/12"
|
|
1549
|
+
]
|
|
1550
|
+
},
|
|
1551
|
+
{
|
|
1552
|
+
variant: "outlined",
|
|
1553
|
+
color: "error",
|
|
1554
|
+
className: [
|
|
1555
|
+
"[--ib-bg:transparent]",
|
|
1556
|
+
"[--ib-fg:var(--color-on-surface-variant)]",
|
|
1557
|
+
"[--ib-sl:var(--color-on-surface-variant)]",
|
|
1558
|
+
"[--ib-border:var(--color-outline)]",
|
|
1559
|
+
"[--ib-bg-off:transparent]",
|
|
1560
|
+
"[--ib-fg-off:var(--color-on-surface-variant)]",
|
|
1561
|
+
"[--ib-bg-on:var(--color-inverse-surface)]",
|
|
1562
|
+
"[--ib-fg-on:var(--color-inverse-on-surface)]",
|
|
1563
|
+
"data-[disabled]:border-on-surface/12"
|
|
1564
|
+
]
|
|
1350
1565
|
}
|
|
1351
1566
|
],
|
|
1352
|
-
/**
|
|
1353
|
-
* Default variants
|
|
1354
|
-
*/
|
|
1355
1567
|
defaultVariants: {
|
|
1356
1568
|
variant: "standard",
|
|
1357
1569
|
color: "primary",
|
|
1358
1570
|
size: "medium",
|
|
1359
|
-
|
|
1360
|
-
|
|
1571
|
+
width: "default",
|
|
1572
|
+
shape: "round"
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
);
|
|
1576
|
+
var iconButtonStateLayerVariants = classVarianceAuthority.cva([
|
|
1577
|
+
"absolute inset-0 rounded-[inherit] pointer-events-none opacity-0",
|
|
1578
|
+
"bg-[var(--ib-sl,currentColor)]",
|
|
1579
|
+
// Effects transition (opacity — no spatial overshoot)
|
|
1580
|
+
"transition-opacity duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
|
|
1581
|
+
// Interaction opacities (MD3: hover 8%, focus/pressed 10%)
|
|
1582
|
+
"group-data-[hovered]/icon-button:opacity-8",
|
|
1583
|
+
"group-data-[focus-visible]/icon-button:opacity-10",
|
|
1584
|
+
"group-data-[pressed]/icon-button:opacity-10",
|
|
1585
|
+
// No state layer when disabled
|
|
1586
|
+
"group-data-[disabled]/icon-button:hidden"
|
|
1587
|
+
]);
|
|
1588
|
+
var iconButtonIconVariants = classVarianceAuthority.cva(
|
|
1589
|
+
[
|
|
1590
|
+
"relative z-10 inline-flex shrink-0 items-center justify-center",
|
|
1591
|
+
"transition-colors duration-spring-standard-fast-effects ease-spring-standard-fast-effects"
|
|
1592
|
+
],
|
|
1593
|
+
{
|
|
1594
|
+
variants: {
|
|
1595
|
+
size: {
|
|
1596
|
+
xsmall: "size-5",
|
|
1597
|
+
// 20dp
|
|
1598
|
+
small: "size-6",
|
|
1599
|
+
// 24dp
|
|
1600
|
+
medium: "size-6",
|
|
1601
|
+
// 24dp
|
|
1602
|
+
large: "size-8",
|
|
1603
|
+
// 32dp
|
|
1604
|
+
xlarge: "size-10"
|
|
1605
|
+
// 40dp
|
|
1606
|
+
}
|
|
1607
|
+
},
|
|
1608
|
+
defaultVariants: {
|
|
1609
|
+
size: "medium"
|
|
1361
1610
|
}
|
|
1362
1611
|
}
|
|
1363
1612
|
);
|
|
1364
1613
|
var IconButton = React.forwardRef(
|
|
1365
1614
|
({
|
|
1366
|
-
// Variant props (CVA)
|
|
1615
|
+
// Variant props (CVA / design-time)
|
|
1367
1616
|
variant = "standard",
|
|
1368
1617
|
color = "primary",
|
|
1369
1618
|
size = "medium",
|
|
1619
|
+
width = "default",
|
|
1620
|
+
shape = "round",
|
|
1370
1621
|
// IconButton specific props
|
|
1371
1622
|
children,
|
|
1623
|
+
selectedIcon,
|
|
1372
1624
|
value,
|
|
1373
1625
|
selected,
|
|
1374
1626
|
disableRipple = false,
|
|
1375
1627
|
className,
|
|
1376
1628
|
// React Aria props
|
|
1377
|
-
isDisabled
|
|
1629
|
+
isDisabled = false,
|
|
1378
1630
|
onPress,
|
|
1379
1631
|
onMouseDown,
|
|
1380
1632
|
"aria-label": ariaLabel,
|
|
@@ -1393,7 +1645,8 @@ var IconButton = React.forwardRef(
|
|
|
1393
1645
|
console.warn("[IconButton] IconButton should have an icon as children.");
|
|
1394
1646
|
}
|
|
1395
1647
|
}
|
|
1396
|
-
const
|
|
1648
|
+
const isToggle = selected !== void 0;
|
|
1649
|
+
const isSelected = isToggle ? selected ?? false : false;
|
|
1397
1650
|
const { onMouseDown: handleRipple, ripples } = useRipple({
|
|
1398
1651
|
disabled: isDisabled || disableRipple
|
|
1399
1652
|
});
|
|
@@ -1411,32 +1664,37 @@ var IconButton = React.forwardRef(
|
|
|
1411
1664
|
...getConnectedRadiusClasses(groupCtx, value),
|
|
1412
1665
|
groupCtx.enforceMinWidth ? "min-w-12" : ""
|
|
1413
1666
|
] : [];
|
|
1667
|
+
const iconNode = isToggle && isSelected && selectedIcon ? selectedIcon : children;
|
|
1414
1668
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1415
1669
|
IconButtonHeadless,
|
|
1416
1670
|
{
|
|
1417
1671
|
ref,
|
|
1418
1672
|
className: cn(
|
|
1419
|
-
// CVA
|
|
1420
|
-
|
|
1421
|
-
//
|
|
1422
|
-
|
|
1423
|
-
//
|
|
1424
|
-
// path, preventing the overshoot-to-0px sharp-corner flash.
|
|
1673
|
+
// Root CVA — sets CSS role variables, dimensions, shape, transitions
|
|
1674
|
+
iconButtonRootVariants({ variant, color, size, width, shape }),
|
|
1675
|
+
// Group scope for child slot selectors
|
|
1676
|
+
"group/icon-button",
|
|
1677
|
+
// ButtonGroup asymmetric border-radius easing (connected selection morph)
|
|
1425
1678
|
isGroupSelected ? "btn-transition-selected" : "",
|
|
1426
1679
|
...connectedClasses,
|
|
1427
|
-
//
|
|
1680
|
+
// Consumer custom classes
|
|
1428
1681
|
className
|
|
1429
1682
|
),
|
|
1430
1683
|
"aria-label": ariaLabel,
|
|
1684
|
+
isSelected,
|
|
1685
|
+
isToggle,
|
|
1431
1686
|
"data-variant": variant,
|
|
1432
1687
|
"data-color": color,
|
|
1688
|
+
"data-size": size,
|
|
1689
|
+
"data-width": width,
|
|
1690
|
+
"data-shape": shape,
|
|
1433
1691
|
"data-group-selected": isGroupSelected ? "" : void 0,
|
|
1434
|
-
...selected !== void 0 && { selected },
|
|
1435
1692
|
...title && { title },
|
|
1436
1693
|
...mergedPropsValue,
|
|
1437
1694
|
children: [
|
|
1695
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: iconButtonStateLayerVariants(), "aria-hidden": "true", "data-state-layer": "" }),
|
|
1438
1696
|
ripples,
|
|
1439
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className:
|
|
1697
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: iconButtonIconVariants({ size }), "data-icon-slot": "", "aria-hidden": "true", children: iconNode })
|
|
1440
1698
|
]
|
|
1441
1699
|
}
|
|
1442
1700
|
);
|
|
@@ -1452,232 +1710,273 @@ var FABHeadless = React.forwardRef(
|
|
|
1452
1710
|
type,
|
|
1453
1711
|
"aria-label": ariaLabel,
|
|
1454
1712
|
title,
|
|
1455
|
-
...
|
|
1713
|
+
...restProps
|
|
1456
1714
|
}, forwardedRef) => {
|
|
1457
1715
|
const internalRef = React.useRef(null);
|
|
1458
1716
|
const ref = forwardedRef ?? internalRef;
|
|
1459
1717
|
const { buttonProps } = reactAria.useButton(
|
|
1460
1718
|
{
|
|
1461
|
-
...
|
|
1719
|
+
...restProps,
|
|
1462
1720
|
elementType: "button"
|
|
1463
1721
|
},
|
|
1464
1722
|
ref
|
|
1465
1723
|
);
|
|
1466
|
-
const
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1724
|
+
const {
|
|
1725
|
+
isDisabled: _isDisabled,
|
|
1726
|
+
onPress: _onPress,
|
|
1727
|
+
onPressStart: _onPressStart,
|
|
1728
|
+
onPressEnd: _onPressEnd,
|
|
1729
|
+
onPressChange: _onPressChange,
|
|
1730
|
+
onPressUp: _onPressUp,
|
|
1731
|
+
...htmlAttrs
|
|
1732
|
+
} = restProps;
|
|
1733
|
+
const mergedProps = utils.mergeProps(
|
|
1734
|
+
buttonProps,
|
|
1735
|
+
{
|
|
1736
|
+
tabIndex,
|
|
1737
|
+
className,
|
|
1738
|
+
onMouseDown,
|
|
1739
|
+
"aria-label": ariaLabel,
|
|
1740
|
+
...title !== void 0 && { title }
|
|
1741
|
+
},
|
|
1742
|
+
htmlAttrs
|
|
1743
|
+
);
|
|
1477
1744
|
return (
|
|
1478
|
-
// eslint-disable-next-line react/button-has-type
|
|
1479
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", { ...mergedProps, ref, children })
|
|
1745
|
+
// eslint-disable-next-line react/button-has-type -- type is dynamically passed from props
|
|
1746
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { ...mergedProps, ref, type: type ?? "button", children })
|
|
1480
1747
|
);
|
|
1481
1748
|
}
|
|
1482
1749
|
);
|
|
1483
1750
|
FABHeadless.displayName = "FABHeadless";
|
|
1484
1751
|
var fabVariants = classVarianceAuthority.cva(
|
|
1485
1752
|
[
|
|
1486
|
-
//
|
|
1487
|
-
"relative inline-flex items-center justify-center cursor-pointer",
|
|
1488
|
-
"overflow-hidden",
|
|
1489
|
-
"transition-all duration-200",
|
|
1490
|
-
"focus-visible:outline-primary focus-visible:outline-2 focus-visible:outline-offset-2",
|
|
1753
|
+
// Layout — NO overflow-hidden here (focus ring must extend outside)
|
|
1754
|
+
"relative inline-flex items-center justify-center cursor-pointer select-none",
|
|
1491
1755
|
"shrink-0",
|
|
1492
|
-
//
|
|
1493
|
-
|
|
1494
|
-
"
|
|
1495
|
-
|
|
1496
|
-
"
|
|
1497
|
-
"
|
|
1498
|
-
"active:before:opacity-12",
|
|
1499
|
-
// Elevation (floating appearance)
|
|
1500
|
-
"shadow-elevation-3",
|
|
1501
|
-
// Default elevation
|
|
1502
|
-
"hover:shadow-elevation-4"
|
|
1503
|
-
// Hover elevation
|
|
1756
|
+
// Effects transition: color / bg / shadow — standard spring, no overshoot
|
|
1757
|
+
"transition-[color,background-color,box-shadow]",
|
|
1758
|
+
"duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
|
|
1759
|
+
// Disabled — self-targeting data-[x]: selectors (not group-data — these target the root itself)
|
|
1760
|
+
"data-[disabled]:bg-on-surface/12 data-[disabled]:text-on-surface/38",
|
|
1761
|
+
"data-[disabled]:shadow-none data-[disabled]:cursor-not-allowed data-[disabled]:pointer-events-none"
|
|
1504
1762
|
],
|
|
1505
1763
|
{
|
|
1506
1764
|
variants: {
|
|
1507
1765
|
/**
|
|
1508
|
-
* FAB size
|
|
1766
|
+
* FAB size — controls container dimensions, corner radius, and icon slot size.
|
|
1509
1767
|
*/
|
|
1510
1768
|
size: {
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
"rounded-xl",
|
|
1517
|
-
// 12px corner radius (not fully rounded!)
|
|
1518
|
-
"m-1"
|
|
1519
|
-
// 4px margin for 48×48px touch target
|
|
1520
|
-
],
|
|
1521
|
-
medium: [
|
|
1769
|
+
/**
|
|
1770
|
+
* fab (default) — 56×56dp, 16dp corner radius.
|
|
1771
|
+
* MD3 standard FAB.
|
|
1772
|
+
*/
|
|
1773
|
+
fab: [
|
|
1522
1774
|
"h-14 w-14",
|
|
1523
|
-
//
|
|
1524
|
-
"p-4",
|
|
1525
|
-
// 16px padding for 24px icon
|
|
1775
|
+
// 56dp
|
|
1526
1776
|
"rounded-2xl"
|
|
1527
|
-
//
|
|
1777
|
+
// 16dp corner
|
|
1528
1778
|
],
|
|
1779
|
+
/**
|
|
1780
|
+
* medium — 80×80dp, 20dp corner radius.
|
|
1781
|
+
* M3 Expressive Medium FAB. Previously this value mapped to 56dp;
|
|
1782
|
+
* it is now remapped to the Expressive 80dp Medium FAB.
|
|
1783
|
+
*/
|
|
1784
|
+
medium: [
|
|
1785
|
+
"h-20 w-20",
|
|
1786
|
+
// 80dp
|
|
1787
|
+
"rounded-[20px]"
|
|
1788
|
+
// 20dp corner (large-increased shape token)
|
|
1789
|
+
],
|
|
1790
|
+
/**
|
|
1791
|
+
* large — 96×96dp, 28dp corner radius.
|
|
1792
|
+
*/
|
|
1529
1793
|
large: [
|
|
1530
1794
|
"h-24 w-24",
|
|
1531
|
-
//
|
|
1532
|
-
"p-[30px]",
|
|
1533
|
-
// 30px padding for 36px icon
|
|
1795
|
+
// 96dp
|
|
1534
1796
|
"rounded-[28px]"
|
|
1535
|
-
//
|
|
1797
|
+
// 28dp corner
|
|
1536
1798
|
],
|
|
1799
|
+
/**
|
|
1800
|
+
* extended — 56dp height, variable width, 16dp corner.
|
|
1801
|
+
* Icon + text label side by side.
|
|
1802
|
+
* Padding: 16dp leading (icon side), 20dp trailing (text side).
|
|
1803
|
+
* Gap: 12dp between icon and label (MD3 spec).
|
|
1804
|
+
*/
|
|
1537
1805
|
extended: [
|
|
1538
1806
|
"h-14",
|
|
1539
|
-
//
|
|
1807
|
+
// 56dp height
|
|
1540
1808
|
"rounded-2xl",
|
|
1541
|
-
//
|
|
1809
|
+
// 16dp corner
|
|
1542
1810
|
"pl-4 pr-5",
|
|
1543
|
-
//
|
|
1544
|
-
"gap-
|
|
1545
|
-
//
|
|
1811
|
+
// 16dp leading, 20dp trailing
|
|
1812
|
+
"gap-3"
|
|
1813
|
+
// 12dp gap between icon and label
|
|
1814
|
+
],
|
|
1815
|
+
/**
|
|
1816
|
+
* @deprecated Use `fab` (56dp) instead.
|
|
1817
|
+
* small — 40×40dp, 12dp corner radius. No longer recommended in M3 Expressive.
|
|
1818
|
+
* Kept functional for backward compatibility.
|
|
1819
|
+
*/
|
|
1820
|
+
small: [
|
|
1821
|
+
"h-10 w-10",
|
|
1822
|
+
// 40dp
|
|
1823
|
+
"rounded-xl",
|
|
1824
|
+
// 12dp corner
|
|
1825
|
+
"m-1"
|
|
1826
|
+
// 4dp margin for 48×48dp minimum touch target
|
|
1546
1827
|
]
|
|
1547
1828
|
},
|
|
1548
1829
|
/**
|
|
1549
|
-
*
|
|
1830
|
+
* FAB color — controls container + on-color.
|
|
1831
|
+
* State-layer color in fabStateLayerVariants must match icon/on-color.
|
|
1550
1832
|
*/
|
|
1551
1833
|
color: {
|
|
1552
|
-
primary:
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1834
|
+
"primary-container": [
|
|
1835
|
+
"bg-primary-container text-on-primary-container",
|
|
1836
|
+
// Elevation base=3, hover=4 (state driven), disabled handled by root data-[disabled]
|
|
1837
|
+
"shadow-elevation-3",
|
|
1838
|
+
"group-data-[hovered]/fab:shadow-elevation-4",
|
|
1839
|
+
// Focus / pressed: return to elevation-3
|
|
1840
|
+
// Doubled attribute selector gives higher specificity than single hover selector
|
|
1841
|
+
"group-data-[focus-visible]/fab:shadow-elevation-3",
|
|
1842
|
+
"group-data-[pressed]/fab:group-data-[pressed]/fab:shadow-elevation-3"
|
|
1843
|
+
],
|
|
1844
|
+
"secondary-container": [
|
|
1845
|
+
"bg-secondary-container text-on-secondary-container",
|
|
1846
|
+
"shadow-elevation-3",
|
|
1847
|
+
"group-data-[hovered]/fab:shadow-elevation-4",
|
|
1848
|
+
"group-data-[focus-visible]/fab:shadow-elevation-3",
|
|
1849
|
+
"group-data-[pressed]/fab:group-data-[pressed]/fab:shadow-elevation-3"
|
|
1850
|
+
],
|
|
1851
|
+
"tertiary-container": [
|
|
1852
|
+
"bg-tertiary-container text-on-tertiary-container",
|
|
1853
|
+
"shadow-elevation-3",
|
|
1854
|
+
"group-data-[hovered]/fab:shadow-elevation-4",
|
|
1855
|
+
"group-data-[focus-visible]/fab:shadow-elevation-3",
|
|
1856
|
+
"group-data-[pressed]/fab:group-data-[pressed]/fab:shadow-elevation-3"
|
|
1857
|
+
],
|
|
1858
|
+
primary: [
|
|
1859
|
+
"bg-primary text-on-primary",
|
|
1860
|
+
"shadow-elevation-3",
|
|
1861
|
+
"group-data-[hovered]/fab:shadow-elevation-4",
|
|
1862
|
+
"group-data-[focus-visible]/fab:shadow-elevation-3",
|
|
1863
|
+
"group-data-[pressed]/fab:group-data-[pressed]/fab:shadow-elevation-3"
|
|
1864
|
+
],
|
|
1865
|
+
secondary: [
|
|
1866
|
+
"bg-secondary text-on-secondary",
|
|
1867
|
+
"shadow-elevation-3",
|
|
1868
|
+
"group-data-[hovered]/fab:shadow-elevation-4",
|
|
1869
|
+
"group-data-[focus-visible]/fab:shadow-elevation-3",
|
|
1870
|
+
"group-data-[pressed]/fab:group-data-[pressed]/fab:shadow-elevation-3"
|
|
1871
|
+
],
|
|
1872
|
+
tertiary: [
|
|
1873
|
+
"bg-tertiary text-on-tertiary",
|
|
1874
|
+
"shadow-elevation-3",
|
|
1875
|
+
"group-data-[hovered]/fab:shadow-elevation-4",
|
|
1876
|
+
"group-data-[focus-visible]/fab:shadow-elevation-3",
|
|
1877
|
+
"group-data-[pressed]/fab:group-data-[pressed]/fab:shadow-elevation-3"
|
|
1878
|
+
],
|
|
1879
|
+
/** @deprecated Use `primary-container` instead. */
|
|
1880
|
+
surface: [
|
|
1881
|
+
"bg-surface-container-high text-primary",
|
|
1882
|
+
"shadow-elevation-3",
|
|
1883
|
+
"group-data-[hovered]/fab:shadow-elevation-4",
|
|
1884
|
+
"group-data-[focus-visible]/fab:shadow-elevation-3",
|
|
1885
|
+
"group-data-[pressed]/fab:group-data-[pressed]/fab:shadow-elevation-3"
|
|
1886
|
+
]
|
|
1563
1887
|
}
|
|
1564
1888
|
},
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
{
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
{
|
|
1629
|
-
color: "tertiary",
|
|
1630
|
-
size: "large",
|
|
1631
|
-
className: "bg-tertiary-container text-on-tertiary-container"
|
|
1632
|
-
},
|
|
1633
|
-
{
|
|
1634
|
-
color: "tertiary",
|
|
1635
|
-
size: "extended",
|
|
1636
|
-
className: "bg-tertiary-container text-on-tertiary-container"
|
|
1637
|
-
},
|
|
1638
|
-
// ====================
|
|
1639
|
-
// SURFACE COLOR
|
|
1640
|
-
// ====================
|
|
1641
|
-
{
|
|
1642
|
-
color: "surface",
|
|
1643
|
-
size: "small",
|
|
1644
|
-
className: "bg-surface text-primary"
|
|
1645
|
-
},
|
|
1646
|
-
{
|
|
1647
|
-
color: "surface",
|
|
1648
|
-
size: "medium",
|
|
1649
|
-
className: "bg-surface text-primary"
|
|
1650
|
-
},
|
|
1651
|
-
{
|
|
1652
|
-
color: "surface",
|
|
1653
|
-
size: "large",
|
|
1654
|
-
className: "bg-surface text-primary"
|
|
1889
|
+
defaultVariants: {
|
|
1890
|
+
size: "fab",
|
|
1891
|
+
color: "primary-container"
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
);
|
|
1895
|
+
var fabStateLayerVariants = classVarianceAuthority.cva(
|
|
1896
|
+
[
|
|
1897
|
+
"absolute inset-0 rounded-[inherit] overflow-hidden pointer-events-none opacity-0",
|
|
1898
|
+
// Effects transition — opacity must not overshoot
|
|
1899
|
+
"transition-opacity duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
|
|
1900
|
+
// Hover: 8%
|
|
1901
|
+
"group-data-[hovered]/fab:opacity-8",
|
|
1902
|
+
// Focus: 10%
|
|
1903
|
+
"group-data-[focus-visible]/fab:opacity-10",
|
|
1904
|
+
// Pressed: 10% — doubled selector wins over hover's 8%
|
|
1905
|
+
"group-data-[pressed]/fab:group-data-[pressed]/fab:opacity-10",
|
|
1906
|
+
// No state layer when disabled
|
|
1907
|
+
"group-data-[disabled]/fab:hidden"
|
|
1908
|
+
],
|
|
1909
|
+
{
|
|
1910
|
+
variants: {
|
|
1911
|
+
color: {
|
|
1912
|
+
"primary-container": "bg-on-primary-container",
|
|
1913
|
+
"secondary-container": "bg-on-secondary-container",
|
|
1914
|
+
"tertiary-container": "bg-on-tertiary-container",
|
|
1915
|
+
primary: "bg-on-primary",
|
|
1916
|
+
secondary: "bg-on-secondary",
|
|
1917
|
+
tertiary: "bg-on-tertiary",
|
|
1918
|
+
/** @deprecated */
|
|
1919
|
+
surface: "bg-primary"
|
|
1920
|
+
}
|
|
1921
|
+
},
|
|
1922
|
+
defaultVariants: { color: "primary-container" }
|
|
1923
|
+
}
|
|
1924
|
+
);
|
|
1925
|
+
var fabFocusRingVariants = classVarianceAuthority.cva([
|
|
1926
|
+
"pointer-events-none absolute inset-[-3px] rounded-[inherit]",
|
|
1927
|
+
"outline outline-2 outline-offset-0 outline-secondary",
|
|
1928
|
+
// Effects transition — opacity change must not overshoot
|
|
1929
|
+
"transition-opacity duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
|
|
1930
|
+
"opacity-0",
|
|
1931
|
+
"group-data-[focus-visible]/fab:opacity-100"
|
|
1932
|
+
]);
|
|
1933
|
+
var fabIconVariants = classVarianceAuthority.cva(
|
|
1934
|
+
[
|
|
1935
|
+
"relative z-10 inline-flex shrink-0 items-center justify-center",
|
|
1936
|
+
// Color transition uses effects token (no spatial overshoot on color)
|
|
1937
|
+
"transition-colors duration-spring-standard-fast-effects ease-spring-standard-fast-effects"
|
|
1938
|
+
],
|
|
1939
|
+
{
|
|
1940
|
+
variants: {
|
|
1941
|
+
size: {
|
|
1942
|
+
fab: "size-6",
|
|
1943
|
+
// 24dp
|
|
1944
|
+
medium: "size-7",
|
|
1945
|
+
// 28dp
|
|
1946
|
+
large: "size-9",
|
|
1947
|
+
// 36dp
|
|
1948
|
+
extended: "size-6",
|
|
1949
|
+
// 24dp
|
|
1950
|
+
small: "size-6"
|
|
1951
|
+
// 24dp
|
|
1655
1952
|
},
|
|
1656
|
-
{
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
className: "bg-surface text-primary"
|
|
1953
|
+
hidden: {
|
|
1954
|
+
true: "invisible",
|
|
1955
|
+
false: ""
|
|
1660
1956
|
}
|
|
1661
|
-
|
|
1662
|
-
/**
|
|
1663
|
-
* Default variants
|
|
1664
|
-
*/
|
|
1957
|
+
},
|
|
1665
1958
|
defaultVariants: {
|
|
1666
|
-
size: "
|
|
1667
|
-
|
|
1668
|
-
isDisabled: false
|
|
1959
|
+
size: "fab",
|
|
1960
|
+
hidden: false
|
|
1669
1961
|
}
|
|
1670
1962
|
}
|
|
1671
1963
|
);
|
|
1964
|
+
var fabLabelVariants = classVarianceAuthority.cva([
|
|
1965
|
+
"relative z-10 inline-flex items-center",
|
|
1966
|
+
"text-label-large tracking-[0.1px]"
|
|
1967
|
+
]);
|
|
1672
1968
|
var Spinner2 = () => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1673
1969
|
"svg",
|
|
1674
1970
|
{
|
|
1675
1971
|
role: "progressbar",
|
|
1676
1972
|
"aria-label": "Loading",
|
|
1677
|
-
className: "
|
|
1973
|
+
className: "relative z-10 animate-spin",
|
|
1678
1974
|
xmlns: "http://www.w3.org/2000/svg",
|
|
1679
1975
|
fill: "none",
|
|
1680
1976
|
viewBox: "0 0 24 24",
|
|
1977
|
+
width: "1em",
|
|
1978
|
+
height: "1em",
|
|
1979
|
+
style: { fontSize: "inherit" },
|
|
1681
1980
|
children: [
|
|
1682
1981
|
/* @__PURE__ */ jsxRuntime.jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
1683
1982
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1693,80 +1992,98 @@ var Spinner2 = () => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
|
1693
1992
|
);
|
|
1694
1993
|
var FAB = React.forwardRef(
|
|
1695
1994
|
({
|
|
1696
|
-
// Variant props
|
|
1697
|
-
size = "
|
|
1698
|
-
color = "primary",
|
|
1699
|
-
//
|
|
1995
|
+
// Variant props
|
|
1996
|
+
size = "fab",
|
|
1997
|
+
color = "primary-container",
|
|
1998
|
+
// Content
|
|
1700
1999
|
icon,
|
|
1701
2000
|
children,
|
|
1702
|
-
|
|
2001
|
+
// State
|
|
1703
2002
|
loading = false,
|
|
1704
2003
|
disableRipple = false,
|
|
2004
|
+
isDisabled = false,
|
|
2005
|
+
// Styling
|
|
1705
2006
|
className,
|
|
1706
|
-
//
|
|
1707
|
-
|
|
1708
|
-
onPress,
|
|
1709
|
-
onMouseDown,
|
|
2007
|
+
// Accessibility
|
|
2008
|
+
"aria-label": ariaLabel,
|
|
1710
2009
|
title,
|
|
2010
|
+
// Passthrough — forwarded to FABHeadless
|
|
2011
|
+
tabIndex = 0,
|
|
2012
|
+
type = "button",
|
|
2013
|
+
// Passed through to FABHeadless → useButton
|
|
1711
2014
|
...props
|
|
1712
2015
|
}, ref) => {
|
|
2016
|
+
const fabRef = React.useRef(null);
|
|
2017
|
+
const resolvedRef = ref ?? fabRef;
|
|
2018
|
+
const isFABDisabled = isDisabled || loading;
|
|
2019
|
+
const [isPressed, setIsPressed] = React.useState(false);
|
|
2020
|
+
const handlePressStart = React.useCallback(() => setIsPressed(true), []);
|
|
2021
|
+
const handlePressEnd = React.useCallback(() => setIsPressed(false), []);
|
|
2022
|
+
const { isHovered, hoverProps } = reactAria.useHover({ isDisabled: isFABDisabled });
|
|
2023
|
+
const { isFocusVisible, focusProps } = reactAria.useFocusRing();
|
|
2024
|
+
const { onMouseDown: handleRipple, ripples } = useRipple({
|
|
2025
|
+
disabled: isFABDisabled || disableRipple
|
|
2026
|
+
});
|
|
1713
2027
|
if (process.env.NODE_ENV === "development") {
|
|
1714
2028
|
if (!icon) {
|
|
1715
|
-
console.warn("[FAB] FAB must have an icon. Please provide the icon prop.");
|
|
2029
|
+
console.warn("[FAB] FAB must have an icon. Please provide the `icon` prop.");
|
|
1716
2030
|
}
|
|
1717
2031
|
if (size === "extended" && !children) {
|
|
1718
|
-
console.warn("[FAB] Extended FAB requires text label as children
|
|
2032
|
+
console.warn("[FAB] Extended FAB requires a text label as `children`.");
|
|
1719
2033
|
}
|
|
1720
2034
|
if (size !== "extended" && children) {
|
|
1721
2035
|
console.warn(
|
|
1722
|
-
"[FAB]
|
|
2036
|
+
"[FAB] `children` (text label) is only rendered for `size='extended'`. For icon-only FABs, use the `icon` prop only."
|
|
2037
|
+
);
|
|
2038
|
+
}
|
|
2039
|
+
if (size === "small") {
|
|
2040
|
+
console.warn(
|
|
2041
|
+
"[FAB] `size='small'` is deprecated in M3 Expressive. Use `size='fab'` (56dp) instead."
|
|
2042
|
+
);
|
|
2043
|
+
}
|
|
2044
|
+
if (color === "surface") {
|
|
2045
|
+
console.warn(
|
|
2046
|
+
"[FAB] `color='surface'` is deprecated in M3 Expressive. Use `color='primary-container'` instead."
|
|
1723
2047
|
);
|
|
1724
2048
|
}
|
|
1725
2049
|
}
|
|
1726
|
-
const isDisabled = propIsDisabled || loading;
|
|
1727
|
-
const { onMouseDown: handleRipple, ripples } = useRipple({
|
|
1728
|
-
disabled: isDisabled || disableRipple
|
|
1729
|
-
});
|
|
1730
|
-
const mergedOnMouseDown = (e) => {
|
|
1731
|
-
onMouseDown?.(e);
|
|
1732
|
-
handleRipple(e);
|
|
1733
|
-
};
|
|
1734
|
-
const mergedPropsValue = utils.mergeProps(props, {
|
|
1735
|
-
...onPress && { onPress },
|
|
1736
|
-
onMouseDown: mergedOnMouseDown,
|
|
1737
|
-
isDisabled
|
|
1738
|
-
});
|
|
1739
2050
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1740
2051
|
FABHeadless,
|
|
1741
2052
|
{
|
|
1742
|
-
|
|
2053
|
+
...reactAria.mergeProps(
|
|
2054
|
+
hoverProps,
|
|
2055
|
+
focusProps,
|
|
2056
|
+
{ onPressStart: handlePressStart, onPressEnd: handlePressEnd },
|
|
2057
|
+
props
|
|
2058
|
+
),
|
|
2059
|
+
ref: resolvedRef,
|
|
2060
|
+
type,
|
|
2061
|
+
isDisabled: isFABDisabled,
|
|
2062
|
+
tabIndex,
|
|
2063
|
+
onMouseDown: handleRipple,
|
|
2064
|
+
"aria-label": ariaLabel,
|
|
2065
|
+
...title !== void 0 && { title },
|
|
2066
|
+
...getInteractionDataAttributes({
|
|
2067
|
+
isHovered,
|
|
2068
|
+
isFocusVisible,
|
|
2069
|
+
isPressed,
|
|
2070
|
+
isDisabled: isFABDisabled
|
|
2071
|
+
}),
|
|
2072
|
+
"data-with-icon": icon ? "" : void 0,
|
|
2073
|
+
"data-loading": loading ? "" : void 0,
|
|
1743
2074
|
className: cn(
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
"
|
|
1747
|
-
"focus-visible:outline-primary focus-visible:outline-2 focus-visible:outline-offset-2",
|
|
1748
|
-
"shrink-0",
|
|
1749
|
-
// State layers (hover, focus, active)
|
|
1750
|
-
"before:absolute before:inset-0 before:rounded-[inherit] before:transition-opacity before:duration-200",
|
|
1751
|
-
"before:bg-current before:opacity-0",
|
|
1752
|
-
"hover:before:opacity-8",
|
|
1753
|
-
"focus-visible:before:opacity-12",
|
|
1754
|
-
"active:before:opacity-12",
|
|
1755
|
-
// Elevation
|
|
1756
|
-
"shadow-elevation-3 hover:shadow-elevation-4",
|
|
1757
|
-
// CVA variants
|
|
1758
|
-
fabVariants({ size, color, isDisabled }),
|
|
1759
|
-
// User custom classes
|
|
2075
|
+
fabVariants({ size, color }),
|
|
2076
|
+
// group/fab: enables group-data-[x]/fab child selectors in all slots
|
|
2077
|
+
"group/fab",
|
|
1760
2078
|
className
|
|
1761
2079
|
),
|
|
1762
|
-
"aria-label": ariaLabel,
|
|
1763
|
-
...title && { title },
|
|
1764
|
-
...mergedPropsValue,
|
|
1765
2080
|
children: [
|
|
1766
2081
|
ripples,
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
2082
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(fabStateLayerVariants({ color })), "aria-hidden": "true" }),
|
|
2083
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(fabFocusRingVariants()), "aria-hidden": "true" }),
|
|
2084
|
+
icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(fabIconVariants({ size, hidden: loading })), children: icon }),
|
|
2085
|
+
loading && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(fabIconVariants({ size })), children: /* @__PURE__ */ jsxRuntime.jsx(Spinner2, {}) }),
|
|
2086
|
+
size === "extended" && children && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(fabLabelVariants()), children })
|
|
1770
2087
|
]
|
|
1771
2088
|
}
|
|
1772
2089
|
);
|