svger-cli 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -118,4 +118,4 @@ Cleans output folder at the end if needed.
118
118
 
119
119
  Acknowledgements
120
120
 
121
- This project was implemented by Faeze Mohadespor, following the ADR authored by Navid Rezadoost and based on the TDR prepared by Ehsan Jafari. Their guidance and documentation on SVG integration methods in React were instrumental in shaping the design and functionality of the svger-cli CLI.
121
+ This project was implemented by Faeze Mohades, following the ADR authored by Navid Rezadoost and based on the TDR prepared by Ehsan Jafari. Their guidance and documentation on SVG integration methods in React were instrumental in shaping the design and functionality of the svger-cli CLI.
@@ -1,35 +1,12 @@
1
1
  /**
2
- * Generates a React functional component string from an SVG file's content.
3
- *
4
- * This template replaces XML/DOCTYPE declarations, cleans up formatting,
5
- * and injects React props (`width`, `height`, `fill`, and any others via `...props`)
6
- * directly into the root `<svg>` tag.
7
- *
8
- * @param {Object} params - Template generation parameters.
9
- * @param {string} params.componentName - The name of the generated React component.
10
- * @param {string} params.svgContent - The raw SVG markup to transform into a React component.
11
- * @param {number} [params.defaultWidth=24] - Default width of the SVG (used if none is provided via props).
12
- * @param {number} [params.defaultHeight=24] - Default height of the SVG (used if none is provided via props).
13
- * @param {string} [params.defaultFill="currentColor"] - Default fill color of the SVG.
14
- *
15
- * @returns {string} The complete TypeScript React component code as a string.
16
- *
17
- * @example
18
- * const svg = '<svg viewBox="0 0 24 24"><path d="M0 0h24v24H0z"/></svg>';
19
- * const componentCode = reactTemplate({
20
- * componentName: "MyIcon",
21
- * svgContent: svg,
22
- * defaultWidth: 32,
23
- * defaultHeight: 32,
24
- * });
25
- *
26
- * // Result: a ready-to-write .tsx file containing a typed React component
27
- * console.log(componentCode);
2
+ * Generates a React functional component string from an SVG file's content,
3
+ * safely converting any inline `style="..."` to React-compatible object.
28
4
  */
