@cyberalien/svg-utils 0.1.7 → 1.0.0

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.
@@ -0,0 +1,6 @@
1
+ import { IconViewBox } from "../../../svg/viewbox/types.js";
2
+ /**
3
+ * Get viewBox ratio as string
4
+ */
5
+ declare function getViewBoxRatio(viewBox: IconViewBox): string;
6
+ export { getViewBoxRatio };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Get viewBox ratio as string
3
+ */
4
+ function getViewBoxRatio(viewBox) {
5
+ const ratio = viewBox.width / viewBox.height;
6
+ return (Math.ceil(ratio * 100) / 100).toFixed(2).replace(/\.?0+$/, "");
7
+ }
8
+
9
+ export { getViewBoxRatio };
@@ -1,7 +1,7 @@
1
1
  import { getComponentSizeValues } from "./helpers/content/size.js";
2
2
  import { stringifyFactoryIconContent } from "./helpers/content/stringify.js";
3
3
  import { getGeneratedComponentTypesFilename } from "./helpers/filenames/types.js";
4
- import { getIconViewBox } from "../svg/viewbox/value.js";
4
+ import { stringifyIconViewBox } from "../svg/viewbox/value.js";
5
5
  import { createFactoryImports } from "./helpers/imports/create.js";
6
6
  import { generateCSSFilesForComponent } from "./helpers/css/generate.js";
7
7
  import { stringifyFactoryImports } from "./helpers/imports/stringify.js";
