-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Vincent Smedinga <[email protected]> Co-authored-by: Aram <[email protected]>
- Loading branch information
1 parent
d7316e8
commit 7b6ba98
Showing
11 changed files
with
264 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { FileInput } from './FileInput' | ||
export type { FileInputProps } from './FileInput' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 42 additions & 0 deletions
42
proprietary/tokens/src/components/ams/file-input.tokens.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
{ | ||
"ams": { | ||
"file-input": { | ||
"background-color": { "value": "{ams.color.primary-white}" }, | ||
"border": { "value": "{ams.border.width.sm} dashed {ams.color.neutral-grey3}" }, | ||
"color": { "value": "{ams.color.primary-black}" }, | ||
"cursor": { "value": "{ams.action.activate.cursor}" }, | ||
"font-family": { "value": "{ams.text.font-family}" }, | ||
"font-size": { "value": "{ams.text.level.5.font-size}" }, | ||
"font-weight": { "value": "{ams.text.font-weight.normal}" }, | ||
"line-height": { "value": "{ams.text.level.5.line-height}" }, | ||
"outline-offset": { "value": "{ams.focus.outline-offset}" }, | ||
"padding-block": { "value": "{ams.space.inside.md}" }, | ||
"padding-inline": { "value": "{ams.space.inside.md}" }, | ||
"disabled": { | ||
"color": { "value": "{ams.color.neutral-grey2}" }, | ||
"cursor": { "value": "{ams.action.disabled.cursor}" } | ||
}, | ||
"file-selector-button": { | ||
"background-color": { "value": "{ams.color.primary-white}" }, | ||
"box-shadow": { "value": "inset 0 0 0 {ams.border.width.md} {ams.color.primary-blue}" }, | ||
"color": { "value": "{ams.color.primary-blue}" }, | ||
"cursor": { "value": "{ams.action.activate.cursor}" }, | ||
"margin-inline-end": { "value": "{ams.space.inside.md}" }, | ||
"padding-block": { "value": "{ams.space.inside.xs}" }, | ||
"padding-inline": { "value": "{ams.space.inside.md}" }, | ||
"hover": { | ||
"box-shadow": { "value": "inset 0 0 0 {ams.border.width.lg} {ams.color.dark-blue}" }, | ||
"color": { "value": "{ams.color.dark-blue}" } | ||
}, | ||
"disabled": { | ||
"box-shadow": { "value": "inset 0 0 0 {ams.border.width.md} {ams.color.neutral-grey2}" }, | ||
"color": { "value": "{ams.color.neutral-grey2}" }, | ||
"cursor": { "value": "{ams.action.disabled.cursor}" } | ||
}, | ||
"forced-color-mode": { | ||
"border": { "value": "{ams.border.width.md} solid" } | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { Canvas, Controls, Markdown, Meta, Primary } from "@storybook/blocks"; | ||
import * as FileInputStories from "./FileInput.stories.tsx"; | ||
import README from "../../../../packages/css/src/components/file-input/README.md?raw"; | ||
|
||
<Meta of={FileInputStories} /> | ||
|
||
<Markdown>{README}</Markdown> | ||
|
||
<Primary /> | ||
|
||
<Controls /> | ||
|
||
## Multiple Files | ||
|
||
Allow multiple files to be selected. The label will update to show the number of files selected. | ||
|
||
<Canvas of={FileInputStories.Multiple} /> | ||
|
||
## Accept | ||
|
||
Limit the types of files that can be selected. Some examples are `image/*`, `video/*`, or `audio/*`. To limit to a specific file type, use the MIME type, such as `application/pdf`. | ||
|
||
- [MDN File Input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#limiting_accepted_file_types): More examples | ||
|
||
<Canvas of={FileInputStories.Accept} /> | ||
|
||
## Disabled | ||
|
||
<Canvas of={FileInputStories.Disabled} /> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/** | ||
* @license EUPL-1.2+ | ||
* Copyright Gemeente Amsterdam | ||
*/ | ||
|
||
import { FileInput } from '@amsterdam/design-system-react/src' | ||
import { Meta, StoryObj } from '@storybook/react' | ||
|
||
const meta = { | ||
title: 'Components/Forms/File Input', | ||
component: FileInput, | ||
args: { | ||
accept: undefined, | ||
multiple: false, | ||
disabled: false, | ||
}, | ||
argTypes: { | ||
accept: { | ||
control: { | ||
type: 'text', | ||
}, | ||
}, | ||
multiple: { | ||
control: { | ||
type: 'boolean', | ||
}, | ||
}, | ||
disabled: { | ||
control: { | ||
type: 'boolean', | ||
}, | ||
}, | ||
}, | ||
} satisfies Meta<typeof FileInput> | ||
|
||
export default meta | ||
|
||
type Story = StoryObj<typeof meta> | ||
|
||
export const Default: Story = {} | ||
|
||
export const Multiple: Story = { | ||
args: { multiple: true }, | ||
} | ||
|
||
export const Accept: Story = { | ||
args: { accept: 'application/pdf' }, | ||
} | ||
|
||
export const Disabled: Story = { | ||
args: { disabled: true }, | ||
} |