@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.
- package/dist/cjs/actor/index.js +0 -7
- package/dist/cjs/actor/tracker.js +47 -102
- package/dist/cjs/actor/utils.js +1 -1
- package/dist/cjs/actor/view.js +12 -1
- package/dist/cjs/actor/views.js +24 -2
- package/dist/cjs/asset/svgs.js +14 -4
- package/dist/cjs/constants.js +3 -2
- package/dist/cjs/layout/affiliation/affiliation.js +152 -58
- package/dist/cjs/layout/input/option-list.js +34 -49
- package/dist/cjs/layout/list/collection.js +22 -43
- package/dist/cjs/layout/templates.js +54 -32
- package/dist/cjs/layout/text/typewriter/index.js +12 -7
- package/dist/cjs/layout/trackable.js +124 -0
- package/dist/cjs/util/bindings.js +58 -110
- package/dist/cjs/util/states.js +31 -24
- package/dist/cjs/util/trackers.js +75 -0
- package/dist/cjs/util/viewables.js +55 -0
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/workflow/ask.js +1 -5
- package/dist/cjs/workflow/base.js +2 -7
- package/dist/cjs/workflow/recommendation.js +2 -0
- package/package.json +2 -2
- package/src/actor/index.js +0 -1
- package/src/actor/tracker.js +37 -94
- package/src/actor/utils.js +1 -1
- package/src/actor/view.js +14 -1
- package/src/actor/views.js +30 -1
- package/src/asset/svgs.js +13 -2
- package/src/constants.js +7 -1
- package/src/layout/affiliation/affiliation.js +140 -55
- package/src/layout/input/option-list.js +35 -43
- package/src/layout/list/collection.js +20 -38
- package/src/layout/templates.js +25 -19
- package/src/layout/text/typewriter/index.js +8 -6
- package/src/layout/trackable.js +106 -0
- package/src/util/bindings.js +47 -103
- package/src/util/states.js +26 -20
- package/src/util/trackers.js +69 -0
- package/src/util/viewables.js +47 -0
- package/src/version.js +1 -1
- package/src/workflow/ask.js +1 -4
- package/src/workflow/base.js +3 -5
- package/src/workflow/recommendation.js +1 -0
- package/dist/cjs/actor/trackers.js +0 -51
- package/dist/cjs/layout/affiliation/viewable.js +0 -65
- package/dist/cjs/layout/text/typewriter/progress.js +0 -45
- package/dist/cjs/util/tracker.js +0 -348
- package/src/actor/trackers.js +0 -45
- package/src/layout/affiliation/viewable.js +0 -61
- package/src/layout/text/typewriter/progress.js +0 -33
- package/src/util/tracker.js +0 -318
package/src/util/tracker.js
DELETED
|
@@ -1,318 +0,0 @@
|
|
|
1
|
-
import { EventEmitter, isElement, findInAncestors, trimObj, asArray, viewable as whenViewable } from '@miso.ai/commons';
|
|
2
|
-
import { EVENT_TYPE, TRACKING_STATUS, validateEventType } from '../constants.js';
|
|
3
|
-
import { Bindings } from './bindings.js';
|
|
4
|
-
import States from './states.js';
|
|
5
|
-
import ProxyElement from './proxy.js';
|
|
6
|
-
|
|
7
|
-
const { IMPRESSION, VIEWABLE, CLICK } = EVENT_TYPE;
|
|
8
|
-
const { UNTRACKED, TRACKING, TRIGGERED } = TRACKING_STATUS;
|
|
9
|
-
|
|
10
|
-
const DEFAULT_TRACKING_OPTIONS = Object.freeze({
|
|
11
|
-
impression: Object.freeze({
|
|
12
|
-
}),
|
|
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
|
-
|
|
23
|
-
function mergeOptions(def, opt) {
|
|
24
|
-
// if opt is falsy then return false, merge otherwise
|
|
25
|
-
return !!opt && { ...def, ...opt };
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function normalizeOptions(options) {
|
|
29
|
-
if (options === false) {
|
|
30
|
-
return false; // turn off all tracking
|
|
31
|
-
}
|
|
32
|
-
if (options === true) {
|
|
33
|
-
options = {};
|
|
34
|
-
}
|
|
35
|
-
if (typeof options !== 'object') {
|
|
36
|
-
throw new Error(`Invalid options: ${options}`);
|
|
37
|
-
}
|
|
38
|
-
const { impression = {}, viewable = {}, click = {}, ...rest } = options;
|
|
39
|
-
return trimObj({
|
|
40
|
-
...DEFAULT_TRACKING_OPTIONS,
|
|
41
|
-
...rest,
|
|
42
|
-
impression: mergeOptions(DEFAULT_TRACKING_OPTIONS.impression, impression),
|
|
43
|
-
viewable: mergeOptions(DEFAULT_TRACKING_OPTIONS.viewable, viewable),
|
|
44
|
-
click: mergeOptions(DEFAULT_TRACKING_OPTIONS.click, click),
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export default class Tracker {
|
|
49
|
-
|
|
50
|
-
constructor({
|
|
51
|
-
proxyElement,
|
|
52
|
-
element,
|
|
53
|
-
sessionId = 'default',
|
|
54
|
-
active = true,
|
|
55
|
-
bindings,
|
|
56
|
-
...options
|
|
57
|
-
} = {}) {
|
|
58
|
-
this._events = new EventEmitter({ target: this });
|
|
59
|
-
this._proxyElement = proxyElement || new ProxyElement(element);
|
|
60
|
-
this._getSessionId = typeof sessionId === 'function' ? sessionId : () => sessionId;
|
|
61
|
-
this._isActive = typeof active === 'function' ? active : () => active;
|
|
62
|
-
this._bindings = new Bindings(bindings);
|
|
63
|
-
this._viewables = new WeakMap();
|
|
64
|
-
this._options = normalizeOptions(options);
|
|
65
|
-
|
|
66
|
-
this._unsubscribes = [
|
|
67
|
-
this._proxyElement.on('click', event => this._handleClick(event)),
|
|
68
|
-
this._proxyElement.on('element', () => this.refresh()),
|
|
69
|
-
];
|
|
70
|
-
|
|
71
|
-
this.refresh();
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
get active() {
|
|
75
|
-
return this._isActive();
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
config(options) {
|
|
79
|
-
this._options = normalizeOptions(options);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
refresh() {
|
|
83
|
-
// refresh against root element
|
|
84
|
-
this._syncElement();
|
|
85
|
-
// refresh against view state
|
|
86
|
-
this._syncStates();
|
|
87
|
-
// refresh bindings
|
|
88
|
-
this._refreshBindings();
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
_syncStates() {
|
|
92
|
-
const sessionId = this._getSessionId();
|
|
93
|
-
if (!sessionId) {
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
if (this._states && sessionId !== this._states.sessionId) {
|
|
97
|
-
this._retireStates();
|
|
98
|
-
}
|
|
99
|
-
if (!this._states && sessionId) {
|
|
100
|
-
this._states = new States(sessionId);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
impression(values, options) {
|
|
105
|
-
this._assertActive();
|
|
106
|
-
if (this._options && this._options.impression) {
|
|
107
|
-
this._trigger(IMPRESSION, values, { manual: true, ...options });
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
viewable(values, options) {
|
|
112
|
-
this._assertActive();
|
|
113
|
-
if (this._options && this._options.viewable) {
|
|
114
|
-
this._trigger(VIEWABLE, values, { manual: true, ...options });
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
click(values, options) {
|
|
119
|
-
this._assertActive();
|
|
120
|
-
if (this._options && this._options.click) {
|
|
121
|
-
this._trigger(CLICK, values, { manual: true, ...options });
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
_assertActive() {
|
|
126
|
-
if (!this._isActive()) {
|
|
127
|
-
throw new Error(`Tracker is not active.`);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
getState(value) {
|
|
132
|
-
// TODO: do we have to be so precise?
|
|
133
|
-
return Object.freeze({
|
|
134
|
-
[CLICK]: this._proxyElement.current ? TRACKING : UNTRACKED,
|
|
135
|
-
...this._states.getFullState(value),
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
_syncElement() {
|
|
142
|
-
this._proxyElement.sync({ silent: true });
|
|
143
|
-
const element = this._proxyElement.current;
|
|
144
|
-
if (this._element === element) {
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
// remove observer from old element
|
|
148
|
-
this._retireElement();
|
|
149
|
-
|
|
150
|
-
// add observer on new element
|
|
151
|
-
if (element) {
|
|
152
|
-
if (this._options && this._options.watch) {
|
|
153
|
-
// TODO: move to proxy element
|
|
154
|
-
this._mutationObserver = new MutationObserver(() => this.refresh());
|
|
155
|
-
this._mutationObserver.observe(element, { childList: true, subtree: true });
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
this._element = element;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
_retireElement() {
|
|
162
|
-
if (!this._element) {
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
if (this._mutationObserver) {
|
|
166
|
-
this._mutationObserver.disconnect();
|
|
167
|
-
this._mutationObserver = undefined;
|
|
168
|
-
}
|
|
169
|
-
this._element = undefined;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
_retireStates() {
|
|
173
|
-
const { unbounds } = this._bindings.unbindAll();
|
|
174
|
-
this._untrackViewables(unbounds);
|
|
175
|
-
this._states = undefined;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
_refreshBindings() {
|
|
179
|
-
if (!this._states) {
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
const element = this._proxyElement.current;
|
|
183
|
-
const { bounds, unbounds } = this._bindings.refresh(element);
|
|
184
|
-
this._untrackViewables(unbounds);
|
|
185
|
-
this._trackImpressions(bounds);
|
|
186
|
-
this._trackViewables(bounds);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
// impression //
|
|
192
|
-
_trackImpressions(bindings) {
|
|
193
|
-
const options = this._options && this._options.impression;
|
|
194
|
-
if (!options) {
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
this._trigger(IMPRESSION, bindings.map(b => b.value), { bindings });
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
// viewable //
|
|
203
|
-
_trackViewables(bindings) {
|
|
204
|
-
const options = this._options && this._options.viewable;
|
|
205
|
-
if (!options) {
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
for (const binding of bindings) {
|
|
209
|
-
this._trackViewableOnElement(binding);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
async _trackViewableOnElement(binding) {
|
|
214
|
-
const { value, element } = binding;
|
|
215
|
-
if (!value || !isElement(element) || this._viewables.has(element)) {
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
// TODO: when element is replaced without proper unload...
|
|
219
|
-
const state = this._states.get(value, VIEWABLE);
|
|
220
|
-
if (state !== UNTRACKED) {
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
223
|
-
this._states.set(value, VIEWABLE, TRACKING);
|
|
224
|
-
|
|
225
|
-
const { area, duration } = this._options && this._options.viewable;
|
|
226
|
-
// abort signal
|
|
227
|
-
const ac = new AbortController();
|
|
228
|
-
const { signal } = ac;
|
|
229
|
-
this._viewables.set(element, { ac });
|
|
230
|
-
await whenViewable(element, { area, duration, signal });
|
|
231
|
-
this._viewables.delete(element);
|
|
232
|
-
this._trigger(VIEWABLE, [value], { bindings: [binding] });
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
_untrackViewableOnElement({ value, element }) {
|
|
236
|
-
const viewable = this._viewables.get(element);
|
|
237
|
-
if (!viewable) {
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
viewable.ac.abort();
|
|
241
|
-
this._viewables.delete(element);
|
|
242
|
-
const type = VIEWABLE;
|
|
243
|
-
if (this._states.get(value, type) === TRACKING) {
|
|
244
|
-
this._states.set(value, type, UNTRACKED);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
_untrackViewables(bindings) {
|
|
249
|
-
for (const binding of bindings) {
|
|
250
|
-
this._untrackViewableOnElement(binding);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
// click //
|
|
257
|
-
_handleClick(event) {
|
|
258
|
-
const options = this._options && this._options.click;
|
|
259
|
-
if (!options || !this._isActive()) {
|
|
260
|
-
return;
|
|
261
|
-
}
|
|
262
|
-
const binding = this._bindings.get(event.target);
|
|
263
|
-
if (!binding) {
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// TODO: refactor
|
|
268
|
-
if (typeof options.validate === 'function') {
|
|
269
|
-
if (!options.validate(event, binding)) {
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
} else if (!options.lenient) {
|
|
273
|
-
// it must be a left click
|
|
274
|
-
if (event.button !== 0) {
|
|
275
|
-
return;
|
|
276
|
-
}
|
|
277
|
-
// event default must not be prevented
|
|
278
|
-
if (event.defaultPrevented) {
|
|
279
|
-
return;
|
|
280
|
-
}
|
|
281
|
-
// must go through a real link
|
|
282
|
-
if (!findInAncestors(event.target, element => (element.tagName === 'A' && element.href) || undefined)) {
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
this._trigger(CLICK, [binding.value], { bindings: [binding] });
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
_trigger(event, values, { manual = false, bindings } = {}) {
|
|
292
|
-
validateEventType(event);
|
|
293
|
-
|
|
294
|
-
if (!this._isActive()) {
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// ignore already triggered
|
|
299
|
-
values = this._states.untriggered(asArray(values), event);
|
|
300
|
-
|
|
301
|
-
if (values.length === 0) {
|
|
302
|
-
return;
|
|
303
|
-
}
|
|
304
|
-
this._states.set(values, event, TRIGGERED);
|
|
305
|
-
this._events.emit(event, { event, values, manual, bindings });
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
destroy() {
|
|
309
|
-
this._retireElement();
|
|
310
|
-
this._retireStates();
|
|
311
|
-
this._bindings._destroy();
|
|
312
|
-
for (const unsubscribe of this._unsubscribes) {
|
|
313
|
-
unsubscribe();
|
|
314
|
-
}
|
|
315
|
-
this._unsubscribes = [];
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
}
|