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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/cjs/asset/svgs.js +4 -2
  2. package/dist/cjs/constants.js +2 -0
  3. package/dist/cjs/defaults/ask/index.js +2 -1
  4. package/dist/cjs/defaults/ask/templates.js +2 -1
  5. package/dist/cjs/defaults/hybrid-search/index.js +2 -1
  6. package/dist/cjs/defaults/hybrid-search/templates.js +2 -1
  7. package/dist/cjs/defaults/index.js +2 -1
  8. package/dist/cjs/defaults.js +107 -10
  9. package/dist/cjs/element/container/index.js +14 -0
  10. package/dist/cjs/element/container/miso-message-item.js +91 -0
  11. package/dist/cjs/element/container/miso-thread-item.js +91 -0
  12. package/dist/cjs/element/index.js +2 -1
  13. package/dist/cjs/element/role/index.js +7 -0
  14. package/dist/cjs/element/role/miso-delete.js +20 -0
  15. package/dist/cjs/layout/button/button.js +45 -5
  16. package/dist/cjs/layout/button/checkbox.js +2 -1
  17. package/dist/cjs/layout/container/item-container.js +99 -0
  18. package/dist/cjs/layout/index.js +14 -0
  19. package/dist/cjs/layout/input/search-box.js +9 -4
  20. package/dist/cjs/layout/list/collection.js +21 -4
  21. package/dist/cjs/layout/list/messages.js +261 -224
  22. package/dist/cjs/layout/list/threads.js +106 -150
  23. package/dist/cjs/layout/templates.js +98 -38
  24. package/dist/cjs/layout/text/question.js +71 -0
  25. package/dist/cjs/layout/text/typewriter/index.js +15 -21
  26. package/dist/cjs/plugin.js +6 -3
  27. package/dist/cjs/util/dom.js +21 -0
  28. package/dist/cjs/util/notify.js +74 -0
  29. package/dist/cjs/version.js +1 -1
  30. package/package.json +3 -3
  31. package/src/CLAUDE.md +7 -2
  32. package/src/asset/svgs.js +3 -1
  33. package/src/constants.js +2 -0
  34. package/src/defaults.js +75 -5
  35. package/src/element/container/index.js +2 -0
  36. package/src/element/container/miso-message-item.js +94 -0
  37. package/src/element/container/miso-thread-item.js +94 -0
  38. package/src/element/role/index.js +1 -0
  39. package/src/element/role/miso-delete.js +16 -0
  40. package/src/layout/button/button.js +40 -4
  41. package/src/layout/button/checkbox.js +2 -1
  42. package/src/layout/container/item-container.js +99 -0
  43. package/src/layout/index.js +2 -0
  44. package/src/layout/input/search-box.js +4 -2
  45. package/src/layout/list/collection.js +22 -5
  46. package/src/layout/list/messages.js +231 -201
  47. package/src/layout/list/threads.js +107 -128
  48. package/src/layout/templates.js +100 -38
  49. package/src/layout/text/question.js +58 -0
  50. package/src/layout/text/typewriter/index.js +11 -15
  51. package/src/plugin.js +3 -2
  52. package/src/util/dom.js +16 -0
  53. package/src/util/notify.js +68 -0
  54. package/src/version.js +1 -1
@@ -28,7 +28,8 @@ const ICON_NAME = {
28
28
  PLUS: 'plus',
29
29
  PENCIL: 'pencil',
30
30
  BELL: 'bell',
31
- BELL_FILL: 'bell-fill'
31
+ BELL_FILL: 'bell-fill',
32
+ TRASH: 'trash'
32
33
  };
33
34
 
34
35
  // CC0 SVGs
@@ -48,7 +49,8 @@ const ICON_PLUS = `<symbol id="${PREFIX}-${ICON_NAME.PLUS}" viewBox="0 0 16 16">
48
49
  const ICON_PENCIL = `<symbol id="${PREFIX}-${ICON_NAME.PENCIL}" viewBox="0 0 16 16"><path fill="currentColor" d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.325-.175"/></symbol>`;
49
50
  const ICON_BELL = `<symbol id="${PREFIX}-${ICON_NAME.BELL}" viewBox="0 0 16 16"><path fill="currentColor" d="M8 16a2 2 0 0 0 2-2H6a2 2 0 0 0 2 2M8 1.918l-.797.161A4 4 0 0 0 4 6c0 .628-.134 2.197-.459 3.742-.16.767-.376 1.566-.663 2.258h10.244c-.287-.692-.502-1.49-.663-2.258C12.134 8.197 12 6.628 12 6a4 4 0 0 0-3.203-3.92zM14.22 12c.223.447.481.801.78 1H1c.299-.199.557-.553.78-1C2.68 10.2 3 6.88 3 6c0-2.42 1.72-4.44 4.005-4.901a1 1 0 1 1 1.99 0A5 5 0 0 1 13 6c0 .88.32 4.2 1.22 6"/></symbol>`;
