@miso.ai/client-sdk-ui 1.13.2-beta.1 → 1.14.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. package/dist/cjs/asset/svgs.js +17 -4
  2. package/dist/cjs/combo/ask/index.js +2 -2
  3. package/dist/cjs/constants.js +120 -98
  4. package/dist/cjs/defaults/ask/controls.js +1 -1
  5. package/dist/cjs/defaults/hybrid-search/answer-box.js +4 -4
  6. package/dist/cjs/defaults.js +259 -0
  7. package/dist/cjs/element/container/index.js +28 -0
  8. package/dist/cjs/element/container/miso-ask.js +3 -3
  9. package/dist/cjs/element/container/miso-conversation.js +21 -0
  10. package/dist/cjs/element/container/miso-explore.js +1 -1
  11. package/dist/cjs/element/container/miso-history.js +21 -0
  12. package/dist/cjs/element/container/miso-hybrid-search.js +1 -1
  13. package/dist/cjs/element/container/miso-message-item.js +91 -0
  14. package/dist/cjs/element/container/miso-recommendation.js +1 -1
  15. package/dist/cjs/element/container/miso-search.js +1 -1
  16. package/dist/cjs/element/container/miso-thread-item.js +91 -0
  17. package/dist/cjs/element/context/miso-follow-ups.js +1 -1
  18. package/dist/cjs/element/role/index.js +49 -0
  19. package/dist/cjs/element/role/miso-delete.js +20 -0
  20. package/dist/cjs/element/role/miso-messages.js +20 -0
  21. package/dist/cjs/element/role/miso-new-thread.js +20 -0
  22. package/dist/cjs/element/role/miso-rename.js +20 -0
  23. package/dist/cjs/element/role/miso-subscription.js +20 -0
  24. package/dist/cjs/element/role/miso-threads.js +20 -0
  25. package/dist/cjs/element/role/miso-title.js +20 -0
  26. package/dist/cjs/layout/affiliation/affiliation.js +1 -1
  27. package/dist/cjs/layout/banner/banner.js +2 -1
  28. package/dist/cjs/layout/button/button.js +170 -0
  29. package/dist/cjs/layout/button/checkbox.js +116 -0
  30. package/dist/cjs/layout/button/more-button.js +3 -3
  31. package/dist/cjs/layout/container/container.js +1 -1
  32. package/dist/cjs/layout/container/item-container.js +99 -0
  33. package/dist/cjs/layout/error/error.js +2 -1
  34. package/dist/cjs/layout/index.js +42 -0
  35. package/dist/cjs/layout/input/facets.js +4 -3
  36. package/dist/cjs/layout/input/option-list.js +3 -2
  37. package/dist/cjs/layout/input/search-box.js +50 -12
  38. package/dist/cjs/layout/input/select.js +2 -1
  39. package/dist/cjs/layout/list/cards.js +2 -1
  40. package/dist/cjs/layout/list/carousel.js +2 -1
  41. package/dist/cjs/layout/list/collection.js +13 -1
  42. package/dist/cjs/layout/list/gallery.js +2 -1
  43. package/dist/cjs/layout/list/horizontal.js +2 -1
  44. package/dist/cjs/layout/list/list.js +2 -1
  45. package/dist/cjs/layout/list/messages.js +359 -0
  46. package/dist/cjs/layout/list/threads.js +199 -0
  47. package/dist/cjs/layout/mixin/trackable.js +4 -5
  48. package/dist/cjs/layout/mixin/triggerable.js +2 -2
  49. package/dist/cjs/layout/radio/feedback.js +4 -3
  50. package/dist/cjs/layout/templates.js +97 -0
  51. package/dist/cjs/layout/text/question.js +71 -0
  52. package/dist/cjs/layout/text/text.js +2 -1
  53. package/dist/cjs/layout/text/typewriter/index.js +18 -23
  54. package/dist/cjs/plugin.js +43 -104
  55. package/dist/cjs/util/confirm.js +33 -0
  56. package/dist/cjs/util/dom.js +21 -0
  57. package/dist/cjs/util/modal.js +48 -0
  58. package/dist/cjs/util/prompt.js +47 -0
  59. package/dist/cjs/version.js +1 -1
  60. package/package.json +5 -4
  61. package/src/CLAUDE.md +51 -104
  62. package/src/asset/svgs.js +16 -3
  63. package/src/combo/ask/index.js +2 -2
  64. package/src/constants.js +39 -147
  65. package/src/defaults/ask/controls.js +1 -1
  66. package/src/defaults/hybrid-search/answer-box.js +2 -2
  67. package/src/defaults.js +174 -0
  68. package/src/element/container/index.js +4 -0
  69. package/src/element/container/miso-ask.js +3 -3
  70. package/src/element/container/miso-conversation.js +19 -0
  71. package/src/element/container/miso-explore.js +1 -1
  72. package/src/element/container/miso-history.js +19 -0
  73. package/src/element/container/miso-hybrid-search.js +1 -1
  74. package/src/element/container/miso-message-item.js +94 -0
  75. package/src/element/container/miso-recommendation.js +1 -1
  76. package/src/element/container/miso-search.js +1 -1
  77. package/src/element/container/miso-thread-item.js +94 -0
  78. package/src/element/context/miso-follow-ups.js +1 -1
  79. package/src/element/role/index.js +7 -0
  80. package/src/element/role/miso-delete.js +16 -0
  81. package/src/element/role/miso-messages.js +16 -0
  82. package/src/element/role/miso-new-thread.js +16 -0
  83. package/src/element/role/miso-rename.js +16 -0
  84. package/src/element/role/miso-subscription.js +16 -0
  85. package/src/element/role/miso-threads.js +16 -0
  86. package/src/element/role/miso-title.js +16 -0
  87. package/src/layout/affiliation/affiliation.js +2 -2
  88. package/src/layout/banner/banner.js +2 -1
  89. package/src/layout/button/button.js +152 -0
  90. package/src/layout/button/checkbox.js +92 -0
  91. package/src/layout/button/more-button.js +3 -3
  92. package/src/layout/container/container.js +2 -2
  93. package/src/layout/container/item-container.js +99 -0
  94. package/src/layout/error/error.js +2 -1
  95. package/src/layout/index.js +6 -0
  96. package/src/layout/input/facets.js +3 -2
  97. package/src/layout/input/option-list.js +3 -2
  98. package/src/layout/input/search-box.js +45 -8
  99. package/src/layout/input/select.js +2 -1
  100. package/src/layout/list/cards.js +2 -1
  101. package/src/layout/list/carousel.js +2 -1
  102. package/src/layout/list/collection.js +15 -2
  103. package/src/layout/list/gallery.js +2 -1
  104. package/src/layout/list/horizontal.js +2 -1
  105. package/src/layout/list/list.js +2 -1
  106. package/src/layout/list/messages.js +316 -0
  107. package/src/layout/list/threads.js +166 -0
  108. package/src/layout/mixin/trackable.js +2 -3
  109. package/src/layout/mixin/triggerable.js +1 -1
  110. package/src/layout/radio/feedback.js +3 -2
  111. package/src/layout/templates.js +97 -0
  112. package/src/layout/text/question.js +58 -0
  113. package/src/layout/text/text.js +2 -1
  114. package/src/layout/text/typewriter/index.js +15 -18
  115. package/src/plugin.js +31 -117
  116. package/src/util/confirm.js +28 -0
  117. package/src/util/dom.js +16 -0
  118. package/src/util/modal.js +49 -0
  119. package/src/util/prompt.js +42 -0
  120. package/src/version.js +1 -1
  121. package/dist/cjs/actor/data.js +0 -132
  122. package/dist/cjs/actor/feedback.js +0 -29
  123. package/dist/cjs/actor/fields.js +0 -57
  124. package/dist/cjs/actor/filters.js +0 -161
  125. package/dist/cjs/actor/hub.js +0 -57
  126. package/dist/cjs/actor/index.js +0 -73
  127. package/dist/cjs/actor/interactions.js +0 -36
  128. package/dist/cjs/actor/sessions.js +0 -25
  129. package/dist/cjs/actor/tracker-states.js +0 -61
  130. package/dist/cjs/actor/tracker.js +0 -109
  131. package/dist/cjs/actor/trackers.js +0 -52
  132. package/dist/cjs/actor/utils.js +0 -15
  133. package/dist/cjs/actor/view.js +0 -294
  134. package/dist/cjs/actor/views.js +0 -209
  135. package/dist/cjs/source.js +0 -27
  136. package/dist/cjs/util/proxy.js +0 -88
  137. package/dist/cjs/util/trackers.js +0 -88
  138. package/dist/cjs/workflow/affiliations.js +0 -140
  139. package/dist/cjs/workflow/answer-based.js +0 -337
  140. package/dist/cjs/workflow/ask.js +0 -319
  141. package/dist/cjs/workflow/asks.js +0 -150
  142. package/dist/cjs/workflow/autocompletable.js +0 -63
  143. package/dist/cjs/workflow/autocomplete.js +0 -120
  144. package/dist/cjs/workflow/base.js +0 -418
  145. package/dist/cjs/workflow/context.js +0 -19
  146. package/dist/cjs/workflow/explore.js +0 -210
  147. package/dist/cjs/workflow/explores.js +0 -21
  148. package/dist/cjs/workflow/hybrid-search-answer.js +0 -88
  149. package/dist/cjs/workflow/hybrid-search-views.js +0 -109
  150. package/dist/cjs/workflow/hybrid-search.js +0 -213
  151. package/dist/cjs/workflow/index.js +0 -41
  152. package/dist/cjs/workflow/options/api.js +0 -41
  153. package/dist/cjs/workflow/options/auto-query.js +0 -97
  154. package/dist/cjs/workflow/options/configurable.js +0 -45
  155. package/dist/cjs/workflow/options/data-processor.js +0 -20
  156. package/dist/cjs/workflow/options/filters.js +0 -15
  157. package/dist/cjs/workflow/options/index.js +0 -126
  158. package/dist/cjs/workflow/options/interactions.js +0 -41
  159. package/dist/cjs/workflow/options/layouts.js +0 -79
  160. package/dist/cjs/workflow/options/options.js +0 -156
  161. package/dist/cjs/workflow/options/pagination.js +0 -25
  162. package/dist/cjs/workflow/options/roles.js +0 -15
  163. package/dist/cjs/workflow/options/templates.js +0 -30
  164. package/dist/cjs/workflow/options/trackers.js +0 -83
  165. package/dist/cjs/workflow/options/utils.js +0 -33
  166. package/dist/cjs/workflow/processors.js +0 -607
  167. package/dist/cjs/workflow/recommendation.js +0 -57
  168. package/dist/cjs/workflow/recommendations.js +0 -18
  169. package/dist/cjs/workflow/search-based.js +0 -337
  170. package/dist/cjs/workflow/search.js +0 -64
  171. package/dist/cjs/workflow/unit.js +0 -57
  172. package/dist/cjs/workflow/units.js +0 -42
  173. package/dist/cjs/workflow/use-link.js +0 -49
  174. package/src/actor/data.js +0 -106
  175. package/src/actor/feedback.js +0 -28
  176. package/src/actor/fields.js +0 -51
  177. package/src/actor/filters.js +0 -149
  178. package/src/actor/hub.js +0 -47
  179. package/src/actor/index.js +0 -10
  180. package/src/actor/interactions.js +0 -32
  181. package/src/actor/sessions.js +0 -21
  182. package/src/actor/tracker-states.js +0 -57
  183. package/src/actor/tracker.js +0 -104
  184. package/src/actor/trackers.js +0 -45
  185. package/src/actor/utils.js +0 -7
  186. package/src/actor/view.js +0 -272
  187. package/src/actor/views.js +0 -224
  188. package/src/source.js +0 -17
  189. package/src/util/proxy.js +0 -81
  190. package/src/util/trackers.js +0 -84
  191. package/src/workflow/affiliations.js +0 -121
  192. package/src/workflow/answer-based.js +0 -312
  193. package/src/workflow/ask.js +0 -284
  194. package/src/workflow/asks.js +0 -143
  195. package/src/workflow/autocompletable.js +0 -67
  196. package/src/workflow/autocomplete.js +0 -114
  197. package/src/workflow/base.js +0 -396
  198. package/src/workflow/context.js +0 -16
  199. package/src/workflow/explore.js +0 -194
  200. package/src/workflow/explores.js +0 -18
  201. package/src/workflow/hybrid-search-answer.js +0 -73
  202. package/src/workflow/hybrid-search-views.js +0 -116
  203. package/src/workflow/hybrid-search.js +0 -230
  204. package/src/workflow/index.js +0 -5
  205. package/src/workflow/options/api.js +0 -31
  206. package/src/workflow/options/auto-query.js +0 -70
  207. package/src/workflow/options/configurable.js +0 -48
  208. package/src/workflow/options/data-processor.js +0 -15
  209. package/src/workflow/options/filters.js +0 -10
  210. package/src/workflow/options/index.js +0 -11
  211. package/src/workflow/options/interactions.js +0 -36
  212. package/src/workflow/options/layouts.js +0 -73
  213. package/src/workflow/options/options.js +0 -175
  214. package/src/workflow/options/pagination.js +0 -18
  215. package/src/workflow/options/roles.js +0 -12
  216. package/src/workflow/options/templates.js +0 -27
  217. package/src/workflow/options/trackers.js +0 -80
  218. package/src/workflow/options/utils.js +0 -26
  219. package/src/workflow/processors.js +0 -490
  220. package/src/workflow/recommendation.js +0 -63
  221. package/src/workflow/recommendations.js +0 -14
  222. package/src/workflow/search-based.js +0 -329
  223. package/src/workflow/search.js +0 -73
  224. package/src/workflow/unit.js +0 -51
  225. package/src/workflow/units.js +0 -43
  226. package/src/workflow/use-link.js +0 -41
