Skip to content

Commit

Permalink
Merge pull request #42 from fortanix/datepicker
Browse files Browse the repository at this point in the history
Datepicker
  • Loading branch information
nighto authored Dec 18, 2024
2 parents 790f1d5 + 7ac4cd4 commit d683455
Show file tree
Hide file tree
Showing 19 changed files with 862 additions and 5 deletions.
4 changes: 4 additions & 0 deletions app/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,20 @@ export { SubmitButton } from '../src/components/forms/context/SubmitButton/Submi

// Forms > Controls
export { Checkbox } from '../src/components/forms/controls/Checkbox/Checkbox.tsx';
export { DatePicker } from '../src/components/forms/controls/DatePicker/DatePicker.tsx';
export { DatePickerRange } from '../src/components/forms/controls/DatePickerRange/DatePickerRange.tsx';
export { Input } from '../src/components/forms/controls/Input/Input.tsx';
export { Radio } from '../src/components/forms/controls/Radio/Radio.tsx';
export { SegmentedControl } from '../src/components/forms/controls/SegmentedControl/SegmentedControl.tsx';
export { Select } from '../src/components/forms/controls/Select/Select.tsx';
export { Switch } from '../src/components/forms/controls/Switch/Switch.tsx';
export { TimePicker } from '../src/components/forms/controls/TimePicker/TimePicker.tsx';

// Forms > Fields
export { CheckboxField } from '../src/components/forms/fields/CheckboxField/CheckboxField.tsx';
export { CheckboxGroup } from '../src/components/forms/fields/CheckboxGroup/CheckboxGroup.tsx';
export { InputField } from '../src/components/forms/fields/InputField/InputField.tsx';
export { InputFieldWithTags } from '../src/components/forms/fields/InputFieldWithTags/InputFieldWithTags.tsx';
export { RadioField } from '../src/components/forms/fields/RadioField/RadioField.tsx';
export { RadioGroup } from '../src/components/forms/fields/RadioGroup/RadioGroup.tsx';

Expand Down
49 changes: 45 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@
"react-toastify": "^10.0.6",
"effect": "^3.11.3",
"react-hook-form": "^7.54.0",
"optics-ts": "^2.4.1"
"optics-ts": "^2.4.1",
"react-datepicker": "^7.5.0"
},
"peerDependencies": {
"react": ">= 19.0.0",
Expand All @@ -118,6 +119,10 @@
"@storybook/icons": {
"react": "$react",
"react-dom": "$react-dom"
},
"react-datepicker": {
"react": "$react",
"react-dom": "$react-dom"
}
}
}
6 changes: 6 additions & 0 deletions package.json.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ const packageConfig = {
'react-hook-form': '^7.54.0',

'optics-ts': '^2.4.1',
"react-datepicker": "^7.5.0",
},
peerDependencies: {
'react': '>= 19.0.0',
Expand All @@ -171,6 +172,11 @@ const packageConfig = {
'react': '$react',
'react-dom': '$react-dom',
},
// Issue: https://github.com/Hacker0x01/react-datepicker/issues/5273
'react-datepicker': {
'react': '$react',
'react-dom': '$react-dom',
},
},
};

Expand Down
37 changes: 37 additions & 0 deletions src/components/forms/controls/DatePicker/DatePicker.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/* Copyright (c) Fortanix, Inc.
|* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
|* the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */

@use '../../../../styling/defs.scss' as bk;
@use '../../../../styling/lib/react-datepicker.scss';

