Skip to content

Commit

Permalink
Various fixes / improvements for datetime2 (#5370)
Browse files Browse the repository at this point in the history
  • Loading branch information
adidahiya authored Jun 14, 2022
1 parent 4991365 commit bb88c6c
Show file tree
Hide file tree
Showing 8 changed files with 62 additions and 60 deletions.
1 change: 0 additions & 1 deletion packages/datetime2/src/common/classes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,3 @@ export const DATE_INPUT_TIMEZONE_SELECT = `${NS}-date-input-timezone-select`;

export const TIMEZONE_SELECT = `${NS}-timezone-select`;
export const TIMEZONE_SELECT_POPOVER = `${TIMEZONE_SELECT}-popover`;
export const TIMEZONE_SELECT_TARGET = `${TIMEZONE_SELECT}-target`;
32 changes: 18 additions & 14 deletions packages/datetime2/src/components/date-input2/dateInput2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,15 @@ export interface DateInput2Props extends Omit<DateInputProps, "onChange" | "valu
value: string | null;

/**
* Whether to completely hide timezone elements.
* If `timePrecision` is undefined, this will always be true.
* Whether to show the timezone select dropdown on the right side of the input.
* If `timePrecision` is undefined, this will always be false.
*
* @default false
*/
hideTimezone?: boolean;
showTimezoneSelect?: boolean;

/**
* Whether to disable the timezone picker.
* Whether to disable the timezone select.
*
* @default false
*/
Expand All @@ -60,23 +62,23 @@ const timezoneSelectButtonProps: Partial<ButtonProps> = {
export const DateInput2: React.FC<DateInput2Props> = React.memo(function _DateInput2(props) {
const {
defaultTimezone,
value,
disabled,
disableTimezoneSelect,
onChange,
showTimezoneSelect,
timePrecision,
disableTimezoneSelect,
hideTimezone: hideTimezoneProp,
disabled,
...passThroughToDateInputProps
value,
...dateInputProps
} = props;

const [timezoneValue, updateTimezoneValue] = React.useState(defaultTimezone ?? getCurrentTimezone());
const hideTimezone = timePrecision === undefined ? true : hideTimezoneProp;
const dateValue = React.useMemo(() => getDateObjectFromIsoString(value, timezoneValue), [timezoneValue, value]);

const handleTimezoneChange = React.useCallback(
(newTimezone: string) => {
if (dateValue != null) {
onChange?.(getIsoEquivalentWithUpdatedTimezone(dateValue, newTimezone, timePrecision));
const newDateString = getIsoEquivalentWithUpdatedTimezone(dateValue, newTimezone, timePrecision);
onChange?.(newDateString);
}
updateTimezoneValue(newTimezone);
},
Expand All @@ -88,7 +90,8 @@ export const DateInput2: React.FC<DateInput2Props> = React.memo(function _DateIn
if (newDate == null) {
return;
}
onChange?.(getIsoEquivalentWithUpdatedTimezone(newDate, timezoneValue, timePrecision), isUserChange);
const newDateString = getIsoEquivalentWithUpdatedTimezone(newDate, timezoneValue, timePrecision);
onChange?.(newDateString, isUserChange);
},
[onChange, timezoneValue, timePrecision],
);
Expand All @@ -103,9 +106,10 @@ export const DateInput2: React.FC<DateInput2Props> = React.memo(function _DateIn
[timezoneValue, dateValue],
);

const isTimezoneSelectHidden = timePrecision === undefined || showTimezoneSelect === false;
const isTimezoneSelectDisabled = disabled || disableTimezoneSelect;

const maybeTimezonePicker = hideTimezone ? undefined : (
const maybeTimezonePicker = isTimezoneSelectHidden ? undefined : (
<TimezoneSelect
value={timezoneValue}
onChange={handleTimezoneChange}
Expand All @@ -126,7 +130,7 @@ export const DateInput2: React.FC<DateInput2Props> = React.memo(function _DateIn

return (
<DateInput
{...passThroughToDateInputProps}
{...dateInputProps}
value={dateValue}
onChange={handleDateChange}
timePrecision={timePrecision}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ import {
MenuItem,
Props,
} from "@blueprintjs/core";
import type { Popover2Props } from "@blueprintjs/popover2";
import { ItemListPredicate, ItemRenderer, Select2 } from "@blueprintjs/select";
import { ItemListPredicate, ItemRenderer, Select2, SelectPopoverProps } from "@blueprintjs/select";

import * as Classes from "../../common/classes";
import { TIMEZONE_ITEMS } from "../../common/timezoneItems";
Expand Down Expand Up @@ -111,7 +110,7 @@ export interface TimezoneSelectProps extends Props {
inputProps?: InputGroupProps2;

/** Props to spread to `Popover2`. Note that `content` cannot be changed. */
popoverProps?: Partial<Omit<Popover2Props, "content">>;
popoverProps?: SelectPopoverProps["popoverProps"];
}

export interface TimezoneSelectState {
Expand Down Expand Up @@ -169,7 +168,6 @@ export class TimezoneSelect extends AbstractPureComponent2<TimezoneSelectProps,
...popoverProps,
popoverClassName: classNames(Classes.TIMEZONE_SELECT_POPOVER, popoverProps?.popoverClassName),
}}
popoverTargetProps={{ className: Classes.TIMEZONE_SELECT_TARGET }}
resetOnClose={true}
resetOnSelect={true}
>
Expand Down
18 changes: 9 additions & 9 deletions packages/datetime2/test/components/dateInput2Tests.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,41 +53,41 @@ describe("<DateInput2>", () => {
it("Correctly passes on the default selected timezone", () => {
const defaultTimezone = "Europe/Paris";
const wrapper = mount(<DateInput2 {...DEFAULT_PROPS} defaultTimezone={defaultTimezone} />);
const timezonePicker = wrapper.find(TimezoneSelect);
const timezoneSelect = wrapper.find(TimezoneSelect);

assert.strictEqual(timezonePicker.prop("value"), defaultTimezone);
assert.strictEqual(timezoneSelect.prop("value"), defaultTimezone);
});

it("It updates the passed back string when timezone is changed", () => {
const wrapper = mount(<DateInput2 {...DEFAULT_PROPS} />);
const timezonePicker = wrapper.find(TimezoneSelect);
const timezoneSelect = wrapper.find(TimezoneSelect);
const newTimezone = "Europe/Paris";
timezonePicker.prop("onChange")(newTimezone);
timezoneSelect.prop("onChange")(newTimezone);

assert.isTrue(onChange.calledOnce);
assert.deepEqual(onChange.firstCall.args, ["2021-11-29T10:30:00.000+01:00"]);
});

it("It formats the string based on the time precision when timezone is changed", () => {
const wrapper = mount(<DateInput2 {...DEFAULT_PROPS} timePrecision={TimePrecision.MINUTE} />);
const timezonePicker = wrapper.find(TimezoneSelect);
const timezoneSelect = wrapper.find(TimezoneSelect);
const newTimezone = "Europe/Paris";
timezonePicker.prop("onChange")(newTimezone);
timezoneSelect.prop("onChange")(newTimezone);

assert.isTrue(onChange.calledOnce);
assert.deepEqual(onChange.firstCall.args, ["2021-11-29T10:30+01:00"]);
});

it("It updates the passed back string when time is changed", () => {
const wrapper = mount(<DateInput2 {...DEFAULT_PROPS} />);
const timezonePicker = wrapper.find(DateInput);
timezonePicker.prop("onChange")!(new Date("2021-11-29T11:30:00.000"), true);
const timezoneSelect = wrapper.find(DateInput);
timezoneSelect.prop("onChange")!(new Date("2021-11-29T11:30:00.000"), true);

assert.isTrue(onChange.calledOnce);
assert.deepEqual(onChange.firstCall.args, ["2021-11-29T11:30:00.000+00:00", true]);
});

it("Does not render a timezone picker not passed a precision", () => {
it("Does not render a timezone select if timePrecision is undefined", () => {
const wrapper = mount(<DateInput2 {...DEFAULT_PROPS} timePrecision={undefined} />);
assert.isFalse(wrapper.find(TimezoneSelect).exists());
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,26 @@ export interface DateInput2ExampleState {
closeOnSelection: boolean;
date: string | null;
disabled: boolean;
disableTimezoneSelect: boolean;
fill: boolean;
format: DateFormatProps;
reverseMonthAndYearMenus: boolean;
shortcuts: boolean;
showTimezoneSelect: boolean;
timePrecision: TimePrecision | undefined;
disableTimezonePicker: boolean;
hideTimezonePicker: boolean;
}

export class DateInput2Example extends React.PureComponent<IExampleProps, DateInput2ExampleState> {
public state: DateInput2ExampleState = {
closeOnSelection: true,
date: null,
disableTimezonePicker: false,
disableTimezoneSelect: false,
disabled: false,
fill: false,
format: FORMATS[0],
hideTimezonePicker: false,
reverseMonthAndYearMenus: false,
shortcuts: false,
showTimezoneSelect: true,
timePrecision: TimePrecision.MINUTE,
};

Expand All @@ -57,22 +57,22 @@ export class DateInput2Example extends React.PureComponent<IExampleProps, DateIn

private toggleDisabled = handleBooleanChange(disabled => this.setState({ disabled }));

private toggleHideTimezonePicker = handleBooleanChange(hideTimezonePicker => this.setState({ hideTimezonePicker }));
private toggleShowTimezoneSelect = handleBooleanChange(showTimezoneSelect => this.setState({ showTimezoneSelect }));

private toggleDisableTimezonePicker = handleBooleanChange(disableTimezonePicker =>
this.setState({ disableTimezonePicker }),
private toggleDisableTimezoneSelect = handleBooleanChange(disableTimezoneSelect =>
this.setState({ disableTimezoneSelect }),
);

private toggleFill = handleBooleanChange(fill => this.setState({ fill }));

private toggleReverseMenus = handleBooleanChange(reverse => this.setState({ reverseMonthAndYearMenus: reverse }));

private toggleTimePrecision = handleValueChange((timePrecision: TimePrecision | "none") =>
private handleTimePrecisionChange = handleValueChange((timePrecision: TimePrecision | "none") =>
this.setState({ timePrecision: timePrecision === "none" ? undefined : timePrecision }),
);

public render() {
const { date, format, timePrecision, hideTimezonePicker, disableTimezonePicker, ...spreadProps } = this.state;
const { date, format, timePrecision, ...spreadProps } = this.state;
return (
<Example options={this.renderOptions()} {...this.props}>
<DateInput2
Expand All @@ -82,8 +82,6 @@ export class DateInput2Example extends React.PureComponent<IExampleProps, DateIn
popoverProps={{ position: Position.BOTTOM }}
timePrecision={timePrecision}
value={date}
hideTimezone={hideTimezonePicker}
disableTimezoneSelect={disableTimezonePicker}
/>
{date}
</Example>
Expand All @@ -99,34 +97,37 @@ export class DateInput2Example extends React.PureComponent<IExampleProps, DateIn
format,
timePrecision,
shortcuts,
disableTimezonePicker,
hideTimezonePicker,
disableTimezoneSelect,
showTimezoneSelect,
} = this.state;
return (
<>
<H5>Props</H5>
<Switch label="Close on selection" checked={closeOnSelection} onChange={this.toggleSelection} />
<Switch checked={shortcuts} label="Show shortcuts" onChange={this.toggleShortcuts} />
<PrecisionSelect
allowNone={true}
label="Time precision"
onChange={this.handleTimePrecisionChange}
value={timePrecision}
/>

<H5>Appearance props</H5>
<Switch label="Disabled" checked={disabled} onChange={this.toggleDisabled} />
<Switch label="Fill" checked={fill} onChange={this.toggleFill} />
<Switch label="Reverse month and year menus" checked={reverse} onChange={this.toggleReverseMenus} />
<FormatSelect format={format} onChange={this.handleFormatChange} />

<H5>Timezone props</H5>
<Switch
label="Disable timezone picker"
checked={disableTimezonePicker}
onChange={this.toggleDisableTimezonePicker}
label="Disable timezone select"
checked={disableTimezoneSelect}
onChange={this.toggleDisableTimezoneSelect}
/>
<Switch
label="Hide timezone picker"
checked={hideTimezonePicker}
onChange={this.toggleHideTimezonePicker}
/>

<FormatSelect format={format} onChange={this.handleFormatChange} />
<PrecisionSelect
allowNone={true}
label="Time precision"
onChange={this.toggleTimePrecision}
value={timePrecision}
label="Show timezone select"
checked={showTimezoneSelect}
onChange={this.toggleShowTimezoneSelect}
/>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export class TimezonePickerExample extends React.PureComponent<IExampleProps, IT
</>
);

/* eslint-disable deprecation/deprecation */
return (
<Example options={options} {...this.props}>
<TimezonePicker
Expand All @@ -86,6 +87,7 @@ export class TimezonePickerExample extends React.PureComponent<IExampleProps, IT
</TimezonePicker>
</Example>
);
/* eslint-enable deprecation/deprecation */
}

private renderCustomTarget() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ export interface ITimezonePickerState {
// eslint-disable-next-line deprecation/deprecation
const TypedSelect = Select.ofType<TimezoneItem>();

/** @deprecated use { TimezoneSelect } from "@blueprintjs/datetime2" */
export class TimezonePicker extends AbstractPureComponent2<TimezonePickerProps, ITimezonePickerState> {
public static displayName = `${DISPLAYNAME_PREFIX}.TimezonePicker`;

Expand Down
7 changes: 2 additions & 5 deletions packages/timezone/test/timezonePickerTests.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const shallow = (
options?: ShallowRendererProps,
): TimezonePickerShallowWrapper => untypedShallow<TimezonePicker>(el, options);

const VALUE = "America/Los_Angeles";
/* eslint-disable deprecation/deprecation */

describe("<TimezonePicker>", () => {
const onChange = sinon.spy();
Expand All @@ -60,7 +60,7 @@ describe("<TimezonePicker>", () => {
isOpen: true,
usePortal: false,
},
value: VALUE,
value: "America/Los_Angeles",
};

afterEach(() => onChange.resetHistory());
Expand All @@ -69,7 +69,6 @@ describe("<TimezonePicker>", () => {
// remove isOpen from popoverProps so it's
const timezonePicker = mount(<TimezonePicker {...DEFAULT_PROPS} popoverProps={{ usePortal: false }} />);
timezonePicker.find(Button).simulate("click");
/* eslint-disable-next-line deprecation/deprecation */
assert.isTrue(timezonePicker.find(Popover).prop("isOpen"));
});

Expand All @@ -78,7 +77,6 @@ describe("<TimezonePicker>", () => {
<TimezonePicker {...DEFAULT_PROPS} disabled={true} popoverProps={{ usePortal: false }} />,
);
timezonePicker.find(Button).simulate("click");
/* eslint-disable-next-line deprecation/deprecation */
assert.isFalse(timezonePicker.find(Popover).prop("isOpen"));
});

Expand Down Expand Up @@ -244,7 +242,6 @@ describe("<TimezonePicker>", () => {
}

function findPopover(timezonePicker: TimezonePickerShallowWrapper) {
/* eslint-disable-next-line deprecation/deprecation */
return findQueryList(timezonePicker).shallow().find(Popover);
}

Expand Down

1 comment on commit bb88c6c

@blueprint-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Various fixes / improvements for datetime2 (#5370)

Previews: documentation | landing | table | demo

Please sign in to comment.