diff --git a/package-lock.json b/package-lock.json
index 658883f..76635fe 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "editorjs-blocks-react-renderer",
- "version": "1.2.4",
+ "version": "1.3.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "editorjs-blocks-react-renderer",
- "version": "1.2.4",
+ "version": "1.3.0",
"license": "MIT",
"dependencies": {
"html-react-parser": "^1.4.14"
diff --git a/src/renderers/list/__snapshots__/index.test.tsx.snap b/src/renderers/list/__snapshots__/index.test.tsx.snap
index 88b9adf..ca8fe2b 100644
--- a/src/renderers/list/__snapshots__/index.test.tsx.snap
+++ b/src/renderers/list/__snapshots__/index.test.tsx.snap
@@ -1,5 +1,27 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
+exports[`
backward compatibility renders ordered list without meta property (default behavior) 1`] = `
+
+ -
+ Item without meta
+
+ -
+ Another item
+
+
+`;
+
+exports[`
backward compatibility renders unordered list without meta property 1`] = `
+
+ -
+ Bullet item
+
+ -
+ Another bullet
+
+
+`;
+
exports[`
when receives a list "ordered" block renders a block 1`] = `
-
@@ -36,6 +58,137 @@ exports[`
when receives a list "unordered" block renders a
`;
+exports[`
when receives a list with meta property with custom start value renders an block with start attribute 1`] = `
+
+ -
+ First item
+
+ -
+ Second item
+
+ -
+ Third item
+
+
+`;
+
+exports[`
when receives a list with meta property with lower-alpha counter type renders an block with lower-alpha list style 1`] = `
+
+ -
+ First item
+
+ -
+ Second item
+
+ -
+ Third item
+
+
+`;
+
+exports[`
when receives a list with meta property with lower-roman counter type renders an block with lower-roman list style 1`] = `
+
+ -
+ First item
+
+ -
+ Second item
+
+ -
+ Third item
+
+
+`;
+
+exports[`
when receives a list with meta property with nested lists and meta properties renders nested blocks with inherited meta properties 1`] = `
+
+ -
+ First level item 1
+
+ -
+ First level item 2
+
+ -
+ Nested item 1
+
+ -
+ Nested item 2
+
+
+
+
+`;
+
+exports[`
when receives a list with meta property with upper-alpha counter type renders an block with upper-alpha list style and custom start 1`] = `
+
+ -
+ First item
+
+ -
+ Second item
+
+ -
+ Third item
+
+
+`;
+
+exports[`
when receives a list with meta property with upper-roman counter type renders an block with upper-roman list style and custom start 1`] = `
+
+ -
+ First item
+
+ -
+ Second item
+
+ -
+ Third item
+
+
+`;
+
exports[`
when receives a nested list "ordered" block and when className is provided renders className to all blocks 1`] = `
', () => {
});
});
});
-});
+
+ describe('when receives a list with meta property', () => {
+ describe('with custom start value', () => {
+ const data: ListBlockData = {
+ style: 'ordered',
+ items: [
+ 'First item',
+ 'Second item',
+ 'Third item',
+ ],
+ meta: {
+ start: 5,
+ counterType: 'numeric',
+ },
+ };
+
+ it('renders an block with start attribute', () => {
+ const tree = create(
).toJSON();
+ expect(tree).toMatchSnapshot();
+ // @ts-expect-error - accessing props for testing
+ expect(tree.props.start).toBe(5);
+ });
+ });
+
+ describe('with lower-roman counter type', () => {
+ const data: ListBlockData = {
+ style: 'ordered',
+ items: [
+ 'First item',
+ 'Second item',
+ 'Third item',
+ ],
+ meta: {
+ start: 1,
+ counterType: 'lower-roman',
+ },
+ };
+
+ it('renders an block with lower-roman list style', () => {
+ const tree = create(
).toJSON();
+ expect(tree).toMatchSnapshot();
+ // @ts-expect-error - accessing props for testing
+ expect(tree.props.style.listStyleType).toBe('lower-roman');
+ });
+ });
+
+ describe('with upper-roman counter type', () => {
+ const data: ListBlockData = {
+ style: 'ordered',
+ items: [
+ 'First item',
+ 'Second item',
+ 'Third item',
+ ],
+ meta: {
+ start: 3,
+ counterType: 'upper-roman',
+ },
+ };
+
+ it('renders an block with upper-roman list style and custom start', () => {
+ const tree = create(
).toJSON();
+ expect(tree).toMatchSnapshot();
+ // @ts-expect-error - accessing props for testing
+ expect(tree.props.start).toBe(3);
+ // @ts-expect-error - accessing props for testing
+ expect(tree.props.style.listStyleType).toBe('upper-roman');
+ });
+ });
+
+ describe('with lower-alpha counter type', () => {
+ const data: ListBlockData = {
+ style: 'ordered',
+ items: [
+ 'First item',
+ 'Second item',
+ 'Third item',
+ ],
+ meta: {
+ start: 1,
+ counterType: 'lower-alpha',
+ },
+ };
+
+ it('renders an block with lower-alpha list style', () => {
+ const tree = create(
).toJSON();
+ expect(tree).toMatchSnapshot();
+ // @ts-expect-error - accessing props for testing
+ expect(tree.props.style.listStyleType).toBe('lower-alpha');
+ });
+ });
+
+ describe('with upper-alpha counter type', () => {
+ const data: ListBlockData = {
+ style: 'ordered',
+ items: [
+ 'First item',
+ 'Second item',
+ 'Third item',
+ ],
+ meta: {
+ start: 2,
+ counterType: 'upper-alpha',
+ },
+ };
+
+ it('renders an block with upper-alpha list style and custom start', () => {
+ const tree = create(
).toJSON();
+ expect(tree).toMatchSnapshot();
+ // @ts-expect-error - accessing props for testing
+ expect(tree.props.start).toBe(2);
+ // @ts-expect-error - accessing props for testing
+ expect(tree.props.style.listStyleType).toBe('upper-alpha');
+ });
+ });
+
+ describe('with nested lists and meta properties', () => {
+ const data: ListBlockData = {
+ style: 'ordered',
+ items: [
+ {
+ content: 'First level item 1',
+ items: [],
+ },
+ {
+ content: 'First level item 2',
+ items: [
+ {
+ content: 'Nested item 1',
+ items: [],
+ },
+ {
+ content: 'Nested item 2',
+ items: [],
+ },
+ ],
+ },
+ ],
+ meta: {
+ start: 3,
+ counterType: 'upper-roman',
+ },
+ };
+
+ it('renders nested blocks with inherited meta properties', () => {
+ const tree = create(
).toJSON();
+ expect(tree).toMatchSnapshot();
+ });
+ });
+ });
+
+ describe('backward compatibility', () => {
+ it('renders ordered list without meta property (default behavior)', () => {
+ const data: ListBlockData = {
+ style: 'ordered',
+ items: [
+ 'Item without meta',
+ 'Another item',
+ ],
+ };
+
+ const tree = create(
).toJSON();
+ expect(tree).toMatchSnapshot();
+ // Should not have start attribute when start is 1 (default)
+ // @ts-expect-error - accessing props for testing
+ expect(tree.props.start).toBeUndefined();
+ });
+
+ it('renders unordered list without meta property', () => {
+ const data: ListBlockData = {
+ style: 'unordered',
+ items: [
+ 'Bullet item',
+ 'Another bullet',
+ ],
+ };
+
+ const tree = create(
).toJSON();
+ expect(tree).toMatchSnapshot();
+ });
+ });
+});
\ No newline at end of file
diff --git a/src/renderers/list/index.tsx b/src/renderers/list/index.tsx
index f2435a2..bf0d088 100644
--- a/src/renderers/list/index.tsx
+++ b/src/renderers/list/index.tsx
@@ -5,6 +5,10 @@ import { RenderFn } from '../..';
export interface ListBlockData {
style: 'ordered' | 'unordered';
items: NestedListItem[];
+ meta?: {
+ start?: number;
+ counterType?: 'numeric' | 'lower-roman' | 'upper-roman' | 'lower-alpha' | 'upper-alpha';
+ };
}
export type NestedListItem =
@@ -20,22 +24,61 @@ const Group: FC<{
Tag: keyof JSX.IntrinsicElements;
items: NestedListItem[];
className?: string;
-}> = ({ Tag, items, ...props }) => (
-
- {items.map((item, i) => (
-
- {typeof item === 'string' ? (
- HTMLReactParser(item)
- ) : (
- <>
- {HTMLReactParser(item?.content)}
- {item?.items?.length > 0 && }
- >
- )}
-
- ))}
-
-);
+ start?: number;
+ counterType?: 'numeric' | 'lower-roman' | 'upper-roman' | 'lower-alpha' | 'upper-alpha';
+}> = ({ Tag, items, className, start = 1, counterType = 'numeric', ...props }) => {
+ const listProps: {
+ [key: string]: any;
+ } = { ...props };
+
+ if (className) {
+ listProps.className = className;
+ }
+
+ // Handle ordered list attributes
+ if (Tag === 'ol') {
+ if (start && start !== 1) {
+ listProps.start = start;
+ }
+ // Apply counter type styling
+ if (counterType && counterType !== 'numeric') {
+ const counterTypeMap: Record = {
+ 'lower-roman': 'lower-roman',
+ 'upper-roman': 'upper-roman',
+ 'lower-alpha': 'lower-alpha',
+ 'upper-alpha': 'upper-alpha',
+ };
+ const styleType = counterTypeMap[counterType] || counterType;
+ listProps.style = { listStyleType: styleType };
+ }
+ }
+
+ return (
+
+ {items.map((item, i) => (
+
+ {typeof item === 'string' ? (
+ HTMLReactParser(item)
+ ) : (
+ <>
+ {HTMLReactParser(item?.content)}
+ {item?.items?.length > 0 && (
+
+ )}
+ >
+ )}
+
+ ))}
+
+ );
+};
const List: RenderFn = ({ data, className = '' }) => {
const props: {
@@ -46,8 +89,20 @@ const List: RenderFn = ({ data, className = '' }) => {
props.className = className;
}
+ const { start = 1, counterType = 'numeric' } = data?.meta || {};
const Tag = (data?.style === 'ordered' ? `ol` : `ul`) as keyof JSX.IntrinsicElements;
- return data && ;
+
+ return (
+ data && (
+
+ )
+ );
};
-export default List;
+export default List;
\ No newline at end of file