@madgex/design-system 3.0.2 → 3.0.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 (109) hide show
  1. package/.eslintignore +2 -0
  2. package/.eslintrc.js +3 -3
  3. package/__tests__/.eslintrc.js +3 -3
  4. package/__tests__/unit/src/components/combobox.spec.js +4 -28
  5. package/__tests__/unit/src/components/notification.spec.js +14 -12
  6. package/__tests__/unit/src/components/popover.spec.js +4 -0
  7. package/__tests__/unit/tasks/css.spec.js +3 -2
  8. package/__tests__/unit/tasks/jsbundle.spec.js +3 -2
  9. package/__tests__/unit/tasks/svgsprite.spec.js +3 -2
  10. package/__tests__/unit/tasks/tokens.spec.js +3 -2
  11. package/coverage/cobertura-coverage.xml +389 -389
  12. package/coverage/components/accordion/accordion.js.html +164 -127
  13. package/coverage/components/accordion/index.html +23 -22
  14. package/coverage/components/button/button.js.html +3 -2
  15. package/coverage/components/button/index.html +3 -2
  16. package/coverage/components/inputs/combobox/combobox.js.html +3 -2
  17. package/coverage/components/inputs/combobox/index.html +3 -2
  18. package/coverage/components/inputs/combobox/vue-components/Combobox.vue.html +55 -54
  19. package/coverage/components/inputs/combobox/vue-components/ListBoxOption.vue.html +9 -8
  20. package/coverage/components/inputs/combobox/vue-components/index.html +21 -20
  21. package/coverage/components/inputs/file-upload/file-upload.js.html +7 -3
  22. package/coverage/components/inputs/file-upload/index.html +3 -2
  23. package/coverage/components/inputs/textarea/character-count.js.html +13 -3
  24. package/coverage/components/inputs/textarea/index.html +3 -2
  25. package/coverage/components/modal/index.html +23 -22
  26. package/coverage/components/modal/modal.js.html +118 -111
  27. package/coverage/components/notification/index.html +3 -2
  28. package/coverage/components/notification/notification.js.html +13 -3
  29. package/coverage/components/popover/index.html +3 -2
  30. package/coverage/components/popover/popover.js.html +3 -2
  31. package/coverage/components/switch-state/index.html +19 -18
  32. package/coverage/components/switch-state/switch-state.js.html +22 -21
  33. package/coverage/components/tabs/index.html +3 -2
  34. package/coverage/components/tabs/tabs.js.html +37 -3
  35. package/coverage/favicon.png +0 -0
  36. package/coverage/index.html +52 -51
  37. package/coverage/js/common.js.html +3 -2
  38. package/coverage/js/fractal-scripts/combobox.js.html +22 -3
  39. package/coverage/js/fractal-scripts/index.html +3 -2
  40. package/coverage/js/fractal-scripts/notification.js.html +13 -3
  41. package/coverage/js/fractal-scripts/switch-state.js.html +13 -3
  42. package/coverage/js/index-fractal.js.html +3 -2
  43. package/coverage/js/index-polyfills.js.html +3 -2
  44. package/coverage/js/index-vue.js.html +3 -2
  45. package/coverage/js/index.html +3 -2
  46. package/coverage/js/index.js.html +3 -2
  47. package/coverage/js/polyfills/arrayPrototypeFind.js.html +20 -10
  48. package/coverage/js/polyfills/closest.js.html +8 -4
  49. package/coverage/js/polyfills/index.html +3 -2
  50. package/coverage/js/polyfills/objectAssign.js.html +19 -9
  51. package/coverage/js/polyfills/remove.js.html +3 -2
  52. package/coverage/tokens/_config.js.html +3 -2
  53. package/coverage/tokens/index.html +3 -2
  54. package/cypress/.eslintrc.js +6 -6
  55. package/cypress/fixtures/testuploadfile.txt +1 -0
  56. package/cypress/integration/components/accordion.spec.js +40 -3
  57. package/cypress/integration/components/button.spec.js +2 -3
  58. package/cypress/integration/components/card.spec.js +2 -3
  59. package/cypress/integration/components/icons.spec.js +10 -0
  60. package/cypress/integration/components/{combobox.spec.js → inputs/combobox.spec.js} +6 -0
  61. package/cypress/integration/components/inputs/file-upload.spec.js +45 -0
  62. package/cypress/integration/components/{input.spec.js → inputs/input.spec.js} +1 -1
  63. package/cypress/integration/components/inputs/label.spec.js +15 -0
  64. package/cypress/integration/components/inputs/radio.spec.js +20 -0
  65. package/cypress/integration/components/inputs/select.spec.js +31 -0
  66. package/cypress/integration/components/inputs/textarea.spec.js +23 -0
  67. package/cypress/integration/components/modal.spec.js +65 -0
  68. package/cypress/integration/components/notifications.spec.js +35 -0
  69. package/cypress/integration/components/popover.spec.js +36 -0
  70. package/cypress/integration/components/skip-link.spec.js +9 -0
  71. package/cypress/plugins/index.js +1 -1
  72. package/cypress/support/commands.js +14 -0
  73. package/cypress/support/index.js +2 -0
  74. package/dist/_tokens/css/_tokens.css +1 -1
  75. package/dist/_tokens/js/_tokens-module.js +455 -1
  76. package/dist/_tokens/scss/_tokens.scss +4 -4
  77. package/dist/assets/icons.json +1 -1
  78. package/dist/assets/icons.svg +6 -1
  79. package/dist/js/index.js +1 -1
  80. package/fractal.js +2 -0
  81. package/package.json +59 -54
  82. package/server.js +1 -1
  83. package/src/components/accordion/accordion.config.js +9 -12
  84. package/src/components/accordion/accordion.js +12 -0
  85. package/src/components/inputs/file-upload/file-upload.js +1 -0
  86. package/src/components/inputs/textarea/character-count.js +3 -0
  87. package/src/components/modal/modal.js +3 -1
  88. package/src/components/notification/notification.js +3 -0
  89. package/src/components/skip-link/skip-link.njk +11 -1
  90. package/src/components/tabs/tabs.js +11 -0
  91. package/src/js/fractal-scripts/combobox.js +6 -0
  92. package/src/js/fractal-scripts/notification.js +3 -0
  93. package/src/js/fractal-scripts/switch-state.js +3 -0
  94. package/src/js/polyfills/arrayPrototypeFind.js +9 -6
  95. package/src/js/polyfills/closest.js +2 -1
  96. package/src/js/polyfills/objectAssign.js +9 -6
  97. package/tasks/colorTransforms.js +4 -0
  98. package/tasks/createMacroIndex.js +1 -0
  99. package/tasks/css.js +3 -0
  100. package/tasks/fractal.js +2 -0
  101. package/tasks/js-bundle.js +6 -2
  102. package/tasks/svgsprite.js +31 -21
  103. package/tasks/tokens.js +2 -0
  104. package/__tests__/unit/src/components/accordion.spec.js +0 -88
  105. package/__tests__/unit/src/components/modal.spec.js +0 -87
  106. package/__tests__/unit/src/components/switch-state.spec.js +0 -21
  107. package/cypress/integration/components/textarea.spec.js +0 -9
  108. /package/cypress/integration/components/{checkbox-list.spec.js → inputs/checkbox-list.spec.js} +0 -0
  109. /package/cypress/integration/components/{single-checkbox.spec.js → inputs/single-checkbox.spec.js} +0 -0
