@bento-core/facet-filter 1.0.1-c3dc.6 → 1.0.1-c3dc.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,41 +4,128 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _react = _interopRequireDefault(require("react"));
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _core = require("@material-ui/core");
8
9
  var _ReduxCheckbox = _interopRequireDefault(require("./checkbox/ReduxCheckbox"));
9
10
  var _ReduxSlider = _interopRequireDefault(require("./slider/ReduxSlider"));
10
11
  var _Types = require("./Types");
11
12
  var _Sort = require("../../utils/Sort");
13
+ var _FilterItemStyle = _interopRequireDefault(require("./FilterItemStyle"));
12
14
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
16
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
13
17
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
14
18
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
15
19
  function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
16
20
  function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
17
21
  function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
22
+ const INITIAL_ITEM_SIZE = 20;
18
23
  const FilterItems = _ref => {
19
24
  let {
20
25
  facet,
21
- sortBy
26
+ sortBy = null,
27
+ classes
22
28
  } = _ref;
23
29
  const {
24
30
  type,
25
31
  datafield,
26
32
  section
27
33
  } = facet;
34
+ const [displayCount, setDisplayCount] = (0, _react.useState)(INITIAL_ITEM_SIZE);
35
+ const scrollableRef = (0, _react.useRef)(null);
28
36
  const sortFilters = (0, _Sort.sortBySection)(_objectSpread(_objectSpread({}, facet), {}, {
29
37
  sortBy
30
38
  }));
39
+
40
+ // Memoized scroll handler
41
+ const handleScroll = (0, _react.useCallback)(uncheckedCount => e => {
42
+ if (displayCount < uncheckedCount && uncheckedCount > INITIAL_ITEM_SIZE) {
43
+ const {
44
+ scrollTop,
45
+ scrollHeight,
46
+ clientHeight
47
+ } = e.target;
48
+ if (scrollHeight > clientHeight) {
49
+ const position = Math.ceil(scrollTop / (scrollHeight - clientHeight) * 100);
50
+ if (position >= 90) {
51
+ setDisplayCount(prevCount => prevCount + INITIAL_ITEM_SIZE);
52
+ }
53
+ }
54
+ }
55
+ }, [displayCount]);
31
56
  const filterItems = () => {
32
57
  switch (type) {
33
58
  case _Types.InputTypes.CHECKBOX:
34
- return sortFilters.map((item, index) => /*#__PURE__*/_react.default.createElement(_ReduxCheckbox.default, {
35
- checkboxItem: _objectSpread(_objectSpread({}, item), {}, {
36
- index,
37
- section
38
- }),
39
- datafield: datafield,
40
- facet: facet
41
- }));
59
+ {
60
+ // Only use lazy loading if we have more items than the initial size
61
+ const uncheckedCount = sortFilters.filter(item => !item.isChecked).length;
62
+ if (uncheckedCount <= INITIAL_ITEM_SIZE) {
63
+ // Render all items normally if below threshold
64
+ return sortFilters.map((item, index) => /*#__PURE__*/_react.default.createElement(_ReduxCheckbox.default, {
65
+ key: "all-".concat(item.name, "-").concat(index),
66
+ checkboxItem: _objectSpread(_objectSpread({}, item), {}, {
67
+ index,
68
+ section
69
+ }),
70
+ datafield: datafield,
71
+ facet: facet
72
+ }));
73
+ }
74
+
75
+ // Single pass: separate checked and unchecked items with their indices - O(n) complexity
76
+ const checkedItemsWithIndices = [];
77
+ const uncheckedItemsWithIndices = [];
78
+ sortFilters.forEach((item, originalIndex) => {
79
+ if (item.isChecked) {
80
+ checkedItemsWithIndices.push({
81
+ item,
82
+ originalIndex
83
+ });
84
+ } else {
85
+ uncheckedItemsWithIndices.push({
86
+ item,
87
+ originalIndex
88
+ });
89
+ }
90
+ });
91
+
92
+ // Always show checked items first
93
+ const checkedItems = checkedItemsWithIndices.map(_ref2 => {
94
+ let {
95
+ item,
96
+ originalIndex
97
+ } = _ref2;
98
+ return /*#__PURE__*/_react.default.createElement(_ReduxCheckbox.default, {
99
+ key: "checked-".concat(item.name, "-").concat(originalIndex),
100
+ checkboxItem: _objectSpread(_objectSpread({}, item), {}, {
101
+ index: originalIndex,
102
+ section
103
+ }),
104
+ datafield: datafield,
105
+ facet: facet
106
+ });
107
+ });
108
+ const uncheckedItems = uncheckedItemsWithIndices.slice(0, displayCount).map(_ref3 => {
109
+ let {
110
+ item,
111
+ originalIndex
112
+ } = _ref3;
113
+ return /*#__PURE__*/_react.default.createElement(_ReduxCheckbox.default, {
114
+ key: "unchecked-".concat(item.name, "-").concat(originalIndex),
115
+ checkboxItem: _objectSpread(_objectSpread({}, item), {}, {
116
+ index: originalIndex,
117
+ section
118
+ }),
119
+ datafield: datafield,
120
+ facet: facet
121
+ });
122
+ });
123
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("div", null, checkedItems), /*#__PURE__*/_react.default.createElement("div", {
124
+ ref: scrollableRef,
125
+ className: classes.itemsContainer,
126
+ onScroll: handleScroll(uncheckedItemsWithIndices.length)
127
+ }, uncheckedItems));
128
+ }
42
129
  case _Types.InputTypes.SLIDER:
43
130
  return /*#__PURE__*/_react.default.createElement(_ReduxSlider.default, {
44
131
  facet: facet
@@ -47,7 +134,13 @@ const FilterItems = _ref => {
47
134
  return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null);
48
135
  }
49
136
  };
137
+ (0, _react.useEffect)(() => {
138
+ setDisplayCount(INITIAL_ITEM_SIZE);
139
+ if (scrollableRef.current) {
140
+ scrollableRef.current.scrollTo(0, 0);
141
+ }
142
+ }, [sortBy]);
50
143
  return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, filterItems());
51
144
  };
