From 60424067366559020f085c0b0e5b341529e72d64 Mon Sep 17 00:00:00 2001 From: Miroslav Petrik Date: Fri, 17 Oct 2025 10:56:39 +0200 Subject: [PATCH 1/2] fix: drop render-prop as only children-prop is used --- package.json | 5 -- src/components/field-errors/FieldErrors.tsx | 21 +++++---- src/components/field-label/FieldLabel.tsx | 20 +++++--- src/components/file-upload/FileUpload.tsx | 6 ++- .../file-upload/SwitchUploadAtom.tsx | 24 +++++----- src/components/radio/Radio.tsx | 8 ++-- src/components/radio/RadioControl.tsx | 5 +- .../select/TwoOptionsOneSelect.stories.tsx | 5 +- src/scenarios/PicoFieldErrors.tsx | 31 +++++++------ src/scenarios/StoryForm.tsx | 12 ++--- yarn.lock | 46 ------------------- 11 files changed, 76 insertions(+), 107 deletions(-) diff --git a/package.json b/package.json index 106578f..8a0352c 100644 --- a/package.json +++ b/package.json @@ -66,11 +66,9 @@ "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", "@types/lodash.shuffle": "^4.2.9", - "@types/prettier": "^3.0.0", "@types/react": "^18", "@types/react-copy-to-clipboard": "^5", "@types/react-dom": "^18", - "@types/semantic-release": "^20.0.6", "@vitejs/plugin-react": "^4.7.0", "@vitest/coverage-v8": "^3.2.4", "eslint": "9.37.0", @@ -96,9 +94,6 @@ "vitest": "^3.2.4", "zod": "3.22.4" }, - "dependencies": { - "react-render-prop-type": "0.1.0" - }, "publishConfig": { "access": "public" }, diff --git a/src/components/field-errors/FieldErrors.tsx b/src/components/field-errors/FieldErrors.tsx index 04fc603..eb019c1 100644 --- a/src/components/field-errors/FieldErrors.tsx +++ b/src/components/field-errors/FieldErrors.tsx @@ -1,14 +1,15 @@ -import { useFieldErrors } from "form-atoms"; -import type { FieldAtom } from "form-atoms"; -import { RenderProp } from "react-render-prop-type"; +import { type FieldAtom, useFieldErrors } from "form-atoms"; -type ChildrenProp = RenderProp<{ errors: ReturnType }>; +export type FieldErrorsProps = { + field: FieldAtom; + children?: (props: { + errors: ReturnType; + }) => React.ReactElement; +}; -export type FieldErrorsProps = { - field: FieldAtom; -} & Partial; - -export const FieldErrors = ({ +export function FieldErrors({ field, children = ({ errors }) => <>{errors.join("\n")}, -}: FieldErrorsProps) => children({ errors: useFieldErrors(field) }); +}: FieldErrorsProps) { + return children({ errors: useFieldErrors(field) }); +} diff --git a/src/components/field-label/FieldLabel.tsx b/src/components/field-label/FieldLabel.tsx index 939c9f7..8c44a82 100644 --- a/src/components/field-label/FieldLabel.tsx +++ b/src/components/field-label/FieldLabel.tsx @@ -1,22 +1,30 @@ -import { FieldAtom } from "form-atoms"; -import { MouseEventHandler, ReactNode, useCallback } from "react"; -import { RenderProp } from "react-render-prop-type"; +"use client"; -type Children = RenderProp<{ - children: ReactNode; +import type { FieldAtom } from "form-atoms"; +import { + MouseEventHandler, + PropsWithChildren, + ReactNode, + useCallback, +} from "react"; + +type ChildrenProps = PropsWithChildren<{ htmlFor: string; onMouseDown: MouseEventHandler; }>; +// eslint-disable-next-line @typescript-eslint/no-explicit-any type FieldLabelProps> = { field: Field; label: ReactNode; -} & Partial; + children?: (props: ChildrenProps) => React.ReactElement; +}; /** * Renders an accessible label controlling the field's input. * @deprecated The atomKey is not suitable for input/label pairing as it does not support SSR. Moreover the onMouseDown is UX feature, not a logic concern for a field. */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any export const FieldLabel = >({ field, label, diff --git a/src/components/file-upload/FileUpload.tsx b/src/components/file-upload/FileUpload.tsx index 24c9dc0..3d93f45 100644 --- a/src/components/file-upload/FileUpload.tsx +++ b/src/components/file-upload/FileUpload.tsx @@ -1,6 +1,5 @@ import { useAtomValue, useSetAtom } from "jotai"; import { useEffect } from "react"; -import { RenderProp } from "react-render-prop-type"; import { UploadAtom } from "../../atoms"; @@ -10,7 +9,10 @@ type ChildrenProps = { isSuccess: boolean; }; -type Props = { field: UploadAtom } & RenderProp; +type Props = { + field: UploadAtom; + children: (props: ChildrenProps) => React.ReactElement; +}; export function FileUpload({ field, children }: Props) { const atoms = useAtomValue(field); diff --git a/src/components/file-upload/SwitchUploadAtom.tsx b/src/components/file-upload/SwitchUploadAtom.tsx index a5ad478..d9ae41e 100644 --- a/src/components/file-upload/SwitchUploadAtom.tsx +++ b/src/components/file-upload/SwitchUploadAtom.tsx @@ -1,27 +1,27 @@ import { FieldAtom } from "form-atoms"; import { useAtomValue } from "jotai"; -import { RenderProp } from "react-render-prop-type"; import { UploadAtom } from "../../atoms"; -export function useIsUploadAtom( - field: FieldAtom, -): field is UploadAtom { +export function useIsUploadAtom( + field: FieldAtom, +): field is UploadAtom { const atoms = useAtomValue(field); - return !!(atoms as any).uploadStatus; + return "uploadStatus" in atoms; } type UploadProps = { isUpload: true; field: UploadAtom }; - type RegularProps = { isUpload: false; field: FieldAtom }; -export const SwitchUploadAtom = ({ - field, - children, -}: { field: FieldAtom } & RenderProp< - UploadProps | RegularProps ->) => { +type Props = { + field: FieldAtom; + children: ( + props: UploadProps | RegularProps, + ) => React.ReactNode; +}; + +export const SwitchUploadAtom = ({ field, children }: Props) => { if (useIsUploadAtom(field)) { return <>{children({ isUpload: true, field })}; } else { diff --git a/src/components/radio/Radio.tsx b/src/components/radio/Radio.tsx index adeb0ec..d660a3a 100644 --- a/src/components/radio/Radio.tsx +++ b/src/components/radio/Radio.tsx @@ -1,7 +1,6 @@ import { useFieldActions, useFieldValue } from "form-atoms"; import { useAtom } from "jotai"; import { useEffect, useRef } from "react"; -import { RenderProp } from "react-render-prop-type"; import { RadioControlAtom } from "./RadioControl"; import { CheckboxField } from "../../fields"; @@ -72,5 +71,8 @@ export const Radio = ({ field, control, children, -}: Props & RenderProp>) => - children(useRadio({ control, field })); +}: Props & { + children: ( + props: ReturnType, + ) => React.ReactNode; +}) => children(useRadio({ control, field })); diff --git a/src/components/radio/RadioControl.tsx b/src/components/radio/RadioControl.tsx index 33cfac9..34caf75 100644 --- a/src/components/radio/RadioControl.tsx +++ b/src/components/radio/RadioControl.tsx @@ -1,6 +1,5 @@ import { atom } from "jotai"; import { useMemo } from "react"; -import { RenderProp } from "react-render-prop-type"; import { CheckboxField } from "../../fields"; @@ -11,7 +10,9 @@ export type RadioControlAtom = ReturnType; export const RadioControl = ({ name, children, -}: Partial<{ name: string }> & RenderProp<{ control: RadioControlAtom }>) => { +}: Partial<{ name: string }> & { + children: (props: { control: RadioControlAtom }) => React.ReactNode; +}) => { /** * Atom to keep track of currently active checkbox fieldAtom. */ diff --git a/src/components/select/TwoOptionsOneSelect.stories.tsx b/src/components/select/TwoOptionsOneSelect.stories.tsx index 3ac1237..57da398 100644 --- a/src/components/select/TwoOptionsOneSelect.stories.tsx +++ b/src/components/select/TwoOptionsOneSelect.stories.tsx @@ -1,6 +1,5 @@ import shuffle from "lodash.shuffle"; import { useCallback, useState } from "react"; -import { RenderProp } from "react-render-prop-type"; import { SelectField } from "./SelectField.mock"; import { stringField } from "../../fields"; @@ -48,7 +47,9 @@ export const TwoOptionsOneSelect = formStory({ const SwapCountries = ({ children, -}: RenderProp<{ countries: typeof countryOptions }>) => { +}: { + children: (props: { countries: typeof countryOptions }) => React.ReactNode; +}) => { const [countries, setCountries] = useState(countryOptions); const swapCountries = useCallback(() => { diff --git a/src/scenarios/PicoFieldErrors.tsx b/src/scenarios/PicoFieldErrors.tsx index b8ac271..280d246 100644 --- a/src/scenarios/PicoFieldErrors.tsx +++ b/src/scenarios/PicoFieldErrors.tsx @@ -2,16 +2,21 @@ import { FieldErrors, FieldErrorsProps } from "../components"; const style = { color: "var(--pico-color-red-550)" }; -export const PicoFieldErrors = (props: Omit) => ( - - {({ errors }) => ( - <> - {errors.map((error, index) => ( -

- {error} -

- ))} - - )} -
-); +export function PicoFieldErrors( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + props: Omit, "children">, +) { + return ( + + {({ errors }) => ( + <> + {errors.map((error, index) => ( +

+ {error} +

+ ))} + + )} +
+ ); +} diff --git a/src/scenarios/StoryForm.tsx b/src/scenarios/StoryForm.tsx index 64654a9..90ec5f0 100644 --- a/src/scenarios/StoryForm.tsx +++ b/src/scenarios/StoryForm.tsx @@ -2,17 +2,17 @@ import { action } from "storybook/actions"; import { Meta, StoryObj } from "@storybook/react"; import { FormAtom, FormFields, formAtom, useFormActions } from "form-atoms"; import { useMemo } from "react"; -import { RenderProp } from "react-render-prop-type"; type Props = { fields: Fields; resettable?: boolean; required?: boolean; -} & RenderProp<{ - form: FormAtom; - fields: Fields; - required: boolean; -}>; + children: (props: { + form: FormAtom; + fields: Fields; + required: boolean; + }) => React.ReactNode; +}; export const StoryForm = ({ resettable = true, diff --git a/yarn.lock b/yarn.lock index e349183..46ad8ac 100644 --- a/yarn.lock +++ b/yarn.lock @@ -878,11 +878,9 @@ __metadata: "@testing-library/react": "npm:^16.3.0" "@testing-library/user-event": "npm:^14.6.1" "@types/lodash.shuffle": "npm:^4.2.9" - "@types/prettier": "npm:^3.0.0" "@types/react": "npm:^18" "@types/react-copy-to-clipboard": "npm:^5" "@types/react-dom": "npm:^18" - "@types/semantic-release": "npm:^20.0.6" "@vitejs/plugin-react": "npm:^4.7.0" "@vitest/coverage-v8": "npm:^3.2.4" eslint: "npm:9.37.0" @@ -898,7 +896,6 @@ __metadata: react: "npm:^18.2.0" react-copy-to-clipboard: "npm:^5.1.0" react-dom: "npm:^18.2.0" - react-render-prop-type: "npm:0.1.0" remark-gfm: "npm:^4.0.1" semantic-release: "npm:^25.0.0" shiki: "npm:^3.13.0" @@ -2602,13 +2599,6 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*": - version: 18.11.18 - resolution: "@types/node@npm:18.11.18" - checksum: 10/da05cf3a0036ef05cd695ac4cb265948593acbe723ba818f0ca0ce466b13ba99e1aac3a363086d6b8c7ea8f30c9233478e0293ac878a6f4b1d5515b10c392257 - languageName: node - linkType: hard - "@types/node@npm:^20.0.0": version: 20.19.17 resolution: "@types/node@npm:20.19.17" @@ -2632,15 +2622,6 @@ __metadata: languageName: node linkType: hard -"@types/prettier@npm:^3.0.0": - version: 3.0.0 - resolution: "@types/prettier@npm:3.0.0" - dependencies: - prettier: "npm:*" - checksum: 10/a2a512d304e5bcf78f38089dc88ad19215e6ab871d435a17aef3ce538a63b07c0e359c18db23989dc1ed9fff96d99eee1f680416080184df5c7e0e3bf767e165 - languageName: node - linkType: hard - "@types/prop-types@npm:*": version: 15.7.5 resolution: "@types/prop-types@npm:15.7.5" @@ -2691,15 +2672,6 @@ __metadata: languageName: node linkType: hard -"@types/semantic-release@npm:^20.0.6": - version: 20.0.6 - resolution: "@types/semantic-release@npm:20.0.6" - dependencies: - "@types/node": "npm:*" - checksum: 10/7e2c186b07012a0468c1024201be0eda801927093eeb1c7b98d58881b8d66ca7647ff310673eaaeeef312f16c70409386d6a839b6c1a552dd500057678d4b682 - languageName: node - linkType: hard - "@types/unist@npm:*, @types/unist@npm:^3.0.0": version: 3.0.3 resolution: "@types/unist@npm:3.0.3" @@ -8625,15 +8597,6 @@ __metadata: languageName: node linkType: hard -"prettier@npm:*": - version: 3.1.0 - resolution: "prettier@npm:3.1.0" - bin: - prettier: bin/prettier.cjs - checksum: 10/e95e8f93c6b9aea2ac1e86bebe329bee90c8c50d9a23d1f593eba8d7f39b33b3641eb28785001505b6723c47895a5322ad12a2fb855b289cb7bae450ffc34425 - languageName: node - linkType: hard - "prettier@npm:3.6.2": version: 3.6.2 resolution: "prettier@npm:3.6.2" @@ -8953,15 +8916,6 @@ __metadata: languageName: node linkType: hard -"react-render-prop-type@npm:0.1.0": - version: 0.1.0 - resolution: "react-render-prop-type@npm:0.1.0" - peerDependencies: - react: ^18.2.0 - checksum: 10/165460282d60135b1287ce2801f2179b1d0a1e0665200ce8ba0868c0c37149bf93101934a63d5b75249e96bf1bc5d127a26bc6b571d6fcf3985d72515548e6cc - languageName: node - linkType: hard - "react-resizable-panels@npm:^0.0.54": version: 0.0.54 resolution: "react-resizable-panels@npm:0.0.54" From 5358ac70566895fbfc030b52235de2f51f1daf0d Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 17 Oct 2025 09:20:24 +0000 Subject: [PATCH 2/2] chore(release): 5.3.2 ## [5.3.2](https://github.com/form-atoms/field/compare/v5.3.1...v5.3.2) (2025-10-17) ### Bug Fixes * drop render-prop as only children-prop is used ([6042406](https://github.com/form-atoms/field/commit/60424067366559020f085c0b0e5b341529e72d64)) --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a58a10b..2623056 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [5.3.2](https://github.com/form-atoms/field/compare/v5.3.1...v5.3.2) (2025-10-17) + + +### Bug Fixes + +* drop render-prop as only children-prop is used ([6042406](https://github.com/form-atoms/field/commit/60424067366559020f085c0b0e5b341529e72d64)) + ## [5.3.1](https://github.com/form-atoms/field/compare/v5.3.0...v5.3.1) (2025-10-17)