@automattic/plans-grid-next 1.0.1 → 1.0.3

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.
Files changed (339) hide show
  1. package/CHANGELOG.md +4 -1
  2. package/dist/cjs/_shared.scss +4 -3
  3. package/dist/cjs/components/comparison-grid/index.js +101 -71
  4. package/dist/cjs/components/comparison-grid/index.js.map +1 -1
  5. package/dist/cjs/components/comparison-grid/index.stories.js.map +1 -1
  6. package/dist/cjs/components/comparison-grid/style.scss +10 -2
  7. package/dist/cjs/components/features-grid/client-logo-list/client-list.js +0 -12
  8. package/dist/cjs/components/features-grid/client-logo-list/client-list.js.map +1 -1
  9. package/dist/cjs/components/features-grid/index.js +9 -6
  10. package/dist/cjs/components/features-grid/index.js.map +1 -1
  11. package/dist/cjs/components/features-grid/plan-features-list.js +10 -3
  12. package/dist/cjs/components/features-grid/plan-features-list.js.map +1 -1
  13. package/dist/cjs/components/features-grid/plan-headers.js +2 -2
  14. package/dist/cjs/components/features-grid/plan-headers.js.map +1 -1
  15. package/dist/cjs/components/features-grid/plan-tagline.js +1 -1
  16. package/dist/cjs/components/features-grid/plan-tagline.js.map +1 -1
  17. package/dist/cjs/components/features-grid/style.scss +111 -21
  18. package/dist/cjs/components/features-grid/table.js +1 -1
  19. package/dist/cjs/components/features-grid/table.js.map +1 -1
  20. package/dist/cjs/components/features.js +43 -4
  21. package/dist/cjs/components/features.js.map +1 -1
  22. package/dist/cjs/components/item.js +1 -1
  23. package/dist/cjs/components/item.js.map +1 -1
  24. package/dist/cjs/components/plan-button/index.js +5 -3
  25. package/dist/cjs/components/plan-button/index.js.map +1 -1
  26. package/dist/cjs/components/plan-button/style.scss +71 -47
  27. package/dist/cjs/components/plan-div-td-container.js +4 -1
  28. package/dist/cjs/components/plan-div-td-container.js.map +1 -1
  29. package/dist/cjs/components/plan-logo.js +6 -3
  30. package/dist/cjs/components/plan-logo.js.map +1 -1
  31. package/dist/cjs/components/plan-type-selector/components/interval-type-dropdown.js +12 -1
  32. package/dist/cjs/components/plan-type-selector/components/interval-type-dropdown.js.map +1 -1
  33. package/dist/cjs/components/plan-type-selector/hooks/use-max-discount.js +4 -33
  34. package/dist/cjs/components/plan-type-selector/hooks/use-max-discount.js.map +1 -1
  35. package/dist/cjs/components/plan-type-selector/hooks/use-max-discounts-for-plan-terms.js +11 -13
  36. package/dist/cjs/components/plan-type-selector/hooks/use-max-discounts-for-plan-terms.js.map +1 -1
  37. package/dist/cjs/components/plans-2023-tooltip.js +16 -5
  38. package/dist/cjs/components/plans-2023-tooltip.js.map +1 -1
  39. package/dist/cjs/components/shared/action-button/index.js +22 -7
  40. package/dist/cjs/components/shared/action-button/index.js.map +1 -1
  41. package/dist/cjs/components/shared/action-button/style.scss +4 -0
  42. package/dist/cjs/components/shared/billing-timeframe/index.js +8 -4
  43. package/dist/cjs/components/shared/billing-timeframe/index.js.map +1 -1
  44. package/dist/cjs/components/shared/header-price/index.js +60 -15
  45. package/dist/cjs/components/shared/header-price/index.js.map +1 -1
  46. package/dist/cjs/components/shared/header-price/style.scss +10 -2
  47. package/dist/cjs/components/shared/storage/components/plan-storage.js +2 -2
  48. package/dist/cjs/components/shared/storage/components/plan-storage.js.map +1 -1
  49. package/dist/cjs/components/shared/storage/components/storage-dropdown.js +29 -6
  50. package/dist/cjs/components/shared/storage/components/storage-dropdown.js.map +1 -1
  51. package/dist/cjs/components/shared/storage/components/storage-feature-label.js +2 -1
  52. package/dist/cjs/components/shared/storage/components/storage-feature-label.js.map +1 -1
  53. package/dist/cjs/components/shared/storage/hooks/use-plan-storage.js +2 -0
  54. package/dist/cjs/components/shared/storage/hooks/use-plan-storage.js.map +1 -1
  55. package/dist/cjs/fixtures/sites-purchases.js +2 -4
  56. package/dist/cjs/fixtures/sites-purchases.js.map +1 -1
  57. package/dist/cjs/grid-context.js +4 -1
  58. package/dist/cjs/grid-context.js.map +1 -1
  59. package/dist/cjs/hooks/data-store/get-renewal-pricing-text.js +50 -0
  60. package/dist/cjs/hooks/data-store/get-renewal-pricing-text.js.map +1 -0
  61. package/dist/cjs/hooks/data-store/use-grid-plans-for-comparison-grid.js +6 -1
  62. package/dist/cjs/hooks/data-store/use-grid-plans-for-comparison-grid.js.map +1 -1
  63. package/dist/cjs/hooks/data-store/use-grid-plans-for-features-grid.js +6 -1
  64. package/dist/cjs/hooks/data-store/use-grid-plans-for-features-grid.js.map +1 -1
  65. package/dist/cjs/hooks/data-store/use-grid-plans.js +175 -21
  66. package/dist/cjs/hooks/data-store/use-grid-plans.js.map +1 -1
  67. package/dist/cjs/hooks/data-store/use-highlight-labels.js +13 -4
  68. package/dist/cjs/hooks/data-store/use-highlight-labels.js.map +1 -1
  69. package/dist/cjs/hooks/data-store/use-plan-billing-description.js +68 -13
  70. package/dist/cjs/hooks/data-store/use-plan-billing-description.js.map +1 -1
  71. package/dist/cjs/hooks/data-store/use-plan-billing-period.js +14 -0
  72. package/dist/cjs/hooks/data-store/use-plan-billing-period.js.map +1 -0
  73. package/dist/cjs/hooks/data-store/use-plan-features-for-grid-plans.js +76 -2
  74. package/dist/cjs/hooks/data-store/use-plan-features-for-grid-plans.js.map +1 -1
  75. package/dist/cjs/hooks/data-store/use-restructured-plan-features-for-comparison-grid.js +60 -12
  76. package/dist/cjs/hooks/data-store/use-restructured-plan-features-for-comparison-grid.js.map +1 -1
  77. package/dist/cjs/hooks/data-store/use-title-badges.js +19 -0
  78. package/dist/cjs/hooks/data-store/use-title-badges.js.map +1 -0
  79. package/dist/cjs/hooks/use-grid-size.js.map +1 -1
  80. package/dist/cjs/hooks/use-is-large-currency.js +2 -2
  81. package/dist/cjs/hooks/use-is-large-currency.js.map +1 -1
  82. package/dist/cjs/hooks/use-visible-grid-plans.js +70 -0
  83. package/dist/cjs/hooks/use-visible-grid-plans.js.map +1 -0
  84. package/dist/cjs/index.js +8 -1
  85. package/dist/cjs/index.js.map +1 -1
  86. package/dist/cjs/lib/get-plan-features-object.js +15 -2
  87. package/dist/cjs/lib/get-plan-features-object.js.map +1 -1
  88. package/dist/cjs/lib/plan-pricing-utils.js +135 -0
  89. package/dist/cjs/lib/plan-pricing-utils.js.map +1 -0
  90. package/dist/esm/_shared.scss +4 -3
  91. package/dist/esm/components/comparison-grid/index.js +102 -72
  92. package/dist/esm/components/comparison-grid/index.js.map +1 -1
  93. package/dist/esm/components/comparison-grid/index.stories.js.map +1 -1
  94. package/dist/esm/components/comparison-grid/style.scss +10 -2
  95. package/dist/esm/components/features-grid/client-logo-list/client-list.js +0 -12
  96. package/dist/esm/components/features-grid/client-logo-list/client-list.js.map +1 -1
  97. package/dist/esm/components/features-grid/index.js +9 -6
  98. package/dist/esm/components/features-grid/index.js.map +1 -1
  99. package/dist/esm/components/features-grid/plan-features-list.js +10 -3
  100. package/dist/esm/components/features-grid/plan-features-list.js.map +1 -1
  101. package/dist/esm/components/features-grid/plan-headers.js +3 -3
  102. package/dist/esm/components/features-grid/plan-headers.js.map +1 -1
  103. package/dist/esm/components/features-grid/plan-tagline.js +1 -1
  104. package/dist/esm/components/features-grid/plan-tagline.js.map +1 -1
  105. package/dist/esm/components/features-grid/style.scss +111 -21
  106. package/dist/esm/components/features-grid/table.js +1 -1
  107. package/dist/esm/components/features-grid/table.js.map +1 -1
  108. package/dist/esm/components/features.js +44 -5
  109. package/dist/esm/components/features.js.map +1 -1
  110. package/dist/esm/components/item.js +1 -1
  111. package/dist/esm/components/item.js.map +1 -1
  112. package/dist/esm/components/plan-button/index.js +5 -3
  113. package/dist/esm/components/plan-button/index.js.map +1 -1
  114. package/dist/esm/components/plan-button/style.scss +71 -47
  115. package/dist/esm/components/plan-div-td-container.js +4 -1
  116. package/dist/esm/components/plan-div-td-container.js.map +1 -1
  117. package/dist/esm/components/plan-logo.js +7 -4
  118. package/dist/esm/components/plan-logo.js.map +1 -1
  119. package/dist/esm/components/plan-type-selector/components/interval-type-dropdown.js +12 -1
  120. package/dist/esm/components/plan-type-selector/components/interval-type-dropdown.js.map +1 -1
  121. package/dist/esm/components/plan-type-selector/hooks/use-max-discount.js +3 -33
  122. package/dist/esm/components/plan-type-selector/hooks/use-max-discount.js.map +1 -1
  123. package/dist/esm/components/plan-type-selector/hooks/use-max-discounts-for-plan-terms.js +11 -13
  124. package/dist/esm/components/plan-type-selector/hooks/use-max-discounts-for-plan-terms.js.map +1 -1
  125. package/dist/esm/components/plans-2023-tooltip.js +16 -5
  126. package/dist/esm/components/plans-2023-tooltip.js.map +1 -1
  127. package/dist/esm/components/shared/action-button/index.js +22 -7
  128. package/dist/esm/components/shared/action-button/index.js.map +1 -1
  129. package/dist/esm/components/shared/action-button/style.scss +4 -0
  130. package/dist/esm/components/shared/billing-timeframe/index.js +8 -4
  131. package/dist/esm/components/shared/billing-timeframe/index.js.map +1 -1
  132. package/dist/esm/components/shared/header-price/index.js +60 -15
  133. package/dist/esm/components/shared/header-price/index.js.map +1 -1
  134. package/dist/esm/components/shared/header-price/style.scss +10 -2
  135. package/dist/esm/components/shared/storage/components/plan-storage.js +2 -2
  136. package/dist/esm/components/shared/storage/components/plan-storage.js.map +1 -1
  137. package/dist/esm/components/shared/storage/components/storage-dropdown.js +30 -7
  138. package/dist/esm/components/shared/storage/components/storage-dropdown.js.map +1 -1
  139. package/dist/esm/components/shared/storage/components/storage-feature-label.js +2 -1
  140. package/dist/esm/components/shared/storage/components/storage-feature-label.js.map +1 -1
  141. package/dist/esm/components/shared/storage/hooks/use-plan-storage.js +3 -1
  142. package/dist/esm/components/shared/storage/hooks/use-plan-storage.js.map +1 -1
  143. package/dist/esm/fixtures/sites-purchases.js +2 -4
  144. package/dist/esm/fixtures/sites-purchases.js.map +1 -1
  145. package/dist/esm/grid-context.js +4 -1
  146. package/dist/esm/grid-context.js.map +1 -1
  147. package/dist/esm/hooks/data-store/get-renewal-pricing-text.js +47 -0
  148. package/dist/esm/hooks/data-store/get-renewal-pricing-text.js.map +1 -0
  149. package/dist/esm/hooks/data-store/use-grid-plans-for-comparison-grid.js +6 -1
  150. package/dist/esm/hooks/data-store/use-grid-plans-for-comparison-grid.js.map +1 -1
  151. package/dist/esm/hooks/data-store/use-grid-plans-for-features-grid.js +6 -1
  152. package/dist/esm/hooks/data-store/use-grid-plans-for-features-grid.js.map +1 -1
  153. package/dist/esm/hooks/data-store/use-grid-plans.js +176 -22
  154. package/dist/esm/hooks/data-store/use-grid-plans.js.map +1 -1
  155. package/dist/esm/hooks/data-store/use-highlight-labels.js +14 -5
  156. package/dist/esm/hooks/data-store/use-highlight-labels.js.map +1 -1
  157. package/dist/esm/hooks/data-store/use-plan-billing-description.js +66 -11
  158. package/dist/esm/hooks/data-store/use-plan-billing-description.js.map +1 -1
  159. package/dist/esm/hooks/data-store/use-plan-billing-period.js +12 -0
  160. package/dist/esm/hooks/data-store/use-plan-billing-period.js.map +1 -0
  161. package/dist/esm/hooks/data-store/use-plan-features-for-grid-plans.js +77 -3
  162. package/dist/esm/hooks/data-store/use-plan-features-for-grid-plans.js.map +1 -1
  163. package/dist/esm/hooks/data-store/use-restructured-plan-features-for-comparison-grid.js +59 -11
  164. package/dist/esm/hooks/data-store/use-restructured-plan-features-for-comparison-grid.js.map +1 -1
  165. package/dist/esm/hooks/data-store/use-title-badges.js +17 -0
  166. package/dist/esm/hooks/data-store/use-title-badges.js.map +1 -0
  167. package/dist/esm/hooks/use-grid-size.js.map +1 -1
  168. package/dist/esm/hooks/use-is-large-currency.js +1 -1
  169. package/dist/esm/hooks/use-is-large-currency.js.map +1 -1
  170. package/dist/esm/hooks/use-visible-grid-plans.js +66 -0
  171. package/dist/esm/hooks/use-visible-grid-plans.js.map +1 -0
  172. package/dist/esm/index.js +4 -1
  173. package/dist/esm/index.js.map +1 -1
  174. package/dist/esm/lib/get-plan-features-object.js +15 -2
  175. package/dist/esm/lib/get-plan-features-object.js.map +1 -1
  176. package/dist/esm/lib/plan-pricing-utils.js +129 -0
  177. package/dist/esm/lib/plan-pricing-utils.js.map +1 -0
  178. package/dist/tsconfig-cjs.tsbuildinfo +1 -1
  179. package/dist/tsconfig.tsbuildinfo +1 -1
  180. package/dist/types/components/comparison-grid/index.d.ts +1 -1
  181. package/dist/types/components/comparison-grid/index.d.ts.map +1 -1
  182. package/dist/types/components/comparison-grid/index.stories.d.ts +2 -2
  183. package/dist/types/components/dropdown-option.d.ts.map +1 -1
  184. package/dist/types/components/features-grid/billing-timeframes.d.ts.map +1 -1
  185. package/dist/types/components/features-grid/client-logo-list/client-list.d.ts.map +1 -1
  186. package/dist/types/components/features-grid/client-logo-list/index.d.ts.map +1 -1
  187. package/dist/types/components/features-grid/enterprise-features.d.ts.map +1 -1
  188. package/dist/types/components/features-grid/index.d.ts.map +1 -1
  189. package/dist/types/components/features-grid/plan-features-list.d.ts.map +1 -1
  190. package/dist/types/components/features-grid/plan-headers.d.ts +2 -0
  191. package/dist/types/components/features-grid/plan-headers.d.ts.map +1 -1
  192. package/dist/types/components/features-grid/plan-logos.d.ts.map +1 -1
  193. package/dist/types/components/features-grid/plan-prices.d.ts.map +1 -1
  194. package/dist/types/components/features-grid/plan-tagline.d.ts.map +1 -1
  195. package/dist/types/components/features-grid/previous-features-included-title.d.ts.map +1 -1
  196. package/dist/types/components/features-grid/spotlight-plan.d.ts.map +1 -1
  197. package/dist/types/components/features-grid/table.d.ts.map +1 -1
  198. package/dist/types/components/features-grid/top-buttons.d.ts.map +1 -1
  199. package/dist/types/components/features.d.ts.map +1 -1
  200. package/dist/types/components/item.d.ts +2 -1
  201. package/dist/types/components/item.d.ts.map +1 -1
  202. package/dist/types/components/plan-button/index.d.ts +2 -1
  203. package/dist/types/components/plan-button/index.d.ts.map +1 -1
  204. package/dist/types/components/plan-div-td-container.d.ts +2 -0
  205. package/dist/types/components/plan-div-td-container.d.ts.map +1 -1
  206. package/dist/types/components/plan-logo.d.ts.map +1 -1
  207. package/dist/types/components/plan-type-selector/components/interval-type-dropdown.d.ts.map +1 -1
  208. package/dist/types/components/plan-type-selector/hooks/use-max-discount.d.ts.map +1 -1
  209. package/dist/types/components/plan-type-selector/hooks/use-max-discounts-for-plan-terms.d.ts.map +1 -1
  210. package/dist/types/components/plans-2023-tooltip.d.ts.map +1 -1
  211. package/dist/types/components/shared/action-button/index.d.ts +2 -1
  212. package/dist/types/components/shared/action-button/index.d.ts.map +1 -1
  213. package/dist/types/components/shared/billing-timeframe/index.d.ts.map +1 -1
  214. package/dist/types/components/shared/header-price/header-price-context.d.ts.map +1 -1
  215. package/dist/types/components/shared/header-price/index.d.ts.map +1 -1
  216. package/dist/types/components/shared/storage/components/plan-storage.d.ts.map +1 -1
  217. package/dist/types/components/shared/storage/components/storage-dropdown.d.ts.map +1 -1
  218. package/dist/types/components/shared/storage/components/storage-feature-label.d.ts.map +1 -1
  219. package/dist/types/components/shared/storage/hooks/use-plan-storage.d.ts +1 -1
  220. package/dist/types/components/shared/storage/hooks/use-plan-storage.d.ts.map +1 -1
  221. package/dist/types/css-mixins.d.ts.map +1 -1
  222. package/dist/types/fixtures/sites-purchases.d.ts +2 -4
  223. package/dist/types/fixtures/sites-purchases.d.ts.map +1 -1
  224. package/dist/types/grid-context.d.ts +4 -1
  225. package/dist/types/grid-context.d.ts.map +1 -1
  226. package/dist/types/hooks/data-store/get-renewal-pricing-text.d.ts +14 -0
  227. package/dist/types/hooks/data-store/get-renewal-pricing-text.d.ts.map +1 -0
  228. package/dist/types/hooks/data-store/types.d.ts +21 -0
  229. package/dist/types/hooks/data-store/types.d.ts.map +1 -1
  230. package/dist/types/hooks/data-store/use-grid-plan-for-spotlight.d.ts.map +1 -1
  231. package/dist/types/hooks/data-store/use-grid-plans-for-comparison-grid.d.ts +1 -1
  232. package/dist/types/hooks/data-store/use-grid-plans-for-comparison-grid.d.ts.map +1 -1
  233. package/dist/types/hooks/data-store/use-grid-plans-for-features-grid.d.ts +1 -1
  234. package/dist/types/hooks/data-store/use-grid-plans-for-features-grid.d.ts.map +1 -1
  235. package/dist/types/hooks/data-store/use-grid-plans.d.ts.map +1 -1
  236. package/dist/types/hooks/data-store/use-highlight-labels.d.ts.map +1 -1
  237. package/dist/types/hooks/data-store/use-plan-billing-description.d.ts.map +1 -1
  238. package/dist/types/hooks/data-store/use-plan-billing-period.d.ts +8 -0
  239. package/dist/types/hooks/data-store/use-plan-billing-period.d.ts.map +1 -0
  240. package/dist/types/hooks/data-store/use-plan-features-for-grid-plans.d.ts +4 -1
  241. package/dist/types/hooks/data-store/use-plan-features-for-grid-plans.d.ts.map +1 -1
  242. package/dist/types/hooks/data-store/use-plans-from-types.d.ts.map +1 -1
  243. package/dist/types/hooks/data-store/use-restructured-plan-features-for-comparison-grid.d.ts +4 -1
  244. package/dist/types/hooks/data-store/use-restructured-plan-features-for-comparison-grid.d.ts.map +1 -1
  245. package/dist/types/hooks/data-store/use-title-badges.d.ts +9 -0
  246. package/dist/types/hooks/data-store/use-title-badges.d.ts.map +1 -0
  247. package/dist/types/hooks/use-grid-size.d.ts +3 -2
  248. package/dist/types/hooks/use-grid-size.d.ts.map +1 -1
  249. package/dist/types/hooks/use-highlight-adjacency-matrix.d.ts.map +1 -1
  250. package/dist/types/hooks/use-visible-grid-plans.d.ts +14 -0
  251. package/dist/types/hooks/use-visible-grid-plans.d.ts.map +1 -0
  252. package/dist/types/index.d.ts +9 -1
  253. package/dist/types/index.d.ts.map +1 -1
  254. package/dist/types/lib/filter-unused-features-object.d.ts.map +1 -1
  255. package/dist/types/lib/get-plan-features-object.d.ts +1 -1
  256. package/dist/types/lib/get-plan-features-object.d.ts.map +1 -1
  257. package/dist/types/lib/plan-pricing-utils.d.ts +105 -0
  258. package/dist/types/lib/plan-pricing-utils.d.ts.map +1 -0
  259. package/dist/types/types.d.ts +33 -6
  260. package/dist/types/types.d.ts.map +1 -1
  261. package/package.json +39 -28
  262. package/src/_shared.scss +4 -3
  263. package/src/components/comparison-grid/index.stories.tsx +1 -1
  264. package/src/components/comparison-grid/index.tsx +263 -158
  265. package/src/components/comparison-grid/style.scss +10 -2
  266. package/src/components/features-grid/client-logo-list/client-list.tsx +0 -25
  267. package/src/components/features-grid/index.tsx +37 -19
  268. package/src/components/features-grid/plan-features-list.tsx +15 -4
  269. package/src/components/features-grid/plan-headers.tsx +10 -3
  270. package/src/components/features-grid/plan-tagline.tsx +1 -1
  271. package/src/components/features-grid/style.scss +111 -21
  272. package/src/components/features-grid/table.tsx +4 -2
  273. package/src/components/features.tsx +66 -6
  274. package/src/components/item.tsx +6 -3
  275. package/src/components/plan-button/index.tsx +7 -1
  276. package/src/components/plan-button/style.scss +71 -47
  277. package/src/components/plan-div-td-container.tsx +6 -2
  278. package/src/components/plan-logo.tsx +16 -9
  279. package/src/components/plan-type-selector/components/interval-type-dropdown.tsx +14 -1
  280. package/src/components/plan-type-selector/hooks/use-max-discount.ts +8 -47
  281. package/src/components/plan-type-selector/hooks/use-max-discounts-for-plan-terms.ts +19 -17
  282. package/src/components/plans-2023-tooltip.tsx +17 -5
  283. package/src/components/shared/action-button/index.tsx +46 -5
  284. package/src/components/shared/action-button/style.scss +4 -0
  285. package/src/components/shared/billing-timeframe/index.tsx +12 -7
  286. package/src/components/shared/header-price/index.tsx +129 -27
  287. package/src/components/shared/header-price/style.scss +10 -2
  288. package/src/components/shared/storage/components/plan-storage.tsx +2 -2
  289. package/src/components/shared/storage/components/storage-dropdown.tsx +36 -15
  290. package/src/components/shared/storage/components/storage-feature-label.tsx +2 -1
  291. package/src/components/shared/storage/hooks/use-plan-storage.ts +3 -0
  292. package/src/components/test/actions-button.tsx +5 -0
  293. package/src/components/test/billing-timeframe.tsx +1 -1
  294. package/src/components/test/header-price.tsx +342 -4
  295. package/src/fixtures/sites-purchases.ts +2 -4
  296. package/src/grid-context.tsx +9 -0
  297. package/src/hooks/data-store/get-renewal-pricing-text.ts +73 -0
  298. package/src/hooks/data-store/types.ts +21 -0
  299. package/src/hooks/data-store/use-grid-plans-for-comparison-grid.ts +10 -0
  300. package/src/hooks/data-store/use-grid-plans-for-features-grid.ts +10 -0
  301. package/src/hooks/data-store/use-grid-plans.tsx +189 -23
  302. package/src/hooks/data-store/use-highlight-labels.ts +12 -3
  303. package/src/hooks/data-store/use-plan-billing-description.tsx +80 -15
  304. package/src/hooks/data-store/use-plan-billing-period.tsx +28 -0
  305. package/src/hooks/data-store/use-plan-features-for-grid-plans.ts +135 -1
  306. package/src/hooks/data-store/use-restructured-plan-features-for-comparison-grid.ts +93 -20
  307. package/src/hooks/data-store/use-title-badges.ts +31 -0
  308. package/src/hooks/test/use-visible-grid-plans.tsx +116 -0
  309. package/src/hooks/use-grid-size.ts +3 -2
  310. package/src/hooks/use-is-large-currency.ts +1 -1
  311. package/src/hooks/use-visible-grid-plans.tsx +102 -0
  312. package/src/index.tsx +20 -0
  313. package/src/lib/get-plan-features-object.ts +23 -2
  314. package/src/lib/plan-pricing-utils.ts +211 -0
  315. package/src/lib/test/plan-pricing-utils.ts +594 -0
  316. package/src/style-imports.d.ts +3 -0
  317. package/src/types.ts +45 -4
  318. package/dist/cjs/components/features-grid/mobile-free-domain.js +0 -25
  319. package/dist/cjs/components/features-grid/mobile-free-domain.js.map +0 -1
  320. package/dist/cjs/lib/get-plan-pricing-info-from-grid-plans.js +0 -15
  321. package/dist/cjs/lib/get-plan-pricing-info-from-grid-plans.js.map +0 -1
  322. package/dist/cjs/lib/sort-plan-properties.js +0 -26
  323. package/dist/cjs/lib/sort-plan-properties.js.map +0 -1
  324. package/dist/esm/components/features-grid/mobile-free-domain.js +0 -23
  325. package/dist/esm/components/features-grid/mobile-free-domain.js.map +0 -1
  326. package/dist/esm/lib/get-plan-pricing-info-from-grid-plans.js +0 -12
  327. package/dist/esm/lib/get-plan-pricing-info-from-grid-plans.js.map +0 -1
  328. package/dist/esm/lib/sort-plan-properties.js +0 -23
  329. package/dist/esm/lib/sort-plan-properties.js.map +0 -1
  330. package/dist/types/components/features-grid/mobile-free-domain.d.ts +0 -8
  331. package/dist/types/components/features-grid/mobile-free-domain.d.ts.map +0 -1
  332. package/dist/types/lib/get-plan-pricing-info-from-grid-plans.d.ts +0 -9
  333. package/dist/types/lib/get-plan-pricing-info-from-grid-plans.d.ts.map +0 -1
  334. package/dist/types/lib/sort-plan-properties.d.ts +0 -3
  335. package/dist/types/lib/sort-plan-properties.d.ts.map +0 -1
  336. package/src/components/features-grid/mobile-free-domain.tsx +0 -51
  337. package/src/lib/get-plan-pricing-info-from-grid-plans.ts +0 -31
  338. package/src/lib/sort-plan-properties.ts +0 -27
  339. package/src/lib/test/sort-plan-properties.ts +0 -122
