@miso.ai/client-sdk-ui 1.10.0-beta.9 → 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 -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 +150 -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 +142 -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';
@@ -33,40 +34,35 @@ function ready(layout, state) {
33
34
  } = layout;
34
35
  const items = layout._getItems(state);
35
36
  if (items && items.length > 0) {
36
- return templates.control(layout, state, 'previous') + templates.body(layout, state) + templates.control(layout, state, 'next');
37
+ return templates.controlContainer(layout, state, 'previous') + templates.body(layout, state) + templates.controlContainer(layout, state, 'next');
37
38
  } else {
38
39
  return templates.empty(layout, state);
39
40
  }
40
41
  }
41
- function control(layout, state, direction) {
42
+ function controlContainer(layout, state, direction) {
42
43
  const {
43
- className
44
+ className,
45
+ templates
44
46
  } = layout;
45
- return `<div class="${className}__control-${direction}" data-role="${direction}"></div>`;
47
+ return `<div class="${className}__control-${direction}-container">${templates.control(layout, state, direction)}</div>`;
46
48
  }
47
- function body(layout, state) {
49
+ function control(layout, state, direction) {
48
50
  const {
49
51
  className,
50
52
  templates
51
53
  } = layout;
52
- const items = layout._getItems(state);
53
- return `<div class="${className}__body">${templates.list(layout, state, items)}</div>`;
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;
54
58
  }
55
- function header(layout, state) {
59
+ function body(layout, state) {
56
60
  const {
57
61
  className,
58
62
  templates
59
63
  } = 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>`;
64
+ const items = layout._getItems(state);
65
+ return `<div class="${className}__body">${templates.list(layout, state, items)}</div>`;
70
66
  }
71
67
  function item(layout, state, value, index) {
72
68
  const {
@@ -83,7 +79,7 @@ function item(layout, state, value, index) {
83
79
  const body = templates[itemType](layout, state, value, {
84
80
  index
85
81
  });
86
- return `<li class="${className}__item">${header}${body}</li>`;
82
+ return `<li class="${className}__item"><div class="${className}__item-inner">${header}${body}</div></li>`;
87
83
  }
88
84
  function itemHeader(layout, state, value, meta) {
89
85
  const {
@@ -91,29 +87,81 @@ function itemHeader(layout, state, value, meta) {
91
87
  templates
92
88
  } = layout;
93
89
  let {
94
- headerText
90
+ itemHeaderLeftText,
91
+ itemHeaderRightText
95
92
  } = templates;
96
- if (typeof headerText === 'function') {
97
- headerText = headerText(layout, state, value, meta);
98
- }
99
- 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) {
100
116
  return '';
101
117
  }
102
- return `<div class="${className}__item-header"><div class="${className}__item-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}>`;
103
121
  }
104
122
  const DEFAULT_TEMPLATES = Object.freeze({
105
123
  root,
106
124
  [_constants.STATUS.READY]: ready,
125
+ controlContainer,
107
126
  control,
127
+ controlIcon,
108
128
  body,
109
- header,
110
129
  item,
111
130
  itemHeader,
112
131
  affiliation: _templates.affiliation,
113
- ctaText: 'View',
114
- headerText: 'Featured'
132
+ ctaText: 'View deal',
133
+ itemHeaderLeftText: `Today's best deals`,
134
+ itemHeaderRightText,
135
+ logoImg,
136
+ logoText: 'Selected by'
115
137
  });
116
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
+
117
165
  class AffiliationLayout extends _collection.default {
118
166
  static get category() {
119
167
  return _constants.LAYOUT_CATEGORY.AFFILIATION;
@@ -141,25 +189,47 @@ class AffiliationLayout extends _collection.default {
141
189
  }, options));
142
190
  this._itemCount = undefined;
143
191
  this._itemIndex = 0;
192
+ this._displayedCount = undefined;
144
193
  this._displayedIndex = undefined;
145
- this._viewable = new _viewable.default(this._onViewable.bind(this));
194
+ this._viewable = undefined;
195
+
196
+ // TODO: extract this
197
+ /*
198
+ this._autoplay = {};
199
+ this.autoplay(autoplay);
200
+ */
146
201
  }
147
- get itemIndex() {
148
- return this._itemIndex;
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);
149
208
  }
150
- next() {
151
- if (this._itemCount === undefined) {
209
+
210
+ /*
211
+ autoplay(options = false) {
212
+ options = normalizeAutoplayOptions(options);
213
+ if (autoplayOptionsEquals(options, this._autoplay.options)) {
152
214
  return;
153
215
  }
154
- this.go(this._itemIndex + 1);
155
- }
156
- previous() {
157
- if (this._itemCount === undefined) {
158
- return;
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);
159
225
  }
160
- this.go(this._itemIndex - 1);
161
226
  }
162
- go(index) {
227
+ */
228
+
229
+ get itemIndex() {
230
+ return this._itemIndex;
231
+ }
232
+ set itemIndex(index) {
163
233
  if (this._itemCount === undefined) {
164
234
  return;
165
235
  }
@@ -169,7 +239,19 @@ class AffiliationLayout extends _collection.default {
169
239
  index = 0;
170
240
  }
171
241
  this._itemIndex = index;
172
- this._syncItemIndex();
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--;
173
255
  }
174
256
  _getItems(state) {
175
257
  const {
@@ -179,8 +261,14 @@ class AffiliationLayout extends _collection.default {
179
261
  }
180
262
  _render(element, states, controls) {
181
263
  super._render(element, states, controls);
182
- this._syncItemCount(element, states);
183
- this._syncItemIndex();
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
+ });
184
272
  }
185
273
  _syncElement(element) {
186
274
  const oldElement = this._element;
@@ -194,16 +282,19 @@ class AffiliationLayout extends _collection.default {
194
282
  oldElement && this._viewable.unobserve(oldElement);
195
283
  newElement && this._viewable.observe(newElement);
196
284
  }
197
- _syncItemCount(element, states) {
285
+ _syncItemCount() {
286
+ const itemCount = this._itemCount;
287
+ if (itemCount === this._displayedCount) {
288
+ return;
289
+ }
290
+ let {
291
+ element
292
+ } = this._view;
198
293
  element = element.firstElementChild;
199
294
  if (!element) {
200
295
  return;
201
296
  }
202
- const {
203
- state
204
- } = states;
205
- const items = this._getItems(state);
206
- const itemCount = this._itemCount = items ? items.length : undefined;
297
+ this._displayedCount = itemCount;
207
298
  if (itemCount === undefined) {
208
299
  element.removeAttribute('data-item-count');
209
300
  } else {
@@ -211,7 +302,10 @@ class AffiliationLayout extends _collection.default {
211
302
  }
212
303
  }
213
304
  _syncItemIndex() {
214
- // TODO: raf
305
+ const index = this._itemIndex;
306
+ if (index === this._displayedIndex) {
307
+ return;
308
+ }
215
309
  const {
216
310
  element
217
311
  } = this._view;
@@ -219,10 +313,6 @@ class AffiliationLayout extends _collection.default {
219
313
  if (!listElement) {
220
314
  return;
221
315
  }
222
- const index = this._itemIndex;
223
- if (index === this._displayedIndex) {
224
- return;
225
- }
226
316
  this._displayedIndex = index;
227
317
  listElement.style.left = `${-index * 100}%`;
228
318
  this._viewable.display(index);
@@ -235,7 +325,7 @@ class AffiliationLayout extends _collection.default {
235
325
  if (!item) {
236
326
  return;
237
327
  }
238
- this._view._events.emit(_constants.EVENT_TYPE.VIEWABLE, [item]);
328
+ this._view.tracker.viewable([item]);
239
329
  }
240
330
  _getRenderedItemData(index) {
241
331
  const {
@@ -249,8 +339,9 @@ class AffiliationLayout extends _collection.default {
249
339
  } = value;
250
340
  return products[index];
251
341
  }
342
+ _trackViewables() {} // omit default behavior for we want to track by other means
343
+
252
344
  _onClick(event) {
253
- super._onClick(event);
254
345
  const element = event.target;
255
346
  if (element.closest(`[data-role="previous"]`)) {
256
347
  this.previous();
@@ -260,6 +351,7 @@ class AffiliationLayout extends _collection.default {
260
351
  this.next();
261
352
  return;
262
353
  }
354
+ super._onClick(event);
263
355
  }
264
356
  }
265
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,
@@ -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);