@patternfly/react-docs 5.21.36 → 5.21.40

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 CHANGED
@@ -3,6 +3,38 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [5.21.40](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-docs@5.21.39...@patternfly/react-docs@5.21.40) (2021-09-16)
7
+
8
+ **Note:** Version bump only for package @patternfly/react-docs
9
+
10
+
11
+
12
+
13
+
14
+ ## [5.21.39](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-docs@5.21.38...@patternfly/react-docs@5.21.39) (2021-09-16)
15
+
16
+ **Note:** Version bump only for package @patternfly/react-docs
17
+
18
+
19
+
20
+
21
+
22
+ ## [5.21.38](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-docs@5.21.37...@patternfly/react-docs@5.21.38) (2021-09-14)
23
+
24
+ **Note:** Version bump only for package @patternfly/react-docs
25
+
26
+
27
+
28
+
29
+
30
+ ## [5.21.37](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-docs@5.21.36...@patternfly/react-docs@5.21.37) (2021-09-14)
31
+
32
+ **Note:** Version bump only for package @patternfly/react-docs
33
+
34
+
35
+
36
+
37
+
6
38
  ## [5.21.36](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-docs@5.21.35...@patternfly/react-docs@5.21.36) (2021-09-14)
7
39
 
8
40
  **Note:** Version bump only for package @patternfly/react-docs
package/RELEASE-NOTES.md CHANGED
@@ -3,6 +3,88 @@ id: Release notes
3
3
  section: developer-resources
4
4
  ---
5
5
 
