From 2537c6089bcef57f05ed18d4864add895b1dbae5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dami=C3=A1n=20Su=C3=A1rez?= Date: Tue, 12 May 2026 18:56:37 -0300 Subject: [PATCH] make widget framework types generic Parametrize WidgetTypeMetadata and WidgetType over the widget's attribute object (Item). Add WidgetRenderProps. Promote the widget-types module to a composite TS project so consumers in other compilation units can reference it cleanly. --- routes/dashboard/tsconfig.json | 2 +- routes/dashboard/widget-types/index.ts | 7 ++- routes/dashboard/widget-types/tsconfig.json | 19 ++++++++ routes/dashboard/widget-types/types.ts | 53 +++++++++++++++------ 4 files changed, 64 insertions(+), 17 deletions(-) create mode 100644 routes/dashboard/widget-types/tsconfig.json diff --git a/routes/dashboard/tsconfig.json b/routes/dashboard/tsconfig.json index ae3abe9d2d4bf8..d6f992df6b4959 100644 --- a/routes/dashboard/tsconfig.json +++ b/routes/dashboard/tsconfig.json @@ -11,5 +11,5 @@ "types": [ "style-imports" ] }, "include": [ "**/*.ts", "**/*.tsx" ], - "exclude": [ "**/test/**", "build", "node_modules" ] + "exclude": [ "**/test/**", "build", "node_modules", "widget-types" ] } diff --git a/routes/dashboard/widget-types/index.ts b/routes/dashboard/widget-types/index.ts index b76807da061f0a..c5743c48a1e7e4 100644 --- a/routes/dashboard/widget-types/index.ts +++ b/routes/dashboard/widget-types/index.ts @@ -6,4 +6,9 @@ export { useWidgetTypes } from './hooks'; /** * Types */ -export type { WidgetName, WidgetTypeMetadata, WidgetType } from './types'; +export type { + WidgetName, + WidgetTypeMetadata, + WidgetType, + WidgetRenderProps, +} from './types'; diff --git a/routes/dashboard/widget-types/tsconfig.json b/routes/dashboard/widget-types/tsconfig.json new file mode 100644 index 00000000000000..47a4279ec0c9da --- /dev/null +++ b/routes/dashboard/widget-types/tsconfig.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig.json", + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "rootDir": ".", + "declarationDir": "./build-types", + "types": [ "style-imports" ] + }, + "references": [ + { "path": "../../../packages/components" }, + { "path": "../../../packages/core-data" }, + { "path": "../../../packages/data" }, + { "path": "../../../packages/dataviews" }, + { "path": "../../../packages/element" }, + { "path": "../../../packages/i18n" } + ], + "include": [ "**/*.ts", "**/*.tsx" ], + "exclude": [ "**/test/**", "build-types", "node_modules" ] +} diff --git a/routes/dashboard/widget-types/types.ts b/routes/dashboard/widget-types/types.ts index bbec6e2086fa2f..065201f2d70bd4 100644 --- a/routes/dashboard/widget-types/types.ts +++ b/routes/dashboard/widget-types/types.ts @@ -4,6 +4,10 @@ * Canonical home for widget identity types consumed by the registry, * surfaces that render widgets, and tools that author them * (`@wordpress/build`, schema validators, IDE autocomplete). + * + * Each type is generic over the widget's attribute object (`Item`) so a + * widget binds its own attribute shape once and gets typed `attributes`, + * `example`, and `setAttributes` throughout the framework. */ /** @@ -23,7 +27,7 @@ export type WidgetName = `${ string }/${ string }`; /** * Literal contents of a widget's `widget.json` metadata file. * - * Captures the *authoring* shape only — module entry points and style + * Captures the *authoring* shape only; module entry points and style * assets are discovered by convention from the widget directory * (`render.*`, `widget.*`, `render.scss`), not declared here. * @@ -32,7 +36,7 @@ export type WidgetName = `${ string }/${ string }`; * which extends this shape with runtime-only fields produced by the * build manifest. */ -export interface WidgetTypeMetadata { +export interface WidgetTypeMetadata< Item = unknown > { /** * Version of the Widget API used by the widget. */ @@ -70,31 +74,29 @@ export interface WidgetTypeMetadata { keywords?: string[]; /** - * Widget version — used for asset cache invalidation. + * Widget version, used for asset cache invalidation. */ version?: string; /** - * Experiment gate — boolean `true`, or a specific experiment name. + * Experiment gate; boolean `true`, or a specific experiment name. */ __experimental?: string | boolean; /** - * Declarative attribute schema, reusing the DataViews `Field` shape so - * surfaces can render forms via `DataForm` without per-widget form - * wiring. `Field< any >` is used here because the array is - * heterogeneous — each widget narrows `Item` to its own attribute type - * at the point of registration. + * Declarative attribute schema, bound to the widget's attribute + * object via `Item`. Surfaces render forms straight from this list + * via `DataForm`, with no per-widget form wiring. */ - attributes?: Field< any >[]; + attributes?: Field< Item >[]; /** - * Structured example data for the Inspector Help Panel preview, and the - * default attributes applied when a new instance is created without - * initial attributes. + * Structured example data for the Inspector Help Panel preview, and + * the default attributes applied when a new instance is created + * without initial attributes. */ example?: { - attributes?: Record< string, unknown >; + attributes?: Partial< Item >; }; } @@ -110,7 +112,8 @@ export interface WidgetTypeMetadata { * (`render_module`). The `getWidgetTypes` resolver is the single boundary * that maps it to the camelCase shape consumed throughout JS/TS. */ -export interface WidgetType extends WidgetTypeMetadata { +export interface WidgetType< Item = unknown > + extends WidgetTypeMetadata< Item > { /** * Script-module identifier resolved to a React component at render * time. Produced by the build pipeline from the conventional @@ -118,3 +121,23 @@ export interface WidgetType extends WidgetTypeMetadata { */ renderModule: string; } + +/** + * Props passed to a widget's render component by the consuming surface. + * + * Bound over `Item` so the destructured `attributes` and any + * `setAttributes` payload are typed against the widget's attribute + * object. + */ +export interface WidgetRenderProps< Item = unknown > { + /** + * User-configured attributes for this widget instance. + */ + attributes: Item; + + /** + * Updates the attributes of this instance. Optional because some + * surfaces render widgets in read-only contexts. + */ + setAttributes?: ( next: Partial< Item > ) => void; +}