Skip to content

Commit

Permalink
Merge branch 'develop' into feature/DES-733-use-invalid-prop
Browse files Browse the repository at this point in the history
# Conflicts:
#	packages/react/src/TextArea/TextArea.test.tsx
#	packages/react/src/TextArea/TextArea.tsx
#	packages/react/src/TextInput/TextInput.test.tsx
#	packages/react/src/TextInput/TextInput.tsx
  • Loading branch information
VincentSmedinga committed May 27, 2024
2 parents 8abaf13 + d2b371e commit 1042376
Show file tree
Hide file tree
Showing 25 changed files with 335 additions and 17 deletions.
9 changes: 9 additions & 0 deletions packages/css/src/components/file-input/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!-- @license CC0-1.0 -->

# File Input

Allows the user to upload one or more files from their device.

## Visual considerations

The filename label and button are displayed in the language of the browser and can vary between browsers and operating systems.
68 changes: 68 additions & 0 deletions packages/css/src/components/file-input/file-input.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* @license EUPL-1.2+
* Copyright Gemeente Amsterdam
*/

@import "../../common/text-rendering";

@mixin reset-button {
border: 0;
border-radius: 0; // Reset rounded borders on iOS devices
box-sizing: border-box;
}

.ams-file-input {
background-color: var(--ams-file-input-background-color);
border: var(--ams-file-input-border);
color: var(--ams-file-input-color);
cursor: var(--ams-file-input-cursor);
font-family: var(--ams-file-input-font-family);
font-size: var(--ams-file-input-font-size);
font-weight: var(--ams-file-input-font-weight);
line-height: var(--ams-file-input-line-height);
max-inline-size: calc(100% - var(--ams-file-input-padding-inline) * 2);
outline-offset: 0.25rem; // Double the default focus outline offset to compensate for the dashed border
padding-block: var(--ams-file-input-padding-block);
padding-inline: var(--ams-file-input-padding-inline);
touch-action: manipulation;

@include text-rendering;
}

.ams-file-input:disabled {
color: var(--ams-file-input-disabled-color);
cursor: var(--ams-file-input-disabled-cursor);
}

.ams-file-input::file-selector-button {
appearance: none; // Reset default appearance on iOS devices
background-color: var(--ams-file-input-file-selector-button-background-color);
box-shadow: var(--ams-file-input-file-selector-button-box-shadow);
color: var(--ams-file-input-file-selector-button-color);
cursor: var(--ams-file-input-file-selector-button-cursor);
font-family: inherit;
font-size: inherit; // iOS specific fix
font-weight: inherit;
margin-inline-end: var(--ams-file-input-file-selector-button-margin-inline-end);
padding-block: var(--ams-file-input-file-selector-button-padding-block);
padding-inline: var(--ams-file-input-file-selector-button-padding-inline);

@media screen and (-ms-high-contrast: active), screen and (forced-colors: active) {
border: var(
--ams-file-input-file-selector-button-forced-color-mode-border
); // add border because forced colors changes box-shadow to none
}

@include reset-button;
}

.ams-file-input:disabled::file-selector-button {
box-shadow: var(--ams-file-input-file-selector-button-disabled-box-shadow);
color: var(--ams-file-input-disabled-color);
cursor: var(--ams-file-input-file-selector-button-disabled-cursor);
}

.ams-file-input:not(:disabled):hover::file-selector-button {
box-shadow: var(--ams-file-input-file-selector-button-hover-box-shadow);
color: var(--ams-file-input-file-selector-button-hover-color);
}
1 change: 1 addition & 0 deletions packages/css/src/components/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

/* Append here */
@import "./file-input/file-input";
@import "./field/field";
@import "./select/select";
@import "./time-input/time-input";
Expand Down
1 change: 1 addition & 0 deletions packages/css/src/components/search-field/search-field.scss
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@

.ams-search-field__input::placeholder {
color: var(--ams-search-field-input-placeholder-color);
opacity: 100%; // This resets the lower opacity set by Firefox
}