52
- var _default = FilterItems;
145
+ var _default = (0, _core.withStyles)(_FilterItemStyle.default)(FilterItems);
53
146
  exports.default = _default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bento-core/facet-filter",
3
- "version": "1.0.1-c3dc.6",
3
+ "version": "1.0.1-c3dc.7",
4
4
  "description": "### Bento core sidebar design:",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -1,28 +1,105 @@
1
1
  /* eslint-disable react/jsx-wrap-multilines */
2
2
  /* eslint-disable react/jsx-indent */
3
- import React from 'react';
3
+ import React,
4
+ {
5
+ useEffect, useState, useRef, useCallback,
6
+ } from 'react';
7
+ import { withStyles } from '@material-ui/core';
4
8
  import ReduxCheckbox from './checkbox/ReduxCheckbox';
5
9
  import ReduxSlider from './slider/ReduxSlider';
6
10
  import { InputTypes } from './Types';
7
11
  import { sortBySection } from '../../utils/Sort';
12
+ import styles from './FilterItemStyle';
13
+
14
+ const INITIAL_ITEM_SIZE = 20;
8
15
 
9
16
  const FilterItems = ({
10
17
  facet,
11
- sortBy,
18
+ sortBy = null,
19
+ classes,
12
20
  }) => {
13
21
  const { type, datafield, section } = facet;
22
+ const [displayCount, setDisplayCount] = useState(INITIAL_ITEM_SIZE);
23
+ const scrollableRef = useRef(null);
14
24
  const sortFilters = sortBySection({ ...facet, sortBy });
15
25
 
26
+ // Memoized scroll handler
27
+ const handleScroll = useCallback((uncheckedCount) => (e) => {
28
+ if (displayCount < uncheckedCount && uncheckedCount > INITIAL_ITEM_SIZE) {
29
+ const { scrollTop, scrollHeight, clientHeight } = e.target;
30
+ if (scrollHeight > clientHeight) {
31
+ const position = Math.ceil((scrollTop / (scrollHeight - clientHeight)) * 100);
32
+ if (position >= 90) {
33
+ setDisplayCount((prevCount) => prevCount + INITIAL_ITEM_SIZE);
34
+ }
35
+ }
36
+ }
37
+ }, [displayCount]);
38
+
16
39
  const filterItems = () => {
17
40
  switch (type) {
18
- case InputTypes.CHECKBOX:
19
- return sortFilters.map((item, index) => (
41
+ case InputTypes.CHECKBOX: {
42
+ // Only use lazy loading if we have more items than the initial size
43
+ const uncheckedCount = sortFilters.filter((item) => !item.isChecked).length;
44
+ if (uncheckedCount <= INITIAL_ITEM_SIZE) {
45
+ // Render all items normally if below threshold
46
+ return sortFilters.map((item, index) => (
47
+ <ReduxCheckbox
48
+ key={`all-${item.name}-${index}`}
49
+ checkboxItem={{ ...item, index, section }}
50
+ datafield={datafield}
51
+ facet={facet}
52
+ />
53
+ ));
54
+ }
55
+
56
+ // Single pass: separate checked and unchecked items with their indices - O(n) complexity
57
+ const checkedItemsWithIndices = [];
58
+ const uncheckedItemsWithIndices = [];
59
+
60
+ sortFilters.forEach((item, originalIndex) => {
61
+ if (item.isChecked) {
62
+ checkedItemsWithIndices.push({ item, originalIndex });
63
+ } else {
64
+ uncheckedItemsWithIndices.push({ item, originalIndex });
65
+ }
66
+ });
67
+
68
+ // Always show checked items first
69
+ const checkedItems = checkedItemsWithIndices.map(({ item, originalIndex }) => (
20
70
  <ReduxCheckbox
21
- checkboxItem={{ ...item, index, section }}
71
+ key={`checked-${item.name}-${originalIndex}`}
72
+ checkboxItem={{ ...item, index: originalIndex, section }}
22
73
  datafield={datafield}
23
74
  facet={facet}
24
75
  />
25
76
  ));
77
+ const uncheckedItems = uncheckedItemsWithIndices
78
+ .slice(0, displayCount)
79
+ .map(({ item, originalIndex }) => (
80
+ <ReduxCheckbox
81
+ key={`unchecked-${item.name}-${originalIndex}`}
82
+ checkboxItem={{ ...item, index: originalIndex, section }}
83
+ datafield={datafield}
84
+ facet={facet}
85
+ />
86
+ ));
87
+
88
+ return (
89
+ <>
90
+ <div>
91
+ {checkedItems}
92
+ </div>
93
+ <div
94
+ ref={scrollableRef}
95
+ className={classes.itemsContainer}
96
+ onScroll={handleScroll(uncheckedItemsWithIndices.length)}
97
+ >
98
+ {uncheckedItems}
99
+ </div>
100
+ </>
101
+ );
102
+ }
26
103
  case InputTypes.SLIDER:
27
104
  return (<ReduxSlider facet={facet} />);
28
105
  default:
@@ -30,6 +107,13 @@ const FilterItems = ({
30
107
  }
31
108
  };
32
109
 
110
+ useEffect(() => {
111
+ setDisplayCount(INITIAL_ITEM_SIZE);
112
+ if (scrollableRef.current) {
113
+ scrollableRef.current.scrollTo(0, 0);
114
+ }
115
+ }, [sortBy]);
116
+
33
117
  return (
34
118
  <>
35
119
  {filterItems()}
@@ -37,4 +121,4 @@ const FilterItems = ({
37
121
  );
38
122
  };
39
123
 
40
- export default FilterItems;
124
+ export default withStyles(styles)(FilterItems);