@@ -0,0 +1,94 @@
1
+ import MisoContainerElement from './miso-container.js';
2
+ import { getContainer } from '../utils.js';
3
+
4
+ const TAG_NAME = 'miso-thread-item';
5
+
6
+ const ATTR_THREAD_ID = 'thread-id';
7
+ const OBSERVED_ATTRIBUTES = Object.freeze([
8
+ ...MisoContainerElement.observedAttributes,
9
+ ATTR_THREAD_ID,
10
+ ]);
11
+
12
+ /**
13
+ * A container element for one thread item of the thread list, placed inside
14
+ * <miso-history> — a container element inside another container element
15
+ * hosting an item subworkflow (the `thread` workflow). Normally bound
16
+ * implicitly: the threads layout renders one <miso-thread-item> per item and
17
+ * assigns the workflow off the item binding (element.workflow = parent
18
+ * workflow's _getThreadWorkflow(record)), which also covers a thread being
19
+ * created that has no thread id yet. A `thread-id` attribute binds
20
+ * explicitly instead, through the parent container's workflow. Role
21
+ * elements inside (title, rename, delete, subscription) bind to the thread
22
+ * workflow as usual — getContainer() resolves to the closest container
23
+ * ancestor.
24
+ */
25
+ export default class MisoThreadItemElement extends MisoContainerElement {
26
+
27
+ static get tagName() {
28
+ return TAG_NAME;
29
+ }
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
+
40
+ set threadId(value) {
41
+ value = value !== undefined ? `${value}` : undefined;
42
+ if (value === this.threadId) {
43
+ return;
44
+ }
45
+ if (value) {
46
+ this.setAttribute(ATTR_THREAD_ID, value);
47
+ } else {
48
+ this.removeAttribute(ATTR_THREAD_ID);
49
+ }
50
+ }
51
+
52
+ _getWorkflow(client) {
53
+ const { threadId } = 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
+
67
+ _getParentContainer() {
68
+ try {
69
+ return this.parentNode ? getContainer(this.parentNode) : undefined;
70
+ } catch (_) {
71
+ return undefined; // not inside a container element
72
+ }
73
+ }
74
+
75
+ attributeChangedCallback(attr, oldValue, newValue) {
76
+ switch (attr) {
77
+ case ATTR_THREAD_ID:
78
+ this._handleThreadIdUpdate(oldValue, newValue);
79
+ break;
80
+ default:
81
+ super.attributeChangedCallback(attr, oldValue, newValue);
82
+ }
83
+ }
84
+
85
+ _handleThreadIdUpdate(oldValue, newValue) {
86
+ oldValue = oldValue || undefined; // null -> undefined
87
+ newValue = newValue || undefined;
88
+ if (oldValue === newValue || !this._client) {
89
+ return;
90
+ }
91
+ this._setWorkflow(this._getWorkflow(this._client));
92
+ }
93
+
94
+ }
@@ -19,7 +19,7 @@ export default class MisoFollowUpsElement extends MisoContextElement {
19
19
  }
20
20
 
21
21
  _getContext(client) {
22
- return client.ui.asks;
22
+ return client.workflows.asks;
23
23
  }
24
24
 
25
25
  _onContext(context, oldContext) {
@@ -18,4 +18,11 @@ export { default as MisoTotalElement } from './miso-total.js';
18
18
  export { default as MisoFacetsElement } from './miso-facets.js';
19
19
  export { default as MisoMoreElement } from './miso-more.js';
20
20
  export { default as MisoSortElement } from './miso-sort.js';
21
+ export { default as MisoThreadsElement } from './miso-threads.js';
22
+ export { default as MisoNewThreadElement } from './miso-new-thread.js';
23
+ export { default as MisoTitleElement } from './miso-title.js';
24
+ export { default as MisoRenameElement } from './miso-rename.js';
25
+ export { default as MisoDeleteElement } from './miso-delete.js';
26
+ export { default as MisoSubscriptionElement } from './miso-subscription.js';
27
+ export { default as MisoMessagesElement } from './miso-messages.js';
21
28
  export { default as MisoErrorElement } from './miso-error.js';
@@ -0,0 +1,16 @@
1
+ import MisoComponentElement from './miso-component.js';
2
+ import { ROLE } from '../../constants.js';
3
+
4
+ export default class MisoDeleteElement extends MisoComponentElement {
5
+
6
+ constructor() {
7
+ super({
8
+ role: ROLE.DELETE,
9
+ });
10
+ }
11
+
12
+ static get tagName() {
13
+ return 'miso-delete';
14
+ }
15
+
16
+ }
@@ -0,0 +1,16 @@
1
+ import MisoComponentElement from './miso-component.js';
2
+ import { ROLE } from '../../constants.js';
3
+
4
+ export default class MisoMessagesElement extends MisoComponentElement {
5
+
6
+ constructor() {
7
+ super({
8
+ role: ROLE.MESSAGES,
9
+ });
10
+ }
11
+
12
+ static get tagName() {
13
+ return 'miso-messages';
14
+ }
15
+
16
+ }
@@ -0,0 +1,16 @@
1
+ import MisoComponentElement from './miso-component.js';
2
+ import { ROLE } from '../../constants.js';
3
+
4
+ export default class MisoNewThreadElement extends MisoComponentElement {
5
+
6
+ constructor() {
7
+ super({
8
+ role: ROLE.NEW_THREAD,
9
+ });
10
+ }
11
+
12
+ static get tagName() {
13
+ return 'miso-new-thread';
14
+ }
15
+
16
+ }
@@ -0,0 +1,16 @@
1
+ import MisoComponentElement from './miso-component.js';
2
+ import { ROLE } from '../../constants.js';
3
+
4
+ export default class MisoRenameElement extends MisoComponentElement {
5
+
6
+ constructor() {
7
+ super({
8
+ role: ROLE.RENAME,
9
+ });
10
+ }
11
+
12
+ static get tagName() {
13
+ return 'miso-rename';
14
+ }
15
+
16
+ }
@@ -0,0 +1,16 @@
1
+ import MisoComponentElement from './miso-component.js';
2
+ import { ROLE } from '../../constants.js';
3
+
4
+ export default class MisoSubscriptionElement extends MisoComponentElement {
5
+
6
+ constructor() {
7
+ super({
8
+ role: ROLE.SUBSCRIPTION,
9
+ });
10
+ }
11
+
12
+ static get tagName() {
13
+ return 'miso-subscription';
14
+ }
15
+
16
+ }
@@ -0,0 +1,16 @@
1
+ import MisoComponentElement from './miso-component.js';
2
+ import { ROLE } from '../../constants.js';
3
+
4
+ export default class MisoThreadsElement extends MisoComponentElement {
5
+
6
+ constructor() {
7
+ super({
8
+ role: ROLE.THREADS,
9
+ });
10
+ }
11
+
12
+ static get tagName() {
13
+ return 'miso-threads';
14
+ }
15
+
16
+ }
@@ -0,0 +1,16 @@
1
+ import MisoComponentElement from './miso-component.js';
2
+ import { ROLE } from '../../constants.js';
3
+
4
+ export default class MisoTitleElement extends MisoComponentElement {
5
+
6
+ constructor() {
7
+ super({
8
+ role: ROLE.TITLE,
9
+ });
10
+ }
11
+
12
+ static get tagName() {
13
+ return 'miso-title';
14
+ }
15
+
16
+ }
@@ -1,11 +1,11 @@
1
1
  import { CarouselItemViewabilityObserver, requestAnimationFrame as raf } from '@miso.ai/commons';
2
- import { STATUS } from '../../constants.js';
2
+ import { STATUS, LAYOUT_TYPE } from '../../constants.js';
3
3
  import CollectionLayout from '../list/collection.js';
4
4
  import { affiliation, helpers } from '../templates.js';
5
5
  import { TRIANGLE } from '../../asset/svgs.js';
6
6
  import { setOrRemoveAttribute } from '../../util/dom.js';
7
7
 
8
- const TYPE = 'affiliation';
8
+ const TYPE = LAYOUT_TYPE.AFFILIATION;
9
9
  const DEFAULT_CLASSNAME = 'miso-affiliation';
10
10
 
11
11
  function root(layout, state) {
@@ -1,7 +1,8 @@
1
+ import { LAYOUT_TYPE } from '../../constants.js';
1
2
  import TemplateBasedLayout from '../template.js';
2
3
  import { LOGO } from '../svgs.js';
3
4
 
4
- const TYPE = 'banner';
5
+ const TYPE = LAYOUT_TYPE.BANNER;
5
6
  const DEFAULT_CLASSNAME = 'miso-banner';
6
7
 
7
8
  function root(layout) {
@@ -0,0 +1,152 @@
1
+ import { escapeHtml } from '@miso.ai/commons';
2
+ import { LAYOUT_TYPE } from '../../constants.js';
3
+ import TemplateBasedLayout from '../template.js';
4
+ import { getIcon } from '../../asset/svgs.js';
5
+ import prompt from '../../util/prompt.js';
6
+ import confirm from '../../util/confirm.js';
7
+
8
+ const TYPE = LAYOUT_TYPE.BUTTON;
9
+ const DEFAULT_CLASSNAME = 'miso-button';
10
+
11
+ function root(layout, state) {
12
+ const { className, role, templates } = layout;
13
+ const roleAttr = role ? ` data-role="${role}"` : '';
14
+ const disabledAttr = layout._isDisabled(state) ? ' disabled' : '';
15
+ return `<button type="button" class="${className}"${roleAttr}${disabledAttr}>${templates.icon(layout, state)}${templates.text(layout, state)}</button>`;
16
+ }
17
+
18
+ function icon(layout) {
19
+ const { icon } = layout.options;
20
+ return icon ? getIcon(icon) : '';
21
+ }
22
+
23
+ function text(layout) {
24
+ const { className, options: { text } } = layout;
25
+ return text ? `<span class="${className}__text">${escapeHtml(text)}</span>` : '';
26
+ }
27
+
28
+ const DEFAULT_TEMPLATES = Object.freeze({
29
+ root,
30
+ icon,
31
+ text,
32
+ });
33
+
34
+ /**
35
+ * A generic button: an icon and a label, both configurable (`icon` is an icon
36
+ * name, `text` the label; either can be omitted), emitting a `submit` view
37
+ * event when clicked — for the workflow to act on, per role.
38
+ *
39
+ * It carries no data of its own, so it renders in any state; use it for
40
+ * actions that stand apart from the data they act on, such as the new chat
41
+ * button (role `new_thread`) of the chat history interface.
42
+ *
43
+ * With a `prompt` option, the click asks for a text through the shared
44
+ * prompt dialog first, pre-filled with the control's current value — the
45
+ * role's mapped data value, as of the latest render — and the submit event
46
+ * carries the confirmed text as `value`; a cancelled, cleared, or unchanged
47
+ * dialog submits nothing. Use it for actions that take a text input, such
48
+ * as the rename button (role `rename`) of the conversation header, whose
49
+ * role maps to `'thread.title'`.
50
+ *
51
+ * With a `confirm` option, the click asks through the shared confirm dialog
52
+ * first, and submits only when confirmed; the option's `message` may be a
53
+ * function of the control's current value. Use it for destructive actions,
54
+ * such as the delete button (role `delete`) of a thread item's context menu.
55
+ *
56
+ * The control's current value is the role's mapped data value, put through
57
+ * the `value` option when given — map the role to a record and let `value`
58
+ * pick the text the dialogs work with. A `disabled` option (a boolean, or a
59
+ * function of the mapped value) renders the button's disabled state from
60
+ * the data, re-evaluated on every commit — e.g. rename/delete disable while
61
+ * their thread record has no thread id yet (a thread being created is not
62
+ * addressable), enabling in place when the resolution patches the record.
63
+ */
64
+ export default class ButtonLayout extends TemplateBasedLayout {
65
+
66
+ static get type() {
67
+ return TYPE;
68
+ }
69
+
70
+ static get defaultTemplates() {
71
+ return DEFAULT_TEMPLATES;
72
+ }
73
+
74
+ static get defaultClassName() {
75
+ return DEFAULT_CLASSNAME;
76
+ }
77
+
78
+ constructor({ className = DEFAULT_CLASSNAME, templates, ...options } = {}) {
79
+ super({
80
+ className,
81
+ templates: { ...DEFAULT_TEMPLATES, ...templates },
82
+ ...options,
83
+ });
84
+ }
85
+
86
+ initialize(view) {
87
+ this._unsubscribes = [
88
+ ...this._unsubscribes,
89
+ view.proxyElement.on('click', event => this._handleClick(event)),
90
+ ];
91
+ }
92
+
93
+ _handleClick(event) {
94
+ // only left click
95
+ if (event.button !== 0) {
96
+ return;
97
+ }
98
+ const button = event.target.closest(`button.${this.className}`);
99
+ if (!button || button.disabled) {
100
+ return;
101
+ }
102
+ this.options.prompt ? this._submitViaPrompt(event) :
103
+ this.options.confirm ? this._submitViaConfirm(event) :
104
+ this._submit(event);
105
+ }
106
+
107
+ _submit(event, payload) {
108
+ const { session } = this._view._state || {};
109
+ this._view._emit('submit', { session, domEvent: event, ...payload });
110
+ }
111
+
112
+ async _submitViaPrompt(event) {
113
+ const current = this._currentValue();
114
+ const value = await prompt({
115
+ value: typeof current === 'string' ? current : '',
116
+ ...this.options.prompt,
117
+ });
118
+ if (!value || value === current) {
119
+ return; // cancelled, cleared, or unchanged
120
+ }
121
+ this._submit(event, { value });
122
+ }
123
+
124
+ async _submitViaConfirm(event) {
125
+ const { message, ...options } = this.options.confirm;
126
+ const confirmed = await confirm({
127
+ ...options,
128
+ message: typeof message === 'function' ? message(this._currentValue()) : message,
129
+ });
130
+ if (!confirmed) {
131
+ return;
132
+ }
133
+ this._submit(event);
134
+ }
135
+
136
+ /**
137
+ * The current value of the control: the role's mapped data value, as of
138
+ * the latest render, put through the `value` option when given.
139
+ */
140
+ _currentValue() {
141
+ const state = this._element && this._rendered.get(this._element);
142
+ const raw = state && state.value;
143
+ const { value } = this.options;
144
+ return typeof value === 'function' ? value(raw) : raw;
145
+ }
146
+
147
+ _isDisabled(state) {
148
+ const { disabled } = this.options;
149
+ return typeof disabled === 'function' ? !!disabled(state && state.value) : !!disabled;
150
+ }
151
+
152
+ }
@@ -0,0 +1,92 @@
1
+ import { escapeHtml } from '@miso.ai/commons';
2
+ import { LAYOUT_TYPE } from '../../constants.js';
3
+ import ButtonLayout from './button.js';
4
+ import { getIcon } from '../../asset/svgs.js';
5
+
6
+ const TYPE = LAYOUT_TYPE.CHECKBOX;
7
+ const DEFAULT_CLASSNAME = 'miso-checkbox';
8
+
9
+ function root(layout, state) {
10
+ const { className, role, templates } = layout;
11
+ const checked = isChecked(state);
12
+ const roleAttr = role ? ` data-role="${role}"` : '';
13
+ const checkedAttr = checked ? ' data-checked' : '';
14
+ const disabledAttr = layout._isDisabled(state) ? ' disabled' : '';
15
+ return `<button type="button" class="${className}" role="switch" aria-checked="${checked}"${roleAttr}${checkedAttr}${disabledAttr}>${templates.icon(layout, state)}${templates.text(layout, state)}</button>`;
16
+ }
17
+
18
+ function icon(layout, state) {
19
+ const { icon, checkedIcon = icon } = layout.options;
20
+ const name = isChecked(state) ? checkedIcon : icon;
21
+ return name ? getIcon(name) : '';
22
+ }
23
+
24
+ function text(layout, state) {
25
+ const { className, options: { text, checkedText = text } } = layout;
26
+ const value = isChecked(state) ? checkedText : text;
27
+ return value ? `<span class="${className}__text">${escapeHtml(value)}</span>` : '';
28
+ }
29
+
30
+ // the checked state is the mapped data value, so it renders from data alone
31
+ function isChecked({ value } = {}) {
32
+ return value === true;
33
+ }
34
+
35
+ const DEFAULT_TEMPLATES = Object.freeze({
36
+ root,
37
+ icon,
38
+ text,
39
+ });
40
+
41
+ /**
42
+ * A checkbox that looks like a button: an icon and a label, each with an
43
+ * optional checked variant (`icon`/`text` and `checkedIcon`/`checkedText`,
44
+ * the latter falling back to the former). It is a switch — semantically a
45
+ * checkbox (`role="switch"`, `aria-checked`), visually a button — for
46
+ * on/off state a user toggles, such as the answer-updates subscription of
47
+ * the conversation panel (role `subscription`).
48
+ *
49
+ * The checked state comes from the data (the mapped value is the boolean —
50
+ * e.g. role `subscription` maps to `'thread.subscribed'`), so a click emits
51
+ * a `change` view event carrying the requested state (`{ checked }`) and
52
+ * nothing else: the workflow acts on it and the new state arrives back down
53
+ * the data path, like any other rendering.
54
+ */
55
+ export default class CheckboxLayout extends ButtonLayout {
56
+
57
+ static get type() {
58
+ return TYPE;
59
+ }
60
+
61
+ static get defaultTemplates() {
62
+ return DEFAULT_TEMPLATES;
63
+ }
64
+
65
+ static get defaultClassName() {
66
+ return DEFAULT_CLASSNAME;
67
+ }
68
+
69
+ constructor({ className = DEFAULT_CLASSNAME, templates, ...options } = {}) {
70
+ super({
71
+ className,
72
+ templates: { ...DEFAULT_TEMPLATES, ...templates },
73
+ ...options,
74
+ });
75
+ }
76
+
77
+ _handleClick(event) {
78
+ // only left click
79
+ if (event.button !== 0) {
80
+ return;
81
+ }
82
+ const button = event.target.closest(`button.${this.className}`);
83
+ if (!button || button.disabled) {
84
+ return;
85
+ }
86
+ // what the user toggles is the control's current value
87
+ const checked = this._currentValue() === true;
88
+ const { session } = this._view._state || {};
89
+ this._view._emit('change', { session, checked: !checked, domEvent: event });
90
+ }
91
+
92
+ }
@@ -1,9 +1,9 @@
1
- import { STATUS } from '../../constants.js';
2
- import { fields } from '../../actor/index.js';
1
+ import { STATUS, LAYOUT_TYPE } from '../../constants.js';
2
+ import { fields } from '@miso.ai/client-sdk-workflow';
3
3
  import TemplateBasedLayout from '../template.js';
4
4
  import { helpers } from '../templates.js';
5
5
 
6
- const TYPE = 'more-button';
6
+ const TYPE = LAYOUT_TYPE.MORE_BUTTON;
7
7
  const DEFAULT_CLASSNAME = 'miso-more-button';
8
8
 
9
9
  function root(layout, state) {
@@ -1,10 +1,10 @@
1
- import { ROLE, STATUS } from '../../constants.js';
1
+ import { ROLE, STATUS, LAYOUT_TYPE } from '../../constants.js';
2
2
  import RafLayout from '../raf.js';
3
3
  import MisoBannerElement from '../../element/util/miso-banner.js';
4
4
  import Viewables from '../../util/viewables.js';
5
5
  import { setOrRemoveAttribute } from '../../util/dom.js';
6
6
 
7
- const TYPE = 'container';
7
+ const TYPE = LAYOUT_TYPE.CONTAINER;
8
8
 
9
9
  export default class ContainerLayout extends RafLayout {
10
10
 
@@ -0,0 +1,99 @@
1
+ import { LAYOUT_TYPE } from '../../constants.js';
2
+ import ContainerLayout from './container.js';
3
+
4
+ const TYPE = LAYOUT_TYPE.ITEM_CONTAINER;
5
+
6
+ /**
7
+ * The container layout of a collection's item subworkflow (a thread of the
8
+ * thread list, a message of the conversation panel): the standard container
9
+ * duties (status attributes, banner, trackings), plus the item-level
10
+ * behaviors — currently the context menu (vertical dots + popup).
11
+ *
12
+ * The menu is handled by contract, not rendered here: the item template
13
+ * supplies the markup (e.g. the threads layout's threadMenuBlock), marking
14
+ * the toggle button `data-role="item-menu-button"` and the popup
15
+ * `data-role="item-menu"`, and this layout drives their open/close behavior
16
+ * — toggle on the button; any other click on the item (a menu action
17
+ * included) closes it, and so does a click outside the item, which is also
18
+ * how opening one item's menu closes another's. The menu contents are
19
+ * typically role elements binding to the item workflow (e.g. the thread
20
+ * item's `<miso-rename>`/`<miso-delete>` buttons), so the actions stay the
21
+ * workflow's own controls. Collection shells treat clicks carrying the
22
+ * menu data-roles as item-internal (e.g. the threads layout does not
23
+ * select); an item template without menu markup simply has nothing to
24
+ * drive. Ownership is guarded: the layout only ever drives its own item's
25
+ * menu — a menu or click inside a nested container element is that
26
+ * container's own layout's — so the layout is inert on the list panel
27
+ * itself, whose options bag it shares with the items.
28
+ */
29
+ export default class ItemContainerLayout extends ContainerLayout {
30
+
31
+ static get type() {
32
+ return TYPE;
33
+ }
34
+
35
+ initialize(view) {
36
+ this._unsubscribes.push(view.proxyElement.on('click', event => this._handleClick(event)));
37
+ if (typeof document !== 'undefined') {
38
+ const onDocumentClick = (event) => {
39
+ const element = this._element;
40
+ if (element && !element.contains(event.target)) {
41
+ this._closeMenu();
42
+ }
43
+ };
44
+ document.addEventListener('click', onDocumentClick);
45
+ this._unsubscribes.push(() => document.removeEventListener('click', onDocumentClick));
46
+ }
47
+ }
48
+
49
+ // menu //
50
+ _handleClick(event) {
51
+ // only left click
52
+ if (event.button !== 0) {
53
+ return;
54
+ }
55
+ // a click inside a nested container element belongs to that
56
+ // container's own layout (this layout may also host the list panel,
57
+ // whose subtree holds the items)
58
+ if (!this._owns(event.target)) {
59
+ return;
60
+ }
61
+ if (event.target.closest(`[data-role="item-menu-button"]`)) {
62
+ this._toggleMenu();
63
+ return;
64
+ }
65
+ // any other click on the item — a menu action included — closes the menu
66
+ this._closeMenu();
67
+ }
68
+
69
+ _getMenu() {
70
+ const menu = this._element && this._element.querySelector(`[data-role="item-menu"]`);
71
+ // only its own item's menu: one found inside a nested container
72
+ // element is that container's own layout's to drive
73
+ return menu && this._owns(menu) ? menu : undefined;
74
+ }
75
+
76
+ _owns(node) {
77
+ for (let el = node; el && el !== this._element; el = el.parentElement) {
78
+ if (el.isContainer) {
79
+ return false;
80
+ }
81
+ }
82
+ return true;
83
+ }
84
+
85
+ _toggleMenu() {
86
+ const menu = this._getMenu();
87
+ if (menu) {
88
+ menu.hidden = !menu.hidden;
89
+ }
90
+ }
91
+
92
+ _closeMenu() {
93
+ const menu = this._getMenu();
94
+ if (menu && !menu.hidden) {
95
+ menu.hidden = true;
96
+ }
97
+ }
98
+
99
+ }
@@ -1,6 +1,7 @@
1
+ import { LAYOUT_TYPE } from '../../constants.js';
1
2
  import TemplateBasedLayout from '../template.js';
2
3
 
3
- const TYPE = 'error';
4
+ const TYPE = LAYOUT_TYPE.ERROR;
4
5
  const DEFAULT_CLASSNAME = 'miso-error';
5
6
 
6
7
  function root(layout, state) {
@@ -1,9 +1,12 @@
1
1
  export { default as TemplateBasedLayout } from './template.js';
2
2
  export { default as ContainerLayout } from './container/container.js';
3
+ export { default as ItemContainerLayout } from './container/item-container.js';
3
4
  export { default as ErrorLayout } from './error/error.js';
4
5
  export { default as BannerLayout } from './banner/banner.js';
5
6
  export { default as CollectionLayout } from './list/collection.js';
6
7
  export { default as ListLayout } from './list/list.js';
8
+ export { default as ThreadsLayout } from './list/threads.js';
9
+ export { default as MessagesLayout } from './list/messages.js';
7
10
  export { default as HorizontalLayout } from './list/horizontal.js';
8
11
  export { default as CardsLayout } from './list/cards.js';
9
12
  export { default as CarouselLayout } from './list/carousel.js';
@@ -12,8 +15,11 @@ export { default as SearchBoxLayout } from './input/search-box.js';
12
15
  export { default as OptionListLayout } from './input/option-list.js';
13
16
  export { default as FeedbackLayout } from './radio/feedback.js';
14
17
  export { default as TextLayout } from './text/text.js';
18
+ export { default as QuestionLayout } from './text/question.js';
15
19
  export { default as TypewriterLayout } from './text/typewriter/index.js';
16
20
  export { default as AffiliationLayout } from './affiliation/affiliation.js';
17
21
  export { default as FacetsLayout } from './input/facets.js';
18
22
  export { default as SelectLayout } from './input/select.js';
19
23
  export { default as MoreButtonLayout } from './button/more-button.js';
24
+ export { default as ButtonLayout } from './button/button.js';
25
+ export { default as CheckboxLayout } from './button/checkbox.js';