@miso.ai/client-sdk-ui 1.10.0-beta.9 → 1.10.1-beta.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 -102
  3. package/dist/cjs/actor/utils.js +1 -1
  4. package/dist/cjs/actor/view.js +12 -1
  5. package/dist/cjs/actor/views.js +24 -2
  6. package/dist/cjs/asset/svgs.js +14 -4
  7. package/dist/cjs/constants.js +3 -2
  8. package/dist/cjs/layout/affiliation/affiliation.js +152 -58
  9. package/dist/cjs/layout/input/option-list.js +34 -49
  10. package/dist/cjs/layout/list/collection.js +22 -43
  11. package/dist/cjs/layout/templates.js +54 -32
  12. package/dist/cjs/layout/text/typewriter/index.js +12 -7
  13. package/dist/cjs/layout/trackable.js +124 -0
  14. package/dist/cjs/util/bindings.js +58 -110
  15. package/dist/cjs/util/states.js +31 -24
  16. package/dist/cjs/util/trackers.js +75 -0
  17. package/dist/cjs/util/viewables.js +55 -0
  18. package/dist/cjs/version.js +1 -1
  19. package/dist/cjs/workflow/ask.js +1 -5
  20. package/dist/cjs/workflow/base.js +2 -7
  21. package/dist/cjs/workflow/recommendation.js +2 -0
  22. package/package.json +2 -2
  23. package/src/actor/index.js +0 -1
  24. package/src/actor/tracker.js +37 -94
  25. package/src/actor/utils.js +1 -1
  26. package/src/actor/view.js +14 -1
  27. package/src/actor/views.js +30 -1
  28. package/src/asset/svgs.js +13 -2
  29. package/src/constants.js +7 -1
  30. package/src/layout/affiliation/affiliation.js +140 -55
  31. package/src/layout/input/option-list.js +35 -43
  32. package/src/layout/list/collection.js +20 -38
  33. package/src/layout/templates.js +25 -19
  34. package/src/layout/text/typewriter/index.js +8 -6
  35. package/src/layout/trackable.js +106 -0
  36. package/src/util/bindings.js +47 -103
  37. package/src/util/states.js +26 -20
  38. package/src/util/trackers.js +69 -0
  39. package/src/util/viewables.js +47 -0
  40. package/src/version.js +1 -1
  41. package/src/workflow/ask.js +1 -4
  42. package/src/workflow/base.js +3 -5
  43. package/src/workflow/recommendation.js +1 -0
  44. package/dist/cjs/actor/trackers.js +0 -51
  45. package/dist/cjs/layout/affiliation/viewable.js +0 -65
  46. package/dist/cjs/layout/text/typewriter/progress.js +0 -45
  47. package/dist/cjs/util/tracker.js +0 -348
  48. package/src/actor/trackers.js +0 -45
  49. package/src/layout/affiliation/viewable.js +0 -61
  50. package/src/layout/text/typewriter/progress.js +0 -33
  51. package/src/util/tracker.js +0 -318
@@ -4,11 +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
- var _viewable = _interopRequireDefault(require("./viewable.js"));
11
- const _excluded = ["className", "templates"];
11
+ var _svgs = require("../../asset/svgs.js");
12
+ const _excluded = ["className", "templates", "autoplay"];
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
15
  const TYPE = 'affiliation';
@@ -25,7 +26,10 @@ function root(layout, state) {
25
26
  const roleAttr = role ? ` data-role="${role}"` : '';
26
27
  const data = state.value || {};
27
28
  const channelAttr = data.channel ? ` data-channel="${data.channel}"` : '';
28
- return `<div class="${className} ${status}"${roleAttr}${channelAttr}>${status === _constants.STATUS.READY ? templates[status](layout, state) : ''}</div>`;
29
+ const items = layout._getItems(state);
30
+ const itemCount = items ? items.length : undefined;
31
+ const itemCountAttr = itemCount !== undefined ? ` data-item-count="${itemCount}"` : '';
32
+ return `<div class="${className} ${status}"${roleAttr}${channelAttr}${itemCountAttr}>${status === _constants.STATUS.READY ? templates[status](layout, state) : ''}</div>`;
29
33
  }
