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

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 (78) hide show
  1. package/dist/cjs/actor/data.js +1 -1
  2. package/dist/cjs/actor/tracker.js +46 -70
  3. package/dist/cjs/actor/trackers.js +5 -1
  4. package/dist/cjs/actor/utils.js +6 -2
  5. package/dist/cjs/actor/view.js +14 -3
  6. package/dist/cjs/actor/views.js +9 -1
  7. package/dist/cjs/affiliation/index.js +126 -0
  8. package/dist/cjs/combo/ask/options.js +1 -1
  9. package/dist/cjs/combo/base.js +1 -1
  10. package/dist/cjs/constants.js +6 -3
  11. package/dist/cjs/defaults/ask/controls.js +1 -1
  12. package/dist/cjs/defaults/ask/phrases.js +1 -1
  13. package/dist/cjs/defaults/ask/templates.js +14 -4
  14. package/dist/cjs/element/role/index.js +7 -0
  15. package/dist/cjs/element/role/miso-affiliation.js +20 -0
  16. package/dist/cjs/layout/affiliation/affiliation.js +330 -0
  17. package/dist/cjs/layout/banner/banner.js +1 -1
  18. package/dist/cjs/layout/container/container.js +1 -1
  19. package/dist/cjs/layout/error/error.js +1 -1
  20. package/dist/cjs/layout/index.js +7 -0
  21. package/dist/cjs/layout/input/option-list.js +35 -50
  22. package/dist/cjs/layout/input/search-box.js +17 -5
  23. package/dist/cjs/layout/list/cards.js +1 -1
  24. package/dist/cjs/layout/list/carousel.js +5 -3
  25. package/dist/cjs/layout/list/collection.js +38 -48
  26. package/dist/cjs/layout/list/list.js +1 -1
  27. package/dist/cjs/layout/radio/feedback.js +1 -1
  28. package/dist/cjs/layout/radio/radio.js +1 -1
  29. package/dist/cjs/layout/raf.js +1 -1
  30. package/dist/cjs/layout/template.js +1 -1
  31. package/dist/cjs/layout/templates.js +135 -44
  32. package/dist/cjs/layout/text/text.js +1 -1
  33. package/dist/cjs/layout/text/typewriter/index.js +3 -3
  34. package/dist/cjs/layout/trackable.js +124 -0
  35. package/dist/cjs/plugin.js +1 -1
  36. package/dist/cjs/util/bindings.js +58 -110
  37. package/dist/cjs/util/states.js +31 -24
  38. package/dist/cjs/util/trackers.js +75 -0
  39. package/dist/cjs/util/viewables.js +55 -0
  40. package/dist/cjs/version.js +1 -1
  41. package/dist/cjs/workflow/ask.js +14 -5
  42. package/dist/cjs/workflow/asks.js +1 -1
  43. package/dist/cjs/workflow/base.js +5 -5
  44. package/dist/cjs/workflow/explore.js +1 -1
  45. package/dist/cjs/workflow/options.js +6 -1
  46. package/dist/cjs/workflow/recommendation.js +2 -0
  47. package/package.json +2 -2
  48. package/src/actor/tracker.js +39 -62
  49. package/src/actor/trackers.js +3 -1
  50. package/src/actor/utils.js +6 -2
  51. package/src/actor/view.js +12 -1
  52. package/src/actor/views.js +11 -0
  53. package/src/affiliation/index.js +108 -0
  54. package/src/constants.js +10 -1
  55. package/src/defaults/ask/phrases.js +1 -1
  56. package/src/defaults/ask/templates.js +13 -2
  57. package/src/element/role/index.js +1 -0
  58. package/src/element/role/miso-affiliation.js +16 -0
  59. package/src/layout/affiliation/affiliation.js +295 -0
  60. package/src/layout/index.js +1 -0
  61. package/src/layout/input/option-list.js +35 -43
  62. package/src/layout/input/search-box.js +7 -2
  63. package/src/layout/list/carousel.js +4 -2
  64. package/src/layout/list/collection.js +37 -43
  65. package/src/layout/templates.js +101 -26
  66. package/src/layout/text/typewriter/index.js +2 -2
  67. package/src/layout/trackable.js +106 -0
  68. package/src/util/bindings.js +47 -103
  69. package/src/util/states.js +26 -20
  70. package/src/util/trackers.js +69 -0
  71. package/src/util/viewables.js +47 -0
  72. package/src/version.js +1 -1
  73. package/src/workflow/ask.js +7 -3
  74. package/src/workflow/base.js +1 -1
  75. package/src/workflow/options.js +5 -1
  76. package/src/workflow/recommendation.js +1 -0
  77. package/dist/cjs/util/tracker.js +0 -348
  78. package/src/util/tracker.js +0 -318
@@ -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
- }