Skip to content

Commit 718bcbe

Browse files
committed
refactor(CCarousel): add dark version, crossfade transistion
1 parent bd11a89 commit 718bcbe

File tree

5 files changed

+202
-31
lines changed

5 files changed

+202
-31
lines changed

src/components/carousel/CCarousel.mdx

Lines changed: 144 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { CCarouselIndicators } from './CCarouselIndicators.tsx'
1616
import { CCarouselInner } from './CCarouselInner.tsx'
1717
import { CCarouselItem } from './CCarouselItem.tsx'
1818

19-
import {slides} from './slides.ts'
19+
import {slides, slidesLight} from './slides.ts'
2020

2121
## How it works
2222

@@ -28,35 +28,159 @@ In browsers where the [Page Visibility API](https://www.w3.org/TR/page-visibilit
2828

2929
Carousels don't automatically normalize slide dimensions. As such, you may want to use extra utilities or custom methods to properly size content. While carousels support previous/next controls and indicators, they're not explicitly expected. Add and customize as you see fit.
3030

31+
### Slides only
32+
3133
<Playground>
3234
{() => {
3335
return (
3436
<CCarousel>
35-
<CCarouselInner>
36-
<CCarouselItem>
37-
<img className="d-block w-100" src={slides[0]} alt="slide 1"/>
38-
</CCarouselItem>
39-
<CCarouselItem>
40-
<img className="d-block w-100" src={slides[1]} alt="slide 2"/>
41-
</CCarouselItem>
42-
<CCarouselItem>
43-
<img className="d-block w-100" src={slides[2]} alt="slide 3"/>
44-
</CCarouselItem>
45-
</CCarouselInner>
46-
<CCarouselControl direction="prev"/>
47-
<CCarouselControl direction="next"/>
37+
<CCarouselItem>
38+
<img className="d-block w-100" src={slides[0]} alt="slide 1"/>
39+
</CCarouselItem>
40+
<CCarouselItem>
41+
<img className="d-block w-100" src={slides[1]} alt="slide 2"/>
42+
</CCarouselItem>
43+
<CCarouselItem>
44+
<img className="d-block w-100" src={slides[2]} alt="slide 3"/>
45+
</CCarouselItem>
4846
</CCarousel>
4947
)
5048
}}
49+
</Playground>
50+
51+
### With controls
52+
53+
Adding in the previous and next controls by `controls` property.
5154

55+
<Playground>
56+
{() => {
57+
return (
58+
<CCarousel controls>
59+
<CCarouselItem>
60+
<img className="d-block w-100" src={slides[0]} alt="slide 1"/>
61+
</CCarouselItem>
62+
<CCarouselItem>
63+
<img className="d-block w-100" src={slides[1]} alt="slide 2"/>
64+
</CCarouselItem>
65+
<CCarouselItem>
66+
<img className="d-block w-100" src={slides[2]} alt="slide 3"/>
67+
</CCarouselItem>
68+
</CCarousel>
69+
)
70+
}}
5271
</Playground>
5372

54-
<CCallout color="info">
55-
<h5>Conveying meaning to assistive technologies</h5>
56-
<p>
57-
Using color to add meaning only provides a visual indication, which will not be conveyed to users of assistive technologies – such as screen readers. Ensure that information denoted by the color is either obvious from the content itself (e.g. the visible text), or is included through alternative means, such as additional text hidden with the `.visually-hidden` class.
58-
</p>
59-
</CCallout>
73+
### With indicators
74+
75+
You can attach the indicators to the carousel, lengthwise the controls, too.
76+
77+
<Playground>
78+
{() => {
79+
return (
80+
<CCarousel controls indicators>
81+
<CCarouselItem>
82+
<img className="d-block w-100" src={slides[0]} alt="slide 1"/>
83+
</CCarouselItem>
84+
<CCarouselItem>
85+
<img className="d-block w-100" src={slides[1]} alt="slide 2"/>
86+
</CCarouselItem>
87+
<CCarouselItem>
88+
<img className="d-block w-100" src={slides[2]} alt="slide 3"/>
89+
</CCarouselItem>
90+
</CCarousel>
91+
)
92+
}}
93+
</Playground>
94+
95+
### With captions
96+
97+
You can add captions to slides with the `<CCarouselCaption>` element within any `<CCarouselItem>`. They can be immediately hidden on smaller viewports, as shown below, with optional [display utilities](https://coreui.io/4.0/utilities/display"). We hide them with `.d-none` and draw them back on medium-sized devices with `.d-md-block`.
98+
99+
<Playground>
100+
{() => {
101+
return (
102+
<CCarousel controls indicators>
103+
<CCarouselItem>
104+
<img className="d-block w-100" src={slides[0]} alt="slide 1"/>
105+
<CCarouselCaption className="d-none d-md-block">
106+
<h5>First slide label</h5>
107+
<p>Some representative placeholder content for the first slide.</p>
108+
</CCarouselCaption>
109+
</CCarouselItem>
110+
<CCarouselItem>
111+
<img className="d-block w-100" src={slides[1]} alt="slide 2"/>
112+
<CCarouselCaption className="d-none d-md-block">
113+
<h5>Second slide label</h5>
114+
<p>Some representative placeholder content for the first slide.</p>
115+
</CCarouselCaption>
116+
</CCarouselItem>
117+
<CCarouselItem>
118+
<img className="d-block w-100" src={slides[2]} alt="slide 3"/>
119+
<CCarouselCaption className="d-none d-md-block">
120+
<h5>Third slide label</h5>
121+
<p>Some representative placeholder content for the first slide.</p>
122+
</CCarouselCaption>
123+
</CCarouselItem>
124+
</CCarousel>
125+
)
126+
}}
127+
</Playground>
128+
129+
### Crossfade
130+
131+
Add `transition="crossfade"` to your carousel to animate slides with a fade transition instead of a slide.
132+
133+
<Playground>
134+
{() => {
135+
return (
136+
<CCarousel controls transition="crossfade">
137+
<CCarouselItem>
138+
<img className="d-block w-100" src={slides[0]} alt="slide 1"/>
139+
</CCarouselItem>
140+
<CCarouselItem>
141+
<img className="d-block w-100" src={slides[1]} alt="slide 2"/>
142+
</CCarouselItem>
143+
<CCarouselItem>
144+
<img className="d-block w-100" src={slides[2]} alt="slide 3"/>
145+
</CCarouselItem>
146+
</CCarousel>
147+
)
148+
}}
149+
</Playground>
150+
151+
## Dark variant
152+
153+
Add `dark` property to the `CCarousel` for darker controls, indicators, and captions. Controls have been inverted from their default white fill with the `filter` CSS property. Captions and controls have additional Sass variables that customize the `color` and `background-color`.
154+
155+
<Playground>
156+
{() => {
157+
return (
158+
<CCarousel controls indicators dark>
159+
<CCarouselItem>
160+
<img className="d-block w-100" src={slidesLight[0]} alt="slide 1"/>
161+
<CCarouselCaption className="d-none d-md-block">
162+
<h5>First slide label</h5>
163+
<p>Some representative placeholder content for the first slide.</p>
164+
</CCarouselCaption>
165+
</CCarouselItem>
166+
<CCarouselItem>
167+
<img className="d-block w-100" src={slidesLight[1]} alt="slide 2"/>
168+
<CCarouselCaption className="d-none d-md-block">
169+
<h5>Second slide label</h5>
170+
<p>Some representative placeholder content for the first slide.</p>
171+
</CCarouselCaption>
172+
</CCarouselItem>
173+
<CCarouselItem>
174+
<img className="d-block w-100" src={slidesLight[2]} alt="slide 3"/>
175+
<CCarouselCaption className="d-none d-md-block">
176+
<h5>Third slide label</h5>
177+
<p>Some representative placeholder content for the first slide.</p>
178+
</CCarouselCaption>
179+
</CCarouselItem>
180+
</CCarousel>
181+
)
182+
}}
183+
</Playground>
60184

61185
## API
62186

src/components/carousel/CCarousel.tsx

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,35 @@ import React, { forwardRef, HTMLAttributes, useState, useEffect, useRef } from '
22
import PropTypes from 'prop-types'
33
import classNames from 'classnames'
44

5+
import { CCarouselControl } from './CCarouselControl'
6+
import { CCarouselIndicators } from './CCarouselIndicators'
7+
import { CCarouselInner } from './CCarouselInner'
8+
59
export interface CCarouselProps extends HTMLAttributes<HTMLDivElement> {
10+
/**
11+
* Set 'animate' variable for created context. [docs]
12+
*
13+
* @type boolean
14+
*/
15+
animate?: boolean
616
/**
717
* A string of all className you want applied to the base component. [docs]
18+
*
19+
* @type string
820
*/
921
className?: string
1022
/**
11-
* Set 'animate' variable for created context. [docs]
23+
* Adding in the previous and next controls. [docs]
1224
*
25+
* @type: boolean
26+
*/
27+
controls?: boolean
28+
/**
29+
* Add darker controls, indicators, and captions. [docs]
30+
*
1331
* @type boolean
1432
*/
15-
animate?: boolean
33+
dark?: boolean
1634
/**
1735
* The amount of time to delay between automatically cycling an item. If false, carousel will not automatically cycle. [docs]
1836
*
@@ -25,6 +43,12 @@ export interface CCarouselProps extends HTMLAttributes<HTMLDivElement> {
2543
* @type number
2644
*/
2745
index?: number
46+
/**
47+
* Adding indicators at the bottom of the carousel for each item. [docs]
48+
*
49+
* @type boolean
50+
*/
51+
indicators?: boolean
2852
/**
2953
* On slide change callback. [docs]
3054
*
@@ -67,7 +91,19 @@ export const Context = React.createContext<ContextType>({
6791

6892
export const CCarousel = forwardRef<HTMLDivElement, CCarouselProps>(
6993
(
70-
{ className, children, index = 0, animate = true, interval = 5000, onSlideChange, transition, ...rest },
94+
{
95+
children,
96+
animate = true,
97+
className,
98+
controls,
99+
dark,
100+
index = 0,
101+
indicators,
102+
interval = 5000,
103+
onSlideChange,
104+
transition,
105+
...rest
106+
},
71107
ref,
72108
) => {
73109
const [state, setState] = useState<[number | null, number, string?]>([null, index])
@@ -105,7 +141,8 @@ export const CCarousel = forwardRef<HTMLDivElement, CCarouselProps>(
105141
const _className = classNames(
106142
'carousel slide',
107143
transition === 'crossfade' && 'carousel-fade',
108-
className
144+
dark && 'carousel-dark',
145+
className,
109146
)
110147

111148
return (
@@ -121,7 +158,14 @@ export const CCarousel = forwardRef<HTMLDivElement, CCarouselProps>(
121158
setAnimating,
122159
}}
123160
>
124-
{children}
161+
{indicators && <CCarouselIndicators/>}
162+
<CCarouselInner>{children}</CCarouselInner>
163+
{controls && (
164+
<>
165+
<CCarouselControl direction="prev" />
166+
<CCarouselControl direction="next" />
167+
</>
168+
)}
125169
</Context.Provider>
126170
</div>
127171
)
@@ -133,10 +177,7 @@ CCarousel.propTypes = {
133177
children: PropTypes.node,
134178
className: PropTypes.string,
135179
index: PropTypes.number,
136-
interval: PropTypes.oneOfType([
137-
PropTypes.bool,
138-
PropTypes.number
139-
]).isRequired,
180+
interval: PropTypes.oneOfType([PropTypes.bool, PropTypes.number]).isRequired,
140181
onSlideChange: PropTypes.func,
141182
}
142183

src/components/carousel/CCarouselControl.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { forwardRef, HTMLAttributes, RefObject, useContext } from 'react'
1+
import React, { forwardRef, HTMLAttributes, useContext } from 'react'
22
import PropTypes from 'prop-types'
33
import classNames from 'classnames'
44
import { Context } from './CCarousel'
@@ -50,7 +50,7 @@ export const CCarouselControl = forwardRef<HTMLButtonElement, CCarouselControlPr
5050
CCarouselControl.propTypes = {
5151
children: PropTypes.node,
5252
className: PropTypes.string,
53-
direction: PropTypes.oneOf<Direction>(['prev', 'next']).isRequired, // TODO: check
53+
direction: PropTypes.oneOf<Direction>(['prev', 'next']).isRequired,
5454
}
5555

5656
CCarouselControl.displayName = 'CCarouselControl'

src/components/carousel/CCarouselIndicators.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export const CCarouselIndicators = forwardRef<HTMLOListElement, CCarouselIndicat
3030
!animating && key !== state[1] && setState([state[1], key])
3131
}}
3232
className={state[1] === key ? 'active' : ''}
33+
data-coreui-target=''
3334
/>
3435
)
3536
})

src/components/carousel/slides.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,9 @@ export const slides = [
22
'data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22800%22%20height%3D%22400%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20800%20400%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_1607923e7e2%20text%20%7B%20fill%3A%23555%3Bfont-weight%3Anormal%3Bfont-family%3AHelvetica%2C%20monospace%3Bfont-size%3A40pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_1607923e7e2%22%3E%3Crect%20width%3D%22800%22%20height%3D%22400%22%20fill%3D%22%23777%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%22285.9296875%22%20y%3D%22217.75625%22%3EFirst%20slide%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E',
33
'data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22800%22%20height%3D%22400%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20800%20400%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_15ba800aa20%20text%20%7B%20fill%3A%23444%3Bfont-weight%3Anormal%3Bfont-family%3AHelvetica%2C%20monospace%3Bfont-size%3A40pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_15ba800aa20%22%3E%3Crect%20width%3D%22800%22%20height%3D%22400%22%20fill%3D%22%23666%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%22247.3203125%22%20y%3D%22218.3%22%3ESecond%20slide%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E',
44
'data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22800%22%20height%3D%22400%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20800%20400%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_15ba800aa21%20text%20%7B%20fill%3A%23333%3Bfont-weight%3Anormal%3Bfont-family%3AHelvetica%2C%20monospace%3Bfont-size%3A40pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_15ba800aa21%22%3E%3Crect%20width%3D%22800%22%20height%3D%22400%22%20fill%3D%22%23555%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%22277%22%20y%3D%22218.3%22%3EThird%20slide%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E',
5+
]
6+
export const slidesLight = [
7+
'data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22800%22%20height%3D%22400%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20800%20400%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_1607923e7e2%20text%20%7B%20fill%3A%23AAA%3Bfont-weight%3Anormal%3Bfont-family%3AHelvetica%2C%20monospace%3Bfont-size%3A40pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_1607923e7e2%22%3E%3Crect%20width%3D%22800%22%20height%3D%22400%22%20fill%3D%22%23F5F5F5%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%22285.9296875%22%20y%3D%22217.75625%22%3EFirst%20slide%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E',
8+
'data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22800%22%20height%3D%22400%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20800%20400%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_15ba800aa20%20text%20%7B%20fill%3A%23BBB%3Bfont-weight%3Anormal%3Bfont-family%3AHelvetica%2C%20monospace%3Bfont-size%3A40pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_15ba800aa20%22%3E%3Crect%20width%3D%22800%22%20height%3D%22400%22%20fill%3D%22%23EEE%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%22247.3203125%22%20y%3D%22218.3%22%3ESecond%20slide%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E',
9+
'data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22800%22%20height%3D%22400%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20800%20400%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_15ba800aa21%20text%20%7B%20fill%3A%23999%3Bfont-weight%3Anormal%3Bfont-family%3AHelvetica%2C%20monospace%3Bfont-size%3A40pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_15ba800aa21%22%3E%3Crect%20width%3D%22800%22%20height%3D%22400%22%20fill%3D%22%23E5E5E5%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%22277%22%20y%3D%22218.3%22%3EThird%20slide%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E',
510
]

0 commit comments

Comments
 (0)