Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/giant-needles-travel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@frontify/fondue-components": patch
"@frontify/fondue": patch
---

feat(lang): expose lang prop in appropriate components
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { type ComponentProps, type ComponentType } from 'react';

import { deCH, deDE, enUS, esES, frCH, frFR, itCH, itIT, nlNL, plPL, ptPT } from '#/locales';
import { type LocaleIdentifier } from '#/locales/types';
import { type LocaleConfig, type LocaleIdentifier } from '#/locales/types';

import { ThemeProvider } from '../../src/components/ThemeProvider/ThemeProvider';

Expand All @@ -15,7 +15,7 @@ type WithThemeOptions = {
};

export const withTheme = (Story: ComponentType, options: WithThemeOptions) => {
let locale = enUS;
let locale: LocaleConfig = enUS;

switch (options.locale) {
case 'de-DE':
Expand Down
5 changes: 4 additions & 1 deletion packages/components/src/components/Badge/Badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { IconCross } from '@frontify/fondue-icons';
import { type MouseEvent, type ReactNode } from 'react';

import { type CommonGlobalProps } from '#/helpers/aria';
import { useTranslation } from '#/hooks/useTranslation';

import { BadgeStatus, type BadgeStatusProps } from './BadgeStatus';
Expand All @@ -14,7 +15,7 @@ type BadgeEmphasis = 'strong' | 'weak';

type BadgeSize = 'default' | 'small';

type BadgeProps = {
type BadgeProps = CommonGlobalProps & {
/**
* @default 'strong'
*/
Expand Down Expand Up @@ -55,6 +56,7 @@ export const Badge = ({
children,
disabled = false,
emphasis = 'strong',
lang,
onClick,
onDismiss,
size = 'default',
Expand All @@ -74,6 +76,7 @@ export const Badge = ({
'data-test-id': dataTestId,
'data-variant': variant,
className: styles.root,
lang,
title,
};

Expand Down
9 changes: 9 additions & 0 deletions packages/components/src/components/Badge/tests/Badge.ct.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,12 @@ test('should keep regular font weight when wrapped in a bold ancestor', async ({
const fontWeight = await component.evaluate((element) => getComputedStyle(element).fontWeight);
expect(fontWeight).toBe('400');
});

test('should render lang on the badge element', async ({ mount }) => {
const wrapper = await mount(
<Badge data-test-id="badge-root" lang="fr-CH">
{BADGE_TEXT}
</Badge>,
);
await expect(wrapper.getByTestId('badge-root')).toHaveAttribute('lang', 'fr-CH');
});
7 changes: 5 additions & 2 deletions packages/components/src/components/Box/Box.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { forwardRef, type ReactNode } from 'react';

import { type CommonAriaProps } from '#/helpers/aria';
import { type CommonAriaProps, type CommonGlobalProps } from '#/helpers/aria';
import { type Responsive, type LayoutComponentProps } from '#/helpers/layout';
import { propsToCssVariables } from '#/helpers/propsToCssVariables';

Expand All @@ -22,7 +22,8 @@ export type BoxProps = LayoutComponentProps & {

children?: ReactNode;
'data-test-id'?: string;
} & CommonAriaProps;
} & CommonAriaProps &
CommonGlobalProps;

export const Box = forwardRef<HTMLDivElement, BoxProps>(
(
Expand All @@ -37,6 +38,7 @@ export const Box = forwardRef<HTMLDivElement, BoxProps>(
'aria-labelledby': ariaLabelledBy,
'aria-expanded': ariaExpanded,
'aria-haspopup': ariaHasPopup,
lang,
...props
},
ref,
Expand All @@ -53,6 +55,7 @@ export const Box = forwardRef<HTMLDivElement, BoxProps>(
aria-labelledby={ariaLabelledBy}
aria-expanded={ariaExpanded}
aria-haspopup={ariaHasPopup}
lang={lang}
ref={ref}
>
{children}
Expand Down
9 changes: 9 additions & 0 deletions packages/components/src/components/Box/__tests__/Box.ct.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,12 @@ test.describe('Responsiveness (lg)', () => {
await expect(component).toHaveCSS('margin', '120px');
});
});

test('should render lang on the root element', async ({ mount }) => {
const wrapper = await mount(
<Box data-test-id="box-root" lang="fr-CH">
{BOX_TEXT}
</Box>,
);
await expect(wrapper.getByTestId('box-root')).toHaveAttribute('lang', 'fr-CH');
});
4 changes: 3 additions & 1 deletion packages/components/src/components/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import { forwardRef, type ForwardedRef, type MouseEvent, type ReactNode } from 'react';

import { type CommonGlobalProps } from '#/helpers/aria';

import styles from './styles/button.module.scss';

type ButtonRounding = 'medium' | 'full';
Expand All @@ -16,7 +18,7 @@ type ButtonEmphasis = 'default' | 'weak' | 'strong';

type ButtonAspect = 'default' | 'square';

export type ButtonProps = {
export type ButtonProps = CommonGlobalProps & {
/**
* @default "button"
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,12 @@ test('should render in positive medium with an icon and text.', async ({ mount }
await expect(component).toHaveText(BUTTON_TEXT);
await expect(component.locator('data-test-id=fondue-icon-icon')).toBeVisible();
});

test('should render lang on the button element', async ({ mount }) => {
const wrapper = await mount(
<Button data-test-id="button-root" lang="fr-CH">
{BUTTON_TEXT}
</Button>,
);
await expect(wrapper.getByTestId('button-root')).toHaveAttribute('lang', 'fr-CH');
});
5 changes: 4 additions & 1 deletion packages/components/src/components/Card/CardRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
useMemo,
} from 'react';

import { type CommonGlobalProps } from '#/helpers/aria';
import { useTranslation } from '#/hooks/useTranslation';

import { useFondueRouter } from '../RouterProvider/RouterProvider';
Expand All @@ -21,7 +22,7 @@ import { ForwardedRefCardAction } from './CardAction';
import { CardContext } from './CardContext';
import styles from './styles/card.module.scss';

type CardRootBaseProps = {
type CardRootBaseProps = CommonGlobalProps & {
'data-test-id'?: string;
/**
* Additional class name(s) merged onto the card's root element. Useful for
Expand Down Expand Up @@ -114,6 +115,7 @@ export const CardRoot = (
'aria-label': ariaLabel,
'aria-describedby': ariaDescribedby,
className = '',
lang,
selected = false,
href,
target,
Expand Down Expand Up @@ -184,6 +186,7 @@ export const CardRoot = (
ref={ref}
className={[styles.root, className].filter(Boolean).join(' ')}
data-test-id={dataTestId}
lang={lang}
data-interactive={isClickable}
data-selectable={isSelectable}
data-selected={isSelectable && selected}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,12 @@ test('should still shift an un-toned banner background on hover', async ({ mount
.poll(() => banner.evaluate((element) => getComputedStyle(element).backgroundColor))
.toBe(expectedHover);
});

test('should render lang on the card root', async ({ mount }) => {
const wrapper = await mount(
<Card.Root data-test-id={CARD_TEST_ID} lang="fr-CH">
<Card.Title>Card title</Card.Title>
</Card.Root>,
);
await expect(wrapper.getByTestId(CARD_TEST_ID)).toHaveAttribute('lang', 'fr-CH');
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
import { Slot } from '@radix-ui/react-slot';
import { type ReactNode, forwardRef, useRef, useState } from 'react';

import { type CommonGlobalProps } from '#/helpers/aria';

import styles from './styles/editable-text.module.scss';

export type EditableTextProps = {
export type EditableTextProps = CommonGlobalProps & {
/**
* Callback fired with the plain text value when editing is confirmed (on blur or Enter).
* Only fires if the value has actually changed.
Expand Down Expand Up @@ -37,6 +39,7 @@ export const EditableText = forwardRef<HTMLElement, EditableTextProps>(
hugWidth = true,
'aria-label': ariaLabel,
children,
lang,
'data-test-id': dataTestId = 'fondue-editable-text',
},
forwardedRef,
Expand Down Expand Up @@ -94,6 +97,7 @@ export const EditableText = forwardRef<HTMLElement, EditableTextProps>(
<TextElement
ref={forwardedRef}
className={styles.text}
lang={lang}
contentEditable={isEditing ? 'plaintext-only' : undefined}
suppressContentEditableWarning
tabIndex={0}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,3 +202,8 @@ test('should switch asChild heading to textbox role on focus', async ({ mount, p
await heading.focus();
await expect(heading).toHaveAttribute('role', 'textbox');
});

test('should render lang on the editable element', async ({ mount }) => {
const component = await mount(<EditableText lang="fr-CH">{EDITABLE_TEXT_TEXT}</EditableText>);
await expect(component.getByText(EDITABLE_TEXT_TEXT)).toHaveAttribute('lang', 'fr-CH');
});
7 changes: 5 additions & 2 deletions packages/components/src/components/Flex/Flex.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { forwardRef, type ReactNode } from 'react';

import { type CommonAriaProps } from '#/helpers/aria';
import { type CommonAriaProps, type CommonGlobalProps } from '#/helpers/aria';
import { type Responsive, type SizeValue, type LayoutComponentProps } from '#/helpers/layout';
import { propsToCssVariables } from '#/helpers/propsToCssVariables';

Expand Down Expand Up @@ -51,7 +51,8 @@ export type FlexProps = LayoutComponentProps & {

children?: ReactNode;
'data-test-id'?: string;
} & CommonAriaProps;
} & CommonAriaProps &
CommonGlobalProps;

export const Flex = forwardRef<HTMLDivElement, FlexProps>(
(
Expand All @@ -66,6 +67,7 @@ export const Flex = forwardRef<HTMLDivElement, FlexProps>(
'aria-labelledby': ariaLabelledBy,
'aria-expanded': ariaExpanded,
'aria-haspopup': ariaHasPopup,
lang,
...props
},
ref,
Expand All @@ -82,6 +84,7 @@ export const Flex = forwardRef<HTMLDivElement, FlexProps>(
aria-labelledby={ariaLabelledBy}
aria-expanded={ariaExpanded}
aria-haspopup={ariaHasPopup}
lang={lang}
ref={ref}
>
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,12 @@ test.describe('Responsiveness (lg)', () => {
await expect(component).toHaveCSS('padding', '100px');
});
});

test('should render lang on the root element', async ({ mount }) => {
const wrapper = await mount(
<Flex data-test-id="flex-root" lang="fr-CH">
{FLEX_TEXT}
</Flex>,
);
await expect(wrapper.getByTestId('flex-root')).toHaveAttribute('lang', 'fr-CH');
});
7 changes: 5 additions & 2 deletions packages/components/src/components/Grid/Grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { forwardRef, type ReactNode } from 'react';

import { type CommonAriaProps } from '#/helpers/aria';
import { type CommonAriaProps, type CommonGlobalProps } from '#/helpers/aria';
import { type Responsive, type SizeValue, type LayoutComponentProps } from '#/helpers/layout';
import { propsToCssVariables } from '#/helpers/propsToCssVariables';

Expand Down Expand Up @@ -55,7 +55,8 @@ export type GridProps = LayoutComponentProps & {

children?: ReactNode;
'data-test-id'?: string;
} & CommonAriaProps;
} & CommonAriaProps &
CommonGlobalProps;

export const Grid = forwardRef<HTMLDivElement, GridProps>(
(
Expand All @@ -70,6 +71,7 @@ export const Grid = forwardRef<HTMLDivElement, GridProps>(
'aria-labelledby': ariaLabelledBy,
'aria-expanded': ariaExpanded,
'aria-haspopup': ariaHasPopup,
lang,
...props
},
ref,
Expand All @@ -86,6 +88,7 @@ export const Grid = forwardRef<HTMLDivElement, GridProps>(
aria-labelledby={ariaLabelledBy}
aria-expanded={ariaExpanded}
aria-haspopup={ariaHasPopup}
lang={lang}
ref={ref}
>
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,12 @@ test.describe('Responsiveness (lg)', () => {
await expect(component).toHaveCSS('grid-template-rows', '24px 24px 24px');
});
});

test('should render lang on the root element', async ({ mount }) => {
const wrapper = await mount(
<Grid data-test-id="grid-root" lang="fr-CH">
{GRID_TEXT}
</Grid>,
);
await expect(wrapper.getByTestId('grid-root')).toHaveAttribute('lang', 'fr-CH');
});
4 changes: 2 additions & 2 deletions packages/components/src/components/Heading/Heading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { type ForwardedRef, forwardRef, type ReactElement, type ReactNode } from 'react';

import { type CommonAriaProps } from '#/helpers/aria';
import { type CommonAriaProps, type CommonGlobalProps } from '#/helpers/aria';

import styles from './styles/heading.module.scss';

Expand All @@ -12,7 +12,7 @@ type HeadingColor = 'default' | 'weak' | 'x-weak' | 'disabled' | 'negative' | 'p

type TagType = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'span' | 'p';

export type HeadingProps<TTag extends TagType = 'span'> = CommonAriaProps & {
export type HeadingProps<TTag extends TagType = 'span'> = CommonAriaProps & CommonGlobalProps & {
'data-test-id'?: string;
as?: TTag;
children?: ReactNode;
Expand Down
4 changes: 3 additions & 1 deletion packages/components/src/components/Label/Label.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
import * as LabelPrimitive from '@radix-ui/react-label';
import { type ForwardedRef, forwardRef, type MouseEventHandler, type ReactNode, useRef, useLayoutEffect } from 'react';

import { type CommonGlobalProps } from '#/helpers/aria';

import styles from './styles/label.module.scss';

type LabelVariant = 'default' | 'strong';

export type LabelProps = {
export type LabelProps = CommonGlobalProps & {
id?: string;
children: ReactNode;
/**
Expand Down
4 changes: 3 additions & 1 deletion packages/components/src/components/Link/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import { forwardRef, type ReactNode, type MouseEvent, useCallback } from 'react';

import { type CommonGlobalProps } from '#/helpers/aria';

import { useFondueRouter } from '../RouterProvider/RouterProvider';

import styles from './styles/link.module.scss';
Expand All @@ -13,7 +15,7 @@ type LinkOnContainerColor = 'secondary' | 'disabled' | 'error' | 'success' | 'wa
type LinkWrap = 'wrap' | 'nowrap';
type LinkUnderline = 'auto' | 'always' | 'hover' | 'none';

export type LinkProps = {
export type LinkProps = CommonGlobalProps & {
children?: ReactNode;
/**
* The link to navigate to when clicked
Expand Down
Loading