@@ -3,6 +3,9 @@ import {
3
3
  FEATURE_GROUP_ESSENTIAL_FEATURES,
4
4
  FEATURE_GROUP_PAYMENT_TRANSACTION_FEES,
5
5
  getPlans,
6
+ FEATURE_AI_WRITER_DESIGNER,
7
+ FEATURE_AI_WRITER_DESIGNER_LIMITED,
8
+ FEATURE_REALTIME_BACKUPS_JP,
6
9
  } from '@automattic/calypso-products';
7
10
  import { Gridicon, JetpackLogo } from '@automattic/components';
8
11
  import { AddOns } from '@automattic/data-stores';
@@ -27,9 +30,9 @@ import PlansGridContextProvider, { usePlansGridContext } from '../../grid-contex
27
30
  import useGridSize from '../../hooks/use-grid-size';
28
31
  import useHighlightAdjacencyMatrix from '../../hooks/use-highlight-adjacency-matrix';
29
32
  import { useManageTooltipToggle } from '../../hooks/use-manage-tooltip-toggle';
33
+ import { useVisibleGridPlans } from '../../hooks/use-visible-grid-plans';
30
34
  import filterUnusedFeaturesObject from '../../lib/filter-unused-features-object';
31
35
  import getPlanFeaturesObject from '../../lib/get-plan-features-object';