50
51
  const ICON_BELL_FILL = `<symbol id="${PREFIX}-${ICON_NAME.BELL_FILL}" viewBox="0 0 16 16"><path fill="currentColor" d="M8 16a2 2 0 0 0 2-2H6a2 2 0 0 0 2 2m.995-14.901a1 1 0 1 0-1.99 0A5 5 0 0 0 3 6c0 1.098-.5 6-2 7h14c-1.5-1-2-5.902-2-7 0-2.42-1.72-4.44-4.005-4.901"/></symbol>`;
51
- const ICONS = [ICON_SEND, ICON_SEARCH, ICON_TRIANGLE, ICON_TRIANGLE_EQ, ICON_CHEVRON, ICON_CHEVRON_NEGATIVE, ICON_BULB, ICON_DOTS_VERTICAL, ICON_PLUS, ICON_PENCIL, ICON_BELL, ICON_BELL_FILL];
52
+ const ICON_TRASH = `<symbol id="${PREFIX}-${ICON_NAME.TRASH}" viewBox="0 0 16 16"><path fill="currentColor" d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5m2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5m3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0z"/><path fill="currentColor" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4zM2.5 3h11V2h-11z"/></symbol>`;
53
+ const ICONS = [ICON_SEND, ICON_SEARCH, ICON_TRIANGLE, ICON_TRIANGLE_EQ, ICON_CHEVRON, ICON_CHEVRON_NEGATIVE, ICON_BULB, ICON_DOTS_VERTICAL, ICON_PLUS, ICON_PENCIL, ICON_BELL, ICON_BELL_FILL, ICON_TRASH];
52
54
  const SPRITES_SVG = `<svg id="${ID}" style="display:none;">${ICONS.join('')}</svg>`;
53
55
  let loaded = false;
