diff --git a/.changeset/old-plums-explode.md b/.changeset/old-plums-explode.md new file mode 100644 index 00000000000..494da343cbb --- /dev/null +++ b/.changeset/old-plums-explode.md @@ -0,0 +1,5 @@ +--- +"@primer/react": patch +--- + +fix(DataTable): export datatable utility types diff --git a/contributor-docs/adrs/adr-002-behavior-isolation.md b/contributor-docs/adrs/adr-002-behavior-isolation.md index 072099e985c..575468dadc1 100644 --- a/contributor-docs/adrs/adr-002-behavior-isolation.md +++ b/contributor-docs/adrs/adr-002-behavior-isolation.md @@ -108,5 +108,7 @@ Some behaviors can be implemented as vanilla JavaScript without introducing addi In general, _portions of behaviors_ that affect or rely on **user interactions and events**, **shared state**, or **CSS styles** should be kept in React Hooks. Parts of the behavior that can be implemented in isolation of these concepts should be built with no dependency on React or other libraries. [^1]: https://codesandbox.io/s/demo-styling-custom-element-g973d?file=/src/index.tsx + [^2]: https://github.com/github/details-dialog-element/blob/main/src/index.ts#L195 + [^3]: https://github.com/github/details-dialog-element#details-dialog-close diff --git a/package-lock.json b/package-lock.json index 48c76c6bd04..859cf34e62e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "examples/*" ], "devDependencies": { - "@babel/eslint-parser": "7.23.3", + "@babel/eslint-parser": "7.25.9", "@changesets/changelog-github": "0.5.0", "@changesets/cli": "2.27.1", "@github/axe-github": "0.6.1", @@ -44,7 +44,7 @@ "jest-watch-typeahead": "2.2.2", "markdownlint-cli2": "^0.11.0", "markdownlint-cli2-formatter-pretty": "0.0.3", - "prettier": "3.0.3", + "prettier": "3.3.3", "rimraf": "5.0.5", "size-limit": "11.1.5", "stylelint": "16.9.0", @@ -62,7 +62,7 @@ "name": "example-app-router", "version": "0.0.0", "dependencies": { - "@primer/react": "37.0.0-rc.11", + "@primer/react": "37.0.1", "next": "^14.2.10", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -81,7 +81,7 @@ "react-dom": "^18.3.1" }, "devDependencies": { - "@primer/react": "37.0.0-rc.11", + "@primer/react": "37.0.1", "@types/react": "^18.3.11", "@types/react-dom": "^18.3.0", "@typescript-eslint/eslint-plugin": "^7.11.0", @@ -99,7 +99,7 @@ "name": "example-consumer-test", "version": "0.0.0", "dependencies": { - "@primer/react": "37.0.0-rc.11", + "@primer/react": "37.0.1", "@types/react": "^18.3.11", "@types/react-dom": "^18.2.19", "@types/styled-components": "^5.1.11", @@ -125,7 +125,7 @@ "version": "0.0.0", "dependencies": { "@primer/octicons-react": "^19.9.0", - "@primer/react": "37.0.0-rc.11", + "@primer/react": "37.0.1", "clsx": "^1.2.1", "next": "^14.2.10", "react": "^18.3.1", @@ -303,9 +303,10 @@ } }, "node_modules/@babel/eslint-parser": { - "version": "7.23.3", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.25.9.tgz", + "integrity": "sha512-5UXfgpK0j0Xr/xIdgdLEhOFxaDZ0bRPWJJchRpqOSur/3rZoPbqqki5mm0p4NE2cs28krBEiSM2MB7//afRSQQ==", "dev": true, - "license": "MIT", "dependencies": { "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", "eslint-visitor-keys": "^2.1.0", @@ -316,7 +317,7 @@ }, "peerDependencies": { "@babel/core": "^7.11.0", - "eslint": "^7.5.0 || ^8.0.0" + "eslint": "^7.5.0 || ^8.0.0 || ^9.0.0" } }, "node_modules/@babel/eslint-parser/node_modules/semver": { @@ -5993,22 +5994,6 @@ "prettier": "3.3" } }, - "node_modules/@primer/stylelint-config/node_modules/prettier": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", - "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, "node_modules/@primer/view-components": { "version": "0.27.0", "dev": true, @@ -7104,21 +7089,6 @@ "node": ">=4.0" } }, - "node_modules/@storybook/addon-storysource/node_modules/prettier": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", - "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", - "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, "node_modules/@storybook/addon-toolbars": { "version": "8.3.0", "dev": true, @@ -7832,20 +7802,6 @@ "node": ">=4.0" } }, - "node_modules/@storybook/source-loader/node_modules/prettier": { - "version": "3.3.3", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, "node_modules/@storybook/test": { "version": "8.3.0", "dev": true, @@ -23968,9 +23924,9 @@ } }, "node_modules/prettier": { - "version": "3.0.3", - "dev": true, - "license": "MIT", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", "bin": { "prettier": "bin/prettier.cjs" }, @@ -30099,7 +30055,7 @@ }, "packages/react": { "name": "@primer/react", - "version": "37.0.0-rc.11", + "version": "37.0.1", "license": "MIT", "dependencies": { "@github/relative-time-element": "^4.4.2", @@ -30477,19 +30433,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "packages/react/node_modules/prettier": { - "version": "3.3.3", - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, "packages/react/node_modules/rollup-plugin-visualizer": { "version": "5.9.2", "dev": true, diff --git a/package.json b/package.json index e5402ad0b14..4a9020b2e90 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "npm": ">=7" }, "devDependencies": { - "@babel/eslint-parser": "7.23.3", + "@babel/eslint-parser": "7.25.9", "@changesets/changelog-github": "0.5.0", "@changesets/cli": "2.27.1", "@github/axe-github": "0.6.1", @@ -72,7 +72,7 @@ "jest-watch-typeahead": "2.2.2", "markdownlint-cli2": "^0.11.0", "markdownlint-cli2-formatter-pretty": "0.0.3", - "prettier": "3.0.3", + "prettier": "3.3.3", "rimraf": "5.0.5", "size-limit": "11.1.5", "stylelint": "16.9.0", diff --git a/packages/react/src/ActionList/Group.tsx b/packages/react/src/ActionList/Group.tsx index 1e29f5be58d..d0db9a77ff2 100644 --- a/packages/react/src/ActionList/Group.tsx +++ b/packages/react/src/ActionList/Group.tsx @@ -97,7 +97,7 @@ export const Group: React.FC> = ({ // because the heading is hidden from the accessibility tree and only used for presentation role. // We will instead use aria-label to label the list. See a line below. aria-labelledby={listRole ? undefined : groupHeadingId} - aria-label={listRole ? title ?? (slots.groupHeading?.props.children as string) : undefined} + aria-label={listRole ? (title ?? (slots.groupHeading?.props.children as string)) : undefined} role={role || (listRole && 'group')} > {slots.groupHeading ? childrenWithoutSlots : props.children} diff --git a/packages/react/src/ActionList/List.tsx b/packages/react/src/ActionList/List.tsx index 7786f392682..874ce8195ef 100644 --- a/packages/react/src/ActionList/List.tsx +++ b/packages/react/src/ActionList/List.tsx @@ -39,7 +39,7 @@ export const List = React.forwardRef( enableFocusZone: enableFocusZoneFromContainer, } = React.useContext(ActionListContainerContext) - const ariaLabelledBy = slots.heading ? slots.heading.props.id ?? headingId : listLabelledBy + const ariaLabelledBy = slots.heading ? (slots.heading.props.id ?? headingId) : listLabelledBy const listRole = role || listRoleFromContainer const listRef = useProvidedRefOrCreate(forwardedRef as React.RefObject) diff --git a/packages/react/src/Button/ButtonBase.tsx b/packages/react/src/Button/ButtonBase.tsx index dc4ffdcfad1..f64137b8433 100644 --- a/packages/react/src/Button/ButtonBase.tsx +++ b/packages/react/src/Button/ButtonBase.tsx @@ -198,13 +198,13 @@ const ButtonBase = forwardRef( true, ) : TrailingVisual - ? renderModuleVisual( - TrailingVisual, - Boolean(loading) && !LeadingVisual, - 'trailingVisual', - false, - ) - : null + ? renderModuleVisual( + TrailingVisual, + Boolean(loading) && !LeadingVisual, + 'trailingVisual', + false, + ) + : null } { @@ -314,8 +314,13 @@ const ButtonBase = forwardRef( true, ) : TrailingVisual - ? renderModuleVisual(TrailingVisual, Boolean(loading) && !LeadingVisual, 'trailingVisual', false) - : null + ? renderModuleVisual( + TrailingVisual, + Boolean(loading) && !LeadingVisual, + 'trailingVisual', + false, + ) + : null } { @@ -420,8 +425,8 @@ const ButtonBase = forwardRef( 'trailingVisual', ) : TrailingVisual - ? renderVisual(TrailingVisual, Boolean(loading) && !LeadingVisual, 'trailingVisual') - : null + ? renderVisual(TrailingVisual, Boolean(loading) && !LeadingVisual, 'trailingVisual') + : null } { diff --git a/packages/react/src/DataTable/DataTable.stories.tsx b/packages/react/src/DataTable/DataTable.stories.tsx index 7726463411d..610b33dfcb0 100644 --- a/packages/react/src/DataTable/DataTable.stories.tsx +++ b/packages/react/src/DataTable/DataTable.stories.tsx @@ -189,8 +189,8 @@ export const Playground = (args: DataTableProps & ColWidthArgTypes) = return args[`colWidth${colIndex}`] !== 'explicit width' ? args[`colWidth${colIndex}`] : args[`explicitColWidth${colIndex}`] - ? args[`explicitColWidth${colIndex}`] - : 'grow' + ? args[`explicitColWidth${colIndex}`] + : 'grow' } const align = args.align as CellAlignment diff --git a/packages/react/src/DataTable/index.ts b/packages/react/src/DataTable/index.ts index 620df9a88f3..a21097e624a 100644 --- a/packages/react/src/DataTable/index.ts +++ b/packages/react/src/DataTable/index.ts @@ -50,4 +50,6 @@ export type { TableSkeletonProps, } from './Table' export {createColumnHelper} from './column' -export type {Column} from './column' +export type {Column, CellAlignment, ColumnWidth} from './column' +export type {UniqueRow} from './row' +export type {ObjectPaths} from './utils' diff --git a/packages/react/src/DataTable/useTable.ts b/packages/react/src/DataTable/useTable.ts index c5a9140744c..28fd042b2a4 100644 --- a/packages/react/src/DataTable/useTable.ts +++ b/packages/react/src/DataTable/useTable.ts @@ -135,8 +135,8 @@ export function useTable({ header.column.sortBy === true ? strategies.basic : typeof header.column.sortBy === 'string' - ? strategies[header.column.sortBy] - : header.column.sortBy + ? strategies[header.column.sortBy] + : header.column.sortBy setRowOrder(rowOrder => { return rowOrder.slice().sort((a, b) => { diff --git a/packages/react/src/DataTable/utils.ts b/packages/react/src/DataTable/utils.ts index e28c1d362aa..779a4598468 100644 --- a/packages/react/src/DataTable/utils.ts +++ b/packages/react/src/DataTable/utils.ts @@ -12,9 +12,9 @@ type MaxLength = ArrayOfLength<10>[number] type ArrayIndex, Keys extends number = never> = A extends readonly [] ? Keys : // eslint-disable-next-line @typescript-eslint/no-unused-vars - A extends readonly [infer _, ...infer Tail] - ? ArrayIndex - : Keys + A extends readonly [infer _, ...infer Tail] + ? ArrayIndex + : Keys // Check if the given type is within the bounds set by `MaxLength` // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -30,25 +30,25 @@ type ArrayWithinBounds = T extends ReadonlyArray & {length: infer Length export type ObjectPaths = T extends readonly any[] & ArrayWithinBounds ? `${ArrayIndex}` | PrefixPath> : // eslint-disable-next-line @typescript-eslint/no-explicit-any - T extends any[] - ? never & 'Unable to determine keys of potentially boundless array' - : T extends Date - ? never - : T extends object - ? Extract | PrefixPath> - : never + T extends any[] + ? never & 'Unable to determine keys of potentially boundless array' + : T extends Date + ? never + : T extends object + ? Extract | PrefixPath> + : never -type PrefixPath = Prefix extends Extract - ? `${Prefix}.${ObjectPaths}` - : never +type PrefixPath = + Prefix extends Extract ? `${Prefix}.${ObjectPaths}` : never // Get the value of a given path within an object -export type ObjectPathValue = ObjectType extends Record< - string | number, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - any -> - ? Path extends `${infer Key}.${infer NestedPath}` - ? ObjectPathValue - : ObjectType[Path] - : never +export type ObjectPathValue = + ObjectType extends Record< + string | number, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + any + > + ? Path extends `${infer Key}.${infer NestedPath}` + ? ObjectPathValue + : ObjectType[Path] + : never diff --git a/packages/react/src/PageLayout/PageLayout.tsx b/packages/react/src/PageLayout/PageLayout.tsx index 994f3d007a6..dee02530fcc 100644 --- a/packages/react/src/PageLayout/PageLayout.tsx +++ b/packages/react/src/PageLayout/PageLayout.tsx @@ -788,8 +788,8 @@ const Pane = React.forwardRef )} diff --git a/packages/react/src/__tests__/__snapshots__/exports.test.ts.snap b/packages/react/src/__tests__/__snapshots__/exports.test.ts.snap index 376d5974445..546b1b187d1 100644 --- a/packages/react/src/__tests__/__snapshots__/exports.test.ts.snap +++ b/packages/react/src/__tests__/__snapshots__/exports.test.ts.snap @@ -263,8 +263,10 @@ exports[`@primer/react/experimental should not update exports without a semver c "type BlankslateProps", "ButtonBase", "type ButtonBaseProps", + "type CellAlignment", "type ChildrenPropTypes", "type Column", + "type ColumnWidth", "createColumnHelper", "DataTable", "type DataTableProps", @@ -299,6 +301,7 @@ exports[`@primer/react/experimental should not update exports without a semver c "type NavListProps", "type NavListSubNavProps", "type NavListTrailingVisualProps", + "type ObjectPaths", "PageHeader", "type PageHeaderProps", "type ParentLinkProps", @@ -333,6 +336,7 @@ exports[`@primer/react/experimental should not update exports without a semver c "type UnderlinePanelsPanelProps", "type UnderlinePanelsProps", "type UnderlinePanelsTabProps", + "type UniqueRow", "useFeatureFlag", "useOverflow", "useSlots", diff --git a/packages/react/src/experimental/index.ts b/packages/react/src/experimental/index.ts index 19ebadec41a..9346c8c39a6 100644 --- a/packages/react/src/experimental/index.ts +++ b/packages/react/src/experimental/index.ts @@ -31,6 +31,10 @@ export type { TableSubtitleProps, TableActionsProps, Column, + CellAlignment, + ColumnWidth, + UniqueRow, + ObjectPaths, } from '../DataTable' export * from '../Dialog/Dialog' diff --git a/packages/react/src/hooks/useSlots.ts b/packages/react/src/hooks/useSlots.ts index 29aaed481af..9fb3d824b29 100644 --- a/packages/react/src/hooks/useSlots.ts +++ b/packages/react/src/hooks/useSlots.ts @@ -20,12 +20,12 @@ type SlotElements = { type SlotValue = Config[Property] extends React.ElementType // config option 1 ? React.ReactElement, Config[Property]> : Config[Property] extends readonly [ - infer ElementType extends React.ElementType, // config option 2, infer array[0] as component - // eslint-disable-next-line @typescript-eslint/no-unused-vars - infer _testFn, // even though we don't use testFn, we need to infer it to support types for slots.*.props - ] - ? React.ReactElement, ElementType> - : never // useful for narrowing types, third option is not possible + infer ElementType extends React.ElementType, // config option 2, infer array[0] as component + // eslint-disable-next-line @typescript-eslint/no-unused-vars + infer _testFn, // even though we don't use testFn, we need to infer it to support types for slots.*.props + ] + ? React.ReactElement, ElementType> + : never // useful for narrowing types, third option is not possible /** * Extract components from `children` so we can render them in different places, diff --git a/packages/react/src/internal/components/TextInputInnerAction.tsx b/packages/react/src/internal/components/TextInputInnerAction.tsx index ec9b6100828..75fcb22349f 100644 --- a/packages/react/src/internal/components/TextInputInnerAction.tsx +++ b/packages/react/src/internal/components/TextInputInnerAction.tsx @@ -107,10 +107,10 @@ const TextInputAction = forwardRef( const accessibleLabel = ariaLabel ? {'aria-label': ariaLabel} : ariaLabelledBy - ? {'aria-labelledby': ariaLabelledBy} - : { - 'aria-label': '', - } + ? {'aria-labelledby': ariaLabelledBy} + : { + 'aria-label': '', + } return ( diff --git a/packages/react/src/sx.ts b/packages/react/src/sx.ts index de25c93e0c0..5b9a20fc011 100644 --- a/packages/react/src/sx.ts +++ b/packages/react/src/sx.ts @@ -8,10 +8,10 @@ export type BetterCssProperties = { [K in keyof SystemCssProperties]: K extends keyof ColorProps ? ThemeColorPaths | SystemCssProperties[K] : K extends keyof BorderColorProps - ? ThemeColorPaths | SystemCssProperties[K] - : K extends keyof ShadowProps - ? ThemeShadowPaths | SystemCssProperties[K] - : SystemCssProperties[K] + ? ThemeColorPaths | SystemCssProperties[K] + : K extends keyof ShadowProps + ? ThemeShadowPaths | SystemCssProperties[K] + : SystemCssProperties[K] } // Support CSS custom properties in the `sx` prop diff --git a/packages/react/src/utils/polymorphic.ts b/packages/react/src/utils/polymorphic.ts index 9e017eb33ae..1dd2314cd53 100644 --- a/packages/react/src/utils/polymorphic.ts +++ b/packages/react/src/utils/polymorphic.ts @@ -50,10 +50,10 @@ interface ForwardRefComponent< props: As extends '' ? {as: keyof JSX.IntrinsicElements} : As extends React.ComponentType - ? Merge - : As extends keyof JSX.IntrinsicElements - ? Merge - : never, + ? Merge + : As extends keyof JSX.IntrinsicElements + ? Merge + : never, ): React.ReactElement | null } diff --git a/packages/react/src/utils/types/ComponentProps.ts b/packages/react/src/utils/types/ComponentProps.ts index 83256126a04..4ddc3c7cf95 100644 --- a/packages/react/src/utils/types/ComponentProps.ts +++ b/packages/react/src/utils/types/ComponentProps.ts @@ -5,8 +5,5 @@ * * @example ComponentProps */ -export type ComponentProps = T extends React.ComponentType> - ? Props extends object - ? Props - : never - : never +export type ComponentProps = + T extends React.ComponentType> ? (Props extends object ? Props : never) : never