@miso.ai/client-sdk-ui 1.13.2-beta.1 → 1.14.0-beta.3
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/asset/svgs.js +17 -4
- package/dist/cjs/combo/ask/index.js +2 -2
- package/dist/cjs/constants.js +120 -98
- package/dist/cjs/defaults/ask/controls.js +1 -1
- package/dist/cjs/defaults/hybrid-search/answer-box.js +4 -4
- package/dist/cjs/defaults.js +259 -0
- package/dist/cjs/element/container/index.js +28 -0
- package/dist/cjs/element/container/miso-ask.js +3 -3
- package/dist/cjs/element/container/miso-conversation.js +21 -0
- package/dist/cjs/element/container/miso-explore.js +1 -1
- package/dist/cjs/element/container/miso-history.js +21 -0
- package/dist/cjs/element/container/miso-hybrid-search.js +1 -1
- package/dist/cjs/element/container/miso-message-item.js +91 -0
- package/dist/cjs/element/container/miso-recommendation.js +1 -1
- package/dist/cjs/element/container/miso-search.js +1 -1
- package/dist/cjs/element/container/miso-thread-item.js +91 -0
- package/dist/cjs/element/context/miso-follow-ups.js +1 -1
- package/dist/cjs/element/role/index.js +49 -0
- package/dist/cjs/element/role/miso-delete.js +20 -0
- package/dist/cjs/element/role/miso-messages.js +20 -0
- package/dist/cjs/element/role/miso-new-thread.js +20 -0
- package/dist/cjs/element/role/miso-rename.js +20 -0
- package/dist/cjs/element/role/miso-subscription.js +20 -0
- package/dist/cjs/element/role/miso-threads.js +20 -0
- package/dist/cjs/element/role/miso-title.js +20 -0
- package/dist/cjs/layout/affiliation/affiliation.js +1 -1
- package/dist/cjs/layout/banner/banner.js +2 -1
- package/dist/cjs/layout/button/button.js +170 -0
- package/dist/cjs/layout/button/checkbox.js +116 -0
- package/dist/cjs/layout/button/more-button.js +3 -3
- package/dist/cjs/layout/container/container.js +1 -1
- package/dist/cjs/layout/container/item-container.js +99 -0
- package/dist/cjs/layout/error/error.js +2 -1
- package/dist/cjs/layout/index.js +42 -0
- package/dist/cjs/layout/input/facets.js +4 -3
- package/dist/cjs/layout/input/option-list.js +3 -2
- package/dist/cjs/layout/input/search-box.js +50 -12
- package/dist/cjs/layout/input/select.js +2 -1
- package/dist/cjs/layout/list/cards.js +2 -1
- package/dist/cjs/layout/list/carousel.js +2 -1
- package/dist/cjs/layout/list/collection.js +13 -1
- package/dist/cjs/layout/list/gallery.js +2 -1
- package/dist/cjs/layout/list/horizontal.js +2 -1
- package/dist/cjs/layout/list/list.js +2 -1
- package/dist/cjs/layout/list/messages.js +359 -0
- package/dist/cjs/layout/list/threads.js +199 -0
- package/dist/cjs/layout/mixin/trackable.js +4 -5
- package/dist/cjs/layout/mixin/triggerable.js +2 -2
- package/dist/cjs/layout/radio/feedback.js +4 -3
- package/dist/cjs/layout/templates.js +97 -0
- package/dist/cjs/layout/text/question.js +71 -0
- package/dist/cjs/layout/text/text.js +2 -1
- package/dist/cjs/layout/text/typewriter/index.js +18 -23
- package/dist/cjs/plugin.js +43 -104
- package/dist/cjs/util/confirm.js +33 -0
- package/dist/cjs/util/dom.js +21 -0
- package/dist/cjs/util/modal.js +48 -0
- package/dist/cjs/util/prompt.js +47 -0
- package/dist/cjs/version.js +1 -1
- package/package.json +5 -4
- package/src/CLAUDE.md +51 -104
- package/src/asset/svgs.js +16 -3
- package/src/combo/ask/index.js +2 -2
- package/src/constants.js +39 -147
- package/src/defaults/ask/controls.js +1 -1
- package/src/defaults/hybrid-search/answer-box.js +2 -2
- package/src/defaults.js +174 -0
- package/src/element/container/index.js +4 -0
- package/src/element/container/miso-ask.js +3 -3
- package/src/element/container/miso-conversation.js +19 -0
- package/src/element/container/miso-explore.js +1 -1
- package/src/element/container/miso-history.js +19 -0
- package/src/element/container/miso-hybrid-search.js +1 -1
- package/src/element/container/miso-message-item.js +94 -0
- package/src/element/container/miso-recommendation.js +1 -1
- package/src/element/container/miso-search.js +1 -1
- package/src/element/container/miso-thread-item.js +94 -0
- package/src/element/context/miso-follow-ups.js +1 -1
- package/src/element/role/index.js +7 -0
- package/src/element/role/miso-delete.js +16 -0
- package/src/element/role/miso-messages.js +16 -0
- package/src/element/role/miso-new-thread.js +16 -0
- package/src/element/role/miso-rename.js +16 -0
- package/src/element/role/miso-subscription.js +16 -0
- package/src/element/role/miso-threads.js +16 -0
- package/src/element/role/miso-title.js +16 -0
- package/src/layout/affiliation/affiliation.js +2 -2
- package/src/layout/banner/banner.js +2 -1
- package/src/layout/button/button.js +152 -0
- package/src/layout/button/checkbox.js +92 -0
- package/src/layout/button/more-button.js +3 -3
- package/src/layout/container/container.js +2 -2
- package/src/layout/container/item-container.js +99 -0
- package/src/layout/error/error.js +2 -1
- package/src/layout/index.js +6 -0
- package/src/layout/input/facets.js +3 -2
- package/src/layout/input/option-list.js +3 -2
- package/src/layout/input/search-box.js +45 -8
- package/src/layout/input/select.js +2 -1
- package/src/layout/list/cards.js +2 -1
- package/src/layout/list/carousel.js +2 -1
- package/src/layout/list/collection.js +15 -2
- package/src/layout/list/gallery.js +2 -1
- package/src/layout/list/horizontal.js +2 -1
- package/src/layout/list/list.js +2 -1
- package/src/layout/list/messages.js +316 -0
- package/src/layout/list/threads.js +166 -0
- package/src/layout/mixin/trackable.js +2 -3
- package/src/layout/mixin/triggerable.js +1 -1
- package/src/layout/radio/feedback.js +3 -2
- package/src/layout/templates.js +97 -0
- package/src/layout/text/question.js +58 -0
- package/src/layout/text/text.js +2 -1
- package/src/layout/text/typewriter/index.js +15 -18
- package/src/plugin.js +31 -117
- package/src/util/confirm.js +28 -0
- package/src/util/dom.js +16 -0
- package/src/util/modal.js +49 -0
- package/src/util/prompt.js +42 -0
- package/src/version.js +1 -1
- package/dist/cjs/actor/data.js +0 -132
- package/dist/cjs/actor/feedback.js +0 -29
- package/dist/cjs/actor/fields.js +0 -57
- package/dist/cjs/actor/filters.js +0 -161
- package/dist/cjs/actor/hub.js +0 -57
- package/dist/cjs/actor/index.js +0 -73
- package/dist/cjs/actor/interactions.js +0 -36
- package/dist/cjs/actor/sessions.js +0 -25
- package/dist/cjs/actor/tracker-states.js +0 -61
- package/dist/cjs/actor/tracker.js +0 -109
- package/dist/cjs/actor/trackers.js +0 -52
- package/dist/cjs/actor/utils.js +0 -15
- package/dist/cjs/actor/view.js +0 -294
- package/dist/cjs/actor/views.js +0 -209
- package/dist/cjs/source.js +0 -27
- package/dist/cjs/util/proxy.js +0 -88
- package/dist/cjs/util/trackers.js +0 -88
- package/dist/cjs/workflow/affiliations.js +0 -140
- package/dist/cjs/workflow/answer-based.js +0 -337
- package/dist/cjs/workflow/ask.js +0 -319
- package/dist/cjs/workflow/asks.js +0 -150
- package/dist/cjs/workflow/autocompletable.js +0 -63
- package/dist/cjs/workflow/autocomplete.js +0 -120
- package/dist/cjs/workflow/base.js +0 -418
- package/dist/cjs/workflow/context.js +0 -19
- package/dist/cjs/workflow/explore.js +0 -210
- package/dist/cjs/workflow/explores.js +0 -21
- package/dist/cjs/workflow/hybrid-search-answer.js +0 -88
- package/dist/cjs/workflow/hybrid-search-views.js +0 -109
- package/dist/cjs/workflow/hybrid-search.js +0 -213
- package/dist/cjs/workflow/index.js +0 -41
- package/dist/cjs/workflow/options/api.js +0 -41
- package/dist/cjs/workflow/options/auto-query.js +0 -97
- package/dist/cjs/workflow/options/configurable.js +0 -45
- package/dist/cjs/workflow/options/data-processor.js +0 -20
- package/dist/cjs/workflow/options/filters.js +0 -15
- package/dist/cjs/workflow/options/index.js +0 -126
- package/dist/cjs/workflow/options/interactions.js +0 -41
- package/dist/cjs/workflow/options/layouts.js +0 -79
- package/dist/cjs/workflow/options/options.js +0 -156
- package/dist/cjs/workflow/options/pagination.js +0 -25
- package/dist/cjs/workflow/options/roles.js +0 -15
- package/dist/cjs/workflow/options/templates.js +0 -30
- package/dist/cjs/workflow/options/trackers.js +0 -83
- package/dist/cjs/workflow/options/utils.js +0 -33
- package/dist/cjs/workflow/processors.js +0 -607
- package/dist/cjs/workflow/recommendation.js +0 -57
- package/dist/cjs/workflow/recommendations.js +0 -18
- package/dist/cjs/workflow/search-based.js +0 -337
- package/dist/cjs/workflow/search.js +0 -64
- package/dist/cjs/workflow/unit.js +0 -57
- package/dist/cjs/workflow/units.js +0 -42
- package/dist/cjs/workflow/use-link.js +0 -49
- package/src/actor/data.js +0 -106
- package/src/actor/feedback.js +0 -28
- package/src/actor/fields.js +0 -51
- package/src/actor/filters.js +0 -149
- package/src/actor/hub.js +0 -47
- package/src/actor/index.js +0 -10
- package/src/actor/interactions.js +0 -32
- package/src/actor/sessions.js +0 -21
- package/src/actor/tracker-states.js +0 -57
- package/src/actor/tracker.js +0 -104
- package/src/actor/trackers.js +0 -45
- package/src/actor/utils.js +0 -7
- package/src/actor/view.js +0 -272
- package/src/actor/views.js +0 -224
- package/src/source.js +0 -17
- package/src/util/proxy.js +0 -81
- package/src/util/trackers.js +0 -84
- package/src/workflow/affiliations.js +0 -121
- package/src/workflow/answer-based.js +0 -312
- package/src/workflow/ask.js +0 -284
- package/src/workflow/asks.js +0 -143
- package/src/workflow/autocompletable.js +0 -67
- package/src/workflow/autocomplete.js +0 -114
- package/src/workflow/base.js +0 -396
- package/src/workflow/context.js +0 -16
- package/src/workflow/explore.js +0 -194
- package/src/workflow/explores.js +0 -18
- package/src/workflow/hybrid-search-answer.js +0 -73
- package/src/workflow/hybrid-search-views.js +0 -116
- package/src/workflow/hybrid-search.js +0 -230
- package/src/workflow/index.js +0 -5
- package/src/workflow/options/api.js +0 -31
- package/src/workflow/options/auto-query.js +0 -70
- package/src/workflow/options/configurable.js +0 -48
- package/src/workflow/options/data-processor.js +0 -15
- package/src/workflow/options/filters.js +0 -10
- package/src/workflow/options/index.js +0 -11
- package/src/workflow/options/interactions.js +0 -36
- package/src/workflow/options/layouts.js +0 -73
- package/src/workflow/options/options.js +0 -175
- package/src/workflow/options/pagination.js +0 -18
- package/src/workflow/options/roles.js +0 -12
- package/src/workflow/options/templates.js +0 -27
- package/src/workflow/options/trackers.js +0 -80
- package/src/workflow/options/utils.js +0 -26
- package/src/workflow/processors.js +0 -490
- package/src/workflow/recommendation.js +0 -63
- package/src/workflow/recommendations.js +0 -14
- package/src/workflow/search-based.js +0 -329
- package/src/workflow/search.js +0 -73
- package/src/workflow/unit.js +0 -51
- package/src/workflow/units.js +0 -43
- 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
|
|
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 =
|
|
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(
|
|
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[
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
367
|
+
if (this.options.blurOnSubmit !== false) {
|
|
368
|
+
inputElement.blur();
|
|
369
|
+
}
|
|
343
370
|
this._submit(inputElement.value);
|
|
344
371
|
}
|
|
345
372
|
return;
|
|
@@ -375,14 +402,25 @@ 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
|
-
//
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
409
|
+
// a view event, like the buttons: the workflow routes it into its query
|
|
410
|
+
// flow (or its own submission semantics), the layout stays hands-off
|
|
411
|
+
const {
|
|
412
|
+
session
|
|
413
|
+
} = this._view._state || {};
|
|
414
|
+
this._view._emit('submit', Object.freeze({
|
|
415
|
+
session,
|
|
416
|
+
value
|
|
417
|
+
}));
|
|
418
|
+
if (this.options.clearOnSubmit) {
|
|
419
|
+
const inputElement = this._element && this._element.querySelector(`[data-role="input"]`);
|
|
420
|
+
if (inputElement) {
|
|
421
|
+
inputElement.value = '';
|
|
422
|
+
}
|
|
423
|
+
}
|
|
386
424
|
this._trackSubmit(value);
|
|
387
425
|
}
|
|
388
426
|
_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 =
|
|
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 =
|
|
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 =
|
|
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
|
+
threadBody: _templates.threadBody,
|
|
100
|
+
threadMenuBlock: _templates.threadMenuBlock,
|
|
101
|
+
message: _templates.message,
|
|
102
|
+
messageBody: _templates.messageBody,
|
|
98
103
|
root,
|
|
99
104
|
[_constants.STATUS.READY]: ready,
|
|
100
105
|
empty: () => ``,
|
|
@@ -203,7 +208,14 @@ class CollectionLayout extends _template.default {
|
|
|
203
208
|
return element.querySelector('[data-role="list"]');
|
|
204
209
|
}
|
|
205
210
|
_getItemElements(element) {
|
|
206
|
-
|
|
211
|
+
if (!element) {
|
|
212
|
+
return [];
|
|
213
|
+
}
|
|
214
|
+
// an item may host a nested collection with items of its own (a
|
|
215
|
+
// conversation message and its source cards): ours are only those whose
|
|
216
|
+
// closest list is this layout's own list
|
|
217
|
+
const listElement = this._getListElement(element);
|
|
218
|
+
return Array.from((listElement || element).querySelectorAll(`[data-role="item"]`)).filter(item => item.closest(`[data-role="list"]`) === listElement);
|
|
207
219
|
}
|
|
208
220
|
_onClick(event) {
|
|
209
221
|
const element = event.target.closest(`[data-role="item"]`);
|
|
@@ -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 =
|
|
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 =
|
|
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 =
|
|
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,359 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _constants = require("../../constants.js");
|
|
8
|
+
var _collection = _interopRequireDefault(require("./collection.js"));
|
|
9
|
+
const _excluded = ["className", "templates"];
|
|
10
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
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; }
|
|
12
|
+
const TYPE = _constants.LAYOUT_TYPE.MESSAGES;
|
|
13
|
+
const DEFAULT_CLASSNAME = 'miso-messages';
|
|
14
|
+
|
|
15
|
+
// the infinite scroll trigger sits ABOVE the list — older messages load as
|
|
16
|
+
// the user scrolls up, unlike the stock collection root's bottom trigger
|
|
17
|
+
function root(layout, state) {
|
|
18
|
+
const {
|
|
19
|
+
className,
|
|
20
|
+
role,
|
|
21
|
+
templates,
|
|
22
|
+
options
|
|
23
|
+
} = layout;
|
|
24
|
+
const {
|
|
25
|
+
status
|
|
26
|
+
} = state;
|
|
27
|
+
const roleAttr = role ? ` data-role="${role}"` : '';
|
|
28
|
+
const itemTypeAttr = options.itemType ? ` data-item-type="${options.itemType}"` : '';
|
|
29
|
+
return `<div class="${className} ${status}"${roleAttr}${itemTypeAttr}>${templates.trigger(layout, state)}${status === _constants.STATUS.READY ? templates[status](layout, state) : ''}${templates.loading(layout, state)}</div>`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The conversation panel of the chat history interface: a shell that renders
|
|
34
|
+
* one <miso-message-item> container element per message item, incrementally —
|
|
35
|
+
* fresh items land at either end of the list: appended messages (a posted
|
|
36
|
+
* follow-up question) render as new items at the bottom, while an older
|
|
37
|
+
* page fetched by the more flow (infinite scroll: the trigger, placed above
|
|
38
|
+
* the list, fires the `more` hub field as the user scrolls up) renders as
|
|
39
|
+
* prepended items — told apart by which boundary the already-rendered
|
|
40
|
+
* records line up with.
|
|
41
|
+
* The content of a message is not rendered here: each <miso-message-item> is
|
|
42
|
+
* assigned its item subworkflow (workflow._getMessageWorkflow, off the item
|
|
43
|
+
* binding) in the post-render sync pass, and the role elements inside
|
|
44
|
+
* (question, answer, ...) render through that workflow's own layouts.
|
|
45
|
+
*
|
|
46
|
+
* All message-level presentation is the message workflow's own: a record
|
|
47
|
+
* without its answer body presents as status `loading`, stamped on the
|
|
48
|
+
* <miso-message-item> element by its container layout — there is deliberately no
|
|
49
|
+
* per-message loading icon; the answer typewriter's blinking caret is the
|
|
50
|
+
* loading indication — and the question bubble (text, authorship
|
|
51
|
+
* attributes) renders through the `question` layout.
|
|
52
|
+
*
|
|
53
|
+
* The shell keeps the panel-level behaviors: scroll pinning (the view sticks
|
|
54
|
+
* to the bottom while the user has not scrolled up, following content growth
|
|
55
|
+
* as answers type out), scroll anchoring while scrolled up (prepended items
|
|
56
|
+
* — and their contents, rendering in later through their own workflows —
|
|
57
|
+
* must not shift the reading position), and the `ongoing` view state read
|
|
58
|
+
* off the data — the last message's answer absent or unfinished — which
|
|
59
|
+
* e.g. disables the search box while an answer is on its way.
|
|
60
|
+
*/
|
|
61
|
+
class MessagesLayout extends _collection.default {
|
|
62
|
+
static get type() {
|
|
63
|
+
return TYPE;
|
|
64
|
+
}
|
|
65
|
+
static get defaultClassName() {
|
|
66
|
+
return DEFAULT_CLASSNAME;
|
|
67
|
+
}
|
|
68
|
+
constructor(_ref = {}) {
|
|
69
|
+
let {
|
|
70
|
+
className = DEFAULT_CLASSNAME,
|
|
71
|
+
templates
|
|
72
|
+
} = _ref,
|
|
73
|
+
options = _objectWithoutPropertiesLoose(_ref, _excluded);
|
|
74
|
+
super(Object.assign({
|
|
75
|
+
className,
|
|
76
|
+
templates: Object.assign({
|
|
77
|
+
root
|
|
78
|
+
}, templates)
|
|
79
|
+
}, options));
|
|
80
|
+
this._pinned = true; // whether the view sticks to the bottom on updates
|
|
81
|
+
this._anchor = undefined; // the scroll anchor while prepended content settles
|
|
82
|
+
this._ongoing = undefined;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// item identity: the question id, or the local placeholder id standing in
|
|
86
|
+
// for it while a posted question awaits its response — the placeholder id
|
|
87
|
+
// survives the settle, so the element and its workflow do too
|
|
88
|
+
_getItemKey(message) {
|
|
89
|
+
return message.placeholder_id || message.question_id || message;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// render //
|
|
93
|
+
async render(element, state, controls = {}) {
|
|
94
|
+
// capture the view state callback for the ongoing report
|
|
95
|
+
this._notifyUpdate = controls.notifyUpdate;
|
|
96
|
+
await super.render(element, state, controls);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// incremental renders cover a pure append (a posted follow-up at the
|
|
100
|
+
// bottom) or a pure prepend (an older page above) — anything else
|
|
101
|
+
// re-renders in full
|
|
102
|
+
_shallRenderIncrementally(state, rendered) {
|
|
103
|
+
if (!super._shallRenderIncrementally(state, rendered)) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
const values = this._getItems(state) || [];
|
|
107
|
+
const renderedValues = rendered.value;
|
|
108
|
+
const count = values.length - renderedValues.length;
|
|
109
|
+
return count === 0 ||
|
|
110
|
+
// in-place changes only
|
|
111
|
+
this._getItemKey(values[0]) === this._getItemKey(renderedValues[0]) ||
|
|
112
|
+
// appended
|
|
113
|
+
this._getItemKey(values[count]) === this._getItemKey(renderedValues[0]); // prepended
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// the fresh items land at the tail (a posted follow-up) or at the head
|
|
117
|
+
// (an older page fetched by the more flow): told apart by which boundary
|
|
118
|
+
// the already-rendered records line up with
|
|
119
|
+
_html(state, rendered, incremental) {
|
|
120
|
+
if (!incremental) {
|
|
121
|
+
return this.templates.root(this, state);
|
|
122
|
+
}
|
|
123
|
+
const values = this._getItems(state) || [];
|
|
124
|
+
const renderedValues = rendered.value;
|
|
125
|
+
const count = values.length - renderedValues.length;
|
|
126
|
+
if (count === 0) {
|
|
127
|
+
return '';
|
|
128
|
+
}
|
|
129
|
+
if (this._getItemKey(values[0]) === this._getItemKey(renderedValues[0])) {
|
|
130
|
+
const fresh = values.slice(renderedValues.length);
|
|
131
|
+
return {
|
|
132
|
+
position: 'beforeend',
|
|
133
|
+
items: this.templates.items(this, state, fresh, {
|
|
134
|
+
offset: renderedValues.length
|
|
135
|
+
})
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
const fresh = values.slice(0, count);
|
|
139
|
+
return {
|
|
140
|
+
position: 'afterbegin',
|
|
141
|
+
items: this.templates.items(this, state, fresh, {
|
|
142
|
+
offset: 0
|
|
143
|
+
})
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
_render(element, {
|
|
147
|
+
state
|
|
148
|
+
}, {
|
|
149
|
+
notifyUpdate
|
|
150
|
+
}) {
|
|
151
|
+
const {
|
|
152
|
+
incremental,
|
|
153
|
+
html
|
|
154
|
+
} = state;
|
|
155
|
+
if (incremental) {
|
|
156
|
+
if (html) {
|
|
157
|
+
const listElement = this._getListElement(element);
|
|
158
|
+
if (html.position === 'afterbegin') {
|
|
159
|
+
this._prependAnchored(listElement, html.items);
|
|
160
|
+
} else {
|
|
161
|
+
listElement.insertAdjacentHTML('beforeend', html.items);
|
|
162
|
+
}
|
|
163
|
+
} else {
|
|
164
|
+
notifyUpdate(false);
|
|
165
|
+
}
|
|
166
|
+
} else {
|
|
167
|
+
element.innerHTML = html;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
_afterRender(element, state) {
|
|
171
|
+
super._afterRender(element, state); // syncs bindings and (re)arms the trigger
|
|
172
|
+
if (!state.incremental) {
|
|
173
|
+
// a fresh render (thread load): jump to the bottom
|
|
174
|
+
this._dropAnchor();
|
|
175
|
+
this._scrollToBottom({
|
|
176
|
+
force: true
|
|
177
|
+
});
|
|
178
|
+
} else if (state.html && state.html.position === 'beforeend') {
|
|
179
|
+
// appended items (posted follow-up): jump to the bottom
|
|
180
|
+
this._scrollToBottom({
|
|
181
|
+
force: true
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
this._watchGrowth(this._getListElement(element) || element);
|
|
185
|
+
this._syncWorkflows(element);
|
|
186
|
+
this._syncOngoing(state);
|
|
187
|
+
}
|
|
188
|
+
_unrender() {
|
|
189
|
+
super._unrender();
|
|
190
|
+
this._dropAnchor();
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// assign each <miso-message-item> its item subworkflow, off the item binding
|
|
194
|
+
_syncWorkflows(element) {
|
|
195
|
+
const workflow = this._view && this._view.workflow;
|
|
196
|
+
if (!workflow || typeof workflow._getMessageWorkflow !== 'function') {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
for (const item of this._getItemElements(element)) {
|
|
200
|
+
const binding = this._bindings.get(item);
|
|
201
|
+
if (binding && item.isContainer) {
|
|
202
|
+
item.workflow = workflow._getMessageWorkflow(binding.value);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// whether an answer is on its way — pending, or still being generated —
|
|
208
|
+
// reported as the `ongoing` view state, e.g. for the search box to disable
|
|
209
|
+
// submission
|
|
210
|
+
_syncOngoing(state) {
|
|
211
|
+
const messages = state.value || [];
|
|
212
|
+
const last = messages[messages.length - 1];
|
|
213
|
+
// a message settled by a failed content fetch is not on its way anymore
|
|
214
|
+
const ongoing = !!last && !last.error && (last.answer === undefined || last.finished === false);
|
|
215
|
+
if (this._ongoing === ongoing) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
this._ongoing = ongoing;
|
|
219
|
+
this._notifyUpdate && this._notifyUpdate({
|
|
220
|
+
ongoing
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// scrolling //
|
|
225
|
+
/**
|
|
226
|
+
* Scroll the containing scrollable to the bottom. Unless forced, only
|
|
227
|
+
* applies while the user is pinned to the bottom — scrolling up to read
|
|
228
|
+
* releases the pin, scrolling back down restores it.
|
|
229
|
+
*/
|
|
230
|
+
_scrollToBottom({
|
|
231
|
+
force = false
|
|
232
|
+
} = {}) {
|
|
233
|
+
const scrollable = this._getScrollable();
|
|
234
|
+
if (!scrollable || !(force || this._pinned)) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
scrollable.scrollTop = scrollable.scrollHeight;
|
|
238
|
+
this._pinned = true;
|
|
239
|
+
}
|
|
240
|
+
_getScrollable() {
|
|
241
|
+
const element = this._element;
|
|
242
|
+
if (!element || typeof getComputedStyle === 'undefined') {
|
|
243
|
+
return undefined;
|
|
244
|
+
}
|
|
245
|
+
for (let el = element; el && el.nodeType === 1 && el !== document.body; el = el.parentElement) {
|
|
246
|
+
const {
|
|
247
|
+
overflowY
|
|
248
|
+
} = getComputedStyle(el);
|
|
249
|
+
if (overflowY === 'auto' || overflowY === 'scroll') {
|
|
250
|
+
this._watchScroll(el);
|
|
251
|
+
return el;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return undefined;
|
|
255
|
+
}
|
|
256
|
+
_watchScroll(scrollable) {
|
|
257
|
+
if (this._watchedScrollable === scrollable) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
this._unwatchScroll && this._unwatchScroll();
|
|
261
|
+
const onScroll = () => {
|
|
262
|
+
this._pinned = scrollable.scrollHeight - scrollable.scrollTop - scrollable.clientHeight < 40;
|
|
263
|
+
if (this._pinned) {
|
|
264
|
+
// back at the bottom: the reading position needs no anchor
|
|
265
|
+
this._anchor = undefined;
|
|
266
|
+
} else if (this._anchor && this._anchor.element.isConnected) {
|
|
267
|
+
// follow the user: the anchor holds the position they scrolled to,
|
|
268
|
+
// not the one where the prepend happened
|
|
269
|
+
this._anchor.top = this._relativeTop(this._anchor.element, scrollable);
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
scrollable.addEventListener('scroll', onScroll, {
|
|
273
|
+
passive: true
|
|
274
|
+
});
|
|
275
|
+
this._watchedScrollable = scrollable;
|
|
276
|
+
const unwatch = this._unwatchScroll = () => {
|
|
277
|
+
scrollable.removeEventListener('scroll', onScroll);
|
|
278
|
+
this._watchedScrollable = undefined;
|
|
279
|
+
this._unwatchScroll = undefined;
|
|
280
|
+
};
|
|
281
|
+
this._unsubscribes.push(() => this._unwatchScroll === unwatch && unwatch());
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// the message contents render (and type out) through their own workflows,
|
|
285
|
+
// outside this layout's render cycle: follow the content growth — pinned,
|
|
286
|
+
// the view sticks to the bottom; scrolled up with an anchor active (a
|
|
287
|
+
// prepended page still rendering its contents in), the anchor is held
|
|
288
|
+
// stationary instead
|
|
289
|
+
_watchGrowth(element) {
|
|
290
|
+
if (!element || this._watchedGrowth === element || typeof ResizeObserver === 'undefined') {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
this._unwatchGrowth && this._unwatchGrowth();
|
|
294
|
+
const observer = new ResizeObserver(() => this._onContentGrowth());
|
|
295
|
+
observer.observe(element);
|
|
296
|
+
this._watchedGrowth = element;
|
|
297
|
+
const unwatch = this._unwatchGrowth = () => {
|
|
298
|
+
observer.disconnect();
|
|
299
|
+
this._watchedGrowth = undefined;
|
|
300
|
+
this._unwatchGrowth = undefined;
|
|
301
|
+
};
|
|
302
|
+
this._unsubscribes.push(() => this._unwatchGrowth === unwatch && unwatch());
|
|
303
|
+
}
|
|
304
|
+
_onContentGrowth() {
|
|
305
|
+
if (this._pinned) {
|
|
306
|
+
this._scrollToBottom();
|
|
307
|
+
} else {
|
|
308
|
+
this._restoreAnchor();
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// scroll anchoring for prepended content //
|
|
313
|
+
// The anchor is the previously-first item: everything prepended — and
|
|
314
|
+
// its content, rendering in later through the item workflows — sits
|
|
315
|
+
// above it, so holding the anchor stationary holds the reading position,
|
|
316
|
+
// while growth below it (a streaming answer at the bottom) moves nothing
|
|
317
|
+
// above and needs no compensation. Not the browser's own scroll
|
|
318
|
+
// anchoring, which not every engine provides.
|
|
319
|
+
_prependAnchored(listElement, items) {
|
|
320
|
+
this._setAnchor();
|
|
321
|
+
listElement.insertAdjacentHTML('afterbegin', items);
|
|
322
|
+
this._restoreAnchor();
|
|
323
|
+
}
|
|
324
|
+
_setAnchor() {
|
|
325
|
+
const scrollable = this._getScrollable();
|
|
326
|
+
const element = this._getItemElements(this._element)[0];
|
|
327
|
+
this._anchor = scrollable && element ? {
|
|
328
|
+
element,
|
|
329
|
+
scrollable,
|
|
330
|
+
top: this._relativeTop(element, scrollable)
|
|
331
|
+
} : undefined;
|
|
332
|
+
}
|
|
333
|
+
_restoreAnchor() {
|
|
334
|
+
const anchor = this._anchor;
|
|
335
|
+
if (!anchor) {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
const {
|
|
339
|
+
element,
|
|
340
|
+
scrollable,
|
|
341
|
+
top
|
|
342
|
+
} = anchor;
|
|
343
|
+
if (!element.isConnected) {
|
|
344
|
+
this._anchor = undefined;
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
const delta = this._relativeTop(element, scrollable) - top;
|
|
348
|
+
if (delta) {
|
|
349
|
+
scrollable.scrollTop += delta;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
_relativeTop(element, scrollable) {
|
|
353
|
+
return element.getBoundingClientRect().top - scrollable.getBoundingClientRect().top;
|
|
354
|
+
}
|
|
355
|
+
_dropAnchor() {
|
|
356
|
+
this._anchor = undefined;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
exports.default = MessagesLayout;
|