54
56
  function loadSvgSprites() {
@@ -108,6 +108,7 @@ const ATTR_DATA_MISO_UNIT_ID = exports.ATTR_DATA_MISO_UNIT_ID = `data-miso-unit-
108
108
  const ATTR_DATA_MISO_PRODUCT_ID = exports.ATTR_DATA_MISO_PRODUCT_ID = `data-miso-product-id`;
109
109
  const LAYOUT_TYPE = exports.LAYOUT_TYPE = Object.freeze({
110
110
  CONTAINER: 'container',
111
+ ITEM_CONTAINER: 'item-container',
111
112
  ERROR: 'error',
112
113
  BANNER: 'banner',
113
114
  AFFILIATION: 'affiliation',
@@ -127,5 +128,6 @@ const LAYOUT_TYPE = exports.LAYOUT_TYPE = Object.freeze({
127
128
  CHECKBOX: 'checkbox',
128
129
  FEEDBACK: 'feedback',
129
130
  TEXT: 'text',
131
+ QUESTION: 'question',
130
132
  TYPEWRITER: 'typewriter'
131
133
  });
@@ -24,7 +24,8 @@ Object.keys(_controls).forEach(function (key) {
24
24
  }
25
25
  });
26
26
  });
27
- function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
27
+ var cache;
28
+ function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var r, c, a = Object.defineProperty, n = { __proto__: null, default: e }; if (Object(e) !== e) return n; if (cache || "function" != typeof WeakMap || (cache = new WeakMap()), cache) { if (cache.has(e)) return cache.get(e); cache.set(e, n); } for (c in e) "default" !== c && {}.hasOwnProperty.call(e, c) && ((r = a && Object.getOwnPropertyDescriptor(e, c)) && (r.get || r.set) ? a(n, c, r) : n[c] = e[c]); return n; }
28
29
  const constants = exports.constants = Object.freeze(_constants);
29
30
  const phrases = exports.phrases = Object.freeze(_phrases);
30
31
  const templates = exports.templates = Object.freeze(_templates);
@@ -12,7 +12,8 @@ var CONSTANTS = _interopRequireWildcard(require("./constants.js"));
12
12
  var DEFAULT_PHRASES = _interopRequireWildcard(require("./phrases.js"));
13
13
  var _svgs = require("../../asset/svgs.js");
14
14
  var _templates = require("../common/templates.js");
15
- function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
15
+ var cache;
16
+ function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var r, c, a = Object.defineProperty, n = { __proto__: null, default: e }; if (Object(e) !== e) return n; if (cache || "function" != typeof WeakMap || (cache = new WeakMap()), cache) { if (cache.has(e)) return cache.get(e); cache.set(e, n); } for (c in e) "default" !== c && {}.hasOwnProperty.call(e, c) && ((r = a && Object.getOwnPropertyDescriptor(e, c)) && (r.get || r.set) ? a(n, c, r) : n[c] = e[c]); return n; }
16
17
  class Sections extends _templates.Sections {
17
18
  constructor() {
18
19
  super({
@@ -24,7 +24,8 @@ Object.keys(_controls).forEach(function (key) {
24
24
  }
25
25
  });
26
26
  });
27
- function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
27
+ var cache;
28
+ function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var r, c, a = Object.defineProperty, n = { __proto__: null, default: e }; if (Object(e) !== e) return n; if (cache || "function" != typeof WeakMap || (cache = new WeakMap()), cache) { if (cache.has(e)) return cache.get(e); cache.set(e, n); } for (c in e) "default" !== c && {}.hasOwnProperty.call(e, c) && ((r = a && Object.getOwnPropertyDescriptor(e, c)) && (r.get || r.set) ? a(n, c, r) : n[c] = e[c]); return n; }
28
29
  const constants = exports.constants = Object.freeze(_constants);
29
30
  const phrases = exports.phrases = Object.freeze(_phrases);
30
31
  const templates = exports.templates = Object.freeze(_templates);
@@ -10,7 +10,8 @@ var _commons = require("@miso.ai/commons");
10
10
  var CONSTANTS = _interopRequireWildcard(require("./constants.js"));
11
11
  var DEFAULT_PHRASES = _interopRequireWildcard(require("./phrases.js"));
12
12
  var _templates = require("../common/templates.js");
13
- function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
13
+ var cache;
14
+ function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var r, c, a = Object.defineProperty, n = { __proto__: null, default: e }; if (Object(e) !== e) return n; if (cache || "function" != typeof WeakMap || (cache = new WeakMap()), cache) { if (cache.has(e)) return cache.get(e); cache.set(e, n); } for (c in e) "default" !== c && {}.hasOwnProperty.call(e, c) && ((r = a && Object.getOwnPropertyDescriptor(e, c)) && (r.get || r.set) ? a(n, c, r) : n[c] = e[c]); return n; }
14
15
  class Sections extends _templates.Sections {
15
16
  constructor() {
16
17
  super({
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.hybridSearch = exports.ask = void 0;
7
7
  var _ask = _interopRequireWildcard(require("./ask/index.js"));
8
8
  var _hybridSearch = _interopRequireWildcard(require("./hybrid-search/index.js"));
9
- function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
9
+ var cache;
10
+ function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var r, c, a = Object.defineProperty, n = { __proto__: null, default: e }; if (Object(e) !== e) return n; if (cache || "function" != typeof WeakMap || (cache = new WeakMap()), cache) { if (cache.has(e)) return cache.get(e); cache.set(e, n); } for (c in e) "default" !== c && {}.hasOwnProperty.call(e, c) && ((r = a && Object.getOwnPropertyDescriptor(e, c)) && (r.get || r.set) ? a(n, c, r) : n[c] = e[c]); return n; }
10
11
  const ask = exports.ask = Object.freeze(_ask);
11
12
  const hybridSearch = exports.hybridSearch = Object.freeze(_hybridSearch);
@@ -4,8 +4,12 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.defaultLayouts = void 0;
7
+ var _commons = require("@miso.ai/commons");
7
8
  var _constants = require("./constants.js");
8
9
  var _templates = require("./layout/templates.js");
10
+ 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
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
12
+ function _toPrimitive(t, e) { if ("object" != typeof t || !t) return t; var r; if ("undefined" != typeof Symbol && void 0 !== (r = t[Symbol.toPrimitive])) { var i = r.call(t, e || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === e ? String : Number)(t); }
9
13
  /**
10
14
  * Default layout options of each workflow, keyed by workflow name. The UI
11
15
  * plugin seeds the workflow plugin's defaults store with these values at
@@ -57,6 +61,29 @@ function totalContent(layout, {
57
61
  const label = value === 1 ? 'result' : 'results';
58
62
  return `${formatted} ${label}`;
59
63
  }
64
+ const _ROLE$QUERY = _constants.ROLE.QUERY,
65
+ MESSAGE_LAYOUTS = _objectWithoutPropertiesLoose(ANSWER_BASED_LAYOUTS, [_ROLE$QUERY].map(_toPropertyKey));
66
+
67
+ // the rename/delete button controls of a thread (the conversation header's,
68
+ // and a thread list item's context menu's): mapped to the thread record —
69
+ // the dialogs work with its title, and the buttons disable while the record
70
+ // has no thread id yet (a thread being created is not addressable until
71
+ // resolved; the workflows guard all the same)
72
+ const THREAD_CONTROL_OPTIONS = Object.freeze({
73
+ value: thread => thread && thread.title,
74
+ disabled: thread => !(thread && thread.thread_id)
75
+ });
76
+ const THREAD_RENAME_PROMPT = Object.freeze({
77
+ title: 'Rename thread',
78
+ placeholder: 'Thread name',
79
+ confirmText: 'Rename'
80
+ });
81
+ const THREAD_DELETE_CONFIRM = Object.freeze({
82
+ title: 'Delete thread',
83
+ message: title => `Are you sure you want to delete "${title || 'this thread'}"? This cannot be undone.`,
84
+ confirmText: 'Delete',
85
+ danger: true
86
+ });
60
87
  const SEARCH_BASED_LAYOUTS = Object.assign({}, BASE_LAYOUTS, {
61
88
  [_constants.ROLE.QUERY]: [_constants.LAYOUT_TYPE.SEARCH_BOX],
62
89
  [_constants.ROLE.PRODUCTS]: [_constants.LAYOUT_TYPE.LIST, {
@@ -124,20 +151,90 @@ const defaultLayouts = exports.defaultLayouts = Object.freeze({
124
151
  placeholder: 'Ask a question'
125
152
  }]
126
153
  })),
154
+ // the thread list's own roles plus its thread item subworkflows' — the
155
+ // items share the history workflow's options, so one bag serves both.
156
+ // The item roles: the item-container layout (the standard container
157
+ // duties plus the items' context menus, driven by the item-menu
158
+ // data-role contract — it only ever drives its own item's menu, so
159
+ // hosting it on the panel is inert, and the panel never triggers the
160
+ // auto logo either, having no main-role component), the title text
161
+ // (with a presentation fallback for untitled threads), the context
162
+ // menu's rename (ask-then-submit through the prompt dialog) and delete
163
+ // (confirm-then-submit) buttons, and its subscription toggle — a menu
164
+ // item like the other two, so text only, labeled by the action a click
165
+ // takes rather than by the state
127
166
  'history': Object.freeze(Object.assign({}, BASE_LAYOUTS, {
167
+ [_constants.ROLE.CONTAINER]: [_constants.LAYOUT_TYPE.ITEM_CONTAINER, {
168
+ logo: false
169
+ }],
128
170
  [_constants.ROLE.THREADS]: [_constants.LAYOUT_TYPE.THREADS, {
129
171
  itemType: 'thread',
130
- incremental: true
172
+ incremental: true,
173
+ infiniteScroll: true
131
174
  }],
132
175
  [_constants.ROLE.NEW_THREAD]: [_constants.LAYOUT_TYPE.BUTTON, {
133
176
  icon: 'plus',
134
177
  text: 'New chat'
178
+ }],
179
+ [_constants.ROLE.TITLE]: [_constants.LAYOUT_TYPE.TEXT, {
180
+ tag: 'div',
181
+ templates: {
182
+ content: (layout, {
183
+ value
184
+ }) => (0, _commons.escapeHtml)(value || 'Untitled')
185
+ }
186
+ }],
187
+ [_constants.ROLE.RENAME]: [_constants.LAYOUT_TYPE.BUTTON, Object.assign({}, THREAD_CONTROL_OPTIONS, {
188
+ text: 'Rename',
189
+ prompt: THREAD_RENAME_PROMPT
190
+ })],
191
+ [_constants.ROLE.DELETE]: [_constants.LAYOUT_TYPE.BUTTON, Object.assign({}, THREAD_CONTROL_OPTIONS, {
192
+ text: 'Delete',
193
+ confirm: THREAD_DELETE_CONFIRM
194
+ })],
195
+ [_constants.ROLE.SUBSCRIPTION]: [_constants.LAYOUT_TYPE.CHECKBOX, {
196
+ text: 'Subscribe',
197
+ checkedText: 'Unsubscribe'
135
198
  }]
136
199
  })),
137
- 'conversation': Object.freeze(Object.assign({}, BASE_LAYOUTS, {
200
+ // the conversation panel's own roles plus its message item subworkflows'
201
+ // — the items share the conversation workflow's options, so one bag
202
+ // serves both. The message roles: the answer-based layouts minus the
203
+ // query role (a message has no query flow of its own; the query entry
204
+ // below is the panel's composer), with the question layout (text plus
205
+ // authorship attributes, off the whole record), the answer typewriter
206
+ // with `instant: true` (an answer starts at what is already available: a
207
+ // finished one renders in one shot, an ongoing one types out only the rest),
208
+ // the error notice worded for a message (messageErrorMessage),
209
+ // and the sources as the compact horizontal cards of the hybrid-search
210
+ // UI. logo: false turns the per-message banner off; the panel never
211
+ // triggers the auto logo anyway, having no main-role component
212
+ 'conversation': Object.freeze(Object.assign({}, MESSAGE_LAYOUTS, {
213
+ [_constants.ROLE.CONTAINER]: [_constants.LAYOUT_TYPE.CONTAINER, {
214
+ logo: false
215
+ }],
216
+ [_constants.ROLE.QUESTION]: _constants.LAYOUT_TYPE.QUESTION,
217
+ [_constants.ROLE.ANSWER]: [_constants.LAYOUT_TYPE.TYPEWRITER, {
218
+ instant: true
219
+ }],
220
+ [_constants.ROLE.ERROR]: [_constants.LAYOUT_TYPE.ERROR, {
221
+ templates: {
222
+ message: _templates.messageErrorMessage
223
+ }
224
+ }],
225
+ [_constants.ROLE.SOURCES]: [_constants.LAYOUT_TYPE.HORIZONTAL, {
226
+ incremental: true,
227
+ itemType: 'article',
228
+ templates: {
229
+ ordered: true,
230
+ article: _templates.compactArticle,
231
+ articleInfoBlock: _templates.compactArticleInfoBlock
232
+ }
233
+ }],
138
234
  [_constants.ROLE.MESSAGES]: [_constants.LAYOUT_TYPE.MESSAGES, {
139
235
  itemType: 'message',
140
- incremental: true
236
+ incremental: true,
237
+ infiniteScroll: true
141
238
  }],
142
239
  [_constants.ROLE.QUERY]: [_constants.LAYOUT_TYPE.SEARCH_BOX, {
143
240
  placeholder: 'Ask a follow-up question',
@@ -151,14 +248,14 @@ const defaultLayouts = exports.defaultLayouts = Object.freeze({
151
248
  [_constants.ROLE.TITLE]: [_constants.LAYOUT_TYPE.TEXT, {
152
249
  tag: 'div'
153
250
  }],
154
- [_constants.ROLE.RENAME]: [_constants.LAYOUT_TYPE.BUTTON, {
251
+ [_constants.ROLE.RENAME]: [_constants.LAYOUT_TYPE.BUTTON, Object.assign({}, THREAD_CONTROL_OPTIONS, {
155
252
  icon: 'pencil',
156
- prompt: {
157
- title: 'Rename thread',
158
- placeholder: 'Thread name',
159
- confirmText: 'Rename'
160
- }
161
- }],
253
+ prompt: THREAD_RENAME_PROMPT
254
+ })],
255
+ [_constants.ROLE.DELETE]: [_constants.LAYOUT_TYPE.BUTTON, Object.assign({}, THREAD_CONTROL_OPTIONS, {
256
+ icon: 'trash',
257
+ confirm: THREAD_DELETE_CONFIRM
258
+ })],
162
259
  [_constants.ROLE.SUBSCRIPTION]: [_constants.LAYOUT_TYPE.CHECKBOX, {
163
260
  icon: 'bell',
164
261
  text: 'Subscribe',
@@ -33,6 +33,12 @@ Object.defineProperty(exports, "MisoHybridSearchElement", {
33
33
  return _misoHybridSearch.default;
34
34
  }
35
35
  });
36
+ Object.defineProperty(exports, "MisoMessageItemElement", {
37
+ enumerable: true,
38
+ get: function () {
39
+ return _misoMessageItem.default;
40
+ }
41
+ });
36
42
  Object.defineProperty(exports, "MisoRecommendationElement", {
37
43
  enumerable: true,
38
44
  get: function () {
@@ -45,10 +51,18 @@ Object.defineProperty(exports, "MisoSearchElement", {
45
51
  return _misoSearch.default;
46
52
  }
47
53
  });
54
+ Object.defineProperty(exports, "MisoThreadItemElement", {
55
+ enumerable: true,
56
+ get: function () {
57
+ return _misoThreadItem.default;
58
+ }
59
+ });
48
60
  var _misoAsk = _interopRequireDefault(require("./miso-ask.js"));
49
61
  var _misoExplore = _interopRequireDefault(require("./miso-explore.js"));
50
62
  var _misoHistory = _interopRequireDefault(require("./miso-history.js"));
51
63
  var _misoConversation = _interopRequireDefault(require("./miso-conversation.js"));
64
+ var _misoMessageItem = _interopRequireDefault(require("./miso-message-item.js"));
65
+ var _misoThreadItem = _interopRequireDefault(require("./miso-thread-item.js"));
52
66
  var _misoHybridSearch = _interopRequireDefault(require("./miso-hybrid-search.js"));
53
67
  var _misoSearch = _interopRequireDefault(require("./miso-search.js"));
54
68
  var _misoRecommendation = _interopRequireDefault(require("./miso-recommendation.js"));
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _misoContainer = _interopRequireDefault(require("./miso-container.js"));
8
+ var _utils = require("../utils.js");
9
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
+ const TAG_NAME = 'miso-message-item';
11
+ const ATTR_QUESTION_ID = 'question-id';
12
+ const OBSERVED_ATTRIBUTES = Object.freeze([..._misoContainer.default.observedAttributes, ATTR_QUESTION_ID]);
13
+
14
+ /**
15
+ * A container element for one message (question-answer pair) of the
16
+ * conversation panel, placed inside <miso-conversation> — a container
17
+ * element inside another container element hosting an item subworkflow (the
18
+ * `message` workflow). Normally bound implicitly: the messages layout
19
+ * renders one <miso-message-item> per item and assigns the workflow off the item
20
+ * binding (element.workflow = parent workflow's _getMessageWorkflow(record)),
21
+ * which also covers a just-posted message that has no question id yet. A
22
+ * `question-id` attribute binds explicitly instead, through the parent
23
+ * container's workflow. Role elements inside (question, answer, sources,
24
+ * ...) bind to the message workflow as usual — getContainer() resolves to
25
+ * the closest container ancestor.
26
+ */
27
+ class MisoMessageItemElement extends _misoContainer.default {
28
+ static get tagName() {
29
+ return TAG_NAME;
30
+ }
31
+ static get observedAttributes() {
32
+ return OBSERVED_ATTRIBUTES;
33
+ }
34
+
35
+ // properties //
36
+ get questionId() {
37
+ return this.getAttribute(ATTR_QUESTION_ID) || undefined;
38
+ }
39
+ set questionId(value) {
40
+ value = value !== undefined ? `${value}` : undefined;
41
+ if (value === this.questionId) {
42
+ return;
43
+ }
44
+ if (value) {
45
+ this.setAttribute(ATTR_QUESTION_ID, value);
46
+ } else {
47
+ this.removeAttribute(ATTR_QUESTION_ID);
48
+ }
49
+ }
50
+ _getWorkflow(client) {
51
+ const {
52
+ questionId
53
+ } = this;
54
+ if (!questionId) {
55
+ // implicitly bound: the messages layout assigns element.workflow off
56
+ // the item binding — keep whatever is (or will be) assigned
57
+ return this._workflow;
58
+ }
59
+ const container = this._getParentContainer();
60
+ const workflow = container && container.workflow;
61
+ // the parent workflow hands out the item subworkflow; the parent binds
62
+ // its own workflow first (its connectedCallback resolves earlier), so
63
+ // it is normally present by now
64
+ return workflow && typeof workflow._getMessageWorkflow === 'function' ? workflow._getMessageWorkflow(questionId) : undefined;
65
+ }
66
+ _getParentContainer() {
67
+ try {
68
+ return this.parentNode ? (0, _utils.getContainer)(this.parentNode) : undefined;
69
+ } catch (_) {
70
+ return undefined; // not inside a container element
71
+ }
72
+ }
73
+ attributeChangedCallback(attr, oldValue, newValue) {
74
+ switch (attr) {
75
+ case ATTR_QUESTION_ID:
76
+ this._handleQuestionIdUpdate(oldValue, newValue);
77
+ break;
78
+ default:
79
+ super.attributeChangedCallback(attr, oldValue, newValue);
80
+ }
81
+ }
82
+ _handleQuestionIdUpdate(oldValue, newValue) {
83
+ oldValue = oldValue || undefined; // null -> undefined
84
+ newValue = newValue || undefined;
85
+ if (oldValue === newValue || !this._client) {
86
+ return;
87
+ }
88
+ this._setWorkflow(this._getWorkflow(this._client));
89
+ }
90
+ }
91
+ exports.default = MisoMessageItemElement;
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _misoContainer = _interopRequireDefault(require("./miso-container.js"));
8
+ var _utils = require("../utils.js");
9
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
+ const TAG_NAME = 'miso-thread-item';
11
+ const ATTR_THREAD_ID = 'thread-id';
12
+ const OBSERVED_ATTRIBUTES = Object.freeze([..._misoContainer.default.observedAttributes, ATTR_THREAD_ID]);
13
+
14
+ /**
15
+ * A container element for one thread item of the thread list, placed inside
16
+ * <miso-history> — a container element inside another container element
17
+ * hosting an item subworkflow (the `thread` workflow). Normally bound
18
+ * implicitly: the threads layout renders one <miso-thread-item> per item and
19
+ * assigns the workflow off the item binding (element.workflow = parent
20
+ * workflow's _getThreadWorkflow(record)), which also covers a thread being
21
+ * created that has no thread id yet. A `thread-id` attribute binds
22
+ * explicitly instead, through the parent container's workflow. Role
23
+ * elements inside (title, rename, delete, subscription) bind to the thread
24
+ * workflow as usual — getContainer() resolves to the closest container
25
+ * ancestor.
26
+ */
27
+ class MisoThreadItemElement extends _misoContainer.default {
28
+ static get tagName() {
29
+ return TAG_NAME;
30
+ }
31
+ static get observedAttributes() {
32
+ return OBSERVED_ATTRIBUTES;
33
+ }
34
+
35
+ // properties //
36
+ get threadId() {
37
+ return this.getAttribute(ATTR_THREAD_ID) || undefined;
38
+ }
39
+ set threadId(value) {
40
+ value = value !== undefined ? `${value}` : undefined;
41
+ if (value === this.threadId) {
42
+ return;
43
+ }
44
+ if (value) {
45
+ this.setAttribute(ATTR_THREAD_ID, value);
46
+ } else {
47
+ this.removeAttribute(ATTR_THREAD_ID);
48
+ }
49
+ }
50
+ _getWorkflow(client) {
51
+ const {
52
+ threadId
53
+ } = this;
54
+ if (!threadId) {
55
+ // implicitly bound: the threads layout assigns element.workflow off
56
+ // the item binding — keep whatever is (or will be) assigned
57
+ return this._workflow;
58
+ }
59
+ const container = this._getParentContainer();
60
+ const workflow = container && container.workflow;
61
+ // the parent workflow hands out the item subworkflow; the parent binds
62
+ // its own workflow first (its connectedCallback resolves earlier), so
63
+ // it is normally present by now
64
+ return workflow && typeof workflow._getThreadWorkflow === 'function' ? workflow._getThreadWorkflow(threadId) : undefined;
65
+ }
66
+ _getParentContainer() {
67
+ try {
68
+ return this.parentNode ? (0, _utils.getContainer)(this.parentNode) : undefined;
69
+ } catch (_) {
70
+ return undefined; // not inside a container element
71
+ }
72
+ }
73
+ attributeChangedCallback(attr, oldValue, newValue) {
74
+ switch (attr) {
75
+ case ATTR_THREAD_ID:
76
+ this._handleThreadIdUpdate(oldValue, newValue);
77
+ break;
78
+ default:
79
+ super.attributeChangedCallback(attr, oldValue, newValue);
80
+ }
81
+ }
82
+ _handleThreadIdUpdate(oldValue, newValue) {
83
+ oldValue = oldValue || undefined; // null -> undefined
84
+ newValue = newValue || undefined;
85
+ if (oldValue === newValue || !this._client) {
86
+ return;
87
+ }
88
+ this._setWorkflow(this._getWorkflow(this._client));
89
+ }
90
+ }
91
+ exports.default = MisoThreadItemElement;
@@ -30,4 +30,5 @@ Object.keys(_index5).forEach(function (key) {
30
30
  }
31
31
  });
32
32
  });
33
- function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
33
+ var cache;
34
+ function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var r, c, a = Object.defineProperty, n = { __proto__: null, default: e }; if (Object(e) !== e) return n; if (cache || "function" != typeof WeakMap || (cache = new WeakMap()), cache) { if (cache.has(e)) return cache.get(e); cache.set(e, n); } for (c in e) "default" !== c && {}.hasOwnProperty.call(e, c) && ((r = a && Object.getOwnPropertyDescriptor(e, c)) && (r.get || r.set) ? a(n, c, r) : n[c] = e[c]); return n; }
@@ -21,6 +21,12 @@ Object.defineProperty(exports, "MisoComponentElement", {
21
21
  return _misoComponent.default;
22
22
  }
23
23
  });
24
+ Object.defineProperty(exports, "MisoDeleteElement", {
25
+ enumerable: true,
26
+ get: function () {
27
+ return _misoDelete.default;
28
+ }
29
+ });
24
30
  Object.defineProperty(exports, "MisoErrorElement", {
25
31
  enumerable: true,
26
32
  get: function () {
@@ -189,6 +195,7 @@ var _misoThreads = _interopRequireDefault(require("./miso-threads.js"));
189
195
  var _misoNewThread = _interopRequireDefault(require("./miso-new-thread.js"));
190
196
  var _misoTitle = _interopRequireDefault(require("./miso-title.js"));
191
197
  var _misoRename = _interopRequireDefault(require("./miso-rename.js"));
198
+ var _misoDelete = _interopRequireDefault(require("./miso-delete.js"));
192
199
  var _misoSubscription = _interopRequireDefault(require("./miso-subscription.js"));
193
200
  var _misoMessages = _interopRequireDefault(require("./miso-messages.js"));
194
201
  var _misoError = _interopRequireDefault(require("./miso-error.js"));
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _misoComponent = _interopRequireDefault(require("./miso-component.js"));
8
+ var _constants = require("../../constants.js");
9
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
+ class MisoDeleteElement extends _misoComponent.default {
11
+ constructor() {
12
+ super({
13
+ role: _constants.ROLE.DELETE
14
+ });
15
+ }
16
+ static get tagName() {
17
+ return 'miso-delete';
18
+ }
19
+ }
20
+ exports.default = MisoDeleteElement;
@@ -9,7 +9,9 @@ var _constants = require("../../constants.js");
9
9
  var _template = _interopRequireDefault(require("../template.js"));
10
10
  var _svgs = require("../../asset/svgs.js");
11
11
  var _prompt = _interopRequireDefault(require("../../util/prompt.js"));
12
- const _excluded = ["className", "templates"];
12
+ var _confirm = _interopRequireDefault(require("../../util/confirm.js"));
13
+ const _excluded = ["className", "templates"],
14
+ _excluded2 = ["message"];
13
15
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
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; }
15
17
  const TYPE = _constants.LAYOUT_TYPE.BUTTON;
@@ -21,7 +23,8 @@ function root(layout, state) {
21
23
  templates
22
24
  } = layout;
23
25
  const roleAttr = role ? ` data-role="${role}"` : '';
24
- return `<button type="button" class="${className}"${roleAttr}>${templates.icon(layout, state)}${templates.text(layout, state)}</button>`;
26
+ const disabledAttr = layout._isDisabled(state) ? ' disabled' : '';
27
+ return `<button type="button" class="${className}"${roleAttr}${disabledAttr}>${templates.icon(layout, state)}${templates.text(layout, state)}</button>`;
25
28
  }
26
29
  function icon(layout) {
27
30
  const {
@@ -60,6 +63,19 @@ const DEFAULT_TEMPLATES = Object.freeze({
60
63
  * dialog submits nothing. Use it for actions that take a text input, such
61
64
  * as the rename button (role `rename`) of the conversation header, whose
62
65
  * role maps to `'thread.title'`.
66
+ *
67
+ * With a `confirm` option, the click asks through the shared confirm dialog
68
+ * first, and submits only when confirmed; the option's `message` may be a
69
+ * function of the control's current value. Use it for destructive actions,
70
+ * such as the delete button (role `delete`) of a thread item's context menu.
71
+ *
72
+ * The control's current value is the role's mapped data value, put through
73
+ * the `value` option when given — map the role to a record and let `value`
74
+ * pick the text the dialogs work with. A `disabled` option (a boolean, or a
75
+ * function of the mapped value) renders the button's disabled state from
76
+ * the data, re-evaluated on every commit — e.g. rename/delete disable while
77
+ * their thread record has no thread id yet (a thread being created is not
78
+ * addressable), enabling in place when the resolution patches the record.
63
79
  */
64
80
  class ButtonLayout extends _template.default {
65
81
  static get type() {
@@ -94,7 +110,7 @@ class ButtonLayout extends _template.default {
94
110
  if (!button || button.disabled) {
95
111
  return;
96
112
  }
97
- this.options.prompt ? this._submitViaPrompt(event) : this._submit(event);
113
+ this.options.prompt ? this._submitViaPrompt(event) : this.options.confirm ? this._submitViaConfirm(event) : this._submit(event);
98
114
  }
99
115
  _submit(event, payload) {
100
116
  const {
@@ -117,14 +133,38 @@ class ButtonLayout extends _template.default {
117
133
  value
118
134
  });
119
135
  }
136
+ async _submitViaConfirm(event) {
137
+ const _this$options$confirm = this.options.confirm,
138
+ {
139
+ message
140
+ } = _this$options$confirm,
141
+ options = _objectWithoutPropertiesLoose(_this$options$confirm, _excluded2);
142
+ const confirmed = await (0, _confirm.default)(Object.assign({}, options, {
143
+ message: typeof message === 'function' ? message(this._currentValue()) : message
144
+ }));
145
+ if (!confirmed) {
146
+ return;
147
+ }
148
+ this._submit(event);
149
+ }
120
150
 
121
151
  /**
122
152
  * The current value of the control: the role's mapped data value, as of
123
- * the latest render.
153
+ * the latest render, put through the `value` option when given.
124
154
  */
125
155
  _currentValue() {
126
156
  const state = this._element && this._rendered.get(this._element);
127
- return state && state.value;
157
+ const raw = state && state.value;
158
+ const {
159
+ value
160
+ } = this.options;
161
+ return typeof value === 'function' ? value(raw) : raw;
162
+ }
163
+ _isDisabled(state) {
164
+ const {
165
+ disabled
166
+ } = this.options;
167
+ return typeof disabled === 'function' ? !!disabled(state && state.value) : !!disabled;
128
168
  }
129
169
  }
130
170
  exports.default = ButtonLayout;
@@ -22,7 +22,8 @@ function root(layout, state) {
22
22
  const checked = isChecked(state);
23
23
  const roleAttr = role ? ` data-role="${role}"` : '';
24
24
  const checkedAttr = checked ? ' data-checked' : '';
25
- return `<button type="button" class="${className}" role="switch" aria-checked="${checked}"${roleAttr}${checkedAttr}>${templates.icon(layout, state)}${templates.text(layout, state)}</button>`;
25
+ const disabledAttr = layout._isDisabled(state) ? ' disabled' : '';
26
+ return `<button type="button" class="${className}" role="switch" aria-checked="${checked}"${roleAttr}${checkedAttr}${disabledAttr}>${templates.icon(layout, state)}${templates.text(layout, state)}</button>`;
26
27
  }
27
28
  function icon(layout, state) {
28
29
  const {