@bytebrand/fe-ui-core-autobahn 1.0.116 → 1.0.118

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
@@ -272,7 +272,7 @@ const CarRow: React.FunctionComponent<CarRowProps> = ({
272
272
  {facts.map(([ic, v]) => (
273
273
  <span key={ic} style={{ display: 'inline-flex', alignItems: 'center', gap: 7, whiteSpace: 'nowrap' }}>
274
274
  <Icon name={ic} size={15} color="var(--md-primary)" stroke={1.8} style={{ flex: 'none' }} />
275
- <span style={{ fontSize: 13.5, fontWeight: 600, color: 'var(--md-on-surface)' }}>{v}</span>
275
+ <span className="specstrip-val">{v}</span>
276
276
  </span>
277
277
  ))}
278
278
  </div>
@@ -334,7 +334,7 @@ export const EcoLine: React.FunctionComponent<EcoLineProps> = ({ car, style, t }
334
334
  if (car.phev) {
335
335
  const p = car.phev;
336
336
  return (
337
- <div style={wrap}>
337
+ <div className="eco-line" style={wrap}>
338
338
  {p.consEl}{' '}
339
339
  {t('autobahn:card.eco.phevConsumptionLine', {
340
340
  consFuel: p.consFuel,
@@ -347,7 +347,7 @@ export const EcoLine: React.FunctionComponent<EcoLineProps> = ({ car, style, t }
347
347
  );
348
348
  }
349
349
  return (
350
- <div style={wrap}>
350
+ <div className="eco-line" style={wrap}>
351
351
  {t('autobahn:card.eco.consumptionLine', { cons: car.cons, co2: car.co2, co2class: car.co2class })}
352
352
  </div>
353
353
  );
@@ -96,6 +96,33 @@ function num(v: any): number | undefined {
96
96
  return Number.isFinite(n) ? n : undefined;
97
97
  }
98
98
 
99
+ /** like num(), but 0/negative count as absent — a 0-filled consumption field is
100
+ * "no data" (CBD skips zeros on enrichment), never a real figure to print. */
101
+ function pos(v: any): number | undefined {
102
+ const n = num(v);
103
+ return n != null && n > 0 ? n : undefined;
104
+ }
105
+
106
+ /** gas-type fuels whose consumption is measured in kg/100 km (legacy cbdConsumptionUnit set). */
107
+ const KG_FUELS = ['selector_fuel_naturalGas', 'selector_fuel_carGas', 'selector_fuel_hydrogen', 'selector_fuel_ethanol'];
108
+
109
+ /**
110
+ * EnVKV combined-consumption label, fuel-aware. Electric cars consume kWh — their
111
+ * l/100km fields (wltpCombined/consumptionCombined-as-liters) arrive as 0, so the
112
+ * flat `l/100 km` template printed "0 l/100 km" on every EV; gas/hydrogen cars
113
+ * measure kg. WLTP figure preferred, else NEDC — same order as before.
114
+ */
115
+ function consumptionLabel(consumption: any, language?: string): string {
116
+ const fuel = String(consumption.fuel || '');
117
+ const electric = fuel === 'selector_fuel_electrical';
118
+ const val = electric
119
+ ? pos(consumption.wltpPowerCombined) ?? pos(consumption.consumptionPowerCombined) ?? pos(consumption.consumptionCombined)
120
+ : pos(consumption.wltpCombined) ?? pos(consumption.consumptionCombined);
121
+ if (val == null) return '';
122
+ const unit = electric ? 'kWh/100 km' : KG_FUELS.indexOf(fuel) >= 0 ? 'kg/100 km' : 'l/100 km';
123
+ return `${val.toLocaleString(localeTag(language))} ${unit}`;
124
+ }
125
+
99
126
  // strike-price ("UVP-Rate"/list-price) eligibility — a separate product rule from the NEU
100
127
  // badge's own showNewLabel (which also requires a recent modificationDate; see fe-main's
101
128
  // DataTransformers.ts shouldShowNewLabel). Here: as-good-as-new only — mileage under 1,000 km
@@ -371,9 +398,8 @@ export function toAutobahnCar(storeCar: any, deps: ToAutobahnCarDeps = {}): Auto
371
398
 
372
399
  // --- EnVKV consumption line (REQUIRED on every German car ad) ---
373
400
  // Prefer WLTP figures when present (the legacy cards do too), else NEDC.
374
- const consVal = num(consumption.wltpCombined) ?? num(consumption.consumptionCombined);
375
401
  const co2Val = num(emissions.wltpCo2) ?? num(emissions.co2);
376
- const cons = consVal != null ? `${consVal.toLocaleString(localeTag(language))} l/100 km` : '';
402
+ const cons = consumptionLabel(consumption, language);
377
403
  const co2 = co2Val != null ? `${co2Val.toLocaleString(localeTag(language))} g/km` : '';
378
404
  const co2class = co2ClassLetter(emissions.wltpEnergyEfficiencyClass);
379
405
  const phev = buildPhev(storeCar, language);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytebrand/fe-ui-core-autobahn",
3
- "version": "1.0.116",
3
+ "version": "1.0.118",
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
@@ -3033,6 +3033,11 @@ line-height: 31px;
3033
3033
  left: auto;
3034
3034
  right: 0;
3035
3035
  }
3036
+ /* body-level portal menu: must paint over every fixed overlay its trigger can live in —
3037
+ .sheet (71), .fin-modal-scrim (60), .vdp-photosheet (211), .mmodal-scrim (1300). */
3038
+ .md3 .mselect-menu--portal {
3039
+ z-index: 1400;
3040
+ }
3036
3041
  .md3 .mselect-list {
3037
3042
  max-height: 288px;
3038
3043
  overflow-y: auto;
@@ -4222,6 +4227,24 @@ line-height: 31px;
4222
4227
  background: var(--md-sc-low);
4223
4228
  border-radius: var(--md-r-md);
4224
4229
  }
4230
+ /* spec strip values — mobile keeps the bold 13.5px; desktop follows the design (11px/400) */
4231
+ .md3 .specstrip-val {
4232
+ font-size: 13.5px;
4233
+ font-weight: 600;
4234
+ color: var(--md-on-surface);
4235
+ }
4236
+ @media (min-width: 601px) {
4237
+ .md3 .listcard .specstrip-val {
4238
+ font-size: 11px;
4239
+ font-weight: 400;
4240
+ }
4241
+ /* SRP list card EnVKV line — design wants full-contrast text (#1a1b22 = --md-on-surface) on
4242
+ desktop; the component's inline base color (on-surface-variant) stays for every other
4243
+ surface (grid card, mobile), hence the !important against the inline style. */
4244
+ .md3 .listcard .eco-line {
4245
+ color: var(--md-on-surface) !important;
4246
+ }
4247
+ }
4225
4248
  /* desktop only (mobile keeps the flex-wrap flow above, untouched): a clean 2-column grid so
4226
4249
  pairs line up (km|EZ, Kraftstoff|Getriebe, Leistung|Halter) instead of reflowing by text
4227
4250
  length (Figma "mcard"). Facts render in DOM order [km, EZ, Getriebe, Kraftstoff, Leistung,
package/ui/Dropdown.tsx CHANGED
@@ -420,7 +420,7 @@ const Dropdown: React.FunctionComponent<DropdownProps> = ({
420
420
  ? ReactDOM.createPortal(
421
421
  <div
422
422
  ref={menuElRef}
423
- className={'mselect-menu' + (searchable ? ' mselect-menu--searchable' : '')}
423
+ className={'mselect-menu mselect-menu--portal' + (searchable ? ' mselect-menu--searchable' : '')}
424
424
  // menuPos is null for one frame on open, before the position effect has measured
425
425
  // the trigger — stay invisible rather than flash at (0,0)/full-width.
426
426
  style={