Skip to content

Commit a870081

Browse files
DEmmaRLDiego Riveraautofix-ci[bot]kermanx
authored
feat: introduce named animation presets for v-click (#2501)
Co-authored-by: Diego Rivera <d.rivera@beehivesystems.mx> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: _Kerman <kermanx@qq.com>
1 parent dcbd357 commit a870081

15 files changed

Lines changed: 321 additions & 39 deletions

File tree

cypress/e2e/examples/basic.spec.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,4 +257,61 @@ context('Basic', () => {
257257
cy.get('#slideshow .slidev-page-13 .cy-wrapdecorate > ul > .slidev-vclick-target:not(.slidev-vclick-hidden)')
258258
.should('have.text', 'AEFZ')
259259
})
260+
261+
it('click animation presets', () => {
262+
goPage(14)
263+
264+
// Check animation classes are set on mount
265+
cy.get('#slideshow .slidev-page-14 .cy-animation-presets .slidev-vclick-target').eq(0).should('have.class', 'slidev-vclick-anim-fade').and('have.class', 'slidev-vclick-anim-up')
266+
cy.get('#slideshow .slidev-page-14 .cy-animation-presets .slidev-vclick-target').eq(1).should('have.class', 'slidev-vclick-anim-scale')
267+
cy.get('#slideshow .slidev-page-14 .cy-animation-presets .slidev-vclick-target').eq(2).should('have.class', 'slidev-vclick-anim-none')
268+
269+
// After clicks, elements become visible
270+
cy.rightArrow()
271+
cy.get('#slideshow .slidev-page-14 .cy-animation-presets .slidev-vclick-target:not(.slidev-vclick-hidden)')
272+
.should('have.text', 'fade-up')
273+
274+
cy.rightArrow()
275+
cy.get('#slideshow .slidev-page-14 .cy-animation-presets .slidev-vclick-target:not(.slidev-vclick-hidden)')
276+
.should('have.length', 2)
277+
278+
cy.rightArrow()
279+
cy.get('#slideshow .slidev-page-14 .cy-animation-presets .slidev-vclick-target:not(.slidev-vclick-hidden)')
280+
.should('have.length', 3)
281+
})
282+
283+
it('click animation from frontmatter', () => {
284+
goPage(15)
285+
286+
cy.get('#slideshow .slidev-page-15 .cy-animation-frontmatter .slidev-vclick-target')
287+
.should('have.class', 'slidev-vclick-anim-fade')
288+
.and('have.class', 'slidev-vclick-anim-down')
289+
290+
cy.rightArrow()
291+
cy.get('#slideshow .slidev-page-15 .cy-animation-frontmatter .slidev-vclick-target:not(.slidev-vclick-hidden)')
292+
.should('have.text', 'from-frontmatter')
293+
})
294+
295+
it('click animation hierarchy and override', () => {
296+
goPage(16)
297+
298+
const targets = '#slideshow .slidev-page-16 .cy-animation-hierarchy .slidev-vclick-target'
299+
300+
// custom frontmatter still gets reflected for elements without modifiers
301+
cy.get(targets).eq(0).should('have.class', 'slidev-vclick-anim-foo')
302+
303+
// element modifiers override slide frontmatter preset
304+
cy.get(targets).eq(1).should('not.have.class', 'slidev-vclick-anim-foo').and('have.class', 'slidev-vclick-anim-fade').and('have.class', 'slidev-vclick-anim-right')
305+
306+
// none modifier also overrides slide frontmatter preset
307+
cy.get(targets).eq(2).should('not.have.class', 'slidev-vclick-anim-foo').and('have.class', 'slidev-vclick-anim-none').invoke('css', 'transition').should('match', /^none/)
308+
309+
// another valid modifier should also override invalid frontmatter
310+
cy.get(targets).eq(3).should('not.have.class', 'slidev-vclick-anim-foo').and('have.class', 'slidev-vclick-anim-scale')
311+
312+
// reveal sequence remains functional with mixed presets
313+
cy.rightArrow(4)
314+
cy.get(`${targets}:not(.slidev-vclick-hidden)`)
315+
.should('have.length', 4)
316+
})
260317
})

cypress/fixtures/basic/slides.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,3 +177,36 @@ Left
177177
<li>step j</li>
178178
</wrap-in-component-in-clicks>
179179
</div>
180+
181+
---
182+
183+
# Page 14
184+
185+
<div class="cy-animation-presets">
186+
<div v-click.fade.up>fade-up</div>
187+
<div v-click.scale>scale</div>
188+
<div v-click.none>none</div>
189+
</div>
190+
191+
---
192+
clickAnimation: fade down
193+
---
194+
195+
# Page 15
196+
197+
<div class="cy-animation-frontmatter">
198+
<div v-click>from-frontmatter</div>
199+
</div>
200+
201+
---
202+
clickAnimation: foo
203+
---
204+
205+
# Page 16
206+
207+
<div class="cy-animation-hierarchy">
208+
<div v-click>frontmatter-invalid-foo</div>
209+
<div v-click.fade.right>modifier-overrides-frontmatter</div>
210+
<div v-click.none>modifier-none-overrides-frontmatter</div>
211+
<div v-click.scale>modifier-scale-overrides-frontmatter</div>
212+
</div>

