Dashboard: lift Suspense + error boundary into widget chrome and add a default header#78012
Conversation
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
|
Size Change: 0 B Total Size: 7.95 MB ℹ️ View Unchanged
|
|
Flaky tests detected in 549e5c3. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/25497243870
|
0cb432c to
412539e
Compare
| * Visual identifier shown in the widget header; dashicon string, React node, or SVG component. | ||
| */ | ||
| icon?: string; | ||
| icon?: IconType; |
There was a problem hiding this comment.
This tightens types so that the string cannot be just any string; it has to be from a list of supported dashicons.
We might actually want to not support dashicons; a new Icon component from DS doesn't support them either, they're pretty heavy dependency vs just focused SVGs. But I think this is fine for now and mimics Blocks API.
simison
left a comment
There was a problem hiding this comment.
This is now in a good state to land methinks
0fa9303 to
38221a0
Compare
Part of #77616
What?
Two atomic refactors of the per-instance widget chrome inside the dashboard rendering engine.
Suspenseand the error boundary out ofWidgetRenderand into the chrome component (WidgetDashboard.Widget). The render component is now a pure dispatcher that resolves the lazy module and forwardsattributes/setAttributes.WidgetTypemetadata. The widget body keeps the minimalWidgetRenderPropscontract; the chrome owns the surrounding visual frame. Uses DS Card component for the UI.Why?
The chrome is the layer where surface concerns (header, error/loading state, edit-mode affordances, settings entry points) meet the widget API. Keeping the boundaries inside
WidgetRenderhad two issues:WidgetRendershould do) and "present the widget instance to the user" (what the chrome should do).Lifting the boundaries clarifies that split and unblocks the rest of the chrome work tracked in RSM-554 (remove action, settings entry point, drag/resize affordances) without further reshuffling.
The header lands the first chrome surface that consumes
WidgetTypemetadata. Title comes fromwidgetType.title. Icon accepts both forms used elsewhere in Gutenberg:"chart-bar"), the only formwidget.jsoncan express.@wordpress/iconsSVG component or any element.@wordpress/componentsIconalready normalizes both shapes, so no per-source branch in our code.How?
routes/dashboard/widget-dashboard/components/widget/widget.tsx: now hostsWidgetErrorBoundary(a class, since error boundaries still require classes in React),LoadingOverlay, and aHeadersubcomponent. Root element switched to<section>witharia-labelledbypointing at the title'suseId()-generated id.routes/dashboard/widget-dashboard/components/widget-render/widget-render.tsx: stripped down to module resolution +setAttributesplumbing. CSS module deleted.routes/dashboard/widget-dashboard/components/widget/widget.module.css: new.header,.headerIcon,.headerTitleclasses with WPDS tokens; root.widgetis nowflex columnso header and body stack.routes/dashboard/widget-dashboard/types.ts:icon?: string | ReactNodewith JSDoc clarifying the two authoring shapes.routes/dashboard/package.json: adds@wordpress/components(now imported forIcon).No public API change.
WidgetRenderPropsis unchanged (attributes,setAttributes);WidgetType.icononly widens.Testing
npm run test:unit -- routes/dashboard/widget-dashboard/test/— 10/10 passing.import()to confirm the loading overlay.Follow-ups
Tracked under RSM-554:
onLayoutChange)widgetType.attributes@wordpress/gridScreenshots