@orangesk/orange-design-system 2.2.0 → 3.1.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 (83) hide show
  1. package/build/components/Accordion/style.css +1 -1
  2. package/build/components/Accordion/style.css.map +1 -1
  3. package/build/components/Card/style.css +1 -1
  4. package/build/components/Card/style.css.map +1 -1
  5. package/build/components/Carousel/style.css +1 -1
  6. package/build/components/Carousel/style.css.map +1 -1
  7. package/build/components/CarouselHero/style.css +1 -1
  8. package/build/components/CarouselHero/style.css.map +1 -1
  9. package/build/components/Cover/style.css +1 -1
  10. package/build/components/Cover/style.css.map +1 -1
  11. package/build/components/FeatureAccordion/style.css +1 -1
  12. package/build/components/FeatureAccordion/style.css.map +1 -1
  13. package/build/components/Footer/style.css +1 -1
  14. package/build/components/Footer/style.css.map +1 -1
  15. package/build/components/Grid/style.css +1 -1
  16. package/build/components/Grid/style.css.map +1 -1
  17. package/build/components/IconList/style.css +1 -1
  18. package/build/components/IconList/style.css.map +1 -1
  19. package/build/components/Link/style.css +1 -1
  20. package/build/components/Link/style.css.map +1 -1
  21. package/build/components/Megamenu/style.css +1 -1
  22. package/build/components/Megamenu/style.css.map +1 -1
  23. package/build/components/PromoBanner/style.css +1 -1
  24. package/build/components/PromoBanner/style.css.map +1 -1
  25. package/build/components/Timeline/style.css +2 -0
  26. package/build/components/Timeline/style.css.map +1 -0
  27. package/build/components/index.js +1 -1
  28. package/build/components/index.js.map +1 -1
  29. package/build/components/tsconfig.tsbuildinfo +1 -1
  30. package/build/components/types/index.d.ts +30 -2
  31. package/build/components/types/src/components/FeatureAccordion/FeatureAccordion.d.ts +3 -0
  32. package/build/components/types/src/components/FeatureAccordion/FeatureAccordion.static.d.ts +0 -3
  33. package/build/components/types/src/components/FeatureAccordion/FeatureAccordionItem.d.ts +2 -1
  34. package/build/components/types/src/components/Timeline/Timeline.d.ts +13 -0
  35. package/build/components/types/src/components/Timeline/index.d.ts +2 -0
  36. package/build/components/types/src/components/index.d.ts +2 -1
  37. package/build/lib/base.css +1 -1
  38. package/build/lib/base.css.map +1 -1
  39. package/build/lib/components.css +1 -1
  40. package/build/lib/components.css.map +1 -1
  41. package/build/lib/footer.css +1 -1
  42. package/build/lib/footer.css.map +1 -1
  43. package/build/lib/megamenu.css +1 -1
  44. package/build/lib/megamenu.css.map +1 -1
  45. package/build/lib/scripts.js +1 -1
  46. package/build/lib/scripts.js.map +1 -1
  47. package/build/lib/style.css +1 -1
  48. package/build/lib/style.css.map +1 -1
  49. package/build/search-index.json +7 -3
  50. package/build/sprite.svg +1 -1
  51. package/package.json +8 -8
  52. package/src/assets/icons/communication-settings.svg +5 -0
  53. package/src/assets/icons/cookies.svg +4 -0
  54. package/src/assets/icons/device-mobile-package.svg +6 -0
  55. package/src/assets/icons/identity-protection.svg +4 -0
  56. package/src/assets/icons/pictogram-disney--dark.svg +5 -14
  57. package/src/assets/icons/pictogram-disney.svg +5 -9
  58. package/src/assets/icons/pictogram-tariffs--dark.svg +4 -8
  59. package/src/assets/icons/pictogram-tariffs.svg +4 -8
  60. package/src/components/Accordion/styles/mixins.scss +2 -4
  61. package/src/components/Card/styles/mixins.scss +2 -0
  62. package/src/components/Carousel/styles/mixins.scss +0 -1
  63. package/src/components/CarouselHero/styles/mixins.scss +0 -2
  64. package/src/components/Cover/styles/mixins.scss +2 -0
  65. package/src/components/FeatureAccordion/FeatureAccordion.static.ts +3 -71
  66. package/src/components/FeatureAccordion/FeatureAccordion.tsx +23 -59
  67. package/src/components/FeatureAccordion/FeatureAccordionItem.tsx +9 -14
  68. package/src/components/FeatureAccordion/styles/mixins.scss +67 -27
  69. package/src/components/FeatureAccordion/tests/FeatureAccordion.unit.test.jsx +9 -0
  70. package/src/components/Grid/styles/mixins.scss +34 -2
  71. package/src/components/IconList/styles/mixins.scss +2 -1
  72. package/src/components/Link/styles/style.scss +8 -0
  73. package/src/components/PromoBanner/styles/mixins.scss +8 -0
  74. package/src/components/PromoBanner/styles/style.scss +1 -0
  75. package/src/components/Timeline/Timeline.tsx +60 -0
  76. package/src/components/Timeline/index.ts +2 -0
  77. package/src/components/Timeline/styles/config.scss +25 -0
  78. package/src/components/Timeline/styles/mixins.scss +102 -0
  79. package/src/components/Timeline/styles/style.scss +60 -0
  80. package/src/components/Timeline/tests/Timeline.conformance.test.jsx +29 -0
  81. package/src/components/Timeline/tests/Timeline.unit.test.jsx +89 -0
  82. package/src/components/index.ts +2 -0
  83. package/src/styles/typography/mixins.scss +3 -1
