@miso.ai/client-sdk-ui 1.9.0 → 1.9.1-beta.0

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.
@@ -1,6 +1,4 @@
1
1
  import { defineValues, waitForDomContentLoaded } from '@miso.ai/commons';
2
- import { fields } from '../../actor/index.js';
3
- import { ROLE } from '../../constants.js';
4
2
  import Combo from '../base.js';
5
3
  import AskComboOptions from './options.js';
6
4
  import AskComboElements from './elements.js';
@@ -109,7 +107,7 @@ export default class AskCombo extends Combo {
109
107
 
110
108
  // when a answer is fully populated, insert a new section for the follow-up question
111
109
  context.on('done', ({ workflow }) => {
112
- elements.followUpsSection.insertAdjacentHTML('beforeend', templates.followUp(options, { parentQuestionId: workflow.questionId }));
110
+ elements.followUpsSection.insertAdjacentHTML('beforeend', templates.followUp({ ...options, parentQuestionId: workflow.questionId }));
113
111
  });
114
112
 
115
113
  // when a new query starts, associate the last section container (for related resources) to that workflow
@@ -125,20 +123,8 @@ export default class AskCombo extends Combo {
125
123
  context.reset({ root: false });
126
124
  });
127
125
 
128
- // wait for miso-query content to be populated
129
- const QUERY = fields.view(ROLE.QUERY);
130
- if (!rootWorkflow.states[QUERY]) {
131
- await rootWorkflow._hub.once(QUERY);
132
- }
133
-
134
126
  // start query if specified in URL
135
- const { q } = options;
136
- if (q) {
137
- elements.rootInput.value = q;
138
- rootWorkflow.query({ q });
139
- } else {
140
- elements.rootInput.focus();
141
- }
127
+ rootWorkflow.autoQuery();
142
128
  }
143
129
 
144
130
  }
@@ -1,6 +1,5 @@
1
1
  import { trimObj } from '@miso.ai/commons';
2
- import * as templates from './templates.js';
3
- import * as phrases from './phrases.js';
2
+ import { templates } from '../../defaults/ask/index.js';
4
3
 
5
4
  // TODO: generalize
6
5
 
@@ -8,7 +7,6 @@ const { currentScript } = document;
8
7
 
9
8
  const DEFAULT_OPTIONS = Object.freeze({
10
9
  templates,
11
- phrases,
12
10
  autostart: true,
13
11
  });
14
12
 
@@ -48,7 +46,7 @@ function normalizeOptions({ api_key: apiKey, api_host: apiHost, templates, phras
48
46
  apiKey,
49
47
  apiHost,
50
48
  templates: templateAsFunction(templates),
51
- phrases: templateAsFunction(phrases),
49
+ phrases,
52
50
  ...options,
53
51
  });
54
52
  }