@@ -34,6 +34,7 @@ async function createMacroIndex(cb) {
34
34
  };
35
35
  });
36
36
  let template = `{# automatically generated by the Design System build - do not edit #}\n\n`;
37
+
37
38
  template += componentList
38
39
  .map((component) =>
39
40
  component.macros.map((macroName) => `{% from '${component.path}' import ${macroName} %}`).join('\n')
package/tasks/css.js CHANGED
@@ -59,16 +59,19 @@ async function cssWebpack(srcFilePath, distFilePath, hashFilePath = false, filen
59
59
  },
60
60
  (err, stats) => {
61
61
  const info = stats.toJson();
62
+
62
63
  if (err || stats.hasErrors()) {
63
64
  if (err) {
64
65
  console.error(err);
65
66
  reject(err);
66
67
  }
68
+
67
69
  if (stats.hasErrors()) {
68
70
  console.error(info.errors);
69
71
  reject(err);
70
72
  }
71
73
  }
74
+
72
75
  resolve('webpack compiled');
73
76
  }
74
77
  );
package/tasks/fractal.js CHANGED
@@ -12,6 +12,7 @@ function fractalStart() {
12
12
  const server = fractal.web.server({
13
13
  sync: true,
14
14
  });
15
+
15
16
  server.on('error', (err) => logger.error(err.message));
16
17
  return server.start().then(() => {
17
18
  return logger.success(`Fractal server is now running at ${server.urls.sync.local}`);
@@ -24,6 +25,7 @@ function fractalBuild() {
24
25
  // import the Fractal instance configured in the fractal.js file
25
26
  const logger = fractal.cli.console; // make use of Fractal's console object for logging
26
27
  const builder = fractal.web.builder();
28
+
27
29
  builder.on('progress', (completed, total) => logger.update(`Exported ${completed} of ${total} items`, 'info'));
28
30
  builder.on('error', (err) => logger.error(err.message));
29
31
  return builder.build().then(() => {
@@ -1,6 +1,6 @@
1
1
  const path = require('path');
2
2
  const webpack = require('webpack');
3
- const VueLoaderPlugin = require('vue-loader/lib/plugin');
3
+ const VueLoaderPlugin = require('vue-loader-plugin');
4
4
 
5
5
  async function runWebpack() {
6
6
  return new Promise((resolve, reject) => {
@@ -29,19 +29,23 @@ async function runWebpack() {
29
29
  },
30
30
  ],
31
31
  },
32
- plugins: [new VueLoaderPlugin(), new webpack.EnvironmentPlugin(['NODE_ENV'])],
32
+ plugins: [new VueLoaderPlugin(), new webpack.EnvironmentPlugin({ NODE_ENV: 'production' })],
33
33
  },
34
34
  (err, stats) => {
35
35
  const info = stats.toJson();
36
+
36
37
  if (err || stats.hasErrors()) {
37
38
  if (err) {
38
39
  console.error(err);
39
40
  }
41
+
40
42
  if (stats.hasErrors()) {
41
43
  console.error(info.errors);
42
44
  }
45
+
43
46
  reject(err);
44
47
  }
48
+
45
49
  resolve('Webpack has compiled');
46
50
  }
47
51
  );
@@ -1,35 +1,37 @@
1
1
  const path = require('path');
2
2
  const fs = require('fs');
3
- const SVGO = require('svgo');
3
+ const { optimize } = require('svgo');
4
4
  const svgstore = require('svgstore');
5
5
 
6
6
  const filepath = path.resolve(__dirname, '../src/icons/');
7
7
  const prefix = path.basename(filepath, path.extname(filepath));
8
- const svgoOptions = new SVGO({
8
+ const svgoOptions = {
9
9
  plugins: [
10
10
  {
11
- cleanupIDs: {
11
+ name: 'cleanupIDs',
12
+ params: {
12
13
  prefix: `${prefix}-`,
13
14
  minify: true,
14
15
  },
15
16
  },
16
- { removeDoctype: true },
17
- { removeComments: true },
18
- { removeTitle: true },
19
- { removeDesc: true },
20
- { removeUselessDefs: true },
21
- { removeEditorsNSData: true },
22
- { cleanupAttrs: true },
23
- { cleanupNumericValues: true },
24
- { removeViewBox: false },
25
- { removeDimensions: true },
17
+ { name: 'removeDoctype', params: true },
18
+ { name: 'removeComments', params: true },
19
+ { name: 'removeTitle', params: true },
20
+ { name: 'removeDesc', params: true },
21
+ { name: 'removeUselessDefs', params: true },
22
+ { name: 'removeEditorsNSData', params: true },
23
+ { name: 'cleanupAttrs', params: true },
24
+ { name: 'cleanupNumericValues', params: true },
25
+ { name: 'removeViewBox', params: false },
26
+ { name: 'removeDimensions', params: true },
26
27
  {
27
- removeAttrs: {
28
+ name: 'removeAttrs',
29
+ params: {
28
30
  attrs: 'fill',
29
31
  },
30
32
  },
31
33
  ],
32
- });
34
+ };
33
35
 
34
36
  let files = [];
35
37
  const icons = [];
@@ -39,17 +41,25 @@ async function createSvgStack() {
39
41
  return new Promise((resolve, reject) => {
40
42
  files = fs.readdirSync(filepath);
41
43
  files.forEach((file) => {
42
- svgoOptions
43
- .optimize(fs.readFileSync(`${path.resolve(__dirname, filepath)}/${file}`, { encoding: 'utf8' }), {
44
- path: `${path.resolve(__dirname, filepath)}\\${file}`,
45
- })
44
+ // eslint-disable-next-line promise/param-names
45
+ new Promise((res) => {
46
+ const svgdata = fs.readFileSync(`${path.resolve(__dirname, filepath, file)}`, { encoding: 'utf8' });
47
+ const result = optimize(svgdata, {
48
+ path: `${path.resolve(__dirname, filepath, file)}`,
49
+ ...svgoOptions,
50
+ });
51
+
52
+ res(result);
53
+ })
46
54
  .then((icon) => {
47
55
  const fileName = path.parse(file).name;
56
+
48
57
  sprites.add(fileName, icon.data);
58
+
49
59
  return fs.mkdir(path.resolve(__dirname, '../dist/assets'), { recursive: true }, async () => {
50
60
  icons.push({ name: fileName });
51
- fs.writeFileSync(`${path.resolve(__dirname, '../dist/assets')}/icons.svg`, sprites);
52
- fs.writeFileSync(`${path.resolve(__dirname, '../dist/assets')}/icons.json`, JSON.stringify(icons));
61
+ fs.writeFileSync(`${path.resolve(__dirname, '../dist/assets', 'icons.svg')}`, sprites);
62
+ fs.writeFileSync(`${path.resolve(__dirname, '../dist/assets', 'icons.json')}`, JSON.stringify(icons));
53
63
  });
54
64
  })
55
65
  .catch((err) => {
package/tasks/tokens.js CHANGED
@@ -13,6 +13,7 @@ async function transformBaseTokens(filePath) {
13
13
  const transformed = JSON.stringify(transformTokens(JSON.parse(baseTokens)), null, ' ')
14
14
  // Add a space after every key, before the `:`
15
15
  .replace(/: "(?:[^"]+|\\")*",?$/gm, ' $&');
16
+
16
17
  return writeFileAsync(filePath, transformed);
17
18
  }
18
19
 
@@ -20,6 +21,7 @@ async function tokens() {
20
21
  try {
21
22
  await transformBaseTokens(path.resolve(__dirname, '../src/tokens/color.json'));
22
23
  const StyleDictionary = StyleDictionaryPackage.extend(path.resolve(__dirname, '../src/tokens/_config'));
24
+
23
25
  await registerTransforms(StyleDictionary);
24
26
  await StyleDictionary.buildAllPlatforms();
25
27
  } catch (e) {
@@ -1,88 +0,0 @@
1
- import accordion from '../../../../src/components/accordion/accordion';
2
-
3
- // document.querySelector = jest.fn().mockReturnValue('<body style="font-size: 16px;"><div id="root"></div></body>');
4
- window.getComputedStyle = jest.fn().mockReturnValue({ 'font-size': '16px' });
5
-
6
- describe('Accordion - checkBreakpoint', () => {
7
- const element = {
8
- dataset: {
9
- bp: '',
10
- },
11
- };
12
- beforeEach(() => {});
13
- it('shows accordion when no bp is set', async () => {
14
- element.dataset.bp = false;
15
- expect.assertions(1);
16
- const isAccordion = accordion.checkBreakpoint(element, '800');
17
- expect(isAccordion).toBe(true);
18
- });
19
- it('shows accordion when screen is < than bp', async () => {
20
- element.dataset.bp = '500px';
21
- expect.assertions(1);
22
- const isAccordion = accordion.checkBreakpoint(element, '300');
23
- expect(isAccordion).toBe(true);
24
- });
25
- it('hide accordion when screen is > than bp (px)', async () => {
26
- element.dataset.bp = '500px';
27
- expect.assertions(1);
28
- const isAccordion = accordion.checkBreakpoint(element, '800');
29
- expect(isAccordion).toBe(false);
30
- });
31
- it('hide accordion when screen is > than bp (rem)', async () => {
32
- element.dataset.bp = '34rem';
33
- expect.assertions(1);
34
- const isAccordion = accordion.checkBreakpoint(element, '800');
35
- expect(isAccordion).toBe(false);
36
- });
37
- it('hide accordion when screen is > than bp (em)', async () => {
38
- element.dataset.bp = '34em';
39
- expect.assertions(1);
40
- const isAccordion = accordion.checkBreakpoint(element, '800');
41
- expect(isAccordion).toBe(false);
42
- });
43
- it('shows accordion when unit is not supported', async () => {
44
- element.dataset.bp = '34pt';
45
- expect.assertions(1);
46
- const isAccordion = accordion.checkBreakpoint(element, '800');
47
- expect(isAccordion).toBe(true);
48
- });
49
- });
50
-
51
- describe('Accordion - createButton', () => {
52
- const element = document.createElement('div');
53
- element.classList.add('mds-accordion-trigger');
54
- element.innerHTML = '<span>this is the span</span>';
55
- beforeEach(() => {});
56
- it('created the button and contains correct attrs', async () => {
57
- expect.assertions(2);
58
- const accordionTriggerButton = accordion.createButton(element);
59
- expect(accordionTriggerButton.innerHTML).toContain('this is the span');
60
- expect(accordionTriggerButton.classList).toEqual(expect.objectContaining({ '0': 'mds-accordion-trigger__button' }));
61
- });
62
- });
63
-
64
- describe('Accordion - switchLabel', () => {
65
- const element = document.createElement('span');
66
- element.dataset.labelinverse = 'view less';
67
- element.textContent = 'view more';
68
- beforeEach(() => {});
69
- it('switches labels', async () => {
70
- expect.assertions(1);
71
- accordion.switchLabel(element);
72
- expect(element.textContent).toBe('view less');
73
- });
74
- });
75
-
76
- describe('Accordion - setAccordion', () => {
77
- const accordionTrigger = document.createElement('div');
78
- accordionTrigger.classList.add('mds-accordion-trigger');
79
- accordionTrigger.innerHTML = '<span><span class="mds-accordion-trigger__label">label</span></span>';
80
- const accordionContent = document.createElement('div');
81
- accordionContent.classList.add('mds-accordion-content');
82
- beforeEach(() => {});
83
- it('set accordion button', async () => {
84
- expect.assertions(1);
85
- accordion.setAccordion(accordionTrigger, accordionContent);
86
- expect(accordionTrigger.textContent).toContain('label');
87
- });
88
- });
@@ -1,87 +0,0 @@
1
- import modals from '../../../../src/components/modal/modal';
2
-
3
- if (window.document) {
4
- window.document.createRange = () => ({
5
- setStart: () => {},
6
- setEnd: () => {},
7
- commonAncestorContainer: {
8
- nodeName: 'BODY',
9
- ownerDocument: document,
10
- },
11
- });
12
- }
13
-
14
- document.body.innerHTML = `
15
- <div id="site-container">
16
- <button id="modal-trigger" class="js-mds-modal-trigger" data-modal-id="test-modal">Open Modal</button>
17
- </div>
18
- <div class="mds-modal" role="dialog" id="test-modal" aria-labelledby="modal-label" data-site-container="site-container">
19
- <div class="mds-modal__inner">
20
- <button id="close-button" type="button" class="js-mds-modal-close mds-modal-default-close-button">Close</button>
21
- <h1 id="modal-label">Hello!</h1>
22
- </div>
23
- </div>`;
24
- const modalActiveClass = 'mds-modal--active';
25
- const trigger = document.getElementById('modal-trigger');
26
- const modal = document.getElementById('test-modal');
27
- const closeButton = document.getElementById('close-button');
28
- const siteContainer = document.getElementById('site-container');
29
- // const modalDefaultCloseButtonClass = 'mds-modal-default-close-button';
30
-
31
- beforeEach(() => {
32
- trigger.focus();
33
- modal.classList.remove(modalActiveClass);
34
- siteContainer.removeAttribute('aria-hidden');
35
- modals.init();
36
- });
37
- afterEach(() => {
38
- document.body.innerHTML = '';
39
- });
40
-
41
- describe('modal - clicking on trigger', () => {
42
- it('add active class to modal, move focus to focusable element in modal and aria-hidden="true" to site container', () => {
43
- expect.assertions(3);
44
- trigger.click();
45
- expect(modal.classList.contains(modalActiveClass)).toBe(true);
46
- expect(document.activeElement).toEqual(closeButton);
47
- expect(siteContainer.getAttribute('aria-hidden')).toBe('true');
48
- });
49
- });
50
-
51
- describe('modal - close modal', () => {
52
- it('close modal if clicking outside of "modal__inner"', () => {
53
- expect.assertions(3);
54
- trigger.click(); // opening modal first
55
- modal.click();
56
- expect(modal.classList.contains(modalActiveClass)).toBe(false);
57
- expect(document.activeElement).toEqual(trigger);
58
- expect(siteContainer.getAttribute('aria-hidden')).toBe(null);
59
- });
60
- it('close modal if using escape key', () => {
61
- expect.assertions(3);
62
- trigger.click();
63
- modal.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }));
64
- expect(modal.classList.contains(modalActiveClass)).toBe(false);
65
- expect(document.activeElement).toEqual(trigger);
66
- expect(siteContainer.getAttribute('aria-hidden')).toBe(null);
67
- });
68
- it('close modal if using close button', () => {
69
- expect.assertions(3);
70
- trigger.click();
71
- closeButton.click();
72
- expect(modal.classList.contains(modalActiveClass)).toBe(false);
73
- expect(document.activeElement).toEqual(trigger);
74
- expect(siteContainer.getAttribute('aria-hidden')).toBe(null);
75
- });
76
- });
77
-
78
- describe('modal - trap focus', () => {
79
- it('tab or shift tab keeps you focused on the close button inside the modal', () => {
80
- expect.assertions(2);
81
- trigger.click(); // opening modal first
82
- modal.dispatchEvent(new KeyboardEvent('keydown', { key: 'Tab' }));
83
- expect(document.activeElement).toEqual(closeButton);
84
- modal.dispatchEvent(new KeyboardEvent('keydown', { shiftKey: true, key: 'Tab' }));
85
- expect(document.activeElement).toEqual(closeButton);
86
- });
87
- });
@@ -1,21 +0,0 @@
1
- import switchState from '../../../../src/components/switch-state/switch-state';
2
-
3
- describe('Switch State', () => {
4
- let element = document.createElement('div');
5
- element.innerHTML = `<button class="mds-switch-state js-mds-switch-state mds-switch-state--default">
6
- <span class="mds-switch-state--default">this is default</span>
7
- <span class="mds-switch-state--inverse">this is inverse</span>
8
- </button>`;
9
- it('setToinverse to be true', async () => {
10
- expect.assertions(2);
11
- switchState.switchToinverse(element);
12
- expect(element.classList.contains('mds-switch-state--inverse')).toBe(true);
13
- expect(element.classList.contains('mds-switch-state--default')).toBe(false);
14
- });
15
- it('setTodefault to be true', async () => {
16
- expect.assertions(2);
17
- switchState.switchTodefault(element);
18
- expect(element.classList.contains('mds-switch-state--default')).toBe(true);
19
- expect(element.classList.contains('mds-switch-state--inverse')).toBe(false);
20
- });
21
- });
@@ -1,9 +0,0 @@
1
- context('Textarea', () => {
2
- beforeEach(() => {
3
- cy.visitComponent('textarea');
4
- });
5
-
6
- it('has no detectable a11y violations on load', () => {
7
- cy.checkA11y('[data-test="textarea-example-textarea"]');
8
- });
9
- });