uikit 3.16.21 → 3.16.22-dev.8dfedb1d6

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 (56) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/build/build.js +4 -4
  3. package/build/less.js +2 -2
  4. package/build/publishDev.js +12 -13
  5. package/build/release.js +33 -27
  6. package/build/scss/inverse.scss +30 -0
  7. package/build/scss/mixin.scss +32 -0
  8. package/build/scss.js +77 -197
  9. package/build/util.js +5 -17
  10. package/dist/css/uikit-core-rtl.css +1 -1
  11. package/dist/css/uikit-core-rtl.min.css +1 -1
  12. package/dist/css/uikit-core.css +1 -1
  13. package/dist/css/uikit-core.min.css +1 -1
  14. package/dist/css/uikit-rtl.css +1 -1
  15. package/dist/css/uikit-rtl.min.css +1 -1
  16. package/dist/css/uikit.css +1 -1
  17. package/dist/css/uikit.min.css +1 -1
  18. package/dist/js/components/countdown.js +1 -1
  19. package/dist/js/components/countdown.min.js +1 -1
  20. package/dist/js/components/filter.js +1 -1
  21. package/dist/js/components/filter.min.js +1 -1
  22. package/dist/js/components/lightbox-panel.js +1 -1
  23. package/dist/js/components/lightbox-panel.min.js +1 -1
  24. package/dist/js/components/lightbox.js +1 -1
  25. package/dist/js/components/lightbox.min.js +1 -1
  26. package/dist/js/components/notification.js +9 -5
  27. package/dist/js/components/notification.min.js +1 -1
  28. package/dist/js/components/parallax.js +1 -1
  29. package/dist/js/components/parallax.min.js +1 -1
  30. package/dist/js/components/slider-parallax.js +1 -1
  31. package/dist/js/components/slider-parallax.min.js +1 -1
  32. package/dist/js/components/slider.js +1 -1
  33. package/dist/js/components/slider.min.js +1 -1
  34. package/dist/js/components/slideshow-parallax.js +1 -1
  35. package/dist/js/components/slideshow-parallax.min.js +1 -1
  36. package/dist/js/components/slideshow.js +1 -1
  37. package/dist/js/components/slideshow.min.js +1 -1
  38. package/dist/js/components/sortable.js +1 -1
  39. package/dist/js/components/sortable.min.js +1 -1
  40. package/dist/js/components/tooltip.js +1 -1
  41. package/dist/js/components/tooltip.min.js +1 -1
  42. package/dist/js/components/upload.js +1 -1
  43. package/dist/js/components/upload.min.js +1 -1
  44. package/dist/js/uikit-core.js +6 -12
  45. package/dist/js/uikit-core.min.js +1 -1
  46. package/dist/js/uikit-icons.js +1 -1
  47. package/dist/js/uikit-icons.min.js +1 -1
  48. package/dist/js/uikit.js +14 -16
  49. package/dist/js/uikit.min.js +1 -1
  50. package/package.json +3 -2
  51. package/src/js/components/notification.js +8 -4
  52. package/src/js/core/height-viewport.js +7 -12
  53. package/src/scss/components/mixin.scss +11 -11
  54. package/src/scss/mixins-theme.scss +1 -1
  55. package/src/scss/mixins.scss +1 -1
  56. package/tests/dropbar.html +97 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## WIP
4
+
5
+ ### Fixed
6
+
7
+ - Fix existing notification container has to be visible before appending notification
8
+
3
9
  ## 3.16.21 (June 13, 2023)
4
10
 
5
11
  ### Fixed
package/build/build.js CHANGED
@@ -1,7 +1,7 @@
1
+ import path from 'path';
1
2
  import { glob } from 'glob';
2
3
  import pLimit from 'p-limit';
3
4
  import camelize from 'camelcase';
4
- import { basename, resolve } from 'path';
5
5
  import { args, compile, icons } from './util.js';
6
6
 
7
7
  const limit = pLimit(Number(process.env.cpus || 2));
