Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
d34339b
update widget package pins in unit manifests
retrofox Jul 6, 2026
ac9b70a
migrate design tokens to renamed theme groups
retrofox Jul 6, 2026
7116393
update js-tools theme to 0.17.0
retrofox Jul 6, 2026
8ccbf9a
link wp packages to local gutenberg checkout
retrofox Jul 6, 2026
ac8e1b5
promote locations view mode to widget attribute
retrofox Jul 6, 2026
16959a6
type widget attributes and unify component jsdoc
retrofox Jul 6, 2026
72aef4e
promote top-platforms mode to widget attribute
retrofox Jul 6, 2026
e617759
drop dead content wrapper in locations widget
retrofox Jul 6, 2026
749eaad
unify object param jsdoc across hooks and stories
retrofox Jul 6, 2026
f75e9d9
Redo `@wordpress/dataviews/wp` pnpmfile hack
anomiex Jun 9, 2026
3e144f5
bump premium-analytics wp deps to 0.17 stack
retrofox Jul 7, 2026
cc42687
UTM Insights: replace custom param selector with high-relevance utmDi…
retrofox Jul 6, 2026
570c558
UTM Insights: drop the .content wrapper
retrofox Jul 6, 2026
88482b2
Emails: replace custom header and metric selector with high-relevance…
retrofox Jul 6, 2026
79ea8d6
Subscribers chart: replace in-body Group by selector with high-releva…
retrofox Jul 6, 2026
c4ab393
Traffic chart: replace in-body Group by selector with high-relevance …
retrofox Jul 6, 2026
f5b529d
Premium Analytics widgets: use DataViews-compatible text type for hig…
retrofox Jul 6, 2026
43295dc
Premium Analytics commerce widgets: declare framed presentation in wi…
retrofox Jul 6, 2026
c00dd5b
Premium Analytics widgets: align package.json dependencies with sourc…
retrofox Jul 6, 2026
94620e3
Subscribers list: pass host attributes through WidgetRoot
retrofox Jul 6, 2026
b0eca05
Subscribers list: compose render attributes with ReportParamsFieldAtt…
retrofox Jul 6, 2026
0ada851
use published next snapshots for widget packages
retrofox Jul 7, 2026
e24fda5
keep js-tools theme stable, exempt PA token lint
retrofox Jul 7, 2026
11954c0
Merge remote-tracking branch 'origin/trunk' into update/premium-analy…
retrofox Jul 7, 2026
0313bb2
fix pruned lockfile dep edge and stale changelog
retrofox Jul 7, 2026
a037c5e
adapt pa to widget-dashboard 0.3.1-next API
retrofox Jul 7, 2026
fe32082
Premium Analytics widgets: frame annual-highlights
retrofox Jul 7, 2026
16170ce
disable stylelint token-fallback rule with null
retrofox Jul 7, 2026
2db21d7
Merge remote-tracking branch 'origin/trunk' into update/premium-analy…
retrofox Jul 7, 2026
1094249
Merge remote-tracking branch 'origin/trunk' into codex/pr-50271-resol…
dognose24 Jul 7, 2026
4442699
Premium Analytics: Update pnpm lockfile
dognose24 Jul 7, 2026
84f0db7
drop redundant PA token-lint exemptions
retrofox Jul 7, 2026
c9fb24e
Merge remote-tracking branch 'origin/trunk' into update/premium-analy…
retrofox Jul 7, 2026
298f452
Merge remote-tracking branch 'origin/trunk' into update/premium-analy…
retrofox Jul 7, 2026
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
7 changes: 6 additions & 1 deletion .agents/skills/widget-audit.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,12 @@ assume: namespace, text domain, and the dependency versions the package resolves
- Props are a named `type`/`interface` with each field documented on the type,
not echoed in `@param`. A component takes one typed tag
(`@param {Props} props - The component props.`) — never `@param props.<field>`
blocks; plain functions keep positional `@param`s.
blocks.
- The same one-typed-tag rule applies to ANY function taking an object argument
(hooks, story helpers, test builders): `@param {UseXArgs} args - Hook
arguments.` with fields documented on the args type — never `@param
args.<field>` / `@param root0.<field>` blocks. Only scalar positional
parameters keep plain per-param tags (`@param interval - The interval.`).
- Descriptions track the code: referenced symbols still exist, terminology is
consistent (`widget.json` ↔ `widget.ts` ↔ rendered strings), `@return` is accurate.
- Verify, don't guess: `jsdoc/require-param` is satisfied by that single typed
Expand Down
869 changes: 783 additions & 86 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: changed

