Skip to content

Commit

Permalink
feat(project): add datefield component
Browse files Browse the repository at this point in the history
  • Loading branch information
RCVZ committed Jul 27, 2021
1 parent 23e2ef3 commit 6a6aedc
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 0 deletions.
82 changes: 82 additions & 0 deletions src/components/DateField/DateField.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
@use '../../styles/variables';
@use '../../styles/theme';

.dateField {
width: 100%;
margin-bottom: 8px;

&.error {
.helperText {
color: theme.$text-field-error-color;
}

.container {
border-color: theme.$text-field-error-color;
}
}

&.disabled {
.container {
opacity: 0.7;
}
}

&:hover {
&:not(.disabled) {
.container {
background-color: theme.$text-field-hover-bg-color;
border-color: theme.$text-field-hover-border-color;
}
}
}
}

.label {
display: block;
margin-bottom: 4px;
font-family: theme.$body-font-family;
font-weight: 700;
text-align: left;
}

.control > div {
width: 48px;
height: 48px;
}

.container {
display: flex;
width: 100%;

color: theme.$text-field-resting-color;

background-color: theme.$text-field-bg-color;
border: 1px solid theme.$text-field-resting-border-color;
border-radius: 4px;
transition: border 0.2s ease;

&:focus-within {
color: theme.$text-field-active-color;
border-color: theme.$text-field-active-border-color;
}
}

.input {
width: 100%;
min-height: 48px;
padding: 14px 16px;
color: inherit;
font-size: 16px;
line-height: 18px;
background: transparent;
border: none;
outline: none;
appearance: none;
}

.helperText {
margin-top: 4px;
font-family: theme.$body-font-family;
font-size: 12px;
text-align: left;
}
73 changes: 73 additions & 0 deletions src/components/DateField/DateField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import React from 'react';
import classNames from 'classnames';

import useOpaqueId from '../../hooks/useOpaqueId';

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

type Props = {
className?: string;
label?: string;
placeholder?: string;
name?: string;
value: string;
onChange?: React.ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement>;
onFocus?: React.ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement>;
helperText?: React.ReactNode;
error?: boolean;
};

const DateField: React.FC<Props> = ({
className,
label,
error,
helperText,

...rest
}: Props) => {
const id = useOpaqueId('text-field', rest.name);

const DateFieldClassName = classNames(
styles.dateField,
{
[styles.error]: error,
},
className,
);

const formatDate = (event: React.KeyboardEvent) => {
const format: string = 'mm/dd/yyyy';
if (!event.ctrlKey && !event.metaKey && (event.keyCode == 32 || event.keyCode > 46)) {
const target: Partial<HTMLTextAreaElement> = event.target;

const match = new RegExp(
format
.replace(/(\w+)\W(\w+)\W(\w+)/, '^\\s*($1)\\W*($2)?\\W*($3)?([0-9]*).*')
.replace(/mm|dd/g, '\\d{2}')
.replace(/yy/g, '\\d{4}'),
);
const replacer = format.match(/\W/) as unknown as string;
if (!target.value) return;

const replace = '$1/$2/$3$4'.replace(/\//g, replacer);
target.value = target.value
.replace(/(^|\W)(?=\d\W)/g, '$10') // padding
.replace(match, replace) // fields
.replace(/(\W)+/g, '$1'); // remove repeats}
}
};

return (
<div className={DateFieldClassName}>
<label htmlFor={id} className={styles.label}>
{label}
</label>
<div className={styles.container}>
<input className={styles.input} onKeyUp={formatDate} maxLength={10} type="text" id={id} {...rest} />
</div>
{helperText ? <div className={styles.helperText}>{helperText}</div> : null}
</div>
);
};

export default DateField;

0 comments on commit 6a6aedc

Please sign in to comment.