Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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

Add a Vite alias resolving `@jetpack-premium-analytics/*` internal package imports so Premium Analytics ui package stories build.
8 changes: 8 additions & 0 deletions projects/js-packages/storybook/storybook/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,14 @@ const sbconfig = {
alias: {
...config.resolve?.alias,

// Premium Analytics internal packages. At build time wp-build maps
// `@jetpack-premium-analytics/<dir>` to `packages/<dir>`; mirror that here
// (each package's `main` points at its TS source).
'@jetpack-premium-analytics': path.join(
__dirname,
'../../../packages/premium-analytics/packages'
),

// Boost-specific aliases
$lib: path.join( __dirname, '../../../plugins/boost/app/assets/src/js/lib' ),
$features: path.join( __dirname, '../../../plugins/boost/app/assets/src/js/features' ),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: added

Port the components package (date range/comparison filter UI components and SCSS) from next-woocommerce-analytics as the internal `ui` package.
16 changes: 16 additions & 0 deletions projects/packages/premium-analytics/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,22 @@ export default defineConfig(
'import/no-extraneous-dependencies': 'off',
},
},
{
// First UI package in the port: also soften JSDoc rules for the ui
// package and allow the upstream inline-handler JSX style. Temporary —
// tighten these up in a follow-up alongside datetime/formatters.
files: [ 'packages/ui/**' ],
rules: {
'jsdoc/require-jsdoc': 'off',
'jsdoc/require-description': 'off',
'jsdoc/require-param': 'off',
'jsdoc/require-param-description': 'off',
'jsdoc/require-returns': 'off',
'jsdoc/check-indentation': 'off',
'jsdoc/escape-inline-tags': 'off',
'react/jsx-no-bind': 'off',
},
},
{
// The routing port also imports `react` directly (the staged-search
// hook), flagged as extraneous because the internal package's deps are
Expand Down
8 changes: 7 additions & 1 deletion projects/packages/premium-analytics/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,23 @@
},
"dependencies": {
"@automattic/number-formatters": "workspace:*",
"@automattic/ui": "1.0.2",
"@date-fns/tz": "1.4.1",
"@tanstack/react-query": "5.90.8",
"@wordpress/api-fetch": "7.48.0",
"@wordpress/boot": "0.14.1",
"@wordpress/components": "35.0.0",
"@wordpress/compose": "8.1.0",
"@wordpress/core-data": "7.48.0",
"@wordpress/data": "10.48.0",
"@wordpress/i18n": "^6.9.0",
"@wordpress/icons": "^13.0.0",
"@wordpress/primitives": "4.48.0",
"@wordpress/private-apis": "1.48.0",
"@wordpress/route": "0.13.1",
"@wordpress/ui": "0.13.0",
"@wordpress/url": "4.48.0",
"clsx": "2.1.1",
"date-fns": "4.1.0",
"react": "18.3.1",
"react-dom": "18.3.1"
Expand All @@ -55,8 +61,8 @@
"@testing-library/dom": "10.4.1",
"@types/jest": "30.0.0",
"@typescript/native-preview": "7.0.0-dev.20260225.1",
"@wordpress/base-styles": "8.0.0",
"@wordpress/build": "0.14.0",
"@wordpress/ui": "0.13.0",
"browserslist": "4.28.2",
"jest": "30.4.2",
"storybook": "10.3.6",
Expand Down
28 changes: 28 additions & 0 deletions projects/packages/premium-analytics/packages/ui/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "@automattic/jetpack-premium-analytics-ui",
"version": "0.1.0",
"private": true,
"type": "module",
"main": "src/index.ts",
"types": "src/index.ts",
"sideEffects": [
"*.scss"
],
"dependencies": {
"@automattic/ui": "1.0.2",
"@jetpack-premium-analytics/datetime": "workspace:*",
"@jetpack-premium-analytics/formatters": "workspace:*",
"@wordpress/components": "33.1.0",
"@wordpress/compose": "7.46.0",
"@wordpress/i18n": "^6.9.0",
"@wordpress/icons": "^13.0.0",
"@wordpress/private-apis": "1.46.0",
Comment on lines +15 to +19

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[suggestion] These three pins (@wordpress/components 33.1.0, @wordpress/compose 7.46.0, @wordpress/private-apis 1.46.0) are older than what the parent manifest resolves (35.0.0 / 8.1.0 / 1.48.0), and the sibling data leaf matches the parent exactly — so the PR description's "versions match siblings" doesn't hold for these.

No runtime impact today since the leaf isn't a pnpm workspace member, but when it becomes load-bearing in the first-consumer PR, pnpm would install a second, older @wordpress/components alongside the parent's. The private-apis skew is the riskiest one: its lock/unlock is version-coupled to @wordpress/components, so a mismatched pair can throw at runtime.

Suggest bumping the three specifiers to match the parent (35.0.0 / 8.1.0 / 1.48.0).

"@wordpress/ui": "0.13.0",
"clsx": "2.1.1",
"react": "18.3.1"
},
"devDependencies": {
"@storybook/react": "10.3.6",
"date-fns": "4.1.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
.date-comparison-dropdown {

&__button {
background-color: var(--wpds-color-bg-surface-neutral-strong);
}
}

.date-filters-panel-button {
background-color: var(--wpds-color-bg-surface-neutral-strong);
}

.date-comparison-dropdown__popover {
width: 235px;
}

/* disable animation for the date range popover */
/* stylelint-disable property-no-unknown, selector-pseudo-element-no-unknown */
@media not ( prefers-reduced-motion: reduce ) {

.date-comparison-dropdown__popover {
view-transition-name: jp-premium-analytics--date-comparison-dropdown;
transition: none !important;
}
}

/* ensure it's above the canvas/stage during the transition */
::view-transition-group(jp-premium-analytics--date-comparison-dropdown) {
z-index: 3000;
}

/* no animation for the snapshot (avoid "flashing") */
::view-transition-new(jp-premium-analytics--date-comparison-dropdown),
::view-transition-old(jp-premium-analytics--date-comparison-dropdown) {
animation: none;
}
/* stylelint-enable property-no-unknown, selector-pseudo-element-no-unknown */
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/**
* External dependencies
*/
import { formatDateRange } from '@jetpack-premium-analytics/formatters';
import { privateApis as componentsPrivateApis } from '@wordpress/components';
import { sprintf, __ } from '@wordpress/i18n';
import { Button } from '@wordpress/ui';
import { useMemo } from 'react';
/**
* Internal dependencies
*/
import { DateRangePresets } from '../date-range-presets';
import { unlock } from '../lock/unlock';
import type { ComparisonDateRangePreset } from '../use-comparison-date-presets';
import type {
ComparisonPresetId,
DateRangePreset,
PrimaryPresetId,
} from '@jetpack-premium-analytics/datetime';
import './date-comparison-dropdown.scss';

const { Menu } = unlock( componentsPrivateApis );

type DateComparisonDropdownProps = {
/**
* Available comparison presets (e.g., previous-period, previous-month)
*/
presets: ComparisonDateRangePreset[];
/**
* Whether comparison is enabled
*/
enabled: boolean;
/**
* Currently selected comparison preset ID
*/
presetId?: ComparisonPresetId;
/**
* Whether to remove "Compare to:" prefix from button label
*/
removeCompareToPrefix?: boolean;
/**
* Callback when comparison is enabled
*/
onEnable: () => void;
/**
* Callback when a comparison preset is selected
*/
onPresetChange: ( id: ComparisonPresetId ) => void;
/**
* Callback when comparison is cleared
*/
onClear: () => void;
};

export function DateComparisonDropdown( {
presets,
enabled,
presetId,
removeCompareToPrefix = false,
onEnable,
onPresetChange,
onClear,
}: DateComparisonDropdownProps ) {
const selectedPreset = useMemo(
() => ( presetId ? presets.find( p => p.id === presetId ) : undefined ),
[ presets, presetId ]
);

const comparisonRange = selectedPreset?.range;
const hasValidPreset = !! comparisonRange;
const hasPresets = presets.length > 0;

if ( ! enabled ) {
return (
<Menu>
<Menu.TriggerButton
render={
<Button
className="date-filters-panel-button"
variant="outline"
tone="neutral"
size="compact"
id="date-comparison-dropdown-button"
>
{ __( 'No comparison', 'jetpack-premium-analytics' ) }
</Button>
}
/>
<Menu.Popover className="date-comparison-dropdown__popover">
<Menu.Group>
<Menu.CheckboxItem name="comparison-toggle" value="no-comparison" checked={ true }>
<Menu.ItemLabel>
{ __( 'No comparison', 'jetpack-premium-analytics' ) }
</Menu.ItemLabel>
</Menu.CheckboxItem>

<Menu.CheckboxItem
name="comparison-toggle"
value="comparison-to-past"
checked={ false }
onChange={ onEnable }
hideOnClick
>
<Menu.ItemLabel>
{ __( 'Comparison to past', 'jetpack-premium-analytics' ) }
</Menu.ItemLabel>
</Menu.CheckboxItem>
</Menu.Group>
</Menu.Popover>
</Menu>
);
}

let label: string = __( 'Select comparison', 'jetpack-premium-analytics' );
if ( hasValidPreset ) {
if ( removeCompareToPrefix ) {
label = formatDateRange( comparisonRange );
} else {
label = sprintf(
// translators: %s is the comparison range label
__( 'Compare to: %s', 'jetpack-premium-analytics' ),
formatDateRange( comparisonRange )
);
}
}

return (
<Menu>
<Menu.TriggerButton
render={
<Button
className="date-comparison-dropdown__button"
variant="outline"
tone="neutral"
size="compact"
>
{ label }
</Button>
}
/>
<Menu.Popover className="date-comparison-dropdown__popover">
{ hasPresets && (
<DateRangePresets
/*
* DateRangePresets is typed for primary presets, but it only
* reads `id`/`label`/`range` to render each row, so it renders
* comparison presets identically. Cast to the primary-preset
* prop types; the runtime shape matches.
*/
value={ ( presetId ?? null ) as PrimaryPresetId | null }
presets={ presets as unknown as DateRangePreset[] }
hideOnClick
onRangeChange={ ( _range, id ) => {
/*
* Type assertion is safe here because:
* 1. presets is ComparisonDateRangePreset[] (strongly typed)
* 2. DateRangePresets picks id from our presets array
* 3. Therefore id must be ComparisonPresetId
*/
onPresetChange( id as ComparisonPresetId );
} }
onClear={ onClear }
/>
) }
</Menu.Popover>
</Menu>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { DateComparisonDropdown } from './date-comparison-dropdown';
Loading
Loading