From 234a233d80846ef77e19fa45e092c248468c651a Mon Sep 17 00:00:00 2001 From: Shreyag02 Date: Mon, 12 Oct 2026 00:31:25 +0530 Subject: [PATCH 1/4] feat: export the props type of every component --- .agents/skills/add-new-component/SKILL.md | 15 +- AGENTS.md | 2 +- .../docs/(overview)/getting-started.mdx | 14 + packages/react/components/accordion/index.tsx | 1 + .../react/components/alert-dialog/index.ts | 1 + .../announcement-bar/announcement-bar.tsx | 2 +- .../components/announcement-bar/index.tsx | 2 +- packages/react/components/avatar/index.tsx | 7 +- packages/react/components/badge/badge.tsx | 2 +- packages/react/components/badge/index.tsx | 2 +- .../react/components/breadcrumb/index.tsx | 6 + packages/react/components/button/button.tsx | 2 +- packages/react/components/button/index.tsx | 2 +- packages/react/components/calendar/index.tsx | 6 +- .../components/calendar/range-picker.tsx | 4 +- packages/react/components/callout/index.tsx | 2 +- .../react/components/chat-panel/index.tsx | 7 +- packages/react/components/chat/index.tsx | 12 +- .../react/components/checkbox/checkbox.tsx | 4 +- packages/react/components/checkbox/index.tsx | 6 +- .../code-block/code-block-language-select.tsx | 6 +- .../react/components/code-block/index.tsx | 7 + .../react/components/color-picker/index.ts | 6 + packages/react/components/combobox/index.ts | 4 + .../components/command/command-content.tsx | 6 +- .../components/command/command-empty.tsx | 2 +- packages/react/components/command/index.tsx | 11 + .../react/components/container/container.tsx | 2 +- packages/react/components/container/index.tsx | 2 +- .../react/components/context-menu/index.ts | 14 + .../react/components/copy-button/index.tsx | 2 +- .../components/display-settings.tsx | 4 +- .../data-table/components/filters.tsx | 14 +- .../data-table/components/toolbar.tsx | 6 +- .../components/virtualized-content.tsx | 6 +- .../components/data-table/data-table.tsx | 2 +- .../data-table/data-table.types.tsx | 3 +- packages/react/components/data-table/index.ts | 8 +- .../data-view/components/display-controls.tsx | 4 +- .../data-view/components/toolbar.tsx | 10 +- .../react/components/data-view/data-view.tsx | 2 +- .../components/data-view/data-view.types.tsx | 1 + packages/react/components/data-view/index.ts | 3 +- packages/react/components/dialog/index.ts | 1 + .../components/drawer/drawer-content.tsx | 7 +- packages/react/components/drawer/index.tsx | 2 + .../components/empty-state/empty-state.tsx | 2 +- .../react/components/empty-state/index.tsx | 2 +- packages/react/components/flex/flex.tsx | 5 +- packages/react/components/flex/index.tsx | 2 +- packages/react/components/grid/grid-item.tsx | 2 +- packages/react/components/grid/grid.tsx | 2 +- packages/react/components/grid/index.ts | 2 + packages/react/components/headline/index.tsx | 1 + .../react/components/icon-button/index.tsx | 2 +- packages/react/components/image/image.tsx | 4 +- packages/react/components/image/index.tsx | 2 +- packages/react/components/indicator/index.tsx | 2 +- packages/react/components/input/index.tsx | 2 +- packages/react/components/link/index.tsx | 2 +- packages/react/components/list/index.tsx | 9 +- packages/react/components/list/list.tsx | 10 +- packages/react/components/menu/index.ts | 5 + packages/react/components/menu/menu-misc.tsx | 6 +- packages/react/components/message/index.tsx | 12 +- packages/react/components/meter/index.tsx | 1 + packages/react/components/navbar/index.tsx | 6 + packages/react/components/otp-field/index.tsx | 7 +- packages/react/components/popover/index.tsx | 2 +- .../react/components/preview-card/index.tsx | 2 +- packages/react/components/progress/index.tsx | 1 + .../react/components/prompt-input/index.tsx | 5 + packages/react/components/radio/index.ts | 6 +- packages/react/components/radio/radio.tsx | 4 +- packages/react/components/reasoning/index.tsx | 4 +- packages/react/components/search/index.ts | 2 +- packages/react/components/select/index.ts | 10 + .../react/components/select/select-value.tsx | 2 +- packages/react/components/separator/index.tsx | 2 +- .../react/components/separator/separator.tsx | 2 +- .../react/components/side-panel/index.tsx | 7 +- .../components/side-panel/side-panel.tsx | 6 +- packages/react/components/sidebar/index.tsx | 9 +- .../components/sidebar/sidebar-group.tsx | 4 +- packages/react/components/skeleton/index.ts | 6 +- .../react/components/skeleton/skeleton.tsx | 2 +- packages/react/components/slider/index.tsx | 2 +- packages/react/components/spinner/index.tsx | 2 +- packages/react/components/switch/index.ts | 2 +- packages/react/components/table/index.ts | 10 +- packages/react/components/table/table.tsx | 50 ++- packages/react/components/tabs/index.tsx | 6 +- packages/react/components/tabs/tabs.tsx | 5 +- packages/react/components/text-area/index.tsx | 2 +- packages/react/components/text/index.tsx | 1 + packages/react/components/toast/index.ts | 2 +- packages/react/components/toggle/index.ts | 2 +- packages/react/components/tooltip/index.tsx | 1 + packages/react/components/tour/index.tsx | 2 +- packages/react/index.tsx | 312 ++++++++++++++---- 100 files changed, 597 insertions(+), 200 deletions(-) diff --git a/.agents/skills/add-new-component/SKILL.md b/.agents/skills/add-new-component/SKILL.md index 0d26750bf..a754675f6 100644 --- a/.agents/skills/add-new-component/SKILL.md +++ b/.agents/skills/add-new-component/SKILL.md @@ -177,11 +177,13 @@ Key rules: ## Step 2: Create the Index File -Simple re-export: +Re-export the component and its props types: ```tsx // packages/react/components//index.tsx export { Component } from './'; +export type { ComponentContentProps } from './-content'; +export type { ComponentRootProps as ComponentProps } from './-root'; ``` ## Step 3: Add CSS Module Styles @@ -239,10 +241,12 @@ Common `--rs-*` tokens: Add to `packages/react/index.tsx` in **alphabetical order**: ```tsx -export { Chip } from './components/chip'; -export { CodeBlock } from './components/code-block'; -export { Collapsible } from './components/collapsible'; // <-- new -export { Combobox } from './components/combobox'; +export { Chip, type ChipProps } from './components/chip'; +export { + Component, + type ComponentContentProps, + type ComponentProps +} from './components/'; // <-- new ``` ## Step 5: Write Tests @@ -506,4 +510,5 @@ Checklist: - [ ] Every rendered element has a `data-slot`, with a `data-slots.test.tsx` covering them - [ ] CSS uses `--rs-*` tokens only - [ ] Export in `packages/react/index.tsx` in alphabetical order +- [ ] Props types exported from the component index and `packages/react/index.tsx` (`__tests__/exports.test.ts` passes) - [ ] Interactive `playground` added to `demo.ts`, covering the component's main props diff --git a/AGENTS.md b/AGENTS.md index da467e173..abf89a7b7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -21,7 +21,7 @@ Skills are in `.agents/skills/`. `.claude/skills` is a symlink to that folder, s ## Code - Each component is in `packages/react/components//`. Its `index.tsx` only re-exports. -- Export new components from `packages/react/index.tsx`, in alphabetical order. +- Export new components from `packages/react/index.tsx`, in alphabetical order, with their props types: `Props` for the root part and `Props` for each part with its own type. `__tests__/exports.test.ts` checks this. - Wrap Base UI primitives, for example `import { Tabs as TabsPrimitive } from '@base-ui/react'`. Do not rebuild behavior that Base UI already has. - For plain elements, use `useRender` and `mergeProps` so the `render` prop works. - Pass `ref` as a normal prop (React 19). Do not use `forwardRef`. diff --git a/apps/www/src/content/docs/(overview)/getting-started.mdx b/apps/www/src/content/docs/(overview)/getting-started.mdx index 04b318c80..706be908d 100644 --- a/apps/www/src/content/docs/(overview)/getting-started.mdx +++ b/apps/www/src/content/docs/(overview)/getting-started.mdx @@ -189,6 +189,20 @@ function ThemeToggle() { } ``` +## Importing prop types + +Components export their props types from the main entry, for example `ButtonProps`, `TabsProps` and `TabsTabProps`: + +```tsx +import { Button, type ButtonProps } from "@raystack/apsara"; + +function SaveButton({ saving, ...props }: ButtonProps & { saving: boolean }) { + return ), classNames -}: DisplaySettingsProps) { +}: DataTableDisplayControlsProps) { const { table, updateTableQuery, diff --git a/packages/react/components/data-table/components/filters.tsx b/packages/react/components/data-table/components/filters.tsx index cc319ea2e..b120f22df 100644 --- a/packages/react/components/data-table/components/filters.tsx +++ b/packages/react/components/data-table/components/filters.tsx @@ -88,18 +88,20 @@ function AddFilter({ ) : null; } -export function Filters({ - classNames, - className, - trigger -}: { +export interface DataTableFiltersProps { classNames?: { filterChips?: string; addFilter?: string; }; className?: string; trigger?: Trigger; -}) { +} + +export function Filters({ + classNames, + className, + trigger +}: DataTableFiltersProps) { const { table, tableQuery } = useDataTable(); const columns = table?.getAllColumns() as DataTableColumn[]; diff --git a/packages/react/components/data-table/components/toolbar.tsx b/packages/react/components/data-table/components/toolbar.tsx index 40a3bdbbe..792c5f77d 100644 --- a/packages/react/components/data-table/components/toolbar.tsx +++ b/packages/react/components/data-table/components/toolbar.tsx @@ -7,7 +7,11 @@ import { useDataTable } from '../hooks/useDataTable'; import { DisplaySettings } from './display-settings'; import { Filters } from './filters'; -export function Toolbar({ className }: { className?: string }) { +export interface DataTableToolbarProps { + className?: string; +} + +export function Toolbar({ className }: DataTableToolbarProps) { const { shouldShowFilters = false } = useDataTable(); if (!shouldShowFilters) { diff --git a/packages/react/components/data-table/components/virtualized-content.tsx b/packages/react/components/data-table/components/virtualized-content.tsx index 5238fcc13..5a5ef8913 100644 --- a/packages/react/components/data-table/components/virtualized-content.tsx +++ b/packages/react/components/data-table/components/virtualized-content.tsx @@ -14,9 +14,9 @@ import { Skeleton } from '../../skeleton'; import styles from '../data-table.module.css'; import { DataTableColumnDef, + DataTableVirtualizedContentProps, defaultGroupOption, - GroupedData, - VirtualizedContentProps + GroupedData } from '../data-table.types'; import { useDataTable } from '../hooks/useDataTable'; import { useStickyGroupAnchor } from '../hooks/useStickyGroupAnchor'; @@ -220,7 +220,7 @@ export function VirtualizedContent({ emptyState, zeroState, classNames = {} -}: VirtualizedContentProps) { +}: DataTableVirtualizedContentProps) { const { onRowClick, table, diff --git a/packages/react/components/data-table/data-table.tsx b/packages/react/components/data-table/data-table.tsx index 42369cc62..52cb44a10 100644 --- a/packages/react/components/data-table/data-table.tsx +++ b/packages/react/components/data-table/data-table.tsx @@ -51,7 +51,7 @@ function DataTableRoot({ onColumnVisibilityChange, stickyGroupHeader = false, getRowId -}: React.PropsWithChildren>) { +}: DataTableProps) { const defaultTableQuery = useMemo( () => getDefaultTableQuery(defaultSort, query), [defaultSort, query] diff --git a/packages/react/components/data-table/data-table.types.tsx b/packages/react/components/data-table/data-table.types.tsx index 83821f9cc..592e37971 100644 --- a/packages/react/components/data-table/data-table.types.tsx +++ b/packages/react/components/data-table/data-table.types.tsx @@ -120,6 +120,7 @@ export interface DataTableProps { stickyGroupHeader?: boolean; /** Return a stable unique id for each row (used as React key). Use for sortable/filterable tables. */ getRowId?: (row: TData, index: number) => string; + children?: React.ReactNode; } export type DataTableContentClassNames = { @@ -138,7 +139,7 @@ export type DataTableContentBaseProps = { export type DataTableContentProps = DataTableContentBaseProps; -export type VirtualizedContentProps = DataTableContentBaseProps & { +export type DataTableVirtualizedContentProps = DataTableContentBaseProps & { /** Height of each row in pixels. */ rowHeight?: number; /** Height of group header rows in pixels. Defaults to 40 (matches the non-virtualized section header height). */ diff --git a/packages/react/components/data-table/index.ts b/packages/react/components/data-table/index.ts index 6070e9bd1..275400b14 100644 --- a/packages/react/components/data-table/index.ts +++ b/packages/react/components/data-table/index.ts @@ -1,14 +1,18 @@ export { EmptyFilterValue } from '~/types/filters'; +export type { DataTableDisplayControlsProps } from './components/display-settings'; +export type { DataTableFiltersProps } from './components/filters'; export type { DataTableSearchProps } from './components/search'; +export type { DataTableToolbarProps } from './components/toolbar'; export { DataTable } from './data-table'; export { DataTableColumnDef, DataTableContentProps, DataTableFilter, + type DataTableProps, DataTableQuery, DataTableSort, + DataTableVirtualizedContentProps, InternalFilter, - InternalQuery, - VirtualizedContentProps + InternalQuery } from './data-table.types'; export { useDataTable } from './hooks/useDataTable'; diff --git a/packages/react/components/data-view/components/display-controls.tsx b/packages/react/components/data-view/components/display-controls.tsx index d90a670c8..41a8d9690 100644 --- a/packages/react/components/data-view/components/display-controls.tsx +++ b/packages/react/components/data-view/components/display-controls.tsx @@ -15,7 +15,7 @@ import { Grouping } from './grouping'; import { Ordering } from './ordering'; import { ViewSwitcher } from './view-switcher'; -interface DisplayControlsProps +export interface DataViewDisplayControlsProps extends Pick { trigger?: ReactNode; hideViewSwitcher?: boolean; @@ -49,7 +49,7 @@ export function DisplayControls({ hideDisplayProperties = false, align = 'end', ...positionerProps -}: DisplayControlsProps) { +}: DataViewDisplayControlsProps) { const { fields, updateTableQuery, diff --git a/packages/react/components/data-view/components/toolbar.tsx b/packages/react/components/data-view/components/toolbar.tsx index 96f3231ad..6184be86c 100644 --- a/packages/react/components/data-view/components/toolbar.tsx +++ b/packages/react/components/data-view/components/toolbar.tsx @@ -1,15 +1,16 @@ 'use client'; import { cx } from 'class-variance-authority'; -import { PropsWithChildren } from 'react'; +import { ReactNode } from 'react'; import { Flex } from '../../flex'; import styles from '../data-view.module.css'; import { useDataView } from '../hooks/useDataView'; import { DisplayControls } from './display-controls'; import { Filters } from './filters'; -interface ToolbarProps { +export interface DataViewToolbarProps { className?: string; + children?: ReactNode; } /** @@ -19,10 +20,7 @@ interface ToolbarProps { * custom actions); omitting children renders the default * ` + ` pair. */ -export function Toolbar({ - className, - children -}: PropsWithChildren) { +export function Toolbar({ className, children }: DataViewToolbarProps) { const { shouldShowFilters } = useDataView(); if (!shouldShowFilters) return null; diff --git a/packages/react/components/data-view/data-view.tsx b/packages/react/components/data-view/data-view.tsx index c2e419cbb..120b16080 100644 --- a/packages/react/components/data-view/data-view.tsx +++ b/packages/react/components/data-view/data-view.tsx @@ -67,7 +67,7 @@ function DataViewRoot({ view, onViewChange, groupByResolvers -}: React.PropsWithChildren>) { +}: DataViewProps) { const defaultTableQuery = useMemo( () => getDefaultTableQuery(defaultSort, query), [defaultSort, query] diff --git a/packages/react/components/data-view/data-view.types.tsx b/packages/react/components/data-view/data-view.types.tsx index d0d703e31..3d3308bf1 100644 --- a/packages/react/components/data-view/data-view.types.tsx +++ b/packages/react/components/data-view/data-view.types.tsx @@ -187,6 +187,7 @@ export interface DataViewProps { * to compute the bucket id per row when a key matches one in this map. */ groupByResolvers?: Record>; + children?: React.ReactNode; } /** @deprecated Every key here has an equivalent `[data-slot]` selector. See the List slot table in the DataView docs. Prefer styling by `data-slot` over threading class names through props. */ diff --git a/packages/react/components/data-view/index.ts b/packages/react/components/data-view/index.ts index 7481ea22b..5531872bf 100644 --- a/packages/react/components/data-view/index.ts +++ b/packages/react/components/data-view/index.ts @@ -3,11 +3,12 @@ export { EmptyFilterValue } from '~/types/filters'; export type { DataViewClearFiltersProps } from './components/clear-filters'; export type { DataViewCustomProps } from './components/custom'; export type { DataViewDisplayAccessProps } from './components/display-access'; +export type { DataViewDisplayControlsProps } from './components/display-controls'; export type { DataViewEmptyStateProps } from './components/empty-state'; export type { DataViewFiltersProps } from './components/filters'; export type { DataViewSearchProps } from './components/search'; +export type { DataViewToolbarProps } from './components/toolbar'; export type { DataViewZeroStateProps } from './components/zero-state'; - export { DataView } from './data-view'; export type { DataViewContextType, diff --git a/packages/react/components/dialog/index.ts b/packages/react/components/dialog/index.ts index 480740a46..e5d671ec2 100644 --- a/packages/react/components/dialog/index.ts +++ b/packages/react/components/dialog/index.ts @@ -1 +1,2 @@ export { Dialog } from './dialog'; +export type { DialogContentProps } from './dialog-content'; diff --git a/packages/react/components/drawer/drawer-content.tsx b/packages/react/components/drawer/drawer-content.tsx index e07342b7e..d596bfac0 100644 --- a/packages/react/components/drawer/drawer-content.tsx +++ b/packages/react/components/drawer/drawer-content.tsx @@ -32,6 +32,11 @@ export interface DrawerContentProps children?: ReactNode; /** Corner radius for this drawer only. Overrides the theme's `radius`. */ radius?: Radius; + /** + * Accessible label for the close button. + * @default 'Close' + */ + closeLabel?: string; } export function DrawerContent({ @@ -45,7 +50,7 @@ export function DrawerContent({ closeLabel = 'Close', radius, ...props -}: DrawerContentProps & { closeLabel?: string }) { +}: DrawerContentProps) { const resolvedAriaLabel = ariaLabel ?? (ariaLabelledBy ? undefined : 'Drawer'); const theme = useThemeInjection(); diff --git a/packages/react/components/drawer/index.tsx b/packages/react/components/drawer/index.tsx index 8827142e8..855852bb6 100644 --- a/packages/react/components/drawer/index.tsx +++ b/packages/react/components/drawer/index.tsx @@ -1 +1,3 @@ export { Drawer } from './drawer'; +export type { DrawerContentProps } from './drawer-content'; +export type { DrawerRootProps as DrawerProps } from './drawer-root'; diff --git a/packages/react/components/empty-state/empty-state.tsx b/packages/react/components/empty-state/empty-state.tsx index 14b05185c..faddad338 100644 --- a/packages/react/components/empty-state/empty-state.tsx +++ b/packages/react/components/empty-state/empty-state.tsx @@ -11,7 +11,7 @@ type classNameKeys = | 'heading' | 'subHeading'; -interface EmptyStateProps extends ComponentProps { +export interface EmptyStateProps extends ComponentProps { icon: ReactNode; heading?: ReactNode; subHeading?: ReactNode; diff --git a/packages/react/components/empty-state/index.tsx b/packages/react/components/empty-state/index.tsx index 6cc754ae0..ef799c543 100644 --- a/packages/react/components/empty-state/index.tsx +++ b/packages/react/components/empty-state/index.tsx @@ -1 +1 @@ -export { EmptyState } from './empty-state'; +export { EmptyState, type EmptyStateProps } from './empty-state'; diff --git a/packages/react/components/flex/flex.tsx b/packages/react/components/flex/flex.tsx index 4a9e79b83..e3ab53022 100644 --- a/packages/react/components/flex/flex.tsx +++ b/packages/react/components/flex/flex.tsx @@ -44,7 +44,8 @@ const flex = cva(styles.flex, { } }); -type BoxProps = VariantProps & useRender.ComponentProps<'div'>; +export type FlexProps = VariantProps & + useRender.ComponentProps<'div'>; export function Flex({ inline, @@ -57,7 +58,7 @@ export function Flex({ render, ref, ...props -}: BoxProps) { +}: FlexProps) { const flexProps = { 'data-slot': 'flex', className: flex({ diff --git a/packages/react/components/flex/index.tsx b/packages/react/components/flex/index.tsx index 7d7e52a50..f4adaa3ca 100644 --- a/packages/react/components/flex/index.tsx +++ b/packages/react/components/flex/index.tsx @@ -1 +1 @@ -export { Flex } from './flex'; +export { Flex, type FlexProps } from './flex'; diff --git a/packages/react/components/grid/grid-item.tsx b/packages/react/components/grid/grid-item.tsx index 923860b01..a4d93dbf2 100644 --- a/packages/react/components/grid/grid-item.tsx +++ b/packages/react/components/grid/grid-item.tsx @@ -2,7 +2,7 @@ import { mergeProps, useRender } from '@base-ui/react'; import { CSSProperties } from 'react'; import { AlignType } from './types'; -type GridItemProps = useRender.ComponentProps<'div'> & { +export type GridItemProps = useRender.ComponentProps<'div'> & { area?: string; colStart?: number | string; colEnd?: number | string; diff --git a/packages/react/components/grid/grid.tsx b/packages/react/components/grid/grid.tsx index 37a9eb617..ae178b8a6 100644 --- a/packages/react/components/grid/grid.tsx +++ b/packages/react/components/grid/grid.tsx @@ -17,7 +17,7 @@ const grid = cva(styles.grid, { } }); -type GridProps = useRender.ComponentProps<'div'> & +export type GridProps = useRender.ComponentProps<'div'> & VariantProps & { /** * Supports CSS Grid template areas syntax. diff --git a/packages/react/components/grid/index.ts b/packages/react/components/grid/index.ts index 265dfc40f..7d19a15b0 100644 --- a/packages/react/components/grid/index.ts +++ b/packages/react/components/grid/index.ts @@ -4,3 +4,5 @@ import { GridItem } from './grid-item'; export const Grid = Object.assign(GridPrimitive, { Item: GridItem }); +export type { GridProps } from './grid'; +export type { GridItemProps } from './grid-item'; diff --git a/packages/react/components/headline/index.tsx b/packages/react/components/headline/index.tsx index 1869c5dd4..5aad07dae 100644 --- a/packages/react/components/headline/index.tsx +++ b/packages/react/components/headline/index.tsx @@ -1 +1,2 @@ +export type { HeadlineProps } from './headline'; export * from './headline'; diff --git a/packages/react/components/icon-button/index.tsx b/packages/react/components/icon-button/index.tsx index 13aaf00af..52133029c 100644 --- a/packages/react/components/icon-button/index.tsx +++ b/packages/react/components/icon-button/index.tsx @@ -1 +1 @@ -export { IconButton } from './icon-button'; +export { IconButton, type IconButtonProps } from './icon-button'; diff --git a/packages/react/components/image/image.tsx b/packages/react/components/image/image.tsx index 6caa803bd..b205ea319 100644 --- a/packages/react/components/image/image.tsx +++ b/packages/react/components/image/image.tsx @@ -22,7 +22,9 @@ const image = cva(styles.image, { } }); -interface ImageProps extends ComponentProps<'img'>, VariantProps { +export interface ImageProps + extends ComponentProps<'img'>, + VariantProps { fallback?: string; } diff --git a/packages/react/components/image/index.tsx b/packages/react/components/image/index.tsx index c6fc1f1a5..816932890 100644 --- a/packages/react/components/image/index.tsx +++ b/packages/react/components/image/index.tsx @@ -1 +1 @@ -export { Image } from './image'; +export { Image, type ImageProps } from './image'; diff --git a/packages/react/components/indicator/index.tsx b/packages/react/components/indicator/index.tsx index e914a6cd2..d93375687 100644 --- a/packages/react/components/indicator/index.tsx +++ b/packages/react/components/indicator/index.tsx @@ -1 +1 @@ -export { Indicator } from './indicator'; +export { Indicator, type IndicatorProps } from './indicator'; diff --git a/packages/react/components/input/index.tsx b/packages/react/components/input/index.tsx index f376f8cdb..f47a3e090 100644 --- a/packages/react/components/input/index.tsx +++ b/packages/react/components/input/index.tsx @@ -1 +1 @@ -export { Input } from './input'; +export { Input, type InputProps } from './input'; diff --git a/packages/react/components/link/index.tsx b/packages/react/components/link/index.tsx index 63b88256e..f0f795b85 100644 --- a/packages/react/components/link/index.tsx +++ b/packages/react/components/link/index.tsx @@ -1 +1 @@ -export { Link } from './link'; +export { Link, type LinkProps } from './link'; diff --git a/packages/react/components/list/index.tsx b/packages/react/components/list/index.tsx index 53821c4bd..41c3baca0 100644 --- a/packages/react/components/list/index.tsx +++ b/packages/react/components/list/index.tsx @@ -1 +1,8 @@ -export { List } from './list'; +export { + List, + type ListHeaderProps, + type ListItemProps, + type ListLabelProps, + type ListRootProps as ListProps, + type ListValueProps +} from './list'; diff --git a/packages/react/components/list/list.tsx b/packages/react/components/list/list.tsx index 7bf508851..c61f3f6f9 100644 --- a/packages/react/components/list/list.tsx +++ b/packages/react/components/list/list.tsx @@ -10,25 +10,25 @@ const value = cva(styles.value); const header = cva(styles.header); const headerText = cva(styles['header-text']); -interface ListRootProps +export interface ListRootProps extends ComponentProps<'ul'>, VariantProps { children: ReactNode; } -interface ListItemProps extends ComponentProps<'li'> { +export interface ListItemProps extends ComponentProps<'li'> { children: ReactNode; } -interface ListLabelProps extends ComponentProps<'span'> { +export interface ListLabelProps extends ComponentProps<'span'> { children: ReactNode; } -interface ListValueProps extends ComponentProps<'span'> { +export interface ListValueProps extends ComponentProps<'span'> { children: ReactNode; } -interface ListHeaderProps extends ComponentProps<'div'> { +export interface ListHeaderProps extends ComponentProps<'div'> { children: ReactNode; /** * Heading level set as `aria-level` on the underlying heading. diff --git a/packages/react/components/menu/index.ts b/packages/react/components/menu/index.ts index 01435c7b0..53f7d3473 100644 --- a/packages/react/components/menu/index.ts +++ b/packages/react/components/menu/index.ts @@ -1 +1,6 @@ export { Menu } from './menu'; +export type { MenuContentProps } from './menu-content'; +export type { MenuItemProps } from './menu-item'; +export type { MenuEmptyStateProps } from './menu-misc'; +export type { MenuRootProps as MenuProps, MenuSubMenuProps } from './menu-root'; +export type { MenuSubTriggerProps, MenuTriggerProps } from './menu-trigger'; diff --git a/packages/react/components/menu/menu-misc.tsx b/packages/react/components/menu/menu-misc.tsx index 78c3c8ba3..792b99486 100644 --- a/packages/react/components/menu/menu-misc.tsx +++ b/packages/react/components/menu/menu-misc.tsx @@ -67,11 +67,15 @@ export function MenuSeparator({ className, ...props }: ComponentProps<'div'>) { } MenuSeparator.displayName = 'Menu.Separator'; +export interface MenuEmptyStateProps extends ComponentProps<'div'> { + children: ReactNode; +} + export function MenuEmptyState({ className, children, ...props -}: ComponentProps<'div'> & { children: ReactNode }) { +}: MenuEmptyStateProps) { return (
, 'orientation'> { orientation?: 'vertical' | 'horizontal'; @@ -60,7 +60,7 @@ function RadioGroup({ RadioGroup.displayName = 'Radio.Group'; -interface RadioItemProps +export interface RadioItemProps extends RadioPrimitive.Root.Props, VariantProps {} diff --git a/packages/react/components/reasoning/index.tsx b/packages/react/components/reasoning/index.tsx index ff53538d0..9a241c843 100644 --- a/packages/react/components/reasoning/index.tsx +++ b/packages/react/components/reasoning/index.tsx @@ -1,5 +1,7 @@ export { Reasoning, + type ReasoningContentProps, type ReasoningProps, - type ReasoningStepProps + type ReasoningStepProps, + type ReasoningTriggerProps } from './reasoning'; diff --git a/packages/react/components/search/index.ts b/packages/react/components/search/index.ts index 161bbbb64..b3bae083f 100644 --- a/packages/react/components/search/index.ts +++ b/packages/react/components/search/index.ts @@ -1 +1 @@ -export { Search } from './search'; +export { Search, type SearchProps } from './search'; diff --git a/packages/react/components/select/index.ts b/packages/react/components/select/index.ts index de9bdf23a..4284e8a7f 100644 --- a/packages/react/components/select/index.ts +++ b/packages/react/components/select/index.ts @@ -1 +1,11 @@ export { Select } from './select'; +export type { SelectContentProps } from './select-content'; +export type { SelectItemProps } from './select-item'; +export type { + SelectGroupProps, + SelectLabelProps, + SelectSeparatorProps +} from './select-misc'; +export type { SelectRootProps as SelectProps } from './select-root'; +export type { SelectTriggerProps } from './select-trigger'; +export type { SelectValueProps } from './select-value'; diff --git a/packages/react/components/select/select-value.tsx b/packages/react/components/select/select-value.tsx index 548586d33..5a5ceb136 100644 --- a/packages/react/components/select/select-value.tsx +++ b/packages/react/components/select/select-value.tsx @@ -9,7 +9,7 @@ import { ItemType } from './types'; type ValueType = Omit; -type SelectValueProps = ComponentProps<'span'> & { +export type SelectValueProps = ComponentProps<'span'> & { placeholder?: string; children?: ((value?: ValueType | ValueType[]) => ReactNode) | ReactNode; className?: string; diff --git a/packages/react/components/separator/index.tsx b/packages/react/components/separator/index.tsx index c99fe35dc..84b5222ed 100644 --- a/packages/react/components/separator/index.tsx +++ b/packages/react/components/separator/index.tsx @@ -1 +1 @@ -export { Separator } from './separator'; +export { Separator, type SeparatorProps } from './separator'; diff --git a/packages/react/components/separator/separator.tsx b/packages/react/components/separator/separator.tsx index 7d0d01325..dfcd38627 100644 --- a/packages/react/components/separator/separator.tsx +++ b/packages/react/components/separator/separator.tsx @@ -22,7 +22,7 @@ const separator = cva(styles.separator, { } }); -type SeparatorProps = SeparatorPrimitive.Props & +export type SeparatorProps = SeparatorPrimitive.Props & VariantProps & { /** * When true, the separator is purely decorative and hidden from diff --git a/packages/react/components/side-panel/index.tsx b/packages/react/components/side-panel/index.tsx index 5c3fc9e19..3620dc217 100644 --- a/packages/react/components/side-panel/index.tsx +++ b/packages/react/components/side-panel/index.tsx @@ -1 +1,6 @@ -export { SidePanel } from './side-panel'; +export { + SidePanel, + type SidePanelHeaderProps, + type SidePanelProps, + type SidePanelSectionProps +} from './side-panel'; diff --git a/packages/react/components/side-panel/side-panel.tsx b/packages/react/components/side-panel/side-panel.tsx index 6527c9ec6..6734fcb20 100644 --- a/packages/react/components/side-panel/side-panel.tsx +++ b/packages/react/components/side-panel/side-panel.tsx @@ -16,7 +16,7 @@ const sidePanelRoot = cva(styles['side-panel'], { } }); -interface SidePanelProps +export interface SidePanelProps extends ComponentProps<'aside'>, VariantProps {} @@ -36,7 +36,7 @@ const SidePanelRoot = ({ SidePanelRoot.displayName = 'SidePanel'; -interface SidePanelHeaderProps extends ComponentProps<'div'> { +export interface SidePanelHeaderProps extends ComponentProps<'div'> { title: string; icon?: ReactNode; actions?: Array; @@ -95,7 +95,7 @@ const SidePanelHeader = ({ SidePanelHeader.displayName = 'SidePanel.Header'; -interface SidePanelSectionProps extends ComponentProps<'div'> {} +export interface SidePanelSectionProps extends ComponentProps<'div'> {} const SidePanelSection = ({ className, ...props }: SidePanelSectionProps) => { return ( diff --git a/packages/react/components/sidebar/index.tsx b/packages/react/components/sidebar/index.tsx index 23d174c20..ea6da8518 100644 --- a/packages/react/components/sidebar/index.tsx +++ b/packages/react/components/sidebar/index.tsx @@ -1,3 +1,10 @@ export { Sidebar } from './sidebar'; -export type { SidebarContextValue } from './sidebar-root'; +export type { SidebarGroupProps } from './sidebar-group'; +export type { SidebarItemProps } from './sidebar-item'; +export type { SidebarMoreProps } from './sidebar-more'; +export type { + SidebarContextValue, + SidebarRootProps as SidebarProps +} from './sidebar-root'; export { useSidebar } from './sidebar-root'; +export type { SidebarTriggerProps } from './sidebar-trigger'; diff --git a/packages/react/components/sidebar/sidebar-group.tsx b/packages/react/components/sidebar/sidebar-group.tsx index 5f58cd716..4545e34f8 100644 --- a/packages/react/components/sidebar/sidebar-group.tsx +++ b/packages/react/components/sidebar/sidebar-group.tsx @@ -10,7 +10,7 @@ import { SidebarLeadingVisual } from './sidebar-leading-visual'; import { useSidebarSafe } from './sidebar-root'; import { SidebarTrailingVisual } from './sidebar-trailing-visual'; -export interface SidebarNavigationGroupProps extends ComponentProps<'section'> { +export interface SidebarGroupProps extends ComponentProps<'section'> { label: string; /** * Renders the group as an accordion whose items can be shown or hidden. @@ -54,7 +54,7 @@ export function SidebarNavigationGroup({ classNames, children, ...props -}: SidebarNavigationGroupProps) { +}: SidebarGroupProps) { const { isCollapsed } = useSidebarSafe(); const [internalOpen, setInternalOpen] = useState(defaultOpen); const isOpen = isCollapsed || (providedOpen ?? internalOpen); diff --git a/packages/react/components/skeleton/index.ts b/packages/react/components/skeleton/index.ts index 9147f13a9..d682bf302 100644 --- a/packages/react/components/skeleton/index.ts +++ b/packages/react/components/skeleton/index.ts @@ -1 +1,5 @@ -export { Skeleton } from './skeleton'; +export { + Skeleton, + type SkeletonProps, + type SkeletonProviderProps +} from './skeleton'; diff --git a/packages/react/components/skeleton/skeleton.tsx b/packages/react/components/skeleton/skeleton.tsx index 9e0ce8c8c..b09698307 100644 --- a/packages/react/components/skeleton/skeleton.tsx +++ b/packages/react/components/skeleton/skeleton.tsx @@ -22,7 +22,7 @@ export interface SkeletonProps { const SkeletonContext = createContext(null); -interface SkeletonProviderProps extends SkeletonProps { +export interface SkeletonProviderProps extends SkeletonProps { children: ReactNode; } diff --git a/packages/react/components/slider/index.tsx b/packages/react/components/slider/index.tsx index 611e90646..74eacb709 100644 --- a/packages/react/components/slider/index.tsx +++ b/packages/react/components/slider/index.tsx @@ -1 +1 @@ -export { Slider } from './slider'; +export { Slider, type SliderProps } from './slider'; diff --git a/packages/react/components/spinner/index.tsx b/packages/react/components/spinner/index.tsx index b2a4e980b..c70327904 100644 --- a/packages/react/components/spinner/index.tsx +++ b/packages/react/components/spinner/index.tsx @@ -1 +1 @@ -export { Spinner } from './spinner'; +export { Spinner, type SpinnerProps } from './spinner'; diff --git a/packages/react/components/switch/index.ts b/packages/react/components/switch/index.ts index 675ddba51..73eb5710d 100644 --- a/packages/react/components/switch/index.ts +++ b/packages/react/components/switch/index.ts @@ -1 +1 @@ -export { Switch } from './switch'; +export { Switch, type SwitchProps } from './switch'; diff --git a/packages/react/components/table/index.ts b/packages/react/components/table/index.ts index 48232283c..9d4fc0b57 100644 --- a/packages/react/components/table/index.ts +++ b/packages/react/components/table/index.ts @@ -1 +1,9 @@ -export { Table } from './table'; +export { + Table, + type TableCellProps, + type TableHeaderProps, + type TableHeadProps, + type TableProps, + type TableRowProps, + type TableSectionHeaderProps +} from './table'; diff --git a/packages/react/components/table/table.tsx b/packages/react/components/table/table.tsx index 619d1a806..afd599fe4 100644 --- a/packages/react/components/table/table.tsx +++ b/packages/react/components/table/table.tsx @@ -3,10 +3,8 @@ import { ComponentProps } from 'react'; import styles from './table.module.css'; const table = cva(styles['table']); -function TableRoot({ - className, - ...props -}: ComponentProps<'table'> & VariantProps) { +export type TableProps = ComponentProps<'table'> & VariantProps; +function TableRoot({ className, ...props }: TableProps) { return ( ); @@ -14,10 +12,9 @@ function TableRoot({ TableRoot.displayName = 'Table'; const header = cva(styles['header']); -function TableHeader({ - className, - ...props -}: ComponentProps<'thead'> & VariantProps) { +export type TableHeaderProps = ComponentProps<'thead'> & + VariantProps; +function TableHeader({ className, ...props }: TableHeaderProps) { return ( & VariantProps) { +export type TableRowProps = ComponentProps<'tr'> & VariantProps; +function TableRow({ className, interactive, ...props }: TableRowProps) { return ( & VariantProps) { +export type TableHeadProps = ComponentProps<'th'> & VariantProps; +function TableHead({ className, scope = 'col', ...props }: TableHeadProps) { return ( ; +export type TabsRootProps = TabsPrimitive.Root.Props & + VariantProps; function TabsRoot({ className, variant, size, ...props }: TabsRootProps) { return ( @@ -52,7 +53,7 @@ function TabsList({ className, children, ...props }: TabsPrimitive.List.Props) { } TabsList.displayName = 'Tabs.List'; -interface TabsTabProps extends TabsPrimitive.Tab.Props { +export interface TabsTabProps extends TabsPrimitive.Tab.Props { leadingIcon?: ReactNode; } diff --git a/packages/react/components/text-area/index.tsx b/packages/react/components/text-area/index.tsx index 88ff10393..b6419545a 100644 --- a/packages/react/components/text-area/index.tsx +++ b/packages/react/components/text-area/index.tsx @@ -1 +1 @@ -export { TextArea } from './text-area'; +export { TextArea, type TextAreaProps } from './text-area'; diff --git a/packages/react/components/text/index.tsx b/packages/react/components/text/index.tsx index 1a9ac1460..74782c49e 100644 --- a/packages/react/components/text/index.tsx +++ b/packages/react/components/text/index.tsx @@ -1 +1,2 @@ +export type { TextProps } from './text'; export * from './text'; diff --git a/packages/react/components/toast/index.ts b/packages/react/components/toast/index.ts index bcb815d4e..56ded51ab 100644 --- a/packages/react/components/toast/index.ts +++ b/packages/react/components/toast/index.ts @@ -1,3 +1,3 @@ export { Toast, toastManager, useToastManager } from './toast'; export type { ToastPosition, ToastProviderProps } from './toast-provider'; -export type { ToastRootProps } from './toast-root'; +export type { ToastRootProps as ToastProps } from './toast-root'; diff --git a/packages/react/components/toggle/index.ts b/packages/react/components/toggle/index.ts index 6618bb578..edd005658 100644 --- a/packages/react/components/toggle/index.ts +++ b/packages/react/components/toggle/index.ts @@ -1 +1 @@ -export { Toggle } from './toggle'; +export { Toggle, type ToggleProps } from './toggle'; diff --git a/packages/react/components/tooltip/index.tsx b/packages/react/components/tooltip/index.tsx index c20c22cb1..a773cf172 100644 --- a/packages/react/components/tooltip/index.tsx +++ b/packages/react/components/tooltip/index.tsx @@ -1 +1,2 @@ export { Tooltip } from './tooltip'; +export type { TooltipContentProps } from './tooltip-content'; diff --git a/packages/react/components/tour/index.tsx b/packages/react/components/tour/index.tsx index 16c5e769a..a24547d27 100644 --- a/packages/react/components/tour/index.tsx +++ b/packages/react/components/tour/index.tsx @@ -3,7 +3,7 @@ export type { TourContentProps } from './tour-content'; export { type UseTourReturn, useTour } from './tour-context'; export type { TourOverlayProps } from './tour-overlay'; export type { TourProgressProps } from './tour-parts'; -export type { TourRootProps } from './tour-root'; +export type { TourRootProps as TourProps } from './tour-root'; export type { TourActions, TourAlign, diff --git a/packages/react/index.tsx b/packages/react/index.tsx index c8018c342..c5839b763 100644 --- a/packages/react/index.tsx +++ b/packages/react/index.tsx @@ -1,22 +1,36 @@ import './styles/index.css'; import './normalize.css'; -export { Accordion } from './components/accordion'; -export { AlertDialog } from './components/alert-dialog'; +export { Accordion, type AccordionProps } from './components/accordion'; +export { + AlertDialog, + type AlertDialogContentProps +} from './components/alert-dialog'; export { Amount, type AmountProps } from './components/amount'; -export { AnnouncementBar } from './components/announcement-bar'; +export { + AnnouncementBar, + type AnnouncementBarProps +} from './components/announcement-bar'; export { AVATAR_COLORS, Avatar, type AvatarColor, AvatarGroup, + type AvatarGroupProps, + type AvatarProps, type GetAvatarColorOptions, getAvatarColor } from './components/avatar'; -export { Badge } from './components/badge'; +export { Badge, type BadgeProps } from './components/badge'; export { Box } from './components/box'; -export { Breadcrumb } from './components/breadcrumb'; -export { Button } from './components/button'; +export { + Breadcrumb, + type BreadcrumbEllipsisProps, + type BreadcrumbItemProps, + type BreadcrumbProps, + type BreadcrumbSeparatorProps +} from './components/breadcrumb'; +export { Button, type ButtonProps } from './components/button'; export { Calendar, type CalendarProps, @@ -25,7 +39,9 @@ export { type DatePickerProps, type DatePickerSlotProps, type DateRange, - RangePicker + RangePicker, + type RangePickerProps, + type RangePickerSlotProps } from './components/calendar'; export { CalendarPreview, @@ -62,56 +78,121 @@ export { type UseCalendarReturn, useCalendar } from './components/calendar-preview'; -export { Callout } from './components/callout'; +export { Callout, type CalloutProps } from './components/callout'; export { Chat, + type ChatAttachmentProps, type ChatAttachmentState, + type ChatComposerProps, + type ChatItemProps, type ChatJumpButtonProps, type ChatMessagesActions, + type ChatMessagesProps, + type ChatProps, + type ChatSeparatorProps, type UseChatMessagesReturn, useChatMessages } from './components/chat'; export { ChatPanel, + type ChatPanelActionsProps, + type ChatPanelContentProps, type ChatPanelDragBoundary, type ChatPanelExpandTriggerProps, type ChatPanelExpandTriggerState, + type ChatPanelHeaderProps, + type ChatPanelMinimizeTriggerProps, type ChatPanelMode, type ChatPanelPosition, type ChatPanelProps, type ChatPanelResize, type ChatPanelSide, type ChatPanelSize, + type ChatPanelTitleProps, type ChatPanelTransition, type ChatPanelTriggerProps } from './components/chat-panel'; -export { Checkbox } from './components/checkbox'; +export { + Checkbox, + type CheckboxGroupProps, + type CheckboxProps +} from './components/checkbox'; export { Chip, type ChipProps } from './components/chip'; -export { CodeBlock } from './components/code-block'; +export { + CodeBlock, + type CodeBlockCodeProps, + type CodeBlockCollapseTriggerProps, + type CodeBlockCopyButtonProps, + type CodeBlockLanguageSelectProps, + type CodeBlockProps +} from './components/code-block'; export { Collapsible } from './components/collapsible'; export * from './components/color-picker'; -export { Combobox } from './components/combobox'; -export { Command } from './components/command'; -export { Container } from './components/container'; -export { ContextMenu } from './components/context-menu'; -export { CopyButton } from './components/copy-button'; +export { + Combobox, + type ComboboxContentProps, + type ComboboxInputProps, + type ComboboxItemProps, + type ComboboxProps +} from './components/combobox'; +export { + Command, + type CommandContentProps, + type CommandDialogContentProps, + type CommandEmptyProps, + type CommandGroupProps, + type CommandInputProps, + type CommandItemProps, + type CommandLabelProps, + type CommandProps, + type CommandSeparatorProps +} from './components/command'; +export { Container, type ContainerProps } from './components/container'; +export { + ContextMenu, + type ContextMenuContentProps, + type ContextMenuGroupProps, + type ContextMenuItemProps, + type ContextMenuLabelProps, + type ContextMenuProps, + type ContextMenuSubMenuProps, + type ContextMenuSubTriggerProps, + type ContextMenuTriggerProps +} from './components/context-menu'; +export { CopyButton, type CopyButtonProps } from './components/copy-button'; export { DataTable, DataTableColumnDef, + type DataTableContentProps, + type DataTableDisplayControlsProps, + type DataTableFiltersProps, + type DataTableProps, DataTableQuery, + type DataTableSearchProps, DataTableSort, + type DataTableToolbarProps, + type DataTableVirtualizedContentProps, EmptyFilterValue, useDataTable } from './components/data-table'; export { DataView, + type DataViewClearFiltersProps, + type DataViewCustomProps, + type DataViewDisplayAccessProps, + type DataViewDisplayControlsProps, + type DataViewEmptyStateProps, DataViewField, + type DataViewFiltersProps, DataViewListColumn, DataViewListProps, DataViewProps, DataViewQuery, + type DataViewSearchProps, DataViewSort, DataViewTimelineProps, + type DataViewToolbarProps, + type DataViewZeroStateProps, TimelineActions, TimelineCardContext, TimelineDateInput, @@ -119,8 +200,12 @@ export { TimelineScale, useDataView } from './components/data-view'; -export { Dialog } from './components/dialog'; -export { Drawer } from './components/drawer'; +export { Dialog, type DialogContentProps } from './components/dialog'; +export { + Drawer, + type DrawerContentProps, + type DrawerProps +} from './components/drawer'; export { defaultShortcuts, defaultSlashItems, @@ -161,42 +246,96 @@ export { useEditor, useEditorState } from './components/editor'; -export { EmptyState } from './components/empty-state'; -export { Field } from './components/field'; -export { Fieldset } from './components/fieldset'; +export { EmptyState, type EmptyStateProps } from './components/empty-state'; +export { + Field, + type FieldLabelProps, + type FieldProps +} from './components/field'; +export { Fieldset, type FieldsetProps } from './components/fieldset'; export { FilterChip, type FilterChipCalendarProps, type FilterChipProps, type FilterChipValue } from './components/filter-chip'; -export { Flex } from './components/flex'; -export { FloatingActions } from './components/floating-actions'; -export { Form } from './components/form'; -export { Grid } from './components/grid'; -export { Headline } from './components/headline'; -export { IconButton } from './components/icon-button'; -export { Image } from './components/image'; -export { Indicator } from './components/indicator'; -export { Input } from './components/input'; -export { Kbd } from './components/kbd'; -export { Label } from './components/label'; -export { Link } from './components/link'; -export { List } from './components/list'; -export { Menu } from './components/menu'; +export { Flex, type FlexProps } from './components/flex'; +export { + FloatingActions, + type FloatingActionsGroupProps, + type FloatingActionsProps, + type FloatingActionsSeparatorProps +} from './components/floating-actions'; +export { Form, type FormProps } from './components/form'; +export { Grid, type GridItemProps, type GridProps } from './components/grid'; +export { Headline, type HeadlineProps } from './components/headline'; +export { IconButton, type IconButtonProps } from './components/icon-button'; +export { Image, type ImageProps } from './components/image'; +export { Indicator, type IndicatorProps } from './components/indicator'; +export { Input, type InputProps } from './components/input'; +export { Kbd, type KbdGroupProps, type KbdProps } from './components/kbd'; +export { Label, type LabelProps } from './components/label'; +export { Link, type LinkProps } from './components/link'; +export { + List, + type ListHeaderProps, + type ListItemProps, + type ListLabelProps, + type ListProps, + type ListValueProps +} from './components/list'; +export { + Menu, + type MenuContentProps, + type MenuEmptyStateProps, + type MenuItemProps, + type MenuProps, + type MenuSubMenuProps, + type MenuSubTriggerProps, + type MenuTriggerProps +} from './components/menu'; export { Menubar } from './components/menubar'; -export { Message } from './components/message'; -export { Meter } from './components/meter'; -export { Navbar } from './components/navbar'; -export { NumberField } from './components/number-field'; -export { OTPField } from './components/otp-field'; -export { Popover } from './components/popover'; -export { PreviewCard } from './components/preview-card'; -export { Progress } from './components/progress'; +export { + Message, + type MessageActionsProps, + type MessageAvatarProps, + type MessageBubbleProps, + type MessageContentProps, + type MessageFooterProps, + type MessageGroupProps, + type MessageHeaderProps, + type MessageProps +} from './components/message'; +export { Meter, type MeterProps } from './components/meter'; +export { + Navbar, + type NavbarCenterProps, + type NavbarEndProps, + type NavbarProps, + type NavbarStartProps +} from './components/navbar'; +export { + NumberField, + type NumberFieldScrubAreaProps +} from './components/number-field'; +export { + OTPField, + type OTPFieldInputProps, + type OTPFieldProps, + type OTPFieldSeparatorProps +} from './components/otp-field'; +export { Popover, type PopoverContentProps } from './components/popover'; +export { + PreviewCard, + type PreviewCardContentProps +} from './components/preview-card'; +export { Progress, type ProgressProps } from './components/progress'; export { PromptInput, type PromptInputActions, type PromptInputEditorProps, + type PromptInputFooterProps, + type PromptInputHeaderProps, type PromptInputMention, type PromptInputMentionItem, type PromptInputMentionRef, @@ -204,28 +343,71 @@ export { type PromptInputMessage, type PromptInputProps, type PromptInputStatus, + type PromptInputSubmitProps, type PromptInputTextareaProps } from './components/prompt-input'; -export { Radio } from './components/radio'; -export { Reasoning } from './components/reasoning'; -export { ScrollArea } from './components/scroll-area'; -export { Search } from './components/search'; -export { Select } from './components/select'; -export { Separator } from './components/separator'; -export { SidePanel } from './components/side-panel'; +export { + Radio, + type RadioGroupProps, + type RadioProps +} from './components/radio'; +export { + Reasoning, + type ReasoningContentProps, + type ReasoningProps, + type ReasoningStepProps, + type ReasoningTriggerProps +} from './components/reasoning'; +export { ScrollArea, type ScrollAreaProps } from './components/scroll-area'; +export { Search, type SearchProps } from './components/search'; +export { + Select, + type SelectContentProps, + type SelectGroupProps, + type SelectItemProps, + type SelectLabelProps, + type SelectProps, + type SelectSeparatorProps, + type SelectTriggerProps, + type SelectValueProps +} from './components/select'; +export { Separator, type SeparatorProps } from './components/separator'; +export { + SidePanel, + type SidePanelHeaderProps, + type SidePanelProps, + type SidePanelSectionProps +} from './components/side-panel'; export { Sidebar, type SidebarContextValue, + type SidebarGroupProps, + type SidebarItemProps, + type SidebarMoreProps, + type SidebarProps, + type SidebarTriggerProps, useSidebar } from './components/sidebar'; -export { Skeleton } from './components/skeleton'; -export { Slider } from './components/slider'; -export { Spinner } from './components/spinner'; -export { Switch } from './components/switch'; -export { Table } from './components/table'; -export { Tabs } from './components/tabs'; -export { Text } from './components/text'; -export { TextArea } from './components/text-area'; +export { + Skeleton, + type SkeletonProps, + type SkeletonProviderProps +} from './components/skeleton'; +export { Slider, type SliderProps } from './components/slider'; +export { Spinner, type SpinnerProps } from './components/spinner'; +export { Switch, type SwitchProps } from './components/switch'; +export { + Table, + type TableCellProps, + type TableHeaderProps, + type TableHeadProps, + type TableProps, + type TableRowProps, + type TableSectionHeaderProps +} from './components/table'; +export { Tabs, type TabsProps, type TabsTabProps } from './components/tabs'; +export { Text, type TextProps } from './components/text'; +export { TextArea, type TextAreaProps } from './components/text-area'; export { type AccentColor, type Appearance, @@ -251,15 +433,25 @@ export { useTheme, useThemeInjection } from './components/theme'; -export { Toast, toastManager, useToastManager } from './components/toast'; -export { Toggle } from './components/toggle'; +export { + Toast, + type ToastProps, + type ToastProviderProps, + toastManager, + useToastManager +} from './components/toast'; +export { Toggle, type ToggleProps } from './components/toggle'; export { Toolbar } from './components/toolbar'; -export { Tooltip } from './components/tooltip'; +export { Tooltip, type TooltipContentProps } from './components/tooltip'; export { Tour, type TourActions, + type TourContentProps, type TourEndStatus, type TourEvent, + type TourOverlayProps, + type TourProgressProps, + type TourProps, type TourRenderProps, type TourStep, type TourTarget, From f6645496c36a920e58c8095ccfa8bf40c8b2133f Mon Sep 17 00:00:00 2001 From: Shreyag02 Date: Mon, 12 Oct 2026 00:31:27 +0530 Subject: [PATCH 2/4] test: check that every props type is exported --- packages/react/__tests__/exports.test.ts | 102 +++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 packages/react/__tests__/exports.test.ts diff --git a/packages/react/__tests__/exports.test.ts b/packages/react/__tests__/exports.test.ts new file mode 100644 index 000000000..004f5a33b --- /dev/null +++ b/packages/react/__tests__/exports.test.ts @@ -0,0 +1,102 @@ +// @vitest-environment node +import { resolve } from 'node:path'; +import ts from 'typescript'; +import { describe, expect, it } from 'vitest'; + +/* Consumers import components and their types from the root entry only, so a + props type is public only when index.tsx exports it. */ + +const PACKAGE_DIR = process.cwd(); + +const isLocal = (node: ts.Node) => + !node.getSourceFile().fileName.includes('/node_modules/'); + +function loadRootEntry() { + const { config } = ts.readConfigFile( + resolve(PACKAGE_DIR, 'tsconfig.json'), + ts.sys.readFile + ); + const { options } = ts.parseJsonConfigFileContent( + config, + ts.sys, + PACKAGE_DIR + ); + const entry = resolve(PACKAGE_DIR, 'index.tsx'); + const program = ts.createProgram([entry], { ...options, noEmit: true }); + const checker = program.getTypeChecker(); + const sourceFile = program.getSourceFile(entry); + const moduleSymbol = sourceFile && checker.getSymbolAtLocation(sourceFile); + if (!sourceFile || !moduleSymbol) throw new Error('index.tsx did not load'); + /* Type-only exports are erased at runtime, so only the compiler sees a + duplicate or a missing name. */ + const errors = ts + .getPreEmitDiagnostics(program, sourceFile) + .map(error => ts.flattenDiagnosticMessageText(error.messageText, '\n')); + return { checker, errors, exports: checker.getExportsOfModule(moduleSymbol) }; +} + +function findUnexportedPropsTypes() { + const { checker, errors, exports } = loadRootEntry(); + const resolveAlias = (symbol: ts.Symbol) => + symbol.flags & ts.SymbolFlags.Alias + ? checker.getAliasedSymbol(symbol) + : symbol; + const exported = new Set(exports.map(resolveAlias)); + + const localType = (node: ts.TypeReferenceNode) => { + const symbol = checker.getSymbolAtLocation(node.typeName); + const target = symbol && resolveAlias(symbol); + const declaration = target?.declarations?.[0]; + if (!target || !declaration || !isLocal(declaration)) return undefined; + if (ts.isTypeParameterDeclaration(declaration)) return undefined; + return target; + }; + const wrapsLocalType = (node: ts.Node): boolean => + (ts.isTypeReferenceNode(node) && localType(node) !== undefined) || + (ts.forEachChild(node, wrapsLocalType) ?? false); + + const problems = [...errors]; + const checkPart = (name: string, type: ts.Type) => { + const declaration = type.getCallSignatures()[0]?.declaration; + /* A Base UI part used as it is has no props type of ours. */ + if (!declaration || !isLocal(declaration)) return; + if (!ts.isFunctionLike(declaration)) return; + const props = declaration.parameters[0]; + if (!props) return; + const annotation = props.type; + if (!annotation || !ts.isTypeReferenceNode(annotation)) { + problems.push(`${name}: give its props one named type`); + return; + } + const target = localType(annotation); + if (target && !exported.has(target)) { + problems.push(`${name}: export ${target.getName()} from index.tsx`); + } + if (!target && annotation.typeArguments?.some(wrapsLocalType)) { + problems.push(`${name}: move ${annotation.getText()} into one type`); + } + }; + + for (const symbol of exports) { + const component = resolveAlias(symbol); + const declaration = component.valueDeclaration; + if (!declaration || !isLocal(declaration)) continue; + if (!/^[A-Z]/.test(symbol.getName())) continue; + const type = checker.getTypeOfSymbolAtLocation(component, declaration); + checkPart(symbol.getName(), type); + for (const part of type.getProperties()) { + if (!part.valueDeclaration || !/^[A-Z]/.test(part.getName())) continue; + checkPart( + `${symbol.getName()}.${part.getName()}`, + checker.getTypeOfSymbolAtLocation(part, part.valueDeclaration) + ); + } + } + return problems; +} + +describe('package exports', () => { + it('exports the props type of every component and part', () => { + expect(findUnexportedPropsTypes()).toEqual([]); + }, 120_000); +}); From 49c3690880b76e2f997e37c290232939497f7e9b Mon Sep 17 00:00:00 2001 From: Shreyag02 Date: Mon, 12 Oct 2026 00:38:52 +0530 Subject: [PATCH 3/4] chore: check props exports in the add-new-component skill --- .agents/skills/add-new-component/SKILL.md | 5 +- AGENTS.md | 2 +- packages/react/__tests__/exports.test.ts | 102 ---------------------- 3 files changed, 5 insertions(+), 104 deletions(-) delete mode 100644 packages/react/__tests__/exports.test.ts diff --git a/.agents/skills/add-new-component/SKILL.md b/.agents/skills/add-new-component/SKILL.md index a754675f6..49dd093e0 100644 --- a/.agents/skills/add-new-component/SKILL.md +++ b/.agents/skills/add-new-component/SKILL.md @@ -500,8 +500,11 @@ Notes: pnpm --filter @raystack/apsara build pnpm --filter @raystack/apsara test -- --reporter=verbose components/ pnpm --filter www build +grep -n "from './components/'" packages/react/dist/index.d.ts ``` +The `grep` prints the root export of the component. Check that it lists the props type of every part that declares its own type. Type-only exports are erased at runtime, so the tests and the build still pass when one is missing. Parts that take Base UI or HTML props unchanged have no type to export. + Checklist: - [ ] Component builds without errors - [ ] All tests pass @@ -510,5 +513,5 @@ Checklist: - [ ] Every rendered element has a `data-slot`, with a `data-slots.test.tsx` covering them - [ ] CSS uses `--rs-*` tokens only - [ ] Export in `packages/react/index.tsx` in alphabetical order -- [ ] Props types exported from the component index and `packages/react/index.tsx` (`__tests__/exports.test.ts` passes) +- [ ] Props types exported from the component index and `packages/react/index.tsx`, and listed in `dist/index.d.ts` - [ ] Interactive `playground` added to `demo.ts`, covering the component's main props diff --git a/AGENTS.md b/AGENTS.md index abf89a7b7..f4c03220c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -21,7 +21,7 @@ Skills are in `.agents/skills/`. `.claude/skills` is a symlink to that folder, s ## Code - Each component is in `packages/react/components//`. Its `index.tsx` only re-exports. -- Export new components from `packages/react/index.tsx`, in alphabetical order, with their props types: `Props` for the root part and `Props` for each part with its own type. `__tests__/exports.test.ts` checks this. +- Export new components from `packages/react/index.tsx`, in alphabetical order, with their props types: `Props` for the root part and `Props` for each part with its own type. - Wrap Base UI primitives, for example `import { Tabs as TabsPrimitive } from '@base-ui/react'`. Do not rebuild behavior that Base UI already has. - For plain elements, use `useRender` and `mergeProps` so the `render` prop works. - Pass `ref` as a normal prop (React 19). Do not use `forwardRef`. diff --git a/packages/react/__tests__/exports.test.ts b/packages/react/__tests__/exports.test.ts deleted file mode 100644 index 004f5a33b..000000000 --- a/packages/react/__tests__/exports.test.ts +++ /dev/null @@ -1,102 +0,0 @@ -// @vitest-environment node -import { resolve } from 'node:path'; -import ts from 'typescript'; -import { describe, expect, it } from 'vitest'; - -/* Consumers import components and their types from the root entry only, so a - props type is public only when index.tsx exports it. */ - -const PACKAGE_DIR = process.cwd(); - -const isLocal = (node: ts.Node) => - !node.getSourceFile().fileName.includes('/node_modules/'); - -function loadRootEntry() { - const { config } = ts.readConfigFile( - resolve(PACKAGE_DIR, 'tsconfig.json'), - ts.sys.readFile - ); - const { options } = ts.parseJsonConfigFileContent( - config, - ts.sys, - PACKAGE_DIR - ); - const entry = resolve(PACKAGE_DIR, 'index.tsx'); - const program = ts.createProgram([entry], { ...options, noEmit: true }); - const checker = program.getTypeChecker(); - const sourceFile = program.getSourceFile(entry); - const moduleSymbol = sourceFile && checker.getSymbolAtLocation(sourceFile); - if (!sourceFile || !moduleSymbol) throw new Error('index.tsx did not load'); - /* Type-only exports are erased at runtime, so only the compiler sees a - duplicate or a missing name. */ - const errors = ts - .getPreEmitDiagnostics(program, sourceFile) - .map(error => ts.flattenDiagnosticMessageText(error.messageText, '\n')); - return { checker, errors, exports: checker.getExportsOfModule(moduleSymbol) }; -} - -function findUnexportedPropsTypes() { - const { checker, errors, exports } = loadRootEntry(); - const resolveAlias = (symbol: ts.Symbol) => - symbol.flags & ts.SymbolFlags.Alias - ? checker.getAliasedSymbol(symbol) - : symbol; - const exported = new Set(exports.map(resolveAlias)); - - const localType = (node: ts.TypeReferenceNode) => { - const symbol = checker.getSymbolAtLocation(node.typeName); - const target = symbol && resolveAlias(symbol); - const declaration = target?.declarations?.[0]; - if (!target || !declaration || !isLocal(declaration)) return undefined; - if (ts.isTypeParameterDeclaration(declaration)) return undefined; - return target; - }; - const wrapsLocalType = (node: ts.Node): boolean => - (ts.isTypeReferenceNode(node) && localType(node) !== undefined) || - (ts.forEachChild(node, wrapsLocalType) ?? false); - - const problems = [...errors]; - const checkPart = (name: string, type: ts.Type) => { - const declaration = type.getCallSignatures()[0]?.declaration; - /* A Base UI part used as it is has no props type of ours. */ - if (!declaration || !isLocal(declaration)) return; - if (!ts.isFunctionLike(declaration)) return; - const props = declaration.parameters[0]; - if (!props) return; - const annotation = props.type; - if (!annotation || !ts.isTypeReferenceNode(annotation)) { - problems.push(`${name}: give its props one named type`); - return; - } - const target = localType(annotation); - if (target && !exported.has(target)) { - problems.push(`${name}: export ${target.getName()} from index.tsx`); - } - if (!target && annotation.typeArguments?.some(wrapsLocalType)) { - problems.push(`${name}: move ${annotation.getText()} into one type`); - } - }; - - for (const symbol of exports) { - const component = resolveAlias(symbol); - const declaration = component.valueDeclaration; - if (!declaration || !isLocal(declaration)) continue; - if (!/^[A-Z]/.test(symbol.getName())) continue; - const type = checker.getTypeOfSymbolAtLocation(component, declaration); - checkPart(symbol.getName(), type); - for (const part of type.getProperties()) { - if (!part.valueDeclaration || !/^[A-Z]/.test(part.getName())) continue; - checkPart( - `${symbol.getName()}.${part.getName()}`, - checker.getTypeOfSymbolAtLocation(part, part.valueDeclaration) - ); - } - } - return problems; -} - -describe('package exports', () => { - it('exports the props type of every component and part', () => { - expect(findUnexportedPropsTypes()).toEqual([]); - }, 120_000); -}); From 9ada6159960bc532e5f8e86fee04003fc2300426 Mon Sep 17 00:00:00 2001 From: Shreyag02 Date: Wed, 14 Oct 2026 12:56:05 +0530 Subject: [PATCH 4/4] fix: [tooltip] export the trigger props type --- packages/react/components/tooltip/index.tsx | 1 + packages/react/components/tooltip/tooltip-misc.tsx | 2 +- packages/react/index.tsx | 6 +++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/react/components/tooltip/index.tsx b/packages/react/components/tooltip/index.tsx index a773cf172..63c4ccd6e 100644 --- a/packages/react/components/tooltip/index.tsx +++ b/packages/react/components/tooltip/index.tsx @@ -1,2 +1,3 @@ export { Tooltip } from './tooltip'; export type { TooltipContentProps } from './tooltip-content'; +export type { TooltipTriggerProps } from './tooltip-misc'; diff --git a/packages/react/components/tooltip/tooltip-misc.tsx b/packages/react/components/tooltip/tooltip-misc.tsx index 174f815fb..330e9c2aa 100644 --- a/packages/react/components/tooltip/tooltip-misc.tsx +++ b/packages/react/components/tooltip/tooltip-misc.tsx @@ -4,7 +4,7 @@ import { Tooltip as TooltipPrimitive } from '@base-ui/react'; export interface TooltipTriggerProps extends TooltipPrimitive.Trigger.Props {} -export function TooltipTrigger(props: TooltipPrimitive.Trigger.Props) { +export function TooltipTrigger(props: TooltipTriggerProps) { return (
& VariantProps) { +export type TableCellProps = ComponentProps<'td'> & VariantProps; +function TableCell({ className, ...props }: TableCellProps) { return ( ); @@ -85,6 +74,14 @@ TableCell.displayName = 'Table.Cell'; const sectionHeader = cva(styles['sectionHeader']); type SectionHeaderClassNames = 'row' | 'cell'; +export interface TableSectionHeaderProps extends ComponentProps<'tr'> { + colSpan: number; + /** + * @deprecated Use `[data-slot="table-section-header"]` (row) and + * `[data-slot="table-section-header-cell"]` (cell) instead. + */ + classNames?: Partial>; +} function SectionHeader({ className, classNames, @@ -92,14 +89,7 @@ function SectionHeader({ children, ref, ...rest -}: ComponentProps<'tr'> & { - colSpan: number; - /** - * @deprecated Use `[data-slot="table-section-header"]` (row) and - * `[data-slot="table-section-header-cell"]` (cell) instead. - */ - classNames?: Partial>; -}) { +}: TableSectionHeaderProps) { return (