Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions .storybook/main.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import { mergeConfig } from 'vite'
import { dirname } from 'node:path'
import { fileURLToPath } from 'node:url'

import type { StorybookConfig } from '@storybook/react-vite'
import { type ParserOptions } from 'react-docgen-typescript'
import remarkGfm from 'remark-gfm'
import { mergeConfig } from 'vite'

type ExtendedStorybookConfig = StorybookConfig & {
chromatic?: {
disableSnapshot?: boolean
}
}

const docgenConfig: ParserOptions = {
shouldExtractLiteralValuesFromEnum: true,
Expand Down Expand Up @@ -40,7 +49,7 @@ const docgenConfig: ParserOptions = {
* StorybookConfig:
* https://storybook.js.org/docs/api/main-config/main-config
*/
const config: StorybookConfig = {
const config: ExtendedStorybookConfig = {
framework: {
name: '@storybook/react-vite',
options: {},
Expand Down Expand Up @@ -79,7 +88,7 @@ const config: StorybookConfig = {
test: false, // We are not yet using vitest for integrated tests in the storybook UI.
},
},
}
},
],
core: {
disableTelemetry: true,
Expand Down
1,560 changes: 1,210 additions & 350 deletions package-lock.json

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@
"@nx/js": "21.5.3",
"@playwright/test": "1.55.1",
"@spark-ui/cli-utils": "^17.5.3",
"@storybook/addon-a11y": "10.3.5",
"@storybook/addon-a11y": "10.4.0",
"@storybook/addon-designs": "11.1.3",
"@storybook/addon-docs": "10.3.5",
"@storybook/addon-mcp": "^0.5.0",
"@storybook/react-vite": "10.3.5",
"@storybook/addon-docs": "10.4.0",
"@storybook/addon-mcp": "^0.6.0",
"@storybook/react-vite": "10.4.0",
"@tailwindcss/postcss": "4.1.18",
"@testing-library/dom": "10.4.1",
"@testing-library/jest-dom": "6.9.1",
Expand Down Expand Up @@ -108,7 +108,7 @@
"resize-observer-polyfill": "1.5.1",
"rollup": "4.59.0",
"scroll-into-view-if-needed": "3.1.0",
"storybook": "10.3.5",
"storybook": "10.4.0",
"tailwindcss": "4.1.18",
"ts-node": "10.9.2",
"type-fest": "5.1.0",
Expand Down
7 changes: 7 additions & 0 deletions packages/components/src/accordion/Accordion.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,17 @@ import { useState } from 'react'
import { Accordion } from '.'
import { Checkbox, CheckboxGroup } from '../checkbox'
import { Tag } from '../tag'
import { Item as AccordionItem } from './AccordionItem'

const meta: Meta<typeof Accordion> = {
title: 'Components/Accordion',
component: Accordion,
subcomponents: {
'Accordion.Item': AccordionItem,
'Accordion.ItemHeader': Accordion.ItemHeader,
'Accordion.ItemTrigger': Accordion.ItemTrigger,
'Accordion.ItemContent': Accordion.ItemContent,
},
tags: ['data-display'],
parameters: {
design: {
Expand Down
3 changes: 3 additions & 0 deletions packages/components/src/accordion/AccordionItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ export interface AccordionItemProps extends ExtentedZagInterface {
ref?: Ref<HTMLDivElement>
}

/**
* Groups an accordion header with the corresponding panel. Renders a <div> element.
*/
export const Item = ({
asChild = false,
className,
Expand Down
24 changes: 24 additions & 0 deletions packages/components/src/alert-dialog/AlertDialog.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,34 @@ import { useRef, useState } from 'react'
import { AlertDialog } from '.'
import { Button } from '../button'
import { Input } from '../input'
import { AlertDialogAction } from './AlertDialogAction'
import { AlertDialogBody } from './AlertDialogBody'
import { AlertDialogCancel } from './AlertDialogCancel'
import { AlertDialogContent } from './AlertDialogContent'
import { AlertDialogDescription } from './AlertDialogDescription'
import { AlertDialogFooter } from './AlertDialogFooter'
import { AlertDialogHeader } from './AlertDialogHeader'
import { AlertDialogOverlay } from './AlertDialogOverlay'
import { AlertDialogPortal } from './AlertDialogPortal'
import { AlertDialogTitle } from './AlertDialogTitle'
import { AlertDialogTrigger } from './AlertDialogTrigger'

const meta: Meta<typeof AlertDialog> = {
title: 'Components/AlertDialog',
component: AlertDialog,
subcomponents: {
'AlertDialog.Action': AlertDialogAction,
'AlertDialog.Body': AlertDialogBody,
'AlertDialog.Cancel': AlertDialogCancel,
'AlertDialog.Content': AlertDialogContent,
'AlertDialog.Description': AlertDialogDescription,
'AlertDialog.Footer': AlertDialogFooter,
'AlertDialog.Header': AlertDialogHeader,
'AlertDialog.Overlay': AlertDialogOverlay,
'AlertDialog.Portal': AlertDialogPortal,
'AlertDialog.Title': AlertDialogTitle,
'AlertDialog.Trigger': AlertDialogTrigger,
},
tags: ['overlays'],
parameters: {
design: {
Expand Down
3 changes: 3 additions & 0 deletions packages/components/src/alert-dialog/AlertDialogAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ export interface AlertDialogActionProps extends Omit<
ref?: Ref<HTMLButtonElement>
}

/**
* A button that closes the dialog and confirms the action. Renders a <button> element.
*/
export const AlertDialogAction = ({ asChild = false, ...props }: AlertDialogActionProps) => {
const renderSlot = useRenderSlot(asChild, 'button')

Expand Down
3 changes: 3 additions & 0 deletions packages/components/src/alert-dialog/AlertDialogBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ export interface AlertDialogBodyProps {
inset?: boolean
}

/**
* The scrollable body section of the alert dialog. Renders a <div> element.
*/
export const AlertDialogBody = ({
children,
className,
Expand Down
3 changes: 3 additions & 0 deletions packages/components/src/alert-dialog/AlertDialogCancel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ export interface AlertDialogCancelProps extends Omit<
ref?: Ref<HTMLButtonElement>
}

/**
* A button that closes the dialog without confirming the action. Renders a <button> element.
*/
export const AlertDialogCancel = ({
asChild = false,
ref: forwardedRef,
Expand Down
3 changes: 3 additions & 0 deletions packages/components/src/alert-dialog/AlertDialogContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ export interface AlertDialogContentProps extends Omit<
ref?: Ref<HTMLDivElement>
}

/**
* The popup element that contains the alert dialog content. Renders a <div> element.
*/
export const AlertDialogContent = ({
className,
ref,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ export interface AlertDialogDescriptionProps extends Omit<
ref?: Ref<HTMLParagraphElement>
}

/**
* A paragraph with additional information about the dialog. Renders a <p> element.
*/
export const AlertDialogDescription = (props: AlertDialogDescriptionProps) => {
return <BaseAlertDialog.Description data-spark-component="alert-dialog-description" {...props} />
}
Expand Down
3 changes: 3 additions & 0 deletions packages/components/src/alert-dialog/AlertDialogFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export interface AlertDialogFooterProps {
ref?: Ref<HTMLDivElement>
}

/**
* The footer section of the alert dialog, typically containing action buttons. Renders a <footer> element.
*/
export const AlertDialogFooter = ({
children,
className,
Expand Down
3 changes: 3 additions & 0 deletions packages/components/src/alert-dialog/AlertDialogHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export interface AlertDialogHeaderProps {
ref?: Ref<HTMLDivElement>
}

/**
* The header section of the alert dialog. Renders a <header> element.
*/
export const AlertDialogHeader = ({
children,
className,
Expand Down
3 changes: 3 additions & 0 deletions packages/components/src/alert-dialog/AlertDialogOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ export interface AlertDialogOverlayProps extends Omit<
ref?: Ref<HTMLDivElement>
}

/**
* The backdrop element that dims the rest of the page. Renders a <div> element.
*/
export const AlertDialogOverlay = ({ className, ...props }: AlertDialogOverlayProps) => {
return (
<BaseAlertDialog.Backdrop
Expand Down
3 changes: 3 additions & 0 deletions packages/components/src/alert-dialog/AlertDialogPortal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { ComponentProps } from 'react'

export type AlertDialogPortalProps = ComponentProps<typeof BaseAlertDialog.Portal>

/**
* A portal that renders the dialog in a different part of the DOM. Renders a <div> element.
*/
export const AlertDialogPortal = ({ className, ...props }: AlertDialogPortalProps) => {
return (
<BaseAlertDialog.Portal
Expand Down
3 changes: 3 additions & 0 deletions packages/components/src/alert-dialog/AlertDialogTitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ export interface AlertDialogTitleProps extends Omit<
ref?: Ref<HTMLHeadingElement>
}

/**
* The title of the alert dialog, announced to assistive technology. Renders an <h2> element.
*/
export const AlertDialogTitle = ({ className, ...props }: AlertDialogTitleProps) => {
return (
<BaseAlertDialog.Title
Expand Down
3 changes: 3 additions & 0 deletions packages/components/src/alert-dialog/AlertDialogTrigger.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ export interface AlertDialogTriggerProps extends Omit<
ref?: Ref<HTMLButtonElement>
}

/**
* A button that opens the alert dialog. Renders a <button> element.
*/
export const AlertDialogTrigger = ({ asChild = false, ...props }: AlertDialogTriggerProps) => {
const renderSlot = useRenderSlot(asChild, 'button')

Expand Down
3 changes: 3 additions & 0 deletions packages/components/src/avatar/AvatarAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ export interface AvatarActionProps extends React.ButtonHTMLAttributes<HTMLButton
ariaLabel: string
}

/**
* An action button positioned on the avatar, typically for editing. Renders a <button> element.
*/
export const AvatarAction = ({
className,
children,
Expand Down
3 changes: 3 additions & 0 deletions packages/components/src/avatar/AvatarImage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ export interface AvatarImageProps extends React.ImgHTMLAttributes<HTMLImageEleme
asChild?: boolean
}

/**
* The avatar's image content. Renders an <img> element.
*/
export const AvatarImage = ({
className,
asChild,
Expand Down
3 changes: 3 additions & 0 deletions packages/components/src/avatar/AvatarOnlineBadge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ interface AvatarOnlineBadgeProps extends ComponentPropsWithoutRef<'div'> {
angle?: number
}

/**
* A badge indicator showing the user's online status. Renders a <div> element.
*/
export const AvatarOnlineBadge = ({ angle = 135, ...props }: AvatarOnlineBadgeProps) => {
const { isOnline, pixelSize, shape, onlineText, size } = useAvatarContext()

Expand Down
3 changes: 3 additions & 0 deletions packages/components/src/avatar/AvatarPlaceholder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export interface AvatarPlaceholderProps extends React.ImgHTMLAttributes<HTMLDivE
children?: React.ReactNode
}

/**
* A placeholder shown when no image is available, typically displaying the user's initial. Renders a <div> element.
*/
export const AvatarPlaceholder = ({ className, children, ...props }: AvatarPlaceholderProps) => {
const { size, username } = useAvatarContext()

Expand Down
3 changes: 3 additions & 0 deletions packages/components/src/avatar/AvatarUser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export interface AvatarImageProps extends React.ImgHTMLAttributes<HTMLDivElement
asChild?: boolean
}

/**
* The user container that wraps avatar content. Renders a <div> element.
*/
export const AvatarUser = ({ asChild, children, className, ...props }: AvatarImageProps) => {
const { shape, isOnline, onlineText, username } = useAvatarContext()
const Comp = asChild ? Slot : 'div'
Expand Down
12 changes: 12 additions & 0 deletions packages/components/src/avatar/avatar.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,22 @@ import { Avatar } from '.'
import { Button } from '../button'
import { Icon } from '../icon'
import avatarImg from './avatar.png'
import { AvatarAction } from './AvatarAction'
import { AvatarImage } from './AvatarImage'
import { AvatarOnlineBadge } from './AvatarOnlineBadge'
import { AvatarPlaceholder } from './AvatarPlaceholder'
import { AvatarUser } from './AvatarUser'

const meta: Meta<typeof Avatar> = {
title: 'Components/Avatar',
component: Avatar,
subcomponents: {
'Avatar.Image': AvatarImage,
'Avatar.Action': AvatarAction,
'Avatar.OnlineBadge': AvatarOnlineBadge,
'Avatar.User': AvatarUser,
'Avatar.Placeholder': AvatarPlaceholder,
},
tags: ['data-display'],
}

Expand Down
10 changes: 10 additions & 0 deletions packages/components/src/breadcrumb/Breadcrumb.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,20 @@ import { Meta, StoryFn } from '@storybook/react-vite'

import { Breadcrumb } from '.'
import { Icon } from '../icon'
import { CurrentPage } from './BreadcrumbCurrentPage'
import { Item } from './BreadcrumbItem'
import { Link } from './BreadcrumbLink'
import { Separator } from './BreadcrumbSeparator'

const meta: Meta<typeof Breadcrumb> = {
title: 'Components/Breadcrumb',
component: Breadcrumb,
subcomponents: {
'Breadcrumb.Item': Item,
'Breadcrumb.Link': Link,
'Breadcrumb.CurrentPage': CurrentPage,
'Breadcrumb.Separator': Separator,
},
tags: ['navigation'],
parameters: {
design: {
Expand Down
3 changes: 3 additions & 0 deletions packages/components/src/breadcrumb/BreadcrumbCurrentPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ export interface CurrentPageProps extends ComponentPropsWithoutRef<typeof TextLi
ref?: Ref<HTMLAnchorElement>
}

/**
* Indicates the current page in the breadcrumb trail. Renders a <span> element.
*/
export const CurrentPage = ({
asChild = false,
className,
Expand Down
3 changes: 3 additions & 0 deletions packages/components/src/breadcrumb/BreadcrumbItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ export interface ItemProps extends ComponentPropsWithoutRef<'li'> {
ref?: Ref<HTMLLIElement>
}

/**
* A breadcrumb item container. Renders a <li> element.
*/
export const Item = ({ className, ...rest }: ItemProps) => {
return (
<li
Expand Down
3 changes: 3 additions & 0 deletions packages/components/src/breadcrumb/BreadcrumbLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ export interface LinkProps extends ComponentPropsWithoutRef<typeof TextLink> {
ref?: Ref<HTMLAnchorElement>
}

/**
* A navigable breadcrumb link. Renders an <a> element.
*/
export const Link = ({
asChild = false,
className,
Expand Down
3 changes: 3 additions & 0 deletions packages/components/src/breadcrumb/BreadcrumbSeparator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ export interface SeparatorProps extends ComponentPropsWithoutRef<'li'> {
ref?: Ref<HTMLLIElement>
}

/**
* A visual separator between breadcrumb items. Renders a <li> element.
*/
export const Separator = ({
asChild = false,
className,
Expand Down
Loading
Loading