Merge branch 'master' into feature/tracking

This commit is contained in:
Linus Flood
2024-12-03 07:48:59 +01:00
159 changed files with 2609 additions and 1227 deletions
@@ -5,6 +5,8 @@ import { useRef } from "react"
import { ChevronDownIcon } from "@/components/Icons"
import { getIconByIconName } from "@/components/Icons/get-icon-by-icon-name"
import Body from "../../Text/Body"
import Subtitle from "../../Text/Subtitle"
import { accordionItemVariants } from "./variants"
import styles from "./accordionItem.module.css"
@@ -49,7 +51,23 @@ export default function AccordionItem({
<details ref={detailsRef} onToggle={toggleAccordion}>
<summary className={styles.summary}>
{IconComp && <IconComp className={styles.icon} color="burgundy" />}
<span className={styles.title}>{title}</span>
{variant === "card" ? (
<Body
textTransform="bold"
color="baseTextHighContrast"
className={styles.title}
>
{title}
</Body>
) : (
<Subtitle
className={styles.title}
type="two"
color="baseTextHighContrast"
>
{title}
</Subtitle>
)}
<ChevronDownIcon
className={styles.chevron}
color="burgundy"
@@ -20,7 +20,7 @@
font-weight: 500;
font-size: var(--typography-Caption-Bold-fontSize);
line-height: var(--typography-Caption-Bold-lineHeight);
letter-spacing: 0.6%;
letter-spacing: 0.084px;
text-decoration: none;
}
@@ -13,7 +13,7 @@
font-size: var(--typography-Body-Bold-fontSize);
font-weight: 500;
line-height: var(--typography-Body-Bold-lineHeight);
letter-spacing: 0.6%;
letter-spacing: 0.084px;
text-decoration: none;
}
@@ -13,7 +13,7 @@ export const dividerVariants = cva(styles.divider, {
primaryLightSubtle: styles.primaryLightSubtle,
subtle: styles.subtle,
white: styles.white,
baseSurfaceSutbleHover: styles.baseSurfaceSubtleHover,
baseSurfaceSubtleHover: styles.baseSurfaceSubtleHover,
},
opacity: {
100: styles.opacity100,
+20 -12
View File
@@ -76,19 +76,17 @@ export default function DateSelect({ name, registerOptions = {} }: DateProps) {
}
}
if (year && month && day) {
const newDate = dt()
.year(Number(year))
.month(Number(month) - 1)
.date(Number(day))
const newDate = dt()
.year(Number(year))
.month(Number(month) - 1)
.date(Number(day))
if (newDate.isValid()) {
setValue(name, newDate.format("YYYY-MM-DD"), {
shouldDirty: true,
shouldTouch: true,
shouldValidate: true,
})
}
if (newDate.isValid()) {
setValue(name, newDate.format("YYYY-MM-DD"), {
shouldDirty: true,
shouldTouch: true,
shouldValidate: true,
})
}
}, [year, month, day, setValue, name, formState.isSubmitting])
@@ -106,6 +104,16 @@ export default function DateSelect({ name, registerOptions = {} }: DateProps) {
console.warn("Known error for parse date in DateSelect: ", error)
}
useEffect(() => {
if (formState.isSubmitting) return
if (!(day && month && year) && dateValue) {
setValue(DateName.day, Number(dateValue.day))
setValue(DateName.month, Number(dateValue.month))
setValue(DateName.year, Number(dateValue.year))
}
}, [setValue, formState.isSubmitting, dateValue, day, month, year])
return (
<DatePicker
aria-label={intl.formatMessage({ id: "Select date of birth" })}
@@ -12,17 +12,23 @@ import {
} from "react-international-phone"
import { useIntl } from "react-intl"
import { Lang } from "@/constants/languages"
import { ChevronDownIcon } from "@/components/Icons"
import ErrorMessage from "@/components/TempDesignSystem/Form/ErrorMessage"
import AriaInputWithLabel from "@/components/TempDesignSystem/Form/Input/AriaInputWithLabel"
import Label from "@/components/TempDesignSystem/Form/Label"
import Body from "@/components/TempDesignSystem/Text/Body"
import useLang from "@/hooks/useLang"
import styles from "./phone.module.css"
import type { ChangeEvent } from "react"
import type { PhoneProps } from "./phone"
import type {
LowerCaseCountryCode,
PhoneProps,
} from "@/types/components/form/phone"
export default function Phone({
ariaLabel = "Phone number input",
@@ -37,6 +43,7 @@ export default function Phone({
},
}: PhoneProps) {
const intl = useIntl()
const lang = useLang()
const { control, setValue, trigger } = useFormContext()
const phone = useWatch({ name })
@@ -47,13 +54,17 @@ export default function Phone({
rules: registerOptions,
})
const defaultPhoneNumber = formState.defaultValues?.phoneNumber
// If defaultPhoneNumber exists and is valid, parse it to get the country code,
// otherwise set the default country from the lang.
const defaultCountry = isValidPhoneNumber(defaultPhoneNumber)
? parsePhoneNumber(defaultPhoneNumber).country?.toLowerCase()
: getDefaultCountryFromLang(lang)
const { country, handlePhoneValueChange, inputValue, setCountry } =
usePhoneInput({
defaultCountry: isValidPhoneNumber(formState.defaultValues?.phoneNumber)
? parsePhoneNumber(
formState.defaultValues?.phoneNumber
).country?.toLowerCase()
: "se",
defaultCountry,
disableDialCodeAndPrefix: true,
forceDialCode: true,
value: phone,
@@ -142,3 +153,15 @@ export default function Phone({
</div>
)
}
function getDefaultCountryFromLang(lang: Lang): LowerCaseCountryCode {
const countryMap: Record<Lang, LowerCaseCountryCode> = {
sv: "se",
da: "dk",
fi: "fi",
no: "no",
de: "de",
en: "se", // Default to Sweden for English
}
return countryMap[lang] || "se"
}
@@ -1,12 +0,0 @@
import type { RegisterOptions } from "react-hook-form"
export type PhoneProps = {
ariaLabel?: string
className?: string
disabled?: boolean
label: string
name?: string
placeholder?: string
readOnly?: boolean
registerOptions?: RegisterOptions
}
@@ -16,7 +16,8 @@
.breadcrumb {
font-family: var(--typography-Footnote-Bold-fontFamily);
font-size: var(--typography-Footnote-Bold-fontSize);
font-weight: 500; /* var(--typography-Footnote-Bold-fontWeight); */
font-weight: 500;
/* var(--typography-Footnote-Bold-fontWeight); */
letter-spacing: var(--typography-Footnote-Bold-letterSpacing);
line-height: var(--typography-Footnote-Bold-lineHeight);
}
@@ -24,7 +25,8 @@
.link.breadcrumb {
font-family: var(--typography-Footnote-Bold-fontFamily);
font-size: var(--typography-Footnote-Bold-fontSize);
font-weight: 500; /* var(--typography-Footnote-Bold-fontWeight); */
font-weight: 500;
/* var(--typography-Footnote-Bold-fontWeight); */
letter-spacing: var(--typography-Footnote-Bold-letterSpacing);
line-height: var(--typography-Footnote-Bold-lineHeight);
}
@@ -159,12 +161,15 @@
color: var(--Scandic-Peach-50);
}
.peach80 {
.peach80,
.baseTextMediumContrast {
color: var(--Base-Text-Medium-contrast);
}
.peach80:hover,
.peach80:active {
.peach80:active,
.baseTextMediumContrast:hover,
.baseTextMediumContrast:active {
color: var(--Base-Text-High-contrast);
}
@@ -235,6 +240,7 @@
letter-spacing: var(--typography-Caption-Bold-letterSpacing);
line-height: var(--typography-Caption-Bold-lineHeight);
}
.bold {
font-family: var(--typography-Body-Bold-fontFamily);
font-size: var(--typography-Body-Bold-fontSize);
@@ -9,6 +9,7 @@ export const linkVariants = cva(styles.link, {
},
color: {
baseButtonTextOnFillNormal: styles.baseButtonTextOnFillNormal,
baseTextMediumContrast: styles.baseTextMediumContrast,
black: styles.black,
burgundy: styles.burgundy,
none: "",
@@ -63,7 +63,7 @@
color: var(--Scandic-Brand-Pale-Peach);
}
.baseTextMediumContrast {
.baseTextHighContrast {
color: var(--Base-Text-High-contrast);
}
@@ -86,3 +86,7 @@
.baseTextDisabled {
color: var(--Base-Text-Disabled);
}
.mainGrey60 {
color: var(--Main-Grey-60);
}
@@ -9,11 +9,12 @@ const config = {
burgundy: styles.burgundy,
baseTextDisabled: styles.baseTextDisabled,
pale: styles.pale,
baseTextMediumContrast: styles.baseTextMediumContrast,
baseTextHighContrast: styles.baseTextHighContrast,
uiTextHighContrast: styles.uiTextHighContrast,
uiTextMediumContrast: styles.uiTextMediumContrast,
uiTextPlaceholder: styles.uiTextPlaceholder,
red: styles.red,
mainGrey60: styles.mainGrey60,
},
textAlign: {
center: styles.center,
+11 -5
View File
@@ -32,7 +32,7 @@ function getIcon(variant: ToastsProps["variant"]) {
}
}
export function Toast({ message, onClose, variant }: ToastsProps) {
export function Toast({ children, message, onClose, variant }: ToastsProps) {
const className = toastVariants({ variant })
const Icon = getIcon(variant)
return (
@@ -40,10 +40,16 @@ export function Toast({ message, onClose, variant }: ToastsProps) {
<div className={styles.iconContainer}>
{Icon && <Icon color="white" height={24} width={24} />}
</div>
<Body className={styles.message}>{message}</Body>
<Button onClick={onClose} variant="icon" intent="text">
<CloseLargeIcon />
</Button>
{message ? (
<Body className={styles.message}>{message}</Body>
) : (
<div className={styles.content}>{children}</div>
)}
{onClose ? (
<Button onClick={onClose} variant="icon" intent="text">
<CloseLargeIcon />
</Button>
) : null}
</div>
)
}
@@ -8,6 +8,11 @@
align-items: center;
}
.content {
padding: var(--Spacing-x-one-and-half) var(--Spacing-x3)
var(--Spacing-x-one-and-half) var(--Spacing-x2);
}
@media screen and (min-width: 768px) {
.toast {
width: var(--width);
+13 -6
View File
@@ -2,9 +2,16 @@ import { toastVariants } from "./variants"
import type { VariantProps } from "class-variance-authority"
export interface ToastsProps
extends Omit<React.AnchorHTMLAttributes<HTMLDivElement>, "color">,
VariantProps<typeof toastVariants> {
message: React.ReactNode
onClose: () => void
}
export type ToastsProps = Omit<React.HTMLAttributes<HTMLDivElement>, "color"> &
VariantProps<typeof toastVariants> & {
onClose?: () => void
} & (
| {
children: React.ReactNode
message?: never
}
| {
children?: never
message: React.ReactNode
}
)
+13 -3
View File
@@ -14,12 +14,20 @@ export function Tooltip<P extends TooltipPosition>({
position,
arrow,
children,
isTouchable = false,
}: PropsWithChildren<TooltipProps<P>>) {
const className = tooltipVariants({ position, arrow })
const [isActive, setIsActive] = useState(false)
function handleToggle() {
setIsActive(!isActive)
setIsActive((prevState) => !prevState)
}
function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault()
handleToggle()
}
}
return (
@@ -27,8 +35,10 @@ export function Tooltip<P extends TooltipPosition>({
className={styles.tooltipContainer}
role="tooltip"
aria-label={text}
onClick={handleToggle}
onTouchStart={handleToggle}
tabIndex={0}
onClick={isTouchable ? undefined : handleToggle}
onTouchStart={isTouchable ? handleToggle : undefined}
onKeyDown={handleKeyDown}
data-active={isActive}
>
<div className={className}>