vueless 0.0.490 → 0.0.492

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 (45) hide show
  1. package/constants.js +11 -2
  2. package/package.json +1 -1
  3. package/plugin-vite.d.ts +1 -0
  4. package/plugin-vite.js +25 -16
  5. package/ui.form-select/USelect.vue +0 -1
  6. package/ui.image-icon/UIcon.vue +9 -7
  7. package/utils/node/helper.js +20 -8
  8. package/utils/node/loaderIcon.js +198 -126
  9. package/utils/node/loaderSvg.js +3 -3
  10. package/utils/node/vuelessConfig.js +5 -2
  11. package/web-types.json +1 -1
  12. /package/assets/icons/{add.svg → vueless/add.svg} +0 -0
  13. /package/assets/icons/{apps.svg → vueless/apps.svg} +0 -0
  14. /package/assets/icons/{arrow_back.svg → vueless/arrow_back.svg} +0 -0
  15. /package/assets/icons/{attach_file.svg → vueless/attach_file.svg} +0 -0
  16. /package/assets/icons/{calendar_month-fill.svg → vueless/calendar_month-fill.svg} +0 -0
  17. /package/assets/icons/{check.svg → vueless/check.svg} +0 -0
  18. /package/assets/icons/{check_circle.svg → vueless/check_circle.svg} +0 -0
  19. /package/assets/icons/{chevron_left.svg → vueless/chevron_left.svg} +0 -0
  20. /package/assets/icons/{chevron_right.svg → vueless/chevron_right.svg} +0 -0
  21. /package/assets/icons/{close.svg → vueless/close.svg} +0 -0
  22. /package/assets/icons/{close_small.svg → vueless/close_small.svg} +0 -0
  23. /package/assets/icons/{delete.svg → vueless/delete.svg} +0 -0
  24. /package/assets/icons/{description.svg → vueless/description.svg} +0 -0
  25. /package/assets/icons/{drag_indicator.svg → vueless/drag_indicator.svg} +0 -0
  26. /package/assets/icons/{edit.svg → vueless/edit.svg} +0 -0
  27. /package/assets/icons/{edit_note.svg → vueless/edit_note.svg} +0 -0
  28. /package/assets/icons/{emoji_food_beverage.svg → vueless/emoji_food_beverage.svg} +0 -0
  29. /package/assets/icons/{error.svg → vueless/error.svg} +0 -0
  30. /package/assets/icons/{expand_more.svg → vueless/expand_more.svg} +0 -0
  31. /package/assets/icons/{first_page.svg → vueless/first_page.svg} +0 -0
  32. /package/assets/icons/{image.svg → vueless/image.svg} +0 -0
  33. /package/assets/icons/{keyboard_arrow_down.svg → vueless/keyboard_arrow_down.svg} +0 -0
  34. /package/assets/icons/{keyboard_arrow_left.svg → vueless/keyboard_arrow_left.svg} +0 -0
  35. /package/assets/icons/{keyboard_arrow_right.svg → vueless/keyboard_arrow_right.svg} +0 -0
  36. /package/assets/icons/{label.svg → vueless/label.svg} +0 -0
  37. /package/assets/icons/{last_page.svg → vueless/last_page.svg} +0 -0
  38. /package/assets/icons/{remove.svg → vueless/remove.svg} +0 -0
  39. /package/assets/icons/{search.svg → vueless/search.svg} +0 -0
  40. /package/assets/icons/{star-fill.svg → vueless/star-fill.svg} +0 -0
  41. /package/assets/icons/{star.svg → vueless/star.svg} +0 -0
  42. /package/assets/icons/{title.svg → vueless/title.svg} +0 -0
  43. /package/assets/icons/{visibility-fill.svg → vueless/visibility-fill.svg} +0 -0
  44. /package/assets/icons/{visibility_off-fill.svg → vueless/visibility_off-fill.svg} +0 -0
  45. /package/assets/icons/{warning.svg → vueless/warning.svg} +0 -0
package/constants.js CHANGED
@@ -185,6 +185,17 @@ export const DEFAULT_SVGO_CONFIG = {
185
185
  ],
186
186
  };
187
187
 
188
+ /* Vueless general */
189
+ export const ICONS_DIR = "assets/icons";
190
+ export const VUELESS_LIBRARY = "vueless";
191
+ export const VUELESS_CONFIG_FILE_NAME = "vueless.config";
192
+ export const VUELESS_CACHE_DIR = "node_modules/.cache/vueless";
193
+ export const VUELESS_DIR = `node_modules/${VUELESS_LIBRARY}`;
194
+ export const VUELESS_LOCAL_DIR = `src`;
195
+ export const VUELESS_ICONS_DIR = `${VUELESS_DIR}/${ICONS_DIR}`;
196
+ export const VUELESS_ICONS_LOCAL_DIR = `src/${ICONS_DIR}`;
197
+ export const VUELESS_ICONS_CACHED_DIR = `${VUELESS_CACHE_DIR}/${ICONS_DIR}`;
198
+
188
199
  /* Other */
