@miso.ai/client-sdk-ui 1.12.1-beta.1 → 1.12.1-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 (53) hide show
  1. package/dist/cjs/actor/fields.js +0 -4
  2. package/dist/cjs/actor/view.js +28 -29
  3. package/dist/cjs/actor/views.js +2 -14
  4. package/dist/cjs/affiliation/index.js +17 -2
  5. package/dist/cjs/defaults/ask/templates.js +30 -12
  6. package/dist/cjs/defaults/common/templates.js +2 -0
  7. package/dist/cjs/element/container/miso-container.js +8 -2
  8. package/dist/cjs/element/role/index.js +6 -6
  9. package/dist/cjs/element/util/index.js +3 -3
  10. package/dist/cjs/element/util/miso-stub.js +81 -0
  11. package/dist/cjs/element/utils.js +0 -10
  12. package/dist/cjs/layout/input/option-list.js +2 -9
  13. package/dist/cjs/layout/templates.js +7 -2
  14. package/dist/cjs/layout/text/typewriter/index.js +1 -1
  15. package/dist/cjs/plugin.js +5 -4
  16. package/dist/cjs/trait/collapsible.js +57 -0
  17. package/dist/cjs/trait/helpers.js +65 -0
  18. package/dist/cjs/trait/index.js +13 -0
  19. package/dist/cjs/version.js +1 -1
  20. package/dist/cjs/workflow/ask.js +28 -32
  21. package/dist/cjs/workflow/base.js +1 -2
  22. package/dist/cjs/workflow/hybrid-search-views.js +0 -1
  23. package/dist/cjs/workflow/processors.js +20 -9
  24. package/package.json +2 -2
  25. package/src/actor/fields.js +0 -4
  26. package/src/actor/view.js +28 -25
  27. package/src/actor/views.js +2 -12
  28. package/src/affiliation/index.js +18 -2
  29. package/src/defaults/ask/templates.js +36 -23
  30. package/src/defaults/common/templates.js +2 -2
  31. package/src/element/container/miso-container.js +10 -2
  32. package/src/element/role/index.js +1 -1
  33. package/src/element/util/index.js +1 -1
  34. package/src/element/util/miso-stub.js +85 -0
  35. package/src/element/utils.js +0 -10
  36. package/src/layout/input/option-list.js +1 -8
  37. package/src/layout/templates.js +8 -2
  38. package/src/layout/text/typewriter/index.js +1 -1
  39. package/src/plugin.js +4 -4
  40. package/src/trait/collapsible.js +51 -0
  41. package/src/trait/helpers.js +48 -0
  42. package/src/trait/index.js +1 -0
  43. package/src/version.js +1 -1
  44. package/src/workflow/ask.js +28 -21
  45. package/src/workflow/base.js +2 -2
  46. package/src/workflow/hybrid-search-views.js +0 -1
  47. package/src/workflow/processors.js +16 -9
  48. package/dist/cjs/element/util/miso-collapsible.js +0 -52
  49. package/dist/cjs/element/util/miso-utility.js +0 -83
  50. package/dist/cjs/element/util/utils.js +0 -12
  51. package/src/element/util/miso-collapsible.js +0 -49
  52. package/src/element/util/miso-utility.js +0 -69
  53. package/src/element/util/utils.js +0 -3
