@miso.ai/client-sdk-ui 1.10.0-beta.13 → 1.10.0-beta.15

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,70 @@ 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
+ className,
103
+ templates
104
+ } = layout;
105
+ const logoText = _templates.helpers.asFunction(templates.logoText)(layout, state, value, meta) || '';
106
+ const logoImg = _templates.helpers.asFunction(templates.logoImg)(layout, state, value, meta);
107
+ return logoImg ? `<span class="${className}__item-header-logo-phrase">${logoText}</span>${logoImg}` : '';
108
+ }
109
+ function logoImg(layout, state, value, meta) {
110
+ const {
111
+ className,
112
+ templates
113
+ } = layout;
114
+ const logoUrl = _templates.helpers.asFunction(templates.logoUrl)(layout, state, value, meta);
115
+ if (!logoUrl) {
100
116
  return '';
101
117
  }
102
- return `<div class="${className}__item-header"><div class="${className}__item-header-tab">${headerText}</div></div>`;
118
+ const logoAltText = _templates.helpers.asFunction(templates.logoAltText)(layout, state, value, meta);
119
+ const logoAltTextAttr = logoAltText ? ` alt="${logoAltText}"` : '';
120
+ return `<img class="${className}__item-header-logo" src="${logoUrl}"${logoAltTextAttr}>`;
103
121
  }
104
122
  const DEFAULT_TEMPLATES = Object.freeze({
105
123
  root,
106
124
  [_constants.STATUS.READY]: ready,
125
+ controlContainer,
107
126
  control,
127
+ controlIcon,
108
128
  body,
109
- header,
110
129
  item,
111
130
  itemHeader,
112
131
  affiliation: _templates.affiliation,
113
- ctaText: 'View',
114
- headerText: 'Featured'
132
+ ctaText: 'View deal',
133
+ itemHeaderLeftText: `Today's best deals`,
134
+ itemHeaderRightText,
135
+ logoImg,
136
+ logoText: 'Selected by'
115
137
  });
116
138
  const INHERITED_DEFAULT_TEMPLATES = Object.freeze(Object.assign({}, _collection.default.defaultTemplates, DEFAULT_TEMPLATES));
