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

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.
@@ -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.0';
7
+ var _default = exports.default = '1.10.0-beta.1';
@@ -7,10 +7,13 @@ exports.default = void 0;
7
7
  var _commons = require("@miso.ai/commons");
8
8
  var _base = _interopRequireDefault(require("./base.js"));
9
9
  var _options = require("./options.js");
10
- var _index = require("../actor/index.js");
10
+ var sources = _interopRequireWildcard(require("../source/index.js"));
11
+ var _index2 = require("../actor/index.js");
11
12
  var _constants = require("../constants.js");
12
- var _index2 = require("../layout/index.js");
13
+ var _index3 = require("../layout/index.js");
13
14
  const _excluded = ["q", "qs"];
15
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
16
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
14
17
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
15
18
  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
19
  const DEFAULT_API_OPTIONS = Object.freeze({
@@ -24,27 +27,34 @@ const DEFAULT_API_OPTIONS = Object.freeze({
24
27
  cite_end: ']'
25
28
  }
26
29
  });
30
+ const DEFAULT_AUTOCOMPLETE_OPTIONS = Object.freeze({
31
+ actor: false,
32
+ api: {
33
+ group: _commons.API.GROUP.ASK,
34
+ name: _commons.API.NAME.AUTOCOMPLETE
35
+ }
36
+ });
27
37
  const DEFAULT_LAYOUTS = Object.freeze({
28
- [_constants.ROLE.QUERY]: [_index2.SearchBoxLayout.type, {
38
+ [_constants.ROLE.QUERY]: [_index3.SearchBoxLayout.type, {
29
39
  placeholder: 'Ask a question'
30
40
  }],
31
- [_constants.ROLE.QUESTION]: [_index2.TextLayout.type, {
41
+ [_constants.ROLE.QUESTION]: [_index3.TextLayout.type, {
32
42
  tag: 'h2'
33
43
  }],
34
- [_constants.ROLE.ANSWER]: _index2.TypewriterLayout.type,
35
- [_constants.ROLE.FEEDBACK]: _index2.FeedbackLayout.type,
36
- [_constants.ROLE.SOURCES]: [_index2.ListLayout.type, {
44
+ [_constants.ROLE.ANSWER]: _index3.TypewriterLayout.type,
45
+ [_constants.ROLE.FEEDBACK]: _index3.FeedbackLayout.type,
46
+ [_constants.ROLE.SOURCES]: [_index3.ListLayout.type, {
37
47
  incremental: true,
38
48
  itemType: 'article',
39
49
  templates: {
40
50
  ordered: true
41
51
  }
42
52
  }],
43
- [_constants.ROLE.RELATED_RESOURCES]: [_index2.ListLayout.type, {
53
+ [_constants.ROLE.RELATED_RESOURCES]: [_index3.ListLayout.type, {
44
54
  incremental: true,
45
55
  itemType: 'article'
46
56
  }],
47
- [_constants.ROLE.QUERY_SUGGESTIONS]: _index2.OptionListLayout.type
57
+ [_constants.ROLE.QUERY_SUGGESTIONS]: _index3.OptionListLayout.type
48
58
  });
49
59
  const DEFAULT_TRACKERS = Object.freeze({
50
60
  [_constants.ROLE.SOURCES]: {},
@@ -59,6 +69,7 @@ const DEFAULT_TRACKERS = Object.freeze({
59
69
  });
60
70
  const DEFAULT_OPTIONS = Object.freeze({
61
71
  api: DEFAULT_API_OPTIONS,
72
+ autocomplete: DEFAULT_AUTOCOMPLETE_OPTIONS,
62
73
  layouts: DEFAULT_LAYOUTS,
63
74
  trackers: DEFAULT_TRACKERS
64
75
  });
@@ -75,9 +86,17 @@ class Ask extends _base.default {
75
86
  (0, _commons.defineValues)(this, {
76
87
  parentQuestionId
77
88
  });
78
- this._feedback = new _index.FeedbackActor(this._hub);
89
+ this._feedback = new _index2.FeedbackActor(this._hub);
79
90
  this._setSuggestedQuestions();
80
- this._unsubscribes = [...this._unsubscribes, this._hub.on(_index.fields.query(), payload => this.query(payload)), this._hub.on(_index.fields.view(_constants.ROLE.ANSWER), data => this._onAnswerViewUpdate(data)), this._views.get(_constants.ROLE.ANSWER).on('citation-click', event => this._onCitationClick(event))];
91
+
92
+ /*
93
+ this._autocomplete = new AutocompleteActor(this._hub, {
94
+ source: sources.api(this._client),
95
+ options: this._options,
96
+ });
97
+ */
98
+
99
+ this._unsubscribes = [...this._unsubscribes, this._hub.on(_index2.fields.query(), payload => this.query(payload)), this._hub.on(_index2.fields.view(_constants.ROLE.ANSWER), data => this._onAnswerViewUpdate(data)), this._views.get(_constants.ROLE.ANSWER).on('citation-click', event => this._onCitationClick(event))];
81
100
  parentQuestionId && context._byPqid.set(parentQuestionId, this);
82
101
  context._events.emit('create', this);
83
102
  this.reset(); // create a session so query suggestions can be tracked
@@ -163,7 +182,7 @@ class Ask extends _base.default {
163
182
  session
164
183
  } = this;
165
184
  session.meta.question_source = questionSource;
166
- this._hub.update(_index.fields.request(), (0, _options.mergeApiOptions)(this._options.resolved.api, {
185
+ this._hub.update(_index2.fields.request(), (0, _options.mergeApiOptions)(this._options.resolved.api, {
167
186
  payload,
168
187
  session
169
188
  }));
@@ -175,7 +194,7 @@ class Ask extends _base.default {
175
194
  session,
176
195
  status,
177
196
  ongoing
178
- } = this._hub.states[_index.fields.view(_constants.ROLE.ANSWER)] || {};
197
+ } = this._hub.states[_index2.fields.view(_constants.ROLE.ANSWER)] || {};
179
198
  if (session && status !== _constants.STATUS.INITIAL && (status !== _constants.STATUS.READY || ongoing)) {
180
199
  // it's interrupted by a new question
181
200
  const state = Object.freeze({
@@ -188,6 +207,18 @@ class Ask extends _base.default {
188
207
  }
189
208
  super.restart();
190
209
  }
210
+
211
+ /*
212
+ updateCompletions(event) {
213
+ // TODO: verify
214
+ this._hub.update(fields.completions(), {
215
+ ...event,
216
+ source: 'manual',
217
+ });
218
+ return this;
219
+ }
220
+ */
221
+
191
222
  _defaultProcessData(data) {
192
223
  data = super._defaultProcessData(data);
193
224
  const {
@@ -258,9 +289,9 @@ class Ask extends _base.default {
258
289
  if (!previous) {
259
290
  return;
260
291
  }
261
- const values = previous.states[_index.fields.data()].value;
292
+ const values = previous.states[_index2.fields.data()].value;
262
293
  const value = values.suggested_followup_questions || values.followup_questions || [];
263
- this._hub.update(_index.fields.suggestions(), {
294
+ this._hub.update(_index2.fields.suggestions(), {
264
295
  value: value.map(text => ({
265
296
  text
266
297
  }))
@@ -272,7 +303,7 @@ class Ask extends _base.default {
272
303
  } = _ref3;
273
304
  const {
274
305
  value
275
- } = this.states[_index.fields.data()] || {};
306
+ } = this.states[_index2.fields.data()] || {};
276
307
  const {
277
308
  sources
278
309
  } = value || {};
@@ -327,6 +358,7 @@ class Ask extends _base.default {
327
358
  this._context._byQid.delete(questionId);
328
359
  }
329
360
  this._feedback._destroy();
361
+ this._autocomplete._destroy();
330
362
  super._destroy(options);
331
363
  }
332
364
  }
@@ -59,11 +59,10 @@ class Workflow extends _commons.Component {
59
59
  const hub = this._hub = (0, _utils.injectLogger)(new _index.Hub(), function () {
60
60
  return _this._log(...arguments);
61
61
  });
62
- const source = this._source = sources.api(client);
63
62
  const layouts = plugin.layouts;
64
63
  this._sessions = new _index.SessionMaker(hub);
65
64
  this._data = new _index.DataActor(hub, {
66
- source,
65
+ source: sources.api(client),
67
66
  options
68
67
  });
69
68
  const views = this._views = new _index.ViewsActor(hub, {
@@ -19,7 +19,10 @@ const DEFAULT_API_OPTIONS = Object.freeze({
19
19
  });
20
20
  const DEFAULT_LAYOUTS = Object.freeze({
21
21
  [_constants.ROLE.RELATED_QUESTIONS]: [_index2.ListLayout.type, {
22
- itemType: 'question'
22
+ itemType: 'question',
23
+ link: {
24
+ rel: 'noopener nofollow'
25
+ }
23
26
  }],
24
27
  [_constants.ROLE.QUERY]: [_index2.SearchBoxLayout.type, {
25
28
  placeholder: 'Ask a question'
@@ -6,11 +6,13 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.WorkflowOptions = exports.WorkflowContextOptions = void 0;
7
7
  exports.makeConfigurable = makeConfigurable;
8
8
  exports.mergeApiOptions = mergeApiOptions;
9
+ exports.mergeAutocompleteOptions = mergeAutocompleteOptions;
9
10
  exports.mergeDataProcessorOptions = mergeDataProcessorOptions;
10
11
  exports.mergeInteractionsOptions = mergeInteractionsOptions;
11
12
  exports.mergeLayoutsOptions = mergeLayoutsOptions;
12
13
  exports.mergeTrackersOptions = mergeTrackersOptions;
13
14
  exports.normalizeApiOptions = normalizeApiOptions;
15
+ exports.normalizeAutocompleteOptions = normalizeAutocompleteOptions;
14
16
  exports.normalizeDataProcessorOptions = normalizeDataProcessorOptions;
15
17
  exports.normalizeInteractionsOptions = normalizeInteractionsOptions;
16
18
  exports.normalizeLayoutsOptions = normalizeLayoutsOptions;
@@ -23,6 +25,7 @@ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e =
23
25
  // normalize //
24
26
  function normalizeApiOptions() {
25
27
  let [name, payload] = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
28
+ // TODO: take object form as well
26
29
  if (name === false) {
27
30
  return {
28
31
  actor: false
@@ -131,6 +134,20 @@ function normalizeInteractionsOptions(options) {
131
134
  preprocess
132
135
  });
133
136
  }
137
+ function normalizeAutocompleteOptions(options) {
138
+ if (options === undefined) {
139
+ throw new Error(`Expect autocomplete options to be an object or a boolean value: ${options}`);
140
+ }
141
+ if (typeof options === 'boolean') {
142
+ options = {
143
+ actor: options
144
+ };
145
+ }
146
+ const processData = normalizeDataProcessorOptions(options.processData);
147
+ return Object.assign({}, options, {
148
+ processData
149
+ });
150
+ }
134
151
 
135
152
  // merge //
136
153
  function mergeApiOptions() {
@@ -217,6 +234,18 @@ function mergeInteractionsOptions() {
217
234
  preprocess: concatArrays(merged.preprocess, options.preprocess)
218
235
  })));
219
236
  }
237
+ function mergeAutocompleteOptions() {
238
+ for (var _len6 = arguments.length, optionsList = new Array(_len6), _key7 = 0; _key7 < _len6; _key7++) {
239
+ optionsList[_key7] = arguments[_key7];
240
+ }
241
+ if (optionsList[optionsList.length - 1] === false) {
242
+ return false;
243
+ }
244
+ return mergeOptions(optionsList, (merged, options) => Object.assign(merged, Object.assign({}, options, {
245
+ api: mergeApiOptions(merged.api, options.api),
246
+ processData: mergeDataProcessorOptions(merged.processData, options.processData)
247
+ })));
248
+ }
220
249
 
221
250
  // manifest //
222
251
  const FEATURES = [{
@@ -239,6 +268,10 @@ const FEATURES = [{
239
268
  key: 'interactions',
240
269
  normalize: normalizeInteractionsOptions,
241
270
  merge: mergeInteractionsOptions
271
+ }, {
272
+ key: 'autocomplete',
273
+ normalize: normalizeAutocompleteOptions,
274
+ merge: mergeAutocompleteOptions
242
275
  }];
243
276
  class WorkflowContextOptions {
244
277
  constructor() {
@@ -339,21 +372,29 @@ for (const {
339
372
  }
340
373
  });
341
374
  }
375
+ const DEFAULT_FEATURES = ['api', 'layouts', 'dataProcessor', 'trackers', 'interactions'];
342
376
  function makeConfigurable(prototype) {
343
- Object.assign(prototype, {
344
- useApi() {
345
- for (var _len6 = arguments.length, args = new Array(_len6), _key7 = 0; _key7 < _len6; _key7++) {
346
- args[_key7] = arguments[_key7];
377
+ let features = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_FEATURES;
378
+ for (const feature of features) {
379
+ injectConfigurableFeature(prototype, feature);
380
+ }
381
+ }
382
+ function injectConfigurableFeature(prototype, feature) {
383
+ if (feature === 'api') {
384
+ Object.assign(prototype, {
385
+ useApi() {
386
+ for (var _len7 = arguments.length, args = new Array(_len7), _key8 = 0; _key8 < _len7; _key8++) {
387
+ args[_key8] = arguments[_key8];
388
+ }
389
+ this._options.api.merge(args);
390
+ return this;
391
+ },
392
+ clearApi() {
393
+ this._options.api.set();
394
+ return this;
347
395
  }
348
- this._options.api.merge(args);
349
- return this;
350
- },
351
- clearApi() {
352
- this._options.api.set();
353
- return this;
354
- }
355
- });
356
- for (const feature of ['layouts', 'dataProcessor', 'trackers', 'interactions']) {
396
+ });
397
+ } else {
357
398
  const upperCased = upperCase(feature);
358
399
  Object.assign(prototype, {
359
400
  [`use${upperCased}`](value) {
@@ -7,9 +7,12 @@ exports.default = void 0;
7
7
  var _commons = require("@miso.ai/commons");
8
8
  var _base = _interopRequireDefault(require("./base.js"));
9
9
  var _options = require("./options.js");
10
- var _index = require("../actor/index.js");
10
+ var sources = _interopRequireWildcard(require("../source/index.js"));
11
+ var _index2 = require("../actor/index.js");
11
12
  var _constants = require("../constants.js");
12
- var _index2 = require("../layout/index.js");
13
+ var _index3 = require("../layout/index.js");
14
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
15
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
13
16
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
17
  const DEFAULT_API_OPTIONS = Object.freeze({
15
18
  group: _commons.API.GROUP.SEARCH,
@@ -18,15 +21,28 @@ const DEFAULT_API_OPTIONS = Object.freeze({
18
21
  fl: ['*']
19
22
  }
20
23
  });
24
+ const DEFAULT_AUTOCOMPLETE_OPTIONS = Object.freeze({
25
+ actor: false,
26
+ api: {
27
+ group: _commons.API.GROUP.SEARCH,
28
+ name: _commons.API.NAME.AUTOCOMPLETE,
29
+ payload: {
30
+ completion_fields: ['suggested_queries', 'title'],
31
+ fl: ['title', 'url', 'cover_image']
32
+ }
33
+ },
34
+ throttle: 300
35
+ });
21
36
  const DEFAULT_LAYOUTS = Object.freeze({
22
- [_constants.ROLE.QUERY]: _index2.SearchBoxLayout.type,
23
- [_constants.ROLE.PRODUCTS]: _index2.ListLayout.type
37
+ [_constants.ROLE.QUERY]: _index3.SearchBoxLayout.type,
38
+ [_constants.ROLE.PRODUCTS]: _index3.ListLayout.type
24
39
  });
25
40
  const DEFAULT_TRACKERS = Object.freeze({
26
41
  [_constants.ROLE.PRODUCTS]: {}
27
42
  });
28
43
  const DEFAULT_OPTIONS = Object.freeze({
29
44
  api: DEFAULT_API_OPTIONS,
45
+ autocomplete: DEFAULT_AUTOCOMPLETE_OPTIONS,
30
46
  layouts: DEFAULT_LAYOUTS,
31
47
  trackers: DEFAULT_TRACKERS
32
48
  });
@@ -39,7 +55,11 @@ class Search extends _base.default {
39
55
  roles: Object.keys(DEFAULT_LAYOUTS),
40
56
  defaults: DEFAULT_OPTIONS
41
57
  });
42
- this._unsubscribes.push(this._hub.on(_index.fields.query(), payload => this.query(payload)));
58
+ this._autocomplete = new _index2.AutocompleteActor(this._hub, {
59
+ source: sources.api(this._client),
60
+ options: this._options
61
+ });
62
+ this._unsubscribes.push(this._hub.on(_index2.fields.query(), payload => this.query(payload)));
43
63
  }
44
64
 
45
65
  // lifecycle //
@@ -71,12 +91,19 @@ class Search extends _base.default {
71
91
  const {
72
92
  session
73
93
  } = this;
74
- this._hub.update(_index.fields.request(), (0, _options.mergeApiOptions)(this._options.resolved.api, {
94
+ this._hub.update(_index2.fields.request(), (0, _options.mergeApiOptions)(this._options.resolved.api, {
75
95
  payload,
76
96
  session
77
97
  }));
78
98
  return this;
79
99
  }
100
+ updateCompletions(event) {
101
+ // TODO: verify
102
+ this._hub.update(_index2.fields.completions(), Object.assign({}, event, {
103
+ source: 'manual'
104
+ }));
105
+ return this;
106
+ }
80
107
  notifyViewUpdate() {
81
108
  let role = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _constants.ROLE.PRODUCTS;
82
109
  for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
@@ -86,4 +113,5 @@ class Search extends _base.default {
86
113
  return this;
87
114
  }
88
115
  }
89
- exports.default = Search;
116
+ exports.default = Search;
117
+ (0, _options.makeConfigurable)(Search.prototype, ['autocomplete']);
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.0"
29
+ "@miso.ai/commons": "1.10.0-beta.1"
30
30
  },
31
- "version": "1.10.0-beta.0"
31
+ "version": "1.10.0-beta.1"
32
32
  }
@@ -0,0 +1,131 @@
1
+ import { STATUS } from '../constants.js';
2
+ import * as fields from './fields.js';
3
+
4
+ export default class AutocompleteActor {
5
+
6
+ constructor(hub, { source, options }) {
7
+ this._hub = hub;
8
+ this._source = source;
9
+ this._options = options;
10
+ this._index = -1;
11
+
12
+ this._unsubscribes = [
13
+ hub.on(fields.input(), () => this._sync()),
14
+ options.on('autocomplete', () => this._syncOptions()),
15
+ ];
16
+
17
+ // sync right away
18
+ this._sync(true);
19
+ }
20
+
21
+ get active() {
22
+ return this._options.resolved.autocomplete.actor !== false;
23
+ }
24
+
25
+ get source() {
26
+ return this._source;
27
+ }
28
+
29
+ _syncOptions() {
30
+ // TODO: explore scenarios where options.actor true -> false
31
+ this._sync(true);
32
+ }
33
+
34
+ async _sync(force = false) {
35
+ // protocol: inactive -> no reaction
36
+ if (!this.active) {
37
+ return;
38
+ }
39
+
40
+ const { input } = this._hub.states;
41
+ const value = input && input.value && input.value.trim() || undefined;
42
+
43
+ if (sameInput(this._input, input) && !force) {
44
+ return;
45
+ }
46
+ this._input = input;
47
+ const index = ++this._index;
48
+
49
+ // new input, abort previous data fetch if any
50
+ this._clearTimeout();
51
+ this._abortPendingRequest({
52
+ type: 'new-input',
53
+ message: 'A new input renders previous autocomplete request obsolete.',
54
+ });
55
+
56
+ // emit loading/initial state
57
+ this._emitCompletions({ index, input, status: value ? STATUS.LOADING : STATUS.INITIAL });
58
+
59
+ if (!value) {
60
+ return;
61
+ }
62
+
63
+ try {
64
+ const response = await this._fetchCompletions(input);
65
+ if (this._index !== index) {
66
+ return; // new results loading, discard this one
67
+ }
68
+ this._emitCompletions({ index, input, status: STATUS.READY, value: response.completions });
69
+ } catch (error) {
70
+ this._error(error);
71
+ if (this._index !== index) {
72
+ return; // ignore
73
+ }
74
+ this._emitCompletions({ index, input, status: STATUS.ERRONEOUS, error });
75
+ }
76
+ }
77
+
78
+ async _getCompletions(input) {
79
+ // TODO: cache
80
+ return await this._fetchCompletions(input);
81
+ }
82
+
83
+ async _fetchCompletions({ value }) {
84
+ // TODO: other options?
85
+ const { api } = this._options.resolved.autocomplete;
86
+ const { group, name } = api;
87
+ const { signal } = this._ac || {};
88
+ const options = { ...api.options, signal };
89
+ const payload = { ...api.payload, q: value };
90
+ return await this._source({ group, name, payload, options });
91
+ }
92
+
93
+ _clearTimeout() {
94
+ if (this._timeoutId) {
95
+ clearTimeout(this._timeoutId);
96
+ this._timeoutId = undefined;
97
+ }
98
+ }
99
+
100
+ _abortPendingRequest(info) {
101
+ this._ac && this._ac.abort(info);
102
+ this._ac = new AbortController();
103
+ }
104
+
105
+ _emitCompletions(event) {
106
+ event.source = 'actor';
107
+ this._hub.update(fields.completions(), event);
108
+ }
109
+
110
+ _error(error) {
111
+ // TODO
112
+ console.error(error);
113
+ }
114
+
115
+ _destroy() {
116
+ // abort ongoing data fetch if any
117
+ this._ac && this._ac.abort({
118
+ type: 'autocomplete-actor-destroy',
119
+ message: 'Autocomplete actor is destroyed.',
120
+ });
121
+ for (const unsubscribe of this._unsubscribes) {
122
+ unsubscribe();
123
+ }
124
+ this._unsubscribes = [];
125
+ }
126
+
127
+ }
128
+
129
+ function sameInput(a, b) {
130
+ return (!a && !b) || (a && b && a.value === b.value);
131
+ }
package/src/actor/data.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as fields from './fields.js';
2
+ import { isCurrentSession } from './utils.js';
2
3
 
3
4
  export default class DataActor {
4
5
 
@@ -61,7 +62,7 @@ export default class DataActor {
61
62
  let value;
62
63
  for await (value of response) {
63
64
  // A new session invalidates ongoing data fetch for the old session, terminating the loop
64
- if (!this._isCurrentSession(session)) {
65
+ if (!isCurrentSession(this._hub, session)) {
65
66
  break;
66
67
  }
67
68
  this._emitResponse({ session, request, value });
@@ -77,15 +78,7 @@ export default class DataActor {
77
78
 
78
79
  _emitResponseWithSessionCheck(response) {
79
80
  // A new session invalidates ongoing data fetch
80
- this._isCurrentSession(response.session) && this._emitResponse(response);
81
- }
82
-
83
- _isCurrentSession(session) {
84
- if (!session) {
85
- return false;
86
- }
87
- const { session: currentSession } = this._hub.states;
88
- return currentSession && currentSession.index === session.index;
81
+ isCurrentSession(this._hub, response.session) && this._emitResponse(response);
89
82
  }
90
83
 
91
84
  _emitResponse(response) {
@@ -37,3 +37,11 @@ export function interaction() {
37
37
  export function feedback() {
38
38
  return 'feedback';
39
39
  }
40
+
41
+ export function input() {
42
+ return 'input';
43
+ }
44
+
45
+ export function completions() {
46
+ return 'completions';
47
+ }
@@ -7,4 +7,5 @@ export { default as DataActor } from './data.js';
7
7
  export { default as ViewsActor } from './views.js';
8
8
  export { default as Trackers } from './trackers.js';
9
9
  export { default as FeedbackActor } from './feedback.js';
10
+ export { default as AutocompleteActor } from './autocomplete.js';
10
11
  export { default as InteractionsActor } from './interactions.js';
@@ -40,3 +40,11 @@ export function toInteraction({ property, misoId, request }, { event, values, ma
40
40
  });
41
41
  return payload;
42
42
  }
43
+
44
+ export function isCurrentSession(hub, session) {
45
+ if (!session) {
46
+ return false;
47
+ }
48
+ const { session: currentSession } = hub.states;
49
+ return currentSession && currentSession.index === session.index;
50
+ }
@@ -26,6 +26,27 @@ export function followUp(options = {}) {
26
26
  ]);
27
27
  };
28
28
 
29
+ export const sections = Object.freeze({
30
+ followUps,
31
+ relatedResources,
32
+ querySuggestions,
33
+ answerGroup,
34
+ answer,
35
+ sources,
36
+ });
37
+
38
+ export const helpers = Object.freeze({
39
+ normalizeOptions,
40
+ normalizePhraseOptions,
41
+ normalizePhraseOptionKey,
42
+ phrase,
43
+ phraseText,
44
+ section,
45
+ container,
46
+ element,
47
+ attrs,
48
+ });
49
+
29
50
 
30
51
 
31
52
  // options //