demo/starter/slides.md

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -340,21 +340,46 @@ You can add `v-click` to elements to add a click animation.
340340

341341
<div v-click>
342342

343-
This shows up when you click the slide:
343+
This shows up when you press <kbd>space</kbd> or <kbd>right</kbd>, or click outside the slide on the right.
344344

345345
```html
346-
<div v-click>This shows up when you click the slide.</div>
346+
<div v-click>This shows up when you trigger a click animation.</div>
347347
```
348348

349349
</div>
350350

351-
<br>
351+
<p v-click>
352+
You can also add modifiers to change the animation:
353+
</p>
354+
355+
<div class="grid gap-3 mt-4 text-sm" style="grid-template-columns: repeat(3, 1fr) 1.5fr 1fr">
356+
<div v-after.up class="p-3 rounded border border-primary/20 bg-primary/10">
357+
<div class="font-mono text-xs opacity-60 mb-1">v-click.up</div>
358+
<div>Slide from bottom</div>
359+
</div>
360+
<div v-click.fade-in class="p-3 rounded border border-primary/30 bg-primary/15">
361+
<div class="font-mono text-xs opacity-60 mb-1">v-click.fade-in</div>
362+
<div>Fade in</div>
363+
</div>
364+
<div v-click.fade class="p-3 rounded border border-primary/40 bg-primary/20">
365+
<div class="font-mono text-xs opacity-60 mb-1">v-click.fade</div>
366+
<div>Dim (0.5 opacity)</div>
367+
</div>
368+
<div v-click.fade.right.scale class="p-3 rounded border border-primary/50 bg-primary/25">
369+
<div class="font-mono text-xs opacity-60 mb-1">v-click.fade.right.scale</div>
370+
<div>Composed</div>
371+
</div>
372+
<div v-click.none class="p-3 rounded border border-primary/60 bg-primary/30">
373+
<div class="font-mono text-xs opacity-60 mb-1">v-click.none</div>
374+
<div>No transition</div>
375+
</div>
376+
</div>
352377

353378
<v-click>
354379

