diff --git a/apps/demos/Demos/CardView/FieldTemplate/React/Progress.tsx b/apps/demos/Demos/CardView/FieldTemplate/React/Progress.tsx index 8e42f9c1a94d..cb65d2f9ae93 100644 --- a/apps/demos/Demos/CardView/FieldTemplate/React/Progress.tsx +++ b/apps/demos/Demos/CardView/FieldTemplate/React/Progress.tsx @@ -5,12 +5,15 @@ interface ProgressProps { value: number; } +const progressElementAttributes = { 'aria-label': 'Progress Bar' }; +const formatPercent = (_: unknown, value: number) => `${value}%`; + const Progress = ({ value }: ProgressProps) => (
`${value}%`} + elementAttr={progressElementAttributes} + statusFormat={formatPercent} />
); diff --git a/apps/demos/Demos/CardView/FieldTemplate/ReactJs/Progress.js b/apps/demos/Demos/CardView/FieldTemplate/ReactJs/Progress.js index a40b505fda87..efdc15cbd741 100644 --- a/apps/demos/Demos/CardView/FieldTemplate/ReactJs/Progress.js +++ b/apps/demos/Demos/CardView/FieldTemplate/ReactJs/Progress.js @@ -1,12 +1,14 @@ import React from 'react'; import { ProgressBar } from 'devextreme-react/progress-bar'; +const progressElementAttributes = { 'aria-label': 'Progress Bar' }; +const formatPercent = (_, value) => `${value}%`; const Progress = ({ value }) => (
`${value}%`} + elementAttr={progressElementAttributes} + statusFormat={formatPercent} />
); diff --git a/apps/demos/Demos/CardView/FieldTemplate/ReactJs/index.html b/apps/demos/Demos/CardView/FieldTemplate/ReactJs/index.html index b6ad2f9b1595..7b47950bbaff 100644 --- a/apps/demos/Demos/CardView/FieldTemplate/ReactJs/index.html +++ b/apps/demos/Demos/CardView/FieldTemplate/ReactJs/index.html @@ -12,7 +12,6 @@
- diff --git a/apps/demos/Demos/DataGrid/AIAssistant/React/App.tsx b/apps/demos/Demos/DataGrid/AIAssistant/React/App.tsx index e946c12b7744..9eb3af60410e 100644 --- a/apps/demos/Demos/DataGrid/AIAssistant/React/App.tsx +++ b/apps/demos/Demos/DataGrid/AIAssistant/React/App.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useRef } from 'react'; +import React, { useCallback, useMemo, useRef } from 'react'; import DataGrid, { Column, @@ -76,7 +76,7 @@ export default function App() { }]); }, []); - const chatOptions: ChatTypes.Properties = { + const chatOptions = useMemo(() => ({ onInitialized: onChatInitialized, user: { id: 'user', @@ -85,7 +85,7 @@ export default function App() { ...suggestions, onItemClick: onSuggestionItemClick, }, - }; + }), [onChatInitialized, onSuggestionItemClick]); return ( ({ + onInitialized: onChatInitialized, + user: { + id: 'user', + }, + suggestions: { + ...suggestions, + onItemClick: onSuggestionItemClick, + }, + }), + [onChatInitialized, onSuggestionItemClick], + ); return ( ( + + ), [showInfo]); + + const renderLicenseInfo = useCallback(() => ( + + ), [currentVehicle]); + return ( <> - - } + cellRender={renderTrademark} /> - - } + contentRender={renderLicenseInfo} > onShowInfo(vehicle), [onShowInfo, vehicle]); + return (
@@ -23,7 +25,7 @@ export default function Trademark({ vehicle, onShowInfo }: TrademarkProps) { src={`../../../../images/vehicles/image_${ID}.png`} alt={`${TrademarkName} ${Name}`} tabIndex={0} - onClick={() => onShowInfo(vehicle)} + onClick={onClick} role="button" onKeyDown={onKeyDown} aria-haspopup="dialog" diff --git a/apps/demos/Demos/DataGrid/AIColumns/ReactJs/App.js b/apps/demos/Demos/DataGrid/AIColumns/ReactJs/App.js index 44edf7fbb179..b974f5a2eca5 100644 --- a/apps/demos/Demos/DataGrid/AIColumns/ReactJs/App.js +++ b/apps/demos/Demos/DataGrid/AIColumns/ReactJs/App.js @@ -25,6 +25,19 @@ export default function App() { const hideInfo = useCallback(() => { setCurrentVehicle(null); }, []); + const renderTrademark = useCallback( + (cellData) => ( + + ), + [showInfo], + ); + const renderLicenseInfo = useCallback( + () => , + [currentVehicle], + ); return ( <> ( - - )} + cellRender={renderTrademark} /> } + contentRender={renderLicenseInfo} > onShowInfo(vehicle), [onShowInfo, vehicle]); return (
@@ -18,7 +19,7 @@ export default function Trademark({ vehicle, onShowInfo }) { src={`../../../../images/vehicles/image_${ID}.png`} alt={`${TrademarkName} ${Name}`} tabIndex={0} - onClick={() => onShowInfo(vehicle)} + onClick={onClick} role="button" onKeyDown={onKeyDown} aria-haspopup="dialog" diff --git a/apps/demos/Demos/DataGrid/CustomEditors/React/App.tsx b/apps/demos/Demos/DataGrid/CustomEditors/React/App.tsx index 531d01b545ba..1438ccfbcb7d 100644 --- a/apps/demos/Demos/DataGrid/CustomEditors/React/App.tsx +++ b/apps/demos/Demos/DataGrid/CustomEditors/React/App.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useCallback } from 'react'; import DataGrid, { Paging, @@ -73,36 +73,41 @@ function calculateFilterExpression( const onRowInserted = (e: DataGridTypes.RowInsertedEvent) => e.component.navigateToRow(e.key); -const statusEditorRender = (cell: DataGridTypes.ColumnEditCellTemplateData) => { - const onValueChanged = (e: SelectBoxTypes.ValueChangedEvent) => cell.setValue(e.value); +const statusEditorRender = (cell: DataGridTypes.ColumnEditCellTemplateData) => ; - const itemRender = (data: { id: number, name: string } | null) => { - if (data) { - const imageSource = `images/icons/status-${data.id}.svg`; +const statusItemRender = (data: { id: number, name: string } | null) => { + if (data) { + const imageSource = `images/icons/status-${data.id}.svg`; - return ( -
- - {data.name} -
- ); - } + return ( +
+ + {data.name} +
+ ); + } - return (All); - }; + return (All); +}; +const StatusEditor = ({ cell }: { cell: DataGridTypes.ColumnEditCellTemplateData }) => { const lookupDataSource = cell.column.lookup?.dataSource; const dataSource = typeof lookupDataSource === 'function' ? lookupDataSource({ data: cell.data, key: cell.row.key }) : lookupDataSource; + const onValueChanged = useCallback((e: SelectBoxTypes.ValueChangedEvent) => { + cell.setValue(e.value); + }, [cell]); return ( + itemRender={statusItemRender} /> ); }; diff --git a/apps/demos/Demos/DataGrid/CustomEditors/React/EmployeeDropDownBoxComponent.tsx b/apps/demos/Demos/DataGrid/CustomEditors/React/EmployeeDropDownBoxComponent.tsx index c7f30924b288..69024a643cdd 100644 --- a/apps/demos/Demos/DataGrid/CustomEditors/React/EmployeeDropDownBoxComponent.tsx +++ b/apps/demos/Demos/DataGrid/CustomEditors/React/EmployeeDropDownBoxComponent.tsx @@ -11,9 +11,12 @@ import DropDownBox, { type DropDownBoxTypes } from 'devextreme-react/drop-down-b const dropDownOptions = { width: 500 }; const ownerLabel = { 'aria-label': 'Owner' }; +const clearContextMenu = (event: DataGridTypes.ContextMenuPreparingEvent) => { + event.items = []; +}; -const EmployeeDropDownBoxComponent = (props: DataGridTypes.ColumnCellTemplateData) => { - const { data: { value: dataValue } } = props; +const EmployeeDropDownBoxComponent = ({ data }: DataGridTypes.ColumnCellTemplateData) => { + const { value: dataValue } = data; const initialSelectedRowKeys = dataValue !== null && dataValue !== undefined ? [dataValue] : []; const [selectedRowKeys, setSelectedRowKeys] = useState(initialSelectedRowKeys); const [isDropDownOpened, setDropDownOpened] = useState(false); @@ -24,48 +27,43 @@ const EmployeeDropDownBoxComponent = (props: DataGridTypes.ColumnCellTemplateDat } }, []); - const contentRender = useCallback(() => { - const onContextMenuPreparing = (event: DataGridTypes.ContextMenuPreparingEvent) => { - event.items = []; - }; - const onSelectionChanged = (args: DataGridTypes.SelectionChangedEvent) => { - setSelectedRowKeys(args.selectedRowKeys); - setDropDownOpened(false); + const onSelectionChanged = useCallback((args: DataGridTypes.SelectionChangedEvent) => { + setSelectedRowKeys(args.selectedRowKeys); + setDropDownOpened(false); - props.data.setValue(args.selectedRowKeys[0]); - }; + data.setValue(args.selectedRowKeys[0]); + }, [data]); - return ( - - - - - - - - - ); - }, [props.data, selectedRowKeys]); + const contentRender = useCallback(() => ( + + + + + + + + + ), [data, onSelectionChanged, selectedRowKeys]); return ( (rowData.AssignedEmployee || []).indexOf(filterValue) !== -1; } const onRowInserted = (e) => e.component.navigateToRow(e.key); -const statusEditorRender = (cell) => { - const onValueChanged = (e) => cell.setValue(e.value); - const itemRender = (data) => { - if (data) { - const imageSource = `images/icons/status-${data.id}.svg`; - return ( -
- - {data.name} -
- ); - } - return (All); - }; +const statusEditorRender = (cell) => ; +const statusItemRender = (data) => { + if (data) { + const imageSource = `images/icons/status-${data.id}.svg`; + return ( +
+ + {data.name} +
+ ); + } + return (All); +}; +const StatusEditor = ({ cell }) => { const lookupDataSource = cell.column.lookup?.dataSource; const dataSource = typeof lookupDataSource === 'function' ? lookupDataSource({ data: cell.data, key: cell.row.key }) : lookupDataSource; + const onValueChanged = useCallback( + (e) => { + cell.setValue(e.value); + }, + [cell], + ); return ( ); }; diff --git a/apps/demos/Demos/DataGrid/CustomEditors/ReactJs/EmployeeDropDownBoxComponent.js b/apps/demos/Demos/DataGrid/CustomEditors/ReactJs/EmployeeDropDownBoxComponent.js index 48cca013ebad..ec6f824b6713 100644 --- a/apps/demos/Demos/DataGrid/CustomEditors/ReactJs/EmployeeDropDownBoxComponent.js +++ b/apps/demos/Demos/DataGrid/CustomEditors/ReactJs/EmployeeDropDownBoxComponent.js @@ -6,10 +6,11 @@ import DropDownBox from 'devextreme-react/drop-down-box'; const dropDownOptions = { width: 500 }; const ownerLabel = { 'aria-label': 'Owner' }; -const EmployeeDropDownBoxComponent = (props) => { - const { - data: { value: dataValue }, - } = props; +const clearContextMenu = (event) => { + event.items = []; +}; +const EmployeeDropDownBoxComponent = ({ data }) => { + const { value: dataValue } = data; const initialSelectedRowKeys = dataValue !== null && dataValue !== undefined ? [dataValue] : []; const [selectedRowKeys, setSelectedRowKeys] = useState(initialSelectedRowKeys); const [isDropDownOpened, setDropDownOpened] = useState(false); @@ -18,23 +19,23 @@ const EmployeeDropDownBoxComponent = (props) => { setDropDownOpened(e.value); } }, []); - const contentRender = useCallback(() => { - const onContextMenuPreparing = (event) => { - event.items = []; - }; - const onSelectionChanged = (args) => { + const onSelectionChanged = useCallback( + (args) => { setSelectedRowKeys(args.selectedRowKeys); setDropDownOpened(false); - props.data.setValue(args.selectedRowKeys[0]); - }; - return ( + data.setValue(args.selectedRowKeys[0]); + }, + [data], + ); + const contentRender = useCallback( + () => ( { - ); - }, [props.data, selectedRowKeys]); + ), + [data, onSelectionChanged, selectedRowKeys], + ); return (
- diff --git a/apps/demos/Demos/DataGrid/PDFCellCustomization/React/App.tsx b/apps/demos/Demos/DataGrid/PDFCellCustomization/React/App.tsx index 42170e52ab9f..ca70c5c78223 100644 --- a/apps/demos/Demos/DataGrid/PDFCellCustomization/React/App.tsx +++ b/apps/demos/Demos/DataGrid/PDFCellCustomization/React/App.tsx @@ -81,7 +81,7 @@ const App = () => ( - renderGridCell(e)} /> + ( dataField="Website" alignment="center" width={100} - cellRender={(e) => renderGridCell(e)} + cellRender={renderGridCell} /> diff --git a/apps/demos/Demos/DataGrid/RealTimeUpdates/React/App.tsx b/apps/demos/Demos/DataGrid/RealTimeUpdates/React/App.tsx index 317753f7b7c6..62a3181dbf48 100644 --- a/apps/demos/Demos/DataGrid/RealTimeUpdates/React/App.tsx +++ b/apps/demos/Demos/DataGrid/RealTimeUpdates/React/App.tsx @@ -1,4 +1,6 @@ -import React, { useEffect, useState } from 'react'; +import React, { + memo, useCallback, useEffect, useState, +} from 'react'; import DataGrid, { Column, Summary, TotalItem, MasterDetail, Paging, } from 'devextreme-react/data-grid'; @@ -24,43 +26,35 @@ const getDetailGridDataSource = (product: Product) => ({ const getAmount = (order: Order) => order.UnitPrice * order.Quantity; -const detailRender = (detail: DataGridTypes.MasterDetailTemplateData) => ( - - - - - - - - - - - - - - -); +const DetailGrid: React.ComponentType<{ data: DataGridTypes.MasterDetailTemplateData }> = memo(({ data: detail }) => { + const detailDataSource = getDetailGridDataSource(detail.data); + + return ( + + + + + + + + + + + + + + + ); +}); const App = () => { const [updateFrequency, setUpdateFrequency] = useState(100); @@ -79,9 +73,9 @@ const App = () => { return () => clearInterval(interval); }, [updateFrequency]); - const onUpdateFrequencyChanged = (e: SliderTypes.ValueChangedEvent) => { + const onUpdateFrequencyChanged = useCallback((e: SliderTypes.ValueChangedEvent) => { setUpdateFrequency(e.value); - }; + }, []); return (
@@ -115,7 +109,7 @@ const App = () => {
+ component={DetailGrid}>
diff --git a/apps/demos/Demos/DataGrid/RealTimeUpdates/ReactJs/App.js b/apps/demos/Demos/DataGrid/RealTimeUpdates/ReactJs/App.js index 51e2adb1fefb..f69eb4a6cf0d 100644 --- a/apps/demos/Demos/DataGrid/RealTimeUpdates/ReactJs/App.js +++ b/apps/demos/Demos/DataGrid/RealTimeUpdates/ReactJs/App.js @@ -1,4 +1,6 @@ -import React, { useEffect, useState } from 'react'; +import React, { + memo, useCallback, useEffect, useState, +} from 'react'; import DataGrid, { Column, Summary, @@ -22,62 +24,65 @@ const getDetailGridDataSource = (product) => ({ filter: ['ProductID', '=', product.ProductID], }); const getAmount = (order) => order.UnitPrice * order.Quantity; -const detailRender = (detail) => ( - - - - - - - - - - { + const detailDataSource = getDetailGridDataSource(detail.data); + return ( + + + + + - - - - -); + + + + + + + + ); +}); const App = () => { const [updateFrequency, setUpdateFrequency] = useState(100); useEffect(() => { @@ -91,9 +96,9 @@ const App = () => { }, 50); return () => clearInterval(interval); }, [updateFrequency]); - const onUpdateFrequencyChanged = (e) => { + const onUpdateFrequencyChanged = useCallback((e) => { setUpdateFrequency(e.value); - }; + }, []); return (
{
diff --git a/apps/demos/Demos/DataGrid/RealTimeUpdates/ReactJs/index.html b/apps/demos/Demos/DataGrid/RealTimeUpdates/ReactJs/index.html index b6ad2f9b1595..7b47950bbaff 100644 --- a/apps/demos/Demos/DataGrid/RealTimeUpdates/ReactJs/index.html +++ b/apps/demos/Demos/DataGrid/RealTimeUpdates/ReactJs/index.html @@ -12,7 +12,6 @@
- diff --git a/apps/demos/Demos/DataGrid/RowEditing/React/App.tsx b/apps/demos/Demos/DataGrid/RowEditing/React/App.tsx index 603cf85d7df9..d2356c6a003d 100644 --- a/apps/demos/Demos/DataGrid/RowEditing/React/App.tsx +++ b/apps/demos/Demos/DataGrid/RowEditing/React/App.tsx @@ -16,6 +16,19 @@ const App = () => { setEvents([]); }, []); + const logEditingStart = useCallback(() => logEvent('EditingStart'), [logEvent]); + const logInitNewRow = useCallback(() => logEvent('InitNewRow'), [logEvent]); + const logRowInserting = useCallback(() => logEvent('RowInserting'), [logEvent]); + const logRowInserted = useCallback(() => logEvent('RowInserted'), [logEvent]); + const logRowUpdating = useCallback(() => logEvent('RowUpdating'), [logEvent]); + const logRowUpdated = useCallback(() => logEvent('RowUpdated'), [logEvent]); + const logRowRemoving = useCallback(() => logEvent('RowRemoving'), [logEvent]); + const logRowRemoved = useCallback(() => logEvent('RowRemoved'), [logEvent]); + const logSaving = useCallback(() => logEvent('Saving'), [logEvent]); + const logSaved = useCallback(() => logEvent('Saved'), [logEvent]); + const logEditCanceling = useCallback(() => logEvent('EditCanceling'), [logEvent]); + const logEditCanceled = useCallback(() => logEvent('EditCanceled'), [logEvent]); + return ( <> { keyExpr="ID" allowColumnReordering={true} showBorders={true} - onEditingStart={() => logEvent('EditingStart')} - onInitNewRow={() => logEvent('InitNewRow')} - onRowInserting={() => logEvent('RowInserting')} - onRowInserted={() => logEvent('RowInserted')} - onRowUpdating={() => logEvent('RowUpdating')} - onRowUpdated={() => logEvent('RowUpdated')} - onRowRemoving={() => logEvent('RowRemoving')} - onRowRemoved={() => logEvent('RowRemoved')} - onSaving={() => logEvent('Saving')} - onSaved={() => logEvent('Saved')} - onEditCanceling={() => logEvent('EditCanceling')} - onEditCanceled={() => logEvent('EditCanceled')}> + onEditingStart={logEditingStart} + onInitNewRow={logInitNewRow} + onRowInserting={logRowInserting} + onRowInserted={logRowInserted} + onRowUpdating={logRowUpdating} + onRowUpdated={logRowUpdated} + onRowRemoving={logRowRemoving} + onRowRemoved={logRowRemoved} + onSaving={logSaving} + onSaved={logSaved} + onEditCanceling={logEditCanceling} + onEditCanceled={logEditCanceled}> { const clearEvents = useCallback(() => { setEvents([]); }, []); + const logEditingStart = useCallback(() => logEvent('EditingStart'), [logEvent]); + const logInitNewRow = useCallback(() => logEvent('InitNewRow'), [logEvent]); + const logRowInserting = useCallback(() => logEvent('RowInserting'), [logEvent]); + const logRowInserted = useCallback(() => logEvent('RowInserted'), [logEvent]); + const logRowUpdating = useCallback(() => logEvent('RowUpdating'), [logEvent]); + const logRowUpdated = useCallback(() => logEvent('RowUpdated'), [logEvent]); + const logRowRemoving = useCallback(() => logEvent('RowRemoving'), [logEvent]); + const logRowRemoved = useCallback(() => logEvent('RowRemoved'), [logEvent]); + const logSaving = useCallback(() => logEvent('Saving'), [logEvent]); + const logSaved = useCallback(() => logEvent('Saved'), [logEvent]); + const logEditCanceling = useCallback(() => logEvent('EditCanceling'), [logEvent]); + const logEditCanceled = useCallback(() => logEvent('EditCanceled'), [logEvent]); return ( <> { keyExpr="ID" allowColumnReordering={true} showBorders={true} - onEditingStart={() => logEvent('EditingStart')} - onInitNewRow={() => logEvent('InitNewRow')} - onRowInserting={() => logEvent('RowInserting')} - onRowInserted={() => logEvent('RowInserted')} - onRowUpdating={() => logEvent('RowUpdating')} - onRowUpdated={() => logEvent('RowUpdated')} - onRowRemoving={() => logEvent('RowRemoving')} - onRowRemoved={() => logEvent('RowRemoved')} - onSaving={() => logEvent('Saving')} - onSaved={() => logEvent('Saved')} - onEditCanceling={() => logEvent('EditCanceling')} - onEditCanceled={() => logEvent('EditCanceled')} + onEditingStart={logEditingStart} + onInitNewRow={logInitNewRow} + onRowInserting={logRowInserting} + onRowInserted={logRowInserted} + onRowUpdating={logRowUpdating} + onRowUpdated={logRowUpdated} + onRowRemoving={logRowRemoving} + onRowRemoved={logRowRemoved} + onSaving={logSaving} + onSaved={logSaved} + onEditCanceling={logEditCanceling} + onEditCanceled={logEditCanceled} > { const searchValueRef = useRef(''); @@ -58,8 +60,8 @@ const App = () => { -
- Similarity Factor: +
+ Similarity Factor: { const searchValueRef = useRef(''); const similarityFactorRef = useRef(0.31); @@ -66,8 +68,8 @@ const App = () => { -
- Similarity Factor: +
+ Similarity Factor: