@miso.ai/client-sdk-ui 1.10.0-beta.8 → 1.10.0

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.
Files changed (51) hide show
  1. package/dist/cjs/actor/index.js +0 -7
  2. package/dist/cjs/actor/tracker.js +47 -97
  3. package/dist/cjs/actor/utils.js +3 -1
  4. package/dist/cjs/actor/view.js +12 -1
  5. package/dist/cjs/actor/views.js +24 -2
  6. package/dist/cjs/affiliation/index.js +26 -10
  7. package/dist/cjs/asset/svgs.js +14 -4
  8. package/dist/cjs/constants.js +3 -2
  9. package/dist/cjs/layout/affiliation/affiliation.js +263 -13
  10. package/dist/cjs/layout/input/option-list.js +34 -49
  11. package/dist/cjs/layout/list/collection.js +24 -45
  12. package/dist/cjs/layout/templates.js +54 -32
  13. package/dist/cjs/layout/text/typewriter/index.js +12 -7
  14. package/dist/cjs/layout/trackable.js +124 -0
  15. package/dist/cjs/util/bindings.js +58 -110
  16. package/dist/cjs/util/states.js +31 -24
  17. package/dist/cjs/util/trackers.js +75 -0
  18. package/dist/cjs/util/viewables.js +55 -0
  19. package/dist/cjs/version.js +1 -1
  20. package/dist/cjs/workflow/ask.js +1 -2
  21. package/dist/cjs/workflow/base.js +2 -7
  22. package/dist/cjs/workflow/recommendation.js +2 -0
  23. package/package.json +2 -2
  24. package/src/actor/index.js +0 -1
  25. package/src/actor/tracker.js +37 -88
  26. package/src/actor/utils.js +3 -1
  27. package/src/actor/view.js +14 -1
  28. package/src/actor/views.js +30 -1
  29. package/src/affiliation/index.js +25 -8
  30. package/src/asset/svgs.js +13 -2
  31. package/src/constants.js +7 -1
  32. package/src/layout/affiliation/affiliation.js +247 -14
  33. package/src/layout/input/option-list.js +35 -43
  34. package/src/layout/list/collection.js +22 -40
  35. package/src/layout/templates.js +25 -19
  36. package/src/layout/text/typewriter/index.js +8 -6
  37. package/src/layout/trackable.js +106 -0
  38. package/src/util/bindings.js +47 -103
  39. package/src/util/states.js +26 -20
  40. package/src/util/trackers.js +69 -0
  41. package/src/util/viewables.js +47 -0
  42. package/src/version.js +1 -1
  43. package/src/workflow/ask.js +1 -2
  44. package/src/workflow/base.js +3 -5
  45. package/src/workflow/recommendation.js +1 -0
  46. package/dist/cjs/actor/trackers.js +0 -51
  47. package/dist/cjs/layout/text/typewriter/progress.js +0 -45
  48. package/dist/cjs/util/tracker.js +0 -348
  49. package/src/actor/trackers.js +0 -45
  50. package/src/layout/text/typewriter/progress.js +0 -33
  51. package/src/util/tracker.js +0 -318
@@ -4,10 +4,12 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
+ var _commons = require("@miso.ai/commons");
7
8
  var _constants = require("../../constants.js");
8
9
  var _collection = _interopRequireDefault(require("../list/collection.js"));
9
10
  var _templates = require("../templates.js");
10
- const _excluded = ["className", "templates"];
11
+ var _svgs = require("../../asset/svgs.js");
12
+ const _excluded = ["className", "templates", "autoplay"];
11
13
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
14
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.includes(n)) continue; t[n] = r[n]; } return t; }
13
15
  const TYPE = 'affiliation';
@@ -32,45 +34,134 @@ function ready(layout, state) {
32
34
  } = layout;
33
35
  const items = layout._getItems(state);
34
36
  if (items && items.length > 0) {
35
- return templates.body(layout, state);
37
+ return templates.controlContainer(layout, state, 'previous') + templates.body(layout, state) + templates.controlContainer(layout, state, 'next');
36
38
  } else {
37
39
  return templates.empty(layout, state);
38
40
  }
