@miso.ai/client-sdk-ui 1.11.0-beta.7 → 1.11.0-beta.8

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.
@@ -3,7 +3,8 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.TRIANGLE = exports.SEND = exports.SEARCH = void 0;
6
+ exports.TRIANGLE = exports.SEND = exports.SEARCH = exports.ICON_NAMES = void 0;
7
+ exports.getIcon = getIcon;
7
8
  var _version = _interopRequireDefault(require("../version.js"));
8
9
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
9
10
  function trianglePath(r) {
@@ -14,13 +15,18 @@ function trianglePath(r) {
14
15
  }
15
16
  const PREFIX = 'miso-ui-icon';
16
17
  const ID = `${PREFIX}-svg-${_version.default.replaceAll('.', '_')}`;
18
+ const ICON_NAME = {
19
+ SEND: 'send',
20
+ SEARCH: 'search',
21
+ TRIANGLE: 'triangle'
22
+ };
17
23
 
18
24
  // CC0 SVGs
19
- const ICON_SEND = `<symbol id="${PREFIX}-send" viewBox="0 0 32 32"><path fill="currentColor" d="M11.499,19.173l5.801,-5.849c0.389,-0.392 1.022,-0.394 1.414,-0.006c0.392,0.389 0.395,1.022 0.006,1.414l-5.798,5.847l5.306,8.002c0.207,0.313 0.572,0.483 0.945,0.441c0.373,-0.042 0.691,-0.289 0.824,-0.64l9.024,-23.904c0.138,-0.366 0.05,-0.78 -0.226,-1.058c-0.276,-0.278 -0.689,-0.369 -1.057,-0.233l-24.004,8.892c-0.353,0.13 -0.602,0.448 -0.646,0.821c-0.044,0.373 0.125,0.74 0.438,0.948l7.973,5.325Z"/></symbol>`;
20
- const ICON_SEARCH = `<symbol id="${PREFIX}-search" viewBox="0 0 24 24"><path fill="currentColor" d="M4 11C4 7.13401 7.13401 4 11 4C14.866 4 18 7.13401 18 11C18 14.866 14.866 18 11 18C7.13401 18 4 14.866 4 11ZM11 2C6.02944 2 2 6.02944 2 11C2 15.9706 6.02944 20 11 20C13.125 20 15.078 19.2635 16.6177 18.0319L20.2929 21.7071C20.6834 22.0976 21.3166 22.0976 21.7071 21.7071C22.0976 21.3166 22.0976 20.6834 21.7071 20.2929L18.0319 16.6177C19.2635 15.078 20 13.125 20 11C20 6.02944 15.9706 2 11 2Z"/></symbol>`;
25
+ const ICON_SEND = `<symbol id="${PREFIX}-${ICON_NAME.SEND}" viewBox="0 0 32 32"><path fill="currentColor" d="M11.499,19.173l5.801,-5.849c0.389,-0.392 1.022,-0.394 1.414,-0.006c0.392,0.389 0.395,1.022 0.006,1.414l-5.798,5.847l5.306,8.002c0.207,0.313 0.572,0.483 0.945,0.441c0.373,-0.042 0.691,-0.289 0.824,-0.64l9.024,-23.904c0.138,-0.366 0.05,-0.78 -0.226,-1.058c-0.276,-0.278 -0.689,-0.369 -1.057,-0.233l-24.004,8.892c-0.353,0.13 -0.602,0.448 -0.646,0.821c-0.044,0.373 0.125,0.74 0.438,0.948l7.973,5.325Z"/></symbol>`;
26
+ const ICON_SEARCH = `<symbol id="${PREFIX}-${ICON_NAME.SEARCH}" viewBox="0 0 24 24"><path fill="currentColor" d="M4 11C4 7.13401 7.13401 4 11 4C14.866 4 18 7.13401 18 11C18 14.866 14.866 18 11 18C7.13401 18 4 14.866 4 11ZM11 2C6.02944 2 2 6.02944 2 11C2 15.9706 6.02944 20 11 20C13.125 20 15.078 19.2635 16.6177 18.0319L20.2929 21.7071C20.6834 22.0976 21.3166 22.0976 21.7071 21.7071C22.0976 21.3166 22.0976 20.6834 21.7071 20.2929L18.0319 16.6177C19.2635 15.078 20 13.125 20 11C20 6.02944 15.9706 2 11 2Z"/></symbol>`;
21
27
 
22
28
  // Custom SVGs
23
- const ICON_TRIANGLE = `<symbol id="${PREFIX}-triangle" viewBox="-5 -5 105 105"><path d="${trianglePath(5)}"/></symbol>`;
29
+ const ICON_TRIANGLE = `<symbol id="${PREFIX}-${ICON_NAME.TRIANGLE}" viewBox="-5 -5 105 105"><path d="${trianglePath(5)}"/></symbol>`;
24
30
  const ICONS = [ICON_SEND, ICON_SEARCH, ICON_TRIANGLE];
25
31
  const SPRITES_SVG = `<svg id="${ID}" style="display:none;">${ICONS.join('')}</svg>`;
26
32
  let loaded = false;
@@ -32,9 +38,13 @@ function loadSvgSprites() {
32
38
  document.head.insertAdjacentHTML('beforeend', SPRITES_SVG);
33
39
  }
34
40
  loadSvgSprites();
35
- function getSvg(name) {
41
+ function _icon(name) {
36
42
  return `<svg class="miso-ui-icon miso-ui-icon-${name}"><use href="#${PREFIX}-${name}"></use></svg>`;
37
43
  }
38
- const SEND = exports.SEND = getSvg('send');
39
- const SEARCH = exports.SEARCH = getSvg('search');
40
- const TRIANGLE = exports.TRIANGLE = getSvg('triangle');
44
+ const ICON_NAMES = exports.ICON_NAMES = new Set(Object.values(ICON_NAME));
45
+ function getIcon(name) {
46
+ return ICON_NAMES.has(name) ? _icon(name) : '';
47
+ }
48
+ const SEND = exports.SEND = _icon(ICON_NAME.SEND);
49
+ const SEARCH = exports.SEARCH = _icon(ICON_NAME.SEARCH);
50
+ const TRIANGLE = exports.TRIANGLE = _icon(ICON_NAME.TRIANGLE);
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.default = void 0;
7
7
  var _constants = require("./constants.js");
8
8
  var _constants2 = require("../../constants.js");
9
+ var _index = require("../../actor/index.js");
9
10
  var _phrases = require("./phrases.js");
10
11
  const CLASS_OPEN = 'answer-box-open';
11
12
  const CLASS_SHOWN = 'answer-box-shown';
@@ -29,7 +30,12 @@ class AnswerBox {
29
30
 
30
31
  // expose widget API
31
32
  workflow.answerBox = this;
32
- workflow._unsubscribes.push(() => this.destroy()); // TODO: review
33
+ workflow._unsubscribes.push(() => {
34
+ if (workflow.answerBox === this) {
35
+ this.destroy();
36
+ workflow.answerBox = undefined;
37
+ }
38
+ });
33
39
 
34
40
  // handle toggle button clicks
35
41
  const callback = event => this._handleClick(event);
@@ -38,7 +44,9 @@ class AnswerBox {
38
44
  // sync state
39
45
  this._syncWofkflowStatus();
40
46
  this._syncButtonText();
41
- this._unsubscribes = [() => element.removeEventListener('click', callback), workflow._answer.on('loading', () => this.hide()), workflow._answer.on('error', () => this.show()), workflow._answer.on('ready', () => this.show())];
47
+ this._unsubscribes = [() => element.removeEventListener('click', callback),
48
+ // cling to data rather than view, as we may miss view event when tab is inactive due to raf
49
+ workflow._answer._hub.on(_index.fields.data(), () => this._syncWofkflowStatus())];
42
50
  }
43
51
  _handleClick(_ref) {
44
52
  let {
@@ -75,6 +83,13 @@ class AnswerBox {
75
83
  button.textContent = phrase;
76
84
  }
77
85
  }
86
+ _syncScroll() {
87
+ if (!this.isOpen) {
88
+ this._element.scrollIntoView({
89
+ behavior: 'smooth'
90
+ });
91
+ }
92
+ }
78
93
  destroy() {
79
94
  for (const unsubscribe of this._unsubscribes) {
80
95
  unsubscribe();
@@ -110,6 +125,7 @@ for (const [method, [action, className]] of Object.entries(METHODS)) {
110
125
  this._updateBoxStatus(action, className);
111
126
  if (className === CLASS_OPEN) {
112
127
  this._syncButtonText();
128
+ this._syncScroll();
113
129
  }
114
130
  };
115
131
  }
@@ -19,26 +19,40 @@ const DEFAULT_AUTOCOMPLETE_CLASSNAME = 'miso-autocomplete';
19
19
  function root(layout) {
20
20
  const {
21
21
  className,
22
+ templates,
22
23
  role,
23
24
  options,
24
- workflow,
25
25
  autocomplete
26
26
  } = layout;
27
27
  const {
28
- placeholder,
29
- buttonText
28
+ placeholder
30
29
  } = options;
31
30
  const roleAttr = role ? `data-role="${role}"` : '';
32
- const buttonContent = buttonText || workflow === 'search' ? _svgs.SEARCH : _svgs.SEND;
33
31
  return `
34
32
  <div class="${className}" ${roleAttr}>
35
33
  <div class="${className}__input-group">
36
34
  <input class="${className}__input" type="text" data-role="input" ${placeholder ? `placeholder="${placeholder}"` : ''}>
37
- <button class="${className}__button" type="submit" data-role="submit">${buttonContent}</button>
35
+ <button class="${className}__button" type="submit" data-role="submit">${templates.buttonContent(layout)}</button>
38
36
  </div>
39
37
  <div class="${autocomplete.className}" data-role="autocomplete"></div>
40
38
  </div>`.trim();
41
39
  }
40
+ function buttonContent(layout) {
41
+ const {
42
+ templates,
43
+ options
44
+ } = layout;
45
+ if (options.buttonText) {
46
+ return options.buttonText; // legacy
47
+ }
48
+ const {
49
+ buttonText,
50
+ buttonIcon
51
+ } = templates;
52
+ const text = typeof buttonText === 'function' ? buttonText(layout) : `${buttonText}`;
53
+ const icon = typeof buttonIcon === 'function' ? buttonIcon(layout) : (0, _svgs.getIcon)(buttonIcon) || `${buttonIcon}`;
54
+ return text + icon;
55
+ }
42
56
  function completions(layout, items) {
43
57
  const {
44
58
  templates,
@@ -110,6 +124,9 @@ function completionItem(layout, type, item) {
110
124
  }
111
125
  const DEFAULT_TEMPLATES = Object.freeze({
112
126
  root,
127
+ buttonContent,
128
+ buttonText: '',
129
+ buttonIcon: 'search',
113
130
  completions,
114
131
  completionList,
115
132
  completionItem,
@@ -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.11.0-beta.7';
7
+ var _default = exports.default = '1.11.0-beta.8';
@@ -20,6 +20,11 @@ const DEFAULT_API_OPTIONS = Object.freeze(Object.assign({}, _answerBased.default
20
20
  })
21
21
  }));
22
22
  const DEFAULT_LAYOUTS = Object.freeze(Object.assign({}, _answerBased.default.DEFAULT_LAYOUTS, {
23
+ [_constants.ROLE.QUERY]: [_index2.SearchBoxLayout.type, {
24
+ templates: {
25
+ buttonIcon: 'send'
26
+ }
27
+ }],
23
28
  [_constants.ROLE.RELATED_RESOURCES]: [_index2.ListLayout.type, {
24
29
  incremental: true,
25
30
  itemType: 'article'
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.11.0-beta.7"
29
+ "@miso.ai/commons": "1.11.0-beta.8"
30
30
  },
31
- "version": "1.11.0-beta.7"
31
+ "version": "1.11.0-beta.8"
32
32
  }
package/src/asset/svgs.js CHANGED
@@ -10,12 +10,18 @@ function trianglePath(r) {
10
10
  const PREFIX = 'miso-ui-icon';
11
11
  const ID = `${PREFIX}-svg-${version.replaceAll('.', '_')}`;
12
12
 
13
+ const ICON_NAME = {
14
+ SEND: 'send',
15
+ SEARCH: 'search',
16
+ TRIANGLE: 'triangle',
17
+ };
18
+
13
19
  // CC0 SVGs
14
- const ICON_SEND = `<symbol id="${PREFIX}-send" viewBox="0 0 32 32"><path fill="currentColor" d="M11.499,19.173l5.801,-5.849c0.389,-0.392 1.022,-0.394 1.414,-0.006c0.392,0.389 0.395,1.022 0.006,1.414l-5.798,5.847l5.306,8.002c0.207,0.313 0.572,0.483 0.945,0.441c0.373,-0.042 0.691,-0.289 0.824,-0.64l9.024,-23.904c0.138,-0.366 0.05,-0.78 -0.226,-1.058c-0.276,-0.278 -0.689,-0.369 -1.057,-0.233l-24.004,8.892c-0.353,0.13 -0.602,0.448 -0.646,0.821c-0.044,0.373 0.125,0.74 0.438,0.948l7.973,5.325Z"/></symbol>`;
15
- const ICON_SEARCH = `<symbol id="${PREFIX}-search" viewBox="0 0 24 24"><path fill="currentColor" d="M4 11C4 7.13401 7.13401 4 11 4C14.866 4 18 7.13401 18 11C18 14.866 14.866 18 11 18C7.13401 18 4 14.866 4 11ZM11 2C6.02944 2 2 6.02944 2 11C2 15.9706 6.02944 20 11 20C13.125 20 15.078 19.2635 16.6177 18.0319L20.2929 21.7071C20.6834 22.0976 21.3166 22.0976 21.7071 21.7071C22.0976 21.3166 22.0976 20.6834 21.7071 20.2929L18.0319 16.6177C19.2635 15.078 20 13.125 20 11C20 6.02944 15.9706 2 11 2Z"/></symbol>`;
20
+ const ICON_SEND = `<symbol id="${PREFIX}-${ICON_NAME.SEND}" viewBox="0 0 32 32"><path fill="currentColor" d="M11.499,19.173l5.801,-5.849c0.389,-0.392 1.022,-0.394 1.414,-0.006c0.392,0.389 0.395,1.022 0.006,1.414l-5.798,5.847l5.306,8.002c0.207,0.313 0.572,0.483 0.945,0.441c0.373,-0.042 0.691,-0.289 0.824,-0.64l9.024,-23.904c0.138,-0.366 0.05,-0.78 -0.226,-1.058c-0.276,-0.278 -0.689,-0.369 -1.057,-0.233l-24.004,8.892c-0.353,0.13 -0.602,0.448 -0.646,0.821c-0.044,0.373 0.125,0.74 0.438,0.948l7.973,5.325Z"/></symbol>`;
21
+ const ICON_SEARCH = `<symbol id="${PREFIX}-${ICON_NAME.SEARCH}" viewBox="0 0 24 24"><path fill="currentColor" d="M4 11C4 7.13401 7.13401 4 11 4C14.866 4 18 7.13401 18 11C18 14.866 14.866 18 11 18C7.13401 18 4 14.866 4 11ZM11 2C6.02944 2 2 6.02944 2 11C2 15.9706 6.02944 20 11 20C13.125 20 15.078 19.2635 16.6177 18.0319L20.2929 21.7071C20.6834 22.0976 21.3166 22.0976 21.7071 21.7071C22.0976 21.3166 22.0976 20.6834 21.7071 20.2929L18.0319 16.6177C19.2635 15.078 20 13.125 20 11C20 6.02944 15.9706 2 11 2Z"/></symbol>`;
16
22
 
17
23
  // Custom SVGs
18
- const ICON_TRIANGLE = `<symbol id="${PREFIX}-triangle" viewBox="-5 -5 105 105"><path d="${trianglePath(5)}"/></symbol>`;
24
+ const ICON_TRIANGLE = `<symbol id="${PREFIX}-${ICON_NAME.TRIANGLE}" viewBox="-5 -5 105 105"><path d="${trianglePath(5)}"/></symbol>`;
19
25
 
20
26
  const ICONS = [ICON_SEND, ICON_SEARCH, ICON_TRIANGLE];
21
27
 
@@ -33,10 +39,16 @@ function loadSvgSprites() {
33
39
 
34
40
  loadSvgSprites();
35
41
 
36
- function getSvg(name) {
42
+ function _icon(name) {
37
43
  return `<svg class="miso-ui-icon miso-ui-icon-${name}"><use href="#${PREFIX}-${name}"></use></svg>`;
38
44
  }
39
45
 
40
- export const SEND = getSvg('send');
41
- export const SEARCH = getSvg('search');
42
- export const TRIANGLE = getSvg('triangle');
46
+ export const ICON_NAMES = new Set(Object.values(ICON_NAME));
47
+
48
+ export function getIcon(name) {
49
+ return ICON_NAMES.has(name) ? _icon(name) : '';
50
+ }
51
+
52
+ export const SEND = _icon(ICON_NAME.SEND);
53
+ export const SEARCH = _icon(ICON_NAME.SEARCH);
54
+ export const TRIANGLE = _icon(ICON_NAME.TRIANGLE);
@@ -1,5 +1,6 @@
1
1
  import { CLASS_PREFIX } from './constants.js';
2
2
  import { STATUS } from '../../constants.js';
3
+ import { fields } from '../../actor/index.js';
3
4
  import { showMore as DEFAULT_PHRASE_SHOW_MORE, showLess as DEFAULT_PHRASE_SHOW_LESS } from './phrases.js';
4
5
 
5
6
  const CLASS_OPEN = 'answer-box-open';
@@ -23,7 +24,12 @@ export default class AnswerBox {
23
24
 
24
25
  // expose widget API
25
26
  workflow.answerBox = this;
26
- workflow._unsubscribes.push(() => this.destroy()); // TODO: review
27
+ workflow._unsubscribes.push(() => {
28
+ if (workflow.answerBox === this) {
29
+ this.destroy();
30
+ workflow.answerBox = undefined;
31
+ }
32
+ });
27
33
 
28
34
  // handle toggle button clicks
29
35
  const callback = event => this._handleClick(event);
@@ -35,9 +41,8 @@ export default class AnswerBox {
35
41
 
36
42
  this._unsubscribes = [
37
43
  () => element.removeEventListener('click', callback),
38
- workflow._answer.on('loading', () => this.hide()),
39
- workflow._answer.on('error', () => this.show()),
40
- workflow._answer.on('ready', () => this.show()),
44
+ // cling to data rather than view, as we may miss view event when tab is inactive due to raf
45
+ workflow._answer._hub.on(fields.data(), () => this._syncWofkflowStatus()),
41
46
  ];
42
47
  }
43
48
 
@@ -74,6 +79,12 @@ export default class AnswerBox {
74
79
  }
75
80
  }
76
81
 
82
+ _syncScroll() {
83
+ if (!this.isOpen) {
84
+ this._element.scrollIntoView({ behavior: 'smooth' });
85
+ }
86
+ }
87
+
77
88
  destroy() {
78
89
  for (const unsubscribe of this._unsubscribes) {
79
90
  unsubscribe();
@@ -113,6 +124,7 @@ for (const [method, [action, className]] of Object.entries(METHODS)) {
113
124
  this._updateBoxStatus(action, className);
114
125
  if (className === CLASS_OPEN) {
115
126
  this._syncButtonText();
127
+ this._syncScroll();
116
128
  }
117
129
  };
118
130
  }
@@ -3,27 +3,37 @@ import { LAYOUT_CATEGORY, STATUS, EVENT_TYPE, DATA_ASPECT } from '../../constant
3
3
  import { fields } from '../../actor/index.js';
4
4
  import TemplateBasedLayout from '../template.js';
5
5
  import { imageBlock, productInfoBlock } from '../templates.js';
6
- import { SEND, SEARCH } from '../../asset/svgs.js';
6
+ import { getIcon } from '../../asset/svgs.js';
7
7
 
8
8
  const TYPE = 'search-box';
9
9
  const DEFAULT_CLASSNAME = 'miso-search-box';
10
10
  const DEFAULT_AUTOCOMPLETE_CLASSNAME = 'miso-autocomplete';
11
11
 
12
12
  function root(layout) {
13
- const { className, role, options, workflow, autocomplete } = layout;
14
- const { placeholder, buttonText } = options;
13
+ const { className, templates, role, options, autocomplete } = layout;
14
+ const { placeholder } = options;
15
15
  const roleAttr = role ? `data-role="${role}"` : '';
16
- const buttonContent = buttonText || workflow === 'search' ? SEARCH : SEND;
17
16
  return `
18
17
  <div class="${className}" ${roleAttr}>
19
18
  <div class="${className}__input-group">
20
19
  <input class="${className}__input" type="text" data-role="input" ${placeholder ? `placeholder="${placeholder}"` : ''}>
21
- <button class="${className}__button" type="submit" data-role="submit">${buttonContent}</button>
20
+ <button class="${className}__button" type="submit" data-role="submit">${templates.buttonContent(layout)}</button>
22
21
  </div>
23
22
  <div class="${autocomplete.className}" data-role="autocomplete"></div>
24
23
  </div>`.trim();
25
24
  }
26
25
 
26
+ function buttonContent(layout) {
27
+ const { templates, options } = layout;
28
+ if (options.buttonText) {
29
+ return options.buttonText; // legacy
30
+ }
31
+ const { buttonText, buttonIcon } = templates;
32
+ const text = typeof buttonText === 'function' ? buttonText(layout) : `${buttonText}`;
33
+ const icon = typeof buttonIcon === 'function' ? buttonIcon(layout) : (getIcon(buttonIcon) || `${buttonIcon}`);
34
+ return text + icon;
35
+ }
36
+
27
37
  function completions(layout, items) {
28
38
  const { templates, workflow, autocomplete } = layout;
29
39
  // use options under layout.autocomplete from now on
@@ -84,6 +94,9 @@ function completionItem(layout, type, item) {
84
94
 
85
95
  const DEFAULT_TEMPLATES = Object.freeze({
86
96
  root,
97
+ buttonContent,
98
+ buttonText: '',
99
+ buttonIcon: 'search',
87
100
  completions,
88
101
  completionList,
89
102
  completionItem,
package/src/version.js CHANGED
@@ -1 +1 @@
1
- export default '1.11.0-beta.7';
1
+ export default '1.11.0-beta.8';
@@ -2,7 +2,7 @@ import { defineValues, trimObj, API } from '@miso.ai/commons';
2
2
  import AnswerBasedWorkflow from './answer-based.js';
3
3
  import { fields } from '../actor/index.js';
4
4
  import { ROLE, ORGANIC_QUESTION_SOURCE } from '../constants.js';
5
- import { OptionListLayout, ListLayout } from '../layout/index.js';
5
+ import { OptionListLayout, ListLayout, SearchBoxLayout } from '../layout/index.js';
6
6
 
7
7
  const DEFAULT_API_OPTIONS = Object.freeze({
8
8
  ...AnswerBasedWorkflow.DEFAULT_API_OPTIONS,
@@ -15,6 +15,7 @@ const DEFAULT_API_OPTIONS = Object.freeze({
15
15
 
16
16
  const DEFAULT_LAYOUTS = Object.freeze({
17
17
  ...AnswerBasedWorkflow.DEFAULT_LAYOUTS,
18
+ [ROLE.QUERY]: [SearchBoxLayout.type, { templates: { buttonIcon: 'send' } }],
18
19
  [ROLE.RELATED_RESOURCES]: [ListLayout.type, { incremental: true, itemType: 'article' }],
19
20
  [ROLE.QUERY_SUGGESTIONS]: OptionListLayout.type,
20
21
  });