@patternfly/react-docs 7.6.0-prerelease.7 → 7.6.0-prerelease.8
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/package.json +12 -13
- package/patternfly-docs/generated/components/about-modal/react.js +149 -0
- package/patternfly-docs/generated/components/accordion/react.js +262 -0
- package/patternfly-docs/generated/components/action-list/react.js +144 -0
- package/patternfly-docs/generated/components/alert/react-demos.js +56 -0
- package/patternfly-docs/generated/components/alert/react.js +1433 -0
- package/patternfly-docs/generated/components/avatar/react.js +166 -0
- package/patternfly-docs/generated/components/back-to-top/react-demos.js +60 -0
- package/patternfly-docs/generated/components/back-to-top/react.js +77 -0
- package/patternfly-docs/generated/components/backdrop/react.js +64 -0
- package/patternfly-docs/generated/components/background-image/react.js +62 -0
- package/patternfly-docs/generated/components/badge/react.js +97 -0
- package/patternfly-docs/generated/components/banner/react-demos.js +57 -0
- package/patternfly-docs/generated/components/banner/react.js +148 -0
- package/patternfly-docs/generated/components/brand/react.js +142 -0
- package/patternfly-docs/generated/components/breadcrumb/react.js +206 -0
- package/patternfly-docs/generated/components/button/react-demos.js +57 -0
- package/patternfly-docs/generated/components/button/react.js +826 -0
- package/patternfly-docs/generated/components/card/react-demos.js +201 -0
- package/patternfly-docs/generated/components/card/react.js +1015 -0
- package/patternfly-docs/generated/components/charts/area-chart/-Victory.js +1350 -0
- package/patternfly-docs/generated/components/charts/bar-chart/-Victory.js +1334 -0
- package/patternfly-docs/generated/components/charts/box-plot-chart/-Victory.js +1282 -0
- package/patternfly-docs/generated/components/charts/bullet-chart/-Victory.js +848 -0
- package/patternfly-docs/generated/components/charts/colors-for-charts/-Victory.js +192 -0
- package/patternfly-docs/generated/components/charts/donut-chart/-Victory.js +426 -0
- package/patternfly-docs/generated/components/charts/donut-utilization-chart/-Victory.js +804 -0
- package/patternfly-docs/generated/components/charts/legends/-Victory.js +3230 -0
- package/patternfly-docs/generated/components/charts/line-chart/-Victory.js +1178 -0
- package/patternfly-docs/generated/components/charts/line-chart/ECharts.js +525 -0
- package/patternfly-docs/generated/components/charts/patterns/-Victory.js +3382 -0
- package/patternfly-docs/generated/components/charts/pie-chart/-Victory.js +377 -0
- package/patternfly-docs/generated/components/charts/resize-observer/-Victory.js +2475 -0
- package/patternfly-docs/generated/components/charts/sankey-chart/ECharts.js +538 -0
- package/patternfly-docs/generated/components/charts/scatter-chart/-Victory.js +1551 -0
- package/patternfly-docs/generated/components/charts/skeletons/-Victory.js +4115 -0
- package/patternfly-docs/generated/components/charts/sparkline-chart/-Victory.js +955 -0
- package/patternfly-docs/generated/components/charts/stack-chart/-Victory.js +1173 -0
- package/patternfly-docs/generated/components/charts/threshold-chart/-Victory.js +1166 -0
- package/patternfly-docs/generated/components/charts/tooltips/-Victory.js +413 -0
- package/patternfly-docs/generated/components/chip/react-deprecated.js +323 -0
- package/patternfly-docs/generated/components/clipboard-copy/react.js +373 -0
- package/patternfly-docs/generated/components/code-block/react.js +148 -0
- package/patternfly-docs/generated/components/code-editor/react.js +659 -0
- package/patternfly-docs/generated/components/compass/react-demos.js +147 -0
- package/patternfly-docs/generated/components/compass/react.js +440 -0
- package/patternfly-docs/generated/components/content/react.js +248 -0
- package/patternfly-docs/generated/components/data-list/react-demos.js +90 -0
- package/patternfly-docs/generated/components/data-list/react.js +709 -0
- package/patternfly-docs/generated/components/date-and-time/calendar-month/react.js +283 -0
- package/patternfly-docs/generated/components/date-and-time/date-and-time-picker/react-demos.js +64 -0
- package/patternfly-docs/generated/components/date-and-time/date-picker/react-demos.js +83 -0
- package/patternfly-docs/generated/components/date-and-time/date-picker/react.js +395 -0
- package/patternfly-docs/generated/components/date-and-time/time-picker/react.js +241 -0
- package/patternfly-docs/generated/components/description-list/react-demos.js +58 -0
- package/patternfly-docs/generated/components/description-list/react.js +743 -0
- package/patternfly-docs/generated/components/divider/react.js +126 -0
- package/patternfly-docs/generated/components/drag-and-drop/react-demos.js +351 -0
- package/patternfly-docs/generated/components/drag-and-drop/react-deprecated.js +184 -0
- package/patternfly-docs/generated/components/drag-and-drop/react.js +137 -0
- package/patternfly-docs/generated/components/drawer/react.js +598 -0
- package/patternfly-docs/generated/components/dual-list-selector/react-deprecated.js +772 -0
- package/patternfly-docs/generated/components/dual-list-selector/react.js +594 -0
- package/patternfly-docs/generated/components/empty-state/react.js +199 -0
- package/patternfly-docs/generated/components/expandable-section/react-demos.js +65 -0
- package/patternfly-docs/generated/components/expandable-section/react.js +408 -0
- package/patternfly-docs/generated/components/file-upload/multiple-file-upload/react-demos.js +52 -0
- package/patternfly-docs/generated/components/file-upload/multiple-file-upload/react.js +398 -0
- package/patternfly-docs/generated/components/file-upload/simple-file-upload/react.js +749 -0
- package/patternfly-docs/generated/components/forms/checkbox/react.js +222 -0
- package/patternfly-docs/generated/components/forms/form/react.js +1106 -0
- package/patternfly-docs/generated/components/forms/form-select/react.js +208 -0
- package/patternfly-docs/generated/components/forms/radio/react.js +212 -0
- package/patternfly-docs/generated/components/forms/text-area/react.js +160 -0
- package/patternfly-docs/generated/components/forms/text-input/react.js +216 -0
- package/patternfly-docs/generated/components/helper-text/react-demos.js +180 -0
- package/patternfly-docs/generated/components/helper-text/react.js +164 -0
- package/patternfly-docs/generated/components/hero/react.js +88 -0
- package/patternfly-docs/generated/components/hint/react.js +169 -0
- package/patternfly-docs/generated/components/icon/react.js +215 -0
- package/patternfly-docs/generated/components/input-group/react.js +182 -0
- package/patternfly-docs/generated/components/jump-links/react-demos.js +154 -0
- package/patternfly-docs/generated/components/jump-links/react.js +212 -0
- package/patternfly-docs/generated/components/label/react-demos.js +57 -0
- package/patternfly-docs/generated/components/label/react.js +417 -0
- package/patternfly-docs/generated/components/list/react.js +175 -0
- package/patternfly-docs/generated/components/login-page/react.js +587 -0
- package/patternfly-docs/generated/components/masthead/react-demos.js +79 -0
- package/patternfly-docs/generated/components/masthead/react.js +291 -0
- package/patternfly-docs/generated/components/menus/application-launcher/react-demos.js +769 -0
- package/patternfly-docs/generated/components/menus/context-selector/react-demos.js +665 -0
- package/patternfly-docs/generated/components/menus/custom-menus/react-demos.js +187 -0
- package/patternfly-docs/generated/components/menus/dropdown/react-templates.js +163 -0
- package/patternfly-docs/generated/components/menus/dropdown/react.js +998 -0
- package/patternfly-docs/generated/components/menus/menu/react.js +1540 -0
- package/patternfly-docs/generated/components/menus/menu-toggle/react.js +747 -0
- package/patternfly-docs/generated/components/menus/options-menu/react-demos.js +508 -0
- package/patternfly-docs/generated/components/menus/select/react-templates.js +257 -0
- package/patternfly-docs/generated/components/menus/select/react.js +998 -0
- package/patternfly-docs/generated/components/modal/react-deprecated.js +554 -0
- package/patternfly-docs/generated/components/modal/react.js +597 -0
- package/patternfly-docs/generated/components/navigation/react-demos.js +356 -0
- package/patternfly-docs/generated/components/navigation/react.js +409 -0
- package/patternfly-docs/generated/components/notification-badge/react.js +196 -0
- package/patternfly-docs/generated/components/notification-drawer/react-demos.js +107 -0
- package/patternfly-docs/generated/components/notification-drawer/react.js +394 -0
- package/patternfly-docs/generated/components/number-input/react.js +210 -0
- package/patternfly-docs/generated/components/overflow-menu/react.js +274 -0
- package/patternfly-docs/generated/components/page/react-demos.js +149 -0
- package/patternfly-docs/generated/components/page/react.js +1352 -0
- package/patternfly-docs/generated/components/pagination/react.js +492 -0
- package/patternfly-docs/generated/components/panel/react.js +236 -0
- package/patternfly-docs/generated/components/popover/react.js +390 -0
- package/patternfly-docs/generated/components/progress/react-demos.js +59 -0
- package/patternfly-docs/generated/components/progress/react.js +283 -0
- package/patternfly-docs/generated/components/progress-stepper/react-demos.js +45 -0
- package/patternfly-docs/generated/components/progress-stepper/react.js +219 -0
- package/patternfly-docs/generated/components/search-input/react-demos.js +113 -0
- package/patternfly-docs/generated/components/search-input/react.js +263 -0
- package/patternfly-docs/generated/components/sidebar/react.js +236 -0
- package/patternfly-docs/generated/components/simple-list/react.js +200 -0
- package/patternfly-docs/generated/components/skeleton/react-demos.js +44 -0
- package/patternfly-docs/generated/components/skeleton/react.js +122 -0
- package/patternfly-docs/generated/components/skip-to-content/react.js +73 -0
- package/patternfly-docs/generated/components/slider/react.js +309 -0
- package/patternfly-docs/generated/components/spinner/react.js +111 -0
- package/patternfly-docs/generated/components/switch/react.js +163 -0
- package/patternfly-docs/generated/components/table/react-demos.js +355 -0
- package/patternfly-docs/generated/components/table/react-deprecated.js +1350 -0
- package/patternfly-docs/generated/components/table/react.js +3241 -0
- package/patternfly-docs/generated/components/tabs/react-demos.js +108 -0
- package/patternfly-docs/generated/components/tabs/react.js +1359 -0
- package/patternfly-docs/generated/components/text-input-group/react-demos.js +152 -0
- package/patternfly-docs/generated/components/text-input-group/react.js +278 -0
- package/patternfly-docs/generated/components/tile/react-deprecated.js +242 -0
- package/patternfly-docs/generated/components/timestamp/react.js +283 -0
- package/patternfly-docs/generated/components/title/react.js +94 -0
- package/patternfly-docs/generated/components/toggle-group/react.js +299 -0
- package/patternfly-docs/generated/components/toolbar/react-demos.js +66 -0
- package/patternfly-docs/generated/components/toolbar/react.js +932 -0
- package/patternfly-docs/generated/components/tooltip/react.js +241 -0
- package/patternfly-docs/generated/components/tree-view/react.js +429 -0
- package/patternfly-docs/generated/components/truncate/react.js +211 -0
- package/patternfly-docs/generated/components/wizard/react-demos.js +87 -0
- package/patternfly-docs/generated/components/wizard/react-deprecated.js +788 -0
- package/patternfly-docs/generated/components/wizard/react.js +986 -0
- package/patternfly-docs/generated/developer-guides/open-ui-automation/react.js +285 -0
- package/patternfly-docs/generated/foundations-and-styles/layouts/bullseye/react.js +70 -0
- package/patternfly-docs/generated/foundations-and-styles/layouts/flex/react.js +506 -0
- package/patternfly-docs/generated/foundations-and-styles/layouts/gallery/react.js +94 -0
- package/patternfly-docs/generated/foundations-and-styles/layouts/grid/react.js +272 -0
- package/patternfly-docs/generated/foundations-and-styles/layouts/level/react.js +87 -0
- package/patternfly-docs/generated/foundations-and-styles/layouts/split/react.js +124 -0
- package/patternfly-docs/generated/foundations-and-styles/layouts/stack/react.js +112 -0
- package/patternfly-docs/generated/index.js +1769 -0
- package/patternfly-docs/generated/patterns/card-view/react-demos.js +78 -0
- package/patternfly-docs/generated/patterns/filters/react-demos.js +141 -0
- package/patternfly-docs/generated/patterns/password-generator/react-demos.js +51 -0
- package/patternfly-docs/generated/patterns/password-strength/react-demos.js +61 -0
- package/patternfly-docs/generated/patterns/primary-detail/react-demos.js +124 -0
- package/patternfly-docs/generated/patterns/right-to-left/react-demos.js +81 -0
- package/LICENSE +0 -21
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import RhUiCheckCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-check-circle-fill-icon';
|
|
5
|
+
const pageData = {
|
|
6
|
+
"id": "Expandable section",
|
|
7
|
+
"section": "components",
|
|
8
|
+
"subsection": "",
|
|
9
|
+
"deprecated": false,
|
|
10
|
+
"template": false,
|
|
11
|
+
"beta": false,
|
|
12
|
+
"demo": false,
|
|
13
|
+
"newImplementationLink": false,
|
|
14
|
+
"source": "react",
|
|
15
|
+
"tabName": null,
|
|
16
|
+
"slug": "/components/expandable-section/react",
|
|
17
|
+
"sourceLink": "https://github.com/patternfly/patternfly-react/blob/main/packages/react-core/src/components/ExpandableSection/examples/ExpandableSection.md",
|
|
18
|
+
"relPath": "packages/react-core/src/components/ExpandableSection/examples/ExpandableSection.md",
|
|
19
|
+
"propComponents": [
|
|
20
|
+
{
|
|
21
|
+
"name": "ExpandableSection",
|
|
22
|
+
"description": "The main expandable section component.",
|
|
23
|
+
"props": [
|
|
24
|
+
{
|
|
25
|
+
"name": "children",
|
|
26
|
+
"type": "React.ReactNode",
|
|
27
|
+
"description": "Content rendered inside the expandable section."
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "className",
|
|
31
|
+
"type": "string",
|
|
32
|
+
"description": "Additional classes added to the expandable section.",
|
|
33
|
+
"defaultValue": "''"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "contentId",
|
|
37
|
+
"type": "string",
|
|
38
|
+
"description": "Id of the content of the expandable section. When passing in the isDetached property, this\nproperty's value should match the contentId property of the expandable section toggle sub-component."
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"name": "direction",
|
|
42
|
+
"type": "'up' | 'down'",
|
|
43
|
+
"description": "Sets the direction of the expandable animation when isDetached is true. If this prop is not passed,\nanimation will not occur."
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "displaySize",
|
|
47
|
+
"type": "'default' | 'lg'",
|
|
48
|
+
"description": "Display size variant. Set to \"lg\" for disclosure styling.",
|
|
49
|
+
"defaultValue": "'default'"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"name": "hasToggleIcon",
|
|
53
|
+
"type": "boolean",
|
|
54
|
+
"description": "Whether to show a toggle icon when variant is not truncated. If omitted, it is important to ensure the current state of the ExpandableSection is conveyed, most likely by having dynamic toggle text."
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"name": "isDetached",
|
|
58
|
+
"type": "boolean",
|
|
59
|
+
"description": "Flag indicating that the expandable section and expandable toggle are detached from one another.",
|
|
60
|
+
"defaultValue": "false"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"name": "isExpanded",
|
|
64
|
+
"type": "boolean",
|
|
65
|
+
"description": "Flag to indicate if the content is expanded."
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"name": "isIndented",
|
|
69
|
+
"type": "boolean",
|
|
70
|
+
"description": "Flag to indicate if the content is indented.",
|
|
71
|
+
"defaultValue": "false"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"name": "isWidthLimited",
|
|
75
|
+
"type": "boolean",
|
|
76
|
+
"description": "Flag to indicate the width of the component is limited. Set to \"true\" for disclosure styling.",
|
|
77
|
+
"defaultValue": "false"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"name": "onToggle",
|
|
81
|
+
"type": "(event: React.MouseEvent, isExpanded: boolean) => void",
|
|
82
|
+
"description": "Callback function to toggle the expandable section. Detached expandable sections should\nuse the onToggle property of the expandable section toggle sub-component.",
|
|
83
|
+
"defaultValue": "(event, isExpanded): void => undefined"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"name": "toggleAriaLabel",
|
|
87
|
+
"type": "string",
|
|
88
|
+
"description": "Accessible name via human readable string for the expandable section toggle.",
|
|
89
|
+
"defaultValue": "undefined"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"name": "toggleAriaLabelledBy",
|
|
93
|
+
"type": "string",
|
|
94
|
+
"description": "Accessible name via space delimtted list of IDs for the expandable section toggle.",
|
|
95
|
+
"defaultValue": "undefined"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"name": "toggleContent",
|
|
99
|
+
"type": "React.ReactNode | ((isExpanded: boolean) => React.ReactNode)",
|
|
100
|
+
"description": "React node that appears in the attached toggle in place of the toggleText property.\nCan also be a function that receives the expanded state and returns a React node."
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"name": "toggleIcon",
|
|
104
|
+
"type": "React.ReactNode",
|
|
105
|
+
"description": "Icon shown in toggle when variant is not truncated."
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"name": "toggleId",
|
|
109
|
+
"type": "string",
|
|
110
|
+
"description": "Id of the toggle of the expandable section, which provides an accessible name to the\nexpandable section content via the aria-labelledby attribute. When the isDetached property\nis also passed in, the value of this property must match the toggleId property of the\nexpandable section toggle sub-component."
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"name": "toggleText",
|
|
114
|
+
"type": "string",
|
|
115
|
+
"description": "Text that appears in the attached toggle.",
|
|
116
|
+
"defaultValue": "''"
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"name": "toggleTextCollapsed",
|
|
120
|
+
"type": "string",
|
|
121
|
+
"description": "Text that appears in the attached toggle when collapsed (will override toggleText if\nboth are specified; used for uncontrolled expandable with dynamic toggle text).",
|
|
122
|
+
"defaultValue": "''"
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"name": "toggleTextExpanded",
|
|
126
|
+
"type": "string",
|
|
127
|
+
"description": "Text that appears in the attached toggle when expanded (will override toggleText if\nboth are specified; used for uncontrolled expandable with dynamic toggle text).",
|
|
128
|
+
"defaultValue": "''"
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"name": "toggleWrapper",
|
|
132
|
+
"type": "'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'",
|
|
133
|
+
"description": "The HTML element to use for the toggle wrapper. Can be 'div' (default) or any heading level.\nWhen using heading elements, the button will be rendered inside the heading for proper semantics.\nThis is useful when the toggle text should function as a heading in the document structure."
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"name": "truncateMaxLines",
|
|
137
|
+
"type": "number",
|
|
138
|
+
"description": "Truncates the expandable content to the specified number of lines when using the\n\"truncate\" variant."
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"name": "variant",
|
|
142
|
+
"type": "'default' | 'truncate'",
|
|
143
|
+
"description": "Determines the variant of the expandable section. When passing in \"truncate\" as the\nvariant, the expandable content will be truncated after 3 lines by default.",
|
|
144
|
+
"defaultValue": "'default'"
|
|
145
|
+
}
|
|
146
|
+
]
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"name": "ExpandableSectionToggle",
|
|
150
|
+
"description": "Acts as the toggle sub-component when the main expandable section component has the isDetached\nproperty passed in. Allows for more custom control over the expandable section's toggle.",
|
|
151
|
+
"props": [
|
|
152
|
+
{
|
|
153
|
+
"name": "children",
|
|
154
|
+
"type": "React.ReactNode",
|
|
155
|
+
"description": "Content rendered inside the expandable toggle."
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"name": "className",
|
|
159
|
+
"type": "string",
|
|
160
|
+
"description": "Additional classes added to the expandable toggle.",
|
|
161
|
+
"defaultValue": "''"
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"name": "contentId",
|
|
165
|
+
"type": "string",
|
|
166
|
+
"description": "Id of the toggle's respective expandable section content. The value passed into this\nproperty should match the contentId property of the main expandable section component."
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"name": "direction",
|
|
170
|
+
"type": "'up' | 'down'",
|
|
171
|
+
"description": "Direction the toggle arrow should point when the expandable section is expanded.",
|
|
172
|
+
"defaultValue": "'down'"
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"name": "hasTruncatedContent",
|
|
176
|
+
"type": "boolean",
|
|
177
|
+
"description": "Flag to determine toggle styling when the expandable content is truncated.",
|
|
178
|
+
"defaultValue": "false"
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"name": "isDetached",
|
|
182
|
+
"type": "boolean",
|
|
183
|
+
"description": "Flag indicating that the expandable section and expandable toggle are detached from one another."
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"name": "isExpanded",
|
|
187
|
+
"type": "boolean",
|
|
188
|
+
"description": "Flag indicating if the expandable section is expanded.",
|
|
189
|
+
"defaultValue": "false"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"name": "onToggle",
|
|
193
|
+
"type": "(isExpanded: boolean) => void",
|
|
194
|
+
"description": "Callback function to toggle the expandable content."
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
"name": "toggleAriaLabel",
|
|
198
|
+
"type": "string",
|
|
199
|
+
"description": "Accessible name via human readable string for the expandable section toggle."
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"name": "toggleAriaLabelledBy",
|
|
203
|
+
"type": "string",
|
|
204
|
+
"description": "Accessible name via space delimtted list of IDs for the expandable section toggle."
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"name": "toggleId",
|
|
208
|
+
"type": "string",
|
|
209
|
+
"description": "Id of the toggle. The value passed into this property should match the aria-labelledby\nproperty of the main expandable section component."
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
"name": "toggleWrapper",
|
|
213
|
+
"type": "'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'",
|
|
214
|
+
"description": "The HTML element to use for the toggle wrapper. Can be 'div' (default) or any heading level.\nWhen using heading elements, the button will be rendered inside the heading for proper semantics.\nThis is useful when the toggle text should function as a heading in the document structure.",
|
|
215
|
+
"defaultValue": "'div'"
|
|
216
|
+
}
|
|
217
|
+
]
|
|
218
|
+
}
|
|
219
|
+
],
|
|
220
|
+
"cssPrefix": [
|
|
221
|
+
"pf-v6-c-expandable-section"
|
|
222
|
+
],
|
|
223
|
+
"examples": [
|
|
224
|
+
"Basic",
|
|
225
|
+
"Uncontrolled",
|
|
226
|
+
"Uncontrolled with dynamic toggle text",
|
|
227
|
+
"Uncontrolled with dynamic toggle content (function)",
|
|
228
|
+
"Detached",
|
|
229
|
+
"Disclosure variation",
|
|
230
|
+
"Indented expandable content",
|
|
231
|
+
"With custom toggle content",
|
|
232
|
+
"With heading semantics",
|
|
233
|
+
"Truncate expansion"
|
|
234
|
+
]
|
|
235
|
+
};
|
|
236
|
+
pageData.liveContext = {
|
|
237
|
+
useState,
|
|
238
|
+
RhUiCheckCircleFillIcon
|
|
239
|
+
};
|
|
240
|
+
pageData.examples = {
|
|
241
|
+
'Basic': props =>
|
|
242
|
+
<Example {...pageData} {...props} {...{"code":"import { useState } from 'react';\nimport { ExpandableSection } from '@patternfly/react-core';\n\nexport const ExpandableSectionBasic: React.FunctionComponent = () => {\n const [isExpanded, setIsExpanded] = useState(false);\n\n const onToggle = (_event: React.MouseEvent, isExpanded: boolean) => {\n setIsExpanded(isExpanded);\n };\n\n return (\n <ExpandableSection\n toggleText={isExpanded ? 'Show less basic example content' : 'Show more basic example content'}\n onToggle={onToggle}\n isExpanded={isExpanded}\n >\n This content is visible only when the component is expanded.\n </ExpandableSection>\n );\n};\n","title":"Basic","lang":"ts","className":""}}>
|
|
243
|
+
|
|
244
|
+
</Example>,
|
|
245
|
+
'Uncontrolled': props =>
|
|
246
|
+
<Example {...pageData} {...props} {...{"code":"import { ExpandableSection } from '@patternfly/react-core';\n\nexport const ExpandableSectionUncontrolled: React.FunctionComponent = () => (\n <ExpandableSection toggleText=\"Show more uncontrolled example content\">\n This content is visible only when the component is expanded.\n </ExpandableSection>\n);\n","title":"Uncontrolled","lang":"ts","className":""}}>
|
|
247
|
+
|
|
248
|
+
</Example>,
|
|
249
|
+
'Uncontrolled with dynamic toggle text': props =>
|
|
250
|
+
<Example {...pageData} {...props} {...{"code":"import { ExpandableSection } from '@patternfly/react-core';\n\nexport const ExpandableSectionUncontrolledDynamicToggle: React.FunctionComponent = () => (\n <ExpandableSection\n toggleTextExpanded=\"Show less uncontrolled dynamic toggle example content\"\n toggleTextCollapsed=\"Show more uncontrolled dynamic toggle example content\"\n >\n This content is visible only when the component is expanded.\n </ExpandableSection>\n);\n","title":"Uncontrolled with dynamic toggle text","lang":"ts","className":""}}>
|
|
251
|
+
|
|
252
|
+
</Example>,
|
|
253
|
+
'Uncontrolled with dynamic toggle content (function)': props =>
|
|
254
|
+
<Example {...pageData} {...props} {...{"code":"import { ExpandableSection } from '@patternfly/react-core';\n\nexport const ExpandableSectionUncontrolledDynamicToggleFunction: React.FunctionComponent = () => (\n <ExpandableSection\n toggleContent={(isExpanded) =>\n isExpanded\n ? 'Show less uncontrolled dynamic toggle example content'\n : 'Show more uncontrolled dynamic toggle example content'\n }\n >\n This content is visible only when the component is expanded.\n </ExpandableSection>\n);\n","title":"Uncontrolled with dynamic toggle content (function)","lang":"ts","className":""}}>
|
|
255
|
+
|
|
256
|
+
<p {...{"className":"pf-v6-c-content--p pf-m-editorial ws-p "}}>
|
|
257
|
+
{`Use `}
|
|
258
|
+
|
|
259
|
+
<code {...{"className":"ws-code "}}>
|
|
260
|
+
{`toggleContent`}
|
|
261
|
+
</code>
|
|
262
|
+
{` as a function to dynamically render different content based on the expanded state without managing state yourself.`}
|
|
263
|
+
</p>
|
|
264
|
+
</Example>,
|
|
265
|
+
'Detached': props =>
|
|
266
|
+
<Example {...pageData} {...props} {...{"code":"import { useState } from 'react';\nimport { ExpandableSection, ExpandableSectionToggle, Stack, StackItem } from '@patternfly/react-core';\n\nexport const ExpandableSectionDetached: React.FunctionComponent = () => {\n const [isExpanded, setIsExpanded] = useState(false);\n\n const onToggle = (isExpanded: boolean) => {\n setIsExpanded(isExpanded);\n };\n\n const contentId = 'detached-expandable-section-content';\n const toggleId = 'detached-expandable-section-toggle';\n return (\n <Stack hasGutter>\n <StackItem>\n <ExpandableSection isExpanded={isExpanded} isDetached direction=\"up\" toggleId={toggleId} contentId={contentId}>\n This content is visible only when the component is expanded.\n </ExpandableSection>\n </StackItem>\n <StackItem>\n <ExpandableSectionToggle\n isExpanded={isExpanded}\n onToggle={onToggle}\n toggleId={toggleId}\n contentId={contentId}\n direction=\"up\"\n >\n {isExpanded ? 'Show less detached example content' : 'Show more detached example content'}\n </ExpandableSectionToggle>\n </StackItem>\n </Stack>\n );\n};\n","title":"Detached","lang":"ts","className":""}}>
|
|
267
|
+
|
|
268
|
+
<p {...{"className":"pf-v6-c-content--p pf-m-editorial ws-p "}}>
|
|
269
|
+
{`When passing the `}
|
|
270
|
+
|
|
271
|
+
<code {...{"className":"ws-code "}}>
|
|
272
|
+
{`isDetached`}
|
|
273
|
+
</code>
|
|
274
|
+
{` property into `}
|
|
275
|
+
|
|
276
|
+
<code {...{"className":"ws-code "}}>
|
|
277
|
+
{`<ExpandableSection>`}
|
|
278
|
+
</code>
|
|
279
|
+
{`, you must also manually pass in the same `}
|
|
280
|
+
|
|
281
|
+
<code {...{"className":"ws-code "}}>
|
|
282
|
+
{`toggleId`}
|
|
283
|
+
</code>
|
|
284
|
+
{` and `}
|
|
285
|
+
|
|
286
|
+
<code {...{"className":"ws-code "}}>
|
|
287
|
+
{`contentId`}
|
|
288
|
+
</code>
|
|
289
|
+
{` properties to both `}
|
|
290
|
+
|
|
291
|
+
<code {...{"className":"ws-code "}}>
|
|
292
|
+
{`<ExpandableSection>`}
|
|
293
|
+
</code>
|
|
294
|
+
{` and `}
|
|
295
|
+
|
|
296
|
+
<code {...{"className":"ws-code "}}>
|
|
297
|
+
{`<ExpandableSectionToggle>`}
|
|
298
|
+
</code>
|
|
299
|
+
{`. This will link the content to the toggle via ARIA attributes.`}
|
|
300
|
+
</p>
|
|
301
|
+
|
|
302
|
+
<p {...{"className":"pf-v6-c-content--p pf-m-editorial ws-p "}}>
|
|
303
|
+
{`By default animations will not be enabled for a detached `}
|
|
304
|
+
|
|
305
|
+
<code {...{"className":"ws-code "}}>
|
|
306
|
+
{`<ExpandableSection>`}
|
|
307
|
+
</code>
|
|
308
|
+
{`. You must manually pass the `}
|
|
309
|
+
|
|
310
|
+
<code {...{"className":"ws-code "}}>
|
|
311
|
+
{`direction`}
|
|
312
|
+
</code>
|
|
313
|
+
{` property with an appropriate value based on where the expandable content is rendered. If the expandable content is above the expandable toggle, `}
|
|
314
|
+
|
|
315
|
+
<code {...{"className":"ws-code "}}>
|
|
316
|
+
{`direction="up"`}
|
|
317
|
+
</code>
|
|
318
|
+
{` must be passed like in this example.`}
|
|
319
|
+
</p>
|
|
320
|
+
</Example>,
|
|
321
|
+
'Disclosure variation': props =>
|
|
322
|
+
<Example {...pageData} {...props} {...{"code":"import { useState } from 'react';\nimport { ExpandableSection } from '@patternfly/react-core';\n\nexport const ExpandableSectionDisclosure: React.FunctionComponent = () => {\n const [isExpanded, setIsExpanded] = useState(false);\n\n const onToggle = (_event: React.MouseEvent, isExpanded: boolean) => {\n setIsExpanded(isExpanded);\n };\n\n return (\n <ExpandableSection\n toggleText={\n isExpanded ? 'Show less disclosure variation example content' : 'Show more disclosure variation example content'\n }\n onToggle={onToggle}\n isExpanded={isExpanded}\n displaySize=\"lg\"\n isWidthLimited\n >\n This content is visible only when the component is expanded.\n </ExpandableSection>\n );\n};\n","title":"Disclosure variation","lang":"ts","className":""}}>
|
|
323
|
+
|
|
324
|
+
<p {...{"className":"pf-v6-c-content--p pf-m-editorial ws-p "}}>
|
|
325
|
+
{`You can pass in the `}
|
|
326
|
+
|
|
327
|
+
<code {...{"className":"ws-code "}}>
|
|
328
|
+
{`displaySize="lg"`}
|
|
329
|
+
</code>
|
|
330
|
+
{` property for a disclosure variation styling.`}
|
|
331
|
+
</p>
|
|
332
|
+
</Example>,
|
|
333
|
+
'Indented expandable content': props =>
|
|
334
|
+
<Example {...pageData} {...props} {...{"code":"import { FormEvent, useState } from 'react';\nimport { ExpandableSection, Checkbox } from '@patternfly/react-core';\n\nexport const ExpandableSectionIndented: React.FunctionComponent = () => {\n const [isExpanded, setIsExpanded] = useState(true);\n const [isDisplayLgChecked, setIsDisplayLgChecked] = useState(false);\n\n const onToggle = (_event: React.MouseEvent, isExpanded: boolean) => {\n setIsExpanded(isExpanded);\n };\n\n const onDisplaySizeCheck = (_event: FormEvent<HTMLInputElement>, checked: boolean) => setIsDisplayLgChecked(checked);\n\n return (\n <>\n <Checkbox\n id=\"displaySize-checkbox\"\n isChecked={isDisplayLgChecked}\n label='displaySize=\"lg\"'\n onChange={onDisplaySizeCheck}\n />\n <br />\n <ExpandableSection\n toggleText={isExpanded ? 'Show less indented example content' : 'Show more indented example content'}\n onToggle={onToggle}\n isExpanded={isExpanded}\n isIndented\n displaySize={isDisplayLgChecked ? 'lg' : 'default'}\n >\n This content is visible only when the component is expanded.\n </ExpandableSection>\n </>\n );\n};\n","title":"Indented expandable content","lang":"ts","className":""}}>
|
|
335
|
+
|
|
336
|
+
<p {...{"className":"pf-v6-c-content--p pf-m-editorial ws-p "}}>
|
|
337
|
+
{`You can indent the expandable content by passing in the `}
|
|
338
|
+
|
|
339
|
+
<code {...{"className":"ws-code "}}>
|
|
340
|
+
{`isIndented`}
|
|
341
|
+
</code>
|
|
342
|
+
{` property. This will not affect the expandable toggle.`}
|
|
343
|
+
</p>
|
|
344
|
+
</Example>,
|
|
345
|
+
'With custom toggle content': props =>
|
|
346
|
+
<Example {...pageData} {...props} {...{"code":"import { useState } from 'react';\nimport { ExpandableSection, Badge, Stack, StackItem } from '@patternfly/react-core';\nimport RhUiCheckCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-check-circle-fill-icon';\n\nexport const ExpandableSectionCustomToggle: React.FunctionComponent = () => {\n const [isExpanded, setIsExpanded] = useState(false);\n\n const onToggle = (_event: React.MouseEvent, isExpanded: boolean) => {\n setIsExpanded(isExpanded);\n };\n\n return (\n <Stack hasGutter>\n <StackItem>\n <h3>Custom Toggle Content</h3>\n <p>You can use custom content such as icons and badges in the toggle:</p>\n <ExpandableSection\n toggleContent={\n <div>\n <span>You can also use icons </span>\n <RhUiCheckCircleFillIcon />\n <span> or badges </span>\n <Badge isRead={true}>4</Badge>\n <span> !</span>\n </div>\n }\n onToggle={onToggle}\n isExpanded={isExpanded}\n >\n This content is visible only when the component is expanded.\n </ExpandableSection>\n </StackItem>\n\n <StackItem>\n <h3>Accessibility Note</h3>\n <p>\n <strong>Important:</strong> If you need the toggle text to function as a heading in the document structure, do\n NOT put heading elements (h1-h6) inside the <code>toggleContent</code> prop, as this creates invalid HTML\n structure. Instead, use the <code>toggleWrapper</code> prop.\n </p>\n </StackItem>\n </Stack>\n );\n};\n","title":"With custom toggle content","lang":"ts","className":""}}>
|
|
347
|
+
|
|
348
|
+
<p {...{"className":"pf-v6-c-content--p pf-m-editorial ws-p "}}>
|
|
349
|
+
{`By using the `}
|
|
350
|
+
|
|
351
|
+
<code {...{"className":"ws-code "}}>
|
|
352
|
+
{`toggleContent`}
|
|
353
|
+
</code>
|
|
354
|
+
{` prop, you can pass in content other than a simple string such as an icon or a badge. When passing in custom content in this way, you should not pass in any interactive element such as a button.`}
|
|
355
|
+
</p>
|
|
356
|
+
</Example>,
|
|
357
|
+
'With heading semantics': props =>
|
|
358
|
+
<Example {...pageData} {...props} {...{"code":"import { useState, MouseEvent } from 'react';\nimport { ExpandableSection, ExpandableSectionToggle, Stack, StackItem } from '@patternfly/react-core';\nimport RhUiCheckCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-check-circle-fill-icon';\n\nexport const ExpandableSectionWithHeading = () => {\n const [isExpanded1, setIsExpanded1] = useState(false);\n const [isExpanded2, setIsExpanded2] = useState(false);\n const [isExpandedDetached, setIsExpandedDetached] = useState(false);\n\n const onToggle1 = (_event: MouseEvent, isExpanded: boolean) => {\n setIsExpanded1(isExpanded);\n };\n\n const onToggle2 = (_event: MouseEvent, isExpanded: boolean) => {\n setIsExpanded2(isExpanded);\n };\n\n const onToggleDetached = (isExpanded: boolean) => {\n setIsExpandedDetached(isExpanded);\n };\n\n return (\n <Stack hasGutter>\n <StackItem>\n <h4>Document with Expandable Sections</h4>\n <p>This demonstrates how to use expandable sections with proper heading semantics.</p>\n\n {/* Using toggleWrapper prop for proper heading semantics */}\n <ExpandableSection\n toggleWrapper=\"h5\"\n toggleText=\"Toggle as a heading\"\n onToggle={onToggle1}\n isExpanded={isExpanded1}\n >\n <p>\n This content is visible only when the component is expanded. The toggle text above functions as a proper\n heading in the document structure, which is important for screen readers and other assistive technologies.\n </p>\n <p>\n When using the <code>toggleWrapper</code> prop with heading elements (h1-h6), the button is rendered inside\n the heading element, maintaining proper semantic structure.\n </p>\n </ExpandableSection>\n </StackItem>\n\n <StackItem>\n <h4>Detached Variant with Heading</h4>\n <p>You can also use the detached variant with heading semantics:</p>\n\n <ExpandableSectionToggle\n toggleWrapper=\"h5\"\n toggleId=\"detached-heading-toggle\"\n contentId=\"detached-heading-content\"\n isExpanded={isExpandedDetached}\n onToggle={onToggleDetached}\n >\n Detached Toggle with Heading\n </ExpandableSectionToggle>\n\n <ExpandableSection\n isDetached\n toggleId=\"detached-heading-toggle\"\n contentId=\"detached-heading-content\"\n isExpanded={isExpandedDetached}\n >\n <p>This is detached content that can be positioned anywhere in the DOM.</p>\n </ExpandableSection>\n </StackItem>\n\n <StackItem>\n <h4>Custom Content with Heading</h4>\n <p>You can also use custom content within heading wrappers:</p>\n\n <ExpandableSection\n toggleWrapper=\"h5\"\n toggleContent={\n <span>\n <RhUiCheckCircleFillIcon /> Custom Heading Content with Icon\n </span>\n }\n onToggle={onToggle2}\n isExpanded={isExpanded2}\n >\n <p>This expandable section uses custom content with an icon inside a heading wrapper.</p>\n </ExpandableSection>\n </StackItem>\n </Stack>\n );\n};\n","title":"With heading semantics","lang":"ts","className":""}}>
|
|
359
|
+
|
|
360
|
+
<p {...{"className":"pf-v6-c-content--p pf-m-editorial ws-p "}}>
|
|
361
|
+
{`When the toggle text should function as a heading in the document structure, use the `}
|
|
362
|
+
|
|
363
|
+
<code {...{"className":"ws-code "}}>
|
|
364
|
+
{`toggleWrapper`}
|
|
365
|
+
</code>
|
|
366
|
+
{` prop to specify a heading element (h1-h6). This ensures proper semantic structure for screen readers and other assistive technologies. The component automatically uses a native button element when heading wrappers are used, allowing the heading styles to display properly.`}
|
|
367
|
+
</p>
|
|
368
|
+
</Example>,
|
|
369
|
+
'Truncate expansion': props =>
|
|
370
|
+
<Example {...pageData} {...props} {...{"code":"import { useState } from 'react';\nimport { ExpandableSection, ExpandableSectionVariant } from '@patternfly/react-core';\n\nexport const ExpandableSectionTruncateExpansion: React.FunctionComponent = () => {\n const [isExpanded, setIsExpanded] = useState(false);\n\n const onToggle = (_event: React.MouseEvent, isExpanded: boolean) => {\n setIsExpanded(isExpanded);\n };\n\n return (\n <ExpandableSection\n variant={ExpandableSectionVariant.truncate}\n toggleText={isExpanded ? 'Show less truncated content' : 'Show more truncated content'}\n onToggle={onToggle}\n isExpanded={isExpanded}\n >\n Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque nec dignissim turpis, et tristique purus.\n Phasellus efficitur ante quis dolor viverra imperdiet. Orci varius natoque penatibus et magnis dis parturient\n montes, nascetur ridiculus mus. Pellentesque laoreet, sem ac elementum semper, lectus mauris vestibulum nulla,\n eget volutpat massa neque vel turpis. Donec finibus enim eu leo accumsan consectetur. Praesent massa diam,\n tincidunt eu dui ac, ullamcorper elementum est. Phasellus metus felis, venenatis vitae semper nec, porta a metus.\n Vestibulum justo nisi, imperdiet id eleifend at, varius nec lorem. Fusce porttitor mollis nibh, ut elementum ante\n commodo tincidunt. Integer tincidunt at ipsum non aliquet.\n </ExpandableSection>\n );\n};\n","title":"Truncate expansion","lang":"ts","className":""}}>
|
|
371
|
+
|
|
372
|
+
<p {...{"className":"pf-v6-c-content--p pf-m-editorial ws-p "}}>
|
|
373
|
+
{`By passing in `}
|
|
374
|
+
|
|
375
|
+
<code {...{"className":"ws-code "}}>
|
|
376
|
+
{`variant="truncate"`}
|
|
377
|
+
</code>
|
|
378
|
+
{`, the expandable content will be visible up to a maximum number of lines before being truncated, with the toggle revealing or hiding the truncated content. By default the expandable content will truncate after 3 lines, and this can be customized by also passing in the `}
|
|
379
|
+
|
|
380
|
+
<code {...{"className":"ws-code "}}>
|
|
381
|
+
{`truncateMaxLines`}
|
|
382
|
+
</code>
|
|
383
|
+
{` prop.`}
|
|
384
|
+
</p>
|
|
385
|
+
</Example>
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
const Component = () => (
|
|
389
|
+
<React.Fragment>
|
|
390
|
+
<AutoLinkHeader {...{"id":"examples","headingLevel":"h2","className":"ws-title ws-h2"}}>
|
|
391
|
+
{`Examples`}
|
|
392
|
+
</AutoLinkHeader>
|
|
393
|
+
{React.createElement(pageData.examples["Basic"])}
|
|
394
|
+
{React.createElement(pageData.examples["Uncontrolled"])}
|
|
395
|
+
{React.createElement(pageData.examples["Uncontrolled with dynamic toggle text"])}
|
|
396
|
+
{React.createElement(pageData.examples["Uncontrolled with dynamic toggle content (function)"])}
|
|
397
|
+
{React.createElement(pageData.examples["Detached"])}
|
|
398
|
+
{React.createElement(pageData.examples["Disclosure variation"])}
|
|
399
|
+
{React.createElement(pageData.examples["Indented expandable content"])}
|
|
400
|
+
{React.createElement(pageData.examples["With custom toggle content"])}
|
|
401
|
+
{React.createElement(pageData.examples["With heading semantics"])}
|
|
402
|
+
{React.createElement(pageData.examples["Truncate expansion"])}
|
|
403
|
+
</React.Fragment>
|
|
404
|
+
);
|
|
405
|
+
Component.displayName = 'ComponentsExpandableSectionReactDocs';
|
|
406
|
+
Component.pageData = pageData;
|
|
407
|
+
|
|
408
|
+
export default Component;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components';
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
import { Modal as ModalDeprecated, ModalVariant as ModalVariantDeprecated } from '@patternfly/react-core/deprecated';
|
|
5
|
+
import UploadIcon from '@patternfly/react-icons/dist/esm/icons/upload-icon';
|
|
6
|
+
const pageData = {
|
|
7
|
+
"id": "Multiple file upload",
|
|
8
|
+
"section": "components",
|
|
9
|
+
"subsection": "file-upload",
|
|
10
|
+
"deprecated": false,
|
|
11
|
+
"template": false,
|
|
12
|
+
"beta": false,
|
|
13
|
+
"demo": false,
|
|
14
|
+
"newImplementationLink": false,
|
|
15
|
+
"source": "react-demos",
|
|
16
|
+
"tabName": null,
|
|
17
|
+
"slug": "/components/file-upload/multiple-file-upload/react-demos",
|
|
18
|
+
"sourceLink": "https://github.com/patternfly/patternfly-react/blob/main/packages/react-core/src/demos/MultipleFileUploadDemos.md",
|
|
19
|
+
"relPath": "packages/react-core/src/demos/MultipleFileUploadDemos.md",
|
|
20
|
+
"examples": [
|
|
21
|
+
"Rejected file handling"
|
|
22
|
+
]
|
|
23
|
+
};
|
|
24
|
+
pageData.liveContext = {
|
|
25
|
+
useEffect,
|
|
26
|
+
useState,
|
|
27
|
+
ModalDeprecated,
|
|
28
|
+
ModalVariantDeprecated,
|
|
29
|
+
UploadIcon
|
|
30
|
+
};
|
|
31
|
+
pageData.examples = {
|
|
32
|
+
'Rejected file handling': props =>
|
|
33
|
+
<Example {...pageData} {...props} {...{"code":"import { useEffect, useState } from 'react';\nimport { FileRejection } from 'react-dropzone';\nimport {\n MultipleFileUpload,\n MultipleFileUploadMain,\n MultipleFileUploadStatus,\n MultipleFileUploadStatusItem,\n Checkbox,\n DropEvent,\n Modal,\n ModalHeader,\n ModalBody\n} from '@patternfly/react-core';\nimport UploadIcon from '@patternfly/react-icons/dist/esm/icons/upload-icon';\n\ninterface readFile {\n fileName: string;\n data?: string;\n loadResult?: 'danger' | 'success';\n loadError?: DOMException;\n}\n\nexport const MultipleFileUploadBasic: React.FunctionComponent = () => {\n const [isHorizontal, setIsHorizontal] = useState(false);\n const [currentFiles, setCurrentFiles] = useState<File[]>([]);\n const [readFileData, setReadFileData] = useState<readFile[]>([]);\n const [showStatus, setShowStatus] = useState(false);\n const [statusIcon, setStatusIcon] = useState('inProgress');\n const [modalText, setModalText] = useState('');\n\n // only show the status component once a file has been uploaded, but keep the status list component itself even if all files are removed\n if (!showStatus && currentFiles.length > 0) {\n setShowStatus(true);\n }\n\n // determine the icon that should be shown for the overall status list\n useEffect(() => {\n if (readFileData.length < currentFiles.length) {\n setStatusIcon('inProgress');\n } else if (readFileData.every((file) => file.loadResult === 'success')) {\n setStatusIcon('success');\n } else {\n setStatusIcon('danger');\n }\n }, [readFileData, currentFiles]);\n\n // remove files from both state arrays based on their name\n const removeFiles = (namesOfFilesToRemove: string[]) => {\n const newCurrentFiles = currentFiles.filter(\n (currentFile) => !namesOfFilesToRemove.some((fileName) => fileName === currentFile.name)\n );\n\n setCurrentFiles(newCurrentFiles);\n\n const newReadFiles = readFileData.filter(\n (readFile) => !namesOfFilesToRemove.some((fileName) => fileName === readFile.fileName)\n );\n\n setReadFileData(newReadFiles);\n };\n\n // callback that will be called by the react dropzone with the newly dropped file objects\n const handleFileDrop = (_event: DropEvent, droppedFiles: File[]) => {\n // identify what, if any, files are re-uploads of already uploaded files\n const currentFileNames = currentFiles.map((file) => file.name);\n const reUploads = droppedFiles.filter((droppedFile) => currentFileNames.includes(droppedFile.name));\n\n /** this promise chain is needed because if the file removal is done at the same time as the file adding react\n * won't realize that the status items for the re-uploaded files needs to be re-rendered */\n Promise.resolve()\n .then(() => removeFiles(reUploads.map((file) => file.name)))\n .then(() => setCurrentFiles((prevFiles) => [...prevFiles, ...droppedFiles]));\n };\n\n // callback called by the status item when a file is successfully read with the built-in file reader\n const handleReadSuccess = (data: string, file: File) => {\n setReadFileData((prevReadFiles) => [...prevReadFiles, { data, fileName: file.name, loadResult: 'success' }]);\n };\n\n // callback called by the status item when a file encounters an error while being read with the built-in file reader\n const handleReadFail = (error: DOMException, file: File) => {\n setReadFileData((prevReadFiles) => [\n ...prevReadFiles,\n { loadError: error, fileName: file.name, loadResult: 'danger' }\n ]);\n };\n\n // dropzone prop that communicates to the user that files they've attempted to upload are not an appropriate type\n const handleDropRejected = (fileRejections: FileRejection[]) => {\n if (fileRejections.length === 1) {\n setModalText(`${fileRejections[0].file.name} is not an accepted file type`);\n } else {\n const rejectedMessages = fileRejections.reduce(\n (acc, fileRejection) => (acc += `${fileRejection.file.name}, `),\n ''\n );\n setModalText(`${rejectedMessages}are not accepted file types`);\n }\n };\n\n const successfullyReadFileCount = readFileData.filter((fileData) => fileData.loadResult === 'success').length;\n\n return (\n <>\n <MultipleFileUpload\n onFileDrop={handleFileDrop}\n dropzoneProps={{\n accept: {\n 'image/jpeg': ['.jpg', '.jpeg'],\n 'application/msword': ['.doc'],\n 'application/pdf': ['.pdf'],\n 'image/png': ['.png']\n },\n onDropRejected: handleDropRejected\n }}\n isHorizontal={isHorizontal}\n >\n <MultipleFileUploadMain\n titleIcon={<UploadIcon />}\n titleText=\"Drag and drop files here\"\n titleTextSeparator=\"or\"\n infoText=\"Accepted file types: JPEG, Doc, PDF, PNG\"\n />\n {showStatus && (\n <MultipleFileUploadStatus\n statusToggleText={`${successfullyReadFileCount} of ${currentFiles.length} files uploaded`}\n statusToggleIcon={statusIcon}\n >\n {currentFiles.map((file) => (\n <MultipleFileUploadStatusItem\n file={file}\n key={file.name}\n onClearClick={() => removeFiles([file.name])}\n onReadSuccess={handleReadSuccess}\n onReadFail={handleReadFail}\n />\n ))}\n </MultipleFileUploadStatus>\n )}\n <Modal isOpen={!!modalText} aria-label=\"unsupported file upload attempted\" onClose={() => setModalText('')}>\n <ModalHeader title=\"Unsupported file\" titleIconVariant=\"warning\" />\n <ModalBody>{modalText}</ModalBody>\n </Modal>\n </MultipleFileUpload>\n <Checkbox\n id=\"horizontal-checkbox\"\n label=\"Show as horizontal\"\n isChecked={isHorizontal}\n onChange={() => setIsHorizontal(!isHorizontal)}\n />\n </>\n );\n};\n","title":"Rejected file handling","lang":"ts","className":""}}>
|
|
34
|
+
|
|
35
|
+
<p {...{"className":"pf-v6-c-content--p pf-m-editorial ws-p "}}>
|
|
36
|
+
{`This demo shows how to add a modal to alert users that the file(s) they attempted to drop was of a non-acceptable type.`}
|
|
37
|
+
</p>
|
|
38
|
+
</Example>
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const Component = () => (
|
|
42
|
+
<React.Fragment>
|
|
43
|
+
<AutoLinkHeader {...{"id":"demos","headingLevel":"h2","className":"ws-title ws-h2"}}>
|
|
44
|
+
{`Demos`}
|
|
45
|
+
</AutoLinkHeader>
|
|
46
|
+
{React.createElement(pageData.examples["Rejected file handling"])}
|
|
47
|
+
</React.Fragment>
|
|
48
|
+
);
|
|
49
|
+
Component.displayName = 'ComponentsFileUploadMultipleFileUploadReactDemosDocs';
|
|
50
|
+
Component.pageData = pageData;
|
|
51
|
+
|
|
52
|
+
export default Component;
|