@automattic/jetpack-components 1.2.2 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  ### This is a list detailing changes for the Jetpack RNA Components package releases.
4
4
 
5
+ ## [1.3.1] - 2025-09-01
6
+ ### Changed
7
+ - My Jetpack: Add product interstitials state management. [#44772]
8
+
9
+ ## [1.3.0] - 2025-08-25
10
+ ### Changed
11
+ - Use PricingTable component for product interstitials. [#44801]
12
+
5
13
  ## [1.2.2] - 2025-08-25
6
14
  ### Changed
7
15
  - Update dependencies.
@@ -1516,6 +1524,8 @@
1516
1524
  ### Changed
1517
1525
  - Update node version requirement to 14.16.1
1518
1526
 
1527
+ [1.3.1]: https://github.com/Automattic/jetpack-components/compare/1.3.0...1.3.1
1528
+ [1.3.0]: https://github.com/Automattic/jetpack-components/compare/1.2.2...1.3.0
1519
1529
  [1.2.2]: https://github.com/Automattic/jetpack-components/compare/1.2.1...1.2.2
1520
1530
  [1.2.1]: https://github.com/Automattic/jetpack-components/compare/1.2.0...1.2.1
1521
1531
  [1.2.0]: https://github.com/Automattic/jetpack-components/compare/1.1.19...1.2.0
@@ -32,6 +32,7 @@ const getItemLabels = (isComingSoon, isIncluded, featureNameLabel) => {
32
32
  export const PricingTableItem = ({ isIncluded = false, isComingSoon = false, index = 0, label = null, tooltipInfo, tooltipTitle, tooltipClassName = '', }) => {
33
33
  const [isLg] = useBreakpointMatch('lg');
34
34
  const item = useContext(PricingTableContext)[index];
35
+ const isExplicitlyEmpty = label === '';
35
36
  const showTick = isComingSoon || isIncluded;
36
37
  const featureNameLabel = item.name;
37
38
  const defaultTooltipInfo = item.tooltipInfo;
@@ -39,6 +40,10 @@ export const PricingTableItem = ({ isIncluded = false, isComingSoon = false, ind
39
40
  const showTooltip = tooltipInfo || (!isLg && defaultTooltipInfo);
40
41
  const labels = getItemLabels(isComingSoon, isIncluded, featureNameLabel);
41
42
  const defaultLabel = isLg ? labels.lg : labels.default;
43
+ // Handle explicitly empty items (when label is empty string)
44
+ if (isExplicitlyEmpty) {
45
+ return (_jsx("div", { className: clsx(styles.item, styles.value, styles.empty) }));
46
+ }
42
47
  return (_jsxs("div", { className: clsx(styles.item, styles.value), children: [_jsx(Icon, { className: clsx(styles.icon, showTick ? styles['icon-check'] : styles['icon-cross']), size: 32, icon: showTick ? check : closeSmall }), _jsx(Text, { variant: "body-small", children: label || defaultLabel }), showTooltip && (_jsx(IconTooltip, { title: tooltipTitle ? tooltipTitle : defaultTooltipTitle, iconClassName: styles['popover-icon'], className: clsx(styles.popover, tooltipClassName), placement: 'bottom-end', iconSize: 14, offset: 4, wide: Boolean(tooltipTitle && tooltipInfo), children: _jsx(Text, { variant: "body-small", component: "div", children: tooltipInfo || defaultTooltipInfo }) }))] }));
43
48
  };
44
49
  export const PricingTableHeader = ({ title, children }) => (_jsxs("div", { className: styles.headerContainer, children: [title && (_jsx(Text, { variant: "headline-small", className: styles.title, children: title })), _jsx("div", { className: styles.header, children: children })] }));
@@ -58,9 +63,15 @@ const PricingTable = ({ title, headerLogo, items, children, showIntroOfferDiscla
58
63
  return (_jsxs(PricingTableContext.Provider, { value: items, children: [_jsx("div", { className: clsx(styles.container, { [styles['is-viewport-large']]: isLg }), style: {
59
64
  '--rows': items.length + 1,
60
65
  '--columns': Children.toArray(children).length + 1,
61
- }, children: _jsxs("div", { className: styles.table, children: [_jsxs("div", { children: [headerLogo && _jsx("div", { className: styles['header-logo'], children: headerLogo }), _jsx(Text, { variant: "headline-small", children: title })] }), isLg &&
62
- items.map((item, i) => (_jsxs("div", { className: clsx(styles.item, styles.feature, {
63
- [styles['last-feature']]: i === items.length - 1,
64
- }), children: [_jsx(Text, { variant: "body-small", children: _jsx("strong", { children: item.name }) }), item.tooltipInfo && (_jsx(IconTooltip, { title: item.tooltipTitle, iconClassName: styles['popover-icon'], className: styles.popover, placement: item.tooltipPlacement ? item.tooltipPlacement : 'bottom-end', iconSize: 14, offset: 4, wide: Boolean(item.tooltipTitle && item.tooltipInfo), children: _jsx(Text, { variant: "body-small", children: item.tooltipInfo }) }))] }, i))), children] }) }), _jsx("div", { className: styles['tos-container'], children: _jsxs("div", { className: styles.tos, children: [showIntroOfferDisclaimer && (_jsx(Text, { variant: "body-small", children: __('Reduced pricing is a limited offer for the first year and renews at regular price.', 'jetpack-components') })), _jsx(TermsOfService, { multipleButtons: true })] }) })] }));
66
+ }, children: _jsxs("div", { className: styles.table, children: [_jsxs("div", { children: [headerLogo && _jsx("div", { className: styles['header-logo'], children: headerLogo }), _jsx(Text, { variant: "headline-small", className: styles.tableTitle, children: title })] }), isLg &&
67
+ items.map((item, i) => {
68
+ // Skip rendering feature names that are empty
69
+ if (!item.name) {
70
+ return (_jsx("div", { className: clsx(styles.item, styles.feature, styles.empty) }, i));
71
+ }
72
+ return (_jsxs("div", { className: clsx(styles.item, styles.feature, {
73
+ [styles['last-feature']]: i === items.length - 1,
74
+ }), children: [_jsx(Text, { variant: "body-small", children: _jsx("strong", { children: item.name }) }), item.tooltipInfo && (_jsx(IconTooltip, { title: item.tooltipTitle, iconClassName: styles['popover-icon'], className: styles.popover, placement: item.tooltipPlacement ? item.tooltipPlacement : 'bottom-end', iconSize: 14, offset: 4, wide: Boolean(item.tooltipTitle && item.tooltipInfo), children: _jsx(Text, { variant: "body-small", children: item.tooltipInfo }) }))] }, i));
75
+ }), children] }) }), _jsx("div", { className: styles['tos-container'], children: _jsxs("div", { className: styles.tos, children: [showIntroOfferDisclaimer && (_jsx(Text, { variant: "body-small", children: __('Reduced pricing is a limited offer for the first year and renews at regular price.', 'jetpack-components') })), _jsx(TermsOfService, { multipleButtons: true })] }) })] }));
65
76
  };
