@tinybigui/react 0.9.0 → 0.11.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 +16 -16
- package/dist/index.cjs +213 -166
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +102 -34
- package/dist/index.d.ts +102 -34
- package/dist/index.js +213 -166
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/styles.css.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ A modern, accessible React component library implementing Google's Material Desi
|
|
|
12
12
|
|
|
13
13
|
## ✅ Status
|
|
14
14
|
|
|
15
|
-
> **Latest Release: v0.
|
|
15
|
+
> **Latest Release: v0.11.0** (2026-06-09)
|
|
16
16
|
>
|
|
17
17
|
> **29 MD3 components** published to npm with full TypeScript support and WCAG 2.1 AA accessibility.
|
|
18
18
|
>
|
|
@@ -149,24 +149,24 @@ See [THEMING.md](./THEMING.md) for the full customization guide.
|
|
|
149
149
|
|
|
150
150
|
### Phase 2: Navigation ✅
|
|
151
151
|
|
|
152
|
-
| Component | Status | Description
|
|
153
|
-
| ------------------ | ------ |
|
|
154
|
-
| `AppBar` | ✅ |
|
|
155
|
-
| `Tabs` | ✅ | Primary and secondary tab variants
|
|
156
|
-
| `NavigationDrawer` | ✅ | Modal and standard navigation drawer
|
|
157
|
-
| `NavigationBar` | ✅ | Bottom navigation with badges
|
|
158
|
-
| `Search` | ✅ | SearchBar and SearchView overlay
|
|
152
|
+
| Component | Status | Description |
|
|
153
|
+
| ------------------ | ------ | ------------------------------------------------------------------- |
|
|
154
|
+
| `AppBar` | ✅ | M3 expressive flexible slot architecture, subtitle growth (v0.10.0) |
|
|
155
|
+
| `Tabs` | ✅ | Primary and secondary tab variants |
|
|
156
|
+
| `NavigationDrawer` | ✅ | Modal and standard navigation drawer |
|
|
157
|
+
| `NavigationBar` | ✅ | Bottom navigation with badges |
|
|
158
|
+
| `Search` | ✅ | SearchBar and SearchView overlay |
|
|
159
159
|
|
|
160
160
|
### Phase 3: Feedback ✅
|
|
161
161
|
|
|
162
|
-
| Component | Status | Description
|
|
163
|
-
| ------------- | ------ |
|
|
164
|
-
| `Dialog` | ✅ | Basic and fullscreen modal dialogs
|
|
165
|
-
| `Snackbar` | ✅ | Provider, stacking, imperative API
|
|
166
|
-
| `Menu` | ✅ | Dropdown, context menu, submenus
|
|
167
|
-
| `Progress` | ✅ | Linear and circular indicators
|
|
168
|
-
| `BottomSheet` | ✅ |
|
|
169
|
-
| `Tooltip` | ✅ | Plain and rich tooltip with positioning
|
|
162
|
+
| Component | Status | Description |
|
|
163
|
+
| ------------- | ------ | ---------------------------------------------------------------- |
|
|
164
|
+
| `Dialog` | ✅ | Basic and fullscreen modal dialogs |
|
|
165
|
+
| `Snackbar` | ✅ | Provider, stacking, imperative API |
|
|
166
|
+
| `Menu` | ✅ | Dropdown, context menu, submenus |
|
|
167
|
+
| `Progress` | ✅ | Linear and circular indicators |
|
|
168
|
+
| `BottomSheet` | ✅ | MD3 expressive handle, variants-vs-states architecture (v0.11.0) |
|
|
169
|
+
| `Tooltip` | ✅ | Plain and rich tooltip with positioning |
|
|
170
170
|
|
|
171
171
|
### Phase 4: Data Display ✅
|
|
172
172
|
|
package/dist/index.cjs
CHANGED
|
@@ -211,65 +211,111 @@ function useScrollElevation(options = {}) {
|
|
|
211
211
|
};
|
|
212
212
|
}
|
|
213
213
|
var AppBarHeadless = React.forwardRef(
|
|
214
|
-
({ className, children, scrolled: scrolledProp, onScrollStateChange }, ref) => {
|
|
214
|
+
({ className, children, scrolled: scrolledProp, onScrollStateChange, ...htmlProps }, ref) => {
|
|
215
215
|
const { isScrolled } = useScrollElevation({
|
|
216
216
|
scrolled: scrolledProp,
|
|
217
217
|
onScrollStateChange
|
|
218
218
|
});
|
|
219
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
219
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
220
|
+
"header",
|
|
221
|
+
{
|
|
222
|
+
...htmlProps,
|
|
223
|
+
ref,
|
|
224
|
+
role: "banner",
|
|
225
|
+
className,
|
|
226
|
+
"data-scrolled": isScrolled ? "" : void 0,
|
|
227
|
+
children
|
|
228
|
+
}
|
|
229
|
+
);
|
|
220
230
|
}
|
|
221
231
|
);
|
|
222
232
|
AppBarHeadless.displayName = "AppBarHeadless";
|
|
223
233
|
var appBarVariants = classVarianceAuthority.cva(
|
|
224
234
|
[
|
|
225
|
-
//
|
|
226
|
-
"w-full",
|
|
235
|
+
// Layout
|
|
236
|
+
"w-full flex flex-col",
|
|
237
|
+
// Color (base — at rest)
|
|
227
238
|
"bg-surface text-on-surface",
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
239
|
+
// Elevation base
|
|
240
|
+
"shadow-elevation-0",
|
|
241
|
+
// Scroll state — effects properties animated with standard spring (no overshoot)
|
|
242
|
+
"transition-[background-color,box-shadow]",
|
|
243
|
+
"duration-spring-standard-default-effects",
|
|
244
|
+
"ease-spring-standard-default-effects",
|
|
245
|
+
// On scroll: surface-container background + elevation-2
|
|
246
|
+
"group-data-[scrolled]/appbar:bg-surface-container",
|
|
247
|
+
"group-data-[scrolled]/appbar:shadow-elevation-2"
|
|
231
248
|
],
|
|
232
249
|
{
|
|
233
250
|
variants: {
|
|
234
251
|
/**
|
|
235
|
-
* Size variant
|
|
236
|
-
*
|
|
252
|
+
* Size variant — controls bar height and which title row is shown.
|
|
253
|
+
* With-subtitle height growth is handled via group-data-[with-subtitle]/appbar below.
|
|
237
254
|
*/
|
|
238
255
|
variant: {
|
|
239
|
-
/** 64dp
|
|
256
|
+
/** 64dp fixed — title left-aligned in top row */
|
|
240
257
|
small: "h-appbar-small",
|
|
241
|
-
/** 64dp
|
|
242
|
-
"center-aligned": "h-appbar-small
|
|
243
|
-
/**
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
258
|
+
/** 64dp fixed — title centered in top row */
|
|
259
|
+
"center-aligned": "h-appbar-small",
|
|
260
|
+
/**
|
|
261
|
+
* 112dp no-subtitle / 136dp with-subtitle — title in expanded bottom row.
|
|
262
|
+
* group-data-[with-subtitle]/appbar switches to the taller token.
|
|
263
|
+
*/
|
|
264
|
+
medium: [
|
|
265
|
+
"min-h-appbar-medium",
|
|
266
|
+
"group-data-[with-subtitle]/appbar:min-h-appbar-medium-subtitle"
|
|
267
|
+
],
|
|
268
|
+
/**
|
|
269
|
+
* 120dp no-subtitle / 152dp with-subtitle — title in expanded bottom row.
|
|
270
|
+
* group-data-[with-subtitle]/appbar switches to the taller token.
|
|
271
|
+
*/
|
|
272
|
+
large: [
|
|
273
|
+
"min-h-appbar-large",
|
|
274
|
+
"group-data-[with-subtitle]/appbar:min-h-appbar-large-subtitle"
|
|
275
|
+
]
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
defaultVariants: {
|
|
279
|
+
variant: "small"
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
);
|
|
283
|
+
var appBarTopRowVariants = classVarianceAuthority.cva(["flex items-center justify-between", "px-1"], {
|
|
284
|
+
variants: {
|
|
285
|
+
variant: {
|
|
286
|
+
small: "flex-1",
|
|
287
|
+
"center-aligned": "flex-1",
|
|
288
|
+
medium: "h-16 shrink-0",
|
|
289
|
+
large: "h-16 shrink-0"
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
defaultVariants: {
|
|
293
|
+
variant: "small"
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
var appBarLeadingVariants = classVarianceAuthority.cva(["flex shrink-0 items-center", "text-on-surface"]);
|
|
297
|
+
var appBarHeadlineBlockVariants = classVarianceAuthority.cva(
|
|
298
|
+
["flex min-w-0 flex-1 flex-col justify-center", "px-1"],
|
|
299
|
+
{
|
|
300
|
+
variants: {
|
|
301
|
+
variant: {
|
|
302
|
+
small: "",
|
|
303
|
+
"center-aligned": "items-center text-center",
|
|
304
|
+
medium: "",
|
|
305
|
+
large: ""
|
|
255
306
|
}
|
|
256
307
|
},
|
|
257
308
|
defaultVariants: {
|
|
258
|
-
variant: "small"
|
|
259
|
-
scrolled: false
|
|
309
|
+
variant: "small"
|
|
260
310
|
}
|
|
261
311
|
}
|
|
262
312
|
);
|
|
263
313
|
var appBarTitleVariants = classVarianceAuthority.cva("text-on-surface font-normal", {
|
|
264
314
|
variants: {
|
|
265
315
|
variant: {
|
|
266
|
-
/** title-large: 22px / 28px line-height */
|
|
267
316
|
small: "text-title-large truncate",
|
|
268
|
-
/** title-large: 22px / 28px line-height, centered */
|
|
269
317
|
"center-aligned": "text-title-large truncate",
|
|
270
|
-
/** headline-medium: 28px / 36px line-height */
|
|
271
318
|
medium: "text-headline-medium",
|
|
272
|
-
/** display-small: 36px / 44px line-height */
|
|
273
319
|
large: "text-display-small"
|
|
274
320
|
}
|
|
275
321
|
},
|
|
@@ -277,23 +323,27 @@ var appBarTitleVariants = classVarianceAuthority.cva("text-on-surface font-norma
|
|
|
277
323
|
variant: "small"
|
|
278
324
|
}
|
|
279
325
|
});
|
|
280
|
-
var appBarSubtitleVariants = classVarianceAuthority.cva("font-normal", {
|
|
326
|
+
var appBarSubtitleVariants = classVarianceAuthority.cva("text-on-surface-variant font-normal", {
|
|
281
327
|
variants: {
|
|
282
328
|
variant: {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
/** title-large: 22px / 28px, on-surface color */
|
|
288
|
-
medium: "text-title-large text-on-surface",
|
|
289
|
-
/** headline-small: 24px / 32px, on-surface color */
|
|
290
|
-
large: "text-headline-small text-on-surface"
|
|
329
|
+
small: "text-label-medium truncate",
|
|
330
|
+
"center-aligned": "text-label-medium truncate",
|
|
331
|
+
medium: "text-label-large",
|
|
332
|
+
large: "text-title-medium"
|
|
291
333
|
}
|
|
292
334
|
},
|
|
293
335
|
defaultVariants: {
|
|
294
336
|
variant: "small"
|
|
295
337
|
}
|
|
296
338
|
});
|
|
339
|
+
var appBarTrailingVariants = classVarianceAuthority.cva([
|
|
340
|
+
"flex shrink-0 items-center gap-0.5",
|
|
341
|
+
"text-on-surface-variant"
|
|
342
|
+
]);
|
|
343
|
+
var appBarExpandedTitleVariants = classVarianceAuthority.cva([
|
|
344
|
+
"flex flex-1 flex-col justify-end",
|
|
345
|
+
"gap-0.5 px-4 pb-4"
|
|
346
|
+
]);
|
|
297
347
|
var AppBar = React.forwardRef(
|
|
298
348
|
({
|
|
299
349
|
variant = "small",
|
|
@@ -310,76 +360,54 @@ var AppBar = React.forwardRef(
|
|
|
310
360
|
onScrollStateChange
|
|
311
361
|
});
|
|
312
362
|
const isExpandedVariant = variant === "medium" || variant === "large";
|
|
363
|
+
const hasSubtitle = subtitle != null;
|
|
313
364
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
314
365
|
AppBarHeadless,
|
|
315
366
|
{
|
|
316
367
|
ref,
|
|
317
368
|
scrolled: isScrolled,
|
|
318
|
-
className: cn(
|
|
369
|
+
className: cn(
|
|
370
|
+
appBarVariants({ variant }),
|
|
371
|
+
// group/appbar: enables group-data-[scrolled]/appbar and
|
|
372
|
+
// group-data-[with-subtitle]/appbar child selectors in all slots
|
|
373
|
+
"group/appbar",
|
|
374
|
+
className
|
|
375
|
+
),
|
|
376
|
+
"data-with-subtitle": hasSubtitle ? "" : void 0,
|
|
319
377
|
children: [
|
|
320
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
321
|
-
"div",
|
|
322
|
-
{
|
|
323
|
-
"data-
|
|
324
|
-
|
|
325
|
-
"
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
)
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
),
|
|
354
|
-
actions != null && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-slot": "actions", className: "flex shrink-0 items-center gap-0.5", children: actions })
|
|
355
|
-
]
|
|
356
|
-
}
|
|
357
|
-
),
|
|
358
|
-
isExpandedVariant && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
359
|
-
"div",
|
|
360
|
-
{
|
|
361
|
-
"data-slot": "expanded-title",
|
|
362
|
-
className: cn("flex flex-1 flex-col justify-end", "gap-0.5 px-4 pb-4"),
|
|
363
|
-
children: [
|
|
364
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
365
|
-
"span",
|
|
366
|
-
{
|
|
367
|
-
"data-testid": "appbar-title",
|
|
368
|
-
className: cn("min-w-0", appBarTitleVariants({ variant })),
|
|
369
|
-
children: title
|
|
370
|
-
}
|
|
371
|
-
),
|
|
372
|
-
subtitle != null && /* @__PURE__ */ jsxRuntime.jsx(
|
|
373
|
-
"span",
|
|
374
|
-
{
|
|
375
|
-
"data-testid": "appbar-subtitle",
|
|
376
|
-
className: cn("min-w-0", appBarSubtitleVariants({ variant })),
|
|
377
|
-
children: subtitle
|
|
378
|
-
}
|
|
379
|
-
)
|
|
380
|
-
]
|
|
381
|
-
}
|
|
382
|
-
)
|
|
378
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { "data-slot": "top-row", className: cn(appBarTopRowVariants({ variant })), children: [
|
|
379
|
+
navigationIcon != null && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-slot": "navigation", className: cn(appBarLeadingVariants()), children: navigationIcon }),
|
|
380
|
+
!isExpandedVariant && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(appBarHeadlineBlockVariants({ variant })), children: [
|
|
381
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "data-testid": "appbar-title", className: cn(appBarTitleVariants({ variant })), children: title }),
|
|
382
|
+
hasSubtitle && /* @__PURE__ */ jsxRuntime.jsx(
|
|
383
|
+
"span",
|
|
384
|
+
{
|
|
385
|
+
"data-testid": "appbar-subtitle",
|
|
386
|
+
className: cn(appBarSubtitleVariants({ variant })),
|
|
387
|
+
children: subtitle
|
|
388
|
+
}
|
|
389
|
+
)
|
|
390
|
+
] }),
|
|
391
|
+
actions != null && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-slot": "actions", className: cn(appBarTrailingVariants()), children: actions })
|
|
392
|
+
] }),
|
|
393
|
+
isExpandedVariant && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-slot": "expanded-title", className: cn(appBarExpandedTitleVariants()), children: [
|
|
394
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
395
|
+
"span",
|
|
396
|
+
{
|
|
397
|
+
"data-testid": "appbar-title",
|
|
398
|
+
className: cn("min-w-0", appBarTitleVariants({ variant })),
|
|
399
|
+
children: title
|
|
400
|
+
}
|
|
401
|
+
),
|
|
402
|
+
hasSubtitle && /* @__PURE__ */ jsxRuntime.jsx(
|
|
403
|
+
"span",
|
|
404
|
+
{
|
|
405
|
+
"data-testid": "appbar-subtitle",
|
|
406
|
+
className: cn("min-w-0", appBarSubtitleVariants({ variant })),
|
|
407
|
+
children: subtitle
|
|
408
|
+
}
|
|
409
|
+
)
|
|
410
|
+
] })
|
|
383
411
|
]
|
|
384
412
|
}
|
|
385
413
|
);
|
|
@@ -11132,7 +11160,7 @@ var BottomSheetModalPanel = ({
|
|
|
11132
11160
|
"aria-modal": "true",
|
|
11133
11161
|
className: cn(className, getAnimationClassName?.(animationState)),
|
|
11134
11162
|
"data-animation-state": animationState,
|
|
11135
|
-
"data-dragging": isDragging
|
|
11163
|
+
"data-dragging": isDragging ? "" : void 0,
|
|
11136
11164
|
style: panelStyle,
|
|
11137
11165
|
onTransitionEnd,
|
|
11138
11166
|
children
|
|
@@ -11269,7 +11297,7 @@ var BottomSheetHeadless = React.forwardRef(
|
|
|
11269
11297
|
ref,
|
|
11270
11298
|
className: cn(className, getAnimationClassName?.(animationState)),
|
|
11271
11299
|
"data-animation-state": animationState,
|
|
11272
|
-
"data-dragging": isDragging
|
|
11300
|
+
"data-dragging": isDragging ? "" : void 0,
|
|
11273
11301
|
style: panelStyle,
|
|
11274
11302
|
onTransitionEnd: handleTransitionEnd,
|
|
11275
11303
|
children
|
|
@@ -11284,7 +11312,6 @@ var bottomSheetAnimationVariants = classVarianceAuthority.cva("", {
|
|
|
11284
11312
|
variants: {
|
|
11285
11313
|
animationState: {
|
|
11286
11314
|
// entering: initial mount frame — sheet starts below viewport (translateY(100%))
|
|
11287
|
-
// The CSS is handled inside animate-md-slide-in-bottom keyframes
|
|
11288
11315
|
entering: ["opacity-0"],
|
|
11289
11316
|
// visible: entry animation active — animate-md-slide-in-bottom runs once
|
|
11290
11317
|
visible: ["animate-md-slide-in-bottom"],
|
|
@@ -11301,52 +11328,38 @@ var bottomSheetAnimationVariants = classVarianceAuthority.cva("", {
|
|
|
11301
11328
|
var bottomSheetVariants = classVarianceAuthority.cva(
|
|
11302
11329
|
[
|
|
11303
11330
|
// Position: fixed to bottom edge, full width
|
|
11304
|
-
"fixed",
|
|
11305
|
-
"bottom-0",
|
|
11306
|
-
"left-0",
|
|
11307
|
-
"right-0",
|
|
11331
|
+
"fixed bottom-0 left-0 right-0",
|
|
11308
11332
|
// Surface token
|
|
11309
11333
|
"bg-surface-container-low",
|
|
11310
11334
|
// Elevation level 1 per MD3 spec
|
|
11311
11335
|
"shadow-elevation-1",
|
|
11312
|
-
// Shape: extra-large top corners (28dp), bottom
|
|
11336
|
+
// Shape: extra-large top corners (28dp), square bottom (screen-attached)
|
|
11337
|
+
// NOTE: measurement-derived value from MD3 spec; permitted exception per component-variants rule
|
|
11313
11338
|
"rounded-t-xl",
|
|
11314
11339
|
// Layout
|
|
11315
|
-
"flex",
|
|
11316
|
-
|
|
11317
|
-
// Max width constraint (full width up to 640dp)
|
|
11340
|
+
"flex flex-col",
|
|
11341
|
+
// Width constraint (full width up to 640dp)
|
|
11318
11342
|
"mx-auto",
|
|
11319
11343
|
// NOTE: measurement-derived value from MD3 spec; permitted exception
|
|
11320
11344
|
"w-[640px] max-w-full",
|
|
11321
|
-
// Clip content during height transitions
|
|
11345
|
+
// Clip content during height transitions
|
|
11322
11346
|
"overflow-hidden",
|
|
11323
|
-
//
|
|
11324
|
-
// Standard personality, default speed tier, spatial: no overshoot.
|
|
11325
|
-
// During drag, data-[dragging=true]:transition-none suppresses this so the
|
|
11326
|
-
// sheet height follows the pointer 1:1 without transition lag.
|
|
11327
|
-
// After drag release, the spring transition animates height to the new snap position.
|
|
11347
|
+
// Snap spring: spatial property (height), standard personality, default tier
|
|
11328
11348
|
"transition-[height]",
|
|
11329
11349
|
"duration-spring-standard-default-spatial",
|
|
11330
11350
|
"ease-spring-standard-default-spatial",
|
|
11331
|
-
|
|
11351
|
+
// Suppress spring while dragging so the sheet follows the pointer 1:1
|
|
11352
|
+
"data-[dragging]:transition-none",
|
|
11332
11353
|
"will-change-[height]",
|
|
11333
|
-
// Responsive layout:
|
|
11334
|
-
// The sheet remains bottom-anchored at all sizes. Side centering is handled by
|
|
11335
|
-
// mx-auto + max-w-[640px] — at 752dp viewport this naturally produces 56dp side
|
|
11336
|
-
// margins on each side (exactly matching MD3 measurements).
|
|
11337
|
-
// Top margin is expressed as max-height so the sheet cannot overlap the top edge:
|
|
11338
|
-
// - Default: 72dp top margin (max-h-[calc(100vh-72px)])
|
|
11339
|
-
// - Wide viewport (> 640dp): 56dp top margin (sm:max-h-[calc(100vh-56px)])
|
|
11354
|
+
// Responsive layout: top margin expressed as max-height
|
|
11340
11355
|
// NOTE: measurement-derived values from MD3 spec; permitted exception
|
|
11341
11356
|
"max-h-[calc(100vh-72px)]",
|
|
11342
|
-
"sm:max-h-[calc(100vh-56px)]"
|
|
11343
|
-
// Top corners rounded at wide layout (sheet floats away from screen edge)
|
|
11344
|
-
"rounded-t-xl"
|
|
11357
|
+
"sm:max-h-[calc(100vh-56px)]"
|
|
11345
11358
|
],
|
|
11346
11359
|
{
|
|
11347
11360
|
variants: {
|
|
11348
11361
|
variant: {
|
|
11349
|
-
// Modal: above scrim (z-50)
|
|
11362
|
+
// Modal: rendered above the scrim (z-50)
|
|
11350
11363
|
modal: "z-50",
|
|
11351
11364
|
// Standard: sits above normal content but below overlays
|
|
11352
11365
|
standard: "z-10"
|
|
@@ -11358,62 +11371,96 @@ var bottomSheetVariants = classVarianceAuthority.cva(
|
|
|
11358
11371
|
}
|
|
11359
11372
|
);
|
|
11360
11373
|
var bottomSheetScrimVariants = classVarianceAuthority.cva([
|
|
11361
|
-
"fixed",
|
|
11362
|
-
"
|
|
11363
|
-
|
|
11364
|
-
"
|
|
11365
|
-
"opacity-32",
|
|
11366
|
-
"transition-opacity",
|
|
11367
|
-
"duration-short4",
|
|
11368
|
-
"ease-standard"
|
|
11374
|
+
"fixed inset-0 z-40",
|
|
11375
|
+
"bg-scrim opacity-32",
|
|
11376
|
+
// Screen-level effects transition (scrim enters/exits the screen, not an on-screen state change)
|
|
11377
|
+
"transition-opacity duration-short4 ease-standard"
|
|
11369
11378
|
]);
|
|
11370
11379
|
var bottomSheetHandleWrapperVariants = classVarianceAuthority.cva([
|
|
11371
|
-
// Center the
|
|
11372
|
-
"flex",
|
|
11373
|
-
|
|
11374
|
-
"justify-center",
|
|
11375
|
-
// Top/bottom padding creates the 48dp touch target area
|
|
11376
|
-
// 22dp top + 4dp handle + 22dp bottom ≈ 48dp interaction zone (per MD3 measurements)
|
|
11380
|
+
// Center the pill horizontally; provide positioning context for overlays
|
|
11381
|
+
"relative flex items-center justify-center w-full",
|
|
11382
|
+
// 48dp touch target (22dp top + 4dp pill + 22dp bottom)
|
|
11377
11383
|
// NOTE: measurement-derived value from MD3 spec; permitted exception
|
|
11378
11384
|
"py-[22px]",
|
|
11379
|
-
//
|
|
11380
|
-
"w-full",
|
|
11381
|
-
// Focus ring styling for keyboard/switch navigation
|
|
11382
|
-
// MD3 spec: focus indicator color = secondary, thickness = 3dp, offset = 2dp
|
|
11385
|
+
// Suppress browser default focus outline — the focus-ring overlay slot handles it
|
|
11383
11386
|
"focus-visible:outline-none",
|
|
11384
|
-
|
|
11385
|
-
"focus-visible:ring-secondary",
|
|
11386
|
-
"focus-visible:ring-offset-2",
|
|
11387
|
-
"focus-visible:rounded-sm",
|
|
11388
|
-
// Cursor affordance
|
|
11387
|
+
// Cursor affordance for drag interaction
|
|
11389
11388
|
"cursor-ns-resize"
|
|
11390
11389
|
]);
|
|
11390
|
+
var bottomSheetHandleStateLayerVariants = classVarianceAuthority.cva([
|
|
11391
|
+
// Overlay positioned centrally — sits behind the pill
|
|
11392
|
+
"absolute pointer-events-none",
|
|
11393
|
+
// Pill-shaped to complement the handle's form
|
|
11394
|
+
"rounded-full",
|
|
11395
|
+
// Sized wider than the pill to provide a visible state layer halo
|
|
11396
|
+
// 48dp wide × 16dp tall — centred by the flex wrapper
|
|
11397
|
+
"w-12 h-4",
|
|
11398
|
+
// State-layer color (same role as the pill)
|
|
11399
|
+
"bg-on-surface-variant",
|
|
11400
|
+
// Effects transition — opacity must NOT overshoot
|
|
11401
|
+
"transition-opacity duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
|
|
11402
|
+
// Opacity at rest
|
|
11403
|
+
"opacity-0",
|
|
11404
|
+
// Hover: 8%
|
|
11405
|
+
"group-data-[hovered]/handle:opacity-8",
|
|
11406
|
+
// Focus-visible: 10%
|
|
11407
|
+
"group-data-[focus-visible]/handle:opacity-10",
|
|
11408
|
+
// Pressed: 10% (doubled selector wins over hover at same cascade position)
|
|
11409
|
+
"group-data-[pressed]/handle:group-data-[pressed]/handle:opacity-10",
|
|
11410
|
+
// Dragging: 16% (MD3 dragged state — highest on-screen opacity)
|
|
11411
|
+
// Doubled selector wins over hover + pressed
|
|
11412
|
+
"group-data-[dragging]/handle:group-data-[dragging]/handle:opacity-16"
|
|
11413
|
+
]);
|
|
11414
|
+
var bottomSheetHandleFocusRingVariants = classVarianceAuthority.cva([
|
|
11415
|
+
"absolute pointer-events-none",
|
|
11416
|
+
"rounded-full",
|
|
11417
|
+
// Sized to sit around the state layer halo
|
|
11418
|
+
"w-14 h-5",
|
|
11419
|
+
// MD3 focus indicator: secondary color, 2dp weight
|
|
11420
|
+
"outline outline-2 outline-offset-0 outline-secondary",
|
|
11421
|
+
// Effects transition — opacity change must NOT overshoot
|
|
11422
|
+
"transition-opacity duration-spring-standard-fast-effects ease-spring-standard-fast-effects",
|
|
11423
|
+
// Hidden at rest; shown on keyboard/programmatic focus
|
|
11424
|
+
"opacity-0",
|
|
11425
|
+
"group-data-[focus-visible]/handle:opacity-100"
|
|
11426
|
+
]);
|
|
11391
11427
|
var bottomSheetHandlePillVariants = classVarianceAuthority.cva([
|
|
11428
|
+
"relative z-10 pointer-events-none",
|
|
11392
11429
|
"bg-on-surface-variant",
|
|
11393
|
-
"opacity-40",
|
|
11394
11430
|
"rounded-full",
|
|
11395
11431
|
// Dimensions: 32dp × 4dp per MD3 spec (measurement-derived; permitted exception)
|
|
11396
11432
|
"w-8",
|
|
11397
|
-
// 32dp = 2rem
|
|
11398
|
-
"h-1"
|
|
11399
|
-
// 4dp
|
|
11400
|
-
// Pill itself is decorative; the wrapper handles interaction
|
|
11401
|
-
"pointer-events-none"
|
|
11433
|
+
// 32dp = 2rem
|
|
11434
|
+
"h-1"
|
|
11435
|
+
// 4dp = 0.25rem
|
|
11402
11436
|
]);
|
|
11403
11437
|
function BottomSheetHandle({
|
|
11404
11438
|
className,
|
|
11405
11439
|
"aria-label": ariaLabelOverride
|
|
11406
11440
|
}) {
|
|
11407
11441
|
const { handleProps, isDragging } = useBottomSheetContext();
|
|
11408
|
-
|
|
11442
|
+
const { isHovered, hoverProps } = reactAria.useHover({});
|
|
11443
|
+
const { isFocusVisible, focusProps } = reactAria.useFocusRing();
|
|
11444
|
+
const mergedHandleProps = reactAria.mergeProps(handleProps, hoverProps, focusProps);
|
|
11445
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11409
11446
|
"div",
|
|
11410
11447
|
{
|
|
11411
|
-
...
|
|
11448
|
+
...mergedHandleProps,
|
|
11412
11449
|
...ariaLabelOverride !== void 0 ? { "aria-label": ariaLabelOverride } : {},
|
|
11413
|
-
className: cn(bottomSheetHandleWrapperVariants(), className),
|
|
11450
|
+
className: cn(bottomSheetHandleWrapperVariants(), "group/handle", className),
|
|
11414
11451
|
"data-testid": "bottom-sheet-handle",
|
|
11415
|
-
|
|
11416
|
-
|
|
11452
|
+
...getInteractionDataAttributes({
|
|
11453
|
+
isHovered,
|
|
11454
|
+
isFocusVisible,
|
|
11455
|
+
// Treat active drag as pressed — drives the state layer to 10% opacity
|
|
11456
|
+
isPressed: isDragging
|
|
11457
|
+
}),
|
|
11458
|
+
"data-dragging": isDragging ? "" : void 0,
|
|
11459
|
+
children: [
|
|
11460
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(bottomSheetHandleStateLayerVariants()), "aria-hidden": "true" }),
|
|
11461
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(bottomSheetHandleFocusRingVariants()), "aria-hidden": "true" }),
|
|
11462
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(bottomSheetHandlePillVariants()), "aria-hidden": "true" })
|
|
11463
|
+
]
|
|
11417
11464
|
}
|
|
11418
11465
|
);
|
|
11419
11466
|
}
|