Skip to content

Commit

Permalink
Add horizontal-nowrap compactType (#154)
Browse files Browse the repository at this point in the history
* feat: horizontal-nowrap compactType

* fix: adgusted layout memo parent merge

* fix: originalLayouts memo fix for adjustedLayouts items

* feat: move horizaontal nowrap to context hoc

* fix: update original layout when working with groups

* fix: add groups layout and props memoization

* fix: not autoheight elements height update fix

* feat: simplified nowrap adjust

* fix: cleanup original map if layout updated

* fix: removed redundunt ref for predicate
  • Loading branch information
flops authored Jul 12, 2024
1 parent 49969d0 commit 8468427
Show file tree
Hide file tree
Showing 8 changed files with 296 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ export const DashKitGroupsShowcase: React.FC = () => {
);
},
gridProperties: (props: ReactGridLayoutProps) => {
return {...props, compactType: 'horizontal'};
return {...props, compactType: 'horizontal-nowrap', maxRows: 2};
},
},
{
Expand Down
11 changes: 6 additions & 5 deletions src/components/DashKit/__stories__/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export const getConfig = (withGroups?: boolean): DashKitProps['config'] => ({
id: 'Fr',
data: {
text: 'special mode _editActive',
_editActive: true,
},
type: 'text',
namespace: 'default',
Expand Down Expand Up @@ -114,17 +115,17 @@ export const getConfig = (withGroups?: boolean): DashKitProps['config'] => ({
{
h: 2,
i: 'Fk',
w: 36,
w: 10,
x: 0,
y: 0,
parent: fixedGroup,
},
{
h: 6,
h: 2,
i: 'Fr',
w: 12,
x: 0,
y: 2,
w: 10,
x: 10,
y: 0,
parent: fixedGroup,
},
]
Expand Down
121 changes: 106 additions & 15 deletions src/components/GridLayout/GridLayout.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import React from 'react';

import {DEFAULT_GROUP, OVERLAY_CONTROLS_CLASS_NAME, TEMPORARY_ITEM_ID} from '../../constants';
import {
COMPACT_TYPE_HORIZONTAL_NOWRAP,
DEFAULT_GROUP,
OVERLAY_CONTROLS_CLASS_NAME,
TEMPORARY_ITEM_ID,
} from '../../constants';
import {DashKitContext} from '../../context/DashKitContext';
import GridItem from '../GridItem/GridItem';

Expand Down Expand Up @@ -29,10 +34,20 @@ export default class GridLayout extends React.PureComponent {
componentWillUnmount() {
clearTimeout(this._timeout);
document.removeEventListener('visibilitychange', this.onVisibilityChange);

this._memoCallbacksForGroups = {};
this._memoGroupsProps = {};
this._memoGroupsLayouts = {};
this._memoForwardedPluginRef = [];
}

static contextType = DashKitContext;

_memoForwardedPluginRef = [];
_memoGroupsProps = {};
_memoGroupsLayouts = {};
_memoCallbacksForGroups = {};

_timeout;
_lastReloadAt;

Expand Down Expand Up @@ -76,6 +91,74 @@ export default class GridLayout extends React.PureComponent {
return temporaryLayout?.data || layout;
}

getMemoGroupLayout = (group, layout) => {
// fastest possible way to match json
const key = JSON.stringify(layout);

if (this._memoGroupsLayouts[group]) {
if (this._memoGroupsLayouts[group].key === key) {
return this._memoGroupsLayouts[group];
} else {
this._memoGroupsLayouts[group].key = key;
this._memoGroupsLayouts[group].layout = layout;
}
} else {
this._memoGroupsLayouts[group] = {
key,
layout,
};
}

return this._memoGroupsLayouts[group];
};

getMemoGroupCallbacks = (group) => {
if (!this._memoCallbacksForGroups[group]) {
const onStart = this._onStart;
const onStop = this._onStop.bind(this, group);
const onDrop = this._onDrop.bind(this, group);
const onDropDragOver = this._onDropDragOver.bind(this, group);

this._memoCallbacksForGroups[group] = {
onDragStart: onStart,
onResizeStart: onStart,
onDragStop: onStop,
onResizeStop: onStop,
onDrop: onDrop,
onDropDragOver,
};
}

return this._memoCallbacksForGroups[group];
};

getMemoGroupProps = (group, renderLayout, properties) => {
// Needed for _onDropDragOver
this._memoGroupsProps[group] = properties;

return {
layout: this.getMemoGroupLayout(group, renderLayout).layout,
callbacks: this.getMemoGroupCallbacks(group),
};
};

getLayoutAndPropsByGroup = (group) => {
return {
properties: this._memoGroupsProps[group],
layout: this._memoGroupsLayouts[group].layout,
};
};

getMemoForwardRefCallback = (refIndex) => {
if (!this._memoForwardedPluginRef[refIndex]) {
this._memoForwardedPluginRef[refIndex] = (pluginRef) => {
this.pluginsRefs[refIndex] = pluginRef;
};
}

return this._memoForwardedPluginRef[refIndex];
};

mergeGroupsLayout(group, newLayout, temporaryItem) {
const renderLayout = this.getActiveLayout();
const itemsByGroup = renderLayout.reduce(
Expand Down Expand Up @@ -148,14 +231,16 @@ export default class GridLayout extends React.PureComponent {
this.setState({isDragging: false});
};

_onDropDragOver = (e) => {
const {editMode, dragOverPlugin, onDropDragOver} = this.context;
_onDropDragOver = (group, e) => {
const {editMode, dragOverPlugin} = this.context;

if (!editMode || !dragOverPlugin) {
return false;
}

return onDropDragOver(e);
const {properties, layout} = this.getLayoutAndPropsByGroup(group);

return this.context.onDropDragOver(e, properties, layout);
};

_onDrop = (group, newLayout, item, e) => {
Expand Down Expand Up @@ -218,40 +303,46 @@ export default class GridLayout extends React.PureComponent {
...registerManager.gridLayout,
})
: registerManager.gridLayout;
let {compactType} = properties;

if (compactType === COMPACT_TYPE_HORIZONTAL_NOWRAP) {
compactType = 'horizontal';
}

const {callbacks, layout} = this.getMemoGroupProps(group, renderLayout, properties);

return (
<Layout
{...properties}
layout={renderLayout}
compactType={compactType}
layout={layout}
key={`group_${group}`}
isDraggable={editMode}
isResizable={editMode}
onDragStart={this._onStart}
onDragStop={(...args) => this._onStop(group, ...args)}
onResizeStart={this._onStart}
onResizeStop={(...args) => this._onStop(group, ...args)}
onDragStart={callbacks.onDragStart}
onDragStop={callbacks.onDragStop}
onResizeStart={callbacks.onResizeStart}
onResizeStop={callbacks.onResizeStop}
{...(draggableHandleClassName
? {draggableHandle: `.${draggableHandleClassName}`}
: null)}
{...(outerDnDEnable
? {
isDroppable: true,
onDropDragOver: this._onDropDragOver,
onDrop: (...args) => this._onDrop(group, ...args),
onDropDragOver: callbacks.onDropDragOver,
onDrop: callbacks.onDrop,
}
: null)}
draggableCancel={`.${OVERLAY_CONTROLS_CLASS_NAME}`}
>
{renderItems.map((item, i) => {
return (
<GridItem
forwardedPluginRef={(pluginRef) => {
this.pluginsRefs[offset + i] = pluginRef;
}} // forwarded ref to plugin
forwardedPluginRef={this.getMemoForwardRefCallback(offset + i)} // forwarded ref to plugin
key={item.id}
id={item.id}
item={item}
layout={renderLayout}
layout={layout}
adjustWidgetLayout={this.adjustWidgetLayout}
isDragging={this.state.isDragging}
noOverlay={noOverlay}
Expand Down
2 changes: 2 additions & 0 deletions src/constants/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ export const DEFAULT_WIDGET_HEIGHT = 3;
export const DEFAULT_WIDGET_WIDTH = 3;

export const DEFAULT_GROUP = '__default';

export const COMPACT_TYPE_HORIZONTAL_NOWRAP = 'horizontal-nowrap';
25 changes: 22 additions & 3 deletions src/hocs/prepareItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,13 @@ export function prepareItem(Component) {
this.context.onItemStateAndParamsChange(this.props.id, stateAndParams, options);
};

render() {
_currentRenderProps = {};
getRenderProps = () => {
const {id, width, height, item, adjustWidgetLayout, layout, isPlaceholder} = this.props;
const {itemsState, itemsParams, registerManager, settings, context, editMode} =
this.context;
const {type, data, defaults, namespace} = item;
const {data, defaults, namespace} = item;

const rendererProps = {
data,
editMode,
Expand All @@ -63,10 +65,27 @@ export function prepareItem(Component) {
adjustWidgetLayout,
isPlaceholder,
};

const changedProp = Object.entries(rendererProps).find(
([key, value]) => this._currentRenderProps[key] !== value,
);

if (changedProp) {
this._currentRenderProps = rendererProps;
}

return this._currentRenderProps;
};

render() {
const {item, isPlaceholder} = this.props;
const {registerManager} = this.context;
const {type} = item;

return (
<Component
forwardedPluginRef={this.props.forwardedPluginRef}
rendererProps={rendererProps}
rendererProps={this.getRenderProps()}
registerManager={registerManager}
type={type}
isPlaceholder={isPlaceholder}
Expand Down
Loading

0 comments on commit 8468427

Please sign in to comment.