139
+
140
+ /*
117
141
  function normalizeAutoplayOptions(options) {
118
142
  if (options === true) {
119
- options = {
120
- interval: 5000
121
- };
143
+ options = { interval: 10000 };
122
144
  } else if (typeof options === 'number') {
123
145
  if (options <= 0) {
124
146
  options = false;
125
147
  } else {
126
- options = {
127
- interval: Math.max(options, 500)
128
- };
148
+ options = { interval: Math.max(options, 500) };
129
149
  }
130
150
  }
131
151
  return options;
132
152
  }
153
+
133
154
  function autoplayOptionsEquals(a, b) {
134
155
  if (a === b) {
135
156
  return true;
@@ -139,6 +160,8 @@ function autoplayOptionsEquals(a, b) {
139
160
  }
140
161
  return a.interval === b.interval;
141
162
  }
163
+ */
164
+
142
165
  class AffiliationLayout extends _collection.default {
143
166
  static get category() {
144
167
  return _constants.LAYOUT_CATEGORY.AFFILIATION;
@@ -156,8 +179,7 @@ class AffiliationLayout extends _collection.default {
156
179
  let _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
157
180
  let {
158
181
  className = DEFAULT_CLASSNAME,
159
- templates,
160
- autoplay
182
+ templates
161
183
  } = _ref,
162
184
  options = _objectWithoutPropertiesLoose(_ref, _excluded);
163
185
  super(Object.assign({
@@ -170,8 +192,12 @@ class AffiliationLayout extends _collection.default {
170
192
  this._displayedCount = undefined;
171
193
  this._displayedIndex = undefined;
172
194
  this._viewable = undefined;
195
+
196
+ // TODO: extract this
197
+ /*
173
198
  this._autoplay = {};
174
199
  this.autoplay(autoplay);
200
+ */
175
201
  }
176
202
  initialize(view) {
177
203
  super.initialize(view);
@@ -180,8 +206,9 @@ class AffiliationLayout extends _collection.default {
180
206
  } = this._view.trackerOptions || {};
181
207
  this._viewable = new _commons.CarouselItemViewabilityObserver(this._onViewable.bind(this), options);
182
208
  }
183
- autoplay() {
184
- let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
209
+
210
+ /*
211
+ autoplay(options = false) {
185
212
  options = normalizeAutoplayOptions(options);
186
213
  if (autoplayOptionsEquals(options, this._autoplay.options)) {
187
214
  return;
@@ -189,9 +216,7 @@ class AffiliationLayout extends _collection.default {
189
216
  if (this._autoplay.options) {
190
217
  clearInterval(this._autoplay.intervalId);
191
218
  }
192
- this._autoplay = {
193
- options
194
- };
219
+ this._autoplay = { options };
195
220
  // TODO: use slower transition speed for autoplay
196
221
  // TODO: pause on hover
197
222
  // TODO: cooldown after manual interaction
@@ -199,6 +224,8 @@ class AffiliationLayout extends _collection.default {
199
224
  this._autoplay.intervalId = setInterval(() => this.next(), options.interval);
200
225
  }
201
226
  }
227
+ */
228
+
202
229
  get itemIndex() {
203
230
  return this._itemIndex;
204
231
  }
@@ -315,7 +342,6 @@ class AffiliationLayout extends _collection.default {
315
342
  _trackViewables() {} // omit default behavior for we want to track by other means
316
343
 
317
344
  _onClick(event) {
318
- super._onClick(event);
319
345
  const element = event.target;
320
346
  if (element.closest(`[data-role="previous"]`)) {
321
347
  this.previous();
@@ -325,6 +351,7 @@ class AffiliationLayout extends _collection.default {
325
351
  this.next();
326
352
  return;
327
353
  }
354
+ super._onClick(event);
328
355
  }
329
356
  }
330
357
  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.13';
7
+ var _default = exports.default = '1.10.0-beta.15';
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.13"
29
+ "@miso.ai/commons": "1.10.0-beta.15"
30
30
  },
31
- "version": "1.10.0-beta.13"
31
+ "version": "1.10.0-beta.15"
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,58 @@ 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 { className, templates } = layout;
71
+ const logoText = helpers.asFunction(templates.logoText)(layout, state, value, meta) || '';
72
+ const logoImg = helpers.asFunction(templates.logoImg)(layout, state, value, meta);
73
+ return logoImg ? `<span class="${className}__item-header-logo-phrase">${logoText}</span>${logoImg}` : '';
74
+ }
75
+
76
+ function logoImg(layout, state, value, meta) {
77
+ const { className, templates } = layout;
78
+ const logoUrl = helpers.asFunction(templates.logoUrl)(layout, state, value, meta);
79
+ if (!logoUrl) {
67
80
  return '';
68
81
  }
69
- return `<div class="${className}__item-header"><div class="${className}__item-header-tab">${headerText}</div></div>`;
82
+ const logoAltText = helpers.asFunction(templates.logoAltText)(layout, state, value, meta);
83
+ const logoAltTextAttr = logoAltText ? ` alt="${logoAltText}"` : '';
84
+ return `<img class="${className}__item-header-logo" src="${logoUrl}"${logoAltTextAttr}>`;
70
85
  }
71
86
 
72
87
  const DEFAULT_TEMPLATES = Object.freeze({
73
88
  root,
74
89
  [STATUS.READY]: ready,
90
+ controlContainer,
75
91
  control,
92
+ controlIcon,
76
93
  body,
77
- header,
78
94
  item,
79
95
  itemHeader,
80
96
  affiliation,
81
- ctaText: 'View',
82
- headerText: 'Featured',
97
+ ctaText: 'View deal',
98
+ itemHeaderLeftText: `Today's best deals`,
99
+ itemHeaderRightText,
100
+ logoImg,
101
+ logoText: 'Selected by',
83
102
  });
84
103
 
85
104
  const INHERITED_DEFAULT_TEMPLATES = Object.freeze({
@@ -87,9 +106,10 @@ const INHERITED_DEFAULT_TEMPLATES = Object.freeze({
87
106
  ...DEFAULT_TEMPLATES,
88
107
  });
89
108
 
109
+ /*
90
110
  function normalizeAutoplayOptions(options) {
91
111
  if (options === true) {
92
- options = { interval: 5000 };
112
+ options = { interval: 10000 };
93
113
  } else if (typeof options === 'number') {
94
114
  if (options <= 0) {
95
115
  options = false;
@@ -109,6 +129,7 @@ function autoplayOptionsEquals(a, b) {
109
129
  }
110
130
  return a.interval === b.interval;
111
131
  }
132
+ */
112
133
 
113
134
  export default class AffiliationLayout extends CollectionLayout {
114
135
 
@@ -135,9 +156,12 @@ export default class AffiliationLayout extends CollectionLayout {
135
156
  this._displayedCount = undefined;
136
157
  this._displayedIndex = undefined;
137
158
  this._viewable = undefined;
138
- this._autoplay = {};
139
159
 
160
+ // TODO: extract this
161
+ /*
162
+ this._autoplay = {};
140
163
  this.autoplay(autoplay);
164
+ */
141
165
  }
142
166
 
143
167
  initialize(view) {
@@ -146,7 +170,8 @@ export default class AffiliationLayout extends CollectionLayout {
146
170
  this._viewable = new CarouselItemViewabilityObserver(this._onViewable.bind(this), options);
147
171
  }
148
172
 
149
- autoplay(options = true) {
173
+ /*
174
+ autoplay(options = false) {
150
175
  options = normalizeAutoplayOptions(options);
151
176
  if (autoplayOptionsEquals(options, this._autoplay.options)) {
152
177
  return;
@@ -162,6 +187,7 @@ export default class AffiliationLayout extends CollectionLayout {
162
187
  this._autoplay.intervalId = setInterval(() => this.next(), options.interval);
163
188
  }
164
189
  }
190
+ */
165
191
 
166
192
  get itemIndex() {
167
193
  return this._itemIndex;
@@ -280,7 +306,6 @@ export default class AffiliationLayout extends CollectionLayout {
280
306
  _trackViewables() {} // omit default behavior for we want to track by other means
281
307
 
282
308
  _onClick(event) {
283
- super._onClick(event);
284
309
  const element = event.target;
285
310
  if (element.closest(`[data-role="previous"]`)) {
286
311
  this.previous();
@@ -290,6 +315,7 @@ export default class AffiliationLayout extends CollectionLayout {
290
315
  this.next();
291
316
  return;
292
317
  }
318
+ super._onClick(event);
293
319
  }
294
320
 
295
321
  }
@@ -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.13';
1
+ export default '1.10.0-beta.15';