189
200
  export const PX_IN_REM = 16;
190
201
  export const NESTED_COMPONENT_REG_EXP = /\{U[^}]*}/g;
@@ -192,5 +203,3 @@ export const DYNAMIC_COLOR_PATTERN = "{color}";
192
203
  export const TAILWIND_COLOR_OPACITY_DELIMITER = "/";
193
204
  export const TAILWIND_VARIANT_DELIMITER = ":";
194
205
  export const TAILWIND_VARIANT_DELIMITER_REG_EXP = /:(?![^[]*])/;
195
- export const CACHE_PATH = "node_modules/.cache/vueless";
196
- export const VUELESS_CONFIG_FILE_NAME = "vueless.config";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vueless",
3
- "version": "0.0.490",
3
+ "version": "0.0.492",
4
4
  "license": "MIT",
5
5
  "description": "Vue Styleless UI Component Library, powered by Tailwind CSS.",
6
6
  "keywords": [
package/plugin-vite.d.ts CHANGED
@@ -7,4 +7,5 @@ export function Vueless(options?: {
7
7
  mode?: string;
8
8
  debug?: boolean;
9
9
  include?: string[];
10
+ mirrorCacheDir?: string;
10
11
  }): never;
package/plugin-vite.js CHANGED
@@ -6,9 +6,9 @@
6
6
  import UnpluginVueComponents from "unplugin-vue-components/vite";
7
7
 
8
8
  import { loadSvg } from "./utils/node/loaderSvg.js";
9
- import { copyIcons, removeIcons } from "./utils/node/loaderIcon.js";
9
+ import { cacheIcons, removeIconsCache, copyIconsCache } from "./utils/node/loaderIcon.js";
10
10
  import { createTailwindSafelist, clearTailwindSafelist } from "./utils/node/tailwindSafelist.js";
11
- import { getNuxtFiles, getVueSourceFile } from "./utils/node/helper.js";
11
+ import { getNuxtFiles, getVueFiles } from "./utils/node/helper.js";
12
12
  import { componentResolver, directiveResolver } from "./utils/node/vuelessResolver.js";
13
13
 
14
14
  /* Automatically importing Vueless components on demand */
@@ -25,21 +25,22 @@ export const VuelessUnpluginComponents = (options) =>
25
25
  – Loads SVG images as a Vue components.
26
26
  */
27
27
  export const Vueless = function (options = {}) {
28
- const { mode, debug, env, include } = options;
28
+ const { mode, debug, env, include, mirrorCacheDir } = options;
29
29
 
30
30
  const isVuelessEnv = env === "vueless";
31
31
  const isNuxt = mode === "nuxt-module";
32
- const srcDir = isNuxt ? process.cwd() : getVueSourceFile();
33
32
 
34
- const targetFiles = [srcDir, ...(include || []), ...(isNuxt ? getNuxtFiles() : [])];
33
+ const targetFiles = [...(include || []), ...(isNuxt ? getNuxtFiles() : getVueFiles())];
35
34
 
36
35
  /* if server stopped by developer (Ctrl+C) */
37
36
  process.on("SIGINT", async () => {
38
- /* remove dynamically copied icons */
39
- await removeIcons({ debug });
37
+ /* remove cached icons */
38
+ await removeIconsCache(mirrorCacheDir, debug);
40
39
 
41
40
  /* clear tailwind safelist */
42
41
  clearTailwindSafelist(debug);
42
+
43
+ /* stop command line process */
43
44
  process.exit(0);
44
45
  });
45
46
 
@@ -57,28 +58,36 @@ export const Vueless = function (options = {}) {
57
58
  }),
58
59
 
59
60
  configResolved: async (config) => {
60
- /* collect used in project colors for tailwind safelist */
61
61
  if (!isNuxt) {
62
+ /* collect used in project colors for tailwind safelist */
62
63
  await createTailwindSafelist({ mode, env, debug, targetFiles });
63
64
  }
64
65
 
65
66
  if (config.command === "build") {
66
- await removeIcons({ debug });
67
+ /* remove cached icons */
68
+ await removeIconsCache(mirrorCacheDir, debug);
69
+
70
+ /* cache vueless built-in and project icons */
71
+ await cacheIcons({ mode: "vuelessIcons", env, debug, targetFiles });
72
+ await cacheIcons({ mode, env, debug, targetFiles });
67
73
 
68
- /* dynamically copy used icons before build */
69
- await copyIcons({ mode: "vuelessIcons", env, debug, targetFiles });
70
- await copyIcons({ mode, env, debug, targetFiles });
74
+ /* copy vueless cache folder */
75
+ await copyIconsCache(mirrorCacheDir, debug);
71
76
  }
72
77
 
73
78
  if (config.command === "dev" || config.command === "serve") {
74
- /* remove dynamically copied icons on dev server start */
75
- await removeIcons({ debug });
79
+ /* remove cached icons */
80
+ await removeIconsCache(mirrorCacheDir, debug);
81
+ /* cache vueless built-in icons */
82
+ await cacheIcons({ mode: "vuelessIcons", env, debug, targetFiles });
83
+ /* copy vueless cache folder */
84
+ await copyIconsCache(mirrorCacheDir, debug);
76
85
  }
77
86
  },
78
87
 
79
- /* remove dynamically copied icons after build */
80
88
  buildEnd: async () => {
81
- await removeIcons({ debug });
89
+ /* remove cached icons */
90
+ await removeIconsCache(mirrorCacheDir, debug);
82
91
  },
83
92
 
84
93
  /* load SVG images as a Vue components */
@@ -209,7 +209,6 @@
209
209
  autocomplete="off"
210
210
  :spellcheck="false"
211
211
  :placeholder="inputPlaceholder"
212
- :value="search"
213
212
  :disabled="disabled"
214
213
  :aria-controls="'listbox-' + elementId"
215
214
  v-bind="searchInputAttrs"
@@ -11,15 +11,15 @@
11
11
 
12
12
  <script setup>
13
13
  import { computed, defineAsyncComponent } from "vue";
14
+ import { vTooltip } from "../directives";
14
15
  import { getDefault } from "../utils/ui.ts";
15
16
  import { isSSR } from "../utils/helper.ts";
17
+ import { VUELESS_ICONS_CACHED_DIR, VUELESS_LIBRARY } from "../constants.js";
16
18
 
17
19
  import { UIcon } from "./constants.js";
18
20
  import defaultConfig from "./config.ts";
19
21
  import useAttrs from "./useAttrs.js";
20
22
 
21
- import { vTooltip } from "../directives";
22
-
23
23
  defineOptions({ inheritAttrs: false });
24
24
 
25
25
  const props = defineProps({
@@ -140,10 +140,12 @@ const generatedIcons = computed(() => {
140
140
  const dynamicComponent = computed(() => {
141
141
  const FILL_SUFFIX = "-fill";
142
142
 
143
- const isDefaultIcon = Boolean(generatedIcons.value.find(([path]) => path.includes(props.name)));
144
- const userLibrary = config.value.defaults.library;
143
+ const isInternalIcon = Boolean(
144
+ generatedIcons.value.find(([path]) => path.includes(VUELESS_LIBRARY + "/" + props.name)),
145
+ );
145
146
 
146
- const library = props.internal && isDefaultIcon ? "vueless" : userLibrary;
147
+ const userLibrary = config.value.defaults.library;
148
+ const library = props.internal && isInternalIcon ? VUELESS_LIBRARY : userLibrary;
147
149
  const weight = config.value.defaults.weight;
148
150
  const style = config.value.defaults.style;
149
151
  const isFill = props.name.endsWith(FILL_SUFFIX);
@@ -176,8 +178,8 @@ const dynamicComponent = computed(() => {
176
178
  return import.meta.env.PROD
177
179
  ? await getIcon([name])
178
180
  : isSSR
179
- ? import(/* @vite-ignore */ `node_modules/.cache/vueless/assets/icons/${name}.svg?component`)
180
- : import(/* @vite-ignore */ `/node_modules/.cache/vueless/assets/icons/${name}.svg?component`);
181
+ ? import(/* @vite-ignore */ `${VUELESS_ICONS_CACHED_DIR}/${VUELESS_LIBRARY}/${name}.svg?component`)
182
+ : import(/* @vite-ignore */ `/${VUELESS_ICONS_CACHED_DIR}/${VUELESS_LIBRARY}/${name}.svg?component`);
181
183
  },
182
184
  "@material-symbols": async () => {
183
185
  return import.meta.env.PROD
@@ -5,15 +5,27 @@ import { readdir } from "node:fs/promises";
5
5
  export async function getDirFiles(dirPath, ext, { recursive = true, exclude = [] } = {}) {
6
6
  let fileNames = [];
7
7
 
8
+ const ERROR_CODE = {
9
+ dirIsFile: "ENOTDIR",
10
+ noEntry: "ENOENT",
11
+ };
12
+
8
13
  try {
9
14
  fileNames = await readdir(dirPath, { recursive });
10
15
  } catch (error) {
11
- if (error.code === "ENOTDIR") {
12
- fileNames = [dirPath.split(path.sep).at(-1)];
13
- dirPath = dirPath.split(path.sep).slice(0, -1).join(path.sep);
14
- } else if (error.code === "ENOENT") {
16
+ if (error.code === ERROR_CODE.dirIsFile) {
17
+ const pathArray = dirPath.split(path.sep);
18
+ const fileName = pathArray.pop();
19
+
20
+ fileNames = [fileName];
21
+ dirPath = pathArray.join(path.sep);
22
+ }
23
+
24
+ if (error.code === ERROR_CODE.noEntry) {
15
25
  fileNames = [];
16
- } else {
26
+ }
27
+
28
+ if (!Object.values(ERROR_CODE).includes(error.code)) {
17
29
  // eslint-disable-next-line no-console
18
30
  console.error(error);
19
31
  }
@@ -52,8 +64,8 @@ export function getNuxtFiles() {
52
64
  ];
53
65
  }
54
66
 
55
- export function getVueSourceFile() {
56
- return path.join(process.cwd(), "src");
67
+ export function getVueFiles() {
68
+ return [path.join(process.cwd(), "src")];
57
69
  }
58
70
 
59
71
  export function getDefaultConfigJson(fileContents) {
@@ -64,7 +76,7 @@ export function getDefaultConfigJson(fileContents) {
64
76
  return (0, eval)("(" + objectString + ")"); // Converting into JS object
65
77
  }
66
78
 
67
- export function merge(source, target) {
79
+ export function merge(source = {}, target = {}) {
68
80
  for (const [key, val] of Object.entries(source)) {
69
81
  if (val !== null && typeof val === `object`) {
70
82
  target[key] ??= new val.__proto__.constructor();
@@ -1,10 +1,7 @@
1
1
  /**
2
2
  This scrypt find icon names from the UIcon props and objects across the project
3
3
  and copy SVG icons from the default icons library (@material-symbols or other from config)
4
- to the ".../cache" folder.
5
-
6
- Those icons will be used only in the build stage.
7
- The script is needed to avoid all @material-symbols icons set in the project bundle.
4
+ to the `VUELESS_ICONS_CACHED_DIR` folder.
8
5
  */
9
6
 
10
7
  /* eslint-disable no-console */
@@ -15,89 +12,140 @@ import { rm, cp } from "node:fs/promises";
15
12
 
16
13
  import { vuelessConfig } from "./vuelessConfig.js";
17
14
  import { getDirFiles, getDefaultConfigJson, merge } from "./helper.js";
18
- import { CACHE_PATH, VUELESS_CONFIG_FILE_NAME } from "../../constants.js";
19
-
20
- const ICONS_DIR = "assets/icons";
21
- const DEFAULT_ICONS_DIR = path.join(process.cwd(), `node_modules/vueless/${ICONS_DIR}`);
22
- const DEFAULT_ICONS_LOCAL_DIR = path.join(process.cwd(), `src/${ICONS_DIR}`);
23
- const CACHED_ICONS_DIR = path.join(process.cwd(), `${CACHE_PATH}/${ICONS_DIR}`);
24
- const ICON_CONFIG_PATH = "ui.image-icon/config.ts";
25
- const ICON_COMPONENT_NAME = "UIcon";
26
- const STORYBOOK_STORY_EXTENSIONS = ["/stories.js", "/stories.ts"];
15
+ import {
16
+ COMPONENTS,
17
+ VUELESS_DIR,
18
+ VUELESS_LOCAL_DIR,
19
+ VUELESS_LIBRARY,
20
+ VUELESS_ICONS_DIR,
21
+ VUELESS_ICONS_LOCAL_DIR,
22
+ VUELESS_ICONS_CACHED_DIR,
23
+ VUELESS_CONFIG_FILE_NAME,
24
+ ICONS_DIR,
25
+ } from "../../constants.js";
26
+
27
+ const cwd = process.cwd();
28
+
29
+ const DEFAULT_ICONS_DIR = path.join(cwd, VUELESS_ICONS_DIR);
30
+ const DEFAULT_ICONS_LOCAL_DIR = path.join(cwd, VUELESS_ICONS_LOCAL_DIR);
31
+ const CACHED_ICONS_DIR = path.join(cwd, VUELESS_ICONS_CACHED_DIR);
32
+ const U_ICON = "UIcon";
27
33
 
28
34
  let isDebug = false;
29
35
  let isVuelessEnv = false;
30
- let isDefaultMode = false;
31
36
  let isStorybookMode = false;
32
37
  let isVuelessIconsMode = false;
33
- let cachedIconsDir = CACHED_ICONS_DIR;
38
+ let cacheIconsPath = CACHED_ICONS_DIR;
34
39
 
35
- // perform icons copy magick... ✨
36
- export async function copyIcons({ mode = "", env, debug, targetFiles = [] } = {}) {
40
+ /**
41
+ * Dynamically find icons across the project and cache it.
42
+ * Icons cache magick happens here... ✨
43
+ * @param {string} mode
44
+ * @param {string} env
45
+ * @param {boolean} debug
46
+ * @param {Array} targetFiles
47
+ */
48
+ export async function cacheIcons({ mode, env, debug, targetFiles = [] } = {}) {
37
49
  isDebug = debug || false;
38
50
  isVuelessEnv = env === "vueless";
39
- isDefaultMode = mode === "";
40
51
  isStorybookMode = mode === "storybook";
41
52
  isVuelessIconsMode = mode === "vuelessIcons";
53
+ cacheIconsPath = CACHED_ICONS_DIR;
42
54
 
43
- /* Copy icons which using in vueless components to the cache (vueless env only). */
44
- if (isVuelessEnv && fs.existsSync(DEFAULT_ICONS_LOCAL_DIR)) {
45
- await cp(DEFAULT_ICONS_LOCAL_DIR, CACHED_ICONS_DIR, { recursive: true });
55
+ if (isVuelessIconsMode && isVuelessEnv) {
56
+ cacheIconsPath = DEFAULT_ICONS_LOCAL_DIR;
46
57
  }
47
58
 
48
- /* Copy icons which using in vueless components to the cache. */
49
- if (!isVuelessEnv && fs.existsSync(DEFAULT_ICONS_DIR)) {
50
- await cp(DEFAULT_ICONS_DIR, CACHED_ICONS_DIR, { recursive: true });
51
- }
59
+ const exclude = isStorybookMode ? [] : ["/stories.js", "/stories.ts", ".d.ts"];
52
60
 
53
- if (isVuelessIconsMode && isVuelessEnv) cachedIconsDir = DEFAULT_ICONS_LOCAL_DIR;
54
- if (isStorybookMode && isVuelessEnv) cachedIconsDir = CACHED_ICONS_DIR;
61
+ const vueFiles = targetFiles.map((componentPath) => getDirFiles(componentPath, ".vue"));
62
+ const jsFiles = targetFiles.map((jsFilePath) => getDirFiles(jsFilePath, ".js", { exclude }));
63
+ const tsFiles = targetFiles.map((tsFilePath) => getDirFiles(tsFilePath, ".ts", { exclude }));
55
64
 
56
- if (isStorybookMode) {
57
- const storybookStoriesJs = await getDirFiles("src", STORYBOOK_STORY_EXTENSIONS[0]);
58
- const storybookStoriesTs = await getDirFiles("src", STORYBOOK_STORY_EXTENSIONS[1]);
65
+ const iconFiles = await Promise.all([...vueFiles, ...jsFiles, ...tsFiles]);
59
66
 
60
- findAndCopyIcons([...storybookStoriesJs, ...storybookStoriesTs]);
61
- }
67
+ findAndCopyIcons([
68
+ ...iconFiles.flat(),
69
+ `${VUELESS_CONFIG_FILE_NAME}.js`,
70
+ `${VUELESS_CONFIG_FILE_NAME}.ts`,
71
+ ]);
62
72
 
63
- if (isVuelessIconsMode || isDefaultMode || isStorybookMode) {
64
- const vueFiles = targetFiles.map((componentPath) => getDirFiles(componentPath, ".vue"));
73
+ if (isVuelessIconsMode) {
74
+ await copyVuelessIconsIntoCache(isVuelessEnv);
75
+ }
76
+ }
65
77
 
66
- const jsFiles = targetFiles.map((jsFilePath) =>
67
- getDirFiles(jsFilePath, ".js", { exclude: [STORYBOOK_STORY_EXTENSIONS[0]] }),
68
- );
78
+ /**
79
+ * Remove cached icons.
80
+ * @param {string} mirrorCacheDir
81
+ * @param {boolean} debug
82
+ * @returns {Promise<void>}
83
+ */
84
+ export async function removeIconsCache(mirrorCacheDir, debug) {
85
+ if (fs.existsSync(cacheIconsPath)) {
86
+ await rm(cacheIconsPath, { recursive: true, force: true });
87
+ }
69
88
 
70
- const tsFiles = targetFiles.map((tsFilePath) =>
71
- getDirFiles(tsFilePath, ".ts", { exclude: [STORYBOOK_STORY_EXTENSIONS[1], ".d.ts"] }),
72
- );
89
+ if (mirrorCacheDir) {
90
+ const mirrorCacheIconsPath = path.join(cwd, mirrorCacheDir, ICONS_DIR);
73
91
 
74
- const iconFiles = await Promise.all([...vueFiles, ...jsFiles, ...tsFiles]);
92
+ if (fs.existsSync(mirrorCacheIconsPath)) {
93
+ await rm(mirrorCacheIconsPath, { recursive: true, force: true });
94
+ }
95
+ }
75
96
 
76
- findAndCopyIcons([
77
- ...iconFiles.flat(),
78
- `${VUELESS_CONFIG_FILE_NAME}.js`,
79
- `${VUELESS_CONFIG_FILE_NAME}.ts`,
80
- ]);
97
+ if (debug) {
98
+ console.log("Icons cache was successfully removed.");
81
99
  }
82
100
  }
83
101
 
84
- export async function removeIcons({ debug }) {
85
- if (!fs.existsSync(cachedIconsDir)) return;
102
+ /**
103
+ * Copy cached icons in the provided folder by path.
104
+ * @param {string} mirrorCacheDir
105
+ * @param {boolean} debug
106
+ * @returns {Promise<void>}
107
+ */
108
+ export async function copyIconsCache(mirrorCacheDir, debug) {
109
+ const cachePath = path.join(cwd, VUELESS_ICONS_CACHED_DIR);
86
110
 
87
- await rm(cachedIconsDir, { recursive: true, force: true });
111
+ if (mirrorCacheDir && fs.existsSync(cachePath)) {
112
+ await cp(cachePath, path.join(cwd, mirrorCacheDir, ICONS_DIR), { recursive: true });
113
+ }
88
114
 
89
115
  if (debug) {
90
- console.log("Dynamically copied icons was successfully removed.");
116
+ console.log(`Vueless cached icons was successfully copied into: ${mirrorCacheDir}.`);
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Copy icons which using in vueless components to the cache.
122
+ * @param {boolean} isVuelessEnv
123
+ * @returns {Promise<void>}
124
+ */
125
+ async function copyVuelessIconsIntoCache(isVuelessEnv) {
126
+ if (isVuelessEnv && fs.existsSync(DEFAULT_ICONS_LOCAL_DIR)) {
127
+ await cp(DEFAULT_ICONS_LOCAL_DIR, CACHED_ICONS_DIR, {
128
+ recursive: true,
129
+ });
130
+ }
131
+
132
+ if (!isVuelessEnv && fs.existsSync(DEFAULT_ICONS_DIR)) {
133
+ await cp(DEFAULT_ICONS_DIR, CACHED_ICONS_DIR, {
134
+ recursive: true,
135
+ });
91
136
  }
92
137
  }
93
138
 
139
+ /**
140
+ * Scan the project for icon names and copy found icons to the cache.
141
+ * @param {Array} files
142
+ */
94
143
  function findAndCopyIcons(files) {
95
- const defaults = getMergedConfig();
96
- const safelistIcons = getSafelistIcons();
144
+ const defaults = getDefaults();
145
+ const safelistIcons = vuelessConfig.component?.[U_ICON]?.safelistIcons;
97
146
 
98
- safelistIcons.forEach((iconName) => {
99
- copyFile(iconName, false);
100
- copyFile(iconName, true);
147
+ safelistIcons?.forEach((iconName) => {
148
+ copyIcon(iconName, defaults);
101
149
  });
102
150
 
103
151
  files.forEach((file) => {
@@ -114,7 +162,7 @@ function findAndCopyIcons(files) {
114
162
 
115
163
  try {
116
164
  if (iconName) {
117
- copyFile(iconName);
165
+ copyIcon(iconName, defaults);
118
166
  }
119
167
  } catch (error) {
120
168
  isDebug && console.log(error);
@@ -137,103 +185,127 @@ function findAndCopyIcons(files) {
137
185
  try {
138
186
  if (!iconName) return;
139
187
 
140
- if (iconName?.includes("?")) {
188
+ if (iconName?.includes("?") && iconName?.includes(":")) {
141
189
  const [trueName, falseName] = getTernaryValues(iconName);
142
190
 
143
- copyFile(trueName);
144
- copyFile(falseName);
191
+ copyIcon(trueName, defaults);
192
+ copyIcon(falseName, defaults);
145
193
  } else {
146
- copyFile(iconName);
194
+ copyIcon(iconName, defaults);
147
195
  }
148
196
  } catch (error) {
149
197
  isDebug && console.log(error);
150
198
  }
151
199
  }
152
200
  });
201
+ }
153
202
 
154
- function getTernaryValues(expression) {
155
- const [, values] = expression
156
- .replace(/\s/g, "") // newlines and spaces
157
- .replace(/\?\./g, "") // conditional chaining `?.`
158
- .replace(/['"]/g, "") // single and double quotes
159
- .split("?");
203
+ /**
204
+ * Retrieve values from ternary of strings.
205
+ * @param {string} expression
206
+ * @returns {Array} of ternary values
207
+ */
208
+ function getTernaryValues(expression) {
209
+ const [, values] = expression
210
+ .replace(/\s/g, "") // newlines and spaces
211
+ .replace(/\?\./g, "") // conditional chaining `?.`
212
+ .replace(/['"]/g, "") // single and double quotes
213
+ .split("?");
160
214
 
161
- const [trueValue, falseValue] = values.split(":");
215
+ const [trueValue, falseValue] = values.split(":");
162
216
 
163
- return [trueValue, falseValue];
164
- }
217
+ return [trueValue, falseValue];
218
+ }
165
219
 
166
- function copyFile(name) {
167
- name = name.toLowerCase();
220
+ /**
221
+ * Copy icon from icon package into cache folder.
222
+ * @param {string} name
223
+ * @param {object} defaults
224
+ */
225
+ function copyIcon(name, defaults) {
226
+ name = name.toLowerCase();
168
227
 
169
- const iconNameRegex = /^[a-z0-9_-]+$/;
228
+ const iconNameRegex = /^[a-z0-9_-]+$/;
170
229
 
171
- /* Filter irrelevant icon name cases. */
172
- if (!iconNameRegex.test(name)) {
173
- return;
174
- }
230
+ /* Stop the scrypt if the icon name is irrelevant. */
231
+ if (!iconNameRegex.test(name)) {
232
+ return;
233
+ }
175
234
 
176
- const library = defaults.library;
177
- const weight = defaults.weight;
178
- const style = defaults.style;
179
-
180
- const require = createRequire(import.meta.url);
181
-
182
- /* eslint-disable vue/max-len, prettier/prettier */
183
- const libraries = {
184
- vueless: {
185
- // @material-symbols icons which used across the components.
186
- source: `${process.cwd()}/node_modules/${library}/svg-${weight}/${style}/${name}.svg`,
187
- destination: `${cachedIconsDir}/${name}.svg`
188
- },
189
- "@material-symbols": {
190
- source: `${process.cwd()}/node_modules/${library}/svg-${weight}/${style}/${name}.svg`,
191
- destination: `${cachedIconsDir}/${library}/svg-${weight}/${style}/${name}.svg`
192
- },
193
- "bootstrap-icons": {
194
- source: `${process.cwd()}/node_modules/${library}/icons/${name}.svg`,
195
- destination: `${cachedIconsDir}/${library}/icons/${name}.svg`
196
- },
197
- heroicons: {
198
- source: `${process.cwd()}/node_modules/${library}/24/${name.endsWith("-fill") ? "solid" : "outline"}/${name}.svg`,
199
- destination: `${cachedIconsDir}/24/${style}/${name.endsWith("-fill") ? "solid" : "outline"}/${name}.svg`
200
- }
201
- };
202
- /* eslint-enable vue/max-len, prettier/prettier */
235
+ const { source, destination } = getIconLibraryPaths(name, defaults);
203
236
 
204
- const { source, destination } =
205
- libraries[isVuelessIconsMode && isVuelessEnv ? "vueless" : library];
237
+ if (!fs.existsSync(source) || fs.existsSync(destination)) {
238
+ return;
239
+ }
206
240
 
207
- if (fs.existsSync(destination) || !fs.existsSync(source)) return;
241
+ const require = createRequire(import.meta.url);
242
+ const destDir = path.dirname(destination);
208
243
 
209
- const destDir = path.dirname(destination);
244
+ fs.mkdirSync(destDir, {
245
+ recursive: true,
246
+ });
210
247
 
211
- fs.mkdirSync(destDir, { recursive: true });
212
- fs.copyFile(require.resolve(source), destination, (error) => {
213
- if (isDebug) {
214
- error
215
- ? console.error(`Error copying icon "${name}":`, error)
216
- : console.log(`Icon "${name}" copied successfully!`);
217
- }
218
- });
219
- }
248
+ fs.copyFile(require.resolve(source), destination, (error) => {
249
+ if (isDebug) {
250
+ error
251
+ ? console.error(`Error copying icon "${name}":`, error)
252
+ : console.log(`Icon "${name}" copied successfully!`);
253
+ }
254
+ });
220
255
  }
221
256
 
222
- function getSafelistIcons() {
223
- return vuelessConfig.component
224
- ? vuelessConfig.component[ICON_COMPONENT_NAME]?.safelistIcons || []
225
- : [];
257
+ /**
258
+ * Build a path to the icon source in the selected icon library and cache destination path.
259
+ * @param {string} name
260
+ * @param {object} defaults
261
+ * @returns {source: string, destination: string}
262
+ */
263
+ function getIconLibraryPaths(name, defaults) {
264
+ const library = defaults.library;
265
+ const weight = defaults.weight;
266
+ const style = defaults.style;
267
+
268
+ /* eslint-disable prettier/prettier, vue/max-len */
269
+ const libraries = {
270
+ [VUELESS_LIBRARY]: {
271
+ // @material-symbols icons which used across the components.
272
+ source: `${cwd}/node_modules/${library}/svg-${weight}/${style}/${name}.svg`,
273
+ destination: `${cacheIconsPath}/${VUELESS_LIBRARY}/${name}.svg`
274
+ },
275
+ "@material-symbols": {
276
+ source: `${cwd}/node_modules/${library}/svg-${weight}/${style}/${name}.svg`,
277
+ destination: `${cacheIconsPath}/${library}/svg-${weight}/${style}/${name}.svg`
278
+ },
279
+ "bootstrap-icons": {
280
+ source: `${cwd}/node_modules/${library}/icons/${name}.svg`,
281
+ destination: `${cacheIconsPath}/${library}/icons/${name}.svg`
282
+ },
283
+ "heroicons": {
284
+ source: `${cwd}/node_modules/${library}/24/${name.endsWith("-fill") ? "solid" : "outline"}/${name}.svg`,
285
+ destination: `${cacheIconsPath}/${library}/24/${style}/${name.endsWith("-fill") ? "solid" : "outline"}/${name}.svg`
286
+ }
287
+ };
288
+ /* eslint-enable prettier/prettier, vue/max-len */
289
+
290
+ const libraryName = isVuelessIconsMode && isVuelessEnv ? VUELESS_LIBRARY : library;
291
+
292
+ return libraries[libraryName];
226
293
  }
227
294
 
228
- function getMergedConfig() {
229
- const defaultConfigPath = (isVuelessEnv ? "src/" : "node_modules/vueless/") + ICON_CONFIG_PATH;
295
+ /**
296
+ * Merge global and local defaults config for UIcon.
297
+ * @returns {Object}
298
+ */
299
+ function getDefaults() {
300
+ const defaultIconsDir = isVuelessEnv ? VUELESS_LOCAL_DIR : VUELESS_DIR;
301
+ const defaultConfigPath = path.join(cwd, defaultIconsDir, COMPONENTS[U_ICON], "config.ts");
230
302
 
231
303
  if (fs.existsSync(defaultConfigPath)) {
232
304
  const defaultConfigFile = fs.readFileSync(defaultConfigPath).toString();
233
305
 
234
- const defaultConfig = getDefaultConfigJson(defaultConfigFile);
235
- const globalConfig = vuelessConfig.component && vuelessConfig.component[ICON_COMPONENT_NAME];
236
-
237
- return merge(globalConfig?.defaults || {}, defaultConfig.defaults);
306
+ return merge(
307
+ getDefaultConfigJson(defaultConfigFile)?.defaults,
308
+ vuelessConfig?.component?.[U_ICON]?.defaults,
309
+ );
238
310
  }
239
311
  }
@@ -25,7 +25,7 @@ export async function loadSvg(id, options) {
25
25
  svgPath = svgPath.replace("/__skip_vite/", "");
26
26
 
27
27
  // use default svg loader
28
- if (importType === "url" && !svgPath.includes(".generated")) {
28
+ if (importType === "url") {
29
29
  return;
30
30
  }
31
31
 
@@ -36,11 +36,11 @@ export async function loadSvg(id, options) {
36
36
 
37
37
  try {
38
38
  svg = await fs.promises.readFile(svgPath, "utf-8");
39
- } catch {
39
+ } catch (error) {
40
40
  // define an empty svg to prevent a UI crash.
41
41
  svg = `<svg xmlns="http://www.w3.org/2000/svg"></svg>`;
42
42
  // eslint-disable-next-line no-console
43
- console.warn("\n", `${id} couldn't be loaded by vueless vite plugin.`);
43
+ console.warn(`${svgPath} couldn't be loaded by vueless vite plugin.`, "\n", error);
44
44
  }
45
45
 
46
46
  if (importType === "raw") {
@@ -2,7 +2,7 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import esbuild from "esbuild";
4
4
 
5
- import { CACHE_PATH, VUELESS_CONFIG_FILE_NAME } from "../../constants.js";
5
+ import { VUELESS_CACHE_DIR, VUELESS_CONFIG_FILE_NAME } from "../../constants.js";
6
6
 
7
7
  /**
8
8
  * Load Vueless config from the project root.
@@ -13,7 +13,10 @@ export let vuelessConfig = {};
13
13
  (async () => {
14
14
  const configPathJs = path.join(process.cwd(), `${VUELESS_CONFIG_FILE_NAME}.js`);
15
15
  const configPathTs = path.join(process.cwd(), `${VUELESS_CONFIG_FILE_NAME}.ts`);
16
- const configOutPath = path.join(process.cwd(), `${CACHE_PATH}/${VUELESS_CONFIG_FILE_NAME}.mjs`);
16
+ const configOutPath = path.join(
17
+ process.cwd(),
18
+ `${VUELESS_CACHE_DIR}/${VUELESS_CONFIG_FILE_NAME}.mjs`,
19
+ );
17
20
 
18
21
  if (!fs.existsSync(configPathJs) && !fs.existsSync(configPathTs)) {
19
22
  vuelessConfig = {};
package/web-types.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "framework": "vue",
3
3
  "name": "vueless",
4
- "version": "0.0.490",
4
+ "version": "0.0.492",
5
5
  "contributions": {
6
6
  "html": {
7
7
  "description-markup": "markdown",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes