@arc-ui/community-components 3.13.0 → 3.14.0

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 (64) hide show
  1. package/.turbo/turbo-build.log +18 -16
  2. package/CHANGELOG.md +18 -0
  3. package/lib/ArticleCarousel/ArticleCarousel.cjs +1 -1
  4. package/lib/ArticleCarousel/ArticleCarousel.mjs +1 -1
  5. package/lib/ArticleSidebar/ArticleSidebar.cjs +15 -9
  6. package/lib/ArticleSidebar/ArticleSidebar.mjs +16 -10
  7. package/lib/CopyLead/CopyLead.cjs +1 -1
  8. package/lib/CopyLead/CopyLead.mjs +1 -1
  9. package/lib/FeaturePost/FeaturePost.cjs +1 -1
  10. package/lib/FeaturePost/FeaturePost.mjs +1 -1
  11. package/lib/InlineLinkGroup/InlineLinkGroup.cjs +2 -2
  12. package/lib/InlineLinkGroup/InlineLinkGroup.mjs +2 -2
  13. package/lib/ProductCard/ProductCard.cjs +77 -0
  14. package/lib/ProductCard/ProductCard.mjs +72 -0
  15. package/lib/ProductCard/styles.css +1 -0
  16. package/lib/ProductCardGrid/ProductCardGrid.cjs +69 -0
  17. package/lib/ProductCardGrid/ProductCardGrid.mjs +67 -0
  18. package/lib/ProductNavigation/ProductNavigation.cjs +1 -1
  19. package/lib/ProductNavigation/ProductNavigation.mjs +1 -1
  20. package/lib/PromoListing/PromoListing.cjs +1 -1
  21. package/lib/PromoListing/PromoListing.mjs +1 -1
  22. package/lib/Summary/Summary.cjs +1 -1
  23. package/lib/Summary/Summary.mjs +1 -1
  24. package/lib/VideoHeroCard/VideoHeroCard.cjs +4 -4
  25. package/lib/VideoHeroCard/VideoHeroCard.mjs +4 -4
  26. package/lib/VideoPortraitCard/VideoPortraitCard.cjs +3 -3
  27. package/lib/VideoPortraitCard/VideoPortraitCard.mjs +3 -3
  28. package/lib/_shared/cjs/{VideoCardThumbnail-BM3GwyWR.cjs → VideoCardThumbnail-DhdbNf5c.cjs} +10 -2
  29. package/lib/_shared/cjs/{index.es-DcJ01c8P.cjs → index.es-5qmN4ppJ.cjs} +1 -1
  30. package/lib/_shared/esm/{VideoCardThumbnail-K6eHIeAM.mjs → VideoCardThumbnail-B8JS-s6O.mjs} +10 -2
  31. package/lib/_shared/esm/{index.es-C76rXaZz.mjs → index.es-Cis5MKaa.mjs} +1 -1
  32. package/lib/index.cjs +309 -180
  33. package/lib/index.cjs.map +1 -1
  34. package/lib/index.d.cts +75 -2
  35. package/lib/index.d.mts +75 -2
  36. package/lib/index.mjs +306 -182
  37. package/lib/index.mjs.map +1 -1
  38. package/lib/styles.css +1 -1
  39. package/package.json +14 -14
  40. package/src/components/ArticleSidebar/ArticleSidebar.tsx +24 -10
  41. package/src/components/InlineLinkGroup/InlineLinkGroup.tsx +4 -0
  42. package/src/components/ProductCard/ProductCard.module.css +49 -0
  43. package/src/components/ProductCard/ProductCard.tsx +113 -0
  44. package/src/components/ProductCard/ProductCardBenefits/ProductCardBenefits.module.css +14 -0
  45. package/src/components/ProductCard/ProductCardBenefits/ProductCardBenefits.tsx +42 -0
  46. package/src/components/ProductCard/ProductCardBenefits/index.ts +4 -0
  47. package/src/components/ProductCard/ProductCardPrice/ProductCardPrice.module.css +5 -0
  48. package/src/components/ProductCard/ProductCardPrice/ProductCardPrice.tsx +37 -0
  49. package/src/components/ProductCard/ProductCardPrice/index.ts +4 -0
  50. package/src/components/ProductCard/ProductCardPriceIncrease/ProductCardPriceIncrease.module.css +25 -0
  51. package/src/components/ProductCard/ProductCardPriceIncrease/ProductCardPriceIncrease.tsx +39 -0
  52. package/src/components/ProductCard/ProductCardPriceIncrease/index.ts +4 -0
  53. package/src/components/ProductCard/index.ts +13 -0
  54. package/src/components/ProductCardGrid/ProductCardGrid.tsx +162 -0
  55. package/src/components/ProductCardGrid/components/CardGrid/CardGrid.module.css +34 -0
  56. package/src/components/ProductCardGrid/components/CardGrid/CardGrid.tsx +44 -0
  57. package/src/components/ProductCardGrid/components/CardGrid/index.ts +1 -0
  58. package/src/components/ProductCardGrid/index.ts +5 -0
  59. package/src/components/VideoHeroCard/components/VideoHeroCardContent/VideoHeroCardContent.tsx +9 -3
  60. package/src/components/VideoPortraitCard/VideoPortraitCard.tsx +11 -3
  61. package/src/components/index.ts +2 -0
  62. package/src/internal/VideoCardPlayer/VideoCardPlayer.module.css +5 -2
  63. package/src/internal/VideoCardPlayer/VideoCardPlayer.tsx +16 -1
  64. package/versions.json +1 -1
