Merged in fix/3697-prettier-configs (pull request #3396)

fix(SW-3691): Setup one prettier config for whole repo

* Setup prettierrc in root and remove other configs


Approved-by: Joakim Jäderberg
Approved-by: Linus Flood
This commit is contained in:
Rasmus Langvad
2026-01-07 12:45:50 +00:00
parent 932413412b
commit d0546926a9
500 changed files with 18367 additions and 18419 deletions

View File

@@ -1,18 +1,18 @@
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
import type { Meta, StoryObj } from "@storybook/nextjs-vite"
import Accordion from './index'
import AccordionItem from './AccordionItem/index'
import { MaterialIcon } from '../Icons/MaterialIcon'
import { IconName } from '../Icons/iconName'
import { Typography } from '../Typography'
import Accordion from "./index"
import AccordionItem from "./AccordionItem/index"
import { MaterialIcon } from "../Icons/MaterialIcon"
import { IconName } from "../Icons/iconName"
import { Typography } from "../Typography"
const meta: Meta<typeof Accordion> = {
title: 'Core Components/Accordion',
title: "Core Components/Accordion",
component: Accordion,
argTypes: {
type: {
control: 'select',
options: ['card', 'sidepeek', 'inline'],
control: "select",
options: ["card", "sidepeek", "inline"],
},
},
}
@@ -23,7 +23,7 @@ type Story = StoryObj<typeof Accordion>
export const Default: Story = {
args: {
type: 'card',
type: "card",
},
render: (args) => (
<Accordion {...args}>
@@ -60,7 +60,7 @@ export const Default: Story = {
export const WithIcons: Story = {
args: {
type: 'card',
type: "card",
},
render: (args) => (
<Accordion {...args}>
@@ -106,7 +106,7 @@ export const WithIcons: Story = {
export const WithSubtitle: Story = {
args: {
type: 'card',
type: "card",
},
render: (args) => (
<Accordion {...args}>
@@ -140,7 +140,7 @@ export const WithSubtitle: Story = {
export const Inline: Story = {
args: {
type: 'inline',
type: "inline",
},
render: () => (
<Accordion type="inline">

View File

@@ -1,23 +1,24 @@
'use client'
"use client"
import { type ReactNode, useEffect, useRef } from 'react'
import { type ReactNode, useEffect, useRef } from "react"
import { IconByIconName } from '../../Icons/IconByIconName'
import { MaterialIcon } from '../../Icons/MaterialIcon'
import { IconByIconName } from "../../Icons/IconByIconName"
import { MaterialIcon } from "../../Icons/MaterialIcon"
import { accordionItemVariants } from './variants'
import { accordionItemVariants } from "./variants"
import styles from './accordionItem.module.css'
import styles from "./accordionItem.module.css"
import type { VariantProps } from 'class-variance-authority'
import type { IconName } from '../../Icons/iconName'
import { Typography } from '../../Typography'
import type { VariantProps } from "class-variance-authority"
import type { IconName } from "../../Icons/iconName"
import { Typography } from "../../Typography"
export interface AccordionItemProps
extends React.HtmlHTMLAttributes<HTMLDetailsElement>,
extends
React.HtmlHTMLAttributes<HTMLDetailsElement>,
VariantProps<typeof accordionItemVariants> {
title: string
titleLevel?: 'span' | 'p' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'
titleLevel?: "span" | "p" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6"
iconName?: IconName
icon?: ReactNode
subtitle?: string
@@ -31,7 +32,7 @@ export default function AccordionItem({
icon,
iconName,
title,
titleLevel = 'p',
titleLevel = "p",
type,
className,
subtitle,
@@ -59,17 +60,17 @@ export default function AccordionItem({
if (details.open) {
content.style.maxHeight = `${content.scrollHeight}px`
content.addEventListener(
'transitionend',
"transitionend",
() => {
// Remove maxHeight after transition to allow content to transition multiple times
content.style.maxHeight = 'none'
content.style.maxHeight = "none"
},
{ once: true }
)
onOpen?.()
} else {
content.style.maxHeight = '0'
content.style.maxHeight = "0"
}
}
}
@@ -89,11 +90,11 @@ export default function AccordionItem({
<details ref={detailsRef} onToggle={toggleAccordion}>
<summary className={styles.summary}>
{IconComp}
{type === 'sidepeek' ? (
{type === "sidepeek" ? (
<Typography variant="Title/Subtitle/md">
<p className={styles.title}>{title}</p>
</Typography>
) : type === 'inline' ? (
) : type === "inline" ? (
<Typography variant="Body/Supporting text (caption)/smBold">
<p className={styles.title}>{title}</p>
</Typography>

View File

@@ -1,6 +1,6 @@
import { cva } from 'class-variance-authority'
import { cva } from "class-variance-authority"
import styles from './accordionItem.module.css'
import styles from "./accordionItem.module.css"
export const accordionItemVariants = cva(styles.accordionItem, {
variants: {
@@ -11,6 +11,6 @@ export const accordionItemVariants = cva(styles.accordionItem, {
},
},
defaultVariants: {
type: 'card',
type: "card",
},
})

View File

@@ -1,12 +1,13 @@
import { Children, cloneElement, isValidElement } from 'react'
import { Children, cloneElement, isValidElement } from "react"
import type { VariantProps } from 'class-variance-authority'
import type { VariantProps } from "class-variance-authority"
import type { AccordionItemProps } from './AccordionItem'
import { accordionVariants } from './variants'
import type { AccordionItemProps } from "./AccordionItem"
import { accordionVariants } from "./variants"
interface AccordionProps
extends React.HtmlHTMLAttributes<HTMLUListElement>,
extends
React.HtmlHTMLAttributes<HTMLUListElement>,
VariantProps<typeof accordionVariants> {}
export default function Accordion({

View File

@@ -1,6 +1,6 @@
import { cva } from 'class-variance-authority'
import { cva } from "class-variance-authority"
import styles from './accordion.module.css'
import styles from "./accordion.module.css"
export const accordionVariants = cva(styles.accordion, {
variants: {
@@ -11,6 +11,6 @@ export const accordionVariants = cva(styles.accordion, {
},
},
defaultVariants: {
type: 'card',
type: "card",
},
})

View File

@@ -1,22 +1,22 @@
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
import { Alert } from './index'
import { AlertTypeEnum } from '@scandic-hotels/common/constants/alert'
import { expect, fn } from 'storybook/test'
import type { Meta, StoryObj } from "@storybook/nextjs-vite"
import { Alert } from "./index"
import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert"
import { expect, fn } from "storybook/test"
const meta: Meta<typeof Alert> = {
title: 'Core Components/Alert',
title: "Core Components/Alert",
component: Alert,
parameters: {
layout: 'centered',
layout: "centered",
},
tags: ['autodocs'],
tags: ["autodocs"],
argTypes: {
variant: {
control: { type: 'select' },
options: ['banner', 'inline'],
control: { type: "select" },
options: ["banner", "inline"],
},
type: {
control: { type: 'select' },
control: { type: "select" },
options: Object.values(AlertTypeEnum),
},
close: {
@@ -32,43 +32,43 @@ type Story = StoryObj<typeof meta>
export const Default: Story = {
args: {
variant: 'inline',
variant: "inline",
type: AlertTypeEnum.Info,
heading: 'Heading',
text: 'Caramels danish jelly-o pudding tart croissant. Pie cotton candy jujubes carrot cake gummies. Apple pie cake chocolate bar halvah tootsie roll bonbon cheesecake. Brownie dessert macaroon bear claw pastry.',
heading: "Heading",
text: "Caramels danish jelly-o pudding tart croissant. Pie cotton candy jujubes carrot cake gummies. Apple pie cake chocolate bar halvah tootsie roll bonbon cheesecake. Brownie dessert macaroon bear claw pastry.",
close: undefined,
ariaRole: 'alert',
ariaRole: "alert",
},
play: async ({ canvas }) => {
canvas.findByRole('alert')
canvas.findByRole("alert")
},
}
export const Closable: Story = {
args: {
variant: 'inline',
variant: "inline",
type: AlertTypeEnum.Info,
heading: 'Heading',
text: 'Caramels danish jelly-o pudding tart croissant. Pie cotton candy jujubes carrot cake gummies. Apple pie cake chocolate bar halvah tootsie roll bonbon cheesecake. Brownie dessert macaroon bear claw pastry.',
heading: "Heading",
text: "Caramels danish jelly-o pudding tart croissant. Pie cotton candy jujubes carrot cake gummies. Apple pie cake chocolate bar halvah tootsie roll bonbon cheesecake. Brownie dessert macaroon bear claw pastry.",
close: fn(),
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.close).toHaveBeenCalledTimes(1)
},
}
export const WithPhonenumber: Story = {
args: {
variant: 'inline',
variant: "inline",
type: AlertTypeEnum.Info,
heading: 'Heading',
text: 'Caramels danish jelly-o pudding tart croissant. Pie cotton candy jujubes carrot cake gummies. Apple pie cake chocolate bar halvah tootsie roll bonbon cheesecake. Brownie dessert macaroon bear claw pastry.',
heading: "Heading",
text: "Caramels danish jelly-o pudding tart croissant. Pie cotton candy jujubes carrot cake gummies. Apple pie cake chocolate bar halvah tootsie roll bonbon cheesecake. Brownie dessert macaroon bear claw pastry.",
close: fn(),
phoneContact: {
displayText: 'Call us:',
phoneNumber: '+4685551234',
footnote: 'Available 24/7',
displayText: "Call us:",
phoneNumber: "+4685551234",
footnote: "Available 24/7",
},
},
}

View File

@@ -1,16 +1,16 @@
'use client'
"use client"
import { useState } from 'react'
import { useIntl } from 'react-intl'
import { useState } from "react"
import { useIntl } from "react-intl"
import { Button } from '../../Button'
import { MaterialIcon } from '../../Icons/MaterialIcon'
import { JsonToHtml } from '../../JsonToHtml/JsonToHtml'
import SidePeek from '../../SidePeek'
import { Button } from "../../Button"
import { MaterialIcon } from "../../Icons/MaterialIcon"
import { JsonToHtml } from "../../JsonToHtml/JsonToHtml"
import SidePeek from "../../SidePeek"
import styles from './sidepeek.module.css'
import styles from "./sidepeek.module.css"
import type { AlertSidepeekProps } from './sidepeek'
import type { AlertSidepeekProps } from "./sidepeek"
export default function AlertSidepeek({
ctaText,
@@ -37,8 +37,8 @@ export default function AlertSidepeek({
isOpen={sidePeekIsOpen}
handleClose={() => setSidePeekIsOpen(false)}
closeLabel={intl.formatMessage({
id: 'common.close',
defaultMessage: 'Close',
id: "common.close",
defaultMessage: "Close",
})}
>
<JsonToHtml

View File

@@ -1,4 +1,4 @@
import type { SidepeekContent } from '@scandic-hotels/common/constants/alert'
import type { SidepeekContent } from "@scandic-hotels/common/constants/alert"
export interface AlertSidepeekProps {
ctaText: string

View File

@@ -1,11 +1,11 @@
import type {
AlertTypeEnum,
SidepeekContent,
} from '@scandic-hotels/common/constants/alert'
import type { VariantProps } from 'class-variance-authority'
import type { AriaRole } from 'react'
} from "@scandic-hotels/common/constants/alert"
import type { VariantProps } from "class-variance-authority"
import type { AriaRole } from "react"
import type { alertVariants } from './variants'
import type { alertVariants } from "./variants"
export interface AlertProps extends VariantProps<typeof alertVariants> {
className?: string
@@ -26,5 +26,5 @@ export interface AlertProps extends VariantProps<typeof alertVariants> {
} | null
close?: () => void
ariaRole?: AriaRole
ariaLive?: 'off' | 'assertive' | 'polite'
ariaLive?: "off" | "assertive" | "polite"
}

View File

@@ -1,17 +1,17 @@
'use client'
"use client"
import { Button } from '../Button'
import { MaterialIcon } from '../Icons/MaterialIcon'
import Link from '../OldDSLink'
import { Typography } from '../Typography'
import { Button } from "../Button"
import { MaterialIcon } from "../Icons/MaterialIcon"
import Link from "../OldDSLink"
import { Typography } from "../Typography"
import AlertSidepeek from './Sidepeek'
import { IconByAlertType } from './utils'
import { alertVariants } from './variants'
import AlertSidepeek from "./Sidepeek"
import { IconByAlertType } from "./utils"
import { alertVariants } from "./variants"
import styles from './alert.module.css'
import styles from "./alert.module.css"
import type { AlertProps } from './alert'
import type { AlertProps } from "./alert"
export function Alert({
className,
@@ -61,7 +61,7 @@ export function Alert({
<>
<span> {phoneContact.displayText} </span>
<Link
href={`tel:${phoneContact.phoneNumber.replace(/ /g, '')}`}
href={`tel:${phoneContact.phoneNumber.replace(/ /g, "")}`}
>
{phoneContact.phoneNumber}
</Link>

View File

@@ -1,28 +1,28 @@
import {
MaterialIcon,
type MaterialIconSetIconProps,
} from '../Icons/MaterialIcon'
import { AlertTypeEnum } from '@scandic-hotels/common/constants/alert'
} from "../Icons/MaterialIcon"
import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert"
import type { JSX } from 'react'
import type { JSX } from "react"
import type { AlertProps } from './alert'
import type { AlertProps } from "./alert"
interface IconByAlertProps {
alertType: AlertTypeEnum
variant?: AlertProps['variant']
variant?: AlertProps["variant"]
}
export function IconByAlertType({
alertType,
variant = 'inline',
variant = "inline",
...props
}: IconByAlertProps & MaterialIconSetIconProps): JSX.Element {
switch (alertType) {
case AlertTypeEnum.Alarm:
return (
<MaterialIcon
color={variant === 'inline' ? 'Icon/Inverted' : 'Icon/Feedback/Error'}
color={variant === "inline" ? "Icon/Inverted" : "Icon/Feedback/Error"}
isFilled
icon="error"
{...props}
@@ -33,7 +33,7 @@ export function IconByAlertType({
<MaterialIcon
icon="warning"
color={
variant === 'inline' ? 'Icon/Inverted' : 'Icon/Feedback/Warning'
variant === "inline" ? "Icon/Inverted" : "Icon/Feedback/Warning"
}
isFilled
{...props}
@@ -44,7 +44,7 @@ export function IconByAlertType({
<MaterialIcon
icon="check_circle"
color={
variant === 'inline' ? 'Icon/Inverted' : 'Icon/Feedback/Success'
variant === "inline" ? "Icon/Inverted" : "Icon/Feedback/Success"
}
isFilled
{...props}
@@ -55,7 +55,7 @@ export function IconByAlertType({
return (
<MaterialIcon
color={
variant === 'inline' ? 'Icon/Inverted' : 'Icon/Feedback/Information'
variant === "inline" ? "Icon/Inverted" : "Icon/Feedback/Information"
}
isFilled
icon="info"

View File

@@ -1,8 +1,8 @@
import { cva } from 'class-variance-authority'
import { cva } from "class-variance-authority"
import { AlertTypeEnum } from '@scandic-hotels/common/constants/alert'
import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert"
import styles from './alert.module.css'
import styles from "./alert.module.css"
export const alertVariants = cva(styles.alert, {
variants: {
@@ -18,7 +18,7 @@ export const alertVariants = cva(styles.alert, {
},
},
defaultVariants: {
variant: 'inline',
variant: "inline",
type: AlertTypeEnum.Info,
},
})

View File

@@ -1,17 +1,17 @@
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
import type { Meta, StoryObj } from "@storybook/nextjs-vite"
import { Avatar } from '.'
import { config } from './variants'
import { Avatar } from "."
import { config } from "./variants"
const meta: Meta<typeof Avatar> = {
title: 'Core Components/Avatar',
title: "Core Components/Avatar",
component: Avatar,
parameters: {
layout: 'centered',
layout: "centered",
},
argTypes: {
size: {
control: { type: 'select' },
control: { type: "select" },
options: Object.keys(config.variants.size),
},
},
@@ -20,31 +20,31 @@ const meta: Meta<typeof Avatar> = {
export default meta
type Story = StoryObj<typeof Avatar>
const imageFile = './img/profile-picture.png' as const
const imageFile = "./img/profile-picture.png" as const
export const WithImage: Story = {
args: {
src: imageFile,
alt: 'Profile photo',
size: 'md',
alt: "Profile photo",
size: "md",
},
}
export const WithInitials: Story = {
args: {
initials: 'FR',
size: 'md',
initials: "FR",
size: "md",
},
}
export const Fallback: Story = {
args: {
size: 'md',
size: "md",
},
}
export const SmallSize: Story = {
render: () => (
<div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>
<div style={{ display: "flex", gap: "16px", alignItems: "center" }}>
<Avatar src={imageFile} alt="Profile photo" size="sm" />
<Avatar initials="FR" size="sm" />
<Avatar size="sm" />
@@ -54,7 +54,7 @@ export const SmallSize: Story = {
export const MediumSize: Story = {
render: () => (
<div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>
<div style={{ display: "flex", gap: "16px", alignItems: "center" }}>
<Avatar src={imageFile} alt="Profile photo" size="md" />
<Avatar initials="FR" size="md" />
<Avatar size="md" />
@@ -64,7 +64,7 @@ export const MediumSize: Story = {
export const LargeSize: Story = {
render: () => (
<div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>
<div style={{ display: "flex", gap: "16px", alignItems: "center" }}>
<Avatar src={imageFile} alt="Profile photo" size="lg" />
<Avatar initials="FR" size="lg" />
<Avatar size="lg" />
@@ -74,39 +74,39 @@ export const LargeSize: Story = {
export const AllSizes: Story = {
render: () => (
<div style={{ display: 'flex', gap: '24px', alignItems: 'center' }}>
<div style={{ display: "flex", gap: "24px", alignItems: "center" }}>
<div
style={{
display: 'flex',
flexDirection: 'column',
gap: '8px',
alignItems: 'center',
display: "flex",
flexDirection: "column",
gap: "8px",
alignItems: "center",
}}
>
<Avatar initials="FR" size="sm" />
<span style={{ fontSize: '12px' }}>Small (20px)</span>
<span style={{ fontSize: "12px" }}>Small (20px)</span>
</div>
<div
style={{
display: 'flex',
flexDirection: 'column',
gap: '8px',
alignItems: 'center',
display: "flex",
flexDirection: "column",
gap: "8px",
alignItems: "center",
}}
>
<Avatar initials="FR" size="md" />
<span style={{ fontSize: '12px' }}>Medium (32px)</span>
<span style={{ fontSize: "12px" }}>Medium (32px)</span>
</div>
<div
style={{
display: 'flex',
flexDirection: 'column',
gap: '8px',
alignItems: 'center',
display: "flex",
flexDirection: "column",
gap: "8px",
alignItems: "center",
}}
>
<Avatar initials="FR" size="lg" />
<span style={{ fontSize: '12px' }}>Large (55px)</span>
<span style={{ fontSize: "12px" }}>Large (55px)</span>
</div>
</div>
),

View File

@@ -1,28 +1,28 @@
import { MaterialIcon } from '../Icons/MaterialIcon'
import { Typography } from '../Typography'
import Image from '../Image'
import { MaterialIcon } from "../Icons/MaterialIcon"
import { Typography } from "../Typography"
import Image from "../Image"
import { variants } from './variants'
import type { AvatarProps } from './types'
import { variants } from "./variants"
import type { AvatarProps } from "./types"
export function Avatar({
src,
alt,
initials,
size = 'md',
size = "md",
className,
}: AvatarProps) {
const classNames = variants({ size, className })
const pixelSize = size === 'sm' ? 24 : size === 'md' ? 32 : 55
const iconSize = size === 'sm' ? 16 : 24
const pixelSize = size === "sm" ? 24 : size === "md" ? 32 : 55
const iconSize = size === "sm" ? 16 : 24
return (
<div className={classNames}>
{src ? (
<Image src={src} alt={alt || ''} width={pixelSize} height={pixelSize} />
<Image src={src} alt={alt || ""} width={pixelSize} height={pixelSize} />
) : initials ? (
<Typography
variant={size === 'lg' ? 'Title/Overline/sm' : 'Tag/sm'}
variant={size === "lg" ? "Title/Overline/sm" : "Tag/sm"}
className={variants.initials}
>
<span data-hj-suppress>{initials}</span>

View File

@@ -15,7 +15,7 @@ export interface AvatarProps {
* Size of the avatar
* @default 'md'
*/
size?: 'sm' | 'md' | 'lg'
size?: "sm" | "md" | "lg"
/**
* Additional CSS class names
*/

View File

@@ -1,17 +1,17 @@
import { cva } from 'class-variance-authority'
import { cva } from "class-variance-authority"
import styles from './avatar.module.css'
import styles from "./avatar.module.css"
export const config = {
variants: {
size: {
sm: styles['size-sm'],
md: styles['size-md'],
lg: styles['size-lg'],
sm: styles["size-sm"],
md: styles["size-md"],
lg: styles["size-lg"],
},
},
defaultVariants: {
size: 'md',
size: "md",
},
} as const

View File

@@ -1,12 +1,12 @@
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
import type { Meta, StoryObj } from "@storybook/nextjs-vite"
import { expect, fn } from 'storybook/test'
import { expect, fn } from "storybook/test"
import { BackToTopButton } from '.'
import { config as backToTopButtonConfig } from './variants'
import { BackToTopButton } from "."
import { config as backToTopButtonConfig } from "./variants"
const meta: Meta<typeof BackToTopButton> = {
title: 'Patterns/BackToTopButton',
title: "Patterns/BackToTopButton",
component: BackToTopButton,
argTypes: {
onPress: {
@@ -15,13 +15,13 @@ const meta: Meta<typeof BackToTopButton> = {
},
},
position: {
control: 'select',
control: "select",
options: Object.keys(backToTopButtonConfig.variants.position),
table: {
type: {
summary: 'string',
summary: "string",
detail: Object.keys(backToTopButtonConfig.variants.position).join(
' | '
" | "
),
},
defaultValue: {
@@ -30,7 +30,7 @@ const meta: Meta<typeof BackToTopButton> = {
},
},
label: {
control: 'text',
control: "text",
},
},
}
@@ -40,16 +40,16 @@ export default meta
type Story = StoryObj<typeof BackToTopButton>
const globalStoryPropsInverted = {
backgrounds: { value: 'scandicPrimaryDark' },
backgrounds: { value: "scandicPrimaryDark" },
}
export const Default: Story = {
args: {
onPress: fn(),
label: 'Back to top',
label: "Back to top",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -57,10 +57,10 @@ export const Default: Story = {
export const PositionLeft: Story = {
args: {
...Default.args,
position: 'left',
position: "left",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -68,10 +68,10 @@ export const PositionLeft: Story = {
export const PositionCenter: Story = {
args: {
...Default.args,
position: 'center',
position: "center",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -79,10 +79,10 @@ export const PositionCenter: Story = {
export const PositionRight: Story = {
args: {
...Default.args,
position: 'right',
position: "right",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -91,10 +91,10 @@ export const OnDarkBackground: Story = {
globals: globalStoryPropsInverted,
args: {
onPress: fn(),
label: 'Back to top',
label: "Back to top",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}

View File

@@ -31,7 +31,7 @@
/* This button is able to be on top of dark background colors,
so we need to create an illusion that it also has an inverted border on focus */
&::before {
content: '';
content: "";
position: absolute;
inset: -4px;
border: 2px solid var(--Border-Inverted);

View File

@@ -1,20 +1,19 @@
'use client'
"use client"
import { Button as ButtonRAC } from 'react-aria-components'
import { Button as ButtonRAC } from "react-aria-components"
import { MaterialIcon } from '../Icons/MaterialIcon'
import { Typography } from '../Typography'
import { MaterialIcon } from "../Icons/MaterialIcon"
import { Typography } from "../Typography"
import { variants } from './variants'
import { variants } from "./variants"
import styles from './backToTopButton.module.css'
import styles from "./backToTopButton.module.css"
import type { VariantProps } from 'class-variance-authority'
import type { ComponentProps } from 'react'
import type { VariantProps } from "class-variance-authority"
import type { ComponentProps } from "react"
interface BackToTopButtonProps
extends ComponentProps<typeof ButtonRAC>,
VariantProps<typeof variants> {
extends ComponentProps<typeof ButtonRAC>, VariantProps<typeof variants> {
label: string
}

View File

@@ -1,6 +1,6 @@
import { cva } from 'class-variance-authority'
import { cva } from "class-variance-authority"
import styles from './backToTopButton.module.css'
import styles from "./backToTopButton.module.css"
export const config = {
variants: {
@@ -11,7 +11,7 @@ export const config = {
},
},
defaultVariants: {
position: 'right',
position: "right",
},
} as const

View File

@@ -1,9 +1,9 @@
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
import type { Meta, StoryObj } from "@storybook/nextjs-vite"
import { Badge } from './Badge.tsx'
import { Badge } from "./Badge.tsx"
const meta: Meta<typeof Badge> = {
title: 'Core Components/Badge',
title: "Core Components/Badge",
component: Badge,
}
@@ -15,7 +15,7 @@ export const Default: Story = {}
export const XS: Story = {
render: () => (
<div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>
<div style={{ display: "flex", gap: "16px", alignItems: "center" }}>
<Badge number={3} color="primary" size="20" />
<Badge number={3} color="green" size="20" />
</div>
@@ -24,7 +24,7 @@ export const XS: Story = {
export const Small: Story = {
render: () => (
<div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>
<div style={{ display: "flex", gap: "16px", alignItems: "center" }}>
<Badge number={3} color="primary" size="24" />
<Badge number={3} color="green" size="24" />
</div>
@@ -32,7 +32,7 @@ export const Small: Story = {
}
export const Medium: Story = {
render: () => (
<div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>
<div style={{ display: "flex", gap: "16px", alignItems: "center" }}>
<Badge number={3} color="primary" size="28" />
<Badge number={3} color="green" size="28" />
</div>
@@ -40,7 +40,7 @@ export const Medium: Story = {
}
export const Large: Story = {
render: () => (
<div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>
<div style={{ display: "flex", gap: "16px", alignItems: "center" }}>
<Badge number={3} color="primary" size="32" />
<Badge number={3} color="green" size="32" />
</div>
@@ -49,7 +49,7 @@ export const Large: Story = {
export const XL: Story = {
render: () => (
<div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>
<div style={{ display: "flex", gap: "16px", alignItems: "center" }}>
<Badge number={3} color="primary" size="36" />
<Badge number={3} color="green" size="36" />
</div>

View File

@@ -1,8 +1,8 @@
import { config } from './variants'
import { config } from "./variants"
import { VariantProps } from 'class-variance-authority'
import { Typography } from '../Typography'
import { TypographyProps } from '../Typography/types'
import { VariantProps } from "class-variance-authority"
import { Typography } from "../Typography"
import { TypographyProps } from "../Typography/types"
interface BadgeProps extends VariantProps<typeof config> {
number: string | number
@@ -21,15 +21,15 @@ export function Badge({ number, color, size }: BadgeProps) {
)
}
function getTypography(size: BadgeProps['size']): TypographyProps['variant'] {
function getTypography(size: BadgeProps["size"]): TypographyProps["variant"] {
switch (size) {
case '36':
case '32':
return 'Body/Paragraph/mdBold'
case '28':
case '24':
return 'Body/Supporting text (caption)/smBold'
case '20':
return 'Label/xsRegular'
case "36":
case "32":
return "Body/Paragraph/mdBold"
case "28":
case "24":
return "Body/Supporting text (caption)/smBold"
case "20":
return "Label/xsRegular"
}
}

View File

@@ -1 +1 @@
export { Badge } from './Badge'
export { Badge } from "./Badge"

View File

@@ -1,6 +1,6 @@
import { cva } from 'class-variance-authority'
import { cva } from "class-variance-authority"
import styles from './badge.module.css'
import styles from "./badge.module.css"
export const config = cva(styles.badge, {
variants: {
@@ -9,15 +9,15 @@ export const config = cva(styles.badge, {
green: styles.green,
},
size: {
'36': styles._36,
'32': styles._32,
'28': styles._28,
'24': styles._24,
'20': styles._20,
"36": styles._36,
"32": styles._32,
"28": styles._28,
"24": styles._24,
"20": styles._20,
},
},
defaultVariants: {
color: 'primary',
size: '28',
color: "primary",
size: "28",
},
})

View File

@@ -1,12 +1,12 @@
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
import { fn } from 'storybook/test'
import { BookingCodeChip } from './index'
import type { Meta, StoryObj } from "@storybook/nextjs-vite"
import { fn } from "storybook/test"
import { BookingCodeChip } from "./index"
const meta = {
title: 'Product Components/BookingCodeChip',
title: "Product Components/BookingCodeChip",
component: BookingCodeChip,
parameters: {
layout: 'centered',
layout: "centered",
},
} satisfies Meta<typeof BookingCodeChip>

View File

@@ -1,13 +1,13 @@
import { useIntl } from 'react-intl'
import { useIntl } from "react-intl"
import IconChip from '../IconChip'
import { MaterialIcon } from '../Icons/MaterialIcon'
import FilledDiscountIcon from '../Icons/Nucleo/Benefits/FilledDiscount'
import { Typography } from '../Typography'
import IconChip from "../IconChip"
import { MaterialIcon } from "../Icons/MaterialIcon"
import FilledDiscountIcon from "../Icons/Nucleo/Benefits/FilledDiscount"
import { Typography } from "../Typography"
import { cx } from 'class-variance-authority'
import { IconButton } from '../IconButton'
import styles from './bookingCodeChip.module.css'
import { cx } from "class-variance-authority"
import { IconButton } from "../IconButton"
import styles from "./bookingCodeChip.module.css"
type BaseBookingCodeChipProps = {
alignCenter?: boolean
@@ -47,11 +47,11 @@ export function BookingCodeChip({
return null
}
const color = isCampaignRate ? 'green' : 'blue'
const color = isCampaignRate ? "green" : "blue"
const iconColor = isCampaignRate
? 'Icon/Feedback/Success'
: 'Icon/Feedback/Information'
? "Icon/Feedback/Success"
: "Icon/Feedback/Information"
const isUnavailableRate = isCampaignRate
? isCampaignUnavailable
@@ -59,12 +59,12 @@ export function BookingCodeChip({
const label = isCampaignRate
? intl.formatMessage({
id: 'booking.campaign',
defaultMessage: 'Campaign',
id: "booking.campaign",
defaultMessage: "Campaign",
})
: intl.formatMessage({
id: 'booking.bookingCode',
defaultMessage: 'Booking code',
id: "booking.bookingCode",
defaultMessage: "Booking code",
})
const icon = isCampaignRate ? (
@@ -107,8 +107,8 @@ export function BookingCodeChip({
className={styles.removeButton}
onPress={onClose}
aria-label={intl.formatMessage({
id: 'booking.removeBookingCode',
defaultMessage: 'Remove booking code',
id: "booking.removeBookingCode",
defaultMessage: "Remove booking code",
})}
iconName="close"
/>

View File

@@ -1,41 +1,41 @@
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
import type { Meta, StoryObj } from "@storybook/nextjs-vite"
import { expect, fn } from 'storybook/test'
import { expect, fn } from "storybook/test"
import { Button } from './Button'
import { buttonIconNames } from './types'
import { config as buttonConfig } from './variants'
import { Button } from "./Button"
import { buttonIconNames } from "./types"
import { config as buttonConfig } from "./variants"
const meta: Meta<typeof Button> = {
title: 'Core Components/Button',
title: "Core Components/Button",
component: Button,
argTypes: {
onPress: {
table: {
type: { summary: 'function' },
defaultValue: { summary: 'undefined' },
type: { summary: "function" },
defaultValue: { summary: "undefined" },
},
description: 'Callback function to handle button press events.',
description: "Callback function to handle button press events.",
},
variant: {
control: 'select',
control: "select",
options: Object.keys(buttonConfig.variants.variant),
default: 'Primary',
default: "Primary",
table: {
defaultValue: {
summary: buttonConfig.defaultVariants.variant,
},
type: {
summary: Object.keys(buttonConfig.variants.variant).join(' | '),
summary: Object.keys(buttonConfig.variants.variant).join(" | "),
},
},
},
color: {
control: 'select',
control: "select",
options: Object.keys(buttonConfig.variants.color),
table: {
type: {
summary: Object.keys(buttonConfig.variants.color).join(' | '),
summary: Object.keys(buttonConfig.variants.color).join(" | "),
},
defaultValue: {
summary: buttonConfig.defaultVariants.color,
@@ -43,11 +43,11 @@ const meta: Meta<typeof Button> = {
},
},
size: {
control: 'select',
control: "select",
options: Object.keys(buttonConfig.variants.size),
table: {
type: {
summary: Object.keys(buttonConfig.variants.size).join(' | '),
summary: Object.keys(buttonConfig.variants.size).join(" | "),
},
defaultValue: {
summary: buttonConfig.defaultVariants.size,
@@ -55,63 +55,63 @@ const meta: Meta<typeof Button> = {
},
},
wrapping: {
control: 'boolean',
control: "boolean",
options: Object.keys(buttonConfig.variants.wrapping),
type: 'boolean',
type: "boolean",
table: {
defaultValue: {
summary: buttonConfig.defaultVariants.wrapping.toString(),
},
},
description:
'Only applies to variant `Text`. If `false`, the button will use smaller padding.',
"Only applies to variant `Text`. If `false`, the button will use smaller padding.",
},
leadingIconName: {
control: 'select',
control: "select",
options: buttonIconNames,
table: {
type: { summary: buttonIconNames.join(' | ') },
defaultValue: { summary: 'undefined' },
type: { summary: buttonIconNames.join(" | ") },
defaultValue: { summary: "undefined" },
},
description: 'Name of the Material Icon to use as leading icon.',
description: "Name of the Material Icon to use as leading icon.",
},
trailingIconName: {
control: 'select',
control: "select",
options: buttonIconNames,
table: {
type: { summary: buttonIconNames.join(' | ') },
defaultValue: { summary: 'undefined' },
type: { summary: buttonIconNames.join(" | ") },
defaultValue: { summary: "undefined" },
},
description: 'Name of the Material Icon to use as trailing icon.',
description: "Name of the Material Icon to use as trailing icon.",
},
isDisabled: {
control: 'boolean',
control: "boolean",
table: {
type: { summary: 'boolean' },
defaultValue: { summary: 'false' },
type: { summary: "boolean" },
defaultValue: { summary: "false" },
},
},
isPending: {
control: 'boolean',
control: "boolean",
table: {
type: { summary: 'boolean' },
defaultValue: { summary: 'false' },
type: { summary: "boolean" },
defaultValue: { summary: "false" },
},
},
fullWidth: {
control: 'boolean',
control: "boolean",
table: {
type: { summary: 'boolean' },
defaultValue: { summary: 'false' },
type: { summary: "boolean" },
defaultValue: { summary: "false" },
},
description:
'By default, the button width adjusts to its content. Set to true to make the button take the full width of its container.',
"By default, the button width adjusts to its content. Set to true to make the button take the full width of its container.",
},
},
}
const globalStoryPropsInverted = {
backgrounds: { value: 'scandicPrimaryDark' },
backgrounds: { value: "scandicPrimaryDark" },
}
export default meta
@@ -120,10 +120,10 @@ type Story = StoryObj<typeof Button>
export const Default: Story = {
args: {
onPress: fn(),
children: 'Button',
children: "Button",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -131,11 +131,11 @@ export const Default: Story = {
export const PrimaryLarge: Story = {
args: {
...Default.args,
variant: 'Primary',
size: 'lg',
variant: "Primary",
size: "lg",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -143,10 +143,10 @@ export const PrimaryLarge: Story = {
export const PrimaryMedium: Story = {
args: {
...PrimaryLarge.args,
size: 'md',
size: "md",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -154,10 +154,10 @@ export const PrimaryMedium: Story = {
export const PrimarySmall: Story = {
args: {
...PrimaryLarge.args,
size: 'sm',
size: "sm",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -169,7 +169,7 @@ export const PrimaryDisabled: Story = {
onPress: fn(), // Fresh spy instance for disabled test
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}
@@ -181,7 +181,7 @@ export const PrimaryLoading: Story = {
onPress: fn(), // Fresh spy instance for loading test
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}
@@ -192,7 +192,7 @@ export const PrimaryOnDarkBackground: Story = {
...PrimaryLarge.args,
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -201,11 +201,11 @@ export const PrimaryInvertedLarge: Story = {
globals: globalStoryPropsInverted,
args: {
...Default.args,
size: 'lg',
color: 'Inverted',
size: "lg",
color: "Inverted",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -214,10 +214,10 @@ export const PrimaryInvertedMedium: Story = {
globals: globalStoryPropsInverted,
args: {
...PrimaryInvertedLarge.args,
size: 'md',
size: "md",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -226,10 +226,10 @@ export const PrimaryInvertedSmall: Story = {
globals: globalStoryPropsInverted,
args: {
...PrimaryInvertedLarge.args,
size: 'sm',
size: "sm",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -242,7 +242,7 @@ export const PrimaryInvertedDisabled: Story = {
onPress: fn(), // Fresh spy instance for disabled test
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}
@@ -255,7 +255,7 @@ export const PrimaryInvertedLoading: Story = {
onPress: fn(), // Fresh spy instance for loading test
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}
@@ -263,11 +263,11 @@ export const PrimaryInvertedLoading: Story = {
export const SecondaryLarge: Story = {
args: {
...Default.args,
variant: 'Secondary',
size: 'lg',
variant: "Secondary",
size: "lg",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -275,10 +275,10 @@ export const SecondaryLarge: Story = {
export const SecondaryMedium: Story = {
args: {
...SecondaryLarge.args,
size: 'md',
size: "md",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -286,10 +286,10 @@ export const SecondaryMedium: Story = {
export const SecondarySmall: Story = {
args: {
...SecondaryLarge.args,
size: 'sm',
size: "sm",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -301,7 +301,7 @@ export const SecondaryDisabled: Story = {
onPress: fn(), // Fresh spy instance for disabled test
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}
@@ -313,7 +313,7 @@ export const SecondaryLoading: Story = {
onPress: fn(), // Fresh spy instance for loading test
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}
@@ -322,12 +322,12 @@ export const SecondaryInvertedLarge: Story = {
globals: globalStoryPropsInverted,
args: {
...Default.args,
variant: 'Secondary',
color: 'Inverted',
size: 'lg',
variant: "Secondary",
color: "Inverted",
size: "lg",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -336,10 +336,10 @@ export const SecondaryInvertedMedium: Story = {
globals: globalStoryPropsInverted,
args: {
...SecondaryInvertedLarge.args,
size: 'md',
size: "md",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -348,10 +348,10 @@ export const SecondaryInvertedSmall: Story = {
globals: globalStoryPropsInverted,
args: {
...SecondaryInvertedLarge.args,
size: 'sm',
size: "sm",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -364,7 +364,7 @@ export const SecondaryInvertedDisabled: Story = {
onPress: fn(), // Fresh spy instance for disabled test
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}
@@ -377,7 +377,7 @@ export const SecondaryInvertedLoading: Story = {
onPress: fn(), // Fresh spy instance for loading test
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}
@@ -385,11 +385,11 @@ export const SecondaryInvertedLoading: Story = {
export const TertiaryLarge: Story = {
args: {
...Default.args,
variant: 'Tertiary',
size: 'lg',
variant: "Tertiary",
size: "lg",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -397,10 +397,10 @@ export const TertiaryLarge: Story = {
export const TertiaryMedium: Story = {
args: {
...TertiaryLarge.args,
size: 'md',
size: "md",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -408,10 +408,10 @@ export const TertiaryMedium: Story = {
export const TertiarySmall: Story = {
args: {
...TertiaryLarge.args,
size: 'sm',
size: "sm",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -423,7 +423,7 @@ export const TertiaryDisabled: Story = {
onPress: fn(), // Fresh spy instance for disabled test
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}
@@ -435,7 +435,7 @@ export const TertiaryLoading: Story = {
onPress: fn(), // Fresh spy instance for loading test
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}
@@ -443,11 +443,11 @@ export const TertiaryLoading: Story = {
export const TextLarge: Story = {
args: {
...Default.args,
variant: 'Text',
size: 'lg',
variant: "Text",
size: "lg",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -455,11 +455,11 @@ export const TextLarge: Story = {
export const TextMedium: Story = {
args: {
...TextLarge.args,
size: 'md',
size: "md",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -467,11 +467,11 @@ export const TextMedium: Story = {
export const TextSmall: Story = {
args: {
...TextLarge.args,
size: 'sm',
size: "sm",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -483,7 +483,7 @@ export const TextDisabled: Story = {
onPress: fn(), // Fresh spy instance for disabled test
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}
@@ -494,7 +494,7 @@ export const TextNoWrapping: Story = {
wrapping: false,
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -503,12 +503,12 @@ export const TextInvertedLarge: Story = {
globals: globalStoryPropsInverted,
args: {
...Default.args,
variant: 'Text',
color: 'Inverted',
size: 'lg',
variant: "Text",
color: "Inverted",
size: "lg",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -517,10 +517,10 @@ export const TextInvertedMedium: Story = {
globals: globalStoryPropsInverted,
args: {
...TextInvertedLarge.args,
size: 'md',
size: "md",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -529,10 +529,10 @@ export const TextInvertedSmall: Story = {
globals: globalStoryPropsInverted,
args: {
...TextInvertedLarge.args,
size: 'sm',
size: "sm",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
},
}
@@ -545,7 +545,7 @@ export const TextInvertedDisabled: Story = {
onPress: fn(), // Fresh spy instance for disabled test
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(0)
},
}
@@ -553,15 +553,15 @@ export const TextInvertedDisabled: Story = {
export const TextWithIcon: Story = {
args: {
...TextLarge.args,
children: 'Text with icon',
trailingIconName: 'chevron_right',
children: "Text with icon",
trailingIconName: "chevron_right",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
expect(canvas.getByText('Text with icon')).toBeDefined()
expect(canvas.getByTestId('MaterialIcon')).toBeDefined()
expect(canvas.getByText("Text with icon")).toBeDefined()
expect(canvas.getByTestId("MaterialIcon")).toBeDefined()
},
}
@@ -569,13 +569,13 @@ export const TextWithIconInverted: Story = {
globals: globalStoryPropsInverted,
args: {
...TextWithIcon.args,
color: 'Inverted',
color: "Inverted",
},
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(await canvas.findByRole('button'))
await userEvent.click(await canvas.findByRole("button"))
expect(args.onPress).toHaveBeenCalledTimes(1)
expect(canvas.getByText('Text with icon')).toBeDefined()
expect(canvas.getByTestId('MaterialIcon')).toBeDefined()
expect(canvas.getByText("Text with icon")).toBeDefined()
expect(canvas.getByTestId("MaterialIcon")).toBeDefined()
},
}

View File

@@ -1,10 +1,10 @@
import { Button as ButtonRAC } from 'react-aria-components'
import { Loading } from '../Loading/Loading'
import { Button as ButtonRAC } from "react-aria-components"
import { Loading } from "../Loading/Loading"
import { MaterialIcon } from '../Icons/MaterialIcon'
import { Typography } from '../Typography'
import type { ButtonProps } from './types'
import { variants } from './variants'
import { MaterialIcon } from "../Icons/MaterialIcon"
import { Typography } from "../Typography"
import type { ButtonProps } from "./types"
import { variants } from "./variants"
export function Button({
variant,
@@ -30,9 +30,9 @@ export function Button({
return (
<Typography
variant={
size === 'sm'
? 'Body/Supporting text (caption)/smBold'
: 'Body/Paragraph/mdBold'
size === "sm"
? "Body/Supporting text (caption)/smBold"
: "Body/Paragraph/mdBold"
}
>
<ButtonRAC {...props} className={classNames}>
@@ -43,7 +43,7 @@ export function Button({
<MaterialIcon
icon={leadingIconName}
color="CurrentColor"
size={size === 'sm' ? 20 : 24}
size={size === "sm" ? 20 : 24}
/>
) : null}
{children}
@@ -51,11 +51,11 @@ export function Button({
<MaterialIcon
icon={trailingIconName}
color="CurrentColor"
size={size === 'sm' ? 20 : 24}
size={size === "sm" ? 20 : 24}
/>
) : null}
{isPending ? (
<Loading size={size === 'sm' ? 18 : 20} type="CurrentColor" />
<Loading size={size === "sm" ? 18 : 20} type="CurrentColor" />
) : null}
</>
)

View File

@@ -27,7 +27,7 @@
outline-offset: 2px;
&::before {
content: '';
content: "";
position: absolute;
inset: -4px;
border: 2px solid var(--Border-Inverted);

View File

@@ -1,4 +1,4 @@
export { Button } from './Button'
export { type ButtonProps } from './types'
export { Button } from "./Button"
export { type ButtonProps } from "./types"
// eslint-disable-next-line react-refresh/only-export-components
export { variants as buttonVariants, withButton } from './variants'
export { variants as buttonVariants, withButton } from "./variants"

View File

@@ -1,28 +1,28 @@
import { Button } from 'react-aria-components'
import { Button } from "react-aria-components"
import type { VariantProps } from 'class-variance-authority'
import type { ComponentProps } from 'react'
import type { VariantProps } from "class-variance-authority"
import type { ComponentProps } from "react"
import type { SymbolCodepoints } from '../Icons/MaterialIcon/MaterialSymbol/types'
import type { variants } from './variants'
import type { SymbolCodepoints } from "../Icons/MaterialIcon/MaterialSymbol/types"
import type { variants } from "./variants"
export const buttonIconNames = [
'add_circle',
'open_in_new',
'keyboard_arrow_down',
'keyboard_arrow_up',
'edit_square',
'location_on',
'link',
'mail',
'cancel',
'calendar_month',
'calendar_clock',
'edit_calendar',
'calendar_add_on',
'delete',
'chevron_right',
'chevron_left',
"add_circle",
"open_in_new",
"keyboard_arrow_down",
"keyboard_arrow_up",
"edit_square",
"location_on",
"link",
"mail",
"cancel",
"calendar_month",
"calendar_clock",
"edit_calendar",
"calendar_add_on",
"delete",
"chevron_right",
"chevron_left",
] as const
export type ButtonIconName = Extract<

View File

@@ -1,38 +1,38 @@
import { cva } from 'class-variance-authority'
import { cva } from "class-variance-authority"
import { deepmerge } from 'deepmerge-ts'
import styles from './button.module.css'
import { deepmerge } from "deepmerge-ts"
import styles from "./button.module.css"
export const config = {
variants: {
variant: {
Primary: styles['variant-primary'],
Secondary: styles['variant-secondary'],
Tertiary: styles['variant-tertiary'],
Text: styles['variant-text'],
Primary: styles["variant-primary"],
Secondary: styles["variant-secondary"],
Tertiary: styles["variant-tertiary"],
Text: styles["variant-text"],
},
color: {
Primary: styles['color-primary'],
Inverted: styles['color-inverted'],
Primary: styles["color-primary"],
Inverted: styles["color-inverted"],
},
size: {
sm: styles['size-sm'],
md: styles['size-md'],
lg: styles['size-lg'],
sm: styles["size-sm"],
md: styles["size-md"],
lg: styles["size-lg"],
},
wrapping: {
true: undefined,
false: styles['no-wrapping'],
false: styles["no-wrapping"],
},
fullWidth: {
true: styles['full-width'],
true: styles["full-width"],
false: undefined,
},
},
defaultVariants: {
variant: 'Primary',
color: 'Primary',
size: 'lg',
variant: "Primary",
color: "Primary",
size: "lg",
wrapping: true,
},
} as const

View File

@@ -1,20 +1,20 @@
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
import type { Meta, StoryObj } from "@storybook/nextjs-vite"
import { expect, fn } from 'storybook/test'
import { expect, fn } from "storybook/test"
import ButtonLink from '.'
import buttonMeta from '../Button/Button.stories'
import ButtonLink from "."
import buttonMeta from "../Button/Button.stories"
const meta: Meta<typeof ButtonLink> = {
title: 'Core Components/ButtonLink',
title: "Core Components/ButtonLink",
component: ButtonLink,
argTypes: {
onClick: {
table: {
type: { summary: 'function' },
defaultValue: { summary: 'undefined' },
type: { summary: "function" },
defaultValue: { summary: "undefined" },
},
description: 'Callback function to handle link click events.',
description: "Callback function to handle link click events.",
},
variant: buttonMeta.argTypes?.variant,
color: buttonMeta.argTypes?.color,
@@ -25,16 +25,16 @@ const meta: Meta<typeof ButtonLink> = {
fullWidth: buttonMeta.argTypes?.fullWidth,
href: {
table: {
type: { summary: 'string' },
defaultValue: { summary: 'undefined' },
type: { summary: "string" },
defaultValue: { summary: "undefined" },
},
description: 'The URL that the link points to.',
description: "The URL that the link points to.",
},
},
}
const globalStoryPropsInverted = {
backgrounds: { value: 'scandicPrimaryDark' },
backgrounds: { value: "scandicPrimaryDark" },
}
export default meta
@@ -43,12 +43,12 @@ type Story = StoryObj<typeof ButtonLink>
export const Default: Story = {
args: {
onClick: fn(),
href: '#',
children: 'Button link',
href: "#",
children: "Button link",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}
@@ -56,12 +56,12 @@ export const Default: Story = {
export const PrimaryLarge: Story = {
args: {
...Default.args,
variant: 'Primary',
size: 'lg',
variant: "Primary",
size: "lg",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}
@@ -69,11 +69,11 @@ export const PrimaryLarge: Story = {
export const PrimaryMedium: Story = {
args: {
...PrimaryLarge.args,
size: 'md',
size: "md",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}
@@ -81,11 +81,11 @@ export const PrimaryMedium: Story = {
export const PrimarySmall: Story = {
args: {
...PrimaryLarge.args,
size: 'sm',
size: "sm",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}
@@ -94,12 +94,12 @@ export const PrimaryOnDarkBackground: Story = {
globals: globalStoryPropsInverted,
args: {
...Default.args,
variant: 'Primary',
size: 'lg',
variant: "Primary",
size: "lg",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}
@@ -108,14 +108,14 @@ export const PrimaryInvertedLarge: Story = {
globals: globalStoryPropsInverted,
args: {
...Default.args,
variant: 'Primary',
color: 'Inverted',
size: 'lg',
variant: "Primary",
color: "Inverted",
size: "lg",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}
@@ -124,11 +124,11 @@ export const PrimaryInvertedMedium: Story = {
globals: globalStoryPropsInverted,
args: {
...PrimaryInvertedLarge.args,
size: 'md',
size: "md",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}
@@ -137,11 +137,11 @@ export const PrimaryInvertedSmall: Story = {
globals: globalStoryPropsInverted,
args: {
...PrimaryInvertedLarge.args,
size: 'sm',
size: "sm",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}
@@ -149,12 +149,12 @@ export const PrimaryInvertedSmall: Story = {
export const SecondaryLarge: Story = {
args: {
...Default.args,
variant: 'Secondary',
size: 'lg',
variant: "Secondary",
size: "lg",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}
@@ -162,11 +162,11 @@ export const SecondaryLarge: Story = {
export const SecondaryMedium: Story = {
args: {
...SecondaryLarge.args,
size: 'md',
size: "md",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}
@@ -174,11 +174,11 @@ export const SecondaryMedium: Story = {
export const SecondarySmall: Story = {
args: {
...SecondaryLarge.args,
size: 'sm',
size: "sm",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}
@@ -187,13 +187,13 @@ export const SecondaryInvertedLarge: Story = {
globals: globalStoryPropsInverted,
args: {
...Default.args,
variant: 'Secondary',
color: 'Inverted',
size: 'lg',
variant: "Secondary",
color: "Inverted",
size: "lg",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}
@@ -202,11 +202,11 @@ export const SecondaryInvertedMedium: Story = {
globals: globalStoryPropsInverted,
args: {
...SecondaryInvertedLarge.args,
size: 'md',
size: "md",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}
@@ -215,11 +215,11 @@ export const SecondaryInvertedSmall: Story = {
globals: globalStoryPropsInverted,
args: {
...SecondaryInvertedLarge.args,
size: 'sm',
size: "sm",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}
@@ -227,12 +227,12 @@ export const SecondaryInvertedSmall: Story = {
export const TertiaryLarge: Story = {
args: {
...Default.args,
variant: 'Tertiary',
size: 'lg',
variant: "Tertiary",
size: "lg",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}
@@ -240,11 +240,11 @@ export const TertiaryLarge: Story = {
export const TertiaryMedium: Story = {
args: {
...TertiaryLarge.args,
size: 'md',
size: "md",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}
@@ -252,11 +252,11 @@ export const TertiaryMedium: Story = {
export const TertiarySmall: Story = {
args: {
...TertiaryLarge.args,
size: 'sm',
size: "sm",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}
@@ -264,12 +264,12 @@ export const TertiarySmall: Story = {
export const TextLarge: Story = {
args: {
...Default.args,
variant: 'Text',
size: 'lg',
variant: "Text",
size: "lg",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}
@@ -277,11 +277,11 @@ export const TextLarge: Story = {
export const TextMedium: Story = {
args: {
...TextLarge.args,
size: 'md',
size: "md",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}
@@ -289,11 +289,11 @@ export const TextMedium: Story = {
export const TextSmall: Story = {
args: {
...TextLarge.args,
size: 'sm',
size: "sm",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}
@@ -301,12 +301,12 @@ export const TextSmall: Story = {
export const TextNoWrapping: Story = {
args: {
...TextLarge.args,
children: 'Text button with wrapping false',
children: "Text button with wrapping false",
wrapping: false,
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}
@@ -315,13 +315,13 @@ export const TextInvertedLarge: Story = {
globals: globalStoryPropsInverted,
args: {
...Default.args,
variant: 'Text',
color: 'Inverted',
size: 'lg',
variant: "Text",
color: "Inverted",
size: "lg",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}
@@ -330,11 +330,11 @@ export const TextInvertedMedium: Story = {
globals: globalStoryPropsInverted,
args: {
...TextInvertedLarge.args,
size: 'md',
size: "md",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}
@@ -343,11 +343,11 @@ export const TextInvertedSmall: Story = {
globals: globalStoryPropsInverted,
args: {
...TextInvertedLarge.args,
size: 'sm',
size: "sm",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}
@@ -355,13 +355,13 @@ export const TextInvertedSmall: Story = {
export const TextWithIcon: Story = {
args: {
...Default.args,
variant: 'Text',
children: 'Text with icon',
trailingIconName: 'chevron_right',
variant: "Text",
children: "Text with icon",
trailingIconName: "chevron_right",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}
@@ -370,11 +370,11 @@ export const TextWithIconInverted: Story = {
globals: globalStoryPropsInverted,
args: {
...TextWithIcon.args,
color: 'Inverted',
color: "Inverted",
},
play: async ({ canvasElement }) => {
const link = canvasElement.querySelector('a')
if (!link) throw new Error('Link not found')
const link = canvasElement.querySelector("a")
if (!link) throw new Error("Link not found")
expect(link).toBeInTheDocument()
},
}

View File

@@ -1,19 +1,19 @@
'use client'
"use client"
import { type ComponentProps } from 'react'
import { type ComponentProps } from "react"
import { variants } from './variants'
import { variants } from "./variants"
import type { VariantProps } from 'class-variance-authority'
import Link from 'next/link'
import { useIntl } from 'react-intl'
import { ButtonIconName } from '../Button/types'
import { MaterialIcon } from '../Icons/MaterialIcon'
import { Typography } from '../Typography'
import type { VariantProps } from "class-variance-authority"
import Link from "next/link"
import { useIntl } from "react-intl"
import { ButtonIconName } from "../Button/types"
import { MaterialIcon } from "../Icons/MaterialIcon"
import { Typography } from "../Typography"
export interface ButtonLinkProps
extends
Omit<ComponentProps<typeof Link>, 'color'>,
Omit<ComponentProps<typeof Link>, "color">,
VariantProps<typeof variants> {
leadingIconName?: ButtonIconName | null
trailingIconName?: ButtonIconName | null
@@ -44,30 +44,30 @@ export default function ButtonLink({
const intl = useIntl()
const newTabText = intl.formatMessage({
id: 'common.linkOpenInNewTab',
defaultMessage: 'Opens in a new tab/window',
id: "common.linkOpenInNewTab",
defaultMessage: "Opens in a new tab/window",
})
return (
<Typography
variant={
size === 'sm'
? 'Body/Supporting text (caption)/smBold'
: 'Body/Paragraph/mdBold'
size === "sm"
? "Body/Supporting text (caption)/smBold"
: "Body/Paragraph/mdBold"
}
>
<Link
className={classNames}
href={href}
target={target}
title={target === '_blank' ? newTabText : ''}
title={target === "_blank" ? newTabText : ""}
{...props}
>
{leadingIconName ? (
<MaterialIcon
icon={leadingIconName}
color="CurrentColor"
size={size === 'sm' ? 20 : 24}
size={size === "sm" ? 20 : 24}
/>
) : null}
{children}
@@ -75,7 +75,7 @@ export default function ButtonLink({
<MaterialIcon
icon={trailingIconName}
color="CurrentColor"
size={size === 'sm' ? 20 : 24}
size={size === "sm" ? 20 : 24}
/>
) : null}
</Link>

View File

@@ -1,6 +1,6 @@
import { cva } from 'class-variance-authority'
import { cva } from "class-variance-authority"
import { withButton } from '../Button'
import buttonStyles from '../Button/button.module.css'
import { withButton } from "../Button"
import buttonStyles from "../Button/button.module.css"
export const variants = cva([buttonStyles.button], withButton({}))

View File

@@ -1,10 +1,11 @@
import { Slot } from '@radix-ui/react-slot'
import { Slot } from "@radix-ui/react-slot"
import { captionVariants, fontOnlycaptionVariants } from './variants'
import { VariantProps } from 'class-variance-authority'
import { captionVariants, fontOnlycaptionVariants } from "./variants"
import { VariantProps } from "class-variance-authority"
interface CaptionProps
extends Omit<React.HTMLAttributes<HTMLHeadingElement>, 'color'>,
extends
Omit<React.HTMLAttributes<HTMLHeadingElement>, "color">,
VariantProps<typeof captionVariants> {
asChild?: boolean
fontOnly?: boolean
@@ -15,7 +16,7 @@ interface CaptionProps
*/
export default function Caption({
asChild = false,
className = '',
className = "",
color,
fontOnly = false,
textAlign,
@@ -25,7 +26,7 @@ export default function Caption({
type,
...props
}: CaptionProps) {
const Comp = asChild ? Slot : 'p'
const Comp = asChild ? Slot : "p"
const classNames = fontOnly
? fontOnlycaptionVariants({
className,

View File

@@ -1,6 +1,6 @@
import { cva } from 'class-variance-authority'
import { cva } from "class-variance-authority"
import styles from './caption.module.css'
import styles from "./caption.module.css"
const config = {
variants: {
@@ -44,8 +44,8 @@ const config = {
},
},
defaultVariants: {
color: 'black',
type: 'regular',
color: "black",
type: "regular",
},
} as const
@@ -70,7 +70,7 @@ const fontOnlyConfig = {
},
},
defaultVariants: {
type: 'regular',
type: "regular",
},
} as const

View File

@@ -1,9 +1,9 @@
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
import type { Meta, StoryObj } from "@storybook/nextjs-vite"
import { Card } from './Card.tsx'
import { Card } from "./Card.tsx"
const meta: Meta<typeof Card> = {
title: 'Core Components/Card',
title: "Core Components/Card",
component: Card,
}
@@ -13,13 +13,13 @@ type Story = StoryObj<typeof Card>
export const Default: Story = {
args: {
as: 'Default',
as: "Default",
},
}
export const Featured: Story = {
args: {
...Default.args,
as: 'Featured',
as: "Featured",
},
}

View File

@@ -1,6 +1,6 @@
import { variants } from './variants'
import { variants } from "./variants"
import type { CardProps } from './types'
import type { CardProps } from "./types"
export function Card({ as, className, children }: CardProps) {
const classNames = variants({

View File

@@ -1,11 +1,11 @@
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
import { fn } from 'storybook/test'
import type { Meta, StoryObj } from "@storybook/nextjs-vite"
import { fn } from "storybook/test"
import { themes } from '../../../../.storybook/preview'
import { themes } from "../../../../.storybook/preview"
import { Card } from '../'
import { Button } from '../../Button'
import { Typography } from '../../Typography'
import { Card } from "../"
import { Button } from "../../Button"
import { Typography } from "../../Typography"
type CompositionProps = React.ComponentPropsWithoutRef<typeof Card> & {
_onPrimaryPress?: () => void
@@ -18,18 +18,18 @@ type CompositionProps = React.ComponentPropsWithoutRef<typeof Card> & {
}
const meta: Meta<CompositionProps> = {
title: 'Compositions/Card',
title: "Compositions/Card",
component: Card,
decorators: [
(Story, context) => {
if (context.name.toLowerCase().indexOf('all themes') >= 0) {
if (context.name.toLowerCase().indexOf("all themes") >= 0) {
return (
<>
<h1>{context.name}</h1>
{Object.entries(themes.themes).map(([key, value], ix) => {
return (
<div key={ix} className={value} style={{ padding: '1em 0' }}>
<h2 style={{ paddingBottom: '0.5em' }}>{key}</h2>
<div key={ix} className={value} style={{ padding: "1em 0" }}>
<h2 style={{ paddingBottom: "0.5em" }}>{key}</h2>
<Story />
</div>
)
@@ -39,7 +39,7 @@ const meta: Meta<CompositionProps> = {
}
return (
<div style={{ display: 'flex' }}>
<div style={{ display: "flex" }}>
<Story />
</div>
)
@@ -47,19 +47,19 @@ const meta: Meta<CompositionProps> = {
],
argTypes: {
inMainArea: {
name: 'Is in main area',
name: "Is in main area",
},
showTitle: {
name: 'Composition: Show title',
name: "Composition: Show title",
},
showPreamble: {
name: 'Composition: Show preamble',
name: "Composition: Show preamble",
},
showPrimaryButton: {
name: 'Composition: Show primary button',
name: "Composition: Show primary button",
},
showSecondaryButton: {
name: 'Composition: Show secondary button',
name: "Composition: Show secondary button",
},
_onPrimaryPress: {
table: {
@@ -110,7 +110,7 @@ const meta: Meta<CompositionProps> = {
{showSecondaryButton && (
<Button
size={inMainArea ? 'lg' : 'sm'}
size={inMainArea ? "lg" : "sm"}
variant="Secondary"
onPress={args._onSecondaryPress}
>
@@ -127,7 +127,7 @@ type Story = StoryObj<CompositionProps>
export const ContentCardMainArea: Story = {
args: {
as: 'Default',
as: "Default",
inMainArea: true,
showTitle: true,
showPreamble: true,
@@ -140,7 +140,7 @@ export const ContentCardMainArea: Story = {
export const ContentCardNonMainArea: Story = {
args: {
as: 'Default',
as: "Default",
inMainArea: false,
showTitle: true,
showPreamble: true,

View File

@@ -1 +1 @@
export { Card } from './Card'
export { Card } from "./Card"

View File

@@ -1,11 +1,10 @@
import type { VariantProps } from 'class-variance-authority'
import type { VariantProps } from "class-variance-authority"
import type { variants } from './variants'
import type { variants } from "./variants"
type CardStyles = 'Default' | 'Featured'
type CardStyles = "Default" | "Featured"
export interface CardProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof variants> {
extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof variants> {
as: CardStyles
}

View File

@@ -1,6 +1,6 @@
import { cva } from 'class-variance-authority'
import { cva } from "class-variance-authority"
import styles from './card.module.css'
import styles from "./card.module.css"
const config = {
variants: {
@@ -10,7 +10,7 @@ const config = {
},
},
defaultVariants: {
as: 'Default',
as: "Default",
},
} as const

View File

@@ -1,9 +1,10 @@
import { VariantProps } from 'class-variance-authority'
import { chipVariants } from './variants'
import Footnote from '../Footnote'
import { VariantProps } from "class-variance-authority"
import { chipVariants } from "./variants"
import Footnote from "../Footnote"
export interface ChipProps
extends React.HtmlHTMLAttributes<HTMLDivElement>,
extends
React.HtmlHTMLAttributes<HTMLDivElement>,
VariantProps<typeof chipVariants> {}
/**

View File

@@ -1,6 +1,6 @@
import { cva } from 'class-variance-authority'
import { cva } from "class-variance-authority"
import styles from './chip.module.css'
import styles from "./chip.module.css"
export const chipVariants = cva(styles.chip, {
variants: {
@@ -17,7 +17,7 @@ export const chipVariants = cva(styles.chip, {
},
},
defaultVariants: {
size: 'medium',
variant: 'default',
size: "medium",
variant: "default",
},
})

View File

@@ -1,18 +1,18 @@
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
import type { Meta, StoryObj } from "@storybook/nextjs-vite"
import { fn } from 'storybook/test'
import { fn } from "storybook/test"
import { MaterialIcon } from '../Icons/MaterialIcon/MaterialIcon.tsx'
import { ChipButton } from './ChipButton.tsx'
import { config as chipButtonConfig } from './variants'
import { MaterialIcon } from "../Icons/MaterialIcon/MaterialIcon.tsx"
import { ChipButton } from "./ChipButton.tsx"
import { config as chipButtonConfig } from "./variants"
const meta: Meta<typeof ChipButton> = {
title: 'Core Components/ChipButton',
title: "Core Components/ChipButton",
component: ChipButton,
argTypes: {
variant: {
control: 'select',
type: 'string',
control: "select",
type: "string",
options: Object.keys(chipButtonConfig.variants.variant),
},
onPress: {
@@ -41,7 +41,7 @@ export const Default: Story = {
export const Outlined: Story = {
args: {
variant: 'Outlined',
variant: "Outlined",
onPress: fn(),
children: (
<>
@@ -54,9 +54,9 @@ export const Outlined: Story = {
export const FilterRoundedLarge: Story = {
args: {
variant: 'FilterRounded',
variant: "FilterRounded",
onPress: fn(),
size: 'Large',
size: "Large",
children: (
<>
<MaterialIcon icon="location_city" size={20} color="CurrentColor" />
@@ -68,9 +68,9 @@ export const FilterRoundedLarge: Story = {
export const FilterRoundedLargeSelected: Story = {
args: {
variant: 'FilterRounded',
variant: "FilterRounded",
onPress: fn(),
size: 'Large',
size: "Large",
selected: true,
children: (
<>
@@ -83,9 +83,9 @@ export const FilterRoundedLargeSelected: Story = {
export const FilterRoundedMedium: Story = {
args: {
variant: 'FilterRounded',
variant: "FilterRounded",
onPress: fn(),
size: 'Medium',
size: "Medium",
children: (
<>
<MaterialIcon icon="location_city" size={20} color="CurrentColor" />
@@ -97,9 +97,9 @@ export const FilterRoundedMedium: Story = {
export const FilterRoundedMediumSelected: Story = {
args: {
variant: 'FilterRounded',
variant: "FilterRounded",
onPress: fn(),
size: 'Medium',
size: "Medium",
selected: true,
children: (
<>

View File

@@ -1,13 +1,13 @@
import { Button as ButtonRAC } from 'react-aria-components'
import { Button as ButtonRAC } from "react-aria-components"
import { ChipButtonProps } from './types'
import { variants } from './variants'
import { ChipButtonProps } from "./types"
import { variants } from "./variants"
export function ChipButton({
children,
variant,
selected = false,
size = 'Large',
size = "Large",
className,
...props
}: ChipButtonProps) {
@@ -18,7 +18,7 @@ export function ChipButton({
})
return (
<ButtonRAC {...props} className={[className, classNames].join(' ')}>
<ButtonRAC {...props} className={[className, classNames].join(" ")}>
{children}
</ButtonRAC>
)

View File

@@ -1 +1 @@
export { ChipButton } from './ChipButton'
export { ChipButton } from "./ChipButton"

View File

@@ -1,10 +1,9 @@
import { Button } from 'react-aria-components'
import { Button } from "react-aria-components"
import type { VariantProps } from 'class-variance-authority'
import type { ComponentProps } from 'react'
import type { VariantProps } from "class-variance-authority"
import type { ComponentProps } from "react"
import type { variants } from './variants'
import type { variants } from "./variants"
export interface ChipButtonProps
extends ComponentProps<typeof Button>,
VariantProps<typeof variants> {}
extends ComponentProps<typeof Button>, VariantProps<typeof variants> {}

View File

@@ -1,22 +1,22 @@
import { cva } from 'class-variance-authority'
import { cva } from "class-variance-authority"
import { deepmerge } from 'deepmerge-ts'
import styles from './chip-button.module.css'
import { config as typographyConfig } from '../Typography/variants'
import { deepmerge } from "deepmerge-ts"
import styles from "./chip-button.module.css"
import { config as typographyConfig } from "../Typography/variants"
const variantKeys = {
variant: {
Default: 'Default',
Outlined: 'Outlined',
FilterRounded: 'FilterRounded',
Default: "Default",
Outlined: "Outlined",
FilterRounded: "FilterRounded",
},
style: {
Medium: 'Medium',
Large: 'Large',
Medium: "Medium",
Large: "Large",
},
typography: {
Bold: 'Body/Supporting text (caption)/smBold',
Regular: 'Body/Supporting text (caption)/smRegular',
Bold: "Body/Supporting text (caption)/smBold",
Regular: "Body/Supporting text (caption)/smRegular",
},
} as const
@@ -28,12 +28,12 @@ export const config = {
[variantKeys.variant.FilterRounded]: styles.FilterRounded,
},
selected: {
true: '',
false: '',
true: "",
false: "",
},
size: {
[variantKeys.style.Medium]: '',
[variantKeys.style.Large]: '',
[variantKeys.style.Medium]: "",
[variantKeys.style.Large]: "",
},
},
compoundVariants: [
@@ -41,7 +41,7 @@ export const config = {
variant: variantKeys.variant.Default,
className: [
typographyConfig.variants.variant[
'Body/Supporting text (caption)/smBold'
"Body/Supporting text (caption)/smBold"
],
],
},
@@ -49,7 +49,7 @@ export const config = {
variant: variantKeys.variant.Outlined,
className: [
typographyConfig.variants.variant[
'Body/Supporting text (caption)/smBold'
"Body/Supporting text (caption)/smBold"
],
],
},
@@ -59,7 +59,7 @@ export const config = {
selected: true,
className: [
typographyConfig.variants.variant[
'Body/Supporting text (caption)/smRegular'
"Body/Supporting text (caption)/smRegular"
],
styles.selected,
styles.medium,
@@ -71,7 +71,7 @@ export const config = {
selected: false,
className: [
typographyConfig.variants.variant[
'Body/Supporting text (caption)/smRegular'
"Body/Supporting text (caption)/smRegular"
],
styles.medium,
],
@@ -82,7 +82,7 @@ export const config = {
selected: true,
className: [
typographyConfig.variants.variant[
'Body/Supporting text (caption)/smRegular'
"Body/Supporting text (caption)/smRegular"
],
styles.selected,
styles.large,
@@ -94,7 +94,7 @@ export const config = {
selected: false,
className: [
typographyConfig.variants.variant[
'Body/Supporting text (caption)/smRegular'
"Body/Supporting text (caption)/smRegular"
],
styles.large,
],

View File

@@ -1,10 +1,10 @@
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
import type { Meta, StoryObj } from "@storybook/nextjs-vite"
import { MaterialIcon } from '../Icons/MaterialIcon'
import { ChipLink } from './ChipLink.tsx'
import { MaterialIcon } from "../Icons/MaterialIcon"
import { ChipLink } from "./ChipLink.tsx"
const meta: Meta<typeof ChipLink> = {
title: 'Core Components/ChipLink',
title: "Core Components/ChipLink",
component: ChipLink,
}
@@ -14,7 +14,7 @@ type Story = StoryObj<typeof ChipLink>
export const Default: Story = {
args: {
href: '/',
href: "/",
onPress: (e) => console.log(e),
children: (
<>

View File

@@ -1,13 +1,13 @@
import { cx } from 'class-variance-authority'
import { Typography } from '../Typography'
import { cx } from "class-variance-authority"
import { Typography } from "../Typography"
import styles from './chip-link.module.css'
import styles from "./chip-link.module.css"
import type { PropsWithChildren } from 'react'
import type { PropsWithChildren } from "react"
import {
Link as LinkRAC,
LinkProps as LinkRACProps,
} from 'react-aria-components'
} from "react-aria-components"
export function ChipLink({
children,

View File

@@ -1 +1 @@
export { ChipLink } from './ChipLink'
export { ChipLink } from "./ChipLink"

View File

@@ -1,19 +1,19 @@
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
import { fn } from 'storybook/test'
import type { Meta, StoryObj } from "@storybook/nextjs-vite"
import { fn } from "storybook/test"
import { Chips } from './Chips.tsx'
import { ChipLink } from '../ChipLink/ChipLink.tsx'
import { ChipButton } from '../ChipButton/ChipButton.tsx'
import { Chips } from "./Chips.tsx"
import { ChipLink } from "../ChipLink/ChipLink.tsx"
import { ChipButton } from "../ChipButton/ChipButton.tsx"
import { Default as ChipLinkDefault } from '../ChipLink/ChipLink.stories.tsx'
import { Default as ChipButtonDefault } from '../ChipButton/ChipButton.stories.tsx'
import { Default as ChipLinkDefault } from "../ChipLink/ChipLink.stories.tsx"
import { Default as ChipButtonDefault } from "../ChipButton/ChipButton.stories.tsx"
type StoryProps = React.ComponentPropsWithoutRef<typeof Chips> & {
onPress: () => void
}
const meta: Meta<StoryProps> = {
title: 'Compositions/Chips',
title: "Compositions/Chips",
component: Chips,
argTypes: {
onPress: {

View File

@@ -1,6 +1,6 @@
import styles from './chips.module.css'
import styles from "./chips.module.css"
import type { PropsWithChildren } from 'react'
import type { PropsWithChildren } from "react"
export function Chips({ children }: PropsWithChildren) {
return <div className={styles.chips}>{children}</div>

View File

@@ -1 +1 @@
export { Chips } from './Chips'
export { Chips } from "./Chips"

View File

@@ -2,6 +2,6 @@
display: flex;
}
div[data-rac][data-open='true'] .chevron {
div[data-rac][data-open="true"] .chevron {
transform: rotate(180deg);
}

View File

@@ -1,13 +1,13 @@
import { IconProps } from '../../Icons'
import { MaterialIcon } from '../../Icons/MaterialIcon'
import styles from './chevron.module.css'
import { IconProps } from "../../Icons"
import { MaterialIcon } from "../../Icons/MaterialIcon"
import styles from "./chevron.module.css"
export default function SelectChevron(props: IconProps) {
return (
<span aria-hidden="true" className={styles.chevron}>
<MaterialIcon
icon="keyboard_arrow_down"
color={props.color ?? 'Icon/Default'}
color={props.color ?? "Icon/Default"}
size={20}
/>
</span>

View File

@@ -1,5 +1,5 @@
'use client'
import { ReactElement, useState } from 'react'
"use client"
import { ReactElement, useState } from "react"
import {
Button,
type Key,
@@ -8,17 +8,17 @@ import {
Popover,
Select as ReactAriaSelect,
SelectValue,
} from 'react-aria-components'
} from "react-aria-components"
import SelectChevron from './SelectChevron'
import SelectChevron from "./SelectChevron"
import styles from './select.module.css'
import { InputLabel } from '../InputLabel'
import { Typography } from '../Typography'
import styles from "./select.module.css"
import { InputLabel } from "../InputLabel"
import { Typography } from "../Typography"
interface SelectProps extends Omit<
React.SelectHTMLAttributes<HTMLSelectElement>,
'onSelect'
"onSelect"
> {
defaultSelectedKey?: Key
items: { label: string; value: Key }[]
@@ -37,14 +37,14 @@ interface SelectProps extends Omit<
type SelectPortalContainer = HTMLDivElement | undefined
type SelectPortalContainerArgs = HTMLDivElement | null
const DELIMITER = ':'
const DELIMITER = ":"
/**
* @deprecated Do not use.
*/
export default function Select({
className = '',
'aria-label': ariaLabel,
className = "",
"aria-label": ariaLabel,
defaultSelectedKey,
items,
label,
@@ -78,16 +78,16 @@ export default function Select({
let chevronProps = {}
if (discreet) {
chevronProps = { color: 'baseButtonTextOnFillNormal' }
chevronProps = { color: "baseButtonTextOnFillNormal" }
} else if (disabled) {
chevronProps = { color: 'disabled' }
chevronProps = { color: "disabled" }
}
return (
<div className={`${styles.container} ${className}`} ref={setRef}>
<ReactAriaSelect
aria-label={ariaLabel}
className={`${styles.select} ${discreet ? styles.discreet : ''} select-container`}
className={`${styles.select} ${discreet ? styles.discreet : ""} select-container`}
defaultSelectedKey={defaultSelectedKey}
name={name}
onSelectionChange={handleOnSelect}
@@ -105,7 +105,7 @@ export default function Select({
<>
<InputLabel
required={required}
size={discreet ? 'discreet' : 'regular'}
size={discreet ? "discreet" : "regular"}
>
{label}
{discreet && DELIMITER}
@@ -113,7 +113,7 @@ export default function Select({
{selectedText && (
<Typography
variant="Body/Paragraph/mdRegular"
className={optionsIcon ? styles.iconLabel : ''}
className={optionsIcon ? styles.iconLabel : ""}
>
<p>
{optionsIcon ? optionsIcon : null}
@@ -165,9 +165,9 @@ export default function Select({
function useSetOverflowVisibleOnRA(isNestedInModal?: boolean) {
function setOverflowVisible(isOpen: boolean) {
if (isOpen) {
document.body.style.overflow = 'visible'
document.body.style.overflow = "visible"
} else if (!isNestedInModal) {
document.body.style.overflow = ''
document.body.style.overflow = ""
}
}

View File

@@ -10,16 +10,16 @@
gap: var(--Space-x05);
}
.select[data-focused='true'] {
.select[data-focused="true"] {
border: 2px solid var(--Border-Interactive-Focus);
outline: none;
}
.select[data-focused='true'].discreet {
.select[data-focused="true"].discreet {
border: 1px solid transparent;
outline: none;
}
.select[data-focus-visible='true'].discreet {
.select[data-focus-visible="true"].discreet {
border: 2px solid var(--Border-Interactive-Focus);
}
@@ -97,8 +97,8 @@
padding: var(--Space-x1);
}
.listBoxItem[data-focused='true'],
.listBoxItem[data-selected='true'] {
.listBoxItem[data-focused="true"],
.listBoxItem[data-selected="true"] {
background: var(--UI-Input-Controls-Surface-Hover);
border-radius: var(--Corner-radius-md);
outline: none;
@@ -111,7 +111,7 @@
.listBoxItem.showRadioButton:before {
flex-shrink: 0;
content: '';
content: "";
margin-right: var(--Space-x15);
background-color: white;
width: 24px;
@@ -120,6 +120,6 @@
box-shadow: inset 0 0 0 2px var(--Base-Border-Normal);
}
.listBoxItem[data-selected='true'].showRadioButton:before {
.listBoxItem[data-selected="true"].showRadioButton:before {
box-shadow: inset 0 0 0 8px var(--Surface-UI-Fill-Active);
}

View File

@@ -1,9 +1,9 @@
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
import type { Meta, StoryObj } from "@storybook/nextjs-vite"
import { Divider } from './Divider'
import { Divider } from "./Divider"
const meta: Meta<typeof Divider> = {
title: 'Core Components/Divider',
title: "Core Components/Divider",
component: Divider,
argTypes: {},
}

View File

@@ -1,6 +1,6 @@
import { dividerVariants } from './variants'
import { dividerVariants } from "./variants"
import type { DividerProps } from './types'
import type { DividerProps } from "./types"
export function Divider({ className, color, variant }: DividerProps) {
const classNames = dividerVariants({ className, color, variant })

View File

@@ -1,4 +1,4 @@
export { Divider } from './Divider'
export { Divider } from "./Divider"
// eslint-disable-next-line react-refresh/only-export-components
export { dividerVariants } from './variants'
export { dividerVariants } from "./variants"

View File

@@ -1,7 +1,8 @@
import type { VariantProps } from 'class-variance-authority'
import type { VariantProps } from "class-variance-authority"
import type { dividerVariants } from './variants'
import type { dividerVariants } from "./variants"
export interface DividerProps
extends Omit<React.HTMLAttributes<HTMLHRElement>, 'color'>,
extends
Omit<React.HTMLAttributes<HTMLHRElement>, "color">,
VariantProps<typeof dividerVariants> {}

View File

@@ -1,6 +1,6 @@
import { cva } from 'class-variance-authority'
import { cva } from "class-variance-authority"
import styles from './divider.module.css'
import styles from "./divider.module.css"
export const dividerVariants = cva(styles.divider, {
variants: {
@@ -9,15 +9,15 @@ export const dividerVariants = cva(styles.divider, {
pale: styles.pale,
peach: styles.peach,
white: styles.white,
'Border/Divider/Accent': styles['Border-Divider-Accent'],
'Border/Divider/Default': styles['Border-Divider-Default'],
'Border/Divider/Brand/OnPrimary 3/Default':
styles['Border-Divider-Brand-OnPrimary-3-Default'],
'Border/Divider/Subtle': styles['Border-Divider-Subtle'],
'Surface/Brand/Primary 1/OnSurface/Accent Secondary':
styles['Surface-Brand-Primary-1-OnSurface-Accent-Secondary'],
'Border/Divider/Brand/OnAccent/Default':
styles['Border-Divider-Brand-OnAccent-Default'],
"Border/Divider/Accent": styles["Border-Divider-Accent"],
"Border/Divider/Default": styles["Border-Divider-Default"],
"Border/Divider/Brand/OnPrimary 3/Default":
styles["Border-Divider-Brand-OnPrimary-3-Default"],
"Border/Divider/Subtle": styles["Border-Divider-Subtle"],
"Surface/Brand/Primary 1/OnSurface/Accent Secondary":
styles["Surface-Brand-Primary-1-OnSurface-Accent-Secondary"],
"Border/Divider/Brand/OnAccent/Default":
styles["Border-Divider-Brand-OnAccent-Default"],
},
variant: {
horizontal: styles.horizontal,
@@ -25,7 +25,7 @@ export const dividerVariants = cva(styles.divider, {
},
},
defaultVariants: {
color: 'Border/Divider/Default',
variant: 'horizontal',
color: "Border/Divider/Default",
variant: "horizontal",
},
})

View File

@@ -1,9 +1,9 @@
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
import type { Meta, StoryObj } from "@storybook/nextjs-vite"
import { FacilityEnum } from '@scandic-hotels/common/constants/facilities'
import { FacilityEnum } from "@scandic-hotels/common/constants/facilities"
import { FacilityToIcon } from '.'
import { iconVariantConfig } from '../Icons/variants'
import { FacilityToIcon } from "."
import { iconVariantConfig } from "../Icons/variants"
const facilityMapping: Record<string, FacilityEnum> = Object.fromEntries(
Object.entries(FacilityEnum).filter(([k]) => isNaN(Number(k)))
@@ -12,26 +12,26 @@ const facilityMapping: Record<string, FacilityEnum> = Object.fromEntries(
const colorOptions = Object.keys(iconVariantConfig.variants.color)
const meta: Meta<typeof FacilityToIcon> = {
title: 'Core Components/Facility To Icon',
title: "Core Components/Facility To Icon",
component: FacilityToIcon,
argTypes: {
id: {
control: 'select',
control: "select",
options: Object.keys(FacilityEnum)
.map((key) => FacilityEnum[key as keyof typeof FacilityEnum])
.filter((x) => typeof x === 'string')
.filter((x) => typeof x === "string")
.toSorted(),
mapping: facilityMapping,
description: 'Facility identifier (mapped to the corresponding icon)',
description: "Facility identifier (mapped to the corresponding icon)",
},
color: {
control: 'select',
control: "select",
options: colorOptions,
description: 'Icon color variant',
description: "Icon color variant",
},
size: {
control: 'number',
description: 'Icon pixel size',
control: "number",
description: "Icon pixel size",
},
},
}
@@ -44,7 +44,7 @@ export const Playground: Story = {
args: {
id: FacilityEnum.Bar,
size: 24,
color: 'Icon/Default',
color: "Icon/Default",
},
}
@@ -65,13 +65,13 @@ const exampleFacilities = [
export const Examples: Story = {
args: {
size: 24,
color: 'Icon/Default',
color: "Icon/Default",
},
render: (args) => (
<div
style={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fill, minmax(180px, 1fr))',
display: "grid",
gridTemplateColumns: "repeat(auto-fill, minmax(180px, 1fr))",
gap: 16,
}}
>
@@ -79,12 +79,12 @@ export const Examples: Story = {
<div
key={key}
style={{
display: 'flex',
alignItems: 'center',
display: "flex",
alignItems: "center",
gap: 12,
padding: 8,
borderRadius: 8,
background: 'var(--ds-color-surface-subtle, #F2ECE6)',
background: "var(--ds-color-surface-subtle, #F2ECE6)",
}}
>
<FacilityToIcon id={key} size={args.size} color={args.color} />

View File

@@ -1,10 +1,10 @@
import { FacilityEnum } from '@scandic-hotels/common/constants/facilities'
import { FacilityEnum } from "@scandic-hotels/common/constants/facilities"
import type { JSX } from 'react'
import { IconProps, NucleoIconProps } from '../Icons'
import { IconByIconName } from '../Icons/IconByIconName'
import { IconName } from '../Icons/iconName'
import { MaterialIconSetIconProps } from '../Icons/MaterialIcon'
import type { JSX } from "react"
import { IconProps, NucleoIconProps } from "../Icons"
import { IconByIconName } from "../Icons/IconByIconName"
import { IconName } from "../Icons/iconName"
import { MaterialIconSetIconProps } from "../Icons/MaterialIcon"
interface mapFacilityToIconProps {
id: FacilityEnum

View File

@@ -1,14 +1,14 @@
'use client'
"use client"
import { variants } from './variants'
import { variants } from "./variants"
import { cx, type VariantProps } from 'class-variance-authority'
import type { HTMLAttributes } from 'react'
import { Typography } from '../Typography'
import { cx, type VariantProps } from "class-variance-authority"
import type { HTMLAttributes } from "react"
import { Typography } from "../Typography"
interface FakeButtonProps
extends
Omit<HTMLAttributes<HTMLSpanElement>, 'color'>,
Omit<HTMLAttributes<HTMLSpanElement>, "color">,
VariantProps<typeof variants> {
isDisabled?: boolean
}
@@ -36,9 +36,9 @@ export function FakeButton({
return (
<Typography
variant={
size === 'sm'
? 'Body/Supporting text (caption)/smBold'
: 'Body/Paragraph/mdBold'
size === "sm"
? "Body/Supporting text (caption)/smBold"
: "Body/Paragraph/mdBold"
}
>
<span

View File

@@ -1,8 +1,8 @@
import { cva } from 'class-variance-authority'
import { cva } from "class-variance-authority"
import { withButton } from '../Button'
import { withButton } from "../Button"
import buttonStyles from '../Button/button.module.css'
import buttonStyles from "../Button/button.module.css"
export const variants = cva(
buttonStyles.button,

View File

@@ -1,11 +1,12 @@
import { Slot } from '@radix-ui/react-slot'
import { Slot } from "@radix-ui/react-slot"
import { footnoteFontOnlyVariants, footnoteVariants } from './variants'
import { footnoteFontOnlyVariants, footnoteVariants } from "./variants"
import type { VariantProps } from 'class-variance-authority'
import type { VariantProps } from "class-variance-authority"
interface FootnoteProps
extends Omit<React.HTMLAttributes<HTMLParagraphElement>, 'color'>,
extends
Omit<React.HTMLAttributes<HTMLParagraphElement>, "color">,
VariantProps<typeof footnoteVariants> {
asChild?: boolean
fontOnly?: boolean
@@ -16,7 +17,7 @@ interface FootnoteProps
*/
export default function Footnote({
asChild = false,
className = '',
className = "",
color,
fontOnly = false,
textAlign,
@@ -24,7 +25,7 @@ export default function Footnote({
type,
...props
}: FootnoteProps) {
const Comp = asChild ? Slot : 'p'
const Comp = asChild ? Slot : "p"
const classNames = fontOnly
? footnoteFontOnlyVariants({
className,

View File

@@ -1,6 +1,6 @@
import { cva } from 'class-variance-authority'
import { cva } from "class-variance-authority"
import styles from './footnote.module.css'
import styles from "./footnote.module.css"
const config = {
variants: {
@@ -29,7 +29,7 @@ const config = {
},
},
defaultVariants: {
type: 'regular',
type: "regular",
},
} as const
@@ -51,7 +51,7 @@ const fontOnlyConfig = {
},
},
defaultVariants: {
type: 'regular',
type: "regular",
},
} as const

View File

@@ -1,16 +1,16 @@
'use client'
"use client"
import { forwardRef } from 'react'
import { Checkbox as AriaCheckbox } from 'react-aria-components'
import { forwardRef } from "react"
import { Checkbox as AriaCheckbox } from "react-aria-components"
import {
type RegisterOptions,
useController,
useFormContext,
} from 'react-hook-form'
} from "react-hook-form"
import styles from './checkbox.module.css'
import { MaterialIcon } from '../../Icons/MaterialIcon'
import { ErrorMessage } from '../ErrorMessage'
import styles from "./checkbox.module.css"
import { MaterialIcon } from "../../Icons/MaterialIcon"
import { ErrorMessage } from "../ErrorMessage"
interface CheckboxProps extends React.InputHTMLAttributes<HTMLInputElement> {
name: string
@@ -25,7 +25,7 @@ const CheckboxComponent = forwardRef<
React.PropsWithChildren<CheckboxProps>
>(function Checkbox(
{
className = '',
className = "",
name,
children,
registerOptions,
@@ -55,7 +55,7 @@ const CheckboxComponent = forwardRef<
{({ isSelected }) => (
<>
<span
className={`${styles.checkboxContainer} ${topAlign ? styles.topAlign : ''}`}
className={`${styles.checkboxContainer} ${topAlign ? styles.topAlign : ""}`}
>
<span
className={styles.checkbox}

View File

@@ -1,6 +1,6 @@
'use client'
"use client"
import { type SyntheticEvent, useMemo, useState } from 'react'
import { type SyntheticEvent, useMemo, useState } from "react"
import {
Button,
ComboBox,
@@ -10,33 +10,33 @@ import {
ListBoxItem,
Popover,
useFilter,
} from 'react-aria-components'
import { useController } from 'react-hook-form'
} from "react-aria-components"
import { useController } from "react-hook-form"
import { MaterialIcon } from '../../Icons/MaterialIcon'
import { Typography } from '../../Typography'
import { ErrorMessage } from '../ErrorMessage'
import { MaterialIcon } from "../../Icons/MaterialIcon"
import { Typography } from "../../Typography"
import { ErrorMessage } from "../ErrorMessage"
import styles from './country.module.css'
import styles from "./country.module.css"
import type { CountryProps } from './country'
import type { CountryProps } from "./country"
const prioCountryCode = ['DE', 'DK', 'FI', 'NO', 'SE']
const prioCountryCode = ["DE", "DK", "FI", "NO", "SE"]
export default function CountryCombobox({
// hack used since chrome does not respect autocomplete="off"
autoComplete = 'nope',
className = '',
autoComplete = "nope",
className = "",
errorMessage,
label,
lang = 'en',
lang = "en",
countries,
name = 'country',
name = "country",
disabled = false,
registerOptions = {},
}: CountryProps) {
const { startsWith } = useFilter({ sensitivity: 'base' })
const [filterValue, setFilterValue] = useState('')
const { startsWith } = useFilter({ sensitivity: "base" })
const [filterValue, setFilterValue] = useState("")
const { field, formState, fieldState } = useController({
name,
rules: registerOptions,
@@ -68,7 +68,7 @@ export default function CountryCombobox({
function handleOnInput(evt: SyntheticEvent<HTMLInputElement>) {
setFilterValue(evt.currentTarget.value)
const isAutoCompleteEvent = !('inputType' in evt.nativeEvent)
const isAutoCompleteEvent = !("inputType" in evt.nativeEvent)
if (isAutoCompleteEvent) {
const { value } = evt.currentTarget
const cc = countries.find((c) => c.name === value || c.code === value)
@@ -89,7 +89,7 @@ export default function CountryCombobox({
isInvalid={fieldState.invalid}
name={name}
onBlur={field.onBlur}
onSelectionChange={(c) => field.onChange(c ?? '')}
onSelectionChange={(c) => field.onChange(c ?? "")}
selectedKey={field.value}
menuTrigger="focus"
>
@@ -142,8 +142,8 @@ export default function CountryCombobox({
<Typography
variant={
isSelected
? 'Body/Paragraph/mdBold'
: 'Body/Paragraph/mdRegular'
? "Body/Paragraph/mdBold"
: "Body/Paragraph/mdRegular"
}
>
<span>{item.label}</span>

View File

@@ -1,23 +1,23 @@
'use client'
"use client"
import { useMemo } from 'react'
import { useController } from 'react-hook-form'
import { useMemo } from "react"
import { useController } from "react-hook-form"
import { Select } from '../../Select'
import { Select } from "../../Select"
import { ErrorMessage } from '../ErrorMessage'
import { ErrorMessage } from "../ErrorMessage"
import type { CountryProps } from './country'
import type { CountryProps } from "./country"
const prioCountryCode = ['DE', 'DK', 'FI', 'NO', 'SE']
const prioCountryCode = ["DE", "DK", "FI", "NO", "SE"]
export default function CountrySelect({
className = '',
className = "",
errorMessage,
label,
countries,
lang = 'en',
name = 'country',
lang = "en",
name = "country",
disabled = false,
registerOptions = {},
}: CountryProps) {
@@ -58,7 +58,7 @@ export default function CountrySelect({
isInvalid={fieldState.invalid}
name={name}
onBlur={field.onBlur}
onSelectionChange={(c) => field.onChange(c ?? '')}
onSelectionChange={(c) => field.onChange(c ?? "")}
selectedKey={field.value}
data-testid={name}
/>

View File

@@ -6,7 +6,7 @@
height: 56px;
&[data-required] .label::after {
content: ' *';
content: " *";
}
&[data-open] {
@@ -92,12 +92,12 @@
}
}
.inner:has(input:placeholder-shown, input[data-focused='true'], input:valid)
.inner:has(input:placeholder-shown, input[data-focused="true"], input:valid)
.labelValue {
display: initial;
}
.inner:has(input[value='']:not([data-focused='true'])) .labelEmpty {
.inner:has(input[value=""]:not([data-focused="true"])) .labelEmpty {
display: initial;
}
@@ -110,7 +110,7 @@
transition: min-height 150ms ease;
width: 100%;
&[value]:not([value='']) {
&[value]:not([value=""]) {
min-height: 18px;
}
}

View File

@@ -1,4 +1,4 @@
import type { RegisterOptions } from 'react-hook-form'
import type { RegisterOptions } from "react-hook-form"
export type CountryProps = {
autoComplete?: string

View File

@@ -1,14 +1,14 @@
'use client'
"use client"
import { useMediaQuery } from 'usehooks-ts'
import { useMediaQuery } from "usehooks-ts"
import CountryCombobox from './CountryCombobox'
import CountrySelect from './CountrySelect'
import CountryCombobox from "./CountryCombobox"
import CountrySelect from "./CountrySelect"
import type { CountryProps } from './country'
import type { CountryProps } from "./country"
export default function Country(props: CountryProps) {
const isDesktop = useMediaQuery('(min-width: 768px)', {
const isDesktop = useMediaQuery("(min-width: 768px)", {
initializeWithValue: false,
})

View File

@@ -1,14 +1,13 @@
import { Lang } from '@scandic-hotels/common/constants/language'
import type { RegisterOptions } from 'react-hook-form'
import { Lang } from "@scandic-hotels/common/constants/language"
import type { RegisterOptions } from "react-hook-form"
export const enum DateName {
date = 'date',
day = 'day',
month = 'month',
year = 'year',
date = "date",
day = "day",
month = "month",
year = "year",
}
export interface DateProps
extends React.SelectHTMLAttributes<HTMLSelectElement> {
export interface DateProps extends React.SelectHTMLAttributes<HTMLSelectElement> {
labels: {
day: string
month: string

View File

@@ -1,19 +1,19 @@
'use client'
import { parseDate } from '@internationalized/date'
import { useEffect } from 'react'
import { useController, useFormContext, useWatch } from 'react-hook-form'
import { useMediaQuery } from 'usehooks-ts'
"use client"
import { parseDate } from "@internationalized/date"
import { useEffect } from "react"
import { useController, useFormContext, useWatch } from "react-hook-form"
import { useMediaQuery } from "usehooks-ts"
import { dt } from '@scandic-hotels/common/dt'
import { logger } from '@scandic-hotels/common/logger'
import { getLocalizedMonthName } from '@scandic-hotels/common/utils/dateFormatting'
import { rangeArray } from '@scandic-hotels/common/utils/rangeArray'
import { ErrorMessage } from '../../Form/ErrorMessage'
import { Select } from '../../Select'
import { dt } from "@scandic-hotels/common/dt"
import { logger } from "@scandic-hotels/common/logger"
import { getLocalizedMonthName } from "@scandic-hotels/common/utils/dateFormatting"
import { rangeArray } from "@scandic-hotels/common/utils/rangeArray"
import { ErrorMessage } from "../../Form/ErrorMessage"
import { Select } from "../../Select"
import { DateName, type DateProps } from './date'
import { DateName, type DateProps } from "./date"
import styles from './date.module.css'
import styles from "./date.module.css"
export default function DateSelect({
labels,
@@ -21,7 +21,7 @@ export default function DateSelect({
name,
registerOptions = {},
}: DateProps) {
const isDesktop = useMediaQuery('(min-width: 768px)', {
const isDesktop = useMediaQuery("(min-width: 768px)", {
initializeWithValue: false,
})
@@ -37,7 +37,7 @@ export default function DateSelect({
const month = watch(DateName.month)
const day = watch(DateName.day)
const minAgeDate = dt().subtract(18, 'year').toDate() // age 18
const minAgeDate = dt().subtract(18, "year").toDate() // age 18
const minAgeYear = minAgeDate.getFullYear()
const minAgeMonth = year === minAgeYear ? minAgeDate.getMonth() + 1 : null
const minAgeDay =
@@ -86,7 +86,7 @@ export default function DateSelect({
.date(Number(day))
if (newDate.isValid()) {
setValue(name, newDate.format('YYYY-MM-DD'), {
setValue(name, newDate.format("YYYY-MM-DD"), {
shouldDirty: true,
shouldTouch: true,
shouldValidate: true,
@@ -105,7 +105,7 @@ export default function DateSelect({
? parseDate(currentDateValue)
: null
} catch (error) {
logger.warn('Known error for parse date in DateSelect: ', error)
logger.warn("Known error for parse date in DateSelect: ", error)
}
useEffect(() => {

View File

@@ -1,7 +1,7 @@
import { MaterialIcon } from '../../Icons/MaterialIcon'
import { MaterialIcon } from "../../Icons/MaterialIcon"
import styles from './error.module.css'
import { Typography } from '../../Typography'
import styles from "./error.module.css"
import { Typography } from "../../Typography"
export function Error({ children }: React.PropsWithChildren) {
return (

View File

@@ -1,11 +1,11 @@
import type { FieldValuesFromFieldErrors } from '@hookform/error-message'
import type { FieldValuesFromFieldErrors } from "@hookform/error-message"
import type {
FieldErrors,
FieldName,
FieldValues,
Message,
MultipleFieldErrors,
} from 'react-hook-form'
} from "react-hook-form"
export type ErrorMessageProps<TFieldErrors> = {
errors?: FieldErrors<FieldValues>

View File

@@ -1,8 +1,8 @@
import { ErrorMessage as RHFErrorMessage } from '@hookform/error-message'
import { ErrorMessage as RHFErrorMessage } from "@hookform/error-message"
import { Error } from './Error'
import { Error } from "./Error"
import type { ErrorMessageProps } from './errorMessage'
import type { ErrorMessageProps } from "./errorMessage"
export function ErrorMessage<T>({
errors,

View File

@@ -1,45 +1,45 @@
'use client'
"use client"
import { forwardRef, type HTMLAttributes, type WheelEvent } from 'react'
import { Text, TextField } from 'react-aria-components'
import { Controller, useFormContext } from 'react-hook-form'
import { useIntl, type IntlShape } from 'react-intl'
import { cx } from 'class-variance-authority'
import { forwardRef, type HTMLAttributes, type WheelEvent } from "react"
import { Text, TextField } from "react-aria-components"
import { Controller, useFormContext } from "react-hook-form"
import { useIntl, type IntlShape } from "react-intl"
import { cx } from "class-variance-authority"
import { Error } from '../ErrorMessage/Error'
import { mergeRefs } from '../utils/mergeRefs'
import { MaterialIcon, MaterialIconProps } from '../../Icons/MaterialIcon'
import { Input } from '../../Input'
import { Error } from "../ErrorMessage/Error"
import { mergeRefs } from "../utils/mergeRefs"
import { MaterialIcon, MaterialIconProps } from "../../Icons/MaterialIcon"
import { Input } from "../../Input"
import styles from './input.module.css'
import styles from "./input.module.css"
import type { FormInputProps } from './input'
import type { FormInputProps } from "./input"
const defaultErrorFormatter = (
_intl: IntlShape,
errorMessage?: string
): string => errorMessage ?? ''
): string => errorMessage ?? ""
export const FormInput = forwardRef<HTMLInputElement, FormInputProps>(
function FormInput(
{
autoComplete,
className = '',
description = '',
descriptionIcon = 'info' as MaterialIconProps['icon'],
className = "",
description = "",
descriptionIcon = "info" as MaterialIconProps["icon"],
disabled = false,
errorFormatter,
hideError,
inputMode,
label,
labelPosition = 'floating',
labelPosition = "floating",
maxLength,
name,
id,
placeholder,
readOnly = false,
registerOptions = {},
type = 'text',
type = "text",
validationState,
...props
},
@@ -52,7 +52,7 @@ export const FormInput = forwardRef<HTMLInputElement, FormInputProps>(
// Number input: prevent scroll from changing value
const numberAttributes: HTMLAttributes<HTMLInputElement> =
type === 'number'
type === "number"
? {
onWheel: (evt: WheelEvent<HTMLInputElement>) => {
evt.currentTarget.blur()
@@ -87,7 +87,7 @@ export const FormInput = forwardRef<HTMLInputElement, FormInputProps>(
name={field.name}
onBlur={field.onBlur}
onChange={field.onChange}
value={field.value ?? ''}
value={field.value ?? ""}
autoComplete={autoComplete}
id={id ?? field.name}
label={label}
@@ -123,4 +123,4 @@ export const FormInput = forwardRef<HTMLInputElement, FormInputProps>(
}
)
FormInput.displayName = 'FormInput'
FormInput.displayName = "FormInput"

View File

@@ -8,7 +8,7 @@
gap: var(--Space-x05);
margin-top: var(--Space-x1);
font-size: var(--Body-Supporting-text-Size);
font-family: var(--Body-Supporting-text-Font-family, 'Fira Sans');
font-family: var(--Body-Supporting-text-Font-family, "Fira Sans");
font-style: normal;
font-weight: var(--Body-Supporting-text-Font-weight);
letter-spacing: var(--Body-Supporting-text-Letter-spacing);

View File

@@ -1,14 +1,14 @@
import type { RegisterOptions } from 'react-hook-form'
import type { IntlShape } from 'react-intl'
import type { RegisterOptions } from "react-hook-form"
import type { IntlShape } from "react-intl"
import type { MaterialIconProps } from '../../Icons/MaterialIcon'
import type { InputProps } from '../../Input/types'
import type { MaterialIconProps } from "../../Icons/MaterialIcon"
import type { InputProps } from "../../Input/types"
export interface FormInputProps extends InputProps {
/** Helper text displayed below the input (hidden when there's an error) */
description?: string
/** Icon to display with the description text. Defaults to 'info' */
descriptionIcon?: MaterialIconProps['icon']
descriptionIcon?: MaterialIconProps["icon"]
/** Field id for react-hook-form registration */
id?: string
/** Field name for react-hook-form registration */
@@ -24,5 +24,5 @@ export interface FormInputProps extends InputProps {
* - 'warning': Shows warning styling (yellow background, focus ring)
* - Note: Error state is automatically derived from form validation
*/
validationState?: 'warning'
validationState?: "warning"
}

View File

@@ -1,10 +1,10 @@
'use client'
"use client"
import { useController } from 'react-hook-form'
import { useController } from "react-hook-form"
import { Select } from '../../Select'
import { Select } from "../../Select"
import { SelectProps } from '../../Select/types'
import { SelectProps } from "../../Select/types"
export function FormSelect({ label, items, name }: SelectProps) {
const { field, fieldState } = useController({
@@ -17,7 +17,7 @@ export function FormSelect({ label, items, name }: SelectProps) {
isInvalid={fieldState.invalid}
name={name}
onBlur={field.onBlur}
onSelectionChange={(c) => field.onChange(c ?? '')}
onSelectionChange={(c) => field.onChange(c ?? "")}
selectedKey={field.value}
data-testid={name}
/>

View File

@@ -1,12 +1,12 @@
import { cx } from 'class-variance-authority'
import { Label, Radio } from 'react-aria-components'
import { cx } from "class-variance-authority"
import { Label, Radio } from "react-aria-components"
import styles from './paymentOption.module.css'
import styles from "./paymentOption.module.css"
import type { PaymentMethodEnum } from '@scandic-hotels/common/constants/paymentMethod'
import type { PaymentMethodEnum } from "@scandic-hotels/common/constants/paymentMethod"
import { PaymentMethodIcon } from '../../Payment/PaymentMethodIcon'
import { Typography } from '../../Typography'
import { PaymentMethodIcon } from "../../Payment/PaymentMethodIcon"
import { Typography } from "../../Typography"
export type PaymentOptionProps = {
value: string

View File

@@ -1,13 +1,13 @@
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
import { expect, fn } from 'storybook/test'
import type { Meta, StoryObj } from "@storybook/nextjs-vite"
import { expect, fn } from "storybook/test"
import { PaymentOptionsGroup } from './PaymentOptionsGroup'
import { PaymentOption } from './PaymentOption'
import { PaymentMethodEnum } from '@scandic-hotels/common/constants/paymentMethod'
import { FormDecorator } from '../../../../.storybook/decorators/FormDecorator'
import { PaymentOptionsGroup } from "./PaymentOptionsGroup"
import { PaymentOption } from "./PaymentOption"
import { PaymentMethodEnum } from "@scandic-hotels/common/constants/paymentMethod"
import { FormDecorator } from "../../../../.storybook/decorators/FormDecorator"
const meta: Meta<typeof PaymentOptionsGroup> = {
title: 'Patterns/Form/Payment/PaymentOptionsGroup',
title: "Patterns/Form/Payment/PaymentOptionsGroup",
component: PaymentOptionsGroup,
decorators: [FormDecorator],
}
@@ -17,8 +17,8 @@ type Story = StoryObj<typeof PaymentOptionsGroup>
export const Default: Story = {
args: {
label: 'Select Payment Method',
name: 'paymentMethod',
label: "Select Payment Method",
name: "paymentMethod",
onChange: fn(),
children: (
<>
@@ -42,11 +42,11 @@ export const Default: Story = {
),
},
play: async ({ canvas, userEvent, args }) => {
const visaOption = await canvas.findByRole('radio', { name: 'Visa' })
const visaOption = await canvas.findByRole("radio", { name: "Visa" })
expect(visaOption).toBeInTheDocument()
expect(args.onChange).not.toHaveBeenCalled()
await userEvent.click(visaOption)
expect(args.onChange).toHaveBeenCalledWith('visa')
expect(args.onChange).toHaveBeenCalledWith("visa")
},
}

View File

@@ -1,9 +1,9 @@
'use client'
"use client"
import { Label, RadioGroup } from 'react-aria-components'
import { useController, useFormContext } from 'react-hook-form'
import type { ReactNode } from 'react'
import { Typography } from '../../../components/Typography'
import { Label, RadioGroup } from "react-aria-components"
import { useController, useFormContext } from "react-hook-form"
import type { ReactNode } from "react"
import { Typography } from "../../../components/Typography"
interface PaymentOptionsGroupProps {
name: string

View File

@@ -1,9 +1,9 @@
'use client'
import 'react-international-phone/style.css'
"use client"
import "react-international-phone/style.css"
import { useEffect, useMemo } from 'react'
import { TextField } from 'react-aria-components'
import { useFormContext, useWatch } from 'react-hook-form'
import { useEffect, useMemo } from "react"
import { TextField } from "react-aria-components"
import { useFormContext, useWatch } from "react-hook-form"
import {
buildCountryData,
CountrySelector,
@@ -12,29 +12,29 @@ import {
parseCountry,
type ParsedCountry,
usePhoneInput,
} from 'react-international-phone'
} from "react-international-phone"
import { ErrorMessage } from '../ErrorMessage'
import { MaterialIcon } from '../../Icons/MaterialIcon'
import { Input } from '../../Input'
import { InputLabel } from '../../InputLabel'
import { ErrorMessage } from "../ErrorMessage"
import { MaterialIcon } from "../../Icons/MaterialIcon"
import { Input } from "../../Input"
import { InputLabel } from "../../InputLabel"
import styles from './phone.module.css'
import styles from "./phone.module.css"
import type { PhoneProps } from './phone'
import { Typography } from '../../Typography'
import type { PhoneProps } from "./phone"
import { Typography } from "../../Typography"
export default function Phone({
ariaLabel = 'Phone number input',
className = '',
countryLabel = 'Country code',
countrySelectorName = 'phoneNumberCC',
ariaLabel = "Phone number input",
className = "",
countryLabel = "Country code",
countrySelectorName = "phoneNumberCC",
countriesWithTranslatedName,
defaultCountryCode,
disabled = false,
errorMessage,
label,
name = 'phoneNumber',
name = "phoneNumber",
placeholder,
registerOptions = {
required: true,
@@ -90,7 +90,7 @@ export default function Phone({
dropdownArrowClassName={styles.arrow}
flagClassName={styles.flag}
onSelect={handleSelectCountry}
preferredCountries={['de', 'dk', 'fi', 'no', 'se', 'gb']}
preferredCountries={["de", "dk", "fi", "no", "se", "gb"]}
selectedCountry={country.iso2}
renderButtonWrapper={(props) => (
<button

View File

@@ -90,7 +90,7 @@
}
}
.select[aria-expanded='true'] .chevron {
.select[aria-expanded="true"] .chevron {
transform: rotate(180deg);
}

View File

@@ -1,4 +1,4 @@
import type { RegisterOptions } from 'react-hook-form'
import type { RegisterOptions } from "react-hook-form"
export interface PhoneProps {
ariaLabel?: string

View File

@@ -1,12 +1,12 @@
'use client'
"use client"
import { cx } from 'class-variance-authority'
import { Label, Radio, RadioGroup, Text } from 'react-aria-components'
import { cx } from "class-variance-authority"
import { Label, Radio, RadioGroup, Text } from "react-aria-components"
import { Divider } from '../../Divider'
import { Typography } from '../../Typography'
import { Divider } from "../../Divider"
import { Typography } from "../../Typography"
import styles from './radioButtonsGroup.module.css'
import styles from "./radioButtonsGroup.module.css"
interface Option {
value: string
title: string

View File

@@ -1,15 +1,15 @@
'use client'
"use client"
import { cx } from 'class-variance-authority'
import { useFormContext } from 'react-hook-form'
import { cx } from "class-variance-authority"
import { useFormContext } from "react-hook-form"
import { Divider } from '../../Divider'
import { MaterialIcon } from '../../Icons/MaterialIcon'
import { Typography } from '../../Typography'
import { Divider } from "../../Divider"
import { MaterialIcon } from "../../Icons/MaterialIcon"
import { Typography } from "../../Typography"
import styles from './radioCard.module.css'
import styles from "./radioCard.module.css"
import type { RadioCardProps } from './types'
import type { RadioCardProps } from "./types"
export default function RadioCard({
Icon,
@@ -37,7 +37,7 @@ export default function RadioCard({
function onKeyDown(event: React.KeyboardEvent) {
if (disabled) return
if (event.key === 'Enter') {
if (event.key === "Enter") {
setValue(name, value)
}
}

View File

@@ -5,8 +5,8 @@
grid-template-columns: 1fr auto;
grid-auto-rows: min-content;
grid-template-areas:
'icon subtitleSecondary'
'title subtitle';
"icon subtitleSecondary"
"title subtitle";
border-radius: var(--Corner-radius-md);
border: 1px solid var(--Border-Strong);
background: var(--Surface-Primary-Default);

View File

@@ -1,8 +1,10 @@
import type { IconProps } from '../../Icons'
import type { JSX } from 'react'
import type { IconProps } from "../../Icons"
import type { JSX } from "react"
export interface RadioCardProps
extends Omit<React.LabelHTMLAttributes<HTMLLabelElement>, 'title'> {
export interface RadioCardProps extends Omit<
React.LabelHTMLAttributes<HTMLLabelElement>,
"title"
> {
Icon?: (props: IconProps) => JSX.Element
iconHeight?: number
name: string

View File

@@ -1,12 +1,12 @@
import type { ComponentProps } from 'react'
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
import { fn, expect } from 'storybook/test'
import { SelectPaymentMethod } from './index'
import { PaymentMethodEnum } from '@scandic-hotels/common/constants/paymentMethod'
import { FormDecorator } from '../../../../.storybook/decorators/FormDecorator'
import type { ComponentProps } from "react"
import type { Meta, StoryObj } from "@storybook/nextjs-vite"
import { fn, expect } from "storybook/test"
import { SelectPaymentMethod } from "./index"
import { PaymentMethodEnum } from "@scandic-hotels/common/constants/paymentMethod"
import { FormDecorator } from "../../../../.storybook/decorators/FormDecorator"
const meta: Meta<typeof SelectPaymentMethod> = {
title: 'Patterns/Form/Payment/SelectCreditCard',
title: "Patterns/Form/Payment/SelectCreditCard",
component: SelectPaymentMethod,
argTypes: {},
decorators: [FormDecorator],
@@ -18,30 +18,30 @@ type Story = StoryObj<typeof SelectPaymentMethod>
export const PrimaryDefault: Story = {
args: {
formName: 'paymentMethod',
formName: "paymentMethod",
onChange: fn(),
paymentMethods: [
{
id: 'klarna',
alias: 'Card 1',
id: "klarna",
alias: "Card 1",
cardType: PaymentMethodEnum.klarna,
truncatedNumber: '1234',
truncatedNumber: "1234",
},
{
id: 'applePay',
alias: 'Card 2',
id: "applePay",
alias: "Card 2",
cardType: PaymentMethodEnum.applePay,
truncatedNumber: '1234',
truncatedNumber: "1234",
},
],
} satisfies ComponentProps<typeof SelectPaymentMethod>,
play: async ({ canvas, userEvent, args }) => {
const options = await canvas.findAllByRole('radio')
const options = await canvas.findAllByRole("radio")
expect(options[0]).toBeInTheDocument()
expect(args.onChange).not.toHaveBeenCalled()
await userEvent.click(options[0])
expect(args.onChange).toHaveBeenCalledWith('klarna')
expect(args.onChange).toHaveBeenCalledWith("klarna")
},
}

View File

@@ -1,16 +1,16 @@
import { useIntl } from 'react-intl'
import { Label } from 'react-aria-components'
import { useIntl } from "react-intl"
import { Label } from "react-aria-components"
import { PaymentOptionsGroup } from '../PaymentOption/PaymentOptionsGroup'
import { PaymentOption } from '../PaymentOption/PaymentOption'
import { Typography } from '../../../components/Typography'
import { PaymentOptionsGroup } from "../PaymentOption/PaymentOptionsGroup"
import { PaymentOption } from "../PaymentOption/PaymentOption"
import { Typography } from "../../../components/Typography"
import styles from './selectPaymentMethod.module.css'
import styles from "./selectPaymentMethod.module.css"
import {
PAYMENT_METHOD_TITLES,
PaymentMethodEnum,
} from '@scandic-hotels/common/constants/paymentMethod'
} from "@scandic-hotels/common/constants/paymentMethod"
type PaymentMethod = {
id: string
@@ -39,15 +39,15 @@ export function SelectPaymentMethod({
const mySavedCardsLabel = paymentMethods.length
? intl.formatMessage({
id: 'payment.mySavedCards',
defaultMessage: 'My saved cards',
id: "payment.mySavedCards",
defaultMessage: "My saved cards",
})
: undefined
const otherCardLabel = paymentMethods.length
? intl.formatMessage({
id: 'common.other',
defaultMessage: 'Other',
id: "common.other",
defaultMessage: "Other",
})
: undefined
@@ -64,8 +64,8 @@ export function SelectPaymentMethod({
>
<Label className="sr-only">
{intl.formatMessage({
id: 'enterDetails.guarantee.cardOptions',
defaultMessage: 'Card options',
id: "enterDetails.guarantee.cardOptions",
defaultMessage: "Card options",
})}
</Label>
<Typography variant="Title/Overline/sm">
@@ -94,8 +94,8 @@ export function SelectPaymentMethod({
value={PaymentMethodEnum.card}
type={PaymentMethodEnum.card}
label={intl.formatMessage({
id: 'common.creditCard',
defaultMessage: 'Credit card',
id: "common.creditCard",
defaultMessage: "Credit card",
})}
/>
</PaymentOptionsGroup>

View File

@@ -1 +1 @@
export { mergeRefs } from './mergeRefs'
export { mergeRefs } from "./mergeRefs"

View File

@@ -1,4 +1,4 @@
import type { Ref, RefCallback } from 'react'
import type { Ref, RefCallback } from "react"
/**
* Merges multiple refs into a single ref callback.
@@ -14,7 +14,7 @@ export function mergeRefs<T>(
): RefCallback<T> {
return (node: T | null) => {
refs.forEach((ref) => {
if (typeof ref === 'function') {
if (typeof ref === "function") {
ref(node)
} else if (ref) {
ref.current = node

Some files were not shown because too many files have changed in this diff Show More