@bytebrand/fe-ui-core-autobahn 1.0.63 → 1.0.65

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/cards/CarRow.tsx CHANGED
@@ -86,7 +86,9 @@ const CarRow: React.FunctionComponent<CarRowProps> = ({ car, isFavorite, onToggl
86
86
  style={{ background: 'var(--md-sc-lowest)' }}
87
87
  >
88
88
  <div className="listcard-media" style={{ position: 'relative' }} onMouseEnter={onMediaEnter} onTouchStart={onMediaEnter}>
89
- <CardCarousel images={car.gallery} height="100%" fit="contain" onChange={setPhotoIndex} />
89
+ {/* 'auto': desktop picks cover/contain per photo (crops only when it wouldn't lose too
90
+ much of the shot); below 601px this is identical to 'contain', so mobile is unchanged. */}
91
+ <CardCarousel images={car.gallery} height="100%" fit="auto" onChange={setPhotoIndex} />
90
92
  {/* deal badges — ONE compact line: NEU · −€ · 0 € Anz. · −%, plus the "⚡ Angebot" badge
91
93
  (Figma) on its own line below. The price RATING ('Guter Preis') is NOT here — it
92
94
  lives in the price column (PriceMeter). */}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytebrand/fe-ui-core-autobahn",
3
- "version": "1.0.63",
3
+ "version": "1.0.65",
4
4
  "description": "auto.de md3 (Autobahn) design system — UI primitives, cards, chrome, VDP modules, theme CSS and locales. Ships raw TypeScript source (like fe-ui-core before it); each consumer's bundler compiles it.",
5
5
  "main": "index.ts",
6
6
  "license": "UNLICENSED",
package/theme/md3.css CHANGED
@@ -4040,14 +4040,6 @@ line-height: 31px;
4040
4040
  .md3 .specstrip > span:nth-child(1) { order: -3; }
4041
4041
  .md3 .specstrip > span:nth-child(2) { order: -2; }
4042
4042
  .md3 .specstrip > span:nth-child(4) { order: -1; }
4043
- /* mcard (SRP CarRow) photo: fill the media box edge-to-edge on desktop (Figma "mcard") instead
4044
- of the letterboxed object-fit:contain CardCarousel applies by default (that "contain" +
4045
- padding is still correct on mobile, untouched — this overrides only the desktop rendering,
4046
- since CardCarousel's `fit`/`padded` props are one shared JS value for both breakpoints). */
4047
- .md3 .listcard-media .cardcar img {
4048
- object-fit: cover !important;
4049
- padding: 0 !important;
4050
- }
4051
4043
  }
4052
4044
  /* filter rail: collapsible sections */
4053
4045
  .md3 .frail-group {
@@ -10,8 +10,15 @@ export interface CardCarouselProps {
10
10
  radius?: number | string;
11
11
  /** fired with the new active index whenever the slide changes. */
12
12
  onChange?: (index: number) => void;
13
- /** object-fit for each image; 'contain' adds inset padding by default. */
14
- fit?: 'cover' | 'contain';
13
+ /**
14
+ * object-fit for each image; 'contain' adds inset padding by default. 'auto' always fills the
15
+ * box's full WIDTH (never a left/right gap) and lets height follow the image's own aspect
16
+ * ratio — landscape photos in this taller-than-wide card box typically end up shorter than the
17
+ * box (a top/bottom gap, filled by the studio-white background), while a portrait/near-square
18
+ * photo can end up taller than the box and get cropped top/bottom by its overflow:hidden. 'auto'
19
+ * behaves exactly like 'contain' below 601px viewport width (no change to any mobile rendering).
20
+ */
21
+ fit?: 'cover' | 'contain' | 'auto';
15
22
  /** set false to drop the 5%/6% inset padding 'contain' normally adds (e.g. the VDP
16
23
  * gallery, which wants the image filling the box edge-to-edge). Defaults to true. */
17
24
  padded?: boolean;
@@ -50,6 +57,21 @@ const CardCarousel: React.FunctionComponent<CardCarouselProps> = ({
50
57
  const go = (d: number, e?: React.SyntheticEvent) => jump((i + d + n) % n, e);
51
58
  const trackRef = useRef<HTMLDivElement>(null);
52
59
  const tx = useRef<number | null>(null);
60
+
61
+ // 'auto' mode only diverges from plain 'contain' at desktop widths — below 601px it resolves
62
+ // to 'contain' unconditionally, so mobile's existing rendering is untouched either way.
63
+ const [isDesktop, setIsDesktop] = useState(
64
+ () => fit === 'auto' && typeof window !== 'undefined' && window.matchMedia('(min-width: 601px)').matches,
65
+ );
66
+ useEffect(() => {
67
+ if (fit !== 'auto' || typeof window === 'undefined') return;
68
+ const mq = window.matchMedia('(min-width: 601px)');
69
+ const handler = () => setIsDesktop(mq.matches);
70
+ mq.addEventListener('change', handler);
71
+ return () => mq.removeEventListener('change', handler);
72
+ }, [fit]);
73
+ const autoDesktop = fit === 'auto' && isDesktop;
74
+
53
75
  return (
54
76
  <div
55
77
  className="cardcar"
@@ -80,15 +102,32 @@ const CardCarousel: React.FunctionComponent<CardCarouselProps> = ({
80
102
  alt=""
81
103
  loading="lazy"
82
104
  decoding="async"
83
- style={{
84
- flex: '0 0 100%',
85
- width: '100%',
86
- height: '100%',
87
- objectFit: fit,
88
- padding: fit === 'contain' && padded ? '5% 6%' : 0,
89
- boxSizing: 'border-box',
90
- background: '#fff',
91
- }}
105
+ style={
106
+ autoDesktop
107
+ ? {
108
+ // width-anchored: always fills the box's full width (no left/right gap,
109
+ // ever); height is 'auto' (NOT a min-height floor — that would force
110
+ // object-fit:fill's default stretch/distortion on a narrower photo), so it
111
+ // follows the photo's own ratio, cropped top/bottom by the box's
112
+ // overflow:hidden when taller than the box, centered so the crop doesn't
113
+ // favor either edge.
114
+ flex: '0 0 100%',
115
+ width: '100%',
116
+ height: 'auto',
117
+ alignSelf: 'center',
118
+ boxSizing: 'border-box',
119
+ background: '#fff',
120
+ }
121
+ : {
122
+ flex: '0 0 100%',
123
+ width: '100%',
124
+ height: '100%',
125
+ objectFit: fit === 'auto' ? 'contain' : fit,
126
+ padding: fit !== 'cover' && padded ? '5% 6%' : 0,
127
+ boxSizing: 'border-box',
128
+ background: '#fff',
129
+ }
130
+ }
92
131
  />
93
132
  ))}
94
133
  </div>