-
+
{`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}
+
+
+
+
+
+ );
+}
+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 (
+
+
+
+ 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 (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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 (
+
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+
+
+
+
+
+ );
+}
+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 (
+
+ );
+};
+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 (
+
+ );
+};
+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.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