39
41
  }
42
+ function controlContainer(layout, state, direction) {
43
+ const {
44
+ className,
45
+ templates
46
+ } = layout;
47
+ return `<div class="${className}__control-${direction}-container">${templates.control(layout, state, direction)}</div>`;
48
+ }
49
+ function control(layout, state, direction) {
50
+ const {
51
+ className,
52
+ templates
53
+ } = layout;
54
+ return `<div class="${className}__control-${direction}" data-role="${direction}">${templates.controlIcon(layout, state, direction)}</div>`;
55
+ }
56
+ function controlIcon(layout, state, direction) {
57
+ return _svgs.TRIANGLE;
58
+ }
40
59
  function body(layout, state) {
41
60
  const {
42
61
  className,
43
62
  templates
44
63
  } = layout;
45
64
  const items = layout._getItems(state);
46
- return `<div class="${className}__body">${templates.header(layout, state)}${templates.list(layout, state, items)}</div>`;
65
+ return `<div class="${className}__body">${templates.list(layout, state, items)}</div>`;
66
+ }
67
+ function item(layout, state, value, index) {
68
+ const {
69
+ className,
70
+ templates,
71
+ options
72
+ } = layout;
73
+ const {
74
+ itemType
75
+ } = options;
76
+ const header = templates.itemHeader(layout, state, value, {
77
+ index
78
+ });
79
+ const body = templates[itemType](layout, state, value, {
80
+ index
81
+ });
82
+ return `<li class="${className}__item"><div class="${className}__item-inner">${header}${body}</div></li>`;
47
83
  }
