feat(WEB-162): final design edit profile page
This commit is contained in:
committed by
Christel Westerberg
parent
5f3e417593
commit
d84efcbb0f
@@ -1,167 +1,411 @@
|
||||
.btn {
|
||||
background: none;
|
||||
border: none;
|
||||
/* No variable yet for radius 50px */
|
||||
border-radius: 50px;
|
||||
cursor: pointer;
|
||||
/* TODO: Waiting for variables for buttons from Design team */
|
||||
font-family: var(--typography-Body-Regular-fontFamily);
|
||||
font-weight: 600;
|
||||
line-height: 150%;
|
||||
letter-spacing: 1%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
transition:
|
||||
background-color 300ms ease,
|
||||
color 300ms ease;
|
||||
|
||||
/* TODO: Waiting for variables for buttons from Design team */
|
||||
font-family: var(--typography-Body-Bold-fontFamily);
|
||||
font-size: var(--typography-Body-Bold-fontSize);
|
||||
font-weight: var(--typography-Body-Bold-fontWeight);
|
||||
line-height: 24px;
|
||||
letter-spacing: 0.6%;
|
||||
}
|
||||
|
||||
/* INTENT */
|
||||
.primary,
|
||||
a.primary {
|
||||
background-color: var(--background-color);
|
||||
color: var(--font-color);
|
||||
}
|
||||
|
||||
.primary:hover,
|
||||
a.primary:hover,
|
||||
.primary:active,
|
||||
a.primary:active,
|
||||
.primary:focus,
|
||||
a.primary:focus {
|
||||
background-color: var(--hover-background);
|
||||
color: var(--hover-color);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.secondary,
|
||||
a.secondary {
|
||||
background-color: transparent;
|
||||
border: 1px solid var(--background-color);
|
||||
color: var(--background-color);
|
||||
background: none;
|
||||
border-style: solid;
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.secondary:hover,
|
||||
a.secondary:hover,
|
||||
.secondary:active,
|
||||
a.secondary:active,
|
||||
.secondary:focus,
|
||||
a.secondary:focus {
|
||||
border: 1px solid var(--hover-color);
|
||||
color: var(--hover-color);
|
||||
.tertiary,
|
||||
a.tertiary {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.inverted,
|
||||
a.inverted {
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* VARIANTS */
|
||||
.default,
|
||||
a.default {
|
||||
align-items: center;
|
||||
border-radius: 50px;
|
||||
/* No variable yet */
|
||||
display: flex;
|
||||
gap: var(--Spacing-x1);
|
||||
}
|
||||
|
||||
.icon {
|
||||
align-items: baseline;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
/* Disabled styles */
|
||||
/* SIZES */
|
||||
.small {
|
||||
gap: var(--Spacing-x-quarter);
|
||||
height: 40px;
|
||||
padding: var(--Spacing-x1) var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.medium {
|
||||
gap: var(--Spacing-x-quarter);
|
||||
height: 48px;
|
||||
padding: var(--Spacing-x-one-and-half) var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.large {
|
||||
gap: var(--Spacing-x-half);
|
||||
height: 56px;
|
||||
padding: var(--Spacing-x2) var(--Spacing-x3);
|
||||
}
|
||||
|
||||
/* DISABLED */
|
||||
.btn:disabled {
|
||||
background-color: var(--disabled-background-color);
|
||||
color: var(--disabled-color);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* Sizes */
|
||||
.small {
|
||||
font-size: 14px;
|
||||
gap: var(--Spacing-x2);
|
||||
height: 40px;
|
||||
padding: var(--Spacing-x1) var(--Spacing-x2);
|
||||
/* THEMES */
|
||||
.basePrimary {
|
||||
background-color: var(--Base-Button-Primary-Fill-Normal);
|
||||
color: var(--Base-Button-Primary-On-Fill-Normal);
|
||||
}
|
||||
|
||||
.medium {
|
||||
font-size: 16px;
|
||||
height: 30px;
|
||||
padding: var(--Spacing-x-one-and-half) var(--Spacing-x2);
|
||||
.basePrimary:active,
|
||||
.basePrimary:focus,
|
||||
.basePrimary:hover {
|
||||
background-color: var(--Base-Button-Primary-Fill-Hover);
|
||||
color: var(--Base-Button-Primary-On-Fill-Hover);
|
||||
}
|
||||
|
||||
.large {
|
||||
font-size: 16px;
|
||||
height: 50px;
|
||||
gap: var(--Spacing-x-half);
|
||||
padding: var(--Spacing-x2) var(--Spacing-x3);
|
||||
.basePrimary:disabled {
|
||||
background-color: var(--Base-Button-Primary-Fill-Disabled);
|
||||
color: var(--Base-Button-Primary-On-Fill-Disabled);
|
||||
}
|
||||
|
||||
.primaryLight {
|
||||
--font-color: var(--Theme-Primary-Light-Button-Primary-On-Fill-Normal);
|
||||
--background-color: var(--Theme-Primary-Light-Button-Primary-Fill-Normal);
|
||||
--hover-background: var(--Theme-Primary-Light-Button-Primary-Fill-Hover);
|
||||
--hover-color: var(--Theme-Primary-Light-Button-Primary-On-Fill-Hover);
|
||||
--disabled-background-color: var(
|
||||
--Theme-Primary-Light-Button-Primary-Fill-Disabled
|
||||
);
|
||||
--disabled-color: var(--Theme-Primary-Light-Button-Primary-On-Fill-Disabled);
|
||||
.baseSecondary {
|
||||
background-color: var(--Base-Button-Secondary-Fill-Normal);
|
||||
border-color: var(--Base-Button-Secondary-Border-Normal);
|
||||
color: var(--Base-Button-Secondary-On-Fill-Normal);
|
||||
}
|
||||
|
||||
.primaryDark {
|
||||
--font-color: var(--Theme-Primary-Dark-Button-Primary-On-Fill-Normal);
|
||||
--background-color: var(--Theme-Primary-Dark-Button-Primary-Fill-Normal);
|
||||
--hover-color: var(--Theme-Primary-Dark-Button-Primary-On-Fill-Hover);
|
||||
--hover-background: var(--Theme-Primary-Dark-Button-Primary-Fill-Hover);
|
||||
--disabled-background-color: var(
|
||||
--Theme-Primary-Dark-Button-Primary-Fill-Disabled
|
||||
);
|
||||
--disabled-color: var(--Theme-Primary-Dark-Button-Primary-On-Fill-Disabled);
|
||||
.baseSecondary:active,
|
||||
.baseSecondary:focus,
|
||||
.baseSecondary:hover {
|
||||
background-color: var(--Base-Button-Secondary-Fill-Hover);
|
||||
border-color: var(--Base-Button-Secondary-Border-Hover);
|
||||
color: var(--Base-Button-Secondary-On-Fill-Hover);
|
||||
}
|
||||
|
||||
.primaryStrong {
|
||||
--background-color: var(--Theme-Primary-Strong-Button-Primary-Fill-Normal);
|
||||
--disabled-background-color: var(
|
||||
--Theme-Primary-Strong-Button-Primary-Fill-Disabled
|
||||
);
|
||||
--disabled-color: var(--Theme-Primary-Strong-Button-Primary-On-Fill-Disabled);
|
||||
--font-color: var(--Theme-Primary-Strong-Button-Primary-On-Fill-Normal);
|
||||
--hover-background: var(--Theme-Primary-Strong-Button-Primary-Fill-Hover);
|
||||
--hover-color: var(--Theme-Primary-Strong-Button-Primary-On-Fill-Hover);
|
||||
.baseSecondary:disabled {
|
||||
background-color: var(--Base-Button-Secondary-Fill-Disabled);
|
||||
border-color: var(--Base-Button-Secondary-Border-Disabled);
|
||||
color: var(--Base-Button-Secondary-On-Fill-Disabled);
|
||||
}
|
||||
|
||||
.secondaryLight {
|
||||
--font-color: var(--Theme-Secondary-Light-Button-Primary-On-Fill-Normal);
|
||||
--background-color: var(--Theme-Secondary-Light-Button-Primary-Fill-Normal);
|
||||
--hover-color: var(--Theme-Secondary-Light-Button-Primary-On-Fill-Hover);
|
||||
--hover-background: var(--Theme-Secondary-Light-Button-Primary-Fill-Hover);
|
||||
--disabled-background-color: var(
|
||||
--Theme-Secondary-Light-Button-Primary-Fill-Disabled
|
||||
);
|
||||
--disabled-color: var(
|
||||
--Theme-Secondary-Light-Button-Primary-On-Fill-Disabled
|
||||
);
|
||||
.baseTertiary {
|
||||
background-color: var(--Base-Button-Tertiary-Fill-Normal);
|
||||
color: var(--Base-Button-Tertiary-On-Fill-Normal);
|
||||
}
|
||||
|
||||
.secondaryDark {
|
||||
--font-color: var(--Theme-Secondary-Dark-Button-Primary-On-Fill-Normal);
|
||||
--background-color: var(--Theme-Secondary-Dark-Button-Primary-Fill-Normal);
|
||||
--hover-color: var(--Theme-Secondary-Dark-Button-Primary-On-Fill-Hover);
|
||||
--hover-background: var(--Theme-Secondary-Dark-Button-Primary-Fill-Hover);
|
||||
--disabled-background-color: var(
|
||||
--Theme-Secondary-Dark-Button-Primary-Fill-Disabled
|
||||
);
|
||||
--disabled-color: var(--Theme-Secondary-Dark-Button-Primary-On-Fill-Disabled);
|
||||
.baseTertiary:active,
|
||||
.baseTertiary:focus,
|
||||
.baseTertiary:hover {
|
||||
background-color: var(--Base-Button-Tertiary-Fill-Hover);
|
||||
color: var(--Base-Button-Tertiary-On-Fill-Hover);
|
||||
}
|
||||
|
||||
.tertiaryLight {
|
||||
--font-color: var(--Theme-Tertiary-Light-Button-Primary-On-Fill-Normal);
|
||||
--background-color: var(--Theme-Tertiary-Light-Button-Primary-Fill-Normal);
|
||||
--hover-color: var(--Theme-Tertiary-Light-Button-Primary-On-Fill-Hover);
|
||||
--hover-background: var(--Theme-Tertiary-Light-Button-Primary-Fill-Hover);
|
||||
--disabled-background-color: var(
|
||||
--Theme-Tertiary-Light-Button-Primary-Fill-Disabled
|
||||
);
|
||||
--disabled-color: var(--Theme-Tertiary-Light-Button-Primary-On-Fill-Disabled);
|
||||
.baseTertiary:disabled {
|
||||
background-color: var(--Base-Button-Tertiary-Fill-Disabled);
|
||||
color: var(--Base-Button-Tertiary-On-Fill-Disabled);
|
||||
}
|
||||
|
||||
.tertiaryDark {
|
||||
--font-color: var(--Theme-Tertiary-Dark-Button-Primary-On-Fill-Normal);
|
||||
--background-color: var(--Theme-Tertiary-Dark-Button-Primary-Fill-Normal);
|
||||
--hover-color: var(--Theme-Tertiary-Dark-Button-Primary-On-Fill-Hover);
|
||||
--hover-background: var(--Theme-Tertiary-Dark-Button-Primary-Fill-Hover);
|
||||
--disabled-background-color: var(
|
||||
--Theme-Tertiary-Dark-Button-Primary-Fill-Disabled
|
||||
);
|
||||
--disabled-color: var(--Theme-Tertiary-Dark-Button-Primary-On-Fill-Disabled);
|
||||
.baseInverted {
|
||||
background-color: var(--Base-Button-Inverted-Fill-Normal);
|
||||
color: var(--Base-Button-Inverted-On-Fill-Normal);
|
||||
}
|
||||
|
||||
.baseInverted:active,
|
||||
.baseInverted:focus,
|
||||
.baseInverted:hover {
|
||||
background-color: var(--Base-Button-Inverted-Fill-Hover);
|
||||
color: var(--Base-Button-Inverted-On-Fill-Hover);
|
||||
}
|
||||
|
||||
.baseInverted:disabled {
|
||||
background-color: var(--Base-Button-Inverted-Fill-Disabled);
|
||||
color: var(--Base-Button-Inverted-On-Fill-Disabled);
|
||||
}
|
||||
|
||||
.primaryStrongPrimary {
|
||||
background-color: var(--Theme-Primary-Strong-Button-Primary-Fill-Normal);
|
||||
color: var(--Theme-Primary-Strong-Button-Primary-On-Fill-Normal);
|
||||
}
|
||||
|
||||
.primaryStrongPrimary:active,
|
||||
.primaryStrongPrimary:focus,
|
||||
.primaryStrongPrimary:hover {
|
||||
background-color: var(--Theme-Primary-Strong-Button-Primary-Fill-Hover);
|
||||
color: var(--Theme-Primary-Strong-Button-Primary-On-Fill-Hover);
|
||||
}
|
||||
|
||||
.primaryStrongPrimary:disabled {
|
||||
background-color: var(--Theme-Primary-Strong-Button-Primary-Fill-Disabled);
|
||||
color: var(--Theme-Primary-Strong-Button-Primary-On-Fill-Disabled);
|
||||
}
|
||||
|
||||
.primaryStrongSecondary {
|
||||
background-color: var(--Theme-Primary-Strong-Button-Secondary-Fill-Normal);
|
||||
border-color: var(--Theme-Primary-Strong-Button-Secondary-Border-Normal);
|
||||
color: var(--Theme-Primary-Strong-Button-Secondary-On-Fill-Normal);
|
||||
}
|
||||
|
||||
.primaryStrongSecondary:active,
|
||||
.primaryStrongSecondary:focus,
|
||||
.primaryStrongSecondary:hover {
|
||||
background-color: var(--Theme-Primary-Strong-Button-Secondary-Fill-Hover);
|
||||
border-color: var(--Theme-Primary-Strong-Button-Secondary-Border-Hover);
|
||||
color: var(--Theme-Primary-Strong-Button-Secondary-On-Fill-Hover);
|
||||
}
|
||||
|
||||
.primaryStrongSecondary:disabled {
|
||||
background-color: var(--Theme-Primary-Strong-Button-Secondary-Fill-Disabled);
|
||||
border-color: var(--Theme-Primary-Strong-Button-Secondary-Border-Disabled);
|
||||
color: var(--Theme-Primary-Strong-Button-Secondary-On-Fill-Disabled);
|
||||
}
|
||||
|
||||
.primaryDarkPrimary {
|
||||
background-color: var(--Theme-Primary-Dark-Button-Primary-Fill-Normal);
|
||||
color: var(--Theme-Primary-Dark-Button-Primary-On-Fill-Normal);
|
||||
}
|
||||
|
||||
.primaryDarkPrimary:active,
|
||||
.primaryDarkPrimary:focus,
|
||||
.primaryDarkPrimary:hover {
|
||||
background-color: var(--Theme-Primary-Dark-Button-Primary-Fill-Hover);
|
||||
color: var(--Theme-Primary-Dark-Button-Primary-On-Fill-Hover);
|
||||
}
|
||||
|
||||
.primaryDarkPrimary:disabled {
|
||||
background-color: var(--Theme-Primary-Dark-Button-Primary-Fill-Disabled);
|
||||
color: var(--Theme-Primary-Dark-Button-Primary-On-Fill-Disabled);
|
||||
}
|
||||
|
||||
.primaryDarkSecondary {
|
||||
background-color: var(--Theme-Primary-Dark-Button-Secondary-Fill-Normal);
|
||||
border-color: var(--Theme-Primary-Dark-Button-Secondary-Border-Normal);
|
||||
color: var(--Theme-Primary-Dark-Button-Secondary-On-Fill-Normal);
|
||||
}
|
||||
|
||||
.primaryDarkSecondary:active,
|
||||
.primaryDarkSecondary:focus,
|
||||
.primaryDarkSecondary:hover {
|
||||
background-color: var(--Theme-Primary-Dark-Button-Secondary-Fill-Hover);
|
||||
border-color: var(--Theme-Primary-Dark-Button-Secondary-Border-Hover);
|
||||
color: var(--Theme-Primary-Dark-Button-Secondary-On-Fill-Hover);
|
||||
}
|
||||
|
||||
.primaryDarkSecondary:disabled {
|
||||
background-color: var(--Theme-Primary-Dark-Button-Secondary-Fill-Disabled);
|
||||
border-color: var(--Theme-Primary-Dark-Button-Secondary-Border-Disabled);
|
||||
color: var(--Theme-Primary-Dark-Button-Secondary-On-Fill-Disabled);
|
||||
}
|
||||
|
||||
.primaryLightPrimary {
|
||||
background-color: var(--Theme-Primary-Light-Button-Primary-Fill-Normal);
|
||||
color: var(--Theme-Primary-Light-Button-Primary-On-Fill-Normal);
|
||||
}
|
||||
|
||||
.primaryLightPrimary:active,
|
||||
.primaryLightPrimary:focus,
|
||||
.primaryLightPrimary:hover {
|
||||
background-color: var(--Theme-Primary-Light-Button-Primary-Fill-Hover);
|
||||
color: var(--Theme-Primary-Light-Button-Primary-On-Fill-Hover);
|
||||
}
|
||||
|
||||
.primaryLightPrimary:disabled {
|
||||
background-color: var(--Theme-Primary-Light-Button-Primary-Fill-Disabled);
|
||||
color: var(--Theme-Primary-Light-Button-Primary-On-Fill-Disabled);
|
||||
}
|
||||
|
||||
.primaryLightSecondary {
|
||||
background-color: var(--Theme-Primary-Light-Button-Secondary-Fill-Normal);
|
||||
border-color: var(--Theme-Primary-Light-Button-Secondary-Border-Normal);
|
||||
color: var(--Theme-Primary-Light-Button-Secondary-On-Fill-Normal);
|
||||
}
|
||||
|
||||
.primaryLightSecondary:active,
|
||||
.primaryLightSecondary:focus,
|
||||
.primaryLightSecondary:hover {
|
||||
background-color: var(--Theme-Primary-Light-Button-Secondary-Fill-Hover);
|
||||
border-color: var(--Theme-Primary-Light-Button-Secondary-Border-Hover);
|
||||
color: var(--Theme-Primary-Light-Button-Secondary-On-Fill-Hover);
|
||||
}
|
||||
|
||||
.primaryLightSecondary:disabled {
|
||||
background-color: var(--Theme-Primary-Light-Button-Secondary-Fill-Disabled);
|
||||
border-color: var(--Theme-Primary-Light-Button-Secondary-Border-Disabled);
|
||||
color: var(--Theme-Primary-Light-Button-Secondary-On-Fill-Disabled);
|
||||
}
|
||||
|
||||
.secondaryDarkPrimary {
|
||||
background-color: var(--Theme-Secondary-Dark-Button-Primary-Fill-Normal);
|
||||
color: var(--Theme-Secondary-Dark-Button-Primary-On-Fill-Normal);
|
||||
}
|
||||
|
||||
.secondaryDarkPrimary:active,
|
||||
.secondaryDarkPrimary:focus,
|
||||
.secondaryDarkPrimary:hover {
|
||||
background-color: var(--Theme-Secondary-Dark-Button-Primary-Fill-Hover);
|
||||
color: var(--Theme-Secondary-Dark-Button-Primary-On-Fill-Hover);
|
||||
}
|
||||
|
||||
.secondaryDarkPrimary:disabled {
|
||||
background-color: var(--Theme-Secondary-Dark-Button-Primary-Fill-Disabled);
|
||||
color: var(--Theme-Secondary-Dark-Button-Primary-On-Fill-Disabled);
|
||||
}
|
||||
|
||||
.secondaryDarkSecondary {
|
||||
background-color: var(--Theme-Secondary-Dark-Button-Secondary-Fill-Normal);
|
||||
border-color: var(--Theme-Secondary-Dark-Button-Secondary-Border-Normal);
|
||||
color: var(--Theme-Secondary-Dark-Button-Secondary-On-Fill-Normal);
|
||||
}
|
||||
|
||||
.secondaryDarkSecondary:active,
|
||||
.secondaryDarkSecondary:focus,
|
||||
.secondaryDarkSecondary:hover {
|
||||
background-color: var(--Theme-Secondary-Dark-Button-Secondary-Fill-Hover);
|
||||
border-color: var(--Theme-Secondary-Dark-Button-Secondary-Border-Hover);
|
||||
color: var(--Theme-Secondary-Dark-Button-Secondary-On-Fill-Hover);
|
||||
}
|
||||
|
||||
.secondaryDarkSecondary:disabled {
|
||||
background-color: var(--Theme-Secondary-Dark-Button-Secondary-Fill-Disabled);
|
||||
border-color: var(--Theme-Secondary-Dark-Button-Secondary-Border-Disabled);
|
||||
color: var(--Theme-Secondary-Dark-Button-Secondary-On-Fill-Disabled);
|
||||
}
|
||||
|
||||
.secondaryLightPrimary {
|
||||
background-color: var(--Theme-Secondary-Light-Button-Primary-Fill-Normal);
|
||||
color: var(--Theme-Secondary-Light-Button-Primary-On-Fill-Normal);
|
||||
}
|
||||
|
||||
.secondaryLightPrimary:active,
|
||||
.secondaryLightPrimary:focus,
|
||||
.secondaryLightPrimary:hover {
|
||||
background-color: var(--Theme-Secondary-Light-Button-Primary-Fill-Hover);
|
||||
color: var(--Theme-Secondary-Light-Button-Primary-On-Fill-Hover);
|
||||
}
|
||||
|
||||
.secondaryLightPrimary:disabled {
|
||||
background-color: var(--Theme-Secondary-Light-Button-Primary-Fill-Disabled);
|
||||
color: var(--Theme-Secondary-Light-Button-Primary-On-Fill-Disabled);
|
||||
}
|
||||
|
||||
.secondaryLightSecondary {
|
||||
background-color: var(--Theme-Secondary-Light-Button-Secondary-Fill-Normal);
|
||||
border-color: var(--Theme-Secondary-Light-Button-Secondary-Border-Normal);
|
||||
color: var(--Theme-Secondary-Light-Button-Secondary-On-Fill-Normal);
|
||||
}
|
||||
|
||||
.secondaryLightSecondary:active,
|
||||
.secondaryLightSecondary:focus,
|
||||
.secondaryLightSecondary:hover {
|
||||
background-color: var(--Theme-Secondary-Light-Button-Secondary-Fill-Hover);
|
||||
border-color: var(--Theme-Secondary-Light-Button-Secondary-Border-Hover);
|
||||
color: var(--Theme-Secondary-Light-Button-Secondary-On-Fill-Hover);
|
||||
}
|
||||
|
||||
.secondaryLightSecondary:disabled {
|
||||
background-color: var(--Theme-Secondary-Light-Button-Secondary-Fill-Disabled);
|
||||
border-color: var(--Theme-Secondary-Light-Button-Secondary-Border-Disabled);
|
||||
color: var(--Theme-Secondary-Light-Button-Secondary-On-Fill-Disabled);
|
||||
}
|
||||
|
||||
.tertiaryDarkPrimary {
|
||||
background-color: var(--Theme-Tertiary-Dark-Button-Primary-Fill-Normal);
|
||||
color: var(--Theme-Tertiary-Dark-Button-Primary-On-Fill-Normal);
|
||||
}
|
||||
|
||||
.tertiaryDarkPrimary:active,
|
||||
.tertiaryDarkPrimary:focus,
|
||||
.tertiaryDarkPrimary:hover {
|
||||
background-color: var(--Theme-Tertiary-Dark-Button-Primary-Fill-Hover);
|
||||
color: var(--Theme-Tertiary-Dark-Button-Primary-On-Fill-Hover);
|
||||
}
|
||||
|
||||
.tertiaryDarkPrimary:disabled {
|
||||
background-color: var(--Theme-Tertiary-Dark-Button-Primary-Fill-Disabled);
|
||||
color: var(--Theme-Tertiary-Dark-Button-Primary-On-Fill-Disabled);
|
||||
}
|
||||
|
||||
.tertiaryDarkSecondary {
|
||||
background-color: var(--Theme-Tertiary-Dark-Button-Secondary-Fill-Normal);
|
||||
border-color: var(--Theme-Tertiary-Dark-Button-Secondary-Border-Normal);
|
||||
color: var(--Theme-Tertiary-Dark-Button-Secondary-On-Fill-Normal);
|
||||
}
|
||||
|
||||
.tertiaryDarkSecondary:active,
|
||||
.tertiaryDarkSecondary:focus,
|
||||
.tertiaryDarkSecondary:hover {
|
||||
background-color: var(--Theme-Tertiary-Dark-Button-Secondary-Fill-Hover);
|
||||
border-color: var(--Theme-Tertiary-Dark-Button-Secondary-Border-Hover);
|
||||
color: var(--Theme-Tertiary-Dark-Button-Secondary-On-Fill-Hover);
|
||||
}
|
||||
|
||||
.tertiaryDarkSecondary:disabled {
|
||||
background-color: var(--Theme-Tertiary-Dark-Button-Secondary-Fill-Disabled);
|
||||
border-color: var(--Theme-Tertiary-Dark-Button-Secondary-Border-Disabled);
|
||||
color: var(--Theme-Tertiary-Dark-Button-Secondary-On-Fill-Disabled);
|
||||
}
|
||||
|
||||
.tertiaryLightPrimary {
|
||||
background-color: var(--Theme-Tertiary-Light-Button-Primary-Fill-Normal);
|
||||
color: var(--Theme-Tertiary-Light-Button-Primary-On-Fill-Normal);
|
||||
}
|
||||
|
||||
.tertiaryLightPrimary:active,
|
||||
.tertiaryLightPrimary:focus,
|
||||
.tertiaryLightPrimary:hover {
|
||||
background-color: var(--Theme-Tertiary-Light-Button-Primary-Fill-Hover);
|
||||
color: var(--Theme-Tertiary-Light-Button-Primary-On-Fill-Hover);
|
||||
}
|
||||
|
||||
.tertiaryLightPrimary:disabled {
|
||||
background-color: var(--Theme-Tertiary-Light-Button-Primary-Fill-Disabled);
|
||||
color: var(--Theme-Tertiary-Light-Button-Primary-On-Fill-Disabled);
|
||||
}
|
||||
|
||||
.tertiaryLightSecondary {
|
||||
background-color: var(--Tertiary-Light-Button-Secondary-Fill-Normal);
|
||||
border-color: var(--Tertiary-Light-Button-Secondary-Border-Normal);
|
||||
color: var(--Tertiary-Light-Button-Secondary-On-Fill-Normal);
|
||||
}
|
||||
|
||||
.tertiaryLightSecondary:active,
|
||||
.tertiaryLightSecondary:focus,
|
||||
.tertiaryLightSecondary:hover {
|
||||
background-color: var(--Tertiary-Light-Button-Secondary-Fill-Hover);
|
||||
border-color: var(--Tertiary-Light-Button-Secondary-Border-Hover);
|
||||
color: var(--Tertiary-Light-Button-Secondary-On-Fill-Hover);
|
||||
}
|
||||
|
||||
.tertiaryLightSecondary:disabled {
|
||||
background-color: var(--Tertiary-Light-Button-Secondary-Fill-Disabled);
|
||||
border-color: var(--Tertiary-Light-Button-Secondary-Border-Disabled);
|
||||
color: var(--Tertiary-Light-Button-Secondary-On-Fill-Disabled);
|
||||
}
|
||||
|
||||
@@ -5,8 +5,10 @@ import styles from "./button.module.css"
|
||||
export const buttonVariants = cva(styles.btn, {
|
||||
variants: {
|
||||
intent: {
|
||||
inverted: styles.inverted,
|
||||
primary: styles.primary,
|
||||
secondary: styles.secondary,
|
||||
tertiary: styles.tertiary,
|
||||
},
|
||||
size: {
|
||||
small: styles.small,
|
||||
@@ -14,13 +16,14 @@ export const buttonVariants = cva(styles.btn, {
|
||||
large: styles.large,
|
||||
},
|
||||
theme: {
|
||||
primaryDark: styles.primaryDark,
|
||||
primaryLight: styles.primaryLight,
|
||||
primaryStrong: styles.primaryStrong,
|
||||
secondaryLight: styles.secondaryLight,
|
||||
secondaryDark: styles.secondaryDark,
|
||||
tertiaryLight: styles.tertiaryLight,
|
||||
tertiaryDark: styles.tertiaryDark,
|
||||
base: "",
|
||||
primaryDark: "",
|
||||
primaryStrong: "",
|
||||
primaryLight: "",
|
||||
secondaryLight: "",
|
||||
secondaryDark: "",
|
||||
tertiaryLight: "",
|
||||
tertiaryDark: "",
|
||||
},
|
||||
variant: {
|
||||
default: styles.default,
|
||||
@@ -33,4 +36,97 @@ export const buttonVariants = cva(styles.btn, {
|
||||
theme: "primaryLight",
|
||||
variant: "default",
|
||||
},
|
||||
|
||||
compoundVariants: [
|
||||
{
|
||||
className: styles.basePrimary,
|
||||
intent: "primary",
|
||||
theme: "base",
|
||||
},
|
||||
{
|
||||
className: styles.baseSecondary,
|
||||
intent: "secondary",
|
||||
theme: "base",
|
||||
},
|
||||
{
|
||||
className: styles.baseTertiary,
|
||||
intent: "tertiary",
|
||||
theme: "base",
|
||||
},
|
||||
{
|
||||
className: styles.baseInverted,
|
||||
intent: "inverted",
|
||||
theme: "base",
|
||||
},
|
||||
{
|
||||
className: styles.primaryDarkPrimary,
|
||||
intent: "primary",
|
||||
theme: "primaryDark",
|
||||
},
|
||||
{
|
||||
className: styles.primaryDarkSecondary,
|
||||
intent: "secondary",
|
||||
theme: "primaryDark",
|
||||
},
|
||||
{
|
||||
className: styles.primaryLightPrimary,
|
||||
intent: "primary",
|
||||
theme: "primaryLight",
|
||||
},
|
||||
{
|
||||
className: styles.primaryLightSecondary,
|
||||
intent: "secondary",
|
||||
theme: "primaryLight",
|
||||
},
|
||||
{
|
||||
className: styles.primaryStrongPrimary,
|
||||
intent: "primary",
|
||||
theme: "primaryStrong",
|
||||
},
|
||||
{
|
||||
className: styles.primaryStrongSecondary,
|
||||
intent: "secondary",
|
||||
theme: "primaryStrong",
|
||||
},
|
||||
{
|
||||
className: styles.secondaryDarkPrimary,
|
||||
intent: "primary",
|
||||
theme: "secondaryDark",
|
||||
},
|
||||
{
|
||||
className: styles.secondaryDarkSecondary,
|
||||
intent: "secondary",
|
||||
theme: "secondaryDark",
|
||||
},
|
||||
{
|
||||
className: styles.secondaryLightPrimary,
|
||||
intent: "primary",
|
||||
theme: "secondaryLight",
|
||||
},
|
||||
{
|
||||
className: styles.secondaryLightSecondary,
|
||||
intent: "secondary",
|
||||
theme: "secondaryLight",
|
||||
},
|
||||
{
|
||||
className: styles.tertiaryDarkPrimary,
|
||||
intent: "primary",
|
||||
theme: "tertiaryDark",
|
||||
},
|
||||
{
|
||||
className: styles.tertiaryDarkSecondary,
|
||||
intent: "secondary",
|
||||
theme: "tertiaryDark",
|
||||
},
|
||||
{
|
||||
className: styles.tertiaryLightPrimary,
|
||||
intent: "primary",
|
||||
theme: "tertiaryLight",
|
||||
},
|
||||
{
|
||||
className: styles.tertiaryLightSecondary,
|
||||
intent: "secondary",
|
||||
theme: "tertiaryLight",
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
.gridContainer {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.carousel {
|
||||
display: grid;
|
||||
grid-auto-columns: 80dvw;
|
||||
grid-auto-flow: column;
|
||||
gap: var(--Spacing-x2);
|
||||
margin-left: calc(0 - var(--Spacing-x2));
|
||||
margin-right: calc(0 - var(--Spacing-x2));
|
||||
padding-left: var(--Spacing-x2);
|
||||
overflow-x: scroll;
|
||||
scroll-padding-left: var(--Spacing-x2);
|
||||
scroll-snap-type: x mandatory;
|
||||
scrollbar-width: none;
|
||||
/* Hide scrollbar IE and Edge */
|
||||
-ms-overflow-style: none;
|
||||
/* Hide Scrollbar Firefox */
|
||||
}
|
||||
|
||||
.carousel:last-child {
|
||||
margin-right: var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.carousel > * {
|
||||
scroll-snap-align: start;
|
||||
}
|
||||
|
||||
/* Hide Scrollbar Chrome, Safari and Opera */
|
||||
.gridContainer::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1367px) {
|
||||
.twoColumnGrid,
|
||||
.twoPlusOne {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.threeColumnGrid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
|
||||
.twoPlusOne > *:last-child {
|
||||
grid-column: span 2;
|
||||
}
|
||||
|
||||
.carousel {
|
||||
grid-auto-flow: unset;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,46 @@
|
||||
.container {
|
||||
--select-border: 2px solid var(--UI-Grey-60);
|
||||
--select-width: min(28rem, 100%);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.comboBoxContainer {
|
||||
background-color: var(--Main-Grey-White);
|
||||
border-color: var(--Scandic-Beige-40);
|
||||
border-radius: var(--Corner-radius-Medium);
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
display: grid;
|
||||
grid-template-areas: "content";
|
||||
width: var(--select-width);
|
||||
gap: var(--Spacing-x-half);
|
||||
grid-template-areas:
|
||||
"label chevron"
|
||||
"input chevron";
|
||||
grid-template-columns: 1fr auto;
|
||||
grid-template-rows: auto auto;
|
||||
height: 60px;
|
||||
padding: var(--Spacing-x1) var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.label {
|
||||
grid-area: label;
|
||||
}
|
||||
|
||||
.input {
|
||||
background-color: var(--Main-Grey-White);
|
||||
border: var(--select-border);
|
||||
border-radius: var(--Corner-radius-Small);
|
||||
grid-area: content;
|
||||
height: 40px;
|
||||
padding: var(--Spacing-x1) var(--Spacing-x2);
|
||||
width: var(--select-width);
|
||||
border: none;
|
||||
grid-area: input;
|
||||
height: 18px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.input,
|
||||
.listBoxItem {
|
||||
color: var(--UI-Grey-60);
|
||||
color: var(--Main-Grey-100);
|
||||
}
|
||||
|
||||
.button {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
grid-area: content;
|
||||
grid-area: chevron;
|
||||
height: 100%;
|
||||
justify-self: flex-end;
|
||||
padding-left: 0;
|
||||
@@ -38,13 +49,27 @@
|
||||
|
||||
.popover {
|
||||
background-color: var(--Main-Grey-White);
|
||||
border: var(--select-border);
|
||||
border-radius: var(--Corner-radius-Small);
|
||||
border-color: var(--Scandic-Beige-40);
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-radius: var(--Corner-radius-Medium);
|
||||
left: 0px;
|
||||
max-height: 400px;
|
||||
overflow: auto;
|
||||
padding: var(--Spacing-x2) var(--Spacing-x2) var(--Spacing-x2) var(--Spacing-x1);
|
||||
width: var(--select-width);
|
||||
padding: var(--Spacing-x2);
|
||||
top: calc(60px + var(--Spacing-x1));
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.listBoxItem {
|
||||
padding: 0 var(--Spacing-x1);
|
||||
}
|
||||
padding: var(--Spacing-x1) var(--Spacing-x1) var(--Spacing-x1)
|
||||
var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.listBoxItem[data-selected="true"],
|
||||
.listBoxItem:hover {
|
||||
background-color: var(--Scandic-Blue-00);
|
||||
border-radius: var(--Corner-radius-Medium);
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import type { RegisterOptions } from "react-hook-form"
|
||||
|
||||
export type CountryProps = {
|
||||
label: string
|
||||
name?: string
|
||||
placeholder?: string
|
||||
registerOptions?: RegisterOptions
|
||||
}
|
||||
|
||||
export type CountryPortalContainer = HTMLDivElement | undefined
|
||||
export type CountryPortalContainerArgs = HTMLDivElement | null
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
import { ErrorMessage } from "@hookform/error-message"
|
||||
import { useRef } from "react"
|
||||
import { useState } from "react"
|
||||
import {
|
||||
Button,
|
||||
ComboBox,
|
||||
@@ -14,21 +14,33 @@ import {
|
||||
import { useController, useFormContext } from "react-hook-form"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import Label from "@/components/TempDesignSystem/Form/Label"
|
||||
import SelectChevron from "@/components/TempDesignSystem/Form/SelectChevron"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
|
||||
import SelectChevron from "../SelectChevron"
|
||||
import { countries } from "./countries"
|
||||
|
||||
import styles from "./country.module.css"
|
||||
|
||||
import type { CountryProps } from "./country"
|
||||
import type {
|
||||
CountryPortalContainer,
|
||||
CountryPortalContainerArgs,
|
||||
CountryProps,
|
||||
} from "./country"
|
||||
|
||||
export default function CountrySelect({
|
||||
label,
|
||||
name = "country",
|
||||
registerOptions,
|
||||
registerOptions = {},
|
||||
}: CountryProps) {
|
||||
const { formatMessage } = useIntl()
|
||||
const divRef = useRef<HTMLDivElement>(null)
|
||||
const [rootDiv, setRootDiv] = useState<CountryPortalContainer>(undefined)
|
||||
|
||||
function setRef(node: CountryPortalContainerArgs) {
|
||||
if (node) {
|
||||
setRootDiv(node)
|
||||
}
|
||||
}
|
||||
const { control, setValue } = useFormContext()
|
||||
const { field } = useController({
|
||||
control,
|
||||
@@ -43,7 +55,7 @@ export default function CountrySelect({
|
||||
const selectCountryLabel = formatMessage({ id: "Select a country" })
|
||||
|
||||
return (
|
||||
<div className={styles.container} ref={divRef}>
|
||||
<div className={styles.container} ref={setRef}>
|
||||
<ComboBox
|
||||
aria-label={formatMessage({ id: "Select country of residence" })}
|
||||
className={styles.select}
|
||||
@@ -55,6 +67,13 @@ export default function CountrySelect({
|
||||
selectedKey={field.value}
|
||||
>
|
||||
<div className={styles.comboBoxContainer}>
|
||||
<Label
|
||||
className={styles.label}
|
||||
size="small"
|
||||
required={!!registerOptions.required}
|
||||
>
|
||||
{label}
|
||||
</Label>
|
||||
<Body asChild fontOnly>
|
||||
<Input
|
||||
aria-label={selectCountryLabel}
|
||||
@@ -73,13 +92,14 @@ export default function CountrySelect({
|
||||
className={styles.popover}
|
||||
placement="bottom"
|
||||
shouldFlip={false}
|
||||
shouldUpdatePosition={false}
|
||||
/**
|
||||
* react-aria uses portals to render Popover in body
|
||||
* unless otherwise specified. We need it to be contained
|
||||
* by this component to both access css variables assigned
|
||||
* on the container as well as to not overflow it at any time.
|
||||
*/
|
||||
UNSTABLE_portalContainer={divRef.current ?? undefined}
|
||||
UNSTABLE_portalContainer={rootDiv}
|
||||
>
|
||||
<ListBox>
|
||||
{countries.map((country, idx) => (
|
||||
|
||||
@@ -1,20 +1,9 @@
|
||||
/* Leaving, will most likely get deleted */
|
||||
.container {
|
||||
--border: 2px solid var(--some-black-color, #757575);
|
||||
--radius: 0.4rem;
|
||||
--width: min(28rem, 100%);
|
||||
|
||||
--width-day: 6rem;
|
||||
--width-month: 6rem;
|
||||
--width-year: 8rem;
|
||||
|
||||
display: grid;
|
||||
gap: 0.8rem;
|
||||
grid-template-areas: "day month year";
|
||||
grid-template-columns: min(--width-day, 1fr) min(--width-month, 1fr) min(
|
||||
--width-year,
|
||||
2fr
|
||||
);
|
||||
gap: var(--Spacing-x2);
|
||||
grid-template-areas: "year month day";
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
width: var(--width);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import type { Control, RegisterOptions } from "react-hook-form"
|
||||
|
||||
import type { EditProfileSchema } from "@/components/MyProfile/Profile/Edit/Form/schema"
|
||||
import type { RegisterOptions } from "react-hook-form"
|
||||
|
||||
export const enum DateName {
|
||||
date = "date",
|
||||
@@ -9,7 +7,6 @@ export const enum DateName {
|
||||
}
|
||||
export interface DateProps
|
||||
extends React.SelectHTMLAttributes<HTMLSelectElement> {
|
||||
control: Control<EditProfileSchema>
|
||||
name: keyof EditProfileSchema
|
||||
registerOptions: RegisterOptions<EditProfileSchema>
|
||||
name: string
|
||||
registerOptions: RegisterOptions
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@ import { useIntl } from "react-intl"
|
||||
|
||||
import { dt } from "@/lib/dt"
|
||||
|
||||
import Select from "@/components/TempDesignSystem/Select"
|
||||
import { rangeArray } from "@/utils/rangeArray"
|
||||
|
||||
import Select from "../Select"
|
||||
import { DateName } from "./date"
|
||||
|
||||
import styles from "./date.module.css"
|
||||
@@ -23,14 +23,10 @@ import type { Key } from "react-aria-components"
|
||||
import type { DateProps } from "./date"
|
||||
|
||||
/** TODO: Get selecting with Enter-key to work */
|
||||
export default function DateSelect({
|
||||
control,
|
||||
name,
|
||||
registerOptions,
|
||||
}: DateProps) {
|
||||
export default function DateSelect({ name, registerOptions }: DateProps) {
|
||||
const { formatMessage } = useIntl()
|
||||
const d = useWatch({ name })
|
||||
const { setValue } = useFormContext()
|
||||
const { control, setValue } = useFormContext()
|
||||
const { field } = useController({
|
||||
control,
|
||||
name,
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
.message {
|
||||
align-items: center;
|
||||
color: var(--Scandic-Red-60);
|
||||
margin: var(--Spacing-x-half) 0 0;
|
||||
}
|
||||
display: flex;
|
||||
gap: var(--Spacing-x-half);
|
||||
margin: var(--Spacing-x1) 0 0;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ErrorMessage as RHFErrorMessage } from "@hookform/error-message"
|
||||
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import { InfoCircleIcon } from "@/components/Icons"
|
||||
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
||||
|
||||
import styles from "./error.module.css"
|
||||
|
||||
@@ -15,9 +16,10 @@ export default function ErrorMessage<T>({
|
||||
errors={errors}
|
||||
name={name}
|
||||
render={({ message }) => (
|
||||
<Body className={styles.message} fontOnly>
|
||||
<Caption className={styles.message} fontOnly>
|
||||
<InfoCircleIcon color="red" />
|
||||
{message}
|
||||
</Body>
|
||||
</Caption>
|
||||
)}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
"use client"
|
||||
import { Input as AriaInput, TextField } from "react-aria-components"
|
||||
import { useController } from "react-hook-form"
|
||||
import {
|
||||
Input as AriaInput,
|
||||
Label as AriaLabel,
|
||||
TextField,
|
||||
} from "react-aria-components"
|
||||
import { useController, useFormContext } from "react-hook-form"
|
||||
|
||||
import ErrorMessage from "@/components/TempDesignSystem/Form/ErrorMessage"
|
||||
import Label from "@/components/TempDesignSystem/Form/Label"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
|
||||
import styles from "./input.module.css"
|
||||
@@ -11,17 +16,24 @@ import type { InputProps } from "./input"
|
||||
|
||||
export default function Input({
|
||||
"aria-label": ariaLabel,
|
||||
control,
|
||||
disabled,
|
||||
label,
|
||||
name,
|
||||
placeholder,
|
||||
registerOptions,
|
||||
placeholder = "",
|
||||
registerOptions = {},
|
||||
required = false,
|
||||
type = "text",
|
||||
}: InputProps) {
|
||||
const { control } = useFormContext()
|
||||
const rules = {
|
||||
...registerOptions,
|
||||
required:
|
||||
"required" in registerOptions ? !!registerOptions.required : required,
|
||||
}
|
||||
const { field, fieldState, formState } = useController({
|
||||
control,
|
||||
name,
|
||||
rules: registerOptions,
|
||||
rules,
|
||||
})
|
||||
|
||||
return (
|
||||
@@ -32,18 +44,24 @@ export default function Input({
|
||||
isInvalid={fieldState.invalid}
|
||||
isRequired={!!registerOptions?.required}
|
||||
name={field.name}
|
||||
onBlur={field.onBlur}
|
||||
onChange={field.onChange}
|
||||
type={type}
|
||||
>
|
||||
<Body asChild fontOnly>
|
||||
<AriaInput
|
||||
className={styles.input}
|
||||
placeholder={placeholder}
|
||||
ref={field.ref}
|
||||
/>
|
||||
</Body>
|
||||
<ErrorMessage errors={formState.errors} name={name} />
|
||||
<AriaLabel className={styles.container} htmlFor={field.name}>
|
||||
<Body asChild fontOnly>
|
||||
<AriaInput
|
||||
className={styles.input}
|
||||
id={field.name}
|
||||
name={field.name}
|
||||
onBlur={field.onBlur}
|
||||
onChange={field.onChange}
|
||||
placeholder={placeholder}
|
||||
ref={field.ref}
|
||||
required={rules.required}
|
||||
/>
|
||||
</Body>
|
||||
<Label required={rules.required}>{label}</Label>
|
||||
</AriaLabel>
|
||||
<ErrorMessage errors={formState.errors} name={field.name} />
|
||||
</TextField>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,44 @@
|
||||
.input {
|
||||
border: 2px solid var(--UI-Grey-60);
|
||||
border-radius: var(--Corner-radius-Small);
|
||||
color: var(--UI-Grey-60);
|
||||
height: 40px;
|
||||
.container {
|
||||
align-content: center;
|
||||
background-color: var(--Main-Grey-White);
|
||||
border-color: var(--Scandic-Beige-40);
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-radius: var(--Corner-radius-Medium);
|
||||
display: grid;
|
||||
gap: var(--Spacing-x-half);
|
||||
grid-template-rows: auto auto;
|
||||
height: 60px;
|
||||
padding: var(--Spacing-x1) var(--Spacing-x2);
|
||||
width: min(280px, 100%);
|
||||
}
|
||||
transition: border-color 200ms ease;
|
||||
}
|
||||
|
||||
.container:has(.input:not(:focus):placeholder-shown) {
|
||||
gap: 0;
|
||||
grid-template-rows: 1fr;
|
||||
}
|
||||
|
||||
.container:has(.input:active, .input:focus) {
|
||||
border-color: var(--Scandic-Blue-90);
|
||||
}
|
||||
|
||||
.input {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--Main-Grey-100);
|
||||
height: 18px;
|
||||
margin: 0;
|
||||
order: 2;
|
||||
overflow: visible;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.input:not(:active, :focus):placeholder-shown {
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
.input:focus,
|
||||
.input:focus:placeholder-shown {
|
||||
height: 18px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { Control, RegisterOptions } from "react-hook-form"
|
||||
|
||||
import { EditProfileSchema } from "@/components/MyProfile/Profile/Edit/Form/schema"
|
||||
import type { RegisterOptions } from "react-hook-form"
|
||||
|
||||
export interface InputProps
|
||||
extends React.InputHTMLAttributes<HTMLInputElement> {
|
||||
control: Control<EditProfileSchema>
|
||||
name: keyof EditProfileSchema
|
||||
registerOptions?: RegisterOptions<EditProfileSchema>
|
||||
label: string
|
||||
name: string
|
||||
registerOptions?: RegisterOptions
|
||||
}
|
||||
|
||||
20
components/TempDesignSystem/Form/Label/index.tsx
Normal file
20
components/TempDesignSystem/Form/Label/index.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import { labelVariants } from "./variants"
|
||||
|
||||
import type { LabelProps } from "./label"
|
||||
|
||||
export default function Label({
|
||||
children,
|
||||
className,
|
||||
required,
|
||||
size,
|
||||
}: LabelProps) {
|
||||
const classNames = labelVariants({
|
||||
className,
|
||||
size,
|
||||
})
|
||||
return (
|
||||
<span className={classNames}>
|
||||
{children} {required ? "*" : ""}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
30
components/TempDesignSystem/Form/Label/label.module.css
Normal file
30
components/TempDesignSystem/Form/Label/label.module.css
Normal file
@@ -0,0 +1,30 @@
|
||||
.label {
|
||||
color: var(--UI-Grey-60);
|
||||
font-family: "fira sans";
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.03px;
|
||||
line-height: 120%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
span.small {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
span.regular {
|
||||
font-size: 16px;
|
||||
order: 1;
|
||||
transition: font-size 200ms ease 100ms;
|
||||
}
|
||||
|
||||
input:focus ~ .label,
|
||||
input:not(:placeholder-shown) ~ .label {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
input:placeholder-shown ~ .label {
|
||||
align-self: center;
|
||||
grid-row: 1/-1;
|
||||
}
|
||||
9
components/TempDesignSystem/Form/Label/label.ts
Normal file
9
components/TempDesignSystem/Form/Label/label.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { labelVariants } from "./variants"
|
||||
|
||||
import type { VariantProps } from "class-variance-authority"
|
||||
|
||||
export interface LabelProps
|
||||
extends React.PropsWithChildren<React.HTMLAttributes<HTMLSpanElement>>,
|
||||
VariantProps<typeof labelVariants> {
|
||||
required?: boolean
|
||||
}
|
||||
15
components/TempDesignSystem/Form/Label/variants.ts
Normal file
15
components/TempDesignSystem/Form/Label/variants.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { cva } from "class-variance-authority"
|
||||
|
||||
import styles from "./label.module.css"
|
||||
|
||||
export const labelVariants = cva(styles.label, {
|
||||
variants: {
|
||||
size: {
|
||||
small: styles.small,
|
||||
regular: styles.regular,
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
size: "regular",
|
||||
},
|
||||
})
|
||||
@@ -1,99 +1,137 @@
|
||||
"use client"
|
||||
import "react-international-phone/style.css"
|
||||
|
||||
import { useCallback, useEffect, useRef } from "react"
|
||||
import { parsePhoneNumber } from "libphonenumber-js"
|
||||
import {
|
||||
Input as AriaInput,
|
||||
Label as AriaLabel,
|
||||
TextField,
|
||||
} from "react-aria-components"
|
||||
import { useController, useFormContext, useWatch } from "react-hook-form"
|
||||
import {
|
||||
defaultCountries,
|
||||
getCountry,
|
||||
PhoneInput,
|
||||
type PhoneInputRefType,
|
||||
CountrySelector,
|
||||
DialCodePreview,
|
||||
ParsedCountry,
|
||||
usePhoneInput,
|
||||
} from "react-international-phone"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { ChevronDownIcon } from "@/components/Icons"
|
||||
import ErrorMessage from "@/components/TempDesignSystem/Form/ErrorMessage"
|
||||
import Label from "@/components/TempDesignSystem/Form/Label"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
|
||||
import styles from "./phone.module.css"
|
||||
|
||||
import type { ChangeEvent } from "react"
|
||||
|
||||
import type { PhoneProps } from "./phone"
|
||||
|
||||
export default function Phone({
|
||||
countrySelectName = "country",
|
||||
ariaLabel = "Phone number input",
|
||||
disabled = false,
|
||||
label,
|
||||
name = "phoneNumber",
|
||||
placeholder = "",
|
||||
registerOptions = {
|
||||
required: true,
|
||||
},
|
||||
}: PhoneProps) {
|
||||
const phoneRef = useRef<PhoneInputRefType>(null)
|
||||
const { control, formState } = useFormContext()
|
||||
const countryValue = useWatch({ name: countrySelectName })
|
||||
const defaultCountry = getCountry({
|
||||
countries: defaultCountries,
|
||||
field: "iso2",
|
||||
value: String(countryValue).toLowerCase(),
|
||||
})
|
||||
/**
|
||||
* Holds the previous selected country to be able to update
|
||||
* countrycode based on country select field.
|
||||
* Since PhoneInput inputs the countrys dialcode (country code) upon
|
||||
* selection, we need to check if the current value is just
|
||||
* the previously selected countrys dialcode number.
|
||||
*/
|
||||
const prevSelectedCountry = useRef<string | undefined>(countryValue)
|
||||
const { field } = useController({
|
||||
const { formatMessage } = useIntl()
|
||||
const { control, setValue } = useFormContext()
|
||||
const phone = useWatch({ name })
|
||||
|
||||
const { field, fieldState, formState } = useController({
|
||||
control,
|
||||
disabled,
|
||||
name,
|
||||
rules: registerOptions,
|
||||
})
|
||||
|
||||
const handleCountrySelectForPhone = useCallback((country: string) => {
|
||||
const selectedCountry = getCountry({
|
||||
countries: defaultCountries,
|
||||
field: "iso2",
|
||||
value: country.toLowerCase(),
|
||||
const { country, handlePhoneValueChange, inputValue, setCountry } =
|
||||
usePhoneInput({
|
||||
defaultCountry:
|
||||
parsePhoneNumber(
|
||||
formState.defaultValues?.phoneNumber
|
||||
).country?.toLowerCase() ?? "sv",
|
||||
disableCountryGuess: true,
|
||||
forceDialCode: true,
|
||||
value: phone,
|
||||
})
|
||||
|
||||
if (selectedCountry) {
|
||||
phoneRef.current?.setCountry(selectedCountry.iso2)
|
||||
prevSelectedCountry.current = country.toLowerCase()
|
||||
}
|
||||
}, [])
|
||||
function handleSelectCountry(value: ParsedCountry) {
|
||||
setCountry(value.iso2)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (countryValue) {
|
||||
if (field.value) {
|
||||
if (prevSelectedCountry.current) {
|
||||
if (prevSelectedCountry.current !== countryValue) {
|
||||
const selectedCountryPrev = getCountry({
|
||||
countries: defaultCountries,
|
||||
field: "iso2",
|
||||
value: prevSelectedCountry.current.toLowerCase(),
|
||||
})
|
||||
if (
|
||||
field.value.replace("+", "") === selectedCountryPrev?.dialCode
|
||||
) {
|
||||
handleCountrySelectForPhone(countryValue)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
handleCountrySelectForPhone(countryValue)
|
||||
}
|
||||
} else {
|
||||
handleCountrySelectForPhone(countryValue)
|
||||
}
|
||||
}
|
||||
}, [countryValue, field.value, handleCountrySelectForPhone])
|
||||
function handleChange(evt: ChangeEvent<HTMLInputElement>) {
|
||||
handlePhoneValueChange(evt)
|
||||
setValue(name, evt.target.value)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.phone}>
|
||||
<PhoneInput
|
||||
{...field}
|
||||
className={styles.input}
|
||||
defaultCountry={defaultCountry?.iso2 ?? "se"}
|
||||
placeholder={placeholder}
|
||||
<CountrySelector
|
||||
dropdownArrowClassName={styles.arrow}
|
||||
flagClassName={styles.flag}
|
||||
onSelect={handleSelectCountry}
|
||||
preferredCountries={["de", "dk", "fi", "no", "se", "gb"]}
|
||||
ref={phoneRef}
|
||||
selectedCountry={country.iso2}
|
||||
renderButtonWrapper={(props) => (
|
||||
<button
|
||||
{...props.rootProps}
|
||||
className={styles.select}
|
||||
tabIndex={0}
|
||||
type="button"
|
||||
>
|
||||
<Label required={!!registerOptions.required} size="small">
|
||||
{formatMessage({ id: "Country code" })}
|
||||
</Label>
|
||||
<div className={styles.selectContainer}>
|
||||
{props.children}
|
||||
<Body asChild fontOnly>
|
||||
<DialCodePreview
|
||||
className={styles.dialCode}
|
||||
dialCode={country.dialCode}
|
||||
prefix="+"
|
||||
/>
|
||||
</Body>
|
||||
<ChevronDownIcon
|
||||
className={styles.chevron}
|
||||
color="grey80"
|
||||
height={18}
|
||||
width={18}
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
)}
|
||||
/>
|
||||
<TextField
|
||||
aria-label={ariaLabel}
|
||||
defaultValue={field.value}
|
||||
isDisabled={disabled ?? field.disabled}
|
||||
isInvalid={fieldState.invalid}
|
||||
isRequired={!!registerOptions?.required}
|
||||
name={field.name}
|
||||
type="tel"
|
||||
>
|
||||
<AriaLabel className={styles.inputContainer} htmlFor={field.name}>
|
||||
<Body asChild fontOnly>
|
||||
<AriaInput
|
||||
className={styles.input}
|
||||
id={field.name}
|
||||
name={field.name}
|
||||
onBlur={field.onBlur}
|
||||
onChange={handleChange}
|
||||
placeholder={placeholder}
|
||||
ref={field.ref}
|
||||
required={!!registerOptions.required}
|
||||
value={inputValue}
|
||||
/>
|
||||
</Body>
|
||||
<Label required={!!registerOptions.required}>{label}</Label>
|
||||
</AriaLabel>
|
||||
<ErrorMessage errors={formState.errors} name={field.name} />
|
||||
</TextField>
|
||||
<ErrorMessage errors={formState.errors} name={name} />
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -1,26 +1,130 @@
|
||||
.phone {
|
||||
--react-international-phone-border-color: var(--UI-Grey-60);
|
||||
--react-international-phone-border-radius: var(--Corner-radius-Small);
|
||||
--react-international-phone-font-size: var(
|
||||
--typography-Body-Regular-fontSize
|
||||
);
|
||||
--react-international-phone-height: 40px;
|
||||
--react-international-phone-text-color: var(--UI-Grey-60);
|
||||
}
|
||||
|
||||
.phone :global(.react-international-phone-input-container) {
|
||||
display: grid;
|
||||
/* r-i-p sets their width dynamically and doesn't respect the width property of its parent */
|
||||
grid-template-columns: 470px minmax(203px, 1fr);
|
||||
width: min(280px, 100%);
|
||||
gap: var(--Spacing-x2);
|
||||
grid-template-columns: max(164px) 1fr;
|
||||
|
||||
--react-international-phone-background-color: var(--Main-Grey-White);
|
||||
--react-international-phone-border-color: var(--Scandic-Beige-40);
|
||||
--react-international-phone-dropdown-preferred-list-divider-color: var(
|
||||
--Scandic-Brand-Pale-Peach
|
||||
);
|
||||
--react-international-phone-selected-dropdown-item-background-color: var(
|
||||
--Scandic-Blue-00
|
||||
);
|
||||
--react-international-phone-text-color: var(--Main-Grey-100);
|
||||
|
||||
--react-international-phone-dropdown-preferred-list-divider-margin: 8px;
|
||||
|
||||
--react-international-phone-height: 60px;
|
||||
--react-international-phone-dropdown-top: calc(
|
||||
var(--react-international-phone-height) + var(--Spacing-x1)
|
||||
);
|
||||
}
|
||||
|
||||
/* react-international-phone only exposes variables to change border-color */
|
||||
.phone :global(.react-international-phone-country-selector-button),
|
||||
.phone :global(.react-international-phone-input) {
|
||||
border-width: 2px;
|
||||
.phone:has(.input:active, .input:focus) {
|
||||
--react-international-phone-border-color: var(--Scandic-Blue-90);
|
||||
}
|
||||
|
||||
.phone :global(.react-international-phone-input) {
|
||||
.phone :global(.react-international-phone-country-selector-dropdown) {
|
||||
background: var(--Main-Grey-White);
|
||||
border-radius: var(--Corner-radius-Medium);
|
||||
box-shadow: 0px 4px 24px 0px rgba(0, 0, 0, 0.08);
|
||||
gap: var(--Spacing-x1);
|
||||
outline: none;
|
||||
padding: var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.phone
|
||||
:global(.react-international-phone-country-selector-dropdown__list-item) {
|
||||
border-radius: var(--Corner-radius-Medium);
|
||||
padding: var(--Spacing-x1) var(--Spacing-x1) var(--Spacing-x1)
|
||||
var(--Spacing-x-one-and-half);
|
||||
}
|
||||
|
||||
.phone
|
||||
:global(.react-international-phone-country-selector-button__button-content) {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.inputContainer,
|
||||
.select {
|
||||
align-content: center;
|
||||
background-color: var(--Main-Grey-White);
|
||||
border-color: var(--Scandic-Beige-40);
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-radius: var(--Corner-radius-Medium);
|
||||
display: grid;
|
||||
gap: var(--Spacing-x-half);
|
||||
grid-template-rows: auto auto;
|
||||
height: 60px;
|
||||
padding: var(--Spacing-x1) var(--Spacing-x2);
|
||||
transition: border-color 200ms ease;
|
||||
}
|
||||
|
||||
.select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.select[aria-expanded="true"] .chevron {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.selectContainer {
|
||||
background-color: var(--Main-Grey-White);
|
||||
border: none;
|
||||
display: grid;
|
||||
gap: var(--Spacing-x1);
|
||||
grid-template-columns: auto 1fr auto;
|
||||
height: 18px;
|
||||
justify-content: flex-start;
|
||||
order: 2;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.flag {
|
||||
height: 18px;
|
||||
margin: 0;
|
||||
width: 18px;
|
||||
}
|
||||
|
||||
.select .dialCode {
|
||||
border: none;
|
||||
color: var(--Main-Grey-100);
|
||||
line-height: 1;
|
||||
justify-self: flex-start;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.inputContainer:has(.input:not(:focus):placeholder-shown) {
|
||||
gap: 0;
|
||||
grid-template-rows: 1fr;
|
||||
}
|
||||
|
||||
.inputContainer:has(.input:active, .input:focus) {
|
||||
border-color: var(--Scandic-Blue-90);
|
||||
}
|
||||
|
||||
.input {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--Main-Grey-100);
|
||||
height: 18px;
|
||||
margin: 0;
|
||||
order: 2;
|
||||
overflow: visible;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.input:not(:active, :focus):placeholder-shown {
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
.input:focus,
|
||||
.input:focus:placeholder-shown {
|
||||
height: 18px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import type { RegisterOptions } from "react-hook-form"
|
||||
|
||||
export type PhoneProps = {
|
||||
countrySelectName?: string
|
||||
ariaLabel?: string
|
||||
disabled?: boolean
|
||||
label: string
|
||||
name?: string
|
||||
placeholder?: string
|
||||
registerOptions?: RegisterOptions
|
||||
|
||||
@@ -1,94 +1,35 @@
|
||||
"use client"
|
||||
import { useState } from "react"
|
||||
import {
|
||||
Button,
|
||||
type Key,
|
||||
Label,
|
||||
ListBox,
|
||||
ListBoxItem,
|
||||
Popover,
|
||||
Select as ReactAriaSelect,
|
||||
SelectValue,
|
||||
} from "react-aria-components"
|
||||
import { useController, useFormContext } from "react-hook-form"
|
||||
|
||||
import Body from "../../Text/Body"
|
||||
import Footnote from "../../Text/Footnote"
|
||||
import SelectChevron from "../SelectChevron"
|
||||
import ReactAriaSelect from "@/components/TempDesignSystem/Select"
|
||||
|
||||
import styles from "./select.module.css"
|
||||
|
||||
import type { SelectPortalContainer, SelectProps } from "./select"
|
||||
import type { SelectProps } from "./select"
|
||||
|
||||
export default function Select({
|
||||
"aria-label": ariaLabel,
|
||||
items,
|
||||
label,
|
||||
onSelect,
|
||||
name,
|
||||
placeholder,
|
||||
value,
|
||||
defaultSelectedKey,
|
||||
registerOptions = {},
|
||||
}: SelectProps) {
|
||||
const [rootDiv, setRootDiv] = useState<SelectPortalContainer>(null)
|
||||
|
||||
function setRef(node: SelectPortalContainer) {
|
||||
if (node) {
|
||||
setRootDiv(node)
|
||||
}
|
||||
}
|
||||
|
||||
function handleOnSelect(key: Key) {
|
||||
onSelect(key)
|
||||
}
|
||||
const { control } = useFormContext()
|
||||
const { field } = useController({
|
||||
control,
|
||||
name,
|
||||
rules: registerOptions,
|
||||
})
|
||||
|
||||
return (
|
||||
<div className={styles.container} ref={setRef}>
|
||||
<ReactAriaSelect
|
||||
defaultSelectedKey={defaultSelectedKey}
|
||||
aria-label={ariaLabel}
|
||||
className={styles.select}
|
||||
onSelectionChange={handleOnSelect}
|
||||
placeholder={placeholder}
|
||||
selectedKey={value as Key}
|
||||
>
|
||||
<Body asChild fontOnly>
|
||||
<Button className={styles.input}>
|
||||
<div className={styles.inputContentWrapper}>
|
||||
<Footnote asChild fontOnly>
|
||||
<Label className={styles.label}>{label}</Label>
|
||||
</Footnote>
|
||||
<SelectValue />
|
||||
</div>
|
||||
<SelectChevron />
|
||||
</Button>
|
||||
</Body>
|
||||
<Body asChild fontOnly>
|
||||
<Popover
|
||||
className={styles.popover}
|
||||
placement="bottom"
|
||||
shouldFlip={false}
|
||||
/**
|
||||
* react-aria uses portals to render Popover in body
|
||||
* unless otherwise specified. We need it to be contained
|
||||
* by this component to both access css variables assigned
|
||||
* on the container as well as to not overflow it at any time.
|
||||
*/
|
||||
UNSTABLE_portalContainer={rootDiv ?? undefined}
|
||||
>
|
||||
<ListBox className={styles.listBox}>
|
||||
{items.map((item) => (
|
||||
<ListBoxItem
|
||||
aria-label={String(item)}
|
||||
className={styles.listBoxItem}
|
||||
id={item.value}
|
||||
key={item.label}
|
||||
>
|
||||
{item.label}
|
||||
</ListBoxItem>
|
||||
))}
|
||||
</ListBox>
|
||||
</Popover>
|
||||
</Body>
|
||||
</ReactAriaSelect>
|
||||
</div>
|
||||
<ReactAriaSelect
|
||||
defaultSelectedKey={field.value}
|
||||
disabled={field.disabled}
|
||||
items={items}
|
||||
label={label}
|
||||
name={field.name}
|
||||
onBlur={field.onBlur}
|
||||
onSelect={field.onChange}
|
||||
placeholder={placeholder}
|
||||
value={field.value}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import type { Key } from "react-aria-components"
|
||||
import type { RegisterOptions } from "react-hook-form"
|
||||
|
||||
import type { SelectProps as ReactAriaSelectProps } from "@/components/TempDesignSystem/Select/select"
|
||||
|
||||
export interface SelectProps
|
||||
extends Omit<React.SelectHTMLAttributes<HTMLSelectElement>, "onSelect"> {
|
||||
items: { label: string; value: Key }[]
|
||||
label: string
|
||||
name: string
|
||||
onSelect: (key: Key) => void
|
||||
placeholder?: string
|
||||
defaultSelectedKey?: Key
|
||||
extends Omit<
|
||||
React.SelectHTMLAttributes<HTMLSelectElement>,
|
||||
"name" | "onSelect"
|
||||
>,
|
||||
Omit<ReactAriaSelectProps, "onSelect" | "ref" | "value"> {
|
||||
registerOptions?: RegisterOptions
|
||||
}
|
||||
|
||||
export type SelectPortalContainer = HTMLDivElement | null
|
||||
|
||||
@@ -5,7 +5,7 @@ import styles from "./chevron.module.css"
|
||||
export default function SelectChevron() {
|
||||
return (
|
||||
<span aria-hidden="true" className={styles.chevron}>
|
||||
<ChevronDownIcon height={24} width={24} />
|
||||
<ChevronDownIcon color="grey80" />
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
}
|
||||
|
||||
.activeSidebar {
|
||||
background-color: var(--Scandic-Brand-Warm-White);
|
||||
background-color: var(--Scandic-Brand-Pale-Peach);
|
||||
}
|
||||
|
||||
.black {
|
||||
|
||||
@@ -10,6 +10,7 @@ export const linkVariants = cva(styles.link, {
|
||||
color: {
|
||||
black: styles.black,
|
||||
burgundy: styles.burgundy,
|
||||
none: "",
|
||||
pale: styles.pale,
|
||||
peach80: styles.peach80,
|
||||
},
|
||||
|
||||
98
components/TempDesignSystem/Select/index.tsx
Normal file
98
components/TempDesignSystem/Select/index.tsx
Normal file
@@ -0,0 +1,98 @@
|
||||
"use client"
|
||||
import { useState } from "react"
|
||||
import {
|
||||
Button,
|
||||
type Key,
|
||||
ListBox,
|
||||
ListBoxItem,
|
||||
Popover,
|
||||
Select as ReactAriaSelect,
|
||||
SelectValue,
|
||||
} from "react-aria-components"
|
||||
|
||||
import Label from "@/components/TempDesignSystem/Form/Label"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
|
||||
import SelectChevron from "../Form/SelectChevron"
|
||||
|
||||
import styles from "./select.module.css"
|
||||
|
||||
import type {
|
||||
SelectPortalContainer,
|
||||
SelectPortalContainerArgs,
|
||||
SelectProps,
|
||||
} from "./select"
|
||||
|
||||
export default function Select({
|
||||
"aria-label": ariaLabel,
|
||||
defaultSelectedKey,
|
||||
items,
|
||||
label,
|
||||
name,
|
||||
onSelect,
|
||||
placeholder,
|
||||
value,
|
||||
}: SelectProps) {
|
||||
const [rootDiv, setRootDiv] = useState<SelectPortalContainer>(undefined)
|
||||
|
||||
function setRef(node: SelectPortalContainerArgs) {
|
||||
if (node) {
|
||||
setRootDiv(node)
|
||||
}
|
||||
}
|
||||
|
||||
function handleOnSelect(key: Key) {
|
||||
onSelect(key)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.container} ref={setRef}>
|
||||
<ReactAriaSelect
|
||||
aria-label={ariaLabel}
|
||||
className={styles.select}
|
||||
defaultSelectedKey={defaultSelectedKey}
|
||||
name={name}
|
||||
onSelectionChange={handleOnSelect}
|
||||
placeholder={placeholder}
|
||||
selectedKey={value as Key}
|
||||
>
|
||||
<Body asChild fontOnly>
|
||||
<Button className={styles.input}>
|
||||
<div className={styles.inputContentWrapper}>
|
||||
<Label size="small">{label}</Label>
|
||||
<SelectValue />
|
||||
</div>
|
||||
<SelectChevron />
|
||||
</Button>
|
||||
</Body>
|
||||
<Body asChild fontOnly>
|
||||
<Popover
|
||||
className={styles.popover}
|
||||
placement="bottom"
|
||||
shouldFlip={false}
|
||||
/**
|
||||
* react-aria uses portals to render Popover in body
|
||||
* unless otherwise specified. We need it to be contained
|
||||
* by this component to both access css variables assigned
|
||||
* on the container as well as to not overflow it at any time.
|
||||
*/
|
||||
UNSTABLE_portalContainer={rootDiv}
|
||||
>
|
||||
<ListBox className={styles.listBox}>
|
||||
{items.map((item) => (
|
||||
<ListBoxItem
|
||||
aria-label={String(item)}
|
||||
className={styles.listBoxItem}
|
||||
id={item.value}
|
||||
key={item.label}
|
||||
>
|
||||
{item.label}
|
||||
</ListBoxItem>
|
||||
))}
|
||||
</ListBox>
|
||||
</Popover>
|
||||
</Body>
|
||||
</ReactAriaSelect>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -2,10 +2,6 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: var(--Base-Text-UI-Placeholder);
|
||||
}
|
||||
|
||||
.select {
|
||||
border: 1px solid var(--Base-Border-Normal);
|
||||
border-radius: var(--Corner-radius-Medium);
|
||||
@@ -27,7 +23,7 @@
|
||||
color: var(--Base-Text-UI-High-contrast);
|
||||
display: flex;
|
||||
gap: var(--Spacing-x-half);
|
||||
height: 56px;
|
||||
height: 60px;
|
||||
outline: none;
|
||||
padding: var(--Spacing-x-one-and-half) var(--Spacing-x2);
|
||||
text-align: left;
|
||||
@@ -69,4 +65,4 @@
|
||||
|
||||
.listBoxItem[data-selected="true"] {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
15
components/TempDesignSystem/Select/select.ts
Normal file
15
components/TempDesignSystem/Select/select.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import type { Key } from "react-aria-components"
|
||||
|
||||
export interface SelectProps
|
||||
extends Omit<React.SelectHTMLAttributes<HTMLSelectElement>, "onSelect"> {
|
||||
defaultSelectedKey?: Key
|
||||
items: { label: string; value: Key }[]
|
||||
label: string
|
||||
name: string
|
||||
onSelect: (key: Key) => void
|
||||
placeholder?: string
|
||||
value?: string | number
|
||||
}
|
||||
|
||||
export type SelectPortalContainer = HTMLDivElement | undefined
|
||||
export type SelectPortalContainerArgs = HTMLDivElement | null
|
||||
@@ -5,18 +5,22 @@
|
||||
}
|
||||
|
||||
.one {
|
||||
font-size: clamp(var(--typography-Script-1-Mobile-fontSize),
|
||||
1.3vw + 14px,
|
||||
var(--typography-Script-1-Desktop-fontSize));
|
||||
font-size: clamp(
|
||||
var(--typography-Script-1-Mobile-fontSize),
|
||||
1.3vw + 14px,
|
||||
var(--typography-Script-1-Desktop-fontSize)
|
||||
);
|
||||
font-weight: var(--typography-Script-1-fontWeight);
|
||||
letter-spacing: var(--typography-Script-1-letterSpacing);
|
||||
line-height: var(--typography-Script-1-lineHeight);
|
||||
}
|
||||
|
||||
.two {
|
||||
font-size: clamp(var(--typography-Script-2-Mobile-fontSize),
|
||||
0.6vw + 15px,
|
||||
var(--typography-Script-2-Desktop-fontSize));
|
||||
font-size: clamp(
|
||||
var(--typography-Script-2-Mobile-fontSize),
|
||||
0.6vw + 15px,
|
||||
var(--typography-Script-2-Desktop-fontSize)
|
||||
);
|
||||
font-weight: var(--typography-Script-2-fontWeight);
|
||||
letter-spacing: var(--typography-Script-2-letterSpacing);
|
||||
line-height: var(--typography-Script-2-lineHeight);
|
||||
@@ -31,7 +35,7 @@
|
||||
}
|
||||
|
||||
.black {
|
||||
color: #000;
|
||||
color: var(--Main-Grey-100);
|
||||
}
|
||||
|
||||
.burgundy {
|
||||
@@ -44,4 +48,4 @@
|
||||
|
||||
.plosa {
|
||||
color: var(--Theme-Primary-Light-On-Surface-Accent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,8 +43,7 @@
|
||||
}
|
||||
|
||||
.black {
|
||||
/* No black variable exist yet */
|
||||
color: #000;
|
||||
color: var(--Main-Grey-100);
|
||||
}
|
||||
|
||||
.burgundy {
|
||||
|
||||
@@ -26,8 +26,7 @@
|
||||
}
|
||||
|
||||
.black {
|
||||
/* No black variable exist yet */
|
||||
color: #000;
|
||||
color: var(--Main-Grey-100);
|
||||
}
|
||||
|
||||
.burgundy {
|
||||
|
||||
@@ -34,8 +34,7 @@
|
||||
}
|
||||
|
||||
.black {
|
||||
/* No black variable exist yet */
|
||||
color: #000;
|
||||
color: var(--Main-Grey-100);
|
||||
}
|
||||
|
||||
.burgundy {
|
||||
|
||||
@@ -28,6 +28,10 @@
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.black {
|
||||
color: var(--Main-Grey-100);
|
||||
}
|
||||
|
||||
.burgundy {
|
||||
color: var(--Scandic-Brand-Burgundy);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import styles from "./subtitle.module.css"
|
||||
const config = {
|
||||
variants: {
|
||||
color: {
|
||||
black: styles.black,
|
||||
burgundy: styles.burgundy,
|
||||
pale: styles.pale,
|
||||
},
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
}
|
||||
|
||||
.black {
|
||||
color: #000;
|
||||
color: var(--Main-Grey-100);
|
||||
}
|
||||
|
||||
.burgundy {
|
||||
@@ -96,6 +96,10 @@
|
||||
color: var(--Scandic-Brand-Pale-Peach);
|
||||
}
|
||||
|
||||
.peach80 {
|
||||
color: var(--Scandic-Peach-80);
|
||||
}
|
||||
|
||||
.red {
|
||||
color: var(--Scandic-Brand-Scandic-Red);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ const config = {
|
||||
black: styles.black,
|
||||
burgundy: styles.burgundy,
|
||||
pale: styles.pale,
|
||||
peach80: styles.peach80,
|
||||
red: styles.red,
|
||||
},
|
||||
textAlign: {
|
||||
|
||||
Reference in New Issue
Block a user