@financial-times/n-myft-ui 28.2.0 → 28.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -65,6 +65,7 @@
65
65
  "karma-sinon": "^1.0.5",
66
66
  "karma-sinon-chai": "2.0.2",
67
67
  "karma-sourcemap-loader": "^0.3.7",
68
+ "karma-viewport": "^1.0.9",
68
69
  "karma-webpack": "^4.0.2",
69
70
  "lintspaces-cli": "^0.7.0",
70
71
  "lolex": "5.1.1",
@@ -3383,6 +3384,84 @@
3383
3384
  "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
3384
3385
  "dev": true
3385
3386
  },
3387
+ "node_modules/@types/karma": {
3388
+ "version": "6.3.3",
3389
+ "resolved": "https://registry.npmjs.org/@types/karma/-/karma-6.3.3.tgz",
3390
+ "integrity": "sha512-nRMec4mTCt+tkpRqh5/pAxmnjzEgAaalIq7mdfLFH88gSRC8+bxejLiSjHMMT/vHIhJHqg4GPIGCnCFbwvDRww==",
3391
+ "dev": true,
3392
+ "dependencies": {
3393
+ "@types/node": "*",
3394
+ "log4js": "^6.4.1"
3395
+ }
3396
+ },
3397
+ "node_modules/@types/karma/node_modules/date-format": {
3398
+ "version": "4.0.13",
3399
+ "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.13.tgz",
3400
+ "integrity": "sha512-bnYCwf8Emc3pTD8pXnre+wfnjGtfi5ncMDKy7+cWZXbmRAsdWkOQHrfC1yz/KiwP5thDp2kCHWYWKBX4HP1hoQ==",
3401
+ "dev": true,
3402
+ "engines": {
3403
+ "node": ">=4.0"
3404
+ }
3405
+ },
3406
+ "node_modules/@types/karma/node_modules/flatted": {
3407
+ "version": "3.2.6",
3408
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz",
3409
+ "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==",
3410
+ "dev": true
3411
+ },
3412
+ "node_modules/@types/karma/node_modules/fs-extra": {
3413
+ "version": "8.1.0",
3414
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
3415
+ "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
3416
+ "dev": true,
3417
+ "dependencies": {
3418
+ "graceful-fs": "^4.2.0",
3419
+ "jsonfile": "^4.0.0",
3420
+ "universalify": "^0.1.0"
3421
+ },
3422
+ "engines": {
3423
+ "node": ">=6 <7 || >=8"
3424
+ }
3425
+ },
3426
+ "node_modules/@types/karma/node_modules/jsonfile": {
3427
+ "version": "4.0.0",
3428
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
3429
+ "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
3430
+ "dev": true,
3431
+ "optionalDependencies": {
3432
+ "graceful-fs": "^4.1.6"
3433
+ }
3434
+ },
3435
+ "node_modules/@types/karma/node_modules/log4js": {
3436
+ "version": "6.6.1",
3437
+ "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.6.1.tgz",
3438
+ "integrity": "sha512-J8VYFH2UQq/xucdNu71io4Fo+purYYudyErgBbswWKO0MC6QVOERRomt5su/z6d3RJSmLyTGmXl3Q/XjKCf+/A==",
3439
+ "dev": true,
3440
+ "dependencies": {
3441
+ "date-format": "^4.0.13",
3442
+ "debug": "^4.3.4",
3443
+ "flatted": "^3.2.6",
3444
+ "rfdc": "^1.3.0",
3445
+ "streamroller": "^3.1.2"
3446
+ },
3447
+ "engines": {
3448
+ "node": ">=8.0"
3449
+ }
3450
+ },
3451
+ "node_modules/@types/karma/node_modules/streamroller": {
3452
+ "version": "3.1.2",
3453
+ "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.2.tgz",
3454
+ "integrity": "sha512-wZswqzbgGGsXYIrBYhOE0yP+nQ6XRk7xDcYwuQAGTYXdyAUmvgVFE0YU1g5pvQT0m7GBaQfYcSnlHbapuK0H0A==",
3455
+ "dev": true,
3456
+ "dependencies": {
3457
+ "date-format": "^4.0.13",
3458
+ "debug": "^4.3.4",
3459
+ "fs-extra": "^8.1.0"
3460
+ },
3461
+ "engines": {
3462
+ "node": ">=8.0"
3463
+ }
3464
+ },
3386
3465
  "node_modules/@types/mdast": {
3387
3466
  "version": "3.0.10",
3388
3467
  "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz",
@@ -12267,6 +12346,15 @@
12267
12346
  "graceful-fs": "^4.1.6"
12268
12347
  }
12269
12348
  },