29
- export declare function reactTemplate({ componentName, svgContent, defaultWidth, defaultHeight, defaultFill, }: {
5
+ export declare function reactTemplate({ componentName, svgContent, defaultWidth, defaultHeight, defaultFill, defaultStroke, }: {
30
6
  componentName: string;
31
7
  svgContent: string;
32
8
  defaultWidth?: number;
33
9
  defaultHeight?: number;
34
10
  defaultFill?: string;
11
+ defaultStroke?: string;
35
12
  }): string;
@@ -1,57 +1,42 @@
1
1
  /**
2
- * Generates a React functional component string from an SVG file's content.
3
- *
4
- * This template replaces XML/DOCTYPE declarations, cleans up formatting,
5
- * and injects React props (`width`, `height`, `fill`, and any others via `...props`)
6
- * directly into the root `<svg>` tag.
7
- *
8
- * @param {Object} params - Template generation parameters.
9
- * @param {string} params.componentName - The name of the generated React component.
10
- * @param {string} params.svgContent - The raw SVG markup to transform into a React component.
11
- * @param {number} [params.defaultWidth=24] - Default width of the SVG (used if none is provided via props).
12
- * @param {number} [params.defaultHeight=24] - Default height of the SVG (used if none is provided via props).
13
- * @param {string} [params.defaultFill="currentColor"] - Default fill color of the SVG.
14
- *
15
- * @returns {string} The complete TypeScript React component code as a string.
16
- *
17
- * @example
18
- * const svg = '<svg viewBox="0 0 24 24"><path d="M0 0h24v24H0z"/></svg>';
19
- * const componentCode = reactTemplate({
20
- * componentName: "MyIcon",
21
- * svgContent: svg,
22
- * defaultWidth: 32,
23
- * defaultHeight: 32,
24
- * });
25
- *
26
- * // Result: a ready-to-write .tsx file containing a typed React component
27
- * console.log(componentCode);
2
+ * Generates a React functional component string from an SVG file's content,
3
+ * safely converting any inline `style="..."` to React-compatible object.
28
4
  */
29
- export function reactTemplate({ componentName, svgContent, defaultWidth = 24, defaultHeight = 24, defaultFill = "currentColor", }) {
30
- // پاکسازی XML/DOCTYPE و حذف style های inline که React قبول نداره
5
+ export function reactTemplate({ componentName, svgContent, defaultWidth = 24, defaultHeight = 24, defaultFill = "currentColor", defaultStroke = "none", }) {
6
+ // helper: convert inline style string to JS object
7
+ function styleStringToObject(style) {
8
+ const obj = {};
9
+ style.split(";").forEach((pair) => {
10
+ if (!pair.trim())
11
+ return;
12
+ const [key, value] = pair.split(":");
13
+ if (!key || value === undefined)
14
+ return;
15
+ // convert kebab-case to camelCase
16
+ const camelKey = key.trim().replace(/-([a-z])/g, (_, c) => c.toUpperCase());
17
+ let v = value.trim();
18
+ if (!isNaN(Number(v)))
19
+ v = Number(v);
20
+ obj[camelKey] = v;
21
+ });
22
+ return obj;
23
+ }
24
+ // clean SVG content
31
25
  let cleaned = svgContent
32
- .replace(/<\?xml.*?\?>/g, "")
33
- .replace(/<!DOCTYPE.*?>/g, "")
34
- .replace(/\r?\n|\r/g, "")
35
- .replace(/style="[^"]*"/g, "") // حذف style های inline
36
- .replace(/\s(class|id)=["'][^"']*["']/g, "") // حذف class/id مستقیم
26
+ .replace(/<\?xml.*?\?>/g, "") // remove XML declaration
27
+ .replace(/<!DOCTYPE.*?>/g, "") // remove DOCTYPE
28
+ .replace(/\r?\n|\r/g, "") // remove newlines
37
29
  .trim();
38
- // تغییر attribute های SVG به React-compatible و اضافه کردن props
39
- cleaned = cleaned.replace(/<svg([^>]*)>/, `<svg$1
40
- width={width}
41
- height={height}
42
- fill={fill}
43
- stroke={props.stroke || "none"}
44
- className={props.className}
45
- {...props}>`);
30
+ // convert all style="..." to React objects
31
+ cleaned = cleaned.replace(/style="([^"]*)"/g, (_, styleContent) => {
32
+ return `{...{style: ${JSON.stringify(styleStringToObject(styleContent))}}}`;
33
+ });
34
+ // inject React props into <svg> tag
35
+ cleaned = cleaned.replace(/<svg([^>]*)>/, `<svg$1 width={props.width || ${defaultWidth}} height={props.height || ${defaultHeight}} fill={props.fill || "${defaultFill}"} stroke={props.stroke || "${defaultStroke}"} {...props}>`);
46
36
  return `import * as React from "react";
47
37
  import type { SVGProps } from "react";
48
38
 
49
- export const ${componentName}: React.FC<SVGProps<SVGSVGElement>> = ({
50
- width = ${defaultWidth},
51
- height = ${defaultHeight},
52
- fill = "${defaultFill}",
53
- ...props
54
- }) => (
39
+ export const ${componentName}: React.FC<SVGProps<SVGSVGElement>> = (props) => (
55
40
  ${cleaned}
56
41
  );
57
42
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svger-cli",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "CLI and runtime for converting SVGs to React components with watch support",
5
5
  "main": "dist/cli.js",
6
6
  "type": "module",
@@ -17,7 +17,7 @@
17
17
  "cli",
18
18
  "components"
19
19
  ],
20
- "author": "faeze mohadespoor",
20
+ "author": "faeze mohades",
21
21
  "license": "MIT",
22
22
  "dependencies": {
23
23
  "change-case": "^5.4.4",
@@ -1,30 +1,6 @@
1
1
  /**
2
- * Generates a React functional component string from an SVG file's content.
3
- *
4
- * This template replaces XML/DOCTYPE declarations, cleans up formatting,
5
- * and injects React props (`width`, `height`, `fill`, and any others via `...props`)
6
- * directly into the root `<svg>` tag.
7
- *
8
- * @param {Object} params - Template generation parameters.
9
- * @param {string} params.componentName - The name of the generated React component.
10
- * @param {string} params.svgContent - The raw SVG markup to transform into a React component.
11
- * @param {number} [params.defaultWidth=24] - Default width of the SVG (used if none is provided via props).
12
- * @param {number} [params.defaultHeight=24] - Default height of the SVG (used if none is provided via props).
13
- * @param {string} [params.defaultFill="currentColor"] - Default fill color of the SVG.
14
- *
15
- * @returns {string} The complete TypeScript React component code as a string.
16
- *
17
- * @example
18
- * const svg = '<svg viewBox="0 0 24 24"><path d="M0 0h24v24H0z"/></svg>';
19
- * const componentCode = reactTemplate({
20
- * componentName: "MyIcon",
21
- * svgContent: svg,
22
- * defaultWidth: 32,
23
- * defaultHeight: 32,
24
- * });
25
- *
26
- * // Result: a ready-to-write .tsx file containing a typed React component
27
- * console.log(componentCode);
2
+ * Generates a React functional component string from an SVG file's content,
3
+ * safely converting any inline `style="..."` to React-compatible object.
28
4
  */
29
5
  export function reactTemplate({
30
6
  componentName,
@@ -32,43 +8,53 @@ export function reactTemplate({
32
8
  defaultWidth = 24,
33
9
  defaultHeight = 24,
34
10
  defaultFill = "currentColor",
11
+ defaultStroke = "none",
35
12
  }: {
36
13
  componentName: string;
37
14
  svgContent: string;
38
15
  defaultWidth?: number;
39
16
  defaultHeight?: number;
40
17
  defaultFill?: string;
18
+ defaultStroke?: string;
41
19
  }) {
42
- // پاکسازی XML/DOCTYPE و حذف style های inline که React قبول نداره
20
+ // helper: convert inline style string to JS object
21
+ function styleStringToObject(style: string) {
22
+ const obj: Record<string, string | number> = {};
23
+ style.split(";").forEach((pair) => {
24
+ if (!pair.trim()) return;
25
+ const [key, value] = pair.split(":");
26
+ if (!key || value === undefined) return;
27
+ // convert kebab-case to camelCase
28
+ const camelKey = key.trim().replace(/-([a-z])/g, (_, c) => c.toUpperCase());
29
+ let v: string | number = value.trim();
30
+ if (!isNaN(Number(v))) v = Number(v);
31
+ obj[camelKey] = v;
32
+ });
33
+ return obj;
34
+ }
35
+
36
+ // clean SVG content
43
37
  let cleaned = svgContent
44
- .replace(/<\?xml.*?\?>/g, "")
45
- .replace(/<!DOCTYPE.*?>/g, "")
46
- .replace(/\r?\n|\r/g, "")
47
- .replace(/style="[^"]*"/g, "") // حذف style های inline
48
- .replace(/\s(class|id)=["'][^"']*["']/g, "") // حذف class/id مستقیم
38
+ .replace(/<\?xml.*?\?>/g, "") // remove XML declaration
39
+ .replace(/<!DOCTYPE.*?>/g, "") // remove DOCTYPE
40
+ .replace(/\r?\n|\r/g, "") // remove newlines
49
41
  .trim();
50
42
 
51
- // تغییر attribute های SVG به React-compatible و اضافه کردن props
43
+ // convert all style="..." to React objects
44
+ cleaned = cleaned.replace(/style="([^"]*)"/g, (_, styleContent) => {
45
+ return `{...{style: ${JSON.stringify(styleStringToObject(styleContent))}}}`;
46
+ });
47
+
48
+ // inject React props into <svg> tag
52
49
  cleaned = cleaned.replace(
53
50
  /<svg([^>]*)>/,
54
- `<svg$1
55
- width={width}
56
- height={height}
57
- fill={fill}
58
- stroke={props.stroke || "none"}
59
- className={props.className}
60
- {...props}>`
51
+ `<svg$1 width={props.width || ${defaultWidth}} height={props.height || ${defaultHeight}} fill={props.fill || "${defaultFill}"} stroke={props.stroke || "${defaultStroke}"} {...props}>`
61
52
  );
62
53
 
63
54
  return `import * as React from "react";
64
55
  import type { SVGProps } from "react";
65
56
 
66
- export const ${componentName}: React.FC<SVGProps<SVGSVGElement>> = ({
67
- width = ${defaultWidth},
68
- height = ${defaultHeight},
69
- fill = "${defaultFill}",
70
- ...props
71
- }) => (
57
+ export const ${componentName}: React.FC<SVGProps<SVGSVGElement>> = (props) => (
72
58
  ${cleaned}
73
59
  );
74
60