Skip to content

Commit

Permalink
feat: APP-2730 - Implement InputDate component (#55)
Browse files Browse the repository at this point in the history
  • Loading branch information
cgero-eth authored Jan 22, 2024
1 parent 9ce9d61 commit 5f38ab1
Show file tree
Hide file tree
Showing 13 changed files with 145 additions and 4 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
### Fixed

- Minimum `tailwindcss` version required
- Fix disabled input style on Firefox

### Added

- Implement `InputDate` component

## [1.0.8] - 2024-01-17

Expand Down
3 changes: 2 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ const config = {
setupFilesAfterEnv: ['<rootDir>/src/test/setup.ts'],
transform: {
'^.+\\.svg$': '<rootDir>/src/test/svgTransform.js',
'^.+\\.tsx?$': 'ts-jest',
'^.+\\.m?[tj]sx?$': 'ts-jest',
},
transformIgnorePatterns: ['node_modules/(?!(.*\\.mjs$|react-merge-refs))'],
};

module.exports = config;
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@
"@radix-ui/react-toggle-group": "^1.0.0",
"classnames": "^2.0.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
"react-dom": "^18.0.0",
"react-merge-refs": "^2.0.0"
},
"peerDependencies": {
"tailwindcss": "^3.4.0"
Expand Down
1 change: 1 addition & 0 deletions src/components/input/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './inputContainer';
export * from './inputDate';
export * from './inputSearch';
export * from './inputText';
1 change: 1 addition & 0 deletions src/components/input/inputDate/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { InputDate, type IInputDateProps } from './inputDate';
25 changes: 25 additions & 0 deletions src/components/input/inputDate/inputDate.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { Meta, StoryObj } from '@storybook/react';
import { InputDate } from './inputDate';

const meta: Meta<typeof InputDate> = {
title: 'components/Input/InputDate',
component: InputDate,
tags: ['autodocs'],
parameters: {
design: {
type: 'figma',
url: 'https://www.figma.com/file/jfKRr1V9evJUp1uBeyP3Zz/v1.0.0?type=design&node-id=10080-1466&mode=design&t=2bLCEeKZ7ueBboTs-4',
},
},
};

type Story = StoryObj<typeof InputDate>;

/**
* Default usage example of the InputDate component.
*/
export const Default: Story = {
args: {},
};

export default meta;
51 changes: 51 additions & 0 deletions src/components/input/inputDate/inputDate.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { fireEvent, render, screen, within } from '@testing-library/react';
import React from 'react';
import * as MergeRefs from 'react-merge-refs';
import { IconType } from '../../icon';
import { InputDate, type IInputDateProps } from './inputDate';

describe('<InputDate /> component', () => {
const useRefMock = jest.spyOn(React, 'useRef');
const mergeRefMock = jest.spyOn(MergeRefs, 'mergeRefs');

afterEach(() => {
useRefMock.mockReset();
mergeRefMock.mockReset();
});

const createTestComponent = (props?: Partial<IInputDateProps>) => {
const completeProps = { ...props };

return <InputDate {...completeProps} />;
};

it('renders a date input', () => {
const label = 'Date label';
render(createTestComponent({ label }));
const dateInput = screen.getByLabelText<HTMLInputElement>(label);
expect(dateInput).toBeInTheDocument();
expect(dateInput.type).toEqual('date');
});

it('renders the input as disabled when the isDisabled property is set to true', () => {
const isDisabled = true;
const label = 'test';
render(createTestComponent({ label, isDisabled }));
expect(screen.getByLabelText(label)).toBeDisabled();
expect(screen.getByRole('button')).toBeDisabled();
});

it('renders a button which opens the date picker on click', () => {
const showPicker = jest.fn();
useRefMock.mockReturnValue({ current: { showPicker } });
mergeRefMock.mockReturnValue(() => null);
render(createTestComponent());

const calendarButton = screen.getByRole('button');
expect(calendarButton).toBeInTheDocument();
expect(within(calendarButton).getByTestId(IconType.CALENDAR)).toBeInTheDocument();

fireEvent.click(calendarButton);
expect(showPicker).toHaveBeenCalled();
});
});
46 changes: 46 additions & 0 deletions src/components/input/inputDate/inputDate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import classNames from 'classnames';
import { forwardRef, useRef } from 'react';
import { mergeRefs } from 'react-merge-refs';
import { Button } from '../../button';
import { IconType } from '../../icon';
import { InputContainer, type IInputComponentProps } from '../inputContainer';
import { useInputProps } from '../useInputProps';

export interface IInputDateProps extends Omit<IInputComponentProps, 'maxLength'> {}

export const InputDate: React.FC<IInputDateProps> = forwardRef((props, ref) => {
const { containerProps, inputProps } = useInputProps(props);

const { className: containerClassName, ...otherContainerProps } = containerProps;
const { className: inputClassName, disabled, ...otherInputProps } = inputProps;

const inputRef = useRef<HTMLInputElement>(null);

const handleCalendarClick = () => {
inputRef.current?.showPicker();
};

return (
// Using absolute and relative positions to hide native date-picker icon on Firefox as it cannot be customised
// (see Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1812397)
<InputContainer className={classNames('relative', containerClassName)} {...otherContainerProps}>
<input
type="date"
className={classNames('absolute calendar-icon:hidden calendar-icon:appearance-none', inputClassName)}
ref={mergeRefs([inputRef, ref])}
disabled={disabled}
{...otherInputProps}
/>
<Button
variant="tertiary"
size="sm"
iconLeft={IconType.CALENDAR}
className="absolute right-2"
onClick={handleCalendarClick}
state={disabled ? 'disabled' : undefined}
/>
</InputContainer>
);
});

InputDate.displayName = 'InputDate';
2 changes: 1 addition & 1 deletion src/components/input/inputSearch/inputSearch.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const meta: Meta<typeof InputSearch> = {
parameters: {
design: {
type: 'figma',
url: 'https://www.figma.com/file/jfKRr1V9evJUp1uBeyP3Zz/v1.0.0?type=design&node-id=17-292&mode=design&t=dehPZplRn0YEdOuB-4',
url: 'https://www.figma.com/file/jfKRr1V9evJUp1uBeyP3Zz/v1.0.0?type=design&node-id=8199-17879&mode=design&t=2bLCEeKZ7ueBboTs-4',
},
},
};
Expand Down
2 changes: 1 addition & 1 deletion src/components/input/useInputProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export const useInputProps = (props: IInputComponentProps): IUseInputPropsResult
};

