banhaten 0.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 (201) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +361 -0
  3. package/banhaten.config.example.json +13 -0
  4. package/package.json +59 -0
  5. package/registry/assets/activity-feed-avatar.png +0 -0
  6. package/registry/assets/avatars/avatar-01.jpg +0 -0
  7. package/registry/assets/avatars/avatar-02.jpg +0 -0
  8. package/registry/assets/avatars/avatar-03.jpg +0 -0
  9. package/registry/assets/avatars/avatar-04.jpg +0 -0
  10. package/registry/assets/avatars/avatar-05.jpg +0 -0
  11. package/registry/assets/avatars/avatar-06.jpg +0 -0
  12. package/registry/assets/avatars/avatar-07.jpg +0 -0
  13. package/registry/assets/avatars/avatar-08.jpg +0 -0
  14. package/registry/assets/avatars/avatar-09.jpg +0 -0
  15. package/registry/assets/avatars/avatar-10.jpg +0 -0
  16. package/registry/assets/avatars/avatar-11.jpg +0 -0
  17. package/registry/assets/avatars/avatar-12.jpg +0 -0
  18. package/registry/assets/avatars/avatar-13.jpg +0 -0
  19. package/registry/assets/avatars/avatar-14.jpg +0 -0
  20. package/registry/assets/avatars/avatar-15.jpg +0 -0
  21. package/registry/assets/avatars/avatar-16.jpg +0 -0
  22. package/registry/assets/avatars/avatar-17.jpg +0 -0
  23. package/registry/assets/avatars/avatar-18.jpg +0 -0
  24. package/registry/assets/avatars/avatar-19.jpg +0 -0
  25. package/registry/assets/avatars/avatar-20.jpg +0 -0
  26. package/registry/assets/avatars/avatar-21.jpg +0 -0
  27. package/registry/assets/avatars/avatar-22.jpg +0 -0
  28. package/registry/assets/avatars/avatar-23.jpg +0 -0
  29. package/registry/assets/avatars/avatar-24.jpg +0 -0
  30. package/registry/assets/avatars/avatar-25.jpg +0 -0
  31. package/registry/assets/avatars/avatar-26.jpg +0 -0
  32. package/registry/assets/avatars/avatar-27.jpg +0 -0
  33. package/registry/assets/avatars/avatar-28.jpg +0 -0
  34. package/registry/assets/avatars/avatar-29.jpg +0 -0
  35. package/registry/assets/avatars/avatar-30.jpg +0 -0
  36. package/registry/assets/avatars/avatar-31.jpg +0 -0
  37. package/registry/assets/avatars/avatar-32.jpg +0 -0
  38. package/registry/assets/avatars/avatar-33.jpg +0 -0
  39. package/registry/assets/avatars/avatar-34.jpg +0 -0
  40. package/registry/assets/avatars/avatar-35.jpg +0 -0
  41. package/registry/assets/image-assets.json +744 -0
  42. package/registry/assets/images/art-01.jpg +0 -0
  43. package/registry/assets/images/art-02.jpg +0 -0
  44. package/registry/assets/images/art-03.jpg +0 -0
  45. package/registry/assets/images/art-04.jpg +0 -0
  46. package/registry/assets/images/art-05.jpg +0 -0
  47. package/registry/assets/images/art-06.jpg +0 -0
  48. package/registry/assets/images/art-07.jpg +0 -0
  49. package/registry/assets/images/art-08.jpg +0 -0
  50. package/registry/assets/images/art-09.jpg +0 -0
  51. package/registry/assets/images/art-10.jpg +0 -0
  52. package/registry/assets/images/art-11.jpg +0 -0
  53. package/registry/assets/images/art-12.jpg +0 -0
  54. package/registry/assets/images/art-13.jpg +0 -0
  55. package/registry/assets/images/art-14.jpg +0 -0
  56. package/registry/assets/images/art-15.jpg +0 -0
  57. package/registry/assets/images/art-16.jpg +0 -0
  58. package/registry/assets/images/art-17.jpg +0 -0
  59. package/registry/assets/images/art-18.jpg +0 -0
  60. package/registry/assets/images/art-19.jpg +0 -0
  61. package/registry/assets/images/art-20.jpg +0 -0
  62. package/registry/assets/images/art-21.jpg +0 -0
  63. package/registry/assets/images/art-22.jpg +0 -0
  64. package/registry/assets/images/art-23.jpg +0 -0
  65. package/registry/assets/images/art-24.jpg +0 -0
  66. package/registry/assets/images/art-25.jpg +0 -0
  67. package/registry/assets/images/art-26.jpg +0 -0
  68. package/registry/assets/images/art-27.jpg +0 -0
  69. package/registry/assets/images/nature-01.jpg +0 -0
  70. package/registry/assets/images/nature-02.jpg +0 -0
  71. package/registry/assets/images/nature-03.jpg +0 -0
  72. package/registry/assets/images/nature-04.jpg +0 -0
  73. package/registry/assets/images/nature-05.jpg +0 -0
  74. package/registry/assets/images/nature-06.jpg +0 -0
  75. package/registry/assets/images/nature-07.jpg +0 -0
  76. package/registry/assets/images/nature-08.jpg +0 -0
  77. package/registry/assets/images/nature-09.jpg +0 -0
  78. package/registry/assets/images/nature-10.jpg +0 -0
  79. package/registry/assets/images/nature-11.jpg +0 -0
  80. package/registry/assets/images/nature-12.jpg +0 -0
  81. package/registry/assets/images/nature-13.jpg +0 -0
  82. package/registry/assets/images/nature-14.jpg +0 -0
  83. package/registry/assets/images/nature-15.jpg +0 -0
  84. package/registry/assets/images/nature-16.jpg +0 -0
  85. package/registry/assets/images/nature-17.jpg +0 -0
  86. package/registry/assets/images/nature-18.jpg +0 -0
  87. package/registry/assets/images/nature-19.jpg +0 -0
  88. package/registry/assets/images/nature-20.jpg +0 -0
  89. package/registry/components/accordion.tsx +119 -0
  90. package/registry/components/alert.tsx +282 -0
  91. package/registry/components/attribute.tsx +452 -0
  92. package/registry/components/avatar.tsx +142 -0
  93. package/registry/components/badge.tsx +567 -0
  94. package/registry/components/button-group.tsx +246 -0
  95. package/registry/components/button.tsx +102 -0
  96. package/registry/components/card.tsx +613 -0
  97. package/registry/components/checkbox.tsx +244 -0
  98. package/registry/components/date-picker.tsx +1143 -0
  99. package/registry/components/divider.tsx +82 -0
  100. package/registry/components/expanded/ActivityFeed.tsx +226 -0
  101. package/registry/components/expanded/Banner.tsx +145 -0
  102. package/registry/components/expanded/BannerBoard.tsx +225 -0
  103. package/registry/components/expanded/Breadcrumbs.tsx +156 -0
  104. package/registry/components/expanded/CatalogComponentsShowcase.tsx +211 -0
  105. package/registry/components/expanded/CatalogDivider.tsx +48 -0
  106. package/registry/components/expanded/CatalogTag.tsx +92 -0
  107. package/registry/components/expanded/CommandBar.tsx +406 -0
  108. package/registry/components/expanded/FileUpload.tsx +231 -0
  109. package/registry/components/expanded/IconExplorer.tsx +612 -0
  110. package/registry/components/expanded/OnboardingStepListItem.tsx +67 -0
  111. package/registry/components/expanded/PageHeader.tsx +184 -0
  112. package/registry/components/expanded/Slideout.tsx +514 -0
  113. package/registry/components/expanded/Steps.tsx +266 -0
  114. package/registry/components/expanded/Table.tsx +1014 -0
  115. package/registry/components/expanded/Tabs.tsx +86 -0
  116. package/registry/components/expanded/Timeline.tsx +235 -0
  117. package/registry/components/expanded/TimelineShowcase.tsx +158 -0
  118. package/registry/components/expanded/activityFeed.css +292 -0
  119. package/registry/components/expanded/banner.css +312 -0
  120. package/registry/components/expanded/breadcrumbs.css +140 -0
  121. package/registry/components/expanded/catalogComponentsShowcase.css +87 -0
  122. package/registry/components/expanded/commandBar.css +473 -0
  123. package/registry/components/expanded/divider.css +75 -0
  124. package/registry/components/expanded/fileUpload.css +228 -0
  125. package/registry/components/expanded/iconExplorer.css +764 -0
  126. package/registry/components/expanded/iconPacks.ts +866 -0
  127. package/registry/components/expanded/onboardingStepListItem.css +126 -0
  128. package/registry/components/expanded/pageHeader.css +287 -0
  129. package/registry/components/expanded/slideout.css +955 -0
  130. package/registry/components/expanded/steps.css +329 -0
  131. package/registry/components/expanded/table.css +607 -0
  132. package/registry/components/expanded/tabs.css +197 -0
  133. package/registry/components/expanded/tag.css +148 -0
  134. package/registry/components/expanded/timeline.css +282 -0
  135. package/registry/components/input-content.ts +106 -0
  136. package/registry/components/input.tsx +866 -0
  137. package/registry/components/menu.tsx +758 -0
  138. package/registry/components/modal.tsx +799 -0
  139. package/registry/components/pagination.tsx +543 -0
  140. package/registry/components/progress-slider.tsx +216 -0
  141. package/registry/components/progress.tsx +367 -0
  142. package/registry/components/radio-card.tsx +654 -0
  143. package/registry/components/radio-group.tsx +570 -0
  144. package/registry/components/select-content.tsx +313 -0
  145. package/registry/components/select.tsx +871 -0
  146. package/registry/components/slider.tsx +380 -0
  147. package/registry/components/social-button.tsx +360 -0
  148. package/registry/components/spinner.tsx +31 -0
  149. package/registry/components/tag.tsx +423 -0
  150. package/registry/components/textarea.tsx +625 -0
  151. package/registry/components/toggle.tsx +272 -0
  152. package/registry/components/toolbar.tsx +467 -0
  153. package/registry/components/tooltip.tsx +427 -0
  154. package/registry/examples/accordion-demo.tsx +34 -0
  155. package/registry/examples/alert-demo.tsx +14 -0
  156. package/registry/examples/attribute-demo.tsx +65 -0
  157. package/registry/examples/avatar-demo.tsx +74 -0
  158. package/registry/examples/badge-demo.tsx +53 -0
  159. package/registry/examples/button-demo.tsx +83 -0
  160. package/registry/examples/button-group-demo.tsx +42 -0
  161. package/registry/examples/card-demo.tsx +48 -0
  162. package/registry/examples/checkbox-demo.tsx +67 -0
  163. package/registry/examples/date-picker-demo.tsx +74 -0
  164. package/registry/examples/divider-demo.tsx +17 -0
  165. package/registry/examples/expanded/activity-feed-demo.tsx +22 -0
  166. package/registry/examples/expanded/banner-demo.tsx +23 -0
  167. package/registry/examples/expanded/catalog-components-demo.tsx +5 -0
  168. package/registry/examples/expanded/command-bar-demo.tsx +10 -0
  169. package/registry/examples/expanded/icons-demo.tsx +5 -0
  170. package/registry/examples/expanded/onboarding-step-demo.tsx +11 -0
  171. package/registry/examples/expanded/page-header-demo.tsx +19 -0
  172. package/registry/examples/expanded/slideout-demo.tsx +15 -0
  173. package/registry/examples/expanded/steps-demo.tsx +18 -0
  174. package/registry/examples/expanded/tabs-demo.tsx +13 -0
  175. package/registry/examples/expanded/timeline-demo.tsx +18 -0
  176. package/registry/examples/input-demo.tsx +87 -0
  177. package/registry/examples/menu-demo.tsx +109 -0
  178. package/registry/examples/modal-demo.tsx +16 -0
  179. package/registry/examples/pagination-demo.tsx +17 -0
  180. package/registry/examples/progress-demo.tsx +37 -0
  181. package/registry/examples/progress-slider-demo.tsx +29 -0
  182. package/registry/examples/radio-card-demo.tsx +51 -0
  183. package/registry/examples/radio-group-demo.tsx +62 -0
  184. package/registry/examples/select-demo.tsx +73 -0
  185. package/registry/examples/slider-demo.tsx +31 -0
  186. package/registry/examples/social-button-demo.tsx +51 -0
  187. package/registry/examples/tag-demo.tsx +29 -0
  188. package/registry/examples/textarea-demo.tsx +79 -0
  189. package/registry/examples/toggle-demo.tsx +59 -0
  190. package/registry/examples/toolbar-demo.tsx +80 -0
  191. package/registry/examples/tooltip-demo.tsx +115 -0
  192. package/registry/hooks/use-direction.ts +27 -0
  193. package/registry/index.json +1213 -0
  194. package/registry/styles/globals.css +4600 -0
  195. package/registry/utils/cn.ts +6 -0
  196. package/src/cli/index.js +826 -0
  197. package/tokens/Color mode.zip +0 -0
  198. package/tokens/Numbers.zip +0 -0
  199. package/tokens/Radius.zip +0 -0
  200. package/tokens/Theme.zip +0 -0
  201. package/tokens/banhaten.tokens.json +5525 -0
