Merge master
This commit is contained in:
@@ -30,7 +30,6 @@ export default function Alert({
|
||||
if (!text && !heading) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<section className={classNames}>
|
||||
<div className={styles.content}>
|
||||
@@ -65,7 +64,7 @@ export default function Alert({
|
||||
) : null}
|
||||
</div>
|
||||
{link ? (
|
||||
<Link color="burgundy" href={link.url}>
|
||||
<Link color="burgundy" textDecoration="underline" href={link.url}>
|
||||
{link.title}
|
||||
</Link>
|
||||
) : null}
|
||||
|
||||
@@ -265,6 +265,10 @@ a.default {
|
||||
color: var(--Base-Button-Text-On-Fill-Normal);
|
||||
}
|
||||
|
||||
.baseTextInverted {
|
||||
color: var(--Base-Button-Primary-On-Fill-Normal);
|
||||
}
|
||||
|
||||
.baseText:active,
|
||||
.baseText:focus,
|
||||
.baseText:hover {
|
||||
|
||||
@@ -10,6 +10,7 @@ export const buttonVariants = cva(styles.btn, {
|
||||
secondary: styles.secondary,
|
||||
tertiary: styles.tertiary,
|
||||
text: styles.text,
|
||||
textInverted: styles.text,
|
||||
},
|
||||
size: {
|
||||
small: styles.small,
|
||||
@@ -140,5 +141,10 @@ export const buttonVariants = cva(styles.btn, {
|
||||
intent: "text",
|
||||
theme: "base",
|
||||
},
|
||||
{
|
||||
className: styles.baseTextInverted,
|
||||
intent: "textInverted",
|
||||
theme: "base",
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
min-width: 24px;
|
||||
background: var(--UI-Input-Controls-Surface-Normal);
|
||||
border: 1px solid var(--UI-Input-Controls-Border-Normal);
|
||||
border-radius: 4px;
|
||||
transition: all 200ms;
|
||||
|
||||
@@ -15,7 +15,6 @@ export default function Card({
|
||||
iconHeight = 32,
|
||||
iconWidth = 32,
|
||||
declined = false,
|
||||
defaultChecked,
|
||||
highlightSubtitle = false,
|
||||
id,
|
||||
list,
|
||||
@@ -58,7 +57,6 @@ export default function Card({
|
||||
<input
|
||||
{...register(name)}
|
||||
aria-hidden
|
||||
defaultChecked={defaultChecked}
|
||||
id={id || name}
|
||||
hidden
|
||||
type={type}
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
/* Leaving, will most likely get deleted */
|
||||
.datePicker {
|
||||
container-name: datePickerContainer;
|
||||
container-type: inline-size;
|
||||
}
|
||||
.container {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x2);
|
||||
@@ -11,6 +6,13 @@
|
||||
width: var(--width);
|
||||
}
|
||||
|
||||
@media (max-width: 350px) {
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.day {
|
||||
grid-area: day;
|
||||
}
|
||||
@@ -31,10 +33,3 @@
|
||||
.year.invalid > div > div {
|
||||
border-color: var(--Scandic-Red-60);
|
||||
}
|
||||
|
||||
@container datePickerContainer (max-width: 350px) {
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,21 +36,6 @@ export default function NewPassword({
|
||||
const intl = useIntl()
|
||||
const [isPasswordVisible, setIsPasswordVisible] = useState(false)
|
||||
|
||||
function getErrorMessage(key: PasswordValidatorKey) {
|
||||
switch (key) {
|
||||
case "length":
|
||||
return `10 ${intl.formatMessage({ id: "to" })} 40 ${intl.formatMessage({ id: "characters" })}`
|
||||
case "hasUppercase":
|
||||
return `1 ${intl.formatMessage({ id: "uppercase letter" })}`
|
||||
case "hasLowercase":
|
||||
return `1 ${intl.formatMessage({ id: "lowercase letter" })}`
|
||||
case "hasNumber":
|
||||
return `1 ${intl.formatMessage({ id: "number" })}`
|
||||
case "hasSpecialChar":
|
||||
return `1 ${intl.formatMessage({ id: "special character" })}`
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Controller
|
||||
disabled={disabled}
|
||||
@@ -59,6 +44,7 @@ export default function NewPassword({
|
||||
rules={registerOptions}
|
||||
render={({ field, fieldState, formState }) => {
|
||||
const errors = Object.values(formState.errors[name]?.types ?? []).flat()
|
||||
|
||||
return (
|
||||
<TextField
|
||||
aria-label={ariaLabel}
|
||||
@@ -100,20 +86,9 @@ export default function NewPassword({
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
{field.value ? (
|
||||
<div className={styles.errors}>
|
||||
{Object.entries(passwordValidators).map(
|
||||
([key, { message }]) => (
|
||||
<Caption asChild color="black" key={key}>
|
||||
<Text className={styles.helpText} slot="description">
|
||||
<Icon errorMessage={message} errors={errors} />
|
||||
{getErrorMessage(key as PasswordValidatorKey)}
|
||||
</Text>
|
||||
</Caption>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<PasswordValidation value={field.value} errors={errors} />
|
||||
|
||||
{!field.value && fieldState.error ? (
|
||||
<Caption className={styles.error} fontOnly>
|
||||
<InfoCircleIcon color="red" />
|
||||
@@ -134,3 +109,43 @@ function Icon({ errorMessage, errors }: IconProps) {
|
||||
<CheckIcon color="green" height={20} width={20} />
|
||||
)
|
||||
}
|
||||
|
||||
function PasswordValidation({
|
||||
value,
|
||||
errors,
|
||||
}: {
|
||||
value: string
|
||||
errors: string[]
|
||||
}) {
|
||||
const intl = useIntl()
|
||||
|
||||
if (!value) return null
|
||||
|
||||
function getErrorMessage(key: PasswordValidatorKey) {
|
||||
switch (key) {
|
||||
case "length":
|
||||
return `10 ${intl.formatMessage({ id: "to" })} 40 ${intl.formatMessage({ id: "characters" })}`
|
||||
case "hasUppercase":
|
||||
return `1 ${intl.formatMessage({ id: "uppercase letter" })}`
|
||||
case "hasLowercase":
|
||||
return `1 ${intl.formatMessage({ id: "lowercase letter" })}`
|
||||
case "hasNumber":
|
||||
return `1 ${intl.formatMessage({ id: "number" })}`
|
||||
case "hasSpecialChar":
|
||||
return `1 ${intl.formatMessage({ id: "special character" })}`
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.errors}>
|
||||
{Object.entries(passwordValidators).map(([key, { message }]) => (
|
||||
<Caption asChild color="black" key={key}>
|
||||
<Text className={styles.helpText} slot="description">
|
||||
<Icon errorMessage={message} errors={errors} />
|
||||
{getErrorMessage(key as PasswordValidatorKey)}
|
||||
</Text>
|
||||
</Caption>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -78,69 +78,67 @@ export default function Phone({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`${styles.wrapper} ${className}`}>
|
||||
<div className={styles.phone}>
|
||||
<CountrySelector
|
||||
disabled={readOnly}
|
||||
dropdownArrowClassName={styles.arrow}
|
||||
flagClassName={styles.flag}
|
||||
onSelect={handleSelectCountry}
|
||||
preferredCountries={["de", "dk", "fi", "no", "se", "gb"]}
|
||||
selectedCountry={country.iso2}
|
||||
renderButtonWrapper={(props) => (
|
||||
<button
|
||||
{...props.rootProps}
|
||||
className={styles.select}
|
||||
tabIndex={0}
|
||||
type="button"
|
||||
data-testid="country-selector"
|
||||
>
|
||||
<Label required={!!registerOptions.required} size="small">
|
||||
{intl.formatMessage({ id: "Country code" })}
|
||||
</Label>
|
||||
<span 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 className={`${styles.phone} ${className}`}>
|
||||
<CountrySelector
|
||||
disabled={readOnly}
|
||||
dropdownArrowClassName={styles.arrow}
|
||||
flagClassName={styles.flag}
|
||||
onSelect={handleSelectCountry}
|
||||
preferredCountries={["de", "dk", "fi", "no", "se", "gb"]}
|
||||
selectedCountry={country.iso2}
|
||||
renderButtonWrapper={(props) => (
|
||||
<button
|
||||
{...props.rootProps}
|
||||
className={styles.select}
|
||||
tabIndex={0}
|
||||
type="button"
|
||||
data-testid="country-selector"
|
||||
>
|
||||
<Label required={!!registerOptions.required} size="small">
|
||||
{intl.formatMessage({ id: "Country code" })}
|
||||
</Label>
|
||||
<span className={styles.selectContainer}>
|
||||
{props.children}
|
||||
<Body asChild fontOnly>
|
||||
<DialCodePreview
|
||||
className={styles.dialCode}
|
||||
dialCode={country.dialCode}
|
||||
prefix="+"
|
||||
/>
|
||||
</span>
|
||||
</button>
|
||||
)}
|
||||
/>
|
||||
<TextField
|
||||
aria-label={ariaLabel}
|
||||
defaultValue={field.value}
|
||||
isDisabled={disabled ?? field.disabled}
|
||||
isInvalid={fieldState.invalid}
|
||||
isRequired={!!registerOptions?.required}
|
||||
isReadOnly={readOnly}
|
||||
name={field.name}
|
||||
</Body>
|
||||
<ChevronDownIcon
|
||||
className={styles.chevron}
|
||||
color="grey80"
|
||||
height={18}
|
||||
width={18}
|
||||
/>
|
||||
</span>
|
||||
</button>
|
||||
)}
|
||||
/>
|
||||
<TextField
|
||||
aria-label={ariaLabel}
|
||||
defaultValue={field.value}
|
||||
isDisabled={disabled ?? field.disabled}
|
||||
isInvalid={fieldState.invalid}
|
||||
isRequired={!!registerOptions?.required}
|
||||
isReadOnly={readOnly}
|
||||
name={field.name}
|
||||
type="tel"
|
||||
>
|
||||
<AriaInputWithLabel
|
||||
{...field}
|
||||
id={field.name}
|
||||
label={label}
|
||||
onChange={handleChange}
|
||||
placeholder={placeholder}
|
||||
readOnly={readOnly}
|
||||
required={!!registerOptions.required}
|
||||
type="tel"
|
||||
>
|
||||
<AriaInputWithLabel
|
||||
{...field}
|
||||
id={field.name}
|
||||
label={label}
|
||||
onChange={handleChange}
|
||||
placeholder={placeholder}
|
||||
readOnly={readOnly}
|
||||
required={!!registerOptions.required}
|
||||
type="tel"
|
||||
value={inputValue}
|
||||
/>
|
||||
<ErrorMessage errors={formState.errors} name={field.name} />
|
||||
</TextField>
|
||||
</div>
|
||||
value={inputValue}
|
||||
/>
|
||||
<ErrorMessage errors={formState.errors} name={field.name} />
|
||||
</TextField>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
.wrapper {
|
||||
container-name: phoneContainer;
|
||||
container-type: inline-size;
|
||||
}
|
||||
.phone {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--Spacing-x2);
|
||||
grid-template-columns: minmax(124px, 164px) 1fr;
|
||||
|
||||
--react-international-phone-background-color: var(--Main-Grey-White);
|
||||
--react-international-phone-border-color: var(--Scandic-Beige-40);
|
||||
@@ -28,6 +24,12 @@
|
||||
);
|
||||
}
|
||||
|
||||
@media (min-width: 385px) {
|
||||
.phone {
|
||||
grid-template-columns: minmax(124px, 164px) 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.phone:has(.input:active, .input:focus) {
|
||||
--react-international-phone-border-color: var(--Scandic-Blue-90);
|
||||
}
|
||||
@@ -104,10 +106,3 @@
|
||||
justify-self: flex-start;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@container phoneContainer (max-width: 350px) {
|
||||
.phone {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
box-shadow: 0px 0px 14px 6px rgba(0, 0, 0, 0.1);
|
||||
padding: var(--Spacing-x2);
|
||||
max-width: calc(360px + var(--Spacing-x2) * 2);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.root section:focus-visible {
|
||||
|
||||
@@ -38,9 +38,10 @@ export default function Select({
|
||||
maxHeight,
|
||||
showRadioButton = false,
|
||||
discreet = false,
|
||||
isNestedInModal = false,
|
||||
}: SelectProps) {
|
||||
const [rootDiv, setRootDiv] = useState<SelectPortalContainer>(undefined)
|
||||
const setOverflowVisible = useSetOverflowVisibleOnRA()
|
||||
const setOverflowVisible = useSetOverflowVisibleOnRA(isNestedInModal)
|
||||
|
||||
function setRef(node: SelectPortalContainerArgs) {
|
||||
if (node) {
|
||||
|
||||
@@ -12,6 +12,7 @@ export interface SelectProps
|
||||
maxHeight?: number
|
||||
showRadioButton?: boolean
|
||||
discreet?: boolean
|
||||
isNestedInModal?: boolean
|
||||
}
|
||||
|
||||
export type SelectPortalContainer = HTMLDivElement | undefined
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
|
||||
.dialog {
|
||||
height: 100%;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.sidePeek {
|
||||
|
||||
@@ -16,7 +16,7 @@ import { toastVariants } from "./variants"
|
||||
import styles from "./toasts.module.css"
|
||||
|
||||
export function ToastHandler() {
|
||||
return <Toaster position="bottom-right" />
|
||||
return <Toaster position="bottom-right" duration={5000} />
|
||||
}
|
||||
|
||||
function getIcon(variant: ToastsProps["variant"]) {
|
||||
|
||||
@@ -6,7 +6,12 @@
|
||||
background: var(--Base-Surface-Primary-light-Normal);
|
||||
box-shadow: 0px 0px 8px 2px rgba(0, 0, 0, 0.08);
|
||||
align-items: center;
|
||||
width: var(--width);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.toast {
|
||||
width: var(--width);
|
||||
}
|
||||
}
|
||||
|
||||
.toast .message {
|
||||
|
||||
Reference in New Issue
Block a user