355-
The <span v-mark.red="3"><code>v-mark</code> directive</span>
380+
The <span v-mark.red="7"><code>v-mark</code> directive</span>
356381
also allows you to add
357-
<span v-mark.circle.orange="4">inline marks</span>
382+
<span v-mark.circle.orange="8">inline marks</span>
358383
, powered by [Rough Notation](https://roughnotation.com/):
359384

360385
```html
@@ -363,7 +388,7 @@ also allows you to add
363388

364389
</v-click>
365390

366-
<div mt-20 v-click>
391+
<div v-click mt-12>
367392

368393
[Learn more](https://sli.dev/guide/animations#click-animation)
369394

docs/custom/index.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,21 @@ contextMenu: true
6666
wakeLock: true
6767
# take snapshot for each slide in the overview
6868
overviewSnapshots: false
69+
# router mode for vue-router, can be "history" or "hash"
70+
routerMode: history
6971

7072
# force color schema for the slides, can be 'auto', 'light', or 'dark'
7173
colorSchema: auto
72-
# router mode for vue-router, can be "history" or "hash"
73-
routerMode: history
7474
# aspect ratio for the slides
7575
aspectRatio: 16/9
7676
# real width of the canvas, unit in px
7777
canvasWidth: 980
78+
# defines the default transition between slides
79+
# Learn more: https://sli.dev/guide/animations.html#slide-transitions
80+
transition: undefined # or BuiltinSlideTransition | string | TransitionGroupProps | null
81+
# defines the default animation presets for click animations
82+
# Learn more: https://sli.dev/guide/animations.html#click-animation-presets
83+
clickAnimation: undefined # or comma-delimited string
7884
# used for theme customization, will inject root styles as `--slidev-theme-x` for attribute `x`
7985
themeConfig:
8086
primary: '#5d8392'
@@ -161,6 +167,9 @@ title: undefined # or string
161167
# defines the transition between the slide and the next one
162168
# Learn more: https://sli.dev/guide/animations.html#slide-transitions
163169
transition: undefined # or BuiltinSlideTransition | string | TransitionGroupProps | null
170+
# defines the default animation presets for click animations in this slide
171+
# Learn more: https://sli.dev/guide/animations.html#click-animation-presets
172+
clickAnimation: undefined # or comma-delimited string
164173
# custom zoom scale
165174
# useful for slides with a lot of content
166175
zoom: 1

docs/guide/animations.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,44 @@ clicks: 10
228228
---
229229
```
230230

231+
### Click Animation Presets {#click-animation-presets}
232+
233+
You can define default click animation presets in headmatter/frontmatter:
234+
235+
```yaml
236+
---
237+
clickAnimation: up
238+
---
239+
```
240+
241+
Or specify them per element with directive modifiers:
242+
243+
```md
244+
<div v-click>Uses default animation preset defined in frontmatter</div>
245+
<div v-click.scale>Scales up when showing and scales down when hiding</div>
246+
<div v-click.fade.right>Composes multiple animations: fade and right</div>
247+
<div v-click.none>No animation for this element</div>
248+
```
249+
250+
There are some built-in presets available for you to use:
251+
252+
- `fade`: Fade in from opacity 0.5 to 1
253+
- `fade-in`: Fade in from opacity 0 to 1
254+
- `up`: Translate 20px up
255+
- `down`: Translate 20px down
256+
- `left`: Translate 20px left
257+
- `right`: Translate 20px right
258+
- `scale`: Scale to 0.9
259+
- `none`: Disables animation for this element
260+
261+
And you can also define your own presets with custom CSS rules for `.slidev-vclick-anim-{presetName}`:
262+
263+
```css
264+
.slidev-vclick-anim-pop.slidev-vclick-hidden {
265+
transform: scale(0.96) translateY(8px);
266+
}
267+
```
268+
231269
### Element Transitions {#element-transitions}
232270

233271
When you apply the `v-click` directive to your elements, it will attach the class name `slidev-vclick-target` to it. When the elements are hidden, the class name `slidev-vclick-hidden` will also be attached. For example:

packages/client/builtin/VClick.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,17 @@ export default defineComponent({
1919
type: Boolean,
2020
default: false,
2121
},
22+
/**
23+
* @deprecated use `animation` instead
24+
*/
2225
fade: {
2326
type: Boolean,
2427
default: false,
2528
},
29+
animation: {
30+
type: String,
31+
default: undefined,
32+
},
2633
wrapText: {
2734
type: Function as PropType<(text: VNode) => VNode>,
2835
default: (text: VNode) => h('span', text),
@@ -36,6 +43,7 @@ export default defineComponent({
3643
at: this.at,
3744
hide: this.hide,
3845
fade: this.fade,
46+
animation: this.animation,
3947
handleSpecialElements: false,
4048
},
4149
{

packages/client/builtin/VClicks.ts

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,17 @@ export default defineComponent({
3030
type: Boolean,
3131
default: false,
3232
},
33+
/**
34+
* @deprecated use `animation` instead
35+
*/
3336
fade: {
3437
type: Boolean,
3538
default: false,
3639
},
40+
animation: {
41+
type: [String, Array<string>],
42+
default: undefined,
43+
},
3744
handleSpecialElements: {
3845
type: Boolean,
3946
default: true,
@@ -53,14 +60,26 @@ export default defineComponent({
5360
const click = resolveDirective('click')!
5461

5562
const applyDirective = (node: VNode, value: number | string) => {
63+
const modifiers: Record<string, boolean> = {
64+
hide: this.hide,
65+
}
66+
if (typeof this.animation === 'string') {
67+
this.animation.split(/[\s,]+/).forEach((a) => {
68+
if (a)
69+
modifiers[a] = true
70+
})
71+
}
72+
else if (Array.isArray(this.animation)) {
73+
this.animation.forEach(a => modifiers[a] = true)
74+
}
75+
if (this.fade)
76+
modifiers.fade = true
77+
5678
return withDirectives(node, [[
5779
click,
5880
value,
5981
'',
60-
{
61-
hide: this.hide,
62-
fade: this.fade,
63-
},
82+
modifiers,
6483
]])
6584
}
6685

packages/client/constants.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ export const injectionSlideZoom = '$$slidev-slide-zoom' as unknown as InjectionK
1616

1717
export const CLASS_VCLICK_TARGET = 'slidev-vclick-target'
1818
export const CLASS_VCLICK_HIDDEN = 'slidev-vclick-hidden'
19-
export const CLASS_VCLICK_FADE = 'slidev-vclick-fade'
2019
export const CLASS_VCLICK_GONE = 'slidev-vclick-gone'
2120
export const CLASS_VCLICK_HIDDEN_EXP = 'slidev-vclick-hidden-explicitly'
2221
export const CLASS_VCLICK_CURRENT = 'slidev-vclick-current'
2322
export const CLASS_VCLICK_PRIOR = 'slidev-vclick-prior'
2423
export const CLASS_VCLICK_DISPLAY_NONE = 'slidev-vclick-display-none'
24+
export const CLASS_VCLICK_ANIMATION_PREFIX = 'slidev-vclick-anim-'
2525

2626
export const CLICKS_MAX = 999999
2727

@@ -46,6 +46,7 @@ export const FRONTMATTER_FIELDS = [
4646
'zoom',
4747
'dragPos',
4848
'lang',
49+
'clickAnimation',
4950
]
5051

5152
export const HEADMATTER_FIELDS = [

0 commit comments

Comments
 (0)