@miso.ai/client-sdk-ui 1.10.0-beta.12 → 1.10.0-beta.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,16 +3,25 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.SEND = exports.SEARCH = void 0;
6
+ exports.TRIANGLE = exports.SEND = exports.SEARCH = void 0;
7
7
  var _version = _interopRequireDefault(require("../version.js"));
8
8
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
9
+ function trianglePath(r) {
10
+ const l = 100;
11
+ const d = r * Math.tan(3 * Math.PI / 8);
12
+ const e = d * Math.sin(Math.PI / 4);
13
+ return `M${r} 0L${l - d} 0A${r} ${r} 0 0 1 ${l - e} ${e}L${e} ${l - e}A${r} ${r} 0 0 1 0 ${l - d}L0 ${r}Z`;
14
+ }
9
15
  const PREFIX = 'miso-ui-icon';
10
16
  const ID = `${PREFIX}-svg-${_version.default.replaceAll('.', '_')}`;
11
17
 
12
- // all are CC0 SVGs
18
+ // CC0 SVGs
13
19
  const ICON_SEND = `<symbol id="${PREFIX}-send" viewBox="0 0 32 32"><path fill="currentColor" d="M11.499,19.173l5.801,-5.849c0.389,-0.392 1.022,-0.394 1.414,-0.006c0.392,0.389 0.395,1.022 0.006,1.414l-5.798,5.847l5.306,8.002c0.207,0.313 0.572,0.483 0.945,0.441c0.373,-0.042 0.691,-0.289 0.824,-0.64l9.024,-23.904c0.138,-0.366 0.05,-0.78 -0.226,-1.058c-0.276,-0.278 -0.689,-0.369 -1.057,-0.233l-24.004,8.892c-0.353,0.13 -0.602,0.448 -0.646,0.821c-0.044,0.373 0.125,0.74 0.438,0.948l7.973,5.325Z"/></symbol>`;
14
20
  const ICON_SEARCH = `<symbol id="${PREFIX}-search" viewBox="0 0 24 24"><path fill="currentColor" d="M4 11C4 7.13401 7.13401 4 11 4C14.866 4 18 7.13401 18 11C18 14.866 14.866 18 11 18C7.13401 18 4 14.866 4 11ZM11 2C6.02944 2 2 6.02944 2 11C2 15.9706 6.02944 20 11 20C13.125 20 15.078 19.2635 16.6177 18.0319L20.2929 21.7071C20.6834 22.0976 21.3166 22.0976 21.7071 21.7071C22.0976 21.3166 22.0976 20.6834 21.7071 20.2929L18.0319 16.6177C19.2635 15.078 20 13.125 20 11C20 6.02944 15.9706 2 11 2Z"/></symbol>`;
15
- const ICONS = [ICON_SEND, ICON_SEARCH];
21
+
22
+ // Custom SVGs
23
+ const ICON_TRIANGLE = `<symbol id="${PREFIX}-triangle" viewBox="-5 -5 105 105"><path d="${trianglePath(5)}"/></symbol>`;
24
+ const ICONS = [ICON_SEND, ICON_SEARCH, ICON_TRIANGLE];
16
25
  const SPRITES_SVG = `<svg id="${ID}" style="display:none;">${ICONS.join('')}</svg>`;
17
26
  let loaded = false;
18
27
  function loadSvgSprites() {
@@ -27,4 +36,5 @@ function getSvg(name) {
27
36
  return `<svg class="miso-ui-icon miso-ui-icon-${name}"><use href="#${PREFIX}-${name}"></use></svg>`;
28
37
  }
29
38
  const SEND = exports.SEND = getSvg('send');
30
- const SEARCH = exports.SEARCH = getSvg('search');
39
+ const SEARCH = exports.SEARCH = getSvg('search');
40
+ const TRIANGLE = exports.TRIANGLE = getSvg('triangle');
@@ -8,6 +8,7 @@ var _commons = require("@miso.ai/commons");
8
8
  var _constants = require("../../constants.js");
9
9
  var _collection = _interopRequireDefault(require("../list/collection.js"));
10
10
  var _templates = require("../templates.js");
11
+ var _svgs = require("../../asset/svgs.js");
11
12
  const _excluded = ["className", "templates", "autoplay"];
12
13
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
13
14
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.includes(n)) continue; t[n] = r[n]; } return t; }
@@ -33,40 +34,35 @@ function ready(layout, state) {
33
34
  } = layout;
34
35
  const items = layout._getItems(state);
35
36
  if (items && items.length > 0) {
36
- return templates.control(layout, state, 'previous') + templates.body(layout, state) + templates.control(layout, state, 'next');
37
+ return templates.controlContainer(layout, state, 'previous') + templates.body(layout, state) + templates.controlContainer(layout, state, 'next');
37
38
  } else {
38
39
  return templates.empty(layout, state);
39
40
  }
