-
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: Aram <[email protected]>
- Loading branch information
Showing
11 changed files
with
255 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
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,11 @@ | ||
<!-- @license CC0-1.0 --> | ||
|
||
# Time Input | ||
|
||
Helps users enter time. | ||
|
||
## Visual considerations | ||
|
||
This component uses a native time input, which is styled differently in different browsers and operating systems. | ||
Recreating the native functionality is quite difficult and prone to accessibility errors, which is why we’ve chosen not to do that. | ||
This does mean that this component does not look identical on all 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,79 @@ | ||
/** | ||
* @license EUPL-1.2+ | ||
* Copyright Gemeente Amsterdam | ||
*/ | ||
|
||
@import "../../common/text-rendering"; | ||
|
||
@mixin reset { | ||
// Reset native appearance, this causes issues on iOS and Android devices | ||
-webkit-appearance: none; | ||
appearance: none; | ||
border: 0; | ||
border-radius: 0; // Reset rounded borders on iOS devices | ||
box-sizing: border-box; | ||
margin-block: 0; | ||
width: auto; // Reset width of 10em set by Android devices | ||
} | ||
|
||
.ams-time-input { | ||
background-color: var(--ams-time-input-background-color); | ||
box-shadow: var(--ams-time-input-box-shadow); | ||
color: var(--ams-time-input-color); | ||
font-family: var(--ams-time-input-font-family); | ||
font-size: var(--ams-time-input-font-size); | ||
font-weight: var(--ams-time-input-font-weight); | ||
line-height: var(--ams-time-input-line-height); | ||
|
||
// Set min height for iOS, otherwise an empty box is a lot smaller than a filled one. | ||
min-height: calc( | ||
(var(--ams-time-input-font-size) * var(--ams-time-input-line-height)) + 2 * var(--ams-time-input-padding-block) | ||
); | ||
|
||
// Set min width for iOS, so the width is closer to the filled in width. | ||
min-width: calc(4ch + (2 * var(--ams-time-input-padding-inline))); | ||
outline-offset: var(--ams-time-input-outline-offset); | ||
padding-block: var(--ams-time-input-padding-block); | ||
padding-inline: var(--ams-time-input-padding-inline); | ||
touch-action: manipulation; | ||
|
||
@include text-rendering; | ||
@include reset; | ||
|
||
&:hover { | ||
box-shadow: var(--ams-time-input-hover-box-shadow); | ||
} | ||
} | ||
|
||
// This changes the default calendar icon on Chromium browsers only | ||
.ams-time-input::-webkit-calendar-picker-indicator { | ||
appearance: none; | ||
background-image: var(--ams-time-input-calender-picker-indicator-background-image); | ||
cursor: pointer; | ||
} | ||
|
||
.ams-time-input:hover::-webkit-calendar-picker-indicator { | ||
background-image: var(--ams-time-input-hover-calender-picker-indicator-background-image); | ||
} | ||
|
||
.ams-time-input:disabled { | ||
background-color: var(--ams-time-input-disabled-background-color); | ||
box-shadow: var(--ams-time-input-disabled-box-shadow); | ||
color: var(--ams-time-input-disabled-color); | ||
cursor: not-allowed; | ||
} | ||
|
||
.ams-time-input:disabled::-webkit-calendar-picker-indicator { | ||
background-image: var(--ams-time-input-disabled-calender-picker-indicator-background-image); | ||
visibility: visible; | ||
} | ||
|
||
.ams-time-input:invalid, | ||
.ams-time-input[aria-invalid="true"] { | ||
box-shadow: var(--ams-time-input-invalid-box-shadow); | ||
|
||
&:hover { | ||
// TODO: this should be the (currently non-existent) dark red hover color | ||
box-shadow: var(--ams-time-input-invalid-hover-box-shadow); | ||
} | ||
} |
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 Time Input component | ||
|
||
[Time Input documentation](../../../css/src/components/time-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,41 @@ | ||
import { render } from '@testing-library/react' | ||
import { createRef } from 'react' | ||
import { TimeInput } from './TimeInput' | ||
import '@testing-library/jest-dom' | ||
|
||
describe('Time input', () => { | ||
it('renders', () => { | ||
const { container } = render(<TimeInput />) | ||
|
||
const component = container.querySelector(':only-child') | ||
|
||
expect(component).toBeInTheDocument() | ||
expect(component).toBeVisible() | ||
}) | ||
|
||
it('renders a design system BEM class name', () => { | ||
const { container } = render(<TimeInput />) | ||
|
||
const component = container.querySelector(':only-child') | ||
|
||
expect(component).toHaveClass('ams-time-input') | ||
}) | ||
|
||
it('renders an additional class name', () => { | ||
const { container } = render(<TimeInput className="extra" />) | ||
|
||
const component = container.querySelector(':only-child') | ||
|
||
expect(component).toHaveClass('ams-time-input extra') | ||
}) | ||
|
||
it('supports ForwardRef in React', () => { | ||
const ref = createRef<HTMLInputElement>() | ||
|
||
const { container } = render(<TimeInput ref={ref} />) | ||
|
||
const component = container.querySelector(':only-child') | ||
|
||
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 TimeInputProps = InputHTMLAttributes<HTMLInputElement> | ||
|
||
export const TimeInput = forwardRef( | ||
({ className, ...restProps }: TimeInputProps, ref: ForwardedRef<HTMLInputElement>) => ( | ||
<input {...restProps} ref={ref} className={clsx('ams-time-input', className)} type="time" /> | ||
), | ||
) | ||
|
||
TimeInput.displayName = 'TimeInput' |
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 { TimeInput } from './TimeInput' | ||
export type { TimeInputProps } from './TimeInput' |
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
45 changes: 45 additions & 0 deletions
45
proprietary/tokens/src/components/ams/time-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,45 @@ | ||
{ | ||
"ams": { | ||
"time-input": { | ||
"background-color": { "value": "{ams.color.primary-white}" }, | ||
"box-shadow": { "value": "inset 0 0 0 {ams.border.width.sm} {ams.color.primary-black}" }, | ||
"color": { "value": "{ams.color.primary-black}" }, | ||
"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.xs}" }, | ||
"padding-inline": { "value": "{ams.space.inside.md}" }, | ||
"calender-picker-indicator": { | ||
"background-image": { | ||
"value": "url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32' fill='%23004699'><path d='M16 0C7.163 0 0 7.163 0 16s7.163 16 16 16 16-7.163 16-16A16 16 0 0 0 16 0zm.9 28v-2h-2v1.9A11.8 11.8 0 0 1 4.1 17H6v-2H4.1A11.8 11.8 0 0 1 15 4.1V6h2V4.1A11.8 11.8 0 0 1 27.9 15H26v2h1.9a11.9 11.9 0 0 1-11 11zm.1-13h4v2h-6V9h2v6z'/></svg>\")" | ||
} | ||
}, | ||
"disabled": { | ||
"background-color": { "value": "{ams.color.primary-white}" }, | ||
"box-shadow": { "value": "inset 0 0 0 {ams.border.width.sm} {ams.color.neutral-grey2}" }, | ||
"color": { "value": "{ams.color.neutral-grey2}" }, | ||
"calender-picker-indicator": { | ||
"background-image": { | ||
"value": "url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32' fill='%23BEBEBE'><path d='M16 0C7.163 0 0 7.163 0 16s7.163 16 16 16 16-7.163 16-16A16 16 0 0 0 16 0zm.9 28v-2h-2v1.9A11.8 11.8 0 0 1 4.1 17H6v-2H4.1A11.8 11.8 0 0 1 15 4.1V6h2V4.1A11.8 11.8 0 0 1 27.9 15H26v2h1.9a11.9 11.9 0 0 1-11 11zm.1-13h4v2h-6V9h2v6z'/></svg>\")" | ||
} | ||
} | ||
}, | ||
"hover": { | ||
"box-shadow": { "value": "inset 0 0 0 {ams.border.width.md} {ams.color.primary-black}" }, | ||
"calender-picker-indicator": { | ||
"background-image": { | ||
"value": "url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32' fill='%23102E62'><path d='M16 0C7.163 0 0 7.163 0 16s7.163 16 16 16 16-7.163 16-16A16 16 0 0 0 16 0zm.9 28v-2h-2v1.9A11.8 11.8 0 0 1 4.1 17H6v-2H4.1A11.8 11.8 0 0 1 15 4.1V6h2V4.1A11.8 11.8 0 0 1 27.9 15H26v2h1.9a11.9 11.9 0 0 1-11 11zm.1-13h4v2h-6V9h2v6z'/></svg>\")" | ||
} | ||
} | ||
}, | ||
"invalid": { | ||
"box-shadow": { "value": "inset 0 0 0 {ams.border.width.sm} {ams.color.primary-red}" }, | ||
"hover": { | ||
"box-shadow": { "value": "inset 0 0 0 {ams.border.width.md} {ams.color.primary-red}" } | ||
} | ||
} | ||
} | ||
} | ||
} |
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,19 @@ | ||
import { Canvas, Controls, Markdown, Meta, Primary } from "@storybook/blocks"; | ||
import * as TimeInputStories from "./TimeInput.stories.tsx"; | ||
import README from "../../../../packages/css/src/components/time-input/README.md?raw"; | ||
|
||
<Meta of={TimeInputStories} /> | ||
|
||
<Markdown>{README}</Markdown> | ||
|
||
<Primary /> | ||
|
||
<Controls /> | ||
|
||
## Invalid | ||
|
||
<Canvas of={TimeInputStories.Invalid} /> | ||
|
||
## Disabled | ||
|
||
<Canvas of={TimeInputStories.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,33 @@ | ||
/** | ||
* @license EUPL-1.2+ | ||
* Copyright Gemeente Amsterdam | ||
*/ | ||
|
||
import { TimeInput } from '@amsterdam/design-system-react/src' | ||
import { Meta, StoryObj } from '@storybook/react' | ||
|
||
const meta = { | ||
title: 'Components/Forms/Time Input', | ||
component: TimeInput, | ||
args: { | ||
disabled: false, | ||
}, | ||
} satisfies Meta<typeof TimeInput> | ||
|
||
export default meta | ||
|
||
type Story = StoryObj<typeof meta> | ||
|
||
export const Default: Story = {} | ||
|
||
export const Invalid: Story = { | ||
args: { | ||
required: true, | ||
}, | ||
} | ||
|
||
export const Disabled: Story = { | ||
args: { | ||
disabled: true, | ||
}, | ||
} |