48
- function header(layout, state) {
84
+ function itemHeader(layout, state, value, meta) {
49
85
  const {
50
86
  className,
51
87
  templates
52
88
  } = layout;
53
89
  let {
54
- headerText
90
+ itemHeaderLeftText,
91
+ itemHeaderRightText
55
92
  } = templates;
56
- if (typeof headerText === 'function') {
57
- headerText = headerText(layout, state);
58
- }
59
- if (!headerText) {
93
+ itemHeaderLeftText = _templates.helpers.asFunction(itemHeaderLeftText)(layout, state, value, meta);
94
+ itemHeaderRightText = _templates.helpers.asFunction(itemHeaderRightText)(layout, state, value, meta);
95
+ return `<div class="${className}__item-header">
96
+ <div class="${className}__item-header-left">${itemHeaderLeftText}</div>
97
+ <div class="${className}__item-header-right">${itemHeaderRightText}</div>
98
+ </div>`;
99
+ }
100
+ function itemHeaderRightText(layout, state, value, meta) {
101
+ const {
102
+ className,
103
+ templates
104
+ } = layout;
105
+ const logoText = _templates.helpers.asFunction(templates.logoText)(layout, state, value, meta) || '';
106
+ const logoImg = _templates.helpers.asFunction(templates.logoImg)(layout, state, value, meta);
107
+ return logoImg ? `<span class="${className}__item-header-logo-phrase">${logoText}</span>${logoImg}` : '';
108
+ }
109
+ function logoImg(layout, state, value, meta) {
110
+ const {
111
+ className,
112
+ templates
113
+ } = layout;
114
+ const logoUrl = _templates.helpers.asFunction(templates.logoUrl)(layout, state, value, meta);
115
+ if (!logoUrl) {
60
116
  return '';
61
117
  }
62
- return `<div class="${className}__header"><div class="${className}__header-tab">${headerText}</div></div>`;
118
+ const logoAltText = _templates.helpers.asFunction(templates.logoAltText)(layout, state, value, meta);
119
+ const logoAltTextAttr = logoAltText ? ` alt="${logoAltText}"` : '';
120
+ return `<img class="${className}__item-header-logo" src="${logoUrl}"${logoAltTextAttr}>`;
63
121
  }
64
122
  const DEFAULT_TEMPLATES = Object.freeze({
65
123
  root,
66
124
  [_constants.STATUS.READY]: ready,
125
+ controlContainer,
126
+ control,
127
+ controlIcon,
67
128
  body,
68
- header,
129
+ item,
130
+ itemHeader,
69
131
  affiliation: _templates.affiliation,
70
- ctaText: 'View',
71
- headerText: 'Featured'
132
+ ctaText: 'View deal',
133
+ itemHeaderLeftText: `Today's best deals`,
134
+ itemHeaderRightText,
135
+ logoImg,
136
+ logoText: 'Selected by'
72
137
  });
73
138
  const INHERITED_DEFAULT_TEMPLATES = Object.freeze(Object.assign({}, _collection.default.defaultTemplates, DEFAULT_TEMPLATES));
139
+
140
+ /*
141
+ function normalizeAutoplayOptions(options) {
142
+ if (options === true) {
143
+ options = { interval: 10000 };
144
+ } else if (typeof options === 'number') {
145
+ if (options <= 0) {
146
+ options = false;
147
+ } else {
148
+ options = { interval: Math.max(options, 500) };
149
+ }
150
+ }
151
+ return options;
152
+ }
153
+
154
+ function autoplayOptionsEquals(a, b) {
155
+ if (a === b) {
156
+ return true;
157
+ }
158
+ if (!a || !b) {
159
+ return false;
160
+ }
161
+ return a.interval === b.interval;
162
+ }
163
+ */
164
+
74
165
  class AffiliationLayout extends _collection.default {
75
166
  static get category() {
76
167
  return _constants.LAYOUT_CATEGORY.AFFILIATION;
@@ -96,6 +187,71 @@ class AffiliationLayout extends _collection.default {
96
187
  itemType: 'affiliation',
97
188
  templates: Object.assign({}, DEFAULT_TEMPLATES, templates)
98
189
  }, options));
190
+ this._itemCount = undefined;
191
+ this._itemIndex = 0;
192
+ this._displayedCount = undefined;
193
+ this._displayedIndex = undefined;
194
+ this._viewable = undefined;
195
+
196
+ // TODO: extract this
197
+ /*
198
+ this._autoplay = {};
199
+ this.autoplay(autoplay);
200
+ */
201
+ }
202
+ initialize(view) {
203
+ super.initialize(view);
204
+ const {
205
+ viewable: options
206
+ } = this._view.tracker.options || {};
207
+ this._viewable = new _commons.CarouselItemViewabilityObserver(this._onViewable.bind(this), options);
208
+ }
209
+
210
+ /*
211
+ autoplay(options = false) {
212
+ options = normalizeAutoplayOptions(options);
213
+ if (autoplayOptionsEquals(options, this._autoplay.options)) {
214
+ return;
215
+ }
216
+ if (this._autoplay.options) {
217
+ clearInterval(this._autoplay.intervalId);
218
+ }
219
+ this._autoplay = { options };
220
+ // TODO: use slower transition speed for autoplay
221
+ // TODO: pause on hover
222
+ // TODO: cooldown after manual interaction
223
+ if (options) {
224
+ this._autoplay.intervalId = setInterval(() => this.next(), options.interval);
225
+ }
226
+ }
227
+ */
228
+
229
+ get itemIndex() {
230
+ return this._itemIndex;
231
+ }
232
+ set itemIndex(index) {
233
+ if (this._itemCount === undefined) {
234
+ return;
235
+ }
236
+ if (index < 0) {
237
+ index = this._itemCount - 1;
238
+ } else if (index >= this._itemCount) {
239
+ index = 0;
240
+ }
241
+ this._itemIndex = index;
242
+ (0, _commons.requestAnimationFrame)(() => this._syncItemIndex());
243
+ }
244
+ next() {
245
+ if (this._itemCount === undefined) {
246
+ return;
247
+ }
248
+ this.itemIndex++;
249
+ }
250
+ previous() {
251
+ if (this._itemCount === undefined) {
252
+ return;
253
+ }
254
+ this.itemIndex--;
99
255
  }
100
256
  _getItems(state) {
101
257
  const {
@@ -103,5 +259,99 @@ class AffiliationLayout extends _collection.default {
103
259
  } = state.value || {};
104
260
  return products;
105
261
  }
262
+ _render(element, states, controls) {
263
+ super._render(element, states, controls);
264
+
265
+ // update item count, but raf to display as attribute
266
+ const items = this._getItems(states.state);
267
+ this._itemCount = items ? items.length : undefined;
268
+ (0, _commons.requestAnimationFrame)(() => {
269
+ this._syncItemCount();
270
+ this._syncItemIndex();
271
+ });
272
+ }
273
+ _syncElement(element) {
274
+ const oldElement = this._element;
275
+ super._syncElement(element);
276
+ this._syncViewableElement(oldElement, element);
277
+ }
278
+ _syncViewableElement(oldElement, newElement) {
279
+ if (oldElement === newElement) {
280
+ return;
281
+ }
282
+ oldElement && this._viewable.unobserve(oldElement);
283
+ newElement && this._viewable.observe(newElement);
284
+ }
285
+ _syncItemCount() {
286
+ const itemCount = this._itemCount;
287
+ if (itemCount === this._displayedCount) {
288
+ return;
289
+ }
290
+ let {
291
+ element
292
+ } = this._view;
293
+ element = element.firstElementChild;
294
+ if (!element) {
295
+ return;
296
+ }
297
+ this._displayedCount = itemCount;
298
+ if (itemCount === undefined) {
299
+ element.removeAttribute('data-item-count');
300
+ } else {
301
+ element.setAttribute('data-item-count', itemCount);
302
+ }
303
+ }
304
+ _syncItemIndex() {
305
+ const index = this._itemIndex;
306
+ if (index === this._displayedIndex) {
307
+ return;
308
+ }
309
+ const {
310
+ element
311
+ } = this._view;
312
+ const listElement = element && this._getListElement(element);
313
+ if (!listElement) {
314
+ return;
315
+ }
316
+ this._displayedIndex = index;
317
+ listElement.style.left = `${-index * 100}%`;
318
+ this._viewable.display(index);
319
+ this._view._events.emit('display', {
320
+ index
321
+ });
322
+ }
323
+ _onViewable(index) {
324
+ const item = this._getRenderedItemData(index);
325
+ if (!item) {
326
+ return;
327
+ }
328
+ this._view.tracker.viewable([item]);
329
+ }
330
+ _getRenderedItemData(index) {
331
+ const {
332
+ value
333
+ } = this._rendered.get(this._element) || {};
334
+ if (!value) {
335
+ return undefined;
336
+ }
337
+ const {
338
+ products = []
339
+ } = value;
340
+ return products[index];
341
+ }
342
+ _trackViewables() {} // omit default behavior for we want to track by other means
343
+
344
+ _onClick(event) {
345
+ const element = event.target;
346
+ if (element.closest(`[data-role="previous"]`)) {
347
+ this.previous();
348
+ return;
349
+ }
350
+ if (element.closest(`[data-role="next"]`)) {
351
+ this.next();
352
+ return;
353
+ }
354
+ super._onClick(event);
355
+ }
106
356
  }
107
357
  exports.default = AffiliationLayout;
@@ -8,10 +8,10 @@ var _commons = require("@miso.ai/commons");
8
8
  var _constants = require("../../constants.js");
9
9
  var _index = require("../../actor/index.js");
10
10
  var _template = _interopRequireDefault(require("../template.js"));
11
+ var _trackable = require("../trackable.js");
11
12
  const _excluded = ["className", "templates"];
12
13
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
13
14
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.includes(n)) continue; t[n] = r[n]; } return t; }
14
- const OPTION_VALUE = Symbol.for('miso.option-value');
15
15
  const TYPE = 'option-list';
