@patternfly/react-core 6.5.0-prerelease.24 → 6.5.0-prerelease.26
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 +12 -0
- package/components/package.json +1 -1
- package/deprecated/package.json +1 -1
- package/dist/dynamic/components/AboutModal/package.json +1 -1
- package/dist/dynamic/components/Accordion/package.json +1 -1
- package/dist/dynamic/components/ActionList/package.json +1 -1
- package/dist/dynamic/components/Alert/package.json +1 -1
- package/dist/dynamic/components/Avatar/package.json +1 -1
- package/dist/dynamic/components/BackToTop/package.json +1 -1
- package/dist/dynamic/components/Backdrop/package.json +1 -1
- package/dist/dynamic/components/BackgroundImage/package.json +1 -1
- package/dist/dynamic/components/Badge/package.json +1 -1
- package/dist/dynamic/components/Banner/package.json +1 -1
- package/dist/dynamic/components/Brand/package.json +1 -1
- package/dist/dynamic/components/Breadcrumb/package.json +1 -1
- package/dist/dynamic/components/Button/package.json +1 -1
- package/dist/dynamic/components/CalendarMonth/package.json +1 -1
- package/dist/dynamic/components/Card/package.json +1 -1
- package/dist/dynamic/components/Checkbox/package.json +1 -1
- package/dist/dynamic/components/ClipboardCopy/package.json +1 -1
- package/dist/dynamic/components/CodeBlock/package.json +1 -1
- package/dist/dynamic/components/Compass/package.json +1 -1
- package/dist/dynamic/components/Content/package.json +1 -1
- package/dist/dynamic/components/DataList/package.json +1 -1
- package/dist/dynamic/components/DatePicker/package.json +1 -1
- package/dist/dynamic/components/DescriptionList/package.json +1 -1
- package/dist/dynamic/components/Divider/package.json +1 -1
- package/dist/dynamic/components/Drawer/package.json +1 -1
- package/dist/dynamic/components/Dropdown/package.json +1 -1
- package/dist/dynamic/components/DualListSelector/package.json +1 -1
- package/dist/dynamic/components/EmptyState/package.json +1 -1
- package/dist/dynamic/components/ExpandableSection/package.json +1 -1
- package/dist/dynamic/components/FileUpload/package.json +1 -1
- package/dist/dynamic/components/Form/package.json +1 -1
- package/dist/dynamic/components/FormSelect/package.json +1 -1
- package/dist/dynamic/components/HelperText/package.json +1 -1
- package/dist/dynamic/components/Hero/package.json +1 -1
- package/dist/dynamic/components/Hint/package.json +1 -1
- package/dist/dynamic/components/Icon/package.json +1 -1
- package/dist/dynamic/components/InputGroup/package.json +1 -1
- package/dist/dynamic/components/JumpLinks/package.json +1 -1
- package/dist/dynamic/components/Label/package.json +1 -1
- package/dist/dynamic/components/List/package.json +1 -1
- package/dist/dynamic/components/LoginPage/package.json +1 -1
- package/dist/dynamic/components/Masthead/package.json +1 -1
- package/dist/dynamic/components/Menu/package.json +1 -1
- package/dist/dynamic/components/MenuToggle/package.json +1 -1
- package/dist/dynamic/components/Modal/package.json +1 -1
- package/dist/dynamic/components/MultipleFileUpload/package.json +1 -1
- package/dist/dynamic/components/Nav/package.json +1 -1
- package/dist/dynamic/components/NotificationBadge/package.json +1 -1
- package/dist/dynamic/components/NotificationDrawer/package.json +1 -1
- package/dist/dynamic/components/NumberInput/package.json +1 -1
- package/dist/dynamic/components/OverflowMenu/package.json +1 -1
- package/dist/dynamic/components/Page/package.json +1 -1
- package/dist/dynamic/components/Pagination/package.json +1 -1
- package/dist/dynamic/components/Panel/package.json +1 -1
- package/dist/dynamic/components/Popover/package.json +1 -1
- package/dist/dynamic/components/Progress/package.json +1 -1
- package/dist/dynamic/components/ProgressStepper/package.json +1 -1
- package/dist/dynamic/components/Radio/package.json +1 -1
- package/dist/dynamic/components/SearchInput/package.json +1 -1
- package/dist/dynamic/components/Select/package.json +1 -1
- package/dist/dynamic/components/Sidebar/package.json +1 -1
- package/dist/dynamic/components/SimpleList/package.json +1 -1
- package/dist/dynamic/components/Skeleton/package.json +1 -1
- package/dist/dynamic/components/SkipToContent/package.json +1 -1
- package/dist/dynamic/components/Slider/package.json +1 -1
- package/dist/dynamic/components/Spinner/package.json +1 -1
- package/dist/dynamic/components/Switch/package.json +1 -1
- package/dist/dynamic/components/Tabs/package.json +1 -1
- package/dist/dynamic/components/TextArea/package.json +1 -1
- package/dist/dynamic/components/TextInput/package.json +1 -1
- package/dist/dynamic/components/TextInputGroup/package.json +1 -1
- package/dist/dynamic/components/TimePicker/package.json +1 -1
- package/dist/dynamic/components/Timestamp/package.json +1 -1
- package/dist/dynamic/components/Title/package.json +1 -1
- package/dist/dynamic/components/ToggleGroup/package.json +1 -1
- package/dist/dynamic/components/Toolbar/package.json +1 -1
- package/dist/dynamic/components/Tooltip/package.json +1 -1
- package/dist/dynamic/components/TreeView/package.json +1 -1
- package/dist/dynamic/components/Truncate/package.json +1 -1
- package/dist/dynamic/components/Wizard/hooks/package.json +1 -1
- package/dist/dynamic/components/Wizard/package.json +1 -1
- package/dist/dynamic/deprecated/components/Chip/package.json +1 -1
- package/dist/dynamic/deprecated/components/DragDrop/package.json +1 -1
- package/dist/dynamic/deprecated/components/DualListSelector/package.json +1 -1
- package/dist/dynamic/deprecated/components/Modal/package.json +1 -1
- package/dist/dynamic/deprecated/components/Tile/package.json +1 -1
- package/dist/dynamic/deprecated/components/Wizard/package.json +1 -1
- package/dist/dynamic/deprecated/components/package.json +1 -1
- package/dist/dynamic/helpers/AnimationsProvider/AnimationsProvider/package.json +1 -1
- package/dist/dynamic/helpers/AnimationsProvider/package.json +1 -1
- package/dist/dynamic/helpers/FocusTrap/FocusTrap/package.json +1 -1
- package/dist/dynamic/helpers/GenerateId/GenerateId/package.json +1 -1
- package/dist/dynamic/helpers/KeyboardHandler/package.json +1 -1
- package/dist/dynamic/helpers/OUIA/ouia/package.json +1 -1
- package/dist/dynamic/helpers/Popper/Popper/package.json +1 -1
- package/dist/dynamic/helpers/constants/package.json +1 -1
- package/dist/dynamic/helpers/datetimeUtils/package.json +1 -1
- package/dist/dynamic/helpers/fileUtils/package.json +1 -1
- package/dist/dynamic/helpers/htmlConstants/package.json +1 -1
- package/dist/dynamic/helpers/package.json +1 -1
- package/dist/dynamic/helpers/resizeObserver/package.json +1 -1
- package/dist/dynamic/helpers/typeUtils/package.json +1 -1
- package/dist/dynamic/helpers/useInterval/package.json +1 -1
- package/dist/dynamic/helpers/useIsomorphicLayout/package.json +1 -1
- package/dist/dynamic/helpers/useUnmountEffect/package.json +1 -1
- package/dist/dynamic/helpers/util/package.json +1 -1
- package/dist/dynamic/layouts/Bullseye/package.json +1 -1
- package/dist/dynamic/layouts/Flex/package.json +1 -1
- package/dist/dynamic/layouts/Gallery/package.json +1 -1
- package/dist/dynamic/layouts/Grid/package.json +1 -1
- package/dist/dynamic/layouts/Level/package.json +1 -1
- package/dist/dynamic/layouts/Split/package.json +1 -1
- package/dist/dynamic/layouts/Stack/package.json +1 -1
- package/dist/dynamic/styles/package.json +1 -1
- package/dist/esm/components/ClipboardCopy/ClipboardCopy.d.ts +8 -0
- package/dist/esm/components/ClipboardCopy/ClipboardCopy.d.ts.map +1 -1
- package/dist/esm/components/ClipboardCopy/ClipboardCopy.js +4 -2
- package/dist/esm/components/ClipboardCopy/ClipboardCopy.js.map +1 -1
- package/dist/esm/components/Label/Label.js +1 -1
- package/dist/esm/components/Label/Label.js.map +1 -1
- package/dist/js/components/ClipboardCopy/ClipboardCopy.d.ts +8 -0
- package/dist/js/components/ClipboardCopy/ClipboardCopy.d.ts.map +1 -1
- package/dist/js/components/ClipboardCopy/ClipboardCopy.js +4 -2
- package/dist/js/components/ClipboardCopy/ClipboardCopy.js.map +1 -1
- package/dist/js/components/Label/Label.js +1 -1
- package/dist/js/components/Label/Label.js.map +1 -1
- package/dist/umd/assets/{output-BbsSnXfK.css → output-BOKd1GXO.css} +18528 -18528
- package/dist/umd/react-core.min.js +2 -2
- package/helpers/package.json +1 -1
- package/layouts/package.json +1 -1
- package/next/package.json +1 -1
- package/package.json +2 -2
- package/src/components/ClipboardCopy/ClipboardCopy.tsx +16 -1
- package/src/components/ClipboardCopy/__tests__/ClipboardCopy.test.tsx +72 -0
- package/src/components/ClipboardCopy/__tests__/__snapshots__/ClipboardCopy.test.tsx.snap +1 -1
- package/src/components/Dropdown/examples/Dropdown.md +13 -1
- package/src/components/Dropdown/examples/DropdownWithSplit.tsx +97 -0
- package/src/components/Label/Label.tsx +1 -1
- package/src/demos/Banner.md +2 -139
- package/src/demos/DateTimePicker.md +2 -86
- package/src/demos/JumpLinks.md +2 -129
- package/src/demos/ProgressDemo.md +2 -65
- package/src/demos/ProgressStepperDemo.md +1 -72
- package/src/demos/Tabs.md +6 -417
- package/src/demos/examples/Banner/BannerBasicSticky.tsx +55 -0
- package/src/demos/examples/Banner/BannerTopBottom.tsx +81 -0
- package/src/demos/examples/DateTimePicker/DateTimeRangePicker.tsx +93 -0
- package/src/demos/examples/JumpLinks/JumpLinksScrollspy.tsx +125 -0
- package/src/demos/examples/JumpLinks/{JumpLinksWithDrawer.js → JumpLinksWithDrawer.tsx} +1 -1
- package/src/demos/examples/Progress/ProgressBasic.tsx +32 -0
- package/src/demos/examples/Progress/ProgressWithOnlyIncreasing.tsx +33 -0
- package/src/demos/examples/ProgressStepper/ProgressStepperBasic.tsx +72 -0
- package/src/demos/examples/Tabs/TabsOpen.tsx +185 -0
- package/src/demos/examples/Tabs/TabsOpenWithSecondaryTabs.tsx +228 -0
- package/src/layouts/Gallery/examples/Gallery.md +8 -99
- package/src/layouts/Gallery/examples/GalleryAdjustingMaxWidths.tsx +21 -0
- package/src/layouts/Gallery/examples/GalleryAdjustingMinMaxWidths.tsx +25 -0
- package/src/layouts/Gallery/examples/GalleryAdjustingMinWidths.tsx +22 -0
- package/src/layouts/Gallery/examples/GalleryAlternativeComponents.tsx +11 -0
- package/src/layouts/Gallery/examples/GalleryBasic.tsx +14 -0
- package/src/layouts/Gallery/examples/GalleryWithGutters.tsx +12 -0
package/helpers/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@patternfly/react-core-helpers","main":"../dist/js/helpers/index.js","module":"../dist/esm/helpers/index.js","typings":"../dist/esm/helpers/index.d.ts","version":"6.5.0-prerelease.
|
|
1
|
+
{"name":"@patternfly/react-core-helpers","main":"../dist/js/helpers/index.js","module":"../dist/esm/helpers/index.js","typings":"../dist/esm/helpers/index.d.ts","version":"6.5.0-prerelease.25","private":true}
|
package/layouts/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@patternfly/react-core-layouts","main":"../dist/js/layouts/index.js","module":"../dist/esm/layouts/index.js","typings":"../dist/esm/layouts/index.d.ts","version":"6.5.0-prerelease.
|
|
1
|
+
{"name":"@patternfly/react-core-layouts","main":"../dist/js/layouts/index.js","module":"../dist/esm/layouts/index.js","typings":"../dist/esm/layouts/index.d.ts","version":"6.5.0-prerelease.25","private":true}
|
package/next/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@patternfly/react-core-next","main":"../dist/js/next/index.js","module":"../dist/esm/next/index.js","typings":"../dist/esm/next/index.d.ts","version":"6.5.0-prerelease.
|
|
1
|
+
{"name":"@patternfly/react-core-next","main":"../dist/js/next/index.js","module":"../dist/esm/next/index.js","typings":"../dist/esm/next/index.d.ts","version":"6.5.0-prerelease.25","private":true}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patternfly/react-core",
|
|
3
|
-
"version": "6.5.0-prerelease.
|
|
3
|
+
"version": "6.5.0-prerelease.26",
|
|
4
4
|
"description": "This library provides a set of common React components for use with the PatternFly reference implementation.",
|
|
5
5
|
"main": "dist/js/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -63,5 +63,5 @@
|
|
|
63
63
|
"react": "^17 || ^18 || ^19",
|
|
64
64
|
"react-dom": "^17 || ^18 || ^19"
|
|
65
65
|
},
|
|
66
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "296178f84f2073ea2034858f812ab6d5dd03f3f0"
|
|
67
67
|
}
|
|
@@ -55,6 +55,10 @@ export interface ClipboardCopyProps extends Omit<React.HTMLProps<HTMLDivElement>
|
|
|
55
55
|
textAriaLabel?: string;
|
|
56
56
|
/** Aria-label to use on the ClipboardCopyToggle. */
|
|
57
57
|
toggleAriaLabel?: string;
|
|
58
|
+
/** ID to use on the TextInput. */
|
|
59
|
+
inputId?: string;
|
|
60
|
+
/** Name attribute to use on the TextInput. */
|
|
61
|
+
inputName?: string;
|
|
58
62
|
/** Flag to show if the input is read only. */
|
|
59
63
|
isReadOnly?: boolean;
|
|
60
64
|
/** Flag to determine if clipboard copy is in the expanded state initially */
|
|
@@ -91,6 +95,10 @@ export interface ClipboardCopyProps extends Omit<React.HTMLProps<HTMLDivElement>
|
|
|
91
95
|
onCopy?: (event: React.ClipboardEvent<HTMLDivElement>, text?: React.ReactNode) => void;
|
|
92
96
|
/** A function that is triggered on changing the text. */
|
|
93
97
|
onChange?: (event: React.FormEvent, text?: string) => void;
|
|
98
|
+
/** Callback function when text input is focused */
|
|
99
|
+
onInputFocus?: (event?: any) => void;
|
|
100
|
+
/** Callback function when text input is blurred (focus leaves) */
|
|
101
|
+
onInputBlur?: (event?: any) => void;
|
|
94
102
|
/** The text which is copied. */
|
|
95
103
|
children: string | string[];
|
|
96
104
|
/** Additional actions for inline clipboard copy. Should be wrapped with ClipboardCopyAction. */
|
|
@@ -177,6 +185,8 @@ class ClipboardCopy extends Component<ClipboardCopyProps, ClipboardCopyState> {
|
|
|
177
185
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
178
186
|
isExpanded,
|
|
179
187
|
onChange, // Don't pass to <div>
|
|
188
|
+
onInputFocus, // Don't pass to <div>
|
|
189
|
+
onInputBlur, // Don't pass to <div>
|
|
180
190
|
/* eslint-enable @typescript-eslint/no-unused-vars */
|
|
181
191
|
isReadOnly,
|
|
182
192
|
isCode,
|
|
@@ -189,6 +199,8 @@ class ClipboardCopy extends Component<ClipboardCopyProps, ClipboardCopyState> {
|
|
|
189
199
|
clickTip,
|
|
190
200
|
textAriaLabel,
|
|
191
201
|
toggleAriaLabel,
|
|
202
|
+
inputId,
|
|
203
|
+
inputName,
|
|
192
204
|
variant,
|
|
193
205
|
position,
|
|
194
206
|
className,
|
|
@@ -295,8 +307,11 @@ class ClipboardCopy extends Component<ClipboardCopyProps, ClipboardCopyState> {
|
|
|
295
307
|
readOnlyVariant={isReadOnly || this.state.expanded ? 'default' : undefined}
|
|
296
308
|
onChange={this.updateText}
|
|
297
309
|
value={this.state.expanded ? this.state.textWhenExpanded : copyableText}
|
|
298
|
-
id={`text-input-${id}`}
|
|
310
|
+
id={inputId ?? `text-input-${id}`}
|
|
311
|
+
name={inputName}
|
|
299
312
|
aria-label={textAriaLabel}
|
|
313
|
+
onFocus={onInputFocus}
|
|
314
|
+
onBlur={onInputBlur}
|
|
300
315
|
{...(isCode && { dir: 'ltr' })}
|
|
301
316
|
/>
|
|
302
317
|
<ClipboardCopyButton
|
|
@@ -309,6 +309,18 @@ test('Passes textAriaLabel to TextInput', () => {
|
|
|
309
309
|
expect(screen.getByRole('textbox')).toHaveAccessibleName('text label');
|
|
310
310
|
});
|
|
311
311
|
|
|
312
|
+
test('Passes inputId to TextInput', () => {
|
|
313
|
+
render(<ClipboardCopy inputId="custom-input-id">{children}</ClipboardCopy>);
|
|
314
|
+
|
|
315
|
+
expect(screen.getByRole('textbox')).toHaveAttribute('id', 'custom-input-id');
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
test('Passes inputName to TextInput', () => {
|
|
319
|
+
render(<ClipboardCopy inputName="custom-input-name">{children}</ClipboardCopy>);
|
|
320
|
+
|
|
321
|
+
expect(screen.getByRole('textbox')).toHaveAttribute('name', 'custom-input-name');
|
|
322
|
+
});
|
|
323
|
+
|
|
312
324
|
test('Calls onChange when ClipboardCopy textinput is typed in', async () => {
|
|
313
325
|
const onChangeMock = jest.fn();
|
|
314
326
|
const user = userEvent.setup();
|
|
@@ -338,6 +350,66 @@ test('Does not call onChange when ClipboardCopy textinput is not typed in', asyn
|
|
|
338
350
|
expect(onChangeMock).not.toHaveBeenCalled();
|
|
339
351
|
});
|
|
340
352
|
|
|
353
|
+
test('Calls onFocus when ClipboardCopy textinput is focused', async () => {
|
|
354
|
+
const onFocusMock = jest.fn();
|
|
355
|
+
const user = userEvent.setup();
|
|
356
|
+
|
|
357
|
+
render(<ClipboardCopy onInputFocus={onFocusMock}>{children}</ClipboardCopy>);
|
|
358
|
+
|
|
359
|
+
await user.click(screen.getByRole('textbox'));
|
|
360
|
+
|
|
361
|
+
expect(onFocusMock).toHaveBeenCalledTimes(1);
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
test('Does not call onFocus when ClipboardCopy textinput is not focused', async () => {
|
|
365
|
+
const onFocusMock = jest.fn();
|
|
366
|
+
const user = userEvent.setup();
|
|
367
|
+
|
|
368
|
+
render(
|
|
369
|
+
<>
|
|
370
|
+
<ClipboardCopy onInputFocus={onFocusMock}>{children}</ClipboardCopy>
|
|
371
|
+
<input aria-label="native input" />
|
|
372
|
+
</>
|
|
373
|
+
);
|
|
374
|
+
|
|
375
|
+
await user.click(screen.getByRole('textbox', { name: 'native input' }));
|
|
376
|
+
|
|
377
|
+
expect(onFocusMock).not.toHaveBeenCalled();
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
test('Calls onBlur when ClipboardCopy textinput loses focus', async () => {
|
|
381
|
+
const onBlurMock = jest.fn();
|
|
382
|
+
const user = userEvent.setup();
|
|
383
|
+
|
|
384
|
+
render(
|
|
385
|
+
<>
|
|
386
|
+
<ClipboardCopy onInputBlur={onBlurMock}>{children}</ClipboardCopy>
|
|
387
|
+
<input aria-label="native input" />
|
|
388
|
+
</>
|
|
389
|
+
);
|
|
390
|
+
|
|
391
|
+
await user.click(screen.getByRole('textbox', { name: 'Copyable input' }));
|
|
392
|
+
await user.click(screen.getByRole('textbox', { name: 'native input' }));
|
|
393
|
+
|
|
394
|
+
expect(onBlurMock).toHaveBeenCalledTimes(1);
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
test('Does not call onBlur when ClipboardCopy textinput does not lose focus', async () => {
|
|
398
|
+
const onBlurMock = jest.fn();
|
|
399
|
+
const user = userEvent.setup();
|
|
400
|
+
|
|
401
|
+
render(
|
|
402
|
+
<>
|
|
403
|
+
<ClipboardCopy onInputBlur={onBlurMock}>{children}</ClipboardCopy>
|
|
404
|
+
<input aria-label="native input" />
|
|
405
|
+
</>
|
|
406
|
+
);
|
|
407
|
+
|
|
408
|
+
await user.click(screen.getByRole('textbox', { name: 'native input' }));
|
|
409
|
+
|
|
410
|
+
expect(onBlurMock).not.toHaveBeenCalled();
|
|
411
|
+
});
|
|
412
|
+
|
|
341
413
|
test('Calls onCopy when ClipboardCopyButton is clicked', async () => {
|
|
342
414
|
const onCopyMock = jest.fn();
|
|
343
415
|
const user = userEvent.setup();
|
|
@@ -18,7 +18,7 @@ exports[`Matches snapshot 1`] = `
|
|
|
18
18
|
<input
|
|
19
19
|
aria-invalid="false"
|
|
20
20
|
aria-label="Copyable input"
|
|
21
|
-
data-ouia-component-id="OUIA-Generated-TextInputBase-
|
|
21
|
+
data-ouia-component-id="OUIA-Generated-TextInputBase-42"
|
|
22
22
|
data-ouia-component-type="PF6/TextInput"
|
|
23
23
|
data-ouia-safe="true"
|
|
24
24
|
id="text-input-generated-id"
|
|
@@ -16,7 +16,7 @@ propComponents:
|
|
|
16
16
|
]
|
|
17
17
|
---
|
|
18
18
|
|
|
19
|
-
import { useState } from 'react';
|
|
19
|
+
import { useState, useRef } from 'react';
|
|
20
20
|
import EllipsisVIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon';
|
|
21
21
|
|
|
22
22
|
## Examples
|
|
@@ -63,3 +63,15 @@ To provide users with more context about a `<DropdownItem>`, pass a short messag
|
|
|
63
63
|
```ts file="./DropdownWithDescriptions.tsx"
|
|
64
64
|
|
|
65
65
|
```
|
|
66
|
+
|
|
67
|
+
### Split toggle with checkbox
|
|
68
|
+
|
|
69
|
+
To combine a checkbox or other control with a dropdown menu, use a split button.
|
|
70
|
+
|
|
71
|
+
A `<MenuToggle>` can be rendered as a split button via `splitButtonItems`. Elements to be displayed before the dropdown toggle button (like the `<MenuToggleCheckbox>`) must be included in the `splitButtonItems`.
|
|
72
|
+
|
|
73
|
+
If the dropdown menu closes upon selection, you will need to manually shift focus back to the toggle element after a user selects an item from the menu.
|
|
74
|
+
|
|
75
|
+
```ts file="./DropdownWithSplit.tsx"
|
|
76
|
+
|
|
77
|
+
```
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Dropdown,
|
|
3
|
+
MenuToggle,
|
|
4
|
+
MenuToggleCheckbox,
|
|
5
|
+
DropdownItem,
|
|
6
|
+
DropdownList,
|
|
7
|
+
Divider,
|
|
8
|
+
MenuToggleElement
|
|
9
|
+
} from '@patternfly/react-core';
|
|
10
|
+
import { useRef, useState } from 'react';
|
|
11
|
+
|
|
12
|
+
export const DropdownSplitButtonText: React.FunctionComponent = () => {
|
|
13
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
14
|
+
const toggleRef = useRef<MenuToggleElement>(null);
|
|
15
|
+
|
|
16
|
+
const onFocus = () => {
|
|
17
|
+
if (!toggleRef.current) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const toggleButton = toggleRef.current.querySelector('button[aria-expanded]');
|
|
22
|
+
toggleButton?.focus();
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const onSelect = () => {
|
|
26
|
+
setIsOpen(false);
|
|
27
|
+
onFocus();
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const onToggleClick = () => {
|
|
31
|
+
setIsOpen(!isOpen);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<Dropdown
|
|
36
|
+
onSelect={onSelect}
|
|
37
|
+
onOpenChange={(isOpen: boolean) => setIsOpen(isOpen)}
|
|
38
|
+
toggle={(toggleRefCallback: React.Ref<MenuToggleElement>) => (
|
|
39
|
+
<MenuToggle
|
|
40
|
+
ref={(node) => {
|
|
41
|
+
// Handle both callback ref and useRef
|
|
42
|
+
if (typeof toggleRefCallback === 'function') {
|
|
43
|
+
toggleRefCallback(node);
|
|
44
|
+
} else if (toggleRefCallback) {
|
|
45
|
+
(toggleRefCallback as React.MutableRefObject<MenuToggleElement | null>).current = node;
|
|
46
|
+
}
|
|
47
|
+
(toggleRef as React.MutableRefObject<MenuToggleElement | null>).current = node;
|
|
48
|
+
}}
|
|
49
|
+
splitButtonItems={[
|
|
50
|
+
<MenuToggleCheckbox id="split-button-checkbox-example" key="split-checkbox" aria-label="Select all" />
|
|
51
|
+
]}
|
|
52
|
+
aria-label="Dropdown with checkbox split button"
|
|
53
|
+
onClick={onToggleClick}
|
|
54
|
+
isExpanded={isOpen}
|
|
55
|
+
/>
|
|
56
|
+
)}
|
|
57
|
+
isOpen={isOpen}
|
|
58
|
+
>
|
|
59
|
+
<DropdownList>
|
|
60
|
+
<DropdownItem value={0} key="action">
|
|
61
|
+
Action
|
|
62
|
+
</DropdownItem>
|
|
63
|
+
<DropdownItem
|
|
64
|
+
value={1}
|
|
65
|
+
key="link"
|
|
66
|
+
to="#default-link2"
|
|
67
|
+
// Prevent the default onClick functionality for example purposes
|
|
68
|
+
onClick={(ev: any) => ev.preventDefault()}
|
|
69
|
+
>
|
|
70
|
+
Link
|
|
71
|
+
</DropdownItem>
|
|
72
|
+
<DropdownItem value={2} isDisabled key="disabled action">
|
|
73
|
+
Disabled Action
|
|
74
|
+
</DropdownItem>
|
|
75
|
+
<DropdownItem value={3} isDisabled key="disabled link" to="#default-link4">
|
|
76
|
+
Disabled Link
|
|
77
|
+
</DropdownItem>
|
|
78
|
+
<DropdownItem
|
|
79
|
+
value={4}
|
|
80
|
+
isAriaDisabled
|
|
81
|
+
key="aria-disabled link"
|
|
82
|
+
to="#default-link5"
|
|
83
|
+
tooltipProps={{ content: 'aria-disabled link', position: 'top' }}
|
|
84
|
+
>
|
|
85
|
+
Aria-disabled Link
|
|
86
|
+
</DropdownItem>
|
|
87
|
+
<Divider component="li" key="separator" />
|
|
88
|
+
<DropdownItem value={5} key="separated action">
|
|
89
|
+
Separated Action
|
|
90
|
+
</DropdownItem>
|
|
91
|
+
<DropdownItem value={6} key="separated link" to="#default-link6" onClick={(ev) => ev.preventDefault()}>
|
|
92
|
+
Separated Link
|
|
93
|
+
</DropdownItem>
|
|
94
|
+
</DropdownList>
|
|
95
|
+
</Dropdown>
|
|
96
|
+
);
|
|
97
|
+
};
|
|
@@ -338,7 +338,7 @@ export const Label: React.FunctionComponent<LabelProps> = ({
|
|
|
338
338
|
);
|
|
339
339
|
}
|
|
340
340
|
|
|
341
|
-
const LabelComponent = (isOverflowLabel ? 'button' : 'span') as any;
|
|
341
|
+
const LabelComponent = (isOverflowLabel || isAddLabel ? 'button' : 'span') as any;
|
|
342
342
|
|
|
343
343
|
return (
|
|
344
344
|
<LabelComponent
|
package/src/demos/Banner.md
CHANGED
|
@@ -11,148 +11,11 @@ import { DashboardWrapper } from '@patternfly/react-core/dist/js/demos/Dashboard
|
|
|
11
11
|
|
|
12
12
|
### Basic sticky banner
|
|
13
13
|
|
|
14
|
-
```
|
|
15
|
-
import { Fragment } from 'react';
|
|
16
|
-
import { Banner, Card, CardBody, Flex, Gallery, GalleryItem, PageSection, Content } from '@patternfly/react-core';
|
|
17
|
-
|
|
18
|
-
import { DashboardWrapper } from '@patternfly/react-core/dist/js/demos/DashboardWrapper';
|
|
19
|
-
import { css } from '@patternfly/react-styles';
|
|
20
|
-
import display from '@patternfly/react-styles/css/utilities/Display/display';
|
|
21
|
-
|
|
22
|
-
class BannerDemo extends React.Component {
|
|
23
|
-
render() {
|
|
24
|
-
const banner = (
|
|
25
|
-
<Banner isSticky>
|
|
26
|
-
<Flex
|
|
27
|
-
justifyContent={{ default: 'justifyContentCenter', lg: 'justifyContentSpaceBetween' }}
|
|
28
|
-
flexWrap={{ default: 'nowrap' }}
|
|
29
|
-
>
|
|
30
|
-
<div className={css(display.displayNone, display.displayBlockOnLg)}>Localhost</div>
|
|
31
|
-
<div className={css(display.displayNone, display.displayBlockOnLg)}>
|
|
32
|
-
This message is sticky to the top of the page.
|
|
33
|
-
</div>
|
|
34
|
-
<div className={css(display.displayNoneOnLg)}>Drop some text on mobile, truncate if needed.</div>
|
|
35
|
-
<div className={css(display.displayNone, display.displayBlockOnLg)}>Ned Username</div>
|
|
36
|
-
</Flex>
|
|
37
|
-
</Banner>
|
|
38
|
-
);
|
|
39
|
-
return (
|
|
40
|
-
<Fragment>
|
|
41
|
-
<DashboardWrapper banner={banner} breadcrumb={null}>
|
|
42
|
-
<PageSection aria-labelledby="main-title">
|
|
43
|
-
<Content>
|
|
44
|
-
<h1 id="main-title">Main title</h1>
|
|
45
|
-
<p>
|
|
46
|
-
Body text should be Red Hat Text at 1rem(16px). It should have leading of 1.5rem(24px) because <br />
|
|
47
|
-
of it’s relative line height of 1.5.
|
|
48
|
-
</p>
|
|
49
|
-
</Content>
|
|
50
|
-
</PageSection>
|
|
51
|
-
<PageSection aria-label='Cards gallery'>
|
|
52
|
-
<Gallery hasGutter>
|
|
53
|
-
{Array.from({ length: 30 }).map((_value, index) => (
|
|
54
|
-
<GalleryItem key={index}>
|
|
55
|
-
<Card key={index}>
|
|
56
|
-
<CardBody>This is a card</CardBody>
|
|
57
|
-
</Card>
|
|
58
|
-
</GalleryItem>
|
|
59
|
-
))}
|
|
60
|
-
</Gallery>
|
|
61
|
-
</PageSection>
|
|
62
|
-
</DashboardWrapper>
|
|
63
|
-
</Fragment>
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
14
|
+
```ts file="examples/Banner/BannerBasicSticky.tsx" isFullscreen
|
|
67
15
|
```
|
|
68
16
|
|
|
69
17
|
### Top and bottom banner
|
|
70
18
|
|
|
71
|
-
```
|
|
72
|
-
import { Fragment } from 'react';
|
|
73
|
-
import {
|
|
74
|
-
Banner,
|
|
75
|
-
Card,
|
|
76
|
-
CardBody,
|
|
77
|
-
Flex,
|
|
78
|
-
FlexItem,
|
|
79
|
-
Gallery,
|
|
80
|
-
GalleryItem,
|
|
81
|
-
PageSection,
|
|
82
|
-
Content
|
|
83
|
-
} from '@patternfly/react-core';
|
|
84
|
-
import { DashboardWrapper } from '@patternfly/react-core/dist/js/demos/DashboardWrapper';
|
|
85
|
-
import { css } from '@patternfly/react-styles';
|
|
86
|
-
import display from '@patternfly/react-styles/css/utilities/Display/display';
|
|
19
|
+
```ts file="examples/Banner/BannerTopBottom.tsx" isFullscreen
|
|
87
20
|
|
|
88
|
-
class BannerDemo extends React.Component {
|
|
89
|
-
render() {
|
|
90
|
-
return (
|
|
91
|
-
<Fragment>
|
|
92
|
-
<Flex
|
|
93
|
-
direction={{ default: 'column' }}
|
|
94
|
-
flexWrap={{ default: 'nowrap' }}
|
|
95
|
-
spaceItems={{ default: 'spaceItemsNone' }}
|
|
96
|
-
style={{ height: '100%' }}
|
|
97
|
-
>
|
|
98
|
-
<FlexItem>
|
|
99
|
-
<Banner isSticky>
|
|
100
|
-
<Flex
|
|
101
|
-
justifyContent={{ default: 'justifyContentCenter', lg: 'justifyContentSpaceBetween' }}
|
|
102
|
-
flexWrap={{ default: 'nowrap' }}
|
|
103
|
-
>
|
|
104
|
-
<div className={css(display.displayNone, display.displayBlockOnLg)}>Localhost</div>
|
|
105
|
-
<div className={css(display.displayNone, display.displayBlockOnLg)}>
|
|
106
|
-
This message is sticky to the top of the page.
|
|
107
|
-
</div>
|
|
108
|
-
<div className={css(display.displayNoneOnLg)}>Drop some text on mobile, truncate if needed.</div>
|
|
109
|
-
<div className={css(display.displayNone, display.displayBlockOnLg)}>Ned Username</div>
|
|
110
|
-
</Flex>
|
|
111
|
-
</Banner>
|
|
112
|
-
</FlexItem>
|
|
113
|
-
<FlexItem grow={{ default: 'grow' }} style={{ minHeight: 0 }}>
|
|
114
|
-
<DashboardWrapper breadcrumb={null}>
|
|
115
|
-
<PageSection aria-labelledby="main-title">
|
|
116
|
-
<Content>
|
|
117
|
-
<h1 id='main-title'>Main title</h1>
|
|
118
|
-
<p>
|
|
119
|
-
Body text should be Red Hat Text at 1rem(16px). It should have leading of 1.5rem(24px) because{' '}
|
|
120
|
-
<br />
|
|
121
|
-
of it’s relative line height of 1.5.
|
|
122
|
-
</p>
|
|
123
|
-
</Content>
|
|
124
|
-
</PageSection>
|
|
125
|
-
<PageSection aria-label='Cards gallery'>
|
|
126
|
-
<Gallery hasGutter>
|
|
127
|
-
{Array.from({ length: 30 }).map((_value, index) => (
|
|
128
|
-
<GalleryItem key={index}>
|
|
129
|
-
<Card key={index}>
|
|
130
|
-
<CardBody>This is a card</CardBody>
|
|
131
|
-
</Card>
|
|
132
|
-
</GalleryItem>
|
|
133
|
-
))}
|
|
134
|
-
</Gallery>
|
|
135
|
-
</PageSection>
|
|
136
|
-
</DashboardWrapper>
|
|
137
|
-
</FlexItem>
|
|
138
|
-
<FlexItem>
|
|
139
|
-
<Banner isSticky>
|
|
140
|
-
<Flex
|
|
141
|
-
justifyContent={{ default: 'justifyContentCenter', lg: 'justifyContentSpaceBetween' }}
|
|
142
|
-
flexWrap={{ default: 'nowrap' }}
|
|
143
|
-
>
|
|
144
|
-
<div className={css(display.displayNone, display.displayBlockOnLg)}>Localhost</div>
|
|
145
|
-
<div className={css(display.displayNone, display.displayBlockOnLg)}>
|
|
146
|
-
This message is sticky to the bottom of the page.
|
|
147
|
-
</div>
|
|
148
|
-
<div className={css(display.displayNoneOnLg)}>Drop some text on mobile, truncate if needed.</div>
|
|
149
|
-
<div className={css(display.displayNone, display.displayBlockOnLg)}>Ned Username</div>
|
|
150
|
-
</Flex>
|
|
151
|
-
</Banner>
|
|
152
|
-
</FlexItem>
|
|
153
|
-
</Flex>
|
|
154
|
-
</Fragment>
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
21
|
```
|
|
@@ -14,96 +14,12 @@ In this demo, learn how to use a [CalendarMonth](/components/date-and-time/calen
|
|
|
14
14
|
|
|
15
15
|
### Date and time picker
|
|
16
16
|
|
|
17
|
-
```ts file="
|
|
17
|
+
```ts file="examples/DateTimePicker/DateTimePicker.tsx"
|
|
18
18
|
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
### Date and time range picker
|
|
22
22
|
|
|
23
|
-
```
|
|
24
|
-
import { useState } from 'react';
|
|
25
|
-
import { Flex, FlexItem, InputGroup, InputGroupItem, DatePicker, isValidDate, TimePicker, yyyyMMddFormat, updateDateTime } from '@patternfly/react-core';
|
|
26
|
-
|
|
27
|
-
DateTimeRangePicker = () => {
|
|
28
|
-
const [from, setFrom] = useState();
|
|
29
|
-
const [to, setTo] = useState();
|
|
30
|
-
|
|
31
|
-
const toValidator = (date) => {
|
|
32
|
-
return isValidDate(from) && yyyyMMddFormat(date) >= yyyyMMddFormat(from)
|
|
33
|
-
? ''
|
|
34
|
-
: 'The "to" date must be after the "from" date';
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
const onFromDateChange = (_event, inputDate, newFromDate) => {
|
|
38
|
-
if (isValidDate(from) && isValidDate(newFromDate) && inputDate === yyyyMMddFormat(newFromDate)) {
|
|
39
|
-
newFromDate.setHours(from.getHours());
|
|
40
|
-
newFromDate.setMinutes(from.getMinutes());
|
|
41
|
-
}
|
|
42
|
-
if (isValidDate(newFromDate) && inputDate === yyyyMMddFormat(newFromDate)) {
|
|
43
|
-
setFrom(new Date(newFromDate));
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const onFromTimeChange = (_event, time, hour, minute) => {
|
|
48
|
-
if (isValidDate(from)) {
|
|
49
|
-
const updatedFromDate = new Date(from);
|
|
50
|
-
updatedFromDate.setHours(hour);
|
|
51
|
-
updatedFromDate.setMinutes(minute);
|
|
52
|
-
setFrom(updatedFromDate);
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const onToDateChange = (_event, inputDate, newToDate) => {
|
|
57
|
-
if (isValidDate(to) && isValidDate(newToDate) && inputDate === yyyyMMddFormat(newToDate)) {
|
|
58
|
-
newToDate.setHours(to.getHours());
|
|
59
|
-
newToDate.setMinutes(to.getMinutes());
|
|
60
|
-
}
|
|
61
|
-
if (isValidDate(newToDate) && inputDate === yyyyMMddFormat(newToDate)) {
|
|
62
|
-
setTo(newToDate);
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const onToTimeChange = (_event, time, hour, minute) => {
|
|
67
|
-
if (isValidDate(to)) {
|
|
68
|
-
const updatedToDate = new Date(to);
|
|
69
|
-
updatedToDate.setHours(hour);
|
|
70
|
-
updatedToDate.setMinutes(minute);
|
|
71
|
-
setTo(updatedToDate);
|
|
72
|
-
}
|
|
73
|
-
};
|
|
23
|
+
```ts file="examples/DateTimePicker/DateTimeRangePicker.tsx"
|
|
74
24
|
|
|
75
|
-
return (
|
|
76
|
-
<Flex direction={{ default: 'column', lg: 'row' }}>
|
|
77
|
-
<FlexItem>
|
|
78
|
-
<InputGroup>
|
|
79
|
-
<InputGroupItem>
|
|
80
|
-
<DatePicker onChange={onFromDateChange} aria-label="Start date" placeholder="YYYY-MM-DD" />
|
|
81
|
-
</InputGroupItem>
|
|
82
|
-
<InputGroupItem>
|
|
83
|
-
<TimePicker aria-label="Start time" style={{ width: '150px' }} onChange={onFromTimeChange} />
|
|
84
|
-
</InputGroupItem>
|
|
85
|
-
</InputGroup>
|
|
86
|
-
</FlexItem>
|
|
87
|
-
<FlexItem>to</FlexItem>
|
|
88
|
-
<FlexItem>
|
|
89
|
-
<InputGroup>
|
|
90
|
-
<InputGroupItem>
|
|
91
|
-
<DatePicker
|
|
92
|
-
value={isValidDate(to) ? yyyyMMddFormat(to) : to}
|
|
93
|
-
onChange={onToDateChange}
|
|
94
|
-
isDisabled={!isValidDate(from)}
|
|
95
|
-
rangeStart={from}
|
|
96
|
-
validators={[toValidator]}
|
|
97
|
-
aria-label="End date"
|
|
98
|
-
placeholder="YYYY-MM-DD"
|
|
99
|
-
/>
|
|
100
|
-
</InputGroupItem>
|
|
101
|
-
<InputGroupItem>
|
|
102
|
-
<TimePicker style={{ width: '150px' }} onChange={onToTimeChange} isDisabled={!isValidDate(from)} />
|
|
103
|
-
</InputGroupItem>
|
|
104
|
-
</InputGroup>
|
|
105
|
-
</FlexItem>
|
|
106
|
-
</Flex>
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
25
|
```
|