@cyberalien/svg-utils 0.1.0 → 0.1.1

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.
@@ -6,8 +6,9 @@ import { stringifyFactoryPropTypes } from "../../props/types.js";
6
6
  */
7
7
  function addVueComponentTypes(data, options, assets, props) {
8
8
  const propTypes = stringifyFactoryPropTypes(props);
9
+ const filename = getGeneratedComponentTypesFilename(data, options);
9
10
  assets.push({
10
- ...getGeneratedComponentTypesFilename(data, options),
11
+ ...filename,
11
12
  content: `import { DefineSetupFnComponent, PublicProps } from 'vue';
12
13
 
13
14
  interface IconProps {
@@ -20,6 +21,7 @@ export { type IconProps };
20
21
  export default Component;
21
22
  `
22
23
  });
24
+ return filename.filename;
23
25
  }
24
26
 
25
27
  export { addVueComponentTypes };
@@ -0,0 +1,8 @@
1
+ import { FactoryIconData } from "../types/data.js";
2
+ import { FactoryGeneratedComponent } from "../types/component.js";
3
+ import { ComponentFactoryOptions } from "../types/options.js";
4
+ /**
5
+ * Create functional Vue component code
6
+ */
7
+ declare function createVueFunctionalComponent(data: FactoryIconData, options: ComponentFactoryOptions): FactoryGeneratedComponent;
8
+ export { createVueFunctionalComponent };
@@ -0,0 +1,99 @@
1
+ import { makeSquareViewBox } from "../../../svg/viewbox/square.js";
2
+ import { getIconViewBox } from "../../../svg/viewbox/value.js";
3
+ import { getComponentSizeValues } from "../content/size.js";
4
+ import { stringifyFactoryIconContent } from "../content/stringify.js";
5
+ import { createFactoryImports } from "../imports/create.js";
6
+ import { generateCSSFilesForComponent } from "../css/generate.js";
7
+ import { stringifyFactoryImports } from "../imports/stringify.js";
8
+ import { getUsedFactoryProps } from "../props/types.js";
9
+ import { addVueComponentTypes } from "./vue/types.js";
10
+ import { addSizeFunctionAsset } from "./shared/size.js";
11
+ import { stringifyFactoryPropsAsJSON } from "../props/object.js";
12
+
13
+ /**
14
+ * Create functional Vue component code
15
+ */
16
+ function createVueFunctionalComponent(data, options) {
17
+ const assets = [];
18
+ const imports = createFactoryImports();
19
+ const hasFallback = !!data.fallback;
20
+ if (hasFallback) imports.named["@iconify/css-vue"] = new Set(["Icon"]);
21
+ const vueNamedImports = new Set(["defineComponent", "h"]);
22
+ imports.named["vue"] = vueNamedImports;
23
+ generateCSSFilesForComponent(data.icon, imports, assets, options);
24
+ const componentCode = [];
25
+ const sizeProps = getComponentSizeValues(options, data.viewBox);
26
+ const props = {};
27
+ if (!hasFallback) props.xmlns = "http://www.w3.org/2000/svg";
28
+ const viewBox = data.viewBox;
29
+ const isDynanicViewBox = !sizeProps && options.square && viewBox.width !== viewBox.height;
30
+ if (sizeProps) {
31
+ props.width = sizeProps.width;
32
+ props.height = sizeProps.height;
33
+ } else if (hasFallback) {
34
+ props.width = {
35
+ type: "string",
36
+ value: "width",
37
+ template: "width: props.width,"
38
+ };
39
+ props.height = {
40
+ type: "string",
41
+ value: "height",
42
+ template: "height: props.height,"
43
+ };
44
+ } else {
45
+ const getSizeProps = addSizeFunctionAsset(imports, assets, options);
46
+ componentCode.push(`const size = computed(() => ${getSizeProps}(props.width, props.height, viewBox${isDynanicViewBox ? ".value" : ""}));`);
47
+ vueNamedImports.add("computed");
48
+ props.width = {
49
+ type: "string",
50
+ value: "width",
51
+ template: "...size.value,"
52
+ };
53
+ props.height = {
54
+ type: "string",
55
+ value: "height",
56
+ template: ""
57
+ };
58
+ }
59
+ if (options.square) props.square = { type: "boolean" };
60
+ const getViewBox = (viewBox$1) => hasFallback ? JSON.stringify(viewBox$1) : `'${getIconViewBox(viewBox$1)}'`;
61
+ const viewBoxValue = getViewBox(viewBox);
62
+ if (isDynanicViewBox) {
63
+ componentCode.unshift(`const baseViewBox = ${viewBoxValue};`, `const squareViewBox = ${getViewBox(makeSquareViewBox(viewBox))};`, `const viewBox = computed(() => props.square ? squareViewBox : baseViewBox);`);
64
+ props.viewBox = {
65
+ value: "viewBox",
66
+ template: "viewBox: viewBox.value,"
67
+ };
68
+ } else {
69
+ componentCode.unshift(`const viewBox = ${viewBoxValue};`);
70
+ props.viewBox = {
71
+ value: "viewBox",
72
+ template: "viewBox,"
73
+ };
74
+ }
75
+ props[hasFallback ? "content" : "innerHTML"] = { value: stringifyFactoryIconContent(data.icon, options) };
76
+ if (data.fallback) props.fallback = data.fallback;
77
+ const types = addVueComponentTypes(data, options, assets, props);
78
+ componentCode.push(`return () => h(${hasFallback ? "Icon" : "'svg'"}, {
79
+ ${stringifyFactoryPropsAsJSON(props, "\n ")}
80
+ });`);
81
+ const usedProps = getUsedFactoryProps(props);
82
+ const componentFunction = `const Component = defineComponent(
83
+ (${usedProps.length ? "props" : ""}) => {
84
+ ${componentCode.join("\n ")}
85
+ },
86
+ {
87
+ props: ${JSON.stringify(usedProps)}
88
+ }
89
+ );
90
+ `;
91
+ const content = `${stringifyFactoryImports(imports)}\n${componentFunction}\nexport default Component;\n`;
92
+ return {
93
+ assets,
94
+ content,
95
+ types
96
+ };
97
+ }
98
+
99
+ export { createVueFunctionalComponent };
@@ -1,8 +1,11 @@
1
1
  import { FactoryIconData } from "../types/data.js";
