11import React , { useRef } from "react" ;
2- import styled , { css , keyframes } from "styled-components" ;
3- import Spine , { VariantProp , variantColor } from "./spine" ;
2+ import Spine , { VariantProp , colorRegex } from "./spine" ;
43export type { VariantProp } ;
5- import { h2 , p , small } from "../../../styles/common-style" ;
4+ import clsx from "clsx" ;
5+ import { cn , isUndefined } from "../../../utils" ;
66
77export interface SideProp {
88 rightSided ?: boolean ;
@@ -12,138 +12,110 @@ export interface StateProp {
1212 state ?: "loading" | "disabled" | "active" ;
1313}
1414
15- const loading = keyframes `
16- 0%{
17- opacity: 1;
18- }
19- 50%{
20- opacity: 0.5;
21- }
22- 100%{
23- opacity: 1;
24- }
25- ` ;
26-
27- const Wrapper = styled . div < SideProp & StateProp > `
28- display: flex;
29- position: relative;
30- justify-content: ${ ( { rightSided } ) =>
31- rightSided ? "flex-start" : "flex-end" } ;
32- ${ ( { state } ) => {
33- if ( state === "disabled" )
34- return css `
35- opacity: 0.5;
36- ` ;
37- if ( state === "loading" )
38- return css `
39- animation: ${ loading } 2s ease-in-out infinite normal;
40- ` ;
41- return css `
42- opacity: 1;
43- ` ;
44- } }
45- ` ;
46-
47- const StyledTitle = styled . h2 `` ;
48- const StyledParty = styled . p `` ;
49- const StyledSubtitle = styled . small `` ;
50- const PartyElementWrapper = styled . div `
51- display: inline-flex;
52- ` ;
53-
54- const TextContainer = styled . div < SideProp & VariantProp & { isLast : boolean } > `
55- margin-${ ( { rightSided } ) => ( rightSided ? "left" : "right" ) } : 20px;
56- order: ${ ( { rightSided } ) => ( rightSided ? 1 : - 1 ) } ;
57- display: flex;
58- flex-direction: column;
59- margin-bottom: ${ ( { isLast } ) => ( isLast ? "0" : "18px" ) } ;
60- gap: 2px;
61- text-align: ${ ( { rightSided } ) => ( rightSided ? "left" : "right" ) } ;
62-
63- @media (max-width: 900px) {
64- margin-${ ( { rightSided } ) => ( rightSided ? "left" : "right" ) } : 16px;
65- margin-bottom: ${ ( { isLast } ) => ( isLast ? "0" : "16px" ) } ;
66- gap: 4px;
67- }
68-
69- & ${ StyledTitle } {
70- ${ h2 }
71- order: ${ ( { rightSided } ) => ( rightSided ? 1 : 2 ) } ;
72- font-size: 14px;
73- line-height: 19px;
74- color: ${ ( { theme } ) => theme . klerosUIComponentsPrimaryText } ;
75- }
76-
77- & ${ StyledParty } {
78- ${ p }
79- order: ${ ( { rightSided } ) => ( rightSided ? 2 : 1 ) } ;
80-
81- font-size: 14px;
82- line-height: 19px;
83- color: ${ variantColor } ;
84- }
85-
86- & ${ PartyElementWrapper } {
87- order: ${ ( { rightSided } ) => ( rightSided ? 2 : 1 ) } ;
88- max-height: 32px;
89- overflow: hidden;
90- }
91-
92- & ${ StyledSubtitle } {
93- ${ small }
94- align-self: flex-${ ( { rightSided } ) => ( rightSided ? "start" : "end" ) } ;
95- font-size: 12px;
96- line-height: 16px;
97- }
98- ` ;
99-
100- const PartyTitleContainer = styled . div < SideProp > `
101- display: flex;
102- position: relative;
103- align-items: center;
104- flex-direction: row;
105- flex-wrap: wrap;
106- gap: 4px 8px;
107- justify-content: ${ ( { rightSided } ) =>
108- rightSided ? "flex-start" : "flex-end" } ;
109- ` ;
110-
11115interface BulletProps extends VariantProp , SideProp , StateProp {
11216 title : string ;
11317 party : string | React . ReactElement ;
11418 subtitle : string ;
115- active ?: boolean ;
11619 Icon ?: React . FC < React . SVGAttributes < SVGElement > > ;
11720 line ?: boolean ;
11821 isLast : boolean ;
22+ className ?: string ;
11923}
12024
12125const Bullet : React . FC < BulletProps > = ( props ) => {
122- const { title, party, subtitle, ...restProps } = props ;
123- const { rightSided, variant, line, Icon, isLast, state, ...wrapperProps } =
124- restProps ;
26+ const { title, party, subtitle, className, ...restProps } = props ;
27+ const { rightSided, variant, line, Icon, isLast, state } = restProps ;
12528 const titleRef = useRef < HTMLHeadingElement > ( null ) ;
12629
12730 return (
128- < Wrapper { ...{ rightSided, state } } { ...wrapperProps } >
31+ < div
32+ className = { cn (
33+ "relative flex opacity-100" ,
34+ rightSided ? "justify-start" : "justify-end" ,
35+ {
36+ "opacity-50" : state === "disabled" ,
37+ "animate-loading" : state === "loading" ,
38+ } ,
39+ className ,
40+ ) }
41+ aria-label = { `Timeline item: ${ title } ` }
42+ role = "listitem"
43+ aria-current = { state === "active" ? "step" : undefined }
44+ aria-busy = { state === "loading" ? true : false }
45+ aria-disabled = { state === "disabled" ? true : false }
46+ >
12947 < Spine { ...{ variant, line, Icon, titleRef } } />
130- < TextContainer
131- className = "text-container"
132- { ...{ variant, rightSided, isLast } }
48+ < div
49+ className = { clsx (
50+ "flex flex-col gap-1 lg:gap-0.5" ,
51+ rightSided
52+ ? [ "ml-4 lg:ml-5" , "order-1 text-left" ]
53+ : [ "mr-4 lg:mr-5" , "-order-1 text-right" ] ,
54+ isLast ? "mb-0" : "mb-4 lg:mb-4.5" ,
55+ ) }
13356 >
134- < PartyTitleContainer { ...{ rightSided } } >
135- < StyledTitle ref = { titleRef } > { title } </ StyledTitle >
57+ < div
58+ className = { clsx (
59+ "relative" ,
60+ "flex flex-row flex-wrap items-center gap-x-2 gap-y-1" ,
61+ rightSided ? "justify-start" : "justify-end" ,
62+ ) }
63+ >
64+ < h2
65+ className = { clsx (
66+ "text-klerosUIComponentsPrimaryText text-sm font-semibold" ,
67+ rightSided ? "order-1" : "order-2" ,
68+ ) }
69+ aria-label = { `Timeline item title: ${ title } ` }
70+ ref = { titleRef }
71+ >
72+ { title }
73+ </ h2 >
13674 { typeof party === `string` ? (
137- < StyledParty > { party } </ StyledParty >
75+ < p
76+ className = { clsx (
77+ "text-sm font-normal break-words" ,
78+ rightSided ? "order-2" : "order-1" ,
79+ {
80+ "text-klerosUIComponentsSuccess" : variant === "accepted" ,
81+ "text-klerosUIComponentsError" : variant === "refused" ,
82+ "text-klerosUIComponentsPrimaryBlue" : isUndefined ( variant ) ,
83+ } ,
84+ ) }
85+ style = {
86+ variant && colorRegex . test ( variant )
87+ ? {
88+ color : variant ,
89+ }
90+ : undefined
91+ }
92+ aria-label = { `Timeline item party: ${ party } ` }
93+ >
94+ { party }
95+ </ p >
13896 ) : (
139- < PartyElementWrapper className = "party-wrapper" >
97+ < div
98+ className = { clsx (
99+ "inline-flex max-h-8 overflow-hidden" ,
100+ rightSided ? "order-2" : "order-1" ,
101+ ) }
102+ aria-label = "Timeline item party element"
103+ >
140104 { party }
141- </ PartyElementWrapper >
105+ </ div >
106+ ) }
107+ </ div >
108+ < small
109+ className = { clsx (
110+ "text-klerosUIComponentsSecondaryText text-xs break-words" ,
111+ rightSided ? "self-start" : "self-end" ,
142112 ) }
143- </ PartyTitleContainer >
144- < StyledSubtitle > { subtitle } </ StyledSubtitle >
145- </ TextContainer >
146- </ Wrapper >
113+ aria-label = { `Timeline item date: ${ subtitle } ` }
114+ >
115+ { subtitle }
116+ </ small >
117+ </ div >
118+ </ div >
147119 ) ;
148120} ;
149121
0 commit comments