From cf0c05f0c1c411dc66c6e801a0c995bb711788fb Mon Sep 17 00:00:00 2001 From: ivanblinov2k17 Date: Mon, 13 Nov 2023 20:28:50 +0400 Subject: [PATCH] Navigation: Transfer demos to TS (#2825) * Typestat config created + files renamed * Enhance types with typestat * Improve typings + add missing @types/react-dom package * Typings improvments * fix cannot use jsx components in vscode * Types improv + tsconf changes to remove component is not tsx problem * Check tsc version on CI * Revert printing tsc version on CI * Revert TSConfig changes * Generate JS from ts * Revert bad js generation result for DateBox and DateRangeBox * Fix sysemJs index.js import to tsx in index.html * Final TS enhansments * generate js * Exclude Vue from ts config because it's polluting react JSX with wrong typings * Revert excluding vue from ts * Update ts for tabs demos (merge) * Fix minor errors * Missed extension in tabpanel * Drawer: navigationList fix file extension * Fix generate-js * Fix missing merge changes * Fix styles generation * generate js --- .../Overview/React/{App.js => App.tsx} | 24 +- .../React/{CustomItem.js => CustomItem.tsx} | 0 .../React/{CustomTitle.js => CustomTitle.tsx} | 0 .../Overview/React/{data.js => data.ts} | 0 .../Demos/Accordion/Overview/React/index.html | 2 +- .../Overview/React/index.tsx} | 2 +- .../Demos/Accordion/Overview/ReactJs/App.js | 116 ++++ .../Accordion/Overview/ReactJs/CustomItem.js | 34 ++ .../Accordion/Overview/ReactJs/CustomTitle.js | 5 + .../Demos/Accordion/Overview/ReactJs/data.js | 51 ++ .../Accordion/Overview/ReactJs/index.html | 44 ++ .../Demos/Accordion/Overview/ReactJs/index.js | 5 + .../Accordion/Overview/ReactJs/styles.css | 52 ++ .../React/{App.js => App.tsx} | 14 +- .../React/{data.js => data.ts} | 0 .../NavigationOverview/React/index.html | 2 +- .../NavigationOverview/React/index.tsx} | 2 +- .../Common/NavigationOverview/ReactJs/App.js | 122 ++++ .../Common/NavigationOverview/ReactJs/data.js | 576 ++++++++++++++++++ .../NavigationOverview/ReactJs/index.html | 44 ++ .../NavigationOverview/ReactJs/index.js | 5 + .../NavigationOverview/ReactJs/styles.css | 133 ++++ .../React/{App.js => App.tsx} | 14 +- .../React/{data.js => data.ts} | 0 .../React/index.html | 2 +- .../React/index.tsx} | 2 +- .../ReactJs/App.js | 89 +++ .../ReactJs/data.js | 271 ++++++++ .../ReactJs/index.html | 44 ++ .../ReactJs/index.js | 5 + .../ReactJs/styles.css | 25 + .../React/{App.js => App.tsx} | 13 +- .../{NavigationList.js => NavigationList.tsx} | 2 +- .../React/{data.js => data.ts} | 0 .../LeftOrRightPosition/React/index.html | 2 +- .../LeftOrRightPosition/React/index.tsx} | 2 +- .../Drawer/LeftOrRightPosition/ReactJs/App.js | 108 ++++ .../ReactJs/NavigationList.js | 21 + .../LeftOrRightPosition/ReactJs/data.js | 8 + .../LeftOrRightPosition/ReactJs/index.html | 45 ++ .../LeftOrRightPosition/ReactJs/index.js | 5 + .../LeftOrRightPosition/ReactJs/styles.css | 66 ++ .../React/{App.js => App.tsx} | 13 +- .../React/NavigationList.tsx | 18 + .../React/{data.js => data.ts} | 0 .../TopOrBottomPosition/React/index.html | 2 +- .../Drawer/TopOrBottomPosition/React/index.js | 9 - .../TopOrBottomPosition/React/index.tsx | 9 + .../Drawer/TopOrBottomPosition/ReactJs/App.js | 107 ++++ .../{React => ReactJs}/NavigationList.js | 5 +- .../TopOrBottomPosition/ReactJs/data.js | 8 + .../TopOrBottomPosition/ReactJs/index.html | 45 ++ .../TopOrBottomPosition/ReactJs/index.js | 5 + .../TopOrBottomPosition/ReactJs/styles.css | 71 +++ JSDemos/Demos/Menu/Overview/React/App.tsx | 107 ++++ .../Menu/Overview/React/{data.js => data.ts} | 15 +- JSDemos/Demos/Menu/Overview/React/index.html | 2 +- JSDemos/Demos/Menu/Overview/React/index.js | 9 - JSDemos/Demos/Menu/Overview/React/index.tsx | 9 + .../Menu/Overview/{React => ReactJs}/App.js | 47 +- JSDemos/Demos/Menu/Overview/ReactJs/data.js | 116 ++++ .../Demos/Menu/Overview/ReactJs/index.html | 44 ++ JSDemos/Demos/Menu/Overview/ReactJs/index.js | 5 + .../Demos/Menu/Overview/ReactJs/styles.css | 60 ++ .../Overview/React/{App.js => App.tsx} | 14 +- .../React/{CompanyItem.js => CompanyItem.tsx} | 0 .../Overview/React/{data.js => data.ts} | 0 .../Demos/MultiView/Overview/React/index.html | 2 +- .../Demos/MultiView/Overview/React/index.js | 9 - .../Demos/MultiView/Overview/React/index.tsx | 9 + .../Demos/MultiView/Overview/ReactJs/App.js | 66 ++ .../MultiView/Overview/ReactJs/CompanyItem.js | 39 ++ .../Demos/MultiView/Overview/ReactJs/data.js | 46 ++ .../MultiView/Overview/ReactJs/index.html | 44 ++ .../Demos/MultiView/Overview/ReactJs/index.js | 5 + .../MultiView/Overview/ReactJs/styles.css | 44 ++ .../Overview/React/{App.js => App.tsx} | 4 +- .../{TabPanelItem.js => TabPanelItem.tsx} | 2 +- .../React/{TaskItem.js => TaskItem.tsx} | 0 .../Overview/React/{data.js => data.ts} | 8 +- .../Demos/TabPanel/Overview/React/index.html | 2 +- .../Demos/TabPanel/Overview/React/index.js | 9 - .../Demos/TabPanel/Overview/React/index.tsx | 9 + .../Demos/TabPanel/Overview/ReactJs/App.js | 112 ++++ .../TabPanel/Overview/ReactJs/TabPanelItem.js | 13 + .../TabPanel/Overview/ReactJs/TaskItem.js | 14 + .../Demos/TabPanel/Overview/ReactJs/data.js | 230 +++++++ .../TabPanel/Overview/ReactJs/index.html | 44 ++ .../Demos/TabPanel/Overview/ReactJs/index.js | 5 + .../TabPanel/Overview/ReactJs/styles.css | 122 ++++ .../React/{App.js => App.tsx} | 16 +- .../React/EmployeeTemplate.tsx | 43 ++ .../React/{data.js => data.ts} | 0 .../SortableClosableTabs/React/index.html | 2 +- .../SortableClosableTabs/React/index.js | 9 - .../SortableClosableTabs/React/index.tsx | 9 + .../SortableClosableTabs/ReactJs/App.js | 105 ++++ .../{React => ReactJs}/EmployeeTemplate.js | 13 +- .../SortableClosableTabs/ReactJs/data.js | 517 ++++++++++++++++ .../SortableClosableTabs/ReactJs/index.html | 44 ++ .../SortableClosableTabs/ReactJs/index.js | 5 + .../SortableClosableTabs/ReactJs/styles.css | 76 +++ .../Demos/TabPanel/Templates/React/App.tsx | 77 +++ .../React/{CompanyItem.js => CompanyItem.tsx} | 0 .../Templates/React/{data.js => data.ts} | 0 .../Demos/TabPanel/Templates/React/index.html | 2 +- .../Demos/TabPanel/Templates/React/index.js | 9 - .../Demos/TabPanel/Templates/React/index.tsx | 9 + .../Templates/{React => ReactJs}/App.js | 47 +- .../TabPanel/Templates/ReactJs/CompanyItem.js | 42 ++ .../Demos/TabPanel/Templates/ReactJs/data.js | 46 ++ .../TabPanel/Templates/ReactJs/description.md | 16 + .../TabPanel/Templates/ReactJs/index.html | 44 ++ .../Demos/TabPanel/Templates/ReactJs/index.js | 5 + .../TabPanel/Templates/ReactJs/styles.css | 40 ++ .../Tabs/Overview/React/{App.js => App.tsx} | 2 +- JSDemos/Demos/Tabs/Overview/React/data.ts | 106 ++++ JSDemos/Demos/Tabs/Overview/React/index.html | 2 +- JSDemos/Demos/Tabs/Overview/React/index.js | 9 - JSDemos/Demos/Tabs/Overview/React/index.tsx | 9 + JSDemos/Demos/Tabs/Overview/ReactJs/App.js | 190 ++++++ .../Tabs/Overview/{React => ReactJs}/data.js | 18 +- .../Demos/Tabs/Overview/ReactJs/index.html | 44 ++ JSDemos/Demos/Tabs/Overview/ReactJs/index.js | 5 + .../Demos/Tabs/Overview/ReactJs/styles.css | 68 +++ .../Tabs/Selection/React/{App.js => App.tsx} | 11 +- .../Tabs/Selection/React/{data.js => data.ts} | 0 JSDemos/Demos/Tabs/Selection/React/index.html | 2 +- JSDemos/Demos/Tabs/Selection/React/index.js | 9 - JSDemos/Demos/Tabs/Selection/React/index.tsx | 9 + JSDemos/Demos/Tabs/Selection/ReactJs/App.js | 82 +++ JSDemos/Demos/Tabs/Selection/ReactJs/data.js | 30 + .../Demos/Tabs/Selection/ReactJs/index.html | 44 ++ JSDemos/Demos/Tabs/Selection/ReactJs/index.js | 5 + .../Demos/Tabs/Selection/ReactJs/styles.css | 58 ++ .../Adaptability/React/{App.js => App.tsx} | 25 +- .../Adaptability/React/{data.js => data.ts} | 0 .../Toolbar/Adaptability/React/index.html | 2 +- .../Demos/Toolbar/Adaptability/React/index.js | 9 - .../Toolbar/Adaptability/React/index.tsx | 9 + .../Demos/Toolbar/Adaptability/ReactJs/App.js | 408 +++++++++++++ .../Toolbar/Adaptability/ReactJs/data.js | 96 +++ .../Toolbar/Adaptability/ReactJs/index.html | 44 ++ .../Toolbar/Adaptability/ReactJs/index.js | 5 + .../Toolbar/Adaptability/ReactJs/styles.css | 56 ++ .../Overview/React/{App.js => App.tsx} | 4 +- .../Overview/React/{data.js => data.ts} | 0 .../Demos/Toolbar/Overview/React/index.html | 2 +- JSDemos/Demos/Toolbar/Overview/React/index.js | 9 - .../Demos/Toolbar/Overview/React/index.tsx | 9 + JSDemos/Demos/Toolbar/Overview/ReactJs/App.js | 119 ++++ .../Demos/Toolbar/Overview/ReactJs/data.js | 68 +++ .../Demos/Toolbar/Overview/ReactJs/index.html | 44 ++ .../Demos/Toolbar/Overview/ReactJs/index.js | 5 + .../Demos/Toolbar/Overview/ReactJs/styles.css | 8 + .../React/{App.js => App.tsx} | 18 +- .../React/{data.js => data.ts} | 0 .../ContextMenuIntegration/React/index.html | 2 +- .../ContextMenuIntegration/React/index.js | 9 - .../ContextMenuIntegration/React/index.tsx | 9 + .../ContextMenuIntegration/ReactJs/App.js | 85 +++ .../ContextMenuIntegration/ReactJs/data.js | 393 ++++++++++++ .../ContextMenuIntegration/ReactJs/index.html | 44 ++ .../ContextMenuIntegration/ReactJs/index.js | 5 + .../ContextMenuIntegration/ReactJs/styles.css | 35 ++ .../React/{App.js => App.tsx} | 40 +- .../React/{data.js => data.ts} | 0 .../React/index.html | 2 +- .../React/index.js | 9 - .../React/index.tsx | 9 + .../ReactJs/App.js | 184 ++++++ .../ReactJs/data.js | 113 ++++ .../ReactJs/index.html | 44 ++ .../ReactJs/index.js | 5 + .../ReactJs/styles.css | 31 + .../React/{App.js => App.tsx} | 38 +- .../React/{data.js => data.ts} | 0 .../React/index.html | 2 +- .../React/index.js | 9 - .../React/index.tsx | 9 + .../ReactJs/App.js | 200 ++++++ .../ReactJs/data.js | 126 ++++ .../ReactJs/index.html | 44 ++ .../ReactJs/index.js | 5 + .../ReactJs/styles.css | 31 + .../React/{App.js => App.tsx} | 6 +- .../React/{data.js => data.ts} | 11 +- .../FlatDataStructure/React/index.html | 2 +- .../TreeView/FlatDataStructure/React/index.js | 9 - .../FlatDataStructure/React/index.tsx | 9 + .../TreeView/FlatDataStructure/ReactJs/App.js | 39 ++ .../FlatDataStructure/ReactJs/data.js | 114 ++++ .../FlatDataStructure/ReactJs/index.html | 44 ++ .../FlatDataStructure/ReactJs/index.js | 5 + .../FlatDataStructure/ReactJs/styles.css | 35 ++ .../React/{App.js => App.tsx} | 16 +- .../React/{data.js => data.ts} | 11 +- .../React/index.html | 2 +- .../HierarchicalDataStructure/React/index.js | 9 - .../HierarchicalDataStructure/React/index.tsx | 9 + .../HierarchicalDataStructure/ReactJs/App.js | 32 + .../HierarchicalDataStructure/ReactJs/data.js | 384 ++++++++++++ .../ReactJs/index.html | 44 ++ .../ReactJs/index.js | 5 + .../ReactJs/styles.css | 35 ++ .../React/{App.js => App.tsx} | 42 +- .../React/{data.js => data.ts} | 0 .../React/index.html | 2 +- .../React/index.js | 9 - .../React/index.tsx | 9 + .../ReactJs/App.js | 158 +++++ .../ReactJs/data.js | 89 +++ .../ReactJs/index.html | 44 ++ .../ReactJs/index.js | 5 + .../ReactJs/styles.css | 67 ++ .../TreeView/LoadDataOnDemand/React/App.tsx | 26 + .../LoadDataOnDemand/React/index.html | 2 +- .../TreeView/LoadDataOnDemand/React/index.js | 9 - .../TreeView/LoadDataOnDemand/React/index.tsx | 9 + .../{React => ReactJs}/App.js | 7 +- .../LoadDataOnDemand/ReactJs/index.html | 39 ++ .../LoadDataOnDemand/ReactJs/index.js | 5 + .../TreeViewWithSearchBar/React/App.tsx | 43 ++ .../React/{data.js => data.ts} | 0 .../TreeViewWithSearchBar/React/index.html | 2 +- .../TreeViewWithSearchBar/React/index.js | 9 - .../TreeViewWithSearchBar/React/index.tsx | 9 + .../{React => ReactJs}/App.js | 15 +- .../TreeViewWithSearchBar/ReactJs/data.js | 341 +++++++++++ .../TreeViewWithSearchBar/ReactJs/index.html | 44 ++ .../TreeViewWithSearchBar/ReactJs/index.js | 5 + .../TreeViewWithSearchBar/ReactJs/styles.css | 30 + .../VirtualMode/React/{App.js => App.tsx} | 0 .../TreeView/VirtualMode/React/index.html | 2 +- .../Demos/TreeView/VirtualMode/React/index.js | 9 - .../TreeView/VirtualMode/React/index.tsx | 9 + .../Demos/TreeView/VirtualMode/ReactJs/App.js | 25 + .../TreeView/VirtualMode/ReactJs/index.html | 39 ++ .../TreeView/VirtualMode/ReactJs/index.js | 5 + package-lock.json | 19 + package.json | 1 + tsconfig.json | 3 +- 242 files changed, 9332 insertions(+), 438 deletions(-) rename JSDemos/Demos/Accordion/Overview/React/{App.js => App.tsx} (75%) rename JSDemos/Demos/Accordion/Overview/React/{CustomItem.js => CustomItem.tsx} (100%) rename JSDemos/Demos/Accordion/Overview/React/{CustomTitle.js => CustomTitle.tsx} (100%) rename JSDemos/Demos/Accordion/Overview/React/{data.js => data.ts} (100%) rename JSDemos/Demos/{Common/NavigationRightToLeftSupport/React/index.js => Accordion/Overview/React/index.tsx} (81%) create mode 100644 JSDemos/Demos/Accordion/Overview/ReactJs/App.js create mode 100644 JSDemos/Demos/Accordion/Overview/ReactJs/CustomItem.js create mode 100644 JSDemos/Demos/Accordion/Overview/ReactJs/CustomTitle.js create mode 100644 JSDemos/Demos/Accordion/Overview/ReactJs/data.js create mode 100644 JSDemos/Demos/Accordion/Overview/ReactJs/index.html create mode 100644 JSDemos/Demos/Accordion/Overview/ReactJs/index.js create mode 100644 JSDemos/Demos/Accordion/Overview/ReactJs/styles.css rename JSDemos/Demos/Common/NavigationOverview/React/{App.js => App.tsx} (87%) rename JSDemos/Demos/Common/NavigationOverview/React/{data.js => data.ts} (100%) rename JSDemos/Demos/{Accordion/Overview/React/index.js => Common/NavigationOverview/React/index.tsx} (81%) create mode 100644 JSDemos/Demos/Common/NavigationOverview/ReactJs/App.js create mode 100644 JSDemos/Demos/Common/NavigationOverview/ReactJs/data.js create mode 100644 JSDemos/Demos/Common/NavigationOverview/ReactJs/index.html create mode 100644 JSDemos/Demos/Common/NavigationOverview/ReactJs/index.js create mode 100644 JSDemos/Demos/Common/NavigationOverview/ReactJs/styles.css rename JSDemos/Demos/Common/NavigationRightToLeftSupport/React/{App.js => App.tsx} (87%) rename JSDemos/Demos/Common/NavigationRightToLeftSupport/React/{data.js => data.ts} (100%) rename JSDemos/Demos/{Drawer/LeftOrRightPosition/React/index.js => Common/NavigationRightToLeftSupport/React/index.tsx} (81%) create mode 100644 JSDemos/Demos/Common/NavigationRightToLeftSupport/ReactJs/App.js create mode 100644 JSDemos/Demos/Common/NavigationRightToLeftSupport/ReactJs/data.js create mode 100644 JSDemos/Demos/Common/NavigationRightToLeftSupport/ReactJs/index.html create mode 100644 JSDemos/Demos/Common/NavigationRightToLeftSupport/ReactJs/index.js create mode 100644 JSDemos/Demos/Common/NavigationRightToLeftSupport/ReactJs/styles.css rename JSDemos/Demos/Drawer/LeftOrRightPosition/React/{App.js => App.tsx} (85%) rename JSDemos/Demos/Drawer/LeftOrRightPosition/React/{NavigationList.js => NavigationList.tsx} (90%) rename JSDemos/Demos/Drawer/LeftOrRightPosition/React/{data.js => data.ts} (100%) rename JSDemos/Demos/{Common/NavigationOverview/React/index.js => Drawer/LeftOrRightPosition/React/index.tsx} (81%) create mode 100644 JSDemos/Demos/Drawer/LeftOrRightPosition/ReactJs/App.js create mode 100644 JSDemos/Demos/Drawer/LeftOrRightPosition/ReactJs/NavigationList.js create mode 100644 JSDemos/Demos/Drawer/LeftOrRightPosition/ReactJs/data.js create mode 100644 JSDemos/Demos/Drawer/LeftOrRightPosition/ReactJs/index.html create mode 100644 JSDemos/Demos/Drawer/LeftOrRightPosition/ReactJs/index.js create mode 100644 JSDemos/Demos/Drawer/LeftOrRightPosition/ReactJs/styles.css rename JSDemos/Demos/Drawer/TopOrBottomPosition/React/{App.js => App.tsx} (85%) create mode 100644 JSDemos/Demos/Drawer/TopOrBottomPosition/React/NavigationList.tsx rename JSDemos/Demos/Drawer/TopOrBottomPosition/React/{data.js => data.ts} (100%) delete mode 100644 JSDemos/Demos/Drawer/TopOrBottomPosition/React/index.js create mode 100644 JSDemos/Demos/Drawer/TopOrBottomPosition/React/index.tsx create mode 100644 JSDemos/Demos/Drawer/TopOrBottomPosition/ReactJs/App.js rename JSDemos/Demos/Drawer/TopOrBottomPosition/{React => ReactJs}/NavigationList.js (90%) create mode 100644 JSDemos/Demos/Drawer/TopOrBottomPosition/ReactJs/data.js create mode 100644 JSDemos/Demos/Drawer/TopOrBottomPosition/ReactJs/index.html create mode 100644 JSDemos/Demos/Drawer/TopOrBottomPosition/ReactJs/index.js create mode 100644 JSDemos/Demos/Drawer/TopOrBottomPosition/ReactJs/styles.css create mode 100644 JSDemos/Demos/Menu/Overview/React/App.tsx rename JSDemos/Demos/Menu/Overview/React/{data.js => data.ts} (88%) delete mode 100644 JSDemos/Demos/Menu/Overview/React/index.js create mode 100644 JSDemos/Demos/Menu/Overview/React/index.tsx rename JSDemos/Demos/Menu/Overview/{React => ReactJs}/App.js (80%) create mode 100644 JSDemos/Demos/Menu/Overview/ReactJs/data.js create mode 100644 JSDemos/Demos/Menu/Overview/ReactJs/index.html create mode 100644 JSDemos/Demos/Menu/Overview/ReactJs/index.js create mode 100644 JSDemos/Demos/Menu/Overview/ReactJs/styles.css rename JSDemos/Demos/MultiView/Overview/React/{App.js => App.tsx} (74%) rename JSDemos/Demos/MultiView/Overview/React/{CompanyItem.js => CompanyItem.tsx} (100%) rename JSDemos/Demos/MultiView/Overview/React/{data.js => data.ts} (100%) delete mode 100644 JSDemos/Demos/MultiView/Overview/React/index.js create mode 100644 JSDemos/Demos/MultiView/Overview/React/index.tsx create mode 100644 JSDemos/Demos/MultiView/Overview/ReactJs/App.js create mode 100644 JSDemos/Demos/MultiView/Overview/ReactJs/CompanyItem.js create mode 100644 JSDemos/Demos/MultiView/Overview/ReactJs/data.js create mode 100644 JSDemos/Demos/MultiView/Overview/ReactJs/index.html create mode 100644 JSDemos/Demos/MultiView/Overview/ReactJs/index.js create mode 100644 JSDemos/Demos/MultiView/Overview/ReactJs/styles.css rename JSDemos/Demos/TabPanel/Overview/React/{App.js => App.tsx} (97%) rename JSDemos/Demos/TabPanel/Overview/React/{TabPanelItem.js => TabPanelItem.tsx} (87%) rename JSDemos/Demos/TabPanel/Overview/React/{TaskItem.js => TaskItem.tsx} (100%) rename JSDemos/Demos/TabPanel/Overview/React/{data.js => data.ts} (96%) delete mode 100644 JSDemos/Demos/TabPanel/Overview/React/index.js create mode 100644 JSDemos/Demos/TabPanel/Overview/React/index.tsx create mode 100644 JSDemos/Demos/TabPanel/Overview/ReactJs/App.js create mode 100644 JSDemos/Demos/TabPanel/Overview/ReactJs/TabPanelItem.js create mode 100644 JSDemos/Demos/TabPanel/Overview/ReactJs/TaskItem.js create mode 100644 JSDemos/Demos/TabPanel/Overview/ReactJs/data.js create mode 100644 JSDemos/Demos/TabPanel/Overview/ReactJs/index.html create mode 100644 JSDemos/Demos/TabPanel/Overview/ReactJs/index.js create mode 100644 JSDemos/Demos/TabPanel/Overview/ReactJs/styles.css rename JSDemos/Demos/TabPanel/SortableClosableTabs/React/{App.js => App.tsx} (83%) create mode 100644 JSDemos/Demos/TabPanel/SortableClosableTabs/React/EmployeeTemplate.tsx rename JSDemos/Demos/TabPanel/SortableClosableTabs/React/{data.js => data.ts} (100%) delete mode 100644 JSDemos/Demos/TabPanel/SortableClosableTabs/React/index.js create mode 100644 JSDemos/Demos/TabPanel/SortableClosableTabs/React/index.tsx create mode 100644 JSDemos/Demos/TabPanel/SortableClosableTabs/ReactJs/App.js rename JSDemos/Demos/TabPanel/SortableClosableTabs/{React => ReactJs}/EmployeeTemplate.js (82%) create mode 100644 JSDemos/Demos/TabPanel/SortableClosableTabs/ReactJs/data.js create mode 100644 JSDemos/Demos/TabPanel/SortableClosableTabs/ReactJs/index.html create mode 100644 JSDemos/Demos/TabPanel/SortableClosableTabs/ReactJs/index.js create mode 100644 JSDemos/Demos/TabPanel/SortableClosableTabs/ReactJs/styles.css create mode 100644 JSDemos/Demos/TabPanel/Templates/React/App.tsx rename JSDemos/Demos/TabPanel/Templates/React/{CompanyItem.js => CompanyItem.tsx} (100%) rename JSDemos/Demos/TabPanel/Templates/React/{data.js => data.ts} (100%) delete mode 100644 JSDemos/Demos/TabPanel/Templates/React/index.js create mode 100644 JSDemos/Demos/TabPanel/Templates/React/index.tsx rename JSDemos/Demos/TabPanel/Templates/{React => ReactJs}/App.js (75%) create mode 100644 JSDemos/Demos/TabPanel/Templates/ReactJs/CompanyItem.js create mode 100644 JSDemos/Demos/TabPanel/Templates/ReactJs/data.js create mode 100644 JSDemos/Demos/TabPanel/Templates/ReactJs/description.md create mode 100644 JSDemos/Demos/TabPanel/Templates/ReactJs/index.html create mode 100644 JSDemos/Demos/TabPanel/Templates/ReactJs/index.js create mode 100644 JSDemos/Demos/TabPanel/Templates/ReactJs/styles.css rename JSDemos/Demos/Tabs/Overview/React/{App.js => App.tsx} (99%) create mode 100644 JSDemos/Demos/Tabs/Overview/React/data.ts delete mode 100644 JSDemos/Demos/Tabs/Overview/React/index.js create mode 100644 JSDemos/Demos/Tabs/Overview/React/index.tsx create mode 100644 JSDemos/Demos/Tabs/Overview/ReactJs/App.js rename JSDemos/Demos/Tabs/Overview/{React => ReactJs}/data.js (89%) create mode 100644 JSDemos/Demos/Tabs/Overview/ReactJs/index.html create mode 100644 JSDemos/Demos/Tabs/Overview/ReactJs/index.js create mode 100644 JSDemos/Demos/Tabs/Overview/ReactJs/styles.css rename JSDemos/Demos/Tabs/Selection/React/{App.js => App.tsx} (91%) rename JSDemos/Demos/Tabs/Selection/React/{data.js => data.ts} (100%) delete mode 100644 JSDemos/Demos/Tabs/Selection/React/index.js create mode 100644 JSDemos/Demos/Tabs/Selection/React/index.tsx create mode 100644 JSDemos/Demos/Tabs/Selection/ReactJs/App.js create mode 100644 JSDemos/Demos/Tabs/Selection/ReactJs/data.js create mode 100644 JSDemos/Demos/Tabs/Selection/ReactJs/index.html create mode 100644 JSDemos/Demos/Tabs/Selection/ReactJs/index.js create mode 100644 JSDemos/Demos/Tabs/Selection/ReactJs/styles.css rename JSDemos/Demos/Toolbar/Adaptability/React/{App.js => App.tsx} (94%) rename JSDemos/Demos/Toolbar/Adaptability/React/{data.js => data.ts} (100%) delete mode 100644 JSDemos/Demos/Toolbar/Adaptability/React/index.js create mode 100644 JSDemos/Demos/Toolbar/Adaptability/React/index.tsx create mode 100644 JSDemos/Demos/Toolbar/Adaptability/ReactJs/App.js create mode 100644 JSDemos/Demos/Toolbar/Adaptability/ReactJs/data.js create mode 100644 JSDemos/Demos/Toolbar/Adaptability/ReactJs/index.html create mode 100644 JSDemos/Demos/Toolbar/Adaptability/ReactJs/index.js create mode 100644 JSDemos/Demos/Toolbar/Adaptability/ReactJs/styles.css rename JSDemos/Demos/Toolbar/Overview/React/{App.js => App.tsx} (95%) rename JSDemos/Demos/Toolbar/Overview/React/{data.js => data.ts} (100%) delete mode 100644 JSDemos/Demos/Toolbar/Overview/React/index.js create mode 100644 JSDemos/Demos/Toolbar/Overview/React/index.tsx create mode 100644 JSDemos/Demos/Toolbar/Overview/ReactJs/App.js create mode 100644 JSDemos/Demos/Toolbar/Overview/ReactJs/data.js create mode 100644 JSDemos/Demos/Toolbar/Overview/ReactJs/index.html create mode 100644 JSDemos/Demos/Toolbar/Overview/ReactJs/index.js create mode 100644 JSDemos/Demos/Toolbar/Overview/ReactJs/styles.css rename JSDemos/Demos/TreeView/ContextMenuIntegration/React/{App.js => App.tsx} (82%) rename JSDemos/Demos/TreeView/ContextMenuIntegration/React/{data.js => data.ts} (100%) delete mode 100644 JSDemos/Demos/TreeView/ContextMenuIntegration/React/index.js create mode 100644 JSDemos/Demos/TreeView/ContextMenuIntegration/React/index.tsx create mode 100644 JSDemos/Demos/TreeView/ContextMenuIntegration/ReactJs/App.js create mode 100644 JSDemos/Demos/TreeView/ContextMenuIntegration/ReactJs/data.js create mode 100644 JSDemos/Demos/TreeView/ContextMenuIntegration/ReactJs/index.html create mode 100644 JSDemos/Demos/TreeView/ContextMenuIntegration/ReactJs/index.js create mode 100644 JSDemos/Demos/TreeView/ContextMenuIntegration/ReactJs/styles.css rename JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/React/{App.js => App.tsx} (79%) rename JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/React/{data.js => data.ts} (100%) delete mode 100644 JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/React/index.js create mode 100644 JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/React/index.tsx create mode 100644 JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/ReactJs/App.js create mode 100644 JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/ReactJs/data.js create mode 100644 JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/ReactJs/index.html create mode 100644 JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/ReactJs/index.js create mode 100644 JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/ReactJs/styles.css rename JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/React/{App.js => App.tsx} (84%) rename JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/React/{data.js => data.ts} (100%) delete mode 100644 JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/React/index.js create mode 100644 JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/React/index.tsx create mode 100644 JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/ReactJs/App.js create mode 100644 JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/ReactJs/data.js create mode 100644 JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/ReactJs/index.html create mode 100644 JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/ReactJs/index.js create mode 100644 JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/ReactJs/styles.css rename JSDemos/Demos/TreeView/FlatDataStructure/React/{App.js => App.tsx} (78%) rename JSDemos/Demos/TreeView/FlatDataStructure/React/{data.js => data.ts} (91%) delete mode 100644 JSDemos/Demos/TreeView/FlatDataStructure/React/index.js create mode 100644 JSDemos/Demos/TreeView/FlatDataStructure/React/index.tsx create mode 100644 JSDemos/Demos/TreeView/FlatDataStructure/ReactJs/App.js create mode 100644 JSDemos/Demos/TreeView/FlatDataStructure/ReactJs/data.js create mode 100644 JSDemos/Demos/TreeView/FlatDataStructure/ReactJs/index.html create mode 100644 JSDemos/Demos/TreeView/FlatDataStructure/ReactJs/index.js create mode 100644 JSDemos/Demos/TreeView/FlatDataStructure/ReactJs/styles.css rename JSDemos/Demos/TreeView/HierarchicalDataStructure/React/{App.js => App.tsx} (50%) rename JSDemos/Demos/TreeView/HierarchicalDataStructure/React/{data.js => data.ts} (97%) delete mode 100644 JSDemos/Demos/TreeView/HierarchicalDataStructure/React/index.js create mode 100644 JSDemos/Demos/TreeView/HierarchicalDataStructure/React/index.tsx create mode 100644 JSDemos/Demos/TreeView/HierarchicalDataStructure/ReactJs/App.js create mode 100644 JSDemos/Demos/TreeView/HierarchicalDataStructure/ReactJs/data.js create mode 100644 JSDemos/Demos/TreeView/HierarchicalDataStructure/ReactJs/index.html create mode 100644 JSDemos/Demos/TreeView/HierarchicalDataStructure/ReactJs/index.js create mode 100644 JSDemos/Demos/TreeView/HierarchicalDataStructure/ReactJs/styles.css rename JSDemos/Demos/TreeView/ItemSelectionAndCustomization/React/{App.js => App.tsx} (77%) rename JSDemos/Demos/TreeView/ItemSelectionAndCustomization/React/{data.js => data.ts} (100%) delete mode 100644 JSDemos/Demos/TreeView/ItemSelectionAndCustomization/React/index.js create mode 100644 JSDemos/Demos/TreeView/ItemSelectionAndCustomization/React/index.tsx create mode 100644 JSDemos/Demos/TreeView/ItemSelectionAndCustomization/ReactJs/App.js create mode 100644 JSDemos/Demos/TreeView/ItemSelectionAndCustomization/ReactJs/data.js create mode 100644 JSDemos/Demos/TreeView/ItemSelectionAndCustomization/ReactJs/index.html create mode 100644 JSDemos/Demos/TreeView/ItemSelectionAndCustomization/ReactJs/index.js create mode 100644 JSDemos/Demos/TreeView/ItemSelectionAndCustomization/ReactJs/styles.css create mode 100644 JSDemos/Demos/TreeView/LoadDataOnDemand/React/App.tsx delete mode 100644 JSDemos/Demos/TreeView/LoadDataOnDemand/React/index.js create mode 100644 JSDemos/Demos/TreeView/LoadDataOnDemand/React/index.tsx rename JSDemos/Demos/TreeView/LoadDataOnDemand/{React => ReactJs}/App.js (89%) create mode 100644 JSDemos/Demos/TreeView/LoadDataOnDemand/ReactJs/index.html create mode 100644 JSDemos/Demos/TreeView/LoadDataOnDemand/ReactJs/index.js create mode 100644 JSDemos/Demos/TreeView/TreeViewWithSearchBar/React/App.tsx rename JSDemos/Demos/TreeView/TreeViewWithSearchBar/React/{data.js => data.ts} (100%) delete mode 100644 JSDemos/Demos/TreeView/TreeViewWithSearchBar/React/index.js create mode 100644 JSDemos/Demos/TreeView/TreeViewWithSearchBar/React/index.tsx rename JSDemos/Demos/TreeView/TreeViewWithSearchBar/{React => ReactJs}/App.js (89%) create mode 100644 JSDemos/Demos/TreeView/TreeViewWithSearchBar/ReactJs/data.js create mode 100644 JSDemos/Demos/TreeView/TreeViewWithSearchBar/ReactJs/index.html create mode 100644 JSDemos/Demos/TreeView/TreeViewWithSearchBar/ReactJs/index.js create mode 100644 JSDemos/Demos/TreeView/TreeViewWithSearchBar/ReactJs/styles.css rename JSDemos/Demos/TreeView/VirtualMode/React/{App.js => App.tsx} (100%) delete mode 100644 JSDemos/Demos/TreeView/VirtualMode/React/index.js create mode 100644 JSDemos/Demos/TreeView/VirtualMode/React/index.tsx create mode 100644 JSDemos/Demos/TreeView/VirtualMode/ReactJs/App.js create mode 100644 JSDemos/Demos/TreeView/VirtualMode/ReactJs/index.html create mode 100644 JSDemos/Demos/TreeView/VirtualMode/ReactJs/index.js diff --git a/JSDemos/Demos/Accordion/Overview/React/App.js b/JSDemos/Demos/Accordion/Overview/React/App.tsx similarity index 75% rename from JSDemos/Demos/Accordion/Overview/React/App.js rename to JSDemos/Demos/Accordion/Overview/React/App.tsx index e2dde21bbf9..3e5962ddedb 100644 --- a/JSDemos/Demos/Accordion/Overview/React/App.js +++ b/JSDemos/Demos/Accordion/Overview/React/App.tsx @@ -1,12 +1,12 @@ import React from 'react'; -import Accordion from 'devextreme-react/accordion'; -import CheckBox from 'devextreme-react/check-box'; -import TagBox from 'devextreme-react/tag-box'; -import Slider, { Tooltip, Label } from 'devextreme-react/slider'; +import Accordion, { AccordionTypes } from 'devextreme-react/accordion'; +import CheckBox, { CheckBoxTypes } from 'devextreme-react/check-box'; +import TagBox, { TagBoxTypes } from 'devextreme-react/tag-box'; +import Slider, { Tooltip, Label, SliderTypes } from 'devextreme-react/slider'; -import service from './data.js'; -import CustomTitle from './CustomTitle.js'; -import CustomItem from './CustomItem.js'; +import service from './data.ts'; +import CustomTitle from './CustomTitle.tsx'; +import CustomItem from './CustomItem.tsx'; const companyLabel = { 'aria-label': 'Company' }; const companies = service.getCompanies(); @@ -17,7 +17,7 @@ const App = () => { const [collapsible, setCollapsible] = React.useState(false); const [animationDuration, setAnimationDuration] = React.useState(300); - const selectionChanged = React.useCallback((e) => { + const selectionChanged = React.useCallback((e: AccordionTypes.SelectionChangedEvent) => { let newItems = [...selectedItems]; e.removedItems.forEach((item) => { const index = newItems.indexOf(item); @@ -31,19 +31,19 @@ const App = () => { setSelectedItems(newItems); }, [selectedItems, setSelectedItems]); - const selectedItemsChanged = React.useCallback((e) => { + const selectedItemsChanged = React.useCallback((e: TagBoxTypes.ValueChangedEvent) => { setSelectedItems(e.value); }, [setSelectedItems]); - const multipleChanged = React.useCallback((e) => { + const multipleChanged = React.useCallback((e: CheckBoxTypes.ValueChangedEvent) => { setMultiple(e.value); }, [setMultiple]); - const collapsibleChanged = React.useCallback((e) => { + const collapsibleChanged = React.useCallback((e: CheckBoxTypes.ValueChangedEvent) => { setCollapsible(e.value); }, [setCollapsible]); - const animationDurationChanged = React.useCallback((e) => { + const animationDurationChanged = React.useCallback((e: SliderTypes.ValueChangedEvent) => { setAnimationDuration(e.value); }, [setAnimationDuration]); diff --git a/JSDemos/Demos/Accordion/Overview/React/CustomItem.js b/JSDemos/Demos/Accordion/Overview/React/CustomItem.tsx similarity index 100% rename from JSDemos/Demos/Accordion/Overview/React/CustomItem.js rename to JSDemos/Demos/Accordion/Overview/React/CustomItem.tsx diff --git a/JSDemos/Demos/Accordion/Overview/React/CustomTitle.js b/JSDemos/Demos/Accordion/Overview/React/CustomTitle.tsx similarity index 100% rename from JSDemos/Demos/Accordion/Overview/React/CustomTitle.js rename to JSDemos/Demos/Accordion/Overview/React/CustomTitle.tsx diff --git a/JSDemos/Demos/Accordion/Overview/React/data.js b/JSDemos/Demos/Accordion/Overview/React/data.ts similarity index 100% rename from JSDemos/Demos/Accordion/Overview/React/data.js rename to JSDemos/Demos/Accordion/Overview/React/data.ts diff --git a/JSDemos/Demos/Accordion/Overview/React/index.html b/JSDemos/Demos/Accordion/Overview/React/index.html index fb33a47d3fb..7aef756bcb4 100644 --- a/JSDemos/Demos/Accordion/Overview/React/index.html +++ b/JSDemos/Demos/Accordion/Overview/React/index.html @@ -12,7 +12,7 @@ diff --git a/JSDemos/Demos/Common/NavigationRightToLeftSupport/React/index.js b/JSDemos/Demos/Accordion/Overview/React/index.tsx similarity index 81% rename from JSDemos/Demos/Common/NavigationRightToLeftSupport/React/index.js rename to JSDemos/Demos/Accordion/Overview/React/index.tsx index d9d7442ce76..8acbec4b617 100644 --- a/JSDemos/Demos/Common/NavigationRightToLeftSupport/React/index.js +++ b/JSDemos/Demos/Accordion/Overview/React/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import App from './App.js'; +import App from './App.tsx'; ReactDOM.render( , diff --git a/JSDemos/Demos/Accordion/Overview/ReactJs/App.js b/JSDemos/Demos/Accordion/Overview/ReactJs/App.js new file mode 100644 index 00000000000..2706889d336 --- /dev/null +++ b/JSDemos/Demos/Accordion/Overview/ReactJs/App.js @@ -0,0 +1,116 @@ +import React from 'react'; +import Accordion from 'devextreme-react/accordion'; +import CheckBox from 'devextreme-react/check-box'; +import TagBox from 'devextreme-react/tag-box'; +import Slider, { Tooltip, Label } from 'devextreme-react/slider'; +import service from './data.js'; +import CustomTitle from './CustomTitle.js'; +import CustomItem from './CustomItem.js'; + +const companyLabel = { 'aria-label': 'Company' }; +const companies = service.getCompanies(); +const App = () => { + const [selectedItems, setSelectedItems] = React.useState([companies[0]]); + const [multiple, setMultiple] = React.useState(false); + const [collapsible, setCollapsible] = React.useState(false); + const [animationDuration, setAnimationDuration] = React.useState(300); + const selectionChanged = React.useCallback( + (e) => { + let newItems = [...selectedItems]; + e.removedItems.forEach((item) => { + const index = newItems.indexOf(item); + if (index >= 0) { + newItems.splice(index, 1); + } + }); + if (e.addedItems.length) { + newItems = [...newItems, ...e.addedItems]; + } + setSelectedItems(newItems); + }, + [selectedItems, setSelectedItems], + ); + const selectedItemsChanged = React.useCallback( + (e) => { + setSelectedItems(e.value); + }, + [setSelectedItems], + ); + const multipleChanged = React.useCallback( + (e) => { + setMultiple(e.value); + }, + [setMultiple], + ); + const collapsibleChanged = React.useCallback( + (e) => { + setCollapsible(e.value); + }, + [setCollapsible], + ); + const animationDurationChanged = React.useCallback( + (e) => { + setAnimationDuration(e.value); + }, + [setAnimationDuration], + ); + return ( +
+ +
+
Options
+
+ +
+
+ +
+
+ Animation duration + + + +
+
+ Selected Items + +
+
+
+ ); +}; +export default App; diff --git a/JSDemos/Demos/Accordion/Overview/ReactJs/CustomItem.js b/JSDemos/Demos/Accordion/Overview/ReactJs/CustomItem.js new file mode 100644 index 00000000000..d5d889c7c41 --- /dev/null +++ b/JSDemos/Demos/Accordion/Overview/ReactJs/CustomItem.js @@ -0,0 +1,34 @@ +import React from 'react'; + +export default function CustomItem(data) { + return ( +
+
+

+ {data.City} ({data.State}) +

+

+ {data.Zipcode} + {data.Address} +

+
+
+

+ Phone: {data.Phone} +

+

+ Fax: {data.Fax} +

+

+ Website:{' '} + + {data.Website} + +

+
+
+ ); +} diff --git a/JSDemos/Demos/Accordion/Overview/ReactJs/CustomTitle.js b/JSDemos/Demos/Accordion/Overview/ReactJs/CustomTitle.js new file mode 100644 index 00000000000..4b902be665a --- /dev/null +++ b/JSDemos/Demos/Accordion/Overview/ReactJs/CustomTitle.js @@ -0,0 +1,5 @@ +import React from 'react'; + +export default function CustomTitle(data) { + return
{data.CompanyName}
; +} diff --git a/JSDemos/Demos/Accordion/Overview/ReactJs/data.js b/JSDemos/Demos/Accordion/Overview/ReactJs/data.js new file mode 100644 index 00000000000..a32f55a09bd --- /dev/null +++ b/JSDemos/Demos/Accordion/Overview/ReactJs/data.js @@ -0,0 +1,51 @@ +const companies = [ + { + ID: 1, + CompanyName: 'Super Mart of the West', + Address: '702 SW 8th Street', + City: 'Bentonville', + State: 'Arkansas', + Zipcode: 72716, + Phone: '(800) 555-2797', + Fax: '(800) 555-2171', + Website: 'http://www.nowebsitesupermart.com', + }, + { + ID: 2, + CompanyName: 'Electronics Depot', + Address: '2455 Paces Ferry Road NW', + City: 'Atlanta', + State: 'Georgia', + Zipcode: 30339, + Phone: '(800) 595-3232', + Fax: '(800) 595-3231', + Website: 'http://www.nowebsitedepot.com', + }, + { + ID: 3, + CompanyName: 'K&S Music', + Address: '1000 Nicllet Mall', + City: 'Minneapolis', + State: 'Minnesota', + Zipcode: 55403, + Phone: '(612) 304-6073', + Fax: '(612) 304-6074', + Website: 'http://www.nowebsitemusic.com', + }, + { + ID: 4, + CompanyName: "Tom's Club", + Address: '999 Lake Drive', + City: 'Issaquah', + State: 'Washington', + Zipcode: 98027, + Phone: '(800) 955-2292', + Fax: '(800) 955-2293', + Website: 'http://www.nowebsitetomsclub.com', + }, +]; +export default { + getCompanies() { + return companies; + }, +}; diff --git a/JSDemos/Demos/Accordion/Overview/ReactJs/index.html b/JSDemos/Demos/Accordion/Overview/ReactJs/index.html new file mode 100644 index 00000000000..4d0ee54d8eb --- /dev/null +++ b/JSDemos/Demos/Accordion/Overview/ReactJs/index.html @@ -0,0 +1,44 @@ + + + + DevExtreme Demo + + + + + + + + + + + + + +
+
+
+ + diff --git a/JSDemos/Demos/Accordion/Overview/ReactJs/index.js b/JSDemos/Demos/Accordion/Overview/ReactJs/index.js new file mode 100644 index 00000000000..b853e0be824 --- /dev/null +++ b/JSDemos/Demos/Accordion/Overview/ReactJs/index.js @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App.js'; + +ReactDOM.render(, document.getElementById('app')); diff --git a/JSDemos/Demos/Accordion/Overview/ReactJs/styles.css b/JSDemos/Demos/Accordion/Overview/ReactJs/styles.css new file mode 100644 index 00000000000..aa555ce5344 --- /dev/null +++ b/JSDemos/Demos/Accordion/Overview/ReactJs/styles.css @@ -0,0 +1,52 @@ +#accordion { + height: 700px; +} + +#accordion .header { + font-size: 20px; +} + +#accordion .header, +#accordion p { + margin: 0; +} + +#accordion-container { + margin-right: 400px; +} + +.dx-theme-material #accordion .dx-accordion-item-title { + display: flex; +} + +.dx-theme-material #accordion .header { + align-self: center; +} + +.options { + padding: 20px; + position: absolute; + bottom: 0; + right: 0; + width: 340px; + top: 0; + background-color: rgba(191, 191, 191, 0.15); +} + +.options > .caption { + font-weight: 500; + font-size: 18px; +} + +.option { + margin-top: 10px; +} + +.option > .caption { + margin-top: 10px; + display: inline-block; +} + +.option > .dx-tagbox { + margin-top: 2px; +} diff --git a/JSDemos/Demos/Common/NavigationOverview/React/App.js b/JSDemos/Demos/Common/NavigationOverview/React/App.tsx similarity index 87% rename from JSDemos/Demos/Common/NavigationOverview/React/App.js rename to JSDemos/Demos/Common/NavigationOverview/React/App.tsx index 2e17d067367..080075cad4c 100644 --- a/JSDemos/Demos/Common/NavigationOverview/React/App.js +++ b/JSDemos/Demos/Common/NavigationOverview/React/App.tsx @@ -1,7 +1,7 @@ import React from 'react'; -import TreeView from 'devextreme-react/tree-view'; -import TabPanel from 'devextreme-react/tab-panel'; -import { continents } from './data.js'; +import TreeView, { TreeViewTypes } from 'devextreme-react/tree-view'; +import TabPanel, { TabPanelTypes } from 'devextreme-react/tab-panel'; +import { continents } from './data.ts'; const renderPanelItemTitle = (item) => {item.text}; @@ -45,7 +45,9 @@ function App() { const [countryData, setCountryData] = React.useState(continents[0].items[0]); const [citiesData, setCitiesData] = React.useState(continents[0].items[0].cities); - const handleTreeViewSelectionChange = React.useCallback((e) => { + const handleTreeViewSelectionChange = React.useCallback(( + e: TreeViewTypes.SelectionChangedEvent & { itemData: any }, + ) => { const selectedCountryData = e.itemData; if (selectedCountryData.cities) { setTabPanelIndex(0); @@ -54,7 +56,9 @@ function App() { } }, [setTabPanelIndex, setCountryData, setCitiesData]); - const handleTabPanelSelectionChange = React.useCallback((e) => { + const handleTabPanelSelectionChange = React.useCallback(( + e: TabPanelTypes.SelectionChangedEvent & { value: any }, + ) => { setTabPanelIndex(e.value); }, [setTabPanelIndex]); diff --git a/JSDemos/Demos/Common/NavigationOverview/React/data.js b/JSDemos/Demos/Common/NavigationOverview/React/data.ts similarity index 100% rename from JSDemos/Demos/Common/NavigationOverview/React/data.js rename to JSDemos/Demos/Common/NavigationOverview/React/data.ts diff --git a/JSDemos/Demos/Common/NavigationOverview/React/index.html b/JSDemos/Demos/Common/NavigationOverview/React/index.html index fb33a47d3fb..7aef756bcb4 100644 --- a/JSDemos/Demos/Common/NavigationOverview/React/index.html +++ b/JSDemos/Demos/Common/NavigationOverview/React/index.html @@ -12,7 +12,7 @@ diff --git a/JSDemos/Demos/Accordion/Overview/React/index.js b/JSDemos/Demos/Common/NavigationOverview/React/index.tsx similarity index 81% rename from JSDemos/Demos/Accordion/Overview/React/index.js rename to JSDemos/Demos/Common/NavigationOverview/React/index.tsx index d9d7442ce76..8acbec4b617 100644 --- a/JSDemos/Demos/Accordion/Overview/React/index.js +++ b/JSDemos/Demos/Common/NavigationOverview/React/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import App from './App.js'; +import App from './App.tsx'; ReactDOM.render( , diff --git a/JSDemos/Demos/Common/NavigationOverview/ReactJs/App.js b/JSDemos/Demos/Common/NavigationOverview/ReactJs/App.js new file mode 100644 index 00000000000..1b635a995b7 --- /dev/null +++ b/JSDemos/Demos/Common/NavigationOverview/ReactJs/App.js @@ -0,0 +1,122 @@ +import React from 'react'; +import TreeView from 'devextreme-react/tree-view'; +import TabPanel from 'devextreme-react/tab-panel'; +import { continents } from './data.js'; + +const renderPanelItemTitle = (item) => {item.text}; +const renderPanelItem = (city) => ( + + country flag +
+
+ {city.capital ? 'Capital. ' : ''} + {city.description} +
+
+
+
Population
+
+ {city.population} people +
+
+
+
Area
+
+ + {city.area} km2 + +
+
+
+
Density
+
+ + {city.density}/km2 + +
+
+
+
+
+); +function App() { + const [tabPanelIndex, setTabPanelIndex] = React.useState(0); + const [countryData, setCountryData] = React.useState(continents[0].items[0]); + const [citiesData, setCitiesData] = React.useState(continents[0].items[0].cities); + const handleTreeViewSelectionChange = React.useCallback( + (e) => { + const selectedCountryData = e.itemData; + if (selectedCountryData.cities) { + setTabPanelIndex(0); + setCountryData(selectedCountryData); + setCitiesData(selectedCountryData.cities); + } + }, + [setTabPanelIndex, setCountryData, setCitiesData], + ); + const handleTabPanelSelectionChange = React.useCallback( + (e) => { + setTabPanelIndex(e.value); + }, + [setTabPanelIndex], + ); + return ( +
+
+ +
+
+
+ country flag +
+
{countryData.fullName}
+
{countryData.description}
+
+
+ +
+
+
+ Area, km2 +
+
{countryData.area}
+
+
+
Population
+
{countryData.population}
+
+
+
GDP, billion
+
{`$${countryData.gdp}`}
+
+
+ +
Largest cities
+ + +
+
+ ); +} +export default App; diff --git a/JSDemos/Demos/Common/NavigationOverview/ReactJs/data.js b/JSDemos/Demos/Common/NavigationOverview/ReactJs/data.js new file mode 100644 index 00000000000..db8f048891f --- /dev/null +++ b/JSDemos/Demos/Common/NavigationOverview/ReactJs/data.js @@ -0,0 +1,576 @@ +export const continents = [ + { + id: '1', + text: 'Africa', + expanded: true, + items: [ + { + id: '1_1', + text: 'Egypt', + fullName: 'Arab Republic of Egypt', + description: + 'Egypt is a transcontinental country spanning the northeast corner of Africa and southwest corner of Asia by a land bridge the Sinai Peninsula forms.', + area: '1,010,407.87', + population: '94,798,827', + gdp: '1,173', + selected: true, + flag: '../../../../images/flags/Egypt.svg', + cities: [ + { + id: '1_1_1', + text: 'Cairo', + population: '9,500,000', + area: '528', + density: '19,376', + description: + "The city's metropolitan area is the largest in the Middle East and the Arab world, and the 15th-largest in the world, is associated with ancient Egypt.", + capital: true, + flag: '../../../../images/flags/Cairo.svg', + }, + { + id: '1_1_2', + text: 'Alexandria', + population: '4,984,387', + area: '2,679', + density: '1,900', + description: + 'Alexandria is the second largest city and a major economic center in Egypt, extending about 32 km (20 mi) along the coast of the Mediterranean Sea in the north central part of the country.', + flag: '../../../../images/flags/Alexandria.svg', + }, + { + id: '1_1_3', + text: 'Giza', + population: '3,628,062', + area: '1,579.75', + density: '2,300', + description: + 'Giza is the third-largest city in Egypt. It is located on the west bank of the Nile, 5 km (3 mi) southwest of central Cairo.', + flag: '../../../../images/flags/Giza.svg', + }, + ], + }, + { + id: '1_2', + text: 'South Africa', + fullName: 'Republic of South Africa', + description: + 'South Africa is the southernmost country in Africa. It is bounded on the south by 2,798 kilometres (1,739 mi) of coastline of Southern Africa stretching along the South Atlantic and Indian Oceans.', + area: '1,221,037', + population: '54,956,900', + gdp: '742.461', + flag: '../../../../images/flags/SouthAfrica.svg', + cities: [ + { + id: '1_2_2', + text: 'Pretoria', + population: '741,651', + area: '687.54', + density: '1,100', + description: + "Pretoria is a city in the northern part of Gauteng, South Africa. Being one of the country's three capital cities, it serves as the seat of the executive branch of government.", + capital: true, + flag: '../../../../images/flags/Pretoria.svg', + }, + { + id: '1_2_1', + text: 'Johannesburg', + population: '957,441', + area: '334.81', + density: '2,900', + description: + 'Johannesburg is the largest city in South Africa and is one of the 50 largest urban areas in the world.', + flag: '../../../../images/flags/Johannesburg.svg', + }, + { + id: '1_2_3', + text: 'Durban', + population: '595,061', + area: '225.91', + density: '2,600', + description: + 'Durban is the largest city in the South African province of KwaZulu-Natal. It is Located on the Indian Ocean coast of the African continent.', + flag: '../../../../images/flags/Durban.svg', + }, + ], + }, + ], + }, + { + id: '2', + text: 'Asia', + items: [ + { + id: '2_1', + text: 'Japan', + fullName: 'Japan', + description: + 'Japan is a sovereign island nation in East Asia. Located in the Pacific Ocean, it lies off the eastern coast of the Asian mainland and stretches from the Sea of Okhotsk in the north to the East China Sea and China in the southwest.', + area: '377,972', + population: '126,672,000', + gdp: '5,420', + flag: '../../../../images/flags/Japan.svg', + cities: [ + { + id: '2_1_1', + text: 'Tokyo', + population: '13,617,445', + area: '2,187.66', + density: '6,224.66', + description: + 'The Greater Tokyo Area is the most populous metropolitan area in the world. The city is located in the Kantō region on the southeastern side of the main island Honshu and includes the Izu Islands and Ogasawara Islands.', + capital: true, + flag: '../../../../images/flags/Tokyo.svg', + }, + { + id: '2_1_2', + text: 'Yokohama', + population: '3,732,616', + area: '437.38', + density: '8,534.03', + description: + 'Yokohama is the second largest city in Japan by population, after Tokyo, and the most populous municipality of Japan. It lies on Tokyo Bay, south of Tokyo, in the Kantō region of the main island of Honshu.', + flag: '../../../../images/flags/Yokohama.svg', + }, + { + id: '2_1_3', + text: 'Osaka', + population: '2,668,586', + area: '223', + density: '12,030', + description: + 'Osaka is a designated city in the Kansai region of Japan. It is the largest component of the Keihanshin Metropolitan Area, the second largest metropolitan area in Japan. The city is situated at the mouth of the Yodo River on Osaka Bay, Honshu island', + flag: '../../../../images/flags/Osaka.svg', + }, + { + id: '2_1_4', + text: 'Nagoya', + population: '2,283,289', + area: '326.43', + density: '6,969.86', + description: + "Nagoya is the largest city in the Chūbu region of Japan. It is Japan's third-largest incorporated city and the fourth most populous urban area.", + flag: '../../../../images/flags/Nagoya.svg', + }, + ], + }, + { + id: '2_2', + text: 'Malaysia', + fullName: 'Malaysia', + description: 'Malaysia is a federal constitutional monarchy located in Southeast Asia.', + area: '330,803', + population: '31,708,000', + gdp: '913.593', + flag: '../../../../images/flags/Malaysia.svg', + cities: [ + { + id: '2_2_1', + text: 'Kuala Lumpur', + population: '1,768,000', + area: '243', + density: '6,891', + description: + 'Kuala Lumpur, officially the Federal Territory of Kuala Lumpur, or commonly KL, is the largest city of Malaysia. It is located in Klang Valley.', + capital: true, + flag: '../../../../images/flags/KualaLumpur.svg', + }, + { + id: '2_2_2', + text: 'George Town', + population: '708,127', + area: '305.77', + density: '2,372', + description: + 'George Town, the capital city of the Malaysian state of Penang, is located at the northeastern tip of Penang Island.', + flag: '../../../../images/flags/GeorgeTown.svg', + }, + { + id: '2_2_3', + text: 'Ipoh', + population: '657,892', + area: '643', + density: '1,023', + description: + 'Ipoh is the capital of the Malaysian state of Perak. It stands on the banks of the Kinta River.', + flag: '../../../../images/flags/Ipoh.svg', + }, + ], + }, + ], + }, + { + id: '3', + text: 'Australia', + items: [ + { + id: '3_1', + text: 'Australia', + fullName: 'Commonwealth of Australia', + description: + "It is a sovereign country comprising the mainland of the Australian continent, the island of Tasmania and numerous smaller islands. It is the largest country in Oceania and the world's sixth-largest country by total area.", + area: '7,692,024', + population: '24,696,700', + gdp: '1,189', + flag: '../../../../images/flags/Australia.svg', + cities: [ + { + id: '3_1_1', + text: 'Canberra', + population: '403,468', + area: '814.2', + density: '428.6', + description: + 'The city is located at the northern end of the Australian Capital Territory (ACT), 280 km (170 mi) south-west of Sydney, and 660 km (410 mi) north-east of Melbourne.', + capital: true, + flag: '../../../../images/flags/Canberra.svg', + }, + { + id: '3_1_2', + text: 'Sydney', + population: '5,029,768', + area: '12,367.7', + density: '400', + description: + "Sydney is the state capital of New South Wales and the most populous city in Australia and Oceania. It is located on Australia's east coast.", + flag: '../../../../images/flags/Sydney.svg', + }, + { + id: '3_1_3', + text: 'Melbourne', + population: '4,725,316', + area: '2,664', + density: '453', + description: + 'Melbourne is the capital and most populous city of the Australian state of Victoria, and the second-most populous city in Australia and Oceania. The city is located in the south-eastern part of mainland Australia.', + flag: '../../../../images/flags/Melbourne.svg', + }, + ], + }, + ], + }, + { + id: '4', + text: 'Europe', + items: [ + { + id: '4_1', + text: 'Germany', + fullName: 'Federal Republic of Germany', + description: + 'The country is a federal parliamentary republic in central-western Europe. Germany is the most populous member state of the European Union.', + area: '357,168', + population: '82,175,700', + gdp: '4,150', + flag: '../../../../images/flags/Germany.svg', + cities: [ + { + id: '4_1_1', + text: 'Berlin', + capital: true, + population: '3,670,622', + area: '891.7', + density: '4,100', + description: + 'Berlin is the capital and the largest city of Germany as well as one of its 16 constituent states.', + flag: '../../../../images/flags/Berlin.svg', + }, + { + id: '4_1_2', + text: 'Hamburg', + population: '1,787,408', + area: '755', + density: '2,400', + description: + 'Hamburg, officially the Free and Hanseatic City of Hamburg, is the second largest city and a state of Germany.', + flag: '../../../../images/flags/Hamburg.svg', + }, + { + id: '4_1_3', + text: 'Munich', + population: '1,450,381', + area: '310.43', + density: '4,700', + description: + 'Munich is the capital and the most populated city in the German state of Bavaria, on the banks of River Isar north of the Bavarian Alps.', + flag: '../../../../images/flags/Munich.svg', + }, + ], + }, + { + id: '4_2', + text: 'Russia', + fullName: 'Russian Federation', + description: + "Russia is a country in Eurasia. It is the largest country in the world by surface area, covering more than one-eighth of the Earth's inhabited land area.", + area: '17,075,200', + population: '144,463,451', + gdp: '4,000', + flag: '../../../../images/flags/Russia.svg', + cities: [ + { + id: '4_2_1', + text: 'Moscow', + capital: true, + population: '12,228,685', + area: '2,511', + density: '4,833.36', + description: + 'Moscow is the capital and most populous city of Russia. It is located in the western part of Russia on the banks of the Moskva River.', + flag: '../../../../images/flags/Moscow.svg', + }, + { + id: '4_2_2', + text: 'Saint Petersburg', + population: '5,323,300', + area: '1,439', + density: '3,764.49', + description: + "Saint Petersburg is Russia's second-largest city after Moscow. An important Russian port on the Baltic Sea, it is politically administered as a federal subject (a federal city).", + flag: '../../../../images/flags/SaintPetersburg.svg', + }, + { + id: '4_2_3', + text: 'Novosibirsk', + population: '1,473,754', + area: '502.7', + density: '2,932', + description: + 'Novosibirsk is the most populous city in Asian Russia. The city is located in the southwestern part of Siberia on the banks of the Ob River adjacent to the Ob River Valley.', + flag: '../../../../images/flags/Novosibirsk.svg', + }, + ], + }, + { + id: '4_3', + text: 'United Kingdom', + fullName: 'United Kingdom of Great Britain and Northern Ireland', + description: + 'United Kingdom is a sovereign country in western Europe. Lying off the north-western coast of the European mainland, the United Kingdom includes the island of Great Britain, the north-eastern part of the island of Ireland and many smaller islands.', + area: '242,495', + population: '65,648,000', + gdp: '2,790', + flag: '../../../../images/flags/UnitedKingdom.svg', + cities: [ + { + id: '4_3_1', + text: 'London', + capital: true, + population: '8,787,892', + area: '1,572', + density: '5,590', + description: + 'London is the capital and most populous city of England and the United Kingdom. It stands on the River Thames in the south-east of the Great Britain island.', + flag: '../../../../images/flags/London.svg', + }, + { + id: '4_3_2', + text: 'Birmingham', + population: '1,124,600', + area: '267.8', + density: '4,199', + description: + 'Birmingham is a city and metropolitan borough in the West Midlands, England. The city stands on the small River Rea.', + flag: '../../../../images/flags/Birmingham.svg', + }, + ], + }, + ], + }, + { + id: '5', + text: 'North America', + items: [ + { + id: '5_2', + text: 'Mexico', + fullName: 'United Mexican States', + description: 'Mexico is a federal republic in the southern portion of North America.', + area: '1,972,550', + population: '119,530,753', + gdp: '2,406', + flag: '../../../../images/flags/Mexico.svg', + cities: [ + { + id: '5_2_1', + text: 'Mexico City', + population: '8,918,653', + area: '1,485', + density: '6,000', + description: + 'Mexico City is the most populous city of Mexico. It is located in the Valley of Mexico, a large valley in the high plateaus at the center of Mexico.', + capital: true, + flag: '../../../../images/flags/MexicoCity.svg', + }, + { + id: '5_2_2', + text: 'Puebla', + population: '2,499,519', + area: '534.32', + density: '4,678', + description: + 'Puebla, formally Heroica Puebla de Zaragoza and also known as Puebla de los Angeles, is located in the Valley of Puebla, a large valley surrounded by the mountains and volcanoes of the Trans-Mexican volcanic belt on four sides.', + flag: '../../../../images/flags/Puebla.svg', + }, + { + id: '5_2_3', + text: 'Guadalajara', + population: '1,495,189', + area: '151', + density: '10,361', + description: + 'Guadalajara is the capital and largest city of the Mexican state of Jalisco. The city is in the central region of Jalisco in the Western-Pacific area of Mexico.', + flag: '../../../../images/flags/Guadalajara.svg', + }, + ], + }, + { + id: '5_1', + text: 'United States', + fullName: 'United States of America', + description: + 'The country is a federal republic mainly located in the central part of the North American continent. The state of Alaska is in the northwest corner of North America and the state of Hawaii is an archipelago in the mid-Pacific Ocean.', + area: '9,833,520', + population: '325,365,189', + gdp: '18,558', + flag: '../../../../images/flags/UnitedStates.svg', + cities: [ + { + id: '5_1_1', + text: 'Washington', + capital: true, + population: '681,170', + area: '177', + density: '4,308', + description: + 'Washington, D.C., is located in the mid-Atlantic region of the U.S. East Coast and partially bordered by the Potomac River.', + flag: '../../../../images/flags/Washington.svg', + }, + { + id: '5_1_2', + text: 'New York City', + population: '8,175,133', + area: '34,306', + density: '10,890', + description: + 'The City of New York is the most populous city in the United States. Located at the southern tip of the state of New York, the city is the center of the New York metropolitan area, one of the most populous urban agglomerations in the world.', + flag: '../../../../images/flags/NewYorkCity.svg', + }, + { + id: '5_1_3', + text: 'Los Angeles', + population: '3,792,621', + area: '1,302.15', + density: '8,483.02', + description: + 'Los Angeles, officially the City of Los Angeles, is located on the on the West Coast of the United States. It is the second most populous city in the United States and the most populous city in the state of California.', + flag: '../../../../images/flags/LosAngeles.svg', + }, + { + id: '5_1_4', + text: 'Chicago', + population: '2,695,598', + area: '606.42', + density: '11,898.29', + description: + 'Chicago, officially the City of Chicago, is the third-most populous city in the United States. It is located in northern Illinois at the south-western tip of Lake Michigan.', + flag: '../../../../images/flags/Chicago.svg', + }, + ], + }, + ], + }, + { + id: '6', + text: 'South America', + items: [ + { + id: '6_1', + text: 'Brazil', + fullName: 'Federative Republic of Brazil', + description: + "Brasília is the federal capital of Brazil and seat of the Federal District government. It occupies a large area along the eastern coast of South America and includes much of the continent's interior.", + area: '8,515,767', + population: '208,064,000', + gdp: '3,217', + flag: '../../../../images/flags/Brazil.svg', + cities: [ + { + id: '6_1_1', + text: 'Brasilia', + capital: true, + population: '2,977,216', + area: '5,801,937', + density: '513,14', + description: + "Brasília is the federal capital of Brazil and seat of the Federal District government. The city is located atop the Brazilian highlands in the country's center-western region.", + flag: '../../../../images/flags/Brasilia.svg', + }, + { + id: '6_1_2', + text: 'Sao Paulo', + population: '12,038,175', + area: '1,521.11', + density: '7,913.29', + description: + 'Sao Paulo is a municipality in the southeast region of Brazil. The city is the capital of the surrounding San Paulo state.', + flag: '../../../../images/flags/SaoPaulo.svg', + }, + { + id: '6_1_3', + text: 'Rio de Janeiro', + population: '6,453,682', + area: '1,221', + density: '2,705.1', + description: + "Rio de Janeiro is the second-most populous municipality in Brazil and the capital of the Rio de Janeiro state, Brazil's third-most populous state.", + flag: '../../../../images/flags/RioDeJaneiro.svg', + }, + ], + }, + { + id: '6_2', + text: 'Colombia', + fullName: 'Republic of Colombia', + description: + 'Colombia is a sovereign state mainly located in the northwest of South America, with territories in Central America.', + area: '1,141,748', + population: '49,364,592', + gdp: '720.151', + flag: '../../../../images/flags/Colombia.svg', + cities: [ + { + id: '6_2_1', + text: 'Bogota', + capital: true, + population: '8,080,734', + area: '1,587', + density: '6,060', + description: + 'Bogotá is the capital and largest city of Colombia administered as the Capital District, although often thought of as part of Cundinamarca. The city is located in the southeastern part of the Bogotá savanna.', + flag: '../../../../images/flags/Bogota.svg', + }, + { + id: '6_2_2', + text: 'Medellin', + population: '2,441,123', + area: '380.64', + density: '6,413', + description: + 'Medellín is the second-largest city in Colombia and the capital of the Antioquia department. It is located in the Aburrá Valley, a central region of the Andes Mountains in South America.', + flag: '../../../../images/flags/Medellin.svg', + }, + { + id: '6_2_3', + text: 'Cali', + population: '2,400,653', + area: '619', + density: '3,900', + description: + 'Santiago de Cali, usually known by its short name Cali, is the capital of the Valle del Cauca department, and the most populous city in southwest Colombia.', + flag: '../../../../images/flags/Cali.svg', + }, + ], + }, + ], + }, +]; diff --git a/JSDemos/Demos/Common/NavigationOverview/ReactJs/index.html b/JSDemos/Demos/Common/NavigationOverview/ReactJs/index.html new file mode 100644 index 00000000000..4d0ee54d8eb --- /dev/null +++ b/JSDemos/Demos/Common/NavigationOverview/ReactJs/index.html @@ -0,0 +1,44 @@ + + + + DevExtreme Demo + + + + + + + + + + + + + +
+
+
+ + diff --git a/JSDemos/Demos/Common/NavigationOverview/ReactJs/index.js b/JSDemos/Demos/Common/NavigationOverview/ReactJs/index.js new file mode 100644 index 00000000000..b853e0be824 --- /dev/null +++ b/JSDemos/Demos/Common/NavigationOverview/ReactJs/index.js @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App.js'; + +ReactDOM.render(, document.getElementById('app')); diff --git a/JSDemos/Demos/Common/NavigationOverview/ReactJs/styles.css b/JSDemos/Demos/Common/NavigationOverview/ReactJs/styles.css new file mode 100644 index 00000000000..368d99d577f --- /dev/null +++ b/JSDemos/Demos/Common/NavigationOverview/ReactJs/styles.css @@ -0,0 +1,133 @@ +.container { + position: relative; +} + +.container, +.left-content { + min-height: 530px; +} + +.left-content { + display: inline-block; + width: 180px; + padding: 0 10px 10px; + background-color: rgba(191, 191, 191, 0.15); + box-shadow: -5px 0 14px -8px rgba(0, 0, 0, 0.25) inset; +} + +.right-content { + position: absolute; + right: 0; + left: 220px; + top: 0; + height: 100%; +} + +sup { + font-size: 0.8em; + vertical-align: super; + line-height: 0; +} + +.right-content .sub-title { + font-size: 120%; + color: rgba(152, 152, 152, 0.8); +} + +.title-container { + min-height: 140px; + margin-bottom: 10px; +} + +.title-container .country-name { + font-size: 240%; + font-weight: bold; + line-height: 34px; + margin-bottom: 10px; +} + +.title-container > div:not(.flag) { + margin-left: 204px; +} + +.stats { + display: table; + width: 100%; + margin-bottom: 20px; +} + +.stats > div { + display: table-cell; + text-align: center; + border: 1px solid rgba(191, 191, 191, 0.25); + padding: 20px 0 25px; + width: 33%; +} + +.stats > div:first-child, +.stats > div:last-child { + border-right-width: 0; + border-left-width: 0; +} + +.stats .stat-value { + font-size: 200%; +} + +#tabpanel { + margin-top: 10px; +} + +#tabpanel .dx-multiview-wrapper { + border-left: 0; + border-right: 0; + border-bottom: 0; +} + +#tabpanel .tab-panel-title { + font-size: 120%; + font-weight: 500; +} + +#tabpanel .dx-multiview-item-content { + padding: 20px 0 22px; + min-height: 178px; + position: relative; +} + +#tabpanel .right-content { + top: 15px; + left: 202px; +} + +#tabpanel .stats { + width: 398px; + margin-top: 20px; + border-top: 1px solid rgba(191, 191, 191, 0.25); +} + +#tabpanel .stats > div { + padding: 7px 0; + text-align: left; + border: 0; +} + +#tabpanel .stats > div:first-child { + width: 40%; +} + +#tabpanel .stats > div:not(:first-child) { + width: 30%; +} + +.flag { + width: 172px; + max-height: 122px; + border: 1px solid rgba(191, 191, 191, 0.25); + float: left; + margin: 0 30px 10px 0; +} + +.left-content .dx-treeview-node.dx-state-selected > .dx-item > .dx-item-content { + font-weight: 500; +} diff --git a/JSDemos/Demos/Common/NavigationRightToLeftSupport/React/App.js b/JSDemos/Demos/Common/NavigationRightToLeftSupport/React/App.tsx similarity index 87% rename from JSDemos/Demos/Common/NavigationRightToLeftSupport/React/App.js rename to JSDemos/Demos/Common/NavigationRightToLeftSupport/React/App.tsx index c1d62b65b3c..108768f84fe 100644 --- a/JSDemos/Demos/Common/NavigationRightToLeftSupport/React/App.js +++ b/JSDemos/Demos/Common/NavigationRightToLeftSupport/React/App.tsx @@ -3,7 +3,7 @@ import SelectBox from 'devextreme-react/select-box'; import Menu from 'devextreme-react/menu'; import TreeView from 'devextreme-react/tree-view'; import Accordion from 'devextreme-react/accordion'; -import { continents, europeCountries, languageLabel } from './data.js'; +import { continents, europeCountries, languageLabel } from './data.ts'; const languages = [ 'Arabic: Right-to-Left direction', @@ -14,9 +14,9 @@ const renderArabicTitle = (item) => (
{item.nameAr}
); const renderArabic = (country) => (
-
عاصمة: { country.capitalAr }
-
عدد السكان: { country.population } نسمة
-
المساحة: { country.area } كم2
+
عاصمة: {country.capitalAr}
+
عدد السكان: {country.population} نسمة
+
المساحة: {country.area} كم2
); @@ -24,9 +24,9 @@ const renderEnglishTitle = (item) => (
{item.nameEn}
); const renderEnglish = (country) => (
-
Capital: { country.capitalEn }
-
Population: { country.population } people
-
Area: { country.area } km2
+
Capital: {country.capitalEn}
+
Population: {country.population} people
+
Area: {country.area} km2
); diff --git a/JSDemos/Demos/Common/NavigationRightToLeftSupport/React/data.js b/JSDemos/Demos/Common/NavigationRightToLeftSupport/React/data.ts similarity index 100% rename from JSDemos/Demos/Common/NavigationRightToLeftSupport/React/data.js rename to JSDemos/Demos/Common/NavigationRightToLeftSupport/React/data.ts diff --git a/JSDemos/Demos/Common/NavigationRightToLeftSupport/React/index.html b/JSDemos/Demos/Common/NavigationRightToLeftSupport/React/index.html index fb33a47d3fb..7aef756bcb4 100644 --- a/JSDemos/Demos/Common/NavigationRightToLeftSupport/React/index.html +++ b/JSDemos/Demos/Common/NavigationRightToLeftSupport/React/index.html @@ -12,7 +12,7 @@ diff --git a/JSDemos/Demos/Drawer/LeftOrRightPosition/React/index.js b/JSDemos/Demos/Common/NavigationRightToLeftSupport/React/index.tsx similarity index 81% rename from JSDemos/Demos/Drawer/LeftOrRightPosition/React/index.js rename to JSDemos/Demos/Common/NavigationRightToLeftSupport/React/index.tsx index d9d7442ce76..8acbec4b617 100644 --- a/JSDemos/Demos/Drawer/LeftOrRightPosition/React/index.js +++ b/JSDemos/Demos/Common/NavigationRightToLeftSupport/React/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import App from './App.js'; +import App from './App.tsx'; ReactDOM.render( , diff --git a/JSDemos/Demos/Common/NavigationRightToLeftSupport/ReactJs/App.js b/JSDemos/Demos/Common/NavigationRightToLeftSupport/ReactJs/App.js new file mode 100644 index 00000000000..7f3caef4b7f --- /dev/null +++ b/JSDemos/Demos/Common/NavigationRightToLeftSupport/ReactJs/App.js @@ -0,0 +1,89 @@ +import React from 'react'; +import SelectBox from 'devextreme-react/select-box'; +import Menu from 'devextreme-react/menu'; +import TreeView from 'devextreme-react/tree-view'; +import Accordion from 'devextreme-react/accordion'; +import { continents, europeCountries, languageLabel } from './data.js'; + +const languages = ['Arabic: Right-to-Left direction', 'English: Left-to-Right direction']; +const renderArabicTitle = (item) =>
{item.nameAr}
; +const renderArabic = (country) => ( +
+
عاصمة: {country.capitalAr}
+
عدد السكان: {country.population} نسمة
+
+ المساحة: {country.area} كم2 +
+
+); +const renderEnglishTitle = (item) =>
{item.nameEn}
; +const renderEnglish = (country) => ( +
+
Capital: {country.capitalEn}
+
Population: {country.population} people
+
+ Area: {country.area} km2 +
+
+); +const App = () => { + const [rtlEnabled, setRtl] = React.useState(false); + const selectLanguage = React.useCallback( + ({ value }) => { + setRtl(value === languages[0]); + }, + [setRtl], + ); + return ( +
+
+
Options
+
+
+
Language
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+
+ +
+
+ +
+
+
+
+
+ ); +}; +export default App; diff --git a/JSDemos/Demos/Common/NavigationRightToLeftSupport/ReactJs/data.js b/JSDemos/Demos/Common/NavigationRightToLeftSupport/ReactJs/data.js new file mode 100644 index 00000000000..fd00cac9f2b --- /dev/null +++ b/JSDemos/Demos/Common/NavigationRightToLeftSupport/ReactJs/data.js @@ -0,0 +1,271 @@ +export const continents = [ + { + id: '1', + text: 'Africa', + textAr: 'أفريقيا', + items: [ + { + id: '1_2', + text: 'Ethiopia', + textAr: 'أثيوبيا', + items: [ + { + id: '1_2_1', + text: 'Addis Ababa', + textAr: 'أديس أبابا', + }, + { + id: '1_2_2', + text: 'Dire Dawa', + textAr: 'دير داوا', + }, + ], + }, + { + id: '1_1', + text: 'Nigeria', + textAr: 'نيجيريا', + items: [ + { + id: '1_1_1', + text: 'Lagos', + textAr: 'لاغوس', + }, + { + id: '1_1_2', + text: 'Kano', + textAr: 'كانو', + }, + ], + }, + ], + }, + { + id: '2', + text: 'Asia', + textAr: 'آسيا', + items: [ + { + id: '2_1', + text: 'China', + textAr: 'الصين', + items: [ + { + id: '2_1_1', + text: 'Beijing', + textAr: 'بكين', + }, + { + id: '2_1_2', + text: 'Shanghai', + textAr: 'شنغهاي', + }, + ], + }, + { + id: '2_2', + text: 'India', + textAr: 'الهند', + items: [ + { + id: '2_2_1', + text: 'Indianapolis', + textAr: 'انديانابوليس', + }, + { + id: '2_2_2', + text: 'New Delhi', + textAr: 'نيودلهي', + }, + ], + }, + ], + }, + { + id: '3', + text: 'Australia', + textAr: 'أستراليا', + items: [ + { + id: '3_1', + text: 'Australia', + textAr: 'أستراليا', + items: [ + { + id: '3_1_1', + text: 'Canberra', + textAr: 'كانبيرا', + }, + { + id: '3_1_2', + text: 'Melbourne', + textAr: 'ملبورن', + }, + { + id: '3_1_3', + text: 'Sydney', + textAr: 'سيدني', + }, + ], + }, + ], + }, + { + id: '4', + text: 'Europe', + textAr: 'أوروبا', + items: [ + { + id: '4_1', + text: 'Germany', + textAr: 'ألمانيا', + items: [ + { + id: '4_1_1', + text: 'Berlin', + textAr: 'البرلينية', + }, + { + id: '4_1_2', + text: 'Hamburg', + textAr: 'هامبورغ', + }, + ], + }, + { + id: '4_2', + text: 'Russia', + textAr: 'روسيا', + items: [ + { + id: '4_2_1', + text: 'Moscow', + textAr: 'موسكو', + }, + { + id: '4_2_2', + text: 'Saint Petersburg', + textAr: 'سانت بطرسبرغ', + }, + ], + }, + ], + }, + { + id: '5', + text: 'North America', + textAr: 'أمريكا الشمالية', + items: [ + { + id: '5_2', + text: 'Mexico', + textAr: 'المكسيك', + items: [ + { + id: '5_2_1', + text: 'Mexico City', + textAr: 'مكسيكو سيتي', + }, + { + id: '5_2_2', + text: 'Guadalajara', + textAr: 'غوادالاخارا', + }, + ], + }, + { + id: '5_1', + text: 'United States', + textAr: 'الولايات المتحدة الأمريكية', + items: [ + { + id: '5_1_1', + text: 'New York', + textAr: 'نيويورك', + }, + { + id: '5_1_2', + text: 'Washington', + textAr: 'واشنطن', + }, + ], + }, + ], + }, + { + id: '6', + text: 'South America', + textAr: 'أمريكا الجنوبية', + items: [ + { + id: '6_1', + text: 'Brazil', + textAr: 'البرازيل', + items: [ + { + id: '6_1_1', + text: 'Brasilia', + textAr: 'برازيليا', + }, + { + id: '6_1_2', + text: 'Sao Paulo', + textAr: 'ساو باولو', + }, + ], + }, + { + id: '6_2', + text: 'Colombia', + textAr: 'كولومبيا', + items: [ + { + id: '6_2_1', + text: 'Bogota', + textAr: 'بوغوتا', + }, + { + id: '6_2_2', + text: 'Medellin', + textAr: 'ميديلين', + }, + ], + }, + ], + }, +]; +export const europeCountries = [ + { + nameAr: 'النمسا', + nameEn: 'Austria', + population: 8451900, + area: 83855.0, + capitalEn: 'Vienna', + capitalAr: 'فيينا', + }, + { + nameAr: 'بلجيكا', + nameEn: 'Belgium', + population: 11161600, + area: 30528.0, + capitalEn: 'Brussels', + capitalAr: 'بروكسل', + }, + { + nameAr: 'بلغاريا', + nameEn: 'Bulgaria', + population: 7284600, + area: 110994.0, + capitalEn: 'Sofia', + capitalAr: 'صوفيا', + }, + { + nameAr: 'كرواتيا', + nameEn: 'Croatia', + population: 4262100, + area: 56594.0, + capitalEn: 'Zagreb', + capitalAr: 'زغرب', + }, +]; +export const languageLabel = { 'aria-label': 'Language' }; diff --git a/JSDemos/Demos/Common/NavigationRightToLeftSupport/ReactJs/index.html b/JSDemos/Demos/Common/NavigationRightToLeftSupport/ReactJs/index.html new file mode 100644 index 00000000000..4d0ee54d8eb --- /dev/null +++ b/JSDemos/Demos/Common/NavigationRightToLeftSupport/ReactJs/index.html @@ -0,0 +1,44 @@ + + + + DevExtreme Demo + + + + + + + + + + + + + +
+
+
+ + diff --git a/JSDemos/Demos/Common/NavigationRightToLeftSupport/ReactJs/index.js b/JSDemos/Demos/Common/NavigationRightToLeftSupport/ReactJs/index.js new file mode 100644 index 00000000000..b853e0be824 --- /dev/null +++ b/JSDemos/Demos/Common/NavigationRightToLeftSupport/ReactJs/index.js @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App.js'; + +ReactDOM.render(, document.getElementById('app')); diff --git a/JSDemos/Demos/Common/NavigationRightToLeftSupport/ReactJs/styles.css b/JSDemos/Demos/Common/NavigationRightToLeftSupport/ReactJs/styles.css new file mode 100644 index 00000000000..e2c3944d043 --- /dev/null +++ b/JSDemos/Demos/Common/NavigationRightToLeftSupport/ReactJs/styles.css @@ -0,0 +1,25 @@ +sup { + font-size: 0.8em; + vertical-align: super; + line-height: 0; +} + +.options { + padding: 20px; + background-color: rgba(191, 191, 191, 0.15); + margin-bottom: 20px; +} + +.options .dx-fieldset { + margin: 0; +} + +.caption { + font-size: 18px; + font-weight: 500; + padding-right: 15px; +} + +.dx-theme-material .dx-accordion .dx-accordion-item-opened .dx-accordion-item-title { + padding-top: 20px; +} diff --git a/JSDemos/Demos/Drawer/LeftOrRightPosition/React/App.js b/JSDemos/Demos/Drawer/LeftOrRightPosition/React/App.tsx similarity index 85% rename from JSDemos/Demos/Drawer/LeftOrRightPosition/React/App.js rename to JSDemos/Demos/Drawer/LeftOrRightPosition/React/App.tsx index 2cfe645daf1..a6fb86c432f 100644 --- a/JSDemos/Demos/Drawer/LeftOrRightPosition/React/App.js +++ b/JSDemos/Demos/Drawer/LeftOrRightPosition/React/App.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import Drawer from 'devextreme-react/drawer'; +import Drawer, { DrawerTypes } from 'devextreme-react/drawer'; import RadioGroup from 'devextreme-react/radio-group'; import Toolbar from 'devextreme-react/toolbar'; import HTMLReactParser from 'html-react-parser'; -import { text } from './data.js'; -import NavigationList from './NavigationList.js'; +import { text } from './data.ts'; +import NavigationList from './NavigationList.tsx'; const openedStateModes = ['push', 'shrink', 'overlap']; const positions = ['left', 'right']; @@ -12,9 +12,9 @@ const revealModes = ['slide', 'expand']; const App = () => { const [opened, setOpened] = React.useState(true); - const [openedStateMode, setOpenedStateMode] = React.useState('shrink'); - const [revealMode, setRevealMode] = React.useState('slide'); - const [position, setPosition] = React.useState('left'); + const [openedStateMode, setOpenedStateMode] = React.useState('shrink'); + const [revealMode, setRevealMode] = React.useState('slide'); + const [position, setPosition] = React.useState('left'); const toolbarItems = React.useMemo(() => [{ widget: 'dxButton', @@ -39,6 +39,7 @@ const App = () => { const onOutsideClick = React.useCallback(() => { setOpened(false); + return false; }, [setOpened]); return ( diff --git a/JSDemos/Demos/Drawer/LeftOrRightPosition/React/NavigationList.js b/JSDemos/Demos/Drawer/LeftOrRightPosition/React/NavigationList.tsx similarity index 90% rename from JSDemos/Demos/Drawer/LeftOrRightPosition/React/NavigationList.js rename to JSDemos/Demos/Drawer/LeftOrRightPosition/React/NavigationList.tsx index bab30aa121c..8f6793e6bd0 100644 --- a/JSDemos/Demos/Drawer/LeftOrRightPosition/React/NavigationList.js +++ b/JSDemos/Demos/Drawer/LeftOrRightPosition/React/NavigationList.tsx @@ -1,7 +1,7 @@ import React from 'react'; import List from 'devextreme-react/list'; -import { navigation } from './data.js'; +import { navigation } from './data.ts'; function NavigationList() { return ( diff --git a/JSDemos/Demos/Drawer/LeftOrRightPosition/React/data.js b/JSDemos/Demos/Drawer/LeftOrRightPosition/React/data.ts similarity index 100% rename from JSDemos/Demos/Drawer/LeftOrRightPosition/React/data.js rename to JSDemos/Demos/Drawer/LeftOrRightPosition/React/data.ts diff --git a/JSDemos/Demos/Drawer/LeftOrRightPosition/React/index.html b/JSDemos/Demos/Drawer/LeftOrRightPosition/React/index.html index 680f807e025..4a927206bae 100644 --- a/JSDemos/Demos/Drawer/LeftOrRightPosition/React/index.html +++ b/JSDemos/Demos/Drawer/LeftOrRightPosition/React/index.html @@ -13,7 +13,7 @@ diff --git a/JSDemos/Demos/Common/NavigationOverview/React/index.js b/JSDemos/Demos/Drawer/LeftOrRightPosition/React/index.tsx similarity index 81% rename from JSDemos/Demos/Common/NavigationOverview/React/index.js rename to JSDemos/Demos/Drawer/LeftOrRightPosition/React/index.tsx index d9d7442ce76..8acbec4b617 100644 --- a/JSDemos/Demos/Common/NavigationOverview/React/index.js +++ b/JSDemos/Demos/Drawer/LeftOrRightPosition/React/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import App from './App.js'; +import App from './App.tsx'; ReactDOM.render( , diff --git a/JSDemos/Demos/Drawer/LeftOrRightPosition/ReactJs/App.js b/JSDemos/Demos/Drawer/LeftOrRightPosition/ReactJs/App.js new file mode 100644 index 00000000000..26b83bf0018 --- /dev/null +++ b/JSDemos/Demos/Drawer/LeftOrRightPosition/ReactJs/App.js @@ -0,0 +1,108 @@ +import React from 'react'; +import Drawer from 'devextreme-react/drawer'; +import RadioGroup from 'devextreme-react/radio-group'; +import Toolbar from 'devextreme-react/toolbar'; +import HTMLReactParser from 'html-react-parser'; +import { text } from './data.js'; +import NavigationList from './NavigationList.js'; + +const openedStateModes = ['push', 'shrink', 'overlap']; +const positions = ['left', 'right']; +const revealModes = ['slide', 'expand']; +const App = () => { + const [opened, setOpened] = React.useState(true); + const [openedStateMode, setOpenedStateMode] = React.useState('shrink'); + const [revealMode, setRevealMode] = React.useState('slide'); + const [position, setPosition] = React.useState('left'); + const toolbarItems = React.useMemo( + () => [ + { + widget: 'dxButton', + location: 'before', + options: { + icon: 'menu', + onClick: () => setOpened(!opened), + }, + }, + ], + [opened, setOpened], + ); + const onOpenedStateModeChanged = React.useCallback( + ({ value }) => { + setOpenedStateMode(value); + }, + [setOpenedStateMode], + ); + const onRevealModeChanged = React.useCallback( + ({ value }) => { + setRevealMode(value); + }, + [setRevealMode], + ); + const onPositionChanged = React.useCallback( + ({ value }) => { + setPosition(value); + }, + [setPosition], + ); + const onOutsideClick = React.useCallback(() => { + setOpened(false); + return false; + }, [setOpened]); + return ( + + + +
+ {HTMLReactParser(text)} +
+
+
+
Options
+
+
+ + +
+
+ + +
+ {openedStateMode !== 'push' && ( +
+ + +
+ )} +
+
+
+ ); +}; +export default App; diff --git a/JSDemos/Demos/Drawer/LeftOrRightPosition/ReactJs/NavigationList.js b/JSDemos/Demos/Drawer/LeftOrRightPosition/ReactJs/NavigationList.js new file mode 100644 index 00000000000..e5cb4ebaddd --- /dev/null +++ b/JSDemos/Demos/Drawer/LeftOrRightPosition/ReactJs/NavigationList.js @@ -0,0 +1,21 @@ +import React from 'react'; +import List from 'devextreme-react/list'; +import { navigation } from './data.js'; + +function NavigationList() { + return ( +
+ +
+ ); +} +export default NavigationList; diff --git a/JSDemos/Demos/Drawer/LeftOrRightPosition/ReactJs/data.js b/JSDemos/Demos/Drawer/LeftOrRightPosition/ReactJs/data.js new file mode 100644 index 00000000000..613ba4eab47 --- /dev/null +++ b/JSDemos/Demos/Drawer/LeftOrRightPosition/ReactJs/data.js @@ -0,0 +1,8 @@ +export const navigation = [ + { id: 1, text: 'Products', icon: 'product' }, + { id: 2, text: 'Sales', icon: 'money' }, + { id: 3, text: 'Customers', icon: 'group' }, + { id: 4, text: 'Employees', icon: 'card' }, + { id: 5, text: 'Reports', icon: 'chart' }, +]; +export const text = '

Drawer Demo

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Penatibus et magnis dis parturient. Eget dolor morbi non arcu risus. Tristique magna sit amet purus gravida quis blandit. Auctor urna nunc id cursus metus aliquam eleifend mi in. Tellus orci ac auctor augue mauris augue neque gravida. Nullam vehicula ipsum a arcu. Nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi. Cursus in hac habitasse platea dictumst. Egestas dui id ornare arcu. Dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim.

Mauris rhoncus aenean vel elit scelerisque mauris pellentesque pulvinar. Neque volutpat ac tincidunt vitae semper quis lectus. Sed sed risus pretium quam vulputate dignissim suspendisse in. Urna nec tincidunt praesent semper feugiat nibh sed pulvinar. Ultricies lacus sed turpis tincidunt id aliquet risus feugiat. Amet cursus sit amet dictum sit amet justo donec enim. Vestibulum rhoncus est pellentesque elit ullamcorper. Id aliquet risus feugiat in ante metus dictum at.

'; diff --git a/JSDemos/Demos/Drawer/LeftOrRightPosition/ReactJs/index.html b/JSDemos/Demos/Drawer/LeftOrRightPosition/ReactJs/index.html new file mode 100644 index 00000000000..100ccd4b6d3 --- /dev/null +++ b/JSDemos/Demos/Drawer/LeftOrRightPosition/ReactJs/index.html @@ -0,0 +1,45 @@ + + + + DevExtreme Demo + + + + + + + + + + + + + + +
+
+
+ + diff --git a/JSDemos/Demos/Drawer/LeftOrRightPosition/ReactJs/index.js b/JSDemos/Demos/Drawer/LeftOrRightPosition/ReactJs/index.js new file mode 100644 index 00000000000..b853e0be824 --- /dev/null +++ b/JSDemos/Demos/Drawer/LeftOrRightPosition/ReactJs/index.js @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App.js'; + +ReactDOM.render(, document.getElementById('app')); diff --git a/JSDemos/Demos/Drawer/LeftOrRightPosition/ReactJs/styles.css b/JSDemos/Demos/Drawer/LeftOrRightPosition/ReactJs/styles.css new file mode 100644 index 00000000000..cbf1e4db62a --- /dev/null +++ b/JSDemos/Demos/Drawer/LeftOrRightPosition/ReactJs/styles.css @@ -0,0 +1,66 @@ +.dx-toolbar { + box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.12), 0 2px 2px 0 rgba(0, 0, 0, 0.08); + padding: 5px 10px; + margin-bottom: 5px; +} + +.dx-list-item-icon-container, +.dx-toolbar-before { + width: 36px; + padding-right: 0 !important; + text-align: center; +} + +.dx-list-item-content { + padding-left: 10px !important; +} + +.dx-button { + background-color: rgba(191, 191, 191, -0.15); + border: none; +} + +.panel-list { + height: 400px; +} + +.dx-drawer-expand.dx-drawer-right .panel-list { + float: right; +} + +.panel-list .dx-list-item { + border-top: 1px solid rgba(221, 221, 221, 0.2); +} + +.options { + padding: 20px; + background-color: rgba(191, 191, 191, 0.15); +} + +.options-container { + display: flex; + align-items: center; +} + +.caption { + font-size: 18px; + font-weight: 500; +} + +.option { + margin-top: 10px; + display: inline-block; + margin-right: 50px; +} + +label { + font-weight: bold; +} + +#content { + padding: 0 24px; +} + +#content h2 { + font-size: 26px; +} diff --git a/JSDemos/Demos/Drawer/TopOrBottomPosition/React/App.js b/JSDemos/Demos/Drawer/TopOrBottomPosition/React/App.tsx similarity index 85% rename from JSDemos/Demos/Drawer/TopOrBottomPosition/React/App.js rename to JSDemos/Demos/Drawer/TopOrBottomPosition/React/App.tsx index a647ffd5e9d..c18d588f324 100644 --- a/JSDemos/Demos/Drawer/TopOrBottomPosition/React/App.js +++ b/JSDemos/Demos/Drawer/TopOrBottomPosition/React/App.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import Drawer from 'devextreme-react/drawer'; +import Drawer, { DrawerTypes } from 'devextreme-react/drawer'; import RadioGroup from 'devextreme-react/radio-group'; import Toolbar from 'devextreme-react/toolbar'; import HTMLReactParser from 'html-react-parser'; -import { text } from './data.js'; -import NavigationList from './NavigationList.js'; +import { text } from './data.ts'; +import NavigationList from './NavigationList.tsx'; const RadioGroupOpenedOptions = ['push', 'shrink', 'overlap']; const RadioGroupPositionOptions = ['top', 'bottom']; @@ -12,9 +12,9 @@ const RadioGroupRevealOptions = ['slide', 'expand']; const App = () => { const [opened, setOpened] = React.useState(false); - const [openedStateMode, setOpenedStateMode] = React.useState('shrink'); - const [revealMode, setRevealMode] = React.useState('expand'); - const [position, setPosition] = React.useState('top'); + const [openedStateMode, setOpenedStateMode] = React.useState('shrink'); + const [revealMode, setRevealMode] = React.useState('expand'); + const [position, setPosition] = React.useState('top'); const toolbarItems = React.useMemo(() => [{ widget: 'dxButton', @@ -39,6 +39,7 @@ const App = () => { const onOutsideClick = React.useCallback(() => { setOpened(false); + return false; }, [setOpened]); return ( diff --git a/JSDemos/Demos/Drawer/TopOrBottomPosition/React/NavigationList.tsx b/JSDemos/Demos/Drawer/TopOrBottomPosition/React/NavigationList.tsx new file mode 100644 index 00000000000..fd35f97a84a --- /dev/null +++ b/JSDemos/Demos/Drawer/TopOrBottomPosition/React/NavigationList.tsx @@ -0,0 +1,18 @@ +import React from 'react'; + +import List from 'devextreme-react/list'; +import { navigation } from './data.ts'; + +function NavigationList() { + return ( +
+ +
+ ); +} + +export default NavigationList; diff --git a/JSDemos/Demos/Drawer/TopOrBottomPosition/React/data.js b/JSDemos/Demos/Drawer/TopOrBottomPosition/React/data.ts similarity index 100% rename from JSDemos/Demos/Drawer/TopOrBottomPosition/React/data.js rename to JSDemos/Demos/Drawer/TopOrBottomPosition/React/data.ts diff --git a/JSDemos/Demos/Drawer/TopOrBottomPosition/React/index.html b/JSDemos/Demos/Drawer/TopOrBottomPosition/React/index.html index 680f807e025..4a927206bae 100644 --- a/JSDemos/Demos/Drawer/TopOrBottomPosition/React/index.html +++ b/JSDemos/Demos/Drawer/TopOrBottomPosition/React/index.html @@ -13,7 +13,7 @@ diff --git a/JSDemos/Demos/Drawer/TopOrBottomPosition/React/index.js b/JSDemos/Demos/Drawer/TopOrBottomPosition/React/index.js deleted file mode 100644 index d9d7442ce76..00000000000 --- a/JSDemos/Demos/Drawer/TopOrBottomPosition/React/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App.js'; - -ReactDOM.render( - , - document.getElementById('app'), -); diff --git a/JSDemos/Demos/Drawer/TopOrBottomPosition/React/index.tsx b/JSDemos/Demos/Drawer/TopOrBottomPosition/React/index.tsx new file mode 100644 index 00000000000..8acbec4b617 --- /dev/null +++ b/JSDemos/Demos/Drawer/TopOrBottomPosition/React/index.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import App from './App.tsx'; + +ReactDOM.render( + , + document.getElementById('app'), +); diff --git a/JSDemos/Demos/Drawer/TopOrBottomPosition/ReactJs/App.js b/JSDemos/Demos/Drawer/TopOrBottomPosition/ReactJs/App.js new file mode 100644 index 00000000000..17fff78eaa3 --- /dev/null +++ b/JSDemos/Demos/Drawer/TopOrBottomPosition/ReactJs/App.js @@ -0,0 +1,107 @@ +import React from 'react'; +import Drawer from 'devextreme-react/drawer'; +import RadioGroup from 'devextreme-react/radio-group'; +import Toolbar from 'devextreme-react/toolbar'; +import HTMLReactParser from 'html-react-parser'; +import { text } from './data.js'; +import NavigationList from './NavigationList.js'; + +const RadioGroupOpenedOptions = ['push', 'shrink', 'overlap']; +const RadioGroupPositionOptions = ['top', 'bottom']; +const RadioGroupRevealOptions = ['slide', 'expand']; +const App = () => { + const [opened, setOpened] = React.useState(false); + const [openedStateMode, setOpenedStateMode] = React.useState('shrink'); + const [revealMode, setRevealMode] = React.useState('expand'); + const [position, setPosition] = React.useState('top'); + const toolbarItems = React.useMemo( + () => [ + { + widget: 'dxButton', + location: 'before', + options: { + icon: 'menu', + onClick: () => setOpened(!opened), + }, + }, + ], + [opened, setOpened], + ); + const onOpenedStateModeChanged = React.useCallback( + ({ value }) => { + setOpenedStateMode(value); + }, + [setOpenedStateMode], + ); + const onRevealModeChanged = React.useCallback( + ({ value }) => { + setRevealMode(value); + }, + [setRevealMode], + ); + const onPositionChanged = React.useCallback( + ({ value }) => { + setPosition(value); + }, + [setPosition], + ); + const onOutsideClick = React.useCallback(() => { + setOpened(false); + return false; + }, [setOpened]); + return ( + + + +
+ {HTMLReactParser(text)} +
+
+
+
Options
+
+ + +
{' '} +
+ + +
{' '} + {openedStateMode !== 'push' && ( +
+ + +
+ )} +
+
+ ); +}; +export default App; diff --git a/JSDemos/Demos/Drawer/TopOrBottomPosition/React/NavigationList.js b/JSDemos/Demos/Drawer/TopOrBottomPosition/ReactJs/NavigationList.js similarity index 90% rename from JSDemos/Demos/Drawer/TopOrBottomPosition/React/NavigationList.js rename to JSDemos/Demos/Drawer/TopOrBottomPosition/ReactJs/NavigationList.js index cddd9fe87d4..9ee9f95162a 100644 --- a/JSDemos/Demos/Drawer/TopOrBottomPosition/React/NavigationList.js +++ b/JSDemos/Demos/Drawer/TopOrBottomPosition/ReactJs/NavigationList.js @@ -1,5 +1,4 @@ import React from 'react'; - import List from 'devextreme-react/list'; import { navigation } from './data.js'; @@ -9,9 +8,9 @@ function NavigationList() { + height={200} + /> ); } - export default NavigationList; diff --git a/JSDemos/Demos/Drawer/TopOrBottomPosition/ReactJs/data.js b/JSDemos/Demos/Drawer/TopOrBottomPosition/ReactJs/data.js new file mode 100644 index 00000000000..1cf8414f8ed --- /dev/null +++ b/JSDemos/Demos/Drawer/TopOrBottomPosition/ReactJs/data.js @@ -0,0 +1,8 @@ +export const navigation = [ + { id: 1, text: 'Products' }, + { id: 2, text: 'Sales' }, + { id: 3, text: 'Customers' }, + { id: 4, text: 'Employees' }, + { id: 5, text: 'Reports' }, +]; +export const text = '

Drawer Demo

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Penatibus et magnis dis parturient. Eget dolor morbi non arcu risus. Tristique magna sit amet purus gravida quis blandit. Auctor urna nunc id cursus metus aliquam eleifend mi in. Tellus orci ac auctor augue mauris augue neque gravida. Nullam vehicula ipsum a arcu. Nullam ac tortor vitae purus faucibus ornare suspendisse sed nisi. Cursus in hac habitasse platea dictumst. Egestas dui id ornare arcu. Dictumst vestibulum rhoncus est pellentesque elit ullamcorper dignissim.

Mauris rhoncus aenean vel elit scelerisque mauris pellentesque pulvinar. Neque volutpat ac tincidunt vitae semper quis lectus. Sed sed risus pretium quam vulputate dignissim suspendisse in. Urna nec tincidunt praesent semper feugiat nibh sed pulvinar. Ultricies lacus sed turpis tincidunt id aliquet risus feugiat. Amet cursus sit amet dictum sit amet justo donec enim. Vestibulum rhoncus est pellentesque elit ullamcorper. Id aliquet risus feugiat in ante metus dictum at.

'; diff --git a/JSDemos/Demos/Drawer/TopOrBottomPosition/ReactJs/index.html b/JSDemos/Demos/Drawer/TopOrBottomPosition/ReactJs/index.html new file mode 100644 index 00000000000..100ccd4b6d3 --- /dev/null +++ b/JSDemos/Demos/Drawer/TopOrBottomPosition/ReactJs/index.html @@ -0,0 +1,45 @@ + + + + DevExtreme Demo + + + + + + + + + + + + + + +
+
+
+ + diff --git a/JSDemos/Demos/Drawer/TopOrBottomPosition/ReactJs/index.js b/JSDemos/Demos/Drawer/TopOrBottomPosition/ReactJs/index.js new file mode 100644 index 00000000000..b853e0be824 --- /dev/null +++ b/JSDemos/Demos/Drawer/TopOrBottomPosition/ReactJs/index.js @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App.js'; + +ReactDOM.render(, document.getElementById('app')); diff --git a/JSDemos/Demos/Drawer/TopOrBottomPosition/ReactJs/styles.css b/JSDemos/Demos/Drawer/TopOrBottomPosition/ReactJs/styles.css new file mode 100644 index 00000000000..8b87540b4c6 --- /dev/null +++ b/JSDemos/Demos/Drawer/TopOrBottomPosition/ReactJs/styles.css @@ -0,0 +1,71 @@ +.dx-toolbar { + box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.12), 0 2px 2px 0 rgba(0, 0, 0, 0.08); + padding: 5px 10px; + margin-bottom: 5px; +} + +.dx-list-item-icon-container, +.dx-toolbar-before { + width: 36px; + padding-right: 0 !important; + text-align: center; +} + +.dx-list-item-content { + padding-left: 10px !important; +} + +.dx-button { + background-color: rgba(191, 191, 191, -0.15); + border: none; +} + +.dx-drawer-shrink #content { + overflow: hidden; + transition: all 0.4s ease-out; + column-width: 900px; +} + +.dx-drawer-shrink.dx-drawer-opened #content { + column-width: 300px; + margin-right: -10px; +} + +.panel-list { + height: 200px; + pointer-events: none; +} + +.panel-list .dx-list-item { + text-align: center; + border-top: 1px solid rgba(221, 221, 221, 0.2); +} + +.options { + padding: 20px; + background-color: rgba(191, 191, 191, 0.15); +} + +.caption { + font-size: 18px; + font-weight: 500; +} + +.option { + margin-top: 10px; + display: inline-block; + margin-right: 50px; +} + +label { + font-weight: bold; +} + +#content { + height: 100%; + padding: 10px 20px; +} + +#content h2 { + font-size: 26px; +} diff --git a/JSDemos/Demos/Menu/Overview/React/App.tsx b/JSDemos/Demos/Menu/Overview/React/App.tsx new file mode 100644 index 00000000000..0ae95cb1361 --- /dev/null +++ b/JSDemos/Demos/Menu/Overview/React/App.tsx @@ -0,0 +1,107 @@ +import React from 'react'; +import Menu, { MenuTypes } from 'devextreme-react/menu'; +import SelectBox, { SelectBoxTypes } from 'devextreme-react/select-box'; +import CheckBox, { CheckBoxTypes } from 'devextreme-react/check-box'; +import service, { ProductItemType } from './data.ts'; + +const orientations = ['horizontal', 'vertical']; +const orientationLabel = { 'aria-label': 'Orientation' }; +const showSubmenuModeLabel = { 'aria-label': 'Show Submenu Mode' }; +const products = service.getProducts(); + +interface showSubmenuModesType { + name: MenuTypes.SubmenuShowMode, + delay: { + show: number, + hide: number + } +} +const showSubmenuModes: showSubmenuModesType[] = [ + { + name: 'onHover', + delay: { show: 0, hide: 500 }, + }, + { + name: 'onClick', + delay: { show: 0, hide: 300 }, + }, +]; + +const App = () => { + const [showFirstSubmenuModes, setShowFirstSubmenuModes] = React.useState(showSubmenuModes[1]); + const [orientation, setOrientation] = React.useState('horizontal'); + const [hideSubmenuOnMouseLeave, setHideSubmenuOnMouseLeave] = React.useState(false); + const [currentProduct, setCurrentProduct] = React.useState(null); + + const itemClick = React.useCallback((e: MenuTypes.ItemClickEvent & { itemData: ProductItemType }) => { + if (e.itemData.price) { + setCurrentProduct(e.itemData); + } + }, [setCurrentProduct]); + + const showSubmenuModeChanged = React.useCallback((e: SelectBoxTypes.ValueChangedEvent) => { + setShowFirstSubmenuModes(e.value); + }, [setShowFirstSubmenuModes]); + + const orientationChanged = React.useCallback((e: SelectBoxTypes.ValueChangedEvent) => { + setOrientation(e.value); + }, [setOrientation]); + + const hideSubmenuOnMouseLeaveChanged = React.useCallback((e: CheckBoxTypes.ValueChangedEvent) => { + setHideSubmenuOnMouseLeave(e.value); + }, [setHideSubmenuOnMouseLeave]); + + return ( +
+
+
Catalog:
+ + {currentProduct && ( +
+ +
{currentProduct.name}
+
{`$${currentProduct.price}`}
+
+ )} +
+
+
Options
+
+
Show First Submenu Mode
+ +
+
+
Orientation
+ +
+
+ +
+
+
+ ); +}; + +export default App; diff --git a/JSDemos/Demos/Menu/Overview/React/data.js b/JSDemos/Demos/Menu/Overview/React/data.ts similarity index 88% rename from JSDemos/Demos/Menu/Overview/React/data.js rename to JSDemos/Demos/Menu/Overview/React/data.ts index 04499931146..08b1d404456 100644 --- a/JSDemos/Demos/Menu/Overview/React/data.js +++ b/JSDemos/Demos/Menu/Overview/React/data.ts @@ -85,8 +85,21 @@ const products = [{ }], }]; +export interface ProductItemType { + id: string, + name: string, + price: number, + icon: string, +} + +export interface ProductType { + id: string, + name: string, + items: (ProductItemType | ProductType)[], +} + export default { - getProducts() { + getProducts(): ProductType[] { return products; }, }; diff --git a/JSDemos/Demos/Menu/Overview/React/index.html b/JSDemos/Demos/Menu/Overview/React/index.html index fb33a47d3fb..7aef756bcb4 100644 --- a/JSDemos/Demos/Menu/Overview/React/index.html +++ b/JSDemos/Demos/Menu/Overview/React/index.html @@ -12,7 +12,7 @@ diff --git a/JSDemos/Demos/Menu/Overview/React/index.js b/JSDemos/Demos/Menu/Overview/React/index.js deleted file mode 100644 index d9d7442ce76..00000000000 --- a/JSDemos/Demos/Menu/Overview/React/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App.js'; - -ReactDOM.render( - , - document.getElementById('app'), -); diff --git a/JSDemos/Demos/Menu/Overview/React/index.tsx b/JSDemos/Demos/Menu/Overview/React/index.tsx new file mode 100644 index 00000000000..8acbec4b617 --- /dev/null +++ b/JSDemos/Demos/Menu/Overview/React/index.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import App from './App.tsx'; + +ReactDOM.render( + , + document.getElementById('app'), +); diff --git a/JSDemos/Demos/Menu/Overview/React/App.js b/JSDemos/Demos/Menu/Overview/ReactJs/App.js similarity index 80% rename from JSDemos/Demos/Menu/Overview/React/App.js rename to JSDemos/Demos/Menu/Overview/ReactJs/App.js index e4fbfd7bf9a..53134ffcb64 100644 --- a/JSDemos/Demos/Menu/Overview/React/App.js +++ b/JSDemos/Demos/Menu/Overview/ReactJs/App.js @@ -18,31 +18,37 @@ const showSubmenuModes = [ delay: { show: 0, hide: 300 }, }, ]; - const App = () => { const [showFirstSubmenuModes, setShowFirstSubmenuModes] = React.useState(showSubmenuModes[1]); const [orientation, setOrientation] = React.useState('horizontal'); const [hideSubmenuOnMouseLeave, setHideSubmenuOnMouseLeave] = React.useState(false); const [currentProduct, setCurrentProduct] = React.useState(null); - - const itemClick = React.useCallback((e) => { - if (e.itemData.price) { - setCurrentProduct(e.itemData); - } - }, [setCurrentProduct]); - - const showSubmenuModeChanged = React.useCallback((e) => { - setShowFirstSubmenuModes(e.value); - }, [setShowFirstSubmenuModes]); - - const orientationChanged = React.useCallback((e) => { - setOrientation(e.value); - }, [setOrientation]); - - const hideSubmenuOnMouseLeaveChanged = React.useCallback((e) => { - setHideSubmenuOnMouseLeave(e.value); - }, [setHideSubmenuOnMouseLeave]); - + const itemClick = React.useCallback( + (e) => { + if (e.itemData.price) { + setCurrentProduct(e.itemData); + } + }, + [setCurrentProduct], + ); + const showSubmenuModeChanged = React.useCallback( + (e) => { + setShowFirstSubmenuModes(e.value); + }, + [setShowFirstSubmenuModes], + ); + const orientationChanged = React.useCallback( + (e) => { + setOrientation(e.value); + }, + [setOrientation], + ); + const hideSubmenuOnMouseLeaveChanged = React.useCallback( + (e) => { + setHideSubmenuOnMouseLeave(e.value); + }, + [setHideSubmenuOnMouseLeave], + ); return (
@@ -95,5 +101,4 @@ const App = () => {
); }; - export default App; diff --git a/JSDemos/Demos/Menu/Overview/ReactJs/data.js b/JSDemos/Demos/Menu/Overview/ReactJs/data.js new file mode 100644 index 00000000000..6ba62b5a70f --- /dev/null +++ b/JSDemos/Demos/Menu/Overview/ReactJs/data.js @@ -0,0 +1,116 @@ +const products = [ + { + id: '1', + name: 'Video Players', + items: [ + { + id: '1_1', + name: 'HD Video Player', + price: 220, + icon: '../../../../images/products/1.png', + }, + { + id: '1_2', + name: 'SuperHD Video Player', + icon: '../../../../images/products/2.png', + price: 270, + }, + ], + }, + { + id: '2', + name: 'Televisions', + items: [ + { + id: '2_1', + name: 'SuperLCD 42', + icon: '../../../../images/products/7.png', + price: 1200, + }, + { + id: '2_2', + name: 'SuperLED 42', + icon: '../../../../images/products/5.png', + price: 1450, + }, + { + id: '2_3', + name: 'SuperLED 50', + icon: '../../../../images/products/4.png', + price: 1600, + }, + { + id: '2_4', + name: 'SuperLCD 55 (Not available)', + icon: '../../../../images/products/6.png', + price: 1350, + disabled: true, + }, + { + id: '2_5', + name: 'SuperLCD 70', + icon: '../../../../images/products/9.png', + price: 4000, + }, + ], + }, + { + id: '3', + name: 'Monitors', + items: [ + { + id: '3_1', + name: '19"', + items: [ + { + id: '3_1_1', + name: 'DesktopLCD 19', + icon: '../../../../images/products/10.png', + price: 160, + }, + ], + }, + { + id: '3_2', + name: '21"', + items: [ + { + id: '3_2_1', + name: 'DesktopLCD 21', + icon: '../../../../images/products/12.png', + price: 170, + }, + { + id: '3_2_2', + name: 'DesktopLED 21', + icon: '../../../../images/products/13.png', + price: 175, + }, + ], + }, + ], + }, + { + id: '4', + name: 'Projectors', + items: [ + { + id: '4_1', + name: 'Projector Plus', + icon: '../../../../images/products/14.png', + price: 550, + }, + { + id: '4_2', + name: 'Projector PlusHD', + icon: '../../../../images/products/15.png', + price: 750, + }, + ], + }, +]; +export default { + getProducts() { + return products; + }, +}; diff --git a/JSDemos/Demos/Menu/Overview/ReactJs/index.html b/JSDemos/Demos/Menu/Overview/ReactJs/index.html new file mode 100644 index 00000000000..4d0ee54d8eb --- /dev/null +++ b/JSDemos/Demos/Menu/Overview/ReactJs/index.html @@ -0,0 +1,44 @@ + + + + DevExtreme Demo + + + + + + + + + + + + + +
+
+
+ + diff --git a/JSDemos/Demos/Menu/Overview/ReactJs/index.js b/JSDemos/Demos/Menu/Overview/ReactJs/index.js new file mode 100644 index 00000000000..b853e0be824 --- /dev/null +++ b/JSDemos/Demos/Menu/Overview/ReactJs/index.js @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App.js'; + +ReactDOM.render(, document.getElementById('app')); diff --git a/JSDemos/Demos/Menu/Overview/ReactJs/styles.css b/JSDemos/Demos/Menu/Overview/ReactJs/styles.css new file mode 100644 index 00000000000..9743854ec0f --- /dev/null +++ b/JSDemos/Demos/Menu/Overview/ReactJs/styles.css @@ -0,0 +1,60 @@ +.form { + margin-left: 3px; +} + +.form > div:first-child { + margin-right: 320px; +} + +.label { + font-size: 22px; + padding-bottom: 24px; +} + +#product-details { + width: 400px; + height: 400px; + margin: 20px auto 0; +} + +#product-details > img { + height: 300px; + width: 400px; +} + +#product-details > .name { + text-align: center; + font-size: 20px; +} + +#product-details > .price { + text-align: center; + font-size: 24px; +} + +.dark #product-details > div { + color: #f0f0f0; +} + +.options { + padding: 20px; + position: absolute; + bottom: 0; + right: 0; + width: 260px; + top: 0; + background-color: rgba(191, 191, 191, 0.15); +} + +.caption { + font-size: 18px; + font-weight: 500; +} + +.option { + margin-top: 10px; +} + +.hidden { + visibility: hidden; +} diff --git a/JSDemos/Demos/MultiView/Overview/React/App.js b/JSDemos/Demos/MultiView/Overview/React/App.tsx similarity index 74% rename from JSDemos/Demos/MultiView/Overview/React/App.js rename to JSDemos/Demos/MultiView/Overview/React/App.tsx index 817a1f783cc..9d303c350a6 100644 --- a/JSDemos/Demos/MultiView/Overview/React/App.js +++ b/JSDemos/Demos/MultiView/Overview/React/App.tsx @@ -1,25 +1,25 @@ import React from 'react'; -import CheckBox from 'devextreme-react/check-box'; -import MultiView from 'devextreme-react/multi-view'; -import { multiViewItems as companies } from './data.js'; -import CompanyItem from './CompanyItem.js'; +import CheckBox, { CheckBoxTypes } from 'devextreme-react/check-box'; +import MultiView, { MultiViewTypes } from 'devextreme-react/multi-view'; +import { multiViewItems as companies } from './data.ts'; +import CompanyItem from './CompanyItem.tsx'; const App = () => { const [animationEnabled, setAnimationEnabled] = React.useState(true); const [loop, setLoop] = React.useState(false); const [selectedIndex, setSelectedIndex] = React.useState(0); - const onSelectionChanged = React.useCallback((args) => { + const onSelectionChanged = React.useCallback((args: MultiViewTypes.OptionChangedEvent) => { if (args.name === 'selectedIndex') { setSelectedIndex(args.value); } }, [setSelectedIndex]); - const onLoopChanged = React.useCallback((args) => { + const onLoopChanged = React.useCallback((args: CheckBoxTypes.ValueChangedEvent) => { setLoop(args.value); }, [setLoop]); - const onAnimationEnabledChanged = React.useCallback((args) => { + const onAnimationEnabledChanged = React.useCallback((args: CheckBoxTypes.ValueChangedEvent) => { setAnimationEnabled(args.value); }, [setAnimationEnabled]); diff --git a/JSDemos/Demos/MultiView/Overview/React/CompanyItem.js b/JSDemos/Demos/MultiView/Overview/React/CompanyItem.tsx similarity index 100% rename from JSDemos/Demos/MultiView/Overview/React/CompanyItem.js rename to JSDemos/Demos/MultiView/Overview/React/CompanyItem.tsx diff --git a/JSDemos/Demos/MultiView/Overview/React/data.js b/JSDemos/Demos/MultiView/Overview/React/data.ts similarity index 100% rename from JSDemos/Demos/MultiView/Overview/React/data.js rename to JSDemos/Demos/MultiView/Overview/React/data.ts diff --git a/JSDemos/Demos/MultiView/Overview/React/index.html b/JSDemos/Demos/MultiView/Overview/React/index.html index fb33a47d3fb..7aef756bcb4 100644 --- a/JSDemos/Demos/MultiView/Overview/React/index.html +++ b/JSDemos/Demos/MultiView/Overview/React/index.html @@ -12,7 +12,7 @@ diff --git a/JSDemos/Demos/MultiView/Overview/React/index.js b/JSDemos/Demos/MultiView/Overview/React/index.js deleted file mode 100644 index d9d7442ce76..00000000000 --- a/JSDemos/Demos/MultiView/Overview/React/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App.js'; - -ReactDOM.render( - , - document.getElementById('app'), -); diff --git a/JSDemos/Demos/MultiView/Overview/React/index.tsx b/JSDemos/Demos/MultiView/Overview/React/index.tsx new file mode 100644 index 00000000000..8acbec4b617 --- /dev/null +++ b/JSDemos/Demos/MultiView/Overview/React/index.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import App from './App.tsx'; + +ReactDOM.render( + , + document.getElementById('app'), +); diff --git a/JSDemos/Demos/MultiView/Overview/ReactJs/App.js b/JSDemos/Demos/MultiView/Overview/ReactJs/App.js new file mode 100644 index 00000000000..810a38c3ff3 --- /dev/null +++ b/JSDemos/Demos/MultiView/Overview/ReactJs/App.js @@ -0,0 +1,66 @@ +import React from 'react'; +import CheckBox from 'devextreme-react/check-box'; +import MultiView from 'devextreme-react/multi-view'; +import { multiViewItems as companies } from './data.js'; +import CompanyItem from './CompanyItem.js'; + +const App = () => { + const [animationEnabled, setAnimationEnabled] = React.useState(true); + const [loop, setLoop] = React.useState(false); + const [selectedIndex, setSelectedIndex] = React.useState(0); + const onSelectionChanged = React.useCallback( + (args) => { + if (args.name === 'selectedIndex') { + setSelectedIndex(args.value); + } + }, + [setSelectedIndex], + ); + const onLoopChanged = React.useCallback( + (args) => { + setLoop(args.value); + }, + [setLoop], + ); + const onAnimationEnabledChanged = React.useCallback( + (args) => { + setAnimationEnabled(args.value); + }, + [setAnimationEnabled], + ); + return ( +
+
+ Item {selectedIndex + 1} of {companies.length}:{' '} + Swipe the view horizontally to switch to the next view. +
+ +
+
Options
+
+ +
+
+ +
+
+
+ ); +}; +export default App; diff --git a/JSDemos/Demos/MultiView/Overview/ReactJs/CompanyItem.js b/JSDemos/Demos/MultiView/Overview/ReactJs/CompanyItem.js new file mode 100644 index 00000000000..fe904402e14 --- /dev/null +++ b/JSDemos/Demos/MultiView/Overview/ReactJs/CompanyItem.js @@ -0,0 +1,39 @@ +import React from 'react'; + +function CompanyItem({ data }) { + const company = data; + return ( +
+
+
{company.CompanyName}
+
+

+ {company.City} ({company.State}) +

+

+ {company.Zipcode} + {company.Address} +

+
+
+

+ Phone: {company.Phone} +

+

+ Fax: {company.Fax} +

+

+ Website:{' '} + + {company.Website} + +

+
+
+
+ ); +} +export default CompanyItem; diff --git a/JSDemos/Demos/MultiView/Overview/ReactJs/data.js b/JSDemos/Demos/MultiView/Overview/ReactJs/data.js new file mode 100644 index 00000000000..b5adca5592c --- /dev/null +++ b/JSDemos/Demos/MultiView/Overview/ReactJs/data.js @@ -0,0 +1,46 @@ +export const multiViewItems = [ + { + ID: 1, + CompanyName: 'SuprMart', + Address: '702 SW 8th Street', + City: 'Bentonville', + State: 'Arkansas', + Zipcode: 72716, + Phone: '(800) 555-2797', + Fax: '(800) 555-2171', + Website: 'http://www.nowebsitesupermart.com', + }, + { + ID: 2, + CompanyName: "El'Depot", + Address: '2455 Paces Ferry Road NW', + City: 'Atlanta', + State: 'Georgia', + Zipcode: 30339, + Phone: '(800) 595-3232', + Fax: '(800) 595-3231', + Website: 'http://www.nowebsitedepot.com', + }, + { + ID: 3, + CompanyName: 'K&S Music', + Address: '1000 Nicllet Mall', + City: 'Minneapolis', + State: 'Minnesota', + Zipcode: 55403, + Phone: '(612) 304-6073', + Fax: '(612) 304-6074', + Website: 'http://www.nowebsitemusic.com', + }, + { + ID: 4, + CompanyName: 'Tom Club', + Address: '999 Lake Drive', + City: 'Issaquah', + State: 'Washington', + Zipcode: 98027, + Phone: '(800) 955-2292', + Fax: '(800) 955-2293', + Website: 'http://www.nowebsitetomsclub.com', + }, +]; diff --git a/JSDemos/Demos/MultiView/Overview/ReactJs/index.html b/JSDemos/Demos/MultiView/Overview/ReactJs/index.html new file mode 100644 index 00000000000..4d0ee54d8eb --- /dev/null +++ b/JSDemos/Demos/MultiView/Overview/ReactJs/index.html @@ -0,0 +1,44 @@ + + + + DevExtreme Demo + + + + + + + + + + + + + +
+
+
+ + diff --git a/JSDemos/Demos/MultiView/Overview/ReactJs/index.js b/JSDemos/Demos/MultiView/Overview/ReactJs/index.js new file mode 100644 index 00000000000..b853e0be824 --- /dev/null +++ b/JSDemos/Demos/MultiView/Overview/ReactJs/index.js @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App.js'; + +ReactDOM.render(, document.getElementById('app')); diff --git a/JSDemos/Demos/MultiView/Overview/ReactJs/styles.css b/JSDemos/Demos/MultiView/Overview/ReactJs/styles.css new file mode 100644 index 00000000000..d7204f9c1b9 --- /dev/null +++ b/JSDemos/Demos/MultiView/Overview/ReactJs/styles.css @@ -0,0 +1,44 @@ +#multiview { + margin-top: 25px; +} + +.multiview-item { + margin: 25px; + user-select: none; + border-top: 1px solid lightgray; + border-bottom: 1px solid lightgray; + padding: 20px 0 30px; +} + +.multiview-item > div { + padding-top: 20px; +} + +#multiview > div:first-child { + padding-left: 25px; +} + +#multiview p, +#multiview .header { + margin: 0; +} + +#multiview .header { + font-size: 34px; + padding-top: 0; +} + +.options { + padding: 20px; + background-color: rgba(191, 191, 191, 0.15); + margin-top: 20px; +} + +.caption { + font-size: 18px; + font-weight: 500; +} + +.option { + margin-top: 10px; +} diff --git a/JSDemos/Demos/TabPanel/Overview/React/App.js b/JSDemos/Demos/TabPanel/Overview/React/App.tsx similarity index 97% rename from JSDemos/Demos/TabPanel/Overview/React/App.js rename to JSDemos/Demos/TabPanel/Overview/React/App.tsx index 30d902acdd3..1abf4f31642 100644 --- a/JSDemos/Demos/TabPanel/Overview/React/App.js +++ b/JSDemos/Demos/TabPanel/Overview/React/App.tsx @@ -2,7 +2,7 @@ import React from 'react'; import SelectBox from 'devextreme-react/select-box'; import CheckBox from 'devextreme-react/check-box'; import TabPanel from 'devextreme-react/tab-panel'; -import TabPanelItem from './TabPanelItem.js'; +import TabPanelItem from './TabPanelItem.tsx'; import { tabsPositionsSelectBoxLabel, @@ -13,7 +13,7 @@ import { iconPositions, navButtonsCheckBoxLabel, dataSource, -} from './data.js'; +} from './data.ts'; const App = () => { const [tabsPosition, setTabsPosition] = React.useState(tabsPositions[0]); diff --git a/JSDemos/Demos/TabPanel/Overview/React/TabPanelItem.js b/JSDemos/Demos/TabPanel/Overview/React/TabPanelItem.tsx similarity index 87% rename from JSDemos/Demos/TabPanel/Overview/React/TabPanelItem.js rename to JSDemos/Demos/TabPanel/Overview/React/TabPanelItem.tsx index 6f7ff1d7dd9..dcef42d4f2f 100644 --- a/JSDemos/Demos/TabPanel/Overview/React/TabPanelItem.js +++ b/JSDemos/Demos/TabPanel/Overview/React/TabPanelItem.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import TaskItem from './TaskItem.js'; +import TaskItem from './TaskItem.tsx'; function TabPanelItem({ data }) { const taskItems = data.tasks.map((task, index) => ); diff --git a/JSDemos/Demos/TabPanel/Overview/React/TaskItem.js b/JSDemos/Demos/TabPanel/Overview/React/TaskItem.tsx similarity index 100% rename from JSDemos/Demos/TabPanel/Overview/React/TaskItem.js rename to JSDemos/Demos/TabPanel/Overview/React/TaskItem.tsx diff --git a/JSDemos/Demos/TabPanel/Overview/React/data.js b/JSDemos/Demos/TabPanel/Overview/React/data.ts similarity index 96% rename from JSDemos/Demos/TabPanel/Overview/React/data.js rename to JSDemos/Demos/TabPanel/Overview/React/data.ts index 40814f746ce..53aea1df461 100644 --- a/JSDemos/Demos/TabPanel/Overview/React/data.js +++ b/JSDemos/Demos/TabPanel/Overview/React/data.ts @@ -1,6 +1,8 @@ +import { Position, TabsIconPosition, TabsStyle } from 'devextreme/common'; + export const tabsPositionsSelectBoxLabel = { 'aria-label': 'Tab position' }; -export const tabsPositions = [ +export const tabsPositions: Position[] = [ 'left', 'top', 'right', @@ -9,14 +11,14 @@ export const tabsPositions = [ export const stylingModesSelectBoxLabel = { 'aria-label': 'Styling mode' }; -export const stylingModes = [ +export const stylingModes: TabsStyle[] = [ 'secondary', 'primary', ]; export const iconPositionsSelectBoxLabel = { 'aria-label': 'Icon positions' }; -export const iconPositions = [ +export const iconPositions: TabsIconPosition[] = [ 'top', 'start', 'end', diff --git a/JSDemos/Demos/TabPanel/Overview/React/index.html b/JSDemos/Demos/TabPanel/Overview/React/index.html index fb33a47d3fb..7aef756bcb4 100644 --- a/JSDemos/Demos/TabPanel/Overview/React/index.html +++ b/JSDemos/Demos/TabPanel/Overview/React/index.html @@ -12,7 +12,7 @@ diff --git a/JSDemos/Demos/TabPanel/Overview/React/index.js b/JSDemos/Demos/TabPanel/Overview/React/index.js deleted file mode 100644 index d9d7442ce76..00000000000 --- a/JSDemos/Demos/TabPanel/Overview/React/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App.js'; - -ReactDOM.render( - , - document.getElementById('app'), -); diff --git a/JSDemos/Demos/TabPanel/Overview/React/index.tsx b/JSDemos/Demos/TabPanel/Overview/React/index.tsx new file mode 100644 index 00000000000..8acbec4b617 --- /dev/null +++ b/JSDemos/Demos/TabPanel/Overview/React/index.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import App from './App.tsx'; + +ReactDOM.render( + , + document.getElementById('app'), +); diff --git a/JSDemos/Demos/TabPanel/Overview/ReactJs/App.js b/JSDemos/Demos/TabPanel/Overview/ReactJs/App.js new file mode 100644 index 00000000000..004b53da59e --- /dev/null +++ b/JSDemos/Demos/TabPanel/Overview/ReactJs/App.js @@ -0,0 +1,112 @@ +import React from 'react'; +import SelectBox from 'devextreme-react/select-box'; +import CheckBox from 'devextreme-react/check-box'; +import TabPanel from 'devextreme-react/tab-panel'; +import TabPanelItem from './TabPanelItem.js'; +import { + tabsPositionsSelectBoxLabel, + tabsPositions, + stylingModesSelectBoxLabel, + stylingModes, + iconPositionsSelectBoxLabel, + iconPositions, + navButtonsCheckBoxLabel, + dataSource, +} from './data.js'; + +const App = () => { + const [tabsPosition, setTabsPosition] = React.useState(tabsPositions[0]); + const [stylingMode, setStylingMode] = React.useState(stylingModes[0]); + const [iconPosition, setIconPosition] = React.useState(iconPositions[0]); + const [showNavButtons, setShowNavButtons] = React.useState(true); + const onTabsPositionChanged = React.useCallback( + (args) => { + setTabsPosition(args.value); + }, + [setTabsPosition], + ); + const onStylingModeChanged = React.useCallback( + (args) => { + setStylingMode(args.value); + }, + [setStylingMode], + ); + const onIconPositionChanged = React.useCallback( + (args) => { + setIconPosition(args.value); + }, + [setIconPosition], + ); + const onShowNavButtonsChanged = React.useCallback( + (args) => { + setShowNavButtons(args.value); + }, + [setShowNavButtons], + ); + return ( +
+
+ +
+ +
+
Options
+ +
+
Tab position
+ + +
+ +
+
Styling mode
+ + +
+ +
+
Icon position
+ + +
+ +
+ +
+
+
+ ); +}; +export default App; diff --git a/JSDemos/Demos/TabPanel/Overview/ReactJs/TabPanelItem.js b/JSDemos/Demos/TabPanel/Overview/ReactJs/TabPanelItem.js new file mode 100644 index 00000000000..54116c216d1 --- /dev/null +++ b/JSDemos/Demos/TabPanel/Overview/ReactJs/TabPanelItem.js @@ -0,0 +1,13 @@ +import React from 'react'; +import TaskItem from './TaskItem.js'; + +function TabPanelItem({ data }) { + const taskItems = data.tasks.map((task, index) => ( + + )); + return
{taskItems}
; +} +export default TabPanelItem; diff --git a/JSDemos/Demos/TabPanel/Overview/ReactJs/TaskItem.js b/JSDemos/Demos/TabPanel/Overview/ReactJs/TaskItem.js new file mode 100644 index 00000000000..537a8031c3d --- /dev/null +++ b/JSDemos/Demos/TabPanel/Overview/ReactJs/TaskItem.js @@ -0,0 +1,14 @@ +import React from 'react'; + +function TaskItem({ prop }) { + return ( +
+ {prop.text} + + {`${prop.date} by ${prop.assignedBy}`} + + +
+ ); +} +export default TaskItem; diff --git a/JSDemos/Demos/TabPanel/Overview/ReactJs/data.js b/JSDemos/Demos/TabPanel/Overview/ReactJs/data.js new file mode 100644 index 00000000000..de1cee5c2ba --- /dev/null +++ b/JSDemos/Demos/TabPanel/Overview/ReactJs/data.js @@ -0,0 +1,230 @@ +export const tabsPositionsSelectBoxLabel = { 'aria-label': 'Tab position' }; +export const tabsPositions = ['left', 'top', 'right', 'bottom']; +export const stylingModesSelectBoxLabel = { 'aria-label': 'Styling mode' }; +export const stylingModes = ['secondary', 'primary']; +export const iconPositionsSelectBoxLabel = { 'aria-label': 'Icon positions' }; +export const iconPositions = ['top', 'start', 'end', 'bottom']; +export const navButtonsCheckBoxLabel = { 'aria-label': 'Show navigation buttons' }; +const tasks = [ + { + status: 'Not Started', + priority: 'high', + text: 'Revenue Projections', + date: '2023/09/16', + assignedBy: 'John Heart', + }, + { + status: 'Not Started', + priority: 'high', + text: 'New Brochures', + date: '2023/09/16', + assignedBy: 'Samantha Bright', + }, + { + status: 'Not Started', + priority: 'medium', + text: 'Training', + date: '2023/09/16', + assignedBy: 'Arthur Miller', + }, + { + status: 'Not Started', + priority: 'medium', + text: 'NDA', + date: '2023/09/16', + assignedBy: 'Robert Reagan', + }, + { + status: 'Not Started', + priority: 'low', + text: 'Health Insurance', + date: '2023/09/16', + assignedBy: 'Greta Sims', + }, + { + status: 'Help Needed', + priority: 'low', + text: 'TV Recall', + date: '2023/09/16', + assignedBy: 'Brett Wade', + }, + { + status: 'Help Needed', + priority: 'low', + text: 'Recall and Refund Forms', + date: '2023/09/16', + assignedBy: 'Sandra Johnson', + }, + { + status: 'Help Needed', + priority: 'high', + text: 'Shippers', + date: '2023/09/16', + assignedBy: 'Ed Holmes', + }, + { + status: 'Help Needed', + priority: 'medium', + text: 'Hardware Upgrade', + date: '2023/09/16', + assignedBy: 'Barb Banks', + }, + { + status: 'In Progress', + priority: 'medium', + text: 'Online Sales', + date: '2023/09/16', + assignedBy: 'Cindy Stanwick', + }, + { + status: 'In Progress', + priority: 'medium', + text: 'New Website Design', + date: '2023/09/16', + assignedBy: 'Sammy Hill', + }, + { + status: 'In Progress', + priority: 'low', + text: 'Bandwidth Increase', + date: '2023/09/16', + assignedBy: 'Davey Jones', + }, + { + status: 'In Progress', + priority: 'medium', + text: 'Support', + date: '2023/09/16', + assignedBy: 'Victor Norris', + }, + { + status: 'In Progress', + priority: 'low', + text: 'Training Material', + date: '2023/09/16', + assignedBy: 'John Heart', + }, + { + status: 'Deferred', + priority: 'medium', + text: 'New Database', + date: '2023/09/16', + assignedBy: 'Samantha Bright', + }, + { + status: 'Deferred', + priority: 'high', + text: 'Automation Server', + date: '2023/09/16', + assignedBy: 'Arthur Miller', + }, + { + status: 'Deferred', + priority: 'medium', + text: 'Retail Sales', + date: '2023/09/16', + assignedBy: 'Robert Reagan', + }, + { + status: 'Deferred', + priority: 'medium', + text: 'Shipping Labels', + date: '2023/09/16', + assignedBy: 'Greta Sims', + }, + { + status: 'Rejected', + priority: 'high', + text: 'Schedule Meeting with Sales Team', + date: '2023/09/16', + assignedBy: 'Sandra Johnson', + }, + { + status: 'Rejected', + priority: 'medium', + text: 'Confirm Availability for Sales Meeting', + date: '2023/09/16', + assignedBy: 'Ed Holmes', + }, + { + status: 'Rejected', + priority: 'medium', + text: 'Reschedule Sales Team Meeting', + date: '2023/09/16', + assignedBy: 'Barb Banks', + }, + { + status: 'Rejected', + priority: 'high', + text: 'Update Database with New Leads', + date: '2023/09/16', + assignedBy: 'Kevin Carter', + }, + { + status: 'Rejected', + priority: 'low', + text: 'Send Territory Sales Breakdown', + date: '2023/09/16', + assignedBy: 'Cindy Stanwick', + }, + { + status: 'Completed', + priority: 'medium', + text: 'Territory Sales Breakdown Report', + date: '2023/09/16', + assignedBy: 'Sammy Hill', + }, + { + status: 'Completed', + priority: 'low', + text: 'Return Merchandise Report', + date: '2023/09/16', + assignedBy: 'Davey Jones', + }, + { + status: 'Completed', + priority: 'high', + text: 'Staff Productivity Report', + date: '2023/09/16', + assignedBy: 'Victor Norris', + }, + { + status: 'Completed', + priority: 'medium', + text: 'Review HR Budget Company Wide', + date: '2023/09/16', + assignedBy: 'Mary Stern', + }, +]; +export const dataSource = [ + { + icon: 'description', + title: 'Not Started', + tasks: tasks.filter((item) => item.status === 'Not Started'), + }, + { + icon: 'taskhelpneeded', + title: 'Help Needed', + tasks: tasks.filter((item) => item.status === 'Help Needed'), + }, + { + icon: 'taskinprogress', + title: 'In Progress', + tasks: tasks.filter((item) => item.status === 'In Progress'), + }, + { + icon: 'taskstop', + title: 'Deferred', + tasks: tasks.filter((item) => item.status === 'Deferred'), + }, + { + icon: 'taskrejected', + title: 'Rejected', + tasks: tasks.filter((item) => item.status === 'Rejected'), + }, + { + icon: 'taskcomplete', + title: 'Completed', + tasks: tasks.filter((item) => item.status === 'Completed'), + }, +]; diff --git a/JSDemos/Demos/TabPanel/Overview/ReactJs/index.html b/JSDemos/Demos/TabPanel/Overview/ReactJs/index.html new file mode 100644 index 00000000000..4d0ee54d8eb --- /dev/null +++ b/JSDemos/Demos/TabPanel/Overview/ReactJs/index.html @@ -0,0 +1,44 @@ + + + + DevExtreme Demo + + + + + + + + + + + + + +
+
+
+ + diff --git a/JSDemos/Demos/TabPanel/Overview/ReactJs/index.js b/JSDemos/Demos/TabPanel/Overview/ReactJs/index.js new file mode 100644 index 00000000000..b853e0be824 --- /dev/null +++ b/JSDemos/Demos/TabPanel/Overview/ReactJs/index.js @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App.js'; + +ReactDOM.render(, document.getElementById('app')); diff --git a/JSDemos/Demos/TabPanel/Overview/ReactJs/styles.css b/JSDemos/Demos/TabPanel/Overview/ReactJs/styles.css new file mode 100644 index 00000000000..ff40f98567f --- /dev/null +++ b/JSDemos/Demos/TabPanel/Overview/ReactJs/styles.css @@ -0,0 +1,122 @@ +.tabpanel-demo { + display: flex; + height: 100%; + min-height: 450px; +} + +.widget-container { + display: flex; + justify-content: center; + flex-grow: 1; + min-width: 360px; + padding: 16px 32px; +} + +.dx-theme-material .widget-container { + background-color: rgba(191, 191, 191, 0.15); +} + +.dx-tabpanel-tabs-position-left .dx-tabpanel-container, +.dx-tabpanel-tabs-position-right .dx-tabpanel-container { + width: 0; +} + +.dx-viewport:not(.dx-theme-generic) .dx-tabpanel { + border-radius: 8px; + overflow: clip; +} + +.dx-tabs-vertical { + min-width: 120px; +} + +.options { + display: inline-flex; + flex-direction: column; + flex-shrink: 0; + box-sizing: border-box; + padding: 20px; + background-color: rgba(191, 191, 191, 0.15); +} + +.caption { + font-weight: 500; + font-size: 18px; +} + +.option { + margin-top: 20px; +} + +.tabpanel-item { + display: flex; + flex-direction: column; + gap: 12px; + padding: 24px; +} + +.task-item { + position: relative; + display: flex; + flex-direction: column; + justify-content: center; + width: 100%; + height: 48px; + padding: 8px 12px 8px 8px; + border-radius: 4px; + box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.15); +} + +.task-item::before { + content: ""; + position: absolute; + top: 8px; + left: 6px; + bottom: 8px; + width: 3px; + border-radius: 4px; +} + +.task-item-priority-high::before { + background-color: #e1bee7; +} + +.task-item-priority-medium::before { + background-color: #ffe0b2; +} + +.task-item-priority-low::before { + background-color: #c8e6c9; +} + +.task-item-text, +.task-item-info { + margin: 0; + padding: 0 24px 0 16px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.task-item-info { + font-size: 12px; + opacity: 0.38; +} + +.task-item-pseudo-button { + position: absolute; + right: 8px; + top: 50%; + font-size: 18px; + transform: translateY(-50%); + cursor: pointer; + opacity: 0.6; +} + +.dx-color-scheme-contrast .task-item { + border: 1px solid #fff; +} + +.dx-theme-fluent.dx-color-scheme-blue-dark .task-item { + background-color: #1f1f1f; +} diff --git a/JSDemos/Demos/TabPanel/SortableClosableTabs/React/App.js b/JSDemos/Demos/TabPanel/SortableClosableTabs/React/App.tsx similarity index 83% rename from JSDemos/Demos/TabPanel/SortableClosableTabs/React/App.js rename to JSDemos/Demos/TabPanel/SortableClosableTabs/React/App.tsx index ab2dbe7e551..cd66c77fb28 100644 --- a/JSDemos/Demos/TabPanel/SortableClosableTabs/React/App.js +++ b/JSDemos/Demos/TabPanel/SortableClosableTabs/React/App.tsx @@ -1,11 +1,11 @@ import React from 'react'; -import { Button } from 'devextreme-react'; -import { Sortable } from 'devextreme-react/sortable'; -import TabPanel from 'devextreme-react/tab-panel'; +import Button from 'devextreme-react/button'; +import Sortable, { SortableTypes } from 'devextreme-react/sortable'; +import TabPanel, { TabPanelTypes } from 'devextreme-react/tab-panel'; import 'devextreme/data/odata/store'; -import service from './data.js'; -import EmployeeTemplate from './EmployeeTemplate.js'; +import service from './data.ts'; +import EmployeeTemplate from './EmployeeTemplate.tsx'; const allEmployees = service.getEmployees(); @@ -48,15 +48,15 @@ function App() { ), [employees, closeButtonHandler]); - const onSelectionChanged = React.useCallback((args) => { + const onSelectionChanged = React.useCallback((args: TabPanelTypes.SelectionChangedEvent) => { setSelectedItem(args.addedItems[0]); }, [setSelectedItem]); - const onTabDragStart = React.useCallback((e) => { + const onTabDragStart = React.useCallback((e: SortableTypes.DragStartEvent) => { e.itemData = e.fromData[e.fromIndex]; }, []); - const onTabDrop = React.useCallback((e) => { + const onTabDrop = React.useCallback((e: SortableTypes.ReorderEvent) => { const newEmployees = [...employees]; newEmployees.splice(e.fromIndex, 1); diff --git a/JSDemos/Demos/TabPanel/SortableClosableTabs/React/EmployeeTemplate.tsx b/JSDemos/Demos/TabPanel/SortableClosableTabs/React/EmployeeTemplate.tsx new file mode 100644 index 00000000000..74a903889cd --- /dev/null +++ b/JSDemos/Demos/TabPanel/SortableClosableTabs/React/EmployeeTemplate.tsx @@ -0,0 +1,43 @@ +import React from 'react'; +import { List } from 'devextreme-react/list'; +import service from './data.ts'; + +function itemRender(data) { + return
{data.Subject}
; +} + +function EmployeeTemplate(props: { data: { ID?: any; FirstName?: any; LastName?: any; Picture?: any; Position?: any; Notes?: any; }; }) { + const tasks = service + .getTasks() + .filter((task: { EmployeeID: any; }) => task.EmployeeID === props.data.ID); + const { + FirstName, LastName, Picture, Position, Notes, + } = props.data; + const completedTasks = tasks.filter((task: { Status: string; }) => task.Status === 'Completed'); + + return ( + +
+ {`${FirstName} +

+ {`Position: ${Position}`} +
+ {Notes} +

+
+
{`${FirstName} ${LastName}'s Tasks:`}
+
+ +
+
+ ); +} + +export default EmployeeTemplate; diff --git a/JSDemos/Demos/TabPanel/SortableClosableTabs/React/data.js b/JSDemos/Demos/TabPanel/SortableClosableTabs/React/data.ts similarity index 100% rename from JSDemos/Demos/TabPanel/SortableClosableTabs/React/data.js rename to JSDemos/Demos/TabPanel/SortableClosableTabs/React/data.ts diff --git a/JSDemos/Demos/TabPanel/SortableClosableTabs/React/index.html b/JSDemos/Demos/TabPanel/SortableClosableTabs/React/index.html index fb33a47d3fb..7aef756bcb4 100644 --- a/JSDemos/Demos/TabPanel/SortableClosableTabs/React/index.html +++ b/JSDemos/Demos/TabPanel/SortableClosableTabs/React/index.html @@ -12,7 +12,7 @@ diff --git a/JSDemos/Demos/TabPanel/SortableClosableTabs/React/index.js b/JSDemos/Demos/TabPanel/SortableClosableTabs/React/index.js deleted file mode 100644 index d9d7442ce76..00000000000 --- a/JSDemos/Demos/TabPanel/SortableClosableTabs/React/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App.js'; - -ReactDOM.render( - , - document.getElementById('app'), -); diff --git a/JSDemos/Demos/TabPanel/SortableClosableTabs/React/index.tsx b/JSDemos/Demos/TabPanel/SortableClosableTabs/React/index.tsx new file mode 100644 index 00000000000..8acbec4b617 --- /dev/null +++ b/JSDemos/Demos/TabPanel/SortableClosableTabs/React/index.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import App from './App.tsx'; + +ReactDOM.render( + , + document.getElementById('app'), +); diff --git a/JSDemos/Demos/TabPanel/SortableClosableTabs/ReactJs/App.js b/JSDemos/Demos/TabPanel/SortableClosableTabs/ReactJs/App.js new file mode 100644 index 00000000000..c6b647f2957 --- /dev/null +++ b/JSDemos/Demos/TabPanel/SortableClosableTabs/ReactJs/App.js @@ -0,0 +1,105 @@ +import React from 'react'; +import Button from 'devextreme-react/button'; +import Sortable from 'devextreme-react/sortable'; +import TabPanel from 'devextreme-react/tab-panel'; +import 'devextreme/data/odata/store'; +import service from './data.js'; +import EmployeeTemplate from './EmployeeTemplate.js'; + +const allEmployees = service.getEmployees(); +function App() { + const [employees, setEmployees] = React.useState(allEmployees.slice(0, 3)); + const [selectedItem, setSelectedItem] = React.useState(allEmployees[0]); + const addButtonHandler = React.useCallback(() => { + const newItem = allEmployees.filter((employee) => employees.indexOf(employee) === -1)[0]; + setEmployees([...employees, newItem]); + setSelectedItem(newItem); + }, [employees, setEmployees, setSelectedItem]); + function disableButton() { + return employees.length === allEmployees.length; + } + const closeButtonHandler = React.useCallback( + (item) => { + const newEmployees = [...employees]; + const index = newEmployees.indexOf(item); + newEmployees.splice(index, 1); + setEmployees(newEmployees); + if (index >= newEmployees.length && index > 0) { + setSelectedItem(newEmployees[index - 1]); + } + }, + [employees, setEmployees, setSelectedItem], + ); + const renderTitle = React.useCallback( + (data) => ( + +
+ + {data.FirstName} {data.LastName} + + {employees.length >= 2 && ( + { + closeButtonHandler(data); + }} + /> + )} +
+
+ ), + [employees, closeButtonHandler], + ); + const onSelectionChanged = React.useCallback( + (args) => { + setSelectedItem(args.addedItems[0]); + }, + [setSelectedItem], + ); + const onTabDragStart = React.useCallback((e) => { + e.itemData = e.fromData[e.fromIndex]; + }, []); + const onTabDrop = React.useCallback( + (e) => { + const newEmployees = [...employees]; + newEmployees.splice(e.fromIndex, 1); + newEmployees.splice(e.toIndex, 0, e.itemData); + setEmployees(newEmployees); + }, + [employees, setEmployees], + ); + return ( + +
+
+ + + +
+ ); +} +export default App; diff --git a/JSDemos/Demos/TabPanel/SortableClosableTabs/React/EmployeeTemplate.js b/JSDemos/Demos/TabPanel/SortableClosableTabs/ReactJs/EmployeeTemplate.js similarity index 82% rename from JSDemos/Demos/TabPanel/SortableClosableTabs/React/EmployeeTemplate.js rename to JSDemos/Demos/TabPanel/SortableClosableTabs/ReactJs/EmployeeTemplate.js index c819ed5c5a6..8f6418dfc58 100644 --- a/JSDemos/Demos/TabPanel/SortableClosableTabs/React/EmployeeTemplate.js +++ b/JSDemos/Demos/TabPanel/SortableClosableTabs/ReactJs/EmployeeTemplate.js @@ -5,20 +5,20 @@ import service from './data.js'; function itemRender(data) { return
{data.Subject}
; } - function EmployeeTemplate(props) { - const tasks = service - .getTasks() - .filter((task) => task.EmployeeID === props.data.ID); + const tasks = service.getTasks().filter((task) => task.EmployeeID === props.data.ID); const { FirstName, LastName, Picture, Position, Notes, } = props.data; const completedTasks = tasks.filter((task) => task.Status === 'Completed'); - return (
- {`${FirstName} + {`${FirstName}

{`Position: ${Position}`}
@@ -39,5 +39,4 @@ function EmployeeTemplate(props) { ); } - export default EmployeeTemplate; diff --git a/JSDemos/Demos/TabPanel/SortableClosableTabs/ReactJs/data.js b/JSDemos/Demos/TabPanel/SortableClosableTabs/ReactJs/data.js new file mode 100644 index 00000000000..87b9aa32b4f --- /dev/null +++ b/JSDemos/Demos/TabPanel/SortableClosableTabs/ReactJs/data.js @@ -0,0 +1,517 @@ +const employees = [ + { + ID: 1, + FirstName: 'John', + LastName: 'Heart', + Prefix: 'Mr.', + Position: 'CEO', + Picture: '../../../../images/employees/01.png', + BirthDate: '1964/03/16', + HireDate: '1995/01/15', + Notes: + 'John has been in the Audio/Video industry since 1990. He has led DevAv as its CEO since 2003. When not working hard as the CEO, John loves to golf and bowl. He once bowled a perfect game of 300.', + Address: '351 S Hill St.', + State: 'California', + City: 'Los Angeles', + }, + { + ID: 2, + FirstName: 'Olivia', + LastName: 'Peyton', + Prefix: 'Mrs.', + Position: 'Sales Assistant', + Picture: '../../../../images/employees/09.png', + BirthDate: '1981/06/03', + HireDate: '2012/05/14', + Notes: + 'Olivia loves to sell. She has been selling DevAV products since 2012. Olivia was homecoming queen in high school. She is expecting her first child in 6 months. Good Luck Olivia.', + Address: '807 W Paseo Del Mar', + State: 'California', + City: 'Los Angeles', + }, + { + ID: 3, + FirstName: 'Robert', + LastName: 'Reagan', + Prefix: 'Mr.', + Position: 'CMO', + Picture: '../../../../images/employees/03.png', + BirthDate: '1974/09/07', + HireDate: '2002/11/08', + Notes: + 'Robert was recently voted the CMO of the year by CMO Magazine. He is a proud member of the DevAV Management Team. Robert is a championship BBQ chef, so when you get the chance ask him for his secret recipe.', + Address: '4 Westmoreland Pl.', + State: 'Arkansas', + City: 'Bentonville', + }, + { + ID: 4, + FirstName: 'Greta', + LastName: 'Sims', + Prefix: 'Ms.', + Position: 'HR Manager', + Picture: '../../../../images/employees/04.png', + BirthDate: '1977/11/22', + HireDate: '1998/04/23', + Notes: + "Greta has been DevAV's HR Manager since 2003. She joined DevAV from Sonee Corp. Greta is currently training for the NYC marathon. Her best marathon time is 4 hours. Go Greta.", + Address: '1700 S Grandview Dr.', + State: 'Georgia', + City: 'Atlanta', + }, + { + ID: 5, + FirstName: 'Brett', + LastName: 'Wade', + Prefix: 'Mr.', + Position: 'IT Manager', + Picture: '../../../../images/employees/05.png', + BirthDate: '1968/12/01', + HireDate: '2009/03/06', + Notes: + 'Brett came to DevAv from Microsoft and has led our IT department since 2012. When he is not working hard for DevAV, he coaches Little League (he was a high school pitcher).', + Address: '1120 Old Mill Rd.', + State: 'Idaho', + City: 'Boise', + }, + { + ID: 6, + FirstName: 'Sandra', + LastName: 'Johnson', + Prefix: 'Mrs.', + Position: 'Controller', + Picture: '../../../../images/employees/06.png', + BirthDate: '1974/11/15', + HireDate: '2005/05/11', + Notes: + "Sandra is a CPA and has been our controller since 2008. She loves to interact with staff so if you've not met her, be certain to say hi. Sandra has 2 daughters both of whom are accomplished gymnasts.", + Address: '4600 N Virginia Rd.', + State: 'Utah', + City: 'Beaver', + }, + { + ID: 7, + FirstName: 'Kevin', + LastName: 'Carter', + Prefix: 'Mr.', + Position: 'Shipping Manager', + Picture: '../../../../images/employees/07.png', + BirthDate: '1978/01/09', + HireDate: '2009/08/11', + Notes: + 'Kevin is our hard-working shipping manager and has been helping that department work like clockwork for 18 months. When not in the office, he is usually on the basketball court playing pick-up games.', + Address: '424 N Main St.', + State: 'California', + City: 'San Diego', + }, + { + ID: 8, + FirstName: 'Cynthia', + LastName: 'Stanwick', + Prefix: 'Ms.', + Position: 'HR Assistant', + Picture: '../../../../images/employees/08.png', + BirthDate: '1985/06/05', + HireDate: '2008/03/24', + Notes: + 'Cindy joined us in 2008 and has been in the HR department for 2 years. She was recently awarded employee of the month. Way to go Cindy!', + Address: '2211 Bonita Dr.', + State: 'Arkansas', + City: 'Little Rock', + }, + { + ID: 9, + FirstName: 'Kent', + LastName: 'Samuelson', + Prefix: 'Dr.', + Position: 'Ombudsman', + Picture: '../../../../images/employees/02.png', + BirthDate: '1972/09/11', + HireDate: '2009/04/22', + Notes: + 'As our ombudsman, Kent is on the front-lines solving customer problems and helping our partners address issues out in the field. He is a classically trained musician and is a member of the Chamber Orchestra.', + Address: '12100 Mora Dr', + State: 'Missouri', + City: 'St. Louis', + }, +]; +const tasks = [ + { + ID: 1, + Subject: 'Prepare 2013 Financial', + StartDate: '2013/01/15', + DueDate: '2013/01/31', + Status: 'Completed', + Priority: 'High', + Completion: 100, + EmployeeID: 8, + }, + { + ID: 2, + Subject: 'Prepare 3013 Marketing Plan', + StartDate: '2013/01/01', + DueDate: '2013/01/31', + Status: 'Completed', + Priority: 'High', + Completion: 100, + EmployeeID: 5, + }, + { + ID: 3, + Subject: 'Update Personnel Files', + StartDate: '2013/02/03', + DueDate: '2013/02/28', + Status: 'Completed', + Priority: 'High', + Completion: 100, + EmployeeID: 2, + }, + { + ID: 4, + Subject: 'Review Health Insurance Options Under the Affordable Care Act', + StartDate: '2013/02/12', + DueDate: '2013/04/25', + Status: 'In Progress', + Priority: 'High', + Completion: 50, + EmployeeID: 2, + }, + { + ID: 5, + Subject: 'Choose between PPO and HMO Health Plan', + StartDate: '2013/02/15', + DueDate: '2013/04/15', + Status: 'In Progress', + Priority: 'High', + Completion: 75, + EmployeeID: 1, + }, + { + ID: 6, + Subject: 'Google AdWords Strategy', + StartDate: '2013/02/16', + DueDate: '2013/02/28', + Status: 'Completed', + Priority: 'High', + Completion: 100, + EmployeeID: 1, + }, + { + ID: 7, + Subject: 'New Brochures', + StartDate: '2013/02/17', + DueDate: '2013/02/24', + Status: 'Completed', + Priority: 'Normal', + Completion: 100, + EmployeeID: 1, + }, + { + ID: 11, + Subject: 'Rollout of New Website and Marketing Brochures', + StartDate: '2013/02/20', + DueDate: '2013/02/28', + Status: 'Completed', + Priority: 'High', + Completion: 100, + EmployeeID: 5, + }, + { + ID: 12, + Subject: 'Update Sales Strategy Documents', + StartDate: '2013/02/20', + DueDate: '2013/02/22', + Status: 'Completed', + Priority: 'Normal', + Completion: 100, + EmployeeID: 9, + }, + { + ID: 15, + Subject: 'Review 2012 Sales Report and Approve 2013 Plans', + StartDate: '2013/02/23', + DueDate: '2013/02/28', + Status: 'Completed', + Priority: 'Normal', + Completion: 100, + EmployeeID: 5, + }, + { + ID: 16, + Subject: 'Deliver R&D Plans for 2013', + StartDate: '2013/03/01', + DueDate: '2013/03/10', + Status: 'Completed', + Priority: 'High', + Completion: 100, + EmployeeID: 3, + }, + { + ID: 20, + Subject: 'Approve Hiring of John Jeffers', + StartDate: '2013/03/02', + DueDate: '2013/03/12', + Status: 'Completed', + Priority: 'Normal', + Completion: 100, + EmployeeID: 4, + }, + { + ID: 20, + Subject: 'Approve Hiring of John Jeffers', + StartDate: '2013/03/02', + DueDate: '2013/03/12', + Status: 'Completed', + Priority: 'Normal', + Completion: 100, + EmployeeID: 6, + }, + { + ID: 21, + Subject: 'Non-Compete Agreements', + StartDate: '2013/03/12', + DueDate: '2013/03/14', + Status: 'Completed', + Priority: 'Low', + Completion: 100, + EmployeeID: 2, + }, + { + ID: 22, + Subject: 'Update NDA Agreement', + StartDate: '2013/03/14', + DueDate: '2013/03/16', + Status: 'Completed', + Priority: 'High', + Completion: 100, + EmployeeID: 1, + }, + { + ID: 23, + Subject: 'Update Employee Files with New NDA', + StartDate: '2013/03/16', + DueDate: '2013/03/26', + Status: 'Need Assistance', + Priority: 'Normal', + Completion: 90, + EmployeeID: 4, + }, + { + ID: 24, + Subject: 'Update Employee Files with New NDA', + StartDate: '2013/03/16', + DueDate: '2013/03/26', + Status: 'Need Assistance', + Priority: 'Normal', + Completion: 90, + EmployeeID: 6, + }, + { + ID: 25, + Subject: 'Sign Updated NDA', + StartDate: '2013/03/20', + DueDate: '2013/03/25', + Status: 'Completed', + Priority: 'Urgent', + Completion: 100, + EmployeeID: 7, + }, + { + ID: 26, + Subject: 'Sign Updated NDA', + StartDate: '2013/03/20', + DueDate: '2013/03/25', + Status: 'Completed', + Priority: 'Urgent', + Completion: 100, + EmployeeID: 8, + }, + { + ID: 27, + Subject: 'Sign Updated NDA', + StartDate: '2013/03/20', + DueDate: '2013/03/25', + Status: 'Need Assistance', + Priority: 'Urgent', + Completion: 25, + EmployeeID: 9, + }, + { + ID: 35, + Subject: 'Update Revenue Projections', + StartDate: '2013/03/24', + DueDate: '2013/04/07', + Status: 'Completed', + Priority: 'Normal', + Completion: 100, + EmployeeID: 8, + }, + { + ID: 36, + Subject: 'Review Revenue Projections', + StartDate: '2013/03/25', + DueDate: '2013/04/06', + Status: 'Completed', + Priority: 'High', + Completion: 100, + EmployeeID: 9, + }, + { + ID: 40, + Subject: 'Provide New Health Insurance Docs', + StartDate: '2013/03/28', + DueDate: '2013/04/07', + Status: 'Completed', + Priority: 'Normal', + Completion: 100, + EmployeeID: 4, + }, + { + ID: 41, + Subject: 'Provide New Health Insurance Docs', + StartDate: '2013/03/28', + DueDate: '2013/04/07', + Status: 'Completed', + Priority: 'Normal', + Completion: 100, + EmployeeID: 6, + }, + { + ID: 50, + Subject: 'Give Final Approval for Refunds', + StartDate: '2013/05/05', + DueDate: '2013/05/15', + Status: 'Completed', + Priority: 'Normal', + Completion: 100, + EmployeeID: 2, + }, + { + ID: 52, + Subject: 'Review Product Recall Report by Engineering Team', + StartDate: '2013/05/17', + DueDate: '2013/05/20', + Status: 'Completed', + Priority: 'High', + Completion: 100, + EmployeeID: 1, + }, + { + ID: 55, + Subject: 'Review Overtime Report', + StartDate: '2013/06/10', + DueDate: '2013/06/14', + Status: 'Completed', + Priority: 'Normal', + Completion: 100, + EmployeeID: 7, + }, + { + ID: 60, + Subject: 'Refund Request Template', + StartDate: '2013/06/17', + DueDate: '2014/04/01', + Status: 'Deferred', + Priority: 'Normal', + Completion: 0, + EmployeeID: 9, + }, + { + ID: 71, + Subject: 'Upgrade Server Hardware', + StartDate: '2013/07/22', + DueDate: '2013/07/31', + Status: 'Completed', + Priority: 'Urgent', + Completion: 100, + EmployeeID: 7, + }, + { + ID: 72, + Subject: 'Upgrade Personal Computers', + StartDate: '2013/07/24', + DueDate: '2014/04/30', + Status: 'In Progress', + Priority: 'Normal', + Completion: 85, + EmployeeID: 7, + }, + { + ID: 74, + Subject: 'Decide on Mobile Devices to Use in the Field', + StartDate: '2013/07/30', + DueDate: '2013/08/02', + Status: 'Completed', + Priority: 'High', + Completion: 100, + EmployeeID: 3, + }, + { + ID: 78, + Subject: 'Try New Touch-Enabled WinForms Apps', + StartDate: '2013/08/11', + DueDate: '2013/08/15', + Status: 'Completed', + Priority: 'Normal', + Completion: 100, + EmployeeID: 3, + }, + { + ID: 81, + Subject: 'Review Site Up-Time Report', + StartDate: '2013/08/24', + DueDate: '2013/08/30', + Status: 'Completed', + Priority: 'Urgent', + Completion: 100, + EmployeeID: 5, + }, + { + ID: 99, + Subject: 'Submit D&B Number to ISP for Credit Approval', + StartDate: '2013/11/04', + DueDate: '2013/11/07', + Status: 'Completed', + Priority: 'High', + Completion: 100, + EmployeeID: 8, + }, + { + ID: 117, + Subject: 'Approval on Converting to New HDMI Specification', + StartDate: '2014/01/11', + DueDate: '2014/01/31', + Status: 'Deferred', + Priority: 'Normal', + Completion: 75, + EmployeeID: 3, + }, + { + ID: 138, + Subject: 'Review HR Budget Company Wide', + StartDate: '2014/03/20', + DueDate: '2014/03/25', + Status: 'In Progress', + Priority: 'Normal', + Completion: 40, + EmployeeID: 6, + }, + { + ID: 145, + Subject: 'Final Budget Review', + StartDate: '2014/03/26', + DueDate: '2014/03/27', + Status: 'In Progress', + Priority: 'High', + Completion: 25, + EmployeeID: 6, + }, +]; +export default { + getEmployees() { + return employees; + }, + getTasks() { + return tasks; + }, +}; diff --git a/JSDemos/Demos/TabPanel/SortableClosableTabs/ReactJs/index.html b/JSDemos/Demos/TabPanel/SortableClosableTabs/ReactJs/index.html new file mode 100644 index 00000000000..4d0ee54d8eb --- /dev/null +++ b/JSDemos/Demos/TabPanel/SortableClosableTabs/ReactJs/index.html @@ -0,0 +1,44 @@ + + + + DevExtreme Demo + + + + + + + + + + + + + +

+
+
+ + diff --git a/JSDemos/Demos/TabPanel/SortableClosableTabs/ReactJs/index.js b/JSDemos/Demos/TabPanel/SortableClosableTabs/ReactJs/index.js new file mode 100644 index 00000000000..b853e0be824 --- /dev/null +++ b/JSDemos/Demos/TabPanel/SortableClosableTabs/ReactJs/index.js @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App.js'; + +ReactDOM.render(, document.getElementById('app')); diff --git a/JSDemos/Demos/TabPanel/SortableClosableTabs/ReactJs/styles.css b/JSDemos/Demos/TabPanel/SortableClosableTabs/ReactJs/styles.css new file mode 100644 index 00000000000..13728ea7cea --- /dev/null +++ b/JSDemos/Demos/TabPanel/SortableClosableTabs/ReactJs/styles.css @@ -0,0 +1,76 @@ +#container { + display: flex; + justify-content: flex-end; + padding-bottom: 10px; +} + +.dx-tabs .dx-tabs-wrapper .dx-item.dx-tab { + width: auto; + padding-left: 20px; +} + +.dx-sortable-dragging .dx-tab { + box-sizing: border-box; + text-align: center; +} + +.employeeInfo .employeePhoto { + height: 100px; + float: left; + padding: 10px 20px 10px 20px; +} + +.caption { + padding: 0 0 10px 30px; + font-size: 14px; + font-weight: bold; +} + +.task-list { + padding: 0 20px; +} + +.task-list .dx-state-disabled { + opacity: 1; +} + +.task-list .dx-state-disabled .dx-list-item { + opacity: 1; +} + +.employeeInfo .employeeNotes { + min-height: 100px; + padding: 20px; + text-align: justify; + white-space: normal; +} + +.dx-theme-generic .dx-tabs-wrapper .dx-item.dx-tab { + max-width: fit-content; + padding-left: 14px; + padding-right: 9px; + line-height: 1.618; +} + +.dx-tabpanel .dx-tab .dx-icon.dx-icon-close { + display: inline-block; + margin-right: 0; + margin-left: 7px; + opacity: 0.6; +} + +.dx-theme-generic .dx-tabpanel .dx-tab .dx-icon.dx-icon-close { + font-size: 15px; +} + +.dx-theme-material .dx-tabpanel .dx-tab .dx-icon.dx-icon-close { + font-size: 18px; +} + +.dx-theme-material .dx-tab-content { + flex-direction: row; +} + +.dx-theme-material .employeeNotes { + margin: 0; +} diff --git a/JSDemos/Demos/TabPanel/Templates/React/App.tsx b/JSDemos/Demos/TabPanel/Templates/React/App.tsx new file mode 100644 index 00000000000..fc37134eb3b --- /dev/null +++ b/JSDemos/Demos/TabPanel/Templates/React/App.tsx @@ -0,0 +1,77 @@ +import React from 'react'; +import CheckBox, { CheckBoxTypes } from 'devextreme-react/check-box'; +import TabPanel, { TabPanelTypes } from 'devextreme-react/tab-panel'; +import { multiViewItems as companies } from './data.ts'; +import CompanyItem from './CompanyItem.tsx'; + +const itemTitleRender = (company) => {company.CompanyName}; + +const App = () => { + const [animationEnabled, setAnimationEnabled] = React.useState(true); + const [swipeEnabled, setSwipeEnabled] = React.useState(true); + const [loop, setLoop] = React.useState(false); + const [selectedIndex, setSelectedIndex] = React.useState(0); + + const onSelectionChanged = React.useCallback((args: TabPanelTypes.OptionChangedEvent) => { + if (args.name === 'selectedIndex') { + setSelectedIndex(args.value); + } + }, [setSelectedIndex]); + + const onLoopChanged = React.useCallback((args: CheckBoxTypes.ValueChangedEvent) => { + setLoop(args.value); + }, [setLoop]); + + const onAnimationEnabledChanged = React.useCallback((args: CheckBoxTypes.ValueChangedEvent) => { + setAnimationEnabled(args.value); + }, [setAnimationEnabled]); + + const onSwipeEnabledChanged = React.useCallback((args: CheckBoxTypes.ValueChangedEvent) => { + setSwipeEnabled(args.value); + }, [setSwipeEnabled]); + + return ( +
+ +
+ Item {selectedIndex + 1} of {companies.length} +
+
+
Options
+
+ +
+
+ +
+
+ +
+
+
+ ); +}; + +export default App; diff --git a/JSDemos/Demos/TabPanel/Templates/React/CompanyItem.js b/JSDemos/Demos/TabPanel/Templates/React/CompanyItem.tsx similarity index 100% rename from JSDemos/Demos/TabPanel/Templates/React/CompanyItem.js rename to JSDemos/Demos/TabPanel/Templates/React/CompanyItem.tsx diff --git a/JSDemos/Demos/TabPanel/Templates/React/data.js b/JSDemos/Demos/TabPanel/Templates/React/data.ts similarity index 100% rename from JSDemos/Demos/TabPanel/Templates/React/data.js rename to JSDemos/Demos/TabPanel/Templates/React/data.ts diff --git a/JSDemos/Demos/TabPanel/Templates/React/index.html b/JSDemos/Demos/TabPanel/Templates/React/index.html index fb33a47d3fb..7aef756bcb4 100644 --- a/JSDemos/Demos/TabPanel/Templates/React/index.html +++ b/JSDemos/Demos/TabPanel/Templates/React/index.html @@ -12,7 +12,7 @@ diff --git a/JSDemos/Demos/TabPanel/Templates/React/index.js b/JSDemos/Demos/TabPanel/Templates/React/index.js deleted file mode 100644 index d9d7442ce76..00000000000 --- a/JSDemos/Demos/TabPanel/Templates/React/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App.js'; - -ReactDOM.render( - , - document.getElementById('app'), -); diff --git a/JSDemos/Demos/TabPanel/Templates/React/index.tsx b/JSDemos/Demos/TabPanel/Templates/React/index.tsx new file mode 100644 index 00000000000..8acbec4b617 --- /dev/null +++ b/JSDemos/Demos/TabPanel/Templates/React/index.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import App from './App.tsx'; + +ReactDOM.render( + , + document.getElementById('app'), +); diff --git a/JSDemos/Demos/TabPanel/Templates/React/App.js b/JSDemos/Demos/TabPanel/Templates/ReactJs/App.js similarity index 75% rename from JSDemos/Demos/TabPanel/Templates/React/App.js rename to JSDemos/Demos/TabPanel/Templates/ReactJs/App.js index 7ec5e5ea98f..5fa4370dc04 100644 --- a/JSDemos/Demos/TabPanel/Templates/React/App.js +++ b/JSDemos/Demos/TabPanel/Templates/ReactJs/App.js @@ -5,31 +5,37 @@ import { multiViewItems as companies } from './data.js'; import CompanyItem from './CompanyItem.js'; const itemTitleRender = (company) => {company.CompanyName}; - const App = () => { const [animationEnabled, setAnimationEnabled] = React.useState(true); const [swipeEnabled, setSwipeEnabled] = React.useState(true); const [loop, setLoop] = React.useState(false); const [selectedIndex, setSelectedIndex] = React.useState(0); - - const onSelectionChanged = React.useCallback((args) => { - if (args.name === 'selectedIndex') { - setSelectedIndex(args.value); - } - }, [setSelectedIndex]); - - const onLoopChanged = React.useCallback((args) => { - setLoop(args.value); - }, [setLoop]); - - const onAnimationEnabledChanged = React.useCallback((args) => { - setAnimationEnabled(args.value); - }, [setAnimationEnabled]); - - const onSwipeEnabledChanged = React.useCallback((args) => { - setSwipeEnabled(args.value); - }, [setSwipeEnabled]); - + const onSelectionChanged = React.useCallback( + (args) => { + if (args.name === 'selectedIndex') { + setSelectedIndex(args.value); + } + }, + [setSelectedIndex], + ); + const onLoopChanged = React.useCallback( + (args) => { + setLoop(args.value); + }, + [setLoop], + ); + const onAnimationEnabledChanged = React.useCallback( + (args) => { + setAnimationEnabled(args.value); + }, + [setAnimationEnabled], + ); + const onSwipeEnabledChanged = React.useCallback( + (args) => { + setSwipeEnabled(args.value); + }, + [setSwipeEnabled], + ); return (
{
); }; - export default App; diff --git a/JSDemos/Demos/TabPanel/Templates/ReactJs/CompanyItem.js b/JSDemos/Demos/TabPanel/Templates/ReactJs/CompanyItem.js new file mode 100644 index 00000000000..4a31621e23f --- /dev/null +++ b/JSDemos/Demos/TabPanel/Templates/ReactJs/CompanyItem.js @@ -0,0 +1,42 @@ +import React from 'react'; + +function CompanyItem({ data }) { + const company = data; + return ( +
+
+
+

+ {company.Address} +

+

+ + {company.City},  + + {company.State}  + {company.Zipcode} +

+
+
+

+ Phone: {company.Phone} +

+

+ Fax: {company.Fax} +

+

+ Website:{' '} + + {company.Website} + +

+
+
+
+ ); +} +export default CompanyItem; diff --git a/JSDemos/Demos/TabPanel/Templates/ReactJs/data.js b/JSDemos/Demos/TabPanel/Templates/ReactJs/data.js new file mode 100644 index 00000000000..b5adca5592c --- /dev/null +++ b/JSDemos/Demos/TabPanel/Templates/ReactJs/data.js @@ -0,0 +1,46 @@ +export const multiViewItems = [ + { + ID: 1, + CompanyName: 'SuprMart', + Address: '702 SW 8th Street', + City: 'Bentonville', + State: 'Arkansas', + Zipcode: 72716, + Phone: '(800) 555-2797', + Fax: '(800) 555-2171', + Website: 'http://www.nowebsitesupermart.com', + }, + { + ID: 2, + CompanyName: "El'Depot", + Address: '2455 Paces Ferry Road NW', + City: 'Atlanta', + State: 'Georgia', + Zipcode: 30339, + Phone: '(800) 595-3232', + Fax: '(800) 595-3231', + Website: 'http://www.nowebsitedepot.com', + }, + { + ID: 3, + CompanyName: 'K&S Music', + Address: '1000 Nicllet Mall', + City: 'Minneapolis', + State: 'Minnesota', + Zipcode: 55403, + Phone: '(612) 304-6073', + Fax: '(612) 304-6074', + Website: 'http://www.nowebsitemusic.com', + }, + { + ID: 4, + CompanyName: 'Tom Club', + Address: '999 Lake Drive', + City: 'Issaquah', + State: 'Washington', + Zipcode: 98027, + Phone: '(800) 955-2292', + Fax: '(800) 955-2293', + Website: 'http://www.nowebsitetomsclub.com', + }, +]; diff --git a/JSDemos/Demos/TabPanel/Templates/ReactJs/description.md b/JSDemos/Demos/TabPanel/Templates/ReactJs/description.md new file mode 100644 index 00000000000..9840e0117bf --- /dev/null +++ b/JSDemos/Demos/TabPanel/Templates/ReactJs/description.md @@ -0,0 +1,16 @@ +This demo illustrates the use of templates in TabPanel. If your data objects contain custom fields, you need to specify the [itemTitleRender](/Documentation/ApiReference/UI_Components/dxTabPanel/Configuration/#itemTitleRender)/[itemTitleComponent](/Documentation/ApiReference/UI_Components/dxTabPanel/Configuration/#itemTitleComponent) and [itemRender](/Documentation/ApiReference/UI_Components/dxTabPanel/Configuration/#itemRender)/[itemComponent](/Documentation/ApiReference/UI_Components/dxTabPanel/Configuration/#itemComponent) that define how to display the fields in tabs and views. + +If you want each tab and view to have differently structured content, define individual renders. To do this, assign an array of objects to the **items[]** or **dataSource** property and specify the [tabRender](/Documentation/ApiReference/UI_Components/dxTabPanel/Configuration/items/#tabRender)/[tabComponent](/Documentation/ApiReference/UI_Components/dxTabPanel/Configuration/items/#tabComponent) and [render](/Documentation/ApiReference/UI_Components/dxTabPanel/Configuration/items/#render)/[component](/Documentation/ApiReference/UI_Components/dxTabPanel/Configuration/items/#component) properties in each object. This use case is illustrated in the following tutorial: [Getting Started with TabPanel](/Documentation/Guide/UI_Components/TabPanel/Getting_Started_with_TabPanel/). + +Use the following properties to configure user navigation between tabs: + +- [swipeEnabled](/Documentation/ApiReference/UI_Components/dxTabPanel/Configuration/#swipeEnabled) + Defines whether to switch between views with a swipe gesture. + +- [loop](/Documentation/ApiReference/UI_Components/dxTabPanel/Configuration/#loop) + Specifies whether to loop views. + +- [animationEnabled](/Documentation/ApiReference/UI_Components/dxTabPanel/Configuration/#animationEnabled) + Specifies whether to animate transition between views. + +You can switch the checkboxes below the TabPanel to change the **loop**, **animationEnabled**, and **swipeEnabled** property values. diff --git a/JSDemos/Demos/TabPanel/Templates/ReactJs/index.html b/JSDemos/Demos/TabPanel/Templates/ReactJs/index.html new file mode 100644 index 00000000000..4d0ee54d8eb --- /dev/null +++ b/JSDemos/Demos/TabPanel/Templates/ReactJs/index.html @@ -0,0 +1,44 @@ + + + + DevExtreme Demo + + + + + + + + + + + + + +
+
+
+ + diff --git a/JSDemos/Demos/TabPanel/Templates/ReactJs/index.js b/JSDemos/Demos/TabPanel/Templates/ReactJs/index.js new file mode 100644 index 00000000000..b853e0be824 --- /dev/null +++ b/JSDemos/Demos/TabPanel/Templates/ReactJs/index.js @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App.js'; + +ReactDOM.render(, document.getElementById('app')); diff --git a/JSDemos/Demos/TabPanel/Templates/ReactJs/styles.css b/JSDemos/Demos/TabPanel/Templates/ReactJs/styles.css new file mode 100644 index 00000000000..ca49d985334 --- /dev/null +++ b/JSDemos/Demos/TabPanel/Templates/ReactJs/styles.css @@ -0,0 +1,40 @@ +.tabpanel-item { + height: 200px; + user-select: none; + padding-left: 25px; + padding-top: 55px; +} + +.mobile .tabpanel-item { + padding-top: 10px; +} + +.tabpanel-item > div { + float: left; + padding: 0 85px 10px 10px; +} + +.tabpanel-item p { + font-size: 16px; + margin: 0; +} + +.item-box { + font-size: 16px; + margin: 15px 0 45px 10px; +} + +.options { + padding: 20px; + background-color: rgba(191, 191, 191, 0.15); + margin-top: 20px; +} + +.caption { + font-size: 18px; + font-weight: 500; +} + +.option { + margin-top: 10px; +} diff --git a/JSDemos/Demos/Tabs/Overview/React/App.js b/JSDemos/Demos/Tabs/Overview/React/App.tsx similarity index 99% rename from JSDemos/Demos/Tabs/Overview/React/App.js rename to JSDemos/Demos/Tabs/Overview/React/App.tsx index 470309fce40..ee74ea4da5b 100644 --- a/JSDemos/Demos/Tabs/Overview/React/App.js +++ b/JSDemos/Demos/Tabs/Overview/React/App.tsx @@ -14,7 +14,7 @@ import { iconPositions, tabsIcon, orientationLabel, -} from './data.js'; +} from './data.ts'; function OptionWrapper(props) { return ( diff --git a/JSDemos/Demos/Tabs/Overview/React/data.ts b/JSDemos/Demos/Tabs/Overview/React/data.ts new file mode 100644 index 00000000000..3e922ee3560 --- /dev/null +++ b/JSDemos/Demos/Tabs/Overview/React/data.ts @@ -0,0 +1,106 @@ +import { Orientation, TabsIconPosition, TabsStyle } from 'devextreme/common'; + +export const tabsText = [ + { + id: 0, + text: 'User', + }, + { + id: 1, + text: 'Analytics', + }, + { + id: 2, + text: 'Clients', + }, + { + id: 3, + text: 'Orders', + }, + { + id: 4, + text: 'Favorites', + }, + { + id: 5, + text: 'Search', + }, +]; + +export const tabsIconAndText = [ + { + id: 0, + text: 'User', + icon: 'user', + }, + { + id: 1, + text: 'Analytics', + icon: 'chart', + }, + { + id: 2, + text: 'Clients', + icon: 'accountbox', + }, + { + id: 3, + text: 'Orders', + icon: 'ordersbox', + }, + { + id: 4, + text: 'Favorites', + icon: 'bookmark', + }, + { + id: 5, + text: 'Search', + icon: 'search', + }, +]; + +export const tabsIcon = [ + { + id: 0, + icon: 'user', + }, + { + id: 1, + icon: 'chart', + }, + { + id: 2, + icon: 'accountbox', + }, + { + id: 3, + icon: 'ordersbox', + }, + { + id: 4, + icon: 'bookmark', + }, + { + id: 5, + icon: 'search', + }, +]; + +export const orientations: Orientation[] = ['horizontal', 'vertical']; + +export const stylingModes: TabsStyle[] = [ + 'primary', + 'secondary', +]; + +export const orientationLabel = { 'aria-label': 'Orientation' }; +export const stylingModeLabel = { 'aria-label': 'Styling Mode' }; +export const iconPositionLabel = { 'aria-label': 'Icon Position' }; + +export const iconPositions: TabsIconPosition[] = [ + 'top', + 'start', + 'end', + 'bottom', +]; diff --git a/JSDemos/Demos/Tabs/Overview/React/index.html b/JSDemos/Demos/Tabs/Overview/React/index.html index fb33a47d3fb..7aef756bcb4 100644 --- a/JSDemos/Demos/Tabs/Overview/React/index.html +++ b/JSDemos/Demos/Tabs/Overview/React/index.html @@ -12,7 +12,7 @@ diff --git a/JSDemos/Demos/Tabs/Overview/React/index.js b/JSDemos/Demos/Tabs/Overview/React/index.js deleted file mode 100644 index d9d7442ce76..00000000000 --- a/JSDemos/Demos/Tabs/Overview/React/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App.js'; - -ReactDOM.render( - , - document.getElementById('app'), -); diff --git a/JSDemos/Demos/Tabs/Overview/React/index.tsx b/JSDemos/Demos/Tabs/Overview/React/index.tsx new file mode 100644 index 00000000000..8acbec4b617 --- /dev/null +++ b/JSDemos/Demos/Tabs/Overview/React/index.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import App from './App.tsx'; + +ReactDOM.render( + , + document.getElementById('app'), +); diff --git a/JSDemos/Demos/Tabs/Overview/ReactJs/App.js b/JSDemos/Demos/Tabs/Overview/ReactJs/App.js new file mode 100644 index 00000000000..f1a05418118 --- /dev/null +++ b/JSDemos/Demos/Tabs/Overview/ReactJs/App.js @@ -0,0 +1,190 @@ +import React from 'react'; +import Tabs from 'devextreme-react/tabs'; +import SelectBox from 'devextreme-react/select-box'; +import CheckBox from 'devextreme-react/check-box'; +import { + orientations, + tabsText, + stylingModeLabel, + iconPositionLabel, + tabsIconAndText, + stylingModes, + iconPositions, + tabsIcon, + orientationLabel, +} from './data.js'; + +function OptionWrapper(props) { + return ( +
+ {props.caption && {props.caption}} + {props.children} +
+ ); +} +const App = () => { + const [orientation, setOrientation] = React.useState(orientations[0]); + const [stylingMode, setStylingMode] = React.useState(stylingModes[1]); + const [iconPosition, setIconPosition] = React.useState(iconPositions[0]); + const [showNavigation, setShowNavigation] = React.useState(false); + const [scrollContent, setScrollContent] = React.useState(false); + const [fullWidth, setFullWidth] = React.useState(false); + const [rtlEnabled, setRtlEnabled] = React.useState(false); + const [widgetWrapperClasses, setWidgetWrapperClasses] = React.useState( + 'widget-wrapper widget-wrapper-horizontal', + ); + const stylingModeChanged = React.useCallback( + (e) => { + setStylingMode(e.value); + }, + [setStylingMode], + ); + const iconPositionChanged = React.useCallback( + (e) => { + setIconPosition(e.value); + }, + [setIconPosition], + ); + const orientationChanged = React.useCallback( + (e) => { + setWidgetWrapperClasses(`widget-wrapper widget-wrapper-${e.value}`); + setOrientation(e.value); + }, + [setOrientation, setWidgetWrapperClasses], + ); + const showNavigationChanged = React.useCallback( + (e) => { + setShowNavigation(e.value); + }, + [setShowNavigation], + ); + const scrollContentChanged = React.useCallback( + (e) => { + setScrollContent(e.value); + }, + [setScrollContent], + ); + const fullWidthChanged = React.useCallback( + (e) => { + setFullWidth(e.value); + }, + [setFullWidth], + ); + const rtlEnabledChanged = React.useCallback( + (e) => { + setRtlEnabled(e.value); + }, + [setRtlEnabled], + ); + return ( +
+
+
+ + + + + +
+
+ +
+
Options
+ + + + + + + + + + + + + +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ ); +}; +export default App; diff --git a/JSDemos/Demos/Tabs/Overview/React/data.js b/JSDemos/Demos/Tabs/Overview/ReactJs/data.js similarity index 89% rename from JSDemos/Demos/Tabs/Overview/React/data.js rename to JSDemos/Demos/Tabs/Overview/ReactJs/data.js index 5259a714ab3..51af3557b74 100644 --- a/JSDemos/Demos/Tabs/Overview/React/data.js +++ b/JSDemos/Demos/Tabs/Overview/ReactJs/data.js @@ -24,7 +24,6 @@ export const tabsText = [ text: 'Search', }, ]; - export const tabsIconAndText = [ { id: 0, @@ -57,7 +56,6 @@ export const tabsIconAndText = [ icon: 'search', }, ]; - export const tabsIcon = [ { id: 0, @@ -84,21 +82,9 @@ export const tabsIcon = [ icon: 'search', }, ]; - export const orientations = ['horizontal', 'vertical']; - -export const stylingModes = [ - 'primary', - 'secondary', -]; - +export const stylingModes = ['primary', 'secondary']; export const orientationLabel = { 'aria-label': 'Orientation' }; export const stylingModeLabel = { 'aria-label': 'Styling Mode' }; export const iconPositionLabel = { 'aria-label': 'Icon Position' }; - -export const iconPositions = [ - 'top', - 'start', - 'end', - 'bottom', -]; +export const iconPositions = ['top', 'start', 'end', 'bottom']; diff --git a/JSDemos/Demos/Tabs/Overview/ReactJs/index.html b/JSDemos/Demos/Tabs/Overview/ReactJs/index.html new file mode 100644 index 00000000000..4d0ee54d8eb --- /dev/null +++ b/JSDemos/Demos/Tabs/Overview/ReactJs/index.html @@ -0,0 +1,44 @@ + + + + DevExtreme Demo + + + + + + + + + + + + + +
+
+
+ + diff --git a/JSDemos/Demos/Tabs/Overview/ReactJs/index.js b/JSDemos/Demos/Tabs/Overview/ReactJs/index.js new file mode 100644 index 00000000000..b853e0be824 --- /dev/null +++ b/JSDemos/Demos/Tabs/Overview/ReactJs/index.js @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App.js'; + +ReactDOM.render(, document.getElementById('app')); diff --git a/JSDemos/Demos/Tabs/Overview/ReactJs/styles.css b/JSDemos/Demos/Tabs/Overview/ReactJs/styles.css new file mode 100644 index 00000000000..8c1f34ad9cb --- /dev/null +++ b/JSDemos/Demos/Tabs/Overview/ReactJs/styles.css @@ -0,0 +1,68 @@ +#tabs-demo { + display: flex; + min-height: 450px; +} + +.widget-container { + display: flex; + align-items: center; + justify-content: center; + flex-grow: 1; + max-width: calc(100% - 300px); + min-width: 200px; + padding: 16px 32px; + overflow: clip; +} + +.widget-wrapper { + display: inline-flex; + flex-direction: column; + align-items: flex-start; + justify-content: center; + gap: 80px; + max-width: 100%; +} + +.widget-wrapper-vertical { + width: 100%; + flex-direction: row; + align-items: center; +} + +.options { + display: flex; + flex-direction: column; + flex-shrink: 0; + padding: 20px; + background-color: rgba(191, 191, 191, 0.15); +} + +.caption { + font-weight: 500; + font-size: 18px; +} + +#show-navigation-buttons { + margin-top: 22px; +} + +.option { + margin-top: 20px; +} + +.dx-tabs { + max-width: 100%; +} + +.dx-tabs-vertical { + height: 216px; +} + +.dx-viewport:not(.dx-theme-generic) .dx-tabs-horizontal { + border-block-end: 1px solid rgb(225, 225, 225, 0.4); +} + +.dx-viewport:not(.dx-theme-generic) .dx-tabs-vertical { + height: 232px; + border-inline-end: 1px solid rgb(225, 225, 225, 0.4); +} diff --git a/JSDemos/Demos/Tabs/Selection/React/App.js b/JSDemos/Demos/Tabs/Selection/React/App.tsx similarity index 91% rename from JSDemos/Demos/Tabs/Selection/React/App.js rename to JSDemos/Demos/Tabs/Selection/React/App.tsx index 3ac5f983277..5f94d54b9a3 100644 --- a/JSDemos/Demos/Tabs/Selection/React/App.js +++ b/JSDemos/Demos/Tabs/Selection/React/App.tsx @@ -4,9 +4,16 @@ import Tabs from 'devextreme-react/tabs'; import SelectBox from 'devextreme-react/select-box'; import MultiView from 'devextreme-react/multi-view'; -import { employees, selectBoxLabel } from './data.js'; +import { employees, selectBoxLabel } from './data.ts'; -class EmployeeInfo extends React.Component { +class EmployeeInfo extends React.Component<{ + data: { + text: string, + picture: string, + position: string, + notes: string + } +}> { render() { const { text, picture, position, notes, diff --git a/JSDemos/Demos/Tabs/Selection/React/data.js b/JSDemos/Demos/Tabs/Selection/React/data.ts similarity index 100% rename from JSDemos/Demos/Tabs/Selection/React/data.js rename to JSDemos/Demos/Tabs/Selection/React/data.ts diff --git a/JSDemos/Demos/Tabs/Selection/React/index.html b/JSDemos/Demos/Tabs/Selection/React/index.html index fb33a47d3fb..7aef756bcb4 100644 --- a/JSDemos/Demos/Tabs/Selection/React/index.html +++ b/JSDemos/Demos/Tabs/Selection/React/index.html @@ -12,7 +12,7 @@ diff --git a/JSDemos/Demos/Tabs/Selection/React/index.js b/JSDemos/Demos/Tabs/Selection/React/index.js deleted file mode 100644 index d9d7442ce76..00000000000 --- a/JSDemos/Demos/Tabs/Selection/React/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App.js'; - -ReactDOM.render( - , - document.getElementById('app'), -); diff --git a/JSDemos/Demos/Tabs/Selection/React/index.tsx b/JSDemos/Demos/Tabs/Selection/React/index.tsx new file mode 100644 index 00000000000..8acbec4b617 --- /dev/null +++ b/JSDemos/Demos/Tabs/Selection/React/index.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import App from './App.tsx'; + +ReactDOM.render( + , + document.getElementById('app'), +); diff --git a/JSDemos/Demos/Tabs/Selection/ReactJs/App.js b/JSDemos/Demos/Tabs/Selection/ReactJs/App.js new file mode 100644 index 00000000000..8295b0df34d --- /dev/null +++ b/JSDemos/Demos/Tabs/Selection/ReactJs/App.js @@ -0,0 +1,82 @@ +import React from 'react'; +import Tabs from 'devextreme-react/tabs'; +import SelectBox from 'devextreme-react/select-box'; +import MultiView from 'devextreme-react/multi-view'; +import { employees, selectBoxLabel } from './data.js'; + +class EmployeeInfo extends React.Component { + render() { + const { + text, picture, position, notes, + } = this.props.data; + return ( +
+ {text} +

+ Position: {position} +
+ {notes} +

+
+ ); + } +} +const App = () => { + const [selectedItem, setSelectedItem] = React.useState(employees[0]); + const onSelectionChanged = React.useCallback( + (args) => { + setSelectedItem(args.selectedItem || args.addedItems[0]); + }, + [setSelectedItem], + ); + return ( +
+
+
+
+ +
+ +
+
Selected user:
+
+ +
+
+ +
+ +
+ +
+ + You can use swipe gestures in this area. +
+
+
+
+ ); +}; +export default App; diff --git a/JSDemos/Demos/Tabs/Selection/ReactJs/data.js b/JSDemos/Demos/Tabs/Selection/ReactJs/data.js new file mode 100644 index 00000000000..1ad552d7910 --- /dev/null +++ b/JSDemos/Demos/Tabs/Selection/ReactJs/data.js @@ -0,0 +1,30 @@ +export const employees = [ + { + id: 0, + icon: 'user', + text: 'John Heart', + position: 'CEO', + picture: '../../../../images/employees/01.png', + notes: + 'John has been in the Audio/Video industry since 1990. He has led DevAv as its CEO since 2003. When not working hard as the CEO, John loves to golf and bowl. He once bowled a perfect game of 300.', + }, + { + id: 1, + icon: 'user', + text: 'Olivia Peyton', + position: 'Sales Assistant', + picture: '../../../../images/employees/09.png', + notes: + 'Olivia loves to sell. She has been selling DevAV products since 2012. Olivia was homecoming queen in high school. She is expecting her first child in 6 months. Good Luck Olivia.', + }, + { + id: 2, + icon: 'user', + text: 'Robert Reagan', + position: 'CMO', + picture: '../../../../images/employees/03.png', + notes: + 'Robert was recently voted the CMO of the year by CMO Magazine. He is a proud member of the DevAV Management Team. Robert is a championship BBQ chef, so when you get the chance ask him for his secret recipe.', + }, +]; +export const selectBoxLabel = { 'aria-label': 'Select Employee' }; diff --git a/JSDemos/Demos/Tabs/Selection/ReactJs/index.html b/JSDemos/Demos/Tabs/Selection/ReactJs/index.html new file mode 100644 index 00000000000..4d0ee54d8eb --- /dev/null +++ b/JSDemos/Demos/Tabs/Selection/ReactJs/index.html @@ -0,0 +1,44 @@ + + + + DevExtreme Demo + + + + + + + + + + + + + +
+
+
+ + diff --git a/JSDemos/Demos/Tabs/Selection/ReactJs/index.js b/JSDemos/Demos/Tabs/Selection/ReactJs/index.js new file mode 100644 index 00000000000..b853e0be824 --- /dev/null +++ b/JSDemos/Demos/Tabs/Selection/ReactJs/index.js @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App.js'; + +ReactDOM.render(, document.getElementById('app')); diff --git a/JSDemos/Demos/Tabs/Selection/ReactJs/styles.css b/JSDemos/Demos/Tabs/Selection/ReactJs/styles.css new file mode 100644 index 00000000000..97629905900 --- /dev/null +++ b/JSDemos/Demos/Tabs/Selection/ReactJs/styles.css @@ -0,0 +1,58 @@ +#center-content { + display: flex; + align-items: center; + justify-content: center; +} + +.select-box-container, +.multiview-container { + padding: 16px; +} + +#demo-items-container { + width: 680px; +} + +.employee-info { + display: flex; + align-items: center; +} + +.employee-photo { + height: 80px; + width: 80px; + border-radius: 50%; + border-width: 1px; + border-style: solid; + flex-shrink: 0; + object-fit: contain; + margin-right: 24px; +} + +.employee-notes b { + display: inline-block; + margin-bottom: 8px; +} + +.dx-field-label { + font-size: 16px; +} + +#multiview { + cursor: move; +} + +.demo-info { + padding-left: 8px; + opacity: 0.6; +} + +.icon-container { + padding-left: 16px; + display: flex; + align-items: center; +} + +.dx-icon { + font-size: 18px; +} diff --git a/JSDemos/Demos/Toolbar/Adaptability/React/App.js b/JSDemos/Demos/Toolbar/Adaptability/React/App.tsx similarity index 94% rename from JSDemos/Demos/Toolbar/Adaptability/React/App.js rename to JSDemos/Demos/Toolbar/Adaptability/React/App.tsx index 75ea353a808..3f61dc56c28 100644 --- a/JSDemos/Demos/Toolbar/Adaptability/React/App.js +++ b/JSDemos/Demos/Toolbar/Adaptability/React/App.tsx @@ -1,11 +1,11 @@ import React from 'react'; import Toolbar, { Item } from 'devextreme-react/toolbar'; -import { Button } from 'devextreme-react/button'; -import { ButtonGroup } from 'devextreme-react/button-group'; +import Button from 'devextreme-react/button'; +import ButtonGroup, { ButtonGroupTypes } from 'devextreme-react/button-group'; import Resizable from 'devextreme-react/resizable'; import CheckBox from 'devextreme-react/check-box'; -import DropDownButton from 'devextreme-react/drop-down-button'; -import SelectBox from 'devextreme-react/select-box'; +import DropDownButton, { DropDownButtonTypes } from 'devextreme-react/drop-down-button'; +import SelectBox, { SelectBoxTypes } from 'devextreme-react/select-box'; import notify from 'devextreme/ui/notify'; import 'devextreme/ui/select_box'; import { @@ -19,18 +19,18 @@ import { listTypes, fontInputAttr, textStyleInputAttr, -} from './data.js'; +} from './data.ts'; const lineHeightDefault = lineHeights[1].lineHeight; const textAlignDefault = [textAlignItems[0].alignment]; const fontSizeDefault = fontSizes[2].size; const headingDefault = headings[0].text; -function onButtonClick(name) { +function onButtonClick(name: string) { notify(`The "${name}" button has been clicked`); } -function onSelectionChanged(name) { +function onSelectionChanged(name: string) { notify(`The "${name}" value has been changed`); } @@ -49,7 +49,7 @@ function App() { onButtonClick('Undo'); }, []); - const onButtonGroupClick = React.useCallback((e) => { + const onButtonGroupClick = React.useCallback((e: ButtonGroupTypes.ItemClickEvent) => { onButtonClick(e.itemData.hint); }, []); @@ -86,7 +86,7 @@ function App() { }, []); const onHeadingClick = React.useCallback( - (e) => { + (e: SelectBoxTypes.ItemClickEvent) => { setHeading(e.itemData.text); notify('The "Heading" value has been changed'); }, @@ -94,7 +94,7 @@ function App() { ); const onLineHeightChanged = React.useCallback( - (e) => { + (e: DropDownButtonTypes.SelectionChangedEvent) => { setLineHeight(e.item.lineHeight); onSelectionChanged('Line Height'); }, @@ -102,7 +102,7 @@ function App() { ); const onFontSizeChange = React.useCallback( - (e) => { + (e: DropDownButtonTypes.SelectionChangedEvent) => { setFontSize(e.item.size); onSelectionChanged('Font Size'); }, @@ -110,7 +110,7 @@ function App() { ); const onTextAlignChanged = React.useCallback( - (e) => { + (e: ButtonGroupTypes.ItemClickEvent) => { const { alignment, hint } = e.itemData; setTextAlign([alignment]); @@ -149,7 +149,6 @@ function App() { const renderTextAlignMenu = React.useCallback( () => ( diff --git a/JSDemos/Demos/Toolbar/Adaptability/React/index.js b/JSDemos/Demos/Toolbar/Adaptability/React/index.js deleted file mode 100644 index d9d7442ce76..00000000000 --- a/JSDemos/Demos/Toolbar/Adaptability/React/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App.js'; - -ReactDOM.render( - , - document.getElementById('app'), -); diff --git a/JSDemos/Demos/Toolbar/Adaptability/React/index.tsx b/JSDemos/Demos/Toolbar/Adaptability/React/index.tsx new file mode 100644 index 00000000000..8acbec4b617 --- /dev/null +++ b/JSDemos/Demos/Toolbar/Adaptability/React/index.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import App from './App.tsx'; + +ReactDOM.render( + , + document.getElementById('app'), +); diff --git a/JSDemos/Demos/Toolbar/Adaptability/ReactJs/App.js b/JSDemos/Demos/Toolbar/Adaptability/ReactJs/App.js new file mode 100644 index 00000000000..36fc16bd62e --- /dev/null +++ b/JSDemos/Demos/Toolbar/Adaptability/ReactJs/App.js @@ -0,0 +1,408 @@ +import React from 'react'; +import Toolbar, { Item } from 'devextreme-react/toolbar'; +import Button from 'devextreme-react/button'; +import ButtonGroup from 'devextreme-react/button-group'; +import Resizable from 'devextreme-react/resizable'; +import CheckBox from 'devextreme-react/check-box'; +import DropDownButton from 'devextreme-react/drop-down-button'; +import SelectBox from 'devextreme-react/select-box'; +import notify from 'devextreme/ui/notify'; +import 'devextreme/ui/select_box'; +import { + fontSizes, + lineHeights, + fontFamilies, + fontStyles, + headings, + textAlignItems, + textAlignItemsExtended, + listTypes, + fontInputAttr, + textStyleInputAttr, +} from './data.js'; + +const lineHeightDefault = lineHeights[1].lineHeight; +const textAlignDefault = [textAlignItems[0].alignment]; +const fontSizeDefault = fontSizes[2].size; +const headingDefault = headings[0].text; +function onButtonClick(name) { + notify(`The "${name}" button has been clicked`); +} +function onSelectionChanged(name) { + notify(`The "${name}" value has been changed`); +} +function App() { + const [lineHeight, setLineHeight] = React.useState(lineHeightDefault); + const [textAlign, setTextAlign] = React.useState(textAlignDefault); + const [fontSize, setFontSize] = React.useState(fontSizeDefault); + const [heading, setHeading] = React.useState(headingDefault); + const [multiline, setMultiline] = React.useState(true); + const onFontFamilyClick = React.useCallback(() => { + notify('The "Font Family" value has been changed'); + }, []); + const onUndoButtonClick = React.useCallback(() => { + onButtonClick('Undo'); + }, []); + const onButtonGroupClick = React.useCallback((e) => { + onButtonClick(e.itemData.hint); + }, []); + const onRedoButtonClick = React.useCallback(() => { + onButtonClick('Redo'); + }, []); + const onLinkButtonClick = React.useCallback(() => { + onButtonClick('Link'); + }, []); + const onAddImageButtonClick = React.useCallback(() => { + onButtonClick('Add Image'); + }, []); + const onClearButtonClick = React.useCallback(() => { + onButtonClick('Clear Formating'); + }, []); + const onCodeBlockButtonClick = React.useCallback(() => { + onButtonClick('Code Block'); + }, []); + const onQuoteButtonClick = React.useCallback(() => { + onButtonClick('Blockquote'); + }, []); + const onAttachButtonClick = React.useCallback(() => { + onButtonClick('Attach'); + }, []); + const onAboutButtonClick = React.useCallback(() => { + onButtonClick('Attach'); + }, []); + const onHeadingClick = React.useCallback( + (e) => { + setHeading(e.itemData.text); + notify('The "Heading" value has been changed'); + }, + [setHeading], + ); + const onLineHeightChanged = React.useCallback( + (e) => { + setLineHeight(e.item.lineHeight); + onSelectionChanged('Line Height'); + }, + [setLineHeight], + ); + const onFontSizeChange = React.useCallback( + (e) => { + setFontSize(e.item.size); + onSelectionChanged('Font Size'); + }, + [setFontSize], + ); + const onTextAlignChanged = React.useCallback( + (e) => { + const { alignment, hint } = e.itemData; + setTextAlign([alignment]); + onButtonClick(hint); + }, + [setTextAlign], + ); + const onToolbarLineModeChanged = React.useCallback( + ({ value }) => { + setMultiline(value); + }, + [setMultiline], + ); + const renderFontSize = React.useCallback( + (itemData) =>
{itemData.text}
, + [], + ); + const renderTextAlign = React.useCallback( + () => ( + + ), + [textAlign, onTextAlignChanged], + ); + const renderTextAlignMenu = React.useCallback( + () => ( + + ), + [textAlign, onTextAlignChanged], + ); + const renderMenuSeparator = React.useCallback( + () =>
, + [], + ); + return ( + +
+ + + + + + + + + + + +
+
+ + + + + + + + + + + + + + +
+
+ + + + + + +
+
+ + + + + + + + +
+
+ + + + + + +
+
+ + + + + + + + + + +
+
+ + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
+
+ +
+
Options
+ + +
+
+ ); +} +export default App; diff --git a/JSDemos/Demos/Toolbar/Adaptability/ReactJs/data.js b/JSDemos/Demos/Toolbar/Adaptability/ReactJs/data.js new file mode 100644 index 00000000000..192c6ad6ce8 --- /dev/null +++ b/JSDemos/Demos/Toolbar/Adaptability/ReactJs/data.js @@ -0,0 +1,96 @@ +export const fontSizes = [ + { size: 10, text: '10px' }, + { size: 12, text: '12px' }, + { size: 14, text: '14px' }, + { size: 16, text: '16px' }, + { size: 18, text: '18px' }, +]; +export const lineHeights = [ + { lineHeight: 1, text: '1' }, + { lineHeight: 1.35, text: '1.35' }, + { lineHeight: 1.5, text: '1.5' }, + { lineHeight: 2, text: '2' }, +]; +export const fontFamilies = [ + { text: 'Arial' }, + { text: 'Courier New' }, + { text: 'Georgia' }, + { text: 'Impact' }, + { text: 'Lucida Console' }, + { text: 'Tahoma' }, + { text: 'Times New Roman' }, +]; +export const headings = [ + { text: 'Normal text' }, + { text: 'Heading 1' }, + { text: 'Heading 2' }, + { text: 'Heading 3' }, + { text: 'Heading 4' }, + { text: 'Heading 5' }, +]; +export const fontStyles = [ + { + icon: 'bold', + hint: 'Bold', + }, + { + icon: 'italic', + hint: 'Italic', + }, + { + icon: 'underline', + hint: 'Underlined', + }, + { + icon: 'strike', + hint: 'Strikethrough', + }, +]; +export const textAlignItemsExtended = [ + { + icon: 'alignleft', + alignment: 'left', + hint: 'Align Left', + text: 'Align left', + }, + { + icon: 'aligncenter', + alignment: 'center', + hint: 'Center', + text: 'Center', + }, + { + icon: 'alignright', + alignment: 'right', + hint: 'Align Right', + text: 'Align right', + }, + { + icon: 'alignjustify', + alignment: 'justify', + hint: 'Justify', + text: 'Justify', + }, +]; +export const textAlignItems = textAlignItemsExtended.map((item) => { + const { icon, alignment, hint } = item; + return { + icon, + alignment, + hint, + }; +}); +export const listTypes = [ + { + icon: 'orderedlist', + alignment: 'orderedlist', + hint: 'Ordered', + }, + { + icon: 'bulletlist', + alignment: 'bulletlist', + hint: 'Bullet', + }, +]; +export const fontInputAttr = { 'aria-label': 'Font' }; +export const textStyleInputAttr = { 'aria-label': 'Text Style' }; diff --git a/JSDemos/Demos/Toolbar/Adaptability/ReactJs/index.html b/JSDemos/Demos/Toolbar/Adaptability/ReactJs/index.html new file mode 100644 index 00000000000..4d0ee54d8eb --- /dev/null +++ b/JSDemos/Demos/Toolbar/Adaptability/ReactJs/index.html @@ -0,0 +1,44 @@ + + + + DevExtreme Demo + + + + + + + + + + + + + +
+
+
+ + diff --git a/JSDemos/Demos/Toolbar/Adaptability/ReactJs/index.js b/JSDemos/Demos/Toolbar/Adaptability/ReactJs/index.js new file mode 100644 index 00000000000..b853e0be824 --- /dev/null +++ b/JSDemos/Demos/Toolbar/Adaptability/ReactJs/index.js @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App.js'; + +ReactDOM.render(, document.getElementById('app')); diff --git a/JSDemos/Demos/Toolbar/Adaptability/ReactJs/styles.css b/JSDemos/Demos/Toolbar/Adaptability/ReactJs/styles.css new file mode 100644 index 00000000000..3675f14a1f5 --- /dev/null +++ b/JSDemos/Demos/Toolbar/Adaptability/ReactJs/styles.css @@ -0,0 +1,56 @@ +.dx-resizable-handle::after { + content: ""; + position: absolute; + width: 9px; + height: 36px; + border: none; + border-radius: 50px; + background-color: #fff; + box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.24); +} + +.dx-resizable-handle-right::after { + top: 50%; + right: -5px; + transform: translateY(-50%); +} + +.dx-toolbar.dx-toolbar-multiline .dx-toolbar-item { + margin-bottom: 5px; +} + +.widget-container { + margin-right: 10px; +} + +.resizable-container { + padding: 10px; + height: 300px; + border: 1px dotted #999; + border-radius: 4px; + box-sizing: border-box; +} + +.options-container { + margin-top: 20px; + padding: 20px; + background-color: rgba(191, 191, 191, 0.15); + position: relative; +} + +.caption { + font-size: 18px; + font-weight: 500; + margin-bottom: 10px; +} + +.toolbar-separator { + height: 36px; + margin: 0 5px; + border-left: 1px solid #ddd; +} + +.toolbar-menu-separator { + height: 1px; + border-bottom: 1px solid #ddd; +} diff --git a/JSDemos/Demos/Toolbar/Overview/React/App.js b/JSDemos/Demos/Toolbar/Overview/React/App.tsx similarity index 95% rename from JSDemos/Demos/Toolbar/Overview/React/App.js rename to JSDemos/Demos/Toolbar/Overview/React/App.tsx index 025b34561a6..269b937fb57 100644 --- a/JSDemos/Demos/Toolbar/Overview/React/App.js +++ b/JSDemos/Demos/Toolbar/Overview/React/App.tsx @@ -7,7 +7,7 @@ import DataSource from 'devextreme/data/data_source'; import notify from 'devextreme/ui/notify'; import 'devextreme/ui/select_box'; -import { productTypes, products } from './data.js'; +import { productTypes, products } from './data.ts'; const renderLabel = () =>
Tom's Club Products
; @@ -70,7 +70,7 @@ const selectBoxOptions = { inputAttr: { 'aria-label': 'Categories' }, onValueChanged: (args) => { if (args.value > 1) { - productsStore.filter('type', '=', args.value); + productsStore.filter(['type', '=', args.value]); } else { productsStore.filter(null); } diff --git a/JSDemos/Demos/Toolbar/Overview/React/data.js b/JSDemos/Demos/Toolbar/Overview/React/data.ts similarity index 100% rename from JSDemos/Demos/Toolbar/Overview/React/data.js rename to JSDemos/Demos/Toolbar/Overview/React/data.ts diff --git a/JSDemos/Demos/Toolbar/Overview/React/index.html b/JSDemos/Demos/Toolbar/Overview/React/index.html index fb33a47d3fb..7aef756bcb4 100644 --- a/JSDemos/Demos/Toolbar/Overview/React/index.html +++ b/JSDemos/Demos/Toolbar/Overview/React/index.html @@ -12,7 +12,7 @@ diff --git a/JSDemos/Demos/Toolbar/Overview/React/index.js b/JSDemos/Demos/Toolbar/Overview/React/index.js deleted file mode 100644 index d9d7442ce76..00000000000 --- a/JSDemos/Demos/Toolbar/Overview/React/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App.js'; - -ReactDOM.render( - , - document.getElementById('app'), -); diff --git a/JSDemos/Demos/Toolbar/Overview/React/index.tsx b/JSDemos/Demos/Toolbar/Overview/React/index.tsx new file mode 100644 index 00000000000..8acbec4b617 --- /dev/null +++ b/JSDemos/Demos/Toolbar/Overview/React/index.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import App from './App.tsx'; + +ReactDOM.render( + , + document.getElementById('app'), +); diff --git a/JSDemos/Demos/Toolbar/Overview/ReactJs/App.js b/JSDemos/Demos/Toolbar/Overview/ReactJs/App.js new file mode 100644 index 00000000000..faeced0437e --- /dev/null +++ b/JSDemos/Demos/Toolbar/Overview/ReactJs/App.js @@ -0,0 +1,119 @@ +import React from 'react'; +import Toolbar, { Item } from 'devextreme-react/toolbar'; +import List from 'devextreme-react/list'; +import DataSource from 'devextreme/data/data_source'; +import notify from 'devextreme/ui/notify'; +import 'devextreme/ui/select_box'; +import { productTypes, products } from './data.js'; + +const renderLabel = () => ( +
+ Tom's Club Products +
+); +const App = () => ( + + + + + + + + + + + + + +); +const productsStore = new DataSource(products); +const backButtonOptions = { + icon: 'back', + onClick: () => { + notify('Back button has been clicked!'); + }, +}; +const refreshButtonOptions = { + icon: 'refresh', + onClick: () => { + notify('Refresh button has been clicked!'); + }, +}; +const selectBoxOptions = { + width: 140, + items: productTypes, + valueExpr: 'id', + displayExpr: 'text', + value: productTypes[0].id, + inputAttr: { 'aria-label': 'Categories' }, + onValueChanged: (args) => { + if (args.value > 1) { + productsStore.filter(['type', '=', args.value]); + } else { + productsStore.filter(null); + } + productsStore.load(); + }, +}; +const addButtonOptions = { + icon: 'plus', + onClick: () => { + notify('Add button has been clicked!'); + }, +}; +const saveButtonOptions = { + text: 'Save', + onClick: () => { + notify('Save option has been clicked!'); + }, +}; +const printButtonOptions = { + text: 'Print', + onClick: () => { + notify('Print option has been clicked!'); + }, +}; +const settingsButtonOptions = { + text: 'Settings', + onClick: () => { + notify('Settings option has been clicked!'); + }, +}; +export default App; diff --git a/JSDemos/Demos/Toolbar/Overview/ReactJs/data.js b/JSDemos/Demos/Toolbar/Overview/ReactJs/data.js new file mode 100644 index 00000000000..b1ae6732638 --- /dev/null +++ b/JSDemos/Demos/Toolbar/Overview/ReactJs/data.js @@ -0,0 +1,68 @@ +export const productTypes = [ + { + id: 1, + text: 'All', + }, + { + id: 2, + text: 'Video Players', + }, + { + id: 3, + text: 'Televisions', + }, + { + id: 4, + text: 'Monitors', + }, + { + id: 5, + text: 'Projectors', + }, +]; +export const products = [ + { + text: 'HD Video Player', + type: 2, + }, + { + text: 'SuperHD Video Player', + type: 2, + }, + { + text: 'SuperLCD 42', + type: 3, + }, + { + text: 'SuperLED 42', + type: 3, + }, + { + text: 'SuperLED 50', + type: 3, + }, + { + text: 'SuperLCD 55', + type: 3, + }, + { + text: 'DesktopLCD 19', + type: 4, + }, + { + text: 'DesktopLCD 21', + type: 4, + }, + { + text: 'DesktopLED 21', + type: 4, + }, + { + text: 'Projector Plus', + type: 5, + }, + { + text: 'Projector PlusHD', + type: 5, + }, +]; diff --git a/JSDemos/Demos/Toolbar/Overview/ReactJs/index.html b/JSDemos/Demos/Toolbar/Overview/ReactJs/index.html new file mode 100644 index 00000000000..4d0ee54d8eb --- /dev/null +++ b/JSDemos/Demos/Toolbar/Overview/ReactJs/index.html @@ -0,0 +1,44 @@ + + + + DevExtreme Demo + + + + + + + + + + + + + +
+
+
+ + diff --git a/JSDemos/Demos/Toolbar/Overview/ReactJs/index.js b/JSDemos/Demos/Toolbar/Overview/ReactJs/index.js new file mode 100644 index 00000000000..b853e0be824 --- /dev/null +++ b/JSDemos/Demos/Toolbar/Overview/ReactJs/index.js @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App.js'; + +ReactDOM.render(, document.getElementById('app')); diff --git a/JSDemos/Demos/Toolbar/Overview/ReactJs/styles.css b/JSDemos/Demos/Toolbar/Overview/ReactJs/styles.css new file mode 100644 index 00000000000..bed969cfac8 --- /dev/null +++ b/JSDemos/Demos/Toolbar/Overview/ReactJs/styles.css @@ -0,0 +1,8 @@ +.toolbar-label, +.toolbar-label > b { + font-size: 16px; +} + +#products { + margin-top: 10px; +} diff --git a/JSDemos/Demos/TreeView/ContextMenuIntegration/React/App.js b/JSDemos/Demos/TreeView/ContextMenuIntegration/React/App.tsx similarity index 82% rename from JSDemos/Demos/TreeView/ContextMenuIntegration/React/App.js rename to JSDemos/Demos/TreeView/ContextMenuIntegration/React/App.tsx index 0e9600cb1db..708decf4dd4 100644 --- a/JSDemos/Demos/TreeView/ContextMenuIntegration/React/App.js +++ b/JSDemos/Demos/TreeView/ContextMenuIntegration/React/App.tsx @@ -1,19 +1,21 @@ import React from 'react'; -import TreeView from 'devextreme-react/tree-view'; -import ContextMenu from 'devextreme-react/context-menu'; +import TreeView, { TreeViewTypes } from 'devextreme-react/tree-view'; +import ContextMenu, { ContextMenuTypes } from 'devextreme-react/context-menu'; import List from 'devextreme-react/list'; -import service from './data.js'; +import service from './data.ts'; const products = service.getProducts(); const menuItems = service.getMenuItems(); const App = () => { - const contextMenuRef = React.useRef(); - const treeViewRef = React.useRef(); + const contextMenuRef = React.useRef(null); + const treeViewRef = React.useRef(null); const [logItems, setLogItems] = React.useState([]); const [selectedTreeItem, setSelectedTreeItem] = React.useState(undefined); - const treeViewItemContextMenu = React.useCallback((e) => { + const treeViewItemContextMenu = React.useCallback(( + e: TreeViewTypes.ItemContextMenuEvent & { itemData: { price?: any; }; }, + ) => { setSelectedTreeItem(e.itemData); const isProduct = e.itemData.price !== undefined; @@ -26,7 +28,9 @@ const App = () => { contextMenuRef.current.instance.option('items[1].disabled', !e.node.expanded); }, []); - const contextMenuItemClick = React.useCallback((e) => { + const contextMenuItemClick = React.useCallback(( + e: ContextMenuTypes.ItemClickEvent & { itemData: { id?: any; }; }, + ) => { let logEntry = ''; switch (e.itemData.id) { case 'expand': { diff --git a/JSDemos/Demos/TreeView/ContextMenuIntegration/React/data.js b/JSDemos/Demos/TreeView/ContextMenuIntegration/React/data.ts similarity index 100% rename from JSDemos/Demos/TreeView/ContextMenuIntegration/React/data.js rename to JSDemos/Demos/TreeView/ContextMenuIntegration/React/data.ts diff --git a/JSDemos/Demos/TreeView/ContextMenuIntegration/React/index.html b/JSDemos/Demos/TreeView/ContextMenuIntegration/React/index.html index fb33a47d3fb..7aef756bcb4 100644 --- a/JSDemos/Demos/TreeView/ContextMenuIntegration/React/index.html +++ b/JSDemos/Demos/TreeView/ContextMenuIntegration/React/index.html @@ -12,7 +12,7 @@ diff --git a/JSDemos/Demos/TreeView/ContextMenuIntegration/React/index.js b/JSDemos/Demos/TreeView/ContextMenuIntegration/React/index.js deleted file mode 100644 index d9d7442ce76..00000000000 --- a/JSDemos/Demos/TreeView/ContextMenuIntegration/React/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App.js'; - -ReactDOM.render( - , - document.getElementById('app'), -); diff --git a/JSDemos/Demos/TreeView/ContextMenuIntegration/React/index.tsx b/JSDemos/Demos/TreeView/ContextMenuIntegration/React/index.tsx new file mode 100644 index 00000000000..8acbec4b617 --- /dev/null +++ b/JSDemos/Demos/TreeView/ContextMenuIntegration/React/index.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import App from './App.tsx'; + +ReactDOM.render( + , + document.getElementById('app'), +); diff --git a/JSDemos/Demos/TreeView/ContextMenuIntegration/ReactJs/App.js b/JSDemos/Demos/TreeView/ContextMenuIntegration/ReactJs/App.js new file mode 100644 index 00000000000..9a47ee5b095 --- /dev/null +++ b/JSDemos/Demos/TreeView/ContextMenuIntegration/ReactJs/App.js @@ -0,0 +1,85 @@ +import React from 'react'; +import TreeView from 'devextreme-react/tree-view'; +import ContextMenu from 'devextreme-react/context-menu'; +import List from 'devextreme-react/list'; +import service from './data.js'; + +const products = service.getProducts(); +const menuItems = service.getMenuItems(); +const App = () => { + const contextMenuRef = React.useRef(null); + const treeViewRef = React.useRef(null); + const [logItems, setLogItems] = React.useState([]); + const [selectedTreeItem, setSelectedTreeItem] = React.useState(undefined); + const treeViewItemContextMenu = React.useCallback((e) => { + setSelectedTreeItem(e.itemData); + const isProduct = e.itemData.price !== undefined; + contextMenuRef.current.instance.option('items[0].visible', !isProduct); + contextMenuRef.current.instance.option('items[1].visible', !isProduct); + contextMenuRef.current.instance.option('items[2].visible', isProduct); + contextMenuRef.current.instance.option('items[3].visible', isProduct); + contextMenuRef.current.instance.option('items[0].disabled', e.node.expanded); + contextMenuRef.current.instance.option('items[1].disabled', !e.node.expanded); + }, []); + const contextMenuItemClick = React.useCallback( + (e) => { + let logEntry = ''; + switch (e.itemData.id) { + case 'expand': { + logEntry = `The '${selectedTreeItem.text}' group was expanded`; + treeViewRef.current.instance.expandItem(selectedTreeItem.id); + break; + } + case 'collapse': { + logEntry = `The '${selectedTreeItem.text}' group was collapsed`; + treeViewRef.current.instance.collapseItem(selectedTreeItem.id); + break; + } + case 'details': { + logEntry = `Details about '${selectedTreeItem.text}' were displayed`; + break; + } + case 'copy': { + logEntry = `Information about '${selectedTreeItem.text}' was copied`; + break; + } + default: + break; + } + const updatedLogItems = [...logItems, logEntry]; + setLogItems(updatedLogItems); + }, + [logItems, selectedTreeItem, setLogItems], + ); + return ( +
+ +
+
+  Operations log: +
+ +
+ +
+ ); +}; +export default App; diff --git a/JSDemos/Demos/TreeView/ContextMenuIntegration/ReactJs/data.js b/JSDemos/Demos/TreeView/ContextMenuIntegration/ReactJs/data.js new file mode 100644 index 00000000000..ec385c448b5 --- /dev/null +++ b/JSDemos/Demos/TreeView/ContextMenuIntegration/ReactJs/data.js @@ -0,0 +1,393 @@ +const menuItems = [ + { id: 'expand', text: 'Expand category' }, + { id: 'collapse', text: 'Collapse category' }, + { id: 'details', text: 'Show product details' }, + { id: 'copy', text: 'Copy product info' }, +]; +const products = [ + { + id: '1', + text: 'Stores', + expanded: true, + items: [ + { + id: '1_1', + text: 'Super Mart of the West', + expanded: true, + items: [ + { + id: '1_1_1', + text: 'Video Players', + items: [ + { + id: '1_1_1_1', + text: 'HD Video Player', + price: 220, + image: '../../../../images/products/1.png', + }, + { + id: '1_1_1_2', + text: 'SuperHD Video Player', + image: '../../../../images/products/2.png', + price: 270, + }, + ], + }, + { + id: '1_1_2', + text: 'Televisions', + expanded: true, + items: [ + { + id: '1_1_2_1', + text: 'SuperLCD 42', + image: '../../../../images/products/7.png', + price: 1200, + }, + { + id: '1_1_2_2', + text: 'SuperLED 42', + image: '../../../../images/products/5.png', + price: 1450, + }, + { + id: '1_1_2_3', + text: 'SuperLED 50', + image: '../../../../images/products/4.png', + price: 1600, + }, + { + id: '1_1_2_4', + text: 'SuperLCD 55', + image: '../../../../images/products/6.png', + price: 1350, + }, + { + id: '1_1_2_5', + text: 'SuperLCD 70', + image: '../../../../images/products/9.png', + price: 4000, + }, + ], + }, + { + id: '1_1_3', + text: 'Monitors', + expanded: true, + items: [ + { + id: '1_1_3_1', + text: '19"', + expanded: true, + items: [ + { + id: '1_1_3_1_1', + text: 'DesktopLCD 19', + image: '../../../../images/products/10.png', + price: 160, + }, + ], + }, + { + id: '1_1_3_2', + text: '21"', + items: [ + { + id: '1_1_3_2_1', + text: 'DesktopLCD 21', + image: '../../../../images/products/12.png', + price: 170, + }, + { + id: '1_1_3_2_2', + text: 'DesktopLED 21', + image: '../../../../images/products/13.png', + price: 175, + }, + ], + }, + ], + }, + { + id: '1_1_4', + text: 'Projectors', + items: [ + { + id: '1_1_4_1', + text: 'Projector Plus', + image: '../../../../images/products/14.png', + price: 550, + }, + { + id: '1_1_4_2', + text: 'Projector PlusHD', + image: '../../../../images/products/15.png', + price: 750, + }, + ], + }, + ], + }, + { + id: '1_2', + text: 'Braeburn', + items: [ + { + id: '1_2_1', + text: 'Video Players', + items: [ + { + id: '1_2_1_1', + text: 'HD Video Player', + image: '../../../../images/products/1.png', + price: 240, + }, + { + id: '1_2_1_2', + text: 'SuperHD Video Player', + image: '../../../../images/products/2.png', + price: 300, + }, + ], + }, + { + id: '1_2_2', + text: 'Televisions', + items: [ + { + id: '1_2_2_1', + text: 'SuperPlasma 50', + image: '../../../../images/products/3.png', + price: 1800, + }, + { + id: '1_2_2_2', + text: 'SuperPlasma 65', + image: '../../../../images/products/8.png', + price: 3500, + }, + ], + }, + { + id: '1_2_3', + text: 'Monitors', + items: [ + { + id: '1_2_3_1', + text: '19"', + items: [ + { + id: '1_2_3_1_1', + text: 'DesktopLCD 19', + image: '../../../../images/products/10.png', + price: 170, + }, + ], + }, + { + id: '1_2_3_2', + text: '21"', + items: [ + { + id: '1_2_3_2_1', + text: 'DesktopLCD 21', + image: '../../../../images/products/12.png', + price: 180, + }, + { + id: '1_2_3_2_2', + text: 'DesktopLED 21', + image: '../../../../images/products/13.png', + price: 190, + }, + ], + }, + ], + }, + ], + }, + { + id: '1_3', + text: 'E-Mart', + items: [ + { + id: '1_3_1', + text: 'Video Players', + items: [ + { + id: '1_3_1_1', + text: 'HD Video Player', + image: '../../../../images/products/1.png', + price: 220, + }, + { + id: '1_3_1_2', + text: 'SuperHD Video Player', + image: '../../../../images/products/2.png', + price: 275, + }, + ], + }, + { + id: '1_3_3', + text: 'Monitors', + items: [ + { + id: '1_3_3_1', + text: '19"', + items: [ + { + id: '1_3_3_1_1', + text: 'DesktopLCD 19', + image: '../../../../images/products/10.png', + price: 165, + }, + ], + }, + { + id: '1_3_3_2', + text: '21"', + items: [ + { + id: '1_3_3_2_1', + text: 'DesktopLCD 21', + image: '../../../../images/products/12.png', + price: 175, + }, + ], + }, + ], + }, + ], + }, + { + id: '1_4', + text: 'Walters', + items: [ + { + id: '1_4_1', + text: 'Video Players', + items: [ + { + id: '1_4_1_1', + text: 'HD Video Player', + image: '../../../../images/products/1.png', + price: 210, + }, + { + id: '1_4_1_2', + text: 'SuperHD Video Player', + image: '../../../../images/products/2.png', + price: 250, + }, + ], + }, + { + id: '1_4_2', + text: 'Televisions', + items: [ + { + id: '1_4_2_1', + text: 'SuperLCD 42', + image: '../../../../images/products/7.png', + price: 1100, + }, + { + id: '1_4_2_2', + text: 'SuperLED 42', + image: '../../../../images/products/5.png', + price: 1400, + }, + { + id: '1_4_2_3', + text: 'SuperLED 50', + image: '../../../../images/products/4.png', + price: 1500, + }, + { + id: '1_4_2_4', + text: 'SuperLCD 55', + image: '../../../../images/products/6.png', + price: 1300, + }, + { + id: '1_4_2_5', + text: 'SuperLCD 70', + image: '../../../../images/products/9.png', + price: 4000, + }, + { + id: '1_4_2_6', + text: 'SuperPlasma 50', + image: '../../../../images/products/3.png', + price: 1700, + }, + ], + }, + { + id: '1_4_3', + text: 'Monitors', + items: [ + { + id: '1_4_3_1', + text: '19"', + items: [ + { + id: '1_4_3_1_1', + text: 'DesktopLCD 19', + image: '../../../../images/products/10.png', + price: 160, + }, + ], + }, + { + id: '1_4_3_2', + text: '21"', + items: [ + { + id: '1_4_3_2_1', + text: 'DesktopLCD 21', + image: '../../../../images/products/12.png', + price: 170, + }, + { + id: '1_4_3_2_2', + text: 'DesktopLED 21', + image: '../../../../images/products/13.png', + price: 180, + }, + ], + }, + ], + }, + { + id: '1_4_4', + text: 'Projectors', + items: [ + { + id: '1_4_4_1', + text: 'Projector Plus', + image: '../../../../images/products/14.png', + price: 550, + }, + { + id: '1_4_4_2', + text: 'Projector PlusHD', + image: '../../../../images/products/15.png', + price: 750, + }, + ], + }, + ], + }, + ], + }, +]; +export default { + getProducts() { + return products; + }, + getMenuItems() { + return menuItems; + }, +}; diff --git a/JSDemos/Demos/TreeView/ContextMenuIntegration/ReactJs/index.html b/JSDemos/Demos/TreeView/ContextMenuIntegration/ReactJs/index.html new file mode 100644 index 00000000000..4d0ee54d8eb --- /dev/null +++ b/JSDemos/Demos/TreeView/ContextMenuIntegration/ReactJs/index.html @@ -0,0 +1,44 @@ + + + + DevExtreme Demo + + + + + + + + + + + + + +
+
+
+ + diff --git a/JSDemos/Demos/TreeView/ContextMenuIntegration/ReactJs/index.js b/JSDemos/Demos/TreeView/ContextMenuIntegration/ReactJs/index.js new file mode 100644 index 00000000000..b853e0be824 --- /dev/null +++ b/JSDemos/Demos/TreeView/ContextMenuIntegration/ReactJs/index.js @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App.js'; + +ReactDOM.render(, document.getElementById('app')); diff --git a/JSDemos/Demos/TreeView/ContextMenuIntegration/ReactJs/styles.css b/JSDemos/Demos/TreeView/ContextMenuIntegration/ReactJs/styles.css new file mode 100644 index 00000000000..cb947fce44f --- /dev/null +++ b/JSDemos/Demos/TreeView/ContextMenuIntegration/ReactJs/styles.css @@ -0,0 +1,35 @@ +.form { + display: flex; +} + +.form > div, +#treeview { + display: inline-block; + vertical-align: top; +} + +.log-container { + padding: 20px; + margin-left: 20px; + font-size: 115%; + font-weight: bold; + background-color: rgba(191, 191, 191, 0.15); + height: 100%; +} + +.log-container .dx-icon-clock { + position: relative; + top: 1px; +} + +#log { + margin-top: 10px; +} + +#log .dx-empty-message { + padding-left: 0; +} + +.dx-list-item-content { + padding-left: 0; +} diff --git a/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/React/App.js b/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/React/App.tsx similarity index 79% rename from JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/React/App.js rename to JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/React/App.tsx index 513b4afee66..5a10e3f6b06 100644 --- a/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/React/App.js +++ b/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/React/App.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import TreeView from 'devextreme-react/tree-view'; -import Sortable from 'devextreme-react/sortable'; +import TreeView, { TreeViewTypes } from 'devextreme-react/tree-view'; +import Sortable, { SortableTypes } from 'devextreme-react/sortable'; -import service from './data.js'; +import service from './data.ts'; -const calculateToIndex = (e) => { +const calculateToIndex = (e: SortableTypes.DragChangeEvent) => { if (e.fromComponent !== e.toComponent || e.dropInsideItem) { return e.toIndex; } @@ -14,7 +14,7 @@ const calculateToIndex = (e) => { : e.toIndex + 1; }; -const findNode = (treeView, index) => { +const findNode = (treeView: any, index: string | number) => { const nodeElement = treeView.element().querySelectorAll('.dx-treeview-node')[index]; if (nodeElement) { return findNodeById(treeView.getNodes(), nodeElement.getAttribute('data-item-id')); @@ -22,7 +22,7 @@ const findNode = (treeView, index) => { return null; }; -const findNodeById = (nodes, id) => { +const findNodeById = (nodes: TreeViewTypes.Node[], id) => { for (let i = 0; i < nodes.length; i += 1) { if (nodes[i].itemData.id === id) { return nodes[i]; @@ -37,9 +37,9 @@ const findNodeById = (nodes, id) => { return null; }; -const moveNode = (fromNode, toNode, fromItems, toItems, isDropInsideItem) => { +const moveNode = (fromNode: TreeViewTypes.Node, toNode: TreeViewTypes.Node, fromItems, toItems, isDropInsideItem) => { const fromNodeContainingArray = getNodeContainingArray(fromNode, fromItems); - const fromIndex = fromNodeContainingArray.findIndex((item) => item.id === fromNode.itemData.id); + const fromIndex = fromNodeContainingArray.findIndex((item: { id: any; }) => item.id === fromNode.itemData.id); fromNodeContainingArray.splice(fromIndex, 1); if (isDropInsideItem) { @@ -48,16 +48,16 @@ const moveNode = (fromNode, toNode, fromItems, toItems, isDropInsideItem) => { const toNodeContainingArray = getNodeContainingArray(toNode, toItems); const toIndex = toNode === null ? toNodeContainingArray.length - : toNodeContainingArray.findIndex((item) => item.id === toNode.itemData.id); + : toNodeContainingArray.findIndex((item: { id: any; }) => item.id === toNode.itemData.id); toNodeContainingArray.splice(toIndex, 0, fromNode.itemData); } }; -const getNodeContainingArray = (node, rootArray) => (node === null || node.parent === null +const getNodeContainingArray = (node: TreeViewTypes.Node, rootArray) => (node === null || node.parent === null ? rootArray : node.parent.itemData.items); -const isChildNode = (parentNode, childNode) => { +const isChildNode = (parentNode: TreeViewTypes.Node, childNode: TreeViewTypes.Node) => { let { parent } = childNode; while (parent !== null) { if (parent.itemData.id === parentNode.itemData.id) { @@ -83,13 +83,17 @@ const getTopVisibleNode = (component) => { }; const App = () => { - const treeViewDriveCRef = React.useRef(); - const treeViewDriveDRef = React.useRef(); + const treeViewDriveCRef = React.useRef(null); + const treeViewDriveDRef = React.useRef(null); const [itemsDriveC, setItemsDriveC] = React.useState(service.getItemsDriveC()); const [itemsDriveD, setItemsDriveD] = React.useState(service.getItemsDriveD()); - const onDragChange = React.useCallback((e) => { + const getTreeView = React.useCallback((driveName: string) => (driveName === 'driveC' + ? treeViewDriveCRef.current.instance + : treeViewDriveDRef.current.instance), []); + + const onDragChange = React.useCallback((e: SortableTypes.DragChangeEvent) => { if (e.fromComponent === e.toComponent) { const fromNode = findNode(getTreeView(e.fromData), e.fromIndex); const toNode = findNode(getTreeView(e.toData), calculateToIndex(e)); @@ -99,11 +103,11 @@ const App = () => { } }, [getTreeView]); - const getStateFieldItems = React.useCallback((driveName) => (driveName === 'driveC' + const getStateFieldItems = React.useCallback((driveName: string) => (driveName === 'driveC' ? itemsDriveC : itemsDriveD), [itemsDriveC, itemsDriveD]); - const onDragEnd = React.useCallback((e) => { + const onDragEnd = React.useCallback((e: SortableTypes.DragEndEvent) => { if (e.fromComponent === e.toComponent && e.fromIndex === e.toIndex) { return; } @@ -131,10 +135,6 @@ const App = () => { toTreeView.scrollToItem(toTopVisibleNode); }, [getTreeView, getStateFieldItems]); - const getTreeView = React.useCallback((driveName) => (driveName === 'driveC' - ? treeViewDriveCRef.current.instance - : treeViewDriveDRef.current.instance), []); - return (
diff --git a/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/React/data.js b/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/React/data.ts similarity index 100% rename from JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/React/data.js rename to JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/React/data.ts diff --git a/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/React/index.html b/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/React/index.html index fb33a47d3fb..7aef756bcb4 100644 --- a/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/React/index.html +++ b/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/React/index.html @@ -12,7 +12,7 @@ diff --git a/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/React/index.js b/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/React/index.js deleted file mode 100644 index d9d7442ce76..00000000000 --- a/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/React/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App.js'; - -ReactDOM.render( - , - document.getElementById('app'), -); diff --git a/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/React/index.tsx b/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/React/index.tsx new file mode 100644 index 00000000000..8acbec4b617 --- /dev/null +++ b/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/React/index.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import App from './App.tsx'; + +ReactDOM.render( + , + document.getElementById('app'), +); diff --git a/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/ReactJs/App.js b/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/ReactJs/App.js new file mode 100644 index 00000000000..2b575d62f5b --- /dev/null +++ b/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/ReactJs/App.js @@ -0,0 +1,184 @@ +import React from 'react'; +import TreeView from 'devextreme-react/tree-view'; +import Sortable from 'devextreme-react/sortable'; +import service from './data.js'; + +const calculateToIndex = (e) => { + if (e.fromComponent !== e.toComponent || e.dropInsideItem) { + return e.toIndex; + } + return e.fromIndex >= e.toIndex ? e.toIndex : e.toIndex + 1; +}; +const findNode = (treeView, index) => { + const nodeElement = treeView.element().querySelectorAll('.dx-treeview-node')[index]; + if (nodeElement) { + return findNodeById(treeView.getNodes(), nodeElement.getAttribute('data-item-id')); + } + return null; +}; +const findNodeById = (nodes, id) => { + for (let i = 0; i < nodes.length; i += 1) { + if (nodes[i].itemData.id === id) { + return nodes[i]; + } + if (nodes[i].children) { + const node = findNodeById(nodes[i].children, id); + if (node != null) { + return node; + } + } + } + return null; +}; +const moveNode = (fromNode, toNode, fromItems, toItems, isDropInsideItem) => { + const fromNodeContainingArray = getNodeContainingArray(fromNode, fromItems); + const fromIndex = fromNodeContainingArray.findIndex((item) => item.id === fromNode.itemData.id); + fromNodeContainingArray.splice(fromIndex, 1); + if (isDropInsideItem) { + toNode.itemData.items.splice(toNode.itemData.items.length, 0, fromNode.itemData); + } else { + const toNodeContainingArray = getNodeContainingArray(toNode, toItems); + const toIndex = toNode === null + ? toNodeContainingArray.length + : toNodeContainingArray.findIndex((item) => item.id === toNode.itemData.id); + toNodeContainingArray.splice(toIndex, 0, fromNode.itemData); + } +}; +const getNodeContainingArray = (node, rootArray) => + (node === null || node.parent === null ? rootArray : node.parent.itemData.items); +const isChildNode = (parentNode, childNode) => { + let { parent } = childNode; + while (parent !== null) { + if (parent.itemData.id === parentNode.itemData.id) { + return true; + } + parent = parent.parent; + } + return false; +}; +const getTopVisibleNode = (component) => { + const treeViewElement = component.element(); + const treeViewTopPosition = treeViewElement.getBoundingClientRect().top; + const nodes = treeViewElement.querySelectorAll('.dx-treeview-node'); + for (let i = 0; i < nodes.length; i += 1) { + const nodeTopPosition = nodes[i].getBoundingClientRect().top; + if (nodeTopPosition >= treeViewTopPosition) { + return nodes[i]; + } + } + return null; +}; +const App = () => { + const treeViewDriveCRef = React.useRef(null); + const treeViewDriveDRef = React.useRef(null); + const [itemsDriveC, setItemsDriveC] = React.useState(service.getItemsDriveC()); + const [itemsDriveD, setItemsDriveD] = React.useState(service.getItemsDriveD()); + const getTreeView = React.useCallback( + (driveName) => + (driveName === 'driveC' + ? treeViewDriveCRef.current.instance + : treeViewDriveDRef.current.instance), + [], + ); + const onDragChange = React.useCallback( + (e) => { + if (e.fromComponent === e.toComponent) { + const fromNode = findNode(getTreeView(e.fromData), e.fromIndex); + const toNode = findNode(getTreeView(e.toData), calculateToIndex(e)); + if (toNode !== null && isChildNode(fromNode, toNode)) { + e.cancel = true; + } + } + }, + [getTreeView], + ); + const getStateFieldItems = React.useCallback( + (driveName) => (driveName === 'driveC' ? itemsDriveC : itemsDriveD), + [itemsDriveC, itemsDriveD], + ); + const onDragEnd = React.useCallback( + (e) => { + if (e.fromComponent === e.toComponent && e.fromIndex === e.toIndex) { + return; + } + const fromTreeView = getTreeView(e.fromData); + const toTreeView = getTreeView(e.toData); + const fromNode = findNode(fromTreeView, e.fromIndex); + const toNode = findNode(toTreeView, calculateToIndex(e)); + if (e.dropInsideItem && toNode !== null && !toNode.itemData.isDirectory) { + return; + } + const fromTopVisibleNode = getTopVisibleNode(e.fromComponent); + const toTopVisibleNode = getTopVisibleNode(e.toComponent); + const fromItems = getStateFieldItems(e.fromData); + const toItems = getStateFieldItems(e.toData); + moveNode(fromNode, toNode, fromItems, toItems, e.dropInsideItem); + setItemsDriveC([...fromItems]); + setItemsDriveD([...toItems]); + fromTreeView.scrollToItem(fromTopVisibleNode); + toTreeView.scrollToItem(toTopVisibleNode); + }, + [getTreeView, getStateFieldItems], + ); + return ( +
+
+
+
+ + Drive C: +
+
+ + + +
+
+
+
+ + Drive D: +
+
+ + + +
+
+ ); +}; +export default App; diff --git a/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/ReactJs/data.js b/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/ReactJs/data.js new file mode 100644 index 00000000000..b335069662d --- /dev/null +++ b/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/ReactJs/data.js @@ -0,0 +1,113 @@ +const itemsDriveD = []; +const itemsDriveC = [ + { + id: '1', + name: 'Documents', + icon: 'activefolder', + isDirectory: true, + expanded: true, + items: [ + { + id: '2', + name: 'Projects', + icon: 'activefolder', + isDirectory: true, + expanded: true, + items: [ + { + id: '3', + name: 'About.rtf', + icon: 'file', + isDirectory: false, + }, + { + id: '4', + name: 'Passwords.rtf', + icon: 'file', + isDirectory: false, + }, + ], + }, + { + id: '5', + name: 'About.xml', + icon: 'file', + isDirectory: false, + }, + { + id: '6', + name: 'Managers.rtf', + icon: 'file', + isDirectory: false, + }, + { + id: '7', + name: 'ToDo.txt', + icon: 'file', + isDirectory: false, + }, + ], + }, + { + id: '8', + name: 'Images', + icon: 'activefolder', + isDirectory: true, + expanded: true, + items: [ + { + id: '9', + name: 'logo.png', + icon: 'file', + isDirectory: false, + }, + { + id: '10', + name: 'banner.gif', + icon: 'file', + isDirectory: false, + }, + ], + }, + { + id: '11', + name: 'System', + icon: 'activefolder', + isDirectory: true, + expanded: true, + items: [ + { + id: '12', + name: 'Employees.txt', + icon: 'file', + isDirectory: false, + }, + { + id: '13', + name: 'PasswordList.txt', + icon: 'file', + isDirectory: false, + }, + ], + }, + { + id: '14', + name: 'Description.rtf', + icon: 'file', + isDirectory: false, + }, + { + id: '15', + name: 'Description.txt', + icon: 'file', + isDirectory: false, + }, +]; +export default { + getItemsDriveC() { + return itemsDriveC; + }, + getItemsDriveD() { + return itemsDriveD; + }, +}; diff --git a/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/ReactJs/index.html b/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/ReactJs/index.html new file mode 100644 index 00000000000..4d0ee54d8eb --- /dev/null +++ b/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/ReactJs/index.html @@ -0,0 +1,44 @@ + + + + DevExtreme Demo + + + + + + + + + + + + + +
+
+
+ + diff --git a/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/ReactJs/index.js b/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/ReactJs/index.js new file mode 100644 index 00000000000..b853e0be824 --- /dev/null +++ b/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/ReactJs/index.js @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App.js'; + +ReactDOM.render(, document.getElementById('app')); diff --git a/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/ReactJs/styles.css b/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/ReactJs/styles.css new file mode 100644 index 00000000000..0a32b1fd7ca --- /dev/null +++ b/JSDemos/Demos/TreeView/DragAndDropHierarchicalDataStructure/ReactJs/styles.css @@ -0,0 +1,31 @@ +.form { + display: flex; +} + +.form > div { + display: inline-block; + vertical-align: top; +} + +#treeviewDriveC, +#treeviewDriveD { + margin-top: 10px; +} + +.drive-header { + min-height: auto; + padding: 0; + cursor: default; +} + +.drive-panel { + padding: 20px 30px; + font-size: 115%; + font-weight: bold; + border-right: 1px solid rgba(165, 165, 165, 0.4); + height: 100%; +} + +.drive-panel:last-of-type { + border-right: none; +} diff --git a/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/React/App.js b/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/React/App.tsx similarity index 84% rename from JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/React/App.js rename to JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/React/App.tsx index 245e660fff1..3156f6fae82 100644 --- a/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/React/App.js +++ b/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/React/App.tsx @@ -1,14 +1,14 @@ import React from 'react'; import TreeView from 'devextreme-react/tree-view'; -import Sortable from 'devextreme-react/sortable'; +import Sortable, { SortableTypes } from 'devextreme-react/sortable'; -import service from './data.js'; +import service from './data.ts'; -const getStateFieldName = (driveName) => (driveName === 'driveC' +const getStateFieldName = (driveName: string) => (driveName === 'driveC' ? 'itemsDriveC' : 'itemsDriveD'); -const calculateToIndex = (e) => { +const calculateToIndex = (e: SortableTypes.DragChangeEvent) => { if (e.fromComponent !== e.toComponent || e.dropInsideItem) { return e.toIndex; } @@ -18,7 +18,7 @@ const calculateToIndex = (e) => { : e.toIndex + 1; }; -const findNode = (treeView, index) => { +const findNode = (treeView, index: string | number) => { const nodeElement = treeView.element().querySelectorAll('.dx-treeview-node')[index]; if (nodeElement) { return findNodeById(treeView.getNodes(), nodeElement.getAttribute('data-item-id')); @@ -60,7 +60,7 @@ const moveNode = (fromNode, toNode, fromItems, toItems, isDropInsideItem) => { } }; -const moveChildren = (node, fromDataSource, toDataSource) => { +const moveChildren = (node, fromDataSource, toDataSource: any[]) => { if (!node.itemData.isDirectory) { return; } @@ -76,7 +76,7 @@ const moveChildren = (node, fromDataSource, toDataSource) => { }); }; -const isChildNode = (parentNode, childNode) => { +const isChildNode = (parentNode: { itemData: { id: any; }; }, childNode: { parent: any; }) => { let { parent } = childNode; while (parent !== null) { if (parent.itemData.id === parentNode.itemData.id) { @@ -102,13 +102,17 @@ const getTopVisibleNode = (component) => { }; const App = () => { - const treeViewDriveCRef = React.useRef(); - const treeViewDriveDRef = React.useRef(); + const treeViewDriveCRef = React.useRef(null); + const treeViewDriveDRef = React.useRef(null); const [itemsDriveC, setItemsDriveC] = React.useState(service.getItemsDriveC()); const [itemsDriveD, setItemsDriveD] = React.useState(service.getItemsDriveD()); - const onDragChange = React.useCallback((e) => { + const getTreeView = React.useCallback((driveName: string) => (driveName === 'driveC' + ? treeViewDriveCRef.current.instance + : treeViewDriveDRef.current.instance), []); + + const onDragChange = React.useCallback((e: SortableTypes.DragChangeEvent) => { if (e.fromComponent === e.toComponent) { const fromNode = findNode(getTreeView(e.fromData), e.fromIndex); const toNode = findNode(getTreeView(e.toData), calculateToIndex(e)); @@ -118,7 +122,7 @@ const App = () => { } }, [getTreeView]); - const onDragEnd = React.useCallback((e) => { + const onDragEnd = React.useCallback((e: SortableTypes.DragEndEvent) => { if (e.fromComponent === e.toComponent && e.fromIndex === e.toIndex) { return; } @@ -136,23 +140,23 @@ const App = () => { const fromTopVisibleNode = getTopVisibleNode(e.fromComponent); const toTopVisibleNode = getTopVisibleNode(e.toComponent); - const fromItems = getStateFieldName(e.fromData) === 'driveC' + const fromItems = getStateFieldName(e.fromData) === 'itemsDriveC' ? itemsDriveC : itemsDriveD; - const toItems = getStateFieldName(e.toData) === 'driveC' + const toItems = getStateFieldName(e.toData) === 'itemsDriveC' ? itemsDriveC : itemsDriveD; moveNode(fromNode, toNode, fromItems, toItems, e.dropInsideItem); - if (getStateFieldName(e.fromData) === 'driveC') { + if (getStateFieldName(e.fromData) === 'itemsDriveC') { setItemsDriveC([...fromItems]); } else { setItemsDriveD([...fromItems]); } - if (getStateFieldName(e.toData) === 'driveC') { + if (getStateFieldName(e.toData) === 'itemsDriveC') { setItemsDriveC([...toItems]); } else { setItemsDriveD([...toItems]); @@ -162,10 +166,6 @@ const App = () => { toTreeView.scrollToItem(toTopVisibleNode); }, [getTreeView, itemsDriveC, itemsDriveD, setItemsDriveC, setItemsDriveD]); - const getTreeView = React.useCallback((driveName) => (driveName === 'driveC' - ? treeViewDriveCRef.current.instance - : treeViewDriveDRef.current.instance), []); - return (
diff --git a/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/React/data.js b/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/React/data.ts similarity index 100% rename from JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/React/data.js rename to JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/React/data.ts diff --git a/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/React/index.html b/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/React/index.html index fb33a47d3fb..7aef756bcb4 100644 --- a/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/React/index.html +++ b/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/React/index.html @@ -12,7 +12,7 @@ diff --git a/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/React/index.js b/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/React/index.js deleted file mode 100644 index d9d7442ce76..00000000000 --- a/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/React/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App.js'; - -ReactDOM.render( - , - document.getElementById('app'), -); diff --git a/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/React/index.tsx b/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/React/index.tsx new file mode 100644 index 00000000000..8acbec4b617 --- /dev/null +++ b/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/React/index.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import App from './App.tsx'; + +ReactDOM.render( + , + document.getElementById('app'), +); diff --git a/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/ReactJs/App.js b/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/ReactJs/App.js new file mode 100644 index 00000000000..38c4e1d7490 --- /dev/null +++ b/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/ReactJs/App.js @@ -0,0 +1,200 @@ +import React from 'react'; +import TreeView from 'devextreme-react/tree-view'; +import Sortable from 'devextreme-react/sortable'; +import service from './data.js'; + +const getStateFieldName = (driveName) => (driveName === 'driveC' ? 'itemsDriveC' : 'itemsDriveD'); +const calculateToIndex = (e) => { + if (e.fromComponent !== e.toComponent || e.dropInsideItem) { + return e.toIndex; + } + return e.fromIndex >= e.toIndex ? e.toIndex : e.toIndex + 1; +}; +const findNode = (treeView, index) => { + const nodeElement = treeView.element().querySelectorAll('.dx-treeview-node')[index]; + if (nodeElement) { + return findNodeById(treeView.getNodes(), nodeElement.getAttribute('data-item-id')); + } + return null; +}; +const findNodeById = (nodes, id) => { + for (let i = 0; i < nodes.length; i += 1) { + if (nodes[i].itemData.id === id) { + return nodes[i]; + } + if (nodes[i].children) { + const node = findNodeById(nodes[i].children, id); + if (node != null) { + return node; + } + } + } + return null; +}; +const moveNode = (fromNode, toNode, fromItems, toItems, isDropInsideItem) => { + const fromIndex = fromItems.findIndex((item) => item.id === fromNode.itemData.id); + fromItems.splice(fromIndex, 1); + const toIndex = toNode === null || isDropInsideItem + ? toItems.length + : toItems.findIndex((item) => item.id === toNode.itemData.id); + toItems.splice(toIndex, 0, fromNode.itemData); + moveChildren(fromNode, fromItems, toItems); + if (isDropInsideItem) { + fromNode.itemData.parentId = toNode.itemData.id; + } else { + fromNode.itemData.parentId = toNode != null ? toNode.itemData.parentId : undefined; + } +}; +const moveChildren = (node, fromDataSource, toDataSource) => { + if (!node.itemData.isDirectory) { + return; + } + node.children.forEach((child) => { + if (child.itemData.isDirectory) { + moveChildren(child, fromDataSource, toDataSource); + } + const fromIndex = fromDataSource.findIndex((item) => item.id === child.itemData.id); + fromDataSource.splice(fromIndex, 1); + toDataSource.splice(toDataSource.length, 0, child.itemData); + }); +}; +const isChildNode = (parentNode, childNode) => { + let { parent } = childNode; + while (parent !== null) { + if (parent.itemData.id === parentNode.itemData.id) { + return true; + } + parent = parent.parent; + } + return false; +}; +const getTopVisibleNode = (component) => { + const treeViewElement = component.element(); + const treeViewTopPosition = treeViewElement.getBoundingClientRect().top; + const nodes = treeViewElement.querySelectorAll('.dx-treeview-node'); + for (let i = 0; i < nodes.length; i += 1) { + const nodeTopPosition = nodes[i].getBoundingClientRect().top; + if (nodeTopPosition >= treeViewTopPosition) { + return nodes[i]; + } + } + return null; +}; +const App = () => { + const treeViewDriveCRef = React.useRef(null); + const treeViewDriveDRef = React.useRef(null); + const [itemsDriveC, setItemsDriveC] = React.useState(service.getItemsDriveC()); + const [itemsDriveD, setItemsDriveD] = React.useState(service.getItemsDriveD()); + const getTreeView = React.useCallback( + (driveName) => + (driveName === 'driveC' + ? treeViewDriveCRef.current.instance + : treeViewDriveDRef.current.instance), + [], + ); + const onDragChange = React.useCallback( + (e) => { + if (e.fromComponent === e.toComponent) { + const fromNode = findNode(getTreeView(e.fromData), e.fromIndex); + const toNode = findNode(getTreeView(e.toData), calculateToIndex(e)); + if (toNode !== null && isChildNode(fromNode, toNode)) { + e.cancel = true; + } + } + }, + [getTreeView], + ); + const onDragEnd = React.useCallback( + (e) => { + if (e.fromComponent === e.toComponent && e.fromIndex === e.toIndex) { + return; + } + const fromTreeView = getTreeView(e.fromData); + const toTreeView = getTreeView(e.toData); + const fromNode = findNode(fromTreeView, e.fromIndex); + const toNode = findNode(toTreeView, calculateToIndex(e)); + if (e.dropInsideItem && toNode !== null && !toNode.itemData.isDirectory) { + return; + } + const fromTopVisibleNode = getTopVisibleNode(e.fromComponent); + const toTopVisibleNode = getTopVisibleNode(e.toComponent); + const fromItems = getStateFieldName(e.fromData) === 'itemsDriveC' ? itemsDriveC : itemsDriveD; + const toItems = getStateFieldName(e.toData) === 'itemsDriveC' ? itemsDriveC : itemsDriveD; + moveNode(fromNode, toNode, fromItems, toItems, e.dropInsideItem); + if (getStateFieldName(e.fromData) === 'itemsDriveC') { + setItemsDriveC([...fromItems]); + } else { + setItemsDriveD([...fromItems]); + } + if (getStateFieldName(e.toData) === 'itemsDriveC') { + setItemsDriveC([...toItems]); + } else { + setItemsDriveD([...toItems]); + } + fromTreeView.scrollToItem(fromTopVisibleNode); + toTreeView.scrollToItem(toTopVisibleNode); + }, + [getTreeView, itemsDriveC, itemsDriveD, setItemsDriveC, setItemsDriveD], + ); + return ( +
+
+
+
+ + Drive C: +
+
+ + + +
+
+
+
+ + Drive D: +
+
+ + + +
+
+ ); +}; +export default App; diff --git a/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/ReactJs/data.js b/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/ReactJs/data.js new file mode 100644 index 00000000000..a5460713e7b --- /dev/null +++ b/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/ReactJs/data.js @@ -0,0 +1,126 @@ +const itemsDriveD = []; +const itemsDriveC = [ + { + id: '1', + name: 'Documents', + icon: 'activefolder', + isDirectory: true, + expanded: true, + }, + { + id: '2', + parentId: '1', + name: 'Projects', + icon: 'activefolder', + isDirectory: true, + expanded: true, + }, + { + id: '3', + parentId: '2', + name: 'About.rtf', + icon: 'file', + isDirectory: false, + expanded: true, + }, + { + id: '4', + parentId: '2', + name: 'Passwords.rtf', + icon: 'file', + isDirectory: false, + expanded: true, + }, + { + id: '5', + parentId: '2', + name: 'About.xml', + icon: 'file', + isDirectory: false, + expanded: true, + }, + { + id: '6', + parentId: '2', + name: 'Managers.rtf', + icon: 'file', + isDirectory: false, + expanded: true, + }, + { + id: '7', + parentId: '2', + name: 'ToDo.txt', + icon: 'file', + isDirectory: false, + expanded: true, + }, + { + id: '8', + name: 'Images', + icon: 'activefolder', + isDirectory: true, + expanded: true, + }, + { + id: '9', + parentId: '8', + name: 'logo.png', + icon: 'file', + isDirectory: false, + expanded: true, + }, + { + id: '10', + parentId: '8', + name: 'banner.gif', + icon: 'file', + isDirectory: false, + expanded: true, + }, + { + id: '11', + name: 'System', + icon: 'activefolder', + isDirectory: true, + expanded: true, + }, + { + id: '12', + parentId: '11', + name: 'Employees.txt', + icon: 'file', + isDirectory: false, + expanded: true, + }, + { + id: '13', + parentId: '11', + name: 'PasswordList.txt', + icon: 'file', + isDirectory: false, + expanded: true, + }, + { + id: '14', + name: 'Description.rtf', + icon: 'file', + isDirectory: false, + expanded: true, + }, + { + id: '15', + name: 'Description.txt', + icon: 'file', + isDirectory: false, + expanded: true, + }, +]; +export default { + getItemsDriveC() { + return itemsDriveC; + }, + getItemsDriveD() { + return itemsDriveD; + }, +}; diff --git a/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/ReactJs/index.html b/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/ReactJs/index.html new file mode 100644 index 00000000000..4d0ee54d8eb --- /dev/null +++ b/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/ReactJs/index.html @@ -0,0 +1,44 @@ + + + + DevExtreme Demo + + + + + + + + + + + + + +
+
+
+ + diff --git a/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/ReactJs/index.js b/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/ReactJs/index.js new file mode 100644 index 00000000000..b853e0be824 --- /dev/null +++ b/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/ReactJs/index.js @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App.js'; + +ReactDOM.render(, document.getElementById('app')); diff --git a/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/ReactJs/styles.css b/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/ReactJs/styles.css new file mode 100644 index 00000000000..0a32b1fd7ca --- /dev/null +++ b/JSDemos/Demos/TreeView/DragAndDropPlainDataStructure/ReactJs/styles.css @@ -0,0 +1,31 @@ +.form { + display: flex; +} + +.form > div { + display: inline-block; + vertical-align: top; +} + +#treeviewDriveC, +#treeviewDriveD { + margin-top: 10px; +} + +.drive-header { + min-height: auto; + padding: 0; + cursor: default; +} + +.drive-panel { + padding: 20px 30px; + font-size: 115%; + font-weight: bold; + border-right: 1px solid rgba(165, 165, 165, 0.4); + height: 100%; +} + +.drive-panel:last-of-type { + border-right: none; +} diff --git a/JSDemos/Demos/TreeView/FlatDataStructure/React/App.js b/JSDemos/Demos/TreeView/FlatDataStructure/React/App.tsx similarity index 78% rename from JSDemos/Demos/TreeView/FlatDataStructure/React/App.js rename to JSDemos/Demos/TreeView/FlatDataStructure/React/App.tsx index f80c315dc37..8f126ebcbaa 100644 --- a/JSDemos/Demos/TreeView/FlatDataStructure/React/App.js +++ b/JSDemos/Demos/TreeView/FlatDataStructure/React/App.tsx @@ -1,14 +1,14 @@ import React from 'react'; -import TreeView from 'devextreme-react/tree-view'; +import TreeView, { TreeViewTypes } from 'devextreme-react/tree-view'; -import service from './data.js'; +import service, { ProductType } from './data.ts'; const products = service.getProducts(); const App = () => { const [currentItem, setCurrentItem] = React.useState(products[0]); - const selectItem = React.useCallback((e) => { + const selectItem = React.useCallback((e: TreeViewTypes.ItemClickEvent & { itemData: ProductType }) => { setCurrentItem({ ...e.itemData }); }, [setCurrentItem]); diff --git a/JSDemos/Demos/TreeView/FlatDataStructure/React/data.js b/JSDemos/Demos/TreeView/FlatDataStructure/React/data.ts similarity index 91% rename from JSDemos/Demos/TreeView/FlatDataStructure/React/data.js rename to JSDemos/Demos/TreeView/FlatDataStructure/React/data.ts index 5506f38d15b..d0a7ceea256 100644 --- a/JSDemos/Demos/TreeView/FlatDataStructure/React/data.js +++ b/JSDemos/Demos/TreeView/FlatDataStructure/React/data.ts @@ -91,8 +91,17 @@ const products = [{ }, ]; +export interface ProductType { + ID: string, + categoryId?: string, + name: string, + icon?: string, + expanded?: boolean, + price?: number +} + export default { - getProducts() { + getProducts(): ProductType[] { return products; }, }; diff --git a/JSDemos/Demos/TreeView/FlatDataStructure/React/index.html b/JSDemos/Demos/TreeView/FlatDataStructure/React/index.html index fb33a47d3fb..7aef756bcb4 100644 --- a/JSDemos/Demos/TreeView/FlatDataStructure/React/index.html +++ b/JSDemos/Demos/TreeView/FlatDataStructure/React/index.html @@ -12,7 +12,7 @@ diff --git a/JSDemos/Demos/TreeView/FlatDataStructure/React/index.js b/JSDemos/Demos/TreeView/FlatDataStructure/React/index.js deleted file mode 100644 index d9d7442ce76..00000000000 --- a/JSDemos/Demos/TreeView/FlatDataStructure/React/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App.js'; - -ReactDOM.render( - , - document.getElementById('app'), -); diff --git a/JSDemos/Demos/TreeView/FlatDataStructure/React/index.tsx b/JSDemos/Demos/TreeView/FlatDataStructure/React/index.tsx new file mode 100644 index 00000000000..8acbec4b617 --- /dev/null +++ b/JSDemos/Demos/TreeView/FlatDataStructure/React/index.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import App from './App.tsx'; + +ReactDOM.render( + , + document.getElementById('app'), +); diff --git a/JSDemos/Demos/TreeView/FlatDataStructure/ReactJs/App.js b/JSDemos/Demos/TreeView/FlatDataStructure/ReactJs/App.js new file mode 100644 index 00000000000..45fb436dc42 --- /dev/null +++ b/JSDemos/Demos/TreeView/FlatDataStructure/ReactJs/App.js @@ -0,0 +1,39 @@ +import React from 'react'; +import TreeView from 'devextreme-react/tree-view'; +import service from './data.js'; + +const products = service.getProducts(); +const App = () => { + const [currentItem, setCurrentItem] = React.useState(products[0]); + const selectItem = React.useCallback( + (e) => { + setCurrentItem({ ...e.itemData }); + }, + [setCurrentItem], + ); + return ( +
+ + {currentItem.price && ( +
+ {currentItem.name} +
{currentItem.name}
+
{`$${currentItem.price}`}
+
+ )} +
+ ); +}; +export default App; diff --git a/JSDemos/Demos/TreeView/FlatDataStructure/ReactJs/data.js b/JSDemos/Demos/TreeView/FlatDataStructure/ReactJs/data.js new file mode 100644 index 00000000000..a253be81179 --- /dev/null +++ b/JSDemos/Demos/TreeView/FlatDataStructure/ReactJs/data.js @@ -0,0 +1,114 @@ +const products = [ + { + ID: '1', + name: 'Stores', + expanded: true, + }, + { + ID: '1_1', + categoryId: '1', + name: 'Super Mart of the West', + expanded: true, + }, + { + ID: '1_1_1', + categoryId: '1_1', + name: 'Video Players', + }, + { + ID: '1_1_1_1', + categoryId: '1_1_1', + name: 'HD Video Player', + icon: '../../../../images/products/1.png', + price: 220, + }, + { + ID: '1_1_1_2', + categoryId: '1_1_1', + name: 'SuperHD Video Player', + icon: '../../../../images/products/2.png', + price: 270, + }, + { + ID: '1_1_2', + categoryId: '1_1', + name: 'Televisions', + expanded: true, + }, + { + ID: '1_1_2_1', + categoryId: '1_1_2', + name: 'SuperLCD 42', + icon: '../../../../images/products/7.png', + price: 1200, + }, + { + ID: '1_1_2_2', + categoryId: '1_1_2', + name: 'SuperLED 42', + icon: '../../../../images/products/5.png', + price: 1450, + }, + { + ID: '1_1_2_3', + categoryId: '1_1_2', + name: 'SuperLED 50', + icon: '../../../../images/products/4.png', + price: 1600, + }, + { + ID: '1_1_2_4', + categoryId: '1_1_2', + name: 'SuperLCD 55', + icon: '../../../../images/products/6.png', + price: 1750, + }, + { + ID: '1_1_2_5', + categoryId: '1_1_2', + name: 'SuperLCD 70', + icon: '../../../../images/products/9.png', + price: 4000, + }, + { + ID: '1_1_3', + categoryId: '1_1', + name: 'Monitors', + }, + { + ID: '1_1_3_1', + categoryId: '1_1_3', + name: '19"', + }, + { + ID: '1_1_3_1_1', + categoryId: '1_1_3_1', + name: 'DesktopLCD 19', + icon: '../../../../images/products/10.png', + price: 160, + }, + { + ID: '1_1_4', + categoryId: '1_1', + name: 'Projectors', + }, + { + ID: '1_1_4_1', + categoryId: '1_1_4', + name: 'Projector Plus', + icon: '../../../../images/products/14.png', + price: 550, + }, + { + ID: '1_1_4_2', + categoryId: '1_1_4', + name: 'Projector PlusHD', + icon: '../../../../images/products/15.png', + price: 750, + }, +]; +export default { + getProducts() { + return products; + }, +}; diff --git a/JSDemos/Demos/TreeView/FlatDataStructure/ReactJs/index.html b/JSDemos/Demos/TreeView/FlatDataStructure/ReactJs/index.html new file mode 100644 index 00000000000..4d0ee54d8eb --- /dev/null +++ b/JSDemos/Demos/TreeView/FlatDataStructure/ReactJs/index.html @@ -0,0 +1,44 @@ + + + + DevExtreme Demo + + + + + + + + + + + + + +
+
+
+ + diff --git a/JSDemos/Demos/TreeView/FlatDataStructure/ReactJs/index.js b/JSDemos/Demos/TreeView/FlatDataStructure/ReactJs/index.js new file mode 100644 index 00000000000..b853e0be824 --- /dev/null +++ b/JSDemos/Demos/TreeView/FlatDataStructure/ReactJs/index.js @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App.js'; + +ReactDOM.render(, document.getElementById('app')); diff --git a/JSDemos/Demos/TreeView/FlatDataStructure/ReactJs/styles.css b/JSDemos/Demos/TreeView/FlatDataStructure/ReactJs/styles.css new file mode 100644 index 00000000000..ff9fb16cb1e --- /dev/null +++ b/JSDemos/Demos/TreeView/FlatDataStructure/ReactJs/styles.css @@ -0,0 +1,35 @@ +#simple-treeview, +#product-details { + display: inline-block; +} + +#product-details { + vertical-align: top; + width: 400px; + height: 420px; + margin-left: 20px; +} + +#product-details > img { + border: none; + height: 300px; + width: 400px; +} + +#product-details > .name { + text-align: center; + font-size: 20px; +} + +#product-details > .price { + text-align: center; + font-size: 24px; +} + +.dark #product-details > div { + color: #f0f0f0; +} + +.hidden { + visibility: hidden; +} diff --git a/JSDemos/Demos/TreeView/HierarchicalDataStructure/React/App.js b/JSDemos/Demos/TreeView/HierarchicalDataStructure/React/App.tsx similarity index 50% rename from JSDemos/Demos/TreeView/HierarchicalDataStructure/React/App.js rename to JSDemos/Demos/TreeView/HierarchicalDataStructure/React/App.tsx index c86db4f6313..4b61b64afa9 100644 --- a/JSDemos/Demos/TreeView/HierarchicalDataStructure/React/App.js +++ b/JSDemos/Demos/TreeView/HierarchicalDataStructure/React/App.tsx @@ -1,13 +1,13 @@ import React from 'react'; -import TreeView from 'devextreme-react/tree-view'; -import service from './data.js'; +import TreeView, { TreeViewTypes } from 'devextreme-react/tree-view'; +import service, { ProductType } from './data.ts'; const products = service.getProducts(); const App = () => { const [currentItem, setCurrentItem] = React.useState({ ...products[0] }); - const selectItem = React.useCallback((e) => { + const selectItem = React.useCallback((e: TreeViewTypes.ItemClickEvent & { itemData?: ProductType; }) => { setCurrentItem({ ...e.itemData }); }, [setCurrentItem]); @@ -18,11 +18,11 @@ const App = () => { width={300} onItemClick={selectItem} /> {currentItem.price - &&
- -
{currentItem.text}
-
{`$${currentItem.price}`}
-
+ &&
+ +
{currentItem.text}
+
{`$${currentItem.price}`}
+
}
); diff --git a/JSDemos/Demos/TreeView/HierarchicalDataStructure/React/data.js b/JSDemos/Demos/TreeView/HierarchicalDataStructure/React/data.ts similarity index 97% rename from JSDemos/Demos/TreeView/HierarchicalDataStructure/React/data.js rename to JSDemos/Demos/TreeView/HierarchicalDataStructure/React/data.ts index 529a2d2202c..068c125846d 100644 --- a/JSDemos/Demos/TreeView/HierarchicalDataStructure/React/data.js +++ b/JSDemos/Demos/TreeView/HierarchicalDataStructure/React/data.ts @@ -292,8 +292,17 @@ const products = [{ }], }]; +export interface ProductType { + id: string, + text: string, + items?: ProductType[], + expanded?: boolean, + image?: string, + price?: number, +} + export default { - getProducts() { + getProducts(): ProductType[] { return products; }, }; diff --git a/JSDemos/Demos/TreeView/HierarchicalDataStructure/React/index.html b/JSDemos/Demos/TreeView/HierarchicalDataStructure/React/index.html index fb33a47d3fb..7aef756bcb4 100644 --- a/JSDemos/Demos/TreeView/HierarchicalDataStructure/React/index.html +++ b/JSDemos/Demos/TreeView/HierarchicalDataStructure/React/index.html @@ -12,7 +12,7 @@ diff --git a/JSDemos/Demos/TreeView/HierarchicalDataStructure/React/index.js b/JSDemos/Demos/TreeView/HierarchicalDataStructure/React/index.js deleted file mode 100644 index d9d7442ce76..00000000000 --- a/JSDemos/Demos/TreeView/HierarchicalDataStructure/React/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App.js'; - -ReactDOM.render( - , - document.getElementById('app'), -); diff --git a/JSDemos/Demos/TreeView/HierarchicalDataStructure/React/index.tsx b/JSDemos/Demos/TreeView/HierarchicalDataStructure/React/index.tsx new file mode 100644 index 00000000000..8acbec4b617 --- /dev/null +++ b/JSDemos/Demos/TreeView/HierarchicalDataStructure/React/index.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import App from './App.tsx'; + +ReactDOM.render( + , + document.getElementById('app'), +); diff --git a/JSDemos/Demos/TreeView/HierarchicalDataStructure/ReactJs/App.js b/JSDemos/Demos/TreeView/HierarchicalDataStructure/ReactJs/App.js new file mode 100644 index 00000000000..e85ed032374 --- /dev/null +++ b/JSDemos/Demos/TreeView/HierarchicalDataStructure/ReactJs/App.js @@ -0,0 +1,32 @@ +import React from 'react'; +import TreeView from 'devextreme-react/tree-view'; +import service from './data.js'; + +const products = service.getProducts(); +const App = () => { + const [currentItem, setCurrentItem] = React.useState({ ...products[0] }); + const selectItem = React.useCallback( + (e) => { + setCurrentItem({ ...e.itemData }); + }, + [setCurrentItem], + ); + return ( +
+ + {currentItem.price && ( +
+ +
{currentItem.text}
+
{`$${currentItem.price}`}
+
+ )} +
+ ); +}; +export default App; diff --git a/JSDemos/Demos/TreeView/HierarchicalDataStructure/ReactJs/data.js b/JSDemos/Demos/TreeView/HierarchicalDataStructure/ReactJs/data.js new file mode 100644 index 00000000000..d7dedfbd017 --- /dev/null +++ b/JSDemos/Demos/TreeView/HierarchicalDataStructure/ReactJs/data.js @@ -0,0 +1,384 @@ +const products = [ + { + id: '1', + text: 'Stores', + expanded: true, + items: [ + { + id: '1_1', + text: 'Super Mart of the West', + expanded: true, + items: [ + { + id: '1_1_1', + text: 'Video Players', + items: [ + { + id: '1_1_1_1', + text: 'HD Video Player', + price: 220, + image: '../../../../images/products/1.png', + }, + { + id: '1_1_1_2', + text: 'SuperHD Video Player', + image: '../../../../images/products/2.png', + price: 270, + }, + ], + }, + { + id: '1_1_2', + text: 'Televisions', + expanded: true, + items: [ + { + id: '1_1_2_1', + text: 'SuperLCD 42', + image: '../../../../images/products/7.png', + price: 1200, + }, + { + id: '1_1_2_2', + text: 'SuperLED 42', + image: '../../../../images/products/5.png', + price: 1450, + }, + { + id: '1_1_2_3', + text: 'SuperLED 50', + image: '../../../../images/products/4.png', + price: 1600, + }, + { + id: '1_1_2_4', + text: 'SuperLCD 55', + image: '../../../../images/products/6.png', + price: 1350, + }, + { + id: '1_1_2_5', + text: 'SuperLCD 70', + image: '../../../../images/products/9.png', + price: 4000, + }, + ], + }, + { + id: '1_1_3', + text: 'Monitors', + expanded: true, + items: [ + { + id: '1_1_3_1', + text: '19"', + expanded: true, + items: [ + { + id: '1_1_3_1_1', + text: 'DesktopLCD 19', + image: '../../../../images/products/10.png', + price: 160, + }, + ], + }, + { + id: '1_1_3_2', + text: '21"', + items: [ + { + id: '1_1_3_2_1', + text: 'DesktopLCD 21', + image: '../../../../images/products/12.png', + price: 170, + }, + { + id: '1_1_3_2_2', + text: 'DesktopLED 21', + image: '../../../../images/products/13.png', + price: 175, + }, + ], + }, + ], + }, + { + id: '1_1_4', + text: 'Projectors', + items: [ + { + id: '1_1_4_1', + text: 'Projector Plus', + image: '../../../../images/products/14.png', + price: 550, + }, + { + id: '1_1_4_2', + text: 'Projector PlusHD', + image: '../../../../images/products/15.png', + price: 750, + }, + ], + }, + ], + }, + { + id: '1_2', + text: 'Braeburn', + items: [ + { + id: '1_2_1', + text: 'Video Players', + items: [ + { + id: '1_2_1_1', + text: 'HD Video Player', + image: '../../../../images/products/1.png', + price: 240, + }, + { + id: '1_2_1_2', + text: 'SuperHD Video Player', + image: '../../../../images/products/2.png', + price: 300, + }, + ], + }, + { + id: '1_2_2', + text: 'Televisions', + items: [ + { + id: '1_2_2_1', + text: 'SuperPlasma 50', + image: '../../../../images/products/3.png', + price: 1800, + }, + { + id: '1_2_2_2', + text: 'SuperPlasma 65', + image: '../../../../images/products/8.png', + price: 3500, + }, + ], + }, + { + id: '1_2_3', + text: 'Monitors', + items: [ + { + id: '1_2_3_1', + text: '19"', + items: [ + { + id: '1_2_3_1_1', + text: 'DesktopLCD 19', + image: '../../../../images/products/10.png', + price: 170, + }, + ], + }, + { + id: '1_2_3_2', + text: '21"', + items: [ + { + id: '1_2_3_2_1', + text: 'DesktopLCD 21', + image: '../../../../images/products/12.png', + price: 180, + }, + { + id: '1_2_3_2_2', + text: 'DesktopLED 21', + image: '../../../../images/products/13.png', + price: 190, + }, + ], + }, + ], + }, + ], + }, + { + id: '1_3', + text: 'E-Mart', + items: [ + { + id: '1_3_1', + text: 'Video Players', + items: [ + { + id: '1_3_1_1', + text: 'HD Video Player', + image: '../../../../images/products/1.png', + price: 220, + }, + { + id: '1_3_1_2', + text: 'SuperHD Video Player', + image: '../../../../images/products/2.png', + price: 275, + }, + ], + }, + { + id: '1_3_3', + text: 'Monitors', + items: [ + { + id: '1_3_3_1', + text: '19"', + items: [ + { + id: '1_3_3_1_1', + text: 'DesktopLCD 19', + image: '../../../../images/products/10.png', + price: 165, + }, + ], + }, + { + id: '1_3_3_2', + text: '21"', + items: [ + { + id: '1_3_3_2_1', + text: 'DesktopLCD 21', + image: '../../../../images/products/12.png', + price: 175, + }, + ], + }, + ], + }, + ], + }, + { + id: '1_4', + text: 'Walters', + items: [ + { + id: '1_4_1', + text: 'Video Players', + items: [ + { + id: '1_4_1_1', + text: 'HD Video Player', + image: '../../../../images/products/1.png', + price: 210, + }, + { + id: '1_4_1_2', + text: 'SuperHD Video Player', + image: '../../../../images/products/2.png', + price: 250, + }, + ], + }, + { + id: '1_4_2', + text: 'Televisions', + items: [ + { + id: '1_4_2_1', + text: 'SuperLCD 42', + image: '../../../../images/products/7.png', + price: 1100, + }, + { + id: '1_4_2_2', + text: 'SuperLED 42', + image: '../../../../images/products/5.png', + price: 1400, + }, + { + id: '1_4_2_3', + text: 'SuperLED 50', + image: '../../../../images/products/4.png', + price: 1500, + }, + { + id: '1_4_2_4', + text: 'SuperLCD 55', + image: '../../../../images/products/6.png', + price: 1300, + }, + { + id: '1_4_2_5', + text: 'SuperLCD 70', + image: '../../../../images/products/9.png', + price: 4000, + }, + { + id: '1_4_2_6', + text: 'SuperPlasma 50', + image: '../../../../images/products/3.png', + price: 1700, + }, + ], + }, + { + id: '1_4_3', + text: 'Monitors', + items: [ + { + id: '1_4_3_1', + text: '19"', + items: [ + { + id: '1_4_3_1_1', + text: 'DesktopLCD 19', + image: '../../../../images/products/10.png', + price: 160, + }, + ], + }, + { + id: '1_4_3_2', + text: '21"', + items: [ + { + id: '1_4_3_2_1', + text: 'DesktopLCD 21', + image: '../../../../images/products/12.png', + price: 170, + }, + { + id: '1_4_3_2_2', + text: 'DesktopLED 21', + image: '../../../../images/products/13.png', + price: 180, + }, + ], + }, + ], + }, + { + id: '1_4_4', + text: 'Projectors', + items: [ + { + id: '1_4_4_1', + text: 'Projector Plus', + image: '../../../../images/products/14.png', + price: 550, + }, + { + id: '1_4_4_2', + text: 'Projector PlusHD', + image: '../../../../images/products/15.png', + price: 750, + }, + ], + }, + ], + }, + ], + }, +]; +export default { + getProducts() { + return products; + }, +}; diff --git a/JSDemos/Demos/TreeView/HierarchicalDataStructure/ReactJs/index.html b/JSDemos/Demos/TreeView/HierarchicalDataStructure/ReactJs/index.html new file mode 100644 index 00000000000..4d0ee54d8eb --- /dev/null +++ b/JSDemos/Demos/TreeView/HierarchicalDataStructure/ReactJs/index.html @@ -0,0 +1,44 @@ + + + + DevExtreme Demo + + + + + + + + + + + + + +
+
+
+ + diff --git a/JSDemos/Demos/TreeView/HierarchicalDataStructure/ReactJs/index.js b/JSDemos/Demos/TreeView/HierarchicalDataStructure/ReactJs/index.js new file mode 100644 index 00000000000..b853e0be824 --- /dev/null +++ b/JSDemos/Demos/TreeView/HierarchicalDataStructure/ReactJs/index.js @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App.js'; + +ReactDOM.render(, document.getElementById('app')); diff --git a/JSDemos/Demos/TreeView/HierarchicalDataStructure/ReactJs/styles.css b/JSDemos/Demos/TreeView/HierarchicalDataStructure/ReactJs/styles.css new file mode 100644 index 00000000000..ff9fb16cb1e --- /dev/null +++ b/JSDemos/Demos/TreeView/HierarchicalDataStructure/ReactJs/styles.css @@ -0,0 +1,35 @@ +#simple-treeview, +#product-details { + display: inline-block; +} + +#product-details { + vertical-align: top; + width: 400px; + height: 420px; + margin-left: 20px; +} + +#product-details > img { + border: none; + height: 300px; + width: 400px; +} + +#product-details > .name { + text-align: center; + font-size: 20px; +} + +#product-details > .price { + text-align: center; + font-size: 24px; +} + +.dark #product-details > div { + color: #f0f0f0; +} + +.hidden { + visibility: hidden; +} diff --git a/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/React/App.js b/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/React/App.tsx similarity index 77% rename from JSDemos/Demos/TreeView/ItemSelectionAndCustomization/React/App.js rename to JSDemos/Demos/TreeView/ItemSelectionAndCustomization/React/App.tsx index cd6a6edad34..e8435611de1 100644 --- a/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/React/App.js +++ b/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/React/App.tsx @@ -1,20 +1,20 @@ import React from 'react'; -import TreeView from 'devextreme-react/tree-view'; +import TreeView, { TreeViewTypes } from 'devextreme-react/tree-view'; import List from 'devextreme-react/list'; -import SelectBox from 'devextreme-react/select-box'; -import CheckBox from 'devextreme-react/check-box'; +import SelectBox, { SelectBoxTypes } from 'devextreme-react/select-box'; +import CheckBox, { CheckBoxTypes } from 'devextreme-react/check-box'; -import { employees, showCheckboxesModeLabel, selectionModeLabel } from './data.js'; +import { employees, showCheckboxesModeLabel, selectionModeLabel } from './data.ts'; -const showCheckBoxesModes = ['normal', 'selectAll', 'none']; -const selectionModes = ['multiple', 'single']; +const showCheckBoxesModes: TreeViewTypes.TreeViewCheckBoxMode[] = ['normal', 'selectAll', 'none']; +const selectionModes: TreeViewTypes.SingleOrMultiple[] = ['multiple', 'single']; -const renderTreeViewItem = (item) => `${item.fullName} (${item.position})`; +const renderTreeViewItem = (item: { fullName: any; position: any; }) => `${item.fullName} (${item.position})`; -const renderListItem = (item) => `${item.prefix} ${item.fullName} (${item.position})`; +const renderListItem = (item: { prefix: any; fullName: any; position: any; }) => `${item.prefix} ${item.fullName} (${item.position})`; const App = () => { - const treeViewRef = React.useRef(); + const treeViewRef = React.useRef(null); const [selectedEmployees, setSelectedEmployees] = React.useState([]); const [selectNodesRecursive, setSelectNodesRecursive] = React.useState(true); const [selectByClick, setSelectByClick] = React.useState(false); @@ -23,14 +23,6 @@ const App = () => { const [isSelectionModeDisabled, setIsSelectionModeDisabled] = React.useState(false); const [isRecursiveDisabled, setIsRecursiveDisabled] = React.useState(false); - const treeViewSelectionChanged = React.useCallback((e) => { - syncSelection(e.component); - }, [syncSelection]); - - const treeViewContentReady = React.useCallback((e) => { - syncSelection(e.component); - }, [syncSelection]); - const syncSelection = React.useCallback((treeView) => { const syncSelectedEmployees = treeView.getSelectedNodes() .map((node) => node.itemData); @@ -38,7 +30,15 @@ const App = () => { setSelectedEmployees(syncSelectedEmployees); }, [setSelectedEmployees]); - const showCheckBoxesModeValueChanged = React.useCallback((e) => { + const treeViewSelectionChanged = React.useCallback((e: TreeViewTypes.SelectionChangedEvent) => { + syncSelection(e.component); + }, [syncSelection]); + + const treeViewContentReady = React.useCallback((e: TreeViewTypes.ContentReadyEvent) => { + syncSelection(e.component); + }, [syncSelection]); + + const showCheckBoxesModeValueChanged = React.useCallback((e: SelectBoxTypes.ValueChangedEvent) => { const value = e.value; setShowCheckBoxesMode(value); @@ -49,7 +49,7 @@ const App = () => { setIsSelectionModeDisabled(value === 'selectAll'); }, [setShowCheckBoxesMode, setSelectionMode, setIsRecursiveDisabled, setIsSelectionModeDisabled]); - const selectionModeValueChanged = React.useCallback((e) => { + const selectionModeValueChanged = React.useCallback((e: SelectBoxTypes.ValueChangedEvent) => { const value = e.value; setSelectionMode(value); @@ -60,11 +60,11 @@ const App = () => { setIsRecursiveDisabled(value === 'single'); }, [setSelectionMode, setSelectNodesRecursive, setIsRecursiveDisabled]); - const selectNodesRecursiveValueChanged = React.useCallback((e) => { + const selectNodesRecursiveValueChanged = React.useCallback((e: CheckBoxTypes.ValueChangedEvent) => { setSelectNodesRecursive(e.value); }, [setSelectNodesRecursive]); - const selectByClickValueChanged = React.useCallback((e) => { + const selectByClickValueChanged = React.useCallback((e: CheckBoxTypes.ValueChangedEvent) => { setSelectByClick(e.value); }, [setSelectByClick]); diff --git a/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/React/data.js b/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/React/data.ts similarity index 100% rename from JSDemos/Demos/TreeView/ItemSelectionAndCustomization/React/data.js rename to JSDemos/Demos/TreeView/ItemSelectionAndCustomization/React/data.ts diff --git a/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/React/index.html b/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/React/index.html index fb33a47d3fb..7aef756bcb4 100644 --- a/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/React/index.html +++ b/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/React/index.html @@ -12,7 +12,7 @@ diff --git a/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/React/index.js b/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/React/index.js deleted file mode 100644 index d9d7442ce76..00000000000 --- a/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/React/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App.js'; - -ReactDOM.render( - , - document.getElementById('app'), -); diff --git a/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/React/index.tsx b/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/React/index.tsx new file mode 100644 index 00000000000..8acbec4b617 --- /dev/null +++ b/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/React/index.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import App from './App.tsx'; + +ReactDOM.render( + , + document.getElementById('app'), +); diff --git a/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/ReactJs/App.js b/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/ReactJs/App.js new file mode 100644 index 00000000000..9d95ce43249 --- /dev/null +++ b/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/ReactJs/App.js @@ -0,0 +1,158 @@ +import React from 'react'; +import TreeView from 'devextreme-react/tree-view'; +import List from 'devextreme-react/list'; +import SelectBox from 'devextreme-react/select-box'; +import CheckBox from 'devextreme-react/check-box'; +import { employees, showCheckboxesModeLabel, selectionModeLabel } from './data.js'; + +const showCheckBoxesModes = ['normal', 'selectAll', 'none']; +const selectionModes = ['multiple', 'single']; +const renderTreeViewItem = (item) => `${item.fullName} (${item.position})`; +const renderListItem = (item) => `${item.prefix} ${item.fullName} (${item.position})`; +const App = () => { + const treeViewRef = React.useRef(null); + const [selectedEmployees, setSelectedEmployees] = React.useState([]); + const [selectNodesRecursive, setSelectNodesRecursive] = React.useState(true); + const [selectByClick, setSelectByClick] = React.useState(false); + const [showCheckBoxesMode, setShowCheckBoxesMode] = React.useState(showCheckBoxesModes[0]); + const [selectionMode, setSelectionMode] = React.useState(selectionModes[0]); + const [isSelectionModeDisabled, setIsSelectionModeDisabled] = React.useState(false); + const [isRecursiveDisabled, setIsRecursiveDisabled] = React.useState(false); + const syncSelection = React.useCallback( + (treeView) => { + const syncSelectedEmployees = treeView.getSelectedNodes().map((node) => node.itemData); + setSelectedEmployees(syncSelectedEmployees); + }, + [setSelectedEmployees], + ); + const treeViewSelectionChanged = React.useCallback( + (e) => { + syncSelection(e.component); + }, + [syncSelection], + ); + const treeViewContentReady = React.useCallback( + (e) => { + syncSelection(e.component); + }, + [syncSelection], + ); + const showCheckBoxesModeValueChanged = React.useCallback( + (e) => { + const value = e.value; + setShowCheckBoxesMode(value); + if (value === 'selectAll') { + setSelectionMode('multiple'); + setIsRecursiveDisabled(false); + } + setIsSelectionModeDisabled(value === 'selectAll'); + }, + [setShowCheckBoxesMode, setSelectionMode, setIsRecursiveDisabled, setIsSelectionModeDisabled], + ); + const selectionModeValueChanged = React.useCallback( + (e) => { + const value = e.value; + setSelectionMode(value); + if (value === 'single') { + setSelectNodesRecursive(false); + treeViewRef.current.instance.unselectAll(); + } + setIsRecursiveDisabled(value === 'single'); + }, + [setSelectionMode, setSelectNodesRecursive, setIsRecursiveDisabled], + ); + const selectNodesRecursiveValueChanged = React.useCallback( + (e) => { + setSelectNodesRecursive(e.value); + }, + [setSelectNodesRecursive], + ); + const selectByClickValueChanged = React.useCallback( + (e) => { + setSelectByClick(e.value); + }, + [setSelectByClick], + ); + return ( +
+
+

Employees

+ {' '} +
+ Selected employees + +
+
+
+
Options
+
+
+ Show Check Boxes Mode: +
+ +
+
+
+ Selection Mode: +
+ +
+
+
+
 
+
+ +
+
+
+
 
+
+ +
+
+
+
+
+ ); +}; +export default App; diff --git a/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/ReactJs/data.js b/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/ReactJs/data.js new file mode 100644 index 00000000000..8af188e7a5b --- /dev/null +++ b/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/ReactJs/data.js @@ -0,0 +1,89 @@ +export const employees = [ + { + id: 1, + fullName: 'John Heart', + prefix: 'Dr.', + position: 'CEO', + expanded: true, + items: [ + { + id: 2, + fullName: 'Samantha Bright', + prefix: 'Dr.', + position: 'COO', + expanded: true, + items: [ + { + id: 3, + fullName: 'Kevin Carter', + prefix: 'Mr.', + position: 'Shipping Manager', + }, + { + id: 14, + fullName: 'Victor Norris', + prefix: 'Mr.', + selected: true, + position: 'Shipping Assistant', + }, + ], + }, + { + id: 4, + fullName: 'Brett Wade', + prefix: 'Mr.', + position: 'IT Manager', + expanded: true, + items: [ + { + id: 5, + fullName: 'Amelia Harper', + prefix: 'Mrs.', + position: 'Network Admin', + }, + { + id: 6, + fullName: 'Wally Hobbs', + prefix: 'Mr.', + position: 'Programmer', + }, + { + id: 7, + fullName: 'Brad Jameson', + prefix: 'Mr.', + position: 'Programmer', + }, + { + id: 8, + fullName: 'Violet Bailey', + prefix: 'Ms.', + position: 'Jr Graphic Designer', + }, + ], + }, + { + id: 9, + fullName: 'Barb Banks', + prefix: 'Mrs.', + position: 'Support Manager', + expanded: true, + items: [ + { + id: 10, + fullName: 'Kelly Rodriguez', + prefix: 'Ms.', + position: 'Support Assistant', + }, + { + id: 11, + fullName: 'James Anderson', + prefix: 'Mr.', + position: 'Support Assistant', + }, + ], + }, + ], + }, +]; +export const selectionModeLabel = { 'aria-label': 'Selection Mode' }; +export const showCheckboxesModeLabel = { 'aria-label': 'Show Checkboxes Mode' }; diff --git a/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/ReactJs/index.html b/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/ReactJs/index.html new file mode 100644 index 00000000000..4d0ee54d8eb --- /dev/null +++ b/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/ReactJs/index.html @@ -0,0 +1,44 @@ + + + + DevExtreme Demo + + + + + + + + + + + + + +
+
+
+ + diff --git a/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/ReactJs/index.js b/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/ReactJs/index.js new file mode 100644 index 00000000000..b853e0be824 --- /dev/null +++ b/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/ReactJs/index.js @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App.js'; + +ReactDOM.render(, document.getElementById('app')); diff --git a/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/ReactJs/styles.css b/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/ReactJs/styles.css new file mode 100644 index 00000000000..7df382f0893 --- /dev/null +++ b/JSDemos/Demos/TreeView/ItemSelectionAndCustomization/ReactJs/styles.css @@ -0,0 +1,67 @@ +.form > h4 { + margin-bottom: 20px; +} + +.form > div, +#treeview { + display: inline-block; + vertical-align: top; +} + +#selected-employees { + margin-top: 20px; +} + +.selected-container .dx-list-item-content { + padding-left: 0; +} + +.selected-container { + padding: 20px; + margin-left: 20px; + background-color: rgba(191, 191, 191, 0.15); + font-size: 115%; + font-weight: bold; +} + +.options { + padding: 20px; + background-color: rgba(191, 191, 191, 0.15); + margin-top: 20px; + box-sizing: border-box; +} + +.caption { + font-size: 18px; + font-weight: 500; +} + +.option { + width: 24%; + margin-top: 10px; + margin-right: 9px; + box-sizing: border-box; + display: flex; + flex-direction: column; + justify-content: center; +} + +.options-container { + display: flex; + justify-content: space-between; + align-items: stretch; +} + +.editor-container { + height: 100%; + display: flex; + align-items: center; +} + +.editor-container > * { + width: 100%; +} + +.option:last-of-type { + margin-right: 0; +} diff --git a/JSDemos/Demos/TreeView/LoadDataOnDemand/React/App.tsx b/JSDemos/Demos/TreeView/LoadDataOnDemand/React/App.tsx new file mode 100644 index 00000000000..fef4dd98998 --- /dev/null +++ b/JSDemos/Demos/TreeView/LoadDataOnDemand/React/App.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import TreeView, { TreeViewTypes } from 'devextreme-react/tree-view'; +import 'whatwg-fetch'; + +const createChildren = (parent: TreeViewTypes.Node) => { + const parentId = parent ? parent.itemData.id : ''; + + return fetch(`https://js.devexpress.com/Demos/Mvc/api/TreeViewData?parentId=${parentId}`) + .then((response) => response.json()) + .catch(() => { throw new Error('Data Loading Error'); }); +}; + +const App = () => ( + + + +); + +export default App; diff --git a/JSDemos/Demos/TreeView/LoadDataOnDemand/React/index.html b/JSDemos/Demos/TreeView/LoadDataOnDemand/React/index.html index 537a755f3bb..fc2ebd0a819 100644 --- a/JSDemos/Demos/TreeView/LoadDataOnDemand/React/index.html +++ b/JSDemos/Demos/TreeView/LoadDataOnDemand/React/index.html @@ -11,7 +11,7 @@ diff --git a/JSDemos/Demos/TreeView/LoadDataOnDemand/React/index.js b/JSDemos/Demos/TreeView/LoadDataOnDemand/React/index.js deleted file mode 100644 index d9d7442ce76..00000000000 --- a/JSDemos/Demos/TreeView/LoadDataOnDemand/React/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App.js'; - -ReactDOM.render( - , - document.getElementById('app'), -); diff --git a/JSDemos/Demos/TreeView/LoadDataOnDemand/React/index.tsx b/JSDemos/Demos/TreeView/LoadDataOnDemand/React/index.tsx new file mode 100644 index 00000000000..8acbec4b617 --- /dev/null +++ b/JSDemos/Demos/TreeView/LoadDataOnDemand/React/index.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import App from './App.tsx'; + +ReactDOM.render( + , + document.getElementById('app'), +); diff --git a/JSDemos/Demos/TreeView/LoadDataOnDemand/React/App.js b/JSDemos/Demos/TreeView/LoadDataOnDemand/ReactJs/App.js similarity index 89% rename from JSDemos/Demos/TreeView/LoadDataOnDemand/React/App.js rename to JSDemos/Demos/TreeView/LoadDataOnDemand/ReactJs/App.js index 0f08d9d42af..098ec4f6d9e 100644 --- a/JSDemos/Demos/TreeView/LoadDataOnDemand/React/App.js +++ b/JSDemos/Demos/TreeView/LoadDataOnDemand/ReactJs/App.js @@ -4,12 +4,12 @@ import 'whatwg-fetch'; const createChildren = (parent) => { const parentId = parent ? parent.itemData.id : ''; - return fetch(`https://js.devexpress.com/Demos/Mvc/api/TreeViewData?parentId=${parentId}`) .then((response) => response.json()) - .catch(() => { throw new Error('Data Loading Error'); }); + .catch(() => { + throw new Error('Data Loading Error'); + }); }; - const App = () => ( ( /> ); - export default App; diff --git a/JSDemos/Demos/TreeView/LoadDataOnDemand/ReactJs/index.html b/JSDemos/Demos/TreeView/LoadDataOnDemand/ReactJs/index.html new file mode 100644 index 00000000000..54983a89e52 --- /dev/null +++ b/JSDemos/Demos/TreeView/LoadDataOnDemand/ReactJs/index.html @@ -0,0 +1,39 @@ + + + + DevExtreme Demo + + + + + + + + + + + + +
+
+
+ + diff --git a/JSDemos/Demos/TreeView/LoadDataOnDemand/ReactJs/index.js b/JSDemos/Demos/TreeView/LoadDataOnDemand/ReactJs/index.js new file mode 100644 index 00000000000..b853e0be824 --- /dev/null +++ b/JSDemos/Demos/TreeView/LoadDataOnDemand/ReactJs/index.js @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App.js'; + +ReactDOM.render(, document.getElementById('app')); diff --git a/JSDemos/Demos/TreeView/TreeViewWithSearchBar/React/App.tsx b/JSDemos/Demos/TreeView/TreeViewWithSearchBar/React/App.tsx new file mode 100644 index 00000000000..d40a0a4ef5e --- /dev/null +++ b/JSDemos/Demos/TreeView/TreeViewWithSearchBar/React/App.tsx @@ -0,0 +1,43 @@ +import React from 'react'; + +import TreeView from 'devextreme-react/tree-view'; +import SelectBox, { SelectBoxTypes } from 'devextreme-react/select-box'; +import { SearchMode } from 'devextreme/common'; + +import { products, searchModeLabel } from './data.ts'; + +const options: SearchMode[] = ['contains', 'startswith', 'equals']; + +const App = () => { + const [value, setValue] = React.useState('contains'); + + const valueChanged = React.useCallback((e: SelectBoxTypes.ValueChangedEvent) => { + setValue(e.value); + }, [setValue]); + + return ( + + +
+
Options
+
+ Search mode + +
+
+
+ ); +}; + +export default App; diff --git a/JSDemos/Demos/TreeView/TreeViewWithSearchBar/React/data.js b/JSDemos/Demos/TreeView/TreeViewWithSearchBar/React/data.ts similarity index 100% rename from JSDemos/Demos/TreeView/TreeViewWithSearchBar/React/data.js rename to JSDemos/Demos/TreeView/TreeViewWithSearchBar/React/data.ts diff --git a/JSDemos/Demos/TreeView/TreeViewWithSearchBar/React/index.html b/JSDemos/Demos/TreeView/TreeViewWithSearchBar/React/index.html index fb33a47d3fb..7aef756bcb4 100644 --- a/JSDemos/Demos/TreeView/TreeViewWithSearchBar/React/index.html +++ b/JSDemos/Demos/TreeView/TreeViewWithSearchBar/React/index.html @@ -12,7 +12,7 @@ diff --git a/JSDemos/Demos/TreeView/TreeViewWithSearchBar/React/index.js b/JSDemos/Demos/TreeView/TreeViewWithSearchBar/React/index.js deleted file mode 100644 index d9d7442ce76..00000000000 --- a/JSDemos/Demos/TreeView/TreeViewWithSearchBar/React/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App.js'; - -ReactDOM.render( - , - document.getElementById('app'), -); diff --git a/JSDemos/Demos/TreeView/TreeViewWithSearchBar/React/index.tsx b/JSDemos/Demos/TreeView/TreeViewWithSearchBar/React/index.tsx new file mode 100644 index 00000000000..8acbec4b617 --- /dev/null +++ b/JSDemos/Demos/TreeView/TreeViewWithSearchBar/React/index.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import App from './App.tsx'; + +ReactDOM.render( + , + document.getElementById('app'), +); diff --git a/JSDemos/Demos/TreeView/TreeViewWithSearchBar/React/App.js b/JSDemos/Demos/TreeView/TreeViewWithSearchBar/ReactJs/App.js similarity index 89% rename from JSDemos/Demos/TreeView/TreeViewWithSearchBar/React/App.js rename to JSDemos/Demos/TreeView/TreeViewWithSearchBar/ReactJs/App.js index 2e100452c52..c0d10752f4c 100644 --- a/JSDemos/Demos/TreeView/TreeViewWithSearchBar/React/App.js +++ b/JSDemos/Demos/TreeView/TreeViewWithSearchBar/ReactJs/App.js @@ -1,19 +1,17 @@ import React from 'react'; - import TreeView from 'devextreme-react/tree-view'; import SelectBox from 'devextreme-react/select-box'; - import { products, searchModeLabel } from './data.js'; const options = ['contains', 'startswith', 'equals']; - const App = () => { const [value, setValue] = React.useState('contains'); - - const valueChanged = React.useCallback((e) => { - setValue(e.value); - }, [setValue]); - + const valueChanged = React.useCallback( + (e) => { + setValue(e.value); + }, + [setValue], + ); return ( { ); }; - export default App; diff --git a/JSDemos/Demos/TreeView/TreeViewWithSearchBar/ReactJs/data.js b/JSDemos/Demos/TreeView/TreeViewWithSearchBar/ReactJs/data.js new file mode 100644 index 00000000000..6abad954662 --- /dev/null +++ b/JSDemos/Demos/TreeView/TreeViewWithSearchBar/ReactJs/data.js @@ -0,0 +1,341 @@ +export const products = [ + { + id: '1', + text: 'Stores', + expanded: true, + items: [ + { + id: '1_1', + text: 'Super Mart of the West', + expanded: true, + items: [ + { + id: '1_1_1', + text: 'Video Players', + items: [ + { + id: '1_1_1_1', + text: 'HD Video Player', + price: 220, + }, + { + id: '1_1_1_2', + text: 'SuperHD Video Player', + price: 270, + }, + ], + }, + { + id: '1_1_2', + text: 'Televisions', + items: [ + { + id: '1_1_2_1', + text: 'SuperLCD 42', + price: 1200, + }, + { + id: '1_1_2_2', + text: 'SuperLED 42', + price: 1450, + }, + { + id: '1_1_2_3', + text: 'SuperLED 50', + price: 1600, + }, + { + id: '1_1_2_4', + text: 'SuperLCD 55', + price: 1350, + }, + { + id: '1_1_2_5', + text: 'SuperLCD 70', + price: 4000, + }, + ], + }, + { + id: '1_1_3', + text: 'Monitors', + items: [ + { + id: '1_1_3_1', + text: '19"', + items: [ + { + id: '1_1_3_1_1', + text: 'DesktopLCD 19', + price: 160, + }, + ], + }, + { + id: '1_1_3_2', + text: '21"', + items: [ + { + id: '1_1_3_2_1', + text: 'DesktopLCD 21', + price: 170, + }, + { + id: '1_1_3_2_2', + text: 'DesktopLED 21', + price: 175, + }, + ], + }, + ], + }, + { + id: '1_1_4', + text: 'Projectors', + items: [ + { + id: '1_1_4_1', + text: 'Projector Plus', + price: 550, + }, + { + id: '1_1_4_2', + text: 'Projector PlusHD', + price: 750, + }, + ], + }, + ], + }, + { + id: '1_2', + text: 'Braeburn', + items: [ + { + id: '1_2_1', + text: 'Video Players', + items: [ + { + id: '1_2_1_1', + text: 'HD Video Player', + price: 240, + }, + { + id: '1_2_1_2', + text: 'SuperHD Video Player', + price: 300, + }, + ], + }, + { + id: '1_2_2', + text: 'Televisions', + items: [ + { + id: '1_2_2_1', + text: 'SuperPlasma 50', + price: 1800, + }, + { + id: '1_2_2_2', + text: 'SuperPlasma 65', + price: 3500, + }, + ], + }, + { + id: '1_2_3', + text: 'Monitors', + items: [ + { + id: '1_2_3_1', + text: '19"', + items: [ + { + id: '1_2_3_1_1', + text: 'DesktopLCD 19', + price: 170, + }, + ], + }, + { + id: '1_2_3_2', + text: '21"', + items: [ + { + id: '1_2_3_2_1', + text: 'DesktopLCD 21', + price: 180, + }, + { + id: '1_2_3_2_2', + text: 'DesktopLED 21', + price: 190, + }, + ], + }, + ], + }, + ], + }, + { + id: '1_3', + text: 'E-Mart', + items: [ + { + id: '1_3_1', + text: 'Video Players', + items: [ + { + id: '1_3_1_1', + text: 'HD Video Player', + price: 220, + }, + { + id: '1_3_1_2', + text: 'SuperHD Video Player', + price: 275, + }, + ], + }, + { + id: '1_3_3', + text: 'Monitors', + items: [ + { + id: '1_3_3_1', + text: '19"', + items: [ + { + id: '1_3_3_1_1', + text: 'DesktopLCD 19', + price: 165, + }, + ], + }, + { + id: '1_3_3_2', + text: '21"', + items: [ + { + id: '1_3_3_2_1', + text: 'DesktopLCD 21', + price: 175, + }, + ], + }, + ], + }, + ], + }, + { + id: '1_4', + text: 'Walters', + items: [ + { + id: '1_4_1', + text: 'Video Players', + items: [ + { + id: '1_4_1_1', + text: 'HD Video Player', + price: 210, + }, + { + id: '1_4_1_2', + text: 'SuperHD Video Player', + price: 250, + }, + ], + }, + { + id: '1_4_2', + text: 'Televisions', + items: [ + { + id: '1_4_2_1', + text: 'SuperLCD 42', + price: 1100, + }, + { + id: '1_4_2_2', + text: 'SuperLED 42', + price: 1400, + }, + { + id: '1_4_2_3', + text: 'SuperLED 50', + price: 1500, + }, + { + id: '1_4_2_4', + text: 'SuperLCD 55', + price: 1300, + }, + { + id: '1_4_2_5', + text: 'SuperLCD 70', + price: 4000, + }, + { + id: '1_4_2_6', + text: 'SuperPlasma 50', + price: 1700, + }, + ], + }, + { + id: '1_4_3', + text: 'Monitors', + items: [ + { + id: '1_4_3_1', + text: '19"', + items: [ + { + id: '1_4_3_1_1', + text: 'DesktopLCD 19', + price: 160, + }, + ], + }, + { + id: '1_4_3_2', + text: '21"', + items: [ + { + id: '1_4_3_2_1', + text: 'DesktopLCD 21', + price: 170, + }, + { + id: '1_4_3_2_2', + text: 'DesktopLED 21', + price: 180, + }, + ], + }, + ], + }, + { + id: '1_4_4', + text: 'Projectors', + items: [ + { + id: '1_4_4_1', + text: 'Projector Plus', + price: 550, + }, + { + id: '1_4_4_2', + text: 'Projector PlusHD', + price: 750, + }, + ], + }, + ], + }, + ], + }, +]; +export const searchModeLabel = { 'aria-label': 'Search Mode' }; diff --git a/JSDemos/Demos/TreeView/TreeViewWithSearchBar/ReactJs/index.html b/JSDemos/Demos/TreeView/TreeViewWithSearchBar/ReactJs/index.html new file mode 100644 index 00000000000..4d0ee54d8eb --- /dev/null +++ b/JSDemos/Demos/TreeView/TreeViewWithSearchBar/ReactJs/index.html @@ -0,0 +1,44 @@ + + + + DevExtreme Demo + + + + + + + + + + + + + +
+
+
+ + diff --git a/JSDemos/Demos/TreeView/TreeViewWithSearchBar/ReactJs/index.js b/JSDemos/Demos/TreeView/TreeViewWithSearchBar/ReactJs/index.js new file mode 100644 index 00000000000..b853e0be824 --- /dev/null +++ b/JSDemos/Demos/TreeView/TreeViewWithSearchBar/ReactJs/index.js @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App.js'; + +ReactDOM.render(, document.getElementById('app')); diff --git a/JSDemos/Demos/TreeView/TreeViewWithSearchBar/ReactJs/styles.css b/JSDemos/Demos/TreeView/TreeViewWithSearchBar/ReactJs/styles.css new file mode 100644 index 00000000000..fbe6b2b093d --- /dev/null +++ b/JSDemos/Demos/TreeView/TreeViewWithSearchBar/ReactJs/styles.css @@ -0,0 +1,30 @@ +#treeview { + height: 400px; +} + +.options { + padding: 20px; + position: absolute; + bottom: 0; + right: 0; + width: 260px; + top: 0; + background-color: #f5f5f5; +} + +.caption { + font-size: 18px; + font-weight: 500; +} + +.option { + margin-top: 10px; +} + +.option > .dx-selectbox { + display: inline-block; + vertical-align: middle; + max-width: 350px; + width: 100%; + margin-top: 5px; +} diff --git a/JSDemos/Demos/TreeView/VirtualMode/React/App.js b/JSDemos/Demos/TreeView/VirtualMode/React/App.tsx similarity index 100% rename from JSDemos/Demos/TreeView/VirtualMode/React/App.js rename to JSDemos/Demos/TreeView/VirtualMode/React/App.tsx diff --git a/JSDemos/Demos/TreeView/VirtualMode/React/index.html b/JSDemos/Demos/TreeView/VirtualMode/React/index.html index 537a755f3bb..fc2ebd0a819 100644 --- a/JSDemos/Demos/TreeView/VirtualMode/React/index.html +++ b/JSDemos/Demos/TreeView/VirtualMode/React/index.html @@ -11,7 +11,7 @@ diff --git a/JSDemos/Demos/TreeView/VirtualMode/React/index.js b/JSDemos/Demos/TreeView/VirtualMode/React/index.js deleted file mode 100644 index d9d7442ce76..00000000000 --- a/JSDemos/Demos/TreeView/VirtualMode/React/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App.js'; - -ReactDOM.render( - , - document.getElementById('app'), -); diff --git a/JSDemos/Demos/TreeView/VirtualMode/React/index.tsx b/JSDemos/Demos/TreeView/VirtualMode/React/index.tsx new file mode 100644 index 00000000000..8acbec4b617 --- /dev/null +++ b/JSDemos/Demos/TreeView/VirtualMode/React/index.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import App from './App.tsx'; + +ReactDOM.render( + , + document.getElementById('app'), +); diff --git a/JSDemos/Demos/TreeView/VirtualMode/ReactJs/App.js b/JSDemos/Demos/TreeView/VirtualMode/ReactJs/App.js new file mode 100644 index 00000000000..adba0ba4a78 --- /dev/null +++ b/JSDemos/Demos/TreeView/VirtualMode/ReactJs/App.js @@ -0,0 +1,25 @@ +import React from 'react'; +import TreeView from 'devextreme-react/tree-view'; +import DataSource from 'devextreme/data/data_source'; +import ODataStore from 'devextreme/data/odata/store'; + +const dataSource = new DataSource({ + store: new ODataStore({ + version: 2, + url: 'https://js.devexpress.com/Demos/WidgetsGallery/odata/HierarchicalItems', + }), +}); +const App = () => ( + + + +); +export default App; diff --git a/JSDemos/Demos/TreeView/VirtualMode/ReactJs/index.html b/JSDemos/Demos/TreeView/VirtualMode/ReactJs/index.html new file mode 100644 index 00000000000..54983a89e52 --- /dev/null +++ b/JSDemos/Demos/TreeView/VirtualMode/ReactJs/index.html @@ -0,0 +1,39 @@ + + + + DevExtreme Demo + + + + + + + + + + + + +
+
+
+ + diff --git a/JSDemos/Demos/TreeView/VirtualMode/ReactJs/index.js b/JSDemos/Demos/TreeView/VirtualMode/ReactJs/index.js new file mode 100644 index 00000000000..b853e0be824 --- /dev/null +++ b/JSDemos/Demos/TreeView/VirtualMode/ReactJs/index.js @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App.js'; + +ReactDOM.render(, document.getElementById('app')); diff --git a/package-lock.json b/package-lock.json index fad9521de54..654869ed2f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -74,6 +74,7 @@ "@types/eslint": "8.21.2", "@types/fs-extra": "11.0.2", "@types/react": "17.0.2", + "@types/react-dom": "17.0.2", "@types/yargs": "17.0.24", "@typescript-eslint/eslint-plugin": "4.33.0", "@typescript-eslint/parser": "4.33.0", @@ -4905,6 +4906,15 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/react-dom": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-Icd9KEgdnFfJs39KyRyr0jQ7EKhq8U6CcHRMGAS45fp5qgUvxL3ujUCfWFttUK2UErqZNj97t9gsVPNAqcwoCg==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/semver": { "version": "7.5.3", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.3.tgz", @@ -33239,6 +33249,15 @@ "csstype": "^3.0.2" } }, + "@types/react-dom": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-Icd9KEgdnFfJs39KyRyr0jQ7EKhq8U6CcHRMGAS45fp5qgUvxL3ujUCfWFttUK2UErqZNj97t9gsVPNAqcwoCg==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/semver": { "version": "7.5.3", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.3.tgz", diff --git a/package.json b/package.json index c6d242d1116..127455ee4ce 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "@testcafe-community/axe": "3.5.0", "@types/fs-extra": "11.0.2", "@types/react": "17.0.2", + "@types/react-dom": "17.0.2", "@types/yargs": "17.0.24", "@types/eslint": "8.21.2", "@typescript-eslint/eslint-plugin": "4.33.0", diff --git a/tsconfig.json b/tsconfig.json index 893da6e77b0..087f647b64d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,8 +8,7 @@ "jsx": "react", "moduleResolution": "node", }, - "include": [ "utils/**/*.ts" ] -} +} \ No newline at end of file