From 632010b6a867ec1c255939003ee4b7ac2978cc21 Mon Sep 17 00:00:00 2001 From: melloware Date: Tue, 23 Aug 2022 08:12:58 -0400 Subject: [PATCH] Add prettier to standardize formatting --- .eslintrc.json | 11 +- .prettierignore | 7 + .prettierrc.json | 9 + components/doc/accordion/index.js | 540 +- components/doc/autocomplete/index.js | 429 +- components/doc/avatar/index.js | 111 +- components/doc/badge/index.js | 100 +- components/doc/blockui/index.js | 81 +- components/doc/breadcrumb/index.js | 83 +- components/doc/button/index.js | 178 +- components/doc/calendar/index.js | 571 +- components/doc/captcha/index.js | 80 +- components/doc/card/index.js | 99 +- components/doc/carousel/index.js | 206 +- components/doc/cascadeselect/index.js | 309 +- components/doc/chart/index.js | 91 +- components/doc/checkbox/index.js | 144 +- components/doc/chip/index.js | 131 +- components/doc/chips/index.js | 239 +- components/doc/colorpicker/index.js | 283 +- components/doc/common/developmentsection.js | 4 +- components/doc/common/docactions.js | 56 +- components/doc/common/liveeditor.js | 156 +- components/doc/common/liveeditordata.js | 32 +- components/doc/confirmdialog/index.js | 233 +- components/doc/confirmpopup/index.js | 232 +- components/doc/contextmenu/index.js | 236 +- components/doc/datascroller/index.js | 120 +- components/doc/datatable/index.js | 1062 +- components/doc/dataview/index.js | 253 +- components/doc/deferredcontent/index.js | 86 +- components/doc/dialog/index.js | 241 +- components/doc/divider/index.js | 310 +- components/doc/dock/index.js | 184 +- components/doc/dropdown/index.js | 472 +- components/doc/editor/index.js | 128 +- components/doc/fieldset/index.js | 188 +- components/doc/fileupload/index.js | 895 +- components/doc/floatlabel/index.js | 22 +- components/doc/galleria/index.js | 248 +- components/doc/gmap/index.js | 107 +- components/doc/image/index.js | 104 +- components/doc/inplace/index.js | 215 +- components/doc/inputgroup/index.js | 22 +- components/doc/inputmask/index.js | 133 +- components/doc/inputnumber/index.js | 289 +- components/doc/inputswitch/index.js | 418 +- components/doc/inputtext/index.js | 135 +- components/doc/inputtextarea/index.js | 99 +- components/doc/invalid/index.js | 21 +- components/doc/keyfilter/index.js | 61 +- components/doc/knob/index.js | 463 +- components/doc/listbox/index.js | 373 +- components/doc/megamenu/index.js | 228 +- components/doc/mention/index.js | 207 +- components/doc/menu/index.js | 235 +- components/doc/menubar/index.js | 231 +- components/doc/messages/index.js | 232 +- components/doc/multiselect/index.js | 646 +- components/doc/multistatecheckbox/index.js | 511 +- components/doc/orderlist/index.js | 367 +- components/doc/organizationchart/index.js | 165 +- components/doc/overlaypanel/index.js | 249 +- components/doc/paginator/index.js | 178 +- components/doc/panel/index.js | 206 +- components/doc/panelmenu/index.js | 154 +- components/doc/password/index.js | 149 +- components/doc/picklist/index.js | 376 +- components/doc/progressbar/index.js | 91 +- components/doc/progressspinner/index.js | 93 +- components/doc/radiobutton/index.js | 162 +- components/doc/rating/index.js | 177 +- components/doc/ripple/index.js | 90 +- components/doc/scrollpanel/index.js | 149 +- components/doc/scrolltop/index.js | 152 +- components/doc/selectbutton/index.js | 181 +- components/doc/sidebar/index.js | 236 +- components/doc/skeleton/index.js | 107 +- components/doc/slidemenu/index.js | 258 +- components/doc/slider/index.js | 218 +- components/doc/speeddial/index.js | 252 +- components/doc/splitbutton/index.js | 318 +- components/doc/splitter/index.js | 423 +- components/doc/steps/index.js | 207 +- components/doc/styleclass/index.js | 75 +- components/doc/tabmenu/index.js | 236 +- components/doc/tabview/index.js | 146 +- components/doc/tag/index.js | 77 +- components/doc/terminal/index.js | 122 +- components/doc/tieredmenu/index.js | 290 +- components/doc/timeline/index.js | 125 +- components/doc/toast/index.js | 207 +- components/doc/togglebutton/index.js | 146 +- components/doc/toolbar/index.js | 114 +- components/doc/tooltip/index.js | 214 +- components/doc/tree/index.js | 296 +- components/doc/treeselect/index.js | 527 +- components/doc/treetable/index.js | 621 +- components/doc/tristatecheckbox/index.js | 150 +- components/doc/virtualscroller/index.js | 160 +- components/layout/analytics.js | 6 +- components/layout/config.js | 476 +- components/layout/footer.js | 25 +- components/layout/layout.js | 67 +- components/layout/menu.js | 172 +- components/layout/topbar.js | 635 +- components/lib/accordion/Accordion.js | 61 +- components/lib/accordion/accordion.d.ts | 4 +- components/lib/api/Api.js | 2 +- components/lib/api/FilterService.js | 44 +- components/lib/api/Locale.js | 16 +- components/lib/api/PrimeIcons.js | 2 +- components/lib/api/PrimeReact.js | 30 +- components/lib/api/api.d.ts | 6 +- components/lib/autocomplete/AutoComplete.js | 1076 +- .../lib/autocomplete/AutoCompletePanel.js | 195 +- components/lib/autocomplete/autocomplete.d.ts | 4 +- components/lib/avatar/Avatar.js | 34 +- components/lib/avatar/avatar.d.ts | 2 +- components/lib/avatargroup/AvatarGroup.js | 4 +- components/lib/avatargroup/avatargroup.d.ts | 2 +- components/lib/badge/Badge.js | 48 +- components/lib/badge/badge.d.ts | 2 +- components/lib/blockui/BlockUI.js | 31 +- components/lib/breadcrumb/BreadCrumb.js | 226 +- components/lib/breadcrumb/breadcrumb.d.ts | 2 +- components/lib/button/Button.js | 112 +- components/lib/button/button.d.ts | 4 +- components/lib/calendar/Calendar.js | 5214 +- components/lib/calendar/CalendarPanel.js | 19 +- components/lib/calendar/calendar.d.ts | 7 +- components/lib/captcha/Captcha.js | 164 +- components/lib/card/Card.js | 23 +- components/lib/card/card.d.ts | 2 +- components/lib/carousel/Carousel.js | 894 +- components/lib/carousel/carousel.d.ts | 2 +- components/lib/cascadeselect/CascadeSelect.js | 559 +- .../lib/cascadeselect/CascadeSelectSub.js | 95 +- .../lib/cascadeselect/cascadeselect.d.ts | 4 +- components/lib/chart/Chart.js | 132 +- components/lib/checkbox/Checkbox.js | 169 +- components/lib/checkbox/checkbox.d.ts | 2 +- components/lib/chip/Chip.js | 108 +- components/lib/chip/chip.d.ts | 2 +- components/lib/chips/Chips.js | 476 +- components/lib/chips/chips.d.ts | 6 +- components/lib/colorpicker/ColorPicker.js | 1018 +- .../lib/colorpicker/ColorPickerPanel.js | 19 +- components/lib/colorpicker/colorpicker.d.ts | 2 +- components/lib/column/Column.js | 4 +- components/lib/column/column.d.ts | 6 +- components/lib/columngroup/ColumnGroup.js | 4 +- components/lib/columngroup/columngroup.d.ts | 2 +- components/lib/confirmdialog/ConfirmDialog.js | 245 +- components/lib/confirmpopup/ConfirmPopup.js | 444 +- components/lib/contextmenu/ContextMenu.js | 346 +- components/lib/contextmenu/ContextMenuSub.js | 42 +- components/lib/csstransition/CSSTransition.js | 29 +- .../lib/csstransition/csstransition.d.ts | 4 +- components/lib/datascroller/DataScroller.js | 346 +- components/lib/datatable/BodyCell.js | 171 +- components/lib/datatable/BodyRow.js | 164 +- components/lib/datatable/ColumnFilter.js | 310 +- components/lib/datatable/DataTable.js | 743 +- components/lib/datatable/FooterCell.js | 13 +- components/lib/datatable/HeaderCell.js | 135 +- components/lib/datatable/HeaderCheckbox.js | 14 +- components/lib/datatable/RowCheckbox.js | 15 +- components/lib/datatable/RowRadioButton.js | 21 +- components/lib/datatable/RowTogglerButton.js | 9 +- components/lib/datatable/TableBody.js | 1676 +- components/lib/datatable/TableFooter.js | 27 +- components/lib/datatable/TableHeader.js | 101 +- components/lib/datatable/datatable.d.ts | 4 +- components/lib/dataview/DataView.js | 349 +- components/lib/dataview/dataview.d.ts | 4 +- .../lib/deferredcontent/DeferredContent.js | 17 +- .../lib/deferredcontent/deferredcontent.d.ts | 2 +- components/lib/dialog/Dialog.js | 169 +- components/lib/divider/Divider.js | 28 +- components/lib/divider/divider.d.ts | 2 +- components/lib/dock/Dock.js | 226 +- components/lib/dock/dock.d.ts | 2 +- components/lib/dropdown/Dropdown.js | 1309 +- components/lib/dropdown/DropdownItem.js | 23 +- components/lib/dropdown/DropdownPanel.js | 374 +- components/lib/dropdown/dropdown.d.ts | 2 +- components/lib/editor/Editor.js | 355 +- components/lib/fieldset/Fieldset.js | 56 +- components/lib/fieldset/fieldset.d.ts | 2 +- components/lib/fileupload/FileUpload.js | 905 +- components/lib/fileupload/fileupload.d.ts | 10 +- components/lib/fullcalendar/FullCalendar.js | 117 +- components/lib/fullcalendar/fullcalendar.d.ts | 2 +- components/lib/galleria/Galleria.js | 427 +- components/lib/galleria/GalleriaItem.js | 314 +- components/lib/galleria/GalleriaThumbnails.js | 569 +- components/lib/gmap/GMap.js | 198 +- components/lib/gmap/gmap.d.ts | 4 +- components/lib/hooks/useEventListener.js | 11 +- components/lib/hooks/useInterval.js | 5 +- components/lib/hooks/useOverlayListener.js | 24 +- .../lib/hooks/useOverlayScrollListener.js | 13 +- components/lib/hooks/usePrevious.js | 2 +- components/lib/hooks/useStorage.js | 19 +- components/lib/hooks/useTimeout.js | 5 +- components/lib/hooks/useUpdateEffect.js | 2 +- components/lib/image/Image.js | 330 +- components/lib/image/image.d.ts | 2 +- components/lib/inplace/Inplace.js | 63 +- components/lib/inplace/inplace.d.ts | 2 +- components/lib/inputmask/InputMask.js | 982 +- components/lib/inputmask/inputmask.d.ts | 2 +- components/lib/inputnumber/InputNumber.js | 1882 +- components/lib/inputswitch/InputSwitch.js | 151 +- components/lib/inputswitch/inputswitch.d.ts | 2 +- components/lib/inputtext/InputText.js | 96 +- components/lib/inputtext/inputtext.d.ts | 4 +- components/lib/inputtextarea/InputTextarea.js | 163 +- .../lib/inputtextarea/inputtextarea.d.ts | 2 +- components/lib/keyfilter/KeyFilter.js | 22 +- components/lib/knob/Knob.js | 254 +- components/lib/knob/knob.d.ts | 2 +- components/lib/listbox/ListBox.js | 679 +- components/lib/listbox/ListBoxHeader.js | 27 +- components/lib/listbox/ListBoxItem.js | 42 +- components/lib/listbox/listbox.d.ts | 1 - components/lib/megamenu/MegaMenu.js | 699 +- components/lib/megamenu/megamenu.d.ts | 3 +- components/lib/mention/Mention.js | 732 +- components/lib/menu/Menu.js | 458 +- components/lib/menubar/Menubar.js | 217 +- components/lib/menubar/MenubarSub.js | 423 +- components/lib/menubar/menubar.d.ts | 2 +- components/lib/message/Message.js | 94 +- components/lib/message/message.d.ts | 2 +- components/lib/messages/Messages.js | 101 +- components/lib/messages/UIMessage.js | 120 +- components/lib/multiselect/MultiSelect.js | 1049 +- .../lib/multiselect/MultiSelectHeader.js | 32 +- components/lib/multiselect/MultiSelectItem.js | 23 +- .../lib/multiselect/MultiSelectPanel.js | 350 +- components/lib/multiselect/multiselect.d.ts | 2 +- .../multistatecheckbox/MultiStateCheckbox.js | 278 +- .../multistatecheckbox.d.ts | 2 +- components/lib/orderlist/OrderList.js | 331 +- components/lib/orderlist/OrderListControls.js | 37 +- components/lib/orderlist/OrderListSubList.js | 96 +- components/lib/orderlist/orderlist.d.ts | 2 +- .../organizationchart/OrganizationChart.js | 121 +- .../OrganizationChartNode.js | 111 +- .../organizationchart/organizationchart.d.ts | 4 +- components/lib/overlaypanel/OverlayPanel.js | 79 +- components/lib/paginator/CurrentPageReport.js | 17 +- components/lib/paginator/FirstPageLink.js | 6 +- components/lib/paginator/JumpToPageInput.js | 7 +- components/lib/paginator/LastPageLink.js | 6 +- components/lib/paginator/NextPageLink.js | 6 +- components/lib/paginator/PageLinks.js | 17 +- components/lib/paginator/Paginator.js | 379 +- components/lib/paginator/PrevPageLink.js | 6 +- .../lib/paginator/RowsPerPageDropdown.js | 6 +- components/lib/paginator/paginator.d.ts | 4 +- components/lib/panel/Panel.js | 53 +- components/lib/panel/panel.d.ts | 2 +- components/lib/panelmenu/PanelMenu.js | 293 +- components/lib/panelmenu/PanelMenuSub.js | 52 +- components/lib/panelmenu/panelmenu.d.ts | 2 +- components/lib/password/Password.js | 591 +- components/lib/password/password.d.ts | 4 +- components/lib/picklist/PickList.js | 453 +- components/lib/picklist/PickListControls.js | 34 +- components/lib/picklist/PickListItem.js | 19 +- components/lib/picklist/PickListSubList.js | 342 +- .../lib/picklist/PickListTransferControls.js | 24 +- components/lib/picklist/picklist.d.ts | 2 +- components/lib/portal/Portal.js | 2 +- components/lib/progressbar/ProgressBar.js | 83 +- components/lib/progressbar/progressbar.d.ts | 2 +- .../lib/progressspinner/ProgressSpinner.js | 36 +- .../lib/progressspinner/progressspinner.d.ts | 2 +- components/lib/radiobutton/RadioButton.js | 174 +- components/lib/rating/Rating.js | 176 +- components/lib/rating/rating.d.ts | 2 +- components/lib/ripple/Ripple.js | 116 +- components/lib/ripple/ripple.d.ts | 2 +- components/lib/row/Row.js | 10 +- components/lib/row/row.d.ts | 2 +- components/lib/scrollpanel/ScrollPanel.js | 48 +- components/lib/scrollpanel/scrollpanel.d.ts | 2 +- components/lib/scrolltop/ScrollTop.js | 139 +- components/lib/scrolltop/scrolltop.d.ts | 2 +- components/lib/selectbutton/SelectButton.js | 197 +- .../lib/selectbutton/SelectButtonItem.js | 33 +- components/lib/selectbutton/selectbutton.d.ts | 2 +- components/lib/selectitem/selectitem.d.ts | 2 +- components/lib/sidebar/Sidebar.js | 95 +- components/lib/sidebar/sidebar.d.ts | 2 +- components/lib/skeleton/Skeleton.js | 38 +- components/lib/skeleton/skeleton.d.ts | 2 +- components/lib/slidemenu/SlideMenu.js | 262 +- components/lib/slidemenu/SlideMenuSub.js | 32 +- components/lib/slider/Slider.js | 488 +- components/lib/slider/slider.d.ts | 4 +- components/lib/speeddial/SpeedDial.js | 466 +- components/lib/splitbutton/SplitButton.js | 264 +- components/lib/splitbutton/SplitButtonItem.js | 21 +- .../lib/splitbutton/SplitButtonPanel.js | 23 +- components/lib/splitter/Splitter.js | 467 +- components/lib/splitter/splitter.d.ts | 4 +- components/lib/steps/Steps.js | 204 +- components/lib/styleclass/StyleClass.js | 53 +- components/lib/styleclass/styleclass.d.ts | 2 +- components/lib/tabmenu/TabMenu.js | 241 +- components/lib/tabmenu/tabmenu.d.ts | 2 +- components/lib/tabview/TabView.js | 123 +- components/lib/tabview/tabview.d.ts | 2 +- components/lib/tag/Tag.js | 18 +- components/lib/tag/tag.d.ts | 2 +- components/lib/terminal/Terminal.js | 265 +- components/lib/tieredmenu/TieredMenu.js | 203 +- components/lib/tieredmenu/TieredMenuSub.js | 63 +- components/lib/timeline/Timeline.js | 93 +- components/lib/timeline/timeline.d.ts | 2 +- components/lib/toast/Toast.js | 159 +- components/lib/toast/ToastMessage.js | 133 +- components/lib/togglebutton/ToggleButton.js | 143 +- components/lib/togglebutton/togglebutton.d.ts | 2 +- components/lib/toolbar/Toolbar.js | 40 +- components/lib/toolbar/toolbar.d.ts | 2 +- components/lib/tooltip/Tooltip.js | 802 +- components/lib/tree/Tree.js | 790 +- components/lib/tree/UITreeNode.js | 297 +- components/lib/tree/tree.d.ts | 2 +- components/lib/treeselect/TreeSelect.js | 935 +- components/lib/treeselect/TreeSelectPanel.js | 24 +- components/lib/treeselect/treeselect.d.ts | 2 +- components/lib/treetable/TreeTable.js | 405 +- components/lib/treetable/TreeTableBody.js | 115 +- components/lib/treetable/TreeTableBodyCell.js | 48 +- components/lib/treetable/TreeTableFooter.js | 37 +- components/lib/treetable/TreeTableHeader.js | 169 +- components/lib/treetable/TreeTableRow.js | 151 +- .../lib/treetable/TreeTableScrollableView.js | 54 +- components/lib/treetable/treetable.d.ts | 2 +- .../lib/tristatecheckbox/TriStateCheckbox.js | 160 +- .../tristatecheckbox/tristatecheckbox.d.ts | 2 +- components/lib/utils/ClassNames.js | 7 +- .../utils/ConnectedOverlayScrollHandler.js | 3 +- components/lib/utils/DomHandler.js | 235 +- components/lib/utils/EventBus.js | 10 +- components/lib/utils/IconUtils.js | 1 - components/lib/utils/Mask.js | 105 +- components/lib/utils/ObjectUtils.js | 129 +- components/lib/utils/ZIndexUtils.js | 16 +- components/lib/utils/utils.d.ts | 23 +- .../lib/virtualscroller/VirtualScroller.js | 1100 +- components/news/newssection.js | 17 +- package-lock.json | 39933 ++++++++-------- package.json | 128 +- 360 files changed, 55973 insertions(+), 51763 deletions(-) create mode 100644 .prettierignore create mode 100644 .prettierrc.json diff --git a/.eslintrc.json b/.eslintrc.json index 9094de5300..bb477ec668 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,9 +1,18 @@ { - "extends": "next/core-web-vitals", + "plugins": ["@typescript-eslint"], + "extends": [ + "next/core-web-vitals", + "plugin:@typescript-eslint/recommended", + "prettier" + ], "rules": { "@next/next/no-img-element": "off", "react/display-name": "off", "react/no-unescaped-entities": "off", + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/no-empty-interface": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", "no-console": 2 } } diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000000..8f2f3cdf94 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,7 @@ +# Ignore artifacts: +build +coverage +api-generator +out +public +styles \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000000..1537fa07af --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,9 @@ +{ + "useTabs": false, + "tabWidth": 4, + "trailingComma": "none", + "semi": true, + "singleQuote": true, + "jsxSingleQuote": true, + "printWidth": 250 +} diff --git a/components/doc/accordion/index.js b/components/doc/accordion/index.js index c7d9569e91..4470b4f532 100644 --- a/components/doc/accordion/index.js +++ b/components/doc/accordion/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const AccordionDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -139,7 +138,7 @@ export class AccordionDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -261,7 +260,7 @@ export const AccordionDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -382,8 +381,8 @@ export const AccordionDemo = () => { ) } ` - }, - 'browser': { + }, + browser: { tabName: 'Browser Source', imports: ` @@ -508,8 +507,8 @@ const AccordionDemo = () => { ) } ` - } - }; + } + }; const extFiles = { 'demo/AccordionDemo.css': { @@ -528,35 +527,37 @@ const AccordionDemo = () => { } ` } - } + }; return ( -
+
- -
Import via Module
- -{` + +
Import via Module
+ + {` import { Accordion, AccordionTab } from 'primereact/accordion'; `} - +
-
Import via CDN
- -{` +
Import via CDN
+ + {` `} - +
-
Getting Started
-

Accordion element consists of one or more AccordionTab elements and can either be used as a Controlled or Uncontrolled component.

+
Getting Started
+

Accordion element consists of one or more AccordionTab elements and can either be used as a Controlled or Uncontrolled component.

-
Controlled Component
-

In controlled mode, activeIndex and onTabChange properties need to be defined to control the state.

+
Controlled Component
+

+ In controlled mode, activeIndex and onTabChange properties need to be defined to control the state. +

- -{` + + {` setActiveIndex(e.index)}> Content I @@ -569,14 +570,16 @@ import { Accordion, AccordionTab } from 'primereact/accordion'; `} - + -
Uncontrolled
-

In uncontrolled mode, no additional properties are required. Initial active tab can be provided using the activeIndex property in uncontrolled mode however it is evaluated at initial rendering and ignored in further updates. If you programmatically - need to update the active tab, prefer to use the component as controlled.

+
Uncontrolled
+

+ In uncontrolled mode, no additional properties are required. Initial active tab can be provided using the activeIndex property in uncontrolled mode however it is evaluated at initial rendering and ignored in further + updates. If you programmatically need to update the active tab, prefer to use the component as controlled. +

- -{` + + {` Content I @@ -589,12 +592,14 @@ import { Accordion, AccordionTab } from 'primereact/accordion'; `} - + -
Multiple
-

By default only one tab at a time can be active, enabling multiple property changes this behavior to allow multiple tabs be active at the same time.

- -{` +
Multiple
+

+ By default only one tab at a time can be active, enabling multiple property changes this behavior to allow multiple tabs be active at the same time. +

+ + {` Content I @@ -607,215 +612,230 @@ import { Accordion, AccordionTab } from 'primereact/accordion'; `} - - -
Properties For AccordionTab
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDefaultDescription
headerstringnullOrientation of tab headers.
disabledbooleanfalseWhether the tab is disabled.
styleobjectnullInline style of the tab header and content.
classNamestringnullStyle class of the tab header and content.
headerStyleobjectnullInline style of the tab header.
headerClassNamestringnullStyle class of the tab header.
headerTemplateanynullTemplate of the tab header.
contentStyleobjectnullInline style of the tab content.
contentClassNamestringnullStyle class of the tab content.
-
+
+ +
Properties For AccordionTab
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
headerstringnullOrientation of tab headers.
disabledbooleanfalseWhether the tab is disabled.
styleobjectnullInline style of the tab header and content.
classNamestringnullStyle class of the tab header and content.
headerStyleobjectnullInline style of the tab header.
headerClassNamestringnullStyle class of the tab header.
headerTemplateanynullTemplate of the tab header.
contentStyleobjectnullInline style of the tab content.
contentClassNamestringnullStyle class of the tab content.
+
-
Properties
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDefaultDescription
idstringnullUnique identifier of the element.
activeIndexanynullActive index or indexes of the element. Use an array of numbers for multiple indexes. the "multiple" prop must be set to true in order to specify multiple indexes.
classNamestringnullStyle class of the element.
styleobjectnullInline style of the element.
multiplebooleanfalseWhen enabled, multiple tabs can be activated at the same time.
expandIconstringpi pi-chevron-rightIcon of a collapsed tab.
collapseIconstringpi pi-chevron-downIcon of an expanded tab.
transitionOptionsobjectnullThe properties of CSSTransition can be customized, except for "nodeRef" and "in" properties.
-
+
Properties
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
idstringnullUnique identifier of the element.
activeIndexanynullActive index or indexes of the element. Use an array of numbers for multiple indexes. the "multiple" prop must be set to true in order to specify multiple indexes.
classNamestringnullStyle class of the element.
styleobjectnullInline style of the element.
multiplebooleanfalseWhen enabled, multiple tabs can be activated at the same time.
expandIconstringpi pi-chevron-rightIcon of a collapsed tab.
collapseIconstringpi pi-chevron-downIcon of an expanded tab.
transitionOptionsobjectnull + The properties of{' '} + + CSSTransition + {' '} + can be customized, except for "nodeRef" and "in" properties. +
+
-
Events
-
- - - - - - - - - - - - - - - - - - - - - - - - - -
NameParametersDescription
onTabOpenevent.originalEvent: browser event
- event.index: Index or indexes of the tab (number or array of numbers). -
Callback to invoke when a tab gets expanded.
onTabCloseevent.originalEvent: browser event
- event.index: Index of the tab -
Callback to invoke when an active tab is collapsed by clicking on the header.
onTabChangeevent.originalEvent: browser event
- event.index: Index of the tab -
Callback to invoke when state of the accordion changes.
-
+
Events
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
NameParametersDescription
onTabOpen + event.originalEvent: browser event
+ event.index: Index or indexes of the tab (number or array of numbers). +
Callback to invoke when a tab gets expanded.
onTabClose + event.originalEvent: browser event
+ event.index: Index of the tab +
Callback to invoke when an active tab is collapsed by clicking on the header.
onTabChange + event.originalEvent: browser event
+ event.index: Index of the tab +
Callback to invoke when state of the accordion changes.
+
-
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
- - - - - - - - - - - - - - - - - - - - - -
NameElement
p-accordionContainer element.
p-accordion-headerHeader of a tab.
p-accordion-contentContainer of a tab.
-
+
Styling
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+ + + + + + + + + + + + + + + + + + + + + +
NameElement
p-accordionContainer element.
p-accordion-headerHeader of a tab.
p-accordion-contentContainer of a tab.
+
-
Accessibility
+
Accessibility
Screen Reader
-

Accordion header elements have a button role and use aria-controls to define the id of the content section along with aria-expanded for the visibility state. The value to read a header element - defaults to the value of the header property and can be customized by defining an aria-label or aria-labelledby via the headerProps property.

-

The content uses region role, defines an id that matches the aria-controls of the header and aria-labelledby referring to the id of the header.

+

+ Accordion header elements have a button role and use aria-controls to define the id of the content section along with aria-expanded for the visibility state. The value to read a header element defaults + to the value of the header property and can be customized by defining an aria-label or aria-labelledby via the headerProps property. +

+

+ The content uses region role, defines an id that matches the aria-controls of the header and aria-labelledby referring to the id of the header. +

Header Keyboard Support
-
- +
+
@@ -824,53 +844,67 @@ import { Accordion, AccordionTab } from 'primereact/accordion'; - + - + - + - + - + - + - + - +
Key
tab + tab + Moves focus to the next the focusable element in the page tab sequence.
shift + tab + shift + tab + Moves focus to the previous the focusable element in the page tab sequence.
enter + enter + Toggles the visibility of the content.
space + space + Toggles the visibility of the content.
down arrow + down arrow + Moves focus to the next header.
up arrow + up arrow + Moves focus to the previous header.
home + home + Moves focus to the first header.
end + end + Moves focus to the last header.
-
Dependencies
-
    -
  • react-transition-group
  • -
+
Dependencies
+
    +
  • react-transition-group
  • +
- { - useLiveEditorTabs({ name: 'AccordionDemo', sources: sources, extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'AccordionDemo', sources: sources, extFiles: extFiles })}
); -}) +}); export default AccordionDoc; diff --git a/components/doc/autocomplete/index.js b/components/doc/autocomplete/index.js index a84f9e729d..bde5bc46cb 100644 --- a/components/doc/autocomplete/index.js +++ b/components/doc/autocomplete/index.js @@ -1,14 +1,13 @@ import React, { memo } from 'react'; -import Link from 'next/link'; +import Link from 'next/link'; import { TabView, TabPanel } from '../../lib/tabview/TabView'; import { useLiveEditorTabs } from '../common/liveeditor'; import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const AutoCompleteDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -163,7 +162,7 @@ export class AutoCompleteDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState, useEffect } from 'react'; @@ -305,7 +304,7 @@ export const AutoCompleteDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState, useEffect } from 'react'; @@ -446,8 +445,8 @@ export const AutoCompleteDemo = () => { ) } ` - }, - 'browser': { + }, + browser: { tabName: 'Browser Source', imports: ` @@ -591,41 +590,41 @@ const AutoCompleteDemo = () => { ) } ` - } } - + }; return ( -
+
- +
Import via Module
- -{` + + {` import { AutoComplete } from 'primereact/autocomplete'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

AutoComplete is used as a controlled component with value and onChange properties. In addition, the component - requires a list of suggestions and a completeMethod to query the results.

+

+ AutoComplete is used as a controlled component with value and onChange properties. In addition, the component requires a list of suggestions and a completeMethod to query the results. +

- -{` + + {` setSelectedCountry(e.value)} /> `} - + - -{` + + {` const countries = // datasource const searchCountry = (event) => { @@ -639,43 +638,48 @@ render() { ); } `} - +
Dropdown
-

Enabling dropdown property displays a button next to the input field where click behavior of the button is defined using - dropdownMode property that takes "blank" or "current" as possible values. - "blank" is the default mode to send a query with an empty string whereas - "current" setting sends a query with the current value of the input.

+

+ Enabling dropdown property displays a button next to the input field where click behavior of the button is defined using dropdownMode property that takes "blank" or "current" as possible values. "blank" is the default + mode to send a query with an empty string whereas "current" setting sends a query with the current value of the input. +

- -{` + + {` setSelectedCountry(e.value)} /> `} - +
Multiple Mode
-

Multiple mode is enabled using multiple property used to select more than one value from the autocomplete. In this case, value reference should be an array.

- -{` +

+ Multiple mode is enabled using multiple property used to select more than one value from the autocomplete. In this case, value reference should be an array. +

+ + {` setSelectedCountry(e.value)} /> `} - +
Objects
-

AutoComplete can also work with objects using the field property that defines the label to display - as a suggestion. The value passed to the model would still be the object instance of a suggestion. - Here is an example with a Country object that has name and code fields such as {name:"United States",code:"USA"}.

+

+ AutoComplete can also work with objects using the field property that defines the label to display as a suggestion. The value passed to the model would still be the object instance of a suggestion. Here is an example + with a Country object that has name and code fields such as {name:"United States",code:"USA"}. +

- -{` + + {` setSelectedCountry(e.value)} /> `} - +
Grouping
-

Options groups are specified with the optionGroupLabel and optionGroupChildren properties.

- -{` +

+ Options groups are specified with the optionGroupLabel and optionGroupChildren properties. +

+ + {` const groupedCities = [ { label: 'Germany', code: 'DE', @@ -706,46 +710,53 @@ const groupedCities = [ } ]; `} - +
- -{` + + {` setSelectedCity(e.value)}/> `} - +
Force Selection
-

ForceSelection mode validates the manual input to check whether it also exists in the suggestions list, if not the input value is cleared - to make sure the value passed to the model is always one of the suggestions. Simply enable forceSelection to enforce that input is always from the suggestion list.

- -{` +

+ ForceSelection mode validates the manual input to check whether it also exists in the suggestions list, if not the input value is cleared to make sure the value passed to the model is always one of the suggestions. Simply + enable forceSelection to enforce that input is always from the suggestion list. +

+ + {` setSelectedCountry(e.value)} /> `} - +
Templating
-

Custom content can be displayed using itemTemplate property that references a function or JSXElement or string which gets - the suggestion option and returns an element. Similarly selectedItemTemplate property is available - to customize the chips in multiple mode using the same approach.

+

+ Custom content can be displayed using itemTemplate property that references a function or JSXElement or string which gets the suggestion option and returns an element. Similarly selectedItemTemplate property is + available to customize the chips in multiple mode using the same approach. +

- -{` + + {` setSelectedCountry(e.value)} itemTemplate={itemTemplate} /> `} - + - -{` + + {` itemTemplate(item) { //return custom element } `} - +
Properties
-

Standard HTMLSpanElement properties are passed to the wrapping div element.
In addition the component uses these properties:

-
- +

+ Standard HTMLSpanElement properties are passed to the wrapping div element. +
+ In addition the component uses these properties: +

+
+
@@ -807,8 +818,7 @@ itemTemplate(item) { - + @@ -934,7 +944,9 @@ itemTemplate(item) { - + @@ -982,7 +994,13 @@ itemTemplate(item) { - + @@ -1000,15 +1018,17 @@ itemTemplate(item) { - +
NameforceSelection boolean falseWhen present, autocomplete clears the manual input if it does not match of the suggestions to force only - accepting values from the suggestions.When present, autocomplete clears the manual input if it does not match of the suggestions to force only accepting values from the suggestions.
autoHighlightappendTo DOM element | string document.bodyDOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. + DOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. +
tabIndextransitionOptions object nullThe properties of CSSTransition can be customized, except for "nodeRef" and "in" properties. + The properties of{' '} + + CSSTransition + {' '} + can be customized, except for "nodeRef" and "in" properties. +
dropdownIconvirtualScrollerOptions object nullWhether to use the virtualScroller feature. The properties of VirtualScroller component can be used like an object in it. + Whether to use the virtualScroller feature. The properties of VirtualScroller component can be used like an object in it. +
Events
-
- +
+
@@ -1027,8 +1047,10 @@ itemTemplate(item) { - + @@ -1043,14 +1065,18 @@ itemTemplate(item) { - + - + @@ -1112,8 +1138,8 @@ itemTemplate(item) {
Styling

Following is the list of structural style classes

-
-
Name
onChangeevent.originalEvent: Browser event
- event.value: Value of the component
+ event.originalEvent: Browser event
+ event.value: Value of the component +
Callback to invoke when autocomplete value changes.
onSelectevent.originalEvent: Browser event
- event.value: Value of the component
+ event.originalEvent: Browser event
+ event.value: Value of the component +
Callback to invoke when a suggestion is selected.
onUnselectevent.originalEvent: Browser event
- event.value: Value of the component
+ event.originalEvent: Browser event
+ event.value: Value of the component +
Callback to invoke when a selected value is removed.
+
+
@@ -1154,15 +1180,22 @@ itemTemplate(item) {
Accessibility
- -
Screen Reader
-

Value to describe the component can either be provided via label tag combined with inputId prop or using aria-labelledby, aria-label props. The input element has combobox role - in addition to aria-autocomplete, aria-haspopup and aria-expanded attributes. The relation between the input and the popup is created with aria-controls and aria-activedescendant attribute is used - to instruct screen reader which option to read during keyboard navigation within the popup list.

-

In multiple mode, chip list uses listbox role with aria-orientation set to horizontal whereas each chip has the option role with aria-label set to the label of the chip.

-

The popup list has an id that refers to the aria-controls attribute of the input element and uses listbox as the role. Each list item has option role and an id to match the aria-activedescendant of the input element.

- -{` + +
Screen Reader
+

+ Value to describe the component can either be provided via label tag combined with inputId prop or using aria-labelledby, aria-label props. The input element has combobox role in addition + to aria-autocomplete, aria-haspopup and aria-expanded attributes. The relation between the input and the popup is created with aria-controls and aria-activedescendant attribute is used to + instruct screen reader which option to read during keyboard navigation within the popup list. +

+

+ In multiple mode, chip list uses listbox role with aria-orientation set to horizontal whereas each chip has the option role with aria-label set to the label of the chip. +

+

+ The popup list has an id that refers to the aria-controls attribute of the input element and uses listbox as the role. Each list item has option role and an id to match the aria-activedescendant{' '} + of the input element. +

+ + {` @@ -1171,110 +1204,130 @@ itemTemplate(item) { `} - -
Keyboard Support
-
-
Name
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus to the input element when popup is not visible. - If the popup is open and an item is highlighted then popup gets closed, item gets selected and focus moves to the next focusable element.
up arrowHighlights the previous item if popup is visible.
down arrowHighlights the next item if popup is visible.
enterSelects the highlighted item and closes the popup if popup is visible.
homeHighlights the first item if popup is visible.
endHighlights the last item if popup is visible.
escapeHides the popup.
-
- -
Chips Input Keyboard Support
-
- - - - - - - - - - - - - - - - - -
KeyFunction
backspaceDeletes the previous chip if the input field is empty.
left arrowMoves focus to the previous chip if available and input field is empty.
-
- -
Chip Keyboard Support
-
- - - - - - - - - - - - - - - - - - - - - -
KeyFunction
left arrowMoves focus to the previous chip if available.
right arrowMoves focus to the next chip, if there is none then input field receives the focus.
backspaceDeletes the chips and adds focus to the input field.
-
- - + +
Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the input element when popup is not visible. If the popup is open and an item is highlighted then popup gets closed, item gets selected and focus moves to the next focusable element.
+ up arrow + Highlights the previous item if popup is visible.
+ down arrow + Highlights the next item if popup is visible.
+ enter + Selects the highlighted item and closes the popup if popup is visible.
+ home + Highlights the first item if popup is visible.
+ end + Highlights the last item if popup is visible.
+ escape + Hides the popup.
+
+ +
Chips Input Keyboard Support
+
+ + + + + + + + + + + + + + + + + +
KeyFunction
+ backspace + Deletes the previous chip if the input field is empty.
+ left arrow + Moves focus to the previous chip if available and input field is empty.
+
+ +
Chip Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ left arrow + Moves focus to the previous chip if available.
+ right arrow + Moves focus to the next chip, if there is none then input field receives the focus.
+ backspace + Deletes the chips and adds focus to the input field.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'AutoCompleteDemo', sources: sources, service: 'CountryService', data: 'countries' }) - } + {useLiveEditorTabs({ name: 'AutoCompleteDemo', sources: sources, service: 'CountryService', data: 'countries' })}
- ) -}) + ); +}); export default AutoCompleteDoc; diff --git a/components/doc/avatar/index.js b/components/doc/avatar/index.js index 7828beabeb..e0814e90e3 100644 --- a/components/doc/avatar/index.js +++ b/components/doc/avatar/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const AvatarDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -116,7 +115,7 @@ export class AvatarDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React from 'react'; @@ -222,7 +221,7 @@ export const AvatarDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React from 'react'; @@ -328,7 +327,7 @@ export const AvatarDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -439,49 +438,53 @@ const AvatarDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Avatar } from 'primereact/avatar'; import { AvatarGroup } from 'primereact/avatargroup'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started

Avatar has three built-in display modes; "label", "icon" and "image".

- -{` + + {` `} - +
Sizes
-

size property defines the size of the Avatar with "large" and "xlarge" as possible values.

- -{` +

+ size property defines the size of the Avatar with "large" and "xlarge" as possible values. +

+ + {` `} - +
AvatarGroup
-

A set of Avatars can be displayed together using the AvatarGroup component.

- -{` +

+ A set of Avatars can be displayed together using the AvatarGroup component. +

+ + {` @@ -489,37 +492,41 @@ import { AvatarGroup } from 'primereact/avatargroup'; `} - +
Shape
-

Avatar comes in two different styles specified with the shape property, "square" is the default and "circle" is the alternative.

- -{` +

+ Avatar comes in two different styles specified with the shape property, "square" is the default and "circle" is the alternative. +

+ + {` `} - +
Badge
-

A badge can be added to an Avatar with the Badge component.

- -{` +

+ A badge can be added to an Avatar with the Badge component. +

+ + {` `} - +
Templating

Content can easily be customized with the default slot instead of using the built-in modes.

- -{` + + {` Content `} - +
Properties of Avatar

Any valid attribute is passed to the root element implicitly, extended properties are as follows;

-
- +
+
@@ -579,8 +586,8 @@ import { AvatarGroup } from 'primereact/avatargroup';

Any property as style and class are passed to the main container element. There are no additional properties.

Events
-
-
Name
+
+
@@ -604,9 +611,11 @@ import { AvatarGroup } from 'primereact/avatargroup';
Styling of Avatar
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -647,8 +656,8 @@ import { AvatarGroup } from 'primereact/avatargroup';
Styling of AvatarGroup
-
-
Name
+
+
@@ -667,8 +676,10 @@ import { AvatarGroup } from 'primereact/avatargroup';
Accessibility
Screen Reader
-

Avatar does not include any roles and attributes by default. Any attribute is passed to the root element so you may add a role like img along with aria-labelledby or aria-label to describe the component. - In case avatars need to be tabbable, tabIndex can be added as well to implement custom key handlers.

+

+ Avatar does not include any roles and attributes by default. Any attribute is passed to the root element so you may add a role like img along with aria-labelledby or aria-label to describe the + component. In case avatars need to be tabbable, tabIndex can be added as well to implement custom key handlers. +

Keyboard Support

Component does not include any interactive elements.

@@ -678,12 +689,10 @@ import { AvatarGroup } from 'primereact/avatargroup';

None.

- { - useLiveEditorTabs({ name: 'AvatarDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'AvatarDemo', sources: sources })} ); -}) +}); export default AvatarDoc; diff --git a/components/doc/badge/index.js b/components/doc/badge/index.js index 618bd84ee9..01fe61117f 100644 --- a/components/doc/badge/index.js +++ b/components/doc/badge/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const BadgeDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -48,7 +47,7 @@ export class BadgeDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React from 'react'; @@ -86,7 +85,7 @@ export const BadgeDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React from 'react'; @@ -124,7 +123,7 @@ export const BadgeDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -166,30 +165,33 @@ const BadgeDemo = () => { } ` } - } + }; return ( -
+
- +
Getting Started

Badge can be used as a component.

Component
- -{` + + {` import { Badge } from 'primereact/badge'; `} - -

Content of the badge is specified using the value property.

- -{` + +

+ Content of the badge is specified using the value property. +

+ + {` `} - +
Severities
-

Different color options are available as severity levels. When used as a component use the severity property - to apply a severity.

+

+ Different color options are available as severity levels. When used as a component use the severity property to apply a severity. +

  • success
  • @@ -197,17 +199,19 @@ import { Badge } from 'primereact/badge';
  • warning
  • danger
- -{` + + {` `} - +
Button Badges
-

Buttons provide integrated badge support with the badge and badgeClass properties.

+

+ Buttons provide integrated badge support with the badge and badgeClass properties. +

- -{` + + {` @@ -216,27 +220,29 @@ import { Badge } from 'primereact/badge'; `} - +
Sizes
-

Badge sizes are adjusted with the size property that accepts "large" and "xlarge" as the possible alternatives to the default size.

- -{` +

+ Badge sizes are adjusted with the size property that accepts "large" and "xlarge" as the possible alternatives to the default size. +

+ + {` `} - +

In addition, when placed inside another element, badge sizes can also derive their size from their parent.

- -{` + + {`

Heading 1

Heading 2

`} -
+
Properties

Any valid attribute is passed to the root element implicitly, extended properties are as follows;

-
-
Name
+
+
@@ -269,14 +275,16 @@ import { Badge } from 'primereact/badge';
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
- - - - + + + + @@ -322,8 +330,10 @@ import { Badge } from 'primereact/badge';
Accessibility
Screen Reader
-

Badge does not include any roles and attributes by default, any attribute is passed to the root element so aria roles and attributes can be added if required. If the badges are dynamic, - aria-live may be utilized as well. In case badges need to be tabbable, tabIndex can be added to implement custom key handlers.

+

+ Badge does not include any roles and attributes by default, any attribute is passed to the root element so aria roles and attributes can be added if required. If the badges are dynamic, + aria-live may be utilized as well. In case badges need to be tabbable, tabIndex can be added to implement custom key handlers. +

Keyboard Support

Component does not include any interactive elements.

@@ -333,12 +343,10 @@ import { Badge } from 'primereact/badge';

None.

- { - useLiveEditorTabs({ name: 'BadgeDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'BadgeDemo', sources: sources })} ); -}) +}); export default BadgeDoc; diff --git a/components/doc/blockui/index.js b/components/doc/blockui/index.js index 480ada8e9c..df23a9c30d 100644 --- a/components/doc/blockui/index.js +++ b/components/doc/blockui/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const BlockUIDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -93,7 +92,7 @@ export class BlockUIDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState, useEffect } from 'react'; @@ -162,7 +161,7 @@ export const BlockUIDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState, useEffect } from 'react'; @@ -231,7 +230,7 @@ export const BlockUIDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -304,8 +303,8 @@ const BlockUIDemo = () => { ) } ` - } } + }; const extFiles = { 'demo/BlockUIDemo.css': { @@ -319,34 +318,35 @@ const BlockUIDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { BlockUI } from 'primereact/blockui'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

BlockUI is controlled using the blocked property, by default target element to block is the child component. In example below, panel gets blocked - with a mask when blockedPanel is enabled and gets unblock when the bound variable is set to false. +

+ BlockUI is controlled using the blocked property, by default target element to block is the child component. In example below, panel gets blocked with a mask when blockedPanel is enabled and gets unblock when the bound + variable is set to false.

- -{` + + {` export const BlockUIDemo = () => { const [blockedPanel, setBlockedPanel] = useState(false); @@ -368,22 +368,24 @@ export const BlockUIDemo = () => { ); } `} - +
Full Screen
-

In full screen mode, instead of a particular element, the whole document gets blocked. Set fullScreen as true in order to enable this functionality.

- -{` +

+ In full screen mode, instead of a particular element, the whole document gets blocked. Set fullScreen as true in order to enable this functionality. +

+ + {` // content `} - +
Properties

Any valid attribute is passed to the root element implicitly, extended properties are as follows;

-
-
NameElement
NameElement
+
+
@@ -446,8 +448,8 @@ export const BlockUIDemo = () => {
Events
-
-
Name
+
+
@@ -471,9 +473,11 @@ export const BlockUIDemo = () => {
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -496,8 +500,10 @@ export const BlockUIDemo = () => {
Accessibility
Screen Reader
-

BlockUI manages aria-busy state attribute when the UI gets blocked and unblocked. Any valid attribute is passed to the root element so additional attributes - like role and aria-live can be used to define live regions.

+

+ BlockUI manages aria-busy state attribute when the UI gets blocked and unblocked. Any valid attribute is passed to the root element so additional attributes like role and aria-live can be used to + define live regions. +

Keyboard Support

Component does not include any interactive elements.

@@ -507,13 +513,10 @@ export const BlockUIDemo = () => {

None.

- { - useLiveEditorTabs({ name: 'BlockUIDemo', sources: sources, extFiles: extFiles }) - } - + {useLiveEditorTabs({ name: 'BlockUIDemo', sources: sources, extFiles: extFiles })} - ) -}) + ); +}); export default BlockUIDoc; diff --git a/components/doc/breadcrumb/index.js b/components/doc/breadcrumb/index.js index 377a83397c..ee2032ec31 100644 --- a/components/doc/breadcrumb/index.js +++ b/components/doc/breadcrumb/index.js @@ -6,11 +6,10 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const BreadCrumbDoc = memo(() => { - - const sources = { - 'class': { - tabName: 'Class Source', - content: ` + const sources = { + class: { + tabName: 'Class Source', + content: ` import React, { Component } from 'react'; import { BreadCrumb } from 'primereact/breadcrumb'; @@ -38,7 +37,7 @@ export class BreadCrumbDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React from 'react'; @@ -65,7 +64,7 @@ const BreadCrumbDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React from 'react'; @@ -92,7 +91,7 @@ const BreadCrumbDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -122,35 +121,37 @@ const BreadCrumbDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { BreadCrumb } from 'primereact/breadcrumb'; `} - +
Import via CDN
- -{` + + {` `} - +
MenuModel API
-

BreadCrumb uses the common menumodel api to define its items, visit MenuModel for details.

+

+ BreadCrumb uses the common menumodel api to define its items, visit MenuModel for details. +

Getting Started

BreadCrumb requires a collection of menuitems as its model.

- -{` + + {` const items = [ { label: 'Categories' }, { label: 'Sports' }, @@ -164,17 +165,17 @@ const items = [ const home = { icon: 'pi pi-home', url: 'https://www.primefaces.org/primereact' } `} - + - -{` + + {` `} - +
Properties
-
-
Name
+
+
@@ -219,9 +220,11 @@ const home = { icon: 'pi pi-home', url: 'https://www.primefaces.org/primereact'
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -251,24 +254,24 @@ const home = { icon: 'pi pi-home', url: 'https://www.primefaces.org/primereact'
Accessibility
-
Screen Reader
-

Breadcrumb uses the nav element and since any attribute is passed to the root implicitly aria-labelledby or aria-label can be used to describe the component. Inside an ordered list is used - where the list item separators have aria-hidden to be able to ignored by the screen readers. If the last link represents the current route, aria-current is added with "page" as the value.

+
Screen Reader
+

+ Breadcrumb uses the nav element and since any attribute is passed to the root implicitly aria-labelledby or aria-label can be used to describe the component. Inside an ordered list is used where the + list item separators have aria-hidden to be able to ignored by the screen readers. If the last link represents the current route, aria-current is added with "page" as the value. +

-
Keyboard Support
-

No special keyboard interaction is needed, all menuitems are focusable based on the page tab sequence.

-
+
Keyboard Support
+

No special keyboard interaction is needed, all menuitems are focusable based on the page tab sequence.

+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'BreadCrumbDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'BreadCrumbDemo', sources: sources })} - ) -}) + ); +}); export default BreadCrumbDoc; diff --git a/components/doc/button/index.js b/components/doc/button/index.js index 35c19d1d74..65825be50a 100644 --- a/components/doc/button/index.js +++ b/components/doc/button/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const ButtonDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -205,7 +204,7 @@ export class ButtonDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -394,7 +393,7 @@ const ButtonDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -583,7 +582,7 @@ const ButtonDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -774,8 +773,8 @@ const ButtonDemo = () => { ) } ` - } } + }; const extFiles = { 'demo/ButtonDemo.css': { @@ -939,70 +938,75 @@ const ButtonDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Button } from 'primereact/button'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started

Button is created using the Button element.

- -{` + + {`
Name
+
+
@@ -1104,9 +1108,11 @@ import { Button } from 'primereact/button';
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -1131,12 +1137,14 @@ import { Button } from 'primereact/button';
Accessibility
- -
Screen Reader
-

Button component renders a native button element that implicitly includes any passed prop. Text to describe the button is defined with the aria-label prop, if not present label prop is used as the value. If the button - is icon only or custom templating is used, it is recommended to use aria-label so that screen readers would be able to read the element properly.

- -{` + +
Screen Reader
+

+ Button component renders a native button element that implicitly includes any passed prop. Text to describe the button is defined with the aria-label prop, if not present label prop is used as the value. If + the button is icon only or custom templating is used, it is recommended to use aria-label so that screen readers would be able to read the element properly. +

+ + {` `} - -
Keyboard Support
-
-
Name
- - - - - - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus to the button.
enterActivates the button.
spaceActivates the button.
-
- + +
Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the button.
+ enter + Activates the button.
+ space + Activates the button.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'ButtonDemo', sources: sources, extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'ButtonDemo', sources: sources, extFiles: extFiles })}
- ) -}) + ); +}); export default ButtonDoc; diff --git a/components/doc/calendar/index.js b/components/doc/calendar/index.js index b368ebd6ed..cf328bb2cb 100644 --- a/components/doc/calendar/index.js +++ b/components/doc/calendar/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const CalendarDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -161,7 +160,7 @@ export class CalendarDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -300,7 +299,7 @@ const CalendarDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -439,7 +438,7 @@ const CalendarDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -581,14 +580,14 @@ const CalendarDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- + {` import { Calendar } from 'primereact/calendar'; `} @@ -603,7 +602,9 @@ import { Calendar } from 'primereact/calendar';
Getting Started
-

Calendar is used a controlled input component with value and onChange properties.

+

+ Calendar is used a controlled input component with value and onChange properties. +

{` @@ -612,7 +613,9 @@ import { Calendar } from 'primereact/calendar';
Popup and Inline
-

Calendar is displayed in a popup by default whereas inline property needs to be enabled for inline mode.

+

+ Calendar is displayed in a popup by default whereas inline property needs to be enabled for inline mode. +

{` @@ -621,9 +624,11 @@ import { Calendar } from 'primereact/calendar';
View Date
-

viewDate defines the date whose month and year are used to display the calendar. By default calendar uses value to render the view and falls back to today's date when value is not defined. In case you'd like - to display a different month/year use viewDate. The usage of this property can either be controlled or uncontrolled. In controlled mode, onViewDateChange is required to manage the viewDate whereas in - uncontrolled mode, viewDate is used only once in initial rendering and ignored in updates. If you'd like to change the displayed month/year programmatically, use the onViewDateChange in controlled mode.

+

+ viewDate defines the date whose month and year are used to display the calendar. By default calendar uses value to render the view and falls back to today's date when value is not defined. In case you'd like to display + a different month/year use viewDate. The usage of this property can either be controlled or uncontrolled. In controlled mode, onViewDateChange is required to manage the viewDate whereas in uncontrolled mode, + viewDate is used only once in initial rendering and ignored in updates. If you'd like to change the displayed month/year programmatically, use the onViewDateChange in controlled mode. +

{` setDate(e.value)} viewDate={viewDate} onViewDateChange={(e) => setViewDate(e.value)}> @@ -631,9 +636,11 @@ import { Calendar } from 'primereact/calendar';
Selection Mode
-

Calendar offers "single" (default), "multiple" and "range" selection types controlled via the selectionMode property. In single, mode the bound value should be an array whereas in multiple - case an array is required. Third alternative is the range mode that allows selecting a range based on an array of two values where first value is the start date and second value - is the end date. Note: Time picker is supported in range mode but not in multiple mode.

+

+ Calendar offers "single" (default), "multiple" and "range" selection types controlled via the selectionMode property. In single, mode the bound value should be an array whereas in multiple case an array is required. + Third alternative is the range mode that allows selecting a range based on an array of two values where first value is the start date and second value is the end date. Note: Time picker is supported in range + mode but not in multiple mode. +

{` setDates(e.value)}> @@ -641,7 +648,9 @@ import { Calendar } from 'primereact/calendar';
DateFormat
-

Default date format is "mm/dd/yy" which can be customized using the dateFormat property.

+

+ Default date format is "mm/dd/yy" which can be customized using the dateFormat property. +

{` @@ -671,11 +680,15 @@ import { Calendar } from 'primereact/calendar';
Locale
-

Translations for the calendar are defined with the Locale API.

+

+ Translations for the calendar are defined with the Locale API. +

Time
-

TimePicker is enabled with showTime property and hourFormat is used to select the 24 (default) or 12 hour mode. Optionally enabling timeOnly - displays a calendare with time controls only.

+

+ TimePicker is enabled with showTime property and hourFormat is used to select the 24 (default) or 12 hour mode. Optionally enabling timeOnly + displays a calendare with time controls only. +

{` @@ -686,7 +699,9 @@ import { Calendar } from 'primereact/calendar';
Date Restriction
-

To disable entering dates manually, set readOnlyInput to true and to restrict selectable date ranges use minDate and maxDate options.

+

+ To disable entering dates manually, set readOnlyInput to true and to restrict selectable date ranges use minDate and maxDate options. +

{` @@ -695,8 +710,10 @@ import { Calendar } from 'primereact/calendar';
Disable specific dates and/or days
-

Specific dates or days can be disabled as well, in this case set readOnlyInput to true and to restrict selectable dates use disabledDates and/or disabledDays options. disabledDates - property should be an array of dates and disabledDays should be an array of disabled weekdays.

+

+ Specific dates or days can be disabled as well, in this case set readOnlyInput to true and to restrict selectable dates use disabledDates and/or disabledDays options. disabledDates + property should be an array of dates and disabledDays should be an array of disabled weekdays. +

{` @@ -705,7 +722,9 @@ import { Calendar } from 'primereact/calendar';
Button Bar
-

Button bar displays today and clear buttons and activated using the showButtonBar property.

+

+ Button bar displays today and clear buttons and activated using the showButtonBar property. +

{` setDate(e.value)} showButtonBar> @@ -713,7 +732,9 @@ import { Calendar } from 'primereact/calendar';
Multiple Months
-

Displaying multiple months is enabled by setting numberOfMonths property to a value greater than 1.

+

+ Displaying multiple months is enabled by setting numberOfMonths property to a value greater than 1. +

{` setDate(e.value)} numberOfMonths={3}> @@ -721,8 +742,10 @@ import { Calendar } from 'primereact/calendar';
Date Template
-

Date cell contents can be templated using the dateTemplate property that returns the content of a cell. This is a handy feature to highlight specific dates. Note that the - variable passed to the template is not a date instance but a metadata object to represent a Date with "day", "month", "year", "otherMonth", "today" and "selectable" properties to represent the date. Example below changes the styling of dates between 10 and 15.

+

+ Date cell contents can be templated using the dateTemplate property that returns the content of a cell. This is a handy feature to highlight specific dates. Note that the variable passed to the template is not a date + instance but a metadata object to represent a Date with "day", "month", "year", "otherMonth", "today" and "selectable" properties to represent the date. Example below changes the styling of dates between 10 and 15. +

{` @@ -730,7 +753,7 @@ import { Calendar } from 'primereact/calendar'; `} - + {` dateTemplate(date) { if (date.day > 10 && date.day < 15) { @@ -746,7 +769,9 @@ dateTemplate(date) {
Header and Footer
-

The headerTemplate and footerTemplate properties are available to place custom content at these sections.

+

+ The headerTemplate and footerTemplate properties are available to place custom content at these sections. +

{` setDate(e.value)} headerTemplate={() =>
); -}) +}); export default CalendarDoc; diff --git a/components/doc/captcha/index.js b/components/doc/captcha/index.js index 48cd7b4dbe..f3db64a3d4 100644 --- a/components/doc/captcha/index.js +++ b/components/doc/captcha/index.js @@ -4,10 +4,9 @@ import { useLiveEditorTabs } from '../common/liveeditor'; import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; -const CaptchaDoc = memo(() => { - +const CaptchaDoc = memo(() => { const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -39,7 +38,7 @@ export class CaptchaDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useRef } from 'react'; @@ -65,7 +64,7 @@ const CaptchaDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useRef } from 'react'; @@ -91,7 +90,7 @@ const CaptchaDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -121,56 +120,57 @@ const CaptchaDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Captcha } from 'primereact/captcha'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started

Captcha is used with a siteKey and a callback to verify the response.

- -{` + + {` `} - +
Verification
-

In order to ensure if a response token is valid, verification against recaptcha api needs to be done at backend. Read more at - official documentation.

- -{` +

+ In order to ensure if a response token is valid, verification against recaptcha api needs to be done at backend. Read more at official documentation. +

+ + {` const showResponse = (response) => { //call to a backend to verify against recaptcha with private key } `} - +

In addition, include the captcha widget resource to your page.

- -{` + + {` `} - +
Properties
-
- +
+
@@ -227,8 +227,8 @@ const showResponse = (response) => {
Events
-
-
Name
+
+
@@ -252,8 +252,8 @@ const showResponse = (response) => {
Methods
-
-
Name
+
+
@@ -278,19 +278,23 @@ const showResponse = (response) => {
Accessibility
-

Refer to the Recaptcha Accessibility documentation for more information.

+

+ Refer to the{' '} + + Recaptcha Accessibility + {' '} + documentation for more information. +

Dependencies

Google Recaptcha V2

- { - useLiveEditorTabs({ name: 'CaptchaDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'CaptchaDemo', sources: sources })} - ) -}) + ); +}); export default CaptchaDoc; diff --git a/components/doc/card/index.js b/components/doc/card/index.js index 8f5653bfcd..b98efe9e88 100644 --- a/components/doc/card/index.js +++ b/components/doc/card/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const CardDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -45,7 +44,7 @@ export class CardDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React from 'react'; @@ -80,7 +79,7 @@ const CardDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React from 'react'; @@ -115,7 +114,7 @@ const CardDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -153,52 +152,54 @@ const CardDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Card } from 'primereact/card'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started

Card is used as a container.

- -{` + + {` Content `} - +
Title
-

Title text of the card is provided using the title property whereas subTitle property is available for additional information about the card. Both of these properties accept JSX as well.

- -{` +

+ Title text of the card is provided using the title property whereas subTitle property is available for additional information about the card. Both of these properties accept JSX as well. +

+ + {` Content `} - +
Header and Footer

Header and Footer sections are defined using the properties of the same name.

- -{` + + {` const header = Card; const footer =
Name
+
+
@@ -270,9 +271,11 @@ const footer =
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -305,34 +308,36 @@ const footer =
Accessibility
- -
Screen Reader
-

A card can be utilized in many use cases as a result no role is enforced, in fact a role may not be necessary if the card is used for presentational purposes only. - Any valid attribute is passed to the container element so if you require to use one of the landmark roles - like region, you may use the role property. -

- - -{` + +
Screen Reader
+

+ A card can be utilized in many use cases as a result no role is enforced, in fact a role may not be necessary if the card is used for presentational purposes only. Any valid attribute is passed to the container element so + if you require to use one of the{' '} + + landmark + {' '} + roles like region, you may use the role property. +

+ + + {` Content `} - +
-
Keyboard Support
-

Component does not include any interactive elements.

-
+
Keyboard Support
+

Component does not include any interactive elements.

+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'CardDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'CardDemo', sources: sources })} - ) -}) + ); +}); export default CardDoc; diff --git a/components/doc/carousel/index.js b/components/doc/carousel/index.js index 5f474908cd..810f61024a 100644 --- a/components/doc/carousel/index.js +++ b/components/doc/carousel/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const CarouselDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -97,7 +96,7 @@ export class CarouselDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState, useEffect } from 'react'; @@ -175,7 +174,7 @@ const CarouselDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState, useEffect } from 'react'; @@ -253,7 +252,7 @@ const CarouselDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -335,8 +334,8 @@ const CarouselDemo = () => { ); } ` - } } + }; const extFiles = { 'demo/CarouselDemo.css': { @@ -355,63 +354,66 @@ const CarouselDemo = () => { } ` } - } + }; - return ( -
+ return ( +
- +
Import via Module
- -{` + + {` import { Carousel } from 'primereact/carousel'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started

Carousel requires a collection of items as its value along with a template to render each item.

- -{` + + {` `} - + - -{` + + {` const itemTemplate = (product) => { // return content; } `} - +
Items per page and Scroll Items
-

Number of items per page is defined using the numVisible property whereas number of items to scroll is defined with the numScroll property.

- -{` +

+ Number of items per page is defined using the numVisible property whereas number of items to scroll is defined with the numScroll property. +

+ + {` `} - +
Responsive
-

For responsive design, numVisible and numScroll can be defined using the responsiveOptions property that should be an array of - objects whose breakpoint defines the max-width to apply the settings.

- -{` +

+ For responsive design, numVisible and numScroll can be defined using the responsiveOptions property that should be an array of objects whose breakpoint defines the max-width to apply the settings. +

+ + {` `} - +
- -{` + + {` const responsiveOptions = [ { breakpoint: '1024px', @@ -430,49 +432,60 @@ const responsiveOptions = [ } ]; `} - +
Header and Footer
-

Custom content projection is available using the header and footer properties.

- -{` +

+ Custom content projection is available using the header and footer properties. +

+ + {` Header}> `} - +
Orientation
-

Default layout of the Carousel is horizontal, other possible option is the vertical mode that is configured with the orientation property.

- -{` +

+ Default layout of the Carousel is horizontal, other possible option is the vertical mode that is configured with the orientation property. +

+ + {` `} - +
AutoPlay and Circular
-

When autoplayInterval is defined in milliseconds, items are scrolled automatically. In addition, for infinite scrolling circular property needs to be enabled. Note that in autoplay mode, circular is enabled by default.

+

+ When autoplayInterval is defined in milliseconds, items are scrolled automatically. In addition, for infinite scrolling circular property needs to be enabled. Note that in autoplay mode, circular is enabled by + default. +

Controlled vs Uncontrolled
-

In controlled mode, page and onPageChange properties need to be defined to control the first visible item.

+

+ In controlled mode, page and onPageChange properties need to be defined to control the first visible item. +

- -{` + + {` setPage(e.page)}> `} - +
Uncontrolled
-

In uncontrolled mode, no additional properties are required. Initial page can be provided using the page property in uncontrolled mode however it is evaluated at initial rendering and ignored in further updates. If you programmatically - need to update the first visible item index, prefer to use the component as controlled.

+

+ In uncontrolled mode, no additional properties are required. Initial page can be provided using the page property in uncontrolled mode however it is evaluated at initial rendering and ignored in further updates. If you + programmatically need to update the first visible item index, prefer to use the component as controlled. +

- -{` + + {` `} - +
Properties
-
-
Name
+
+
@@ -595,8 +608,8 @@ const responsiveOptions = [
Events
-
-
Name
+
+
@@ -616,8 +629,8 @@ const responsiveOptions = [
Styling

Following is the list of structural style classes

-
-
Name
+
+
@@ -664,20 +677,28 @@ const responsiveOptions = [
Accessibility
Screen Reader
-

Carousel uses region role and since any attribute is passed to the main container element, attributes such as aria-label and aria-roledescription can be used as well. The slides container has aria-live attribute - set as "polite" if carousel is not in autoplay mode, otherwise "off" would be the value in autoplay.

+

+ Carousel uses region role and since any attribute is passed to the main container element, attributes such as aria-label and aria-roledescription can be used as well. The slides container has{' '} + aria-live attribute set as "polite" if carousel is not in autoplay mode, otherwise "off" would be the value in autoplay. +

-

A slide has a group role with an aria-label that refers to the aria.slideNumber property of the locale API. Similarly aria.slide is used as the aria-roledescription of the item. - Inactive slides are hidden from the readers with aria-hidden.

+

+ A slide has a group role with an aria-label that refers to the aria.slideNumber property of the locale API. Similarly aria.slide is used as the aria-roledescription{' '} + of the item. Inactive slides are hidden from the readers with aria-hidden. +

-

Next and Previous navigators are button elements with aria-label attributes referring to the aria.nextPageLabel and aria.firstPageLabel properties of the locale API by default respectively, - you may still use your own aria roles and attributes as any valid attribute is passed to the button elements implicitly by using nextButtonProps and prevButtonProps.

+

+ Next and Previous navigators are button elements with aria-label attributes referring to the aria.nextPageLabel and aria.firstPageLabel properties of the locale API by + default respectively, you may still use your own aria roles and attributes as any valid attribute is passed to the button elements implicitly by using nextButtonProps and prevButtonProps. +

-

Quick navigation elements are button elements with an aria-label attribute referring to the aria.pageLabel of the locale API. Current page is marked with aria-current.

+

+ Quick navigation elements are button elements with an aria-label attribute referring to the aria.pageLabel of the locale API. Current page is marked with aria-current. +

Next/Prev Keyboard Support
-
-
Name
+
+
@@ -686,15 +707,21 @@ const responsiveOptions = [ - + - + - + @@ -702,8 +729,8 @@ const responsiveOptions = [
Quick Navigation Keyboard Support
-
-
Key
tab + tab + Moves focus through interactive elements in the carousel.
enter + enter + Activates navigation.
space + space + Activates navigation.
+
+
@@ -712,31 +739,45 @@ const responsiveOptions = [ - + - + - + - + - + - + - + @@ -746,15 +787,12 @@ const responsiveOptions = [
Dependencies

None.

- - { - useLiveEditorTabs({ name: 'CarouselDemo', sources: sources, service: 'ProductService', data: 'products-small', extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'CarouselDemo', sources: sources, service: 'ProductService', data: 'products-small', extFiles: extFiles })} ); -}) +}); export default CarouselDoc; diff --git a/components/doc/cascadeselect/index.js b/components/doc/cascadeselect/index.js index 0637c38dfc..d74c367cf1 100644 --- a/components/doc/cascadeselect/index.js +++ b/components/doc/cascadeselect/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const CascadeSelectDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -131,7 +130,7 @@ export class CascadeSelectDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -245,7 +244,7 @@ const CascadeSelectDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -359,7 +358,7 @@ const CascadeSelectDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -476,40 +475,42 @@ const CascadeSelectDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { CascadeSelect } from 'primereact/cascadeselect'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

CascadeSelect requires a value to bind and a collection of arbitrary objects with a nested hierarchy. optionGroupLabel +

+ CascadeSelect requires a value to bind and a collection of arbitrary objects with a nested hierarchy. optionGroupLabel is used for the text of a category and optionGroupChildren is to define the children of the category. Note that order of the optionGroupChildren - matters and it should correspond to the data hierarchy.

- -{` + matters and it should correspond to the data hierarchy. +

+ + {` setSelectedCity1(event.value)}/> `} - +
- -{` + + {` const countries = [ { name: 'Australia', @@ -587,19 +588,20 @@ const countries = [ } ] `} - - +
Templating
-

Content of an item can be customized with the itemTemplate prop.

- -{` +

+ Content of an item can be customized with the itemTemplate prop. +

+ + {` setSelectedCity2(event.value)} itemTemplate={countryOptionTemplate}/> `} - - -{` + + + {` const countryOptionTemplate = (option) => { return (
@@ -612,12 +614,12 @@ const countryOptionTemplate = (option) => { ); } `} - +
Properties

Any valid attribute is passed to the root element implicitly, extended properties are as follows;

-
-
Key
tab + tab + Moves focus through the active slide link.
enter + enter + Activates the focused slide link.
space + space + Activates the focused slide link.
right arrow + right arrow + Moves focus to the next slide link.
left arrow + left arrow + Moves focus to the previous slide link.
home + home + Moves focus to the first slide link.
end + end + Moves focus to the last slide link.
+
+
@@ -715,7 +717,9 @@ const countryOptionTemplate = (option) => { - + @@ -727,7 +731,13 @@ const countryOptionTemplate = (option) => { - + @@ -740,8 +750,8 @@ const countryOptionTemplate = (option) => {
Events
-
-
NameappendTo DOM element | string document.bodyDOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. + DOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. +
itemTemplatetransitionOptions object nullThe properties of CSSTransition can be customized, except for "nodeRef" and "in" properties. + The properties of{' '} + + CSSTransition + {' '} + can be customized, except for "nodeRef" and "in" properties. +
dropdownIcon
+
+
@@ -752,8 +762,10 @@ const countryOptionTemplate = (option) => { - + @@ -786,9 +798,11 @@ const countryOptionTemplate = (option) => {
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
onChangeevent.originalEvent: Original event
- event.value: Value of the checkbox
+ event.originalEvent: Original event
+ event.value: Value of the checkbox{' '} +
Callback to invoke on value change
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -829,108 +843,137 @@ const countryOptionTemplate = (option) => {
Accessibility
- -
Screen Reader
-

Value to describe the component can either be provided with aria-labelledby or aria-label props. The cascadeselect element has a combobox role - in addition to aria-haspopup and aria-expanded attributes. The relation between the combobox and the popup is created with aria-controls that refers to the id of the popup.

-

The popup list has an id that refers to the aria-controls attribute of the combobox element and uses tree as the role. Each list item has a treeitem role along with aria-label, aria-selected and aria-expanded attributes. The container - element of a treenode has the group role. The aria-setsize, aria-posinset and aria-level attributes are calculated implicitly and added to each treeitem.

- -

If filtering is enabled, filterInputProps can be defined to give aria-* props to the filter input element.

- -{` + +
Screen Reader
+

+ Value to describe the component can either be provided with aria-labelledby or aria-label props. The cascadeselect element has a combobox role in addition to aria-haspopup and{' '} + aria-expanded attributes. The relation between the combobox and the popup is created with aria-controls that refers to the id of the popup. +

+

+ The popup list has an id that refers to the aria-controls attribute of the combobox element and uses tree as the role. Each list item has a treeitem role along with aria-label,{' '} + aria-selected and aria-expanded attributes. The container element of a treenode has the group role. The aria-setsize, aria-posinset and aria-level attributes are calculated + implicitly and added to each treeitem. +

+ +

+ If filtering is enabled, filterInputProps can be defined to give aria-* props to the filter input element. +

+ + {` Options `} - -
Closed State Keyboard Support
-
-
Name
- - - - - - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus to the cascadeselect element.
spaceOpens the popup and moves visual focus to the selected option, if there is none then first option receives the focus.
down arrowOpens the popup and moves visual focus to the selected option, if there is none then first option receives the focus.
-
- -
Popup Keyboard Support
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyFunction
tabHides the popup and moves focus to the next tabbable element.
shift + tabHides the popup and moves focus to the previous tabbable element.
enterSelects the focused option and closes the popup.
spaceSelects the focused option and closes the popup.
escapeCloses the popup, moves focus to the cascadeselect element.
down arrowMoves focus to the next option.
up arrowMoves focus to the previous option.
right arrowIf option is closed, opens the option otherwise moves focus to the first child option.
left arrowIf option is open, closes the option otherwise moves focus to the parent option.
-
- + +
Closed State Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the cascadeselect element.
+ space + Opens the popup and moves visual focus to the selected option, if there is none then first option receives the focus.
+ down arrow + Opens the popup and moves visual focus to the selected option, if there is none then first option receives the focus.
+
+ +
Popup Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Hides the popup and moves focus to the next tabbable element.
+ shift + tab + Hides the popup and moves focus to the previous tabbable element.
+ enter + Selects the focused option and closes the popup.
+ space + Selects the focused option and closes the popup.
+ escape + Closes the popup, moves focus to the cascadeselect element.
+ down arrow + Moves focus to the next option.
+ up arrow + Moves focus to the previous option.
+ right arrow + If option is closed, opens the option otherwise moves focus to the first child option.
+ left arrow + If option is open, closes the option otherwise moves focus to the parent option.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'CascadeSelectDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'CascadeSelectDemo', sources: sources })}
- ) -}) + ); +}); export default CascadeSelectDoc; diff --git a/components/doc/chart/index.js b/components/doc/chart/index.js index 31557d3db7..69223964e3 100644 --- a/components/doc/chart/index.js +++ b/components/doc/chart/index.js @@ -3,48 +3,53 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const ChartDoc = () => { - return ( -
+
Import via Module
- -{` + + {` import { Chart } from 'primereact/chart'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

Chart component is a wrapper around on Chart.js 3.3.2+ so chart.js needs to be included in your project. - For a complete documentation and samples please refer to the chart.js website.

+

+ Chart component is a wrapper around on Chart.js 3.3.2+ so chart.js needs to be included in your project. For a complete documentation and samples please refer to the{' '} + chart.js website. +

- -{` + + {` npm install chart.js `} - +
Chart Types
-

Chart type is defined using the type property. Currently there are 6 options available; "pie", "doughtnut", "line", "bar", "radar" and "polarArea".

+

+ Chart type is defined using the type property. Currently there are 6 options available; "pie", "doughtnut", "line", "bar", "radar" and "polarArea". +

Data
-

Data of a chart is provided using a binding to the data property, each type has its own format of data. Here is an example of a line chart.

+

+ Data of a chart is provided using a binding to the data property, each type has its own format of data. Here is an example of a line chart. +

- -{` + + {` `} - + - -{` + + {` const data = { labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'], datasets: [ @@ -63,20 +68,22 @@ const data = { ] }; `} - +
Options
-

While a series can be customized per dataset, general chart options are defined with options property. - Example below adds a title and customizes the legend position of the chart. For all available options refer to the charts.js documentation.

+

+ While a series can be customized per dataset, general chart options are defined with options property. Example below adds a title and customizes the legend position of the chart. For all available options refer to the charts.js + documentation. +

- -{` + + {` `} - + - -{` + + {` const options = { plugins: { title: { @@ -92,11 +99,11 @@ const options = { }; } `} - +
Properties
-
- +
+
@@ -165,8 +172,8 @@ const options = {
Methods
-
-
Name
+
+
@@ -186,22 +193,22 @@ const options = {
Accessibility
-

Chart components internally use canvas element, refer to the Chart.js accessibility guide for more information. The canvas element can be customized - with canvasProps property to define aria roles and properties, in addition any content inside the component is directly passed as a child of the canvas to be able to - provide fallback content like a table.

- -{` +

+ Chart components internally use canvas element, refer to the Chart.js accessibility guide for more information. The canvas element can be customized with canvasProps property to define aria roles and + properties, in addition any content inside the component is directly passed as a child of the canvas to be able to provide fallback content like a table. +

+ + {` `} - - +
- ) -} + ); +}; export default ChartDoc; diff --git a/components/doc/checkbox/index.js b/components/doc/checkbox/index.js index 44abffd414..9c1df30eae 100644 --- a/components/doc/checkbox/index.js +++ b/components/doc/checkbox/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const CheckboxDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -109,7 +108,7 @@ export class CheckboxDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -197,7 +196,7 @@ const CheckboxDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -285,7 +284,7 @@ const CheckboxDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` `, @@ -375,38 +374,40 @@ const CheckboxDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Checkbox } from 'primereact/checkbox'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

Checkbox is used as a controlled input with checked and onChange properties.

- -{` +

+ Checkbox is used as a controlled input with checked and onChange properties. +

+ + {` setChecked(e.checked)} checked={checked}> `} - +
Multiple Values

Multiple checkboxes can be grouped using a list of values.

- -{` + + {`
@@ -420,10 +421,10 @@ import { Checkbox } from 'primereact/checkbox';
`} -
+
- -{` + + {` const [cities, setCities] = useState([]); const onCityChange = (e) => { @@ -436,12 +437,12 @@ const onCityChange = (e) => { setCities(selectedCities); } `} - +
Properties

Any valid attribute is passed to the root element implicitly, extended properties are as follows;

-
-
Name
+
+
@@ -552,8 +553,8 @@ const onCityChange = (e) => {
Events
-
-
Name
+
+
@@ -564,9 +565,11 @@ const onCityChange = (e) => { - + @@ -584,9 +587,11 @@ const onCityChange = (e) => {
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
onChangeevent.originalEvent: Original event
- event.value: Value of the checkbox
- event.checked: Checked state as a boolean.
+ event.originalEvent: Original event
+ event.value: Value of the checkbox
+ event.checked: Checked state as a boolean. +
Callback to invoke on value change
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -615,11 +620,14 @@ const onCityChange = (e) => {
Accessibility
- -
Screen Reader
-

Checkbox component uses a hidden native checkbox element internally that is only visible to screen readers. Value to describe the component can either be provided via label tag combined with inputId prop or using aria-labelledby, aria-label props.

- -{` + +
Screen Reader
+

+ Checkbox component uses a hidden native checkbox element internally that is only visible to screen readers. Value to describe the component can either be provided via label tag combined with inputId prop or + using aria-labelledby, aria-label props. +

+ + {` @@ -628,39 +636,41 @@ const onCityChange = (e) => { `} - -
Keyboard Support
-
-
Name
- - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus to the checkbox.
spaceToggles the checked state.
-
- + +
Keyboard Support
+
+ + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the checkbox.
+ space + Toggles the checked state.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'CheckboxDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'CheckboxDemo', sources: sources })}
- ) -}) + ); +}); export default CheckboxDoc; diff --git a/components/doc/chip/index.js b/components/doc/chip/index.js index 1e4571b4af..cf79e2c380 100644 --- a/components/doc/chip/index.js +++ b/components/doc/chip/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const ChipDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -59,7 +58,7 @@ export class ChipDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React from 'react'; @@ -107,7 +106,7 @@ const ChipDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React from 'react'; @@ -155,7 +154,7 @@ const ChipDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -207,7 +206,7 @@ const ChipDemo = () => { } ` } - } + }; const extFiles = { 'demo/ChipDemo.css': { content: ` @@ -217,60 +216,64 @@ const ChipDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Chip } from 'primereact/chip'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started

Chip can display labels, icons and images.

- -{` + + {` `} - +
Removable
-

Setting removable property displays an icon to close the chip, the optional onRemove - event is available to get notified when a chip is hidden.

- -{` +

+ Setting removable property displays an icon to close the chip, the optional onRemove + event is available to get notified when a chip is hidden. +

+ + {` `} - +
Templating
-

Content can easily be customized with the template property instead of using the built-in modes.

+

+ Content can easily be customized with the template property instead of using the built-in modes. +

- -{` + + {` Content} /> Content} /> `} - +
Properties
-
- +
+
@@ -339,8 +342,8 @@ import { Chip } from 'primereact/chip';
Events
-
-
Name
+
+
@@ -364,9 +367,11 @@ import { Chip } from 'primereact/chip';
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -395,40 +400,42 @@ import { Chip } from 'primereact/chip';
Accessibility
- -
Screen Reader
-

Chip uses the label property as the default aria-label, since any attribute is passed to the root element aria-labelledby or aria-label can be used to override the default behavior. - Removable chips have a tabIndex and focusable with the tab key.

- -
Keyboard Support
-
-
Name
- - - - - - - - - - - - -
KeyFunction
backspaceHides removable.
-
- + +
Screen Reader
+

+ Chip uses the label property as the default aria-label, since any attribute is passed to the root element aria-labelledby or aria-label can be used to override the default behavior. Removable + chips have a tabIndex and focusable with the tab key. +

+ +
Keyboard Support
+
+ + + + + + + + + + + + + +
KeyFunction
+ backspace + Hides removable.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'ChipDemo', sources: sources, extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'ChipDemo', sources: sources, extFiles: extFiles })}
- ) -}) + ); +}); export default ChipDoc; diff --git a/components/doc/chips/index.js b/components/doc/chips/index.js index 893fe9aeae..af5423e58a 100644 --- a/components/doc/chips/index.js +++ b/components/doc/chips/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; export const ChipsDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -53,7 +52,7 @@ export class ChipsDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -90,7 +89,7 @@ const ChipsDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -127,7 +126,7 @@ const ChipsDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -167,45 +166,49 @@ const ChipsDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Chips } from 'primereact/chips'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

Chips requires an array as its value and onChange callback to update the model.

+

+ Chips requires an array as its value and onChange callback to update the model. +

- -{` + + {` setValue(e.value)}> `} - +
Custom Content
-

A chip is customized using itemTemplate function where value is passed to return JSX.

- -{` +

+ A chip is customized using itemTemplate function where value is passed to return JSX. +

+ + {` setValue(e.value)} itemTemplate={customChip}> `} - - -{` + + + {` customChip(item) { return (
@@ -216,13 +219,15 @@ customChip(item) { } `} - +
KeyFilter
-

Chips has built-in key filtering support to block certain keys, refer to keyfilter page for more information.

+

+ Chips has built-in key filtering support to block certain keys, refer to keyfilter page for more information. +

Properties
-
- +
+
@@ -351,8 +356,8 @@ customChip(item) {
Events
-
-
Name
+
+
@@ -363,20 +368,26 @@ customChip(item) { - + - + - + @@ -399,9 +410,11 @@ customChip(item) {
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
onChangeoriginalEvent: Browser event
- value: New value of the component
+ originalEvent: Browser event
+ value: New value of the component +
Callback to invoke when a chip is added or removed.
onAddoriginalEvent: Browser event
- value: Added item value
+ originalEvent: Browser event
+ value: Added item value +
Callback to invoke when a chip is added. Return 'false' to prevent the item from being added.
onRemoveoriginalEvent: Browser event
- value: Removed item value
+ originalEvent: Browser event
+ value: Removed item value +
Callback to invoke when a chip is removed.
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -434,12 +447,14 @@ customChip(item) {
Accessibility
- -
Screen Reader
-

Value to describe the component can either be provided via label tag combined with inputId prop or using aria-labelledby, aria-label props. - Chip list uses listbox role with aria-orientation set to horizontal whereas each chip has the option role with aria-label set to the label of the chip.

- -{` + +
Screen Reader
+

+ Value to describe the component can either be provided via label tag combined with inputId prop or using aria-labelledby, aria-label props. Chip list uses listbox role with{' '} + aria-orientation set to horizontal whereas each chip has the option role with aria-label set to the label of the chip. +

+ + {` @@ -448,73 +463,85 @@ customChip(item) { `} - -
Input Field Keyboard Support
-
-
Name
- - - - - - - - - - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus to the input element
enterAdds a new chips using the input field value.
backspaceDeletes the previous chip if the input field is empty.
left arrowMoves focus to the previous chip if available and input field is empty.
-
- -
Chip Keyboard Support
-
- - - - - - - - - - - - - - - - - - - - - -
KeyFunction
left arrowMoves focus to the previous chip if available.
right arrowMoves focus to the next chip, if there is none then input field receives the focus.
backspaceDeletes the chips and adds focus to the input field.
-
- + +
Input Field Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the input element
+ enter + Adds a new chips using the input field value.
+ backspace + Deletes the previous chip if the input field is empty.
+ left arrow + Moves focus to the previous chip if available and input field is empty.
+
+ +
Chip Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ left arrow + Moves focus to the previous chip if available.
+ right arrow + Moves focus to the next chip, if there is none then input field receives the focus.
+ backspace + Deletes the chips and adds focus to the input field.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'ChipsDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'ChipsDemo', sources: sources })}
); -}) +}); export default ChipsDoc; diff --git a/components/doc/colorpicker/index.js b/components/doc/colorpicker/index.js index 331cd6a1ba..e42966deb9 100644 --- a/components/doc/colorpicker/index.js +++ b/components/doc/colorpicker/index.js @@ -5,9 +5,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const ColorPickerDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -39,7 +38,7 @@ export class ColorPickerDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -63,7 +62,7 @@ const ColorPickerDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -87,7 +86,7 @@ const ColorPickerDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -113,11 +112,11 @@ const ColorPickerDemo = () => { ) } ` - } } + }; - const extFiles = { - 'index.css': ` + const extFiles = { + 'index.css': ` .p-colorpicker-panel .p-colorpicker-hue { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAACWCAIAAAC3uvTNAAAA7ElEQVRYw+2YUQqDQAxEh9GWuqV6Be9/JT88RN0VRUuv0ElBwhKY3yF5m90kLKd+mF/975r6geNyjm9Fy0kgqTJ6nqoIdGKczjmPJU5tZxA8wWPL7YOHKhZAlcmTAVVcxSCrMbfgqY/H6JEOoASPe56tgSrqLR7U2zWojwWjJ3jq47HEiZoGTwJxP1RRXw8y9RZfCMhbhTHOVTxXnUFtPJ5rGjzu35y2KfKGQxWT2K4TQL1d2zz6KAH1kRU8wfOXx+37qY3Hct+aDaqot2u7R/wMuDS3qnj0z0HqK4X/+kRNHdfUwFP2Nisqe/sFuUZiVjC9HCUAAAAASUVORK5CYII=) } @@ -125,52 +124,54 @@ const ColorPickerDemo = () => { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAACWCAYAAAA8AXHiAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHotAACAlQAA+NcAAIhSAABxRQAA6mYAADkHAAAh+QMnhVYAACf5SURBVHja7H3LjuRIkqQaJ+e0wB72T/s7+w/qOKduoLBd3ZVZmeEP0z0UjSUUiqqpuUf1AoMJIBDuTjrdwyhUERVVMzZ3/y8z+99m9jAz33/7/hs97vb7zzv7qff54n7HNncv7Vc9nnjuf/Ixsv2i7y/328eii/EMP9vd5fjvr3cc4/Fa793dvffe+/P57Pf73b99+9b/8pe/9C+99/9jZv9rB8Dsn3kWT9RsQCIgzE7Us3r8le+Ig/fqMRKAp8cAEPAY4/Gy93l2cY393P0J+/nYBtvH8+e+rfXe246cBr/+eDz68/m0+/3uHx8f9v37d/v69av9/PPP/tNPP9lf//pX+9J7f+ygenzCSfPZgLxz0l48oeEvXKVv7fPisU4/v28yM7O2/5q7t+A5P3Y8hvq772/u3nYQjdePfXbgbDuYxmv+fD7t+Xza4/Gwx+Ph9/vdbreb3W43//79u/3666/2z3/+0/72t7/5Tz/9ZN++fbMv8A+Vfmj/ZmZtf63hgLXWVo7z0ueOgQ0enwY9+MH9Kp99+Vw8wcG2bQc+7+cF8BgcC4957EevNwDRRgByAFYbQILIdIDI3e35fFrvvY2/j8ejPR6P7X6/++1284+Pj/bjxw/79u1b+/XXX9s//vGP9ve//91+/vnn9ng82pfe+8qJ5YH1FeAEJ28KEPpsg5NyArEA3+lEtdaOE8MXQvBZDBKbAYv3w+PhNnhsapu7W2tt671ba63vf1vvPQQWRaUjUu2/B9D2c34C0YhSO5B8j1B9/9uez2e73++2/247BfrXr1/tX//6l/3yyy/2yy+/+NevX+35fNoUWDAwKZCKESYEZyGCpSdeAEnRTRW4YSQKgJQBy+HxRkHUOZrtwEGAMICOY/wRhE60NsDTB7DGMZHuzMx778Zgcnd7PB4DWPZ8Pn0A6na79dvtZvf7fbvf7/bbb78dwPr111/t69ev/ttvv1nvfQqs8Y/5Im2VIluR3sag+uQ7toDi5PcQ39FEVLqALgNW8HgDJPWE0i5gIp00ANSZ0sxs0BkCyDBCjef7376/NgT51ns/IhYCCzXV/X63j48P//HjR//4+Gj3+719+/bNxu/379/9drv9DqwoUlQBpehnIk6jSOSr+ir4jnysCCDZ+46T1FrDk+2tNcOLESN6AKzTRwFQZsByEteK7hrS3R6ZBngaRizQUcfj5/PZdh01QDWe266p2uPxsPv93m632/i179+/t99++619fHwMrdV+/PjRbrebPR6PZmZaY1WFNdFkKwCqLYjriI48SCAqkU5RldJEXtBLBhGpR8AiACGNdd4v0EuH+GZggd7aRJTqCKRBhyN6YYQaVLhrqra/tokscEQs+/j4sG/fvg0hbz9+/LDb7eaPx8Pc/UKFHlz1L9GkONk+iXQZ9UnwKKApQNIxWyGVtxkV9t7bHsGOyBYAq+3jzGDCCHWIa6C+Jva9ZHs7tWEE25D6CEwDaObu2wDW8/n0XVPZ4/FAkLUBKgTWANK3b9/6x8fHtuuwASy/UOEMT8paSFJzn2WEETjpODK4Bd6PR1GVhT1mZgIUjhdYkt35hOKG3cD7oDVw8pYYdOOYw7AkXXWiwmEbDDpES2Hoqp3ybKfAE/09n8+2R6p2v9/brrdOVIiPPz4+2sfHhz0ej+3xePQRGTliTb2fLErR1e0FjeQB2CLqi7Ix3keefBF5HPZzYQd4JNCVfzRokSmTQDYcbtZU214iMQBiI5G+Daug//5zimSwDS2Ek0AHj2oYn0dk6r0fgn3XVna/3/1+v/fn87kNU3QI+X2bff/+vd/vd3s8HkekvGisiVGYgSoDVEsiT2iyigzsopeQgnbvx/Gqx+PTtgiATQBGelCUwTUGDBxzUxkd6qMByID6DEouaG6iN9VRoO9AQyBhJriBV3VQ4W6EbgJYdr/f++Px2G63G2aJvgNxZJI+wH0CFmc8k2wrjXJIQXBCj9d3s/L0VgDJBcScKJzMIG0BuNJ5FKkuEXCAqxClsowuMi3VYxbiJ62EYAIgDVrrHLH2KIXaagBpRCnctiGwBqD2yLXtUWgAaQAMjdIDgB8fHw4R96yxXgBV5rAfJ1fQravPGumyos8MaALUlwwPwYRCXgGNdZWyDlico/YR9oADAE7uusr20DkHf8r2E8flmAFMh+cbRqjn83lsez6f296NcESpkQkOnXS/3we42g6utkerfr/ffddhbQflQaPj89y9lahwxesKKC0T4XiVSwOTNJLyiDLt1DIdJQS82rYSlSLfaRNU2MAaQOd9i7K9AUb0o0a0IothwzLN8/kc20YmeGis/bUTre1Z4TYi1g4wu91uDr6X7zRruw5rkgoDEKlolUWKCCAVoEURxZSQJ8CYMk5VticikQEFSkc9K/4yeJSOQ0obQh6jFdoSqLcITJ0tBQTT0FXjdbQUIAvsz+ezuXvbW1+s9953CtzAbrDb7dZHlENb4na79cfjsaFFMT5jnI+S3VDcJwJPRG2evB+BEkU4BTKPaJIozIPOAUWBzlEIvxcBS+2LOglFuTM4oeRy2m8/YRdLAbRVH71S6LSzdwUdC0iPB609Hg9398NuGIVnduL3bUcHBEdPM+vTiFWNYBOgWGYh0L6H97MQiZTx6YHYNnDLEUwciYztAlWjE/ttlME5ZXlHJBrWA9b5JhGLHfROADuAhNFrWAoAtpHFdXcfAh47Ghr0YA09tqGRumutkwE7LA4z2xBYUQmkUqbxLCIJY1JRIeopT7SUKUCojI7KMxYArqExySZn1gfFAAs01sm7wmwPTE9JjQCyEaUYZNu+30AYgqcrd33fZxuFZtZYe4RyyBjb7XbroMl8aCoE6gDr+O5fVIE0A0zv3aGJ7wjp+2tH9rJbB6ayqQb+Az8fINn7jxToOCPzSG8RxTXhtl/cdwCnTwT7MR4ELG6oc5HtObnpp/4poJWTFTGi0XjfSO/JAPVdQw2v6jnApOyGYTOAI98AiIdbPxx4LFbvugw7Kw5cfBGV+ik1BtX6qB32orH4GIKO0ZJQ1MmRT1Irl0w4SkJDnZHmMWETXLwxtgYIdJjhdUGF3IhnAJgjGRj6CemPxLtDG8ygvw6txdtOhaOp73gO9oPt4NqGyN8j0jaAOOgSW5VHZOMCOFPhTF8p51s994QOmfqUPvJApB/utqBJRX0bTBy4RC/x/GRaMkgmlsJF3KOFEBidbG4iNSItbnDS0EbAks62U1pD8xTAZgAutBs6UJ7v+2yot0D0H/qLitqnwvnQsFVgqZpd9FxZES0CUKSjqLxigYnJ2VhEmS6EOReAT811rL8WgLXh8Vg3ofWwA+mSNQLINmExdDBFEWRSvA/AjegzBHvkY8H+p6gEYv6IbFjGuUQsprAqLSYgs4mQtwmNeUCfyvl2bo6j6KLc9YstwPvS+0xYAxcdFbjsjaLVoHjpvKPdgJoKAMcaC2fXODbwPZ9PN7OGzvjYd4js4aADiNpuJRwZ6PCp0LLgRIUK7meNNfOZEjBkJRaOVJdSSkSTIqM7rgZBca5qjMpZh6Jw5+iV1fJWtqFews8D7WSsozgqiVrhAEDn/SBadSjpDCAeVEjUeNo2DFLY5rhtHHOPdCNK+U6XGwD/bDfMIlY1WhE4PHHNI4A1dYxAU4XHUIYoHwMjmSpCZ6BT9Dd6pLDTYUxcIJpE6uukqzpMdjhto8cdvKpOvesH3cF+h/OOtIglHnDtj5LOHgEdmgZP+yEFAtuUqLAFnQtyP8iyuMB8WBJgR1yyxgGAkakFwLlENkFpRkLc4AQbgc0n+51oblAOfO4lewQKc4peWFh2ENzOzXy4DaIWuutO7cdD6xx0ho+HVTDEOLxnFKbZUjg04E6Bg2o9MIevdgObo4UIFWmrBuhN9QtrGQQI+EPsVXUVEVkHBd7UpeeKIo8JbYXFYRP2ggmLAT2ok8M+ohmA01QkwuiFpihEqUYRa2Mq3CMNUmFjWtyp7JQtDsCOrHAHU8dmweGZjYwSorSdSjpF6otqgCXARTQ5iUycBQ7dwVkh7yd9LAYaG6WTDHD6GgOL/KqTjUBA6kpjsa1AuoofH5kgPwbnHUE3PCoGXaPCNb5/dDQ4jLFjQpSJ9xmwLAFVn4AtAowFYPGkM8ECC8Gw15wzFirhOLnkTdT4PAIbFIgjMDkbqUizkN1dtou+9Q7PO2WGG7bGoI8VAM0hCrGYd0oAnH0rBBOiKrUbkozPFwA3jWbZZwsgeTKBIXL2I+q1RNzPgHbyvYbmEdmeilJOFsXIFk009xnPA6TuBnyM2grfh1rqpLmoHnn6HlBQvui28b7xOWKisIxYF7tAgKklloGanOBFoLRk1ktEY5445JZkf1GdEBfQkBYD1sXIp7pQoXjM2R33sOO+LcoKdzBjScfJee9QG+SscPRnjcenyIbvo3LQhiCmHvsOLTMW2g0TuptFuAs4lI5SACRwc8lF+VZNUaYQ9TMtZYGQb0Hr8Ba0w1QfH5po2ApCsGMJp2OGBuDBiIVA29DvejwekgrBQkCN5ZCVnqgOaRLXi4DEb5yDlApLYCIxHwnxVyjPgga8GXg8oEDuS3dM8xNKPOk9thCGTqJJppbQX4Pow/sZ2wtAPyb621FjOTb3DbpCehs2whhLbPaDx2pSa4eGANSXijFi8f4GmEyUY6Jow3pHinoB1Ma1uARIDF6mxVeimQVCHP0tg8LyicbAuzpFL9jviF7Q/tKhsH0yQckQ7QAiJyo8KA0jFACpg9vuoiLg6MqTIXpcV6tUaNEMYUVbKu2f7RcBSWR/GTVeQJFto8euwMRZ57hyx7iRWMcGvosgB7P40GVDXOMx0I8S1Gg4E4eywE1RIWaFBJDDx+LskUE2to3pZSozBJDNs8IJpZ0a/9TJ3534sV9pG9sNTE0U9bB/yYVRe9nGrcojonDNUVkUUTSb6SoCz0Ws4zGSbQg6zgLlNnTY99c6l35GZCI6RN13lG6gG3YjmwGXw6xHrGx71uxHK6ZY5G5Tx4EFUUxFPVetLcEyQKps48JB5++EeuJSHcBtrLfAjmg41ii8iU6noKOuBuPno8MBvC+MbidLAnSd4TR/ZWUgaOm8vq6xotphdKJFS0oTGaAFYLKgCM0n10UHQ0aLbFq66HDwaMlF9Rqk2a40VqCrsCW57ye0K/CwxsIeLKKtC90hLY7C86DXPZrhhAvH/i+0Mjh6EQ2ySeqr4l3ZCGo61ax3KrMfPNFHHmgsfu+lyMxLA0WinCjPlaNOkQdLMZfIQ89PugomWaDzPhz1LTipJ10FNgQ+b1w7xONNjn8CJOspFvNUysEVoXONNel8UK3HvmAtmABGRrGtCC7V0WDsSzHdcQE9mFjBFoKiTAvsBiedhfbCKVoCHbH9cBLwAU3iMRCIbCOw/jqKyWhhiPmQp+yXHPe8VhgBYCWyiQxy9tcUpTGNFo7VAi2XUiE77qp7Qbjrp3mHSGdAb5sAlQQFWgoYXiArRKrifixTVoTICtFuONEpRCaHibK8aK7D3Mlxg4JtSbwHLTGhXprNoIkiV9BLlQEwshRc1ASjKV3Sn1JCP8r8gomopuwGKuEgWNhtv1Am05aIRsP34udHBgfgQQCdgKkoEj0tBJT9cVMEEzdPuFLhrDwza/KLAEZzDUfjXybW8X1oSRj3rcMqNU10MKi7MrRoHiF3JYCzfsr88H1oVSC10usnpx7pMrMb4DV23Q93HVeiYRrjKfmDEqF33Uk3Oq0WqHrcj4xY0KCmwqh9Zva3oNOauEOCV8Q7ao/EL1MWA9Of6njgRj4X7cdGRWjpwuNECIpUHkS+jQDNrTKYKXJDIEYsIz8Ko9RGbcUYlRymxWON0Fig49pb4pYpuEqhpsKqYRqUbFINlYh8SXcBeCzyoQJH3YLGPksoMivjXPQW7XeiuERHZRHqoEVw0Lnxj+2Fk/OO1IeuOWZ36HGx5hL7bwxAPK0DjO8AK1vJxSagU4150eKwFpRvLlYA2xFKZwn91YLPOhWTsYwzsxTgdiJhNIs0G0QJg5PEpRvOItEcPYEJdJPNwMMrKw8A9T/C0waAOmmeEcna7+WXksaKIs4sml0AtmgjqC4GGcnUcRSlUshW7noDB91EZuk0+cEFxbONEIl+ZyCJ/YymrV9KQ+TOG82W9ijikuNvgcbEi+k/MPJyVeEljVWIYiH4koJxtmZV1sulsj3LqFFEM349ctRN0aJ6zuBlW6FChaKDAd9zoSRhYLLxqaIXZ5ONi9M4NY1tDl5c1/Jb6r0NrOo2bpO53CcmAODqtkukigCnthGNZVEJqaHT+0KNhdqJhbly14nqTpYFLfxh7HFRDfGizSjCskiX20TUisCV2w3FTFD2ZbGPla02o3rXZ9FsITNUjX6RQGeLIRL6FkyYcCXsxW1LVCZ4cegJOMYOvIq+2Iajoi5aHXa+odPlQsXvwKsfTvR3q4p3dsSz5j++8SJ/KZt0Mlh0jCgaTWgwms4VaQwP9mui/yqNRASyTLybcNeV3trIGe9KwON+ogUGC9enY1BN8RSFqIpwMUrtfOfY17LCpI041EbBzGSV0cmisOipsgJFqrZi9X+kuinTYgJA8jhMd7iUJMyQOQGVTzIDieyGkz4iUc/Oe4dVbzZBh05FZ4/oTznxEljD5c6iUmQrDGc9obGmoh4CZEzFh8YyC3wsizI3Me39otPIdc78rBBYTBViZo4pK0LNI6RtRgC69E+hpQDH3sR0fKepXXwHi4bgIMA79Iixj4WPOxWjrxqrUjuMSjdqra2kPhjZBvgdwvmEAd15ZoKSpSAb1hD4Qo+5yh4ZmFFEEyCRjjyPI/tg4II3QZenLJPAPsZno2LypXKA27MVHVliKLshKwRPxbuKSgkoZRdnRndCw10ojyOiaitOIl00jT6kPWE/lEDF2eOgrsBuiKyHjagLb9WLJR0T9oOLzPVEjQN8SnO11oab31prDu77MErnGqvappzMPK4CzZXADmwJi6Z8BdrsYpAGNcx3gSXFexVkILw70h2e+KGbRNaIgn0LANRoRcBO+25KN4F+6sQiKFcODyu1G16xHxIDVa1Eo1aJ8cmxs2JytGJfVIy2aA6hinJEd0p/+cwgnbjrJhoDjaZfScCDFJH/B72u5kBmcxPUvAE1sfi0ul8UseQUeBLtbRKFZhNTLZh5YyrDg5MrJ66Kx9Iby05M9lwtYzSJYivg2qA+N8vSkO4syBJNUSG56CzAnZr1Tlnh6Mfax+J4PBr9IKot+VgVSyFccDaqNRZn9yhATgGzAKooWqkZOjh3sAUa5ZLdLYLM1DHIrnBlEzAQry93pNcGqwaeqBZ1GtCcUfXkdFqXqTCYfm6VVWMyAEZrZgWWRhM9QKlrn0U1sbAarzBzWbVPTNBwtSQR2wsq26YSUGQtyP0R5ERxFyqcPVa2h8iYnTLSU8Mle5IV5z2cqJoJ74Du1H6WzGbOKLMUkYIZzp5Qps9Ee0XMs3e1Eqn4GJn7zk2EahtMyjhFupHBcXZKrceZu47UucmI9Q4VfvJfZSuE0Yw0oCXlnFRDrWx7RU+xF5WBh+wG1Dboe3UwP7swQtuMFvE1BAr2YkU/qMHUtjKwVrRWBArVnCeOO41YybZoTXYLANlIY83mH34KsKIINekm5ULxBvTEBucmOhTYYO2Be99QsEcRKrMjXrIbXphqP5soMRXyiZg3RasqokW99up4yj4Q/fIl2syi1mT/6cSKV6IprlHBvmCwOLGpIKDmRXCTXykrnAjyCyWpGdAV0CjjM3hPGKHQkpjMal61Ilql0BzpLdHa0oniD8oTC3Hw1HY+tjJSp1SGnQ404/mwFPx8oy2eMCF11ytUyECyqp8ljhFRYaWmmIl4FxHKkt72ioeljMRNZamRcBelGgWWLTBfsU345C0xILhZT0THxmUdpZlGnRCSNxf2g9Rd7zjvLeppd73YbATIMt0FlDa1FqJIJ+qRlixZxHXFavuyqYwz6Yl3VYxG519M0PDo+yYTPGZlL3nBk9OeUWWJCtMidAYK9cWSfipTglropdPxsZk/MTgtG8hKJlh9raK5YKVlhzIQrliTaS+MKEq8MzU20eqy8RQuFO+RG09rjI5WmRaI95LznkYo3xdPE6CoUKFHi3cosKjOhYjiou/AV3kCqtmV3agzIQNXqxSnDe7uEGilMLsTq7+EoEt0Fy9LEFkNNko6YVY4A9ZouptRGO8HzxtZ/5dUO4lYYRbHa55y8Ve1xwRTuySgKDJmIMzmFWYTYC8aCBaNVYYrg0KKegJPn2Sfl/YZO995TYEQI5W9bDcks3iiKFJp+rPA85rpNBOTMyT1ZdqJVgEMPS7XyyCFES1q3OMEYFbsTioIVun7Clx1NYMZP2cjAW/BxInNzjekr9sNb04Bk6I5ocJSVHKx0GxgP6T/C1JhJGgrmip4LqMIZoUFw3QaibDLAxYekTqKoq3KJi/RS0yOUKUcL1PhZ80trHphKvIks3iiWUItiy4V8LzTUrPw+ibm53G/uSfU52w9FKiQPSZTAl2BhyZHRHXCnAor0+SjSDHRR+E6Ddl0MY5Y1W0ZZfp16e1wichkgZGs5TmkqmSbqwkbLC9YqwoAnjRitE1Eqct71HlJlgNQoG7u/jsVvhOhViOYJ2tofWbEUgD8jIj1KlVSppVGpUm2p7apblZ0wtMoJaZ0WVILtGRq/VljfTKwShpL2As+mZg6O36a7U2cd59NvCj6XS3SWMpVT7LHkOKo5SUCYIOJppca6OwYag4h02miuUIqjIDliRHqlanzZEOEWWHi9l8ilrp5wMTNP9FJkFm2QlaYeWxhVljVbOJ3KSuEC5QjVsggOzi6KMifzldrrSeF6OWI1SbT6ytZoru+l2BGhe0zIpZoRmwTz6tNJhfMjiGn2WfbJkDjyNRmVMhzBFgrCfozmEvITvvJfE1o8o+s0Oc3DLBocY+CeJ/tF3VFmOijT8V61NEgDNCmJmEm8w3D4nIwuZUjVIkKwc2faSk1u4n3a5GjruhOtQ2prJDbygVNloDVBAVeXo8yPdHWosxNTzLElgl2MfO5VP5h2npFyE8ojW/FYolgj3RYKwj2BnP9VGRrQv031Fi4YiECRL0naJHREWumsWbZnOtbyVXc9WxF5iZmgmRWwgWoCb2qmUVRd4NP9JYHzr4pLRY0FFo0z4+zWnH/aY9aeFTHBHZJiHmBPjQwfz6v3Ke+47LGyiJV0CLsSYdpEyvMRCc++tzmwXpbijYnAJveVzoo8zTuREhotWXGaBKxGBRIbU3onsox25giDxNlT5ke9MM3YbC2SdRa0lih2A5626OZzjZZlC1qObaJWPcos0sshmmbdHEGUNgZkfTYN+WiD6AyVRKgZsKedZSzrlLgEZJBaimIXNENBNbtBhfLDlWjmxdX96uUgsS8xjbRZekcxSBCSr00KVaXgTabdDKZDGIqeqpedLXOgud3SruMu6JBoj2nx8t2w2UtiFdn6aw+T2ZYS4DNTlTyOWHr8gs98j6ZNCspTFBatB2bBi9ZZXRRctZo55uKXgzW3Xf8/cXf9VdUoLYMWDNB7QUd5olm8SjqqTbjZJ0IOWs6Wj0mWg9iZZbQqxljYkmE0VNZA5HGUtsYJGSOKpo8ZYEIJlHCacqFh225xsoMUdN3hOeTnE4sLYhxD45XmXoW+VHHohXQWhvdE3oGKmcdmCxkEiYK1QQAszkRsXwCzBZotsu5YC2Fj1U7MtwPqZ+A5fkNAaKsrBK50tVrZms3JAuLyAgQbTO9Zle4hGREw4XJr6WW5yxdp0bJTApEU+V4llKLLq7J3ED+Xkc7DGfe8LOV7IZK94Ja4sjyNbCmvV8RKAmIrThP0YNo5gVwHItf0KSNbCGT2WODe0TPoll2T+pTdiZ0WESFFwolf8wpU22ZnhJF6andICNUEm0yYW/ZdHkFSl7hRZmZ6vssAHC6yFtkJ7ygv0K7wa73f7yARzy+lIjUeWMqBM3UAr01Lib2uKaUKrLDuvMujE6vrOOQTXCd7avmrLlYzJ9S3Wx57xBkQdboonzkgQ2hwDKL0O76lnd8k/aQwuiejyEVqpJWQGkRDVZ/1px3RnoAlnQlwEADhTOdg2wuA4O6430YRZJk4aXF3Cy/eVQKas7qmJJEs1/o8NNYuIp6UbSEJQqixr6WWA2SCmW5xvRdvGS0CGgypEX6otFM53BFP/E+lXmqyNGoU7KtmLaFRU3k8YN9WpDVZced0mTCBsp6uFBxpOdIXzXx2vZqEfpIkyEMZ9nd6R8e97UjUSp77llEi6jHt+xNbyhgtM57Eh0vjXmV8g/eQKE6jS6iyaizZDETHrZKmHTtjX3KcR/foQdO+xoVFhr6mpiXl7YsGy3g7ws3MVflC4+X4bbAT4vuPOHqs5NJIWGPF2dukT8nwOau762YabNwfATItqxDlywEFYk2/r8m0WuLgFWxGUoAFNGsfC8dNTMoygotuZcOR6wCjdmsnvnqJF/qXvWZLlNue0WjTVqUXF1QykIItke9WgbA2krAssLdVhO9ZUJQZ9tkCSiaK8hRrgCeyv2r24y+kszykqREyxREYprXlA/GP5y0IRItj7ZlIFNRifcTrTdaY0WaqkJzE701NUhnJ00lCQEwsruQtaQtR1GiKX0XZcSq3x9Ape6tqDJbaTvw+7m7IehAiNgntCCqVkRQOWhlKpwAa+VWKFlkakmWWB5wC27bG2SIL93Z1ea3zCttq1wkynmPji0incxARWRSkccCZ139fZkKU8c40UcZ3aQDLpz/sLZXAJm6OtOLYWX5gJVtxRM/pdkK3RFlVujfo0SENNccWEkEyoCQvged+eL0MC+K2PTkUEZ5cuOD+YvRhaHc9ugv949faI7oFFN5eZfXzPkOdFgUwdOCd8AW2b4hZVbshupKyZXV/ppK+UUnwZQu+OQVqGsq7JPoMt03atku7hutKJ2uv5pF90CUl6IeZ3wiK6zQYY0KZzbDRD+F1FeJNsWsLdNA4Y2eIkG+AKQl8BSpMFpLtfRX7R9kdDITRCciyvyULvtsYL26nQvXK6DhbC2LSrLSb/mtVyyLhivabEWjTcpIUaG/VTUTue8ntx3/CuB07l6ZAQp7tsysZRortQsyWgw0i7+wXxrBJkapnASQNPXNXn/17+zzKxNIZEeE0l7B9LqNvtcmXHd83zaZO5h1Pcw1lriyohM9i0rT6MXiepH+lujzE+julUXnymAU9cyZxOA+9EaNchcao6zPIvqLsmwKEKi//iOkwkRHVeiwqrlUCC6DJaHLyrpdHvRNyWiyApwsSnv9tjBLEVFNfXshqjrNxpK0V9Bfsd1QHUhlAUyc33DwTawFUb3iA41Volo66ThnsXxh8ISRzC2HDojliykzgCsXjZr8gdO2ZvT6VqPf7MQWoluoubIu0iwardb4qE1aDlRB21T2LS/tZGICb9Jq3YQf5rNxy8xhQXkyYwyikE0MUrtErGwyRdKk5wG4wmn4BX1mBZqcgilq3KPHFwO18v6F5QeyMcnqmCt+XoUaS9osiXQp0FJgsTgfwvH3fjyb9rejm7yH+Sk1BS65Rc452gCT99nEeA09rFmf/4rVUJUT1WJ81vxXKIJ70KDHTn8nK2IWnaJt799hddaxUNFfq1d7YOAp8LcJrVc1nK1GjVmnwCSNXynuz8Y9M2952wYRp3x88Tn5vXQy8R2d8IS2ImBYRI8FqktnoVQj0qSNZOkkW2Eyb2G/ENAe30CrelFENGkzGgz0Va6xFoBlBdMzsx+sAMw2+8ez42VC3q7rPFgFdK+8JjRlJTpbpbtDXAipPgoqDyFIFsAUAat9mWUxFe0xEdvlq3ySGEyv6iIgLSiCX6h1ov2y/WRL9IsXxiXlL1BuutbF7DiJLVFx3+tUOANJAZAvAUFllJOBtSJNlibmJu8vj0ehM6Q6HlaRDOyoT4Dq3NIjHHULMsQocmkqTNLRWYSJ/pmVfavcz5liBRQrYCtnigWQTcfrxfctA+mNCzKjWN7+h92QDeCLUWsm6itXepT1hSvYvXhS1bHlehKFx+r/qZysGeVYVqoqHqN8Yb1QeJ5TYeWERf1Z1cczWqtQwgsAj56Xv8vKZ70g9g26S18Z5yVGwGhXAL0XBXxKhauRoBTiI4p9ZUCKgLQKgF8By+Ljy8JmwRKas/F4aayidbImGiuqF8p1Q98GVvZPRxMpOPNKsrCLo6s4vBgRo8FV6028FfU+8z0JMK3yv2ZjIKKTPJYAzyyKaWAVwrP0qWb7FY8XtuNUo1oVeFWRXDhRSyd0Ieq+StcWRN9IXL+roS4rKb+ssYoRbAVAFaBcwLUIIp8BYuVkV9qBXvn/3rhIOBq98v+FUWghQtWpcAYYE1O7FgfOViJCcHWWBi/L0lYo6819qxdgCZQTvfbKxcUyJKPEGQBjKlxMQzM6e2dQl04AaUr1vALiFcCvnECbXQR0wlqwQNzKBZPNE1QgerfB7xRcoog1PakU/lKAvHuyiiG9fKzZSXklYolWlYo9sxLVo/PwKcCOnos7U2QUOaXCtL3lVXAt/OP2Zw3UKuheeT4By2dfiC9duG+MXUv01RxYBYpLwQZNf2NVvsNRV8/Ve2YDhfuLIvClKEz2gnz+DrDwlmxOt2hzccu2NwE6u1iWLnjTyxGkIAqAlmusd8Bm8U0yj31oichsUZHsua1ShSooF6l/etUnd+IwS+Y8zjLOYvTl/1U+V3qouNpQVXed7QabtKysgE3RpLqSKldb9SpNTpjP3le1WCqvBRfa7AKogPnVqJXtUx7HSrQ6LW6b1KaWgFR9TXzJV8BTeQ3D+yVqBO9NFxyrjo8ARBlwn/jadHwqF+KCthqvnanwzcFcAZeKaMvgLAz0pbRUOAGlzymcQCu44y9fNCsAiFzyBQC9Yje0acRaOLnLJz07cew7rZ7kyeBZdVALBfmXx2p1TFZBTp5eNbq/PFbGq828GKHSiLQKxhWQUSZnnzAgqwBafv2dC1QIeV+JrquRsxC9PImAVyqcXYkjZVb7i22n9hnYdnHXs22RNmOHXXzfYQGE08f3z22R6SeuePx8qTnE6+G2JFJE52TFTa9E42XqK7zn7LxPIlBkCagaVmWbXL5xEsGq0c3oam9R1lNJ6YvR6E/ZlnhOKxGqHKWK22ZRrE6FVeAFYCiD5Z3BenfQKlfjnzk2s/cuXmjLY/fu2EyBNRmg0vY3BupdMK0O2lIPeqXHXLnwq/tkOq0KpM+4EBcuuHgyxeIAzsBV3mcCwqV9XgBrKwJ6+eSJIndqylYnRiwAwQoXin/GPvSzXeyGPwsUk5NVOWHVaPUpA754oqvezn/LsQr7sQJgrUwtaoXBWBmUTxucKh28eZVWLsK3x2oFlCsR992xsqi74QWP6t0r8933rAz4CkDfeU8LLJeq1qy8b+WiWAFGaHu8eAG2jArfAcorJ3/1arIXrqxXr8iXxPtqlMre9xkX0rvRbAG8ORV+EsBWuNzeHbDPHLw35cFnSIG3xuGViPxJ0bAOLFrd7+DVVwZahPxy2UCl68k+lcHzxYFtK//fZHw+PZH4BEB68XNnwGpf3g3vq1ffK0nBm9T06VfuvzGb/LOBtGwzFT+3fem9f/n/+c/8Gwa+2X/zn38DSFd//vNL7/3/mtnD/ufnf34+7+df/28AkXg9KZ7Ze3oAAAAASUVORK5CYII=) } ` - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { ColorPicker } from 'primereact/colorpicker'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

ColorPicker is used as a controlled input component with value and onChange properties.

+

+ ColorPicker is used as a controlled input component with value and onChange properties. +

- -{` + + {` setColor(e.value)} /> `} - +
Formats

Default color format to use in value binding is "hex" and other possible values are "rgb" and "hsb". Example below has 3 colorpickers having default values with different formats.

- -{` + + {` setColor1(e.value)} /> setColor2(e.value)} /> setColor3(e.value)}/> `} - +
Properties
-
- +
+
@@ -226,7 +227,9 @@ import { ColorPicker } from 'primereact/colorpicker'; - + @@ -262,15 +265,21 @@ import { ColorPicker } from 'primereact/colorpicker'; - +
NameappendTo DOM element | string document.bodyDOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. + DOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. +
disabledtransitionOptions object nullThe properties of CSSTransition can be customized, except for "nodeRef" and "in" properties. + The properties of{' '} + + CSSTransition + {' '} + can be customized, except for "nodeRef" and "in" properties. +
Events
-
- +
+
@@ -300,8 +309,8 @@ import { ColorPicker } from 'primereact/colorpicker';
Styling

Following is the list of structural style classes

-
-
Name
+
+
@@ -354,110 +363,122 @@ import { ColorPicker } from 'primereact/colorpicker';
Accessibility
- -
Screen Reader
-

Specification does not cover a color picker yet and using a semantic native color picker is not consistent across browsers so currently component is not compatible with screen readers. - In the upcoming versions, text fields will be introduced below the slider section to be able to pick a color using accessible text boxes in hsl, rgba and hex formats.

- -
Closed State Keyboard Support of Popup ColorPicker
-
-
Name
- - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus to the color picker button.
spaceOpens the popup and moves focus to the color slider.
-
- -
Popup Keyboard Support
-
- - - - - - - - - - - - - - - - - - - - - -
KeyFunction
enterSelects the color and closes the popup.
spaceSelects the color and closes the popup.
escapeCloses the popup, moves focus to the input.
-
- -
Color Picker Slider
-
- - - - - - - - - - - - - -
KeyFunction
arrow keysChanges color.
-
- -
Hue Slider
-
- - - - - - - - - - - - - -
KeyFunction
- - up arrow - down arrow - - Changes hue.
-
- + +
Screen Reader
+

+ Specification does not cover a color picker yet and using a semantic native color picker is not consistent across browsers so currently component is not compatible with + screen readers. In the upcoming versions, text fields will be introduced below the slider section to be able to pick a color using accessible text boxes in hsl, rgba and hex formats. +

+ +
Closed State Keyboard Support of Popup ColorPicker
+
+ + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the color picker button.
+ space + Opens the popup and moves focus to the color slider.
+
+ +
Popup Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ enter + Selects the color and closes the popup.
+ space + Selects the color and closes the popup.
+ escape + Closes the popup, moves focus to the input.
+
+ +
Color Picker Slider
+
+ + + + + + + + + + + + + +
KeyFunction
+ arrow keys + Changes color.
+
+ +
Hue Slider
+
+ + + + + + + + + + + + + +
KeyFunction
+ + up arrow + down arrow + + Changes hue.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'ColorPickerDemo', sources: sources, extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'ColorPickerDemo', sources: sources, extFiles: extFiles })}
- ) -}) + ); +}); export default ColorPickerDoc; diff --git a/components/doc/common/developmentsection.js b/components/doc/common/developmentsection.js index 60cd9b41bb..e79767546a 100644 --- a/components/doc/common/developmentsection.js +++ b/components/doc/common/developmentsection.js @@ -4,9 +4,7 @@ export const DevelopmentSection = React.memo((props) => { const isProduction = process.env.NODE_ENV === 'production'; if (isProduction) { - return ( -

This section is under development. After the necessary tests and improvements are made, it will be shared with the users as soon as possible.

- ) + return

This section is under development. After the necessary tests and improvements are made, it will be shared with the users as soon as possible.

; } return props.children; diff --git a/components/doc/common/docactions.js b/components/doc/common/docactions.js index 8131adb32f..3e2f1b69da 100644 --- a/components/doc/common/docactions.js +++ b/components/doc/common/docactions.js @@ -44,7 +44,7 @@ export const DocActions = (props) => { const toggleMenu = (event) => { menu.current.toggle(event); - } + }; const scrollToDocs = () => { const top = DomHandler.getOffset(document.getElementById('app-doc')).top - DomHandler.getOuterHeight(document.getElementsByClassName('layout-topbar')[0], true); @@ -53,38 +53,40 @@ export const DocActions = (props) => { top, behavior: 'smooth' }); - } + }; const viewOnGitHub = () => { window.open('https://github.com/primefaces/primereact/blob/master/pages/' + props.github, '_blank'); - } + }; const viewOnFigma = () => { - if (context.darkTheme) - window.open('https://www.figma.com/file/LJBqVfMpK8xY6KR2KIc8RK/Preview-%7C-Dark-%7C-PrimeOne-2022-%7C-1.0.0?node-id=806%3A36648', '_blank'); - else - window.open('https://www.figma.com/file/c3BuENd8nGcyPmn7ADieee/Preview-%7C-PrimeOne-2022-%7C-1.0.0?node-id=806%3A36648', '_blank'); - } + if (context.darkTheme) window.open('https://www.figma.com/file/LJBqVfMpK8xY6KR2KIc8RK/Preview-%7C-Dark-%7C-PrimeOne-2022-%7C-1.0.0?node-id=806%3A36648', '_blank'); + else window.open('https://www.figma.com/file/c3BuENd8nGcyPmn7ADieee/Preview-%7C-PrimeOne-2022-%7C-1.0.0?node-id=806%3A36648', '_blank'); + }; return ( <> - -
- - - - - -
+ +
+ + + + + +
- ) -} - + ); +}; diff --git a/components/doc/common/liveeditor.js b/components/doc/common/liveeditor.js index 4ba42b8859..f09cab71db 100644 --- a/components/doc/common/liveeditor.js +++ b/components/doc/common/liveeditor.js @@ -9,7 +9,7 @@ const vPrimeReact = '^8.0.0'; // latest let currentProps = {}; const contents = (name, content, imports) => ({ - 'js': `import 'primeicons/primeicons.css'; + js: `import 'primeicons/primeicons.css'; import 'primereact/resources/themes/lara-light-indigo/theme.css'; import 'primereact/resources/primereact.css'; import 'primeflex/primeflex.css'; @@ -19,7 +19,7 @@ ${content} const rootElement = document.getElementById("root"); ReactDOM.render(<${name} />, rootElement);`, - 'browser': ` + browser: ` @@ -61,28 +61,30 @@ export const useLiveEditorTabs = (props) => { const liveEditor = useLiveEditor(); - let extFiles = props.extFiles && Object.entries(props.extFiles).map(([key, value], i) => { - if (key === 'index.css') { - return null; - } + let extFiles = + props.extFiles && + Object.entries(props.extFiles).map(([key, value], i) => { + if (key === 'index.css') { + return null; + } - const lang = key.indexOf('.css') !== -1 ? 'css' : 'js'; - return ( - -{` + const lang = key.indexOf('.css') !== -1 ? 'css' : 'js'; + return ( + + {` /* ${key.replace('demo/', '')} */ `} - {value.content} - - ) - }); + {value.content} + + ); + }); let ordered_sources = { - 'hooks': { ...props.sources.hooks }, - 'class': { ...props.sources.class }, - 'ts': { ...props.sources.ts }, - 'browser': {...props.sources.browser} - } + hooks: { ...props.sources.hooks }, + class: { ...props.sources.class }, + ts: { ...props.sources.ts }, + browser: { ...props.sources.browser } + }; let tabs = Object.entries(ordered_sources).map(([key, value]) => { const { content: _c, imports: _i } = value; @@ -91,13 +93,11 @@ export const useLiveEditorTabs = (props) => { return ( {/* eslint-disable */} - liveEditor.postSandboxParameters(key)}> + liveEditor.postSandboxParameters(key)}> Edit in CodeSandbox {/* eslint-enable */} - - {content} - + {content} {extFiles} @@ -105,34 +105,32 @@ export const useLiveEditorTabs = (props) => { }); if (props.service) { - const serviceArr = props.service.replace(/\s/g,'').split(','); + const serviceArr = props.service.replace(/\s/g, '').split(','); serviceArr.forEach((s, i) => { tabs.push( - - {services[s]} - - * This code is different for the 'Browser Source'. + {services[s]} + * This code is different for the 'Browser Source'. - ) + ); }); } if (props.data) { - const dataArr = props.data.replace(/\s/g,'').split(','); + const dataArr = props.data.replace(/\s/g, '').split(','); dataArr.forEach((d, i) => { tabs.push( - + {data[d]} - ) + ); }); } return tabs; -} +}; export const useLiveEditor = () => { const props = currentProps; @@ -144,7 +142,7 @@ export const useLiveEditor = () => { delete _extFiles['index.css']; let extFiles = {}; - Object.entries(_extFiles).forEach(([k, v]) => extFiles[`${rootPath}${k}`] = v); + Object.entries(_extFiles).forEach(([k, v]) => (extFiles[`${rootPath}${k}`] = v)); const dependencies = pkg ? pkg.dependencies : {}; @@ -153,20 +151,23 @@ export const useLiveEditor = () => { 'package.json': { content: { main: `${rootPath}demo/${nameWithExt}`, - dependencies: isBrowser ? {} : { - ...extDependencies, - 'react': dependencies['react'], - 'react-dom': dependencies['react-dom'], - 'react-transition-group': dependencies['react-transition-group'], - 'primereact': vPrimeReact, // latest - 'primeflex': dependencies['primeflex'], - 'primeicons': dependencies['primeicons'] - } + dependencies: isBrowser + ? {} + : { + ...extDependencies, + react: dependencies['react'], + 'react-dom': dependencies['react-dom'], + 'react-transition-group': dependencies['react-transition-group'], + primereact: vPrimeReact, // latest + primeflex: dependencies['primeflex'], + primeicons: dependencies['primeicons'] + } } }, 'index.html': { - content: isBrowser ? `` : - `
+ content: isBrowser + ? `` + : `
` @@ -372,12 +373,12 @@ img.flag { width:30px } ${extIndexCSS} - `, + ` }, ...files, ...extFiles } - } + }; }; const getSandboxParameters = (sourceType) => { @@ -396,21 +397,19 @@ ${extIndexCSS} _files[`sandbox.config.json`] = { content: { - "infiniteLoopProtection": false + infiniteLoopProtection: false } - } + }; if (sourceType === 'class' || sourceType === 'hooks') { extension = serviceExtension = '.js'; content = js; - } - else if (sourceType === 'ts') { + } else if (sourceType === 'ts') { extension = serviceExtension = '.tsx'; content = js; _files[`tsconfig.json`] = { - content: - `{ + content: `{ "compilerOptions": { "target": "es5", "lib": [ @@ -435,20 +434,19 @@ ${extIndexCSS} "src" ] }` - } + }; extDependencies = { ...extDependencies, - "@types/node": "10.12.24", - "@types/react": "16.8.2", - "@types/react-dom": "16.8.0", - "@types/react-transition-group": "^4.2.4", - "@types/classnames": "^2.2.10", - "react-scripts": "2.1.3", - "typescript": "3.3.3" - } - } - else if (sourceType === 'browser') { + '@types/node': '10.12.24', + '@types/react': '16.8.2', + '@types/react-dom': '16.8.0', + '@types/react-transition-group': '^4.2.4', + '@types/classnames': '^2.2.10', + 'react-scripts': '2.1.3', + typescript: '3.3.3' + }; + } else if (sourceType === 'browser') { extension = '.html'; content = browser; rootPath = ''; @@ -458,52 +456,52 @@ ${extIndexCSS} _files[`${rootPath}demo/${name}${extension}`] = { content - } + }; if (props.service) { - const serviceArr = props.service.replace(/\s/g,'').split(','); - serviceArr.forEach(s => { + const serviceArr = props.service.replace(/\s/g, '').split(','); + serviceArr.forEach((s) => { const path = `${rootPath}${sourceType === 'browser' ? 'demo' : 'service'}/${s}${serviceExtension}`; const content = sourceType === 'browser' ? services[s].replace('export class', 'class') : services[s]; _files[path] = { content - } + }; }); } if (props.data) { - const dataArr = props.data.replace(/\s/g,'').split(','); - dataArr.forEach(d => { + const dataArr = props.data.replace(/\s/g, '').split(','); + dataArr.forEach((d) => { const path = `${sourceType === 'browser' ? 'demo' : 'public'}/data/${d}.json`; const content = data[d]; _files[path] = { content - } + }; }); } return createSandboxParameters(`${name}${extension}`, _files, extDependencies, sourceType, rootPath); - } + }; return { postSandboxParameters(sourceType, toast) { const sandboxParameters = getSandboxParameters(sourceType); if (!sandboxParameters) { - toast.current.show({severity: 'warn', summary: 'Not Available', detail: 'That code sandbox demonstration is not available!'}); + toast.current.show({ severity: 'warn', summary: 'Not Available', detail: 'That code sandbox demonstration is not available!' }); return; } fetch('https://codesandbox.io/api/v1/sandboxes/define?json=1', { - method: "POST", + method: 'POST', headers: { 'Content-Type': 'application/json', - 'Accept': 'application/json' + Accept: 'application/json' }, body: JSON.stringify(sandboxParameters) }) - .then(response => response.json()) - .then(data => window.open(`https://codesandbox.io/s/${data.sandbox_id}`, '_blank')); + .then((response) => response.json()) + .then((data) => window.open(`https://codesandbox.io/s/${data.sandbox_id}`, '_blank')); } - } -} + }; +}; diff --git a/components/doc/common/liveeditordata.js b/components/doc/common/liveeditordata.js index b1da15b45b..3029e3af78 100644 --- a/components/doc/common/liveeditordata.js +++ b/components/doc/common/liveeditordata.js @@ -1,5 +1,5 @@ const services = { - 'CountryService': ` + CountryService: ` export class CountryService { getCountries() { @@ -8,7 +8,7 @@ export class CountryService { } } `, - 'CustomerService': ` + CustomerService: ` export class CustomerService { getCustomersSmall() { @@ -37,7 +37,7 @@ export class CustomerService { } } `, - 'EventService': ` + EventService: ` export class EventService { getEvents() { @@ -46,7 +46,7 @@ export class EventService { } } `, - 'NodeService': ` + NodeService: ` export class NodeService { getTreeTableNodes() { @@ -60,7 +60,7 @@ export class NodeService { } } `, - 'PhotoService': ` + PhotoService: ` export class PhotoService { getImages() { @@ -69,7 +69,7 @@ export class PhotoService { } } `, - 'ProductService': ` + ProductService: ` export class ProductService { getProductsSmall() { @@ -85,7 +85,7 @@ export class ProductService { } } `, - 'CarService': ` + CarService: ` export class CarService { brands = ['Vapid', 'Carson', 'Kitano', 'Dabver', 'Ibex', 'Morello', 'Akira', 'Titan', 'Dover', 'Norma']; @@ -126,10 +126,10 @@ export class CarService { } } ` -} +}; const data = { - 'countries': ` + countries: ` { "data": [ {"name": "Afghanistan", "code": "AF"}, @@ -378,7 +378,7 @@ const data = { ] } `, - 'events': ` + events: ` { "data": [ {"id": 1,"title": "All Day Event","start": "2017-02-01"}, @@ -396,7 +396,7 @@ const data = { ] } `, - 'photos': ` + photos: ` { "data":[ {"itemImageSrc": "images/galleria/galleria1.jpg","thumbnailImageSrc": "images/galleria/galleria1s.jpg","alt": "Description for Image 1","title": "Title 1"}, @@ -417,7 +417,7 @@ const data = { ] } `, - 'treenodes': ` + treenodes: ` { "root": [ { @@ -473,7 +473,7 @@ const data = { ] } `, - 'treetablenodes': ` + treetablenodes: ` { "root": [ @@ -13532,7 +13532,7 @@ const data = { ] } `, - 'products': ` + products: ` { "data": [ {"id": "1000","code": "f230fh0g3","name": "Bamboo Watch","description": "Product Description","image": "bamboo-watch.jpg","price": 65,"category": "Accessories","quantity": 24,"inventoryStatus": "INSTOCK","rating": 5}, @@ -13635,7 +13635,7 @@ const data = { {"id": "1009","code": "cm230f032","name": "Gaming Set","description": "Product Description","image": "gaming-set.jpg","price": 299,"category": "Electronics","quantity": 63,"inventoryStatus": "INSTOCK","rating": 3,"orders": [{"id": "10000","productCode": "cm230f032","date": "2020-06-24","amount": 299,"quantity": 1,"customer": "Kadeem Mujtaba","status": "PENDING"},{"id": "10001","productCode": "cm230f032","date": "2020-05-11","amount": 299,"quantity": 1,"customer": "Ashley Wickens","status": "DELIVERED"},{"id": "10002","productCode": "cm230f032","date": "2019-02-07","amount": 299,"quantity": 1,"customer": "Julie Johnson","status": "DELIVERED"},{"id": "10003","productCode": "cm230f032","date": "2020-04-26","amount": 299,"quantity": 1,"customer": "Tony Costa","status": "CANCELLED"}]} ] } - `, -} + ` +}; export { services, data }; diff --git a/components/doc/confirmdialog/index.js b/components/doc/confirmdialog/index.js index 78d4c27574..176b72beb8 100644 --- a/components/doc/confirmdialog/index.js +++ b/components/doc/confirmdialog/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const ConfirmDialogDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -113,7 +112,7 @@ export class ConfirmDialogDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState, useRef } from 'react'; @@ -204,7 +203,7 @@ const ConfirmDialogDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState, useRef } from 'react'; @@ -295,7 +294,7 @@ const ConfirmDialogDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -390,35 +389,37 @@ const ConfirmDialogDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { ConfirmDialog } from 'primereact/confirmdialog'; // To use tag import { confirmDialog } from 'primereact/confirmdialog'; // To use confirmDialog method `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

There are two ways to display confirm dialog. One of them is to use the confirmDialog method and the other is to use the <ConfirmDialog> tag. - These independently create dialog element. It supports the same properties in both.

+

+ There are two ways to display confirm dialog. One of them is to use the confirmDialog method and the other is to use the <ConfirmDialog> tag. These independently create dialog element. It supports the same + properties in both. +

1. confirmDialog method
- -{` + + {` const confirm = () => { confirmDialog({ message: 'Are you sure you want to proceed?', @@ -432,33 +433,37 @@ const confirm = () => { `} - +
2. <ConfirmDialog> tag
-

ConfirmDialog is used as a container and visibility is managed with visible property where onHide event is required to update the visibility state.

+

+ ConfirmDialog is used as a container and visibility is managed with visible property where onHide event is required to update the visibility state. +

- -{` + + {` setVisible(false)} message="Are you sure you want to proceed?" header="Confirmation" icon="pi pi-exclamation-triangle" accept={accept} reject={reject} />
- ) -}) + ); +}); export default ConfirmDialogDoc; diff --git a/components/doc/confirmpopup/index.js b/components/doc/confirmpopup/index.js index b609885fdb..7e0abd8c78 100644 --- a/components/doc/confirmpopup/index.js +++ b/components/doc/confirmpopup/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const ConfirmPopupDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -83,7 +82,7 @@ export class ConfirmPopupDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState, useRef } from 'react'; @@ -145,7 +144,7 @@ const ConfirmPopupDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState, useRef } from 'react'; @@ -206,8 +205,8 @@ const ConfirmPopupDemo = () => { ) } ` - }, - 'browser': { + }, + browser: { tabName: 'Browser Source', imports: ` @@ -273,35 +272,37 @@ const ConfirmPopupDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { ConfirmPopup } from 'primereact/confirmpopup'; // To use tag import { confirmPopup } from 'primereact/confirmpopup'; // To use confirmPopup method `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

There are two ways to display confirm popup. One of them is to use the confirmPopup method and the other is to use the <ConfirmPopup> tag. - These independently create popup element. It supports the same properties in both. target property is mandatory to align the popup to its caller.

+

+ There are two ways to display confirm popup. One of them is to use the confirmPopup method and the other is to use the <ConfirmPopup> tag. These independently create popup element. It supports the same + properties in both. target property is mandatory to align the popup to its caller. +

1. confirmPopup method
- -{` + + {` const confirm = (event) => { confirmPopup({ target: event.currentTarget, @@ -314,11 +315,13 @@ const confirm = (event) => { `} - -

The confirmPopup method returns an object incudes hide and show methods. The component can be shown or hidden by using this object at any time.

+
+

+ The confirmPopup method returns an object incudes hide and show methods. The component can be shown or hidden by using this object at any time. +

- -{` + + {` const confirm = (event) => { const myConfirm = confirmPopup({ target: event.currentTarget, @@ -340,22 +343,24 @@ const confirm = (event) => { `} - +
2. <ConfirmPopup> tag
-

ConfirmPopup is used as a container and visibility is managed with visible property where onHide event is required to update the visibility state.

+

+ ConfirmPopup is used as a container and visibility is managed with visible property where onHide event is required to update the visibility state. +

- -{` + + {` setVisible(false)} message="Are you sure you want to proceed?" icon="pi pi-exclamation-triangle" accept={accept} reject={reject} />
- ) -}) + ); +}); export default ConfirmPopupDoc; diff --git a/components/doc/contextmenu/index.js b/components/doc/contextmenu/index.js index 3ae12304f2..bfd134ecff 100644 --- a/components/doc/contextmenu/index.js +++ b/components/doc/contextmenu/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const ContextMenuDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -165,7 +164,7 @@ export class ContextMenuDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useRef } from 'react'; @@ -316,7 +315,7 @@ const ContextMenuDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useRef } from 'react'; @@ -467,7 +466,7 @@ const ContextMenuDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -621,34 +620,36 @@ const ContextMenuDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { ContextMenu } from 'primereact/contextmenu'; `} - +
Import via CDN
- -{` + + {` `} - +
MenuItem API
-

ContextMenu uses the common menu item api to define its items, visit MenuModel for details.

+

+ ContextMenu uses the common menu item api to define its items, visit MenuModel for details. +

Getting Started

Menu requires a collection of menuitems as its model.

- -{` + + {` const items = [ { label:'File', @@ -781,37 +782,36 @@ const items = [ } ]; `} - + - -{` + + {` `} - +
Document Menu

Setting global property attaches the context menu to the document.

- - -{` + + {` `} - +
Element Menu

ContextMenu is attached to a custom element manually using the reference and calling the show(event) method.

- -{` + + {` Logo cm.current.show(e)}/> `} - +
Properties
-
- +
+
@@ -867,21 +867,29 @@ const items = [ - + - +
NameappendTo DOM element | string document.bodyDOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. + DOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. +
transitionOptions object nullThe properties of CSSTransition can be customized, except for "nodeRef" and "in" properties. + The properties of{' '} + + CSSTransition + {' '} + can be customized, except for "nodeRef" and "in" properties. +
Methods
-
- +
+
@@ -905,8 +913,8 @@ const items = [
Events
-
-
Name
+
+
@@ -930,9 +938,11 @@ const items = [
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -970,77 +980,97 @@ const items = [
Accessibility
-
Screen Reader
-

ContextMenu component uses the menubar role with aria-orientation set to "vertical" and the value to describe the menu can either be provided with aria-labelledby or aria-label props. Each list item has a presentation role - whereas anchor elements have a menuitem role with aria-label referring to the label of the item and aria-disabled defined if the item is disabled. A submenu within a ContextMenu uses the menu role with an aria-labelledby defined - as the id of the submenu root menuitem label. In addition, menuitems that open a submenu have aria-haspopup, aria-expanded and aria-controls to define the relation between the item and the submenu.

+
Screen Reader
+

+ ContextMenu component uses the menubar role with aria-orientation set to "vertical" and the value to describe the menu can either be provided with aria-labelledby or aria-label props. Each list + item has a presentation role whereas anchor elements have a menuitem role with aria-label referring to the label of the item and aria-disabled defined if the item is disabled. A submenu within a + ContextMenu uses the menu role with an aria-labelledby defined as the id of the submenu root menuitem label. In addition, menuitems that open a submenu have aria-haspopup, aria-expanded and{' '} + aria-controls to define the relation between the item and the submenu. +

-
Keyboard Support
-
-
Name
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyFunction
tabWhen focus is in the menu, closes the context menu and moves focus to the next focusable element in the page sequence.
enterIf menuitem has a submenu, toggles the visibility of the submenu otherwise activates the menuitem and closes all open overlays.
spaceIf menuitem has a submenu, toggles the visibility of the submenu otherwise activates the menuitem and closes all open overlays.
escapeCloses the context menu.
down arrowIf focus is not inside the menu and menu is open, add focus to the first item. If an item is already focused, moves focus to the next menuitem within the submenu.
up arrowIf focus is not inside the menu and menu is open, add focus to the last item. If an item is already focused, moves focus to the next menuitem within the submenu.
right arrowOpens a submenu if there is one available and moves focus to the first item.
left arrowCloses a submenu and moves focus to the root item of the closed submenu.
homeMoves focus to the first menuitem within the submenu.
endMoves focus to the last menuitem within the submenu.
-
- +
Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + When focus is in the menu, closes the context menu and moves focus to the next focusable element in the page sequence.
+ enter + If menuitem has a submenu, toggles the visibility of the submenu otherwise activates the menuitem and closes all open overlays.
+ space + If menuitem has a submenu, toggles the visibility of the submenu otherwise activates the menuitem and closes all open overlays.
+ escape + Closes the context menu.
+ down arrow + If focus is not inside the menu and menu is open, add focus to the first item. If an item is already focused, moves focus to the next menuitem within the submenu.
+ up arrow + If focus is not inside the menu and menu is open, add focus to the last item. If an item is already focused, moves focus to the next menuitem within the submenu.
+ right arrow + Opens a submenu if there is one available and moves focus to the first item.
+ left arrow + Closes a submenu and moves focus to the root item of the closed submenu.
+ home + Moves focus to the first menuitem within the submenu.
+ end + Moves focus to the last menuitem within the submenu.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'ContextMenuDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'ContextMenuDemo', sources: sources })}
- ) - -}) + ); +}); export default ContextMenuDoc; diff --git a/components/doc/datascroller/index.js b/components/doc/datascroller/index.js index 841c21e5e7..76a26a9bcd 100644 --- a/components/doc/datascroller/index.js +++ b/components/doc/datascroller/index.js @@ -5,9 +5,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const DataScrollerDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -66,7 +65,7 @@ export class DataScrollerDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState, useEffect } from 'react'; @@ -114,7 +113,7 @@ const DataScrollerDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState, useEffect } from 'react'; @@ -162,7 +161,7 @@ const DataScrollerDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -215,7 +214,7 @@ const DataScrollerDemo = () => { } ` } - } + }; const extFiles = { 'demo/DataScrollerDemo.css': { @@ -310,76 +309,81 @@ const DataScrollerDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { DataScroller } from 'primereact/datascroller'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

DataScroller requires a collection of items as its value, number of rows to load and a template content to display. Here is a sample DataScroller that displays a - list of cars where each load event adds 10 more rows if available.

- -{` +

+ DataScroller requires a collection of items as its value, number of rows to load and a template content to display. Here is a sample DataScroller that displays a list of cars where each load event adds 10 more rows if + available. +

+ + {` `} - - - {` + + + {` const itemTemplate = (item) => { // custom item content } `} - +
Inline
-

By default DataScroller listens to the scroll event of window, the alternative is the inline mode where container of the DataScroller element itself is used as the event target. Set inline option to true to enable this mode.

- - {` +

+ By default DataScroller listens to the scroll event of window, the alternative is the inline mode where container of the DataScroller element itself is used as the event target. Set inline option to true to enable this + mode. +

+ + {` `} - +
Lazy Loading
-

Lazy mode is handy to deal with large datasets, instead of loading the entire data, small chunks of data is loaded by invoking - onLazyLoad callback everytime paging happens. To implement lazy loading, - enable lazy property and provide a method callback using onLazyLoad that actually loads the data from a remote datasource. onLazyLoad gets an event object - that contains information about what to load.

+

+ Lazy mode is handy to deal with large datasets, instead of loading the entire data, small chunks of data is loaded by invoking onLazyLoad callback everytime paging happens. To implement lazy loading, enable lazy{' '} + property and provide a method callback using onLazyLoad that actually loads the data from a remote datasource. onLazyLoad gets an event object that contains information about what to load. +

- - {` + + {` `} - + - -{` + + {` const loadData = (event) => { //event.first = First row offset //event.rows = Number of rows per page //add more records to the cars array } `} - +
Properties
-
- +
+
@@ -472,8 +476,8 @@ const loadData = (event) => {
Events
-
-
Name
+
+
@@ -484,8 +488,10 @@ const loadData = (event) => { - + @@ -494,8 +500,8 @@ const loadData = (event) => {
Styling

Following is the list of structural style classes

-
-
Name
onLazyLoadevent.first = First row offset
- event.rows = Number of rows per page
+ event.first = First row offset
+ event.rows = Number of rows per page
+
Callback to invoke in lazy mode to load new data.
+
+
@@ -529,26 +535,24 @@ const loadData = (event) => {
Accessibility
-
Screen Reader
-

DataScroller uses a semantic list element to list the items. No specific role is enforced, still you may use any aria role and attributes - as any valid attribute is passed to the container element. List element can be also customized for accessibility using listProps property. -

+
Screen Reader
+

+ DataScroller uses a semantic list element to list the items. No specific role is enforced, still you may use any aria role and attributes as any valid attribute is passed to the container element. List element can be also + customized for accessibility using listProps property. +

-
Keyboard Support
-

Component does not include any built-in interactive elements.

+
Keyboard Support
+

Component does not include any built-in interactive elements.

-
Dependencies
-

None.

+
Dependencies
+

None.

- - { - useLiveEditorTabs({ name: 'DataScrollerDemo', sources: sources, service: 'ProductService', data: 'products', extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'DataScrollerDemo', sources: sources, service: 'ProductService', data: 'products', extFiles: extFiles })} ); -}) +}); export default DataScrollerDoc; diff --git a/components/doc/datatable/index.js b/components/doc/datatable/index.js index 9bc252c6b1..5677533c1b 100644 --- a/components/doc/datatable/index.js +++ b/components/doc/datatable/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const DataTableDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -249,7 +248,7 @@ export class DataTableDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState, useEffect } from 'react'; @@ -467,7 +466,7 @@ const DataTableDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState, useEffect } from 'react'; @@ -685,7 +684,7 @@ const DataTableDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -911,7 +910,7 @@ const DataTableDemo = () => { } ` } - } + }; const extFiles = { 'demo/DataTableDemo.css': { @@ -948,35 +947,37 @@ const DataTableDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { DataTable } from 'primereact/datatable'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

DataTable requires a value as an array of objects and columns defined with Column component. Throughout the samples, a product interface having code, name, description, image, category, quantity, price, inventoryStatus and rating properties is used to define an object to be displayed by the datatable. - Products are loaded by a CustomerService that connects to a server to fetch the products. Note that this is only for demo purposes, DataTable does not have any restrictions on how data is provided. +

+ DataTable requires a value as an array of objects and columns defined with Column component. Throughout the samples, a product interface having code, name, description, image, category, quantity, price, inventoryStatus and + rating properties is used to define an object to be displayed by the datatable. Products are loaded by a CustomerService that connects to a server to fetch the products. Note that this is only for demo purposes, DataTable does + not have any restrictions on how data is provided.

- -{` + + {` export default class ProductService { getProductsSmall() { @@ -992,11 +993,11 @@ export default class ProductService { } } `} - +

Following sample datatable has 4 columns and retrieves the data from a service on componentDidMount.

- - {` + + {` export const DataTableDemo = () => { const [products, setProducts] = useState([]) @@ -1017,11 +1018,11 @@ export const DataTableDemo = () => { } `} - +

Dynamic columns are also possible by creating the column component dynamically.

- -{` + + {` export const DataTableDemo = () => { const [products, setProducts] = useState([]); @@ -1049,14 +1050,14 @@ export const DataTableDemo = () => { ); } `} - +
Column Component

Column component defines various options to specify corresponding features.

Properties
-
-
Name
+
+
@@ -1515,17 +1516,20 @@ export const DataTableDemo = () => {
Table Layout
-

Default table-layout is fixed meaning the cell widths do not depend on their content. If you require cells to scale based on their contents - set autoLayout property to true. Note that Scrollable and/or Resizable tables do not support auto layout due to technical limitations. +

+ Default table-layout is fixed meaning the cell widths do not depend on their content. If you require cells to scale based on their contents set autoLayout property to true. Note that Scrollable and/or Resizable tables + do not support auto layout due to technical limitations.

Templates
-

Field data of a corresponding row is displayed as the cell content by default, this can be customized using templating where current row data and column properties are passed to the body template. - On the other hand, header and footer properties of a column are used to define the content of these sections by accepting either simple string values or JSX for advanced content. Similarly DataTable itself - also provides header and footer properties for the main header and footer of the table.

+

+ Field data of a corresponding row is displayed as the cell content by default, this can be customized using templating where current row data and column properties are passed to the body template. On the other hand,{' '} + header and footer properties of a column are used to define the content of these sections by accepting either simple string values or JSX for advanced content. Similarly DataTable itself also provides{' '} + header and footer properties for the main header and footer of the table. +

- -{` + + {` export const DataTableTemplatingDemo = () => { const [products, setProducts] = useState([]) @@ -1576,13 +1580,13 @@ export const DataTableTemplatingDemo = () => { } `} - +
Size

In addition to the regular table, a smal and a large version are available with different paddings.

- -{` + + {` @@ -1604,13 +1608,15 @@ export const DataTableTemplatingDemo = () => { `} - +
Column Group
-

Columns can be grouped at header and footer sections by defining a ColumnGroup component as the headerColumnGroup and footerColumnGroup properties.

+

+ Columns can be grouped at header and footer sections by defining a ColumnGroup component as the headerColumnGroup and footerColumnGroup properties. +

- - {` + + {` import React, { Component } from 'react'; import {DataTable} from 'primereact/datatable'; import {Column} from 'primereact/column'; @@ -1705,17 +1711,21 @@ export const DataTableColGroupDemo = () => { ); } `} - +

When using sorting with column groups, define sort properties like sortable at columns inside column groups not at the direct children of DataTable component.

Pagination
-

Pagination is enabled by setting paginator property to true, rows property defines the number of rows per page and optionally pageLinks specify the the number of page links to display. - See paginator component for more information about further customization options such as paginator template.

+

+ Pagination is enabled by setting paginator property to true, rows property defines the number of rows per page and optionally pageLinks specify the the number of page links to display. See{' '} + paginator component for more information about further customization options such as paginator template. +

-

Pagination can either be used in Controlled or Uncontrolled manner. In controlled mode, first and onPage properties need to be defined to control the paginator state.

- -{` +

+ Pagination can either be used in Controlled or Uncontrolled manner. In controlled mode, first and onPage properties need to be defined to control the paginator state. +

+ + {` export const DataTablePaginatorDemo = () => { const [products, setProducts] = useState([]); @@ -1736,12 +1746,14 @@ export const DataTablePaginatorDemo = () => { ); } `} - +
-

In uncontrolled mode, only paginator and rows need to be enabled. Index of the first record can be still be provided using the first property in uncontrolled mode however - it is evaluated at initial rendering and ignored in further updates. If you programmatically need to update the paginator state, prefer to use the component as controlled.

- -{` +

+ In uncontrolled mode, only paginator and rows need to be enabled. Index of the first record can be still be provided using the first property in uncontrolled mode however it is evaluated at initial + rendering and ignored in further updates. If you programmatically need to update the paginator state, prefer to use the component as controlled. +

+ + {` export const DataTablePaginatorDemo = () => { const [products, setProducts] = useState([]); @@ -1761,11 +1773,13 @@ export const DataTablePaginatorDemo = () => { ); } `} - +
-

Elements of the paginator can be customized using the paginatorTemplate by the DataTable. Refer to the template section of the paginator documentation for further options.

- -{` +

+ Elements of the paginator can be customized using the paginatorTemplate by the DataTable. Refer to the template section of the paginator documentation for further options. +

+ + {` @@ -1774,37 +1788,42 @@ export const DataTablePaginatorDemo = () => { `} - +
Sorting
-

Enabling sortable property at column component would be enough to make a column sortable. The property to use when sorting is field by default and can be customized using sortField.

- -{` +

+ Enabling sortable property at column component would be enough to make a column sortable. The property to use when sorting is field by default and can be customized using sortField. +

+ + {` `} - +
-

By default sorting is executed on the clicked column only. To enable multiple field sorting, set sortMode property to "multiple" and use metakey when clicking on another column.

- -{` +

+ By default sorting is executed on the clicked column only. To enable multiple field sorting, set sortMode property to "multiple" and use metakey when clicking on another column. +

+ + {` `} - +
+

+ In case you'd like to display the table as sorted per a single column by default on mount, use sortField and sortOrder properties in Controlled or Uncontrolled manner. In controlled mode,{' '} + sortField, sortOrder and onSort properties need to be defined to control the sorting state. +

-

In case you'd like to display the table as sorted per a single column by default on mount, use sortField and sortOrder properties in Controlled or Uncontrolled manner. - In controlled mode, sortField, sortOrder and onSort properties need to be defined to control the sorting state.

- - -{` + + {` const onSort = (e) => { setSortField(e.sortField); setSortOrder(e.sortOrder); } `} - - - {` + + + {` @@ -1812,11 +1831,13 @@ const onSort = (e) => { `} - + -

In multiple mode, use the multiSortMeta property and bind an array of SortMeta objects instead.

- -{` +

+ In multiple mode, use the multiSortMeta property and bind an array of SortMeta objects instead. +

+ + {` setMultiSortMeta(e.multiSortMeta)}> @@ -1824,21 +1845,23 @@ const onSort = (e) => { `} - +
- -{` + + {` let multiSortMeta = []; multiSortMeta.push({field: 'code', order: 1}); multiSortMeta.push({field: 'name', order: -1}); `} - + -

In uncontrolled mode, no additional properties need to be enabled. Initial sort field can be still be provided using the sortField property in uncontrolled mode however - it is evaluated at initial rendering and ignored in further updates. If you programmatically need to update the sorting state, prefer to use the component as controlled.

+

+ In uncontrolled mode, no additional properties need to be enabled. Initial sort field can be still be provided using the sortField property in uncontrolled mode however it is evaluated at initial rendering and ignored + in further updates. If you programmatically need to update the sorting state, prefer to use the component as controlled. +

- -{` + + {` @@ -1846,11 +1869,11 @@ multiSortMeta.push({field: 'name', order: -1}); `} - +

To customize sorting algorithm, define a sortFunction that sorts the list.

- -{` + + {` @@ -1858,20 +1881,22 @@ multiSortMeta.push({field: 'name', order: -1}); `} - + - -{` + + {` const mysort = (event) => { //event.field = Field to sort //event.order = Sort order } `} - + -

Getting access to the sorted data is provided by the onValueChange callback.

- -{` +

+ Getting access to the sorted data is provided by the onValueChange callback. +

+ + {` console.log(sortedData)}> @@ -1879,16 +1904,17 @@ const mysort = (event) => { `} - +
Filtering
-

DataTable has advanced filtering capabilities that does the heavy lifting while providing flexible customization. Filtering has two layout alternatives defined with the filterDisplay. - In row setting, filter elements are displayed in a separate row at the header section whereas - in menu mode filter elements are displayed inside an overlay. The template filter gets a value, filterCallback and filterApplyCallback, - use value to populate the filter with your own form components and call the filterCallback with the event of your choice like onInput, onChange, onClick. - FilterCallback adds new values in hidden 'filters' state in DataTable and when filterApplyCallback is called, data is filtered. The filterApplyCallback method can be used directly if you want to filter by value directly.

- -{` +

+ DataTable has advanced filtering capabilities that does the heavy lifting while providing flexible customization. Filtering has two layout alternatives defined with the filterDisplay. In row setting, filter + elements are displayed in a separate row at the header section whereas in menu mode filter elements are displayed inside an overlay. The template filter gets a value, filterCallback and{' '} + filterApplyCallback, use value to populate the filter with your own form components and call the filterCallback with the event of your choice like onInput, onChange, onClick. FilterCallback adds new values in hidden + 'filters' state in DataTable and when filterApplyCallback is called, data is filtered. The filterApplyCallback method can be used directly if you want to filter by value directly. +

+ + {` const DataTableFilterDemo = () => { const [customers, setCustomers] = useState(null); const filters = { @@ -1902,44 +1928,43 @@ const DataTableFilterDemo = () => { ) } `} - +
Filter Row

Input field is displayed in a separate header row.

- -{` + + {` `} - +
Filter Menu

Input field is displayed in an overlay.

- -{` + + {` `} - +
Multiple Constraints
-

In "menu" display, it is possible to add more constraints to a same filter. In this case, metadata could be an array of constraints. The operator - defines whether all or any of the constraints should match.

+

In "menu" display, it is possible to add more constraints to a same filter. In this case, metadata could be an array of constraints. The operator defines whether all or any of the constraints should match.

- -{` + + {` const filters = { 'name': {operator: FilterOperator.AND, constraints: [{value: null, matchMode: FilterMatchMode.STARTS_WITH}]}, } `} - +
Populate Filters

Providing a filters with predefined values would be enough to display the table as filtered by default. This approach can also be used to clear filters progammatically.

- -{` + + {` const filters = { 'name': {operator: FilterOperator.AND, constraints: [ {value: 'Prime', matchMode: FilterMatchMode.STARTS_WITH}, @@ -1947,12 +1972,15 @@ const filters = { ]} } `} - +
Match Modes
-

Depending on the dataType of the column, suitable match modes are displayed. Default configuration is available at PrimeReact.filterMatchModeOptions which can be used to customize the modes globally for all tables.

- -{` +

+ Depending on the dataType of the column, suitable match modes are displayed. Default configuration is available at PrimeReact.filterMatchModeOptions which can be used to customize the modes globally for all + tables. +

+ + {` PrimeReact.filterMatchModeOptions = { text: [ FilterMatchMode.STARTS_WITH, @@ -1978,11 +2006,13 @@ PrimeReact.filterMatchModeOptions = { ] } `} - +
-

If you need to override the match modes for a particular column use the filterMatchModeOptions property and provide an array with label-value pairs.

- -{` +

+ If you need to override the match modes for a particular column use the filterMatchModeOptions property and provide an array with label-value pairs. +

+ + {` const matchModes = [ {label: 'Starts With', value: FilterMatchMode.STARTS_WITH}, {label: 'Contains', value: FilterMatchMode.CONTAINS}, @@ -1990,12 +2020,14 @@ const matchModes = [ ... `} - +
Custom Filter
-

Custom filtering is implemented using the FilterService, first register your filter and add it to your filterMatchModeOptions.

- -{` +

+ Custom filtering is implemented using the FilterService, first register your filter and add it to your filterMatchModeOptions. +

+ + {` import {FilterService} from 'primereact/api'; FilterService.register('myfilter', (a,b) => a === b); @@ -2007,11 +2039,14 @@ const matchModes = [ {label: 'Contains', value: FilterMatchMode.CONTAINS}, ] `} - +
-

By default, input fields are used as filter elements and this can be customized using the filterElement property of the Column that calls the filter function of the table instance by passing the value, field and the match mode.

- -{` +

+ By default, input fields are used as filter elements and this can be customized using the filterElement property of the Column that calls the filter function of the table instance by passing the value, field and the + match mode. +

+ + {` export const DataTableCustomFilterDemo = () => { const [products, setProducts] = useState([]); @@ -2048,13 +2083,15 @@ export const DataTableCustomFilterDemo = () => { ); } `} - +
-

In case you'd like to display the table as filtered by default on mount, use filters property in Controlled or Uncontrolled manner. - In controlled mode, filters and onFilter properties need to be defined to control the filtering state.

+

+ In case you'd like to display the table as filtered by default on mount, use filters property in Controlled or Uncontrolled manner. In controlled mode, filters and onFilter properties need to + be defined to control the filtering state. +

- -{` + + {` export const DataTableDefaultFilteredDemo = () => { const [products, setProducts] = useState([]); @@ -2078,13 +2115,15 @@ export const DataTableDefaultFilteredDemo = () => { ); } `} - + -

In uncontrolled filtering, no additional properties need to be enabled. Initial filtering can be still be provided using the filters property in uncontrolled mode however - it is evaluated at initial rendering and ignored in further updates. If you programmatically need to update the filtering state, prefer to use the component as controlled.

+

+ In uncontrolled filtering, no additional properties need to be enabled. Initial filtering can be still be provided using the filters property in uncontrolled mode however it is evaluated at initial rendering and ignored + in further updates. If you programmatically need to update the filtering state, prefer to use the component as controlled. +

- -{` + + {` @@ -2092,12 +2131,13 @@ export const DataTableDefaultFilteredDemo = () => { `} - + - -

Getting access to the filtered data is provided by the onValueChange callback.

- -{` +

+ Getting access to the filtered data is provided by the onValueChange callback. +

+ + {` console.log(filteredData)}> @@ -2105,16 +2145,19 @@ export const DataTableDefaultFilteredDemo = () => { `} - +
Selection
-

DataTable provides single and multiple selection modes on click of a row or cell. Selected rows are bound to the selection property for reading and updated using onSelectionChange callback. - Alternatively column based selection can be done using radio buttons or checkboxes using selectionMode of a particular column. In addition onRowSelect-onRowUnselect / onCellSelect-onCellUnselect events are provided as optional callbacks.

+

+ DataTable provides single and multiple selection modes on click of a row or cell. Selected rows are bound to the selection property for reading and updated using onSelectionChange callback. Alternatively column + based selection can be done using radio buttons or checkboxes using selectionMode of a particular column. In addition onRowSelect-onRowUnselect / onCellSelect-onCellUnselect events are + provided as optional callbacks. +

In single mode, selection binding is an object reference.

- -{` + + {` export const DataTableSelectionDemo = () => { const [products, setProducts] = useState([]); @@ -2147,13 +2190,16 @@ export const DataTableSelectionDemo = () => { ); } `} - + -

In multiple mode, selection binding should be an array and multiple items can either be selected using metaKey or toggled individually depending on the value of metaKeySelection property value which is true by default. - On touch enabled devices metaKeySelection is turned off automatically. Also, ShiftKey is supported for range selection. In addition, the rectangular selection can be dragged over the desired rows or cells thanks to the dragSelection property. In this way, a range of rows or cells can be selected.

+

+ In multiple mode, selection binding should be an array and multiple items can either be selected using metaKey or toggled individually depending on the value of metaKeySelection property value which is true by default. On + touch enabled devices metaKeySelection is turned off automatically. Also, ShiftKey is supported for range selection. In addition, the rectangular selection can be dragged over the desired rows or cells thanks to the + dragSelection property. In this way, a range of rows or cells can be selected. +

- -{` + + {` export const DataTableSelectionDemo = () => { const [products, setProducts] = useState([]); @@ -2205,13 +2251,17 @@ export const DataTableSelectionDemo = () => { } `} - + -

If you prefer a radiobutton or a checkbox instead of a row click, use the selectionMode of a column instead. - Following datatable displays a checkbox at the first column of each row and automatically adds a header checkbox to toggle selection of all rows.

-

Tip: Use showSelectionElement function in case you need to hide selection element for a particular row.

- -{` +

+ If you prefer a radiobutton or a checkbox instead of a row click, use the selectionMode of a column instead. Following datatable displays a checkbox at the first column of each row and automatically adds a header + checkbox to toggle selection of all rows. +

+

+ Tip: Use showSelectionElement function in case you need to hide selection element for a particular row. +

+ + {`
Row and Checkbox Selection
setSelectedProducts(e.value))}> @@ -2230,14 +2280,15 @@ export const DataTableSelectionDemo = () => { `} -
+
Cell Editing
-

Incell editing feature provides a way to quickly edit data inside the table. A cell editor is defined using the editor property - that refers to a function to return an input element for the editing.

+

+ Incell editing feature provides a way to quickly edit data inside the table. A cell editor is defined using the editor property that refers to a function to return an input element for the editing. +

- -{` + + {` @@ -2245,10 +2296,10 @@ export const DataTableSelectionDemo = () => { `} - + - -{` + + {` const onEditorValueChange = (props, value) => { let updatedProducts = [...props.value]; updatedProducts[props.rowIndex][props.field] = value; @@ -2281,37 +2332,39 @@ const statusEditor = (props) => { ); } `} - + -

Clicking outside the cell or hitting enter key closes the cell, however this may not be desirable if the input is invalid. In order - to decide whether to keep the cell open or not, provide a cellEditValidator function that validates the value. Optionally onCellEditComplete and onCellEditCancel - events are available at the column component to provide callbacks whenever an editor is submitted or cancelled.

+

+ Clicking outside the cell or hitting enter key closes the cell, however this may not be desirable if the input is invalid. In order to decide whether to keep the cell open or not, provide a cellEditValidator function + that validates the value. Optionally onCellEditComplete and onCellEditCancel + events are available at the column component to provide callbacks whenever an editor is submitted or cancelled. +

- -{` + + {` `} - + - - {` + + {` const requiredValidator = (e) => { let props = e.columnProps; let value = props.rowData[props.field]; return value && value.length > 0; } `} - +
Row Editing

Row editing toggles the visibility of the all editors in the row at once and provides additional options to save and cancel editing.

- -{` + + {` @@ -2319,22 +2372,24 @@ const requiredValidator = (e) => { `} - + - - {` + + {` const onRowEditValidator = (rowData) => { let value = rowData['inventoryStatuses']; return value.length > 0; } `} - +
ContextMenu
-

DataTable provides exclusive integration with ContextMenu. contextMenuSelection and onContextMenuSelectionChange are used to get a reference of the the selected row - and onContextMenu callback is utilized to display a particular context menu.

- -{` +

+ DataTable provides exclusive integration with ContextMenu. contextMenuSelection and onContextMenuSelectionChange are used to get a reference of the the selected row and onContextMenu callback is utilized + to display a particular context menu. +

+ + {` export const DataTableContextMenuDemo = () => { const [products, setProducts] = useState([]); @@ -2389,15 +2444,17 @@ export const DataTableContextMenuDemo = () => { ); } `} - +
Expandable Rows
-

Row expansion allows displaying detailed content for a particular row. To use this feature, add an expander column, define a rowExpansionTemplate as a function to return the expanded content and bind to +

+ Row expansion allows displaying detailed content for a particular row. To use this feature, add an expander column, define a rowExpansionTemplate as a function to return the expanded content and bind to expandedRows property to read the expanded rows along with the onRowToggle property to update it. expandedRows property either accepts an array of row data or a map whose key is the dataKey of the record. - Using expandable rows with a dataKey is suggested for better performance.

+ Using expandable rows with a dataKey is suggested for better performance. +

- - {` + + {` export const DataTableRowExpansionDemo = () => { const [products, setProducts] = useState([]); @@ -2497,13 +2554,15 @@ export const DataTableRowExpansionDemo = () => { ); } `} - +
Column Resize
-

Columns can be resized using drag drop by setting the resizableColumns to true. There are two resize modes; "fit" and "expand". Fit is the default one and the overall table width does not change when a column is resized. - In "expand" mode, table width also changes along with the column width. onColumnResizeEnd is a callback that passes the resized column header as a parameter.

- -{` +

+ Columns can be resized using drag drop by setting the resizableColumns to true. There are two resize modes; "fit" and "expand". Fit is the default one and the overall table width does not change when a column is + resized. In "expand" mode, table width also changes along with the column width. onColumnResizeEnd is a callback that passes the resized column header as a parameter. +

+ + {` @@ -2511,11 +2570,11 @@ export const DataTableRowExpansionDemo = () => { `} - +

It is important to note that when you need to change column widths, since table width is 100%, giving fixed pixel widths does not work well as browsers scale them, instead give percentage widths.

- -{` + + {` @@ -2523,11 +2582,13 @@ export const DataTableRowExpansionDemo = () => { `} - + -

You can choose which columns are resizeable per column.

- -{` +

+ You can choose which columns are resizeable per column. +

+ + {` @@ -2535,14 +2596,16 @@ export const DataTableRowExpansionDemo = () => { `} - +
Column Reorder
-

Columns can be reordered using drag drop by setting the reorderableColumns to true. onColReorder is a callback that is invoked when a column is reordered. - DataTable keeps the column order state internally using keys that identifies a column using the field property. If the column has no field, use columnKey instead.

+

+ Columns can be reordered using drag drop by setting the reorderableColumns to true. onColReorder is a callback that is invoked when a column is reordered. DataTable keeps the column order state internally using + keys that identifies a column using the field property. If the column has no field, use columnKey instead. +

- -{` + + {` @@ -2550,15 +2613,19 @@ export const DataTableRowExpansionDemo = () => { `} - +
Row Reorder
-

Data can be reordered using drag drop by adding a reorder column that will display an icon as a drag handle. onRowReorder is a callback that is invoked when a column is reordered, use - this callback to update the new order. The reorder icon can be customized using rowReorderIcon of the column component.

-

Tip: Use showRowReorderElement function in case you need to hide selection element for a particular row.

+

+ Data can be reordered using drag drop by adding a reorder column that will display an icon as a drag handle. onRowReorder is a callback that is invoked when a column is reordered, use this callback to update the new + order. The reorder icon can be customized using rowReorderIcon of the column component. +

+

+ Tip: Use showRowReorderElement function in case you need to hide selection element for a particular row. +

- -{` + + {` setProducts(e.value)}> @@ -2567,12 +2634,12 @@ export const DataTableRowExpansionDemo = () => { `} - +
Data Export

DataTable can export its data in CSV format using exportCSV() method.

- -{` + + {` export const DataTableExportDemo = () => { const [products, setProducts] = useState([]); @@ -2599,16 +2666,17 @@ export const DataTableExportDemo = () => { ); } `} - +
RowGrouping
-

RowGrouping has two modes defined be the rowGroupMode property, in "subheader" option rows are grouped by a groupRowsBy and in "rowspan" mode grouping - is done based on the sort field. In both cases, data should be sorted initally using the properties such as sortField and sortOrder. In "subheader" mode, - rowGroupHeaderTemplate property should be defined to provide the content of the header and optionally rowGroupFooterTemplate is available to provide a footer - for the group.

+

+ RowGrouping has two modes defined be the rowGroupMode property, in "subheader" option rows are grouped by a groupRowsBy and in "rowspan" mode grouping is done based on the sort field. In both cases, data should be + sorted initally using the properties such as sortField and sortOrder. In "subheader" mode, + rowGroupHeaderTemplate property should be defined to provide the content of the header and optionally rowGroupFooterTemplate is available to provide a footer for the group. +

- -{` + + {` const DataTableRowGroupDemo = () => { const [products, setProducts] = useState(null); @@ -2666,12 +2734,14 @@ const DataTableRowGroupDemo = () => { } `} - +
Scrolling
-

DataTable supports both horizontal and vertical scrolling as well as frozen columns and rows. Scrollable DataTable is enabled using scrollable property and scrollHeight to define the viewport height.

- -{` +

+ DataTable supports both horizontal and vertical scrolling as well as frozen columns and rows. Scrollable DataTable is enabled using scrollable property and scrollHeight to define the viewport height. +

+ + {` @@ -2679,27 +2749,36 @@ const DataTableRowGroupDemo = () => { `} - +
Column Widths of a Scrollable Table

Scrollable table uses flex layout so there are a couple of rules to consider when adjusting the widths of columns.

    -
  • Use min-width in vertical scrolling only so that when there is enough space columns may grow and for smaller screens a horizontal scrollbar is displayed to provide responsive design.
  • -
  • When horizontal scrolling is enabled, prefer width instead of min-width.
  • -
  • In vertical scrolling only, use flex to disable grow and shrink while defining a initial width. When horizontal scrolling is enabled, this is not required as columns do not grow or shrink in horizontal scrolling.
  • +
  • + Use min-width in vertical scrolling only so that when there is enough space columns may grow and for smaller screens a horizontal scrollbar is displayed to provide responsive design. +
  • +
  • + When horizontal scrolling is enabled, prefer width instead of min-width. +
  • +
  • + In vertical scrolling only, use flex to disable grow and shrink while defining a initial width. When horizontal scrolling is enabled, this is not required as columns do not grow or shrink in horizontal scrolling. +
- -{` + + {` `} - +
Flex Scroll
-

In cases where viewport should adjust itself according to the table parent's height instead of a fixed viewport height, set scrollHeight option as flex. In example below, table is inside a Dialog where viewport size dynamically responds to the dialog size changes such as maximizing.

+

+ In cases where viewport should adjust itself according to the table parent's height instead of a fixed viewport height, set scrollHeight option as flex. In example below, table is inside a Dialog where viewport size + dynamically responds to the dialog size changes such as maximizing. +

- -{` + + {`
Name
+
+
@@ -3000,8 +3100,12 @@ export const DataTableStateDemo = () => { - - + + @@ -3031,15 +3135,15 @@ export const DataTableStateDemo = () => { - + - + @@ -3135,7 +3239,9 @@ export const DataTableStateDemo = () => { - + @@ -3147,10 +3253,11 @@ export const DataTableStateDemo = () => { - + when set to false selection of each item can be toggled individually. On touch enabled devices, metaKeySelection is turned off automatically. + @@ -3204,7 +3311,9 @@ export const DataTableStateDemo = () => { - + @@ -3264,8 +3373,11 @@ export const DataTableStateDemo = () => { - + @@ -3307,13 +3419,17 @@ export const DataTableStateDemo = () => { - + - + @@ -3355,7 +3471,9 @@ export const DataTableStateDemo = () => { - + @@ -3373,11 +3491,11 @@ export const DataTableStateDemo = () => { - + event.field: Column field. event.rowData: Row data. event.column: Column. + @@ -3467,8 +3585,10 @@ export const DataTableStateDemo = () => { - + @@ -3481,8 +3601,8 @@ export const DataTableStateDemo = () => {
Events
-
-
Name
paginatorTemplate string|objectFirstPageLink PrevPageLink PageLinks
NextPageLink LastPageLink RowsPerPageDropdown
Template of the paginator. For details, refer to the template section of the paginator documentation for further options. + FirstPageLink PrevPageLink PageLinks
NextPageLink LastPageLink RowsPerPageDropdown +
+ Template of the paginator. For details, refer to the template section of the paginator documentation for further options. +
paginatorLeftcurrentPageReportTemplate string ({currentPage} of {totalPages})Template of the current page report element. Available placeholders are - {currentPage}, {totalPages}, {rows}, {first}, {last} and {totalRecords} - Template of the current page report element. Available placeholders are {currentPage}, {totalPages}, {rows}, {first}, {last} and {totalRecords}
paginatorDropdownAppendTo DOM element | string document.bodyDOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. + DOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. +
firstcompareSelectionBy string deepEqualsAlgorithm to define if a row is selected, valid values are "equals" that compares by reference and
"deepEquals" that compares all fields.
+ Algorithm to define if a row is selected, valid values are "equals" that compares by reference and
"deepEquals" that compares all fields. +
dataKeymetaKeySelection boolean trueDefines whether metaKey is requred or not for the selection.
+
+ Defines whether metaKey is requred or not for the selection.
When true metaKey needs to be pressed to select or unselect an item and
- when set to false selection of each item - can be toggled individually. On touch enabled devices, metaKeySelection is turned off automatically.
selectionPageOnlycolumnResizeMode string fitDefines whether the overall table width should change on column resize,
valid values are "fit" and "expand".
+ Defines whether the overall table width should change on column resize,
valid values are "fit" and "expand". +
reorderableColumnsvirtualScrollerOptions object nullWhether to use the virtualScroller feature. The properties of VirtualScroller component can be used like an object in it. -
Note: Currently only vertical orientation mode is supported.
+ Whether to use the virtualScroller feature. The properties of VirtualScroller component can be used like an object in it. +
+ Note: Currently only vertical orientation mode is supported. +
frozenWidthrowClassName function nullFunction that takes the row data and
returns an object in "{'styleclass' : condition}" format to define a classname for a particular now.
+ Function that takes the row data and
returns an object in "{'styleclass' : condition}" format to define a classname for a particular now. +
cellClassName function nullFunction that takes the cell data and
returns an object in "{'styleclass' : condition}" format to define a classname for a particular now.
+ Function that takes the cell data and
returns an object in "{'styleclass' : condition}" format to define a classname for a particular now. +
rowGroupHeaderTemplatestateStorage string sessionDefines where a stateful table keeps its state,
valid values are "session" for sessionStorage, "local" for localStorage and "custom".
+ Defines where a stateful table keeps its state,
valid values are "session" for sessionStorage, "local" for localStorage and "custom". +
editModeexportFunction function nullA function to implement custom export. Need to return string value.
+
+ A function to implement custom export. Need to return string value.
event.data: Field data.
- event.field: Column field. - event.rowData: Row data. - event.column: Column.
expandableRowGroupscustomSaveState function nullA function to implement custom saveState with stateStorage="custom".
- state: the object to be stored.
+ A function to implement custom saveState with stateStorage="custom".
+ state: the object to be stored.{' '} +
customRestoreState
+
+
@@ -3493,14 +3613,16 @@ export const DataTableStateDemo = () => { - - @@ -3512,36 +3634,50 @@ export const DataTableStateDemo = () => { - + - + - + - + event.multiSortMeta: MultiSort metadata. + - + @@ -3551,78 +3687,100 @@ export const DataTableStateDemo = () => { - + event.type: Type of the selection, valid value is "all". + - + event.type: Type of the selection, valid value is "all". + - + event.index: Clicked row data index + - + event.index: Clicked row data index + - + event.type: Type of the selection, valid values are "row", "radio" or "checkbox". + - + event.type: Type of the selection, valid values are "row", "radio" or "checkbox". + - + - + - + - + event.columns: Columns array after reorder. + - + event.dropIndex: Index of the drop location + @@ -3637,37 +3795,47 @@ export const DataTableStateDemo = () => { - + - + - + event.index: Editing row data index + - + event.index: Current editing row data index + - + event.index: Current editing row data index{' '} + @@ -3685,8 +3853,8 @@ export const DataTableStateDemo = () => {
Methods
-
-
Name
onSelectionChangeevent.originalEvent: Browser event
+
+ event.originalEvent: Browser event
event.value: Selection object
Callback to invoke when selection changes.
onContextMenuSelectionChangeevent.originalEvent: Browser event
+
+ event.originalEvent: Browser event
event.value: Selection object
Callback to invoke when a row selected with right click.
onColumnResizeEndevent.element: DOM element of the resized column.
- event.column: Properties of the resized column.
- event.delta: Change in column width
+ event.element: DOM element of the resized column. +
+ event.column: Properties of the resized column. +
+ event.delta: Change in column width +
Callback to invoke when a column is resized.
onColumnResizerClickevent.originalEvent: Browser event
- event.element: DOM element of the column.
- event.column: Properties of the column.
+ event.originalEvent: Browser event
+ event.element: DOM element of the column. +
+ event.column: Properties of the column. +
Callback to invoke when a resizer element is clicked.
onColumnResizerDoubleClickevent.originalEvent: Browser event
- event.element: DOM element of the column.
- event.column: Properties of the column.
+ event.originalEvent: Browser event
+ event.element: DOM element of the column. +
+ event.column: Properties of the column. +
Callback to invoke when a resizer element is double clicked.
onSortevent.sortField: Field to sort against.
+
+ event.sortField: Field to sort against.
event.sortOrder: Sort order as integer.
- event.multiSortMeta: MultiSort metadata.
Callback to invoke on sort.
onPageevent.first: Index of the first row.
- event.rows: Rows per page.
+ event.first: Index of the first row.
+ event.rows: Rows per page. +
Callback to invoke on pagination.
onAllRowsSelectevent.originalEvent: Browser event.
+
+ event.originalEvent: Browser event.
event.data: Selected rows data.
- event.type: Type of the selection, valid value is "all".
Callback to invoke when all rows are selected using the header checkbox.
onAllRowsUnselectevent.originalEvent: Browser event.
+
+ event.originalEvent: Browser event.
event.data: Unselected rows data.
- event.type: Type of the selection, valid value is "all".
Callback to invoke when all rows are unselected using the header checkbox.
onRowClickevent.originalEvent: Browser event
+
+ event.originalEvent: Browser event
event.data: Clicked row data
- event.index: Clicked row data index
Callback to invoke when a row is clicked.
onRowDoubleClickevent.originalEvent: Browser event
+
+ event.originalEvent: Browser event
event.data: Clicked row data
- event.index: Clicked row data index
Callback to invoke when a row is double clicked.
onRowSelectevent.originalEvent: Browser event.
+
+ event.originalEvent: Browser event.
event.data: Selected row data.
- event.type: Type of the selection, valid values are "row", "radio" or "checkbox".
Callback to invoke when a row is selected.
onRowUnselectevent.originalEvent: Browser event.
+
+ event.originalEvent: Browser event.
event.data: Unselected row data.
- event.type: Type of the selection, valid values are "row", "radio" or "checkbox".
Callback to invoke when a row is unselected.
onRowExpandevent.originalEvent: Browser event.
- event.data: Expanded row data.
+ event.originalEvent: Browser event.
+ event.data: Expanded row data. +
Callback to invoke when a row is expanded.
onRowCollapseevent.originalEvent: Browser event.
- event.data: Collapsed row data.
+ event.originalEvent: Browser event.
+ event.data: Collapsed row data. +
Callback to invoke when a row is collapsed.
onContextMenuevent.originalEvent: Original event instance.
- event.data: Collapsed row data
+ event.originalEvent: Original event instance.
+ event.data: Collapsed row data +
Callback to invoke when a context menu is clicked.
onColReorderevent.originalEvent: Browser event
+
+ event.originalEvent: Browser event
event.dragIndex: Index of the dragged column
event.dropIndex: Index of the dropped column
- event.columns: Columns array after reorder.
Callback to invoke when a column is reordered.
onRowOrderevent.originalEvent: Browser event.
+
+ event.originalEvent: Browser event.
event.value: New value after reorder
event.dragIndex: Index of the dragged row
- event.dropIndex: Index of the drop location
Callback to invoke when a row is reordered.
onRowEditInitevent.originalEvent: Browser event
- event.data: Editing row data
+ event.originalEvent: Browser event
+ event.data: Editing row data{' '} +
Callback to invoke when the editing icon is clicked on row editing mode.
onRowEditSaveevent.originalEvent: Browser event
- event.data: Editing row data
+ event.originalEvent: Browser event
+ event.data: Editing row data +
Callback to invoke when the save icon is clicked on row editing mode.
onRowEditCancelevent.originalEvent: Browser event
+
+ event.originalEvent: Browser event
event.data: Editing row data
- event.index: Editing row data index
Callback to invoke when the cancel icon is clicked on row editing mode.
onRowEditChangeevent.originalEvent: Browser event
+
+ event.originalEvent: Browser event
event.data: Editing rows data
- event.index: Current editing row data index
Callback to invoke when the row editor is programmatically shown/hidden on row editing mode.
onRowEditCompleteevent.originalEvent: Browser event
+
+ event.originalEvent: Browser event
event.data: Original rows data
event.newData: Editing rows data
event.field: Column field
- event.index: Current editing row data index
Callback to invoke when row edit is completed.
+
+
@@ -3707,7 +3875,8 @@ export const DataTableStateDemo = () => { - @@ -3738,9 +3907,11 @@ export const DataTableStateDemo = () => {
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
filtervalue: the filter value
+
+ value: the filter value
field: the filter field
mode: filter match mode.
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -3835,29 +4006,49 @@ export const DataTableStateDemo = () => {
Accessibility
Screen Reader
-

DataTable uses a table element whose attributes can be extended with the tableProps option. This property allows passing aria roles and attributes like aria-label and aria-describedby to define the table for readers. Default - role of the table is table. Header, body and footer elements use rowgroup, rows use row role, header cells have columnheader and body cells use cell roles. Sortable headers utilizer aria-sort attribute - either set to "ascending" or "descending".

- -

Built-in checkbox and radiobutton components for row selection use checkbox and radiobutton roles respectively with aria-checked state attribute. The label to describe them is retrieved from the - aria.selectRow and aria.unselectRow properties of the locale API. Similarly header checkbox uses selectAll and unselectAll keys. When a row is selected, aria-selected is set to true on a row.

- -

The element to expand or collapse a row is a button with aria-expanded and aria-controls properties. Value to describe the buttons is derived from aria.expandRow and aria.collapseRow properties of the locale API.

- -

The filter menu button use aria.showFilterMenu and aria.hideFilterMenu properties as aria-label in addition to the aria-haspopup, aria-expanded and aria-controls to define the relation between the button and the overlay. Popop menu has dialog role with aria-modal - as focus is kept within the overlay. The operator dropdown use aria.filterOperator and filter constraints dropdown use aria.filterConstraint properties. Buttons to add rules on the other hand utilize aria.addRule and aria.removeRule properties. The footer buttons similarly use - aria.clear and aria.apply properties. filterInputProps of the Column component can be used to define aria labels for the built-in filter components, if a custom component is used with templating you also may define your own aria labels as well.

- -

Editable cells use custom templating so you need to manage aria roles and attributes manually if required. The row editor controls are button elements with aria.editRow, aria.cancelEdit and aria.saveEdit used for the aria-label.

- -

Paginator is a standalone component used inside the DataTable, refer to the paginator for more information about the accessibility features.

+

+ DataTable uses a table element whose attributes can be extended with the tableProps option. This property allows passing aria roles and attributes like aria-label and aria-describedby to define + the table for readers. Default role of the table is table. Header, body and footer elements use rowgroup, rows use row role, header cells have columnheader and body cells use cell roles. + Sortable headers utilizer aria-sort attribute either set to "ascending" or "descending". +

+ +

+ Built-in checkbox and radiobutton components for row selection use checkbox and radiobutton roles respectively with aria-checked state attribute. The label to describe them is retrieved from the + aria.selectRow and aria.unselectRow properties of the locale API. Similarly header checkbox uses selectAll and unselectAll keys. When a row is selected,{' '} + aria-selected is set to true on a row. +

+ +

+ The element to expand or collapse a row is a button with aria-expanded and aria-controls properties. Value to describe the buttons is derived from aria.expandRow and aria.collapseRow{' '} + properties of the locale API. +

+ +

+ The filter menu button use aria.showFilterMenu and aria.hideFilterMenu properties as aria-label in addition to the aria-haspopup, aria-expanded and aria-controls to define the + relation between the button and the overlay. Popop menu has dialog role with aria-modal + as focus is kept within the overlay. The operator dropdown use aria.filterOperator and filter constraints dropdown use aria.filterConstraint properties. Buttons to add rules on the other hand utilize{' '} + aria.addRule and aria.removeRule properties. The footer buttons similarly use + aria.clear and aria.apply properties. filterInputProps of the Column component can be used to define aria labels for the built-in filter components, if a custom component is used with templating you + also may define your own aria labels as well. +

+ +

+ Editable cells use custom templating so you need to manage aria roles and attributes manually if required. The row editor controls are button elements with aria.editRow, aria.cancelEdit and{' '} + aria.saveEdit used for the aria-label. +

+ +

+ Paginator is a standalone component used inside the DataTable, refer to the paginator for more information about the accessibility features. +

Sortable Headers Keyboard Support
-

Any button element inside the DataTable used for cases like filter, row expansion, edit are tabbable and can be used with space and enter keys.

- +

+ Any button element inside the DataTable used for cases like filter, row expansion, edit are tabbable and can be used with space and enter keys. +

+
Sortable Headers Keyboard Support
-
-
Name
+
+
@@ -3866,15 +4057,21 @@ export const DataTableStateDemo = () => { - + - + - + @@ -3882,8 +4079,8 @@ export const DataTableStateDemo = () => {
Filter Menu Keyboard Support
-
-
Key
tab + tab + Moves through the headers.
enter + enter + Sorts the column.
space + space + Sorts the column.
+
+
@@ -3892,11 +4089,15 @@ export const DataTableStateDemo = () => { - + - + @@ -3904,8 +4105,8 @@ export const DataTableStateDemo = () => {
Selection Keyboard Support
-
-
Key
tab + tab + Moves through the elements inside the popup.
escape + escape + Hides the popup.
+
+
@@ -3914,55 +4115,81 @@ export const DataTableStateDemo = () => { - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -3972,14 +4199,11 @@ export const DataTableStateDemo = () => {
Dependencies

None.

- - { - useLiveEditorTabs({ name: 'DataTableDemo', sources: sources, service: 'CustomerService', data: 'customers-large', extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'DataTableDemo', sources: sources, service: 'CustomerService', data: 'customers-large', extFiles: extFiles })} ); -}) +}); export default DataTableDoc; diff --git a/components/doc/dataview/index.js b/components/doc/dataview/index.js index 182262ace0..14c2f7fbd9 100644 --- a/components/doc/dataview/index.js +++ b/components/doc/dataview/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const DataViewDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -151,7 +150,7 @@ export class DataViewDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState, useEffect } from 'react'; @@ -279,7 +278,7 @@ const DataViewDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState, useEffect } from 'react'; @@ -407,7 +406,7 @@ const DataViewDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -540,7 +539,7 @@ const DataViewDemo = () => { } ` } - } + }; const extFiles = { 'demo/DataViewDemo.css': { @@ -668,41 +667,47 @@ const DataViewDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { DataView, DataViewLayoutOptions } from 'primereact/dataview'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

Layout of the DataView is managed by the PrimeFlex that can be downloaded from npm.

+

+ Layout of the DataView is managed by the PrimeFlex that can be downloaded from npm. +

- -{` + + {` npm install primeflex `} - + -

DataView requires a collection of items as its value and one or more templates depending on the layout mode e.g. list and grid.

+

+ DataView requires a collection of items as its value and one or more templates depending on the layout mode e.g. list and grid.{' '} +

-

DataView has two layout modes; list and grid where itemTemplate function is called by passing the item to render along with the layout mode.

- -{` +

+ DataView has two layout modes; list and grid where itemTemplate function is called by passing the item to render along with the layout mode. +

+ + {` const itemTemplate = (data, layout) => { if (layout === 'list') { return ( @@ -718,26 +723,26 @@ const itemTemplate = (data, layout) => { } `} - +
- -{` + + {` `} - +
DataViewLayoutOptions

DataViewLayoutOptions is a helper component to choose between layout modes. This component is used in controlled manner to manage the state of layout orientation.

- -{` + + {` setLayout(e.value)} /> `} - +
Properties of DataViewLayoutOptions
-
-
Key
tab + tab + Moves focus to the first selected row, if there is none then first row receives the focus.
up arrow + up arrow + Moves focus to the previous row.
down arrow + down arrow + Moves focus to the next row.
enter + enter + Toggles the selected state of the focused row depending on the metaKeySelection setting.
space + space + Toggles the selected state of the focused row depending on the metaKeySelection setting.
home + home + Moves focus to the first row.
end + end + Moves focus to the last row.
shift + down arrow + shift + down arrow + Moves focus to the next row and toggles the selection state.
shift + up arrow + shift + up arrow + Moves focus to the previous row and toggles the selection state.
shift + space + shift + space + Selects the rows between the most recently selected row and the focused row.
control + shift + home + control + shift + home + Selects the focused rows and all the options up to the first one.
control + shift + end + control + shift + end + Selects the focused rows and all the options down to the last one.
control + a + control + a + Selects all rows.
+
+
@@ -782,8 +787,8 @@ const itemTemplate = (data, layout) => {
Events of DataViewLayoutOptions
-
-
Name
+
+
@@ -794,7 +799,8 @@ const itemTemplate = (data, layout) => { - @@ -804,31 +810,39 @@ const itemTemplate = (data, layout) => {
Paginator
-

Pagination is enabled by setting paginator property to true, rows attribute defines the number of rows per page and pageLinks specify the the number - of page links to display. Visit the paginator paginator component for more information about the available properties.

+

+ Pagination is enabled by setting paginator property to true, rows attribute defines the number of rows per page and pageLinks specify the the number of page links to display. Visit the paginator{' '} + paginator component for more information about the available properties. +

-

Pagination can either be used in Controlled or Uncontrolled manner. In controlled mode, first and onPage properties needs to be defined to control the pagination state.

+

+ Pagination can either be used in Controlled or Uncontrolled manner. In controlled mode, first and onPage properties needs to be defined to control the pagination state. +

- -{` + + {` setFirst(e.first)}> `} - - -

In uncontrolled mode, only paginator property needs to be enabled. Initial page state can be still be provided using the first property in uncontrolled mode however - it is evaluated at initial rendering and ignored in further updates. If you programmatically need to update the paginator, prefer to use the component as controlled.

- -{` + + +

+ In uncontrolled mode, only paginator property needs to be enabled. Initial page state can be still be provided using the first property in uncontrolled mode however it is evaluated at initial rendering and + ignored in further updates. If you programmatically need to update the paginator, prefer to use the component as controlled. +

+ + {` `} - +
Sorting
-

sortField and sortOrder properties are available for sorting functionality, for flexibility there is no built-in UI available so that a custom UI can be used for the sorting element. - Here is an example that uses a dropdown where simply updating the sortField-sortOrder bindings of the DataView initiates sorting.

+

+ sortField and sortOrder properties are available for sorting functionality, for flexibility there is no built-in UI available so that a custom UI can be used for the sorting element. Here is an example that uses + a dropdown where simply updating the sortField-sortOrder bindings of the DataView initiates sorting. +

- -{` + + {` const sortOptions = [ {label: 'Price High to Low', value: '!price'}, {label: 'Price Low to High', value: 'price'}, @@ -845,10 +859,10 @@ const header = ( `} - + - -{` + + {` const onSortChange = (event) => { const value = event.value; @@ -864,16 +878,18 @@ const onSortChange = (event) => { } } `} - +
Lazy Loading
-

Lazy loading is useful to deal with huge datasets, in order to implement lazy loading use the pagination in controlled mode and utilize the onPage callback to load your data from the backend. - Pagination in this case needs to display the logical number of records so bind this value to the totalRecords property so that paginator can display itself according to the total records although you'd only - need to load the data of the current page. Refer to DataTable lazy loading for a sample implementation.

+

+ Lazy loading is useful to deal with huge datasets, in order to implement lazy loading use the pagination in controlled mode and utilize the onPage callback to load your data from the backend. Pagination in this case + needs to display the logical number of records so bind this value to the totalRecords property so that paginator can display itself according to the total records although you'd only need to load the data of the current + page. Refer to DataTable lazy loading for a sample implementation. +

Properties
-
-
Name
onChangeevent.originalEvent: browser event
+
+ event.originalEvent: browser event
event.value = layout mode e.g. "list" or "grid"
Callback to invoke when layout mode is changed.
+
+
@@ -959,7 +975,9 @@ const onSortChange = (event) => { - + @@ -995,7 +1013,9 @@ const onSortChange = (event) => { - + @@ -1050,21 +1070,23 @@ const onSortChange = (event) => {
Events
-
-
NamepaginatorTemplate string|object FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdownTemplate of the paginator. For details, refer to the template section of the paginator documentation for further options. + Template of the paginator. For details, refer to the template section of the paginator documentation for further options. +
paginatorLeftpaginatorDropdownAppendTo DOM element | string document.bodyDOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. + DOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. +
emptyMessage
+
+
- - - - - + + + + + - + event.rows: Number of records to display per page. + @@ -1072,14 +1094,16 @@ const onSortChange = (event) => {
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
NameParametersDescription
NameParametersDescription
onPageevent.originalEvent: Browser event
+
+ event.originalEvent: Browser event
event.first: Index of the first records on page.
- event.rows: Number of records to display per page.
Callback to invoke on pagination.
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
- - - - + + + + @@ -1111,47 +1135,52 @@ const onSortChange = (event) => {
Accessibility
- -
Screen Reader
-

The container element that wraps the layout options buttons has a group role whereas each button element uses button role and aria-pressed is updated depending on selection state. - Values to describe the buttons are derived from the aria.listView and aria.gridView properties of the locale API respectively.

- -

Refer to paginator accessibility documentation for the paginator of the component.

- -
Keyboard Support
-
-
NameElement
NameElement
- - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus to the buttons.
spaceToggles the checked state of a button.
-
- + +
Screen Reader
+

+ The container element that wraps the layout options buttons has a group role whereas each button element uses button role and aria-pressed is updated depending on selection state. Values to describe + the buttons are derived from the aria.listView and aria.gridView properties of the locale API respectively. +

+ +

+ Refer to paginator accessibility documentation for the paginator of the component. +

+ +
Keyboard Support
+
+ + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the buttons.
+ space + Toggles the checked state of a button.
+
+
Dependencies

None.

-
- { - useLiveEditorTabs({ name: 'DataViewDemo', sources: sources, service: 'ProductService', data: 'products', extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'DataViewDemo', sources: sources, service: 'ProductService', data: 'products', extFiles: extFiles })}
); -}) +}); export default DataViewDoc; diff --git a/components/doc/deferredcontent/index.js b/components/doc/deferredcontent/index.js index b4d5ac20ce..0bf3351eea 100644 --- a/components/doc/deferredcontent/index.js +++ b/components/doc/deferredcontent/index.js @@ -5,9 +5,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const DeferredContentDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -70,7 +69,7 @@ export class DeferredContentDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState, useRef } from 'react'; @@ -123,7 +122,7 @@ const DeferredContentDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState, useRef } from 'react'; @@ -176,7 +175,7 @@ const DeferredContentDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -236,31 +235,31 @@ const DeferredContentDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { DeferredContent } from 'primereact/deferredcontent'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started

DeferredContent is used as a wrapper element of its content.

- -{` + + {` @@ -270,12 +269,14 @@ import { DeferredContent } from 'primereact/deferredcontent'; `} - +
Callback
-

onLoad callback is useful to initialize the content when it becomes visible on scroll such as loading data.

- -{` +

+ onLoad callback is useful to initialize the content when it becomes visible on scroll such as loading data. +

+ + {` @@ -285,16 +286,14 @@ import { DeferredContent } from 'primereact/deferredcontent'; `} - +
Properties
-
- Component has no attributes. -
+
Component has no attributes.
Events
-
- +
+
@@ -316,33 +315,36 @@ import { DeferredContent } from 'primereact/deferredcontent';

Component does not apply any styling.

Accessibility
- -
Screen Reader
-

DeferredContent can be utilized in many use cases as a result no role is enforced, in fact a role may not be necessary if the card is used for presentational purposes only. - Any valid attribute is passed to the container element so you have full control over the roles like landmark and attributes like aria-live. -

- - -{` + +
Screen Reader
+

+ DeferredContent can be utilized in many use cases as a result no role is enforced, in fact a role may not be necessary if the card is used for presentational purposes only. Any valid attribute is passed to the container + element so you have full control over the roles like{' '} + + landmark + {' '} + and attributes like aria-live. +

+ + + {` Content `} - +
-
Keyboard Support
-

Component does not include any interactive elements.

-
+
Keyboard Support
+

Component does not include any interactive elements.

+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'DeferredContentDemo', sources: sources, service: 'ProductService', data: 'products-small' }) - } + {useLiveEditorTabs({ name: 'DeferredContentDemo', sources: sources, service: 'ProductService', data: 'products-small' })} ); -}) +}); export default DeferredContentDoc; diff --git a/components/doc/dialog/index.js b/components/doc/dialog/index.js index c00bc0a163..731cc68324 100644 --- a/components/doc/dialog/index.js +++ b/components/doc/dialog/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const DialogDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -167,7 +166,7 @@ export class DialogDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -315,7 +314,7 @@ const DialogDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -463,7 +462,7 @@ const DialogDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -614,7 +613,7 @@ const DialogDemo = () => { } ` } - } + }; const extFiles = { 'demo/DialogDemo.css': { @@ -634,30 +633,32 @@ const DialogDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Dialog } from 'primereact/dialog'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

Dialog is used as a container and visibility is managed with visible property where onHide event is required to update the visibility state.

- -{` +

+ Dialog is used as a container and visibility is managed with visible property where onHide event is required to update the visibility state. +

+ + {`
Name
+
+
@@ -868,7 +874,9 @@ const myIcon = ( - + @@ -922,15 +930,21 @@ const myIcon = ( - +
NameappendTo DOM element | string document.bodyDOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. + DOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. +
baseZIndextransitionOptions object nullThe properties of CSSTransition can be customized, except for "nodeRef" and "in" properties. + The properties of{' '} + + CSSTransition + {' '} + can be customized, except for "nodeRef" and "in" properties. +
Events
-
- +
+
@@ -951,7 +965,8 @@ const myIcon = ( - @@ -1001,9 +1016,11 @@ const myIcon = (
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
onMaximizeevent.originalEvent: Browser event
+
+ event.originalEvent: Browser event
event.maximized: Whether to show the dialog or not on fullscreen.
Callback to invoke when toggle maximize icon is clicked.
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -1041,84 +1058,100 @@ const myIcon = (
Accessibility
-
Screen Reader
-

Dialog component uses dialog role along with aria-labelledby referring to the header element however any attribute is passed to the root element so you may use aria-labelledby to override this default behavior. - In addition aria-modal is added since focus is kept within the popup.

-

It is recommended to use a trigger component that can be accessed with keyboard such as a button, if not adding tabIndex would be necessary.

-

Trigger element also requires aria-expanded and aria-controls to be handled explicitly.

-

Close element is a button with an aria-label that refers to the aria.close property of the locale API by default, you may use - closeButtonProps to customize the element and override the default aria-label.

- - -{` +
Screen Reader
+

+ Dialog component uses dialog role along with aria-labelledby referring to the header element however any attribute is passed to the root element so you may use aria-labelledby to override this default + behavior. In addition aria-modal is added since focus is kept within the popup. +

+

+ It is recommended to use a trigger component that can be accessed with keyboard such as a button, if not adding tabIndex would be necessary. +

+

+ Trigger element also requires aria-expanded and aria-controls to be handled explicitly. +

+

+ Close element is a button with an aria-label that refers to the aria.close property of the locale API by default, you may use + closeButtonProps to customize the element and override the default aria-label. +

+ + + {`
Name
- - - - - - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus to the next the focusable element within the dialog.
shift + tabMoves focus to the previous the focusable element within the dialog.
escapeCloses the dialog if closeOnEscape is true.
-
+ + +
Overlay Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the next the focusable element within the dialog.
+ shift + tab + Moves focus to the previous the focusable element within the dialog.
+ escape + + Closes the dialog if closeOnEscape is true. +
+
-
Close Button Keyboard Support
-
- - - - - - - - - - - - - - - - - -
KeyFunction
enterCloses the dialog.
spaceCloses the dialog.
-
+
Close Button Keyboard Support
+
+ + + + + + + + + + + + + + + + + +
KeyFunction
+ enter + Closes the dialog.
+ space + Closes the dialog.
+
Dependencies

None.

-
- { - useLiveEditorTabs({ name: 'DialogDemo', sources: sources, extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'DialogDemo', sources: sources, extFiles: extFiles })}
); -}) +}); export default DialogDoc; diff --git a/components/doc/divider/index.js b/components/doc/divider/index.js index 19790dcef3..bbf8598517 100644 --- a/components/doc/divider/index.js +++ b/components/doc/divider/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const DividerDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -164,7 +163,7 @@ export class DividerDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React from 'react'; @@ -319,7 +318,7 @@ const DividerDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React from 'react'; @@ -474,7 +473,7 @@ const DividerDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -632,51 +631,57 @@ const DividerDemo = () => { } ` } - } + }; return ( -
+
- -
Import via Module
- -{` + +
Import via Module
+ + {` import { Divider } from 'primereact/divider'; `} - +
-
Import via CDN
- -{` +
Import via CDN
+ + {` `} - - -
Getting Started
-

Divider has two orientations defined with the layout property, default is "horizontal" and the alternative is "vertical".

- -{` + + +
Getting Started
+

+ Divider has two orientations defined with the layout property, default is "horizontal" and the alternative is "vertical". +

+ + {`
Content 1
Content 2
`} -
- -
Border Style
-

Style of the border is configured with the type property and supports 3 values; default is "solid" and other possibilities are "dashed" and "dotted".

- -{` + + +
Border Style
+

+ Style of the border is configured with the type property and supports 3 values; default is "solid" and other possibilities are "dashed" and "dotted". +

+ + {`
Content 1
Content 2
`} -
- -
Vertical Divider
-

Vertical divider is enabled by setting the layout property as "vertical".

- -{` + + +
Vertical Divider
+

+ Vertical divider is enabled by setting the layout property as "vertical". +

+ + {`
Content 1
@@ -685,15 +690,15 @@ import { Divider } from 'primereact/divider';
Content 3
`} -
+
-
Content
-

Any content placed inside is rendered within the boundaries of the divider. In addition, location - of the content is configured with the align property. In horizontal layout, alignment options - are "left", "center" and "right" whereas vertical mode supports "top", "center" and "bottom". -

- -{` +
Content
+

+ Any content placed inside is rendered within the boundaries of the divider. In addition, location of the content is configured with the align property. In horizontal layout, alignment options are "left", "center" and + "right" whereas vertical mode supports "top", "center" and "bottom". +

+ + {`
Content 1
@@ -717,121 +722,122 @@ import { Divider } from 'primereact/divider';
Content 4
`} -
- -
Properties
-

Any valid attribute is passed to the root element implicitly, extended properties are as follows;

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDefaultDescription
alignstringnullAlignment of the content, options are "left", "center", "right" for horizontal layout - and "top", "center", "bottom" for vertical.
layoutstringhorizontalSpecifies the orientation, valid values are "horizontal" and "vertical".
typeStringsolidBorder style type, default is "solid" and other options are "dashed" and "dotted".
-
+
+ +
Properties
+

Any valid attribute is passed to the root element implicitly, extended properties are as follows;

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
alignstringnullAlignment of the content, options are "left", "center", "right" for horizontal layout and "top", "center", "bottom" for vertical.
layoutstringhorizontalSpecifies the orientation, valid values are "horizontal" and "vertical".
typeStringsolidBorder style type, default is "solid" and other options are "dashed" and "dotted".
+
-
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameElement
p-dividerContainer element.
p-divider-horizontalContainer element in horizontal layout.
p-divider-verticalContainer element in vertical layout.
p-divider-solidContainer element with solid border.
p-divider-dashedContainer element with dashed border.
p-divider-dottedContainer element with dotted border.
p-divider-leftContainer element with content aligned to left.
p-divider-rightContainer element with content aligned to right.
p-divider-centerContainer element with content aligned to center.
p-divider-bottomContainer element with content aligned to bottom.
p-divider-topContainer element with content aligned to top.
-
+
Styling
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameElement
p-dividerContainer element.
p-divider-horizontalContainer element in horizontal layout.
p-divider-verticalContainer element in vertical layout.
p-divider-solidContainer element with solid border.
p-divider-dashedContainer element with dashed border.
p-divider-dottedContainer element with dotted border.
p-divider-leftContainer element with content aligned to left.
p-divider-rightContainer element with content aligned to right.
p-divider-centerContainer element with content aligned to center.
p-divider-bottomContainer element with content aligned to bottom.
p-divider-topContainer element with content aligned to top.
+
-
Accessibility
- -
Screen Reader
-

Divider uses a separator role with aria-orientation set to either "horizontal" or "vertical".

- -
Keyboard Support
-

Component does not include any interactive elements.

-
-
Dependencies
-

None.

-
- - { - useLiveEditorTabs({ name: 'DividerDemo', sources: sources }) - } +
Accessibility
+ +
Screen Reader
+

+ Divider uses a separator role with aria-orientation set to either "horizontal" or "vertical". +

+ +
Keyboard Support
+

Component does not include any interactive elements.

+
+
Dependencies
+

None.

+ + + {useLiveEditorTabs({ name: 'DividerDemo', sources: sources })}
); -}) +}); export default DividerDoc; diff --git a/components/doc/dock/index.js b/components/doc/dock/index.js index 398f3dc30c..df8c514474 100644 --- a/components/doc/dock/index.js +++ b/components/doc/dock/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const DockDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -360,7 +359,7 @@ export class DockDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState, useEffect } from 'react'; @@ -707,7 +706,7 @@ export const DockDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState, useEffect } from 'react'; @@ -1054,7 +1053,7 @@ export const DockDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -1408,8 +1407,8 @@ const DockDemo = () => { ) } ` - } } + }; const extFiles = { 'demo/DockDemo.css': { @@ -1492,32 +1491,34 @@ const DockDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Dock } from 'primereact/dock'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

Dock is a navigation component consisting of menuitems. It has a collection of additional options defined by the model property.

+

+ Dock is a navigation component consisting of menuitems. It has a collection of additional options defined by the model property. +

- -{` + + {` export const DockDemo = () => { const imgPath = 'images/dock'; @@ -1547,15 +1548,17 @@ export const DockDemo = () => { ); } `} - +
MenuModel API
-

Dock uses the common MenuModel API to define the items, visit MenuModel API for details.

+

+ Dock uses the common MenuModel API to define the items, visit MenuModel API for details. +

Properties

Any valid attribute is passed to the root element implicitly, extended properties are as follows;

-
- +
+
@@ -1618,9 +1621,11 @@ export const DockDemo = () => {
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -1645,69 +1650,84 @@ export const DockDemo = () => {
Accessibility
- -
Screen Reader
-

Dock component uses the menu role with the aria-orientation and the value to describe the menu can either be provided with aria-labelledby or aria-label props. Each list item has a presentation role - whereas anchor elements have a menuitem role with aria-label referring to the label of the item and aria-disabled defined if the item is disabled.

- -
Keyboard Support
-
-
Name
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyFunction
tabAdd focus to the first item if focus moves in to the menu. If the focus is already within the menu, focus moves to the next focusable item in the page tab sequence.
shift + tabAdd focus to the last item if focus moves in to the menu. If the focus is already within the menu, focus moves to the previous focusable item in the page tab sequence.
enterActivates the focused menuitem.
spaceActivates the focused menuitem.
down arrowMoves focus to the next menuitem in vertical layout.
up arrowMoves focus to the previous menuitem in vertical layout.
homeMoves focus to the first menuitem in horizontal layout.
endMoves focus to the last menuitem in horizontal layout.
-
- + +
Screen Reader
+

+ Dock component uses the menu role with the aria-orientation and the value to describe the menu can either be provided with aria-labelledby or aria-label props. Each list item has a{' '} + presentation role whereas anchor elements have a menuitem role with aria-label referring to the label of the item and aria-disabled defined if the item is disabled. +

+ +
Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Add focus to the first item if focus moves in to the menu. If the focus is already within the menu, focus moves to the next focusable item in the page tab sequence.
+ shift + tab + Add focus to the last item if focus moves in to the menu. If the focus is already within the menu, focus moves to the previous focusable item in the page tab sequence.
+ enter + Activates the focused menuitem.
+ space + Activates the focused menuitem.
+ down arrow + Moves focus to the next menuitem in vertical layout.
+ up arrow + Moves focus to the previous menuitem in vertical layout.
+ home + Moves focus to the first menuitem in horizontal layout.
+ end + Moves focus to the last menuitem in horizontal layout.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'DockDemo', sources: sources, service: 'NodeService, PhotoService', extFiles: extFiles }) - } - + {useLiveEditorTabs({ name: 'DockDemo', sources: sources, service: 'NodeService, PhotoService', extFiles: extFiles })}
- ) -}) + ); +}); export default DockDoc; diff --git a/components/doc/dropdown/index.js b/components/doc/dropdown/index.js index f091e12435..af9b918cd2 100644 --- a/components/doc/dropdown/index.js +++ b/components/doc/dropdown/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const DropdownDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -218,7 +217,7 @@ export class DropdownDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState, useEffect, useRef } from 'react'; @@ -411,7 +410,7 @@ const DropdownDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState, useEffect, useRef } from 'react'; @@ -604,7 +603,7 @@ const DropdownDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -801,7 +800,7 @@ const DropdownDemo = () => { } ` } - } + }; const extFiles = { 'demo/DropdownDemo.css': { @@ -815,35 +814,38 @@ const DropdownDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Dropdown } from 'primereact/dropdown'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

SelectButton is used as a controlled component with value and onChange properties along with the options collection. There are two alternatives - of how to define the options property; One way is providing a collection of SelectItem instances having label-value pairs - whereas other way is providing an array of arbitrary objects along with the optionLabel and optionValue properties to specify the label/value field pair. In addition, - options can be simple primitive values such as a string array, in this case no optionLabel or optionValue is necessary.

- -

Options as SelectItems

- -{` +

+ SelectButton is used as a controlled component with value and onChange properties along with the options collection. There are two alternatives of how to define the options property; One way is providing a + collection of SelectItem instances having label-value pairs whereas other way is providing an array of arbitrary objects along with the optionLabel and optionValue properties to specify the label/value + field pair. In addition, options can be simple primitive values such as a string array, in this case no optionLabel or optionValue is necessary. +

+ +

+ Options as SelectItems +

+ + {` const citySelectItems = [ {label: 'New York', value: 'NY'}, {label: 'Rome', value: 'RM'}, @@ -852,17 +854,19 @@ const citySelectItems = [ {label: 'Paris', value: 'PRS'} ]; `} - +
- -{` + + {` setCity(e.value)} placeholder="Select a City"/> `} - + -

Options as any type

- -{` +

+ Options as any type +

+ + {` const cities = [ {name: 'New York', code: 'NY'}, {name: 'Rome', code: 'RM'}, @@ -871,42 +875,48 @@ const cities = [ {name: 'Paris', code: 'PRS'} ]; `} - +
- -{` + + {` setCity(e.value)} placeholder="Select a City"/> setCity(e.value)} placeholder="Select a City"/> `} - -

When optionValue is not defined, value of an option refers to the option object itself.

+
+

+ When optionValue is not defined, value of an option refers to the option object itself. +

Placeholder

Common pattern is providing an empty option as the placeholder when using native selects, however Dropdown has built-in support using the placeholder option so it is suggested to use it instead of creating an empty option.

Filtering
-

Options can be filtered using an input field in the overlay by enabling the filter property. By default filtering is done against - label of the items and filterBy property is available to choose one or more properties of the options. In addition filterMatchMode can be utilized - to define the filtering algorithm, valid options are "contains" (default), "startsWith", "endsWith", "equals" and "notEquals".

+

+ Options can be filtered using an input field in the overlay by enabling the filter property. By default filtering is done against label of the items and filterBy property is available to choose one or more + properties of the options. In addition filterMatchMode can be utilized to define the filtering algorithm, valid options are "contains" (default), "startsWith", "endsWith", "equals" and "notEquals". +

- -{` + + {` setSelectedCountry(e.value)} optionLabel="name" filter showClear filterBy="name" placeholder="Select a Country" itemTemplate={countryOptionTemplate} /> `} - +
Custom Content
-

Label of an option is used as the display text of an item by default, for custom content support define an itemTemplate function that gets the option instance as a parameter and returns the content. For custom filter support define a filterTemplate function that gets the option instance as a parameter and returns the content for the filter element.

- -{` +

+ Label of an option is used as the display text of an item by default, for custom content support define an itemTemplate function that gets the option instance as a parameter and returns the content. For custom filter + support define a filterTemplate function that gets the option instance as a parameter and returns the content for the filter element. +

+ + {` setSelectedCountry(e.value)} optionLabel="name" placeholder="Select a Country" valueTemplate={selectedCountryTemplate} itemTemplate={countryOptionTemplate} filter filterTemplate={filterTemplate}/> `} - +
- -{` + + {` const [filterValue, setFilterValue] = useState(''); const filterInputRef = useRef(); @@ -959,12 +969,14 @@ const myFilterFunction = (event, options) => { options.filter(event); } `} - +
Grouping
-

Options groups are specified with the optionGroupLabel and optionGroupChildren properties.

- -{` +

+ Options groups are specified with the optionGroupLabel and optionGroupChildren properties. +

+ + {` const groupedCities = [ { label: 'Germany', code: 'DE', @@ -995,16 +1007,16 @@ const groupedCities = [ } ]; `} - +
- -{` + + {` setSelectedGroupedCity(e.value)} optionLabel="label" optionGroupLabel="label" optionGroupChildren="items" /> `} - +
SelectItem API
-
- +
+
@@ -1050,8 +1062,8 @@ const groupedCities = [
Properties

Any valid attribute is passed to the root element implicitly, extended properties are as follows;

-
-
Name
+
+
@@ -1233,7 +1245,9 @@ const groupedCities = [ - + @@ -1323,7 +1337,13 @@ const groupedCities = [ - + @@ -1341,15 +1361,17 @@ const groupedCities = [ - +
NameappendTo DOM element | string document.bodyDOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. + DOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. +
tabIndextransitionOptions object nullThe properties of CSSTransition can be customized, except for "nodeRef" and "in" properties. + The properties of{' '} + + CSSTransition + {' '} + can be customized, except for "nodeRef" and "in" properties. +
dropdownIconvirtualScrollerOptions object nullWhether to use the virtualScroller feature. The properties of VirtualScroller component can be used like an object in it. + Whether to use the virtualScroller feature. The properties of VirtualScroller component can be used like an object in it. +
Events
-
- +
+
@@ -1360,8 +1382,10 @@ const groupedCities = [ - + @@ -1386,8 +1410,10 @@ const groupedCities = [ - + @@ -1395,8 +1421,8 @@ const groupedCities = [
Methods
-
-
Name
onChangeevent.originalEvent: Original event
- event.value: Value of the checkbox
+ event.originalEvent: Original event
+ event.value: Value of the checkbox{' '} +
Callback to invoke on value change
onFilterevent.originalEvent: Original event
- event.filter: Value of the filter input
+ event.originalEvent: Original event
+ event.filter: Value of the filter input +
Callback to invoke when the value is filtered.
+
+
@@ -1430,9 +1456,11 @@ const groupedCities = [
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -1485,147 +1513,187 @@ const groupedCities = [
Accessibility
- -
Screen Reader
-

Value to describe the component can either be provided with aria-labelledby or aria-label props. The dropdown element has a combobox role - in addition to aria-haspopup and aria-expanded attributes. If the editable option is enabled aria-autocomplete is also added. - The relation between the combobox and the popup is created with aria-controls and aria-activedescendant attribute is used - to instruct screen reader which option to read during keyboard navigation within the popup list.

-

The popup list has an id that refers to the aria-controls attribute of the combobox element and uses listbox as the role. Each list item has an option role, an id to match the aria-activedescendant of the input element along with aria-label, aria-selected and aria-disabled attributes.

- -

If filtering is enabled, filterInputProps can be defined to give aria-* props to the filter input element.

- -{` + +
Screen Reader
+

+ Value to describe the component can either be provided with aria-labelledby or aria-label props. The dropdown element has a combobox role in addition to aria-haspopup and aria-expanded{' '} + attributes. If the editable option is enabled aria-autocomplete is also added. The relation between the combobox and the popup is created with aria-controls and aria-activedescendant attribute is used + to instruct screen reader which option to read during keyboard navigation within the popup list. +

+

+ The popup list has an id that refers to the aria-controls attribute of the combobox element and uses listbox as the role. Each list item has an option role, an id to match the{' '} + aria-activedescendant of the input element along with aria-label, aria-selected and aria-disabled attributes. +

+ +

+ If filtering is enabled, filterInputProps can be defined to give aria-* props to the filter input element. +

+ + {` Options `} - -
Closed State Keyboard Support
-
-
Name
- - - - - - - - - - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus to the dropdown element.
spaceOpens the popup and moves visual focus to the selected option, if there is none then first option receives the focus.
down arrowOpens the popup and moves visual focus to the selected option, if there is none then first option receives the focus.
up arrowOpens the popup and moves visual focus to the selected option, if there is none then last option receives the focus.
-
+ +
Closed State Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the dropdown element.
+ space + Opens the popup and moves visual focus to the selected option, if there is none then first option receives the focus.
+ down arrow + Opens the popup and moves visual focus to the selected option, if there is none then first option receives the focus.
+ up arrow + Opens the popup and moves visual focus to the selected option, if there is none then last option receives the focus.
+
-
Popup Keyboard Support
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus to the next focusable element in the popup, if there is none then first focusable element receives the focus.
shift + tabMoves focus to the previous focusable element in the popup, if there is none then last focusable element receives the focus.
enterSelects the focused option and closes the popup.
spaceSelects the focused option and closes the popup.
escapeCloses the popup, moves focus to the dropdown element.
down arrowMoves focus to the next option, if there is none then visual focus does not change.
up arrowMoves focus to the previous option, if there is none then visual focus does not change.
right arrowIf the dropdown is editable, removes the visual focus from the current option and moves input cursor to one character left.
left arrowIf the dropdown is editable, removes the visual focus from the current option and moves input cursor to one character right.
homeIf the dropdown is editable, moves input cursor at the end, if not then moves focus to the first option.
endIf the dropdown is editable, moves input cursor at the beginning, if not then moves focus to the last option.
any printable characterMoves focus to the option whose label starts with the characters being typed if dropdown is not editable.
-
+
Popup Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the next focusable element in the popup, if there is none then first focusable element receives the focus.
+ shift + tab + Moves focus to the previous focusable element in the popup, if there is none then last focusable element receives the focus.
+ enter + Selects the focused option and closes the popup.
+ space + Selects the focused option and closes the popup.
+ escape + Closes the popup, moves focus to the dropdown element.
+ down arrow + Moves focus to the next option, if there is none then visual focus does not change.
+ up arrow + Moves focus to the previous option, if there is none then visual focus does not change.
+ right arrow + If the dropdown is editable, removes the visual focus from the current option and moves input cursor to one character left.
+ left arrow + If the dropdown is editable, removes the visual focus from the current option and moves input cursor to one character right.
+ home + If the dropdown is editable, moves input cursor at the end, if not then moves focus to the first option.
+ end + If the dropdown is editable, moves input cursor at the beginning, if not then moves focus to the last option.
+ any printable character + Moves focus to the option whose label starts with the characters being typed if dropdown is not editable.
+
-
Filter Input Keyboard Support
-
- - - - - - - - - - - - - - - - - -
KeyFunction
enterCloses the popup and moves focus to the dropdown element.
escapeCloses the popup and moves focus to the dropdown element.
-
- +
Filter Input Keyboard Support
+
+ + + + + + + + + + + + + + + + + +
KeyFunction
+ enter + Closes the popup and moves focus to the dropdown element.
+ escape + Closes the popup and moves focus to the dropdown element.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'DropdownDemo', sources: sources, extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'DropdownDemo', sources: sources, extFiles: extFiles })}
- ) -}) + ); +}); export default DropdownDoc; diff --git a/components/doc/editor/index.js b/components/doc/editor/index.js index 66e89b4b8d..f120b53507 100644 --- a/components/doc/editor/index.js +++ b/components/doc/editor/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const EditorDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -52,7 +51,7 @@ export class EditorDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -88,7 +87,7 @@ const EditorDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -124,7 +123,7 @@ const EditorDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -165,41 +164,46 @@ const EditorDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Editor } from 'primereact/editor'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

Editor is used as a controlled component with value and onTextChange properties.

+

+ Editor is used as a controlled component with value and onTextChange properties. +

- -{` + + {` setText(e.htmlValue)} /> `} - +
Toolbar
-

Editor provides a default toolbar with common options, to customize it define your elements with the headerTemplate. Refer to Quill documentation for available controls.

+

+ Editor provides a default toolbar with common options, to customize it define your elements with the headerTemplate. Refer to Quill documentation for available + controls. +

- -{` + + {` const header = ( @@ -210,12 +214,12 @@ const header = ( setText(e.htmlValue)} headerTemplate={header}/> `} - +
Properties

Any valid attribute is passed to the root element implicitly, extended properties are as follows;

-
- +
+
@@ -265,13 +269,17 @@ const header = ( - + - + @@ -284,8 +292,8 @@ const header = (
Events
-
-
Namemodules object nullModules configuration, see here for available options. + Modules configuration, see here for available options. +
formats string[] nullWhitelist of formats to display, see here for available options. + Whitelist of formats to display, see here for available options. +
headerTemplate
+
+
@@ -296,17 +304,27 @@ const header = ( - + - + @@ -318,12 +336,16 @@ const header = (
Name
onTextChangeevent.delta: Representation of the change.
- event.source: Source of change. Will be either "user" or "api".
- event.htmlValue: Current value as html.
- event.textValue: Current value as text.
+ event.delta: Representation of the change. +
+ event.source: Source of change. Will be either "user" or "api". +
+ event.htmlValue: Current value as html. +
+ event.textValue: Current value as text. +
+
Callback to invoke when text of editor changes.
onSelectionChangeevent.range: Object with index and length keys indicating where the selection exists.
- event.oldRange: Object with index and length keys indicating where the previous selection was.
- event.source: Source of change. Will be either "user" or "api".
+ event.range: Object with index and length keys indicating where the selection exists. +
+ event.oldRange: Object with index and length keys indicating where the previous selection was. +
+ event.source: Source of change. Will be either "user" or "api". +
Callback to invoke when selected text of editor changes.
-

Refer to Quill documentation for more information.

+

+ Refer to Quill documentation for more information. +

Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
- +

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -348,26 +370,28 @@ const header = (
Accessibility
- -

Quill performs generally well in terms of accessibility. The elements in the toolbar can be tabbed and have the necessary ARIA roles/attributes for screen readers. One known limitation is the lack of arrow key support - for dropdowns in the toolbar that may be overcome with a custom toolbar.

-
+ +

+ Quill performs generally well in terms of accessibility. The elements in the toolbar can be tabbed and have the necessary ARIA roles/attributes for screen readers. One known limitation is the lack of arrow key support for{' '} + dropdowns in the toolbar that may be overcome with a custom toolbar. +

+
Dependencies
-

Quill Editor 1.3+.

+

+ Quill Editor 1.3+. +

Resources of quill needs to be added to your application.

- -{` + + {` npm install quill `} - + - { - useLiveEditorTabs({ name: 'EditorDemo', sources: sources, dependencies: { "quill": "1.3.7" } }) - } + {useLiveEditorTabs({ name: 'EditorDemo', sources: sources, dependencies: { quill: '1.3.7' } })} - ) -}) + ); +}); export default EditorDoc; diff --git a/components/doc/fieldset/index.js b/components/doc/fieldset/index.js index dce9f416d5..084ffc2239 100644 --- a/components/doc/fieldset/index.js +++ b/components/doc/fieldset/index.js @@ -5,10 +5,9 @@ import { useLiveEditorTabs } from '../common/liveeditor'; import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; -export const FieldsetDoc = memo(() => { - +export const FieldsetDoc = memo(() => { const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -42,7 +41,7 @@ export class FieldsetDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React from 'react'; @@ -73,7 +72,7 @@ const FieldsetDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React from 'react'; @@ -104,7 +103,7 @@ const FieldsetDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -138,31 +137,31 @@ const FieldsetDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Fieldset } from 'primereact/fieldset'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started

Panel is a container component that accepts content as its children.

- -{` + + {`

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. @@ -170,16 +169,22 @@ import { Fieldset } from 'primereact/fieldset'; cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

`} -
+
-

Instead of simple strings, legend propery also can be used to provide custom content as JSX.

+

+ Instead of simple strings, legend propery also can be used to provide custom content as JSX. +

Toggleable
-

Content of the fieldset can be expanded and collapsed using toggleable option. A toggleable fieldset can either be used as a Controlled or Uncontrolled component.

+

+ Content of the fieldset can be expanded and collapsed using toggleable option. A toggleable fieldset can either be used as a Controlled or Uncontrolled component. +

-

In controlled mode, collapsed and onToggle properties need to be defined to control the collapsed state.

- -{` +

+ In controlled mode, collapsed and onToggle properties need to be defined to control the collapsed state. +

+ + {`
this.setState({panelCollapsed: e.value})}>

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. @@ -187,13 +192,15 @@ import { Fieldset } from 'primereact/fieldset'; cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

`} -
+
-

In uncontrolled mode, only toggleable property needs to be enabled. Initial state can be still be provided using the collapsed property in uncontrolled mode however - it is evaluated at initial rendering and ignored in further updates. If you programmatically need to update the collapsed state, prefer to use the component as controlled.

+

+ In uncontrolled mode, only toggleable property needs to be enabled. Initial state can be still be provided using the collapsed property in uncontrolled mode however it is evaluated at initial rendering and + ignored in further updates. If you programmatically need to update the collapsed state, prefer to use the component as controlled. +

- -{` + + {`

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. @@ -201,11 +208,11 @@ import { Fieldset } from 'primereact/fieldset'; cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

`} -
+
Properties
-
-
Name
+
+
@@ -255,15 +262,21 @@ import { Fieldset } from 'primereact/fieldset'; - +
NametransitionOptions object nullThe properties of CSSTransition can be customized, except for "nodeRef" and "in" properties. + The properties of{' '} + + CSSTransition + {' '} + can be customized, except for "nodeRef" and "in" properties. +
Events
-
- +
+
@@ -284,9 +297,10 @@ import { Fieldset } from 'primereact/fieldset'; - + @@ -299,9 +313,11 @@ import { Fieldset } from 'primereact/fieldset';
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
onToggleevent.originalEvent: browser event
- event.value: Collapsed state as a boolean -
+ event.originalEvent: browser event
+ event.value: Collapsed state as a boolean +
Callback to invoke when a tab gets expanded.
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -330,55 +346,63 @@ import { Fieldset } from 'primereact/fieldset';
Accessibility
- -
Screen Reader
-

Fieldset component uses the semantic fieldset element. When toggleable option is enabled, a clickable element with button role is included inside the legend element, this button - has aria-controls to define the id of the content section along with aria-expanded for the visibility state. The value to read the button - defaults to the value of the legend property and can be customized by defining an aria-label or aria-labelledby via the toggleButtonProps property.

-

The content uses region, defines an id that matches the aria-controls of the content toggle button and aria-labelledby referring to the id of the header.

+ +
Screen Reader
+

+ Fieldset component uses the semantic fieldset element. When toggleable option is enabled, a clickable element with button role is included inside the legend element, this button has{' '} + aria-controls to define the id of the content section along with aria-expanded for the visibility state. The value to read the button defaults to the value of the legend property and can be customized + by defining an aria-label or aria-labelledby via the toggleButtonProps property. +

+

+ The content uses region, defines an id that matches the aria-controls of the content toggle button and aria-labelledby referring to the id of the header. +

-
Content Toggle Button Keyboard Support
-
-
Name
- - - - - - - - - - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus to the next the focusable element in the page tab sequence.
shift + tabMoves focus to the previous the focusable element in the page tab sequence.
enterToggles the visibility of the content.
spaceToggles the visibility of the content.
-
- +
Content Toggle Button Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the next the focusable element in the page tab sequence.
+ shift + tab + Moves focus to the previous the focusable element in the page tab sequence.
+ enter + Toggles the visibility of the content.
+ space + Toggles the visibility of the content.
+
+
Dependencies

None.

-
- { - useLiveEditorTabs({ name: 'FieldsetDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'FieldsetDemo', sources: sources })}
); - -}) +}); export default FieldsetDoc; diff --git a/components/doc/fileupload/index.js b/components/doc/fileupload/index.js index f49dab5669..430b9f853d 100644 --- a/components/doc/fileupload/index.js +++ b/components/doc/fileupload/index.js @@ -5,9 +5,8 @@ import { useLiveEditorTabs } from '../common/liveeditor'; import { CodeHighlight } from '../common/codehighlight'; const FileUploadDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -176,7 +175,7 @@ export class FileUploadDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useRef, useState } from 'react'; @@ -321,7 +320,7 @@ export const FileUploadDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useRef, useState } from 'react'; @@ -466,7 +465,7 @@ export const FileUploadDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -615,8 +614,8 @@ const FileUploadDemo = () => { ) } ` - } - }; + } + }; const extFiles = { 'public/upload.php': { @@ -627,119 +626,129 @@ echo '

Fake Upload Process

'; ?> ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { FileUpload } from 'primereact/fileupload'; `} - +
Import via CDN
- -{` + + {` `} - - -
Getting Started
-

FileUpload requires a url property as the upload target and a name to identify the files at backend.

- -{` + + +
Getting Started
+

+ FileUpload requires a url property as the upload target and a name to identify the files at backend. +

+ + {` `} - +
-
Multiple Uploads
-

Only one file can be selected at a time by default, to allow selecting multiple files at once enable multiple option.

+
Multiple Uploads
+

+ Only one file can be selected at a time by default, to allow selecting multiple files at once enable multiple option. +

- -{` + + {` `} - + -
DragDrop
-

File selection can also be done by dragging and dropping from the filesystem to the content section of the component.

+
DragDrop
+

File selection can also be done by dragging and dropping from the filesystem to the content section of the component.

-
Auto Uploads
-

When auto property is enabled, upload begins as soon as file selection is completed or a file is dropped on the drop area.

+
Auto Uploads
+

+ When auto property is enabled, upload begins as soon as file selection is completed or a file is dropped on the drop area. +

- -{` + + {` `} - - -
File Types
-

Selectable file types can be restricted with accept property, example below only allows images to be uploaded. Read more about other possible values here.

- -{` + + +
File Types
+

+ Selectable file types can be restricted with accept property, example below only allows images to be uploaded. Read more about other possible values{' '} + here. +

+ + {` `} - +
-
File Size
-

Maximium file size can be restricted using maxFileSize property defined in bytes.

+
File Size
+

+ Maximium file size can be restricted using maxFileSize property defined in bytes. +

- -{` + + {` `} - - -

In order to customize the default messages use invalidFileSizeMessageSummary and invalidFileSizeMessageDetail options. In summary messages, {0} placeholder refers to the filename and in detail message, the file size.

-
    -
  • - invalidFileSizeMessageSummary: '{0}: Invalid file size, ' -
  • -
  • - invalidFileSizeMessageDetail: string = 'maximum upload size is {0}.' -
  • -
- -
Request Customization
-

XHR request to upload the files can be customized using the onBeforeUpload callback that passes the xhr instance and FormData object as event parameters.

- -
Basic UI
-

FileUpload basic mode provides a simpler UI as an alternative to advanced mode.

- - -{` + + +

+ In order to customize the default messages use invalidFileSizeMessageSummary and invalidFileSizeMessageDetail options. In summary messages, {0} placeholder refers to the filename and in detail message, the file + size. +

+
    +
  • invalidFileSizeMessageSummary: '{0}: Invalid file size, '
  • +
  • invalidFileSizeMessageDetail: string = 'maximum upload size is {0}.'
  • +
+ +
Request Customization
+

XHR request to upload the files can be customized using the onBeforeUpload callback that passes the xhr instance and FormData object as event parameters.

+ +
Basic UI
+

FileUpload basic mode provides a simpler UI as an alternative to advanced mode.

+ + + {` `} - +
-
Custom Upload
-

Uploading implementation can be overriden by enabling customUpload property and defining a custom upload handler event.

- -{` +
Custom Upload
+

Uploading implementation can be overriden by enabling customUpload property and defining a custom upload handler event.

+ + {` `} - - -{` + + + {` const myUploader = (event) => { //event.files == files to upload } `} - +
-
ItemTemplate
-

Used to create custom item elements in the container.

- -{` +
ItemTemplate
+

Used to create custom item elements in the container.

+ + {` `} - - -{` + + + {` const customItemTemplate = (file, props) => { // file: Current file object. // options.onRemove: Event used to remove current file in the container. @@ -754,24 +763,24 @@ const customItemTemplate = (file, props) => { // options.props: component props. } `} - +
-
Button Options
-

Used to customize choose, upload and cancel buttons.

- -{` +
Button Options
+

Used to customize choose, upload and cancel buttons.

+ + {` const chooseOptions = {label: 'Choose', icon: 'pi pi-fw pi-plus'}; const uploadOptions = {label: 'Uplaod', icon: 'pi pi-upload', className: 'p-button-success'}; const cancelOptions = {label: 'Cancel', icon: 'pi pi-times', className: 'p-button-danger'}; `} - - -{` + + + {` `} - - -{` + + + {` const buttonOptions = { // label: The label of button. // icon: The icon of button. @@ -779,353 +788,371 @@ const buttonOptions = { // style: Style of button. } `} - - -
Properties
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDefaultDescription
idstringnullUnique identifier of the element.
namestringnullName of the request parameter to identify the files at backend.
urlstringnullRemote url to upload the files.
modestringadvancedDefines the UI of the component, possible values are "advanced" and "basic".
multiplebooleanfalseUsed to select multiple files at once from file dialog.
acceptstringfalsePattern to restrict the allowed file types such as "image/*".
disabledbooleanfalseDisables the upload functionality.
autobooleanfalseWhen enabled, upload begins automatically after selection is completed.
maxFileSizenumbernullMaximum file size allowed in bytes.
invalidFileSizeMessageSummarystring"{0}: Invalid file size, "Summary message of the invalid fize size.
invalidFileSizeMessageDetailstring"maximum upload size is {0}."Detail message of the invalid fize size.
styleobjectnullInline style of the component.
classNamestringnullStyle class of the component.
withCredentialsbooleanfalseCross-site Access-Control requests should be made using credentials such as cookies, authorization headers or TLS client certificates.
previewWidthnumber50Width of the image thumbnail in pixels.
chooseLabelstringnullLabel of the choose button. Defaults to global value in Locale configuration.
uploadLabelstringnullLabel of the upload button. Defaults to global value in Locale configuration.
cancelLabelstringnullLabel of the cancel button. Defaults to global value in Locale configuration.
chooseOptionsobject (OptionsType)nullOptions used to customize the choose button. These options have "label", "icon", "className" and "style" properties.
uploadOptionsobject (OptionsType)nullOptions used to customize the upload button. These options have "label", "icon", "className" and "style" properties.
cancelOptionsobject (OptionsType)nullOptions used to customize the cancel button. These options have "label", "icon", "className" and "style" properties.
customUploadbooleanfalseWhether to use the default upload or a manual implementation defined in uploadHandler callback.
emptyTemplateanynullThe template of empty content in the container.
progressBarTemplateanynullThe template of progressBar content in the container.
itemTemplateanynullThe template of each item content in the container.
headerTemplateanynullThe template of the header.
headerStyleobjectnullInline style of the header.
headerClassNamestringnullStyle class of the header.
contentStyleobjectnullInline style of the content.
contentClassNamestringnullStyle class of the content.
-
- -
Events
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameParametersDescription
onBeforeUploadevent.xhr: XmlHttpRequest instance.
- event.formData: FormData object.
Callback to invoke before file upload begins to customize the request - such as post parameters before the files.
onBeforeSendevent.xhr: XmlHttpRequest instance.
- event.formData: FormData object.
Callback to invoke before file send begins to customize the request - such as adding headers.
onBeforeDropevent: DragEvent instance.Callback to invoke before files dropped. Return false from callback to prevent drop.
onBeforeSelectevent.originalEvent: Original browser event.
- event.target.files: List of selected files.
Callback to invoke before files are selected. Return false from callback to prevent selection.
onUploadevent.xhr: XmlHttpRequest instance.
- event.files: Uploaded files.
Callback to invoke when file upload is complete.
onErrorevent.xhr: XmlHttpRequest instance.
- event.files: Files that are not uploaded.
Callback to invoke if file upload fails.
onClear-Callback to invoke when files in queue are removed without uploading.
onSelectevent.originalEvent: Original browser event.
- event.target.files: List of selected files.
Callback to invoke when files are selected.
onProgressevent.originalEvent: Original browser event.
- event.progress: Calculated progress value.
Callback to invoke when files are being uploaded.
onValidationFailfile: Invalid file.Callback to invoke when a validation file fails.
uploadHandlerevent.files: List of selected files.
- event.options: Handler options.
Callback to invoke in custom upload mode to upload the files manually.
onRemoveevent.originalEvent: Original browser event.
- event.file: Selected file.
Callback to invoke when a file is removed without uploading using clear button of a file.
-
- -
Methods
-
- - - - - - - - - - - - - - - - - - - - -
NameParametersDescription
upload-Uploads the selected files.
clear-Clears the files list.
-
- -
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
- - - - - - - - - - - - - - - - - - - - - -
NameElement
p-fileuploadContainer element.
p-fileupload-buttonbarHeader containing the buttons.
p-fileupload-contentContent section.
- -
Dependencies
-

None.

-
- +
+ +
Properties
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
idstringnullUnique identifier of the element.
namestringnullName of the request parameter to identify the files at backend.
urlstringnullRemote url to upload the files.
modestringadvancedDefines the UI of the component, possible values are "advanced" and "basic".
multiplebooleanfalseUsed to select multiple files at once from file dialog.
acceptstringfalsePattern to restrict the allowed file types such as "image/*".
disabledbooleanfalseDisables the upload functionality.
autobooleanfalseWhen enabled, upload begins automatically after selection is completed.
maxFileSizenumbernullMaximum file size allowed in bytes.
invalidFileSizeMessageSummarystring"{0}: Invalid file size, "Summary message of the invalid fize size.
invalidFileSizeMessageDetailstring"maximum upload size is {0}."Detail message of the invalid fize size.
styleobjectnullInline style of the component.
classNamestringnullStyle class of the component.
withCredentialsbooleanfalseCross-site Access-Control requests should be made using credentials such as cookies, authorization headers or TLS client certificates.
previewWidthnumber50Width of the image thumbnail in pixels.
chooseLabelstringnullLabel of the choose button. Defaults to global value in Locale configuration.
uploadLabelstringnullLabel of the upload button. Defaults to global value in Locale configuration.
cancelLabelstringnullLabel of the cancel button. Defaults to global value in Locale configuration.
chooseOptionsobject (OptionsType)nullOptions used to customize the choose button. These options have "label", "icon", "className" and "style" properties.
uploadOptionsobject (OptionsType)nullOptions used to customize the upload button. These options have "label", "icon", "className" and "style" properties.
cancelOptionsobject (OptionsType)nullOptions used to customize the cancel button. These options have "label", "icon", "className" and "style" properties.
customUploadbooleanfalseWhether to use the default upload or a manual implementation defined in uploadHandler callback.
emptyTemplateanynullThe template of empty content in the container.
progressBarTemplateanynullThe template of progressBar content in the container.
itemTemplateanynullThe template of each item content in the container.
headerTemplateanynullThe template of the header.
headerStyleobjectnullInline style of the header.
headerClassNamestringnullStyle class of the header.
contentStyleobjectnullInline style of the content.
contentClassNamestringnullStyle class of the content.
+
+ +
Events
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameParametersDescription
onBeforeUpload + event.xhr: XmlHttpRequest instance.
+ event.formData: FormData object. +
Callback to invoke before file upload begins to customize the request such as post parameters before the files.
onBeforeSend + event.xhr: XmlHttpRequest instance.
+ event.formData: FormData object. +
Callback to invoke before file send begins to customize the request such as adding headers.
onBeforeDropevent: DragEvent instance.Callback to invoke before files dropped. Return false from callback to prevent drop.
onBeforeSelect + event.originalEvent: Original browser event.
+ event.target.files: List of selected files. +
Callback to invoke before files are selected. Return false from callback to prevent selection.
onUpload + event.xhr: XmlHttpRequest instance. +
+ event.files: Uploaded files. +
Callback to invoke when file upload is complete.
onError + event.xhr: XmlHttpRequest instance. +
+ event.files: Files that are not uploaded. +
Callback to invoke if file upload fails.
onClear-Callback to invoke when files in queue are removed without uploading.
onSelect + event.originalEvent: Original browser event.
+ event.target.files: List of selected files. +
Callback to invoke when files are selected.
onProgress + event.originalEvent: Original browser event.
+ event.progress: Calculated progress value. +
Callback to invoke when files are being uploaded.
onValidationFailfile: Invalid file.Callback to invoke when a validation file fails.
uploadHandler + event.files: List of selected files. +
+ event.options: Handler options. +
Callback to invoke in custom upload mode to upload the files manually.
onRemove + event.originalEvent: Original browser event.
+ event.file: Selected file. +
Callback to invoke when a file is removed without uploading using clear button of a file.
+
+ +
Methods
+
+ + + + + + + + + + + + + + + + + + + + +
NameParametersDescription
upload-Uploads the selected files.
clear-Clears the files list.
+
+ +
Styling
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+ + + + + + + + + + + + + + + + + + + + + +
NameElement
p-fileuploadContainer element.
p-fileupload-buttonbarHeader containing the buttons.
p-fileupload-contentContent section.
+ +
Dependencies
+

None.

+
- { - useLiveEditorTabs({ name: 'FileUploadDemo', sources: sources, extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'FileUploadDemo', sources: sources, extFiles: extFiles })}
); -}) +}); export default FileUploadDoc; diff --git a/components/doc/floatlabel/index.js b/components/doc/floatlabel/index.js index 4f12e69041..68f29ebbfa 100644 --- a/components/doc/floatlabel/index.js +++ b/components/doc/floatlabel/index.js @@ -3,9 +3,8 @@ import { TabView } from '../../lib/tabview/TabView'; import { useLiveEditorTabs } from '../common/liveeditor'; const FloatLabelDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -264,7 +263,7 @@ export class FloatLabelDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState, useEffect } from 'react'; @@ -512,7 +511,7 @@ const FloatLabelDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState, useEffect } from 'react'; @@ -760,7 +759,7 @@ const FloatLabelDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -1025,18 +1024,13 @@ const FloatLabelDemo = () => { } ` } - } + }; return ( -
- - { - useLiveEditorTabs({ name: 'FloatLabelDemo', sources: sources, service: 'CountryService, NodeService', data: 'countries, treenodes' }) - } - +
+ {useLiveEditorTabs({ name: 'FloatLabelDemo', sources: sources, service: 'CountryService, NodeService', data: 'countries, treenodes' })}
); - -}) +}); export default FloatLabelDoc; diff --git a/components/doc/galleria/index.js b/components/doc/galleria/index.js index 4c4cbbe551..f44a3560c1 100644 --- a/components/doc/galleria/index.js +++ b/components/doc/galleria/index.js @@ -6,9 +6,8 @@ import { useLiveEditorTabs } from '../common/liveeditor'; import { DevelopmentSection } from '../common/developmentsection'; const GalleriaDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -52,10 +51,10 @@ export class GalleriaDemo extends Component { ); } ` - }, - 'hooks': { - tabName: 'Hooks Source', - content: ` + }, + hooks: { + tabName: 'Hooks Source', + content: ` import React, { useState, useEffect } from 'react'; import { PhotoService } from '../service/PhotoService'; import { Galleria } from 'primereact/galleria'; @@ -102,10 +101,10 @@ const GalleriaDemo = () => { ); } ` - }, - 'ts': { - tabName: 'TS Source', - content: ` + }, + ts: { + tabName: 'TS Source', + content: ` import React, { useState, useEffect } from 'react'; import { PhotoService } from '../service/PhotoService'; import { Galleria } from 'primereact/galleria'; @@ -152,14 +151,14 @@ const GalleriaDemo = () => { ); } ` - }, - 'browser': { - tabName: 'Browser Source', - imports: ` + }, + browser: { + tabName: 'Browser Source', + imports: ` `, - content: ` + content: ` const { useEffect, useState, useRef } = React; const { Galleria } = primereact.galleria; @@ -206,38 +205,38 @@ const GalleriaDemo = () => { ); } ` - } -} + } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Galleria } from 'primereact/galleria'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started

Galleria requires a value as an array of objects and can either be used as a Controlled or Uncontrolled component.

- -{` + + {` `} - - -{` + + + {` const itemTemplate = (item) => { // custom item content } @@ -246,29 +245,32 @@ const thumbnailTemplate = (item) => { // custom thumbnail content } `} - +
Items per page
-

Number of items per page is defined using the numVisible property.

- -{` +

+ Number of items per page is defined using the numVisible property. +

+ + {` `} - +
Responsive
-

For responsive design, numVisible can be defined using the responsiveOptions property that should be an array of - objects whose breakpoint defines the max-width to apply the settings.

- -{` +

+ For responsive design, numVisible can be defined using the responsiveOptions property that should be an array of objects whose breakpoint defines the max-width to apply the settings. +

+ + {` `} - +
- -{` + + {` const responsiveOptions = [ { breakpoint: '1024px', @@ -284,41 +286,47 @@ const responsiveOptions = [ } ]; `} - +
Header and Footer
-

Custom content projection is available using the header and footer properties.

- -{` +

+ Custom content projection is available using the header and footer properties. +

+ + {` Header}> `} - +
Controlled vs Uncontrolled
-

In controlled mode, activeIndex and onItemChange properties need to be defined to control the first visible item.

+

+ In controlled mode, activeIndex and onItemChange properties need to be defined to control the first visible item. +

- -{` + + {` setActiveIndex(e.index)}> `} - +
Uncontrolled
-

In uncontrolled mode, no additional properties are required. Initial item can be provided using the activeItemIndex property in uncontrolled mode however it is evaluated at initial rendering and ignored in further updates. If you programmatically - need to update the first visible item index, prefer to use the component as controlled.

+

+ In uncontrolled mode, no additional properties are required. Initial item can be provided using the activeItemIndex property in uncontrolled mode however it is evaluated at initial rendering and ignored in further + updates. If you programmatically need to update the first visible item index, prefer to use the component as controlled. +

- -{` + + {` `} - +
Properties
-
- +
+
@@ -500,21 +508,27 @@ const responsiveOptions = [ - +
NametransitionOptions object nullThe properties of CSSTransition can be customized, except for "nodeRef" and "in" properties. + The properties of{' '} + + CSSTransition + {' '} + can be customized, except for "nodeRef" and "in" properties. +
Events
-
- +
+
- - - - - + + + + + @@ -538,13 +552,13 @@ const responsiveOptions = [
Styling

Following is the list of structural style classes

-
-
NameParametersDescription
NameParametersDescription
+
+
- - - - + + + + @@ -590,23 +604,33 @@ const responsiveOptions = [
Accessibility
Screen Reader
-

Galleria uses region role and since any attribute is passed to the main container element, attributes such as aria-label and aria-roledescription can be used as well. The slides container has aria-live attribute - set as "polite" if galleria is not in autoplay mode, otherwise "off" would be the value in autoplay.

- -

A slide has a group role with an aria-label that refers to the aria.slideNumber property of the locale API. Similarly aria.slide is used as the aria-roledescription of the item. - Inactive slides are hidden from the readers with aria-hidden.

- -

Next and Previous navigators are button elements with aria-label attributes referring to the aria.nextPageLabel and aria.firstPageLabel properties of the locale API by default respectively, - you may still use your own aria roles and attributes as any valid attribute is passed to the button elements implicitly by using nextButtonProps and prevButtonProps.

- -

Quick navigation elements and thumnbails follow the tab pattern. They are placed inside an element with a tablist role whereas each item has a tab role with aria-selected and aria-controls attributes. - The aria-label attribute of a quick navigation item refers to the aria.pageLabel of the locale API. Current page is marked with aria-current.

- -

In full screen mode, modal element uses dialog role with aria-modal enabled. The close button retrieves aria-label from the aria.close property of the locale API.

+

+ Galleria uses region role and since any attribute is passed to the main container element, attributes such as aria-label and aria-roledescription can be used as well. The slides container has{' '} + aria-live attribute set as "polite" if galleria is not in autoplay mode, otherwise "off" would be the value in autoplay. +

+ +

+ A slide has a group role with an aria-label that refers to the aria.slideNumber property of the locale API. Similarly aria.slide is used as the aria-roledescription{' '} + of the item. Inactive slides are hidden from the readers with aria-hidden. +

+ +

+ Next and Previous navigators are button elements with aria-label attributes referring to the aria.nextPageLabel and aria.firstPageLabel properties of the locale API by + default respectively, you may still use your own aria roles and attributes as any valid attribute is passed to the button elements implicitly by using nextButtonProps and prevButtonProps. +

+ +

+ Quick navigation elements and thumnbails follow the tab pattern. They are placed inside an element with a tablist role whereas each item has a tab role with aria-selected and aria-controls{' '} + attributes. The aria-label attribute of a quick navigation item refers to the aria.pageLabel of the locale API. Current page is marked with aria-current. +

+ +

+ In full screen mode, modal element uses dialog role with aria-modal enabled. The close button retrieves aria-label from the aria.close property of the locale API. +

Next/Prev Keyboard Support
-
-
NameElement
NameElement
+
+
@@ -615,15 +639,21 @@ const responsiveOptions = [ - + - + - + @@ -631,8 +661,8 @@ const responsiveOptions = [
Quick Navigation Keyboard Support
-
-
Key
tab + tab + Moves focus through interactive elements in the carousel.
enter + enter + Activates navigation.
space + space + Activates navigation.
+
+
@@ -641,31 +671,45 @@ const responsiveOptions = [ - + - + - + - + - + - + - + @@ -676,12 +720,10 @@ const responsiveOptions = [
Dependencies

None.

- { - useLiveEditorTabs({ name: 'GalleriaDemo', sources: sources, service: 'PhotoService', data: 'photos' }) - } + {useLiveEditorTabs({ name: 'GalleriaDemo', sources: sources, service: 'PhotoService', data: 'photos' })} ); -}) +}); export default GalleriaDoc; diff --git a/components/doc/gmap/index.js b/components/doc/gmap/index.js index b0a1eb7ba0..8f9ddcb930 100644 --- a/components/doc/gmap/index.js +++ b/components/doc/gmap/index.js @@ -5,9 +5,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const GMapDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Sources', content: ` import React, { Component } from 'react'; @@ -162,7 +161,7 @@ export class GMapDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useEffect, useState, useRef } from 'react'; @@ -301,7 +300,7 @@ const GMapDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useEffect, useState, useRef } from 'react'; @@ -440,7 +439,7 @@ const GMapDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -584,7 +583,7 @@ const GMapDemo = () => { } ` } - } + }; const extFiles = { 'demo/GoogleMaps.js': { @@ -628,32 +627,32 @@ export const removeGoogleMaps = () => { }; ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { GMap } from 'primereact/gmap'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started

A map is initialized with options and dimensions. Refer to the google maps api for the list of available options.

- -{` + + {` const options = { center: {lat: 36.890257, lng: 30.707417}, zoom: 12 @@ -663,27 +662,26 @@ return ( ) `} - +
TypeScript

If you are using TypeScript you should install the Google Maps types.

- -{` + + {` // npm install types into devDependencies npm i -D @types/google.maps // yarn install types into devDependencies yarn add @types/google.maps --production=false `} - +
Overlays
-

GMap can display any type of overlay such as markers, polygons and circles. Overlay instances are bound using the overlays property array. Overlays are aware - of binding so whenever the array changes, gmap updates itself.

+

GMap can display any type of overlay such as markers, polygons and circles. Overlay instances are bound using the overlays property array. Overlays are aware of binding so whenever the array changes, gmap updates itself.

- -{` + + {` const options = { center: {lat: 36.890257, lng: 30.707417}, zoom: 12 @@ -705,13 +703,13 @@ return ( ) `} - +
Events

GMap provides common callbacks to hook into events including map click, overlay click and overlay dragging.

- -{` + + {` const onMapClick = (event) => { //event: MouseEvent of Google Maps api } @@ -741,14 +739,16 @@ return ( ) `} - +
Google Maps API
-

In case you need to access the map instance directly, use the getMap() method. In the following example, this.gmap.getMap() will provide the map instance. Alternative - is using onMapReady event as it passes the map instance as a parameter.

+

+ In case you need to access the map instance directly, use the getMap() method. In the following example, this.gmap.getMap() will provide the map instance. Alternative is using onMapReady event as it passes the map instance as + a parameter. +

- -{` + + {` const options = { center: {lat: 36.890257, lng: 30.707417}, zoom: 12 @@ -758,20 +758,20 @@ return ( ) `} - +
Properties
-
-
Key
tab + tab + Moves focus through the active slide link.
enter + enter + Activates the focused slide link.
space + space + Activates the focused slide link.
right arrow + right arrow + Moves focus to the next slide link.
left arrow + left arrow + Moves focus to the previous slide link.
home + home + Moves focus to the first slide link.
end + end + Moves focus to the last slide link.
+
+
- - - - - - + + + + + + - + @@ -801,8 +801,8 @@ return (
Events
-
-
NameTypeDefaultDescription
NameTypeDefaultDescription
options object
+
+
@@ -828,9 +828,11 @@ return ( - + map: Map instance
+ @@ -862,19 +864,18 @@ return (
Accessibility
-

Refer to the Google Maps documentation for more information about accessibility.

+

+ Refer to the Google Maps documentation for more information about accessibility. +

Dependencies

Google Maps script.

- - { - useLiveEditorTabs({ name: 'GMapDemo', sources: sources, extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'GMapDemo', sources: sources, extFiles: extFiles })} ); -}) +}); export default GMapDoc; diff --git a/components/doc/image/index.js b/components/doc/image/index.js index 5c92e51080..d9a4cb8ee6 100644 --- a/components/doc/image/index.js +++ b/components/doc/image/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const ImageDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -32,7 +31,7 @@ export class ImageDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React from 'react'; @@ -54,7 +53,7 @@ const ImageDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React from 'react'; @@ -76,7 +75,7 @@ const ImageDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -101,53 +100,56 @@ const ImageDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Image } from 'primereact/image'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

Image is used as the native img element and supports all properties that the native element has.

+

+ Image is used as the native img element and supports all properties that the native element has. +

- -{` + + {` `} - +
Preview

Preview mode displays a modal layer when the image is clicked that provides transformation options such as rotating and zooming.

Templating
-

An eye icon is displayed by default when the image is hovered in preview mode. Use thetemplateprop for custom content.

+

+ An eye icon is displayed by default when the image is hovered in preview mode. Use thetemplateprop for custom content. +

- -{` + + {` `} - - +
Properties

Image passes any valid attribute to the underlying img element, additional attribute is the following.

-
-
Name
onOverlayClickoriginalEvent: Google Maps MouseEvent
+
+ originalEvent: Google Maps MouseEvent
overlay: Clicked overlay
- map: Map instance
Callback to invoke when an overlay is clicked.
+
+
@@ -187,8 +189,8 @@ import { Image } from 'primereact/image';
Events

Any valid event like click and mouseover are passed to the underlying input element. Events below are the additional ones related to the preview functionality.

-
-
Name
+
+
@@ -217,9 +219,11 @@ import { Image } from 'primereact/image';
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -266,17 +270,23 @@ import { Image } from 'primereact/image';
Accessibility
Screen Reader
-

The preview button is a native button element with an aria-label that refers to the aria.zoomImage property of the locale API by default, with previewButtonProps - you may use your own aria roles and attributes as any valid attribute is passed to the button element implicitly.

+

+ The preview button is a native button element with an aria-label that refers to the aria.zoomImage property of the locale API by default, with previewButtonProps + you may use your own aria roles and attributes as any valid attribute is passed to the button element implicitly. +

-

When preview is active, dialog role with aria-modal is applied to the overlay image container.

+

+ When preview is active, dialog role with aria-modal is applied to the overlay image container. +

-

Button controls use aria.rotateRight, aria.rotateLeft, aria.zoomIn, aria.zoomOut and aria.close from the locale API as aria-label.

+

+ Button controls use aria.rotateRight, aria.rotateLeft, aria.zoomIn, aria.zoomOut and aria.close from the locale API as aria-label. +

ButtonBar Keyboard Support

When preview is activated, close button receives the initial focus.

-
-
Name
+
+
@@ -285,19 +295,27 @@ import { Image } from 'primereact/image'; - + - + - + - + @@ -309,12 +327,10 @@ import { Image } from 'primereact/image';

None.

- { - useLiveEditorTabs({ name: 'ImageDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'ImageDemo', sources: sources })} ); -}) +}); export default ImageDoc; diff --git a/components/doc/inplace/index.js b/components/doc/inplace/index.js index c526d29955..0e53d3b598 100644 --- a/components/doc/inplace/index.js +++ b/components/doc/inplace/index.js @@ -6,11 +6,10 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const InplaceDoc = memo(() => { - - const sources = { - 'class': { - tabName: 'Class Source', - content: ` + const sources = { + class: { + tabName: 'Class Source', + content: ` import React, { Component } from 'react'; import { Inplace, InplaceDisplay, InplaceContent } from 'primereact/inplace'; import { InputText } from 'primereact/inputtext'; @@ -83,7 +82,7 @@ export class InplaceDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -148,7 +147,7 @@ const InplaceDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -213,7 +212,7 @@ const InplaceDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -284,34 +283,35 @@ const InplaceDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Inplace } from 'primereact/inplace'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

Inplace requires InplaceDisplay and InplaceContent component as children to define the content to display in each state. Active state of the inplace - can either be managed as a Controlled or Uncontrolled component.

+

Inplace requires InplaceDisplay and InplaceContent component as children to define the content to display in each state. Active state of the inplace can either be managed as a Controlled or Uncontrolled component.

-

In controlled mode, active and onToggle properties need to be defined to control the active state.

- -{` +

+ In controlled mode, active and onToggle properties need to be defined to control the active state. +

+ + {` setActive(e.value)}> Click to Edit @@ -321,13 +321,15 @@ import { Inplace } from 'primereact/inplace'; `} - +
-

In uncontrolled mode, no additional properties are required. Initial state can be still be provided using the active property in uncontrolled mode however - it is evaluated at initial rendering and ignored in further updates. If you programmatically need to update the active state, prefer to use the component as controlled.

+

+ In uncontrolled mode, no additional properties are required. Initial state can be still be provided using the active property in uncontrolled mode however it is evaluated at initial rendering and ignored in further + updates. If you programmatically need to update the active state, prefer to use the component as controlled. +

- -{` + + {` Click to Edit @@ -337,12 +339,14 @@ import { Inplace } from 'primereact/inplace'; `} - +
Closable
-

closable property is handy within forms as it enables to get back to output mode after editing is completed using a button displayed next to the form field.

- -{` +

+ closable property is handy within forms as it enables to get back to output mode after editing is completed using a button displayed next to the form field. +

+ + {` Click to Edit @@ -352,13 +356,12 @@ import { Inplace } from 'primereact/inplace'; `} - +
Lazy Loading
-

Inplace allows lazy loading content so that the content gets initialized after getting opened instead of on load. Here is an example that loads, data of a table - if the user decides to open the inplace.

- -{` +

Inplace allows lazy loading content so that the content gets initialized after getting opened instead of on load. Here is an example that loads, data of a table if the user decides to open the inplace.

+ + {` const onOpen = () => { productService.getProductsSmall().then(data => setProducts(data)); } @@ -377,11 +380,11 @@ const onOpen = () => { `} - +
Properties
-
-
Key
tab + tab + Moves focus through button bar.
enter + enter + Activates the button.
space + space + Activates the button.
esc + esc + Closes the image preview.
+
+
@@ -432,8 +435,8 @@ const onOpen = () => {
Events
-
-
Name
+
+
@@ -454,9 +457,10 @@ const onOpen = () => { - + @@ -464,9 +468,11 @@ const onOpen = () => {
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
onToggleevent.originalEvent: browser event
- event.value: active state as a boolean -
+ event.originalEvent: browser event
+ event.value: active state as a boolean +
Callback to invoke when inplace is opened or closed.
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -491,66 +497,75 @@ const onOpen = () => {
Accessibility
- -
Screen Reader
-

Inplace component defines aria-live as "polite" by default, since any valid attribute is passed to the main container aria roles and attributes of the root element can be customized easily.

-

Display element uses button role in view mode by default, displayProps can be used for customizations like adding aria-label or aria-labelledby attributes - to describe the content of the view mode or even overriding the default role.

-

Closable inplace components displays a button with an aria-label that refers to the aria.close property of the locale API by default, you may use - closeButtonProps to customize the element and override the default aria-label.

- -
View Mode Keyboard Support
-
-
Name
- - - - - - - - - - - - -
KeyFunction
enterSwitches to content.
-
- -
Close Button Keyboard Support
-
- - - - - - - - - - - - - - - - - -
KeyFunction
enterSwitches to display.
spaceSwitches to display.
-
- + +
Screen Reader
+

+ Inplace component defines aria-live as "polite" by default, since any valid attribute is passed to the main container aria roles and attributes of the root element can be customized easily. +

+

+ Display element uses button role in view mode by default, displayProps can be used for customizations like adding aria-label or aria-labelledby attributes to describe the content of the view + mode or even overriding the default role. +

+

+ Closable inplace components displays a button with an aria-label that refers to the aria.close property of the locale API by default, you may use + closeButtonProps to customize the element and override the default aria-label. +

+ +
View Mode Keyboard Support
+
+ + + + + + + + + + + + + +
KeyFunction
+ enter + Switches to content.
+
+ +
Close Button Keyboard Support
+
+ + + + + + + + + + + + + + + + + +
KeyFunction
+ enter + Switches to display.
+ space + Switches to display.
+
+
Dependencies

None.

-
- { - useLiveEditorTabs({ name: 'InplaceDemo', sources: sources, service: 'ProductService', data: 'products-small' }) - } + {useLiveEditorTabs({ name: 'InplaceDemo', sources: sources, service: 'ProductService', data: 'products-small' })}
); -}) +}); export default InplaceDoc; diff --git a/components/doc/inputgroup/index.js b/components/doc/inputgroup/index.js index 43e07649a9..953c4f012d 100644 --- a/components/doc/inputgroup/index.js +++ b/components/doc/inputgroup/index.js @@ -3,9 +3,8 @@ import { TabView } from '../../lib/tabview/TabView'; import { useLiveEditorTabs } from '../common/liveeditor'; const InputGroupDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -139,7 +138,7 @@ export class InputGroupDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hook Source', content: ` import React, { useState } from 'react'; @@ -265,7 +264,7 @@ const InputGroupDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -391,7 +390,7 @@ const InputGroupDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -523,18 +522,13 @@ const InputGroupDemo = () => { } ` } - } - + }; return ( -
- - { - useLiveEditorTabs({ name: 'InputGroupDemo', sources: sources }) - } - +
+ {useLiveEditorTabs({ name: 'InputGroupDemo', sources: sources })}
); -}) +}); export default InputGroupDoc; diff --git a/components/doc/inputmask/index.js b/components/doc/inputmask/index.js index 11fa0edb37..0fc2601794 100644 --- a/components/doc/inputmask/index.js +++ b/components/doc/inputmask/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const InputMaskDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -70,7 +69,7 @@ export class InputMaskDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -124,7 +123,7 @@ const InputMaskDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -178,7 +177,7 @@ const InputMaskDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -235,14 +234,14 @@ const InputMaskDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- + {` import { InputMask } from 'primereact/inputmask'; `} @@ -257,7 +256,9 @@ import { InputMask } from 'primereact/inputmask';
Getting Started
-

InputMask is used as a controlled component with value and onChange properties.

+

+ InputMask is used as a controlled component with value and onChange properties. +

{` @@ -269,15 +270,9 @@ import { InputMask } from 'primereact/inputmask';

Mask format can be a combination of the the following built-in definitions.

    -
  • - a - Alpha character (A-Z,a-z) -
  • -
  • - 9 - Numeric character (0-9) -
  • -
  • - * - Alpha numberic character (A-Z,a-z,0-9) -
  • +
  • a - Alpha character (A-Z,a-z)
  • +
  • 9 - Numeric character (0-9)
  • +
  • * - Alpha numberic character (A-Z,a-z,0-9)
@@ -287,7 +282,9 @@ import { InputMask } from 'primereact/inputmask';
SlotChar
-

Underscore is the default placeholder for a mask and this can be customized using slotChart option.

+

+ Underscore is the default placeholder for a mask and this can be customized using slotChart option. +

{` @@ -296,10 +293,10 @@ import { InputMask } from 'primereact/inputmask';
Optional Values
-

If the input does not complete the mask definition, it is cleared by default. - Use autoClear property to control this behavior. In addition, certain part of - a mask can be made optional by using ? symbol where anything after the question - mark becomes optional.

+

+ If the input does not complete the mask definition, it is cleared by default. Use autoClear property to control this behavior. In addition, certain part of a mask can be made optional by using ? symbol where anything + after the question mark becomes optional. +

{` @@ -309,8 +306,8 @@ import { InputMask } from 'primereact/inputmask';
Properties

InputMask passes any valid attribute to the underlying React HTMLInputElement element. Extended properties are as follows;

-
- +
+
@@ -439,8 +436,8 @@ import { InputMask } from 'primereact/inputmask';
Events
-
-
Name
+
+
@@ -461,14 +458,19 @@ import { InputMask } from 'primereact/inputmask'; - + - + @@ -476,9 +478,11 @@ import { InputMask } from 'primereact/inputmask';
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
onCompleteevent: Browser event
- value: New value of the component
+ event: Browser event +
+ value: New value of the component +
Callback to invoke on when user completes the mask pattern.
onChangeoriginalEvent: Browser event
- value: New value of the component
+ originalEvent: Browser event
+ value: New value of the component +
Callback to invoke on value change.
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -499,11 +503,14 @@ import { InputMask } from 'primereact/inputmask';
Accessibility
- -
Screen Reader
-

InputMask component renders a native input element that implicitly includes any passed prop. Value to describe the component can either be provided via label tag combined with id prop or using aria-labelledby, aria-label props.

- -{` + +
Screen Reader
+

+ InputMask component renders a native input element that implicitly includes any passed prop. Value to describe the component can either be provided via label tag combined with id prop or using{' '} + aria-labelledby, aria-label props. +

+ + {` @@ -512,35 +519,35 @@ import { InputMask } from 'primereact/inputmask'; `} - -
Keyboard Support
-
-
Name
- - - - - - - - - - - - -
KeyFunction
tabMoves focus to the input.
-
- +
+
Keyboard Support
+
+ + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the input.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'InputMaskDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'InputMaskDemo', sources: sources })}
); -}) +}); export default InputMaskDoc; diff --git a/components/doc/inputnumber/index.js b/components/doc/inputnumber/index.js index 3b2bcf8b05..a60b55e52c 100644 --- a/components/doc/inputnumber/index.js +++ b/components/doc/inputnumber/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const InputNumberDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -154,7 +153,7 @@ export class InputNumberDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -292,7 +291,7 @@ const InputNumberDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -430,7 +429,7 @@ const InputNumberDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` `, @@ -570,54 +569,63 @@ const InputNumberDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { InputNumber } from 'primereact/inputnumber'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

InputNumber is used as a controlled input with value and onValueChange properties. Component always provides a number type although formatting on the input is a string.

+

+ InputNumber is used as a controlled input with value and onValueChange properties. Component always provides a number type although formatting on the input is a string. +

- -{` + + {` setValue(e.value)} /> `} - +
Decimal Mode
-

Format is defined using the mode property, "decimal" is the default value allowing only integers when there is no other configuration.

- -{` +

+ Format is defined using the mode property, "decimal" is the default value allowing only integers when there is no other configuration. +

+ + {` setValue(e.value)} mode="decimal" /> `} - +
-

Fractions are configured with the minFractionDigits property. Optionally maxFractionDigits can be used to defined a boundary for the maximum digits.

- -{` +

+ Fractions are configured with the minFractionDigits property. Optionally maxFractionDigits can be used to defined a boundary for the maximum digits. +

+ + {` setValue1(e.value)} mode="decimal" minFractionDigits={2} /> setValue2(e.value)} mode="decimal" minFractionDigits={2} maxFractionDigits={2} /> `} - - -

locale option is available to set the localization information such as grouping and decimal symbols where default value is the browser locale. Locales are defined per BCP Language Tag.

- -{` + + +

+ locale option is available to set the localization information such as grouping and decimal symbols where default value is the browser locale. Locales are defined per{' '} + BCP Language Tag. +

+ + {` User Locale setValue1(e.value)} mode="decimal" minFractionDigits={2} /> @@ -630,13 +638,15 @@ German Locale Indian Locale setValue4(e.value)} mode="decimal" locale="en-IN" minFractionDigits={2} /> `} - +
Currency
-

Currency formatting is specified by setting the mode option to currency and currency property. In addition currencyDisplay option - allows how the currency is displayed, valid values are "symbol" (default) or "code".

- -{` +

+ Currency formatting is specified by setting the mode option to currency and currency property. In addition currencyDisplay option allows how the currency is displayed, valid values are "symbol" (default) + or "code". +

+ + {` United States setValue1(e.value)} mode="currency" currency="USD" locale="en-US" /> @@ -649,12 +659,14 @@ India Japan setValue4(e.value)} mode="currency" currency="JPY" locale="jp-JP"/> `} - +
Prefix and Suffix
-

Custom texts e.g. units can be placed before or after the input section with the prefix and suffix properties.

- -{` +

+ Custom texts e.g. units can be placed before or after the input section with the prefix and suffix properties. +

+ + {` Mile setValue1(e.value)} suffix=" mi" /> @@ -667,13 +679,15 @@ Expiry Temperature setValue4(e.value)} prefix="↑ " suffix="℃" min={0} max={40} /> `} - +
Buttons
-

Spinner buttons is enabled using the showButtons options and layout is defined with the buttonLayout. Default value is "stacked" whereas - "horizontal" and "stacked" are alternatives. Note that even there are no buttons, up and down arrow keys can be used to spin the values with keyboard.

- -{` +

+ Spinner buttons is enabled using the showButtons options and layout is defined with the buttonLayout. Default value is "stacked" whereas "horizontal" and "stacked" are alternatives. Note that even there are no + buttons, up and down arrow keys can be used to spin the values with keyboard. +

+ + {` Stacked setValue1(e.value)} showButtons mode="currency" currency="USD" /> @@ -685,28 +699,31 @@ Vertical setValue3(e.value)} mode="decimal" showButtons buttonLayout="vertical" style={{width: '6em'}} decrementButtonClassName="p-button-secondary" incrementButtonClassName="p-button-secondary" incrementButtonIcon="pi pi-plus" decrementButtonIcon="pi pi-minus" /> `} - +
Step
-

Step factor is 1 by default and can be customized with step option.

- -{` +

+ Step factor is 1 by default and can be customized with step option. +

+ + {` setValue(e.value)} step={0.25} /> `} - - +
Min and Max Boundaries
-

Value to be entered can be restricted by configuring the min and max options.

- -{` +

+ Value to be entered can be restricted by configuring the min and max options. +

+ + {` setValue1(e.value)} min={0} max={100} /> `} - +
Properties
-
- +
+
@@ -774,8 +791,9 @@ Vertical - @@ -800,16 +818,19 @@ Vertical - + - + @@ -821,17 +842,20 @@ Vertical - + - + @@ -982,8 +1006,8 @@ Vertical
Events
-
-
NamelocaleMatcher string best fitThe locale matching algorithm to use. Possible values are "lookup" and "best fit"; the default is "best fit". - See Locale Negotation for details. + + The locale matching algorithm to use. Possible values are "lookup" and "best fit"; the default is "best fit". See{' '} + Locale Negotation for details.
currency string nullThe currency to use in currency formatting. Possible values are the ISO 4217 currency codes, - such as "USD" for the US dollar, "EUR" for the euro, or "CNY" for the Chinese RMB. - There is no default value; if the style is "currency", the currency property must be provided. + The currency to use in currency formatting. Possible values are the ISO 4217 currency codes, such as "USD" for the US dollar, "EUR" for + the euro, or "CNY" for the Chinese RMB. There is no default value; if the style is "currency", the currency property must be provided. +
currencyDisplay string symbolHow to display the currency in currency formatting. Possible values are "symbol" to use a localized currency symbol such as €, - ü"code" to use the ISO currency code, "name" to use a localized currency name such as "dollar"; the default is "symbol". + How to display the currency in currency formatting. Possible values are "symbol" to use a localized currency symbol such as €, ü"code" to use the ISO currency code, "name" to use a localized currency name such + as "dollar"; the default is "symbol". +
useGroupingminFractionDigits number nullThe minimum number of fraction digits to use. Possible values are from 0 to 20; the default for plain number and percent formatting is 0; the default for currency formatting is the number of - minor unit digits provided by the ISO 4217 currency code list (2 if the list doesn't provide that information). + The minimum number of fraction digits to use. Possible values are from 0 to 20; the default for plain number and percent formatting is 0; the default for currency formatting is the number of minor unit digits + provided by the ISO 4217 currency code list (2 if the list doesn't provide that information). +
maxFractionDigits number nullThe maximum number of fraction digits to use. Possible values are from 0 to 20; the default for plain - number formatting is the larger of minimumFractionDigits and 3; the default for currency formatting - is the larger of minimumFractionDigits and the number of minor unit digits provided by the ISO 4217 currency code list - (2 if the list doesn't provide that information). + The maximum number of fraction digits to use. Possible values are from 0 to 20; the default for plain number formatting is the larger of minimumFractionDigits and 3; the default for currency formatting is the + larger of minimumFractionDigits and the number of minor unit digits provided by the ISO 4217 currency code list + (2 if the list doesn't provide that information). +
id
+
+
@@ -994,14 +1018,18 @@ Vertical - + - + @@ -1024,9 +1052,11 @@ Vertical
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
onValueChangeevent.originalEvent: Browser event
- event.value: New value
+ event.originalEvent: Browser event
+ event.value: New value +
Callback to invoke after validation check and value change.
onChangeevent.originalEvent: Browser event
- event.value: New value
+ event.originalEvent: Browser event
+ event.value: New value +
Callback to invoke on value change.
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -1070,18 +1100,19 @@ Vertical -
Namep-inputnumber-button-icon Button icon
Accessibility
- -
Screen Reader
-

Value to describe the component can either be provided via label tag combined with inputId prop or using aria-labelledby, aria-label props. - The input element uses spinbutton role in addition to the aria-valuemin, aria-valuemax and aria-valuenow attributes.

- -{` + +
Screen Reader
+

+ Value to describe the component can either be provided via label tag combined with inputId prop or using aria-labelledby, aria-label props. The input element uses spinbutton role in + addition to the aria-valuemin, aria-valuemax and aria-valuenow attributes. +

+ + {` @@ -1090,53 +1121,61 @@ Vertical `} - - -
Keyboard Support
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus to the input.
up arrowIncrements the value.
down arrowDecrements the value.
homeSet the minimum value if provided.
endSet the maximum value if provided.
-
-
+
+ +
Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the input.
+ up arrow + Increments the value.
+ down arrow + Decrements the value.
+ home + Set the minimum value if provided.
+ end + Set the maximum value if provided.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'InputNumberDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'InputNumberDemo', sources: sources })}
); -}) +}); export default InputNumberDoc; diff --git a/components/doc/inputswitch/index.js b/components/doc/inputswitch/index.js index f0b6a0a607..4020dd8993 100644 --- a/components/doc/inputswitch/index.js +++ b/components/doc/inputswitch/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const InputSwitchDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -40,7 +39,7 @@ export class InputSwitchDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -64,7 +63,7 @@ const InputSwitchDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -88,7 +87,7 @@ const InputSwitchDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -115,189 +114,198 @@ const InputSwitchDemo = () => { } ` } - } + }; return ( -
- - -
Import via Module
- -{` +
+ + +
Import via Module
+ + {` import { InputSwitch } from 'primereact/inputswitch'; `} - + -
Import via CDN
- -{` +
Import via CDN
+ + {` `} - +
-
Getting Started
-

InputSwitch is used as a controlled input with checked and onChange properties.

+
Getting Started
+

+ InputSwitch is used as a controlled input with checked and onChange properties. +

- -{` + + {` setValue(e.value)} /> `} - + -
Properties
-

Any valid attribute is passed to the root element implicitly, extended properties are as follows;

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDefaultDescription
idstringnullUnique identifier of the element.
stylestringnullInline style of the element.
classNamestringnullStyle class of the element.
inputIdstringnullIdentifier of the input element.
namestringnullName of the input element.
tabIndexnumbernullIndex of the element in tabbing order.
checkedbooleanfalseSpecifies whether a inputswitch should be checked or not.
trueValueanytrueValue in checked state.
falseValueanyfalseValue in unchecked state.
disabledbooleanfalseWhen present, it specifies that the component should be disabled.
tooltipanynullContent of the tooltip.
tooltipOptionsobjectnullConfiguration of the tooltip, refer to the tooltip documentation for more information.
-
+
Properties
+

Any valid attribute is passed to the root element implicitly, extended properties are as follows;

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
idstringnullUnique identifier of the element.
stylestringnullInline style of the element.
classNamestringnullStyle class of the element.
inputIdstringnullIdentifier of the input element.
namestringnullName of the input element.
tabIndexnumbernullIndex of the element in tabbing order.
checkedbooleanfalseSpecifies whether a inputswitch should be checked or not.
trueValueanytrueValue in checked state.
falseValueanyfalseValue in unchecked state.
disabledbooleanfalseWhen present, it specifies that the component should be disabled.
tooltipanynullContent of the tooltip.
tooltipOptionsobjectnullConfiguration of the tooltip, refer to the tooltip documentation for more information.
+
-
Events
-
- - - - - - - - - - - - - - - - - - - - - - - - - -
NameParametersDescription
onChangeevent.originalEvent: Browser event
- event.value: Checked state as a boolean.
Callback to invoke on value change.
onFocusevent: Browser event.Callback to invoke when the element receives focus.
onBlurevent: Browser event.Callback to invoke when the element loses focus.
-
+
Events
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
NameParametersDescription
onChange + event.originalEvent: Browser event
+ event.value: Checked state as a boolean. +
Callback to invoke on value change.
onFocusevent: Browser event.Callback to invoke when the element receives focus.
onBlurevent: Browser event.Callback to invoke when the element loses focus.
+
-
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
- - - - - - - - - - - - - - - - - - - - - -
NameElement
p-inputswitchContainer element.
p-inputswitch-checkedContainer element in active state.
p-inputswitch-sliderSlider element behind the handle.
-
+
Styling
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+ + + + + + + + + + + + + + + + + + + + + +
NameElement
p-inputswitchContainer element.
p-inputswitch-checkedContainer element in active state.
p-inputswitch-sliderSlider element behind the handle.
+
-
Accessibility
- -
Screen Reader
-

InputSwitch component uses a hidden native checkbox element with switch role internally that is only visible to screen readers. Value to describe the component can either be provided via label tag combined with inputId prop or using aria-labelledby, aria-label props.

- -{` +
Accessibility
+ +
Screen Reader
+

+ InputSwitch component uses a hidden native checkbox element with switch role internally that is only visible to screen readers. Value to describe the component can either be provided via label tag combined + with inputId prop or using aria-labelledby, aria-label props. +

+ + {` @@ -306,39 +314,41 @@ import { InputSwitch } from 'primereact/inputswitch'; `} - -
Keyboard Support
-
- - - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus to the switch.
spaceToggles the checked state.
-
-
-
Dependencies
-

None.

-
+ +
Keyboard Support
+
+ + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the switch.
+ space + Toggles the checked state.
+
+ +
Dependencies
+

None.

+ - { - useLiveEditorTabs({ name: 'InputSwitchDemo', sources: sources }) - } -
-
+ {useLiveEditorTabs({ name: 'InputSwitchDemo', sources: sources })} +
+
); -}) +}); export default InputSwitchDoc; diff --git a/components/doc/inputtext/index.js b/components/doc/inputtext/index.js index 10ed361a26..1d3aa38343 100644 --- a/components/doc/inputtext/index.js +++ b/components/doc/inputtext/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const InputTextDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -83,7 +82,7 @@ export class InputTextDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -150,7 +149,7 @@ const InputTextDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -216,8 +215,8 @@ const InputTextDemo = () => { ) } ` - }, - 'browser': { + }, + browser: { tabName: 'Browser Source', imports: ` `, @@ -286,52 +285,64 @@ const InputTextDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { InputText } from 'primereact/inputtext'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

InputText is used as a controlled input with value and onChange properties.

- -{` +

+ InputText is used as a controlled input with value and onChange properties. +

+ + {` setValue(e.target.value)} /> `} - +
Float Label
-

A floating label is implemented by wrapping the input and the label inside a container having .p-float-label style class.

- -{` +

+ A floating label is implemented by wrapping the input and the label inside a container having .p-float-label style class. +

+ + {` setValue(e.target.value)} /> `} - +
KeyFilter
-

InputText has built-in key filtering support to block certain keys, refer to keyfilter page for more information.

+

+ InputText has built-in key filtering support to block certain keys, refer to keyfilter page for more information. +

Properties
-

InputText passes any valid attribute to the underlying React HTMLInputElement element. Extended properties are as follows;

-
- +

+ InputText passes any valid attribute to the underlying{' '} + + React HTMLInputElement + {' '} + element. Extended properties are as follows; +

+
+
@@ -370,9 +381,11 @@ import { InputText } from 'primereact/inputtext';
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -389,11 +402,14 @@ import { InputText } from 'primereact/inputtext';
Accessibility
- -
Screen Reader
-

InputText component renders a native input element that implicitly includes any passed prop. Value to describe the component can either be provided via label tag combined with id prop or using aria-labelledby, aria-label props.

- -{` + +
Screen Reader
+

+ InputText component renders a native input element that implicitly includes any passed prop. Value to describe the component can either be provided via label tag combined with id prop or using{' '} + aria-labelledby, aria-label props. +

+ + {` @@ -402,36 +418,35 @@ import { InputText } from 'primereact/inputtext'; `} - -
Keyboard Support
-
-
Name
- - - - - - - - - - - - -
KeyFunction
tabMoves focus to the input.
-
- + +
Keyboard Support
+
+ + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the input.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'InputTextDemo', sources: sources }) - } - + {useLiveEditorTabs({ name: 'InputTextDemo', sources: sources })}
- ) -}) + ); +}); export default InputTextDoc; diff --git a/components/doc/inputtextarea/index.js b/components/doc/inputtextarea/index.js index 6bf4fa0e26..62052b7adc 100644 --- a/components/doc/inputtextarea/index.js +++ b/components/doc/inputtextarea/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const InputTextareaDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, {Component} from 'react'; @@ -44,7 +43,7 @@ export class InputTextareaDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -71,8 +70,8 @@ const InputTextareaDemo = () => { ) } ` - }, - 'ts': { + }, + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -100,7 +99,7 @@ const InputTextareaDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -131,15 +130,14 @@ const InputTextareaDemo = () => { } ` } - } - + }; return ( -
+
- +
Import via Module
- + {` import { InputTextarea } from 'primereact/inputtextarea'; `} @@ -154,7 +152,9 @@ import { InputTextarea } from 'primereact/inputtextarea';
Getting Started
-

Textarea is used as a controlled input with value and onChange properties.

+

+ Textarea is used as a controlled input with value and onChange properties. +

{` setValue(event.target.value)} /> @@ -171,8 +171,8 @@ import { InputTextarea } from 'primereact/inputtextarea';
Properties

InputTextarea passes any attribute to the underlying textarea element, additional attributes are as follows;

-
- +
+
@@ -205,9 +205,11 @@ import { InputTextarea } from 'primereact/inputtextarea';
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -224,11 +226,14 @@ import { InputTextarea } from 'primereact/inputtextarea';
Accessibility
- -
Screen Reader
-

InputTextarea component renders a native textarea element that implicitly includes any passed prop. Value to describe the component can either be provided via label tag combined with id prop or using aria-labelledby, aria-label props.

- -{` + +
Screen Reader
+

+ InputTextarea component renders a native textarea element that implicitly includes any passed prop. Value to describe the component can either be provided via label tag combined with id prop or using{' '} + aria-labelledby, aria-label props. +

+ + {` @@ -237,36 +242,36 @@ import { InputTextarea } from 'primereact/inputtextarea'; `} - - -
Keyboard Support
-
-
Name
- - - - - - - - - - - - -
KeyFunction
tabMoves focus to the input.
-
- +
+ +
Keyboard Support
+
+ + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the input.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'InputTextareaDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'InputTextareaDemo', sources: sources })}
- ) -}) + ); +}); export default InputTextareaDoc; diff --git a/components/doc/invalid/index.js b/components/doc/invalid/index.js index 58fee69216..f5dd9e30cd 100644 --- a/components/doc/invalid/index.js +++ b/components/doc/invalid/index.js @@ -3,9 +3,8 @@ import { TabView } from '../../lib/tabview/TabView'; import { useLiveEditorTabs } from '../common/liveeditor'; const InvalidDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -210,7 +209,7 @@ export class InvalidDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState, useEffect } from 'react'; @@ -406,7 +405,7 @@ const InvalidDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState, useEffect } from 'react'; @@ -602,7 +601,7 @@ const InvalidDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -815,17 +814,13 @@ const InvalidDemo = () => { } ` } - } + }; return ( -
- - { - useLiveEditorTabs({ name: 'InvalidDemo', sources: sources, service: 'CountryService, NodeService', data: 'countries, treenodes' }) - } - +
+ {useLiveEditorTabs({ name: 'InvalidDemo', sources: sources, service: 'CountryService, NodeService', data: 'countries, treenodes' })}
); -}) +}); export default InvalidDoc; diff --git a/components/doc/keyfilter/index.js b/components/doc/keyfilter/index.js index 7337cdaca5..e9abcde7f4 100644 --- a/components/doc/keyfilter/index.js +++ b/components/doc/keyfilter/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const KeyFilterDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, {Component} from 'react'; @@ -61,7 +60,7 @@ export class KeyFilterDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React from 'react'; @@ -112,7 +111,7 @@ const KeyFilterDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React from 'react'; @@ -163,7 +162,7 @@ const KeyFilterDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` `, @@ -216,35 +215,37 @@ const KeyFilterDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { InputText } from 'primereact/inputtext'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

KeyFilter property is integrated in input components such as InputText using the keyfilter property. The value of the filter - can either a built-in regular expression or a custom one. Following input only accepts integers.

+

+ KeyFilter property is integrated in input components such as InputText using the keyfilter property. The value of the filter can either a built-in regular expression or a custom one. Following input only accepts + integers. +

- -{` + + {` `} - +
Built-in Filters

Commonly used cases have their own built-in shortcuts.

@@ -261,26 +262,26 @@ import { InputText } from 'primereact/inputtext';
Custom Filter

A custom filter is enabled by binding a regular expression, an example that blocks special characters would be;

- -{` + + {` *!]+$/}/> `} - +
Accessibility
- -

Refer to InputText for accessibility as KeyFilter is a built-in add-on of the InputText.

-
+ +

+ Refer to InputText for accessibility as KeyFilter is a built-in add-on of the InputText. +

+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'KeyFilterDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'KeyFilterDemo', sources: sources })}
- ) -}) + ); +}); export default KeyFilterDoc; diff --git a/components/doc/knob/index.js b/components/doc/knob/index.js index c3a5cd5e3e..b0cb1a7fda 100644 --- a/components/doc/knob/index.js +++ b/components/doc/knob/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const KnobDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, {Component} from 'react'; @@ -116,7 +115,7 @@ export class KnobDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -206,7 +205,7 @@ const KnobDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -296,7 +295,7 @@ const KnobDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -389,295 +388,315 @@ const KnobDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Knob } from 'primereact/knob'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started

Knob is used as a controlled input with value and onChange properties.

- -{` + + {` setValue(value)} /> `} - +
Minimum and Maximum
-

Boundaries are configured with the min and max values whose defaults are 0 and 100 respectively.

- -{` +

+ Boundaries are configured with the min and max values whose defaults are 0 and 100 respectively. +

+ + {` setValue(value)} /> `} - +
Step
-

Step factor is 1 by default and can be customized with step option.

- - {` +

+ Step factor is 1 by default and can be customized with step option. +

+ + {` setValue(value)} /> `} - +
Styling
-

valueColor defines the value color, rangeColor defines the range background and similarly textColor configures the color of the value text. - In addition, strokeWidth is used to determine the width of the stroke of range and value sections.

- -{` +

+ valueColor defines the value color, rangeColor defines the range background and similarly textColor configures the color of the value text. In addition, strokeWidth is used to determine the width of + the stroke of range and value sections. +

+ + {` setValue(value)} /> `} - +
Size
-

Default size of the Knob is 100 pixels for width and height, use the size property to customize it per your requirements.

- -{` +

+ Default size of the Knob is 100 pixels for width and height, use the size property to customize it per your requirements. +

+ + {` setValue(value)} /> `} - +
Properties

Any valid attribute is passed to the root element implicitly, extended properties are as follows;

-
- +
+
- - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
NameTypeDefaultDescription
idstringnullUnique identifier of the element.
valuenumbernullValue of the component.
sizenumber100Size of the component in pixels.
disabledbooleanfalseWhen present, it specifies that the component should be disabled.
readOnlybooleanfalseWhen present, it specifies that the component value cannot be edited.
stepnumbernullStep factor to increment/decrement the value.
minnumber0Mininum boundary value.
maxnumber100Maximum boundary value.
valueColorstringnullBackground of the value.
rangeColorstringnullBackground color of the range.
textColorstringnullColor of the value text.
strokeWidthnumber14Width of the knob stroke.
showValuebooleantrueWhether the show the value inside the knob.
valueTemplatestring{value}Template string of the value.
idstringnullUnique identifier of the element.
valuenumbernullValue of the component.
sizenumber100Size of the component in pixels.
disabledbooleanfalseWhen present, it specifies that the component should be disabled.
readOnlybooleanfalseWhen present, it specifies that the component value cannot be edited.
stepnumbernullStep factor to increment/decrement the value.
minnumber0Mininum boundary value.
maxnumber100Maximum boundary value.
valueColorstringnullBackground of the value.
rangeColorstringnullBackground color of the range.
textColorstringnullColor of the value text.
strokeWidthnumber14Width of the knob stroke.
showValuebooleantrueWhether the show the value inside the knob.
valueTemplatestring{value}Template string of the value.
Events
-
- +
+
- - - - - + + + + + - - - - - + + + + +
NameParametersDescription
NameParametersDescription
onChangevalue: New valueCallback to invoke when the value changes.
onChangevalue: New valueCallback to invoke when the value changes.
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
- - - - - - - - - - - - - - - - - - - - - - - - - -
NameElement
p-knobContainer element.
p-knob-rangeRange element.
p-knob-valueValue element.
p-knob-textText element.
-
- -
Accessibility
- -
Screen Reader
-

Knob element component uses slider role in addition to the aria-valuemin, aria-valuemax and aria-valuenow attributes. Value to describe the component can be defined using - aria-labelledby and aria-label props.

- -{` -Number - - - -`} - -
Keyboard Support
-
- +

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
- - + + - - + + - - + + - - + + - - - - - - - - - - - - - - + +
KeyFunctionNameElement
tabMoves focus to the slider.p-knobContainer element.
- - left arrow - down arrow - - Decrements the value.p-knob-rangeRange element.
- - right arrow - up arrow - - Increments the value.p-knob-valueValue element.
homeSet the minimum value.
endSet the maximum value.
page upIncrements the value by 10 steps.
page downDecrements the value by 10 steps.p-knob-textText element.
-
+ +
Accessibility
+ +
Screen Reader
+

+ Knob element component uses slider role in addition to the aria-valuemin, aria-valuemax and aria-valuenow attributes. Value to describe the component can be defined using + aria-labelledby and aria-label props. +

+ + {` +Number + + + +`} + +
Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the slider.
+ + left arrow + down arrow + + Decrements the value.
+ + right arrow + up arrow + + Increments the value.
+ home + Set the minimum value.
+ end + Set the maximum value.
+ page up + Increments the value by 10 steps.
+ page down + Decrements the value by 10 steps.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'KnobDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'KnobDemo', sources: sources })}
- ) -}) + ); +}); export default KnobDoc; diff --git a/components/doc/listbox/index.js b/components/doc/listbox/index.js index 66d0ab8e43..3878d3e413 100644 --- a/components/doc/listbox/index.js +++ b/components/doc/listbox/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const ListBoxDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, {Component} from 'react'; @@ -122,7 +121,7 @@ export class ListBoxDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -226,7 +225,7 @@ const ListBoxDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -329,8 +328,8 @@ const ListBoxDemo = () => { ); } ` - }, - 'browser': { + }, + browser: { tabName: 'Browser Source', imports: ` @@ -437,36 +436,39 @@ const ListBoxDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { ListBox } from 'primereact/listbox'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

Listbox is used as a controlled component with value and onChange properties along with the options collection. There are two alternatives - of how to define the options property; One way is providing a collection of SelectItem instances having label-value pairs - whereas other way is providing an array of arbitrary objects along with the optionLabel and optionValue properties to specify the label/value field pair. - In addition, options can be simple primitive values such as a string array, in this case no optionLabel or optionValue is necessary.

- -

Options as SelectItems

- -{` +

+ Listbox is used as a controlled component with value and onChange properties along with the options collection. There are two alternatives of how to define the options property; One way is providing a collection + of SelectItem instances having label-value pairs whereas other way is providing an array of arbitrary objects along with the optionLabel and optionValue properties to specify the label/value field pair. In + addition, options can be simple primitive values such as a string array, in this case no optionLabel or optionValue is necessary. +

+ +

+ Options as SelectItems +

+ + {` const citySelectItems = [ {label: 'New York', value: 'NY'}, {label: 'Rome', value: 'RM'}, @@ -475,17 +477,19 @@ const citySelectItems = [ {label: 'Paris', value: 'PRS'} ]; `} - +
- -{` + + {` setCity(e.value)} /> `} - + -

Options as any type

- -{` +

+ Options as any type +

+ + {` const cities = [ {name: 'New York', code: 'NY'}, {name: 'Rome', code: 'RM'}, @@ -494,38 +498,44 @@ const cities = [ {name: 'Paris', code: 'PRS'} ]; `} - +
- -{` + + {` setCity(e.value)} /> setCity(e.value)} /> `} - -

When optionValue is not defined, value of an option refers to the option object itself.

+
+

+ When optionValue is not defined, value of an option refers to the option object itself. +

Selection
-

Listbox allows selection of either single or multiple items. In single case, model should be a single object reference whereas in multiple case should be an array. Multiple items can either be selected - using metaKey or toggled individually depending on the value of metaKeySelection property value which is false by default. On touch enabled - devices metaKeySelection is turned on automatically even when enabled.

+

+ Listbox allows selection of either single or multiple items. In single case, model should be a single object reference whereas in multiple case should be an array. Multiple items can either be selected using metaKey or toggled + individually depending on the value of metaKeySelection property value which is false by default. On touch enabled devices metaKeySelection is turned on automatically even when enabled. +

- -{` + + {` setCity(e.value)} multiple /> `} - +
Custom Content
-

Label of an option is used as the display text of an item by default, for custom content support define an itemTemplate property. Its value can be JSXElement, function or string. For custom filter support, define a filterTemplate function that gets the option instance as a parameter and returns the content for the filter element.

+

+ Label of an option is used as the display text of an item by default, for custom content support define an itemTemplate property. Its value can be JSXElement, function or string. For custom filter support, define a{' '} + filterTemplate function that gets the option instance as a parameter and returns the content for the filter element. +

- -{` + + {` setCity(e.value)} itemTemplate={itemTemplate} filter filterTemplate={filterTemplate}/> `} - + - -{` + + {` const [filterValue, setFilterValue] = useState(''); const filterInputRef = React.useRef(); @@ -556,30 +566,35 @@ const myFilterFunction = (event, options) => { options.filter(event); } `} - +
Filtering
-

Options can be filtered using an input field in the overlay by enabling the filter property. By default filtering is done against - label of the items and filterBy property is available to choose one or more properties of the options. In addition filterMatchMode can be utilized - to define the filtering algorithm, valid options are "contains" (default), "startsWith", "endsWith", "equals" and "notEquals". - Also, the filterValue and onFilterValueChange properties can be used to control the filter value.

- - -{` +

+ Options can be filtered using an input field in the overlay by enabling the filter property. By default filtering is done against label of the items and filterBy property is available to choose one or more + properties of the options. In addition filterMatchMode can be utilized to define the filtering algorithm, valid options are "contains" (default), "startsWith", "endsWith", "equals" and "notEquals". Also, the{' '} + filterValue and onFilterValueChange properties can be used to control the filter value. +

+ + + {` setCity(e.value)} filter /> `} - +
-

Filter input can be customized with the filterInputProps option that passes any property to the filter input element.

- -{` +

+ Filter input can be customized with the filterInputProps option that passes any property to the filter input element. +

+ + {` setCity(e.value)} filter filterInputProps={{className:'p-3', maxLength: 10}}/> `} - +
Grouping
-

Options groups are specified with the optionGroupLabel and optionGroupChildren properties.

- -{` +

+ Options groups are specified with the optionGroupLabel and optionGroupChildren properties. +

+ + {` const groupedCities = [ { label: 'Germany', code: 'DE', @@ -610,17 +625,17 @@ const groupedCities = [ } ]; `} - +
- -{` + + {` setSelectedGroupedCity(e.value)} optionLabel="label" optionGroupLabel="label" optionGroupChildren="items" /> `} - +
SelectItem API
-
- +
+
@@ -665,8 +680,8 @@ const groupedCities = [
Properties
-
-
Name
+
+
@@ -788,8 +803,10 @@ const groupedCities = [ - + @@ -855,15 +872,17 @@ const groupedCities = [ - +
NamemetaKeySelection boolean trueDefines how multiple items can be selected, when true metaKey needs to be pressed to select or unselect an item and when set to false selection of each item - can be toggled individually. On touch enabled devices, metaKeySelection is turned off automatically. + Defines how multiple items can be selected, when true metaKey needs to be pressed to select or unselect an item and when set to false selection of each item can be toggled individually. On touch enabled + devices, metaKeySelection is turned off automatically. +
filtervirtualScrollerOptions object nullWhether to use the virtualScroller feature. The properties of VirtualScroller component can be used like an object in it. + Whether to use the virtualScroller feature. The properties of VirtualScroller component can be used like an object in it. +
Events
-
- +
+
@@ -874,15 +893,17 @@ const groupedCities = [ - - @@ -891,9 +912,11 @@ const groupedCities = [
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
onChangeevent.originalEvent: Browser event
- event.value: Single value or an array of values depending on the selection mode
+
+ event.originalEvent: Browser event
+ event.value: Single value or an array of values depending on the selection mode
Callback to invoke when value of listbox changes.
onFilterValueChangeevent.originalEvent: Browser event
- event.value: the filtered value
+
+ event.originalEvent: Browser event
+ event.value: the filtered value
Callback to invoke when filter value changes.
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -926,95 +949,123 @@ const groupedCities = [
Accessibility
- -
Screen Reader
-

Value to describe the component can be provided aria-labelledby or aria-label props. The list element has a listbox role with the aria-multiselectable attribute that sets to true when multiple selection is enabled. - Each list item has an option role with aria-selected and aria-disabled as their attributes.

-

If filtering is enabled, filterInputProps can be defined to give aria-* props to the input element. Alternatively filterPlaceholder is usually utilized by the screen readers as well.

- -{` + +
Screen Reader
+

+ Value to describe the component can be provided aria-labelledby or aria-label props. The list element has a listbox role with the aria-multiselectable attribute that sets to true when multiple + selection is enabled. Each list item has an option role with aria-selected and aria-disabled as their attributes. +

+

+ If filtering is enabled, filterInputProps can be defined to give aria-* props to the input element. Alternatively filterPlaceholder is usually utilized by the screen readers as well. +

+ + {` Options `} - -
Keyboard Support
-
-
Name
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus to the first selected option, if there is none then first option receives the focus.
up arrowMoves focus to the previous option.
down arrowMoves focus to the next option.
enterToggles the selected state of the focused option.
spaceToggles the selected state of the focused option.
homeMoves focus to the first option.
endMoves focus to the last option.
shift + down arrowMoves focus to the next option and toggles the selection state.
shift + up arrowMoves focus to the previous option and toggles the selection state.
shift + spaceSelects the items between the most recently selected option and the focused option.
control + shift + homeSelects the focused options and all the options up to the first one.
control + shift + endSelects the focused options and all the options down to the last one.
control + aSelects all options.
-
- + +
Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the first selected option, if there is none then first option receives the focus.
+ up arrow + Moves focus to the previous option.
+ down arrow + Moves focus to the next option.
+ enter + Toggles the selected state of the focused option.
+ space + Toggles the selected state of the focused option.
+ home + Moves focus to the first option.
+ end + Moves focus to the last option.
+ shift + down arrow + Moves focus to the next option and toggles the selection state.
+ shift + up arrow + Moves focus to the previous option and toggles the selection state.
+ shift + space + Selects the items between the most recently selected option and the focused option.
+ control + shift + home + Selects the focused options and all the options up to the first one.
+ control + shift + end + Selects the focused options and all the options down to the last one.
+ control + a + Selects all options.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'ListBoxDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'ListBoxDemo', sources: sources })}
); -}) +}); export default ListBoxDoc; diff --git a/components/doc/megamenu/index.js b/components/doc/megamenu/index.js index fc1778a5fc..ac5e20afdd 100644 --- a/components/doc/megamenu/index.js +++ b/components/doc/megamenu/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const MegaMenuDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -155,7 +154,7 @@ export class MegaMenuDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React from 'react'; @@ -296,7 +295,7 @@ const MegaMenuDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React from 'react'; @@ -437,7 +436,7 @@ const MegaMenuDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -581,33 +580,35 @@ const MegaMenuDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { MegaMenu } from 'primereact/megamenu'; `} - +
Import via CDN
- -{` + + {` `} - +
MenuItem API
-

MegaMenu uses the common menu item api to define its items, visit MenuModel for details.

+

+ MegaMenu uses the common menu item api to define its items, visit MenuModel for details. +

MegaMenu requires a collection of menuitems as its model.

- -{` + + {` const items = [ { label: 'Videos', icon: 'pi pi-fw pi-video', @@ -721,37 +722,37 @@ const items = [ } ] `} - + - -{` + + {` `} - +
Orientation

Default orientation is "horizontal" with "vertical" as the alternative.

- -{` + + {` `} - +
Custom Content

The megamenu can display custom content by using the "start" and "end" properties.

- -{` + + {` } end={
- ) -}) + ); +}); export default MegaMenuDoc; diff --git a/components/doc/mention/index.js b/components/doc/mention/index.js index b84697e478..ab782aff3a 100644 --- a/components/doc/mention/index.js +++ b/components/doc/mention/index.js @@ -5,9 +5,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const MentionDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -148,7 +147,7 @@ export class MentionDemo extends Component { ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState, useEffect } from 'react'; @@ -275,7 +274,7 @@ const MentionDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState, useEffect } from 'react'; @@ -402,7 +401,7 @@ const MentionDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -533,38 +532,40 @@ const MentionDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Mention } from 'primereact/mention'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

Mention is used as a controlled component with suggestions and onSearch properties.

+

+ Mention is used as a controlled component with suggestions and onSearch properties. +

- -{` + + {` `} - + - -{` + + {` const customers = // datasource const onSearch = (event) => { @@ -586,22 +587,22 @@ const onSearch = (event) => { }, 250); } `} - +
Trigger

It is used to define the expected keyword/s in the input field to mention someone or something.

- -{` + + {` `} - +
Properties

InputTextarea passes any attribute to the underlying textarea element, additional attributes are as follows;

-
- +
+
@@ -723,15 +724,21 @@ const onSearch = (event) => { - +
NametransitionOptions object nullThe properties of CSSTransition can be customized, except for "nodeRef" and "in" properties. + The properties of{' '} + + CSSTransition + {' '} + can be customized, except for "nodeRef" and "in" properties. +
Events
-
- +
+
@@ -767,14 +774,17 @@ const onSearch = (event) => { - - @@ -790,8 +800,8 @@ const onSearch = (event) => {
Styling

Following is the list of structural style classes

-
-
Name
onSearchevent.originalEvent: Browser event
+
+ event.originalEvent: Browser event
event.trigger: Current trigger keyword.
Callback to invoke when search.
onSelectevent.originalEvent: Browser event
+
+ event.originalEvent: Browser event +
event.suggestion: Selected item
Callback to invoke when selection changes.
+
+
@@ -820,14 +830,19 @@ const onSearch = (event) => {
Accessibility
- -
Screen Reader
-

Value to describe the component can either be provided via label tag combined with inputId prop or using aria-labelledby, aria-label props. The input element has combobox role - in addition to aria-autocomplete, aria-haspopup and aria-expanded attributes. The relation between the input and the popup is created with aria-controls and aria-activedescendant attribute is used - to instruct screen reader which option to read during keyboard navigation within the popup list.

-

The popup list has an id that refers to the aria-controls attribute of the input element and uses listbox as the role. Each list item has option role and an id to match the aria-activedescendant of the input element.

- -{` + +
Screen Reader
+

+ Value to describe the component can either be provided via label tag combined with inputId prop or using aria-labelledby, aria-label props. The input element has combobox role in addition + to aria-autocomplete, aria-haspopup and aria-expanded attributes. The relation between the input and the popup is created with aria-controls and aria-activedescendant attribute is used to + instruct screen reader which option to read during keyboard navigation within the popup list. +

+

+ The popup list has an id that refers to the aria-controls attribute of the input element and uses listbox as the role. Each list item has option role and an id to match the aria-activedescendant{' '} + of the input element. +

+ + {` @@ -836,60 +851,70 @@ const onSearch = (event) => { `} - -
Keyboard Support
-
-
Name
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus to the input element when popup is not visible. - If the popup is open and an item is highlighted then popup gets closed, item gets selected and focus moves to the next focusable element.
up arrowHighlights the previous item if popup is visible.
down arrowHighlights the next item if popup is visible.
enterSelects the highlighted item and closes the popup if popup is visible.
homeHighlights the first item if popup is visible.
endHighlights the last item if popup is visible.
escapeHides the popup.
-
- + +
Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the input element when popup is not visible. If the popup is open and an item is highlighted then popup gets closed, item gets selected and focus moves to the next focusable element.
+ up arrow + Highlights the previous item if popup is visible.
+ down arrow + Highlights the next item if popup is visible.
+ enter + Selects the highlighted item and closes the popup if popup is visible.
+ home + Highlights the first item if popup is visible.
+ end + Highlights the last item if popup is visible.
+ escape + Hides the popup.
+
+
Dependencies

None.

-
- { - useLiveEditorTabs({ name: 'MentionDemo', sources: sources, service: 'CustomerService', data: 'customers-small' }) - } + {useLiveEditorTabs({ name: 'MentionDemo', sources: sources, service: 'CustomerService', data: 'customers-small' })}
- ) -}) + ); +}); export default MentionDoc; diff --git a/components/doc/menu/index.js b/components/doc/menu/index.js index e28d9e4c32..592e3bf02b 100644 --- a/components/doc/menu/index.js +++ b/components/doc/menu/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const MenuDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -80,7 +79,7 @@ export class MenuDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useRef } from 'react'; @@ -147,7 +146,7 @@ const MenuDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useRef } from 'react'; @@ -214,7 +213,7 @@ const MenuDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -285,51 +284,53 @@ const MenuDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Menu } from 'primereact/menu'; `} - +
Import via CDN
- -{` + + {` `} - +
MenuModel API
-

Menu uses the common menumodel api to define its items, visit MenuModel API for details.

+

+ Menu uses the common menumodel api to define its items, visit MenuModel API for details. +

Getting Started

Menu requires a collection of menuitems as its model.

- -{` + + {` `} - + - -{` + + {` let items = [ {label: 'New', icon: 'pi pi-fw pi-plus'}, {label: 'Delete', icon: 'pi pi-fw pi-trash'} ]; `} - +
SubMenus

Menu supports one level of nesting via subitems of an item.

- -{` + + {` let items = [ { label: 'Options', @@ -343,21 +344,21 @@ let items = [ } ] `} - +
Popup Mode

Menu is inline by default whereas popup mode is supported by enabling popup property and calling toggle method with an event of the target.

- -{` + + {`
- ) -}) + ); +}); export default MenuDoc; diff --git a/components/doc/menubar/index.js b/components/doc/menubar/index.js index a8219fd5b6..601f0f200e 100644 --- a/components/doc/menubar/index.js +++ b/components/doc/menubar/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const MenubarDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -164,7 +163,7 @@ export class MenubarDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React from 'react'; @@ -313,7 +312,7 @@ const MenubarDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React from 'react'; @@ -462,7 +461,7 @@ const MenubarDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -614,40 +613,42 @@ const MenubarDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Menubar } from 'primereact/menubar'; `} - +
Import via CDN
- -{` + + {` `} - +
MenuItem API
-

Menubar uses the common menu item api to define its items, visit MenuModel for details.

+

+ Menubar uses the common menu item api to define its items, visit MenuModel for details. +

Getting Started

Menubar requires nested menuitems as its model.

- -{` + + {` `} - + - -{` + + {` const items = [ { label:'File', @@ -777,23 +778,23 @@ const items = [ } ]; `} - +
Custom Content

The menubar can display custom content by using the "start" and "end" properties.

- -{` + + {` } end={
- ) -}) + ); +}); export default MenubarDoc; diff --git a/components/doc/messages/index.js b/components/doc/messages/index.js index cf230842ea..942b0c9020 100644 --- a/components/doc/messages/index.js +++ b/components/doc/messages/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const MessagesDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -114,10 +113,10 @@ export class MessagesDemo extends Component { } } ` - }, - 'hooks': { - tabName: 'Hooks Source', - content: ` + }, + hooks: { + tabName: 'Hooks Source', + content: ` import React, { useEffect, useRef } from 'react'; import { Messages } from 'primereact/messages'; import { Message } from 'primereact/message'; @@ -215,10 +214,10 @@ const MessagesDemo = () => { ) } ` - }, - 'ts': { - tabName: 'TS Source', - content: ` + }, + ts: { + tabName: 'TS Source', + content: ` import React, { useEffect, useRef } from 'react'; import { Messages } from 'primereact/messages'; import { Message } from 'primereact/message'; @@ -316,14 +315,14 @@ const MessagesDemo = () => { ) } ` - }, - 'browser': { - tabName: 'Browser Source', - imports: ` + }, + browser: { + tabName: 'Browser Source', + imports: ` `, - content: ` + content: ` const { useEffect, useState, useRef } = React; const { Messages } = primereact.messages; const { Message } = primereact.message; @@ -422,50 +421,52 @@ const MessagesDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Messages } from 'primereact/messages'; import { Message } from 'primereact/message'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

A single message is specified by the Message interface in PrimeReact that defines various properties such as severity, - summary and detail. Messages are displayed by using the show method on the ref of the Messages instance.

+

+ A single message is specified by the Message interface in PrimeReact that defines various properties such as severity, summary and detail. Messages are displayed by using the show method on the ref of the Messages + instance. +

Note that for animations, messages requires react-transition-group package.

- -{` + + {` `} - + - -{` + + {` messages.current.show({severity: 'success', summary: 'Success Message', detail: 'Order submitted'}); `} - +
Message API
-
- +
+
@@ -534,8 +535,8 @@ messages.current.show({severity: 'success', summary: 'Success Message', detail:
Showing Messages

Show method accepts either a single message or an array of messages.

- -{` + + {`
Name
+
+
@@ -688,8 +697,8 @@ messages.current.show({ life: 5000, severity: 'error', summary: 'Error Message',
Properties of Messages
-
-
Name
+
+
@@ -721,15 +730,21 @@ messages.current.show({ life: 5000, severity: 'error', summary: 'Error Message', - +
NametransitionOptions object nullThe properties of CSSTransition can be customized, except for "nodeRef" and "in" properties. + The properties of{' '} + + CSSTransition + {' '} + can be customized, except for "nodeRef" and "in" properties. +
Events of Messages
-
- +
+
@@ -753,9 +768,11 @@ messages.current.show({ life: 5000, severity: 'error', summary: 'Error Message',
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -805,49 +822,54 @@ messages.current.show({ life: 5000, severity: 'error', summary: 'Error Message',
Accessibility
-
Screen Reader
-

Message components use alert role that implicitly defines aria-live as "assertive" and aria-atomic as "true". Since any attribute is passed - to the root element, attributes like aria-labelledby and aria-label can optionally be used as well.

- -

Close element is a button with an aria-label that refers to the aria.close property of the locale API by default, you may use - closeButtonProps to customize the element and override the default aria-label.

- -
Close Button Keyboard Support
-
-
Name
- - - - - - - - - - - - - - - - -
KeyFunction
enterCloses the message.
spaceCloses the message.
-
+
Screen Reader
+

+ Message components use alert role that implicitly defines aria-live as "assertive" and aria-atomic as "true". Since any attribute is passed to the root element, attributes like aria-labelledby{' '} + and aria-label can optionally be used as well. +

+ +

+ Close element is a button with an aria-label that refers to the aria.close property of the locale API by default, you may use + closeButtonProps to customize the element and override the default aria-label. +

+ +
Close Button Keyboard Support
+
+ + + + + + + + + + + + + + + + + +
KeyFunction
+ enter + Closes the message.
+ space + Closes the message.
+
Dependencies
  • react-transition-group
-
- { - useLiveEditorTabs({ name: 'MessagesDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'MessagesDemo', sources: sources })}
); -}) +}); export default MessagesDoc; diff --git a/components/doc/multiselect/index.js b/components/doc/multiselect/index.js index 814d852198..ae327757eb 100644 --- a/components/doc/multiselect/index.js +++ b/components/doc/multiselect/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const MultiSelectDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -199,7 +198,7 @@ export class MultiSelectDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState, useEffect, useRef } from 'react'; @@ -373,7 +372,7 @@ const MultiSelectDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState, useEffect, useRef } from 'react'; @@ -547,7 +546,7 @@ const MultiSelectDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -726,7 +725,7 @@ const MultiSelectDemo = () => { } ` } - } + }; const extFiles = { 'demo/MultiSelectDemo.css': { @@ -754,36 +753,39 @@ const MultiSelectDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { MultiSelect } from 'primereact/multiselect'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

MultiSelect is used as a controlled component with value and onChange properties along with the options collection. There are two alternatives - of how to define the options property; One way is providing a collection of SelectItem instances having label-value pairs - whereas other way is providing an array of arbitrary objects along with the optionLabel and optionValue properties to specify the label/value field pair. In addition, - options can be simple primitive values such as a string array, in this case no optionLabel or optionValue is necessary.

- -

Options as SelectItems

- -{` +

+ MultiSelect is used as a controlled component with value and onChange properties along with the options collection. There are two alternatives of how to define the options property; One way is providing a + collection of SelectItem instances having label-value pairs whereas other way is providing an array of arbitrary objects along with the optionLabel and optionValue properties to specify the label/value + field pair. In addition, options can be simple primitive values such as a string array, in this case no optionLabel or optionValue is necessary. +

+ +

+ Options as SelectItems +

+ + {` const citySelectItems = [ {label: 'New York', value: 'NY'}, {label: 'Rome', value: 'RM'}, @@ -792,17 +794,19 @@ const citySelectItems = [ {label: 'Paris', value: 'PRS'} ]; `} - +
- -{` + + {` setCities(e.value)} /> `} - + -

Options as any type

- -{` +

+ Options as any type +

+ + {` const cities = [ {name: 'New York', code: 'NY'}, {name: 'Rome', code: 'RM'}, @@ -811,35 +815,42 @@ const cities = [ {name: 'Paris', code: 'PRS'} ]; `} - +
- -{` + + {` setCities(e.value)} /> setCities(e.value)} /> `} - -

When optionValue is not defined, value of an option refers to the option object itself.

+
+

+ When optionValue is not defined, value of an option refers to the option object itself. +

Chips Display
-

A comma separated list is used by default to display selected items whereas alternative chip mode is provided using the display property to visualize the items as tokens.

- -{` +

+ A comma separated list is used by default to display selected items whereas alternative chip mode is provided using the display property to visualize the items as tokens. +

+ + {` setSelectedCities(e.value)} /> `} - +
Custom Content
-

Label of an option is used as the display text of an item by default, for custom content support define an itemTemplate function that gets the option instance as a parameter and returns the content. For custom filter support define a filterTemplate function that gets the option instance as a parameter and returns the content for the filter element.

+

+ Label of an option is used as the display text of an item by default, for custom content support define an itemTemplate function that gets the option instance as a parameter and returns the content. For custom filter + support define a filterTemplate function that gets the option instance as a parameter and returns the content for the filter element. +

- -{` + + {` setCities(e.value)} itemTemplate={itemTemplate} filter filterTemplate={filterTemplate}/> `} - + - -{` + + {` const [filterValue, setFilterValue] = useState(''); const filterInputRef = useRef(); @@ -870,32 +881,36 @@ const myFilterFunction = (event, options) => { options.filter(event); } `} - -

selectedItemTemplate can be used to customize the selected values display instead of the default comma separated list.

+
+

+ selectedItemTemplate can be used to customize the selected values display instead of the default comma separated list. +

- -{` + + {` setCities(e.value)} selectedItemTemplate={selectedItemTemplate} /> `} - + - -{` + + {` selectedItemTemplate(option) { // custom selected item content } `} - + -

In addition panelHeaderTemplate and panelFooterTemplate can be used to customize the header and footer of panel.

- -{` +

+ In addition panelHeaderTemplate and panelFooterTemplate can be used to customize the header and footer of panel. +

+ + {` setCities(e.value)} panelHeaderTemplate={panelHeaderTemplate} panelFooterTemplate={panelFooterTemplate} /> `} - +
- -{` + + {` panelHeaderTemplate(options) { // options.className: Style class of the panel header. // options.checkboxElement: Default checkbox element created by the component. @@ -914,12 +929,14 @@ panelFooterTemplate(options) { // options.props: component props. } `} - +
Grouping
-

Options groups are specified with the optionGroupLabel and optionGroupChildren properties.

- -{` +

+ Options groups are specified with the optionGroupLabel and optionGroupChildren properties. +

+ + {` const groupedCities = [ { label: 'Germany', code: 'DE', @@ -950,28 +967,29 @@ const groupedCities = [ } ]; `} - +
- -{` + + {` setSelectedGroupedCities(e.value)} optionLabel="label" optionGroupLabel="label" optionGroupChildren="items" /> `} - +
Filtering
-

Options can be filtered using an input field in the overlay by enabling the filter property. By default filtering is done against - label of the items and filterBy property is available to choose one or more properties of the options. In addition filterMatchMode can be utilized - to define the filtering algorithm, valid options are "contains" (default), "startsWith", "endsWith", "equals" and "notEquals".

+

+ Options can be filtered using an input field in the overlay by enabling the filter property. By default filtering is done against label of the items and filterBy property is available to choose one or more + properties of the options. In addition filterMatchMode can be utilized to define the filtering algorithm, valid options are "contains" (default), "startsWith", "endsWith", "equals" and "notEquals". +

- -{` + + {` setCities(e.value)} filter/> `} - +
SelectItem API
-
- +
+
@@ -1017,15 +1035,15 @@ const groupedCities = [
Properties

Any valid attribute is passed to the root element implicitly, extended properties are as follows;

-
-
Name
+
+
- - - - - - + + + + + + @@ -1248,7 +1266,9 @@ const groupedCities = [ - + @@ -1284,7 +1304,13 @@ const groupedCities = [ - + @@ -1302,7 +1328,9 @@ const groupedCities = [ - + @@ -1321,20 +1349,23 @@ const groupedCities = [
Events
-
-
NameTypeDefaultDescription
NameTypeDefaultDescription
appendTo DOM element | string document.bodyDOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. + DOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. +
maxSelectedLabelstransitionOptions object nullThe properties of CSSTransition can be customized, except for "nodeRef" and "in" properties. + The properties of{' '} + + CSSTransition + {' '} + can be customized, except for "nodeRef" and "in" properties. +
dropdownIconvirtualScrollerOptions object nullWhether to use the virtualScroller feature. The properties of VirtualScroller component can be used like an object in it. + Whether to use the virtualScroller feature. The properties of VirtualScroller component can be used like an object in it. +
showSelectAll
+
+
- - - - - + + + + + - @@ -1360,14 +1391,20 @@ const groupedCities = [ - + - + @@ -1375,14 +1412,14 @@ const groupedCities = [
Methods
-
-
NameParametersDescription
NameParametersDescription
onChangeevent.originalEvent: Browser event
- event.value: Current selected values
+
+ event.originalEvent: Browser event +
+ event.value: Current selected values +
Callback to invoke when value changes.
onFilterevent.originalEvent: Browser event
- event.filter: Filter value.
+ event.originalEvent: Browser event +
+ event.filter: Filter value. +
Callback to invoke on filtering.
onSelectAllevent.originalEvent: Browser event
- event.checked: Whether all data is selected.
+ event.originalEvent: Browser event +
+ event.checked: Whether all data is selected. +
Callback to invoke when all data is selected.
+
+
- - - - - + + + + + @@ -1395,9 +1432,11 @@ const groupedCities = [
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
NameParametersDescription
NameParametersDescription
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -1454,189 +1493,240 @@ const groupedCities = [
Accessibility
- -
Screen Reader
-

Value to describe the component can either be provided with aria-labelledby or aria-label props. The multiselect component has a combobox role - in addition to aria-haspopup and aria-expanded attributes. The relation between the combobox and the popup is created with aria-controls attribute that refers to the id of the popup listbox.

-

The popup listbox uses listbox as the role with aria-multiselectable enabled. Each list item has an option role along with aria-label, aria-selected and aria-disabled attributes.

- -

Checkbox component at the header uses a hidden native checkbox element internally that is only visible to screen readers. Value to read is defined with the selectAll and unselectAll keys of the aria property from the locale API.

- -

If filtering is enabled, filterInputProps can be defined to give aria-* props to the input element.

- -

Close button uses close key of the aria property from the locale API as the aria-label by default, this can be overriden with the closeButtonProps.

- -{` + +
Screen Reader
+

+ Value to describe the component can either be provided with aria-labelledby or aria-label props. The multiselect component has a combobox role in addition to aria-haspopup and{' '} + aria-expanded attributes. The relation between the combobox and the popup is created with aria-controls attribute that refers to the id of the popup listbox. +

+

+ The popup listbox uses listbox as the role with aria-multiselectable enabled. Each list item has an option role along with aria-label, aria-selected and aria-disabled attributes. +

+ +

+ Checkbox component at the header uses a hidden native checkbox element internally that is only visible to screen readers. Value to read is defined with the selectAll and unselectAll keys of the aria{' '} + property from the locale API. +

+ +

+ If filtering is enabled, filterInputProps can be defined to give aria-* props to the input element. +

+ +

+ Close button uses close key of the aria property from the locale API as the aria-label by default, this can be overriden with the closeButtonProps. +

+ + {` Options `} - - -
Closed State Keyboard Support
-
-
Name
- - - - - - - - - - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus to the multiselect element.
spaceOpens the popup and moves visual focus to the selected option, if there is none then first option receives the focus.
down arrowOpens the popup and moves visual focus to the selected option, if there is none then first option receives the focus.
up arrowOpens the popup and moves visual focus to the selected option, if there is none then first option receives the focus.
-
+ + +
Closed State Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the multiselect element.
+ space + Opens the popup and moves visual focus to the selected option, if there is none then first option receives the focus.
+ down arrow + Opens the popup and moves visual focus to the selected option, if there is none then first option receives the focus.
+ up arrow + Opens the popup and moves visual focus to the selected option, if there is none then first option receives the focus.
+
-
Popup Keyboard Support
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus to the next focusable element in the popup, if there is none then first focusable element receives the focus.
shift + tabMoves focus to the previous focusable element in the popup, if there is none then last focusable element receives the focus.
enterToggles the selection state of the focused option.
spaceToggles the selection state of the focused option.
escapeCloses the popup, moves focus to the multiselect element.
down arrowMoves focus to the next option, if there is none then visual focus does not change.
up arrowMoves focus to the previous option, if there is none then visual focus does not change.
homeMoves focus to the first option.
endMoves focus to the last option.
any printable characterMoves focus to the option whose label starts with the characters being typed if dropdown is not editable.
-
+
Popup Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the next focusable element in the popup, if there is none then first focusable element receives the focus.
+ shift + tab + Moves focus to the previous focusable element in the popup, if there is none then last focusable element receives the focus.
+ enter + Toggles the selection state of the focused option.
+ space + Toggles the selection state of the focused option.
+ escape + Closes the popup, moves focus to the multiselect element.
+ down arrow + Moves focus to the next option, if there is none then visual focus does not change.
+ up arrow + Moves focus to the previous option, if there is none then visual focus does not change.
+ home + Moves focus to the first option.
+ end + Moves focus to the last option.
+ any printable character + Moves focus to the option whose label starts with the characters being typed if dropdown is not editable.
+
-
Toggle All Checkbox Keyboard Support
-
- - - - - - - - - - - - - - - - - -
KeyFunction
spaceToggles the checked state.
escapeCloses the popup.
-
+
Toggle All Checkbox Keyboard Support
+
+ + + + + + + + + + + + + + + + + +
KeyFunction
+ space + Toggles the checked state.
+ escape + Closes the popup.
+
-
Filter Input Keyboard Support
-
- - - - - - - - - - - - - - - - - -
KeyFunction
enterCloses the popup and moves focus to the multiselect element.
escapeCloses the popup and moves focus to the multiselect element.
-
+
Filter Input Keyboard Support
+
+ + + + + + + + + + + + + + + + + +
KeyFunction
+ enter + Closes the popup and moves focus to the multiselect element.
+ escape + Closes the popup and moves focus to the multiselect element.
+
-
Close Button Keyboard Support
-
- - - - - - - - - - - - - - - - - - - - - -
KeyFunction
enterCloses the popup and moves focus to the multiselect element.
spaceCloses the popup and moves focus to the multiselect element.
escapeCloses the popup and moves focus to the multiselect element.
-
- +
Close Button Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ enter + Closes the popup and moves focus to the multiselect element.
+ space + Closes the popup and moves focus to the multiselect element.
+ escape + Closes the popup and moves focus to the multiselect element.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'MultiSelectDemo', sources: sources, extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'MultiSelectDemo', sources: sources, extFiles: extFiles })}
); -}) +}); export default MultiSelectDoc; diff --git a/components/doc/multistatecheckbox/index.js b/components/doc/multistatecheckbox/index.js index 2d53520a15..056beb5750 100644 --- a/components/doc/multistatecheckbox/index.js +++ b/components/doc/multistatecheckbox/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const MultiStateCheckboxDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -45,7 +44,7 @@ export class MultiStateCheckboxDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -72,7 +71,7 @@ const MultiStateCheckboxDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -99,9 +98,9 @@ const MultiStateCheckboxDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', - imports: ` + imports: ` `, content: ` @@ -129,31 +128,33 @@ const MultiStateCheckboxDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { MultiStateCheckbox } from 'primereact/multistatecheckbox'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

MultiStateCheckbox is used as a controlled input with value, options and onChange properties. The optionValue field refers to the value of each option.

- -{` +

+ MultiStateCheckbox is used as a controlled input with value, options and onChange properties. The optionValue field refers to the value of each option. +

+ + {` const [value, setValue] = useState('public'); const options = [ { value: 'public', icon: 'pi pi-globe' }, @@ -161,257 +162,269 @@ const options = [ { value: 'private', icon: 'pi pi-lock' } ]; `} - +
- -{` + + {` setValue(e.value)} optionValue="value" /> `} - - -
Icons
-

Icon of each option is defined with the icon property of an option object. For templating use iconTemplate to render custom content inside the checkbox.

+
-
Option
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDefaultDescription
iconstringnullThe icon of the option. This is optional. The iconTemplate property can be used instead.
styleobjectnullInline style of the checkbox element when the option is selected.
classNamestringnullStyle class of the checkbox element when the option is selected.
-
- -
Properties
-

Any valid attribute is passed to the root element implicitly, extended properties are as follows;

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDefaultDescription
idstringnullUnique identifier of the element.
valueanynullValue of the MultiStateCheckbox.
optionsarraynullAn array to display as the available options.
optionValuestringnullProperty name to use as the value of an option, defaults to the option itself when not defined.
optionLabelstringnullProperty name to refer to the option label, used by screen readers only. Defaults to optionValue.
iconTemplateanynullTemplate of icon for the selected option.
dataKeystringnullA property to uniquely match the value in options for better performance.
stylestringnullInline style of the element.
classNamestringnullStyle class of the element.
disabledbooleanfalseWhen present, it specifies that the element value cannot be altered.
readOnlybooleanfalseWhen present, it specifies that the value cannot be changed.
tabIndexnumbernullIndex of the element in tabbing order.
emptybooleantrueIf false, the empty state is skipped in the chekbox.
tooltipanynullContent of the tooltip.
tooltipOptionsobjectnullConfiguration of the tooltip, refer to the tooltip documentation for more information.
-
+
Icons
+

+ Icon of each option is defined with the icon property of an option object. For templating use iconTemplate to render custom content inside the checkbox. +

-
Events
-
- - - - - - - - - - - - - - - -
NameParametersDescription
onChangeevent.originalEvent: Browser event
- event.value: Current Value -
Callback to invoke on value change
-
+
Option
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
iconstringnull + The icon of the option. This is optional. The iconTemplate property can be used instead. +
styleobjectnullInline style of the checkbox element when the option is selected.
classNamestringnullStyle class of the checkbox element when the option is selected.
+
-
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
- - - - - - - - - - - - - - - - - - - - - - - - - -
NameElement
p-chkboxContainer element
p-multistatechkboxContainer element
p-chkbox-boxContainer of icon.
p-chkbox-iconIcon element.
-
+
Properties
+

Any valid attribute is passed to the root element implicitly, extended properties are as follows;

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
idstringnullUnique identifier of the element.
valueanynullValue of the MultiStateCheckbox.
optionsarraynullAn array to display as the available options.
optionValuestringnullProperty name to use as the value of an option, defaults to the option itself when not defined.
optionLabelstringnullProperty name to refer to the option label, used by screen readers only. Defaults to optionValue.
iconTemplateanynullTemplate of icon for the selected option.
dataKeystringnullA property to uniquely match the value in options for better performance.
stylestringnullInline style of the element.
classNamestringnullStyle class of the element.
disabledbooleanfalseWhen present, it specifies that the element value cannot be altered.
readOnlybooleanfalseWhen present, it specifies that the value cannot be changed.
tabIndexnumbernullIndex of the element in tabbing order.
emptybooleantrueIf false, the empty state is skipped in the chekbox.
tooltipanynullContent of the tooltip.
tooltipOptionsobjectnullConfiguration of the tooltip, refer to the tooltip documentation for more information.
+
-
Accessibility
- -
Screen Reader
-

MultiStateCheckbox component uses an element with checkbox role. Value to describe the component can either be provided with aria-labelledby or aria-label props. Component adds an element with - aria-live attribute that is only visible to screen readers to read the value displayed. Values to read are defined with the optionLabel property that defaults to optionValue if not defined. Unchecked state label on the other hand is - retrieved from nullLabel key of the aria property from the locale API. This is an example of a custom accessibility implementation as there is no one to one mapping between the component design and the WCAG specification.

- -{` -Access Type - +
Events
+
+ + + + + + + + + + + + + + + +
NameParametersDescription
onChange + event.originalEvent: Browser event
+ event.value: Current Value +
Callback to invoke on value change
+
- -`} -
-
Keyboard Support
-
- +
Styling
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
- - + + - - + + + + + + - - + + + + + +
KeyFunctionNameElement
tabMoves focus to the checkbox.p-chkboxContainer element
p-multistatechkboxContainer element
spaceToggles between the values.p-chkbox-boxContainer of icon.
p-chkbox-iconIcon element.
-
-
Dependencies
-

None.

-
- { - useLiveEditorTabs({ name: 'MultiStateCheckboxDemo', sources: sources }) - } -
-
- ) -}) +
Accessibility
+ +
Screen Reader
+

+ MultiStateCheckbox component uses an element with checkbox role. Value to describe the component can either be provided with aria-labelledby or aria-label props. Component adds an element with + aria-live attribute that is only visible to screen readers to read the value displayed. Values to read are defined with the optionLabel property that defaults to optionValue if not defined. Unchecked + state label on the other hand is retrieved from nullLabel key of the aria property from the locale API. This is an example of a custom accessibility implementation as there is no + one to one mapping between the component design and the WCAG specification. +

+ + {` +Access Type + + + +`} + +
Keyboard Support
+
+ + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the checkbox.
+ space + Toggles between the values.
+
+
+
Dependencies
+

None.

+ + + {useLiveEditorTabs({ name: 'MultiStateCheckboxDemo', sources: sources })} + +
+ ); +}); export default MultiStateCheckboxDoc; diff --git a/components/doc/orderlist/index.js b/components/doc/orderlist/index.js index a7294198c8..af3d1bd6ce 100644 --- a/components/doc/orderlist/index.js +++ b/components/doc/orderlist/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const OrderListDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -65,7 +64,7 @@ export class OrderListDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState, useEffect } from 'react'; @@ -111,7 +110,7 @@ const OrderListDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState, useEffect } from 'react'; @@ -157,7 +156,7 @@ const OrderListDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -262,61 +261,68 @@ const OrderListDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { OrderList } from 'primereact/orderlist'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

OrderList requires an array as its value, a template for its content where each item in the array can be accessed inside the template and onChange - callback to update the value after reorder. +

+ OrderList requires an array as its value, a template for its content where each item in the array can be accessed inside the template and onChange + callback to update the value after reorder.

- -{` + + {` setProducts(e.value)}> `} - +
DragDrop
-

Items can be reordered using drag and drop by enabling dragdrop property.

+

+ Items can be reordered using drag and drop by enabling dragdrop property. +

- -{` + + {` setProducts(e.value)}> `} - +
Filtering
-

Items can be filtered using an input field by enabling the filter property. By default filtering is done against - label of the items and filterBy property is available to choose one or more properties of the options. In addition filterMatchMode can be utilized - to define the filtering algorithm, valid options are "contains" (default), "startsWith", "endsWith", "equals" and "notEquals".

+

+ Items can be filtered using an input field by enabling the filter property. By default filtering is done against label of the items and filterBy property is available to choose one or more properties of the + options. In addition filterMatchMode can be utilized to define the filtering algorithm, valid options are "contains" (default), "startsWith", "endsWith", "equals" and "notEquals". +

- -{` + + {` `} - +
Custom Content
-

For custom content support define an itemTemplate function that gets the item instance as a parameter and returns the content. For custom filter support define a filterTemplate function that gets the option instance as a parameter and returns the content for the filter element.

+

+ For custom content support define an itemTemplate function that gets the item instance as a parameter and returns the content. For custom filter support define a filterTemplate function that gets the option + instance as a parameter and returns the content for the filter element. +

- -{` + + {` const [filterValue, setFilterValue] = useState(''); const filterInputRef = useRef(); @@ -347,24 +353,24 @@ const myFilterFunction = (event, options) => { options.filter(event); } `} - + - -{` + + {` `} - +
Properties
-
- +
+
- - - - - - + + + + + + @@ -474,26 +480,30 @@ const myFilterFunction = (event, options) => {
Events
-
-
NameTypeDefaultDescription
NameTypeDefaultDescription
+
+
- - - - - + + + + + - + - + @@ -501,8 +511,8 @@ const myFilterFunction = (event, options) => {
Methods
-
-
NameParametersDescription
NameParametersDescription
onChangeevent.originalEvent: Browser event
- event.value: Reordered list
+ event.originalEvent: Browser event
+ event.value: Reordered list +
Callback to invoke when list is reordered.
onFilterevent.originalEvent: Original event
- event.filter: Value of the filter input
+ event.originalEvent: Original event
+ event.filter: Value of the filter input +
Callback to invoke when the value is filtered.
+
+
@@ -521,9 +531,11 @@ const myFilterFunction = (event, options) => {
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -560,119 +572,152 @@ const myFilterFunction = (event, options) => {
Accessibility
- -
Screen Reader
-

Value to describe the listbox can be provided with listProps by passing aria-labelledby or aria-label props. The list element has a listbox role with the aria-multiselectable attribute. - Each list item has an option role with aria-selected and aria-disabled as their attributes.

-

Controls buttons are button elements with an aria-label that refers to the aria.moveTop, aria.moveUp, aria.moveDown and aria.moveBottom properties of the locale API by default, alternatively you may use - moveTopButtonProps, moveUpButtonProps, moveDownButtonProps and moveBottomButtonProps to customize the buttons like overriding the default aria-label attributes.

- -{` + +
Screen Reader
+

+ Value to describe the listbox can be provided with listProps by passing aria-labelledby or aria-label props. The list element has a listbox role with the aria-multiselectable attribute. + Each list item has an option role with aria-selected and aria-disabled as their attributes. +

+

+ Controls buttons are button elements with an aria-label that refers to the aria.moveTop, aria.moveUp, aria.moveDown and aria.moveBottom properties of the{' '} + locale API by default, alternatively you may use + moveTopButtonProps, moveUpButtonProps, moveDownButtonProps and moveBottomButtonProps to customize the buttons like overriding the default aria-label attributes. +

+ + {` Options `} - -
ListBox Keyboard Support
-
-
Name
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus to the first selected option, if there is none then first option receives the focus.
up arrowMoves focus to the previous option.
down arrowMoves focus to the next option.
enterToggles the selected state of the focused option.
spaceToggles the selected state of the focused option.
homeMoves focus to the first option.
endMoves focus to the last option.
shift + down arrowMoves focus to the next option and toggles the selection state.
shift + up arrowMoves focus to the previous option and toggles the selection state.
shift + spaceSelects the items between the most recently selected option and the focused option.
control + shift + homeSelects the focused options and all the options up to the first one.
control + shift + endSelects the focused options and all the options down to the first one.
control + aSelects all options.
-
- -
Buttons Keyboard Support
-
- - - - - - - - - - - - - - - - - -
KeyFunction
enterExecutes button action.
spaceExecutes button action.
-
- + +
ListBox Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the first selected option, if there is none then first option receives the focus.
+ up arrow + Moves focus to the previous option.
+ down arrow + Moves focus to the next option.
+ enter + Toggles the selected state of the focused option.
+ space + Toggles the selected state of the focused option.
+ home + Moves focus to the first option.
+ end + Moves focus to the last option.
+ shift + down arrow + Moves focus to the next option and toggles the selection state.
+ shift + up arrow + Moves focus to the previous option and toggles the selection state.
+ shift + space + Selects the items between the most recently selected option and the focused option.
+ control + shift + home + Selects the focused options and all the options up to the first one.
+ control + shift + end + Selects the focused options and all the options down to the first one.
+ control + a + Selects all options.
+
+ +
Buttons Keyboard Support
+
+ + + + + + + + + + + + + + + + + +
KeyFunction
+ enter + Executes button action.
+ space + Executes button action.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'OrderListDemo', sources: sources, service: 'ProductService', data: 'products-small', extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'OrderListDemo', sources: sources, service: 'ProductService', data: 'products-small', extFiles: extFiles })}
); -}) +}); export default OrderListDoc; diff --git a/components/doc/organizationchart/index.js b/components/doc/organizationchart/index.js index df5b7b3b6a..1df7957636 100644 --- a/components/doc/organizationchart/index.js +++ b/components/doc/organizationchart/index.js @@ -5,9 +5,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const OrganizationChartDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -158,7 +157,7 @@ export class OrganizationChartDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -297,7 +296,7 @@ const OrganizationChartDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -436,7 +435,7 @@ const OrganizationChartDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -579,7 +578,7 @@ const OrganizationChartDemo = () => { } ` } - } + }; const extFiles = { 'demo/OrganizationChartDemo.css': { @@ -627,31 +626,31 @@ const OrganizationChartDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { OrganizationChart } from 'primereact/organizationchart'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started

OrganizationChart requires a model of TreeNode as its value.

- -{` + + {` export const OrganizationChartDemo = () => { const data = [{ @@ -690,19 +689,19 @@ export const OrganizationChartDemo = () => { ) } `} - +
Templating

Label of the treenode is displayed inside the node content by default and templating enables further customization.

- -{` + + {` `} - + - -{` + + {` const nodeTemplate = (node) => { if (node.type === "person") { @@ -722,22 +721,25 @@ const nodeTemplate = (node) => { } } `} - +
Expand/Collapse State

In order to display a treenode as expanded by default, set "expanded" property as true in your model.

Selection
-

OrganizationChart supports two selection methods; single or multiple. Selection is enabled by setting selectionMode property to the corresponding mode, defining selection property along with selectionChange callback.

- -{` +

+ OrganizationChart supports two selection methods; single or multiple. Selection is enabled by setting selectionMode property to the corresponding mode, defining selection property along with{' '} + selectionChange callback. +

+ + {` setSelectedNode(event.data)}> `} - +
Properties
-
- +
+
@@ -794,8 +796,8 @@ const nodeTemplate = (node) => {
Events
-
-
Name
+
+
@@ -806,20 +808,26 @@ const nodeTemplate = (node) => { - + - + - + @@ -828,8 +836,8 @@ const nodeTemplate = (node) => {
Styling

Following is the list of structural style classes.

-
-
Name
onNodeSelectevent.originalEvent: browser event
- event.node: Selected node instance.
+ event.originalEvent: browser event
+ event.node: Selected node instance. +
Callback to invoke when a node is selected.
onNodeUnselectevent.originalEvent: browser event
- event.node: Unselected node instance.
+ event.originalEvent: browser event
+ event.node: Unselected node instance. +
Callback to invoke when a node is unselected.
onSelectionChangeevent.originalEvent: browser event
- event.data: New selection.
+ event.originalEvent: browser event
+ event.data: New selection. +
Callback to invoke when node selection changes.
+
+
@@ -870,49 +878,54 @@ const nodeTemplate = (node) => {
Accessibility
- -
Screen Reader
-

Component currently uses a table based implementation and does not provide high level of screen reader support, - a nested list implementation replacement is planned with aria roles and attributes aligned to a tree widget for high level of reader support in the upcoming versions.

- -
Keyboard Support
-
-
Name
- - - - - - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus through the focusable elements within the chart.
enterToggles the expanded state of a node.
spaceToggles the expanded state of a node.
-
- + +
Screen Reader
+

+ Component currently uses a table based implementation and does not provide high level of screen reader support, a nested list implementation replacement is planned with aria roles and attributes aligned to a tree widget + for high level of reader support in the upcoming versions. +

+ +
Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus through the focusable elements within the chart.
+ enter + Toggles the expanded state of a node.
+ space + Toggles the expanded state of a node.
+
+
Dependencies

None.

-
- { - useLiveEditorTabs({ name: 'OrganizationChartDemo', sources: sources, extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'OrganizationChartDemo', sources: sources, extFiles: extFiles })}
); -}) +}); export default OrganizationChartDoc; diff --git a/components/doc/overlaypanel/index.js b/components/doc/overlaypanel/index.js index 94c1a01d2d..4c5921cf0e 100644 --- a/components/doc/overlaypanel/index.js +++ b/components/doc/overlaypanel/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const OverlayPanelDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -82,7 +81,7 @@ export class OverlayPanelDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState, useEffect, useRef } from 'react'; @@ -151,7 +150,7 @@ const OverlayPanelDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState, useEffect, useRef } from 'react'; @@ -273,7 +272,7 @@ type ProductItem = { }; ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -364,73 +363,74 @@ const OverlayPanelDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { OverlayPanel } from 'primereact/overlaypanel'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started

OverlayPanel is accessed via its reference where visibility is controlled using toggle, show and hide methods.

- -{` + + {`
); -}) +}); export default OverlayPanelDoc; diff --git a/components/doc/paginator/index.js b/components/doc/paginator/index.js index 2d94357a86..0656b98ef7 100644 --- a/components/doc/paginator/index.js +++ b/components/doc/paginator/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const PaginatorDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -229,7 +228,7 @@ export class PaginatorDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -424,7 +423,7 @@ const PaginatorDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -619,7 +618,7 @@ const PaginatorDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -829,66 +828,67 @@ const PaginatorDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Paginator } from 'primereact/paginator'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

Paginator is used as a controlled component with first, rows (optional) and onPageChange properties.

+

+ Paginator is used as a controlled component with first, rows (optional) and onPageChange properties. +

- -{` + + {` setFirst(e.first)}> `} - +
Rows and TotalRecords

Rows and TotalRecords define how many pages the paginator should display. Paginator below will have 10 pages.

- -{` + + {` setFirst(e.first)}> `} - +
Rows Per Page
-

Number of items per page can be changed by the user using a dropdown if you define rowsPerPageOptions as an array of possible values. In this case, - rows property should also be updated -

- -{` +

Number of items per page can be changed by the user using a dropdown if you define rowsPerPageOptions as an array of possible values. In this case, rows property should also be updated

+ + {` const onPageChange = (e) => { setFirst(e.first); setRows(e.rows); } `} - - -{` + + + {` `} - +
Template
-

Paginator elements can be customized using the template property using the predefined keys, default value is - "FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown". Here are the available elements that - can be placed inside a paginator.

+

+ Paginator elements can be customized using the template property using the predefined keys, default value is "FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown". Here are the available elements + that can be placed inside a paginator. +

  • FirstPageLink
  • @@ -901,9 +901,11 @@ const onPageChange = (e) => {
  • CurrentPageReport
-

The pagination element is fully customizable. To make special paginators, an object can be given to the template property as below.

- -{` +

+ The pagination element is fully customizable. To make special paginators, an object can be given to the template property as below. +

+ + {` const template = { layout: 'FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown CurrentPageReport', // The above keys can be set in the desired order. 'FirstPageLink': (options) => { @@ -987,16 +989,15 @@ const template = { } }; `} - - -{` + + + {` `} - +
CurrentPageReport
-

Current page report item in the itemplate displays information about the pagination state. Default value is ({currentPage} of {totalPages}) - whereas available placeholders are the following;

+

Current page report item in the itemplate displays information about the pagination state. Default value is ({currentPage} of {totalPages}) whereas available placeholders are the following;

  • {currentPage}
  • {totalPages}
  • @@ -1007,8 +1008,8 @@ const template = {
Properties
-
- +
+
@@ -1082,22 +1083,23 @@ const template = { - + - +
NamecurrentPageReportTemplate string ({currentPage} of {totalPages})Template of the current page report element. Available placeholders are - {currentPage},{totalPages},{rows},{first},{last} and {totalRecords}Template of the current page report element. Available placeholders are {currentPage},{totalPages},{rows},{first},{last} and {totalRecords}
dropdownAppendTo DOM element | string document.bodyDOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. + DOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. +
Events
-
- +
+
@@ -1108,12 +1110,13 @@ const template = { - + @@ -1121,9 +1124,11 @@ const template = {
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
onPageChangeevent.page: New page number
- event.first: Index of first record
- event.rows: Number of rows to display in new page
- event.page: Index of the new page
- event.pageCount: Total number of pages -
+ event.page: New page number
+ event.first: Index of first record
+ event.rows: Number of rows to display in new page
+ event.page: Index of the new page
+ event.pageCount: Total number of pages +
Callback to invoke when page changes, the event object contains information about the new state.
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -1170,23 +1175,36 @@ const template = {
Accessibility
Screen Reader
-

Paginator is placed inside a nav element to indicate a navigation section. All of the paginator elements can be customized using templating however the default behavious is listed below.

- -

First, previous, next and last page navigators elements with aria-label attributes referring to the aria.firstPageLabel, aria.prevPageLabel, aria.nextPageLabel and aria.lastPageLabel - properties of the locale API respectively.

+

+ Paginator is placed inside a nav element to indicate a navigation section. All of the paginator elements can be customized using templating however the default behavious is listed below. +

-

Page links are also button elements with an aria-label attribute derived from the aria.pageLabel of the locale API. Current page is marked with aria-current set to "page" as well.

+

+ First, previous, next and last page navigators elements with aria-label attributes referring to the aria.firstPageLabel, aria.prevPageLabel, aria.nextPageLabel and aria.lastPageLabel + properties of the locale API respectively. +

-

Current page report uses aria-live="polite" to instruct screen reader about the changes to the pagination state.

+

+ Page links are also button elements with an aria-label attribute derived from the aria.pageLabel of the locale API. Current page is marked with aria-current set to "page" as + well. +

-

Rows per page dropdown internally uses a dropdown component, refer to the dropdown documentation for accessibility details. Additionally, the dropdown uses an aria-label - from the aria.rowsPerPage property of the locale API.

+

+ Current page report uses aria-live="polite" to instruct screen reader about the changes to the pagination state. +

-

Jump to page input is an input element with an aria-label that refers to the aria.jumpToPage property of the locale API.

+

+ Rows per page dropdown internally uses a dropdown component, refer to the dropdown documentation for accessibility details. Additionally, the dropdown uses an aria-label + from the aria.rowsPerPage property of the locale API. +

+ +

+ Jump to page input is an input element with an aria-label that refers to the aria.jumpToPage property of the locale API. +

Keyboard Support
-
-
Name
+
+
@@ -1195,15 +1213,21 @@ const template = { - + - + - + @@ -1211,19 +1235,19 @@ const template = {
Rows Per Page Dropdown Keyboard Support
-

Refer to the dropdown documentation for more details about keyboard support.

+

+ Refer to the dropdown documentation for more details about keyboard support. +

Dependencies

None.

- { - useLiveEditorTabs({ name: 'PaginatorDemo', sources: sources, extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'PaginatorDemo', sources: sources, extFiles: extFiles })} ); -}) +}); export default PaginatorDoc; diff --git a/components/doc/panel/index.js b/components/doc/panel/index.js index dddab47bcb..0b2c32ca68 100644 --- a/components/doc/panel/index.js +++ b/components/doc/panel/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const PanelDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -73,7 +72,7 @@ export class PanelDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React from 'react'; @@ -129,7 +128,7 @@ const PanelDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React from 'react'; @@ -185,7 +184,7 @@ const PanelDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -244,31 +243,31 @@ const PanelDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Panel } from 'primereact/panel'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started

Panel is a container component that accepts content as its children.

- -{` + + {`

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. @@ -276,17 +275,23 @@ import { Panel } from 'primereact/panel'; cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

`} -
+
-

header propery also can be used to provide custom content as JSX.

+

+ header propery also can be used to provide custom content as JSX. +

Toggleable
-

Content of the panel can be expanded and collapsed using toggleable option. A toggleable panel can either be used as a Controlled or Uncontrolled component.

+

+ Content of the panel can be expanded and collapsed using toggleable option. A toggleable panel can either be used as a Controlled or Uncontrolled component. +

-

In controlled mode, collapsed and onToggle properties needs to be defined to control the collapsed state.

+

+ In controlled mode, collapsed and onToggle properties needs to be defined to control the collapsed state. +

- -{` + + {` setPanelCollapsed(e.value)}>

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. @@ -294,13 +299,15 @@ import { Panel } from 'primereact/panel'; cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

`} -
+
-

In uncontrolled mode, only toggleable property needs to be enabled. Initial state can be still be provided using the collapsed property in uncontrolled mode however - it is evaluated at initial rendering and ignored in further updates. If you programmatically need to update the collapsed state, prefer to use the component as controlled.

+

+ In uncontrolled mode, only toggleable property needs to be enabled. Initial state can be still be provided using the collapsed property in uncontrolled mode however it is evaluated at initial rendering and + ignored in further updates. If you programmatically need to update the collapsed state, prefer to use the component as controlled. +

- -{` + + {`

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. @@ -308,12 +315,14 @@ import { Panel } from 'primereact/panel'; cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

`} -
+
Header Template
-

The header element is fully customizable on Panel. To make special header, an object can be given to the headerTemplate property as below.

- -{` +

+ The header element is fully customizable on Panel. To make special header, an object can be given to the headerTemplate property as below. +

+ + {`

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. @@ -321,10 +330,10 @@ import { Panel } from 'primereact/panel'; cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

`} -
+
- - {` + + {` template: (options) => { // options.className: Style class of the default header element. // options.titleClassName: Style class of the title element. @@ -340,11 +349,11 @@ template: (options) => { // options.collapsed: Whether the panel is collapsed. } `} - +
Properties
-
-
Key
tab + tab + Moves focus through the paginator elements.
enter + enter + Executes the paginator element action.
space + space + Executes the paginator element action.
+
+
@@ -406,21 +415,27 @@ template: (options) => { - +
NametransitionOptions object nullThe properties of CSSTransition can be customized, except for "nodeRef" and "in" properties. + The properties of{' '} + + CSSTransition + {' '} + can be customized, except for "nodeRef" and "in" properties. +
Events
-
- +
+
- - - - - + + + + + @@ -435,7 +450,8 @@ template: (options) => { - @@ -445,9 +461,11 @@ template: (options) => {
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
NameParametersDescription
NameParametersDescription
onToggleevent.originalEvent: browser event
+
+ event.originalEvent: browser event
event.value: collapsed state as a boolean
Callback to invoke when a tab gets expanded.
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -480,54 +498,64 @@ template: (options) => {
Accessibility
- -
Screen Reader
-

Toggleable panels use a content toggle button at the header that has aria-controls to define the id of the content section along with aria-expanded for the visibility state. The value to read the button - defaults to the value of the header property and can be customized by defining an aria-label or aria-labelledby via the toggleButtonProps property.

-

The content uses region, defines an id that matches the aria-controls of the content toggle button and aria-labelledby referring to the id of the header.

- -
Content Toggle Button Keyboard Support
-
-
Name
- - - - - - - - - - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus to the next the focusable element in the page tab sequence.
shift + tabMoves focus to the previous the focusable element in the page tab sequence.
enterToggles the visibility of the content.
spaceToggles the visibility of the content.
-
- + +
Screen Reader
+

+ Toggleable panels use a content toggle button at the header that has aria-controls to define the id of the content section along with aria-expanded for the visibility state. The value to read the button + defaults to the value of the header property and can be customized by defining an aria-label or aria-labelledby via the toggleButtonProps property. +

+

+ The content uses region, defines an id that matches the aria-controls of the content toggle button and aria-labelledby referring to the id of the header. +

+ +
Content Toggle Button Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the next the focusable element in the page tab sequence.
+ shift + tab + Moves focus to the previous the focusable element in the page tab sequence.
+ enter + Toggles the visibility of the content.
+ space + Toggles the visibility of the content.
+
+
Dependencies
  • react-transition-group
- { - useLiveEditorTabs({ name: 'PanelDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'PanelDemo', sources: sources })}
); -}) +}); export default PanelDoc; diff --git a/components/doc/panelmenu/index.js b/components/doc/panelmenu/index.js index 01c05e3373..4be8699d1a 100644 --- a/components/doc/panelmenu/index.js +++ b/components/doc/panelmenu/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const PanelMenuDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -149,7 +148,7 @@ export class PanelMenuDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React from 'react'; @@ -283,7 +282,7 @@ const PanelMenuDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React from 'react'; @@ -417,7 +416,7 @@ const PanelMenuDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -554,39 +553,41 @@ const PanelMenuDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { PanelMenu } from 'primereact/panelmenu'; `} - +
Import via CDN
- -{` + + {` `} - +
MenuItem API
-

PanelMenu uses the common menu item api to define its items, visit MenuModel for details.

+

+ PanelMenu uses the common menu item api to define its items, visit MenuModel for details. +

Getting Started

PanelMenu requires a collection of menuitems as its model.

- -{` + + {` `} - + - -{` + + {` const items = [ { label:'File', @@ -705,11 +706,11 @@ const items = [ } ]; `} - +
Properties
-
- +
+
@@ -753,16 +754,24 @@ const items = [ - +
NametransitionOptions object nullThe properties of CSSTransition can be customized, except for "nodeRef" and "in" properties. + The properties of{' '} + + CSSTransition + {' '} + can be customized, except for "nodeRef" and "in" properties. +
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
- +

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -809,15 +818,22 @@ const items = [
Accessibility
Screen Reader
-

Accordion header elements have a button role, an aria-label defined using the label property of the menuitem model and aria-controls to define the id of the content section along with aria-expanded for the visibility state.

-

The content of an accordion panel uses region role, defines an id that matches the aria-controls of the header and aria-labelledby referring to the id of the header.

+

+ Accordion header elements have a button role, an aria-label defined using the label property of the menuitem model and aria-controls to define the id of the content section along with{' '} + aria-expanded for the visibility state. +

+

+ The content of an accordion panel uses region role, defines an id that matches the aria-controls of the header and aria-labelledby referring to the id of the header. +

-

The tree elements has a tree as the role and each menu item has a treeitem role along with aria-label, aria-selected and aria-expanded attributes. The container - element of a treenode has the group role. The aria-setsize, aria-posinset and aria-level attributes are calculated implicitly and added to each treeitem.

+

+ The tree elements has a tree as the role and each menu item has a treeitem role along with aria-label, aria-selected and aria-expanded attributes. The container element of a treenode has + the group role. The aria-setsize, aria-posinset and aria-level attributes are calculated implicitly and added to each treeitem. +

Header Keyboard Support
-
-
Name
+
+
@@ -826,31 +842,45 @@ const items = [ - + - + - + - + - + - + - + @@ -858,8 +888,8 @@ const items = [
Tree Keyboard Support
-
-
Key
tab + tab + Adds focus to the first header when focus moves in to the component, if there is already a focused tab header then moves the focus out of the component based on the page tab sequence.
enter + enter + Toggles the visibility of the content.
space + space + Toggles the visibility of the content.
down arrow + down arrow + If panel is collapsed then moves focus to the next header, otherwise first treenode of the panel receives the focus.
up arrow + up arrow + If previous panel is collapsed then moves focus to the previous header, otherwise last treenode of the previous panel receives the focus.
home + home + Moves focus to the first header.
end + end + Moves focus to the last header.
+
+
@@ -868,35 +898,51 @@ const items = [ - + - + - + - + - + - + - + - + @@ -908,12 +954,10 @@ const items = [

None.

- { - useLiveEditorTabs({ name: 'PanelMenuDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'PanelMenuDemo', sources: sources })} - ) -}) + ); +}); export default PanelMenuDoc; diff --git a/components/doc/password/index.js b/components/doc/password/index.js index 7f0d501e74..880124df3c 100644 --- a/components/doc/password/index.js +++ b/components/doc/password/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const PasswordDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, {Component} from 'react'; @@ -65,7 +64,7 @@ export class PasswordDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -113,7 +112,7 @@ const PasswordDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React from 'react'; @@ -161,7 +160,7 @@ const PasswordDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -214,7 +213,7 @@ const PasswordDemo = () => { } ` } - } + }; const extFiles = { 'demo/PasswordDemo.css': { @@ -224,40 +223,42 @@ width: 15rem; } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Password } from 'primereact/password'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

Password is used as a controlled component with value and onChange properties.

- -{` +

+ Password is used as a controlled component with value and onChange properties. +

+ + {` setValue(e.target.value)} /> `} - +
Properties

Password accepts all valid properties of an input element in addition the the custom properties below.

-
-
Key
tab + tab + Moves focus to the next focusable element in the page tab order.
shift + tab + shift + tab + Moves focus to the previous focusable element in the page tab order.
enter + enter + Activates the focused treenode.
space + space + Activates the focused treenode.
down arrow + down arrow + Moves focus to the next treenode.
up arrow + up arrow + Moves focus to the previous treenode.
right arrow + right arrow + If node is closed, opens the node otherwise moves focus to the first child node.
left arrow + left arrow + If node is open, closes the node otherwise moves focus to the parent node.
+
+
@@ -331,7 +332,9 @@ import { Password } from 'primereact/password'; - + @@ -409,21 +412,27 @@ import { Password } from 'primereact/password'; - +
NameappendTo DOM element | string document.bodyDOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. + DOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. +
headertransitionOptions object nullThe properties of CSSTransition can be customized, except for "nodeRef" and "in" properties. + The properties of{' '} + + CSSTransition + {' '} + can be customized, except for "nodeRef" and "in" properties. +
Events
-
- +
+
- - - - - + + + + + @@ -441,9 +450,11 @@ import { Password } from 'primereact/password';
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
NameParametersDescription
NameParametersDescription
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -476,12 +487,14 @@ import { Password } from 'primereact/password';
Accessibility
- -
Screen Reader
-

Value to describe the component can either be provided via label tag combined with id prop or using aria-labelledby, aria-label props. Screen reader - is notified about the changes to the strength of the password using a section that has aria-live while typing.

- -{` + +
Screen Reader
+

+ Value to describe the component can either be provided via label tag combined with id prop or using aria-labelledby, aria-label props. Screen reader is notified about the changes to the strength + of the password using a section that has aria-live while typing. +

+ + {` @@ -490,39 +503,41 @@ import { Password } from 'primereact/password'; `} - -
Keyboard Support
-
-
Name
- - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus to the input.
escapeHides the strength meter if open.
-
- + +
Keyboard Support
+
+ + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the input.
+ escape + Hides the strength meter if open.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'PasswordDemo', sources: sources, extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'PasswordDemo', sources: sources, extFiles: extFiles })}
- ) -}) + ); +}); export default PasswordDoc; diff --git a/components/doc/picklist/index.js b/components/doc/picklist/index.js index 6cd540e3b8..4d8b10791d 100644 --- a/components/doc/picklist/index.js +++ b/components/doc/picklist/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const PickListDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -75,7 +74,7 @@ export class PickListDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState, useEffect } from 'react'; @@ -128,7 +127,7 @@ const PickListDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState, useEffect } from 'react'; @@ -181,7 +180,7 @@ const PickListDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -293,58 +292,61 @@ const PickListDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { PickList } from 'primereact/picklist'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

PickList requires two arrays as source and target lists, an itemTemplate for the item content and onChange callback to update the value after reorder or transfer.

- -{` +

+ PickList requires two arrays as source and target lists, an itemTemplate for the item content and onChange callback to update the value after reorder or transfer. +

+ + {` const onChange = (e) => { setSource(e.source); setTarget(e.target); } `} - - -{` + + + {` `} - - +
Headers
-

sourceHeader and targetHeader properties are used to define captions for the lists that accept simple strings or JSX for custom content.

+

+ sourceHeader and targetHeader properties are used to define captions for the lists that accept simple strings or JSX for custom content. +

- -{` + + {` `} - +
Properties
-
- +
+
@@ -436,8 +438,9 @@ const onChange = (e) => { - @@ -456,8 +459,10 @@ const onChange = (e) => { - + @@ -542,8 +547,8 @@ const onChange = (e) => {
Events
-
-
NameitemTemplate function nullTemplate that gets the options for both source and target items and returns the content for it. - Useful if you want the same template for both lists else use the custom sourceItemTemplate or targetItemTemplate properties. + + Template that gets the options for both source and target items and returns the content for it. Useful if you want the same template for both lists else use the custom sourceItemTemplate or{' '} + targetItemTemplate properties.
metaKeySelection boolean trueDefines how multiple items can be selected, when true metaKey needs to be pressed to select or unselect an item and when set to false selection of each item - can be toggled individually. On touch enabled devices, metaKeySelection is turned off automatically. + Defines how multiple items can be selected, when true metaKey needs to be pressed to select or unselect an item and when set to false selection of each item can be toggled individually. On touch enabled + devices, metaKeySelection is turned off automatically. +
filterBy
+
+
@@ -554,57 +559,75 @@ const onChange = (e) => { - + - + - + - + - + - + - + - + - + @@ -612,9 +635,11 @@ const onChange = (e) => {
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
onChangeevent.originalEvent: Browser event
- event.source: Source list
- event.target: Target list
+ event.originalEvent: Browser event
+ event.source: Source list
+ event.target: Target list{' '} +
Callback to invoke when items are moved from source to target.
onMoveToSourceevent.originalEvent: Browser event
- event.value: Moved items
+ event.originalEvent: Browser event
+ event.value: Moved items +
Callback to invoke when items are moved from target to source.
onMoveAllToSourceevent.originalEvent: Browser event
- event.value: Moved items
+ event.originalEvent: Browser event
+ event.value: Moved items +
Callback to invoke when all items are moved from target to source.
onMoveToTargetevent.originalEvent: Browser event
- event.value: Moved items
+ event.originalEvent: Browser event
+ event.value: Moved items +
Callback to invoke when items are moved from source to target.
onMoveAllToTargetevent.originalEvent: Browser event
- event.value: Moved items
+ event.originalEvent: Browser event
+ event.value: Moved items +
Callback to invoke when all items are moved from source to target.
onSourceSelectionChangeevent.originalEvent: Browser event
- items: Selected items array
+ event.originalEvent: Browser event
+ items: Selected items array +
Callback to invoke when items are selected within source list.
onTargetSelectionChangeevent.originalEvent: Browser event
- items: Selected items array
+ event.originalEvent: Browser event
+ items: Selected items array +
Callback to invoke when items are selected within target list.
onSourceFilterChangeevent.originalEvent: Browser event
- event.value: Filtered value
+ event.originalEvent: Browser event
+ event.value: Filtered value +
Callback to invoke when items are filtered within source list.
onTargetFilterChangeevent.originalEvent: Browser event
- event.value: Filtered value
+ event.originalEvent: Browser event
+ event.value: Filtered value +
Callback to invoke when items are filtered within target list.
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -654,123 +679,154 @@ const onChange = (e) => {
Name
Accessibility
- -
Screen Reader
-

Value to describe the source listbox and target listbox can be provided with sourceListProps and targetListProps by passing aria-labelledby or aria-label props. The list elements has a listbox role with the aria-multiselectable attribute. - Each list item has an option role with aria-selected and aria-disabled as their attributes.

-

Controls buttons are button elements with an aria-label that refers to the aria.moveTop, aria.moveUp, aria.moveDown, aria.moveBottom, - aria.moveTo, aria.moveAllTo, aria.moveFrom and aria.moveAllFrom properties of the locale API by default, alternatively you may use - moveTopButtonProps, moveUpButtonProps, moveDownButtonProps, moveToButtonProps, moveAllToButtonProps, moveFromButtonProps, moveFromButtonProps and moveAllFromButtonProps to customize the buttons like overriding the default aria-label attributes.

- -{` + +
Screen Reader
+

+ Value to describe the source listbox and target listbox can be provided with sourceListProps and targetListProps by passing aria-labelledby or aria-label props. The list elements has a{' '} + listbox role with the aria-multiselectable attribute. Each list item has an option role with aria-selected and aria-disabled as their attributes. +

+

+ Controls buttons are button elements with an aria-label that refers to the aria.moveTop, aria.moveUp, aria.moveDown, aria.moveBottom,aria.moveTo, aria.moveAllTo,{' '} + aria.moveFrom and aria.moveAllFrom properties of the locale API by default, alternatively you may use + moveTopButtonProps, moveUpButtonProps, moveDownButtonProps, moveToButtonProps, moveAllToButtonProps, moveFromButtonProps, moveFromButtonProps and{' '} + moveAllFromButtonProps to customize the buttons like overriding the default aria-label attributes. +

+ + {` Options `} - -
ListBox Keyboard Support
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus to the first selected option, if there is none then first option receives the focus.
up arrowMoves focus to the previous option.
down arrowMoves focus to the next option.
enterToggles the selected state of the focused option.
spaceToggles the selected state of the focused option.
homeMoves focus to the first option.
endMoves focus to the last option.
shift + down arrowMoves focus to the next option and toggles the selection state.
shift + up arrowMoves focus to the previous option and toggles the selection state.
shift + spaceSelects the items between the most recently selected option and the focused option.
control + shift + homeSelects the focused options and all the options up to the first one.
control + shift + endSelects the focused options and all the options down to the first one.
control + aSelects all options.
-
- -
Buttons Keyboard Support
-
- - - - - - - - - - - - - - - - - -
KeyFunction
enterExecutes button action.
spaceExecutes button action.
-
-
- +
+
ListBox Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the first selected option, if there is none then first option receives the focus.
+ up arrow + Moves focus to the previous option.
+ down arrow + Moves focus to the next option.
+ enter + Toggles the selected state of the focused option.
+ space + Toggles the selected state of the focused option.
+ home + Moves focus to the first option.
+ end + Moves focus to the last option.
+ shift + down arrow + Moves focus to the next option and toggles the selection state.
+ shift + up arrow + Moves focus to the previous option and toggles the selection state.
+ shift + space + Selects the items between the most recently selected option and the focused option.
+ control + shift + home + Selects the focused options and all the options up to the first one.
+ control + shift + end + Selects the focused options and all the options down to the first one.
+ control + a + Selects all options.
+
+ +
Buttons Keyboard Support
+
+ + + + + + + + + + + + + + + + + +
KeyFunction
+ enter + Executes button action.
+ space + Executes button action.
+
+
Dependencies

None.

-
- { - useLiveEditorTabs({ name: 'PickListDemo', sources: sources, service: 'ProductService', data: 'products-small', extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'PickListDemo', sources: sources, service: 'ProductService', data: 'products-small', extFiles: extFiles })}
); -}) +}); export default PickListDoc; diff --git a/components/doc/progressbar/index.js b/components/doc/progressbar/index.js index fc87b0390c..50397bb3b2 100644 --- a/components/doc/progressbar/index.js +++ b/components/doc/progressbar/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const ProgressBarDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -82,7 +81,7 @@ export class ProgressBarDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState, useEffect, useRef } from 'react'; @@ -146,7 +145,7 @@ const ProgressBarDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState, useEffect, useRef } from 'react'; @@ -210,7 +209,7 @@ const ProgressBarDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -279,44 +278,46 @@ const ProgressBarDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { ProgressBar } from 'primereact/progressbar'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started

ProgressBar has two modes; "determinate" (default) and "indeterminate". In determinate mode, a value between 0 and 100 is required to display the progress.

- -{` + + {` `} - -

Indeterminate is simplly enabled using mode property.

- -{` + +

+ Indeterminate is simplly enabled using mode property. +

+ + {` `} - +
Properties

Any valid attribute is passed to the root element implicitly, extended properties are as follows;

-
- +
+
@@ -385,9 +386,11 @@ import { ProgressBar } from 'primereact/progressbar';
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -418,33 +421,33 @@ import { ProgressBar } from 'primereact/progressbar';
Name
-
Accessibility
- -
Screen Reader
-

ProgressBar components uses progressbar role along with aria-valuemin, aria-valuemax and aria-valuenow attributes. Value to describe the component can be defined using - aria-labelledby and aria-label props.

- -{` +
Accessibility
+ +
Screen Reader
+

+ ProgressBar components uses progressbar role along with aria-valuemin, aria-valuemax and aria-valuenow attributes. Value to describe the component can be defined using + aria-labelledby and aria-label props. +

+ + {` Status `} - +
-
Keyboard Support
-

Not applicable.

-
-
Dependencies
-

None.

-
+
Keyboard Support
+

Not applicable.

+ +
Dependencies
+

None.

+
- { - useLiveEditorTabs({ name: 'ProgressBarDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'ProgressBarDemo', sources: sources })}
); -}) +}); export default ProgressBarDoc; diff --git a/components/doc/progressspinner/index.js b/components/doc/progressspinner/index.js index 2648f9fa99..0d2da303a9 100644 --- a/components/doc/progressspinner/index.js +++ b/components/doc/progressspinner/index.js @@ -6,11 +6,10 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const ProgressSpinnerDoc = memo(() => { - - const sources = { - 'class': { - tabName: 'Class Source', - content: ` + const sources = { + class: { + tabName: 'Class Source', + content: ` import React, { Component } from 'react'; import { ProgressSpinner } from 'primereact/progressspinner'; @@ -32,7 +31,7 @@ export class ProgressSpinnerDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React from 'react'; @@ -53,7 +52,7 @@ const ProgressSpinnerDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React from 'react'; @@ -74,7 +73,7 @@ const ProgressSpinnerDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -98,39 +97,39 @@ const ProgressSpinnerDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { ProgressSpinner } from 'primereact/progressspinner'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started

ProgressSpinner is defined using ProgressSpinner element.

- -{` + + {` `} - +
Colors

Colors of the spinner can be changed by overriding the keyframes animation

- -{` + + {` @keyframes p-progress-spinner-color { 100%, 0% { @@ -148,11 +147,11 @@ import { ProgressSpinner } from 'primereact/progressspinner'; } } `} - +
Properties
-
- +
+
@@ -202,14 +201,16 @@ import { ProgressSpinner } from 'primereact/progressspinner';
Name
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
- +

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
- - - - + + + + @@ -229,29 +230,29 @@ import { ProgressSpinner } from 'primereact/progressspinner';
Accessibility
- -
Screen Reader
-

ProgressSpinner components uses progressbar role. Value to describe the component can be defined using aria-labelledby and aria-label props.

- -{` + +
Screen Reader
+

+ ProgressSpinner components uses progressbar role. Value to describe the component can be defined using aria-labelledby and aria-label props. +

+ + {` `} - +
-
Keyboard Support
-

Component does not include any interactive elements.

-
+
Keyboard Support
+

Component does not include any interactive elements.

+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'ProgressSpinnerDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'ProgressSpinnerDemo', sources: sources })} - ) -}) + ); +}); export default ProgressSpinnerDoc; diff --git a/components/doc/radiobutton/index.js b/components/doc/radiobutton/index.js index a241d861aa..ab6ff9e0ee 100644 --- a/components/doc/radiobutton/index.js +++ b/components/doc/radiobutton/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const RadioButtonDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -67,7 +66,7 @@ export class RadioButtonDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -116,7 +115,7 @@ const RadioButtonDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -165,7 +164,7 @@ const RadioButtonDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -217,40 +216,40 @@ const RadioButtonDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { RadioButton } from 'primereact/radiobutton'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started

RadioButton is used as a controlled input with checked and onChange properties.

- -{` + + {` setValue(e.value)} checked={value === 'val1'} /> setValue(e.value)} checked={value === 'val2'} /> `} - +
Properties

Any valid attribute is passed to the root element implicitly, extended properties are as follows;

-
-
NameElement
NameElement
+
+
@@ -331,8 +330,8 @@ import { RadioButton } from 'primereact/radiobutton';
Events
-
-
Name
+
+
@@ -343,9 +342,11 @@ import { RadioButton } from 'primereact/radiobutton'; - + event.checked: Checked state as a boolean. + @@ -353,9 +354,11 @@ import { RadioButton } from 'primereact/radiobutton';
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
onChangeevent.originalEvent: Original event
+
+ event.originalEvent: Original event
event.value: Value of the radiobutton
- event.checked: Checked state as a boolean.
Callback to invoke on radio button click.
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -384,11 +387,14 @@ import { RadioButton } from 'primereact/radiobutton';
Accessibility
- -
Screen Reader
-

RadioButton component uses a hidden native radio button element internally that is only visible to screen readers. Value to describe the component can either be provided via label tag combined with inputId prop or using aria-labelledby, aria-label props.

- -{` + +
Screen Reader
+

+ RadioButton component uses a hidden native radio button element internally that is only visible to screen readers. Value to describe the component can either be provided via label tag combined with inputId{' '} + prop or using aria-labelledby, aria-label props. +

+ + {` @@ -397,57 +403,59 @@ import { RadioButton } from 'primereact/radiobutton'; `} - -
Keyboard Support
-
-
Name
- - - - - - - - - - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus to the checked radio button, if there is none within the group then first radio button receives the focus.
- - left arrow - up arrow - - Moves focus to the previous radio button, if there is none then last radio button receives the focus.
- - right arrow - down arrow - - Moves focus to the next radio button, if there is none then first radio button receives the focus.
spaceIf the focused radio button is unchecked, changes the state to checked.
-
- + +
Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the checked radio button, if there is none within the group then first radio button receives the focus.
+ + left arrow + up arrow + + Moves focus to the previous radio button, if there is none then last radio button receives the focus.
+ + right arrow + down arrow + + Moves focus to the next radio button, if there is none then first radio button receives the focus.
+ space + If the focused radio button is unchecked, changes the state to checked.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'RadioButtonDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'RadioButtonDemo', sources: sources })}
- ) -}) + ); +}); export default RadioButtonDoc; diff --git a/components/doc/rating/index.js b/components/doc/rating/index.js index 75a224e2f1..a028046eed 100644 --- a/components/doc/rating/index.js +++ b/components/doc/rating/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const RatingDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -47,7 +46,7 @@ export class RatingDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -77,7 +76,7 @@ const RatingDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -107,7 +106,7 @@ const RatingDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -140,58 +139,64 @@ const RatingDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Rating } from 'primereact/rating'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

Rating is used a controlled input component with value and onChange properties.

+

+ Rating is used a controlled input component with value and onChange properties. +

- -{` + + {` setValue(e.value)} /> `} - +
Number of Stars
-

Number of stars to display is defined with stars property, default is 5.

+

+ Number of stars to display is defined with stars property, default is 5. +

- -{` + + {` setValue(e.value)} stars={5} /> `} - +
Cancel
-

A cancel icon is displayed to reset the value by default, set cancel as false to remove this option.

+

+ A cancel icon is displayed to reset the value by default, set cancel as false to remove this option. +

- -{` + + {` setValue(e.value)} cancel={5} /> `} - +
Properties

Any valid attribute is passed to the root element implicitly, extended properties are as follows;

-
- +
+
@@ -266,8 +271,8 @@ import { Rating } from 'primereact/rating';
Events
-
-
Name
+
+
@@ -278,7 +283,8 @@ import { Rating } from 'primereact/rating'; - @@ -289,8 +295,8 @@ import { Rating } from 'primereact/rating';
Styling

Following is the list of structural style classes

-
-
Name
onChangeevent.originalEvent: Browser event
+
+ event.originalEvent: Browser event
event.value: selected value
Callback to invoke on value change.
+
+
@@ -319,61 +325,66 @@ import { Rating } from 'primereact/rating';
Accessibility
- -
Screen Reader
-

Rating component internally uses radio buttons that are only visible to screen readers. The value to read for item is retrieved from the locale API via star and stars of the aria property.

- -
Keyboard Support
-

Keyboard interaction is derived from the native browser handling of radio buttons in a group.

-
-
Name
- - - - - - - - - - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus to the star representing the value, if there is none then first star receives the focus.
- - left arrow - up arrow - - Moves focus to the previous star, if there is none then last radio button receives the focus.
- - right arrow - down arrow - - Moves focus to the next star, if there is none then first star receives the focus.
spaceIf the focused star does not represent the value, changes the value to the star value.
-
- + +
Screen Reader
+

+ Rating component internally uses radio buttons that are only visible to screen readers. The value to read for item is retrieved from the locale API via star and stars of the{' '} + aria property. +

+ +
Keyboard Support
+

Keyboard interaction is derived from the native browser handling of radio buttons in a group.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the star representing the value, if there is none then first star receives the focus.
+ + left arrow + up arrow + + Moves focus to the previous star, if there is none then last radio button receives the focus.
+ + right arrow + down arrow + + Moves focus to the next star, if there is none then first star receives the focus.
+ space + If the focused star does not represent the value, changes the value to the star value.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'RatingDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'RatingDemo', sources: sources })}
- ) -}) + ); +}); export default RatingDoc; diff --git a/components/doc/ripple/index.js b/components/doc/ripple/index.js index adf186d957..95a7bc812f 100644 --- a/components/doc/ripple/index.js +++ b/components/doc/ripple/index.js @@ -5,9 +5,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const RippleDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -50,7 +49,7 @@ export class RippleDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React from 'react'; @@ -86,7 +85,7 @@ const RippleDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React from 'react'; @@ -122,7 +121,7 @@ const RippleDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -200,70 +199,77 @@ const RippleDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import PrimeReact from 'primereact/api'; import { Ripple } from 'primereact/ripple'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

Ripple effect is an optional animation for the supported components such as buttons. It is disabled by default and needs to be enabled at - your app's main container (e.g. App.js) using the PrimeReact class.

- -{` +

+ Ripple effect is an optional animation for the supported components such as buttons. It is disabled by default and needs to be enabled at your app's main container (e.g. App.js) using the PrimeReact class. +

+ + {` PrimeReact.ripple = true; `} - +
-

Note: That would be it to enable ripple on PrimeReact components, next section describes how to use it with your own components and standard elements.

+

+ Note: That would be it to enable ripple on PrimeReact components, next section describes how to use it with your own components and standard elements. +

Usage
-

Ripple is a component that needs to be imported and activated using PrimeReact.ripple = true

- -{` +

+ Ripple is a component that needs to be imported and activated using PrimeReact.ripple = true +

+ + {` import { Ripple } from 'primereact/ripple';
`} -
+
Styling
-

Default styling of the animation adds a shade of white. This can easily be customized using css that changes the color of .p-ink element.

- -{` +

+ Default styling of the animation adds a shade of white. This can easily be customized using css that changes the color of .p-ink element. +

+ + {`
`} -
+
- -{` + + {` .p-ripple.purple .p-ink { background: rgba(256,39,176,.3); } `} - +
Styling
-
- +
+
@@ -288,23 +294,23 @@ import { Ripple } from 'primereact/ripple'; -
Screen Reader
-

Ripple element has the aria-hidden attribute as true so that it gets ignored by the screen readers.

+
Screen Reader
+

+ Ripple element has the aria-hidden attribute as true so that it gets ignored by the screen readers. +

-
Keyboard Support
-

Component does not include any interactive elements.

-
+
Keyboard Support
+

Component does not include any interactive elements.

+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'RippleDemo', sources: sources, extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'RippleDemo', sources: sources, extFiles: extFiles })} ); -}) +}); export default RippleDoc; diff --git a/components/doc/scrollpanel/index.js b/components/doc/scrollpanel/index.js index afa305f7d9..bce2eb6240 100644 --- a/components/doc/scrollpanel/index.js +++ b/components/doc/scrollpanel/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const ScrollPanelDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -78,7 +77,7 @@ export class ScrollPanelDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React from 'react'; @@ -145,7 +144,7 @@ const ScrollPanelDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React from 'react'; @@ -211,8 +210,8 @@ const ScrollPanelDemo = () => { ) } ` - }, - 'browser': { + }, + browser: { tabName: 'Browser Source', imports: ` @@ -325,31 +324,31 @@ const ScrollPanelDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { ScrollPanel } from 'primereact/scrollpanel'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started

ScrollPanel is defined using dimensions for the scrollable viewport.

- -{` + + {` The story begins as Don Vito Corleone, the head of a New York Mafia family, oversees his daughter's wedding. His beloved son Michael has just come home from the war, but does not intend to become part of his father's business. @@ -357,12 +356,12 @@ import { ScrollPanel } from 'primereact/scrollpanel'; kind and benevolent to those who give respect, but given to ruthless violence whenever anything stands against the good of the family. `} - +
Customization

Look and feel can easily be customized, here is an example with a custom handle.

- -{` + + {` The story begins as Don Vito Corleone, the head of a New York Mafia family, oversees his daughter's wedding. His beloved son Michael has just come home from the war, but does not intend to become part of his father's business. @@ -370,10 +369,10 @@ import { ScrollPanel } from 'primereact/scrollpanel'; kind and benevolent to those who give respect, but given to ruthless violence whenever anything stands against the good of the family. `} - + - -{` + + {` .custom .p-scrollpanel-wrapper { border-right: 9px solid #f4f4f4; } @@ -388,11 +387,11 @@ import { ScrollPanel } from 'primereact/scrollpanel'; background-color: #135ba1; } `} - +
Properties
-
-
Name
+
+
@@ -425,8 +424,8 @@ import { ScrollPanel } from 'primereact/scrollpanel';
Methods
-
-
Name
+
+
@@ -445,9 +444,11 @@ import { ScrollPanel } from 'primereact/scrollpanel';
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -483,52 +484,60 @@ import { ScrollPanel } from 'primereact/scrollpanel';
Name
Accessibility
- -
Screen Reader
-

Scrollbars of the ScrollPanel has a scrollbar role along with the aria-controls attribute that refers to the id of the scrollable content container and the aria-orientation to indicate the orientation of scrolling.

+ +
Screen Reader
+

+ Scrollbars of the ScrollPanel has a scrollbar role along with the aria-controls attribute that refers to the id of the scrollable content container and the aria-orientation to indicate the + orientation of scrolling. +

-
Header Keyboard Support
-
- - - - - - - - - - - - - - - - - - - - - - - - - -
KeyFunction
down arrowScrolls content down when vertical scrolling is available.
up arrowScrolls content up when vertical scrolling is available.
leftScrolls content left when horizontal scrolling is available.
rightScrolls content right when horizontal scrolling is available.
-
-
+
Header Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ down arrow + Scrolls content down when vertical scrolling is available.
+ up arrow + Scrolls content up when vertical scrolling is available.
+ left + Scrolls content left when horizontal scrolling is available.
+ right + Scrolls content right when horizontal scrolling is available.
+
+
Dependencies

None.

-
- { - useLiveEditorTabs({ name: 'ScrollPanelDemo', sources: sources, extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'ScrollPanelDemo', sources: sources, extFiles: extFiles })}
); -}) +}); -export default ScrollPanelDoc +export default ScrollPanelDoc; diff --git a/components/doc/scrolltop/index.js b/components/doc/scrolltop/index.js index 499c1ff132..9e9fdfea87 100644 --- a/components/doc/scrolltop/index.js +++ b/components/doc/scrolltop/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const ScrollTopDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -50,7 +49,7 @@ export class ScrollTopDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React from 'react'; @@ -90,7 +89,7 @@ export const ScrollTopDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React from 'react'; @@ -130,7 +129,7 @@ export const ScrollTopDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -196,57 +195,60 @@ const ScrollTopDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { ScrollTop } from 'primereact/scrolltop'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started

Without any configuration, ScrollTop listens window scroll.

- -{` + + {` `} - +
Threshold
-

When the vertical scroll position reaches a certain value, ScrollTop gets displayed. This value is - defined with the threshold property that defaults to 400.

- -{` +

+ When the vertical scroll position reaches a certain value, ScrollTop gets displayed. This value is defined with the threshold property that defaults to 400. +

+ + {` `} - +
Target Element
-

ScrollTop can also be assigned to its parent element by setting target as "parent".

- -{` +

+ ScrollTop can also be assigned to its parent element by setting target as "parent". +

+ + {`
Content that overflows to container
`} -
+
Properties

Any valid attribute is passed to the root element implicitly, extended properties are as follows;

-
- +
+
@@ -284,21 +286,27 @@ import { ScrollTop } from 'primereact/scrolltop'; - +
NametransitionOptions object nullThe properties of CSSTransition can be customized, except for "nodeRef" and "in" properties. + The properties of{' '} + + CSSTransition + {' '} + can be customized, except for "nodeRef" and "in" properties. +
Events
-
- +
+
- - - - - + + + + + @@ -316,9 +324,11 @@ import { ScrollTop } from 'primereact/scrolltop';
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
NameParametersDescription
NameParametersDescription
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -339,44 +349,48 @@ import { ScrollTop } from 'primereact/scrolltop';
Accessibility
- -
Screen Reader
-

ScrollTop uses a button element with an aria-label that refers to the aria.scrollTop property of the locale API by default, you may use - your own aria roles and attributes as any valid attribute is passed to the button element implicitly.

+ +
Screen Reader
+

+ ScrollTop uses a button element with an aria-label that refers to the aria.scrollTop property of the locale API by default, you may use your own aria roles and attributes as any + valid attribute is passed to the button element implicitly. +

-
Keyboard Support
-
-
Name
- - - - - - - - - - - - - - - - -
KeyFunction
enterScrolls to top.
spaceScrolls to top.
-
- +
Keyboard Support
+
+ + + + + + + + + + + + + + + + + +
KeyFunction
+ enter + Scrolls to top.
+ space + Scrolls to top.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'ScrollTopDemo', sources: sources, extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'ScrollTopDemo', sources: sources, extFiles: extFiles })}
); -}) +}); export default ScrollTopDoc; diff --git a/components/doc/selectbutton/index.js b/components/doc/selectbutton/index.js index 883881f7e2..b9d1b7311d 100644 --- a/components/doc/selectbutton/index.js +++ b/components/doc/selectbutton/index.js @@ -5,9 +5,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const SelectButtonDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -62,7 +61,7 @@ export class SelectButtonDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -106,7 +105,7 @@ const SelectButtonDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -150,7 +149,7 @@ const SelectButtonDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -197,36 +196,39 @@ const SelectButtonDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { SelectButton } from 'primereact/selectbutton'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

Dropdown is used as a controlled component with value and onChange properties along with the options collection. There are two alternatives - of how to define the options property; One way is providing a collection of SelectItem instances having label-value pairs - whereas other way is providing an array of arbitrary objects along with the optionLabel and optionValue properties to specify the label/value field pair. In addition, - options can be simple primitive values such as a string array, in this case no optionLabel or optionValue is necessary.

- -

Options as SelectItems

- -{` +

+ Dropdown is used as a controlled component with value and onChange properties along with the options collection. There are two alternatives of how to define the options property; One way is providing a collection + of SelectItem instances having label-value pairs whereas other way is providing an array of arbitrary objects along with the optionLabel and optionValue properties to specify the label/value field pair. In + addition, options can be simple primitive values such as a string array, in this case no optionLabel or optionValue is necessary. +

+ +

+ Options as SelectItems +

+ + {` const citySelectItems = [ {label: 'New York', value: 'NY'}, {label: 'Rome', value: 'RM'}, @@ -235,17 +237,19 @@ const citySelectItems = [ {label: 'Paris', value: 'PRS'} ]; `} - +
- -{` + + {` setValue(e.value)}> `} - + -

Options as any type

- -{` +

+ Options as any type +

+ + {` const cities = [ {name: 'New York', code: 'NY'}, {name: 'Rome', code: 'RM'}, @@ -254,40 +258,46 @@ const cities = [ {name: 'Paris', code: 'PRS'} ]; `} - +
- -{` + + {` setValue(e.value)}> setValue(e.value)}> `} - -

When optionValue is not defined, value of an option refers to the option object itself.

+
+

+ When optionValue is not defined, value of an option refers to the option object itself. +

Multiple
-

SelectButton allows selecting only one item by default and setting multiple option enables choosing more than one item. In multiple case, model property should be an array.

+

+ SelectButton allows selecting only one item by default and setting multiple option enables choosing more than one item. In multiple case, model property should be an array. +

Custom Content
-

Options support templating using the itemTemplate property that references a function to render the content. Notice - the usage of optionLabel, although it is not rendered visually, it is still required to be used as the list key.

+

+ Options support templating using the itemTemplate property that references a function to render the content. Notice the usage of optionLabel, although it is not rendered visually, it is still required to be used as the + list key. +

- -{` + + {` setValue(e.value)} itemTemplate={itemTemplate} /> `} - + - -{` + + {` const itemTemplate = (option) => { // custom item content } `} - +
SelectItem API
-
- +
+
@@ -333,8 +343,8 @@ const itemTemplate = (option) => {
Properties

Any valid attribute is passed to the root element implicitly, extended properties are as follows;

-
-
Name
+
+
@@ -445,8 +455,8 @@ const itemTemplate = (option) => {
Events
-
-
Name
+
+
@@ -457,8 +467,10 @@ const itemTemplate = (option) => { - + @@ -466,44 +478,47 @@ const itemTemplate = (option) => {
Accessibility
- -
Screen Reader
-

The container element that wraps the buttons has a group role whereas each button element uses button role and aria-pressed is updated depending on selection state. - Value to describe an option is automatically set using the aria-label property that refers to the label of an option so it is still suggested to define a label even the option display - consists of presentational content like icons only.

- -
Keyboard Support
-
-
Name
onChangeevent.originalEvent: browser event
- event.value: Single value or an array of values that are selected.
+ event.originalEvent: browser event
+ event.value: Single value or an array of values that are selected. +
Callback to invoke on value change.
- - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus to the buttons.
spaceToggles the checked state of a button.
-
- + +
Screen Reader
+

+ The container element that wraps the buttons has a group role whereas each button element uses button role and aria-pressed is updated depending on selection state. Value to describe an option is + automatically set using the aria-label property that refers to the label of an option so it is still suggested to define a label even the option display consists of presentational content like icons only. +

+ +
Keyboard Support
+
+ + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the buttons.
+ space + Toggles the checked state of a button.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'SelectButtonDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'SelectButtonDemo', sources: sources })}
); -}) +}); export default SelectButtonDoc; diff --git a/components/doc/sidebar/index.js b/components/doc/sidebar/index.js index 07a2acb6db..fce63f825f 100644 --- a/components/doc/sidebar/index.js +++ b/components/doc/sidebar/index.js @@ -5,9 +5,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const SidebarDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -80,7 +79,7 @@ export class SidebarDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -145,7 +144,7 @@ const SidebarDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -210,7 +209,7 @@ const SidebarDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -278,77 +277,83 @@ const SidebarDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Sidebar } from 'primereact/sidebar'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

Sidebar is used as a container and visibility is controlled with visible property.

+

+ Sidebar is used as a container and visibility is controlled with visible property. +

- -{` + + {` setVisible(false)}> Content
- ) -}) + ); +}); export default SidebarDoc; diff --git a/components/doc/skeleton/index.js b/components/doc/skeleton/index.js index 90afcf13da..57031d7c40 100644 --- a/components/doc/skeleton/index.js +++ b/components/doc/skeleton/index.js @@ -5,10 +5,9 @@ import { useLiveEditorTabs } from '../common/liveeditor'; import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; -const SkeletonDoc = memo( () => { - +const SkeletonDoc = memo(() => { const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from "react"; @@ -149,7 +148,7 @@ export class SkeletonDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React from 'react'; @@ -287,7 +286,7 @@ export const SkeletonDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React from "react"; @@ -425,7 +424,7 @@ export const SkeletonDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -583,67 +582,75 @@ const SkeletonDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Skeleton } from 'primereact/skeleton'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started

Skeleton displays a rectangle in its simplest form.

- -{` + + {` `} - +
Circle
-

The other option is the circle by setting shape property as "circle".

- -{` +

+ The other option is the circle by setting shape property as "circle". +

+ + {` `} - +
Size
-

In order to customize the size, use width and height properties for rectangles and size for Circle and Square shapes.

- -{` +

+ In order to customize the size, use width and height properties for rectangles and size for Circle and Square shapes. +

+ + {` `} - +
Border Radius
-

The default border radius of a rectangle is specified by the theme and can be overriden using the borderRadius property.

- -{` +

+ The default border radius of a rectangle is specified by the theme and can be overriden using the borderRadius property. +

+ + {` `} - +
Animation
-

Animation can be turned of by setting animation to "none".

- -{` +

+ Animation can be turned of by setting animation to "none". +

+ + {` `} - +
Properties

Any valid attribute is passed to the root element implicitly, extended properties are as follows;

-
- +
+
@@ -694,9 +701,11 @@ import { Skeleton } from 'primereact/skeleton';
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -722,23 +731,23 @@ import { Skeleton } from 'primereact/skeleton';
Accessibility
-
Screen Reader
-

Skeleton uses aria-hidden as "true" so that it gets ignored by screen readers, any valid attribute is passed to the root element so you may customize it further if required. If multiple skeletons are grouped inside a container, - you may use aria-busy on the container element as well to indicate the loading process.

- -
Keyboard Support
-

Component does not include any interactive elements.

+
Screen Reader
+

+ Skeleton uses aria-hidden as "true" so that it gets ignored by screen readers, any valid attribute is passed to the root element so you may customize it further if required. If multiple skeletons are grouped inside + a container, you may use aria-busy on the container element as well to indicate the loading process. +

+ +
Keyboard Support
+

Component does not include any interactive elements.

Dependencies

None.

- { - useLiveEditorTabs({ name: 'SkeletonDemo', sources: sources, extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'SkeletonDemo', sources: sources, extFiles: extFiles })} ); -}) +}); export default SkeletonDoc; diff --git a/components/doc/slidemenu/index.js b/components/doc/slidemenu/index.js index c6569e2660..744852bf04 100644 --- a/components/doc/slidemenu/index.js +++ b/components/doc/slidemenu/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const SlideMenuDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -169,7 +168,7 @@ export class SlideMenuDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useRef } from 'react'; @@ -324,7 +323,7 @@ const SlideMenuDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useRef } from 'react'; @@ -479,7 +478,7 @@ const SlideMenuDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -637,35 +636,37 @@ const SlideMenuDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { SlideMenu } from 'primereact/slidemenu'; `} - +
Import via CDN
- -{` + + {` `} - +
MenuItem API
-

Menu uses the common menumodel api to define its items, visit MenuModel API for details.

+

+ Menu uses the common menumodel api to define its items, visit MenuModel API for details. +

Getting Started

Menu requires a collection of menuitems as its model.

- -{` + + {` const items = [ { label:'File', @@ -798,38 +799,38 @@ const items = [ } ]; `} - + - -{` + + {` `} - - +
Popup Mode

SlideMenu is inline by default whereas popup mode is supported by enabling popup property and calling toggle method with an event of the target.

- -{` + + {` `} - +
Effects
-

The easing function to use is "ease-out" by default which can be customized using easing property. - See here for possible alternative values.

+

+ The easing function to use is "ease-out" by default which can be customized using easing property. See here for possible alternative values. +

- -{` + + {` `} - +
Properties
-
-
Name
+
+
@@ -915,21 +916,29 @@ const items = [ - + - +
NameappendTo DOM element | string document.bodyDOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. + DOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. +
transitionOptions object nullThe properties of CSSTransition can be customized, except for "nodeRef" and "in" properties. + The properties of{' '} + + CSSTransition + {' '} + can be customized, except for "nodeRef" and "in" properties. +
Methods
-
- +
+
@@ -958,8 +967,8 @@ const items = [
Events
-
-
Name
+
+
@@ -984,13 +993,13 @@ const items = [
Styling

Following is the list of structural style classes.

-
-
Name
+
+
- - - - + + + + @@ -1035,82 +1044,107 @@ const items = [
Accessibility
-
Screen Reader
-

SlideMenu component uses the menubar role with aria-orientation set to "vertical" and the value to describe the menu can either be provided with aria-labelledby or aria-label props. Each list item has a presentation role - whereas anchor elements have a menuitem role with aria-label referring to the label of the item and aria-disabled defined if the item is disabled. A submenu within a SlideMenu uses the menu role with an aria-labelledby defined - as the id of the submenu root menuitem label. In addition, menuitems that open a submenu have aria-expanded and aria-controls to define the relation between the item and the submenu.

+
Screen Reader
+

+ SlideMenu component uses the menubar role with aria-orientation set to "vertical" and the value to describe the menu can either be provided with aria-labelledby or aria-label props. Each list + item has a presentation role whereas anchor elements have a menuitem role with aria-label referring to the label of the item and aria-disabled defined if the item is disabled. A submenu within a + SlideMenu uses the menu role with an aria-labelledby defined as the id of the submenu root menuitem label. In addition, menuitems that open a submenu have aria-expanded and aria-controls to + define the relation between the item and the submenu. +

-

In popup mode, the component implicitly manages the aria-expanded, aria-haspopup and aria-controls attributes of the target element to define the relation between the target and the popup.

+

+ In popup mode, the component implicitly manages the aria-expanded, aria-haspopup and aria-controls attributes of the target element to define the relation between the target and the popup. +

-
Keyboard Support
-
-
NameElement
NameElement
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyFunction
tabAdd focus to the first item if focus moves in to the menu. If the focus is already within the menu, focus moves to the next focusable item in the page tab sequence.
shift + tabAdd focus to the last item if focus moves in to the menu. If the focus is already within the menu, focus moves to the previous focusable item in the page tab sequence.
enterIf menuitem has a submenu, toggles the visibility of the submenu otherwise activates the menuitem and closes all open overlays.
spaceIf menuitem has a submenu, toggles the visibility of the submenu otherwise activates the menuitem and closes all open overlays.
escapeIf focus is inside a popup submenu, closes the submenu and moves focus to the root item of the closed submenu.
down arrowMoves focus to the next menuitem within the submenu.
up arrowMoves focus to the previous menuitem within the submenu.
right arrowOpens a submenu if there is one available and moves focus to the first item.
left arrowCloses a submenu and moves focus to the root item of the closed submenu.
homeMoves focus to the first menuitem within the submenu.
endMoves focus to the last menuitem within the submenu.
-
- +
Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Add focus to the first item if focus moves in to the menu. If the focus is already within the menu, focus moves to the next focusable item in the page tab sequence.
+ shift + tab + Add focus to the last item if focus moves in to the menu. If the focus is already within the menu, focus moves to the previous focusable item in the page tab sequence.
+ enter + If menuitem has a submenu, toggles the visibility of the submenu otherwise activates the menuitem and closes all open overlays.
+ space + If menuitem has a submenu, toggles the visibility of the submenu otherwise activates the menuitem and closes all open overlays.
+ escape + If focus is inside a popup submenu, closes the submenu and moves focus to the root item of the closed submenu.
+ down arrow + Moves focus to the next menuitem within the submenu.
+ up arrow + Moves focus to the previous menuitem within the submenu.
+ right arrow + Opens a submenu if there is one available and moves focus to the first item.
+ left arrow + Closes a submenu and moves focus to the root item of the closed submenu.
+ home + Moves focus to the first menuitem within the submenu.
+ end + Moves focus to the last menuitem within the submenu.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'SlideMenuDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'SlideMenuDemo', sources: sources })}
- ) -}) + ); +}); export default SlideMenuDoc; diff --git a/components/doc/slider/index.js b/components/doc/slider/index.js index 55472f68ea..2c9ac270e2 100644 --- a/components/doc/slider/index.js +++ b/components/doc/slider/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const SliderDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -60,7 +59,7 @@ export class SliderDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -103,7 +102,7 @@ const SliderDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -146,7 +145,7 @@ const SliderDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -207,56 +206,62 @@ const SliderDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { Slider } from 'primereact/slider'; `} - + - < h5>Import via CDN - -{` +
Import via CDN
+ + {` `} - +
Getting Started
-

Slider is used as a controlled input with value and onChange properties.

+

+ Slider is used as a controlled input with value and onChange properties. +

- -{` + + {` setValue(e.value)} /> `} - +
Range
-

Range slider provides two handles to define two values. Enable range property and bind an array to implement a range slider.

- -{` +

+ Range slider provides two handles to define two values. Enable range property and bind an array to implement a range slider. +

+ + {` setRangeValues(e.value)} range /> `} - +
Orientation
-

Default layout of slider is horizontal, use orientation property for the alternative vertical mode.

- -{` +

+ Default layout of slider is horizontal, use orientation property for the alternative vertical mode. +

+ + {` setValue(e.value)} orientation="vertical" /> `} - +
Properties

Any valid attribute is passed to the root element implicitly, extended properties are as follows;

-
- +
+
@@ -343,8 +348,8 @@ import { Slider } from 'primereact/slider';
Events
-
-
Name
+
+
@@ -355,14 +360,16 @@ import { Slider } from 'primereact/slider'; - - @@ -372,9 +379,11 @@ import { Slider } from 'primereact/slider';
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
onChangeevent.originalEvent: Slide event
+
+ event.originalEvent: Slide event
event.value: New value.
Callback to invoke on value change via slide.
onSlideEndevent.originalEvent: Slide event
+
+ event.originalEvent: Slide event
event.value: New value.
Callback to invoke when slide ends.
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -395,80 +404,91 @@ import { Slider } from 'primereact/slider';
Accessibility
- -
Screen Reader
-

Slider element component uses slider role on the handle in addition to the aria-orientation, aria-valuemin, aria-valuemax and aria-valuenow attributes. Value to describe the component can be defined using - aria-labelledby and aria-label props.

- -{` + +
Screen Reader
+

+ Slider element component uses slider role on the handle in addition to the aria-orientation, aria-valuemin, aria-valuemax and aria-valuenow attributes. Value to describe the component can + be defined using + aria-labelledby and aria-label props. +

+ + {` Number `} - -
Keyboard Support
-
-
Name
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyFunction
tabMoves focus to the slider.
- - left arrow - up arrow - - Decrements the value.
- - right arrow - down arrow - - Increments the value.
homeSet the minimum value.
endSet the maximum value.
page upIncrements the value by 10 steps.
page downDecrements the value by 10 steps.
-
- + +
Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ tab + Moves focus to the slider.
+ + left arrow + up arrow + + Decrements the value.
+ + right arrow + down arrow + + Increments the value.
+ home + Set the minimum value.
+ end + Set the maximum value.
+ page up + Increments the value by 10 steps.
+ page down + Decrements the value by 10 steps.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'SliderDemo', sources: sources, extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'SliderDemo', sources: sources, extFiles: extFiles })}
); -}) +}); export default SliderDoc; diff --git a/components/doc/speeddial/index.js b/components/doc/speeddial/index.js index 3c58e4cd1a..f034fd57e9 100644 --- a/components/doc/speeddial/index.js +++ b/components/doc/speeddial/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const SpeedDialDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -121,7 +120,7 @@ export class SpeedDialDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React from 'react'; @@ -230,7 +229,7 @@ export const SpeedDialDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React from 'react'; @@ -339,7 +338,7 @@ export const SpeedDialDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -453,7 +452,7 @@ const SpeedDialDemo = () => { } ` } - } + }; const extFiles = { 'demo/SpeedDialDemo.css': { @@ -528,33 +527,35 @@ const SpeedDialDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { SpeedDial } from 'primereact/speeddial'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

When pressed, a floating action button can display multiple primary actions that can be performed on a page. It has a collection of additional options defined by the model property. - SpeedDial's position is calculated according to the container element with the position type style.

+

+ When pressed, a floating action button can display multiple primary actions that can be performed on a page. It has a collection of additional options defined by the model property. SpeedDial's position is calculated + according to the container element with the position type style. +

- -{` + + {` export const SpeedDialDemo = () => { const items = [ @@ -586,21 +587,28 @@ export const SpeedDialDemo = () => { ); } `} - +
MenuModel API
-

SpeedDial uses the common MenuModel API to define the items, visit MenuModel API for details.

+

+ SpeedDial uses the common MenuModel API to define the items, visit MenuModel API for details. +

Type
-

SpeedDial has 4 types; linear, circle, semi-circle and quarter-circle.

+

+ SpeedDial has 4 types; linear, circle, semi-circle and quarter-circle. +

Direction
-

Specifies the opening direction of actions. For the linear and semi-circle types; up, down, left and right. For the quarter-circle type; up-left, up-right, down-left and down-right.

+

+ Specifies the opening direction of actions. For the linear and semi-circle types; up, down, left and right. For the quarter-circle type;{' '} + up-left, up-right, down-left and down-right. +

Properties

Any valid attribute is passed to the root element implicitly, extended properties are as follows;

-
- +
+
@@ -735,8 +743,8 @@ export const SpeedDialDemo = () => {
Events
-
-
Name
+
+
@@ -770,9 +778,11 @@ export const SpeedDialDemo = () => {
Styling
-

Following is the list of structural style classes, for theming classes visit theming page.

-
-
Name
+

+ Following is the list of structural style classes, for theming classes visit theming page. +

+
+
@@ -805,95 +815,113 @@ export const SpeedDialDemo = () => {
Accessibility
- -
Screen Reader
-

SpeedDial component renders a native button element that implicitly includes any passed prop. Text to describe the button can be defined with the aria-labelledby or aria-label props. - Addititonally the button includes includes aria-haspopup, aria-expanded for states along with aria-controls to define the relation between the popup and the button.

- -

The popup overlay uses menu role on the list and each action item has a menuitem role with an aria-label as the menuitem label. The id of the menu refers to the aria-controls of the button.

- - -{` + +
Screen Reader
+

+ SpeedDial component renders a native button element that implicitly includes any passed prop. Text to describe the button can be defined with the aria-labelledby or aria-label props. Addititonally the button + includes includes aria-haspopup, aria-expanded for states along with aria-controls to define the relation between the popup and the button. +

+ +

+ The popup overlay uses menu role on the list and each action item has a menuitem role with an aria-label as the menuitem label. The id of the menu refers to the aria-controls of the button. +

+ + + {` `} - - - -
Menu Button Keyboard Support
-
-
Name
- - - - - - - - - - - - - - - - - - - - - - - - -
KeyFunction
enterToggles the visibility of the menu.
spaceToggles the visibility of the menu.
down arrowOpens the menu and moves focus to the first item.
up arrowOpens the menu and moves focus to the last item.
-
- -
Menu Keyboard Support
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyFunction
enterActives the menuitem, closes the menu and sets focus on the menu button.
escapeCloses the menu and sets focus on the menu button.
arrow keysNavigates between the menu items.
homeMoves focus to the first item.
endMoves focus to the last item.
-
- + + +
Menu Button Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ enter + Toggles the visibility of the menu.
+ space + Toggles the visibility of the menu.
+ down arrow + Opens the menu and moves focus to the first item.
+ up arrow + Opens the menu and moves focus to the last item.
+
+ +
Menu Keyboard Support
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
+ enter + Actives the menuitem, closes the menu and sets focus on the menu button.
+ escape + Closes the menu and sets focus on the menu button.
+ arrow keys + Navigates between the menu items.
+ home + Moves focus to the first item.
+ end + Moves focus to the last item.
+
+
Dependencies

None.

- { - useLiveEditorTabs({ name: 'SpeedDialDemo', sources: sources, extFiles: extFiles }) - } - + {useLiveEditorTabs({ name: 'SpeedDialDemo', sources: sources, extFiles: extFiles })}
- ) -}) + ); +}); export default SpeedDialDoc; diff --git a/components/doc/splitbutton/index.js b/components/doc/splitbutton/index.js index 93e58bbb51..2f069c1fb1 100644 --- a/components/doc/splitbutton/index.js +++ b/components/doc/splitbutton/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const SplitButtonDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -133,7 +132,7 @@ export class SplitButtonDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useRef } from 'react'; @@ -250,7 +249,7 @@ const SplitButtonDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useRef } from 'react'; @@ -367,7 +366,7 @@ const SplitButtonDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -488,31 +487,33 @@ const SplitButtonDemo = () => { } ` } - } + }; return ( -
+
- +
Import via Module
- -{` + + {` import { SplitButton } from 'primereact/splitbutton'; `} - +
Import via CDN
- -{` + + {` `} - +
Getting Started
-

SplitButton has a default command button and a collection of additional options defined by the model property.

- -{` +

+ SplitButton has a default command button and a collection of additional options defined by the model property. +

+ + {` export const SplitButtonDemo = () => { const items = [ @@ -556,10 +557,12 @@ export const SplitButtonDemo = () => { } `} - +
MenuModel API
-

SplitButton uses the common MenuModel API to define the items, visit MenuModel API for details.

+

+ SplitButton uses the common MenuModel API to define the items, visit MenuModel API for details. +

Severity

Different color options are available as severity levels.

@@ -572,8 +575,8 @@ export const SplitButtonDemo = () => {
  • .p-button-danger
  • - -{` + + {` @@ -582,19 +585,19 @@ export const SplitButtonDemo = () => { `} - +
    Raised and Rounded Buttons

    SplitButton can be raised by having "p-button-raised" style class and similarly borders can be made rounded using "p-button-rounded" class.

    - -{` + + {` `} - +
    Properties
    -
    - +
    +
    @@ -692,7 +695,9 @@ export const SplitButtonDemo = () => { - + @@ -716,7 +721,13 @@ export const SplitButtonDemo = () => { - + @@ -741,8 +752,8 @@ export const SplitButtonDemo = () => {
    Events
    -
    -
    NameappendTo DOM element | string document.bodyDOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. + DOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. +
    tooltiptransitionOptions object nullThe properties of CSSTransition can be customized, except for "nodeRef" and "in" properties. + The properties of{' '} + + CSSTransition + {' '} + can be customized, except for "nodeRef" and "in" properties. +
    dropdownIcon
    +
    +
    @@ -771,9 +782,11 @@ export const SplitButtonDemo = () => {
    Styling
    -

    Following is the list of structural style classes, for theming classes visit theming page.

    -
    -
    Name
    +

    + Following is the list of structural style classes, for theming classes visit theming page. +

    +
    +
    @@ -798,117 +811,144 @@ export const SplitButtonDemo = () => {
    Accessibility
    - -
    Screen Reader
    -

    SplitButton component renders two native button elements, main button uses the label property to define aria-label by default which can be customized with buttonProps. - Dropdown button requires an explicit definition to describe it using menuButtonProps option and also includes aria-haspopup, aria-expanded for states along with aria-controls to define the relation between the popup and the button.

    - -

    The popup overlay uses menu role on the list and each action item has a menuitem role with an aria-label as the menuitem label. The id of the menu refers to the aria-controls of the dropdown button.

    - -{` + +
    Screen Reader
    +

    + SplitButton component renders two native button elements, main button uses the label property to define aria-label by default which can be customized with buttonProps. Dropdown button requires an explicit + definition to describe it using menuButtonProps option and also includes aria-haspopup, aria-expanded for states along with aria-controls to define the relation between the popup and the button. +

    + +

    + The popup overlay uses menu role on the list and each action item has a menuitem role with an aria-label as the menuitem label. The id of the menu refers to the aria-controls of the dropdown + button. +

    + + {` `} - -
    Main Button Keyboard Support
    -
    -
    Name
    - - - - - - - - - - - - - - - - -
    KeyFunction
    enterActivates the button.
    spaceActivates the button.
    -
    - -
    Menu Button Keyboard Support
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - -
    KeyFunction
    enterToggles the visibility of the menu.
    spaceToggles the visibility of the menu.
    down arrowOpens the menu and moves focus to the first item.
    up arrowOpens the menu and moves focus to the last item.
    -
    - -
    Menu Keyboard Support
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    KeyFunction
    enterActives the menuitem, closes the menu and sets focus on the menu button.
    escapeCloses the menu and sets focus on the menu button.
    down arrowMoves focus to the next item, if it is the last one then first item receives the focus.
    up arrowMoves focus to the previous item, if it is the first one then last item receives the focus.
    homeMoves focus to the first item.
    endMoves focus to the last item.
    -
    - + +
    Main Button Keyboard Support
    +
    + + + + + + + + + + + + + + + + + +
    KeyFunction
    + enter + Activates the button.
    + space + Activates the button.
    +
    + +
    Menu Button Keyboard Support
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    KeyFunction
    + enter + Toggles the visibility of the menu.
    + space + Toggles the visibility of the menu.
    + down arrow + Opens the menu and moves focus to the first item.
    + up arrow + Opens the menu and moves focus to the last item.
    +
    + +
    Menu Keyboard Support
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    KeyFunction
    + enter + Actives the menuitem, closes the menu and sets focus on the menu button.
    + escape + Closes the menu and sets focus on the menu button.
    + down arrow + Moves focus to the next item, if it is the last one then first item receives the focus.
    + up arrow + Moves focus to the previous item, if it is the first one then last item receives the focus.
    + home + Moves focus to the first item.
    + end + Moves focus to the last item.
    +
    +
    Dependencies

    None.

    - { - useLiveEditorTabs({ name: 'SplitButtonDemo', sources: sources }) - } -
    + {useLiveEditorTabs({ name: 'SplitButtonDemo', sources: sources })} +
    - ) -}) + ); +}); export default SplitButtonDoc; diff --git a/components/doc/splitter/index.js b/components/doc/splitter/index.js index 36fff97ed2..80010939d1 100644 --- a/components/doc/splitter/index.js +++ b/components/doc/splitter/index.js @@ -5,9 +5,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const SplitterDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -73,7 +72,7 @@ export class SplitterDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React from 'react'; @@ -136,7 +135,7 @@ const SplitterDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React from 'react'; @@ -199,7 +198,7 @@ const SplitterDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -265,32 +264,32 @@ const SplitterDemo = () => { } ` } - } + }; return ( -
    +
    - +
    Import via Module
    - -{` + + {` import { Splitter, SplitterPanel } from 'primereact/splitter'; `} - +
    Import via CDN
    - -{` + + {` `} - +
    Getting Started

    Splitter requires two SplitterPanel components to wrap.

    - -{` + + {` Panel 1 @@ -300,13 +299,15 @@ import { Splitter, SplitterPanel } from 'primereact/splitter'; `} - +
    Layout
    -

    Default orientation is configured with the layout property and default is the "horizontal" whereas other alternative is the "vertical".

    +

    + Default orientation is configured with the layout property and default is the "horizontal" whereas other alternative is the "vertical". +

    - -{` + + {` Panel 1 @@ -316,13 +317,15 @@ import { Splitter, SplitterPanel } from 'primereact/splitter'; `} - +
    Initial Sizes
    -

    When no size is defined, panels are split 50/50, use the size property to give relative widths e.g. 20/80.

    +

    + When no size is defined, panels are split 50/50, use the size property to give relative widths e.g. 20/80. +

    - -{` + + {` Panel 1 @@ -332,13 +335,13 @@ import { Splitter, SplitterPanel } from 'primereact/splitter'; `} - +
    Minimum Size

    Minimum size defines the lowest boundary for the size of a panel.

    - -{` + + {` Panel 1 @@ -348,13 +351,13 @@ import { Splitter, SplitterPanel } from 'primereact/splitter'; `} - +
    Nested Panels

    Splitters can be combined to create advanced layouts.

    - -{` + + {` Panel 1 @@ -378,15 +381,16 @@ import { Splitter, SplitterPanel } from 'primereact/splitter'; `} - +
    Stateful
    -

    Splitters can be configured as stateful so that when the user visits the page again, the adjusts sizes - can be restored. Define a stateKey to enable this feature. Default location of the state is - session storage and other option is the local storage which can be configured using the stateStorage property.

    +

    + Splitters can be configured as stateful so that when the user visits the page again, the adjusts sizes can be restored. Define a stateKey to enable this feature. Default location of the state is session storage and + other option is the local storage which can be configured using the stateStorage property. +

    - -{` + + {` Panel 1 @@ -396,226 +400,233 @@ import { Splitter, SplitterPanel } from 'primereact/splitter'; `} - +
    Properties of SplitterPanel
    -

    Any property as style and class are passed to the main container element. Following are the - additional properties to configure the component.

    -
    - +

    Any property as style and class are passed to the main container element. Following are the additional properties to configure the component.

    +
    +
    - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDefaultDescription
    NameTypeDefaultDescription
    sizenumbernullSize of the element relative to 100%.
    minSizenumbernullMinimum size of the element relative to 100%.
    styleobjectnullInline style of the component.
    classNamestringnullClassName of the component.
    sizenumbernullSize of the element relative to 100%.
    minSizenumbernullMinimum size of the element relative to 100%.
    styleobjectnullInline style of the component.
    classNamestringnullClassName of the component.
    Properties of Splitter
    -

    Any property as style and class are passed to the main container element. Following are the - additional properties to configure the component.

    -
    - +

    Any property as style and class are passed to the main container element. Following are the additional properties to configure the component.

    +
    +
    - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDefaultDescription
    NameTypeDefaultDescription
    idstringnullUnique identifier of the element.
    styleobjectnullInline style of the component.
    classNamestringnullClassName of the component.
    layoutstringhorizontalOrientation of the panels, valid values are "horizontal" and "vertical".
    gutterSizenumber4Size of the divider in pixels.
    stateKeystringnullStorage identifier of a stateful Splitter.
    stateStoragestringsessionDefines where a stateful splitter keeps its state, valid values are "session" - for sessionStorage and "local" for localStorage. -
    idstringnullUnique identifier of the element.
    styleobjectnullInline style of the component.
    classNamestringnullClassName of the component.
    layoutstringhorizontalOrientation of the panels, valid values are "horizontal" and "vertical".
    gutterSizenumber4Size of the divider in pixels.
    stateKeystringnullStorage identifier of a stateful Splitter.
    stateStoragestringsessionDefines where a stateful splitter keeps its state, valid values are "session" for sessionStorage and "local" for localStorage.
    Events of Splitter
    -
    - +
    +
    - - - - - + + + + + - - - - - + + + + +
    NameParametersDescription
    NameParametersDescription
    onResizeEndevent.originalEvent: Browser event
    - event.sizes: Sizes of the panels as an array -
    Callback to invoke when resize ends.
    onResizeEnd + event.originalEvent: Browser event
    + event.sizes: Sizes of the panels as an array +
    Callback to invoke when resize ends.
    Styling

    Following is the list of structural style classes

    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NameElement
    p-splitterContainer element.
    p-splitterContainer element during resize.
    p-splitter-horizontalContainer element with horizontal layout.
    p-splitter-verticalContainer element with vertical layout.
    p-splitter-panelSplitter panel element.
    p-splitter-gutterGutter element to use when resizing the panels.
    p-splitter-gutter-handleHandl element of the gutter.
    -
    - -
    Accessibility
    - -
    Screen Reader
    -

    Splitter bar defines separator as the role with aria-orientation set to either horizontal or vertical.

    - -
    Keyboard Support
    -
    - +
    +
    - - + + - - + + + + + + + + + + - - + + - - + + - - + + - - + +
    KeyFunctionNameElement
    tabMoves focus through the splitter bar.p-splitterContainer element.
    p-splitterContainer element during resize.
    p-splitter-horizontalContainer element with horizontal layout.
    down arrowMoves a vertical splitter down.p-splitter-verticalContainer element with vertical layout.
    up arrowMoves a vertical splitter up.p-splitter-panelSplitter panel element.
    left arrowMoves a vertical splitter to the left.p-splitter-gutterGutter element to use when resizing the panels.
    right arrowMoves a vertical splitter to the right.p-splitter-gutter-handleHandl element of the gutter.
    -
    + +
    Accessibility
    + +
    Screen Reader
    +

    + Splitter bar defines separator as the role with aria-orientation set to either horizontal or vertical. +

    + +
    Keyboard Support
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    KeyFunction
    + tab + Moves focus through the splitter bar.
    + down arrow + Moves a vertical splitter down.
    + up arrow + Moves a vertical splitter up.
    + left arrow + Moves a vertical splitter to the left.
    + right arrow + Moves a vertical splitter to the right.
    +
    +
    Dependencies

    None.

    - { - useLiveEditorTabs({ name: 'SplitterDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'SplitterDemo', sources: sources })}
    - ) -}) + ); +}); export default SplitterDoc; diff --git a/components/doc/steps/index.js b/components/doc/steps/index.js index f761e1985f..cc00cb237a 100644 --- a/components/doc/steps/index.js +++ b/components/doc/steps/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const StepsDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -70,7 +69,7 @@ export class StepsDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState, useRef } from 'react'; @@ -124,7 +123,7 @@ const StepsDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState, useRef } from 'react'; @@ -178,7 +177,7 @@ const StepsDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -239,7 +238,7 @@ const StepsDemo = () => { } ` } - } + }; const extFiles = { 'demo/StepsDemo.css': { @@ -287,34 +286,36 @@ const StepsDemo = () => { } ` } - } + }; return ( -
    +
    - +
    Import via Module
    - -{` + + {` import { Steps } from 'primereact/steps'; `} - +
    Import via CDN
    - -{` + + {` `} - +
    MenuItem API
    -

    Steps uses the common menu item api to define its items, visit MenuModel for details.

    +

    + Steps uses the common menu item api to define its items, visit MenuModel for details. +

    Getting Started

    TabMenu requires a collection of menuitems as its model.

    - -{` + + {` const items = [ {label: 'Personal'}, {label: 'Seat'}, @@ -322,26 +323,28 @@ const items = [ {label: 'Confirmation'} ]; `} - + - -{` + + {` `} - +
    interactive
    -

    Items are readOnly by default, if you'd like to make them interactive then disable readonly, use command handlers of menuitem to respond to selection events and define activeIndex property along with the - onSelect event to use it as a controlled component.

    +

    + Items are readOnly by default, if you'd like to make them interactive then disable readonly, use command handlers of menuitem to respond to selection events and define activeIndex property along with the onSelect event to use + it as a controlled component. +

    - -{` + + {` setActiveIndex(e.index)} readOnly={false} /> `} - + - -{` + + {` const interactiveItems = [ { label: 'Personal', @@ -369,11 +372,11 @@ const interactiveItems = [ } ]; `} - +
    Properties
    -
    - +
    +
    @@ -424,8 +427,8 @@ const interactiveItems = [
    Events
    -
    -
    Name
    +
    +
    @@ -436,9 +439,13 @@ const interactiveItems = [ - + @@ -446,9 +453,11 @@ const interactiveItems = [
    Styling
    -

    Following is the list of structural style classes, for theming classes visit theming page.

    -
    -
    Name
    onSelectevent.originalEvent: Browser event
    - event.item: Selected item instance
    - event.index: Index of selected item instance
    + event.originalEvent: Browser event +
    + event.item: Selected item instance +
    + event.index: Index of selected item instance +
    Callback to invoke when the new step is selected.
    +

    + Following is the list of structural style classes, for theming classes visit theming page. +

    +
    +
    @@ -477,64 +486,78 @@ const interactiveItems = [
    Accessibility
    - -
    Screen Reader
    -

    Steps component uses the nav element and since any attribute is passed to the root implicitly aria-labelledby or aria-label can be used to describe the component. Inside an ordered list is used - where the current step item defines aria-current as "step".

    - -
    Keyboard Support
    -
    -
    Name
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    KeyFunction
    tabAdds focus to the active step when focus moves in to the component, if there is already a focused tab header then moves the focus out of the component based on the page tab sequence.
    enterActivates the focused step if readonly is not enabled.
    spaceActivates the focused step if readonly is not enabled.
    right arrowMoves focus to the next step if readonly is not enabled.
    left arrowMoves focus to the previous step if readonly is not enabled.
    homeMoves focus to the first step if readonly is not enabled.
    endMoves focus to the last step if readonly is not enabled.
    -
    - + +
    Screen Reader
    +

    + Steps component uses the nav element and since any attribute is passed to the root implicitly aria-labelledby or aria-label can be used to describe the component. Inside an ordered list is used where + the current step item defines aria-current as "step". +

    + +
    Keyboard Support
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    KeyFunction
    + tab + Adds focus to the active step when focus moves in to the component, if there is already a focused tab header then moves the focus out of the component based on the page tab sequence.
    + enter + Activates the focused step if readonly is not enabled.
    + space + Activates the focused step if readonly is not enabled.
    + right arrow + Moves focus to the next step if readonly is not enabled.
    + left arrow + Moves focus to the previous step if readonly is not enabled.
    + home + Moves focus to the first step if readonly is not enabled.
    + end + Moves focus to the last step if readonly is not enabled.
    +
    +
    Dependencies

    None.

    - { - useLiveEditorTabs({ name: 'StepsDemo', sources: sources, extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'StepsDemo', sources: sources, extFiles: extFiles })}
    - ) -}) + ); +}); export default StepsDoc; diff --git a/components/doc/styleclass/index.js b/components/doc/styleclass/index.js index cc28bf27db..2472771967 100644 --- a/components/doc/styleclass/index.js +++ b/components/doc/styleclass/index.js @@ -4,9 +4,8 @@ import { useLiveEditorTabs } from '../common/liveeditor'; import { CodeHighlight } from '../common/codehighlight'; const StyleClassDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -50,7 +49,7 @@ export class StyleClassDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useRef } from 'react'; @@ -88,7 +87,7 @@ const StyleClassDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useRef } from 'react'; @@ -126,7 +125,7 @@ const StyleClassDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -168,7 +167,7 @@ const StyleClassDemo = () => { } ` } - } + }; const extFiles = { 'demo/StyleClassDemo.css': { @@ -208,42 +207,48 @@ const StyleClassDemo = () => { } ` } - } + }; return ( -
    +
    - +
    Import via Module
    - -{` + + {` import { StyleClass } from 'primereact/styleclass'; `} - +
    Import via CDN
    - -{` + + {` `} - +
    Getting Started
    -

    Required prop nodeRef needs to be bind to target's ref which is DOM element. StyleClass has two modes, toggleClassName to simply add-remove a class and enter/leave animations.

    - -

    ToggleClass

    - -{` +

    + Required prop nodeRef needs to be bind to target's ref which is DOM element. StyleClass has two modes, toggleClassName to simply add-remove a class and enter/leave animations. +

    + +

    + ToggleClass +

    + + {`
    - ) -}) + ); +}); export default TabMenuDoc; diff --git a/components/doc/tabview/index.js b/components/doc/tabview/index.js index 3056eaf1ea..e65fad9ef4 100644 --- a/components/doc/tabview/index.js +++ b/components/doc/tabview/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const TabViewDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -224,7 +223,7 @@ export class TabViewDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -427,7 +426,7 @@ const TabViewDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -630,7 +629,7 @@ const TabViewDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -856,35 +855,37 @@ const TabViewDemo = () => { } ` } - } + }; return ( -
    +
    - +
    Import via Module
    - -{` + + {` import { TabView, TabPanel } from 'primereact/tabview'; `} - +
    Import via CDN
    - -{` + + {` `} - +
    Getting Started

    Tabview element consists of one or more TabPanel elements and can either be used as a Controlled or Uncontrolled component.

    Controlled Component
    -

    In controlled mode, activeIndex and onTabChange properties need to be defined to control the state.

    +

    + In controlled mode, activeIndex and onTabChange properties need to be defined to control the state. +

    - -{` + + {` const [activeIndex, setActiveIndex] = useState(0); setActiveIndex(e.index)}> @@ -899,14 +900,16 @@ const [activeIndex, setActiveIndex] = useState(0);
    `} - +
    Uncontrolled
    -

    In uncontrolled mode, no additional properties are required. Initial active tab can be provided using the activeIndex property in uncontrolled mode however it is evaluated at initial rendering and ignored in further updates. If you programmatically - need to update the active tab, prefer to use the component as controlled.

    +

    + In uncontrolled mode, no additional properties are required. Initial active tab can be provided using the activeIndex property in uncontrolled mode however it is evaluated at initial rendering and ignored in further + updates. If you programmatically need to update the active tab, prefer to use the component as controlled. +

    - -{` + + {` Content I @@ -919,22 +922,24 @@ const [activeIndex, setActiveIndex] = useState(0); `} - +
    Header Template
    -

    The header element is fully customizable on TabPanel. To make special header, an object can be given to the headerTemplate property as below.

    - -{` +

    + The header element is fully customizable on TabPanel. To make special header, an object can be given to the headerTemplate property as below. +

    + + {` Content I `} - +
    - - {` + + {` template: (options) => { // options.className: Style class of the default header element. // options.titleClassName: Style class of the title element. @@ -949,11 +954,11 @@ template: (options) => { // options.ariaControls: The value of aria-controls property. } `} - +
    Properties For TabPanel
    -
    - +
    +
    @@ -1040,8 +1045,8 @@ template: (options) => {
    Properties For TabView
    -
    -
    Name
    +
    +
    @@ -1104,8 +1109,8 @@ template: (options) => {
    Events
    -
    -
    Name
    +
    +
    @@ -1116,9 +1121,10 @@ template: (options) => { - + @@ -1126,8 +1132,8 @@ template: (options) => {
    Methods
    -
    -
    Name
    onTabChangeevent.originalEvent: Browser event
    - event.index: Index of the selected tab -
    + event.originalEvent: Browser event
    + event.index: Index of the selected tab +
    Callback to invoke when an active tab is changed.
    +
    +
    @@ -1146,9 +1152,11 @@ template: (options) => {
    Styling
    -

    Following is the list of structural style classes, for theming classes visit theming page.

    -
    -
    Name
    +

    + Following is the list of structural style classes, for theming classes visit theming page. +

    +
    +
    @@ -1180,16 +1188,18 @@ template: (options) => {
    Name
    -
    Accessibility
    +
    Accessibility
    Screen Reader
    -

    TabView container is defined with the tablist role, as any attribute is passed to the container element aria-labelledby can be optionally used to specify an element to describe the TabView. Each tab header - has a tab role along with aria-selected state attribute and aria-controls to refer to the corresponding tab content element. The content element of each tab has tabpanel role, an id to match the - aria-controls of the header and aria-labelledby reference to the header as the accessible name.

    +

    + TabView container is defined with the tablist role, as any attribute is passed to the container element aria-labelledby can be optionally used to specify an element to describe the TabView. Each tab header + has a tab role along with aria-selected state attribute and aria-controls to refer to the corresponding tab content element. The content element of each tab has tabpanel role, an id to match the + aria-controls of the header and aria-labelledby reference to the header as the accessible name. +

    Tab Header Keyboard Support
    -
    - +
    +
    @@ -1198,49 +1208,59 @@ template: (options) => { - + - + - + - + - + - + - +
    Key
    tab + tab + Moves focus through the header.
    enter + enter + Activates the focused tab header.
    space + space + Activates the focused tab header.
    right arrow + right arrow + Moves focus to the next header.
    left arrow + left arrow + Moves focus to the previous header.
    home + home + Moves focus to the last header.
    end + end + Moves focus to the first header.
    -
    Dependencies

    None.

    - - { - useLiveEditorTabs({ name: 'TabViewDemo', sources: sources, extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'TabViewDemo', sources: sources, extFiles: extFiles })}
    ); -}) +}); export default TabViewDoc; diff --git a/components/doc/tag/index.js b/components/doc/tag/index.js index 5756a94d7f..be01fe1b04 100644 --- a/components/doc/tag/index.js +++ b/components/doc/tag/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const TagDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -47,7 +46,7 @@ export class TagDemo extends Component { ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React from 'react'; @@ -83,7 +82,7 @@ export const TagDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React from 'react'; @@ -119,7 +118,7 @@ export const TagDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -158,41 +157,45 @@ const TagDemo = () => { } ` } - } + }; return ( -
    +
    - +
    Import via Module
    - -{` + + {` import { Tag } from 'primereact/tag'; `} - +
    Import via CDN
    - -{` + + {` `} - +
    Getting Started
    -

    Content of the tag is specified using the value property.

    - -{` +

    + Content of the tag is specified using the value property. +

    + + {` `} - +
    Icon
    -

    An icon can also be configured to be displayed next to the value with the icon property.

    - -{` +

    + An icon can also be configured to be displayed next to the value with the icon property. +

    + + {` `} - +
    Severities

    Different color options are available as severity levels.

    @@ -206,18 +209,18 @@ import { Tag } from 'primereact/tag';
    Templating

    Content can easily be added like a child element.

    - -{` + + {` Content `} - +
    Properties

    Any valid attribute is passed to the root element implicitly, extended properties are as follows;

    -
    - +
    +
    @@ -256,9 +259,11 @@ import { Tag } from 'primereact/tag';
    Styling
    -

    Following is the list of structural style classes, for theming classes visit theming page.

    -
    -
    Name
    +

    + Following is the list of structural style classes, for theming classes visit theming page. +

    +
    +
    @@ -289,8 +294,10 @@ import { Tag } from 'primereact/tag';
    Accessibility
    Screen Reader
    -

    Tag does not include any roles and attributes by default, any attribute is passed to the root element so aria roles and attributes can be added if required. If the tags are dynamic, - aria-live may be utilized as well. In case badges need to be tabbable, tabIndex can be added to implement custom key handlers.

    +

    + Tag does not include any roles and attributes by default, any attribute is passed to the root element so aria roles and attributes can be added if required. If the tags are dynamic, + aria-live may be utilized as well. In case badges need to be tabbable, tabIndex can be added to implement custom key handlers. +

    Keyboard Support

    Component does not include any interactive elements.

    @@ -300,12 +307,10 @@ import { Tag } from 'primereact/tag';

    None.

    - { - useLiveEditorTabs({ name: 'TagDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'TagDemo', sources: sources })} ); -}) +}); export default TagDoc; diff --git a/components/doc/terminal/index.js b/components/doc/terminal/index.js index ec90a24ffc..c65e3c4b80 100644 --- a/components/doc/terminal/index.js +++ b/components/doc/terminal/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const TerminalDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -74,7 +73,7 @@ export class TerminalDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useEFfect } from 'react'; @@ -138,7 +137,7 @@ export const TerminalDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useEFfect } from 'react'; @@ -202,7 +201,7 @@ export const TerminalDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -270,7 +269,7 @@ const TerminalDemo = () => { } ` } - } + }; const extFiles = { 'demo/TerminalDemo.css': { @@ -293,35 +292,36 @@ const TerminalDemo = () => { } ` } - } + }; return ( -
    +
    - +
    Import via Module
    - -{` + + {` import { Terminal } from 'primereact/terminal'; import { TerminalService } from 'primereact/terminalservice'; `} - +
    Import via CDN
    - -{` + + {` `} - +
    Getting Started
    -

    Commands are processed using an EventBus implementation called TerminalService. - Import this service into your component and subscribe to the command event to process the commands by - sending replies with the response event. Also, all commands can be cleared using the clear event

    +

    + Commands are processed using an EventBus implementation called TerminalService. Import this service into your component and subscribe to the command event to process the commands by sending replies with the{' '} + response event. Also, all commands can be cleared using the clear event +

    - -{` + + {` export const TerminalDemo = () => { const commandHandler = (text) => { @@ -372,12 +372,12 @@ export const TerminalDemo = () => { ); } `} - +
    Properties

    Any valid attribute is passed to the root element implicitly, extended properties are as follows;

    -
    -
    Name
    +
    +
    @@ -422,9 +422,11 @@ export const TerminalDemo = () => {
    Styling
    -

    Following is the list of structural style classes, for theming classes visit theming page.

    -
    -
    Name
    +

    + Following is the list of structural style classes, for theming classes visit theming page. +

    +
    +
    @@ -457,44 +459,48 @@ export const TerminalDemo = () => {
    Accessibility
    - -
    Screen Reader
    -

    Terminal component has an input element that can be described with aria-label or aria-labelledby props. The element that lists the previous commands has aria-live so that changes are received by the screen reader.

    - -
    Keyboard Support
    -
    -
    Name
    - - - - - - - - - - - - - - - - -
    KeyFunction
    tabMoves focus through the input element.
    enterExecutes the command when focus in on the input element.
    -
    - + +
    Screen Reader
    +

    + Terminal component has an input element that can be described with aria-label or aria-labelledby props. The element that lists the previous commands has aria-live so that changes are received by the + screen reader. +

    + +
    Keyboard Support
    +
    + + + + + + + + + + + + + + + + + +
    KeyFunction
    + tab + Moves focus through the input element.
    + enter + Executes the command when focus in on the input element.
    +
    +
    Dependencies

    None.

    - { - useLiveEditorTabs({ name: 'TerminalDemo', sources: sources, extFiles: extFiles }) - } - + {useLiveEditorTabs({ name: 'TerminalDemo', sources: sources, extFiles: extFiles })}
    - ) -}) + ); +}); export default TerminalDoc; diff --git a/components/doc/tieredmenu/index.js b/components/doc/tieredmenu/index.js index 2dd3309dd3..994848ab97 100644 --- a/components/doc/tieredmenu/index.js +++ b/components/doc/tieredmenu/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const TieredMenuDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -168,7 +167,7 @@ export class TieredMenuDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useRef } from 'react'; @@ -322,7 +321,7 @@ const TieredMenuDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useRef } from 'react'; @@ -476,7 +475,7 @@ const TieredMenuDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -633,34 +632,36 @@ const TieredMenuDemo = () => { } ` } - } + }; - return ( -
    - - -
    Import via Module
    - -{` + return ( +
    + + +
    Import via Module
    + + {` import { TieredMenu } from 'primereact/tieredmenu'; `} - + -
    Import via CDN
    - -{` +
    Import via CDN
    + + {` `} - +
    -
    MenuItem API
    -

    TieredMenu uses the common menu item api to define its items, visit MenuModel for details.

    +
    MenuItem API
    +

    + TieredMenu uses the common menu item api to define its items, visit MenuModel for details. +

    -
    Getting Started
    -

    Menu requires a collection of menuitems as its model.

    - -{` +
    Getting Started
    +

    Menu requires a collection of menuitems as its model.

    + + {` const items = [ { label:'File', @@ -793,27 +794,27 @@ const items = [ } ]; `} - +
    - -{` + + {` `} - +
    Popup Mode

    TieredMenu is inline by default whereas popup mode is supported by enabling popup property and calling toggle method with an event of the target.

    - -{` + + {`
    - ) -}) + ); +}); export default TieredMenuDoc; diff --git a/components/doc/timeline/index.js b/components/doc/timeline/index.js index d2f1bf5ac9..2d79062729 100644 --- a/components/doc/timeline/index.js +++ b/components/doc/timeline/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const TimelineDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -98,7 +97,7 @@ export class TimelineDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useRef } from 'react'; @@ -181,7 +180,7 @@ const TimelineDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useRef } from 'react'; @@ -265,7 +264,7 @@ const TieredMenuDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -353,7 +352,7 @@ const TimelineDemo = () => { } ` } - } + }; const extFiles = { 'demo/TimelineDemo.css': { @@ -390,32 +389,34 @@ const TimelineDemo = () => { } ` } - } + }; return ( -
    +
    - +
    Import via Module
    - -{` + + {` import { Timeline } from 'primereact/timeline'; `} - +
    Import via CDN
    - -{` + + {` `} - +
    Getting Started
    -

    Timeline receives the events with the value property as a collection of arbitrary objects. In addition, content property is required to display the representation of an event. - Example below is a sample events array that is used throughout the documentation.

    - -{` +

    + Timeline receives the events with the value property as a collection of arbitrary objects. In addition, content property is required to display the representation of an event. Example below is a sample events + array that is used throughout the documentation. +

    + + {` const events = [ { status: 'Ordered', date: '15/10/2020 10:30', icon: 'pi pi-shopping-cart', color: '#9C27B0', image: 'game-controller.jpg' }, { status: 'Processing', date: '15/10/2020 14:00', icon: 'pi pi-cog', color: '#673AB7' }, @@ -423,56 +424,64 @@ const events = [ { status: 'Delivered', date: '16/10/2020 10:00', icon: 'pi pi-check', color: '#607D8B' } ]; `} - +
    - -{` + + {` item.status} /> `} - +
    Layout
    -

    Default layout of the timeline is vertical, setting layout to "horizontal" displays the items horizontally.

    - -{` +

    + Default layout of the timeline is vertical, setting layout to "horizontal" displays the items horizontally. +

    + + {` item.status} /> `} - +
    Alignment
    -

    Location of the timeline bar is defined using the align property.

    - -{` +

    + Location of the timeline bar is defined using the align property. +

    + + {` item.status} /> `} - +

    In addition, the "alternate" alignment option make the contents take turns around the timeline bar.

    - -{` + + {` item.status} /> `} - +
    Opposite
    -

    Content to be placed at the other side of the bar is defined with the opposite property.

    - -{` +

    + Content to be placed at the other side of the bar is defined with the opposite property. +

    + + {` item.status} content={(item) => {item.date}} /> `} - +
    Custom Markers
    -

    marker property allows placing a custom event marker instead of the default one. Below is an example with custom markers and content.

    - -{` +

    + marker property allows placing a custom event marker instead of the default one. Below is an example with custom markers and content. +

    + + {` } content={(item) => item.status}} /> `} - +
    Properties
    -
    - +
    +
    @@ -529,9 +538,11 @@ const events = [
    Styling
    -

    Following is the list of structural style classes, for theming classes visit theming page.

    -
    -
    Name
    +

    + Following is the list of structural style classes, for theming classes visit theming page. +

    +
    +
    @@ -601,25 +612,21 @@ const events = [
    Accessibility
    -
    Screen Reader
    -

    Timeline uses a semantic ordered list element to list the events. No specific role is enforced, still you may use any aria role and attributes - as any valid attribute is passed to the list element. -

    +
    Screen Reader
    +

    Timeline uses a semantic ordered list element to list the events. No specific role is enforced, still you may use any aria role and attributes as any valid attribute is passed to the list element.

    -
    Keyboard Support
    -

    Component does not include any interactive elements.

    -
    +
    Keyboard Support
    +

    Component does not include any interactive elements.

    +
    Dependencies

    None.

    - { - useLiveEditorTabs({ name: 'TimelineDemo', sources: sources, extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'TimelineDemo', sources: sources, extFiles: extFiles })} - ) -}) + ); +}); export default TimelineDoc; diff --git a/components/doc/toast/index.js b/components/doc/toast/index.js index 8d99ab81c0..aede5ee719 100644 --- a/components/doc/toast/index.js +++ b/components/doc/toast/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const ToastDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -134,7 +133,7 @@ export class ToastDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useRef } from 'react'; @@ -248,7 +247,7 @@ const ToastDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useRef } from 'react'; @@ -362,7 +361,7 @@ const ToastDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -498,48 +497,50 @@ const ToastDemo = () => { } ` } - } + }; return ( -
    +
    - +
    Import via Module
    - -{` + + {` import { Toast } from 'primereact/toast'; `} - +
    Import via CDN
    - -{` + + {` `} - +
    Getting Started
    -

    A single message is represented by the Message interface in PrimeReact that defines various properties such as severity, - summary and detail. Messages are displayed by using the show method on the ref of the Toast instance.

    +

    + A single message is represented by the Message interface in PrimeReact that defines various properties such as severity, summary and detail. Messages are displayed by using the show method on the ref of the Toast + instance. +

    Note that for animations, toast requires react-transition-group package.

    - -{` + + {` `} - + - -{` + + {` toast.current.show({severity: 'success', summary: 'Success Message', detail: 'Order submitted'}); `} - +
    Message API
    -
    -
    Name
    +
    +
    @@ -632,8 +633,8 @@ toast.current.show({severity: 'success', summary: 'Success Message', detail: 'Or
    Showing Messages

    Show method accepts either a single message or an array of messages.

    - -{` + + {`
    Name
    +
    +
    @@ -770,21 +776,29 @@ toast.current.replace(newMessages); - + - +
    NametransitionOptions object nullThe properties of CSSTransition can be customized, except for "nodeRef" and "in" properties. + The properties of{' '} + + CSSTransition + {' '} + can be customized, except for "nodeRef" and "in" properties. +
    appendTo DOM element | string selfDOM element instance where the component should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. + DOM element instance where the component should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. +
    Events
    -
    - +
    +
    @@ -818,9 +832,11 @@ toast.current.replace(newMessages);
    Styling
    -

    Following is the list of structural style classes, for theming classes visit theming page.

    -
    -
    Name
    +

    + Following is the list of structural style classes, for theming classes visit theming page. +

    +
    +
    @@ -862,48 +878,53 @@ toast.current.replace(newMessages);
    Accessibility
    -
    Screen Reader
    -

    Toast component use alert role that implicitly defines aria-live as "assertive" and aria-atomic as "true".

    - -

    Close element is a button with an aria-label that refers to the aria.close property of the locale API by default, you may use - closeButtonProps to customize the element and override the default aria-label.

    - -
    Close Button Keyboard Support
    -
    -
    Name
    - - - - - - - - - - - - - - - - -
    KeyFunction
    enterCloses the message.
    spaceCloses the message.
    -
    +
    Screen Reader
    +

    + Toast component use alert role that implicitly defines aria-live as "assertive" and aria-atomic as "true". +

    + +

    + Close element is a button with an aria-label that refers to the aria.close property of the locale API by default, you may use + closeButtonProps to customize the element and override the default aria-label. +

    + +
    Close Button Keyboard Support
    +
    + + + + + + + + + + + + + + + + + +
    KeyFunction
    + enter + Closes the message.
    + space + Closes the message.
    +
    Dependencies
    • react-transition-group
    -
    - { - useLiveEditorTabs({ name: 'ToastDemo', sources: sources, extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'ToastDemo', sources: sources, extFiles: extFiles })}
    ); -}) +}); export default ToastDoc; diff --git a/components/doc/togglebutton/index.js b/components/doc/togglebutton/index.js index 0895ece444..4b9e7a1090 100644 --- a/components/doc/togglebutton/index.js +++ b/components/doc/togglebutton/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const ToggleButtonDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -41,7 +40,7 @@ export class ToggleButtonDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -64,10 +63,10 @@ const ToggleButtonDemo = () => { ); } ` - }, - 'ts': { - tabName: 'TS Source', - content: ` + }, + ts: { + tabName: 'TS Source', + content: ` import React, { useState } from 'react'; import { ToggleButton } from 'primereact/togglebutton'; @@ -89,7 +88,7 @@ const ToggleButtonDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -116,49 +115,53 @@ const ToggleButtonDemo = () => { } ` } - } + }; return ( -
    +
    - +
    Import via Module
    - -{` + + {` import { ToggleButton } from 'primereact/togglebutton'; `} - +
    Import via CDN
    - -{` + + {` `} - +
    Getting Started
    -

    ToggleButton is used as a controlled input with checked and onChange properties.

    +

    + ToggleButton is used as a controlled input with checked and onChange properties. +

    - -{` + + {` setChecked1(e.value)} /> `} - +
    Labels and Icons
    -

    Icons and Labels can be customized using onLabel, offLabel, onIcon and offIcon properties.

    +

    + Icons and Labels can be customized using onLabel, offLabel, onIcon and offIcon properties. +

    - -{` + + {` setChecked2(e.value)} /> `} - +
    Properties

    Any valid attribute is passed to the root element implicitly, extended properties are as follows;

    -
    - +
    +
    @@ -245,8 +248,8 @@ import { ToggleButton } from 'primereact/togglebutton';
    Events
    -
    -
    Name
    +
    +
    @@ -257,8 +260,10 @@ import { ToggleButton } from 'primereact/togglebutton'; - + @@ -276,9 +281,11 @@ import { ToggleButton } from 'primereact/togglebutton';
    Styling
    -

    Following is the list of structural style classes, for theming classes visit theming page.

    -
    -
    Name
    onChangeevent.originalEvent: Browser event
    - event.value: Value as the checked state.
    + event.originalEvent: Browser event
    + event.value: Value as the checked state. +
    Callback to invoke on value change.
    +

    + Following is the list of structural style classes, for theming classes visit theming page. +

    +
    +
    @@ -303,50 +310,55 @@ import { ToggleButton } from 'primereact/togglebutton';
    Accessibility
    - -
    Screen Reader
    -

    ToggleButton component uses an element with button role and updates aria-pressed state for screen readers. Value to describe the component can be defined with aria-labelledby or aria-label props, it is highly suggested to use - either of these props as the component changes the label displayed which will result in screen readers to read different labels when the component receives focus. To prevent this, always provide an aria label that does not change related to state.

    - -{` + +
    Screen Reader
    +

    + ToggleButton component uses an element with button role and updates aria-pressed state for screen readers. Value to describe the component can be defined with aria-labelledby or aria-label{' '} + props, it is highly suggested to use either of these props as the component changes the label displayed which will result in screen readers to read different labels when the component receives focus. To prevent this, + always provide an aria label that does not change related to state. +

    + + {` Remember Me `} - -
    Keyboard Support
    -
    -
    Name
    - - - - - - - - - - - - - - - - -
    KeyFunction
    tabMoves focus to the button.
    spaceToggles the checked state.
    -
    - + +
    Keyboard Support
    +
    + + + + + + + + + + + + + + + + + +
    KeyFunction
    + tab + Moves focus to the button.
    + space + Toggles the checked state.
    +
    +
    Dependencies

    None.

    - { - useLiveEditorTabs({ name: 'ToggleButtonDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'ToggleButtonDemo', sources: sources })}
    ); -}) +}); export default ToggleButtonDoc; diff --git a/components/doc/toolbar/index.js b/components/doc/toolbar/index.js index 386841c092..8a986bc11b 100644 --- a/components/doc/toolbar/index.js +++ b/components/doc/toolbar/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const ToolbarDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -73,7 +72,7 @@ export class ToolbarDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React from 'react'; @@ -131,7 +130,7 @@ const ToolbarDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React from 'react'; @@ -189,7 +188,7 @@ const ToolbarDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -253,31 +252,33 @@ const ToolbarDemo = () => { } ` } - } + }; return ( -
    +
    - +
    Import via Module
    - -{` + + {` import { Toolbar } from 'primereact/toolbar'; `} - +
    Import via CDN
    - -{` + + {` `} - +
    Getting Started
    -

    Toolbar provides left and right templates to place content at these sections.

    - -{` +

    + Toolbar provides left and right templates to place content at these sections. +

    + + {` const leftContents = (
    - ) -}) + ); +}); export default ToolbarDoc; diff --git a/components/doc/tooltip/index.js b/components/doc/tooltip/index.js index 8aabd3f538..1b5c05d66e 100644 --- a/components/doc/tooltip/index.js +++ b/components/doc/tooltip/index.js @@ -5,9 +5,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const TooltipDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -133,7 +132,7 @@ export class TooltipDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -251,7 +250,7 @@ const TooltipDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -369,7 +368,7 @@ const TooltipDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -548,57 +547,64 @@ const TooltipDemo = () => { } ` } - } + }; return ( -
    +
    - +
    Import to use it as a component
    - -{` + + {` import { Tooltip } from 'primereact/tooltip'; `} - +
    Getting Started
    -

    Tooltip functionality is integrated within the the components that have support such as inputtext or buttons. Content is defined with the tooltip property.

    - -{` +

    + Tooltip functionality is integrated within the the components that have support such as inputtext or buttons. Content is defined with the tooltip property. +

    + + {`
    - ) -}) + ); +}); export default TooltipDoc; diff --git a/components/doc/tree/index.js b/components/doc/tree/index.js index 670ce07705..3ff6b29e64 100644 --- a/components/doc/tree/index.js +++ b/components/doc/tree/index.js @@ -5,9 +5,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const TreeDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -78,7 +77,7 @@ export class TreeDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState, useEffect } from 'react'; @@ -137,7 +136,7 @@ const TreeDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState, useEffect } from 'react'; @@ -196,7 +195,7 @@ const TreeDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -258,32 +257,34 @@ const TreeDemo = () => { } ` } - } + }; return ( -
    +
    - +
    Import via Module
    - -{` + + {` import { Tree } from 'primereact/tree'; `} - +
    Import via CDN
    - -{` + + {` `} - +
    Getting Started
    -

    Tree component requires an array of TreeNode objects as its value.

    +

    + Tree component requires an array of TreeNode objects as its value. +

    TreeNode API
    -
    - +
    +
    @@ -363,14 +364,14 @@ import { Tree } from 'primereact/tree';
    Name
    - -{` + + {` `} - + - -{` + + {` const data: [ { "key": "0", @@ -424,15 +425,17 @@ const data: [ } ] `} - +
    Controlled vs Uncontrolled
    -

    Tree expansion state is managed in two ways, in uncontrolled mode only initial expanded state of a node can be defined using expandedKeys property whereas in controlled mode expandedKeys +

    + Tree expansion state is managed in two ways, in uncontrolled mode only initial expanded state of a node can be defined using expandedKeys property whereas in controlled mode expandedKeys property along with onToggle properties are used for full control over the state. If you need to expand or collapse the state of nodes programmatically then controlled mode should be used. Example below demonstrates - both cases;

    + both cases; +

    - -{` + + {` import React, { Component } from 'react'; import { Tree } from 'primereact/tree'; import { Button } from 'primereact/button'; @@ -471,14 +474,16 @@ export const TreeDemo = () => { ) } `} - +
    Selection
    -

    Tree supports single, multiple and checkbox selection modes. Define selectionMode, selectionKeys and onSelectionChange properties to control the selection. In single mode, selectionKeys should - be a single value whereas in multiple or checkbox modes an array is required. By default in multiple selection mode, metaKey is necessary to add to existing selections however this can be configured with metaKeySelection property. Note that - in touch enabled devices, Tree does not require metaKey.

    - -{` +

    + Tree supports single, multiple and checkbox selection modes. Define selectionMode, selectionKeys and onSelectionChange properties to control the selection. In single mode, selectionKeys should be a single + value whereas in multiple or checkbox modes an array is required. By default in multiple selection mode, metaKey is necessary to add to existing selections however this can be configured with metaKeySelection property. + Note that in touch enabled devices, Tree does not require metaKey. +

    + + {` import React, {Component} from 'react'; import {Tree} from 'primereact/tree'; import {NodeService} from '../service/NodeService'; @@ -513,13 +518,15 @@ export const TreeSelectionDemo = () => { ) } `} - +
    Lazy
    -

    Lazy loading is implemented using the onExpand event by adding children to the expanded node. leaf property should be enabled to indicate the node has children but not yet loaded. Here is a in-memory demo - that loads generated nodes on expand event to imitate a remote call with a timeout. Notice the usage of loading property as well to give users a feedback about the loading process.

    - -{` +

    + Lazy loading is implemented using the onExpand event by adding children to the expanded node. leaf property should be enabled to indicate the node has children but not yet loaded. Here is a in-memory demo that + loads generated nodes on expand event to imitate a remote call with a timeout. Notice the usage of loading property as well to give users a feedback about the loading process. +

    + + {` import React, {Component} from 'react'; import {Tree} from 'primereact/tree'; import {NodeService} from '../service/NodeService'; @@ -567,13 +574,15 @@ export const TreeLazyDemo = () => { ) } `} - +
    Templating
    -

    label property of a node is used to display as the content by default. Templating is supported as well with the nodeTemplate callback that gets the node instance and returns JSX. For custom filter support define a filterTemplate function that gets the option instance as a parameter and returns the content for the filter element. Example - below is a sample tree based navigation of React docs.

    - -{` +

    + label property of a node is used to display as the content by default. Templating is supported as well with the nodeTemplate callback that gets the node instance and returns JSX. For custom filter support define + a filterTemplate function that gets the option instance as a parameter and returns the content for the filter element. Example below is a sample tree based navigation of React docs. +

    + + {` import React, { Component, useState, useRef } from 'react'; import { Tree } from 'primereact/tree'; @@ -650,13 +659,15 @@ export const TreeTemplatingDemo = () => { ) } `} - +
    DragDrop
    -

    Tree nodes can be reordered using dragdrop by setting dragdropScope property to a unique variable and updating the new value at onDragDrop callback. The value of the dragdropScope must be unique to provide - intervention from other draggable elements on the page.

    - -{` +

    + Tree nodes can be reordered using dragdrop by setting dragdropScope property to a unique variable and updating the new value at onDragDrop callback. The value of the dragdropScope must be unique to provide + intervention from other draggable elements on the page. +

    + + {` import React, {Component} from 'react'; import {Tree} from 'primereact/tree'; import {NodeService} from '../service/NodeService'; @@ -677,31 +688,37 @@ export const TreeDragDropDemo = () => { ) } `} - +
    Filtering
    -

    Filtering is enabled by setting the filter property to true, by default label property of a node - is used to compare against the value in the text field, in order to customize which field(s) should be used during search define filterBy property.

    - -

    In addition filterMode specifies the filtering strategy. In lenient mode when the query matches a node, children of the node are not searched further as all descendants of the node are included. On the other hand, - in strict mode when the query matches a node, filtering continues on all descendants.

    - - -{` +

    + Filtering is enabled by setting the filter property to true, by default label property of a node is used to compare against the value in the text field, in order to customize which field(s) should be used during search + define filterBy property. +

    + +

    + In addition filterMode specifies the filtering strategy. In lenient mode when the query matches a node, children of the node are not searched further as all descendants of the node are included. On the other + hand, in strict mode when the query matches a node, filtering continues on all descendants. +

    + + + {` `} - +
    ContextMenu
    -

    One or more ContextMenu instances can be attached to nodes. Similar to selection, separate contextMenuSelectionKey and onContextMenuSelectionChange properties are necesary to manage the selected node with - right click. In addition, a context menu can either be displayed at onContextMenu event. Since this event also passes the node instance, you may choose to display a different context menu for a particular node.

    +

    + One or more ContextMenu instances can be attached to nodes. Similar to selection, separate contextMenuSelectionKey and onContextMenuSelectionChange properties are necesary to manage the selected node with right + click. In addition, a context menu can either be displayed at onContextMenu event. Since this event also passes the node instance, you may choose to display a different context menu for a particular node. +

    - -{` + + {` import React, { Component } from 'react'; import {Tree} from 'primereact/tree' import {ContextMenu} from 'primereact/contextmenu'; @@ -755,11 +772,11 @@ export const TreeContextMenuDemo = () => { ) } `} - +
    Properties
    -
    - +
    +
    @@ -833,8 +850,10 @@ export const TreeContextMenuDemo = () => { - + @@ -967,8 +986,8 @@ export const TreeContextMenuDemo = () => {
    Events
    -
    -
    NamemetaKeySelection boolean trueDefines how multiple items can be selected, when true metaKey needs to be pressed to select or unselect an item and when set to false selection of each item - can be toggled individually. On touch enabled devices, metaKeySelection is turned off automatically. + Defines how multiple items can be selected, when true metaKey needs to be pressed to select or unselect an item and when set to false selection of each item can be toggled individually. On touch enabled + devices, metaKeySelection is turned off automatically. +
    propagateSelectionUp
    +
    +
    @@ -979,76 +998,97 @@ export const TreeContextMenuDemo = () => { - + - + - + - + - + - + - + - + - + - - - @@ -1057,8 +1097,8 @@ export const TreeContextMenuDemo = () => {
    Methods
    -
    -
    Name
    onSelectevent.originalEvent: browser event
    - event.node: Selected node instance.
    + event.originalEvent: browser event
    + event.node: Selected node instance. +
    Callback to invoke when a node is selected.
    onUnselectevent.originalEvent: browser event
    - event.node: Unselected node instance.
    + event.originalEvent: browser event
    + event.node: Unselected node instance. +
    Callback to invoke when a node is unselected.
    onExpandevent.originalEvent: browser event
    - event.node: Expanded node instance.
    + event.originalEvent: browser event
    + event.node: Expanded node instance. +
    Callback to invoke when a node is expanded.
    onCollapseevent.originalEvent: browser event
    - event.node: Collapsed node instance.
    + event.originalEvent: browser event
    + event.node: Collapsed node instance. +
    Callback to invoke when a node is collapsed.
    onSelectionChangeevent.originalEvent: browser event
    - event.value: Selected node key(s).
    + event.originalEvent: browser event
    + event.value: Selected node key(s). +
    Callback to invoke when selection changes.
    onContextMenuSelectionChangeevent.originalEvent: browser event
    - event.value: Selected node key.
    + event.originalEvent: browser event
    + event.value: Selected node key. +
    Callback to invoke when selection changes with a context menu.
    onToggleevent.originalEvent: browser event
    - event.node: Toggled node instance.
    + event.originalEvent: browser event
    + event.node: Toggled node instance. +
    Callback to invoke when a node is toggled.
    onDragDropevent.originalEvent: browser event
    - event.value: New value after the dragdrop.
    + event.originalEvent: browser event
    + event.value: New value after the dragdrop. +
    Callback to invoke when a node is selected.
    onContextMenuevent.originalEvent: browser event
    - event.node: Selected node instance.
    + event.originalEvent: browser event
    + event.node: Selected node instance. +
    Callback to invoke when a node is selected with a context menu.
    onFilterValueChangeevent.originalEvent: Browser event
    - event.value: the filtered value
    +
    + event.originalEvent: Browser event
    + event.value: the filtered value
    Callback to invoke when filter value changes.
    onNodeClickevent.originalEvent: Browser event
    - event.node: the current node
    +
    + event.originalEvent: Browser event
    + event.node: the current node
    Callback to invoke when the node is clicked.
    onNodeDoubleClickevent.originalEvent: Browser event
    - event.node: the current node
    +
    + event.originalEvent: Browser event
    + event.node: the current node
    Callback to invoke when the node is double-clicked.
    +
    +
    @@ -1078,8 +1118,8 @@ export const TreeContextMenuDemo = () => {
    Styling

    Following is the list of structural style classes

    -
    -
    Name
    +
    +
    @@ -1134,13 +1174,16 @@ export const TreeContextMenuDemo = () => {
    Accessibility
    Screen Reader
    -

    Value to describe the component can either be provided with aria-labelledby or aria-label props. The root list element has a tree role whereas - each list item has a treeitem role along with aria-label, aria-selected and aria-expanded attributes. In checkbox selection, aria-checked is used instead of aria-selected. The container - element of a treenode has the group role. Checkbox and toggle icons are hidden from screen readers as their parent element with treeitem role and attributes are used instead for readers and keyboard support. The aria-setsize, aria-posinset and aria-level attributes are calculated implicitly and added to each treeitem.

    +

    + Value to describe the component can either be provided with aria-labelledby or aria-label props. The root list element has a tree role whereas each list item has a treeitem role along with{' '} + aria-label, aria-selected and aria-expanded attributes. In checkbox selection, aria-checked is used instead of aria-selected. The container element of a treenode has the group{' '} + role. Checkbox and toggle icons are hidden from screen readers as their parent element with treeitem role and attributes are used instead for readers and keyboard support. The aria-setsize,{' '} + aria-posinset and aria-level attributes are calculated implicitly and added to each treeitem. +

    Keyboard Support
    -
    -
    Name
    +
    +
    @@ -1149,39 +1192,57 @@ export const TreeContextMenuDemo = () => { - - + - - + - + - + - + - + - + - + @@ -1191,15 +1252,12 @@ export const TreeContextMenuDemo = () => {
    Dependencies

    None.

    - - { - useLiveEditorTabs({ name: 'TreeDemo', sources: sources, service: 'NodeService', data: 'treenodes' }) - } + {useLiveEditorTabs({ name: 'TreeDemo', sources: sources, service: 'NodeService', data: 'treenodes' })} ); -}) +}); export default TreeDoc; diff --git a/components/doc/treeselect/index.js b/components/doc/treeselect/index.js index 6d61db1f7a..cc4a8b1ad0 100644 --- a/components/doc/treeselect/index.js +++ b/components/doc/treeselect/index.js @@ -5,9 +5,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const TreeSelectDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -60,7 +59,7 @@ export class TreeSelectDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState, useEffect } from 'react'; @@ -104,7 +103,7 @@ const TreeSelectDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState, useEffect } from 'react'; @@ -148,7 +147,7 @@ const TreeSelectDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -211,39 +210,41 @@ const TreeSelectDemo = () => { } ` } - } + }; return ( -
    +
    - +
    Import via Module
    - -{` + + {` import { TreeSelect } from 'primereact/treeselect'; `} - +
    Import via CDN
    - -{` + + {` `} - +
    Getting Started
    -

    TreeSelect component requires an array of TreeNode objects as its options and keys of the nodes as its value.

    +

    + TreeSelect component requires an array of TreeNode objects as its options and keys of the nodes as its value. +

    - -{` + + {` setSelectedNodeKey(e.value)} placeholder="Select Item"> `} - +

    In example below, nodes are retrieved from a remote data source.

    - -{` + + {` export const TreeSelectDemo = () => { const [nodes, setNodes] = useState(null); const [selectedNodeKey, setSelectedNodeKey] = useState(null); @@ -258,10 +259,10 @@ export const TreeSelectDemo = () => { ) } `} - + - -{` + + {` export class NodeService { getTreeNodes() { @@ -270,11 +271,11 @@ export class NodeService { } `} - +

    The json response sample would be as following.

    - -{` + + {` { "root": [ { @@ -330,11 +331,11 @@ export class NodeService { ] } `} - +
    TreeNode API utilized by the TreeSelect
    -
    -
    Key
    tabMoves focus to the first selected node when focus enters the component, if there is none then first element receives the focus. If focus is already inside the component, moves focus to the next - focusable element in the page tab sequence. + + tab + + Moves focus to the first selected node when focus enters the component, if there is none then first element receives the focus. If focus is already inside the component, moves focus to the next focusable + element in the page tab sequence.
    shift + tabMoves focus to the last selected node when focus enters the component, if there is none then first element receives the focus. If focus is already inside the component, moves focus to the previous - focusable element in the page tab sequence. + + shift + tab + + Moves focus to the last selected node when focus enters the component, if there is none then first element receives the focus. If focus is already inside the component, moves focus to the previous focusable + element in the page tab sequence.
    enter + enter + Selects the focused treenode.
    space + space + Selects the focused treenode.
    down arrow + down arrow + Moves focus to the next treenode.
    up arrow + up arrow + Moves focus to the previous treenode.
    right arrow + right arrow + If node is closed, opens the node otherwise moves focus to the first child node.
    left arrow + left arrow + If node is open, closes the node otherwise moves focus to the parent node.
    +
    +
    @@ -403,11 +404,13 @@ export class NodeService {
    Selection
    -

    TreeSelect supports "single", "multiple" and "checkbox" selection modes. Define selectionMode, value and onChange properties to control the selection. In single mode, selectionKeys should - be a single value whereas in multiple or checkbox modes an object is required. By default in multiple selection mode, metaKey is necessary to add to existing selections however this can be configured with metaKeySelection property. Note that - in touch enabled devices, Tree does not require metaKey.

    - -{` +

    + TreeSelect supports "single", "multiple" and "checkbox" selection modes. Define selectionMode, value and onChange properties to control the selection. In single mode, selectionKeys should be a single value + whereas in multiple or checkbox modes an object is required. By default in multiple selection mode, metaKey is necessary to add to existing selections however this can be configured with metaKeySelection property. Note + that in touch enabled devices, Tree does not require metaKey. +

    + + {` import React, {Component} from 'react'; import {TreeSelect} from 'primereact/treeselect'; import {NodeService} from '../service/NodeService'; @@ -438,15 +441,16 @@ export const TreeSelectionDemo = () => { ) } `} - +
    Value Format
    -

    Value passed to and from the TreeSelect via the value property should be a an object with key-value pairs where key is the node key and - value is a boolean to indicate selection. On the other hand - in "checkbox" mode, instead of a boolean, value should be an object that has "checked" and "partialChecked" properties to represent the checked state of a node. Best way to clarify it is prepopulating a TreeSelect with an existing value.

    +

    + Value passed to and from the TreeSelect via the value property should be a an object with key-value pairs where key is the node key and value is a boolean to indicate selection. On the other hand in "checkbox" mode, instead of + a boolean, value should be an object that has "checked" and "partialChecked" properties to represent the checked state of a node. Best way to clarify it is prepopulating a TreeSelect with an existing value. +

    - -{` + + {` data() { return { selectedNodeKey1: '2-1', @@ -456,22 +460,26 @@ data() { } }, `} - +
    Chips Display
    -

    A comma separated list is used by default to display selected items whereas alternative chip mode is provided using the display property to visualize the items as tokens.

    - -{` +

    + A comma separated list is used by default to display selected items whereas alternative chip mode is provided using the display property to visualize the items as tokens. +

    + + {` setSelectedNodeKeys(e.value)} selectionMode="multiple" placeholder="Select Items" /> `} - +
    Templating
    -

    Label of an option is used as the display text of an item by default, for custom content support define a valueTemplate that gets the selected nodes as a parameter. - For custom filter support define a filterTemplate function that gets the option instance as a parameter and returns the content for the filter element. - In addition header, footer and emptyMessage templates are provided for further customization.

    - -{` +

    + Label of an option is used as the display text of an item by default, for custom content support define a valueTemplate that gets the selected nodes as a parameter. For custom filter support define a{' '} + filterTemplate function that gets the option instance as a parameter and returns the content for the filter element. In addition header, footer and emptyMessage templates are provided for further + customization. +

    + + {` const [filterValue, setFilterValue] = useState(''); const filterInputRef = useRef(); @@ -504,34 +512,38 @@ const myFilterFunction = (event, options) => { options.filter(event); } `} - - -{` + + + {` setSelectedNodeKeys(e.value)} valueTemplate={valueTemplate} placeholder="Select Items" filter filterTemplate={filterTemplate}/> `} - +
    Filtering
    -

    Filtering is enabled by setting the filter property to true, by default label property of a node - is used to compare against the value in the text field, in order to customize which field(s) should be used during search define filterBy property.

    - -

    In addition filterMode specifies the filtering strategy. In lenient mode when the query matches a node, children of the node are not searched further as all descendants of the node are included. On the other hand, - in strict mode when the query matches a node, filtering continues on all descendants.

    - - -{` +

    + Filtering is enabled by setting the filter property to true, by default label property of a node is used to compare against the value in the text field, in order to customize which field(s) should be used during search + define filterBy property. +

    + +

    + In addition filterMode specifies the filtering strategy. In lenient mode when the query matches a node, children of the node are not searched further as all descendants of the node are included. On the other + hand, in strict mode when the query matches a node, filtering continues on all descendants. +

    + + + {` `} - +
    Properties

    Any valid attribute is passed to the root element implicitly, extended properties are as follows;

    -
    -
    Name
    +
    +
    @@ -641,7 +653,9 @@ const myFilterFunction = (event, options) => { - + @@ -659,8 +673,10 @@ const myFilterFunction = (event, options) => { - + @@ -690,7 +706,13 @@ const myFilterFunction = (event, options) => { - + @@ -751,8 +773,8 @@ const myFilterFunction = (event, options) => {
    Events
    -
    -
    NameappendTo DOM element | string document.bodyDOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. + DOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. +
    emptyMessagemetaKeySelection boolean trueDefines how multiple items can be selected, when true metaKey needs to be pressed to select or unselect an item and when set to false selection of each item - can be toggled individually. On touch enabled devices, metaKeySelection is turned off automatically. + Defines how multiple items can be selected, when true metaKey needs to be pressed to select or unselect an item and when set to false selection of each item can be toggled individually. On touch enabled + devices, metaKeySelection is turned off automatically. +
    valueTemplatetransitionOptions object nullThe properties of CSSTransition can be customized, except for "nodeRef" and "in" properties. + The properties of{' '} + + CSSTransition + {' '} + can be customized, except for "nodeRef" and "in" properties. +
    dropdownIcon
    +
    +
    @@ -773,38 +795,49 @@ const myFilterFunction = (event, options) => { - + - + - + - + - + - @@ -813,8 +846,8 @@ const myFilterFunction = (event, options) => {
    Methods
    -
    -
    Name
    onChangeevent.originalEvent: browser event
    - event.value: Selected node key(s).
    + event.originalEvent: browser event
    + event.value: Selected node key(s). +
    Callback to invoke when selection changes.
    onNodeSelectevent.originalEvent: browser event
    - event.node: Selected node instance.
    + event.originalEvent: browser event
    + event.node: Selected node instance. +
    Callback to invoke when a node is selected.
    onNodeUnselectevent.originalEvent: browser event
    - event.node: Unselected node instance.
    + event.originalEvent: browser event
    + event.node: Unselected node instance. +
    Callback to invoke when a node is unselected.
    onNodeExpandevent.originalEvent: browser event
    - event.node: Expanded node instance.
    + event.originalEvent: browser event
    + event.node: Expanded node instance. +
    Callback to invoke when a node is expanded.
    onNodeCollapseevent.originalEvent: browser event
    - event.node: Collapsed node instance.
    + event.originalEvent: browser event
    + event.node: Collapsed node instance. +
    Callback to invoke when a node is collapsed.
    onFilterValueChangeevent.originalEvent: Browser event
    - event.value: the filtered value
    +
    + event.originalEvent: Browser event
    + event.value: the filtered value
    Callback to invoke when filter value changes.
    +
    +
    @@ -834,8 +867,8 @@ const myFilterFunction = (event, options) => {
    Styling

    Following is the list of structural style classes

    -
    -
    Name
    +
    +
    @@ -871,159 +904,197 @@ const myFilterFunction = (event, options) => {
    Name
    Accessibility
    - -
    Screen Reader
    -

    Value to describe the component can either be provided with aria-labelledby or aria-label props. The treeselect element has a combobox role - in addition to aria-haspopup and aria-expanded attributes. The relation between the combobox and the popup is created with aria-controls that refers to the id of the popup.

    -

    The popup list has an id that refers to the aria-controls attribute of the combobox element and uses tree as the role. Each list item has a treeitem role along with aria-label, aria-selected and aria-expanded attributes. - In checkbox selection, aria-checked is used instead of aria-selected. Checkbox and toggle icons are hidden from screen readers as their parent element with treeitem role and attributes are used instead for readers and keyboard support. - The container element of a treenode has the group role. The aria-setsize, aria-posinset and aria-level attributes are calculated implicitly and added to each treeitem.

    - -

    If filtering is enabled, filterInputProps can be defined to give aria-* props to the filter input element.

    - -{` + +
    Screen Reader
    +

    + Value to describe the component can either be provided with aria-labelledby or aria-label props. The treeselect element has a combobox role in addition to aria-haspopup and{' '} + aria-expanded attributes. The relation between the combobox and the popup is created with aria-controls that refers to the id of the popup. +

    +

    + The popup list has an id that refers to the aria-controls attribute of the combobox element and uses tree as the role. Each list item has a treeitem role along with aria-label,{' '} + aria-selected and aria-expanded attributes. In checkbox selection, aria-checked is used instead of aria-selected. Checkbox and toggle icons are hidden from screen readers as their parent + element with treeitem role and attributes are used instead for readers and keyboard support. The container element of a treenode has the group role. The aria-setsize, aria-posinset and{' '} + aria-level attributes are calculated implicitly and added to each treeitem. +

    + +

    + If filtering is enabled, filterInputProps can be defined to give aria-* props to the filter input element. +

    + + {` Options `} - -
    Closed State Keyboard Support
    -
    - - - - - - - - - - - - - - - - - - - - - -
    KeyFunction
    tabMoves focus to the treeselect element.
    spaceOpens the popup and moves visual focus to the selected treenode, if there is none then first treenode receives the focus.
    down arrowOpens the popup and moves visual focus to the selected option, if there is none then first option receives the focus.
    -
    - -
    Popup Keyboard Support
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    KeyFunction
    tabMoves focus to the next focusable element in the popup, if there is none then first focusable element receives the focus.
    shift + tabMoves focus to the previous focusable element in the popup, if there is none then last focusable element receives the focus.
    enterSelects the focused option, closes the popup if selection mode is single.
    spaceSelects the focused option, closes the popup if selection mode is single.
    escapeCloses the popup, moves focus to the treeselect element.
    down arrowMoves focus to the next treenode.
    up arrowMoves focus to the previous treenode.
    right arrowIf node is closed, opens the node otherwise moves focus to the first child node.
    left arrowIf node is open, closes the node otherwise moves focus to the parent node.
    -
    - -
    Filter Input Keyboard Support
    -
    - - - - - - - - - - - - - - - - - -
    KeyFunction
    enterCloses the popup and moves focus to the treeselect element.
    escapeCloses the popup and moves focus to the treeselect element.
    -
    - -
    Close Button Keyboard Support
    -
    - - - - - - - - - - - - - - - - - - - - - -
    KeyFunction
    enterCloses the popup and moves focus to the treeselect element.
    spaceCloses the popup and moves focus to the treeselect element.
    escapeCloses the popup and moves focus to the treeselect element.
    -
    -
    +
    +
    Closed State Keyboard Support
    +
    + + + + + + + + + + + + + + + + + + + + + +
    KeyFunction
    + tab + Moves focus to the treeselect element.
    + space + Opens the popup and moves visual focus to the selected treenode, if there is none then first treenode receives the focus.
    + down arrow + Opens the popup and moves visual focus to the selected option, if there is none then first option receives the focus.
    +
    + +
    Popup Keyboard Support
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    KeyFunction
    + tab + Moves focus to the next focusable element in the popup, if there is none then first focusable element receives the focus.
    + shift + tab + Moves focus to the previous focusable element in the popup, if there is none then last focusable element receives the focus.
    + enter + Selects the focused option, closes the popup if selection mode is single.
    + space + Selects the focused option, closes the popup if selection mode is single.
    + escape + Closes the popup, moves focus to the treeselect element.
    + down arrow + Moves focus to the next treenode.
    + up arrow + Moves focus to the previous treenode.
    + right arrow + If node is closed, opens the node otherwise moves focus to the first child node.
    + left arrow + If node is open, closes the node otherwise moves focus to the parent node.
    +
    + +
    Filter Input Keyboard Support
    +
    + + + + + + + + + + + + + + + + + +
    KeyFunction
    + enter + Closes the popup and moves focus to the treeselect element.
    + escape + Closes the popup and moves focus to the treeselect element.
    +
    + +
    Close Button Keyboard Support
    +
    + + + + + + + + + + + + + + + + + + + + + +
    KeyFunction
    + enter + Closes the popup and moves focus to the treeselect element.
    + space + Closes the popup and moves focus to the treeselect element.
    + escape + Closes the popup and moves focus to the treeselect element.
    +
    +
    Dependencies

    None.

    -
    - { - useLiveEditorTabs({ name: 'TreeSelectDemo', sources: sources, service: 'NodeService', data: 'treenodes', extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'TreeSelectDemo', sources: sources, service: 'NodeService', data: 'treenodes', extFiles: extFiles })}
    ); -}) +}); export default TreeSelectDoc; diff --git a/components/doc/treetable/index.js b/components/doc/treetable/index.js index a1b78d3340..71fae50690 100644 --- a/components/doc/treetable/index.js +++ b/components/doc/treetable/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const TreeTableDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -71,7 +70,7 @@ export class TreeTableDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState, useEffect } from 'react'; @@ -125,7 +124,7 @@ const TreeTableDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState, useEffect } from 'react'; @@ -179,7 +178,7 @@ const TreeTableDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -237,37 +236,39 @@ const TreeTableDemo = () => { ); } ` - } - } + } + }; return ( -
    +
    - +
    Import via Module
    - -{` + + {` import { Column } from 'primereact/column'; import { TreeTable } from 'primereact/treetable'; `} - +
    Import via CDN
    - -{` + + {` `} - +
    Getting Started
    -

    TreeTable component requires an array of TreeNode objects as its value and columns defined with one or more Column components.

    +

    + TreeTable component requires an array of TreeNode objects as its value and columns defined with one or more Column components. +

    TreeNode API

    Following properties of the API are currently utilized by the TreeTable.

    -
    - +
    +
    @@ -324,9 +325,9 @@ import { TreeTable } from 'primereact/treetable';

    Here is a sample json response to serve as the datasource of the TreeTable.

    -
    - -{` +
    + + {` { "root": [ @@ -681,14 +682,13 @@ import { TreeTable } from 'primereact/treetable'; ] } `} - -
    +
    +
    -

    Throughout the samples, a NodeService would be used to connect to a server to fetch the nodes. - Note that this is only for demo purposes, TreeTable does not have any restrictions on how data is provided.

    +

    Throughout the samples, a NodeService would be used to connect to a server to fetch the nodes. Note that this is only for demo purposes, TreeTable does not have any restrictions on how data is provided.

    - -{` + + {` export class NodeService { getTreeTableNodes() { @@ -698,12 +698,14 @@ export class NodeService { } `} - + -

    Following sample TreeTable has 3 columns and retrieves the data from the service on componentDidMount. Notice the expander property - in the name column to indicate that this column displays an icon to toggle the child nodes.

    - -{` +

    + Following sample TreeTable has 3 columns and retrieves the data from the service on componentDidMount. Notice the expander property in the name column to indicate that this column displays an icon to toggle the child + nodes. +

    + + {` import React, { Component } from 'react'; import { TreeTable } from 'primereact/treetable'; import { Column } from 'primereact/column'; @@ -727,11 +729,11 @@ export const TreeTableDemo = () => { ); } `} - +

    Dynamic columns are also possible by creating the column component dynamically.

    - -{` + + {` import React, { Component } from 'react'; import { TreeTable } from 'primereact/treetable'; import { Column } from 'primereact/column'; @@ -763,12 +765,12 @@ export const TreeTableDemo = () => { ); } `} - +
    Column Component

    Column component defines various options that are utilized by the TreeTable to specify corresponding features.

    -
    -
    Name
    +
    +
    @@ -987,12 +989,14 @@ export const TreeTableDemo = () => {
    Controlled vs Uncontrolled
    -

    Expansion state is managed in two ways, in uncontrolled mode only initial expanded state of a node can be defined using expandedKeys property whereas in controlled mode expandedKeys - property along with onToggle properties are used for full control over the state. If you need to expand or collapse the state of nodes programmatically then controlled mode should be used. Example below demonstrates - both cases;

    +

    + Expansion state is managed in two ways, in uncontrolled mode only initial expanded state of a node can be defined using expandedKeys property whereas in controlled mode expandedKeys + property along with onToggle properties are used for full control over the state. If you need to expand or collapse the state of nodes programmatically then controlled mode should be used. Example below demonstrates + both cases; +

    - -{` + + {` import React, { Component } from 'react'; import { TreeTable } from 'primereact/treetable'; import { Column } from 'primereact/column'; @@ -1040,20 +1044,23 @@ export class TreeTableDemo = () => { ) } `} - +
    Table Layout
    -

    Default table-layout is fixed meaning the cell widths do not depend on their content. If you require cells to scale based on their contents - set autoLayout property to true. Note that auto layout cannot be supported in Scrollable or Resizable columns. +

    + Default table-layout is fixed meaning the cell widths do not depend on their content. If you require cells to scale based on their contents set autoLayout property to true. Note that auto layout cannot be supported in + Scrollable or Resizable columns.

    Templates
    -

    Field data of a corresponding row is displayed as the cell content by default, this can be customized using templating where current row data and column properties are passed to the body template. - On the other hand, header and footer properties of a column are used to define the content of these sections by accepting either simple string values or JSX for advanced content. Similarly TreeTable itself - also provides header and footer properties for the main header and footer of the table.

    +

    + Field data of a corresponding row is displayed as the cell content by default, this can be customized using templating where current row data and column properties are passed to the body template. On the other hand,{' '} + header and footer properties of a column are used to define the content of these sections by accepting either simple string values or JSX for advanced content. Similarly TreeTable itself also provides{' '} + header and footer properties for the main header and footer of the table. +

    - -{` + + {` import React, { Component } from 'react'; import { TreeTable } from 'primereact/treetable'; import { Column } from 'primereact/column'; @@ -1091,13 +1098,15 @@ export const TreeTableTemplatingDemo = () => { } } `} - +
    Column Group
    -

    Columns can be grouped at header and footer sections by defining a ColumnGroup component as the headerColumnGroup and footerColumnGroup properties.

    +

    + Columns can be grouped at header and footer sections by defining a ColumnGroup component as the headerColumnGroup and footerColumnGroup properties. +

    - -{` + + {` import React, { Component } from 'react'; import { TreeTable } from 'primereact/treetable'; import { Column } from 'primereact/column'; @@ -1308,16 +1317,20 @@ export const TreeTableColGroupDemo = () => { ) } `} - +
    Pagination
    -

    Pagination is enabled by setting paginator property to true, rows property defines the number of rows per page and optionally pageLinks specify the the number of page links to display. - See paginator component for more information about further customization options such as paginatorTemplate.

    +

    + Pagination is enabled by setting paginator property to true, rows property defines the number of rows per page and optionally pageLinks specify the the number of page links to display. See{' '} + paginator component for more information about further customization options such as paginatorTemplate. +

    -

    Pagination can either be used in Controlled or Uncontrolled manner. In controlled mode, first and onPage properties need to be defined to control the paginator state.

    +

    + Pagination can either be used in Controlled or Uncontrolled manner. In controlled mode, first and onPage properties need to be defined to control the paginator state. +

    - -{` + + {` import React, { Component } from 'react'; import { TreeTable } from 'primereact/treetable'; import { Column } from 'primereact/column'; @@ -1341,13 +1354,15 @@ export const TreeTablePageDemo = () => { ) } `} - + -

    In uncontrolled mode, only paginator and rows need to be enabled. Index of the first record can be still be provided using the first property in uncontrolled mode however - it is evaluated at initial rendering and ignored in further updates. If you programmatically need to update the paginator state, prefer to use the component as controlled.

    +

    + In uncontrolled mode, only paginator and rows need to be enabled. Index of the first record can be still be provided using the first property in uncontrolled mode however it is evaluated at initial + rendering and ignored in further updates. If you programmatically need to update the paginator state, prefer to use the component as controlled. +

    - -{` + + {` import React, { Component } from 'react'; import { TreeTable } from 'primereact/treetable'; import { Column } from 'primereact/column'; @@ -1370,11 +1385,13 @@ export const TreeTablePageDemo = () => { } `} - + -

    Elements of the paginator can be customized using the paginatorTemplate by the TreeTable. Refer to the template section of the paginator documentation for further options.

    - -{` +

    + Elements of the paginator can be customized using the paginatorTemplate by the TreeTable. Refer to the template section of the paginator documentation for further options. +

    + + {` @@ -1382,106 +1399,117 @@ export const TreeTablePageDemo = () => { `} - +
    Sorting
    -

    Enabling sortable property at column component would be enough to make a column sortable. The property to use when sorting is field by default and can be customized using sortField.

    +

    + Enabling sortable property at column component would be enough to make a column sortable. The property to use when sorting is field by default and can be customized using sortField. +

    - -{` + + {` `} - + -

    By default sorting is executed on the clicked column only. To enable multiple field sorting, set sortMode property to "multiple" and use metakey when clicking on another column.

    - -{` +

    + By default sorting is executed on the clicked column only. To enable multiple field sorting, set sortMode property to "multiple" and use metakey when clicking on another column. +

    + + {` `} - +
    -

    In case you'd like to display the table as sorted per a single column by default on mount, use sortField and sortOrder properties in Controlled or Uncontrolled manner. - In controlled mode, sortField, sortOrder and onSort properties need to be defined to control the sorting state.

    +

    + In case you'd like to display the table as sorted per a single column by default on mount, use sortField and sortOrder properties in Controlled or Uncontrolled manner. In controlled mode,{' '} + sortField, sortOrder and onSort properties need to be defined to control the sorting state. +

    - -{` + + {` {setSortField(e.sortField); setSortOrder(e.sortOrder}}> `} - + -

    In multiple mode, use the multiSortMeta property and bind an array of SortMeta objects instead.

    - -{` +

    + In multiple mode, use the multiSortMeta property and bind an array of SortMeta objects instead. +

    + + {` setMultiSortMeta(e.multiSortMeta)}> `} - +
    - -{` + + {` let multiSortMeta = []; multiSortMeta.push({field: 'year', order: 1}); multiSortMeta.push({field: 'brand', order: -1}); `} - + -

    In uncontrolled mode, no additional properties need to be enabled. Initial sort field can be still be provided using the sortField property in uncontrolled mode however - it is evaluated at initial rendering and ignored in further updates. If you programmatically need to update the sorting state, prefer to use the component as controlled.

    - -{` +

    + In uncontrolled mode, no additional properties need to be enabled. Initial sort field can be still be provided using the sortField property in uncontrolled mode however it is evaluated at initial rendering and ignored + in further updates. If you programmatically need to update the sorting state, prefer to use the component as controlled. +

    + + {` `} - +

    To customize sorting algorithm, set sortable option to custom and define a sortFunction that sorts the list.

    - -{` + + {` `} - + - -{` + + {` mysort(event) { //event.field = Field to sort //event.order = Sort order } `} - +
    Filtering
    -

    Filtering is enabled by setting the filter property on a column. filterMode specifies the filtering strategy. In lenient mode when the query matches a node, children of the node are not searched further as all descendants of the node are included. On the other hand, - in strict mode when the query matches a node, filtering continues on all descendants.

    +

    + Filtering is enabled by setting the filter property on a column. filterMode specifies the filtering strategy. In lenient mode when the query matches a node, children of the node are not searched further as + all descendants of the node are included. On the other hand, in strict mode when the query matches a node, filtering continues on all descendants. +

    - -{` + + {` `} - + -

    An optional global filter feature is available to search all fields with the same keyword, - to implement this place an input component whose value is bound to the globalFilter property of the TreeTable.

    - -{` +

    An optional global filter feature is available to search all fields with the same keyword, to implement this place an input component whose value is bound to the globalFilter property of the TreeTable.

    + + {` export const TreeTableFilterDemo = () => { const [nodes, setNodes] = useState{[]}; @@ -1506,13 +1534,15 @@ export const TreeTableFilterDemo = () => { ) } `} - +
    -

    In case you'd like to display the table as filtered by default on mount, use filters property in Controlled or Uncontrolled manner. - In controlled mode, filters and onFilter properties need to be defined to control the filtering state.

    +

    + In case you'd like to display the table as filtered by default on mount, use filters property in Controlled or Uncontrolled manner. In controlled mode, filters and onFilter properties need to + be defined to control the filtering state. +

    - -{` + + {` export const TreeTableDefaultFilteredDemo = () => { const [nodes, setNodes] = useState([]); @@ -1538,13 +1568,17 @@ export const TreeTableDefaultFilteredDemo = () => { } } `} - -

    In uncontrolled filtering, no additional properties need to be enabled. Initial filtering can be still be provided using the filters property in uncontrolled mode however - it is evaluated at initial rendering and ignored in further updates. If you programmatically need to update the filtering state, prefer to use the component as controlled.

    +
    +

    + In uncontrolled filtering, no additional properties need to be enabled. Initial filtering can be still be provided using the filters property in uncontrolled mode however it is evaluated at initial rendering and ignored + in further updates. If you programmatically need to update the filtering state, prefer to use the component as controlled. +

    -

    Custom filtering is implemented by setting the filterMatchMode property as "custom" and providing a function that takes the data value along with the filter value to return a boolean.

    - -{` +

    + Custom filtering is implemented by setting the filterMatchMode property as "custom" and providing a function that takes the data value along with the filter value to return a boolean. +

    + + {` export const TreeTableFilterDemo = () => { const [nodes, setNodes] = useState([]); @@ -1569,18 +1603,19 @@ export const TreeTableFilterDemo = () => { } } `} - - +
    Selection
    -

    TreeTable supports single, multiple and checkbox selection modes. Define selectionMode, selectionKeys and onSelectionChange properties to control the selection. In single mode, selectionKeys should - be a single value whereas in multiple or checkbox modes an array is required. By default in multiple selection mode, metaKey is necessary to add to existing selections however this can be configured with metaKeySelection property. Note that - in touch enabled devices, TreeTable does not require metaKey.

    +

    + TreeTable supports single, multiple and checkbox selection modes. Define selectionMode, selectionKeys and onSelectionChange properties to control the selection. In single mode, selectionKeys should be a + single value whereas in multiple or checkbox modes an array is required. By default in multiple selection mode, metaKey is necessary to add to existing selections however this can be configured with metaKeySelection{' '} + property. Note that in touch enabled devices, TreeTable does not require metaKey. +

    Example below demonstrates all cases along with the available callbacks to listen events such as node selection.

    - -{` + + {` import React, { Component } from 'react'; import { TreeTable } from 'primereact/treetable'; import { Column } from 'primereact/column'; @@ -1662,14 +1697,16 @@ export const TreeTableSelectionDemo = () => { ) } `} - +
    Lazy
    -

    Lazy loading is implemented using the onExpand event by adding children to the expanded node. leaf property should be enabled to indicate the node has children but not yet loaded. Here is a in-memory demo - that loads generated nodes on expand event to imitate a remote call with a timeout. Notice the usage of loading property as well to give users a feedback about the loading process.

    +

    + Lazy loading is implemented using the onExpand event by adding children to the expanded node. leaf property should be enabled to indicate the node has children but not yet loaded. Here is a in-memory demo that + loads generated nodes on expand event to imitate a remote call with a timeout. Notice the usage of loading property as well to give users a feedback about the loading process. +

    - -{` + + {` import React, { Component } from 'react'; import { TreeTable } from 'primereact/treetable'; import { Column } from 'primereact/column'; @@ -1766,15 +1803,17 @@ export const TreeTableLazyDemo = () => { ) } `} - +
    Incell Editing
    -

    Incell editing feature provides a way to quickly edit data inside the table. A cell editor is defined using the editor property - that refers to a function to return an input element for the editing. Clicking outside the cell or hitting enter key closes the cell, however this may not be desirable if the input is invalid. In order - to decide whether to keep the cell open or not, provide a cellEditValidator function that validates the value.

    +

    + Incell editing feature provides a way to quickly edit data inside the table. A cell editor is defined using the editor property that refers to a function to return an input element for the editing. Clicking outside the + cell or hitting enter key closes the cell, however this may not be desirable if the input is invalid. In order to decide whether to keep the cell open or not, provide a cellEditValidator function that validates the + value. +

    - -{` + + {` import React, { Component } from 'react'; import { TreeTable } from 'primereact/treetable'; import { Column } from 'primereact/column'; @@ -1842,14 +1881,16 @@ export const TreeTableEditDemo = () => { ) } `} - +
    ContextMenu
    -

    One or more ContextMenu instances can be attached to nodes. Similar to selection, separate contextMenuSelectionKey and onContextMenuSelectionChange properties are necesary to manage the selected node with - right click. In addition, a context menu can either be displayed at onContextMenu event. Since this event also passes the node instance, you may choose to display a different context menu for a particular node.

    +

    + One or more ContextMenu instances can be attached to nodes. Similar to selection, separate contextMenuSelectionKey and onContextMenuSelectionChange properties are necesary to manage the selected node with right + click. In addition, a context menu can either be displayed at onContextMenu event. Since this event also passes the node instance, you may choose to display a different context menu for a particular node. +

    - -{` + + {` import React, { Component } from 'react'; import { TreeTable } from 'primereact/treetable'; import { Column } from 'primereact/column'; @@ -1909,13 +1950,15 @@ export const TreeTableContextMenuDemo = () => { ) } `} - +
    Column Resize
    -

    Columns can be resized using drag drop by setting the resizableColumns to true. There are two resize modes; "fit" and "expand". Fit is the default one and the overall table width does not change when a column is resized. - In "expand" mode, table width also changes along with the column width. onColumnResizeEnd is a callback that passes the resized column header as a parameter.

    - -{` +

    + Columns can be resized using drag drop by setting the resizableColumns to true. There are two resize modes; "fit" and "expand". Fit is the default one and the overall table width does not change when a column is + resized. In "expand" mode, table width also changes along with the column width. onColumnResizeEnd is a callback that passes the resized column header as a parameter. +

    + + {`
    Fit Mode
    @@ -1930,60 +1973,66 @@ export const TreeTableContextMenuDemo = () => { `} -
    +

    It is important to note that when you need to change column widths, since table width is 100%, giving fixed pixel widths does not work well as browsers scale them, instead give percentage widths.

    - -{` + + {` `} - +
    Column Reorder
    -

    Columns can be reordered using drag drop by setting the reorderableColumns to true. onColReorder is a callback that is invoked when a column is reordered. - TreeTable keeps the column order state internally using keys that identifies a column using the field property. If the column has no field, use columnKey instead.

    +

    + Columns can be reordered using drag drop by setting the reorderableColumns to true. onColReorder is a callback that is invoked when a column is reordered. TreeTable keeps the column order state internally using + keys that identifies a column using the field property. If the column has no field, use columnKey instead. +

    - -{` + + {` `} - +
    Scrolling
    -

    TreeTable supports both horizontal and vertical scrolling as well as frozen columns. Vertical scrolling is enabled using scrollable property and scrollHeight to define the viewport height.

    - -{` +

    + TreeTable supports both horizontal and vertical scrolling as well as frozen columns. Vertical scrolling is enabled using scrollable property and scrollHeight to define the viewport height. +

    + + {` `} - +

    Horizontal Scrolling requires a width of DataTable to be defined and explicit widths on columns.

    - -{` + + {` `} - + -

    Certain columns can be frozen by using the frozen property of the column component. Widths of the frozen section is specified by the frozenWidth property.

    +

    + Certain columns can be frozen by using the frozen property of the column component. Widths of the frozen section is specified by the frozenWidth property. +

    - -{` + + {` @@ -1994,27 +2043,29 @@ export const TreeTableContextMenuDemo = () => { `} - +

    Note that frozen columns are enabled, frozen and scrollable cells may have content with varying height which leads to misalignment. Provide fixed height to cells to avoid alignment issues.

    - -{` + + {` `} - + -

    When using frozen columns with column grouping, use frozenHeaderColumnGroup and frozenFooterColumnGroup properties along with - headerColumnGroup and footerColumnGroup.

    +

    + When using frozen columns with column grouping, use frozenHeaderColumnGroup and frozenFooterColumnGroup properties along with + headerColumnGroup and footerColumnGroup. +

    Responsive

    TreeTable columns are displayed as stacked in responsive mode if the screen size becomes smaller than a certain breakpoint value. Here is a sample implementation;

    - -{` + + {` .p-col-d { display: table-cell; } @@ -2033,10 +2084,10 @@ export const TreeTableContextMenuDemo = () => { } } `} - + - -{` + + {` import React, { Component } from 'react'; import { TreeTable } from 'primereact/treetable'; import { Column } from 'primereact/column'; @@ -2072,12 +2123,12 @@ export const TreeTableResponsiveDemo = () => { } `} - +
    Properties

    Any valid attribute is passed to the root element implicitly, extended properties are as follows;

    -
    -
    Name
    +
    +
    @@ -2169,7 +2220,9 @@ export const TreeTableResponsiveDemo = () => { - + @@ -2199,15 +2252,18 @@ export const TreeTableResponsiveDemo = () => { - + - + @@ -2291,8 +2347,10 @@ export const TreeTableResponsiveDemo = () => { - + @@ -2449,8 +2507,8 @@ export const TreeTableResponsiveDemo = () => {
    Events
    -
    -
    NamepaginatorTemplate string|object FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdownTemplate of the paginator. For details, refer to the template section of the paginator documentation for further options. + Template of the paginator. For details, refer to the template section of the paginator documentation for further options. +
    paginatorLeftcurrentPageReportTemplate string ({`{currentPage} of {totalPages}`})Template of the current page report element. Available placeholders are - {` {currentPage}, {totalPages}, {rows}, {first}, {last} and {totalRecords}`} - + Template of the current page report element. Available placeholders are + {` {currentPage}, {totalPages}, {rows}, {first}, {last} and {totalRecords}`} +
    paginatorDropdownAppendTo DOM element | string document.bodyDOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. + DOM element instance where the overlay panel should be mounted. Valid values are any DOM Element and 'self'. The self value is used to render a component where it is located. +
    firstmetaKeySelection boolean trueDefines whether metaKey is requred or not for the selection. When true metaKey needs to be pressed to select or unselect an item and when set to false selection of each item - can be toggled individually. On touch enabled devices, metaKeySelection is turned off automatically. + Defines whether metaKey is requred or not for the selection. When true metaKey needs to be pressed to select or unselect an item and when set to false selection of each item can be toggled individually. On + touch enabled devices, metaKeySelection is turned off automatically. +
    selectOnEdit
    +
    +
    @@ -2461,33 +2519,43 @@ export const TreeTableResponsiveDemo = () => { - + - + - + - + - + event.multiSortMeta: MultiSort metadata. + @@ -2497,53 +2565,69 @@ export const TreeTableResponsiveDemo = () => { - + - + - + - + - + - + - + event.columns: Columns array after reorder. + - + @@ -2551,9 +2635,11 @@ export const TreeTableResponsiveDemo = () => {
    Styling
    -

    Following is the list of structural style classes, for theming classes visit theming page.

    -
    -
    Name
    onExpandevent.originalEvent: browser event
    - event.node: Expanded node instance.
    + event.originalEvent: browser event
    + event.node: Expanded node instance. +
    Callback to invoke when a node is expanded.
    onCollapseevent.originalEvent: browser event
    - event.node: Collapsed node instance.
    + event.originalEvent: browser event
    + event.node: Collapsed node instance. +
    Callback to invoke when a node is collapsed.
    onToggleevent.originalEvent: browser event
    - event.node: Toggled node instance.
    + event.originalEvent: browser event
    + event.node: Toggled node instance. +
    Callback to invoke when a node is toggled.
    onPageevent.first: Index of the first row.
    - event.rows: Rows per page.
    + event.first: Index of the first row.
    + event.rows: Rows per page. +
    Callback to invoke on pagination.
    onSortevent.sortField: Field to sort against.
    +
    + event.sortField: Field to sort against.
    event.sortOrder: Sort order as integer.
    - event.multiSortMeta: MultiSort metadata.
    Callback to invoke on sort.
    onSelectevent.originalEvent: browser event
    - event.node: Selected node instance.
    + event.originalEvent: browser event
    + event.node: Selected node instance. +
    Callback to invoke when a node is selected.
    onUnselectevent.originalEvent: browser event
    - event.node: Unselected node instance.
    + event.originalEvent: browser event
    + event.node: Unselected node instance. +
    Callback to invoke when a node is unselected.
    onRowClickevent.originalEvent: Browser event
    - event.data: Clicked row data
    + event.originalEvent: Browser event
    + event.data: Clicked row data +
    Callback to invoke when a row is clicked.
    onSelectionChangeevent.originalEvent: browser event
    - event.value: Selected node key(s).
    + event.originalEvent: browser event
    + event.value: Selected node key(s). +
    Callback to invoke when selection changes.
    onContextMenuSelectionChangeevent.originalEvent: browser event
    - event.value: Selected node key.
    + event.originalEvent: browser event
    + event.value: Selected node key. +
    Callback to invoke when selection changes with a context menu.
    onColumnResizeEndevent.element: DOM element of the resized column. - event.column: Properties of the resized column.
    - event.delta: Change in column width
    + event.element: DOM element of the resized column. event.column: Properties of the resized column. +
    + event.delta: Change in column width +
    Callback to invoke when a column is resized.
    onColReorderevent.originalEvent: Browser event
    +
    + event.originalEvent: Browser event
    event.dragIndex: Index of the dragged column
    event.dropIndex: Index of the dropped column
    - event.columns: Columns array after reorder.
    Callback to invoke when a column is reordered.
    onContextMenuevent.originalEvent: Original event instance.
    - event.data: Collapsed row data
    + event.originalEvent: Original event instance.
    + event.data: Collapsed row data +
    Callback to invoke when a context menu is clicked.
    +

    + Following is the list of structural style classes, for theming classes visit theming page. +

    +
    +
    @@ -2608,21 +2694,29 @@ export const TreeTableResponsiveDemo = () => {
    Accessibility
    Screen Reader
    -

    DataTable uses a treegrid element whose attributes can be extended with the tableProps option. This property allows passing aria roles and attributes like aria-label and aria-describedby to define the table for readers. Default - role of the table is table. Header, body and footer elements use rowgroup, rows use row role, header cells have columnheader and body cells use cell roles. Sortable headers utilizer aria-sort attribute - either set to "ascending" or "descending".

    +

    + DataTable uses a treegrid element whose attributes can be extended with the tableProps option. This property allows passing aria roles and attributes like aria-label and aria-describedby to + define the table for readers. Default role of the table is table. Header, body and footer elements use rowgroup, rows use row role, header cells have columnheader and body cells use cell{' '} + roles. Sortable headers utilizer aria-sort attribute either set to "ascending" or "descending". +

    -

    Row elements manage aria-expanded for state along with aria-posinset, aria-setsize and aria-level attribute to define the hierachy.

    +

    + Row elements manage aria-expanded for state along with aria-posinset, aria-setsize and aria-level attribute to define the hierachy. +

    -

    When selection is enabled, aria-selected is set to true on a row. In checkbox mode, the built-in checkbox component use checkbox role with aria-checked state attribute.

    +

    + When selection is enabled, aria-selected is set to true on a row. In checkbox mode, the built-in checkbox component use checkbox role with aria-checked state attribute. +

    Editable cells use custom templating so you need to manage aria roles and attributes manually if required.

    -

    Paginator is a standalone component used inside the DataTable, refer to the paginator for more information about the accessibility features.

    - +

    + Paginator is a standalone component used inside the DataTable, refer to the paginator for more information about the accessibility features. +

    +
    Sortable Headers Keyboard Support
    -
    -
    Name
    +
    +
    @@ -2631,15 +2725,21 @@ export const TreeTableResponsiveDemo = () => { - + - + - + @@ -2647,8 +2747,8 @@ export const TreeTableResponsiveDemo = () => {
    Keyboard Support
    -
    -
    Key
    tab + tab + Moves through the headers.
    enter + enter + Sorts the column.
    space + space + Sorts the column.
    +
    +
    @@ -2657,39 +2757,57 @@ export const TreeTableResponsiveDemo = () => { - - + - - + - + - + - + - + - + - + @@ -2699,15 +2817,12 @@ export const TreeTableResponsiveDemo = () => {
    Dependencies

    None.

    - - { - useLiveEditorTabs({ name: 'TreeTableDemo', sources: sources, service: 'NodeService', data: 'treetablenodes' }) - } + {useLiveEditorTabs({ name: 'TreeTableDemo', sources: sources, service: 'NodeService', data: 'treetablenodes' })} ); -}) +}); export default TreeTableDoc; diff --git a/components/doc/tristatecheckbox/index.js b/components/doc/tristatecheckbox/index.js index 0157bfad72..4d20dd8df5 100644 --- a/components/doc/tristatecheckbox/index.js +++ b/components/doc/tristatecheckbox/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const TriStateCheckboxDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -39,7 +38,7 @@ export class TriStateCheckboxDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useState } from 'react'; @@ -61,7 +60,7 @@ const TriStateCheckboxDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useState } from 'react'; @@ -83,7 +82,7 @@ const TriStateCheckboxDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -108,39 +107,41 @@ const TriStateCheckboxDemo = () => { } ` } - } + }; - return ( -
    - - -
    Import via Module
    - -{` + return ( +
    + + +
    Import via Module
    + + {` import { TriStateCheckbox } from 'primereact/tristatecheckbox'; `} - + -
    Import via CDN
    - -{` +
    Import via CDN
    + + {` `} - +
    -
    Getting Started
    -

    TriStateCheckbox is used as a controlled input with checked and onChange properties.

    - -{` +
    Getting Started
    +

    + TriStateCheckbox is used as a controlled input with checked and onChange properties. +

    + + {` setValue(e.value)} /> `} - +
    Properties

    Any valid attribute is passed to the root element implicitly, extended properties are as follows;

    -
    -
    Key
    tabMoves focus to the first selected node when focus enters the component, if there is none then first element receives the focus. If focus is already inside the component, moves focus to the next - focusable element in the page tab sequence. + + tab + + Moves focus to the first selected node when focus enters the component, if there is none then first element receives the focus. If focus is already inside the component, moves focus to the next focusable + element in the page tab sequence.
    shift + tabMoves focus to the last selected node when focus enters the component, if there is none then first element receives the focus. If focus is already inside the component, moves focus to the previous - focusable element in the page tab sequence. + + shift + tab + + Moves focus to the last selected node when focus enters the component, if there is none then first element receives the focus. If focus is already inside the component, moves focus to the previous focusable + element in the page tab sequence.
    enter + enter + Selects the focused treenode.
    space + space + Selects the focused treenode.
    down arrow + down arrow + Moves focus to the next treenode.
    up arrow + up arrow + Moves focus to the previous treenode.
    right arrow + right arrow + If node is closed, opens the node otherwise moves focus to the first child node.
    left arrow + left arrow + If node is open, closes the node otherwise moves focus to the parent node.
    +
    +
    @@ -209,8 +210,8 @@ import { TriStateCheckbox } from 'primereact/tristatecheckbox';
    Events
    -
    -
    Name
    +
    +
    @@ -221,7 +222,8 @@ import { TriStateCheckbox } from 'primereact/tristatecheckbox'; - @@ -231,9 +233,11 @@ import { TriStateCheckbox } from 'primereact/tristatecheckbox';
    Styling
    -

    Following is the list of structural style classes, for theming classes visit theming page.

    -
    -
    Name
    onChangeevent.originalEvent: Browser event
    +
    + event.originalEvent: Browser event
    event.value: Current Value
    Callback to invoke on value change
    +

    + Following is the list of structural style classes, for theming classes visit theming page. +

    +
    +
    @@ -262,55 +266,61 @@ import { TriStateCheckbox } from 'primereact/tristatecheckbox';
    Accessibility
    - -
    Screen Reader
    -

    TriStateCheckbox component uses an element with checkbox role. Value to describe the component can either be provided with aria-labelledby or aria-label props. Component adds an element with - aria-live attribute that is only visible to screen readers to read the value displayed. Values to read are defined with the trueLabel, falseLabel and nullLabel keys of the aria - property from the locale API. This is an example of a custom accessibility implementation as there is no one to one mapping between the component design and the WCAG specification.

    - -{` + +
    Screen Reader
    +

    + TriStateCheckbox component uses an element with checkbox role. Value to describe the component can either be provided with aria-labelledby or aria-label props. Component adds an element with + aria-live attribute that is only visible to screen readers to read the value displayed. Values to read are defined with the trueLabel, falseLabel and nullLabel keys of the aria + property from the locale API. This is an example of a custom accessibility implementation as there is no one to one mapping between the component design and the WCAG specification. +

    + + {` Remember Me `} - -
    Keyboard Support
    -
    -
    Name
    - - - - - - - - - - - - - - - - - - - - -
    KeyFunction
    tabMoves focus to the checkbox.
    spaceToggles between the values.
    enterToggles between the values.
    -
    - + +
    Keyboard Support
    +
    + + + + + + + + + + + + + + + + + + + + + +
    KeyFunction
    + tab + Moves focus to the checkbox.
    + space + Toggles between the values.
    + enter + Toggles between the values.
    +
    +
    Dependencies

    None.

    - { - useLiveEditorTabs({ name: 'TriStateCheckboxDemo', sources: sources }) - } + {useLiveEditorTabs({ name: 'TriStateCheckboxDemo', sources: sources })}
    - ) -}) + ); +}); export default TriStateCheckboxDoc; diff --git a/components/doc/virtualscroller/index.js b/components/doc/virtualscroller/index.js index a8fd26b13d..163dd8ebc4 100644 --- a/components/doc/virtualscroller/index.js +++ b/components/doc/virtualscroller/index.js @@ -6,9 +6,8 @@ import { CodeHighlight } from '../common/codehighlight'; import { DevelopmentSection } from '../common/developmentsection'; const VirtualScrollerDoc = memo(() => { - const sources = { - 'class': { + class: { tabName: 'Class Source', content: ` import React, { Component } from 'react'; @@ -211,7 +210,7 @@ export class VirtualScrollerDemo extends Component { } ` }, - 'hooks': { + hooks: { tabName: 'Hooks Source', content: ` import React, { useEffect, useState, useRef } from 'react'; @@ -395,7 +394,7 @@ const VirtualScrollerDemo = () => { } ` }, - 'ts': { + ts: { tabName: 'TS Source', content: ` import React, { useEffect, useState, useRef } from 'react'; @@ -579,7 +578,7 @@ const VirtualScrollerDemo = () => { } ` }, - 'browser': { + browser: { tabName: 'Browser Source', imports: ` @@ -769,7 +768,7 @@ const VirtualScrollerDemo = () => { } ` } - } + }; const extFiles = { 'demo/VirtualScrollerDemo.css': { @@ -804,39 +803,43 @@ const VirtualScrollerDemo = () => { } ` } - } + }; return ( -
    +
    - +
    Import via Module
    - -{` + + {` import { VirtualScroller } from 'primereact/virtualscroller'; `} - +
    Import via CDN
    - -{` + + {` `} - +
    Getting Started
    -

    VirtualScroller is used to display huge data. It periodically adds special elements defined according to the scroll's position to the DOM. - The itemSize and itemTemplate properties are required on component. In addition, an initial array is required based on the total number of items to display.
    - VirtualScroller automatically calculates how many items will be displayed in the view according to itemSize using a specified scroll height. Its scroll height can be adjusted with scrollHeight property or height property of CSS.

    - -{` +

    + VirtualScroller is used to display huge data. It periodically adds special elements defined according to the scroll's position to the DOM. The itemSize and itemTemplate properties are required on component. In + addition, an initial array is required based on the total number of items to display. +
    + VirtualScroller automatically calculates how many items will be displayed in the view according to itemSize using a specified scroll height. Its scroll height can be adjusted with scrollHeight property or height + property of CSS. +

    + + {` `} - +
    - -{` + + {` const items = Array.from({ length: 100000 }).map((_, i) => \`Item #\${i}\`); const itemTemplate = (item, options) => { @@ -852,21 +855,22 @@ const itemTemplate = (item, options) => { return
    {item}
    ; } `} -
    +
    Loader
    -

    VirtualScroller has a special loader. It can be activated with the showLoader property. - In addition, loadingTemplate can be used to add custom loaders to item elements.

    - -{` +

    + VirtualScroller has a special loader. It can be activated with the showLoader property. In addition, loadingTemplate can be used to add custom loaders to item elements. +

    + + {` `} - +
    - -{` + + {` const loadingTemplate = (options) => { // options.index: Index of the item. // options.count: Total numbers of items. @@ -884,20 +888,22 @@ const loadingTemplate = (options) => { ); } `} - +
    Lazy
    -

    Lazy mode is handy to deal with large datasets, instead of loading the entire data, small chunks of data is loaded by invoking onLazyLoad callback.

    +

    + Lazy mode is handy to deal with large datasets, instead of loading the entire data, small chunks of data is loaded by invoking onLazyLoad callback. +

    - -{` + + {` `} - + - -{` + + {` const onLazyLoad = (event) => { setLazyLoading(true); @@ -919,19 +925,21 @@ const onLazyLoad = (event) => { }, Math.random() * 1000 + 250); } `} - +
    Content Template
    -

    VirtualScroller has a HTML div element to wrap the all items. But in some cases, it may be desirable to define a completely special wrapper element instead of the HTML div element. The contentTemplate property can be used for this. - This will be especially necessary to maintain the DOM layout and provide accessibility.

    - -{` +

    + VirtualScroller has a HTML div element to wrap the all items. But in some cases, it may be desirable to define a completely special wrapper element instead of the HTML div element. The contentTemplate property can be + used for this. This will be especially necessary to maintain the DOM layout and provide accessibility. +

    + + {` `} - +
    - -{` + + {` const contentTemplate = (options) => { // options.className: Class name of wrapper element. // options.contentRef: Ref of wrapper element. @@ -961,10 +969,10 @@ const itemTemplate = (item, options) => { return
  • {item}
  • } `} -
    +
    Properties
    -
    - +
    +
    @@ -1026,9 +1034,11 @@ const itemTemplate = (item, options) => { - + Default value is half the number of items shown in the view. + @@ -1113,8 +1123,8 @@ const itemTemplate = (item, options) => {
    Events
    -
    -
    NamenumToleratedItems number nullDetermines how many additional elements to add to the DOM outside of the view.
    +
    + Determines how many additional elements to add to the DOM outside of the view.
    According to the scrolls made up and down, extra items are added in a certain algorithm in the form of multiples of this number.
    - Default value is half the number of items shown in the view.
    delay
    +
    +
    @@ -1130,14 +1140,18 @@ const itemTemplate = (item, options) => { - - @@ -1147,8 +1161,8 @@ const itemTemplate = (item, options) => {
    Methods
    -
    -
    Name
    onScrollIndexChangeevent.first: First index of the new data range to be loaded.
    +
    + event.first: First index of the new data range to be loaded. +
    event.last: Last index of the new data range to be loaded.
    Callback to invoke when scroll position and item's range in view changes.
    onLazyLoadevent.first: First index of the new data range to be loaded.
    +
    + event.first: First index of the new data range to be loaded. +
    event.last: Last index of the new data range to be loaded.
    Callback to invoke in lazy mode to load new data.
    +
    +
    @@ -1198,9 +1212,11 @@ const itemTemplate = (item, options) => {
    Styling
    -

    Following is the list of structural style classes, for theming classes visit theming page.

    -
    -
    Name
    +

    + Following is the list of structural style classes, for theming classes visit theming page. +

    +
    +
    @@ -1226,26 +1242,24 @@ const itemTemplate = (item, options) => {
    Accessibility
    -
    Screen Reader
    -

    VirtualScroller uses a semantic list element to list the items. No specific role is enforced, still you may use any aria role and attributes - as any valid attribute is passed to the container element. List element can be also customized for accessibility using listProps property. -

    - -
    Keyboard Support
    -

    Component does not include any built-in interactive elements.

    +
    Screen Reader
    +

    + VirtualScroller uses a semantic list element to list the items. No specific role is enforced, still you may use any aria role and attributes as any valid attribute is passed to the container element. List element can be + also customized for accessibility using listProps property. +

    + +
    Keyboard Support
    +

    Component does not include any built-in interactive elements.

    Dependencies

    None.

    - - { - useLiveEditorTabs({ name: 'VirtualScrollerDemo', sources: sources, extFiles: extFiles }) - } + {useLiveEditorTabs({ name: 'VirtualScrollerDemo', sources: sources, extFiles: extFiles })} - ) -}) + ); +}); export default VirtualScrollerDoc; diff --git a/components/layout/analytics.js b/components/layout/analytics.js index 322c38b959..ee9e1c55a4 100644 --- a/components/layout/analytics.js +++ b/components/layout/analytics.js @@ -15,12 +15,12 @@ export default function Analytics() { return () => { router.events.off('routeChangeComplete', handleRouteChange); }; - }, [router.events]); + }, [router.events]); return ( <> - {/* eslint-enable */} @@ -87,23 +85,24 @@ export default function Layout(props) { {props.newsActive && } - -
    -
    + }} + > +
    +
    {props.children}
    - +
    - ) + ); } diff --git a/components/layout/menu.js b/components/layout/menu.js index e5f3127738..94caa9479f 100644 --- a/components/layout/menu.js +++ b/components/layout/menu.js @@ -2,9 +2,9 @@ import Link from 'next/link'; import { classNames } from '../lib/utils/ClassNames'; import { CSSTransition } from 'react-transition-group'; import React, { useRef, useState } from 'react'; -import { useRouter } from 'next/router' +import { useRouter } from 'next/router'; import { InputText } from '../lib/inputtext/InputText'; -import MenuData from "./menu.json"; +import MenuData from './menu.json'; import getConfig from 'next/config'; export default function Menu(props) { @@ -17,7 +17,7 @@ export default function Menu(props) { let _activeSubmenus = { ...activeSubmenus }; _activeSubmenus[name] = _activeSubmenus[name] ? false : true; setActiveSubmenus(_activeSubmenus); - } + }; const isSubmenuActive = (name) => { if (activeSubmenus.hasOwnProperty(name)) { @@ -25,18 +25,16 @@ export default function Menu(props) { } return false; - } + }; const renderBadge = (item) => { const badge = item.badge; if (badge) { - return ( - {badge} - ); + return {badge}; } return null; - } + }; const renderLink = (item, linkProps) => { const { name, to, href } = item; @@ -49,103 +47,104 @@ export default function Menu(props) { ); if (href) - return {content} + return ( + + {content} + + ); else if (!to) - return + return ( + + ); return ( - {content} + + {content} + ); - } + }; const renderCategorySubmenuItems = (item, submenuKey) => { const cSubmenuRef = React.createRef(); return ( - -
    -
      - { - item.children.map((item, index) => { - const link = renderLink(item); - return ( -
    • - {link} -
    • - ); - }) - } + +
      +
        + {item.children.map((item, index) => { + const link = renderLink(item); + return ( +
      • + {link} +
      • + ); + })}
      ); - } + }; const renderCategoryItem = (menuitem, menuitemIndex) => { if (menuitem.children) { return ( <> - { - menuitem.children.map((item, index) => { - const submenuKey = `${menuitemIndex}_${index}`; - const link = renderLink(item, { onClick: () => toggleSubmenu(item.name) }); + {menuitem.children.map((item, index) => { + const submenuKey = `${menuitemIndex}_${index}`; + const link = renderLink(item, { onClick: () => toggleSubmenu(item.name) }); - return ( - - {link} - {item.children && renderCategorySubmenuItems(item, submenuKey)} - - ) - }) - } + return ( + + {link} + {item.children && renderCategorySubmenuItems(item, submenuKey)} + + ); + })} ); } return null; - } + }; const renderMenu = () => { return ( <> - { - filteredMenu.map((menuitem, index) => { - const categoryItem = renderCategoryItem(menuitem, index); - const badge = renderBadge(menuitem); - - return ( - -
      - {menuitem.name} - {badge} -
      - {menuitem.children &&
      - {categoryItem} -
      } - {menuitem.banner &&
      + {filteredMenu.map((menuitem, index) => { + const categoryItem = renderCategoryItem(menuitem, index); + const badge = renderBadge(menuitem); + + return ( + +
      + {menuitem.name} + {badge} +
      + {menuitem.children &&
      {categoryItem}
      } + {menuitem.banner && ( + } -
      - ) - }) - } +
      + )} +
      + ); + })} ); - } + }; const onSearchInputChange = (event) => { if (!MenuData.data) { setFilteredMenu([]); - } - else if (!event.target.value) { + } else if (!event.target.value) { setFilteredMenu(MenuData.data); - } - else if (MenuData.data) { + } else if (MenuData.data) { const searchVal = event.target.value && event.target.value.toLowerCase(); let _filteredMenu = []; for (let item of MenuData.data) { @@ -157,7 +156,7 @@ export default function Menu(props) { setFilteredMenu(_filteredMenu); } - } + }; const findFilteredItems = (item, searchVal) => { if (item) { @@ -179,7 +178,7 @@ export default function Menu(props) { return true; } } - } + }; const isFilterMatched = (item, searchVal) => { let matched = false; @@ -192,58 +191,57 @@ export default function Menu(props) { } return matched; - } + }; const onFilterOnOptions = (item, searchVal, optionKeys) => { if (item && optionKeys) { const isMatched = (val) => { if (searchVal.indexOf('&') < 0) { return val.toLowerCase().indexOf(searchVal) > -1; - } - else { - return searchVal.split('&').some(s => !!s && val.toLowerCase().indexOf(s) > -1); + } else { + return searchVal.split('&').some((s) => !!s && val.toLowerCase().indexOf(s) > -1); } }; - return optionKeys.some(optionKey => { + return optionKeys.some((optionKey) => { const value = item[optionKey]; - return value && (typeof value === 'string' ? isMatched(value) : value.filter(meta => isMatched(meta)).length > 0); + return value && (typeof value === 'string' ? isMatched(value) : value.filter((meta) => isMatched(meta)).length > 0); }); } return false; - } + }; const resetFilter = () => { setFilteredMenu(MenuData.data); searchInput.current.value = ''; searchInput.current.focus(); - } + }; const menuItems = renderMenu(); const showClearIcon = filteredMenu.length !== MenuData.data.length; - const sidebarClassName = classNames('layout-sidebar', { 'active': props.active }); + const sidebarClassName = classNames('layout-sidebar', { active: props.active }); const filterContentClassName = classNames('layout-sidebar-filter-content p-input-icon-left p-fluid', { 'p-input-icon-right': showClearIcon }); const searchInput = useRef(); return ( -
      - - - logo +
      + + + logo -
      +
      - - - {showClearIcon && } + + + {showClearIcon && }
      -
      +
      {menuItems}
      ); -} \ No newline at end of file +} diff --git a/components/layout/topbar.js b/components/layout/topbar.js index 4a317a644d..a377585ff2 100644 --- a/components/layout/topbar.js +++ b/components/layout/topbar.js @@ -6,81 +6,77 @@ import { VersionService } from '../../service/VersionService'; import getConfig from 'next/config'; export default function Topbar(props) { - const [activeMenuIndex,setActiveMenuIndex] = useState(null); - const [versions,setVersions] = useState([]); + const [activeMenuIndex, setActiveMenuIndex] = useState(null); + const [versions, setVersions] = useState([]); const onMenuButtonClick = () => { props.onMenuButtonClick(); - } + }; const resetMenuActive = () => { setActiveMenuIndex(null); - } + }; const toggleMenu = (index) => { - setActiveMenuIndex(prevActiveMenuIndex => prevActiveMenuIndex === index ? null : index); - } + setActiveMenuIndex((prevActiveMenuIndex) => (prevActiveMenuIndex === index ? null : index)); + }; const bindOutsideClickListener = () => { if (!outsideClickListener.current) { outsideClickListener.current = (event) => { - if ((activeMenuIndex != null && isOutsideTopbarMenuClicked(event))) { + if (activeMenuIndex != null && isOutsideTopbarMenuClicked(event)) { setActiveMenuIndex(null); } }; document.addEventListener('click', outsideClickListener.current); } - } + }; const unbindOutsideClickListener = () => { if (outsideClickListener.current) { document.removeEventListener('click', outsideClickListener.current); outsideClickListener.current = null; } - } + }; const isOutsideTopbarMenuClicked = (event) => { return !(topbarMenu.current.isSameNode(event.target) || topbarMenu.current.contains(event.target)); - } + }; const onThemeChange = (theme, dark) => { - props.onThemeChange({theme, dark}); + props.onThemeChange({ theme, dark }); resetMenuActive(); - } + }; useEffect(() => { - if (activeMenuIndex == null) - unbindOutsideClickListener(); - else - bindOutsideClickListener(); + if (activeMenuIndex == null) unbindOutsideClickListener(); + else bindOutsideClickListener(); return function unbind() { unbindOutsideClickListener(); - } + }; }, [activeMenuIndex]); // eslint-disable-line react-hooks/exhaustive-deps useEffect(() => { - versionService.getVersions().then(data => setVersions(data)); - },[]); // eslint-disable-line react-hooks/exhaustive-deps + versionService.getVersions().then((data) => setVersions(data)); + }, []); // eslint-disable-line react-hooks/exhaustive-deps const containerElement = useRef(null); const scrollListener = useRef(); const bindScrollListener = () => { scrollListener.current = () => { if (containerElement && containerElement.current) { - if (window.scrollY > 0) - containerElement.current.classList.add('layout-topbar-sticky'); - else - containerElement.current.classList.remove('layout-topbar-sticky'); + if (window.scrollY > 0) containerElement.current.classList.add('layout-topbar-sticky'); + else containerElement.current.classList.remove('layout-topbar-sticky'); } - } + }; window.addEventListener('scroll', scrollListener.current); - } + }; const unbindScrollListener = () => { if (scrollListener.current) { window.removeEventListener('scroll', scrollListener.current); scrollListener.current = null; } - } + }; useEffect(() => { bindScrollListener(); return function unbind() { unbindScrollListener(); - } + }; }, []); const topbarMenu = useRef(); @@ -122,204 +118,517 @@ export default function Topbar(props) { 'arya-green': 'arya-green.png', 'arya-orange': 'arya-orange.png', 'arya-purple': 'arya-purple.png', - 'nova': 'nova.png', + nova: 'nova.png', 'nova-alt': 'nova-alt.png', 'nova-accent': 'nova-accent.png', 'luna-blue': 'luna-blue.png', 'luna-green': 'luna-green.png', 'luna-pink': 'luna-pink.png', 'luna-amber': 'luna-amber.png', - 'rhea': 'rhea.png', + rhea: 'rhea.png', 'fluent-light': 'fluent-light.png', 'soho-light': 'soho-light.png', 'soho-dark': 'soho-dark.png', 'viva-light': 'viva-light.svg', 'viva-dark': 'viva-dark.svg', - 'mira': 'mira.jpg', - 'nano': 'nano.jpg', + mira: 'mira.jpg', + nano: 'nano.jpg', 'tailwind-light': 'tailwind-light.png' }; const contextPath = getConfig().publicRuntimeConfig.contextPath; return ( -
      - -
      +
      {props.theme}
      -
        -
      • - - -
          -
        • THEMING
        • -
        • Guide
        • -
        • Designer
        • -
        • Visual Editor
        • -
        • Icons
        • -
        • Figma UI Kit
        • +
            +
          • + + +
              +
            • + THEMING +
            • +
            • + + + + Guide + + +
            • +
            • + + + Designer + +
            • +
            • + + + Visual Editor + +
            • +
            • + + + + Icons + + +
            • +
            • + + + + Figma UI Kit + + +
            • -
            • BOOTSTRAP
            • -
            • -
            • -
            • -
            • +
            • + BOOTSTRAP +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • -
            • MATERIAL DESIGN
            • -
            • -
            • -
            • -
            • +
            • + MATERIAL DESIGN +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • -
            • MATERIAL DESIGN COMPACT
            • -
            • -
            • -
            • -
            • +
            • + MATERIAL DESIGN COMPACT +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • -
            • TAILWIND
            • -
            • +
            • + TAILWIND +
            • +
            • + +
            • -
            • FLUENT UI
            • -
            • +
            • + FLUENT UI +
            • +
            • + +
            • -
            • PRIMEONE 2022
            • -
            • -
            • -
            • -
            • -
            • -
            • -
            • -
            • +
            • + PRIMEONE 2022 +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • -
            • PRIMEONE 2021
            • -
            • -
            • -
            • -
            • -
            • -
            • -
            • -
            • -
            • -
            • -
            • -
            • +
            • + PRIMEONE 2021 +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • -
            • PREMIUM
            • -
            • -
            • -
            • -
            • -
            • -
            • +
            • + PREMIUM +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • -
            • LEGACY
            • -
            • -
            • -
            • -
            • -
            • -
            • -
            • -
            • +
            • + LEGACY +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • +
            • + +
            • +
            • + +
          • -
          • - - -
              -
            • FREE ADMIN TEMPLATES
            • -
            • - - SakaiSakai +
            • + + +
            • - - - Blocks - + + Blocks
            • -
            • - - -
                - { - versions.map(version => { - return ( -
              • - - {version.version} - -
              • - ) - }) - } +
              • + + +
              • diff --git a/components/lib/accordion/Accordion.js b/components/lib/accordion/Accordion.js index 5e62688850..9cd36f1118 100644 --- a/components/lib/accordion/Accordion.js +++ b/components/lib/accordion/Accordion.js @@ -3,7 +3,7 @@ import { CSSTransition } from '../csstransition/CSSTransition'; import { useMountEffect } from '../hooks/Hooks'; import { classNames, IconUtils, ObjectUtils, UniqueComponentId } from '../utils/Utils'; -export const AccordionTab = () => { } +export const AccordionTab = () => {}; export const Accordion = React.forwardRef((props, ref) => { const [idState, setIdState] = React.useState(props.id); @@ -20,9 +20,8 @@ export const Accordion = React.forwardRef((props, ref) => { if (props.multiple) { const indexes = activeIndex || []; - newActiveIndex = selected ? indexes.filter(i => i !== index) : [...indexes, index]; - } - else { + newActiveIndex = selected ? indexes.filter((i) => i !== index) : [...indexes, index]; + } else { newActiveIndex = selected ? null : index; } @@ -34,18 +33,17 @@ export const Accordion = React.forwardRef((props, ref) => { originalEvent: event, index: newActiveIndex }); - } - else { + } else { setActiveIndexState(newActiveIndex); } } event.preventDefault(); - } + }; const isSelected = (index) => { - return props.multiple ? (activeIndex && activeIndex.some(i => i === index)) : activeIndex === index; - } + return props.multiple ? activeIndex && activeIndex.some((i) => i === index) : activeIndex === index; + }; React.useImperativeHandle(ref, () => ({ props, @@ -60,25 +58,30 @@ export const Accordion = React.forwardRef((props, ref) => { const createTabHeader = (tab, selected, index) => { const style = { ...(tab.props.style || {}), ...(tab.props.headerStyle || {}) }; - const className = classNames('p-accordion-header', { - 'p-highlight': selected, - 'p-disabled': tab.props.disabled - }, tab.props.headerClassName, tab.props.className); + const className = classNames( + 'p-accordion-header', + { + 'p-highlight': selected, + 'p-disabled': tab.props.disabled + }, + tab.props.headerClassName, + tab.props.className + ); const headerId = idState + '_header_' + index; const ariaControls = idState + '_content_' + index; const tabIndex = tab.props.disabled ? -1 : null; - const header = tab.props.headerTemplate ? ObjectUtils.getJSXElement(tab.props.headerTemplate, tab.props) : {tab.props.header}; + const header = tab.props.headerTemplate ? ObjectUtils.getJSXElement(tab.props.headerTemplate, tab.props) : {tab.props.header}; const icon = IconUtils.getJSXIcon(selected ? props.collapseIcon : props.expandIcon, { className: 'p-accordion-toggle-icon' }, { props, selected }); return ( - ) - } + ); + }; const createTabContent = (tab, selected, index) => { const style = { ...(tab.props.style || {}), ...(tab.props.contentStyle || {}) }; @@ -88,15 +91,13 @@ export const Accordion = React.forwardRef((props, ref) => { const contentRef = React.createRef(); return ( - -
                -
                - {tab.props.children} -
                + +
                +
                {tab.props.children}
                - ) - } + ); + }; const createTab = (tab, index) => { if (shouldUseTab(tab)) { @@ -114,15 +115,15 @@ export const Accordion = React.forwardRef((props, ref) => { {tabHeader} {tabContent}
                - ) + ); } return null; - } + }; const createTabs = () => { return React.Children.map(props.children, createTab); - } + }; const otherProps = ObjectUtils.findDiffKeys(props, Accordion.defaultProps); const className = classNames('p-accordion p-component', props.className); @@ -132,7 +133,7 @@ export const Accordion = React.forwardRef((props, ref) => {
                {tabs}
                - ) + ); }); AccordionTab.displayName = 'AccordionTab'; @@ -147,7 +148,7 @@ AccordionTab.defaultProps = { headerTemplate: null, contentStyle: null, contentClassName: null -} +}; Accordion.displayName = 'Accordion'; Accordion.defaultProps = { @@ -163,4 +164,4 @@ Accordion.defaultProps = { onTabOpen: null, onTabClose: null, onTabChange: null -} +}; diff --git a/components/lib/accordion/accordion.d.ts b/components/lib/accordion/accordion.d.ts index 5993a05c10..48a6a27062 100644 --- a/components/lib/accordion/accordion.d.ts +++ b/components/lib/accordion/accordion.d.ts @@ -17,7 +17,7 @@ interface AccordionTabProps { children?: React.ReactNode; } -export declare class AccordionTab extends React.Component { } +export declare class AccordionTab extends React.Component {} type AccordionActiveIndexType = number | number[] | undefined | null; @@ -39,6 +39,6 @@ export interface AccordionProps extends Omit { +export declare class Accordion extends React.Component { public getElement(): HTMLDivElement; } diff --git a/components/lib/api/Api.js b/components/lib/api/Api.js index 766e0673e7..a8bd14bd37 100644 --- a/components/lib/api/Api.js +++ b/components/lib/api/Api.js @@ -4,7 +4,7 @@ import { PrimeIcons } from './PrimeIcons'; import { MessageSeverity } from './MessageSeverity'; import { FilterMatchMode } from './FilterMatchMode'; import { FilterOperator } from './FilterOperator'; -import { FilterService } from './FilterService' +import { FilterService } from './FilterService'; export default PrimeReact; diff --git a/components/lib/api/FilterService.js b/components/lib/api/FilterService.js index bdf76bdbc1..6deb99d4d5 100644 --- a/components/lib/api/FilterService.js +++ b/components/lib/api/FilterService.js @@ -20,7 +20,7 @@ export const FilterService = { return filteredItems; }, filters: { - startsWith(value, filter, filterLocale) { + startsWith(value, filter, filterLocale) { if (filter === undefined || filter === null || filter.trim() === '') { return true; } @@ -85,10 +85,8 @@ export const FilterService = { return false; } - if (value.getTime && filter.getTime) - return value.getTime() === filter.getTime(); - else - return ObjectUtils.removeAccents(value.toString()).toLocaleLowerCase(filterLocale) === ObjectUtils.removeAccents(filter.toString()).toLocaleLowerCase(filterLocale); + if (value.getTime && filter.getTime) return value.getTime() === filter.getTime(); + else return ObjectUtils.removeAccents(value.toString()).toLocaleLowerCase(filterLocale) === ObjectUtils.removeAccents(filter.toString()).toLocaleLowerCase(filterLocale); }, notEquals(value, filter, filterLocale) { if (filter === undefined || filter === null || (typeof filter === 'string' && filter.trim() === '')) { @@ -99,10 +97,8 @@ export const FilterService = { return true; } - if (value.getTime && filter.getTime) - return value.getTime() !== filter.getTime(); - else - return ObjectUtils.removeAccents(value.toString()).toLocaleLowerCase(filterLocale) !== ObjectUtils.removeAccents(filter.toString()).toLocaleLowerCase(filterLocale); + if (value.getTime && filter.getTime) return value.getTime() !== filter.getTime(); + else return ObjectUtils.removeAccents(value.toString()).toLocaleLowerCase(filterLocale) !== ObjectUtils.removeAccents(filter.toString()).toLocaleLowerCase(filterLocale); }, in(value, filter) { if (filter === undefined || filter === null || filter.length === 0) { @@ -126,10 +122,8 @@ export const FilterService = { return false; } - if (value.getTime) - return filter[0].getTime() <= value.getTime() && value.getTime() <= filter[1].getTime(); - else - return filter[0] <= value && value <= filter[1]; + if (value.getTime) return filter[0].getTime() <= value.getTime() && value.getTime() <= filter[1].getTime(); + else return filter[0] <= value && value <= filter[1]; }, lt(value, filter) { if (filter === undefined || filter === null) { @@ -140,10 +134,8 @@ export const FilterService = { return false; } - if (value.getTime && filter.getTime) - return value.getTime() < filter.getTime(); - else - return value < filter; + if (value.getTime && filter.getTime) return value.getTime() < filter.getTime(); + else return value < filter; }, lte(value, filter) { if (filter === undefined || filter === null) { @@ -154,10 +146,8 @@ export const FilterService = { return false; } - if (value.getTime && filter.getTime) - return value.getTime() <= filter.getTime(); - else - return value <= filter; + if (value.getTime && filter.getTime) return value.getTime() <= filter.getTime(); + else return value <= filter; }, gt(value, filter) { if (filter === undefined || filter === null) { @@ -168,10 +158,8 @@ export const FilterService = { return false; } - if (value.getTime && filter.getTime) - return value.getTime() > filter.getTime(); - else - return value > filter; + if (value.getTime && filter.getTime) return value.getTime() > filter.getTime(); + else return value > filter; }, gte(value, filter) { if (filter === undefined || filter === null) { @@ -182,10 +170,8 @@ export const FilterService = { return false; } - if (value.getTime && filter.getTime) - return value.getTime() >= filter.getTime(); - else - return value >= filter; + if (value.getTime && filter.getTime) return value.getTime() >= filter.getTime(); + else return value >= filter; }, dateIs(value, filter) { if (filter === undefined || filter === null) { diff --git a/components/lib/api/Locale.js b/components/lib/api/Locale.js index ea2451583c..f094b7b2b1 100644 --- a/components/lib/api/Locale.js +++ b/components/lib/api/Locale.js @@ -1,7 +1,7 @@ import PrimeReact from './PrimeReact'; let locales = { - 'en': { + en: { startsWith: 'Starts with', contains: 'Contains', notContains: 'Not contains', @@ -31,9 +31,9 @@ let locales = { cancel: 'Cancel', dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], - dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], - monthNames: ['January','February','March','April','May','June','July','August','September','October','November','December'], - monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun','Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + dayNamesMin: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'], + monthNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], today: 'Today', weekHeader: 'Wk', firstDayOfWeek: 0, @@ -63,7 +63,7 @@ function locale(locale) { return { locale: PrimeReact.locale, options: locales[PrimeReact.locale] - } + }; } function addLocale(locale, options) { @@ -84,8 +84,7 @@ function localeOption(key, locale) { try { return localeOptions(_locale)[key]; - } - catch(error) { + } catch (error) { throw new Error(`The ${key} option is not found in the current locale('${_locale}').`); } } @@ -95,8 +94,7 @@ function ariaLabel(key) { try { return localeOptions(_locale)['aria'][key]; - } - catch(error) { + } catch (error) { throw new Error(`The ${key} option is not found in the current locale('${_locale}').`); } } diff --git a/components/lib/api/PrimeIcons.js b/components/lib/api/PrimeIcons.js index 7a17471a4b..14fed7527f 100644 --- a/components/lib/api/PrimeIcons.js +++ b/components/lib/api/PrimeIcons.js @@ -91,7 +91,7 @@ export const PrimeIcons = Object.freeze({ ENVELOPE: 'pi pi-envelope', EURO: 'pi pi-euro', EXCLAMATION_CIRCLE: 'pi pi-exclamation-circle', - EXCLAMATION_TRIANGLE : 'pi pi-exclamation-triangle', + EXCLAMATION_TRIANGLE: 'pi pi-exclamation-triangle', EXTERNAL_LINK: 'pi pi-external-link', EYE: 'pi pi-eye', EYE_SLASH: 'pi pi-eye-slash', diff --git a/components/lib/api/PrimeReact.js b/components/lib/api/PrimeReact.js index 76969c5b7b..7092318044 100644 --- a/components/lib/api/PrimeReact.js +++ b/components/lib/api/PrimeReact.js @@ -1,7 +1,6 @@ import { FilterMatchMode } from './FilterMatchMode'; export default class PrimeReact { - static ripple = false; static inputStyle = 'outlined'; @@ -24,30 +23,11 @@ export default class PrimeReact { menu: 1000, tooltip: 1100, toast: 1200 - } + }; static filterMatchModeOptions = { - text: [ - FilterMatchMode.STARTS_WITH, - FilterMatchMode.CONTAINS, - FilterMatchMode.NOT_CONTAINS, - FilterMatchMode.ENDS_WITH, - FilterMatchMode.EQUALS, - FilterMatchMode.NOT_EQUALS - ], - numeric: [ - FilterMatchMode.EQUALS, - FilterMatchMode.NOT_EQUALS, - FilterMatchMode.LESS_THAN, - FilterMatchMode.LESS_THAN_OR_EQUAL_TO, - FilterMatchMode.GREATER_THAN, - FilterMatchMode.GREATER_THAN_OR_EQUAL_TO - ], - date: [ - FilterMatchMode.DATE_IS, - FilterMatchMode.DATE_IS_NOT, - FilterMatchMode.DATE_BEFORE, - FilterMatchMode.DATE_AFTER - ] - } + text: [FilterMatchMode.STARTS_WITH, FilterMatchMode.CONTAINS, FilterMatchMode.NOT_CONTAINS, FilterMatchMode.ENDS_WITH, FilterMatchMode.EQUALS, FilterMatchMode.NOT_EQUALS], + numeric: [FilterMatchMode.EQUALS, FilterMatchMode.NOT_EQUALS, FilterMatchMode.LESS_THAN, FilterMatchMode.LESS_THAN_OR_EQUAL_TO, FilterMatchMode.GREATER_THAN, FilterMatchMode.GREATER_THAN_OR_EQUAL_TO], + date: [FilterMatchMode.DATE_IS, FilterMatchMode.DATE_IS_NOT, FilterMatchMode.DATE_BEFORE, FilterMatchMode.DATE_AFTER] + }; } diff --git a/components/lib/api/api.d.ts b/components/lib/api/api.d.ts index 3320482157..b880f320a1 100644 --- a/components/lib/api/api.d.ts +++ b/components/lib/api/api.d.ts @@ -35,7 +35,7 @@ declare const PrimeReact: APIOptions; export default PrimeReact; // Locale -export declare function locale(locale: string): { locale: string, options: object }; +export declare function locale(locale: string): { locale: string; options: object }; export declare function addLocale(locale: string, options: object): void; export declare function updateLocaleOption(key: string, value: any, locale: string): void; export declare function updateLocaleOptions(options: object, locale: string): void; @@ -136,7 +136,7 @@ export interface PrimeIconsOptions { readonly ENVELOPE: string; readonly EURO: string; readonly EXCLAMATION_CIRCLE: string; - readonly EXCLAMATION_TRIANGLE : string; + readonly EXCLAMATION_TRIANGLE: string; readonly EXTERNAL_LINK: string; readonly EYE: string; readonly EYE_SLASH: string; @@ -337,6 +337,6 @@ export declare namespace FilterService { dateIsNot(value: any, filter: string): boolean; dateBefore(value: any, filter: string): boolean; dateAfter(value: any, filter: string): boolean; - } + }; export function register(rule: string, fn: (...arg: any[]) => boolean): void; } diff --git a/components/lib/autocomplete/AutoComplete.js b/components/lib/autocomplete/AutoComplete.js index ceeb5e8a2e..0a5f420224 100644 --- a/components/lib/autocomplete/AutoComplete.js +++ b/components/lib/autocomplete/AutoComplete.js @@ -8,576 +8,630 @@ import { Tooltip } from '../tooltip/Tooltip'; import { classNames, DomHandler, IconUtils, ObjectUtils, UniqueComponentId, ZIndexUtils } from '../utils/Utils'; import { AutoCompletePanel } from './AutoCompletePanel'; -export const AutoComplete = React.memo(React.forwardRef((props, ref) => { - const [idState, setIdState] = React.useState(props.id); - const [searchingState, setSearchingState] = React.useState(false); - const [focusedState, setFocusedState] = React.useState(false); - const [overlayVisibleState, setOverlayVisibleState] = React.useState(false); - const elementRef = React.useRef(null); - const overlayRef = React.useRef(null); - const inputRef = React.useRef(props.inputRef); - const multiContainerRef = React.useRef(null); - const virtualScrollerRef = React.useRef(null); - const timeout = React.useRef(null); - const selectedItem = React.useRef(null); - - const [bindOverlayListener, unbindOverlayListener] = useOverlayListener({ - target: elementRef, overlay: overlayRef, listener: (event, { type, valid }) => { - if (valid) { - (type === 'outside') ? !isInputClicked(event) && hide() : hide(); +export const AutoComplete = React.memo( + React.forwardRef((props, ref) => { + const [idState, setIdState] = React.useState(props.id); + const [searchingState, setSearchingState] = React.useState(false); + const [focusedState, setFocusedState] = React.useState(false); + const [overlayVisibleState, setOverlayVisibleState] = React.useState(false); + const elementRef = React.useRef(null); + const overlayRef = React.useRef(null); + const inputRef = React.useRef(props.inputRef); + const multiContainerRef = React.useRef(null); + const virtualScrollerRef = React.useRef(null); + const timeout = React.useRef(null); + const selectedItem = React.useRef(null); + + const [bindOverlayListener, unbindOverlayListener] = useOverlayListener({ + target: elementRef, + overlay: overlayRef, + listener: (event, { type, valid }) => { + if (valid) { + type === 'outside' ? !isInputClicked(event) && hide() : hide(); + } + }, + when: overlayVisibleState + }); + + const isInputClicked = (event) => { + return props.multiple ? event.target === multiContainerRef.current || multiContainerRef.current.contains(event.target) : event.target === inputRef.current; + }; + + const onInputChange = (event) => { + //Cancel the search request if user types within the timeout + if (timeout.current) { + clearTimeout(timeout.current); } - }, when: overlayVisibleState - }); - - const isInputClicked = (event) => { - return props.multiple ? event.target === multiContainerRef.current || multiContainerRef.current.contains(event.target) : event.target === inputRef.current; - } - - const onInputChange = (event) => { - //Cancel the search request if user types within the timeout - if (timeout.current) { - clearTimeout(timeout.current); - } - - const query = event.target.value; - if (!props.multiple) { - updateModel(event, query); - } - - if (ObjectUtils.isEmpty(query)) { - hide(); - props.onClear && props.onClear(event); - } - else { - if (query.length >= props.minLength) { - timeout.current = setTimeout(() => { - search(event, query, 'input'); - }, props.delay); + + const query = event.target.value; + if (!props.multiple) { + updateModel(event, query); } - else { + + if (ObjectUtils.isEmpty(query)) { hide(); + props.onClear && props.onClear(event); + } else { + if (query.length >= props.minLength) { + timeout.current = setTimeout(() => { + search(event, query, 'input'); + }, props.delay); + } else { + hide(); + } } - } - } - - const search = (event, query, source) => { - //allow empty string but not undefined or null - if (query === undefined || query === null) { - return; - } - - //do not search blank values on input change - if (source === 'input' && query.trim().length === 0) { - return; - } - - if (props.completeMethod) { - setSearchingState(true); - props.completeMethod({ - originalEvent: event, - query - }); - } - } - - const selectItem = (event, option, preventInputFocus) => { - if (props.multiple) { - inputRef.current.value = ''; - if (!isSelected(option)) { - const newValue = props.value ? [...props.value, option] : [option]; - updateModel(event, newValue); + }; + + const search = (event, query, source) => { + //allow empty string but not undefined or null + if (query === undefined || query === null) { + return; } - } - else { - updateInputField(option); - updateModel(event, option); - } - - if (props.onSelect) { - props.onSelect({ - originalEvent: event, - value: option - }) - } - if (!preventInputFocus) { - DomHandler.focus(inputRef.current); - hide(); - } - } - - const updateModel = (event, value) => { - // #2176 only call change if value actually changed - if (selectedItem && selectedItem.current === value) { - return; - } - if (props.onChange) { - props.onChange({ - originalEvent: event, - value, - stopPropagation: () => { }, - preventDefault: () => { }, - target: { - name: props.name, - id: idState, - value + //do not search blank values on input change + if (source === 'input' && query.trim().length === 0) { + return; + } + + if (props.completeMethod) { + setSearchingState(true); + props.completeMethod({ + originalEvent: event, + query + }); + } + }; + + const selectItem = (event, option, preventInputFocus) => { + if (props.multiple) { + inputRef.current.value = ''; + if (!isSelected(option)) { + const newValue = props.value ? [...props.value, option] : [option]; + updateModel(event, newValue); } - }); - } + } else { + updateInputField(option); + updateModel(event, option); + } - selectedItem.current = value; - } + if (props.onSelect) { + props.onSelect({ + originalEvent: event, + value: option + }); + } - const formatValue = (value) => { - if (value) { - if (props.selectedItemTemplate && (props.multiple ? isSelected(value) : findOptionIndex(value) > -1)) { - const resolvedFieldData = ObjectUtils.getJSXElement(props.selectedItemTemplate, value); - return resolvedFieldData ? resolvedFieldData : value; + if (!preventInputFocus) { + DomHandler.focus(inputRef.current); + hide(); } - else if (props.field) { - const resolvedFieldData = ObjectUtils.resolveFieldData(value, props.field); - return resolvedFieldData !== null && resolvedFieldData !== undefined ? resolvedFieldData : value; + }; + + const updateModel = (event, value) => { + // #2176 only call change if value actually changed + if (selectedItem && selectedItem.current === value) { + return; } - else { - return value; + if (props.onChange) { + props.onChange({ + originalEvent: event, + value, + stopPropagation: () => {}, + preventDefault: () => {}, + target: { + name: props.name, + id: idState, + value + } + }); } - } - - return ''; - } - - const updateInputField = (value) => { - inputRef.current.value = formatValue(value); - } - - const show = () => { - setOverlayVisibleState(true); - } - - const hide = () => { - setOverlayVisibleState(false); - setSearchingState(false); - } - - const onOverlayEnter = () => { - ZIndexUtils.set('overlay', overlayRef.current, PrimeReact.autoZIndex, PrimeReact.zIndex['overlay']); - alignOverlay(); - } - - const onOverlayEntering = () => { - if (props.autoHighlight && props.suggestions && props.suggestions.length) { - const element = getScrollableElement().firstChild.firstChild; - DomHandler.addClass(element, 'p-highlight'); - } - } - - const onOverlayEntered = () => { - bindOverlayListener(); - props.onShow && props.onShow(); - } - - const onOverlayExit = () => { - unbindOverlayListener(); - } - - const onOverlayExited = () => { - ZIndexUtils.clear(overlayRef.current); - - props.onHide && props.onHide(); - } - - const alignOverlay = () => { - const target = props.multiple ? multiContainerRef.current : inputRef.current; - DomHandler.alignOverlay(overlayRef.current, target, props.appendTo || PrimeReact.appendTo); - } - - const onPanelClick = (event) => { - OverlayService.emit('overlay-click', { - originalEvent: event, - target: elementRef.current - }); - } - const onDropdownClick = (event) => { - if (props.dropdownAutoFocus) { - DomHandler.focus(inputRef.current, props.dropdownAutoFocus); - } + selectedItem.current = value; + }; + + const formatValue = (value) => { + if (value) { + if (props.selectedItemTemplate && (props.multiple ? isSelected(value) : findOptionIndex(value) > -1)) { + const resolvedFieldData = ObjectUtils.getJSXElement(props.selectedItemTemplate, value); + return resolvedFieldData ? resolvedFieldData : value; + } else if (props.field) { + const resolvedFieldData = ObjectUtils.resolveFieldData(value, props.field); + return resolvedFieldData !== null && resolvedFieldData !== undefined ? resolvedFieldData : value; + } else { + return value; + } + } - if (props.dropdownMode === 'blank') - search(event, '', 'dropdown'); - else if (props.dropdownMode === 'current') - search(event, inputRef.current.value, 'dropdown'); + return ''; + }; - if (props.onDropdownClick) { - props.onDropdownClick({ - originalEvent: event, - query: inputRef.current.value - }); - } - } + const updateInputField = (value) => { + inputRef.current.value = formatValue(value); + }; - const removeItem = (event, index) => { - const removedValue = props.value[index]; - const newValue = props.value.filter((_, i) => (index !== i)); - updateModel(event, newValue); + const show = () => { + setOverlayVisibleState(true); + }; + + const hide = () => { + setOverlayVisibleState(false); + setSearchingState(false); + }; + + const onOverlayEnter = () => { + ZIndexUtils.set('overlay', overlayRef.current, PrimeReact.autoZIndex, PrimeReact.zIndex['overlay']); + alignOverlay(); + }; + + const onOverlayEntering = () => { + if (props.autoHighlight && props.suggestions && props.suggestions.length) { + const element = getScrollableElement().firstChild.firstChild; + DomHandler.addClass(element, 'p-highlight'); + } + }; - if (props.onUnselect) { - props.onUnselect({ + const onOverlayEntered = () => { + bindOverlayListener(); + props.onShow && props.onShow(); + }; + + const onOverlayExit = () => { + unbindOverlayListener(); + }; + + const onOverlayExited = () => { + ZIndexUtils.clear(overlayRef.current); + + props.onHide && props.onHide(); + }; + + const alignOverlay = () => { + const target = props.multiple ? multiContainerRef.current : inputRef.current; + DomHandler.alignOverlay(overlayRef.current, target, props.appendTo || PrimeReact.appendTo); + }; + + const onPanelClick = (event) => { + OverlayService.emit('overlay-click', { originalEvent: event, - value: removedValue + target: elementRef.current }); - } - } - - const onInputKeyDown = (event) => { - if (overlayVisibleState) { - let highlightItem = DomHandler.findSingle(overlayRef.current, 'li.p-highlight'); - - switch (event.which) { - //down - case 40: - if (highlightItem) { - let nextElement = findNextItem(highlightItem); - if (nextElement) { - DomHandler.addClass(nextElement, 'p-highlight'); - DomHandler.removeClass(highlightItem, 'p-highlight'); - DomHandler.scrollInView(getScrollableElement(), nextElement); - } - } - else { - highlightItem = DomHandler.findSingle(overlayRef.current, 'li'); - if (DomHandler.hasClass(highlightItem, 'p-autocomplete-item-group')) { - highlightItem = findNextItem(highlightItem); + }; + + const onDropdownClick = (event) => { + if (props.dropdownAutoFocus) { + DomHandler.focus(inputRef.current, props.dropdownAutoFocus); + } + + if (props.dropdownMode === 'blank') search(event, '', 'dropdown'); + else if (props.dropdownMode === 'current') search(event, inputRef.current.value, 'dropdown'); + + if (props.onDropdownClick) { + props.onDropdownClick({ + originalEvent: event, + query: inputRef.current.value + }); + } + }; + + const removeItem = (event, index) => { + const removedValue = props.value[index]; + const newValue = props.value.filter((_, i) => index !== i); + updateModel(event, newValue); + + if (props.onUnselect) { + props.onUnselect({ + originalEvent: event, + value: removedValue + }); + } + }; + + const onInputKeyDown = (event) => { + if (overlayVisibleState) { + let highlightItem = DomHandler.findSingle(overlayRef.current, 'li.p-highlight'); + + switch (event.which) { + //down + case 40: + if (highlightItem) { + let nextElement = findNextItem(highlightItem); + if (nextElement) { + DomHandler.addClass(nextElement, 'p-highlight'); + DomHandler.removeClass(highlightItem, 'p-highlight'); + DomHandler.scrollInView(getScrollableElement(), nextElement); + } + } else { + highlightItem = DomHandler.findSingle(overlayRef.current, 'li'); + if (DomHandler.hasClass(highlightItem, 'p-autocomplete-item-group')) { + highlightItem = findNextItem(highlightItem); + } + + if (highlightItem) { + DomHandler.addClass(highlightItem, 'p-highlight'); + } } + event.preventDefault(); + break; + + //up + case 38: if (highlightItem) { - DomHandler.addClass(highlightItem, 'p-highlight'); + let previousElement = findPrevItem(highlightItem); + if (previousElement) { + DomHandler.addClass(previousElement, 'p-highlight'); + DomHandler.removeClass(highlightItem, 'p-highlight'); + DomHandler.scrollInView(getScrollableElement(), previousElement); + } } - } - event.preventDefault(); - break; - - //up - case 38: - if (highlightItem) { - let previousElement = findPrevItem(highlightItem); - if (previousElement) { - DomHandler.addClass(previousElement, 'p-highlight'); - DomHandler.removeClass(highlightItem, 'p-highlight'); - DomHandler.scrollInView(getScrollableElement(), previousElement); + event.preventDefault(); + break; + + //enter + case 13: + if (highlightItem) { + selectHighlightItem(event, highlightItem); + hide(); + event.preventDefault(); } - } - event.preventDefault(); - break; + break; - //enter - case 13: - if (highlightItem) { - selectHighlightItem(event, highlightItem); + //escape + case 27: hide(); event.preventDefault(); - } - - break; + break; - //escape - case 27: - hide(); - event.preventDefault(); - break; - - //tab - case 9: - if (highlightItem) { - selectHighlightItem(event, highlightItem); - } + //tab + case 9: + if (highlightItem) { + selectHighlightItem(event, highlightItem); + } - hide(); - break; + hide(); + break; - default: - break; + default: + break; + } } - } - - if (props.multiple) { - switch (event.which) { - //backspace - case 8: - if (props.value && props.value.length && !inputRef.current.value) { - const removedValue = props.value[props.value.length - 1]; - const newValue = props.value.slice(0, -1); - - updateModel(event, newValue); - - if (props.onUnselect) { - props.onUnselect({ - originalEvent: event, - value: removedValue - }) + + if (props.multiple) { + switch (event.which) { + //backspace + case 8: + if (props.value && props.value.length && !inputRef.current.value) { + const removedValue = props.value[props.value.length - 1]; + const newValue = props.value.slice(0, -1); + + updateModel(event, newValue); + + if (props.onUnselect) { + props.onUnselect({ + originalEvent: event, + value: removedValue + }); + } } - } - break; + break; - default: - break; + default: + break; + } } - } - } - - const selectHighlightItem = (event, item) => { - if (props.optionGroupLabel) { - const optionGroup = props.suggestions[item.dataset.group]; - selectItem(event, getOptionGroupChildren(optionGroup)[item.dataset.index]); - } - else { - selectItem(event, props.suggestions[DomHandler.index(item)]); - } - } - - const findNextItem = (item) => { - const nextItem = item.nextElementSibling; - - return nextItem ? (DomHandler.hasClass(nextItem, 'p-autocomplete-item-group') ? findNextItem(nextItem) : nextItem) : null; - } - - const findPrevItem = (item) => { - let prevItem = item.previousElementSibling; - - return prevItem ? (DomHandler.hasClass(prevItem, 'p-autocomplete-item-group') ? findPrevItem(prevItem) : prevItem) : null; - } - - const onInputFocus = (event) => { - setFocusedState(true); - props.onFocus && props.onFocus(event); - } - - const forceItemSelection = (event) => { - const inputValue = event.target.value.trim(); - const item = (props.suggestions || []).find(it => { - const value = props.field ? ObjectUtils.resolveFieldData(it, props.field) : it; - return value && inputValue === value.trim(); - }); + }; + + const selectHighlightItem = (event, item) => { + if (props.optionGroupLabel) { + const optionGroup = props.suggestions[item.dataset.group]; + selectItem(event, getOptionGroupChildren(optionGroup)[item.dataset.index]); + } else { + selectItem(event, props.suggestions[DomHandler.index(item)]); + } + }; - if (item) { - selectItem(event, item, true); - } - else { - inputRef.current.value = ''; - updateModel(event, null); + const findNextItem = (item) => { + const nextItem = item.nextElementSibling; - props.onClear && props.onClear(event); - } - } + return nextItem ? (DomHandler.hasClass(nextItem, 'p-autocomplete-item-group') ? findNextItem(nextItem) : nextItem) : null; + }; - const onInputBlur = (event) => { - setFocusedState(false); + const findPrevItem = (item) => { + let prevItem = item.previousElementSibling; - if (props.forceSelection) { - forceItemSelection(event); - } + return prevItem ? (DomHandler.hasClass(prevItem, 'p-autocomplete-item-group') ? findPrevItem(prevItem) : prevItem) : null; + }; - props.onBlur && props.onBlur(event); - } + const onInputFocus = (event) => { + setFocusedState(true); + props.onFocus && props.onFocus(event); + }; - const onMultiContainerClick = (event) => { - DomHandler.focus(inputRef.current); + const forceItemSelection = (event) => { + const inputValue = event.target.value.trim(); + const item = (props.suggestions || []).find((it) => { + const value = props.field ? ObjectUtils.resolveFieldData(it, props.field) : it; + return value && inputValue === value.trim(); + }); + + if (item) { + selectItem(event, item, true); + } else { + inputRef.current.value = ''; + updateModel(event, null); - props.onClick && props.onClick(event); - } + props.onClear && props.onClear(event); + } + }; - const onMultiInputFocus = (event) => { - onInputFocus(event); - DomHandler.addClass(multiContainerRef.current, 'p-focus'); - } + const onInputBlur = (event) => { + setFocusedState(false); - const onMultiInputBlur = (event) => { - onInputBlur(event); - DomHandler.removeClass(multiContainerRef.current, 'p-focus'); - } + if (props.forceSelection) { + forceItemSelection(event); + } - const isSelected = (val) => { - return props.value ? props.value.some(v => ObjectUtils.equals(v, val)) : false; - } + props.onBlur && props.onBlur(event); + }; - const findOptionIndex = (option) => { - return props.suggestions ? props.suggestions.findIndex(s => ObjectUtils.equals(s, option)) : -1; - } + const onMultiContainerClick = (event) => { + DomHandler.focus(inputRef.current); - const getScrollableElement = () => { - return virtualScrollerRef.current ? overlayRef.current.firstChild : overlayRef.current; - } + props.onClick && props.onClick(event); + }; - const getOptionGroupLabel = (optionGroup) => { - return props.optionGroupLabel ? ObjectUtils.resolveFieldData(optionGroup, props.optionGroupLabel) : optionGroup; - } + const onMultiInputFocus = (event) => { + onInputFocus(event); + DomHandler.addClass(multiContainerRef.current, 'p-focus'); + }; - const getOptionGroupChildren = (optionGroup) => { - return ObjectUtils.resolveFieldData(optionGroup, props.optionGroupChildren); - } + const onMultiInputBlur = (event) => { + onInputBlur(event); + DomHandler.removeClass(multiContainerRef.current, 'p-focus'); + }; - React.useEffect(() => { - ObjectUtils.combinedRefs(inputRef, props.inputRef); - }, [inputRef, props.inputRef]); + const isSelected = (val) => { + return props.value ? props.value.some((v) => ObjectUtils.equals(v, val)) : false; + }; - useMountEffect(() => { - if (!idState) { - setIdState(UniqueComponentId()); - } + const findOptionIndex = (option) => { + return props.suggestions ? props.suggestions.findIndex((s) => ObjectUtils.equals(s, option)) : -1; + }; - if (props.autoFocus) { - DomHandler.focus(inputRef.current, props.autoFocus); - } - }); + const getScrollableElement = () => { + return virtualScrollerRef.current ? overlayRef.current.firstChild : overlayRef.current; + }; - useUpdateEffect(() => { - if (searchingState) { - ObjectUtils.isNotEmpty(props.suggestions) ? show() : hide(); - setSearchingState(false); - } - }, [props.suggestions]); - - useUpdateEffect(() => { - if (inputRef.current && !props.multiple) { - updateInputField(props.value); - } - }); - - useUnmountEffect(() => { - if (timeout.current) { - clearTimeout(timeout.current); - } - - ZIndexUtils.clear(overlayRef.current); - }); - - React.useImperativeHandle(ref, () => ({ - props, - search, - getElement: () => elementRef.current, - getOverlay: () => overlayRef.current, - getInput: () => inputRef.current, - getVirtualScroller: () => virtualScrollerRef.current - })); - - const createSimpleAutoComplete = () => { - const value = formatValue(props.value); - const ariaControls = overlayVisibleState ? idState + '_list' : null; - const className = classNames('p-autocomplete-input', props.inputClassName, { - 'p-autocomplete-dd-input': props.dropdown + const getOptionGroupLabel = (optionGroup) => { + return props.optionGroupLabel ? ObjectUtils.resolveFieldData(optionGroup, props.optionGroupLabel) : optionGroup; + }; + + const getOptionGroupChildren = (optionGroup) => { + return ObjectUtils.resolveFieldData(optionGroup, props.optionGroupChildren); + }; + + React.useEffect(() => { + ObjectUtils.combinedRefs(inputRef, props.inputRef); + }, [inputRef, props.inputRef]); + + useMountEffect(() => { + if (!idState) { + setIdState(UniqueComponentId()); + } + + if (props.autoFocus) { + DomHandler.focus(inputRef.current, props.autoFocus); + } }); - return ( - - ) - } - - const createChips = () => { - if (ObjectUtils.isNotEmpty(props.value)) { - return props.value.map((val, index) => { - const key = index + 'multi-item'; - return ( -
              • - {formatValue(val)} - {!props.disabled && IconUtils.getJSXIcon(props.removeIcon, { className: 'p-autocomplete-token-icon', onClick: (e) => removeItem(e, index) }, { props })} -
              • - ) - }) - } - - return null; - } - - const createMultiInput = () => { - const ariaControls = overlayVisibleState ? idState + '_list' : null; + useUpdateEffect(() => { + if (searchingState) { + ObjectUtils.isNotEmpty(props.suggestions) ? show() : hide(); + setSearchingState(false); + } + }, [props.suggestions]); - return ( -
              • - -
              • - ) - } - - const createMultipleAutoComplete = () => { - const className = classNames('p-autocomplete-multiple-container p-component p-inputtext', { - 'p-disabled': props.disabled + useUpdateEffect(() => { + if (inputRef.current && !props.multiple) { + updateInputField(props.value); + } }); - const tokens = createChips(); - const input = createMultiInput(); + + useUnmountEffect(() => { + if (timeout.current) { + clearTimeout(timeout.current); + } + + ZIndexUtils.clear(overlayRef.current); + }); + + React.useImperativeHandle(ref, () => ({ + props, + search, + getElement: () => elementRef.current, + getOverlay: () => overlayRef.current, + getInput: () => inputRef.current, + getVirtualScroller: () => virtualScrollerRef.current + })); + + const createSimpleAutoComplete = () => { + const value = formatValue(props.value); + const ariaControls = overlayVisibleState ? idState + '_list' : null; + const className = classNames('p-autocomplete-input', props.inputClassName, { + 'p-autocomplete-dd-input': props.dropdown + }); + + return ( + + ); + }; + + const createChips = () => { + if (ObjectUtils.isNotEmpty(props.value)) { + return props.value.map((val, index) => { + const key = index + 'multi-item'; + return ( +
              • + {formatValue(val)} + {!props.disabled && IconUtils.getJSXIcon(props.removeIcon, { className: 'p-autocomplete-token-icon', onClick: (e) => removeItem(e, index) }, { props })} +
              • + ); + }); + } + + return null; + }; + + const createMultiInput = () => { + const ariaControls = overlayVisibleState ? idState + '_list' : null; + + return ( +
              • + +
              • + ); + }; + + const createMultipleAutoComplete = () => { + const className = classNames('p-autocomplete-multiple-container p-component p-inputtext', { + 'p-disabled': props.disabled + }); + const tokens = createChips(); + const input = createMultiInput(); + + return ( +
                  + {tokens} + {input} +
                + ); + }; + + const createDropdown = () => { + if (props.dropdown) { + return
      - ) + ); }); Avatar.displayName = 'Avatar'; @@ -55,4 +57,4 @@ Avatar.defaultProps = { template: null, imageAlt: 'avatar', onImageError: null -} +}; diff --git a/components/lib/avatar/avatar.d.ts b/components/lib/avatar/avatar.d.ts index ead9dca3f8..1ab254ab92 100644 --- a/components/lib/avatar/avatar.d.ts +++ b/components/lib/avatar/avatar.d.ts @@ -20,6 +20,6 @@ export interface AvatarProps extends Omit { +export declare class Avatar extends React.Component { public getElement(): HTMLDivElement; } diff --git a/components/lib/avatargroup/AvatarGroup.js b/components/lib/avatargroup/AvatarGroup.js index b75e6c038f..74039e7d89 100644 --- a/components/lib/avatargroup/AvatarGroup.js +++ b/components/lib/avatargroup/AvatarGroup.js @@ -15,7 +15,7 @@ export const AvatarGroup = React.forwardRef((props, ref) => {
      {props.children}
      - ) + ); }); AvatarGroup.displayName = 'AvatarGroup'; @@ -23,4 +23,4 @@ AvatarGroup.defaultProps = { __TYPE: 'AvatarGroup', style: null, className: null -} +}; diff --git a/components/lib/avatargroup/avatargroup.d.ts b/components/lib/avatargroup/avatargroup.d.ts index 7bf1b26767..89773edaef 100644 --- a/components/lib/avatargroup/avatargroup.d.ts +++ b/components/lib/avatargroup/avatargroup.d.ts @@ -4,6 +4,6 @@ export interface AvatarGroupProps extends Omit { +export declare class AvatarGroup extends React.Component { public getElement(): HTMLDivElement; } diff --git a/components/lib/badge/Badge.js b/components/lib/badge/Badge.js index 9cbfaee1de..eeb525e590 100644 --- a/components/lib/badge/Badge.js +++ b/components/lib/badge/Badge.js @@ -1,28 +1,34 @@ import * as React from 'react'; import { classNames, ObjectUtils } from '../utils/Utils'; -export const Badge = React.memo(React.forwardRef((props, ref) => { - const elementRef = React.useRef(null); - const otherProps = ObjectUtils.findDiffKeys(props, Badge.defaultProps); - const className = classNames('p-badge p-component', { - 'p-badge-no-gutter': ObjectUtils.isNotEmpty(props.value) && String(props.value).length === 1, - 'p-badge-dot': ObjectUtils.isEmpty(props.value), - 'p-badge-lg': props.size === 'large', - 'p-badge-xl': props.size === 'xlarge', - [`p-badge-${props.severity}`]: props.severity !== null - }, props.className); +export const Badge = React.memo( + React.forwardRef((props, ref) => { + const elementRef = React.useRef(null); + const otherProps = ObjectUtils.findDiffKeys(props, Badge.defaultProps); + const className = classNames( + 'p-badge p-component', + { + 'p-badge-no-gutter': ObjectUtils.isNotEmpty(props.value) && String(props.value).length === 1, + 'p-badge-dot': ObjectUtils.isEmpty(props.value), + 'p-badge-lg': props.size === 'large', + 'p-badge-xl': props.size === 'xlarge', + [`p-badge-${props.severity}`]: props.severity !== null + }, + props.className + ); - React.useImperativeHandle(ref, () => ({ - props, - getElement: () => elementRef.current - })); + React.useImperativeHandle(ref, () => ({ + props, + getElement: () => elementRef.current + })); - return ( - - {props.value} - - ) -})); + return ( + + {props.value} + + ); + }) +); Badge.displayName = 'Badge'; Badge.defaultProps = { @@ -32,4 +38,4 @@ Badge.defaultProps = { size: null, style: null, className: null -} +}; diff --git a/components/lib/badge/badge.d.ts b/components/lib/badge/badge.d.ts index a4ff0d4e05..204d2da345 100644 --- a/components/lib/badge/badge.d.ts +++ b/components/lib/badge/badge.d.ts @@ -13,4 +13,4 @@ export interface BadgeProps extends Omit { public getElement(): HTMLSpanElement; - } +} diff --git a/components/lib/blockui/BlockUI.js b/components/lib/blockui/BlockUI.js index eb0a2a3e8c..9fad5f01d0 100644 --- a/components/lib/blockui/BlockUI.js +++ b/components/lib/blockui/BlockUI.js @@ -11,7 +11,7 @@ export const BlockUI = React.forwardRef((props, ref) => { const block = () => { setVisibleState(true); - } + }; const unblock = () => { const callback = () => { @@ -19,7 +19,7 @@ export const BlockUI = React.forwardRef((props, ref) => { props.fullScreen && DomHandler.removeClass(document.body, 'p-overflow-hidden'); props.onUnblocked && props.onUnblocked(); - } + }; if (maskRef.current) { DomHandler.addClass(maskRef.current, 'p-component-overlay-leave'); @@ -27,11 +27,10 @@ export const BlockUI = React.forwardRef((props, ref) => { ZIndexUtils.clear(maskRef.current); callback(); }); - } - else { + } else { callback(); } - } + }; const onPortalMounted = () => { if (props.fullScreen) { @@ -45,7 +44,7 @@ export const BlockUI = React.forwardRef((props, ref) => { } props.onBlocked && props.onBlocked(); - } + }; useMountEffect(() => { visibleState && block(); @@ -73,9 +72,13 @@ export const BlockUI = React.forwardRef((props, ref) => { const createMask = () => { if (visibleState) { const appendTo = props.fullScreen ? document.body : 'self'; - const className = classNames('p-blockui p-component-overlay p-component-overlay-enter', { - 'p-blockui-document': props.fullScreen - }, props.className); + const className = classNames( + 'p-blockui p-component-overlay p-component-overlay-enter', + { + 'p-blockui-document': props.fullScreen + }, + props.className + ); const content = props.template ? ObjectUtils.getJSXElement(props.template, props) : null; const mask = (
      @@ -83,21 +86,21 @@ export const BlockUI = React.forwardRef((props, ref) => {
      ); - return + return ; } return null; - } + }; const otherProps = ObjectUtils.findDiffKeys(props, BlockUI.defaultProps); const mask = createMask(); return ( -
      +
      {props.children} {mask}
      - ) + ); }); BlockUI.displayName = 'BlockUI'; @@ -113,4 +116,4 @@ BlockUI.defaultProps = { template: null, onBlocked: null, onUnblocked: null -} +}; diff --git a/components/lib/breadcrumb/BreadCrumb.js b/components/lib/breadcrumb/BreadCrumb.js index 4f1617590c..ae61783407 100644 --- a/components/lib/breadcrumb/BreadCrumb.js +++ b/components/lib/breadcrumb/BreadCrumb.js @@ -1,137 +1,139 @@ import * as React from 'react'; import { classNames, IconUtils, ObjectUtils } from '../utils/Utils'; -export const BreadCrumb = React.memo(React.forwardRef((props, ref) => { - const elementRef = React.useRef(null); - - const itemClick = (event, item) => { - if (item.disabled) { - event.preventDefault(); - return; - } - - if (!item.url) { - event.preventDefault(); - } - - if (item.command) { - item.command({ - originalEvent: event, - item - }); - } - } - - const createHome = () => { - const home = props.home; - - if (home) { - const { icon: _icon, target, url, disabled, style, className: _className, template } = home; - const className = classNames('p-breadcrumb-home', { 'p-disabled': disabled }, _className); - const icon = IconUtils.getJSXIcon(_icon, { className: 'p-menuitem-icon' }, { props }); +export const BreadCrumb = React.memo( + React.forwardRef((props, ref) => { + const elementRef = React.useRef(null); + + const itemClick = (event, item) => { + if (item.disabled) { + event.preventDefault(); + return; + } + + if (!item.url) { + event.preventDefault(); + } + + if (item.command) { + item.command({ + originalEvent: event, + item + }); + } + }; + + const createHome = () => { + const home = props.home; + + if (home) { + const { icon: _icon, target, url, disabled, style, className: _className, template } = home; + const className = classNames('p-breadcrumb-home', { 'p-disabled': disabled }, _className); + const icon = IconUtils.getJSXIcon(_icon, { className: 'p-menuitem-icon' }, { props }); + + let content = ( + itemClick(event, home)}> + {icon} + + ); + + if (template) { + const defaultContentOptions = { + onClick: (event) => itemClick(event, home), + className: 'p-menuitem-link', + labelClassName: 'p-menuitem-text', + element: content, + props + }; + + content = ObjectUtils.getJSXElement(template, home, defaultContentOptions); + } + + return ( +
    • + {content} +
    • + ); + } + + return null; + }; + const createSeparator = () => { + return
    • ; + }; + + const createMenuitem = (item) => { + const className = classNames(item.className, { 'p-disabled': item.disabled }); + const label = item.label && {item.label}; let content = ( - itemClick(event, home)}> - {icon} + itemClick(event, item)} aria-disabled={item.disabled}> + {label} - ) + ); - if (template) { + if (item.template) { const defaultContentOptions = { - onClick: (event) => itemClick(event, home), + onClick: (event) => itemClick(event, item), className: 'p-menuitem-link', labelClassName: 'p-menuitem-text', element: content, props }; - content = ObjectUtils.getJSXElement(template, home, defaultContentOptions); + content = ObjectUtils.getJSXElement(item.template, item, defaultContentOptions); } return ( -
    • +
    • {content}
    • - ) - } - - return null; - } - - const createSeparator = () => { - return
    • - } - - const createMenuitem = (item) => { - const className = classNames(item.className, { 'p-disabled': item.disabled }); - const label = item.label && {item.label}; - let content = ( - itemClick(event, item)} aria-disabled={item.disabled}> - {label} - - ); - - if (item.template) { - const defaultContentOptions = { - onClick: (event) => itemClick(event, item), - className: 'p-menuitem-link', - labelClassName: 'p-menuitem-text', - element: content, - props + ); + }; + + const createMenuitems = () => { + if (props.model) { + const items = props.model.map((item, index) => { + const menuitem = createMenuitem(item); + const separator = index === props.model.length - 1 ? null : createSeparator(); + const key = item.label + '_' + index; + + return ( + + {menuitem} + {separator} + + ); + }); + + return items; } - content = ObjectUtils.getJSXElement(item.template, item, defaultContentOptions); - } + return null; + }; - return ( -
    • - {content} -
    • - ) - } - - const createMenuitems = () => { - if (props.model) { - const items = props.model.map((item, index) => { - const menuitem = createMenuitem(item); - const separator = (index === props.model.length - 1) ? null : createSeparator(); - const key = item.label + '_' + index; + React.useImperativeHandle(ref, () => ({ + props, + getElement: () => elementRef.current + })); - return ( - - {menuitem} - {separator} - - ) - }); - - return items; - } - - return null; - } - - React.useImperativeHandle(ref, () => ({ - props, - getElement: () => elementRef.current - })); - - const otherProps = ObjectUtils.findDiffKeys(props, BreadCrumb.defaultProps); - const className = classNames('p-breadcrumb p-component', props.className); - const home = createHome(); - const items = createMenuitems(); - const separator = createSeparator(); - - return ( - - ) -})); + const otherProps = ObjectUtils.findDiffKeys(props, BreadCrumb.defaultProps); + const className = classNames('p-breadcrumb p-component', props.className); + const home = createHome(); + const items = createMenuitems(); + const separator = createSeparator(); + + return ( + + ); + }) +); BreadCrumb.displayName = 'BreadCrumb'; BreadCrumb.defaultProps = { @@ -141,4 +143,4 @@ BreadCrumb.defaultProps = { home: null, style: null, className: null -} +}; diff --git a/components/lib/breadcrumb/breadcrumb.d.ts b/components/lib/breadcrumb/breadcrumb.d.ts index b1f446ef53..8737312cfc 100644 --- a/components/lib/breadcrumb/breadcrumb.d.ts +++ b/components/lib/breadcrumb/breadcrumb.d.ts @@ -7,6 +7,6 @@ export interface BreadCrumbProps extends Omit { +export declare class BreadCrumb extends React.Component { public getElement(): HTMLElement; } diff --git a/components/lib/button/Button.js b/components/lib/button/Button.js index 1ef9947809..a40503e54c 100644 --- a/components/lib/button/Button.js +++ b/components/lib/button/Button.js @@ -3,71 +3,73 @@ import { Ripple } from '../ripple/Ripple'; import { Tooltip } from '../tooltip/Tooltip'; import { classNames, IconUtils, ObjectUtils } from '../utils/Utils'; -export const Button = React.memo(React.forwardRef((props, ref) => { - const elementRef = React.useRef(ref); +export const Button = React.memo( + React.forwardRef((props, ref) => { + const elementRef = React.useRef(ref); - React.useEffect(() => { - ObjectUtils.combinedRefs(elementRef, ref); - }, [elementRef, ref]); + React.useEffect(() => { + ObjectUtils.combinedRefs(elementRef, ref); + }, [elementRef, ref]); - const createIcon = () => { - const icon = props.loading ? props.loadingIcon : props.icon; - const className = classNames('p-button-icon p-c', { - 'p-button-loading-icon': props.loading, - [`p-button-icon-${props.iconPos}`]: props.label - }); + const createIcon = () => { + const icon = props.loading ? props.loadingIcon : props.icon; + const className = classNames('p-button-icon p-c', { + 'p-button-loading-icon': props.loading, + [`p-button-icon-${props.iconPos}`]: props.label + }); - return IconUtils.getJSXIcon(icon, { className }, { props }); - } + return IconUtils.getJSXIcon(icon, { className }, { props }); + }; - const createLabel = () => { - if (props.label) { - return {props.label} - } + const createLabel = () => { + if (props.label) { + return {props.label}; + } - return !props.children && !props.label && - } + return !props.children && !props.label && ; + }; - const createBadge = () => { - if (props.badge) { - const badgeClassName = classNames('p-badge', props.badgeClassName); + const createBadge = () => { + if (props.badge) { + const badgeClassName = classNames('p-badge', props.badgeClassName); - return {props.badge} - } + return {props.badge}; + } - return null; - } + return null; + }; - const hasTooltip = ObjectUtils.isNotEmpty(props.tooltip); - const disabled = props.disabled || props.loading; - const otherProps = ObjectUtils.findDiffKeys(props, Button.defaultProps); - const className = classNames('p-button p-component', props.className, { - 'p-button-icon-only': (props.icon || (props.loading && props.loadingIcon)) && !props.label, - 'p-button-vertical': (props.iconPos === 'top' || props.iconPos === 'bottom') && props.label, - 'p-disabled': disabled, - 'p-button-loading': props.loading, - 'p-button-loading-label-only': props.loading && !props.icon && props.label, - [`p-button-loading-${props.iconPos}`]: props.loading && props.loadingIcon && props.label - }); + const hasTooltip = ObjectUtils.isNotEmpty(props.tooltip); + const disabled = props.disabled || props.loading; + const otherProps = ObjectUtils.findDiffKeys(props, Button.defaultProps); + const className = classNames('p-button p-component', props.className, { + 'p-button-icon-only': (props.icon || (props.loading && props.loadingIcon)) && !props.label, + 'p-button-vertical': (props.iconPos === 'top' || props.iconPos === 'bottom') && props.label, + 'p-disabled': disabled, + 'p-button-loading': props.loading, + 'p-button-loading-label-only': props.loading && !props.icon && props.label, + [`p-button-loading-${props.iconPos}`]: props.loading && props.loadingIcon && props.label + }); - const icon = createIcon(); - const label = createLabel(); - const badge = createBadge(); - const defaultAriaLabel = (props.label ? props.label + (props.badge ? ' ' + props.badge : '') : props['aria-label']); + const icon = createIcon(); + const label = createLabel(); + const badge = createBadge(); + const defaultAriaLabel = props.label ? props.label + (props.badge ? ' ' + props.badge : '') : props['aria-label']; - return ( - <> - - {hasTooltip && } - - ) -})); + return ( + <> + + {hasTooltip && } + + ); + }) +); Button.displayName = 'Button'; Button.defaultProps = { @@ -82,4 +84,4 @@ Button.defaultProps = { disabled: false, loading: false, loadingIcon: 'pi pi-spinner pi-spin' -} +}; diff --git a/components/lib/button/button.d.ts b/components/lib/button/button.d.ts index 81a6020fda..5586aff043 100644 --- a/components/lib/button/button.d.ts +++ b/components/lib/button/button.d.ts @@ -4,7 +4,7 @@ import { IconType } from '../utils'; type ButtonPositionType = 'top' | 'bottom' | 'left' | 'right'; -export interface ButtonProps extends Omit, HTMLButtonElement>, 'disabled'|'ref'> { +export interface ButtonProps extends Omit, HTMLButtonElement>, 'disabled' | 'ref'> { label?: string; icon?: IconType; iconPos?: ButtonPositionType; @@ -18,6 +18,6 @@ export interface ButtonProps extends Omit { +export declare class Button extends React.Component { public getElement(): HTMLButtonElement; } diff --git a/components/lib/calendar/Calendar.js b/components/lib/calendar/Calendar.js index bc0db37a6c..220e4e4221 100644 --- a/components/lib/calendar/Calendar.js +++ b/components/lib/calendar/Calendar.js @@ -8,3152 +8,3112 @@ import { DomHandler, ObjectUtils, classNames, mask, ZIndexUtils, UniqueComponent import { Ripple } from '../ripple/Ripple'; import { CalendarPanel } from './CalendarPanel'; -export const Calendar = React.memo(React.forwardRef((props, ref) => { - const [focusedState, setFocusedState] = React.useState(false); - const [overlayVisibleState, setOverlayVisibleState] = React.useState(false); - const [viewDateState, setViewDateState] = React.useState(null); - const elementRef = React.useRef(null); - const overlayRef = React.useRef(null); - const inputRef = React.useRef(props.inputRef); - const navigation = React.useRef(null); - const ignoreFocusFunctionality = React.useRef(false); - const isKeydown = React.useRef(false); - const timePickerTimer = React.useRef(null); - const viewStateChanged = React.useRef(false); - const touchUIMask = React.useRef(null); - const overlayEventListener = React.useRef(null); - const touchUIMaskClickListener = React.useRef(null); - const isOverlayClicked = React.useRef(false); - const ignoreMaskChange = React.useRef(false); - - const [currentView, setCurrentView] = React.useState('date') - const [currentMonth, setCurrentMonth] = React.useState(null); - const [currentYear, setCurrentYear] = React.useState(null); - const [yearOptions, setYearOptions] = React.useState([]); - - const previousValue = usePrevious(props.value); - const visible = props.inline || (props.onVisibleChange ? props.visible : overlayVisibleState); - const attributeSelector = UniqueComponentId(); - - const [bindOverlayListener, unbindOverlayListener] = useOverlayListener({ - target: elementRef, overlay: overlayRef, listener: (event, { type, valid }) => { - if (valid) { - (type === 'outside') ? - (!isOverlayClicked.current && !isNavIconClicked(event.target)) && hide('outside') : hide(); - } - - isOverlayClicked.current = false; - }, when: !(props.touchUI || props.inline) && visible - }); - - const getDateFormat = () => { - return props.dateFormat || localeOption('dateFormat', props.locale); - } - - const onInputFocus = (event) => { - if (ignoreFocusFunctionality.current) { - setFocusedState(true); - ignoreFocusFunctionality.current = false; - } - else { - if (props.showOnFocus && !visible) { - show(); - } - - setFocusedState(true); - props.onFocus && props.onFocus(event); - } - } - - const onInputBlur = (event) => { - setFocusedState(false); - !props.keepInvalid && updateInputfield(props.value); - props.onBlur && props.onBlur(event); - } - - const onInputKeyDown = (event) => { - isKeydown.current = true; - - switch (event.which) { - //escape - case 27: { - hide(); - break; - } - - //tab - case 9: { - visible && trapFocus(event); - props.touchUI && disableModality(); - break; - } - - default: - //no op - break; - } - } - - const onUserInput = (event) => { - // IE 11 Workaround for input placeholder - if (!isKeydown.current) { - return; - } - isKeydown.current = false; - - updateValueOnInput(event, event.target.value); - props.onInput && props.onInput(event); - } - - const updateValueOnInput = (event, rawValue) => { - try { - const value = parseValueFromString(rawValue); - if (isValidSelection(value)) { - updateModel(event, value); - updateViewDate(event, value.length ? value[0] : value); - } - } - catch (err) { - //invalid date - const value = props.keepInvalid ? rawValue : null; - updateModel(event, value); - } - } - - const reFocusInputField = () => { - if (!props.inline && inputRef.current) { - ignoreFocusFunctionality.current = true; - DomHandler.focus(inputRef.current); - } - } - - const isValidSelection = (value) => { - let isValid = true; - if (isSingleSelection()) { - if (!(isSelectable(value.getDate(), value.getMonth(), value.getFullYear(), false) && isSelectableTime(value))) { - isValid = false; - } - } - else if (value.every(v => (isSelectable(v.getDate(), v.getMonth(), v.getFullYear(), false) && isSelectableTime(v)))) { - if (isRangeSelection()) { - isValid = value.length > 1 && value[1] > value[0] ? true : false; - } - } - - return isValid; - } - - const onButtonClick = () => { - visible ? hide() : show(); - } - - const onPrevButtonClick = (event) => { - navigation.current = { backward: true, button: true }; - navBackward(event); - } - - const onNextButtonClick = (event) => { - navigation.current = { backward: false, button: true }; - navForward(event); - } - - const onContainerButtonKeydown = (event) => { - switch (event.which) { - //tab - case 9: - trapFocus(event); - break; - - //escape - case 27: - hide(null, reFocusInputField); - event.preventDefault(); - break; +export const Calendar = React.memo( + React.forwardRef((props, ref) => { + const [focusedState, setFocusedState] = React.useState(false); + const [overlayVisibleState, setOverlayVisibleState] = React.useState(false); + const [viewDateState, setViewDateState] = React.useState(null); + const elementRef = React.useRef(null); + const overlayRef = React.useRef(null); + const inputRef = React.useRef(props.inputRef); + const navigation = React.useRef(null); + const ignoreFocusFunctionality = React.useRef(false); + const isKeydown = React.useRef(false); + const timePickerTimer = React.useRef(null); + const viewStateChanged = React.useRef(false); + const touchUIMask = React.useRef(null); + const overlayEventListener = React.useRef(null); + const touchUIMaskClickListener = React.useRef(null); + const isOverlayClicked = React.useRef(false); + const ignoreMaskChange = React.useRef(false); + + const [currentView, setCurrentView] = React.useState('date'); + const [currentMonth, setCurrentMonth] = React.useState(null); + const [currentYear, setCurrentYear] = React.useState(null); + const [yearOptions, setYearOptions] = React.useState([]); + + const previousValue = usePrevious(props.value); + const visible = props.inline || (props.onVisibleChange ? props.visible : overlayVisibleState); + const attributeSelector = UniqueComponentId(); + + const [bindOverlayListener, unbindOverlayListener] = useOverlayListener({ + target: elementRef, + overlay: overlayRef, + listener: (event, { type, valid }) => { + if (valid) { + type === 'outside' ? !isOverlayClicked.current && !isNavIconClicked(event.target) && hide('outside') : hide(); + } + + isOverlayClicked.current = false; + }, + when: !(props.touchUI || props.inline) && visible + }); - default: - //Noop - break; - } - } + const getDateFormat = () => { + return props.dateFormat || localeOption('dateFormat', props.locale); + }; - const trapFocus = (event) => { - event.preventDefault(); - const focusableElements = DomHandler.getFocusableElements(overlayRef.current); + const onInputFocus = (event) => { + if (ignoreFocusFunctionality.current) { + setFocusedState(true); + ignoreFocusFunctionality.current = false; + } else { + if (props.showOnFocus && !visible) { + show(); + } - if (focusableElements && focusableElements.length > 0) { - if (!document.activeElement) { - focusableElements[0].focus(); + setFocusedState(true); + props.onFocus && props.onFocus(event); } - else { - const focusedIndex = focusableElements.indexOf(document.activeElement); + }; - if (event.shiftKey) { - if (focusedIndex === -1 || focusedIndex === 0) - focusableElements[focusableElements.length - 1].focus(); - else - focusableElements[focusedIndex - 1].focus(); + const onInputBlur = (event) => { + setFocusedState(false); + !props.keepInvalid && updateInputfield(props.value); + props.onBlur && props.onBlur(event); + }; + + const onInputKeyDown = (event) => { + isKeydown.current = true; + + switch (event.which) { + //escape + case 27: { + hide(); + break; } - else { - if (focusedIndex === -1 || focusedIndex === (focusableElements.length - 1)) - focusableElements[0].focus(); - else - focusableElements[focusedIndex + 1].focus(); + + //tab + case 9: { + visible && trapFocus(event); + props.touchUI && disableModality(); + break; } + + default: + //no op + break; } - } - } + }; - const updateFocus = () => { - if (navigation.current) { - if (navigation.current.button) { - initFocusableCell(); + const onUserInput = (event) => { + // IE 11 Workaround for input placeholder + if (!isKeydown.current) { + return; + } + isKeydown.current = false; - if (navigation.current.backward) - DomHandler.findSingle(overlayRef.current, '.p-datepicker-prev').focus(); - else - DomHandler.findSingle(overlayRef.current, '.p-datepicker-next').focus(); - } - else { - let cell; - if (navigation.current.backward) { - let cells = DomHandler.find(overlayRef.current, '.p-datepicker-calendar td span:not(.p-disabled)'); - cell = cells[cells.length - 1]; - } - else { - cell = DomHandler.findSingle(overlayRef.current, '.p-datepicker-calendar td span:not(.p-disabled)'); - } - - if (cell) { - cell.tabIndex = '0'; - cell.focus(); - } - } - - navigation.current = null; - } - else { - initFocusableCell(); - } - } - - const initFocusableCell = () => { - let cell; - if (props.view === 'month') { - const cells = DomHandler.find(overlayRef.current, '.p-monthpicker .p-monthpicker-month'); - const selectedCell = DomHandler.findSingle(overlayRef.current, '.p-monthpicker .p-monthpicker-month.p-highlight'); - cells.forEach(cell => cell.tabIndex = -1); - cell = selectedCell || cells[0]; - } - else { - cell = DomHandler.findSingle(overlayRef.current, 'span.p-highlight'); - if (!cell) { - const todayCell = DomHandler.findSingle(overlayRef.current, 'td.p-datepicker-today span:not(.p-disabled)'); - cell = todayCell || DomHandler.findSingle(overlayRef.current, '.p-datepicker-calendar td span:not(.p-disabled)'); - } - } - - if (cell) { - cell.tabIndex = '0'; - } - } - - const navBackward = (event) => { - if (props.disabled) { - event.preventDefault(); - return; - } + updateValueOnInput(event, event.target.value); + props.onInput && props.onInput(event); + }; - let newViewDate = new Date(getViewDate().getTime()); - newViewDate.setDate(1); + const updateValueOnInput = (event, rawValue) => { + try { + const value = parseValueFromString(rawValue); + if (isValidSelection(value)) { + updateModel(event, value); + updateViewDate(event, value.length ? value[0] : value); + } + } catch (err) { + //invalid date + const value = props.keepInvalid ? rawValue : null; + updateModel(event, value); + } + }; - if (currentView === 'date') { - if (newViewDate.getMonth() === 0) { - newViewDate.setMonth(11); - newViewDate.setFullYear(decrementYear()); - setCurrentMonth(11); + const reFocusInputField = () => { + if (!props.inline && inputRef.current) { + ignoreFocusFunctionality.current = true; + DomHandler.focus(inputRef.current); } - else { - newViewDate.setMonth(newViewDate.getMonth() - 1); - setCurrentMonth(prevState => prevState - 1) + }; + + const isValidSelection = (value) => { + let isValid = true; + if (isSingleSelection()) { + if (!(isSelectable(value.getDate(), value.getMonth(), value.getFullYear(), false) && isSelectableTime(value))) { + isValid = false; + } + } else if (value.every((v) => isSelectable(v.getDate(), v.getMonth(), v.getFullYear(), false) && isSelectableTime(v))) { + if (isRangeSelection()) { + isValid = value.length > 1 && value[1] > value[0] ? true : false; + } } - } - else if (currentView === 'month') { - let newYear = newViewDate.getFullYear() - 1; - if (props.yearNavigator) { - const minYear = parseInt(props.yearRange.split(':')[0], 10); + return isValid; + }; + + const onButtonClick = () => { + visible ? hide() : show(); + }; + + const onPrevButtonClick = (event) => { + navigation.current = { backward: true, button: true }; + navBackward(event); + }; + + const onNextButtonClick = (event) => { + navigation.current = { backward: false, button: true }; + navForward(event); + }; + + const onContainerButtonKeydown = (event) => { + switch (event.which) { + //tab + case 9: + trapFocus(event); + break; + + //escape + case 27: + hide(null, reFocusInputField); + event.preventDefault(); + break; + + default: + //Noop + break; + } + }; + + const trapFocus = (event) => { + event.preventDefault(); + const focusableElements = DomHandler.getFocusableElements(overlayRef.current); + + if (focusableElements && focusableElements.length > 0) { + if (!document.activeElement) { + focusableElements[0].focus(); + } else { + const focusedIndex = focusableElements.indexOf(document.activeElement); - if (newYear < minYear) { - newYear = minYear; + if (event.shiftKey) { + if (focusedIndex === -1 || focusedIndex === 0) focusableElements[focusableElements.length - 1].focus(); + else focusableElements[focusedIndex - 1].focus(); + } else { + if (focusedIndex === -1 || focusedIndex === focusableElements.length - 1) focusableElements[0].focus(); + else focusableElements[focusedIndex + 1].focus(); + } } } + }; - newViewDate.setFullYear(newYear); - } + const updateFocus = () => { + if (navigation.current) { + if (navigation.current.button) { + initFocusableCell(); - if (currentView === 'month') { - newViewDate.setFullYear(decrementYear()); - } - else if (currentView === 'year') { - newViewDate.setFullYear(decrementDecade()); - } + if (navigation.current.backward) DomHandler.findSingle(overlayRef.current, '.p-datepicker-prev').focus(); + else DomHandler.findSingle(overlayRef.current, '.p-datepicker-next').focus(); + } else { + let cell; + if (navigation.current.backward) { + let cells = DomHandler.find(overlayRef.current, '.p-datepicker-calendar td span:not(.p-disabled)'); + cell = cells[cells.length - 1]; + } else { + cell = DomHandler.findSingle(overlayRef.current, '.p-datepicker-calendar td span:not(.p-disabled)'); + } - updateViewDate(event, newViewDate); + if (cell) { + cell.tabIndex = '0'; + cell.focus(); + } + } - event.preventDefault(); - } + navigation.current = null; + } else { + initFocusableCell(); + } + }; - const navForward = (event) => { - if (props.disabled) { - event.preventDefault(); - return; - } + const initFocusableCell = () => { + let cell; + if (props.view === 'month') { + const cells = DomHandler.find(overlayRef.current, '.p-monthpicker .p-monthpicker-month'); + const selectedCell = DomHandler.findSingle(overlayRef.current, '.p-monthpicker .p-monthpicker-month.p-highlight'); + cells.forEach((cell) => (cell.tabIndex = -1)); + cell = selectedCell || cells[0]; + } else { + cell = DomHandler.findSingle(overlayRef.current, 'span.p-highlight'); + if (!cell) { + const todayCell = DomHandler.findSingle(overlayRef.current, 'td.p-datepicker-today span:not(.p-disabled)'); + cell = todayCell || DomHandler.findSingle(overlayRef.current, '.p-datepicker-calendar td span:not(.p-disabled)'); + } + } - let newViewDate = new Date(getViewDate().getTime()); - newViewDate.setDate(1); + if (cell) { + cell.tabIndex = '0'; + } + }; - if (currentView === 'date') { - if (newViewDate.getMonth() === 11) { - newViewDate.setMonth(0); - newViewDate.setFullYear(incrementYear()); - setCurrentMonth(0); + const navBackward = (event) => { + if (props.disabled) { + event.preventDefault(); + return; + } + + let newViewDate = new Date(getViewDate().getTime()); + newViewDate.setDate(1); + + if (currentView === 'date') { + if (newViewDate.getMonth() === 0) { + newViewDate.setMonth(11); + newViewDate.setFullYear(decrementYear()); + setCurrentMonth(11); + } else { + newViewDate.setMonth(newViewDate.getMonth() - 1); + setCurrentMonth((prevState) => prevState - 1); + } + } else if (currentView === 'month') { + let newYear = newViewDate.getFullYear() - 1; + + if (props.yearNavigator) { + const minYear = parseInt(props.yearRange.split(':')[0], 10); + + if (newYear < minYear) { + newYear = minYear; + } + } + + newViewDate.setFullYear(newYear); } - else { - newViewDate.setMonth(newViewDate.getMonth() + 1); - setCurrentMonth(prevState => prevState + 1) + + if (currentView === 'month') { + newViewDate.setFullYear(decrementYear()); + } else if (currentView === 'year') { + newViewDate.setFullYear(decrementDecade()); } - } - else if (currentView === 'month') { - let newYear = newViewDate.getFullYear() + 1; - if (props.yearNavigator) { - const maxYear = parseInt(props.yearRange.split(':')[1], 10); + updateViewDate(event, newViewDate); + + event.preventDefault(); + }; + + const navForward = (event) => { + if (props.disabled) { + event.preventDefault(); + return; + } + + let newViewDate = new Date(getViewDate().getTime()); + newViewDate.setDate(1); - if (newYear > maxYear) { - newYear = maxYear; + if (currentView === 'date') { + if (newViewDate.getMonth() === 11) { + newViewDate.setMonth(0); + newViewDate.setFullYear(incrementYear()); + setCurrentMonth(0); + } else { + newViewDate.setMonth(newViewDate.getMonth() + 1); + setCurrentMonth((prevState) => prevState + 1); + } + } else if (currentView === 'month') { + let newYear = newViewDate.getFullYear() + 1; + + if (props.yearNavigator) { + const maxYear = parseInt(props.yearRange.split(':')[1], 10); + + if (newYear > maxYear) { + newYear = maxYear; + } } + + newViewDate.setFullYear(newYear); } - newViewDate.setFullYear(newYear); - } + if (currentView === 'month') { + newViewDate.setFullYear(incrementYear()); + } else if (currentView === 'year') { + newViewDate.setFullYear(incrementDecade()); + } - if (currentView === 'month') { - newViewDate.setFullYear(incrementYear()); - } - else if (currentView === 'year') { - newViewDate.setFullYear(incrementDecade()); - } + updateViewDate(event, newViewDate); - updateViewDate(event, newViewDate); + event.preventDefault(); + }; - event.preventDefault(); - } + const populateYearOptions = (start, end) => { + let _yearOptions = []; - const populateYearOptions = (start, end) => { - let _yearOptions = []; + for (let i = start; i <= end; i++) { + yearOptions.push(i); + } - for (let i = start; i <= end; i++) { - yearOptions.push(i); - } + setYearOptions(_yearOptions); + }; + + const decrementYear = () => { + const _currentYear = currentYear - 1; + setCurrentYear(_currentYear); - setYearOptions(_yearOptions) - } + if (props.yearNavigator && _currentYear < yearOptions[0]) { + let difference = yearOptions[yearOptions.length - 1] - yearOptions[0]; + populateYearOptions(yearOptions[0] - difference, yearOptions[yearOptions.length - 1] - difference); + } + return _currentYear; + }; - const decrementYear = () => { - const _currentYear = currentYear - 1 - setCurrentYear(_currentYear); + const incrementYear = () => { + const _currentYear = currentYear + 1; + setCurrentYear(_currentYear); - if (props.yearNavigator && _currentYear < yearOptions[0]) { - let difference = yearOptions[yearOptions.length - 1] - yearOptions[0]; - populateYearOptions(yearOptions[0] - difference, yearOptions[yearOptions.length - 1] - difference); - } - return _currentYear; - } + if (props.yearNavigator && _currentYear.current > yearOptions[yearOptions.length - 1]) { + let difference = yearOptions[yearOptions.length - 1] - yearOptions[0]; + populateYearOptions(yearOptions[0] + difference, yearOptions[yearOptions.length - 1] + difference); + } + return _currentYear; + }; - const incrementYear = () => { - const _currentYear = currentYear + 1 - setCurrentYear(_currentYear); + const onMonthDropdownChange = (event, value) => { + const currentViewDate = getViewDate(); + let newViewDate = new Date(currentViewDate.getTime()); + newViewDate.setMonth(parseInt(value, 10)); - if (props.yearNavigator && _currentYear.current > yearOptions[yearOptions.length - 1]) { - let difference = yearOptions[yearOptions.length - 1] - yearOptions[0]; - populateYearOptions(yearOptions[0] + difference, yearOptions[yearOptions.length - 1] + difference); - } - return _currentYear; - } + updateViewDate(event, newViewDate); + }; - const onMonthDropdownChange = (event, value) => { - const currentViewDate = getViewDate(); - let newViewDate = new Date(currentViewDate.getTime()); - newViewDate.setMonth(parseInt(value, 10)); + const onYearDropdownChange = (event, value) => { + const currentViewDate = getViewDate(); + let newViewDate = new Date(currentViewDate.getTime()); + newViewDate.setFullYear(parseInt(value, 10)); - updateViewDate(event, newViewDate); - } + updateViewDate(event, newViewDate); + }; - const onYearDropdownChange = (event, value) => { - const currentViewDate = getViewDate(); - let newViewDate = new Date(currentViewDate.getTime()); - newViewDate.setFullYear(parseInt(value, 10)); + const onTodayButtonClick = (event) => { + const today = new Date(); + const dateMeta = { day: today.getDate(), month: today.getMonth(), year: today.getFullYear(), today: true, selectable: true }; + const timeMeta = { hours: today.getHours(), minutes: today.getMinutes(), seconds: today.getSeconds(), milliseconds: today.getMilliseconds() }; - updateViewDate(event, newViewDate); - } + updateViewDate(event, today); + onDateSelect(event, dateMeta, timeMeta); - const onTodayButtonClick = (event) => { - const today = new Date(); - const dateMeta = { day: today.getDate(), month: today.getMonth(), year: today.getFullYear(), today: true, selectable: true }; - const timeMeta = { hours: today.getHours(), minutes: today.getMinutes(), seconds: today.getSeconds(), milliseconds: today.getMilliseconds() }; + props.onTodayButtonClick && props.onTodayButtonClick(event); + }; - updateViewDate(event, today); - onDateSelect(event, dateMeta, timeMeta); + const onClearButtonClick = (event) => { + updateModel(event, null); + updateInputfield(null); + hide(); - props.onTodayButtonClick && props.onTodayButtonClick(event); - } + props.onClearButtonClick && props.onClearButtonClick(event); + }; - const onClearButtonClick = (event) => { - updateModel(event, null); - updateInputfield(null); - hide(); + const onPanelClick = (event) => { + if (!props.inline) { + OverlayService.emit('overlay-click', { + originalEvent: event, + target: elementRef.current + }); + } + }; - props.onClearButtonClick && props.onClearButtonClick(event); - } + const onPanelMouseUp = (event) => { + onPanelClick(event); + }; - const onPanelClick = (event) => { - if (!props.inline) { - OverlayService.emit('overlay-click', { - originalEvent: event, - target: elementRef.current - }); - } - } + const onTimePickerElementMouseDown = (event, type, direction) => { + if (!props.disabled) { + repeat(event, null, type, direction); + event.preventDefault(); + } + }; - const onPanelMouseUp = (event) => { - onPanelClick(event); - } + const onTimePickerElementMouseUp = () => { + if (!props.disabled) { + clearTimePickerTimer(); + } + }; - const onTimePickerElementMouseDown = (event, type, direction) => { - if (!props.disabled) { - repeat(event, null, type, direction); - event.preventDefault(); - } - } + const onTimePickerElementMouseLeave = () => { + if (!props.disabled) { + clearTimePickerTimer(); + } + }; - const onTimePickerElementMouseUp = () => { - if (!props.disabled) { + const repeat = (event, interval, type, direction) => { clearTimePickerTimer(); - } - } + timePickerTimer.current = setTimeout(() => { + repeat(event, 100, type, direction); + }, interval || 500); + + switch (type) { + case 0: + if (direction === 1) incrementHour(event); + else decrementHour(event); + break; - const onTimePickerElementMouseLeave = () => { - if (!props.disabled) { - clearTimePickerTimer(); - } - } - - const repeat = (event, interval, type, direction) => { - clearTimePickerTimer(); - timePickerTimer.current = setTimeout(() => { - repeat(event, 100, type, direction); - }, interval || 500); - - switch (type) { - case 0: - if (direction === 1) - incrementHour(event); - else - decrementHour(event); - break; - - case 1: - if (direction === 1) - incrementMinute(event); - else - decrementMinute(event); - break; - - case 2: - if (direction === 1) - incrementSecond(event); - else - decrementSecond(event); - break; - - case 3: - if (direction === 1) - incrementMilliSecond(event); - else - decrementMilliSecond(event); - break; - - default: - break; - } - } - - const clearTimePickerTimer = () => { - if (timePickerTimer.current) { - clearTimeout(timePickerTimer.current); - } - } - - const incrementHour = (event) => { - const currentTime = getCurrentDateTime(); - const currentHour = currentTime.getHours(); - let newHour = currentHour + props.stepHour; - newHour = (newHour >= 24) ? (newHour - 24) : newHour; - - if (validateHour(newHour, currentTime)) { - if (props.maxDate && props.maxDate.toDateString() === currentTime.toDateString() && props.maxDate.getHours() === newHour) { - if (props.maxDate.getMinutes() < currentTime.getMinutes()) { - if (props.maxDate.getSeconds() < currentTime.getSeconds()) { - if (props.maxDate.getMilliseconds() < currentTime.getMilliseconds()) { - updateTime(event, newHour, props.maxDate.getMinutes(), props.maxDate.getSeconds(), props.maxDate.getMilliseconds()); - } - else { - updateTime(event, newHour, props.maxDate.getMinutes(), props.maxDate.getSeconds(), currentTime.getMilliseconds()); - } - } - else { - updateTime(event, newHour, props.maxDate.getMinutes(), currentTime.getSeconds(), currentTime.getMilliseconds()); - } - } - else if (props.maxDate.getMinutes() === currentTime.getMinutes()) { - if (props.maxDate.getSeconds() < currentTime.getSeconds()) { - if (props.maxDate.getMilliseconds() < currentTime.getMilliseconds()) { - updateTime(event, newHour, props.maxDate.getMinutes(), props.maxDate.getSeconds(), props.maxDate.getMilliseconds()); + case 1: + if (direction === 1) incrementMinute(event); + else decrementMinute(event); + break; + + case 2: + if (direction === 1) incrementSecond(event); + else decrementSecond(event); + break; + + case 3: + if (direction === 1) incrementMilliSecond(event); + else decrementMilliSecond(event); + break; + + default: + break; + } + }; + + const clearTimePickerTimer = () => { + if (timePickerTimer.current) { + clearTimeout(timePickerTimer.current); + } + }; + + const incrementHour = (event) => { + const currentTime = getCurrentDateTime(); + const currentHour = currentTime.getHours(); + let newHour = currentHour + props.stepHour; + newHour = newHour >= 24 ? newHour - 24 : newHour; + + if (validateHour(newHour, currentTime)) { + if (props.maxDate && props.maxDate.toDateString() === currentTime.toDateString() && props.maxDate.getHours() === newHour) { + if (props.maxDate.getMinutes() < currentTime.getMinutes()) { + if (props.maxDate.getSeconds() < currentTime.getSeconds()) { + if (props.maxDate.getMilliseconds() < currentTime.getMilliseconds()) { + updateTime(event, newHour, props.maxDate.getMinutes(), props.maxDate.getSeconds(), props.maxDate.getMilliseconds()); + } else { + updateTime(event, newHour, props.maxDate.getMinutes(), props.maxDate.getSeconds(), currentTime.getMilliseconds()); + } + } else { + updateTime(event, newHour, props.maxDate.getMinutes(), currentTime.getSeconds(), currentTime.getMilliseconds()); } - else { - updateTime(event, newHour, props.maxDate.getMinutes(), props.maxDate.getSeconds(), currentTime.getMilliseconds()); + } else if (props.maxDate.getMinutes() === currentTime.getMinutes()) { + if (props.maxDate.getSeconds() < currentTime.getSeconds()) { + if (props.maxDate.getMilliseconds() < currentTime.getMilliseconds()) { + updateTime(event, newHour, props.maxDate.getMinutes(), props.maxDate.getSeconds(), props.maxDate.getMilliseconds()); + } else { + updateTime(event, newHour, props.maxDate.getMinutes(), props.maxDate.getSeconds(), currentTime.getMilliseconds()); + } + } else { + updateTime(event, newHour, props.maxDate.getMinutes(), currentTime.getSeconds(), currentTime.getMilliseconds()); } + } else { + updateTime(event, newHour, currentTime.getMinutes(), currentTime.getSeconds(), currentTime.getMilliseconds()); } - else { - updateTime(event, newHour, props.maxDate.getMinutes(), currentTime.getSeconds(), currentTime.getMilliseconds()); - } - } - else { + } else { updateTime(event, newHour, currentTime.getMinutes(), currentTime.getSeconds(), currentTime.getMilliseconds()); } } - else { - updateTime(event, newHour, currentTime.getMinutes(), currentTime.getSeconds(), currentTime.getMilliseconds()); - } - } - - event.preventDefault(); - } - const decrementHour = (event) => { - const currentTime = getCurrentDateTime(); - const currentHour = currentTime.getHours(); - let newHour = currentHour - props.stepHour; - newHour = (newHour < 0) ? (newHour + 24) : newHour; + event.preventDefault(); + }; - if (validateHour(newHour, currentTime)) { - if (props.minDate && props.minDate.toDateString() === currentTime.toDateString() && props.minDate.getHours() === newHour) { - if (props.minDate.getMinutes() > currentTime.getMinutes()) { - if (props.minDate.getSeconds() > currentTime.getSeconds()) { - if (props.minDate.getMilliseconds() > currentTime.getMilliseconds()) { - updateTime(event, newHour, props.minDate.getMinutes(), props.minDate.getSeconds(), props.minDate.getMilliseconds()); - } - else { - updateTime(event, newHour, props.minDate.getMinutes(), props.minDate.getSeconds(), currentTime.getMilliseconds()); - } - } - else { - updateTime(event, newHour, props.minDate.getMinutes(), currentTime.getSeconds(), currentTime.getMilliseconds()); - } - } - else if (props.minDate.getMinutes() === currentTime.getMinutes()) { - if (props.minDate.getSeconds() > currentTime.getSeconds()) { - if (props.minDate.getMilliseconds() > currentTime.getMilliseconds()) { - updateTime(event, newHour, props.minDate.getMinutes(), props.minDate.getSeconds(), props.minDate.getMilliseconds()); + const decrementHour = (event) => { + const currentTime = getCurrentDateTime(); + const currentHour = currentTime.getHours(); + let newHour = currentHour - props.stepHour; + newHour = newHour < 0 ? newHour + 24 : newHour; + + if (validateHour(newHour, currentTime)) { + if (props.minDate && props.minDate.toDateString() === currentTime.toDateString() && props.minDate.getHours() === newHour) { + if (props.minDate.getMinutes() > currentTime.getMinutes()) { + if (props.minDate.getSeconds() > currentTime.getSeconds()) { + if (props.minDate.getMilliseconds() > currentTime.getMilliseconds()) { + updateTime(event, newHour, props.minDate.getMinutes(), props.minDate.getSeconds(), props.minDate.getMilliseconds()); + } else { + updateTime(event, newHour, props.minDate.getMinutes(), props.minDate.getSeconds(), currentTime.getMilliseconds()); + } + } else { + updateTime(event, newHour, props.minDate.getMinutes(), currentTime.getSeconds(), currentTime.getMilliseconds()); } - else { - updateTime(event, newHour, props.minDate.getMinutes(), props.minDate.getSeconds(), currentTime.getMilliseconds()); + } else if (props.minDate.getMinutes() === currentTime.getMinutes()) { + if (props.minDate.getSeconds() > currentTime.getSeconds()) { + if (props.minDate.getMilliseconds() > currentTime.getMilliseconds()) { + updateTime(event, newHour, props.minDate.getMinutes(), props.minDate.getSeconds(), props.minDate.getMilliseconds()); + } else { + updateTime(event, newHour, props.minDate.getMinutes(), props.minDate.getSeconds(), currentTime.getMilliseconds()); + } + } else { + updateTime(event, newHour, props.minDate.getMinutes(), currentTime.getSeconds(), currentTime.getMilliseconds()); } + } else { + updateTime(event, newHour, currentTime.getMinutes(), currentTime.getSeconds(), currentTime.getMilliseconds()); } - else { - updateTime(event, newHour, props.minDate.getMinutes(), currentTime.getSeconds(), currentTime.getMilliseconds()); - } - } - else { + } else { updateTime(event, newHour, currentTime.getMinutes(), currentTime.getSeconds(), currentTime.getMilliseconds()); } } - else { - updateTime(event, newHour, currentTime.getMinutes(), currentTime.getSeconds(), currentTime.getMilliseconds()); - } - } - event.preventDefault(); - } + event.preventDefault(); + }; - const doStepMinute = (currentMinute, step) => { - if (props.stepMinute <= 1) { - return step ? currentMinute + step : currentMinute; - } - if (!step) { - step = props.stepMinute; - if (currentMinute % step === 0) { - return currentMinute; + const doStepMinute = (currentMinute, step) => { + if (props.stepMinute <= 1) { + return step ? currentMinute + step : currentMinute; + } + if (!step) { + step = props.stepMinute; + if (currentMinute % step === 0) { + return currentMinute; + } } - } - return Math.floor((currentMinute + step) / step) * step; - } + return Math.floor((currentMinute + step) / step) * step; + }; - const incrementMinute = (event) => { - const currentTime = getCurrentDateTime(); - const currentMinute = currentTime.getMinutes(); - let newMinute = doStepMinute(currentMinute, props.stepMinute); - newMinute = (newMinute > 59) ? (newMinute - 60) : newMinute; + const incrementMinute = (event) => { + const currentTime = getCurrentDateTime(); + const currentMinute = currentTime.getMinutes(); + let newMinute = doStepMinute(currentMinute, props.stepMinute); + newMinute = newMinute > 59 ? newMinute - 60 : newMinute; - if (validateMinute(newMinute, currentTime)) { - if (props.maxDate && props.maxDate.toDateString() === currentTime.toDateString() && props.maxDate.getMinutes() === newMinute) { - if (props.maxDate.getSeconds() < currentTime.getSeconds()) { - if (props.maxDate.getMilliseconds() < currentTime.getMilliseconds()) { - updateTime(event, currentTime.getHours(), newMinute, props.maxDate.getSeconds(), props.maxDate.getMilliseconds()); - } - else { - updateTime(event, currentTime.getHours(), newMinute, props.maxDate.getSeconds(), currentTime.getMilliseconds()); + if (validateMinute(newMinute, currentTime)) { + if (props.maxDate && props.maxDate.toDateString() === currentTime.toDateString() && props.maxDate.getMinutes() === newMinute) { + if (props.maxDate.getSeconds() < currentTime.getSeconds()) { + if (props.maxDate.getMilliseconds() < currentTime.getMilliseconds()) { + updateTime(event, currentTime.getHours(), newMinute, props.maxDate.getSeconds(), props.maxDate.getMilliseconds()); + } else { + updateTime(event, currentTime.getHours(), newMinute, props.maxDate.getSeconds(), currentTime.getMilliseconds()); + } + } else { + updateTime(event, currentTime.getHours(), newMinute, currentTime.getSeconds(), currentTime.getMilliseconds()); } - } - else { + } else { updateTime(event, currentTime.getHours(), newMinute, currentTime.getSeconds(), currentTime.getMilliseconds()); } } - else { - updateTime(event, currentTime.getHours(), newMinute, currentTime.getSeconds(), currentTime.getMilliseconds()); - } - } - event.preventDefault(); - } + event.preventDefault(); + }; - const decrementMinute = (event) => { - const currentTime = getCurrentDateTime(); - const currentMinute = currentTime.getMinutes(); - let newMinute = doStepMinute(currentMinute, -props.stepMinute); - newMinute = (newMinute < 0) ? (newMinute + 60) : newMinute; + const decrementMinute = (event) => { + const currentTime = getCurrentDateTime(); + const currentMinute = currentTime.getMinutes(); + let newMinute = doStepMinute(currentMinute, -props.stepMinute); + newMinute = newMinute < 0 ? newMinute + 60 : newMinute; - if (validateMinute(newMinute, currentTime)) { - if (props.minDate && props.minDate.toDateString() === currentTime.toDateString() && props.minDate.getMinutes() === newMinute) { - if (props.minDate.getSeconds() > currentTime.getSeconds()) { - if (props.minDate.getMilliseconds() > currentTime.getMilliseconds()) { - updateTime(event, currentTime.getHours(), newMinute, props.minDate.getSeconds(), props.minDate.getMilliseconds()); - } - else { - updateTime(event, currentTime.getHours(), newMinute, props.minDate.getSeconds(), currentTime.getMilliseconds()); + if (validateMinute(newMinute, currentTime)) { + if (props.minDate && props.minDate.toDateString() === currentTime.toDateString() && props.minDate.getMinutes() === newMinute) { + if (props.minDate.getSeconds() > currentTime.getSeconds()) { + if (props.minDate.getMilliseconds() > currentTime.getMilliseconds()) { + updateTime(event, currentTime.getHours(), newMinute, props.minDate.getSeconds(), props.minDate.getMilliseconds()); + } else { + updateTime(event, currentTime.getHours(), newMinute, props.minDate.getSeconds(), currentTime.getMilliseconds()); + } + } else { + updateTime(event, currentTime.getHours(), newMinute, currentTime.getSeconds(), currentTime.getMilliseconds()); } - } - else { + } else { updateTime(event, currentTime.getHours(), newMinute, currentTime.getSeconds(), currentTime.getMilliseconds()); } } - else { - updateTime(event, currentTime.getHours(), newMinute, currentTime.getSeconds(), currentTime.getMilliseconds()); - } - } - event.preventDefault(); - } + event.preventDefault(); + }; - const incrementSecond = (event) => { - const currentTime = getCurrentDateTime(); - const currentSecond = currentTime.getSeconds(); - let newSecond = currentSecond + props.stepSecond; - newSecond = (newSecond > 59) ? (newSecond - 60) : newSecond; + const incrementSecond = (event) => { + const currentTime = getCurrentDateTime(); + const currentSecond = currentTime.getSeconds(); + let newSecond = currentSecond + props.stepSecond; + newSecond = newSecond > 59 ? newSecond - 60 : newSecond; - if (validateSecond(newSecond, currentTime)) { - if (props.maxDate && props.maxDate.toDateString() === currentTime.toDateString() && props.maxDate.getSeconds() === newSecond) { - if (props.maxDate.getMilliseconds() < currentTime.getMilliseconds()) { - updateTime(event, currentTime.getHours(), currentTime.getMinutes(), newSecond, props.maxDate.getMilliseconds()); - } - else { + if (validateSecond(newSecond, currentTime)) { + if (props.maxDate && props.maxDate.toDateString() === currentTime.toDateString() && props.maxDate.getSeconds() === newSecond) { + if (props.maxDate.getMilliseconds() < currentTime.getMilliseconds()) { + updateTime(event, currentTime.getHours(), currentTime.getMinutes(), newSecond, props.maxDate.getMilliseconds()); + } else { + updateTime(event, currentTime.getHours(), currentTime.getMinutes(), newSecond, currentTime.getMilliseconds()); + } + } else { updateTime(event, currentTime.getHours(), currentTime.getMinutes(), newSecond, currentTime.getMilliseconds()); } } - else { - updateTime(event, currentTime.getHours(), currentTime.getMinutes(), newSecond, currentTime.getMilliseconds()); - } - } - event.preventDefault(); - } + event.preventDefault(); + }; - const decrementSecond = (event) => { - const currentTime = getCurrentDateTime(); - const currentSecond = currentTime.getSeconds(); - let newSecond = currentSecond - props.stepSecond; - newSecond = (newSecond < 0) ? (newSecond + 60) : newSecond; + const decrementSecond = (event) => { + const currentTime = getCurrentDateTime(); + const currentSecond = currentTime.getSeconds(); + let newSecond = currentSecond - props.stepSecond; + newSecond = newSecond < 0 ? newSecond + 60 : newSecond; - if (validateSecond(newSecond, currentTime)) { - if (props.minDate && props.minDate.toDateString() === currentTime.toDateString() && props.minDate.getSeconds() === newSecond) { - if (props.minDate.getMilliseconds() > currentTime.getMilliseconds()) { - updateTime(event, currentTime.getHours(), currentTime.getMinutes(), newSecond, props.minDate.getMilliseconds()); - } - else { + if (validateSecond(newSecond, currentTime)) { + if (props.minDate && props.minDate.toDateString() === currentTime.toDateString() && props.minDate.getSeconds() === newSecond) { + if (props.minDate.getMilliseconds() > currentTime.getMilliseconds()) { + updateTime(event, currentTime.getHours(), currentTime.getMinutes(), newSecond, props.minDate.getMilliseconds()); + } else { + updateTime(event, currentTime.getHours(), currentTime.getMinutes(), newSecond, currentTime.getMilliseconds()); + } + } else { updateTime(event, currentTime.getHours(), currentTime.getMinutes(), newSecond, currentTime.getMilliseconds()); } } - else { - updateTime(event, currentTime.getHours(), currentTime.getMinutes(), newSecond, currentTime.getMilliseconds()); - } - } - event.preventDefault(); - } + event.preventDefault(); + }; - const incrementMilliSecond = (event) => { - const currentTime = getCurrentDateTime(); - const currentMillisecond = currentTime.getMilliseconds(); - let newMillisecond = currentMillisecond + props.stepMillisec; - newMillisecond = (newMillisecond > 999) ? (newMillisecond - 1000) : newMillisecond; + const incrementMilliSecond = (event) => { + const currentTime = getCurrentDateTime(); + const currentMillisecond = currentTime.getMilliseconds(); + let newMillisecond = currentMillisecond + props.stepMillisec; + newMillisecond = newMillisecond > 999 ? newMillisecond - 1000 : newMillisecond; - if (validateMillisecond(newMillisecond, currentTime)) { - updateTime(event, currentTime.getHours(), currentTime.getMinutes(), currentTime.getSeconds(), newMillisecond); - } + if (validateMillisecond(newMillisecond, currentTime)) { + updateTime(event, currentTime.getHours(), currentTime.getMinutes(), currentTime.getSeconds(), newMillisecond); + } - event.preventDefault(); - } + event.preventDefault(); + }; - const decrementMilliSecond = (event) => { - const currentTime = getCurrentDateTime(); - const currentMillisecond = currentTime.getMilliseconds(); - let newMillisecond = currentMillisecond - props.stepMillisec; - newMillisecond = (newMillisecond < 0) ? (newMillisecond + 999) : newMillisecond; + const decrementMilliSecond = (event) => { + const currentTime = getCurrentDateTime(); + const currentMillisecond = currentTime.getMilliseconds(); + let newMillisecond = currentMillisecond - props.stepMillisec; + newMillisecond = newMillisecond < 0 ? newMillisecond + 999 : newMillisecond; - if (validateMillisecond(newMillisecond, currentTime)) { - updateTime(event, currentTime.getHours(), currentTime.getMinutes(), currentTime.getSeconds(), newMillisecond); - } + if (validateMillisecond(newMillisecond, currentTime)) { + updateTime(event, currentTime.getHours(), currentTime.getMinutes(), currentTime.getSeconds(), newMillisecond); + } - event.preventDefault(); - } + event.preventDefault(); + }; - const toggleAmPm = (event) => { - const currentTime = getCurrentDateTime(); - const currentHour = currentTime.getHours(); - const newHour = (currentHour >= 12) ? currentHour - 12 : currentHour + 12; + const toggleAmPm = (event) => { + const currentTime = getCurrentDateTime(); + const currentHour = currentTime.getHours(); + const newHour = currentHour >= 12 ? currentHour - 12 : currentHour + 12; - if (validateHour(convertTo24Hour(newHour, !(currentHour > 11)), currentTime)) { - updateTime(event, newHour, currentTime.getMinutes(), currentTime.getSeconds(), currentTime.getMilliseconds()); - } + if (validateHour(convertTo24Hour(newHour, !(currentHour > 11)), currentTime)) { + updateTime(event, newHour, currentTime.getMinutes(), currentTime.getSeconds(), currentTime.getMilliseconds()); + } - event.preventDefault(); - } + event.preventDefault(); + }; - const getViewDate = (date) => { - let propValue = props.value; - let viewDate = date || (props.onViewDateChange ? props.viewDate : viewDateState); - if (Array.isArray(propValue)) { - propValue = propValue[0]; - } + const getViewDate = (date) => { + let propValue = props.value; + let viewDate = date || (props.onViewDateChange ? props.viewDate : viewDateState); + if (Array.isArray(propValue)) { + propValue = propValue[0]; + } - return viewDate && isValidDate(viewDate) ? viewDate : (propValue && isValidDate(propValue) ? propValue : new Date()); - } + return viewDate && isValidDate(viewDate) ? viewDate : propValue && isValidDate(propValue) ? propValue : new Date(); + }; - const getCurrentDateTime = () => { - if (isSingleSelection()) { - return (props.value && props.value instanceof Date) ? props.value : getViewDate(); - } - else if (isMultipleSelection()) { - if (props.value && props.value.length) { - return props.value[props.value.length - 1]; - } - } - else if (isRangeSelection()) { - if (props.value && props.value.length) { - let startDate = props.value[0]; - let endDate = props.value[1]; + const getCurrentDateTime = () => { + if (isSingleSelection()) { + return props.value && props.value instanceof Date ? props.value : getViewDate(); + } else if (isMultipleSelection()) { + if (props.value && props.value.length) { + return props.value[props.value.length - 1]; + } + } else if (isRangeSelection()) { + if (props.value && props.value.length) { + let startDate = props.value[0]; + let endDate = props.value[1]; - return endDate || startDate; + return endDate || startDate; + } } - } - return new Date(); - } + return new Date(); + }; - const isValidDate = (date) => { - return date instanceof Date && !isNaN(date); - } + const isValidDate = (date) => { + return date instanceof Date && !isNaN(date); + }; - const convertTo24Hour = (hour, pm) => { - if (props.hourFormat == '12') { - return hour === 12 ? (pm ? 12 : 0) : (pm ? hour + 12 : hour); - } + const convertTo24Hour = (hour, pm) => { + if (props.hourFormat == '12') { + return hour === 12 ? (pm ? 12 : 0) : pm ? hour + 12 : hour; + } - return hour; - } + return hour; + }; - const validateHour = (hour, value) => { - let valid = true; - let valueDateString = value ? value.toDateString() : null; + const validateHour = (hour, value) => { + let valid = true; + let valueDateString = value ? value.toDateString() : null; - if (props.minDate && valueDateString && props.minDate.toDateString() === valueDateString) { - if (props.minDate.getHours() > hour) { - valid = false; + if (props.minDate && valueDateString && props.minDate.toDateString() === valueDateString) { + if (props.minDate.getHours() > hour) { + valid = false; + } } - } - if (props.maxDate && valueDateString && props.maxDate.toDateString() === valueDateString) { - if (props.maxDate.getHours() < hour) { - valid = false; + if (props.maxDate && valueDateString && props.maxDate.toDateString() === valueDateString) { + if (props.maxDate.getHours() < hour) { + valid = false; + } } - } - return valid; - } + return valid; + }; - const validateMinute = (minute, value) => { - let valid = true; - let valueDateString = value ? value.toDateString() : null; + const validateMinute = (minute, value) => { + let valid = true; + let valueDateString = value ? value.toDateString() : null; - if (props.minDate && valueDateString && props.minDate.toDateString() === valueDateString) { - if (value.getHours() === props.minDate.getHours()) { - if (props.minDate.getMinutes() > minute) { - valid = false; + if (props.minDate && valueDateString && props.minDate.toDateString() === valueDateString) { + if (value.getHours() === props.minDate.getHours()) { + if (props.minDate.getMinutes() > minute) { + valid = false; + } } } - } - if (props.maxDate && valueDateString && props.maxDate.toDateString() === valueDateString) { - if (value.getHours() === props.maxDate.getHours()) { - if (props.maxDate.getMinutes() < minute) { - valid = false; + if (props.maxDate && valueDateString && props.maxDate.toDateString() === valueDateString) { + if (value.getHours() === props.maxDate.getHours()) { + if (props.maxDate.getMinutes() < minute) { + valid = false; + } } } - } - return valid; - } + return valid; + }; - const validateSecond = (second, value) => { - let valid = true; - let valueDateString = value ? value.toDateString() : null; + const validateSecond = (second, value) => { + let valid = true; + let valueDateString = value ? value.toDateString() : null; - if (props.minDate && valueDateString && props.minDate.toDateString() === valueDateString) { - if (value.getHours() === props.minDate.getHours() && value.getMinutes() === props.minDate.getMinutes()) { - if (props.minDate.getSeconds() > second) { - valid = false; + if (props.minDate && valueDateString && props.minDate.toDateString() === valueDateString) { + if (value.getHours() === props.minDate.getHours() && value.getMinutes() === props.minDate.getMinutes()) { + if (props.minDate.getSeconds() > second) { + valid = false; + } } } - } - if (props.maxDate && valueDateString && props.maxDate.toDateString() === valueDateString) { - if (value.getHours() === props.maxDate.getHours() && value.getMinutes() === props.maxDate.getMinutes()) { - if (props.maxDate.getSeconds() < second) { - valid = false; + if (props.maxDate && valueDateString && props.maxDate.toDateString() === valueDateString) { + if (value.getHours() === props.maxDate.getHours() && value.getMinutes() === props.maxDate.getMinutes()) { + if (props.maxDate.getSeconds() < second) { + valid = false; + } } } - } - return valid; - } + return valid; + }; - const validateMillisecond = (millisecond, value) => { - let valid = true; - let valueDateString = value ? value.toDateString() : null; + const validateMillisecond = (millisecond, value) => { + let valid = true; + let valueDateString = value ? value.toDateString() : null; - if (props.minDate && valueDateString && props.minDate.toDateString() === valueDateString) { - if (value.getHours() === props.minDate.getHours() && value.getSeconds() === props.minDate.getSeconds() && value.getMinutes() === props.minDate.getMinutes()) { - if (props.minDate.getMilliseconds() > millisecond) { - valid = false; + if (props.minDate && valueDateString && props.minDate.toDateString() === valueDateString) { + if (value.getHours() === props.minDate.getHours() && value.getSeconds() === props.minDate.getSeconds() && value.getMinutes() === props.minDate.getMinutes()) { + if (props.minDate.getMilliseconds() > millisecond) { + valid = false; + } } } - } - if (props.maxDate && valueDateString && props.maxDate.toDateString() === valueDateString) { - if (value.getHours() === props.maxDate.getHours() && value.getSeconds() === props.maxDate.getSeconds() && value.getMinutes() === props.maxDate.getMinutes()) { - if (props.maxDate.getMilliseconds() < millisecond) { - valid = false; + if (props.maxDate && valueDateString && props.maxDate.toDateString() === valueDateString) { + if (value.getHours() === props.maxDate.getHours() && value.getSeconds() === props.maxDate.getSeconds() && value.getMinutes() === props.maxDate.getMinutes()) { + if (props.maxDate.getMilliseconds() < millisecond) { + valid = false; + } } } - } - return valid; - } + return valid; + }; - const validateDate = (value) => { - if (props.yearNavigator) { - let viewYear = value.getFullYear(); + const validateDate = (value) => { + if (props.yearNavigator) { + let viewYear = value.getFullYear(); - const minRangeYear = props.yearRange ? parseInt(props.yearRange.split(':')[0], 10) : null; - const maxRangeYear = props.yearRange ? parseInt(props.yearRange.split(':')[1], 10) : null; - const minYear = props.minDate && minRangeYear != null ? Math.max(props.minDate.getFullYear(), minRangeYear) : props.minDate || minRangeYear; - const maxYear = props.maxDate && maxRangeYear != null ? Math.min(props.maxDate.getFullYear(), maxRangeYear) : props.maxDate || maxRangeYear; + const minRangeYear = props.yearRange ? parseInt(props.yearRange.split(':')[0], 10) : null; + const maxRangeYear = props.yearRange ? parseInt(props.yearRange.split(':')[1], 10) : null; + const minYear = props.minDate && minRangeYear != null ? Math.max(props.minDate.getFullYear(), minRangeYear) : props.minDate || minRangeYear; + const maxYear = props.maxDate && maxRangeYear != null ? Math.min(props.maxDate.getFullYear(), maxRangeYear) : props.maxDate || maxRangeYear; - if (minYear && minYear > viewYear) { - viewYear = minYear; - } - if (maxYear && maxYear < viewYear) { - viewYear = maxYear + if (minYear && minYear > viewYear) { + viewYear = minYear; + } + if (maxYear && maxYear < viewYear) { + viewYear = maxYear; + } + + value.setFullYear(viewYear); } - value.setFullYear(viewYear); - } + if (props.monthNavigator && props.view !== 'month') { + let viewMonth = value.getMonth(); + let viewMonthWithMinMax = parseInt((isInMinYear(value) && Math.max(props.minDate.getMonth(), viewMonth).toString()) || (isInMaxYear(value) && Math.min(props.maxDate.getMonth(), viewMonth).toString()) || viewMonth); - if (props.monthNavigator && props.view !== 'month') { - let viewMonth = value.getMonth(); - let viewMonthWithMinMax = parseInt((isInMinYear(value) && Math.max(props.minDate.getMonth(), viewMonth).toString()) || (isInMaxYear(value) && Math.min(props.maxDate.getMonth(), viewMonth).toString()) || viewMonth); + value.setMonth(viewMonthWithMinMax); + } + }; - value.setMonth(viewMonthWithMinMax); - } - } + const updateTime = (event, hour, minute, second, millisecond) => { + let newDateTime = getCurrentDateTime(); - const updateTime = (event, hour, minute, second, millisecond) => { - let newDateTime = getCurrentDateTime(); + newDateTime.setHours(hour); + newDateTime.setMinutes(minute); + newDateTime.setSeconds(second); + newDateTime.setMilliseconds(millisecond); - newDateTime.setHours(hour); - newDateTime.setMinutes(minute); - newDateTime.setSeconds(second); - newDateTime.setMilliseconds(millisecond); + if (isMultipleSelection()) { + if (props.value && props.value.length) { + let value = [...props.value]; + value[value.length - 1] = newDateTime; - if (isMultipleSelection()) { - if (props.value && props.value.length) { - let value = [...props.value]; - value[value.length - 1] = newDateTime; + newDateTime = value; + } else { + newDateTime = [newDateTime]; + } + } else if (isRangeSelection()) { + if (props.value && props.value.length) { + let startDate = props.value[0]; + let endDate = props.value[1]; - newDateTime = value; - } - else { - newDateTime = [newDateTime]; + newDateTime = endDate ? [startDate, newDateTime] : [newDateTime, null]; + } else { + newDateTime = [newDateTime, null]; + } } - } - else if (isRangeSelection()) { - if (props.value && props.value.length) { - let startDate = props.value[0]; - let endDate = props.value[1]; - newDateTime = endDate ? [startDate, newDateTime] : [newDateTime, null]; - } - else { - newDateTime = [newDateTime, null]; + updateModel(event, newDateTime); + + if (props.onSelect) { + props.onSelect({ + originalEvent: event, + value: newDateTime + }); } - } - updateModel(event, newDateTime); + updateInputfield(newDateTime); + }; - if (props.onSelect) { - props.onSelect({ - originalEvent: event, - value: newDateTime - }); - } + const updateViewDate = (event, value) => { + validateDate(value); - updateInputfield(newDateTime); - } + if (props.onViewDateChange) { + props.onViewDateChange({ + originalEvent: event, + value + }); + } else { + viewStateChanged.current = true; + setViewDateState(value); + } + setCurrentMonth(value.getMonth()); + setCurrentYear(value.getFullYear()); + }; - const updateViewDate = (event, value) => { - validateDate(value); + const setNavigationState = (newViewDate) => { + if (!props.showMinMaxRange || props.view !== 'date' || !overlayRef.current) { + return; + } - if (props.onViewDateChange) { - props.onViewDateChange({ - originalEvent: event, - value - }); - } - else { - viewStateChanged.current = true; - setViewDateState(value); - } - setCurrentMonth(value.getMonth()); - setCurrentYear(value.getFullYear()); - } - - const setNavigationState = (newViewDate) => { - if (!props.showMinMaxRange || props.view !== 'date' || !overlayRef.current) { - return; - } - - const navPrev = DomHandler.findSingle(overlayRef.current, '.p-datepicker-prev'); - const navNext = DomHandler.findSingle(overlayRef.current, '.p-datepicker-next'); - - if (props.disabled) { - DomHandler.addClass(navPrev, 'p-disabled'); - DomHandler.addClass(navNext, 'p-disabled'); - return; - } - - // previous (check first day of month at 00:00:00) - if (props.minDate) { - let firstDayOfMonth = new Date(newViewDate.getTime()); - if (firstDayOfMonth.getMonth() === 0) { - firstDayOfMonth.setMonth(11, 1); - firstDayOfMonth.setFullYear(firstDayOfMonth.getFullYear() - 1); - } - else { - firstDayOfMonth.setMonth(firstDayOfMonth.getMonth() - 1, 1); - } - firstDayOfMonth.setHours(0); - firstDayOfMonth.setMinutes(0); - firstDayOfMonth.setSeconds(0); - if (props.minDate > firstDayOfMonth) { + const navPrev = DomHandler.findSingle(overlayRef.current, '.p-datepicker-prev'); + const navNext = DomHandler.findSingle(overlayRef.current, '.p-datepicker-next'); + + if (props.disabled) { DomHandler.addClass(navPrev, 'p-disabled'); - } else { - DomHandler.removeClass(navPrev, 'p-disabled'); + DomHandler.addClass(navNext, 'p-disabled'); + return; } - } - // next (check last day of month at 11:59:59) - if (props.maxDate) { - let lastDayOfMonth = new Date(newViewDate.getTime()); - if (lastDayOfMonth.getMonth() === 11) { - lastDayOfMonth.setMonth(0, 1); - lastDayOfMonth.setFullYear(lastDayOfMonth.getFullYear() + 1); + // previous (check first day of month at 00:00:00) + if (props.minDate) { + let firstDayOfMonth = new Date(newViewDate.getTime()); + if (firstDayOfMonth.getMonth() === 0) { + firstDayOfMonth.setMonth(11, 1); + firstDayOfMonth.setFullYear(firstDayOfMonth.getFullYear() - 1); + } else { + firstDayOfMonth.setMonth(firstDayOfMonth.getMonth() - 1, 1); + } + firstDayOfMonth.setHours(0); + firstDayOfMonth.setMinutes(0); + firstDayOfMonth.setSeconds(0); + if (props.minDate > firstDayOfMonth) { + DomHandler.addClass(navPrev, 'p-disabled'); + } else { + DomHandler.removeClass(navPrev, 'p-disabled'); + } } - else { - lastDayOfMonth.setMonth(lastDayOfMonth.getMonth() + 1, 1); + + // next (check last day of month at 11:59:59) + if (props.maxDate) { + let lastDayOfMonth = new Date(newViewDate.getTime()); + if (lastDayOfMonth.getMonth() === 11) { + lastDayOfMonth.setMonth(0, 1); + lastDayOfMonth.setFullYear(lastDayOfMonth.getFullYear() + 1); + } else { + lastDayOfMonth.setMonth(lastDayOfMonth.getMonth() + 1, 1); + } + lastDayOfMonth.setHours(0); + lastDayOfMonth.setMinutes(0); + lastDayOfMonth.setSeconds(0); + lastDayOfMonth.setSeconds(-1); + if (props.maxDate < lastDayOfMonth) { + DomHandler.addClass(navNext, 'p-disabled'); + } else { + DomHandler.removeClass(navNext, 'p-disabled'); + } } - lastDayOfMonth.setHours(0); - lastDayOfMonth.setMinutes(0); - lastDayOfMonth.setSeconds(0) - lastDayOfMonth.setSeconds(-1); - if (props.maxDate < lastDayOfMonth) { - DomHandler.addClass(navNext, 'p-disabled'); - } else { - DomHandler.removeClass(navNext, 'p-disabled'); - } - } - } - - const onDateCellKeydown = (event, date, groupIndex) => { - const cellContent = event.currentTarget; - const cell = cellContent.parentElement; - - switch (event.which) { - //down arrow - case 40: { - cellContent.tabIndex = '-1'; - let cellIndex = DomHandler.index(cell); - let nextRow = cell.parentElement.nextElementSibling; - if (nextRow) { - let focusCell = nextRow.children[cellIndex].children[0]; - if (DomHandler.hasClass(focusCell, 'p-disabled')) { + }; + + const onDateCellKeydown = (event, date, groupIndex) => { + const cellContent = event.currentTarget; + const cell = cellContent.parentElement; + + switch (event.which) { + //down arrow + case 40: { + cellContent.tabIndex = '-1'; + let cellIndex = DomHandler.index(cell); + let nextRow = cell.parentElement.nextElementSibling; + if (nextRow) { + let focusCell = nextRow.children[cellIndex].children[0]; + if (DomHandler.hasClass(focusCell, 'p-disabled')) { + navigation.current = { backward: false }; + navForward(event); + } else { + nextRow.children[cellIndex].children[0].tabIndex = '0'; + nextRow.children[cellIndex].children[0].focus(); + } + } else { navigation.current = { backward: false }; navForward(event); } - else { - nextRow.children[cellIndex].children[0].tabIndex = '0'; - nextRow.children[cellIndex].children[0].focus(); - } - } - else { - navigation.current = { backward: false }; - navForward(event); + event.preventDefault(); + break; } - event.preventDefault(); - break; - } - //up arrow - case 38: { - cellContent.tabIndex = '-1'; - let cellIndex = DomHandler.index(cell); - let prevRow = cell.parentElement.previousElementSibling; - if (prevRow) { - let focusCell = prevRow.children[cellIndex].children[0]; - if (DomHandler.hasClass(focusCell, 'p-disabled')) { + //up arrow + case 38: { + cellContent.tabIndex = '-1'; + let cellIndex = DomHandler.index(cell); + let prevRow = cell.parentElement.previousElementSibling; + if (prevRow) { + let focusCell = prevRow.children[cellIndex].children[0]; + if (DomHandler.hasClass(focusCell, 'p-disabled')) { + navigation.current = { backward: true }; + navBackward(event); + } else { + focusCell.tabIndex = '0'; + focusCell.focus(); + } + } else { navigation.current = { backward: true }; navBackward(event); } - else { - focusCell.tabIndex = '0'; - focusCell.focus(); + event.preventDefault(); + break; + } + + //left arrow + case 37: { + cellContent.tabIndex = '-1'; + let prevCell = cell.previousElementSibling; + if (prevCell) { + let focusCell = prevCell.children[0]; + if (DomHandler.hasClass(focusCell, 'p-disabled')) { + navigateToMonth(true, groupIndex, event); + } else { + focusCell.tabIndex = '0'; + focusCell.focus(); + } + } else { + navigateToMonth(true, groupIndex, event); } + event.preventDefault(); + break; } - else { + + //right arrow + case 39: { + cellContent.tabIndex = '-1'; + let nextCell = cell.nextElementSibling; + if (nextCell) { + let focusCell = nextCell.children[0]; + if (DomHandler.hasClass(focusCell, 'p-disabled')) { + navigateToMonth(false, groupIndex, event); + } else { + focusCell.tabIndex = '0'; + focusCell.focus(); + } + } else { + navigateToMonth(false, groupIndex, event); + } + event.preventDefault(); + break; + } + + //enter + case 13: { + onDateSelect(event, date); + event.preventDefault(); + break; + } + + //escape + case 27: { + hide(null, reFocusInputField); + event.preventDefault(); + break; + } + + //tab + case 9: { + trapFocus(event); + break; + } + + default: + //no op + break; + } + }; + + const navigateToMonth = (prev, groupIndex, event) => { + if (prev) { + if (props.numberOfMonths === 1 || groupIndex === 0) { navigation.current = { backward: true }; navBackward(event); + } else { + const prevMonthContainer = overlayRef.current.children[groupIndex - 1]; + const cells = DomHandler.find(prevMonthContainer, '.p-datepicker-calendar td span:not(.p-disabled)'); + const focusCell = cells[cells.length - 1]; + focusCell.tabIndex = '0'; + focusCell.focus(); + } + } else { + if (props.numberOfMonths === 1 || groupIndex === props.numberOfMonths - 1) { + navigation.current = { backward: false }; + navForward(event); + } else { + const nextMonthContainer = overlayRef.current.children[groupIndex + 1]; + const focusCell = DomHandler.findSingle(nextMonthContainer, '.p-datepicker-calendar td span:not(.p-disabled)'); + focusCell.tabIndex = '0'; + focusCell.focus(); } - event.preventDefault(); - break; } + }; - //left arrow - case 37: { - cellContent.tabIndex = '-1'; - let prevCell = cell.previousElementSibling; - if (prevCell) { - let focusCell = prevCell.children[0]; - if (DomHandler.hasClass(focusCell, 'p-disabled')) { - navigateToMonth(true, groupIndex, event); + const onMonthCellKeydown = (event, index) => { + const cell = event.currentTarget; + + switch (event.which) { + //arrows + case 38: + case 40: { + cell.tabIndex = '-1'; + const cells = cell.parentElement.children; + const cellIndex = DomHandler.index(cell); + const nextCell = cells[event.which === 40 ? cellIndex + 3 : cellIndex - 3]; + if (nextCell) { + nextCell.tabIndex = '0'; + nextCell.focus(); } - else { - focusCell.tabIndex = '0'; - focusCell.focus(); - } - } - else { - navigateToMonth(true, groupIndex, event); + event.preventDefault(); + break; } - event.preventDefault(); - break; - } - //right arrow - case 39: { - cellContent.tabIndex = '-1'; - let nextCell = cell.nextElementSibling; - if (nextCell) { - let focusCell = nextCell.children[0]; - if (DomHandler.hasClass(focusCell, 'p-disabled')) { - navigateToMonth(false, groupIndex, event); + //left arrow + case 37: { + cell.tabIndex = '-1'; + const prevCell = cell.previousElementSibling; + if (prevCell) { + prevCell.tabIndex = '0'; + prevCell.focus(); } - else { - focusCell.tabIndex = '0'; - focusCell.focus(); + event.preventDefault(); + break; + } + + //right arrow + case 39: { + cell.tabIndex = '-1'; + const nextCell = cell.nextElementSibling; + if (nextCell) { + nextCell.tabIndex = '0'; + nextCell.focus(); } + event.preventDefault(); + break; } - else { - navigateToMonth(false, groupIndex, event); + + //enter + case 13: { + onMonthSelect(event, index); + event.preventDefault(); + break; } - event.preventDefault(); - break; + + //escape + case 27: { + hide(null, reFocusInputField); + event.preventDefault(); + break; + } + + //tab + case 9: { + trapFocus(event); + break; + } + + default: + //no op + break; } + }; - //enter - case 13: { - onDateSelect(event, date); + const onDateSelect = (event, dateMeta, timeMeta) => { + if (props.disabled || !dateMeta.selectable) { event.preventDefault(); - break; + return; } - //escape - case 27: { - hide(null, reFocusInputField) - event.preventDefault(); - break; - } - - //tab - case 9: { - trapFocus(event); - break; - } - - default: - //no op - break; - } - } - - const navigateToMonth = (prev, groupIndex, event) => { - if (prev) { - if (props.numberOfMonths === 1 || (groupIndex === 0)) { - navigation.current = { backward: true }; - navBackward(event); - } - else { - const prevMonthContainer = overlayRef.current.children[groupIndex - 1]; - const cells = DomHandler.find(prevMonthContainer, '.p-datepicker-calendar td span:not(.p-disabled)'); - const focusCell = cells[cells.length - 1]; - focusCell.tabIndex = '0'; - focusCell.focus(); - } - } - else { - if (props.numberOfMonths === 1 || (groupIndex === props.numberOfMonths - 1)) { - navigation.current = { backward: false }; - navForward(event); - } - else { - const nextMonthContainer = overlayRef.current.children[groupIndex + 1]; - const focusCell = DomHandler.findSingle(nextMonthContainer, '.p-datepicker-calendar td span:not(.p-disabled)'); - focusCell.tabIndex = '0'; - focusCell.focus(); - } - } - } - - - const onMonthCellKeydown = (event, index) => { - const cell = event.currentTarget; - - switch (event.which) { - //arrows - case 38: - case 40: { - cell.tabIndex = '-1'; - const cells = cell.parentElement.children; - const cellIndex = DomHandler.index(cell); - const nextCell = cells[event.which === 40 ? cellIndex + 3 : cellIndex - 3]; - if (nextCell) { - nextCell.tabIndex = '0'; - nextCell.focus(); + DomHandler.find(overlayRef.current, '.p-datepicker-calendar td span:not(.p-disabled)').forEach((cell) => (cell.tabIndex = -1)); + event.currentTarget.focus(); + + if (isMultipleSelection()) { + if (isSelected(dateMeta)) { + let value = props.value.filter((date, i) => { + return !isDateEquals(date, dateMeta); + }); + updateModel(event, value); + updateInputfield(value); + } else if (!props.maxDateCount || !props.value || props.maxDateCount > props.value.length) { + selectDate(event, dateMeta, timeMeta); } - event.preventDefault(); - break; + } else { + selectDate(event, dateMeta, timeMeta); } - //left arrow - case 37: { - cell.tabIndex = '-1'; - const prevCell = cell.previousElementSibling; - if (prevCell) { - prevCell.tabIndex = '0'; - prevCell.focus(); + if (!props.inline && isSingleSelection() && (!props.showTime || props.hideOnDateTimeSelect)) { + setTimeout(() => { + hide('dateselect'); + }, 100); + + if (touchUIMask.current) { + disableModality(); } - event.preventDefault(); - break; } - //right arrow - case 39: { - cell.tabIndex = '-1'; - const nextCell = cell.nextElementSibling; - if (nextCell) { - nextCell.tabIndex = '0'; - nextCell.focus(); + event.preventDefault(); + }; + + const selectTime = (date, timeMeta) => { + if (props.showTime) { + let hours, minutes, seconds, milliseconds; + + if (timeMeta) { + ({ hours, minutes, seconds, milliseconds } = timeMeta); + } else { + let time = getCurrentDateTime(); + [hours, minutes, seconds, milliseconds] = [time.getHours(), time.getMinutes(), time.getSeconds(), time.getMilliseconds()]; } - event.preventDefault(); - break; - } - //enter - case 13: { - onMonthSelect(event, index); - event.preventDefault(); - break; + date.setHours(hours); + date.setMinutes(minutes); + date.setSeconds(seconds); + date.setMilliseconds(milliseconds); } + }; - //escape - case 27: { - hide(null, reFocusInputField); - event.preventDefault(); - break; + const selectDate = (event, dateMeta, timeMeta) => { + let date = new Date(dateMeta.year, dateMeta.month, dateMeta.day); + + selectTime(date, timeMeta); + + if (props.minDate && props.minDate > date) { + date = props.minDate; } - //tab - case 9: { - trapFocus(event); - break; + if (props.maxDate && props.maxDate < date) { + date = props.maxDate; } - default: - //no op - break; - } - } + let selectedValues = date; - const onDateSelect = (event, dateMeta, timeMeta) => { - if (props.disabled || !dateMeta.selectable) { - event.preventDefault(); - return; - } + if (isSingleSelection()) { + updateModel(event, date); + } else if (isMultipleSelection()) { + selectedValues = props.value ? [...props.value, date] : [date]; + updateModel(event, selectedValues); + } else if (isRangeSelection()) { + if (props.value && props.value.length) { + let startDate = props.value[0]; + let endDate = props.value[1]; + + if (!endDate) { + if (date.getTime() >= startDate.getTime()) { + endDate = date; + } else { + endDate = startDate; + startDate = date; + } + } else { + startDate = date; + endDate = null; + } - DomHandler.find(overlayRef.current, '.p-datepicker-calendar td span:not(.p-disabled)').forEach(cell => cell.tabIndex = -1); - event.currentTarget.focus(); + selectedValues = [startDate, endDate]; + updateModel(event, selectedValues); + } else { + selectedValues = [date, null]; + updateModel(event, selectedValues); + } + } - if (isMultipleSelection()) { - if (isSelected(dateMeta)) { - let value = props.value.filter((date, i) => { - return !isDateEquals(date, dateMeta); + if (props.onSelect) { + props.onSelect({ + originalEvent: event, + value: date }); - updateModel(event, value); - updateInputfield(value); - } - else if (!props.maxDateCount || !props.value || props.maxDateCount > props.value.length) { - selectDate(event, dateMeta, timeMeta); } - } - else { - selectDate(event, dateMeta, timeMeta); - } - if (!props.inline && isSingleSelection() && (!props.showTime || props.hideOnDateTimeSelect)) { - setTimeout(() => { - hide('dateselect'); - }, 100); + updateInputfield(selectedValues); + }; - if (touchUIMask.current) { - disableModality(); - } - } + const decrementDecade = () => { + const _currentYear = currentYear - 10; + setCurrentYear(_currentYear); + return _currentYear; + }; + + const incrementDecade = () => { + const _currentYear = currentYear + 10; + setCurrentYear(_currentYear); + return _currentYear; + }; + + const switchToMonthView = (event) => { + setCurrentView('month'); + event.preventDefault(); + }; - event.preventDefault(); - } + const switchToYearView = (event) => { + setCurrentView('year'); + event.preventDefault(); + }; - const selectTime = (date, timeMeta) => { - if (props.showTime) { - let hours, minutes, seconds, milliseconds; + const onMonthSelect = (event, month) => { + if (props.view === 'month') { + onDateSelect(event, { year: currentYear, month: month, day: 1, selectable: true }); + event.preventDefault(); + } else { + setCurrentMonth(month); + createMonthsMeta(month, currentYear); + const currentDate = new Date(getCurrentDateTime().getTime()); + currentDate.setDate(1); // #2948 always set to 1st of month + currentDate.setMonth(month); + currentDate.setYear(currentYear); - if (timeMeta) { - ({ hours, minutes, seconds, milliseconds } = timeMeta); - } - else { - let time = getCurrentDateTime(); - [hours, minutes, seconds, milliseconds] = [time.getHours(), time.getMinutes(), time.getSeconds(), time.getMilliseconds()]; + setViewDateState(currentDate); + setCurrentView('date'); + props.onMonthChange && props.onMonthChange({ month: month + 1, year: currentYear }); } + }; - date.setHours(hours); - date.setMinutes(minutes); - date.setSeconds(seconds); - date.setMilliseconds(milliseconds); - } - } + const onYearSelect = (event, year) => { + if (props.view === 'year') { + onDateSelect(event, { year: year, month: 0, day: 1, selectable: true }); + } else { + setCurrentYear(year); + setCurrentView('month'); + props.onMonthChange && props.onMonthChange({ month: currentMonth + 1, year: year }); + } + }; - const selectDate = (event, dateMeta, timeMeta) => { - let date = new Date(dateMeta.year, dateMeta.month, dateMeta.day); + const updateModel = (event, value) => { + if (props.onChange) { + const newValue = value && value instanceof Date ? new Date(value.getTime()) : value; + viewStateChanged.current = true; - selectTime(date, timeMeta); + props.onChange({ + originalEvent: event, + value: newValue, + stopPropagation: () => {}, + preventDefault: () => {}, + target: { + name: props.name, + id: props.id, + value: newValue + } + }); + } + }; - if (props.minDate && props.minDate > date) { - date = props.minDate; - } + const show = (type) => { + if (props.onVisibleChange) { + props.onVisibleChange({ + visible: true, + type + }); + } else { + setOverlayVisibleState(true); + overlayEventListener.current = (e) => { + if (!isOutsideClicked(e)) { + isOverlayClicked.current = true; + } + }; - if (props.maxDate && props.maxDate < date) { - date = props.maxDate; - } + OverlayService.on('overlay-click', overlayEventListener.current); + } + }; - let selectedValues = date; + const hide = (type, callback) => { + const _hideCallback = () => { + viewStateChanged.current = false; + ignoreFocusFunctionality.current = false; + isOverlayClicked.current = false; - if (isSingleSelection()) { - updateModel(event, date); - } - else if (isMultipleSelection()) { - selectedValues = props.value ? [...props.value, date] : [date]; - updateModel(event, selectedValues); - } - else if (isRangeSelection()) { - if (props.value && props.value.length) { - let startDate = props.value[0]; - let endDate = props.value[1]; + callback && callback(); - if (!endDate) { - if (date.getTime() >= startDate.getTime()) { - endDate = date; - } - else { - endDate = startDate; - startDate = date; - } - } - else { - startDate = date; - endDate = null; - } + OverlayService.off('overlay-click', overlayEventListener.current); + overlayEventListener.current = null; + }; - selectedValues = [startDate, endDate]; - updateModel(event, selectedValues); + props.touchUI && disableModality(); + + if (props.onVisibleChange) { + props.onVisibleChange({ + visible: false, + type, + callback: _hideCallback + }); + } else { + setOverlayVisibleState(false); + _hideCallback(); } - else { - selectedValues = [date, null]; - updateModel(event, selectedValues); + }; + + const onOverlayEnter = () => { + if (props.autoZIndex) { + const key = props.touchUI ? 'modal' : 'overlay'; + ZIndexUtils.set(key, overlayRef.current, PrimeReact.autoZIndex, props.baseZIndex || PrimeReact.zIndex[key]); } - } - if (props.onSelect) { - props.onSelect({ - originalEvent: event, - value: date - }); - } + alignOverlay(); + }; - updateInputfield(selectedValues); - } + const onOverlayEntered = () => { + bindOverlayListener(); + props.onShow && props.onShow(); + }; - const decrementDecade = () => { - const _currentYear = currentYear - 10; - setCurrentYear(_currentYear); - return _currentYear; - } + const onOverlayExit = () => { + unbindOverlayListener(); + }; - const incrementDecade = () => { - const _currentYear = currentYear + 10; - setCurrentYear(_currentYear); - return _currentYear; - } + const onOverlayExited = () => { + ZIndexUtils.clear(overlayRef.current); - const switchToMonthView = (event) => { - setCurrentView('month') - event.preventDefault(); - } + props.onHide && props.onHide(); + }; + const appendDisabled = () => { + return props.appendTo === 'self' || props.inline; + }; - const switchToYearView = (event) => { - setCurrentView('year'); - event.preventDefault(); - } + const alignOverlay = () => { + if (props.touchUI) { + enableModality(); + } else if (overlayRef && overlayRef.current && inputRef && inputRef.current) { + DomHandler.alignOverlay(overlayRef.current, inputRef.current, props.appendTo || PrimeReact.appendTo); - const onMonthSelect = (event, month) => { - if (props.view === 'month') { - onDateSelect(event, { year: currentYear, month: month, day: 1, selectable: true }); - event.preventDefault(); - } - else { - setCurrentMonth(month); - createMonthsMeta(month, currentYear); - const currentDate = new Date(getCurrentDateTime().getTime()); - currentDate.setDate(1); // #2948 always set to 1st of month - currentDate.setMonth(month); - currentDate.setYear(currentYear); - - setViewDateState(currentDate); - setCurrentView('date'); - props.onMonthChange && props.onMonthChange({ month: month + 1, year: currentYear }); - } - } - - const onYearSelect = (event, year) => { - if (props.view === 'year') { - onDateSelect(event, { year: year, month: 0, day: 1, selectable: true }); - } - else { - setCurrentYear(year); - setCurrentView('month'); - props.onMonthChange && props.onMonthChange({ month: currentMonth + 1, year: year }); - } - } - - const updateModel = (event, value) => { - if (props.onChange) { - const newValue = (value && value instanceof Date) ? new Date(value.getTime()) : value; - viewStateChanged.current = true; - - props.onChange({ - originalEvent: event, - value: newValue, - stopPropagation: () => { }, - preventDefault: () => { }, - target: { - name: props.name, - id: props.id, - value: newValue - } - }); - } - } - - const show = (type) => { - if (props.onVisibleChange) { - props.onVisibleChange({ - visible: true, - type - }); - } - else { - setOverlayVisibleState(true); - overlayEventListener.current = (e) => { - if (!isOutsideClicked(e)) { - isOverlayClicked.current = true; + if (appendDisabled()) { + DomHandler.relativePosition(overlayRef.current, inputRef.current); + } else { + if (currentView === 'date') { + overlayRef.current.style.width = DomHandler.getOuterWidth(overlayRef.current) + 'px'; + overlayRef.current.style.minWidth = DomHandler.getOuterWidth(inputRef.current) + 'px'; + } else { + overlayRef.current.style.width = DomHandler.getOuterWidth(inputRef.current) + 'px'; + } + + DomHandler.absolutePosition(overlayRef.current, inputRef.current); } - }; + } + }; - OverlayService.on('overlay-click', overlayEventListener.current); - } - } + const enableModality = () => { + if (!touchUIMask.current) { + touchUIMask.current = document.createElement('div'); + touchUIMask.current.style.zIndex = String(ZIndexUtils.get(overlayRef.current) - 1); + DomHandler.addMultipleClasses(touchUIMask.current, 'p-component-overlay p-datepicker-mask p-datepicker-mask-scrollblocker p-component-overlay-enter'); - const hide = (type, callback) => { - const _hideCallback = () => { - viewStateChanged.current = false; - ignoreFocusFunctionality.current = false; - isOverlayClicked.current = false; + touchUIMaskClickListener.current = () => { + disableModality(); + hide(); + }; + touchUIMask.current.addEventListener('click', touchUIMaskClickListener.current); - callback && callback(); + document.body.appendChild(touchUIMask.current); + DomHandler.addClass(document.body, 'p-overflow-hidden'); + } + }; - OverlayService.off('overlay-click', overlayEventListener.current); - overlayEventListener.current = null; + const disableModality = () => { + if (touchUIMask.current) { + DomHandler.addClass(touchUIMask.current, 'p-component-overlay-leave'); + touchUIMask.current.addEventListener('animationend', () => { + destroyMask(); + }); + } }; - props.touchUI && disableModality(); + const destroyMask = () => { + if (touchUIMask.current) { + touchUIMask.current.removeEventListener('click', touchUIMaskClickListener.current); + touchUIMaskClickListener.current = null; + document.body.removeChild(touchUIMask.current); + touchUIMask.current = null; + } + + let bodyChildren = document.body.children; + let hasBlockerMasks; + for (let i = 0; i < bodyChildren.length; i++) { + let bodyChild = bodyChildren[i]; + if (DomHandler.hasClass(bodyChild, 'p-datepicker-mask-scrollblocker')) { + hasBlockerMasks = true; + break; + } + } + + if (!hasBlockerMasks) { + DomHandler.removeClass(document.body, 'p-overflow-hidden'); + } + }; - if (props.onVisibleChange) { - props.onVisibleChange({ - visible: false, - type, - callback: _hideCallback - }); - } - else { - setOverlayVisibleState(false); - _hideCallback(); - } - } + const isOutsideClicked = (event) => { + return elementRef.current && !(elementRef.current.isSameNode(event.target) || isNavIconClicked(event.target) || elementRef.current.contains(event.target) || (overlayRef.current && overlayRef.current.contains(event.target))); + }; - const onOverlayEnter = () => { - if (props.autoZIndex) { - const key = props.touchUI ? 'modal' : 'overlay'; - ZIndexUtils.set(key, overlayRef.current, PrimeReact.autoZIndex, props.baseZIndex || PrimeReact.zIndex[key]); - } + const isNavIconClicked = (target) => { + return DomHandler.hasClass(target, 'p-datepicker-prev') || DomHandler.hasClass(target, 'p-datepicker-prev-icon') || DomHandler.hasClass(target, 'p-datepicker-next') || DomHandler.hasClass(target, 'p-datepicker-next-icon'); + }; - alignOverlay(); - } + const getFirstDayOfMonthIndex = (month, year) => { + let day = new Date(); + day.setDate(1); + day.setMonth(month); + day.setFullYear(year); - const onOverlayEntered = () => { - bindOverlayListener(); - props.onShow && props.onShow(); - } + let dayIndex = day.getDay() + getSundayIndex(); + return dayIndex >= 7 ? dayIndex - 7 : dayIndex; + }; - const onOverlayExit = () => { - unbindOverlayListener(); - } + const getDaysCountInMonth = (month, year) => { + return 32 - daylightSavingAdjust(new Date(year, month, 32)).getDate(); + }; - const onOverlayExited = () => { - ZIndexUtils.clear(overlayRef.current); + const getDaysCountInPrevMonth = (month, year) => { + let prev = getPreviousMonthAndYear(month, year); + return getDaysCountInMonth(prev.month, prev.year); + }; - props.onHide && props.onHide(); - } + const daylightSavingAdjust = (date) => { + if (!date) { + return null; + } - const appendDisabled = () => { - return props.appendTo === 'self' || props.inline; - } + date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); - const alignOverlay = () => { - if (props.touchUI) { - enableModality(); - } + return date; + }; - else if (overlayRef && overlayRef.current && inputRef && inputRef.current) { - DomHandler.alignOverlay(overlayRef.current, inputRef.current, props.appendTo || PrimeReact.appendTo); + const getPreviousMonthAndYear = (month, year) => { + let m, y; - if (appendDisabled()) { - DomHandler.relativePosition(overlayRef.current, inputRef.current); + if (month === 0) { + m = 11; + y = year - 1; + } else { + m = month - 1; + y = year; } - else { - if (currentView === 'date') { - overlayRef.current.style.width = DomHandler.getOuterWidth(overlayRef.current) + 'px'; - overlayRef.current.style.minWidth = DomHandler.getOuterWidth(inputRef.current) + 'px'; - } - else { - overlayRef.current.style.width = DomHandler.getOuterWidth(inputRef.current) + 'px'; - } - DomHandler.absolutePosition(overlayRef.current, inputRef.current); - } - } - } + return { month: m, year: y }; + }; - const enableModality = () => { - if (!touchUIMask.current) { - touchUIMask.current = document.createElement('div'); - touchUIMask.current.style.zIndex = String(ZIndexUtils.get(overlayRef.current) - 1); - DomHandler.addMultipleClasses(touchUIMask.current, 'p-component-overlay p-datepicker-mask p-datepicker-mask-scrollblocker p-component-overlay-enter'); + const getNextMonthAndYear = (month, year) => { + let m, y; - touchUIMaskClickListener.current = () => { - disableModality(); - hide(); - }; - touchUIMask.current.addEventListener('click', touchUIMaskClickListener.current); - - document.body.appendChild(touchUIMask.current); - DomHandler.addClass(document.body, 'p-overflow-hidden'); - } - } - - const disableModality = () => { - if (touchUIMask.current) { - DomHandler.addClass(touchUIMask.current, 'p-component-overlay-leave'); - touchUIMask.current.addEventListener('animationend', () => { - destroyMask(); - }); - } - } - - const destroyMask = () => { - if (touchUIMask.current) { - touchUIMask.current.removeEventListener('click', touchUIMaskClickListener.current); - touchUIMaskClickListener.current = null; - document.body.removeChild(touchUIMask.current); - touchUIMask.current = null; - } - - let bodyChildren = document.body.children; - let hasBlockerMasks; - for (let i = 0; i < bodyChildren.length; i++) { - let bodyChild = bodyChildren[i]; - if (DomHandler.hasClass(bodyChild, 'p-datepicker-mask-scrollblocker')) { - hasBlockerMasks = true; - break; - } - } - - if (!hasBlockerMasks) { - DomHandler.removeClass(document.body, 'p-overflow-hidden'); - } - } - - const isOutsideClicked = (event) => { - return elementRef.current && !(elementRef.current.isSameNode(event.target) || isNavIconClicked(event.target) || - elementRef.current.contains(event.target) || (overlayRef.current && overlayRef.current.contains(event.target))); - } - - const isNavIconClicked = (target) => { - return (DomHandler.hasClass(target, 'p-datepicker-prev') || DomHandler.hasClass(target, 'p-datepicker-prev-icon') - || DomHandler.hasClass(target, 'p-datepicker-next') || DomHandler.hasClass(target, 'p-datepicker-next-icon')); - } - - const getFirstDayOfMonthIndex = (month, year) => { - let day = new Date(); - day.setDate(1); - day.setMonth(month); - day.setFullYear(year); - - let dayIndex = day.getDay() + getSundayIndex(); - return dayIndex >= 7 ? dayIndex - 7 : dayIndex; - } - - const getDaysCountInMonth = (month, year) => { - return 32 - daylightSavingAdjust(new Date(year, month, 32)).getDate(); - } - - const getDaysCountInPrevMonth = (month, year) => { - let prev = getPreviousMonthAndYear(month, year); - return getDaysCountInMonth(prev.month, prev.year); - } - - const daylightSavingAdjust = (date) => { - if (!date) { - return null; - } - - date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); - - return date; - } - - const getPreviousMonthAndYear = (month, year) => { - let m, y; - - if (month === 0) { - m = 11; - y = year - 1; - } - else { - m = month - 1; - y = year; - } - - return { 'month': m, 'year': y }; - } - - const getNextMonthAndYear = (month, year) => { - let m, y; - - if (month === 11) { - m = 0; - y = year + 1; - } - else { - m = month + 1; - y = year; - } - - return { 'month': m, 'year': y }; - } - - const getSundayIndex = () => { - const firstDayOfWeek = localeOption('firstDayOfWeek', props.locale); - return firstDayOfWeek > 0 ? 7 - firstDayOfWeek : 0; - } - - const createWeekDaysMeta = () => { - let weekDays = []; - let { firstDayOfWeek: dayIndex, dayNamesMin } = localeOptions(props.locale); - for (let i = 0; i < 7; i++) { - weekDays.push(dayNamesMin[dayIndex]); - dayIndex = (dayIndex === 6) ? 0 : ++dayIndex; - } - - return weekDays; - } - - const createMonthsMeta = (month, year) => { - let months = []; - for (let i = 0; i < props.numberOfMonths; i++) { - let m = month + i; - let y = year; - if (m > 11) { - m = m % 11 - 1; + if (month === 11) { + m = 0; y = year + 1; + } else { + m = month + 1; + y = year; } - months.push(createMonthMeta(m, y)); - } + return { month: m, year: y }; + }; - return months; - } + const getSundayIndex = () => { + const firstDayOfWeek = localeOption('firstDayOfWeek', props.locale); + return firstDayOfWeek > 0 ? 7 - firstDayOfWeek : 0; + }; - const createMonthMeta = (month, year) => { - let dates = []; - let firstDay = getFirstDayOfMonthIndex(month, year); - let daysLength = getDaysCountInMonth(month, year); - let prevMonthDaysLength = getDaysCountInPrevMonth(month, year); - let dayNo = 1; - let today = new Date(); - let weekNumbers = []; - let monthRows = Math.ceil((daysLength + firstDay) / 7); + const createWeekDaysMeta = () => { + let weekDays = []; + let { firstDayOfWeek: dayIndex, dayNamesMin } = localeOptions(props.locale); + for (let i = 0; i < 7; i++) { + weekDays.push(dayNamesMin[dayIndex]); + dayIndex = dayIndex === 6 ? 0 : ++dayIndex; + } - for (let i = 0; i < monthRows; i++) { - let week = []; + return weekDays; + }; - if (i === 0) { - for (let j = (prevMonthDaysLength - firstDay + 1); j <= prevMonthDaysLength; j++) { - let prev = getPreviousMonthAndYear(month, year); - week.push({ - day: j, month: prev.month, year: prev.year, otherMonth: true, - today: isToday(today, j, prev.month, prev.year), selectable: isSelectable(j, prev.month, prev.year, true) - }); + const createMonthsMeta = (month, year) => { + let months = []; + for (let i = 0; i < props.numberOfMonths; i++) { + let m = month + i; + let y = year; + if (m > 11) { + m = (m % 11) - 1; + y = year + 1; } - let remainingDaysLength = 7 - week.length; - for (let j = 0; j < remainingDaysLength; j++) { - week.push({ - day: dayNo, month: month, year: year, today: isToday(today, dayNo, month, year), - selectable: isSelectable(dayNo, month, year, false) - }); - dayNo++; - } + months.push(createMonthMeta(m, y)); } - else { - for (let j = 0; j < 7; j++) { - if (dayNo > daysLength) { - let next = getNextMonthAndYear(month, year); + + return months; + }; + + const createMonthMeta = (month, year) => { + let dates = []; + let firstDay = getFirstDayOfMonthIndex(month, year); + let daysLength = getDaysCountInMonth(month, year); + let prevMonthDaysLength = getDaysCountInPrevMonth(month, year); + let dayNo = 1; + let today = new Date(); + let weekNumbers = []; + let monthRows = Math.ceil((daysLength + firstDay) / 7); + + for (let i = 0; i < monthRows; i++) { + let week = []; + + if (i === 0) { + for (let j = prevMonthDaysLength - firstDay + 1; j <= prevMonthDaysLength; j++) { + let prev = getPreviousMonthAndYear(month, year); week.push({ - day: dayNo - daysLength, month: next.month, year: next.year, otherMonth: true, - today: isToday(today, dayNo - daysLength, next.month, next.year), - selectable: isSelectable((dayNo - daysLength), next.month, next.year, true) + day: j, + month: prev.month, + year: prev.year, + otherMonth: true, + today: isToday(today, j, prev.month, prev.year), + selectable: isSelectable(j, prev.month, prev.year, true) }); } - else { + + let remainingDaysLength = 7 - week.length; + for (let j = 0; j < remainingDaysLength; j++) { week.push({ - day: dayNo, month: month, year: year, today: isToday(today, dayNo, month, year), + day: dayNo, + month: month, + year: year, + today: isToday(today, dayNo, month, year), selectable: isSelectable(dayNo, month, year, false) }); + dayNo++; + } + } else { + for (let j = 0; j < 7; j++) { + if (dayNo > daysLength) { + let next = getNextMonthAndYear(month, year); + week.push({ + day: dayNo - daysLength, + month: next.month, + year: next.year, + otherMonth: true, + today: isToday(today, dayNo - daysLength, next.month, next.year), + selectable: isSelectable(dayNo - daysLength, next.month, next.year, true) + }); + } else { + week.push({ + day: dayNo, + month: month, + year: year, + today: isToday(today, dayNo, month, year), + selectable: isSelectable(dayNo, month, year, false) + }); + } + + dayNo++; } + } - dayNo++; + if (props.showWeek) { + weekNumbers.push(getWeekNumber(new Date(week[0].year, week[0].month, week[0].day))); } + + dates.push(week); } - if (props.showWeek) { - weekNumbers.push(getWeekNumber(new Date(week[0].year, week[0].month, week[0].day))); - } - - dates.push(week); - } - - return { - month: month, - year: year, - dates: dates, - weekNumbers: weekNumbers - } - } - - const getWeekNumber = (date) => { - let checkDate = new Date(date.getTime()); - checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); - let time = checkDate.getTime(); - checkDate.setMonth(0); - checkDate.setDate(1); - return Math.floor(Math.round((time - checkDate.getTime()) / 86400000) / 7) + 1; - } - - const isSelectable = (day, month, year, otherMonth) => { - let validMin = true; - let validMax = true; - let validDate = true; - let validDay = true; - let validMonth = true; - - if (props.minDate) { - if (props.minDate.getFullYear() > year) { - validMin = false; - } - else if (props.minDate.getFullYear() === year) { - if (props.minDate.getMonth() > month) { + return { + month: month, + year: year, + dates: dates, + weekNumbers: weekNumbers + }; + }; + + const getWeekNumber = (date) => { + let checkDate = new Date(date.getTime()); + checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); + let time = checkDate.getTime(); + checkDate.setMonth(0); + checkDate.setDate(1); + return Math.floor(Math.round((time - checkDate.getTime()) / 86400000) / 7) + 1; + }; + + const isSelectable = (day, month, year, otherMonth) => { + let validMin = true; + let validMax = true; + let validDate = true; + let validDay = true; + let validMonth = true; + + if (props.minDate) { + if (props.minDate.getFullYear() > year) { validMin = false; - } - else if (props.minDate.getMonth() === month) { - if (props.minDate.getDate() > day) { + } else if (props.minDate.getFullYear() === year) { + if (props.minDate.getMonth() > month) { validMin = false; + } else if (props.minDate.getMonth() === month) { + if (props.minDate.getDate() > day) { + validMin = false; + } } } } - } - if (props.maxDate) { - if (props.maxDate.getFullYear() < year) { - validMax = false; - } - else if (props.maxDate.getFullYear() === year) { - if (props.maxDate.getMonth() < month) { + if (props.maxDate) { + if (props.maxDate.getFullYear() < year) { validMax = false; - } - else if (props.maxDate.getMonth() === month) { - if (props.maxDate.getDate() < day) { + } else if (props.maxDate.getFullYear() === year) { + if (props.maxDate.getMonth() < month) { validMax = false; + } else if (props.maxDate.getMonth() === month) { + if (props.maxDate.getDate() < day) { + validMax = false; + } } } } - } - if (props.disabledDates) { - validDate = !isDateDisabled(day, month, year); - } + if (props.disabledDates) { + validDate = !isDateDisabled(day, month, year); + } - if (props.disabledDays) { - validDay = !isDayDisabled(day, month, year) - } + if (props.disabledDays) { + validDay = !isDayDisabled(day, month, year); + } - if (props.selectOtherMonths === false && otherMonth) { - validMonth = false; - } + if (props.selectOtherMonths === false && otherMonth) { + validMonth = false; + } - return validMin && validMax && validDate && validDay && validMonth; - } + return validMin && validMax && validDate && validDay && validMonth; + }; - const isSelectableTime = (value) => { - let validMin = true; - let validMax = true; + const isSelectableTime = (value) => { + let validMin = true; + let validMax = true; - if (props.minDate && props.minDate.toDateString() === value.toDateString()) { - if (props.minDate.getHours() > value.getHours()) { - validMin = false; - } - else if (props.minDate.getHours() === value.getHours()) { - if (props.minDate.getMinutes() > value.getMinutes()) { + if (props.minDate && props.minDate.toDateString() === value.toDateString()) { + if (props.minDate.getHours() > value.getHours()) { validMin = false; - } - else if (props.minDate.getMinutes() === value.getMinutes()) { - if (props.minDate.getSeconds() > value.getSeconds()) { + } else if (props.minDate.getHours() === value.getHours()) { + if (props.minDate.getMinutes() > value.getMinutes()) { validMin = false; - } - else if (props.minDate.getSeconds() === value.getSeconds()) { - if (props.minDate.getMilliseconds() > value.getMilliseconds()) { + } else if (props.minDate.getMinutes() === value.getMinutes()) { + if (props.minDate.getSeconds() > value.getSeconds()) { validMin = false; + } else if (props.minDate.getSeconds() === value.getSeconds()) { + if (props.minDate.getMilliseconds() > value.getMilliseconds()) { + validMin = false; + } } } } } - } - if (props.maxDate && props.maxDate.toDateString() === value.toDateString()) { - if (props.maxDate.getHours() < value.getHours()) { - validMax = false; - } - else if (props.maxDate.getHours() === value.getHours()) { - if (props.maxDate.getMinutes() < value.getMinutes()) { + if (props.maxDate && props.maxDate.toDateString() === value.toDateString()) { + if (props.maxDate.getHours() < value.getHours()) { validMax = false; - } - else if (props.maxDate.getMinutes() === value.getMinutes()) { - if (props.maxDate.getSeconds() < value.getSeconds()) { + } else if (props.maxDate.getHours() === value.getHours()) { + if (props.maxDate.getMinutes() < value.getMinutes()) { validMax = false; - } - else if (props.maxDate.getSeconds() === value.getSeconds()) { - if (props.maxDate.getMilliseconds() < value.getMilliseconds()) { + } else if (props.maxDate.getMinutes() === value.getMinutes()) { + if (props.maxDate.getSeconds() < value.getSeconds()) { validMax = false; + } else if (props.maxDate.getSeconds() === value.getSeconds()) { + if (props.maxDate.getMilliseconds() < value.getMilliseconds()) { + validMax = false; + } } } } } - } - return validMin && validMax; - } + return validMin && validMax; + }; - const isSelected = (dateMeta) => { - if (props.value) { - if (isSingleSelection()) { - return isDateEquals(props.value, dateMeta); - } - else if (isMultipleSelection()) { - let selected = false; - for (let date of props.value) { - selected = isDateEquals(date, dateMeta); - if (selected) { - break; + const isSelected = (dateMeta) => { + if (props.value) { + if (isSingleSelection()) { + return isDateEquals(props.value, dateMeta); + } else if (isMultipleSelection()) { + let selected = false; + for (let date of props.value) { + selected = isDateEquals(date, dateMeta); + if (selected) { + break; + } } - } - return selected; - } - else if (isRangeSelection()) { - if (props.value[1]) - return isDateEquals(props.value[0], dateMeta) || isDateEquals(props.value[1], dateMeta) || isDateBetween(props.value[0], props.value[1], dateMeta); - else { - return isDateEquals(props.value[0], dateMeta); + return selected; + } else if (isRangeSelection()) { + if (props.value[1]) return isDateEquals(props.value[0], dateMeta) || isDateEquals(props.value[1], dateMeta) || isDateBetween(props.value[0], props.value[1], dateMeta); + else { + return isDateEquals(props.value[0], dateMeta); + } } + } else { + return false; } - } - else { - return false; - } - } + }; - const isComparable = () => { - return props.value != null && typeof props.value !== 'string'; - } + const isComparable = () => { + return props.value != null && typeof props.value !== 'string'; + }; - const isMonthSelected = (month) => { - if (isComparable()) { - let value = isRangeSelection() ? props.value[0] : props.value; + const isMonthSelected = (month) => { + if (isComparable()) { + let value = isRangeSelection() ? props.value[0] : props.value; - return !isMultipleSelection() ? (value.getMonth() === month && value.getFullYear() === currentYear) : false; - } + return !isMultipleSelection() ? value.getMonth() === month && value.getFullYear() === currentYear : false; + } - return false; - } + return false; + }; - const isYearSelected = (year) => { - if (isComparable()) { - let value = isRangeSelection() ? props.value[0] : props.value; + const isYearSelected = (year) => { + if (isComparable()) { + let value = isRangeSelection() ? props.value[0] : props.value; - return !isMultipleSelection() && isComparable() ? (value.getFullYear() === year) : false; - } + return !isMultipleSelection() && isComparable() ? value.getFullYear() === year : false; + } - return false; - } + return false; + }; - const switchViewButtonDisabled = () => { - return props.numberOfMonths > 1 || props.disabled; - } + const switchViewButtonDisabled = () => { + return props.numberOfMonths > 1 || props.disabled; + }; - const isDateEquals = (value, dateMeta) => { - if (value && value instanceof Date) - return value.getDate() === dateMeta.day && value.getMonth() === dateMeta.month && value.getFullYear() === dateMeta.year; - else - return false; - } + const isDateEquals = (value, dateMeta) => { + if (value && value instanceof Date) return value.getDate() === dateMeta.day && value.getMonth() === dateMeta.month && value.getFullYear() === dateMeta.year; + else return false; + }; - const isDateBetween = (start, end, dateMeta) => { - let between = false; - if (start && end) { - let date = new Date(dateMeta.year, dateMeta.month, dateMeta.day); - return start.getTime() <= date.getTime() && end.getTime() >= date.getTime(); - } + const isDateBetween = (start, end, dateMeta) => { + let between = false; + if (start && end) { + let date = new Date(dateMeta.year, dateMeta.month, dateMeta.day); + return start.getTime() <= date.getTime() && end.getTime() >= date.getTime(); + } - return between; - } + return between; + }; - const isSingleSelection = () => { - return props.selectionMode === 'single'; - } + const isSingleSelection = () => { + return props.selectionMode === 'single'; + }; - const isRangeSelection = () => { - return props.selectionMode === 'range'; - } + const isRangeSelection = () => { + return props.selectionMode === 'range'; + }; - const isMultipleSelection = () => { - return props.selectionMode === 'multiple'; - } + const isMultipleSelection = () => { + return props.selectionMode === 'multiple'; + }; - const isToday = (today, day, month, year) => { - return today.getDate() === day && today.getMonth() === month && today.getFullYear() === year; - } + const isToday = (today, day, month, year) => { + return today.getDate() === day && today.getMonth() === month && today.getFullYear() === year; + }; - const isDateDisabled = (day, month, year) => { - return props.disabledDates ? props.disabledDates.some(d => d.getFullYear() === year && d.getMonth() === month && d.getDate() === day) : false; - } + const isDateDisabled = (day, month, year) => { + return props.disabledDates ? props.disabledDates.some((d) => d.getFullYear() === year && d.getMonth() === month && d.getDate() === day) : false; + }; - const isDayDisabled = (day, month, year) => { - if (props.disabledDays) { - let weekday = new Date(year, month, day); - let weekdayNumber = weekday.getDay(); + const isDayDisabled = (day, month, year) => { + if (props.disabledDays) { + let weekday = new Date(year, month, day); + let weekdayNumber = weekday.getDay(); - return props.disabledDays.indexOf(weekdayNumber) !== -1; - } + return props.disabledDays.indexOf(weekdayNumber) !== -1; + } - return false; - } + return false; + }; - const updateInputfield = (value) => { - if (!inputRef.current) { - return; - } + const updateInputfield = (value) => { + if (!inputRef.current) { + return; + } - let formattedValue = ''; + let formattedValue = ''; - if (value) { - try { - if (isSingleSelection()) { - formattedValue = isValidDate(value) ? formatDateTime(value) : ''; - } - else if (isMultipleSelection()) { - for (let i = 0; i < value.length; i++) { - let selectedValue = value[i]; - let dateAsString = isValidDate(selectedValue) ? formatDateTime(selectedValue) : ''; - formattedValue += dateAsString; - if (i !== (value.length - 1)) { - formattedValue += ', '; + if (value) { + try { + if (isSingleSelection()) { + formattedValue = isValidDate(value) ? formatDateTime(value) : ''; + } else if (isMultipleSelection()) { + for (let i = 0; i < value.length; i++) { + let selectedValue = value[i]; + let dateAsString = isValidDate(selectedValue) ? formatDateTime(selectedValue) : ''; + formattedValue += dateAsString; + if (i !== value.length - 1) { + formattedValue += ', '; + } } + } else if (isRangeSelection()) { + if (value && value.length) { + let startDate = value[0]; + let endDate = value[1]; + + formattedValue = isValidDate(startDate) ? formatDateTime(startDate) : ''; + if (endDate) { + formattedValue += isValidDate(endDate) ? ' - ' + formatDateTime(endDate) : ''; + } + } + } + } catch (err) { + formattedValue = value; + } + } + + inputRef.current.value = formattedValue; + }; + + const formatDateTime = (date) => { + let formattedValue = null; + if (date) { + if (props.timeOnly) { + formattedValue = formatTime(date); + } else { + formattedValue = formatDate(date, getDateFormat()); + if (props.showTime) { + formattedValue += ' ' + formatTime(date); } } - else if (isRangeSelection()) { - if (value && value.length) { - let startDate = value[0]; - let endDate = value[1]; + } + + return formattedValue; + }; - formattedValue = isValidDate(startDate) ? formatDateTime(startDate) : ''; - if (endDate) { - formattedValue += (isValidDate(endDate) ? ' - ' + formatDateTime(endDate) : ''); + const formatDate = (date, format) => { + if (!date) { + return ''; + } + + let iFormat; + const lookAhead = (match) => { + const matches = iFormat + 1 < format.length && format.charAt(iFormat + 1) === match; + if (matches) { + iFormat++; + } + return matches; + }, + formatNumber = (match, value, len) => { + let num = '' + value; + if (lookAhead(match)) { + while (num.length < len) { + num = '0' + num; + } + } + return num; + }, + formatName = (match, value, shortNames, longNames) => { + return lookAhead(match) ? longNames[value] : shortNames[value]; + }; + let output = ''; + let literal = false; + const { dayNamesShort, dayNames, monthNamesShort, monthNames } = localeOptions(props.locale); + + if (date) { + for (iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) { + if (format.charAt(iFormat) === "'" && !lookAhead("'")) { + literal = false; + } else { + output += format.charAt(iFormat); + } + } else { + switch (format.charAt(iFormat)) { + case 'd': + output += formatNumber('d', date.getDate(), 2); + break; + case 'D': + output += formatName('D', date.getDay(), dayNamesShort, dayNames); + break; + case 'o': + output += formatNumber('o', Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3); + break; + case 'm': + output += formatNumber('m', date.getMonth() + 1, 2); + break; + case 'M': + output += formatName('M', date.getMonth(), monthNamesShort, monthNames); + break; + case 'y': + output += lookAhead('y') ? date.getFullYear() : (date.getFullYear() % 100 < 10 ? '0' : '') + (date.getFullYear() % 100); + break; + case '@': + output += date.getTime(); + break; + case '!': + output += date.getTime() * 10000 + ticksTo1970; + break; + case "'": + if (lookAhead("'")) { + output += "'"; + } else { + literal = true; + } + break; + default: + output += format.charAt(iFormat); } } } } - catch (err) { - formattedValue = value; + return output; + }; + + const formatTime = (date) => { + if (!date) { + return ''; } - } - inputRef.current.value = formattedValue; - } + let output = ''; + let hours = date.getHours(); + let minutes = date.getMinutes(); + let seconds = date.getSeconds(); + let milliseconds = date.getMilliseconds(); - const formatDateTime = (date) => { - let formattedValue = null; - if (date) { - if (props.timeOnly) { - formattedValue = formatTime(date); + if (props.hourFormat === '12' && hours > 11 && hours !== 12) { + hours -= 12; + } + + if (props.hourFormat === '12') { + output += hours === 0 ? 12 : hours < 10 ? '0' + hours : hours; + } else { + output += hours < 10 ? '0' + hours : hours; + } + output += ':'; + output += minutes < 10 ? '0' + minutes : minutes; + + if (props.showSeconds) { + output += ':'; + output += seconds < 10 ? '0' + seconds : seconds; + } + + if (props.showMillisec) { + output += '.'; + output += milliseconds < 100 ? (milliseconds < 10 ? '00' : '0') + milliseconds : milliseconds; + } + + if (props.hourFormat === '12') { + output += date.getHours() > 11 ? ' PM' : ' AM'; + } + + return output; + }; + + const parseValueFromString = (text) => { + if (!text || text.trim().length === 0) { + return null; + } + + let value; + + if (isSingleSelection()) { + value = parseDateTime(text); + } else if (isMultipleSelection()) { + let tokens = text.split(','); + value = []; + for (let token of tokens) { + value.push(parseDateTime(token.trim())); + } + } else if (isRangeSelection()) { + let tokens = text.split(' - '); + value = []; + for (let i = 0; i < tokens.length; i++) { + value[i] = parseDateTime(tokens[i].trim()); + } } - else { - formattedValue = formatDate(date, getDateFormat()); + + return value; + }; + + const parseDateTime = (text) => { + let date; + let parts = text.split(' '); + + if (props.timeOnly) { + date = new Date(); + populateTime(date, parts[0], parts[1]); + } else { if (props.showTime) { - formattedValue += ' ' + formatTime(date); + date = parseDate(parts[0], getDateFormat()); + populateTime(date, parts[1], parts[2]); + } else { + date = parseDate(text, getDateFormat()); } } - } - return formattedValue; - } + return date; + }; + + const populateTime = (value, timeString, ampm) => { + if (props.hourFormat === '12' && ampm !== 'PM' && ampm !== 'AM') { + throw new Error('Invalid Time'); + } + + let time = parseTime(timeString, ampm); + value.setHours(time.hour); + value.setMinutes(time.minute); + value.setSeconds(time.second); + value.setMilliseconds(time.millisecond); + }; - const formatDate = (date, format) => { - if (!date) { - return ''; - } + const parseTime = (value, ampm) => { + value = props.showMillisec ? value.replace('.', ':') : value; + let tokens = value.split(':'); + let validTokenLength = props.showSeconds ? 3 : 2; + validTokenLength = props.showMillisec ? validTokenLength + 1 : validTokenLength; - let iFormat; - const lookAhead = (match) => { - const matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); - if (matches) { - iFormat++; + if (tokens.length !== validTokenLength || tokens[0].length !== 2 || tokens[1].length !== 2 || (props.showSeconds && tokens[2].length !== 2) || (props.showMillisec && tokens[3].length !== 3)) { + throw new Error('Invalid time'); } - return matches; - }, - formatNumber = (match, value, len) => { - let num = '' + value; - if (lookAhead(match)) { - while (num.length < len) { - num = '0' + num; - } + + let h = parseInt(tokens[0], 10); + let m = parseInt(tokens[1], 10); + let s = props.showSeconds ? parseInt(tokens[2], 10) : null; + let ms = props.showMillisec ? parseInt(tokens[3], 10) : null; + + if (isNaN(h) || isNaN(m) || h > 23 || m > 59 || (props.hourFormat === '12' && h > 12) || (props.showSeconds && (isNaN(s) || s > 59)) || (props.showMillisec && (isNaN(s) || s > 1000))) { + throw new Error('Invalid time'); + } else { + if (props.hourFormat === '12' && h !== 12 && ampm === 'PM') { + h += 12; } - return num; - }, - formatName = (match, value, shortNames, longNames) => { - return (lookAhead(match) ? longNames[value] : shortNames[value]); - }; - let output = ''; - let literal = false; - const { dayNamesShort, dayNames, monthNamesShort, monthNames } = localeOptions(props.locale); - if (date) { + return { hour: h, minute: m, second: s, millisecond: ms }; + } + }; + + // Ported from jquery-ui datepicker parseDate + const parseDate = (value, format) => { + if (format == null || value == null) { + throw new Error('Invalid arguments'); + } + + value = typeof value === 'object' ? value.toString() : value + ''; + if (value === '') { + return null; + } + + let iFormat, + dim, + extra, + iValue = 0, + shortYearCutoff = typeof props.shortYearCutoff !== 'string' ? props.shortYearCutoff : (new Date().getFullYear() % 100) + parseInt(props.shortYearCutoff, 10), + year = -1, + month = -1, + day = -1, + doy = -1, + literal = false, + date, + lookAhead = (match) => { + let matches = iFormat + 1 < format.length && format.charAt(iFormat + 1) === match; + if (matches) { + iFormat++; + } + return matches; + }, + getNumber = (match) => { + let isDoubled = lookAhead(match), + size = match === '@' ? 14 : match === '!' ? 20 : match === 'y' && isDoubled ? 4 : match === 'o' ? 3 : 2, + minSize = match === 'y' ? size : 1, + digits = new RegExp('^\\d{' + minSize + ',' + size + '}'), + num = value.substring(iValue).match(digits); + if (!num) { + throw new Error('Missing number at position ' + iValue); + } + iValue += num[0].length; + return parseInt(num[0], 10); + }, + getName = (match, shortNames, longNames) => { + let index = -1; + let arr = lookAhead(match) ? longNames : shortNames; + let names = []; + + for (let i = 0; i < arr.length; i++) { + names.push([i, arr[i]]); + } + names.sort((a, b) => { + return -(a[1].length - b[1].length); + }); + + for (let i = 0; i < names.length; i++) { + let name = names[i][1]; + if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) { + index = names[i][0]; + iValue += name.length; + break; + } + } + + if (index !== -1) { + return index + 1; + } else { + throw new Error('Unknown name at position ' + iValue); + } + }, + checkLiteral = () => { + if (value.charAt(iValue) !== format.charAt(iFormat)) { + throw new Error('Unexpected literal at position ' + iValue); + } + iValue++; + }; + + if (props.view === 'month') { + day = 1; + } + + const { dayNamesShort, dayNames, monthNamesShort, monthNames } = localeOptions(props.locale); + for (iFormat = 0; iFormat < format.length; iFormat++) { if (literal) { - if (format.charAt(iFormat) === '\'' && !lookAhead('\'')) { + if (format.charAt(iFormat) === "'" && !lookAhead("'")) { literal = false; } else { - output += format.charAt(iFormat); + checkLiteral(); } } else { switch (format.charAt(iFormat)) { case 'd': - output += formatNumber('d', date.getDate(), 2); + day = getNumber('d'); break; case 'D': - output += formatName('D', date.getDay(), dayNamesShort, dayNames); + getName('D', dayNamesShort, dayNames); break; case 'o': - output += formatNumber('o', - Math.round(( - new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3); + doy = getNumber('o'); break; case 'm': - output += formatNumber('m', date.getMonth() + 1, 2); + month = getNumber('m'); break; case 'M': - output += formatName('M', date.getMonth(), monthNamesShort, monthNames); + month = getName('M', monthNamesShort, monthNames); break; case 'y': - output += lookAhead('y') ? date.getFullYear() : (date.getFullYear() % 100 < 10 ? '0' : '') + (date.getFullYear() % 100); + year = getNumber('y'); break; case '@': - output += date.getTime(); + date = new Date(getNumber('@')); + year = date.getFullYear(); + month = date.getMonth() + 1; + day = date.getDate(); break; case '!': - output += date.getTime() * 10000 + ticksTo1970; + date = new Date((getNumber('!') - ticksTo1970) / 10000); + year = date.getFullYear(); + month = date.getMonth() + 1; + day = date.getDate(); break; - case '\'': - if (lookAhead('\'')) { - output += '\''; + case "'": + if (lookAhead("'")) { + checkLiteral(); } else { literal = true; } - break; - default: - output += format.charAt(iFormat); - } - } - } - } - return output; - } - - const formatTime = (date) => { - if (!date) { - return ''; - } - - let output = ''; - let hours = date.getHours(); - let minutes = date.getMinutes(); - let seconds = date.getSeconds(); - let milliseconds = date.getMilliseconds(); - - if (props.hourFormat === '12' && hours > 11 && hours !== 12) { - hours -= 12; - } - - if (props.hourFormat === '12') { - output += hours === 0 ? 12 : (hours < 10) ? '0' + hours : hours; - } - else { - output += (hours < 10) ? '0' + hours : hours; - } - output += ':'; - output += (minutes < 10) ? '0' + minutes : minutes; - - if (props.showSeconds) { - output += ':'; - output += (seconds < 10) ? '0' + seconds : seconds; - } - - if (props.showMillisec) { - output += '.'; - output += milliseconds < 100 ? (milliseconds < 10 ? '00' : '0') + milliseconds : milliseconds; - } - - if (props.hourFormat === '12') { - output += date.getHours() > 11 ? ' PM' : ' AM'; - } - - return output; - } - - const parseValueFromString = (text) => { - if (!text || text.trim().length === 0) { - return null; - } - - let value; - - if (isSingleSelection()) { - value = parseDateTime(text); - } - else if (isMultipleSelection()) { - let tokens = text.split(','); - value = []; - for (let token of tokens) { - value.push(parseDateTime(token.trim())); - } - } - else if (isRangeSelection()) { - let tokens = text.split(' - '); - value = []; - for (let i = 0; i < tokens.length; i++) { - value[i] = parseDateTime(tokens[i].trim()); - } - } - - return value; - } - - const parseDateTime = (text) => { - let date; - let parts = text.split(' '); - - if (props.timeOnly) { - date = new Date(); - populateTime(date, parts[0], parts[1]); - } - else { - if (props.showTime) { - date = parseDate(parts[0], getDateFormat()); - populateTime(date, parts[1], parts[2]); - } - else { - date = parseDate(text, getDateFormat()); - } - } - - return date; - } - - const populateTime = (value, timeString, ampm) => { - if (props.hourFormat === '12' && (ampm !== 'PM' && ampm !== 'AM')) { - throw new Error('Invalid Time'); - } - - let time = parseTime(timeString, ampm); - value.setHours(time.hour); - value.setMinutes(time.minute); - value.setSeconds(time.second); - value.setMilliseconds(time.millisecond); - } - - const parseTime = (value, ampm) => { - value = props.showMillisec ? value.replace('.', ':') : value; - let tokens = value.split(':'); - let validTokenLength = props.showSeconds ? 3 : 2; - validTokenLength = props.showMillisec ? validTokenLength + 1 : validTokenLength; - - if (tokens.length !== validTokenLength || tokens[0].length !== 2 || tokens[1].length !== 2 || - (props.showSeconds && tokens[2].length !== 2) || - (props.showMillisec && tokens[3].length !== 3)) { - throw new Error('Invalid time'); - } - - let h = parseInt(tokens[0], 10); - let m = parseInt(tokens[1], 10); - let s = props.showSeconds ? parseInt(tokens[2], 10) : null; - let ms = props.showMillisec ? parseInt(tokens[3], 10) : null; - - if (isNaN(h) || isNaN(m) || h > 23 || m > 59 || (props.hourFormat === '12' && h > 12) || - (props.showSeconds && (isNaN(s) || s > 59)) || - (props.showMillisec && (isNaN(s) || s > 1000))) { - throw new Error('Invalid time'); - } - else { - if (props.hourFormat === '12' && h !== 12 && ampm === 'PM') { - h += 12; - } - - return { hour: h, minute: m, second: s, millisecond: ms }; - } - } - - // Ported from jquery-ui datepicker parseDate - const parseDate = (value, format) => { - if (format == null || value == null) { - throw new Error('Invalid arguments'); - } - - value = (typeof value === "object" ? value.toString() : value + ""); - if (value === "") { - return null; - } - - let iFormat, dim, extra, - iValue = 0, - shortYearCutoff = (typeof props.shortYearCutoff !== "string" ? props.shortYearCutoff : new Date().getFullYear() % 100 + parseInt(props.shortYearCutoff, 10)), - year = -1, - month = -1, - day = -1, - doy = -1, - literal = false, - date, - lookAhead = (match) => { - let matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); - if (matches) { - iFormat++; - } - return matches; - }, - getNumber = (match) => { - let isDoubled = lookAhead(match), - size = (match === "@" ? 14 : (match === "!" ? 20 : - (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))), - minSize = (match === "y" ? size : 1), - digits = new RegExp("^\\d{" + minSize + "," + size + "}"), - num = value.substring(iValue).match(digits); - if (!num) { - throw new Error('Missing number at position ' + iValue); - } - iValue += num[0].length; - return parseInt(num[0], 10); - }, - getName = (match, shortNames, longNames) => { - let index = -1; - let arr = lookAhead(match) ? longNames : shortNames; - let names = []; - - for (let i = 0; i < arr.length; i++) { - names.push([i, arr[i]]); - } - names.sort((a, b) => { - return -(a[1].length - b[1].length); - }); - - for (let i = 0; i < names.length; i++) { - let name = names[i][1]; - if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) { - index = names[i][0]; - iValue += name.length; - break; + break; + default: + checkLiteral(); } } + } - if (index !== -1) { - return index + 1; - } else { - throw new Error('Unknown name at position ' + iValue); - } - }, - checkLiteral = () => { - if (value.charAt(iValue) !== format.charAt(iFormat)) { - throw new Error('Unexpected literal at position ' + iValue); + if (iValue < value.length) { + extra = value.substr(iValue); + if (!/^\s+/.test(extra)) { + throw new Error('Extra/unparsed characters found in date: ' + extra); } - iValue++; - }; - - if (props.view === 'month') { - day = 1; - } + } - const { dayNamesShort, dayNames, monthNamesShort, monthNames } = localeOptions(props.locale); + if (year === -1) { + year = new Date().getFullYear(); + } else if (year < 100) { + year += new Date().getFullYear() - (new Date().getFullYear() % 100) + (year <= shortYearCutoff ? 0 : -100); + } - for (iFormat = 0; iFormat < format.length; iFormat++) { - if (literal) { - if (format.charAt(iFormat) === "'" && !lookAhead("'")) { - literal = false; - } else { - checkLiteral(); - } - } else { - switch (format.charAt(iFormat)) { - case "d": - day = getNumber("d"); - break; - case "D": - getName("D", dayNamesShort, dayNames); - break; - case "o": - doy = getNumber("o"); + if (doy > -1) { + month = 1; + day = doy; + do { + dim = getDaysCountInMonth(year, month - 1); + if (day <= dim) { break; - case "m": - month = getNumber("m"); - break; - case "M": - month = getName("M", monthNamesShort, monthNames); - break; - case "y": - year = getNumber("y"); - break; - case "@": - date = new Date(getNumber("@")); - year = date.getFullYear(); - month = date.getMonth() + 1; - day = date.getDate(); - break; - case "!": - date = new Date((getNumber("!") - ticksTo1970) / 10000); - year = date.getFullYear(); - month = date.getMonth() + 1; - day = date.getDate(); - break; - case "'": - if (lookAhead("'")) { - checkLiteral(); - } else { - literal = true; - } - break; - default: - checkLiteral(); - } + } + month++; + day -= dim; + } while (true); } - } - if (iValue < value.length) { - extra = value.substr(iValue); - if (!/^\s+/.test(extra)) { - throw new Error('Extra/unparsed characters found in date: ' + extra); + date = daylightSavingAdjust(new Date(year, month - 1, day)); + if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) { + throw new Error('Invalid date'); // E.g. 31/02/00 } - } - if (year === -1) { - year = new Date().getFullYear(); - } else if (year < 100) { - year += new Date().getFullYear() - new Date().getFullYear() % 100 + - (year <= shortYearCutoff ? 0 : -100); - } + return date; + }; - if (doy > -1) { - month = 1; - day = doy; - do { - dim = getDaysCountInMonth(year, month - 1); - if (day <= dim) { - break; - } - month++; - day -= dim; - } while (true); - } + const isInMinYear = (viewDate) => { + return props.minDate && props.minDate.getFullYear() === viewDate.getFullYear(); + }; - date = daylightSavingAdjust(new Date(year, month - 1, day)); - if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) { - throw new Error('Invalid date'); // E.g. 31/02/00 - } + const isInMaxYear = (viewDate) => { + return props.maxDate && props.maxDate.getFullYear() === viewDate.getFullYear(); + }; + + React.useEffect(() => { + ObjectUtils.combinedRefs(inputRef, props.inputRef); + }, [inputRef, props.inputRef]); - return date; - } + useMountEffect(() => { + let unbindMaskEvents = null; + let viewDate = getViewDate(props.viewDate); + validateDate(viewDate); + setViewDateState(viewDate); - const isInMinYear = (viewDate) => { - return props.minDate && props.minDate.getFullYear() === viewDate.getFullYear(); - } + setCurrentMonth(viewDate.getMonth()); + setCurrentYear(viewDate.getFullYear()); + setCurrentView(props.view); - const isInMaxYear = (viewDate) => { - return props.maxDate && props.maxDate.getFullYear() === viewDate.getFullYear(); - } + if (props.inline) { + overlayRef && overlayRef.current.setAttribute(attributeSelector, ''); - React.useEffect(() => { - ObjectUtils.combinedRefs(inputRef, props.inputRef); - }, [inputRef, props.inputRef]); + if (!props.disabled) { + initFocusableCell(); + if (props.numberOfMonths === 1) { + overlayRef.current.style.width = DomHandler.getOuterWidth(overlayRef.current) + 'px'; + } + } + } else if (props.mask) { + unbindMaskEvents = mask(inputRef.current, { + mask: props.mask, + readOnly: props.readOnlyInput || props.disabled, + onChange: (e) => { + !ignoreMaskChange.current && updateValueOnInput(e.originalEvent, e.value); + ignoreMaskChange.current = false; + }, + onBlur: () => { + ignoreMaskChange.current = true; + } + }).unbindEvents; + } - useMountEffect(() => { - let unbindMaskEvents = null; - let viewDate = getViewDate(props.viewDate); - validateDate(viewDate); - setViewDateState(viewDate); + if (props.value) { + updateInputfield(props.value); + } - setCurrentMonth(viewDate.getMonth()); - setCurrentYear(viewDate.getFullYear()); - setCurrentView(props.view); + return () => { + props.mask && unbindMaskEvents(); + }; + }); - if (props.inline) { - overlayRef && overlayRef.current.setAttribute(attributeSelector, ''); + useUpdateEffect(() => { + setCurrentView(props.view); + }, [props.view]); - if (!props.disabled) { - initFocusableCell(); - if (props.numberOfMonths === 1) { - overlayRef.current.style.width = DomHandler.getOuterWidth(overlayRef.current) + 'px'; - } - } - } - else if (props.mask) { - unbindMaskEvents = mask(inputRef.current, { - mask: props.mask, - readOnly: props.readOnlyInput || props.disabled, - onChange: (e) => { - !ignoreMaskChange.current && updateValueOnInput(e.originalEvent, e.value); - ignoreMaskChange.current = false; - }, - onBlur: () => { - ignoreMaskChange.current = true; + useUpdateEffect(() => { + if (!props.onViewDateChange && !viewStateChanged.current) { + let propValue = props.value; + if (Array.isArray(propValue)) { + propValue = propValue[0]; } - }).unbindEvents; - } - if (props.value) { - updateInputfield(props.value); - } + let prevPropValue = previousValue; + if (Array.isArray(prevPropValue)) { + prevPropValue = prevPropValue[0]; + } - return () => { - props.mask && unbindMaskEvents(); - } - }); + if ((!prevPropValue && propValue) || (propValue && propValue instanceof Date && propValue.getTime() !== prevPropValue.getTime())) { + let viewDate = props.viewDate && isValidDate(props.viewDate) ? props.viewDate : propValue && isValidDate(propValue) ? propValue : new Date(); - useUpdateEffect(() => { - setCurrentView(props.view); - }, [props.view]) + validateDate(viewDate); - useUpdateEffect(() => { - if (!props.onViewDateChange && !viewStateChanged.current) { - let propValue = props.value; - if (Array.isArray(propValue)) { - propValue = propValue[0]; + setViewDateState(viewDate); + viewStateChanged.current = true; + } } + }, [props.onViewDateChange, props.value]); - let prevPropValue = previousValue; - if (Array.isArray(prevPropValue)) { - prevPropValue = prevPropValue[0]; + useUpdateEffect(() => { + if (previousValue !== props.value && (!viewStateChanged || !visible)) { + updateInputfield(props.value); } + }, [props.value, visible]); - if ((!prevPropValue && propValue) || (propValue && propValue instanceof Date && propValue.getTime() !== prevPropValue.getTime())) { - let viewDate = props.viewDate && isValidDate(props.viewDate) ? - props.viewDate : (propValue && isValidDate(propValue) ? propValue : new Date()); - - validateDate(viewDate); + useUpdateEffect(() => { + updateInputfield(props.value); + }, [props.dateFormat, props.hourFormat, props.timeOnly, props.showSeconds, props.showMillisec]); - setViewDateState(viewDate); - viewStateChanged.current = true; + useUpdateEffect(() => { + if (overlayRef.current) { + setNavigationState(viewDateState); + updateFocus(); } - } - }, [props.onViewDateChange, props.value]); + }); - useUpdateEffect(() => { - if (previousValue !== props.value && (!viewStateChanged || !visible)) { - updateInputfield(props.value); - } - }, [props.value, visible]); - - useUpdateEffect(() => { - updateInputfield(props.value); - }, [props.dateFormat, props.hourFormat, props.timeOnly, props.showSeconds, props.showMillisec]); - - useUpdateEffect(() => { - if (overlayRef.current) { - setNavigationState(viewDateState); - updateFocus(); - } - }); - - useUnmountEffect(() => { - if (touchUIMask.current) { - disableModality(); - touchUIMask.current = null; - } - - ZIndexUtils.clear(overlayRef.current); - }); - - React.useImperativeHandle(ref, () => ({ - props, - show, - hide, - getCurrentDateTime, - getViewDate, - updateViewDate, - getElement: () => elementRef.current, - getOverlay: () => overlayRef.current, - getInput: () => inputRef.current - })); - - const createBackwardNavigator = (isVisible) => { - const navigatorProps = isVisible ? { 'onClick': onPrevButtonClick, 'onKeyDown': e => onContainerButtonKeydown(e) } : { 'style': { visibility: 'hidden' } }; - return ( - - ) - } - - const createForwardNavigator = (isVisible) => { - const navigatorProps = isVisible ? { 'onClick': onNextButtonClick, 'onKeyDown': e => onContainerButtonKeydown(e) } : { 'style': { visibility: 'hidden' } }; - return ( - - ) - } + useUnmountEffect(() => { + if (touchUIMask.current) { + disableModality(); + touchUIMask.current = null; + } - const createTitleMonthElement = (month) => { - const monthNames = localeOption('monthNames', props.locale); + ZIndexUtils.clear(overlayRef.current); + }); - if (props.monthNavigator && props.view !== 'month') { - const viewDate = getViewDate(); - const viewMonth = viewDate.getMonth(); - const displayedMonthOptions = monthNames.map((month, index) => ((!isInMinYear(viewDate) || index >= props.minDate.getMonth()) && (!isInMaxYear(viewDate) || index <= props.maxDate.getMonth())) ? { label: month, value: index, index } : null).filter(option => !!option); - const displayedMonthNames = displayedMonthOptions.map(option => option.label); - const content = ( - + React.useImperativeHandle(ref, () => ({ + props, + show, + hide, + getCurrentDateTime, + getViewDate, + updateViewDate, + getElement: () => elementRef.current, + getOverlay: () => overlayRef.current, + getInput: () => inputRef.current + })); + + const createBackwardNavigator = (isVisible) => { + const navigatorProps = isVisible ? { onClick: onPrevButtonClick, onKeyDown: (e) => onContainerButtonKeydown(e) } : { style: { visibility: 'hidden' } }; + return ( + ); + }; - if (props.monthNavigatorTemplate) { - const defaultContentOptions = { - onChange: onMonthDropdownChange, - className: 'p-datepicker-month', - value: viewMonth, - names: displayedMonthNames, - options: displayedMonthOptions, - element: content, - props - }; + const createForwardNavigator = (isVisible) => { + const navigatorProps = isVisible ? { onClick: onNextButtonClick, onKeyDown: (e) => onContainerButtonKeydown(e) } : { style: { visibility: 'hidden' } }; + return ( + + ); + }; - return ObjectUtils.getJSXElement(props.monthNavigatorTemplate, defaultContentOptions); + const createTitleMonthElement = (month) => { + const monthNames = localeOption('monthNames', props.locale); + + if (props.monthNavigator && props.view !== 'month') { + const viewDate = getViewDate(); + const viewMonth = viewDate.getMonth(); + const displayedMonthOptions = monthNames + .map((month, index) => ((!isInMinYear(viewDate) || index >= props.minDate.getMonth()) && (!isInMaxYear(viewDate) || index <= props.maxDate.getMonth()) ? { label: month, value: index, index } : null)) + .filter((option) => !!option); + const displayedMonthNames = displayedMonthOptions.map((option) => option.label); + const content = ( + + ); + + if (props.monthNavigatorTemplate) { + const defaultContentOptions = { + onChange: onMonthDropdownChange, + className: 'p-datepicker-month', + value: viewMonth, + names: displayedMonthNames, + options: displayedMonthOptions, + element: content, + props + }; + + return ObjectUtils.getJSXElement(props.monthNavigatorTemplate, defaultContentOptions); + } + + return content; } - return content; - } - - return currentView === 'date' && - } - - const createTitleYearElement = () => { - if (props.yearNavigator) { - let yearOptions = []; - const years = props.yearRange.split(':'); - const yearStart = parseInt(years[0], 10); - const yearEnd = parseInt(years[1], 10); + return ( + currentView === 'date' && ( + + ) + ); + }; - for (let i = yearStart; i <= yearEnd; i++) { - yearOptions.push(i); + const createTitleYearElement = () => { + if (props.yearNavigator) { + let yearOptions = []; + const years = props.yearRange.split(':'); + const yearStart = parseInt(years[0], 10); + const yearEnd = parseInt(years[1], 10); + + for (let i = yearStart; i <= yearEnd; i++) { + yearOptions.push(i); + } + + const viewDate = getViewDate(); + const viewYear = viewDate.getFullYear(); + const displayedYearNames = yearOptions.filter((year) => !(props.minDate && props.minDate.getFullYear() > year) && !(props.maxDate && props.maxDate.getFullYear() < year)); + const content = ( + + ); + + if (props.yearNavigatorTemplate) { + const options = displayedYearNames.map((name, i) => ({ label: name, value: name, index: i })); + const defaultContentOptions = { + onChange: onYearDropdownChange, + className: 'p-datepicker-year', + value: viewYear, + names: displayedYearNames, + options, + element: content, + props + }; + + return ObjectUtils.getJSXElement(props.yearNavigatorTemplate, defaultContentOptions); + } + + return content; } - const viewDate = getViewDate(); - const viewYear = viewDate.getFullYear(); - const displayedYearNames = yearOptions.filter(year => (!(props.minDate && props.minDate.getFullYear() > year) && !(props.maxDate && props.maxDate.getFullYear() < year))); - const content = ( - + return ( + currentView !== 'year' && ( + + ) ); + }; - if (props.yearNavigatorTemplate) { - const options = displayedYearNames.map((name, i) => ({ label: name, value: name, index: i })); - const defaultContentOptions = { - onChange: onYearDropdownChange, - className: 'p-datepicker-year', - value: viewYear, - names: displayedYearNames, - options, - element: content, - props - }; + const createTitleDecadeElement = () => { + const years = yearPickerValues(); - return ObjectUtils.getJSXElement(props.yearNavigatorTemplate, defaultContentOptions); + if (currentView === 'year') { + return {props.decadeTemplate ? props.decadeTemplate(years) : {`${yearPickerValues()[0]} - ${yearPickerValues()[yearPickerValues().length - 1]}`}}; } - return content; - } + return null; + }; + + const createTitle = (monthMetaData) => { + const month = createTitleMonthElement(monthMetaData.month); + const year = createTitleYearElement(monthMetaData.year); + const decade = createTitleDecadeElement(); + + return ( +
      + {month} + {year} + {decade} +
      + ); + }; + const createDayNames = (weekDays) => { + const dayNames = weekDays.map((weekDay, index) => ( +
    + )); + if (props.showWeek) { + const weekHeader = ( + + ); - return currentView !== 'year' && - } + return [weekHeader, ...dayNames]; + } - const createTitleDecadeElement = () => { - const years = yearPickerValues(); + return dayNames; + }; - if (currentView === 'year') { + const createDateCellContent = (date, className, groupIndex) => { + const content = props.dateTemplate ? props.dateTemplate(date) : date.day; return ( - - {props.decadeTemplate ? props.decadeTemplate(years) : {`${yearPickerValues()[0]} - ${yearPickerValues()[yearPickerValues().length - 1]}`}} + onDateSelect(e, date)} onKeyDown={(e) => onDateCellKeydown(e, date, groupIndex)}> + {content} + - ) - } - - return null; - } + ); + }; - const createTitle = (monthMetaData) => { - const month = createTitleMonthElement(monthMetaData.month); - const year = createTitleYearElement(monthMetaData.year); - const decade = createTitleDecadeElement(); + const createWeek = (weekDates, weekNumber, groupIndex) => { + const week = weekDates.map((date) => { + const selected = isSelected(date); + const cellClassName = classNames({ 'p-datepicker-other-month': date.otherMonth, 'p-datepicker-today': date.today }); + const dateClassName = classNames({ 'p-highlight': selected, 'p-disabled': !date.selectable }); + const content = date.otherMonth && !props.showOtherMonths ? null : createDateCellContent(date, dateClassName, groupIndex); + + return ( + + ); + }); - return ( -
    - {month} - {year} - {decade} -
    - ) - } - - const createDayNames = (weekDays) => { - const dayNames = weekDays.map((weekDay, index) => ( -
    - )); - - if (props.showWeek) { - const weekHeader = ( - - ); + if (props.showWeek) { + const weekNumberCell = ( + + ); - return [weekHeader, ...dayNames]; - } + return [weekNumberCell, ...week]; + } - return dayNames; - } + return week; + }; - const createDateCellContent = (date, className, groupIndex) => { - const content = props.dateTemplate ? props.dateTemplate(date) : date.day; - return ( - onDateSelect(e, date)} onKeyDown={e => onDateCellKeydown(e, date, groupIndex)}> - {content} - - - ) - } + const createDates = (monthMetaData, groupIndex) => { + return monthMetaData.dates.map((weekDates, index) => {createWeek(weekDates, monthMetaData.weekNumbers[index], groupIndex)}); + }; - const createWeek = (weekDates, weekNumber, groupIndex) => { - const week = weekDates.map((date) => { - const selected = isSelected(date); - const cellClassName = classNames({ 'p-datepicker-other-month': date.otherMonth, 'p-datepicker-today': date.today }); - const dateClassName = classNames({ 'p-highlight': selected, 'p-disabled': !date.selectable }); - const content = (date.otherMonth && !props.showOtherMonths) ? null : createDateCellContent(date, dateClassName, groupIndex); + const createDateViewGrid = (monthMetaData, weekDays, groupIndex) => { + const dayNames = createDayNames(weekDays); + const dates = createDates(monthMetaData, groupIndex); return ( - - ) - }); - - if (props.showWeek) { - const weekNumberCell = ( - + currentView === 'date' && ( +
    +
    Name + {weekDay} + + {localeOption('weekHeader', props.locale)} + + {content} + - {weekDay} - - {localeOption('weekHeader', props.locale)} - + {weekNumber} +
    - {content} - - - {weekNumber} - -
    + + {dayNames} + + {dates} +
    +
    + ) ); + }; - return [weekNumberCell, ...week]; - } + const createMonth = (monthMetaData, index) => { + const weekDays = createWeekDaysMeta(); + const backwardNavigator = createBackwardNavigator(index === 0); + const forwardNavigator = createForwardNavigator(props.numberOfMonths === 1 || index === props.numberOfMonths - 1); + const title = createTitle(monthMetaData); - return week; - } + const dateViewGrid = createDateViewGrid(monthMetaData, weekDays, index); + const header = props.headerTemplate ? props.headerTemplate() : null; - const createDates = (monthMetaData, groupIndex) => { - return monthMetaData.dates.map((weekDates, index) => ( - - {createWeek(weekDates, monthMetaData.weekNumbers[index], groupIndex)} - - )); - } + return ( +
    +
    + {header} + {backwardNavigator} + {title} + {forwardNavigator} +
    + {dateViewGrid} +
    + ); + }; - const createDateViewGrid = (monthMetaData, weekDays, groupIndex) => { - const dayNames = createDayNames(weekDays); - const dates = createDates(monthMetaData, groupIndex); + const createMonths = (monthsMetaData) => { + const groups = monthsMetaData.map(createMonth); - return ( - currentView === 'date' &&
    - - - - {dayNames} - - - - {dates} - -
    -
    - ) - } - - const createMonth = (monthMetaData, index) => { - const weekDays = createWeekDaysMeta(); - const backwardNavigator = createBackwardNavigator((index === 0)); - const forwardNavigator = createForwardNavigator((props.numberOfMonths === 1) || (index === props.numberOfMonths - 1)); - const title = createTitle(monthMetaData); - - const dateViewGrid = createDateViewGrid(monthMetaData, weekDays, index); - const header = props.headerTemplate ? props.headerTemplate() : null; + return
    {groups}
    ; + }; - return ( -
    -
    - {header} - {backwardNavigator} - {title} - {forwardNavigator} -
    - {dateViewGrid} -
    - ) - } + const createDateView = () => { + const viewDate = getViewDate(); + const monthsMetaData = createMonthsMeta(viewDate.getMonth(), viewDate.getFullYear()); + const months = createMonths(monthsMetaData); - const createMonths = (monthsMetaData) => { - const groups = monthsMetaData.map(createMonth); + return months; + }; - return ( -
    - {groups} -
    - ) - } + const createMonthViewMonth = (index) => { + const className = classNames('p-monthpicker-month', { 'p-highlight': isMonthSelected(index), 'p-disabled': !isSelectable(1, index, currentYear) }); + const monthNamesShort = localeOption('monthNamesShort', props.locale); + const monthName = monthNamesShort[index]; - const createDateView = () => { - const viewDate = getViewDate(); - const monthsMetaData = createMonthsMeta(viewDate.getMonth(), viewDate.getFullYear()); - const months = createMonths(monthsMetaData); + return ( + onMonthSelect(event, index)} onKeyDown={(event) => onMonthCellKeydown(event, index)}> + {monthName} + + + ); + }; - return months; - } + const createMonthViewMonths = () => { + let months = []; + for (let i = 0; i <= 11; i++) { + months.push(createMonthViewMonth(i)); + } - const createMonthViewMonth = (index) => { - const className = classNames('p-monthpicker-month', { 'p-highlight': isMonthSelected(index), 'p-disabled': !isSelectable(1, index, currentYear) }); - const monthNamesShort = localeOption('monthNamesShort', props.locale); - const monthName = monthNamesShort[index]; + return months; + }; - return ( - onMonthSelect(event, index)} onKeyDown={event => onMonthCellKeydown(event, index)}> - {monthName} - - - ) - } - - const createMonthViewMonths = () => { - let months = []; - for (let i = 0; i <= 11; i++) { - months.push(createMonthViewMonth(i)); - } - - return months; - } - - const monthPickerValues = () => { - let monthPickerValues = []; - const monthNamesShort = localeOption('monthNamesShort', props.locale); - for (let i = 0; i <= 11; i++) { - monthPickerValues.push(monthNamesShort[i]); - } - - return monthPickerValues; - } - - const yearPickerValues = () => { - let yearPickerValues = []; - let base = currentYear - (currentYear % 10); - for (let i = 0; i < 10; i++) { - yearPickerValues.push(base + i); - } - - return yearPickerValues; - } - - const createMonthYearView = () => { - const backwardNavigator = createBackwardNavigator(true); - const forwardNavigator = createForwardNavigator(true); - const yearElement = createTitleYearElement(getViewDate().getFullYear()); - const decade = createTitleDecadeElement(); + const monthPickerValues = () => { + let monthPickerValues = []; + const monthNamesShort = localeOption('monthNamesShort', props.locale); + for (let i = 0; i <= 11; i++) { + monthPickerValues.push(monthNamesShort[i]); + } - return ( - <> -
    -
    -
    - {backwardNavigator} -
    - {yearElement} - {decade} -
    - {forwardNavigator} -
    -
    -
    - - ) - } + return monthPickerValues; + }; - const createDatePicker = () => { - if (!props.timeOnly) { - if (props.view === 'date') { - return createDateView(); + const yearPickerValues = () => { + let yearPickerValues = []; + let base = currentYear - (currentYear % 10); + for (let i = 0; i < 10; i++) { + yearPickerValues.push(base + i); } - else { - return createMonthYearView(); - } - } - - return null; - } - const createHourPicker = () => { - let currentTime = getCurrentDateTime(); - let hour = currentTime.getHours(); + return yearPickerValues; + }; - if (props.hourFormat === '12') { - if (hour === 0) - hour = 12; - else if (hour > 11 && hour !== 12) - hour = hour - 12; - } + const createMonthYearView = () => { + const backwardNavigator = createBackwardNavigator(true); + const forwardNavigator = createForwardNavigator(true); + const yearElement = createTitleYearElement(getViewDate().getFullYear()); + const decade = createTitleDecadeElement(); - const hourDisplay = hour < 10 ? '0' + hour : hour; + return ( + <> +
    +
    +
    + {backwardNavigator} +
    + {yearElement} + {decade} +
    + {forwardNavigator} +
    +
    +
    + + ); + }; + const createDatePicker = () => { + if (!props.timeOnly) { + if (props.view === 'date') { + return createDateView(); + } else { + return createMonthYearView(); + } + } - return ( -
    - - {hourDisplay} - -
    - ) - } + return null; + }; - const createMinutePicker = () => { - const currentTime = getCurrentDateTime(); - const minute = currentTime.getMinutes(); - const minuteDisplay = minute < 10 ? '0' + minute : minute; + const createHourPicker = () => { + let currentTime = getCurrentDateTime(); + let hour = currentTime.getHours(); - return ( -
    - - {minuteDisplay} - -
    - ) - } + if (props.hourFormat === '12') { + if (hour === 0) hour = 12; + else if (hour > 11 && hour !== 12) hour = hour - 12; + } - const createSecondPicker = () => { - if (props.showSeconds) { - const currentTime = getCurrentDateTime(); - const second = currentTime.getSeconds(); - const secondDisplay = second < 10 ? '0' + second : second; + const hourDisplay = hour < 10 ? '0' + hour : hour; return ( -
    - - {secondDisplay} -
    - ) - } - - return null; - } + ); + }; - const createMiliSecondPicker = () => { - if (props.showMillisec) { + const createMinutePicker = () => { const currentTime = getCurrentDateTime(); - const millisecond = currentTime.getMilliseconds(); - const millisecondDisplay = millisecond < 100 ? (millisecond < 10 ? '00' : '0') + millisecond : millisecond; + const minute = currentTime.getMinutes(); + const minuteDisplay = minute < 10 ? '0' + minute : minute; return ( -
    - - {millisecondDisplay} -
    - ) - } + ); + }; - return null; - } + const createSecondPicker = () => { + if (props.showSeconds) { + const currentTime = getCurrentDateTime(); + const second = currentTime.getSeconds(); + const secondDisplay = second < 10 ? '0' + second : second; + + return ( +
    + + {secondDisplay} + +
    + ); + } - const createAmPmPicker = () => { - if (props.hourFormat === '12') { - const currentTime = getCurrentDateTime(); - const hour = currentTime.getHours(); - const display = hour > 11 ? 'PM' : 'AM'; + return null; + }; - return ( -
    - - {display} - -
    - ) - } + const createMiliSecondPicker = () => { + if (props.showMillisec) { + const currentTime = getCurrentDateTime(); + const millisecond = currentTime.getMilliseconds(); + const millisecondDisplay = millisecond < 100 ? (millisecond < 10 ? '00' : '0') + millisecond : millisecond; + + return ( +
    + + {millisecondDisplay} + +
    + ); + } + + return null; + }; - return null; - } + const createAmPmPicker = () => { + if (props.hourFormat === '12') { + const currentTime = getCurrentDateTime(); + const hour = currentTime.getHours(); + const display = hour > 11 ? 'PM' : 'AM'; + + return ( +
    + + {display} + +
    + ); + } - const createSeparator = (separator) => { - return ( -
    - {separator} -
    - ) - } - - const createTimePicker = () => { - if ((props.showTime || props.timeOnly) && currentView === 'date') { + return null; + }; + + const createSeparator = (separator) => { return ( -
    - {createHourPicker()} - {createSeparator(':')} - {createMinutePicker()} - {props.showSeconds && createSeparator(':')} - {createSecondPicker()} - {props.showMillisec && createSeparator('.')} - {createMiliSecondPicker()} - {props.hourFormat === '12' && createSeparator(':')} - {createAmPmPicker()} +
    + {separator}
    - ) - } + ); + }; - return null; - } + const createTimePicker = () => { + if ((props.showTime || props.timeOnly) && currentView === 'date') { + return ( +
    + {createHourPicker()} + {createSeparator(':')} + {createMinutePicker()} + {props.showSeconds && createSeparator(':')} + {createSecondPicker()} + {props.showMillisec && createSeparator('.')} + {createMiliSecondPicker()} + {props.hourFormat === '12' && createSeparator(':')} + {createAmPmPicker()} +
    + ); + } - const createInputElement = () => { - if (!props.inline) { - return ( - - ) - } + return null; + }; + + const createInputElement = () => { + if (!props.inline) { + return ( + + ); + } - return null; - } + return null; + }; + + const createButton = () => { + if (props.showIcon) { + return
    - ) - } + return ( +
    +
    + ); + } - return null; - } + return null; + }; - const createFooter = () => { - if (props.footerTemplate) { - const content = props.footerTemplate(); + const createFooter = () => { + if (props.footerTemplate) { + const content = props.footerTemplate(); - return ( -
    - {content} -
    - ) - } - - return null; - } - - const createMonthPicker = () => { - if (currentView === 'month') { - return
    - { - monthPickerValues().map((m, i) => { - return onMonthSelect(event, i)} key={`month${i + 1}`} className={classNames('p-monthpicker-month', { 'p-highlight': isMonthSelected(i), 'p-disabled': !isSelectable(1, i, currentYear) })}> - {m} - - }) - } -
    - } - - return null; - } - - const createYearPicker = () => { - if (currentView === 'year') { - return
    - { - yearPickerValues().map((y, i) => { - return onYearSelect(event, y)} key={`year${i + 1}`} className={classNames('p-yearpicker-year', { 'p-highlight': isYearSelected(y) })}> - {y} - - }) - } -
    - } - - return null; - } - - const otherProps = ObjectUtils.findDiffKeys(props, Calendar.defaultProps); - const className = classNames('p-calendar p-component p-inputwrapper', props.className, { - [`p-calendar-w-btn p-calendar-w-btn-${props.iconPos}`]: props.showIcon, - 'p-calendar-disabled': props.disabled, - 'p-calendar-timeonly': props.timeOnly, - 'p-inputwrapper-filled': props.value || (DomHandler.hasClass(inputRef.current, 'p-filled') && inputRef.current.value !== ''), - 'p-inputwrapper-focus': focusedState - }); - const panelClassName = classNames('p-datepicker p-component', props.panelClassName, { - 'p-datepicker-inline': props.inline, - 'p-disabled': props.disabled, - 'p-datepicker-timeonly': props.timeOnly, - 'p-datepicker-multiple-month': props.numberOfMonths > 1, - 'p-datepicker-monthpicker': (currentView === 'month'), - 'p-datepicker-touch-ui': props.touchUI - }); - const content = createContent(); - const datePicker = createDatePicker(); - const timePicker = createTimePicker(); - const buttonBar = createButtonBar(); - const footer = createFooter(); - const monthPicker = createMonthPicker(); - const yearPicker = createYearPicker(); - - return ( - - {content} - - {datePicker} - {timePicker} - {monthPicker} - {yearPicker} - {buttonBar} - {footer} - - - ) -})); + return
    {content}
    ; + } + + return null; + }; + + const createMonthPicker = () => { + if (currentView === 'month') { + return ( +
    + {monthPickerValues().map((m, i) => { + return ( + onMonthSelect(event, i)} key={`month${i + 1}`} className={classNames('p-monthpicker-month', { 'p-highlight': isMonthSelected(i), 'p-disabled': !isSelectable(1, i, currentYear) })}> + {m} + + ); + })} +
    + ); + } + + return null; + }; + + const createYearPicker = () => { + if (currentView === 'year') { + return ( +
    + {yearPickerValues().map((y, i) => { + return ( + onYearSelect(event, y)} key={`year${i + 1}`} className={classNames('p-yearpicker-year', { 'p-highlight': isYearSelected(y) })}> + {y} + + ); + })} +
    + ); + } + + return null; + }; + + const otherProps = ObjectUtils.findDiffKeys(props, Calendar.defaultProps); + const className = classNames('p-calendar p-component p-inputwrapper', props.className, { + [`p-calendar-w-btn p-calendar-w-btn-${props.iconPos}`]: props.showIcon, + 'p-calendar-disabled': props.disabled, + 'p-calendar-timeonly': props.timeOnly, + 'p-inputwrapper-filled': props.value || (DomHandler.hasClass(inputRef.current, 'p-filled') && inputRef.current.value !== ''), + 'p-inputwrapper-focus': focusedState + }); + const panelClassName = classNames('p-datepicker p-component', props.panelClassName, { + 'p-datepicker-inline': props.inline, + 'p-disabled': props.disabled, + 'p-datepicker-timeonly': props.timeOnly, + 'p-datepicker-multiple-month': props.numberOfMonths > 1, + 'p-datepicker-monthpicker': currentView === 'month', + 'p-datepicker-touch-ui': props.touchUI + }); + const content = createContent(); + const datePicker = createDatePicker(); + const timePicker = createTimePicker(); + const buttonBar = createButtonBar(); + const footer = createFooter(); + const monthPicker = createMonthPicker(); + const yearPicker = createYearPicker(); + + return ( + + {content} + + {datePicker} + {timePicker} + {monthPicker} + {yearPicker} + {buttonBar} + {footer} + + + ); + }) +); Calendar.displayName = 'Calendar'; Calendar.defaultProps = { @@ -3241,4 +3201,4 @@ Calendar.defaultProps = { onShow: null, onHide: null, onMonthChange: null -} +}; diff --git a/components/lib/calendar/CalendarPanel.js b/components/lib/calendar/CalendarPanel.js index 8b2702a0c3..522c1f8732 100644 --- a/components/lib/calendar/CalendarPanel.js +++ b/components/lib/calendar/CalendarPanel.js @@ -3,17 +3,26 @@ import { CSSTransition } from '../csstransition/CSSTransition'; import { Portal } from '../portal/Portal'; export const CalendarPanel = React.forwardRef((props, ref) => { - const createElement = () => { return ( - +
    {props.children}
    - ) - } + ); + }; const element = createElement(); diff --git a/components/lib/calendar/calendar.d.ts b/components/lib/calendar/calendar.d.ts index d5fca7169d..2473fc3b0b 100644 --- a/components/lib/calendar/calendar.d.ts +++ b/components/lib/calendar/calendar.d.ts @@ -55,10 +55,7 @@ interface CalendarVisibleChangeParams { callback?(): void; } -type CalendarNavigatorTemplateChangeCallback = ( - event: React.SyntheticEvent, - value: string | number | undefined | null -) => void; +type CalendarNavigatorTemplateChangeCallback = (event: React.SyntheticEvent, value: string | number | undefined | null) => void; interface CalendarNavigatorTemplateParams { onChange: CalendarNavigatorTemplateChangeCallback; @@ -151,7 +148,7 @@ export interface CalendarProps { onInput?(event: React.FormEvent): void; onSelect?(e: CalendarSelectParams): void; onChange?(e: CalendarChangeParams): void; - onMonthChange?(e: CalendarMonthChangeParams): void + onMonthChange?(e: CalendarMonthChangeParams): void; onViewDateChange?(e: CalendarViewChangeParams): void; onTodayButtonClick?(event: React.MouseEvent): void; onClearButtonClick?(event: React.MouseEvent): void; diff --git a/components/lib/captcha/Captcha.js b/components/lib/captcha/Captcha.js index 7b83b98cb1..965442b600 100644 --- a/components/lib/captcha/Captcha.js +++ b/components/lib/captcha/Captcha.js @@ -2,95 +2,97 @@ import * as React from 'react'; import { useMountEffect, useUnmountEffect } from '../hooks/Hooks'; import { ObjectUtils } from '../utils/Utils'; -export const Captcha = React.memo(React.forwardRef((props, ref) => { - const elementRef = React.useRef(null); - const instance = React.useRef(null); - const recaptchaScript = React.useRef(null); - const isCaptchaLoaded = React.useRef(false); - - const init = () => { - instance.current = (window).grecaptcha.render(elementRef.current, { - 'sitekey': props.siteKey, - 'theme': props.theme, - 'type': props.type, - 'size': props.size, - 'tabindex': props.tabIndex, - 'hl': props.language, - 'callback': recaptchaCallback, - 'expired-callback': recaptchaExpiredCallback - }); - } - - const reset = () => { - !!instance.current && (window).grecaptcha.reset(instance.current); - } - - const getResponse = () => { - return !!instance.current ? (window).grecaptcha.getResponse(instance.current) : null; - } - - const recaptchaCallback = (response) => { - props.onResponse && props.onResponse({ response }); - } - - const recaptchaExpiredCallback = () => { - props.onExpire && props.onExpire(); - } - - const addRecaptchaScript = () => { - recaptchaScript.current = null; - if (!(window).grecaptcha) { - let head = document.head || document.getElementsByTagName('head')[0]; - let script = document.createElement('script'); - script.src = 'https://www.google.com/recaptcha/api.js?render=explicit'; - script.async = true; - script.defer = true; - script.onload = () => { - if (!(window).grecaptcha) { - // eslint-disable-next-line no-console - console.warn('Recaptcha is not loaded'); - return; - } - - window.grecaptcha.ready(() => { - init(); - }); +export const Captcha = React.memo( + React.forwardRef((props, ref) => { + const elementRef = React.useRef(null); + const instance = React.useRef(null); + const recaptchaScript = React.useRef(null); + const isCaptchaLoaded = React.useRef(false); + + const init = () => { + instance.current = window.grecaptcha.render(elementRef.current, { + sitekey: props.siteKey, + theme: props.theme, + type: props.type, + size: props.size, + tabindex: props.tabIndex, + hl: props.language, + callback: recaptchaCallback, + 'expired-callback': recaptchaExpiredCallback + }); + }; + + const reset = () => { + !!instance.current && window.grecaptcha.reset(instance.current); + }; + + const getResponse = () => { + return !!instance.current ? window.grecaptcha.getResponse(instance.current) : null; + }; + + const recaptchaCallback = (response) => { + props.onResponse && props.onResponse({ response }); + }; + + const recaptchaExpiredCallback = () => { + props.onExpire && props.onExpire(); + }; + + const addRecaptchaScript = () => { + recaptchaScript.current = null; + if (!window.grecaptcha) { + let head = document.head || document.getElementsByTagName('head')[0]; + let script = document.createElement('script'); + script.src = 'https://www.google.com/recaptcha/api.js?render=explicit'; + script.async = true; + script.defer = true; + script.onload = () => { + if (!window.grecaptcha) { + // eslint-disable-next-line no-console + console.warn('Recaptcha is not loaded'); + return; + } + + window.grecaptcha.ready(() => { + init(); + }); + }; + recaptchaScript.current = script; + + head.appendChild(recaptchaScript.current); } - recaptchaScript.current = script; + }; - head.appendChild(recaptchaScript.current); - } - } + useMountEffect(() => { + if (!isCaptchaLoaded.current) { + addRecaptchaScript(); - useMountEffect(() => { - if (!isCaptchaLoaded.current) { - addRecaptchaScript(); + if (window.grecaptcha) { + init(); + } - if ((window).grecaptcha) { - init(); + isCaptchaLoaded.current = true; } + }); - isCaptchaLoaded.current = true; - } - }); - - useUnmountEffect(() => { - if (recaptchaScript.current && recaptchaScript.current.parentNode) { - recaptchaScript.current.parentNode.removeChild(recaptchaScript.current); - } - }); + useUnmountEffect(() => { + if (recaptchaScript.current && recaptchaScript.current.parentNode) { + recaptchaScript.current.parentNode.removeChild(recaptchaScript.current); + } + }); - React.useImperativeHandle(ref, () => ({ - props, - reset, - getResponse, - getElement: () => elementRef.current - })); + React.useImperativeHandle(ref, () => ({ + props, + reset, + getResponse, + getElement: () => elementRef.current + })); - const otherProps = ObjectUtils.findDiffKeys(props, Captcha.defaultProps); + const otherProps = ObjectUtils.findDiffKeys(props, Captcha.defaultProps); - return
    -})); + return
    ; + }) +); Captcha.displayName = 'Captcha'; Captcha.defaultProps = { @@ -104,4 +106,4 @@ Captcha.defaultProps = { language: 'en', onResponse: null, onExpire: null -} +}; diff --git a/components/lib/card/Card.js b/components/lib/card/Card.js index e374b4aa51..6d53da013f 100644 --- a/components/lib/card/Card.js +++ b/components/lib/card/Card.js @@ -2,32 +2,31 @@ import * as React from 'react'; import { classNames, ObjectUtils } from '../utils/Utils'; export const Card = React.forwardRef((props, ref) => { - const elementRef = React.useRef(ref); const createHeader = () => { if (props.header) { - return
    {ObjectUtils.getJSXElement(props.header, props)}
    + return
    {ObjectUtils.getJSXElement(props.header, props)}
    ; } return null; - } + }; const createBody = () => { - const title = props.title &&
    {ObjectUtils.getJSXElement(props.title, props)}
    - const subTitle = props.subTitle &&
    {ObjectUtils.getJSXElement(props.subTitle, props)}
    - const children = props.children &&
    {props.children}
    - const footer = props.footer &&
    {ObjectUtils.getJSXElement(props.footer, props)}
    ; + const title = props.title &&
    {ObjectUtils.getJSXElement(props.title, props)}
    ; + const subTitle = props.subTitle &&
    {ObjectUtils.getJSXElement(props.subTitle, props)}
    ; + const children = props.children &&
    {props.children}
    ; + const footer = props.footer &&
    {ObjectUtils.getJSXElement(props.footer, props)}
    ; return ( -
    +
    {title} {subTitle} {children} {footer}
    - ) - } + ); + }; React.useEffect(() => { ObjectUtils.combinedRefs(elementRef, ref); @@ -43,7 +42,7 @@ export const Card = React.forwardRef((props, ref) => { {header} {body}
    - ) + ); }); Card.displayName = 'Card'; @@ -56,4 +55,4 @@ Card.defaultProps = { subTitle: null, style: null, className: null -} +}; diff --git a/components/lib/card/card.d.ts b/components/lib/card/card.d.ts index 1d7efd1c49..2029da822e 100644 --- a/components/lib/card/card.d.ts +++ b/components/lib/card/card.d.ts @@ -10,4 +10,4 @@ export interface CardProps extends Omit { } +export declare class Card extends React.Component {} diff --git a/components/lib/carousel/Carousel.js b/components/lib/carousel/Carousel.js index e24dfa5dc6..558169ef79 100644 --- a/components/lib/carousel/Carousel.js +++ b/components/lib/carousel/Carousel.js @@ -13,555 +13,531 @@ const CarouselItem = React.memo((props) => { 'p-carousel-item-end': props.end }); - return ( -
    - {content} -
    - ) + return
    {content}
    ; }); -export const Carousel = React.memo(React.forwardRef((props, ref) => { - const [numVisibleState, setNumVisibleState] = React.useState(props.numVisible); - const [numScrollState, setNumScrollState] = React.useState(props.numScroll); - const [totalShiftedItemsState, setTotalShiftedItemsState] = React.useState((props.page * props.numScroll) * -1); - const [pageState, setPageState] = React.useState(props.page); - const elementRef = React.useRef(null); - const itemsContainerRef = React.useRef(null); - const remainingItems = React.useRef(0); - const allowAutoplay = React.useRef(!!props.autoplayInterval); - const attributeSelector = React.useRef(''); - const swipeThreshold = React.useRef(20); - const startPos = React.useRef(null); - const interval = React.useRef(null); - const carouselStyle = React.useRef(null); - const isRemainingItemsAdded = React.useRef(false); - const responsiveOptions = React.useRef(null); - const prevNumScroll = usePrevious(numScrollState); - const prevNumVisible = usePrevious(numVisibleState); - const prevValue = usePrevious(props.value); - const prevPage = usePrevious(props.page); - const isVertical = props.orientation === 'vertical'; - const circular = props.circular || !!props.autoplayInterval; - const isCircular = circular && props.value && props.value.length >= numVisibleState; - const currentPage = props.onPageChange ? props.page : pageState; - const totalIndicators = props.value ? Math.max(Math.ceil((props.value.length - numVisibleState) / numScrollState) + 1, 0) : 0; - const isAutoplay = totalIndicators && props.autoplayInterval && allowAutoplay.current; - - const [bindWindowResizeListener,] = useResizeListener({ - listener: () => { - calculatePosition(); - }, when: props.responsiveOptions - }); +export const Carousel = React.memo( + React.forwardRef((props, ref) => { + const [numVisibleState, setNumVisibleState] = React.useState(props.numVisible); + const [numScrollState, setNumScrollState] = React.useState(props.numScroll); + const [totalShiftedItemsState, setTotalShiftedItemsState] = React.useState(props.page * props.numScroll * -1); + const [pageState, setPageState] = React.useState(props.page); + const elementRef = React.useRef(null); + const itemsContainerRef = React.useRef(null); + const remainingItems = React.useRef(0); + const allowAutoplay = React.useRef(!!props.autoplayInterval); + const attributeSelector = React.useRef(''); + const swipeThreshold = React.useRef(20); + const startPos = React.useRef(null); + const interval = React.useRef(null); + const carouselStyle = React.useRef(null); + const isRemainingItemsAdded = React.useRef(false); + const responsiveOptions = React.useRef(null); + const prevNumScroll = usePrevious(numScrollState); + const prevNumVisible = usePrevious(numVisibleState); + const prevValue = usePrevious(props.value); + const prevPage = usePrevious(props.page); + const isVertical = props.orientation === 'vertical'; + const circular = props.circular || !!props.autoplayInterval; + const isCircular = circular && props.value && props.value.length >= numVisibleState; + const currentPage = props.onPageChange ? props.page : pageState; + const totalIndicators = props.value ? Math.max(Math.ceil((props.value.length - numVisibleState) / numScrollState) + 1, 0) : 0; + const isAutoplay = totalIndicators && props.autoplayInterval && allowAutoplay.current; + + const [bindWindowResizeListener] = useResizeListener({ + listener: () => { + calculatePosition(); + }, + when: props.responsiveOptions + }); - const step = (dir, page) => { - let totalShiftedItems = totalShiftedItemsState; - if (page != null) { - totalShiftedItems = (numScrollState * page) * -1; + const step = (dir, page) => { + let totalShiftedItems = totalShiftedItemsState; + if (page != null) { + totalShiftedItems = numScrollState * page * -1; - if (isCircular) { - totalShiftedItems -= numVisibleState; - } + if (isCircular) { + totalShiftedItems -= numVisibleState; + } - isRemainingItemsAdded.current = false; - } - else { - totalShiftedItems += (numScrollState * dir); - if (isRemainingItemsAdded.current) { - totalShiftedItems += remainingItems.current - (numScrollState * dir); isRemainingItemsAdded.current = false; + } else { + totalShiftedItems += numScrollState * dir; + if (isRemainingItemsAdded.current) { + totalShiftedItems += remainingItems.current - numScrollState * dir; + isRemainingItemsAdded.current = false; + } + + const originalShiftedItems = isCircular ? totalShiftedItems + numVisibleState : totalShiftedItems; + page = Math.abs(Math.floor(originalShiftedItems / numScrollState)); } - const originalShiftedItems = isCircular ? (totalShiftedItems + numVisibleState) : totalShiftedItems; - page = Math.abs(Math.floor(originalShiftedItems / numScrollState)); - } - - if (isCircular && pageState === (totalIndicators - 1) && dir === -1) { - totalShiftedItems = -1 * (props.value.length + numVisibleState); - page = 0; - } - else if (isCircular && pageState === 0 && dir === 1) { - totalShiftedItems = 0; - page = (totalIndicators - 1); - } - else if (page === (totalIndicators - 1) && remainingItems.current > 0) { - totalShiftedItems += ((remainingItems.current * -1) - (numScrollState * dir)); - isRemainingItemsAdded.current = true; - } - - if (itemsContainerRef.current) { - DomHandler.removeClass(itemsContainerRef.current, 'p-items-hidden'); - changePosition(totalShiftedItems); - itemsContainerRef.current.style.transition = 'transform 500ms ease 0s'; - } - - if (props.onPageChange) { - setTotalShiftedItemsState(totalShiftedItems); - props.onPageChange({ - page - }) - } - else { - setPageState(page); - setTotalShiftedItemsState(totalShiftedItems); - } - } - - const calculatePosition = () => { - if (itemsContainerRef.current && responsiveOptions.current) { - let windowWidth = window.innerWidth; - let matchedResponsiveData = { - numVisible: props.numVisible, - numScroll: props.numScroll + if (isCircular && pageState === totalIndicators - 1 && dir === -1) { + totalShiftedItems = -1 * (props.value.length + numVisibleState); + page = 0; + } else if (isCircular && pageState === 0 && dir === 1) { + totalShiftedItems = 0; + page = totalIndicators - 1; + } else if (page === totalIndicators - 1 && remainingItems.current > 0) { + totalShiftedItems += remainingItems.current * -1 - numScrollState * dir; + isRemainingItemsAdded.current = true; } - for (let i = 0; i < responsiveOptions.current.length; i++) { - let res = responsiveOptions.current[i]; + if (itemsContainerRef.current) { + DomHandler.removeClass(itemsContainerRef.current, 'p-items-hidden'); + changePosition(totalShiftedItems); + itemsContainerRef.current.style.transition = 'transform 500ms ease 0s'; + } - if (parseInt(res.breakpoint, 10) >= windowWidth) { - matchedResponsiveData = res; - } + if (props.onPageChange) { + setTotalShiftedItemsState(totalShiftedItems); + props.onPageChange({ + page + }); + } else { + setPageState(page); + setTotalShiftedItemsState(totalShiftedItems); } + }; - if (numScrollState !== matchedResponsiveData.numScroll) { - let page = Math.floor((currentPage * numScrollState) / matchedResponsiveData.numScroll); - let totalShiftedItems = (matchedResponsiveData.numScroll * page) * -1; + const calculatePosition = () => { + if (itemsContainerRef.current && responsiveOptions.current) { + let windowWidth = window.innerWidth; + let matchedResponsiveData = { + numVisible: props.numVisible, + numScroll: props.numScroll + }; - if (isCircular) { - totalShiftedItems -= matchedResponsiveData.numVisible; + for (let i = 0; i < responsiveOptions.current.length; i++) { + let res = responsiveOptions.current[i]; + + if (parseInt(res.breakpoint, 10) >= windowWidth) { + matchedResponsiveData = res; + } } - setTotalShiftedItemsState(totalShiftedItems); - setNumScrollState(matchedResponsiveData.numScroll); + if (numScrollState !== matchedResponsiveData.numScroll) { + let page = Math.floor((currentPage * numScrollState) / matchedResponsiveData.numScroll); + let totalShiftedItems = matchedResponsiveData.numScroll * page * -1; + + if (isCircular) { + totalShiftedItems -= matchedResponsiveData.numVisible; + } - if (props.onPageChange) { - props.onPageChange({ - page - }) + setTotalShiftedItemsState(totalShiftedItems); + setNumScrollState(matchedResponsiveData.numScroll); + + if (props.onPageChange) { + props.onPageChange({ + page + }); + } else { + setPageState(page); + } } - else { - setPageState(page); + + if (numVisibleState !== matchedResponsiveData.numVisible) { + setNumVisibleState(matchedResponsiveData.numVisible); } } + }; - if (numVisibleState !== matchedResponsiveData.numVisible) { - setNumVisibleState(matchedResponsiveData.numVisible); + const navBackward = (e, page) => { + if (circular || currentPage !== 0) { + step(1, page); } - } - } - - const navBackward = (e, page) => { - if (circular || currentPage !== 0) { - step(1, page); - } - - allowAutoplay.current = false; - if (e.cancelable) { - e.preventDefault(); - } - } - - const navForward = (e, page) => { - if (circular || currentPage < (totalIndicators - 1)) { - step(-1, page); - } - - allowAutoplay.current = false; - if (e.cancelable) { - e.preventDefault(); - } - } - - const onDotClick = (e, page) => { - if (page > currentPage) { - navForward(e, page); - } - else if (page < currentPage) { - navBackward(e, page); - } - } - - const onTransitionEnd = (e) => { - if (itemsContainerRef.current && e.propertyName === 'transform') { - DomHandler.addClass(itemsContainerRef.current, 'p-items-hidden'); - itemsContainerRef.current.style.transition = ''; - - if ((pageState === 0 || pageState === (totalIndicators - 1)) && isCircular) { - changePosition(totalShiftedItemsState); + + allowAutoplay.current = false; + if (e.cancelable) { + e.preventDefault(); } - } - } + }; - const onTouchStart = (e) => { - const touchobj = e.changedTouches[0]; + const navForward = (e, page) => { + if (circular || currentPage < totalIndicators - 1) { + step(-1, page); + } - startPos.current = { - x: touchobj.pageX, - y: touchobj.pageY + allowAutoplay.current = false; + if (e.cancelable) { + e.preventDefault(); + } }; - } - - const onTouchMove = (e) => { - if (e.cancelable) { - e.preventDefault(); - } - } - - const onTouchEnd = (e) => { - const touchobj = e.changedTouches[0]; - - if (isVertical) { - changePageOnTouch(e, (touchobj.pageY - startPos.current.y)); - } - else { - changePageOnTouch(e, (touchobj.pageX - startPos.current.x)); - } - } - - const changePageOnTouch = (e, diff) => { - if (Math.abs(diff) > swipeThreshold) { - if (diff < 0) { // left - navForward(e); + + const onDotClick = (e, page) => { + if (page > currentPage) { + navForward(e, page); + } else if (page < currentPage) { + navBackward(e, page); } - else { // right - navBackward(e); + }; + + const onTransitionEnd = (e) => { + if (itemsContainerRef.current && e.propertyName === 'transform') { + DomHandler.addClass(itemsContainerRef.current, 'p-items-hidden'); + itemsContainerRef.current.style.transition = ''; + + if ((pageState === 0 || pageState === totalIndicators - 1) && isCircular) { + changePosition(totalShiftedItemsState); + } } - } - } + }; + + const onTouchStart = (e) => { + const touchobj = e.changedTouches[0]; - const startAutoplay = () => { - interval.current = setInterval(() => { - if (pageState === (totalIndicators - 1)) { - step(-1, 0); + startPos.current = { + x: touchobj.pageX, + y: touchobj.pageY + }; + }; + + const onTouchMove = (e) => { + if (e.cancelable) { + e.preventDefault(); } - else { - step(-1, pageState + 1); + }; + + const onTouchEnd = (e) => { + const touchobj = e.changedTouches[0]; + + if (isVertical) { + changePageOnTouch(e, touchobj.pageY - startPos.current.y); + } else { + changePageOnTouch(e, touchobj.pageX - startPos.current.x); + } + }; + + const changePageOnTouch = (e, diff) => { + if (Math.abs(diff) > swipeThreshold) { + if (diff < 0) { + // left + navForward(e); + } else { + // right + navBackward(e); + } } - }, props.autoplayInterval); - } + }; - const stopAutoplay = () => { - if (interval.current) { - clearInterval(interval.current); - } - } + const startAutoplay = () => { + interval.current = setInterval(() => { + if (pageState === totalIndicators - 1) { + step(-1, 0); + } else { + step(-1, pageState + 1); + } + }, props.autoplayInterval); + }; - const createStyle = () => { - if (!carouselStyle.current) { - carouselStyle.current = DomHandler.createInlineStyle(PrimeReact.nonce); - } + const stopAutoplay = () => { + if (interval.current) { + clearInterval(interval.current); + } + }; + + const createStyle = () => { + if (!carouselStyle.current) { + carouselStyle.current = DomHandler.createInlineStyle(PrimeReact.nonce); + } - let innerHTML = ` + let innerHTML = ` .p-carousel[${attributeSelector.current}] .p-carousel-item { - flex: 1 0 ${(100 / numVisibleState)}% + flex: 1 0 ${100 / numVisibleState}% } `; - if (props.responsiveOptions) { - responsiveOptions.current = [...props.responsiveOptions]; - responsiveOptions.current.sort((data1, data2) => { - const value1 = data1.breakpoint; - const value2 = data2.breakpoint; - return ObjectUtils.sort(value1, value2, -1, PrimeReact.locale, PrimeReact.nullSortOrder); - }); + if (props.responsiveOptions) { + responsiveOptions.current = [...props.responsiveOptions]; + responsiveOptions.current.sort((data1, data2) => { + const value1 = data1.breakpoint; + const value2 = data2.breakpoint; + return ObjectUtils.sort(value1, value2, -1, PrimeReact.locale, PrimeReact.nullSortOrder); + }); - for (let i = 0; i < responsiveOptions.current.length; i++) { - let res = responsiveOptions.current[i]; + for (let i = 0; i < responsiveOptions.current.length; i++) { + let res = responsiveOptions.current[i]; - innerHTML += ` + innerHTML += ` @media screen and (max-width: ${res.breakpoint}) { .p-carousel[${attributeSelector.current}] .p-carousel-item { - flex: 1 0 ${(100 / res.numVisible)}% + flex: 1 0 ${100 / res.numVisible}% } } - ` + `; + } } - } - - carouselStyle.current.innerHTML = innerHTML; - } - - const changePosition = (totalShiftedItems) => { - if (itemsContainerRef.current) { - itemsContainerRef.current.style.transform = isVertical ? `translate3d(0, ${totalShiftedItems * (100 / numVisibleState)}%, 0)` : `translate3d(${totalShiftedItems * (100 / numVisibleState)}%, 0, 0)`; - } - } - - React.useImperativeHandle(ref, () => ({ - props, - getElement: () => elementRef.current - })); - - useMountEffect(() => { - if (elementRef.current) { - attributeSelector.current = UniqueComponentId(); - elementRef.current.setAttribute(attributeSelector.current, ''); - } - - createStyle(); - calculatePosition(); - changePosition(totalShiftedItemsState); - bindWindowResizeListener(); - }); - useUpdateEffect(() => { - let stateChanged = false; - let totalShiftedItems = totalShiftedItemsState; + carouselStyle.current.innerHTML = innerHTML; + }; - if (props.autoplayInterval) { - stopAutoplay(); - } + const changePosition = (totalShiftedItems) => { + if (itemsContainerRef.current) { + itemsContainerRef.current.style.transform = isVertical ? `translate3d(0, ${totalShiftedItems * (100 / numVisibleState)}%, 0)` : `translate3d(${totalShiftedItems * (100 / numVisibleState)}%, 0, 0)`; + } + }; - if (prevNumScroll !== numScrollState || prevNumVisible !== numVisibleState || (props.value && prevValue && prevValue.length !== props.value.length)) { - remainingItems.current = (props.value.length - numVisibleState) % numScrollState; + React.useImperativeHandle(ref, () => ({ + props, + getElement: () => elementRef.current + })); - let page = currentPage; - if (totalIndicators !== 0 && page >= totalIndicators) { - page = totalIndicators - 1; + useMountEffect(() => { + if (elementRef.current) { + attributeSelector.current = UniqueComponentId(); + elementRef.current.setAttribute(attributeSelector.current, ''); + } - if (props.onPageChange) { - props.onPageChange({ - page - }) - } - else { - setPageState(page); - } + createStyle(); + calculatePosition(); + changePosition(totalShiftedItemsState); + bindWindowResizeListener(); + }); - stateChanged = true; - } + useUpdateEffect(() => { + let stateChanged = false; + let totalShiftedItems = totalShiftedItemsState; - totalShiftedItems = (page * numScrollState) * -1; - if (isCircular) { - totalShiftedItems -= numVisibleState; + if (props.autoplayInterval) { + stopAutoplay(); } - if (page === (totalIndicators - 1) && remainingItems.current > 0) { - totalShiftedItems += (-1 * remainingItems.current) + numScrollState; - isRemainingItemsAdded.current = true; - } - else { - isRemainingItemsAdded.current = false; - } + if (prevNumScroll !== numScrollState || prevNumVisible !== numVisibleState || (props.value && prevValue && prevValue.length !== props.value.length)) { + remainingItems.current = (props.value.length - numVisibleState) % numScrollState; - if (totalShiftedItems !== totalShiftedItemsState) { - setTotalShiftedItemsState(totalShiftedItems); - stateChanged = true; - } + let page = currentPage; + if (totalIndicators !== 0 && page >= totalIndicators) { + page = totalIndicators - 1; - changePosition(totalShiftedItems); - } + if (props.onPageChange) { + props.onPageChange({ + page + }); + } else { + setPageState(page); + } - if (isCircular) { - if (pageState === 0) { - totalShiftedItems = -1 * numVisibleState; - } - else if (totalShiftedItems === 0) { - totalShiftedItems = -1 * props.value.length; - if (remainingItems.current > 0) { + stateChanged = true; + } + + totalShiftedItems = page * numScrollState * -1; + if (isCircular) { + totalShiftedItems -= numVisibleState; + } + + if (page === totalIndicators - 1 && remainingItems.current > 0) { + totalShiftedItems += -1 * remainingItems.current + numScrollState; isRemainingItemsAdded.current = true; + } else { + isRemainingItemsAdded.current = false; } - } - if (totalShiftedItems !== totalShiftedItemsState) { - setTotalShiftedItemsState(totalShiftedItems); - stateChanged = true; + if (totalShiftedItems !== totalShiftedItemsState) { + setTotalShiftedItemsState(totalShiftedItems); + stateChanged = true; + } + + changePosition(totalShiftedItems); } - } - if (prevPage !== props.page) { - if (props.page > prevPage && props.page <= (totalIndicators - 1)) { - step(-1, props.page); + if (isCircular) { + if (pageState === 0) { + totalShiftedItems = -1 * numVisibleState; + } else if (totalShiftedItems === 0) { + totalShiftedItems = -1 * props.value.length; + if (remainingItems.current > 0) { + isRemainingItemsAdded.current = true; + } + } + + if (totalShiftedItems !== totalShiftedItemsState) { + setTotalShiftedItemsState(totalShiftedItems); + stateChanged = true; + } } - else if (props.page < prevPage) { - step(1, props.page); + + if (prevPage !== props.page) { + if (props.page > prevPage && props.page <= totalIndicators - 1) { + step(-1, props.page); + } else if (props.page < prevPage) { + step(1, props.page); + } } - } - if (!stateChanged && isAutoplay) { - startAutoplay(); - } - }); + if (!stateChanged && isAutoplay) { + startAutoplay(); + } + }); - useUnmountEffect(() => { - if (props.autoplayInterval) { - stopAutoplay(); - } - }); + useUnmountEffect(() => { + if (props.autoplayInterval) { + stopAutoplay(); + } + }); - const createItems = () => { - if (props.value && props.value.length) { - let clonedItemsForStarting = null; - let clonedItemsForFinishing = null; + const createItems = () => { + if (props.value && props.value.length) { + let clonedItemsForStarting = null; + let clonedItemsForFinishing = null; - if (isCircular) { - let clonedElements = null; + if (isCircular) { + let clonedElements = null; + + clonedElements = props.value.slice(-1 * numVisibleState); + clonedItemsForStarting = clonedElements.map((item, index) => { + const isActive = totalShiftedItemsState * -1 === props.value.length + numVisibleState; + const start = index === 0; + const end = index === clonedElements.length - 1; + const key = index + '_scloned'; + + return ; + }); + + clonedElements = props.value.slice(0, numVisibleState); + clonedItemsForFinishing = clonedElements.map((item, index) => { + const isActive = totalShiftedItemsState === 0; + const start = index === 0; + const end = index === clonedElements.length - 1; + const key = index + '_fcloned'; + + return ; + }); + } - clonedElements = props.value.slice(-1 * numVisibleState); - clonedItemsForStarting = clonedElements.map((item, index) => { - const isActive = (totalShiftedItemsState * -1) === (props.value.length + numVisibleState); - const start = index === 0; - const end = index === (clonedElements.length - 1); - const key = index + '_scloned'; + const items = props.value.map((item, index) => { + const firstIndex = isCircular ? -1 * (totalShiftedItemsState + numVisibleState) : totalShiftedItemsState * -1; + const lastIndex = firstIndex + numVisibleState - 1; + const isActive = firstIndex <= index && lastIndex >= index; + const start = firstIndex === index; + const end = lastIndex === index; - return + return ; }); - clonedElements = props.value.slice(0, numVisibleState); - clonedItemsForFinishing = clonedElements.map((item, index) => { - const isActive = totalShiftedItemsState === 0; - const start = index === 0; - const end = index === (clonedElements.length - 1); - const key = index + '_fcloned'; + return ( + <> + {clonedItemsForStarting} + {items} + {clonedItemsForFinishing} + + ); + } + }; - return - }); + const createHeader = () => { + if (props.header) { + return
    {props.header}
    ; } - const items = props.value.map((item, index) => { - const firstIndex = isCircular ? (-1 * (totalShiftedItemsState + numVisibleState)) : (totalShiftedItemsState * -1); - const lastIndex = firstIndex + numVisibleState - 1; - const isActive = firstIndex <= index && lastIndex >= index; - const start = firstIndex === index; - const end = lastIndex === index; + return null; + }; - return - }); + const createFooter = () => { + if (props.footer) { + return
    {props.footer}
    ; + } - return ( - <> - {clonedItemsForStarting} - {items} - {clonedItemsForFinishing} - - ) - } - } - - const createHeader = () => { - if (props.header) { - return ( -
    - {props.header} -
    - ) - } + return null; + }; - return null; - } + const createContent = () => { + const items = createItems(); + const height = isVertical ? props.verticalViewPortHeight : 'auto'; + const backwardNavigator = createBackwardNavigator(); + const forwardNavigator = createForwardNavigator(); + const className = classNames('p-carousel-container', props.containerClassName); - const createFooter = () => { - if (props.footer) { return ( -
    - {props.footer} +
    + {backwardNavigator} +
    +
    + {items} +
    +
    + {forwardNavigator}
    - ) - } + ); + }; - return null; - } + const createBackwardNavigator = () => { + const isDisabled = (!circular || (props.value && props.value.length < numVisibleState)) && currentPage === 0; + const className = classNames('p-carousel-prev p-link', { + 'p-disabled': isDisabled + }); + const iconClassName = classNames('p-carousel-prev-icon pi', { + 'pi-chevron-left': !isVertical, + 'pi-chevron-up': isVertical + }); - const createContent = () => { - const items = createItems(); - const height = isVertical ? props.verticalViewPortHeight : 'auto'; - const backwardNavigator = createBackwardNavigator(); - const forwardNavigator = createForwardNavigator(); - const className = classNames('p-carousel-container', props.containerClassName); + return
    - ) - - if (getPropValue('footer')) { - const defaultContentOptions = { - accept, - reject, - className: 'p-confirm-popup-footer', - acceptClassName, - rejectClassName, - acceptLabel, - rejectLabel, - element: content, - props: getCurrentProps() - }; + useUnmountEffect(() => { + if (overlayEventListener.current) { + OverlayService.off('overlay-click', overlayEventListener.current); + overlayEventListener.current = null; + } - return ObjectUtils.getJSXElement(getPropValue('footer'), defaultContentOptions); - } + OverlayService.off('confirm-popup', confirm); + ZIndexUtils.clear(overlayRef.current); + }); - return content; - } + React.useImperativeHandle(ref, () => ({ + props, + confirm + })); - const createElement = () => { - const otherProps = ObjectUtils.findDiffKeys(props, ConfirmPopup.defaultProps); - const className = classNames('p-confirm-popup p-component', getPropValue('className')); - const content = createContent(); - const footer = createFooter(); + const createContent = () => { + const currentProps = getCurrentProps(); + const message = ObjectUtils.getJSXElement(getPropValue('message'), currentProps); + const icon = IconUtils.getJSXIcon(getPropValue('icon'), { className: 'p-confirm-popup-icon' }, { props: currentProps }); - return ( - -
    - {content} - {footer} + return ( +
    + {icon} + {message}
    - - ) - } - - const element = createElement(); + ); + }; + + const createFooter = () => { + const acceptClassName = classNames('p-confirm-popup-accept p-button-sm', getPropValue('acceptClassName')); + const rejectClassName = classNames( + 'p-confirm-popup-reject p-button-sm', + { + 'p-button-text': !getPropValue('rejectClassName') + }, + getPropValue('rejectClassName') + ); + + const content = ( +
    +
    + ); + + if (getPropValue('footer')) { + const defaultContentOptions = { + accept, + reject, + className: 'p-confirm-popup-footer', + acceptClassName, + rejectClassName, + acceptLabel, + rejectLabel, + element: content, + props: getCurrentProps() + }; + + return ObjectUtils.getJSXElement(getPropValue('footer'), defaultContentOptions); + } - return -})); + return content; + }; + + const createElement = () => { + const otherProps = ObjectUtils.findDiffKeys(props, ConfirmPopup.defaultProps); + const className = classNames('p-confirm-popup p-component', getPropValue('className')); + const content = createContent(); + const footer = createFooter(); + + return ( + +
    + {content} + {footer} +
    +
    + ); + }; + + const element = createElement(); + + return ; + }) +); ConfirmPopup.displayName = 'ConfirmPopup'; ConfirmPopup.defaultProps = { @@ -274,4 +292,4 @@ ConfirmPopup.defaultProps = { accept: null, reject: null, transitionOptions: null -} +}; diff --git a/components/lib/contextmenu/ContextMenu.js b/components/lib/contextmenu/ContextMenu.js index 8d78f53537..787cf2c657 100644 --- a/components/lib/contextmenu/ContextMenu.js +++ b/components/lib/contextmenu/ContextMenu.js @@ -6,188 +6,200 @@ import { Portal } from '../portal/Portal'; import { classNames, DomHandler, ObjectUtils, ZIndexUtils } from '../utils/Utils'; import { ContextMenuSub } from './ContextMenuSub'; -export const ContextMenu = React.memo(React.forwardRef((props, ref) => { - const [visibleState, setVisibleState] = React.useState(false); - const [reshowState, setReshowState] = React.useState(false); - const [resetMenuState, setResetMenuState] = React.useState(false); - const menuRef = React.useRef(null); - const currentEvent = React.useRef(null); - - const [bindDocumentClickListener, unbindDocumentClickListener] = useEventListener({ - type: 'click', listener: event => { - if (isOutsideClicked(event) && event.button !== 2) { - hide(event); - setResetMenuState(true); - } - } - }); - - const [bindDocumentContextMenuListener,] = useEventListener({ - type: 'contextmenu', listener: event => { - show(event); - } - }); - - const [bindDocumentResizeListener, unbindDocumentResizeListener] = useResizeListener({ - listener: event => { - if (visibleState && !DomHandler.isTouchDevice()) { - hide(event); +export const ContextMenu = React.memo( + React.forwardRef((props, ref) => { + const [visibleState, setVisibleState] = React.useState(false); + const [reshowState, setReshowState] = React.useState(false); + const [resetMenuState, setResetMenuState] = React.useState(false); + const menuRef = React.useRef(null); + const currentEvent = React.useRef(null); + + const [bindDocumentClickListener, unbindDocumentClickListener] = useEventListener({ + type: 'click', + listener: (event) => { + if (isOutsideClicked(event) && event.button !== 2) { + hide(event); + setResetMenuState(true); + } } - } - }); - - const onMenuClick = () => { - setResetMenuState(false); - } - - const onMenuMouseEnter = () => { - setResetMenuState(false); - } - - const show = (event) => { - event.stopPropagation(); - event.preventDefault(); - - currentEvent.current = event; - - if (visibleState) { - setReshowState(true); - } - else { - setVisibleState(true); - props.onShow && props.onShow(currentEvent.current); - } - } - - const hide = (event) => { - currentEvent.current = event; - - setVisibleState(false); - setReshowState(false); - props.onHide && props.onHide(currentEvent.current); - } - - const onEnter = () => { - if (props.autoZIndex) { - ZIndexUtils.set('menu', menuRef.current, PrimeReact.autoZIndex, props.baseZIndex || PrimeReact.zIndex['menu']); - } - - position(currentEvent.current); - } - - const onEntered = () => { - bindDocumentListeners(); - } - - const onExit = () => { - unbindDocumentListeners(); - ZIndexUtils.clear(menuRef.current); - } - - const onExited = () => { - ZIndexUtils.clear(menuRef.current); - } - - const position = (event) => { - if (event) { - let left = event.pageX + 1; - let top = event.pageY + 1; - let width = menuRef.current.offsetParent ? menuRef.current.offsetWidth : DomHandler.getHiddenElementOuterWidth(menuRef.current); - let height = menuRef.current.offsetParent ? menuRef.current.offsetHeight : DomHandler.getHiddenElementOuterHeight(menuRef.current); - let viewport = DomHandler.getViewport(); - - //flip - if (left + width - document.body.scrollLeft > viewport.width) { - left -= width; + }); + + const [bindDocumentContextMenuListener] = useEventListener({ + type: 'contextmenu', + listener: (event) => { + show(event); } + }); - //flip - if (top + height - document.body.scrollTop > viewport.height) { - top -= height; + const [bindDocumentResizeListener, unbindDocumentResizeListener] = useResizeListener({ + listener: (event) => { + if (visibleState && !DomHandler.isTouchDevice()) { + hide(event); + } } + }); + + const onMenuClick = () => { + setResetMenuState(false); + }; + + const onMenuMouseEnter = () => { + setResetMenuState(false); + }; - //fit - if (left < document.body.scrollLeft) { - left = document.body.scrollLeft; + const show = (event) => { + event.stopPropagation(); + event.preventDefault(); + + currentEvent.current = event; + + if (visibleState) { + setReshowState(true); + } else { + setVisibleState(true); + props.onShow && props.onShow(currentEvent.current); } + }; + + const hide = (event) => { + currentEvent.current = event; - //fit - if (top < document.body.scrollTop) { - top = document.body.scrollTop; + setVisibleState(false); + setReshowState(false); + props.onHide && props.onHide(currentEvent.current); + }; + + const onEnter = () => { + if (props.autoZIndex) { + ZIndexUtils.set('menu', menuRef.current, PrimeReact.autoZIndex, props.baseZIndex || PrimeReact.zIndex['menu']); } - menuRef.current.style.left = left + 'px'; - menuRef.current.style.top = top + 'px'; - } - } + position(currentEvent.current); + }; + + const onEntered = () => { + bindDocumentListeners(); + }; + + const onExit = () => { + unbindDocumentListeners(); + ZIndexUtils.clear(menuRef.current); + }; + + const onExited = () => { + ZIndexUtils.clear(menuRef.current); + }; + + const position = (event) => { + if (event) { + let left = event.pageX + 1; + let top = event.pageY + 1; + let width = menuRef.current.offsetParent ? menuRef.current.offsetWidth : DomHandler.getHiddenElementOuterWidth(menuRef.current); + let height = menuRef.current.offsetParent ? menuRef.current.offsetHeight : DomHandler.getHiddenElementOuterHeight(menuRef.current); + let viewport = DomHandler.getViewport(); + + //flip + if (left + width - document.body.scrollLeft > viewport.width) { + left -= width; + } + + //flip + if (top + height - document.body.scrollTop > viewport.height) { + top -= height; + } + + //fit + if (left < document.body.scrollLeft) { + left = document.body.scrollLeft; + } + + //fit + if (top < document.body.scrollTop) { + top = document.body.scrollTop; + } + + menuRef.current.style.left = left + 'px'; + menuRef.current.style.top = top + 'px'; + } + }; - const onLeafClick = (event) => { - setResetMenuState(true); - hide(event); + const onLeafClick = (event) => { + setResetMenuState(true); + hide(event); - event.stopPropagation(); - } + event.stopPropagation(); + }; - const isOutsideClicked = (event) => { - return menuRef && menuRef.current && !(menuRef.current.isSameNode(event.target) || menuRef.current.contains(event.target)); - } + const isOutsideClicked = (event) => { + return menuRef && menuRef.current && !(menuRef.current.isSameNode(event.target) || menuRef.current.contains(event.target)); + }; - const bindDocumentListeners = () => { - bindDocumentResizeListener(); - bindDocumentClickListener(); - } + const bindDocumentListeners = () => { + bindDocumentResizeListener(); + bindDocumentClickListener(); + }; - const unbindDocumentListeners = () => { - unbindDocumentResizeListener(); - unbindDocumentClickListener(); - } + const unbindDocumentListeners = () => { + unbindDocumentResizeListener(); + unbindDocumentClickListener(); + }; - useMountEffect(() => { - if (props.global) { - bindDocumentContextMenuListener(); - } - }); + useMountEffect(() => { + if (props.global) { + bindDocumentContextMenuListener(); + } + }); - useUpdateEffect(() => { - if (visibleState) { - setVisibleState(false); - setReshowState(false); - setResetMenuState(true); - } - else if (!reshowState && !visibleState && resetMenuState) { - show(currentEvent.current); - } - }, [reshowState]); - - useUnmountEffect(() => { - ZIndexUtils.clear(menuRef.current); - }); - - React.useImperativeHandle(ref, () => ({ - props, - show, - hide, - getElement: () => menuRef.current - })); - - const createContextMenu = () => { - const otherProps = ObjectUtils.findDiffKeys(props, ContextMenu.defaultProps); - const className = classNames('p-contextmenu p-component', props.className); - - return ( - -
    - -
    -
    - ) - } - - const element = createContextMenu(); - - return -})); + useUpdateEffect(() => { + if (visibleState) { + setVisibleState(false); + setReshowState(false); + setResetMenuState(true); + } else if (!reshowState && !visibleState && resetMenuState) { + show(currentEvent.current); + } + }, [reshowState]); + + useUnmountEffect(() => { + ZIndexUtils.clear(menuRef.current); + }); + + React.useImperativeHandle(ref, () => ({ + props, + show, + hide, + getElement: () => menuRef.current + })); + + const createContextMenu = () => { + const otherProps = ObjectUtils.findDiffKeys(props, ContextMenu.defaultProps); + const className = classNames('p-contextmenu p-component', props.className); + + return ( + +
    + +
    +
    + ); + }; + + const element = createContextMenu(); + + return ; + }) +); ContextMenu.displayName = 'ContextMenu'; ContextMenu.defaultProps = { @@ -203,4 +215,4 @@ ContextMenu.defaultProps = { transitionOptions: null, onShow: null, onHide: null -} +}; diff --git a/components/lib/contextmenu/ContextMenuSub.js b/components/lib/contextmenu/ContextMenuSub.js index 031b9626d9..71d8fc622d 100644 --- a/components/lib/contextmenu/ContextMenuSub.js +++ b/components/lib/contextmenu/ContextMenuSub.js @@ -19,7 +19,7 @@ export const ContextMenuSub = React.memo((props) => { return; } setActiveItemState(item); - } + }; const onItemClick = (event, item) => { if (item.disabled) { @@ -41,44 +41,43 @@ export const ContextMenuSub = React.memo((props) => { if (!item.items) { props.onLeafClick(event); } - } + }; const position = () => { const parentItem = submenuRef.current.parentElement; - const containerOffset = DomHandler.getOffset(submenuRef.current.parentElement) + const containerOffset = DomHandler.getOffset(submenuRef.current.parentElement); const viewport = DomHandler.getViewport(); const sublistWidth = submenuRef.current.offsetParent ? submenuRef.current.offsetWidth : DomHandler.getHiddenElementOuterWidth(submenuRef.current); const itemOuterWidth = DomHandler.getOuterWidth(parentItem.children[0]); submenuRef.current.style.top = '0px'; - if ((parseInt(containerOffset.left, 10) + itemOuterWidth + sublistWidth) > (viewport.width - DomHandler.calculateScrollbarWidth())) { + if (parseInt(containerOffset.left, 10) + itemOuterWidth + sublistWidth > viewport.width - DomHandler.calculateScrollbarWidth()) { submenuRef.current.style.left = -1 * sublistWidth + 'px'; - } - else { + } else { submenuRef.current.style.left = itemOuterWidth + 'px'; } - } + }; const onEnter = () => { position(); - } + }; useUpdateEffect(() => { active && position(); }); const createSeparator = (index) => { - return
  • - } + return
  • ; + }; const createSubmenu = (item) => { if (item.items) { - return + return ; } return null; - } + }; const createMenuItem = (item, index) => { const active = activeItemState === item; @@ -88,12 +87,11 @@ export const ContextMenuSub = React.memo((props) => { const iconClassName = classNames('p-menuitem-icon', item.icon); const submenuIconClassName = 'p-submenu-icon pi pi-angle-right'; const icon = IconUtils.getJSXIcon(item.icon, { className: 'p-menuitem-icon' }, { props: props.menuProps }); - const label = item.label && {item.label}; + const label = item.label && {item.label}; const submenuIcon = item.items && ; const submenu = createSubmenu(item); let content = ( - onItemClick(event, item, index)} role="menuitem" - aria-haspopup={item.items != null} aria-disabled={item.disabled}> + onItemClick(event, item, index)} role='menuitem' aria-haspopup={item.items != null} aria-disabled={item.disabled}> {icon} {label} {submenuIcon} @@ -117,20 +115,20 @@ export const ContextMenuSub = React.memo((props) => { } return ( -
  • onItemMouseEnter(event, item)}> +
  • onItemMouseEnter(event, item)}> {content} {submenu}
  • - ) - } + ); + }; const createItem = (item, index) => { return item.separator ? createSeparator(index) : createMenuItem(item, index); - } + }; const createMenu = () => { return props.model ? props.model.map(createItem) : null; - } + }; const className = classNames({ 'p-submenu-list': !props.root @@ -138,12 +136,12 @@ export const ContextMenuSub = React.memo((props) => { const submenu = createMenu(); return ( - +
      {submenu}
    - ) + ); }); ContextMenuSub.displayName = 'ContextMenuSub'; diff --git a/components/lib/csstransition/CSSTransition.js b/components/lib/csstransition/CSSTransition.js index 8651720d3e..fabf276d30 100644 --- a/components/lib/csstransition/CSSTransition.js +++ b/components/lib/csstransition/CSSTransition.js @@ -10,43 +10,43 @@ export const CSSTransition = React.forwardRef((props, ref) => { const onEnter = (node, isAppearing) => { props.onEnter && props.onEnter(node, isAppearing); // component props.options && props.options.onEnter && props.options.onEnter(node, isAppearing); // user option - } + }; const onEntering = (node, isAppearing) => { props.onEntering && props.onEntering(node, isAppearing); // component props.options && props.options.onEntering && props.options.onEntering(node, isAppearing); // user option - } + }; const onEntered = (node, isAppearing) => { props.onEntered && props.onEntered(node, isAppearing); // component props.options && props.options.onEntered && props.options.onEntered(node, isAppearing); // user option - } + }; const onExit = (node) => { props.onExit && props.onExit(node); // component props.options && props.options.onExit && props.options.onExit(node); // user option - } + }; const onExiting = (node) => { props.onExiting && props.onExiting(node); // component props.options && props.options.onExiting && props.options.onExiting(node); // user option - } + }; const onExited = (node) => { props.onExited && props.onExited(node); // component props.options && props.options.onExited && props.options.onExited(node); // user option - } + }; useUpdateEffect(() => { - if (disabled) { // no animation + if (disabled) { + // no animation const node = ObjectUtils.getRefElement(props.nodeRef); if (props.in) { onEnter(node, true); onEntering(node, true); onEntered(node, true); - } - else { + } else { onExit(node); onExiting(node); onExited(node); @@ -56,21 +56,16 @@ export const CSSTransition = React.forwardRef((props, ref) => { if (disabled) { return props.in ? props.children : null; - } - else { + } else { const immutableProps = { nodeRef: props.nodeRef, in: props.in, onEnter: onEnter, onEntering: onEntering, onEntered: onEntered, onExit: onExit, onExiting: onExiting, onExited: onExited }; const mutableProps = { classNames: props.classNames, timeout: props.timeout, unmountOnExit: props.unmountOnExit }; const mergedProps = { ...mutableProps, ...(props.options || {}), ...immutableProps }; - return ( - - {props.children} - - ) + return {props.children}; } }); CSSTransition.displayName = 'CSSTransition'; CSSTransition.defaultProps = { __TYPE: 'CSSTransition' -} +}; diff --git a/components/lib/csstransition/csstransition.d.ts b/components/lib/csstransition/csstransition.d.ts index fbeb684245..70833394e4 100644 --- a/components/lib/csstransition/csstransition.d.ts +++ b/components/lib/csstransition/csstransition.d.ts @@ -3,6 +3,6 @@ import { CSSTransitionProps as ReactCSSTransitionProps } from 'react-transition- export type CSSTransitionProps = ReactCSSTransitionProps & { disabled?: boolean; -} +}; -export declare class CSSTransition extends React.Component, any> { } +export declare class CSSTransition extends React.Component, any> {} diff --git a/components/lib/datascroller/DataScroller.js b/components/lib/datascroller/DataScroller.js index e5040793bb..66a0b620cd 100644 --- a/components/lib/datascroller/DataScroller.js +++ b/components/lib/datascroller/DataScroller.js @@ -3,213 +3,205 @@ import { localeOption } from '../api/Api'; import { useMountEffect, useUnmountEffect, useUpdateEffect } from '../hooks/Hooks'; import { classNames, ObjectUtils } from '../utils/Utils'; -export const DataScroller = React.memo(React.forwardRef((props, ref) => { - const [dataToRenderState, setDataToRenderState] = React.useState([]); - const elementRef = React.useRef(null); - const contentRef = React.useRef(null); - const value = React.useRef(props.value); - const dataToRender = React.useRef([]); - const first = React.useRef(0); - const scrollFunction = React.useRef(null); - - const handleDataChange = () => { - if (props.lazy) { - dataToRender.current = value.current; +export const DataScroller = React.memo( + React.forwardRef((props, ref) => { + const [dataToRenderState, setDataToRenderState] = React.useState([]); + const elementRef = React.useRef(null); + const contentRef = React.useRef(null); + const value = React.useRef(props.value); + const dataToRender = React.useRef([]); + const first = React.useRef(0); + const scrollFunction = React.useRef(null); + + const handleDataChange = () => { + if (props.lazy) { + dataToRender.current = value.current; + setDataToRenderState([...dataToRender.current]); + } else { + load(); + } + }; + + const load = () => { + if (props.lazy) { + if (props.onLazyLoad) { + props.onLazyLoad(createLazyLoadMetadata()); + } + + first.current += props.rows; + } else { + if (value.current) { + for (let i = first.current; i < first.current + props.rows; i++) { + if (i >= value.current.length) { + break; + } + + dataToRender.current.push(value.current[i]); + } + + if (value.current.length !== 0) { + first.current += props.rows; + } + + setDataToRenderState([...dataToRender.current]); + } + } + }; + + const reset = () => { + first.current = 0; + dataToRender.current = []; setDataToRenderState([...dataToRender.current]); - } - else { load(); - } - } + }; - const load = () => { - if (props.lazy) { - if (props.onLazyLoad) { - props.onLazyLoad(createLazyLoadMetadata()); - } + const isEmpty = () => { + return !dataToRender.current || dataToRender.current.length === 0; + }; + + const createLazyLoadMetadata = () => { + return { + first: first.current, + rows: props.rows + }; + }; + + const bindScrollListener = () => { + if (props.inline) { + scrollFunction.current = () => { + let scrollTop = contentRef.current.scrollTop, + scrollHeight = contentRef.current.scrollHeight, + viewportHeight = contentRef.current.clientHeight; - first.current += props.rows; - } - else { - if (value.current) { - for (let i = first.current; i < (first.current + props.rows); i++) { - if (i >= value.current.length) { - break; + if (scrollTop >= scrollHeight * props.buffer - viewportHeight) { + load(); + } + }; + + contentRef.current.addEventListener('scroll', scrollFunction.current); + } else { + scrollFunction.current = () => { + let docBody = document.body, + docElement = document.documentElement, + scrollTop = window.pageYOffset || document.documentElement.scrollTop, + winHeight = docElement.clientHeight, + docHeight = Math.max(docBody.scrollHeight, docBody.offsetHeight, winHeight, docElement.scrollHeight, docElement.offsetHeight); + + if (scrollTop >= docHeight * props.buffer - winHeight) { + load(); } + }; - dataToRender.current.push(value.current[i]); - } + window.addEventListener('scroll', scrollFunction.current); + } + }; - if (value.current.length !== 0) { - first.current += props.rows; + const unbindScrollListener = () => { + if (scrollFunction.current) { + if (props.inline && contentRef.current) { + contentRef.current.removeEventListener('scroll', scrollFunction.current); + } else if (!props.loader) { + window.removeEventListener('scroll', scrollFunction.current); } - - setDataToRenderState([...dataToRender.current]); } - } - } - - const reset = () => { - first.current = 0; - dataToRender.current = []; - setDataToRenderState([...dataToRender.current]); - load(); - } - - const isEmpty = () => { - return !dataToRender.current || (dataToRender.current.length === 0); - } - - const createLazyLoadMetadata = () => { - return { - first: first.current, - rows: props.rows + + scrollFunction.current = null; }; - } - const bindScrollListener = () => { - if (props.inline) { - scrollFunction.current = () => { - let scrollTop = contentRef.current.scrollTop, - scrollHeight = contentRef.current.scrollHeight, - viewportHeight = contentRef.current.clientHeight; + useMountEffect(() => { + load(); - if ((scrollTop >= ((scrollHeight * props.buffer) - (viewportHeight)))) { - load(); - } + if (!props.loader) { + bindScrollListener(); } + }); - contentRef.current.addEventListener('scroll', scrollFunction.current); - } - else { - scrollFunction.current = () => { - let docBody = document.body, - docElement = document.documentElement, - scrollTop = (window.pageYOffset || document.documentElement.scrollTop), - winHeight = docElement.clientHeight, - docHeight = Math.max(docBody.scrollHeight, docBody.offsetHeight, winHeight, docElement.scrollHeight, docElement.offsetHeight); - - if (scrollTop >= ((docHeight * props.buffer) - winHeight)) { - load(); - } + useUpdateEffect(() => { + if (props.value) { + value.current = props.value; + + first.current = 0; + dataToRender.current = []; + handleDataChange(); } + }, [props.value]); - window.addEventListener('scroll', scrollFunction.current); - } - } + useUpdateEffect(() => { + if (props.loader) { + unbindScrollListener(); + } + }, [props.loader]); - const unbindScrollListener = () => { - if (scrollFunction.current) { - if (props.inline && contentRef.current) { - contentRef.current.removeEventListener('scroll', scrollFunction.current); + useUnmountEffect(() => { + if (scrollFunction.current) { + unbindScrollListener(); + } + }); + + React.useImperativeHandle(ref, () => ({ + props, + load, + reset, + getElement: () => elementRef.current, + getContent: () => contentRef.current + })); + + const createHeader = () => { + if (props.header) { + return
    {props.header}
    ; } - else if (!props.loader) { - window.removeEventListener('scroll', scrollFunction.current); + + return null; + }; + + const createFooter = () => { + if (props.footer) { + return
    {props.footer}
    ; } - } - scrollFunction.current = null; - } + return null; + }; - useMountEffect(() => { - load(); + const createItem = (_value, index) => { + const content = props.itemTemplate ? props.itemTemplate(_value) : _value; - if (!props.loader) { - bindScrollListener(); - } - }); + return
  • {content}
  • ; + }; - useUpdateEffect(() => { - if (props.value) { - value.current = props.value; + const createEmptyMessage = () => { + const content = ObjectUtils.getJSXElement(props.emptyMessage, props) || localeOption('emptyMessage'); - first.current = 0; - dataToRender.current = []; - handleDataChange(); - } - }, [props.value]); - - useUpdateEffect(() => { - if (props.loader) { - unbindScrollListener(); - } - }, [props.loader]); - - useUnmountEffect(() => { - if (scrollFunction.current) { - unbindScrollListener(); - } - }); - - React.useImperativeHandle(ref, () => ({ - props, - load, - reset, - getElement: () => elementRef.current, - getContent: () => contentRef.current - })); - - const createHeader = () => { - if (props.header) { - return
    {props.header}
    - } - - return null; - } - - const createFooter = () => { - if (props.footer) { - return
    {props.footer}
    - } - - return null; - } - - const createItem = (_value, index) => { - const content = props.itemTemplate ? props.itemTemplate(_value) : _value; + return
  • {content}
  • ; + }; - return ( -
  • - {content} -
  • - ) - } + const createContent = () => { + const content = ObjectUtils.isNotEmpty(dataToRenderState) ? dataToRenderState.map(createItem) : createEmptyMessage(); - const createEmptyMessage = () => { - const content = ObjectUtils.getJSXElement(props.emptyMessage, props) || localeOption('emptyMessage'); + return ( +
    +
      {content}
    +
    + ); + }; - return
  • {content}
  • - } + const otherProps = ObjectUtils.findDiffKeys(props, DataScroller.defaultProps); + const className = classNames('p-datascroller p-component', props.className, { + 'p-datascroller-inline': props.inline + }); - const createContent = () => { - const content = ObjectUtils.isNotEmpty(dataToRenderState) ? dataToRenderState.map(createItem) : createEmptyMessage(); + const header = createHeader(); + const footer = createFooter(); + const content = createContent(); return ( -
    -
      - {content} -
    +
    + {header} + {content} + {footer}
    - ) - } - - const otherProps = ObjectUtils.findDiffKeys(props, DataScroller.defaultProps); - const className = classNames('p-datascroller p-component', props.className, { - 'p-datascroller-inline': props.inline - }); - - const header = createHeader(); - const footer = createFooter(); - const content = createContent(); - - return ( -
    - {header} - {content} - {footer} -
    - ) -})); + ); + }) +); DataScroller.displayName = 'DataScroller'; DataScroller.defaultProps = { @@ -229,4 +221,4 @@ DataScroller.defaultProps = { header: null, footer: null, lazy: false -} +}; diff --git a/components/lib/datatable/BodyCell.js b/components/lib/datatable/BodyCell.js index 8f8b9680c0..636f80e0de 100644 --- a/components/lib/datatable/BodyCell.js +++ b/components/lib/datatable/BodyCell.js @@ -19,16 +19,18 @@ export const BodyCell = React.memo((props) => { const getColumnProp = (prop) => (props.column ? props.column.props[prop] : null); const field = getColumnProp('field') || `field_${props.index}`; - const editingKey = props.dataKey ? (props.rowData[props.dataKey] || props.rowIndex) : props.rowIndex; + const editingKey = props.dataKey ? props.rowData[props.dataKey] || props.rowIndex : props.rowIndex; const [bindDocumentClickListener, unbindDocumentClickListener] = useEventListener({ - type: 'click', listener: (e) => { + type: 'click', + listener: (e) => { if (!selfClick.current && isOutsideClicked(e.target)) { switchCellToViewMode(e, true); } selfClick.current = false; - }, options: true + }, + options: true }); if (props.editMode === 'row' && props.editing !== editingState) { @@ -37,34 +39,34 @@ export const BodyCell = React.memo((props) => { const isEditable = () => { return getColumnProp('editor'); - } + }; const isSelected = () => { - return props.selection ? (props.selection instanceof Array ? findIndex(props.selection) > -1 : equals(props.selection)) : false - } + return props.selection ? (props.selection instanceof Array ? findIndex(props.selection) > -1 : equals(props.selection)) : false; + }; const equalsData = (data) => { - return props.compareSelectionBy === 'equals' ? (data === props.rowData) : ObjectUtils.equals(data, props.rowData, props.dataKey); - } + return props.compareSelectionBy === 'equals' ? data === props.rowData : ObjectUtils.equals(data, props.rowData, props.dataKey); + }; const equals = (selectedCell) => { return (selectedCell.rowIndex === props.rowIndex || equalsData(selectedCell.rowData)) && (selectedCell.field === field || selectedCell.cellIndex === props.index); - } + }; const isOutsideClicked = (target) => { return elementRef.current && !(elementRef.current.isSameNode(target) || elementRef.current.contains(target)); - } + }; const getVirtualScrollerOption = (option) => { return props.virtualScrollerOptions ? props.virtualScrollerOptions[option] : null; - } + }; const getStyle = () => { const bodyStyle = getColumnProp('bodyStyle'); const columnStyle = getColumnProp('style'); return getColumnProp('frozen') ? Object.assign({}, columnStyle, bodyStyle, styleObjectState) : Object.assign({}, columnStyle, bodyStyle); - } + }; const getCellParams = () => { return { @@ -76,32 +78,32 @@ export const BodyCell = React.memo((props) => { selected: isSelected(), column: props.column, props - } - } + }; + }; const getCellCallbackParams = (event) => { const params = getCellParams(); return { originalEvent: event, ...params - } - } + }; + }; const resolveFieldData = (data) => { return ObjectUtils.resolveFieldData(data || props.rowData, field); - } + }; const getEditingRowData = () => { return props.editingMeta && props.editingMeta[editingKey] ? props.editingMeta[editingKey].data : props.rowData; - } + }; const getTabIndex = (cellSelected) => { - return props.allowCellSelection ? (cellSelected ? 0 : (props.rowIndex === 0 && props.index === 0 ? props.tabIndex : -1)) : null; - } + return props.allowCellSelection ? (cellSelected ? 0 : props.rowIndex === 0 && props.index === 0 ? props.tabIndex : -1) : null; + }; const findIndex = (collection) => { - return (collection || []).findIndex(data => equals(data)); - } + return (collection || []).findIndex((data) => equals(data)); + }; const closeCell = (event) => { const params = getCellCallbackParams(event); @@ -119,7 +121,7 @@ export const BodyCell = React.memo((props) => { overlayEventListener.current = null; selfClick.current = false; }, 1); - } + }; const switchCellToViewMode = (event, submit) => { const callbackParams = getCellCallbackParams(event); @@ -146,44 +148,43 @@ export const BodyCell = React.memo((props) => { } closeCell(event); - } - else { + } else { event.preventDefault(); } - } + }; const findNextSelectableCell = (cell) => { const nextCell = cell.nextElementSibling; return nextCell ? (DomHandler.hasClass(nextCell, 'p-selectable-cell') ? nextCell : findNextSelectableCell(nextCell)) : null; - } + }; const findPrevSelectableCell = (cell) => { const prevCell = cell.previousElementSibling; return prevCell ? (DomHandler.hasClass(prevCell, 'p-selectable-cell') ? prevCell : findPrevSelectableCell(prevCell)) : null; - } + }; const findDownSelectableCell = (cell) => { const downRow = cell.parentElement.nextElementSibling; const downCell = downRow ? downRow.children[props.index] : null; return downRow && downCell ? (DomHandler.hasClass(downRow, 'p-selectable-row') && DomHandler.hasClass(downCell, 'p-selectable-cell') ? downCell : findDownSelectableCell(downCell)) : null; - } + }; const findUpSelectableCell = (cell) => { const upRow = cell.parentElement.previousElementSibling; const upCell = upRow ? upRow.children[props.index] : null; return upRow && upCell ? (DomHandler.hasClass(upRow, 'p-selectable-row') && DomHandler.hasClass(upCell, 'p-selectable-cell') ? upCell : findUpSelectableCell(upCell)) : null; - } + }; const changeTabIndex = (currentCell, nextCell) => { if (currentCell && nextCell) { currentCell.tabIndex = -1; nextCell.tabIndex = props.tabIndex; } - } + }; const focusOnElement = () => { clearTimeout(tabindexTimeout.current); @@ -195,7 +196,7 @@ export const BodyCell = React.memo((props) => { keyHelperRef.current && (keyHelperRef.current.tabIndex = editingState ? -1 : 0); }, 1); - } + }; const focusOnInit = () => { clearTimeout(initFocusTimeout.current); @@ -203,7 +204,7 @@ export const BodyCell = React.memo((props) => { const focusableEl = props.editMode === 'row' ? DomHandler.findSingle(elementRef.current, '.p-row-editor-init') : null; focusableEl && focusableEl.focus(); }, 1); - } + }; const updateStickyPosition = () => { if (getColumnProp('frozen')) { @@ -216,8 +217,7 @@ export const BodyCell = React.memo((props) => { right = DomHandler.getOuterWidth(next) + parseFloat(next.style.right || 0); } styleObject['right'] = right + 'px'; - } - else { + } else { let left = 0; let prev = elementRef.current.previousElementSibling; if (prev) { @@ -229,7 +229,7 @@ export const BodyCell = React.memo((props) => { const isSameStyle = styleObjectState['left'] === styleObject['left'] && styleObjectState['right'] === styleObject['right']; !isSameStyle && setStyleObjectState(styleObject); } - } + }; const editorCallback = (val) => { let editingRowData = { ...editingRowDataState }; @@ -239,7 +239,7 @@ export const BodyCell = React.memo((props) => { // update editing meta for complete methods on row mode props.editingMeta[editingKey].data[field] = val; - } + }; const onClick = (event) => { const params = getCellCallbackParams(event); @@ -280,25 +280,27 @@ export const BodyCell = React.memo((props) => { if (props.allowCellSelection && props.onClick) { props.onClick(params); } - } + }; const onMouseDown = (event) => { const params = getCellCallbackParams(event); props.onMouseDown && props.onMouseDown(params); - } + }; const onMouseUp = (event) => { const params = getCellCallbackParams(event); props.onMouseUp && props.onMouseUp(params); - } + }; const onKeyDown = (event) => { if (props.editMode !== 'row') { - if (event.which === 13 || event.which === 9) { // tab || enter + if (event.which === 13 || event.which === 9) { + // tab || enter switchCellToViewMode(event, true); } - if (event.which === 27) { // escape + if (event.which === 27) { + // escape switchCellToViewMode(event, false); } } @@ -372,7 +374,7 @@ export const BodyCell = React.memo((props) => { break; } } - } + }; const onBlur = (event) => { selfClick.current = false; @@ -380,11 +382,11 @@ export const BodyCell = React.memo((props) => { if (props.editMode !== 'row' && editingState && getColumnProp('cellEditValidatorEvent') === 'blur') { switchCellToViewMode(event, true); } - } + }; const onEditorFocus = (event) => { onClick(event); - } + }; const onRadioChange = (event) => { props.onRadioChange({ @@ -392,7 +394,7 @@ export const BodyCell = React.memo((props) => { data: props.rowData, index: props.rowIndex }); - } + }; const onCheckboxChange = (event) => { props.onCheckboxChange({ @@ -400,7 +402,7 @@ export const BodyCell = React.memo((props) => { data: props.rowData, index: props.rowIndex }); - } + }; const onRowToggle = (event) => { props.onRowToggle({ @@ -409,21 +411,21 @@ export const BodyCell = React.memo((props) => { }); event.preventDefault(); - } + }; const onRowEditInit = (event) => { props.onRowEditInit({ originalEvent: event, data: props.rowData, newData: getEditingRowData(), field: field, index: props.rowIndex }); - } + }; const onRowEditSave = (event) => { props.onRowEditSave({ originalEvent: event, data: props.rowData, newData: getEditingRowData(), field: field, index: props.rowIndex }); focusOnInit(); - } + }; const onRowEditCancel = (event) => { props.onRowEditCancel({ originalEvent: event, data: props.rowData, newData: getEditingRowData(), field: field, index: props.rowIndex }); focusOnInit(); - } + }; React.useEffect(() => { if (getColumnProp('frozen')) { @@ -461,7 +463,7 @@ export const BodyCell = React.memo((props) => { const options = getVirtualScrollerOption('getLoaderOptions')(props.rowIndex, { cellIndex: props.index, cellFirst: props.index === 0, - cellLast: props.index === (getVirtualScrollerOption('columns').length - 1), + cellLast: props.index === getVirtualScrollerOption('columns').length - 1, cellEven: props.index % 2 === 0, cellOdd: props.index % 2 !== 0, column: props.column, @@ -469,12 +471,8 @@ export const BodyCell = React.memo((props) => { }); const content = ObjectUtils.getJSXElement(getVirtualScrollerOption('loadingTemplate'), options); - return ( - - {content} - - ) - } + return {content}; + }; const createElement = () => { let content, editorKeyHelper; @@ -502,7 +500,7 @@ export const BodyCell = React.memo((props) => { [`p-align-${align}`]: !!align }); const style = getStyle(); - const title = props.responsiveLayout === 'stack' && {ObjectUtils.getJSXElement(header, { props: props.tableProps })}; + const title = props.responsiveLayout === 'stack' && {ObjectUtils.getJSXElement(header, { props: props.tableProps })}; if (selectionMode) { const showSelection = props.showSelectionElement ? props.showSelectionElement(props.rowData, { rowIndex: props.rowIndex, props: props.tableProps }) : true; @@ -512,13 +510,11 @@ export const BodyCell = React.memo((props) => { {selectionMode === 'single' && } {selectionMode === 'multiple' && } - ) - } - else if (rowReorder) { + ); + } else if (rowReorder) { const showReorder = props.showRowReorderElement ? props.showRowReorderElement(props.rowData, { rowIndex: props.rowIndex, props: props.tableProps }) : true; content = showReorder && ; - } - else if (expander) { + } else if (expander) { const iconClassName = classNames('p-row-toggler-icon', props.expanded ? props.expandedRowIcon : props.collapsedRowIcon); const ariaControls = `${props.tableSelector}_content_${props.rowIndex}_expanded`; const expanderProps = { @@ -528,7 +524,7 @@ export const BodyCell = React.memo((props) => { }; content = ( - @@ -538,8 +534,7 @@ export const BodyCell = React.memo((props) => { expanderProps['element'] = content; content = ObjectUtils.getJSXElement(body, props.rowData, { column: props.column, field: field, rowIndex: props.rowIndex, frozenRow: props.frozenRow, props: props.tableProps, expander: expanderProps }); } - } - else if (isRowEditor && rowEditor) { + } else if (isRowEditor && rowEditor) { let rowEditorProps = {}; if (editingState) { @@ -555,18 +550,17 @@ export const BodyCell = React.memo((props) => { content = ( <> - - ); - } - else { + } else { rowEditorProps = { editing: false, onInitClick: onRowEditInit, @@ -575,7 +569,7 @@ export const BodyCell = React.memo((props) => { }; content = ( - @@ -586,32 +580,41 @@ export const BodyCell = React.memo((props) => { rowEditorProps['element'] = content; content = ObjectUtils.getJSXElement(body, props.rowData, { column: props.column, field: field, rowIndex: props.rowIndex, frozenRow: props.frozenRow, props: props.tableProps, rowEditor: rowEditorProps }); } - } - else if (body && !editingState) { + } else if (body && !editingState) { content = body ? ObjectUtils.getJSXElement(body, props.rowData, { column: props.column, field: field, rowIndex: props.rowIndex, frozenRow: props.frozenRow, props: props.tableProps }) : value; - } - else if (editor && editingState) { - content = ObjectUtils.getJSXElement(editor, { rowData: editingRowDataState, value: resolveFieldData(editingRowDataState), column: props.column, field: field, rowIndex: props.rowIndex, frozenRow: props.frozenRow, props: props.tableProps, editorCallback }); - } - else { + } else if (editor && editingState) { + content = ObjectUtils.getJSXElement(editor, { + rowData: editingRowDataState, + value: resolveFieldData(editingRowDataState), + column: props.column, + field: field, + rowIndex: props.rowIndex, + frozenRow: props.frozenRow, + props: props.tableProps, + editorCallback + }); + } else { content = value; } if (!isRowEditor && editor) { /* eslint-disable */ - editorKeyHelper =
    ; + editorKeyHelper = ( + + + + ); /* eslint-enable */ } return ( - + {editorKeyHelper} {title} {content} - ) - } + ); + }; return getVirtualScrollerOption('loading') ? createLoading() : createElement(); }); diff --git a/components/lib/datatable/BodyRow.js b/components/lib/datatable/BodyRow.js index 5b199800aa..508c239eff 100644 --- a/components/lib/datatable/BodyRow.js +++ b/components/lib/datatable/BodyRow.js @@ -8,58 +8,55 @@ export const BodyRow = React.memo((props) => { const isFocusable = () => { return props.selectionMode && props.selectionModeInColumn !== 'single' && props.selectionModeInColumn !== 'multiple'; - } + }; const isGrouped = (column) => { if (props.groupRowsBy && getColumnProp(column, 'field')) { - return Array.isArray(props.groupRowsBy) ? - props.groupRowsBy.indexOf(column.props.field) > -1 : - props.groupRowsBy === column.props.field; + return Array.isArray(props.groupRowsBy) ? props.groupRowsBy.indexOf(column.props.field) > -1 : props.groupRowsBy === column.props.field; } return false; - } + }; const equals = (data1, data2) => { - return props.compareSelectionBy === 'equals' ? (data1 === data2) : ObjectUtils.equals(data1, data2, props.dataKey); - } + return props.compareSelectionBy === 'equals' ? data1 === data2 : ObjectUtils.equals(data1, data2, props.dataKey); + }; const getColumnProp = (col, prop) => { return col ? col.props[prop] : null; - } + }; const getTabIndex = () => { return isFocusable() && !props.allowCellSelection ? (props.index === 0 ? props.tabIndex : -1) : null; - } + }; const findIndex = (collection, rowData) => { - return (collection || []).findIndex(data => equals(rowData, data)); - } + return (collection || []).findIndex((data) => equals(rowData, data)); + }; const changeTabIndex = (currentRow, nextRow) => { if (currentRow && nextRow) { currentRow.tabIndex = -1; nextRow.tabIndex = props.tabIndex; } - } + }; const findNextSelectableRow = (row) => { const nextRow = row.nextElementSibling; return nextRow ? (DomHandler.hasClass(nextRow, 'p-selectable-row') ? nextRow : findNextSelectableRow(nextRow)) : null; - } + }; const findPrevSelectableRow = (row) => { const prevRow = row.previousElementSibling; return prevRow ? (DomHandler.hasClass(prevRow, 'p-selectable-row') ? prevRow : findPrevSelectableRow(prevRow)) : null; - } + }; const shouldRenderBodyCell = (value, column, i) => { if (getColumnProp(column, 'hidden')) { return false; - } - else if (props.rowGroupMode && props.rowGroupMode === 'rowspan' && isGrouped(column)) { + } else if (props.rowGroupMode && props.rowGroupMode === 'rowspan' && isGrouped(column)) { let prevRowData = value[i - 1]; if (prevRowData) { const currentRowFieldData = ObjectUtils.resolveFieldData(value[i], getColumnProp(column, 'field')); @@ -70,7 +67,7 @@ export const BodyRow = React.memo((props) => { } return true; - } + }; const calculateRowGroupSize = (value, column, index) => { if (isGrouped(column)) { @@ -83,34 +80,32 @@ export const BodyRow = React.memo((props) => { let nextRowData = value[++index]; if (nextRowData) { nextRowFieldData = ObjectUtils.resolveFieldData(nextRowData, getColumnProp(column, 'field')); - } - else { + } else { break; } } return groupRowSpan === 1 ? null : groupRowSpan; - } - else { + } else { return null; } - } + }; const onClick = (event) => { props.onRowClick({ originalEvent: event, data: props.rowData, index: props.index }); - } + }; const onDoubleClick = (event) => { props.onRowDoubleClick({ originalEvent: event, data: props.rowData, index: props.index }); - } + }; const onRightClick = (event) => { props.onRowRightClick({ originalEvent: event, data: props.rowData, index: props.index }); - } + }; const onTouchEnd = (event) => { props.onRowTouchEnd(event); - } + }; const onKeyDown = (event) => { if (isFocusable() && !props.allowCellSelection) { @@ -160,35 +155,35 @@ export const BodyRow = React.memo((props) => { break; } } - } + }; const onMouseDown = (event) => { props.onRowMouseDown({ originalEvent: event, data: props.rowData, index: props.index }); - } + }; const onMouseUp = (event) => { props.onRowMouseUp({ originalEvent: event, data: props.rowData, index: props.index }); - } + }; const onDragStart = (event) => { props.onRowDragStart({ originalEvent: event, data: props.rowData, index: props.index }); - } + }; const onDragOver = (event) => { props.onRowDragOver({ originalEvent: event, data: props.rowData, index: props.index }); - } + }; const onDragLeave = (event) => { props.onRowDragLeave({ originalEvent: event, data: props.rowData, index: props.index }); - } + }; const onDragEnd = (event) => { props.onRowDragEnd({ originalEvent: event, data: props.rowData, index: props.index }); - } + }; const onDrop = (event) => { props.onRowDrop({ originalEvent: event, data: props.rowData, index: props.index }); - } + }; const onEditChange = (e, isEditing) => { if (props.onRowEditChange) { @@ -205,19 +200,15 @@ export const BodyRow = React.memo((props) => { // if the key value was changed, stop editing for the new key value too let newDataKeyValue = String(ObjectUtils.resolveFieldData(newData, dataKey)); delete editingRows[newDataKeyValue]; - } - else { + } else { editingRows[dataKeyValue] = true; } - } - else { + } else { let editingRowIndex = findIndex(props.editingRows, data); editingRows = props.editingRows ? [...props.editingRows] : []; - if (editingRowIndex !== -1) - editingRows = editingRows.filter((val, i) => i !== editingRowIndex); - else - editingRows.push(data); + if (editingRowIndex !== -1) editingRows = editingRows.filter((val, i) => i !== editingRowIndex); + else editingRows.push(data); } props.onRowEditChange({ @@ -225,11 +216,10 @@ export const BodyRow = React.memo((props) => { data: editingRows, index }); - } - else { + } else { setEditingState(isEditing); } - } + }; const onEditInit = (e) => { const { originalEvent: event } = e; @@ -245,7 +235,7 @@ export const BodyRow = React.memo((props) => { onEditChange(e, true); event.preventDefault(); - } + }; const onEditSave = (e) => { const { originalEvent: event, newData } = e; @@ -269,7 +259,7 @@ export const BodyRow = React.memo((props) => { } event.preventDefault(); - } + }; const onEditCancel = (e) => { const { originalEvent: event } = e; @@ -285,7 +275,7 @@ export const BodyRow = React.memo((props) => { onEditChange(e, false); event.preventDefault(); - } + }; const createContent = () => { return props.columns.map((col, i) => { @@ -294,20 +284,53 @@ export const BodyRow = React.memo((props) => { const rowSpan = props.rowGroupMode === 'rowspan' ? calculateRowGroupSize(props.value, col, props.index) : null; return ( - - ) + + ); } return null; - }) - } + }); + }; const rowClassName = ObjectUtils.getPropValue(props.rowClassName, props.rowData, { props: props.tableProps }); const className = classNames(rowClassName, { @@ -321,12 +344,27 @@ export const BodyRow = React.memo((props) => { const tabIndex = getTabIndex(); return ( - + {content} - ) + ); }); BodyRow.displayName = 'BodyRow'; diff --git a/components/lib/datatable/ColumnFilter.js b/components/lib/datatable/ColumnFilter.js index 07e1c96fbd..5504dd30ca 100644 --- a/components/lib/datatable/ColumnFilter.js +++ b/components/lib/datatable/ColumnFilter.js @@ -22,67 +22,68 @@ export const ColumnFilter = React.memo((props) => { const filterStoreModel = props.filtersStore && props.filtersStore[field]; const [bindOverlayListener, unbindOverlayListener] = useOverlayListener({ - target: iconRef, overlay: overlayRef, listener: (event, { type, valid }) => { + target: iconRef, + overlay: overlayRef, + listener: (event, { type, valid }) => { if (valid) { - (type === 'outside') ? - (!selfClick.current && !isTargetClicked(event.target)) && hide() : hide(); + type === 'outside' ? !selfClick.current && !isTargetClicked(event.target) && hide() : hide(); } selfClick.current = false; - }, when: overlayVisibleState + }, + when: overlayVisibleState }); const hasFilter = () => { - if (!filterStoreModel || !filterModel) - return false; - return filterStoreModel.operator ? - !isFilterBlank(filterModel.constraints[0].value) && filterStoreModel.constraints[0].value !== filterModel.constraints[0].value : - !isFilterBlank(filterModel.value) && filterStoreModel.value !== filterModel.value; - } + if (!filterStoreModel || !filterModel) return false; + return filterStoreModel.operator + ? !isFilterBlank(filterModel.constraints[0].value) && filterStoreModel.constraints[0].value !== filterModel.constraints[0].value + : !isFilterBlank(filterModel.value) && filterStoreModel.value !== filterModel.value; + }; const hasRowFilter = () => { return filterModel && !isFilterBlank(filterModel.value); - } + }; const isFilterBlank = (filter) => { return ObjectUtils.isEmpty(filter); - } + }; const isRowMatchModeSelected = (matchMode) => { return filterModel && filterModel.matchMode === matchMode; - } + }; const showMenuButton = () => { return getColumnProp('showFilterMenu') && (props.display === 'row' ? getColumnProp('dataType') !== 'boolean' : true); - } + }; const matchModes = () => { - return getColumnProp('filterMatchModeOptions') || PrimeReact.filterMatchModeOptions[findDataType()].map(key => ({ label: localeOption(key), value: key })); - } + return getColumnProp('filterMatchModeOptions') || PrimeReact.filterMatchModeOptions[findDataType()].map((key) => ({ label: localeOption(key), value: key })); + }; const isShowMatchModes = () => { return getColumnProp('dataType') !== 'boolean' && getColumnProp('showFilterMatchModes') && matchModes() && getColumnProp('showFilterMenuOptions'); - } + }; const isShowOperator = () => { return getColumnProp('showFilterOperator') && filterModel && filterModel.operator && getColumnProp('showFilterMenuOptions'); - } + }; const showRemoveIcon = () => { return fieldConstraints().length > 1; - } + }; const isShowAddConstraint = () => { - return getColumnProp('showAddButton') && filterModel && filterModel.operator && (fieldConstraints() && fieldConstraints().length < getColumnProp('maxConstraints')) && getColumnProp('showFilterMenuOptions'); - } + return getColumnProp('showAddButton') && filterModel && filterModel.operator && fieldConstraints() && fieldConstraints().length < getColumnProp('maxConstraints') && getColumnProp('showFilterMenuOptions'); + }; const isOutsideClicked = (target) => { return !isTargetClicked(target) && overlayRef.current && !(overlayRef.current.isSameNode(target) || overlayRef.current.contains(target)); - } + }; const isTargetClicked = (target) => { return iconRef.current && (iconRef.current.isSameNode(target) || iconRef.current.contains(target)); - } + }; const getDefaultConstraint = () => { if (filterStoreModel) { @@ -91,31 +92,29 @@ export const ColumnFilter = React.memo((props) => { matchMode: filterStoreModel.constraints[0].matchMode, operator: filterStoreModel.operator }; - } - else { + } else { return { matchMode: filterStoreModel.matchMode }; } } - } + }; const findDataType = () => { const dataType = getColumnProp('dataType'); const matchMode = getColumnProp('filterMatchMode'); - const hasMatchMode = (key) => PrimeReact.filterMatchModeOptions[key].some(mode => mode === matchMode); + const hasMatchMode = (key) => PrimeReact.filterMatchModeOptions[key].some((mode) => mode === matchMode); if (matchMode === 'custom' && !hasMatchMode(dataType)) { PrimeReact.filterMatchModeOptions[dataType].push(FilterMatchMode.CUSTOM); return dataType; - } - else if (matchMode) { - return Object.keys(PrimeReact.filterMatchModeOptions).find(key => hasMatchMode(key)) || dataType; + } else if (matchMode) { + return Object.keys(PrimeReact.filterMatchModeOptions).find((key) => hasMatchMode(key)) || dataType; } return dataType; - } + }; const clearFilter = () => { const filterClearCallback = getColumnProp('onFilterClear'); @@ -125,8 +124,7 @@ export const ColumnFilter = React.memo((props) => { filters[field].constraints.splice(1); filters[field].operator = defaultConstraint.operator; filters[field].constraints[0] = { value: null, matchMode: defaultConstraint.matchMode }; - } - else { + } else { filters[field].value = null; filters[field].matchMode = defaultConstraint.matchMode; } @@ -135,7 +133,7 @@ export const ColumnFilter = React.memo((props) => { props.onFilterChange(filters); props.onFilterApply(); hide(); - } + }; const applyFilter = () => { const filterApplyClickCallback = getColumnProp('onFilterApplyClick'); @@ -143,11 +141,11 @@ export const ColumnFilter = React.memo((props) => { filterApplyClickCallback && filterApplyClickCallback({ field, constraints: filterModel }); props.onFilterApply(); hide(); - } + }; const toggleMenu = () => { setOverlayVisibleState((prevVisible) => !prevVisible); - } + }; const onToggleButtonKeyDown = (event) => { switch (event.key) { @@ -161,8 +159,7 @@ export const ColumnFilter = React.memo((props) => { const focusable = DomHandler.getFirstFocusableElement(overlayRef.current); focusable && focusable.focus(); event.preventDefault(); - } - else if (event.altKey) { + } else if (event.altKey) { setOverlayVisibleState(true); event.preventDefault(); } @@ -171,14 +168,14 @@ export const ColumnFilter = React.memo((props) => { default: break; } - } + }; const onContentKeyDown = (event) => { if (event.key === 'Escape') { hide(); iconRef.current && iconRef.current.focus(); } - } + }; const onInputChange = (event, index) => { let filters = { ...props.filters }; @@ -186,8 +183,7 @@ export const ColumnFilter = React.memo((props) => { if (props.display === 'menu') { filters[field].constraints[index].value = value; - } - else { + } else { filters[field].value = value; } @@ -196,7 +192,7 @@ export const ColumnFilter = React.memo((props) => { if (!getColumnProp('showApplyButton') || props.display === 'row') { props.onFilterApply(); } - } + }; const onRowMatchModeChange = (matchMode) => { const filterMatchModeChangeCallback = getColumnProp('onFilterMatchModeChange'); @@ -207,7 +203,7 @@ export const ColumnFilter = React.memo((props) => { props.onFilterChange(filters); props.onFilterApply(); hide(); - } + }; const onRowMatchModeKeyDown = (event, matchMode, clear) => { let item = event.target; @@ -244,7 +240,7 @@ export const ColumnFilter = React.memo((props) => { default: break; } - } + }; const onOperatorChange = (e) => { const filterOperationChangeCallback = getColumnProp('onFilterOperatorChange'); @@ -257,7 +253,7 @@ export const ColumnFilter = React.memo((props) => { if (!getColumnProp('showApplyButton')) { props.onFilterApply(); } - } + }; const onMenuMatchModeChange = (value, index) => { const filterMatchModeChangeCallback = getColumnProp('onFilterMatchModeChange'); @@ -269,7 +265,7 @@ export const ColumnFilter = React.memo((props) => { if (!getColumnProp('showApplyButton')) { props.onFilterApply(); } - } + }; const addConstraint = () => { const filterConstraintAddCallback = getColumnProp('onFilterConstraintAdd'); @@ -283,7 +279,7 @@ export const ColumnFilter = React.memo((props) => { if (!getColumnProp('showApplyButton')) { props.onFilterApply(); } - } + }; const removeConstraint = (index) => { const filterConstraintRemoveCallback = getColumnProp('onFilterConstraintRemove'); @@ -295,23 +291,23 @@ export const ColumnFilter = React.memo((props) => { if (!getColumnProp('showApplyButton')) { props.onFilterApply(); } - } + }; const findNextItem = (item) => { const nextItem = item.nextElementSibling; return nextItem ? (DomHandler.hasClass(nextItem, 'p-column-filter-separator') ? findNextItem(nextItem) : nextItem) : item.parentElement.firstElementChild; - } + }; const findPrevItem = (item) => { const prevItem = item.previousElementSibling; return prevItem ? (DomHandler.hasClass(prevItem, 'p-column-filter-separator') ? findPrevItem(prevItem) : prevItem) : item.parentElement.lastElementChild; - } + }; const hide = () => { setOverlayVisibleState(false); - } + }; const onContentClick = (event) => { selfClick.current = true; @@ -320,11 +316,11 @@ export const ColumnFilter = React.memo((props) => { originalEvent: event, target: overlayRef.current }); - } + }; const onContentMouseDown = () => { selfClick.current = true; - } + }; const onOverlayEnter = () => { ZIndexUtils.set('overlay', overlayRef.current, PrimeReact.autoZIndex, PrimeReact.zIndex['overlay']); @@ -334,63 +330,63 @@ export const ColumnFilter = React.memo((props) => { if (!isOutsideClicked(e.target)) { selfClick.current = true; } - } + }; OverlayService.on('overlay-click', overlayEventListener.current); - } + }; const onOverlayEntered = () => { bindOverlayListener(); - } + }; const onOverlayExit = () => { onOverlayHide(); - } + }; const onOverlayExited = () => { ZIndexUtils.clear(overlayRef.current); - } + }; const onOverlayHide = () => { unbindOverlayListener(); OverlayService.off('overlay-click', overlayEventListener.current); overlayEventListener.current = null; selfClick.current = false; - } + }; const fieldConstraints = () => { return filterModel ? filterModel.constraints || [filterModel] : []; - } + }; const operator = () => { return filterModel.operator; - } + }; const operatorOptions = () => { return [ { label: localeOption('matchAll'), value: FilterOperator.AND }, { label: localeOption('matchAny'), value: FilterOperator.OR } ]; - } + }; const noFilterLabel = () => { return localeOption('noFilter'); - } + }; const removeRuleButtonLabel = () => { return localeOption('removeRule'); - } + }; const addRuleButtonLabel = () => { return localeOption('addRule'); - } + }; const clearButtonLabel = () => { return localeOption('clear'); - } + }; const applyButtonLabel = () => { return localeOption('apply'); - } + }; const filterCallback = (value, index = 0) => { let filters = { ...props.filters }; @@ -398,13 +394,13 @@ export const ColumnFilter = React.memo((props) => { props.display === 'menu' && meta && meta.operator ? (filters[field].constraints[index].value = value) : (filters[field].value = value); props.onFilterChange(filters); - } + }; const filterApplyCallback = (...args) => { args && filterCallback(args[0], args[1]); props.onFilterApply(); - } + }; useUpdateEffect(() => { if (props.display === 'menu' && overlayVisibleState) { @@ -427,29 +423,26 @@ export const ColumnFilter = React.memo((props) => { const createFilterElement = (model, index) => { const value = model ? model.value : null; - return getColumnProp('filterElement') ? + return getColumnProp('filterElement') ? ( ObjectUtils.getJSXElement(getColumnProp('filterElement'), { field, index, filterModel: model, value, filterApplyCallback, filterCallback }) - : onInputChange(e, index)} className="p-column-filter" placeholder={getColumnProp('filterPlaceholder')} maxLength={getColumnProp('filterMaxLength')} />; - } + ) : ( + onInputChange(e, index)} className='p-column-filter' placeholder={getColumnProp('filterPlaceholder')} maxLength={getColumnProp('filterMaxLength')} /> + ); + }; const createRowFilterElement = () => { if (props.display === 'row') { const content = createFilterElement(filterModel, 0); - return ( -
    - {content} -
    - ) - + return
    {content}
    ; } return null; - } + }; const createMenuFilterElement = (fieldConstraint, index) => { return props.display === 'menu' ? createFilterElement(fieldConstraint, index) : null; - } + }; const createMenuButton = () => { if (showMenuButton()) { @@ -459,14 +452,14 @@ export const ColumnFilter = React.memo((props) => { }); return ( - - ) + ); } return null; - } + }; const createClearButton = () => { if (getColumnProp('showClearButton') && props.display === 'row') { @@ -475,14 +468,14 @@ export const ColumnFilter = React.memo((props) => { }); return ( - - ) + ); } return null; - } + }; const createRowItems = () => { if (isShowMatchModes()) { @@ -490,28 +483,28 @@ export const ColumnFilter = React.memo((props) => { const _noFilterLabel = noFilterLabel(); return ( -
      - { - _matchModes.map((matchMode, i) => { - const { value, label } = matchMode; - const className = classNames('p-column-filter-row-item', { 'p-highlight': isRowMatchModeSelected(value) }); - const tabIndex = i === 0 ? 0 : null; - - return ( -
    • onRowMatchModeChange(value)} onKeyDown={(e) => onRowMatchModeKeyDown(e, matchMode)} tabIndex={tabIndex}> - {label} -
    • - ) - }) - } -
    • -
    • onRowMatchModeKeyDown(e, null, true)}>{_noFilterLabel}
    • +
        + {_matchModes.map((matchMode, i) => { + const { value, label } = matchMode; + const className = classNames('p-column-filter-row-item', { 'p-highlight': isRowMatchModeSelected(value) }); + const tabIndex = i === 0 ? 0 : null; + + return ( +
      • onRowMatchModeChange(value)} onKeyDown={(e) => onRowMatchModeKeyDown(e, matchMode)} tabIndex={tabIndex}> + {label} +
      • + ); + })} +
      • +
      • onRowMatchModeKeyDown(e, null, true)}> + {_noFilterLabel} +
      - ) + ); } return null; - } + }; const createOperator = () => { if (isShowOperator()) { @@ -519,118 +512,110 @@ export const ColumnFilter = React.memo((props) => { const value = operator(); return ( -
      - +
      +
      - ) + ); } return null; - } + }; const createMatchModeDropdown = (constraint, index) => { if (isShowMatchModes()) { const options = matchModes(); - return ( - onMenuMatchModeChange(e.value, index)} className="p-column-filter-matchmode-dropdown" /> - ) + return onMenuMatchModeChange(e.value, index)} className='p-column-filter-matchmode-dropdown' />; } return null; - } + }; const createRemoveButton = (index) => { if (showRemoveIcon()) { const removeRuleLabel = removeRuleButtonLabel(); - return ( -
      - ) + ); } return null; - } + }; const createFilterClearButton = () => { if (getColumnProp('showClearButton')) { if (!getColumnProp('filterClear')) { const clearLabel = clearButtonLabel(); - return - ) + ); }); RowTogglerButton.displayName = 'RowTogglerButton'; diff --git a/components/lib/datatable/TableBody.js b/components/lib/datatable/TableBody.js index f7319c6317..998d02ab26 100644 --- a/components/lib/datatable/TableBody.js +++ b/components/lib/datatable/TableBody.js @@ -5,904 +5,910 @@ import { classNames, DomHandler, ObjectUtils } from '../utils/Utils'; import { BodyRow } from './BodyRow'; import { RowTogglerButton } from './RowTogglerButton'; -export const TableBody = React.memo(React.forwardRef((props, ref) => { - const [rowGroupHeaderStyleObjectState, setRowGroupHeaderStyleObjectState] = React.useState({}); - const elementRef = React.useRef(null); - const refCallback = React.useCallback((el) => { - elementRef.current = el; - props.virtualScrollerContentRef && props.virtualScrollerContentRef(el); - }, [props]); - const dragSelectionHelper = React.useRef(null); - const initialDragPosition = React.useRef(null); - const anchorRowIndex = React.useRef(null); - const anchorCellIndex = React.useRef(null); - const rangeRowIndex = React.useRef(null); - const anchorRowFirst = React.useRef(null); - const rowTouched = React.useRef(false); - const rowDragging = React.useRef(false); - const draggedRowIndex = React.useRef(null); - const droppedRowIndex = React.useRef(null); - const prevVirtualScrollerOptions = usePrevious(props.virtualScrollerOptions); - const isSubheaderGrouping = props.rowGroupMode && props.rowGroupMode === 'subheader'; - const isRadioSelectionMode = props.selectionMode === 'radiobutton'; - const isCheckboxSelectionMode = props.selectionMode === 'checkbox'; - const isRadioSelectionModeInColumn = props.selectionModeInColumn === 'single'; - const isCheckboxSelectionModeInColumn = props.selectionModeInColumn === 'multiple'; - - const equals = (data1, data2) => { - if (allowCellSelection()) - return (data1.rowIndex === data2.rowIndex || data1.rowData === data2.rowData) && (data1.field === data2.field || data1.cellIndex === data2.cellIndex) - else - return props.compareSelectionBy === 'equals' ? (data1 === data2) : ObjectUtils.equals(data1, data2, props.dataKey); - } - - const isSelectionEnabled = () => { - return (props.selectionMode || props.selectionModeInColumn !== null) || (props.columns && props.columns.some(col => col && !!col.props.selectionMode)); - } - - const isSingleSelection = () => { - return (props.selectionMode === 'single' && !isCheckboxSelectionModeInColumn) || - (!isRadioSelectionMode && isRadioSelectionModeInColumn); - } - - const isMultipleSelection = () => { - return (props.selectionMode === 'multiple' && !isRadioSelectionModeInColumn) || isCheckboxSelectionModeInColumn; - } - - const isRadioOnlySelection = () => { - return isRadioSelectionMode && isRadioSelectionModeInColumn; - } - - const isCheckboxOnlySelection = () => { - return isCheckboxSelectionMode && isCheckboxSelectionModeInColumn; - } - - const isSelected = (rowData) => { - if (rowData && props.selection) { - return (props.selection instanceof Array) ? findIndex(props.selection, rowData) > -1 : equals(rowData, props.selection); - } - - return false; - } - - const isContextMenuSelected = (rowData) => { - if (rowData && props.contextMenuSelection) { - return equals(rowData, props.contextMenuSelection); - } - - return false; - } - - const isSelectable = (options) => { - return props.isDataSelectable ? props.isDataSelectable(options) : true; - } - - const isRowExpanded = (rowData) => { - if (rowData && props.expandedRows) { - if (isSubheaderGrouping && props.expandableRowGroups) { - return isRowGroupExpanded(rowData); - } - else { - if (props.dataKey) - return props.expandedRows ? props.expandedRows[ObjectUtils.resolveFieldData(rowData, props.dataKey)] !== undefined : false; - else - return findIndex(props.expandedRows, rowData) !== -1; - } - } - - return false; - } - - const isRowGroupExpanded = (rowData) => { - if (props.dataKey === props.groupRowsBy) - return Object.keys(props.expandedRows).some(data => ObjectUtils.equals(data, ObjectUtils.resolveFieldData(rowData, props.dataKey))); - else - return props.expandedRows.some(data => ObjectUtils.equals(data, rowData, props.groupRowsBy)); - } - - const isRowEditing = (rowData) => { - if (props.editMode === 'row' && rowData && props.editingRows) { - if (props.dataKey) - return props.editingRows ? props.editingRows[ObjectUtils.resolveFieldData(rowData, props.dataKey)] !== undefined : false; - else - return findIndex(props.editingRows, rowData) !== -1; - } - - return false; - } - - const allowDrag = (event) => { - return props.dragSelection && isMultipleSelection() && !event.originalEvent.shiftKey; - } - - const allowRowDrag = (event) => { - return !allowCellSelection() && allowDrag(event) || props.reorderableRows; - } - - const allowCellDrag = (event) => { - return allowCellSelection() && allowDrag(event); - } - - const allowSelection = (event) => { - return !DomHandler.isClickable(event.originalEvent.target); - } - - const allowMetaKeySelection = (event) => { - return !rowTouched.current && (!props.metaKeySelection || (props.metaKeySelection && (event.originalEvent.metaKey || event.originalEvent.ctrlKey))) - } - - const allowRangeSelection = (event) => { - return isMultipleSelection() && event.originalEvent.shiftKey && anchorRowIndex.current !== null; - } - - const allowRowSelection = () => { - return (props.selectionMode || props.selectionModeInColumn) && !isRadioOnlySelection() && !isCheckboxOnlySelection(); - } - - const allowCellSelection = () => { - return props.cellSelection && !isRadioSelectionModeInColumn && !isCheckboxSelectionModeInColumn; - } - - const getColumnsLength = () => { - return props.columns ? props.columns.length : 0; - } - - const getVirtualScrollerOption = (option, options) => { - options = options || props.virtualScrollerOptions; - return options ? options[option] : null; - } - - const findIndex = (collection, rowData) => { - return (collection || []).findIndex(data => equals(rowData, data)); - } - - const rowGroupHeaderStyle = () => { - if (props.scrollable) { - return { top: rowGroupHeaderStyleObjectState['top'] }; - } - - return null; - } - - const getRowKey = (rowData, index) => { - return props.dataKey ? ObjectUtils.resolveFieldData(rowData, props.dataKey) + '_' + index : index; - } - - const shouldRenderRowGroupHeader = (value, rowData, i) => { - const currentRowFieldData = ObjectUtils.resolveFieldData(rowData, props.groupRowsBy); - const prevRowData = value[i - 1]; - if (prevRowData) { - const previousRowFieldData = ObjectUtils.resolveFieldData(prevRowData, props.groupRowsBy); - return currentRowFieldData !== previousRowFieldData; - } - else { - return true; - } - } - - const shouldRenderRowGroupFooter = (value, rowData, i, expanded) => { - if (props.expandableRowGroups && !expanded) { +export const TableBody = React.memo( + React.forwardRef((props, ref) => { + const [rowGroupHeaderStyleObjectState, setRowGroupHeaderStyleObjectState] = React.useState({}); + const elementRef = React.useRef(null); + const refCallback = React.useCallback( + (el) => { + elementRef.current = el; + props.virtualScrollerContentRef && props.virtualScrollerContentRef(el); + }, + [props] + ); + const dragSelectionHelper = React.useRef(null); + const initialDragPosition = React.useRef(null); + const anchorRowIndex = React.useRef(null); + const anchorCellIndex = React.useRef(null); + const rangeRowIndex = React.useRef(null); + const anchorRowFirst = React.useRef(null); + const rowTouched = React.useRef(false); + const rowDragging = React.useRef(false); + const draggedRowIndex = React.useRef(null); + const droppedRowIndex = React.useRef(null); + const prevVirtualScrollerOptions = usePrevious(props.virtualScrollerOptions); + const isSubheaderGrouping = props.rowGroupMode && props.rowGroupMode === 'subheader'; + const isRadioSelectionMode = props.selectionMode === 'radiobutton'; + const isCheckboxSelectionMode = props.selectionMode === 'checkbox'; + const isRadioSelectionModeInColumn = props.selectionModeInColumn === 'single'; + const isCheckboxSelectionModeInColumn = props.selectionModeInColumn === 'multiple'; + + const equals = (data1, data2) => { + if (allowCellSelection()) return (data1.rowIndex === data2.rowIndex || data1.rowData === data2.rowData) && (data1.field === data2.field || data1.cellIndex === data2.cellIndex); + else return props.compareSelectionBy === 'equals' ? data1 === data2 : ObjectUtils.equals(data1, data2, props.dataKey); + }; + + const isSelectionEnabled = () => { + return props.selectionMode || props.selectionModeInColumn !== null || (props.columns && props.columns.some((col) => col && !!col.props.selectionMode)); + }; + + const isSingleSelection = () => { + return (props.selectionMode === 'single' && !isCheckboxSelectionModeInColumn) || (!isRadioSelectionMode && isRadioSelectionModeInColumn); + }; + + const isMultipleSelection = () => { + return (props.selectionMode === 'multiple' && !isRadioSelectionModeInColumn) || isCheckboxSelectionModeInColumn; + }; + + const isRadioOnlySelection = () => { + return isRadioSelectionMode && isRadioSelectionModeInColumn; + }; + + const isCheckboxOnlySelection = () => { + return isCheckboxSelectionMode && isCheckboxSelectionModeInColumn; + }; + + const isSelected = (rowData) => { + if (rowData && props.selection) { + return props.selection instanceof Array ? findIndex(props.selection, rowData) > -1 : equals(rowData, props.selection); + } + return false; - } - else { - const currentRowFieldData = ObjectUtils.resolveFieldData(rowData, props.groupRowsBy); - const nextRowData = value[i + 1]; - if (nextRowData) { - const nextRowFieldData = ObjectUtils.resolveFieldData(nextRowData, props.groupRowsBy); - return currentRowFieldData !== nextRowFieldData; + }; + + const isContextMenuSelected = (rowData) => { + if (rowData && props.contextMenuSelection) { + return equals(rowData, props.contextMenuSelection); + } + + return false; + }; + + const isSelectable = (options) => { + return props.isDataSelectable ? props.isDataSelectable(options) : true; + }; + + const isRowExpanded = (rowData) => { + if (rowData && props.expandedRows) { + if (isSubheaderGrouping && props.expandableRowGroups) { + return isRowGroupExpanded(rowData); + } else { + if (props.dataKey) return props.expandedRows ? props.expandedRows[ObjectUtils.resolveFieldData(rowData, props.dataKey)] !== undefined : false; + else return findIndex(props.expandedRows, rowData) !== -1; + } } - else { + + return false; + }; + + const isRowGroupExpanded = (rowData) => { + if (props.dataKey === props.groupRowsBy) return Object.keys(props.expandedRows).some((data) => ObjectUtils.equals(data, ObjectUtils.resolveFieldData(rowData, props.dataKey))); + else return props.expandedRows.some((data) => ObjectUtils.equals(data, rowData, props.groupRowsBy)); + }; + + const isRowEditing = (rowData) => { + if (props.editMode === 'row' && rowData && props.editingRows) { + if (props.dataKey) return props.editingRows ? props.editingRows[ObjectUtils.resolveFieldData(rowData, props.dataKey)] !== undefined : false; + else return findIndex(props.editingRows, rowData) !== -1; + } + + return false; + }; + + const allowDrag = (event) => { + return props.dragSelection && isMultipleSelection() && !event.originalEvent.shiftKey; + }; + + const allowRowDrag = (event) => { + return (!allowCellSelection() && allowDrag(event)) || props.reorderableRows; + }; + + const allowCellDrag = (event) => { + return allowCellSelection() && allowDrag(event); + }; + + const allowSelection = (event) => { + return !DomHandler.isClickable(event.originalEvent.target); + }; + + const allowMetaKeySelection = (event) => { + return !rowTouched.current && (!props.metaKeySelection || (props.metaKeySelection && (event.originalEvent.metaKey || event.originalEvent.ctrlKey))); + }; + + const allowRangeSelection = (event) => { + return isMultipleSelection() && event.originalEvent.shiftKey && anchorRowIndex.current !== null; + }; + + const allowRowSelection = () => { + return (props.selectionMode || props.selectionModeInColumn) && !isRadioOnlySelection() && !isCheckboxOnlySelection(); + }; + + const allowCellSelection = () => { + return props.cellSelection && !isRadioSelectionModeInColumn && !isCheckboxSelectionModeInColumn; + }; + + const getColumnsLength = () => { + return props.columns ? props.columns.length : 0; + }; + + const getVirtualScrollerOption = (option, options) => { + options = options || props.virtualScrollerOptions; + return options ? options[option] : null; + }; + + const findIndex = (collection, rowData) => { + return (collection || []).findIndex((data) => equals(rowData, data)); + }; + + const rowGroupHeaderStyle = () => { + if (props.scrollable) { + return { top: rowGroupHeaderStyleObjectState['top'] }; + } + + return null; + }; + + const getRowKey = (rowData, index) => { + return props.dataKey ? ObjectUtils.resolveFieldData(rowData, props.dataKey) + '_' + index : index; + }; + + const shouldRenderRowGroupHeader = (value, rowData, i) => { + const currentRowFieldData = ObjectUtils.resolveFieldData(rowData, props.groupRowsBy); + const prevRowData = value[i - 1]; + if (prevRowData) { + const previousRowFieldData = ObjectUtils.resolveFieldData(prevRowData, props.groupRowsBy); + return currentRowFieldData !== previousRowFieldData; + } else { return true; } - } - } - - const updateFrozenRowStickyPosition = () => { - elementRef.current.style.top = DomHandler.getOuterHeight(elementRef.current.previousElementSibling) + 'px'; - } - - const updateFrozenRowGroupHeaderStickyPosition = () => { - const tableHeaderHeight = DomHandler.getOuterHeight(elementRef.current.previousElementSibling); - const top = tableHeaderHeight + 'px'; - if (rowGroupHeaderStyleObjectState.top !== top) { - setRowGroupHeaderStyleObjectState({ top }); - } - } - - const updateVirtualScrollerPosition = () => { - const tableHeaderHeight = DomHandler.getOuterHeight(elementRef.current.previousElementSibling); - elementRef.current.style.top = (elementRef.current.style.top || 0) + tableHeaderHeight + 'px'; - } - - const onSingleSelection = ({ originalEvent, data, index, toggleable, type }) => { - if (!isSelectable({ data, index })) { - return; - } - - let selected = isSelected(data); - let selection = props.selection; - - if (selected) { - if (toggleable) { - selection = null; - onUnselect({ originalEvent, data, type }); - } - } - else { - selection = data; - onSelect({ originalEvent, data, type }); - } - - focusOnElement(originalEvent, true); - - if (props.onSelectionChange && selection !== props.selection) { - props.onSelectionChange({ - originalEvent, - value: selection, - type - }); - } - } - - const onMultipleSelection = ({ originalEvent, data, index, toggleable, type }) => { - if (!isSelectable({ data, index })) { - return; - } - - let selected = isSelected(data); - let selection = props.selection || []; - - if (selected) { - if (toggleable) { - let selectionIndex = findIndex(selection, data); - selection = props.selection.filter((val, i) => i !== selectionIndex); - onUnselect({ originalEvent, data, type }); - } - else if (selection.length) { - props.selection.forEach(d => onUnselect({ originalEvent, data: d, type })); - selection = [data]; + }; + + const shouldRenderRowGroupFooter = (value, rowData, i, expanded) => { + if (props.expandableRowGroups && !expanded) { + return false; + } else { + const currentRowFieldData = ObjectUtils.resolveFieldData(rowData, props.groupRowsBy); + const nextRowData = value[i + 1]; + if (nextRowData) { + const nextRowFieldData = ObjectUtils.resolveFieldData(nextRowData, props.groupRowsBy); + return currentRowFieldData !== nextRowFieldData; + } else { + return true; + } + } + }; + + const updateFrozenRowStickyPosition = () => { + elementRef.current.style.top = DomHandler.getOuterHeight(elementRef.current.previousElementSibling) + 'px'; + }; + + const updateFrozenRowGroupHeaderStickyPosition = () => { + const tableHeaderHeight = DomHandler.getOuterHeight(elementRef.current.previousElementSibling); + const top = tableHeaderHeight + 'px'; + if (rowGroupHeaderStyleObjectState.top !== top) { + setRowGroupHeaderStyleObjectState({ top }); + } + }; + + const updateVirtualScrollerPosition = () => { + const tableHeaderHeight = DomHandler.getOuterHeight(elementRef.current.previousElementSibling); + elementRef.current.style.top = (elementRef.current.style.top || 0) + tableHeaderHeight + 'px'; + }; + + const onSingleSelection = ({ originalEvent, data, index, toggleable, type }) => { + if (!isSelectable({ data, index })) { + return; + } + + let selected = isSelected(data); + let selection = props.selection; + + if (selected) { + if (toggleable) { + selection = null; + onUnselect({ originalEvent, data, type }); + } + } else { + selection = data; onSelect({ originalEvent, data, type }); } - } - else { - selection = toggleable && isMultipleSelection() ? [...selection, data] : [data]; - onSelect({ originalEvent, data, type }); - } - focusOnElement(originalEvent, true); + focusOnElement(originalEvent, true); - if (props.onSelectionChange && selection !== props.selection) { - props.onSelectionChange({ - originalEvent, - value: selection, - type - }); - } - } - - const onRangeSelection = (event, type) => { - DomHandler.clearSelection(); - rangeRowIndex.current = allowCellSelection() ? event.rowIndex : event.index; - let selectionInRange = selectRange(event); - let selection = isMultipleSelection() ? [...new Set([...(props.selection || []), ...selectionInRange])] : selectionInRange; - - if (props.onSelectionChange && selection !== props.selection) { - props.onSelectionChange({ - originalEvent: event.originalEvent, - value: selection, - type - }); - } - - anchorRowIndex.current = rangeRowIndex.current; - anchorCellIndex.current = event.cellIndex; - - focusOnElement(event.originalEvent, false); - } - - const selectRange = (event) => { - let rangeStart, rangeEnd; - - if (rangeRowIndex.current > anchorRowIndex.current) { - rangeStart = anchorRowIndex.current; - rangeEnd = rangeRowIndex.current; - } - else if (rangeRowIndex.current < anchorRowIndex.current) { - rangeStart = rangeRowIndex.current; - rangeEnd = anchorRowIndex.current; - } - else { - rangeStart = rangeEnd = rangeRowIndex.current; - } - - if (props.paginator) { - rangeStart = Math.max(rangeStart - props.first, 0); - rangeEnd -= props.first; - } - - return allowCellSelection() ? selectRangeOnCell(event, rangeStart, rangeEnd) : selectRangeOnRow(event, rangeStart, rangeEnd); - } - - const selectRangeOnRow = (event, rowRangeStart, rowRangeEnd) => { - const value = props.value; - let selection = []; - - for (let i = rowRangeStart; i <= rowRangeEnd; i++) { - let rangeRowData = value[i]; - if (!isSelectable({ data: rangeRowData, index: i })) { - continue; - } - - selection.push(rangeRowData); - - onSelect({ originalEvent: event.originalEvent, data: rangeRowData, type: 'row' }); - } - - return selection; - } - - const selectRangeOnCell = (event, rowRangeStart, rowRangeEnd) => { - let cellRangeStart, cellRangeEnd, cellIndex = event.cellIndex; - if (cellIndex > anchorCellIndex.current) { - cellRangeStart = anchorCellIndex.current; - cellRangeEnd = cellIndex; - } - else if (cellIndex < anchorCellIndex.current) { - cellRangeStart = cellIndex; - cellRangeEnd = anchorCellIndex.current; - } - else { - cellRangeStart = cellRangeEnd = cellIndex; - } - - const value = props.value; - let selection = []; - - for (let i = rowRangeStart; i <= rowRangeEnd; i++) { - let rowData = value[i]; - let columns = props.columns; - - for (let j = cellRangeStart; j <= cellRangeEnd; j++) { - let field = columns[j].props.field; - let value = ObjectUtils.resolveFieldData(rowData, field); - let rangeRowData = { - value, - field, - rowData, - rowIndex: i, - cellIndex: j, - selected: true - }; + if (props.onSelectionChange && selection !== props.selection) { + props.onSelectionChange({ + originalEvent, + value: selection, + type + }); + } + }; + + const onMultipleSelection = ({ originalEvent, data, index, toggleable, type }) => { + if (!isSelectable({ data, index })) { + return; + } + + let selected = isSelected(data); + let selection = props.selection || []; + + if (selected) { + if (toggleable) { + let selectionIndex = findIndex(selection, data); + selection = props.selection.filter((val, i) => i !== selectionIndex); + onUnselect({ originalEvent, data, type }); + } else if (selection.length) { + props.selection.forEach((d) => onUnselect({ originalEvent, data: d, type })); + selection = [data]; + onSelect({ originalEvent, data, type }); + } + } else { + selection = toggleable && isMultipleSelection() ? [...selection, data] : [data]; + onSelect({ originalEvent, data, type }); + } + + focusOnElement(originalEvent, true); + + if (props.onSelectionChange && selection !== props.selection) { + props.onSelectionChange({ + originalEvent, + value: selection, + type + }); + } + }; + + const onRangeSelection = (event, type) => { + DomHandler.clearSelection(); + rangeRowIndex.current = allowCellSelection() ? event.rowIndex : event.index; + let selectionInRange = selectRange(event); + let selection = isMultipleSelection() ? [...new Set([...(props.selection || []), ...selectionInRange])] : selectionInRange; + + if (props.onSelectionChange && selection !== props.selection) { + props.onSelectionChange({ + originalEvent: event.originalEvent, + value: selection, + type + }); + } + + anchorRowIndex.current = rangeRowIndex.current; + anchorCellIndex.current = event.cellIndex; + + focusOnElement(event.originalEvent, false); + }; + + const selectRange = (event) => { + let rangeStart, rangeEnd; + if (rangeRowIndex.current > anchorRowIndex.current) { + rangeStart = anchorRowIndex.current; + rangeEnd = rangeRowIndex.current; + } else if (rangeRowIndex.current < anchorRowIndex.current) { + rangeStart = rangeRowIndex.current; + rangeEnd = anchorRowIndex.current; + } else { + rangeStart = rangeEnd = rangeRowIndex.current; + } + + if (props.paginator) { + rangeStart = Math.max(rangeStart - props.first, 0); + rangeEnd -= props.first; + } + + return allowCellSelection() ? selectRangeOnCell(event, rangeStart, rangeEnd) : selectRangeOnRow(event, rangeStart, rangeEnd); + }; + + const selectRangeOnRow = (event, rowRangeStart, rowRangeEnd) => { + const value = props.value; + let selection = []; + + for (let i = rowRangeStart; i <= rowRangeEnd; i++) { + let rangeRowData = value[i]; if (!isSelectable({ data: rangeRowData, index: i })) { continue; } selection.push(rangeRowData); - onSelect({ originalEvent: event.originalEvent, data: rangeRowData, type: 'cell' }); + onSelect({ originalEvent: event.originalEvent, data: rangeRowData, type: 'row' }); } - } - return selection; - } + return selection; + }; + + const selectRangeOnCell = (event, rowRangeStart, rowRangeEnd) => { + let cellRangeStart, + cellRangeEnd, + cellIndex = event.cellIndex; + if (cellIndex > anchorCellIndex.current) { + cellRangeStart = anchorCellIndex.current; + cellRangeEnd = cellIndex; + } else if (cellIndex < anchorCellIndex.current) { + cellRangeStart = cellIndex; + cellRangeEnd = anchorCellIndex.current; + } else { + cellRangeStart = cellRangeEnd = cellIndex; + } + + const value = props.value; + let selection = []; + + for (let i = rowRangeStart; i <= rowRangeEnd; i++) { + let rowData = value[i]; + let columns = props.columns; + + for (let j = cellRangeStart; j <= cellRangeEnd; j++) { + let field = columns[j].props.field; + let value = ObjectUtils.resolveFieldData(rowData, field); + let rangeRowData = { + value, + field, + rowData, + rowIndex: i, + cellIndex: j, + selected: true + }; + + if (!isSelectable({ data: rangeRowData, index: i })) { + continue; + } - const onSelect = (event) => { - if (allowCellSelection()) - props.onCellSelect && props.onCellSelect({ originalEvent: event.originalEvent, ...event.data, type: event.type }); - else - props.onRowSelect && props.onRowSelect(event); - } + selection.push(rangeRowData); - const onUnselect = (event) => { - if (allowCellSelection()) - props.onCellUnselect && props.onCellUnselect({ originalEvent: event.originalEvent, ...event.data, type: event.type }); - else - props.onRowUnselect && props.onRowUnselect(event); - } + onSelect({ originalEvent: event.originalEvent, data: rangeRowData, type: 'cell' }); + } + } + + return selection; + }; - const enableDragSelection = (event) => { - if (props.dragSelection && !dragSelectionHelper.current) { - dragSelectionHelper.current = document.createElement('div'); - DomHandler.addClass(dragSelectionHelper.current, 'p-datatable-drag-selection-helper'); + const onSelect = (event) => { + if (allowCellSelection()) props.onCellSelect && props.onCellSelect({ originalEvent: event.originalEvent, ...event.data, type: event.type }); + else props.onRowSelect && props.onRowSelect(event); + }; - initialDragPosition.current = { x: event.clientX, y: event.clientY }; - dragSelectionHelper.current.style.top = `${event.pageY}px`; - dragSelectionHelper.current.style.left = `${event.pageX}px`; + const onUnselect = (event) => { + if (allowCellSelection()) props.onCellUnselect && props.onCellUnselect({ originalEvent: event.originalEvent, ...event.data, type: event.type }); + else props.onRowUnselect && props.onRowUnselect(event); + }; - bindDragSelectionEvents(); - } - } + const enableDragSelection = (event) => { + if (props.dragSelection && !dragSelectionHelper.current) { + dragSelectionHelper.current = document.createElement('div'); + DomHandler.addClass(dragSelectionHelper.current, 'p-datatable-drag-selection-helper'); - const focusOnElement = (event, isFocused) => { - const target = event.currentTarget; + initialDragPosition.current = { x: event.clientX, y: event.clientY }; + dragSelectionHelper.current.style.top = `${event.pageY}px`; + dragSelectionHelper.current.style.left = `${event.pageX}px`; - if (!allowCellSelection() && props.selectionAutoFocus) { - if (isCheckboxSelectionModeInColumn) { - const checkbox = DomHandler.findSingle(target, 'td.p-selection-column .p-checkbox-box'); - checkbox && checkbox.focus(); + bindDragSelectionEvents(); } - else if (isRadioSelectionModeInColumn) { - const radio = DomHandler.findSingle(target, 'td.p-selection-column input[type="radio"]'); - radio && radio.focus(); + }; + + const focusOnElement = (event, isFocused) => { + const target = event.currentTarget; + + if (!allowCellSelection() && props.selectionAutoFocus) { + if (isCheckboxSelectionModeInColumn) { + const checkbox = DomHandler.findSingle(target, 'td.p-selection-column .p-checkbox-box'); + checkbox && checkbox.focus(); + } else if (isRadioSelectionModeInColumn) { + const radio = DomHandler.findSingle(target, 'td.p-selection-column input[type="radio"]'); + radio && radio.focus(); + } } - } - !isFocused && target && target.focus(); - } + !isFocused && target && target.focus(); + }; - const changeTabIndex = (event, type) => { - const target = event.currentTarget; - const isSelectable = DomHandler.hasClass(target, type === 'cell' ? 'p-selectable-cell' : 'p-selectable-row'); + const changeTabIndex = (event, type) => { + const target = event.currentTarget; + const isSelectable = DomHandler.hasClass(target, type === 'cell' ? 'p-selectable-cell' : 'p-selectable-row'); - if (isSelectable) { - const selector = type === 'cell' ? 'tr > td' : 'tr'; - const tabbableEl = DomHandler.findSingle(elementRef.current, `${selector}[tabindex="${props.tabIndex}"]`); + if (isSelectable) { + const selector = type === 'cell' ? 'tr > td' : 'tr'; + const tabbableEl = DomHandler.findSingle(elementRef.current, `${selector}[tabindex="${props.tabIndex}"]`); - if (tabbableEl && target) { - tabbableEl.tabIndex = -1; - target.tabIndex = props.tabIndex; + if (tabbableEl && target) { + tabbableEl.tabIndex = -1; + target.tabIndex = props.tabIndex; + } } - } - } + }; - const onRowClick = (event) => { - if (allowCellSelection() || !allowSelection(event)) { - return; - } + const onRowClick = (event) => { + if (allowCellSelection() || !allowSelection(event)) { + return; + } - props.onRowClick && props.onRowClick(event); + props.onRowClick && props.onRowClick(event); + + if (allowRowSelection()) { + if (allowRangeSelection(event)) { + onRangeSelection(event, 'row'); + } else { + const toggleable = isRadioSelectionModeInColumn || isCheckboxSelectionModeInColumn || allowMetaKeySelection(event); + anchorRowIndex.current = event.index; + rangeRowIndex.current = event.index; + anchorRowFirst.current = props.first; + + if (isSingleSelection()) { + onSingleSelection({ ...event, toggleable, type: 'row' }); + } else { + onMultipleSelection({ ...event, toggleable, type: 'row' }); + } + } - if (allowRowSelection()) { - if (allowRangeSelection(event)) { - onRangeSelection(event, 'row'); + changeTabIndex(event.originalEvent, 'row'); + } else { + focusOnElement(event.originalEvent); } - else { - const toggleable = isRadioSelectionModeInColumn || isCheckboxSelectionModeInColumn || allowMetaKeySelection(event); - anchorRowIndex.current = event.index; - rangeRowIndex.current = event.index; - anchorRowFirst.current = props.first; - if (isSingleSelection()) { - onSingleSelection({ ...event, toggleable, type: 'row' }); + rowTouched.current = false; + }; + + const onRowDoubleClick = (e) => { + const { originalEvent: event } = e; + if (DomHandler.isClickable(event.target)) { + return; + } + + if (props.onRowDoubleClick) { + props.onRowDoubleClick(e); + } + }; + + const onRowRightClick = (event) => { + if (props.onContextMenu || props.onContextMenuSelectionChange) { + DomHandler.clearSelection(); + + if (props.onContextMenuSelectionChange) { + props.onContextMenuSelectionChange({ + originalEvent: event.originalEvent, + value: event.data + }); } - else { - onMultipleSelection({ ...event, toggleable, type: 'row' }); + + if (props.onContextMenu) { + props.onContextMenu({ + originalEvent: event.originalEvent, + data: event.data + }); } - } - changeTabIndex(event.originalEvent, 'row'); - } - else { - focusOnElement(event.originalEvent); - } + event.originalEvent.preventDefault(); + } + }; - rowTouched.current = false; - } + const onRowTouchEnd = () => { + rowTouched.current = true; + }; - const onRowDoubleClick = (e) => { - const { originalEvent: event } = e; - if (DomHandler.isClickable(event.target)) { - return; - } + const onRowMouseDown = (e) => { + const { originalEvent: event } = e; - if (props.onRowDoubleClick) { - props.onRowDoubleClick(e); - } - } + if (DomHandler.hasClass(event.target, 'p-datatable-reorderablerow-handle')) event.currentTarget.draggable = true; + else event.currentTarget.draggable = false; - const onRowRightClick = (event) => { - if (props.onContextMenu || props.onContextMenuSelectionChange) { - DomHandler.clearSelection(); + if (allowRowDrag(e)) { + enableDragSelection(event, 'row'); + anchorRowIndex.current = e.index; + rangeRowIndex.current = e.index; + anchorRowFirst.current = props.first; + } + }; - if (props.onContextMenuSelectionChange) { - props.onContextMenuSelectionChange({ - originalEvent: event.originalEvent, - value: event.data - }); + const onRowMouseUp = (event) => { + const isSameRow = event.index === anchorRowIndex.current; + if (allowRowDrag(event) && !isSameRow) { + onRangeSelection(event, 'row'); + } + }; + + const onRowToggle = (event) => { + let expandedRows; + let dataKey = props.dataKey; + let hasDataKey = props.groupRowsBy ? dataKey === props.groupRowsBy : !!dataKey; + + if (hasDataKey) { + let dataKeyValue = String(ObjectUtils.resolveFieldData(event.data, dataKey)); + expandedRows = props.expandedRows ? { ...props.expandedRows } : {}; + + if (expandedRows[dataKeyValue] != null) { + delete expandedRows[dataKeyValue]; + if (props.onRowCollapse) { + props.onRowCollapse({ originalEvent: event, data: event.data }); + } + } else { + expandedRows[dataKeyValue] = true; + if (props.onRowExpand) { + props.onRowExpand({ originalEvent: event, data: event.data }); + } + } + } else { + let expandedRowIndex = findIndex(props.expandedRows, event.data); + expandedRows = props.expandedRows ? [...props.expandedRows] : []; + + if (expandedRowIndex !== -1) { + expandedRows = expandedRows.filter((_, i) => i !== expandedRowIndex); + if (props.onRowCollapse) { + props.onRowCollapse({ originalEvent: event, data: event.data }); + } + } else { + expandedRows.push(event.data); + if (props.onRowExpand) { + props.onRowExpand({ originalEvent: event, data: event.data }); + } + } } - if (props.onContextMenu) { - props.onContextMenu({ - originalEvent: event.originalEvent, - data: event.data + if (props.onRowToggle) { + props.onRowToggle({ + data: expandedRows }); } + }; + + const onRowDragStart = (e) => { + const { originalEvent: event, index } = e; + if (allowRowDrag(event)) { + rowDragging.current = true; + draggedRowIndex.current = index; + event.dataTransfer.setData('text', 'b'); // For firefox + } + }; + + const onRowDragOver = (e) => { + const { originalEvent: event, index } = e; + + if (rowDragging.current && draggedRowIndex.current !== index) { + const rowElement = event.currentTarget; + const rowY = DomHandler.getOffset(rowElement).top + DomHandler.getWindowScrollTop(); + const pageY = event.pageY + window.scrollY; + const rowMidY = rowY + DomHandler.getOuterHeight(rowElement) / 2; + const prevRowElement = rowElement.previousElementSibling; + + if (pageY < rowMidY) { + DomHandler.removeClass(rowElement, 'p-datatable-dragpoint-bottom'); + + droppedRowIndex.current = index; + if (prevRowElement) DomHandler.addClass(prevRowElement, 'p-datatable-dragpoint-bottom'); + else DomHandler.addClass(rowElement, 'p-datatable-dragpoint-top'); + } else { + if (prevRowElement) DomHandler.removeClass(prevRowElement, 'p-datatable-dragpoint-bottom'); + else DomHandler.addClass(rowElement, 'p-datatable-dragpoint-top'); + + droppedRowIndex.current = index + 1; + DomHandler.addClass(rowElement, 'p-datatable-dragpoint-bottom'); + } + } - event.originalEvent.preventDefault(); - } - } + event.preventDefault(); + }; - const onRowTouchEnd = () => { - rowTouched.current = true; - } + const onRowDragLeave = (e) => { + const { originalEvent: event } = e; + const rowElement = event.currentTarget; + const prevRowElement = rowElement.previousElementSibling; - const onRowMouseDown = (e) => { - const { originalEvent: event } = e; + if (prevRowElement) { + DomHandler.removeClass(prevRowElement, 'p-datatable-dragpoint-bottom'); + } - if (DomHandler.hasClass(event.target, 'p-datatable-reorderablerow-handle')) - event.currentTarget.draggable = true; - else - event.currentTarget.draggable = false; + DomHandler.removeClass(rowElement, 'p-datatable-dragpoint-bottom'); + DomHandler.removeClass(rowElement, 'p-datatable-dragpoint-top'); + }; + + const onRowDragEnd = (e) => { + const { originalEvent: event } = e; - if (allowRowDrag(e)) { - enableDragSelection(event, 'row'); - anchorRowIndex.current = e.index; - rangeRowIndex.current = e.index; - anchorRowFirst.current = props.first; - } - } - - const onRowMouseUp = (event) => { - const isSameRow = event.index === anchorRowIndex.current; - if (allowRowDrag(event) && !isSameRow) { - onRangeSelection(event, 'row'); - } - } - - const onRowToggle = (event) => { - let expandedRows; - let dataKey = props.dataKey; - let hasDataKey = props.groupRowsBy ? dataKey === props.groupRowsBy : !!dataKey; - - if (hasDataKey) { - let dataKeyValue = String(ObjectUtils.resolveFieldData(event.data, dataKey)); - expandedRows = props.expandedRows ? { ...props.expandedRows } : {}; - - if (expandedRows[dataKeyValue] != null) { - delete expandedRows[dataKeyValue]; - if (props.onRowCollapse) { - props.onRowCollapse({ originalEvent: event, data: event.data }); + rowDragging.current = false; + draggedRowIndex.current = null; + droppedRowIndex.current = null; + event.currentTarget.draggable = false; + }; + + const onRowDrop = (e) => { + const { originalEvent: event } = e; + + if (droppedRowIndex.current != null) { + let dropIndex = draggedRowIndex.current > droppedRowIndex.current ? droppedRowIndex.current : droppedRowIndex.current === 0 ? 0 : droppedRowIndex.current - 1; + let val = [...props.value]; + ObjectUtils.reorderArray(val, draggedRowIndex.current, dropIndex); + + if (props.onRowReorder) { + props.onRowReorder({ + originalEvent: event, + value: val, + dragIndex: draggedRowIndex.current, + dropIndex: droppedRowIndex.current + }); } } - else { - expandedRows[dataKeyValue] = true; - if (props.onRowExpand) { - props.onRowExpand({ originalEvent: event, data: event.data }); - } + + //cleanup + onRowDragLeave(e); + onRowDragEnd(e); + event.preventDefault(); + }; + + const onRadioChange = (event) => { + onSingleSelection({ ...event, toggleable: true, type: 'radio' }); + }; + + const onCheckboxChange = (event) => { + onMultipleSelection({ ...event, toggleable: true, type: 'checkbox' }); + }; + + const onDragSelectionMouseMove = (event) => { + const { x, y } = initialDragPosition.current; + const dx = event.clientX - x; + const dy = event.clientY - y; + + if (dy < 0) dragSelectionHelper.current.style.top = `${event.pageY + 5}px`; + if (dx < 0) dragSelectionHelper.current.style.left = `${event.pageX + 5}px`; + + dragSelectionHelper.current.style.height = `${Math.abs(dy)}px`; + dragSelectionHelper.current.style.width = `${Math.abs(dx)}px`; + + event.preventDefault(); + }; + + const onDragSelectionMouseUp = () => { + if (dragSelectionHelper.current) { + dragSelectionHelper.current.remove(); + dragSelectionHelper.current = null; } - } - else { - let expandedRowIndex = findIndex(props.expandedRows, event.data); - expandedRows = props.expandedRows ? [...props.expandedRows] : []; - if (expandedRowIndex !== -1) { - expandedRows = expandedRows.filter((_, i) => i !== expandedRowIndex); - if (props.onRowCollapse) { - props.onRowCollapse({ originalEvent: event, data: event.data }); - } + document.removeEventListener('mousemove', onDragSelectionMouseMove); + document.removeEventListener('mouseup', onDragSelectionMouseUp); + }; + + const onCellClick = (event) => { + if (!allowSelection(event)) { + return; } - else { - expandedRows.push(event.data); - if (props.onRowExpand) { - props.onRowExpand({ originalEvent: event, data: event.data }); + + props.onCellClick && props.onCellClick(event); + + if (allowCellSelection()) { + if (allowRangeSelection(event)) { + onRangeSelection(event, 'cell'); + } else { + let toggleable = allowMetaKeySelection(event); + let { originalEvent, ...data } = event; + anchorRowIndex.current = event.rowIndex; + rangeRowIndex.current = event.rowIndex; + anchorRowFirst.current = props.first; + anchorCellIndex.current = event.cellIndex; + + if (isSingleSelection()) { + onSingleSelection({ originalEvent, data, index: event.rowIndex, toggleable, type: 'cell' }); + } else { + onMultipleSelection({ originalEvent, data, index: event.rowIndex, toggleable, type: 'cell' }); + } } + + changeTabIndex(event.originalEvent, 'cell'); } - } - if (props.onRowToggle) { - props.onRowToggle({ - data: expandedRows - }); - } - } - - const onRowDragStart = (e) => { - const { originalEvent: event, index } = e; - if (allowRowDrag(event)) { - rowDragging.current = true; - draggedRowIndex.current = index; - event.dataTransfer.setData('text', 'b'); // For firefox - } - } - - const onRowDragOver = (e) => { - const { originalEvent: event, index } = e; - - if (rowDragging.current && draggedRowIndex.current !== index) { - const rowElement = event.currentTarget; - const rowY = DomHandler.getOffset(rowElement).top + DomHandler.getWindowScrollTop(); - const pageY = event.pageY + window.scrollY; - const rowMidY = rowY + DomHandler.getOuterHeight(rowElement) / 2; - const prevRowElement = rowElement.previousElementSibling; + rowTouched.current = false; + }; - if (pageY < rowMidY) { - DomHandler.removeClass(rowElement, 'p-datatable-dragpoint-bottom'); - - droppedRowIndex.current = index; - if (prevRowElement) - DomHandler.addClass(prevRowElement, 'p-datatable-dragpoint-bottom'); - else - DomHandler.addClass(rowElement, 'p-datatable-dragpoint-top'); - } - else { - if (prevRowElement) - DomHandler.removeClass(prevRowElement, 'p-datatable-dragpoint-bottom'); - else - DomHandler.addClass(rowElement, 'p-datatable-dragpoint-top'); - - droppedRowIndex.current = index + 1; - DomHandler.addClass(rowElement, 'p-datatable-dragpoint-bottom'); - } - } - - event.preventDefault(); - } - - const onRowDragLeave = (e) => { - const { originalEvent: event } = e; - const rowElement = event.currentTarget; - const prevRowElement = rowElement.previousElementSibling; - - if (prevRowElement) { - DomHandler.removeClass(prevRowElement, 'p-datatable-dragpoint-bottom'); - } - - DomHandler.removeClass(rowElement, 'p-datatable-dragpoint-bottom'); - DomHandler.removeClass(rowElement, 'p-datatable-dragpoint-top'); - } - - const onRowDragEnd = (e) => { - const { originalEvent: event } = e; - - rowDragging.current = false; - draggedRowIndex.current = null; - droppedRowIndex.current = null; - event.currentTarget.draggable = false; - } - - const onRowDrop = (e) => { - const { originalEvent: event } = e; - - if (droppedRowIndex.current != null) { - let dropIndex = (draggedRowIndex.current > droppedRowIndex.current) ? droppedRowIndex.current : (droppedRowIndex.current === 0) ? 0 : droppedRowIndex.current - 1; - let val = [...props.value]; - ObjectUtils.reorderArray(val, draggedRowIndex.current, dropIndex); - - if (props.onRowReorder) { - props.onRowReorder({ - originalEvent: event, - value: val, - dragIndex: draggedRowIndex.current, - dropIndex: droppedRowIndex.current - }) - } - } - - //cleanup - onRowDragLeave(e); - onRowDragEnd(e); - event.preventDefault(); - } - - const onRadioChange = (event) => { - onSingleSelection({ ...event, toggleable: true, type: 'radio' }); - } - - const onCheckboxChange = (event) => { - onMultipleSelection({ ...event, toggleable: true, type: 'checkbox' }); - } - - const onDragSelectionMouseMove = (event) => { - const { x, y } = initialDragPosition.current; - const dx = event.clientX - x; - const dy = event.clientY - y; - - if (dy < 0) - dragSelectionHelper.current.style.top = `${event.pageY + 5}px`; - if (dx < 0) - dragSelectionHelper.current.style.left = `${event.pageX + 5}px`; - - dragSelectionHelper.current.style.height = `${Math.abs(dy)}px`; - dragSelectionHelper.current.style.width = `${Math.abs(dx)}px`; - - event.preventDefault(); - } - - const onDragSelectionMouseUp = () => { - if (dragSelectionHelper.current) { - dragSelectionHelper.current.remove(); - dragSelectionHelper.current = null; - } - - document.removeEventListener('mousemove', onDragSelectionMouseMove); - document.removeEventListener('mouseup', onDragSelectionMouseUp); - } - - const onCellClick = (event) => { - if (!allowSelection(event)) { - return; - } - - props.onCellClick && props.onCellClick(event); - - if (allowCellSelection()) { - if (allowRangeSelection(event)) { - onRangeSelection(event, 'cell'); - } - else { - let toggleable = allowMetaKeySelection(event); - let { originalEvent, ...data } = event; + const onCellMouseDown = (event) => { + if (allowCellDrag(event)) { + enableDragSelection(event.originalEvent); anchorRowIndex.current = event.rowIndex; rangeRowIndex.current = event.rowIndex; anchorRowFirst.current = props.first; anchorCellIndex.current = event.cellIndex; + } + }; - if (isSingleSelection()) { - onSingleSelection({ originalEvent, data, index: event.rowIndex, toggleable, type: 'cell' }); - } - else { - onMultipleSelection({ originalEvent, data, index: event.rowIndex, toggleable, type: 'cell' }); - } + const onCellMouseUp = (event) => { + const isSameCell = event.rowIndex === anchorRowIndex.current && event.cellIndex === anchorCellIndex.current; + if (allowCellDrag(event) && !isSameCell) { + onRangeSelection(event, 'cell'); } + }; - changeTabIndex(event.originalEvent, 'cell'); - } + const bindDragSelectionEvents = () => { + document.addEventListener('mousemove', onDragSelectionMouseMove); + document.addEventListener('mouseup', onDragSelectionMouseUp); + document.body.appendChild(dragSelectionHelper.current); + }; - rowTouched.current = false; - } + const unbindDragSelectionEvents = () => { + onDragSelectionMouseUp(); + }; - const onCellMouseDown = (event) => { - if (allowCellDrag(event)) { - enableDragSelection(event.originalEvent); - anchorRowIndex.current = event.rowIndex; - rangeRowIndex.current = event.rowIndex; - anchorRowFirst.current = props.first; - anchorCellIndex.current = event.cellIndex; - } - } - - const onCellMouseUp = (event) => { - const isSameCell = event.rowIndex === anchorRowIndex.current && event.cellIndex === anchorCellIndex.current; - if (allowCellDrag(event) && !isSameCell) { - onRangeSelection(event, 'cell'); - } - } - - const bindDragSelectionEvents = () => { - document.addEventListener('mousemove', onDragSelectionMouseMove); - document.addEventListener('mouseup', onDragSelectionMouseUp); - document.body.appendChild(dragSelectionHelper.current); - } - - const unbindDragSelectionEvents = () => { - onDragSelectionMouseUp(); - } - - React.useEffect(() => { - if (props.frozenRow) { - updateFrozenRowStickyPosition(); - } - - if (props.scrollable && props.rowGroupMode === 'subheader') { - updateFrozenRowGroupHeaderStickyPosition(); - } - }); - - useMountEffect(() => { - if (!props.isVirtualScrollerDisabled && getVirtualScrollerOption('vertical')) { - updateVirtualScrollerPosition(); - } - }); - - useUpdateEffect(() => { - if (!props.isVirtualScrollerDisabled && getVirtualScrollerOption('vertical') && getVirtualScrollerOption('itemSize', prevVirtualScrollerOptions) !== getVirtualScrollerOption('itemSize')) { - updateVirtualScrollerPosition(); - } - }, [props.virtualScrollerOptions]); - - useUpdateEffect(() => { - if (props.paginator && isMultipleSelection()) { - anchorRowIndex.current = null; - } - }, [props.first]); - - useUnmountEffect(() => { - if (props.dragSelection) { - unbindDragSelectionEvents(); - } - }); - - const createEmptyContent = () => { - if (!props.loading) { - const colSpan = getColumnsLength(); - const content = ObjectUtils.getJSXElement(props.emptyMessage, { props: props.tableProps, frozen: props.frozenRow }) || localeOption('emptyMessage'); - - return ( - - - {content} - - - ) - } - - return null; - } - - const createGroupHeader = (rowData, index, expanded, colSpan) => { - if (isSubheaderGrouping && shouldRenderRowGroupHeader(props.value, rowData, index - props.first)) { - const style = rowGroupHeaderStyle(); - const toggler = props.expandableRowGroups && ( - - ); - const content = ObjectUtils.getJSXElement(props.rowGroupHeaderTemplate, rowData, { index, props: props.tableProps }); - - return ( - - - {toggler} - + React.useEffect(() => { + if (props.frozenRow) { + updateFrozenRowStickyPosition(); + } + + if (props.scrollable && props.rowGroupMode === 'subheader') { + updateFrozenRowGroupHeaderStickyPosition(); + } + }); + + useMountEffect(() => { + if (!props.isVirtualScrollerDisabled && getVirtualScrollerOption('vertical')) { + updateVirtualScrollerPosition(); + } + }); + + useUpdateEffect(() => { + if (!props.isVirtualScrollerDisabled && getVirtualScrollerOption('vertical') && getVirtualScrollerOption('itemSize', prevVirtualScrollerOptions) !== getVirtualScrollerOption('itemSize')) { + updateVirtualScrollerPosition(); + } + }, [props.virtualScrollerOptions]); + + useUpdateEffect(() => { + if (props.paginator && isMultipleSelection()) { + anchorRowIndex.current = null; + } + }, [props.first]); + + useUnmountEffect(() => { + if (props.dragSelection) { + unbindDragSelectionEvents(); + } + }); + + const createEmptyContent = () => { + if (!props.loading) { + const colSpan = getColumnsLength(); + const content = ObjectUtils.getJSXElement(props.emptyMessage, { props: props.tableProps, frozen: props.frozenRow }) || localeOption('emptyMessage'); + + return ( + + {content} - - - - ) - } - - return null; - } - - const createRow = (rowData, index, expanded) => { - if (!props.expandableRowGroups || expanded) { - const selected = isSelectionEnabled() ? isSelected(rowData) : false; - const contextMenuSelected = isContextMenuSelected(rowData); - const _allowRowSelection = allowRowSelection(); - const _allowCellSelection = allowCellSelection(); - const editing = isRowEditing(rowData); - - return ( - - ) - } - } - - const createExpansion = (rowData, index, expanded, colSpan) => { - if (expanded && !(isSubheaderGrouping && props.expandableRowGroups)) { - const content = ObjectUtils.getJSXElement(props.rowExpansionTemplate, rowData, { index }); - const id = `${props.tableSelector}_content_${index}_expanded`; - - return ( - - - {content} - - - ) - } + + + ); + } - return null; - } + return null; + }; - const createGroupFooter = (rowData, index, expanded, colSpan) => { - if (isSubheaderGrouping && shouldRenderRowGroupFooter(props.value, rowData, index - props.first, expanded)) { - const content = ObjectUtils.getJSXElement(props.rowGroupFooterTemplate, rowData, { index, colSpan, props: props.tableProps }); + const createGroupHeader = (rowData, index, expanded, colSpan) => { + if (isSubheaderGrouping && shouldRenderRowGroupHeader(props.value, rowData, index - props.first)) { + const style = rowGroupHeaderStyle(); + const toggler = props.expandableRowGroups && ; + const content = ObjectUtils.getJSXElement(props.rowGroupHeaderTemplate, rowData, { index, props: props.tableProps }); - return ( - - {content} - - ) - } + return ( + + + {toggler} + {content} + + + ); + } - return null; - } + return null; + }; - const createContent = () => { - return ( - props.value.map((rowData, i) => { + const createRow = (rowData, index, expanded) => { + if (!props.expandableRowGroups || expanded) { + const selected = isSelectionEnabled() ? isSelected(rowData) : false; + const contextMenuSelected = isContextMenuSelected(rowData); + const _allowRowSelection = allowRowSelection(); + const _allowCellSelection = allowCellSelection(); + const editing = isRowEditing(rowData); + + return ( + + ); + } + }; + + const createExpansion = (rowData, index, expanded, colSpan) => { + if (expanded && !(isSubheaderGrouping && props.expandableRowGroups)) { + const content = ObjectUtils.getJSXElement(props.rowExpansionTemplate, rowData, { index }); + const id = `${props.tableSelector}_content_${index}_expanded`; + + return ( + + + {content} + + + ); + } + + return null; + }; + + const createGroupFooter = (rowData, index, expanded, colSpan) => { + if (isSubheaderGrouping && shouldRenderRowGroupFooter(props.value, rowData, index - props.first, expanded)) { + const content = ObjectUtils.getJSXElement(props.rowGroupFooterTemplate, rowData, { index, colSpan, props: props.tableProps }); + + return ( + + {content} + + ); + } + + return null; + }; + + const createContent = () => { + return props.value.map((rowData, i) => { const index = getVirtualScrollerOption('getItemOptions') ? getVirtualScrollerOption('getItemOptions')(i).index : props.first + i; const key = getRowKey(rowData, index); const expanded = isRowExpanded(rowData); @@ -920,19 +926,19 @@ export const TableBody = React.memo(React.forwardRef((props, ref) => { {expansion} {groupFooter} - ) - }) - ) - } - - const className = classNames('p-datatable-tbody', props.className); - const content = props.empty ? createEmptyContent() : createContent(); - - return ( - - {content} - - ) -})); + ); + }); + }; + + const className = classNames('p-datatable-tbody', props.className); + const content = props.empty ? createEmptyContent() : createContent(); + + return ( + + {content} + + ); + }) +); TableBody.displayName = 'TableBody'; diff --git a/components/lib/datatable/TableFooter.js b/components/lib/datatable/TableFooter.js index ec82224381..748d0e82c3 100644 --- a/components/lib/datatable/TableFooter.js +++ b/components/lib/datatable/TableFooter.js @@ -2,16 +2,15 @@ import * as React from 'react'; import { FooterCell } from './FooterCell'; export const TableFooter = React.memo((props) => { - const hasFooter = () => { - return props.footerColumnGroup ? true : (props.columns ? props.columns.some(col => col && col.props.footer) : false); - } + return props.footerColumnGroup ? true : props.columns ? props.columns.some((col) => col && col.props.footer) : false; + }; const createGroupFooterCells = (row) => { const columns = React.Children.toArray(row.props.children); return createFooterCells(columns); - } + }; const createFooterCells = (columns) => { return React.Children.map(columns, (col, i) => { @@ -19,27 +18,27 @@ export const TableFooter = React.memo((props) => { const key = col ? col.props.columnKey || col.props.field || i : i; return isVisible && ; - }) - } + }); + }; const createContent = () => { if (props.footerColumnGroup) { const rows = React.Children.toArray(props.footerColumnGroup.props.children); - return rows.map((row, i) => {createGroupFooterCells(row)}); + return rows.map((row, i) => ( + + {createGroupFooterCells(row)} + + )); } - return {createFooterCells(props.columns)}; - } + return {createFooterCells(props.columns)}; + }; if (hasFooter()) { const content = createContent(); - return ( - - {content} - - ) + return {content}; } return null; diff --git a/components/lib/datatable/TableHeader.js b/components/lib/datatable/TableHeader.js index 0c42672dc4..e5ecedfac3 100644 --- a/components/lib/datatable/TableHeader.js +++ b/components/lib/datatable/TableHeader.js @@ -13,8 +13,8 @@ export const TableHeader = React.memo((props) => { const isAllSortableDisabled = isSingleSort && allSortableDisabledState; const isColumnSorted = (column) => { - return props.sortField !== null ? (column.props.field === props.sortField || column.props.sortField === props.sortField) : false; - } + return props.sortField !== null ? column.props.field === props.sortField || column.props.sortField === props.sortField : false; + }; const updateSortableDisabled = () => { if (isSingleSort || (isMultipleSort && props.onSortChange)) { @@ -33,15 +33,15 @@ export const TableHeader = React.memo((props) => { setSortableDisabledFieldsState(sortableDisabledFields); setAllSortableDisabledState(allSortableDisabled); } - } + }; const onSortableChange = () => { updateSortableDisabled(); - } + }; const onCheckboxChange = (e) => { props.onColumnCheckboxChange(e, props.value); - } + }; useMountEffect(() => { updateSortableDisabled(); @@ -51,45 +51,73 @@ export const TableHeader = React.memo((props) => { const columns = React.Children.toArray(row.props.children); return createHeaderCells(columns); - } + }; const createHeaderCells = (columns) => { return React.Children.map(columns, (col, i) => { const isVisible = col ? !col.props.hidden : true; const key = col ? col.props.columnKey || col.props.field || i : i; - return isVisible && ( - - ) + return ( + isVisible && ( + + ) + ); }); - } + }; const createCheckbox = (selectionMode) => { if (props.showSelectAll && selectionMode === 'multiple') { const allRowsSelected = props.allRowsSelected(props.value); - return ( - - ) + return ; } return null; - } + }; const createFilter = (column, filter) => { if (filter) { - return ( - - ) + return ; } return null; - } + }; const createFilterCells = () => { return React.Children.map(props.columns, (col, i) => { @@ -108,39 +136,38 @@ export const TableHeader = React.memo((props) => { {checkbox} {filterRow} - ) + ); } return null; }); - } + }; const createContent = () => { if (props.headerColumnGroup) { const rows = React.Children.toArray(props.headerColumnGroup.props.children); - return rows.map((row, i) => {createGroupHeaderCells(row)}); - } - else { - const headerRow = {createHeaderCells(props.columns)}; - const filterRow = props.filterDisplay === 'row' && {createFilterCells()}; + return rows.map((row, i) => ( + + {createGroupHeaderCells(row)} + + )); + } else { + const headerRow = {createHeaderCells(props.columns)}; + const filterRow = props.filterDisplay === 'row' && {createFilterCells()}; return ( <> {headerRow} {filterRow} - ) + ); } - } + }; const content = createContent(); - return ( - - {content} - - ) + return {content}; }); TableHeader.displayName = 'TableHeader'; diff --git a/components/lib/datatable/datatable.d.ts b/components/lib/datatable/datatable.d.ts index 00fac66b2a..056bc2a4f3 100644 --- a/components/lib/datatable/datatable.d.ts +++ b/components/lib/datatable/datatable.d.ts @@ -181,13 +181,13 @@ interface DataTableSelectParams { type: DataTableSelectType; } -interface DataTableUnselectParams extends DataTableSelectParams { } +interface DataTableUnselectParams extends DataTableSelectParams {} interface DataTableExportFunctionParams { data: any; field: string; rowData: any; - column: Column + column: Column; } interface DataTableColReorderParams { diff --git a/components/lib/dataview/DataView.js b/components/lib/dataview/DataView.js index d40b4bf886..969886df2d 100644 --- a/components/lib/dataview/DataView.js +++ b/components/lib/dataview/DataView.js @@ -5,14 +5,13 @@ import { Ripple } from '../ripple/Ripple'; import { classNames, ObjectUtils } from '../utils/Utils'; export const DataViewLayoutOptions = React.memo((props) => { - const changeLayout = (event, layoutMode) => { props.onChange({ originalEvent: event, value: layoutMode }); event.preventDefault(); - } + }; const otherProps = ObjectUtils.findDiffKeys(props, DataViewLayoutOptions.defaultProps); const className = classNames('p-dataview-layout-options p-selectbutton p-buttonset', props.className); @@ -21,211 +20,223 @@ export const DataViewLayoutOptions = React.memo((props) => { return (
      - -
      - ) + ); }); export const DataViewItem = React.memo((props) => { return props.template(props.item, props.layout); }); -export const DataView = React.memo(React.forwardRef((props, ref) => { - const [firstState, setFirstState] = React.useState(props.first); - const [rowsState, setRowsState] = React.useState(props.rows); - const elementRef = React.useRef(null); - const first = props.onPage ? props.first : firstState; - const rows = props.onPage ? props.rows : rowsState; - - const getItemRenderKey = (value) => { - return props.dataKey ? ObjectUtils.resolveFieldData(value, props.dataKey) : null; - } +export const DataView = React.memo( + React.forwardRef((props, ref) => { + const [firstState, setFirstState] = React.useState(props.first); + const [rowsState, setRowsState] = React.useState(props.rows); + const elementRef = React.useRef(null); + const first = props.onPage ? props.first : firstState; + const rows = props.onPage ? props.rows : rowsState; - const getTotalRecords = () => { - return props.totalRecords ? props.totalRecords : (props.value ? props.value.length : 0); - } + const getItemRenderKey = (value) => { + return props.dataKey ? ObjectUtils.resolveFieldData(value, props.dataKey) : null; + }; - const createPaginator = (position) => { - const className = classNames('p-paginator-' + position, props.paginatorClassName); - const totalRecords = getTotalRecords(); + const getTotalRecords = () => { + return props.totalRecords ? props.totalRecords : props.value ? props.value.length : 0; + }; - return ( - - ) - } - - const onPageChange = (event) => { - if (props.onPage) { - props.onPage(event); - } - else { - setFirstState(event.first) - setRowsState(event.rows); - } - } - - const sort = () => { - if (props.value) { - const value = [...props.value]; - - value.sort((data1, data2) => { - let value1 = ObjectUtils.resolveFieldData(data1, props.sortField); - let value2 = ObjectUtils.resolveFieldData(data2, props.sortField); - return ObjectUtils.sort(value1, value2, props.sortOrder, PrimeReact.locale, PrimeReact.nullSortOrder); - }); + const createPaginator = (position) => { + const className = classNames('p-paginator-' + position, props.paginatorClassName); + const totalRecords = getTotalRecords(); - return value; - } + return ( + + ); + }; + + const onPageChange = (event) => { + if (props.onPage) { + props.onPage(event); + } else { + setFirstState(event.first); + setRowsState(event.rows); + } + }; - return null; - } + const sort = () => { + if (props.value) { + const value = [...props.value]; - const createLoader = () => { - if (props.loading) { - let iconClassName = classNames('p-dataview-loading-icon pi-spin', props.loadingIcon); + value.sort((data1, data2) => { + let value1 = ObjectUtils.resolveFieldData(data1, props.sortField); + let value2 = ObjectUtils.resolveFieldData(data2, props.sortField); + return ObjectUtils.sort(value1, value2, props.sortOrder, PrimeReact.locale, PrimeReact.nullSortOrder); + }); - return ( -
      - -
      - ) - } + return value; + } - return null; - } + return null; + }; - const createTopPaginator = () => { - if (props.paginator && (props.paginatorPosition !== 'bottom' || props.paginatorPosition === 'both')) { - return createPaginator('top'); - } + const createLoader = () => { + if (props.loading) { + let iconClassName = classNames('p-dataview-loading-icon pi-spin', props.loadingIcon); - return null; - } + return ( +
      + +
      + ); + } + return null; + }; - const createBottomPaginator = () => { - if (props.paginator && (props.paginatorPosition !== 'top' || props.paginatorPosition === 'both')) { - return createPaginator('bottom'); - } + const createTopPaginator = () => { + if (props.paginator && (props.paginatorPosition !== 'bottom' || props.paginatorPosition === 'both')) { + return createPaginator('top'); + } - return null; - } + return null; + }; - const createEmptyMessage = () => { - if (!props.loading) { - const content = props.emptyMessage || localeOption('emptyMessage'); + const createBottomPaginator = () => { + if (props.paginator && (props.paginatorPosition !== 'top' || props.paginatorPosition === 'both')) { + return createPaginator('bottom'); + } - return
      {content}
      - } + return null; + }; - return null; - } + const createEmptyMessage = () => { + if (!props.loading) { + const content = props.emptyMessage || localeOption('emptyMessage'); - const createHeader = () => { - if (props.header) { - return
      {props.header}
      - } + return
      {content}
      ; + } - return null; - } + return null; + }; - const createFooter = () => { - if (props.footer) { - return
      {props.footer}
      - } + const createHeader = () => { + if (props.header) { + return
      {props.header}
      ; + } - return null; - } + return null; + }; - const createItems = (value) => { - if (ObjectUtils.isNotEmpty(value)) { - if (props.paginator) { - const currentFirst = props.lazy ? 0 : first; - const totalRecords = getTotalRecords(); - const last = Math.min(rows + currentFirst, totalRecords); - let items = []; + const createFooter = () => { + if (props.footer) { + return
      {props.footer}
      ; + } - for (let i = currentFirst; i < last; i++) { - const val = value[i]; - val && items.push(); + return null; + }; + + const createItems = (value) => { + if (ObjectUtils.isNotEmpty(value)) { + if (props.paginator) { + const currentFirst = props.lazy ? 0 : first; + const totalRecords = getTotalRecords(); + const last = Math.min(rows + currentFirst, totalRecords); + let items = []; + + for (let i = currentFirst; i < last; i++) { + const val = value[i]; + val && items.push(); + } + return items; } - return items; + + return value.map((item, index) => { + return ; + }); } + return createEmptyMessage(); + }; + + const createContent = (value) => { + const items = createItems(value); + const gridClassName = classNames('p-grid grid', { + 'p-nogutter grid-nogutter': !props.gutter + }); + return ( - value.map((item, index) => { - return - }) - ) - } - - return createEmptyMessage(); - } - - const createContent = (value) => { - const items = createItems(value); - const gridClassName = classNames('p-grid grid', { - 'p-nogutter grid-nogutter': !props.gutter - }); +
      +
      {items}
      +
      + ); + }; + + const processData = () => { + let data = props.value; + + if (ObjectUtils.isNotEmpty(data) && props.sortField) { + data = sort(); + } + + return data; + }; + + React.useImperativeHandle(ref, () => ({ + props, + getElement: () => elementRef.current + })); + + const data = processData(); + + const otherProps = ObjectUtils.findDiffKeys(props, DataView.defaultProps); + const className = classNames( + 'p-dataview p-component', + { + [`p-dataview-${props.layout}`]: !!props.layout, + 'p-dataview-loading': props.loading + }, + props.className + ); + const loader = createLoader(); + const topPaginator = createTopPaginator(); + const bottomPaginator = createBottomPaginator(); + const header = createHeader(); + const footer = createFooter(); + const content = createContent(data); return ( -
      -
      - {items} -
      +
      + {loader} + {header} + {topPaginator} + {content} + {bottomPaginator} + {footer}
      - ) - } - - const processData = () => { - let data = props.value; - - if (ObjectUtils.isNotEmpty(data) && props.sortField) { - data = sort(); - } - - return data; - } - - React.useImperativeHandle(ref, () => ({ - props, - getElement: () => elementRef.current - })); - - const data = processData(); - - const otherProps = ObjectUtils.findDiffKeys(props, DataView.defaultProps); - const className = classNames('p-dataview p-component', { - [`p-dataview-${props.layout}`]: !!props.layout, - 'p-dataview-loading': props.loading - }, props.className); - const loader = createLoader(); - const topPaginator = createTopPaginator(); - const bottomPaginator = createBottomPaginator(); - const header = createHeader(); - const footer = createFooter(); - const content = createContent(data); - - return ( -
      - {loader} - {header} - {topPaginator} - {content} - {bottomPaginator} - {footer} -
      - ) -})); + ); + }) +); DataViewLayoutOptions.displayName = 'DataViewLayoutOptions'; DataViewLayoutOptions.defaultProps = { @@ -235,7 +246,7 @@ DataViewLayoutOptions.defaultProps = { className: null, layout: null, onChange: null -} +}; DataViewItem.displayName = 'DataViewItem'; @@ -273,4 +284,4 @@ DataView.defaultProps = { gutter: false, itemTemplate: null, onPage: null -} +}; diff --git a/components/lib/dataview/dataview.d.ts b/components/lib/dataview/dataview.d.ts index 00caf98fdf..d00710c460 100755 --- a/components/lib/dataview/dataview.d.ts +++ b/components/lib/dataview/dataview.d.ts @@ -1,7 +1,7 @@ import * as React from 'react'; import { PaginatorTemplate } from '../paginator'; -type DataViewLayoutType = 'list' | 'grid' | (string & {}); +type DataViewLayoutType = 'list' | 'grid' | (string & Record); type DataViewPaginatorPositionType = 'top' | 'bottom' | 'both'; @@ -30,7 +30,7 @@ export interface DataViewLayoutOptionsProps { children?: React.ReactNode; } -export declare class DataViewLayoutOptions extends React.Component { } +export declare class DataViewLayoutOptions extends React.Component {} export interface DataViewProps extends Omit, HTMLDivElement>, 'ref'> { header?: React.ReactNode; diff --git a/components/lib/deferredcontent/DeferredContent.js b/components/lib/deferredcontent/DeferredContent.js index 90c9c50935..120b97f3aa 100644 --- a/components/lib/deferredcontent/DeferredContent.js +++ b/components/lib/deferredcontent/DeferredContent.js @@ -7,7 +7,9 @@ export const DeferredContent = React.forwardRef((props, ref) => { const elementRef = React.useRef(null); const [bindScrollListener, unbindScrollListener] = useEventListener({ - target: 'window', type: 'scroll', listener: () => { + target: 'window', + type: 'scroll', + listener: () => { if (shouldLoad()) { load(); unbindScrollListener(); @@ -18,19 +20,18 @@ export const DeferredContent = React.forwardRef((props, ref) => { const shouldLoad = () => { if (loadedState) { return false; - } - else { + } else { const rect = elementRef.current.getBoundingClientRect(); const winHeight = document.documentElement.clientHeight; - return (winHeight >= rect.top); + return winHeight >= rect.top; } - } + }; const load = (event) => { setLoadedState(true); props.onLoad && props.onLoad(event); - } + }; React.useImperativeHandle(ref, () => ({ props, @@ -49,11 +50,11 @@ export const DeferredContent = React.forwardRef((props, ref) => {
      {loadedState && props.children}
      - ) + ); }); DeferredContent.displayName = 'DeferredContent'; DeferredContent.defaultProps = { __TYPE: 'DeferredContent', onload: null -} +}; diff --git a/components/lib/deferredcontent/deferredcontent.d.ts b/components/lib/deferredcontent/deferredcontent.d.ts index 22287c44d1..7e488e32ed 100644 --- a/components/lib/deferredcontent/deferredcontent.d.ts +++ b/components/lib/deferredcontent/deferredcontent.d.ts @@ -5,6 +5,6 @@ export interface DeferredContentProps extends Omit { +export declare class DeferredContent extends React.Component { public getElement(): HTMLDivElement; } diff --git a/components/lib/dialog/Dialog.js b/components/lib/dialog/Dialog.js index 36b6d41502..04f3cf8683 100644 --- a/components/lib/dialog/Dialog.js +++ b/components/lib/dialog/Dialog.js @@ -35,7 +35,7 @@ export const Dialog = React.forwardRef((props, ref) => { DomHandler.removeClass(document.body, 'p-overflow-hidden'); props.onHide(); event.preventDefault(); - } + }; const focus = () => { let activeElement = document.activeElement; @@ -43,7 +43,7 @@ export const Dialog = React.forwardRef((props, ref) => { if (!isActiveElementInDialog && props.closable && props.showHeader) { closeRef.current.focus(); } - } + }; const onMaskClick = (event) => { if (props.dismissableMask && props.modal && maskRef.current === event.target) { @@ -51,7 +51,7 @@ export const Dialog = React.forwardRef((props, ref) => { } props.onMaskClick && props.onMaskClick(event); - } + }; const toggleMaximize = (event) => { if (props.onMaximize) { @@ -59,13 +59,12 @@ export const Dialog = React.forwardRef((props, ref) => { originalEvent: event, maximized: !maximized }); - } - else { + } else { setMaximizedState((prevMaximized) => !prevMaximized); } event.preventDefault(); - } + }; const onKeyDown = (event) => { let currentTarget = event.currentTarget; @@ -83,34 +82,27 @@ export const Dialog = React.forwardRef((props, ref) => { event.stopImmediatePropagation(); params.splice(paramLength - 1, 1); - } - else if (event.which === 9) { + } else if (event.which === 9) { event.preventDefault(); let focusableElements = DomHandler.getFocusableElements(dialog); if (focusableElements && focusableElements.length > 0) { if (!document.activeElement) { focusableElements[0].focus(); - } - else { + } else { let focusedIndex = focusableElements.indexOf(document.activeElement); if (event.shiftKey) { - if (focusedIndex === -1 || focusedIndex === 0) - focusableElements[focusableElements.length - 1].focus(); - else - focusableElements[focusedIndex - 1].focus(); - } - else { - if (focusedIndex === -1 || focusedIndex === (focusableElements.length - 1)) - focusableElements[0].focus(); - else - focusableElements[focusedIndex + 1].focus(); + if (focusedIndex === -1 || focusedIndex === 0) focusableElements[focusableElements.length - 1].focus(); + else focusableElements[focusedIndex - 1].focus(); + } else { + if (focusedIndex === -1 || focusedIndex === focusableElements.length - 1) focusableElements[0].focus(); + else focusableElements[focusedIndex + 1].focus(); } } } } } } - } + }; const onDragStart = (event) => { if (DomHandler.hasClass(event.target, 'p-dialog-header-icon') || DomHandler.hasClass(event.target.parentElement, 'p-dialog-header-icon')) { @@ -126,7 +118,7 @@ export const Dialog = React.forwardRef((props, ref) => { props.onDragStart && props.onDragStart(event); } - } + }; const onDrag = (event) => { if (dragging.current) { @@ -142,17 +134,16 @@ export const Dialog = React.forwardRef((props, ref) => { dialogRef.current.style.position = 'fixed'; if (props.keepInViewport) { - if (leftPos >= props.minX && (leftPos + width) < viewport.width) { + if (leftPos >= props.minX && leftPos + width < viewport.width) { lastPageX.current = event.pageX; dialogRef.current.style.left = leftPos + 'px'; } - if (topPos >= props.minY && (topPos + height) < viewport.height) { + if (topPos >= props.minY && topPos + height < viewport.height) { lastPageY.current = event.pageY; dialogRef.current.style.top = topPos + 'px'; } - } - else { + } else { lastPageX.current = event.pageX; dialogRef.current.style.left = leftPos + 'px'; lastPageY.current = event.pageY; @@ -161,7 +152,7 @@ export const Dialog = React.forwardRef((props, ref) => { props.onDrag && props.onDrag(event); } - } + }; const onDragEnd = (event) => { if (dragging.current) { @@ -170,7 +161,7 @@ export const Dialog = React.forwardRef((props, ref) => { props.onDragEnd && props.onDragEnd(event); } - } + }; const onResizeStart = (event) => { if (props.resizable) { @@ -181,7 +172,7 @@ export const Dialog = React.forwardRef((props, ref) => { props.onResizeStart && props.onResizeStart(event); } - } + }; const convertToPx = (value, property, viewport) => { !viewport && (viewport = DomHandler.getViewport()); @@ -192,7 +183,7 @@ export const Dialog = React.forwardRef((props, ref) => { } return val; - } + }; const onResize = (event) => { if (resizing.current) { @@ -214,11 +205,11 @@ export const Dialog = React.forwardRef((props, ref) => { newHeight += deltaY; } - if ((!minWidth || newWidth > minWidth) && (offset.left + newWidth) < viewport.width) { + if ((!minWidth || newWidth > minWidth) && offset.left + newWidth < viewport.width) { dialogRef.current.style.width = newWidth + 'px'; } - if ((!minHeight || newHeight > minHeight) && (offset.top + newHeight) < viewport.height) { + if ((!minHeight || newHeight > minHeight) && offset.top + newHeight < viewport.height) { dialogRef.current.style.height = newHeight + 'px'; } @@ -227,7 +218,7 @@ export const Dialog = React.forwardRef((props, ref) => { props.onResize && props.onResize(event); } - } + }; const onResizeEnd = (event) => { if (resizing.current) { @@ -236,25 +227,25 @@ export const Dialog = React.forwardRef((props, ref) => { props.onResizeEnd && props.onResizeEnd(event); } - } + }; const resetPosition = () => { dialogRef.current.style.position = ''; dialogRef.current.style.left = ''; dialogRef.current.style.top = ''; dialogRef.current.style.margin = ''; - } + }; const getPositionClass = () => { const positions = ['center', 'left', 'right', 'top', 'top-left', 'top-right', 'bottom', 'bottom-left', 'bottom-right']; - const pos = positions.find(item => item === props.position || item.replace('-', '') === props.position); + const pos = positions.find((item) => item === props.position || item.replace('-', '') === props.position); return pos ? `p-dialog-${pos}` : ''; - } + }; const onEnter = () => { dialogRef.current.setAttribute(attributeSelector.current, ''); - } + }; const onEntered = () => { props.onShow && props.onShow(); @@ -264,20 +255,20 @@ export const Dialog = React.forwardRef((props, ref) => { } enableDocumentSettings(); - } + }; const onExiting = () => { if (props.modal) { DomHandler.addClass(maskRef.current, 'p-component-overlay-leave'); } - } + }; const onExited = () => { dragging.current = false; ZIndexUtils.clear(maskRef.current); setMaskVisibleState(false); disableDocumentSettings(); - } + }; const enableDocumentSettings = () => { bindGlobalListeners(); @@ -285,21 +276,20 @@ export const Dialog = React.forwardRef((props, ref) => { if (props.blockScroll || (props.maximizable && maximized)) { DomHandler.addClass(document.body, 'p-overflow-hidden'); } - } + }; const disableDocumentSettings = () => { unbindGlobalListeners(); if (props.modal) { - let hasBlockScroll = document.primeDialogParams && document.primeDialogParams.some(param => param.hasBlockScroll); + let hasBlockScroll = document.primeDialogParams && document.primeDialogParams.some((param) => param.hasBlockScroll); if (hasBlockScroll) { DomHandler.removeClass(document.body, 'p-overflow-hidden'); } - } - else if (props.blockScroll || (props.maximizable && maximized)) { + } else if (props.blockScroll || (props.maximizable && maximized)) { DomHandler.removeClass(document.body, 'p-overflow-hidden'); } - } + }; const bindGlobalListeners = () => { if (props.draggable) { @@ -318,7 +308,7 @@ export const Dialog = React.forwardRef((props, ref) => { const newParam = { id: idState, hasBlockScroll: props.blockScroll }; document.primeDialogParams = document.primeDialogParams ? [...document.primeDialogParams, newParam] : [newParam]; } - } + }; const unbindGlobalListeners = () => { unbindDocumentDragListener(); @@ -327,8 +317,8 @@ export const Dialog = React.forwardRef((props, ref) => { unbindDocumentResizEndListener(); unbindDocumentKeyDownListener(); - document.primeDialogParams = document.primeDialogParams && document.primeDialogParams.filter(param => param.id !== idState); - } + document.primeDialogParams = document.primeDialogParams && document.primeDialogParams.filter((param) => param.id !== idState); + }; const createStyle = () => { if (!styleElement.current) { @@ -342,19 +332,19 @@ export const Dialog = React.forwardRef((props, ref) => { width: ${props.breakpoints[breakpoint]} !important; } } - ` + `; } styleElement.current.innerHTML = innerHTML; } - } + }; const changeScrollOnMaximizable = () => { if (!props.blockScroll) { let funcName = maximized ? 'addClass' : 'removeClass'; DomHandler[funcName](document.body, 'p-overflow-hidden'); } - } + }; useMountEffect(() => { if (!idState) { @@ -413,15 +403,15 @@ export const Dialog = React.forwardRef((props, ref) => { const createCloseIcon = () => { if (props.closable) { return ( - - ) + ); } return null; - } + }; const createMaximizeIcon = () => { const iconClassName = classNames('p-dialog-header-maximize-icon pi', { @@ -431,15 +421,15 @@ export const Dialog = React.forwardRef((props, ref) => { if (props.maximizable) { return ( - - ) + ); } return null; - } + }; const createHeader = () => { if (props.showHeader) { @@ -452,18 +442,20 @@ export const Dialog = React.forwardRef((props, ref) => { return (
      -
      {header}
      -
      +
      + {header} +
      +
      {icons} {maximizeIcon} {closeIcon}
      - ) + ); } return null; - } + }; const createContent = () => { const className = classNames('p-dialog-content', props.contentClassName); @@ -473,22 +465,28 @@ export const Dialog = React.forwardRef((props, ref) => {
      {props.children}
      - ) - } + ); + }; const createFooter = () => { const footer = ObjectUtils.getJSXElement(props.footer, props); - return footer &&
      {footer}
      - } + return ( + footer && ( +
      + {footer} +
      + ) + ); + }; const createResizer = () => { if (props.resizable) { - return + return ; } return null; - } + }; const createElement = () => { const otherProps = ObjectUtils.findDiffKeys(props, Dialog.defaultProps); @@ -496,12 +494,17 @@ export const Dialog = React.forwardRef((props, ref) => { 'p-dialog-rtl': props.rtl, 'p-dialog-maximized': maximized }); - const maskClassName = classNames('p-dialog-mask', getPositionClass(), { - 'p-component-overlay p-component-overlay-enter': props.modal, - 'p-dialog-visible': maskVisibleState, - 'p-dialog-draggable': props.draggable, - 'p-dialog-resizable': props.resizable, - }, props.maskClassName); + const maskClassName = classNames( + 'p-dialog-mask', + getPositionClass(), + { + 'p-component-overlay p-component-overlay-enter': props.modal, + 'p-dialog-visible': maskVisibleState, + 'p-dialog-draggable': props.draggable, + 'p-dialog-resizable': props.resizable + }, + props.maskClassName + ); const header = createHeader(); const content = createContent(); const footer = createFooter(); @@ -516,10 +519,8 @@ export const Dialog = React.forwardRef((props, ref) => { return (
      - - - ) - } + ); + }; const createDialog = () => { const element = createElement(); - return - } + return ; + }; return maskVisibleState && createDialog(); }); @@ -587,4 +588,4 @@ Dialog.defaultProps = { onResizeEnd: null, onClick: null, onMaskClick: null -} +}; diff --git a/components/lib/divider/Divider.js b/components/lib/divider/Divider.js index 098a0009e6..49a007a898 100644 --- a/components/lib/divider/Divider.js +++ b/components/lib/divider/Divider.js @@ -6,13 +6,17 @@ export const Divider = React.forwardRef((props, ref) => { const horizontal = props.layout === 'horizontal'; const vertical = props.layout === 'vertical'; const otherProps = ObjectUtils.findDiffKeys(props, Divider.defaultProps); - const className = classNames(`p-divider p-component p-divider-${props.layout} p-divider-${props.type}`, { - 'p-divider-left': horizontal && (!props.align || props.align === 'left'), - 'p-divider-right': horizontal && props.align === 'right', - 'p-divider-center': (horizontal && props.align === 'center') || (vertical && (!props.align || props.align === 'center')), - 'p-divider-top': vertical && props.align === 'top', - 'p-divider-bottom': vertical && props.align === 'bottom', - }, props.className); + const className = classNames( + `p-divider p-component p-divider-${props.layout} p-divider-${props.type}`, + { + 'p-divider-left': horizontal && (!props.align || props.align === 'left'), + 'p-divider-right': horizontal && props.align === 'right', + 'p-divider-center': (horizontal && props.align === 'center') || (vertical && (!props.align || props.align === 'center')), + 'p-divider-top': vertical && props.align === 'top', + 'p-divider-bottom': vertical && props.align === 'bottom' + }, + props.className + ); React.useImperativeHandle(ref, () => ({ props, @@ -20,12 +24,10 @@ export const Divider = React.forwardRef((props, ref) => { })); return ( -
      -
      - {props.children} -
      +
      +
      {props.children}
      - ) + ); }); Divider.displayName = 'Divider'; @@ -36,4 +38,4 @@ Divider.defaultProps = { type: 'solid', style: null, className: null -} +}; diff --git a/components/lib/divider/divider.d.ts b/components/lib/divider/divider.d.ts index 28afe527d2..dca19b47b4 100644 --- a/components/lib/divider/divider.d.ts +++ b/components/lib/divider/divider.d.ts @@ -13,6 +13,6 @@ export interface DividerProps extends Omit { +export declare class Divider extends React.Component { public getElement(): HTMLDivElement; } diff --git a/components/lib/dock/Dock.js b/components/lib/dock/Dock.js index ccc9e7b207..253089df51 100644 --- a/components/lib/dock/Dock.js +++ b/components/lib/dock/Dock.js @@ -2,129 +2,127 @@ import * as React from 'react'; import { Ripple } from '../ripple/Ripple'; import { classNames, IconUtils, ObjectUtils } from '../utils/Utils'; -export const Dock = React.memo(React.forwardRef((props, ref) => { - const [currentIndexState, setCurrentIndexState] = React.useState(-3); - const elementRef = React.useRef(null); - - const onListMouseLeave = () => { - setCurrentIndexState(-3); - } - - const onItemMouseEnter = (index) => { - setCurrentIndexState(index); - } - - const onItemClick = (e, item) => { - if (item.command) { - item.command({ originalEvent: e, item }); - } - - e.preventDefault(); - } - - const createItem = (item, index) => { - const { disabled, icon: _icon, label, template, url, target } = item; - const className = classNames('p-dock-item', { - 'p-dock-item-second-prev': (currentIndexState - 2) === index, - 'p-dock-item-prev': (currentIndexState - 1) === index, - 'p-dock-item-current': currentIndexState === index, - 'p-dock-item-next': (currentIndexState + 1) === index, - 'p-dock-item-second-next': (currentIndexState + 2) === index - }); - const contentClassName = classNames('p-dock-action', { 'p-disabled': disabled }); - const iconClassName = classNames('p-dock-action-icon', _icon); - const icon = IconUtils.getJSXIcon(_icon, { className: 'p-dock-action-icon' }, { props }); - - let content = ( - onItemClick(e, item)}> - {icon} - - - ); +export const Dock = React.memo( + React.forwardRef((props, ref) => { + const [currentIndexState, setCurrentIndexState] = React.useState(-3); + const elementRef = React.useRef(null); + + const onListMouseLeave = () => { + setCurrentIndexState(-3); + }; + + const onItemMouseEnter = (index) => { + setCurrentIndexState(index); + }; + + const onItemClick = (e, item) => { + if (item.command) { + item.command({ originalEvent: e, item }); + } + + e.preventDefault(); + }; + + const createItem = (item, index) => { + const { disabled, icon: _icon, label, template, url, target } = item; + const className = classNames('p-dock-item', { + 'p-dock-item-second-prev': currentIndexState - 2 === index, + 'p-dock-item-prev': currentIndexState - 1 === index, + 'p-dock-item-current': currentIndexState === index, + 'p-dock-item-next': currentIndexState + 1 === index, + 'p-dock-item-second-next': currentIndexState + 2 === index + }); + const contentClassName = classNames('p-dock-action', { 'p-disabled': disabled }); + const iconClassName = classNames('p-dock-action-icon', _icon); + const icon = IconUtils.getJSXIcon(_icon, { className: 'p-dock-action-icon' }, { props }); + + let content = ( + onItemClick(e, item)}> + {icon} + + + ); + + if (template) { + const defaultContentOptions = { + onClick: (e) => onItemClick(e, item), + className: contentClassName, + iconClassName, + element: content, + props, + index + }; + + content = ObjectUtils.getJSXElement(template, item, defaultContentOptions); + } - if (template) { - const defaultContentOptions = { - onClick: (e) => onItemClick(e, item), - className: contentClassName, - iconClassName, - element: content, - props, - index - }; + return ( +
    • onItemMouseEnter(index)}> + {content} +
    • + ); + }; - content = ObjectUtils.getJSXElement(template, item, defaultContentOptions); - } + const createItems = () => { + return props.model ? props.model.map(createItem) : null; + }; - return ( -
    • onItemMouseEnter(index)}> - {content} -
    • - ) - } - - const createItems = () => { - return props.model ? props.model.map(createItem) : null; - } - - const createHeader = () => { - if (props.header) { - const header = ObjectUtils.getJSXElement(props.header, { props }); - return ( -
      - {header} -
      - ) - } + const createHeader = () => { + if (props.header) { + const header = ObjectUtils.getJSXElement(props.header, { props }); + return
      {header}
      ; + } - return null; - } + return null; + }; - const createList = () => { - const items = createItems(); + const createList = () => { + const items = createItems(); - return ( -
        - {items} -
      - ) - } - - const createFooter = () => { - if (props.footer) { - const footer = ObjectUtils.getJSXElement(props.footer, { props }); return ( -
      +
        + {items} +
      + ); + }; + + const createFooter = () => { + if (props.footer) { + const footer = ObjectUtils.getJSXElement(props.footer, { props }); + return
      {footer}
      ; + } + + return null; + }; + + React.useImperativeHandle(ref, () => ({ + props, + getElement: () => elementRef.current + })); + + const otherProps = ObjectUtils.findDiffKeys(props, Dock.defaultProps); + const className = classNames( + `p-dock p-component p-dock-${props.position}`, + { + 'p-dock-magnification': props.magnification + }, + props.className + ); + const header = createHeader(); + const list = createList(); + const footer = createFooter(); + + return ( +
      +
      + {header} + {list} {footer}
      - ) - } - - return null; - } - - React.useImperativeHandle(ref, () => ({ - props, - getElement: () => elementRef.current - })); - - const otherProps = ObjectUtils.findDiffKeys(props, Dock.defaultProps); - const className = classNames(`p-dock p-component p-dock-${props.position}`, { - 'p-dock-magnification': props.magnification - }, props.className); - const header = createHeader(); - const list = createList(); - const footer = createFooter(); - - return ( -
      -
      - {header} - {list} - {footer}
      -
      - ) -})); + ); + }) +); Dock.displayName = 'Dock'; Dock.defaultProps = { @@ -137,4 +135,4 @@ Dock.defaultProps = { magnification: true, header: null, footer: null -} +}; diff --git a/components/lib/dock/dock.d.ts b/components/lib/dock/dock.d.ts index c616a39649..db879c5f75 100644 --- a/components/lib/dock/dock.d.ts +++ b/components/lib/dock/dock.d.ts @@ -22,6 +22,6 @@ export interface DockProps extends Omit { +export declare class Dock extends React.Component { public getElement(): HTMLDivElement; } diff --git a/components/lib/dropdown/Dropdown.js b/components/lib/dropdown/Dropdown.js index b625b468b2..8215fd9461 100644 --- a/components/lib/dropdown/Dropdown.js +++ b/components/lib/dropdown/Dropdown.js @@ -6,723 +6,764 @@ import { Tooltip } from '../tooltip/Tooltip'; import { classNames, DomHandler, ObjectUtils, ZIndexUtils } from '../utils/Utils'; import { DropdownPanel } from './DropdownPanel'; -export const Dropdown = React.memo(React.forwardRef((props, ref) => { - const [filterState, setFilterState] = React.useState(''); - const [focusedState, setFocusedState] = React.useState(false); - const [overlayVisibleState, setOverlayVisibleState] = React.useState(false); - const elementRef = React.useRef(null); - const overlayRef = React.useRef(null); - const inputRef = React.useRef(props.inputRef); - const focusInputRef = React.useRef(null); - const searchTimeout = React.useRef(null); - const searchValue = React.useRef(null); - const currentSearchChar = React.useRef(null); - const isLazy = props.virtualScrollerOptions && props.virtualScrollerOptions.lazy; - const hasFilter = ObjectUtils.isNotEmpty(filterState); - const appendTo = props.appendTo || PrimeReact.appendTo; - - const [bindOverlayListener, unbindOverlayListener] = useOverlayListener({ - target: elementRef, overlay: overlayRef, listener: (event, { type, valid }) => { - if (valid) { - (type === 'outside') ? !isClearClicked(event) && hide() : hide(); - } - }, when: overlayVisibleState - }); - - const getVisibleOptions = () => { - if (hasFilter && !isLazy) { - const filterValue = filterState.trim().toLocaleLowerCase(props.filterLocale) - const searchFields = props.filterBy ? props.filterBy.split(',') : [props.optionLabel || 'label']; +export const Dropdown = React.memo( + React.forwardRef((props, ref) => { + const [filterState, setFilterState] = React.useState(''); + const [focusedState, setFocusedState] = React.useState(false); + const [overlayVisibleState, setOverlayVisibleState] = React.useState(false); + const elementRef = React.useRef(null); + const overlayRef = React.useRef(null); + const inputRef = React.useRef(props.inputRef); + const focusInputRef = React.useRef(null); + const searchTimeout = React.useRef(null); + const searchValue = React.useRef(null); + const currentSearchChar = React.useRef(null); + const isLazy = props.virtualScrollerOptions && props.virtualScrollerOptions.lazy; + const hasFilter = ObjectUtils.isNotEmpty(filterState); + const appendTo = props.appendTo || PrimeReact.appendTo; + + const [bindOverlayListener, unbindOverlayListener] = useOverlayListener({ + target: elementRef, + overlay: overlayRef, + listener: (event, { type, valid }) => { + if (valid) { + type === 'outside' ? !isClearClicked(event) && hide() : hide(); + } + }, + when: overlayVisibleState + }); - if (props.optionGroupLabel) { - let filteredGroups = []; - for (let optgroup of props.options) { - let filteredSubOptions = FilterService.filter(getOptionGroupChildren(optgroup), searchFields, filterValue, props.filterMatchMode, props.filterLocale); - if (filteredSubOptions && filteredSubOptions.length) { - filteredGroups.push({ ...optgroup, ...{ items: filteredSubOptions } }); + const getVisibleOptions = () => { + if (hasFilter && !isLazy) { + const filterValue = filterState.trim().toLocaleLowerCase(props.filterLocale); + const searchFields = props.filterBy ? props.filterBy.split(',') : [props.optionLabel || 'label']; + + if (props.optionGroupLabel) { + let filteredGroups = []; + for (let optgroup of props.options) { + let filteredSubOptions = FilterService.filter(getOptionGroupChildren(optgroup), searchFields, filterValue, props.filterMatchMode, props.filterLocale); + if (filteredSubOptions && filteredSubOptions.length) { + filteredGroups.push({ ...optgroup, ...{ items: filteredSubOptions } }); + } } + return filteredGroups; + } else { + return FilterService.filter(props.options, searchFields, filterValue, props.filterMatchMode, props.filterLocale); } - return filteredGroups; - } - else { - return FilterService.filter(props.options, searchFields, filterValue, props.filterMatchMode, props.filterLocale); - } - } - else { - return props.options; - } - } - - const isClearClicked = (event) => { - return DomHandler.hasClass(event.target, 'p-dropdown-clear-icon') || DomHandler.hasClass(event.target, 'p-dropdown-filter-clear-icon'); - } - - const onClick = (event) => { - if (props.disabled) { - return; - } - - if (DomHandler.hasClass(event.target, 'p-dropdown-clear-icon') || event.target.tagName === 'INPUT') { - return; - } - else if (!overlayRef.current || !(overlayRef.current && overlayRef.current.contains(event.target))) { - DomHandler.focus(focusInputRef.current); - overlayVisibleState ? hide() : show(); - } - } - - const onInputFocus = (event) => { - if (props.showOnFocus && !overlayVisibleState) { - show(); - } - - setFocusedState(true); - props.onFocus && props.onFocus(event); - } - - const onInputBlur = (event) => { - setFocusedState(false); - - if (props.onBlur) { - setTimeout(() => { - props.onBlur({ - originalEvent: event.originalEvent, - value: inputRef.current.value, - stopPropagation: () => { }, - preventDefault: () => { }, - target: { - name: props.name, - id: props.id, - value: inputRef.current.value, - } - }); - }, 200); - } - } - - const onPanelClick = (event) => { - OverlayService.emit('overlay-click', { - originalEvent: event, - target: elementRef.current - }); - } - - const onInputKeyDown = (event) => { - switch (event.which) { - //down - case 40: - onDownKey(event); - break; - - //up - case 38: - onUpKey(event); - break; - - //space and enter - case 32: - case 13: - overlayVisibleState ? hide() : show(); - event.preventDefault(); - break; - - //escape and tab - case 27: - case 9: - hide(); - break; - - default: - search(event); - break; - } - } - - const onFilterInputKeyDown = (event) => { - switch (event.which) { - //down - case 40: - onDownKey(event); - break; - - //up - case 38: - onUpKey(event); - break; - - //enter and escape - case 13: - case 27: - hide(); - event.preventDefault(); - break; - - default: - break; - } - } - - const onUpKey = (event) => { - if (visibleOptions) { - const prevOption = findPrevOption(getSelectedOptionIndex()); - - if (prevOption) { - selectItem({ - originalEvent: event, - option: prevOption - }); + } else { + return props.options; } - } + }; + + const isClearClicked = (event) => { + return DomHandler.hasClass(event.target, 'p-dropdown-clear-icon') || DomHandler.hasClass(event.target, 'p-dropdown-filter-clear-icon'); + }; - event.preventDefault(); - } + const onClick = (event) => { + if (props.disabled) { + return; + } + + if (DomHandler.hasClass(event.target, 'p-dropdown-clear-icon') || event.target.tagName === 'INPUT') { + return; + } else if (!overlayRef.current || !(overlayRef.current && overlayRef.current.contains(event.target))) { + DomHandler.focus(focusInputRef.current); + overlayVisibleState ? hide() : show(); + } + }; - const onDownKey = (event) => { - if (visibleOptions) { - if (!overlayVisibleState && event.altKey) { + const onInputFocus = (event) => { + if (props.showOnFocus && !overlayVisibleState) { show(); } - else { - const nextOption = findNextOption(getSelectedOptionIndex()); - if (nextOption) { + setFocusedState(true); + props.onFocus && props.onFocus(event); + }; + + const onInputBlur = (event) => { + setFocusedState(false); + + if (props.onBlur) { + setTimeout(() => { + props.onBlur({ + originalEvent: event.originalEvent, + value: inputRef.current.value, + stopPropagation: () => {}, + preventDefault: () => {}, + target: { + name: props.name, + id: props.id, + value: inputRef.current.value + } + }); + }, 200); + } + }; + + const onPanelClick = (event) => { + OverlayService.emit('overlay-click', { + originalEvent: event, + target: elementRef.current + }); + }; + + const onInputKeyDown = (event) => { + switch (event.which) { + //down + case 40: + onDownKey(event); + break; + + //up + case 38: + onUpKey(event); + break; + + //space and enter + case 32: + case 13: + overlayVisibleState ? hide() : show(); + event.preventDefault(); + break; + + //escape and tab + case 27: + case 9: + hide(); + break; + + default: + search(event); + break; + } + }; + + const onFilterInputKeyDown = (event) => { + switch (event.which) { + //down + case 40: + onDownKey(event); + break; + + //up + case 38: + onUpKey(event); + break; + + //enter and escape + case 13: + case 27: + hide(); + event.preventDefault(); + break; + + default: + break; + } + }; + + const onUpKey = (event) => { + if (visibleOptions) { + const prevOption = findPrevOption(getSelectedOptionIndex()); + + if (prevOption) { selectItem({ originalEvent: event, - option: nextOption + option: prevOption }); } } - } - event.preventDefault(); - } - - const findNextOption = (index) => { - if (props.optionGroupLabel) { - const groupIndex = index === -1 ? 0 : index.group; - const optionIndex = index === -1 ? -1 : index.option; - const option = findNextOptionInList(getOptionGroupChildren(visibleOptions[groupIndex]), optionIndex); + event.preventDefault(); + }; + + const onDownKey = (event) => { + if (visibleOptions) { + if (!overlayVisibleState && event.altKey) { + show(); + } else { + const nextOption = findNextOption(getSelectedOptionIndex()); + + if (nextOption) { + selectItem({ + originalEvent: event, + option: nextOption + }); + } + } + } - if (option) - return option; - else if ((groupIndex + 1) !== visibleOptions.length) - return findNextOption({ group: (groupIndex + 1), option: -1 }); - else - return null; - } + event.preventDefault(); + }; - return findNextOptionInList(visibleOptions, index); - } + const findNextOption = (index) => { + if (props.optionGroupLabel) { + const groupIndex = index === -1 ? 0 : index.group; + const optionIndex = index === -1 ? -1 : index.option; + const option = findNextOptionInList(getOptionGroupChildren(visibleOptions[groupIndex]), optionIndex); - const findNextOptionInList = (list, index) => { - const i = index + 1; - if (i === list.length) { - return null; - } + if (option) return option; + else if (groupIndex + 1 !== visibleOptions.length) return findNextOption({ group: groupIndex + 1, option: -1 }); + else return null; + } - const option = list[i]; - return isOptionDisabled(option) ? findNextOptionInList(i) : option; - } + return findNextOptionInList(visibleOptions, index); + }; - const findPrevOption = (index) => { - if (index === -1) { - return null; - } - - if (props.optionGroupLabel) { - const groupIndex = index.group; - const optionIndex = index.option; - const option = findPrevOptionInList(getOptionGroupChildren(visibleOptions[groupIndex]), optionIndex); - - if (option) - return option; - else if (groupIndex > 0) - return findPrevOption({ group: (groupIndex - 1), option: getOptionGroupChildren(visibleOptions[groupIndex - 1]).length }); - else + const findNextOptionInList = (list, index) => { + const i = index + 1; + if (i === list.length) { return null; - } + } - return findPrevOptionInList(visibleOptions, index); - } + const option = list[i]; + return isOptionDisabled(option) ? findNextOptionInList(i) : option; + }; - const findPrevOptionInList = (list, index) => { - const i = index - 1; - if (i < 0) { - return null; - } - - const option = list[i]; - return isOptionDisabled(option) ? findPrevOption(i) : option; - } - - const search = (event) => { - if (searchTimeout.current) { - clearTimeout(searchTimeout.current); - } - - const char = event.key; - if (char === 'Shift' || char === 'Control' || char === 'Alt') { - return; - } - - if (currentSearchChar.current === char) - searchValue.current = char; - else - searchValue.current = searchValue.current ? searchValue.current + char : char; - - currentSearchChar.current = char; - - if (searchValue.current) { - const searchIndex = getSelectedOptionIndex(); - const newOption = props.optionGroupLabel ? searchOptionInGroup(searchIndex) : searchOption(searchIndex + 1); - if (newOption) { - selectItem({ - originalEvent: event, - option: newOption - }); + const findPrevOption = (index) => { + if (index === -1) { + return null; } - } - searchTimeout.current = setTimeout(() => { - searchValue.current = null; - }, 250); - } + if (props.optionGroupLabel) { + const groupIndex = index.group; + const optionIndex = index.option; + const option = findPrevOptionInList(getOptionGroupChildren(visibleOptions[groupIndex]), optionIndex); - const searchOption = (index) => { - if (searchValue.current) { - return searchOptionInRange(index, visibleOptions.length) || searchOptionInRange(0, index); - } + if (option) return option; + else if (groupIndex > 0) return findPrevOption({ group: groupIndex - 1, option: getOptionGroupChildren(visibleOptions[groupIndex - 1]).length }); + else return null; + } - return null; - } + return findPrevOptionInList(visibleOptions, index); + }; - const searchOptionInRange = (start, end) => { - for (let i = start; i < end; i++) { - const opt = visibleOptions[i]; - if (matchesSearchValue(opt)) { - return opt; + const findPrevOptionInList = (list, index) => { + const i = index - 1; + if (i < 0) { + return null; } - } - return null; - } + const option = list[i]; + return isOptionDisabled(option) ? findPrevOption(i) : option; + }; - const searchOptionInGroup = (index) => { - const searchIndex = index === -1 ? { group: 0, option: -1 } : index; + const search = (event) => { + if (searchTimeout.current) { + clearTimeout(searchTimeout.current); + } - for (let i = searchIndex.group; i < visibleOptions.length; i++) { - let groupOptions = getOptionGroupChildren(visibleOptions[i]); - for (let j = (searchIndex.group === i ? searchIndex.option + 1 : 0); j < groupOptions.length; j++) { - if (matchesSearchValue(groupOptions[j])) { - return groupOptions[j]; - } + const char = event.key; + if (char === 'Shift' || char === 'Control' || char === 'Alt') { + return; } - } - for (let i = 0; i <= searchIndex.group; i++) { - let groupOptions = getOptionGroupChildren(visibleOptions[i]); - for (let j = 0; j < (searchIndex.group === i ? searchIndex.option : groupOptions.length); j++) { - if (matchesSearchValue(groupOptions[j])) { - return groupOptions[j]; + if (currentSearchChar.current === char) searchValue.current = char; + else searchValue.current = searchValue.current ? searchValue.current + char : char; + + currentSearchChar.current = char; + + if (searchValue.current) { + const searchIndex = getSelectedOptionIndex(); + const newOption = props.optionGroupLabel ? searchOptionInGroup(searchIndex) : searchOption(searchIndex + 1); + if (newOption) { + selectItem({ + originalEvent: event, + option: newOption + }); } } - } - - return null; - } - - const matchesSearchValue = (option) => { - let label = getOptionLabel(option); - if (!label) { - return false; - } - label = label.toLocaleLowerCase(props.filterLocale); - return label.startsWith(searchValue.current.toLocaleLowerCase(props.filterLocale)); - } - - const onEditableInputChange = (event) => { - if (props.onChange) { - props.onChange({ - originalEvent: event.originalEvent, - value: event.target.value, - stopPropagation: () => { }, - preventDefault: () => { }, - target: { - name: props.name, - id: props.id, - value: event.target.value, - } - }); - } - } - const onEditableInputFocus = (event) => { - setFocusedState(true); - hide(); - props.onFocus && props.onFocus(event); - } + searchTimeout.current = setTimeout(() => { + searchValue.current = null; + }, 250); + }; - const onOptionClick = (event) => { - const option = event.option; + const searchOption = (index) => { + if (searchValue.current) { + return searchOptionInRange(index, visibleOptions.length) || searchOptionInRange(0, index); + } - if (!option.disabled) { - selectItem(event); - DomHandler.focus(focusInputRef.current); - } + return null; + }; - hide(); - } + const searchOptionInRange = (start, end) => { + for (let i = start; i < end; i++) { + const opt = visibleOptions[i]; + if (matchesSearchValue(opt)) { + return opt; + } + } - const onFilterInputChange = (event) => { - const filter = event.target.value; + return null; + }; - setFilterState(filter); + const searchOptionInGroup = (index) => { + const searchIndex = index === -1 ? { group: 0, option: -1 } : index; - if (props.onFilter) { - props.onFilter({ - originalEvent: event, - filter - }); - } - } - - const onFilterClearIconClick = (callback) => { - resetFilter(callback); - } - - const resetFilter = (callback) => { - setFilterState(''); - props.onFilter && props.onFilter({ filter: '' }); - callback && callback(); - } - - const clear = (event) => { - if (props.onChange) { - props.onChange({ - originalEvent: event, - value: undefined, - stopPropagation: () => { }, - preventDefault: () => { }, - target: { - name: props.name, - id: props.id, - value: undefined + for (let i = searchIndex.group; i < visibleOptions.length; i++) { + let groupOptions = getOptionGroupChildren(visibleOptions[i]); + for (let j = searchIndex.group === i ? searchIndex.option + 1 : 0; j < groupOptions.length; j++) { + if (matchesSearchValue(groupOptions[j])) { + return groupOptions[j]; + } } - }); - } + } + + for (let i = 0; i <= searchIndex.group; i++) { + let groupOptions = getOptionGroupChildren(visibleOptions[i]); + for (let j = 0; j < (searchIndex.group === i ? searchIndex.option : groupOptions.length); j++) { + if (matchesSearchValue(groupOptions[j])) { + return groupOptions[j]; + } + } + } - updateEditableLabel(); - } + return null; + }; - const selectItem = (event) => { - if (selectedOption !== event.option) { - updateEditableLabel(event.option); - const optionValue = getOptionValue(event.option); + const matchesSearchValue = (option) => { + let label = getOptionLabel(option); + if (!label) { + return false; + } + label = label.toLocaleLowerCase(props.filterLocale); + return label.startsWith(searchValue.current.toLocaleLowerCase(props.filterLocale)); + }; + const onEditableInputChange = (event) => { if (props.onChange) { props.onChange({ originalEvent: event.originalEvent, - value: optionValue, - stopPropagation: () => { }, - preventDefault: () => { }, + value: event.target.value, + stopPropagation: () => {}, + preventDefault: () => {}, target: { name: props.name, id: props.id, - value: optionValue + value: event.target.value } }); } - } - } + }; - const getSelectedOptionIndex = (options) => { - options = options || visibleOptions; + const onEditableInputFocus = (event) => { + setFocusedState(true); + hide(); + props.onFocus && props.onFocus(event); + }; - if (props.value != null && options) { - if (props.optionGroupLabel) { - for (let i = 0; i < options.length; i++) { - let selectedOptionIndex = findOptionIndexInList(props.value, getOptionGroupChildren(options[i])); - if (selectedOptionIndex !== -1) { - return { group: i, option: selectedOptionIndex }; + const onOptionClick = (event) => { + const option = event.option; + + if (!option.disabled) { + selectItem(event); + DomHandler.focus(focusInputRef.current); + } + + hide(); + }; + + const onFilterInputChange = (event) => { + const filter = event.target.value; + + setFilterState(filter); + + if (props.onFilter) { + props.onFilter({ + originalEvent: event, + filter + }); + } + }; + + const onFilterClearIconClick = (callback) => { + resetFilter(callback); + }; + + const resetFilter = (callback) => { + setFilterState(''); + props.onFilter && props.onFilter({ filter: '' }); + callback && callback(); + }; + + const clear = (event) => { + if (props.onChange) { + props.onChange({ + originalEvent: event, + value: undefined, + stopPropagation: () => {}, + preventDefault: () => {}, + target: { + name: props.name, + id: props.id, + value: undefined } + }); + } + + updateEditableLabel(); + }; + + const selectItem = (event) => { + if (selectedOption !== event.option) { + updateEditableLabel(event.option); + const optionValue = getOptionValue(event.option); + + if (props.onChange) { + props.onChange({ + originalEvent: event.originalEvent, + value: optionValue, + stopPropagation: () => {}, + preventDefault: () => {}, + target: { + name: props.name, + id: props.id, + value: optionValue + } + }); } } - else { - return findOptionIndexInList(props.value, options); + }; + + const getSelectedOptionIndex = (options) => { + options = options || visibleOptions; + + if (props.value != null && options) { + if (props.optionGroupLabel) { + for (let i = 0; i < options.length; i++) { + let selectedOptionIndex = findOptionIndexInList(props.value, getOptionGroupChildren(options[i])); + if (selectedOptionIndex !== -1) { + return { group: i, option: selectedOptionIndex }; + } + } + } else { + return findOptionIndexInList(props.value, options); + } } - } - return -1; - } + return -1; + }; + + const equalityKey = () => { + return props.optionValue ? null : props.dataKey; + }; + + const findOptionIndexInList = (value, list) => { + const key = equalityKey(); + return list.findIndex((item) => ObjectUtils.equals(value, getOptionValue(item), key)); + }; - const equalityKey = () => { - return props.optionValue ? null : props.dataKey; - } - - const findOptionIndexInList = (value, list) => { - const key = equalityKey(); - return list.findIndex(item => ObjectUtils.equals(value, getOptionValue(item), key)); - } + const isSelected = (option) => { + return ObjectUtils.equals(props.value, getOptionValue(option), equalityKey()); + }; - const isSelected = (option) => { - return ObjectUtils.equals(props.value, getOptionValue(option), equalityKey()); - } + const show = () => { + setOverlayVisibleState(true); + }; - const show = () => { - setOverlayVisibleState(true); - } - - const hide = () => { - setOverlayVisibleState(false); - } - - const onOverlayEnter = (callback) => { - ZIndexUtils.set('overlay', overlayRef.current, PrimeReact.autoZIndex, PrimeReact.zIndex['overlay']); - alignOverlay(); - callback && callback(); - } - - const onOverlayEntered = (callback) => { - callback && callback(); - bindOverlayListener(); - - props.onShow && props.onShow(); - } - - const onOverlayExit = () => { - unbindOverlayListener(); - } - - const onOverlayExited = () => { - if (props.filter && props.resetFilterOnHide) { - resetFilter(); - } - - ZIndexUtils.clear(overlayRef.current); - - props.onHide && props.onHide(); - } - - const alignOverlay = () => { - DomHandler.alignOverlay(overlayRef.current, inputRef.current.parentElement, props.appendTo || PrimeReact.appendTo); - } - - const scrollInView = () => { - const highlightItem = DomHandler.findSingle(overlayRef.current, 'li.p-highlight'); - if (highlightItem && highlightItem.scrollIntoView) { - highlightItem.scrollIntoView({ block: 'nearest', inline: 'nearest' }); - } - } - - const updateEditableLabel = (option) => { - if (inputRef.current) { - inputRef.current.value = (option ? getOptionLabel(option) : props.value || ''); - } - } - - const getOptionLabel = (option) => { - return props.optionLabel ? ObjectUtils.resolveFieldData(option, props.optionLabel) : (option && option['label'] !== undefined ? option['label'] : option); - } - - const getOptionValue = (option) => { - return props.optionValue ? ObjectUtils.resolveFieldData(option, props.optionValue) : (option && option['value'] !== undefined ? option['value'] : option); - } - - const getOptionRenderKey = (option) => { - return props.dataKey ? ObjectUtils.resolveFieldData(option, props.dataKey) : getOptionLabel(option); - } - - const isOptionDisabled = (option) => { - if (props.optionDisabled) { - return ObjectUtils.isFunction(props.optionDisabled) ? props.optionDisabled(option) : ObjectUtils.resolveFieldData(option, props.optionDisabled); - } - - return (option && option['disabled'] !== undefined ? option['disabled'] : false); - } - - const getOptionGroupRenderKey = (optionGroup) => { - return ObjectUtils.resolveFieldData(optionGroup, props.optionGroupLabel); - } - - const getOptionGroupLabel = (optionGroup) => { - return ObjectUtils.resolveFieldData(optionGroup, props.optionGroupLabel); - } - - const getOptionGroupChildren = (optionGroup) => { - return ObjectUtils.resolveFieldData(optionGroup, props.optionGroupChildren); - } - - const updateInputField = () => { - if (props.editable && inputRef.current) { - const label = selectedOption ? getOptionLabel(selectedOption) : null; - const value = label || props.value || ''; - inputRef.current.value = value; - } - } - - const getSelectedOption = () => { - const index = getSelectedOptionIndex(props.options); - - return index !== -1 ? (props.optionGroupLabel ? getOptionGroupChildren(props.options[index.group])[index.option] : props.options[index]) : null; - } - - React.useImperativeHandle(ref, () => ({ - props, - show, - hide, - getElement: () => elementRef.current, - getOverlay: () => overlayRef.current, - getInput: () => inputRef.current, - getFocusInput: () => focusInputRef.current - })); - - React.useEffect(() => { - ObjectUtils.combinedRefs(inputRef, props.inputRef); - }, [inputRef, props.inputRef]); - - useMountEffect(() => { - if (props.autoFocus) { - DomHandler.focus(focusInputRef.current, props.autoFocus); - } - }); - - useUpdateEffect(() => { - if (overlayVisibleState && props.value) { - scrollInView(); - } - }, [overlayVisibleState, props.value]); - - useUpdateEffect(() => { - if (overlayVisibleState && props.filter) { + const hide = () => { + setOverlayVisibleState(false); + }; + + const onOverlayEnter = (callback) => { + ZIndexUtils.set('overlay', overlayRef.current, PrimeReact.autoZIndex, PrimeReact.zIndex['overlay']); alignOverlay(); - } - }, [overlayVisibleState, props.filter]); + callback && callback(); + }; - useUpdateEffect(() => { - if (filterState && (!props.options || props.options.length === 0)) { - setFilterState(''); - } + const onOverlayEntered = (callback) => { + callback && callback(); + bindOverlayListener(); + + props.onShow && props.onShow(); + }; + + const onOverlayExit = () => { + unbindOverlayListener(); + }; + + const onOverlayExited = () => { + if (props.filter && props.resetFilterOnHide) { + resetFilter(); + } - updateInputField(); - if (inputRef.current) { - inputRef.current.selectedIndex = 1; - } - }); + ZIndexUtils.clear(overlayRef.current); - useUnmountEffect(() => { - ZIndexUtils.clear(overlayRef.current); - }); + props.onHide && props.onHide(); + }; - const createHiddenSelect = () => { - let option = { value: '', label: props.placeholder }; + const alignOverlay = () => { + DomHandler.alignOverlay(overlayRef.current, inputRef.current.parentElement, props.appendTo || PrimeReact.appendTo); + }; - if (selectedOption) { - const optionValue = getOptionValue(selectedOption); - option = { - value: typeof optionValue === 'object' ? props.options.findIndex(o => o === optionValue) : optionValue, - label: getOptionLabel(selectedOption) + const scrollInView = () => { + const highlightItem = DomHandler.findSingle(overlayRef.current, 'li.p-highlight'); + if (highlightItem && highlightItem.scrollIntoView) { + highlightItem.scrollIntoView({ block: 'nearest', inline: 'nearest' }); } - } + }; - return ( -
      - -
      - ) - } - - const createKeyboardHelper = () => { - return ( -
      - -
      - ) - } + const updateEditableLabel = (option) => { + if (inputRef.current) { + inputRef.current.value = option ? getOptionLabel(option) : props.value || ''; + } + }; + + const getOptionLabel = (option) => { + return props.optionLabel ? ObjectUtils.resolveFieldData(option, props.optionLabel) : option && option['label'] !== undefined ? option['label'] : option; + }; + + const getOptionValue = (option) => { + return props.optionValue ? ObjectUtils.resolveFieldData(option, props.optionValue) : option && option['value'] !== undefined ? option['value'] : option; + }; + + const getOptionRenderKey = (option) => { + return props.dataKey ? ObjectUtils.resolveFieldData(option, props.dataKey) : getOptionLabel(option); + }; + + const isOptionDisabled = (option) => { + if (props.optionDisabled) { + return ObjectUtils.isFunction(props.optionDisabled) ? props.optionDisabled(option) : ObjectUtils.resolveFieldData(option, props.optionDisabled); + } + + return option && option['disabled'] !== undefined ? option['disabled'] : false; + }; + + const getOptionGroupRenderKey = (optionGroup) => { + return ObjectUtils.resolveFieldData(optionGroup, props.optionGroupLabel); + }; + + const getOptionGroupLabel = (optionGroup) => { + return ObjectUtils.resolveFieldData(optionGroup, props.optionGroupLabel); + }; + + const getOptionGroupChildren = (optionGroup) => { + return ObjectUtils.resolveFieldData(optionGroup, props.optionGroupChildren); + }; + + const updateInputField = () => { + if (props.editable && inputRef.current) { + const label = selectedOption ? getOptionLabel(selectedOption) : null; + const value = label || props.value || ''; + inputRef.current.value = value; + } + }; + + const getSelectedOption = () => { + const index = getSelectedOptionIndex(props.options); + + return index !== -1 ? (props.optionGroupLabel ? getOptionGroupChildren(props.options[index.group])[index.option] : props.options[index]) : null; + }; + + React.useImperativeHandle(ref, () => ({ + props, + show, + hide, + getElement: () => elementRef.current, + getOverlay: () => overlayRef.current, + getInput: () => inputRef.current, + getFocusInput: () => focusInputRef.current + })); + + React.useEffect(() => { + ObjectUtils.combinedRefs(inputRef, props.inputRef); + }, [inputRef, props.inputRef]); + + useMountEffect(() => { + if (props.autoFocus) { + DomHandler.focus(focusInputRef.current, props.autoFocus); + } + }); + + useUpdateEffect(() => { + if (overlayVisibleState && props.value) { + scrollInView(); + } + }, [overlayVisibleState, props.value]); - const createLabel = () => { - const label = ObjectUtils.isNotEmpty(selectedOption) ? getOptionLabel(selectedOption) : null; + useUpdateEffect(() => { + if (overlayVisibleState && props.filter) { + alignOverlay(); + } + }, [overlayVisibleState, props.filter]); + + useUpdateEffect(() => { + if (filterState && (!props.options || props.options.length === 0)) { + setFilterState(''); + } + + updateInputField(); + if (inputRef.current) { + inputRef.current.selectedIndex = 1; + } + }); + + useUnmountEffect(() => { + ZIndexUtils.clear(overlayRef.current); + }); + + const createHiddenSelect = () => { + let option = { value: '', label: props.placeholder }; - if (props.editable) { - const value = label || props.value || ''; + if (selectedOption) { + const optionValue = getOptionValue(selectedOption); + option = { + value: typeof optionValue === 'object' ? props.options.findIndex((o) => o === optionValue) : optionValue, + label: getOptionLabel(selectedOption) + }; + } return ( - - ) - } - else { - const className = classNames('p-dropdown-label p-inputtext', { - 'p-placeholder': label === null && props.placeholder, - 'p-dropdown-label-empty': label === null && !props.placeholder - }); - const content = props.valueTemplate ? ObjectUtils.getJSXElement(props.valueTemplate, selectedOption, props) : (label || props.placeholder || 'empty'); +
      + +
      + ); + }; + + const createKeyboardHelper = () => { + return ( +
      + +
      + ); + }; + + const createLabel = () => { + const label = ObjectUtils.isNotEmpty(selectedOption) ? getOptionLabel(selectedOption) : null; + + if (props.editable) { + const value = label || props.value || ''; + + return ( + + ); + } else { + const className = classNames('p-dropdown-label p-inputtext', { + 'p-placeholder': label === null && props.placeholder, + 'p-dropdown-label-empty': label === null && !props.placeholder + }); + const content = props.valueTemplate ? ObjectUtils.getJSXElement(props.valueTemplate, selectedOption, props) : label || props.placeholder || 'empty'; - return {content} - } - } + return ( + + {content} + + ); + } + }; - const createClearIcon = () => { - if (props.value != null && props.showClear && !props.disabled) { - return - } + const createClearIcon = () => { + if (props.value != null && props.showClear && !props.disabled) { + return ; + } + + return null; + }; - return null; - } + const createDropdownIcon = () => { + const iconClassName = classNames('p-dropdown-trigger-icon p-clickable', props.dropdownIcon); - const createDropdownIcon = () => { - const iconClassName = classNames('p-dropdown-trigger-icon p-clickable', props.dropdownIcon); + return ( +
      + +
      + ); + }; + + const visibleOptions = getVisibleOptions(); + const selectedOption = getSelectedOption(); + + const hasTooltip = ObjectUtils.isNotEmpty(props.tooltip); + const otherProps = ObjectUtils.findDiffKeys(props, Dropdown.defaultProps); + const className = classNames( + 'p-dropdown p-component p-inputwrapper', + { + 'p-disabled': props.disabled, + 'p-focus': focusedState, + 'p-dropdown-clearable': props.showClear && !props.disabled, + 'p-inputwrapper-filled': ObjectUtils.isNotEmpty(props.value), + 'p-inputwrapper-focus': focusedState || overlayVisibleState + }, + props.className + ); + const hiddenSelect = createHiddenSelect(); + const keyboardHelper = createKeyboardHelper(); + const labelElement = createLabel(); + const dropdownIcon = createDropdownIcon(); + const clearIcon = createClearIcon(); return ( -
      - -
      - ) - } - - const visibleOptions = getVisibleOptions(); - const selectedOption = getSelectedOption(); - - const hasTooltip = ObjectUtils.isNotEmpty(props.tooltip); - const otherProps = ObjectUtils.findDiffKeys(props, Dropdown.defaultProps); - const className = classNames('p-dropdown p-component p-inputwrapper', { - 'p-disabled': props.disabled, - 'p-focus': focusedState, - 'p-dropdown-clearable': props.showClear && !props.disabled, - 'p-inputwrapper-filled': ObjectUtils.isNotEmpty(props.value), - 'p-inputwrapper-focus': focusedState || overlayVisibleState - }, props.className); - const hiddenSelect = createHiddenSelect(); - const keyboardHelper = createKeyboardHelper(); - const labelElement = createLabel(); - const dropdownIcon = createDropdownIcon(); - const clearIcon = createClearIcon(); - - return ( - <> -
      - {keyboardHelper} - {hiddenSelect} - {labelElement} - {clearIcon} - {dropdownIcon} - -
      - {hasTooltip && } - - ) -})); + <> +
      + {keyboardHelper} + {hiddenSelect} + {labelElement} + {clearIcon} + {dropdownIcon} + +
      + {hasTooltip && } + + ); + }) +); Dropdown.displayName = 'Dropdown'; Dropdown.defaultProps = { @@ -783,4 +824,4 @@ Dropdown.defaultProps = { onShow: null, onHide: null, onFilter: null -} +}; diff --git a/components/lib/dropdown/DropdownItem.js b/components/lib/dropdown/DropdownItem.js index e67e9700fe..31c4c6761c 100644 --- a/components/lib/dropdown/DropdownItem.js +++ b/components/lib/dropdown/DropdownItem.js @@ -3,29 +3,32 @@ import { Ripple } from '../ripple/Ripple'; import { classNames, ObjectUtils } from '../utils/Utils'; export const DropdownItem = React.memo((props) => { - const onClick = (event) => { if (props.onClick) { props.onClick({ originalEvent: event, option: props.option - }) + }); } - } + }; - const className = classNames('p-dropdown-item', { - 'p-highlight': props.selected, - 'p-disabled': props.disabled, - 'p-dropdown-item-empty': (!props.label || props.label.length === 0) - }, props.option && props.option.className); + const className = classNames( + 'p-dropdown-item', + { + 'p-highlight': props.selected, + 'p-disabled': props.disabled, + 'p-dropdown-item-empty': !props.label || props.label.length === 0 + }, + props.option && props.option.className + ); const content = props.template ? ObjectUtils.getJSXElement(props.template, props.option) : props.label; return ( -
    • +
    • {content}
    • - ) + ); }); DropdownItem.displayName = 'DropdownItem'; diff --git a/components/lib/dropdown/DropdownPanel.js b/components/lib/dropdown/DropdownPanel.js index 154d9a8aab..4250cd9b9a 100644 --- a/components/lib/dropdown/DropdownPanel.js +++ b/components/lib/dropdown/DropdownPanel.js @@ -6,206 +6,210 @@ import { classNames, ObjectUtils, DomHandler } from '../utils/Utils'; import { VirtualScroller } from '../virtualscroller/VirtualScroller'; import { DropdownItem } from './DropdownItem'; -export const DropdownPanel = React.memo(React.forwardRef((props, ref) => { - const virtualScrollerRef = React.useRef(null); - const filterInputRef = React.useRef(null); - const isEmptyFilter = !(props.visibleOptions && props.visibleOptions.length) && props.hasFilter; - const filterOptions = { - filter: (e) => onFilterInputChange(e), - reset: () => props.resetFilter() - }; - - const onEnter = () => { - props.onEnter(() => { - if (virtualScrollerRef.current) { - const selectedIndex = props.getSelectedOptionIndex(); - if (selectedIndex !== -1) { - setTimeout(() => virtualScrollerRef.current.scrollToIndex(selectedIndex), 0); +export const DropdownPanel = React.memo( + React.forwardRef((props, ref) => { + const virtualScrollerRef = React.useRef(null); + const filterInputRef = React.useRef(null); + const isEmptyFilter = !(props.visibleOptions && props.visibleOptions.length) && props.hasFilter; + const filterOptions = { + filter: (e) => onFilterInputChange(e), + reset: () => props.resetFilter() + }; + + const onEnter = () => { + props.onEnter(() => { + if (virtualScrollerRef.current) { + const selectedIndex = props.getSelectedOptionIndex(); + if (selectedIndex !== -1) { + setTimeout(() => virtualScrollerRef.current.scrollToIndex(selectedIndex), 0); + } } - } - }); - } + }); + }; - const onEntered = () => { - props.onEntered(() => { - if (props.filter && props.filterInputAutoFocus) { - DomHandler.focus(filterInputRef.current, false); - } - }); - } - - const onFilterInputChange = (event) => { - virtualScrollerRef.current && virtualScrollerRef.current.scrollToIndex(0); - props.onFilterInputChange && props.onFilterInputChange(event); - } - - const createGroupChildren = (optionGroup, style) => { - const groupChildren = props.getOptionGroupChildren(optionGroup); - return ( - groupChildren.map((option, j) => { + const onEntered = () => { + props.onEntered(() => { + if (props.filter && props.filterInputAutoFocus) { + DomHandler.focus(filterInputRef.current, false); + } + }); + }; + + const onFilterInputChange = (event) => { + virtualScrollerRef.current && virtualScrollerRef.current.scrollToIndex(0); + props.onFilterInputChange && props.onFilterInputChange(event); + }; + + const createGroupChildren = (optionGroup, style) => { + const groupChildren = props.getOptionGroupChildren(optionGroup); + return groupChildren.map((option, j) => { const optionLabel = props.getOptionLabel(option); const optionKey = j + '_' + props.getOptionRenderKey(option); const disabled = props.isOptionDisabled(option); + return ; + }); + }; + + const createEmptyMessage = (emptyMessage, isFilter) => { + const message = ObjectUtils.getJSXElement(emptyMessage, props) || localeOption(isFilter ? 'emptyFilterMessage' : 'emptyMessage'); + + return
    • {message}
    • ; + }; + + const createItem = (option, index, scrollerOptions = {}) => { + const style = { height: scrollerOptions.props ? scrollerOptions.props.itemSize : undefined }; + if (props.optionGroupLabel) { + const groupContent = props.optionGroupTemplate ? ObjectUtils.getJSXElement(props.optionGroupTemplate, option, index) : props.getOptionGroupLabel(option); + const groupChildrenContent = createGroupChildren(option, style); + const key = index + '_' + props.getOptionGroupRenderKey(option); + return ( - - ) - }) - ) - } - - const createEmptyMessage = (emptyMessage, isFilter) => { - const message = ObjectUtils.getJSXElement(emptyMessage, props) || localeOption(isFilter ? 'emptyFilterMessage' : 'emptyMessage'); - - return ( -
    • - {message} -
    • - ) - } - - const createItem = (option, index, scrollerOptions = {}) => { - const style = { height: scrollerOptions.props ? scrollerOptions.props.itemSize : undefined }; - if (props.optionGroupLabel) { - const groupContent = props.optionGroupTemplate ? ObjectUtils.getJSXElement(props.optionGroupTemplate, option, index) : props.getOptionGroupLabel(option); - const groupChildrenContent = createGroupChildren(option, style); - const key = index + '_' + props.getOptionGroupRenderKey(option); + +
    • + {groupContent} +
    • + {groupChildrenContent} +
      + ); + } else { + const optionLabel = props.getOptionLabel(option); + const optionKey = index + '_' + props.getOptionRenderKey(option); + const disabled = props.isOptionDisabled(option); - return ( - -
    • - {groupContent} -
    • - {groupChildrenContent} -
      - ) - } - else { - const optionLabel = props.getOptionLabel(option); - const optionKey = index + '_' + props.getOptionRenderKey(option); - const disabled = props.isOptionDisabled(option); + return ; + } + }; - return ( - - ) - } - } - - const createItems = () => { - if (ObjectUtils.isNotEmpty(props.visibleOptions)) { - return props.visibleOptions.map(createItem); - } - else if (props.hasFilter) { - return createEmptyMessage(props.emptyFilterMessage, true); - } - - return createEmptyMessage(props.emptyMessage); - } - - const createFilterClearIcon = () => { - if (props.showFilterClear && props.filterValue) { - return props.onFilterClearIconClick(() => DomHandler.focus(filterInputRef.current))}> - } - - return null; - } - - const createFilter = () => { - if (props.filter) { - const clearIcon = createFilterClearIcon(); - const containerClassName = classNames('p-dropdown-filter-container', { 'p-dropdown-clearable-filter': !!clearIcon }); - let content = ( -
      - + const createItems = () => { + if (ObjectUtils.isNotEmpty(props.visibleOptions)) { + return props.visibleOptions.map(createItem); + } else if (props.hasFilter) { + return createEmptyMessage(props.emptyFilterMessage, true); + } + + return createEmptyMessage(props.emptyMessage); + }; + + const createFilterClearIcon = () => { + if (props.showFilterClear && props.filterValue) { + return props.onFilterClearIconClick(() => DomHandler.focus(filterInputRef.current))}>; + } + + return null; + }; + + const createFilter = () => { + if (props.filter) { + const clearIcon = createFilterClearIcon(); + const containerClassName = classNames('p-dropdown-filter-container', { 'p-dropdown-clearable-filter': !!clearIcon }); + let content = ( +
      + {clearIcon} - -
      - ) - - if (props.filterTemplate) { - const defaultContentOptions = { - className: containerClassName, - element: content, - filterOptions: filterOptions, - filterInputKeyDown: props.onFilterInputKeyDown, - filterInputChange: onFilterInputChange, - filterIconClassName: 'p-dropdown-filter-icon pi pi-search', - clearIcon: clearIcon, - props, - }; - - content = ObjectUtils.getJSXElement(props.filterTemplate, defaultContentOptions); + +
      + ); + + if (props.filterTemplate) { + const defaultContentOptions = { + className: containerClassName, + element: content, + filterOptions: filterOptions, + filterInputKeyDown: props.onFilterInputKeyDown, + filterInputChange: onFilterInputChange, + filterIconClassName: 'p-dropdown-filter-icon pi pi-search', + clearIcon: clearIcon, + props + }; + + content = ObjectUtils.getJSXElement(props.filterTemplate, defaultContentOptions); + } + + return
      {content}
      ; } - return ( -
      - {content} -
      - ) - } - - return null; - } - - const createContent = () => { - if (props.virtualScrollerOptions) { - const virtualScrollerProps = { - ...props.virtualScrollerOptions, - ...{ - style: { ...props.virtualScrollerOptions.style, ...{ height: props.scrollHeight } }, - className: classNames('p-dropdown-items-wrapper', props.virtualScrollerOptions.className), - items: props.visibleOptions, - autoSize: true, - onLazyLoad: (event) => props.virtualScrollerOptions.onLazyLoad({ ...event, ...{ filter: props.filterValue } }), - itemTemplate: (item, options) => item && createItem(item, options.index, options), - contentTemplate: (options) => { - const className = classNames('p-dropdown-items', options.className); - const content = isEmptyFilter ? createEmptyMessage() : options.children; - - return ( -
        - {content} -
      - ) + return null; + }; + + const createContent = () => { + if (props.virtualScrollerOptions) { + const virtualScrollerProps = { + ...props.virtualScrollerOptions, + ...{ + style: { ...props.virtualScrollerOptions.style, ...{ height: props.scrollHeight } }, + className: classNames('p-dropdown-items-wrapper', props.virtualScrollerOptions.className), + items: props.visibleOptions, + autoSize: true, + onLazyLoad: (event) => props.virtualScrollerOptions.onLazyLoad({ ...event, ...{ filter: props.filterValue } }), + itemTemplate: (item, options) => item && createItem(item, options.index, options), + contentTemplate: (options) => { + const className = classNames('p-dropdown-items', options.className); + const content = isEmptyFilter ? createEmptyMessage() : options.children; + + return ( +
        + {content} +
      + ); + } } - } - }; + }; + + return ; + } else { + const items = createItems(); + + return ( +
      +
        + {items} +
      +
      + ); + } + }; - return - } - else { - const items = createItems(); + const createElement = () => { + const className = classNames('p-dropdown-panel p-component', props.panelClassName); + const filter = createFilter(); + const content = createContent(); return ( -
      -
        - {items} -
      -
      - ) - } - } - - const createElement = () => { - const className = classNames('p-dropdown-panel p-component', props.panelClassName); - const filter = createFilter(); - const content = createContent(); - - return ( - -
      - {filter} - {content} -
      -
      - ) - } - - const element = createElement(); - - return -})); + +
      + {filter} + {content} +
      +
      + ); + }; + + const element = createElement(); + + return ; + }) +); DropdownPanel.displayName = 'DropdownPanel'; diff --git a/components/lib/dropdown/dropdown.d.ts b/components/lib/dropdown/dropdown.d.ts index b463818d56..42f72c1e37 100755 --- a/components/lib/dropdown/dropdown.d.ts +++ b/components/lib/dropdown/dropdown.d.ts @@ -104,7 +104,7 @@ export interface DropdownProps extends Omit { +export declare class Dropdown extends React.Component { public getElement(): HTMLDivElement; public getInput(): HTMLInputElement; public getFocusInput(): HTMLInputElement; diff --git a/components/lib/editor/Editor.js b/components/lib/editor/Editor.js index 7bb0819060..f6cc135e8f 100644 --- a/components/lib/editor/Editor.js +++ b/components/lib/editor/Editor.js @@ -2,192 +2,197 @@ import * as React from 'react'; import { useMountEffect, useUpdateEffect } from '../hooks/Hooks'; import { classNames, DomHandler, ObjectUtils } from '../utils/Utils'; -const QuillJS = function() {try {return Quill;} catch {return null;}}(); - -export const Editor = React.memo(React.forwardRef((props, ref) => { - const elementRef = React.useRef(null); - const contentRef = React.useRef(null); - const toolbarRef = React.useRef(null); - const quill = React.useRef(null); - const isQuillLoaded = React.useRef(false); - - useMountEffect(() => { - if (!isQuillLoaded.current) { - const configuration = { - modules: { - toolbar: props.showHeader ? toolbarRef.current : false, - ...props.modules - }, - placeholder: props.placeholder, - readOnly: props.readOnly, - theme: props.theme, - formats: props.formats - }; - - if (QuillJS) { - // GitHub #3097 loaded by script only - quill.current = new Quill(contentRef.current, configuration); - initQuill(); - - if (quill.current && quill.current.getModule('toolbar')) { - props.onLoad && props.onLoad(quill.current); - } - } - else { - import('quill').then((module) => { - if (module && DomHandler.isExist(contentRef.current)) { - if (module.default) { - // webpack - quill.current = new module.default(contentRef.current, configuration); - } else { - // parceljs - quill.current = new module(contentRef.current, configuration); - } - - initQuill(); - } - }).then(() => { +const QuillJS = (function () { + try { + return Quill; + } catch { + return null; + } +})(); + +export const Editor = React.memo( + React.forwardRef((props, ref) => { + const elementRef = React.useRef(null); + const contentRef = React.useRef(null); + const toolbarRef = React.useRef(null); + const quill = React.useRef(null); + const isQuillLoaded = React.useRef(false); + + useMountEffect(() => { + if (!isQuillLoaded.current) { + const configuration = { + modules: { + toolbar: props.showHeader ? toolbarRef.current : false, + ...props.modules + }, + placeholder: props.placeholder, + readOnly: props.readOnly, + theme: props.theme, + formats: props.formats + }; + + if (QuillJS) { + // GitHub #3097 loaded by script only + quill.current = new Quill(contentRef.current, configuration); + initQuill(); + if (quill.current && quill.current.getModule('toolbar')) { props.onLoad && props.onLoad(quill.current); } - }); - } - - isQuillLoaded.current = true; - } - }); - - const initQuill = () => { - if (props.value) { - quill.current.setContents(quill.current.clipboard.convert(props.value)); - } - - quill.current.on('text-change', (delta, oldContents, source) => { - let firstChild = contentRef.current.children[0]; - let html = firstChild ? firstChild.innerHTML : null; - let text = quill.current.getText(); - if (html === '


      ') { - html = null; - } - - // GitHub #2271 prevent infinite loop on clipboard paste of HTML - if (source === "api") { - const htmlValue = contentRef.current.children[0]; - const editorValue = document.createElement("div"); - editorValue.innerHTML = props.value || ""; - // this is necessary because Quill rearranged style elements - if (DomHandler.isEqualElement(htmlValue, editorValue)) { - return; + } else { + import('quill') + .then((module) => { + if (module && DomHandler.isExist(contentRef.current)) { + if (module.default) { + // webpack + quill.current = new module.default(contentRef.current, configuration); + } else { + // parceljs + quill.current = new module(contentRef.current, configuration); + } + + initQuill(); + } + }) + .then(() => { + if (quill.current && quill.current.getModule('toolbar')) { + props.onLoad && props.onLoad(quill.current); + } + }); } - } - if (props.onTextChange) { - props.onTextChange({ - htmlValue: html, - textValue: text, - delta: delta, - source: source - }); + isQuillLoaded.current = true; } }); - quill.current.on('selection-change', (range, oldRange, source) => { - if (props.onSelectionChange) { - props.onSelectionChange({ - range: range, - oldRange: oldRange, - source: source - }); + const initQuill = () => { + if (props.value) { + quill.current.setContents(quill.current.clipboard.convert(props.value)); } - }); - } - useUpdateEffect(() => { - if (quill.current && !quill.current.hasFocus()) { - props.value ? - quill.current.setContents(quill.current.clipboard.convert(props.value)) : - quill.current.setText(''); - } - }, [props.value]); - - React.useImperativeHandle(ref, () => ({ - props, - getQuill: () => quill.current, - getElement: () => elementRef.current, - getContent: () => contentRef.current, - getToolbar: () => toolbarRef.current - })); - - const createToolbarHeader = () => { - if (props.showHeader === false) { - return null; - } - else if (props.headerTemplate) { - return ( -
      - {props.headerTemplate} -
      - ) - } - else { - return ( -
      - - - - - - - - - - - - - - - - - - - - - - - - - - -
      - ) - } - } + quill.current.on('text-change', (delta, oldContents, source) => { + let firstChild = contentRef.current.children[0]; + let html = firstChild ? firstChild.innerHTML : null; + let text = quill.current.getText(); + if (html === '


      ') { + html = null; + } + + // GitHub #2271 prevent infinite loop on clipboard paste of HTML + if (source === 'api') { + const htmlValue = contentRef.current.children[0]; + const editorValue = document.createElement('div'); + editorValue.innerHTML = props.value || ''; + // this is necessary because Quill rearranged style elements + if (DomHandler.isEqualElement(htmlValue, editorValue)) { + return; + } + } - const otherProps = ObjectUtils.findDiffKeys(props, Editor.defaultProps); - const className = classNames('p-component p-editor-container', props.className); - const header = createToolbarHeader(); - const content =
      + if (props.onTextChange) { + props.onTextChange({ + htmlValue: html, + textValue: text, + delta: delta, + source: source + }); + } + }); + + quill.current.on('selection-change', (range, oldRange, source) => { + if (props.onSelectionChange) { + props.onSelectionChange({ + range: range, + oldRange: oldRange, + source: source + }); + } + }); + }; - return ( -
      - {header} - {content} -
      - ) -})); + useUpdateEffect(() => { + if (quill.current && !quill.current.hasFocus()) { + props.value ? quill.current.setContents(quill.current.clipboard.convert(props.value)) : quill.current.setText(''); + } + }, [props.value]); + + React.useImperativeHandle(ref, () => ({ + props, + getQuill: () => quill.current, + getElement: () => elementRef.current, + getContent: () => contentRef.current, + getToolbar: () => toolbarRef.current + })); + + const createToolbarHeader = () => { + if (props.showHeader === false) { + return null; + } else if (props.headerTemplate) { + return ( +
      + {props.headerTemplate} +
      + ); + } else { + return ( +
      + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + ); + } + }; + + const otherProps = ObjectUtils.findDiffKeys(props, Editor.defaultProps); + const className = classNames('p-component p-editor-container', props.className); + const header = createToolbarHeader(); + const content =
      ; + + return ( +
      + {header} + {content} +
      + ); + }) +); Editor.displayName = 'Editor'; Editor.defaultProps = { @@ -206,4 +211,4 @@ Editor.defaultProps = { onTextChange: null, onSelectionChange: null, onLoad: null -} +}; diff --git a/components/lib/fieldset/Fieldset.js b/components/lib/fieldset/Fieldset.js index 9587de6de0..faaad3283f 100644 --- a/components/lib/fieldset/Fieldset.js +++ b/components/lib/fieldset/Fieldset.js @@ -26,7 +26,7 @@ export const Fieldset = React.forwardRef((props, ref) => { } event.preventDefault(); - } + }; const expand = (event) => { if (!props.onToggle) { @@ -34,7 +34,7 @@ export const Fieldset = React.forwardRef((props, ref) => { } props.onExpand && props.onExpand(event); - } + }; const collapse = (event) => { if (!props.onToggle) { @@ -42,25 +42,23 @@ export const Fieldset = React.forwardRef((props, ref) => { } props.onCollapse && props.onCollapse(event); - } + }; useMountEffect(() => { if (!props.id) { setIdState(UniqueComponentId()); } - }) + }); const createContent = () => { return ( - -
      -
      - {props.children} -
      + +
      +
      {props.children}
      - ) - } + ); + }; const createToggleIcon = () => { if (props.toggleable) { @@ -69,11 +67,11 @@ export const Fieldset = React.forwardRef((props, ref) => { 'pi-minus': !collapsed }); - return + return ; } return null; - } + }; const createLegendContent = () => { if (props.toggleable) { @@ -82,26 +80,30 @@ export const Fieldset = React.forwardRef((props, ref) => { return ( {toggleIcon} - {props.legend} + {props.legend} - ) + ); } - return {props.legend} - } + return ( + + {props.legend} + + ); + }; const createLegend = () => { if (props.legend != null || props.toggleable) { const legendContent = createLegendContent(); return ( - + {legendContent} - ) + ); } - } + }; React.useImperativeHandle(ref, () => ({ props, @@ -110,9 +112,13 @@ export const Fieldset = React.forwardRef((props, ref) => { })); const otherProps = ObjectUtils.findDiffKeys(props, Fieldset.defaultProps); - const className = classNames('p-fieldset p-component', { - 'p-fieldset-toggleable': props.toggleable - }, props.className); + const className = classNames( + 'p-fieldset p-component', + { + 'p-fieldset-toggleable': props.toggleable + }, + props.className + ); const legend = createLegend(); const content = createContent(); @@ -121,7 +127,7 @@ export const Fieldset = React.forwardRef((props, ref) => { {legend} {content} - ) + ); }); Fieldset.displayName = 'Fieldset'; @@ -138,4 +144,4 @@ Fieldset.defaultProps = { onCollapse: null, onToggle: null, onClick: null -} +}; diff --git a/components/lib/fieldset/fieldset.d.ts b/components/lib/fieldset/fieldset.d.ts index 0000b294de..2aee170c97 100644 --- a/components/lib/fieldset/fieldset.d.ts +++ b/components/lib/fieldset/fieldset.d.ts @@ -18,7 +18,7 @@ export interface FieldsetProps extends Omit { +export declare class Fieldset extends React.Component { public getElement(): HTMLFieldSetElement; public getContent(): HTMLDivElement; } diff --git a/components/lib/fileupload/FileUpload.js b/components/lib/fileupload/FileUpload.js index d832c2c8b0..f0960ea960 100644 --- a/components/lib/fileupload/FileUpload.js +++ b/components/lib/fileupload/FileUpload.js @@ -6,500 +6,501 @@ import { ProgressBar } from '../progressbar/ProgressBar'; import { Ripple } from '../ripple/Ripple'; import { classNames, DomHandler, IconUtils, ObjectUtils } from '../utils/Utils'; -export const FileUpload = React.memo(React.forwardRef((props, ref) => { - const [filesState, setFilesState] = React.useState([]); - const [progressState, setProgressState] = React.useState(0); - const [focusedState, setFocusedState] = React.useState(false); - const [uploadingState, setUploadingState] = React.useState(false); - const fileInputRef = React.useRef(null); - const messagesRef = React.useRef(null); - const contentRef = React.useRef(null); - const duplicateIEEvent = React.useRef(false); - const uploadedFileCount = React.useRef(0); - const hasFiles = ObjectUtils.isNotEmpty(filesState); - const disabled = props.disabled || uploadingState; - const chooseButtonLabel = props.chooseLabel || props.chooseOptions.label || localeOption('choose'); - const uploadButtonLabel = props.uploadLabel || props.uploadOptions.label || localeOption('upload'); - const cancelButtonLabel = props.cancelLabel || props.cancelOptions.label || localeOption('cancel'); - const chooseDisabled = disabled || (props.fileLimit && props.fileLimit <= filesState.length + uploadedFileCount); - const uploadDisabled = disabled || !hasFiles; - const cancelDisabled = disabled || !hasFiles; - - const isImage = (file) => { - return /^image\//.test(file.type); - } - - const remove = (event, index) => { - clearInput(); - let currentFiles = [...filesState]; - let removedFile = filesState[index]; - - currentFiles.splice(index, 1); - setFilesState(currentFiles); - - if (props.onRemove) { - props.onRemove({ - originalEvent: event, - file: removedFile - }) - } - } - - const clearInput = () => { - if (fileInputRef.current) { - fileInputRef.current.value = ''; - } - } - - const clearIEInput = () => { - if (fileInputRef.current) { - duplicateIEEvent.current = true; //IE11 fix to prevent onFileChange trigger again - fileInputRef.current.value = ''; - } - } - - const formatSize = (bytes) => { - if (bytes === 0) { - return '0 B'; - } - let k = 1000, - dm = 3, - sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'], - i = Math.floor(Math.log(bytes) / Math.log(k)); - - return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; - } - - const onFileSelect = (event) => { - // give caller a chance to stop the selection - if (props.onBeforeSelect && props.onBeforeSelect(event) === false) { - return; - } - - if (event.type !== 'drop' && isIE11() && duplicateIEEvent.current) { - duplicateIEEvent.current = false; - return; - } - - let currentFiles = []; - if (props.multiple) { - currentFiles = filesState ? [...filesState] : []; - } - - let selectedFiles = event.dataTransfer ? event.dataTransfer.files : event.target.files; - for (let i = 0; i < selectedFiles.length; i++) { - let file = selectedFiles[i]; - - if (!isFileSelected(file) && validate(file)) { - if (isImage(file)) { - file.objectURL = window.URL.createObjectURL(file); - } - currentFiles.push(file); +export const FileUpload = React.memo( + React.forwardRef((props, ref) => { + const [filesState, setFilesState] = React.useState([]); + const [progressState, setProgressState] = React.useState(0); + const [focusedState, setFocusedState] = React.useState(false); + const [uploadingState, setUploadingState] = React.useState(false); + const fileInputRef = React.useRef(null); + const messagesRef = React.useRef(null); + const contentRef = React.useRef(null); + const duplicateIEEvent = React.useRef(false); + const uploadedFileCount = React.useRef(0); + const hasFiles = ObjectUtils.isNotEmpty(filesState); + const disabled = props.disabled || uploadingState; + const chooseButtonLabel = props.chooseLabel || props.chooseOptions.label || localeOption('choose'); + const uploadButtonLabel = props.uploadLabel || props.uploadOptions.label || localeOption('upload'); + const cancelButtonLabel = props.cancelLabel || props.cancelOptions.label || localeOption('cancel'); + const chooseDisabled = disabled || (props.fileLimit && props.fileLimit <= filesState.length + uploadedFileCount); + const uploadDisabled = disabled || !hasFiles; + const cancelDisabled = disabled || !hasFiles; + + const isImage = (file) => { + return /^image\//.test(file.type); + }; + + const remove = (event, index) => { + clearInput(); + let currentFiles = [...filesState]; + let removedFile = filesState[index]; + + currentFiles.splice(index, 1); + setFilesState(currentFiles); + + if (props.onRemove) { + props.onRemove({ + originalEvent: event, + file: removedFile + }); } - } + }; - setFilesState(currentFiles); + const clearInput = () => { + if (fileInputRef.current) { + fileInputRef.current.value = ''; + } + }; - if (ObjectUtils.isNotEmpty(currentFiles) && props.auto) { - upload(currentFiles); - } + const clearIEInput = () => { + if (fileInputRef.current) { + duplicateIEEvent.current = true; //IE11 fix to prevent onFileChange trigger again + fileInputRef.current.value = ''; + } + }; - if (props.onSelect) { - props.onSelect({ originalEvent: event, files: selectedFiles }); - } + const formatSize = (bytes) => { + if (bytes === 0) { + return '0 B'; + } + let k = 1000, + dm = 3, + sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'], + i = Math.floor(Math.log(bytes) / Math.log(k)); + + return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; + }; + + const onFileSelect = (event) => { + // give caller a chance to stop the selection + if (props.onBeforeSelect && props.onBeforeSelect(event) === false) { + return; + } - if (event.type !== 'drop' && isIE11()) { - clearIEInput(); - } - else { - clearInput(); - } - - if (props.mode === 'basic' && currentFiles.length > 0) { - fileInputRef.current.style.display = 'none'; - } - } - - const isFileSelected = (file) => { - return filesState.some((f) => (f.name + f.type + f.size) === (file.name + file.type + file.size)); - } - - const isIE11 = () => { - return !!window['MSInputMethodContext'] && !!document['documentMode']; - } - - const validate = (file) => { - if (props.maxFileSize && file.size > props.maxFileSize) { - const message = { - severity: 'error', - summary: props.invalidFileSizeMessageSummary.replace('{0}', file.name), - detail: props.invalidFileSizeMessageDetail.replace('{0}', formatSize(props.maxFileSize)), - sticky: true - }; - - if (props.mode === 'advanced') { - messagesRef.current.show(message); + if (event.type !== 'drop' && isIE11() && duplicateIEEvent.current) { + duplicateIEEvent.current = false; + return; } - props.onValidationFail && props.onValidationFail(file); + let currentFiles = []; + if (props.multiple) { + currentFiles = filesState ? [...filesState] : []; + } - return false; - } + let selectedFiles = event.dataTransfer ? event.dataTransfer.files : event.target.files; + for (let i = 0; i < selectedFiles.length; i++) { + let file = selectedFiles[i]; - return true; - } + if (!isFileSelected(file) && validate(file)) { + if (isImage(file)) { + file.objectURL = window.URL.createObjectURL(file); + } + currentFiles.push(file); + } + } - const upload = (files) => { - files = files || filesState; - if (files && files.nativeEvent) { - files = filesState; - } + setFilesState(currentFiles); - if (props.customUpload) { - if (props.fileLimit) { - uploadedFileCount += files.length; + if (ObjectUtils.isNotEmpty(currentFiles) && props.auto) { + upload(currentFiles); } - if (props.uploadHandler) { - props.uploadHandler({ - files, - options: { - clear, - props - } - }) + if (props.onSelect) { + props.onSelect({ originalEvent: event, files: selectedFiles }); } - } - else { - setUploadingState(true); - let xhr = new XMLHttpRequest(); - let formData = new FormData(); - - if (props.onBeforeUpload) { - props.onBeforeUpload({ - 'xhr': xhr, - 'formData': formData - }); + + if (event.type !== 'drop' && isIE11()) { + clearIEInput(); + } else { + clearInput(); } - for (let file of files) { - formData.append(props.name, file, file.name); + if (props.mode === 'basic' && currentFiles.length > 0) { + fileInputRef.current.style.display = 'none'; } + }; + + const isFileSelected = (file) => { + return filesState.some((f) => f.name + f.type + f.size === file.name + file.type + file.size); + }; + + const isIE11 = () => { + return !!window['MSInputMethodContext'] && !!document['documentMode']; + }; + + const validate = (file) => { + if (props.maxFileSize && file.size > props.maxFileSize) { + const message = { + severity: 'error', + summary: props.invalidFileSizeMessageSummary.replace('{0}', file.name), + detail: props.invalidFileSizeMessageDetail.replace('{0}', formatSize(props.maxFileSize)), + sticky: true + }; + + if (props.mode === 'advanced') { + messagesRef.current.show(message); + } - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - const progress = Math.round((event.loaded * 100) / event.total); - setProgressState(progress); + props.onValidationFail && props.onValidationFail(file); - if (props.onProgress) { - props.onProgress({ - originalEvent: event, - progress - }); - } - } - }); + return false; + } + + return true; + }; - xhr.onreadystatechange = () => { - if (xhr.readyState === 4) { - setProgressState(0); - setUploadingState(false); + const upload = (files) => { + files = files || filesState; + if (files && files.nativeEvent) { + files = filesState; + } + + if (props.customUpload) { + if (props.fileLimit) { + uploadedFileCount += files.length; + } - if (xhr.status >= 200 && xhr.status < 300) { - if (props.fileLimit) { - uploadedFileCount += files.length; + if (props.uploadHandler) { + props.uploadHandler({ + files, + options: { + clear, + props } + }); + } + } else { + setUploadingState(true); + let xhr = new XMLHttpRequest(); + let formData = new FormData(); + + if (props.onBeforeUpload) { + props.onBeforeUpload({ + xhr: xhr, + formData: formData + }); + } + + for (let file of files) { + formData.append(props.name, file, file.name); + } + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + const progress = Math.round((event.loaded * 100) / event.total); + setProgressState(progress); - if (props.onUpload) { - props.onUpload({ - xhr, - files + if (props.onProgress) { + props.onProgress({ + originalEvent: event, + progress }); } } - else { - if (props.onError) { - props.onError({ - xhr, - files - }); + }); + + xhr.onreadystatechange = () => { + if (xhr.readyState === 4) { + setProgressState(0); + setUploadingState(false); + + if (xhr.status >= 200 && xhr.status < 300) { + if (props.fileLimit) { + uploadedFileCount += files.length; + } + + if (props.onUpload) { + props.onUpload({ + xhr, + files + }); + } + } else { + if (props.onError) { + props.onError({ + xhr, + files + }); + } } + + clear(); } + }; + + xhr.open('POST', props.url, true); - clear(); + if (props.onBeforeSend) { + props.onBeforeSend({ + xhr: xhr, + formData: formData + }); } - }; - xhr.open('POST', props.url, true); + xhr.withCredentials = props.withCredentials; + xhr.send(formData); + } + }; - if (props.onBeforeSend) { - props.onBeforeSend({ - 'xhr': xhr, - 'formData': formData - }); + const clear = () => { + setFilesState([]); + setUploadingState(false); + props.onClear && props.onClear(); + clearInput(); + }; + + const choose = () => { + fileInputRef.current.click(); + }; + + const onFocus = () => { + setFocusedState(true); + }; + + const onBlur = () => { + setFocusedState(false); + }; + + const onKeyDown = (event) => { + if (event.which === 13) { + // enter + choose(); } + }; - xhr.withCredentials = props.withCredentials; - xhr.send(formData); - } - } - - const clear = () => { - setFilesState([]); - setUploadingState(false); - props.onClear && props.onClear(); - clearInput(); - } - - const choose = () => { - fileInputRef.current.click(); - } - - const onFocus = () => { - setFocusedState(true); - } - - const onBlur = () => { - setFocusedState(false); - } - - const onKeyDown = (event) => { - if (event.which === 13) { // enter - choose(); - } - } - - const onDragEnter = (event) => { - if (!disabled) { - event.dataTransfer.dropEffect = 'copy'; - event.stopPropagation(); - event.preventDefault(); - } - } + const onDragEnter = (event) => { + if (!disabled) { + event.dataTransfer.dropEffect = 'copy'; + event.stopPropagation(); + event.preventDefault(); + } + }; + + const onDragOver = (event) => { + if (!disabled) { + event.dataTransfer.dropEffect = 'copy'; + DomHandler.addClass(contentRef.current, 'p-fileupload-highlight'); + event.stopPropagation(); + event.preventDefault(); + } + }; + + const onDragLeave = (event) => { + if (!disabled) { + event.dataTransfer.dropEffect = 'copy'; + DomHandler.removeClass(contentRef.current, 'p-fileupload-highlight'); + } + }; + + const onDrop = (event) => { + if (props.disabled) { + return; + } - const onDragOver = (event) => { - if (!disabled) { - event.dataTransfer.dropEffect = 'copy'; - DomHandler.addClass(contentRef.current, 'p-fileupload-highlight'); + DomHandler.removeClass(contentRef.current, 'p-fileupload-highlight'); event.stopPropagation(); event.preventDefault(); - } - } - const onDragLeave = (event) => { - if (!disabled) { - event.dataTransfer.dropEffect = 'copy'; - DomHandler.removeClass(contentRef.current, 'p-fileupload-highlight'); - } - } - - const onDrop = (event) => { - if (props.disabled) { - return; - } - - DomHandler.removeClass(contentRef.current, 'p-fileupload-highlight'); - event.stopPropagation(); - event.preventDefault(); - - // give caller a chance to stop the drop - if (props.onBeforeDrop && props.onBeforeDrop(event) === false) { - return; - } - - const files = event.dataTransfer ? event.dataTransfer.files : event.target.files; - const allowDrop = props.multiple || (ObjectUtils.isEmpty(filesState) && files && files.length === 1); - - allowDrop && onFileSelect(event); - } - - const onSimpleUploaderClick = () => { - !disabled && hasFiles ? upload() : fileInputRef.current.click(); - } - - React.useImperativeHandle(ref, () => ({ - props, - upload, - clear, - formatSize, - onFileSelect, - getInput: () => fileInputRef.current, - getContent: () => contentRef.current - })); - - const createChooseButton = () => { - const { className, style, icon: _icon, iconOnly } = props.chooseOptions; - const chooseClassName = classNames('p-button p-fileupload-choose p-component', { - 'p-disabled': disabled, - 'p-focus': focusedState, - 'p-button-icon-only': iconOnly - }, className); - const labelClassName = 'p-button-label p-clickable'; - const label = iconOnly ? : {chooseButtonLabel}; - const input = ; - const icon = IconUtils.getJSXIcon(_icon || 'pi pi-fw pi-plus', { className: 'p-button-icon p-button-icon-left p-clickable' }, { props }) - return ( - - {input} - {icon} - {label} - - - ) - } - - const createFile = (file, index) => { - const key = file.name + file.type + file.size; - const preview = isImage(file) ?
      {file.name}
      : null; - const fileName =
      {file.name}
      ; - const size =
      {formatSize(file.size)}
      ; - const removeButton =
      - let content = ( - <> - {preview} - {fileName} - {size} - {removeButton} - - ); - - if (props.itemTemplate) { - const defaultContentOptions = { - onRemove: (event) => remove(event, index), - previewElement: preview, - fileNameElement: fileName, - sizeElement: size, - removeElement: removeButton, - formatSize: formatSize(file.size), - element: content, - props - }; - - content = ObjectUtils.getJSXElement(props.itemTemplate, file, defaultContentOptions); - } - - return ( -
      - {content} -
      - ) - } - - const createFiles = () => { - const content = filesState.map(createFile); - - return ( -
      - {content} -
      - ) - } - - const createEmptyContent = () => { - return props.emptyTemplate && !hasFiles ? ObjectUtils.getJSXElement(props.emptyTemplate, props) : null; - } - - const createProgressBarContent = () => { - if (props.progressBarTemplate) { - return ObjectUtils.getJSXElement(props.progressBarTemplate, props); - } - - return - } - - const createAdvanced = () => { - const otherProps = ObjectUtils.findDiffKeys(props, FileUpload.defaultProps); - const className = classNames('p-fileupload p-fileupload-advanced p-component', props.className); - const headerClassName = classNames('p-fileupload-buttonbar', props.headerClassName); - const contentClassName = classNames('p-fileupload-content', props.contentClassName); - const chooseButton = createChooseButton(); - const emptyContent = createEmptyContent(); - let uploadButton, cancelButton, filesList, progressBar; - - if (!props.auto) { - const uploadOptions = props.uploadOptions; - const cancelOptions = props.cancelOptions; - const uploadLabel = !uploadOptions.iconOnly ? uploadButtonLabel : ''; - const cancelLabel = !cancelOptions.iconOnly ? cancelButtonLabel : ''; - - uploadButton =
      + ); + let content = ( + <> + {preview} + {fileName} + {size} + {removeButton} + + ); + + if (props.itemTemplate) { + const defaultContentOptions = { + onRemove: (event) => remove(event, index), + previewElement: preview, + fileNameElement: fileName, + sizeElement: size, + removeElement: removeButton, + formatSize: formatSize(file.size), + element: content, + props + }; + + content = ObjectUtils.getJSXElement(props.itemTemplate, file, defaultContentOptions); + } + + return ( +
      + {content} +
      + ); + }; + + const createFiles = () => { + const content = filesState.map(createFile); + + return
      {content}
      ; + }; + + const createEmptyContent = () => { + return props.emptyTemplate && !hasFiles ? ObjectUtils.getJSXElement(props.emptyTemplate, props) : null; + }; + + const createProgressBarContent = () => { + if (props.progressBarTemplate) { + return ObjectUtils.getJSXElement(props.progressBarTemplate, props); + } + + return ; + }; + + const createAdvanced = () => { + const otherProps = ObjectUtils.findDiffKeys(props, FileUpload.defaultProps); + const className = classNames('p-fileupload p-fileupload-advanced p-component', props.className); + const headerClassName = classNames('p-fileupload-buttonbar', props.headerClassName); + const contentClassName = classNames('p-fileupload-content', props.contentClassName); + const chooseButton = createChooseButton(); + const emptyContent = createEmptyContent(); + let uploadButton, cancelButton, filesList, progressBar; + + if (!props.auto) { + const uploadOptions = props.uploadOptions; + const cancelOptions = props.cancelOptions; + const uploadLabel = !uploadOptions.iconOnly ? uploadButtonLabel : ''; + const cancelLabel = !cancelOptions.iconOnly ? cancelButtonLabel : ''; + + uploadButton = +export const Galleria = React.memo( + React.forwardRef((props, ref) => { + const [visibleState, setVisibleState] = React.useState(false); + const [numVisibleState, setNumVisibleState] = React.useState(props.numVisible); + const [slideShowActiveState, setSlideShowActiveState] = React.useState(false); + const [activeIndexState, setActiveIndexState] = React.useState(props.activeIndex); + const elementRef = React.useRef(null); + const previewContentRef = React.useRef(null); + const maskRef = React.useRef(null); + const activeItemIndex = props.onItemChange ? props.activeIndex : activeIndexState; + const isVertical = props.thumbnailsPosition === 'left' || props.thumbnailsPosition === 'right'; + + useInterval( + () => { + onActiveItemChange({ index: props.circular && props.value.length - 1 === activeItemIndex ? 0 : activeItemIndex + 1 }); + }, + props.transitionInterval, + slideShowActiveState ); - const header = createHeader(); - const footer = createFooter(); - const element = ( -
      - {closeIcon} - {header} -
      - - - { - props.showThumbnails && - } -
      - {footer} -
      - ) - - return element; - } - - const createGalleria = () => { - const element = createElement(); - - if (props.fullScreen) { - const maskClassName = classNames('p-galleria-mask', { - 'p-galleria-visible': visibleState - }); - - const galleriaWrapper = ( -
      - - {element} - -
      + const onActiveItemChange = (event) => { + if (props.onItemChange) { + props.onItemChange(event); + } else { + setActiveIndexState(event.index); + } + }; + + const show = () => { + setVisibleState(true); + }; + + const hide = () => { + setVisibleState(false); + }; + + const onEnter = () => { + DomHandler.addClass(document.body, 'p-overflow-hidden'); + }; + + const onEntering = () => { + ZIndexUtils.set('modal', maskRef.current, PrimeReact.autoZIndex, props.baseZIndex || PrimeReact.zIndex['modal']); + DomHandler.addMultipleClasses(maskRef.current, 'p-component-overlay p-component-overlay-enter'); + }; + + const onEntered = () => { + props.onShow && props.onShow(); + }; + + const onExit = () => { + DomHandler.removeClass(document.body, 'p-overflow-hidden'); + DomHandler.addClass(maskRef.current, 'p-component-overlay-leave'); + }; + + const onExited = () => { + ZIndexUtils.clear(maskRef.current); + + props.onHide && props.onHide(); + }; + + const isAutoPlayActive = () => { + return slideShowActiveState; + }; + + const startSlideShow = () => { + setSlideShowActiveState(true); + }; + + const stopSlideShow = () => { + setSlideShowActiveState(false); + }; + + const getPositionClassName = (preClassName, position) => { + const positions = ['top', 'left', 'bottom', 'right']; + const pos = positions.find((item) => item === position); + + return pos ? `${preClassName}-${pos}` : ''; + }; + + React.useEffect(() => { + if (props.value && props.value.length < numVisibleState) { + setNumVisibleState(props.value.length); + } + }, [props.value, numVisibleState]); + + React.useEffect(() => { + setNumVisibleState(props.numVisible); + }, [props.numVisible]); + + useUnmountEffect(() => { + if (slideShowActiveState) { + stopSlideShow(); + } + + ZIndexUtils.clear(maskRef.current); + }); + + React.useImperativeHandle(ref, () => ({ + props, + show, + hide, + isAutoPlayActive, + startSlideShow, + stopSlideShow, + getElement: () => elementRef.current, + getPreviewContent: () => previewContentRef.current + })); + + const createHeader = () => { + if (props.header) { + return
      {props.header}
      ; + } + + return null; + }; + + const createFooter = () => { + if (props.footer) { + return
      {props.footer}
      ; + } + + return null; + }; + + const createElement = () => { + const otherProps = ObjectUtils.findDiffKeys(props, Galleria.defaultProps); + const thumbnailsPosClassName = props.showThumbnails && getPositionClassName('p-galleria-thumbnails', props.thumbnailsPosition); + const indicatorPosClassName = props.showIndicators && getPositionClassName('p-galleria-indicators', props.indicatorsPosition); + const galleriaClassName = classNames( + 'p-galleria p-component', + props.className, + { + 'p-galleria-fullscreen': props.fullScreen, + 'p-galleria-indicator-onitem': props.showIndicatorsOnItem, + 'p-galleria-item-nav-onhover': props.showItemNavigatorsOnHover && !props.fullScreen + }, + thumbnailsPosClassName, + indicatorPosClassName ); - return - } + const closeIcon = props.fullScreen && ( + + ); - return element; - } + const header = createHeader(); + const footer = createFooter(); + const element = ( +
      + {closeIcon} + {header} +
      + + + {props.showThumbnails && ( + + )} +
      + {footer} +
      + ); - return ObjectUtils.isNotEmpty(props.value) && createGalleria(); -})); + return element; + }; + + const createGalleria = () => { + const element = createElement(); + + if (props.fullScreen) { + const maskClassName = classNames('p-galleria-mask', { + 'p-galleria-visible': visibleState + }); + + const galleriaWrapper = ( +
      + + {element} + +
      + ); + + return ; + } + + return element; + }; + + return ObjectUtils.isNotEmpty(props.value) && createGalleria(); + }) +); Galleria.displayName = 'Galleria'; Galleria.defaultProps = { @@ -231,12 +268,12 @@ Galleria.defaultProps = { autoPlay: false, transitionInterval: 4000, showThumbnails: true, - thumbnailsPosition: "bottom", - verticalThumbnailViewPortHeight: "300px", + thumbnailsPosition: 'bottom', + verticalThumbnailViewPortHeight: '300px', showIndicators: false, showIndicatorsOnItem: false, - indicatorsPosition: "bottom", + indicatorsPosition: 'bottom', baseZIndex: 0, transitionOptions: null, onItemChange: null -} +}; diff --git a/components/lib/galleria/GalleriaItem.js b/components/lib/galleria/GalleriaItem.js index 9881e8e48d..82123452f5 100644 --- a/components/lib/galleria/GalleriaItem.js +++ b/components/lib/galleria/GalleriaItem.js @@ -3,194 +3,184 @@ import { useMountEffect } from '../hooks/Hooks'; import { Ripple } from '../ripple/Ripple'; import { classNames } from '../utils/Utils'; -export const GalleriaItem = React.memo(React.forwardRef((props, ref) => { +export const GalleriaItem = React.memo( + React.forwardRef((props, ref) => { + const next = () => { + const nextItemIndex = props.activeItemIndex + 1; - const next = () => { - const nextItemIndex = props.activeItemIndex + 1; + props.onActiveItemChange({ + index: props.circular && props.value.length - 1 === props.activeItemIndex ? 0 : nextItemIndex + }); + }; - props.onActiveItemChange({ - index: props.circular && (props.value.length - 1) === props.activeItemIndex ? 0 : nextItemIndex - }); - } + const prev = () => { + const prevItemIndex = props.activeItemIndex !== 0 ? props.activeItemIndex - 1 : 0; - const prev = () => { - const prevItemIndex = props.activeItemIndex !== 0 ? props.activeItemIndex - 1 : 0; + props.onActiveItemChange({ + index: props.circular && props.activeItemIndex === 0 ? props.value.length - 1 : prevItemIndex + }); + }; - props.onActiveItemChange({ - index: props.circular && props.activeItemIndex === 0 ? props.value.length - 1 : prevItemIndex - }); - } - - const stopSlideShow = () => { - if (props.slideShowActive && props.stopSlideShow) { - props.stopSlideShow(); - } - } - - const navBackward = (e) => { - stopSlideShow(); - prev(); - - if (e && e.cancelable) { - e.preventDefault(); - } - } - - const navForward = (e) => { - stopSlideShow(); - next(); - - if (e && e.cancelable) { - e.preventDefault(); - } - } - - const onIndicatorClick = (index) => { - stopSlideShow(); - props.onActiveItemChange({ - index - }); - } + const stopSlideShow = () => { + if (props.slideShowActive && props.stopSlideShow) { + props.stopSlideShow(); + } + }; - const onIndicatorMouseEnter = (index) => { - if (props.changeItemOnIndicatorHover) { + const navBackward = (e) => { stopSlideShow(); + prev(); - props.onActiveItemChange({ - index - }); - } - } + if (e && e.cancelable) { + e.preventDefault(); + } + }; - const onIndicatorKeyDown = (event, index) => { - if (event.which === 13) { + const navForward = (e) => { stopSlideShow(); + next(); + if (e && e.cancelable) { + e.preventDefault(); + } + }; + + const onIndicatorClick = (index) => { + stopSlideShow(); props.onActiveItemChange({ index }); - } - } - - useMountEffect(() => { - if (props.autoPlay) { - props.startSlideShow(); - } - }); - - const createBackwardNavigator = () => { - if (props.showItemNavigators) { - const isDisabled = !props.circular && props.activeItemIndex === 0; - const buttonClassName = classNames('p-galleria-item-prev p-galleria-item-nav p-link', { - 'p-disabled': isDisabled - }); + }; - return ( - - ) - } - - return null; - } - - const createForwardNavigator = () => { - if (props.showItemNavigators) { - const isDisabled = !props.circular && props.activeItemIndex === (props.value.length - 1); - const buttonClassName = classNames('p-galleria-item-next p-galleria-item-nav p-link', { - 'p-disabled': isDisabled - }); + const onIndicatorMouseEnter = (index) => { + if (props.changeItemOnIndicatorHover) { + stopSlideShow(); - return ( - - ) - } + props.onActiveItemChange({ + index + }); + } + }; - return null; - } + const onIndicatorKeyDown = (event, index) => { + if (event.which === 13) { + stopSlideShow(); - const createCaption = () => { - if (props.caption) { - const content = props.caption(props.value[props.activeItemIndex]); + props.onActiveItemChange({ + index + }); + } + }; - return ( -
      - {content} -
      - ) - } + useMountEffect(() => { + if (props.autoPlay) { + props.startSlideShow(); + } + }); - return null; - } + const createBackwardNavigator = () => { + if (props.showItemNavigators) { + const isDisabled = !props.circular && props.activeItemIndex === 0; + const buttonClassName = classNames('p-galleria-item-prev p-galleria-item-nav p-link', { + 'p-disabled': isDisabled + }); + + return ( + + ); + } - const createIndicator = (index) => { - const key = 'p-galleria-indicator-' + index; - const isActive = props.activeItemIndex === index; - const className = classNames('p-galleria-indicator', { - 'p-highlight': isActive - }); - let indicator = props.indicator && props.indicator(index); + return null; + }; + + const createForwardNavigator = () => { + if (props.showItemNavigators) { + const isDisabled = !props.circular && props.activeItemIndex === props.value.length - 1; + const buttonClassName = classNames('p-galleria-item-next p-galleria-item-nav p-link', { + 'p-disabled': isDisabled + }); + + return ( + + ); + } - if (!indicator) { - indicator = ( - - ); - } + return null; + }; - return ( -
    • onIndicatorClick(index)} onMouseEnter={() => onIndicatorMouseEnter(index)} onKeyDown={(e) => onIndicatorKeyDown(e, index)}> - {indicator} -
    • - ) - } - - const createIndicators = () => { - if (props.showIndicators) { - const className = classNames('p-galleria-indicators p-reset', props.indicatorsContentClassName); - let indicators = []; - - for (let i = 0; i < props.value.length; i++) { - indicators.push(createIndicator(i)); + const createCaption = () => { + if (props.caption) { + const content = props.caption(props.value[props.activeItemIndex]); + + return
      {content}
      ; + } + + return null; + }; + + const createIndicator = (index) => { + const key = 'p-galleria-indicator-' + index; + const isActive = props.activeItemIndex === index; + const className = classNames('p-galleria-indicator', { + 'p-highlight': isActive + }); + let indicator = props.indicator && props.indicator(index); + + if (!indicator) { + indicator = ( + + ); } return ( -
        - {indicators} -
      - ) - } - - return null; - } - - const content = props.itemTemplate && props.itemTemplate(props.value[props.activeItemIndex]); - const backwardNavigator = createBackwardNavigator(); - const forwardNavigator = createForwardNavigator(); - const caption = createCaption(); - const indicators = createIndicators(); - - return ( -
      -
      - {backwardNavigator} -
      - {content} +
    • onIndicatorClick(index)} onMouseEnter={() => onIndicatorMouseEnter(index)} onKeyDown={(e) => onIndicatorKeyDown(e, index)}> + {indicator} +
    • + ); + }; + + const createIndicators = () => { + if (props.showIndicators) { + const className = classNames('p-galleria-indicators p-reset', props.indicatorsContentClassName); + let indicators = []; + + for (let i = 0; i < props.value.length; i++) { + indicators.push(createIndicator(i)); + } + + return
        {indicators}
      ; + } + + return null; + }; + + const content = props.itemTemplate && props.itemTemplate(props.value[props.activeItemIndex]); + const backwardNavigator = createBackwardNavigator(); + const forwardNavigator = createForwardNavigator(); + const caption = createCaption(); + const indicators = createIndicators(); + + return ( +
      +
      + {backwardNavigator} +
      {content}
      + {forwardNavigator} + {caption}
      - {forwardNavigator} - {caption} -
      - {indicators} -
      - ) -})); + {indicators} +
      + ); + }) +); GalleriaItem.displayName = 'GalleriaItem'; diff --git a/components/lib/galleria/GalleriaThumbnails.js b/components/lib/galleria/GalleriaThumbnails.js index 45aca8da08..b1458927fc 100644 --- a/components/lib/galleria/GalleriaThumbnails.js +++ b/components/lib/galleria/GalleriaThumbnails.js @@ -5,13 +5,12 @@ import { Ripple } from '../ripple/Ripple'; import { classNames, DomHandler, ObjectUtils, UniqueComponentId } from '../utils/Utils'; const GalleriaThumbnailItem = React.memo((props) => { - const onItemClick = (event) => { props.onItemClick({ originalEvent: event, index: props.index }); - } + }; const onItemKeyDown = (event) => { if (event.which === 13) { @@ -20,372 +19,368 @@ const GalleriaThumbnailItem = React.memo((props) => { index: props.index }); } - } + }; const tabIndex = props.active ? 0 : null; const content = props.template && props.template(props.item); - const className = classNames('p-galleria-thumbnail-item', { - 'p-galleria-thumbnail-item-current': props.current, - 'p-galleria-thumbnail-item-active': props.active, - 'p-galleria-thumbnail-item-start': props.start, - 'p-galleria-thumbnail-item-end': props.end - }, props.className); + const className = classNames( + 'p-galleria-thumbnail-item', + { + 'p-galleria-thumbnail-item-current': props.current, + 'p-galleria-thumbnail-item-active': props.active, + 'p-galleria-thumbnail-item-start': props.start, + 'p-galleria-thumbnail-item-end': props.end + }, + props.className + ); return (
      -
      +
      {content}
      - ) + ); }); -export const GalleriaThumbnails = React.memo(React.forwardRef((props, ref) => { - const [numVisibleState, setNumVisibleState] = React.useState(props.numVisible); - const [totalShiftedItemsState, setTotalShiftedItemsState] = React.useState(0); - const itemsContainerRef = React.useRef(null); - const startPos = React.useRef(null); - const attributeSelector = React.useRef(''); - const thumbnailsStyle = React.useRef(null); - const responsiveOptions = React.useRef(null); - const prevNumVisible = usePrevious(numVisibleState); - const prevActiveItemIndex = usePrevious(props.activeItemIndex); - - const [bindWindowResizeListener,] = useResizeListener({ - listener: () => { - calculatePosition(); - }, when: props.responsiveOptions - }); - - const step = (dir) => { - let totalShiftedItems = totalShiftedItemsState + dir; +export const GalleriaThumbnails = React.memo( + React.forwardRef((props, ref) => { + const [numVisibleState, setNumVisibleState] = React.useState(props.numVisible); + const [totalShiftedItemsState, setTotalShiftedItemsState] = React.useState(0); + const itemsContainerRef = React.useRef(null); + const startPos = React.useRef(null); + const attributeSelector = React.useRef(''); + const thumbnailsStyle = React.useRef(null); + const responsiveOptions = React.useRef(null); + const prevNumVisible = usePrevious(numVisibleState); + const prevActiveItemIndex = usePrevious(props.activeItemIndex); + + const [bindWindowResizeListener] = useResizeListener({ + listener: () => { + calculatePosition(); + }, + when: props.responsiveOptions + }); - if (dir < 0 && (-1 * totalShiftedItems) + numVisibleState > (props.value.length - 1)) { - totalShiftedItems = numVisibleState - props.value.length; - } - else if (dir > 0 && totalShiftedItems > 0) { - totalShiftedItems = 0; - } + const step = (dir) => { + let totalShiftedItems = totalShiftedItemsState + dir; - if (props.circular) { - if (dir < 0 && props.value.length - 1 === props.activeItemIndex) { + if (dir < 0 && -1 * totalShiftedItems + numVisibleState > props.value.length - 1) { + totalShiftedItems = numVisibleState - props.value.length; + } else if (dir > 0 && totalShiftedItems > 0) { totalShiftedItems = 0; } - else if (dir > 0 && props.activeItemIndex === 0) { - totalShiftedItems = numVisibleState - props.value.length; + + if (props.circular) { + if (dir < 0 && props.value.length - 1 === props.activeItemIndex) { + totalShiftedItems = 0; + } else if (dir > 0 && props.activeItemIndex === 0) { + totalShiftedItems = numVisibleState - props.value.length; + } } - } - if (itemsContainerRef.current) { - DomHandler.removeClass(itemsContainerRef.current, 'p-items-hidden'); - itemsContainerRef.current.style.transform = props.isVertical ? `translate3d(0, ${totalShiftedItems * (100 / numVisibleState)}%, 0)` : `translate3d(${totalShiftedItems * (100 / numVisibleState)}%, 0, 0)`; - itemsContainerRef.current.style.transition = 'transform 500ms ease 0s'; - } + if (itemsContainerRef.current) { + DomHandler.removeClass(itemsContainerRef.current, 'p-items-hidden'); + itemsContainerRef.current.style.transform = props.isVertical ? `translate3d(0, ${totalShiftedItems * (100 / numVisibleState)}%, 0)` : `translate3d(${totalShiftedItems * (100 / numVisibleState)}%, 0, 0)`; + itemsContainerRef.current.style.transition = 'transform 500ms ease 0s'; + } - setTotalShiftedItemsState(totalShiftedItems); - } + setTotalShiftedItemsState(totalShiftedItems); + }; - const stopSlideShow = () => { - if (props.slideShowActive && props.stopSlideShow) { - props.stopSlideShow(); - } - } + const stopSlideShow = () => { + if (props.slideShowActive && props.stopSlideShow) { + props.stopSlideShow(); + } + }; - const getMedianItemIndex = () => { - const index = Math.floor(numVisibleState / 2); + const getMedianItemIndex = () => { + const index = Math.floor(numVisibleState / 2); - return (numVisibleState % 2) ? index : index - 1; - } + return numVisibleState % 2 ? index : index - 1; + }; - const navBackward = (e) => { - stopSlideShow(); + const navBackward = (e) => { + stopSlideShow(); - let prevItemIndex = props.activeItemIndex !== 0 ? props.activeItemIndex - 1 : 0; - let diff = prevItemIndex + totalShiftedItemsState; - if ((numVisibleState - diff - 1) > getMedianItemIndex() && ((-1 * totalShiftedItemsState) !== 0 || props.circular)) { - step(1); - } + let prevItemIndex = props.activeItemIndex !== 0 ? props.activeItemIndex - 1 : 0; + let diff = prevItemIndex + totalShiftedItemsState; + if (numVisibleState - diff - 1 > getMedianItemIndex() && (-1 * totalShiftedItemsState !== 0 || props.circular)) { + step(1); + } - props.onActiveItemChange({ - index: props.circular && props.activeItemIndex === 0 ? props.value.length - 1 : prevItemIndex - }); + props.onActiveItemChange({ + index: props.circular && props.activeItemIndex === 0 ? props.value.length - 1 : prevItemIndex + }); - if (e.cancelable) { - e.preventDefault(); - } - } + if (e.cancelable) { + e.preventDefault(); + } + }; - const navForward = (e) => { - stopSlideShow(); + const navForward = (e) => { + stopSlideShow(); - let nextItemIndex = props.activeItemIndex + 1; - if (nextItemIndex + totalShiftedItemsState > getMedianItemIndex() && ((-1 * totalShiftedItemsState) < getTotalPageNumber() - 1 || props.circular)) { - step(-1); - } - - props.onActiveItemChange({ - index: props.circular && (props.value.length - 1) === props.activeItemIndex ? 0 : nextItemIndex - }); + let nextItemIndex = props.activeItemIndex + 1; + if (nextItemIndex + totalShiftedItemsState > getMedianItemIndex() && (-1 * totalShiftedItemsState < getTotalPageNumber() - 1 || props.circular)) { + step(-1); + } - if (e.cancelable) { - e.preventDefault(); - } - } + props.onActiveItemChange({ + index: props.circular && props.value.length - 1 === props.activeItemIndex ? 0 : nextItemIndex + }); - const onItemClick = (event) => { - stopSlideShow(); - - let selectedItemIndex = event.index; - if (selectedItemIndex !== props.activeItemIndex) { - const diff = selectedItemIndex + totalShiftedItemsState; - let dir = 0; - if (selectedItemIndex < props.activeItemIndex) { - dir = (numVisibleState - diff - 1) - getMedianItemIndex(); - if (dir > 0 && (-1 * totalShiftedItemsState) !== 0) { - step(dir); - } + if (e.cancelable) { + e.preventDefault(); } - else { - dir = getMedianItemIndex() - diff; - if (dir < 0 && (-1 * totalShiftedItemsState) < getTotalPageNumber() - 1) { - step(dir); + }; + + const onItemClick = (event) => { + stopSlideShow(); + + let selectedItemIndex = event.index; + if (selectedItemIndex !== props.activeItemIndex) { + const diff = selectedItemIndex + totalShiftedItemsState; + let dir = 0; + if (selectedItemIndex < props.activeItemIndex) { + dir = numVisibleState - diff - 1 - getMedianItemIndex(); + if (dir > 0 && -1 * totalShiftedItemsState !== 0) { + step(dir); + } + } else { + dir = getMedianItemIndex() - diff; + if (dir < 0 && -1 * totalShiftedItemsState < getTotalPageNumber() - 1) { + step(dir); + } } - } - props.onActiveItemChange({ - index: selectedItemIndex - }); - } - } + props.onActiveItemChange({ + index: selectedItemIndex + }); + } + }; - const onTransitionEnd = (e) => { - if (itemsContainerRef.current && e.propertyName === 'transform') { - DomHandler.addClass(itemsContainerRef.current, 'p-items-hidden'); - itemsContainerRef.current.style.transition = ''; - } - } + const onTransitionEnd = (e) => { + if (itemsContainerRef.current && e.propertyName === 'transform') { + DomHandler.addClass(itemsContainerRef.current, 'p-items-hidden'); + itemsContainerRef.current.style.transition = ''; + } + }; - const onTouchStart = (e) => { - let touchobj = e.changedTouches[0]; + const onTouchStart = (e) => { + let touchobj = e.changedTouches[0]; - startPos.current = { - x: touchobj.pageX, - y: touchobj.pageY + startPos.current = { + x: touchobj.pageX, + y: touchobj.pageY + }; }; - } - const onTouchMove = (e) => { - if (e.cancelable) { - e.preventDefault(); - } - } + const onTouchMove = (e) => { + if (e.cancelable) { + e.preventDefault(); + } + }; - const onTouchEnd = (e) => { - let touchobj = e.changedTouches[0]; + const onTouchEnd = (e) => { + let touchobj = e.changedTouches[0]; - if (props.isVertical) { - changePageOnTouch(e, (touchobj.pageY - startPos.current.y)); - } - else { - changePageOnTouch(e, (touchobj.pageX - startPos.current.x)); - } - } + if (props.isVertical) { + changePageOnTouch(e, touchobj.pageY - startPos.current.y); + } else { + changePageOnTouch(e, touchobj.pageX - startPos.current.x); + } + }; - const changePageOnTouch = (e, diff) => { - if (diff < 0) { // left - navForward(e); - } - else { // right - navBackward(e); - } - } + const changePageOnTouch = (e, diff) => { + if (diff < 0) { + // left + navForward(e); + } else { + // right + navBackward(e); + } + }; - const getTotalPageNumber = () => { - return props.value.length > numVisibleState ? (props.value.length - numVisibleState) + 1 : 0; - } + const getTotalPageNumber = () => { + return props.value.length > numVisibleState ? props.value.length - numVisibleState + 1 : 0; + }; - const createStyle = () => { - if (!thumbnailsStyle.current) { - thumbnailsStyle.current = DomHandler.createInlineStyle(PrimeReact.nonce); - } + const createStyle = () => { + if (!thumbnailsStyle.current) { + thumbnailsStyle.current = DomHandler.createInlineStyle(PrimeReact.nonce); + } - let innerHTML = ` + let innerHTML = ` .p-galleria-thumbnail-items[${attributeSelector.current}] .p-galleria-thumbnail-item { - flex: 1 0 ${(100 / numVisibleState)}% + flex: 1 0 ${100 / numVisibleState}% } `; - if (props.responsiveOptions) { - responsiveOptions.current = [...props.responsiveOptions]; - responsiveOptions.current.sort((data1, data2) => { - const value1 = data1.breakpoint; - const value2 = data2.breakpoint; - return ObjectUtils.sort(value1, value2, -1, PrimeReact.locale, PrimeReact.nullSortOrder); - }); + if (props.responsiveOptions) { + responsiveOptions.current = [...props.responsiveOptions]; + responsiveOptions.current.sort((data1, data2) => { + const value1 = data1.breakpoint; + const value2 = data2.breakpoint; + return ObjectUtils.sort(value1, value2, -1, PrimeReact.locale, PrimeReact.nullSortOrder); + }); - for (let i = 0; i < responsiveOptions.current.length; i++) { - let res = responsiveOptions.current[i]; + for (let i = 0; i < responsiveOptions.current.length; i++) { + let res = responsiveOptions.current[i]; - innerHTML += ` + innerHTML += ` @media screen and (max-width: ${res.breakpoint}) { .p-galleria-thumbnail-items[${attributeSelector.current}] .p-galleria-thumbnail-item { - flex: 1 0 ${(100 / res.numVisible)}% + flex: 1 0 ${100 / res.numVisible}% } } - ` + `; + } } - } - thumbnailsStyle.current.innerHTML = innerHTML; - } + thumbnailsStyle.current.innerHTML = innerHTML; + }; + + const calculatePosition = () => { + if (itemsContainerRef.current && responsiveOptions.current) { + let windowWidth = window.innerWidth; + let matchedResponsiveData = { + numVisible: props.numVisible + }; - const calculatePosition = () => { - if (itemsContainerRef.current && responsiveOptions.current) { - let windowWidth = window.innerWidth; - let matchedResponsiveData = { - numVisible: props.numVisible - }; + for (let i = 0; i < responsiveOptions.current.length; i++) { + let res = responsiveOptions.current[i]; - for (let i = 0; i < responsiveOptions.current.length; i++) { - let res = responsiveOptions.current[i]; + if (parseInt(res.breakpoint, 10) >= windowWidth) { + matchedResponsiveData = res; + } + } - if (parseInt(res.breakpoint, 10) >= windowWidth) { - matchedResponsiveData = res; + if (numVisibleState !== matchedResponsiveData.numVisible) { + setNumVisibleState(matchedResponsiveData.numVisible); } } + }; - if (numVisibleState !== matchedResponsiveData.numVisible) { - setNumVisibleState(matchedResponsiveData.numVisible); + useMountEffect(() => { + if (itemsContainerRef.current) { + attributeSelector.current = UniqueComponentId(); + itemsContainerRef.current.setAttribute(attributeSelector.current, ''); } - } - } - useMountEffect(() => { - if (itemsContainerRef.current) { - attributeSelector.current = UniqueComponentId(); - itemsContainerRef.current.setAttribute(attributeSelector.current, ''); - } + createStyle(); + calculatePosition(); + bindWindowResizeListener(); + }); - createStyle(); - calculatePosition(); - bindWindowResizeListener(); - }); + useUpdateEffect(() => { + let totalShiftedItems = totalShiftedItemsState; + + if (prevNumVisible !== numVisibleState || prevActiveItemIndex !== props.activeItemIndex) { + if (props.activeItemIndex <= getMedianItemIndex()) { + totalShiftedItems = 0; + } else if (props.value.length - numVisibleState + getMedianItemIndex() < props.activeItemIndex) { + totalShiftedItems = numVisibleState - props.value.length; + } else if (props.value.length - numVisibleState < props.activeItemIndex && numVisibleState % 2 === 0) { + totalShiftedItems = props.activeItemIndex * -1 + getMedianItemIndex() + 1; + } else { + totalShiftedItems = props.activeItemIndex * -1 + getMedianItemIndex(); + } - useUpdateEffect(() => { - let totalShiftedItems = totalShiftedItemsState; + if (totalShiftedItems !== totalShiftedItemsState) { + setTotalShiftedItemsState(totalShiftedItems); + } - if (prevNumVisible !== numVisibleState || prevActiveItemIndex !== props.activeItemIndex) { - if (props.activeItemIndex <= getMedianItemIndex()) { - totalShiftedItems = 0; - } - else if (props.value.length - numVisibleState + getMedianItemIndex() < props.activeItemIndex) { - totalShiftedItems = numVisibleState - props.value.length; - } - else if (props.value.length - numVisibleState < props.activeItemIndex && numVisibleState % 2 === 0) { - totalShiftedItems = (props.activeItemIndex * -1) + getMedianItemIndex() + 1; - } - else { - totalShiftedItems = (props.activeItemIndex * -1) + getMedianItemIndex(); - } + itemsContainerRef.current.style.transform = props.isVertical ? `translate3d(0, ${totalShiftedItems * (100 / numVisibleState)}%, 0)` : `translate3d(${totalShiftedItems * (100 / numVisibleState)}%, 0, 0)`; - if (totalShiftedItems !== totalShiftedItemsState) { - setTotalShiftedItemsState(totalShiftedItems); + if (prevActiveItemIndex !== props.activeItemIndex) { + DomHandler.removeClass(itemsContainerRef.current, 'p-items-hidden'); + itemsContainerRef.current.style.transition = 'transform 500ms ease 0s'; + } } + }); - itemsContainerRef.current.style.transform = props.isVertical ? `translate3d(0, ${totalShiftedItems * (100 / numVisibleState)}%, 0)` : `translate3d(${totalShiftedItems * (100 / numVisibleState)}%, 0, 0)`; + const createItems = () => { + return props.value.map((item, index) => { + const firstIndex = totalShiftedItemsState * -1; + const lastIndex = firstIndex + numVisibleState - 1; + const isActive = firstIndex <= index && lastIndex >= index; + const start = firstIndex === index; + const end = lastIndex === index; + const current = props.activeItemIndex === index; - if (prevActiveItemIndex !== props.activeItemIndex) { - DomHandler.removeClass(itemsContainerRef.current, 'p-items-hidden'); - itemsContainerRef.current.style.transition = 'transform 500ms ease 0s'; + return ; + }); + }; + + const createBackwardNavigator = () => { + if (props.showThumbnailNavigators) { + let isDisabled = (!props.circular && props.activeItemIndex === 0) || props.value.length <= numVisibleState; + let buttonClassName = classNames('p-galleria-thumbnail-prev p-link', { + 'p-disabled': isDisabled + }), + iconClassName = classNames('p-galleria-thumbnail-prev-icon pi', { + 'pi-chevron-left': !props.isVertical, + 'pi-chevron-up': props.isVertical + }); + + return ( + + ); } - } - }); - - const createItems = () => { - return props.value.map((item, index) => { - const firstIndex = totalShiftedItemsState * -1; - const lastIndex = firstIndex + numVisibleState - 1; - const isActive = firstIndex <= index && lastIndex >= index; - const start = firstIndex === index; - const end = lastIndex === index; - const current = props.activeItemIndex === index; - - return - }); - } - - const createBackwardNavigator = () => { - if (props.showThumbnailNavigators) { - let isDisabled = (!props.circular && props.activeItemIndex === 0) || (props.value.length <= numVisibleState); - let buttonClassName = classNames('p-galleria-thumbnail-prev p-link', { - 'p-disabled': isDisabled - }), - iconClassName = classNames('p-galleria-thumbnail-prev-icon pi', { - 'pi-chevron-left': !props.isVertical, - 'pi-chevron-up': props.isVertical + + return null; + }; + + const createForwardNavigator = () => { + if (props.showThumbnailNavigators) { + const isDisabled = (!props.circular && props.activeItemIndex === props.value.length - 1) || props.value.length <= numVisibleState; + const buttonClassName = classNames('p-galleria-thumbnail-next p-link', { + 'p-disabled': isDisabled + }); + const iconClassName = classNames('p-galleria-thumbnail-next-icon pi', { + 'pi-chevron-right': !props.isVertical, + 'pi-chevron-down': props.isVertical }); - return ( - - ) - } + return ( + + ); + } - return null; - } + return null; + }; - const createForwardNavigator = () => { - if (props.showThumbnailNavigators) { - const isDisabled = (!props.circular && props.activeItemIndex === (props.value.length - 1)) || (props.value.length <= numVisibleState); - const buttonClassName = classNames('p-galleria-thumbnail-next p-link', { - 'p-disabled': isDisabled - }); - const iconClassName = classNames('p-galleria-thumbnail-next-icon pi', { - 'pi-chevron-right': !props.isVertical, - 'pi-chevron-down': props.isVertical - }); + const createContent = () => { + const items = createItems(); + const height = props.isVertical ? props.contentHeight : ''; + const backwardNavigator = createBackwardNavigator(); + const forwardNavigator = createForwardNavigator(); return ( - - ) - } - - return null; - } - - const createContent = () => { - const items = createItems(); - const height = props.isVertical ? props.contentHeight : ''; - const backwardNavigator = createBackwardNavigator(); - const forwardNavigator = createForwardNavigator(); - - return ( -
      - {backwardNavigator} -
      -
      - {items} +
      + {backwardNavigator} +
      +
      + {items} +
      + {forwardNavigator}
      - {forwardNavigator} -
      - ) - } + ); + }; - const content = createContent(); + const content = createContent(); - return ( -
      - {content} -
      - ) -})); + return
      {content}
      ; + }) +); GalleriaThumbnailItem.displayName = 'GalleriaThumbnailItem'; GalleriaThumbnails.displayName = 'GalleriaThumbnails'; diff --git a/components/lib/gmap/GMap.js b/components/lib/gmap/GMap.js index 2e6f0a9a69..324af530fe 100644 --- a/components/lib/gmap/GMap.js +++ b/components/lib/gmap/GMap.js @@ -3,123 +3,125 @@ import * as React from 'react'; import { useMountEffect, useUpdateEffect } from '../hooks/Hooks'; import { ObjectUtils } from '../utils/Utils'; -export const GMap = React.memo(React.forwardRef((props, ref) => { - const elementRef = React.useRef(null); - const map = React.useRef(null); - const prevOverlays = React.useRef(null); +export const GMap = React.memo( + React.forwardRef((props, ref) => { + const elementRef = React.useRef(null); + const map = React.useRef(null); + const prevOverlays = React.useRef(null); - const initMap = () => { - map.current = new google.maps.Map(elementRef.current, props.options); + const initMap = () => { + map.current = new google.maps.Map(elementRef.current, props.options); - if (props.onMapReady) { - props.onMapReady({ - map: map.current - }); - } - - initOverlays(props.overlays); - - bindMapEvent('click', props.onMapClick); - bindMapEvent('dragend', props.onMapDragEnd); - bindMapEvent('zoom_changed', props.onZoomChanged); - } - - const initOverlays = (overlays) => { - if (overlays) { - for (let overlay of overlays) { - overlay.setMap(map.current); - bindOverlayEvents(overlay); - } - - prevOverlays.current = overlays; - } - } - - const bindOverlayEvents = (overlay) => { - overlay.addListener('click', (event) => { - if (props.onOverlayClick) { - props.onOverlayClick({ - originalEvent: event, - overlay: overlay, + if (props.onMapReady) { + props.onMapReady({ map: map.current }); } - }); - if (overlay.getDraggable()) { - bindDragEvents(overlay); - } - } + initOverlays(props.overlays); - const bindDragEvents = (overlay) => { - bindDragEvent(overlay, 'dragstart', props.onOverlayDragStart); - bindDragEvent(overlay, 'drag', props.onOverlayDrag); - bindDragEvent(overlay, 'dragend', props.onOverlayDragEnd); - } + bindMapEvent('click', props.onMapClick); + bindMapEvent('dragend', props.onMapDragEnd); + bindMapEvent('zoom_changed', props.onZoomChanged); + }; - const bindMapEvent = (eventName, callback) => { - map.current.addListener(eventName, (event) => { - callback && callback(event); - }); - } - - const bindDragEvent = (overlay, eventName, callback) => { - overlay.addListener(eventName, (event) => { - if (callback) { - callback({ - originalEvent: event, - overlay: overlay, - map: map.current - }); + const initOverlays = (overlays) => { + if (overlays) { + for (let overlay of overlays) { + overlay.setMap(map.current); + bindOverlayEvents(overlay); + } + + prevOverlays.current = overlays; } - }); - } + }; + + const bindOverlayEvents = (overlay) => { + overlay.addListener('click', (event) => { + if (props.onOverlayClick) { + props.onOverlayClick({ + originalEvent: event, + overlay: overlay, + map: map.current + }); + } + }); - const removeOverlays = (overlays) => { - if (overlays) { - for (let overlay of overlays) { - overlay.setMap(null); - unbindOverlayEvents(overlay); + if (overlay.getDraggable()) { + bindDragEvents(overlay); } - } - } + }; - const unbindOverlayEvents = (overlay) => { - google.maps.event.clearListeners(overlay, 'click'); + const bindDragEvents = (overlay) => { + bindDragEvent(overlay, 'dragstart', props.onOverlayDragStart); + bindDragEvent(overlay, 'drag', props.onOverlayDrag); + bindDragEvent(overlay, 'dragend', props.onOverlayDragEnd); + }; - if (overlay.getDraggable()) { - google.maps.event.clearListeners(overlay, 'dragstart'); - google.maps.event.clearListeners(overlay, 'drag'); - google.maps.event.clearListeners(overlay, 'dragend'); - } - } + const bindMapEvent = (eventName, callback) => { + map.current.addListener(eventName, (event) => { + callback && callback(event); + }); + }; + + const bindDragEvent = (overlay, eventName, callback) => { + overlay.addListener(eventName, (event) => { + if (callback) { + callback({ + originalEvent: event, + overlay: overlay, + map: map.current + }); + } + }); + }; + + const removeOverlays = (overlays) => { + if (overlays) { + for (let overlay of overlays) { + overlay.setMap(null); + unbindOverlayEvents(overlay); + } + } + }; - const getMap = () => { - return map.current; - } + const unbindOverlayEvents = (overlay) => { + google.maps.event.clearListeners(overlay, 'click'); - useMountEffect(() => { - initMap(); - }); + if (overlay.getDraggable()) { + google.maps.event.clearListeners(overlay, 'dragstart'); + google.maps.event.clearListeners(overlay, 'drag'); + google.maps.event.clearListeners(overlay, 'dragend'); + } + }; + + const getMap = () => { + return map.current; + }; - useUpdateEffect(() => { - initOverlays(props.overlays); + useMountEffect(() => { + initMap(); + }); - return () => { - removeOverlays(prevOverlays.current); - } - }); + useUpdateEffect(() => { + initOverlays(props.overlays); + + return () => { + removeOverlays(prevOverlays.current); + }; + }); - React.useImperativeHandle(ref, () => ({ - props, - getMap, - getElement: () => elementRef.current - })); + React.useImperativeHandle(ref, () => ({ + props, + getMap, + getElement: () => elementRef.current + })); - const otherProps = ObjectUtils.findDiffKeys(props, GMap.defaultProps); + const otherProps = ObjectUtils.findDiffKeys(props, GMap.defaultProps); - return
      -})); + return
      ; + }) +); GMap.displayName = 'GMap'; GMap.defaultProps = { @@ -136,4 +138,4 @@ GMap.defaultProps = { onOverlayDrag: null, onOverlayDragEnd: null, onOverlayClick: null -} +}; diff --git a/components/lib/gmap/gmap.d.ts b/components/lib/gmap/gmap.d.ts index a4f85ae62c..145259b70e 100644 --- a/components/lib/gmap/gmap.d.ts +++ b/components/lib/gmap/gmap.d.ts @@ -6,7 +6,7 @@ interface GMapEventParams { map: any; } -export interface GMapProps extends Omit, HTMLDivElement>, 'ref'> { +export interface GMapProps extends Omit, HTMLDivElement>, 'ref'> { options?: object; overlays?: any[]; onMapReady?(map: any): void; @@ -20,7 +20,7 @@ export interface GMapProps extends Omit { +export declare class GMap extends React.Component { public getMap(): any; public getElement(): HTMLDivElement; } diff --git a/components/lib/hooks/useEventListener.js b/components/lib/hooks/useEventListener.js index f03e43976d..5566f10dee 100644 --- a/components/lib/hooks/useEventListener.js +++ b/components/lib/hooks/useEventListener.js @@ -16,23 +16,22 @@ export const useEventListener = ({ target = 'document', type, listener, options, } if (!listenerRef.current && targetRef.current) { - listenerRef.current = event => listener && listener(event); + listenerRef.current = (event) => listener && listener(event); targetRef.current.addEventListener(type, listenerRef.current, options); } - } + }; const unbind = () => { if (listenerRef.current) { targetRef.current.removeEventListener(type, listenerRef.current, options); listenerRef.current = null; } - } + }; React.useEffect(() => { if (when) { targetRef.current = DomHandler.getTargetElement(target); - } - else { + } else { unbind(); targetRef.current = null; } @@ -50,5 +49,5 @@ export const useEventListener = ({ target = 'document', type, listener, options, }); return [bind, unbind]; -} +}; /* eslint-enable */ diff --git a/components/lib/hooks/useInterval.js b/components/lib/hooks/useInterval.js index 3cd92f6765..694525bd6d 100644 --- a/components/lib/hooks/useInterval.js +++ b/components/lib/hooks/useInterval.js @@ -20,8 +20,7 @@ export const useInterval = (fn, delay = 0, when = true) => { if (when) { timeout.current = setInterval(callback, delay); return clear; - } - else { + } else { clear(); } }, [delay, when]); @@ -31,5 +30,5 @@ export const useInterval = (fn, delay = 0, when = true) => { }); return [clear]; -} +}; /* eslint-enable */ diff --git a/components/lib/hooks/useOverlayListener.js b/components/lib/hooks/useOverlayListener.js index 5968ad8c71..c34d03cc29 100644 --- a/components/lib/hooks/useOverlayListener.js +++ b/components/lib/hooks/useOverlayListener.js @@ -17,44 +17,44 @@ export const useOverlayListener = ({ target, overlay, listener, when = true }) = * @param {boolean} options.valid It is controlled by PrimeReact. It is determined whether it is valid or not according to some custom validation. */ const [bindDocumentClickListener, unbindDocumentClickListener] = useEventListener({ - type: 'click', listener: event => { - listener && listener(event, { type: 'outside', valid: (event.which !== 3) && isOutsideClicked(event) }); + type: 'click', + listener: (event) => { + listener && listener(event, { type: 'outside', valid: event.which !== 3 && isOutsideClicked(event) }); } }); const [bindWindowResizeListener, unbindWindowResizeListener] = useResizeListener({ - listener: event => { + listener: (event) => { listener && listener(event, { type: 'resize', valid: !DomHandler.isTouchDevice() }); } }); const [bindOverlayScrollListener, unbindOverlayScrollListener] = useOverlayScrollListener({ - target: targetRef, listener: event => { + target: targetRef, + listener: (event) => { listener && listener(event, { type: 'scroll', valid: true }); } }); const isOutsideClicked = (event) => { - return targetRef.current && !(targetRef.current.isSameNode(event.target) || targetRef.current.contains(event.target) - || (overlayRef.current && overlayRef.current.contains(event.target))); - } + return targetRef.current && !(targetRef.current.isSameNode(event.target) || targetRef.current.contains(event.target) || (overlayRef.current && overlayRef.current.contains(event.target))); + }; const bind = () => { bindDocumentClickListener(); bindWindowResizeListener(); bindOverlayScrollListener(); - } + }; const unbind = () => { unbindDocumentClickListener(); unbindWindowResizeListener(); unbindOverlayScrollListener(); - } + }; React.useEffect(() => { if (when) { targetRef.current = DomHandler.getTargetElement(target); overlayRef.current = DomHandler.getTargetElement(overlay); - } - else { + } else { unbind(); targetRef.current = overlayRef.current = null; } @@ -70,5 +70,5 @@ export const useOverlayListener = ({ target, overlay, listener, when = true }) = }); return [bind, unbind]; -} +}; /* eslint-enable */ diff --git a/components/lib/hooks/useOverlayScrollListener.js b/components/lib/hooks/useOverlayScrollListener.js index b3891760ec..947ccc7459 100644 --- a/components/lib/hooks/useOverlayScrollListener.js +++ b/components/lib/hooks/useOverlayScrollListener.js @@ -17,12 +17,12 @@ export const useOverlayScrollListener = ({ target, listener, options, when = tru } if (!listenerRef.current && targetRef.current) { - const nodes = scrollableParents.current = DomHandler.getScrollableParents(targetRef.current); + const nodes = (scrollableParents.current = DomHandler.getScrollableParents(targetRef.current)); - listenerRef.current = event => listener && listener(event); + listenerRef.current = (event) => listener && listener(event); nodes.forEach((node) => node.addEventListener('scroll', listenerRef.current, options)); } - } + }; const unbind = () => { if (listenerRef.current) { @@ -31,13 +31,12 @@ export const useOverlayScrollListener = ({ target, listener, options, when = tru listenerRef.current = null; } - } + }; React.useEffect(() => { if (when) { targetRef.current = DomHandler.getTargetElement(target); - } - else { + } else { unbind(); targetRef.current = null; } @@ -55,5 +54,5 @@ export const useOverlayScrollListener = ({ target, listener, options, when = tru }); return [bind, unbind]; -} +}; /* eslint-enable */ diff --git a/components/lib/hooks/usePrevious.js b/components/lib/hooks/usePrevious.js index 6a979b187a..ba1959912d 100644 --- a/components/lib/hooks/usePrevious.js +++ b/components/lib/hooks/usePrevious.js @@ -8,4 +8,4 @@ export const usePrevious = (newValue) => { }); return ref.current; -} +}; diff --git a/components/lib/hooks/useStorage.js b/components/lib/hooks/useStorage.js index ecb81629be..dab9ad825d 100644 --- a/components/lib/hooks/useStorage.js +++ b/components/lib/hooks/useStorage.js @@ -11,7 +11,6 @@ import { useEventListener } from './useEventListener'; * @returns a stateful value, and a function to update it. */ export const useStorage = (initialValue, key, storage = 'local') => { - // Since the local storage API isn't available in server-rendering environments, // we check that typeof window !== 'undefined' to make SSR and SSG work properly. const storageAvailable = typeof window !== 'undefined'; @@ -19,7 +18,9 @@ export const useStorage = (initialValue, key, storage = 'local') => { // subscribe to window storage event so changes in one tab to a stored value // are properly reflected in all tabs const [bindWindowStorageListener, unbindWindowStorageListener] = useEventListener({ - target: 'window', type: 'storage', listener: event => { + target: 'window', + type: 'storage', + listener: (event) => { const area = storage === 'local' ? window.localStorage : window.sessionStorage; if (event.storageArea === area && event.key === key) { setStoredValue(event.newValue || undefined); @@ -32,9 +33,7 @@ export const useStorage = (initialValue, key, storage = 'local') => { return initialValue; } try { - const item = storage === 'local' ? - window.localStorage.getItem(key) : - window.sessionStorage.getItem(key); + const item = storage === 'local' ? window.localStorage.getItem(key) : window.sessionStorage.getItem(key); return item ? JSON.parse(item) : initialValue; } catch (error) { // If error also return initialValue @@ -49,9 +48,7 @@ export const useStorage = (initialValue, key, storage = 'local') => { setStoredValue(valueToStore); if (storageAvailable) { const serializedValue = JSON.stringify(valueToStore); - storage === 'local' ? - window.localStorage.setItem(key, serializedValue) : - window.sessionStorage.setItem(key, serializedValue); + storage === 'local' ? window.localStorage.setItem(key, serializedValue) : window.sessionStorage.setItem(key, serializedValue); } } catch (error) { throw new Error(`PrimeReact useStorage: Failed to serialize the value at key: ${key}`); @@ -64,7 +61,7 @@ export const useStorage = (initialValue, key, storage = 'local') => { }, []); return [storedValue, setValue]; -} +}; /** * Hook to wrap around useState that stores the value in the browser local storage. @@ -75,7 +72,7 @@ export const useStorage = (initialValue, key, storage = 'local') => { */ export const useLocalStorage = (initialValue, key) => { return useStorage(initialValue, key, 'local'); -} +}; /** * Hook to wrap around useState that stores the value in the browser session storage. @@ -86,5 +83,5 @@ export const useLocalStorage = (initialValue, key) => { */ export const useSessionStorage = (initialValue, key) => { return useStorage(initialValue, key, 'session'); -} +}; /* eslint-enable */ diff --git a/components/lib/hooks/useTimeout.js b/components/lib/hooks/useTimeout.js index a6ab7738ed..289b64176b 100644 --- a/components/lib/hooks/useTimeout.js +++ b/components/lib/hooks/useTimeout.js @@ -20,8 +20,7 @@ export const useTimeout = (fn, delay = 0, when = true) => { if (when) { timeout.current = setTimeout(callback, delay); return clear; - } - else { + } else { clear(); } }, [delay, when]); @@ -31,5 +30,5 @@ export const useTimeout = (fn, delay = 0, when = true) => { }); return [clear]; -} +}; /* eslint-enable */ diff --git a/components/lib/hooks/useUpdateEffect.js b/components/lib/hooks/useUpdateEffect.js index 45f853fb6a..c83b3d9253 100644 --- a/components/lib/hooks/useUpdateEffect.js +++ b/components/lib/hooks/useUpdateEffect.js @@ -11,5 +11,5 @@ export const useUpdateEffect = (fn, deps) => { return fn && fn(); }, deps); -} +}; /* eslint-enable */ diff --git a/components/lib/image/Image.js b/components/lib/image/Image.js index 305343080c..7b9c8d6871 100644 --- a/components/lib/image/Image.js +++ b/components/lib/image/Image.js @@ -5,170 +5,180 @@ import { useUnmountEffect } from '../hooks/Hooks'; import { Portal } from '../portal/Portal'; import { classNames, DomHandler, ObjectUtils, ZIndexUtils } from '../utils/Utils'; -export const Image = React.memo(React.forwardRef((props, ref) => { - const [maskVisibleState, setMaskVisibleState] = React.useState(false); - const [previewVisibleState, setPreviewVisibleState] = React.useState(false); - const [rotateState, setRotateState] = React.useState(0); - const [scaleState, setScaleState] = React.useState(1); - const elementRef = React.useRef(null); - const imageRef = React.useRef(null); - const maskRef = React.useRef(null); - const previewRef = React.useRef(null); - const previewClick = React.useRef(false); - - const onImageClick = () => { - if (props.preview) { - setMaskVisibleState(true); - setTimeout(() => { - setPreviewVisibleState(true); - }, 25); - } - } - - const onPreviewImageClick = () => { - previewClick.current = true; - } - - const onMaskClick = () => { - if (!previewClick.current) { - setPreviewVisibleState(false); - setRotateState(0); - setScaleState(1); - } - - previewClick.current = false; - } - - const onDownload = () => { - const { alt: name, src } = props; - DomHandler.saveAs({ name, src }); - previewClick.current = true; - } - - const rotateRight = () => { - setRotateState(prevRotate => prevRotate + 90); - previewClick.current = true; - } - - const rotateLeft = () => { - setRotateState(prevRotate => prevRotate - 90); - previewClick.current = true; - } - - const zoomIn = () => { - setScaleState(prevScale => prevScale + 0.1); - previewClick.current = true; - } - - const zoomOut = () => { - setScaleState(prevScale => prevScale - 0.1); - previewClick.current = true; - } - - const onEntering = () => { - ZIndexUtils.set('modal', maskRef.current, PrimeReact.autoZIndex, PrimeReact.zIndex['modal']); - } - - const onEntered = () => { - props.onShow && props.onShow(); - } - - const onExit = () => { - DomHandler.addClass(maskRef.current, 'p-component-overlay-leave'); - } - - const onExiting = () => { - props.onHide && props.onHide(); - } - - const onExited = () => { - ZIndexUtils.clear(maskRef.current); - - setMaskVisibleState(false); - } - - useUnmountEffect(() => { - maskRef.current && ZIndexUtils.clear(maskRef.current); - }); - - const createPreview = () => { - if (props.preview) { - return ( -
      - {content} -
      - ) - } +export const Image = React.memo( + React.forwardRef((props, ref) => { + const [maskVisibleState, setMaskVisibleState] = React.useState(false); + const [previewVisibleState, setPreviewVisibleState] = React.useState(false); + const [rotateState, setRotateState] = React.useState(0); + const [scaleState, setScaleState] = React.useState(1); + const elementRef = React.useRef(null); + const imageRef = React.useRef(null); + const maskRef = React.useRef(null); + const previewRef = React.useRef(null); + const previewClick = React.useRef(false); + + const onImageClick = () => { + if (props.preview) { + setMaskVisibleState(true); + setTimeout(() => { + setPreviewVisibleState(true); + }, 25); + } + }; + + const onPreviewImageClick = () => { + previewClick.current = true; + }; + + const onMaskClick = () => { + if (!previewClick.current) { + setPreviewVisibleState(false); + setRotateState(0); + setScaleState(1); + } + + previewClick.current = false; + }; + + const onDownload = () => { + const { alt: name, src } = props; + DomHandler.saveAs({ name, src }); + previewClick.current = true; + }; + + const rotateRight = () => { + setRotateState((prevRotate) => prevRotate + 90); + previewClick.current = true; + }; + + const rotateLeft = () => { + setRotateState((prevRotate) => prevRotate - 90); + previewClick.current = true; + }; + + const zoomIn = () => { + setScaleState((prevScale) => prevScale + 0.1); + previewClick.current = true; + }; + + const zoomOut = () => { + setScaleState((prevScale) => prevScale - 0.1); + previewClick.current = true; + }; + + const onEntering = () => { + ZIndexUtils.set('modal', maskRef.current, PrimeReact.autoZIndex, PrimeReact.zIndex['modal']); + }; + + const onEntered = () => { + props.onShow && props.onShow(); + }; + + const onExit = () => { + DomHandler.addClass(maskRef.current, 'p-component-overlay-leave'); + }; + + const onExiting = () => { + props.onHide && props.onHide(); + }; + + const onExited = () => { + ZIndexUtils.clear(maskRef.current); + + setMaskVisibleState(false); + }; + + useUnmountEffect(() => { + maskRef.current && ZIndexUtils.clear(maskRef.current); + }); + + const createPreview = () => { + if (props.preview) { + return ( +
      + {content} +
      + ); + } - return null; - } + return null; + }; - const createElement = () => { - const { downloadable } = props; - const imagePreviewStyle = { transform: 'rotate(' + rotateState + 'deg) scale(' + scaleState + ')' }; - const zoomDisabled = scaleState <= 0.5 || scaleState >= 1.5; - // const rotateClassName = 'p-image-preview-rotate-' + rotateScale; + const createElement = () => { + const { downloadable } = props; + const imagePreviewStyle = { transform: 'rotate(' + rotateState + 'deg) scale(' + scaleState + ')' }; + const zoomDisabled = scaleState <= 0.5 || scaleState >= 1.5; + // const rotateClassName = 'p-image-preview-rotate-' + rotateScale; - return ( -
      -
      - { - downloadable && ( - - ) - } - - - - - -
      - -
      - {props.alt} + )} + + + + +
      -
      -
      - ) - } - - React.useImperativeHandle(ref, () => ({ - props, - getElement: () => elementRef.current, - getImage: () => imageRef.current - })); - - const { src, alt, width, height } = props; - const otherProps = ObjectUtils.findDiffKeys(props, Image.defaultProps); - const containerClassName = classNames('p-image p-component', props.className, { - 'p-image-preview-container': props.preview - }); - const element = createElement(); - const content = props.template ? ObjectUtils.getJSXElement(props.template, props) : ; - const preview = createPreview(); - const image = {alt}; - - return ( - - {image} - {preview} - {maskVisibleState && } - - ) -})); + +
      + {props.alt} +
      +
      +
      + ); + }; + + React.useImperativeHandle(ref, () => ({ + props, + getElement: () => elementRef.current, + getImage: () => imageRef.current + })); + + const { src, alt, width, height } = props; + const otherProps = ObjectUtils.findDiffKeys(props, Image.defaultProps); + const containerClassName = classNames('p-image p-component', props.className, { + 'p-image-preview-container': props.preview + }); + const element = createElement(); + const content = props.template ? ObjectUtils.getJSXElement(props.template, props) : ; + const preview = createPreview(); + const image = {alt}; + + return ( + + {image} + {preview} + {maskVisibleState && } + + ); + }) +); Image.displayName = 'Image'; Image.defaultProps = { @@ -184,4 +194,4 @@ Image.defaultProps = { width: null, height: null, onError: null -} +}; diff --git a/components/lib/image/image.d.ts b/components/lib/image/image.d.ts index dbf1ea617c..df082833e4 100644 --- a/components/lib/image/image.d.ts +++ b/components/lib/image/image.d.ts @@ -15,7 +15,7 @@ export interface ImageProps extends Omit { +export declare class Image extends React.Component { public getElement(): HTMLSpanElement; public getImage(): HTMLImageElement; } diff --git a/components/lib/inplace/Inplace.js b/components/lib/inplace/Inplace.js index a2101cf6d5..65e3dbb62f 100644 --- a/components/lib/inplace/Inplace.js +++ b/components/lib/inplace/Inplace.js @@ -25,11 +25,10 @@ export const Inplace = React.forwardRef((props, ref) => { originalEvent: event, value: true }); - } - else { + } else { setActiveState(true); } - } + }; const close = (event) => { props.onClose && props.onClose(event); @@ -39,18 +38,17 @@ export const Inplace = React.forwardRef((props, ref) => { originalEvent: event, value: false }); - } - else { + } else { setActiveState(false); } - } + }; const onDisplayKeyDown = (event) => { if (event.key === 'Enter') { open(event); event.preventDefault(); } - } + }; const createDisplay = (content) => { const otherProps = ObjectUtils.findDiffKeys(content.props, InplaceDisplay.defaultProps); @@ -62,41 +60,38 @@ export const Inplace = React.forwardRef((props, ref) => {
      {content}
      - ) - } + ); + }; const createCloseButton = () => { if (props.closable) { - return - ) - } - - const createDownButton = () => { - const className = classNames('p-inputnumber-button p-inputnumber-button-down p-button p-button-icon-only p-component', { - 'p-disabled': props.disabled - }, props.decrementButtonClassName); - const icon = classNames('p-button-icon', props.decrementButtonIcon); + React.useImperativeHandle(ref, () => ({ + props, + getFormatter, + getElement: () => elementRef.current, + getInput: () => inputRef.current + })); + + React.useEffect(() => { + ObjectUtils.combinedRefs(inputRef, props.inputRef); + }, [inputRef, props.inputRef]); + + useMountEffect(() => { + constructParser(); + + const newValue = validateValue(props.value); + if (props.value !== null && props.value !== newValue) { + updateModel(null, newValue); + } + }); + + useUpdateEffect(() => { + constructParser(); + changeValue(); + }, [props.locale, props.localeMatcher, props.mode, props.currency, props.currencyDisplay, props.useGrouping, props.minFractionDigits, props.maxFractionDigits, props.suffix, props.prefix]); + + useUpdateEffect(() => { + changeValue(); + }, [props.value]); + + const createInputElement = () => { + const className = classNames('p-inputnumber-input', props.inputClassName); + const valueToRender = formattedValue(props.value); - return ( - - ) - } - - const createButtonGroup = () => { - const upButton = props.showButtons && createUpButton(); - const downButton = props.showButtons && createDownButton(); - - if (stacked) { return ( - + + ); + }; + + const createUpButton = () => { + const className = classNames( + 'p-inputnumber-button p-inputnumber-button-up p-button p-button-icon-only p-component', + { + 'p-disabled': props.disabled + }, + props.incrementButtonClassName + ); + const icon = classNames('p-button-icon', props.incrementButtonIcon); + + return ( + + ); + }; + + const createDownButton = () => { + const className = classNames( + 'p-inputnumber-button p-inputnumber-button-down p-button p-button-icon-only p-component', + { + 'p-disabled': props.disabled + }, + props.decrementButtonClassName + ); + const icon = classNames('p-button-icon', props.decrementButtonIcon); + + return ( + + ); + }; + + const createButtonGroup = () => { + const upButton = props.showButtons && createUpButton(); + const downButton = props.showButtons && createDownButton(); + + if (stacked) { + return ( + + {upButton} + {downButton} + + ); + } + + return ( + <> {upButton} {downButton} - - ) - } + + ); + }; + + const hasTooltip = ObjectUtils.isNotEmpty(props.tooltip); + const otherProps = ObjectUtils.findDiffKeys(props, InputNumber.defaultProps); + const className = classNames( + 'p-inputnumber p-component p-inputwrapper', + { + 'p-inputwrapper-filled': props.value != null && props.value.toString().length > 0, + 'p-inputwrapper-focus': focusedState, + 'p-inputnumber-buttons-stacked': stacked, + 'p-inputnumber-buttons-horizontal': horizontal, + 'p-inputnumber-buttons-vertical': vertical + }, + props.className + ); + const inputElement = createInputElement(); + const buttonGroup = createButtonGroup(); return ( <> - {upButton} - {downButton} + + {inputElement} + {buttonGroup} + + {hasTooltip && } - ) - } - - const hasTooltip = ObjectUtils.isNotEmpty(props.tooltip); - const otherProps = ObjectUtils.findDiffKeys(props, InputNumber.defaultProps); - const className = classNames('p-inputnumber p-component p-inputwrapper', { - 'p-inputwrapper-filled': props.value != null && props.value.toString().length > 0, - 'p-inputwrapper-focus': focusedState, - 'p-inputnumber-buttons-stacked': stacked, - 'p-inputnumber-buttons-horizontal': horizontal, - 'p-inputnumber-buttons-vertical': vertical - }, props.className); - const inputElement = createInputElement(); - const buttonGroup = createButtonGroup(); - - return ( - <> - - {inputElement} - {buttonGroup} - - {hasTooltip && } - - ) -})); + ); + }) +); InputNumber.displayName = 'InputNumber'; InputNumber.defaultProps = { @@ -1105,4 +1131,4 @@ InputNumber.defaultProps = { onBlur: null, onFocus: null, onKeyDown: null -} +}; diff --git a/components/lib/inputswitch/InputSwitch.js b/components/lib/inputswitch/InputSwitch.js index edf3ea6ea0..7667393c4a 100644 --- a/components/lib/inputswitch/InputSwitch.js +++ b/components/lib/inputswitch/InputSwitch.js @@ -2,83 +2,102 @@ import * as React from 'react'; import { Tooltip } from '../tooltip/Tooltip'; import { classNames, DomHandler, ObjectUtils } from '../utils/Utils'; -export const InputSwitch = React.memo(React.forwardRef((props, ref) => { - const [focusedState, setFocusedState] = React.useState(false); - const elementRef = React.useRef(null); - const inputRef = React.useRef(props.inputRef); - const checked = props.checked === props.trueValue; +export const InputSwitch = React.memo( + React.forwardRef((props, ref) => { + const [focusedState, setFocusedState] = React.useState(false); + const elementRef = React.useRef(null); + const inputRef = React.useRef(props.inputRef); + const checked = props.checked === props.trueValue; - const onClick = (event) => { - if (props.disabled) { - return; - } + const onClick = (event) => { + if (props.disabled) { + return; + } - toggle(event); - DomHandler.focus(inputRef.current); + toggle(event); + DomHandler.focus(inputRef.current); - event.preventDefault(); - } + event.preventDefault(); + }; - const toggle = (event) => { - if (props.onChange) { - const value = checked ? props.falseValue : props.trueValue; + const toggle = (event) => { + if (props.onChange) { + const value = checked ? props.falseValue : props.trueValue; - props.onChange({ - originalEvent: event, - value, - stopPropagation: () => { }, - preventDefault: () => { }, - target: { - name: props.name, - id: props.id, - value - } - }); - } - } + props.onChange({ + originalEvent: event, + value, + stopPropagation: () => {}, + preventDefault: () => {}, + target: { + name: props.name, + id: props.id, + value + } + }); + } + }; - const onFocus = (event) => { - setFocusedState(true); - props.onFocus && props.onFocus(event); - } + const onFocus = (event) => { + setFocusedState(true); + props.onFocus && props.onFocus(event); + }; - const onBlur = (event) => { - setFocusedState(false); - props.onBlur && props.onBlur(event); - } + const onBlur = (event) => { + setFocusedState(false); + props.onBlur && props.onBlur(event); + }; - React.useImperativeHandle(ref, () => ({ - props, - getElement: () => elementRef.current, - getInput: () => elementRef.current - })); + React.useImperativeHandle(ref, () => ({ + props, + getElement: () => elementRef.current, + getInput: () => elementRef.current + })); - React.useEffect(() => { - ObjectUtils.combinedRefs(inputRef, props.inputRef); - }, [inputRef, props.inputRef]); + React.useEffect(() => { + ObjectUtils.combinedRefs(inputRef, props.inputRef); + }, [inputRef, props.inputRef]); - const hasTooltip = ObjectUtils.isNotEmpty(props.tooltip); - const otherProps = ObjectUtils.findDiffKeys(props, InputSwitch.defaultProps); - const className = classNames('p-inputswitch p-component', { - 'p-inputswitch-checked': checked, - 'p-disabled': props.disabled, - 'p-focus': focusedState - }, props.className); + const hasTooltip = ObjectUtils.isNotEmpty(props.tooltip); + const otherProps = ObjectUtils.findDiffKeys(props, InputSwitch.defaultProps); + const className = classNames( + 'p-inputswitch p-component', + { + 'p-inputswitch-checked': checked, + 'p-disabled': props.disabled, + 'p-focus': focusedState + }, + props.className + ); - return ( - <> -