@@ -0,0 +1,85 @@
1
+ const TAG_NAME = 'miso-stub';
2
+
3
+ const ATTR_TRAIT = 'trait';
4
+ const OBSERVED_ATTRIBUTES = Object.freeze([ATTR_TRAIT]);
5
+
6
+ export default class MisoStubElement extends HTMLElement {
7
+
8
+ static get tagName() {
9
+ return TAG_NAME;
10
+ }
11
+
12
+ static get observedAttributes() {
13
+ return OBSERVED_ATTRIBUTES;
14
+ }
15
+
16
+ constructor() {
17
+ super();
18
+ this._traits = [];
19
+ }
20
+
21
+ // lifecycle //
22
+ connectedCallback() {
23
+ this._syncTraits();
24
+ }
25
+
26
+ disconnectedCallback() {
27
+ for (const trait of this._traits) {
28
+ this._destroyTrait(trait);
29
+ }
30
+ this._traits = [];
31
+ }
32
+
33
+ attributeChangedCallback(attr) {
34
+ switch (attr) {
35
+ case ATTR_TRAIT:
36
+ this._syncTraits();
37
+ break;
38
+ }
39
+ }
40
+
41
+ _syncTraits() {
42
+ const names = (this.getAttribute(ATTR_TRAIT) || '').split(/\s+/).filter(Boolean);
43
+ const traits = [];
44
+ for (const trait of this._traits) {
45
+ if (!names.includes(trait.constructor.traitName)) {
46
+ this._destroyTrait(trait);
47
+ } else {
48
+ traits.push(trait);
49
+ }
50
+ }
51
+ if (names.length > 0) {
52
+ const availableTraits = getAvailableTraits(MisoStubElement.MisoClient);
53
+ for (const name of names) {
54
+ if (this._traits.find(trait => trait.constructor.traitName === name)) {
55
+ continue;
56
+ }
57
+ const TraitClass = availableTraits[name];
58
+ if (!TraitClass) {
59
+ console.warn(`Unknown trait: ${name}`);
60
+ continue;
61
+ }
62
+ const trait = new TraitClass(this);
63
+ traits.push(trait);
64
+ }
65
+ }
66
+ this._traits = traits;
67
+ }
68
+
69
+ _destroyTrait(trait) {
70
+ try {
71
+ trait._destroy && trait._destroy();
72
+ } catch (error) {
73
+ console.error(error);
74
+ }
75
+ }
76
+
77
+ }
78
+
79
+ function getAvailableTraits(MisoClient) {
80
+ const traits = MisoClient.ui && MisoClient.ui.traits || {};
81
+ return Object.values(traits).reduce((traits, trait) => {
82
+ traits[trait.traitName] = trait;
83
+ return traits;
84
+ }, {});
85
+ }
@@ -83,13 +83,3 @@ function coerceDefault(str) {
83
83
  }
84
84
  return str;
85
85
  }
86
-
87
- export function defineStatusGetters(prototype, statuses) {
88
- for (const status of statuses) {
89
- Object.defineProperty(prototype, status, {
90
- get() {
91
- return this.classList.contains(status);
92
- },
93
- });
94
- }
95
- }
@@ -63,20 +63,13 @@ export default class OptionListLayout extends TemplateBasedLayout {
63
63
  }
64
64
 
65
65
  initialize(view) {
66
- const { proxyElement, hub } = view;
66
+ const { proxyElement } = view;
67
67
  this._unsubscribes = [
68
68
  ...this._unsubscribes,
69
69
  proxyElement.on('click', (e) => this._handleClick(e)),
70
- hub.on(fields.suggestions(), () => this._handleInput()), // TODO: use data mapping
71
70
  ];
72
71
  }
73
72
 