30
34
  function ready(layout, state) {
31
35
  const {
@@ -33,40 +37,35 @@ function ready(layout, state) {
33
37
  } = layout;
34
38
  const items = layout._getItems(state);
35
39
  if (items && items.length > 0) {
36
- return templates.control(layout, state, 'previous') + templates.body(layout, state) + templates.control(layout, state, 'next');
40
+ return templates.controlContainer(layout, state, 'previous') + templates.body(layout, state) + templates.controlContainer(layout, state, 'next');
37
41
  } else {
38
42
  return templates.empty(layout, state);
39
43
  }
40
44
  }
41
- function control(layout, state, direction) {
45
+ function controlContainer(layout, state, direction) {
42
46
  const {
43
- className
47
+ className,
48
+ templates
44
49
  } = layout;
45
- return `<div class="${className}__control-${direction}" data-role="${direction}"></div>`;
50
+ return `<div class="${className}__control-${direction}-container">${templates.control(layout, state, direction)}</div>`;
46
51
  }
47
- function body(layout, state) {
52
+ function control(layout, state, direction) {
48
53
  const {
49
54
  className,
50
55
  templates
51
56
  } = layout;
52
- const items = layout._getItems(state);
53
- return `<div class="${className}__body">${templates.list(layout, state, items)}</div>`;
57
+ return `<div class="${className}__control-${direction}" data-role="${direction}">${templates.controlIcon(layout, state, direction)}</div>`;
58
+ }
59
+ function controlIcon(layout, state, direction) {
60
+ return _svgs.TRIANGLE;
54
61
  }
55
- function header(layout, state) {
62
+ function body(layout, state) {
56
63
  const {
57
64
  className,
58
65
  templates
59
66
  } = layout;
60
- let {
61
- headerText
62
- } = templates;
63
- if (typeof headerText === 'function') {
64
- headerText = headerText(layout, state);
65
- }
66
- if (!headerText) {
67
- return '';
68
- }
69
- return `<div class="${className}__header"><div class="${className}__header-tab">${headerText}</div></div>`;
67
+ const items = layout._getItems(state);
68
+ return `<div class="${className}__body">${templates.list(layout, state, items)}</div>`;
70
69
  }
71
70
  function item(layout, state, value, index) {
72
71
  const {
@@ -83,7 +82,7 @@ function item(layout, state, value, index) {
83
82
  const body = templates[itemType](layout, state, value, {
84
83
  index
85
84
  });
86
- return `<li class="${className}__item">${header}${body}</li>`;
85
+ return `<li class="${className}__item"><div class="${className}__item-inner">${header}${body}</div></li>`;
87
86
  }
88
87
  function itemHeader(layout, state, value, meta) {
89
88
  const {
@@ -91,29 +90,81 @@ function itemHeader(layout, state, value, meta) {
91
90
  templates
92
91
  } = layout;
93
92
  let {
94
- headerText
93
+ itemHeaderLeftText,
94
+ itemHeaderRightText
95
95
  } = templates;
96
- if (typeof headerText === 'function') {
97
- headerText = headerText(layout, state, value, meta);
98
- }
99
- if (!headerText) {
96
+ itemHeaderLeftText = _templates.helpers.asFunction(itemHeaderLeftText)(layout, state, value, meta);
97
+ itemHeaderRightText = _templates.helpers.asFunction(itemHeaderRightText)(layout, state, value, meta);
98
+ return `<div class="${className}__item-header">
99
+ <div class="${className}__item-header-left">${itemHeaderLeftText}</div>
100
+ <div class="${className}__item-header-right">${itemHeaderRightText}</div>
101
+ </div>`;
102
+ }
103
+ function itemHeaderRightText(layout, state, value, meta) {
104
+ const {
105
+ className,
106
+ templates
107
+ } = layout;
108
+ const logoText = _templates.helpers.asFunction(templates.logoText)(layout, state, value, meta) || '';
109
+ const logoImg = _templates.helpers.asFunction(templates.logoImg)(layout, state, value, meta);
110
+ return logoImg ? `<span class="${className}__item-header-logo-phrase">${logoText}</span>${logoImg}` : '';
111
+ }
112
+ function logoImg(layout, state, value, meta) {
113
+ const {
114
+ className,
115
+ templates
116
+ } = layout;
117
+ const logoUrl = _templates.helpers.asFunction(templates.logoUrl)(layout, state, value, meta);
118
+ if (!logoUrl) {
100
119
  return '';
101
120
  }
102
- return `<div class="${className}__item-header"><div class="${className}__item-header-tab">${headerText}</div></div>`;
121
+ const logoAltText = _templates.helpers.asFunction(templates.logoAltText)(layout, state, value, meta);
122
+ const logoAltTextAttr = logoAltText ? ` alt="${logoAltText}"` : '';
123
+ return `<img class="${className}__item-header-logo" src="${logoUrl}"${logoAltTextAttr}>`;
103
124
  }
104
125
  const DEFAULT_TEMPLATES = Object.freeze({
105
126
  root,
106
127
  [_constants.STATUS.READY]: ready,
128
+ controlContainer,
107
129
  control,
130
+ controlIcon,
108
131
  body,
109
- header,
110
132
  item,
111
133
  itemHeader,
112
134
  affiliation: _templates.affiliation,
113
- ctaText: 'View',
114
- headerText: 'Featured'
135
+ ctaText: 'View deal',
136
+ itemHeaderLeftText: `Today's best deals`,
137
+ itemHeaderRightText,
138
+ logoImg,
139
+ logoText: 'Selected by'
115
140
  });
116
141
  const INHERITED_DEFAULT_TEMPLATES = Object.freeze(Object.assign({}, _collection.default.defaultTemplates, DEFAULT_TEMPLATES));
142
+
143
+ /*
144
+ function normalizeAutoplayOptions(options) {
145
+ if (options === true) {
146
+ options = { interval: 10000 };
147
+ } else if (typeof options === 'number') {
148
+ if (options <= 0) {
149
+ options = false;
150
+ } else {
151
+ options = { interval: Math.max(options, 500) };
152
+ }
153
+ }
154
+ return options;
155
+ }
156
+
157
+ function autoplayOptionsEquals(a, b) {
158
+ if (a === b) {
159
+ return true;
160
+ }
161
+ if (!a || !b) {
162
+ return false;
163
+ }
164
+ return a.interval === b.interval;
165
+ }
166
+ */
167
+
117
168
  class AffiliationLayout extends _collection.default {
118
169
  static get category() {
119
170
  return _constants.LAYOUT_CATEGORY.AFFILIATION;
@@ -141,25 +192,47 @@ class AffiliationLayout extends _collection.default {
141
192
  }, options));
142
193
  this._itemCount = undefined;
143
194
  this._itemIndex = 0;
195
+ this._displayedCount = undefined;
144
196
  this._displayedIndex = undefined;
145
- this._viewable = new _viewable.default(this._onViewable.bind(this));
197
+ this._viewable = undefined;
198
+
199
+ // TODO: extract this
200
+ /*
201
+ this._autoplay = {};
202
+ this.autoplay(autoplay);
203
+ */
146
204
  }
147
- get itemIndex() {
148
- return this._itemIndex;
205
+ initialize(view) {
206
+ super.initialize(view);
207
+ const {
208
+ viewable: options
209
+ } = this._view.tracker.options || {};
210
+ this._viewable = new _commons.CarouselItemViewabilityObserver(this._onViewable.bind(this), options);
149
211
  }
150
- next() {
151
- if (this._itemCount === undefined) {
212
+
213
+ /*
214
+ autoplay(options = false) {
215
+ options = normalizeAutoplayOptions(options);
216
+ if (autoplayOptionsEquals(options, this._autoplay.options)) {
152
217
  return;
153
218
  }
154
- this.go(this._itemIndex + 1);
155
- }
156
- previous() {
157
- if (this._itemCount === undefined) {
158
- return;
219
+ if (this._autoplay.options) {
220
+ clearInterval(this._autoplay.intervalId);
221
+ }
222
+ this._autoplay = { options };
223
+ // TODO: use slower transition speed for autoplay
224
+ // TODO: pause on hover
225
+ // TODO: cooldown after manual interaction
226
+ if (options) {
227
+ this._autoplay.intervalId = setInterval(() => this.next(), options.interval);
159
228
  }
160
- this.go(this._itemIndex - 1);
161
229
  }
162
- go(index) {
230
+ */
231
+
232
+ get itemIndex() {
233
+ return this._itemIndex;
234
+ }
235
+ set itemIndex(index) {
163
236
  if (this._itemCount === undefined) {
164
237
  return;
165
238
  }
@@ -169,7 +242,19 @@ class AffiliationLayout extends _collection.default {
169
242
  index = 0;
170
243
  }
171
244
  this._itemIndex = index;
172
- this._syncItemIndex();
245
+ (0, _commons.requestAnimationFrame)(() => this._syncItemIndex());
246
+ }
247
+ next() {
248
+ if (this._itemCount === undefined) {
249
+ return;
250
+ }
251
+ this.itemIndex++;
252
+ }
253
+ previous() {
254
+ if (this._itemCount === undefined) {
255
+ return;
256
+ }
257
+ this.itemIndex--;
173
258
  }
174
259
  _getItems(state) {
175
260
  const {
@@ -179,7 +264,8 @@ class AffiliationLayout extends _collection.default {
179
264
  }
180
265
  _render(element, states, controls) {
181
266
  super._render(element, states, controls);
182
- this._syncItemCount(element, states);
267
+ // sync again for incremental item rendering
268
+ this._syncItemCount(states);
183
269
  this._syncItemIndex();
184
270
  }
185
271
  _syncElement(element) {
@@ -194,16 +280,23 @@ class AffiliationLayout extends _collection.default {
194
280
  oldElement && this._viewable.unobserve(oldElement);
195
281
  newElement && this._viewable.observe(newElement);
196
282
  }
197
- _syncItemCount(element, states) {
283
+ _syncItemCount() {
284
+ let {
285
+ state
286
+ } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
287
+ const items = this._getItems(state);
288
+ const itemCount = this._itemCount = items ? items.length : undefined;
289
+ if (itemCount === this._displayedCount) {
290
+ return;
291
+ }
292
+ let {
293
+ element
294
+ } = this._view;
198
295
  element = element.firstElementChild;
199
296
  if (!element) {
200
297
  return;
201
298
  }
202
- const {
203
- state
204
- } = states;
205
- const items = this._getItems(state);
206
- const itemCount = this._itemCount = items ? items.length : undefined;
299
+ this._displayedCount = itemCount;
207
300
  if (itemCount === undefined) {
208
301
  element.removeAttribute('data-item-count');
209
302
  } else {
@@ -211,7 +304,10 @@ class AffiliationLayout extends _collection.default {
211
304
  }
212
305
  }
213
306
  _syncItemIndex() {
214
- // TODO: raf
307
+ const index = this._itemIndex;
308
+ if (index === this._displayedIndex) {
309
+ return;
310
+ }
215
311
  const {
216
312
  element
217
313
  } = this._view;
@@ -219,10 +315,6 @@ class AffiliationLayout extends _collection.default {
219
315
  if (!listElement) {
220
316
  return;
221
317
  }
222
- const index = this._itemIndex;
223
- if (index === this._displayedIndex) {
224
- return;
225
- }
226
318
  this._displayedIndex = index;
227
319
  listElement.style.left = `${-index * 100}%`;
228
320
  this._viewable.display(index);
@@ -235,7 +327,7 @@ class AffiliationLayout extends _collection.default {
235
327
  if (!item) {
236
328
  return;
237
329
  }
238
- this._view._events.emit(_constants.EVENT_TYPE.VIEWABLE, [item]);
330
+ this._view.tracker.viewable([item]);
239
331
  }
240
332
  _getRenderedItemData(index) {
241
333
  const {
@@ -249,8 +341,9 @@ class AffiliationLayout extends _collection.default {
249
341
  } = value;
250
342
  return products[index];
251
343
  }
344
+ _trackViewables() {} // omit default behavior for we want to track by other means
345
+
252
346
  _onClick(event) {
253
- super._onClick(event);
254
347
  const element = event.target;
255
348
  if (element.closest(`[data-role="previous"]`)) {
256
349
  this.previous();
@@ -260,6 +353,7 @@ class AffiliationLayout extends _collection.default {
260
353
  this.next();
261
354
  return;
262
355
  }
356
+ super._onClick(event);
263
357
  }
264
358
  }
265
359
  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,
@@ -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,17 +170,10 @@ 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;
@@ -196,37 +181,29 @@ class CollectionLayout extends _template.default {
196
181
  _getListElement(element) {
197
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);