@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
@@ -4,8 +4,9 @@ import { mergeApiOptions } from './options.js';
4
4
  import * as sources from '../source/index.js';
5
5
  import { fields, FeedbackActor, AutocompleteActor } from '../actor/index.js';
6
6
  import { ROLE, STATUS, ORGANIC_QUESTION_SOURCE } from '../constants.js';
7
- import { SearchBoxLayout, OptionListLayout, ListLayout, TextLayout, TypewriterLayout, FeedbackLayout } from '../layout/index.js';
7
+ import { SearchBoxLayout, OptionListLayout, ListLayout, TextLayout, TypewriterLayout, FeedbackLayout, AffiliationLayout } from '../layout/index.js';
8
8
  import { makeConfigurable } from './options.js';
9
+ import { processData as processAffiliationData } from '../affiliation/index.js';
9
10
 
10
11
  const DEFAULT_API_OPTIONS = Object.freeze({
11
12
  group: API.GROUP.ASK,
@@ -35,13 +36,14 @@ const DEFAULT_LAYOUTS = Object.freeze({
35
36
  [ROLE.SOURCES]: [ListLayout.type, { incremental: true, itemType: 'article', templates: { ordered: true } }],
36
37
  [ROLE.RELATED_RESOURCES]: [ListLayout.type, { incremental: true, itemType: 'article' }],
37
38
  [ROLE.QUERY_SUGGESTIONS]: OptionListLayout.type,
39
+ [ROLE.AFFILIATION]: [AffiliationLayout.type, { incremental: true, itemType: 'affiliation', link: { rel: 'noopener nofollow' } }],
38
40
  });
39
41
 
40
42
  const DEFAULT_TRACKERS = Object.freeze({
41
43
  [ROLE.SOURCES]: {},
42
44
  [ROLE.RELATED_RESOURCES]: {},
45
+ [ROLE.AFFILIATION]: {},
43
46
  [ROLE.QUERY_SUGGESTIONS]: {
44
- active: true, // we are tracking events at initial stage, when session is not active yet
45
47
  click: {
46
48
  validate: event => event.button === 0, // left click only
47
49
  },
@@ -207,6 +209,9 @@ export default class Ask extends Workflow {
207
209
  }
208
210
  }
209
211
 
212
+ // affiliation
213
+ data = processAffiliationData(data);
214
+
210
215
  // 1. put answer_stage to meta
211
216
  // 2. mark ongoing flag
212
217
  return {
@@ -288,7 +293,6 @@ export default class Ask extends Workflow {
288
293
  this._context._byQid.delete(questionId);
289
294
  }
290
295
  this._feedback._destroy();
291
- this._autocomplete._destroy();
292
296
  super._destroy(options);
293
297
  }
294
298
 
@@ -47,8 +47,8 @@ export default class Workflow extends Component {
47
47
  this._sessions = new SessionMaker(hub);
48
48
  this._data = new DataActor(hub, { source: sources.api(client), options });
49
49
  const views = this._views = new ViewsActor(hub, { extensions, layouts, roles, options, workflow: name });
50
- this._interactions = new InteractionsActor(hub, { client, options });
51
50
  this._trackers = new Trackers(hub, { views, options });
51
+ this._interactions = new InteractionsActor(hub, { client, options });
52
52
 
53
53
  this._unsubscribes = [
54
54
  this._hub.on(fields.response(), data => this.updateData(data)),
@@ -11,10 +11,14 @@ export function normalizeApiOptions([name, payload] = []) {
11
11
  payload = name;
12
12
  name = undefined;
13
13
  }
14
+ let group = undefined;
15
+ if (name && name.indexOf('/') !== -1) {
16
+ [group, name] = name.split('/');
17
+ }
14
18
  if ((name && typeof name !== 'string') || (payload !== undefined && typeof payload !== 'object')) {
15
19
  throw new Error(`Invalid arguments for useApi(): ${name}, ${payload}`);
16
20
  }
17
- return trimObj({ name, payload });
21
+ return trimObj({ group, name, payload });
18
22
  }
19
23
 
20
24
  export function normalizeLayoutsOptions(options = {}) {
@@ -53,6 +53,7 @@ export default class Recommendation extends Workflow {
53
53
  return this;
54
54
  }
55
55
 
56
+ // TODO: deprecate this
56
57
  startTracker() {
57
58
  this.useApi(false);
58
59
  this.useLayouts(false);
@@ -1,348 +0,0 @@
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
- var _constants = require("../constants.js");
9
- var _bindings = require("./bindings.js");
10
- var _states = _interopRequireDefault(require("./states.js"));
11
- var _proxy = _interopRequireDefault(require("./proxy.js"));
12
- const _excluded = ["impression", "viewable", "click"],
13
- _excluded2 = ["proxyElement", "element", "sessionId", "active", "bindings"];
14
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
15
- function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.indexOf(n) >= 0) continue; t[n] = r[n]; } return t; }
16
- const {
17
- IMPRESSION,
18
- VIEWABLE,
19
- CLICK
20
- } = _constants.EVENT_TYPE;
21
- const {
22
- UNTRACKED,
23
- TRACKING,
24
- TRIGGERED
25
- } = _constants.TRACKING_STATUS;
26
- const DEFAULT_TRACKING_OPTIONS = Object.freeze({
27
- impression: Object.freeze({}),
28
- viewable: Object.freeze({
29
- area: 0.5,
30
- duration: 1000
31
- }),
32
- click: Object.freeze({
33
- lenient: false
34
- }),
35
- watch: false
36
- });
37
- function mergeOptions(def, opt) {
38
- // if opt is falsy then return false, merge otherwise
39
- return !!opt && Object.assign({}, def, opt);
40
- }
41
- function normalizeOptions(options) {
42
- if (options === false) {
43
- return false; // turn off all tracking
44
- }
45
- if (options === true) {
46
- options = {};
47
- }
48
- if (typeof options !== 'object') {
49
- throw new Error(`Invalid options: ${options}`);
50
- }
51
- const {
52
- impression = {},
53
- viewable = {},
54
- click = {}
55
- } = options,
56
- rest = _objectWithoutPropertiesLoose(options, _excluded);
57
- return (0, _commons.trimObj)(Object.assign({}, DEFAULT_TRACKING_OPTIONS, rest, {
58
- impression: mergeOptions(DEFAULT_TRACKING_OPTIONS.impression, impression),
59
- viewable: mergeOptions(DEFAULT_TRACKING_OPTIONS.viewable, viewable),
60
- click: mergeOptions(DEFAULT_TRACKING_OPTIONS.click, click)
61
- }));
62
- }
63
- class Tracker {
64
- constructor() {
65
- let _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
66
- let {
67
- proxyElement,
68
- element,
69
- sessionId = 'default',
70
- active = true,
71
- bindings
72
- } = _ref,
73
- options = _objectWithoutPropertiesLoose(_ref, _excluded2);
74
- this._events = new _commons.EventEmitter({
75
- target: this
76
- });
77
- this._proxyElement = proxyElement || new _proxy.default(element);
78
- this._getSessionId = typeof sessionId === 'function' ? sessionId : () => sessionId;
79
- this._isActive = typeof active === 'function' ? active : () => active;
80
- this._bindings = new _bindings.Bindings(bindings);
81
- this._viewables = new WeakMap();
82
- this._options = normalizeOptions(options);
83
- this._unsubscribes = [this._proxyElement.on('click', event => this._handleClick(event)), this._proxyElement.on('element', () => this.refresh())];
84
- this.refresh();
85
- }
86
- get active() {
87
- return this._isActive();
88
- }
89
- config(options) {
90
- this._options = normalizeOptions(options);
91
- }
92
- refresh() {
93
- // refresh against root element
94
- this._syncElement();
95
- // refresh against view state
96
- this._syncStates();
97
- // refresh bindings
98
- this._refreshBindings();
99
- }
100
- _syncStates() {
101
- const sessionId = this._getSessionId();
102
- if (!sessionId) {
103
- return;
104
- }
105
- if (this._states && sessionId !== this._states.sessionId) {
106
- this._retireStates();
107
- }
108
- if (!this._states && sessionId) {
109
- this._states = new _states.default(sessionId);
110
- }
111
- }
112
- impression(values, options) {
113
- this._assertActive();
114
- if (this._options && this._options.impression) {
115
- this._trigger(IMPRESSION, values, Object.assign({
116
- manual: true
117
- }, options));
118
- }
119
- }
120
- viewable(values, options) {
121
- this._assertActive();
122
- if (this._options && this._options.viewable) {
123
- this._trigger(VIEWABLE, values, Object.assign({
124
- manual: true
125
- }, options));
126
- }
127
- }
128
- click(values, options) {
129
- this._assertActive();
130
- if (this._options && this._options.click) {
131
- this._trigger(CLICK, values, Object.assign({
132
- manual: true
133
- }, options));
134
- }
135
- }
136
- _assertActive() {
137
- if (!this._isActive()) {
138
- throw new Error(`Tracker is not active.`);
139
- }
140
- }
141
- getState(value) {
142
- // TODO: do we have to be so precise?
143
- return Object.freeze(Object.assign({
144
- [CLICK]: this._proxyElement.current ? TRACKING : UNTRACKED
145
- }, this._states.getFullState(value)));
146
- }
147
- _syncElement() {
148
- this._proxyElement.sync({
149
- silent: true
150
- });
151
- const element = this._proxyElement.current;
152
- if (this._element === element) {
153
- return;
154
- }
155
- // remove observer from old element
156
- this._retireElement();
157
-
158
- // add observer on new element
159
- if (element) {
160
- if (this._options && this._options.watch) {
161
- // TODO: move to proxy element
162
- this._mutationObserver = new MutationObserver(() => this.refresh());
163
- this._mutationObserver.observe(element, {
164
- childList: true,
165
- subtree: true
166
- });
167
- }
168
- }
169
- this._element = element;
170
- }
171
- _retireElement() {
172
- if (!this._element) {
173
- return;
174
- }
175
- if (this._mutationObserver) {
176
- this._mutationObserver.disconnect();
177
- this._mutationObserver = undefined;
178
- }
179
- this._element = undefined;
180
- }
181
- _retireStates() {
182
- const {
183
- unbounds
184
- } = this._bindings.unbindAll();
185
- this._untrackViewables(unbounds);
186
- this._states = undefined;
187
- }
188
- _refreshBindings() {
189
- if (!this._states) {
190
- return;
191
- }
192
- const element = this._proxyElement.current;
193
- const {
194
- bounds,
195
- unbounds
196
- } = this._bindings.refresh(element);
197
- this._untrackViewables(unbounds);
198
- this._trackImpressions(bounds);
199
- this._trackViewables(bounds);
200
- }
201
-
202
- // impression //
203
- _trackImpressions(bindings) {
204
- const options = this._options && this._options.impression;
205
- if (!options) {
206
- return;
207
- }
208
- this._trigger(IMPRESSION, bindings.map(b => b.value), {
209
- bindings
210
- });
211
- }
212
-
213
- // viewable //
214
- _trackViewables(bindings) {
215
- const options = this._options && this._options.viewable;
216
- if (!options) {
217
- return;
218
- }
219
- for (const binding of bindings) {
220
- this._trackViewableOnElement(binding);
221
- }
222
- }
223
- async _trackViewableOnElement(binding) {
224
- const {
225
- value,
226
- element
227
- } = binding;
228
- if (!value || !(0, _commons.isElement)(element) || this._viewables.has(element)) {
229
- return;
230
- }
231
- // TODO: when element is replaced without proper unload...
232
- const state = this._states.get(value, VIEWABLE);
233
- if (state !== UNTRACKED) {
234
- return;
235
- }
236
- this._states.set(value, VIEWABLE, TRACKING);
237
- const {
238
- area,
239
- duration
240
- } = this._options && this._options.viewable;
241
- // abort signal
242
- const ac = new AbortController();
243
- const {
244
- signal
245
- } = ac;
246
- this._viewables.set(element, {
247
- ac
248
- });
249
- await (0, _commons.viewable)(element, {
250
- area,
251
- duration,
252
- signal
253
- });
254
- this._viewables.delete(element);
255
- this._trigger(VIEWABLE, [value], {
256
- bindings: [binding]
257
- });
258
- }
259
- _untrackViewableOnElement(_ref2) {
260
- let {
261
- value,
262
- element
263
- } = _ref2;
264
- const viewable = this._viewables.get(element);
265
- if (!viewable) {
266
- return;
267
- }
268
- viewable.ac.abort();
269
- this._viewables.delete(element);
270
- const type = VIEWABLE;
271
- if (this._states.get(value, type) === TRACKING) {
272
- this._states.set(value, type, UNTRACKED);
273
- }
274
- }
275
- _untrackViewables(bindings) {
276
- for (const binding of bindings) {
277
- this._untrackViewableOnElement(binding);
278
- }
279
- }
280
-
281
- // click //
282
- _handleClick(event) {
283
- const options = this._options && this._options.click;
284
- if (!options || !this._isActive()) {
285
- return;
286
- }
287
- const binding = this._bindings.get(event.target);
288
- if (!binding) {
289
- return;
290
- }
291
-
292
- // TODO: refactor
293
- if (typeof options.validate === 'function') {
294
- if (!options.validate(event, binding)) {
295
- return;
296
- }
297
- } else if (!options.lenient) {
298
- // it must be a left click
299
- if (event.button !== 0) {
300
- return;
301
- }
302
- // event default must not be prevented
303
- if (event.defaultPrevented) {
304
- return;
305
- }
306
- // must go through a real link
307
- if (!(0, _commons.findInAncestors)(event.target, element => element.tagName === 'A' && element.href || undefined)) {
308
- return;
309
- }
310
- }
311
- this._trigger(CLICK, [binding.value], {
312
- bindings: [binding]
313
- });
314
- }
315
- _trigger(event, values) {
316
- let {
317
- manual = false,
318
- bindings
319
- } = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
320
- (0, _constants.validateEventType)(event);
321
- if (!this._isActive()) {
322
- return;
323
- }
324
-
325
- // ignore already triggered
326
- values = this._states.untriggered((0, _commons.asArray)(values), event);
327
- if (values.length === 0) {
328
- return;
329
- }
330
- this._states.set(values, event, TRIGGERED);
331
- this._events.emit(event, {
332
- event,
333
- values,
334
- manual,
335
- bindings
336
- });
337
- }
338
- destroy() {
339
- this._retireElement();
340
- this._retireStates();
341
- this._bindings._destroy();
342
- for (const unsubscribe of this._unsubscribes) {
343
- unsubscribe();
344
- }
345
- this._unsubscribes = [];
346
- }
347
- }
348
- exports.default = Tracker;