@miso.ai/client-sdk-ui 1.9.0-beta.8 → 1.9.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.
@@ -18,6 +18,7 @@ class AskCombo extends _base.default {
18
18
  plugin,
19
19
  MisoClient
20
20
  });
21
+ // TODO: extract options to super class
21
22
  this._options = new _options.default();
22
23
  this._localOptions = {};
23
24
  }
@@ -41,6 +42,9 @@ class AskCombo extends _base.default {
41
42
  get elements() {
42
43
  return this._elements;
43
44
  }
45
+ autoStart() {
46
+ this.resolvedOptions.autostart && this.start();
47
+ }
44
48
  async _start() {
45
49
  await (0, _commons.waitForDomContentLoaded)();
46
50
  await this.MisoClient.cmdDone;
@@ -111,6 +115,8 @@ class AskCombo extends _base.default {
111
115
  const context = client.ui.asks;
112
116
  const rootWorkflow = client.ui.ask;
113
117
 
118
+ // TODO: set placeholder is present in options
119
+
114
120
  // when a answer is fully populated, insert a new section for the follow-up question
115
121
  context.on('done', _ref => {
116
122
  let {
@@ -6,7 +6,8 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.default = void 0;
7
7
  var _commons = require("@miso.ai/commons");
8
8
  var templates = _interopRequireWildcard(require("./templates.js"));
9
- const _excluded = ["api_key", "api_host"];
9
+ var phrases = _interopRequireWildcard(require("./phrases.js"));
10
+ const _excluded = ["api_key", "api_host", "templates", "phrases"];
10
11
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
11
12
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
12
13
  function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
@@ -16,7 +17,9 @@ const {
16
17
  currentScript
17
18
  } = document;
18
19
  const DEFAULT_OPTIONS = Object.freeze({
19
- templates
20
+ templates,
21
+ phrases,
22
+ autostart: true
20
23
  });
21
24
  class AskComboOptions {
22
25
  constructor() {
@@ -50,12 +53,16 @@ function normalizeOptions() {
50
53
  let _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
51
54
  let {
52
55
  api_key: apiKey,
53
- api_host: apiHost
56
+ api_host: apiHost,
57
+ templates,
58
+ phrases
54
59
  } = _ref,
55
60
  options = _objectWithoutPropertiesLoose(_ref, _excluded);
56
61
  return (0, _commons.trimObj)(Object.assign({
57
62
  apiKey,
58
- apiHost
63
+ apiHost,
64
+ templates: templateAsFunction(templates),
65
+ phrases: templateAsFunction(phrases)
59
66
  }, options));
60
67
  }
61
68
 
@@ -74,7 +81,7 @@ function readFromScriptSrc() {
74
81
  if (key === 'q') {
75
82
  continue;
76
83
  }
77
- params[key] = value === '' ? true : value;
84
+ params[key] = coerceValue(value);
78
85
  }
79
86
  return params;
80
87
  }
@@ -88,10 +95,36 @@ function readFromPageUrl() {
88
95
  const params = {};
89
96
  for (const [key, value] of new URLSearchParams(window.location.search)) {
90
97
  if (key.startsWith('miso_') && key.length > 5 && key !== 'miso_api_key') {
91
- params[key.substring(5)] = value === '' ? true : value;
98
+ params[key.substring(5)] = coerceValue(value);
92
99
  } else if (key === 'q') {
93
100
  params.q = value;
94
101
  }
95
102
  }
96
103
  return params;
104
+ }
105
+ function coerceValue(value) {
106
+ return value === '' ? true : value === 'false' ? false : value;
107
+ }
108
+ function templateAsFunction(value) {
109
+ if (value === undefined || value === null) {
110
+ return value;
111
+ }
112
+ switch (typeof value) {
113
+ case 'function':
114
+ return value;
115
+ case 'string':
116
+ case 'number':
117
+ return () => value;
118
+ case 'object':
119
+ return Array.isArray(value) ? value.map(templateAsFunction) : mappingObjectValues(value, templateAsFunction);
120
+ default:
121
+ throw new Error(`Unsupported template type: ${value}`);
122
+ }
123
+ }
124
+ function mappingObjectValues(obj, fn) {
125
+ const mapped = {};
126
+ for (const [key, value] of Object.entries(obj)) {
127
+ mapped[key] = fn(value);
128
+ }
129
+ return mapped;
97
130
  }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.sources = exports.relatedResources = exports.relatedQuestions = exports.question = void 0;
7
+ const question = exports.question = 'You asked...';
8
+ const sources = exports.sources = 'My reply is based on the following';
9
+ const relatedQuestions = exports.relatedQuestions = 'Related questions you can explore';
10
+ const relatedResources = exports.relatedResources = 'Go beyond, and learn more about this topic';
@@ -17,50 +17,50 @@ const root = options => `
17
17
  <section class="${_constants.PREFIX}__section ${_constants.PREFIX}__answer">
18
18
  ${options.templates.answer(options)}
19
19
  ${options.templates.sources(options)}
20
+ <miso-ask class="${_constants.PREFIX}__bottom-spacing-container" visible-when="ongoing"></miso-ask>
20
21
  </section>
21
22
  <div id="${_constants.PREFIX}__follow-ups" class="${_constants.PREFIX}__follow-ups"></div>
22
23
  <section id="${_constants.PREFIX}__related-resources" class="${_constants.PREFIX}__section ${_constants.PREFIX}__related-resources">
23
24
  <miso-ask visible-when="nonempty" logo="true">
24
- <h2 class="${_constants.PREFIX}__phrase ${_constants.PREFIX}__related-resources-phrase"></h2>
25
+ <h2 class="${_constants.PREFIX}__phrase ${_constants.PREFIX}__related-resources-phrase">${options.phrases.relatedResources(options)}</h2>
25
26
  <miso-related-resources></miso-related-resources>
26
27
  </miso-ask>
27
28
  </section>
28
29
  `.trim();
29
30
  exports.root = root;
30
- const followUp = (options, _ref) => {
31
- let {
31
+ const followUp = function (options) {
32
+ let session = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
33
+ const {
32
34
  parentQuestionId
33
- } = _ref;
35
+ } = session;
34
36
  return `
35
37
  <section class="${_constants.PREFIX}__section ${_constants.PREFIX}__follow-up">
36
- <miso-ask class="${_constants.PREFIX}__query-suggestions-container" visible-when="initial" parent-question-id="${parentQuestionId}">
37
- <h3 class="${_constants.PREFIX}__phrase ${_constants.PREFIX}__related-questions-phrase"></h3>
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>
38
40
  <miso-query-suggestions></miso-query-suggestions>
39
41
  </miso-ask>
40
42
  <miso-ask class="${_constants.PREFIX}__query-container" visible-when="initial loading" parent-question-id="${parentQuestionId}">
41
43
  <miso-query></miso-query>
42
44
  </miso-ask>
43
- ${options.templates.answer(options, {
44
- parentQuestionId
45
- })}
46
- ${options.templates.sources(options, {
47
- parentQuestionId
48
- })}
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>
49
48
  </section>
50
49
  `.trim();
51
50
  };
52
51
  exports.followUp = followUp;
53
52
  const answer = function (options) {
54
- let {
55
- parentQuestionId
56
- } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
53
+ let session = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
57
54
  // TODO: include/omit miso-circled-citation-index by options
55
+ const {
56
+ parentQuestionId
57
+ } = session;
58
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
59
  const closeTag = '</miso-ask>';
60
60
  return `
61
61
  ${openTag}
62
62
  ${parentQuestionId ? '<hr>' : ''}
63
- <div class="${_constants.PREFIX}__phrase ${_constants.PREFIX}__question-phrase"></div>
63
+ <div class="${_constants.PREFIX}__phrase ${_constants.PREFIX}__question-phrase">${options.phrases.question(options, session)}</div>
64
64
  <miso-question></miso-question>
65
65
  <miso-answer></miso-answer>
66
66
  <miso-feedback></miso-feedback>
@@ -69,16 +69,17 @@ ${closeTag}
69
69
  };
70
70
  exports.answer = answer;
71
71
  const sources = function (options) {
72
- let {
73
- parentQuestionId
74
- } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
72
+ let session = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
75
73
  // TODO: include/omit miso-circled-citation-index by options
74
+ const {
75
+ parentQuestionId
76
+ } = session;
76
77
  const openTag = `<miso-ask class="${_constants.PREFIX}__sources-container miso-circled-citation-index" visible-when="nonempty" logo="false"${parentQuestionId ? ` parent-question-id="${parentQuestionId}"` : ''}>`;
77
78
  const closeTag = '</miso-ask>';
78
79
  return `
79
80
  ${openTag}
80
81
  <hr>
81
- <h3 class="${_constants.PREFIX}__phrase ${_constants.PREFIX}__sources-phrase"></h3>
82
+ <h3 class="${_constants.PREFIX}__phrase ${_constants.PREFIX}__sources-phrase">${options.phrases.sources(options, session)}</h3>
82
83
  <miso-sources></miso-sources>
83
84
  ${closeTag}
84
85
  `.trim();
@@ -30,11 +30,14 @@ class Combo extends _commons.Component {
30
30
  set element(element) {
31
31
  this._element = element;
32
32
  }
33
- start() {
33
+ start(options) {
34
34
  if (this._started) {
35
35
  return;
36
36
  }
37
37
  this._started = true;
38
+ if (options) {
39
+ this.config(options);
40
+ }
38
41
  this._start();
39
42
  }
40
43
  _start() {
@@ -28,7 +28,7 @@ class MisoComboElement extends HTMLElement {
28
28
  }
29
29
  this._combo = combo;
30
30
  combo.element = this;
31
- combo.start();
31
+ combo.autoStart();
32
32
  }
33
33
  }
34
34
  exports.default = MisoComboElement;
@@ -11,6 +11,7 @@ var _layouts = _interopRequireDefault(require("./layouts.js"));
11
11
  var elements = _interopRequireWildcard(require("./element/index.js"));
12
12
  var layouts = _interopRequireWildcard(require("./layout/index.js"));
13
13
  var sources = _interopRequireWildcard(require("./source/index.js"));
14
+ var _styles = require("./styles.js");
14
15
  var _misoContainer = _interopRequireDefault(require("./element/container/miso-container.js"));
15
16
  var _misoCombo = _interopRequireDefault(require("./element/combo/miso-combo.js"));
16
17
  const _excluded = ["containers", "roles", "combos"];
@@ -24,18 +25,13 @@ class UiPlugin extends _commons.Component {
24
25
  return PLUGIN_ID;
25
26
  }
26
27
  constructor() {
27
- let {
28
- loadStyles = true
29
- } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
30
28
  super('ui');
31
29
  this.layouts = new _layouts.default(this);
32
30
  this._recommendations = new WeakMap();
33
31
  this._asks = new WeakMap();
34
32
  this._extensions = new WeakMap();
35
- // TODO: load CSS
36
33
  }
37
-
38
- install(MisoClient, context) {
34
+ async install(MisoClient, context) {
39
35
  context.addSubtree(this);
40
36
  MisoClient.on('create', this._injectClient.bind(this));
41
37
  const ui = {};
@@ -75,6 +71,10 @@ class UiPlugin extends _commons.Component {
75
71
  ElementClass.MisoClient = MisoClient; // TODO: find better way
76
72
  }
77
73
 
74
+ // load styles
75
+ await (0, _styles.loadStylesIfNecessary)();
76
+
77
+ // define custom elements
78
78
  for (const ElementClass of ElementClasses) {
79
79
  (0, _commons.defineAndUpgrade)(ElementClass);
80
80
  }
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.loadStyles = loadStyles;
7
+ exports.loadStylesIfNecessary = loadStylesIfNecessary;
8
+ var _version = _interopRequireDefault(require("./version.js"));
9
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
+ const {
11
+ currentScript
12
+ } = document;
13
+ let cssUrl;
14
+ let stylesLoaded;
15
+ async function loadStylesIfNecessary() {
16
+ return stylesLoaded || (stylesLoaded = loadStyles());
17
+ }
18
+ async function loadStyles() {
19
+ try {
20
+ let link = getExistedLinkElement();
21
+ if (link) {
22
+ return waitForLinkLoaded(link);
23
+ }
24
+ link = document.createElement('link');
25
+ link.rel = 'stylesheet';
26
+ link.href = getCssUrl();
27
+ return new Promise((resolve, reject) => {
28
+ link.onload = resolve;
29
+ link.onerror = reject;
30
+ document.head.appendChild(link);
31
+ });
32
+ } catch (e) {
33
+ console.error(e);
34
+ }
35
+ }
36
+
37
+ // helpers //
38
+ function getCssUrl() {
39
+ return cssUrl || (cssUrl = resolveCssUrl());
40
+ }
41
+ function resolveCssUrl() {
42
+ // TODO: refactor with getPluginScriptUrl() in core
43
+ if (_version.default === 'dev') {
44
+ const src = currentScript.src;
45
+ const searchIndex = src.indexOf('?');
46
+ const k = searchIndex < 0 ? src.length : searchIndex;
47
+ const i = src.lastIndexOf('/', k); // .../dist/umd/*.min.js
48
+ return `${src.slice(0, i - 4)}/css/ui.css`;
49
+ } else {
50
+ return `https://cdn.jsdelivr.net/npm/@miso.ai/client-sdk@${_version.default}/dist/css/ui.css`;
51
+ }
52
+ }
53
+ function getExistedLinkElement() {
54
+ return document.head.querySelector(`link[href="${getCssUrl()}"]`);
55
+ }
56
+ async function waitForLinkLoaded(element) {
57
+ if (element.sheet) {
58
+ return;
59
+ }
60
+ return new Promise((resolve, reject) => {
61
+ let intervalId;
62
+ element.onload = () => {
63
+ intervalId && clearInterval(intervalId);
64
+ resolve();
65
+ };
66
+ element.onerror = () => {
67
+ intervalId && clearInterval(intervalId);
68
+ reject();
69
+ };
70
+ intervalId = setInterval(() => {
71
+ if (element.sheet) {
72
+ intervalId && clearInterval(intervalId);
73
+ resolve();
74
+ }
75
+ }, 100);
76
+ });
77
+ }
@@ -4,4 +4,4 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _default = exports.default = '1.9.0-beta.8';
7
+ var _default = exports.default = '1.9.0';
package/package.json CHANGED
@@ -26,7 +26,7 @@
26
26
  "url": "https://github.com/MisoAI/miso-client-js-sdk/issues"
27
27
  },
28
28
  "dependencies": {
29
- "@miso.ai/commons": "1.9.0-beta.8"
29
+ "@miso.ai/commons": "1.9.0"
30
30
  },
31
- "version": "1.9.0-beta.8"
31
+ "version": "1.9.0"
32
32
  }
@@ -13,6 +13,7 @@ export default class AskCombo extends Combo {
13
13
  plugin,
14
14
  MisoClient,
15
15
  });
16
+ // TODO: extract options to super class
16
17
  this._options = new AskComboOptions();
17
18
  this._localOptions = {};
18
19
  }
@@ -40,6 +41,10 @@ export default class AskCombo extends Combo {
40
41
  return this._elements;
41
42
  }
42
43
 
44
+ autoStart() {
45
+ this.resolvedOptions.autostart && this.start();
46
+ }
47
+
43
48
  async _start() {
44
49
  await waitForDomContentLoaded();
45
50
  await this.MisoClient.cmdDone;
@@ -100,6 +105,8 @@ export default class AskCombo extends Combo {
100
105
  const context = client.ui.asks;
101
106
  const rootWorkflow = client.ui.ask;
102
107
 
108
+ // TODO: set placeholder is present in options
109
+
103
110
  // when a answer is fully populated, insert a new section for the follow-up question
104
111
  context.on('done', ({ workflow }) => {
105
112
  elements.followUpsSection.insertAdjacentHTML('beforeend', templates.followUp(options, { parentQuestionId: workflow.questionId }));
@@ -1,5 +1,6 @@
1
1
  import { trimObj } from '@miso.ai/commons';
2
2
  import * as templates from './templates.js';
3
+ import * as phrases from './phrases.js';
3
4
 
4
5
  // TODO: generalize
5
6
 
@@ -7,6 +8,8 @@ const { currentScript } = document;
7
8
 
8
9
  const DEFAULT_OPTIONS = Object.freeze({
9
10
  templates,
11
+ phrases,
12
+ autostart: true,
10
13
  });
11
14
 
12
15
  export default class AskComboOptions {
@@ -40,10 +43,12 @@ function mergeTwoOptions(merged, overrides) {
40
43
  });
41
44
  }
42
45
 
43
- function normalizeOptions({ api_key: apiKey, api_host: apiHost, ...options } = {}) {
46
+ function normalizeOptions({ api_key: apiKey, api_host: apiHost, templates, phrases, ...options } = {}) {
44
47
  return trimObj({
45
48
  apiKey,
46
49
  apiHost,
50
+ templates: templateAsFunction(templates),
51
+ phrases: templateAsFunction(phrases),
47
52
  ...options,
48
53
  });
49
54
  }
@@ -64,7 +69,7 @@ function readFromScriptSrc() {
64
69
  if (key === 'q') {
65
70
  continue;
66
71
  }
67
- params[key] = value === '' ? true : value;
72
+ params[key] = coerceValue(value);
68
73
  }
69
74
  return params;
70
75
  }
@@ -78,10 +83,39 @@ function readFromPageUrl() {
78
83
  const params = {};
79
84
  for (const [key, value] of new URLSearchParams(window.location.search)) {
80
85
  if (key.startsWith('miso_') && key.length > 5 && key !== 'miso_api_key') {
81
- params[key.substring(5)] = value === '' ? true : value;
86
+ params[key.substring(5)] = coerceValue(value);
82
87
  } else if (key === 'q') {
83
88
  params.q = value;
84
89
  }
85
90
  }
86
91
  return params;
87
92
  }
93
+
94
+ function coerceValue(value) {
95
+ return value === '' ? true : value === 'false' ? false : value;
96
+ }
97
+
98
+ function templateAsFunction(value) {
99
+ if (value === undefined || value === null) {
100
+ return value;
101
+ }
102
+ switch (typeof value) {
103
+ case 'function':
104
+ return value;
105
+ case 'string':
106
+ case 'number':
107
+ return () => value;
108
+ case 'object':
109
+ return Array.isArray(value) ? value.map(templateAsFunction) : mappingObjectValues(value, templateAsFunction);
110
+ default:
111
+ throw new Error(`Unsupported template type: ${value}`);
112
+ }
113
+ }
114
+
115
+ function mappingObjectValues(obj, fn) {
116
+ const mapped = {};
117
+ for (const [key, value] of Object.entries(obj)) {
118
+ mapped[key] = fn(value);
119
+ }
120
+ return mapped;
121
+ }
@@ -0,0 +1,7 @@
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';
@@ -12,38 +12,44 @@ export const root = (options) => `
12
12
  <section class="${PREFIX}__section ${PREFIX}__answer">
13
13
  ${options.templates.answer(options)}
14
14
  ${options.templates.sources(options)}
15
+ <miso-ask class="${PREFIX}__bottom-spacing-container" visible-when="ongoing"></miso-ask>
15
16
  </section>
16
17
  <div id="${PREFIX}__follow-ups" class="${PREFIX}__follow-ups"></div>
17
18
  <section id="${PREFIX}__related-resources" class="${PREFIX}__section ${PREFIX}__related-resources">
18
19
  <miso-ask visible-when="nonempty" logo="true">
19
- <h2 class="${PREFIX}__phrase ${PREFIX}__related-resources-phrase"></h2>
20
+ <h2 class="${PREFIX}__phrase ${PREFIX}__related-resources-phrase">${options.phrases.relatedResources(options)}</h2>
20
21
  <miso-related-resources></miso-related-resources>
21
22
  </miso-ask>
22
23
  </section>
23
24
  `.trim();
24
25
 
25
- export const followUp = (options, { parentQuestionId }) => `
26
+ export const followUp = (options, session = {}) => {
27
+ const { parentQuestionId } = session;
28
+ return `
26
29
  <section class="${PREFIX}__section ${PREFIX}__follow-up">
27
- <miso-ask class="${PREFIX}__query-suggestions-container" visible-when="initial" parent-question-id="${parentQuestionId}">
28
- <h3 class="${PREFIX}__phrase ${PREFIX}__related-questions-phrase"></h3>
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>
29
32
  <miso-query-suggestions></miso-query-suggestions>
30
33
  </miso-ask>
31
34
  <miso-ask class="${PREFIX}__query-container" visible-when="initial loading" parent-question-id="${parentQuestionId}">
32
35
  <miso-query></miso-query>
33
36
  </miso-ask>
34
- ${options.templates.answer(options, { parentQuestionId })}
35
- ${options.templates.sources(options, { parentQuestionId })}
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>
36
40
  </section>
37
41
  `.trim();
42
+ };
38
43
 
39
- export const answer = (options, { parentQuestionId } = {}) => {
44
+ export const answer = (options, session = {}) => {
40
45
  // TODO: include/omit miso-circled-citation-index by options
46
+ const { parentQuestionId } = session;
41
47
  const openTag = `<miso-ask class="${PREFIX}__answer-container miso-circled-citation-index" visible-when="ready" logo="false"${parentQuestionId ? ` parent-question-id="${parentQuestionId}"` : ''}>`;
42
48
  const closeTag = '</miso-ask>';
43
49
  return `
44
50
  ${openTag}
45
51
  ${ parentQuestionId ? '<hr>' : '' }
46
- <div class="${PREFIX}__phrase ${PREFIX}__question-phrase"></div>
52
+ <div class="${PREFIX}__phrase ${PREFIX}__question-phrase">${options.phrases.question(options, session)}</div>
47
53
  <miso-question></miso-question>
48
54
  <miso-answer></miso-answer>
49
55
  <miso-feedback></miso-feedback>
@@ -51,14 +57,15 @@ ${closeTag}
51
57
  `.trim();
52
58
  };
53
59
 
54
- export const sources = (options, { parentQuestionId } = {}) => {
60
+ export const sources = (options, session = {}) => {
55
61
  // TODO: include/omit miso-circled-citation-index by options
62
+ const { parentQuestionId } = session;
56
63
  const openTag = `<miso-ask class="${PREFIX}__sources-container miso-circled-citation-index" visible-when="nonempty" logo="false"${parentQuestionId ? ` parent-question-id="${parentQuestionId}"` : ''}>`;
57
64
  const closeTag = '</miso-ask>';
58
65
  return `
59
66
  ${openTag}
60
67
  <hr>
61
- <h3 class="${PREFIX}__phrase ${PREFIX}__sources-phrase"></h3>
68
+ <h3 class="${PREFIX}__phrase ${PREFIX}__sources-phrase">${options.phrases.sources(options, session)}</h3>
62
69
  <miso-sources></miso-sources>
63
70
  ${closeTag}
64
71
  `.trim();
package/src/combo/base.js CHANGED
@@ -27,11 +27,14 @@ export default class Combo extends Component {
27
27
  this._element = element;
28
28
  }
29
29
 
30
- start() {
30
+ start(options) {
31
31
  if (this._started) {
32
32
  return;
33
33
  }
34
34
  this._started = true;
35
+ if (options) {
36
+ this.config(options);
37
+ }
35
38
  this._start();
36
39
  }
37
40
 
@@ -26,7 +26,7 @@ export default class MisoComboElement extends HTMLElement {
26
26
  }
27
27
  this._combo = combo;
28
28
  combo.element = this;
29
- combo.start();
29
+ combo.autoStart();
30
30
  }
31
31
 
32
32
  }
package/src/plugin.js CHANGED
@@ -5,6 +5,7 @@ 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 { loadStylesIfNecessary } from './styles.js';
8
9
 
9
10
  import MisoContainerElement from './element/container/miso-container.js';
10
11
  import MisoComboElement from './element/combo/miso-combo.js';
@@ -17,16 +18,15 @@ export default class UiPlugin extends Component {
17
18
  return PLUGIN_ID;
18
19
  }
19
20
 
20
- constructor({ loadStyles = true } = {}) {
21
+ constructor() {
21
22
  super('ui');
22
23
  this.layouts = new Layouts(this);
23
24
  this._recommendations = new WeakMap();
24
25
  this._asks = new WeakMap();
25
26
  this._extensions = new WeakMap();
26
- // TODO: load CSS
27
27
  }
28
28
 
29
- install(MisoClient, context) {
29
+ async install(MisoClient, context) {
30
30
  context.addSubtree(this);
31
31
  MisoClient.on('create', this._injectClient.bind(this));
32
32
 
@@ -61,6 +61,11 @@ export default class UiPlugin extends Component {
61
61
  for (const ElementClass of ElementClasses) {
62
62
  ElementClass.MisoClient = MisoClient; // TODO: find better way
63
63
  }
64
+
65
+ // load styles
66
+ await loadStylesIfNecessary();
67
+
68
+ // define custom elements
64
69
  for (const ElementClass of ElementClasses) {
65
70
  defineAndUpgrade(ElementClass);
66
71
  }
package/src/styles.js ADDED
@@ -0,0 +1,74 @@
1
+ import version from './version.js';
2
+
3
+ const { currentScript } = document;
4
+
5
+ let cssUrl;
6
+ let stylesLoaded;
7
+
8
+ export async function loadStylesIfNecessary() {
9
+ return stylesLoaded || (stylesLoaded = loadStyles());
10
+ }
11
+
12
+ export async function loadStyles() {
13
+ try {
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;
24
+ document.head.appendChild(link);
25
+ });
26
+ } catch(e) {
27
+ console.error(e);
28
+ }
29
+ }
30
+
31
+ // helpers //
32
+ function getCssUrl() {
33
+ return cssUrl || (cssUrl = resolveCssUrl());
34
+ }
35
+
36
+ function resolveCssUrl() {
37
+ // TODO: refactor with getPluginScriptUrl() in core
38
+ if (version === 'dev') {
39
+ const src = currentScript.src;
40
+ const searchIndex = src.indexOf('?');
41
+ const k = searchIndex < 0 ? src.length : searchIndex;
42
+ const i = src.lastIndexOf('/', k); // .../dist/umd/*.min.js
43
+ return `${src.slice(0, i - 4)}/css/ui.css`;
44
+ } else {
45
+ return `https://cdn.jsdelivr.net/npm/@miso.ai/client-sdk@${version}/dist/css/ui.css`;
46
+ }
47
+ }
48
+
49
+ function getExistedLinkElement() {
50
+ return document.head.querySelector(`link[href="${getCssUrl()}"]`);
51
+ }
52
+
53
+ async function waitForLinkLoaded(element) {
54
+ if (element.sheet) {
55
+ return;
56
+ }
57
+ return new Promise((resolve, reject) => {
58
+ let intervalId;
59
+ element.onload = () => {
60
+ intervalId && clearInterval(intervalId);
61
+ resolve();
62
+ };
63
+ element.onerror = () => {
64
+ intervalId && clearInterval(intervalId);
65
+ reject();
66
+ };
67
+ intervalId = setInterval(() => {
68
+ if (element.sheet) {
69
+ intervalId && clearInterval(intervalId);
70
+ resolve();
71
+ }
72
+ }, 100);
73
+ });
74
+ }
package/src/version.js CHANGED
@@ -1 +1 @@
1
- export default '1.9.0-beta.8';
1
+ export default '1.9.0';