@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
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.normalizeTrackerOptions = normalizeTrackerOptions;
7
+ exports.validateClick = validateClick;
8
+ var _commons = require("@miso.ai/commons");
9
+ const _excluded = ["impression", "viewable", "click"];
10
+ 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; }
11
+ const DEFAULT_TRACKER_OPTIONS = Object.freeze({
12
+ impression: Object.freeze({}),
13
+ viewable: Object.freeze({
14
+ area: 0.5,
15
+ duration: 1000
16
+ }),
17
+ click: Object.freeze({
18
+ lenient: false
19
+ }),
20
+ watch: false
21
+ });
22
+ function mergeOptions(def, opt) {
23
+ // if opt is falsy then return false, merge otherwise
24
+ return !!opt && Object.assign({}, def, opt);
25
+ }
26
+ function normalizeTrackerOptions(options) {
27
+ if (options === false) {
28
+ return false; // turn off all tracking
29
+ }
30
+ if (options === true) {
31
+ options = {};
32
+ }
33
+ if (typeof options !== 'object') {
34
+ throw new Error(`Invalid options: ${options}`);
35
+ }
36
+ const {
37
+ impression = {},
38
+ viewable = {},
39
+ click = {}
40
+ } = options,
41
+ rest = _objectWithoutPropertiesLoose(options, _excluded);
42
+ return (0, _commons.trimObj)(Object.assign({}, DEFAULT_TRACKER_OPTIONS, rest, {
43
+ impression: mergeOptions(DEFAULT_TRACKER_OPTIONS.impression, impression),
44
+ viewable: mergeOptions(DEFAULT_TRACKER_OPTIONS.viewable, viewable),
45
+ click: mergeOptions(DEFAULT_TRACKER_OPTIONS.click, click)
46
+ }));
47
+ }
48
+ function validateClick() {
49
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
50
+ let event = arguments.length > 1 ? arguments[1] : undefined;
51
+ if (!options) {
52
+ return false;
53
+ }
54
+ if (typeof options.validate === 'function') {
55
+ return options.validate(event);
56
+ }
57
+ if (options.lenient) {
58
+ return true;
59
+ }
60
+
61
+ // standard criteria
62
+ // 1. it must be a left click
63
+ if (event.button !== 0) {
64
+ return false;
65
+ }
66
+ // 2. event default must not be prevented
67
+ if (event.defaultPrevented) {
68
+ return false;
69
+ }
70
+ // 3. must go through a real link
71
+ if (!(0, _commons.findInAncestors)(event.target, element => element.tagName === 'A' && element.href || undefined)) {
72
+ return false;
73
+ }
74
+ return true;
75
+ }
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _commons = require("@miso.ai/commons");
8
+ class Viewables {
9
+ constructor() {
10
+ this._entries = new WeakMap();
11
+ }
12
+ isTracked(element) {
13
+ return this._entries.has(element);
14
+ }
15
+ async track(element) {
16
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
17
+ if (!options) {
18
+ return false;
19
+ }
20
+ const entry = this._entries.get(element);
21
+ if (entry) {
22
+ return false;
23
+ }
24
+ const ac = new AbortController();
25
+ const {
26
+ signal
27
+ } = ac;
28
+ this._entries.set(element, {
29
+ ac
30
+ });
31
+ let result = false;
32
+ try {
33
+ await (0, _commons.viewable)(element, Object.assign({}, options, {
34
+ signal
35
+ }));
36
+ result = true;
37
+ } catch (e) {
38
+ if (e.name !== 'AbortError') {
39
+ throw e;
40
+ }
41
+ } finally {
42
+ this._entries.delete(element);
43
+ }
44
+ return result;
45
+ }
46
+ untrack(element) {
47
+ const entry = this._entries.get(element);
48
+ if (!entry) {
49
+ return;
50
+ }
51
+ entry.ac.abort();
52
+ this._entries.delete(element);
53
+ }
54
+ }
55
+ exports.default = Viewables;
@@ -4,4 +4,4 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _default = exports.default = '1.10.0-beta.9';
7
+ var _default = exports.default = '1.10.1-beta.0';
@@ -67,12 +67,8 @@ const DEFAULT_LAYOUTS = Object.freeze({
67
67
  const DEFAULT_TRACKERS = Object.freeze({
68
68
  [_constants.ROLE.SOURCES]: {},
69
69
  [_constants.ROLE.RELATED_RESOURCES]: {},
70
- [_constants.ROLE.AFFILIATION]: {
71
- viewable: false // track viewable manually
72
- },
70
+ [_constants.ROLE.AFFILIATION]: {},
73
71
  [_constants.ROLE.QUERY_SUGGESTIONS]: {
74
- active: true,
75
- // we are tracking events at initial stage, when session is not active yet
76
72
  click: {
77
73
  validate: event => event.button === 0 // left click only
78
74
  }
@@ -65,7 +65,7 @@ class Workflow extends _commons.Component {
65
65
  source: sources.api(client),
66
66
  options
67
67
  });
68
- const views = this._views = new _index.ViewsActor(hub, {
68
+ this._views = new _index.ViewsActor(hub, {
69
69
  extensions,
70
70
  layouts,
71
71
  roles,
@@ -76,10 +76,6 @@ class Workflow extends _commons.Component {
76
76
  client,
77
77
  options
78
78
  });
79
- this._trackers = new _index.Trackers(hub, {
80
- views,
81
- options
82
- });
83
79
  this._unsubscribes = [this._hub.on(_index.fields.response(), data => this.updateData(data))];
84
80
  }
85
81
  get uuid() {
@@ -171,7 +167,7 @@ class Workflow extends _commons.Component {
171
167
 
172
168
  // trackers //
173
169
  get trackers() {
174
- return this._trackers;
170
+ return this._views.trackers;
175
171
  }
176
172
  _preprocessInteraction() {
177
173
  let _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
@@ -209,7 +205,6 @@ class Workflow extends _commons.Component {
209
205
  unsubscribe();
210
206
  }
211
207
  this._unsubscribes = [];
212
- this._trackers._destroy();
213
208
  this._views._destroy({
214
209
  dom
215
210
  });
@@ -57,6 +57,8 @@ class Recommendation extends _base.default {
57
57
  }));
58
58
  return this;
59
59
  }
60
+
61
+ // TODO: deprecate this
60
62
  startTracker() {
61
63
  this.useApi(false);
62
64
  this.useLayouts(false);
package/package.json CHANGED
@@ -26,7 +26,7 @@
26
26
  "url": "https://github.com/MisoAI/miso-client-js-sdk/issues"
27
27
  },
28
28
  "dependencies": {
29
- "@miso.ai/commons": "1.10.0-beta.9"
29
+ "@miso.ai/commons": "1.10.1-beta.0"
30
30
  },
31
- "version": "1.10.0-beta.9"
31
+ "version": "1.10.1-beta.0"
32
32
  }
@@ -5,7 +5,6 @@ export { default as Hub } from './hub.js';
5
5
  export { default as SessionMaker } from './sessions.js';
6
6
  export { default as DataActor } from './data.js';
7
7
  export { default as ViewsActor } from './views.js';
8
- export { default as Trackers } from './trackers.js';
9
8
  export { default as FeedbackActor } from './feedback.js';
10
9
  export { default as AutocompleteActor } from './autocomplete.js';
11
10
  export { default as InteractionsActor } from './interactions.js';
@@ -1,98 +1,55 @@
1
- import { STATUS, ATTR_DATA_MISO_PRODUCT_ID, EVENT_TYPE } from '../constants.js';
1
+ import { asArray } from '@miso.ai/commons';
2
+ import { TRACKING_EVENT_TYPES, TRACKING_STATUS, validateEventType } from '../constants.js';
2
3
  import * as fields from './fields.js';
3
- import _Tracker from '../util/tracker.js';
4
- import { fallbackListFunction } from '../util/bindings.js';
4
+ import States from '../util/states.js';
5
5
  import { toInteraction } from './utils.js';
6
6
 
7
- function isReady(viewState) {
8
- return viewState && viewState.status === STATUS.READY;
9
- }
10
-
11
7
  export default class Tracker {
12
8
 
13
- constructor(hub, view, { active, bindings, ...options } = {}) {
14
- this._hub = hub;
9
+ constructor(view) {
15
10
  this._view = view;
16
- this._bindings = bindings;
17
- const role = this._role = view.role;
11
+ this._role = view.role;
18
12
  // TODO: know item type
19
13
 
20
- this._tracker = new _Tracker({
21
- bindings: {
22
- list: element => this._listBindingsFn()(element),
23
- },
24
- proxyElement: view.proxyElement,
25
- sessionId: () => this._getSessionId(),
26
- active: active || (() => this._isViewReady()),
27
- ...options,
28
- });
29
-
30
- this._unsubscribes = [
31
- this._tracker.on('*', data => this._handleEvent(data)),
32
- // TODO: view actor has another click event that does not comply to this data format
33
- ...[EVENT_TYPE.VIEWABLE].map(type => this._view.on(type, values => this._handleViewActorEvent(type, values))),
34
- hub.on(fields.view(role), () => this.refresh()),
35
- ];
36
-
37
- this.refresh();
38
- }
39
-
40
- config(options) {
41
- this._tracker.config(options);
14
+ this._states = new States(this._getSessionId());
42
15
  }
43
16
 
44
- start() {
45
- throw new Error(`workflow.tracker.start() is deprecated. Use workflow.startTracker() instead.`);
17
+ get options() {
18
+ return this._view._getTrackerOptions();
46
19
  }
47
20
 
48
- refresh() {
49
- this._tracker.refresh();
21
+ getState(item) {
22
+ return this._states.getFullState(item);
50
23
  }
51
24
 
52
- impression(productIds, options) {
53
- this._assertViewReady();
54
- this._tracker.impression(productIds.map(product_id => ({ product_id })), options);
55
- }
25
+ _trigger(type, items, meta = {}) {
26
+ validateEventType(type);
27
+ this._syncSession();
56
28
 
57
- viewable(productIds, options) {
58
- this._assertViewReady();
59
- this._tracker.viewable(productIds.map(product_id => ({ product_id })), options);
60
- }
29
+ items = this._states.untriggered(asArray(items), type);
30
+ if (items.length === 0) {
31
+ return;
32
+ }
33
+ this._states.set(items, type, TRACKING_STATUS.TRIGGERED);
61
34
 
62
- click(productIds, options) {
63
- this._assertViewReady();
64
- this._tracker.click(productIds.map(product_id => ({ product_id })), options);
65
- }
35
+ const property = this._role === 'results' ? 'products' : this._role; // TODO: ad-hoc, see #83
36
+ const misoId = this._getMisoId();
37
+ const request = this._getRequestPayload();
66
38
 
67
- _listBindingsFn() {
68
- if (this._bindings && typeof this._bindings.list === 'function') {
69
- return this._bindings.list;
70
- }
71
- const { layout } = this._view;
72
- if (layout && layout.bindings && typeof layout.bindings.list === 'function') {
73
- return layout.bindings.list;
74
- }
75
- // TODO: only if item is product typed
76
- return fallbackListFunction(ATTR_DATA_MISO_PRODUCT_ID);
39
+ // TODO: should trigger 'tracker' and let workflow translate to interactions
40
+ this._view.hub.trigger(fields.interaction(), toInteraction({ property, misoId, request }, { event: type, values: items, meta }));
77
41
  }
78
42
 
79
- _assertViewReady() {
80
- if (!this._hub.active) {
81
- throw new Error(`Workflow is not active. Call workflow.start() to activate it.`);
43
+ _syncSession() {
44
+ const sessionId = this._getSessionId();
45
+ if (!sessionId) {
46
+ return;
82
47
  }
83
- if (!isReady(this._getViewState())) {
84
- throw new Error(`Workflow is not rendered yet. If you handle rendering by yourself, call workflow.notifyViewUpdate() when DOM is ready.`);
48
+ if (!this._states || sessionId !== this._states.sessionId) {
49
+ this._states = new States(sessionId);
85
50
  }
86
51
  }
87
52
 
88
- _getViewState() {
89
- return this._hub.states[fields.view(this._role)];
90
- }
91
-
92
- _isViewReady() {
93
- return this._hub.active && isReady(this._getViewState());
94
- }
95
-
96
53
  _getSessionId() {
97
54
  const { session } = this._getViewState() || {};
98
55
  return session && session.uuid;
@@ -100,7 +57,7 @@ export default class Tracker {
100
57
 
101
58
  _getMisoId() {
102
59
  const state = this._getViewState();
103
- return (state && state.meta && state.meta.miso_id) || (this._element && this._element.getAttribute('miso-id')) || undefined;
60
+ return (state && state.meta && state.meta.miso_id) || undefined;
104
61
  }
105
62
 
106
63
  _getRequestPayload() {
@@ -108,28 +65,14 @@ export default class Tracker {
108
65
  return request && request.payload;
109
66
  }
110
67
 
111
- getState(productId) {
112
- return this._tracker.getState(productId);
113
- }
114
-
115
- _handleViewActorEvent(type, values) {
116
- this._tracker._trigger(type, values);
117
- }
118
-
119
- _handleEvent(data) {
120
- const property = this._role === 'results' ? 'products' : this._role; // TODO: ad-hoc, see #83
121
- const misoId = this._getMisoId();
122
- const request = this._getRequestPayload();
123
- // TODO: should trigger 'tracker' and let workflow translate to interactions
124
- this._hub.trigger(fields.interaction(), toInteraction({ property, misoId, request }, data));
68
+ _getViewState() {
69
+ return this._view.hub.states[fields.view(this._role)];
125
70
  }
126
71
 
127
- _destroy() {
128
- for (const unsubscribe of this._unsubscribes) {
129
- unsubscribe();
130
- }
131
- this._unsubscribes = [];
132
- this._tracker.destroy();
133
- }
72
+ }
134
73
 
74
+ for (const type of TRACKING_EVENT_TYPES) {
75
+ Tracker.prototype[type] = function(items, meta) {
76
+ this._trigger(type, items, meta);
77
+ };
135
78
  }
@@ -22,7 +22,7 @@ export function toInteraction({ property, misoId, request }, { event, values, ma
22
22
  // TODO: ad-hoc
23
23
  const question_source = request && request._meta && request._meta.question_source;
24
24
  const isProductType = isProduct(property);
25
- const product_ids = isProductType ? values.map(v => v.product_id).filter(v => v) : [];
25
+ const product_ids = isProductType ? values.map(v => typeof v === 'string' ? v : v.product_id).filter(v => v) : [];
26
26
  const items = isProductType ? undefined : values.map(v => v.text || v.id || v);
27
27
  const channel = property === ROLE.AFFILIATION ? values[0] && values[0].channel : undefined;
28
28
  const positions = property === ROLE.AFFILIATION ? values.map(v => v.position) : undefined;
package/src/actor/view.js CHANGED
@@ -2,6 +2,7 @@ import { trimObj, defineValues, delegateGetters, EventEmitter } from '@miso.ai/c
2
2
  import { STATUS, ROLE, isDataRole } from '../constants.js';
3
3
  import * as fields from './fields.js';
4
4
  import ProxyElement from '../util/proxy.js';
5
+ import Tracker from './tracker.js';
5
6
 
6
7
  function statesEqual(a, b) {
7
8
  return a === b || (a && b &&
@@ -85,6 +86,13 @@ export default class ViewActor {
85
86
  this.refresh({ force: true });
86
87
  }
87
88
 
89
+ get tracker() {
90
+ if (!this._tracker) {
91
+ this._tracker = new Tracker(this);
92
+ }
93
+ return this._tracker;
94
+ }
95
+
88
96
  async refresh({ force = false, data } = {}) {
89
97
  // protocol: no reaction when layout is absent
90
98
  if (!this._layout) {
@@ -134,6 +142,11 @@ export default class ViewActor {
134
142
  this.hub.update(fields.view(role), state, { silent });
135
143
  }
136
144
 
145
+ _getTrackerOptions() {
146
+ // used by tracker to expose tracker options to layout
147
+ return this._views._getTrackerOptions(this.role);
148
+ }
149
+
137
150
  _sliceData({ value, error, status, meta, ...rest }) {
138
151
  const sliced = {
139
152
  value: this.role === ROLE.ERROR ? error : (value && value[this.role]),
@@ -205,7 +218,7 @@ export default class ViewActor {
205
218
  class View {
206
219
 
207
220
  constructor(actor) {
208
- delegateGetters(this, actor, ['role', 'layout', 'element', 'proxyElement', 'refresh', 'on']);
221
+ delegateGetters(this, actor, ['role', 'layout', 'element', 'proxyElement', 'refresh', 'on', 'tracker']);
209
222
  }
210
223
 
211
224
  }
@@ -2,6 +2,7 @@ import { defineValues, delegateGetters } from '@miso.ai/commons';
2
2
  import { STATUS, ROLE } from '../constants.js';
3
3
  import * as fields from './fields.js';
4
4
  import ViewActor from './view.js';
5
+ import { normalizeTrackerOptions } from '../util/trackers.js';
5
6
 
6
7
  export default class ViewsActor {
7
8
 
@@ -19,6 +20,7 @@ export default class ViewsActor {
19
20
  this._options = options;
20
21
  this._containers = new Map();
21
22
  this._views = {};
23
+ this._trackers = new Trackers(this, roles);
22
24
 
23
25
  for (const role of roles) {
24
26
  this._views[role] = new ViewActor(this, role);
@@ -34,12 +36,18 @@ export default class ViewsActor {
34
36
  this._unsubscribes = [
35
37
  () => window.removeEventListener('resize', syncSize),
36
38
  hub.on(fields.data(), () => this.refresh()),
39
+ options.on('trackers', () => this._syncTrackers()),
37
40
  options.on('layouts', () => this._syncLayouts()),
38
41
  ];
39
42
 
43
+ this._syncTrackers();
40
44
  this._syncLayouts();
41
45
  }
42
46
 
47
+ get trackers() {
48
+ return this._trackers;
49
+ }
50
+
43
51
  // elements //
44
52
  addContainer(element) {
45
53
  if (this._containers.has(element)) {
@@ -185,6 +193,14 @@ export default class ViewsActor {
185
193
  return this._data;
186
194
  }
187
195
 
196
+ _syncTrackers() {
197
+ this._trackerOptions = this._options.resolved.trackers;
198
+ }
199
+
200
+ _getTrackerOptions(role) {
201
+ return normalizeTrackerOptions((this._trackerOptions && this._trackerOptions[role]) || false);
202
+ }
203
+
188
204
  _error(e) {
189
205
  // TODO: hub trigger error event
190
206
  console.error(e);
@@ -208,7 +224,7 @@ class Views {
208
224
 
209
225
  constructor(actor) {
210
226
  this._actor = actor;
211
- delegateGetters(this, actor, ['syncSize', 'refresh']);
227
+ delegateGetters(this, actor, ['syncSize', 'refresh', 'trackers']);
212
228
  }
213
229
 
214
230
  get(role) {
@@ -220,3 +236,16 @@ class Views {
220
236
  }
221
237
 
222
238
  }
239
+
240
+ class Trackers {
241
+
242
+ constructor(views, roles) {
243
+ this._views = views;
244
+ for (const role of roles) {
245
+ Object.defineProperty(this, role, {
246
+ get: () => views.get(role).tracker,
247
+ });
248
+ }
249
+ }
250
+
251
+ }
package/src/asset/svgs.js CHANGED
@@ -1,13 +1,23 @@
1
1
  import version from '../version.js';
2
2
 
3
+ function trianglePath(r) {
4
+ const l = 100;
5
+ const d = r * Math.tan(3 * Math.PI / 8);
6
+ const e = d * Math.sin(Math.PI / 4);
7
+ return `M${r} 0L${l-d} 0A${r} ${r} 0 0 1 ${l-e} ${e}L${e} ${l-e}A${r} ${r} 0 0 1 0 ${l-d}L0 ${r}Z`;
8
+ }
9
+
3
10
  const PREFIX = 'miso-ui-icon';
4
11
  const ID = `${PREFIX}-svg-${version.replaceAll('.', '_')}`;
5
12
 
6
- // all are CC0 SVGs
13
+ // CC0 SVGs
7
14
  const ICON_SEND = `<symbol id="${PREFIX}-send" viewBox="0 0 32 32"><path fill="currentColor" d="M11.499,19.173l5.801,-5.849c0.389,-0.392 1.022,-0.394 1.414,-0.006c0.392,0.389 0.395,1.022 0.006,1.414l-5.798,5.847l5.306,8.002c0.207,0.313 0.572,0.483 0.945,0.441c0.373,-0.042 0.691,-0.289 0.824,-0.64l9.024,-23.904c0.138,-0.366 0.05,-0.78 -0.226,-1.058c-0.276,-0.278 -0.689,-0.369 -1.057,-0.233l-24.004,8.892c-0.353,0.13 -0.602,0.448 -0.646,0.821c-0.044,0.373 0.125,0.74 0.438,0.948l7.973,5.325Z"/></symbol>`;
8
15
  const ICON_SEARCH = `<symbol id="${PREFIX}-search" viewBox="0 0 24 24"><path fill="currentColor" d="M4 11C4 7.13401 7.13401 4 11 4C14.866 4 18 7.13401 18 11C18 14.866 14.866 18 11 18C7.13401 18 4 14.866 4 11ZM11 2C6.02944 2 2 6.02944 2 11C2 15.9706 6.02944 20 11 20C13.125 20 15.078 19.2635 16.6177 18.0319L20.2929 21.7071C20.6834 22.0976 21.3166 22.0976 21.7071 21.7071C22.0976 21.3166 22.0976 20.6834 21.7071 20.2929L18.0319 16.6177C19.2635 15.078 20 13.125 20 11C20 6.02944 15.9706 2 11 2Z"/></symbol>`;
9
16
 
10
- const ICONS = [ICON_SEND, ICON_SEARCH];
17
+ // Custom SVGs
18
+ const ICON_TRIANGLE = `<symbol id="${PREFIX}-triangle" viewBox="-5 -5 105 105"><path d="${trianglePath(5)}"/></symbol>`;
19
+
20
+ const ICONS = [ICON_SEND, ICON_SEARCH, ICON_TRIANGLE];
11
21
 
12
22
  const SPRITES_SVG = `<svg id="${ID}" style="display:none;">${ICONS.join('')}</svg>`;
13
23
 
@@ -29,3 +39,4 @@ function getSvg(name) {
29
39
 
30
40
  export const SEND = getSvg('send');
31
41
  export const SEARCH = getSvg('search');
42
+ export const TRIANGLE = getSvg('triangle');
package/src/constants.js CHANGED
@@ -59,6 +59,12 @@ export const EVENT_TYPE = Object.freeze({
59
59
  CLICK: 'click',
60
60
  });
61
61
 
62
+ export const TRACKING_EVENT_TYPES = [
63
+ EVENT_TYPE.IMPRESSION,
64
+ EVENT_TYPE.VIEWABLE,
65
+ EVENT_TYPE.CLICK,
66
+ ];
67
+
62
68
  export const TRACKING_STATUS = Object.freeze({
63
69
  UNTRACKED: 'untracked',
64
70
  TRACKING: 'tracking',
@@ -77,7 +83,7 @@ export const STATUS = Object.freeze({
77
83
  });
78
84
 
79
85
  export function validateEventType(value) {
80
- if (value !== EVENT_TYPE.IMPRESSION && value !== EVENT_TYPE.VIEWABLE && value !== EVENT_TYPE.CLICK) {
86
+ if (TRACKING_EVENT_TYPES.indexOf(value) < 0) {
81
87
  throw new Error(`Unrecognized event type: ${value}`);
82
88
  }
83
89
  }