UNPKG

9.59 kBJavaScriptView Raw
1var __extends = (this && this.__extends) || (function () {
2 var extendStatics = function (d, b) {
3 extendStatics = Object.setPrototypeOf ||
4 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
5 function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
6 return extendStatics(d, b);
7 };
8 return function (d, b) {
9 extendStatics(d, b);
10 function __() { this.constructor = d; }
11 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
12 };
13})();
14import { observable, reaction, observe, transaction, ObservableMap, } from "mobx";
15/**
16 * Reactively sorts a base observable array into multiple observable arrays based on the value of a
17 * `groupBy: (item: T) => G` function.
18 *
19 * This observes the individual computed groupBy values and only updates the source and dest arrays
20 * when there is an actual change, so this is far more efficient than, for example
21 * `base.filter(i => groupBy(i) === 'we')`. Call #dispose() to stop tracking.
22 *
23 * No guarantees are made about the order of items in the grouped arrays.
24 *
25 * The resulting map of arrays is read-only. clear(), set(), delete() are not supported and
26 * modifying the group arrays will lead to undefined behavior.
27 *
28 * NB: ObservableGroupMap relies on `Symbol`s. If you are targeting a platform which doesn't
29 * support these natively, you will need to provide a polyfill.
30 *
31 * @param {array} base The array to sort into groups.
32 * @param {function} groupBy The function used for grouping.
33 * @param options Object with properties:
34 * `name`: Debug name of this ObservableGroupMap.
35 * `keyToName`: Function to create the debug names of the observable group arrays.
36 *
37 * @example
38 * const slices = observable([
39 * { day: "mo", hours: 12 },
40 * { day: "tu", hours: 2 },
41 * ])
42 * const slicesByDay = new ObservableGroupMap(slices, (slice) => slice.day)
43 * autorun(() => console.log(
44 * slicesByDay.get("mo")?.length ?? 0,
45 * slicesByDay.get("we"))) // outputs 1, undefined
46 * slices[0].day = "we" // outputs 0, [{ day: "we", hours: 12 }]
47 */
48var ObservableGroupMap = /** @class */ (function (_super) {
49 __extends(ObservableGroupMap, _super);
50 function ObservableGroupMap(base, groupBy, _a) {
51 var _b = _a === void 0 ? {} : _a, _c = _b.name, name = _c === void 0 ? "ogm" + ((Math.random() * 1000) | 0) : _c, _d = _b.keyToName, keyToName = _d === void 0 ? function (x) { return "" + x; } : _d;
52 var _this = _super.call(this) || this;
53 /**
54 * Base observable array which is being sorted into groups.
55 */
56 Object.defineProperty(_this, "_base", {
57 enumerable: true,
58 configurable: true,
59 writable: true,
60 value: void 0
61 });
62 /**
63 * The ObservableGroupMap needs to track some state per-item. This is the name/symbol of the
64 * property used to attach the state.
65 */
66 Object.defineProperty(_this, "_ogmInfoKey", {
67 enumerable: true,
68 configurable: true,
69 writable: true,
70 value: void 0
71 });
72 /**
73 * The function used to group the items.
74 */
75 Object.defineProperty(_this, "_groupBy", {
76 enumerable: true,
77 configurable: true,
78 writable: true,
79 value: void 0
80 });
81 /**
82 * This function is used to generate the mobx debug names of the observable group arrays.
83 */
84 Object.defineProperty(_this, "_keyToName", {
85 enumerable: true,
86 configurable: true,
87 writable: true,
88 value: void 0
89 });
90 Object.defineProperty(_this, "_disposeBaseObserver", {
91 enumerable: true,
92 configurable: true,
93 writable: true,
94 value: void 0
95 });
96 _this._keyToName = keyToName;
97 _this._groupBy = groupBy;
98 _this._ogmInfoKey = Symbol("ogmInfo" + name);
99 _this._base = base;
100 for (var i = 0; i < base.length; i++) {
101 _this._addItem(base[i]);
102 }
103 _this._disposeBaseObserver = observe(_this._base, function (change) {
104 if ("splice" === change.type) {
105 transaction(function () {
106 for (var _i = 0, _a = change.removed; _i < _a.length; _i++) {
107 var removed = _a[_i];
108 _this._removeItem(removed);
109 }
110 for (var _b = 0, _c = change.added; _b < _c.length; _b++) {
111 var added = _c[_b];
112 _this._addItem(added);
113 }
114 });
115 }
116 else if ("update" === change.type) {
117 transaction(function () {
118 _this._removeItem(change.oldValue);
119 _this._addItem(change.newValue);
120 });
121 }
122 else {
123 throw new Error("illegal state");
124 }
125 });
126 return _this;
127 }
128 Object.defineProperty(ObservableGroupMap.prototype, "clear", {
129 enumerable: false,
130 configurable: true,
131 writable: true,
132 value: function () {
133 throw new Error("not supported");
134 }
135 });
136 Object.defineProperty(ObservableGroupMap.prototype, "delete", {
137 enumerable: false,
138 configurable: true,
139 writable: true,
140 value: function (_key) {
141 throw new Error("not supported");
142 }
143 });
144 Object.defineProperty(ObservableGroupMap.prototype, "set", {
145 enumerable: false,
146 configurable: true,
147 writable: true,
148 value: function (_key, _value) {
149 throw new Error("not supported");
150 }
151 });
152 /**
153 * Disposes all observers created during construction and removes state added to base array
154 * items.
155 */
156 Object.defineProperty(ObservableGroupMap.prototype, "dispose", {
157 enumerable: false,
158 configurable: true,
159 writable: true,
160 value: function () {
161 this._disposeBaseObserver();
162 for (var i = 0; i < this._base.length; i++) {
163 var item = this._base[i];
164 var grouperItemInfo = item[this._ogmInfoKey];
165 grouperItemInfo.reaction();
166 delete item[this._ogmInfoKey];
167 }
168 }
169 });
170 Object.defineProperty(ObservableGroupMap.prototype, "_getGroupArr", {
171 enumerable: false,
172 configurable: true,
173 writable: true,
174 value: function (key) {
175 var result = _super.prototype.get.call(this, key);
176 if (undefined === result) {
177 result = observable([], { name: "GroupArray[" + this._keyToName(key) + "]", deep: false });
178 _super.prototype.set.call(this, key, result);
179 }
180 return result;
181 }
182 });
183 Object.defineProperty(ObservableGroupMap.prototype, "_removeFromGroupArr", {
184 enumerable: false,
185 configurable: true,
186 writable: true,
187 value: function (key, itemIndex) {
188 var arr = _super.prototype.get.call(this, key);
189 if (1 === arr.length) {
190 _super.prototype.delete.call(this, key);
191 }
192 else if (itemIndex === arr.length - 1) {
193 // last position in array
194 arr.length--;
195 }
196 else {
197 arr[itemIndex] = arr[arr.length - 1];
198 arr[itemIndex][this._ogmInfoKey].groupArrIndex = itemIndex;
199 arr.length--;
200 }
201 }
202 });
203 Object.defineProperty(ObservableGroupMap.prototype, "_addItem", {
204 enumerable: false,
205 configurable: true,
206 writable: true,
207 value: function (item) {
208 var _this = this;
209 var groupByValue = this._groupBy(item);
210 var groupArr = this._getGroupArr(groupByValue);
211 var value = {
212 groupByValue: groupByValue,
213 groupArrIndex: groupArr.length,
214 reaction: reaction(function () { return _this._groupBy(item); }, function (newGroupByValue, _r) {
215 var grouperItemInfo = item[_this._ogmInfoKey];
216 _this._removeFromGroupArr(grouperItemInfo.groupByValue, grouperItemInfo.groupArrIndex);
217 var newGroupArr = _this._getGroupArr(newGroupByValue);
218 var newGroupArrIndex = newGroupArr.length;
219 newGroupArr.push(item);
220 grouperItemInfo.groupByValue = newGroupByValue;
221 grouperItemInfo.groupArrIndex = newGroupArrIndex;
222 }),
223 };
224 Object.defineProperty(item, this._ogmInfoKey, {
225 configurable: true,
226 enumerable: false,
227 value: value,
228 });
229 groupArr.push(item);
230 }
231 });
232 Object.defineProperty(ObservableGroupMap.prototype, "_removeItem", {
233 enumerable: false,
234 configurable: true,
235 writable: true,
236 value: function (item) {
237 var grouperItemInfo = item[this._ogmInfoKey];
238 this._removeFromGroupArr(grouperItemInfo.groupByValue, grouperItemInfo.groupArrIndex);
239 grouperItemInfo.reaction();
240 delete item[this._ogmInfoKey];
241 }
242 });
243 return ObservableGroupMap;
244}(ObservableMap));
245export { ObservableGroupMap };