Skip to content

Instantly share code, notes, and snippets.

@gargroh
Created November 14, 2019 10:14
Show Gist options
  • Save gargroh/ab11066424a0bdc775fe0f7eeb451a16 to your computer and use it in GitHub Desktop.
Save gargroh/ab11066424a0bdc775fe0f7eeb451a16 to your computer and use it in GitHub Desktop.
import React from 'react';
import PropTypes from 'prop-types';
import {
ensurePluginOrder,
getFirstDefined,
makeHeaderGroups,
applyPropHooks,
mergeProps,
flexRender
} from '../utils';
import { addActions, actions } from '../actions';
import { defaultState, calculateHeaderWidths, renderErr } from '../hooks/useTable';
defaultState.pinnedColumns = {};
addActions('setColumnPin');
const propTypes = {};
export const usePinColumns = (hooks) => {
hooks.useMain.push(useMain);
};
usePinColumns.pluginName = 'usePinColumns';
const COLUMN_PINS = {
left: -1,
center: 0,
right: 1
};
function useMain(instance) {
PropTypes.checkPropTypes(propTypes, instance, 'property', 'usePinColumns');
const {
plugins,
flatHeaders,
disablePinning,
state: { pinnedColumns },
setState
} = instance;
ensurePluginOrder(plugins, ['useColumnOrder'], 'usePinColumns', []);
const setColumnPin = React.useCallback(
(updater) => {
return setState((old) => {
return {
...old,
pinnedColumns: typeof updater === 'function' ? updater(old.pinnedColumns) : updater
};
}, actions.setColumnPin);
},
[setState]
);
flatHeaders.forEach((column) => {
const { disablePinning: columnDisablePinning, accessor } = column;
const canPin = accessor
? getFirstDefined(
columnDisablePinning === true ? false : undefined,
disablePinning === true ? false : undefined,
true
)
: false;
column.canPin = canPin;
column.pinType = pinnedColumns[column.id] || 0;
column.setColumnPin = (pinType) => {
column.pinType = pinType;
setColumnPin({
...pinnedColumns,
[column.id]: pinType
});
};
column.toggleColumnPin = (pinType) => {
let setPinValue = column.pinType === pinType ? 0 : pinType;
column.setColumnPin(setPinValue);
};
});
const pinnedDetails = getPinnedHeaderGroups(instance);
return {
...instance,
setColumnPin,
...pinnedDetails
};
}
function getPinnedHeaderGroups(instance) {
const {
state: { pinnedColumns },
flatColumns,
defaultColumn
} = instance;
let columnMapBySegments = {
left: [],
right: [],
center: []
};
flatColumns.forEach((column) => {
const pinValue = pinnedColumns[column.id];
switch (pinValue) {
case COLUMN_PINS.left:
columnMapBySegments.left.push(column);
break;
case COLUMN_PINS.right:
columnMapBySegments.right.push(column);
break;
default:
columnMapBySegments.center.push(column);
}
});
let pinnedHeaderGroup = [];
let pinnedflatHeaders = [];
//todo, use constants
['left', 'center', 'right'].forEach((segment, index) => {
const hgrp = makeHeaderGroups(columnMapBySegments[segment], defaultColumn);
addPinTypeInfo(hgrp, index - 1);
determineHeaderVisibility(hgrp[0].headers, instance);
calculateHeaderWidths(hgrp[0].headers);
const flatHeaders = hgrp.reduce((all, headerGroup) => [...all, ...headerGroup.headers], []);
pinnedflatHeaders = [...pinnedflatHeaders, ...flatHeaders];
materializeHeaders(flatHeaders, instance);
materializeHeaderGroups(hgrp, instance);
pinnedHeaderGroup = [...pinnedHeaderGroup, ...hgrp];
});
return {
headerGroups: pinnedHeaderGroup,
flatHeaders: pinnedflatHeaders
};
}
// Todo: This will come via common place i.e. utils for both useTable and usePinColumns
function materializeHeaders(flatHeaders, instance) {
flatHeaders.forEach((column) => {
// Give columns/headers rendering power
column.render = (type, userProps = {}) => {
const Comp = typeof type === 'string' ? column[type] : type;
if (typeof Comp === 'undefined') {
throw new Error(renderErr);
}
return flexRender(Comp, {
...instance,
column,
...userProps
});
};
// Give columns/headers a default getHeaderProps
column.getHeaderProps = (props) =>
mergeProps(
{
key: ['header', column.id].join('_'),
colSpan: column.totalVisibleHeaderCount
},
applyPropHooks(instance.hooks.getHeaderProps, column, instance.current),
props
);
});
}
// Todo: This will come via common place i.e. utils for both useTable and usePinColumns
function materializeHeaderGroups(headerGroups, instance) {
headerGroups.forEach((headerGroup, i) => {
// Filter out any headers and headerGroups that don't have visible columns
headerGroup.headers = headerGroup.headers.filter((header) => {
const recurse = (headers) =>
headers.filter((header) => {
if (header.headers) {
return recurse(header.headers);
}
return header.isVisible;
}).length;
if (header.headers) {
return recurse(header.headers);
}
return header.isVisible;
});
// Give headerGroups getRowProps
if (headerGroup.headers.length) {
headerGroup.getHeaderGroupProps = (props = {}) =>
mergeProps(
{
key: [`header${i}`].join('_')
},
applyPropHooks(instance.hooks.getHeaderGroupProps, headerGroup, instance),
props
);
return true;
}
});
}
// Todo: This will come via common place i.e. utils for both useTable and usePinColumns
function determineHeaderVisibility(headers, instance) {
const handleColumn = (column, parentVisible) => {
column.isVisible = parentVisible
? typeof column.show === 'function'
? column.show(instance)
: true //!!column.show // todo
: false;
let totalVisibleHeaderCount = 0;
if (column.headers && column.headers.length) {
column.headers.forEach(
(subColumn) => (totalVisibleHeaderCount += handleColumn(subColumn, column.isVisible))
);
} else {
totalVisibleHeaderCount = column.isVisible ? 1 : 0;
}
column.totalVisibleHeaderCount = totalVisibleHeaderCount;
console.log(column.id, totalVisibleHeaderCount, column.headers, column.isVisible);
return totalVisibleHeaderCount;
};
let totalVisibleHeaderCount = 0;
headers.forEach((subHeader) => (totalVisibleHeaderCount += handleColumn(subHeader, true)));
}
function addPinTypeInfo(headerGroups, pinType) {
const recurse = (headers) => {
headers.forEach((header) => {
// console.log(header.id, 'id');
header.pinType = pinType;
if (header.headers && header.headers.length) {
recurse(header.headers);
}
});
};
headerGroups.forEach((headerGroup) => {
headerGroup.pinType = pinType;
recurse(headerGroup.headers);
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment