@tinybigui/react 0.11.0 → 0.11.1

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 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.11.0** (2026-06-09)
15
+ > **Latest Release: v0.11.1** (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
  >
@@ -170,15 +170,15 @@ See [THEMING.md](./THEMING.md) for the full customization guide.
170
170
 
171
171
  ### Phase 4: Data Display ✅
172
172
 
173
- | Component | Status | Description |
174
- | ------------ | ------ | --------------------------------------------------------------- |
175
- | `Card` | ✅ | Elevated, filled, outlined variants |
176
- | `List` | ✅ | Static and interactive list items |
177
- | `Chip` | ✅ | MD3 expressive slot architecture, elevated surface (v0.9.0) |
178
- | `Badge` | ✅ | MD3 expressive dot/count badges, icon-corner anchoring (v0.8.0) |
179
- | `Divider` | ✅ | Horizontal/vertical, inset variants |
180
- | `DatePicker` | ✅ | Docked, modal, and input variants |
181
- | `TimePicker` | ✅ | 12h/24h clock dial, range selection |
173
+ | Component | Status | Description |
174
+ | ------------ | ------ | -------------------------------------------------------------------- |
175
+ | `Card` | ✅ | MD3 motion tier, media aspect-ratio fix, CVA export parity (v0.11.1) |
176
+ | `List` | ✅ | Static and interactive list items |
177
+ | `Chip` | ✅ | MD3 expressive slot architecture, elevated surface (v0.9.0) |
178
+ | `Badge` | ✅ | MD3 expressive dot/count badges, icon-corner anchoring (v0.8.0) |
179
+ | `Divider` | ✅ | Horizontal/vertical, inset variants |
180
+ | `DatePicker` | ✅ | Docked, modal, and input variants |
181
+ | `TimePicker` | ✅ | 12h/24h clock dial, range selection |
182
182
 
183
183
  ### Planned
184
184
 
package/dist/index.cjs CHANGED
@@ -5403,28 +5403,42 @@ var ProgressHeadless = React.forwardRef(
5403
5403
  }
5404
5404
  );
5405
5405
  ProgressHeadless.displayName = "ProgressHeadless";
5406
- var CardHeadless = React.forwardRef(function CardHeadless2({ className, children, ...ariaButtonProps }, forwardedRef) {
5406
+ var CardHeadless = React.forwardRef(function CardHeadless2({ className, children, onMouseDown, onMouseUp, onMouseLeave, ...rest }, forwardedRef) {
5407
5407
  const internalRef = React.useRef(null);
5408
5408
  const ref = forwardedRef ?? internalRef;
5409
- const isInteractive = !!(ariaButtonProps.onPress ?? ariaButtonProps.href);
5410
- const { buttonProps } = reactAria.useButton({ elementType: "div", ...ariaButtonProps }, ref);
5411
- const { focusProps, isFocusVisible } = reactAria.useFocusRing();
5409
+ const isInteractive = !!(rest.onPress ?? rest.href);
5410
+ const { buttonProps } = reactAria.useButton({ elementType: "div", ...rest }, ref);
5411
+ const {
5412
+ isDisabled: _isDisabled,
5413
+ onPress: _onPress,
5414
+ onPressStart: _onPressStart,
5415
+ onPressEnd: _onPressEnd,
5416
+ onPressChange: _onPressChange,
5417
+ onPressUp: _onPressUp,
5418
+ href: _href,
5419
+ target: _target,
5420
+ rel: _rel,
5421
+ ...htmlAttrs
5422
+ } = rest;
5423
+ const mouseHandlers = { onMouseDown, onMouseUp, onMouseLeave };
5412
5424
  if (isInteractive) {
5413
- const interactiveProps = utils.mergeProps(buttonProps, focusProps, {
5414
- className,
5415
- "data-focus-visible": isFocusVisible ? "true" : void 0
5416
- });
5425
+ const interactiveProps = utils.mergeProps(buttonProps, mouseHandlers, htmlAttrs, { className });
5417
5426
  return /* @__PURE__ */ jsxRuntime.jsx("div", { ...interactiveProps, ref, children });
5418
5427
  }
5419
- return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "article", className, ref, children });
5428
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "article", className, ref, ...mouseHandlers, ...htmlAttrs, children });
5420
5429
  });
5421
5430
  CardHeadless.displayName = "CardHeadless";
