@patternfly/react-core 4.233.0 → 4.234.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/dist/esm/components/MenuToggle/MenuToggle.js +1 -1
- package/dist/esm/components/MenuToggle/MenuToggle.js.map +1 -1
- package/dist/esm/components/TimePicker/TimePicker.d.ts +1 -0
- package/dist/esm/components/TimePicker/TimePicker.d.ts.map +1 -1
- package/dist/esm/components/TimePicker/TimePicker.js +14 -2
- package/dist/esm/components/TimePicker/TimePicker.js.map +1 -1
- package/dist/esm/components/Timestamp/Timestamp.d.ts +72 -0
- package/dist/esm/components/Timestamp/Timestamp.d.ts.map +1 -0
- package/dist/esm/components/Timestamp/Timestamp.js +33 -0
- package/dist/esm/components/Timestamp/Timestamp.js.map +1 -0
- package/dist/esm/components/Timestamp/index.d.ts +2 -0
- package/dist/esm/components/Timestamp/index.d.ts.map +1 -0
- package/dist/esm/components/Timestamp/index.js +2 -0
- package/dist/esm/components/Timestamp/index.js.map +1 -0
- package/dist/esm/components/index.d.ts +1 -0
- package/dist/esm/components/index.d.ts.map +1 -1
- package/dist/esm/components/index.js +1 -0
- package/dist/esm/components/index.js.map +1 -1
- package/dist/js/components/MenuToggle/MenuToggle.js +1 -1
- package/dist/js/components/MenuToggle/MenuToggle.js.map +1 -1
- package/dist/js/components/TimePicker/TimePicker.d.ts +1 -0
- package/dist/js/components/TimePicker/TimePicker.d.ts.map +1 -1
- package/dist/js/components/TimePicker/TimePicker.js +14 -2
- package/dist/js/components/TimePicker/TimePicker.js.map +1 -1
- package/dist/js/components/Timestamp/Timestamp.d.ts +72 -0
- package/dist/js/components/Timestamp/Timestamp.d.ts.map +1 -0
- package/dist/js/components/Timestamp/Timestamp.js +37 -0
- package/dist/js/components/Timestamp/Timestamp.js.map +1 -0
- package/dist/js/components/Timestamp/index.d.ts +2 -0
- package/dist/js/components/Timestamp/index.d.ts.map +1 -0
- package/dist/js/components/Timestamp/index.js +5 -0
- package/dist/js/components/Timestamp/index.js.map +1 -0
- package/dist/js/components/index.d.ts +1 -0
- package/dist/js/components/index.d.ts.map +1 -1
- package/dist/js/components/index.js +1 -0
- package/dist/js/components/index.js.map +1 -1
- package/dist/styles/base-no-reset.css +2 -2
- package/dist/styles/base.css +2 -2
- package/dist/umd/react-core.css +115 -69
- package/dist/umd/react-core.js +812 -759
- package/dist/umd/react-core.min.css +792 -746
- package/dist/umd/react-core.min.js +4 -4
- package/package.json +6 -6
- package/src/components/Button/examples/Button.md +55 -24
- package/src/components/ContextSelector/examples/ContextSelectorBasic.tsx +4 -4
- package/src/components/ContextSelector/examples/ContextSelectorPlainText.tsx +3 -3
- package/src/components/ContextSelector/examples/ContextSelectorWithFooter.tsx +4 -4
- package/src/components/DualListSelector/examples/DualListSelectorComposable.tsx +8 -2
- package/src/components/DualListSelector/examples/DualListSelectorComposableDragDrop.tsx +3 -9
- package/src/components/DualListSelector/examples/DualListSelectorComposableTree.tsx +3 -3
- package/src/components/DualListSelector/examples/DualListSelectorTreeExample.tsx +8 -5
- package/src/components/MenuToggle/MenuToggle.tsx +2 -2
- package/src/components/TimePicker/TimePicker.tsx +19 -11
- package/src/components/Timestamp/Timestamp.tsx +134 -0
- package/src/components/Timestamp/__tests__/Timestamp.test.tsx +177 -0
- package/src/components/Timestamp/__tests__/__snapshots__/Timestamp.test.tsx.snap +17 -0
- package/src/components/Timestamp/examples/Timestamp.md +57 -0
- package/src/components/Timestamp/examples/TimestampBasicFormats.tsx +26 -0
- package/src/components/Timestamp/examples/TimestampCustomContent.tsx +20 -0
- package/src/components/Timestamp/examples/TimestampCustomFormat.tsx +6 -0
- package/src/components/Timestamp/examples/TimestampCustomTooltip.tsx +19 -0
- package/src/components/Timestamp/examples/TimestampDefault.tsx +4 -0
- package/src/components/Timestamp/examples/TimestampDefaultTooltip.tsx +18 -0
- package/src/components/Timestamp/index.ts +1 -0
- package/src/components/index.ts +1 -0
- package/src/demos/Button.md +5 -1
- package/src/demos/ComposableMenu/examples/ComposableActionsMenu.tsx +12 -8
- package/src/demos/ComposableMenu/examples/ComposableApplicationLauncher.tsx +12 -11
- package/src/demos/ComposableMenu/examples/ComposableContextSelector.tsx +10 -12
- package/src/demos/ComposableMenu/examples/ComposableDrilldownMenu.tsx +7 -7
- package/src/demos/ComposableMenu/examples/ComposableFlyout.tsx +8 -8
- package/src/demos/ComposableMenu/examples/ComposableSimpleCheckboxSelect.tsx +11 -8
- package/src/demos/ComposableMenu/examples/ComposableSimpleDropdown.tsx +7 -7
- package/src/demos/ComposableMenu/examples/ComposableSimpleSelect.tsx +17 -8
- package/src/demos/ComposableMenu/examples/ComposableTreeViewMenu.tsx +11 -10
- package/src/demos/ComposableMenu/examples/ComposableTypeaheadSelect.tsx +2 -2
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import { Timestamp, TimestampFormat, TimestampTooltipVariant } from '../Timestamp';
|
|
4
|
+
|
|
5
|
+
jest.mock('../../Tooltip', () => ({
|
|
6
|
+
Tooltip: ({ content, children, ...props }) => (
|
|
7
|
+
<div data-testid="timestamp-tooltip-mock" {...props}>
|
|
8
|
+
<div data-testid="timestamp-tooltip-mock-content">{content}</div>
|
|
9
|
+
{children}
|
|
10
|
+
</div>
|
|
11
|
+
)
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
test('Matches snapshot', () => {
|
|
15
|
+
/** Due to how the datetime attribute is contstructed internally, dateTime must be
|
|
16
|
+
* manually passed for this snapshot to pass on GitHub.
|
|
17
|
+
*/
|
|
18
|
+
const { asFragment } = render(<Timestamp dateTime="2022-01-01T00:00:00.000Z" date={new Date(2022, 0, 1)} />);
|
|
19
|
+
|
|
20
|
+
expect(asFragment()).toMatchSnapshot();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('Renders component', () => {
|
|
24
|
+
render(
|
|
25
|
+
<div data-testid="timestamp-container">
|
|
26
|
+
<Timestamp />
|
|
27
|
+
</div>
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
expect(screen.getByTestId('timestamp-container').firstChild).toBeVisible();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('Renders with current date by default with default formatting', () => {
|
|
34
|
+
render(<Timestamp />);
|
|
35
|
+
|
|
36
|
+
expect(screen.getByText(new Date().toLocaleString())).toBeInTheDocument();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('Renders passed in date with default formatting', () => {
|
|
40
|
+
render(<Timestamp date={new Date(2022, 0, 1)} />);
|
|
41
|
+
|
|
42
|
+
expect(screen.getByText('1/1/2022, 12:00:00 AM')).toBeInTheDocument();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('Renders with custom formatting when dateFormat and timeFormat are passed in', () => {
|
|
46
|
+
render(
|
|
47
|
+
<Timestamp date={new Date(2022, 0, 1)} dateFormat={TimestampFormat.full} timeFormat={TimestampFormat.short} />
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
expect(screen.getByText('Saturday, January 1, 2022 at 12:00 AM')).toBeInTheDocument();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test('Renders with only date when dateFormat is passed in', () => {
|
|
54
|
+
render(<Timestamp date={new Date('1 Jan 2022 00:00:00 EST')} dateFormat={TimestampFormat.full} />);
|
|
55
|
+
|
|
56
|
+
expect(screen.getByText('Saturday, January 1, 2022')).toBeInTheDocument();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('Renders with only time when timeFormat is passed in', () => {
|
|
60
|
+
render(<Timestamp date={new Date(2022, 0, 1)} timeFormat={TimestampFormat.short} />);
|
|
61
|
+
|
|
62
|
+
expect(screen.getByText('12:00 AM')).toBeInTheDocument();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test('Renders with custom formatting when customFormat is passed in', () => {
|
|
66
|
+
render(
|
|
67
|
+
<Timestamp
|
|
68
|
+
date={new Date(2022, 0, 1)}
|
|
69
|
+
customFormat={{ year: '2-digit', month: 'short', weekday: 'short', day: 'numeric', hour: 'numeric' }}
|
|
70
|
+
/>
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
expect(screen.getByText('Sat, Jan 1, 22, 12 AM')).toBeInTheDocument();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test('Renders with custom content', () => {
|
|
77
|
+
render(<Timestamp>2 days ago</Timestamp>);
|
|
78
|
+
|
|
79
|
+
expect(screen.getByText('2 days ago')).toBeInTheDocument();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test('Renders with a custom suffix when displaySuffix is passed in', () => {
|
|
83
|
+
render(<Timestamp date={new Date(2022, 0, 1)} displaySuffix="US Eastern" />);
|
|
84
|
+
|
|
85
|
+
expect(screen.getByText('1/1/2022, 12:00:00 AM US Eastern')).toBeInTheDocument();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('Renders with 12 hour time when is12Hour is passed', () => {
|
|
89
|
+
render(<Timestamp date={new Date(2022, 0, 1, 13, 0)} is12Hour />);
|
|
90
|
+
|
|
91
|
+
expect(screen.getByText('1/1/2022, 1:00:00 PM')).toBeInTheDocument();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test('Renders with 24 hour time when is12Hour is set to false', () => {
|
|
95
|
+
render(<Timestamp date={new Date(2022, 0, 1, 13, 0)} is12Hour={false} />);
|
|
96
|
+
|
|
97
|
+
expect(screen.getByText('1/1/2022, 13:00:00')).toBeInTheDocument();
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test('Renders with locale passed in', () => {
|
|
101
|
+
render(<Timestamp date={new Date(2022, 1, 1)} locale="en-GB" />);
|
|
102
|
+
|
|
103
|
+
expect(screen.getByText('01/02/2022, 00:00:00')).toBeInTheDocument();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test('Renders with 12 hour time by default for US locale', () => {
|
|
107
|
+
render(<Timestamp date={new Date(2022, 1, 1, 13, 0)} locale="en-US" />);
|
|
108
|
+
|
|
109
|
+
expect(screen.getByText('2/1/2022, 1:00:00 PM')).toBeInTheDocument();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('Renders with 24 hour time for US locale when is12Hour is false', () => {
|
|
113
|
+
render(<Timestamp date={new Date(2022, 1, 1, 13, 0)} locale="en-US" is12Hour={false} />);
|
|
114
|
+
|
|
115
|
+
expect(screen.getByText('2/1/2022, 13:00:00')).toBeInTheDocument();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('Renders with 12 hour time for a 24 hour locale when is12Hour is passed', () => {
|
|
119
|
+
render(<Timestamp date={new Date(2022, 1, 1, 13, 0)} locale="en-GB" is12Hour />);
|
|
120
|
+
|
|
121
|
+
expect(screen.getByText('01/02/2022, 1:00:00 pm')).toBeInTheDocument();
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test('Renders with pf-c-timestamp by default', () => {
|
|
125
|
+
render(<Timestamp date={new Date(2022, 0, 1)} />);
|
|
126
|
+
|
|
127
|
+
expect(screen.getByText('1/1/2022, 12:00:00 AM').parentElement).toHaveClass('pf-c-timestamp');
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test('Renders with pf-c-timestamp__text by default', () => {
|
|
131
|
+
render(<Timestamp date={new Date(2022, 0, 1)} />);
|
|
132
|
+
|
|
133
|
+
expect(screen.getByText('1/1/2022, 12:00:00 AM')).toHaveClass('pf-c-timestamp__text');
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test('Renders with custom class names', () => {
|
|
137
|
+
render(<Timestamp date={new Date(2022, 0, 1)} className="custom-time-class" />);
|
|
138
|
+
|
|
139
|
+
expect(screen.getByText('1/1/2022, 12:00:00 AM').parentElement).toHaveClass('custom-time-class');
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test('Renders with pf-m-help-text class when tooltip is passed in with default variant', () => {
|
|
143
|
+
render(<Timestamp date={new Date(2022, 0, 1)} tooltip={{ variant: TimestampTooltipVariant.default }} />);
|
|
144
|
+
|
|
145
|
+
expect(screen.getByText('1/1/2022, 12:00:00 AM').parentElement).toHaveClass('pf-m-help-text');
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test('Renders with pf-m-help-text class when tooltip is passed in with custom variant', () => {
|
|
149
|
+
render(<Timestamp date={new Date(2022, 0, 1)} tooltip={{ variant: TimestampTooltipVariant.custom }} />);
|
|
150
|
+
|
|
151
|
+
expect(screen.getByText('1/1/2022, 12:00:00 AM').parentElement).toHaveClass('pf-m-help-text');
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
test('Renders with default tooltip content for default variant', () => {
|
|
155
|
+
render(
|
|
156
|
+
<Timestamp date={new Date('1 Jan 2022 00:00:00 EST')} tooltip={{ variant: TimestampTooltipVariant.default }} />
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
expect(screen.getByText('1/1/2022, 5:00:00 AM UTC')).toBeInTheDocument();
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test('Renders with custom tooltip suffix for default variant', () => {
|
|
163
|
+
render(
|
|
164
|
+
<Timestamp
|
|
165
|
+
date={new Date('1 Jan 2022 00:00:00 EST')}
|
|
166
|
+
tooltip={{ variant: TimestampTooltipVariant.default, suffix: 'Coordinated Universal Time' }}
|
|
167
|
+
/>
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
expect(screen.getByText('1/1/2022, 5:00:00 AM Coordinated Universal Time')).toBeInTheDocument();
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test('Renders with custom tooltip content', () => {
|
|
174
|
+
render(<Timestamp tooltip={{ variant: TimestampTooltipVariant.custom, content: 'Custom tooltip content' }} />);
|
|
175
|
+
|
|
176
|
+
expect(screen.getByText('Custom tooltip content')).toBeInTheDocument();
|
|
177
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`Matches snapshot 1`] = `
|
|
4
|
+
<DocumentFragment>
|
|
5
|
+
<span
|
|
6
|
+
class="pf-c-timestamp"
|
|
7
|
+
datetime="2022-01-01T00:00:00.000Z"
|
|
8
|
+
>
|
|
9
|
+
<time
|
|
10
|
+
class="pf-c-timestamp__text"
|
|
11
|
+
datetime="2022-01-01T00:00:00.000Z"
|
|
12
|
+
>
|
|
13
|
+
1/1/2022, 12:00:00 AM
|
|
14
|
+
</time>
|
|
15
|
+
</span>
|
|
16
|
+
</DocumentFragment>
|
|
17
|
+
`;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: Timestamp
|
|
3
|
+
section: components
|
|
4
|
+
cssPrefix: pf-c-timestamp
|
|
5
|
+
propComponents: ['Timestamp', 'TimestampTooltip']
|
|
6
|
+
beta: true
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Examples
|
|
10
|
+
|
|
11
|
+
### Default
|
|
12
|
+
|
|
13
|
+
By default, a timestamp will display the current date and time based on the current locale if the `date` prop is not passed in.
|
|
14
|
+
|
|
15
|
+
```ts file="./TimestampDefault.tsx"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Basic formats
|
|
19
|
+
|
|
20
|
+
The format of the displayed content can be customized by passing in the `dateFormat` and/or `timeFormat` props. Passing in only one of the props will display only the date or time, depending on which prop is passed in. The possible options are "full", "long", "medium", and "short".
|
|
21
|
+
|
|
22
|
+
You can also pass in the `displaySuffix` prop to display a custom suffix at the end of the displayed content. This will not override a timezone that is already displayed from the applied time format.
|
|
23
|
+
|
|
24
|
+
```ts file="./TimestampBasicFormats.tsx"
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Custom format
|
|
28
|
+
|
|
29
|
+
The format of the displayed content can be further customized by passing in the `customFormat` prop. Read [datetime format options](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#options) for a list of options that can be passed in.
|
|
30
|
+
|
|
31
|
+
```ts file="./TimestampCustomFormat.tsx"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Default tooltip
|
|
35
|
+
|
|
36
|
+
To render a tooltip that displays the timestamp content as a UTC time, you can pass in the `tooltip` prop with a variant of "default". The format of the default tooltip content will match the format of the timestamp content.
|
|
37
|
+
|
|
38
|
+
You can customize the suffix of this default tooltip variant by passing in `suffix` to the `tooltip` prop.
|
|
39
|
+
|
|
40
|
+
```ts file="./TimestampDefaultTooltip.tsx"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Custom content
|
|
44
|
+
|
|
45
|
+
To display custom content, such as a relative time or prefacing text, you can pass in content to the `children` prop.
|
|
46
|
+
|
|
47
|
+
When also rendering a default tooltip with the `tooltip` prop, you can pass in the `dateFormat` and/or `timeFormat` props to customize the tooltip content without affecting the custom timestamp content.
|
|
48
|
+
|
|
49
|
+
```ts file="TimestampCustomContent.tsx"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Custom tooltip
|
|
53
|
+
|
|
54
|
+
By passing in `variant="custom"` and `content` to the `tooltip` prop, you can display custom content within the timestamp's tooltip.
|
|
55
|
+
|
|
56
|
+
```ts file="TimestampCustomTooltip.tsx"
|
|
57
|
+
```
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Timestamp, TimestampFormat } from '@patternfly/react-core';
|
|
3
|
+
|
|
4
|
+
export const TimestampBasicFormats: React.FunctionComponent = () => {
|
|
5
|
+
const currentDate = new Date();
|
|
6
|
+
|
|
7
|
+
return (
|
|
8
|
+
<>
|
|
9
|
+
<Timestamp date={currentDate} dateFormat={TimestampFormat.full} timeFormat={TimestampFormat.full} />
|
|
10
|
+
<br />
|
|
11
|
+
<br />
|
|
12
|
+
<Timestamp date={currentDate} dateFormat={TimestampFormat.full} />
|
|
13
|
+
<br />
|
|
14
|
+
<br />
|
|
15
|
+
<Timestamp date={currentDate} timeFormat={TimestampFormat.full} />
|
|
16
|
+
<br />
|
|
17
|
+
<br />
|
|
18
|
+
<Timestamp
|
|
19
|
+
date={currentDate}
|
|
20
|
+
dateFormat={TimestampFormat.medium}
|
|
21
|
+
timeFormat={TimestampFormat.short}
|
|
22
|
+
displaySuffix="US Eastern"
|
|
23
|
+
/>
|
|
24
|
+
</>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Timestamp, TimestampFormat, TimestampTooltipVariant } from '@patternfly/react-core';
|
|
3
|
+
|
|
4
|
+
export const TimestampCustomContent: React.FunctionComponent = () => (
|
|
5
|
+
<>
|
|
6
|
+
<Timestamp date={new Date(2022, 7, 9, 14, 57, 0)} tooltip={{ variant: TimestampTooltipVariant.default }}>
|
|
7
|
+
1 hour ago
|
|
8
|
+
</Timestamp>
|
|
9
|
+
<br />
|
|
10
|
+
<br />
|
|
11
|
+
<Timestamp
|
|
12
|
+
date={new Date(2022, 7, 9, 14, 57, 0)}
|
|
13
|
+
dateFormat={TimestampFormat.medium}
|
|
14
|
+
timeFormat={TimestampFormat.short}
|
|
15
|
+
tooltip={{ variant: TimestampTooltipVariant.default }}
|
|
16
|
+
>
|
|
17
|
+
Last updated August 9th, 2022 at 2:57 PM EDT
|
|
18
|
+
</Timestamp>
|
|
19
|
+
</>
|
|
20
|
+
);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Timestamp } from '@patternfly/react-core';
|
|
3
|
+
|
|
4
|
+
export const TimestampCustomFormat: React.FunctionComponent = () => (
|
|
5
|
+
<Timestamp customFormat={{ year: '2-digit', month: 'short', weekday: 'short', day: 'numeric', hour: 'numeric' }} />
|
|
6
|
+
);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Timestamp, TimestampTooltipVariant } from '@patternfly/react-core';
|
|
3
|
+
|
|
4
|
+
export const TimestampCustomTooltip: React.FunctionComponent = () => (
|
|
5
|
+
<>
|
|
6
|
+
<Timestamp
|
|
7
|
+
date={new Date(2022, 7, 9, 14, 57, 0)}
|
|
8
|
+
tooltip={{ variant: TimestampTooltipVariant.custom, content: 'Last updated on August 9th, 2022 - 2:57 PM UTC' }}
|
|
9
|
+
/>
|
|
10
|
+
<br />
|
|
11
|
+
<br />
|
|
12
|
+
<Timestamp
|
|
13
|
+
date={new Date(2022, 9, 31)}
|
|
14
|
+
tooltip={{ variant: TimestampTooltipVariant.custom, content: '31st of October, 2022' }}
|
|
15
|
+
>
|
|
16
|
+
Halloween
|
|
17
|
+
</Timestamp>
|
|
18
|
+
</>
|
|
19
|
+
);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Timestamp, TimestampTooltipVariant } from '@patternfly/react-core';
|
|
3
|
+
|
|
4
|
+
export const TimestampDefaultTooltip: React.FunctionComponent = () => {
|
|
5
|
+
const currentDate = new Date();
|
|
6
|
+
|
|
7
|
+
return (
|
|
8
|
+
<>
|
|
9
|
+
<Timestamp date={currentDate} tooltip={{ variant: TimestampTooltipVariant.default }} />
|
|
10
|
+
<br />
|
|
11
|
+
<br />
|
|
12
|
+
<Timestamp
|
|
13
|
+
date={currentDate}
|
|
14
|
+
tooltip={{ variant: TimestampTooltipVariant.default, suffix: 'Coordinated Universal Time' }}
|
|
15
|
+
/>
|
|
16
|
+
</>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Timestamp';
|
package/src/components/index.ts
CHANGED
package/src/demos/Button.md
CHANGED
|
@@ -5,10 +5,14 @@ section: components
|
|
|
5
5
|
|
|
6
6
|
import CheckCircleIcon from '@patternfly/react-icons/dist/esm/icons/check-circle-icon';
|
|
7
7
|
|
|
8
|
-
## Demos
|
|
8
|
+
## Demos
|
|
9
9
|
|
|
10
10
|
### Progress button
|
|
11
11
|
|
|
12
|
+
The following demo shows the intended flow for a button that visually indicates progress. This example demonstrates a login process, which updates the button label based on the `loginState`.
|
|
13
|
+
|
|
14
|
+
Please note that only the button can be interacted with in this example. The username and password input fields cannot be edited as the focus is on the button behavior.
|
|
15
|
+
|
|
12
16
|
```ts
|
|
13
17
|
import React from 'react';
|
|
14
18
|
import { Form, FormGroup, ActionGroup, InputGroup, TextInput, Button } from '@patternfly/react-core';
|
|
@@ -8,21 +8,21 @@ import BellIcon from '@patternfly/react-icons/dist/esm/icons/bell-icon';
|
|
|
8
8
|
export const ComposableActionsMenu: React.FunctionComponent = () => {
|
|
9
9
|
const [isOpen, setIsOpen] = React.useState<boolean>(false);
|
|
10
10
|
const [selectedItems, setSelectedItems] = React.useState<number[]>([]);
|
|
11
|
-
const toggleRef = React.useRef<HTMLButtonElement>();
|
|
12
|
-
const menuRef = React.useRef<HTMLDivElement>();
|
|
13
|
-
const containerRef = React.useRef<HTMLDivElement>();
|
|
11
|
+
const toggleRef = React.useRef<HTMLButtonElement>(null);
|
|
12
|
+
const menuRef = React.useRef<HTMLDivElement>(null);
|
|
13
|
+
const containerRef = React.useRef<HTMLDivElement>(null);
|
|
14
14
|
|
|
15
15
|
const handleMenuKeys = (event: KeyboardEvent) => {
|
|
16
|
-
if (isOpen && menuRef.current
|
|
16
|
+
if (isOpen && menuRef.current?.contains(event.target as Node)) {
|
|
17
17
|
if (event.key === 'Escape' || event.key === 'Tab') {
|
|
18
18
|
setIsOpen(!isOpen);
|
|
19
|
-
toggleRef.current
|
|
19
|
+
toggleRef.current?.focus();
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
const handleClickOutside = (event: MouseEvent) => {
|
|
25
|
-
if (isOpen && !menuRef.current
|
|
25
|
+
if (isOpen && !menuRef.current?.contains(event.target as Node)) {
|
|
26
26
|
setIsOpen(false);
|
|
27
27
|
}
|
|
28
28
|
};
|
|
@@ -36,7 +36,11 @@ export const ComposableActionsMenu: React.FunctionComponent = () => {
|
|
|
36
36
|
};
|
|
37
37
|
}, [isOpen, menuRef]);
|
|
38
38
|
|
|
39
|
-
const onSelect = (
|
|
39
|
+
const onSelect = (event?: React.MouseEvent, itemId?: string | number) => {
|
|
40
|
+
if (typeof itemId === 'string' || typeof itemId === 'undefined') {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
40
44
|
if (selectedItems.includes(itemId)) {
|
|
41
45
|
setSelectedItems(selectedItems.filter(id => id !== itemId));
|
|
42
46
|
} else {
|
|
@@ -125,7 +129,7 @@ export const ComposableActionsMenu: React.FunctionComponent = () => {
|
|
|
125
129
|
trigger={toggle}
|
|
126
130
|
popper={menu}
|
|
127
131
|
isVisible={isOpen}
|
|
128
|
-
appendTo={containerRef.current}
|
|
132
|
+
appendTo={containerRef.current || undefined}
|
|
129
133
|
popperMatchesTriggerWidth={false}
|
|
130
134
|
/>
|
|
131
135
|
</div>
|
|
@@ -21,24 +21,24 @@ export const ComposableApplicationLauncher: React.FunctionComponent = () => {
|
|
|
21
21
|
const [refFullOptions, setRefFullOptions] = React.useState<Element[]>();
|
|
22
22
|
const [favorites, setFavorites] = React.useState<string[]>([]);
|
|
23
23
|
const [filteredIds, setFilteredIds] = React.useState<string[]>(['*']);
|
|
24
|
-
const menuRef = React.useRef<HTMLDivElement>();
|
|
25
|
-
const toggleRef = React.useRef<HTMLButtonElement>();
|
|
26
|
-
const containerRef = React.useRef<HTMLDivElement>();
|
|
24
|
+
const menuRef = React.useRef<HTMLDivElement>(null);
|
|
25
|
+
const toggleRef = React.useRef<HTMLButtonElement>(null);
|
|
26
|
+
const containerRef = React.useRef<HTMLDivElement>(null);
|
|
27
27
|
|
|
28
28
|
const handleMenuKeys = (event: KeyboardEvent) => {
|
|
29
29
|
if (!isOpen) {
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
32
|
-
if (menuRef.current
|
|
32
|
+
if (menuRef.current?.contains(event.target as Node) || toggleRef.current?.contains(event.target as Node)) {
|
|
33
33
|
if (event.key === 'Escape') {
|
|
34
34
|
setIsOpen(!isOpen);
|
|
35
|
-
toggleRef.current
|
|
35
|
+
toggleRef.current?.focus();
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
};
|
|
39
39
|
|
|
40
40
|
const handleClickOutside = (event: MouseEvent) => {
|
|
41
|
-
if (isOpen && !menuRef.current
|
|
41
|
+
if (isOpen && !menuRef.current?.contains(event.target as Node)) {
|
|
42
42
|
setIsOpen(false);
|
|
43
43
|
}
|
|
44
44
|
};
|
|
@@ -132,7 +132,7 @@ export const ComposableApplicationLauncher: React.FunctionComponent = () => {
|
|
|
132
132
|
];
|
|
133
133
|
|
|
134
134
|
const createFavorites = (favIds: string[]) => {
|
|
135
|
-
const favorites = [];
|
|
135
|
+
const favorites: unknown[] = [];
|
|
136
136
|
|
|
137
137
|
menuItems.forEach(item => {
|
|
138
138
|
if (item.type === MenuList) {
|
|
@@ -219,9 +219,10 @@ export const ComposableApplicationLauncher: React.FunctionComponent = () => {
|
|
|
219
219
|
return;
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
-
const filteredIds =
|
|
223
|
-
|
|
224
|
-
|
|
222
|
+
const filteredIds =
|
|
223
|
+
refFullOptions
|
|
224
|
+
?.filter(item => (item as HTMLElement).innerText.toLowerCase().includes(textValue.toString().toLowerCase()))
|
|
225
|
+
.map(item => item.id) || [];
|
|
225
226
|
setFilteredIds(filteredIds);
|
|
226
227
|
};
|
|
227
228
|
|
|
@@ -275,7 +276,7 @@ export const ComposableApplicationLauncher: React.FunctionComponent = () => {
|
|
|
275
276
|
popper={menu}
|
|
276
277
|
isVisible={isOpen}
|
|
277
278
|
popperMatchesTriggerWidth={false}
|
|
278
|
-
appendTo={containerRef.current}
|
|
279
|
+
appendTo={containerRef.current || undefined}
|
|
279
280
|
/>
|
|
280
281
|
</div>
|
|
281
282
|
);
|
|
@@ -54,39 +54,37 @@ export const ComposableContextSelector: React.FunctionComponent = () => {
|
|
|
54
54
|
'Azure 2'
|
|
55
55
|
];
|
|
56
56
|
const [isOpen, setIsOpen] = React.useState<boolean>(false);
|
|
57
|
-
const [selected, setSelected] = React.useState
|
|
58
|
-
typeof items[0] === 'string' ? items[0] : items[0].text
|
|
59
|
-
);
|
|
57
|
+
const [selected, setSelected] = React.useState(typeof items[0] === 'string' ? items[0] : items[0].text);
|
|
60
58
|
const [filteredItems, setFilteredItems] = React.useState<ItemArrayType>(items);
|
|
61
59
|
const [searchInputValue, setSearchInputValue] = React.useState<string>('');
|
|
62
|
-
const menuRef = React.useRef<HTMLDivElement>();
|
|
63
|
-
const toggleRef = React.useRef<HTMLButtonElement>();
|
|
64
|
-
const menuFooterBtnRef = React.useRef<HTMLButtonElement>();
|
|
65
|
-
const containerRef = React.useRef<HTMLDivElement>();
|
|
60
|
+
const menuRef = React.useRef<HTMLDivElement>(null);
|
|
61
|
+
const toggleRef = React.useRef<HTMLButtonElement>(null);
|
|
62
|
+
const menuFooterBtnRef = React.useRef<HTMLButtonElement>(null);
|
|
63
|
+
const containerRef = React.useRef<HTMLDivElement>(null);
|
|
66
64
|
|
|
67
65
|
const handleMenuKeys = (event: KeyboardEvent) => {
|
|
68
66
|
if (!isOpen) {
|
|
69
67
|
return;
|
|
70
68
|
}
|
|
71
|
-
if (menuFooterBtnRef.current
|
|
69
|
+
if (menuFooterBtnRef.current?.contains(event.target as Node)) {
|
|
72
70
|
if (event.key === 'Tab') {
|
|
73
71
|
if (event.shiftKey) {
|
|
74
72
|
return;
|
|
75
73
|
}
|
|
76
74
|
setIsOpen(!isOpen);
|
|
77
|
-
toggleRef.current
|
|
75
|
+
toggleRef.current?.focus();
|
|
78
76
|
}
|
|
79
77
|
}
|
|
80
|
-
if (menuRef.current
|
|
78
|
+
if (menuRef.current?.contains(event.target as Node)) {
|
|
81
79
|
if (event.key === 'Escape') {
|
|
82
80
|
setIsOpen(!isOpen);
|
|
83
|
-
toggleRef.current
|
|
81
|
+
toggleRef.current?.focus();
|
|
84
82
|
}
|
|
85
83
|
}
|
|
86
84
|
};
|
|
87
85
|
|
|
88
86
|
const handleClickOutside = (event: MouseEvent) => {
|
|
89
|
-
if (isOpen && !menuRef.current
|
|
87
|
+
if (isOpen && !menuRef.current?.contains(event.target as Node)) {
|
|
90
88
|
setIsOpen(false);
|
|
91
89
|
}
|
|
92
90
|
};
|
|
@@ -24,21 +24,21 @@ export const ComposableDrilldownMenu: React.FunctionComponent = () => {
|
|
|
24
24
|
const [menuDrilledIn, setMenuDrilledIn] = React.useState<string[]>([]);
|
|
25
25
|
const [drilldownPath, setDrilldownPath] = React.useState<string[]>([]);
|
|
26
26
|
const [menuHeights, setMenuHeights] = React.useState<MenuHeightsType>({});
|
|
27
|
-
const toggleRef = React.useRef<HTMLButtonElement>();
|
|
28
|
-
const menuRef = React.useRef<HTMLDivElement>();
|
|
29
|
-
const containerRef = React.useRef<HTMLDivElement>();
|
|
27
|
+
const toggleRef = React.useRef<HTMLButtonElement>(null);
|
|
28
|
+
const menuRef = React.useRef<HTMLDivElement>(null);
|
|
29
|
+
const containerRef = React.useRef<HTMLDivElement>(null);
|
|
30
30
|
|
|
31
31
|
const handleMenuKeys = (event: KeyboardEvent) => {
|
|
32
|
-
if (isOpen && menuRef.current
|
|
32
|
+
if (isOpen && menuRef.current?.contains(event.target as Node)) {
|
|
33
33
|
if (event.key === 'Escape' || event.key === 'Tab') {
|
|
34
34
|
setIsOpen(!isOpen);
|
|
35
|
-
toggleRef.current
|
|
35
|
+
toggleRef.current?.focus();
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
};
|
|
39
39
|
|
|
40
40
|
const handleClickOutside = (event: MouseEvent) => {
|
|
41
|
-
if (isOpen && !menuRef.current
|
|
41
|
+
if (isOpen && !menuRef.current?.contains(event.target as Node)) {
|
|
42
42
|
setIsOpen(false);
|
|
43
43
|
}
|
|
44
44
|
};
|
|
@@ -248,7 +248,7 @@ export const ComposableDrilldownMenu: React.FunctionComponent = () => {
|
|
|
248
248
|
<Popper
|
|
249
249
|
trigger={toggle}
|
|
250
250
|
popper={menu}
|
|
251
|
-
appendTo={containerRef.current}
|
|
251
|
+
appendTo={containerRef.current || undefined}
|
|
252
252
|
isVisible={isOpen}
|
|
253
253
|
popperMatchesTriggerWidth={false}
|
|
254
254
|
/>
|
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { MenuToggle, Menu, MenuContent, MenuList, MenuItem, Popper } from '@patternfly/react-core';
|
|
3
3
|
|
|
4
4
|
// eslint-disable-next-line no-console
|
|
5
|
-
const onSelect = (
|
|
5
|
+
const onSelect = (event?: React.MouseEvent, itemId?: string | number) => console.log('selected', itemId);
|
|
6
6
|
|
|
7
7
|
interface FlyoutMenuProps {
|
|
8
8
|
children?: React.ReactElement;
|
|
@@ -31,24 +31,24 @@ const FlyoutMenu: React.FunctionComponent<FlyoutMenuProps> = ({ depth, children
|
|
|
31
31
|
|
|
32
32
|
export const ComposableFlyout: React.FunctionComponent = () => {
|
|
33
33
|
const [isOpen, setIsOpen] = React.useState<boolean>(false);
|
|
34
|
-
const menuRef = React.useRef<HTMLDivElement>();
|
|
35
|
-
const toggleRef = React.useRef<HTMLButtonElement>();
|
|
36
|
-
const containerRef = React.useRef<HTMLDivElement>();
|
|
34
|
+
const menuRef = React.useRef<HTMLDivElement>(null);
|
|
35
|
+
const toggleRef = React.useRef<HTMLButtonElement>(null);
|
|
36
|
+
const containerRef = React.useRef<HTMLDivElement>(null);
|
|
37
37
|
|
|
38
38
|
const handleMenuKeys = (event: KeyboardEvent) => {
|
|
39
39
|
if (!isOpen) {
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
|
-
if (menuRef.current
|
|
42
|
+
if (menuRef.current?.contains(event.target as Node) || toggleRef.current?.contains(event.target as Node)) {
|
|
43
43
|
if (event.key === 'Escape' || event.key === 'Tab') {
|
|
44
44
|
setIsOpen(!isOpen);
|
|
45
|
-
toggleRef.current
|
|
45
|
+
toggleRef.current?.focus();
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
};
|
|
49
49
|
|
|
50
50
|
const handleClickOutside = (event: MouseEvent) => {
|
|
51
|
-
if (isOpen && !menuRef.current
|
|
51
|
+
if (isOpen && !menuRef.current?.contains(event.target as Node)) {
|
|
52
52
|
setIsOpen(false);
|
|
53
53
|
}
|
|
54
54
|
};
|
|
@@ -105,7 +105,7 @@ export const ComposableFlyout: React.FunctionComponent = () => {
|
|
|
105
105
|
<Popper
|
|
106
106
|
trigger={toggle}
|
|
107
107
|
popper={menu}
|
|
108
|
-
appendTo={containerRef.current}
|
|
108
|
+
appendTo={containerRef.current || undefined}
|
|
109
109
|
isVisible={isOpen}
|
|
110
110
|
popperMatchesTriggerWidth={false}
|
|
111
111
|
/>
|