74
- _preprocess() {
75
- return super._preprocess({
76
- state: this._view.hub.states[fields.suggestions()], // TODO: use data mapping
77
- });
78
- }
79
-
80
73
  _render(element, data, controls) {
81
74
  super._render(element, data, controls);
82
75
  const { state } = data;
@@ -120,7 +120,7 @@ export function imageInfoBlock(layout, data, meta) {
120
120
  }
121
121
 
122
122
  export function titleBlock({ className }, { title, _title_with_markups }) {
123
- const text = _title_with_markups || escapeHtml(title);
123
+ const text = formatHtmlWithMarkup(_title_with_markups) || escapeHtml(title);
124
124
  return text ? `<div class="${className}__item-title">${text}</div>` : '';
125
125
  }
126
126
 
@@ -133,7 +133,7 @@ export function brandBlock({ className }, { brand, brand_logo }) {
133
133
  }
134
134
 
135
135
  export function descriptionBlock({ className }, { snippet, description }) {
136
- return snippet ? `<div class="${className}__item-snippet">${snippet}</div>` : description ? `<div class="${className}__item-desc">${escapeHtml(description)}</div>` : '';
136
+ return snippet ? `<div class="${className}__item-snippet">${formatHtmlWithMarkup(snippet)}</div>` : description ? `<div class="${className}__item-desc">${escapeHtml(description)}</div>` : '';
137
137
  }
138
138
 
139
139
  export function dateBlock({ className, templates }, { created_at, updated_at, published_at }) {
@@ -269,6 +269,11 @@ function formatNumber(number, fn = DEFAULT_NUMBER_OPTIONS) {
269
269
  }
270
270
  }
271
271
 
272
+ function formatHtmlWithMarkup(html) {
273
+ // preserve space between two <mark> elements
274
+ return html && html.replace(/<\/mark>\s+<mark>/g, '</mark>&nbsp;<mark>');
275
+ }
276
+
272
277
  function asFunction(template = '') {
273
278
  return typeof template === 'function' ? template : () => template;
274
279
  }
@@ -277,6 +282,7 @@ export const helpers = Object.freeze({
277
282
  tagPair,
278
283
  formatDate,
279
284
  formatNumber,
285
+ formatHtmlWithMarkup,
280
286
  escapeHtml,
281
287
  asFunction,
282
288
  });
@@ -112,7 +112,7 @@ export default class TypewriterLayout extends ProgressiveLayout {
112
112
  const sameStreak = sameSession && (stage === prev.stage);
113
113
  const streak = !prev ? 0 : sameStreak ? prev.streak : prev.streak + 1;
114
114
 
115
- const doneAt = (sameSession && prev && prev.doneAt) || (status === STATUS.READY && finished ? Date.now() : undefined);
115
+ const doneAt = (sameSession && prev && prev.doneAt) || (status === STATUS.READY && finished ? performance.now() : undefined);
116
116
  const done = doneAt !== undefined;
117
117
 
118
118
  return this._prevState = Object.freeze(trimObj({
package/src/plugin.js CHANGED
@@ -6,6 +6,7 @@ import * as elements from './element/index.js';
6
6
  import * as layouts from './layout/index.js';
7
7
  import * as sources from './source.js';
8
8
  import * as defaults from './defaults/index.js';
9
+ import * as traits from './trait/index.js';
9
10
  import { loadStylesIfNecessary } from './styles.js';
10
11
 
11
12
  import MisoContainerElement from './element/container/miso-container.js';
@@ -33,7 +34,7 @@ export default class UiPlugin extends Component {
33
34
  context.addSubtree(this);
34
35
  MisoClient.on('create', this._injectClient.bind(this));
35
36
 
36
- const ui = { defaults };
37
+ const ui = { defaults, traits };
37
38
  delegateGetters(ui, this, ['layouts', 'combo', 'ready']);
38
39
  defineValues(this, { MisoClient });
39
40
  defineValues(MisoClient, { ui });
@@ -59,9 +60,8 @@ export default class UiPlugin extends Component {
59
60
  ...Object.values(roles),
60
61
  ...Object.values(others),
61
62
  ];
62
- MisoContainerElement.MisoClient = MisoClient;
63
- MisoComboElement.MisoClient = MisoClient;
64
- for (const ElementClass of ElementClasses) {
63
+ const ElementSuperClasses = [MisoContainerElement, MisoComboElement];
64
+ for (const ElementClass of [...ElementSuperClasses, ...ElementClasses]) {
65
65
  ElementClass.MisoClient = MisoClient; // TODO: find better way
66
66
  }
67
67
 
@@ -0,0 +1,51 @@
1
+ import { defineStatusGetters, defineActions, defineClickables, listenToClickables } from './helpers.js';
2
+
3
+ const CLASS_NAME = 'miso-collapsible';
4
+ const STATUS_EXPANDED = 'expanded';
5
+
6
+ const ACTIONS = [
7
+ { action: 'expand', classAction: 'add', className: STATUS_EXPANDED },
8
+ { action: 'collapse', classAction: 'remove', className: STATUS_EXPANDED },
9
+ ];
10
+
11
+ const CLICKABLES = [
12
+ { role: 'expand', action: 'expand' },
13
+ { role: 'collapse', action: 'collapse' },
14
+ { role: 'toggle-expand', action: 'toggle' },
15
+ ];
16
+
17
+ export default class CollapsibleTrait {
18
+
19
+ static get traitName() {
20
+ return 'collapsible';
21
+ }
22
+
23
+ constructor(element) {
24
+ this._element = element;
25
+ element.collapsible = this;
26
+ element.classList.add(CLASS_NAME);
27
+ this._unsubscribes = [
28
+ listenToClickables(this),
29
+ ];
30
+ }
31
+
32
+ _destroy() {
33
+ for (const unsubscribe of this._unsubscribes || []) {
34
+ unsubscribe();
35
+ }
36
+ this._unsubscribes = [];
37
+ delete this._element.collapsible;
38
+ this._element.classList.remove(CLASS_NAME);
39
+ this._element = undefined;
40
+ }
41
+
42
+ // api //
43
+ toggle() {
44
+ this.expanded ? this.collapse() : this.expand();
45
+ }
46
+
47
+ }
48
+
49
+ defineStatusGetters(CollapsibleTrait.prototype, [STATUS_EXPANDED]);
50
+ defineActions(CollapsibleTrait.prototype, ACTIONS);
51
+ defineClickables(CollapsibleTrait.prototype, CLICKABLES);
@@ -0,0 +1,48 @@
1
+ export function defineStatusGetters(prototype, statuses) {
2
+ for (const status of statuses) {
3
+ Object.defineProperty(prototype, status, {
4
+ get() {
5
+ return this._element && this._element.classList.contains(status);
6
+ },
7
+ });
8
+ }
9
+ }
10
+
11
+ export function defineActions(prototype, actions) {
12
+ for (const { action, classAction, className } of actions) {
13
+ prototype[action] = function() {
14
+ this._element && this._element.classList[classAction](className);
15
+ this[`_${action}`] && this[`_${action}`]();
16
+ };
17
+ }
18
+ }
19
+
20
+ export function defineClickables(prototype, clickables) {
21
+ prototype._handleClick = function(event) {
22
+ const { target, button } = event;
23
+ if (button !== 0) {
24
+ return; // only left click
25
+ }
26
+ for (let { role, selector, action } of clickables) {
27
+ selector = selector || `[data-role="${role}"]`;
28
+ if (!selector) {
29
+ continue;
30
+ }
31
+ if (target.closest(selector)) {
32
+ this[action]();
33
+ event.stopPropagation();
34
+ return;
35
+ }
36
+ }
37
+ };
38
+ }
39
+
40
+ export function listenToClickables(addon) {
41
+ const element = addon._element;
42
+ if (!element) {
43
+ return () => {};
44
+ }
45
+ const handleClick = event => addon._handleClick(event);
46
+ element.addEventListener('click', handleClick);
47
+ return () => element.removeEventListener('click', handleClick);
48
+ }
@@ -0,0 +1 @@
1
+ export { default as CollapsibleTrait } from './collapsible.js';
package/src/version.js CHANGED
@@ -1 +1 @@
1
- export default '1.12.1-beta.1';
1
+ export default '1.12.1-beta.3';
@@ -1,10 +1,11 @@
1
1
  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
- import { ROLE, ORGANIC_QUESTION_SOURCE } from '../constants.js';
4
+ import { ROLE, STATUS, ORGANIC_QUESTION_SOURCE } from '../constants.js';
5
5
  import { OptionListLayout, ListLayout, SearchBoxLayout, TypewriterLayout } from '../layout/index.js';
6
6
  import { mergeInteraction } from './processors.js';
7
7
  import { mergeRolesOptions, DEFAULT_TRACKER_OPTIONS } from './options/index.js';
8
+ import { mappingSuggestionsData } from './processors.js';
8
9
 
9
10
  const DEFAULT_API_OPTIONS = Object.freeze({
10
11
  ...AnswerBasedWorkflow.DEFAULT_API_OPTIONS,
@@ -44,6 +45,9 @@ const DEFAULT_OPTIONS = Object.freeze({
44
45
 
45
46
  const ROLES_OPTIONS = mergeRolesOptions(AnswerBasedWorkflow.ROLES_OPTIONS, {
46
47
  members: Object.keys(DEFAULT_LAYOUTS),
48
+ mappings: {
49
+ [ROLE.QUERY_SUGGESTIONS]: mappingSuggestionsData,
50
+ },
47
51
  });
48
52
 
49
53
  export default class Ask extends AnswerBasedWorkflow {
@@ -65,19 +69,11 @@ export default class Ask extends AnswerBasedWorkflow {
65
69
  }
66
70
 
67
71
  _initSubscriptions(args) {
68
- this._setSuggestedQuestions();
69
72
  super._initSubscriptions(args);
70
- }
71
-
72
- _setSuggestedQuestions() {
73
- const { previous } = this;
74
- if (!previous) {
75
- return;
76
- }
77
- // TODO: write question_source from payload._meta, so we don't need to write it to session.meta
78
- const values = previous.states[fields.data()].value;
79
- const value = values.suggested_followup_questions || values.followup_questions || [];
80
- this._hub.update(fields.suggestions(), { value: value.map(text => ({ text })) });
73
+ this._unsubscribes = [
74
+ ...this._unsubscribes,
75
+ this._hub.on(fields.view(ROLE.REASONING), state => this._onReasoningViewUpdate(state)),
76
+ ];
81
77
  }
82
78
 
83
79
  _initSession(args) {
@@ -134,20 +130,25 @@ export default class Ask extends AnswerBasedWorkflow {
134
130
  // data //
135
131
  _updateData(data) {
136
132
  super._updateData(data);
137
- this._triggerReasoningShowIfNecessary(data);
133
+ this._triggerSuggestionsRefreshIfNecessary();
138
134
  }
139
135
 
140
- _triggerReasoningShowIfNecessary({ session, value } = {}) {
141
- if (!value || !value.reasoning) {
136
+ _triggerSuggestionsRefreshIfNecessary() {
137
+ const { next } = this;
138
+ if (!next) {
142
139
  return;
143
140
  }
144
- const context = this._getSessionContext(session);
145
- if (context.reasoningShown) {
141
+ const view = next._views.get(ROLE.QUERY_SUGGESTIONS);
142
+ view && view.refresh();
143
+ }
144
+
145
+ // view //
146
+ _onReasoningViewUpdate({ status, ongoing }) {
147
+ if (status !== STATUS.READY || ongoing) {
146
148
  return;
147
149
  }
148
- context.reasoningShown = true;
149
- const view = this._views.get(ROLE.REASONING);
150
- view && view.triggerAction({ name: 'show', target: '[data-role="reasoning-container"]' });
150
+ const element = this._getReasoningBoxElement();
151
+ element && element.classList.add('done');
151
152
  }
152
153
 
153
154
  // interactions //
@@ -197,6 +198,12 @@ export default class Ask extends AnswerBasedWorkflow {
197
198
  }
198
199
  }
199
200
 
201
+ _getReasoningBoxElement() {
202
+ const view = this._views.get(ROLE.REASONING);
203
+ const element = view && view.element;
204
+ return element && element.closest('[data-role="reasoning-box"]');
205
+ }
206
+
200
207
  // destroy //
201
208
  _destroy(options) {
202
209
  const { parentQuestionId, questionId } = this;
@@ -60,7 +60,7 @@ export default class Workflow extends Component {
60
60
 
61
61
  _initProperties() {}
62
62
 
63
- _initActors({ name, roles }) {
63
+ _initActors({ roles }) {
64
64
  const hub = this._hub;
65
65
  const client = this._client;
66
66
  const options = this._options;
@@ -69,7 +69,7 @@ export default class Workflow extends Component {
69
69
 
70
70
  this._sessions = new SessionMaker(hub);
71
71
  this._data = new DataActor(hub, { source: sources.api(client), options });
72
- this._views = new ViewsActor(hub, { extensions, layouts, roles, options, workflow: name });
72
+ this._views = new ViewsActor(hub, { extensions, layouts, roles, options, workflow: this });
73
73
  this._interactions = new InteractionsActor(hub, { client, options });
74
74
  }
75
75
 
@@ -1,4 +1,3 @@
1
- import { ROLE } from '../constants.js';
2
1
  import HybridSearchResults from './hybrid-search-results.js';
3
2
 
4
3
  function getSubworkflowByRole(role) {
@@ -22,9 +22,18 @@ export function mappingSortData(_, { hub, workflowOptions = {} } = {}) {
22
22
  });
23
23
  }
24
24
 
25
+ function findDefaultSortOption(options) {
26
+ for (const option of options) {
27
+ if (option.default) {
28
+ return option;
29
+ }
30
+ }
31
+ return options[0];
32
+ }
33
+
25
34
  export function mappingAnswerData(data) {
26
35
  if (!data || !data.value) {
27
- return data;
36
+ return undefined;
28
37
  }
29
38
  const { answer = '', answer_stage, finished } = data.value;
30
39
  return Object.freeze({ value: answer, stage: answer_stage, finished: !!finished });
@@ -32,19 +41,17 @@ export function mappingAnswerData(data) {
32
41
 
33
42
  export function mappingReasoningData(data) {
34
43
  if (!data || !data.value) {
35
- return data;
44
+ return undefined;
36
45
  }
37
46
  const { reasoning = '', reasoning_finished } = data.value;
38
47
  return Object.freeze({ value: reasoning, stage: 'reasoning', finished: !!reasoning_finished });
39
48
  }
40
49
 
41
- function findDefaultSortOption(options) {
42
- for (const option of options) {
43
- if (option.default) {
44
- return option;
45
- }
46
- }
47
- return options[0];
50
+ export function mappingSuggestionsData(_, { workflow } = {}) {
51
+ const previous = workflow.previous;
52
+ const values = previous && previous.states[fields.data()].value;
53
+ const value = values && (values.suggested_followup_questions || values.followup_questions || []);
54
+ return value && value.map(text => ({ text }));
48
55
  }
49
56
 
50
57
  // data //
@@ -1,52 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
- var _misoUtility = _interopRequireDefault(require("./miso-utility.js"));
8
- var _utils = require("../utils.js");
9
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
- const TAG_NAME = 'miso-collapsible';
11
- const STATUS_EXPANDED = 'expanded';
12
- const STATUS_HIDDEN = 'hidden';
13
- const ACTIONS = {
14
- expand: ['add', STATUS_EXPANDED],
15
- collapse: ['remove', STATUS_EXPANDED],
16
- hide: ['add', STATUS_HIDDEN],
17
- show: ['remove', STATUS_HIDDEN]
18
- };
19
- const CLICKABLES = [{
20
- role: 'expand',
21
- action: 'expand'
22
- }, {
23
- role: 'collapse',
24
- action: 'collapse'
25
- }, {
26
- role: 'toggle-expand',
27
- action: 'toggleExpand'
28
- }];
29
- class MisoCollapsibleElement extends _misoUtility.default {
30
- static get tagName() {
31
- return TAG_NAME;
32
- }
33
- constructor() {
34
- super({
35
- actions: Object.keys(ACTIONS),
36
- clickables: CLICKABLES
37
- });
38
- }
39
-
40
- // lifecycle //
41
- toggleExpand() {
42
- this.expanded ? this.collapse() : this.expand();
43
- }
44
- }
45
- exports.default = MisoCollapsibleElement;
46
- (0, _utils.defineStatusGetters)(MisoCollapsibleElement.prototype, [STATUS_EXPANDED, STATUS_HIDDEN]);
47
- for (const [method, [action, status]] of Object.entries(ACTIONS)) {
48
- MisoCollapsibleElement.prototype[method] = function () {
49
- this.classList[action](status);
50
- this[`_${method}`] && this[`_${method}`]();
51
- };
52
- }
@@ -1,83 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
- class MisoUtilityElement extends HTMLElement {
8
- constructor({
9
- actions = [],
10
- clickables = []
11
- } = {}) {
12
- super();
13
- this._actions = actions;
14
- this._clickables = clickables;
15
- this._unsubscribes = [];
16
- }
17
-
18
- // lifecycle //
19
- async connectedCallback() {
20
- const handleAction = event => this._handleAction(event);
21
- const handleClick = event => this._handleClick(event);
22
- this.addEventListener('miso:action', handleAction);
23
- this.addEventListener('click', handleClick);
24
- this._unsubscribes = [...this._unsubscribes, () => this.removeEventListener('miso:action', handleAction), () => this.removeEventListener('click', handleClick)];
25
- }
26
- disconnectedCallback() {
27
- for (const unsubscribe of this._unsubscribes) {
28
- unsubscribe();
29
- }
30
- this._unsubscribes = [];
31
- }
32
- _handleAction(event) {
33
- const {
34
- target,
35
- name
36
- } = event.detail || {};
37
- if (!name || !target || !this.matches(target)) {
38
- return;
39
- }
40
- if (!this._actions.includes(name)) {
41
- return;
42
- }
43
- if (this._doAction({
44
- name
45
- })) {
46
- event.stopPropagation();
47
- }
48
- }
49
- _doAction(args) {
50
- const {
51
- name
52
- } = args;
53
- this[name](args);
54
- return true;
55
- }
56
- _handleClick(event) {
57
- const {
58
- target,
59
- button
60
- } = event;
61
- if (button !== 0) {
62
- return; // only left click
63
- }
64
- for (let {
65
- role,
66
- selector,
67
- action
68
- } of this._clickables) {
69
- selector = selector || `[data-role="${role}"]`;
70
- if (!selector) {
71
- continue;
72
- }
73
- if (target.closest(selector)) {
74
- this._doAction({
75
- name: action
76
- });
77
- event.stopPropagation();
78
- return;
79
- }
80
- }
81
- }
82
- }
83
- exports.default = MisoUtilityElement;
@@ -1,12 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.triggerMisoAction = triggerMisoAction;
7
- function triggerMisoAction(element, data) {
8
- element.dispatchEvent(new CustomEvent('miso:action', {
9
- bubbles: true,
10
- detail: data
11
- }));
12
- }
@@ -1,49 +0,0 @@
1
- import MisoUtilityElement from './miso-utility.js';
2
- import { defineStatusGetters } from '../utils.js';
3
-
4
- const TAG_NAME = 'miso-collapsible';
5
-
6
- const STATUS_EXPANDED = 'expanded';
7
- const STATUS_HIDDEN = 'hidden';
8
-
9
- const ACTIONS = {
10
- expand: ['add', STATUS_EXPANDED],
11
- collapse: ['remove', STATUS_EXPANDED],
12
- hide: ['add', STATUS_HIDDEN],
13
- show: ['remove', STATUS_HIDDEN],
14
- };
15
-
16
- const CLICKABLES = [
17
- { role: 'expand', action: 'expand' },
18
- { role: 'collapse', action: 'collapse' },
19
- { role: 'toggle-expand', action: 'toggleExpand' },
20
- ];
21
-
22
- export default class MisoCollapsibleElement extends MisoUtilityElement {
23
-
24
- static get tagName() {
25
- return TAG_NAME;
26
- }
27
-
28
- constructor() {
29
- super({
30
- actions: Object.keys(ACTIONS),
31
- clickables: CLICKABLES,
32
- });
33
- }
34
-
35
- // lifecycle //
36
- toggleExpand() {
37
- this.expanded ? this.collapse() : this.expand();
38
- }
39
-
40
- }
41
-
42
- defineStatusGetters(MisoCollapsibleElement.prototype, [STATUS_EXPANDED, STATUS_HIDDEN]);
43
-
44
- for (const [method, [action, status]] of Object.entries(ACTIONS)) {
45
- MisoCollapsibleElement.prototype[method] = function() {
46
- this.classList[action](status);
47
- this[`_${method}`] && this[`_${method}`]();
48
- };
49
- }