@miso.ai/client-sdk-ui 1.13.2-beta.0 → 1.14.0-beta.2

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 (214) hide show
  1. package/dist/cjs/asset/svgs.js +15 -4
  2. package/dist/cjs/combo/ask/index.js +2 -2
  3. package/dist/cjs/constants.js +118 -98
  4. package/dist/cjs/defaults/ask/controls.js +1 -1
  5. package/dist/cjs/defaults/hybrid-search/answer-box.js +4 -4
  6. package/dist/cjs/defaults.js +169 -0
  7. package/dist/cjs/element/container/index.js +14 -0
  8. package/dist/cjs/element/container/miso-ask.js +3 -3
  9. package/dist/cjs/element/container/miso-conversation.js +21 -0
  10. package/dist/cjs/element/container/miso-explore.js +1 -1
  11. package/dist/cjs/element/container/miso-history.js +21 -0
  12. package/dist/cjs/element/container/miso-hybrid-search.js +1 -1
  13. package/dist/cjs/element/container/miso-recommendation.js +1 -1
  14. package/dist/cjs/element/container/miso-search.js +1 -1
  15. package/dist/cjs/element/context/miso-follow-ups.js +1 -1
  16. package/dist/cjs/element/role/index.js +42 -0
  17. package/dist/cjs/element/role/miso-messages.js +20 -0
  18. package/dist/cjs/element/role/miso-new-thread.js +20 -0
  19. package/dist/cjs/element/role/miso-rename.js +20 -0
  20. package/dist/cjs/element/role/miso-subscription.js +20 -0
  21. package/dist/cjs/element/role/miso-threads.js +20 -0
  22. package/dist/cjs/element/role/miso-title.js +20 -0
  23. package/dist/cjs/layout/affiliation/affiliation.js +1 -1
  24. package/dist/cjs/layout/banner/banner.js +2 -1
  25. package/dist/cjs/layout/button/button.js +130 -0
  26. package/dist/cjs/layout/button/checkbox.js +115 -0
  27. package/dist/cjs/layout/button/more-button.js +3 -3
  28. package/dist/cjs/layout/container/container.js +1 -1
  29. package/dist/cjs/layout/error/error.js +2 -1
  30. package/dist/cjs/layout/index.js +28 -0
  31. package/dist/cjs/layout/input/facets.js +4 -3
  32. package/dist/cjs/layout/input/option-list.js +3 -2
  33. package/dist/cjs/layout/input/search-box.js +42 -9
  34. package/dist/cjs/layout/input/select.js +2 -1
  35. package/dist/cjs/layout/list/cards.js +2 -1
  36. package/dist/cjs/layout/list/carousel.js +2 -1
  37. package/dist/cjs/layout/list/collection.js +5 -0
  38. package/dist/cjs/layout/list/gallery.js +2 -1
  39. package/dist/cjs/layout/list/horizontal.js +2 -1
  40. package/dist/cjs/layout/list/list.js +2 -1
  41. package/dist/cjs/layout/list/messages.js +346 -0
  42. package/dist/cjs/layout/list/threads.js +257 -0
  43. package/dist/cjs/layout/mixin/trackable.js +4 -5
  44. package/dist/cjs/layout/mixin/triggerable.js +2 -2
  45. package/dist/cjs/layout/radio/feedback.js +4 -3
  46. package/dist/cjs/layout/templates.js +70 -0
  47. package/dist/cjs/layout/text/text.js +2 -1
  48. package/dist/cjs/layout/text/typewriter/index.js +4 -2
  49. package/dist/cjs/plugin.js +43 -104
  50. package/dist/cjs/util/confirm.js +33 -0
  51. package/dist/cjs/util/modal.js +48 -0
  52. package/dist/cjs/util/prompt.js +47 -0
  53. package/dist/cjs/version.js +1 -1
  54. package/package.json +5 -4
  55. package/src/CLAUDE.md +48 -105
  56. package/src/asset/svgs.js +14 -3
  57. package/src/combo/ask/index.js +2 -2
  58. package/src/constants.js +37 -147
  59. package/src/defaults/ask/controls.js +1 -1
  60. package/src/defaults/hybrid-search/answer-box.js +2 -2
  61. package/src/defaults.js +107 -0
  62. package/src/element/container/index.js +2 -0
  63. package/src/element/container/miso-ask.js +3 -3
  64. package/src/element/container/miso-conversation.js +19 -0
  65. package/src/element/container/miso-explore.js +1 -1
  66. package/src/element/container/miso-history.js +19 -0
  67. package/src/element/container/miso-hybrid-search.js +1 -1
  68. package/src/element/container/miso-recommendation.js +1 -1
  69. package/src/element/container/miso-search.js +1 -1
  70. package/src/element/context/miso-follow-ups.js +1 -1
  71. package/src/element/role/index.js +6 -0
  72. package/src/element/role/miso-messages.js +16 -0
  73. package/src/element/role/miso-new-thread.js +16 -0
  74. package/src/element/role/miso-rename.js +16 -0
  75. package/src/element/role/miso-subscription.js +16 -0
  76. package/src/element/role/miso-threads.js +16 -0
  77. package/src/element/role/miso-title.js +16 -0
  78. package/src/layout/affiliation/affiliation.js +2 -2
  79. package/src/layout/banner/banner.js +2 -1
  80. package/src/layout/button/button.js +116 -0
  81. package/src/layout/button/checkbox.js +91 -0
  82. package/src/layout/button/more-button.js +3 -3
  83. package/src/layout/container/container.js +2 -2
  84. package/src/layout/error/error.js +2 -1
  85. package/src/layout/index.js +4 -0
  86. package/src/layout/input/facets.js +3 -2
  87. package/src/layout/input/option-list.js +3 -2
  88. package/src/layout/input/search-box.js +41 -6
  89. package/src/layout/input/select.js +2 -1
  90. package/src/layout/list/cards.js +2 -1
  91. package/src/layout/list/carousel.js +2 -1
  92. package/src/layout/list/collection.js +6 -1
  93. package/src/layout/list/gallery.js +2 -1
  94. package/src/layout/list/horizontal.js +2 -1
  95. package/src/layout/list/list.js +2 -1
  96. package/src/layout/list/messages.js +318 -0
  97. package/src/layout/list/threads.js +206 -0
  98. package/src/layout/mixin/trackable.js +2 -3
  99. package/src/layout/mixin/triggerable.js +1 -1
  100. package/src/layout/radio/feedback.js +3 -2
  101. package/src/layout/templates.js +62 -0
  102. package/src/layout/text/text.js +2 -1
  103. package/src/layout/text/typewriter/index.js +5 -3
  104. package/src/plugin.js +31 -117
  105. package/src/util/confirm.js +28 -0
  106. package/src/util/modal.js +49 -0
  107. package/src/util/prompt.js +42 -0
  108. package/src/version.js +1 -1
  109. package/dist/cjs/actor/data.js +0 -132
  110. package/dist/cjs/actor/feedback.js +0 -29
  111. package/dist/cjs/actor/fields.js +0 -57
  112. package/dist/cjs/actor/filters.js +0 -161
  113. package/dist/cjs/actor/hub.js +0 -57
  114. package/dist/cjs/actor/index.js +0 -73
  115. package/dist/cjs/actor/interactions.js +0 -36
  116. package/dist/cjs/actor/sessions.js +0 -25
  117. package/dist/cjs/actor/tracker-states.js +0 -61
  118. package/dist/cjs/actor/tracker.js +0 -109
  119. package/dist/cjs/actor/trackers.js +0 -52
  120. package/dist/cjs/actor/utils.js +0 -15
  121. package/dist/cjs/actor/view.js +0 -294
  122. package/dist/cjs/actor/views.js +0 -209
  123. package/dist/cjs/source.js +0 -27
  124. package/dist/cjs/util/proxy.js +0 -88
  125. package/dist/cjs/util/trackers.js +0 -88
  126. package/dist/cjs/workflow/affiliations.js +0 -140
  127. package/dist/cjs/workflow/answer-based.js +0 -337
  128. package/dist/cjs/workflow/ask.js +0 -319
  129. package/dist/cjs/workflow/asks.js +0 -150
  130. package/dist/cjs/workflow/autocompletable.js +0 -63
  131. package/dist/cjs/workflow/autocomplete.js +0 -120
  132. package/dist/cjs/workflow/base.js +0 -418
  133. package/dist/cjs/workflow/context.js +0 -19
  134. package/dist/cjs/workflow/explore.js +0 -210
  135. package/dist/cjs/workflow/explores.js +0 -21
  136. package/dist/cjs/workflow/hybrid-search-answer.js +0 -88
  137. package/dist/cjs/workflow/hybrid-search-views.js +0 -109
  138. package/dist/cjs/workflow/hybrid-search.js +0 -213
  139. package/dist/cjs/workflow/index.js +0 -41
  140. package/dist/cjs/workflow/options/api.js +0 -41
  141. package/dist/cjs/workflow/options/auto-query.js +0 -97
  142. package/dist/cjs/workflow/options/configurable.js +0 -45
  143. package/dist/cjs/workflow/options/data-processor.js +0 -20
  144. package/dist/cjs/workflow/options/filters.js +0 -15
  145. package/dist/cjs/workflow/options/index.js +0 -126
  146. package/dist/cjs/workflow/options/interactions.js +0 -41
  147. package/dist/cjs/workflow/options/layouts.js +0 -79
  148. package/dist/cjs/workflow/options/options.js +0 -156
  149. package/dist/cjs/workflow/options/pagination.js +0 -25
  150. package/dist/cjs/workflow/options/roles.js +0 -15
  151. package/dist/cjs/workflow/options/templates.js +0 -30
  152. package/dist/cjs/workflow/options/trackers.js +0 -83
  153. package/dist/cjs/workflow/options/utils.js +0 -33
  154. package/dist/cjs/workflow/processors.js +0 -607
  155. package/dist/cjs/workflow/recommendation.js +0 -57
  156. package/dist/cjs/workflow/recommendations.js +0 -18
  157. package/dist/cjs/workflow/search-based.js +0 -337
  158. package/dist/cjs/workflow/search.js +0 -64
  159. package/dist/cjs/workflow/unit.js +0 -57
  160. package/dist/cjs/workflow/units.js +0 -42
  161. package/dist/cjs/workflow/use-link.js +0 -49
  162. package/src/actor/data.js +0 -106
  163. package/src/actor/feedback.js +0 -28
  164. package/src/actor/fields.js +0 -51
  165. package/src/actor/filters.js +0 -149
  166. package/src/actor/hub.js +0 -47
  167. package/src/actor/index.js +0 -10
  168. package/src/actor/interactions.js +0 -32
  169. package/src/actor/sessions.js +0 -21
  170. package/src/actor/tracker-states.js +0 -57
  171. package/src/actor/tracker.js +0 -104
  172. package/src/actor/trackers.js +0 -45
  173. package/src/actor/utils.js +0 -7
  174. package/src/actor/view.js +0 -272
  175. package/src/actor/views.js +0 -224
  176. package/src/source.js +0 -17
  177. package/src/util/proxy.js +0 -81
  178. package/src/util/trackers.js +0 -84
  179. package/src/workflow/affiliations.js +0 -121
  180. package/src/workflow/answer-based.js +0 -312
  181. package/src/workflow/ask.js +0 -284
  182. package/src/workflow/asks.js +0 -143
  183. package/src/workflow/autocompletable.js +0 -67
  184. package/src/workflow/autocomplete.js +0 -114
  185. package/src/workflow/base.js +0 -396
  186. package/src/workflow/context.js +0 -16
  187. package/src/workflow/explore.js +0 -194
  188. package/src/workflow/explores.js +0 -18
  189. package/src/workflow/hybrid-search-answer.js +0 -73
  190. package/src/workflow/hybrid-search-views.js +0 -116
  191. package/src/workflow/hybrid-search.js +0 -230
  192. package/src/workflow/index.js +0 -5
  193. package/src/workflow/options/api.js +0 -31
  194. package/src/workflow/options/auto-query.js +0 -70
  195. package/src/workflow/options/configurable.js +0 -48
  196. package/src/workflow/options/data-processor.js +0 -15
  197. package/src/workflow/options/filters.js +0 -10
  198. package/src/workflow/options/index.js +0 -11
  199. package/src/workflow/options/interactions.js +0 -36
  200. package/src/workflow/options/layouts.js +0 -73
  201. package/src/workflow/options/options.js +0 -175
  202. package/src/workflow/options/pagination.js +0 -18
  203. package/src/workflow/options/roles.js +0 -12
  204. package/src/workflow/options/templates.js +0 -27
  205. package/src/workflow/options/trackers.js +0 -80
  206. package/src/workflow/options/utils.js +0 -26
  207. package/src/workflow/processors.js +0 -490
  208. package/src/workflow/recommendation.js +0 -63
  209. package/src/workflow/recommendations.js +0 -14
  210. package/src/workflow/search-based.js +0 -329
  211. package/src/workflow/search.js +0 -73
  212. package/src/workflow/unit.js +0 -51
  213. package/src/workflow/units.js +0 -43
  214. package/src/workflow/use-link.js +0 -41
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.default = void 0;
7
7
  var _commons = require("@miso.ai/commons");