@@ -0,0 +1,86 @@
1
+ import { useId, useState } from "react";
2
+ import "./tabs.css";
3
+
4
+ export type TabsVariant = "underline" | "segment" | "rounded";
5
+ export type TabsSize = "md" | "sm" | "xs";
6
+
7
+ export type TabsProps = {
8
+ activeIndex?: number;
9
+ ariaLabel?: string;
10
+ className?: string;
11
+ defaultActiveIndex?: number;
12
+ dir?: "ltr" | "rtl";
13
+ fullWidth?: boolean;
14
+ items?: string[];
15
+ onActiveIndexChange?: (index: number) => void;
16
+ size?: TabsSize;
17
+ variant?: TabsVariant;
18
+ };
19
+
20
+ export function Tabs({
21
+ activeIndex,
22
+ ariaLabel,
23
+ className = "",
24
+ defaultActiveIndex = 0,
25
+ dir = "ltr",
26
+ fullWidth = false,
27
+ items = [],
28
+ onActiveIndexChange,
29
+ size = "md",
30
+ variant = "underline",
31
+ }: TabsProps) {
32
+ const rtl = dir === "rtl";
33
+ const generatedId = useId();
34
+ const [uncontrolledActiveIndex, setUncontrolledActiveIndex] = useState(defaultActiveIndex);
35
+ const selectedIndex = activeIndex ?? uncontrolledActiveIndex;
36
+
37
+ function selectTab(index: number) {
38
+ if (activeIndex === undefined) {
39
+ setUncontrolledActiveIndex(index);
40
+ }
41
+
42
+ onActiveIndexChange?.(index);
43
+ }
44
+
45
+ return (
46
+ <div
47
+ aria-label={ariaLabel}
48
+ className={[
49
+ "ds-tabs",
50
+ `ds-tabs--${variant}`,
51
+ `ds-tabs--${size}`,
52
+ fullWidth ? "ds-tabs--full" : "ds-tabs--hug",
53
+ rtl ? "ds-tabs--rtl" : "ds-tabs--ltr",
54
+ className,
55
+ ]
56
+ .filter(Boolean)
57
+ .join(" ")}
58
+ dir={dir}
59
+ role="tablist"
60
+ >
61
+ {items.map((item, index) => {
62
+ const selected = selectedIndex === index;
63
+ const tabId = `${generatedId}-tab-${index}`;
64
+ const panelId = `${generatedId}-panel-${index}`;
65
+
66
+ return (
67
+ <button
68
+ aria-controls={panelId}
69
+ aria-selected={selected}
70
+ className="ds-tabs__tab"
71
+ id={tabId}
72
+ key={`${item}-${index}`}
73
+ onClick={() => selectTab(index)}
74
+ role="tab"
75
+ tabIndex={selected ? 0 : -1}
76
+ type="button"
77
+ >
78
+ <span className="ds-tabs__content">
79
+ <span className="ds-tabs__label">{item}</span>
80
+ </span>
81
+ </button>
82
+ );
83
+ })}
84
+ </div>
85
+ );
86
+ }
@@ -0,0 +1,235 @@
1
+ import type { ReactNode } from "react";
2
+ import "./timeline.css";
3
+
4
+ export type TimelineOrientation = "vertical" | "horizontal";
5
+ export type TimelineVariant = "default" | "icon";
6
+ export type TimelineItemState = "finished" | "active" | "inactive";
7
+
8
+ export type TimelineStep = {
9
+ bottomDate?: string;
10
+ caption?: string;
11
+ date?: string;
12
+ icon?: ReactNode;
13
+ id?: string;
14
+ label?: string;
15
+ showBottomDate?: boolean;
16
+ showCaption?: boolean;
17
+ showLeadingDate?: boolean;
18
+ showLine?: boolean;
19
+ showPaddingBottom?: boolean;
20
+ showTopDate?: boolean;
21
+ state?: TimelineItemState;
22
+ topDate?: string;
23
+ };
24
+
25
+ export type TimelineItemProps = TimelineStep & {
26
+ className?: string;
27
+ dir?: "ltr" | "rtl";
28
+ orientation?: TimelineOrientation;
29
+ variant?: TimelineVariant;
30
+ };
31
+
32
+ export type TimelineProps = {
33
+ ariaLabel?: string;
34
+ className?: string;
35
+ dir?: "ltr" | "rtl";
36
+ orientation?: TimelineOrientation;
37
+ steps?: TimelineStep[];
38
+ variant?: TimelineVariant;
39
+ };
40
+
41
+ function classes(...names: Array<string | false | undefined>) {
42
+ return names.filter(Boolean).join(" ");
43
+ }
44
+
45
+ function Indicator({
46
+ icon,
47
+ orientation,
48
+ rtl,
49
+ showLine,
50
+ state,
51
+ variant,
52
+ }: {
53
+ icon?: ReactNode;
54
+ orientation: TimelineOrientation;
55
+ rtl: boolean;
56
+ showLine: boolean;
57
+ state: TimelineItemState;
58
+ variant: TimelineVariant;
59
+ }) {
60
+ const marker = (
61
+ <span
62
+ aria-hidden="true"
63
+ className={classes(
64
+ "ds-timeline__marker",
65
+ `ds-timeline__marker--${variant}`,
66
+ `ds-timeline__marker--${state}`,
67
+ )}
68
+ >
69
+ {variant === "icon" && (icon ?? <CheckIcon />)}
70
+ </span>
71
+ );
72
+ const line = showLine ? (
73
+ <span aria-hidden="true" className={classes("ds-timeline__line", `ds-timeline__line--${state}`)} />
74
+ ) : null;
75
+
76
+ return (
77
+ <span
78
+ className={classes(
79
+ "ds-timeline__indicator",
80
+ `ds-timeline__indicator--${orientation}`,
81
+ rtl && "ds-timeline__indicator--rtl",
82
+ )}
83
+ aria-hidden="true"
84
+ >
85
+ {orientation === "horizontal" && rtl ? (
86
+ <>
87
+ {line}
88
+ {marker}
89
+ </>
90
+ ) : (
91
+ <>
92
+ {marker}
93
+ {line}
94
+ </>
95
+ )}
96
+ </span>
97
+ );
98
+ }
99
+
100
+ export function TimelineItem({
101
+ bottomDate,
102
+ caption,
103
+ className,
104
+ date,
105
+ dir = "ltr",
106
+ icon,
107
+ label,
108
+ orientation = "vertical",
109
+ showBottomDate = false,
110
+ showCaption = true,
111
+ showLeadingDate = true,
112
+ showLine = true,
113
+ showPaddingBottom,
114
+ showTopDate = false,
115
+ state = "finished",
116
+ topDate,
117
+ variant = "default",
118
+ }: TimelineItemProps) {
119
+ const rtl = dir === "rtl";
120
+ const displayDate = date;
121
+ const displayLabel = label;
122
+ const displayCaption = caption;
123
+ const displayTopDate = topDate ?? displayDate;
124
+ const displayBottomDate = bottomDate ?? displayDate;
125
+ const hasPaddingBottom = showPaddingBottom ?? orientation === "vertical";
126
+
127
+ const body = (
128
+ <span className="ds-timeline__body">
129
+ {showTopDate && displayTopDate && <span className="ds-timeline__date ds-timeline__date--top">{displayTopDate}</span>}
130
+ <span className="ds-timeline__copy">
131
+ {displayLabel && <span className="ds-timeline__label">{displayLabel}</span>}
132
+ {showCaption && displayCaption && <span className="ds-timeline__caption">{displayCaption}</span>}
133
+ </span>
134
+ {showBottomDate && displayBottomDate && <span className="ds-timeline__date ds-timeline__date--bottom">{displayBottomDate}</span>}
135
+ {hasPaddingBottom && <span aria-hidden="true" className="ds-timeline__bottom-space" />}
136
+ </span>
137
+ );
138
+
139
+ const indicator = (
140
+ <Indicator
141
+ icon={icon}
142
+ orientation={orientation}
143
+ rtl={rtl}
144
+ showLine={showLine}
145
+ state={state}
146
+ variant={variant}
147
+ />
148
+ );
149
+
150
+ const leadingDate = showLeadingDate && displayDate ? (
151
+ <span className="ds-timeline__date ds-timeline__date--leading">{displayDate}</span>
152
+ ) : null;
153
+
154
+ return (
155
+ <div
156
+ className={classes(
157
+ "ds-timeline-item",
158
+ `ds-timeline-item--${orientation}`,
159
+ `ds-timeline-item--${variant}`,
160
+ `ds-timeline-item--${state}`,
161
+ rtl ? "ds-timeline-item--rtl" : "ds-timeline-item--ltr",
162
+ className,
163
+ )}
164
+ dir={dir}
165
+ role="listitem"
166
+ >
167
+ {orientation === "vertical" && rtl ? (
168
+ <>
169
+ {body}
170
+ {indicator}
171
+ {leadingDate}
172
+ </>
173
+ ) : orientation === "vertical" ? (
174
+ <>
175
+ {leadingDate}
176
+ {indicator}
177
+ {body}
178
+ </>
179
+ ) : (
180
+ <>
181
+ {leadingDate}
182
+ {indicator}
183
+ {body}
184
+ </>
185
+ )}
186
+ </div>
187
+ );
188
+ }
189
+
190
+ export function Timeline({
191
+ ariaLabel,
192
+ className,
193
+ dir = "ltr",
194
+ orientation = "vertical",
195
+ steps = [],
196
+ variant = "default",
197
+ }: TimelineProps) {
198
+ const rtl = dir === "rtl";
199
+
200
+ return (
201
+ <div
202
+ aria-label={ariaLabel}
203
+ className={classes(
204
+ "ds-timeline",
205
+ `ds-timeline--${orientation}`,
206
+ `ds-timeline--${variant}`,
207
+ rtl ? "ds-timeline--rtl" : "ds-timeline--ltr",
208
+ className,
209
+ )}
210
+ dir={dir}
211
+ role="list"
212
+ >
213
+ {steps.map((step, index) => (
214
+ <TimelineItem
215
+ {...step}
216
+ key={step.id ?? index}
217
+ dir={dir}
218
+ orientation={orientation}
219
+ showTopDate={step.showTopDate ?? orientation === "horizontal"}
220
+ showBottomDate={step.showBottomDate ?? false}
221
+ showPaddingBottom={step.showPaddingBottom ?? orientation === "vertical"}
222
+ variant={variant}
223
+ />
224
+ ))}
225
+ </div>
226
+ );
227
+ }
228
+
229
+ function CheckIcon() {
230
+ return (
231
+ <svg aria-hidden="true" className="ds-timeline__check" fill="none" viewBox="0 0 18 18">
232
+ <path d="m6.98 11.5 5.1-5.1 1.06 1.06-6.16 6.16-3.3-3.3 1.06-1.06 2.24 2.24Z" fill="currentColor" />
233
+ </svg>
234
+ );
235
+ }
@@ -0,0 +1,158 @@
1
+ import {
2
+ Timeline,
3
+ TimelineItem,
4
+ type TimelineItemState,
5
+ type TimelineOrientation,
6
+ type TimelineVariant,
7
+ } from "./Timeline";
8
+
9
+ type TimelineSpec = {
10
+ height: number;
11
+ id: string;
12
+ rtl: boolean;
13
+ variant: TimelineVariant;
14
+ width: number;
15
+ x: number;
16
+ y: number;
17
+ };
18
+
19
+ type TimelineItemSpec = TimelineSpec & {
20
+ orientation: TimelineOrientation;
21
+ state: TimelineItemState;
22
+ };
23
+
24
+ const verticalTimelineSpecs: TimelineSpec[] = [
25
+ { id: "572:6755", variant: "default", rtl: false, x: 225, y: 164, width: 600, height: 532 },
26
+ { id: "584:11474", variant: "icon", rtl: false, x: 1163, y: 164, width: 600, height: 532 },
27
+ { id: "573:6936", variant: "default", rtl: true, x: 225, y: 767, width: 600, height: 532 },
28
+ { id: "584:11482", variant: "icon", rtl: true, x: 1163, y: 767, width: 600, height: 532 },
29
+ ];
30
+
31
+ const horizontalTimelineSpecs: TimelineSpec[] = [
32
+ { id: "584:4500", variant: "default", rtl: false, x: 274, y: 207, width: 1000, height: 128 },
33
+ { id: "584:15619", variant: "icon", rtl: false, x: 274, y: 405, width: 1000, height: 136 },
34
+ { id: "584:4581", variant: "default", rtl: true, x: 274, y: 770, width: 1000, height: 128 },
35
+ { id: "584:15855", variant: "icon", rtl: true, x: 274, y: 968, width: 1000, height: 136 },
36
+ ];
37
+
38
+ const verticalItemSpecs: TimelineItemSpec[] = [
39
+ { id: "572:6443", orientation: "vertical", variant: "default", state: "finished", rtl: false, x: 150, y: 152, width: 500, height: 126 },
40
+ { id: "584:10301", orientation: "vertical", variant: "icon", state: "finished", rtl: false, x: 790, y: 143, width: 500, height: 126 },
41
+ { id: "572:6442", orientation: "vertical", variant: "default", state: "active", rtl: false, x: 150, y: 298, width: 500, height: 126 },
42
+ { id: "584:10317", orientation: "vertical", variant: "icon", state: "active", rtl: false, x: 790, y: 289, width: 500, height: 126 },
43
+ { id: "572:6441", orientation: "vertical", variant: "default", state: "inactive", rtl: false, x: 150, y: 461, width: 500, height: 126 },
44
+ { id: "584:10333", orientation: "vertical", variant: "icon", state: "inactive", rtl: false, x: 790, y: 452, width: 500, height: 126 },
45
+ { id: "572:6769", orientation: "vertical", variant: "default", state: "finished", rtl: true, x: 154, y: 758, width: 500, height: 126 },
46
+ { id: "584:11212", orientation: "vertical", variant: "icon", state: "finished", rtl: true, x: 785, y: 758, width: 500, height: 126 },
47
+ { id: "572:6785", orientation: "vertical", variant: "default", state: "active", rtl: true, x: 154, y: 908, width: 500, height: 126 },
48
+ { id: "584:11228", orientation: "vertical", variant: "icon", state: "active", rtl: true, x: 785, y: 908, width: 500, height: 126 },
49
+ { id: "572:6801", orientation: "vertical", variant: "default", state: "inactive", rtl: true, x: 154, y: 1058, width: 500, height: 126 },
50
+ { id: "584:11244", orientation: "vertical", variant: "icon", state: "inactive", rtl: true, x: 785, y: 1058, width: 500, height: 126 },
51
+ ];
52
+
53
+ const horizontalItemSpecs: TimelineItemSpec[] = [
54
+ { id: "582:4215", orientation: "horizontal", variant: "default", state: "finished", rtl: false, x: 311, y: 168, width: 240, height: 128 },
55
+ { id: "584:4325", orientation: "horizontal", variant: "default", state: "active", rtl: false, x: 595, y: 168, width: 240, height: 128 },
56
+ { id: "584:4351", orientation: "horizontal", variant: "default", state: "inactive", rtl: false, x: 864, y: 168, width: 240, height: 128 },
57
+ { id: "584:14794", orientation: "horizontal", variant: "icon", state: "finished", rtl: false, x: 311, y: 346, width: 240, height: 136 },
58
+ { id: "584:14807", orientation: "horizontal", variant: "icon", state: "active", rtl: false, x: 595, y: 346, width: 240, height: 136 },
59
+ { id: "584:14820", orientation: "horizontal", variant: "icon", state: "inactive", rtl: false, x: 864, y: 346, width: 240, height: 136 },
60
+ { id: "582:4231", orientation: "horizontal", variant: "default", state: "finished", rtl: true, x: 854, y: 630, width: 240, height: 128 },
61
+ { id: "584:4382", orientation: "horizontal", variant: "default", state: "active", rtl: true, x: 577, y: 630, width: 240, height: 128 },
62
+ { id: "584:4408", orientation: "horizontal", variant: "default", state: "inactive", rtl: true, x: 311, y: 630, width: 240, height: 128 },
63
+ { id: "584:14884", orientation: "horizontal", variant: "icon", state: "finished", rtl: true, x: 854, y: 804, width: 240, height: 136 },
64
+ { id: "584:14897", orientation: "horizontal", variant: "icon", state: "active", rtl: true, x: 577, y: 804, width: 240, height: 136 },
65
+ { id: "584:14910", orientation: "horizontal", variant: "icon", state: "inactive", rtl: true, x: 311, y: 804, width: 240, height: 136 },
66
+ ];
67
+
68
+ function timelineSteps(count: number, rtl = false) {
69
+ return Array.from({ length: count }, (_, index) => ({
70
+ caption: rtl ? "\u062a\u0633\u0645\u064a\u0629" : "Caption",
71
+ date: "Mar 15. 2050",
72
+ id: `timeline-step-${index}`,
73
+ label: rtl ? "\u0645\u0644\u0635\u0642" : "Label",
74
+ state: "finished" as const,
75
+ }));
76
+ }
77
+
78
+ function placement(spec: TimelineSpec) {
79
+ return {
80
+ height: spec.height,
81
+ left: spec.x,
82
+ top: spec.y,
83
+ width: spec.width,
84
+ };
85
+ }
86
+
87
+ export function TimelineShowcase() {
88
+ return (
89
+ <section className="timeline-showcase" aria-label="Figma Timeline component matrix">
90
+ <div className="timeline-showcase__row">
91
+ <div className="timeline-canvas timeline-canvas--vertical" data-node-id="572:6768">
92
+ {verticalTimelineSpecs.map((spec) => (
93
+ <div className="timeline-canvas__item" data-node-id={spec.id} key={spec.id} style={placement(spec)}>
94
+ <Timeline
95
+ ariaLabel={`${spec.rtl ? "RTL" : "LTR"} ${spec.variant} vertical timeline`}
96
+ dir={spec.rtl ? "rtl" : "ltr"}
97
+ orientation="vertical"
98
+ steps={timelineSteps(7, spec.rtl)}
99
+ variant={spec.variant}
100
+ />
101
+ </div>
102
+ ))}
103
+ </div>
104
+
105
+ <div className="timeline-canvas timeline-canvas--horizontal" data-node-id="584:4501">
106
+ {horizontalTimelineSpecs.map((spec) => (
107
+ <div className="timeline-canvas__item" data-node-id={spec.id} key={spec.id} style={placement(spec)}>
108
+ <Timeline
109
+ ariaLabel={`${spec.rtl ? "RTL" : "LTR"} ${spec.variant} horizontal timeline`}
110
+ dir={spec.rtl ? "rtl" : "ltr"}
111
+ orientation="horizontal"
112
+ steps={timelineSteps(6, spec.rtl)}
113
+ variant={spec.variant}
114
+ />
115
+ </div>
116
+ ))}
117
+ </div>
118
+ </div>
119
+
120
+ <div className="timeline-showcase__row">
121
+ <div className="timeline-canvas timeline-canvas--vertical-items" data-node-id="572:6444">
122
+ {verticalItemSpecs.map((spec) => (
123
+ <div className="timeline-canvas__item" data-node-id={spec.id} key={spec.id} style={placement(spec)}>
124
+ <TimelineItem
125
+ caption={spec.rtl ? "\u062a\u0633\u0645\u064a\u0629" : "Caption"}
126
+ date="Mar 15. 2050"
127
+ dir={spec.rtl ? "rtl" : "ltr"}
128
+ label={spec.rtl ? "\u0645\u0644\u0635\u0642" : "Label"}
129
+ orientation="vertical"
130
+ showBottomDate
131
+ showTopDate
132
+ state={spec.state}
133
+ variant={spec.variant}
134
+ />
135
+ </div>
136
+ ))}
137
+ </div>
138
+
139
+ <div className="timeline-canvas timeline-canvas--horizontal-items" data-node-id="582:4214">
140
+ {horizontalItemSpecs.map((spec) => (
141
+ <div className="timeline-canvas__item" data-node-id={spec.id} key={spec.id} style={placement(spec)}>
142
+ <TimelineItem
143
+ caption={spec.rtl ? "\u062a\u0633\u0645\u064a\u0629" : "Caption"}
144
+ date="Mar 15. 2050"
145
+ dir={spec.rtl ? "rtl" : "ltr"}
146
+ label={spec.rtl ? "\u0645\u0644\u0635\u0642" : "Label"}
147
+ orientation="horizontal"
148
+ showTopDate
149
+ state={spec.state}
150
+ variant={spec.variant}
151
+ />
152
+ </div>
153
+ ))}
154
+ </div>
155
+ </div>
156
+ </section>
157
+ );
158
+ }