2
2
  import { FactoryGeneratedComponent } from "../types/component.js";
3
3
  import { ComponentFactoryOptions } from "../types/options.js";
4
+ interface VueOptions extends ComponentFactoryOptions {
5
+ ts?: boolean;
6
+ }
4
7
  /**
5
8
  * Create Vue component code
6
9
  */
7
- declare function createVueComponent(data: FactoryIconData, options: ComponentFactoryOptions): FactoryGeneratedComponent;
10
+ declare function createVueComponent(data: FactoryIconData, options: VueOptions): FactoryGeneratedComponent;
8
11
  export { createVueComponent };
@@ -5,98 +5,91 @@ import { stringifyFactoryIconContent } from "../content/stringify.js";
5
5
  import { createFactoryImports } from "../imports/create.js";
6
6
  import { generateCSSFilesForComponent } from "../css/generate.js";
7
7
  import { stringifyFactoryImports } from "../imports/stringify.js";
8
+ import { stringifyFactoryProps } from "../props/stringify.js";
9
+ import { getUsedFactoryProps, stringifyFactoryPropTypes } from "../props/types.js";
8
10
  import { addVueComponentTypes } from "./vue/types.js";
9
11
  import { addSizeFunctionAsset } from "./shared/size.js";
10
- import { stringifyFactoryPropsAsJSON } from "../props/object.js";
11
12
 
12
13
  /**
13
14
  * Create Vue component code
14
15
  */