40
41
  }
41
- function control(layout, state, direction) {
42
+ function controlContainer(layout, state, direction) {
42
43
  const {
43
- className
44
+ className,
45
+ templates
44
46
  } = layout;
45
- return `<div class="${className}__control-${direction}" data-role="${direction}"></div>`;
47
+ return `<div class="${className}__control-${direction}-container">${templates.control(layout, state, direction)}</div>`;
46
48
  }
47
- function body(layout, state) {
49
+ function control(layout, state, direction) {
48
50
  const {
49
51
  className,
50
52
  templates
51
53
  } = layout;
52
- const items = layout._getItems(state);
53
- return `<div class="${className}__body">${templates.list(layout, state, items)}</div>`;
54
+ return `<div class="${className}__control-${direction}" data-role="${direction}">${templates.controlIcon(layout, state, direction)}</div>`;
54
55
  }
55
- function header(layout, state) {
56
+ function controlIcon(layout, state, direction) {
57
+ return _svgs.TRIANGLE;
58
+ }
59
+ function body(layout, state) {
56
60
  const {
57
61
  className,
58
62
  templates
59
63
  } = layout;
60
- let {
61
- headerText
62
- } = templates;
63
- if (typeof headerText === 'function') {
64
- headerText = headerText(layout, state);
65
- }
66
- if (!headerText) {
67
- return '';
68
- }
69
- return `<div class="${className}__header"><div class="${className}__header-tab">${headerText}</div></div>`;
64
+ const items = layout._getItems(state);
65
+ return `<div class="${className}__body">${templates.list(layout, state, items)}</div>`;
70
66
  }
71
67
  function item(layout, state, value, index) {
72
68
  const {
@@ -83,7 +79,7 @@ function item(layout, state, value, index) {
83
79
  const body = templates[itemType](layout, state, value, {
84
80
  index
85
81
  });
86
- return `<li class="${className}__item">${header}${body}</li>`;
82
+ return `<li class="${className}__item"><div class="${className}__item-inner">${header}${body}</div></li>`;
87
83
  }
88
84
  function itemHeader(layout, state, value, meta) {
89
85
  const {
@@ -91,45 +87,67 @@ function itemHeader(layout, state, value, meta) {
91
87
  templates
92
88
  } = layout;
93
89
  let {
94
- headerText
90
+ itemHeaderLeftText,
91
+ itemHeaderRightText
95
92
  } = templates;
96
- if (typeof headerText === 'function') {
97
- headerText = headerText(layout, state, value, meta);
98
- }
99
- if (!headerText) {
93
+ itemHeaderLeftText = _templates.helpers.asFunction(itemHeaderLeftText)(layout, state, value, meta);
94
+ itemHeaderRightText = _templates.helpers.asFunction(itemHeaderRightText)(layout, state, value, meta);
95
+ return `<div class="${className}__item-header">
96
+ <div class="${className}__item-header-left">${itemHeaderLeftText}</div>
97
+ <div class="${className}__item-header-right">${itemHeaderRightText}</div>
98
+ </div>`;
99
+ }
100
+ function itemHeaderRightText(layout, state, value, meta) {
101
+ const {
102
+ templates
103
+ } = layout;
104
+ const logoImg = _templates.helpers.asFunction(templates.logoImg)(layout, state, value, meta);
105
+ return logoImg ? `Selected by ${logoImg}` : '';
106
+ }
107
+ function logoImg(layout, state, value, meta) {
108
+ const {
109
+ className,
110
+ templates
111
+ } = layout;
112
+ const logoUrl = _templates.helpers.asFunction(templates.logoUrl)(layout, state, value, meta);
113
+ if (!logoUrl) {
100
114
  return '';
101
115
  }
102
- return `<div class="${className}__item-header"><div class="${className}__item-header-tab">${headerText}</div></div>`;
116
+ const logoAltText = _templates.helpers.asFunction(templates.logoAltText)(layout, state, value, meta);
117
+ const logoAltTextAttr = logoAltText ? ` alt="${logoAltText}"` : '';
118
+ return `<img class="${className}__item-header-logo" src="${logoUrl}"${logoAltTextAttr}>`;
103
119
  }
104
120
  const DEFAULT_TEMPLATES = Object.freeze({
105
121
  root,
106
122
  [_constants.STATUS.READY]: ready,
123
+ controlContainer,
107
124
  control,
125
+ controlIcon,
108
126
  body,
109
- header,
110
127
  item,
111
128
  itemHeader,
112
129
  affiliation: _templates.affiliation,
113
- ctaText: 'View',
114
- headerText: 'Featured'
130
+ ctaText: 'View deal',
131
+ itemHeaderLeftText: `Today's best deals`,
132
+ itemHeaderRightText,
133
+ logoImg
115
134
  });
116
135
  const INHERITED_DEFAULT_TEMPLATES = Object.freeze(Object.assign({}, _collection.default.defaultTemplates, DEFAULT_TEMPLATES));
136
+
137
+ /*
117
138
  function normalizeAutoplayOptions(options) {
118
139
  if (options === true) {
119
- options = {
120
- interval: 5000
121
- };
140
+ options = { interval: 10000 };
122
141
  } else if (typeof options === 'number') {
123
142
  if (options <= 0) {
124
143
  options = false;
125
144
  } else {
126
- options = {
127
- interval: Math.max(options, 500)
128
- };
145
+ options = { interval: Math.max(options, 500) };
129
146
  }
130
147
  }
131
148
  return options;
132
149
  }
150
+
133
151
  function autoplayOptionsEquals(a, b) {
134
152
  if (a === b) {
135
153
  return true;
@@ -139,6 +157,8 @@ function autoplayOptionsEquals(a, b) {
139
157
  }
140
158
  return a.interval === b.interval;
141
159
  }
160
+ */
161
+
142
162
  class AffiliationLayout extends _collection.default {
143
163
  static get category() {
144
164
  return _constants.LAYOUT_CATEGORY.AFFILIATION;
@@ -156,8 +176,7 @@ class AffiliationLayout extends _collection.default {
156
176
  let _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
157
177
  let {
158
178
  className = DEFAULT_CLASSNAME,
159
- templates,
160
- autoplay
179
+ templates
161
180
  } = _ref,
162
181
  options = _objectWithoutPropertiesLoose(_ref, _excluded);
163
182
  super(Object.assign({
@@ -170,8 +189,12 @@ class AffiliationLayout extends _collection.default {
170
189
  this._displayedCount = undefined;
171
190
  this._displayedIndex = undefined;
172
191
  this._viewable = undefined;
192
+
193
+ // TODO: extract this
194
+ /*
173
195
  this._autoplay = {};
174
196
  this.autoplay(autoplay);
197
+ */
175
198
  }
176
199
  initialize(view) {
177
200
  super.initialize(view);
@@ -180,8 +203,9 @@ class AffiliationLayout extends _collection.default {
180
203
  } = this._view.trackerOptions || {};
181
204
  this._viewable = new _commons.CarouselItemViewabilityObserver(this._onViewable.bind(this), options);
182
205
  }
183
- autoplay() {
184
- let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
206
+
207
+ /*
208
+ autoplay(options = false) {
185
209
  options = normalizeAutoplayOptions(options);
186
210
  if (autoplayOptionsEquals(options, this._autoplay.options)) {
187
211
  return;
@@ -189,9 +213,7 @@ class AffiliationLayout extends _collection.default {
189
213
  if (this._autoplay.options) {
190
214
  clearInterval(this._autoplay.intervalId);
191
215
  }
192
- this._autoplay = {
193
- options
194
- };
216
+ this._autoplay = { options };
195
217
  // TODO: use slower transition speed for autoplay
196
218
  // TODO: pause on hover
197
219
  // TODO: cooldown after manual interaction
@@ -199,6 +221,8 @@ class AffiliationLayout extends _collection.default {
199
221
  this._autoplay.intervalId = setInterval(() => this.next(), options.interval);
200
222
  }
201
223
  }
224
+ */
225
+
202
226
  get itemIndex() {
203
227
  return this._itemIndex;
204
228
  }
@@ -315,7 +339,6 @@ class AffiliationLayout extends _collection.default {
315
339
  _trackViewables() {} // omit default behavior for we want to track by other means
316
340
 
317
341
  _onClick(event) {
318
- super._onClick(event);
319
342
  const element = event.target;
320
343
  if (element.closest(`[data-role="previous"]`)) {
321
344
  this.previous();
@@ -325,6 +348,7 @@ class AffiliationLayout extends _collection.default {
325
348
  this.next();
326
349
  return;
327
350
  }
351
+ super._onClick(event);
328
352
  }
329
353
  }
330
354
  exports.default = AffiliationLayout;
@@ -25,6 +25,8 @@ exports.titleBlock = titleBlock;
25
25
  exports.unimplemented = unimplemented;
26
26
  var _commons = require("@miso.ai/commons");
27
27
  var _constants = require("../constants.js");
28
+ const _excluded = ["classSuffix", "role"];
29
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.includes(n)) continue; t[n] = r[n]; } return t; }
28
30
  function requiresImplementation() {
29
31
  for (var _len = arguments.length, names = new Array(_len), _key = 0; _key < _len; _key++) {
30
32
  names[_key] = arguments[_key];
@@ -61,8 +63,12 @@ function affiliation(layout, state, data, meta) {
61
63
  const {
62
64
  templates
63
65
  } = layout;
64
- const [openTag, closeTag] = tagPair(layout, data);
65
- return [openTag, (templates.infoBlock || templates.affiliationInfoBlock || affiliationInfoBlock)(layout, data, meta), (templates.imageBlock || imageBlock)(layout, data, meta), (templates.brandBlock || brandBlock)(layout, data, meta), closeTag].join('');
66
+ const [openTag, closeTag] = tagPair(layout, data, {
67
+ link: false
68
+ });
69
+ return [openTag, (templates.infoBlock || templates.affiliationInfoBlock || affiliationInfoBlock)(layout, data, meta), (templates.imageBlock || imageBlock)(layout, data, Object.assign({
70
+ brand: true
71
+ }, meta)), closeTag].join('');
66
72
  }
67
73
  function affiliationInfoBlock(layout, data, meta) {
68
74
  const {
@@ -169,26 +175,28 @@ function discountRateText(layout, _ref9) {
169
175
  } = _ref9;
170
176
  return `(${discount_rate_percent}% off)`;
171
177
  }
172
- function imageBlock(_ref10, _ref11) {
173
- let {
174
- className
175
- } = _ref10;
176
- let {
178
+ function imageBlock(layout, data, meta) {
179
+ const {
180
+ className,
181
+ templates
182
+ } = layout;
183
+ const {
177
184
  cover_image
178
- } = _ref11;
185
+ } = data;
179
186
  if (!cover_image) {
180
187
  return '';
181
188
  }
182
189
  const img = `<img class="${className}__item-cover-image" src="${cover_image}">`;
183
- return `<div class="${className}__item-cover-image-container">${img}</div>`;
190
+ const brand = meta.brand ? (templates.brandBlock || brandBlock)(layout, data, meta) : '';
191
+ return `<div class="${className}__item-cover-image-container">${img}${brand}</div>`;
184
192
  }
185
- function indexBlock(_ref12, data, _ref13) {
193
+ function indexBlock(_ref10, data, _ref11) {
186
194
  let {
187
195
  className
188
- } = _ref12;
196
+ } = _ref10;
189
197
  let {
190
198
  index
191
- } = _ref13;
199
+ } = _ref11;
192
200
  return `<div class="${className}__item-index-container"><span class="${className}__item-index miso-citation-index" data-index="${index + 1}"></span></div>`;
193
201
  }
194
202
  function ctaBlock(layout, data, meta) {
@@ -196,38 +204,45 @@ function ctaBlock(layout, data, meta) {
196
204
  className,
197
205
  templates
198
206
  } = layout;
199
- let _cta = templates.cta || cta;
200
- if (typeof _cta === 'function') {
201
- _cta = _cta(layout, data, meta);
202
- }
203
- return _cta ? `<div class="${className}__item-cta-container">${_cta}</div>` : '';
207
+ const cta = helpers.asFunction(templates.cta)(layout, data, meta);
208
+ return cta ? `<div class="${className}__item-cta-container">${cta}</div>` : '';
204
209
  }
205
210
  function cta(layout, data, meta) {
206
211
  const {
207
- className,
208
212
  templates
209
213
  } = layout;
210
- let text = templates.ctaText;
211
- if (typeof text === 'function') {
212
- text = text(layout, data, meta);
214
+ const {
215
+ url
216
+ } = data;
217
+ if (!url) {
218
+ return '';
213
219
  }
214
- return text ? `<div class="${className}__item-cta">${text}</div>` : '';
220
+ const [openTag, closeTag] = tagPair(layout, {
221
+ url
222
+ }, {
223
+ classSuffix: 'item-cta',
224
+ role: 'cta'
225
+ });
226
+ const ctaText = helpers.asFunction(templates.ctaText)(layout, data, meta);
227
+ return ctaText ? `${openTag}${ctaText}${closeTag}` : '';
215
228
  }
216
229
 
217
230
  // helpers //
218
- function tagPair(_ref14, _ref15) {
231
+ function tagPair(_ref13, _ref14) {
219
232
  let {
220
233
  className,
221
234
  options = {}
222
- } = _ref14;
235
+ } = _ref13;
223
236
  let {
224
237
  product_id,
225
238
  url
226
- } = _ref15;
239
+ } = _ref14;
240
+ let _ref12 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
227
241
  let {
228
- classSuffix = 'item-body',
229
- role = 'item'
230
- } = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
242
+ classSuffix = 'item-body',
243
+ role = 'item'
244
+ } = _ref12,
245
+ meta = _objectWithoutPropertiesLoose(_ref12, _excluded);
231
246
  const {
232
247
  link = {}
233
248
  } = options;
@@ -235,8 +250,8 @@ function tagPair(_ref14, _ref15) {
235
250
  target = '_blank',
236
251
  rel = 'noopener'
237
252
  } = link; // TODO: other properties
238
- const tag = url ? 'a' : 'div';
239
- const urlAttrs = url ? `href="${url}" target="${target}" rel="${rel}"` : '';
253
+ const tag = meta.link !== false && url ? 'a' : 'div';
254
+ const urlAttrs = meta.link !== false && url ? `href="${url}" target="${target}" rel="${rel}"` : '';
240
255
  const productAttrs = product_id ? `${_constants.ATTR_DATA_MISO_PRODUCT_ID}="${product_id}"` : '';
241
256
  const roleAttrs = role ? `data-role="${role}"` : '';
242
257
  return [`<${tag} class="${className}__${classSuffix}" ${roleAttrs} ${productAttrs} ${urlAttrs}>`, `</${tag}>`];
@@ -260,8 +275,13 @@ function formatDate(date) {
260
275
  throw new Error(`Invalid date format: ${fn}`);
261
276
  }
262
277
  }
278
+ function asFunction() {
279
+ let template = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
280
+ return typeof template === 'function' ? template : () => template;
281
+ }
263
282
  const helpers = exports.helpers = Object.freeze({
264
283
  tagPair,
265
284
  formatDate,
266
- escapeHtml: _commons.escapeHtml
285
+ escapeHtml: _commons.escapeHtml,
286
+ asFunction
267
287
  });
@@ -4,4 +4,4 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _default = exports.default = '1.10.0-beta.12';
7
+ var _default = exports.default = '1.10.0-beta.14';
package/package.json CHANGED
@@ -26,7 +26,7 @@
26
26
  "url": "https://github.com/MisoAI/miso-client-js-sdk/issues"
27
27
  },
28
28
  "dependencies": {
29
- "@miso.ai/commons": "1.10.0-beta.12"
29
+ "@miso.ai/commons": "1.10.0-beta.14"
30
30
  },
31
- "version": "1.10.0-beta.12"
31
+ "version": "1.10.0-beta.14"
32
32
  }
package/src/asset/svgs.js CHANGED
@@ -1,13 +1,23 @@
1
1
  import version from '../version.js';
2
2
 
3
+ function trianglePath(r) {
4
+ const l = 100;
5
+ const d = r * Math.tan(3 * Math.PI / 8);
6
+ const e = d * Math.sin(Math.PI / 4);
7
+ return `M${r} 0L${l-d} 0A${r} ${r} 0 0 1 ${l-e} ${e}L${e} ${l-e}A${r} ${r} 0 0 1 0 ${l-d}L0 ${r}Z`;
8
+ }
9
+
3
10
  const PREFIX = 'miso-ui-icon';
4
11
  const ID = `${PREFIX}-svg-${version.replaceAll('.', '_')}`;
5
12
 
6
- // all are CC0 SVGs
13
+ // CC0 SVGs
7
14
  const ICON_SEND = `<symbol id="${PREFIX}-send" viewBox="0 0 32 32"><path fill="currentColor" d="M11.499,19.173l5.801,-5.849c0.389,-0.392 1.022,-0.394 1.414,-0.006c0.392,0.389 0.395,1.022 0.006,1.414l-5.798,5.847l5.306,8.002c0.207,0.313 0.572,0.483 0.945,0.441c0.373,-0.042 0.691,-0.289 0.824,-0.64l9.024,-23.904c0.138,-0.366 0.05,-0.78 -0.226,-1.058c-0.276,-0.278 -0.689,-0.369 -1.057,-0.233l-24.004,8.892c-0.353,0.13 -0.602,0.448 -0.646,0.821c-0.044,0.373 0.125,0.74 0.438,0.948l7.973,5.325Z"/></symbol>`;
8
15
  const ICON_SEARCH = `<symbol id="${PREFIX}-search" viewBox="0 0 24 24"><path fill="currentColor" d="M4 11C4 7.13401 7.13401 4 11 4C14.866 4 18 7.13401 18 11C18 14.866 14.866 18 11 18C7.13401 18 4 14.866 4 11ZM11 2C6.02944 2 2 6.02944 2 11C2 15.9706 6.02944 20 11 20C13.125 20 15.078 19.2635 16.6177 18.0319L20.2929 21.7071C20.6834 22.0976 21.3166 22.0976 21.7071 21.7071C22.0976 21.3166 22.0976 20.6834 21.7071 20.2929L18.0319 16.6177C19.2635 15.078 20 13.125 20 11C20 6.02944 15.9706 2 11 2Z"/></symbol>`;
9
16
 
10
- const ICONS = [ICON_SEND, ICON_SEARCH];
17
+ // Custom SVGs
18
+ const ICON_TRIANGLE = `<symbol id="${PREFIX}-triangle" viewBox="-5 -5 105 105"><path d="${trianglePath(5)}"/></symbol>`;
19
+
20
+ const ICONS = [ICON_SEND, ICON_SEARCH, ICON_TRIANGLE];
11
21
 
12
22
  const SPRITES_SVG = `<svg id="${ID}" style="display:none;">${ICONS.join('')}</svg>`;
13
23
 
@@ -29,3 +39,4 @@ function getSvg(name) {
29
39
 
30
40
  export const SEND = getSvg('send');
31
41
  export const SEARCH = getSvg('search');
42
+ export const TRIANGLE = getSvg('triangle');
@@ -1,7 +1,8 @@
1
1
  import { CarouselItemViewabilityObserver, requestAnimationFrame as raf } from '@miso.ai/commons';
2
2
  import { STATUS, LAYOUT_CATEGORY, EVENT_TYPE } from '../../constants.js';
3
3
  import CollectionLayout from '../list/collection.js';
4
- import { affiliation } from '../templates.js';
4
+ import { affiliation, helpers } from '../templates.js';
5
+ import { TRIANGLE } from '../../asset/svgs.js';
5
6
 
6
7
  const TYPE = 'affiliation';
7
8
  const DEFAULT_CLASSNAME = 'miso-affiliation';
@@ -20,15 +21,24 @@ function ready(layout, state) {
20
21
  const items = layout._getItems(state);
21
22
 
22
23
  if (items && items.length > 0) {
23
- return templates.control(layout, state, 'previous') + templates.body(layout, state) + templates.control(layout, state, 'next');
24
+ return templates.controlContainer(layout, state, 'previous') + templates.body(layout, state) + templates.controlContainer(layout, state, 'next');
24
25
  } else {
25
26
  return templates.empty(layout, state);
26
27
  }
27
28
  }
28
29
 
30
+ function controlContainer(layout, state, direction) {
31
+ const { className, templates } = layout;
32
+ return `<div class="${className}__control-${direction}-container">${templates.control(layout, state, direction)}</div>`;
33
+ }
34
+
29
35
  function control(layout, state, direction) {
30
- const { className } = layout;
31
- return `<div class="${className}__control-${direction}" data-role="${direction}"></div>`;
36
+ const { className, templates } = layout;
37
+ return `<div class="${className}__control-${direction}" data-role="${direction}">${templates.controlIcon(layout, state, direction)}</div>`;
38
+ }
39
+
40
+ function controlIcon(layout, state, direction) {
41
+ return TRIANGLE;
32
42
  }
33
43
 
34
44
  function body(layout, state) {
@@ -37,49 +47,56 @@ function body(layout, state) {
37
47
  return `<div class="${className}__body">${templates.list(layout, state, items)}</div>`;
38
48
  }
39
49
 
40
- function header(layout, state) {
41
- const { className, templates } = layout;
42
- let { headerText } = templates;
43
- if (typeof headerText === 'function') {
44
- headerText = headerText(layout, state);
45
- }
46
- if (!headerText) {
47
- return '';
48
- }
49
- return `<div class="${className}__header"><div class="${className}__header-tab">${headerText}</div></div>`;
50
- }
51
-
52
50
  function item(layout, state, value, index) {
53
51
  const { className, templates, options } = layout;
54
52
  const { itemType } = options;
55
53
  const header = templates.itemHeader(layout, state, value, { index });
56
54
  const body = templates[itemType](layout, state, value, { index });
57
- return `<li class="${className}__item">${header}${body}</li>`;
55
+ return `<li class="${className}__item"><div class="${className}__item-inner">${header}${body}</div></li>`;
58
56
  }
59
57
 
60
58
  function itemHeader(layout, state, value, meta) {
61
59
  const { className, templates } = layout;
62
- let { headerText } = templates;
63
- if (typeof headerText === 'function') {
64
- headerText = headerText(layout, state, value, meta);
65
- }
66
- if (!headerText) {
60
+ let { itemHeaderLeftText, itemHeaderRightText } = templates;
61
+ itemHeaderLeftText = helpers.asFunction(itemHeaderLeftText)(layout, state, value, meta);
62
+ itemHeaderRightText = helpers.asFunction(itemHeaderRightText)(layout, state, value, meta);
63
+ return `<div class="${className}__item-header">
64
+ <div class="${className}__item-header-left">${itemHeaderLeftText}</div>
65
+ <div class="${className}__item-header-right">${itemHeaderRightText}</div>
66
+ </div>`;
67
+ }
68
+
69
+ function itemHeaderRightText(layout, state, value, meta) {
70
+ const { templates } = layout;
71
+ const logoImg = helpers.asFunction(templates.logoImg)(layout, state, value, meta);
72
+ return logoImg ? `Selected by ${logoImg}` : '';
73
+ }
74
+
75
+ function logoImg(layout, state, value, meta) {
76
+ const { className, templates } = layout;
77
+ const logoUrl = helpers.asFunction(templates.logoUrl)(layout, state, value, meta);
78
+ if (!logoUrl) {
67
79
  return '';
68
80
  }
69
- return `<div class="${className}__item-header"><div class="${className}__item-header-tab">${headerText}</div></div>`;
81
+ const logoAltText = helpers.asFunction(templates.logoAltText)(layout, state, value, meta);
82
+ const logoAltTextAttr = logoAltText ? ` alt="${logoAltText}"` : '';
83
+ return `<img class="${className}__item-header-logo" src="${logoUrl}"${logoAltTextAttr}>`;
70
84
  }
71
85
 
72
86
  const DEFAULT_TEMPLATES = Object.freeze({
73
87
  root,
74
88
  [STATUS.READY]: ready,
89
+ controlContainer,
75
90
  control,
91
+ controlIcon,
76
92
  body,
77
- header,
78
93
  item,
79
94
  itemHeader,
80
95
  affiliation,
81
- ctaText: 'View',
82
- headerText: 'Featured',
96
+ ctaText: 'View deal',
97
+ itemHeaderLeftText: `Today's best deals`,
98
+ itemHeaderRightText,
99
+ logoImg,
83
100
  });
84
101
 
85
102
  const INHERITED_DEFAULT_TEMPLATES = Object.freeze({
@@ -87,9 +104,10 @@ const INHERITED_DEFAULT_TEMPLATES = Object.freeze({
87
104
  ...DEFAULT_TEMPLATES,
88
105
  });
89
106
 
107
+ /*
90
108
  function normalizeAutoplayOptions(options) {
91
109
  if (options === true) {
92
- options = { interval: 5000 };
110
+ options = { interval: 10000 };
93
111
  } else if (typeof options === 'number') {
94
112
  if (options <= 0) {
95
113
  options = false;
@@ -109,6 +127,7 @@ function autoplayOptionsEquals(a, b) {
109
127
  }
110
128
  return a.interval === b.interval;
111
129
  }
130
+ */
112
131
 
113
132
  export default class AffiliationLayout extends CollectionLayout {
114
133
 
@@ -135,9 +154,12 @@ export default class AffiliationLayout extends CollectionLayout {
135
154
  this._displayedCount = undefined;
136
155
  this._displayedIndex = undefined;
137
156
  this._viewable = undefined;
138
- this._autoplay = {};
139
157
 
158
+ // TODO: extract this
159
+ /*
160
+ this._autoplay = {};
140
161
  this.autoplay(autoplay);
162
+ */
141
163
  }
142
164
 
143
165
  initialize(view) {
@@ -146,7 +168,8 @@ export default class AffiliationLayout extends CollectionLayout {
146
168
  this._viewable = new CarouselItemViewabilityObserver(this._onViewable.bind(this), options);
147
169
  }
148
170
 
149
- autoplay(options = true) {
171
+ /*
172
+ autoplay(options = false) {
150
173
  options = normalizeAutoplayOptions(options);
151
174
  if (autoplayOptionsEquals(options, this._autoplay.options)) {
152
175
  return;
@@ -162,6 +185,7 @@ export default class AffiliationLayout extends CollectionLayout {
162
185
  this._autoplay.intervalId = setInterval(() => this.next(), options.interval);
163
186
  }
164
187
  }
188
+ */
165
189
 
166
190
  get itemIndex() {
167
191
  return this._itemIndex;
@@ -280,7 +304,6 @@ export default class AffiliationLayout extends CollectionLayout {
280
304
  _trackViewables() {} // omit default behavior for we want to track by other means
281
305
 
282
306
  _onClick(event) {
283
- super._onClick(event);
284
307
  const element = event.target;
285
308
  if (element.closest(`[data-role="previous"]`)) {
286
309
  this.previous();
@@ -290,6 +313,7 @@ export default class AffiliationLayout extends CollectionLayout {
290
313
  this.next();
291
314
  return;
292
315
  }
316
+ super._onClick(event);
293
317
  }
294
318
 
295
319
  }
@@ -44,12 +44,11 @@ export function article(layout, state, data, meta) {
44
44
 
45
45
  export function affiliation(layout, state, data, meta) {
46
46
  const { templates } = layout;
47
- const [openTag, closeTag] = tagPair(layout, data);
47
+ const [openTag, closeTag] = tagPair(layout, data, { link: false});
48
48
  return [
49
49
  openTag,
50
50
  (templates.infoBlock || templates.affiliationInfoBlock || affiliationInfoBlock)(layout, data, meta),
51
- (templates.imageBlock || imageBlock)(layout, data, meta),
52
- (templates.brandBlock || brandBlock)(layout, data, meta),
51
+ (templates.imageBlock || imageBlock)(layout, data, { brand: true, ...meta, }),
53
52
  closeTag,
54
53
  ].join('');
55
54
  }
@@ -133,12 +132,15 @@ export function discountRateText(layout, { discount_rate_percent }) {
133
132
  return `(${discount_rate_percent}% off)`;
134
133
  }
135
134
 
136
- export function imageBlock({ className }, { cover_image }) {
135
+ export function imageBlock(layout, data, meta) {
136
+ const { className, templates } = layout;
137
+ const { cover_image } = data;
137
138
  if (!cover_image) {
138
139
  return '';
139
140
  }
140
141
  const img = `<img class="${className}__item-cover-image" src="${cover_image}">`;
141
- return `<div class="${className}__item-cover-image-container">${img}</div>`;
142
+ const brand = meta.brand ? (templates.brandBlock || brandBlock)(layout, data, meta) : '';
143
+ return `<div class="${className}__item-cover-image-container">${img}${brand}</div>`;
142
144
  }
143
145
 
144
146
  export function indexBlock({ className }, data, { index }) {
@@ -147,28 +149,27 @@ export function indexBlock({ className }, data, { index }) {
147
149
 
148
150
  export function ctaBlock(layout, data, meta) {
149
151
  const { className, templates } = layout;
150
- let _cta = templates.cta || cta;
151
- if (typeof _cta === 'function') {
152
- _cta = _cta(layout, data, meta);
153
- }
154
- return _cta ? `<div class="${className}__item-cta-container">${_cta}</div>` : '';
152
+ const cta = helpers.asFunction(templates.cta)(layout, data, meta);
153
+ return cta ? `<div class="${className}__item-cta-container">${cta}</div>` : '';
155
154
  }
156
155
 
157
156
  export function cta(layout, data, meta) {
158
- const { className, templates } = layout;
159
- let text = templates.ctaText;
160
- if (typeof text === 'function') {
161
- text = text(layout, data, meta);
157
+ const { templates } = layout;
158
+ const { url } = data;
159
+ if (!url) {
160
+ return '';
162
161
  }
163
- return text ? `<div class="${className}__item-cta">${text}</div>` : '';
162
+ const [openTag, closeTag] = tagPair(layout, { url }, { classSuffix: 'item-cta', role: 'cta' });
163
+ const ctaText = helpers.asFunction(templates.ctaText)(layout, data, meta);
164
+ return ctaText ? `${openTag}${ctaText}${closeTag}` : '';
164
165
  }
165
166
 
166
167
  // helpers //
167
- function tagPair({ className, options = {} }, { product_id, url }, { classSuffix = 'item-body', role = 'item' } = {}) {
168
+ function tagPair({ className, options = {} }, { product_id, url }, { classSuffix = 'item-body', role = 'item', ...meta } = {}) {
168
169
  const { link = {} } = options;
169
170
  const { target = '_blank', rel = 'noopener' } = link; // TODO: other properties
170
- const tag = url ? 'a' : 'div';
171
- const urlAttrs = url ? `href="${url}" target="${target}" rel="${rel}"` : '';
171
+ const tag = meta.link !== false && url ? 'a' : 'div';
172
+ const urlAttrs = meta.link !== false && url ? `href="${url}" target="${target}" rel="${rel}"` : '';
172
173
  const productAttrs = product_id ? `${ATTR_DATA_MISO_PRODUCT_ID}="${product_id}"` : '';
173
174
  const roleAttrs = role ? `data-role="${role}"` : '';
174
175
  return [`<${tag} class="${className}__${classSuffix}" ${roleAttrs} ${productAttrs} ${urlAttrs}>`, `</${tag}>`];
@@ -189,8 +190,13 @@ function formatDate(date, fn = DEFAULT_DATE_OPTIONS) {
189
190
  }
190
191
  }
191
192
 
193
+ function asFunction(template = '') {
194
+ return typeof template === 'function' ? template : () => template;
195
+ }
196
+
192
197
  export const helpers = Object.freeze({
193
198
  tagPair,
194
199
  formatDate,
195
200
  escapeHtml,
201
+ asFunction,
196
202
  });
package/src/version.js CHANGED
@@ -1 +1 @@
1
- export default '1.10.0-beta.12';
1
+ export default '1.10.0-beta.14';