Skip to content
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions packages/eui/changelogs/upcoming/8810.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
- Added prop `delimiter` on `EuiDatePickerRange`

**Bug fixes**

- Fixed an issue with `EuiSuperDatePicker` where toggling `isQuickSelectOnly` would cause a full re-render when the selected range uses absolute dates
Comment thread
mgadewoll marked this conversation as resolved.

2 changes: 1 addition & 1 deletion packages/eui/src/components/date_picker/date_picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ export const EuiDatePicker: FunctionComponent<EuiDatePickerProps> = ({
}) => {
// Check for whether the passed `selected` moment date is valid
const isInvalid =
_isInvalid || (selected?.isValid() === false ? true : undefined);
_isInvalid || (selected?.isValid?.() === false ? true : undefined);

const styles = useEuiMemoizedStyles(euiDatePickerStyles);
const cssStyles = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,25 +134,28 @@ const StatefulPlayground = ({
...rest
}: EuiDatePickerRangeProps) => {
const [selectedStartDate, setSelectedStartDate] = useState<moment.Moment>(
startDateControl.props.selected
startDateControl?.props.selected ?? moment('01/01/1970')
);
const [selectedEndDate, setSelectedEndDate] = useState<moment.Moment>(
endDateControl.props.selected
endDateControl?.props.selected ?? moment('01/07/1970')
);

const startControl = React.cloneElement(startDateControl, {
selected: selectedStartDate,
onChange: setSelectedStartDate,
startDate: selectedStartDate,
endDate: selectedEndDate,
});

const endControl = React.cloneElement(endDateControl, {
selected: selectedEndDate,
onChange: setSelectedEndDate,
startDate: selectedStartDate,
endDate: selectedEndDate,
});
const startControl =
startDateControl &&
React.cloneElement(startDateControl, {
selected: selectedStartDate,
onChange: setSelectedStartDate,
startDate: selectedStartDate,
endDate: selectedEndDate,
});
const endControl =
endDateControl &&
React.cloneElement(endDateControl, {
selected: selectedEndDate,
onChange: setSelectedEndDate,
startDate: selectedStartDate,
endDate: selectedEndDate,
});

return (
<EuiDatePickerRange
Expand Down
49 changes: 25 additions & 24 deletions packages/eui/src/components/date_picker/date_picker_range.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export type EuiDatePickerRangeProps = CommonProps &
| 'compressed'
| 'prepend'
| 'append'
| 'delimiter'
> & {
/**
* Including any children will replace all innards with the provided children
Expand All @@ -51,12 +52,12 @@ export type EuiDatePickerRangeProps = CommonProps &
/**
* The end date `EuiDatePicker` element
*/
endDateControl: ReactElement;
endDateControl?: ReactElement;

/**
* The start date `EuiDatePicker` element
*/
startDateControl: ReactElement;
startDateControl?: ReactElement;

/**
* Pass either an icon type or set to `false` to remove icon entirely
Expand Down Expand Up @@ -116,6 +117,7 @@ export const EuiDatePickerRange: FunctionComponent<EuiDatePickerRangeProps> = ({
onBlur,
append,
prepend,
delimiter,
...rest
}) => {
// `fullWidth` and `compressed` should not affect inline datepickers (matches non-range behavior)
Expand All @@ -130,8 +132,8 @@ export const EuiDatePickerRange: FunctionComponent<EuiDatePickerRangeProps> = ({
: [
inlineStyles.euiDatePickerRangeInline,
// Determine the inline container query to use based on the width of the react-datepicker
startDateControl.props.showTimeSelect ||
endDateControl.props.showTimeSelect
startDateControl?.props.showTimeSelect ||
endDateControl?.props.showTimeSelect
? inlineStyles.responsiveWithTimeSelect
: inlineStyles.responsive,
shadow && inlineStyles.shadow,
Expand All @@ -141,58 +143,56 @@ export const EuiDatePickerRange: FunctionComponent<EuiDatePickerRangeProps> = ({
let endControl = endDateControl;

if (!isCustom) {
startControl = cloneElement(
startDateControl as ReactElement<EuiDatePickerProps>,
{
startControl =
startControl &&
cloneElement(startDateControl as ReactElement<EuiDatePickerProps>, {
controlOnly: true,
showIcon: false,
inline,
compressed,
fullWidth,
readOnly,
disabled: disabled || startDateControl.props.disabled,
isInvalid: isInvalid || startDateControl.props.isInvalid,
disabled: disabled || startDateControl?.props.disabled,
isInvalid: isInvalid || startDateControl?.props.isInvalid,
className: classNames(
'euiDatePickerRange__start',
startDateControl.props.className
startDateControl?.props.className
),
onBlur: (event: FocusEvent<HTMLInputElement>) => {
startDateControl.props?.onBlur?.(event);
startDateControl?.props?.onBlur?.(event);
onBlur?.(event);
},
onFocus: (event: FocusEvent<HTMLInputElement>) => {
startDateControl.props?.onFocus?.(event);
startDateControl?.props?.onFocus?.(event);
onFocus?.(event);
},
}
);
});

endControl = cloneElement(
endDateControl as ReactElement<EuiDatePickerProps>,
{
endControl =
endControl &&
cloneElement(endDateControl as ReactElement<EuiDatePickerProps>, {
controlOnly: true,
showIcon: false,
inline,
compressed,
fullWidth,
readOnly,
disabled: disabled || endDateControl.props.disabled,
isInvalid: isInvalid || endDateControl.props.isInvalid,
disabled: disabled || endDateControl?.props.disabled,
isInvalid: isInvalid || endDateControl?.props.isInvalid,
popoverPlacement: 'downRight',
className: classNames(
'euiDatePickerRange__end',
endDateControl.props.className
endDateControl?.props.className
),
onBlur: (event: FocusEvent<HTMLInputElement>) => {
endDateControl.props?.onBlur?.(event);
endDateControl?.props?.onBlur?.(event);
onBlur?.(event);
},
onFocus: (event: FocusEvent<HTMLInputElement>) => {
endDateControl.props?.onFocus?.(event);
endDateControl?.props?.onFocus?.(event);
onFocus?.(event);
},
}
);
});
}

const icon = useMemo(() => {
Expand All @@ -205,6 +205,7 @@ export const EuiDatePickerRange: FunctionComponent<EuiDatePickerRangeProps> = ({
return (
<span className={classes} css={cssStyles} {...rest}>
<EuiFormControlLayoutDelimited
delimiter={delimiter}
icon={icon}
startControl={startControl}
endControl={endControl}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
* Side Public License, v 1.
*/

import React from 'react';
import React, { useState } from 'react';
import moment from 'moment';
import type { Meta, StoryObj } from '@storybook/react';
import { expect, fireEvent } from '@storybook/test';
import type { Meta, ReactRenderer, StoryObj } from '@storybook/react';
import { expect, fireEvent, waitFor } from '@storybook/test';
import type { PlayFunctionContext } from '@storybook/csf';
import { within } from '../../../../.storybook/test';
import { LOKI_SELECTORS } from '../../../../.storybook/loki';
import { enableFunctionToggleControls } from '../../../../.storybook/utils';
Expand All @@ -21,6 +22,8 @@ import {
EuiSuperDatePicker,
EuiSuperDatePickerProps,
} from './super_date_picker';
import { EuiFieldText } from '../../form';
import { EuiFlexGroup } from '../../flex';

const meta: Meta<EuiSuperDatePickerProps> = {
title: 'Forms/EuiSuperDatePicker/EuiSuperDatePicker',
Expand Down Expand Up @@ -124,6 +127,45 @@ function CustomPanel({ applyTime }: { applyTime?: ApplyTime }) {
);
}

export const QuickSelectOnly: Story = {
parameters: {
loki: { chromeSelector: LOKI_SELECTORS.portal },
Comment thread
mgadewoll marked this conversation as resolved.
},
args: {
start: '2025-01-01T00:00:00',
end: 'now',
},
render: function Render(args) {
const [isCollapsed, setCollapsed] = useState(false);

return (
<EuiFlexGroup>
<EuiFieldText onFocus={() => setCollapsed(true)} />
<EuiSuperDatePicker
{...args}
isQuickSelectOnly={isCollapsed}
quickSelectButtonProps={{
onClick: () => setCollapsed(false),
}}
/>
</EuiFlexGroup>
);
},
play: async ({ canvasElement }: PlayFunctionContext<ReactRenderer>) => {
const canvas = within(canvasElement);

await waitFor(async () => {
expect(
canvas.getByTestSubject('superDatePickerToggleQuickMenuButton')
).toBeInTheDocument();
});

await fireEvent.click(
canvas.getByTestSubject('superDatePickerToggleQuickMenuButton')
);
},
};

/**
* VRT only
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@
* Side Public License, v 1.
*/

import React from 'react';
import { fireEvent } from '@testing-library/react';
import { render } from '../../../test/rtl';
import React, { useState } from 'react';
import moment from 'moment';
import { fireEvent, act } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import { render, waitForEuiPopoverOpen } from '../../../test/rtl';
import { requiredProps } from '../../../test';
import { shouldRenderCustomStyles } from '../../../test/internal';

import { EuiFieldText } from '../../form';
import {
EuiSuperDatePicker,
EuiSuperDatePickerProps,
} from './super_date_picker';
import moment from 'moment';

const noop = () => {};

Expand Down Expand Up @@ -254,6 +256,59 @@ describe('EuiSuperDatePicker', () => {
);
expect(container.firstChild).toMatchSnapshot();
});

it('should open the quick select panel', async () => {
const Component = () => {
const [isCollapsed, setCollapsed] = useState(false);

return (
<>
<EuiFieldText
onFocus={() => setCollapsed(true)}
data-test-subj="euiFieldText"
/>
<EuiSuperDatePicker
start="2025-01-01T00:00:00"
end="now"
onTimeChange={noop}
isQuickSelectOnly={isCollapsed}
quickSelectButtonProps={{
onClick: () => setCollapsed(false),
'data-test-subj': 'euiSuperDatePickerQuickSelectButton',
}}
/>
</>
);
};
const { getByTestSubject } = render(<Component />);

const input = getByTestSubject('euiFieldText');
const quickSelectButton = getByTestSubject(
'euiSuperDatePickerQuickSelectButton'
);
const startDateButton = getByTestSubject(
'superDatePickerstartDatePopoverButton'
);

expect(startDateButton).toBeInTheDocument();

act(() => {
userEvent.click(input);
});

expect(input).toHaveFocus();
expect(startDateButton).not.toBeInTheDocument();

fireEvent.click(quickSelectButton);

await waitForEuiPopoverOpen();

expect(
getByTestSubject('superDatePickerQuickMenu')
).toBeInTheDocument();

expect(document.querySelector('.euiPanel')).toHaveFocus();
});
});

describe('isDisabled', () => {
Expand Down
Loading