@patternfly/react-core 5.2.0-prerelease.41 → 5.2.0-prerelease.43

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.
Files changed (176) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/components/package.json +1 -1
  3. package/deprecated/package.json +1 -1
  4. package/dist/dynamic/components/AboutModal/package.json +1 -1
  5. package/dist/dynamic/components/Accordion/package.json +1 -1
  6. package/dist/dynamic/components/ActionList/package.json +1 -1
  7. package/dist/dynamic/components/Alert/package.json +1 -1
  8. package/dist/dynamic/components/Avatar/package.json +1 -1
  9. package/dist/dynamic/components/BackToTop/package.json +1 -1
  10. package/dist/dynamic/components/Backdrop/package.json +1 -1
  11. package/dist/dynamic/components/BackgroundImage/package.json +1 -1
  12. package/dist/dynamic/components/Badge/package.json +1 -1
  13. package/dist/dynamic/components/Banner/package.json +1 -1
  14. package/dist/dynamic/components/Brand/package.json +1 -1
  15. package/dist/dynamic/components/Breadcrumb/package.json +1 -1
  16. package/dist/dynamic/components/Button/package.json +1 -1
  17. package/dist/dynamic/components/CalendarMonth/package.json +1 -1
  18. package/dist/dynamic/components/Card/package.json +1 -1
  19. package/dist/dynamic/components/Checkbox/package.json +1 -1
  20. package/dist/dynamic/components/Chip/package.json +1 -1
  21. package/dist/dynamic/components/ClipboardCopy/package.json +1 -1
  22. package/dist/dynamic/components/CodeBlock/package.json +1 -1
  23. package/dist/dynamic/components/DataList/package.json +1 -1
  24. package/dist/dynamic/components/DatePicker/package.json +1 -1
  25. package/dist/dynamic/components/DescriptionList/package.json +1 -1
  26. package/dist/dynamic/components/Divider/package.json +1 -1
  27. package/dist/dynamic/components/DragDrop/package.json +1 -1
  28. package/dist/dynamic/components/Drawer/package.json +1 -1
  29. package/dist/dynamic/components/Dropdown/package.json +1 -1
  30. package/dist/dynamic/components/DualListSelector/package.json +1 -1
  31. package/dist/dynamic/components/EmptyState/package.json +1 -1
  32. package/dist/dynamic/components/ExpandableSection/package.json +1 -1
  33. package/dist/dynamic/components/FileUpload/package.json +1 -1
  34. package/dist/dynamic/components/Form/package.json +1 -1
  35. package/dist/dynamic/components/FormSelect/package.json +1 -1
  36. package/dist/dynamic/components/HelperText/package.json +1 -1
  37. package/dist/dynamic/components/Hint/package.json +1 -1
  38. package/dist/dynamic/components/Icon/package.json +1 -1
  39. package/dist/dynamic/components/InputGroup/package.json +1 -1
  40. package/dist/dynamic/components/JumpLinks/package.json +1 -1
  41. package/dist/dynamic/components/Label/package.json +1 -1
  42. package/dist/dynamic/components/List/package.json +1 -1
  43. package/dist/dynamic/components/LoginPage/package.json +1 -1
  44. package/dist/dynamic/components/Masthead/package.json +1 -1
  45. package/dist/dynamic/components/Menu/package.json +1 -1
  46. package/dist/dynamic/components/MenuToggle/package.json +1 -1
  47. package/dist/dynamic/components/Modal/package.json +1 -1
  48. package/dist/dynamic/components/MultipleFileUpload/package.json +1 -1
  49. package/dist/dynamic/components/Nav/package.json +1 -1
  50. package/dist/dynamic/components/NotificationBadge/package.json +1 -1
  51. package/dist/dynamic/components/NotificationDrawer/package.json +1 -1
  52. package/dist/dynamic/components/NumberInput/package.json +1 -1
  53. package/dist/dynamic/components/OverflowMenu/package.json +1 -1
  54. package/dist/dynamic/components/Page/package.json +1 -1
  55. package/dist/dynamic/components/Pagination/package.json +1 -1
  56. package/dist/dynamic/components/Panel/package.json +1 -1
  57. package/dist/dynamic/components/Popover/package.json +1 -1
  58. package/dist/dynamic/components/Progress/package.json +1 -1
  59. package/dist/dynamic/components/ProgressStepper/package.json +1 -1
  60. package/dist/dynamic/components/Radio/package.json +1 -1
  61. package/dist/dynamic/components/SearchInput/package.json +1 -1
  62. package/dist/dynamic/components/Select/package.json +1 -1
  63. package/dist/dynamic/components/Sidebar/package.json +1 -1
  64. package/dist/dynamic/components/SimpleList/package.json +1 -1
  65. package/dist/dynamic/components/Skeleton/package.json +1 -1
  66. package/dist/dynamic/components/SkipToContent/package.json +1 -1
  67. package/dist/dynamic/components/Slider/package.json +1 -1
  68. package/dist/dynamic/components/Spinner/package.json +1 -1
  69. package/dist/dynamic/components/Switch/package.json +1 -1
  70. package/dist/dynamic/components/Tabs/package.json +1 -1
  71. package/dist/dynamic/components/Text/package.json +1 -1
  72. package/dist/dynamic/components/TextArea/package.json +1 -1
  73. package/dist/dynamic/components/TextInput/package.json +1 -1
  74. package/dist/dynamic/components/TextInputGroup/package.json +1 -1
  75. package/dist/dynamic/components/Tile/package.json +1 -1
  76. package/dist/dynamic/components/TimePicker/package.json +1 -1
  77. package/dist/dynamic/components/Timestamp/package.json +1 -1
  78. package/dist/dynamic/components/Title/package.json +1 -1
  79. package/dist/dynamic/components/ToggleGroup/package.json +1 -1
  80. package/dist/dynamic/components/Toolbar/package.json +1 -1
  81. package/dist/dynamic/components/Tooltip/package.json +1 -1
  82. package/dist/dynamic/components/TreeView/package.json +1 -1
  83. package/dist/dynamic/components/Truncate/package.json +1 -1
  84. package/dist/dynamic/components/Wizard/hooks/package.json +1 -1
  85. package/dist/dynamic/components/Wizard/package.json +1 -1
  86. package/dist/dynamic/deprecated/components/ApplicationLauncher/package.json +1 -1
  87. package/dist/dynamic/deprecated/components/ContextSelector/package.json +1 -1
  88. package/dist/dynamic/deprecated/components/Dropdown/package.json +1 -1
  89. package/dist/dynamic/deprecated/components/OptionsMenu/package.json +1 -1
  90. package/dist/dynamic/deprecated/components/PageHeader/package.json +1 -1
  91. package/dist/dynamic/deprecated/components/Select/package.json +1 -1
  92. package/dist/dynamic/deprecated/components/Wizard/package.json +1 -1
  93. package/dist/dynamic/deprecated/components/package.json +1 -1
  94. package/dist/dynamic/helpers/FocusTrap/FocusTrap/package.json +1 -1
  95. package/dist/dynamic/helpers/GenerateId/GenerateId/package.json +1 -1
  96. package/dist/dynamic/helpers/KeyboardHandler/package.json +1 -1
  97. package/dist/dynamic/helpers/OUIA/ouia/package.json +1 -1
  98. package/dist/dynamic/helpers/Popper/Popper/package.json +1 -1
  99. package/dist/dynamic/helpers/constants/package.json +1 -1
  100. package/dist/dynamic/helpers/datetimeUtils/package.json +1 -1
  101. package/dist/dynamic/helpers/favorites/package.json +1 -1
  102. package/dist/dynamic/helpers/fileUtils/package.json +1 -1
  103. package/dist/dynamic/helpers/htmlConstants/package.json +1 -1
  104. package/dist/dynamic/helpers/package.json +1 -1
  105. package/dist/dynamic/helpers/resizeObserver/package.json +1 -1
  106. package/dist/dynamic/helpers/typeUtils/package.json +1 -1
  107. package/dist/dynamic/helpers/useInterval/package.json +1 -1
  108. package/dist/dynamic/helpers/useIsomorphicLayout/package.json +1 -1
  109. package/dist/dynamic/helpers/useUnmountEffect/package.json +1 -1
  110. package/dist/dynamic/helpers/util/package.json +1 -1
  111. package/dist/dynamic/layouts/Bullseye/package.json +1 -1
  112. package/dist/dynamic/layouts/Flex/package.json +1 -1
  113. package/dist/dynamic/layouts/Gallery/package.json +1 -1
  114. package/dist/dynamic/layouts/Grid/package.json +1 -1
  115. package/dist/dynamic/layouts/Level/package.json +1 -1
  116. package/dist/dynamic/layouts/Split/package.json +1 -1
  117. package/dist/dynamic/layouts/Stack/package.json +1 -1
  118. package/dist/dynamic/next/components/Modal/package.json +1 -1
  119. package/dist/dynamic/next/components/package.json +1 -1
  120. package/dist/esm/components/Checkbox/Checkbox.d.ts +9 -3
  121. package/dist/esm/components/Checkbox/Checkbox.d.ts.map +1 -1
  122. package/dist/esm/components/Checkbox/Checkbox.js +16 -8
  123. package/dist/esm/components/Checkbox/Checkbox.js.map +1 -1
  124. package/dist/esm/components/DragDrop/index.d.ts +1 -0
  125. package/dist/esm/components/DragDrop/index.d.ts.map +1 -1
  126. package/dist/esm/components/DragDrop/index.js +1 -0
  127. package/dist/esm/components/DragDrop/index.js.map +1 -1
  128. package/dist/esm/components/DualListSelector/index.d.ts +2 -0
  129. package/dist/esm/components/DualListSelector/index.d.ts.map +1 -1
  130. package/dist/esm/components/DualListSelector/index.js +2 -0
  131. package/dist/esm/components/DualListSelector/index.js.map +1 -1
  132. package/dist/esm/components/Radio/Radio.d.ts +7 -5
  133. package/dist/esm/components/Radio/Radio.d.ts.map +1 -1
  134. package/dist/esm/components/Radio/Radio.js +13 -20
  135. package/dist/esm/components/Radio/Radio.js.map +1 -1
  136. package/dist/esm/components/index.d.ts +1 -1
  137. package/dist/esm/components/index.d.ts.map +1 -1
  138. package/dist/esm/components/index.js +1 -1
  139. package/dist/esm/components/index.js.map +1 -1
  140. package/dist/js/components/Checkbox/Checkbox.d.ts +9 -3
  141. package/dist/js/components/Checkbox/Checkbox.d.ts.map +1 -1
  142. package/dist/js/components/Checkbox/Checkbox.js +16 -8
  143. package/dist/js/components/Checkbox/Checkbox.js.map +1 -1
  144. package/dist/js/components/DragDrop/index.d.ts +1 -0
  145. package/dist/js/components/DragDrop/index.d.ts.map +1 -1
  146. package/dist/js/components/DragDrop/index.js +1 -0
  147. package/dist/js/components/DragDrop/index.js.map +1 -1
  148. package/dist/js/components/DualListSelector/index.d.ts +2 -0
  149. package/dist/js/components/DualListSelector/index.d.ts.map +1 -1
  150. package/dist/js/components/DualListSelector/index.js +2 -0
  151. package/dist/js/components/DualListSelector/index.js.map +1 -1
  152. package/dist/js/components/Radio/Radio.d.ts +7 -5
  153. package/dist/js/components/Radio/Radio.d.ts.map +1 -1
  154. package/dist/js/components/Radio/Radio.js +13 -20
  155. package/dist/js/components/Radio/Radio.js.map +1 -1
  156. package/dist/js/components/index.d.ts +1 -1
  157. package/dist/js/components/index.d.ts.map +1 -1
  158. package/dist/js/components/index.js +1 -1
  159. package/dist/js/components/index.js.map +1 -1
  160. package/dist/umd/react-core.min.js +1 -1
  161. package/helpers/package.json +1 -1
  162. package/layouts/package.json +1 -1
  163. package/next/package.json +1 -1
  164. package/package.json +2 -2
  165. package/src/components/Checkbox/Checkbox.tsx +63 -29
  166. package/src/components/Checkbox/__tests__/Checkbox.test.tsx +41 -0
  167. package/src/components/DataList/examples/DataList.md +2 -2
  168. package/src/components/DragDrop/examples/DragDrop.md +4 -2
  169. package/src/components/DragDrop/examples/DragDropBasic.tsx +4 -4
  170. package/src/components/DragDrop/examples/DragDropMultipleLists.tsx +7 -2
  171. package/src/components/DragDrop/index.ts +1 -0
  172. package/src/components/DualListSelector/examples/DualListSelector.md +3 -1
  173. package/src/components/DualListSelector/index.ts +2 -0
  174. package/src/components/Radio/Radio.tsx +39 -38
  175. package/src/components/Radio/__tests__/Radio.test.tsx +41 -0
  176. package/src/components/index.ts +1 -1