12349
+ "node_modules/jsonschema": {
12350
+ "version": "1.4.1",
12351
+ "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz",
12352
+ "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==",
12353
+ "dev": true,
12354
+ "engines": {
12355
+ "node": "*"
12356
+ }
12357
+ },
12270
12358
  "node_modules/jsprim": {
12271
12359
  "version": "1.4.2",
12272
12360
  "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
@@ -12441,6 +12529,16 @@
12441
12529
  "graceful-fs": "^4.1.2"
12442
12530
  }
12443
12531
  },
12532
+ "node_modules/karma-viewport": {
12533
+ "version": "1.0.9",
12534
+ "resolved": "https://registry.npmjs.org/karma-viewport/-/karma-viewport-1.0.9.tgz",
12535
+ "integrity": "sha512-E1xVe66vBQtI66TGOtZMzV5nf6BW5tW4TQVUqPK+oakVLdsG/ZUG688tGK0lL1q0t7nfQD1dwLD8Z9Guu/RVdg==",
12536
+ "dev": true,
12537
+ "dependencies": {
12538
+ "@types/karma": "^6.3.3",
12539
+ "jsonschema": "^1.4.0"
12540
+ }
12541
+ },
12444
12542
  "node_modules/karma-webpack": {
12445
12543
  "version": "4.0.2",
12446
12544
  "resolved": "https://registry.npmjs.org/karma-webpack/-/karma-webpack-4.0.2.tgz",
@@ -25822,6 +25920,74 @@
25822
25920
  "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
25823
25921
  "dev": true
25824
25922
  },
25923
+ "@types/karma": {
25924
+ "version": "6.3.3",
25925
+ "resolved": "https://registry.npmjs.org/@types/karma/-/karma-6.3.3.tgz",
25926
+ "integrity": "sha512-nRMec4mTCt+tkpRqh5/pAxmnjzEgAaalIq7mdfLFH88gSRC8+bxejLiSjHMMT/vHIhJHqg4GPIGCnCFbwvDRww==",
25927
+ "dev": true,
25928
+ "requires": {
25929
+ "@types/node": "*",
25930
+ "log4js": "^6.4.1"
25931
+ },
25932
+ "dependencies": {
25933
+ "date-format": {
25934
+ "version": "4.0.13",
25935
+ "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.13.tgz",
25936
+ "integrity": "sha512-bnYCwf8Emc3pTD8pXnre+wfnjGtfi5ncMDKy7+cWZXbmRAsdWkOQHrfC1yz/KiwP5thDp2kCHWYWKBX4HP1hoQ==",
25937
+ "dev": true
25938
+ },
25939
+ "flatted": {
25940
+ "version": "3.2.6",
25941
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz",
25942
+ "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==",
25943
+ "dev": true
25944
+ },
25945
+ "fs-extra": {
25946
+ "version": "8.1.0",
25947
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
25948
+ "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
25949
+ "dev": true,
25950
+ "requires": {
25951
+ "graceful-fs": "^4.2.0",
25952
+ "jsonfile": "^4.0.0",
25953
+ "universalify": "^0.1.0"
25954
+ }
25955
+ },
25956
+ "jsonfile": {
25957
+ "version": "4.0.0",
25958
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
25959
+ "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
25960
+ "dev": true,
25961
+ "requires": {
25962
+ "graceful-fs": "^4.1.6"
25963
+ }
25964
+ },
25965
+ "log4js": {
25966
+ "version": "6.6.1",
25967
+ "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.6.1.tgz",
25968
+ "integrity": "sha512-J8VYFH2UQq/xucdNu71io4Fo+purYYudyErgBbswWKO0MC6QVOERRomt5su/z6d3RJSmLyTGmXl3Q/XjKCf+/A==",
25969
+ "dev": true,
25970
+ "requires": {
25971
+ "date-format": "^4.0.13",
25972
+ "debug": "^4.3.4",
25973
+ "flatted": "^3.2.6",
25974
+ "rfdc": "^1.3.0",
25975
+ "streamroller": "^3.1.2"
25976
+ }
25977
+ },
25978
+ "streamroller": {
25979
+ "version": "3.1.2",
25980
+ "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.2.tgz",
25981
+ "integrity": "sha512-wZswqzbgGGsXYIrBYhOE0yP+nQ6XRk7xDcYwuQAGTYXdyAUmvgVFE0YU1g5pvQT0m7GBaQfYcSnlHbapuK0H0A==",
25982
+ "dev": true,
25983
+ "requires": {
25984
+ "date-format": "^4.0.13",
25985
+ "debug": "^4.3.4",
25986
+ "fs-extra": "^8.1.0"
25987
+ }
25988
+ }
25989
+ }
25990
+ },
25825
25991
  "@types/mdast": {
25826
25992
  "version": "3.0.10",
25827
25993
  "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz",
@@ -33156,6 +33322,12 @@
33156
33322
  "universalify": "^0.1.2"
33157
33323
  }
33158
33324
  },