15
16
  function createVueComponent(data, options) {
17
+ const useTS = options.ts ?? false;
16
18
  const assets = [];
17
19
  const imports = createFactoryImports();
18
20
  const hasFallback = !!data.fallback;
19
21
  if (hasFallback) imports.named["@iconify/css-vue"] = new Set(["Icon"]);
20
- const vueNamedImports = new Set(["defineComponent", "h"]);
22
+ const vueNamedImports = /* @__PURE__ */ new Set();
21
23
  imports.named["vue"] = vueNamedImports;
22
24
  generateCSSFilesForComponent(data.icon, imports, assets, options);
23
25
  const componentCode = [];
24
26
  const sizeProps = getComponentSizeValues(options, data.viewBox);
25
27
  const props = {};
26
28
  if (!hasFallback) props.xmlns = "http://www.w3.org/2000/svg";
27
- const usedProps = [];
28
29
  const viewBox = data.viewBox;
29
30
  const isDynanicViewBox = !sizeProps && options.square && viewBox.width !== viewBox.height;
30
31
  if (sizeProps) {
31
32
  props.width = sizeProps.width;
32
33
  props.height = sizeProps.height;
33
- } else {
34
- usedProps.push("width", "height");
35
- if (hasFallback) {
36
- props.width = {
37
- type: "string",
38
- value: "width",
39
- template: "width: props.width,"
40
- };
41
- props.height = {
42
- type: "string",
43
- value: "height",
44
- template: "height: props.height,"
45
- };
46
- } else {
47
- const getSizeProps = addSizeFunctionAsset(imports, assets, options);
48
- componentCode.push(`const size = computed(() => ${getSizeProps}(props.width, props.height, viewBox${isDynanicViewBox ? ".value" : ""}));`);
49
- vueNamedImports.add("computed");
50
- props.width = {
51
- type: "string",
52
- value: "width",
53
- template: "...size.value,"
54
- };
55
- props.height = {
56
- type: "string",
57
- value: "height",
58
- template: ""
59
- };
60
- }
61
- }
62
- if (options.square) {
63
- usedProps.push("square");
64
- props.square = { type: "boolean" };
65
- }
66
- const getViewBox = (viewBox$1) => hasFallback ? JSON.stringify(viewBox$1) : `'${getIconViewBox(viewBox$1)}'`;
67
- const viewBoxValue = getViewBox(viewBox);
68
- if (isDynanicViewBox) {
69
- componentCode.unshift(`const baseViewBox = ${viewBoxValue};`, `const squareViewBox = ${getViewBox(makeSquareViewBox(viewBox))};`, `const viewBox = computed(() => props.square ? squareViewBox : baseViewBox);`);
70
- props.viewBox = {
71
- value: "viewBox",
72
- template: "viewBox: viewBox.value,"
34
+ } else if (hasFallback) {
35
+ props.width = {
36
+ type: "string",
37
+ value: "width",
38
+ template: ":width"
39
+ };
40
+ props.height = {
41
+ type: "string",
42
+ value: "height",
43
+ template: ":height"
73
44
  };
74
45
  } else {
75
- componentCode.unshift(`const viewBox = ${viewBoxValue};`);
76
- props.viewBox = {
77
- value: "viewBox",
78
- template: "viewBox,"
46
+ const getSizeProps = addSizeFunctionAsset(imports, assets, options);
47
+ componentCode.push(`const size = computed(() => ${getSizeProps}(props.width, props.height, viewBox${isDynanicViewBox ? ".value" : ""}));`);
48
+ vueNamedImports.add("computed");
49
+ props.width = {
50
+ type: "string",
51
+ value: "width",
52
+ template: "v-bind=\"size\""
53
+ };
54
+ props.height = {
55
+ type: "string",
56
+ value: "height",
57
+ template: ""
79
58
  };
80
59
  }
81
- props[hasFallback ? "content" : "innerHTML"] = { value: stringifyFactoryIconContent(data.icon, options) };
82
- if (data.fallback) props.fallback = data.fallback;
83
- addVueComponentTypes(data, options, assets, props);
84
- componentCode.push(`return () => h(${hasFallback ? "Icon" : "'svg'"}, {
85
- ${stringifyFactoryPropsAsJSON(props, "\n ")}
86
- });`);
87
- const componentFunction = `const Component = defineComponent(
88
- (${usedProps.length ? "props" : ""}) => {
89
- ${componentCode.join("\n ")}
90
- },
91
- {
92
- props: ${JSON.stringify(usedProps)}
60
+ if (options.square) props.square = { type: "boolean" };
61
+ const getViewBox = (viewBox$1) => hasFallback ? JSON.stringify(viewBox$1) : `'${getIconViewBox(viewBox$1)}'`;
62
+ const viewBoxValue = getViewBox(viewBox);
63
+ if (isDynanicViewBox) componentCode.unshift(`const baseViewBox = ${viewBoxValue};`, `const squareViewBox = ${getViewBox(makeSquareViewBox(viewBox))};`, `const viewBox = computed(() => props.square ? squareViewBox : baseViewBox);`);
64
+ else componentCode.unshift(`const viewBox = ${viewBoxValue};`);
65
+ props.viewBox = {
66
+ value: "viewBox",
67
+ template: ":viewBox=\"viewBox\""
68
+ };
69
+ componentCode.push(`const content = ${stringifyFactoryIconContent(data.icon, options)};`);
70
+ props.content = {
71
+ value: "content",
72
+ template: hasFallback ? `:content fallback="${data.fallback}"` : "v-html=\"content\""
73
+ };
74
+ const usedProps = getUsedFactoryProps(props);
75
+ if (usedProps.length) {
76
+ const tsCode = useTS ? `<{
77
+ ${stringifyFactoryPropTypes(props)}
78
+ }>` : "";
79
+ componentCode.unshift(`const props = defineProps${tsCode}(${JSON.stringify(usedProps)});\n`);
93
80
  }
94
- );
81
+ const template = `<template><${hasFallback ? "Icon" : "svg"} ${stringifyFactoryProps(props, ":{prop}=\"{value}\"")} /></template>`;
82
+ const content = `<script setup${useTS ? " lang=\"ts\"" : ""}>
83
+ ${stringifyFactoryImports(imports)}
84
+ ${componentCode.join("\n")}
85
+ <\/script>
86
+ ${template}
95
87
  `;
96
- const content = `${stringifyFactoryImports(imports)}\n${componentFunction}\nexport default Component;\n`;
88
+ const types = addVueComponentTypes(data, options, assets, props);
97
89
  return {
98
90
  assets,
99
- content
91
+ content,
92
+ types
100
93
  };
101
94
  }
102
95
 
@@ -1,10 +1,11 @@
1
1
  import { FactoryComponent } from "../types/component.js";
2
+ type Types = string | Record<string, string>;
2
3
  interface Options {
3
4
  ext?: string;
4
- data?: Record<string, string>;
5
+ data?: Record<string, Types>;
5
6
  }
6
7
  /**
7
8
  * Add exports for main files to object
8
9
  */
9
- declare function createExportsForMainFiles(data: FactoryComponent[], options?: Options): Record<string, string>;
10
+ declare function createExportsForMainFiles(data: FactoryComponent[], options?: Options): Record<string, Types>;
10
11
  export { createExportsForMainFiles };
@@ -4,7 +4,10 @@
4
4
  function createExportsForMainFiles(data, options = {}) {
5
5
  const result = options?.data || Object.create(null);
6
6
  const ext = options.ext || "";
7
- for (const { icon, filename } of data) result[`./${icon}${ext}`] = `./${filename}`;
7
+ for (const { icon, filename, types } of data) result[`./${icon}${ext}`] = types ? {
8
+ types: `./${types}`,
9
+ default: `./${filename}`
10
+ } : `./${filename}`;
8
11
  return result;
9
12
  }
10
13
 
@@ -8,7 +8,8 @@
8
8
  */
9
9
  function getGeneratedComponentFilename(icon, componentExtension, options) {
10
10
  const { name, prefix } = icon;
11
- return (options.prefixDirsForComponents ? `${prefix}/` : "") + (options.doubleDirsForComponents ? `${name.slice(0, 1).toLowerCase()}/` : "") + name + componentExtension;
11
+ const { prefixDirsForComponents } = options;
12
+ return (prefixDirsForComponents ? `${typeof prefixDirsForComponents === "string" ? prefixDirsForComponents : prefix}/` : "") + (options.doubleDirsForComponents ? `${name.slice(0, 1).toLowerCase()}/` : "") + name + componentExtension;
12
13
  }
13
14
 
14
15
  export { getGeneratedComponentFilename };
@@ -6,8 +6,11 @@
6
6
  * @returns Asset path
7
7
  */
8
8
  function getFactoryRelativeAssetPath(path, options) {
9
+ const { prefixDirsForComponents } = options;
10
+ const prefixDir = prefixDirsForComponents ? typeof prefixDirsForComponents === "string" ? prefixDirsForComponents : "prefix" : "";
11
+ const parentCount = (prefixDir ? prefixDir.split("/").length : 0) + (options.doubleDirsForComponents ? 1 : 0);
9
12
  return {
10
- import: `../${options.prefixDirsForComponents ? "../" : ""}${options.doubleDirsForComponents ? "../" : ""}${path}`,
13
+ import: (parentCount ? "../".repeat(parentCount) : "./") + path,
11
14
  filename: path
12
15
  };
13
16
  }
@@ -31,11 +31,11 @@ function stringifyFactoryImports(imports, includeTypes = true) {
31
31
  for (const source in data.default) lines.push(`import ${data.default[source]} from '${source}';`);
32
32
  for (const source in data.named) {
33
33
  const items = [...data.named[source]].sort().join(", ");
34
- lines.push(`import { ${items} } from '${source}';`);
34
+ if (items) lines.push(`import { ${items} } from '${source}';`);
35
35
  }
36
36
  if (includeTypes) for (const source in data.types) {
37
37
  const items = [...data.types[source]].sort().join(", ");
38
- lines.push(`import type { ${items} } from '${source}';`);
38
+ if (items) lines.push(`import type { ${items} } from '${source}';`);
39
39
  }
40
40
  for (const source of data.css) lines.push(`import '${source}';`);
41
41
  for (const source in data.modules) lines.push(`import ${data.modules[source]} from '${source}';`);
@@ -3,4 +3,8 @@ import { FactoryComponentProps } from "../types/props.js";
3
3
  * Stringify properties for component
4
4
  */
5
5
  declare function stringifyFactoryPropTypes(props: FactoryComponentProps): string;
6
- export { stringifyFactoryPropTypes };
6
+ /**
7
+ * Get used properties
8
+ */
9
+ declare function getUsedFactoryProps(props: FactoryComponentProps): string[];
10
+ export { getUsedFactoryProps, stringifyFactoryPropTypes };
@@ -1,16 +1,27 @@
1
1
  /**
2
2
  * Stringify properties for component
3
3
  */
4
- function stringifyFactoryPropTypes(props) {
4
+ function parse(props, format) {
5
5
  const result = [];
6
6
  for (const key in props) {
7
7
  const value = props[key];
8
- if (typeof value !== "string") {
9
- const type = value.type;
10
- if (type) result.push(`\t${key}${value.required ? "" : "?"}: ${type};`);
11
- }
8
+ if (typeof value !== "string" && value.type) result.push(format(key, value));
12
9
  }
13
- return result.join("\n");
10
+ return result;
11
+ }
12
+ /**
13
+ * Stringify properties for component
14
+ */
15
+ function stringifyFactoryPropTypes(props) {
16
+ return parse(props, (key, value) => {
17
+ return `\t${key}${value.required ? "" : "?"}: ${value.type};`;
18
+ }).join("\n");
19
+ }
20
+ /**
21
+ * Get used properties
22
+ */
23
+ function getUsedFactoryProps(props) {
24
+ return parse(props, (key) => key);
14
25
  }
15
26
 
16
- export { stringifyFactoryPropTypes };
27
+ export { getUsedFactoryProps, stringifyFactoryPropTypes };
@@ -27,6 +27,7 @@ interface FactoryComponentTemplate {
27
27
  interface FactoryGeneratedComponent {
28
28
  assets: GeneratedAssetFile[];
29
29
  content: string;
30
+ types?: string;
30
31
  }
31
32
  /**
32
33
  * Component data with filename
@@ -5,7 +5,7 @@ import { CSSExportMode } from "./css.js";
5
5
  */
6
6
  interface ComponentFactoryFileSystemOptions {
7
7
  doubleDirsForCSS: boolean;
8
- prefixDirsForComponents: boolean;
8
+ prefixDirsForComponents: boolean | string;
9
9
  doubleDirsForComponents: boolean;
10
10
  chunksPath: GeneratedAssetPath;
11
11
  cssPath: GeneratedAssetPath;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "type": "module",
4
4
  "description": "Common functions for working with SVG used by various packages.",
5
5
  "author": "Vjacheslav Trushkin",
6
- "version": "0.1.0",
6
+ "version": "0.1.1",
7
7
  "license": "MIT",
8
8
  "bugs": "https://github.com/cyberalien/svg-utils/issues",
9
9
  "homepage": "https://cyberalien.dev/",