diff --git a/package-lock.json b/package-lock.json
index 9db5b061..a36690c0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@aboutbits/react-ui",
- "version": "2.6.6",
+ "version": "2.6.8",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@aboutbits/react-ui",
- "version": "2.6.6",
+ "version": "2.6.8",
"dependencies": {
"@aboutbits/pagination": "^2.0.0",
"@aboutbits/react-material-icons": "^1.1.2",
diff --git a/package.json b/package.json
index a297f66f..2d2cf6bc 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@aboutbits/react-ui",
- "version": "2.6.6",
+ "version": "2.6.8",
"types": "./dist/types/index.d.ts",
"module": "./dist/esm/index.js",
"main": "./dist/cjs/index.js",
diff --git a/src/components/content/WithPlaceholder/WithPlacehoder.stories.tsx b/src/components/content/WithPlaceholder/WithPlacehoder.stories.tsx
new file mode 100644
index 00000000..eb1147c4
--- /dev/null
+++ b/src/components/content/WithPlaceholder/WithPlacehoder.stories.tsx
@@ -0,0 +1,52 @@
+import {
+ Controls,
+ Description,
+ Primary,
+ Stories,
+ Subheading,
+ Title,
+} from '@storybook/blocks'
+import { Meta, StoryObj } from '@storybook/react'
+import { WithPlaceholder } from './WithPlaceholder'
+
+const children = {
+ options: ['Null', 'Undefined', 'Empty text', 'ReactNode'],
+ mapping: {
+ Null: null,
+ Undefined: undefined,
+ 'Empty text': '',
+ ReactNode: 'John Doe',
+ },
+ control: { type: 'select' },
+}
+
+const meta = {
+ title: 'Components/Content/WithPlaceHolder',
+ component: WithPlaceholder,
+ args: {
+ placeholder: '-',
+ children: 'John Doe',
+ },
+ argTypes: {
+ children,
+ },
+ parameters: {
+ docs: {
+ page: () => (
+ <>
+
+
+
+ Props
+
+
+ >
+ ),
+ },
+ },
+} satisfies Meta
+export default meta
+
+type Story = StoryObj
+
+export const Default: Story = {}
diff --git a/src/components/content/WithPlaceholder/WithPlaceholder.tsx b/src/components/content/WithPlaceholder/WithPlaceholder.tsx
new file mode 100644
index 00000000..8dd068f3
--- /dev/null
+++ b/src/components/content/WithPlaceholder/WithPlaceholder.tsx
@@ -0,0 +1,26 @@
+import { PropsWithChildren, ReactNode } from 'react'
+
+export type WithPlaceholderProps = PropsWithChildren<{
+ /**
+ * Defines the placeholder to be rendered if the children is not valid.
+ */
+ placeholder?: ReactNode
+}>
+
+/**
+ * This component validates the content and displays a placeholder if the content is empty, null or undefined.
+ */
+export function WithPlaceholder({
+ placeholder = '-',
+ children,
+}: WithPlaceholderProps) {
+ return (
+ <>
+ {typeof children === 'number'
+ ? isNaN(children)
+ ? placeholder
+ : children
+ : children || placeholder}
+ >
+ )
+}
diff --git a/src/components/content/index.ts b/src/components/content/index.ts
index 617ae4a0..959a5cb9 100644
--- a/src/components/content/index.ts
+++ b/src/components/content/index.ts
@@ -11,3 +11,4 @@ export * from './DescriptionItem/DescriptionItemTitle'
export * from './DescriptionItem/DescriptionItemContent'
export * from './DescriptionItem/LoadingDescriptionItem'
export * from './DescriptionItem/types'
+export * from './WithPlaceholder/WithPlaceholder'
diff --git a/src/components/section/SectionItem/SectionListItem.tsx b/src/components/section/SectionItem/SectionListItem.tsx
index 50bd72c1..96d7dcde 100644
--- a/src/components/section/SectionItem/SectionListItem.tsx
+++ b/src/components/section/SectionItem/SectionListItem.tsx
@@ -22,19 +22,32 @@ export function SectionListItem({ className, children }: SectionListItemProps) {
)
}
+function SectionListItemIcon() {
+ const { section } = useTheme()
+
+ return (
+
+ )
+}
+
export type SectionListItemButtonProps = ClassNameProps & {
/**
* On click handler for the button.
*/
onClick: () => void
children?: ReactNode
+ withIcon?: boolean
}
export const SectionListItemButton = forwardRef<
HTMLButtonElement,
SectionListItemButtonProps
>(function SectionListItemButton(
- { children, onClick, className, ...props },
+ { children, onClick, className, withIcon = true, ...props },
ref,
) {
const { section } = useTheme()
@@ -43,30 +56,28 @@ export const SectionListItemButton = forwardRef<
)
})
-export type SectionListItemLinkProps = LinkComponentProps
+export type SectionListItemLinkProps = LinkComponentProps & {
+ withIcon?: boolean
+}
export const SectionListItemLink = forwardRef<
HTMLAnchorElement,
SectionListItemLinkProps
>(function SectionListItemLink(
- { children, className, internal = true, ...props },
+ { children, className, internal = true, withIcon = true, ...props },
ref,
) {
const LinkComponent = useLinkComponent()
@@ -75,8 +86,8 @@ export const SectionListItemLink = forwardRef<
return (
{children}
-
+ {withIcon && }
)
})
diff --git a/src/components/section/theme.ts b/src/components/section/theme.ts
index 464e1325..4c8c187a 100644
--- a/src/components/section/theme.ts
+++ b/src/components/section/theme.ts
@@ -30,7 +30,7 @@ export default {
base: 'grid xl:grid-cols-2 xl:gap-x-11 gap-y-6 px-4 md:px-6 pt-4 md:pt-6 pb-8 md:pb-9',
},
listItem: {
- base: 'flex border-b border-neutral-200 last:border-0 items-center min-h-[3.5rem] bg-white px-4 md:px-6',
+ base: 'flex border-b border-neutral-200 last:border-0 items-center py-4 bg-white px-4 md:px-6',
},
listItemWithAction: {
base: 'justify-between space-x-4',
@@ -38,13 +38,10 @@ export default {
base: 'flex flex-shrink-0',
},
},
- listItemButton: {
+ listItemButtonLink: {
base: 'block w-full focus:outline-neutral-800 justify-between space-x-4 hover:bg-neutral-100 active:bg-neutral-100',
icon: 'fill-current',
},
- listItemLink: {
- base: 'block focus:outline-neutral-800 justify-between space-x-4 hover:bg-neutral-100 active:bg-neutral-100',
- },
subsectionTitle: {
base: 'bg-neutral-100 px-4 md:px-6 py-1 border-b border-t first:border-t-none border-neutral-200 text-sm text-neutral-600',
},
diff --git a/src/examples/List.stories.tsx b/src/examples/List.stories.tsx
index decaaab7..1a7597ff 100644
--- a/src/examples/List.stories.tsx
+++ b/src/examples/List.stories.tsx
@@ -29,6 +29,8 @@ import {
Option,
useFilter,
SearchField,
+ SectionListItemButtonProps,
+ SectionListItemLink,
} from '../components'
const meta = {
@@ -66,7 +68,13 @@ function useMockedList(numberOfTotalItems: number) {
)
}
-const List = ({ numberOfTotalItems = 5 }: { numberOfTotalItems?: number }) => {
+const List = ({
+ numberOfTotalItems = 5,
+ withIcon,
+}: { numberOfTotalItems?: number } & Pick<
+ SectionListItemButtonProps,
+ 'withIcon'
+>) => {
const content = useMockedList(numberOfTotalItems)
return (
@@ -79,14 +87,25 @@ const List = ({ numberOfTotalItems = 5 }: { numberOfTotalItems?: number }) => {
/>
) : (
- {content.map((item) => (
-
- {`${item.name} (${item.role} - ${item.department})`}
-
- ))}
+ {content.map((item, index) =>
+ index % 2 === 0 ? (
+
+ {`Button ${item.name} (${item.role} - ${item.department})`}
+
+ ) : (
+
+ {`Link ${item.name} (${item.role} - ${item.department})`}
+
+ ),
+ )}
)}
@@ -98,6 +117,8 @@ export const SimpleList: Story = () =>
export const EmptySimpleList: Story = () =>
+export const ListWithoutIcon: Story = () =>
+
/**
* The following example shows how multiple section components and the in memory pagination are used to create an overview list with filters.
*/