@san-siva/blogkit 1.1.30 → 1.1.32
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/dist/cjs/components/BlogSection.js.map +1 -1
- package/dist/cjs/components/CheckList.js +4 -1
- package/dist/cjs/components/CheckList.js.map +1 -1
- package/dist/cjs/dynamicComponents/BlogSectionDynamic.js +3 -2
- package/dist/cjs/dynamicComponents/BlogSectionDynamic.js.map +1 -1
- package/dist/cjs/dynamicComponents/CheckListDynamic.js +33 -0
- package/dist/cjs/dynamicComponents/CheckListDynamic.js.map +1 -0
- package/dist/cjs/index.css +1 -1
- package/dist/cjs/index.css.map +1 -1
- package/dist/cjs/staticComponents/BlogSectionStatic.js +3 -2
- package/dist/cjs/staticComponents/BlogSectionStatic.js.map +1 -1
- package/dist/cjs/staticComponents/CheckListStatic.js +1 -1
- package/dist/cjs/staticComponents/CheckListStatic.js.map +1 -1
- package/dist/cjs/utils/index.js +14 -0
- package/dist/cjs/utils/index.js.map +1 -1
- package/dist/esm/components/BlogSection.js.map +1 -1
- package/dist/esm/components/CheckList.js +4 -1
- package/dist/esm/components/CheckList.js.map +1 -1
- package/dist/esm/dynamicComponents/BlogSectionDynamic.js +4 -3
- package/dist/esm/dynamicComponents/BlogSectionDynamic.js.map +1 -1
- package/dist/esm/dynamicComponents/CheckListDynamic.js +29 -0
- package/dist/esm/dynamicComponents/CheckListDynamic.js.map +1 -0
- package/dist/esm/index.css +1 -1
- package/dist/esm/index.css.map +1 -1
- package/dist/esm/staticComponents/BlogSectionStatic.js +4 -3
- package/dist/esm/staticComponents/BlogSectionStatic.js.map +1 -1
- package/dist/esm/staticComponents/CheckListStatic.js +1 -1
- package/dist/esm/staticComponents/CheckListStatic.js.map +1 -1
- package/dist/esm/utils/index.js +14 -1
- package/dist/esm/utils/index.js.map +1 -1
- package/dist/types/components/BlogSection.d.ts +2 -2
- package/dist/types/components/BlogSection.d.ts.map +1 -1
- package/dist/types/components/CheckList.d.ts.map +1 -1
- package/dist/types/dynamicComponents/BlogSectionDynamic.d.ts +2 -2
- package/dist/types/dynamicComponents/BlogSectionDynamic.d.ts.map +1 -1
- package/dist/types/dynamicComponents/CheckListDynamic.d.ts +9 -0
- package/dist/types/dynamicComponents/CheckListDynamic.d.ts.map +1 -0
- package/dist/types/staticComponents/BlogSectionStatic.d.ts +2 -2
- package/dist/types/staticComponents/BlogSectionStatic.d.ts.map +1 -1
- package/dist/types/staticComponents/CheckListStatic.d.ts +2 -2
- package/dist/types/staticComponents/CheckListStatic.d.ts.map +1 -1
- package/dist/types/utils/index.d.ts +2 -0
- package/dist/types/utils/index.d.ts.map +1 -1
- package/dist/types/utils/index.test.d.ts +2 -0
- package/dist/types/utils/index.test.d.ts.map +1 -0
- package/package.json +4 -2
- package/src/components/BlogSection.tsx +2 -2
- package/src/components/CheckList.tsx +12 -1
- package/src/dynamicComponents/BlogSectionDynamic.tsx +6 -5
- package/src/dynamicComponents/CheckListDynamic.tsx +66 -0
- package/src/staticComponents/BlogSectionStatic.tsx +6 -5
- package/src/staticComponents/CheckListStatic.tsx +3 -3
- package/src/styles/BlogSection.module.scss +9 -5
- package/src/utils/index.test.tsx +63 -0
- package/src/utils/index.ts +11 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
2
|
import styles from '../styles/BlogSection.module.scss.js';
|
|
3
|
-
import { generateIdForBlogTitle } from '../utils/index.js';
|
|
3
|
+
import { extractTextFromReactNode, generateIdForBlogTitle } from '../utils/index.js';
|
|
4
4
|
|
|
5
5
|
const BlogSectionStatic = ({ title = '', category = '', children = null, }) => {
|
|
6
|
-
const
|
|
6
|
+
const titleString = typeof title === 'string' ? title : extractTextFromReactNode(title);
|
|
7
|
+
const titleWithCategory = category ? `${category} - ${titleString}` : titleString;
|
|
7
8
|
const id = generateIdForBlogTitle(titleWithCategory);
|
|
8
|
-
return (jsxs("div", { className: styles['blog-section'], "data-title":
|
|
9
|
+
return (jsxs("div", { className: styles['blog-section'], "data-title": titleString, "data-id": id, children: [title ? (jsx("h3", { className: styles['blog-section__title'], children: title })) : null, children] }));
|
|
9
10
|
};
|
|
10
11
|
|
|
11
12
|
export { BlogSectionStatic as default };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BlogSectionStatic.js","sources":["../../../src/staticComponents/BlogSectionStatic.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport styles from '../styles/BlogSection.module.scss';\nimport { generateIdForBlogTitle } from '../utils';\n\ninterface BlogSectionStaticProperties {\n\ttitle?: string
|
|
1
|
+
{"version":3,"file":"BlogSectionStatic.js","sources":["../../../src/staticComponents/BlogSectionStatic.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactElement, ReactNode } from 'react';\nimport styles from '../styles/BlogSection.module.scss';\nimport { extractTextFromReactNode, generateIdForBlogTitle } from '../utils';\n\ninterface BlogSectionStaticProperties {\n\ttitle?: string | ReactElement<HTMLAttributes<HTMLParagraphElement>, 'p'>;\n\tcategory?: string;\n\tchildren?: ReactNode;\n}\n\nconst BlogSectionStatic = ({\n\ttitle = '',\n\tcategory = '',\n\tchildren = null,\n}: BlogSectionStaticProperties) => {\n\tconst titleString = typeof title === 'string' ? title : extractTextFromReactNode(title);\n\tconst titleWithCategory = category ? `${category} - ${titleString}` : titleString;\n\tconst id = generateIdForBlogTitle(titleWithCategory);\n\n\treturn (\n\t\t<div className={styles['blog-section']} data-title={titleString} data-id={id}>\n\t\t\t{title ? (\n\t\t\t\t<h3 className={styles['blog-section__title']}>{title}</h3>\n\t\t\t) : null}\n\t\t\t{children}\n\t\t</div>\n\t);\n};\n\nexport default BlogSectionStatic;\n"],"names":["_jsxs","_jsx"],"mappings":";;;;AAUA,MAAM,iBAAiB,GAAG,CAAC,EAC1B,KAAK,GAAG,EAAE,EACV,QAAQ,GAAG,EAAE,EACb,QAAQ,GAAG,IAAI,GACc,KAAI;AACjC,IAAA,MAAM,WAAW,GAAG,OAAO,KAAK,KAAK,QAAQ,GAAG,KAAK,GAAG,wBAAwB,CAAC,KAAK,CAAC;AACvF,IAAA,MAAM,iBAAiB,GAAG,QAAQ,GAAG,CAAA,EAAG,QAAQ,CAAA,GAAA,EAAM,WAAW,CAAA,CAAE,GAAG,WAAW;AACjF,IAAA,MAAM,EAAE,GAAG,sBAAsB,CAAC,iBAAiB,CAAC;AAEpD,IAAA,QACCA,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,MAAM,CAAC,cAAc,CAAC,EAAA,YAAA,EAAc,WAAW,aAAW,EAAE,EAAA,QAAA,EAAA,CAC1E,KAAK,IACLC,GAAA,CAAA,IAAA,EAAA,EAAI,SAAS,EAAE,MAAM,CAAC,qBAAqB,CAAC,YAAG,KAAK,EAAA,CAAM,IACvD,IAAI,EACP,QAAQ,CAAA,EAAA,CACJ;AAER;;;;"}
|
|
@@ -2,7 +2,7 @@ import { jsx, jsxs } from 'react/jsx-runtime';
|
|
|
2
2
|
import styles from '../styles/CheckList.module.scss.js';
|
|
3
3
|
|
|
4
4
|
const CheckListStatic = ({ items, hasMarginUp = false, hasMarginDown = false, }) => {
|
|
5
|
-
return (jsx("div", { className: `${styles['check-list']} ${hasMarginUp ? styles['margin-top--1'] : ''} ${hasMarginDown ? styles['margin-bottom--2'] : ''}`, children: items.map((item) => (jsxs("div", { className: styles['check-list__item'], "data-id": item.id, children: [jsx("div", { className: `${styles['check-list__item__input']} ${item.isChecked ? styles['check-list__item__input--checked'] : ''}` }),
|
|
5
|
+
return (jsx("div", { className: `${styles['check-list']} ${hasMarginUp ? styles['margin-top--1'] : ''} ${hasMarginDown ? styles['margin-bottom--2'] : ''}`, children: items.map((item) => (jsxs("div", { className: styles['check-list__item'], "data-id": item.id, children: [jsx("div", { className: `${styles['check-list__item__input']} ${item.isChecked ? styles['check-list__item__input--checked'] : ''}` }), item.children] }, item.id))) }));
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
export { CheckListStatic as default };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CheckListStatic.js","sources":["../../../src/staticComponents/CheckListStatic.tsx"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"file":"CheckListStatic.js","sources":["../../../src/staticComponents/CheckListStatic.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactElement } from 'react';\n\nimport styles from '../styles/CheckList.module.scss';\n\nexport interface CheckListItem {\n\tid: string;\n\tchildren: ReactElement<HTMLAttributes<HTMLParagraphElement>, 'p'>;\n\tisChecked?: boolean;\n}\n\ninterface CheckListProperties {\n\titems: CheckListItem[];\n\thasMarginUp?: boolean;\n\thasMarginDown?: boolean;\n}\n\nconst CheckListStatic = ({\n\titems,\n\thasMarginUp = false,\n\thasMarginDown = false,\n}: CheckListProperties) => {\n\treturn (\n\t\t<div\n\t\t\tclassName={`${styles['check-list']} ${hasMarginUp ? styles['margin-top--1'] : ''} ${\n\t\t\t\thasMarginDown ? styles['margin-bottom--2'] : ''\n\t\t\t}`}\n\t\t>\n\t\t\t{items.map((item) => (\n\t\t\t\t<div key={item.id} className={styles['check-list__item']} data-id={item.id}>\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName={`${styles['check-list__item__input']} ${\n\t\t\t\t\t\t\titem.isChecked ? styles['check-list__item__input--checked'] : ''\n\t\t\t\t\t\t}`}\n\t\t\t\t\t/>\n\t\t\t\t\t{item.children}\n\t\t\t\t</div>\n\t\t\t))}\n\t\t</div>\n\t);\n};\n\nexport default CheckListStatic;\n"],"names":["_jsx","_jsxs"],"mappings":";;;AAgBA,MAAM,eAAe,GAAG,CAAC,EACxB,KAAK,EACL,WAAW,GAAG,KAAK,EACnB,aAAa,GAAG,KAAK,GACA,KAAI;IACzB,QACCA,aACC,SAAS,EAAE,GAAG,MAAM,CAAC,YAAY,CAAC,CAAA,CAAA,EAAI,WAAW,GAAG,MAAM,CAAC,eAAe,CAAC,GAAG,EAAE,CAAA,CAAA,EAC/E,aAAa,GAAG,MAAM,CAAC,kBAAkB,CAAC,GAAG,EAC9C,EAAE,EAAA,QAAA,EAED,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,MACfC,IAAA,CAAA,KAAA,EAAA,EAAmB,SAAS,EAAE,MAAM,CAAC,kBAAkB,CAAC,aAAW,IAAI,CAAC,EAAE,EAAA,QAAA,EAAA,CACzED,GAAA,CAAA,KAAA,EAAA,EACC,SAAS,EAAE,CAAA,EAAG,MAAM,CAAC,yBAAyB,CAAC,CAAA,CAAA,EAC9C,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,kCAAkC,CAAC,GAAG,EAC/D,CAAA,CAAE,EAAA,CACD,EACD,IAAI,CAAC,QAAQ,CAAA,EAAA,EANL,IAAI,CAAC,EAAE,CAOX,CACN,CAAC,EAAA,CACG;AAER;;;;"}
|
package/dist/esm/utils/index.js
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
|
+
import { isValidElement } from 'react';
|
|
2
|
+
|
|
3
|
+
const extractTextFromReactNode = (node) => {
|
|
4
|
+
if (node === null || node === undefined || typeof node === 'boolean')
|
|
5
|
+
return '';
|
|
6
|
+
if (typeof node === 'string' || typeof node === 'number')
|
|
7
|
+
return String(node);
|
|
8
|
+
if (isValidElement(node))
|
|
9
|
+
return extractTextFromReactNode(node.props.children);
|
|
10
|
+
if (Array.isArray(node))
|
|
11
|
+
return node.map(extractTextFromReactNode).join('');
|
|
12
|
+
return '';
|
|
13
|
+
};
|
|
1
14
|
const generateIdForBlogTitle = (title) => title.toLowerCase().replace(/[^\w\d]/g, '-');
|
|
2
15
|
const generateUrlForBlogTitle = (title) => encodeURIComponent(title.replace(/[^\w]+/g, '-').toLowerCase());
|
|
3
16
|
const generateSectionHref = (id) => `?section=${id}`;
|
|
4
17
|
|
|
5
|
-
export { generateIdForBlogTitle, generateSectionHref, generateUrlForBlogTitle };
|
|
18
|
+
export { extractTextFromReactNode, generateIdForBlogTitle, generateSectionHref, generateUrlForBlogTitle };
|
|
6
19
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../src/utils/index.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../src/utils/index.ts"],"sourcesContent":["import { isValidElement } from 'react';\nimport type { ReactNode } from 'react';\n\nexport const extractTextFromReactNode = (node: ReactNode): string => {\n\tif (node === null || node === undefined || typeof node === 'boolean') return '';\n\tif (typeof node === 'string' || typeof node === 'number') return String(node);\n\tif (isValidElement(node)) return extractTextFromReactNode((node.props as { children?: ReactNode }).children);\n\tif (Array.isArray(node)) return node.map(extractTextFromReactNode).join('');\n\treturn '';\n};\n\nexport const generateIdForBlogTitle = (title: string) => title.toLowerCase().replace(/[^\\w\\d]/g, '-');\n\nexport const generateUrlForBlogTitle = (title: string) => encodeURIComponent(title.replace(/[^\\w]+/g, '-').toLowerCase());\n\nexport const generateSectionHref = (id: string) => `?section=${id}`;\n"],"names":[],"mappings":";;AAGO,MAAM,wBAAwB,GAAG,CAAC,IAAe,KAAY;IACnE,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS,IAAI,OAAO,IAAI,KAAK,SAAS;AAAE,QAAA,OAAO,EAAE;IAC/E,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,IAAI,KAAK,QAAQ;AAAE,QAAA,OAAO,MAAM,CAAC,IAAI,CAAC;IAC7E,IAAI,cAAc,CAAC,IAAI,CAAC;QAAE,OAAO,wBAAwB,CAAE,IAAI,CAAC,KAAkC,CAAC,QAAQ,CAAC;AAC5G,IAAA,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;AAC3E,IAAA,OAAO,EAAE;AACV;MAEa,sBAAsB,GAAG,CAAC,KAAa,KAAK,KAAK,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG;MAEvF,uBAAuB,GAAG,CAAC,KAAa,KAAK,kBAAkB,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE;AAEjH,MAAM,mBAAmB,GAAG,CAAC,EAAU,KAAK,CAAA,SAAA,EAAY,EAAE,CAAA;;;;"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { ReactNode } from 'react';
|
|
1
|
+
import type { HTMLAttributes, ReactElement, ReactNode } from 'react';
|
|
2
2
|
import type { ForwardedReference } from '../dynamicComponents/BlogDynamic';
|
|
3
3
|
export type { ForwardedReference };
|
|
4
4
|
interface BlogSectionProperties {
|
|
5
|
-
title?: string
|
|
5
|
+
title?: string | ReactElement<HTMLAttributes<HTMLParagraphElement>, 'p'>;
|
|
6
6
|
category?: string;
|
|
7
7
|
children?: ReactNode;
|
|
8
8
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BlogSection.d.ts","sourceRoot":"","sources":["../../../src/components/BlogSection.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"BlogSection.d.ts","sourceRoot":"","sources":["../../../src/components/BlogSection.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAErE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAC3E,YAAY,EAAE,kBAAkB,EAAE,CAAC;AAMnC,UAAU,qBAAqB;IAC9B,KAAK,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC,cAAc,CAAC,oBAAoB,CAAC,EAAE,GAAG,CAAC,CAAC;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACrB;AAED,QAAA,MAAM,WAAW,sHA8BhB,CAAC;AAIF,eAAe,WAAW,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CheckList.d.ts","sourceRoot":"","sources":["../../../src/components/CheckList.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CheckList.d.ts","sourceRoot":"","sources":["../../../src/components/CheckList.tsx"],"names":[],"mappings":"AAGA,OAAwB,EAAE,KAAK,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAI1F,UAAU,mBAAmB;IAC5B,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,QAAA,MAAM,SAAS,GAAI,wCAIhB,mBAAmB,4CAUrB,CAAC;AAEF,OAAO,EAAE,KAAK,aAAa,EAAE,CAAC;AAC9B,eAAe,SAAS,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { ReactNode, RefAttributes } from 'react';
|
|
1
|
+
import type { HTMLAttributes, ReactElement, ReactNode, RefAttributes } from 'react';
|
|
2
2
|
import type { ForwardedReference } from './BlogDynamic';
|
|
3
3
|
interface BlogProperties {
|
|
4
|
-
title?: string
|
|
4
|
+
title?: string | ReactElement<HTMLAttributes<HTMLParagraphElement>, 'p'>;
|
|
5
5
|
category?: string;
|
|
6
6
|
children?: ReactNode;
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BlogSectionDynamic.d.ts","sourceRoot":"","sources":["../../../src/dynamicComponents/BlogSectionDynamic.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"BlogSectionDynamic.d.ts","sourceRoot":"","sources":["../../../src/dynamicComponents/BlogSectionDynamic.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAIpF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAGxD,UAAU,cAAc;IACvB,KAAK,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC,cAAc,CAAC,oBAAoB,CAAC,EAAE,GAAG,CAAC,CAAC;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACrB;AAED,QAAA,MAAM,WAAW,+FAoFhB,CAAC;AAIF,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CheckListItem } from '../staticComponents/CheckListStatic';
|
|
2
|
+
interface Properties {
|
|
3
|
+
items: CheckListItem[];
|
|
4
|
+
hasMarginUp?: boolean;
|
|
5
|
+
hasMarginDown?: boolean;
|
|
6
|
+
}
|
|
7
|
+
declare const CheckListDynamic: ({ items, hasMarginUp, hasMarginDown, }: Properties) => import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export default CheckListDynamic;
|
|
9
|
+
//# sourceMappingURL=CheckListDynamic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CheckListDynamic.d.ts","sourceRoot":"","sources":["../../../src/dynamicComponents/CheckListDynamic.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAGzE,UAAU,UAAU;IACnB,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB;AAKD,QAAA,MAAM,gBAAgB,GAAI,wCAIvB,UAAU,4CA2CZ,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { ReactNode } from 'react';
|
|
1
|
+
import type { HTMLAttributes, ReactElement, ReactNode } from 'react';
|
|
2
2
|
interface BlogSectionStaticProperties {
|
|
3
|
-
title?: string
|
|
3
|
+
title?: string | ReactElement<HTMLAttributes<HTMLParagraphElement>, 'p'>;
|
|
4
4
|
category?: string;
|
|
5
5
|
children?: ReactNode;
|
|
6
6
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BlogSectionStatic.d.ts","sourceRoot":"","sources":["../../../src/staticComponents/BlogSectionStatic.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"BlogSectionStatic.d.ts","sourceRoot":"","sources":["../../../src/staticComponents/BlogSectionStatic.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIrE,UAAU,2BAA2B;IACpC,KAAK,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC,cAAc,CAAC,oBAAoB,CAAC,EAAE,GAAG,CAAC,CAAC;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACrB;AAED,QAAA,MAAM,iBAAiB,GAAI,gCAIxB,2BAA2B,4CAa7B,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { HTMLAttributes, ReactElement } from 'react';
|
|
2
2
|
export interface CheckListItem {
|
|
3
3
|
id: string;
|
|
4
|
-
children:
|
|
4
|
+
children: ReactElement<HTMLAttributes<HTMLParagraphElement>, 'p'>;
|
|
5
5
|
isChecked?: boolean;
|
|
6
6
|
}
|
|
7
7
|
interface CheckListProperties {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CheckListStatic.d.ts","sourceRoot":"","sources":["../../../src/staticComponents/CheckListStatic.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"CheckListStatic.d.ts","sourceRoot":"","sources":["../../../src/staticComponents/CheckListStatic.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAI1D,MAAM,WAAW,aAAa;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,YAAY,CAAC,cAAc,CAAC,oBAAoB,CAAC,EAAE,GAAG,CAAC,CAAC;IAClE,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,UAAU,mBAAmB;IAC5B,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,QAAA,MAAM,eAAe,GAAI,wCAItB,mBAAmB,4CAmBrB,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export declare const extractTextFromReactNode: (node: ReactNode) => string;
|
|
1
3
|
export declare const generateIdForBlogTitle: (title: string) => string;
|
|
2
4
|
export declare const generateUrlForBlogTitle: (title: string) => string;
|
|
3
5
|
export declare const generateSectionHref: (id: string) => string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,eAAO,MAAM,wBAAwB,GAAI,MAAM,SAAS,KAAG,MAM1D,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,OAAO,MAAM,WAAiD,CAAC;AAEtG,eAAO,MAAM,uBAAuB,GAAI,OAAO,MAAM,WAAoE,CAAC;AAE1H,eAAO,MAAM,mBAAmB,GAAI,IAAI,MAAM,WAAqB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../../src/utils/index.test.tsx"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@san-siva/blogkit",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.32",
|
|
4
4
|
"description": "A reusable blog component library for React/Next.js applications with code highlighting, diagrams, and rich content features",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"scripts": {
|
|
25
25
|
"build": "rollup -c && tsc --emitDeclarationOnly --outDir dist/types && cp -r src/assets dist/",
|
|
26
26
|
"dev": "rollup -c -w",
|
|
27
|
+
"test": "vitest run",
|
|
27
28
|
"lint": "tsc --noEmit",
|
|
28
29
|
"prepublishOnly": "npm ci && npm run lint && npm run build"
|
|
29
30
|
},
|
|
@@ -70,6 +71,7 @@
|
|
|
70
71
|
"rollup-plugin-url": "^3.0.1",
|
|
71
72
|
"sass": "^1.77.8",
|
|
72
73
|
"tslib": "^2.8.1",
|
|
73
|
-
"typescript": "^5.7.2"
|
|
74
|
+
"typescript": "^5.7.2",
|
|
75
|
+
"vitest": "^4.1.2"
|
|
74
76
|
}
|
|
75
77
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { forwardRef, lazy, Suspense } from 'react';
|
|
4
|
-
import type { ReactNode } from 'react';
|
|
4
|
+
import type { HTMLAttributes, ReactElement, ReactNode } from 'react';
|
|
5
5
|
import BlogSectionStatic from '../staticComponents/BlogSectionStatic';
|
|
6
6
|
import type { ForwardedReference } from '../dynamicComponents/BlogDynamic';
|
|
7
7
|
export type { ForwardedReference };
|
|
@@ -11,7 +11,7 @@ const BlogSectionDynamic = lazy(
|
|
|
11
11
|
);
|
|
12
12
|
|
|
13
13
|
interface BlogSectionProperties {
|
|
14
|
-
title?: string
|
|
14
|
+
title?: string | ReactElement<HTMLAttributes<HTMLParagraphElement>, 'p'>;
|
|
15
15
|
category?: string;
|
|
16
16
|
children?: ReactNode;
|
|
17
17
|
}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { lazy, Suspense } from 'react';
|
|
1
4
|
import CheckListStatic, { type CheckListItem } from '../staticComponents/CheckListStatic';
|
|
2
5
|
|
|
6
|
+
const CheckListDynamic = lazy(() => import('../dynamicComponents/CheckListDynamic'));
|
|
7
|
+
|
|
3
8
|
interface CheckListProperties {
|
|
4
9
|
items: CheckListItem[];
|
|
5
10
|
hasMarginUp?: boolean;
|
|
@@ -12,7 +17,13 @@ const CheckList = ({
|
|
|
12
17
|
hasMarginDown = false,
|
|
13
18
|
}: CheckListProperties) => {
|
|
14
19
|
return (
|
|
15
|
-
<
|
|
20
|
+
<Suspense
|
|
21
|
+
fallback={
|
|
22
|
+
<CheckListStatic items={items} hasMarginUp={hasMarginUp} hasMarginDown={hasMarginDown} />
|
|
23
|
+
}
|
|
24
|
+
>
|
|
25
|
+
<CheckListDynamic items={items} hasMarginUp={hasMarginUp} hasMarginDown={hasMarginDown} />
|
|
26
|
+
</Suspense>
|
|
16
27
|
);
|
|
17
28
|
};
|
|
18
29
|
|
|
@@ -10,15 +10,15 @@ import {
|
|
|
10
10
|
useRef,
|
|
11
11
|
} from 'react';
|
|
12
12
|
|
|
13
|
-
import type { ReactNode, RefAttributes } from 'react';
|
|
13
|
+
import type { HTMLAttributes, ReactElement, ReactNode, RefAttributes } from 'react';
|
|
14
14
|
|
|
15
15
|
import styles from '../styles/BlogSection.module.scss';
|
|
16
16
|
|
|
17
17
|
import type { ForwardedReference } from './BlogDynamic';
|
|
18
|
-
import { generateIdForBlogTitle, generateSectionHref } from '../utils';
|
|
18
|
+
import { extractTextFromReactNode, generateIdForBlogTitle, generateSectionHref } from '../utils';
|
|
19
19
|
|
|
20
20
|
interface BlogProperties {
|
|
21
|
-
title?: string
|
|
21
|
+
title?: string | ReactElement<HTMLAttributes<HTMLParagraphElement>, 'p'>;
|
|
22
22
|
category?: string;
|
|
23
23
|
children?: ReactNode;
|
|
24
24
|
}
|
|
@@ -28,7 +28,8 @@ const BlogSection = forwardRef<ForwardedReference, BlogProperties>(
|
|
|
28
28
|
{ title = '', category = '', children = null }: BlogProperties,
|
|
29
29
|
forwardedReference
|
|
30
30
|
) => {
|
|
31
|
-
const
|
|
31
|
+
const titleString = typeof title === 'string' ? title : extractTextFromReactNode(title);
|
|
32
|
+
const titleWithCategory = category ? `${category} - ${titleString}` : titleString;
|
|
32
33
|
const id = generateIdForBlogTitle(titleWithCategory);
|
|
33
34
|
|
|
34
35
|
const parentReference = useRef<ForwardedReference['parentRef']>(null);
|
|
@@ -78,7 +79,7 @@ const BlogSection = forwardRef<ForwardedReference, BlogProperties>(
|
|
|
78
79
|
return (
|
|
79
80
|
<div
|
|
80
81
|
className={styles['blog-section']}
|
|
81
|
-
data-title={
|
|
82
|
+
data-title={titleString}
|
|
82
83
|
data-id={id}
|
|
83
84
|
ref={parentReference}
|
|
84
85
|
>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useEffect, useRef, useState } from 'react';
|
|
4
|
+
|
|
5
|
+
import type { CheckListItem } from '../staticComponents/CheckListStatic';
|
|
6
|
+
import styles from '../styles/CheckList.module.scss';
|
|
7
|
+
|
|
8
|
+
interface Properties {
|
|
9
|
+
items: CheckListItem[];
|
|
10
|
+
hasMarginUp?: boolean;
|
|
11
|
+
hasMarginDown?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const CHECKBOX_SIZE = 12;
|
|
15
|
+
const P_TAG_FONT_SIZE = 16;
|
|
16
|
+
|
|
17
|
+
const CheckListDynamic = ({
|
|
18
|
+
items,
|
|
19
|
+
hasMarginUp = false,
|
|
20
|
+
hasMarginDown = false,
|
|
21
|
+
}: Properties) => {
|
|
22
|
+
const [checkboxMarginTop, setCheckboxMarginTop] = useState(0);
|
|
23
|
+
const measureRef = useRef<HTMLDivElement>(null);
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (!measureRef.current) return;
|
|
27
|
+
const p = measureRef.current.querySelector('p');
|
|
28
|
+
if (!p) return;
|
|
29
|
+
const rawLineHeight = getComputedStyle(p).lineHeight;
|
|
30
|
+
const lineHeight =
|
|
31
|
+
rawLineHeight === 'normal'
|
|
32
|
+
? P_TAG_FONT_SIZE * 1.2
|
|
33
|
+
: parseFloat(rawLineHeight);
|
|
34
|
+
if (!isNaN(lineHeight)) {
|
|
35
|
+
setCheckboxMarginTop(Math.max(0, (lineHeight - CHECKBOX_SIZE) / 2));
|
|
36
|
+
}
|
|
37
|
+
}, []);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<div
|
|
41
|
+
className={`${styles['check-list']} ${hasMarginUp ? styles['margin-top--1'] : ''} ${
|
|
42
|
+
hasMarginDown ? styles['margin-bottom--2'] : ''
|
|
43
|
+
}`}
|
|
44
|
+
>
|
|
45
|
+
{items.map((item, index) => (
|
|
46
|
+
<div
|
|
47
|
+
key={item.id}
|
|
48
|
+
className={styles['check-list__item']}
|
|
49
|
+
style={{ alignItems: 'flex-start' }}
|
|
50
|
+
data-id={item.id}
|
|
51
|
+
ref={index === 0 ? measureRef : undefined}
|
|
52
|
+
>
|
|
53
|
+
<div
|
|
54
|
+
className={`${styles['check-list__item__input']} ${
|
|
55
|
+
item.isChecked ? styles['check-list__item__input--checked'] : ''
|
|
56
|
+
}`}
|
|
57
|
+
style={{ marginTop: `${checkboxMarginTop}px` }}
|
|
58
|
+
/>
|
|
59
|
+
{item.children}
|
|
60
|
+
</div>
|
|
61
|
+
))}
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export default CheckListDynamic;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { ReactNode } from 'react';
|
|
1
|
+
import type { HTMLAttributes, ReactElement, ReactNode } from 'react';
|
|
2
2
|
import styles from '../styles/BlogSection.module.scss';
|
|
3
|
-
import { generateIdForBlogTitle } from '../utils';
|
|
3
|
+
import { extractTextFromReactNode, generateIdForBlogTitle } from '../utils';
|
|
4
4
|
|
|
5
5
|
interface BlogSectionStaticProperties {
|
|
6
|
-
title?: string
|
|
6
|
+
title?: string | ReactElement<HTMLAttributes<HTMLParagraphElement>, 'p'>;
|
|
7
7
|
category?: string;
|
|
8
8
|
children?: ReactNode;
|
|
9
9
|
}
|
|
@@ -13,11 +13,12 @@ const BlogSectionStatic = ({
|
|
|
13
13
|
category = '',
|
|
14
14
|
children = null,
|
|
15
15
|
}: BlogSectionStaticProperties) => {
|
|
16
|
-
const
|
|
16
|
+
const titleString = typeof title === 'string' ? title : extractTextFromReactNode(title);
|
|
17
|
+
const titleWithCategory = category ? `${category} - ${titleString}` : titleString;
|
|
17
18
|
const id = generateIdForBlogTitle(titleWithCategory);
|
|
18
19
|
|
|
19
20
|
return (
|
|
20
|
-
<div className={styles['blog-section']} data-title={
|
|
21
|
+
<div className={styles['blog-section']} data-title={titleString} data-id={id}>
|
|
21
22
|
{title ? (
|
|
22
23
|
<h3 className={styles['blog-section__title']}>{title}</h3>
|
|
23
24
|
) : null}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { HTMLAttributes, ReactElement } from 'react';
|
|
2
2
|
|
|
3
3
|
import styles from '../styles/CheckList.module.scss';
|
|
4
4
|
|
|
5
5
|
export interface CheckListItem {
|
|
6
6
|
id: string;
|
|
7
|
-
children:
|
|
7
|
+
children: ReactElement<HTMLAttributes<HTMLParagraphElement>, 'p'>;
|
|
8
8
|
isChecked?: boolean;
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -32,7 +32,7 @@ const CheckListStatic = ({
|
|
|
32
32
|
item.isChecked ? styles['check-list__item__input--checked'] : ''
|
|
33
33
|
}`}
|
|
34
34
|
/>
|
|
35
|
-
|
|
35
|
+
{item.children}
|
|
36
36
|
</div>
|
|
37
37
|
))}
|
|
38
38
|
</div>
|
|
@@ -16,11 +16,15 @@
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
&__title-link {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
&,
|
|
20
|
+
> p,
|
|
21
|
+
> p > * {
|
|
22
|
+
color: inherit;
|
|
23
|
+
text-decoration: none;
|
|
24
|
+
font-size: inherit;
|
|
25
|
+
font-weight: inherit;
|
|
26
|
+
font-family: inherit;
|
|
27
|
+
}
|
|
24
28
|
|
|
25
29
|
&:hover {
|
|
26
30
|
color: stylekit.$color--dark;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { createElement } from 'react';
|
|
3
|
+
import { extractTextFromReactNode } from './index';
|
|
4
|
+
|
|
5
|
+
describe('extractTextFromReactNode', () => {
|
|
6
|
+
it('returns empty string for null', () => {
|
|
7
|
+
expect(extractTextFromReactNode(null)).toBe('');
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('returns empty string for undefined', () => {
|
|
11
|
+
expect(extractTextFromReactNode(undefined)).toBe('');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('returns empty string for boolean', () => {
|
|
15
|
+
expect(extractTextFromReactNode(true)).toBe('');
|
|
16
|
+
expect(extractTextFromReactNode(false)).toBe('');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('returns string as-is', () => {
|
|
20
|
+
expect(extractTextFromReactNode('Hello')).toBe('Hello');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('converts number to string', () => {
|
|
24
|
+
expect(extractTextFromReactNode(42)).toBe('42');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('extracts text from a simple element', () => {
|
|
28
|
+
const node = createElement('p', null, 'Section title');
|
|
29
|
+
expect(extractTextFromReactNode(node)).toBe('Section title');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('extracts text from nested elements', () => {
|
|
33
|
+
const node = createElement('p', null,
|
|
34
|
+
'Hello ',
|
|
35
|
+
createElement('strong', null, 'world'),
|
|
36
|
+
);
|
|
37
|
+
expect(extractTextFromReactNode(node)).toBe('Hello world');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('extracts text from deeply nested elements', () => {
|
|
41
|
+
const node = createElement('p', null,
|
|
42
|
+
createElement('em', null,
|
|
43
|
+
createElement('strong', null, 'deep'),
|
|
44
|
+
),
|
|
45
|
+
);
|
|
46
|
+
expect(extractTextFromReactNode(node)).toBe('deep');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('extracts text from an array of nodes', () => {
|
|
50
|
+
const nodes = ['foo', ' ', createElement('span', null, 'bar')];
|
|
51
|
+
expect(extractTextFromReactNode(nodes)).toBe('foo bar');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('handles mixed content with numbers and elements', () => {
|
|
55
|
+
const node = createElement('p', null, 'Step ', 3, ': done');
|
|
56
|
+
expect(extractTextFromReactNode(node)).toBe('Step 3: done');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('returns empty string for element with no children', () => {
|
|
60
|
+
const node = createElement('p', null);
|
|
61
|
+
expect(extractTextFromReactNode(node)).toBe('');
|
|
62
|
+
});
|
|
63
|
+
});
|
package/src/utils/index.ts
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
import { isValidElement } from 'react';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
export const extractTextFromReactNode = (node: ReactNode): string => {
|
|
5
|
+
if (node === null || node === undefined || typeof node === 'boolean') return '';
|
|
6
|
+
if (typeof node === 'string' || typeof node === 'number') return String(node);
|
|
7
|
+
if (isValidElement(node)) return extractTextFromReactNode((node.props as { children?: ReactNode }).children);
|
|
8
|
+
if (Array.isArray(node)) return node.map(extractTextFromReactNode).join('');
|
|
9
|
+
return '';
|
|
10
|
+
};
|
|
11
|
+
|
|
1
12
|
export const generateIdForBlogTitle = (title: string) => title.toLowerCase().replace(/[^\w\d]/g, '-');
|
|
2
13
|
|
|
3
14
|
export const generateUrlForBlogTitle = (title: string) => encodeURIComponent(title.replace(/[^\w]+/g, '-').toLowerCase());
|