@layer baklava.components {
$caret-width: bk.rem-from-px(18);

.bk-date-picker {
@include bk.component-base(bk-date-picker);
display: flex;
flex-direction: row;
align-items: center;
margin-right: -$caret-width;
}

.bk-date-picker--input {
width: bk.rem-from-px(134);
color: bk.$theme-form-text-default;
}

.bk-date-picker--caret {
width: $caret-width;
height: $caret-width;
position: relative;
left: -$caret-width;
top: bk.rem-from-px(-1);
}

.bk-date-picker--caret__down {
// only when the date picker is closed, allow click on caret to pass through the input behind it;
// if it is open, then we don't, so it counts as a click outside of the input and date picker, which closes it.
pointer-events: none;
}
}
63 changes: 63 additions & 0 deletions src/components/forms/controls/DatePicker/DatePicker.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/* Copyright (c) Fortanix, Inc.
|* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
|* the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import type { Meta, StoryObj } from '@storybook/react';

import * as React from 'react';

import { DatePicker } from './DatePicker.tsx';


type DatePickerArgs = React.ComponentProps<typeof DatePicker>;
type Story = StoryObj<DatePickerArgs>;

export default {
component: DatePicker,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
},
args: {},
decorators: [
Story => <form onSubmit={event => { event.preventDefault(); }}><Story/></form>,
],
} satisfies Meta<DatePickerArgs>;

export const Standard: Story = {
render: (args) => {
const [startDate, setStartDate] = React.useState<Date | null>(new Date(2024, 11, 12, 9, 41));

return (
// with a fixed height to avoid hiding the bottom part of the calendar
<div style={{height: '500px'}}>
<DatePicker
{...args}
selected={startDate}
onChange={(date: Date | null) => { setStartDate(date) }}
/>
<p>Date selected: {startDate?.toDateString()}</p>
</div>
);
}
};

export const DateNotSet: Story = {
render: (args) => {
const [startDate, setStartDate] = React.useState<Date | null>(null);

return (
// with a fixed height to avoid hiding the bottom part of the calendar
<div style={{height: '500px'}}>
<DatePicker
{...args}
selected={startDate}
onChange={(date: Date | null) => { setStartDate(date) }}
/>
<p>Date selected: {startDate?.toDateString()}</p>
</div>
);
}
};
78 changes: 78 additions & 0 deletions src/components/forms/controls/DatePicker/DatePicker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/* Copyright (c) Fortanix, Inc.
|* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
|* the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import * as React from 'react';
import ReactDatePicker from 'react-datepicker';

import { classNames as cx, type ClassNameArgument, type ComponentProps } from '../../../../util/componentUtil.ts';

import { Icon } from '../../../graphics/Icon/Icon.tsx';
import { Input } from '../Input/Input.tsx';

import 'react-datepicker/dist/react-datepicker.css';
import cl from './DatePicker.module.scss';


type GenericProps = {
/** Whether this component should be unstyled. */
unstyled?: undefined | boolean,

/** An optional class name to be appended to the class list. */
className?: undefined | ClassNameArgument,
};

type ReactDatePickerProps = Omit<ComponentProps<typeof ReactDatePicker>, 'onChange'> & {
// Note: need to disable the following features in order to use `ReactDatePicker` as a plain date picker.
selectsRange?: never,
selectsMultiple?: never,
showMonthYearDropdown?: never,
onChange: ((date: Date | null, event?: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>) => void),
selected: Date | null,
};

export type DatePickerProps = GenericProps & ReactDatePickerProps;

export const DatePicker = (props: DatePickerProps) => {
const {
unstyled = false,
className,
dateFormat = 'MM/dd/yyyy',
placeholderText = 'MM/DD/YYYY',
...propsRest
} = props;

const [isOpen, setIsOpen] = React.useState<boolean>(false);

return (
<div className={cx(
'bk',
{ [cl['bk-date-picker']]: !unstyled },
className,
)}>
<ReactDatePicker
dateFormat={dateFormat}
placeholderText={placeholderText}
showIcon
icon={<Icon icon="calendar"/>}
customInput={
<Input className={cx(
{ [cl['bk-date-picker--input']]: !unstyled },
)}/>
}
onCalendarClose={() => setIsOpen(false)}
onCalendarOpen={() => setIsOpen(true)}
{...propsRest}
selected={props.selected}
onChange={props.onChange}
/>
<Icon
className={cx(
cl['bk-date-picker--caret'],
{ [cl['bk-date-picker--caret__down']]: !isOpen },
)}
icon={`caret-${isOpen ? 'up' : 'down'}`}
/>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* Copyright (c) Fortanix, Inc.
|* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
|* the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */

@use '../../../../styling/defs.scss' as bk;
@use '../../../../styling/lib/react-datepicker.scss';

@layer baklava.components {
.bk-date-picker-range {
@include bk.component-base(bk-date-picker-range);
display: flex;
flex-direction: row;
align-items: center;
}

.bk-date-picker-range--input {
width: bk.rem-from-px(134);
color: bk.$theme-form-text-default;
}
}
Loading

0 comments on commit d683455

Please sign in to comment.