8
8
  var _constants = require("../../constants.js");
9
- var _index = require("../../actor/index.js");
9
+ var _clientSdkWorkflow = require("@miso.ai/client-sdk-workflow");
10
10
  var _template = _interopRequireDefault(require("../template.js"));
11
11
  var _templates = require("../templates.js");
12
12
  var _svgs = require("../../asset/svgs.js");
@@ -14,7 +14,7 @@ var _dom = require("../../util/dom.js");
14
14
  const _excluded = ["className", "templates", "autocomplete"];
15
15
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
16
16
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
17
- const TYPE = 'search-box';
17
+ const TYPE = _constants.LAYOUT_TYPE.SEARCH_BOX;
18
18
  const DEFAULT_CLASSNAME = 'miso-search-box';
19
19
  const DEFAULT_AUTOCOMPLETE_CLASSNAME = 'miso-autocomplete';
20
20
  function root(layout) {
@@ -170,9 +170,31 @@ class SearchBoxLayout extends _template.default {
170
170
  proxyElement,
171
171
  hub
172
172
  } = view;
173
- this._unsubscribes = [...this._unsubscribes, proxyElement.on('input', e => this._syncInput(e)), proxyElement.on('keydown', e => this._handleKeyDown(e)), proxyElement.on('click', e => this._handleClick(e)), proxyElement.on('focusin', e => this._handleFocusIn(e)), proxyElement.on('focusout', e => this._handleFocusOut(e)), hub.on(_index.fields.completions(), () => view.refresh({
173
+ this._unsubscribes = [...this._unsubscribes, proxyElement.on('input', e => this._syncInput(e)), proxyElement.on('keydown', e => this._handleKeyDown(e)), proxyElement.on('click', e => this._handleClick(e)), proxyElement.on('focusin', e => this._handleFocusIn(e)), proxyElement.on('focusout', e => this._handleFocusOut(e)), hub.on(_clientSdkWorkflow.fields.completions(), () => view.refresh({
174
174
  force: true
175
175
  }))];
176
+ if (this.options.disableWhenOngoing) {
177
+ // disable submission while the main view is still displaying an answer
178
+ const mainRole = view.workflow._roles && view.workflow._roles.main;
179
+ if (mainRole) {
180
+ this._unsubscribes.push(hub.on(_clientSdkWorkflow.fields.view(mainRole), state => this._syncDisabled(!!state.ongoing)));
181
+ }
182
+ }
183
+ }
184
+ _syncDisabled(disabled) {
185
+ if (this._disabled === disabled) {
186
+ return;
187
+ }
188
+ this._disabled = disabled;
189
+ this._syncDisabledAttributes();
190
+ }
191
+ _syncDisabledAttributes() {
192
+ // the user can keep typing; only submission is disabled
193
+ const element = this._element;
194
+ const button = element && element.querySelector(`[data-role="submit"]`);
195
+ if (button) {
196
+ button.disabled = !!this._disabled;
197
+ }
176
198
  }
177
199
  focus() {
178
200
  // TODO: support blur as well
@@ -203,7 +225,7 @@ class SearchBoxLayout extends _template.default {
203
225
  state
204
226
  });
205
227
  return Object.assign({}, state, {
206
- completions: this._view.hub.states[_index.fields.completions()]
228
+ completions: this._view.hub.states[_clientSdkWorkflow.fields.completions()]
207
229
  });
208
230
  }
209
231
  _render(element, data, controls) {
@@ -216,6 +238,7 @@ class SearchBoxLayout extends _template.default {
216
238
  _afterRender(element, state) {
217
239
  this._fullfillFocusRequest(element);
218
240
  this._fullfillValueRequest(element);
241
+ this._syncDisabledAttributes(); // a re-render replaces the input element
219
242
  }
220
243
  _updateCompletions(element, {
221
244
  state,
@@ -293,7 +316,7 @@ class SearchBoxLayout extends _template.default {
293
316
  }
294
317
  this._prevInput = value;
295
318
  const self = this;
296
- this._debounce(() => self._view.hub.update(_index.fields.input(), {
319
+ this._debounce(() => self._view.hub.update(_clientSdkWorkflow.fields.input(), {
297
320
  value
298
321
  }));
299
322
  }
@@ -325,7 +348,9 @@ class SearchBoxLayout extends _template.default {
325
348
  }) {
326
349
  if (!isComposing && key === 'Enter' && target.matches('[data-role="input"]')) {
327
350
  this._submit(target.value);
328
- target.blur();
351
+ if (this.options.blurOnSubmit !== false) {
352
+ target.blur();
353
+ }
329
354
  }
330
355
  // TODO: select completion items with arrow keys
331
356
  }
@@ -339,7 +364,9 @@ class SearchBoxLayout extends _template.default {
339
364
  for (let element = target; element && element !== this._element; element = element.parentElement) {
340
365
  if (element.matches('[data-role="submit"]') || element.matches('[data-role="button"]') || element.matches('[type="submit"]')) {
341
366
  if (inputElement) {
342
- inputElement.blur();
367
+ if (this.options.blurOnSubmit !== false) {
368
+ inputElement.blur();
369
+ }
343
370
  this._submit(inputElement.value);
344
371
  }
345
372
  return;
@@ -375,14 +402,20 @@ class SearchBoxLayout extends _template.default {
375
402
  }
376
403
  }
377
404
  async _submit(value) {
378
- if (!value || !value.trim()) {
405
+ if (this._disabled || !value || !value.trim()) {
379
406
  return;
380
407
  }
381
408
  this.close();
382
409
  // TODO: q -> value
383
- this._view.hub.update(_index.fields.query(), {
410
+ this._view.hub.update(_clientSdkWorkflow.fields.query(), {
384
411
  q: value
385
412
  });
413
+ if (this.options.clearOnSubmit) {
414
+ const inputElement = this._element && this._element.querySelector(`[data-role="input"]`);
415
+ if (inputElement) {
416
+ inputElement.value = '';
417
+ }
418
+ }
386
419
  this._trackSubmit(value);
387
420
  }
388
421
  _trackSubmit(value) {
@@ -4,13 +4,14 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
+ var _constants = require("../../constants.js");
7
8
  var _commons = require("@miso.ai/commons");
8
9
  var _template = _interopRequireDefault(require("../template.js"));
9
10
  var _trackable = require("../mixin/trackable.js");
10
11
  const _excluded = ["className", "templates"];
11
12
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
13
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
13
- const TYPE = 'select';
14
+ const TYPE = _constants.LAYOUT_TYPE.SELECT;
14
15
  const DEFAULT_CLASSNAME = 'miso-select';
15
16
  function root(layout, state) {
16
17
  const {
@@ -4,11 +4,12 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
+ var _constants = require("../../constants.js");
7
8
  var _collection = _interopRequireDefault(require("./collection.js"));
8
9
  const _excluded = ["className"];
9
10
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
11
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
11
- const TYPE = 'cards';
12
+ const TYPE = _constants.LAYOUT_TYPE.CARDS;
12
13
  const DEFAULT_CLASSNAME = 'miso-cards';
13
14
  class CardsLayout extends _collection.default {
14
15
  static get type() {
@@ -4,13 +4,14 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
+ var _constants = require("../../constants.js");
7
8
  var _collection = _interopRequireDefault(require("./collection.js"));
8
9
  var _swipeable = require("../mixin/swipeable.js");
9
10
  var _svgs = require("../../asset/svgs.js");
10
11
  const _excluded = ["className", "templates"];
11
12
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
13
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
13
- const TYPE = 'carousel';
14
+ const TYPE = _constants.LAYOUT_TYPE.CAROUSEL;
14
15
  const DEFAULT_CLASSNAME = 'miso-carousel';
15
16
  const DEFAULT_TEMPLATES = Object.freeze({
16
17
  body,
@@ -95,6 +95,11 @@ const DEFAULT_TEMPLATES = Object.freeze({
95
95
  compactArticle: _templates.compactArticle,
96
96
  image: _templates.image,
97
97
  question: _templates.question,
98
+ thread: _templates.thread,
99
+ threadMenuBlock: _templates.threadMenuBlock,
100
+ message: _templates.message,
101
+ messageQuestionBlock: _templates.messageQuestionBlock,
102
+ messageAnswerBlock: _templates.messageAnswerBlock,
98
103
  root,
99
104
  [_constants.STATUS.READY]: ready,
100
105
  empty: () => ``,
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
+ var _constants = require("../../constants.js");
7
8
  var _commons = require("@miso.ai/commons");
8
9
  var _collection = _interopRequireDefault(require("./collection.js"));
9
10
  var _dom = require("../../util/dom.js");
@@ -43,7 +44,7 @@ const DEFAULT_HEIGHT = '16rem';
43
44
  const DEFAULT_TEMPLATES = Object.freeze(Object.assign({}, _collection.default.defaultTemplates, {
44
45
  item
45
46
  }));
46
- const TYPE = 'gallery';
47
+ const TYPE = _constants.LAYOUT_TYPE.GALLERY;
47
48
  const DEFAULT_CLASSNAME = 'miso-gallery';
48
49
  class GalleryLayout extends _collection.default {
49
50
  static get type() {
@@ -4,11 +4,12 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
+ var _constants = require("../../constants.js");
7
8
  var _collection = _interopRequireDefault(require("./collection.js"));
8
9
  const _excluded = ["className"];
9
10
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
11
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
11
- const TYPE = 'horizontal';
12
+ const TYPE = _constants.LAYOUT_TYPE.HORIZONTAL;
12
13
  const DEFAULT_CLASSNAME = 'miso-horizontal';
13
14
  class HorizontalLayout extends _collection.default {
14
15
  static get type() {
@@ -4,11 +4,12 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
+ var _constants = require("../../constants.js");
7
8
  var _collection = _interopRequireDefault(require("./collection.js"));
8
9
  const _excluded = ["className"];
9
10
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
11
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
11
- const TYPE = 'list';
12
+ const TYPE = _constants.LAYOUT_TYPE.LIST;
12
13
  const DEFAULT_CLASSNAME = 'miso-list';
13
14
  class ListLayout extends _collection.default {
14
15
  static get type() {
@@ -0,0 +1,346 @@
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 _clientSdkWorkflow = require("@miso.ai/client-sdk-workflow");
9
+ var _constants = require("../../constants.js");
10
+ var _collection = _interopRequireDefault(require("./collection.js"));
11
+ var _utils = require("../text/typewriter/utils.js");
12
+ var _templates = require("../templates.js");
13
+ var _dom = require("../../util/dom.js");
14
+ const _excluded = ["className"];
15
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
16
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
17
+ const TYPE = _constants.LAYOUT_TYPE.MESSAGES;
18
+ const DEFAULT_CLASSNAME = 'miso-messages';
19
+ const TYPEWRITER_CLASSNAME = 'miso-typewriter';
20
+
21
+ /**
22
+ * The conversation panel of the chat history interface: a list of `message`
23
+ * items (question bubble + answer body), rendered incrementally — appended
24
+ * messages (e.g. a posted follow-up question) render as new items, while
25
+ * in-place changes are applied to existing items by a post-render pass
26
+ * (`_syncMessages`):
27
+ *
28
+ * - question texts are filled in when they arrive (the head request carries
29
+ * question ids only)
30
+ * - a finished answer body is transformed from markdown to HTML in one shot
31
+ * through the `std:ui-markdown` plugin
32
+ * - a streaming answer (a follow-up being generated, `finished: false`) is
33
+ * driven by a per-message typewriter: a progressive markdown renderer with
34
+ * a paced cursor, like the typewriter layout of the ask workflow
35
+ */
36
+ class MessagesLayout extends _collection.default {
37
+ static get type() {
38
+ return TYPE;
39
+ }
40
+ static get defaultClassName() {
41
+ return DEFAULT_CLASSNAME;
42
+ }
43
+ constructor(_ref = {}) {
44
+ let {
45
+ className = DEFAULT_CLASSNAME
46
+ } = _ref,
47
+ options = _objectWithoutPropertiesLoose(_ref, _excluded);
48
+ super(Object.assign({
49
+ className
50
+ }, options));
51
+ this._renderedAnswers = new WeakMap(); // answer element -> rendered markdown
52
+ this._typewriters = new WeakMap(); // answer element -> MessageTypewriter
53
+ this._readiness = new _commons.Resolution();
54
+ this._pinned = true; // whether the view sticks to the bottom on updates
55
+ this._displaying = false; // whether a typewriter is still displaying an answer
56
+ // kick off sooner
57
+ MessagesLayout.MisoClient.plugins.install('std:ui-markdown');
58
+ }
59
+ initialize(view) {
60
+ super.initialize(view);
61
+ this._setup();
62
+ }
63
+
64
+ // setup //
65
+ async _setup() {
66
+ try {
67
+ const plugin = await MessagesLayout.MisoClient.plugins.install('std:ui-markdown');
68
+ if (!this._view) {
69
+ return; // destroyed
70
+ }
71
+ this._markdown = plugin.getContext(this._view.workflow._client);
72
+ this._readiness.resolve();
73
+ } catch (e) {
74
+ this._readiness.reject(e);
75
+ }
76
+ }
77
+ async _ready() {
78
+ return this._readiness.promise;
79
+ }
80
+
81
+ // render //
82
+ async render(element, state, controls = {}) {
83
+ // capture the view state callback, so the typewriter can report the
84
+ // `ongoing` state outside the render cycle
85
+ this._notifyUpdate = controls.notifyUpdate;
86
+ await super.render(element, state, controls);
87
+ }
88
+ _afterRender(element, state) {
89
+ super._afterRender(element, state); // syncs bindings to the latest values
90
+ if (!state.incremental) {
91
+ this._displaying = false; // a fresh render (thread load) drops any ongoing typewriter
92
+ }
93
+ if (!state.incremental || state.html) {
94
+ // a fresh render (thread load) or appended items (posted follow-up):
95
+ // jump to the bottom
96
+ this._scrollToBottom({
97
+ force: true
98
+ });
99
+ }
100
+ this._syncMessages(element).catch(error => console.error(error));
101
+ }
102
+ async _syncMessages(element) {
103
+ await this._ready();
104
+ const items = this._getItemElements(element);
105
+ let displaying = false;
106
+ for (let i = 0; i < items.length; i++) {
107
+ const item = items[i];
108
+ const binding = this._bindings.get(item);
109
+ if (!binding) {
110
+ continue;
111
+ }
112
+ const message = binding.value;
113
+ const last = i === items.length - 1;
114
+ this._syncQuestion(item, message);
115
+ this._syncAnswer(item, message, {
116
+ last
117
+ });
118
+ if (last) {
119
+ displaying = this._isDisplaying(item, message);
120
+ }
121
+ }
122
+ this._setDisplaying(displaying);
123
+ }
124
+
125
+ // whether the (last) message pair is still being displayed: its answer is
126
+ // pending, streaming, or still being typed — live (posted in this session)
127
+ // or not: an answer still generating is picked up by the answers polling
128
+ // even after switching away from the thread and back, and must keep
129
+ // blocking submission all the same
130
+ _isDisplaying(item, message) {
131
+ if (!(0, _clientSdkWorkflow.hasAnswer)(message)) {
132
+ return true; // waiting for the answer body
133
+ }
134
+ const answerElement = item.querySelector('[data-role="answer"]');
135
+ const typewriter = answerElement && this._typewriters.get(answerElement);
136
+ return typewriter ? !typewriter.done : message.finished === false;
137
+ }
138
+ _syncQuestion(item, message) {
139
+ const questionElement = item.querySelector('[data-role="question"]');
140
+ if (!questionElement) {
141
+ return;
142
+ }
143
+ // the authorship arrives with the answers response, after the stub render
144
+ (0, _dom.setOrRemoveAttribute)(questionElement, 'data-author', (0, _templates.messageAuthor)(message));
145
+ (0, _dom.setOrRemoveAttribute)(questionElement, 'data-generated-by', (0, _clientSdkWorkflow.getGeneratedBy)(message));
146
+ const {
147
+ question
148
+ } = message;
149
+ if (!question || questionElement.textContent === question) {
150
+ return;
151
+ }
152
+ questionElement.textContent = question;
153
+ questionElement.hidden = false;
154
+ }
155
+ _syncAnswer(item, message, {
156
+ last = false
157
+ } = {}) {
158
+ const answerElement = item.querySelector('[data-role="answer"]');
159
+ if (!answerElement) {
160
+ return;
161
+ }
162
+ // an ongoing typewriter keeps consuming updates until it finishes typing
163
+ const typewriter = this._typewriters.get(answerElement);
164
+ if (typewriter) {
165
+ typewriter.update(message);
166
+ return;
167
+ }
168
+ if (!(0, _clientSdkWorkflow.hasAnswer)(message)) {
169
+ return; // still loading; the spinner stays
170
+ }
171
+ if (message.live || message.finished === false) {
172
+ // an answer being generated live in this session: drive it with a
173
+ // typewriter (even if the data arrived complete in one shot)
174
+ const typewriter = new MessageTypewriter(this._markdown, answerElement, {
175
+ onUpdate: () => this._scrollToBottom(),
176
+ // keep pinned to the bottom while typing
177
+ onDone: () => this._setDisplaying(false)
178
+ });
179
+ this._typewriters.set(answerElement, typewriter);
180
+ typewriter.update(message);
181
+ return;
182
+ }
183
+ // a finished answer: transform in one shot
184
+ if (this._renderedAnswers.get(answerElement) === message.answer) {
185
+ return; // already rendered
186
+ }
187
+ this._renderedAnswers.set(answerElement, message.answer);
188
+ this._transform(answerElement, message).then(() => {
189
+ last && this._scrollToBottom();
190
+ }).catch(error => {
191
+ this._renderedAnswers.delete(answerElement);
192
+ console.error(error);
193
+ });
194
+ }
195
+ async _transform(answerElement, {
196
+ answer,
197
+ sources
198
+ }) {
199
+ answerElement.innerHTML = await this._markdown.transform(answer, sources);
200
+ }
201
+
202
+ // whether the last answer is still being displayed (typed); reported as
203
+ // the `ongoing` view state, e.g. for the search box to disable submission
204
+ _setDisplaying(displaying) {
205
+ if (this._displaying === displaying) {
206
+ return;
207
+ }
208
+ this._displaying = displaying;
209
+ this._notifyUpdate && this._notifyUpdate({
210
+ ongoing: displaying
211
+ });
212
+ }
213
+
214
+ // scrolling //
215
+ /**
216
+ * Scroll the containing scrollable to the bottom. Unless forced, only
217
+ * applies while the user is pinned to the bottom — scrolling up to read
218
+ * releases the pin, scrolling back down restores it.
219
+ */
220
+ _scrollToBottom({
221
+ force = false
222
+ } = {}) {
223
+ const scrollable = this._getScrollable();
224
+ if (!scrollable || !(force || this._pinned)) {
225
+ return;
226
+ }
227
+ scrollable.scrollTop = scrollable.scrollHeight;
228
+ this._pinned = true;
229
+ }
230
+ _getScrollable() {
231
+ const element = this._element;
232
+ if (!element || typeof getComputedStyle === 'undefined') {
233
+ return undefined;
234
+ }
235
+ for (let el = element; el && el.nodeType === 1 && el !== document.body; el = el.parentElement) {
236
+ const {
237
+ overflowY
238
+ } = getComputedStyle(el);
239
+ if (overflowY === 'auto' || overflowY === 'scroll') {
240
+ this._watchScroll(el);
241
+ return el;
242
+ }
243
+ }
244
+ return undefined;
245
+ }
246
+ _watchScroll(scrollable) {
247
+ if (this._watchedScrollable === scrollable) {
248
+ return;
249
+ }
250
+ this._unwatchScroll && this._unwatchScroll();
251
+ const onScroll = () => {
252
+ this._pinned = scrollable.scrollHeight - scrollable.scrollTop - scrollable.clientHeight < 40;
253
+ };
254
+ scrollable.addEventListener('scroll', onScroll, {
255
+ passive: true
256
+ });
257
+ this._watchedScrollable = scrollable;
258
+ const unwatch = this._unwatchScroll = () => {
259
+ scrollable.removeEventListener('scroll', onScroll);
260
+ this._watchedScrollable = undefined;
261
+ this._unwatchScroll = undefined;
262
+ };
263
+ this._unsubscribes.push(() => this._unwatchScroll === unwatch && unwatch());
264
+ }
265
+ }
266
+
267
+ // TODO: can't we just use Controller?
268
+ /**
269
+ * Types a streaming answer into an element: a progressive markdown renderer
270
+ * fed by data updates, advanced by a paced cursor on animation frames — the
271
+ * typewriting effect, without the full typewriter layout machinery.
272
+ */
273
+ exports.default = MessagesLayout;
274
+ class MessageTypewriter {
275
+ constructor(markdown, element, {
276
+ onUpdate,
277
+ onDone
278
+ } = {}) {
279
+ this._element = element;
280
+ this._onUpdate = onUpdate;
281
+ this._onDone = onDone;
282
+ // the element acts as a typewriter container: it starts as the caret ref
283
+ // (the cursor class moves into the content as it types), and the preset
284
+ // stamps the `done` class on finish, which hides the caret via CSS
285
+ element.classList.add(TYPEWRITER_CLASSNAME, (0, _utils.cursorClassName)(TYPEWRITER_CLASSNAME));
286
+ this._renderer = markdown.createRenderer({
287
+ cursorClass: (0, _utils.cursorClassName)(TYPEWRITER_CLASSNAME),
288
+ getSource: index => (this._sources || [])[index]
289
+ });
290
+ this._getNextCursor = (0, _commons.pacer)();
291
+ this._rendered = this._renderer.clear(element);
292
+ this._timestamp = undefined;
293
+ this._value = '';
294
+ this._sources = undefined;
295
+ this._dataDone = false;
296
+ this._doneAt = undefined;
297
+ this._requested = false;
298
+ }
299
+ get done() {
300
+ return this._rendered.done;
301
+ }
302
+ update({
303
+ answer = '',
304
+ finished,
305
+ sources
306
+ }) {
307
+ this._value = answer;
308
+ this._sources = sources;
309
+ this._dataDone = finished !== false;
310
+ this._requestFrame();
311
+ }
312
+ _requestFrame() {
313
+ if (this._requested || this._rendered.done) {
314
+ return;
315
+ }
316
+ this._requested = true;
317
+ (0, _commons.requestAnimationFrame)(timestamp => this._frame(timestamp));
318
+ }
319
+ _frame(timestamp) {
320
+ this._requested = false;
321
+ if (!this._element.isConnected) {
322
+ // the element is gone (re-render, thread switch); stop typing
323
+ this._onDone && this._onDone();
324
+ return;
325
+ }
326
+ const prev = this._rendered;
327
+ const prevTimestamp = this._timestamp !== undefined ? this._timestamp : timestamp;
328
+ if (this._dataDone && this._doneAt === undefined) {
329
+ this._doneAt = timestamp;
330
+ }
331
+ const cursor = this._getNextCursor(prev.cursor, this._doneAt, prevTimestamp, timestamp);
332
+ this._rendered = this._renderer.update(this._element, prev, {
333
+ value: this._value,
334
+ cursor,
335
+ timestamp,
336
+ done: this._dataDone
337
+ });
338
+ this._timestamp = timestamp;
339
+ this._onUpdate && this._onUpdate();
340
+ if (!this._rendered.done) {
341
+ this._requestFrame();
342
+ } else {
343
+ this._onDone && this._onDone();
344
+ }
345
+ }
346
+ }