diff --git a/packages/dataviews/CHANGELOG.md b/packages/dataviews/CHANGELOG.md
index 30cdcb6566e0ab..62601c114ad395 100644
--- a/packages/dataviews/CHANGELOG.md
+++ b/packages/dataviews/CHANGELOG.md
@@ -31,6 +31,7 @@
### Breaking changes
- DataViews: rename `groupByField` to `groupBy.field` to allow control over both the field and the direction of the grouping. [#72780](https://github.com/WordPress/gutenberg/pull/72780)
+- Types: FieldType is now FieldTypeName. [#73546](https://github.com/WordPress/gutenberg/pull/73546)
## 10.3.0 (2025-11-12)
diff --git a/packages/dataviews/src/components/dataform/index.tsx b/packages/dataviews/src/components/dataform/index.tsx
index 321af6f9302669..65f4aad3fb7c5e 100644
--- a/packages/dataviews/src/components/dataform/index.tsx
+++ b/packages/dataviews/src/components/dataform/index.tsx
@@ -8,7 +8,7 @@ import { useMemo } from '@wordpress/element';
*/
import type { DataFormProps } from '../../types';
import { DataFormProvider } from '../dataform-context';
-import normalizeFields from '../../field-types/utils/normalize-fields';
+import normalizeFields from '../../field-types';
import { DataFormLayout } from '../../dataform-layouts/data-form-layout';
import normalizeForm from '../../dataform-layouts/normalize-form';
diff --git a/packages/dataviews/src/components/dataviews-picker/index.tsx b/packages/dataviews/src/components/dataviews-picker/index.tsx
index a97bb40825978f..11e64ee9b21312 100644
--- a/packages/dataviews/src/components/dataviews-picker/index.tsx
+++ b/packages/dataviews/src/components/dataviews-picker/index.tsx
@@ -29,7 +29,7 @@ import DataViewsViewConfig, {
DataviewsViewConfigDropdown,
ViewTypeMenu,
} from '../dataviews-view-config';
-import normalizeFields from '../../field-types/utils/normalize-fields';
+import normalizeFields from '../../field-types';
import type { ActionButton, Field, View, SupportedLayouts } from '../../types';
import type { SelectionOrUpdater } from '../../types/private';
type ItemWithId = { id: string };
diff --git a/packages/dataviews/src/components/dataviews/index.tsx b/packages/dataviews/src/components/dataviews/index.tsx
index 07cda5d91bd9b7..b3200b36b1045a 100644
--- a/packages/dataviews/src/components/dataviews/index.tsx
+++ b/packages/dataviews/src/components/dataviews/index.tsx
@@ -30,7 +30,7 @@ import DataViewsViewConfig, {
DataviewsViewConfigDropdown,
ViewTypeMenu,
} from '../dataviews-view-config';
-import normalizeFields from '../../field-types/utils/normalize-fields';
+import normalizeFields from '../../field-types';
import type { Action, Field, View, SupportedLayouts } from '../../types';
import type { SelectionOrUpdater } from '../../types/private';
type ItemWithId = { id: string };
diff --git a/packages/dataviews/src/field-types/array.tsx b/packages/dataviews/src/field-types/array.tsx
index 50fc08b519a645..4120a15626d29e 100644
--- a/packages/dataviews/src/field-types/array.tsx
+++ b/packages/dataviews/src/field-types/array.tsx
@@ -6,110 +6,72 @@ import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
*/
-import type {
- DataViewRenderFieldProps,
- Field,
- NormalizedField,
- Operator,
- Rules,
- SortDirection,
-} from '../types';
+import type { DataViewRenderFieldProps, Rules, SortDirection } from '../types';
+import type { FieldType } from '../types/private';
import {
OPERATOR_IS_ALL,
OPERATOR_IS_ANY,
OPERATOR_IS_NONE,
OPERATOR_IS_NOT_ALL,
} from '../constants';
-import { getControl } from '../dataform-controls';
-import hasElements from './utils/has-elements';
-import getValueFromId from './utils/get-value-from-id';
-import setValueFromId from './utils/set-value-from-id';
-import getFilterBy from './utils/get-filter-by';
function render( { item, field }: DataViewRenderFieldProps< any > ) {
const value = field.getValue( { item } ) || [];
return value.join( ', ' );
}
-const defaultOperators: Operator[] = [ OPERATOR_IS_ANY, OPERATOR_IS_NONE ];
-const validOperators: Operator[] = [
- OPERATOR_IS_ANY,
- OPERATOR_IS_NONE,
- OPERATOR_IS_ALL,
- OPERATOR_IS_NOT_ALL,
-];
-
-export default function normalizeField< Item >(
- field: Field< Item >
-): NormalizedField< Item > {
- const getValue = field.getValue || getValueFromId( field.id );
- const setValue = field.setValue || setValueFromId( field.id );
+const isValid: Rules< any > = {
+ elements: true,
+ custom: ( item: any, normalizedField ) => {
+ const value = normalizedField.getValue( { item } );
- const sort = ( a: any, b: any, direction: SortDirection ) => {
- // Sort arrays by length, then alphabetically by joined string
- const valueA = getValue( a );
- const valueB = getValue( b );
- const arrA = Array.isArray( valueA ) ? valueA : [];
- const arrB = Array.isArray( valueB ) ? valueB : [];
- if ( arrA.length !== arrB.length ) {
- return direction === 'asc'
- ? arrA.length - arrB.length
- : arrB.length - arrA.length;
+ if (
+ ! [ undefined, '', null ].includes( value ) &&
+ ! Array.isArray( value )
+ ) {
+ return __( 'Value must be an array.' );
}
- const joinedA = arrA.join( ',' );
- const joinedB = arrB.join( ',' );
- return direction === 'asc'
- ? joinedA.localeCompare( joinedB )
- : joinedB.localeCompare( joinedA );
- };
-
- const isValid: Rules< Item > = {
- elements: true,
- custom: ( item: any, normalizedField ) => {
- const value = normalizedField.getValue( { item } );
+ // Only allow strings for now. Can be extended to other types in the future.
+ if ( ! value.every( ( v: any ) => typeof v === 'string' ) ) {
+ return __( 'Every value must be a string.' );
+ }
- if (
- ! [ undefined, '', null ].includes( value ) &&
- ! Array.isArray( value )
- ) {
- return __( 'Value must be an array.' );
- }
+ return null;
+ },
+};
- // Only allow strings for now. Can be extended to other types in the future.
- if ( ! value.every( ( v: any ) => typeof v === 'string' ) ) {
- return __( 'Every value must be a string.' );
- }
+const sort = ( a: any, b: any, direction: SortDirection ) => {
+ // Sort arrays by length, then alphabetically by joined string
+ const arrA = Array.isArray( a ) ? a : [];
+ const arrB = Array.isArray( b ) ? b : [];
+ if ( arrA.length !== arrB.length ) {
+ return direction === 'asc'
+ ? arrA.length - arrB.length
+ : arrB.length - arrA.length;
+ }
- return null;
- },
- };
+ const joinedA = arrA.join( ',' );
+ const joinedB = arrB.join( ',' );
+ return direction === 'asc'
+ ? joinedA.localeCompare( joinedB )
+ : joinedB.localeCompare( joinedA );
+};
- return {
- id: field.id,
- type: 'array',
- label: field.label || field.id,
- header: field.header || field.label || field.id,
- description: field.description,
- placeholder: field.placeholder,
- getValue,
- setValue,
- elements: field.elements,
- getElements: field.getElements,
- hasElements: hasElements( field ),
- render: field.render ?? render,
- Edit: getControl( field, 'array' ),
- sort: field.sort ?? sort,
- isValid: {
- ...isValid,
- ...field.isValid,
- },
- isVisible: field.isVisible,
- enableSorting: field.enableSorting ?? true,
- enableGlobalSearch: field.enableGlobalSearch ?? false,
- enableHiding: field.enableHiding ?? true,
- readOnly: field.readOnly ?? false,
- filterBy: getFilterBy( field, defaultOperators, validOperators ),
- format: {},
- };
-}
+export default {
+ type: 'array',
+ render,
+ Edit: 'array',
+ sort,
+ isValid,
+ enableSorting: true,
+ enableGlobalSearch: false,
+ defaultOperators: [ OPERATOR_IS_ANY, OPERATOR_IS_NONE ],
+ validOperators: [
+ OPERATOR_IS_ANY,
+ OPERATOR_IS_NONE,
+ OPERATOR_IS_ALL,
+ OPERATOR_IS_NOT_ALL,
+ ],
+ getFormat: () => ( {} ),
+} satisfies FieldType< any >;
diff --git a/packages/dataviews/src/field-types/boolean.tsx b/packages/dataviews/src/field-types/boolean.tsx
index 3c1ab3059f4dd6..7e2275e2ae7880 100644
--- a/packages/dataviews/src/field-types/boolean.tsx
+++ b/packages/dataviews/src/field-types/boolean.tsx
@@ -6,21 +6,10 @@ import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
*/
-import type {
- DataViewRenderFieldProps,
- Field,
- NormalizedField,
- Operator,
- Rules,
- SortDirection,
-} from '../types';
+import type { DataViewRenderFieldProps, Rules, SortDirection } from '../types';
+import type { FieldType } from '../types/private';
import RenderFromElements from './utils/render-from-elements';
import { OPERATOR_IS, OPERATOR_IS_NOT } from '../constants';
-import { getControl } from '../dataform-controls';
-import hasElements from './utils/has-elements';
-import getValueFromId from './utils/get-value-from-id';
-import setValueFromId from './utils/set-value-from-id';
-import getFilterBy from './utils/get-filter-by';
function render( { item, field }: DataViewRenderFieldProps< any > ) {
if ( field.hasElements ) {
@@ -38,76 +27,48 @@ function render( { item, field }: DataViewRenderFieldProps< any > ) {
return null;
}
-export default function normalizeField< Item >(
- field: Field< Item >
-): NormalizedField< Item > {
- const getValue = field.getValue || getValueFromId( field.id );
- const setValue = field.setValue || setValueFromId( field.id );
+const isValid: Rules< any > = {
+ elements: true,
+ custom: ( item: any, normalizedField ) => {
+ const value = normalizedField.getValue( { item } );
- const sort = ( a: any, b: any, direction: SortDirection ) => {
- const valueA = getValue( { item: a } );
- const valueB = getValue( { item: b } );
- const boolA = Boolean( valueA );
- const boolB = Boolean( valueB );
-
- if ( boolA === boolB ) {
- return 0;
- }
-
- // In ascending order, false comes before true
- if ( direction === 'asc' ) {
- return boolA ? 1 : -1;
+ if (
+ ! [ undefined, '', null ].includes( value ) &&
+ ! [ true, false ].includes( value )
+ ) {
+ return __( 'Value must be true, false, or undefined' );
}
- // In descending order, true comes before false
- return boolA ? -1 : 1;
- };
-
- const isValid: Rules< Item > = {
- elements: true,
- custom: ( item: any, normalizedField ) => {
- const value = normalizedField.getValue( { item } );
+ return null;
+ },
+};
- if (
- ! [ undefined, '', null ].includes( value ) &&
- ! [ true, false ].includes( value )
- ) {
- return __( 'Value must be true, false, or undefined' );
- }
+const sort = ( a: any, b: any, direction: SortDirection ) => {
+ const boolA = Boolean( a );
+ const boolB = Boolean( b );
- return null;
- },
- };
-
- const defaultOperators: Operator[] = [ OPERATOR_IS, OPERATOR_IS_NOT ];
+ if ( boolA === boolB ) {
+ return 0;
+ }
- const validOperators: Operator[] = [ OPERATOR_IS, OPERATOR_IS_NOT ];
+ // In ascending order, false comes before true
+ if ( direction === 'asc' ) {
+ return boolA ? 1 : -1;
+ }
- return {
- id: field.id,
- type: 'boolean',
- label: field.label || field.id,
- header: field.header || field.label || field.id,
- description: field.description,
- placeholder: field.placeholder,
- getValue,
- setValue,
- elements: field.elements,
- getElements: field.getElements,
- hasElements: hasElements( field ),
- render: field.render ?? render,
- Edit: getControl( field, 'checkbox' ),
- sort: field.sort ?? sort,
- isValid: {
- ...isValid,
- ...field.isValid,
- },
- isVisible: field.isVisible,
- enableSorting: field.enableSorting ?? true,
- enableGlobalSearch: field.enableGlobalSearch ?? false,
- enableHiding: field.enableHiding ?? true,
- readOnly: field.readOnly ?? false,
- filterBy: getFilterBy( field, defaultOperators, validOperators ),
- format: {},
- };
-}
+ // In descending order, true comes before false
+ return boolA ? -1 : 1;
+};
+
+export default {
+ type: 'boolean',
+ render,
+ Edit: 'checkbox',
+ sort,
+ isValid,
+ enableSorting: true,
+ enableGlobalSearch: false,
+ defaultOperators: [ OPERATOR_IS, OPERATOR_IS_NOT ],
+ validOperators: [ OPERATOR_IS, OPERATOR_IS_NOT ],
+ getFormat: () => ( {} ),
+} satisfies FieldType< any >;
diff --git a/packages/dataviews/src/field-types/color.tsx b/packages/dataviews/src/field-types/color.tsx
index 907c62f8ee0620..2aed013d600bd7 100644
--- a/packages/dataviews/src/field-types/color.tsx
+++ b/packages/dataviews/src/field-types/color.tsx
@@ -11,14 +11,8 @@ import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
*/
-import type {
- DataViewRenderFieldProps,
- Field,
- NormalizedField,
- Operator,
- Rules,
- SortDirection,
-} from '../types';
+import type { DataViewRenderFieldProps, Rules, SortDirection } from '../types';
+import type { FieldType } from '../types/private';
import RenderFromElements from './utils/render-from-elements';
import {
OPERATOR_IS,
@@ -26,11 +20,6 @@ import {
OPERATOR_IS_NONE,
OPERATOR_IS_NOT,
} from '../constants';
-import { getControl } from '../dataform-controls';
-import hasElements from './utils/has-elements';
-import getValueFromId from './utils/get-value-from-id';
-import setValueFromId from './utils/set-value-from-id';
-import getFilterBy from './utils/get-filter-by';
function render( { item, field }: DataViewRenderFieldProps< any > ) {
if ( field.hasElements ) {
@@ -61,90 +50,64 @@ function render( { item, field }: DataViewRenderFieldProps< any > ) {
);
}
-export default function normalizeField< Item >(
- field: Field< Item >
-): NormalizedField< Item > {
- const getValue = field.getValue || getValueFromId( field.id );
- const setValue = field.setValue || setValueFromId( field.id );
+const isValid: Rules< any > = {
+ elements: true,
+ custom: ( item: any, normalizedField ) => {
+ const value = normalizedField.getValue( { item } );
- const sort = ( valueA: any, valueB: any, direction: SortDirection ) => {
- // Convert colors to HSL for better sorting
- const colorA = colord( valueA );
- const colorB = colord( valueB );
-
- if ( ! colorA.isValid() && ! colorB.isValid() ) {
- return 0;
- }
- if ( ! colorA.isValid() ) {
- return direction === 'asc' ? 1 : -1;
- }
- if ( ! colorB.isValid() ) {
- return direction === 'asc' ? -1 : 1;
- }
-
- // Sort by hue, then saturation, then lightness
- const hslA = colorA.toHsl();
- const hslB = colorB.toHsl();
-
- if ( hslA.h !== hslB.h ) {
- return direction === 'asc' ? hslA.h - hslB.h : hslB.h - hslA.h;
- }
- if ( hslA.s !== hslB.s ) {
- return direction === 'asc' ? hslA.s - hslB.s : hslB.s - hslA.s;
+ if (
+ ! [ undefined, '', null ].includes( value ) &&
+ ! colord( value ).isValid()
+ ) {
+ return __( 'Value must be a valid color.' );
}
- return direction === 'asc' ? hslA.l - hslB.l : hslB.l - hslA.l;
- };
- const isValid: Rules< Item > = {
- elements: true,
- custom: ( item: any, normalizedField ) => {
- const value = normalizedField.getValue( { item } );
+ return null;
+ },
+};
- if (
- ! [ undefined, '', null ].includes( value ) &&
- ! colord( value ).isValid()
- ) {
- return __( 'Value must be a valid color.' );
- }
+const sort = ( a: any, b: any, direction: SortDirection ) => {
+ // Convert colors to HSL for better sorting
+ const colorA = colord( a );
+ const colorB = colord( b );
- return null;
- },
- };
+ if ( ! colorA.isValid() && ! colorB.isValid() ) {
+ return 0;
+ }
+ if ( ! colorA.isValid() ) {
+ return direction === 'asc' ? 1 : -1;
+ }
+ if ( ! colorB.isValid() ) {
+ return direction === 'asc' ? -1 : 1;
+ }
- const defaultOperators: Operator[] = [ OPERATOR_IS_ANY, OPERATOR_IS_NONE ];
+ // Sort by hue, then saturation, then lightness
+ const hslA = colorA.toHsl();
+ const hslB = colorB.toHsl();
- const validOperators: Operator[] = [
+ if ( hslA.h !== hslB.h ) {
+ return direction === 'asc' ? hslA.h - hslB.h : hslB.h - hslA.h;
+ }
+ if ( hslA.s !== hslB.s ) {
+ return direction === 'asc' ? hslA.s - hslB.s : hslB.s - hslA.s;
+ }
+ return direction === 'asc' ? hslA.l - hslB.l : hslB.l - hslA.l;
+};
+
+export default {
+ type: 'color',
+ render,
+ Edit: 'color',
+ sort,
+ isValid,
+ enableSorting: true,
+ enableGlobalSearch: false,
+ defaultOperators: [ OPERATOR_IS_ANY, OPERATOR_IS_NONE ],
+ validOperators: [
OPERATOR_IS,
OPERATOR_IS_NOT,
OPERATOR_IS_ANY,
OPERATOR_IS_NONE,
- ];
-
- return {
- id: field.id,
- type: 'color',
- label: field.label || field.id,
- header: field.header || field.label || field.id,
- description: field.description,
- placeholder: field.placeholder,
- getValue,
- setValue,
- elements: field.elements,
- getElements: field.getElements,
- hasElements: hasElements( field ),
- render: field.render ?? render,
- Edit: getControl( field, 'color' ),
- sort: field.sort ?? sort,
- isValid: {
- ...isValid,
- ...field.isValid,
- },
- isVisible: field.isVisible,
- enableSorting: field.enableSorting ?? true,
- enableGlobalSearch: field.enableGlobalSearch ?? false,
- enableHiding: field.enableHiding ?? true,
- readOnly: field.readOnly ?? false,
- filterBy: getFilterBy( field, defaultOperators, validOperators ),
- format: {},
- };
-}
+ ],
+ getFormat: () => ( {} ),
+} satisfies FieldType< any >;
diff --git a/packages/dataviews/src/field-types/date.tsx b/packages/dataviews/src/field-types/date.tsx
index dcd8b7d513e08c..48aacaa28eb845 100644
--- a/packages/dataviews/src/field-types/date.tsx
+++ b/packages/dataviews/src/field-types/date.tsx
@@ -10,11 +10,9 @@ import type {
DataViewRenderFieldProps,
Field,
FormatDate,
- NormalizedField,
- Operator,
- Rules,
SortDirection,
} from '../types';
+import type { FieldType } from '../types/private';
import RenderFromElements from './utils/render-from-elements';
import {
OPERATOR_ON,
@@ -28,13 +26,8 @@ import {
OPERATOR_BETWEEN,
DAYS_OF_WEEK,
} from '../constants';
-import { getControl } from '../dataform-controls';
-import hasElements from './utils/has-elements';
-import getValueFromId from './utils/get-value-from-id';
-import setValueFromId from './utils/set-value-from-id';
-import getFilterBy from './utils/get-filter-by';
-function getFormat( field: Field< any > ): Required< FormatDate > {
+function getFormat< Item >( field: Field< Item > ): Required< FormatDate > {
return {
date:
field.format?.date !== undefined &&
@@ -74,26 +67,25 @@ function render( { item, field }: DataViewRenderFieldProps< any > ) {
return dateI18n( format.date, getDate( value ) );
}
-export default function normalizeField< Item >(
- field: Field< Item >
-): NormalizedField< Item > {
- const getValue = field.getValue || getValueFromId( field.id );
- const setValue = field.setValue || setValueFromId( field.id );
- const isValid: Rules< Item > = {
- elements: true,
- custom: () => null,
- };
+const sort = ( a: any, b: any, direction: SortDirection ) => {
+ const timeA = new Date( a ).getTime();
+ const timeB = new Date( b ).getTime();
- const sort = ( a: Item, b: Item, direction: SortDirection ) => {
- const valueA = getValue( { item: a } );
- const valueB = getValue( { item: b } );
- const timeA = new Date( valueA ).getTime();
- const timeB = new Date( valueB ).getTime();
+ return direction === 'asc' ? timeA - timeB : timeB - timeA;
+};
- return direction === 'asc' ? timeA - timeB : timeB - timeA;
- };
-
- const defaultOperators: Operator[] = [
+export default {
+ type: 'date',
+ render,
+ Edit: 'date',
+ sort,
+ isValid: {
+ elements: true,
+ custom: () => null,
+ },
+ enableSorting: true,
+ enableGlobalSearch: false,
+ defaultOperators: [
OPERATOR_ON,
OPERATOR_NOT_ON,
OPERATOR_BEFORE,
@@ -103,9 +95,8 @@ export default function normalizeField< Item >(
OPERATOR_IN_THE_PAST,
OPERATOR_OVER,
OPERATOR_BETWEEN,
- ];
-
- const validOperators: Operator[] = [
+ ],
+ validOperators: [
OPERATOR_ON,
OPERATOR_NOT_ON,
OPERATOR_BEFORE,
@@ -115,33 +106,6 @@ export default function normalizeField< Item >(
OPERATOR_IN_THE_PAST,
OPERATOR_OVER,
OPERATOR_BETWEEN,
- ];
-
- return {
- id: field.id,
- type: 'date',
- label: field.label || field.id,
- header: field.header || field.label || field.id,
- description: field.description,
- placeholder: field.placeholder,
- getValue,
- setValue,
- elements: field.elements,
- getElements: field.getElements,
- hasElements: hasElements( field ),
- render: field.render ?? render,
- Edit: getControl( field, 'date' ),
- sort: field.sort ?? sort,
- isValid: {
- ...isValid,
- ...field.isValid,
- },
- isVisible: field.isVisible,
- enableSorting: field.enableSorting ?? true,
- enableGlobalSearch: field.enableGlobalSearch ?? false,
- enableHiding: field.enableHiding ?? true,
- readOnly: field.readOnly ?? false,
- filterBy: getFilterBy( field, defaultOperators, validOperators ),
- format: getFormat( field ),
- };
-}
+ ],
+ getFormat,
+} satisfies FieldType< any >;
diff --git a/packages/dataviews/src/field-types/datetime.tsx b/packages/dataviews/src/field-types/datetime.tsx
index bdf424c1ec57a3..6edd6eb74e66cb 100644
--- a/packages/dataviews/src/field-types/datetime.tsx
+++ b/packages/dataviews/src/field-types/datetime.tsx
@@ -1,14 +1,8 @@
/**
* Internal dependencies
*/
-import type {
- DataViewRenderFieldProps,
- Field,
- NormalizedField,
- Operator,
- Rules,
- SortDirection,
-} from '../types';
+import type { DataViewRenderFieldProps, SortDirection } from '../types';
+import type { FieldType } from '../types/private';
import RenderFromElements from './utils/render-from-elements';
import parseDateTime from './utils/parse-date-time';
import {
@@ -21,11 +15,6 @@ import {
OPERATOR_IN_THE_PAST,
OPERATOR_OVER,
} from '../constants';
-import { getControl } from '../dataform-controls';
-import hasElements from './utils/has-elements';
-import getValueFromId from './utils/get-value-from-id';
-import setValueFromId from './utils/set-value-from-id';
-import getFilterBy from './utils/get-filter-by';
function render( { item, field }: DataViewRenderFieldProps< any > ) {
if ( field.elements ) {
@@ -45,26 +34,25 @@ function render( { item, field }: DataViewRenderFieldProps< any > ) {
}
}
-export default function normalizeField< Item >(
- field: Field< Item >
-): NormalizedField< Item > {
- const getValue = field.getValue || getValueFromId( field.id );
- const setValue = field.setValue || setValueFromId( field.id );
- const isValid: Rules< Item > = {
- elements: true,
- custom: () => null,
- };
+const sort = ( a: any, b: any, direction: SortDirection ) => {
+ const timeA = new Date( a ).getTime();
+ const timeB = new Date( b ).getTime();
- const sort = ( a: Item, b: Item, direction: SortDirection ) => {
- const valueA = getValue( { item: a } );
- const valueB = getValue( { item: b } );
- const timeA = new Date( valueA ).getTime();
- const timeB = new Date( valueB ).getTime();
+ return direction === 'asc' ? timeA - timeB : timeB - timeA;
+};
- return direction === 'asc' ? timeA - timeB : timeB - timeA;
- };
-
- const defaultOperators: Operator[] = [
+export default {
+ type: 'datetime',
+ render,
+ Edit: 'datetime',
+ sort,
+ isValid: {
+ elements: true,
+ custom: () => null,
+ },
+ enableSorting: true,
+ enableGlobalSearch: false,
+ defaultOperators: [
OPERATOR_ON,
OPERATOR_NOT_ON,
OPERATOR_BEFORE,
@@ -73,9 +61,8 @@ export default function normalizeField< Item >(
OPERATOR_AFTER_INC,
OPERATOR_IN_THE_PAST,
OPERATOR_OVER,
- ];
-
- const validOperators: Operator[] = [
+ ],
+ validOperators: [
OPERATOR_ON,
OPERATOR_NOT_ON,
OPERATOR_BEFORE,
@@ -84,33 +71,6 @@ export default function normalizeField< Item >(
OPERATOR_AFTER_INC,
OPERATOR_IN_THE_PAST,
OPERATOR_OVER,
- ];
-
- return {
- id: field.id,
- type: 'datetime',
- label: field.label || field.id,
- header: field.header || field.label || field.id,
- description: field.description,
- placeholder: field.placeholder,
- getValue,
- setValue,
- elements: field.elements,
- getElements: field.getElements,
- hasElements: hasElements( field ),
- render: field.render ?? render,
- Edit: getControl( field, 'datetime' ),
- sort: field.sort ?? sort,
- isValid: {
- ...isValid,
- ...field.isValid,
- },
- isVisible: field.isVisible,
- enableSorting: field.enableSorting ?? true,
- enableGlobalSearch: field.enableGlobalSearch ?? false,
- enableHiding: field.enableHiding ?? true,
- readOnly: field.readOnly ?? false,
- filterBy: getFilterBy( field, defaultOperators, validOperators ),
- format: {},
- };
-}
+ ],
+ getFormat: () => ( {} ),
+} satisfies FieldType< any >;
diff --git a/packages/dataviews/src/field-types/email.tsx b/packages/dataviews/src/field-types/email.tsx
index ad4e03fa6b0f49..dfb1f85f3eea85 100644
--- a/packages/dataviews/src/field-types/email.tsx
+++ b/packages/dataviews/src/field-types/email.tsx
@@ -6,15 +6,8 @@ import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
*/
-import type {
- DataViewRenderFieldProps,
- Field,
- NormalizedField,
- Operator,
- Rules,
- SortDirection,
-} from '../types';
-import RenderFromElements from './utils/render-from-elements';
+import type { Rules } from '../types';
+import type { FieldType } from '../types/private';
import {
OPERATOR_IS,
OPERATOR_IS_ALL,
@@ -26,58 +19,40 @@ import {
OPERATOR_NOT_CONTAINS,
OPERATOR_STARTS_WITH,
} from '../constants';
-import { getControl } from '../dataform-controls';
-import hasElements from './utils/has-elements';
-import getValueFromId from './utils/get-value-from-id';
-import setValueFromId from './utils/set-value-from-id';
-import getFilterBy from './utils/get-filter-by';
+import render from './utils/render-default';
+import sort from './utils/sort-text';
// Email validation regex based on HTML5 spec
// https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address
const emailRegex =
/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
-function render( { item, field }: DataViewRenderFieldProps< any > ) {
- return field.hasElements ? (
-
- ) : (
- field.getValue( { item } )
- );
-}
+const isValid: Rules< any > = {
+ elements: true,
+ custom: ( item: any, normalizedField ) => {
+ const value = normalizedField.getValue( { item } );
-export default function normalizeField< Item >(
- field: Field< Item >
-): NormalizedField< Item > {
- const getValue = field.getValue || getValueFromId( field.id );
- const setValue = field.setValue || setValueFromId( field.id );
+ if (
+ ! [ undefined, '', null ].includes( value ) &&
+ ! emailRegex.test( value )
+ ) {
+ return __( 'Value must be a valid email address.' );
+ }
- const sort = ( a: any, b: any, direction: SortDirection ) => {
- const valueA = getValue( { item: a } );
- const valueB = getValue( { item: b } );
- return direction === 'asc'
- ? valueA.localeCompare( valueB )
- : valueB.localeCompare( valueA );
- };
+ return null;
+ },
+};
- const isValid: Rules< Item > = {
- elements: true,
- custom: ( item: any, normalizedField ) => {
- const value = normalizedField.getValue( { item } );
-
- if (
- ! [ undefined, '', null ].includes( value ) &&
- ! emailRegex.test( value )
- ) {
- return __( 'Value must be a valid email address.' );
- }
-
- return null;
- },
- };
-
- const defaultOperators: Operator[] = [ OPERATOR_IS_ANY, OPERATOR_IS_NONE ];
-
- const validOperators: Operator[] = [
+export default {
+ type: 'email',
+ render,
+ Edit: 'email',
+ sort,
+ isValid,
+ enableSorting: true,
+ enableGlobalSearch: false,
+ defaultOperators: [ OPERATOR_IS_ANY, OPERATOR_IS_NONE ],
+ validOperators: [
OPERATOR_IS,
OPERATOR_IS_NOT,
OPERATOR_CONTAINS,
@@ -88,33 +63,6 @@ export default function normalizeField< Item >(
OPERATOR_IS_NONE,
OPERATOR_IS_ALL,
OPERATOR_IS_NOT_ALL,
- ];
-
- return {
- id: field.id,
- type: 'email',
- label: field.label || field.id,
- header: field.header || field.label || field.id,
- description: field.description,
- placeholder: field.placeholder,
- getValue,
- setValue,
- elements: field.elements,
- getElements: field.getElements,
- hasElements: hasElements( field ),
- render: field.render ?? render,
- Edit: getControl( field, 'email' ),
- sort: field.sort ?? sort,
- isValid: {
- ...isValid,
- ...field.isValid,
- },
- isVisible: field.isVisible,
- enableSorting: field.enableSorting ?? true,
- enableGlobalSearch: field.enableGlobalSearch ?? false,
- enableHiding: field.enableHiding ?? true,
- readOnly: field.readOnly ?? false,
- filterBy: getFilterBy( field, defaultOperators, validOperators ),
- format: {},
- };
-}
+ ],
+ getFormat: () => ( {} ),
+} satisfies FieldType< any >;
diff --git a/packages/dataviews/src/field-types/index.tsx b/packages/dataviews/src/field-types/index.tsx
index 4534a2ff3e6d6f..70ced3904843b8 100644
--- a/packages/dataviews/src/field-types/index.tsx
+++ b/packages/dataviews/src/field-types/index.tsx
@@ -2,13 +2,17 @@
* Internal dependencies
*/
import type {
- DataViewRenderFieldProps,
Field,
- FieldType,
+ FieldTypeName,
NormalizedField,
- Operator,
SortDirection,
} from '../types';
+import type { FieldType } from '../types/private';
+import { getControl } from '../dataform-controls';
+import getFilterBy from './utils/get-filter-by';
+import getValueFromId from './utils/get-value-from-id';
+import hasElements from './utils/has-elements';
+import setValueFromId from './utils/set-value-from-id';
import { default as email } from './email';
import { default as integer } from './integer';
import { default as number } from './number';
@@ -22,143 +26,93 @@ import { default as password } from './password';
import { default as telephone } from './telephone';
import { default as color } from './color';
import { default as url } from './url';
-import RenderFromElements from './utils/render-from-elements';
-import { ALL_OPERATORS, OPERATOR_IS, OPERATOR_IS_NOT } from '../constants';
-import { getControl } from '../dataform-controls';
-import hasElements from './utils/has-elements';
-import getValueFromId from './utils/get-value-from-id';
-import setValueFromId from './utils/set-value-from-id';
-import getFilterBy from './utils/get-filter-by';
-
-function normalizeField< Item >(
- field: Field< Item >
-): NormalizedField< Item > {
- const getValue = field.getValue || getValueFromId( field.id );
- const setValue = field.setValue || setValueFromId( field.id );
-
- const isValid = {
- elements: true,
- custom: () => null,
- };
-
- const sort = ( a: any, b: any, direction: SortDirection ) => {
- const valueA = getValue( { item: a } );
- const valueB = getValue( { item: b } );
-
- if ( typeof valueA === 'number' && typeof valueB === 'number' ) {
- return direction === 'asc' ? valueA - valueB : valueB - valueA;
- }
-
- return direction === 'asc'
- ? valueA.localeCompare( valueB )
- : valueB.localeCompare( valueA );
- };
-
- const render = ( {
- item,
- field: normalizedField,
- }: DataViewRenderFieldProps< Item > ) => {
- return normalizedField.hasElements ? (
-
- ) : (
- normalizedField.getValue( { item } )
- );
- };
-
- const defaultOperators: Operator[] = [ OPERATOR_IS, OPERATOR_IS_NOT ];
- const validOperators: Operator[] = ALL_OPERATORS;
-
- return {
- id: field.id,
- // type — it does not have a type
- label: field.label || field.id,
- header: field.header || field.label || field.id,
- description: field.description,
- placeholder: field.placeholder,
- getValue,
- setValue,
- elements: field.elements,
- getElements: field.getElements,
- hasElements: hasElements( field ),
- render: field.render ?? render,
- Edit: getControl( field, null ),
- sort: field.sort ?? sort,
- isValid: {
- ...isValid,
- ...field.isValid,
- },
- isVisible: field.isVisible,
- enableSorting: field.enableSorting ?? true,
- enableGlobalSearch: field.enableGlobalSearch ?? false,
- enableHiding: field.enableHiding ?? true,
- readOnly: field.readOnly ?? false,
- filterBy: getFilterBy( field, defaultOperators, validOperators ),
- format: {},
- };
-}
+import { default as noType } from './no-type';
/**
*
- * @param {FieldType} type The field type definition to get.
+ * @param {FieldTypeName} type The field type definition to get.
*
* @return A field type definition.
*/
-export default function getNormalizeFieldFunction< Item >(
- type?: FieldType
-): ( field: Field< Item > ) => NormalizedField< Item > {
- if ( 'email' === type ) {
- return email;
- }
-
- if ( 'integer' === type ) {
- return integer;
- }
-
- if ( 'number' === type ) {
- return number;
- }
-
- if ( 'text' === type ) {
- return text;
- }
-
- if ( 'datetime' === type ) {
- return datetime;
- }
-
- if ( 'date' === type ) {
- return date;
- }
-
- if ( 'boolean' === type ) {
- return boolean;
- }
-
- if ( 'media' === type ) {
- return media;
- }
-
- if ( 'array' === type ) {
- return array;
- }
-
- if ( 'password' === type ) {
- return password;
- }
-
- if ( 'telephone' === type ) {
- return telephone;
- }
-
- if ( 'color' === type ) {
- return color;
- }
-
- if ( 'url' === type ) {
- return url;
+function getFieldTypeByName< Item >( type?: FieldTypeName ): FieldType< Item > {
+ const found = [
+ email,
+ integer,
+ number,
+ text,
+ datetime,
+ date,
+ boolean,
+ media,
+ array,
+ password,
+ telephone,
+ color,
+ url,
+ ].find( ( fieldType ) => fieldType?.type === type );
+
+ if ( !! found ) {
+ return found;
}
// This is a fallback for fields that don't provide a type.
- // It can be removed when the field.type is mandatory.
- return normalizeField;
+ // It can be removed when/if the field.type becomes mandatory.
+ return noType;
+}
+
+/**
+ * Apply default values and normalize the fields config.
+ *
+ * @param fields Fields config.
+ * @return Normalized fields config.
+ */
+export default function normalizeFields< Item >(
+ fields: Field< Item >[]
+): NormalizedField< Item >[] {
+ return fields.map( ( field ) => {
+ const defaultProps = getFieldTypeByName< Item >( field.type );
+
+ const getValue = field.getValue || getValueFromId( field.id );
+ const sort = function ( a: any, b: any, direction: SortDirection ) {
+ const aValue = getValue( { item: a } );
+ const bValue = getValue( { item: b } );
+ return field.sort
+ ? field.sort( aValue, bValue, direction )
+ : defaultProps.sort( aValue, bValue, direction );
+ };
+
+ return {
+ id: field.id,
+ label: field.label || field.id,
+ header: field.header || field.label || field.id,
+ description: field.description,
+ placeholder: field.placeholder,
+ getValue,
+ setValue: field.setValue || setValueFromId( field.id ),
+ elements: field.elements,
+ getElements: field.getElements,
+ hasElements: hasElements( field ),
+ isVisible: field.isVisible,
+ enableHiding: field.enableHiding ?? true,
+ readOnly: field.readOnly ?? false,
+ // The type provides defaults for the following props
+ type: defaultProps.type,
+ render: field.render ?? defaultProps.render,
+ Edit: getControl( field, defaultProps.Edit ),
+ sort,
+ enableSorting: field.enableSorting ?? defaultProps.enableSorting,
+ enableGlobalSearch:
+ field.enableGlobalSearch ?? defaultProps.enableGlobalSearch,
+ isValid: {
+ ...defaultProps.isValid,
+ ...field.isValid,
+ },
+ filterBy: getFilterBy(
+ field,
+ defaultProps.defaultOperators,
+ defaultProps.validOperators
+ ),
+ format: defaultProps.getFormat( field ),
+ };
+ } );
}
diff --git a/packages/dataviews/src/field-types/integer.tsx b/packages/dataviews/src/field-types/integer.tsx
index 19864a1fab7ae8..96b9d1e17b8dd1 100644
--- a/packages/dataviews/src/field-types/integer.tsx
+++ b/packages/dataviews/src/field-types/integer.tsx
@@ -6,15 +6,8 @@ import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
*/
-import type {
- DataViewRenderFieldProps,
- Field,
- NormalizedField,
- Operator,
- Rules,
- SortDirection,
-} from '../types';
-import RenderFromElements from './utils/render-from-elements';
+import type { Rules } from '../types';
+import type { FieldType } from '../types/private';
import {
OPERATOR_IS,
OPERATOR_IS_NOT,
@@ -28,47 +21,33 @@ import {
OPERATOR_IS_NOT_ALL,
OPERATOR_BETWEEN,
} from '../constants';
-import { getControl } from '../dataform-controls';
-import hasElements from './utils/has-elements';
-import getValueFromId from './utils/get-value-from-id';
-import setValueFromId from './utils/set-value-from-id';
-import getFilterBy from './utils/get-filter-by';
+import render from './utils/render-default';
+import sort from './utils/sort-number';
-function render( { item, field }: DataViewRenderFieldProps< any > ) {
- return field.hasElements ? (
-
- ) : (
- field.getValue( { item } )
- );
-}
+const isValid: Rules< any > = {
+ elements: true,
+ custom: ( item: any, normalizedField ) => {
+ const value = normalizedField.getValue( { item } );
+ if (
+ ! [ undefined, '', null ].includes( value ) &&
+ ! Number.isInteger( value )
+ ) {
+ return __( 'Value must be an integer.' );
+ }
-export default function normalizeField< Item >(
- field: Field< Item >
-): NormalizedField< Item > {
- const getValue = field.getValue || getValueFromId( field.id );
- const setValue = field.setValue || setValueFromId( field.id );
- const isValid: Rules< Item > = {
- elements: true,
- custom: ( item: any, normalizedField ) => {
- const value = normalizedField.getValue( { item } );
- if (
- ! [ undefined, '', null ].includes( value ) &&
- ! Number.isInteger( value )
- ) {
- return __( 'Value must be an integer.' );
- }
+ return null;
+ },
+};
- return null;
- },
- };
-
- const sort = ( a: Item, b: Item, direction: SortDirection ) => {
- const valueA = getValue( { item: a } );
- const valueB = getValue( { item: b } );
- return direction === 'asc' ? valueA - valueB : valueB - valueA;
- };
-
- const defaultOperators: Operator[] = [
+export default {
+ type: 'integer',
+ render,
+ Edit: 'integer',
+ sort,
+ isValid,
+ enableSorting: true,
+ enableGlobalSearch: false,
+ defaultOperators: [
OPERATOR_IS,
OPERATOR_IS_NOT,
OPERATOR_LESS_THAN,
@@ -76,9 +55,8 @@ export default function normalizeField< Item >(
OPERATOR_LESS_THAN_OR_EQUAL,
OPERATOR_GREATER_THAN_OR_EQUAL,
OPERATOR_BETWEEN,
- ];
-
- const validOperators: Operator[] = [
+ ],
+ validOperators: [
// Single-selection
OPERATOR_IS,
OPERATOR_IS_NOT,
@@ -92,33 +70,6 @@ export default function normalizeField< Item >(
OPERATOR_IS_NONE,
OPERATOR_IS_ALL,
OPERATOR_IS_NOT_ALL,
- ];
-
- return {
- id: field.id,
- type: 'integer',
- label: field.label || field.id,
- header: field.header || field.label || field.id,
- description: field.description,
- placeholder: field.placeholder,
- getValue,
- setValue,
- elements: field.elements,
- getElements: field.getElements,
- hasElements: hasElements( field ),
- render: field.render ?? render,
- Edit: getControl( field, 'integer' ),
- sort: field.sort ?? sort,
- isValid: {
- ...isValid,
- ...field.isValid,
- },
- isVisible: field.isVisible,
- enableSorting: field.enableSorting ?? true,
- enableGlobalSearch: field.enableGlobalSearch ?? false,
- enableHiding: field.enableHiding ?? true,
- readOnly: field.readOnly ?? false,
- filterBy: getFilterBy( field, defaultOperators, validOperators ),
- format: {},
- };
-}
+ ],
+ getFormat: () => ( {} ),
+} satisfies FieldType< any >;
diff --git a/packages/dataviews/src/field-types/media.tsx b/packages/dataviews/src/field-types/media.tsx
index 6e2ba665110189..9e668b7ca22437 100644
--- a/packages/dataviews/src/field-types/media.tsx
+++ b/packages/dataviews/src/field-types/media.tsx
@@ -1,55 +1,20 @@
/**
* Internal dependencies
*/
-import type { Field, NormalizedField, Rules } from '../types';
-import { getControl } from '../dataform-controls';
-import hasElements from './utils/has-elements';
-import getValueFromId from './utils/get-value-from-id';
-import setValueFromId from './utils/set-value-from-id';
+import type { FieldType } from '../types/private';
-function sort() {
- return 0;
-}
-
-function render() {
- return null;
-}
-
-export default function normalizeField< Item >(
- field: Field< Item >
-): NormalizedField< Item > {
- const getValue = field.getValue || getValueFromId( field.id );
- const setValue = field.setValue || setValueFromId( field.id );
- const isValid: Rules< Item > = {
+export default {
+ type: 'media',
+ render: () => null,
+ Edit: null,
+ sort: () => 0,
+ isValid: {
elements: true,
custom: () => null,
- };
-
- return {
- id: field.id,
- type: 'media',
- label: field.label || field.id,
- header: field.header || field.label || field.id,
- description: field.description,
- placeholder: field.placeholder,
- getValue,
- setValue,
- elements: field.elements,
- getElements: field.getElements,
- hasElements: hasElements( field ),
- render: field.render ?? render,
- Edit: getControl( field, null ),
- sort: field.sort ?? sort,
- isValid: {
- ...isValid,
- ...field.isValid,
- },
- isVisible: field.isVisible,
- enableSorting: field.enableSorting ?? false,
- enableGlobalSearch: field.enableGlobalSearch ?? false,
- enableHiding: field.enableHiding ?? true,
- readOnly: field.readOnly ?? false,
- filterBy: false,
- format: {},
- };
-}
+ },
+ enableSorting: false,
+ enableGlobalSearch: false,
+ defaultOperators: [],
+ validOperators: [],
+ getFormat: () => ( {} ),
+} satisfies FieldType< any >;
diff --git a/packages/dataviews/src/field-types/no-type.tsx b/packages/dataviews/src/field-types/no-type.tsx
new file mode 100644
index 00000000000000..f9c978559b9e59
--- /dev/null
+++ b/packages/dataviews/src/field-types/no-type.tsx
@@ -0,0 +1,33 @@
+/**
+ * Internal dependencies
+ */
+import type { SortDirection } from '../types';
+import type { FieldType } from '../types/private';
+import { ALL_OPERATORS, OPERATOR_IS, OPERATOR_IS_NOT } from '../constants';
+import render from './utils/render-default';
+import sortText from './utils/sort-text';
+import sortNumber from './utils/sort-number';
+
+const sort = ( a: any, b: any, direction: SortDirection ) => {
+ if ( typeof a === 'number' && typeof b === 'number' ) {
+ return sortNumber( a, b, direction );
+ }
+
+ return sortText( a, b, direction );
+};
+
+export default {
+ // type: no type for this one
+ render,
+ Edit: null,
+ sort,
+ isValid: {
+ elements: true,
+ custom: () => null,
+ },
+ enableSorting: true,
+ enableGlobalSearch: false,
+ defaultOperators: [ OPERATOR_IS, OPERATOR_IS_NOT ],
+ validOperators: ALL_OPERATORS,
+ getFormat: () => ( {} ),
+} satisfies FieldType< any >;
diff --git a/packages/dataviews/src/field-types/number.tsx b/packages/dataviews/src/field-types/number.tsx
index ca6d54fbeb352e..15e5ea29870c04 100644
--- a/packages/dataviews/src/field-types/number.tsx
+++ b/packages/dataviews/src/field-types/number.tsx
@@ -6,14 +6,8 @@ import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
*/
-import type {
- DataViewRenderFieldProps,
- Field,
- NormalizedField,
- Operator,
- Rules,
- SortDirection,
-} from '../types';
+import type { DataViewRenderFieldProps, Rules } from '../types';
+import type { FieldType } from '../types/private';
import {
OPERATOR_IS,
OPERATOR_IS_NOT,
@@ -28,11 +22,7 @@ import {
OPERATOR_BETWEEN,
} from '../constants';
import RenderFromElements from './utils/render-from-elements';
-import { getControl } from '../dataform-controls';
-import hasElements from './utils/has-elements';
-import getValueFromId from './utils/get-value-from-id';
-import setValueFromId from './utils/set-value-from-id';
-import getFilterBy from './utils/get-filter-by';
+import sort from './utils/sort-number';
function isEmpty( value: unknown ): value is '' | undefined | null {
return value === '' || value === undefined || value === null;
@@ -51,31 +41,28 @@ function render( { item, field }: DataViewRenderFieldProps< any > ) {
return null;
}
-export default function normalizeField< Item >(
- field: Field< Item >
-): NormalizedField< Item > {
- const getValue = field.getValue || getValueFromId( field.id );
- const setValue = field.setValue || setValueFromId( field.id );
- const isValid: Rules< Item > = {
- elements: true,
- custom: ( item: any, normalizedField ) => {
- const value = normalizedField.getValue( { item } );
+const isValid: Rules< any > = {
+ elements: true,
+ custom: ( item: any, normalizedField ) => {
+ const value = normalizedField.getValue( { item } );
- if ( ! isEmpty( value ) && ! Number.isFinite( value ) ) {
- return __( 'Value must be a number.' );
- }
+ if ( ! isEmpty( value ) && ! Number.isFinite( value ) ) {
+ return __( 'Value must be a number.' );
+ }
- return null;
- },
- };
+ return null;
+ },
+};
- const sort = ( a: Item, b: Item, direction: SortDirection ) => {
- const valueA = getValue( { item: a } );
- const valueB = getValue( { item: b } );
- return direction === 'asc' ? valueA - valueB : valueB - valueA;
- };
-
- const defaultOperators: Operator[] = [
+export default {
+ type: 'number',
+ render,
+ Edit: 'number',
+ sort,
+ isValid,
+ enableSorting: true,
+ enableGlobalSearch: false,
+ defaultOperators: [
OPERATOR_IS,
OPERATOR_IS_NOT,
OPERATOR_LESS_THAN,
@@ -83,9 +70,8 @@ export default function normalizeField< Item >(
OPERATOR_LESS_THAN_OR_EQUAL,
OPERATOR_GREATER_THAN_OR_EQUAL,
OPERATOR_BETWEEN,
- ];
-
- const validOperators: Operator[] = [
+ ],
+ validOperators: [
// Single-selection
OPERATOR_IS,
OPERATOR_IS_NOT,
@@ -99,33 +85,6 @@ export default function normalizeField< Item >(
OPERATOR_IS_NONE,
OPERATOR_IS_ALL,
OPERATOR_IS_NOT_ALL,
- ];
-
- return {
- id: field.id,
- type: 'number',
- label: field.label || field.id,
- header: field.header || field.label || field.id,
- description: field.description,
- placeholder: field.placeholder,
- getValue,
- setValue,
- elements: field.elements,
- getElements: field.getElements,
- hasElements: hasElements( field ),
- render: field.render ?? render,
- Edit: getControl( field, 'number' ),
- sort: field.sort ?? sort,
- isValid: {
- ...isValid,
- ...field.isValid,
- },
- isVisible: field.isVisible,
- enableSorting: field.enableSorting ?? true,
- enableGlobalSearch: field.enableGlobalSearch ?? false,
- enableHiding: field.enableHiding ?? true,
- readOnly: field.readOnly ?? false,
- filterBy: getFilterBy( field, defaultOperators, validOperators ),
- format: {},
- };
-}
+ ],
+ getFormat: () => ( {} ),
+} satisfies FieldType< any >;
diff --git a/packages/dataviews/src/field-types/password.tsx b/packages/dataviews/src/field-types/password.tsx
index ec8c5ea8dc5758..b091998e183026 100644
--- a/packages/dataviews/src/field-types/password.tsx
+++ b/packages/dataviews/src/field-types/password.tsx
@@ -1,24 +1,9 @@
/**
* Internal dependencies
*/
-import type {
- DataViewRenderFieldProps,
- Field,
- NormalizedField,
- Rules,
- SortDirection,
-} from '../types';
+import type { DataViewRenderFieldProps } from '../types';
+import type { FieldType } from '../types/private';
import RenderFromElements from './utils/render-from-elements';
-import { getControl } from '../dataform-controls';
-import hasElements from './utils/has-elements';
-import getValueFromId from './utils/get-value-from-id';
-import setValueFromId from './utils/set-value-from-id';
-
-/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
-function sort( _valueA: any, _valueB: any, _direction: SortDirection ) {
- // Passwords should not be sortable for security reasons
- return 0;
-}
function render( { item, field }: DataViewRenderFieldProps< any > ) {
return field.hasElements ? (
@@ -28,41 +13,18 @@ function render( { item, field }: DataViewRenderFieldProps< any > ) {
);
}
-export default function normalizeField< Item >(
- field: Field< Item >
-): NormalizedField< Item > {
- const getValue = field.getValue || getValueFromId( field.id );
- const setValue = field.setValue || setValueFromId( field.id );
- const isValid: Rules< Item > = {
+export default {
+ type: 'password',
+ render,
+ Edit: 'password',
+ sort: () => 0, // Passwords should not be sortable for security reasons
+ isValid: {
elements: true,
custom: () => null,
- };
-
- return {
- id: field.id,
- type: 'password',
- label: field.label || field.id,
- header: field.header || field.label || field.id,
- description: field.description,
- placeholder: field.placeholder,
- getValue,
- setValue,
- elements: field.elements,
- getElements: field.getElements,
- hasElements: hasElements( field ),
- render: field.render ?? render,
- Edit: getControl( field, 'password' ),
- sort: field.sort ?? sort,
- isValid: {
- ...isValid,
- ...field.isValid,
- },
- isVisible: field.isVisible,
- enableSorting: field.enableSorting ?? false,
- enableGlobalSearch: field.enableGlobalSearch ?? false,
- enableHiding: field.enableHiding ?? true,
- readOnly: field.readOnly ?? false,
- filterBy: false,
- format: {},
- };
-}
+ },
+ enableSorting: false,
+ enableGlobalSearch: false,
+ defaultOperators: [],
+ validOperators: [],
+ getFormat: () => ( {} ),
+} satisfies FieldType< any >;
diff --git a/packages/dataviews/src/field-types/telephone.tsx b/packages/dataviews/src/field-types/telephone.tsx
index 19d2040c820de0..545a324c34164d 100644
--- a/packages/dataviews/src/field-types/telephone.tsx
+++ b/packages/dataviews/src/field-types/telephone.tsx
@@ -1,15 +1,7 @@
/**
* Internal dependencies
*/
-import type {
- DataViewRenderFieldProps,
- Field,
- NormalizedField,
- Operator,
- Rules,
- SortDirection,
-} from '../types';
-import RenderFromElements from './utils/render-from-elements';
+import type { FieldType } from '../types/private';
import {
OPERATOR_IS,
OPERATOR_IS_ALL,
@@ -21,41 +13,22 @@ import {
OPERATOR_NOT_CONTAINS,
OPERATOR_STARTS_WITH,
} from '../constants';
-import { getControl } from '../dataform-controls';
-import hasElements from './utils/has-elements';
-import getValueFromId from './utils/get-value-from-id';
-import setValueFromId from './utils/set-value-from-id';
-import getFilterBy from './utils/get-filter-by';
+import render from './utils/render-default';
+import sort from './utils/sort-text';
-function render( { item, field }: DataViewRenderFieldProps< any > ) {
- return field.hasElements ? (
-
- ) : (
- field.getValue( { item } )
- );
-}
-
-export default function normalizeField< Item >(
- field: Field< Item >
-): NormalizedField< Item > {
- const getValue = field.getValue || getValueFromId( field.id );
- const setValue = field.setValue || setValueFromId( field.id );
- const isValid: Rules< Item > = {
+export default {
+ type: 'telephone',
+ render,
+ Edit: 'telephone',
+ sort,
+ isValid: {
elements: true,
custom: () => null,
- };
-
- const sort = ( a: any, b: any, direction: SortDirection ) => {
- const valueA = getValue( { item: a } );
- const valueB = getValue( { item: b } );
- return direction === 'asc'
- ? valueA.localeCompare( valueB )
- : valueB.localeCompare( valueA );
- };
-
- const defaultOperators: Operator[] = [ OPERATOR_IS_ANY, OPERATOR_IS_NONE ];
-
- const validOperators: Operator[] = [
+ },
+ enableSorting: true,
+ enableGlobalSearch: false,
+ defaultOperators: [ OPERATOR_IS_ANY, OPERATOR_IS_NONE ],
+ validOperators: [
OPERATOR_IS,
OPERATOR_IS_NOT,
OPERATOR_CONTAINS,
@@ -66,33 +39,6 @@ export default function normalizeField< Item >(
OPERATOR_IS_NONE,
OPERATOR_IS_ALL,
OPERATOR_IS_NOT_ALL,
- ];
-
- return {
- id: field.id,
- type: 'telephone',
- label: field.label || field.id,
- header: field.header || field.label || field.id,
- description: field.description,
- placeholder: field.placeholder,
- getValue,
- setValue,
- elements: field.elements,
- getElements: field.getElements,
- hasElements: hasElements( field ),
- render: field.render ?? render,
- Edit: getControl( field, 'telephone' ),
- sort: field.sort ?? sort,
- isValid: {
- ...isValid,
- ...field.isValid,
- },
- isVisible: field.isVisible,
- enableSorting: field.enableSorting ?? true,
- enableGlobalSearch: field.enableGlobalSearch ?? false,
- enableHiding: field.enableHiding ?? true,
- readOnly: field.readOnly ?? false,
- filterBy: getFilterBy( field, defaultOperators, validOperators ),
- format: {},
- };
-}
+ ],
+ getFormat: () => ( {} ),
+} satisfies FieldType< any >;
diff --git a/packages/dataviews/src/field-types/text.tsx b/packages/dataviews/src/field-types/text.tsx
index 036863ff8ad058..1c1c8c17e2bf58 100644
--- a/packages/dataviews/src/field-types/text.tsx
+++ b/packages/dataviews/src/field-types/text.tsx
@@ -1,15 +1,7 @@
/**
* Internal dependencies
*/
-import type {
- DataViewRenderFieldProps,
- Field,
- NormalizedField,
- Operator,
- Rules,
- SortDirection,
-} from '../types';
-import RenderFromElements from './utils/render-from-elements';
+import type { FieldType } from '../types/private';
import {
OPERATOR_CONTAINS,
OPERATOR_IS,
@@ -21,41 +13,22 @@ import {
OPERATOR_NOT_CONTAINS,
OPERATOR_STARTS_WITH,
} from '../constants';
-import { getControl } from '../dataform-controls';
-import hasElements from './utils/has-elements';
-import getValueFromId from './utils/get-value-from-id';
-import setValueFromId from './utils/set-value-from-id';
-import getFilterBy from './utils/get-filter-by';
+import render from './utils/render-default';
+import sort from './utils/sort-text';
-function render( { item, field }: DataViewRenderFieldProps< any > ) {
- return field.hasElements ? (
-
- ) : (
- field.getValue( { item } )
- );
-}
-
-export default function normalizeField< Item >(
- field: Field< Item >
-): NormalizedField< Item > {
- const getValue = field.getValue || getValueFromId( field.id );
- const setValue = field.setValue || setValueFromId( field.id );
- const isValid: Rules< Item > = {
+export default {
+ type: 'text',
+ render,
+ Edit: 'text',
+ sort,
+ isValid: {
elements: true,
custom: () => null,
- };
-
- const sort = ( a: Item, b: Item, direction: SortDirection ) => {
- const valueA = getValue( { item: a } );
- const valueB = getValue( { item: b } );
- return direction === 'asc'
- ? valueA.localeCompare( valueB )
- : valueB.localeCompare( valueA );
- };
-
- const defaultOperators: Operator[] = [ OPERATOR_IS_ANY, OPERATOR_IS_NONE ];
-
- const validOperators: Operator[] = [
+ },
+ enableSorting: true,
+ enableGlobalSearch: false,
+ defaultOperators: [ OPERATOR_IS_ANY, OPERATOR_IS_NONE ],
+ validOperators: [
// Single selection
OPERATOR_IS,
OPERATOR_IS_NOT,
@@ -67,33 +40,6 @@ export default function normalizeField< Item >(
OPERATOR_IS_NONE,
OPERATOR_IS_ALL,
OPERATOR_IS_NOT_ALL,
- ];
-
- return {
- id: field.id,
- type: 'text',
- label: field.label || field.id,
- header: field.header || field.label || field.id,
- description: field.description,
- placeholder: field.placeholder,
- getValue,
- setValue,
- elements: field.elements,
- getElements: field.getElements,
- hasElements: hasElements( field ),
- render: field.render ?? render,
- Edit: getControl( field, 'text' ),
- sort: field.sort ?? sort,
- isValid: {
- ...isValid,
- ...field.isValid,
- },
- isVisible: field.isVisible,
- enableSorting: field.enableSorting ?? true,
- enableGlobalSearch: field.enableGlobalSearch ?? false,
- enableHiding: field.enableHiding ?? true,
- readOnly: field.readOnly ?? false,
- filterBy: getFilterBy( field, defaultOperators, validOperators ),
- format: {},
- };
-}
+ ],
+ getFormat: () => ( {} ),
+} satisfies FieldType< any >;
diff --git a/packages/dataviews/src/field-types/url.tsx b/packages/dataviews/src/field-types/url.tsx
index d43dcfd885e57f..efcd07ab21143a 100644
--- a/packages/dataviews/src/field-types/url.tsx
+++ b/packages/dataviews/src/field-types/url.tsx
@@ -1,15 +1,7 @@
/**
* Internal dependencies
*/
-import type {
- DataViewRenderFieldProps,
- Field,
- NormalizedField,
- Operator,
- Rules,
- SortDirection,
-} from '../types';
-import RenderFromElements from './utils/render-from-elements';
+import type { FieldType } from '../types/private';
import {
OPERATOR_IS,
OPERATOR_IS_ALL,
@@ -21,41 +13,22 @@ import {
OPERATOR_NOT_CONTAINS,
OPERATOR_STARTS_WITH,
} from '../constants';
-import { getControl } from '../dataform-controls';
-import hasElements from './utils/has-elements';
-import getValueFromId from './utils/get-value-from-id';
-import setValueFromId from './utils/set-value-from-id';
-import getFilterBy from './utils/get-filter-by';
+import render from './utils/render-default';
+import sort from './utils/sort-text';
-function render( { item, field }: DataViewRenderFieldProps< any > ) {
- return field.hasElements ? (
-
- ) : (
- field.getValue( { item } )
- );
-}
-
-export default function normalizeField< Item >(
- field: Field< Item >
-): NormalizedField< Item > {
- const getValue = field.getValue || getValueFromId( field.id );
- const setValue = field.setValue || setValueFromId( field.id );
- const isValid: Rules< Item > = {
+export default {
+ type: 'url',
+ render,
+ Edit: 'url',
+ sort,
+ isValid: {
elements: true,
custom: () => null,
- };
-
- const sort = ( a: any, b: any, direction: SortDirection ) => {
- const valueA = getValue( { item: a } );
- const valueB = getValue( { item: b } );
- return direction === 'asc'
- ? valueA.localeCompare( valueB )
- : valueB.localeCompare( valueA );
- };
-
- const defaultOperators: Operator[] = [ OPERATOR_IS_ANY, OPERATOR_IS_NONE ];
-
- const validOperators: Operator[] = [
+ },
+ enableSorting: true,
+ enableGlobalSearch: false,
+ defaultOperators: [ OPERATOR_IS_ANY, OPERATOR_IS_NONE ],
+ validOperators: [
OPERATOR_IS,
OPERATOR_IS_NOT,
OPERATOR_CONTAINS,
@@ -66,33 +39,6 @@ export default function normalizeField< Item >(
OPERATOR_IS_NONE,
OPERATOR_IS_ALL,
OPERATOR_IS_NOT_ALL,
- ];
-
- return {
- id: field.id,
- type: 'url',
- label: field.label || field.id,
- header: field.header || field.label || field.id,
- description: field.description,
- placeholder: field.placeholder,
- getValue,
- setValue,
- elements: field.elements,
- getElements: field.getElements,
- hasElements: hasElements( field ),
- render: field.render ?? render,
- Edit: getControl( field, 'url' ),
- sort: field.sort ?? sort,
- isValid: {
- ...isValid,
- ...field.isValid,
- },
- isVisible: field.isVisible,
- enableSorting: field.enableSorting ?? true,
- enableGlobalSearch: field.enableGlobalSearch ?? false,
- enableHiding: field.enableHiding ?? true,
- readOnly: field.readOnly ?? false,
- filterBy: getFilterBy( field, defaultOperators, validOperators ),
- format: {},
- };
-}
+ ],
+ getFormat: () => ( {} ),
+} satisfies FieldType< any >;
diff --git a/packages/dataviews/src/field-types/utils/get-filter-by.ts b/packages/dataviews/src/field-types/utils/get-filter-by.ts
index 333ed12b959365..f26ea4b5caa7e3 100644
--- a/packages/dataviews/src/field-types/utils/get-filter-by.ts
+++ b/packages/dataviews/src/field-types/utils/get-filter-by.ts
@@ -12,38 +12,20 @@ function getFilterBy< Item >(
return false;
}
- if ( typeof field.filterBy === 'object' ) {
- let operators = field.filterBy.operators;
-
- // Assign default values if no operator was provided.
- if ( ! operators || ! Array.isArray( operators ) ) {
- operators = defaultOperators;
- }
-
- // Make sure only valid operators are included.
- operators = operators.filter( ( operator ) =>
- validOperators.includes( operator )
- );
-
- // If no operators are left at this point,
- // the filters should be disabled.
- if ( operators.length === 0 ) {
- return false;
- }
-
- return {
- isPrimary: !! field.filterBy.isPrimary,
- operators,
- };
- }
-
- if ( defaultOperators.length === 0 ) {
+ const operators =
+ field.filterBy?.operators?.filter( ( op ) =>
+ validOperators.includes( op )
+ ) ?? defaultOperators;
+
+ // If no operators are left at this point,
+ // the filters should be disabled.
+ if ( operators.length === 0 ) {
return false;
}
return {
- isPrimary: false,
- operators: defaultOperators,
+ isPrimary: !! field.filterBy?.isPrimary,
+ operators,
};
}
diff --git a/packages/dataviews/src/field-types/utils/normalize-fields.ts b/packages/dataviews/src/field-types/utils/normalize-fields.ts
deleted file mode 100644
index 0abb1f55f7332c..00000000000000
--- a/packages/dataviews/src/field-types/utils/normalize-fields.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * External dependencies
- */
-
-/**
- * Internal dependencies
- */
-import getNormalizeFieldFunction from '..';
-import type { Field, NormalizedField } from '../../types';
-
-/**
- * Apply default values and normalize the fields config.
- *
- * @param fields Fields config.
- * @return Normalized fields config.
- */
-export default function normalizeFields< Item >(
- fields: Field< Item >[]
-): NormalizedField< Item >[] {
- return fields.map( ( field ) => {
- const normalize = getNormalizeFieldFunction< Item >( field.type );
-
- return normalize( field );
- } );
-}
diff --git a/packages/dataviews/src/field-types/utils/render-default.tsx b/packages/dataviews/src/field-types/utils/render-default.tsx
new file mode 100644
index 00000000000000..bb9ad44589ebad
--- /dev/null
+++ b/packages/dataviews/src/field-types/utils/render-default.tsx
@@ -0,0 +1,16 @@
+/**
+ * Internal dependencies
+ */
+import type { DataViewRenderFieldProps } from '../../types';
+import RenderFromElements from './render-from-elements';
+
+export default function render( {
+ item,
+ field,
+}: DataViewRenderFieldProps< any > ) {
+ return field.hasElements ? (
+
+ ) : (
+ field.getValue( { item } )
+ );
+}
diff --git a/packages/dataviews/src/field-types/utils/sort-number.ts b/packages/dataviews/src/field-types/utils/sort-number.ts
new file mode 100644
index 00000000000000..1cdff01d963857
--- /dev/null
+++ b/packages/dataviews/src/field-types/utils/sort-number.ts
@@ -0,0 +1,8 @@
+/**
+ * Internal dependencies
+ */
+import type { SortDirection } from '../../types';
+
+export default ( a: any, b: any, direction: SortDirection ) => {
+ return direction === 'asc' ? a - b : b - a;
+};
diff --git a/packages/dataviews/src/field-types/utils/sort-text.ts b/packages/dataviews/src/field-types/utils/sort-text.ts
new file mode 100644
index 00000000000000..ba4d55dfb60909
--- /dev/null
+++ b/packages/dataviews/src/field-types/utils/sort-text.ts
@@ -0,0 +1,8 @@
+/**
+ * Internal dependencies
+ */
+import type { SortDirection } from '../../types';
+
+export default ( a: any, b: any, direction: SortDirection ) => {
+ return direction === 'asc' ? a.localeCompare( b ) : b.localeCompare( a );
+};
diff --git a/packages/dataviews/src/hooks/use-form-validity.ts b/packages/dataviews/src/hooks/use-form-validity.ts
index 27bf9d5f5937bf..d068bfca50ceee 100644
--- a/packages/dataviews/src/hooks/use-form-validity.ts
+++ b/packages/dataviews/src/hooks/use-form-validity.ts
@@ -13,7 +13,7 @@ import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
*/
-import normalizeFields from '../field-types/utils/normalize-fields';
+import normalizeFields from '../field-types';
import normalizeForm from '../dataform-layouts/normalize-form';
import type {
Field,
diff --git a/packages/dataviews/src/test/normalize-fields.ts b/packages/dataviews/src/test/normalize-fields.ts
index 807f615841ed38..b38b9b5fcac3d1 100644
--- a/packages/dataviews/src/test/normalize-fields.ts
+++ b/packages/dataviews/src/test/normalize-fields.ts
@@ -1,7 +1,7 @@
/**
* Internal dependencies
*/
-import normalizeFields from '../field-types/utils/normalize-fields';
+import normalizeFields from '../field-types';
import type { Field } from '../types';
describe( 'normalizeFields: default getValue', () => {
diff --git a/packages/dataviews/src/types/field-api.ts b/packages/dataviews/src/types/field-api.ts
index a7b40bb90b5c20..bb3fcf52da5be8 100644
--- a/packages/dataviews/src/types/field-api.ts
+++ b/packages/dataviews/src/types/field-api.ts
@@ -61,7 +61,7 @@ export type Operator =
| 'inThePast'
| 'over';
-export type FieldType =
+export type FieldTypeName =
| 'text'
| 'integer'
| 'number'
@@ -118,7 +118,7 @@ export type EditConfigText = {
* Edit configuration for other control types (excluding 'text' and 'textarea').
*/
export type EditConfigGeneric = {
- control: Exclude< FieldType, 'text' | 'textarea' >;
+ control: Exclude< FieldTypeName, 'text' | 'textarea' >;
};
/**
@@ -137,7 +137,7 @@ export type Field< Item > = {
/**
* Type of the fields.
*/
- type?: FieldType;
+ type?: FieldTypeName;
/**
* The unique identifier of the field.
@@ -244,8 +244,6 @@ export type Field< Item > = {
format?: FormatDate;
};
-export type NormalizedFormat = Required< FormatDate > | {};
-
/**
* Format for date fields:
*
diff --git a/packages/dataviews/src/types/private.ts b/packages/dataviews/src/types/private.ts
index d2d453e63599c9..18941d97cd89a1 100644
--- a/packages/dataviews/src/types/private.ts
+++ b/packages/dataviews/src/types/private.ts
@@ -1,2 +1,23 @@
+/**
+ * Internal dependencies
+ */
+import type { Field, FormatDate, NormalizedField, Operator } from './field-api';
+
export type SelectionOrUpdater = string[] | ( ( prev: string[] ) => string[] );
export type SetSelection = ( selection: SelectionOrUpdater ) => void;
+export type FieldType< Item > = Pick<
+ NormalizedField< Item >,
+ | 'type'
+ | 'render'
+ | 'sort'
+ | 'isValid'
+ | 'enableSorting'
+ | 'enableGlobalSearch'
+> & {
+ Edit: string | null;
+ validOperators: Operator[];
+ defaultOperators: Operator[];
+ getFormat: (
+ field: Field< Item >
+ ) => Record< string, any > | Required< FormatDate >;
+};
diff --git a/packages/dataviews/src/utils/filter-sort-and-paginate.ts b/packages/dataviews/src/utils/filter-sort-and-paginate.ts
index 362d80ab68a4bc..fa273ac8366138 100644
--- a/packages/dataviews/src/utils/filter-sort-and-paginate.ts
+++ b/packages/dataviews/src/utils/filter-sort-and-paginate.ts
@@ -36,7 +36,7 @@ import {
OPERATOR_IN_THE_PAST,
OPERATOR_OVER,
} from '../constants';
-import normalizeFields from '../field-types/utils/normalize-fields';
+import normalizeFields from '../field-types';
import type { Field, View } from '../types';
function normalizeSearchInput( input = '' ) {