From db41114aba416003d2132cf3f563656d7fa283a3 Mon Sep 17 00:00:00 2001 From: Shreyag02 Date: Mon, 12 Oct 2026 13:01:50 +0530 Subject: [PATCH 01/19] fix: [docs] sync props tables with components --- .../content/docs/components/calendar/props.ts | 5 ++++ .../src/content/docs/components/chip/props.ts | 3 +++ .../docs/components/code-block/index.mdx | 2 +- .../docs/components/code-block/props.ts | 22 +++++++++++++--- .../content/docs/components/field/props.ts | 11 ++++++++ .../docs/components/floating-actions/props.ts | 6 +++++ .../docs/components/indicator/index.mdx | 2 +- .../docs/components/indicator/props.ts | 2 +- .../src/content/docs/components/list/demo.ts | 26 +++---------------- .../content/docs/components/list/index.mdx | 7 ----- .../src/content/docs/components/list/props.ts | 9 +++---- .../content/docs/components/select/props.ts | 3 +++ .../content/docs/components/toast/props.ts | 5 ++++ 13 files changed, 62 insertions(+), 41 deletions(-) diff --git a/apps/www/src/content/docs/components/calendar/props.ts b/apps/www/src/content/docs/components/calendar/props.ts index e3f047615..6d76f01ec 100644 --- a/apps/www/src/content/docs/components/calendar/props.ts +++ b/apps/www/src/content/docs/components/calendar/props.ts @@ -137,6 +137,11 @@ export interface CalendarProps { } export interface RangePickerProps { + /** + * Additional CSS class names for the group that holds the start and end inputs. + */ + pickerGroupClassName?: string; + /** * Format for displaying the date. Supports various formats: * - With slashes: "DD/MM/YYYY", "MM/DD/YYYY", "YYYY/MM/DD" diff --git a/apps/www/src/content/docs/components/chip/props.ts b/apps/www/src/content/docs/components/chip/props.ts index 09aff3b13..13ca6d5c9 100644 --- a/apps/www/src/content/docs/components/chip/props.ts +++ b/apps/www/src/content/docs/components/chip/props.ts @@ -31,6 +31,9 @@ export interface ChipProps { /** Callback function when dismiss button is clicked */ onDismiss?: () => void; + /** Disables the chip and its dismiss button */ + disabled?: boolean; + /** Content to display inside the chip */ children?: React.ReactNode; diff --git a/apps/www/src/content/docs/components/code-block/index.mdx b/apps/www/src/content/docs/components/code-block/index.mdx index 9a044bdd4..95ca9acb1 100644 --- a/apps/www/src/content/docs/components/code-block/index.mdx +++ b/apps/www/src/content/docs/components/code-block/index.mdx @@ -111,7 +111,7 @@ Renders a text label displayed in the header. ### LanguageSelect -Renders a language selection dropdown container. +Renders a language selection dropdown container. It accepts the props of a single-selection `Select` root. diff --git a/apps/www/src/content/docs/components/code-block/props.ts b/apps/www/src/content/docs/components/code-block/props.ts index 397d4996d..6d4928bef 100644 --- a/apps/www/src/content/docs/components/code-block/props.ts +++ b/apps/www/src/content/docs/components/code-block/props.ts @@ -119,12 +119,28 @@ export interface CodeBlockLanguageSelectProps { /** * Available languages for selection */ - children: ReactNode; + children?: ReactNode; /** - * Additional CSS class name + * The controlled open state of the dropdown */ - className?: string; + open?: boolean; + + /** + * The initial open state when uncontrolled + * @defaultValue false + */ + defaultOpen?: boolean; + + /** + * Callback fired when the open state changes + */ + onOpenChange?: (open: boolean) => void; + + /** + * Prevents the user from changing the language + */ + disabled?: boolean; } export interface CodeBlockLanguageSelectTriggerProps { diff --git a/apps/www/src/content/docs/components/field/props.ts b/apps/www/src/content/docs/components/field/props.ts index a7b4c0974..43a34f554 100644 --- a/apps/www/src/content/docs/components/field/props.ts +++ b/apps/www/src/content/docs/components/field/props.ts @@ -52,6 +52,17 @@ export interface FieldLabelProps { */ required?: boolean; + /** + * Text rendered next to the label when `required={false}`. + * @defaultValue "(optional)" + */ + optionalText?: string; + + /** + * Text rendered next to the label when `required={true}`. No indicator is rendered when it is omitted. + */ + requiredText?: string; + /** Additional CSS class names. */ className?: string; } diff --git a/apps/www/src/content/docs/components/floating-actions/props.ts b/apps/www/src/content/docs/components/floating-actions/props.ts index 630583412..e1f1f7af8 100644 --- a/apps/www/src/content/docs/components/floating-actions/props.ts +++ b/apps/www/src/content/docs/components/floating-actions/props.ts @@ -47,6 +47,12 @@ export interface FloatingActionsSeparatorProps { */ size?: 'small' | 'half' | 'full'; + /** + * Hides the separator from assistive technology. + * @defaultValue false + */ + decorative?: boolean; + /** Additional CSS class names. */ className?: string; diff --git a/apps/www/src/content/docs/components/indicator/index.mdx b/apps/www/src/content/docs/components/indicator/index.mdx index 6f2620720..8518ee8e4 100644 --- a/apps/www/src/content/docs/components/indicator/index.mdx +++ b/apps/www/src/content/docs/components/indicator/index.mdx @@ -76,7 +76,7 @@ The Indicator component includes several accessibility features: - Uses `role="status"` to indicate its purpose to screen readers - Provides appropriate `aria-label` based on the content: - - Uses custom `ariaLabel` prop if provided + - Uses custom `aria-label` prop if provided - Falls back to the label text if available - Uses a default "indicator" if neither is provided - Hides decorative dot from screen readers when no label is present diff --git a/apps/www/src/content/docs/components/indicator/props.ts b/apps/www/src/content/docs/components/indicator/props.ts index 96c6f13b3..df10960e3 100644 --- a/apps/www/src/content/docs/components/indicator/props.ts +++ b/apps/www/src/content/docs/components/indicator/props.ts @@ -15,7 +15,7 @@ export interface IndicatorProps { pulse?: boolean; /** Optional custom description for screen readers */ - ariaLabel?: string; + 'aria-label'?: string; /** The content to show the indicator on */ children: React.ReactNode; diff --git a/apps/www/src/content/docs/components/list/demo.ts b/apps/www/src/content/docs/components/list/demo.ts index 638f9e5a1..23075ad44 100644 --- a/apps/www/src/content/docs/components/list/demo.ts +++ b/apps/www/src/content/docs/components/list/demo.ts @@ -6,15 +6,15 @@ export const preview = { User Information - + Status Active - + Type Premium Account - + Created April 24, 2024 @@ -27,28 +27,10 @@ export const basicDemo = { code: ` User Information - + Status Active ; ` }; - -export const alignDemo = { - type: 'code', - code: ` - - Deployment - - Status - Succeeded - - - Notes - - Rolled out to three regions. Two nodes were drained and replaced during the rollout. - - -` -}; diff --git a/apps/www/src/content/docs/components/list/index.mdx b/apps/www/src/content/docs/components/list/index.mdx index 96ef76fdf..361cd4e3f 100644 --- a/apps/www/src/content/docs/components/list/index.mdx +++ b/apps/www/src/content/docs/components/list/index.mdx @@ -5,7 +5,6 @@ source: packages/react/components/list --- import { basicDemo, preview, - alignDemo, } from "./demo.ts"; @@ -36,12 +35,6 @@ A `Header` labels the group, then each `Item` pairs a `Label` with its `Value`. -### Aligning rows - -`align` on an `Item` controls how the label sits against its value. `center` suits one-line values; switch to `start` when the value wraps, so the label stays level with the first line rather than floating in the middle. - - - ## API Reference Each item holds an aligned label and value, with an optional header above them. diff --git a/apps/www/src/content/docs/components/list/props.ts b/apps/www/src/content/docs/components/list/props.ts index 7fd35a1eb..ab013dae7 100644 --- a/apps/www/src/content/docs/components/list/props.ts +++ b/apps/www/src/content/docs/components/list/props.ts @@ -1,4 +1,7 @@ export interface ListRootProps { + /** List items and an optional header. */ + children: React.ReactNode; + /** Additional CSS class names. */ className?: string; } @@ -18,12 +21,6 @@ export interface ListHeaderProps { } export interface ListItemProps { - /** - * Alignment of the item content. - * @default "start" - */ - align?: 'start' | 'center' | 'end'; - /** Content to be displayed in the item. */ children?: React.ReactNode; diff --git a/apps/www/src/content/docs/components/select/props.ts b/apps/www/src/content/docs/components/select/props.ts index 80ddce754..1a2006ecb 100644 --- a/apps/www/src/content/docs/components/select/props.ts +++ b/apps/www/src/content/docs/components/select/props.ts @@ -93,6 +93,9 @@ export interface SelectItemProps { /** The value of the item. */ value: string; + /** Icon rendered before the item text. */ + leadingIcon?: React.ReactNode; + /** Additional CSS class names. */ className?: string; } diff --git a/apps/www/src/content/docs/components/toast/props.ts b/apps/www/src/content/docs/components/toast/props.ts index ebf6970a0..67c862cf9 100644 --- a/apps/www/src/content/docs/components/toast/props.ts +++ b/apps/www/src/content/docs/components/toast/props.ts @@ -23,6 +23,11 @@ export interface ToastProviderProps { */ timeout?: number; + /** + * Toast manager instance. Defaults to the exported `toastManager`. Pass one from `Toast.createToastManager()` to scope toasts to this provider. + */ + toastManager?: CreateToastManagerReturn; + children?: React.ReactNode; } From eb767c238be6b6fbb66058fc14578496d18efcc8 Mon Sep 17 00:00:00 2001 From: Shreyag02 Date: Wed, 14 Oct 2026 15:15:53 +0530 Subject: [PATCH 02/19] fix: [docs] list the props each component declares --- .../docs/components/breadcrumb/props.ts | 8 ++--- .../content/docs/components/callout/props.ts | 3 ++ .../docs/components/icon-button/props.ts | 3 ++ .../content/docs/components/search/props.ts | 6 ++++ .../content/docs/components/select/props.ts | 35 +++++++++++++++++++ apps/www/src/content/docs/dataview/props.ts | 33 ++++++++++++++++- .../src/content/docs/theme/overview/props.ts | 16 +++++++++ .../components/code-block/code-block-root.tsx | 1 + .../data-view/components/filters.tsx | 1 + .../react/components/indicator/indicator.tsx | 1 + packages/react/components/menu/menu-root.tsx | 3 ++ 11 files changed, 105 insertions(+), 5 deletions(-) diff --git a/apps/www/src/content/docs/components/breadcrumb/props.ts b/apps/www/src/content/docs/components/breadcrumb/props.ts index eba73e64f..3f271581b 100644 --- a/apps/www/src/content/docs/components/breadcrumb/props.ts +++ b/apps/www/src/content/docs/components/breadcrumb/props.ts @@ -1,16 +1,16 @@ import { ReactElement, ReactNode } from 'react'; export interface BreadcrumbItem { - /** Text to display for the item */ - label: string; + /** Content of the item, usually its text */ + children?: ReactNode; /** URL for the item link */ href?: string; - /** Optional icon element to display before the label */ + /** Optional icon element to display before the content */ leadingIcon?: ReactNode; - /** Optional icon element to display after the label */ + /** Optional icon element to display after the content */ trailingIcon?: ReactNode; /** diff --git a/apps/www/src/content/docs/components/callout/props.ts b/apps/www/src/content/docs/components/callout/props.ts index e9d09584c..205c19946 100644 --- a/apps/www/src/content/docs/components/callout/props.ts +++ b/apps/www/src/content/docs/components/callout/props.ts @@ -51,6 +51,9 @@ export interface CalloutProps { /** Additional CSS class names */ className?: string; + /** Inline styles for the callout */ + style?: React.CSSProperties; + /** * Corner radius for this callout only. Overrides the theme's `radius`. * @defaultValue The theme's `radius` diff --git a/apps/www/src/content/docs/components/icon-button/props.ts b/apps/www/src/content/docs/components/icon-button/props.ts index 25c81193a..453536ae3 100644 --- a/apps/www/src/content/docs/components/icon-button/props.ts +++ b/apps/www/src/content/docs/components/icon-button/props.ts @@ -52,4 +52,7 @@ export interface IconButtonProps { * @defaultValue The theme's `radius` */ radius?: 'none' | 'small' | 'medium' | 'large' | 'full'; + + /** Accessible name for the button. */ + 'aria-label'?: string; } diff --git a/apps/www/src/content/docs/components/search/props.ts b/apps/www/src/content/docs/components/search/props.ts index 91fff7996..efd6491cd 100644 --- a/apps/www/src/content/docs/components/search/props.ts +++ b/apps/www/src/content/docs/components/search/props.ts @@ -5,6 +5,12 @@ export interface SearchProps { */ size?: 'small' | 'large'; + /** + * Visual variant of the input. + * @default "default" + */ + variant?: 'default' | 'borderless'; + /** Placeholder text for the input. */ placeholder?: string; diff --git a/apps/www/src/content/docs/components/select/props.ts b/apps/www/src/content/docs/components/select/props.ts index 1a2006ecb..da95234a0 100644 --- a/apps/www/src/content/docs/components/select/props.ts +++ b/apps/www/src/content/docs/components/select/props.ts @@ -1,4 +1,36 @@ export interface SelectRootProps { + /** The selected value. An array when `multiple` is set. */ + value?: string | string[]; + + /** The value selected on first render when `value` is not set. An array when `multiple` is set. */ + defaultValue?: string | string[]; + + /** Called when the selection changes. Receives an array when `multiple` is set. */ + onValueChange?: (value: string | string[]) => void; + + /** Whether the list is open. */ + open?: boolean; + + /** Whether the list is open on first render when `open` is not set. + * @default false + */ + defaultOpen?: boolean; + + /** Called when the list opens or closes. */ + onOpenChange?: (open: boolean) => void; + + /** Whether the select is disabled. */ + disabled?: boolean; + + /** Whether a value is required. Defaults to the `required` of the surrounding `Field`. */ + required?: boolean; + + /** Name of the field when the select is submitted with a form. */ + name?: string; + + /** The select's parts, such as `Select.Trigger` and `Select.Content`. */ + children?: React.ReactNode; + /** Enables multiple selection. * When enabled, value, onValueChange, and defaultValue will be an array of strings. * @default false @@ -25,6 +57,9 @@ export interface SelectRootProps { /** Callback fired when the search value changes */ onSearch?: (value: string) => void; + + /** All item values. In autocomplete mode, setting it turns off the filtering of `Select.Item` children. */ + items?: string[]; } export interface SelectTriggerProps { diff --git a/apps/www/src/content/docs/dataview/props.ts b/apps/www/src/content/docs/dataview/props.ts index 39513c39b..3259d7528 100644 --- a/apps/www/src/content/docs/dataview/props.ts +++ b/apps/www/src/content/docs/dataview/props.ts @@ -1,4 +1,4 @@ -import { ReactNode, RefObject } from 'react'; +import { CSSProperties, ReactNode, RefObject } from 'react'; // Documentation-only placeholders so `auto-type-table` can render the public // API without surfacing real generics (TData is shown as `T` for readability). @@ -74,6 +74,9 @@ export interface DataViewProps { * Keeps the wire format (`group_by: string[]`) unchanged. */ groupByResolvers?: Record string>; + + /** The DataView's toolbar, renderers and other parts. */ + children?: ReactNode; } export interface DataViewField { @@ -120,6 +123,27 @@ export interface DataViewField { * takes no section. */ groupOrder?: string[]; + + /** + * Value type of a `select` or `multiselect` filter. + * @defaultValue "string" + */ + dataType?: 'string' | 'number' | 'boolean'; + + /** + * Value a new filter on this field starts with. + * @defaultValue today for `date`, the first option for `select`, otherwise `""` + */ + defaultFilterValue?: unknown; + + /** Props for the filter's control. `select` is passed to the filter's `Select`. */ + filterProps?: { select?: Record }; + + /** + * Count shown next to each group header when `showGroupCount` is on, by raw group value. + * @defaultValue the group's row count + */ + groupCountMap?: Record; } export interface DataViewListProps { @@ -181,6 +205,9 @@ export interface DataViewListColumn { * @defaultValue "1fr" */ width?: string | number; + + /** Inline styles for the column's cells and its header cell. */ + styles?: { cell?: CSSProperties; header?: CSSProperties }; } /** Date inputs accepted by Timeline props and row fields. */ @@ -419,12 +446,16 @@ export interface DataViewDisplayAccessProps { export interface DataViewEmptyStateProps { /** Restrict to a specific view's `name`. */ forView?: string; + /** Additional CSS class names. */ + className?: string; children: ReactNode; } export interface DataViewZeroStateProps { /** Restrict to a specific view's `name`. */ forView?: string; + /** Additional CSS class names. */ + className?: string; children: ReactNode; } diff --git a/apps/www/src/content/docs/theme/overview/props.ts b/apps/www/src/content/docs/theme/overview/props.ts index 8d0319859..a4938aa79 100644 --- a/apps/www/src/content/docs/theme/overview/props.ts +++ b/apps/www/src/content/docs/theme/overview/props.ts @@ -1,3 +1,5 @@ +import type { IconOptions } from '../icons/props'; + export type Appearance = 'light' | 'dark'; export type AppearanceSetting = 'light' | 'dark' | 'system'; export type AccentColor = 'indigo' | 'orange' | 'mint'; @@ -109,6 +111,15 @@ export type ThemeProps = { className?: string; children?: React.ReactNode; + + /** Icon overrides: `components` replaces icons by key, and `props` applies to every icon. */ + icons?: IconOptions; + + /** Ref to the theme's element: its `div`, or the element passed to `render`. */ + ref?: React.Ref; + + /** Inline styles for the theme's element. */ + style?: React.CSSProperties; }; /** The theme, as read and driven from anywhere inside a provider. */ @@ -139,4 +150,9 @@ export type ThemeSwitcherProps = { * @defaultValue "nearest" */ target?: 'nearest' | 'root'; + /** + * Accessible name for the button. + * @defaultValue "Switch to light theme" or "Switch to dark theme", by the current appearance + */ + 'aria-label'?: string; }; diff --git a/packages/react/components/code-block/code-block-root.tsx b/packages/react/components/code-block/code-block-root.tsx index 3d0d43e30..4eb187006 100644 --- a/packages/react/components/code-block/code-block-root.tsx +++ b/packages/react/components/code-block/code-block-root.tsx @@ -40,6 +40,7 @@ export interface CodeBlockProps extends ComponentProps<'div'>, CodeBlockCommonProps { defaultValue?: string; + /** @deprecated Has no effect. */ maxHeight?: string | number; onValueChange?: (value: string) => void; defaultCollapsed?: boolean; diff --git a/packages/react/components/data-view/components/filters.tsx b/packages/react/components/data-view/components/filters.tsx index 28f6a5cdc..621d68878 100644 --- a/packages/react/components/data-view/components/filters.tsx +++ b/packages/react/components/data-view/components/filters.tsx @@ -103,6 +103,7 @@ function AddFilter({ } export interface DataViewFiltersProps extends PositionerProps { + /** @deprecated Use the `data-slot` selectors named on each key instead. */ classNames?: { /** @deprecated Use `[data-slot="filter-chip"]` instead. */ filterChips?: string; diff --git a/packages/react/components/indicator/indicator.tsx b/packages/react/components/indicator/indicator.tsx index e6dbbe29d..dc8109cb4 100644 --- a/packages/react/components/indicator/indicator.tsx +++ b/packages/react/components/indicator/indicator.tsx @@ -29,6 +29,7 @@ export interface IndicatorProps pulse?: boolean; children?: ReactNode; 'aria-label'?: string; + /** @deprecated Use `[data-slot="indicator"]` instead. */ classNames?: { /** @deprecated Use `[data-slot="indicator"]` instead. */ container?: string; diff --git a/packages/react/components/menu/menu-root.tsx b/packages/react/components/menu/menu-root.tsx index 3af2ef47e..9e9084cf9 100644 --- a/packages/react/components/menu/menu-root.tsx +++ b/packages/react/components/menu/menu-root.tsx @@ -13,8 +13,11 @@ interface CommonProps { autocomplete?: boolean; autocompleteMode?: 'auto' | 'manual'; inputValue?: string; + /** @internal Set by `Menu` and `Menu.Submenu` for their parts. */ inputRef?: React.RefObject; + /** @internal Set by `Menu` and `Menu.Submenu` for their parts. */ contentRef?: React.RefObject; + /** @internal Set by `Menu` and `Menu.Submenu` for their parts. */ isInitialRender?: React.RefObject; open?: boolean; } From ea3d801863a23296cd5e69a7a39e2554983c5a81 Mon Sep 17 00:00:00 2001 From: Shreyag02 Date: Thu, 15 Oct 2026 18:34:40 +0530 Subject: [PATCH 03/19] fix: [docs] correct required props, defaults and examples --- apps/www/src/content/docs/components/breadcrumb/index.mdx | 2 +- apps/www/src/content/docs/components/calendar/props.ts | 2 +- apps/www/src/content/docs/components/callout/props.ts | 2 +- apps/www/src/content/docs/components/chip/props.ts | 2 +- apps/www/src/content/docs/components/field/props.ts | 3 +-- apps/www/src/content/docs/components/indicator/index.mdx | 2 +- apps/www/src/content/docs/components/indicator/props.ts | 4 ++-- apps/www/src/content/docs/components/list/props.ts | 8 ++++---- apps/www/src/content/docs/components/select/props.ts | 2 +- apps/www/src/content/docs/components/toast/index.mdx | 6 +++--- apps/www/src/content/docs/theme/overview/props.ts | 2 +- packages/react/components/menu/menu-root.tsx | 6 +++--- 12 files changed, 20 insertions(+), 21 deletions(-) diff --git a/apps/www/src/content/docs/components/breadcrumb/index.mdx b/apps/www/src/content/docs/components/breadcrumb/index.mdx index cc8b5e010..c3e401d48 100644 --- a/apps/www/src/content/docs/components/breadcrumb/index.mdx +++ b/apps/www/src/content/docs/components/breadcrumb/index.mdx @@ -58,7 +58,7 @@ Use the `Breadcrumb.Ellipsis` component to truncate the breadcrumb trail when yo ### Icons -Breadcrumb items can include icons via `leadingIcon` (before the label) or `trailingIcon` (after the label), either alongside text or as standalone elements. +Breadcrumb items can include icons via `leadingIcon` (before the content) or `trailingIcon` (after the content), either alongside text or as standalone elements. diff --git a/apps/www/src/content/docs/components/calendar/props.ts b/apps/www/src/content/docs/components/calendar/props.ts index 6d76f01ec..f5b3e24fd 100644 --- a/apps/www/src/content/docs/components/calendar/props.ts +++ b/apps/www/src/content/docs/components/calendar/props.ts @@ -138,7 +138,7 @@ export interface CalendarProps { export interface RangePickerProps { /** - * Additional CSS class names for the group that holds the start and end inputs. + * Additional CSS class names for the group that holds the start and end inputs. Ignored when `children` is set. */ pickerGroupClassName?: string; diff --git a/apps/www/src/content/docs/components/callout/props.ts b/apps/www/src/content/docs/components/callout/props.ts index 205c19946..1913f7ed6 100644 --- a/apps/www/src/content/docs/components/callout/props.ts +++ b/apps/www/src/content/docs/components/callout/props.ts @@ -46,7 +46,7 @@ export interface CalloutProps { onDismiss?: () => void; /** Text content of the callout */ - children?: React.ReactNode; + children: React.ReactNode; /** Additional CSS class names */ className?: string; diff --git a/apps/www/src/content/docs/components/chip/props.ts b/apps/www/src/content/docs/components/chip/props.ts index 13ca6d5c9..c8fa0066e 100644 --- a/apps/www/src/content/docs/components/chip/props.ts +++ b/apps/www/src/content/docs/components/chip/props.ts @@ -31,7 +31,7 @@ export interface ChipProps { /** Callback function when dismiss button is clicked */ onDismiss?: () => void; - /** Disables the chip and its dismiss button */ + /** Disables the chip and blocks pointer clicks on it */ disabled?: boolean; /** Content to display inside the chip */ diff --git a/apps/www/src/content/docs/components/field/props.ts b/apps/www/src/content/docs/components/field/props.ts index 43a34f554..733f3df51 100644 --- a/apps/www/src/content/docs/components/field/props.ts +++ b/apps/www/src/content/docs/components/field/props.ts @@ -47,8 +47,7 @@ export interface FieldProps { export interface FieldLabelProps { /** - * Whether the field is required. When false, shows an (optional) indicator next to the label. - * @defaultValue true + * Whether the field is required. `true` shows `requiredText`, `false` shows `optionalText`, and nothing is shown when it is not set. */ required?: boolean; diff --git a/apps/www/src/content/docs/components/indicator/index.mdx b/apps/www/src/content/docs/components/indicator/index.mdx index 8518ee8e4..906677a81 100644 --- a/apps/www/src/content/docs/components/indicator/index.mdx +++ b/apps/www/src/content/docs/components/indicator/index.mdx @@ -78,7 +78,7 @@ The Indicator component includes several accessibility features: - Provides appropriate `aria-label` based on the content: - Uses custom `aria-label` prop if provided - Falls back to the label text if available - - Uses a default "indicator" if neither is provided + - Uses `" indicator"`, for example `"accent indicator"`, if neither is provided - Hides decorative dot from screen readers when no label is present Example with custom aria label: diff --git a/apps/www/src/content/docs/components/indicator/props.ts b/apps/www/src/content/docs/components/indicator/props.ts index df10960e3..cf13ebf7d 100644 --- a/apps/www/src/content/docs/components/indicator/props.ts +++ b/apps/www/src/content/docs/components/indicator/props.ts @@ -18,8 +18,8 @@ export interface IndicatorProps { 'aria-label'?: string; /** The content to show the indicator on */ - children: React.ReactNode; + children?: React.ReactNode; - /** Additional CSS class names */ + /** Additional CSS class names for the badge */ className?: string; } diff --git a/apps/www/src/content/docs/components/list/props.ts b/apps/www/src/content/docs/components/list/props.ts index ab013dae7..0d553025b 100644 --- a/apps/www/src/content/docs/components/list/props.ts +++ b/apps/www/src/content/docs/components/list/props.ts @@ -8,7 +8,7 @@ export interface ListRootProps { export interface ListHeaderProps { /** Content to be displayed in the header. */ - children?: React.ReactNode; + children: React.ReactNode; /** * Heading level set as `aria-level` on the underlying heading element. @@ -22,7 +22,7 @@ export interface ListHeaderProps { export interface ListItemProps { /** Content to be displayed in the item. */ - children?: React.ReactNode; + children: React.ReactNode; /** Additional CSS class names. */ className?: string; @@ -30,7 +30,7 @@ export interface ListItemProps { export interface ListLabelProps { /** Content to be displayed in the label. */ - children?: React.ReactNode; + children: React.ReactNode; /** Additional CSS class names. */ className?: string; @@ -38,7 +38,7 @@ export interface ListLabelProps { export interface ListValueProps { /** Content to be displayed in the value. */ - children?: React.ReactNode; + children: React.ReactNode; /** Additional CSS class names. */ className?: string; diff --git a/apps/www/src/content/docs/components/select/props.ts b/apps/www/src/content/docs/components/select/props.ts index da95234a0..c0220ae8d 100644 --- a/apps/www/src/content/docs/components/select/props.ts +++ b/apps/www/src/content/docs/components/select/props.ts @@ -58,7 +58,7 @@ export interface SelectRootProps { /** Callback fired when the search value changes */ onSearch?: (value: string) => void; - /** All item values. In autocomplete mode, setting it turns off the filtering of `Select.Item` children. */ + /** All item values. In autocomplete mode, Base UI filters this list instead of the `Select.Item` children. It has no effect without `autocomplete`. */ items?: string[]; } diff --git a/apps/www/src/content/docs/components/toast/index.mdx b/apps/www/src/content/docs/components/toast/index.mdx index e5386a71c..c2cbe7277 100644 --- a/apps/www/src/content/docs/components/toast/index.mdx +++ b/apps/www/src/content/docs/components/toast/index.mdx @@ -104,14 +104,14 @@ Creates a new toast and returns its unique ID. If `id` matches an open toast, it -### createToastManager() +### Toast.createToastManager() Factory that returns a fresh toast manager. The exported singleton `toastManager` is one such instance created at module load. Pass a custom manager to `` to scope toasts to that provider. ```tsx -import { Toast, createToastManager } from '@raystack/apsara' +import { Toast } from '@raystack/apsara' -const manager = createToastManager() +const manager = Toast.createToastManager() diff --git a/apps/www/src/content/docs/theme/overview/props.ts b/apps/www/src/content/docs/theme/overview/props.ts index a4938aa79..86d68fb2a 100644 --- a/apps/www/src/content/docs/theme/overview/props.ts +++ b/apps/www/src/content/docs/theme/overview/props.ts @@ -152,7 +152,7 @@ export type ThemeSwitcherProps = { target?: 'nearest' | 'root'; /** * Accessible name for the button. - * @defaultValue "Switch to light theme" or "Switch to dark theme", by the current appearance + * @defaultValue "Switch to light theme" when the target theme is dark, otherwise "Switch to dark theme" */ 'aria-label'?: string; }; diff --git a/packages/react/components/menu/menu-root.tsx b/packages/react/components/menu/menu-root.tsx index 9e9084cf9..f0febec24 100644 --- a/packages/react/components/menu/menu-root.tsx +++ b/packages/react/components/menu/menu-root.tsx @@ -13,11 +13,11 @@ interface CommonProps { autocomplete?: boolean; autocompleteMode?: 'auto' | 'manual'; inputValue?: string; - /** @internal Set by `Menu` and `Menu.Submenu` for their parts. */ + /** @internal Set by the menu and context menu roots and submenus for their parts. */ inputRef?: React.RefObject; - /** @internal Set by `Menu` and `Menu.Submenu` for their parts. */ + /** @internal Set by the menu and context menu roots and submenus for their parts. */ contentRef?: React.RefObject; - /** @internal Set by `Menu` and `Menu.Submenu` for their parts. */ + /** @internal Set by the menu and context menu roots and submenus for their parts. */ isInitialRender?: React.RefObject; open?: boolean; } From ab4d9989c37461565584bd2fd9aee7654704a217 Mon Sep 17 00:00:00 2001 From: Shreyag02 Date: Fri, 16 Oct 2026 00:51:06 +0530 Subject: [PATCH 04/19] fix: [docs] document button style, search placeholder and select details --- apps/www/src/content/docs/components/button/props.ts | 3 +++ apps/www/src/content/docs/components/search/props.ts | 5 ++++- apps/www/src/content/docs/components/select/props.ts | 4 ++-- apps/www/src/content/docs/dataview/props.ts | 8 +++++++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/apps/www/src/content/docs/components/button/props.ts b/apps/www/src/content/docs/components/button/props.ts index f08e8cdf1..3af27f246 100644 --- a/apps/www/src/content/docs/components/button/props.ts +++ b/apps/www/src/content/docs/components/button/props.ts @@ -62,6 +62,9 @@ export type ButtonProps = { /** Additional CSS class names */ className?: string; + /** Inline styles for the button */ + style?: React.CSSProperties; + /** * Corner radius for this button only. Overrides the theme's `radius`. * @defaultValue The theme's `radius` diff --git a/apps/www/src/content/docs/components/search/props.ts b/apps/www/src/content/docs/components/search/props.ts index efd6491cd..246b76a52 100644 --- a/apps/www/src/content/docs/components/search/props.ts +++ b/apps/www/src/content/docs/components/search/props.ts @@ -11,7 +11,10 @@ export interface SearchProps { */ variant?: 'default' | 'borderless'; - /** Placeholder text for the input. */ + /** + * Placeholder text for the input. + * @default "Search" + */ placeholder?: string; /** Whether the search input is disabled. */ diff --git a/apps/www/src/content/docs/components/select/props.ts b/apps/www/src/content/docs/components/select/props.ts index c0220ae8d..fcc2553be 100644 --- a/apps/www/src/content/docs/components/select/props.ts +++ b/apps/www/src/content/docs/components/select/props.ts @@ -22,7 +22,7 @@ export interface SelectRootProps { /** Whether the select is disabled. */ disabled?: boolean; - /** Whether a value is required. Defaults to the `required` of the surrounding `Field`. */ + /** Whether a value is required. Defaults to the `required` of the surrounding `Field`, which is `true` unless the `Field` sets `required={false}`. */ required?: boolean; /** Name of the field when the select is submitted with a form. */ @@ -128,7 +128,7 @@ export interface SelectItemProps { /** The value of the item. */ value: string; - /** Icon rendered before the item text. */ + /** Icon rendered before the item text. Rendered only when `children` is a string. */ leadingIcon?: React.ReactNode; /** Additional CSS class names. */ diff --git a/apps/www/src/content/docs/dataview/props.ts b/apps/www/src/content/docs/dataview/props.ts index 3259d7528..b632f1b63 100644 --- a/apps/www/src/content/docs/dataview/props.ts +++ b/apps/www/src/content/docs/dataview/props.ts @@ -1,4 +1,5 @@ import { CSSProperties, ReactNode, RefObject } from 'react'; +import type { SelectRootProps } from '../components/select/props'; // Documentation-only placeholders so `auto-type-table` can render the public // API without surfacing real generics (TData is shown as `T` for readability). @@ -137,7 +138,12 @@ export interface DataViewField { defaultFilterValue?: unknown; /** Props for the filter's control. `select` is passed to the filter's `Select`. */ - filterProps?: { select?: Record }; + filterProps?: { + select?: Omit< + SelectRootProps, + 'multiple' | 'value' | 'defaultValue' | 'onValueChange' + >; + }; /** * Count shown next to each group header when `showGroupCount` is on, by raw group value. From 5aab5628ad2d97c02ebe39f13d434c09b7a2e37f Mon Sep 17 00:00:00 2001 From: Shreyag02 Date: Fri, 16 Oct 2026 01:21:02 +0530 Subject: [PATCH 05/19] fix: [docs] remove extra JSDoc tags and wording changes --- .../src/content/docs/components/breadcrumb/index.mdx | 2 +- .../src/content/docs/components/breadcrumb/props.ts | 4 ++-- .../src/content/docs/components/code-block/index.mdx | 2 +- apps/www/src/content/docs/components/toast/index.mdx | 2 +- apps/www/src/content/docs/dataview/props.ts | 10 ++-------- .../react/components/data-view/components/filters.tsx | 1 - packages/react/components/indicator/indicator.tsx | 1 - packages/react/components/menu/menu-root.tsx | 3 --- 8 files changed, 7 insertions(+), 18 deletions(-) diff --git a/apps/www/src/content/docs/components/breadcrumb/index.mdx b/apps/www/src/content/docs/components/breadcrumb/index.mdx index c3e401d48..cc8b5e010 100644 --- a/apps/www/src/content/docs/components/breadcrumb/index.mdx +++ b/apps/www/src/content/docs/components/breadcrumb/index.mdx @@ -58,7 +58,7 @@ Use the `Breadcrumb.Ellipsis` component to truncate the breadcrumb trail when yo ### Icons -Breadcrumb items can include icons via `leadingIcon` (before the content) or `trailingIcon` (after the content), either alongside text or as standalone elements. +Breadcrumb items can include icons via `leadingIcon` (before the label) or `trailingIcon` (after the label), either alongside text or as standalone elements. diff --git a/apps/www/src/content/docs/components/breadcrumb/props.ts b/apps/www/src/content/docs/components/breadcrumb/props.ts index 3f271581b..7affca9a1 100644 --- a/apps/www/src/content/docs/components/breadcrumb/props.ts +++ b/apps/www/src/content/docs/components/breadcrumb/props.ts @@ -7,10 +7,10 @@ export interface BreadcrumbItem { /** URL for the item link */ href?: string; - /** Optional icon element to display before the content */ + /** Optional icon element to display before the label */ leadingIcon?: ReactNode; - /** Optional icon element to display after the content */ + /** Optional icon element to display after the label */ trailingIcon?: ReactNode; /** diff --git a/apps/www/src/content/docs/components/code-block/index.mdx b/apps/www/src/content/docs/components/code-block/index.mdx index 95ca9acb1..882896b40 100644 --- a/apps/www/src/content/docs/components/code-block/index.mdx +++ b/apps/www/src/content/docs/components/code-block/index.mdx @@ -111,7 +111,7 @@ Renders a text label displayed in the header. ### LanguageSelect -Renders a language selection dropdown container. It accepts the props of a single-selection `Select` root. +Renders a language selection dropdown container. It accepts the props of a single-selection `Select` root, except `value`, `defaultValue` and `onValueChange`. Set those on the `CodeBlock` root. diff --git a/apps/www/src/content/docs/components/toast/index.mdx b/apps/www/src/content/docs/components/toast/index.mdx index c2cbe7277..894f32f2d 100644 --- a/apps/www/src/content/docs/components/toast/index.mdx +++ b/apps/www/src/content/docs/components/toast/index.mdx @@ -104,7 +104,7 @@ Creates a new toast and returns its unique ID. If `id` matches an open toast, it -### Toast.createToastManager() +### createToastManager() Factory that returns a fresh toast manager. The exported singleton `toastManager` is one such instance created at module load. Pass a custom manager to `` to scope toasts to that provider. diff --git a/apps/www/src/content/docs/dataview/props.ts b/apps/www/src/content/docs/dataview/props.ts index b632f1b63..2cf8e3369 100644 --- a/apps/www/src/content/docs/dataview/props.ts +++ b/apps/www/src/content/docs/dataview/props.ts @@ -1,5 +1,4 @@ import { CSSProperties, ReactNode, RefObject } from 'react'; -import type { SelectRootProps } from '../components/select/props'; // Documentation-only placeholders so `auto-type-table` can render the public // API without surfacing real generics (TData is shown as `T` for readability). @@ -137,13 +136,8 @@ export interface DataViewField { */ defaultFilterValue?: unknown; - /** Props for the filter's control. `select` is passed to the filter's `Select`. */ - filterProps?: { - select?: Omit< - SelectRootProps, - 'multiple' | 'value' | 'defaultValue' | 'onValueChange' - >; - }; + /** Props for the filter's control. `select` takes the `Select` root props, without the value props, and is passed to the filter's `Select`. */ + filterProps?: { select?: Record }; /** * Count shown next to each group header when `showGroupCount` is on, by raw group value. diff --git a/packages/react/components/data-view/components/filters.tsx b/packages/react/components/data-view/components/filters.tsx index 621d68878..28f6a5cdc 100644 --- a/packages/react/components/data-view/components/filters.tsx +++ b/packages/react/components/data-view/components/filters.tsx @@ -103,7 +103,6 @@ function AddFilter({ } export interface DataViewFiltersProps extends PositionerProps { - /** @deprecated Use the `data-slot` selectors named on each key instead. */ classNames?: { /** @deprecated Use `[data-slot="filter-chip"]` instead. */ filterChips?: string; diff --git a/packages/react/components/indicator/indicator.tsx b/packages/react/components/indicator/indicator.tsx index dc8109cb4..e6dbbe29d 100644 --- a/packages/react/components/indicator/indicator.tsx +++ b/packages/react/components/indicator/indicator.tsx @@ -29,7 +29,6 @@ export interface IndicatorProps pulse?: boolean; children?: ReactNode; 'aria-label'?: string; - /** @deprecated Use `[data-slot="indicator"]` instead. */ classNames?: { /** @deprecated Use `[data-slot="indicator"]` instead. */ container?: string; diff --git a/packages/react/components/menu/menu-root.tsx b/packages/react/components/menu/menu-root.tsx index f0febec24..3af2ef47e 100644 --- a/packages/react/components/menu/menu-root.tsx +++ b/packages/react/components/menu/menu-root.tsx @@ -13,11 +13,8 @@ interface CommonProps { autocomplete?: boolean; autocompleteMode?: 'auto' | 'manual'; inputValue?: string; - /** @internal Set by the menu and context menu roots and submenus for their parts. */ inputRef?: React.RefObject; - /** @internal Set by the menu and context menu roots and submenus for their parts. */ contentRef?: React.RefObject; - /** @internal Set by the menu and context menu roots and submenus for their parts. */ isInitialRender?: React.RefObject; open?: boolean; } From dfb3fb22251859dd4882af93c043dc16c162264c Mon Sep 17 00:00:00 2001 From: Shreyag02 Date: Fri, 16 Oct 2026 01:42:20 +0530 Subject: [PATCH 06/19] fix: [docs] correct sidepanel, empty state, tooltip and preview card docs --- .../docs/components/empty-state/props.ts | 2 +- .../docs/components/preview-card/props.ts | 2 +- .../content/docs/components/sidepanel/demo.ts | 18 +++++++++--------- .../content/docs/components/sidepanel/props.ts | 2 +- .../content/docs/components/tooltip/props.ts | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/www/src/content/docs/components/empty-state/props.ts b/apps/www/src/content/docs/components/empty-state/props.ts index 5bbab566a..6a97e53d8 100644 --- a/apps/www/src/content/docs/components/empty-state/props.ts +++ b/apps/www/src/content/docs/components/empty-state/props.ts @@ -1,6 +1,6 @@ export interface EmptyStateProps { /** Icon to show in top of empty state */ - icon?: React.ReactNode; + icon: React.ReactNode; /** Primary heading message */ heading?: string; diff --git a/apps/www/src/content/docs/components/preview-card/props.ts b/apps/www/src/content/docs/components/preview-card/props.ts index 1445b6251..f4c8cd651 100644 --- a/apps/www/src/content/docs/components/preview-card/props.ts +++ b/apps/www/src/content/docs/components/preview-card/props.ts @@ -104,7 +104,7 @@ export interface PreviewCardContentProps { * May automatically change to avoid collisions. * @defaultValue 'bottom' */ - side?: 'top' | 'right' | 'bottom' | 'left'; + side?: 'top' | 'right' | 'bottom' | 'left' | 'inline-start' | 'inline-end'; /** * How to align the popup relative to the specified side. diff --git a/apps/www/src/content/docs/components/sidepanel/demo.ts b/apps/www/src/content/docs/components/sidepanel/demo.ts index 0b1cf1bdd..0630c5ef3 100644 --- a/apps/www/src/content/docs/components/sidepanel/demo.ts +++ b/apps/www/src/content/docs/components/sidepanel/demo.ts @@ -9,15 +9,15 @@ export const preview = { User Information - + Status Active - + Type Premium Account - + Created April 24, 2024 @@ -26,15 +26,15 @@ export const preview = { User Information - + Status Active - + Type Premium Account - + Created April 24, 2024 @@ -52,7 +52,7 @@ export const basicDemo = { User Information - + Status Active @@ -73,7 +73,7 @@ export const positionDemo = { User Information - + Status Active @@ -90,7 +90,7 @@ export const positionDemo = { User Information - + Status Active diff --git a/apps/www/src/content/docs/components/sidepanel/props.ts b/apps/www/src/content/docs/components/sidepanel/props.ts index 8c01c1e5f..dfcb8c04d 100644 --- a/apps/www/src/content/docs/components/sidepanel/props.ts +++ b/apps/www/src/content/docs/components/sidepanel/props.ts @@ -1,7 +1,7 @@ export interface SidePanelProps { /** * The side to position the panel. - * @default "left" + * @default "right" */ side?: 'left' | 'right'; diff --git a/apps/www/src/content/docs/components/tooltip/props.ts b/apps/www/src/content/docs/components/tooltip/props.ts index c9ec4deaf..ff6aa3af4 100644 --- a/apps/www/src/content/docs/components/tooltip/props.ts +++ b/apps/www/src/content/docs/components/tooltip/props.ts @@ -92,7 +92,7 @@ export interface TooltipContentProps { * Side placement of the tooltip * @default "top" */ - side?: 'top' | 'bottom' | 'left' | 'right'; + side?: 'top' | 'bottom' | 'left' | 'right' | 'inline-start' | 'inline-end'; /** * Alignment of the tooltip From 87a60c00bc34e78b70bb4d206c871801b572d214 Mon Sep 17 00:00:00 2001 From: Shreyag02 Date: Fri, 16 Oct 2026 01:55:39 +0530 Subject: [PATCH 07/19] fix: [docs] correct callback arguments, field error match, message slots and sidepanel source --- apps/www/src/content/docs/ai-elements/message/index.mdx | 3 ++- apps/www/src/content/docs/components/checkbox/props.ts | 2 +- apps/www/src/content/docs/components/field/props.ts | 2 +- apps/www/src/content/docs/components/number-field/props.ts | 2 +- apps/www/src/content/docs/components/sidepanel/index.mdx | 2 +- apps/www/src/content/docs/components/switch/props.ts | 2 +- apps/www/src/content/docs/components/toggle/props.ts | 4 ++-- 7 files changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/www/src/content/docs/ai-elements/message/index.mdx b/apps/www/src/content/docs/ai-elements/message/index.mdx index d89f4a808..44df422fb 100644 --- a/apps/www/src/content/docs/ai-elements/message/index.mdx +++ b/apps/www/src/content/docs/ai-elements/message/index.mdx @@ -101,7 +101,8 @@ Every rendered part carries a stable `data-slot` attribute for [styling and test | `message-group` | Wrapper around consecutive messages from one sender | | `message-avatar` | The sender avatar | | `message-header` | Row above the bubble, for sender name and timestamp | -| `message-content` | The bubble holding the message body | +| `message-content` | Column holding the message bubbles | +| `message-bubble` | The message surface | | `message-actions` | Action row revealed on the message | | `message-footer` | Row below the bubble | diff --git a/apps/www/src/content/docs/components/checkbox/props.ts b/apps/www/src/content/docs/components/checkbox/props.ts index 1d40d3887..58eb0927f 100644 --- a/apps/www/src/content/docs/components/checkbox/props.ts +++ b/apps/www/src/content/docs/components/checkbox/props.ts @@ -75,7 +75,7 @@ export interface CheckboxGroupProps { value?: string[]; /** Event handler called when the checked values change. */ - onValueChange?: (value: string[], event: Event) => void; + onValueChange?: (value: string[], eventDetails: unknown) => void; /** * All checkbox values in the group. Required when using a parent checkbox. diff --git a/apps/www/src/content/docs/components/field/props.ts b/apps/www/src/content/docs/components/field/props.ts index 733f3df51..e1be1d081 100644 --- a/apps/www/src/content/docs/components/field/props.ts +++ b/apps/www/src/content/docs/components/field/props.ts @@ -76,7 +76,7 @@ export interface FieldErrorProps { * Match a specific ValidityState property (e.g., "valueMissing", "typeMismatch", "customError") * or pass `true` to match any error. */ - match?: string | boolean; + match?: boolean | keyof ValidityState; /** Additional CSS class names. */ className?: string; diff --git a/apps/www/src/content/docs/components/number-field/props.ts b/apps/www/src/content/docs/components/number-field/props.ts index a87487d26..6a0bc47ff 100644 --- a/apps/www/src/content/docs/components/number-field/props.ts +++ b/apps/www/src/content/docs/components/number-field/props.ts @@ -9,7 +9,7 @@ export interface NumberFieldProps { defaultValue?: number; /** Event handler called when the value changes. */ - onValueChange?: (value: number | null, event: Event) => void; + onValueChange?: (value: number | null, eventDetails: unknown) => void; /** Minimum allowed value. */ min?: number; diff --git a/apps/www/src/content/docs/components/sidepanel/index.mdx b/apps/www/src/content/docs/components/sidepanel/index.mdx index 8b6fdc0f6..bd90be00c 100644 --- a/apps/www/src/content/docs/components/sidepanel/index.mdx +++ b/apps/www/src/content/docs/components/sidepanel/index.mdx @@ -1,7 +1,7 @@ --- title: Side Panel description: A flexible side panel component to place content on either side of the page. -source: packages/react/components/sidepanel +source: packages/react/components/side-panel --- import { basicDemo, positionDemo, preview } from "./demo.ts"; diff --git a/apps/www/src/content/docs/components/switch/props.ts b/apps/www/src/content/docs/components/switch/props.ts index baa6000c5..6419b78b4 100644 --- a/apps/www/src/content/docs/components/switch/props.ts +++ b/apps/www/src/content/docs/components/switch/props.ts @@ -6,7 +6,7 @@ export interface SwitchProps { defaultChecked?: boolean; /** Event handler called when the checked state changes. */ - onCheckedChange?: (checked: boolean, event: Event) => void; + onCheckedChange?: (checked: boolean, eventDetails: unknown) => void; /** When true, prevents the user from interacting with the switch. */ disabled?: boolean; diff --git a/apps/www/src/content/docs/components/toggle/props.ts b/apps/www/src/content/docs/components/toggle/props.ts index 52d943314..1225e7a4b 100644 --- a/apps/www/src/content/docs/components/toggle/props.ts +++ b/apps/www/src/content/docs/components/toggle/props.ts @@ -12,7 +12,7 @@ export interface ToggleProps { pressed?: boolean; /** Event handler called when the pressed state changes. */ - onPressedChange?: (pressed: boolean, event: Event) => void; + onPressedChange?: (pressed: boolean, eventDetails: unknown) => void; /** * The size of the toggle. @@ -50,7 +50,7 @@ export interface ToggleGroupProps { value?: string[]; /** Event handler called when the pressed values change. */ - onValueChange?: (value: string[], event: Event) => void; + onValueChange?: (value: string[], eventDetails: unknown) => void; /** * When true, multiple toggles can be pressed at the same time. From 55cd58e47ee98793dea709598f59018ad8c09347 Mon Sep 17 00:00:00 2001 From: Shreyag02 Date: Fri, 16 Oct 2026 02:07:33 +0530 Subject: [PATCH 08/19] fix: [docs] document drawer, popover and code block parts --- .../src/content/docs/components/code-block/index.mdx | 11 +++++++++++ .../www/src/content/docs/components/drawer/index.mdx | 12 ++++++++++++ apps/www/src/content/docs/components/drawer/props.ts | 5 ++++- .../src/content/docs/components/popover/index.mdx | 4 ++++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/apps/www/src/content/docs/components/code-block/index.mdx b/apps/www/src/content/docs/components/code-block/index.mdx index 882896b40..9c22f0753 100644 --- a/apps/www/src/content/docs/components/code-block/index.mdx +++ b/apps/www/src/content/docs/components/code-block/index.mdx @@ -28,6 +28,9 @@ import { CodeBlock } from '@raystack/apsara' + + + @@ -121,6 +124,14 @@ Renders the button that opens language selection. +### LanguageSelectContent + +Renders the dropdown that lists the languages. It is [`Select.Content`](/docs/components/select) and takes the same props. + +### LanguageSelectItem + +Renders one language in the dropdown. Selecting it shows the `CodeBlock.Code` with the same `value`, or the same `language` when that block sets no `value`. It is [`Select.Item`](/docs/components/select) and takes the same props. + ### CopyButton Renders a button for copying code to clipboard. diff --git a/apps/www/src/content/docs/components/drawer/index.mdx b/apps/www/src/content/docs/components/drawer/index.mdx index 4c11cf1c6..9fe36a213 100644 --- a/apps/www/src/content/docs/components/drawer/index.mdx +++ b/apps/www/src/content/docs/components/drawer/index.mdx @@ -61,6 +61,18 @@ Groups all parts of the drawer. The `side` prop determines both the slide direct +### Trigger + +Renders the button that opens the drawer. + +- Inherits all Base UI Drawer.Trigger props + +### Close + +Renders a button that closes the drawer. `Drawer.Content` already renders one unless `showCloseButton` is `false`. + +- Inherits all Base UI Drawer.Close props + ### Content Renders the drawer panel that slides in from a screen edge. diff --git a/apps/www/src/content/docs/components/drawer/props.ts b/apps/www/src/content/docs/components/drawer/props.ts index bff6148de..688f975a6 100644 --- a/apps/www/src/content/docs/components/drawer/props.ts +++ b/apps/www/src/content/docs/components/drawer/props.ts @@ -31,7 +31,10 @@ export interface DrawerContentProps { /** The direction from which the drawer appears. */ side?: 'top' | 'right' | 'bottom' | 'left'; - /** Whether to show the close button. */ + /** + * Whether to show the close button. + * @default true + */ showCloseButton?: boolean; /** diff --git a/apps/www/src/content/docs/components/popover/index.mdx b/apps/www/src/content/docs/components/popover/index.mdx index 8a0de78c7..934478ac2 100644 --- a/apps/www/src/content/docs/components/popover/index.mdx +++ b/apps/www/src/content/docs/components/popover/index.mdx @@ -67,6 +67,10 @@ Renders the popover content panel. +### Close + +Renders a button that closes the popover. It takes the Base UI `Popover.Close` props. + ### Trigger Renders the element that opens the popover. From 420abc5a8b14b911e68239370875d3e57e929316 Mon Sep 17 00:00:00 2001 From: Shreyag02 Date: Fri, 16 Oct 2026 13:59:34 +0530 Subject: [PATCH 09/19] fix: [indicator] default the fallback label to the accent variant --- .../components/indicator/__tests__/indicator.test.tsx | 10 ++++++++++ packages/react/components/indicator/indicator.tsx | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/react/components/indicator/__tests__/indicator.test.tsx b/packages/react/components/indicator/__tests__/indicator.test.tsx index b557ce354..4a186ff72 100644 --- a/packages/react/components/indicator/__tests__/indicator.test.tsx +++ b/packages/react/components/indicator/__tests__/indicator.test.tsx @@ -64,4 +64,14 @@ describe('Indicator', () => { expect(dot).toBeInTheDocument(); }); }); + + describe('Accessibility', () => { + it('labels the badge with the default variant', () => { + render(); + expect(screen.getByRole('status')).toHaveAttribute( + 'aria-label', + 'accent indicator' + ); + }); + }); }); diff --git a/packages/react/components/indicator/indicator.tsx b/packages/react/components/indicator/indicator.tsx index e6dbbe29d..ba59d49a4 100644 --- a/packages/react/components/indicator/indicator.tsx +++ b/packages/react/components/indicator/indicator.tsx @@ -38,7 +38,7 @@ export interface IndicatorProps export const Indicator = ({ className, classNames, - variant, + variant = 'accent', pulse, label, children, From c912d8a563847d8d18afd63fd2411000b080f406 Mon Sep 17 00:00:00 2001 From: Shreyag02 Date: Fri, 16 Oct 2026 14:00:16 +0530 Subject: [PATCH 10/19] fix: [docs] correct defaults, types and descriptions in props tables --- .../content/docs/components/calendar/props.ts | 14 +++++------ .../content/docs/components/checkbox/props.ts | 4 +-- .../docs/components/code-block/props.ts | 2 +- .../content/docs/components/drawer/index.mdx | 7 +++--- .../content/docs/components/drawer/props.ts | 10 ++++++-- .../docs/components/empty-state/props.ts | 4 +-- .../content/docs/components/field/props.ts | 3 +-- .../docs/components/number-field/props.ts | 5 ++-- .../docs/components/preview-card/props.ts | 25 +++++++++++++------ .../content/docs/components/select/props.ts | 7 ++++-- .../docs/components/sidepanel/props.ts | 2 +- .../content/docs/components/switch/props.ts | 5 +++- .../content/docs/components/toast/index.mdx | 4 +-- .../content/docs/components/toast/props.ts | 7 +++--- .../content/docs/components/tooltip/props.ts | 2 +- apps/www/src/content/docs/dataview/props.ts | 22 ++++++++++++---- .../src/content/docs/theme/overview/props.ts | 2 +- .../react/components/drawer/drawer-root.tsx | 5 +++- 18 files changed, 82 insertions(+), 48 deletions(-) diff --git a/apps/www/src/content/docs/components/calendar/props.ts b/apps/www/src/content/docs/components/calendar/props.ts index f5b3e24fd..2292a861d 100644 --- a/apps/www/src/content/docs/components/calendar/props.ts +++ b/apps/www/src/content/docs/components/calendar/props.ts @@ -155,24 +155,22 @@ export interface RangePickerProps { dateFormat?: string; /** - * Fires on every step of range selection — not only on the completed range. - * Both fields are optional during partial selection; gate on `range.to` if - * you only want completed ranges. + * Fires on every step of range selection. `to` is unset until the range is complete. */ - onSelect?: (range: { from?: Date; to?: Date }) => void; + onSelect?: (range: { from: Date | undefined; to?: Date }) => void; /** Initial (uncontrolled) date range. */ - defaultValue?: { from?: Date; to?: Date }; + defaultValue?: { from: Date | undefined; to?: Date }; /** Controlled date range. */ - value?: { from?: Date; to?: Date }; + value?: { from: Date | undefined; to?: Date }; /** * Props for each picker slot. When both this and the legacy * `inputsProps` / `calendarProps` / `popoverProps` are set, `slotProps` wins. * - * Input event handlers (`onChange`, `onFocus`, `onBlur`, `onKeyUp`) are not - * forwarded — use `onSelect` for value changes. + * The inputs are read-only. RangePicker replaces their `value` and `onClick`. + * Use `onSelect` for value changes. */ slotProps?: { startInput?: InputProps; diff --git a/apps/www/src/content/docs/components/checkbox/props.ts b/apps/www/src/content/docs/components/checkbox/props.ts index 58eb0927f..615f915ff 100644 --- a/apps/www/src/content/docs/components/checkbox/props.ts +++ b/apps/www/src/content/docs/components/checkbox/props.ts @@ -12,7 +12,7 @@ export interface CheckboxProps { /** * Event handler called when the state changes */ - onCheckedChange?: (checked: boolean) => void; + onCheckedChange?: (checked: boolean, eventDetails: unknown) => void; /** * When true, the checkbox is in an indeterminate state @@ -34,7 +34,7 @@ export interface CheckboxProps { /** * When true, the user must tick the checkbox before submitting a form. - * @defaultValue false + * @defaultValue the `required` of the surrounding `Field`, otherwise false */ required?: boolean; diff --git a/apps/www/src/content/docs/components/code-block/props.ts b/apps/www/src/content/docs/components/code-block/props.ts index 6d4928bef..cf0e80c96 100644 --- a/apps/www/src/content/docs/components/code-block/props.ts +++ b/apps/www/src/content/docs/components/code-block/props.ts @@ -117,7 +117,7 @@ export interface CodeBlockLabelProps { export interface CodeBlockLanguageSelectProps { /** - * Available languages for selection + * The `CodeBlock.LanguageSelectTrigger` and `CodeBlock.LanguageSelectContent` parts */ children?: ReactNode; diff --git a/apps/www/src/content/docs/components/drawer/index.mdx b/apps/www/src/content/docs/components/drawer/index.mdx index 9fe36a213..94ada00e2 100644 --- a/apps/www/src/content/docs/components/drawer/index.mdx +++ b/apps/www/src/content/docs/components/drawer/index.mdx @@ -18,7 +18,8 @@ Import and assemble the component: import { Drawer } from "@raystack/apsara"; - + + @@ -35,7 +36,7 @@ Pick the edge it enters from, then decide who owns its open state. ### Basic -A drawer slides in from the edge named by `side` and traps focus while open. +A drawer slides in from the edge named by the `side` of `Drawer.Content` and traps focus while open. @@ -57,7 +58,7 @@ The same header, body and footer shell as [Dialog](/docs/components/dialog), anc ### Root -Groups all parts of the drawer. The `side` prop determines both the slide direction and the swipe-to-dismiss direction. +Groups all parts of the drawer. Its `side` prop sets the swipe-to-dismiss direction. `Drawer.Content` has its own `side`, which places the panel. Set both to the same edge. diff --git a/apps/www/src/content/docs/components/drawer/props.ts b/apps/www/src/content/docs/components/drawer/props.ts index 688f975a6..7bbda4570 100644 --- a/apps/www/src/content/docs/components/drawer/props.ts +++ b/apps/www/src/content/docs/components/drawer/props.ts @@ -1,5 +1,8 @@ export interface DrawerProps { - /** The direction from which the drawer appears and can be swiped to dismiss. */ + /** + * The edge the user swipes the drawer toward to dismiss it. + * @default "right" + */ side?: 'top' | 'right' | 'bottom' | 'left'; /** Boolean to control the default open state. */ @@ -28,7 +31,10 @@ export interface DrawerProps { } export interface DrawerContentProps { - /** The direction from which the drawer appears. */ + /** + * The edge the panel sits on and slides in from. + * @default "right" + */ side?: 'top' | 'right' | 'bottom' | 'left'; /** diff --git a/apps/www/src/content/docs/components/empty-state/props.ts b/apps/www/src/content/docs/components/empty-state/props.ts index 6a97e53d8..94f15c47a 100644 --- a/apps/www/src/content/docs/components/empty-state/props.ts +++ b/apps/www/src/content/docs/components/empty-state/props.ts @@ -3,10 +3,10 @@ export interface EmptyStateProps { icon: React.ReactNode; /** Primary heading message */ - heading?: string; + heading?: React.ReactNode; /** Secondary heading message */ - subHeading?: string; + subHeading?: React.ReactNode; /** Action to show in empty state like button or link */ primaryAction?: React.ReactNode; diff --git a/apps/www/src/content/docs/components/field/props.ts b/apps/www/src/content/docs/components/field/props.ts index e1be1d081..8d3c13ff6 100644 --- a/apps/www/src/content/docs/components/field/props.ts +++ b/apps/www/src/content/docs/components/field/props.ts @@ -73,8 +73,7 @@ export interface FieldControlProps { export interface FieldErrorProps { /** - * Match a specific ValidityState property (e.g., "valueMissing", "typeMismatch", "customError") - * or pass `true` to match any error. + * The ValidityState key that shows this error, such as `"valueMissing"`. `true` always shows it. When not set, it shows on any error. */ match?: boolean | keyof ValidityState; diff --git a/apps/www/src/content/docs/components/number-field/props.ts b/apps/www/src/content/docs/components/number-field/props.ts index 6a0bc47ff..8300f987a 100644 --- a/apps/www/src/content/docs/components/number-field/props.ts +++ b/apps/www/src/content/docs/components/number-field/props.ts @@ -3,8 +3,7 @@ export interface NumberFieldProps { value?: number | null; /** - * Initial uncontrolled value. - * @defaultValue 0 + * Initial uncontrolled value. The field is empty when neither this nor `value` is set. */ defaultValue?: number; @@ -37,7 +36,7 @@ export interface NumberFieldProps { /** * Whether the field is required. - * @defaultValue false + * @defaultValue the `required` of the surrounding `Field`, otherwise false */ required?: boolean; diff --git a/apps/www/src/content/docs/components/preview-card/props.ts b/apps/www/src/content/docs/components/preview-card/props.ts index f4c8cd651..ddd2d2e70 100644 --- a/apps/www/src/content/docs/components/preview-card/props.ts +++ b/apps/www/src/content/docs/components/preview-card/props.ts @@ -9,7 +9,7 @@ export interface PreviewCardRootProps { defaultOpen?: boolean; /** Event handler called when the preview card is opened or closed. */ - onOpenChange?: (open: boolean) => void; + onOpenChange?: (open: boolean, eventDetails: unknown) => void; /** Event handler called after any animations complete when the preview card is opened or closed. */ onOpenChangeComplete?: (open: boolean) => void; @@ -116,7 +116,7 @@ export interface PreviewCardContentProps { * Distance between the anchor and the popup in pixels. * Also accepts a function to read anchor/positioner dimensions. * @remarks `number | OffsetFunction` - * @defaultValue 4 + * @defaultValue 4, or 10 when `showArrow` is set */ sideOffset?: number | ((data: OffsetData) => number); @@ -130,6 +130,7 @@ export interface PreviewCardContentProps { /** * Additional space to maintain from the edge of the collision boundary. + * @defaultValue 3 */ collisionPadding?: number; @@ -140,12 +141,20 @@ export interface PreviewCardContentProps { collisionBoundary?: Element | Element[] | 'clipping-ancestors'; /** - * Determines how to handle collisions when positioning the popup. - */ - collisionAvoidance?: { - side?: 'escape' | 'flip'; - align?: 'shift' | 'flip'; - }; + * Determines how to handle collisions when positioning the popup. With `side: 'shift'`, `align` takes only `'shift'` or `'none'`. + * @remarks `{ side?: 'flip' | 'shift' | 'none'; align?: 'flip' | 'shift' | 'none'; fallbackAxisSide?: 'start' | 'end' | 'none' }` + */ + collisionAvoidance?: + | { + side?: 'flip' | 'none'; + align?: 'flip' | 'shift' | 'none'; + fallbackAxisSide?: 'start' | 'end' | 'none'; + } + | { + side?: 'shift' | 'none'; + align?: 'shift' | 'none'; + fallbackAxisSide?: 'start' | 'end' | 'none'; + }; /** * Whether to disable the popup from tracking any layout shift of its positioning anchor. diff --git a/apps/www/src/content/docs/components/select/props.ts b/apps/www/src/content/docs/components/select/props.ts index fcc2553be..2c41b6021 100644 --- a/apps/www/src/content/docs/components/select/props.ts +++ b/apps/www/src/content/docs/components/select/props.ts @@ -22,7 +22,10 @@ export interface SelectRootProps { /** Whether the select is disabled. */ disabled?: boolean; - /** Whether a value is required. Defaults to the `required` of the surrounding `Field`, which is `true` unless the `Field` sets `required={false}`. */ + /** + * Whether a value is required. + * @default the `required` of the surrounding `Field`, otherwise false + */ required?: boolean; /** Name of the field when the select is submitted with a form. */ @@ -58,7 +61,7 @@ export interface SelectRootProps { /** Callback fired when the search value changes */ onSearch?: (value: string) => void; - /** All item values. In autocomplete mode, Base UI filters this list instead of the `Select.Item` children. It has no effect without `autocomplete`. */ + /** All item values. In autocomplete mode, setting it turns off filtering of the `Select.Item` children. It has no effect without `autocomplete`. */ items?: string[]; } diff --git a/apps/www/src/content/docs/components/sidepanel/props.ts b/apps/www/src/content/docs/components/sidepanel/props.ts index dfcb8c04d..e11f72c4f 100644 --- a/apps/www/src/content/docs/components/sidepanel/props.ts +++ b/apps/www/src/content/docs/components/sidepanel/props.ts @@ -8,7 +8,7 @@ export interface SidePanelProps { /** * Content to render inside the side panel. */ - children: React.ReactNode; + children?: React.ReactNode; /** * Additional CSS class names to apply. diff --git a/apps/www/src/content/docs/components/switch/props.ts b/apps/www/src/content/docs/components/switch/props.ts index 6419b78b4..6fc1199e4 100644 --- a/apps/www/src/content/docs/components/switch/props.ts +++ b/apps/www/src/content/docs/components/switch/props.ts @@ -11,7 +11,10 @@ export interface SwitchProps { /** When true, prevents the user from interacting with the switch. */ disabled?: boolean; - /** When true, indicates that the user must check the switch. */ + /** + * When true, indicates that the user must check the switch. + * @default the `required` of the surrounding `Field`, otherwise false + */ required?: boolean; /** diff --git a/apps/www/src/content/docs/components/toast/index.mdx b/apps/www/src/content/docs/components/toast/index.mdx index 894f32f2d..7a856bc58 100644 --- a/apps/www/src/content/docs/components/toast/index.mdx +++ b/apps/www/src/content/docs/components/toast/index.mdx @@ -104,7 +104,7 @@ Creates a new toast and returns its unique ID. If `id` matches an open toast, it -### createToastManager() +### Toast.createToastManager() Factory that returns a fresh toast manager. The exported singleton `toastManager` is one such instance created at module load. Pass a custom manager to `` to scope toasts to that provider. @@ -142,7 +142,7 @@ The `promise(promise, options)` method drives a toast through the resolve/reject ### useToastManager() -Hook for dispatching toasts from inside a component tree wrapped by ``. Returns the same methods as `createToastManager()`, including built-in `leadingIcon` support, plus a reactive `toasts` array reflecting the toasts on screen. +Hook for dispatching toasts from inside a component tree wrapped by ``. Returns the same methods as `Toast.createToastManager()`, including built-in `leadingIcon` support, plus a reactive `toasts` array reflecting the toasts on screen. ```tsx import { useToastManager } from '@raystack/apsara' diff --git a/apps/www/src/content/docs/components/toast/props.ts b/apps/www/src/content/docs/components/toast/props.ts index 67c862cf9..200ac60a7 100644 --- a/apps/www/src/content/docs/components/toast/props.ts +++ b/apps/www/src/content/docs/components/toast/props.ts @@ -24,7 +24,8 @@ export interface ToastProviderProps { timeout?: number; /** - * Toast manager instance. Defaults to the exported `toastManager`. Pass one from `Toast.createToastManager()` to scope toasts to this provider. + * The manager the provider renders toasts from. + * @default toastManager */ toastManager?: CreateToastManagerReturn; @@ -157,7 +158,7 @@ export interface ToastObject { } /** - * The toast manager returned by `createToastManager()` and exported as the + * The toast manager returned by `Toast.createToastManager()` and exported as the * `toastManager` singleton. */ export interface CreateToastManagerReturn { @@ -206,7 +207,7 @@ export interface CreateToastManagerReturn { /** * Return value of the `useToastManager()` hook. Same methods as - * `createToastManager()` plus a reactive `toasts` array driving component + * `Toast.createToastManager()` plus a reactive `toasts` array driving component * re-renders. */ export interface UseToastManagerReturn extends CreateToastManagerReturn { diff --git a/apps/www/src/content/docs/components/tooltip/props.ts b/apps/www/src/content/docs/components/tooltip/props.ts index ff6aa3af4..fc83906ca 100644 --- a/apps/www/src/content/docs/components/tooltip/props.ts +++ b/apps/www/src/content/docs/components/tooltip/props.ts @@ -102,7 +102,7 @@ export interface TooltipContentProps { /** * Side offset for positioning - * @default 4 + * @default 4, or 10 when `showArrow` is set */ sideOffset?: number; diff --git a/apps/www/src/content/docs/dataview/props.ts b/apps/www/src/content/docs/dataview/props.ts index 2cf8e3369..326cecce7 100644 --- a/apps/www/src/content/docs/dataview/props.ts +++ b/apps/www/src/content/docs/dataview/props.ts @@ -1,4 +1,5 @@ import { CSSProperties, ReactNode, RefObject } from 'react'; +import type { SelectRootProps } from '../components/select/props'; // Documentation-only placeholders so `auto-type-table` can render the public // API without surfacing real generics (TData is shown as `T` for readability). @@ -86,7 +87,7 @@ export interface DataViewField { /** Human-readable label. */ label: string; - /** Optional icon (e.g. for grouping menu). */ + /** Icon for the field. No built-in DataView part renders it. */ icon?: ReactNode; /** Allow filtering on this field. */ @@ -134,10 +135,21 @@ export interface DataViewField { * Value a new filter on this field starts with. * @defaultValue today for `date`, the first option for `select`, otherwise `""` */ - defaultFilterValue?: unknown; - - /** Props for the filter's control. `select` takes the `Select` root props, without the value props, and is passed to the filter's `Select`. */ - filterProps?: { select?: Record }; + defaultFilterValue?: + | string + | number + | boolean + | (string | number | boolean)[] + | Date + | null; + + /** Props for the filter's control. The filter's `Select` receives `select`. */ + filterProps?: { + select?: Omit< + SelectRootProps, + 'value' | 'defaultValue' | 'onValueChange' | 'multiple' + >; + }; /** * Count shown next to each group header when `showGroupCount` is on, by raw group value. diff --git a/apps/www/src/content/docs/theme/overview/props.ts b/apps/www/src/content/docs/theme/overview/props.ts index 86d68fb2a..497125310 100644 --- a/apps/www/src/content/docs/theme/overview/props.ts +++ b/apps/www/src/content/docs/theme/overview/props.ts @@ -152,7 +152,7 @@ export type ThemeSwitcherProps = { target?: 'nearest' | 'root'; /** * Accessible name for the button. - * @defaultValue "Switch to light theme" when the target theme is dark, otherwise "Switch to dark theme" + * @defaultValue "Switch to light theme" when the `target` theme is dark, otherwise "Switch to dark theme" */ 'aria-label'?: string; }; diff --git a/packages/react/components/drawer/drawer-root.tsx b/packages/react/components/drawer/drawer-root.tsx index 1a19ec49d..390112dd5 100644 --- a/packages/react/components/drawer/drawer-root.tsx +++ b/packages/react/components/drawer/drawer-root.tsx @@ -15,7 +15,10 @@ const sideToSwipeDirection: Record< }; export interface DrawerRootProps extends DrawerPrimitive.Root.Props { - /** The direction from which the drawer appears and can be swiped to dismiss. */ + /** + * The edge the user swipes the drawer toward to dismiss it. + * @default 'right' + */ side?: Side; } From 2d06e5399905ff160127b790ba496e457d379a84 Mon Sep 17 00:00:00 2001 From: Shreyag02 Date: Fri, 16 Oct 2026 14:58:07 +0530 Subject: [PATCH 11/19] fix: [docs] describe null for defaultFilterValue --- apps/www/src/content/docs/dataview/props.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/www/src/content/docs/dataview/props.ts b/apps/www/src/content/docs/dataview/props.ts index 326cecce7..021aeadf2 100644 --- a/apps/www/src/content/docs/dataview/props.ts +++ b/apps/www/src/content/docs/dataview/props.ts @@ -132,7 +132,7 @@ export interface DataViewField { dataType?: 'string' | 'number' | 'boolean'; /** - * Value a new filter on this field starts with. + * Value a new filter on this field starts with. `null` uses the default. * @defaultValue today for `date`, the first option for `select`, otherwise `""` */ defaultFilterValue?: From 31149807d1f95d02c83fbfc4821cf413920dbaac Mon Sep 17 00:00:00 2001 From: Shreyag02 Date: Mon, 19 Oct 2026 16:22:51 +0530 Subject: [PATCH 12/19] chore: [indicator] move the fallback label fix to its own branch --- .../components/indicator/__tests__/indicator.test.tsx | 10 ---------- packages/react/components/indicator/indicator.tsx | 2 +- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/packages/react/components/indicator/__tests__/indicator.test.tsx b/packages/react/components/indicator/__tests__/indicator.test.tsx index 4a186ff72..b557ce354 100644 --- a/packages/react/components/indicator/__tests__/indicator.test.tsx +++ b/packages/react/components/indicator/__tests__/indicator.test.tsx @@ -64,14 +64,4 @@ describe('Indicator', () => { expect(dot).toBeInTheDocument(); }); }); - - describe('Accessibility', () => { - it('labels the badge with the default variant', () => { - render(); - expect(screen.getByRole('status')).toHaveAttribute( - 'aria-label', - 'accent indicator' - ); - }); - }); }); diff --git a/packages/react/components/indicator/indicator.tsx b/packages/react/components/indicator/indicator.tsx index ba59d49a4..e6dbbe29d 100644 --- a/packages/react/components/indicator/indicator.tsx +++ b/packages/react/components/indicator/indicator.tsx @@ -38,7 +38,7 @@ export interface IndicatorProps export const Indicator = ({ className, classNames, - variant = 'accent', + variant, pulse, label, children, From 0b8bb93cc413f261613965c0216ecadf646277c5 Mon Sep 17 00:00:00 2001 From: Shreyag02 Date: Mon, 19 Oct 2026 16:22:52 +0530 Subject: [PATCH 13/19] fix: [docs] fix props tables flagged by the check --- .../docs/ai-elements/prompt-input/index.mdx | 2 ++ .../content/docs/components/accordion/props.ts | 10 ++-------- .../docs/components/alert-dialog/index.mdx | 6 ++++++ .../docs/components/calendar-preview/index.mdx | 6 ++++++ .../src/content/docs/components/calendar/demo.ts | 2 +- .../content/docs/components/calendar/props.ts | 7 +++---- .../content/docs/components/checkbox/props.ts | 2 +- .../content/docs/components/code-block/index.mdx | 16 +++++++++++++++- .../content/docs/components/code-block/props.ts | 10 +++++----- .../docs/components/color-picker/index.mdx | 4 ++++ .../content/docs/components/combobox/index.mdx | 2 ++ .../content/docs/components/command/index.mdx | 4 +++- .../src/content/docs/components/command/props.ts | 9 ++++++--- .../docs/components/context-menu/props.ts | 6 +++--- .../docs/components/copy-button/index.mdx | 4 +--- .../src/content/docs/components/dialog/index.mdx | 6 ++++++ .../src/content/docs/components/dialog/props.ts | 4 ++-- .../src/content/docs/components/editor/index.mdx | 4 ++++ .../src/content/docs/components/editor/props.ts | 7 +++++-- .../docs/components/empty-state/index.mdx | 2 ++ .../src/content/docs/components/field/props.ts | 2 +- .../docs/components/floating-actions/props.ts | 2 +- .../src/content/docs/components/image/props.ts | 9 ++++++--- .../content/docs/components/indicator/index.mdx | 2 +- .../src/content/docs/components/link/index.mdx | 2 +- .../src/content/docs/components/menu/props.ts | 8 ++++---- .../src/content/docs/components/meter/props.ts | 2 +- .../src/content/docs/components/navbar/index.mdx | 6 ++++++ .../docs/components/number-field/props.ts | 2 +- .../src/content/docs/components/popover/props.ts | 9 ++++++--- .../docs/components/preview-card/props.ts | 4 ++-- .../content/docs/components/progress/props.ts | 2 +- .../src/content/docs/components/search/index.mdx | 2 ++ .../content/docs/components/sidebar/index.mdx | 4 +++- .../src/content/docs/components/tour/index.mdx | 2 ++ apps/www/src/content/docs/dataview/props.ts | 6 +++--- .../www/src/content/docs/theme/overview/props.ts | 2 +- 37 files changed, 121 insertions(+), 58 deletions(-) diff --git a/apps/www/src/content/docs/ai-elements/prompt-input/index.mdx b/apps/www/src/content/docs/ai-elements/prompt-input/index.mdx index 5e1089aac..62cbc2501 100644 --- a/apps/www/src/content/docs/ai-elements/prompt-input/index.mdx +++ b/apps/www/src/content/docs/ai-elements/prompt-input/index.mdx @@ -219,6 +219,8 @@ The text field, built on `TextArea variant="borderless"`. It grows with its content up to a max-height cap (override with `--prompt-input-textarea-max-height`), then scrolls. +- Inherits all TextArea props + ### Editor diff --git a/apps/www/src/content/docs/components/accordion/props.ts b/apps/www/src/content/docs/components/accordion/props.ts index cf1ee96fc..33717c37d 100644 --- a/apps/www/src/content/docs/components/accordion/props.ts +++ b/apps/www/src/content/docs/components/accordion/props.ts @@ -32,12 +32,6 @@ export interface AccordionRootProps { */ disabled?: boolean; - /** - * The orientation of the accordion - * @defaultValue "vertical" - */ - orientation?: 'horizontal' | 'vertical'; - /** * Whether to keep the element in the DOM while the panel is closed * @defaultValue false @@ -56,9 +50,9 @@ export interface AccordionRootProps { export interface AccordionItemProps { /** - * A unique value for the item + * A unique value for the item. Base UI generates one when it is not set. */ - value: string; + value?: string; /** * Whether the item is disabled diff --git a/apps/www/src/content/docs/components/alert-dialog/index.mdx b/apps/www/src/content/docs/components/alert-dialog/index.mdx index 28ab454d8..9ecabcc74 100644 --- a/apps/www/src/content/docs/components/alert-dialog/index.mdx +++ b/apps/www/src/content/docs/components/alert-dialog/index.mdx @@ -78,6 +78,8 @@ Renders the alert dialog panel overlay. Renders the alert dialog header section. +- Inherits all Flex props + ### Title @@ -90,6 +92,8 @@ Renders the alert dialog title text. Renders the main content area of the alert dialog. +- Inherits all Flex props + ### Description @@ -108,6 +112,8 @@ Renders the element that opens the alert dialog. Renders the alert dialog footer section. +- Inherits all Flex props + ### Slots diff --git a/apps/www/src/content/docs/components/calendar-preview/index.mdx b/apps/www/src/content/docs/components/calendar-preview/index.mdx index 1087ccd25..ec5b3f941 100644 --- a/apps/www/src/content/docs/components/calendar-preview/index.mdx +++ b/apps/www/src/content/docs/components/calendar-preview/index.mdx @@ -171,6 +171,8 @@ The portaled popover surface. Takes `Popover.Content` props — `side`, `align`, The typeable date field. +- Inherits all Input props + ### CalendarPreview.Body @@ -213,6 +215,8 @@ Step the view one month. Restores `defaultDate`, reporting `reason: 'reset'`. Carries `data-restored` while there is nothing to restore. +- Inherits all IconButton props + ### CalendarPreview.Scales / CalendarPreview.Scale @@ -237,6 +241,8 @@ The field label above the input, and the rule between the switcher and the view. The row below the calendar. A bare string is wrapped in `Text`; anything else renders as given. +- Inherits all Flex props + ### useCalendar diff --git a/apps/www/src/content/docs/components/calendar/demo.ts b/apps/www/src/content/docs/components/calendar/demo.ts index 42b611b85..88abcaa4f 100644 --- a/apps/www/src/content/docs/components/calendar/demo.ts +++ b/apps/www/src/content/docs/components/calendar/demo.ts @@ -112,7 +112,7 @@ export const rangePickerDemo = { { name: 'Disabled', code: ` - /* Disabling either input gates the whole picker — the shared popover would otherwise let users rewrite the "disabled" side through the calendar grid. To fix one side, constrain the calendar via \`calendarProps\` instead. */ + /* Disabling either input gates the whole picker. The shared popover would otherwise let users rewrite the "disabled" side through the calendar grid. To fix one side, constrain the calendar via \`slotProps.calendar\` instead. */ ` }, diff --git a/apps/www/src/content/docs/components/calendar/props.ts b/apps/www/src/content/docs/components/calendar/props.ts index 2292a861d..7c3b0099b 100644 --- a/apps/www/src/content/docs/components/calendar/props.ts +++ b/apps/www/src/content/docs/components/calendar/props.ts @@ -155,7 +155,9 @@ export interface RangePickerProps { dateFormat?: string; /** - * Fires on every step of range selection. `to` is unset until the range is complete. + * Fires on every step of range selection — not only on the completed range. + * Both fields are optional during partial selection; gate on `range.to` if + * you only want completed ranges. */ onSelect?: (range: { from: Date | undefined; to?: Date }) => void; @@ -262,9 +264,6 @@ export interface DatePickerProps { */ onErrorChange?: (error: string | undefined) => void; - /** @deprecated Use `slotProps.calendar` instead. */ - calendarProps?: CalendarProps; - /** * Render prop or custom trigger. Pass a function to render a custom trigger * receiving the formatted `selectedDate` string, or a ReactNode to replace diff --git a/apps/www/src/content/docs/components/checkbox/props.ts b/apps/www/src/content/docs/components/checkbox/props.ts index 615f915ff..3d41ed838 100644 --- a/apps/www/src/content/docs/components/checkbox/props.ts +++ b/apps/www/src/content/docs/components/checkbox/props.ts @@ -34,7 +34,7 @@ export interface CheckboxProps { /** * When true, the user must tick the checkbox before submitting a form. - * @defaultValue the `required` of the surrounding `Field`, otherwise false + * @default the `required` of the surrounding `Field`, otherwise false */ required?: boolean; diff --git a/apps/www/src/content/docs/components/code-block/index.mdx b/apps/www/src/content/docs/components/code-block/index.mdx index 9c22f0753..6cda947fa 100644 --- a/apps/www/src/content/docs/components/code-block/index.mdx +++ b/apps/www/src/content/docs/components/code-block/index.mdx @@ -98,6 +98,8 @@ Groups all parts of the code block and manages state. Renders the optional header section for labels and controls. +- Inherits all Flex props + ### Content @@ -110,11 +112,15 @@ Renders the main content area containing code blocks. Renders a text label displayed in the header. +- Inherits all Text props + ### LanguageSelect -Renders a language selection dropdown container. It accepts the props of a single-selection `Select` root, except `value`, `defaultValue` and `onValueChange`. Set those on the `CodeBlock` root. +Renders a language selection dropdown container. Set `value`, `defaultValue` and `onValueChange` on the `CodeBlock` root, not here. + +- Inherits all Select props @@ -122,6 +128,8 @@ Renders a language selection dropdown container. It accepts the props of a singl Renders the button that opens language selection. +- Inherits all Select.Trigger props + ### LanguageSelectContent @@ -136,6 +144,8 @@ Renders one language in the dropdown. Selecting it shows the `CodeBlock.Code` wi Renders a button for copying code to clipboard. +- Inherits all CopyButton props + ### Code @@ -148,6 +158,8 @@ Renders a syntax-highlighted code block. Renders a button to expand or collapse long code blocks. +- Inherits all Button props + ### Slots @@ -170,6 +182,8 @@ Every rendered part carries a stable `data-slot` attribute for [styling and test | `code-block-collapse-trigger` | The show/hide button (when `maxLines` is exceeded) | | `code-block-language-select-trigger` | The language select trigger button | | `code-block-language-select-value` | The selected language value inside the trigger | +| `select-content` | The `CodeBlock.LanguageSelectContent` popup | +| `select-item` | Each `CodeBlock.LanguageSelectItem` option | ## Accessibility diff --git a/apps/www/src/content/docs/components/code-block/props.ts b/apps/www/src/content/docs/components/code-block/props.ts index cf0e80c96..9e3a6f27b 100644 --- a/apps/www/src/content/docs/components/code-block/props.ts +++ b/apps/www/src/content/docs/components/code-block/props.ts @@ -48,7 +48,7 @@ export interface CodeBlockProps { /** * The code content to display */ - children: ReactNode; + children?: ReactNode; /** * Additional CSS class name @@ -83,7 +83,7 @@ export interface CodeBlockHeaderProps { /** * The content to display in the header */ - children: ReactNode; + children?: ReactNode; /** * Additional CSS class name @@ -95,7 +95,7 @@ export interface CodeBlockContentProps { /** * The content to display */ - children: ReactNode; + children?: ReactNode; /** * Additional CSS class name @@ -107,7 +107,7 @@ export interface CodeBlockLabelProps { /** * The label text to display */ - children: ReactNode; + children?: ReactNode; /** * Additional CSS class name @@ -128,7 +128,7 @@ export interface CodeBlockLanguageSelectProps { /** * The initial open state when uncontrolled - * @defaultValue false + * @default false */ defaultOpen?: boolean; diff --git a/apps/www/src/content/docs/components/color-picker/index.mdx b/apps/www/src/content/docs/components/color-picker/index.mdx index e2eaed7c8..ce8cf0b90 100644 --- a/apps/www/src/content/docs/components/color-picker/index.mdx +++ b/apps/www/src/content/docs/components/color-picker/index.mdx @@ -71,6 +71,8 @@ The pad and sliders compose inside a root. `formatColor` turns a value into a st The `ColorPicker` is composed of several subcomponents, each responsible for a specific aspect of color selection. The root component acts as a data provider for its children. +- Inherits all Flex props + ### Area @@ -89,6 +91,8 @@ Provides a slider for selecting the alpha value of the color. Lets users switch between different color models (HEX, RGB, HSL, OKLCH) via a dropdown menu. +- Inherits all Select.Trigger props + ### Input diff --git a/apps/www/src/content/docs/components/combobox/index.mdx b/apps/www/src/content/docs/components/combobox/index.mdx index ad9c2c0be..53509831d 100644 --- a/apps/www/src/content/docs/components/combobox/index.mdx +++ b/apps/www/src/content/docs/components/combobox/index.mdx @@ -98,6 +98,8 @@ The root element is the parent component that manages the combobox state includi The input field that triggers the combobox dropdown and allows users to type and filter options. +- Inherits all Input props + ### Content Props diff --git a/apps/www/src/content/docs/components/command/index.mdx b/apps/www/src/content/docs/components/command/index.mdx index 89159adf4..2ed998f69 100644 --- a/apps/www/src/content/docs/components/command/index.mdx +++ b/apps/www/src/content/docs/components/command/index.mdx @@ -98,7 +98,9 @@ The root element owns the input value, the list of items, and the context used b ### Input -Text input that drives the search. Accepts the same props as `Input` and defaults to a magnifying-glass leading icon. +Text input that drives the search. Defaults to a magnifying-glass leading icon. + +- Inherits all Input props diff --git a/apps/www/src/content/docs/components/command/props.ts b/apps/www/src/content/docs/components/command/props.ts index d98976187..72f4b21fb 100644 --- a/apps/www/src/content/docs/components/command/props.ts +++ b/apps/www/src/content/docs/components/command/props.ts @@ -80,6 +80,9 @@ export interface CommandInputProps { export interface CommandContentProps { /** Additional CSS class names. */ className?: string; + + /** Ref to the list element. */ + ref?: React.Ref; } export interface CommandEmptyProps { @@ -145,10 +148,10 @@ export interface CommandDialogProps { onOpenChange?: (open: boolean) => void; /** - * Whether the dialog is modal. - * @defaultValue true + * Whether the dialog is modal. `'trap-focus'` traps focus without locking scroll or outside interaction. + * @default true */ - modal?: boolean; + modal?: boolean | 'trap-focus'; } export interface CommandDialogContentProps { diff --git a/apps/www/src/content/docs/components/context-menu/props.ts b/apps/www/src/content/docs/components/context-menu/props.ts index e5ac87ed7..944e39780 100644 --- a/apps/www/src/content/docs/components/context-menu/props.ts +++ b/apps/www/src/content/docs/components/context-menu/props.ts @@ -68,7 +68,7 @@ export interface ContextMenuContentProps { * The side of the anchor element to place the popup. * @default "bottom" */ - side?: 'top' | 'bottom' | 'left' | 'right'; + side?: 'top' | 'bottom' | 'left' | 'right' | 'inline-start' | 'inline-end'; /** * The alignment of the popup relative to the anchor element. @@ -194,9 +194,9 @@ export interface ContextMenuSubContentProps { /** * The side of the anchor element to place the popup. - * @default "bottom" + * @default "inline-end" */ - side?: 'top' | 'bottom' | 'left' | 'right'; + side?: 'top' | 'bottom' | 'left' | 'right' | 'inline-start' | 'inline-end'; /** * The alignment of the popup relative to the anchor element. diff --git a/apps/www/src/content/docs/components/copy-button/index.mdx b/apps/www/src/content/docs/components/copy-button/index.mdx index d2117d665..9943a0893 100644 --- a/apps/www/src/content/docs/components/copy-button/index.mdx +++ b/apps/www/src/content/docs/components/copy-button/index.mdx @@ -40,12 +40,10 @@ CopyButton inherits all IconButton states. A disabled button ignores clicks and ## API Reference -The CopyButton component extends IconButton props and accepts the following additional props +- Inherits all IconButton props -All IconButton props are supported - ### Slots Every rendered part carries a stable `data-slot` attribute for [styling and testing](/docs/styling#with-data-slot): diff --git a/apps/www/src/content/docs/components/dialog/index.mdx b/apps/www/src/content/docs/components/dialog/index.mdx index 893a16ad5..9c2f6863a 100644 --- a/apps/www/src/content/docs/components/dialog/index.mdx +++ b/apps/www/src/content/docs/components/dialog/index.mdx @@ -84,6 +84,8 @@ Renders the dialog panel overlay. Renders the dialog header section. +- Inherits all Flex props + ### Title @@ -96,6 +98,8 @@ Renders the dialog title text. Renders the main content area of the dialog. +- Inherits all Flex props + ### Description @@ -120,6 +124,8 @@ Renders a button that closes the dialog. Renders the dialog footer section. +- Inherits all Flex props + ### Slots diff --git a/apps/www/src/content/docs/components/dialog/props.ts b/apps/www/src/content/docs/components/dialog/props.ts index daa968e26..560b5dcf9 100644 --- a/apps/www/src/content/docs/components/dialog/props.ts +++ b/apps/www/src/content/docs/components/dialog/props.ts @@ -6,10 +6,10 @@ export interface DialogProps { onOpenChange?: (open: boolean) => void; /** - * Whether the dialog is modal + * Whether the dialog is modal. `'trap-focus'` traps focus without locking scroll or outside interaction. * @default true */ - modal?: boolean; + modal?: boolean | 'trap-focus'; } export interface DialogContentProps { diff --git a/apps/www/src/content/docs/components/editor/index.mdx b/apps/www/src/content/docs/components/editor/index.mdx index 2259f888c..1919b800b 100644 --- a/apps/www/src/content/docs/components/editor/index.mdx +++ b/apps/www/src/content/docs/components/editor/index.mdx @@ -135,6 +135,10 @@ The second argument of `onValueChange`. The methods convert the doc from that ch +With the `markdown` prop, the second argument is `EditorMarkdownChangeDetails`. It has the same methods and `getMarkdown`. + + + ### Markdown `MarkdownAdapter.create(options)` returns an adapter for the `markdown` prop. `MarkdownAdapter.toEditor(markdown)` and `MarkdownAdapter.fromEditor(value)` convert without an editor, for example on the server. An app that never imports `MarkdownAdapter` ships no Markdown code. diff --git a/apps/www/src/content/docs/components/editor/props.ts b/apps/www/src/content/docs/components/editor/props.ts index ab020f449..5ea25a208 100644 --- a/apps/www/src/content/docs/components/editor/props.ts +++ b/apps/www/src/content/docs/components/editor/props.ts @@ -337,8 +337,11 @@ export interface EditorChangeDetails { getText: () => string; /** Converts the doc to HTML. */ getHTML: () => string; - /** Converts the doc to Markdown. Only present with the `markdown` prop. */ - getMarkdown?: () => string; +} + +export interface EditorMarkdownChangeDetails extends EditorChangeDetails { + /** Converts the doc to Markdown with the editor's adapter. */ + getMarkdown: () => string; } export interface MarkdownAdapterOptions { diff --git a/apps/www/src/content/docs/components/empty-state/index.mdx b/apps/www/src/content/docs/components/empty-state/index.mdx index f8986d236..00430be02 100644 --- a/apps/www/src/content/docs/components/empty-state/index.mdx +++ b/apps/www/src/content/docs/components/empty-state/index.mdx @@ -47,6 +47,8 @@ Pick the variant that suits the space, then fill in the icon, the message and up Renders a placeholder for empty content areas. +- Inherits all Flex props + ### Slots diff --git a/apps/www/src/content/docs/components/field/props.ts b/apps/www/src/content/docs/components/field/props.ts index 8d3c13ff6..cdaea6762 100644 --- a/apps/www/src/content/docs/components/field/props.ts +++ b/apps/www/src/content/docs/components/field/props.ts @@ -53,7 +53,7 @@ export interface FieldLabelProps { /** * Text rendered next to the label when `required={false}`. - * @defaultValue "(optional)" + * @default "(optional)" */ optionalText?: string; diff --git a/apps/www/src/content/docs/components/floating-actions/props.ts b/apps/www/src/content/docs/components/floating-actions/props.ts index e1f1f7af8..b6f2ae9b1 100644 --- a/apps/www/src/content/docs/components/floating-actions/props.ts +++ b/apps/www/src/content/docs/components/floating-actions/props.ts @@ -49,7 +49,7 @@ export interface FloatingActionsSeparatorProps { /** * Hides the separator from assistive technology. - * @defaultValue false + * @default false */ decorative?: boolean; diff --git a/apps/www/src/content/docs/components/image/props.ts b/apps/www/src/content/docs/components/image/props.ts index 2f353f861..b6cda3eaa 100644 --- a/apps/www/src/content/docs/components/image/props.ts +++ b/apps/www/src/content/docs/components/image/props.ts @@ -1,9 +1,12 @@ export interface ImageProps { /** The URL of the image to display */ - src: string; + src?: string; - /** Alternative text description (required) */ - alt: string; + /** + * Alternative text. Pass `""` for a decorative image. + * @default "" + */ + alt?: string; /** * Object-fit property diff --git a/apps/www/src/content/docs/components/indicator/index.mdx b/apps/www/src/content/docs/components/indicator/index.mdx index 906677a81..c20e10a9f 100644 --- a/apps/www/src/content/docs/components/indicator/index.mdx +++ b/apps/www/src/content/docs/components/indicator/index.mdx @@ -78,7 +78,7 @@ The Indicator component includes several accessibility features: - Provides appropriate `aria-label` based on the content: - Uses custom `aria-label` prop if provided - Falls back to the label text if available - - Uses `" indicator"`, for example `"accent indicator"`, if neither is provided + - Uses `" indicator"`, for example `"danger indicator"`, if neither is provided - Hides decorative dot from screen readers when no label is present Example with custom aria label: diff --git a/apps/www/src/content/docs/components/link/index.mdx b/apps/www/src/content/docs/components/link/index.mdx index 9ba413615..6a4c6fa6e 100644 --- a/apps/www/src/content/docs/components/link/index.mdx +++ b/apps/www/src/content/docs/components/link/index.mdx @@ -64,7 +64,7 @@ import { Link as RouterLink } from "react-router-dom"; ## API Reference -The Link is built over [Text](/docs/components/text#api-reference) and accepts all it's props +- Inherits all Text props diff --git a/apps/www/src/content/docs/components/menu/props.ts b/apps/www/src/content/docs/components/menu/props.ts index 632c75f8a..0335e4d37 100644 --- a/apps/www/src/content/docs/components/menu/props.ts +++ b/apps/www/src/content/docs/components/menu/props.ts @@ -70,7 +70,7 @@ export interface MenuContentProps { * The side of the anchor element to place the popup. * @default "bottom" */ - side?: 'top' | 'bottom' | 'left' | 'right'; + side?: 'top' | 'bottom' | 'left' | 'right' | 'inline-start' | 'inline-end'; /** * The alignment of the popup relative to the anchor element. @@ -131,7 +131,7 @@ export interface MenuSeparatorProps { export interface MenuEmptyStateProps { /** React nodes to render in empty state */ - children?: ReactNode; + children: ReactNode; /** Additional CSS class names */ className?: string; @@ -196,9 +196,9 @@ export interface MenuSubContentProps { /** * The side of the anchor element to place the popup. - * @default "bottom" + * @default "inline-end" */ - side?: 'top' | 'bottom' | 'left' | 'right'; + side?: 'top' | 'bottom' | 'left' | 'right' | 'inline-start' | 'inline-end'; /** * The alignment of the popup relative to the anchor element. diff --git a/apps/www/src/content/docs/components/meter/props.ts b/apps/www/src/content/docs/components/meter/props.ts index 5ca2fa4d5..d797cb057 100644 --- a/apps/www/src/content/docs/components/meter/props.ts +++ b/apps/www/src/content/docs/components/meter/props.ts @@ -26,7 +26,7 @@ export interface MeterProps { export interface MeterLabelProps { /** The label text content. */ - children: React.ReactNode; + children?: React.ReactNode; /** Additional CSS class name. */ className?: string; diff --git a/apps/www/src/content/docs/components/navbar/index.mdx b/apps/www/src/content/docs/components/navbar/index.mdx index 8868c4b12..00229a773 100644 --- a/apps/www/src/content/docs/components/navbar/index.mdx +++ b/apps/www/src/content/docs/components/navbar/index.mdx @@ -71,18 +71,24 @@ Renders the navigation bar container. The start section is a container that accepts Flex props (`align`, `gap`, `direction`, etc.) and section props. It's commonly used for brand logos, primary navigation links, or page titles. +- Inherits all Flex props + ### Center The center section sits in the middle of the navbar in a fixed position, so it stays absolutely centered regardless of the width of Start or End content. The navbar uses a 3-column grid (Start | Center | End) so the center does not shift when left or right content changes. It accepts Flex props and section props. +- Inherits all Flex props + ### End The end section is a container that accepts Flex props and section props. It's commonly used for search inputs, action buttons, user menus, or secondary navigation. +- Inherits all Flex props + ### Slots diff --git a/apps/www/src/content/docs/components/number-field/props.ts b/apps/www/src/content/docs/components/number-field/props.ts index 8300f987a..9a995757d 100644 --- a/apps/www/src/content/docs/components/number-field/props.ts +++ b/apps/www/src/content/docs/components/number-field/props.ts @@ -36,7 +36,7 @@ export interface NumberFieldProps { /** * Whether the field is required. - * @defaultValue the `required` of the surrounding `Field`, otherwise false + * @default the `required` of the surrounding `Field`, otherwise false */ required?: boolean; diff --git a/apps/www/src/content/docs/components/popover/props.ts b/apps/www/src/content/docs/components/popover/props.ts index abbf0a233..9709237c4 100644 --- a/apps/www/src/content/docs/components/popover/props.ts +++ b/apps/www/src/content/docs/components/popover/props.ts @@ -8,13 +8,16 @@ export interface PopoverRootProps { /** Callback when open state changes. */ onOpenChange?: (open: boolean) => void; - /** Boolean to enable modal behavior. */ - modal?: boolean; + /** + * Locks scroll and blocks outside interaction while open. `'trap-focus'` only traps focus. + * @default false + */ + modal?: boolean | 'trap-focus'; } export interface PopoverContentProps { /** Preferred side of the trigger to render. */ - side?: 'top' | 'right' | 'bottom' | 'left'; + side?: 'top' | 'right' | 'bottom' | 'left' | 'inline-start' | 'inline-end'; /** Alignment relative to trigger. */ align?: 'start' | 'center' | 'end'; diff --git a/apps/www/src/content/docs/components/preview-card/props.ts b/apps/www/src/content/docs/components/preview-card/props.ts index ddd2d2e70..ae752cf24 100644 --- a/apps/www/src/content/docs/components/preview-card/props.ts +++ b/apps/www/src/content/docs/components/preview-card/props.ts @@ -116,7 +116,7 @@ export interface PreviewCardContentProps { * Distance between the anchor and the popup in pixels. * Also accepts a function to read anchor/positioner dimensions. * @remarks `number | OffsetFunction` - * @defaultValue 4, or 10 when `showArrow` is set + * @default 4, or 10 when `showArrow` is set */ sideOffset?: number | ((data: OffsetData) => number); @@ -130,7 +130,7 @@ export interface PreviewCardContentProps { /** * Additional space to maintain from the edge of the collision boundary. - * @defaultValue 3 + * @default 3 */ collisionPadding?: number; diff --git a/apps/www/src/content/docs/components/progress/props.ts b/apps/www/src/content/docs/components/progress/props.ts index a8523387f..e525dd100 100644 --- a/apps/www/src/content/docs/components/progress/props.ts +++ b/apps/www/src/content/docs/components/progress/props.ts @@ -29,7 +29,7 @@ export interface ProgressProps { export interface ProgressLabelProps { /** The label text content. */ - children: React.ReactNode; + children?: React.ReactNode; /** Additional CSS class name. */ className?: string; diff --git a/apps/www/src/content/docs/components/search/index.mdx b/apps/www/src/content/docs/components/search/index.mdx index febe8ef1e..e82022cd7 100644 --- a/apps/www/src/content/docs/components/search/index.mdx +++ b/apps/www/src/content/docs/components/search/index.mdx @@ -58,6 +58,8 @@ Use `onValueChange` to receive only the new query string, or `onChange` for the Renders a search input field with clear functionality. +- Inherits all Input props + ### Slots diff --git a/apps/www/src/content/docs/components/sidebar/index.mdx b/apps/www/src/content/docs/components/sidebar/index.mdx index 763870ae4..fae51ebc8 100644 --- a/apps/www/src/content/docs/components/sidebar/index.mdx +++ b/apps/www/src/content/docs/components/sidebar/index.mdx @@ -215,10 +215,12 @@ The footer section is a container that accepts all `div` props. It's commonly us ### Trigger -A button that toggles the sidebar open/closed. It works whether the Sidebar is controlled or uncontrolled, so you can drop it into a header without wiring up any state yourself. It accepts all `IconButton` props (e.g. `size`) plus the ones below. +A button that toggles the sidebar open/closed. It works whether the Sidebar is controlled or uncontrolled, so you can drop it into a header without wiring up any state yourself. *Note: disabled automatically when the Sidebar has `collapsible="none"`. If you use `collapsible="hidden"`, don't place `Sidebar.Trigger` inside `Sidebar.Header`/`Main`/`Footer`, because those sections are hidden along with the rest of the collapsed content, taking the trigger with them. Render it as a direct child of `` instead, or use [external control](#external-control).* +- Inherits all IconButton props + ### More diff --git a/apps/www/src/content/docs/components/tour/index.mdx b/apps/www/src/content/docs/components/tour/index.mdx index 8261b4d09..fbd6ba8c6 100644 --- a/apps/www/src/content/docs/components/tour/index.mdx +++ b/apps/www/src/content/docs/components/tour/index.mdx @@ -170,6 +170,8 @@ The dimmed backdrop with a spotlight cutout over the target. Renders the step counter, e.g. "2 of 5". +- Inherits all Text props + ### Tour.Title / Tour.Description diff --git a/apps/www/src/content/docs/dataview/props.ts b/apps/www/src/content/docs/dataview/props.ts index 021aeadf2..fc28d2e80 100644 --- a/apps/www/src/content/docs/dataview/props.ts +++ b/apps/www/src/content/docs/dataview/props.ts @@ -127,13 +127,13 @@ export interface DataViewField { /** * Value type of a `select` or `multiselect` filter. - * @defaultValue "string" + * @default "string" */ dataType?: 'string' | 'number' | 'boolean'; /** * Value a new filter on this field starts with. `null` uses the default. - * @defaultValue today for `date`, the first option for `select`, otherwise `""` + * @default today for `date`, the first option for `select`, otherwise `""` */ defaultFilterValue?: | string @@ -153,7 +153,7 @@ export interface DataViewField { /** * Count shown next to each group header when `showGroupCount` is on, by raw group value. - * @defaultValue the group's row count + * @default the group's row count */ groupCountMap?: Record; } diff --git a/apps/www/src/content/docs/theme/overview/props.ts b/apps/www/src/content/docs/theme/overview/props.ts index fa7856be8..8d8265ddd 100644 --- a/apps/www/src/content/docs/theme/overview/props.ts +++ b/apps/www/src/content/docs/theme/overview/props.ts @@ -158,7 +158,7 @@ export type ThemeSwitcherProps = { target?: 'nearest' | 'root'; /** * Accessible name for the button. - * @defaultValue "Switch to light theme" when the `target` theme is dark, otherwise "Switch to dark theme" + * @default "Switch to light theme" when the `target` theme is dark, otherwise "Switch to dark theme" */ 'aria-label'?: string; }; From ed823f89f19509854521276c655d7a5e2743213b Mon Sep 17 00:00:00 2001 From: Shreyag02 Date: Mon, 19 Oct 2026 16:22:53 +0530 Subject: [PATCH 14/19] fix: [indicator, data-view] mark classNames as deprecated --- packages/react/components/data-view/components/filters.tsx | 1 + packages/react/components/indicator/indicator.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/react/components/data-view/components/filters.tsx b/packages/react/components/data-view/components/filters.tsx index 28f6a5cdc..4a5754720 100644 --- a/packages/react/components/data-view/components/filters.tsx +++ b/packages/react/components/data-view/components/filters.tsx @@ -103,6 +103,7 @@ function AddFilter({ } export interface DataViewFiltersProps extends PositionerProps { + /** @deprecated Use the `data-slot` selectors instead. */ classNames?: { /** @deprecated Use `[data-slot="filter-chip"]` instead. */ filterChips?: string; diff --git a/packages/react/components/indicator/indicator.tsx b/packages/react/components/indicator/indicator.tsx index e6dbbe29d..431990bfd 100644 --- a/packages/react/components/indicator/indicator.tsx +++ b/packages/react/components/indicator/indicator.tsx @@ -29,6 +29,7 @@ export interface IndicatorProps pulse?: boolean; children?: ReactNode; 'aria-label'?: string; + /** @deprecated Use the `data-slot` selectors instead. */ classNames?: { /** @deprecated Use `[data-slot="indicator"]` instead. */ container?: string; From a689ce28779881d28da7266810c9b1b091f4dde0 Mon Sep 17 00:00:00 2001 From: Shreyag02 Date: Mon, 19 Oct 2026 16:22:54 +0530 Subject: [PATCH 15/19] fix: [progress] make value optional to match its default --- .../components/progress/__tests__/progress.test.tsx | 8 ++++++++ packages/react/components/progress/progress-root.tsx | 10 ++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/react/components/progress/__tests__/progress.test.tsx b/packages/react/components/progress/__tests__/progress.test.tsx index 780df8f63..6e3625e5e 100644 --- a/packages/react/components/progress/__tests__/progress.test.tsx +++ b/packages/react/components/progress/__tests__/progress.test.tsx @@ -25,6 +25,14 @@ describe('Progress', () => { expect(progress).toHaveClass('custom-progress'); }); + it('defaults value to 0', () => { + render(); + expect(screen.getByRole('progressbar')).toHaveAttribute( + 'aria-valuenow', + '0' + ); + }); + it('renders track and indicator by default', () => { const { container } = render(); expect(container.querySelector(`.${styles.track}`)).toBeInTheDocument(); diff --git a/packages/react/components/progress/progress-root.tsx b/packages/react/components/progress/progress-root.tsx index 5abe62866..dfb17d04a 100644 --- a/packages/react/components/progress/progress-root.tsx +++ b/packages/react/components/progress/progress-root.tsx @@ -19,8 +19,14 @@ const progress = cva(styles.progress, { }); export interface ProgressProps - extends ProgressPrimitive.Root.Props, - VariantProps {} + extends Omit, + VariantProps { + /** + * The current value. `null` shows an indeterminate state. + * @default 0 + */ + value?: number | null; +} export interface ProgressContextValue { variant: 'linear' | 'circular'; From 7655bbed44beb0e3e28643a58f3810c17192810c Mon Sep 17 00:00:00 2001 From: Shreyag02 Date: Mon, 19 Oct 2026 16:22:55 +0530 Subject: [PATCH 16/19] feat: [docs] check props tables against component types in ci --- .github/workflows/tests.yml | 27 ++ AGENTS.md | 4 +- CONTRIBUTING.md | 1 + package.json | 7 +- pnpm-lock.yaml | 15 +- scripts/check-docs-props.js | 507 +++++++++++++++++++++++++++++++ scripts/check-docs-props.test.js | 104 +++++++ 7 files changed, 653 insertions(+), 12 deletions(-) create mode 100644 scripts/check-docs-props.js create mode 100644 scripts/check-docs-props.test.js diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 218d40db6..d60e261e0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -37,3 +37,30 @@ jobs: - name: Check build run: pnpm build:apsara + + docs: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 9.3.0 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 24.x + cache: "pnpm" + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Test docs tooling + run: pnpm test:docs + + - name: Check docs props tables + run: pnpm check:docs-props diff --git a/AGENTS.md b/AGENTS.md index f4c03220c..17c612ae9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -40,7 +40,9 @@ Skills are in `.agents/skills/`. `.claude/skills` is a symlink to that folder, s ## Docs - When you change props, variants, or behavior, update the docs page. -- `props.ts` is written by hand, not generated, and `` renders it. Check each prop name and value against the component. The two often get out of sync. +- `props.ts` is written by hand, and `` renders it. `pnpm check:docs-props` compares each exported interface with the component type and fails on drift. CI runs it. +- A docs interface matches the exported type with the same name, then the compound part (`CodeBlockHeaderProps` to `CodeBlock.Header`). Add other matches, docs-only types, inherited components, internal props and props the table keeps required to `CONFIG` in `scripts/check-docs-props.js`, with a reason for each internal or required prop. +- When a part inherits another Apsara component's props, add an `inherits` entry and write "Inherits all props" in the part's section of `index.mdx`. - `demo.ts` exports demo objects: `{ type: 'code', code }` for examples and `{ type: 'playground', controls, getCode }` for the playground. The code strings render live with the library in scope. - Set `defaultValue` on playground controls. The generated code then leaves out props that are at their default. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1dd85d93f..0b65330b1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -109,6 +109,7 @@ Do not worry if you miss a step. CI and the maintainers will help. - PR Title: checks that the title follows the [commit convention](#commit-convention). It runs again when you edit the title. - Tests: runs the Vitest suite and builds the library on Node 22 and 24. To reproduce it, run `pnpm test:apsara` and `pnpm build:apsara`. +- Docs: tests the docs tooling and checks that the props tables match the component types. To reproduce it, run `pnpm test:docs` and `pnpm check:docs-props`. - Canary Release: publishes a preview build to [pkg.pr.new](https://pkg.pr.new) and comments the install command on the PR. See [Canary releases](#canary-releases). - Vercel: deploys a preview of the docs site with your changes. diff --git a/package.json b/package.json index a5fd3b1e7..bf7917ea6 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,9 @@ "lint": "turbo lint --filter=@raystack/apsara", "clean": "turbo clean --filter=@raystack/apsara", "format": "pnpm exec biome check --staged --write .", - "ci:build": "turbo build --filter=@raystack/apsara" + "ci:build": "turbo build --filter=@raystack/apsara", + "check:docs-props": "node scripts/check-docs-props.js", + "test:docs": "vitest run scripts apps/www/src/lib" }, "devDependencies": { "@biomejs/biome": "2.3.8", @@ -21,7 +23,8 @@ "pkg-pr-new": "^0.0.86", "process": "^0.11.10", "turbo": "2.3.1", - "typescript": "4.7" + "typescript": "4.7", + "vitest": "^3.2.4" }, "packageManager": "pnpm@9.3.0", "name": "apsara", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d58544098..091d95f75 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -38,6 +38,9 @@ importers: typescript: specifier: '4.7' version: 4.7.2 + vitest: + specifier: ^3.2.4 + version: 3.2.4(@types/debug@4.1.12)(@types/node@24.10.0)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.39.0) apps/www: dependencies: @@ -61,7 +64,7 @@ importers: version: 1.3.8(typescript@5.9.3) fumadocs-mdx: specifier: 13.0.5 - version: 13.0.5(fumadocs-core@16.0.7(@types/react@19.2.2)(lucide-react@1.45.0(react@19.2.1))(next@16.0.7(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(next@16.0.7(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)(vite@7.1.3(@types/node@24.10.0)) + version: 13.0.5(fumadocs-core@16.0.7(@types/react@19.2.2)(lucide-react@1.45.0(react@19.2.1))(next@16.0.7(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(next@16.0.7(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)(vite@7.1.3(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.39.0)) fumadocs-typescript: specifier: ^4.0.6 version: 4.0.6(@types/react@19.2.2)(typescript@5.9.3) @@ -435,10 +438,6 @@ packages: resolution: {integrity: sha512-NpugTzbKgGrNe45Ui32cN8vCFFMxVtP/9rtfwv0nP5FRDAjvYBxJcLVpYA9mr1jxP6cnIT7x9LUzuDTbWYYNRA==} engines: {node: '>=6.9.0'} - '@babel/runtime@7.29.2': - resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} - engines: {node: '>=6.9.0'} - '@base-ui/react@1.8.0': resolution: {integrity: sha512-P0/1sxo6SBVZOklKMIedvTWqw2s2IQzi9x5bIVsXu980cuSOD4NeuRSs+/L7LZQfDkZP/uRZyGPyfFl/B1oH+Q==} engines: {node: '>=14.0.0'} @@ -6523,8 +6522,6 @@ snapshots: '@babel/runtime@7.29.10': {} - '@babel/runtime@7.29.2': {} - '@base-ui/react@1.8.0(@date-fns/tz@1.5.0)(@types/react@19.1.9)(date-fns@4.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: '@babel/runtime': 7.29.10 @@ -8259,7 +8256,7 @@ snapshots: '@testing-library/dom@10.4.0': dependencies: '@babel/code-frame': 7.26.2 - '@babel/runtime': 7.29.2 + '@babel/runtime': 7.29.10 '@types/aria-query': 5.0.4 aria-query: 5.3.0 chalk: 4.1.2 @@ -9641,7 +9638,7 @@ snapshots: - supports-color - typescript - fumadocs-mdx@13.0.5(fumadocs-core@16.0.7(@types/react@19.2.2)(lucide-react@1.45.0(react@19.2.1))(next@16.0.7(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(next@16.0.7(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)(vite@7.1.3(@types/node@24.10.0)): + fumadocs-mdx@13.0.5(fumadocs-core@16.0.7(@types/react@19.2.2)(lucide-react@1.45.0(react@19.2.1))(next@16.0.7(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(next@16.0.7(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)(vite@7.1.3(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.39.0)): dependencies: '@mdx-js/mdx': 3.1.1 '@standard-schema/spec': 1.0.0 diff --git a/scripts/check-docs-props.js b/scripts/check-docs-props.js new file mode 100644 index 000000000..ce3b613ec --- /dev/null +++ b/scripts/check-docs-props.js @@ -0,0 +1,507 @@ +const { readdirSync, readFileSync } = require('node:fs'); +const { createRequire } = require('node:module'); +const path = require('node:path'); + +const repoRoot = path.resolve(__dirname, '..'); +const reactRoot = path.join(repoRoot, 'packages/react'); +const docsRoot = path.join(repoRoot, 'apps/www/src/content/docs'); + +// The root workspace pins an older TypeScript than the library. +const ts = createRequire(path.join(reactRoot, 'package.json'))('typescript'); + +const toastManager = 'components/toast/toast-manager.ts'; + +/** + * Exceptions for the docs props check. + * + * - `matches`: docs interface to an exported type, a compound part + * (`Menu.SubmenuContent`) or `#` under `packages/react`. + * - `docsOnly`: docs interfaces with no component type. + * - `inherits`: Apsara components whose props a part inherits. The part's + * section in index.mdx must say "Inherits all props". + * - `internal`: component props left out of the table. + * - `required`: props the table marks required although the type allows + * leaving them out. + */ +const CONFIG = { + matches: { + BreadcrumbItem: 'BreadcrumbItemProps', + MenuSubContentProps: 'Menu.SubmenuContent', + ContextMenuSubContentProps: 'ContextMenu.SubmenuContent', + ToastManagerAddOptions: `${toastManager}#ToastAddOptions`, + ToastManagerUpdateOptions: `${toastManager}#ToastUpdateOptions`, + ToastManagerPromiseOptions: `${toastManager}#ToastPromiseOptions`, + CreateToastManagerReturn: `${toastManager}#ToastManager`, + UseToastManagerReturn: `${toastManager}#UseToastManagerReturn`, + ViewSpec: 'components/data-view/index.ts#ViewSpec' + }, + docsOnly: { + ToastObject: 'Base UI type of each item in `toasts`.', + ThemeIconProps: 'The `icons` prop of `Theme`, documented on the Icons page.' + }, + inherits: { + AlertDialogBodyProps: ['Flex'], + AlertDialogFooterProps: ['Flex'], + AlertDialogHeaderProps: ['Flex'], + CalendarPreviewFooterProps: ['Flex'], + CalendarPreviewInputProps: ['Input'], + CalendarPreviewResetProps: ['IconButton'], + CodeBlockCollapseTriggerProps: ['Button'], + CodeBlockCopyButtonProps: ['CopyButton'], + CodeBlockHeaderProps: ['Flex'], + CodeBlockLabelProps: ['Text'], + CodeBlockLanguageSelectProps: ['Select'], + CodeBlockLanguageSelectTriggerProps: ['Select.Trigger'], + ColorPickerModeProps: ['Select.Trigger'], + ColorPickerProps: ['Flex'], + ComboboxInputProps: ['Input'], + CommandInputProps: ['Input'], + CopyButtonProps: ['IconButton'], + DialogBodyProps: ['Flex'], + DialogFooterProps: ['Flex'], + DialogHeaderProps: ['Flex'], + EmptyStateProps: ['Flex'], + LinkProps: ['Text'], + NavbarCenterProps: ['Flex'], + NavbarEndProps: ['Flex'], + NavbarStartProps: ['Flex'], + PromptInputTextareaProps: ['TextArea'], + SearchProps: ['Input'], + SidebarTriggerProps: ['IconButton'], + TourProgressProps: ['Text'] + }, + internal: { + MenuRootProps: { + inputRef: 'Menu context field. The root does not read it.', + contentRef: 'Menu context field. The root does not read it.', + isInitialRender: 'Menu context field. The root does not read it.' + } + }, + required: { + SelectItemProps: { + value: 'Without it the item value is the string "undefined".' + } + } +}; + +const RULES = { + unmatched: 'docs interface matches no component type', + unknown: 'documented prop does not exist on the component', + deprecated: 'deprecated prop is in the table', + optional: 'required/optional differs from the component', + literals: 'literal values differ from the component', + missing: 'component prop is missing from the table', + inherits: 'inherited Apsara props need an inherits entry', + inheritsText: 'index.mdx does not say "Inherits all props"' +}; + +function findFiles(dir, name) { + return readdirSync(dir, { withFileTypes: true }).flatMap(entry => { + const full = path.join(dir, entry.name); + if (entry.isDirectory()) return findFiles(full, name); + return entry.name === name ? [full] : []; + }); +} + +const INHERITS_TEXT = component => + new RegExp(`Inherits all \`?${component.replace('.', '\\.')}\`? props`); + +function isExternal(file) { + return file.includes(`${path.sep}node_modules${path.sep}`); +} + +function isDeprecated(symbol) { + return (symbol.declarations ?? []).some(decl => + ts.getJSDocTags(decl).some(tag => tag.tagName.text === 'deprecated') + ); +} + +function isObjectLike(type) { + if (type.isUnion() || type.isIntersection()) + return type.types.every(isObjectLike); + return (type.flags & ts.TypeFlags.Object) !== 0; +} + +function literalValues(checker, type) { + const values = new Set(); + const members = type.isUnion() ? type.types : [type]; + for (const member of members) { + if (member.isStringLiteral()) values.add(JSON.stringify(member.value)); + else if (member.flags & ts.TypeFlags.BooleanLiteral) + values.add(checker.typeToString(member)); + } + return values; +} + +/** + * Returns the props of one or more types. A prop is optional when any union + * member or overload leaves it out or marks it optional. + */ +function collectProps(checker, types) { + const members = types.flatMap(type => { + const constraint = type.isTypeParameter() + ? checker.getBaseConstraintOfType(type) + : type; + if (!constraint) return []; + return constraint.isUnion() ? constraint.types : [constraint]; + }); + const props = new Map(); + members.forEach(member => { + for (const symbol of checker.getPropertiesOfType( + checker.getApparentType(member) + )) { + const name = symbol.getName(); + const optional = (symbol.flags & ts.SymbolFlags.Optional) !== 0; + const entry = props.get(name) ?? { + symbols: [], + optional: false, + count: 0 + }; + entry.symbols.push(symbol); + entry.optional ||= optional; + entry.count += 1; + props.set(name, entry); + } + }); + for (const entry of props.values()) { + if (entry.count < members.length) entry.optional = true; + } + return props; +} + +/** Returns the directory under `components/`, or undefined for shared code. */ +function componentDir(componentsRoot, file) { + const relative = path.relative(componentsRoot, file); + if (relative.startsWith('..') || path.isAbsolute(relative)) return undefined; + return relative.split(path.sep)[0]; +} + +function createProgram(sourceEntry, docsFiles, tsconfigPath) { + let options = { + strict: true, + noEmit: true, + skipLibCheck: true, + jsx: ts.JsxEmit.ReactJSX, + target: ts.ScriptTarget.ESNext, + module: ts.ModuleKind.ESNext, + moduleResolution: ts.ModuleResolutionKind.Bundler + }; + if (tsconfigPath) { + const { config } = ts.readConfigFile(tsconfigPath, ts.sys.readFile); + options = { + ...ts.parseJsonConfigFileContent( + config, + ts.sys, + path.dirname(tsconfigPath) + ).options, + noEmit: true, + skipLibCheck: true + }; + } + options.baseUrl ??= path.dirname(sourceEntry); + options.paths = { + ...options.paths, + '@raystack/apsara': [sourceEntry] + }; + return ts.createProgram([sourceEntry, ...docsFiles], options); +} + +/** + * Compares each interface in the docs `props.ts` files with the component + * type it documents. + */ +function checkDocsProps({ sourceEntry, docsFiles, config = {}, tsconfigPath }) { + const program = createProgram(sourceEntry, docsFiles, tsconfigPath); + const checker = program.getTypeChecker(); + const componentsRoot = path.join(path.dirname(sourceEntry), 'components'); + const issues = []; + + const entry = checker.getSymbolAtLocation(program.getSourceFile(sourceEntry)); + const exportsByName = new Map( + checker.getExportsOfModule(entry).map(symbol => [symbol.getName(), symbol]) + ); + + const resolve = symbol => + symbol.flags & ts.SymbolFlags.Alias + ? checker.getAliasedSymbol(symbol) + : symbol; + + // A docs name matches the first parameter of a compound part, for example + // `CodeBlockHeaderProps` to `CodeBlock.Header`. Overloads add one type each. + const firstParameter = (type, declaration) => { + const signatures = type.getCallSignatures(); + const types = signatures.flatMap(signature => { + const [param] = signature.getParameters(); + return param + ? [checker.getTypeOfSymbolAtLocation(param, declaration)] + : []; + }); + if (types.length === 0) return undefined; + return { + types, + file: (signatures[0].getDeclaration() ?? declaration).getSourceFile() + .fileName + }; + }; + + const partProps = new Map(); + for (const [name, exported] of exportsByName) { + const symbol = resolve(exported); + if (!(symbol.flags & ts.SymbolFlags.Value) || !symbol.valueDeclaration) + continue; + const valueType = checker.getTypeOfSymbolAtLocation( + symbol, + symbol.valueDeclaration + ); + if (valueType.getCallSignatures().length) { + partProps.set(`${name}Props`, name); + partProps.set(`${name}RootProps`, name); + } + for (const part of checker.getPropertiesOfType(valueType)) { + const partName = part.getName(); + if (!/^[A-Z]/.test(partName)) continue; + partProps.set(`${name}${partName}Props`, `${name}.${partName}`); + } + } + + const lookup = target => { + const [modulePath, typeName] = target.split('#'); + if (typeName) { + const module = program.getSourceFile( + path.join(path.dirname(sourceEntry), modulePath) + ); + const symbol = + module && + checker + .getExportsOfModule(checker.getSymbolAtLocation(module)) + .find(s => s.getName() === typeName); + if (!symbol) return undefined; + const resolved = resolve(symbol); + return { + types: [checker.getDeclaredTypeOfSymbol(resolved)], + file: resolved.declarations[0].getSourceFile().fileName + }; + } + const [head, ...rest] = target.split('.'); + const exported = exportsByName.get(head); + if (!exported) return undefined; + let symbol = resolve(exported); + if (rest.length === 0 && symbol.flags & ts.SymbolFlags.Type) { + return { + types: [checker.getDeclaredTypeOfSymbol(symbol)], + file: symbol.declarations[0].getSourceFile().fileName + }; + } + if (!symbol.valueDeclaration) return undefined; + let type = checker.getTypeOfSymbolAtLocation( + symbol, + symbol.valueDeclaration + ); + for (const key of rest) { + symbol = type.getProperty(key); + if (!symbol) return undefined; + type = checker.getTypeOfSymbolAtLocation( + symbol, + symbol.valueDeclaration ?? symbol.declarations[0] + ); + } + return firstParameter( + type, + symbol.valueDeclaration ?? symbol.declarations[0] + ); + }; + + const docsOnly = config.docsOnly ?? {}; + const matches = config.matches ?? {}; + const inherits = config.inherits ?? {}; + const internal = config.internal ?? {}; + + for (const file of docsFiles) { + const sourceFile = program.getSourceFile(file); + const mdxPath = path.join(path.dirname(file), 'index.mdx'); + let mdx; + try { + mdx = readFileSync(mdxPath, 'utf8'); + } catch { + mdx = ''; + } + + for (const statement of sourceFile.statements) { + if ( + !ts.isInterfaceDeclaration(statement) && + !ts.isTypeAliasDeclaration(statement) + ) + continue; + const name = statement.name.text; + const symbol = checker.getSymbolAtLocation(statement.name); + const docsType = checker.getDeclaredTypeOfSymbol(symbol); + const exported = statement.modifiers?.some( + m => m.kind === ts.SyntaxKind.ExportKeyword + ); + if (!exported) continue; + if (ts.isTypeAliasDeclaration(statement) && !isObjectLike(docsType)) + continue; + + const { line } = sourceFile.getLineAndCharacterOfPosition( + statement.name.getStart() + ); + const report = (rule, prop, detail) => + issues.push({ + rule, + file, + line: line + 1, + name, + prop, + detail + }); + + if (docsOnly[name]) continue; + const real = + (matches[name] && lookup(matches[name])) || + lookup(name) || + (partProps.has(name) && lookup(partProps.get(name))); + if (!real) { + report('unmatched'); + continue; + } + + // Props the docs type inherits from React or Base UI are not in the docs file. + const docsProps = new Map( + [...collectProps(checker, [docsType])].filter(([, docsProp]) => + docsProp.symbols.some(s => + (s.declarations ?? []).some( + d => !isExternal(d.getSourceFile().fileName) + ) + ) + ) + ); + const realProps = collectProps(checker, real.types); + const ownDir = componentDir(componentsRoot, real.file); + + for (const [prop, docsProp] of docsProps) { + const realProp = realProps.get(prop); + if (!realProp) { + report('unknown', prop); + continue; + } + if (realProp.symbols.some(isDeprecated)) report('deprecated', prop); + if ( + docsProp.optional !== realProp.optional && + !(!docsProp.optional && config.required?.[name]?.[prop]) + ) { + report( + 'optional', + prop, + `docs ${docsProp.optional ? 'optional' : 'required'}, component ${realProp.optional ? 'optional' : 'required'}` + ); + } + const docsValues = literalValues( + checker, + checker.getNonNullableType( + checker.getTypeOfSymbol(docsProp.symbols[0]) + ) + ); + const realValues = new Set( + realProp.symbols.flatMap(s => [ + ...literalValues( + checker, + checker.getNonNullableType(checker.getTypeOfSymbol(s)) + ) + ]) + ); + if (docsValues.size === 0 || realValues.size === 0) continue; + const onlyDocs = [...docsValues].filter(v => !realValues.has(v)); + const onlyReal = [...realValues].filter(v => !docsValues.has(v)); + if (onlyDocs.length || onlyReal.length) { + report( + 'literals', + prop, + [ + onlyReal.length && `component also has ${onlyReal.join(' | ')}`, + onlyDocs.length && `docs also has ${onlyDocs.join(' | ')}` + ] + .filter(Boolean) + .join('; ') + ); + } + } + + const inheritedProps = new Set(); + for (const component of inherits[name] ?? []) { + const source = lookup(`${component.replace('.', '')}Props`); + if (!source) throw new Error(`${name}: no ${component}Props export`); + for (const prop of collectProps(checker, source.types).keys()) + inheritedProps.add(prop); + if (!INHERITS_TEXT(component).test(sectionFor(mdx, name))) + report('inheritsText', undefined, component); + } + + for (const [prop, realProp] of realProps) { + if ( + docsProps.has(prop) || + inheritedProps.has(prop) || + internal[name]?.[prop] || + realProp.symbols.some(isDeprecated) + ) + continue; + const files = realProp.symbols + .flatMap(s => s.declarations ?? []) + .map(d => d.getSourceFile().fileName) + .filter(f => !isExternal(f)); + if (files.length === 0) continue; + const dirs = files.map(f => componentDir(componentsRoot, f)); + if (dirs.some(dir => dir === undefined || dir === ownDir)) + report('missing', prop); + else report('inherits', prop, `from components/${dirs[0]}`); + } + } + } + return issues; +} + +/** Returns the index.mdx text from the heading above a table to the next heading. */ +function sectionFor(mdx, name) { + const lines = mdx.split('\n'); + const at = lines.findIndex(l => l.includes(`name="${name}"`)); + if (at === -1) return ''; + let start = at; + while (start > 0 && !/^#{1,6} /.test(lines[start])) start -= 1; + let end = at + 1; + while (end < lines.length && !/^#{1,6} /.test(lines[end])) end += 1; + return lines.slice(start, end).join('\n'); +} + +function formatIssues(issues) { + return issues + .map(issue => { + const where = `${path.relative(repoRoot, issue.file)}:${issue.line}`; + const subject = issue.prop ? `${issue.name}.${issue.prop}` : issue.name; + const detail = issue.detail ? ` (${issue.detail})` : ''; + return `${where} ${subject}: ${RULES[issue.rule]}${detail}`; + }) + .join('\n'); +} + +function main() { + const issues = checkDocsProps({ + sourceEntry: path.join(reactRoot, 'index.tsx'), + docsFiles: findFiles(docsRoot, 'props.ts'), + tsconfigPath: path.join(reactRoot, 'tsconfig.json'), + config: CONFIG + }); + if (issues.length === 0) { + console.log('Docs props tables match the components.'); + return; + } + console.error(formatIssues(issues)); + console.error(''); + for (const rule of Object.keys(RULES)) { + const count = issues.filter(issue => issue.rule === rule).length; + if (count) console.error(`${count} ${RULES[rule]}`); + } + process.exitCode = 1; +} + +module.exports = { checkDocsProps }; + +if (require.main === module) main(); diff --git a/scripts/check-docs-props.test.js b/scripts/check-docs-props.test.js new file mode 100644 index 000000000..b2619b89e --- /dev/null +++ b/scripts/check-docs-props.test.js @@ -0,0 +1,104 @@ +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { afterAll, expect, test } from 'vitest'; +import { checkDocsProps } from './check-docs-props.js'; + +const root = mkdtempSync(path.join(tmpdir(), 'docs-props-')); +afterAll(() => rmSync(root, { recursive: true, force: true })); + +function write(file, content) { + mkdirSync(path.dirname(path.join(root, file)), { recursive: true }); + writeFileSync(path.join(root, file), content); +} + +write( + 'src/index.tsx', + `export { Flex, type FlexProps } from './components/flex/flex'; +export { type BarProps, Foo, type FooProps } from './components/foo/foo'; +` +); +write( + 'src/components/flex/flex.tsx', + `export interface FlexProps { gap?: number } +export function Flex(_props: FlexProps) { return null; } +` +); +write( + 'src/components/foo/foo.tsx', + `import type { FlexProps } from '../flex/flex'; +export interface FooProps { + size: 'small' | 'large'; + /** @deprecated Use \`size\`. */ + legacy?: boolean; + open?: boolean | 'trap-focus'; + tone?: string; + internalFlag?: boolean; +} +export type BarProps = { kind: 'a'; label: string } | { kind: 'b' }; +export interface FooItemData { label?: string } +type PartProps = FlexProps & { title?: string }; +function FooRoot(_props: FooProps) { return null; } +function FooPart(_props: PartProps) { return null; } +export const Foo = Object.assign(FooRoot, { + Header: FooPart, + Body: FooPart, + Footer: FooPart +}); +` +); +write( + 'docs/foo/props.ts', + `export type Size = 'small' | 'large'; +export interface FooProps { + size?: Size; + legacy?: boolean; + open?: boolean; + extra?: string; +} +export interface FooHeaderProps { title?: string } +export interface FooBodyProps { title?: string } +export interface FooFooterProps { title?: string } +export interface BarProps { kind: 'a' | 'b'; label?: string } +export interface FooItem { label?: string } +export interface Orphan { label?: string } +export interface DocsOnlyThing { label?: string } +` +); +write( + 'docs/foo/index.mdx', + `### Header + +- Inherits all Flex props + + + +### Footer + + +` +); + +test('reports each rule', () => { + const issues = checkDocsProps({ + sourceEntry: path.join(root, 'src/index.tsx'), + docsFiles: [path.join(root, 'docs/foo/props.ts')], + config: { + matches: { FooItem: 'components/foo/foo.tsx#FooItemData' }, + docsOnly: { DocsOnlyThing: 'Fixture type with no component.' }, + inherits: { FooHeaderProps: ['Flex'], FooFooterProps: ['Flex'] }, + internal: { FooProps: { internalFlag: 'Fixture internal prop.' } } + } + }); + + expect(issues.map(({ rule, name, prop }) => [rule, name, prop])).toEqual([ + ['optional', 'FooProps', 'size'], + ['deprecated', 'FooProps', 'legacy'], + ['literals', 'FooProps', 'open'], + ['unknown', 'FooProps', 'extra'], + ['missing', 'FooProps', 'tone'], + ['inherits', 'FooBodyProps', 'gap'], + ['inheritsText', 'FooFooterProps', undefined], + ['unmatched', 'Orphan', undefined] + ]); +}); From 75945fd5b9e75dcae139ecc6b9cfcae47a5caf12 Mon Sep 17 00:00:00 2001 From: Shreyag02 Date: Mon, 19 Oct 2026 16:22:56 +0530 Subject: [PATCH 17/19] feat: [docs] show each component's changelog from git history --- apps/www/package.json | 2 +- apps/www/src/app/docs/[[...slug]]/page.tsx | 18 ++- apps/www/src/components/docs/changelog.tsx | 42 +++++++ apps/www/src/lib/changelog.test.ts | 21 ++++ apps/www/src/lib/changelog.ts | 126 +++++++++++++++++++++ 5 files changed, 207 insertions(+), 2 deletions(-) create mode 100644 apps/www/src/components/docs/changelog.tsx create mode 100644 apps/www/src/lib/changelog.test.ts create mode 100644 apps/www/src/lib/changelog.ts diff --git a/apps/www/package.json b/apps/www/package.json index f5ff8770c..a1f784904 100644 --- a/apps/www/package.json +++ b/apps/www/package.json @@ -3,7 +3,7 @@ "version": "0.1.0", "private": true, "scripts": { - "prebuild": "cd ../.. && npm run build:apsara", + "prebuild": "cd ../.. && (git rev-parse -q --verify refs/tags/v1.0.0 >/dev/null || git fetch -q --tags $(test \"$(git rev-parse --is-shallow-repository)\" = true && echo --unshallow) https://github.com/raystack/apsara.git || true) && npm run build:apsara", "dev": "next dev", "build": "next build", "start": "next start", diff --git a/apps/www/src/app/docs/[[...slug]]/page.tsx b/apps/www/src/app/docs/[[...slug]]/page.tsx index 806cd1691..1268f09f6 100644 --- a/apps/www/src/app/docs/[[...slug]]/page.tsx +++ b/apps/www/src/app/docs/[[...slug]]/page.tsx @@ -3,13 +3,24 @@ import { createRelativeLink } from 'fumadocs-ui/mdx'; import type { Metadata } from 'next'; import { notFound } from 'next/navigation'; import { DemoContextProvider } from '@/components/demo/demo-context'; +import Changelog from '@/components/docs/changelog'; import DocsFooter from '@/components/docs/footer'; import DocsNavbar from '@/components/docs/navbar'; import { mdxComponents } from '@/components/mdx'; import TableOfContents from '@/components/toc/toc'; +import { getChangelog } from '@/lib/changelog'; import { docs } from '@/lib/source'; import styles from './page.module.css'; +/** Returns the commit scope of a component page. */ +function changelogScope(slugs: string[]) { + const [section, name] = slugs; + if (section === 'dataview') return 'data-view'; + if ((section === 'components' || section === 'ai-elements') && name) + return name; + return undefined; +} + export default async function Page(props: PageProps<'/docs/[[...slug]]'>) { const params = await props.params; const page = docs.getPage(params.slug); @@ -18,6 +29,10 @@ export default async function Page(props: PageProps<'/docs/[[...slug]]'>) { const MDX = page.data.body; const content = (page.data._exports?._markdown ?? '') as string; const hasPlayground = content.includes(' @@ -59,13 +74,14 @@ export default async function Page(props: PageProps<'/docs/[[...slug]]'>) { a: createRelativeLink(docs, page) }} /> + {scope && } diff --git a/apps/www/src/components/docs/changelog.tsx b/apps/www/src/components/docs/changelog.tsx new file mode 100644 index 000000000..bcf2fe56f --- /dev/null +++ b/apps/www/src/components/docs/changelog.tsx @@ -0,0 +1,42 @@ +import { mdxComponents } from '@/components/mdx'; +import { type ChangelogRelease, RELEASES_URL } from '@/lib/changelog'; + +const { h2: H2, h3: H3, a: A } = mdxComponents; + +export default function Changelog({ + releases +}: { + releases: ChangelogRelease[] | null; +}) { + return ( + <> +

Changelog

+ {releases?.length === 0 &&

No changes since v1.0.0.

} + {releases?.map(release => ( +
+

+ {release.tag ? ( + {release.tag} + ) : ( + 'Unreleased' + )} +

+
    + {release.entries.map(entry => ( +
  • + {entry.type}: {entry.summary} ( + + #{entry.pr} + + ) +
  • + ))} +
+
+ ))} +

+ See GitHub Releases for every release. +

+ + ); +} diff --git a/apps/www/src/lib/changelog.test.ts b/apps/www/src/lib/changelog.test.ts new file mode 100644 index 000000000..f8b131d47 --- /dev/null +++ b/apps/www/src/lib/changelog.test.ts @@ -0,0 +1,21 @@ +import { expect, test } from 'vitest'; +import { parseCommit } from './changelog'; + +const select = ['packages/react/components/select/select-root.tsx']; + +test.each([ + ['fix: [select] keep focus (#1)', [], ['select']], + ['feat: [dialog, data-view] add sizes (#2)', [], ['dialog', 'data-view']], + ['fix(theme): set dir (#3)', [], ['theme']], + ['fix: keep focus (#4)', select, ['select']], + [ + 'fix: keep focus (#5)', + [...select, 'packages/react/components/menu/menu-root.tsx'], + undefined + ], + ['fix: [docs] fix a typo (#6)', [], ['docs']], + ['docs: [select] fix a typo (#7)', [], undefined], + ['fix: [select] keep focus', [], undefined] +])('%s', (subject, files, scopes) => { + expect(parseCommit(subject, files)?.scopes).toEqual(scopes); +}); diff --git a/apps/www/src/lib/changelog.ts b/apps/www/src/lib/changelog.ts new file mode 100644 index 000000000..0d12957e2 --- /dev/null +++ b/apps/www/src/lib/changelog.ts @@ -0,0 +1,126 @@ +import { execFileSync } from 'node:child_process'; + +export const RELEASES_URL = 'https://github.com/raystack/apsara/releases'; + +// Releases before v1.0.0 are the Radix-based library. +const FIRST_TAG = 'v1.0.0'; +const TYPES = new Set(['feat', 'fix', 'refactor']); +const SUBJECT = + /^(\w+)(?:\(([^)]*)\))?!?:\s*(?:\[([^\]]*)\]\s*)?(.+?)\s*\(#(\d+)\)$/; +const COMPONENT_DIR = /^packages\/(?:react|raystack)\/components\/([^/]+)\//; + +export interface ChangelogEntry { + type: string; + summary: string; + pr: number; +} + +export interface ChangelogRelease { + /** `null` for commits after the latest tag. */ + tag: string | null; + entries: ChangelogEntry[]; +} + +/** + * Reads a squash-merged subject, `: [] (#)` or + * `(): (#)`. A subject without scopes belongs to a + * component only when the commit changes one component directory. + */ +export function parseCommit(subject: string, files: string[]) { + const match = SUBJECT.exec(subject); + if (!match) return undefined; + const [, type, parenScopes, bracketScopes, summary, pr] = match; + if (!TYPES.has(type)) return undefined; + let scopes = (bracketScopes ?? parenScopes ?? '') + .split(',') + .map(scope => scope.trim().toLowerCase()) + .filter(Boolean); + if (scopes.length === 0) { + const dirs = new Set( + files.flatMap(file => COMPONENT_DIR.exec(file)?.[1] ?? []) + ); + if (dirs.size === 1) scopes = [...dirs]; + } + if (scopes.length === 0) return undefined; + return { type, scopes, summary, pr: Number(pr) }; +} + +function git(args: string[]) { + return execFileSync('git', args, { + encoding: 'utf8', + stdio: ['ignore', 'pipe', 'ignore'], + maxBuffer: 64 * 1024 * 1024 + }); +} + +function versionOf(tag: string) { + return tag.slice(1).split('.').map(Number); +} + +function compareTags(a: string, b: string) { + const [x, y] = [versionOf(a), versionOf(b)]; + return x[0] - y[0] || x[1] - y[1] || x[2] - y[2]; +} + +function readRange(range: string) { + return git(['log', '--no-merges', '--format=%x1e%s', '--name-only', range]) + .split('\x1e') + .slice(1) + .map(chunk => { + const [subject, ...files] = chunk.trim().split('\n'); + return parseCommit(subject, files.filter(Boolean)); + }) + .filter(commit => commit !== undefined); +} + +/** Maps each scope to its releases, newest first. */ +function readChangelog() { + const tags = git(['tag', '--merged', 'HEAD', '--list', 'v*']) + .split('\n') + .filter(tag => /^v\d+\.\d+\.\d+$/.test(tag)) + .filter(tag => compareTags(tag, FIRST_TAG) >= 0) + .sort(compareTags) + .reverse(); + if (!tags.includes(FIRST_TAG)) return undefined; + + const ranges: [string | null, string][] = [[null, `${tags[0]}..HEAD`]]; + tags.slice(0, -1).forEach((tag, index) => { + ranges.push([tag, `${tags[index + 1]}..${tag}`]); + }); + + const byScope = new Map(); + for (const [tag, range] of ranges) { + for (const { scopes, ...entry } of readRange(range)) { + for (const scope of scopes) { + const releases = byScope.get(scope) ?? []; + let release = releases.at(-1); + if (release?.tag !== tag) { + release = { tag, entries: [] }; + releases.push(release); + } + release.entries.push(entry); + byScope.set(scope, releases); + } + } + } + return byScope; +} + +let cache: Map | null | undefined; + +/** + * Returns the releases that changed a component, newest first, or `null` when + * the build has no git history or tags. + */ +export function getChangelog(scope: string): ChangelogRelease[] | null { + if (cache === undefined) { + try { + cache = readChangelog() ?? null; + } catch { + cache = null; + } + if (cache === null) + console.warn('Changelog: no git history or tags, so pages show none.'); + } + return cache === null ? null : (cache.get(scope) ?? []); +} From 010d3c41beaec246e4eb79cc9e2a206645e72e72 Mon Sep 17 00:00:00 2001 From: Shreyag02 Date: Wed, 28 Oct 2026 12:33:35 +0530 Subject: [PATCH 18/19] fix: [docs] correct the RangePicker onSelect description --- apps/www/src/content/docs/components/calendar/props.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/www/src/content/docs/components/calendar/props.ts b/apps/www/src/content/docs/components/calendar/props.ts index 7c3b0099b..4331e4865 100644 --- a/apps/www/src/content/docs/components/calendar/props.ts +++ b/apps/www/src/content/docs/components/calendar/props.ts @@ -155,9 +155,9 @@ export interface RangePickerProps { dateFormat?: string; /** - * Fires on every step of range selection — not only on the completed range. - * Both fields are optional during partial selection; gate on `range.to` if - * you only want completed ranges. + * Fires on each day picked in the calendar. `from` is always set, and `to` + * is set only when the range is complete. Check `range.to` to handle only + * completed ranges. */ onSelect?: (range: { from: Date | undefined; to?: Date }) => void; From 17b2edf54d74458f760d81973fa01d0bbf71739f Mon Sep 17 00:00:00 2001 From: Shreyag02 Date: Wed, 28 Oct 2026 13:11:05 +0530 Subject: [PATCH 19/19] fix: [docs] address review comments on command, editor and the props check --- apps/www/src/content/docs/components/command/index.mdx | 4 ++-- apps/www/src/content/docs/components/command/props.ts | 2 +- apps/www/src/content/docs/components/editor/props.ts | 2 +- scripts/check-docs-props.js | 3 ++- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/www/src/content/docs/components/command/index.mdx b/apps/www/src/content/docs/components/command/index.mdx index fbdd97da8..60116110b 100644 --- a/apps/www/src/content/docs/components/command/index.mdx +++ b/apps/www/src/content/docs/components/command/index.mdx @@ -99,9 +99,9 @@ The root element owns the input value, the list of items, and the context used b ### Input -Text input that drives the search. Defaults to a magnifying-glass leading icon. +Text input that drives the search. -- Inherits all Input props +- Inherits all Input props except `trailingIcon`, `chips`, `maxChipsVisible` and `variant`. diff --git a/apps/www/src/content/docs/components/command/props.ts b/apps/www/src/content/docs/components/command/props.ts index 717c87fea..4624026b1 100644 --- a/apps/www/src/content/docs/components/command/props.ts +++ b/apps/www/src/content/docs/components/command/props.ts @@ -58,7 +58,7 @@ export interface CommandInputProps { /** Placeholder text for the input. */ placeholder?: string; - /** Icon rendered at the start of the input. Defaults to a magnifying glass. */ + /** Icon rendered at the start of the input. */ leadingIcon?: React.ReactNode; /** diff --git a/apps/www/src/content/docs/components/editor/props.ts b/apps/www/src/content/docs/components/editor/props.ts index 5ea25a208..37cbd1461 100644 --- a/apps/www/src/content/docs/components/editor/props.ts +++ b/apps/www/src/content/docs/components/editor/props.ts @@ -14,7 +14,7 @@ export interface EditorProps { /** * Fires once per doc change. It does not fire for changes made through * `value`, or for labels from `resolveMentions`. The value is always editor - * JSON. + * JSON. With the `markdown` prop, `details` is `EditorMarkdownChangeDetails`. */ onValueChange?: (value: EditorJSON, details: EditorChangeDetails) => void; diff --git a/scripts/check-docs-props.js b/scripts/check-docs-props.js index 2c05240d2..a398420cb 100644 --- a/scripts/check-docs-props.js +++ b/scripts/check-docs-props.js @@ -108,8 +108,9 @@ function findFiles(dir, name) { const INHERITS_TEXT = component => new RegExp(`Inherits all \`?${component.replace('.', '\\.')}\`? props`); +// TypeScript reports file names with `/` on every platform. function isExternal(file) { - return file.includes(`${path.sep}node_modules${path.sep}`); + return file.includes('/node_modules/'); } function isDeprecated(symbol) {