@@ -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":"5.2.0-prerelease.40","private":true}
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":"5.2.0-prerelease.42","private":true}
@@ -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":"5.2.0-prerelease.40","private":true}
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":"5.2.0-prerelease.42","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":"5.2.0-prerelease.40","private":true}
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":"5.2.0-prerelease.42","private":true}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patternfly/react-core",
3
- "version": "5.2.0-prerelease.41",
3
+ "version": "5.2.0-prerelease.43",
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",
@@ -71,5 +71,5 @@
71
71
  "react": "^17 || ^18",
72
72
  "react-dom": "^17 || ^18"
73
73
  },
74
- "gitHead": "c90c7f26330e3d94ae5927318060b6d2a7faeef6"
74
+ "gitHead": "1ae55d8591d99c3d006b0e79fd372efdd8b5b983"
75
75
  }
@@ -8,10 +8,16 @@ import { ASTERISK } from '../../helpers/htmlConstants';
8
8
  export interface CheckboxProps
9
9
  extends Omit<React.HTMLProps<HTMLInputElement>, 'type' | 'onChange' | 'disabled' | 'label'>,
10
10
  OUIAProps {
11
- /** Additional classes added to the checkbox. */
11
+ /** Additional classes added to the checkbox wrapper. This wrapper will be div element by default. It will be a label element if
12
+ * isLabelWrapped is true, or it can be overridden by any element specified in the component prop.
13
+ */
12
14
  className?: string;
13
- /** Additional classed added to the radio input */
15
+ /** Additional classes added to the checkbox input. */
14
16
  inputClassName?: string;
17
+ /** Flag to indicate whether the checkbox wrapper element is a <label> element for the checkbox input. Will not apply if a component prop (with a value other than a "label") is specified. */
18
+ isLabelWrapped?: boolean;
19
+ /** Flag to show if the checkbox label is shown before the checkbox input. */
20
+ isLabelBeforeButton?: boolean;
15
21
  /** Flag to show if the checkbox selection is valid or invalid. */
16
22
  isValid?: boolean;
17
23
  /** Flag to show if the checkbox is disabled. */
@@ -33,7 +39,7 @@ export interface CheckboxProps
33
39
  description?: React.ReactNode;
34
40
  /** Body text of the checkbox */
35
41
  body?: React.ReactNode;
36
- /** Sets the input wrapper component to render. Defaults to <div> */
42
+ /** Sets the checkbox wrapper component to render. Defaults to "div". If set to "label", behaves the same as if isLabelWrapped prop was specified. */
37
43
  component?: React.ElementType;
38
44
  /** Value to overwrite the randomly generated data-ouia-component-id.*/
39
45
  ouiaId?: number | string;
@@ -52,13 +58,13 @@ class Checkbox extends React.Component<CheckboxProps, CheckboxState> {
52
58
  static displayName = 'Checkbox';
53
59
  static defaultProps: PickOptional<CheckboxProps> = {
54
60
  className: '',
61
+ isLabelWrapped: false,
55
62
  isValid: true,
56
63
  isDisabled: false,
57
64
  isRequired: false,
58
65
  isChecked: false,
59
66
  onChange: defaultOnChange,
60
- ouiaSafe: true,
61
- component: 'div'
67
+ ouiaSafe: true
62
68
  };
63
69
 
64
70
  constructor(props: any) {
@@ -78,6 +84,8 @@ class Checkbox extends React.Component<CheckboxProps, CheckboxState> {
78
84
  className,
79
85
  inputClassName,
80
86
  onChange,
87
+ isLabelWrapped,
88
+ isLabelBeforeButton,
81
89
  isValid,
82
90
  isDisabled,
83
91
  isRequired,
@@ -89,7 +97,7 @@ class Checkbox extends React.Component<CheckboxProps, CheckboxState> {
89
97
  body,
90
98
  ouiaId,
91
99
  ouiaSafe,
92
- component: Component,
100
+ component,
93
101
  ...props
94
102
  } = this.props;
95
103
  if (!props.id) {
@@ -107,31 +115,57 @@ class Checkbox extends React.Component<CheckboxProps, CheckboxState> {
107
115
  checkedProps.defaultChecked = defaultChecked;
108
116
  }
109
117
 
118
+ const inputRendered = (
119
+ <input
120
+ {...props}
121
+ className={css(styles.checkInput, inputClassName)}
122
+ type="checkbox"
123
+ onChange={this.handleChange}
124
+ aria-invalid={!isValid}
125
+ aria-label={ariaLabel}
126
+ disabled={isDisabled}
127
+ required={isRequired}
128
+ ref={(elem) => elem && (elem.indeterminate = isChecked === null)}
129
+ {...checkedProps}
130
+ {...getOUIAProps(Checkbox.displayName, ouiaId !== undefined ? ouiaId : this.state.ouiaStateId, ouiaSafe)}
131
+ />
132
+ );
133
+
134
+ const wrapWithLabel = (isLabelWrapped && !component) || component === 'label';
135
+
136
+ const Label = wrapWithLabel ? 'span' : 'label';
137
+ const labelRendered = label ? (
138
+ <Label
139
+ className={css(styles.checkLabel, isDisabled && styles.modifiers.disabled)}
140
+ htmlFor={!wrapWithLabel && props.id}
141
+ >
142
+ {label}
143
+ {isRequired && (
144
+ <span className={css(styles.checkLabelRequired)} aria-hidden="true">
145
+ {ASTERISK}
146
+ </span>
147
+ )}
148
+ </Label>
149
+ ) : null;
150
+
151
+ const Component = component ?? (wrapWithLabel ? 'label' : 'div');
152
+
110
153
  checkedProps.checked = checkedProps.checked === null ? false : checkedProps.checked;
111
154
  return (
112
- <Component className={css(styles.check, !label && styles.modifiers.standalone, className)}>
113
- <input
114
- {...props}
115
- className={css(styles.checkInput, inputClassName)}
116
- type="checkbox"
117
- onChange={this.handleChange}
118
- aria-invalid={!isValid}
119
- aria-label={ariaLabel}
120
- disabled={isDisabled}
121
- required={isRequired}
122
- ref={(elem) => elem && (elem.indeterminate = isChecked === null)}
123
- {...checkedProps}
124
- {...getOUIAProps(Checkbox.displayName, ouiaId !== undefined ? ouiaId : this.state.ouiaStateId, ouiaSafe)}
125
- />
126
- {label && (
127
- <label className={css(styles.checkLabel, isDisabled && styles.modifiers.disabled)} htmlFor={props.id}>
128
- {label}
129
- {isRequired && (
130
- <span className={css(styles.checkLabelRequired)} aria-hidden="true">
131
- {ASTERISK}
132
- </span>
133
- )}
134
- </label>
155
+ <Component
156
+ className={css(styles.check, !label && styles.modifiers.standalone, className)}
157
+ htmlFor={wrapWithLabel && props.id}
158
+ >
159
+ {isLabelBeforeButton ? (
160
+ <>
161
+ {labelRendered}
162
+ {inputRendered}
163
+ </>
164
+ ) : (
165
+ <>
166
+ {inputRendered}
167
+ {labelRendered}
168
+ </>
135
169
  )}
136
170
  {description && <span className={css(styles.checkDescription)}>{description}</span>}
137
171
  {body && <span className={css(styles.checkBody)}>{body}</span>}
@@ -231,6 +231,47 @@ test('Renders with the provided component', () => {
231
231
  expect(screen.getByRole('checkbox').parentElement?.tagName).toBe('SPAN');
232
232
  });
233
233
 
234
+ test('Renders with the label wrapper if isLabelWrapped is provided', () => {
235
+ render(<Checkbox id="test-id" isLabelWrapped />);
236
+
237
+ expect(screen.getByRole('checkbox').parentElement?.tagName).toBe('LABEL');
238
+ });
239
+
240
+ test('Renders with span element around the inner label text if isLabelWrapped is provided', () => {
241
+ const labelText = 'test checkbox label';
242
+ render(<Checkbox id="test-id" isLabelWrapped label={labelText} />);
243
+
244
+ expect(screen.getByText(labelText).tagName).toBe('SPAN');
245
+ });
246
+
247
+ test('Renders with the provided component although isLabelWrapped is provided', () => {
248
+ render(<Checkbox id="test-id" isLabelWrapped component="h3" />);
249
+
250
+ expect(screen.getByRole('checkbox').parentElement?.tagName).toBe('H3');
251
+ });
252
+
253
+ test('Renders with the label wrapper if component is set to label', () => {
254
+ render(<Checkbox id="test-id" component="label" />);
255
+
256
+ expect(screen.getByRole('checkbox').parentElement?.tagName).toBe('LABEL');
257
+ });
258
+
259
+ test('Renders with span element around the inner label text if component is set to label', () => {
260
+ const labelText = 'test checkbox label';
261
+ render(<Checkbox id="test-id" component="label" label={labelText} />);
262
+
263
+ expect(screen.getByText(labelText).tagName).toBe('SPAN');
264
+ });
265
+
266
+ test('Renders label before checkbox input if isLabelBeforeButton is provided', () => {
267
+ render(<Checkbox id="test-id" isLabelBeforeButton label={'test checkbox label'} />);
268
+
269
+ const wrapper = screen.getByRole('checkbox').parentElement!;
270
+
271
+ expect(wrapper.children[0].tagName).toBe('LABEL');
272
+ expect(wrapper.children[1].tagName).toBe('INPUT');
273
+ });
274
+
234
275
  test(`Spreads additional props`, () => {
235
276
  render(<Checkbox id="test-id" data-testid="test-id" />);
236
277
 
@@ -86,9 +86,9 @@ import global_BorderWidth_sm from '@patternfly/react-tokens/dist/esm/global_Bord
86
86
 
87
87
  ### Draggable
88
88
 
89
- Draggable data lists used to have their own HTML5-based API for drag and drop, which wasn't able to fulfill requirements such as custom styling on items being dragged. So we wrote generic `DragDrop`, `Draggable`, and `Droppable` components for this purpose. Use those new components instead of the deprecated (and buggy!) HTML5-based API.
89
+ Note: There is a new recommended drag and drop implementation with full keyboard functionality, which replaces this implementation. To adhere to our new recommendations, refer to the [drag and drop demos](/components/drag-and-drop/react-next-demos).
90
90
 
91
- Note: Keyboard accessibility and screen reader accessibility for the `DragDrop` component are still in development.
91
+ Previously, draggable data lists had their own API for the [drag and drop component](/components/drag-and-drop), which wasn't flexible enough to allow custom styling for items as they are dragged. To address this disparity, `<DragDrop>`, `<Draggable>`, and `<Droppable>` components were added to replace our now deprecated HTML5-based API. Keyboard and screen reader accessibility for the `<DragDrop>` component is still in development.
92
92
 
93
93
  ```ts isBeta file="./DataListDraggable.tsx"
94
94
 
@@ -2,10 +2,10 @@
2
2
  id: Drag and drop
3
3
  section: components
4
4
  propComponents: [DragDrop, Draggable, Droppable, DraggableItemPosition]
5
- beta: true
5
+ title: Drag and drop
6
6
  ---
7
7
 
8
- You can use the `DragDrop` component to move items in or between lists. The `DragDrop` component should contain `Droppable` components which contain `Draggable` components.
8
+ You can use the `<DragDrop>` component to move items in or between lists. The `<DragDrop>` component should contain `<Droppable>` components which contain `<Draggable>` components.
9
9
 
10
10
  ```ts noLive
11
11
  import React from 'react';
@@ -35,9 +35,11 @@ Note: Keyboard accessibility and screen reader accessibility are still in develo
35
35
  ### Basic
36
36
 
37
37
  ```ts file="./DragDropBasic.tsx"
38
+
38
39
  ```
39
40
 
40
41
  ### Multiple lists
41
42
 
42
43
  ```ts file="./DragDropMultipleLists.tsx"
44
+
43
45
  ```
@@ -20,14 +20,14 @@ const getItems = (count: number) =>
20
20
  }));
21
21
 
22
22
  const reorder = (list: ItemType[], startIndex: number, endIndex: number) => {
23
- const result = list;
23
+ const result = [...list];
24
24
  const [removed] = result.splice(startIndex, 1);
25
25
  result.splice(endIndex, 0, removed);
26
26
  return result;
27
27
  };
28
28
 
29
29
  export const DragDropBasic: React.FunctionComponent = () => {
30
- const [items, setItems] = React.useState(getItems(10));
30
+ const [items, setItems] = React.useState<ItemType[]>(getItems(10));
31
31
 
32
32
  function onDrop(source: SourceType, dest: DestinationType) {
33
33
  if (dest) {
@@ -42,8 +42,8 @@ export const DragDropBasic: React.FunctionComponent = () => {
42
42
  return (
43
43
  <DragDrop onDrop={onDrop}>
44
44
  <Droppable>
45
- {items.map(({ content }, i) => (
46
- <Draggable key={i} style={{ padding: '8px' }}>
45
+ {items.map(({ id, content }) => (
46
+ <Draggable key={id} style={{ padding: '8px' }}>
47
47
  {content}
48
48
  </Draggable>
49
49
  ))}
@@ -11,6 +11,11 @@ interface SourceType {
11
11
  index: number;
12
12
  }
13
13
 
14
+ interface MultipleListState {
15
+ items1: ItemType[];
16
+ items2: ItemType[];
17
+ }
18
+
14
19
  interface DestinationType extends SourceType {}
15
20
 
16
21
  const getItems = (count: number, startIndex: number) =>
@@ -35,7 +40,7 @@ const move = (source: ItemType[], destination: ItemType[], sourceIndex: number,
35
40
  };
36
41
 
37
42
  export const DragDropMultipleLists: React.FunctionComponent = () => {
38
- const [items, setItems] = React.useState({
43
+ const [items, setItems] = React.useState<MultipleListState>({
39
44
  items1: getItems(10, 0),
40
45
  items2: getItems(5, 10)
41
46
  });
@@ -84,7 +89,7 @@ export const DragDropMultipleLists: React.FunctionComponent = () => {
84
89
  {Object.entries(items).map(([key, subitems]) => (
85
90
  <SplitItem key={key} style={{ flex: 1 }}>
86
91
  <Droppable zone="multizone" droppableId={key}>
87
- {subitems.map(({ id, content }) => (
92
+ {(subitems as ItemType[]).map(({ id, content }) => (
88
93
  <Draggable key={id} style={{ padding: '8px' }}>
89
94
  {content}
90
95
  </Draggable>
@@ -1,3 +1,4 @@
1
1
  export * from './DragDrop';
2
2
  export * from './Draggable';
3
3
  export * from './Droppable';
4
+ export * from './DroppableContext';
@@ -87,6 +87,8 @@ The dual list selector can also be built in a composable manner to make customiz
87
87
 
88
88
  ### Composable with drag and drop
89
89
 
90
+ Note: There is a new recommended drag and drop implementation with full keyboard functionality, which replaces this implementation. To adhere to our new recommendations, refer to the [drag and drop demos](/components/drag-and-drop/react-next-demos).
91
+
90
92
  This example only allows reordering the contents of the "chosen" pane with drag and drop. To make a pane able to be reordered:
91
93
 
92
94
  - wrap the `DualListSelectorPane` in a `DragDrop` component
@@ -99,7 +101,7 @@ This example only allows reordering the contents of the "chosen" pane with drag
99
101
  - define an `onDrag` callback which ensures that the drag event will not cross hairs with the `onOptionSelect` click
100
102
  event set on the option. Note: the `ignoreNextOptionSelect` state value is used to prevent selection while dragging.
101
103
 
102
- Note: Keyboard accessibility and screen reader accessibility for the `DragDrop` component are still in development.
104
+ Keyboard and screen reader accessibility for the `<DragDrop>` component is still in development.
103
105
 
104
106
  ```ts file="DualListSelectorComposableDragDrop.tsx"
105
107
 
@@ -1,7 +1,9 @@
1
1
  export * from './DualListSelector';
2
+ export * from './DualListSelectorContext';
2
3
  export * from './DualListSelectorControl';
3
4
  export * from './DualListSelectorControlsWrapper';
4
5
  export * from './DualListSelectorPane';
5
6
  export * from './DualListSelectorList';
6
7
  export * from './DualListSelectorListItem';
7
8
  export * from './DualListSelectorTree';
9
+ export * from './DualListSelectorContext';
@@ -7,17 +7,17 @@ import { getOUIAProps, OUIAProps, getDefaultOUIAId } from '../../helpers';
7
7
  export interface RadioProps
8
8
  extends Omit<React.HTMLProps<HTMLInputElement>, 'disabled' | 'label' | 'onChange' | 'type'>,
9
9
  OUIAProps {
10
- /** Additional classes added to the radio wrapper. This will be a div element if
11
- * isLabelWrapped is true, otherwise this will be a label element.
10
+ /** Additional classes added to the radio wrapper. This wrapper will be div element by default. It will be a label element if
11
+ * isLabelWrapped is true, or it can be overridden by any element specified in the component prop.
12
12
  */
13
13
  className?: string;
14
- /** Additional classed added to the radio input */
14
+ /** Additional classes added to the radio input. */
15
15
  inputClassName?: string;
16
16
  /** Id of the radio. */
17
17
  id: string;
18
- /** Flag to show if the radio label is wrapped on small screen. */
18
+ /** Flag to indicate whether the radio wrapper element is a native label element for the radio input. Will not apply if a component prop (with a value other than a "label") is specified. */
19
19
  isLabelWrapped?: boolean;
20
- /** Flag to show if the radio label is shown before the radio button. */
20
+ /** Flag to show if the radio label is shown before the radio input. */
21
21
  isLabelBeforeButton?: boolean;
22
22
  /** Flag to show if the radio is checked. */
23
23
  checked?: boolean;
@@ -39,6 +39,8 @@ export interface RadioProps
39
39
  description?: React.ReactNode;
40
40
  /** Body of the radio. */
41
41
  body?: React.ReactNode;
42
+ /** Sets the radio wrapper component to render. Defaults to "div". If set to "label", behaves the same as if isLabelWrapped prop was specified. */
43
+ component?: React.ElementType;
42
44
  /** Value to overwrite the randomly generated data-ouia-component-id.*/
43
45
  ouiaId?: number | string;
44
46
  /** Set the value of data-ouia-safe. Only set to true when the component is in a static state, i.e. no animations are occurring. At all other times, this value must be false. */
@@ -88,6 +90,7 @@ class Radio extends React.Component<RadioProps, { ouiaStateId: string }> {
88
90
  body,
89
91
  ouiaId,
90
92
  ouiaSafe = true,
93
+ component,
91
94
  ...props
92
95
  } = this.props;
93
96
  if (!props.id) {
@@ -110,41 +113,39 @@ class Radio extends React.Component<RadioProps, { ouiaStateId: string }> {
110
113
  />
111
114
  );
112
115
 
113
- let labelRendered: React.ReactNode = null;
114
- if (label && isLabelWrapped) {
115
- labelRendered = <span className={css(styles.radioLabel, isDisabled && styles.modifiers.disabled)}>{label}</span>;
116
- } else if (label) {
117
- labelRendered = (
118
- <label className={css(styles.radioLabel, isDisabled && styles.modifiers.disabled)} htmlFor={props.id}>
119
- {label}
120
- </label>
121
- );
122
- }
116
+ const wrapWithLabel = (isLabelWrapped && !component) || component === 'label';
123
117
 
124
- const descRender = description ? <span className={css(styles.radioDescription)}>{description}</span> : null;
125
- const bodyRender = body ? <span className={css(styles.radioBody)}>{body}</span> : null;
126
- const childrenRendered = isLabelBeforeButton ? (
127
- <>
128
- {labelRendered}
129
- {inputRendered}
130
- {descRender}
131
- {bodyRender}
132
- </>
133
- ) : (
134
- <>
135
- {inputRendered}
136
- {labelRendered}
137
- {descRender}
138
- {bodyRender}
139
- </>
140
- );
118
+ const Label = wrapWithLabel ? 'span' : 'label';
119
+ const labelRendered = label ? (
120
+ <Label
121
+ className={css(styles.radioLabel, isDisabled && styles.modifiers.disabled)}
122
+ htmlFor={!wrapWithLabel && props.id}
123
+ >
124
+ {label}
125
+ </Label>
126
+ ) : null;
127
+
128
+ const Component = component ?? (wrapWithLabel ? 'label' : 'div');
141
129
 
142
- return isLabelWrapped ? (
143
- <label className={css(styles.radio, className)} htmlFor={props.id}>
144
- {childrenRendered}
145
- </label>
146
- ) : (
147
- <div className={css(styles.radio, !label && styles.modifiers.standalone, className)}>{childrenRendered}</div>
130
+ return (
131
+ <Component
132
+ className={css(styles.radio, !label && styles.modifiers.standalone, className)}
133
+ htmlFor={wrapWithLabel && props.id}
134
+ >
135
+ {isLabelBeforeButton ? (
136
+ <>
137
+ {labelRendered}
138
+ {inputRendered}
139
+ </>
140
+ ) : (
141
+ <>
142
+ {inputRendered}
143
+ {labelRendered}
144
+ </>
145
+ )}
146
+ {description && <span className={css(styles.radioDescription)}>{description}</span>}
147
+ {body && <span className={css(styles.radioBody)}>{body}</span>}
148
+ </Component>
148
149
  );
149
150
  }
150
151
  }
@@ -100,4 +100,45 @@ describe('Radio', () => {
100
100
 
101
101
  expect(myMock).toHaveBeenCalled();
102
102
  });
103
+
104
+ test('Renders with the label wrapper if isLabelWrapped is provided', () => {
105
+ render(<Radio id="test-id" name="check" isLabelWrapped />);
106
+
107
+ expect(screen.getByRole('radio').parentElement?.tagName).toBe('LABEL');
108
+ });
109
+
110
+ test('Renders with span element around the inner label text if isLabelWrapped is provided', () => {
111
+ const labelText = 'test radio label';
112
+ render(<Radio id="test-id" name="check" isLabelWrapped label={labelText} />);
113
+
114
+ expect(screen.getByText(labelText).tagName).toBe('SPAN');
115
+ });
116
+
117
+ test('Renders with the provided component although isLabelWrapped is provided', () => {
118
+ render(<Radio id="test-id" name="check" isLabelWrapped component="h3" />);
119
+
120
+ expect(screen.getByRole('radio').parentElement?.tagName).toBe('H3');
121
+ });
122
+
123
+ test('Renders with the label wrapper if component is set to label', () => {
124
+ render(<Radio id="test-id" name="check" component="label" />);
125
+
126
+ expect(screen.getByRole('radio').parentElement?.tagName).toBe('LABEL');
127
+ });
128
+
129
+ test('Renders with span element around the inner label text if component is set to label', () => {
130
+ const labelText = 'test radio label';
131
+ render(<Radio id="test-id" name="check" component="label" label={labelText} />);
132
+
133
+ expect(screen.getByText(labelText).tagName).toBe('SPAN');
134
+ });
135
+
136
+ test('Renders label before radio input if isLabelBeforeButton is provided', () => {
137
+ render(<Radio id="test-id" name="check" isLabelBeforeButton label={'test radio label'} />);
138
+
139
+ const wrapper = screen.getByRole('radio').parentElement!;
140
+
141
+ expect(wrapper.children[0].tagName).toBe('LABEL');
142
+ expect(wrapper.children[1].tagName).toBe('INPUT');
143
+ });
103
144
  });
@@ -22,6 +22,7 @@ export * from './DataList';
22
22
  export * from './DatePicker';
23
23
  export * from './DescriptionList';
24
24
  export * from './Divider';
25
+ export * from './DragDrop';
25
26
  export * from './Drawer';
26
27
  export * from './Dropdown';
27
28
  export * from './DualListSelector';
@@ -76,7 +77,6 @@ export * from './Tooltip';
76
77
  export * from './NumberInput';
77
78
  export * from './TreeView';
78
79
  export * from './Wizard';
79
- export * from './DragDrop';
80
80
  export * from './TextInputGroup';
81
81
  export * from './Panel';
82
82
  export * from './Truncate';