Skip to content

Commit

Permalink
[datetime2] feat(DateInput2): remove target wrapper, fix fill prop (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
adidahiya authored Aug 1, 2022
1 parent 7fed494 commit cec40f7
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 30 deletions.
7 changes: 7 additions & 0 deletions packages/datetime2/src/blueprint-datetime2.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@
@import "~@blueprintjs/colors/lib/scss/colors";
@import "~@blueprintjs/core/src/common/variables";

.#{$ns}-datepicker-timepicker-wrapper {
// Ensure some padding around the timepicker elements. We need this when precision="millisecond" and
// useAmPm={true} - all four inputs and an HTMLSelect are rendered, which results in the timepicker
// being slightly wider than the datepicker. Without this padding, things look a bit too cramped.
padding: 0 2px;
}

.#{$ns}-timezone-select-popover {
min-width: 370px;
}
Expand Down
82 changes: 57 additions & 25 deletions packages/datetime2/src/components/date-input2/dateInput2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import {
DatePickerShortcut,
DatePickerUtils,
} from "@blueprintjs/datetime";
import { Popover2, Popover2Props } from "@blueprintjs/popover2";
import { Popover2, Popover2Props, Popover2TargetProps } from "@blueprintjs/popover2";

import * as Classes from "../../common/classes";
import { isDateValid, isDayInRange } from "../../common/dateUtils";
Expand Down Expand Up @@ -196,6 +196,7 @@ export const DateInput2: React.FC<DateInput2Props> = React.memo(function _DateIn
defaultTimezone,
defaultValue,
disableTimezoneSelect,
fill,
inputProps = {},
// defaults duplicated here for TypeScript convenience
maxDate = DEFAULT_MAX_DATE,
Expand Down Expand Up @@ -570,40 +571,71 @@ export const DateInput2: React.FC<DateInput2Props> = React.memo(function _DateIn
const shouldShowErrorStyling =
!isInputFocused || inputValue === props.outOfRangeMessage || inputValue === props.invalidDateMessage;

// We use the renderTarget API to flatten the rendered DOM and make it easier to implement features like the "fill" prop.
const renderTarget = React.useCallback(
// N.B. pull out `defaultValue` so that it's not forwarded to the DOM.
({
defaultValue: _defaultValue,
isOpen: targetIsOpen,
ref,
...targetProps
}: Popover2TargetProps & React.HTMLProps<HTMLDivElement>) => {
return (
<InputGroup
autoComplete="off"
className={classNames(targetProps.className, inputProps.className)}
intent={shouldShowErrorStyling && isErrorState ? "danger" : "none"}
placeholder={placeholder}
rightElement={
<>
{maybeTimezonePicker}
{props.rightElement}
</>
}
type="text"
{...targetProps}
{...inputProps}
aria-expanded={targetIsOpen}
disabled={props.disabled}
fill={fill}
inputRef={mergeRefs(ref, inputRef, props.inputProps?.inputRef ?? null)}
onBlur={handleInputBlur}
onChange={handleInputChange}
onClick={handleInputClick}
onFocus={handleInputFocus}
onKeyDown={handleInputKeyDown}
value={(isInputFocused ? inputValue : formattedDateString) ?? ""}
/>
);
},
[
fill,
formattedDateString,
inputValue,
isInputFocused,
isTimezoneSelectDisabled,
isTimezoneSelectHidden,
placeholder,
shouldShowErrorStyling,
props.disabled,
props.inputProps,
props.rightElement,
],
);

// N.B. no need to set `fill` since that is unused with the `renderTarget` API
return (
<Popover2
isOpen={isOpen && !props.disabled}
fill={props.fill}
{...popoverProps}
autoFocus={false}
className={classNames(Classes.DATE_INPUT, popoverProps.className, props.className)}
content={popoverContent}
enforceFocus={false}
onClose={handlePopoverClose}
popoverClassName={classNames(Classes.DATE_INPUT_POPOVER, popoverProps.popoverClassName)}
>
<InputGroup
autoComplete="off"
intent={shouldShowErrorStyling && isErrorState ? "danger" : "none"}
placeholder={placeholder}
rightElement={
<>
{maybeTimezonePicker}
{props.rightElement}
</>
}
type="text"
{...inputProps}
disabled={props.disabled}
inputRef={mergeRefs(inputRef, props.inputProps?.inputRef ?? null)}
onBlur={handleInputBlur}
onChange={handleInputChange}
onClick={handleInputClick}
onFocus={handleInputFocus}
onKeyDown={handleInputKeyDown}
value={(isInputFocused ? inputValue : formattedDateString) ?? ""}
/>
</Popover2>
renderTarget={renderTarget}
/>
);
});
DateInput2.displayName = `${DISPLAYNAME_PREFIX}.DateInput2`;
Expand Down
8 changes: 4 additions & 4 deletions packages/datetime2/test/components/dateInput2Tests.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,12 +126,13 @@ describe("<DateInput2>", () => {
assert.equal(datePicker.prop("todayButtonText"), "today");
});

it("passes inputProps to InputGroup", () => {
it("passes fill and inputProps to InputGroup", () => {
const inputRef = sinon.spy();
const onFocus = sinon.spy();
const wrapper = mount(
<DateInput2
{...DEFAULT_PROPS}
fill={true}
inputProps={{
inputRef,
leftIcon: "star",
Expand All @@ -143,18 +144,18 @@ describe("<DateInput2>", () => {
focusInput(wrapper);

const input = wrapper.find(InputGroup);
assert.strictEqual(input.prop("fill"), true);
assert.strictEqual(input.prop("leftIcon"), "star");
assert.isTrue(input.prop("required"));
assert.isTrue(inputRef.called, "inputRef not invoked");
assert.isTrue(onFocus.called, "onFocus not invoked");
});

it("passes fill and popoverProps to Popover2", () => {
it("passes popoverProps to Popover2", () => {
const onOpening = sinon.spy();
const wrapper = mount(
<DateInput2
{...DEFAULT_PROPS}
fill={true}
popoverProps={{
onOpening,
placement: "top",
Expand All @@ -165,7 +166,6 @@ describe("<DateInput2>", () => {
focusInput(wrapper);

const popover = wrapper.find(Popover2).first();
assert.strictEqual(popover.prop("fill"), true);
assert.strictEqual(popover.prop("placement"), "top");
assert.strictEqual(popover.prop("usePortal"), false);
assert.isTrue(onOpening.calledOnce);
Expand Down
6 changes: 5 additions & 1 deletion packages/docs-app/src/styles/_examples.scss
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,7 @@
#{page("datetime", "^=")} {
.docs-example {
flex-direction: column;
gap: $pt-grid-size;
justify-content: center;
}

Expand All @@ -543,7 +544,10 @@
//

#{example("DateInput2Example")} {
.#{$ns}-input-group {
.#{$ns}-date-input {
// should not grow in vertical direction when fill={true}
flex-grow: 0;
margin: 0;
min-width: 300px;
}
}
Expand Down

1 comment on commit cec40f7

@blueprint-bot
Copy link

Choose a reason for hiding this comment

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

[datetime2] feat(DateInput2): remove target wrapper, fix fill prop (#5473)

Previews: documentation | landing | table | demo

Please sign in to comment.