@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.
- package/compat/CookieModal/CookieModal.tsx +1 -5
- package/compat/Loader/Loader.tsx +1 -7
- package/iconsvg/IconSVG.tsx +1 -5
- package/package.json +1 -1
- package/theme/md3.css +140 -18
- package/ui/Modal.tsx +6 -5
|
@@ -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;
|
package/compat/Loader/Loader.tsx
CHANGED
|
@@ -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;
|
package/iconsvg/IconSVG.tsx
CHANGED
|
@@ -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.
|
|
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
|
|
4816
|
-
|
|
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:
|
|
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
|
|
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
|
-
//
|
|
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}
|