@bytebrand/fe-ui-core-autobahn 1.0.156 → 1.0.158

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.
@@ -7,7 +7,7 @@ export interface ICookieModal {
7
7
  handleSentryInit?: () => void;
8
8
  }
9
9
 
10
- const CookieModal = ({ handleSentryInit }: ICookieModal) => {
10
+ const CookieModal = ({ handleSentryInit = () => {} }: ICookieModal) => {
11
11
  const { isVisible, toggleModal } = useModal();
12
12
  const [modal, setModal] = useState('');
13
13
 
@@ -52,8 +52,4 @@ const CookieModal = ({ handleSentryInit }: ICookieModal) => {
52
52
  : <></>;
53
53
  };
54
54
 
55
- CookieModal.defaultProps = {
56
- handleSentryInit: () => {}
57
- };
58
-
59
55
  export default CookieModal;
@@ -10,7 +10,7 @@ export interface ILoaderProps {
10
10
  fluid?: boolean;
11
11
  }
12
12
 
13
- const Loader: React.FC<ILoaderProps> = ({ className, size, fluid }) => {
13
+ const Loader: React.FC<ILoaderProps> = ({ className = '', size = 'medium', fluid = false }) => {
14
14
  const classNames = classnames(
15
15
  styles.loader,
16
16
  { [styles[size]]: !fluid },
@@ -23,10 +23,4 @@ const Loader: React.FC<ILoaderProps> = ({ className, size, fluid }) => {
23
23
  );
24
24
  };
25
25
 
26
- Loader.defaultProps = {
27
- className: '',
28
- size: 'medium',
29
- fluid: false
30
- };
31
-
32
26
  export default Loader;
@@ -7,7 +7,7 @@ type TIconSVG = {
7
7
  customDimensions?: boolean;
8
8
  };
9
9
 
10
- const IconSVG: React.FC<TIconSVG> = ({ name, isWarrantyActive, customDimensions, ...props }: TIconSVG) => {
10
+ const IconSVG: React.FC<TIconSVG> = ({ name, isWarrantyActive, customDimensions = false, ...props }: TIconSVG) => {
11
11
  if (!name) return null;
12
12
 
13
13
  const Component: any = components[name.toString()];
@@ -23,8 +23,4 @@ const IconSVG: React.FC<TIconSVG> = ({ name, isWarrantyActive, customDimensions,
23
23
  );
24
24
  };
25
25
 
26
- IconSVG.defaultProps = {
27
- customDimensions: false
28
- };
29
-
30
26
  export default IconSVG;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytebrand/fe-ui-core-autobahn",
3
- "version": "1.0.156",
3
+ "version": "1.0.158",
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
@@ -2991,6 +2991,12 @@ line-height: 31px;
2991
2991
  .md3 .co-address-grid .mfield-error-text {
2992
2992
  display: none;
2993
2993
  }
2994
+ /* co-birthdate opts back in: future-date/under-18/empty all show the same red border, so
2995
+ unlike the rest of .co-personal-grid the reason actually needs to be spelled out. */
2996
+ .md3 .co-personal-grid .co-birthdate .mfield-error-text {
2997
+ display: block;
2998
+ margin-top: 4px;
2999
+ }
2994
3000
  /* bug: clearing a valid field and tabbing away flashed the base .mfield:focus-within blue
2995
3001
  ring (#005CFF) for a moment before the error class/red border landed — green -> blue ->
2996
3002
  red. Dropping the blue ring here removes that flash; valid/error still show via their own
@@ -3152,6 +3158,20 @@ line-height: 31px;
3152
3158
  /* Vorwahl/Telefonnummer values (the "Land" dropdown has no <input>, so this only hits these two). */
3153
3159
  .md3 .co-phone .mfield input {
3154
3160
  font-size: 15px;
3161
+ padding: 0;
3162
+ }
3163
+ /* valid check floats in the corner, not in the flex row — the digits need the column's width */
3164
+ .md3 .co-phone .mfield .mfield-ok {
3165
+ position: absolute;
3166
+ top: 50%;
3167
+ right: 10px;
3168
+ transform: translateY(-50%);
3169
+ }
3170
+ .md3 .co-phone .mfield {
3171
+ padding: 0 8px;
3172
+ }
3173
+ .md3 .co-phone .mfield.mfield--floating.mfield--valid {
3174
+ padding: 0 25px 0 8px;
3155
3175
  }
3156
3176
  /* "Land" country-code select — same floating-notched-label look as RegistrationForm.tsx's
3157
3177
  .countryCode (OfferRequestModals/modals.styl + mixins.styl's floatingField(), Stylus/CSS
@@ -4812,8 +4832,38 @@ line-height: 31px;
4812
4832
  gap: 12px;
4813
4833
  }
4814
4834
  .md3 .oo-ls-cell {
4815
- padding: 0 !important;
4816
- border-left: 0 !important;
4835
+ padding: 0;
4836
+ }
4837
+ .md3 .oo-ls-cell:not(:first-child) {
4838
+ border-left: 0;
4839
+ }
4840
+ }
4841
+ /* ≤600px Figma mobile variant (63571:28382): rules between rows with 12px above and below,
4842
+ replacing the 800px stack's gap. */
4843
+ @media (max-width: 600px) {
4844
+ .md3 .oo-ls-row {
4845
+ gap: 0;
4846
+ }
4847
+ .md3 .oo-ls-cell {
4848
+ padding: 0 0 12px;
4849
+ }
4850
+ .md3 .oo-ls-cell:not(:first-child) {
4851
+ padding-top: 12px;
4852
+ border-top: 1px solid var(--md-outline-variant);
4853
+ }
4854
+ .md3 .oo-ls-cell:last-child {
4855
+ padding-bottom: 0;
4856
+ }
4857
+ .md3 .oo-ls-title-row .oo-ls-title,
4858
+ .md3 .oo-ls-title-row ~ .oo-ls-sub,
4859
+ .md3 .oo-ls-terms-link {
4860
+ font-family: Arimo, Arial, sans-serif;
4861
+ }
4862
+ .md3 .oo-ls-terms-link {
4863
+ margin-top: 0;
4864
+ }
4865
+ .md3 .oo-ls-title-row .lucide {
4866
+ stroke: var(--md-on-surface-variant);
4817
4867
  }
4818
4868
  }
4819
4869
  /* "2 Jahre Garantie" "i" popover (OrderOverviewNext.tsx) — same AddServicesTooltipBody/
@@ -5440,6 +5490,12 @@ line-height: 31px;
5440
5490
  min-width: 0;
5441
5491
  flex: 1 0 0;
5442
5492
  }
5493
+ .md3 .oo-vs-text {
5494
+ display: flex;
5495
+ flex-direction: column;
5496
+ gap: 3px;
5497
+ min-width: 0;
5498
+ }
5443
5499
  .md3 .oo-vs-name {
5444
5500
  font-family: Arial;
5445
5501
  font-weight: 700;
@@ -5486,6 +5542,40 @@ line-height: 31px;
5486
5542
  .md3 .oo-vs-seller-icon {
5487
5543
  flex: none;
5488
5544
  }
5545
+ /* mobile only (Figma 63571:28325): photo 110×70 and the vehicle text share row 1, the text
5546
+ centred on the photo; the seller row spans the full width below, 12px under the row */
5547
+ @media (max-width: 600px) {
5548
+ .md3 .oo-vs-row {
5549
+ display: grid;
5550
+ grid-template-columns: 110px minmax(0, 1fr);
5551
+ grid-template-rows: minmax(70px, auto) auto;
5552
+ column-gap: 14px;
5553
+ row-gap: 12px;
5554
+ }
5555
+ .md3 .oo-vs-info {
5556
+ display: contents;
5557
+ }
5558
+ .md3 .oo-vs-photo {
5559
+ grid-column: 1;
5560
+ grid-row: 1;
5561
+ width: 110px;
5562
+ height: 70px;
5563
+ border-radius: 0;
5564
+ }
5565
+ .md3 .oo-vs-text {
5566
+ grid-column: 2;
5567
+ grid-row: 1;
5568
+ align-self: center;
5569
+ }
5570
+ .md3 .oo-vs-name {
5571
+ font-size: 16px;
5572
+ }
5573
+ .md3 .oo-vs-seller {
5574
+ grid-column: 1 / -1;
5575
+ grid-row: 2;
5576
+ justify-self: start;
5577
+ }
5578
+ }
5489
5579
  .md3 .oo-row {
5490
5580
  padding: 12px 0;
5491
5581
  border-bottom: 1px solid var(--md-outline-variant);
@@ -5573,10 +5663,18 @@ line-height: 31px;
5573
5663
  gap (14px), same as every other direct child in this step. */
5574
5664
  .md3 .oo-legal-notice {
5575
5665
  margin: 0;
5576
- font-family: Arial;
5666
+ font-family: 'Arimo';
5667
+ font-weight: 400;
5577
5668
  font-size: 13px;
5578
5669
  line-height: 1.5;
5670
+ letter-spacing: 0;
5579
5671
  color: var(--md-on-surface-variant);
5672
+ text-align: left;
5673
+ }
5674
+ @media (max-width: 600px) {
5675
+ .md3 .oo-legal-notice {
5676
+ text-align: justify;
5677
+ }
5580
5678
  }
5581
5679
  .md3 .oo-legal-link {
5582
5680
  text-decoration: underline;
@@ -5864,6 +5962,17 @@ line-height: 31px;
5864
5962
  line instead of sitting visibly lower (more obvious once the label wraps to 2 lines). */
5865
5963
  margin-top: 7px;
5866
5964
  }
5965
+ @media (max-width: 600px) {
5966
+ .md3 .oo-terms-block .mcheck {
5967
+ padding: 0;
5968
+ }
5969
+ .md3 .oo-terms-block .mcheck-box {
5970
+ margin-top: 0;
5971
+ }
5972
+ .md3 .oo-terms-block .mcheck-label {
5973
+ padding-top: 0;
5974
+ }
5975
+ }
5867
5976
  /* Error state (Figma 64670:106293, "Jetzt kaufen" clicked without confirming both agreements) —
5868
5977
  unconfirmed checkbox gets a thicker red box, plus an icon+message row underneath, indented
5869
5978
  32px (20px box + 12px gap) to sit under the label rather than the box. errorIcon (FormCheckbox
@@ -6026,6 +6135,10 @@ line-height: 31px;
6026
6135
  background: var(--md-outline-variant);
6027
6136
  }
6028
6137
  }
6138
+ /* legal-document dialogs: title clears .mmodal-head-action too (24 + 40 + 4 + 40) */
6139
+ .md3 .oo-terms-modal--doc .mmodal-head {
6140
+ padding-right: 108px;
6141
+ }
6029
6142
  /* "8. Rabatt-Code hinzufügen" card (Figma 63570:28464) — its own full-width .co-card at the
6030
6143
  bottom of the page. Unlike "6."/"7." (where only the small chevron button toggles), the whole
6031
6144
  header row is the click target here — the .h3.co-card-title wraps a full-width
@@ -6366,7 +6479,7 @@ line-height: 31px;
6366
6479
  /* every narrowed checkout field (Vorname/Nachname/Straße/Nr./PLZ/Stadt/…) has the same
6367
6480
  .mfield flex gap:10px reserving room for the trailing .mfield-ok checkmark — fine at
6368
6481
  full width, but at mobile widths it was squeezing the input text out of view (same
6369
- root cause the .co-phone-only fix below already addresses for Vorwahl/Telefonnummer;
6482
+ root cause the .co-phone rules above already address for Vorwahl/Telefonnummer;
6370
6483
  this covers the rest of .co-form). Taking the icon out of flow removes that reserved
6371
6484
  space; the field's own right padding is bumped so text still clears the icon. */
6372
6485
  .md3 .co-form .mfield-ok {
@@ -6399,20 +6512,6 @@ line-height: 31px;
6399
6512
  .md3 .co-phone .co-birthdate {
6400
6513
  grid-column: 1 / -1;
6401
6514
  }
6402
- /* Vorwahl/Telefonnummer at 78px/1fr are too narrow for the flex gap:10px .mfield base rule
6403
- to reserve room for .mfield-ok inline — it was squeezing the input itself. Taking the
6404
- checkmark out of flow (.mfield already has position:relative, base rule above) removes
6405
- that reserved space; the input's own right padding (from .mfield--floating.mfield--valid,
6406
- 10px) is bumped so its text still clears the icon. */
6407
- .md3 .co-phone .mfield-ok {
6408
- position: absolute;
6409
- top: 50%;
6410
- right: 10px;
6411
- transform: translateY(-50%);
6412
- }
6413
- .md3 .co-phone .mfield--floating.mfield--valid {
6414
- padding-right: 34px;
6415
- }
6416
6515
  .md3 .co-address-row {
6417
6516
  display: flex;
6418
6517
  flex-direction: column;
@@ -14072,6 +14171,10 @@ color: #005CFF;
14072
14171
  max-width: 800px;
14073
14172
  }
14074
14173
 
14174
+ /* the dialog itself takes focus on open (Modal.tsx): keep its shadow, not the generic focus ring */
14175
+ .md3 .mmodal:focus-visible {
14176
+ box-shadow: var(--md-e3) !important;
14177
+ }
14075
14178
  .md3 .mmodal-head {
14076
14179
  flex: none;
14077
14180
  display: flex;
@@ -14115,6 +14218,25 @@ color: #005CFF;
14115
14218
  .md3 .mmodal-close:hover {
14116
14219
  background: var(--md-sc-high);
14117
14220
  }
14221
+ /* Modal.tsx headerAction: absolute like .mmodal-close, 4px to its left (right = 24 + 40 + 4). */
14222
+ .md3 .mmodal-head-action {
14223
+ position: absolute;
14224
+ top: 20px;
14225
+ right: 68px;
14226
+ width: 40px;
14227
+ height: 40px;
14228
+ padding: 0;
14229
+ border: 0;
14230
+ border-radius: var(--md-r-full);
14231
+ background: transparent;
14232
+ cursor: pointer;
14233
+ display: inline-flex;
14234
+ align-items: center;
14235
+ justify-content: center;
14236
+ }
14237
+ .md3 .mmodal-head-action:hover {
14238
+ background: var(--md-sc-high);
14239
+ }
14118
14240
 
14119
14241
  .md3 .mmodal-body {
14120
14242
  flex: 1 1 auto;
package/ui/Modal.tsx CHANGED
@@ -51,6 +51,8 @@ export interface ModalProps {
51
51
  * md3.css), so callers with a specific close-icon spec (exact asset, absolute position
52
52
  * independent of title height) aren't stuck fighting the default's flex layout. */
53
53
  closeIcon?: React.ReactNode;
54
+ /** optional extra header button rendered before the close button (e.g. a download action). */
55
+ headerAction?: React.ReactNode;
54
56
  }
55
57
 
56
58
  // focusable descendants used by the basic focus trap.
@@ -67,6 +69,7 @@ const Modal: React.FunctionComponent<ModalProps> = ({
67
69
  dismissOnScrim = true,
68
70
  className,
69
71
  closeIcon,
72
+ headerAction,
70
73
  }) => {
71
74
  const surfaceRef = React.useRef<HTMLDivElement | null>(null);
72
75
  // the element focused before the dialog opened, so focus can be restored on close.
@@ -133,7 +136,7 @@ const Modal: React.FunctionComponent<ModalProps> = ({
133
136
  const prevOverflow = document.body.style.overflow;
134
137
  document.body.style.overflow = 'hidden';
135
138
 
136
- // move focus into the dialog (first focusable, else the surface itself).
139
+ // focus the dialog surface, not its first control: a header icon would take the :focus-visible ring on open.
137
140
  // { preventScroll: true }: this runs at the very first animation frame of the mobile
138
141
  // sheet's own mmodal-sheet-up entrance (md3.css) — at that instant the surface's actual
139
142
  // computed transform is still the keyframe's `from` state (translateY(100%), pushed
@@ -145,10 +148,7 @@ const Modal: React.FunctionComponent<ModalProps> = ({
145
148
  // skips that native auto-scroll entirely, so the CSS animation alone moves the sheet
146
149
  // (same fix as fe-main's BaseModal.tsx, which hit this same glitch first).
147
150
  const surface = surfaceRef.current;
148
- if (surface) {
149
- const first = surface.querySelector<HTMLElement>(FOCUSABLE);
150
- (first || surface).focus({ preventScroll: true });
151
- }
151
+ if (surface) surface.focus({ preventScroll: true });
152
152
 
153
153
  return () => {
154
154
  document.body.style.overflow = prevOverflow;
@@ -237,6 +237,7 @@ const Modal: React.FunctionComponent<ModalProps> = ({
237
237
  ) : (
238
238
  <span className="mmodal-title" aria-hidden="true" />
239
239
  )}
240
+ {headerAction}
240
241
  {closeIcon ? (
241
242
  <button type="button" className="mmodal-close" aria-label="Schließen" onClick={onClose}>
242
243
  {closeIcon}