Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions packages/react-core/src/components/TimePicker/TimePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -373,9 +373,22 @@ export class TimePicker extends React.Component<TimePickerProps, TimePickerState
onToggle = (isOpen: boolean) => {
// on close, parse and validate input
this.setState(prevState => {
const { timeRegex, isInvalid } = prevState;
const { delimiter, is24Hour, includeSeconds } = this.props;
const time = parseTime(prevState.timeState, timeRegex, delimiter, !is24Hour, includeSeconds);
const { timeRegex, isInvalid, timeState } = prevState;
const { delimiter, is24Hour, includeSeconds, onChange } = this.props;
const time = parseTime(timeState, timeRegex, delimiter, !is24Hour, includeSeconds);

// Call onChange when Enter is pressed in input and timeoption does not exist in menu
if (onChange && !isOpen && time !== timeState) {
onChange(
null,
time,
getHours(time, timeRegex),
getMinutes(time, timeRegex),
getSeconds(time, timeRegex),
this.isValid(time)
);
}

return {
isTimeOptionsOpen: isOpen,
timeState: time,
Expand Down Expand Up @@ -414,7 +427,6 @@ export class TimePicker extends React.Component<TimePickerProps, TimePickerState
onInputChange = (newTime: string, event: React.FormEvent<HTMLInputElement>) => {
const { onChange } = this.props;
const { timeRegex } = this.state;

if (onChange) {
onChange(
event,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,28 @@ describe('TimePicker', () => {
expects: { hour: 23, minutes: 59, seconds: null }
});
});

// Disabling because this test does not work on CI
xtest('should call onChange when pressing Enter', async () => {
const onChange = jest.fn();
const user = userEvent.setup();

render(<TimePicker onChange={onChange} aria-label="time picker" />);

// Take into account timezones when tests are ran
const isPM = new Date().getHours() > 12;

await user.type(screen.getByLabelText('time picker'), `11:11`);
await user.keyboard('[Enter]');
expect(onChange).toHaveBeenLastCalledWith(
expect.any(Object),
`11:11 ${isPM ? 'PM' : 'AM'}`,
isPM ? 23 : 11,
11,
null,
true
);
});
});

describe('test isInvalid', () => {
Expand Down
85 changes: 45 additions & 40 deletions packages/react-core/src/demos/DatePicker/DatePicker.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,34 +18,35 @@ DateRangePicker = () => {
const [from, setFrom] = React.useState();
const [to, setTo] = React.useState();

const toValidator = date => isValidDate(from) && date >= from ? '' : 'To date must be less than from date';
const onFromChange = (_str, date) => {
const toValidator = (date) =>
isValidDate(from) && date >= from ? '' : 'The "to" date must be after the "from" date';

const onFromChange = (_event, _value, date) => {
setFrom(new Date(date));
if (isValidDate(date)) {
date.setDate(date.getDate() + 1);
setTo(yyyyMMddFormat(date));
}
else {
} else {
setTo('');
}
};

const onToChange = (_event, _value, date) => {
if (isValidDate(date)) {
setTo(yyyyMMddFormat(date));
}
};

return (
<Split>
<SplitItem>
<DatePicker
onChange={onFromChange}
aria-label="Start date"
placeholder="YYYY-MM-DD"
/>
</SplitItem>
<SplitItem style={{ padding: '6px 12px 0 12px' }}>
to
<DatePicker onChange={onFromChange} aria-label="Start date" placeholder="YYYY-MM-DD" />
</SplitItem>
<SplitItem style={{ padding: '6px 12px 0 12px' }}>to</SplitItem>
<SplitItem>
<DatePicker
value={to}
onChange={date => setTo(date)}
onChange={onToChange}
isDisabled={!isValidDate(from)}
rangeStart={from}
validators={[toValidator]}
Expand All @@ -55,23 +56,34 @@ DateRangePicker = () => {
</SplitItem>
</Split>
);
}
};
```

### Date and time range picker

```js
import { Flex, FlexItem, InputGroup, DatePicker, isValidDate, TimePicker, yyyyMMddFormat, updateDateTime } from '@patternfly/react-core';
import {
Flex,
FlexItem,
InputGroup,
DatePicker,
isValidDate,
TimePicker,
yyyyMMddFormat,
updateDateTime
} from '@patternfly/react-core';

DateTimeRangePicker = () => {
const [from, setFrom] = React.useState();
const [to, setTo] = React.useState();

const toValidator = date => {
return isValidDate(from) && yyyyMMddFormat(date) >= yyyyMMddFormat(from) ? '' : 'To date must after from date';
const toValidator = (date) => {
return isValidDate(from) && yyyyMMddFormat(date) >= yyyyMMddFormat(from)
? ''
: 'The "to" date must be after the "from" date';
};
const onFromDateChange = (inputDate, newFromDate) => {

const onFromDateChange = (_event, inputDate, newFromDate) => {
if (isValidDate(from) && isValidDate(newFromDate) && inputDate === yyyyMMddFormat(newFromDate)) {
newFromDate.setHours(from.getHours());
newFromDate.setMinutes(from.getMinutes());
Expand All @@ -80,7 +92,7 @@ DateTimeRangePicker = () => {
setFrom(new Date(newFromDate));
}
};

const onFromTimeChange = (_event, time, hour, minute) => {
if (isValidDate(from)) {
const updatedFromDate = new Date(from);
Expand All @@ -90,16 +102,16 @@ DateTimeRangePicker = () => {
}
};

const onToDateChange = (inputDate, newToDate) => {
const onToDateChange = (_event, inputDate, newToDate) => {
if (isValidDate(to) && isValidDate(newToDate) && inputDate === yyyyMMddFormat(newToDate)) {
newToDate.setHours(to.getHours());
newToDate.setMinutes(to.getMinutes());
}
if (isValidDate(newToDate) && inputDate === yyyyMMddFormat(newToDate)){
if (isValidDate(newToDate) && inputDate === yyyyMMddFormat(newToDate)) {
setTo(newToDate);
}
};

const onToTimeChange = (_event, time, hour, minute) => {
if (isValidDate(to)) {
const updatedToDate = new Date(to);
Expand All @@ -110,24 +122,14 @@ DateTimeRangePicker = () => {
};

return (
<Flex direction={{default: 'column', lg: 'row'}}>
<Flex direction={{ default: 'column', lg: 'row' }}>
<FlexItem>
<InputGroup>
<DatePicker
onChange={onFromDateChange}
aria-label="Start date"
placeholder="YYYY-MM-DD"
/>
<TimePicker
aria-label="Start time"
style={{width: '150px'}}
onChange={onFromTimeChange}
/>
<DatePicker onChange={onFromDateChange} aria-label="Start date" placeholder="YYYY-MM-DD" />
<TimePicker aria-label="Start time" style={{ width: '150px' }} onChange={onFromTimeChange} />
</InputGroup>
</FlexItem>
<FlexItem>
to
</FlexItem>
<FlexItem>to</FlexItem>
<FlexItem>
<InputGroup>
<DatePicker
Expand All @@ -139,19 +141,22 @@ DateTimeRangePicker = () => {
aria-label="End date"
placeholder="YYYY-MM-DD"
/>
<TimePicker style={{width: '150px'}} onChange={onToTimeChange} isDisabled={!isValidDate(from)}/>
<TimePicker style={{ width: '150px' }} onChange={onToTimeChange} isDisabled={!isValidDate(from)} />
</InputGroup>
</FlexItem>
</Flex>
);
}
};
```


### Date and time pickers in modal

Modals trap focus and watch a few document level events. In order to place a date picker in a modal:

- To avoid the modal's escape press event handler from overruling the date picker's escape press handlers, use the `DatePickerRef` to close the calendar when it is open and the escape key is pressed.
- Append the calendar to the modal to keep it as close to the date picker in the DOM while maintaining correct layouts visually
In order to place a time picker in the modal, its menu must be appended to the time picker's parent.

```ts file="./examples/DateTimePickerInModal.tsx"

```
8 changes: 4 additions & 4 deletions packages/react-table/src/components/Table/ActionsColumn.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { Dropdown, DropdownItem, DropdownList } from '@patternfly/react-core';
import { Dropdown, DropdownItem, DropdownList } from '@patternfly/react-core/dist/esm/components/Dropdown';
import { Button } from '@patternfly/react-core/dist/esm/components/Button';
import { Divider } from '@patternfly/react-core/dist/esm/components/Divider';
import { MenuToggle } from '@patternfly/react-core/dist/esm/components/MenuToggle';
Expand Down Expand Up @@ -70,7 +70,7 @@ const ActionsColumnBase: React.FunctionComponent<ActionsColumnProps> = ({
.map(({ title, itemKey, onClick, isOutsideDropdown, ...props }, key) =>
typeof title === 'string' ? (
<Button
onClick={(event) => onActionClick(event, onClick)}
onClick={(event: MouseEvent | React.MouseEvent<any, MouseEvent> | React.KeyboardEvent<Element>) => onActionClick(event, onClick)}
{...(props as any)}
isDisabled={isDisabled}
key={itemKey || `outside_dropdown_${key}`}
Expand All @@ -85,8 +85,8 @@ const ActionsColumnBase: React.FunctionComponent<ActionsColumnProps> = ({

<Dropdown
isOpen={isOpen}
onOpenChange={(isOpen) => setIsOpen(isOpen)}
toggle={(toggleRef) =>
onOpenChange={(isOpen: boolean) => setIsOpen(isOpen)}
toggle={(toggleRef: any) =>
actionsToggle ? (
actionsToggle({ onToggle, isOpen, isDisabled, toggleRef })
) : (
Expand Down
6 changes: 4 additions & 2 deletions packages/react-table/src/components/Table/BodyCell.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import * as React from 'react';
import { Tooltip } from '@patternfly/react-core/dist/esm/components/Tooltip/Tooltip';
import { Bullseye, EmptyState, SelectProps } from '@patternfly/react-core';
import { Tooltip } from '@patternfly/react-core/dist/esm/components/Tooltip';
import { Bullseye } from '@patternfly/react-core/dist/esm/layouts/Bullseye';
import { EmptyState } from '@patternfly/react-core/dist/esm/components/EmptyState';
import { SelectProps } from '@patternfly/react-core/dist/esm/components/Select';
import { Td } from '../TableComposable/Td';

export interface BodyCellProps {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react';
import AngleDownIcon from '@patternfly/react-icons/dist/esm/icons/angle-down-icon';
import { css } from '@patternfly/react-styles';
import { Button } from '@patternfly/react-core/dist/esm/components/Button/Button';
import { Button } from '@patternfly/react-core/dist/esm/components/Button';
import styles from '@patternfly/react-styles/css/components/Table/table';

export interface CollapseColumnProps {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import GripVerticalIcon from '@patternfly/react-icons/dist/esm/icons/grip-vertical-icon';
import { Button } from '@patternfly/react-core/dist/esm/components/Button/Button';
import { Button } from '@patternfly/react-core/dist/esm/components/Button';

export interface DraggableCellProps {
id: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import { css } from '@patternfly/react-styles';
import { Select, SelectOptionObject } from '@patternfly/react-core';
import { Select, SelectOptionObject } from '@patternfly/react-core/dist/esm/components/Select';
import inlineStyles from '@patternfly/react-styles/css/components/InlineEdit/inline-edit';
import formStyles from '@patternfly/react-styles/css/components/Form/form';
import { EditableSelectInputProps } from './base';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import StarIcon from '@patternfly/react-icons/dist/esm/icons/star-icon';
import { Button } from '@patternfly/react-core/dist/esm/components/Button/Button';
import { Button } from '@patternfly/react-core/dist/esm/components/Button';

export interface FavoritesCellProps {
id?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import * as React from 'react';
import HelpIcon from '@patternfly/react-icons/dist/esm/icons/help-icon';
import { css } from '@patternfly/react-styles';
import styles from '@patternfly/react-styles/css/components/Table/table';
import { Button, Tooltip, Popover, TooltipProps, PopoverProps } from '@patternfly/react-core';
import { Tooltip, TooltipProps } from '@patternfly/react-core/dist/esm/components/Tooltip';
import { Popover, PopoverProps } from '@patternfly/react-core/dist/esm/components/Popover';
import { Button } from '@patternfly/react-core/dist/esm/components/Button';
import { TableText } from './TableText';

export interface ColumnHelpWrapperProps {
Expand Down
4 changes: 2 additions & 2 deletions packages/react-table/src/components/Table/Table.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import { OUIAProps, getDefaultOUIAId } from '@patternfly/react-core';
import { DropdownDirection, DropdownPosition } from '@patternfly/react-core/dist/esm/deprecated/components';
import { OUIAProps, getDefaultOUIAId } from '@patternfly/react-core/dist/esm/helpers';
import { DropdownDirection, DropdownPosition } from '@patternfly/react-core/dist/esm/deprecated/components/Dropdown';
import inlineStyles from '@patternfly/react-styles/css/components/InlineEdit/inline-edit';
import { css } from '@patternfly/react-styles';
import { Provider } from './base';
Expand Down
2 changes: 1 addition & 1 deletion packages/react-table/src/components/Table/TableText.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react';
import styles from '@patternfly/react-styles/css/components/Table/table';
import { css } from '@patternfly/react-styles';
import { Tooltip, TooltipProps } from '@patternfly/react-core/dist/esm/components/Tooltip/Tooltip';
import { Tooltip, TooltipProps } from '@patternfly/react-core/dist/esm/components/Tooltip';

export enum TableTextVariant {
div = 'div',
Expand Down
6 changes: 3 additions & 3 deletions packages/react-table/src/components/Table/TableTypes.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { DropdownItemProps } from '@patternfly/react-core';
import { ButtonProps } from '@patternfly/react-core/dist/esm/components/Button';
import { formatterValueType, ColumnType, RowType, RowKeyType, HeaderType } from './base';
import { SortByDirection } from './SortColumn';
import { DropdownDirection, DropdownPosition } from '@patternfly/react-core/dist/esm/deprecated/components';
import { DropdownItemProps } from '@patternfly/react-core/dist/esm/components/Dropdown';
import { DropdownDirection, DropdownPosition } from '@patternfly/react-core/dist/esm/deprecated/components/Dropdown';
Copy link
Contributor

Choose a reason for hiding this comment

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

We may want to make a note to clean up the remaining usages of the old dropdown. Looks like it's still referenced in IColumn here and TdActionsType in base/types.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@thatblindgeye is this part of your PR for updating demos to use the new dropdown?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah that's something that I should be able to incorporate into #8839

import * as React from 'react';
import { CustomActionsToggleProps } from './ActionsColumn';
import { ButtonProps } from '@patternfly/react-core';

export enum TableGridBreakpoint {
none = '',
Expand Down
6 changes: 4 additions & 2 deletions packages/react-table/src/components/Table/base/types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
*/

import * as React from 'react';
import { TooltipProps, PopoverProps, SelectOptionObject, SelectProps } from '@patternfly/react-core';
import { DropdownPosition, DropdownDirection } from '@patternfly/react-core/dist/esm/deprecated/components';
import { TooltipProps } from '@patternfly/react-core/dist/esm/components/Tooltip';
import { PopoverProps } from '@patternfly/react-core/dist/esm/components/Popover';
import { DropdownPosition, DropdownDirection } from '@patternfly/react-core/dist/esm/deprecated/components/Dropdown';
import { SelectProps, SelectOptionObject } from '@patternfly/react-core/dist/esm/components/Select';
import { TableComposable } from '../../TableComposable/TableComposable';
import { Thead } from '../../TableComposable/Thead';
import { Tbody } from '../../TableComposable/Tbody';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { IExtra, IFormatterValueType, OnCheckChange, OnTreeRowCollapse, OnToggle
import { css } from '@patternfly/react-styles';
import styles from '@patternfly/react-styles/css/components/Table/table';
import stylesTreeView from '@patternfly/react-styles/css/components/Table/table-tree-view';
import { Button, Checkbox } from '@patternfly/react-core';
import { Button } from '@patternfly/react-core/dist/esm/components/Button';
import { Checkbox } from '@patternfly/react-core/dist/esm/components/Checkbox';
import AngleDownIcon from '@patternfly/react-icons/dist/esm/icons/angle-down-icon';
import EllipsisHIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-h-icon';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
textCenter,
cellActions
} from './';
import { DropdownPosition, DropdownDirection } from '@patternfly/react-core/deprecated';
import { DropdownPosition, DropdownDirection } from '@patternfly/react-core/dist/esm/deprecated/components/Dropdown';
import {
IAction,
IActions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import stylesTreeView from '@patternfly/react-styles/css/components/Table/table-
import { css } from '@patternfly/react-styles';
import { toCamel } from '../Table/utils/utils';
import { IVisibility } from '../Table/utils/decorators/classNames';
import { useOUIAProps, OUIAProps, handleArrows, setTabIndex } from '@patternfly/react-core';
import { useOUIAProps, OUIAProps, handleArrows, setTabIndex } from '@patternfly/react-core/dist/esm/helpers';
import { TableGridBreakpoint, TableVariant } from '../Table/TableTypes';

export interface BaseCellProps {
Expand Down
Loading