@@ -1,5 +1,6 @@
1
1
  @use "sass:map" as sassmap;
2
2
  @use "./../../../styles/tools/generate";
3
+ @use "./../../../styles/tools/layout";
3
4
  @use "./../../../styles/tokens/breakpoint";
4
5
  @use "./../../../styles/tokens/space";
5
6
  @use "./../../Section/styles/mixins" as section;
@@ -26,6 +27,7 @@
26
27
  flex-direction: column;
27
28
  justify-content: center;
28
29
  min-width: 0;
30
+ @include layout.reset-last-child-margin-bottom;
29
31
 
30
32
  > * {
31
33
  width: fit-content;
@@ -78,3 +80,9 @@
78
80
  }
79
81
  }
80
82
  }
83
+
84
+ @mixin promo-banner-vertical() {
85
+ .promo-banner__item {
86
+ padding-top: 0 !important;
87
+ }
88
+ }
@@ -26,6 +26,7 @@
26
26
  }
27
27
 
28
28
  &--vertical {
29
+ @include mixins.promo-banner-vertical;
29
30
  .promo-banner__item[class*="grid__col"],
30
31
  .promo-banner__image[class*="grid__col"]:not(
31
32
  .promo-banner__image--bleed-right
@@ -0,0 +1,60 @@
1
+ import cx from "classnames";
2
+ import React from "react";
3
+
4
+ type HeadingTag = "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
5
+
6
+ export interface TimelineItem {
7
+ description: React.ReactNode;
8
+ label?: React.ReactNode;
9
+ title: React.ReactNode;
10
+ }
11
+
12
+ export interface TimelineProps
13
+ extends React.OlHTMLAttributes<HTMLOListElement> {
14
+ items: TimelineItem[];
15
+ titleTag?: HeadingTag;
16
+ }
17
+
18
+ const CLASS_ROOT = "timeline";
19
+
20
+ const Timeline: React.FC<TimelineProps> = ({
21
+ items,
22
+ className,
23
+ start = 1,
24
+ titleTag: TitleTag = "h3",
25
+ ...other
26
+ }) => {
27
+ return (
28
+ <ol className={cx(CLASS_ROOT, className)} start={start} {...other}>
29
+ {items.map((item, index) => {
30
+ const itemNumber = start + index;
31
+ const label = item.label ?? null;
32
+
33
+ return (
34
+ <li
35
+ key={`${CLASS_ROOT}-item-${itemNumber}`}
36
+ className={`${CLASS_ROOT}__item`}
37
+ >
38
+ <div className={`${CLASS_ROOT}__number-column`} aria-hidden="true">
39
+ <span className={`${CLASS_ROOT}__number`}>{itemNumber}</span>
40
+ {index !== items.length - 1 && (
41
+ <div className={`${CLASS_ROOT}__line`} />
42
+ )}
43
+ </div>
44
+ <span className={`${CLASS_ROOT}__label`}>{label}</span>
45
+ <TitleTag className={`${CLASS_ROOT}__headline`}>
46
+ {item.title}
47
+ </TitleTag>
48
+ <div className={`${CLASS_ROOT}__description`}>
49
+ {item.description}
50
+ </div>
51
+ </li>
52
+ );
53
+ })}
54
+ </ol>
55
+ );
56
+ };
57
+
58
+ Timeline.displayName = "Timeline";
59
+
60
+ export { Timeline };
@@ -0,0 +1,2 @@
1
+ export type { TimelineItem, TimelineProps } from "./Timeline";
2
+ export { Timeline } from "./Timeline";
@@ -0,0 +1,25 @@
1
+ @use "sass:map";
2
+ @use "../../../styles/tools/convert";
3
+ @use "../../../styles/typography/config" as typography;
4
+
5
+ $number-column-width: convert.to-rem(64px);
6
+ $column-gap: convert.to-rem(20px);
7
+ $content-max-width: convert.to-rem(420px);
8
+ $line-width: convert.to-rem(2px);
9
+ $label-slot-height: convert.to-rem(20px);
10
+ $label-gap: convert.to-rem(5px);
11
+ $label-space: $label-slot-height + $label-gap;
12
+ $line-indent: convert.to-rem(30px);
13
+ $item-spacing-bottom: convert.to-rem(25px);
14
+
15
+ $headline: map.get(typography.$headings, 3);
16
+ $body: map.get(typography.$body-text, default);
17
+ $caption: (
18
+ default: map.merge(
19
+ map.get(typography.$caption, small),
20
+ (
21
+ font-weight: 700,
22
+ letter-spacing: convert.to-rem(0px),
23
+ )
24
+ ),
25
+ );
@@ -0,0 +1,102 @@
1
+ @use "./config";
2
+ @use "../../../styles/tools/generate";
3
+ @use "../../../styles/tools/convert";
4
+ @use "../../../styles/tokens/breakpoint";
5
+ @use "../../../styles/tokens/space";
6
+
7
+ @mixin timeline() {
8
+ list-style: none;
9
+ margin: 0 0 space.get("large") 0;
10
+ padding: 0;
11
+ }
12
+
13
+ @mixin item() {
14
+ display: grid;
15
+ grid-template-columns: config.$number-column-width minmax(0, 1fr);
16
+ column-gap: convert.to-rem(10px);
17
+ align-items: stretch;
18
+ padding-bottom: config.$item-spacing-bottom;
19
+
20
+ @include breakpoint.get("md") {
21
+ column-gap: convert.to-rem(20px);
22
+ }
23
+ }
24
+
25
+ @mixin item-last-child() {
26
+ padding-bottom: 0;
27
+ }
28
+
29
+ @mixin number-column() {
30
+ display: flex;
31
+ flex-direction: column;
32
+ align-items: center;
33
+ width: config.$number-column-width;
34
+ grid-column: 1;
35
+ grid-row: 1 / span 3;
36
+ }
37
+
38
+ @mixin number() {
39
+ @include generate.responsive-css-map(config.$headline);
40
+ color: var(--color-text-accent);
41
+ display: block;
42
+ text-align: center;
43
+ margin: 0;
44
+ margin-top: config.$label-space;
45
+ }
46
+
47
+ @mixin number-first-item() {
48
+ margin-top: 0;
49
+ }
50
+
51
+ @mixin line() {
52
+ flex: 1 1 auto;
53
+ width: config.$line-width;
54
+ background-color: var(--color-border-strong);
55
+ margin-bottom: convert.to-rem(-30px);
56
+ margin-top: config.$line-indent;
57
+ }
58
+
59
+ @mixin label() {
60
+ @include generate.responsive-css-map(config.$caption);
61
+ color: var(--color-text-default);
62
+ height: config.$label-slot-height;
63
+ min-height: config.$label-slot-height;
64
+ display: flex;
65
+ align-items: center;
66
+ margin: 0;
67
+ grid-column: 2;
68
+ }
69
+
70
+ @mixin label-spaced() {
71
+ margin-bottom: config.$label-gap;
72
+ }
73
+
74
+ @mixin empty-label() {
75
+ height: 0;
76
+ min-height: 0;
77
+ }
78
+
79
+ @mixin headline() {
80
+ @include generate.responsive-css-map(config.$headline);
81
+ color: var(--color-text-default);
82
+ margin: 0 0 space.get("small");
83
+ grid-column: 2;
84
+ max-width: config.$content-max-width;
85
+ min-width: 0;
86
+
87
+ > :last-child {
88
+ margin-bottom: 0;
89
+ }
90
+ }
91
+
92
+ @mixin description() {
93
+ @include generate.responsive-css-map(config.$body);
94
+ color: var(--color-text-default);
95
+ grid-column: 2;
96
+ max-width: config.$content-max-width;
97
+ min-width: 0;
98
+
99
+ > :last-child {
100
+ margin-bottom: 0;
101
+ }
102
+ }
@@ -0,0 +1,60 @@
1
+ @use "./config";
2
+ @use "./mixins";
3
+
4
+ @layer components {
5
+ .timeline {
6
+ @include mixins.timeline();
7
+
8
+ &__item {
9
+ @include mixins.item();
10
+ }
11
+
12
+ &__item:last-child {
13
+ @include mixins.item-last-child();
14
+ }
15
+
16
+ &__number-column {
17
+ @include mixins.number-column();
18
+ }
19
+
20
+ &__number {
21
+ @include mixins.number();
22
+ }
23
+
24
+ &__line {
25
+ @include mixins.line();
26
+ }
27
+
28
+ &__label {
29
+ @include mixins.label();
30
+ }
31
+
32
+ &__item:not(:first-child) &__label {
33
+ @include mixins.label-spaced();
34
+ }
35
+
36
+ &__item:first-child &__number {
37
+ @include mixins.number-first-item();
38
+ }
39
+
40
+ &__item:first-child:has(.timeline__label:not(:empty)) &__number {
41
+ margin-top: config.$label-space;
42
+ }
43
+
44
+ &__item:first-child:has(.timeline__label:not(:empty)) &__label {
45
+ @include mixins.label-spaced();
46
+ }
47
+
48
+ &__item:first-child &__label:empty {
49
+ @include mixins.empty-label();
50
+ }
51
+
52
+ &__headline {
53
+ @include mixins.headline();
54
+ }
55
+
56
+ &__description {
57
+ @include mixins.description();
58
+ }
59
+ }
60
+ }
@@ -0,0 +1,29 @@
1
+ import { render } from "@testing-library/react";
2
+ import { axe } from "vitest-axe";
3
+
4
+ import { Timeline } from "../";
5
+
6
+ const example = (
7
+ <Timeline
8
+ items={[
9
+ {
10
+ title: "Lorem ipsum dolor",
11
+ description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
12
+ },
13
+ {
14
+ title: "Dolor sit amet",
15
+ description: "Sed do eiusmod tempor incididunt ut labore.",
16
+ },
17
+ ]}
18
+ />
19
+ );
20
+
21
+ it("is valid html", () => {
22
+ const { container } = render(example);
23
+ expect(container).toHTMLValidate();
24
+ });
25
+
26
+ it("is accessible", async () => {
27
+ const { container } = render(example);
28
+ expect(await axe(container)).toHaveNoViolations();
29
+ });
@@ -0,0 +1,89 @@
1
+ import { render } from "@testing-library/react";
2
+
3
+ import { Timeline } from "../Timeline";
4
+
5
+ const items = [
6
+ {
7
+ title: "First item",
8
+ description: "First description",
9
+ },
10
+ {
11
+ title: "Second item",
12
+ description: "Second description",
13
+ label: "June 2026",
14
+ },
15
+ ];
16
+
17
+ describe("rendering Timeline", () => {
18
+ it("has default class timeline", () => {
19
+ const { getByTestId } = render(
20
+ <Timeline data-testid="test-id" items={items} />,
21
+ );
22
+
23
+ expect(getByTestId("test-id")).toHaveClass("timeline");
24
+ });
25
+
26
+ it("renders item for each timeline entry", () => {
27
+ const { container } = render(<Timeline items={items} />);
28
+
29
+ expect(container.getElementsByClassName("timeline__item")).toHaveLength(2);
30
+ });
31
+
32
+ it("renders connector only for non-last items", () => {
33
+ const { container } = render(<Timeline items={items} />);
34
+ const renderedItems = container.getElementsByClassName("timeline__item");
35
+
36
+ expect(
37
+ renderedItems[0].getElementsByClassName("timeline__line"),
38
+ ).toHaveLength(1);
39
+ expect(
40
+ renderedItems[1].getElementsByClassName("timeline__line"),
41
+ ).toHaveLength(0);
42
+ });
43
+
44
+ it("has additional class when className is set", () => {
45
+ const { getByTestId } = render(
46
+ <Timeline data-testid="test-id" items={items} className="test-class" />,
47
+ );
48
+
49
+ expect(getByTestId("test-id")).toHaveClass("timeline");
50
+ expect(getByTestId("test-id")).toHaveClass("test-class");
51
+ });
52
+
53
+ it("renders label slots for all items and visible text only for labeled items", () => {
54
+ const { container, getByText } = render(<Timeline items={items} />);
55
+ const renderedLabels = container.getElementsByClassName("timeline__label");
56
+
57
+ expect(renderedLabels).toHaveLength(2);
58
+ expect(getByText("June 2026")).toBeInTheDocument();
59
+ expect(renderedLabels[0].textContent).toBe("");
60
+ expect(renderedLabels[1].textContent).toBe("June 2026");
61
+ });
62
+
63
+ it("uses start prop for visible numbering", () => {
64
+ const { container } = render(<Timeline items={items} start={4} />);
65
+ const renderedNumbers =
66
+ container.getElementsByClassName("timeline__number");
67
+
68
+ expect(renderedNumbers[0].textContent).toBe("4");
69
+ expect(renderedNumbers[1].textContent).toBe("5");
70
+ });
71
+
72
+ it("renders `h3` headlines by default", () => {
73
+ const { container } = render(<Timeline items={items} />);
74
+ const renderedHeadlines = container.querySelectorAll(
75
+ "h3.timeline__headline",
76
+ );
77
+
78
+ expect(renderedHeadlines).toHaveLength(2);
79
+ });
80
+
81
+ it("renders custom headline tag when titleTag is set", () => {
82
+ const { container } = render(<Timeline items={items} titleTag="h4" />);
83
+ const renderedHeadlines = container.querySelectorAll(
84
+ "h4.timeline__headline",
85
+ );
86
+
87
+ expect(renderedHeadlines).toHaveLength(2);
88
+ });
89
+ });
@@ -92,6 +92,7 @@ import { Tab, TabPanel, Tabs } from "./Tabs";
92
92
  import { Tag, TagButton } from "./Tag";
93
93
  import { Testimonial } from "./Testimonial";
94
94
  import { Tile } from "./Tile";
95
+ import { Timeline } from "./Timeline";
95
96
  import { InfoTooltip, Tooltip } from "./Tooltip";
96
97
 
97
98
  export {
@@ -196,5 +197,6 @@ export {
196
197
  TextArea,
197
198
  TextInput,
198
199
  Tile,
200
+ Timeline,
199
201
  Tooltip,
200
202
  };
@@ -129,9 +129,11 @@
129
129
  }
130
130
 
131
131
  @mixin list-spacing($space, $config: config.$list-spacing) {
132
- > *:where(li) {
132
+ > *:where(li):not(:last-child) {
133
133
  margin-bottom: map.get($config, $space);
134
+ }
134
135
 
136
+ > *:where(li) {
135
137
  > *:where(ul, ol) {
136
138
  margin-top: map.get($config, $space);
137
139
  }