.ams-search-field__input::-webkit-search-cancel-button {
Expand Down
1 change: 1 addition & 0 deletions packages/css/src/components/text-area/text-area.scss
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

.ams-text-area::placeholder {
color: var(--ams-text-area-placeholder-color);
opacity: 100%; // This resets the lower opacity set by Firefox
}

.ams-text-area:disabled {
Expand Down
1 change: 1 addition & 0 deletions packages/css/src/components/text-input/text-input.scss
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

.ams-text-input::placeholder {
color: var(--ams-text-input-placeholder-color);
opacity: 100%; // This resets the lower opacity set by Firefox
}

.ams-text-input:disabled {
Expand Down
6 changes: 3 additions & 3 deletions packages/react/src/Checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ export const Checkbox = forwardRef(
<div className={clsx('ams-checkbox', className)}>
<input
{...restProps}
type="checkbox"
aria-invalid={invalid || undefined}
className="ams-checkbox__input"
ref={innerRef}
id={id}
aria-invalid={invalid || undefined}
ref={innerRef}
type="checkbox"
/>
<label className="ams-checkbox__label" htmlFor={id}>
<span className="ams-checkbox__checkmark" />
Expand Down
4 changes: 2 additions & 2 deletions packages/react/src/DateInput/DateInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ export const DateInput = forwardRef(
({ className, invalid, ...restProps }: DateInputProps, ref: ForwardedRef<HTMLInputElement>) => (
<input
{...restProps}
ref={ref}
aria-invalid={invalid || undefined}
className={clsx('ams-date-input', className)}
ref={ref}
type="date"
aria-invalid={invalid || undefined}
/>
),
)
Expand Down
37 changes: 37 additions & 0 deletions packages/react/src/FileInput/FileInput.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { render } from '@testing-library/react'
import { createRef } from 'react'
import { FileInput } from './FileInput'
import '@testing-library/jest-dom'

describe('File input', () => {
it('renders', () => {
const { container } = render(<FileInput />)
const component = container.querySelector('input[type="file"]')

expect(component).toBeInTheDocument()
expect(component).toBeVisible()
})

it('renders a design system BEM class name', () => {
const { container } = render(<FileInput />)
const component = container.querySelector('input[type="file"]')

expect(component).toHaveClass('ams-file-input')
})

it('renders an additional class name', () => {
const { container } = render(<FileInput className="extra" />)
const component = container.querySelector('input[type="file"]')

expect(component).toHaveClass('ams-file-input extra')
})

it('supports ForwardRef in React', () => {
const ref = createRef<HTMLInputElement>()

const { container } = render(<FileInput ref={ref} />)
const component = container.querySelector('input[type="file"]')

expect(ref.current).toBe(component)
})
})
18 changes: 18 additions & 0 deletions packages/react/src/FileInput/FileInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* @license EUPL-1.2+
* Copyright Gemeente Amsterdam
*/

import clsx from 'clsx'
import { forwardRef } from 'react'
import type { ForwardedRef, InputHTMLAttributes } from 'react'

export type FileInputProps = InputHTMLAttributes<HTMLInputElement>

export const FileInput = forwardRef(
({ className, ...restProps }: FileInputProps, ref: ForwardedRef<HTMLInputElement>) => (
<input {...restProps} ref={ref} className={clsx('ams-file-input', className)} type="file" />
),
)

FileInput.displayName = 'FileInput'
5 changes: 5 additions & 0 deletions packages/react/src/FileInput/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<!-- @license CC0-1.0 -->

# React File Input component

[File Input documentation](../../../css/src/components/file-input/README.md)
2 changes: 2 additions & 0 deletions packages/react/src/FileInput/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { FileInput } from './FileInput'
export type { FileInputProps } from './FileInput'
6 changes: 3 additions & 3 deletions packages/react/src/Radio/Radio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ export const Radio = forwardRef(
<div className={clsx('ams-radio', className)}>
<input
{...restProps}
type="radio"
aria-invalid={invalid || undefined}
className="ams-radio__input"
ref={ref}
id={id}
aria-invalid={invalid || undefined}
ref={ref}
type="radio"
/>
<label className="ams-radio__label" htmlFor={id}>
<span className="ams-radio__circle" />
Expand Down
16 changes: 16 additions & 0 deletions packages/react/src/SearchField/SearchFieldInput.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,20 @@ describe('Search field input', () => {

expect(ref.current).toBe(component)
})

it('renders bidirectional by default using `dir="auto"`', () => {
render(<SearchFieldInput />)

const component = screen.getByRole('searchbox', { name: 'Zoeken' })

expect(component).toHaveAttribute('dir', 'auto')
})

it('renders left-to-right by using `dir="ltr"`', () => {
render(<SearchFieldInput dir="ltr" />)

const component = screen.getByRole('searchbox', { name: 'Zoeken' })

expect(component).toHaveAttribute('dir', 'ltr')
})
})
3 changes: 2 additions & 1 deletion packages/react/src/SearchField/SearchFieldInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type SearchFieldInputProps = {
} & InputHTMLAttributes<HTMLInputElement>

export const SearchFieldInput = forwardRef(
({ className, label = 'Zoeken', ...restProps }: SearchFieldInputProps, ref: ForwardedRef<HTMLInputElement>) => {
({ className, dir, label = 'Zoeken', ...restProps }: SearchFieldInputProps, ref: ForwardedRef<HTMLInputElement>) => {
const id = useId()

return (
Expand All @@ -26,6 +26,7 @@ export const SearchFieldInput = forwardRef(
{...restProps}
autoComplete="off"
className={clsx('ams-search-field__input', className)}
dir={dir ?? 'auto'}
enterKeyHint="search"
id={id}
ref={ref}
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/Select/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export type SelectProps = {

const SelectRoot = forwardRef(
({ children, className, invalid, ...restProps }: SelectProps, ref: ForwardedRef<HTMLSelectElement>) => (
<select {...restProps} ref={ref} className={clsx('ams-select', className)} aria-invalid={invalid || undefined}>
<select {...restProps} aria-invalid={invalid || undefined} className={clsx('ams-select', className)} ref={ref}>
{children}
</select>
),
Expand Down
16 changes: 16 additions & 0 deletions packages/react/src/TextArea/TextArea.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,19 @@ describe('Text area', () => {
expect(component).not.toHaveAttribute('aria-invalid')
})
})

it('renders bidirectional by default using `dir="auto"`', () => {
render(<TextArea />)

const component = screen.getByRole('textbox')

expect(component).toHaveAttribute('dir', 'auto')
})

it('renders left-to-right by using `dir="ltr"`', () => {
render(<TextArea dir="ltr" />)

const component = screen.getByRole('textbox')

expect(component).toHaveAttribute('dir', 'ltr')
})
7 changes: 4 additions & 3 deletions packages/react/src/TextArea/TextArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,18 @@ export type TextAreaProps = {
} & Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'aria-invalid'>

export const TextArea = forwardRef(
({ className, invalid, resize, ...restProps }: TextAreaProps, ref: ForwardedRef<HTMLTextAreaElement>) => (
({ className, dir, invalid, resize, ...restProps }: TextAreaProps, ref: ForwardedRef<HTMLTextAreaElement>) => (
<textarea
{...restProps}
ref={ref}
aria-invalid={invalid || undefined}
className={clsx(
'ams-text-area',
resize && `ams-text-area--resize-${resize}`,
restProps.cols && 'ams-text-area--cols',
className,
)}
aria-invalid={invalid || undefined}
dir={dir ?? 'auto'}
ref={ref}
/>
),
)
Expand Down
16 changes: 16 additions & 0 deletions packages/react/src/TextInput/TextInput.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,19 @@ describe('Text input', () => {
expect(component).not.toHaveAttribute('aria-invalid')
})
})

it('renders bidirectional by default using `dir="auto"`', () => {
render(<TextInput />)

const component = screen.getByRole('textbox')

expect(component).toHaveAttribute('dir', 'auto')
})

it('renders left-to-right by using `dir="ltr"`', () => {
render(<TextInput dir="ltr" />)

const component = screen.getByRole('textbox')

expect(component).toHaveAttribute('dir', 'ltr')
})
5 changes: 3 additions & 2 deletions packages/react/src/TextInput/TextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ export type TextInputProps = {
} & Omit<InputHTMLAttributes<HTMLInputElement>, 'aria-invalid'>

export const TextInput = forwardRef(
({ className, invalid, ...restProps }: TextInputProps, ref: ForwardedRef<HTMLInputElement>) => (
({ className, dir, invalid, ...restProps }: TextInputProps, ref: ForwardedRef<HTMLInputElement>) => (
<input
{...restProps}
aria-invalid={invalid || undefined}
className={clsx('ams-text-input', className)}
dir={dir ?? 'auto'}
ref={ref}
type="text"
aria-invalid={invalid || undefined}
/>
),
)
Expand Down
4 changes: 2 additions & 2 deletions packages/react/src/TimeInput/TimeInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ export const TimeInput = forwardRef(
({ className, invalid, ...restProps }: TimeInputProps, ref: ForwardedRef<HTMLInputElement>) => (
<input
{...restProps}
ref={ref}
aria-invalid={invalid || undefined}
className={clsx('ams-time-input', className)}
ref={ref}
type="time"
aria-invalid={invalid || undefined}
/>
),
)
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

/* Append here */
export * from './FileInput'
export * from './Field'
export * from './Select'
export * from './TimeInput'
Expand Down
Loading

0 comments on commit 1042376

Please sign in to comment.