@@ -0,0 +1 @@
1
+ export const CLASS_PREFIX = 'miso-ask-combo';
@@ -0,0 +1,7 @@
1
+ import * as _constants from './constants.js';
2
+ import * as _phrases from './phrases.js';
3
+ import * as _templates from './templates.js';
4
+
5
+ export const constants = Object.freeze(_constants);
6
+ export const phrases = Object.freeze(_phrases);
7
+ export const templates = Object.freeze(_templates);
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The phrase displayed right before <miso-question>
3
+ */
4
+ export const question = 'You asked...';
5
+
6
+ /**
7
+ * The phrase displayed right before <miso-sources>
8
+ */
9
+ export const sources = 'My reply is based on the following';
10
+
11
+ /**
12
+ * The phrase displayed right before <miso-query-suggestions>
13
+ */
14
+ export const relatedQuestions = 'Related questions you can explore';
15
+
16
+ /**
17
+ * The phrase displayed right before <miso-related-resources>
18
+ */
19
+ export const relatedResources = 'Go beyond, and learn more about this topic';
@@ -0,0 +1,107 @@
1
+ import { CLASS_PREFIX } from './constants.js';
2
+ import * as DEFAULT_PHRASES from './phrases.js';
3
+
4
+ // TODO: refactor
5
+ // TODO: make ids constants
6
+ // TODO: placeholder
7
+
8
+ export function root(options = {}) {
9
+ const { classPrefix = CLASS_PREFIX } = options;
10
+ return `
11
+ <section id="${classPrefix}__question" class="${classPrefix}__section ${classPrefix}__question">
12
+ <miso-ask class="${classPrefix}__query-container">
13
+ <miso-query></miso-query>
14
+ </miso-ask>
15
+ </section>
16
+ <section class="${classPrefix}__section ${classPrefix}__answer">
17
+ ${answer(options)}
18
+ ${sources(options)}
19
+ <miso-ask class="${classPrefix}__bottom-spacing-container" visible-when="ongoing"></miso-ask>
20
+ </section>
21
+ <div id="${classPrefix}__follow-ups" class="${classPrefix}__follow-ups"></div>
22
+ <section id="${classPrefix}__related-resources" class="${classPrefix}__section ${classPrefix}__related-resources">
23
+ <miso-ask visible-when="nonempty" logo="true">
24
+ <h2 class="${classPrefix}__phrase ${classPrefix}__related-resources-phrase">${phraseText(options, 'relatedResources')}</h2>
25
+ <miso-related-resources></miso-related-resources>
26
+ </miso-ask>
27
+ </section>`.trim();
28
+ };
29
+
30
+ export function followUp(options = {}) {
31
+ const { classPrefix = CLASS_PREFIX, parentQuestionId } = options;
32
+ return `
33
+ <section class="${classPrefix}__section ${classPrefix}__follow-up">
34
+ <miso-ask class="${classPrefix}__query-suggestions-container" visible-when="initial+nonempty" parent-question-id="${parentQuestionId}">
35
+ <h3 class="${classPrefix}__phrase ${classPrefix}__related-questions-phrase">${phraseText(options, 'relatedQuestions')}</h3>
36
+ <miso-query-suggestions></miso-query-suggestions>
37
+ </miso-ask>
38
+ <miso-ask class="${classPrefix}__query-container" visible-when="initial loading" parent-question-id="${parentQuestionId}">
39
+ <miso-query></miso-query>
40
+ </miso-ask>
41
+ ${answer(options)}
42
+ ${sources(options)}
43
+ <miso-ask class="${classPrefix}__bottom-spacing-container" visible-when="ongoing" parent-question-id="${parentQuestionId}"></miso-ask>
44
+ </section>`.trim();
45
+ };
46
+
47
+
48
+
49
+ // helpers //
50
+ function answer(options) {
51
+ const { classPrefix = CLASS_PREFIX } = options;
52
+ return `
53
+ ${containerOpenTag('answer', { ...options, visibleWhen: 'ready' })}
54
+ ${ options.parentQuestionId ? '<hr>' : '' }
55
+ <div class="${classPrefix}__phrase ${classPrefix}__question-phrase">${phraseText(options, 'question')}</div>
56
+ <miso-question></miso-question>
57
+ <miso-answer></miso-answer>
58
+ <miso-feedback></miso-feedback>
59
+ </miso-ask>`.trim();
60
+ };
61
+
62
+ function sources(options) {
63
+ const { classPrefix = CLASS_PREFIX } = options;
64
+ return `
65
+ ${containerOpenTag('sources', { ...options, visibleWhen: 'nonempty' })}
66
+ <hr>
67
+ <h3 class="${classPrefix}__phrase ${classPrefix}__sources-phrase">${phraseText(options, 'sources')}</h3>
68
+ <miso-sources></miso-sources>
69
+ </miso-ask>`.trim();
70
+ };
71
+
72
+ function phraseText(options, key) {
73
+ const { phrases = {} } = options;
74
+ const fn = phrases[key] || DEFAULT_PHRASES[key];
75
+ switch (typeof fn) {
76
+ case 'function':
77
+ return fn(options);
78
+ case 'string':
79
+ return fn;
80
+ default:
81
+ return '';
82
+ }
83
+ }
84
+
85
+ function containerOpenTag(name, {
86
+ visibleWhen,
87
+ classPrefix = CLASS_PREFIX,
88
+ logo = false,
89
+ circledCitationIndex = true,
90
+ parentQuestionId,
91
+ }) {
92
+ let className = `${classPrefix}__${name}-container`;
93
+ if (circledCitationIndex) {
94
+ className += ` miso-circled-citation-index`;
95
+ }
96
+ const attributes = [
97
+ ` class="${className}"`,
98
+ ` logo="${logo ? 'true' : 'false'}"`,
99
+ ];
100
+ if (visibleWhen) {
101
+ attributes.push(` visible-when="${visibleWhen}"`);
102
+ }
103
+ if (parentQuestionId) {
104
+ attributes.push(` parent-question-id="${parentQuestionId}"`);
105
+ }
106
+ return `<miso-ask${attributes.join('')}>`;
107
+ }
@@ -0,0 +1,3 @@
1
+ import * as _ask from './ask/index.js';
2
+
3
+ export const ask = Object.freeze(_ask);
@@ -91,6 +91,23 @@ export default class SearchBoxLayout extends TemplateBasedLayout {
91
91
  }
