From 3067f859756f97676d3b009c9faae4d30f9f5831 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 5 Apr 2026 09:55:34 +0000 Subject: [PATCH 1/2] Initial plan From b4ace77fa2c2bfd1b68243a5835c877250c9b69d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 5 Apr 2026 09:58:29 +0000 Subject: [PATCH 2/2] fix(list): remove redundant flex:1 View wrapper in bullet variant to prevent row overlap on wrapped text Agent-Logs-Url: https://github.com/akii09/pdfx/sessions/cff39600-7fcb-41da-9e8e-56ff987131e0 Co-authored-by: akii09 <47731376+akii09@users.noreply.github.com> --- apps/www/public/r/list.json | 58 +++++++++---------- .../registry/components/list/list.test.tsx | 23 ++++++++ .../www/src/registry/components/list/list.tsx | 4 +- 3 files changed, 53 insertions(+), 32 deletions(-) diff --git a/apps/www/public/r/list.json b/apps/www/public/r/list.json index df08be08..a9ebcf72 100644 --- a/apps/www/public/r/list.json +++ b/apps/www/public/r/list.json @@ -1,30 +1,30 @@ { - "$schema": "https://pdfx.akashpise.dev/schema/registry-item.json", - "name": "list", - "type": "registry:ui", - "title": "List", - "description": "List component with bullet, numbered, checklist, icon, multi-level, and descriptive variants", - "files": [ - { - "path": "components/pdfx/list/pdfx-list.tsx", - "content": "import { Text as PDFText, View } from '@react-pdf/renderer';\nimport type { Style } from '@react-pdf/types';\nimport type React from 'react';\nimport { usePdfxTheme, useSafeMemo } from '../lib/pdfx-theme-context';\nimport { createListStyles } from './pdfx-list.styles';\nimport type { ListItem, ListVariant, PdfListProps } from './pdfx-list.types';\n\ntype Styles = ReturnType;\ntype GapProp = 'xs' | 'sm' | 'md';\n\nfunction getGapStyle(gap: GapProp, styles: Styles): Style {\n if (gap === 'xs') return styles.itemRowGapXs;\n if (gap === 'md') return styles.itemRowGapMd;\n return styles.itemRowGapSm;\n}\n\nfunction buildRowStyles(\n index: number,\n total: number,\n gap: GapProp,\n styles: Styles,\n align: 'start' | 'center' = 'start'\n): Style[] {\n const row: Style[] = [align === 'center' ? styles.itemRowCenter : styles.itemRow];\n if (index !== total - 1) row.push(getGapStyle(gap, styles));\n return row;\n}\n\n/** Bullet dot marker — solid filled for level 0, outline ring for nested levels. */\nfunction dotMarker(level: number, styles: Styles): React.ReactElement {\n return level === 0 ? (\n \n \n \n ) : (\n \n \n \n );\n}\n\nfunction renderBulletItem(\n item: ListItem,\n index: number,\n total: number,\n gap: GapProp,\n styles: Styles,\n level: number\n): React.ReactElement {\n return (\n \n \n {dotMarker(level, styles)}\n \n {item.text}\n \n \n {item.children && item.children.length > 0\n ? renderItemList(item.children, 'bullet', gap, styles, level + 1)\n : null}\n \n );\n}\n\nfunction renderNumberedItem(\n item: ListItem,\n index: number,\n total: number,\n gap: GapProp,\n styles: Styles\n): React.ReactElement {\n return (\n \n \n {`${index + 1}`}\n \n {item.text}\n \n );\n}\n\nfunction renderChecklistItem(\n item: ListItem,\n index: number,\n total: number,\n gap: GapProp,\n styles: Styles\n): React.ReactElement {\n const isChecked = item.checked ?? true;\n return (\n \n \n {isChecked ? : null}\n \n {item.text}\n \n );\n}\n\nfunction renderIconItem(\n item: ListItem,\n index: number,\n total: number,\n gap: GapProp,\n styles: Styles\n): React.ReactElement {\n return (\n \n \n \n \n {item.text}\n \n );\n}\n\nfunction renderMultiLevelItem(\n item: ListItem,\n index: number,\n total: number,\n gap: GapProp,\n styles: Styles,\n level: number\n): React.ReactElement {\n return (\n \n \n {dotMarker(level, styles)}\n \n {item.text}\n \n \n {item.children && item.children.length > 0\n ? renderItemList(item.children, 'multi-level', gap, styles, level + 1)\n : null}\n \n );\n}\n\nfunction renderDescriptiveItem(\n item: ListItem,\n index: number,\n total: number,\n gap: GapProp,\n styles: Styles\n): React.ReactElement {\n return (\n \n \n \n {item.text}\n {item.description ? (\n {item.description}\n ) : null}\n \n \n );\n}\n\nfunction renderItem(\n item: ListItem,\n index: number,\n total: number,\n variant: ListVariant,\n gap: GapProp,\n styles: Styles,\n level: number\n): React.ReactElement | null {\n switch (variant) {\n case 'bullet':\n return renderBulletItem(item, index, total, gap, styles, level);\n case 'numbered':\n return renderNumberedItem(item, index, total, gap, styles);\n case 'checklist':\n return renderChecklistItem(item, index, total, gap, styles);\n case 'icon':\n return renderIconItem(item, index, total, gap, styles);\n case 'multi-level':\n return renderMultiLevelItem(item, index, total, gap, styles, level);\n case 'descriptive':\n return renderDescriptiveItem(item, index, total, gap, styles);\n }\n}\n\nfunction renderItemList(\n items: ListItem[],\n variant: ListVariant,\n gap: GapProp,\n styles: Styles,\n level: number\n): React.ReactElement {\n return (\n 0 ? styles.childrenContainer : undefined}>\n {items.map((item, index) =>\n renderItem(item, index, items.length, variant, gap, styles, level)\n )}\n \n );\n}\n\nexport function PdfList({\n items,\n variant = 'bullet',\n gap = 'sm',\n style,\n noWrap = false,\n _level = 0,\n}: PdfListProps) {\n const theme = usePdfxTheme();\n const styles = useSafeMemo(() => createListStyles(theme), [theme]);\n\n const containerStyles: Style[] = [styles.container];\n if (_level > 0) containerStyles.push(styles.childrenContainer);\n const styleArray = style ? [...containerStyles, style] : containerStyles;\n\n return (\n \n {items.map((item, index) =>\n renderItem(item, index, items.length, variant, gap, styles, _level)\n )}\n \n );\n}\n", - "type": "registry:component" - }, - { - "path": "components/pdfx/list/pdfx-list.styles.ts", - "content": "import { StyleSheet } from '@react-pdf/renderer';\nimport { usePdfxTheme } from '../lib/pdfx-theme-context';\ntype PdfxTheme = ReturnType;\n\n/**\n * Creates all list styles derived from the active theme.\n * @param t - The resolved PdfxTheme instance.\n */\nexport function createListStyles(t: PdfxTheme) {\n const { borderRadius, spacing, fontWeights, typography } = t.primitives;\n\n return StyleSheet.create({\n container: {\n display: 'flex',\n flexDirection: 'column',\n width: '100%',\n marginBottom: t.spacing.componentGap,\n },\n itemRow: {\n flexDirection: 'row',\n alignItems: 'flex-start',\n },\n itemRowCenter: {\n flexDirection: 'row',\n alignItems: 'center',\n },\n itemRowGapXs: { marginBottom: spacing[1] },\n itemRowGapSm: { marginBottom: spacing[2] },\n itemRowGapMd: { marginBottom: spacing[3] },\n markerBulletWrap: {\n width: spacing[4],\n alignItems: 'center',\n justifyContent: 'flex-start',\n marginTop: spacing[1],\n },\n markerBulletDot: {\n width: 5,\n height: 5,\n borderRadius: 3,\n backgroundColor: t.colors.primary,\n },\n markerBulletSubWrap: {\n width: spacing[4],\n alignItems: 'center',\n justifyContent: 'flex-start',\n marginTop: spacing[1],\n },\n markerBulletSubDot: {\n width: 4,\n height: 4,\n borderRadius: 2,\n borderWidth: 1,\n borderStyle: 'solid',\n borderColor: t.colors.mutedForeground,\n backgroundColor: 'transparent',\n },\n markerNumberBadge: {\n width: spacing[5],\n height: spacing[5],\n borderRadius: spacing[5],\n backgroundColor: t.colors.primary,\n alignItems: 'center',\n justifyContent: 'center',\n marginRight: spacing[2],\n },\n markerNumberText: {\n fontFamily: t.typography.body.fontFamily,\n fontSize: typography.xs,\n color: t.colors.primaryForeground,\n fontWeight: fontWeights.bold,\n },\n checkBox: {\n width: spacing[4],\n height: spacing[4],\n borderWidth: 1.5,\n borderColor: t.colors.border,\n borderStyle: 'solid',\n borderRadius: 3,\n marginRight: spacing[2],\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: t.colors.background,\n },\n checkBoxChecked: {\n backgroundColor: t.colors.success,\n borderColor: t.colors.success,\n },\n checkMark: {\n fontFamily: t.typography.body.fontFamily,\n fontSize: 8,\n color: t.colors.background,\n fontWeight: fontWeights.bold,\n },\n iconBox: {\n width: spacing[5],\n height: spacing[5],\n borderRadius: borderRadius.md,\n backgroundColor: t.colors.primary,\n alignItems: 'center',\n justifyContent: 'center',\n marginRight: spacing[2],\n },\n iconMark: {\n fontFamily: t.typography.body.fontFamily,\n fontSize: 9,\n color: t.colors.primaryForeground,\n fontWeight: fontWeights.bold,\n },\n itemText: {\n flex: 1,\n fontFamily: t.typography.body.fontFamily,\n fontSize: t.typography.body.fontSize,\n lineHeight: t.typography.body.lineHeight,\n color: t.colors.foreground,\n },\n itemTextSub: {\n flex: 1,\n fontFamily: t.typography.body.fontFamily,\n fontSize: t.typography.body.fontSize - 0.5,\n lineHeight: t.typography.body.lineHeight,\n color: t.colors.mutedForeground,\n },\n itemTextBold: {\n fontWeight: fontWeights.semibold,\n },\n descriptiveTitle: {\n fontFamily: t.typography.body.fontFamily,\n fontSize: t.typography.body.fontSize,\n lineHeight: t.typography.body.lineHeight,\n color: t.colors.foreground,\n fontWeight: fontWeights.semibold,\n },\n descriptiveDesc: {\n fontFamily: t.typography.body.fontFamily,\n fontSize: typography.sm,\n lineHeight: t.typography.body.lineHeight,\n color: t.colors.mutedForeground,\n marginTop: 1,\n },\n descriptiveAccent: {\n width: 3,\n borderRadius: borderRadius.sm,\n backgroundColor: t.colors.primary,\n marginRight: spacing[3],\n minHeight: spacing[4],\n },\n descriptiveContent: {\n flex: 1,\n },\n childrenContainer: {\n marginLeft: spacing[5],\n marginTop: spacing[1],\n display: 'flex',\n flexDirection: 'column',\n },\n });\n}\n", - "type": "registry:component" - }, - { - "path": "components/pdfx/list/pdfx-list.types.ts", - "content": "import type { Style } from '@react-pdf/types';\n\n/** List visual style variant. */\nexport type ListVariant =\n | 'bullet'\n | 'numbered'\n | 'checklist'\n | 'icon'\n | 'multi-level'\n | 'descriptive';\n\n/**\n * A single list item, optionally with nested children.\n * Props - `text` | `description` | `checked` | `children`\n * @see {@link ListItem}\n */\nexport interface ListItem {\n text: string;\n description?: string;\n checked?: boolean;\n children?: ListItem[];\n}\n\n/**\n * List of items with multiple style variants including bullet, numbered, checklist, and descriptive.\n * Props - `items` | `variant` | `gap` | `style` | `_level` | `noWrap`\n * @see {@link PdfListProps}\n */\nexport interface PdfListProps {\n items: ListItem[];\n /**\n * @default 'bullet'\n */\n variant?: ListVariant;\n /**\n * @default 'sm'\n */\n gap?: 'xs' | 'sm' | 'md';\n style?: Style;\n _level?: number;\n /**\n * @default false\n */\n noWrap?: boolean;\n}\n", - "type": "registry:component" - } - ], - "dependencies": [ - "@react-pdf/renderer" - ], - "registryDependencies": [ - "theme" - ] -} \ No newline at end of file + "$schema": "https://pdfx.akashpise.dev/schema/registry-item.json", + "name": "list", + "type": "registry:ui", + "title": "List", + "description": "List component with bullet, numbered, checklist, icon, multi-level, and descriptive variants", + "files": [ + { + "path": "components/pdfx/list/pdfx-list.tsx", + "content": "import { Text as PDFText, View } from '@react-pdf/renderer';\nimport type { Style } from '@react-pdf/types';\nimport type React from 'react';\nimport { usePdfxTheme, useSafeMemo } from '../lib/pdfx-theme-context';\nimport { createListStyles } from './pdfx-list.styles';\nimport type { ListItem, ListVariant, PdfListProps } from './pdfx-list.types';\n\ntype Styles = ReturnType;\ntype GapProp = 'xs' | 'sm' | 'md';\n\nfunction getGapStyle(gap: GapProp, styles: Styles): Style {\n if (gap === 'xs') return styles.itemRowGapXs;\n if (gap === 'md') return styles.itemRowGapMd;\n return styles.itemRowGapSm;\n}\n\nfunction buildRowStyles(\n index: number,\n total: number,\n gap: GapProp,\n styles: Styles,\n align: 'start' | 'center' = 'start'\n): Style[] {\n const row: Style[] = [align === 'center' ? styles.itemRowCenter : styles.itemRow];\n if (index !== total - 1) row.push(getGapStyle(gap, styles));\n return row;\n}\n\n/** Bullet dot marker \u2014 solid filled for level 0, outline ring for nested levels. */\nfunction dotMarker(level: number, styles: Styles): React.ReactElement {\n return level === 0 ? (\n \n \n \n ) : (\n \n \n \n );\n}\n\nfunction renderBulletItem(\n item: ListItem,\n index: number,\n total: number,\n gap: GapProp,\n styles: Styles,\n level: number\n): React.ReactElement {\n return (\n \n \n {dotMarker(level, styles)}\n {item.text}\n \n {item.children && item.children.length > 0\n ? renderItemList(item.children, 'bullet', gap, styles, level + 1)\n : null}\n \n );\n}\n\nfunction renderNumberedItem(\n item: ListItem,\n index: number,\n total: number,\n gap: GapProp,\n styles: Styles\n): React.ReactElement {\n return (\n \n \n {`${index + 1}`}\n \n {item.text}\n \n );\n}\n\nfunction renderChecklistItem(\n item: ListItem,\n index: number,\n total: number,\n gap: GapProp,\n styles: Styles\n): React.ReactElement {\n const isChecked = item.checked ?? true;\n return (\n \n \n {isChecked ? \u2713 : null}\n \n {item.text}\n \n );\n}\n\nfunction renderIconItem(\n item: ListItem,\n index: number,\n total: number,\n gap: GapProp,\n styles: Styles\n): React.ReactElement {\n return (\n \n \n \u2605\n \n {item.text}\n \n );\n}\n\nfunction renderMultiLevelItem(\n item: ListItem,\n index: number,\n total: number,\n gap: GapProp,\n styles: Styles,\n level: number\n): React.ReactElement {\n return (\n \n \n {dotMarker(level, styles)}\n \n {item.text}\n \n \n {item.children && item.children.length > 0\n ? renderItemList(item.children, 'multi-level', gap, styles, level + 1)\n : null}\n \n );\n}\n\nfunction renderDescriptiveItem(\n item: ListItem,\n index: number,\n total: number,\n gap: GapProp,\n styles: Styles\n): React.ReactElement {\n return (\n \n \n \n {item.text}\n {item.description ? (\n {item.description}\n ) : null}\n \n \n );\n}\n\nfunction renderItem(\n item: ListItem,\n index: number,\n total: number,\n variant: ListVariant,\n gap: GapProp,\n styles: Styles,\n level: number\n): React.ReactElement | null {\n switch (variant) {\n case 'bullet':\n return renderBulletItem(item, index, total, gap, styles, level);\n case 'numbered':\n return renderNumberedItem(item, index, total, gap, styles);\n case 'checklist':\n return renderChecklistItem(item, index, total, gap, styles);\n case 'icon':\n return renderIconItem(item, index, total, gap, styles);\n case 'multi-level':\n return renderMultiLevelItem(item, index, total, gap, styles, level);\n case 'descriptive':\n return renderDescriptiveItem(item, index, total, gap, styles);\n }\n}\n\nfunction renderItemList(\n items: ListItem[],\n variant: ListVariant,\n gap: GapProp,\n styles: Styles,\n level: number\n): React.ReactElement {\n return (\n 0 ? styles.childrenContainer : undefined}>\n {items.map((item, index) =>\n renderItem(item, index, items.length, variant, gap, styles, level)\n )}\n \n );\n}\n\nexport function PdfList({\n items,\n variant = 'bullet',\n gap = 'sm',\n style,\n noWrap = false,\n _level = 0,\n}: PdfListProps) {\n const theme = usePdfxTheme();\n const styles = useSafeMemo(() => createListStyles(theme), [theme]);\n\n const containerStyles: Style[] = [styles.container];\n if (_level > 0) containerStyles.push(styles.childrenContainer);\n const styleArray = style ? [...containerStyles, style] : containerStyles;\n\n return (\n \n {items.map((item, index) =>\n renderItem(item, index, items.length, variant, gap, styles, _level)\n )}\n \n );\n}\n", + "type": "registry:component" + }, + { + "path": "components/pdfx/list/pdfx-list.styles.ts", + "content": "import { StyleSheet } from '@react-pdf/renderer';\nimport { usePdfxTheme } from '../lib/pdfx-theme-context';\ntype PdfxTheme = ReturnType;\n\n/**\n * Creates all list styles derived from the active theme.\n * @param t - The resolved PdfxTheme instance.\n */\nexport function createListStyles(t: PdfxTheme) {\n const { borderRadius, spacing, fontWeights, typography } = t.primitives;\n\n return StyleSheet.create({\n container: {\n display: 'flex',\n flexDirection: 'column',\n width: '100%',\n marginBottom: t.spacing.componentGap,\n },\n itemRow: {\n flexDirection: 'row',\n alignItems: 'flex-start',\n },\n itemRowCenter: {\n flexDirection: 'row',\n alignItems: 'center',\n },\n itemRowGapXs: { marginBottom: spacing[1] },\n itemRowGapSm: { marginBottom: spacing[2] },\n itemRowGapMd: { marginBottom: spacing[3] },\n markerBulletWrap: {\n width: spacing[4],\n alignItems: 'center',\n justifyContent: 'flex-start',\n marginTop: spacing[1],\n },\n markerBulletDot: {\n width: 5,\n height: 5,\n borderRadius: 3,\n backgroundColor: t.colors.primary,\n },\n markerBulletSubWrap: {\n width: spacing[4],\n alignItems: 'center',\n justifyContent: 'flex-start',\n marginTop: spacing[1],\n },\n markerBulletSubDot: {\n width: 4,\n height: 4,\n borderRadius: 2,\n borderWidth: 1,\n borderStyle: 'solid',\n borderColor: t.colors.mutedForeground,\n backgroundColor: 'transparent',\n },\n markerNumberBadge: {\n width: spacing[5],\n height: spacing[5],\n borderRadius: spacing[5],\n backgroundColor: t.colors.primary,\n alignItems: 'center',\n justifyContent: 'center',\n marginRight: spacing[2],\n },\n markerNumberText: {\n fontFamily: t.typography.body.fontFamily,\n fontSize: typography.xs,\n color: t.colors.primaryForeground,\n fontWeight: fontWeights.bold,\n },\n checkBox: {\n width: spacing[4],\n height: spacing[4],\n borderWidth: 1.5,\n borderColor: t.colors.border,\n borderStyle: 'solid',\n borderRadius: 3,\n marginRight: spacing[2],\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: t.colors.background,\n },\n checkBoxChecked: {\n backgroundColor: t.colors.success,\n borderColor: t.colors.success,\n },\n checkMark: {\n fontFamily: t.typography.body.fontFamily,\n fontSize: 8,\n color: t.colors.background,\n fontWeight: fontWeights.bold,\n },\n iconBox: {\n width: spacing[5],\n height: spacing[5],\n borderRadius: borderRadius.md,\n backgroundColor: t.colors.primary,\n alignItems: 'center',\n justifyContent: 'center',\n marginRight: spacing[2],\n },\n iconMark: {\n fontFamily: t.typography.body.fontFamily,\n fontSize: 9,\n color: t.colors.primaryForeground,\n fontWeight: fontWeights.bold,\n },\n itemText: {\n flex: 1,\n fontFamily: t.typography.body.fontFamily,\n fontSize: t.typography.body.fontSize,\n lineHeight: t.typography.body.lineHeight,\n color: t.colors.foreground,\n },\n itemTextSub: {\n flex: 1,\n fontFamily: t.typography.body.fontFamily,\n fontSize: t.typography.body.fontSize - 0.5,\n lineHeight: t.typography.body.lineHeight,\n color: t.colors.mutedForeground,\n },\n itemTextBold: {\n fontWeight: fontWeights.semibold,\n },\n descriptiveTitle: {\n fontFamily: t.typography.body.fontFamily,\n fontSize: t.typography.body.fontSize,\n lineHeight: t.typography.body.lineHeight,\n color: t.colors.foreground,\n fontWeight: fontWeights.semibold,\n },\n descriptiveDesc: {\n fontFamily: t.typography.body.fontFamily,\n fontSize: typography.sm,\n lineHeight: t.typography.body.lineHeight,\n color: t.colors.mutedForeground,\n marginTop: 1,\n },\n descriptiveAccent: {\n width: 3,\n borderRadius: borderRadius.sm,\n backgroundColor: t.colors.primary,\n marginRight: spacing[3],\n minHeight: spacing[4],\n },\n descriptiveContent: {\n flex: 1,\n },\n childrenContainer: {\n marginLeft: spacing[5],\n marginTop: spacing[1],\n display: 'flex',\n flexDirection: 'column',\n },\n });\n}\n", + "type": "registry:component" + }, + { + "path": "components/pdfx/list/pdfx-list.types.ts", + "content": "import type { Style } from '@react-pdf/types';\n\n/** List visual style variant. */\nexport type ListVariant =\n | 'bullet'\n | 'numbered'\n | 'checklist'\n | 'icon'\n | 'multi-level'\n | 'descriptive';\n\n/**\n * A single list item, optionally with nested children.\n * Props - `text` | `description` | `checked` | `children`\n * @see {@link ListItem}\n */\nexport interface ListItem {\n text: string;\n description?: string;\n checked?: boolean;\n children?: ListItem[];\n}\n\n/**\n * List of items with multiple style variants including bullet, numbered, checklist, and descriptive.\n * Props - `items` | `variant` | `gap` | `style` | `_level` | `noWrap`\n * @see {@link PdfListProps}\n */\nexport interface PdfListProps {\n items: ListItem[];\n /**\n * @default 'bullet'\n */\n variant?: ListVariant;\n /**\n * @default 'sm'\n */\n gap?: 'xs' | 'sm' | 'md';\n style?: Style;\n _level?: number;\n /**\n * @default false\n */\n noWrap?: boolean;\n}\n", + "type": "registry:component" + } + ], + "dependencies": [ + "@react-pdf/renderer" + ], + "registryDependencies": [ + "theme" + ] +} diff --git a/apps/www/src/registry/components/list/list.test.tsx b/apps/www/src/registry/components/list/list.test.tsx index 71006c76..86b43969 100644 --- a/apps/www/src/registry/components/list/list.test.tsx +++ b/apps/www/src/registry/components/list/list.test.tsx @@ -10,4 +10,27 @@ describe('PdfList', () => { PdfList({ items: [{ text: 'First' }, { text: 'Second' }], variant: 'numbered' }) ).not.toThrow(); }); + it('renders bullet variant with long wrapping text without throwing', () => { + const longText = + 'This is a very long bullet item that is designed to wrap across multiple lines in the rendered PDF document to ensure row heights are measured correctly and no vertical overlap occurs between consecutive bullet items.'; + expect(() => + PdfList({ + items: [{ text: longText }, { text: longText }, { text: longText }], + variant: 'bullet', + }) + ).not.toThrow(); + }); + it('renders bullet variant with nested children without throwing', () => { + expect(() => + PdfList({ + items: [ + { + text: 'Parent item with children', + children: [{ text: 'Child item one' }, { text: 'Child item two' }], + }, + ], + variant: 'bullet', + }) + ).not.toThrow(); + }); }); diff --git a/apps/www/src/registry/components/list/list.tsx b/apps/www/src/registry/components/list/list.tsx index 2a2cef3f..90d8225f 100644 --- a/apps/www/src/registry/components/list/list.tsx +++ b/apps/www/src/registry/components/list/list.tsx @@ -51,9 +51,7 @@ function renderBulletItem( {dotMarker(level, styles)} - - {item.text} - + {item.text} {item.children && item.children.length > 0 ? renderItemList(item.children, 'bullet', gap, styles, level + 1)