66
77
  export default PricingTable;
@@ -61,6 +61,7 @@ export const PricingTableItem: FC< PricingTableItemProps > = ( {
61
61
  } ) => {
62
62
  const [ isLg ] = useBreakpointMatch( 'lg' );
63
63
  const item = useContext( PricingTableContext )[ index ];
64
+ const isExplicitlyEmpty = label === '';
64
65
  const showTick = isComingSoon || isIncluded;
65
66
 
66
67
  const featureNameLabel = item.name;
@@ -73,6 +74,15 @@ export const PricingTableItem: FC< PricingTableItemProps > = ( {
73
74
 
74
75
  const defaultLabel = isLg ? labels.lg : labels.default;
75
76
 
77
+ // Handle explicitly empty items (when label is empty string)
78
+ if ( isExplicitlyEmpty ) {
79
+ return (
80
+ <div className={ clsx( styles.item, styles.value, styles.empty ) }>
81
+ { /* No icon and no text for explicitly empty items */ }
82
+ </div>
83
+ );
84
+ }
85
+
76
86
  return (
77
87
  <div className={ clsx( styles.item, styles.value ) }>
78
88
  <Icon
@@ -162,34 +172,45 @@ const PricingTable: FC< PricingTableProps > = ( {
162
172
  <div className={ styles.table }>
163
173
  <div>
164
174
  { headerLogo && <div className={ styles[ 'header-logo' ] }>{ headerLogo }</div> }
165
- <Text variant="headline-small">{ title }</Text>
175
+ <Text variant="headline-small" className={ styles.tableTitle }>
176
+ { title }
177
+ </Text>
166
178
  </div>
167
179
  { isLg &&
168
- items.map( ( item, i ) => (
169
- <div
170
- className={ clsx( styles.item, styles.feature, {
171
- [ styles[ 'last-feature' ] ]: i === items.length - 1,
172
- } ) }
173
- key={ i }
174
- >
175
- <Text variant="body-small">
176
- <strong>{ item.name }</strong>
177
- </Text>
178
- { item.tooltipInfo && (
179
- <IconTooltip
180
- title={ item.tooltipTitle }
181
- iconClassName={ styles[ 'popover-icon' ] }
182
- className={ styles.popover }
183
- placement={ item.tooltipPlacement ? item.tooltipPlacement : 'bottom-end' }
184
- iconSize={ 14 }
185
- offset={ 4 }
186
- wide={ Boolean( item.tooltipTitle && item.tooltipInfo ) }
187
- >
188
- <Text variant="body-small">{ item.tooltipInfo }</Text>
189
- </IconTooltip>
190
- ) }
191
- </div>
192
- ) ) }
180
+ items.map( ( item, i ) => {
181
+ // Skip rendering feature names that are empty
182
+ if ( ! item.name ) {
183
+ return (
184
+ <div key={ i } className={ clsx( styles.item, styles.feature, styles.empty ) } />
185
+ );
186
+ }
187
+
188
+ return (
189
+ <div
190
+ className={ clsx( styles.item, styles.feature, {
191
+ [ styles[ 'last-feature' ] ]: i === items.length - 1,
192
+ } ) }
193
+ key={ i }
194
+ >
195
+ <Text variant="body-small">
196
+ <strong>{ item.name }</strong>
197
+ </Text>
198
+ { item.tooltipInfo && (
199
+ <IconTooltip
200
+ title={ item.tooltipTitle }
201
+ iconClassName={ styles[ 'popover-icon' ] }
202
+ className={ styles.popover }
203
+ placement={ item.tooltipPlacement ? item.tooltipPlacement : 'bottom-end' }
204
+ iconSize={ 14 }
205
+ offset={ 4 }
206
+ wide={ Boolean( item.tooltipTitle && item.tooltipInfo ) }
207
+ >
208
+ <Text variant="body-small">{ item.tooltipInfo }</Text>
209
+ </IconTooltip>
210
+ ) }
211
+ </div>
212
+ );
213
+ } ) }
193
214
  { children }
194
215
  </div>
195
216
  </div>
@@ -1,5 +1,10 @@
1
+ @use "@automattic/jetpack-base-styles/gutenberg-base-styles" as gb;
2
+
1
3
  .container {
2
4
  --padding: calc(var(--spacing-base) * 4);
5
+ --padding-horizontal: calc(var(--spacing-base) * 3);
6
+ --padding-vertical: var(--spacing-base);
7
+ --item-border-color: #f0f0f0;
3
8
  color: var(--jp-black);
4
9
  }
5
10
 
@@ -15,6 +20,13 @@
15
20
  grid-template-rows: repeat(var(--rows), minmax(min-content, max-content));
16
21
  column-gap: var(--gap);
17
22
  }
23
+
24
+ .tableTitle {
25
+ font-size: 32px;
26
+ font-weight: 500;
27
+ line-height: 40px;
28
+ word-wrap: break-word;
29
+ }
18
30
  }
19
31
 
20
32
  .header-logo {
@@ -36,7 +48,7 @@
36
48
  // Border styles for all columns (default gray borders)
37
49
  > :first-child {
38
50
  border-style: solid;
39
- border-color: var(--jp-gray-10);
51
+ border-color: var(--item-border-color);
40
52
  border-width: 1.5px 1.5px 0;
41
53
  border-start-start-radius: 8px;
42
54
  border-start-end-radius: 8px;
@@ -44,20 +56,23 @@
44
56
 
45
57
  > :last-child {
46
58
  border-style: solid;
47
- border-color: var(--jp-gray-10);
59
+ border-color: var(--item-border-color);
48
60
  border-width: 0 1.5px 1.5px;
49
61
  border-end-start-radius: 8px;
50
62
  border-end-end-radius: 8px;
51
63
  }
52
64
 
53
65
  > :not(:first-child):not(:last-child) {
54
- border-inline: 1.5px solid var(--jp-gray-10);
66
+ border-inline: 1.5px solid var(--item-border-color);
67
+ }
68
+
69
+ > * {
70
+ background: var(--jp-white);
55
71
  }
56
72
 
57
73
  &.is-primary {
58
74
 
59
75
  > * {
60
- background: var(--jp-white);
61
76
  position: relative;
62
77
 
63
78
  &::after {
@@ -83,7 +98,11 @@
83
98
  background-image: url(./gradient.svg);
84
99
  background-repeat: no-repeat;
85
100
  background-size: 450px;
86
- background-position-x: 170px;
101
+ background-position-x: center;
102
+
103
+ @media (max-width: gb.$break-large) {
104
+ background-position-x: right;
105
+ }
87
106
  }
88
107
 
89
108
  > :last-child {
@@ -120,18 +139,19 @@
120
139
  .item {
121
140
  display: flex;
122
141
  align-items: center;
123
- padding-bottom: calc(var(--spacing-base) * 2);
142
+ padding-bottom: var(--padding-vertical);
124
143
  position: relative;
144
+ line-height: 20px;
125
145
 
126
- &:not(:nth-child(2)) {
127
- padding-top: calc(var(--spacing-base) * 2);
146
+ &:not(:nth-child(2)):not(.empty) {
147
+ padding-top: var(--padding-vertical);
128
148
 
129
149
  &::before {
130
150
  content: "";
131
151
  position: absolute;
132
152
  top: 0;
133
- inset-inline-start: var(--padding);
134
- inset-inline-end: var(--padding);
153
+ inset-inline-start: var(--padding-horizontal);
154
+ inset-inline-end: var(--padding-horizontal);
135
155
  height: 1px;
136
156
 
137
157
  z-index: 5;
@@ -149,7 +169,7 @@
149
169
  }
150
170
 
151
171
  &:last-of-type {
152
- padding-bottom: var(--padding);
172
+ padding-bottom: var(--padding-vertical);
153
173
  }
154
174
  }
155
175
 
@@ -158,8 +178,8 @@
158
178
  }
159
179
 
160
180
  .value {
161
- padding-left: var(--padding);
162
- padding-right: var(--padding);
181
+ padding-left: var(--padding-horizontal);
182
+ padding-right: var(--padding-horizontal);
163
183
  }
164
184
 
165
185
  .icon {
@@ -86,12 +86,14 @@
86
86
 
87
87
  > p {
88
88
  font-weight: 500;
89
+ font-size: 32px;
90
+ line-height: 32px;
89
91
  margin-right: 8px;
90
92
  }
91
93
 
92
94
  > div {
93
- line-height: 30px;
94
- margin-top: auto;
95
+ line-height: 16px;
96
+ margin: auto 0 0;
95
97
  color: var(--jp-gray-50);
96
98
  }
97
99
  }
@@ -103,8 +105,8 @@
103
105
  font-weight: 400;
104
106
  margin-right: 8px;
105
107
  color: var(--jp-gray-40);
106
- font-size: 32px;
107
- line-height: 50px;
108
+ font-size: 21px;
109
+ line-height: 35px;
108
110
 
109
111
  &::after {
110
112
  background: var(--jp-gray-40);
@@ -112,8 +114,8 @@
112
114
  }
113
115
 
114
116
  > div {
115
- line-height: 38px;
116
- margin-top: auto;
117
+ line-height: 16px;
118
+ margin: auto 0 0;
117
119
  color: var(--jp-gray-50);
118
120
  }
119
121
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automattic/jetpack-components",
3
- "version": "1.2.2",
3
+ "version": "1.3.1",
4
4
  "description": "Jetpack Components Package",
5
5
  "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/components/#readme",
6
6
  "bugs": {