92
92
  }
93
93
 
94
+ focus() {
95
+ if (this._element) {
96
+ this._context().focus();
97
+ } else {
98
+ // take a rain check, wait for render
99
+ this._focusRequested = true;
100
+ }
101
+ }
102
+
103
+ set value(value) {
104
+ if (this._element) {
105
+ this._context().value = value;
106
+ } else {
107
+ this._valueRequested = value;
108
+ }
109
+ }
110
+
94
111
  _preprocess({ state }) {
95
112
  state = super._preprocess({ state });
96
113
  const { autocomplete } = this.options;
@@ -108,6 +125,8 @@ export default class SearchBoxLayout extends TemplateBasedLayout {
108
125
  }
109
126
  this._setupAutocomplete(element);
110
127
  this._renderSuggestions(element, data, controls);
128
+ this._fullfillFocusRequest(element);
129
+ this._fullfillValueRequest(element);
111
130
  }
112
131
 
113
132
  _setupAutocomplete(element) {
@@ -142,6 +161,22 @@ export default class SearchBoxLayout extends TemplateBasedLayout {
142
161
  }
143
162
  }
144
163
 
164
+ _fullfillFocusRequest(element) {
165
+ if (!element || !this._focusRequested) {
166
+ return;
167
+ }
168
+ this._focusRequested = false;
169
+ this._context(element).focus();
170
+ }
171
+
172
+ _fullfillValueRequest(element) {
173
+ if (!element || !this._valueRequested) {
174
+ return;
175
+ }
176
+ this._context(element).value = this._valueRequested;
177
+ this._valueRequested = undefined;
178
+ }
179
+
145
180
  _context(element) {
146
181
  element = element || this._view.element;
147
182
  if (!element) {
@@ -240,6 +275,22 @@ class Context {
240
275
  }
241
276
  }
242
277
 
278
+ focus() {
279
+ if (!this._element) {
280
+ return;
281
+ }
282
+ const { inputElement } = this;
283
+ inputElement && inputElement.focus();
284
+ }
285
+
286
+ set value(value) {
287
+ if (!this._element) {
288
+ return;
289
+ }
290
+ const { inputElement } = this;
291
+ inputElement && (inputElement.value = value);
292
+ }
293
+
243
294
  _get(role) {
244
295
  return !this._element ? undefined : this._cache[role] || (this._cache[role] = this._element.querySelector(`[data-role="${role}"]`));
245
296
  }
package/src/plugin.js CHANGED
@@ -1,10 +1,11 @@
1
- import { Component, defineAndUpgrade, delegateGetters, defineValues } from '@miso.ai/commons';
1
+ import { Component, Resolution, defineAndUpgrade, delegateGetters, defineValues } from '@miso.ai/commons';
2
2
  import { Asks, Explore, Search, Recommendations } from './workflow/index.js';
3
3
  import { AskCombo } from './combo/index.js';
4
4
  import Layouts from './layouts.js';
5
5
  import * as elements from './element/index.js';
6
6
  import * as layouts from './layout/index.js';
7
7
  import * as sources from './source/index.js';
8
+ import * as defaults from './defaults/index.js';
8
9
  import { loadStylesIfNecessary } from './styles.js';
9
10
 
10
11
  import MisoContainerElement from './element/container/miso-container.js';
@@ -24,14 +25,15 @@ export default class UiPlugin extends Component {
24
25
  this._recommendations = new WeakMap();
25
26
  this._asks = new WeakMap();
26
27
  this._extensions = new WeakMap();
28
+ this._ready = new Resolution();
27
29
  }
28
30
 
29
31
  async install(MisoClient, context) {
30
32
  context.addSubtree(this);
31
33
  MisoClient.on('create', this._injectClient.bind(this));
32
34
 
33
- const ui = {};
34
- delegateGetters(ui, this, ['layouts', 'combo']);
35
+ const ui = { defaults };
36
+ delegateGetters(ui, this, ['layouts', 'combo', 'ready']);
35
37
  defineValues(this, { MisoClient });
36
38
  defineValues(MisoClient, { ui });
37
39
 
@@ -69,6 +71,8 @@ export default class UiPlugin extends Component {
69
71
  for (const ElementClass of ElementClasses) {
70
72
  defineAndUpgrade(ElementClass);
71
73
  }
74
+
75
+ this._ready.resolve();
72
76
  }
73
77
 
74
78
  async requireExtension(name) {
@@ -80,6 +84,13 @@ export default class UiPlugin extends Component {
80
84
  }
81
85
  }
82
86
 
87
+ get ready() {
88
+ return Promise.all([
89
+ this._ready.promise,
90
+ MisoClient.any(), // TODO: we need to wait for element connection
91
+ ]).then(() => {});
92
+ }
93
+
83
94
  _injectClient(client) {
84
95
  defineValues(client, {
85
96
  ui: new Ui(this, client),
@@ -169,11 +180,9 @@ class Ui {
169
180
  return this._explore || (this._explore = new Explore(this._plugin, this._client));
170
181
  }
171
182
 
172
- /*
173
- async whenStylesLoaded() {
174
- // TODO
183
+ get ready() {
184
+ return this._plugin._ready.promise;
175
185
  }
176
- */
177
186
 
178
187
  }
179
188
 
package/src/styles.js CHANGED
@@ -12,17 +12,13 @@ export async function loadStylesIfNecessary() {
12
12
  export async function loadStyles() {
13
13
  try {
14
14
  let link = getExistedLinkElement();
15
- if (link) {
16
- return waitForLinkLoaded(link)
17
- }
18
- link = document.createElement('link');
19
- link.rel = 'stylesheet';
20
- link.href = getCssUrl();
21
- return new Promise((resolve, reject) => {
22
- link.onload = resolve;
23
- link.onerror = reject;
15
+ if (!link) {
16
+ link = document.createElement('link');
17
+ link.rel = 'stylesheet';
18
+ link.href = getCssUrl();
24
19
  document.head.appendChild(link);
25
- });
20
+ }
21
+ return waitForStylesApplied(link);
26
22
  } catch(e) {
27
23
  console.error(e);
28
24
  }
@@ -50,25 +46,52 @@ function getExistedLinkElement() {
50
46
  return document.head.querySelector(`link[href="${getCssUrl()}"]`);
51
47
  }
52
48
 
53
- async function waitForLinkLoaded(element) {
49
+ async function waitForStylesApplied(element) {
50
+ await waitForSheetAvailable(element);
51
+ await waitForSheetIncluded(element);
52
+ }
53
+
54
+ async function waitForSheetAvailable(element) {
54
55
  if (element.sheet) {
55
56
  return;
56
57
  }
57
58
  return new Promise((resolve, reject) => {
58
59
  let intervalId;
59
- element.onload = () => {
60
- intervalId && clearInterval(intervalId);
61
- resolve();
62
- };
63
60
  element.onerror = () => {
64
61
  intervalId && clearInterval(intervalId);
65
62
  reject();
66
63
  };
67
64
  intervalId = setInterval(() => {
68
- if (element.sheet) {
69
- intervalId && clearInterval(intervalId);
70
- resolve();
65
+ if (!element.sheet) {
66
+ return;
71
67
  }
72
- }, 100);
68
+ intervalId && clearInterval(intervalId);
69
+ resolve();
70
+ }, 100);
73
71
  });
74
72
  }
73
+
74
+ async function waitForSheetIncluded(element) {
75
+ if (isSheetIncluded(element)) {
76
+ return;
77
+ }
78
+ return new Promise((resolve) => {
79
+ let intervalId;
80
+ intervalId = setInterval(() => {
81
+ if (!isSheetIncluded(element)) {
82
+ return;
83
+ }
84
+ intervalId && clearInterval(intervalId);
85
+ resolve();
86
+ }, 100);
87
+ });
88
+ }
89
+
90
+ function isSheetIncluded(element) {
91
+ for (const sheet of document.styleSheets) {
92
+ if (sheet.ownerNode === element) {
93
+ return true;
94
+ }
95
+ }
96
+ return false;
97
+ }
package/src/version.js CHANGED
@@ -1 +1 @@
1
- export default '1.9.0';
1
+ export default '1.9.1-beta.0';
@@ -108,6 +108,22 @@ export default class Ask extends Workflow {
108
108
  }
109
109
 
110
110
  // lifecycle //
111
+ autoQuery({ setValue = true, focus = true } = {}) {
112
+ const q = new URLSearchParams(window.location.search).get('q');
113
+ const { layout } = this._views.get(ROLE.QUERY);
114
+ if (layout) {
115
+ if (q && setValue) {
116
+ layout.value = q;
117
+ }
118
+ if (!q && focus) {
119
+ layout.focus();
120
+ }
121
+ }
122
+ if (q) {
123
+ this.query({ q });
124
+ }
125
+ }
126
+
111
127
  query({ q: question, ...payload } = {}) {
112
128
  payload = { ...payload, question };
113
129
  if (this.parentQuestionId) {
@@ -73,6 +73,10 @@ export default class Workflow extends Component {
73
73
  return this._hub.states;
74
74
  }
75
75
 
76
+ get views() {
77
+ return this._views.interface;
78
+ }
79
+
76
80
  // lifecycle //
77
81
  reset() {
78
82
  this._sessions.new();
@@ -43,6 +43,22 @@ export default class Search extends Workflow {
43
43
  }
44
44
 
45
45
  // lifecycle //
46
+ autoQuery({ setValue = true, focus = true } = {}) {
47
+ const q = new URLSearchParams(window.location.search).get('q');
48
+ const { layout } = this._views.get(ROLE.QUERY);
49
+ if (layout) {
50
+ if (q && setValue) {
51
+ layout.value = q;
52
+ }
53
+ if (!q && focus) {
54
+ layout.focus();
55
+ }
56
+ }
57
+ if (q) {
58
+ this.query({ q });
59
+ }
60
+ }
61
+
46
62
  query(payload) {
47
63
  this.restart();
48
64
  const { session } = this;
@@ -1,87 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.sources = exports.root = exports.followUp = exports.answer = void 0;
7
- var _constants = require("./constants.js");
8
- // TODO: make ids constants
9
- // TODO: placeholder
10
-
11
- const root = options => `
12
- <section id="${_constants.PREFIX}__question" class="${_constants.PREFIX}__section ${_constants.PREFIX}__question">
13
- <miso-ask class="${_constants.PREFIX}__query-container">
14
- <miso-query></miso-query>
15
- </miso-ask>
16
- </section>
17
- <section class="${_constants.PREFIX}__section ${_constants.PREFIX}__answer">
18
- ${options.templates.answer(options)}
19
- ${options.templates.sources(options)}
20
- <miso-ask class="${_constants.PREFIX}__bottom-spacing-container" visible-when="ongoing"></miso-ask>
21
- </section>
22
- <div id="${_constants.PREFIX}__follow-ups" class="${_constants.PREFIX}__follow-ups"></div>
23
- <section id="${_constants.PREFIX}__related-resources" class="${_constants.PREFIX}__section ${_constants.PREFIX}__related-resources">
24
- <miso-ask visible-when="nonempty" logo="true">
25
- <h2 class="${_constants.PREFIX}__phrase ${_constants.PREFIX}__related-resources-phrase">${options.phrases.relatedResources(options)}</h2>
26
- <miso-related-resources></miso-related-resources>
27
- </miso-ask>
28
- </section>
29
- `.trim();
30
- exports.root = root;
31
- const followUp = function (options) {
32
- let session = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
33
- const {
34
- parentQuestionId
35
- } = session;
36
- return `
37
- <section class="${_constants.PREFIX}__section ${_constants.PREFIX}__follow-up">
38
- <miso-ask class="${_constants.PREFIX}__query-suggestions-container" visible-when="initial+nonempty" parent-question-id="${parentQuestionId}">
39
- <h3 class="${_constants.PREFIX}__phrase ${_constants.PREFIX}__related-questions-phrase">${options.phrases.relatedQuestions(options, session)}</h3>
40
- <miso-query-suggestions></miso-query-suggestions>
41
- </miso-ask>
42
- <miso-ask class="${_constants.PREFIX}__query-container" visible-when="initial loading" parent-question-id="${parentQuestionId}">
43
- <miso-query></miso-query>
44
- </miso-ask>
45
- ${options.templates.answer(options, session)}
46
- ${options.templates.sources(options, session)}
47
- <miso-ask class="${_constants.PREFIX}__bottom-spacing-container" visible-when="ongoing" parent-question-id="${parentQuestionId}"></miso-ask>
48
- </section>
49
- `.trim();
50
- };
51
- exports.followUp = followUp;
52
- const answer = function (options) {
53
- let session = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
54
- // TODO: include/omit miso-circled-citation-index by options
55
- const {
56
- parentQuestionId
57
- } = session;
58
- const openTag = `<miso-ask class="${_constants.PREFIX}__answer-container miso-circled-citation-index" visible-when="ready" logo="false"${parentQuestionId ? ` parent-question-id="${parentQuestionId}"` : ''}>`;
59
- const closeTag = '</miso-ask>';
60
- return `
61
- ${openTag}
62
- ${parentQuestionId ? '<hr>' : ''}
63
- <div class="${_constants.PREFIX}__phrase ${_constants.PREFIX}__question-phrase">${options.phrases.question(options, session)}</div>
64
- <miso-question></miso-question>
65
- <miso-answer></miso-answer>
66
- <miso-feedback></miso-feedback>
67
- ${closeTag}
68
- `.trim();
69
- };
70
- exports.answer = answer;
71
- const sources = function (options) {
72
- let session = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
73
- // TODO: include/omit miso-circled-citation-index by options
74
- const {
75
- parentQuestionId
76
- } = session;
77
- const openTag = `<miso-ask class="${_constants.PREFIX}__sources-container miso-circled-citation-index" visible-when="nonempty" logo="false"${parentQuestionId ? ` parent-question-id="${parentQuestionId}"` : ''}>`;
78
- const closeTag = '</miso-ask>';
79
- return `
80
- ${openTag}
81
- <hr>
82
- <h3 class="${_constants.PREFIX}__phrase ${_constants.PREFIX}__sources-phrase">${options.phrases.sources(options, session)}</h3>
83
- <miso-sources></miso-sources>
84
- ${closeTag}
85
- `.trim();
86
- };
87
- exports.sources = sources;
@@ -1,7 +0,0 @@
1
- export const question = 'You asked...';
2
-
3
- export const sources = 'My reply is based on the following';
4
-
5
- export const relatedQuestions = 'Related questions you can explore';
6
-
7
- export const relatedResources = 'Go beyond, and learn more about this topic';
@@ -1,72 +0,0 @@
1
- import { PREFIX } from './constants.js';
2
-
3
- // TODO: make ids constants
4
- // TODO: placeholder
5
-
6
- export const root = (options) => `
7
- <section id="${PREFIX}__question" class="${PREFIX}__section ${PREFIX}__question">
8
- <miso-ask class="${PREFIX}__query-container">
9
- <miso-query></miso-query>
10
- </miso-ask>
11
- </section>
12
- <section class="${PREFIX}__section ${PREFIX}__answer">
13
- ${options.templates.answer(options)}
14
- ${options.templates.sources(options)}
15
- <miso-ask class="${PREFIX}__bottom-spacing-container" visible-when="ongoing"></miso-ask>
16
- </section>
17
- <div id="${PREFIX}__follow-ups" class="${PREFIX}__follow-ups"></div>
18
- <section id="${PREFIX}__related-resources" class="${PREFIX}__section ${PREFIX}__related-resources">
19
- <miso-ask visible-when="nonempty" logo="true">
20
- <h2 class="${PREFIX}__phrase ${PREFIX}__related-resources-phrase">${options.phrases.relatedResources(options)}</h2>
21
- <miso-related-resources></miso-related-resources>
22
- </miso-ask>
23
- </section>
24
- `.trim();
25
-
26
- export const followUp = (options, session = {}) => {
27
- const { parentQuestionId } = session;
28
- return `
29
- <section class="${PREFIX}__section ${PREFIX}__follow-up">
30
- <miso-ask class="${PREFIX}__query-suggestions-container" visible-when="initial+nonempty" parent-question-id="${parentQuestionId}">
31
- <h3 class="${PREFIX}__phrase ${PREFIX}__related-questions-phrase">${options.phrases.relatedQuestions(options, session)}</h3>
32
- <miso-query-suggestions></miso-query-suggestions>
33
- </miso-ask>
34
- <miso-ask class="${PREFIX}__query-container" visible-when="initial loading" parent-question-id="${parentQuestionId}">
35
- <miso-query></miso-query>
36
- </miso-ask>
37
- ${options.templates.answer(options, session)}
38
- ${options.templates.sources(options, session)}
39
- <miso-ask class="${PREFIX}__bottom-spacing-container" visible-when="ongoing" parent-question-id="${parentQuestionId}"></miso-ask>
40
- </section>
41
- `.trim();
42
- };
43
-
44
- export const answer = (options, session = {}) => {
45
- // TODO: include/omit miso-circled-citation-index by options
46
- const { parentQuestionId } = session;
47
- const openTag = `<miso-ask class="${PREFIX}__answer-container miso-circled-citation-index" visible-when="ready" logo="false"${parentQuestionId ? ` parent-question-id="${parentQuestionId}"` : ''}>`;
48
- const closeTag = '</miso-ask>';
49
- return `
50
- ${openTag}
51
- ${ parentQuestionId ? '<hr>' : '' }
52
- <div class="${PREFIX}__phrase ${PREFIX}__question-phrase">${options.phrases.question(options, session)}</div>
53
- <miso-question></miso-question>
54
- <miso-answer></miso-answer>
55
- <miso-feedback></miso-feedback>
56
- ${closeTag}
57
- `.trim();
58
- };
59
-
60
- export const sources = (options, session = {}) => {
61
- // TODO: include/omit miso-circled-citation-index by options
62
- const { parentQuestionId } = session;
63
- const openTag = `<miso-ask class="${PREFIX}__sources-container miso-circled-citation-index" visible-when="nonempty" logo="false"${parentQuestionId ? ` parent-question-id="${parentQuestionId}"` : ''}>`;
64
- const closeTag = '</miso-ask>';
65
- return `
66
- ${openTag}
67
- <hr>
68
- <h3 class="${PREFIX}__phrase ${PREFIX}__sources-phrase">${options.phrases.sources(options, session)}</h3>
69
- <miso-sources></miso-sources>
70
- ${closeTag}
71
- `.trim();
72
- };