const inputClasses = classNames(
'size-full rounded-xl px-4 py-3 caret-neutral-500 outline-none', // Default
'size-full rounded-xl bg-transparent px-4 py-3 caret-neutral-500 outline-none', // Default
'placeholder:text-base placeholder:font-normal placeholder:leading-tight placeholder:text-neutral-300', // Placeholder
inputClassName, // Prop
);
Expand Down
3 changes: 3 additions & 0 deletions src/styles/primitives/colors.css
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,7 @@
--ods-color-critical-700: #b31b35;
--ods-color-critical-800: #901132;
--ods-color-critical-900: #770a30;

/* Transparent */
--ods-color-transparent: transparent;
}
2 changes: 2 additions & 0 deletions tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ module.exports = {
800: 'var(--ods-color-critical-800)',
900: 'var(--ods-color-critical-900)',
},
transparent: 'var(--ods-color-transparent)',
},
spacing: {
0: 'var(--ods-space-0)', // 0px
Expand Down Expand Up @@ -223,6 +224,7 @@ module.exports = {
plugins: [
require('tailwindcss/plugin')(({ addVariant }) => {
addVariant('search-cancel', '&::-webkit-search-cancel-button');
addVariant('calendar-icon', ['&::-webkit-calendar-picker-indicator', '&::-webkit-inner-spin-button']);
}),
],
};
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9527,6 +9527,11 @@ react-is@^18.0.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==

react-merge-refs@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/react-merge-refs/-/react-merge-refs-2.1.1.tgz#e46763f8f1b881c0226ee54a1a2a10ffefba0233"
integrity sha512-jLQXJ/URln51zskhgppGJ2ub7b2WFKGq3cl3NYKtlHoTG+dN2q7EzWrn3hN3EgPsTMvpR9tpq5ijdp7YwFZkag==

react-refresh@^0.14.0:
version "0.14.0"
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e"
Expand Down

0 comments on commit 5f38ab1

Please sign in to comment.