@@ -0,0 +1,39 @@
1
+ import React from "react";
2
+ import styles from "./ProductCardPriceIncrease.module.css";
3
+ import { Heading, type HeadingLevel } from "@arc-ui/components/Heading";
4
+ import { VerticalSpace } from "@arc-ui/components/VerticalSpace";
5
+
6
+ export const ProductCardPriceIncrease: React.FC<
7
+ ProductCardPriceIncreaseProps
8
+ > = ({ heading = "Price increasing to", headingLevel = "4", items = [] }) => {
9
+ return (
10
+ <>
11
+ <VerticalSpace size="16" />
12
+ <Heading size="xs" level={headingLevel}>
13
+ {heading}
14
+ </Heading>
15
+ <VerticalSpace size="12" />
16
+ <div className={styles.priceIncreaseWrapper}>
17
+ <div className={styles.priceIncreaseBorder} />
18
+ <ul className={styles.priceIncreaseList}>
19
+ {items.map((item, index) => (
20
+ <li key={index} className={styles.priceIncreaseItem}>
21
+ {item}
22
+ </li>
23
+ ))}
24
+ </ul>
25
+ </div>
26
+ </>
27
+ );
28
+ };
29
+
30
+ export interface ProductCardPriceIncreaseProps {
31
+ /** Heading displayed above the price increase list */
32
+ heading?: string;
33
+
34
+ /** heading level for accessibility */
35
+ headingLevel?: HeadingLevel;
36
+
37
+ /** List of price increase entries (e.g. ["£48.99 by April 2027"]) */
38
+ items: string[];
39
+ }
@@ -0,0 +1,4 @@
1
+ export {
2
+ ProductCardPriceIncrease,
3
+ type ProductCardPriceIncreaseProps,
4
+ } from "./ProductCardPriceIncrease";
@@ -0,0 +1,13 @@
1
+ export { ProductCard, type ProductCardProps } from "./ProductCard";
2
+ export {
3
+ ProductCardBenefits,
4
+ type ProductCardBenefitsProps,
5
+ } from "./ProductCardBenefits";
6
+ export {
7
+ ProductCardPriceIncrease,
8
+ type ProductCardPriceIncreaseProps,
9
+ } from "./ProductCardPriceIncrease";
10
+ export {
11
+ ProductCardPrice,
12
+ type ProductCardPriceProps,
13
+ } from "./ProductCardPrice";
@@ -0,0 +1,162 @@
1
+ import React, { useState, useRef, useId } from "react";
2
+
3
+ import { filterAttrs } from "@arc-ui/community-utils/filter-attrs";
4
+
5
+ import { SectionHeading, SectionHeadingProps } from "../SectionHeading";
6
+ import {
7
+ Tabs,
8
+ TabsList,
9
+ TabsItem,
10
+ TabsContent,
11
+ type TabsItemProps,
12
+ } from "@arc-ui/components/Tabs";
13
+ import { VerticalSpace } from "@arc-ui/components/VerticalSpace";
14
+ import { ButtonV2 } from "@arc-ui/components/ButtonV2";
15
+ import { Rule } from "@arc-ui/components/Rule";
16
+ import { Align } from "@arc-ui/components/Align";
17
+
18
+ import { CardGrid } from "./components/CardGrid/CardGrid";
19
+
20
+ export const ProductCardGrid: React.FC<ProductCardGridProps> = ({
21
+ id,
22
+ isHeadingWordWrap,
23
+ heading,
24
+ content,
25
+ headingLevel,
26
+ tabs,
27
+ expanded = true,
28
+ hideTabs = false,
29
+ ...props
30
+ }) => {
31
+ const [cardsRevealed, setCardsRevealed] = useState(expanded);
32
+ const [activeTab, setActiveTab] = useState(tabs?.[0]?.value);
33
+
34
+ const fourthCardRef = useRef<HTMLLIElement>(null);
35
+
36
+ const cardContext = useId();
37
+
38
+ const activeCards = tabs?.find((tab) => tab.value === activeTab)?.cards;
39
+
40
+ const hasMoreCards = (activeCards?.length ?? 0) > 3;
41
+ const remainingCards = Math.max((activeCards?.length ?? 0) - 3, 0);
42
+
43
+ const showMore = () => {
44
+ setCardsRevealed(true);
45
+ setTimeout(() => {
46
+ fourthCardRef.current?.focus();
47
+ }, 0);
48
+ };
49
+
50
+ const showLess = () => {
51
+ setCardsRevealed(false);
52
+ };
53
+
54
+ return (
55
+ <div {...filterAttrs(props)}>
56
+ <SectionHeading
57
+ id={id}
58
+ isHeadingWordWrap={isHeadingWordWrap}
59
+ heading={heading}
60
+ content={content}
61
+ headingLevel={headingLevel}
62
+ isPadded
63
+ />
64
+
65
+ {tabs && !hideTabs && (
66
+ <Tabs
67
+ defaultValue={tabs[0]?.value}
68
+ onValueChange={(value) => {
69
+ setActiveTab(value);
70
+ }}
71
+ >
72
+ <TabsList type="standard">
73
+ {tabs.map((tab) => (
74
+ <TabsItem
75
+ key={tab.value}
76
+ label={tab.label}
77
+ value={tab.value}
78
+ icon={tab.icon}
79
+ iconActive={tab.iconActive}
80
+ />
81
+ ))}
82
+ </TabsList>
83
+ {tabs.map((tab) => (
84
+ <TabsContent key={tab.value} value={tab.value}>
85
+ <VerticalSpace size="24" sizeL="32" />
86
+ <CardGrid
87
+ cards={tab.cards}
88
+ cardsRevealed={cardsRevealed}
89
+ fourthCardRef={
90
+ tab.value === activeTab ? fourthCardRef : { current: null }
91
+ }
92
+ />
93
+ </TabsContent>
94
+ ))}
95
+ </Tabs>
96
+ )}
97
+
98
+ {tabs?.length === 1 && hideTabs && (
99
+ <>
100
+ <CardGrid
101
+ cards={tabs[0].cards}
102
+ cardsRevealed={cardsRevealed}
103
+ fourthCardRef={fourthCardRef}
104
+ />
105
+ </>
106
+ )}
107
+
108
+ {!expanded && hasMoreCards && (
109
+ <>
110
+ <Rule />
111
+ <span id={cardContext} style={{ display: "none" }}>
112
+ {remainingCards === 1
113
+ ? `${remainingCards} card`
114
+ : `${remainingCards} cards`}
115
+ </span>
116
+ <Align horizontal="center">
117
+ <VerticalSpace size="16" />
118
+ {!cardsRevealed && (
119
+ <ButtonV2
120
+ label="Show more"
121
+ buttonStyle="secondary"
122
+ onClick={showMore}
123
+ aria-describedby={cardContext}
124
+ />
125
+ )}
126
+ {cardsRevealed && (
127
+ <ButtonV2
128
+ label="Show less"
129
+ buttonStyle="secondary"
130
+ onClick={showLess}
131
+ aria-describedby={cardContext}
132
+ />
133
+ )}
134
+ </Align>
135
+ </>
136
+ )}
137
+ </div>
138
+ );
139
+ };
140
+
141
+ export interface Tab extends TabsItemProps {
142
+ /*
143
+ * Cards rendered in a responsive grid inside the tab panel
144
+ */
145
+ cards: React.ReactNode[];
146
+ }
147
+
148
+ export interface ProductCardGridProps
149
+ extends Omit<SectionHeadingProps, "isPadded" | "isCentered" | "image"> {
150
+ /*
151
+ * Array of tabs to render in a tabbed layout. Cannot be used together with `cards`.
152
+ */
153
+ tabs?: Tab[];
154
+ /*
155
+ * When true, all cards are displayed by default and the show more/less button is hidden.
156
+ */
157
+ expanded?: boolean;
158
+ /*
159
+ * When true, hide the tabs and only display first grid of cards
160
+ */
161
+ hideTabs?: boolean;
162
+ }
@@ -0,0 +1,34 @@
1
+ .cardGrid {
2
+ display: grid;
3
+ grid-template-columns: 1fr;
4
+ grid-template-rows: auto auto;
5
+ gap: var(--sem-space-padding-110);
6
+ list-style: none;
7
+ margin: 0;
8
+ padding: 0;
9
+ }
10
+
11
+ .cardGridItem {
12
+ display: grid;
13
+ grid-template-rows: subgrid;
14
+ grid-row: span 2;
15
+ row-gap: 0;
16
+ }
17
+
18
+ @media (--arc-custom-media-min-width-s-px) {
19
+ .cardGrid {
20
+ grid-template-columns: repeat(2, 1fr);
21
+ }
22
+ }
23
+
24
+ @media (--arc-custom-media-min-width-l-px) {
25
+ .cardGrid {
26
+ grid-template-columns: repeat(3, 1fr);
27
+ }
28
+ }
29
+
30
+ @media (--arc-custom-media-min-width-xl-px) {
31
+ .cardGrid {
32
+ gap: var(--sem-space-padding-130);
33
+ }
34
+ }
@@ -0,0 +1,44 @@
1
+ import React from "react";
2
+
3
+ import styles from "./CardGrid.module.css";
4
+ import { filterAttrs } from "@arc-ui/community-utils/filter-attrs";
5
+
6
+ import { VerticalSpace } from "@arc-ui/components/VerticalSpace";
7
+
8
+ export const CardGrid: React.FC<CardGridProps> = ({
9
+ cards,
10
+ cardsRevealed,
11
+ fourthCardRef,
12
+ ...props
13
+ }) => (
14
+ <>
15
+ <ul className={styles.cardGrid} {...filterAttrs(props)}>
16
+ {(cardsRevealed ? cards : cards.slice(0, 3)).map((card, index) => (
17
+ <li
18
+ key={`card-${index}`}
19
+ className={styles.cardGridItem}
20
+ ref={index === 3 ? fourthCardRef : undefined}
21
+ tabIndex={-1}
22
+ >
23
+ {card}
24
+ </li>
25
+ ))}
26
+ </ul>
27
+ <VerticalSpace size="24" sizeXL="32" />
28
+ </>
29
+ );
30
+
31
+ export interface CardGridProps {
32
+ /*
33
+ * Array of card elements to render within the grid
34
+ */
35
+ cards: React.ReactNode[];
36
+ /*
37
+ * Whether all cards are visible. When false, only the first 3 cards are shown.
38
+ */
39
+ cardsRevealed: boolean;
40
+ /*
41
+ * Ref attached to the fourth card item, used to manage focus when cards are revealed
42
+ */
43
+ fourthCardRef: React.RefObject<HTMLLIElement>;
44
+ }
@@ -0,0 +1 @@
1
+ export { CardGrid, type CardGridProps } from "./CardGrid";
@@ -0,0 +1,5 @@
1
+ export {
2
+ ProductCardGrid,
3
+ type ProductCardGridProps,
4
+ type Tab,
5
+ } from "./ProductCardGrid";
@@ -4,7 +4,7 @@ import { BtIconCalendar } from "@arc-ui/icons/BtIconCalendar";
4
4
  import { BtIconClock } from "@arc-ui/icons/BtIconClock";
