Merge branch 'master' into feature/tracking
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
.backToTopButton {
|
||||
border-radius: var(--Corner-radius-Rounded);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
z-index: 1000;
|
||||
background-color: var(--Base-Surface-Primary-light-Normal);
|
||||
color: var(--Base-Button-Secondary-On-Fill-Normal);
|
||||
border: 2px solid var(--Base-Button-Secondary-On-Fill-Normal);
|
||||
gap: var(--Spacing-x-half);
|
||||
padding: var(--Spacing-x1);
|
||||
text-align: center;
|
||||
transition:
|
||||
background-color 300ms ease,
|
||||
color 300ms ease;
|
||||
font-family: var(--typography-Body-Bold-fontFamily);
|
||||
font-weight: 500;
|
||||
font-size: var(--typography-Caption-Bold-fontSize);
|
||||
line-height: var(--typography-Caption-Bold-lineHeight);
|
||||
letter-spacing: 0.6%;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.backToTopButtonText {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.backToTopButtonText {
|
||||
display: initial;
|
||||
}
|
||||
.backToTopButton:hover {
|
||||
background-color: var(--Base-Button-Tertiary-Fill-Normal);
|
||||
color: var(--Base-Button-Tertiary-On-Fill-Hover);
|
||||
}
|
||||
.backToTopButton:hover > svg * {
|
||||
fill: var(--Base-Button-Tertiary-On-Fill-Hover);
|
||||
}
|
||||
.backToTopButton {
|
||||
padding: calc(var(--Spacing-x1) + 2px) var(--Spacing-x2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
"use client"
|
||||
|
||||
import { Button as ButtonRAC } from "react-aria-components"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { ArrowUpIcon } from "@/components/Icons"
|
||||
|
||||
import styles from "./backToTopButton.module.css"
|
||||
|
||||
export function BackToTopButton({ onClick }: { onClick: () => void }) {
|
||||
const intl = useIntl()
|
||||
return (
|
||||
<ButtonRAC className={styles.backToTopButton} onPress={onClick}>
|
||||
<ArrowUpIcon color="burgundy" />
|
||||
<span className={styles.backToTopButtonText}>
|
||||
{intl.formatMessage({ id: "Back to top" })}
|
||||
</span>
|
||||
</ButtonRAC>
|
||||
)
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: var(--text-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.container[data-selected] .checkbox {
|
||||
|
||||
@@ -12,6 +12,7 @@ import styles from "./checkbox.module.css"
|
||||
import { CheckboxProps } from "@/types/components/checkbox"
|
||||
|
||||
export default function Checkbox({
|
||||
className,
|
||||
name,
|
||||
children,
|
||||
registerOptions,
|
||||
@@ -25,16 +26,17 @@ export default function Checkbox({
|
||||
|
||||
return (
|
||||
<AriaCheckbox
|
||||
className={styles.container}
|
||||
className={`${styles.container} ${className}`}
|
||||
isSelected={field.value}
|
||||
onChange={field.onChange}
|
||||
data-testid={name}
|
||||
isDisabled={registerOptions?.disabled}
|
||||
excludeFromTabOrder
|
||||
>
|
||||
{({ isSelected }) => (
|
||||
<>
|
||||
<span className={styles.checkboxContainer}>
|
||||
<span className={styles.checkbox}>
|
||||
<span className={styles.checkbox} tabIndex={0}>
|
||||
{isSelected && <CheckIcon color="white" />}
|
||||
</span>
|
||||
{children}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import Card from "./_Card"
|
||||
|
||||
import type { CheckboxProps } from "./_Card/card"
|
||||
|
||||
export default function CheckboxCard(props: CheckboxProps) {
|
||||
return <Card {...props} type="checkbox" />
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
.label {
|
||||
align-self: flex-start;
|
||||
background-color: var(--Base-Surface-Primary-light-Normal);
|
||||
border: 1px solid var(--Base-Border-Subtle);
|
||||
border-radius: var(--Corner-radius-Large);
|
||||
|
||||
@@ -15,6 +15,7 @@ export default function Card({
|
||||
iconHeight = 32,
|
||||
iconWidth = 32,
|
||||
declined = false,
|
||||
defaultChecked,
|
||||
highlightSubtitle = false,
|
||||
id,
|
||||
list,
|
||||
@@ -45,6 +46,7 @@ export default function Card({
|
||||
<input
|
||||
{...register(name)}
|
||||
aria-hidden
|
||||
defaultChecked={defaultChecked}
|
||||
id={id || name}
|
||||
hidden
|
||||
type={type}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
/* Leaving, will most likely get deleted */
|
||||
.datePicker {
|
||||
container-name: datePickerContainer;
|
||||
container-type: inline-size;
|
||||
}
|
||||
.container {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x2);
|
||||
@@ -27,3 +31,10 @@
|
||||
.year.invalid > div > div {
|
||||
border-color: var(--Scandic-Red-60);
|
||||
}
|
||||
|
||||
@container datePickerContainer (max-width: 350px) {
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +115,7 @@ export default function DateSelect({ name, registerOptions = {} }: DateProps) {
|
||||
ref={field.ref}
|
||||
value={dateValue}
|
||||
data-testid={name}
|
||||
className={styles.datePicker}
|
||||
>
|
||||
<Group>
|
||||
<DateInput className={styles.container}>
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--Spacing-x-half);
|
||||
padding: var(--Spacing-x1) var(--Spacing-x-one-and-half);
|
||||
padding: calc(var(--Spacing-x1) - 2px) var(--Spacing-x-one-and-half);
|
||||
border: 1px solid var(--Base-Border-Subtle);
|
||||
border-radius: var(--Corner-radius-Small);
|
||||
background-color: var(--Base-Surface-Secondary-light-Normal);
|
||||
cursor: pointer;
|
||||
height: 32px;
|
||||
background-color: var(--Base-Surface-Secondary-light-Normal);
|
||||
}
|
||||
|
||||
.label[data-selected="true"],
|
||||
@@ -21,8 +23,9 @@
|
||||
}
|
||||
|
||||
.label[data-disabled="true"] {
|
||||
background-color: var(--Base-Button-Primary-Fill-Disabled);
|
||||
border-color: var(--Base-Button-Primary-Fill-Disabled);
|
||||
background-color: var(--UI-Input-Controls-Surface-Disabled);
|
||||
border-color: var(--UI-Input-Controls-Border-Disabled);
|
||||
color: var(--Base-Text-Disabled);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
|
||||
@@ -78,67 +78,69 @@ export default function Phone({
|
||||
}
|
||||
|
||||
return (
|
||||
<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="+"
|
||||
<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}
|
||||
/>
|
||||
</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"
|
||||
value={inputValue}
|
||||
</span>
|
||||
</button>
|
||||
)}
|
||||
/>
|
||||
<ErrorMessage errors={formState.errors} name={field.name} />
|
||||
</TextField>
|
||||
<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"
|
||||
value={inputValue}
|
||||
/>
|
||||
<ErrorMessage errors={formState.errors} name={field.name} />
|
||||
</TextField>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
.wrapper {
|
||||
container-name: phoneContainer;
|
||||
container-type: inline-size;
|
||||
}
|
||||
.phone {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x2);
|
||||
@@ -100,3 +104,10 @@
|
||||
justify-self: flex-start;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@container phoneContainer (max-width: 350px) {
|
||||
.phone {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
.breadcrumb {
|
||||
font-family: var(--typography-Footnote-Bold-fontFamily);
|
||||
font-size: var(--typography-Footnote-Bold-fontSize);
|
||||
font-weight: 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 +24,7 @@
|
||||
.link.breadcrumb {
|
||||
font-family: var(--typography-Footnote-Bold-fontFamily);
|
||||
font-size: var(--typography-Footnote-Bold-fontSize);
|
||||
font-weight: 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);
|
||||
}
|
||||
@@ -128,6 +128,15 @@
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.uiTextPlaceholder {
|
||||
color: var(--Base-Text-Placeholder);
|
||||
}
|
||||
|
||||
.uiTextPlaceholder:hover,
|
||||
.uiTextPlaceholder:active {
|
||||
color: var(--Base-Text-Medium-contrast);
|
||||
}
|
||||
|
||||
.burgundy {
|
||||
color: var(--Base-Text-High-contrast);
|
||||
}
|
||||
@@ -211,6 +220,14 @@
|
||||
line-height: var(--typography-Caption-Regular-lineHeight);
|
||||
}
|
||||
|
||||
.tiny {
|
||||
font-family: var(--typography-Footnote-Regular-fontFamily);
|
||||
font-size: var(--typography-Footnote-Regular-fontSize);
|
||||
font-weight: var(--typography-Footnote-Regular-fontWeight);
|
||||
letter-spacing: var(--typography-Footnote-Regular-letterSpacing);
|
||||
line-height: var(--typography-Footnote-Regular-lineHeight);
|
||||
}
|
||||
|
||||
.activeSmall {
|
||||
font-family: var(--typography-Caption-Bold-fontFamily);
|
||||
font-size: var(--typography-Caption-Bold-fontSize);
|
||||
|
||||
@@ -17,10 +17,12 @@ export const linkVariants = cva(styles.link, {
|
||||
peach80: styles.peach80,
|
||||
white: styles.white,
|
||||
red: styles.red,
|
||||
uiTextPlaceholder: styles.uiTextPlaceholder,
|
||||
},
|
||||
size: {
|
||||
small: styles.small,
|
||||
regular: styles.regular,
|
||||
tiny: styles.tiny,
|
||||
},
|
||||
textDecoration: {
|
||||
none: styles.noDecoration,
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
.arrow {
|
||||
transform-origin: center;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
[data-placement="left"] .arrow,
|
||||
[data-placement="left top"] .arrow,
|
||||
[data-placement="left bottom"] .arrow {
|
||||
transform: rotate(270deg) translateY(-6px);
|
||||
}
|
||||
|
||||
[data-placement="right"] .arrow,
|
||||
[data-placement="right top"] .arrow,
|
||||
[data-placement="right bottom"] .arrow {
|
||||
transform: rotate(90deg) translateY(-6px);
|
||||
}
|
||||
|
||||
[data-placement="bottom"] .arrow,
|
||||
[data-placement="bottom left"] .arrow,
|
||||
[data-placement="bottom right"] .arrow {
|
||||
transform: rotate(180deg) translateY(-2px);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import styles from "./arrow.module.css"
|
||||
|
||||
export function Arrow() {
|
||||
return (
|
||||
<div className={styles.arrow}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="27"
|
||||
height="13"
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
fill="#fff"
|
||||
d="M13.093 12.193.9 0h25.8L14.508 12.193a1 1 0 0 1-1.415 0Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogTrigger,
|
||||
OverlayArrow,
|
||||
Popover as RAPopover,
|
||||
} from "react-aria-components"
|
||||
|
||||
import { CloseLargeIcon } from "@/components/Icons"
|
||||
import useSetOverFlowVisibleOnRA from "@/hooks/useSetOverflowVisibleOnRA"
|
||||
|
||||
import { Arrow } from "./Arrow"
|
||||
import { PopoverProps } from "./popover"
|
||||
|
||||
import styles from "./popover.module.css"
|
||||
|
||||
export default function Popover({
|
||||
triggerContent,
|
||||
children,
|
||||
...props
|
||||
}: PopoverProps) {
|
||||
const setOverflowVisible = useSetOverFlowVisibleOnRA()
|
||||
|
||||
return (
|
||||
<DialogTrigger onOpenChange={setOverflowVisible}>
|
||||
<Button className={styles.trigger}>{triggerContent}</Button>
|
||||
|
||||
<RAPopover
|
||||
{...props}
|
||||
offset={16}
|
||||
crossOffset={-24}
|
||||
className={styles.root}
|
||||
>
|
||||
<OverlayArrow>
|
||||
<Arrow />
|
||||
</OverlayArrow>
|
||||
<Dialog>
|
||||
{({ close }) => (
|
||||
<>
|
||||
<Button className={styles.closeButton} onPress={close}>
|
||||
<CloseLargeIcon height={20} width={20} />
|
||||
</Button>
|
||||
{children}
|
||||
</>
|
||||
)}
|
||||
</Dialog>
|
||||
</RAPopover>
|
||||
</DialogTrigger>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
.root {
|
||||
background-color: var(--Base-Surface-Primary-light-Normal);
|
||||
border-radius: var(--Corner-radius-Medium);
|
||||
box-shadow: 0px 0px 14px 6px rgba(0, 0, 0, 0.1);
|
||||
padding: var(--Spacing-x2);
|
||||
max-width: calc(360px + var(--Spacing-x2) * 2);
|
||||
}
|
||||
|
||||
.root section:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.trigger {
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
.closeButton {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import type { PopoverProps as RAPopoverProps } from "react-aria-components"
|
||||
|
||||
export interface PopoverProps extends Omit<RAPopoverProps, "children"> {
|
||||
triggerContent: React.ReactNode
|
||||
children: React.ReactNode
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
|
||||
import Label from "@/components/TempDesignSystem/Form/Label"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import useSetOverflowVisibleOnRA from "@/hooks/useSetOverflowVisibleOnRA"
|
||||
|
||||
import SelectChevron from "../Form/SelectChevron"
|
||||
|
||||
@@ -39,6 +40,7 @@ export default function Select({
|
||||
discreet = false,
|
||||
}: SelectProps) {
|
||||
const [rootDiv, setRootDiv] = useState<SelectPortalContainer>(undefined)
|
||||
const setOverflowVisible = useSetOverflowVisibleOnRA()
|
||||
|
||||
function setRef(node: SelectPortalContainerArgs) {
|
||||
if (node) {
|
||||
@@ -60,6 +62,7 @@ export default function Select({
|
||||
onSelectionChange={handleOnSelect}
|
||||
placeholder={placeholder}
|
||||
selectedKey={value as Key}
|
||||
onOpenChange={setOverflowVisible}
|
||||
>
|
||||
<Body asChild fontOnly>
|
||||
<Button className={styles.input} data-testid={name}>
|
||||
|
||||
@@ -28,6 +28,7 @@ export function Tooltip<P extends TooltipPosition>({
|
||||
role="tooltip"
|
||||
aria-label={text}
|
||||
onClick={handleToggle}
|
||||
onTouchStart={handleToggle}
|
||||
data-active={isActive}
|
||||
>
|
||||
<div className={className}>
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
transition: opacity 0.3s;
|
||||
max-width: 200px;
|
||||
min-width: 150px;
|
||||
height: fit-content;
|
||||
}
|
||||
|
||||
.tooltipContainer:hover .tooltip {
|
||||
|
||||
Reference in New Issue
Block a user