@@ -72,14 +72,14 @@ async function getComponentTasks() {
72
72
  const components = await glob('src/js/components/!(index).js');
73
73
 
74
74
  return components.reduce((components, file) => {
75
- const name = basename(file, '.js');
75
+ const name = path.basename(file, '.js');
76
76
 
77
77
  components[name] = () =>
78
78
  compile('build/wrapper/component.js', `dist/js/components/${name}`, {
79
79
  name,
80
80
  external: ['uikit', 'uikit-util'],
81
81
  globals: { uikit: 'UIkit', 'uikit-util': 'UIkit.util' },
82
- aliases: { component: resolve('src/js/components', name) },
82
+ aliases: { component: path.resolve('src/js/components', name) },
83
83
  replaces: { NAME: `'${camelize(name)}'` },
84
84
  });
85
85
 
@@ -89,5 +89,5 @@ async function getComponentTasks() {
89
89
 
90
90
  async function getTestFiles() {
91
91
  const files = await glob('tests/!(index).html');
92
- return JSON.stringify(files.sort().map((file) => basename(file, '.html')));
92
+ return JSON.stringify(files.sort().map((file) => path.basename(file, '.html')));
93
93
  }
package/build/less.js CHANGED
@@ -1,6 +1,6 @@
1
+ import path from 'path';
1
2
  import { glob } from 'glob';
2
3
  import rtlcss from 'rtlcss';
3
- import { basename } from 'path';
4
4
  import { args, banner, minify, pathExists, read, readJson, renderLess, write } from './util.js';
5
5
 
6
6
  const { rtl } = args;
@@ -13,7 +13,7 @@ const sources = [
13
13
  const themes = (await pathExists('themes.json')) ? await readJson('themes.json') : {};
14
14
 
15
15
  for (const src of await glob('custom/*.less')) {
16
- const theme = basename(src, '.less');
16
+ const theme = path.basename(src, '.less');
17
17
  const dist = `dist/css/uikit.${theme}${rtl ? '-rtl' : ''}.css`;
18
18
 
19
19
  themes[theme] = { css: `../${dist}` };
@@ -1,34 +1,33 @@
1
+ import { $ } from 'execa';
1
2
  import semver from 'semver';
2
- import { args, getVersion, run } from './util.js';
3
+ import { args, getVersion } from './util.js';
3
4
 
4
- const { inc } = semver;
5
+ const $$ = $({ stdio: 'inherit' });
5
6
 
6
7
  // default exec options
7
8
  if (args.f || args.force || (await isDevCommit())) {
8
9
  // increase version patch number
9
- const version = inc(await getVersion(), 'patch');
10
+ const version = semver.inc(await getVersion(), 'patch');
10
11
 
11
12
  // get current git hash
12
- const hash = (await run('git rev-parse --short HEAD')).trim();
13
+ const hash = (await $`git rev-parse --short HEAD`).stdout.trim();
13
14
 
14
15
  // set version of package.json
15
- await run(`pnpm version ${version}-dev.${hash} --no-git-tag-version`);
16
+ await $$`pnpm version ${version}-dev.${hash} --no-git-tag-version`;
16
17
 
17
18
  // create dist files
18
- await run('pnpm compile && pnpm compile-rtl && pnpm build-scss');
19
+ await $$`pnpm compile`;
20
+ await $$`pnpm compile-rtl`;
21
+ await $$`pnpm build-scss`;
19
22
 
20
23
  // publish to dev tag
21
- await run('pnpm publish --tag dev --no-git-checks');
24
+ await $$`pnpm publish --tag dev --no-git-checks`;
22
25
  }
23
26
 
24
27
  async function isDevCommit() {
25
28
  // check for changes to publish (%B: raw body (unwrapped subject and body)
26
- const message = await run('git log -1 --pretty=%B');
29
+ const message = (await $`git log -1 --pretty=%B`).stdout.trim();
27
30
 
28
31
  // https://www.conventionalcommits.org/en/v1.0.0/
29
- const type = message.match(
30
- /^(revert: )?(feat|fix|polish|docs|style|refactor|perf|test|workflow|ci|chore|types|build)(\(.+\))?: .{1,50}/
31
- );
32
-
33
- return type && ['feat', 'fix', 'refactor', 'perf'].includes(type[2]);
32
+ return Boolean(message.match(/^(revert: )?(feat|fix|refactor|perf)(\(.+\))?: .{1,50}/));
34
33
  }
package/build/release.js CHANGED
@@ -1,14 +1,16 @@
1
+ import fs from 'fs';
2
+ import { $ } from 'execa';
1
3
  import { glob } from 'glob';
4
+ import semver from 'semver';
2
5
  import archiver from 'archiver';
3
6
  import inquirer from 'inquirer';
4
- import { createWriteStream } from 'fs';
5
7
  import dateFormat from 'dateformat/lib/dateformat.js';
6
- import { coerce, gt, inc, prerelease, valid } from 'semver';
7
- import { args, getVersion, logFile, read, replaceInFile, run } from './util.js';
8
+ import { args, getVersion, logFile, read, replaceInFile } from './util.js';
8
9
 
10
+ const $$ = $({ stdio: 'inherit' });
9
11
  const prompt = inquirer.createPromptModule();
10
12
 
11
- if (await run('git status --porcelain')) {
13
+ if ((await $`git status --porcelain`).stdout.trim()) {
12
14
  throw 'Repository contains uncommitted changes.';
13
15
  }
14
16
 
@@ -17,9 +19,9 @@ const version = await inquireVersion(args.v || args.version);
17
19
 
18
20
  await raiseVersion(version);
19
21
 
20
- await run('pnpm compile');
21
- await run('pnpm compile-rtl');
22
- await run('pnpm build-scss');
22
+ await $$`pnpm compile`;
23
+ await $$`pnpm compile-rtl`;
24
+ await $$`pnpm build-scss`;
23
25
 
24
26
  await createPackage(version);
25
27
 
@@ -28,7 +30,7 @@ if (args.d || args.deploy || (await inquireDeploy())) {
28
30
  }
29
31
 
30
32
  function isValidVersion(version) {
31
- return valid(version) && gt(version, prevVersion);
33
+ return semver.valid(version) && semver.gt(version, prevVersion);
32
34
  }
33
35
 
34
36
  async function inquireVersion(version) {
@@ -40,7 +42,8 @@ async function inquireVersion(version) {
40
42
  await prompt({
41
43
  name: 'version',
42
44
  message: 'Enter a version',
43
- default: () => inc(prevVersion, prerelease(prevVersion) ? 'prerelease' : 'patch'),
45
+ default: () =>
46
+ semver.inc(prevVersion, semver.prerelease(prevVersion) ? 'prerelease' : 'patch'),
44
47
  validate: (val) => isValidVersion(val) || 'Invalid version',
45
48
  })
46
49
  ).version;
@@ -48,7 +51,7 @@ async function inquireVersion(version) {
48
51
 
49
52
  function raiseVersion(version) {
50
53
  return Promise.all([
51
- run(`npm version ${version} --git-tag-version false`),
54
+ $$`npm version ${version} --git-tag-version false`,
52
55
  replaceInFile('CHANGELOG.md', (data) =>
53
56
  data.replace(
54
57
  /^##\s*WIP/m,
@@ -65,7 +68,7 @@ async function createPackage(version) {
65
68
  const dest = `dist/uikit-${version}.zip`;
66
69
  const archive = archiver('zip');
67
70
 
68
- archive.pipe(createWriteStream(dest));
71
+ archive.pipe(fs.createWriteStream(dest));
69
72
 
70
73
  for (const file of await glob('dist/{js,css}/uikit?(-icons|-rtl)?(.min).{js,css}')) {
71
74
  archive.file(file, { name: file.substring(5) });
@@ -76,7 +79,7 @@ async function createPackage(version) {
76
79
  }
77
80
 
78
81
  function versionFormat(version) {
79
- return [coerce(version).version].concat(prerelease(version) || []).join(' ');
82
+ return [semver.coerce(version).version].concat(semver.prerelease(version) || []).join(' ');
80
83
  }
81
84
 
82
85
  async function inquireDeploy() {
@@ -91,26 +94,29 @@ async function inquireDeploy() {
91
94
  }
92
95
 
93
96
  async function deploy(version) {
94
- await run(`git checkout -b release/v${version}`);
95
- await run('git stage --all');
96
- await run(`git commit -am "v${version}"`);
97
- await run('git checkout main');
98
- await run(
99
- `git merge release/v${version} --commit --no-ff -m "Merge branch 'release/v${version}'"`
100
- );
97
+ const tag = `v${version}`;
98
+ const branch = `release/v${version}`;
101
99
 
102
- await run(`git tag v${version}`);
103
- await run('git checkout develop');
104
- await run(`git merge v${version} --commit --no-ff -m "Merge tag 'v${version}' into develop"`);
105
- await run(`git branch --delete release/v${version}`);
100
+ await $$`git checkout -b ${branch}`;
101
+ await $$`git stage --all`;
102
+ await $$`git commit -am v${version}`;
106
103
 
107
- await run('git push origin develop');
108
- await run('git push origin main --tags');
104
+ await $$`git checkout main`;
105
+ await $$`git merge ${branch} --commit --no-ff -m ${`Merge branch '${branch}'`}`;
106
+ await $$`git tag ${tag}`;
109
107
 
110
- await run('pnpm publish --no-git-checks');
108
+ await $$`git checkout develop`;
109
+ await $$`git merge ${tag} --commit --no-ff -m ${`Merge tag '${tag}' into develop`}`;
110
+
111
+ await $$`git branch --delete ${branch}`;
112
+
113
+ await $$`git push origin develop`;
114
+ await $$`git push origin main --tags`;
115
+
116
+ await $$`pnpm publish --no-git-checks`;
111
117
 
112
118
  const notes = (await read('./Changelog.md'))
113
119
  .match(/## \d.*?$\s*(.*?)\s*(?=## \d)/ms)[1]
114
120
  .replace(/(["`])/g, '\\$1');
115
- await run(`gh release create v${version} --notes "${notes}" ./dist/uikit-${version}.zip`);
121
+ await $$`gh release create v${version} --notes ${notes} ./dist/uikit-${version}.zip`;
116
122
  }
@@ -0,0 +1,30 @@
1
+ @mixin hook-inverse() {
2
+ @include hook-inverse-component-base();
3
+ @include hook-inverse-component-link();
4
+ @include hook-inverse-component-heading();
5
+ @include hook-inverse-component-divider();
6
+ @include hook-inverse-component-list();
7
+ @include hook-inverse-component-icon();
8
+ @include hook-inverse-component-form();
9
+ @include hook-inverse-component-button();
10
+ @include hook-inverse-component-grid();
11
+ @include hook-inverse-component-close();
12
+ @include hook-inverse-component-totop();
13
+ @include hook-inverse-component-badge();
14
+ @include hook-inverse-component-label();
15
+ @include hook-inverse-component-article();
16
+ @include hook-inverse-component-search();
17
+ @include hook-inverse-component-nav();
18
+ @include hook-inverse-component-navbar();
19
+ @include hook-inverse-component-subnav();
20
+ @include hook-inverse-component-breadcrumb();
21
+ @include hook-inverse-component-pagination();
22
+ @include hook-inverse-component-tab();
23
+ @include hook-inverse-component-slidenav();
24
+ @include hook-inverse-component-dotnav();
25
+ @include hook-inverse-component-accordion();
26
+ @include hook-inverse-component-iconnav();
27
+ @include hook-inverse-component-text();
28
+ @include hook-inverse-component-column();
29
+ @include hook-inverse-component-utility();
30
+ }
@@ -0,0 +1,32 @@
1
+ //
2
+ // Component: Mixin
3
+ // Description: Defines mixins which are used across all components
4
+ //
5
+ // ========================================================================
6
+
7
+ // SVG
8
+ // ========================================================================
9
+
10
+ /// Replace `$search` with `$replace` in `$string`
11
+ /// @author Hugo Giraudel
12
+ /// @param {String} $string - Initial string
13
+ /// @param {String} $search - Substring to replace
14
+ /// @param {String} $replace ('') - New value
15
+ /// @return {String} - Updated string
16
+ @function str-replace($string, $search, $replace: '') {
17
+ $index: str-index($string, $search);
18
+
19
+ @if $index {
20
+ @return str-slice($string, 1, $index - 1) + $replace +
21
+ str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
22
+ }
23
+
24
+ @return $string;
25
+ }
26
+
27
+ @mixin svg-fill($src, $color-default, $color-new) {
28
+ $replace-src: str-replace($src, $color-default, $color-new) !default;
29
+ $replace-src: str-replace($replace-src, '#', '%23');
30
+ $replace-src: quote($replace-src);
31
+ background-image: url($replace-src);
32
+ }
package/build/scss.js CHANGED
@@ -1,84 +1,21 @@
1
1
  import { glob } from 'glob';
2
2
  import NP from 'number-precision';
3
3
  import { read, write } from './util.js';
4
+ import path from 'path';
4
5
 
5
6
  NP.enableBoundaryChecking(false);
6
7
 
7
- const themeMixins = {};
8
8
  const coreMixins = {};
9
- const themeVar = {};
10
- const coreVar = {};
11
-
12
- /* template for the new components/mixins.scss file*/
13
- const mixinTemplate = `//
14
- // Component: Mixin
15
- // Description: Defines mixins which are used across all components
16
- //
17
- // ========================================================================
18
-
19
-
20
- // SVG
21
- // ========================================================================
22
-
23
- /// Replace \`$search\` with \`$replace\` in \`$string\`
24
- /// @author Hugo Giraudel
25
- /// @param {String} $string - Initial string
26
- /// @param {String} $search - Substring to replace
27
- /// @param {String} $replace ('') - New value
28
- /// @return {String} - Updated string
29
- @function str-replace($string, $search, $replace: '') {
30
- $index: str-index($string, $search);
31
-
32
- @if $index {
33
- @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
34
- }
35
-
36
- @return $string;
37
- }
38
-
39
- @mixin svg-fill($src, $color-default, $color-new){
40
-
41
- $replace-src: str-replace($src, $color-default, $color-new) !default;
42
- $replace-src: str-replace($replace-src, "#", "%23");
43
- background-image: url(quote($replace-src));
44
- }`;
45
-
46
- /* template for the inverse components */
47
- const inverseTemplate = ` @include hook-inverse-component-base();
48
- @include hook-inverse-component-link();
49
- @include hook-inverse-component-heading();
50
- @include hook-inverse-component-divider();
51
- @include hook-inverse-component-list();
52
- @include hook-inverse-component-icon();
53
- @include hook-inverse-component-form();
54
- @include hook-inverse-component-button();
55
- @include hook-inverse-component-grid();
56
- @include hook-inverse-component-close();
57
- @include hook-inverse-component-totop();
58
- @include hook-inverse-component-badge();
59
- @include hook-inverse-component-label();
60
- @include hook-inverse-component-article();
61
- @include hook-inverse-component-search();
62
- @include hook-inverse-component-nav();
63
- @include hook-inverse-component-navbar();
64
- @include hook-inverse-component-subnav();
65
- @include hook-inverse-component-breadcrumb();
66
- @include hook-inverse-component-pagination();
67
- @include hook-inverse-component-tab();
68
- @include hook-inverse-component-slidenav();
69
- @include hook-inverse-component-dotnav();
70
- @include hook-inverse-component-accordion();
71
- @include hook-inverse-component-iconnav();
72
- @include hook-inverse-component-text();
73
- @include hook-inverse-component-column();
74
- @include hook-inverse-component-utility();`;
9
+ const themeMixins = {};
10
+ const coreVariables = {};
11
+ const themeVariables = {};
75
12
 
76
13
  /* First Step: Go through all files */
77
14
  for (const file of (await glob('src/less/**/*.less')).sort()) {
78
- const data = await read(file);
15
+ let source = await read(file);
79
16
 
80
17
  /* replace all Less stuff with SCSS */
81
- let scssData = data
18
+ source = (await read(file))
82
19
  .replace(/\/less\//g, '/scss/') // change less/ dir to scss/ on imports
83
20
  .replace(/\.less/g, '.scss') // change .less extensions to .scss on imports
84
21
  .replace(/@/g, '$') // convert variables
@@ -124,26 +61,24 @@ for (const file of (await glob('src/less/**/*.less')).sort()) {
124
61
  .replace(/~('[^']+')/g, 'unquote($1)'); // string literals: for real
125
62
 
126
63
  /* File name of the current file */
127
- const [filename] = file.split('/').pop().split('.less');
64
+ const filename = path.basename(file, '.less');
128
65
 
129
- if (filename !== 'inverse') {
130
- scssData = scssData.replace(/hook-inverse(?!-)/g, `hook-inverse-component-${filename}`);
131
- } else {
132
- const joinedHook = `@mixin hook-inverse(){\n${inverseTemplate}\n}\n`;
133
- scssData = scssData.replace(/\*\//, '*/\n' + joinedHook);
134
- }
66
+ source =
67
+ filename === 'inverse'
68
+ ? source.replace(/\*\//, `*/\n${await read('build/scss/inverse.scss')}`)
69
+ : source.replace(/hook-inverse(?!-)/g, `hook-inverse-component-${filename}`);
135
70
 
136
71
  /* get all the mixins and remove them from the file */
137
- scssData = getMixinsFromFile(file, scssData);
72
+ source = getMixinsFromFile(file, source);
138
73
 
139
74
  /* get all Variables and remove them */
140
- scssData = await getVariablesFromFile(file, scssData);
75
+ source = await getVariablesFromFile(file, source);
141
76
 
142
77
  if (filename === 'uikit.theme') {
143
78
  /* remove the theme import first place */
144
- scssData = scssData.replace(/\/\/\n\/\/ Theme\n\/\/\n\n@import "theme\/_import.scss";/, '');
79
+ source = source.replace(/\/\/\n\/\/ Theme\n\/\/\n\n@import "theme\/_import.scss";/, '');
145
80
  /* add uikit-mixins and uikit-variables include to the uikit.scss file and change order, to load theme files first */
146
- scssData = scssData.replace(
81
+ source = source.replace(
147
82
  /\/\/ Core\n\/\//g,
148
83
  '// Theme\n//\n\n@import "theme/_import.scss";'
149
84
  );
@@ -151,125 +86,90 @@ for (const file of (await glob('src/less/**/*.less')).sort()) {
151
86
 
152
87
  /* mixin.less needs to be fully replaced by the new mixin file*/
153
88
  if (filename === 'mixin') {
154
- scssData = mixinTemplate;
89
+ source = await read('build/scss/mixin.scss');
155
90
  }
156
91
 
157
- await write(file.replace(/less/g, 'scss').replace('.theme.', '-theme.'), scssData);
92
+ await write(file.replace(/less/g, 'scss').replace('.theme.', '-theme.'), source);
158
93
  }
159
94
 
160
- /* Second Step write all new needed files for SASS */
161
-
162
- /* write mixins into new file */
163
- delete themeMixins['svg-fill'];
164
- const mixins_theme = Object.keys(themeMixins).map(function (key) {
165
- return themeMixins[key];
166
- });
167
- await write('src/scss/mixins-theme.scss', mixins_theme.join('\n'));
168
-
169
- delete coreMixins['svg-fill'];
170
- const mixins_core = Object.keys(coreMixins).map(function (key) {
171
- return coreMixins[key];
172
- });
173
- await write('src/scss/mixins.scss', mixins_core.join('\n'));
95
+ /* Second Step: write all new needed files for Sass */
174
96
 
175
- /* write core variables */
176
- const compactCoreVar = new Set();
177
- Object.keys(coreVar).map((key) =>
178
- getAllDependencies(coreVar, key).forEach((dependency) => compactCoreVar.add(dependency))
179
- );
180
-
181
- await write('src/scss/variables.scss', Array.from(compactCoreVar).join('\n'));
182
-
183
- /* write theme variables */
184
- const compactThemeVar = new Set();
185
- Object.keys(themeVar).map((key) =>
186
- getAllDependencies(themeVar, key).forEach((dependency) => compactThemeVar.add(dependency))
187
- );
97
+ /* write mixins files */
98
+ for (const [vars, file] of [
99
+ [coreMixins, 'mixins'],
100
+ [themeMixins, 'mixins-theme'],
101
+ ]) {
102
+ delete vars['svg-fill'];
103
+ await write(`src/scss/${file}.scss`, Object.values(vars).join('\n'));
104
+ }
188
105
 
189
- await write('src/scss/variables-theme.scss', Array.from(compactThemeVar).join('\n'));
106
+ /* write variables files */
107
+ for (const [vars, file] of [
108
+ [coreVariables, 'variables'],
109
+ [themeVariables, 'variables-theme'],
110
+ ]) {
111
+ const variables = Object.keys(vars).reduce(
112
+ (dependencies, key) => resolveDependencies(vars, key, dependencies),
113
+ new Set()
114
+ );
115
+ await write(`src/scss/${file}.scss`, Array.from(variables).join('\n'));
116
+ }
190
117
 
191
118
  /*
192
- * recursive function to get a dependencie Set which is ordered so that no depencies exist to a later on entry
119
+ * recursive function to get a dependencies Set which is ordered so that no dependencies exist to a later on entry
193
120
  * @return Set with all the dependencies.
194
121
  */
195
- function getAllDependencies(allVariables, currentKey, dependencies = new Set()) {
196
- allVariables[currentKey].dependencies?.forEach((dependency) =>
197
- getAllDependencies(allVariables, dependency, dependencies).forEach((newDependency) =>
198
- dependencies.add(newDependency)
199
- )
200
- );
122
+ function resolveDependencies(allVariables, currentKey, dependencies = new Set()) {
123
+ for (const dependency of allVariables[currentKey].dependencies) {
124
+ for (const newDependency of resolveDependencies(allVariables, dependency, dependencies)) {
125
+ dependencies.add(newDependency);
126
+ }
127
+ }
201
128
 
202
129
  dependencies.add(`${currentKey}: ${allVariables[currentKey].value}`);
203
- return Array.from(dependencies);
130
+ return dependencies;
204
131
  }
205
132
 
206
133
  /*
207
- * function to extract all the mixins from a given file with its data.
134
+ * Extract all the mixins from a given file with its data.
208
135
  * @return an updated data where the mixins have been removed.
209
136
  */
210
- function getMixinsFromFile(file, data) {
137
+ function getMixinsFromFile(file, source) {
211
138
  /* Step 1: get all includes and insert them, so that at least empty mixins exist. */
212
- let regex = /@include ([a-z0-9-]+)/g;
213
- let match = regex.exec(data);
214
-
215
- while (match) {
216
- if (!(match[1] in themeMixins)) {
217
- themeMixins[match[1]] = `@mixin ${match[1]}(){}`;
139
+ for (const [, include] of source.matchAll(/@include ([a-z0-9-]+)/g)) {
140
+ if (!(include in themeMixins)) {
141
+ themeMixins[include] = `@mixin ${include}(){}`;
218
142
  }
219
- if (!(match[1] in coreMixins)) {
220
- coreMixins[match[1]] = `@mixin ${match[1]}(){}`;
143
+ if (!(include in coreMixins)) {
144
+ coreMixins[include] = `@mixin ${include}(){}`;
221
145
  }
222
-
223
- match = regex.exec(data);
224
146
  }
225
147
 
226
- /* Step 2: get all multiline mixins */
227
- regex = /@mixin ([\w-]*)\s*\((.*)\)\s*{\n(\s+[\w\W]+?)(?=\n})\n}/g;
228
- match = regex.exec(data);
229
-
230
- while (match) {
231
- [themeMixins[match[1]]] = match;
148
+ /* Step 2: get all mixins */
149
+ for (const [match, mixin] of source.matchAll(
150
+ /@mixin ([\w-]*)\s*\(.*\)\s*{(\n\s+[\w\W]+?(?=\n})\n| [^\n]+)}/g
151
+ )) {
152
+ themeMixins[mixin] = match;
232
153
  if (!file.includes('theme/')) {
233
- [coreMixins[match[1]]] = match;
154
+ coreMixins[mixin] = match;
234
155
  }
235
- match = regex.exec(data);
236
156
  }
237
157
 
238
- /* Step 3: get all single line mixins */
239
- regex = /@mixin ([\w-]*)\s*\((.*)\)\s*{( [^\n]+)}/g;
240
- match = regex.exec(data);
241
-
242
- while (match) {
243
- [themeMixins[match[1]]] = match;
244
- if (!file.includes('theme/')) {
245
- [coreMixins[match[1]]] = match;
246
- }
247
-
248
- match = regex.exec(data);
249
- }
250
-
251
- /* Step 4: remove the mixins from the file, so that users can overwrite them in their custom code. */
252
- return data
253
- .replace(/@mixin ([\w-]*)\s*\((.*)\)\s*{\n(\s+[\w\W]+?)(?=\n})\n}/g, '')
254
- .replace(/@mixin ([\w-]*)\s*\((.*)\)\s*{( [^\n]+)}/g, '');
158
+ /* Step 3: remove the mixins from the file, so that users can overwrite them in their custom code. */
159
+ return source.replace(/@mixin ([\w-]*)\s*\((.*)\)\s*{(\n(\s+[\w\W]+?)(?=\n})\n| [^\n]+)}/g, '');
255
160
  }
256
161
 
257
162
  /*
258
- * function to extract all the variables from a given file with its data.
163
+ * Extract all variables from a given file with its data.
259
164
  * @return an updated data where the icons have been replaced by the actual SVG data.
260
165
  */
261
- async function getVariablesFromFile(file, data) {
262
- const regex = /(\$[\w-]*)\s*:\s*(.*);/g;
263
- let match = regex.exec(data);
166
+ async function getVariablesFromFile(file, source) {
167
+ for (let [, name, value] of source.matchAll(/(\$[\w-]*)\s*:\s*(.*);/g)) {
168
+ let dependencies = [];
264
169
 
265
- while (match) {
266
170
  /* check if variable is a background icon, if so replace it directly by the SVG */
267
- if (match[0].includes('../../images/backgrounds')) {
268
- const iconregex =
269
- /(\$[\w-]+)\s*:\s*"\.\.\/\.\.\/images\/backgrounds\/([\w./-]+)" !default;/g;
270
- const iconmatch = iconregex.exec(match[0]);
271
- let svg = (await read(`src/images/backgrounds/${iconmatch[2]}`)).toString();
272
- svg = `"${svg
171
+ if (value.includes('../../images/backgrounds')) {
172
+ const svg = (await read(`src/${value.match(/images\/backgrounds\/[\w./-]+/)}`))
273
173
  .replace(/\r?\n|\r/g, '%0A')
274
174
  .replace(/"/g, "'")
275
175
  .replace(/\s/g, '%20')
@@ -279,43 +179,23 @@ async function getVariablesFromFile(file, data) {
279
179
  .replace(/:/g, '%3A')
280
180
  .replace(/\//g, '%2F')
281
181
  .replace(/>/g, '%3E')
282
- .replace(/%3Csvg/, 'data:image/svg+xml;charset=UTF-8,%3Csvg')}"`;
283
-
284
- /* add SVG to the coreVar and themeVar only if it is a theme file and make it optional */
285
- if (!file.includes('theme/')) {
286
- coreVar[iconmatch[1]] = { value: `${svg} !default;`, dependencies: [] };
287
- }
288
-
289
- themeVar[iconmatch[1]] = { value: `${svg} !default;`, dependencies: [] };
182
+ .replace(/%3Csvg/, 'data:image/svg+xml;charset=UTF-8,%3Csvg');
290
183
 
291
- /* add SVG to the variable within the file itself as well */
292
- const inlineSVG = `${iconmatch[1]}: ${svg} !default;`;
293
- data = data.replace(match[0], inlineSVG);
184
+ value = `"${svg}" !default`;
294
185
 
295
- /* when it is not an SVG add the variable and search for its dependencies */
186
+ /* if it's not an SVG add the variable and search for its dependencies */
296
187
  } else {
297
- const variablesRegex = /(\$[\w-]+)/g;
298
- let variablesMatch = variablesRegex.exec(match[2]);
299
- const dependencies = [];
300
-
301
- while (variablesMatch) {
302
- dependencies.push(variablesMatch[1]);
303
- variablesMatch = variablesRegex.exec(match[2]);
304
- }
188
+ dependencies = Array.from(value.matchAll(/\$[\w-]+/g)).map(([value]) => value);
189
+ }
305
190
 
306
- /* add variables only to the core Variables if it is not a theme file */
307
- if (!file.includes('theme/')) {
308
- coreVar[match[1]] = {
309
- value: `${match[2]};`,
310
- dependencies: Array.from(dependencies),
311
- };
312
- }
191
+ themeVariables[name] = { value: `${value};`, dependencies };
313
192
 
314
- themeVar[match[1]] = { value: `${match[2]};`, dependencies: Array.from(dependencies) };
193
+ /* add variables only to the core Variables if it is not a theme file */
194
+ if (!file.includes('theme/')) {
195
+ coreVariables[name] = themeVariables[name];
315
196
  }
316
-
317
- match = regex.exec(data);
318
197
  }
319
198
 
320
- return data.replace(/(\$[\w-]*)\s*:(.*);\r?\n/g, '');
199
+ // Remove variables from source
200
+ return source.replace(/(\$[\w-]*)\s*:(.*);\r?\n/g, '');
321
201
  }