5422
5431
  var cardVariants = classVarianceAuthority.cva(
5423
5432
  [
5424
5433
  // Shape: MD3 medium corner = 12dp
5425
- "relative overflow-hidden rounded-md",
5426
- // Shadow transition (effects propertyuse spring standard fast effects)
5427
- "transition-shadow duration-spring-standard-fast-effects ease-spring-standard-fast-effects"
5434
+ "relative overflow-hidden rounded-md text-on-surface",
5435
+ // Transition: effects propertiesstandard default tier (cards are standard-size, not <48dp)
5436
+ // Covers shadow (elevation), opacity (disabled fade), border-color (outlined state)
5437
+ "transition-[box-shadow,opacity,border-color] duration-spring-standard-default-effects ease-spring-standard-default-effects",
5438
+ // Interactive affordance (content flag set by the component)
5439
+ "data-[interactive]:cursor-pointer",
5440
+ // Disabled — self-targeting selectors (38% container, no interaction)
5441
+ "data-[disabled]:cursor-not-allowed data-[disabled]:pointer-events-none data-[disabled]:opacity-38"
5428
5442
  ],
5429
5443
  {
5430
5444
  variants: {
@@ -5432,92 +5446,74 @@ var cardVariants = classVarianceAuthority.cva(
5432
5446
  * Card visual variant per MD3 specification.
5433
5447
  */
5434
5448
  variant: {
5435
- elevated: ["shadow-elevation-1", "hover:shadow-elevation-2"],
5436
- filled: ["shadow-elevation-0"],
5437
- outlined: ["border", "border-outline-variant", "shadow-elevation-0"]
5438
- },
5439
- /**
5440
- * Whether the card is interactive (has onPress or href).
5441
- * Interactive cards gain a cursor, keyboard focus ring, and state layer.
5442
- */
5443
- isInteractive: {
5444
- true: [
5445
- "cursor-pointer",
5446
- "focus-visible:outline-2",
5447
- "focus-visible:outline-primary",
5448
- "focus-visible:outline-offset-2"
5449
+ /**
5450
+ * Elevated — separation via shadow.
5451
+ * MD3: container=surface-container-low.
5452
+ * Elevation: 1 base → 2 hover → 1 focus → 1 pressed → 4 dragged.
5453
+ */
5454
+ elevated: [
5455
+ "bg-surface-container-low",
5456
+ "shadow-elevation-1",
5457
+ "data-[hovered]:shadow-elevation-2",
5458
+ "data-[focus-visible]:shadow-elevation-1",
5459
+ "data-[pressed]:data-[pressed]:shadow-elevation-1",
5460
+ "data-[dragged]:data-[dragged]:data-[dragged]:shadow-elevation-4",
5461
+ "data-[disabled]:shadow-none"
5449
5462
  ],
5450
- false: "cursor-default"
5451
- },
5452
- /**
5453
- * Whether the card is currently being dragged.
5454
- * Applies elevated shadow level 4 with a slower, more intentional transition
5455
- * to communicate physical lift per MD3 motion spec.
5456
- */
5457
- isDragged: {
5458
- true: [
5459
- "shadow-elevation-4",
5460
- // Override base transition to use a slower, decelerate curve for drag onset
5461
- "duration-medium2",
5462
- "ease-emphasized-decelerate"
5463
+ /**
5464
+ * Filled — subtle container fill, no resting shadow.
5465
+ * MD3: container=surface-container-highest.
5466
+ * Elevation: 0 base 1 hover → 0 focus → 0 pressed → 3 dragged.
5467
+ */
5468
+ filled: [
5469
+ "bg-surface-container-highest",
5470
+ "shadow-none",
5471
+ "data-[hovered]:shadow-elevation-1",
5472
+ "data-[focus-visible]:shadow-none",
5473
+ "data-[pressed]:data-[pressed]:shadow-none",
5474
+ "data-[dragged]:data-[dragged]:data-[dragged]:shadow-elevation-3",
5475
+ "data-[disabled]:shadow-none"
5463
5476
  ],
5464
- false: ""
5465
- },
5466
- /**
5467
- * Whether the card is disabled.
5468
- * MD3 spec: 38% opacity, no pointer events.
5469
- */
5470
- isDisabled: {
5471
- true: ["opacity-38", "pointer-events-none"],
5472
- false: ""
5477
+ /**
5478
+ * Outlined — visual boundary via border, no resting shadow.
5479
+ * MD3: container=surface, outline=outline-variant.
5480
+ * Elevation: 0 base 1 hover → 0 focus → 0 pressed → 3 dragged.
5481
+ */
5482
+ outlined: [
5483
+ "bg-surface border border-outline-variant",
5484
+ "shadow-none",
5485
+ "data-[hovered]:shadow-elevation-1",
5486
+ "data-[focus-visible]:shadow-none",
5487
+ "data-[pressed]:data-[pressed]:shadow-none",
5488
+ "data-[dragged]:data-[dragged]:data-[dragged]:shadow-elevation-3",
5489
+ "data-[disabled]:shadow-none"
5490
+ ]
5473
5491
  }
5474
5492
  },
5475
- compoundVariants: [
5476
- // Filled + enabled
5477
- {
5478
- variant: "filled",
5479
- isDisabled: false,
5480
- class: "bg-surface-container-highest"
5481
- },
5482
- // Filled + disabled
5483
- {
5484
- variant: "filled",
5485
- isDisabled: true,
5486
- class: "bg-surface-container-variant"
5487
- },
5488
- // Elevated + enabled
5489
- {
5490
- variant: "elevated",
5491
- isDisabled: true,
5492
- class: "bg-surface"
5493
- },
5494
- // Elevated + disabled
5495
- {
5496
- variant: "elevated",
5497
- isDisabled: false,
5498
- class: "bg-surface-container-low"
5499
- },
5500
- // Outlined + enabled
5501
- {
5502
- variant: "outlined",
5503
- isDisabled: true,
5504
- class: "bg-surface"
5505
- },
5506
- // Outlined + disabled
5507
- {
5508
- variant: "outlined",
5509
- isDisabled: false,
5510
- class: "bg-surface"
5511
- }
5512
- ],
5513
5493
  defaultVariants: {
5514
- variant: "elevated",
5515
- isInteractive: false,
5516
- isDragged: false,
5517
- isDisabled: false
5494
+ variant: "elevated"
5518
5495
  }
5519
5496
  }
5520
5497
  );
5498
+ var cardStateLayerVariants = classVarianceAuthority.cva([
5499
+ "pointer-events-none absolute inset-0 rounded-[inherit] opacity-0",
5500
+ "bg-on-surface",
5501
+ // Effects transition for opacity — standard default tier (200ms, no overshoot)
5502
+ "transition-opacity duration-spring-standard-default-effects ease-spring-standard-default-effects",
5503
+ "group-data-[hovered]/card:opacity-8",
5504
+ "group-data-[focus-visible]/card:opacity-10",
5505
+ "group-data-[pressed]/card:group-data-[pressed]/card:opacity-10",
5506
+ "group-data-[dragged]/card:group-data-[dragged]/card:group-data-[dragged]/card:opacity-16",
5507
+ "group-data-[disabled]/card:hidden"
5508
+ ]);
5509
+ var cardFocusRingVariants = classVarianceAuthority.cva([
5510
+ "pointer-events-none absolute inset-0 z-20 rounded-[inherit]",
5511
+ "outline outline-2 -outline-offset-2 outline-secondary",
5512
+ // Effects transition — standard default tier, opacity must not overshoot
5513
+ "transition-opacity duration-spring-standard-default-effects ease-spring-standard-default-effects",
5514
+ "opacity-0",
5515
+ "group-data-[focus-visible]/card:opacity-100"
5516
+ ]);
5521
5517
  var Card = React.forwardRef(function Card2({
5522
5518
  variant = "elevated",
5523
5519
  onPress,
@@ -5528,9 +5524,15 @@ var Card = React.forwardRef(function Card2({
5528
5524
  children,
5529
5525
  "aria-label": ariaLabel
5530
5526
  }, ref) {
5527
+ const internalRef = React.useRef(null);
5528
+ const resolvedRef = ref ?? internalRef;
5531
5529
  const isInteractive = !!(onPress ?? href);
5532
5530
  const [isDragged, setIsDragged] = React.useState(false);
5533
5531
  const [isPressed, setIsPressed] = React.useState(false);
5532
+ const { isHovered, hoverProps } = reactAria.useHover({ isDisabled: !isInteractive || isDisabled });
5533
+ const { isFocusVisible, focusProps } = reactAria.useFocusRing();
5534
+ const handlePressStart = React.useCallback(() => setIsPressed(true), []);
5535
+ const handlePressEnd = React.useCallback(() => setIsPressed(false), []);
5534
5536
  const { onMouseDown: handleRipple, ripples } = useRipple({
5535
5537
  disabled: !isInteractive || isDisabled
5536
5538
  });
@@ -5544,42 +5546,41 @@ var Card = React.forwardRef(function Card2({
5544
5546
  const handleMouseLeave = () => {
5545
5547
  if (isDraggable) setIsDragged(false);
5546
5548
  };
5547
- const handlePressStart = () => setIsPressed(true);
5548
- const handlePressEnd = () => setIsPressed(false);
5549
+ const interactionAttrs = isInteractive ? getInteractionDataAttributes({ isHovered, isFocusVisible, isPressed, isDisabled }) : {};
5550
+ const interactiveHandlers = isInteractive ? reactAria.mergeProps(hoverProps, focusProps, {
5551
+ onPressStart: handlePressStart,
5552
+ onPressEnd: handlePressEnd
5553
+ }) : {};
5549
5554
  return /* @__PURE__ */ jsxRuntime.jsxs(
5550
5555
  CardHeadless,
5551
5556
  {
5552
- ref,
5557
+ ref: resolvedRef,
5553
5558
  ...onPress !== void 0 && { onPress },
5554
5559
  ...href !== void 0 && { href },
5555
5560
  isDisabled,
5556
5561
  ...ariaLabel !== void 0 && { "aria-label": ariaLabel },
5557
- onPressStart: handlePressStart,
5558
- onPressEnd: handlePressEnd,
5559
- onMouseDown: handleMouseDown,
5560
- onMouseUp: handleMouseUp,
5561
- onMouseLeave: handleMouseLeave,
5562
- className: cn(
5563
- cardVariants({ variant, isInteractive, isDragged, isDisabled }),
5564
- "group",
5565
- className
5566
- ),
5562
+ ...interactiveHandlers,
5563
+ ...isInteractive && { onMouseDown: handleMouseDown },
5564
+ ...isInteractive && isDraggable && {
5565
+ onMouseUp: handleMouseUp,
5566
+ onMouseLeave: handleMouseLeave
5567
+ },
5568
+ ...interactionAttrs,
5569
+ "data-interactive": isInteractive ? "" : void 0,
5570
+ "data-dragged": isInteractive && isDragged ? "" : void 0,
5571
+ className: cn(cardVariants({ variant }), "group/card", className),
5567
5572
  children: [
5568
5573
  isInteractive && /* @__PURE__ */ jsxRuntime.jsx(
5569
- "div",
5574
+ "span",
5570
5575
  {
5571
5576
  "data-testid": "card-state-layer",
5572
- "data-pressed": isPressed ? "" : void 0,
5573
5577
  "aria-hidden": "true",
5574
- className: cn(
5575
- "bg-on-surface pointer-events-none absolute inset-0 rounded-md",
5576
- "opacity-0 group-hover:opacity-8 data-[pressed]:opacity-12",
5577
- "duration-spring-standard-fast-effects ease-spring-standard-fast-effects transition-opacity"
5578
- )
5578
+ className: cn(cardStateLayerVariants())
5579
5579
  }
5580
5580
  ),
5581
5581
  isInteractive && ripples,
5582
- children
5582
+ isInteractive && /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: cn(cardFocusRingVariants()) }),
5583
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative z-10", children })
5583
5584
  ]
5584
5585
  }
5585
5586
  );
@@ -5589,7 +5590,7 @@ var cardMediaVariants = classVarianceAuthority.cva("w-full object-cover", {
5589
5590
  variants: {
5590
5591
  aspectRatio: {
5591
5592
  "16/9": "aspect-video",
5592
- "4/3": "aspect-video",
5593
+ "4/3": "aspect-[4/3]",
5593
5594
  "1/1": "aspect-square",
5594
5595
  auto: ""
5595
5596
  }
@@ -5613,7 +5614,7 @@ var CardMedia = React.forwardRef(function CardMedia2({ src, alt, aspectRatio = "
5613
5614
  CardMedia.displayName = "CardMedia";
5614
5615
  var CardHeader = React.forwardRef(function CardHeader2({ headline, subheader, className }, ref) {
5615
5616
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn("p-4", className), children: [
5616
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-on-surface text-title-large", children: headline }),
5617
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-on-surface text-title-medium", children: headline }),
5617
5618
  subheader !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-on-surface-variant text-body-medium mt-1", children: subheader })
5618
5619
  ] });
5619
5620
  });