16
16
  const DEFAULT_CLASSNAME = 'miso-option-list';
17
17
  function root(layout, state) {
@@ -77,11 +77,7 @@ class OptionListLayout extends _template.default {
77
77
  className,
78
78
  templates: Object.assign({}, DEFAULT_TEMPLATES, templates)
79
79
  }, options));
80
- (0, _commons.defineValues)(this, {
81
- bindings: Object.freeze({
82
- list: this._listBindings.bind(this)
83
- })
84
- });
80
+ this._initTrackable();
85
81
  }
86
82
  initialize(view) {
87
83
  this._view = view;
@@ -98,61 +94,44 @@ class OptionListLayout extends _template.default {
98
94
  }
99
95
  _render(element, data, controls) {
100
96
  super._render(element, data, controls);
101
- this._syncOptionValues(element, data);
102
- }
103
- _syncOptionValues(element, _ref2) {
104
- let {
97
+ const {
105
98
  state
106
- } = _ref2;
107
- if (!element) {
108
- return;
109
- }
110
- const optionsElement = this._getOptionsElement(element);
99
+ } = data;
100
+ this._syncBindings(element, state);
101
+ this._syncOptionValues(element, state);
102
+ }
103
+ _unrender() {
104
+ this._clearBindings();
105
+ }
106
+ _syncOptionValues(element, state) {
107
+ const optionsElement = element && this._getOptionsElement(element);
111
108
  if (!optionsElement) {
112
109
  return;
113
110
  }
114
- const optionValues = state.value || [];
111
+ const optionValues = this._getItems(state) || [];
115
112
  optionsElement.classList[optionValues.length === 0 ? 'add' : 'remove']('empty');
116
- let i = 0;
117
- for (const optionElement of this._listOptionElements(optionsElement)) {
118
- optionElement[OPTION_VALUE] = optionValues[i++];
119
- }
120
113
  }
121
- _listBindings(rootElement) {
122
- if (!rootElement) {
123
- return [];
124
- }
125
- const optionsElement = this._getOptionsElement(rootElement);
126
- const bindings = [];
127
- for (const element of this._listOptionElements(optionsElement)) {
128
- const value = element[OPTION_VALUE];
129
- if (!value) {
130
- continue;
131
- }
132
- const key = value.text || value;
133
- bindings.push({
134
- key,
135
- value,
136
- element
137
- });
138
- }
139
- return bindings;
114
+ _getItems(state) {
115
+ return state.value;
140
116
  }
141
117
  _getOptionsElement(element) {
142
118
  return element.querySelector(`[data-role="options"]`);
143
119
  }
144
- _listOptionElements(optionsElement) {
145
- return optionsElement ? Array.from(optionsElement.querySelectorAll(`[data-role="option"]`)) : [];
120
+ _getItemElements(element) {
121
+ return element ? Array.from(element.querySelectorAll(`[data-role="option"]`)) : [];
146
122
  }
147
- _handleClick(e) {
148
- for (let element = e.target; element && element !== this._view.element; element = element.parentElement) {
149
- const option = element[OPTION_VALUE];
150
- if (!option) {
151
- continue;
152
- }
153
- this._submit(option.text);
123
+ _handleClick(event) {
124
+ const element = event.target.closest(`[data-role="option"]`);
125
+ if (!element) {
126
+ return;
127
+ }
128
+ const binding = this._bindings.get(element);
129
+ const option = binding && binding.value;
130
+ if (!option) {
154
131
  return;
155
132
  }
133
+ this._trackClick(event, binding);
134
+ this._submit(option.text);
156
135
  }
157
136
  async _submit(value) {
158
137
  if (!value) {
@@ -163,5 +142,11 @@ class OptionListLayout extends _template.default {
163
142
  q: value
164
143
  });
165
144
  }
145
+ destroy() {
146
+ this._destroyTrackable();
147
+ this._view = undefined;
148
+ super.destroy();
149
+ }
166
150
  }
167
- exports.default = OptionListLayout;
151
+ exports.default = OptionListLayout;
152
+ (0, _trackable.makeTrackable)(OptionListLayout.prototype);
@@ -4,14 +4,13 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _commons = require("@miso.ai/commons");
8
7
  var _constants = require("../../constants.js");
9
8
  var _template = _interopRequireDefault(require("../template.js"));
9
+ var _trackable = require("../trackable.js");
10
10
  var _templates = require("../templates.js");
11
11
  const _excluded = ["templates", "itemType"];
12
12
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
13
13
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.includes(n)) continue; t[n] = r[n]; } return t; }
14
- const VALUE = Symbol.for('miso.value');
15
14
  function root(layout, state) {
16
15
  const {
17
16
  className,
@@ -45,7 +44,7 @@ function list(layout, state, values) {
45
44
  } = layout;
46
45
  const listTag = templates.ordered ? 'ol' : 'ul';
47
46
  // TODO: support separator?
48
- return `<${listTag} class="${className}__list" data-item-type="${options.itemType}">${templates.items(layout, state, values)}</${listTag}>`;
47
+ return `<${listTag} class="${className}__list" data-role="list" data-item-type="${options.itemType}">${templates.items(layout, state, values)}</${listTag}>`;
49
48
  }
50
49
  function items(layout, state, values) {
51
50
  let {
@@ -116,19 +115,12 @@ class CollectionLayout extends _template.default {
116
115
  templates: Object.assign({}, DEFAULT_TEMPLATES, templates),
117
116
  itemType
118
117
  }, options));
119
- (0, _commons.defineValues)(this, {
120
- bindings: Object.freeze({
121
- list: this._listBindings.bind(this)
122
- })
123
- });
124
118
  this._view = undefined;
119
+ this._initTrackable();
125
120
  }
126
121
  initialize(view) {
127
122
  this._view = view;
128
- const {
129
- proxyElement
130
- } = this._view = view;
131
- this._unsubscribes.push(proxyElement.on('click', this._onClick.bind(this)));
123
+ this._unsubscribes.push(view.proxyElement.on('click', this._onClick.bind(this)));
132
124
  }
133
125
  _preprocess(_ref2) {
134
126
  let {
@@ -178,55 +170,40 @@ class CollectionLayout extends _template.default {
178
170
  } else {
179
171
  element.innerHTML = html;
180
172
  }
181
- this._syncValues(element, state);
173
+ this._syncBindings(element, state);
182
174
  }
183
- _syncValues(element, state) {
184
- if (!element) {
185
- return;
186
- }
187
- const values = this._getItems(state) || [];
188
- let i = 0;
189
- for (const itemElement of this._listItemElements(element)) {
190
- itemElement[VALUE] = values[i++];
191
- }
175
+ _unrender() {
176
+ this._clearBindings();
192
177
  }
193
178
  _getItems(state) {
194
179
  return state.value;
195
180
  }
196
181
  _getListElement(element) {
197
- return element.querySelector(`.${this.className}__list`);
182
+ return element.querySelector('[data-role="list"]');
198
183
  }
199
- _listItemElements(element) {
184
+ _getItemElements(element) {
200
185
  return element ? Array.from(element.querySelectorAll(`[data-role="item"]`)) : [];
201
186
  }
202
- _listBindings(rootElement) {
203
- if (!rootElement) {
204
- return [];
205
- }
206
- const bindings = [];
207
- for (const element of this._listItemElements(rootElement)) {
208
- const value = element[VALUE];
209
- if (!value) {
210
- continue;
211
- }
212
- const key = this.options.itemType === 'product' ? value.product_id : value;
213
- bindings.push({
214
- element,
215
- key,
216
- value
217
- });
218
- }
219
- return bindings;
220
- }
221
187
  _onClick(event) {
222
188
  const element = event.target.closest(`[data-role="item"]`);
223
189
  if (!element) {
224
190
  return;
225
191
  }
226
- const value = element[VALUE];
192
+ const binding = this._bindings.get(element);
193
+ if (!binding) {
194
+ return;
195
+ }
196
+ this._trackClick(event, binding);
197
+ this._emitClickEvent(event, binding);
198
+ }
199
+ _emitClickEvent(event, binding) {
227
200
  const {
228
201
  session
229
202
  } = this._view._state;
203
+ const {
204
+ value,
205
+ element
206
+ } = binding;
230
207
  this._view._events.emit('click', {
231
208
  session,
232
209
  value,
@@ -235,8 +212,10 @@ class CollectionLayout extends _template.default {
235
212
  });
236
213
  }
237
214
  destroy() {
215
+ this._destroyTrackable();
238
216
  this._view = undefined;
239
217
  super.destroy();
240
218
  }
241
219
  }
242
- exports.default = CollectionLayout;
220
+ exports.default = CollectionLayout;
221
+ (0, _trackable.makeTrackable)(CollectionLayout.prototype);