diff --git a/.changeset/tasty-swans-sniff.md b/.changeset/tasty-swans-sniff.md new file mode 100644 index 000000000..8d1867799 --- /dev/null +++ b/.changeset/tasty-swans-sniff.md @@ -0,0 +1,7 @@ +--- +'@keystatic/templates-nextjs': patch +'@keystatic/templates-astro': patch +'@keystatic/templates-remix': patch +--- + +Update template to React 19 diff --git a/.changeset/warm-suits-arrive.md b/.changeset/warm-suits-arrive.md new file mode 100644 index 000000000..0c0cc11ca --- /dev/null +++ b/.changeset/warm-suits-arrive.md @@ -0,0 +1,9 @@ +--- +'@keystatic/core': patch +'@keystar/ui': patch +'@keystatic/astro': patch +'@keystatic/remix': patch +'@keystatic/next': patch +--- + +Allow React 19 in peerDependencies diff --git a/.eslintrc.js b/.eslintrc.js index b216f1f05..aff920fe6 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -119,6 +119,14 @@ module.exports = { }, }, ], + 'no-restricted-syntax': [ + ERROR, + { + selector: "TSQualifiedName[left.name='React']", + message: + "Avoid using the global React type, import the specific type you want from 'react'", + }, + ], 'react/no-unknown-property': OFF, 'react-compiler/react-compiler': [ ERROR, diff --git a/.nvmrc b/.nvmrc index a77793ecc..d5b283a3a 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -lts/hydrogen +22.13.1 diff --git a/babel.config.json b/babel.config.json index fd8cc2372..1a6f64084 100644 --- a/babel.config.json +++ b/babel.config.json @@ -17,10 +17,7 @@ "@babel/preset-typescript", ["@babel/preset-react", { "runtime": "automatic" }] ], - "plugins": [ - "@babel/plugin-transform-runtime", - ["@babel/plugin-transform-private-property-in-object", { "loose": true }] - ], + "plugins": ["@babel/plugin-transform-runtime"], "overrides": [ { "test": ["packages/keystatic/src/**/*", "design-system/pkg/src/**/*"], diff --git a/design-system/docs/.nvmrc b/design-system/docs/.nvmrc new file mode 100644 index 000000000..d5b283a3a --- /dev/null +++ b/design-system/docs/.nvmrc @@ -0,0 +1 @@ +22.13.1 diff --git a/design-system/docs/app/(site)/[[...slug]]/page.tsx b/design-system/docs/app/(site)/[[...slug]]/page.tsx index 156f8e2c5..d2962b967 100644 --- a/design-system/docs/app/(site)/[[...slug]]/page.tsx +++ b/design-system/docs/app/(site)/[[...slug]]/page.tsx @@ -18,11 +18,10 @@ export async function generateStaticParams() { export const dynamicParams = false; -export async function generateMetadata({ - params, -}: { - params: { slug?: string[] }; +export async function generateMetadata(props: { + params: Promise<{ slug?: string[] }>; }): Promise { + const params = await props.params; const slug = (params.slug ?? ['index']).join('/'); let entry = await reader.collections.otherDocs.read(slug); if (!entry && slug !== 'index') { @@ -32,8 +31,10 @@ export async function generateMetadata({ return { title: entry.title }; } -export default async function Page(props: { params: { slug?: string[] } }) { - const slug = (props.params.slug ?? ['index']).join('/'); +export default async function Page(props: { + params: Promise<{ slug?: string[] }>; +}) { + const slug = ((await props.params).slug ?? ['index']).join('/'); let entry = await reader.collections.otherDocs.read(slug, { resolveLinkedFiles: true, }); diff --git a/design-system/docs/app/(site)/colours/colours-inner.tsx b/design-system/docs/app/(site)/colours/colours-inner.tsx index a027dac14..8047050cb 100644 --- a/design-system/docs/app/(site)/colours/colours-inner.tsx +++ b/design-system/docs/app/(site)/colours/colours-inner.tsx @@ -7,6 +7,8 @@ import { Heading, Text } from '@keystar/ui/typography'; import { DocsContent } from '../../../components/content'; +import type { JSX } from 'react'; + export function Colours(): JSX.Element { const colors = [ { diff --git a/design-system/docs/app/(site)/layout.tsx b/design-system/docs/app/(site)/layout.tsx index 941673958..03c127b85 100644 --- a/design-system/docs/app/(site)/layout.tsx +++ b/design-system/docs/app/(site)/layout.tsx @@ -5,6 +5,7 @@ import { Inter } from 'next/font/google'; import { Layout } from '../../components/layout'; import { getNavigation } from '../../utils/packages'; import { basePageTitle } from './utils'; +import { ReactNode } from 'react'; const inter = Inter({ subsets: ['latin'], @@ -23,7 +24,7 @@ export const metadata: Metadata = { export default async function RootLayout({ children, }: { - children: React.ReactNode; + children: ReactNode; }) { return ( diff --git a/design-system/docs/app/(site)/package/[...slug]/page.tsx b/design-system/docs/app/(site)/package/[...slug]/page.tsx index 44c76e0fa..8c2c6460a 100644 --- a/design-system/docs/app/(site)/package/[...slug]/page.tsx +++ b/design-system/docs/app/(site)/package/[...slug]/page.tsx @@ -17,11 +17,10 @@ export async function generateStaticParams() { export const dynamicParams = false; -export async function generateMetadata({ - params, -}: { - params: { slug: string[] }; +export async function generateMetadata(props: { + params: Promise<{ slug: string[] }>; }): Promise { + const params = await props.params; const slugWithDocsBitAdded = [ params.slug[0], 'docs', @@ -36,11 +35,13 @@ export async function generateMetadata({ return { title: entry.title }; } -export default async function Page(props: { params: { slug: string[] } }) { +export default async function Page(props: { + params: Promise<{ slug: string[] }>; +}) { const slugWithDocsBitAdded = [ - props.params.slug[0], + (await props.params).slug[0], 'docs', - ...props.params.slug.slice(1), + ...(await props.params).slug.slice(1), ]; const slug = slugWithDocsBitAdded.join('/'); let entry = await reader.collections.packageDocs.read(slug, { diff --git a/design-system/docs/components/content/index.tsx b/design-system/docs/components/content/index.tsx index de923fdbc..7ba118cb7 100644 --- a/design-system/docs/components/content/index.tsx +++ b/design-system/docs/components/content/index.tsx @@ -6,6 +6,7 @@ import { ReactNode, Fragment, useCallback, + type JSX, } from 'react'; import { Icon } from '@keystar/ui/icon'; diff --git a/design-system/docs/components/doc-page.tsx b/design-system/docs/components/doc-page.tsx index e932a114b..564595959 100644 --- a/design-system/docs/components/doc-page.tsx +++ b/design-system/docs/components/doc-page.tsx @@ -5,6 +5,8 @@ import { generateToc } from '../utils/generate-toc'; import { DocsContent } from './content'; import { DocContent } from './mdx-components/mdx-content'; +import type { JSX } from 'react'; + export type DocPageProps = { content: Tag; description: string | null; diff --git a/design-system/docs/components/layout.tsx b/design-system/docs/components/layout.tsx index 5821fbbbb..42bac4d72 100644 --- a/design-system/docs/components/layout.tsx +++ b/design-system/docs/components/layout.tsx @@ -1,5 +1,5 @@ 'use client'; -import { ReactNode } from 'react'; +import { ReactNode, type JSX } from 'react'; import { Flex } from '@keystar/ui/layout'; diff --git a/design-system/docs/components/mdx-components/code-block.tsx b/design-system/docs/components/mdx-components/code-block.tsx index 19973f23a..3d847f454 100644 --- a/design-system/docs/components/mdx-components/code-block.tsx +++ b/design-system/docs/components/mdx-components/code-block.tsx @@ -4,6 +4,8 @@ import { css, tokenSchema } from '@keystar/ui/style'; import { Highlight } from './highlight'; +import type { JSX } from 'react'; + type CodeBlockProps = { language?: string; content: string; diff --git a/design-system/docs/components/mdx-components/highlight.tsx b/design-system/docs/components/mdx-components/highlight.tsx index 168d37c63..b64ceb091 100644 --- a/design-system/docs/components/mdx-components/highlight.tsx +++ b/design-system/docs/components/mdx-components/highlight.tsx @@ -5,6 +5,8 @@ import { Box } from '@keystar/ui/layout'; import { usePrismTheme } from './prism-theme'; +import type { JSX } from 'react'; + interface HighlightProps { code: string; language: string; diff --git a/design-system/docs/components/mdx-components/mdx-content.tsx b/design-system/docs/components/mdx-components/mdx-content.tsx index dcce9948f..4da2a1487 100644 --- a/design-system/docs/components/mdx-components/mdx-content.tsx +++ b/design-system/docs/components/mdx-components/mdx-content.tsx @@ -3,7 +3,7 @@ import type { RenderableTreeNodes, Scalar, } from '@markdoc/markdoc'; -import React, { ElementType, ReactNode } from 'react'; +import React, { ElementType, ReactNode, type JSX } from 'react'; import { isTag } from '../../utils/utils'; import { mdxComponents } from './mdx-components'; diff --git a/design-system/docs/components/mdx-components/mdx-table.tsx b/design-system/docs/components/mdx-components/mdx-table.tsx index af30f7551..c54ae29ff 100644 --- a/design-system/docs/components/mdx-components/mdx-table.tsx +++ b/design-system/docs/components/mdx-components/mdx-table.tsx @@ -3,6 +3,8 @@ import { Box, BoxProps } from '@keystar/ui/layout'; import { css } from '@keystar/ui/style'; import { Text } from '@keystar/ui/typography'; +import type { JSX } from 'react'; + export function MdxTable({ children, ...rest }: BoxProps): JSX.Element { return ( diff --git a/design-system/docs/components/mdx-components/react-live/index.tsx b/design-system/docs/components/mdx-components/react-live/index.tsx index fd68caa2e..cd0a47c43 100644 --- a/design-system/docs/components/mdx-components/react-live/index.tsx +++ b/design-system/docs/components/mdx-components/react-live/index.tsx @@ -1,7 +1,7 @@ 'use client'; import copy from 'clipboard-copy'; import { createUrl } from 'playroom/utils'; -import { ReactNode, useEffect, useId, useState } from 'react'; +import { ReactNode, useEffect, useId, useState, type JSX } from 'react'; import { ActionButton } from '@keystar/ui/button'; import { chevronDownIcon } from '@keystar/ui/icon/icons/chevronDownIcon'; diff --git a/design-system/docs/package.json b/design-system/docs/package.json index 2c7332670..384551213 100644 --- a/design-system/docs/package.json +++ b/design-system/docs/package.json @@ -28,11 +28,11 @@ "clipboard-copy": "^4.0.1", "emery": "^1.4.1", "esbuild": "^0.14.53", - "next": "^14.1.3", + "next": "^15.1.6", "parse-numeric-range": "^1.3.0", "prism-react-renderer": "^1.3.3", - "react": "^18.2.0", - "react-dom": "^18.2.0", + "react": "^19.0.0", + "react-dom": "^19.0.0", "tsx": "^4.8.2", "vercel": "^33.6.3" }, @@ -51,8 +51,8 @@ "@storybook/nextjs": "^7.4.6", "@storybook/preview-api": "^7.4.6", "@storybook/react": "^7.4.6", - "@types/node": "16.11.13", - "@types/react": "^18.2.8", + "@types/node": "22.13.1", + "@types/react": "^19.0.8", "babel-loader": "^8.2.5", "playroom": "^0.28.0", "storybook": "^7.0.22", diff --git a/design-system/docs/playroom/components.ts b/design-system/docs/playroom/components.ts index 3b0885137..8188805a5 100644 --- a/design-system/docs/playroom/components.ts +++ b/design-system/docs/playroom/components.ts @@ -1,3 +1,5 @@ +import type { JSX } from 'react'; + export * from '../components/scope'; export function Render({ diff --git a/design-system/docs/playroom/frame.tsx b/design-system/docs/playroom/frame.tsx index 94a76c744..c4b26f3f1 100644 --- a/design-system/docs/playroom/frame.tsx +++ b/design-system/docs/playroom/frame.tsx @@ -1,4 +1,4 @@ -import { ReactNode } from 'react'; +import { ReactNode, type JSX } from 'react'; import { ClientSideOnlyDocumentElement, diff --git a/design-system/pkg/package.json b/design-system/pkg/package.json index 18ac080ac..196ba4c71 100644 --- a/design-system/pkg/package.json +++ b/design-system/pkg/package.json @@ -1476,7 +1476,7 @@ }, "dependencies": { "@babel/runtime": "^7.18.3", - "@emotion/css": "^11.9.0", + "@emotion/css": "^11.13.5", "@floating-ui/react": "^0.24.0", "@internationalized/date": "^3.5.5", "@internationalized/string": "^3.2.3", @@ -1560,7 +1560,7 @@ "@react-types/switch": "^3.5.5", "@react-types/table": "^3.10.1", "@react-types/tabs": "^3.3.9", - "@types/react": "^18.2.8", + "@types/react": "^19.0.8", "emery": "^1.4.1", "facepaint": "^1.2.1" }, @@ -1574,21 +1574,21 @@ "@svgr/plugin-jsx": "^6.5.1", "@svgr/plugin-prettier": "^6.5.1", "@svgr/plugin-svgo": "^6.5.1", - "@testing-library/dom": "^8.20.0", - "@testing-library/react": "^13.4.0", - "@testing-library/user-event": "^14.4.3", + "@testing-library/dom": "^10.4.0", + "@testing-library/react": "^16.2.0", + "@testing-library/user-event": "^14.6.1", "@types/facepaint": "^1.2.2", - "@types/react-dom": "^18.0.11", + "@types/react-dom": "^19.0.3", "lucide-static": "^0.314.0", - "next": "^14.1.3", - "react": "^18.2.0", - "react-dom": "^18.2.0", + "next": "^15.1.6", + "react": "^19.0.0", + "react-dom": "^19.0.0", "tsx": "^4.8.2" }, "peerDependencies": { "next": ">=14", - "react": "^18.2.0", - "react-dom": "^18.2.0" + "react": "^18.2.0 || ^19.0.0", + "react-dom": "^18.2.0 || ^19.0.0" }, "peerDependenciesMeta": { "next": { diff --git a/design-system/pkg/src/action-group/ActionGroup.tsx b/design-system/pkg/src/action-group/ActionGroup.tsx index 9c7588fb6..265f9a47a 100644 --- a/design-system/pkg/src/action-group/ActionGroup.tsx +++ b/design-system/pkg/src/action-group/ActionGroup.tsx @@ -14,7 +14,6 @@ import { ListState, useListState } from '@react-stately/list'; import { AriaLabelingProps, DOMProps, Node } from '@react-types/shared'; import { ForwardedRef, - Key, ReactElement, ReactNode, forwardRef, @@ -371,7 +370,7 @@ function ActionGroup( /** Group related action buttons together. */ const _ActionGroup: ( - props: ActionGroupProps & { ref?: RefObject } + props: ActionGroupProps & { ref?: RefObject } ) => ReactElement = forwardRef(ActionGroup) as any; export { _ActionGroup as ActionGroup }; @@ -382,7 +381,7 @@ interface ActionGroupItemProps extends DOMProps, BaseStyleProps { hideButtonText?: boolean; orientation?: 'horizontal' | 'vertical'; prominence?: 'low' | 'default'; - onAction?: (key: Key) => void; + onAction?: (key: string | number) => void; } function ActionGroupItem({ @@ -490,7 +489,7 @@ interface ActionGroupMenuProps extends AriaLabelingProps { isDisabled?: boolean; isOnlyItem?: boolean; items: Node[]; - onAction?: (key: Key) => void; + onAction?: (key: string | number) => void; orientation?: 'horizontal' | 'vertical'; prominence?: 'low' | 'default'; state: ListState; diff --git a/design-system/pkg/src/breadcrumbs/BreadcrumbItem.tsx b/design-system/pkg/src/breadcrumbs/BreadcrumbItem.tsx index ae3e4a7b2..124128c22 100644 --- a/design-system/pkg/src/breadcrumbs/BreadcrumbItem.tsx +++ b/design-system/pkg/src/breadcrumbs/BreadcrumbItem.tsx @@ -2,7 +2,7 @@ import { useBreadcrumbItem } from '@react-aria/breadcrumbs'; import { useLocale } from '@react-aria/i18n'; import { useHover } from '@react-aria/interactions'; import { mergeProps } from '@react-aria/utils'; -import React, { Fragment, useMemo, useRef } from 'react'; +import React, { Fragment, useMemo, useRef, ElementType } from 'react'; import { Icon } from '@keystar/ui/icon'; import { chevronRightIcon } from '@keystar/ui/icon/icons/chevronRightIcon'; @@ -35,7 +35,7 @@ export function BreadcrumbItem(props: BreadcrumbItemProps) { let { direction } = useLocale(); let ref = useRef(null); - let ElementType: React.ElementType = props.href ? 'a' : 'span'; + let ElementType: ElementType = props.href ? 'a' : 'span'; let { itemProps } = useBreadcrumbItem( { ...props, elementType: ElementType }, ref diff --git a/design-system/pkg/src/breadcrumbs/Breadcrumbs.tsx b/design-system/pkg/src/breadcrumbs/Breadcrumbs.tsx index 400adbf51..b8af64c02 100644 --- a/design-system/pkg/src/breadcrumbs/Breadcrumbs.tsx +++ b/design-system/pkg/src/breadcrumbs/Breadcrumbs.tsx @@ -28,6 +28,7 @@ import { classNames, css, tokenSchema, useStyleProps } from '@keystar/ui/style'; import { BreadcrumbItem, breadcrumbsClassList } from './BreadcrumbItem'; import { BreadcrumbsProps } from './types'; +import { ItemProps } from '@react-types/shared'; const MIN_VISIBLE_ITEMS = 1; const MAX_VISIBLE_ITEMS = 4; @@ -47,7 +48,7 @@ function Breadcrumbs( } = props; // Not using React.Children.toArray because it mutates the key prop. - let childArray: ReactElement[] = []; + let childArray: ReactElement>[] = []; Children.forEach(children, child => { if (isValidElement(child)) { childArray.push(child); diff --git a/design-system/pkg/src/button/ButtonGroup.tsx b/design-system/pkg/src/button/ButtonGroup.tsx index 45a9515ae..1e6a959fc 100644 --- a/design-system/pkg/src/button/ButtonGroup.tsx +++ b/design-system/pkg/src/button/ButtonGroup.tsx @@ -121,7 +121,7 @@ export const ButtonGroup: ForwardRefExoticComponent< // 2. External changes: buttongroup won't change size due to any parents // changing size, so listen to its container for size changes to figure out // if we should remeasure - let parent = useRef(); + let parent = useRef(null); useLayoutEffect(() => { if (domRef.current) { parent.current = domRef.current.parentElement as HTMLElement; diff --git a/design-system/pkg/src/calendar/CalendarBase.tsx b/design-system/pkg/src/calendar/CalendarBase.tsx index 6a189a2c5..f2e898a32 100644 --- a/design-system/pkg/src/calendar/CalendarBase.tsx +++ b/design-system/pkg/src/calendar/CalendarBase.tsx @@ -30,7 +30,7 @@ interface CalendarBaseProps calendarProps: HTMLAttributes; nextButtonProps: AriaButtonProps; prevButtonProps: AriaButtonProps; - calendarRef: RefObject; + calendarRef: RefObject; } export function CalendarBase( diff --git a/design-system/pkg/src/checkbox/Checkbox.tsx b/design-system/pkg/src/checkbox/Checkbox.tsx index ed0a44ffa..d77cb0c9a 100644 --- a/design-system/pkg/src/checkbox/Checkbox.tsx +++ b/design-system/pkg/src/checkbox/Checkbox.tsx @@ -3,6 +3,7 @@ import { useToggleState } from '@react-stately/toggle'; import { HTMLAttributes, InputHTMLAttributes, + RefObject, useContext, useMemo, useRef, @@ -70,7 +71,7 @@ function CheckboxAlone(props: CheckboxProps) { function CheckboxInner( props: CheckboxProps & { - inputRef: React.RefObject; + inputRef: RefObject; inputProps: InputHTMLAttributes; } ) { diff --git a/design-system/pkg/src/combobox/Combobox.tsx b/design-system/pkg/src/combobox/Combobox.tsx index 0d8dadca5..1459c8a98 100644 --- a/design-system/pkg/src/combobox/Combobox.tsx +++ b/design-system/pkg/src/combobox/Combobox.tsx @@ -10,6 +10,7 @@ import { useComboBoxState } from '@react-stately/combobox'; import { AriaButtonProps } from '@react-types/button'; import { LoadingState } from '@react-types/shared'; import React, { + CSSProperties, ForwardedRef, InputHTMLAttributes, ReactElement, @@ -131,7 +132,6 @@ const ComboboxBase = React.forwardRef(function ComboboxBase( labelProps={labelProps} ref={fieldRef} > - {/* @ts-expect-error FIXME: not sure how to resolve this type error */} ; - inputRef: RefObject; - fieldRef: RefObject; + buttonRef: RefObject; + inputRef: RefObject; + fieldRef: RefObject; }) { const { buttonRef, inputRef, fieldRef, menuWidth: menuWidthProp } = props; @@ -231,18 +231,18 @@ export function useStatefulRef() { }, [current, statefulRef]); } -interface ComboboxInputProps extends ComboboxProps { +interface ComboboxInputProps extends ComboboxProps { inputProps: InputHTMLAttributes; - inputRef: RefObject; + inputRef: RefObject; triggerProps: AriaButtonProps; - triggerRef: RefObject; - style?: React.CSSProperties; + triggerRef: RefObject; + style?: CSSProperties; isOpen?: boolean; } /** @private Used by multi variant. */ -export const ComboboxInput = React.forwardRef(function ComboboxInput( - props: ComboboxInputProps, +export const ComboboxInput = React.forwardRef(function ComboboxInput( + props: ComboboxInputProps, forwardedRef: ForwardedRef ) { let { @@ -258,7 +258,7 @@ export const ComboboxInput = React.forwardRef(function ComboboxInput( menuTrigger, } = props; let stringFormatter = useLocalizedStringFormatter(localizedMessages); - let timeoutRef = useRef(); + let timeoutRef = useRef(undefined); let [showLoading, setShowLoading] = useState(false); let loadingCircle = ( @@ -298,7 +298,6 @@ export const ComboboxInput = React.forwardRef(function ComboboxInput( } else if (!isLoading) { // If loading is no longer happening, clear any timers and hide the loading circle setShowLoading(false); - // @ts-expect-error FIXME: not sure how to resolve this type error clearTimeout(timeoutRef.current); timeoutRef.current = undefined; } @@ -363,7 +362,9 @@ export const ComboboxInput = React.forwardRef(function ComboboxInput( ); -}); +}) as ( + props: ComboboxInputProps & { ref?: ForwardedRef } +) => ReactElement; /** * A combobox combines a text input with a listbox, and allows users to filter a diff --git a/design-system/pkg/src/combobox/MobileCombobox.tsx b/design-system/pkg/src/combobox/MobileCombobox.tsx index 10b736cf2..0f18a9efa 100644 --- a/design-system/pkg/src/combobox/MobileCombobox.tsx +++ b/design-system/pkg/src/combobox/MobileCombobox.tsx @@ -11,6 +11,7 @@ import { ComboBoxState, useComboBoxState } from '@react-stately/combobox'; import { AriaButtonProps } from '@react-types/button'; import { ValidationState } from '@react-types/shared'; import React, { + CSSProperties, ForwardedRef, HTMLAttributes, KeyboardEvent, @@ -136,7 +137,7 @@ interface ComboboxButtonProps extends AriaButtonProps { isReadOnly?: boolean; isDisabled?: boolean; isPlaceholder?: boolean; - style?: React.CSSProperties; + style?: CSSProperties; validationState?: ValidationState; } @@ -294,7 +295,7 @@ function ComboboxTray(props: ComboboxTrayProps) { onClose, } = props; - let timeoutRef = useRef(); + let timeoutRef = useRef(undefined); let [showLoading, setShowLoading] = useState(false); let inputRef = useRef(null); let buttonRef = useRef(null); @@ -423,7 +424,6 @@ function ComboboxTray(props: ComboboxTrayProps) { } else if (loadingState !== 'filtering') { // If loading is no longer happening, clear any timers and hide the loading circle setShowLoading(false); - // @ts-expect-error FIXME: NodeJS.Timeout is not assignable to number clearTimeout(timeoutRef.current); timeoutRef.current = undefined; } diff --git a/design-system/pkg/src/combobox/MobileComboboxMulti.tsx b/design-system/pkg/src/combobox/MobileComboboxMulti.tsx index 9bc374e3e..4df5f3e60 100644 --- a/design-system/pkg/src/combobox/MobileComboboxMulti.tsx +++ b/design-system/pkg/src/combobox/MobileComboboxMulti.tsx @@ -9,6 +9,7 @@ import { mergeProps, useId, useObjectRef } from '@react-aria/utils'; import { AriaButtonProps } from '@react-types/button'; import { ValidationState } from '@react-types/shared'; import React, { + CSSProperties, ForwardedRef, HTMLAttributes, KeyboardEvent, @@ -133,7 +134,7 @@ interface ComboboxButtonProps extends AriaButtonProps { isReadOnly?: boolean; isDisabled?: boolean; isPlaceholder?: boolean; - style?: React.CSSProperties; + style?: CSSProperties; validationState?: ValidationState; } @@ -291,7 +292,7 @@ function ComboboxTray(props: ComboboxTrayProps) { onClose, } = props; - let timeoutRef = useRef(); + let timeoutRef = useRef(undefined); let [showLoading, setShowLoading] = useState(false); let inputRef = useRef(null); let buttonRef = useRef(null); @@ -422,7 +423,6 @@ function ComboboxTray(props: ComboboxTrayProps) { } else if (loadingState !== 'filtering') { // If loading is no longer happening, clear any timers and hide the loading circle setShowLoading(false); - // @ts-expect-error FIXME: NodeJS.Timeout is not assignable to number clearTimeout(timeoutRef.current); timeoutRef.current = undefined; } diff --git a/design-system/pkg/src/date-time/DatePickerPopover.tsx b/design-system/pkg/src/date-time/DatePickerPopover.tsx index 88fd48357..c662376f4 100644 --- a/design-system/pkg/src/date-time/DatePickerPopover.tsx +++ b/design-system/pkg/src/date-time/DatePickerPopover.tsx @@ -4,7 +4,7 @@ import { DatePickerState, DateRangePickerState, } from '@react-stately/datepicker'; -import { ReactNode, useRef } from 'react'; +import { ReactNode, RefObject, useRef } from 'react'; import { Popover, Tray } from '@keystar/ui/overlays'; import { css, tokenSchema, useIsMobileDevice } from '@keystar/ui/style'; @@ -17,7 +17,7 @@ export function DatePickerPopover({ dialogProps: AriaDialogProps; shouldFlip?: boolean; state: DatePickerState | DateRangePickerState; - triggerRef: React.RefObject; + triggerRef: RefObject; }) { let scrollRef = useRef(null); let { direction } = useLocale(); diff --git a/design-system/pkg/src/date-time/stories/DateField.stories.tsx b/design-system/pkg/src/date-time/stories/DateField.stories.tsx index 610921082..77ae22079 100644 --- a/design-system/pkg/src/date-time/stories/DateField.stories.tsx +++ b/design-system/pkg/src/date-time/stories/DateField.stories.tsx @@ -17,6 +17,7 @@ import { ArgTypes, action } from '@keystar/ui-storybook'; import React from 'react'; import { DateField, DateFieldProps } from '..'; +import { Key } from '@react-types/shared'; export default { title: 'Components/Date and Time/DateField', @@ -268,8 +269,8 @@ const calendars = [ ]; function Example(props: DateFieldProps) { - let [locale, setLocale] = React.useState(''); - let [calendar, setCalendar] = React.useState(calendars[0].key); + let [locale, setLocale] = React.useState(''); + let [calendar, setCalendar] = React.useState(calendars[0].key); let { locale: defaultLocale } = useLocale(); let pref = preferences.find(p => p.locale === locale); @@ -289,7 +290,7 @@ function Example(props: DateFieldProps) { [preferredCalendars] ); - let updateLocale = (locale: React.Key) => { + let updateLocale = (locale: Key) => { setLocale(locale); let pref = preferences.find(p => p.locale === locale); setCalendar(pref!.ordering.split(' ')[0]); diff --git a/design-system/pkg/src/dialog/DialogTrigger.tsx b/design-system/pkg/src/dialog/DialogTrigger.tsx index 5199e4d79..ec5228f6e 100644 --- a/design-system/pkg/src/dialog/DialogTrigger.tsx +++ b/design-system/pkg/src/dialog/DialogTrigger.tsx @@ -6,7 +6,14 @@ import { useOverlayTriggerState, } from '@react-stately/overlays'; import { assertNever } from 'emery'; -import { Children, Fragment, ReactElement, useEffect, useRef } from 'react'; +import { + Children, + Fragment, + ReactElement, + useEffect, + useRef, + type JSX, +} from 'react'; import { Modal, Popover, PopoverProps, Tray } from '@keystar/ui/overlays'; import { breakpointQueries, useMediaQuery } from '@keystar/ui/style'; diff --git a/design-system/pkg/src/dialog/types.ts b/design-system/pkg/src/dialog/types.ts index 937479515..2f86665d5 100644 --- a/design-system/pkg/src/dialog/types.ts +++ b/design-system/pkg/src/dialog/types.ts @@ -44,7 +44,7 @@ export type DialogTriggerProps = { * The ref of the element the dialog should visually attach itself to. * Defaults to the trigger button if not defined. */ - targetRef?: RefObject; + targetRef?: RefObject; /** Whether a "modal" type dialog should be dismissable. */ isDismissable?: boolean; /** Whether pressing the escape key to close the dialog should be disabled. */ diff --git a/design-system/pkg/src/drag-and-drop/types.ts b/design-system/pkg/src/drag-and-drop/types.ts index 0efddb4cf..83413ad20 100644 --- a/design-system/pkg/src/drag-and-drop/types.ts +++ b/design-system/pkg/src/drag-and-drop/types.ts @@ -20,8 +20,9 @@ import { DraggableCollectionProps, DragItem, DroppableCollectionProps, + Key, } from '@react-types/shared'; -import { Key, RefObject } from 'react'; +import { RefObject, type JSX } from 'react'; interface DraggableCollectionStateOpts extends Omit {} diff --git a/design-system/pkg/src/drag-and-drop/useDragAndDrop.ts b/design-system/pkg/src/drag-and-drop/useDragAndDrop.ts index 25fef9d75..b9e6a5fea 100644 --- a/design-system/pkg/src/drag-and-drop/useDragAndDrop.ts +++ b/design-system/pkg/src/drag-and-drop/useDragAndDrop.ts @@ -17,7 +17,7 @@ import { useDroppableCollectionState, } from '@react-stately/dnd'; import type { Key } from '@react-types/shared'; -import { RefObject, useMemo } from 'react'; +import { RefObject, useMemo, type JSX } from 'react'; import { DragAndDropHooks, diff --git a/design-system/pkg/src/editor/EditorListbox.tsx b/design-system/pkg/src/editor/EditorListbox.tsx index dcf8a14d4..48f1982f9 100644 --- a/design-system/pkg/src/editor/EditorListbox.tsx +++ b/design-system/pkg/src/editor/EditorListbox.tsx @@ -15,8 +15,8 @@ import { ListBoxBase, listStyles, useListBoxLayout } from '@keystar/ui/listbox'; import { BaseStyleProps } from '@keystar/ui/style'; export type EditorListboxProps = { - listenerRef: RefObject; - scrollRef?: RefObject; + listenerRef: RefObject; + scrollRef?: RefObject; onAction?: (key: Key) => void; onEscape?: () => void; } & CollectionBase & diff --git a/design-system/pkg/src/editor/EditorToolbar.tsx b/design-system/pkg/src/editor/EditorToolbar.tsx index 33600a479..d462a7cb8 100644 --- a/design-system/pkg/src/editor/EditorToolbar.tsx +++ b/design-system/pkg/src/editor/EditorToolbar.tsx @@ -330,7 +330,10 @@ function useToolbarItem

(props: P) { }; } -function useToolbar(props: EditorToolbarProps, ref: RefObject) { +function useToolbar( + props: EditorToolbarProps, + ref: RefObject +) { let [lastFocusedId, setLastFocusedId] = useState(null); let { direction } = useLocale(); let focusManager = createFocusManager(ref, { wrap: true }); diff --git a/design-system/pkg/src/list-view/ListView.tsx b/design-system/pkg/src/list-view/ListView.tsx index 8aa0f3040..dcfaf87c4 100644 --- a/design-system/pkg/src/list-view/ListView.tsx +++ b/design-system/pkg/src/list-view/ListView.tsx @@ -77,7 +77,7 @@ function useListLayout( function ListView( props: ListViewProps, - ref: RefObject + ref: RefObject ) { let { density = 'regular', @@ -409,6 +409,6 @@ function CenteredWrapper({ children }: PropsWithChildren) { * or perform an action. */ const _ListView = React.forwardRef(ListView as any) as ( - props: ListViewProps & { ref?: RefObject } + props: ListViewProps & { ref?: RefObject } ) => ReactElement; export { _ListView as ListView }; diff --git a/design-system/pkg/src/list-view/ListViewItem.tsx b/design-system/pkg/src/list-view/ListViewItem.tsx index 5546c4878..cb448d161 100644 --- a/design-system/pkg/src/list-view/ListViewItem.tsx +++ b/design-system/pkg/src/list-view/ListViewItem.tsx @@ -16,7 +16,7 @@ import { mergeProps } from '@react-aria/utils'; import { useVisuallyHidden } from '@react-aria/visually-hidden'; import { DropTarget, Node } from '@react-types/shared'; import { assert } from 'emery'; -import React, { useRef } from 'react'; +import React, { HTMLAttributes, useRef } from 'react'; import { Checkbox } from '@keystar/ui/checkbox'; import { KeystarProvider } from '@keystar/ui/core'; @@ -355,7 +355,7 @@ export function ListViewItem(props: ListViewItemProps) { {!isDisabled && (

)} + {...(buttonProps as HTMLAttributes)} className={classNames( listViewItemClassList.element('draghandle'), css({ diff --git a/design-system/pkg/src/list-view/stories/ListView.stories.tsx b/design-system/pkg/src/list-view/stories/ListView.stories.tsx index ab174a328..88fc18a3e 100644 --- a/design-system/pkg/src/list-view/stories/ListView.stories.tsx +++ b/design-system/pkg/src/list-view/stories/ListView.stories.tsx @@ -1,6 +1,6 @@ import { action } from '@keystar/ui-storybook'; import { useAsyncList, useListData } from '@react-stately/data'; -import { ItemDropTarget } from '@react-types/shared'; +import { ItemDropTarget, Key } from '@react-types/shared'; import React from 'react'; import { ActionGroup } from '@keystar/ui/action-group'; @@ -424,7 +424,7 @@ function ReorderExample(props: any) { [] ); - let onMove = (keys: React.Key[], target: ItemDropTarget) => { + let onMove = (keys: Key[], target: ItemDropTarget) => { if (target.dropPosition === 'before') { list.moveBefore(target.key, keys); } else { diff --git a/design-system/pkg/src/list-view/types.ts b/design-system/pkg/src/list-view/types.ts index 6b0d57c70..bd19d3326 100644 --- a/design-system/pkg/src/list-view/types.ts +++ b/design-system/pkg/src/list-view/types.ts @@ -4,7 +4,7 @@ import { LoadingState, SpectrumSelectionProps, } from '@react-types/shared'; -import { Key } from 'react'; +import { Key, type JSX } from 'react'; import { DragAndDropHooks } from '@keystar/ui/drag-and-drop'; import { BaseStyleProps } from '@keystar/ui/style'; diff --git a/design-system/pkg/src/listbox/ListBox.tsx b/design-system/pkg/src/listbox/ListBox.tsx index 04f15e56b..5c7283bb3 100644 --- a/design-system/pkg/src/listbox/ListBox.tsx +++ b/design-system/pkg/src/listbox/ListBox.tsx @@ -8,7 +8,7 @@ import { ListBoxProps } from './types'; function ListBox( props: ListBoxProps, - forwardedRef: RefObject + forwardedRef: RefObject ) { let domRef = useObjectRef(forwardedRef); let state = useListState(props); @@ -24,6 +24,6 @@ function ListBox( * A list of options that can allow selection of one or more. */ const _ListBox: ( - props: ListBoxProps & { ref?: RefObject } + props: ListBoxProps & { ref?: RefObject } ) => ReactElement = forwardRef(ListBox as any) as any; export { _ListBox as ListBox }; diff --git a/design-system/pkg/src/listbox/ListBoxBase.tsx b/design-system/pkg/src/listbox/ListBoxBase.tsx index 69218ebbf..7c5b9c26e 100644 --- a/design-system/pkg/src/listbox/ListBoxBase.tsx +++ b/design-system/pkg/src/listbox/ListBoxBase.tsx @@ -38,7 +38,7 @@ export function useListBoxLayout(): ListBoxLayout { /** @private */ function ListBoxBase( props: ListBoxBaseProps, - forwardedRef: RefObject + forwardedRef: RefObject ) { let { layout, @@ -183,9 +183,11 @@ function ListBoxBase( ); } +
; + // forwardRef doesn't support generic parameters, so cast the result to the correct type // https://stackoverflow.com/questions/58469229/react-with-typescript-generics-while-using-react-forwardref const _ListBoxBase: ( - props: ListBoxBaseProps & { ref?: RefObject } + props: ListBoxBaseProps & { ref?: RefObject } ) => ReactElement = forwardRef(ListBoxBase as any) as any; export { _ListBoxBase as ListBoxBase }; diff --git a/design-system/pkg/src/menu/Menu.tsx b/design-system/pkg/src/menu/Menu.tsx index fd5372adb..ddb5221dc 100644 --- a/design-system/pkg/src/menu/Menu.tsx +++ b/design-system/pkg/src/menu/Menu.tsx @@ -13,7 +13,7 @@ import { MenuProps } from './types'; function Menu( props: MenuProps, - forwardedRef: RefObject + forwardedRef: RefObject ) { let contextProps = useContext(MenuContext); let completeProps = { @@ -57,6 +57,6 @@ function Menu( // forwardRef doesn't support generic parameters, so cast the result to the correct type // https://stackoverflow.com/questions/58469229/react-with-typescript-generics-while-using-react-forwardref const _Menu: ( - props: MenuProps & { ref?: RefObject } + props: MenuProps & { ref?: RefObject } ) => ReactElement = React.forwardRef(Menu as any) as any; export { _Menu as Menu }; diff --git a/design-system/pkg/src/nav-list/NavList.tsx b/design-system/pkg/src/nav-list/NavList.tsx index bdefa1baf..e986396a9 100644 --- a/design-system/pkg/src/nav-list/NavList.tsx +++ b/design-system/pkg/src/nav-list/NavList.tsx @@ -99,7 +99,7 @@ function useDividerStyles() { // Utils // ----------------------------------------------------------------------------- -function useCurrentItem(ref: RefObject) { +function useCurrentItem(ref: RefObject) { let [currentItem, setCurrentItem] = useState(null); useLayoutEffect(() => { diff --git a/design-system/pkg/src/nav-tree/NavTree.tsx b/design-system/pkg/src/nav-tree/NavTree.tsx index 7e32f2677..81eab93bb 100644 --- a/design-system/pkg/src/nav-tree/NavTree.tsx +++ b/design-system/pkg/src/nav-tree/NavTree.tsx @@ -11,11 +11,11 @@ import { Collection, DOMAttributes, FocusableElement, + Key, Node, PressEvent, } from '@react-types/shared'; import React, { - Key, KeyboardEvent as ReactKeyboardEvent, RefObject, createContext, @@ -353,7 +353,7 @@ type TreeItemOptions = { export function useTreeItem( props: TreeItemOptions, state: TreeState, - ref: RefObject + ref: RefObject ) { let { node, isVirtualized } = props; let { selectionManager } = state; diff --git a/design-system/pkg/src/nav-tree/TreeKeyboardDelegate.tsx b/design-system/pkg/src/nav-tree/TreeKeyboardDelegate.tsx index 0d39f9619..672fc036e 100644 --- a/design-system/pkg/src/nav-tree/TreeKeyboardDelegate.tsx +++ b/design-system/pkg/src/nav-tree/TreeKeyboardDelegate.tsx @@ -1,5 +1,4 @@ -import { Collection, KeyboardDelegate, Node } from '@react-types/shared'; -import { Key } from 'react'; +import { Collection, Key, KeyboardDelegate, Node } from '@react-types/shared'; export class TreeKeyboardDelegate implements KeyboardDelegate { collator: Intl.Collator; diff --git a/design-system/pkg/src/nav-tree/stories/NavTree.stories.tsx b/design-system/pkg/src/nav-tree/stories/NavTree.stories.tsx index c77f7ea6e..90c5b1724 100644 --- a/design-system/pkg/src/nav-tree/stories/NavTree.stories.tsx +++ b/design-system/pkg/src/nav-tree/stories/NavTree.stories.tsx @@ -1,5 +1,5 @@ import { action } from '@keystar/ui-storybook'; -import { Key, useRef, useState } from 'react'; +import { useRef, useState } from 'react'; import { ActionButton } from '@keystar/ui/button'; import { Icon } from '@keystar/ui/icon'; @@ -8,6 +8,7 @@ import { Box } from '@keystar/ui/layout'; import { Text } from '@keystar/ui/typography'; import { NavTree, Item, Section } from '../index'; +import { Key } from '@react-types/shared'; let flatItems = [ { id: 1, name: 'Echidna' }, diff --git a/design-system/pkg/src/nav-tree/types.ts b/design-system/pkg/src/nav-tree/types.ts index b68011168..d8449d4ee 100644 --- a/design-system/pkg/src/nav-tree/types.ts +++ b/design-system/pkg/src/nav-tree/types.ts @@ -3,8 +3,9 @@ import { CollectionBase, DOMProps, Expandable, + Key, } from '@react-types/shared'; -import { Key, RefObject } from 'react'; +import { RefObject } from 'react'; import { BaseStyleProps } from '@keystar/ui/style'; @@ -32,7 +33,7 @@ export type NavTreeProps = CollectionBase & { * The ref attached to the scrollable body. Used to provided automatic * scrolling on item focus for non-virtualized trees. */ - scrollRef?: RefObject; + scrollRef?: RefObject; } & Expandable & ControlledSelection & DOMProps & diff --git a/design-system/pkg/src/number-field/test/NumberField.test.tsx b/design-system/pkg/src/number-field/test/NumberField.test.tsx index d3faac4eb..b6e9127e9 100644 --- a/design-system/pkg/src/number-field/test/NumberField.test.tsx +++ b/design-system/pkg/src/number-field/test/NumberField.test.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { RefObject } from 'react'; import { expect, it, describe, afterEach, jest } from '@jest/globals'; import { firePress, renderWithProvider } from '#test-utils'; import userEvent from '@testing-library/user-event'; @@ -9,7 +9,7 @@ let testId = 'test-id'; function renderNumberField( props: Partial = {}, - ref?: React.RefObject + ref?: RefObject ) { let user = userEvent.setup(); let result = renderWithProvider( diff --git a/design-system/pkg/src/overlays/Overlay.tsx b/design-system/pkg/src/overlays/Overlay.tsx index 04d519418..542ada4e1 100644 --- a/design-system/pkg/src/overlays/Overlay.tsx +++ b/design-system/pkg/src/overlays/Overlay.tsx @@ -1,4 +1,4 @@ -import { ForwardedRef, forwardRef } from 'react'; +import { ForwardedRef, forwardRef, ReactElement } from 'react'; import { Overlay as ReactAriaOverlay } from '@react-aria/overlays'; import { OverlayProps } from '@react-types/overlays'; @@ -29,9 +29,12 @@ export const Overlay = forwardRef(function Overlay( // unset container isDisabled={false} > - {cloneValidElement(props.children, { - isOpen: isOpen === 'mounting' ? false : props.isOpen, - }) ?? props.children} + {cloneValidElement( + props.children as ReactElement<{ isOpen?: boolean }>, + { + isOpen: isOpen === 'mounting' ? false : props.isOpen, + } + ) ?? props.children} ); diff --git a/design-system/pkg/src/overlays/Transition.tsx b/design-system/pkg/src/overlays/Transition.tsx index 1efc67181..ec1e3224d 100644 --- a/design-system/pkg/src/overlays/Transition.tsx +++ b/design-system/pkg/src/overlays/Transition.tsx @@ -1,4 +1,4 @@ -import { useLayoutEffect, useRef, useState } from 'react'; +import { ReactElement, useLayoutEffect, useRef, useState } from 'react'; import { cloneValidElement } from '../utils'; @@ -19,7 +19,7 @@ export const Transition = function Transition(props: TransitionProps) { } return ( - cloneValidElement(props.children, { + cloneValidElement(props.children as ReactElement<{ isOpen?: boolean }>, { isOpen: isOpen === 'mounting' ? false : props.isOpen, }) ?? props.children ); diff --git a/design-system/pkg/src/password-field/test/PasswordField.test.tsx b/design-system/pkg/src/password-field/test/PasswordField.test.tsx index 4d161319b..7d6d3129f 100644 --- a/design-system/pkg/src/password-field/test/PasswordField.test.tsx +++ b/design-system/pkg/src/password-field/test/PasswordField.test.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { RefObject } from 'react'; import { jest, it, describe, expect, afterEach } from '@jest/globals'; import { renderWithProvider } from '#test-utils'; import userEvent from '@testing-library/user-event'; @@ -10,7 +10,7 @@ let inputText = 'Hello world'; function renderPasswordField( props: Partial = {}, - ref?: React.RefObject + ref?: RefObject ) { return renderWithProvider( diff --git a/design-system/pkg/src/password-field/usePasswordField.ts b/design-system/pkg/src/password-field/usePasswordField.ts index 565a2472f..2613331c0 100644 --- a/design-system/pkg/src/password-field/usePasswordField.ts +++ b/design-system/pkg/src/password-field/usePasswordField.ts @@ -20,7 +20,7 @@ import { export function usePasswordField( props: PasswordFieldProps, state: PasswordFieldState, - inputRef: RefObject + inputRef: RefObject ): PasswordFieldAria { let { autoComplete = 'current-password', isDisabled } = props; diff --git a/design-system/pkg/src/picker/Picker.tsx b/design-system/pkg/src/picker/Picker.tsx index 6a78f8c44..eb5bf4782 100644 --- a/design-system/pkg/src/picker/Picker.tsx +++ b/design-system/pkg/src/picker/Picker.tsx @@ -35,7 +35,7 @@ import { PickerProps } from './types'; function Picker( props: PickerProps, - forwardedRef: RefObject + forwardedRef: RefObject ) { props = useSlotProps(props, 'picker'); props = useProviderProps(props); @@ -241,6 +241,6 @@ function Picker( * Pickers allow users to choose a single option from a collapsible list of options when space is limited. */ const _Picker: ( - props: PickerProps & { ref?: RefObject } + props: PickerProps & { ref?: RefObject } ) => ReactElement = forwardRef(Picker as any) as any; export { _Picker as Picker }; diff --git a/design-system/pkg/src/radio/test/RadioGroup.test.tsx b/design-system/pkg/src/radio/test/RadioGroup.test.tsx index 6337ed531..bb937c040 100644 --- a/design-system/pkg/src/radio/test/RadioGroup.test.tsx +++ b/design-system/pkg/src/radio/test/RadioGroup.test.tsx @@ -95,7 +95,7 @@ describe('radio/RadioGroup', () => { ); let radioGroup = getByRole('radiogroup'); - let radios = getAllByRole('radio', { exact: true }) as HTMLInputElement[]; + let radios = getAllByRole('radio') as HTMLInputElement[]; expect(radioGroup).toBeTruthy(); expect(radios.length).toBe(3); expect(radios[0]).not.toHaveAttribute('disabled'); diff --git a/design-system/pkg/src/search-field/test/SearchField.test.tsx b/design-system/pkg/src/search-field/test/SearchField.test.tsx index 98a4b8719..d8ca96c4e 100644 --- a/design-system/pkg/src/search-field/test/SearchField.test.tsx +++ b/design-system/pkg/src/search-field/test/SearchField.test.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { RefObject } from 'react'; import { render } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { expect, describe, it, jest, afterEach } from '@jest/globals'; @@ -10,7 +10,7 @@ let inputText = 'Hello world'; function renderSearchField( props: Partial = {}, - ref?: React.RefObject + ref?: RefObject ) { return render( ) { let resolved = cx(inputs); if (resolved.includes(resetClassName)) { diff --git a/design-system/pkg/src/style/responsive.ts b/design-system/pkg/src/style/responsive.ts index 0ddafcab8..056ed64f9 100644 --- a/design-system/pkg/src/style/responsive.ts +++ b/design-system/pkg/src/style/responsive.ts @@ -8,7 +8,7 @@ import { ResponsiveProp, StyleResolver, } from './types'; -import { CSSObject } from '@emotion/css'; +import { CSSObject } from '@emotion/css/create-instance'; // Breakpoints // ---------------------------------------------------------------------------- diff --git a/design-system/pkg/src/style/types.ts b/design-system/pkg/src/style/types.ts index c1f3c64b0..4cde1c548 100644 --- a/design-system/pkg/src/style/types.ts +++ b/design-system/pkg/src/style/types.ts @@ -1,8 +1,8 @@ -import { ClassNamesArg } from '@emotion/css'; import { MaybeArray } from '@keystar/ui/types'; import { CSSProperties } from 'react'; import { tokenSchema } from './tokens'; +import { cx } from '@emotion/css'; export type CSSProp = keyof CSSProperties; export type Primitive = number | string | boolean | null | undefined; @@ -102,7 +102,7 @@ export type RootStyleProps = { /** Responsively hide the element, visually **and** from assistive tech. */ isHidden?: BreakpointRange; /** Sets the CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. Only use as a **last resort**, prefer style props instead. */ - UNSAFE_className?: ClassNamesArg; + UNSAFE_className?: Parameters[0]; /** Sets inline [style](https://developer.mozilla.org/en-US/docs/Web/API/Element/style) for the element. Only use as a **last resort**, prefer style props instead. */ UNSAFE_style?: CSSProperties; }; diff --git a/design-system/pkg/src/style/useStyleProps.ts b/design-system/pkg/src/style/useStyleProps.ts index e7fc983d4..3b3c7939a 100644 --- a/design-system/pkg/src/style/useStyleProps.ts +++ b/design-system/pkg/src/style/useStyleProps.ts @@ -1,6 +1,7 @@ import { HTMLAttributes } from 'react'; import { warning } from 'emery'; -import { css, CSSInterpolation, CSSObject } from '@emotion/css'; +import { css } from '@emotion/css'; +import { CSSObject, CSSInterpolation } from '@emotion/css/create-instance'; import { defaultStyleProps } from './resolvers'; import { @@ -73,7 +74,7 @@ export function useStyleProps( 'Note that this may break in future versions due to DOM structure changes.' ); - let hiddenStyles: CSSInterpolation = []; + let hiddenStyles: CSSInterpolation[] = []; if (isHidden) { if (isHidden === true) { hiddenStyles.push({ display: 'none' }); diff --git a/design-system/pkg/src/table/TableView.tsx b/design-system/pkg/src/table/TableView.tsx index 1db9fba49..c39892bd9 100644 --- a/design-system/pkg/src/table/TableView.tsx +++ b/design-system/pkg/src/table/TableView.tsx @@ -3,7 +3,6 @@ import { type CSSProperties, // type ForwardedRef, type HTMLAttributes, - type Key, type PropsWithChildren, type ReactElement, type ReactNode, @@ -121,6 +120,7 @@ import { } from './styles'; import { TableViewLayout } from './TableViewLayout'; import { ColumnProps, TableCosmeticConfig, TableProps } from './types'; +import { Key } from '@react-types/shared'; // Constants @@ -590,9 +590,9 @@ interface TableVirtualizerProps extends HTMLAttributes { children: View[], renderChildren: (views: View[]) => ReactElement[] ) => ReactElement; - domRef: RefObject; - bodyRef: RefObject; - headerRef: RefObject; + domRef: RefObject; + bodyRef: RefObject; + headerRef: RefObject; onVisibleRectChange: (rect: Rect) => void; isFocusVisible: boolean; isVirtualDragging: boolean; @@ -1407,7 +1407,10 @@ function CellContents(props: HTMLAttributes) { const element = Children.only(children) as ReactElement; return ( - {cloneElement(element, mergeProps(element.props, attributes))} + {cloneElement( + element, + mergeProps(element.props as Record, attributes) + )} ); } diff --git a/design-system/pkg/src/table/context.tsx b/design-system/pkg/src/table/context.tsx index ee29298a9..38e2d7429 100644 --- a/design-system/pkg/src/table/context.tsx +++ b/design-system/pkg/src/table/context.tsx @@ -68,7 +68,7 @@ export function useVirtualizerContext() { type TableRowContextValue = { dragButtonProps: HTMLAttributes; - dragButtonRef: RefObject; + dragButtonRef: RefObject; isFocusVisibleWithin: boolean; isHovered: boolean; }; diff --git a/design-system/pkg/src/table/index.ts b/design-system/pkg/src/table/index.ts index 7cc172190..52d7c2aef 100644 --- a/design-system/pkg/src/table/index.ts +++ b/design-system/pkg/src/table/index.ts @@ -1,8 +1,9 @@ 'use client'; - import { Column } from '@react-stately/table'; import { ColumnProps } from './types'; +import type { JSX } from 'react'; + export { TableView } from './TableView'; // Override TS for Column to support Keystar UI specific props. diff --git a/design-system/pkg/src/table/types.ts b/design-system/pkg/src/table/types.ts index 12cbb5fcc..d1de063f0 100644 --- a/design-system/pkg/src/table/types.ts +++ b/design-system/pkg/src/table/types.ts @@ -7,7 +7,7 @@ import { ColumnSize, TableProps as ReactAriaTableProps, } from '@react-types/table'; -import { Key, ReactElement, ReactNode } from 'react'; +import { Key, ReactElement, ReactNode, type JSX } from 'react'; import { DragAndDropHooks } from '@keystar/ui/drag-and-drop'; import { BaseStyleProps } from '@keystar/ui/style'; @@ -34,9 +34,9 @@ export type TableCosmeticConfig = { }; export type TableProps = { /** Handler that is called when a user performs an action on a row. */ - onAction?: (key: Key) => void; + onAction?: (key: string | number) => void; /** @deprecated Use `onAction` instead. */ - onRowAction?: (key: Key) => void; + onRowAction?: (key: string | number) => void; /** What should render when there is no content to display. */ renderEmptyState?: () => JSX.Element; /** diff --git a/design-system/pkg/src/tabs/Tabs.tsx b/design-system/pkg/src/tabs/Tabs.tsx index 62ce01a72..2d70407a5 100644 --- a/design-system/pkg/src/tabs/Tabs.tsx +++ b/design-system/pkg/src/tabs/Tabs.tsx @@ -23,6 +23,7 @@ import React, { useEffect, useRef, useState, + ElementType, } from 'react'; import { useProvider, useProviderProps } from '@keystar/ui/core'; @@ -191,7 +192,7 @@ function Tab(props: TabProps) { let { pressProps, isPressed } = usePress({ ...otherProps, isDisabled }); let { hoverProps, isHovered } = useHover({ ...otherProps, isDisabled }); - let ElementType: React.ElementType = item.props.href ? 'a' : 'div'; + let ElementType: ElementType = item.props.href ? 'a' : 'div'; return ( @@ -713,6 +714,6 @@ function TabPicker(props: TabPickerProps) { // forwardRef doesn't support generic parameters, so cast the result to the correct type // https://stackoverflow.com/questions/58469229/react-with-typescript-generics-while-using-react-forwardref const _Tabs: ( - props: TabsProps & { ref?: RefObject } + props: TabsProps & { ref?: RefObject } ) => ReactElement = React.forwardRef(Tabs) as any; export { _Tabs as Tabs }; diff --git a/design-system/pkg/src/tabs/types.ts b/design-system/pkg/src/tabs/types.ts index 504f68c89..197843e05 100644 --- a/design-system/pkg/src/tabs/types.ts +++ b/design-system/pkg/src/tabs/types.ts @@ -2,10 +2,11 @@ import { AriaLabelingProps, CollectionChildren, DOMProps, + Key, Orientation, SingleSelection, } from '@react-types/shared'; -import { Key, ReactNode } from 'react'; +import { ReactNode } from 'react'; import { BaseStyleProps } from '@keystar/ui/style'; diff --git a/design-system/pkg/src/test-utils/setup.tsx b/design-system/pkg/src/test-utils/setup.tsx index 95b923704..601c9af47 100644 --- a/design-system/pkg/src/test-utils/setup.tsx +++ b/design-system/pkg/src/test-utils/setup.tsx @@ -1,5 +1,5 @@ import { render, RenderOptions, RenderResult } from '@testing-library/react'; -import { ReactElement, StrictMode } from 'react'; +import { ReactElement, ReactNode, StrictMode } from 'react'; import { TestProvider } from '@keystar/ui/core'; @@ -17,7 +17,7 @@ export function customRender( return render(ui, { wrapper: StrictModeWrapper, ...options }); } -function StrictModeWrapper(props: { children: ReactElement }) { +function StrictModeWrapper(props: { children: ReactNode }) { if (process.env.STRICT_MODE) { return {props.children}; } @@ -25,7 +25,7 @@ function StrictModeWrapper(props: { children: ReactElement }) { return props.children; } -function StrictModeProvider(props: { children: ReactElement }) { +function StrictModeProvider(props: { children: ReactNode }) { return ( {props.children} diff --git a/design-system/pkg/src/text-field/test/TextArea.test.tsx b/design-system/pkg/src/text-field/test/TextArea.test.tsx index 6d4919530..b4d117807 100644 --- a/design-system/pkg/src/text-field/test/TextArea.test.tsx +++ b/design-system/pkg/src/text-field/test/TextArea.test.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { RefObject } from 'react'; import { afterEach, expect, jest, describe, it } from '@jest/globals'; import { render } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; @@ -10,7 +10,7 @@ let inputText = 'Hello world'; function renderTextArea( props: Partial = {}, - ref?: React.RefObject + ref?: RefObject ) { return render(