Type widget attribute fields with WidgetAttributeField, export attribute types from widget.ts, and unify component JSDoc to single typed param tags across all widgets.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: changed

Pin @wordpress/build to 0.19.1-next and the widget packages (@wordpress/widget-primitives, @wordpress/widget-dashboard) to 0.3.1-next development snapshots, scoped to this package.
6 changes: 3 additions & 3 deletions projects/packages/premium-analytics/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@
"@wordpress/theme": "0.17.0",
"@wordpress/ui": "0.17.0",
"@wordpress/url": "4.50.0",
"@wordpress/widget-dashboard": "0.2.0",
"@wordpress/widget-primitives": "0.2.0",
"@wordpress/widget-dashboard": "0.3.1-next.v.202607070741.0",
"@wordpress/widget-primitives": "0.3.1-next.v.202607070741.0",
"clsx": "2.1.1",
"date-fns": "4.1.0",
"fast-deep-equal": "^3.1.3",
Expand All @@ -91,7 +91,7 @@
"@types/react": "18.3.28",
"@typescript/native-preview": "7.0.0-dev.20260225.1",
"@wordpress/base-styles": "10.2.0",
"@wordpress/build": "0.18.0",
"@wordpress/build": "0.19.1-next.v.202607070741.0",
"browserslist": "4.28.4",
"jest": "30.4.2",
"storybook": "10.4.6",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const WidgetCard = ( {
height,
border: '1px solid var(--wpds-color-stroke-surface-neutral-weak, #e0e0e0)',
borderRadius: 'var(--wpds-border-radius-md, 8px)',
background: 'var(--wpds-color-background-surface-neutral-strong, #fff)',
background: 'var(--wpds-color-background-surface-neutral, #fff)',
display: 'flex',
flexDirection: 'column',
overflow: 'hidden',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function Dashboard(): JSX.Element {
DASHBOARD_NAME,
activeSection
);
const [ gridSettings, setGridSettings ] = useDashboardGridSettings();
const [ gridSettings ] = useDashboardGridSettings();

const widgetModules = useSelect(
select =>
Expand Down Expand Up @@ -74,7 +74,6 @@ function Dashboard(): JSX.Element {
onLayoutChange={ setLayout }
onLayoutReset={ resetLayout }
gridSettings={ gridSettings }
onGridSettingsChange={ setGridSettings }
editMode={ editMode }
onEditChange={ setEditMode }
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ function PostDetail(): JSX.Element {
const tabs = useMemo( () => getPostDetailTabs(), [] );
const [ activeTab, setActiveTab ] = useActiveTab();
const [ layout, setLayout, resetLayout ] = usePostDetailTabLayout( activeTab );
const [ gridSettings, setGridSettings ] = useDashboardGridSettings();
const [ gridSettings ] = useDashboardGridSettings();

const summary = usePostSummary( postId );

Expand Down Expand Up @@ -92,7 +92,6 @@ function PostDetail(): JSX.Element {
onLayoutChange={ setLayout }
onLayoutReset={ resetLayout }
gridSettings={ gridSettings }
onGridSettingsChange={ setGridSettings }
editMode={ editMode }
onEditChange={ setEditMode }
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
"@wordpress/i18n": "^6.9.0",
"@wordpress/icons": "^15.0.0",
"@wordpress/ui": "0.17.0",
"@wordpress/widget-primitives": "next",
"date-fns": "4.1.0",
"@wordpress/widget-primitives": "0.2.0",
"react": "18.3.1"
},
"devDependencies": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import type { WidgetRenderProps } from '@wordpress/widget-primitives';
// totals are all-time: the summary query takes no date params, so the picker's
// range and comparison state do not change what this widget shows.
type AllTimeStatsRenderAttributes = AllTimeStatsAttributes & Partial< ReportParamsFieldAttributes >;
type AllTimeStatsWidgetProps = WidgetRenderProps< AllTimeStatsRenderAttributes >;

/**
* The all-time summary carries dynamic WPCOM keys (`views`, `visitors`,
Expand Down Expand Up @@ -130,13 +131,10 @@ function AllTimeStatsReport() {
* range; report params still flow into WidgetRoot for parity with the other
* Stats widgets.
*
* @param props - Render props supplied by the widget host.
* @param props.attributes - Widget attributes.
* @param {AllTimeStatsWidgetProps} props - The widget render props.
* @return The rendered widget.
*/
export default function AllTimeStats( {
attributes = {},
}: WidgetRenderProps< AllTimeStatsRenderAttributes > ) {
export default function AllTimeStats( { attributes = {} }: AllTimeStatsWidgetProps ) {
return (
<WidgetRoot attributes={ attributes }>
<AllTimeStatsReport />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,17 @@ registerReportMocks();
const ALL_TIME_STATS_RENDER_MODULE = 'storybook/all-time-stats';

interface AllTimeStatsStoryControls {
/**
* Whether to include comparison report params.
*/
withComparison: boolean;
}

/**
* Renders the data-connected widget with report params derived from the
* date-range picker preset.
*
* @param props - The story controls.
* @param props.withComparison - Whether to include comparison report params.
* @param {AllTimeStatsStoryControls} props - The story controls.
* @return The rendered widget.
*/
function renderAllTimeStats( { withComparison }: AllTimeStatsStoryControls ) {
Expand Down Expand Up @@ -105,8 +107,7 @@ interface AllTimeStatsDashboardStoryProps
* Renders the data-connected widget through the shared dashboard harness, so it
* appears exactly as it does in product (framed card, sizing, edit mode).
*
* @param props - The dashboard story controls.
* @param props.withComparison - Whether to include comparison report params.
* @param {AllTimeStatsDashboardStoryProps} props - The dashboard story controls.
* @return The widget mounted inside the real `WidgetDashboard`.
*/
function AllTimeStatsDashboardStory( {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"@wordpress/i18n": "^6.9.0",
"@wordpress/icons": "^15.0.0",
"@wordpress/ui": "0.17.0",
"@wordpress/widget-primitives": "next",
"@wordpress/widget-primitives": "0.2.0",
"react": "18.3.1"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
type DataFormat,
type ReportParamsFieldAttributes,
} from '@jetpack-premium-analytics/widgets-toolkit';
import { __, sprintf } from '@wordpress/i18n';
import { __ } from '@wordpress/i18n';
import { arrowLeft, arrowRight, comment, paragraph, postList, starEmpty } from '@wordpress/icons';
import { Button, Icon, Text } from '@wordpress/ui';
import { useCallback, useMemo, useState } from 'react';
Expand All @@ -29,6 +29,12 @@ import type { WidgetRenderProps } from '@wordpress/widget-primitives';
// boundary (and Storybook may inject them) so the host contract holds.
type AnnualHighlightsRenderAttributes = AnnualHighlightsAttributes &
Partial< ReportParamsFieldAttributes >;
type AnnualHighlightsWidgetProps = WidgetRenderProps< AnnualHighlightsRenderAttributes >;

/**
* The enabled-metric flags from widget attributes, with defaults applied.
*/
type AnnualHighlightsReportProps = Required< AnnualHighlightsAttributes >;

const COUNT_FORMAT: DataFormat = {
type: 'number',
Expand All @@ -53,19 +59,15 @@ function sortYearsDescending( data?: StatsInsightsResponse ): StatsInsightsYear[
* comparison period, so each tile shows a bare formatted count. Which tiles
* appear is controlled by the per-metric visibility attributes.
*
* @param props - The enabled-metric flags from widget attributes.
* @param props.showPosts - Whether the Posts tile is shown.
* @param props.showWords - Whether the Words tile is shown.
* @param props.showLikes - Whether the Likes tile is shown.
* @param props.showComments - Whether the Comments tile is shown.
* @param {AnnualHighlightsReportProps} props - The component props.
* @return The widget content.
*/
function AnnualHighlightsReport( {
showPosts,
showWords,
showLikes,
showComments,
}: Required< AnnualHighlightsAttributes > ) {
}: AnnualHighlightsReportProps ) {
const { data, isLoading, isError } = useStatsInsights();

const years = useMemo( () => sortYearsDescending( data ), [ data ] );
Expand Down Expand Up @@ -151,40 +153,34 @@ function AnnualHighlightsReport( {

return (
<div className={ styles.root }>
<div className={ styles.header }>
<Text variant="heading-lg" render={ <h3 /> } className={ styles.title }>
{ sprintf(
/* translators: %s is a calendar year, e.g. "2026". */
__( '%s in review', 'jetpack-premium-analytics' ),
year.year
) }
</Text>
<div className={ styles.yearNav }>
<Button
type="button"
variant="minimal"
tone="neutral"
size="small"
className={ styles.navButton }
onClick={ showOlderYear }
disabled={ ! canShowOlder }
aria-label={ __( 'Previous year', 'jetpack-premium-analytics' ) }
>
<Button.Icon icon={ arrowLeft } size={ 16 } />
</Button>
<Button
type="button"
variant="minimal"
tone="neutral"
size="small"
className={ styles.navButton }
onClick={ showNewerYear }
disabled={ ! canShowNewer }
aria-label={ __( 'Next year', 'jetpack-premium-analytics' ) }
>
<Button.Icon icon={ arrowRight } size={ 16 } />
</Button>
</div>
<div className={ styles.yearNav }>
<Button
type="button"
variant="minimal"
tone="neutral"
size="small"
className={ styles.navButton }
onClick={ showOlderYear }
disabled={ ! canShowOlder }
aria-label={ __( 'Previous year', 'jetpack-premium-analytics' ) }
>
<Button.Icon icon={ arrowLeft } size={ 16 } />
</Button>

<Text className={ styles.yearLabel }>{ year.year }</Text>

<Button
type="button"
variant="minimal"
tone="neutral"
size="small"
className={ styles.navButton }
onClick={ showNewerYear }
disabled={ ! canShowNewer }
aria-label={ __( 'Next year', 'jetpack-premium-analytics' ) }
>
<Button.Icon icon={ arrowRight } size={ 16 } />
</Button>
</div>
{ tiles.length === 0 ? (
<Text className={ styles.placeholder }>
Expand Down Expand Up @@ -219,13 +215,10 @@ function AnnualHighlightsReport( {
* inner report. Host attributes are forwarded so any injected report params are
* preserved even though the insights endpoint is not period-scoped.
*
* @param props - Render props supplied by the widget host.
* @param props.attributes - Widget attributes.
* @param {AnnualHighlightsWidgetProps} props - The widget render props.
* @return The rendered widget.
*/
export default function AnnualHighlights( {
attributes = {},
}: WidgetRenderProps< AnnualHighlightsRenderAttributes > ) {
export default function AnnualHighlights( { attributes = {} }: AnnualHighlightsWidgetProps ) {
return (
<WidgetRoot attributes={ attributes }>
<AnnualHighlightsReport
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,38 @@ registerReportMocks();
const ANNUAL_HIGHLIGHTS_RENDER_MODULE = 'storybook/annual-highlights';

// Carry the widget's metadata, including the metric-visibility attribute schema
// so the dashboard story's settings drawer renders the real checkboxes, and
// surface the full-bleed presentation so it renders edge-to-edge with its own
// header instead of inside the host's framed chrome. The attribute schema is
// typed loosely on the widget definition, so it is cast to the WidgetType shape.
// so the dashboard story's settings drawer renders the real checkboxes.
// Presentation is left unset so the host frames the widget and renders its
// identity (title + icon), matching widget.json. The attribute schema is typed
// loosely on the widget definition, so it is cast to the WidgetType shape.
const storyWidgetType = {
name: widgetDefinition.name,
title: widgetDefinition.title,
icon: widgetDefinition.icon,
attributes: widgetDefinition.attributes as WidgetType[ 'attributes' ],
example: widgetDefinition.example,
presentation: 'full-bleed' as const,
};

interface AnnualHighlightsStoryControls {
/**
* Whether to inject comparison report params.
*/
withComparison: boolean;
/**
* Whether the Posts tile is shown.
*/
showPosts: boolean;
/**
* Whether the Words tile is shown.
*/
showWords: boolean;
/**
* Whether the Likes tile is shown.
*/
showLikes: boolean;
/**
* Whether the Comments tile is shown.
*/
showComments: boolean;
}

Expand All @@ -52,12 +66,7 @@ interface AnnualHighlightsStoryControls {
* host injects comparison params. The metric toggles mirror the widget's
* checkbox settings and hide/show the matching tile.
*
* @param props - Story controls.
* @param props.withComparison - Whether to inject comparison report params.
* @param props.showPosts - Whether the Posts tile is shown.
* @param props.showWords - Whether the Words tile is shown.
* @param props.showLikes - Whether the Likes tile is shown.
* @param props.showComments - Whether the Comments tile is shown.
* @param {AnnualHighlightsStoryControls} props - Story controls.
* @return The rendered widget.
*/
function renderAnnualHighlights( {
Expand Down Expand Up @@ -150,12 +159,7 @@ interface AnnualHighlightsDashboardStoryProps
/**
* Renders the real registered widget through the shared dashboard harness.
*
* @param props - Dashboard and widget controls.
* @param props.withComparison - Whether to inject comparison report params.
* @param props.showPosts - Whether the Posts tile is shown.
* @param props.showWords - Whether the Words tile is shown.
* @param props.showLikes - Whether the Likes tile is shown.
* @param props.showComments - Whether the Comments tile is shown.
* @param {AnnualHighlightsDashboardStoryProps} props - Dashboard and widget controls.
* @return The rendered dashboard with the widget.
*/
function AnnualHighlightsDashboardStory( {
Expand Down
Loading
Loading