@@ -18,7 +18,7 @@ function createRawComponent(data, options) {
18
18
  const props = {
19
19
  xmlns: "http://www.w3.org/2000/svg",
20
20
  ...getComponentSizeValues(options, data.viewBox),
21
- viewBox: getIconViewBox(data.viewBox)
21
+ viewBox: stringifyIconViewBox(data.viewBox)
22
22
  };
23
23
  const icon = {
24
24
  ...data.icon,
@@ -1,6 +1,6 @@
1
1
  import { getComponentSizeValues } from "./helpers/content/size.js";
2
2
  import { stringifyFactoryIconContent } from "./helpers/content/stringify.js";
3
- import { getIconViewBox } from "../svg/viewbox/value.js";
3
+ import { stringifyIconViewBox } from "../svg/viewbox/value.js";
4
4
  import { createFactoryImports } from "./helpers/imports/create.js";
5
5
  import { generateCSSFilesForComponent } from "./helpers/css/generate.js";
6
6
  import { stringifyFactoryImports } from "./helpers/imports/stringify.js";
@@ -9,6 +9,8 @@ import { addSizeFunctionAsset } from "./helpers/functions/size.js";
9
9
  import { makeSquareViewBox } from "../svg/viewbox/square.js";
10
10
  import { getUsedFactoryProps, stringifyFactoryPropTypes } from "./helpers/props/ts.js";
11
11
  import { addSvelteComponentTypes } from "./helpers/ts/svelte.js";
12
+ import { minifyViewBox } from "../svg/viewbox/minify.js";
13
+ import { getViewBoxRatio } from "./helpers/content/ratio.js";
12
14
 
13
15
  /**
14
16
  * Create Svelte component code
@@ -24,14 +26,24 @@ function createSvelteComponent(data, options) {
24
26
  ...options,
25
27
  styleInComponent
26
28
  });
29
+ let hasFixedSize = !!options.width && !!options.height;
30
+ const viewBox = data.viewBox;
31
+ const hasComputedViewbox = options.square && !hasFixedSize && viewBox.width !== viewBox.height;
32
+ const isStringViewBox = !hasFallback;
33
+ const hasComputedRatio = hasComputedViewbox && isStringViewBox;
34
+ if (!hasComputedViewbox && (options.width || options.height)) hasFixedSize = true;
27
35
  const componentCode = [];
28
- const sizeProps = getComponentSizeValues(options, data.viewBox);
29
36
  const props = {};
30
37
  if (!hasFallback) props.xmlns = "http://www.w3.org/2000/svg";
31
- const viewBox = data.viewBox;
32
- const isDynanicViewBox = !sizeProps && options.square && viewBox.width !== viewBox.height;
33
- const viewBoxPropValue = `viewBox${isDynanicViewBox ? "Computed" : ""}`;
34
- if (sizeProps) {
38
+ const viewBoxPropValue = `viewBox${hasComputedViewbox ? "Computed" : ""}`;
39
+ const getViewBox = (viewBox$1) => isStringViewBox ? `'${stringifyIconViewBox(viewBox$1)}'` : JSON.stringify(minifyViewBox(viewBox$1));
40
+ if (hasComputedViewbox) componentCode.push(`const baseViewBox = ${getViewBox(viewBox)};`, `const squareViewBox = ${getViewBox(makeSquareViewBox(viewBox))};`, `let ${viewBoxPropValue} = $derived(square ? squareViewBox : baseViewBox);`);
41
+ else componentCode.push(`const ${viewBoxPropValue} = ${getViewBox(viewBox)};`);
42
+ const ratioValue = getViewBoxRatio(viewBox);
43
+ if (hasComputedRatio) componentCode.push(`let ratio = $derived(square ? 1 : ${ratioValue});`);
44
+ if (hasFixedSize) {
45
+ const sizeProps = getComponentSizeValues(options, data.viewBox);
46
+ if (!sizeProps) throw new Error("Fixed size expected, but could not be determined");
35
47
  props.width = sizeProps.width;
36
48
  props.height = sizeProps.height;
37
49
  } else if (hasFallback) {
@@ -47,7 +59,7 @@ function createSvelteComponent(data, options) {
47
59
  };
48
60
  } else {
49
61
  const getSizeProps = addSizeFunctionAsset(imports, assets, options);
50
- componentCode.push(`let size = $derived(${getSizeProps}(width, height, ${viewBoxPropValue}));`);
62
+ componentCode.push(`let size = $derived(${getSizeProps}(width, height, ${hasComputedRatio ? "ratio" : ratioValue}));`);
51
63
  props.width = {
52
64
  type: "string",
53
65
  value: "width",
@@ -60,10 +72,6 @@ function createSvelteComponent(data, options) {
60
72
  };
61
73
  }
62
74
  if (options.square) props.square = { type: "boolean" };
63
- const getViewBox = (viewBox$1) => hasFallback ? JSON.stringify(viewBox$1) : `'${getIconViewBox(viewBox$1)}'`;
64
- const viewBoxValue = getViewBox(viewBox);
65
- if (isDynanicViewBox) componentCode.unshift(`const baseViewBox = ${viewBoxValue};`, `const squareViewBox = ${getViewBox(makeSquareViewBox(viewBox))};`, `let ${viewBoxPropValue} = $derived(square ? squareViewBox : baseViewBox);`);
66
- else componentCode.unshift(`const viewBox = ${viewBoxValue};`);
67
75
  props.viewBox = {
68
76
  value: "viewBox",
69
77
  template: `viewBox={${viewBoxPropValue}}`
@@ -1,12 +1,14 @@
1
1
  import { getComponentSizeValues } from "./helpers/content/size.js";
2
2
  import { stringifyFactoryIconContent } from "./helpers/content/stringify.js";
3
- import { getIconViewBox } from "../svg/viewbox/value.js";
3
+ import { stringifyIconViewBox } from "../svg/viewbox/value.js";
4
4
  import { createFactoryImports } from "./helpers/imports/create.js";
5
5
  import { generateCSSFilesForComponent } from "./helpers/css/generate.js";
6
6
  import { stringifyFactoryImports } from "./helpers/imports/stringify.js";
7
7
  import { addSizeFunctionAsset } from "./helpers/functions/size.js";
8
8
  import { makeSquareViewBox } from "../svg/viewbox/square.js";
9
9
  import { getUsedFactoryProps } from "./helpers/props/ts.js";
10
+ import { minifyViewBox } from "../svg/viewbox/minify.js";
11
+ import { getViewBoxRatio } from "./helpers/content/ratio.js";
10
12
  import { addVueComponentTypes } from "./helpers/ts/vue.js";
11
13
  import { stringifyFactoryPropsAsJSON } from "./helpers/props/object.js";
12
14
 
@@ -21,13 +23,23 @@ function createVueFunctionalComponent(data, options) {
21
23
  const vueNamedImports = new Set(["defineComponent", "h"]);
22
24
  imports.named["vue"] = vueNamedImports;
23
25
  generateCSSFilesForComponent(data.icon, imports, assets, options);
26
+ let hasFixedSize = !!options.width && !!options.height;
27
+ const viewBox = data.viewBox;
28
+ const hasComputedViewbox = options.square && !hasFixedSize && viewBox.width !== viewBox.height;
29
+ const isStringViewBox = !hasFallback;
30
+ const hasComputedRatio = hasComputedViewbox && isStringViewBox;
31
+ if (!hasComputedViewbox && (options.width || options.height)) hasFixedSize = true;
24
32
  const componentCode = [];
25
- const sizeProps = getComponentSizeValues(options, data.viewBox);
26
33
  const props = {};
27
34
  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) {
35
+ const getViewBox = (viewBox$1) => isStringViewBox ? `'${stringifyIconViewBox(viewBox$1)}'` : JSON.stringify(minifyViewBox(viewBox$1));
36
+ if (hasComputedViewbox) componentCode.push(`const baseViewBox = ${getViewBox(viewBox)};`, `const squareViewBox = ${getViewBox(makeSquareViewBox(viewBox))};`, `const viewBox = computed(() => props.square ? squareViewBox : baseViewBox);`);
37
+ else componentCode.push(`const viewBox = ${getViewBox(viewBox)};`);
38
+ const ratioValue = getViewBoxRatio(viewBox);
39
+ if (hasComputedRatio) componentCode.push(`const ratio = computed(() => props.square ? 1 : ${ratioValue});`);
40
+ if (hasFixedSize) {
41
+ const sizeProps = getComponentSizeValues(options, data.viewBox);
42
+ if (!sizeProps) throw new Error("Fixed size expected, but could not be determined");
31
43
  props.width = sizeProps.width;
32
44
  props.height = sizeProps.height;
33
45
  } else if (hasFallback) {
@@ -43,7 +55,7 @@ function createVueFunctionalComponent(data, options) {
43
55
  };
44
56
  } else {
45
57
  const getSizeProps = addSizeFunctionAsset(imports, assets, options);
46
- componentCode.push(`const size = computed(() => ${getSizeProps}(props.width, props.height, viewBox${isDynanicViewBox ? ".value" : ""}));`);
58
+ componentCode.push(`const size = computed(() => ${getSizeProps}(props.width, props.height, ${hasComputedRatio ? "ratio.value" : ratioValue}));`);
47
59
  vueNamedImports.add("computed");
48
60
  props.width = {
49
61
  type: "string",
@@ -57,21 +69,10 @@ function createVueFunctionalComponent(data, options) {
57
69
  };
58
70
  }
59
71
  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
- }
72
+ props.viewBox = {
73
+ value: "viewBox",
74
+ template: hasComputedViewbox ? "viewBox: viewBox.value," : "viewBox,"
75
+ };
75
76
  props[hasFallback ? "content" : "innerHTML"] = { value: stringifyFactoryIconContent(data.icon, options) };
76
77
  if (data.fallback) props.fallback = data.fallback;
77
78
  const types = addVueComponentTypes(data, options, assets, props);
@@ -1,6 +1,6 @@
1
1
  import { getComponentSizeValues } from "./helpers/content/size.js";
2
2
  import { stringifyFactoryIconContent } from "./helpers/content/stringify.js";
3
- import { getIconViewBox } from "../svg/viewbox/value.js";
3
+ import { stringifyIconViewBox } from "../svg/viewbox/value.js";
4
4
  import { createFactoryImports } from "./helpers/imports/create.js";
5
5
  import { generateCSSFilesForComponent } from "./helpers/css/generate.js";
6
6
  import { stringifyFactoryImports } from "./helpers/imports/stringify.js";
@@ -8,6 +8,8 @@ import { stringifyFactoryProps } from "./helpers/props/stringify.js";
8
8
  import { addSizeFunctionAsset } from "./helpers/functions/size.js";
9
9
  import { makeSquareViewBox } from "../svg/viewbox/square.js";
10
10
  import { getUsedFactoryProps, stringifyFactoryPropTypes } from "./helpers/props/ts.js";
11
+ import { minifyViewBox } from "../svg/viewbox/minify.js";
12
+ import { getViewBoxRatio } from "./helpers/content/ratio.js";
11
13
  import { addVueComponentTypes } from "./helpers/ts/vue.js";
12
14
 
13
15
  /**
@@ -26,29 +28,39 @@ function createVueComponent(data, options) {
26
28
  ...options,
27
29
  styleInComponent
28
30
  });
31
+ let hasFixedSize = !!options.width && !!options.height;
32
+ const viewBox = data.viewBox;
33
+ const hasComputedViewbox = options.square && !hasFixedSize && viewBox.width !== viewBox.height;
34
+ const isStringViewBox = !hasFallback;
35
+ const hasComputedRatio = hasComputedViewbox && isStringViewBox;
36
+ if (!hasComputedViewbox && (options.width || options.height)) hasFixedSize = true;
29
37
  const componentCode = [];
30
- const sizeProps = getComponentSizeValues(options, data.viewBox);
31
38
  const props = {};
32
39
  if (!hasFallback) props.xmlns = "http://www.w3.org/2000/svg";
33
- const viewBox = data.viewBox;
34
- const isDynanicViewBox = !sizeProps && options.square && viewBox.width !== viewBox.height;
35
- if (sizeProps) {
40
+ const getViewBox = (viewBox$1) => isStringViewBox ? `'${stringifyIconViewBox(viewBox$1)}'` : JSON.stringify(minifyViewBox(viewBox$1));
41
+ if (hasComputedViewbox) componentCode.push(`const baseViewBox = ${getViewBox(viewBox)};`, `const squareViewBox = ${getViewBox(makeSquareViewBox(viewBox))};`, `const viewBox = computed(() => props.square ? squareViewBox : baseViewBox);`);
42
+ else componentCode.push(`const viewBox = ${getViewBox(viewBox)};`);
43
+ const ratioValue = getViewBoxRatio(viewBox);
44
+ if (hasComputedRatio) componentCode.push(`const ratio = computed(() => props.square ? 1 : ${ratioValue});`);
45
+ if (hasFixedSize) {
46
+ const sizeProps = getComponentSizeValues(options, data.viewBox);
47
+ if (!sizeProps) throw new Error("Fixed size expected, but could not be determined");
36
48
  props.width = sizeProps.width;
37
49
  props.height = sizeProps.height;
38
50
  } else if (hasFallback) {
39
51
  props.width = {
40
52
  type: "string",
41
53
  value: "width",
42
- template: ":width"
54
+ template: ":width=\"width\""
43
55
  };
44
56
  props.height = {
45
57
  type: "string",
46
58
  value: "height",
47
- template: ":height"
59
+ template: ":height=\"height\""
48
60
  };
49
61
  } else {
50
62
  const getSizeProps = addSizeFunctionAsset(imports, assets, options);
51
- componentCode.push(`const size = computed(() => ${getSizeProps}(props.width, props.height, viewBox${isDynanicViewBox ? ".value" : ""}));`);
63
+ componentCode.push(`const size = computed(() => ${getSizeProps}(props.width, props.height, ${hasComputedRatio ? "ratio.value" : ratioValue}));`);
52
64
  vueNamedImports.add("computed");
53
65
  props.width = {
54
66
  type: "string",
@@ -62,10 +74,6 @@ function createVueComponent(data, options) {
62
74
  };
63
75
  }
64
76
  if (options.square) props.square = { type: "boolean" };
65
- const getViewBox = (viewBox$1) => hasFallback ? JSON.stringify(viewBox$1) : `'${getIconViewBox(viewBox$1)}'`;
66
- const viewBoxValue = getViewBox(viewBox);
67
- if (isDynanicViewBox) componentCode.unshift(`const baseViewBox = ${viewBoxValue};`, `const squareViewBox = ${getViewBox(makeSquareViewBox(viewBox))};`, `const viewBox = computed(() => props.square ? squareViewBox : baseViewBox);`);
68
- else componentCode.unshift(`const viewBox = ${viewBoxValue};`);
69
77
  props.viewBox = {
70
78
  value: "viewBox",
71
79
  template: ":viewBox=\"viewBox\""
@@ -73,7 +81,7 @@ function createVueComponent(data, options) {
73
81
  componentCode.push(`const content = ${stringifyFactoryIconContent(data.icon, options)};`);
74
82
  props.content = {
75
83
  value: "content",
76
- template: hasFallback ? `:content fallback="${data.fallback}"` : "v-html=\"content\""
84
+ template: hasFallback ? `:content="content" fallback="${data.fallback}"` : "v-html=\"content\""
77
85
  };
78
86
  const usedProps = getUsedFactoryProps(props);
79
87
  if (usedProps.length) {
@@ -2,5 +2,5 @@ import { IconViewBox } from "./types.js";
2
2
  /**
3
3
  * Convert IconViewBox to string
4
4
  */
5
- declare function getIconViewBox(viewBox: IconViewBox): string;
6
- export { getIconViewBox };
5
+ declare function stringifyIconViewBox(viewBox: IconViewBox): string;
6
+ export { stringifyIconViewBox };
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Convert IconViewBox to string
3
3
  */
4
- function getIconViewBox(viewBox) {
4
+ function stringifyIconViewBox(viewBox) {
5
5
  return `${viewBox.left ?? 0} ${viewBox.top ?? 0} ${viewBox.width} ${viewBox.height}`;
6
6
  }
7
7
 
8
- export { getIconViewBox };
8
+ export { stringifyIconViewBox };
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.7",
6
+ "version": "1.0.0",
7
7
  "license": "MIT",
8
8
  "bugs": "https://github.com/cyberalien/svg-utils/issues",
9
9
  "homepage": "https://cyberalien.dev/",
@@ -24,16 +24,16 @@
24
24
  },
25
25
  "devDependencies": {
26
26
  "@eslint/eslintrc": "^3.3.1",
27
- "@eslint/js": "^9.35.0",
27
+ "@eslint/js": "^9.37.0",
28
28
  "@iconify-json/ri": "^1.2.5",
29
29
  "@types/jest": "^30.0.0",
30
- "@types/node": "^24.5.2",
31
- "@typescript-eslint/eslint-plugin": "^8.44.0",
32
- "@typescript-eslint/parser": "^8.44.0",
33
- "eslint": "^9.35.0",
30
+ "@types/node": "^24.6.2",
31
+ "@typescript-eslint/eslint-plugin": "^8.45.0",
32
+ "@typescript-eslint/parser": "^8.45.0",
33
+ "eslint": "^9.37.0",
34
34
  "globals": "^16.4.0",
35
- "tsdown": "^0.15.2",
36
- "typescript": "^5.9.2",
35
+ "tsdown": "^0.15.6",
36
+ "typescript": "^5.9.3",
37
37
  "vitest": "^3.2.4"
38
38
  },
39
39
  "scripts": {