33325
+ "jsonschema": {
33326
+ "version": "1.4.1",
33327
+ "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz",
33328
+ "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==",
33329
+ "dev": true
33330
+ },
33159
33331
  "jsprim": {
33160
33332
  "version": "1.4.2",
33161
33333
  "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
@@ -33415,6 +33587,16 @@
33415
33587
  "graceful-fs": "^4.1.2"
33416
33588
  }
33417
33589
  },
33590
+ "karma-viewport": {
33591
+ "version": "1.0.9",
33592
+ "resolved": "https://registry.npmjs.org/karma-viewport/-/karma-viewport-1.0.9.tgz",
33593
+ "integrity": "sha512-E1xVe66vBQtI66TGOtZMzV5nf6BW5tW4TQVUqPK+oakVLdsG/ZUG688tGK0lL1q0t7nfQD1dwLD8Z9Guu/RVdg==",
33594
+ "dev": true,
33595
+ "requires": {
33596
+ "@types/karma": "^6.3.3",
33597
+ "jsonschema": "^1.4.0"
33598
+ }
33599
+ },
33418
33600
  "karma-webpack": {
33419
33601
  "version": "4.0.2",
33420
33602
  "resolved": "https://registry.npmjs.org/karma-webpack/-/karma-webpack-4.0.2.tgz",
package/karma.conf.js CHANGED
@@ -10,7 +10,7 @@ module.exports = function (karma) {
10
10
 
11
11
  // frameworks to use
12
12
  // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
13
- frameworks: ['mocha', 'chai', 'sinon', 'sinon-chai'],
13
+ frameworks: ['mocha', 'chai', 'sinon', 'sinon-chai', 'viewport'],
14
14
 
15
15
  // list of files / patterns to load in the browser
16
16
  files: [
@@ -110,7 +110,8 @@ module.exports = function (karma) {
110
110
  require('karma-webpack'),
111
111
  require('karma-chrome-launcher'),
112
112
  require('karma-browserstack-launcher'),
113
- require('karma-html-reporter')
113
+ require('karma-html-reporter'),
114
+ require('karma-viewport')
114
115
  ],
115
116
  client: {
116
117
  mocha: {
package/myft/main.scss CHANGED
@@ -323,4 +323,34 @@ $spacing-unit: 20px;
323
323
  }
324
324
  }
325
325
  }
326
+
327
+ .myft-notification {
328
+ background: oColorsByName('white-80');
329
+ box-sizing: border-box;
330
+ display: flex;
331
+ align-items: center;
332
+ justify-content: center;
333
+ position: absolute;
334
+ border-radius: 5px;
335
+ font-family: MetricWeb, sans-serif;
336
+ font-size: 18px;
337
+ }
338
+
339
+ .share-nav__vertical {
340
+ .myft-notification {
341
+ top: 175px;
342
+ width: 340px;
343
+ height: 44px;
344
+ left: 50px;
345
+ }
346
+ }
347
+
348
+ .share-nav__horizontal {
349
+ .myft-notification {
350
+ top: -52px;
351
+ width: 340px;
352
+ height: 44px;
353
+ z-index: 10;
354
+ }
355
+ }
326
356
  }
@@ -0,0 +1,5 @@
1
+ export default function stringToHTMLElement (string) {
2
+ const template = document.createElement('template');
3
+ template.innerHTML = string.trim();
4
+ return template.content.firstChild;
5
+ }
@@ -0,0 +1,7 @@
1
+ const MOBILE_BREAKPOINT = 980;
2
+
3
+ export default function isMobile () {
4
+ const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
5
+
6
+ return vw <= MOBILE_BREAKPOINT;
7
+ }
package/myft/ui/lists.js CHANGED
@@ -5,8 +5,10 @@ import * as myFtUiButtonStates from './lib/button-states';
5
5
  import nNotification from '@financial-times/n-notification';
6
6
  import { uuid } from 'n-ui-foundations';
7
7
  import getToken from './lib/get-csrf-token';
8
+ import isMobile from './lib/is-mobile';
8
9
  import oForms from '@financial-times/o-forms';
9
10
  import openSaveArticleToListVariant from './save-article-to-list-variant';
11
+ import stringToHTMLElement from './lib/convert-string-to-html-element';
10
12
 
11
13
  const delegate = new Delegate(document.body);
12
14
  const csrfToken = getToken();
@@ -265,14 +267,23 @@ function initialEventListeners () {
265
267
  // Checks if the createListAndSaveArticle variant is active
266
268
  // and will show the variant overlay if the user has no lists,
267
269
  // otherwise it will show the classic overlay
268
- const createNewListDesign = event.currentTarget.querySelector('[data-myft-ui-save-new="manageArticleLists"]');
269
- if (createNewListDesign) {
270
+ const newListDesign = event.currentTarget.querySelector('[data-myft-ui-save-new="manageArticleLists"]');
271
+ if (newListDesign) {
270
272
  return openCreateListAndAddArticleOverlay(contentId);
271
273
  }
272
274
 
273
275
  handleArticleSaved(contentId);
274
276
  });
275
277
 
278
+ document.body.addEventListener('myft.user.saved.content.remove', event => {
279
+ const contentId = event.detail.subject;
280
+
281
+ const newListDesign = event.currentTarget.querySelector('[data-myft-ui-save-new="manageArticleLists"]');
282
+ if (newListDesign) {
283
+ return showUnsavedNotification(contentId);
284
+ }
285
+ });
286
+
276
287
  delegate.on('click', '[data-myft-ui="copy-to-list"]', event => {
277
288
  event.preventDefault();
278
289
  showCopyToListOverlay(event.target.getAttribute('data-content-id'), event.target.getAttribute('data-actor-id'));
@@ -285,6 +296,34 @@ function initialEventListeners () {
285
296
  delegate.on('submit', '[data-myft-ui="contained"]', handleRemoveToggleSubmit);
286
297
  }
287
298
 
299
+ function showUnsavedNotification () {
300
+ const parentSelector = isMobile() ? '.o-share--horizontal' : '.o-share--vertical';
301
+ const parentNode = document.querySelector(parentSelector);
302
+
303
+ // We're not supporting multiple notifications for now
304
+ // If a notification is present, we'll silently avoid showing another
305
+ if (document.querySelector('.myft-notification') || !parentNode) {
306
+ return;
307
+ }
308
+
309
+ const content = `
310
+ <p role="alert">Removed from <a href="https://www.ft.com/myft/saved-articles">saved articles</a> in myFT</p>
311
+ `;
312
+
313
+ const contentNode = stringToHTMLElement(content);
314
+
315
+ const container = document.createElement('div');
316
+ container.className = 'myft-notification';
317
+ container.appendChild(contentNode);
318
+
319
+ parentNode.appendChild(container);
320
+
321
+ setTimeout(
322
+ () => parentNode.removeChild(container),
323
+ 5 * 1000
324
+ );
325
+ }
326
+
288
327
  export function init () {
289
328
  initialEventListeners();
290
329
  }
@@ -2,6 +2,8 @@ import Overlay from '@financial-times/o-overlay';
2
2
  import myFtClient from 'next-myft-client';
3
3
  import { uuid } from 'n-ui-foundations';
4
4
  import getToken from './lib/get-csrf-token';
5
+ import isMobile from './lib/is-mobile';
6
+ import stringToHTMLElement from './lib/convert-string-to-html-element';
5
7
 
6
8
  const csrfToken = getToken();
7
9
 
@@ -137,12 +139,6 @@ export default async function openSaveArticleToListVariant (name, contentId) {
137
139
  });
138
140
  }
139
141
 
140
- function stringToHTMLElement (string) {
141
- const template = document.createElement('template');
142
- template.innerHTML = string.trim();
143
- return template.content.firstChild;
144
- }
145
-
146
142
  function FormElement (createList) {
147
143
  const formString = `
148
144
  <form class="myft-ui-create-list-variant-form">
@@ -311,12 +307,6 @@ function positionOverlay (target) {
311
307
  }
312
308
  }
313
309
 
314
- function isMobile () {
315
- const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
316
-
317
- return vw <= 980;
318
- }
319
-
320
310
  function calculateLargerScreenHalf (target) {
321
311
  if (!target) {
322
312
  return 'BELOW';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@financial-times/n-myft-ui",
3
- "version": "28.2.0",
3
+ "version": "28.2.1",
4
4
  "description": "Client side component for interaction with myft",
5
5
  "main": "server.js",
6
6
  "scripts": {
@@ -65,6 +65,7 @@
65
65
  "karma-sinon": "^1.0.5",
66
66
  "karma-sinon-chai": "2.0.2",
67
67
  "karma-sourcemap-loader": "^0.3.7",
68
+ "karma-viewport": "^1.0.9",
68
69
  "karma-webpack": "^4.0.2",
69
70
  "lintspaces-cli": "^0.7.0",
70
71
  "lolex": "5.1.1",
@@ -0,0 +1,20 @@
1
+ const expect = require('chai').expect;
2
+ const isMobile = require('../../myft/ui/lib/is-mobile');
3
+
4
+ /* global viewport */
5
+
6
+ describe('IsMobile', function () {
7
+ afterEach(() => {
8
+ viewport.reset();
9
+ });
10
+
11
+ it('detects a desktop device', () => {
12
+ viewport.set(981, 800);
13
+ expect(isMobile()).to.be.false;
14
+ });
15
+
16
+ it('detects a mobile device', () => {
17
+ viewport.set(979, 800);
18
+ expect(isMobile()).to.be.true;
19
+ });
20
+ });