@lessondesk/react-table-context
Advanced tools
Comparing version 1.1.0 to 1.2.0
@@ -1,1 +0,371 @@ | ||
function e(e){return e&&"object"==typeof e&&"default"in e?e.default:e}var t=require("react"),a=e(t),i=e(require("hash-sum")),r=require("fast-equals");module.exports=function(e){void 0===e&&(e=function(){return Promise.resolve([])});var s=t.createContext(),n=function(t){function n(){var a=this;t.call(this),this.checkIfSame=function(e,t){return e.every(function(e){var a=e.id;return t.some(function(e){return e.id===a})})&&t.every(function(t){var a=t.id;return e.some(function(e){return e.id===a})})},this.handleUpdate=function(){var t=a.state,i=a.props.getCacheKey({meta:t.meta,page:t.page,pageSize:t.pageSize,search:t.search,filters:t.filters,sorting:t.sorting,key:a.key});if(a.cache.has(i)){var r=a.cache.get(i);a.setState(Object.assign({},r))}else a.setState({isLoading:!0},function(){e(Object.assign({},a.state)).then(function(e){var t=[],r={};if(e.data&&e.meta?(t=e.data,r=e.meta):r={count:(t=e).length},!Array.isArray(t))throw new Error("Invalid data provided. Expected array, but got "+typeof t);a.setState(function(e){var a=e.page*e.pageSize;return Object.assign({},e,{data:t,meta:r,firstPage:0===e.page,pageData:t.slice(a,a+e.pageSize),isEmpty:0===t.length,isLoading:!1})},function(){var e=a.state;a.cache.set(i,{data:a.state.data,firstPage:e.firstPage,isEmpty:e.isEmpty,isLoading:e.isLoading,pageData:e.pageData,unappliedFilters:e.unappliedFilters,meta:e.meta,page:e.page,pageSize:e.pageSize,search:e.search,filters:e.filters})})}).catch(function(e){console.error("Init table context error: ",e),a.props.onError(e),a.setState({error:e,isLoading:!1})})})},this.setSearch=function(e){a.setState({search:e,page:0},function(){return a.handleUpdate()})},this.setPage=function(e){a.setState({page:e},function(){return a.handleUpdate()})},this.setPageSize=function(e){a.setState({pageSize:e},function(){return a.handleUpdate()})},this.setSelected=function(e){a.setState({selected:e})},this.toggleSelectAll=function(e){var t=a.state,i=t.data,r=t.selected,s=i.every(function(e){var t=e.id;return r.some(function(e){return e.id===t})})?r.filter(function(e){var t=e.id;return!i.some(function(e){return e.id===t})}):r.concat(i),n=s.filter(function(e,t){var a=e.id;return s.findIndex(function(e){return e.id===a})===t}),o=e?n.map(function(t){return Object.assign({},t,{tableName:t.tableName||e})}):n;a.setState({selected:o})},this.setFilters=function(e,t){void 0===t&&(t=!1),a.setState({filters:e,unappliedFilters:e,page:0,data:t?[]:a.state.data},function(){return a.handleUpdate()})},this.setUnappliedFilters=function(e){a.setState({unappliedFilters:e})},this.applyFilters=function(){a.setFilters(a.state.unappliedFilters)},this.setSorting=function(e){a.setState({sorting:e},function(){return a.handleUpdate()})},this.refresh=function(){a.handleUpdate()},this.state={page:0,pageSize:10,firstPage:!0,isLoading:!1,isEmpty:!0,data:[],meta:{},error:null,filters:{},unappliedFilters:{},sorting:{},pageData:[],selected:[],search:""},this.key=i(Date.now()),this.cache=new Map}return t&&(n.__proto__=t),(n.prototype=Object.create(t&&t.prototype)).constructor=n,n.prototype.componentDidMount=function(){var e=this,t=this.props;this.setState({pageSize:t.pageSize,filters:t.filters,selected:t.selected},function(){return e.handleUpdate()})},n.prototype.componentDidUpdate=function(e){var t=this.props,a=t.selected,i=t.filters,s=t.autoApplyFilters;this.checkIfSame(a,e.selected)||this.setState({selected:a}),s&&!r.deepEqual(i,e.filters)&&this.setFilters(i,!0)},n.prototype.render=function(){var e=Object.assign({},this.state,{setSearch:this.setSearch,setPage:this.setPage,setSorting:this.setSorting,setPageSize:this.setPageSize,refresh:this.refresh,setSelected:this.setSelected,toggleSelectAll:this.toggleSelectAll,setFilters:this.setFilters,setUnappliedFilters:this.setUnappliedFilters,applyFilters:this.applyFilters});return a.createElement(s.Provider,{value:e},this.props.children)},n}(t.Component);return n.defaultProps={onError:console.error,pageSize:10,filters:{},selected:[],getCacheKey:function(e){return i(e)}},[n,s.Consumer]}; | ||
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } | ||
var React = require('react'); | ||
var React__default = _interopDefault(React); | ||
var hash = _interopDefault(require('hash-sum')); | ||
var fastEquals = require('fast-equals'); | ||
var debounce = _interopDefault(require('lodash.debounce')); | ||
function _extends() { | ||
_extends = Object.assign || function (target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = arguments[i]; | ||
for (var key in source) { | ||
if (Object.prototype.hasOwnProperty.call(source, key)) { | ||
target[key] = source[key]; | ||
} | ||
} | ||
} | ||
return target; | ||
}; | ||
return _extends.apply(this, arguments); | ||
} | ||
function _inheritsLoose(subClass, superClass) { | ||
subClass.prototype = Object.create(superClass.prototype); | ||
subClass.prototype.constructor = subClass; | ||
subClass.__proto__ = superClass; | ||
} | ||
function _catch(body, recover) { | ||
try { | ||
var result = body(); | ||
} catch (e) { | ||
return recover(e); | ||
} | ||
if (result && result.then) { | ||
return result.then(void 0, recover); | ||
} | ||
return result; | ||
} | ||
var DEFAULT_SEARCH_WAIT = 500; | ||
function initTableContext(requestData) { | ||
if (requestData === void 0) { | ||
requestData = function requestData() { | ||
return Promise.resolve([]); | ||
}; | ||
} | ||
var TableContext = React.createContext(); | ||
var TableProvider = /*#__PURE__*/function (_Component) { | ||
_inheritsLoose(TableProvider, _Component); | ||
function TableProvider(props) { | ||
var _this; | ||
_this = _Component.call(this, props) || this; | ||
_this.checkIfSame = function (selected, prevSelected) { | ||
return selected.every(function (_ref) { | ||
var id = _ref.id; | ||
return prevSelected.some(function (s) { | ||
return s.id === id; | ||
}); | ||
}) && prevSelected.every(function (_ref2) { | ||
var id = _ref2.id; | ||
return selected.some(function (s) { | ||
return s.id === id; | ||
}); | ||
}); | ||
}; | ||
_this.handleUpdate = function (newValues) { | ||
var _this$state$newValues = _extends({}, _this.state, newValues), | ||
page = _this$state$newValues.page, | ||
pageSize = _this$state$newValues.pageSize, | ||
search = _this$state$newValues.search, | ||
filters = _this$state$newValues.filters, | ||
sorting = _this$state$newValues.sorting; | ||
var getCacheKey = _this.props.getCacheKey; | ||
var key = getCacheKey({ | ||
page: page, | ||
pageSize: pageSize, | ||
search: search, | ||
filters: filters, | ||
sorting: sorting, | ||
key: _this.key | ||
}); | ||
var now = new Date(); | ||
_this.latestRequestTime = now; | ||
if (_this.cache.has(key)) { | ||
var newState = _this.cache.get(key); | ||
_this.setState(_extends({}, newState, newValues)); | ||
} else { | ||
_this.setState(_extends({ | ||
isLoading: true | ||
}, newValues), function () { | ||
return _this.getData(_extends({}, _this.state, newValues), key, now); | ||
}); | ||
} | ||
}; | ||
_this.getData = debounce(function (values, key, now) { | ||
try { | ||
return Promise.resolve(_catch(function () { | ||
return Promise.resolve(requestData(values)).then(function (response) { | ||
if (_this.latestRequestTime !== now) return; | ||
var data = []; | ||
var meta = {}; | ||
if (response.data && response.meta) { | ||
data = response.data; | ||
meta = response.meta; | ||
} else { | ||
data = response; | ||
meta = { | ||
count: data.length | ||
}; | ||
} | ||
if (!Array.isArray(data)) { | ||
throw new Error("Invalid data provided. Expected array, but got " + typeof data); | ||
} | ||
_this.setState(function (currentState) { | ||
var start = currentState.page * currentState.pageSize; | ||
var end = start + currentState.pageSize; | ||
return _extends({}, currentState, { | ||
data: data, | ||
meta: meta, | ||
firstPage: currentState.page === 0, | ||
pageData: data.slice(start, end), | ||
isEmpty: data.length === 0, | ||
isLoading: false | ||
}); | ||
}, function () { | ||
var _this$state = _this.state, | ||
firstPage = _this$state.firstPage, | ||
isEmpty = _this$state.isEmpty, | ||
isLoading = _this$state.isLoading, | ||
pageData = _this$state.pageData, | ||
unappliedFilters = _this$state.unappliedFilters, | ||
meta = _this$state.meta, | ||
page = _this$state.page, | ||
pageSize = _this$state.pageSize, | ||
search = _this$state.search, | ||
filters = _this$state.filters; | ||
_this.cache.set(key, { | ||
data: _this.state.data, | ||
firstPage: firstPage, | ||
isEmpty: isEmpty, | ||
isLoading: isLoading, | ||
pageData: pageData, | ||
unappliedFilters: unappliedFilters, | ||
meta: meta, | ||
page: page, | ||
pageSize: pageSize, | ||
search: search, | ||
filters: filters | ||
}); | ||
}); | ||
}); | ||
}, function (error) { | ||
console.error('Init table context error: ', error); | ||
_this.props.onError(error); | ||
_this.setState({ | ||
error: error, | ||
isLoading: false | ||
}); | ||
})); | ||
} catch (e) { | ||
return Promise.reject(e); | ||
} | ||
}, _this.props.searchWait || DEFAULT_SEARCH_WAIT); | ||
_this.setSearch = function (search) { | ||
return _this.handleUpdate({ | ||
search: search, | ||
page: 0 | ||
}); | ||
}; | ||
_this.setPage = function (page) { | ||
return _this.handleUpdate({ | ||
page: page | ||
}); | ||
}; | ||
_this.setPageSize = function (pageSize) { | ||
return _this.handleUpdate({ | ||
pageSize: pageSize | ||
}); | ||
}; | ||
_this.clearCache = function () { | ||
return _this.cache = new Map(); | ||
}; | ||
_this.setSelected = function (selected) { | ||
// NOTE: We do not want to refresh table if an item becomes selected. | ||
_this.setState({ | ||
selected: selected | ||
}); | ||
}; | ||
_this.toggleSelectAll = function (type) { | ||
var _this$state2 = _this.state, | ||
data = _this$state2.data, | ||
currentSelection = _this$state2.selected; | ||
var mustRemoveAll = data.every(function (_ref3) { | ||
var id = _ref3.id; | ||
return currentSelection.some(function (s) { | ||
return s.id === id; | ||
}); | ||
}); | ||
var checkedRows = mustRemoveAll ? currentSelection.filter(function (_ref4) { | ||
var id = _ref4.id; | ||
return !data.some(function (d) { | ||
return d.id === id; | ||
}); | ||
}) : [].concat(currentSelection, data); | ||
var filteredRows = checkedRows.filter(function (_ref5, index) { | ||
var id = _ref5.id; | ||
return checkedRows.findIndex(function (r) { | ||
return r.id === id; | ||
}) === index; | ||
}); | ||
var selected = type ? filteredRows.map(function (row) { | ||
return _extends({}, row, { | ||
tableName: row.tableName || type | ||
}); | ||
}) : filteredRows; | ||
_this.setState({ | ||
selected: selected | ||
}); | ||
}; | ||
_this.setFilters = function (filters, clearData) { | ||
if (clearData === void 0) { | ||
clearData = false; | ||
} | ||
var data = _this.state.data; | ||
_this.handleUpdate({ | ||
filters: filters, | ||
unappliedFilters: filters, | ||
page: 0, | ||
data: clearData ? [] : data | ||
}); | ||
}; | ||
_this.setUnappliedFilters = function (filters) { | ||
_this.setState({ | ||
unappliedFilters: filters | ||
}); | ||
}; | ||
_this.applyFilters = function () { | ||
var unappliedFilters = _this.state.unappliedFilters; | ||
_this.setFilters(unappliedFilters); | ||
}; | ||
_this.setSorting = function (sorting) { | ||
return _this.handleUpdate({ | ||
sorting: sorting | ||
}); | ||
}; | ||
_this.refresh = function () { | ||
_this.handleUpdate(); | ||
}; | ||
_this.state = { | ||
page: 0, | ||
pageSize: 10, | ||
firstPage: true, | ||
isLoading: false, | ||
isEmpty: true, | ||
data: [], | ||
meta: {}, | ||
error: null, | ||
filters: {}, | ||
unappliedFilters: {}, | ||
sorting: {}, | ||
pageData: [], | ||
selected: [], | ||
search: '' | ||
}; | ||
_this.key = hash(Date.now()); | ||
_this.cache = new Map(); | ||
return _this; | ||
} | ||
var _proto = TableProvider.prototype; | ||
_proto.componentDidMount = function componentDidMount() { | ||
var _this$props = this.props, | ||
pageSize = _this$props.pageSize, | ||
filters = _this$props.filters, | ||
selected = _this$props.selected; | ||
this.handleUpdate({ | ||
pageSize: pageSize, | ||
filters: filters, | ||
selected: selected | ||
}); | ||
}; | ||
_proto.componentDidUpdate = function componentDidUpdate(prevProps) { | ||
var _this$props2 = this.props, | ||
selected = _this$props2.selected, | ||
filters = _this$props2.filters, | ||
autoApplyFilters = _this$props2.autoApplyFilters; | ||
var isSame = this.checkIfSame(selected, prevProps.selected); | ||
if (!isSame) this.setState({ | ||
selected: selected | ||
}); | ||
var shouldApplyFilters = autoApplyFilters && !fastEquals.deepEqual(filters, prevProps.filters); | ||
if (shouldApplyFilters) this.setFilters(filters, true); | ||
}; | ||
_proto.render = function render() { | ||
var value = _extends({}, this.state, { | ||
setSearch: this.setSearch, | ||
setPage: this.setPage, | ||
setSorting: this.setSorting, | ||
setPageSize: this.setPageSize, | ||
refresh: this.refresh, | ||
setSelected: this.setSelected, | ||
toggleSelectAll: this.toggleSelectAll, | ||
setFilters: this.setFilters, | ||
setUnappliedFilters: this.setUnappliedFilters, | ||
applyFilters: this.applyFilters, | ||
clearCache: this.clearCache | ||
}); | ||
return /*#__PURE__*/React__default.createElement(TableContext.Provider, { | ||
value: value | ||
}, this.props.children); | ||
}; | ||
return TableProvider; | ||
}(React.Component); | ||
TableProvider.defaultProps = { | ||
onError: console.error, | ||
pageSize: 10, | ||
filters: {}, | ||
selected: [], | ||
getCacheKey: function getCacheKey(state) { | ||
return hash(state); | ||
} | ||
}; | ||
return [TableProvider, TableContext.Consumer]; | ||
} | ||
module.exports = initTableContext; |
{ | ||
"name": "@lessondesk/react-table-context", | ||
"description": "Flexible Table Provider & Consumer", | ||
"version": "1.1.0", | ||
"version": "1.2.0", | ||
"main": "dist/react-table-context.js", | ||
@@ -31,3 +31,3 @@ "source": "src/index.js", | ||
"babel-eslint": "^10.0.3", | ||
"microbundle": "^0.11.0", | ||
"microbundle": "^0.12.2", | ||
"standard": "^14.3.1" | ||
@@ -37,3 +37,4 @@ }, | ||
"fast-equals": "^2.0.0", | ||
"hash-sum": "^2.0.0" | ||
"hash-sum": "^2.0.0", | ||
"lodash.debounce": "^4.0.8" | ||
}, | ||
@@ -40,0 +41,0 @@ "standard": { |
199
src/index.js
import React, { createContext, Component } from 'react' | ||
import hash from 'hash-sum' | ||
import { deepEqual } from 'fast-equals' | ||
import debounce from 'lodash.debounce' | ||
export default function initTableContext(getData = () => Promise.resolve([])) { | ||
const DEFAULT_SEARCH_WAIT = 500 | ||
export default function initTableContext(requestData = () => Promise.resolve([])) { | ||
const TableContext = createContext() | ||
class TableProvider extends Component { | ||
constructor() { | ||
super() | ||
constructor(props) { | ||
super(props) | ||
this.state = { | ||
@@ -42,3 +45,3 @@ page: 0, | ||
const { pageSize, filters, selected } = this.props | ||
this.setState({ pageSize, filters, selected }, () => this.handleUpdate()) | ||
this.handleUpdate({ pageSize, filters, selected }) | ||
} | ||
@@ -60,6 +63,6 @@ | ||
handleUpdate = () => { | ||
const { meta, page, pageSize, search, filters, sorting } = this.state | ||
const key = this.props.getCacheKey({ | ||
meta, | ||
handleUpdate = (newValues) => { | ||
const { page, pageSize, search, filters, sorting } = { ...this.state, ...newValues } | ||
const { getCacheKey } = this.props | ||
const key = getCacheKey({ | ||
page, | ||
@@ -73,94 +76,98 @@ pageSize, | ||
const now = new Date() | ||
this.latestRequestTime = now | ||
if (this.cache.has(key)) { | ||
const newState = this.cache.get(key) | ||
this.setState({ ...newState }) | ||
this.setState({ ...newState, ...newValues }) | ||
} else { | ||
this.setState({ isLoading: true }, () => { | ||
getData({ ...this.state }) | ||
.then(response => { | ||
let data = [] | ||
let meta = {} | ||
this.setState( | ||
{ isLoading: true, ...newValues }, | ||
() => this.getData({ ...this.state, ...newValues }, key, now) | ||
) | ||
} | ||
} | ||
if (response.data && response.meta) { | ||
data = response.data | ||
meta = response.meta | ||
} else { | ||
data = response | ||
meta = { count: data.length } | ||
} | ||
getData = debounce(async (values, key, now) => { | ||
try { | ||
const response = await requestData(values) | ||
if (this.latestRequestTime !== now) return | ||
let data = [] | ||
let meta = {} | ||
if (!Array.isArray(data)) { | ||
throw new Error( | ||
`Invalid data provided. Expected array, but got ${typeof data}` | ||
) | ||
} | ||
if (response.data && response.meta) { | ||
data = response.data | ||
meta = response.meta | ||
} else { | ||
data = response | ||
meta = { count: data.length } | ||
} | ||
this.setState( | ||
currentState => { | ||
const start = currentState.page * currentState.pageSize | ||
const end = start + currentState.pageSize | ||
if (!Array.isArray(data)) { | ||
throw new Error( | ||
`Invalid data provided. Expected array, but got ${typeof data}` | ||
) | ||
} | ||
return { | ||
...currentState, | ||
data, | ||
meta, | ||
firstPage: currentState.page === 0, | ||
pageData: data.slice(start, end), | ||
isEmpty: data.length === 0, | ||
isLoading: false | ||
} | ||
}, | ||
() => { | ||
const { | ||
firstPage, | ||
isEmpty, | ||
isLoading, | ||
pageData, | ||
unappliedFilters, | ||
meta, | ||
page, | ||
pageSize, | ||
search, | ||
filters | ||
} = this.state | ||
this.setState( | ||
currentState => { | ||
const start = currentState.page * currentState.pageSize | ||
const end = start + currentState.pageSize | ||
this.cache.set(key, { | ||
data: this.state.data, | ||
firstPage, | ||
isEmpty, | ||
isLoading, | ||
pageData, | ||
unappliedFilters, | ||
meta, | ||
page, | ||
pageSize, | ||
search, | ||
filters | ||
}) | ||
} | ||
) | ||
return { | ||
...currentState, | ||
data, | ||
meta, | ||
firstPage: currentState.page === 0, | ||
pageData: data.slice(start, end), | ||
isEmpty: data.length === 0, | ||
isLoading: false | ||
} | ||
}, | ||
() => { | ||
const { | ||
firstPage, | ||
isEmpty, | ||
isLoading, | ||
pageData, | ||
unappliedFilters, | ||
meta, | ||
page, | ||
pageSize, | ||
search, | ||
filters | ||
} = this.state | ||
this.cache.set(key, { | ||
data: this.state.data, | ||
firstPage, | ||
isEmpty, | ||
isLoading, | ||
pageData, | ||
unappliedFilters, | ||
meta, | ||
page, | ||
pageSize, | ||
search, | ||
filters | ||
}) | ||
.catch(error => { | ||
console.error('Init table context error: ', error) | ||
this.props.onError(error) | ||
this.setState({ error, isLoading: false }) | ||
}) | ||
}) | ||
} | ||
) | ||
} catch (error) { | ||
console.error('Init table context error: ', error) | ||
this.props.onError(error) | ||
this.setState({ error, isLoading: false }) | ||
} | ||
}; | ||
}, this.props.searchWait || DEFAULT_SEARCH_WAIT) | ||
setSearch = search => { | ||
this.setState({ search, page: 0 }, () => this.handleUpdate()) | ||
}; | ||
setSearch = search => this.handleUpdate({ search, page: 0 }); | ||
setPage = page => { | ||
this.setState({ page }, () => this.handleUpdate()) | ||
}; | ||
setPage = page => this.handleUpdate({ page }); | ||
setPageSize = pageSize => { | ||
this.setState({ pageSize }, () => this.handleUpdate()) | ||
}; | ||
setPageSize = pageSize => this.handleUpdate({ pageSize }); | ||
clearCache = () => this.cache = new Map(); | ||
setSelected = selected => { | ||
// NOTE: We do not want to refresh table if a item becomes selected. | ||
// NOTE: We do not want to refresh table if an item becomes selected. | ||
this.setState({ selected }) | ||
@@ -193,11 +200,8 @@ }; | ||
const { data } = this.state | ||
this.setState( | ||
{ | ||
filters, | ||
unappliedFilters: filters, | ||
page: 0, | ||
data: clearData ? [] : data | ||
}, | ||
() => this.handleUpdate() | ||
) | ||
this.handleUpdate({ | ||
filters, | ||
unappliedFilters: filters, | ||
page: 0, | ||
data: clearData ? [] : data | ||
}) | ||
}; | ||
@@ -216,5 +220,3 @@ | ||
setSorting = sorting => { | ||
this.setState({ sorting }, () => this.handleUpdate()) | ||
}; | ||
setSorting = sorting => this.handleUpdate({ sorting }); | ||
@@ -237,3 +239,4 @@ refresh = () => { | ||
setUnappliedFilters: this.setUnappliedFilters, | ||
applyFilters: this.applyFilters | ||
applyFilters: this.applyFilters, | ||
clearCache: this.clearCache | ||
} | ||
@@ -240,0 +243,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
25634
609
1
3
2
+ Addedlodash.debounce@^4.0.8
+ Addedlodash.debounce@4.0.8(transitive)