Skip to content

Commit

Permalink
Merge branch 'feature/dev-issue-1048' of github.com:handsontable/hand…
Browse files Browse the repository at this point in the history
…sontable into feature/dev-issue-1048
  • Loading branch information
wszymanski committed Mar 27, 2023
2 parents c4a14ea + 999afb1 commit 8e49982
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 148 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [12.3.2] - 2023-03-23

### Added

- Added a Chinese (zh-CN) translation of the "Copy with headers" feature.
[#10273](https://github.com/handsontable/handsontable/pull/10273)
- Added a new "Rows sorting" guide. [#10183](https://github.com/handsontable/handsontable/pull/10183)

### Fixed

Expand All @@ -27,6 +27,7 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
[`getDataAtCol()`](https://handsontable.com/docs/javascript-data-grid/api/core/#getdataatcol) or
[`getDataAtProp()`](https://handsontable.com/docs/javascript-data-grid/api/core/#getdataatprop) caused an error when the data set had more than 125 000 rows.
[#10226](https://github.com/handsontable/handsontable/pull/10226)
-

## [12.3.1] - 2023-02-06

Expand Down
18 changes: 9 additions & 9 deletions docs/content/guides/rows/rows-sorting.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ patterns and trends.

You can sort data in different ways:

- Alphabetically, numerically, or based on a [custom sorting logic](#sort-different-types-of-data)
- In ascending, descending, or a [custom order](#add-a-custom-comparator)
- By a single column, or by [multiple columns](#sort-by-multiple-columns)
- Using Handsontable's [UI](#demo) or [API](#control-sorting-programmatically)
- Alphabetically, numerically, or based on a custom sorting logic
- In ascending, descending, or a custom order
- By a single column, or by multiple columns
- Using Handsontable's UI or API

Handsontable sorts data only visually, so your source data remains in the original order. To save
your sorting changes in the data source, see this guide:
Expand Down Expand Up @@ -176,7 +176,7 @@ const handsontableInstance = new Handsontable(container, {
::: example #example1 :react

```jsx
// to import just individual modules, see the 'Import the sorting module' section of this page
// to import sorting as an individual module, see the 'Import the sorting module' section of this page

import { HotTable } from '@handsontable/react';
import { registerAllModules } from 'handsontable/registry';
Expand Down Expand Up @@ -3864,11 +3864,11 @@ root.render(<HandsontableComponent />);
You can run your code before or after sorting, using the following
[Handsontable hooks](@/guides/getting-started/events-and-hooks.md):
- [`beforeColumnSort`](@/api/hooks.md#beforecolumnsort)
- [`afterColumnSort`](@/api/hooks.md#aftercolumnsort)
- [`beforeColumnSort()`](@/api/hooks.md#beforecolumnsort)
- [`afterColumnSort()`](@/api/hooks.md#aftercolumnsort)
For example, you can use [`beforeColumnSort`](@/api/hooks.md#beforecolumnsort) for server-side
sorting, or use [`afterColumnSort`](@/api/hooks.md#aftercolumnsort) to
For example, you can use [`beforeColumnSort()`](@/api/hooks.md#beforecolumnsort) for server-side
sorting, or use [`afterColumnSort()`](@/api/hooks.md#aftercolumnsort) to
[exclude rows from sorting](#exclude-rows-from-sorting).
::: only-for javascript
Expand Down
2 changes: 2 additions & 0 deletions docs/content/guides/upgrade-and-migration/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ For more information on this release, see:

- Added a Chinese (zh-CN) translation of the "Copy with headers" feature.
[#10273](https://github.com/handsontable/handsontable/pull/10273)
- Added a new "[Rows sorting](https://handsontable.com/docs/rows-sorting)" guide.
[#10183](https://github.com/handsontable/handsontable/pull/10183)

#### Fixed

Expand Down
2 changes: 2 additions & 0 deletions docs/docker/redirects.conf
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ rewrite ^/docs/vue3-simple-example/?$ /docs/javascript-data-grid/vue3-basic-exam
rewrite ^/docs/vue3-setting-up-a-language/?$ /docs/javascript-data-grid/vue3-setting-up-a-translation/ permanent;
rewrite ^/docs/row-sorting/?$ /docs/$framework/rows-sorting/ permanent;
rewrite ^/docs/column-sorting/?$ /docs/$framework/rows-sorting/ permanent;
rewrite ^/docs/(javascript|react)-data-grid/row-sorting/?$ /docs/$framework/rows-sorting/ permanent;
rewrite ^/docs/(javascript|react)-data-grid/column-sorting/?$ /docs/$framework/rows-sorting/ permanent;

# --- demos ---
rewrite ^/docs/((\d+\.\d+|next)/)?demo-scrolling/?$ /docs/$1$framework/row-virtualization/ permanent;
Expand Down
18 changes: 0 additions & 18 deletions wrappers/react/src/editorsPortalManager.tsx

This file was deleted.

51 changes: 9 additions & 42 deletions wrappers/react/src/hotColumn.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,16 @@
import React, { ReactPortal } from 'react';
import React from 'react';
import { HotTableProps, HotColumnProps } from './types';
import {
createEditorPortal,
getExtendedEditorElement,
} from './helpers';
import { SettingsMapper } from './settingsMapper';
import { EditorsPortalManager } from './editorsPortalManager';
import Handsontable from 'handsontable/base';

class HotColumn extends React.Component<HotColumnProps, {}> {
internalProps: string[];
columnSettings: Handsontable.ColumnSettings;

/**
* Component used to manage the editor portals.
*
* @type {React.Component}
*/
private editorsPortalManager: EditorsPortalManager = null;

/**
* Set the editors portal manager ref.
*
* @param {React.ReactComponent} pmComponent The PortalManager component.
*/
private setEditorsPortalManagerRef(pmComponent: EditorsPortalManager): void {
this.editorsPortalManager = pmComponent;
}

/**
* Filter out all the internal properties and return an object with just the Handsontable-related props.
*
Expand Down Expand Up @@ -76,21 +59,6 @@ class HotColumn extends React.Component<HotColumnProps, {}> {
}
}

/**
* Creates the local editor portal and renders it within the editors portal manager component.
*
* @param {Function} callback Callback to call which is triggered after the editors portal is rendered.
*/
renderLocalEditorPortal(callback: () => void): void {
const editorCache = this.props._getEditorCache();
const localEditorElement = getExtendedEditorElement(this.props.children, editorCache, this.props._columnIndex);
const editorPortal = createEditorPortal(this.props._getOwnerDocument(), localEditorElement);

this.editorsPortalManager.setState({
portals: [editorPortal]
}, callback);
}

/**
* Emit the column settings to the parent using a prop passed from the parent.
*/
Expand All @@ -108,20 +76,16 @@ class HotColumn extends React.Component<HotColumnProps, {}> {
* Logic performed after the mounting of the HotColumn component.
*/
componentDidMount(): void {
this.renderLocalEditorPortal(() => {
this.createColumnSettings();
this.emitColumnSettings();
});
this.createColumnSettings();
this.emitColumnSettings();
}

/**
* Logic performed after the updating of the HotColumn component.
*/
componentDidUpdate(): void {
this.renderLocalEditorPortal(() => {
this.createColumnSettings();
this.emitColumnSettings();
});
this.createColumnSettings();
this.emitColumnSettings();
}

/**
Expand All @@ -130,9 +94,12 @@ class HotColumn extends React.Component<HotColumnProps, {}> {
* @returns {React.ReactElement}
*/
render(): React.ReactElement {
const ownerDocument = this.props._getOwnerDocument();
const editorPortal = createEditorPortal(ownerDocument, this.getLocalEditorElement());

return (
<React.Fragment>
<EditorsPortalManager ref={this.setEditorsPortalManagerRef.bind(this)} />
{editorPortal}
</React.Fragment>
)
}
Expand Down
114 changes: 36 additions & 78 deletions wrappers/react/src/hotTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React from 'react';
import Handsontable from 'handsontable/base';
import { SettingsMapper } from './settingsMapper';
import { RenderersPortalManager } from './renderersPortalManager';
import { EditorsPortalManager } from './editorsPortalManager';
import { HotColumn } from './hotColumn';
import * as packageJson from '../package.json';
import {
Expand Down Expand Up @@ -93,12 +92,6 @@ class HotTable extends React.Component<HotTableProps, {}> {
* @type {React.Component}
*/
renderersPortalManager: RenderersPortalManager = null;
/**
* Component used to manage the editor portals.
*
* @type {React.Component}
*/
private editorsPortalManager: EditorsPortalManager = null;

/**
* Array containing the portals cashed to be rendered in bulk after Handsontable's render cycle.
Expand Down Expand Up @@ -194,7 +187,6 @@ class HotTable extends React.Component<HotTableProps, {}> {
* Clear both the editor and the renderer cache.
*/
clearCache(): void {
this.getEditorCache().clear();
this.getRenderedCellCache().clear();
this.componentRendererColumns.clear();
}
Expand Down Expand Up @@ -342,20 +334,6 @@ class HotTable extends React.Component<HotTableProps, {}> {
return getExtendedEditorElement(this.props.children, this.getEditorCache());
}

/**
* Creates the global editor portal and renders it within the editors portal manager component.
*
* @param {Function} callback Callback to call which is triggered after the editors portal is rendered.
*/
renderGlobalEditorPortal(callback: () => void): void {
const globalEditorElement = this.getGlobalEditorElement();
const editorPortal = createEditorPortal(this.getOwnerDocument(), globalEditorElement)

this.editorsPortalManager.setState({
portals: [editorPortal]
}, callback);
}

/**
* Create a new settings object containing the column settings and global editors and renderers.
*
Expand Down Expand Up @@ -426,13 +404,10 @@ class HotTable extends React.Component<HotTableProps, {}> {
* Handsontable's `afterViewRender` hook callback.
*/
handsontableAfterViewRender(): void {
this.renderersPortalManager.setState(() => {
return Object.assign({}, {
portals: this.portalCacheArray
});

this.renderersPortalManager.setState({
portals: [...this.portalCacheArray]
}, () => {
this.portalCacheArray.length = 0;
this.portalCacheArray = [];
});
}

Expand All @@ -455,14 +430,6 @@ class HotTable extends React.Component<HotTableProps, {}> {
private setRenderersPortalManagerRef(pmComponent: RenderersPortalManager): void {
this.renderersPortalManager = pmComponent;
}
/**
* Set the editors portal manager ref.
*
* @param {React.ReactComponent} pmComponent The PortalManager component.
*/
private setEditorsPortalManagerRef(pmComponent: EditorsPortalManager): void {
this.editorsPortalManager = pmComponent;
}

/*
---------------------------------------
Expand All @@ -474,45 +441,37 @@ class HotTable extends React.Component<HotTableProps, {}> {
* Initialize Handsontable after the component has mounted.
*/
componentDidMount(): void {
this.clearCache();
this.renderGlobalEditorPortal(() => {
// In React strict mode the mount/unmount is triggered twice. The `if` prevents
// creating two Handsontable instances for the same component in that mode.
if (this.hotInstance) {
return;
}
const newGlobalSettings = this.createNewGlobalSettings();

const newGlobalSettings = this.createNewGlobalSettings();
this.hotInstance = new Handsontable.Core(this.hotElementRef, newGlobalSettings);

this.hotInstance = new Handsontable.Core(this.hotElementRef, newGlobalSettings);
this.hotInstance.addHook('beforeViewRender', () => this.handsontableBeforeViewRender());
this.hotInstance.addHook('afterViewRender', () => this.handsontableAfterViewRender());

this.hotInstance.addHook('beforeViewRender', () => this.handsontableBeforeViewRender());
this.hotInstance.addHook('afterViewRender', () => this.handsontableAfterViewRender());
// `init` missing in Handsontable's type definitions.
(this.hotInstance as any).init();

// `init` missing in Handsontable's type definitions.
(this.hotInstance as any).init();

this.displayAutoSizeWarning(newGlobalSettings);
});
this.displayAutoSizeWarning(newGlobalSettings);
}

/**
* Logic performed after the component update.
*/
componentDidUpdate(): void {
this.clearCache();
this.renderGlobalEditorPortal(() => {
const newGlobalSettings = this.createNewGlobalSettings();

this.updateHot(newGlobalSettings);
this.displayAutoSizeWarning(newGlobalSettings);
});
const newGlobalSettings = this.createNewGlobalSettings();

this.updateHot(newGlobalSettings);
this.displayAutoSizeWarning(newGlobalSettings);
}

/**
* Destroy the Handsontable instance when the parent component unmounts.
*/
componentWillUnmount(): void {
this.clearCache();

if (this.hotInstance) {
this.hotInstance.destroy();
}
Expand All @@ -524,35 +483,34 @@ class HotTable extends React.Component<HotTableProps, {}> {
render(): React.ReactElement {
const containerProps = getContainerAttributesProps(this.props);
const isHotColumn = (childNode: any) => childNode.type === HotColumn;
let children = React.Children.toArray(this.props.children);

// filter out anything that's not a HotColumn
children = children.filter(function (childNode: any) {
return isHotColumn(childNode);
});
const children = React.Children.toArray(this.props.children);

// clone the HotColumn nodes and extend them with the callbacks
let childClones = children.map((childNode: React.ReactElement, columnIndex: number) => {
return React.cloneElement(childNode, {
_componentRendererColumns: this.componentRendererColumns,
_emitColumnSettings: this.setHotColumnSettings.bind(this),
_columnIndex: columnIndex,
_getChildElementByType: getChildElementByType.bind(this),
_getRendererWrapper: this.getRendererWrapper.bind(this),
_getEditorClass: this.getEditorClass.bind(this),
_getOwnerDocument: this.getOwnerDocument.bind(this),
_getEditorCache: this.getEditorCache.bind(this),
children: childNode.props.children
} as object);
});
const hotColumnClones = children
.filter((childNode: any) => isHotColumn(childNode))
.map((childNode: React.ReactElement, columnIndex: number) => {
return React.cloneElement(childNode, {
_componentRendererColumns: this.componentRendererColumns,
_emitColumnSettings: this.setHotColumnSettings.bind(this),
_columnIndex: columnIndex,
_getChildElementByType: getChildElementByType.bind(this),
_getRendererWrapper: this.getRendererWrapper.bind(this),
_getEditorClass: this.getEditorClass.bind(this),
_getOwnerDocument: this.getOwnerDocument.bind(this),
_getEditorCache: this.getEditorCache.bind(this),
children: childNode.props.children
} as object);
});

const editorPortal = createEditorPortal(this.getOwnerDocument(), this.getGlobalEditorElement());

return (
<React.Fragment>
<div ref={this.setHotElementRef.bind(this)} {...containerProps}>
{childClones}
{hotColumnClones}
</div>
<RenderersPortalManager ref={this.setRenderersPortalManagerRef.bind(this)} />
<EditorsPortalManager ref={this.setEditorsPortalManagerRef.bind(this)} />
{editorPortal}
</React.Fragment>
)
}
Expand Down

0 comments on commit 8e49982

Please sign in to comment.