Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BREAKING: render-based composition #829

Merged
merged 5 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

Reactist follows [semantic versioning](https://semver.org/) and doesn't introduce breaking changes (API-wise) in minor or patch releases. However, the appearance of a component might change in a minor or patch release so keep an eye on redesigns and make sure your app still looks and feels like you expect it.

# v25.0.0-beta.1

- [BREAKING] Use an explicit `render` prop for composition, instead of the `as` prop (in the menu, modal, tabs, toasts and tooltip components).
- [BREAKING] `TabPanel`'s prop `render` is renamed to `renderMode`.

# v25.0.0-beta

- [BREAKING] Removed the `ButtonLink` component.
Expand Down
48 changes: 18 additions & 30 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"email": "[email protected]",
"url": "http://doist.com"
},
"version": "25.0.0-beta",
"version": "25.0.0-beta.1",
"license": "MIT",
"homepage": "https://github.com/Doist/reactist#readme",
"repository": {
Expand Down Expand Up @@ -90,8 +90,8 @@
"@types/jest": "28.1.8",
"@types/jest-axe": "^3.5.3",
"@types/marked": "^4.0.8",
"@types/react": "^17.0.45",
"@types/react-dom": "^17.0.17",
"@types/react": "18.3.1",
"@types/react-dom": "18.3.0",
"@typescript-eslint/eslint-plugin": "^5.25.0",
"@typescript-eslint/parser": "^5.25.0",
"@wojtekmaj/enzyme-adapter-react-17": "^0.6.7",
Expand Down
4 changes: 2 additions & 2 deletions src/avatar/avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { getInitials, emailToIndex } from './utils'
import { getClassNames, ResponsiveProp } from '../utils/responsive-props'
import styles from './avatar.module.css'
import { Box } from '../box'
import type { ObfuscatedClassName } from '../utils/common-types'

const AVATAR_COLORS = [
'#fcc652',
Expand All @@ -29,10 +30,9 @@ const AVATAR_COLORS = [

type AvatarSize = 'xxs' | 'xs' | 's' | 'm' | 'l' | 'xl' | 'xxl' | 'xxxl'

type Props = {
type Props = ObfuscatedClassName & {
/** @deprecated Please use `exceptionallySetClassName` */
className?: string
exceptionallySetClassName?: string
/** @deprecated */
colorList?: string[]
size?: ResponsiveProp<AvatarSize>
Expand Down
9 changes: 7 additions & 2 deletions src/banner/banner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,31 @@ export type BannerTone = 'info' | 'promotion'

type BannerProps = {
id?: string

/**
* The tone of the Banner. Affects the background color and the outline.
*/
tone: BannerTone

/**
* The icon that should be added inside the Banner.
*/
icon: React.ReactChild
icon: React.ReactElement | string | number

/**
* The title to be displayed at the top of the Banner.
*/
title: React.ReactNode

/**
* An optional description to be displayed inside the Banner.
*/
description?: React.ReactNode

/**
* An optional action to displayed inside the Banner.
*/
action?: React.ReactChild
action?: React.ReactElement | string | number
}

const Banner = React.forwardRef<HTMLDivElement, BannerProps>(function Banner(
Expand Down
6 changes: 3 additions & 3 deletions src/button/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function preventDefault(event: React.SyntheticEvent) {
type ButtonVariant = 'primary' | 'secondary' | 'tertiary' | 'quaternary'
type ButtonTone = 'normal' | 'destructive'
type ButtonSize = 'small' | 'normal' | 'large'
type IconElement = React.ReactChild
type IconElement = React.ReactElement | string

interface CommonButtonProps
extends ObfuscatedClassName,
Expand Down Expand Up @@ -98,7 +98,7 @@ interface ButtonProps extends CommonButtonProps {
/**
* The button label content.
*/
children: React.ReactNode
children?: React.ReactNode

/**
* The icon to display at the start of the button (before the label).
Expand Down Expand Up @@ -225,7 +225,7 @@ interface IconButtonProps extends CommonButtonProps {
* also makes sure to always show a tooltip with its label. It follows the
* [WAI-ARIA Button Pattern](https://www.w3.org/TR/wai-aria-practices/#button).
*/
const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(function Button(
const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(function IconButton(
{
variant,
tone = 'normal',
Expand Down
4 changes: 2 additions & 2 deletions src/checkbox-field/checkbox-field.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,14 @@ A checkbox field with an icon and a string. The icon is rendered to the left of
</Story>
</Canvas>

#### ReactChild as Icon
#### React element as Icon

In this example we are passing an SVG image as icon.

<Canvas>
<Story
parameters={{ docs: { source: { type: 'dynamic' } } }}
name="ReactChild as icon"
name="React element as icon"
args={{
label: 'Label with icon',
icon: <Icon />,
Expand Down
70 changes: 44 additions & 26 deletions src/checkbox-field/checkbox-field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,57 @@ import { CheckboxIcon } from './checkbox-icon'
import styles from './checkbox-field.module.css'
import { useForkRef } from './use-fork-ref'

/**
* FIXME: This is a workaround for consumers that are using newer versions of React types that no longer have these props.
* Once we upgrade Reactist to the newest React types, we should be able to remove these.
*/
type DeprecatedProps = 'crossOrigin' | 'onPointerEnterCapture' | 'onPointerLeaveCapture'

type CheckboxFieldProps = Omit<
JSX.IntrinsicElements['input'],
| 'type'
| 'className'
| 'disabled'
| 'aria-controls'
| 'aria-describedby'
| 'aria-label'
| 'aria-labelledby'
| DeprecatedProps
> & {
interface CheckboxFieldProps
extends Omit<
JSX.IntrinsicElements['input'],
| 'type'
| 'className'
| 'disabled'
| 'aria-controls'
| 'aria-describedby'
| 'aria-label'
| 'aria-labelledby'
> {
'aria-checked'?: never
/** Identifies the set of checkboxes controlled by the mixed checkbox for assistive technologies. */
/**
*
* Identifies the set of checkboxes controlled by the mixed checkbox for assistive technologies.
*/
'aria-controls'?: string
/** Identifies the element (or elements) that describes the checkbox for assistive technologies. */

/**
* Identifies the element (or elements) that describes the checkbox for assistive technologies.
*/
'aria-describedby'?: string
/** Defines a string value that labels the current checkbox for assistive technologies. */

/**
* Defines a string value that labels the current checkbox for assistive technologies.
*/
'aria-label'?: string
/** Identifies the element (or elements) that labels the current checkbox for assistive technologies. */

/**
* Identifies the element (or elements) that labels the current checkbox for assistive technologies.
*/
'aria-labelledby'?: string
/** Defines whether or not the checkbox is disabled. */

/**
* Defines whether or not the checkbox is disabled.
*/
disabled?: boolean
/** The label for the checkbox element. */

/**
* The label for the checkbox element.
*/
label?: React.ReactNode
/** The icon that should be added to the checkbox label. */
icon?: React.ReactChild
/** Defines whether or not the checkbox can be of a `mixed` state. */

/**
* The icon that should be added to the checkbox label.
*/
icon?: React.ReactElement | string | number

/**
* Defines whether or not the checkbox can be of a `mixed` state.
*/
indeterminate?: boolean
}

Expand Down
2 changes: 1 addition & 1 deletion src/components/deprecated-dropdown/dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type BoxState = {
showBody: boolean
}

class Box extends React.Component<React.PropsWithChildren<BoxProps>, BoxState> {
class Box extends React.Component<BoxProps, BoxState> {
public static displayName: string

constructor(props: BoxProps, context: React.Context<unknown>) {
Expand Down
19 changes: 8 additions & 11 deletions src/components/deprecated-input/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,17 @@ import classNames from 'classnames'

import './input.less'

type InputProps = {
/** Additional css class applied to the input. */
interface Props extends React.InputHTMLAttributes<HTMLInputElement> {
className?: string
ref?: React.Ref<HTMLInputElement>
}

type Props = InputProps & React.InputHTMLAttributes<HTMLInputElement>

const Input: React.FC<React.PropsWithRef<Props>> = React.forwardRef(
(props: Props, ref: React.Ref<HTMLInputElement>) => {
const className = classNames('reactist_input', props.className)
return <input {...props} className={className} ref={ref} />
},
)
/**
* @deprecated
*/
const Input = React.forwardRef<HTMLInputElement, Props>(function Input(props, ref) {
const className = classNames('reactist_input', props.className)
return <input {...props} className={className} ref={ref} />
})
Input.displayName = 'Input'

export { Input }
Loading
Loading