32
- import { sortPlans } from '../../lib/sort-plan-properties';
33
36
  import PlanTypeSelector from '../plan-type-selector';
34
37
  import { Plans2023Tooltip } from '../plans-2023-tooltip';
35
38
  import PopularBadge from '../popular-badge';
@@ -46,6 +49,7 @@ import type {
46
49
  PlanActionOverrides,
47
50
  TransformedFeatureObject,
48
51
  PlanTypeSelectorProps,
52
+ GridSize,
49
53
  } from '../../types';
50
54
  import type {
51
55
  FeatureObject,
@@ -56,16 +60,37 @@ import type {
56
60
  } from '@automattic/calypso-products';
57
61
  import './style.scss';
58
62
 
63
+ // Plans Differentiators Experiment: treat feature variants (e.g., _LIMITED) as the same row
64
+ const FEATURE_ALIASES: Record< string, string[] > = {
65
+ [ FEATURE_AI_WRITER_DESIGNER ]: [ FEATURE_AI_WRITER_DESIGNER_LIMITED ],
66
+ };
67
+
68
+ // Finds a matching feature, checking both the base slug and any aliases
69
+ const findFeatureWithAlias = (
70
+ featureSlug: string | undefined,
71
+ planFeatures: { getSlug: () => string }[]
72
+ ) => {
73
+ if ( ! featureSlug ) {
74
+ return undefined;
75
+ }
76
+ const slugsToCheck = [ featureSlug, ...( FEATURE_ALIASES[ featureSlug ] ?? [] ) ];
77
+ return planFeatures.find( ( f ) => slugsToCheck.includes( f.getSlug() ) );
78
+ };
79
+
59
80
  const featureGroupRowTitleCellMaxWidth = 450;
60
81
  const rowCellMaxWidth = 290;
61
82
 
62
83
  const JetpackIconContainer = styled.div`
63
- padding-inline-start: 6px;
84
+ padding-inline-start: 3px;
64
85
  display: inline-block;
65
86
  vertical-align: middle;
66
87
  line-height: 1;
67
88
  `;
68
89
 
90
+ const TitlePreventOrphans = styled.span`
91
+ white-space: nowrap;
92
+ `;
93
+
69
94
  const Title = styled.div< { isHiddenInMobile?: boolean } >`
70
95
  font-weight: 500;
71
96
  font-size: 20px;
@@ -96,11 +121,10 @@ const Title = styled.div< { isHiddenInMobile?: boolean } >`
96
121
  ` ) }
97
122
  `;
98
123
 
99
- const Grid = styled.div< { visiblePlans: number } >`
124
+ const StickyGrid = styled( StickyContainer )< { visiblePlans: number } >`
100
125
  display: grid;
101
126
  margin: 0 auto;
102
127
  background: #fff;
103
- border: solid 1px #e0e0e0;
104
128
  ${ ( props ) =>
105
129
  props.visiblePlans &&
106
130
  css`
@@ -110,11 +134,21 @@ const Grid = styled.div< { visiblePlans: number } >`
110
134
  ${ plansGridMediumLarge( css`
111
135
  border-radius: 5px;
112
136
  ` ) }
137
+ `;
113
138
 
114
- > .is-sticky-header-row {
115
- border-bottom: solid 1px #e0e0e0;
116
- background: #fff;
117
- }
139
+ const Grid = styled.div< { visiblePlans: number; as?: string } >`
140
+ display: ${ ( props ) => ( props.as === 'tbody' ? 'table-row-group' : 'grid' ) };
141
+ margin: 0 auto;
142
+ background: #fff;
143
+ ${ ( props ) =>
144
+ props.visiblePlans &&
145
+ css`
146
+ max-width: ${ rowCellMaxWidth * props.visiblePlans + featureGroupRowTitleCellMaxWidth }px;
147
+ ` }
148
+
149
+ ${ plansGridMediumLarge( css`
150
+ border-radius: 5px;
151
+ ` ) }
118
152
  `;
119
153
 
120
154
  const Row = styled.div< {
@@ -218,7 +252,7 @@ const Cell = styled.div< { textAlign?: 'start' | 'center' | 'end' } >`
218
252
  border-right: none;
219
253
  justify-content: center;
220
254
 
221
- &:first-of-type {
255
+ &:first-of-type:not( .popular-plan-parent-class ) {
222
256
  padding-inline-start: 0;
223
257
  }
224
258
  &:last-of-type {
@@ -232,7 +266,27 @@ const Cell = styled.div< { textAlign?: 'start' | 'center' | 'end' } >`
232
266
  ` ) }
233
267
  `;
234
268
 
235
- const RowTitleCell = styled.div< {
269
+ const RowTitleCell = styled.td< {
270
+ isPlaceholderHeaderCell?: boolean;
271
+ isFeatureGroupRowTitleCell?: boolean;
272
+ } >`
273
+ display: none;
274
+ font-size: 14px;
275
+ padding-right: 10px;
276
+ ${ plansGridMediumLarge( css`
277
+ display: block;
278
+ flex: 1;
279
+ min-width: 290px;
280
+ ` ) }
281
+ max-width: ${ ( props ) => {
282
+ if ( props.isPlaceholderHeaderCell || props.isFeatureGroupRowTitleCell ) {
283
+ return `${ featureGroupRowTitleCellMaxWidth }px`;
284
+ }
285
+ return `${ rowCellMaxWidth }px`;
286
+ } };
287
+ `;
288
+
289
+ const RowHeaderCell = styled.th< {
236
290
  isPlaceholderHeaderCell?: boolean;
237
291
  isFeatureGroupRowTitleCell?: boolean;
238
292
  } >`
@@ -361,7 +415,7 @@ const ComparisonGridHeaderCell = ( {
361
415
  showRefundPeriod,
362
416
  isStuck,
363
417
  }: ComparisonGridHeaderCellProps ) => {
364
- const { gridPlansIndex } = usePlansGridContext();
418
+ const { gridPlansIndex, showBillingDescriptionForIncreasedRenewalPrice } = usePlansGridContext();
365
419
  const gridPlan = gridPlansIndex[ planSlug ];
366
420
  const highlightAdjacencyMatrix = useHighlightAdjacencyMatrix( {
367
421
  renderedGridPlans: visibleGridPlans,
@@ -388,7 +442,13 @@ const ComparisonGridHeaderCell = ( {
388
442
  const showPlanSelect = ! allVisible && ! gridPlan.current;
389
443
 
390
444
  return (
391
- <Cell className={ headerClasses } textAlign="start">
445
+ <Cell
446
+ as="th"
447
+ className={ headerClasses }
448
+ textAlign="start"
449
+ { ...{ scope: 'col' } }
450
+ aria-label={ gridPlan.planTitle as string }
451
+ >
392
452
  <PopularBadge
393
453
  isInSignup={ isInSignup }
394
454
  planSlug={ planSlug }
@@ -448,6 +508,7 @@ const ComparisonGridHeaderCell = ( {
448
508
  showMonthlyPrice={ false }
449
509
  isStuck={ false }
450
510
  visibleGridPlans={ visibleGridPlans }
511
+ showPostButtonText={ showBillingDescriptionForIncreasedRenewalPrice ? false : true }
451
512
  />
452
513
  </Cell>
453
514
  );
@@ -483,7 +544,7 @@ const ComparisonGridHeader = forwardRef< HTMLDivElement, ComparisonGridHeaderPro
483
544
  const { coupon } = usePlansGridContext();
484
545
 
485
546
  return (
486
- <PlanRow isHiddenInMobile={ isHiddenInMobile } ref={ ref }>
547
+ <PlanRow as="tr" isHiddenInMobile={ isHiddenInMobile } ref={ ref }>
487
548
  <RowTitleCell
488
549
  key="feature-name"
489
550
  className="plan-comparison-grid__header-cell is-placeholder-header-cell"
@@ -524,6 +585,7 @@ const ComparisonGridHeader = forwardRef< HTMLDivElement, ComparisonGridHeaderPro
524
585
  );
525
586
  }
526
587
  );
588
+ ComparisonGridHeader.displayName = 'ComparisonGridHeader';
527
589
 
528
590
  const ComparisonGridFeatureGroupRowCell: React.FunctionComponent< {
529
591
  feature?: FeatureObject;
@@ -559,19 +621,23 @@ const ComparisonGridFeatureGroupRowCell: React.FunctionComponent< {
559
621
  }
560
622
 
561
623
  const featureSlug = feature?.getSlug();
624
+ const comparisonGridTitle =
625
+ featureSlug === FEATURE_REALTIME_BACKUPS_JP
626
+ ? translate( 'Real-time backups', { textOnly: true } )
627
+ : feature?.getAlternativeTitle?.() || feature?.getTitle();
628
+
629
+ const planFeatures = [
630
+ ...gridPlan.features.wpcomFeatures,
631
+ ...gridPlan.features.jetpackFeatures,
632
+ ].filter( ( feature ) =>
633
+ 'monthly' === intervalType ? ! feature.availableOnlyForAnnualPlans : true
634
+ );
562
635
 
563
- const hasFeature =
564
- isStorageFeature ||
565
- ( featureSlug
566
- ? [ ...gridPlan.features.wpcomFeatures, ...gridPlan.features.jetpackFeatures ]
567
- .filter( ( feature ) =>
568
- 'monthly' === intervalType ? ! feature.availableOnlyForAnnualPlans : true
569
- )
570
- .some( ( feature ) => feature.getSlug() === featureSlug )
571
- : false );
572
-
573
- const featureLabel = featureSlug
574
- ? gridPlan?.features?.comparisonGridFeatureLabels?.[ featureSlug ]
636
+ const matchingFeature = findFeatureWithAlias( featureSlug, planFeatures );
637
+ const hasFeature = isStorageFeature || !! matchingFeature;
638
+ const featureLabelSlug = matchingFeature?.getSlug() ?? featureSlug;
639
+ const featureLabel = featureLabelSlug
640
+ ? gridPlan?.features?.comparisonGridFeatureLabels?.[ featureLabelSlug ]
575
641
  : undefined;
576
642
 
577
643
  const cellClasses = clsx(
@@ -594,7 +660,7 @@ const ComparisonGridFeatureGroupRowCell: React.FunctionComponent< {
594
660
  );
595
661
 
596
662
  return (
597
- <Cell className={ cellClasses } textAlign="center">
663
+ <Cell as="td" className={ cellClasses } textAlign="center">
598
664
  { isStorageFeature ? (
599
665
  <>
600
666
  <span className="plan-comparison-grid__plan-title">{ translate( 'Storage' ) }</span>
@@ -617,7 +683,7 @@ const ComparisonGridFeatureGroupRowCell: React.FunctionComponent< {
617
683
  id={ `${ planSlug }-${ featureSlug }` }
618
684
  >
619
685
  <span className="plan-comparison-grid__plan-title">
620
- { feature?.getAlternativeTitle?.() || feature?.getTitle() }
686
+ { comparisonGridTitle }
621
687
  </span>
622
688
  </Plans2023Tooltip>
623
689
  <span className="plan-comparison-grid__plan-conditional-title">
@@ -642,9 +708,7 @@ const ComparisonGridFeatureGroupRowCell: React.FunctionComponent< {
642
708
  activeTooltipId={ activeTooltipId }
643
709
  id={ `${ planSlug }-${ featureSlug }` }
644
710
  >
645
- <span className="plan-comparison-grid__plan-title">
646
- { feature?.getAlternativeTitle?.() || feature?.getTitle() }
647
- </span>
711
+ <span className="plan-comparison-grid__plan-title">{ comparisonGridTitle }</span>
648
712
  </Plans2023Tooltip>
649
713
  { feature?.getCompareTitle && (
650
714
  <span className="plan-comparison-grid__plan-subtitle">
@@ -662,9 +726,19 @@ const ComparisonGridFeatureGroupRowCell: React.FunctionComponent< {
662
726
  </span>
663
727
  ) }
664
728
  { hasFeature && ! featureLabel && (
665
- <Gridicon icon="checkmark" color="var(--studio-wordpress-blue-50)" />
729
+ <Gridicon
730
+ icon="checkmark"
731
+ color="var(--studio-wordpress-blue-50)"
732
+ aria-label={ translate( 'Feature available' ) }
733
+ />
734
+ ) }
735
+ { ! hasFeature && ! featureLabel && (
736
+ <Gridicon
737
+ icon="minus-small"
738
+ color="#C3C4C7"
739
+ aria-label={ translate( 'Feature not available' ) }
740
+ />
666
741
  ) }
667
- { ! hasFeature && ! featureLabel && <Gridicon icon="minus-small" color="#C3C4C7" /> }
668
742
  </>
669
743
  ) }
670
744
  </>
@@ -675,6 +749,7 @@ const ComparisonGridFeatureGroupRowCell: React.FunctionComponent< {
675
749
 
676
750
  const ComparisonGridFeatureGroupRow: React.FunctionComponent< {
677
751
  feature?: FeatureObject | TransformedFeatureObject;
752
+ featureGroupSlug: string;
678
753
  isHiddenInMobile: boolean;
679
754
  allJetpackFeatures: Set< string >;
680
755
  visibleGridPlans: GridPlan[];
@@ -688,6 +763,7 @@ const ComparisonGridFeatureGroupRow: React.FunctionComponent< {
688
763
  onStorageAddOnClick?: ( addOnSlug: AddOns.StorageAddOnSlug ) => void;
689
764
  } > = ( {
690
765
  feature,
766
+ featureGroupSlug,
691
767
  isHiddenInMobile,
692
768
  allJetpackFeatures,
693
769
  visibleGridPlans,
@@ -706,20 +782,29 @@ const ComparisonGridFeatureGroupRow: React.FunctionComponent< {
706
782
  } );
707
783
  const featureSlug = feature?.getSlug() ?? '';
708
784
  const footnote = planFeatureFootnotes?.footnotesByFeature?.[ featureSlug ];
709
- const tooltipId = `${ feature?.getSlug() }-comparison-grid`;
785
+ const tooltipId = `${ featureGroupSlug }-${ feature?.getSlug() }-comparison-grid`;
786
+ const title =
787
+ featureSlug === FEATURE_REALTIME_BACKUPS_JP
788
+ ? // Always display the short title for backups in comparison grid.
789
+ translate( 'Real-time backups', { textOnly: true } )
790
+ : feature?.getTitle?.();
791
+ const headerAriaLabel: string = typeof title === 'string' ? title : '';
710
792
 
711
793
  const { enableFeatureTooltips } = usePlansGridContext();
712
794
 
713
795
  return (
714
796
  <Row
797
+ as="tr"
715
798
  isHiddenInMobile={ isHiddenInMobile }
716
799
  className={ rowClasses }
717
800
  isHighlighted={ isHighlighted }
718
801
  >
719
- <RowTitleCell
802
+ <RowHeaderCell
720
803
  key="feature-name"
721
804
  className="is-feature-group-row-title-cell"
722
805
  isFeatureGroupRowTitleCell
806
+ scope="row"
807
+ aria-label={ headerAriaLabel }
723
808
  >
724
809
  { isStorageFeature ? (
725
810
  <Plans2023Tooltip
@@ -744,32 +829,52 @@ const ComparisonGridFeatureGroupRow: React.FunctionComponent< {
744
829
  activeTooltipId={ activeTooltipId }
745
830
  id={ tooltipId }
746
831
  >
747
- { feature.getTitle() }
748
- { footnote && (
749
- <FeatureFootnote>
750
- <sup>{ footnote }</sup>
751
- </FeatureFootnote>
832
+ { typeof title === 'string' ? (
833
+ <>
834
+ { title.split( ' ' ).slice( 0, -1 ).join( ' ' ) }
835
+ { title.includes( ' ' ) ? ' ' : null }
836
+ <TitlePreventOrphans>
837
+ { title.split( ' ' ).slice( -1 ) }
838
+ { footnote && (
839
+ <FeatureFootnote>
840
+ <sup>{ footnote }</sup>
841
+ </FeatureFootnote>
842
+ ) }
843
+ { allJetpackFeatures.has( feature.getSlug() ) ? (
844
+ <>
845
+ { '\u00A0' }
846
+ <JetpackIconContainer>
847
+ <Plans2023Tooltip
848
+ text={ translate(
849
+ 'Security, performance, and growth tools—powered by Jetpack.'
850
+ ) }
851
+ setActiveTooltipId={ setActiveTooltipId }
852
+ activeTooltipId={ activeTooltipId }
853
+ id={ `jp-${ tooltipId }` }
854
+ >
855
+ <JetpackLogo size={ 16 } />
856
+ </Plans2023Tooltip>
857
+ </JetpackIconContainer>
858
+ </>
859
+ ) : null }
860
+ </TitlePreventOrphans>
861
+ </>
862
+ ) : (
863
+ <>
864
+ { feature.getTitle() }
865
+ { footnote && (
866
+ <FeatureFootnote>
867
+ <sup>{ footnote }</sup>
868
+ </FeatureFootnote>
869
+ ) }
870
+ </>
752
871
  ) }
753
872
  </Plans2023Tooltip>
754
- { allJetpackFeatures.has( feature.getSlug() ) ? (
755
- <JetpackIconContainer>
756
- <Plans2023Tooltip
757
- text={ translate(
758
- 'Security, performance, and growth tools—powered by Jetpack.'
759
- ) }
760
- setActiveTooltipId={ setActiveTooltipId }
761
- activeTooltipId={ activeTooltipId }
762
- id={ `jp-${ tooltipId }` }
763
- >
764
- <JetpackLogo size={ 16 } />
765
- </Plans2023Tooltip>
766
- </JetpackIconContainer>
767
- ) : null }
768
873
  </>
769
874
  ) }
770
875
  </>
771
876
  ) }
772
- </RowTitleCell>
877
+ </RowHeaderCell>
773
878
  { visibleGridPlans.map( ( { planSlug } ) => (
774
879
  <ComparisonGridFeatureGroupRowCell
775
880
  key={ planSlug }
@@ -800,6 +905,7 @@ const FeatureGroup = ( {
800
905
  featureGroupMap,
801
906
  visibleGridPlans,
802
907
  planFeatureFootnotes,
908
+ plansLength,
803
909
  }: {
804
910
  featureGroup: FeatureGroup;
805
911
  selectedFeature?: string;
@@ -814,17 +920,20 @@ const FeatureGroup = ( {
814
920
  footnoteList: string[];
815
921
  footnotesByFeature: Record< string, number >;
816
922
  };
923
+ plansLength: number;
817
924
  } ) => {
818
- const { allFeaturesList } = usePlansGridContext();
925
+ const { allFeaturesList, isExperimentVariant } = usePlansGridContext();
819
926
  const [ firstSetOfFeatures ] = Object.keys( featureGroupMap );
820
927
  const [ visibleFeatureGroups, setVisibleFeatureGroups ] = useState< string[] >( [
821
928
  firstSetOfFeatures,
822
929
  ] );
823
930
  const features = featureGroup.getFeatures();
931
+
824
932
  const featureObjects = filterUnusedFeaturesObject(
825
933
  visibleGridPlans,
826
- getPlanFeaturesObject( allFeaturesList, features )
934
+ getPlanFeaturesObject( allFeaturesList, features, isExperimentVariant )
827
935
  );
936
+
828
937
  const isHiddenInMobile = ! visibleFeatureGroups.includes( featureGroup.slug );
829
938
 
830
939
  const allJetpackFeatures = useMemo( () => {
@@ -870,12 +979,18 @@ const FeatureGroup = ( {
870
979
  }
871
980
 
872
981
  return (
873
- <div key={ featureGroup.slug } className="plan-comparison-grid__feature-group">
982
+ <Grid
983
+ as="tbody"
984
+ visiblePlans={ plansLength }
985
+ key={ featureGroup.slug }
986
+ className="plan-comparison-grid__feature-group"
987
+ >
874
988
  <TitleRow
989
+ as="tr"
875
990
  className="plan-comparison-grid__feature-group-title-row"
876
991
  onClick={ handleFeatureGroupToggle }
877
992
  >
878
- <Title isHiddenInMobile={ isHiddenInMobile }>
993
+ <Title as="td" isHiddenInMobile={ isHiddenInMobile }>
879
994
  <Gridicon icon="chevron-up" size={ 12 } color="#1E1E1E" />
880
995
  <span>{ featureGroup.getTitle() }</span>
881
996
  </Title>
@@ -884,6 +999,7 @@ const FeatureGroup = ( {
884
999
  <ComparisonGridFeatureGroupRow
885
1000
  key={ feature.getSlug() }
886
1001
  feature={ feature }
1002
+ featureGroupSlug={ featureGroup.slug }
887
1003
  isHiddenInMobile={ isHiddenInMobile }
888
1004
  allJetpackFeatures={ allJetpackFeatures }
889
1005
  visibleGridPlans={ visibleGridPlans }
@@ -900,6 +1016,7 @@ const FeatureGroup = ( {
900
1016
  { featureGroup.slug === FEATURE_GROUP_ESSENTIAL_FEATURES ? (
901
1017
  <ComparisonGridFeatureGroupRow
902
1018
  key="feature-storage"
1019
+ featureGroupSlug={ featureGroup.slug }
903
1020
  isHiddenInMobile={ isHiddenInMobile }
904
1021
  allJetpackFeatures={ allJetpackFeatures }
905
1022
  visibleGridPlans={ visibleGridPlans }
@@ -913,7 +1030,7 @@ const FeatureGroup = ( {
913
1030
  onStorageAddOnClick={ onStorageAddOnClick }
914
1031
  />
915
1032
  ) : null }
916
- </div>
1033
+ </Grid>
917
1034
  );
918
1035
  };
919
1036
 
@@ -930,62 +1047,22 @@ const ComparisonGrid = ( {
930
1047
  showRefundPeriod,
931
1048
  planTypeSelectorProps,
932
1049
  gridSize,
1050
+ siteId,
1051
+ onVisiblePlansCountChange,
933
1052
  }: ComparisonGridProps ) => {
934
- const { gridPlans, gridPlansIndex, featureGroupMap } = usePlansGridContext();
1053
+ const { gridPlans, featureGroupMap } = usePlansGridContext();
935
1054
  const [ activeTooltipId, setActiveTooltipId ] = useManageTooltipToggle();
936
- const [ visiblePlans, setVisiblePlans ] = useState< PlanSlug[] >( [] );
937
1055
 
938
- const displayedGridPlans = useMemo( () => {
939
- return sortPlans( gridPlans, currentSitePlanSlug );
940
- }, [ gridPlans, currentSitePlanSlug ] );
1056
+ const { visibleGridPlans, setVisibleGridPlans } = useVisibleGridPlans( {
1057
+ gridSize,
1058
+ currentSitePlanSlug,
1059
+ siteId,
1060
+ intervalType,
1061
+ } );
941
1062
 
942
1063
  useEffect( () => {
943
- setVisiblePlans( () => {
944
- let visibleLength = displayedGridPlans.length;
945
- switch ( gridSize ) {
946
- case 'large':
947
- visibleLength = 4;
948
- break;
949
- case 'medium':
950
- visibleLength = 3;
951
- break;
952
- case 'smedium':
953
- case 'small':
954
- visibleLength = 2;
955
- break;
956
- }
957
-
958
- return displayedGridPlans.slice( 0, visibleLength ).map( ( { planSlug } ) => planSlug );
959
- } );
960
- }, [ gridSize, displayedGridPlans, gridPlansIndex ] );
961
-
962
- const visibleGridPlans = useMemo(
963
- () =>
964
- visiblePlans.reduce( ( acc, planSlug ) => {
965
- const gridPlan = displayedGridPlans.find(
966
- ( gridPlan ) => getPlanClass( gridPlan.planSlug ) === getPlanClass( planSlug )
967
- );
968
-
969
- if ( gridPlan ) {
970
- acc.push( gridPlan );
971
- }
972
-
973
- return acc;
974
- }, [] as GridPlan[] ),
975
- [ visiblePlans, displayedGridPlans ]
976
- );
977
-
978
- const onPlanChange = useCallback(
979
- ( currentPlan: PlanSlug, event: ChangeEvent< HTMLSelectElement > ) => {
980
- const newPlan = event.currentTarget.value;
981
- const newVisiblePlans = visiblePlans.map( ( plan ) =>
982
- plan === currentPlan ? ( newPlan as PlanSlug ) : plan
983
- );
984
-
985
- setVisiblePlans( newVisiblePlans );
986
- },
987
- [ visiblePlans ]
988
- );
1064
+ onVisiblePlansCountChange?.( visibleGridPlans.length );
1065
+ }, [ visibleGridPlans.length, onVisiblePlansCountChange ] );
989
1066
 
990
1067
  const planFeatureFootnotes = useMemo( () => {
991
1068
  // This is the main list of all footnotes. It is displayed at the bottom of the comparison grid.
@@ -1020,6 +1097,20 @@ const ComparisonGrid = ( {
1020
1097
  };
1021
1098
  }, [ featureGroupMap ] );
1022
1099
 
1100
+ const onPlanChange = useCallback(
1101
+ ( currentPlan: PlanSlug, event: ChangeEvent< HTMLSelectElement > ) => {
1102
+ const newPlanSlug = event.currentTarget.value;
1103
+ const newPlan = gridPlans.find( ( plan ) => plan.planSlug === newPlanSlug );
1104
+
1105
+ if ( newPlan ) {
1106
+ setVisibleGridPlans( ( previousGridPlans ) =>
1107
+ previousGridPlans.map( ( plan ) => ( plan.planSlug === currentPlan ? newPlan : plan ) )
1108
+ );
1109
+ }
1110
+ },
1111
+ [ gridPlans, setVisibleGridPlans ]
1112
+ );
1113
+
1023
1114
  // 100px is the padding of the footer row
1024
1115
  const [ bottomHeaderRef, isBottomHeaderInView ] = useInView( { rootMargin: '-100px' } );
1025
1116
 
@@ -1034,46 +1125,49 @@ const ComparisonGrid = ( {
1034
1125
  } );
1035
1126
 
1036
1127
  return (
1037
- <div className={ classes }>
1038
- <Grid visiblePlans={ visiblePlans.length }>
1039
- <StickyContainer
1040
- disabled={ isBottomHeaderInView }
1041
- stickyClass="is-sticky-header-row"
1042
- stickyOffset={ stickyRowOffset }
1043
- zIndex={ 1 }
1044
- >
1045
- { ( isStuck: boolean ) => (
1046
- <ComparisonGridHeader
1047
- displayedGridPlans={ displayedGridPlans }
1048
- visibleGridPlans={ visibleGridPlans }
1049
- isInSignup={ isInSignup }
1050
- onPlanChange={ onPlanChange }
1051
- currentSitePlanSlug={ currentSitePlanSlug }
1052
- planActionOverrides={ planActionOverrides }
1053
- selectedPlan={ selectedPlan }
1054
- showRefundPeriod={ showRefundPeriod }
1055
- isStuck={ isStuck }
1056
- planTypeSelectorProps={ planTypeSelectorProps }
1057
- />
1058
- ) }
1059
- </StickyContainer>
1060
- { Object.values( featureGroupMap ).map( ( featureGroup: FeatureGroup ) => (
1061
- <FeatureGroup
1062
- key={ featureGroup.slug }
1063
- featureGroup={ featureGroup }
1128
+ <table className={ classes }>
1129
+ <StickyGrid
1130
+ visiblePlans={ visibleGridPlans.length }
1131
+ element="thead"
1132
+ disabled={ isBottomHeaderInView }
1133
+ stickyClass="is-sticky-header-row"
1134
+ stickyOffset={ stickyRowOffset }
1135
+ zIndex={ 1 }
1136
+ >
1137
+ { ( isStuck: boolean ) => (
1138
+ <ComparisonGridHeader
1139
+ displayedGridPlans={ gridPlans }
1064
1140
  visibleGridPlans={ visibleGridPlans }
1065
- featureGroupMap={ featureGroupMap }
1066
- selectedFeature={ selectedFeature }
1067
- intervalType={ intervalType }
1068
- activeTooltipId={ activeTooltipId }
1069
- setActiveTooltipId={ setActiveTooltipId }
1070
- showUpgradeableStorage={ showUpgradeableStorage }
1071
- onStorageAddOnClick={ onStorageAddOnClick }
1072
- planFeatureFootnotes={ planFeatureFootnotes }
1141
+ isInSignup={ isInSignup }
1142
+ onPlanChange={ onPlanChange }
1143
+ currentSitePlanSlug={ currentSitePlanSlug }
1144
+ planActionOverrides={ planActionOverrides }
1145
+ selectedPlan={ selectedPlan }
1146
+ showRefundPeriod={ showRefundPeriod }
1147
+ isStuck={ isStuck }
1148
+ planTypeSelectorProps={ planTypeSelectorProps }
1073
1149
  />
1074
- ) ) }
1150
+ ) }
1151
+ </StickyGrid>
1152
+ { Object.values( featureGroupMap ).map( ( featureGroup: FeatureGroup ) => (
1153
+ <FeatureGroup
1154
+ key={ featureGroup.slug }
1155
+ featureGroup={ featureGroup }
1156
+ visibleGridPlans={ visibleGridPlans }
1157
+ featureGroupMap={ featureGroupMap }
1158
+ selectedFeature={ selectedFeature }
1159
+ intervalType={ intervalType }
1160
+ activeTooltipId={ activeTooltipId }
1161
+ setActiveTooltipId={ setActiveTooltipId }
1162
+ showUpgradeableStorage={ showUpgradeableStorage }
1163
+ onStorageAddOnClick={ onStorageAddOnClick }
1164
+ planFeatureFootnotes={ planFeatureFootnotes }
1165
+ plansLength={ visibleGridPlans.length }
1166
+ />
1167
+ ) ) }
1168
+ <tbody>
1075
1169
  <ComparisonGridHeader
1076
- displayedGridPlans={ displayedGridPlans }
1170
+ displayedGridPlans={ gridPlans }
1077
1171
  visibleGridPlans={ visibleGridPlans }
1078
1172
  isInSignup={ isInSignup }
1079
1173
  isFooter
@@ -1087,20 +1181,22 @@ const ComparisonGrid = ( {
1087
1181
  ref={ bottomHeaderRef }
1088
1182
  planTypeSelectorProps={ planTypeSelectorProps }
1089
1183
  />
1090
- </Grid>
1184
+ </tbody>
1091
1185
 
1092
- <div className="plan-comparison-grid__footer">
1186
+ <tfoot className="plan-comparison-grid__footer">
1093
1187
  { planFeatureFootnotes?.footnoteList && (
1094
- <FeatureFootnotes>
1095
- <ol>
1096
- { planFeatureFootnotes?.footnoteList?.map( ( footnote, index ) => {
1097
- return <li key={ `${ footnote }-${ index }` }>{ footnote }</li>;
1098
- } ) }
1099
- </ol>
1188
+ <FeatureFootnotes as="tr">
1189
+ <td>
1190
+ <ol>
1191
+ { planFeatureFootnotes?.footnoteList?.map( ( footnote, index ) => {
1192
+ return <li key={ `${ footnote }-${ index }` }>{ footnote }</li>;
1193
+ } ) }
1194
+ </ol>
1195
+ </td>
1100
1196
  </FeatureFootnotes>
1101
1197
  ) }
1102
- </div>
1103
- </div>
1198
+ </tfoot>
1199
+ </table>
1104
1200
  );
1105
1201
  };
1106
1202
 
@@ -1131,6 +1227,9 @@ const WrappedComparisonGrid = ( {
1131
1227
  featureGroupMap,
1132
1228
  enableTermSavingsPriceDisplay,
1133
1229
  reflectStorageSelectionInPlanPrices,
1230
+ showSimplifiedBillingDescription,
1231
+ showBillingDescriptionForIncreasedRenewalPrice,
1232
+ isExperimentVariant,
1134
1233
  ...otherProps
1135
1234
  }: ComparisonGridExternalProps ) => {
1136
1235
  const gridContainerRef = useRef< HTMLDivElement >( null );
@@ -1138,7 +1237,7 @@ const WrappedComparisonGrid = ( {
1138
1237
  const gridBreakpoints = useMemo( () => {
1139
1238
  // we want to fit up to the Commerce plan in this breakpoint
1140
1239
  const xlargeBreakpoint = isInSiteDashboard ? 1114 : 1180;
1141
- return new Map( [
1240
+ return new Map< GridSize, number >( [
1142
1241
  [ 'small', 0 ],
1143
1242
  [ 'smedium', 686 ],
1144
1243
  [ 'medium', 835 ],
@@ -1166,6 +1265,7 @@ const WrappedComparisonGrid = ( {
1166
1265
  <div ref={ gridContainerRef } className={ classNames }>
1167
1266
  <PlansGridContextProvider
1168
1267
  intent={ intent }
1268
+ key={ intent }
1169
1269
  siteId={ siteId }
1170
1270
  gridPlans={ gridPlans }
1171
1271
  useCheckPlanAvailabilityForPurchase={ useCheckPlanAvailabilityForPurchase }
@@ -1178,6 +1278,11 @@ const WrappedComparisonGrid = ( {
1178
1278
  hideUnsupportedFeatures={ hideUnsupportedFeatures }
1179
1279
  enableTermSavingsPriceDisplay={ enableTermSavingsPriceDisplay }
1180
1280
  reflectStorageSelectionInPlanPrices={ reflectStorageSelectionInPlanPrices }
1281
+ showSimplifiedBillingDescription={ showSimplifiedBillingDescription }
1282
+ showBillingDescriptionForIncreasedRenewalPrice={
1283
+ showBillingDescriptionForIncreasedRenewalPrice
1284
+ }
1285
+ isExperimentVariant={ isExperimentVariant }
1181
1286
  >
1182
1287
  <ComparisonGrid
1183
1288
  intervalType={ intervalType }