5
5
  import { BtIconChatMessage } from "@arc-ui/icons/BtIconChatMessage";
6
6
 
7
- import { Heading } from "@arc-ui/components/Heading";
7
+ import { Heading, type HeadingLevel } from "@arc-ui/components/Heading";
8
8
  import { Icon } from "@arc-ui/components/Icon";
9
9
  import { Text } from "@arc-ui/components/Text";
10
10
  import { VerticalSpace } from "@arc-ui/components/VerticalSpace";
@@ -15,6 +15,8 @@ import classNames from "classnames";
15
15
  export const VideoHeroCardContent = ({
16
16
  title,
17
17
  label,
18
+ titleLevel = "3",
19
+ labelLevel,
18
20
  description,
19
21
  videoDate,
20
22
  duration,
@@ -42,11 +44,13 @@ export const VideoHeroCardContent = ({
42
44
  styles[`mainText--${background}Background`],
43
45
  )}
44
46
  >
45
- <Heading fontStyle="overline">{label}</Heading>
47
+ <Heading level={labelLevel} fontStyle="overline">
48
+ {label}
49
+ </Heading>
46
50
 
47
51
  <VerticalSpace size="8" sizeM="4" />
48
52
 
49
- <Heading level="3" isWordWrap={false} size="xl">
53
+ <Heading level={titleLevel} isWordWrap={false} size="xl">
50
54
  {title}
51
55
  </Heading>
52
56
 
@@ -88,7 +92,9 @@ type MetaItem = {
88
92
 
89
93
  export interface VideoHeroCardContentProps {
90
94
  title: string;
95
+ titleLevel?: HeadingLevel;
91
96
  label: string;
97
+ labelLevel?: HeadingLevel;
92
98
  description: string | ReactNode;
93
99
  background: "dark" | "light";
94
100
  videoDate?: string;
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
 
3
- import { Heading } from "@arc-ui/components/Heading";
3
+ import { Heading, type HeadingLevel } from "@arc-ui/components/Heading";
4
4
  import { Surface } from "@arc-ui/components/Surface";
5
5
  import { VerticalSpace } from "@arc-ui/components/VerticalSpace";
6
6
 
@@ -21,9 +21,15 @@ export const VideoPortraitCard = ({
21
21
  thumbnail && (
22
22
  <VideoCardThumbnail orientation="portrait" src={thumbnail.img}>
23
23
  <Surface isTransparent background="dark-black">
24
- <Heading fontStyle="overline">{thumbnail.label}</Heading>
24
+ <Heading fontStyle="overline" level={thumbnail.labelLevel}>
25
+ {thumbnail.label}
26
+ </Heading>
25
27
  <VerticalSpace size="8" />
26
- <Heading level="3" isWordWrap={false} size="xs">
28
+ <Heading
29
+ level={thumbnail.titleLevel}
30
+ isWordWrap={false}
31
+ size="xs"
32
+ >
27
33
  {thumbnail.title}
28
34
  </Heading>
29
35
  </Surface>
@@ -44,7 +50,9 @@ export interface VideoPortraitCardProps {
44
50
  */
45
51
  thumbnail?: {
46
52
  title: string;
53
+ titleLevel?: HeadingLevel;
47
54
  label: string;
55
+ labelLevel?: HeadingLevel;
48
56
  img: string;
49
57
  };
50
58
  /**
@@ -25,3 +25,5 @@ export * from "./VideoHeroCard";
25
25
  export * from "./VideoPortraitCard";
26
26
  export * from "./BusinessSegmentSwitcher";
27
27
  export * from "./PartnerBrandLogos";
28
+ export * from "./ProductCard";
29
+ export * from "./ProductCardGrid";
@@ -28,6 +28,7 @@
28
28
  .playerWrapper {
29
29
  width: 100%;
30
30
  position: relative;
31
+ outline: none;
31
32
  }
32
33
 
33
34
  .playerWrapper--landscape {
@@ -38,12 +39,14 @@
38
39
  aspect-ratio: 9 / 16;
39
40
  }
40
41
 
41
- .container:has(:global(.react-player__preview):focus) {
42
+ .container:has(:global(.react-player__preview):focus),
43
+ .container:has(.playerWrapper:focus-visible) {
42
44
  outline-color: var(--sem-color-border-primary-light-default);
43
45
  }
44
46
 
45
47
  .container:has(:global(.react-player__preview):hover),
46
- .container:has(:global(.react-player__preview):focus) {
48
+ .container:has(:global(.react-player__preview):focus),
49
+ .container:has(.playerWrapper:focus-visible) {
47
50
  box-shadow: var(--elevation-05);
48
51
  }
49
52
 
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useState } from "react";
1
+ import React, { useCallback, useEffect, useRef, useState } from "react";
2
2
  import classNames from "classnames";
3
3
 
4
4
  import ReactPlayer from "react-player";
@@ -20,11 +20,19 @@ export const VideoCardPlayer = ({
20
20
  ...props
21
21
  }: VideoCardPlayerProps) => {
22
22
  const [isClient, setIsClient] = useState<boolean>(false);
23
+ const playerWrapperRef = useRef<HTMLDivElement>(null);
23
24
 
24
25
  useEffect(() => {
25
26
  setIsClient(true);
26
27
  }, []);
27
28
 
29
+ const handleClickPreview = useCallback(() => {
30
+ // Restore focus to the player wrapper after preview is clicked.
31
+ requestAnimationFrame(() => {
32
+ playerWrapperRef.current?.focus();
33
+ });
34
+ }, []);
35
+
28
36
  const playerProps = {
29
37
  ...player,
30
38
  light: thumbnail,
@@ -35,12 +43,16 @@ export const VideoCardPlayer = ({
35
43
  className: styles.player,
36
44
  width: "100%",
37
45
  height: "100%",
46
+ onClickPreview: handleClickPreview,
38
47
  };
39
48
 
40
49
  return (
41
50
  <div className={styles.container} {...filterAttrs(props)}>
42
51
  <div
52
+ ref={playerWrapperRef}
43
53
  data-testid="arc-video-card"
54
+ role="button"
55
+ tabIndex={-1}
44
56
  className={classNames(
45
57
  styles.playerWrapper,
46
58
  styles[`playerWrapper--${orientation}`],
@@ -59,4 +71,7 @@ export interface VideoCardPlayerProps {
59
71
  playIconSize: "s" | "l";
60
72
  thumbnail?: ReactPlayerProps["light"];
61
73
  children?: React.ReactNode;
74
+ previewTabIndex?: number;
75
+ wrapper?: React.ReactNode;
76
+ fallback?: React.ReactNode;
62
77
  }
package/versions.json CHANGED
@@ -1 +1 @@
1
- [{"version":"v3.13.0","date":null},{"version":"v3.12.0","date":"2026-07-08"},{"version":"v3.11.0","date":"2026-06-24"},{"version":"v3.10.0","date":"2026-06-16"},{"version":"v3.9.0","date":"2026-05-22"},{"version":"v3.8.1","date":"2026-05-13"},{"version":"v3.8.0","date":"2026-04-29"},{"version":"v3.7.1","date":"2026-04-22"},{"version":"v3.7.0","date":"2026-04-17"},{"version":"v3.6.0","date":"2026-04-10"},{"version":"v3.5.0","date":"2026-04-02"},{"version":"v3.4.0","date":"2026-03-26"},{"version":"v3.3.0","date":"2026-03-20"},{"version":"v3.2.0","date":"2026-03-09"},{"version":"v3.1.0","date":"2026-02-26"},{"version":"v3.0.1","date":null},{"version":"v3.0.0","date":"2026-02-18"},{"version":"v2.0.0","date":"2026-01-21"},{"version":"v1.1.0","date":"2025-11-19"},{"version":"v1.0.2","date":"2025-08-18"},{"version":"v1.0.1","date":"2025-08-05"},{"version":"v1.0.0","date":"2025-04-29"},{"version":"v0.1.0","date":null}]
1
+ [{"version":"v3.14.0","date":null},{"version":"v3.13.1","date":"2026-07-30"},{"version":"v3.13.0","date":"2026-07-24"},{"version":"v3.12.0","date":"2026-07-08"},{"version":"v3.11.0","date":"2026-06-24"},{"version":"v3.10.0","date":"2026-06-16"},{"version":"v3.9.0","date":"2026-05-22"},{"version":"v3.8.1","date":"2026-05-13"},{"version":"v3.8.0","date":"2026-04-29"},{"version":"v3.7.1","date":"2026-04-22"},{"version":"v3.7.0","date":"2026-04-17"},{"version":"v3.6.0","date":"2026-04-10"},{"version":"v3.5.0","date":"2026-04-02"},{"version":"v3.4.0","date":"2026-03-26"},{"version":"v3.3.0","date":"2026-03-20"},{"version":"v3.2.0","date":"2026-03-09"},{"version":"v3.1.0","date":"2026-02-26"},{"version":"v3.0.1","date":null},{"version":"v3.0.0","date":"2026-02-18"},{"version":"v2.0.0","date":"2026-01-21"},{"version":"v1.1.0","date":"2025-11-19"},{"version":"v1.0.2","date":"2025-08-18"},{"version":"v1.0.1","date":"2025-08-05"},{"version":"v1.0.0","date":"2025-04-29"},{"version":"v0.1.0","date":null}]