6
+ ## 2021.12 release notes (2021-09-15)
7
+ - [@patternfly/react-catalog-view-extension@4.12.73](https://www.npmjs.com/package/@patternfly/react-catalog-view-extension/v/4.12.73)
8
+ - [@patternfly/react-charts@6.15.23](https://www.npmjs.com/package/@patternfly/react-charts/v/6.15.23)
9
+ - [@patternfly/react-code-editor@4.3.60](https://www.npmjs.com/package/@patternfly/react-code-editor/v/4.3.60)
10
+ - [@patternfly/react-core@4.157.2](https://www.npmjs.com/package/@patternfly/react-core/v/4.157.2)
11
+ - [@patternfly/react-icons@4.11.17](https://www.npmjs.com/package/@patternfly/react-icons/v/4.11.17)
12
+ - [@patternfly/react-inline-edit-extension@4.7.83](https://www.npmjs.com/package/@patternfly/react-inline-edit-extension/v/4.7.83)
13
+ - [@patternfly/react-log-viewer@4.6.13](https://www.npmjs.com/package/@patternfly/react-log-viewer/v/4.6.13)
14
+ - [@patternfly/react-styles@4.11.16](https://www.npmjs.com/package/@patternfly/react-styles/v/4.11.16)
15
+ - [@patternfly/react-table@4.30.2](https://www.npmjs.com/package/@patternfly/react-table/v/4.30.2)
16
+ - [@patternfly/react-tokens@4.12.18](https://www.npmjs.com/package/@patternfly/react-tokens/v/4.12.18)
17
+ - [@patternfly/react-topology@4.9.79](https://www.npmjs.com/package/@patternfly/react-topology/v/4.9.79)
18
+ - [@patternfly/react-virtualized-extension@4.9.48](https://www.npmjs.com/package/@patternfly/react-virtualized-extension/v/4.9.48)
19
+
20
+ ### Components
21
+ - **Alert:**
22
+ - Added plain variant, added expandable inline ([#6236](https://github.com/patternfly/patternfly-react/pull/6236))
23
+ - **Avatar:**
24
+ - Converted examples to typescript ([#6228](https://github.com/patternfly/patternfly-react/pull/6228))
25
+ - **Back to top:**
26
+ - Introduced back to top component and demos ([#6282](https://github.com/patternfly/patternfly-react/pull/6282))
27
+ - **Calendar month:**
28
+ - Made useEffect respect validators ([#6315](https://github.com/patternfly/patternfly-react/pull/6315))
29
+ - **Card:**
30
+ - Added demos for log and event views ([#6289](https://github.com/patternfly/patternfly-react/pull/6289))
31
+ - Added aggregate status, status tabbed and status demos ([#6206](https://github.com/patternfly/patternfly-react/pull/6206))
32
+ - **Code editor:**
33
+ - Replaced hardcoded text with props, updated microcopy ([#6241](https://github.com/patternfly/patternfly-react/pull/6241))
34
+ - **Date picker:**
35
+ - Updated date picker microcopy ([#6263](https://github.com/patternfly/patternfly-react/pull/6263))
36
+ - **Description list:**
37
+ - Added compact and fluid modifiers ([#6260](https://github.com/patternfly/patternfly-react/pull/6260))
38
+ - **Drag and drop:**
39
+ - Started work towards adding drag and drop component ([#6258](https://github.com/patternfly/patternfly-react/pull/6258))
40
+ - **Dual list selector:**
41
+ - Added support for list item row ([#6294](https://github.com/patternfly/patternfly-react/pull/6294))
42
+ - Added arguments to onOptionsSelect (#6224) ([#6225](https://github.com/patternfly/patternfly-react/pull/6225))
43
+ - **Flex layout:**
44
+ - Added component property to flex layout and subitems. ([#6270](https://github.com/patternfly/patternfly-react/pull/6270))
45
+ - **Gallery layout:**
46
+ - Added component property to gallery layout and subitems. ([#6270](https://github.com/patternfly/patternfly-react/pull/6270))
47
+ - **Grid layout:**
48
+ - Added component property to grid layout and subitems. ([#6270](https://github.com/patternfly/patternfly-react/pull/6270))
49
+ - **Menu:**
50
+ - Added context selector demo using menu ([#6283](https://github.com/patternfly/patternfly-react/pull/6283))
51
+ - **Navigation:**
52
+ - Added flyout support ([#6253](https://github.com/patternfly/patternfly-react/pull/6253))
53
+ - **Search input:**
54
+ - Added autocomplete search input demo ([#6305](https://github.com/patternfly/patternfly-react/pull/6305))
55
+ - **Select:**
56
+ - Fixed select field dropdown showing the create option even when there's no input ([#6248](https://github.com/patternfly/patternfly-react/pull/6248))
57
+ - Added aria-label to toggle ([#6271](https://github.com/patternfly/patternfly-react/pull/6271))
58
+ - **Slider:**
59
+ - Fixed customSteps spacing to respect min/max ([#6231](https://github.com/patternfly/patternfly-react/pull/6231))
60
+ - Updated slider to respect min/max constraints ([#6232](https://github.com/patternfly/patternfly-react/pull/6232))
61
+ - **Spinner:**
62
+ - Fixed spinner tests to check all component sizes ([#6269](https://github.com/patternfly/patternfly-react/pull/6269))
63
+ - **Tabs:**
64
+ - Added support for disabled state tabs ([#6261](https://github.com/patternfly/patternfly-react/pull/6261))
65
+
66
+ ### Log viewer extension
67
+ - Added onScroll and footer props ([#6238](https://github.com/patternfly/patternfly-react/pull/6238))
68
+ - Added required dependency ([#6216](https://github.com/patternfly/patternfly-react/pull/6216))
69
+
70
+ ### Table
71
+ - Added hoverable and selectable rows ([#6233](https://github.com/patternfly/patternfly-react/pull/6233))
72
+ - Added missing styles import ([#6259](https://github.com/patternfly/patternfly-react/pull/6259))
73
+ - Fixed broken links in table's empty state demo ([#6276](https://github.com/patternfly/patternfly-react/pull/6276))
74
+
75
+ ### Other
76
+ - **Chore:**
77
+ - Removed unneeded peer dependency in code editor ([#6239](https://github.com/patternfly/patternfly-react/pull/6239))
78
+ - **Demos**
79
+ - Added search input demo for composable search with form ([#6279](https://github.com/patternfly/patternfly-react/pull/6279))
80
+ - Refactored demos to use masthead ([#6274](https://github.com/patternfly/patternfly-react/pull/6274))
81
+ - Fixed wrapper nav to have hrefs ([#6297](https://github.com/patternfly/patternfly-react/pull/6297))
82
+ - **Deps:**
83
+ - Updated dependency theme-patternfly-org to v0.6.40 ([#6309](https://github.com/patternfly/patternfly-react/pull/6309))
84
+ - **Docs:**
85
+ - Corrected some copy-pasted prop comments ([#6285](https://github.com/patternfly/patternfly-react/pull/6285))
86
+ - Added yarn build before test in contributing docs ([#6273](https://github.com/patternfly/patternfly-react/pull/6273))
87
+
6
88
  ## 2021.11 release notes (2021-08-25)
7
89
  - [@patternfly/react-catalog-view-extension@4.12.56](https://www.npmjs.com/package/@patternfly/react-catalog-view-extension/v/4.12.56)
8
90
  - [@patternfly/react-charts@6.15.20](https://www.npmjs.com/package/@patternfly/react-charts/v/6.15.20)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@patternfly/react-docs",
3
3
  "description": "PatternFly React Docs",
4
- "version": "5.21.36",
4
+ "version": "5.21.40",
5
5
  "publishConfig": {
6
6
  "access": "public",
7
7
  "tag": "prerelease-v4"
@@ -23,18 +23,18 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "@patternfly/patternfly": "4.135.2",
26
- "@patternfly/react-catalog-view-extension": "^4.12.70",
26
+ "@patternfly/react-catalog-view-extension": "^4.12.73",
27
27
  "@patternfly/react-charts": "^6.15.23",
28
- "@patternfly/react-code-editor": "^4.3.57",
29
- "@patternfly/react-core": "^4.156.4",
28
+ "@patternfly/react-code-editor": "^4.3.60",
29
+ "@patternfly/react-core": "^4.157.2",
30
30
  "@patternfly/react-icons": "^4.11.17",
31
- "@patternfly/react-inline-edit-extension": "^4.7.80",
32
- "@patternfly/react-log-viewer": "^4.6.10",
31
+ "@patternfly/react-inline-edit-extension": "^4.7.83",
32
+ "@patternfly/react-log-viewer": "^4.6.13",
33
33
  "@patternfly/react-styles": "^4.11.16",
34
- "@patternfly/react-table": "^4.29.73",
34
+ "@patternfly/react-table": "^4.30.2",
35
35
  "@patternfly/react-tokens": "^4.12.18",
36
- "@patternfly/react-topology": "^4.9.76",
37
- "@patternfly/react-virtualized-extension": "^4.9.45"
36
+ "@patternfly/react-topology": "^4.9.79",
37
+ "@patternfly/react-virtualized-extension": "^4.9.48"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@patternfly/patternfly-a11y": "4.2.1",
@@ -53,5 +53,5 @@
53
53
  "last 2 versions",
54
54
  "not ie <= 11"
55
55
  ],
56
- "gitHead": "4c109dca5aa28a74f321d9b44760b5024d5bd1a8"
56
+ "gitHead": "5d562bd5c3b1a24565196073f12c3ce5d74cb8bd"
57
57
  }
@@ -0,0 +1,147 @@
1
+ import React from 'react';
2
+ import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from 'theme-patternfly-org/components';
3
+
4
+ const pageData = {
5
+ "id": "Drag and drop",
6
+ "section": "components",
7
+ "source": "react",
8
+ "slug": "/components/drag-and-drop/react",
9
+ "sourceLink": "https://github.com/patternfly/patternfly-react/blob/main/packages/react-core/src/components/DragDrop/examples/DragDrop.md",
10
+ "propComponents": [
11
+ {
12
+ "name": "DragDrop",
13
+ "description": "",
14
+ "props": [
15
+ {
16
+ "name": "children",
17
+ "type": "React.ReactNode",
18
+ "description": "Potentially Droppable and Draggable children"
19
+ },
20
+ {
21
+ "name": "onDrag",
22
+ "type": "(source: DraggableItemPosition) => boolean",
23
+ "description": "Callback for drag event. Return true to allow drag, false to disallow.",
24
+ "defaultValue": "() => true"
25
+ },
26
+ {
27
+ "name": "onDrop",
28
+ "type": "(source: DraggableItemPosition, dest?: DraggableItemPosition) => boolean",
29
+ "description": "Callback for drop event. Return true to allow drop, false to disallow.",
30
+ "defaultValue": "() => false"
31
+ }
32
+ ]
33
+ },
34
+ {
35
+ "name": "Draggable",
36
+ "description": "",
37
+ "props": [
38
+ {
39
+ "name": "children",
40
+ "type": "React.ReactNode",
41
+ "description": "Content rendered inside DragDrop"
42
+ },
43
+ {
44
+ "name": "className",
45
+ "type": "string",
46
+ "description": "Class to add to outer div"
47
+ }
48
+ ]
49
+ },
50
+ {
51
+ "name": "Droppable",
52
+ "description": "",
53
+ "props": [
54
+ {
55
+ "name": "children",
56
+ "type": "React.ReactNode",
57
+ "description": "Content rendered inside DragDrop"
58
+ },
59
+ {
60
+ "name": "className",
61
+ "type": "string",
62
+ "description": "Class to add to outer div"
63
+ },
64
+ {
65
+ "name": "droppableId",
66
+ "type": "string",
67
+ "description": "Id to be passed back on drop events",
68
+ "defaultValue": "'defaultId'"
69
+ },
70
+ {
71
+ "name": "zone",
72
+ "type": "string",
73
+ "description": "Name of zone that items can be dragged between. Should specify if there is more than one Droppable on the page.",
74
+ "defaultValue": "'defaultZone'"
75
+ }
76
+ ]
77
+ },
78
+ {
79
+ "name": "DraggableItemPosition",
80
+ "description": "",
81
+ "props": [
82
+ {
83
+ "name": "droppableId",
84
+ "type": "string",
85
+ "description": "Parent droppableId",
86
+ "required": true
87
+ },
88
+ {
89
+ "name": "index",
90
+ "type": "number",
91
+ "description": "Index of item in parent Droppable",
92
+ "required": true
93
+ }
94
+ ]
95
+ }
96
+ ],
97
+ "beta": true,
98
+ "examples": [
99
+ "Basic",
100
+ "Multiple lists"
101
+ ]
102
+ };
103
+ pageData.examples = {
104
+ 'Basic': props =>
105
+ <Example {...pageData} {...props} {...{"code":"import React from 'react';\nimport { DragDrop, Draggable, Droppable } from '@patternfly/react-core';\n\nconst getItems = count =>\n Array.from({ length: count }, (v, k) => k).map(k => ({\n id: `item-${k}`,\n content: `item ${k} `.repeat(k === 4 ? 20 : 1)\n }));\n\nconst reorder = (list, startIndex, endIndex) => {\n const result = Array.from(list);\n const [removed] = result.splice(startIndex, 1);\n result.splice(endIndex, 0, removed);\n return result;\n};\n\nBasic = () => {\n const [items, setItems] = React.useState(getItems(10));\n\n function onDrop(source, dest) {\n if (dest) {\n const newItems = reorder(\n items,\n source.index,\n dest.index\n );\n setItems(newItems);\n\n return true;\n }\n }\n\n return (\n <DragDrop onDrop={onDrop}>\n <Droppable>\n {items.map(({ id, content }, i) =>\n <Draggable key={i} style={{ padding: '8px' }}>\n {content}\n </Draggable>\n )}\n </Droppable>\n </DragDrop>\n );\n}","title":"Basic","lang":"js"}}>
106
+
107
+ </Example>,
108
+ 'Multiple lists': props =>
109
+ <Example {...pageData} {...props} {...{"code":"import React from 'react';\nimport { DragDrop, Draggable, Droppable, Split, SplitItem } from '@patternfly/react-core';\n\nconst getItems = (count, start) =>\n Array.from({ length: count }, (v, k) => k).map(k => ({\n id: `item-${k + start}`,\n content: `item ${k + start} `.repeat(k === 4 ? 20 : 1)\n }));\n\nconst reorder = (list, startIndex, endIndex) => {\n const result = Array.from(list);\n const [removed] = result.splice(startIndex, 1);\n result.splice(endIndex, 0, removed);\n return result;\n};\n\nconst move = (source, destination, sourceIndex, destIndex) => {\n const sourceClone = Array.from(source);\n const destClone = Array.from(destination);\n const [removed] = sourceClone.splice(sourceIndex, 1);\n destClone.splice(destIndex, 0, removed);\n return [sourceClone, destClone];\n};\n\nMultiList = () => {\n const [items, setItems] = React.useState({\n items1: getItems(10, 0),\n items2: getItems(5, 10)\n });\n\n function onDrop(source, dest) {\n console.log(source, dest);\n if (dest) {\n if (source.droppableId === dest.droppableId) {\n const newItems = reorder(\n source.droppableId === 'items1' ? items.items1 : items.items2,\n source.index,\n dest.index\n );\n if (source.droppableId === 'items1') {\n setItems({\n items1: newItems,\n items2: items.items2\n });\n } else {\n setItems({\n items1: items.items1,\n items2: newItems\n });\n }\n } else {\n const [newItems1, newItems2] = move(\n source.droppableId === 'items1' ? items.items1 : items.items2,\n dest.droppableId === 'items1' ? items.items1 : items.items2,\n source.index,\n dest.index\n );\n setItems({\n items1: source.droppableId === 'items1' ? newItems1 : newItems2,\n items2: dest.droppableId === 'items1' ? newItems1 : newItems2\n });\n }\n return true;\n }\n }\n\n return (\n <DragDrop onDrop={onDrop}>\n <Split hasGutter>\n {Object.entries(items).map(([key, subitems]) =>\n <SplitItem key={key} style={{ flex: 1 }}>\n <Droppable zone=\"multizone\" droppableId={key}>\n {subitems.map(({ id, content }, i) =>\n <Draggable key={id} style={{ padding: '8px' }}>\n {content}\n </Draggable>\n )}\n </Droppable>\n </SplitItem>\n )}\n </Split>\n </DragDrop>\n );\n}","title":"Multiple lists","lang":"js"}}>
110
+
111
+ </Example>
112
+ };
113
+
114
+ const Component = () => (
115
+ <React.Fragment>
116
+ <p {...{"className":"ws-p"}}>
117
+ {`You can use `}
118
+ <code {...{"className":"ws-code"}}>
119
+ {`DragDrop`}
120
+ </code>
121
+ {` to move items in or between lists. `}
122
+ <code {...{"className":"ws-code"}}>
123
+ {`DragDrop`}
124
+ </code>
125
+ {`s should contain `}
126
+ <code {...{"className":"ws-code"}}>
127
+ {`Droppable`}
128
+ </code>
129
+ {`s which contain `}
130
+ <code {...{"className":"ws-code"}}>
131
+ {`Draggable`}
132
+ </code>
133
+ {`s.`}
134
+ </p>
135
+ <Example {...{"code":"import React from 'react';\nimport { DragDrop, Draggable, Droppable } from '@patternfly/react-core';\n\n<DragDrop> {/* DragDrop houses the context for dragging and dropping */}\n <Droppable>\n <Draggable>\n You can put anything here! It will be wrapped in a styled div.\n </Draggable>\n <Draggable>\n You can have as many Draggables as you like.\n </Draggable>\n </Droppable>\n <Droppable> {/* You can also have many droppables! */}\n <Draggable />\n </Droppable>\n</DragDrop>","lang":"js","noLive":true}}>
136
+ </Example>
137
+ <AutoLinkHeader {...{"id":"examples","size":"h2","className":"ws-title ws-h2"}}>
138
+ {`Examples`}
139
+ </AutoLinkHeader>
140
+ {React.createElement(pageData.examples["Basic"])}
141
+ {React.createElement(pageData.examples["Multiple lists"])}
142
+ </React.Fragment>
143
+ );
144
+ Component.displayName = 'ComponentsDragAndDropReactDocs';
145
+ Component.pageData = pageData;
146
+
147
+ export default Component;
@@ -1,17 +1,75 @@
1
1
  import React from 'react';
2
2
  import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from 'theme-patternfly-org/components';
3
-
3
+ import {
4
+ Button,
5
+ Card,
6
+ CardBody,
7
+ CardFooter,
8
+ DatePicker,
9
+ Form,
10
+ FormGroup,
11
+ Grid,
12
+ GridItem,
13
+ Menu,
14
+ MenuContent,
15
+ MenuItem,
16
+ MenuList,
17
+ MenuToggle,
18
+ Popper,
19
+ SearchInput,
20
+ TextInput
21
+ } from '@patternfly/react-core';
22
+ import { words } from '../../../../../react-core/src/demos/SearchInput/./words.js';
4
23
  const pageData = {
5
24
  "id": "Search input",
6
25
  "section": "components",
7
26
  "source": "react-demos",
8
27
  "slug": "/components/search-input/react-demos",
9
- "sourceLink": "https://github.com/patternfly/patternfly-react/blob/main/packages/react-core/src/demos/SearchInput.md",
28
+ "sourceLink": "https://github.com/patternfly/patternfly-react/blob/main/packages/react-core/src/demos/SearchInput/SearchInput.md",
10
29
  "examples": [
30
+ "Search with autocomplete",
11
31
  "Composable advanced search"
12
32
  ]
13
33
  };
34
+ pageData.liveContext = {
35
+ Button,
36
+ Card,
37
+ CardBody,
38
+ CardFooter,
39
+ DatePicker,
40
+ Form,
41
+ FormGroup,
42
+ Grid,
43
+ GridItem,
44
+ Menu,
45
+ MenuContent,
46
+ MenuItem,
47
+ MenuList,
48
+ MenuToggle,
49
+ Popper,
50
+ SearchInput,
51
+ TextInput,
52
+ words
53
+ };
14
54
  pageData.examples = {
55
+ 'Search with autocomplete': props =>
56
+ <Example {...pageData} {...props} {...{"code":"import React from 'react';\nimport { \n Menu,\n MenuContent,\n MenuItem,\n MenuList,\n Popper, \n SearchInput\n} from '@patternfly/react-core';\n\nimport { words } from './words.js';\n\nSearchAutocomplete = () => {\n const [value, setValue] = React.useState('');\n const [hint, setHint] = React.useState('');\n const [autocompleteOptions, setAutocompleteOptions] = React.useState([]);\n \n const [isAutocompleteOpen, setIsAutocompleteOpen] = React.useState(false);\n \n const searchInputRef = React.useRef(null);\n const autocompleteRef = React.useRef(null);\n \n const onClear = () => {\n setValue('');\n };\n \n const onChange = (newValue) => {\n if (newValue !== '' && searchInputRef && searchInputRef.current && searchInputRef.current.contains(document.activeElement)) {\n setIsAutocompleteOpen(true);\n \n // When the value of the search input changes, build a list of no more than 10 autocomplete options.\n // Options which start with the search input value are listed first, followed by options which contain\n // the search input value.\n let options = words.filter((option) => option.startsWith(newValue.toLowerCase())).map((option) => <MenuItem itemId={option} key={option}>{option}</MenuItem>);\n if (options.length > 10) {\n options = options.slice(0,10);\n } else {\n options = [...options, ...words.filter((option) => !option.startsWith(newValue.toLowerCase()) && option.includes(newValue.toLowerCase())).map((option) => <MenuItem itemId={option} key={option}>{option}</MenuItem>)].slice(0, 10)\n }\n \n // The hint is set whenever there is only one autocomplete option left.\n setHint(options.length === 1? options[0].props.itemId : '');\n // The menu is hidden if there are no options\n setIsAutocompleteOpen(options.length > 0);\n setAutocompleteOptions(options);\n } else {\n setIsAutocompleteOpen(false);\n }\n setValue(newValue);\n };\n \n // Whenever an autocomplete option is selected, set the search input value, close the menu, and put the browser\n // focus back on the search input\n const onSelect = (e, itemId) => {\n e.stopPropagation();\n setValue(itemId);\n setIsAutocompleteOpen(false);\n searchInputRef.current.focus();\n };\n \n const handleMenuKeys = event => {\n // If there is a hint while the browser focus is on the search input, tab or right arrow will 'accept' the hint value \n // and set it as the search input value\n if (hint && (event.key === 'Tab' || event.key === 'ArrowRight') && searchInputRef.current === event.target) {\n setValue(hint);\n setHint('');\n setIsAutocompleteOpen(false);\n if (event.key === 'ArrowRight') {\n event.preventDefault(); \n }\n // if the autocomplete is open and the browser focus is on the search input,\n } else if (isAutocompleteOpen && searchInputRef.current && searchInputRef.current === event.target) {\n // the escape key closes the autocomplete menu and keeps the focus on the search input.\n if (event.key === 'Escape') {\n setIsAutocompleteOpen(false);\n searchInputRef.current.focus();\n // the up and down arrow keys move browser focus into the autocomplete menu\n } else if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n const firstElement = autocompleteRef.current.querySelector('li > button:not(:disabled)');\n firstElement && firstElement.focus();\n event.preventDefault(); // by default, the up and down arrow keys scroll the window\n // the tab, enter, and space keys will close the menu, and the tab key will move browser\n // focus forward one element (by default)\n } else if (event.key === 'Tab'|| event.key === \"Enter\" || event.key === 'Space'){\n setIsAutocompleteOpen(false);\n if (event.key === \"Enter\" || event.key === 'Space') {\n event.preventDefault();\n }\n }\n // If the autocomplete is open and the browser focus is in the autocomplete menu\n // hitting tab will close the autocomplete and but browser focus back on the search input. \n } else if (isAutocompleteOpen && autocompleteRef.current.contains(event.target) && (event.key === 'Tab')) {\n event.preventDefault();\n setIsAutocompleteOpen(false);\n searchInputRef.current.focus();\n }\n \n };\n \n // The autocomplete menu should close if the user clicks outside the menu.\n const handleClickOutside = event => {\n if (isAutocompleteOpen && autocompleteRef && autocompleteRef.current && !autocompleteRef.current.contains(event.target)) {\n setIsAutocompleteOpen(false);\n }\n };\n \n React.useEffect(() => {\n window.addEventListener('keydown', handleMenuKeys);\n window.addEventListener('click', handleClickOutside);\n return () => {\n window.removeEventListener('keydown', handleMenuKeys);\n window.removeEventListener('click', handleClickOutside);\n };\n }, [isAutocompleteOpen, hint, searchInputRef.current]);\n \n const searchInput = (\n <SearchInput\n value={value}\n onChange={onChange}\n onClear={onClear}\n ref={searchInputRef}\n hint={hint}\n id=\"autocomplete-search\"\n />\n );\n \n const autocomplete = (\n <Menu ref={autocompleteRef} onSelect={onSelect}>\n <MenuContent>\n <MenuList>\n {autocompleteOptions}\n </MenuList>\n </MenuContent>\n </Menu>\n );\n \n\n return (\n <Popper\n trigger={searchInput}\n popper={autocomplete}\n isVisible={isAutocompleteOpen}\n enableFlip={false}\n // append the autocomplete menu to the search input in the DOM for the sake of the keyboard navigation experience\n appendTo={() => document.querySelector('#autocomplete-search')}\n />\n );\n};","title":"Search with autocomplete","lang":"js"}}>
57
+
58
+ <p {...{"className":"ws-p"}}>
59
+ {`This demo handles building the advanced search form using the composable Menu, and the `}
60
+
61
+ <code {...{"className":"ws-code"}}>
62
+ {`SearchInput`}
63
+ </code>
64
+ {`'s `}
65
+
66
+ <code {...{"className":"ws-code"}}>
67
+ {`hint`}
68
+ </code>
69
+ {` prop.
70
+ It also demonstrates wiring up the appropriate keyboard interactions, focus management, and general event handling.`}
71
+ </p>
72
+ </Example>,
15
73
  'Composable advanced search': props =>
16
74
  <Example {...pageData} {...props} {...{"code":"import React from 'react';\nimport { \n ActionGroup,\n Button, \n Card, \n CardBody, \n DatePicker,\n Form, \n FormGroup,\n Grid,\n GridItem, \n isValidDate,\n Menu,\n MenuContent,\n MenuItem,\n MenuList,\n MenuToggle,\n Popper, \n SearchInput, \n TextInput,\n yyyyMMddFormat\n} from '@patternfly/react-core';\n\nAdvancedComposableSearchInput = () => {\n const [value, setValue] = React.useState('');\n const [hasWords, setHasWords] = React.useState('');\n const [dateWithin, setDateWithin] = React.useState('1 day');\n const [date, setDate] = React.useState();\n \n const [isAdvancedSearchOpen, setIsAdvancedSearchOpen] = React.useState(false);\n const [isDateWithinOpen, setIsDateWithinOpen] = React.useState(false);\n \n const isInitialMount = React.useRef(true);\n const firstAttrRef = React.useRef(null);\n const searchInputRef = React.useRef(null);\n const advancedSearchPaneRef = React.useRef(null);\n const dateWithinToggleRef = React.useRef();\n const dateWithinMenuRef = React.useRef();\n \n const onClear = () => {\n setValue('');\n setHasWords('');\n setDateWithin('');\n setDate('');\n };\n \n const onChange = (value) => {\n if (value.length <= hasWords.length + 1) {\n setValue(value);\n setHasWords(value);\n } else {\n setValue(hasWords);\n }\n };\n \n // After initial page load, whenever the advanced search menu is opened, the browser focus should be placed on the\n // first advanced search form input. Whenever the advanced search menu is closed, the browser focus should\n // be returned to the search input.\n React.useEffect(() => {\n if (isInitialMount.current) {\n isInitialMount.current = false;\n } else {\n if (isAdvancedSearchOpen && firstAttrRef && firstAttrRef.current) {\n firstAttrRef.current.focus();\n } else if (!isAdvancedSearchOpen && searchInputRef) {\n searchInputRef.current.focus();\n }\n }\n }, [isAdvancedSearchOpen]);\n \n // If a menu is open and has browser focus, then the escape key closes them and puts the browser focus onto their \n // respective toggle. The 'date within' menu also needs to close when the 'tab' key is hit. However, hitting tab while\n // focus is in the advanced search form should move the focus to the next form input, not close the advanced search\n // menu.\n const handleMenuKeys = event => {\n if (isDateWithinOpen && dateWithinMenuRef.current && dateWithinMenuRef.current.contains(event.target)) {\n if (event.key === 'Escape' || event.key === 'Tab') {\n setIsDateWithinOpen(!isDateWithinOpen);\n dateWithinToggleRef.current.focus();\n }\n } \n if (isAdvancedSearchOpen && advancedSearchPaneRef.current && advancedSearchPaneRef.current.contains(event.target)) {\n if (event.key === 'Escape' || \n (event.key === 'Tab' && !event.shiftKey && advancedSearchPaneRef.current.querySelector('button[type=reset]') === event.target)\n ) {\n setIsAdvancedSearchOpen(!isAdvancedSearchOpen);\n searchInputRef.current.focus();\n }\n } \n };\n \n // If a menu is open and has browser focus, then clicking outside the menu should close it.\n const handleClickOutside = event => {\n if (isDateWithinOpen && dateWithinMenuRef && dateWithinMenuRef.current && !dateWithinMenuRef.current.contains(event.target)) {\n setIsDateWithinOpen(false);\n } \n if (isAdvancedSearchOpen && advancedSearchPaneRef && advancedSearchPaneRef.current && !advancedSearchPaneRef.current.contains(event.target)) {\n setIsAdvancedSearchOpen(false);\n }\n };\n \n React.useEffect(() => {\n window.addEventListener('keydown', handleMenuKeys);\n window.addEventListener('click', handleClickOutside);\n return () => {\n window.removeEventListener('keydown', handleMenuKeys);\n window.removeEventListener('click', handleClickOutside);\n };\n }, [dateWithinMenuRef.current, advancedSearchPaneRef.current, isAdvancedSearchOpen, isDateWithinOpen]);\n \n \n // This demo and its handling of 'date within' and a date picker is modeled after the gmail advanced search form.\n const onSubmit = (value, event) => {\n event.preventDefault();\n \n if (isValidDate(new Date(date)) && dateWithin) {\n let afterDate = new Date(date);\n let toDate = new Date(date);\n switch (dateWithin) {\n case '1 day':\n afterDate.setDate(afterDate.getDate());\n toDate.setDate(toDate.getDate() + 2);\n break;\n case '3 days':\n afterDate.setDate(afterDate.getDate() - 2);\n toDate.setDate(toDate.getDate() + 4);\n break;\n case '1 week':\n afterDate.setDate(afterDate.getDate() - 6);\n toDate.setDate(toDate.getDate() + 8);\n break;\n case '2 weeks':\n afterDate.setDate(afterDate.getDate() - 13);\n toDate.setDate(toDate.getDate() + 15);\n break;\n case '1 month':\n afterDate.setMonth(afterDate.getMonth() - 1);\n afterDate.setDate(afterDate.getDate() + 1);\n toDate.setMonth(toDate.getMonth() + 1);\n toDate.setDate(toDate.getDate() + 1);\n break;\n case '2 months':\n afterDate.setMonth(afterDate.getMonth() - 2);\n afterDate.setDate(afterDate.getDate() + 1);\n toDate.setMonth(toDate.getMonth() + 2);\n toDate.setDate(toDate.getDate() + 1);\n break;\n case '6 months':\n afterDate.setMonth(afterDate.getMonth() - 6);\n afterDate.setDate(afterDate.getDate() + 1);\n toDate.setMonth(toDate.getMonth() + 6);\n toDate.setDate(toDate.getDate() + 1);\n break;\n case '1 year':\n afterDate.setFullYear(afterDate.getFullYear() - 1);\n afterDate.setDate(afterDate.getDate() + 1);\n toDate.setFullYear(toDate.getFullYear() + 1);\n toDate.setDate(toDate.getDate() + 1);\n break;\n }\n setValue(`${hasWords && (hasWords + \" \")}after:${yyyyMMddFormat(afterDate)} to:${yyyyMMddFormat(toDate)}`)\n } else {\n setValue(hasWords);\n }\n \n setIsAdvancedSearchOpen(false);\n };\n \n const searchInput = (\n <SearchInput\n value={value}\n onChange={onChange}\n onToggleAdvancedSearch={(e, isOpen) => {\n e.stopPropagation();\n setIsAdvancedSearchOpen(isOpen)\n }}\n isAdvancedSearchOpen={isAdvancedSearchOpen}\n onClear={onClear}\n onSearch={onSubmit}\n ref={searchInputRef}\n id=\"custom-advanced-search\"\n />\n );\n \n // Clicking the 'date within' toggle should open its associated menu and then place the browser \n // focus on the first menu item. \n const toggleDateWithinMenu = ev => {\n ev.stopPropagation(); // Stop handleClickOutside from handling\n setTimeout(() => {\n if (dateWithinMenuRef.current) {\n const firstElement = dateWithinMenuRef.current.querySelector('li > button:not(:disabled)');\n firstElement && firstElement.focus();\n }\n }, 0);\n setIsDateWithinOpen(!isDateWithinOpen);\n };\n \n // Selecting a date within option closes the menu, sets the value of date within, and puts browser focus back\n // on the date within toggle.\n const onDateWithinSelect = (e, itemId) => {\n e.stopPropagation();\n setIsDateWithinOpen(false);\n setDateWithin(itemId);\n if (dateWithinToggleRef && dateWithinToggleRef.current) {\n dateWithinToggleRef.current.focus();\n }\n };\n \n const dateWithinOptions = (\n <Menu ref={dateWithinMenuRef} selected={dateWithin} onSelect={onDateWithinSelect}>\n <MenuContent>\n <MenuList>\n <MenuItem itemId=\"1 day\">1 day</MenuItem>\n <MenuItem itemId=\"3 days\">3 days</MenuItem>\n <MenuItem itemId=\"1 week\">1 week</MenuItem>\n <MenuItem itemId=\"2 weeks\">2 weeks</MenuItem>\n <MenuItem itemId=\"1 month\">1 month</MenuItem>\n <MenuItem itemId=\"2 months\">2 months</MenuItem>\n <MenuItem itemId=\"6 months\">6 months</MenuItem>\n <MenuItem itemId=\"1 year\">1 year</MenuItem>\n </MenuList>\n </MenuContent>\n </Menu>\n );\n \n const dateWithinToggle = (\n <MenuToggle ref={dateWithinToggleRef} onClick={toggleDateWithinMenu} isExpanded={isDateWithinOpen} style={{width: \"100%\"}}>\n {dateWithin}\n </MenuToggle>\n );\n \n const advancedForm = (\n <div ref={advancedSearchPaneRef} role=\"dialog\" aria-label=\"Advanced search form\">\n <Card>\n <CardBody>\n <Form>\n <FormGroup label='Has the words' fieldId='has-words' key='has-words'>\n <TextInput\n type='text'\n id='has-words'\n value={hasWords}\n onChange={value => {\n setHasWords(value);\n setValue(value);\n }}\n ref={firstAttrRef}\n />\n </FormGroup>\n <Grid hasGutter md={6}>\n <GridItem>\n <FormGroup label='Date within' fieldId='date-within' key='date-within'>\n <Popper trigger={dateWithinToggle} popper={dateWithinOptions} isVisible={isDateWithinOpen} />\n </FormGroup>\n </GridItem>\n <GridItem>\n <FormGroup label='Of date' fieldId='date' key='date'>\n <DatePicker \n id=\"datePicker\" \n style={{width: \"100%\"}} \n value={date} \n onChange={setDate} \n appendTo={() => document.querySelector(\"#datePicker\")}\n />\n </FormGroup>\n </GridItem>\n </Grid>\n <ActionGroup>\n <Button variant=\"primary\" type=\"submit\" onClick={(e) => onSubmit(null, e)}>Submit</Button>\n {!!onClear && (\n <Button variant=\"link\" type=\"reset\" onClick={onClear}>Reset</Button>\n )}\n </ActionGroup>\n </Form>\n </CardBody>\n </Card>\n </div>\n );\n\n // Popper is just one way to build a relationship between a toggle and a menu.\n return (\n <Popper\n trigger={searchInput}\n popper={advancedForm}\n isVisible={isAdvancedSearchOpen}\n enableFlip={false}\n appendTo={() => document.querySelector(\"#custom-advanced-search\")}\n />\n );\n};","title":"Composable advanced search","lang":"js"}}>
17
75
 
@@ -32,6 +90,7 @@ const Component = () => (
32
90
  <AutoLinkHeader {...{"id":"demos","size":"h2","className":"ws-title ws-h2"}}>
33
91
  {`Demos`}
34
92
  </AutoLinkHeader>
93
+ {React.createElement(pageData.examples["Search with autocomplete"])}
35
94
  {React.createElement(pageData.examples["Composable advanced search"])}
36
95
  </React.Fragment>
37
96
  );
@@ -43,6 +43,11 @@ const pageData = {
43
43
  "type": "React.ReactNode",
44
44
  "description": "Attribute label for strings unassociated with one of the provided listed attributes"
45
45
  },
46
+ {
47
+ "name": "hint",
48
+ "type": "string",
49
+ "description": "A suggestion for autocompleting"
50
+ },
46
51
  {
47
52
  "name": "isAdvancedSearchOpen",
48
53
  "type": "boolean",
@@ -164,6 +164,21 @@ const pageData = {
164
164
  "name": "isHidden",
165
165
  "type": "boolean",
166
166
  "description": "Flag indicating the Tr is hidden"
167
+ },
168
+ {
169
+ "name": "isHoverable",
170
+ "type": "boolean",
171
+ "description": "Flag which adds hover styles for the table row"
172
+ },
173
+ {
174
+ "name": "isRowSelected",
175
+ "type": "boolean",
176
+ "description": "Flag indicating the row is selected - adds selected styling"
177
+ },
178
+ {
179
+ "name": "onRowClick",
180
+ "type": "(event?: React.KeyboardEvent | React.MouseEvent) => void",
181
+ "description": "An event handler for the row"
167
182
  }
168
183
  ]
169
184
  },
@@ -779,10 +794,11 @@ const pageData = {
779
794
  ],
780
795
  "examples": [
781
796
  "Composable: Basic",
782
- "Composable: Row click handler, custom row wrapper, header tooltips & popovers",
797
+ "Composable: Custom row wrapper, header tooltips & popovers",
783
798
  "Composable: Sortable & wrapping headers",
784
- "Composable: Selectable",
799
+ "Composable: Selectable with checkbox",
785
800
  "Composable: Selectable radio input",
801
+ "Composable: Row click handler, hoverable & selected rows",
786
802
  "Composable: Actions",
787
803
  "Composable: Expandable",
788
804
  "Composable: Compound expandable",
@@ -814,8 +830,8 @@ pageData.examples = {
814
830
  <Example {...pageData} {...props} {...{"code":"import React from 'react';\nimport { TableComposable, Thead, Tbody, Tr, Th, Td, Caption } from '@patternfly/react-table';\nimport { ToggleGroup, ToggleGroupItem } from '@patternfly/react-core';\n\nComposableTableBasic = () => {\n const columns = ['Repositories', 'Branches', 'Pull requests', 'Workspaces', 'Last commit'];\n const rows = [\n ['one', 'two', 'three', 'four', 'five'],\n ['one - 2', null, null, 'four - 2', 'five - 2'],\n ['one - 3', 'two - 3', 'three - 3', 'four - 3', 'five - 3']\n ];\n const [choice, setChoice] = React.useState('default');\n const handleItemClick = (isSelected, event) => {\n const id = event.currentTarget.id;\n setChoice(id);\n };\n return (\n <React.Fragment>\n <ToggleGroup aria-label=\"Default with single selectable\">\n <ToggleGroupItem\n text=\"Default\"\n buttonId=\"default\"\n isSelected={choice === 'default'}\n onChange={handleItemClick}\n />\n <ToggleGroupItem\n text=\"Compact\"\n buttonId=\"compact\"\n isSelected={choice === 'compact'}\n onChange={handleItemClick}\n />\n <ToggleGroupItem\n text=\"Compact borderless\"\n buttonId=\"compactBorderless\"\n isSelected={choice === 'compactBorderless'}\n onChange={handleItemClick}\n />\n </ToggleGroup>\n <TableComposable\n aria-label=\"Simple table\"\n variant={choice !== 'default' ? 'compact' : null}\n borders={choice !== 'compactBorderless'}\n >\n <Caption>Simple table using composable components</Caption>\n <Thead>\n <Tr>\n {columns.map((column, columnIndex) => (\n <Th key={columnIndex}>{column}</Th>\n ))}\n </Tr>\n </Thead>\n <Tbody>\n {rows.map((row, rowIndex) => (\n <Tr key={rowIndex}>\n {row.map((cell, cellIndex) => (\n <Td key={`${rowIndex}_${cellIndex}`} dataLabel={columns[cellIndex]}>\n {cell}\n </Td>\n ))}\n </Tr>\n ))}\n </Tbody>\n </TableComposable>\n </React.Fragment>\n );\n};","title":"Composable: Basic","lang":"js"}}>
815
831
 
816
832
  </Example>,
817
- 'Composable: Row click handler, custom row wrapper, header tooltips & popovers': props =>
818
- <Example {...pageData} {...props} {...{"code":"import React from 'react';\nimport { TableComposable, Thead, Tbody, Tr, Th, Td } from '@patternfly/react-table';\n\nComposableTableMisc = () => {\n const columns = ['Repositories', 'Branches', 'Pull requests', 'Workspaces', 'Last commit'];\n const rows = [\n ['one', 'two', 'three', 'four', 'five'],\n [{ title: 'one - 2', colSpan: 3 }, null, null, 'four - 2', 'five - 2'],\n ['one - 3', 'two - 3', 'three - 3', 'four - 3', { title: 'five - 3 (not centered)', textCenter: false }]\n ];\n const onRowClick = (event, rowIndex, row) => {\n console.log(`handle row click ${rowIndex}`, row);\n };\n return (\n <TableComposable aria-label=\"Misc table\">\n <Thead noWrap>\n <Tr>\n <Th\n info={{\n tooltip: 'More information about repositories',\n className: 'repositories-info-tip',\n tooltipProps: {\n isContentLeftAligned: true\n }\n }}\n >\n {columns[0]}\n </Th>\n <Th>{columns[1]}</Th>\n <Th\n info={{\n popover: (\n <div>\n More <strong>information</strong> on pull requests\n </div>\n ),\n ariaLabel: 'More information on pull requests',\n popoverProps: {\n headerContent: 'Pull requests',\n footerContent: <a href=\"\">Click here for even more info</a>\n }\n }}\n >\n {columns[2]}\n </Th>\n <Th>{columns[3]}</Th>\n <Th textCenter>{columns[4]}</Th>\n </Tr>\n </Thead>\n <Tbody>\n {rows.map((row, rowIndex) => {\n const isOddRow = (rowIndex + 1) % 2;\n const customStyle = {\n borderLeft: '3px solid var(--pf-global--primary-color--100)'\n };\n return (\n <Tr\n key={rowIndex}\n onClick={event => onRowClick(event, rowIndex, row)}\n className={isOddRow ? 'odd-row-class' : 'even-row-class'}\n style={isOddRow ? customStyle : {}}\n >\n {row.map((cell, cellIndex) => {\n if (!cell) {\n return null;\n }\n let cellObject;\n if (typeof cell !== 'object') {\n cellObject = {\n title: cell\n };\n } else {\n cellObject = cell;\n }\n const { title, ...rest } = cellObject;\n return (\n <Td\n key={`${rowIndex}_${cellIndex}`}\n dataLabel={columns[cellIndex]}\n textCenter={cellIndex === row.length - 1}\n {...rest}\n >\n {title}\n </Td>\n );\n })}\n </Tr>\n );\n })}\n </Tbody>\n </TableComposable>\n );\n};","title":"Composable: Row click handler, custom row wrapper, header tooltips & popovers","lang":"js"}}>
833
+ 'Composable: Custom row wrapper, header tooltips & popovers': props =>
834
+ <Example {...pageData} {...props} {...{"code":"import React from 'react';\nimport { TableComposable, Thead, Tbody, Tr, Th, Td } from '@patternfly/react-table';\n\nComposableTableMisc = () => {\n const columns = ['Repositories', 'Branches', 'Pull requests', 'Workspaces', 'Last commit'];\n const rows = [\n ['one', 'two', 'three', 'four', 'five'],\n [{ title: 'one - 2', colSpan: 3 }, null, null, 'four - 2', 'five - 2'],\n ['one - 3', 'two - 3', 'three - 3', 'four - 3', { title: 'five - 3 (not centered)', textCenter: false }]\n ];\n \n return (\n <TableComposable aria-label=\"Misc table\">\n <Thead noWrap>\n <Tr>\n <Th\n info={{\n tooltip: 'More information about repositories',\n className: 'repositories-info-tip',\n tooltipProps: {\n isContentLeftAligned: true\n }\n }}\n >\n {columns[0]}\n </Th>\n <Th>{columns[1]}</Th>\n <Th\n info={{\n popover: (\n <div>\n More <strong>information</strong> on pull requests\n </div>\n ),\n ariaLabel: 'More information on pull requests',\n popoverProps: {\n headerContent: 'Pull requests',\n footerContent: <a href=\"\">Click here for even more info</a>\n }\n }}\n >\n {columns[2]}\n </Th>\n <Th>{columns[3]}</Th>\n <Th textCenter>{columns[4]}</Th>\n </Tr>\n </Thead>\n <Tbody>\n {rows.map((row, rowIndex) => {\n const isOddRow = (rowIndex + 1) % 2;\n const customStyle = {\n borderLeft: '3px solid var(--pf-global--primary-color--100)'\n };\n return (\n <Tr\n key={rowIndex}\n className={isOddRow ? 'odd-row-class' : 'even-row-class'}\n style={isOddRow ? customStyle : {}}\n >\n {row.map((cell, cellIndex) => {\n if (!cell) {\n return null;\n }\n let cellObject;\n if (typeof cell !== 'object') {\n cellObject = {\n title: cell\n };\n } else {\n cellObject = cell;\n }\n const { title, ...rest } = cellObject;\n return (\n <Td\n key={`${rowIndex}_${cellIndex}`}\n dataLabel={columns[cellIndex]}\n textCenter={cellIndex === row.length - 1}\n {...rest}\n >\n {title}\n </Td>\n );\n })}\n </Tr>\n );\n })}\n </Tbody>\n </TableComposable>\n );\n};","title":"Composable: Custom row wrapper, header tooltips & popovers","lang":"js"}}>
819
835
 
820
836
  <ul {...{"className":"ws-ul"}}>
821
837
 
@@ -861,11 +877,6 @@ pageData.examples = {
861
877
  <li {...{"className":"ws-li"}}>
862
878
  {`You can pass `}
863
879
 
864
- <code {...{"className":"ws-code"}}>
865
- {`onClick`}
866
- </code>
867
- {`, `}
868
-
869
880
  <code {...{"className":"ws-code"}}>
870
881
  {`className`}
871
882
  </code>
@@ -942,8 +953,8 @@ pageData.examples = {
942
953
 
943
954
  </Example>
944
955
  </Example>,
945
- 'Composable: Selectable': props =>
946
- <Example {...pageData} {...props} {...{"code":"import React from 'react';\nimport { TableComposable, Thead, Tbody, Tr, Th, Td } from '@patternfly/react-table';\n\nComposableTableSelectable = () => {\n const columns = ['Repositories', 'Branches', 'Pull requests', 'Workspaces', 'Last commit'];\n const rows = [\n ['one', 'two', 'a', 'four', 'five'],\n ['a', 'two', 'k', 'four', 'five'],\n ['a', 'two', 'k', 'four', 'five'],\n ['a', 'two', 'k', 'four', 'five'],\n ['a', 'two', 'k', 'four', 'five'],\n ['p', 'two', 'b', 'four', 'five']\n ];\n const [allRowsSelected, setAllRowsSelected] = React.useState(false);\n const [selected, setSelected] = React.useState(rows.map(row => false));\n const [recentSelection, setRecentSelection] = React.useState(null);\n const [shifting, setShifting] = React.useState(false);\n const onSelect = (event, isSelected, rowId) => {\n let newSelected = selected.map((sel, index) => (index === rowId ? isSelected : sel))\n \n // if the user is shift + selecting the checkboxes, then all intermediate checkboxes should be selected\n if (shifting && recentSelection !== null && isSelected) {\n const numberSelected = rowId - recentSelection;\n newSelected = newSelected.map((sel, index) => {\n // select all between recentSelection and current rowId;\n const intermediateIndexes = numberSelected > 0 ? \n Array.from(new Array(numberSelected + 1), (x, i) => i + (recentSelection)) : \n Array.from(new Array(Math.abs(numberSelected) + 1), (x, i) => i + rowId);\n return intermediateIndexes.includes(index) ? true : sel;\n })\n }\n setSelected(newSelected);\n setRecentSelection(rowId);\n \n if (!isSelected && allRowsSelected) {\n setAllRowsSelected(false);\n } else if (isSelected && !allRowsSelected) {\n let allSelected = true;\n for (let i = 0; i < selected.length; i++) {\n if (i !== rowId) {\n if (!selected[i]) {\n allSelected = false;\n }\n }\n }\n if (allSelected) {\n setAllRowsSelected(true);\n }\n }\n };\n \n onKeyDown = (e) => {\n if (e.key === 'Shift') {\n setShifting(true);\n }\n };\n onKeyUp = (e) => {\n if (e.key === 'Shift') {\n setShifting(false);\n }\n };\n \n React.useEffect(() => {\n document.addEventListener(\"keydown\", onKeyDown);\n document.addEventListener(\"keyup\", onKeyUp);\n \n return () => {\n document.removeEventListener(\"keydown\", onKeyDown);\n document.removeEventListener(\"keyup\", onKeyUp);\n }\n }, []);\n \n const onSelectAll = (event, isSelected) => {\n setAllRowsSelected(isSelected);\n setSelected(selected.map(sel => isSelected));\n };\n \n return (\n <TableComposable aria-label=\"Selectable Table\">\n <Thead>\n <Tr>\n <Th\n select={{\n onSelect: onSelectAll,\n isSelected: allRowsSelected\n }}\n />\n <Th>{columns[0]}</Th>\n <Th>{columns[1]}</Th>\n <Th>{columns[2]}</Th>\n <Th>{columns[3]}</Th>\n <Th>{columns[4]}</Th>\n </Tr>\n </Thead>\n <Tbody>\n {rows.map((row, rowIndex) => (\n <Tr key={rowIndex}>\n <Td\n key={`${rowIndex}_0`}\n select={{\n rowIndex,\n onSelect,\n isSelected: selected[rowIndex] && rowIndex !== 1,\n disable: rowIndex === 1\n }}\n />\n {row.map((cell, cellIndex) => {\n const shiftedIndex = cellIndex + 1;\n return (\n <Td key={`${rowIndex}_${shiftedIndex}`} dataLabel={columns[cellIndex]}>\n {cell}\n </Td>\n );\n })}\n </Tr>\n ))}\n </Tbody>\n </TableComposable>\n );\n};","title":"Composable: Selectable","lang":"js"}}>
956
+ 'Composable: Selectable with checkbox': props =>
957
+ <Example {...pageData} {...props} {...{"code":"import React from 'react';\nimport { TableComposable, Thead, Tbody, Tr, Th, Td } from '@patternfly/react-table';\n\nComposableTableSelectable = () => {\n const columns = ['Repositories', 'Branches', 'Pull requests', 'Workspaces', 'Last commit'];\n const rows = [\n ['one', 'two', 'a', 'four', 'five'],\n ['a', 'two', 'k', 'four', 'five'],\n ['a', 'two', 'k', 'four', 'five'],\n ['a', 'two', 'k', 'four', 'five'],\n ['a', 'two', 'k', 'four', 'five'],\n ['p', 'two', 'b', 'four', 'five']\n ];\n const [allRowsSelected, setAllRowsSelected] = React.useState(false);\n const [selected, setSelected] = React.useState(rows.map(row => false));\n const [recentSelection, setRecentSelection] = React.useState(null);\n const [shifting, setShifting] = React.useState(false);\n const onSelect = (event, isSelected, rowId) => {\n let newSelected = selected.map((sel, index) => (index === rowId ? isSelected : sel))\n \n // if the user is shift + selecting the checkboxes, then all intermediate checkboxes should be selected\n if (shifting && recentSelection !== null && isSelected) {\n const numberSelected = rowId - recentSelection;\n newSelected = newSelected.map((sel, index) => {\n // select all between recentSelection and current rowId;\n const intermediateIndexes = numberSelected > 0 ? \n Array.from(new Array(numberSelected + 1), (x, i) => i + (recentSelection)) : \n Array.from(new Array(Math.abs(numberSelected) + 1), (x, i) => i + rowId);\n return intermediateIndexes.includes(index) ? true : sel;\n })\n }\n setSelected(newSelected);\n setRecentSelection(rowId);\n \n if (!isSelected && allRowsSelected) {\n setAllRowsSelected(false);\n } else if (isSelected && !allRowsSelected) {\n let allSelected = true;\n for (let i = 0; i < selected.length; i++) {\n if (i !== rowId) {\n if (!selected[i]) {\n allSelected = false;\n }\n }\n }\n if (allSelected) {\n setAllRowsSelected(true);\n }\n }\n };\n \n onKeyDown = (e) => {\n if (e.key === 'Shift') {\n setShifting(true);\n }\n };\n onKeyUp = (e) => {\n if (e.key === 'Shift') {\n setShifting(false);\n }\n };\n \n React.useEffect(() => {\n document.addEventListener(\"keydown\", onKeyDown);\n document.addEventListener(\"keyup\", onKeyUp);\n \n return () => {\n document.removeEventListener(\"keydown\", onKeyDown);\n document.removeEventListener(\"keyup\", onKeyUp);\n }\n }, []);\n \n const onSelectAll = (event, isSelected) => {\n setAllRowsSelected(isSelected);\n setSelected(selected.map(sel => isSelected));\n };\n \n return (\n <TableComposable aria-label=\"Selectable Table\">\n <Thead>\n <Tr>\n <Th\n select={{\n onSelect: onSelectAll,\n isSelected: allRowsSelected\n }}\n />\n <Th>{columns[0]}</Th>\n <Th>{columns[1]}</Th>\n <Th>{columns[2]}</Th>\n <Th>{columns[3]}</Th>\n <Th>{columns[4]}</Th>\n </Tr>\n </Thead>\n <Tbody>\n {rows.map((row, rowIndex) => (\n <Tr key={rowIndex}>\n <Td\n key={`${rowIndex}_0`}\n select={{\n rowIndex,\n onSelect,\n isSelected: selected[rowIndex] && rowIndex !== 1,\n disable: rowIndex === 1\n }}\n />\n {row.map((cell, cellIndex) => {\n const shiftedIndex = cellIndex + 1;\n return (\n <Td key={`${rowIndex}_${shiftedIndex}`} dataLabel={columns[cellIndex]}>\n {cell}\n </Td>\n );\n })}\n </Tr>\n ))}\n </Tbody>\n </TableComposable>\n );\n};","title":"Composable: Selectable with checkbox","lang":"js"}}>
947
958
 
948
959
  <p {...{"className":"ws-p"}}>
949
960
  {`To make a row selectable, the table needs a selection column.
@@ -1040,6 +1051,13 @@ checking checkboxes will check intermediate rows' checkboxes.`}
1040
1051
  {`Similarly to the selectable example above, the radio buttons use the first column. The first header cell is empty, and each body row's first cell has radio button props.`}
1041
1052
  </p>
1042
1053
  </Example>,
1054
+ 'Composable: Row click handler, hoverable & selected rows': props =>
1055
+ <Example {...pageData} {...props} {...{"code":"import React from 'react';\nimport { TableComposable, Thead, Tbody, Tr, Th, Td } from '@patternfly/react-table';\n\nComposableTableHoverable = () => {\n const columns = ['Repositories', 'Branches', 'Pull requests', 'Workspaces', 'Last commit'];\n const [rows, setRows] = React.useState([\n { cells: ['one', 'two', 'a', 'four', 'five'], isRowSelected: false},\n { cells: ['a', 'two', 'k', 'four', 'five'], isRowSelected: false},\n { cells: ['p', 'two', 'b', 'four', 'five'], isRowSelected: false}\n ]);\n const onRowClick = (event, rowIndex, row) => {\n const updatedRows = [...rows];\n updatedRows[rowIndex].isRowSelected = !rows[rowIndex].isRowSelected;\n setRows(updatedRows); \n };\n \n return (\n <TableComposable aria-label=\"Misc table\">\n <Thead noWrap>\n <Tr>\n <Th>\n {columns[0]}\n </Th>\n <Th>{columns[1]}</Th>\n <Th>\n {columns[2]}\n </Th>\n <Th>{columns[3]}</Th>\n <Th>{columns[4]}</Th>\n </Tr>\n </Thead>\n <Tbody>\n {rows.map((row, rowIndex) => {\n return (\n <Tr\n key={rowIndex}\n onRowClick={event => onRowClick(event, rowIndex, row.cells)}\n isHoverable\n isRowSelected={row.isRowSelected}\n >\n {row.cells.map((cell, cellIndex) => {\n return (\n <Td\n key={`${rowIndex}_${cellIndex}`}\n dataLabel={columns[cellIndex]}\n >\n {cell}\n </Td>\n );\n })}\n </Tr>\n );\n })}\n </Tbody>\n </TableComposable>\n );\n};","title":"Composable: Row click handler, hoverable & selected rows","lang":"js"}}>
1056
+
1057
+ <p {...{"className":"ws-p"}}>
1058
+ {`This selectable rows feature is intended for use when a table is used to present a list of objects in a Primary-detail view.`}
1059
+ </p>
1060
+ </Example>,
1043
1061
  'Composable: Actions': props =>
1044
1062
  <Example {...pageData} {...props} {...{"code":"import React from 'react';\nimport { TableComposable, Thead, Tbody, Tr, Th, Td } from '@patternfly/react-table';\nimport { ButtonVariant, DropdownToggle, ToggleGroup, ToggleGroupItem } from '@patternfly/react-core';\n\nComposableTableActions = () => {\n const defaultActions = [\n {\n title: 'Some action',\n onClick: (event, rowId, rowData, extra) => console.log('clicked on Some action, on row: ', rowId)\n },\n {\n title: <a href=\"https://www.patternfly.org\">Link action</a>\n },\n {\n isSeparator: true\n },\n {\n title: 'Third action',\n onClick: (event, rowId, rowData, extra) => console.log('clicked on Third action, on row: ', rowId)\n },\n {\n title: 'Start',\n variant: ButtonVariant.secondary,\n onClick: (event, rowId, rowData, extra) => console.log('clicked on extra action, on row: ', rowId),\n isOutsideDropdown: true\n }\n ];\n const lastRowActions = [\n {\n title: 'Some action',\n onClick: (event, rowId, rowData, extra) => console.log(`clicked on Some action, on row ${rowId}`)\n },\n {\n title: <div>Another action</div>,\n onClick: (event, rowId, rowData, extra) => console.log(`clicked on Another action, on row ${rowId}`)\n },\n {\n isSeparator: true\n },\n {\n title: 'Third action',\n onClick: (event, rowId, rowData, extra) => console.log(`clicked on Third action, on row ${rowId}`)\n }\n ];\n const columns = ['Repositories', 'Branches', 'Pull requests', 'Workspaces', 'Last commit'];\n const rows = [\n ['one', 'two', 'a', 'four', 'five'],\n ['a', 'two', 'k', 'four', 'five'],\n ['p', 'two', 'b', 'four', 'five'],\n ['4', '2', 'b', 'four', 'five'],\n ['5', '2', 'b', 'four', 'five']\n ];\n\n const [toggle, setToggle] = React.useState('defaultToggle');\n\n const customActionsToggle = props => (\n <DropdownToggle onToggle={props.onToggle} isDisabled={props.isDisabled}>\n Actions\n </DropdownToggle>\n );\n\n const toggleCustomToggle = (checked, event) => {\n setToggle(event.currentTarget.id);\n };\n\n return (\n <React.Fragment>\n <ToggleGroup aria-label=\"Default uses kebab toggle\">\n <ToggleGroupItem\n text=\"Default actions toggle\"\n buttonId=\"defaultToggle\"\n isSelected={toggle === 'defaultToggle'}\n onChange={toggleCustomToggle}\n />\n <ToggleGroupItem\n text=\"Custom actions toggle\"\n buttonId=\"customToggle\"\n isSelected={toggle === 'customToggle'}\n onChange={toggleCustomToggle}\n />\n </ToggleGroup>\n <TableComposable aria-label=\"Actions table\">\n <Thead>\n <Tr>\n <Th>{columns[0]}</Th>\n <Th>{columns[1]}</Th>\n <Th>{columns[2]}</Th>\n <Th>{columns[3]}</Th>\n <Th>{columns[4]}</Th>\n <Th />\n </Tr>\n </Thead>\n <Tbody>\n {rows.map((row, rowIndex) => (\n <Tr key={rowIndex}>\n {row.map((cell, cellIndex) => (\n <Td key={`${rowIndex}_${cellIndex}`} dataLabel={columns[cellIndex]}>\n {cell}\n </Td>\n ))}\n <Td\n key={`${rowIndex}_5`}\n actions={{\n items: rowIndex === 1 ? null : rowIndex === 4 ? lastRowActions : defaultActions,\n disable: rowIndex === 3,\n actionsToggle: toggle === 'customToggle' ? customActionsToggle : undefined\n }}\n />\n </Tr>\n ))}\n </Tbody>\n </TableComposable>\n </React.Fragment>\n );\n};","title":"Composable: Actions","lang":"js"}}>
1045
1063
 
@@ -1810,10 +1828,11 @@ const Component = () => (
1810
1828
  </li>
1811
1829
  </ul>
1812
1830
  {React.createElement(pageData.examples["Composable: Basic"])}
1813
- {React.createElement(pageData.examples["Composable: Row click handler, custom row wrapper, header tooltips & popovers"])}
1831
+ {React.createElement(pageData.examples["Composable: Custom row wrapper, header tooltips & popovers"])}
1814
1832
  {React.createElement(pageData.examples["Composable: Sortable & wrapping headers"])}
1815
- {React.createElement(pageData.examples["Composable: Selectable"])}
1833
+ {React.createElement(pageData.examples["Composable: Selectable with checkbox"])}
1816
1834
  {React.createElement(pageData.examples["Composable: Selectable radio input"])}
1835
+ {React.createElement(pageData.examples["Composable: Row click handler, hoverable & selected rows"])}
1817
1836
  {React.createElement(pageData.examples["Composable: Actions"])}
1818
1837
  {React.createElement(pageData.examples["Composable: Expandable"])}
1819
1838
  {React.createElement(pageData.examples["Composable: Compound expandable"])}