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

Make records paths inferred from type compatible with react-hook-form #10279

Merged
merged 4 commits into from
Oct 16, 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
1 change: 0 additions & 1 deletion packages/ra-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@
"clsx": "^2.1.1",
"date-fns": "^3.6.0",
"eventemitter3": "^5.0.1",
"hotscript": "^1.0.12",
"inflection": "^3.0.0",
"jsonexport": "^3.2.0",
"lodash": "~4.17.5",
Expand Down
22 changes: 19 additions & 3 deletions packages/ra-core/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ComponentType, ReactElement, ReactNode } from 'react';
import { FieldPath } from 'react-hook-form';
import { WithPermissionsChildrenParams } from './auth/WithPermissions';
import { AuthActionType } from './auth/types';

Expand Down Expand Up @@ -399,6 +400,21 @@ export type FormFunctions = {

// Type for a string that accept one of the known values but also any other string
// Useful for IDE autocompletion without preventing custom values
export type HintedString<KnownValues extends string> =
| (string & {})
| KnownValues;
export type HintedString<KnownValues extends string> = AnyString | KnownValues;

// Re-export react-hook-form implementation of FieldPath that returns all possible paths of an object
// This will allow us to either include the FieldPath implementation from react-hook-form or replace it with our own
// should we move away from react-hook-form
// type Post = { title: string; author: { name: string; }; tags: { id: string; name: string} };
// => Valid paths are "title" | "author" | "author.name" | "tags.id" | "tags.name"
export type RecordValues = Record<string, any>;
export type RecordPath<TRecordValues extends RecordValues> =
FieldPath<TRecordValues>;

// Returns the union of all possible paths of a type if it is provided, otherwise returns a string
// Useful for props such as "source" in react-admin components
export type ExtractRecordPaths<T extends RecordValues> =
// Trick that allows to check whether T was provided
[T] extends [never] ? string : RecordPath<T>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we used AnyString as the default value, now it's string. Isn't it a BC?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, AnyString is no longer necessary

Copy link
Collaborator Author

@djhi djhi Oct 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More precisely, AnyString wasn't needed before. It was unnecessary already. It's only useful for HintedString


export type AnyString = string & {};
8 changes: 2 additions & 6 deletions packages/ra-core/src/util/useFieldValue.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import get from 'lodash/get';
import { Call, Objects } from 'hotscript';
import { useRecordContext } from '../controller';
import { ExtractRecordPaths } from '../types';

/**
* A hook that gets the value of a field of the current record.
Expand Down Expand Up @@ -38,10 +38,6 @@ export interface UseFieldValueOptions<
> {
// FIXME: Find a way to throw a type error when defaultValue is not of RecordType[Source] type
defaultValue?: any;
source: Call<Objects.AllPaths, RecordType> extends never
? AnyString
: Call<Objects.AllPaths, RecordType>;
source: ExtractRecordPaths<RecordType>;
record?: RecordType;
}

type AnyString = string & {};
1 change: 0 additions & 1 deletion packages/ra-ui-materialui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@
"clsx": "^2.1.1",
"css-mediaquery": "^0.1.2",
"dompurify": "^2.4.3",
"hotscript": "^1.0.12",
"inflection": "^3.0.0",
"jsonexport": "^3.2.0",
"lodash": "~4.17.5",
Expand Down
13 changes: 7 additions & 6 deletions packages/ra-ui-materialui/src/field/FileField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ import * as React from 'react';
import { styled } from '@mui/material/styles';
import get from 'lodash/get';
import Typography from '@mui/material/Typography';
import { useFieldValue, useTranslate } from 'ra-core';
import { Call, Objects } from 'hotscript';
import {
ExtractRecordPaths,
HintedString,
useFieldValue,
useTranslate,
} from 'ra-core';

import { sanitizeFieldRestProps } from './sanitizeFieldRestProps';
import { FieldProps } from './types';
Expand Down Expand Up @@ -114,16 +118,13 @@ export interface FileFieldProps<
RecordType extends Record<string, any> = Record<string, any>,
> extends FieldProps<RecordType> {
src?: string;
title?: Call<Objects.AllPaths, RecordType> extends never
? AnyString
: Call<Objects.AllPaths, RecordType> | AnyString;
title?: HintedString<ExtractRecordPaths<RecordType>>;
target?: string;
download?: boolean | string;
ping?: string;
rel?: string;
sx?: SxProps;
}
type AnyString = string & {};

const PREFIX = 'RaFileField';

Expand Down
14 changes: 7 additions & 7 deletions packages/ra-ui-materialui/src/field/ImageField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ import * as React from 'react';
import { styled } from '@mui/material/styles';
import { Box, Typography } from '@mui/material';
import get from 'lodash/get';
import { useFieldValue, useTranslate } from 'ra-core';
import { Call, Objects } from 'hotscript';
import {
ExtractRecordPaths,
HintedString,
useFieldValue,
useTranslate,
} from 'ra-core';

import { sanitizeFieldRestProps } from './sanitizeFieldRestProps';
import { FieldProps } from './types';
Expand Down Expand Up @@ -111,10 +115,6 @@ export interface ImageFieldProps<
RecordType extends Record<string, any> = Record<string, any>,
> extends FieldProps<RecordType> {
src?: string;
title?: Call<Objects.AllPaths, RecordType> extends never
? AnyString
: Call<Objects.AllPaths, RecordType> | AnyString;
title?: HintedString<ExtractRecordPaths<RecordType>>;
sx?: SxProps;
}

type AnyString = string & {};
9 changes: 3 additions & 6 deletions packages/ra-ui-materialui/src/field/types.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { ReactElement } from 'react';
import { TableCellProps } from '@mui/material/TableCell';
import { Call, Objects } from 'hotscript';
import { ExtractRecordPaths, HintedString } from 'ra-core';

type TextAlign = TableCellProps['align'];
type SortOrder = 'ASC' | 'DESC';
type AnyString = string & {};

export interface FieldProps<
RecordType extends Record<string, any> = Record<string, any>,
Expand All @@ -25,7 +24,7 @@ export interface FieldProps<
* </List>
* );
*/
sortBy?: Call<Objects.AllPaths, RecordType> | AnyString;
sortBy?: HintedString<ExtractRecordPaths<RecordType>>;

/**
* The order used for sorting when users click this column head, if sortable.
Expand Down Expand Up @@ -57,9 +56,7 @@ export interface FieldProps<
* </List>
* );
*/
source: Call<Objects.AllPaths, RecordType> extends never
? AnyString
: Call<Objects.AllPaths, RecordType>;
source: ExtractRecordPaths<RecordType>;

/**
* Label to use as column header when using <Datagrid> or <SimpleShowLayout>.
Expand Down
9 changes: 0 additions & 9 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -12629,13 +12629,6 @@ __metadata:
languageName: node
linkType: hard

"hotscript@npm:^1.0.12":
version: 1.0.12
resolution: "hotscript@npm:1.0.12"
checksum: 3ab48ec3405bda539ed5438e177914f65be0facb1acd1aa725ee716216ca87d2d1916f2b6ac58d8b7e94ad517a349c46fd7c45f24fe9f7fedf4799f12cb410d4
languageName: node
linkType: hard

"html-encoding-sniffer@npm:^3.0.0":
version: 3.0.0
resolution: "html-encoding-sniffer@npm:3.0.0"
Expand Down Expand Up @@ -17831,7 +17824,6 @@ __metadata:
date-fns: "npm:^3.6.0"
eventemitter3: "npm:^5.0.1"
expect: "npm:^27.4.6"
hotscript: "npm:^1.0.12"
ignore-styles: "npm:~5.0.1"
inflection: "npm:^3.0.0"
jscodeshift: "npm:^0.15.2"
Expand Down Expand Up @@ -18105,7 +18097,6 @@ __metadata:
dompurify: "npm:^2.4.3"
expect: "npm:^27.4.6"
file-api: "npm:~0.10.4"
hotscript: "npm:^1.0.12"
ignore-styles: "npm:~5.0.1"
inflection: "npm:^3.0.0"
jsonexport: "npm:^3.2.0"
Expand Down
Loading