@slidev/client 0.47.5 → 0.48.0-beta.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.
@@ -12,18 +12,23 @@ Learn more: https://sli.dev/guide/syntax.html#line-highlighting
12
12
  -->
13
13
 
14
14
  <script setup lang="ts">
15
- import { range, remove } from '@antfu/utils'
16
15
  import { parseRangeString } from '@slidev/parser/core'
17
16
  import { useClipboard } from '@vueuse/core'
18
- import { computed, getCurrentInstance, inject, onMounted, onUnmounted, ref, watchEffect } from 'vue'
17
+ import { computed, inject, onMounted, onUnmounted, ref, watchEffect } from 'vue'
18
+ import type { PropType } from 'vue'
19
19
  import { configs } from '../env'
20
- import { CLASS_VCLICK_TARGET, injectionClicks, injectionClicksDisabled, injectionClicksElements } from '../constants'
21
20
  import { makeId } from '../logic/utils'
21
+ import { CLASS_VCLICK_HIDDEN, CLASS_VCLICK_TARGET, injectionClicksContext } from '../constants'
22
22
 
23
23
  const props = defineProps({
24
24
  ranges: {
25
+ type: Array as PropType<string[]>,
25
26
  default: () => [],
26
27
  },
28
+ finally: {
29
+ type: [String, Number],
30
+ default: 'last',
31
+ },
27
32
  startLine: {
28
33
  type: Number,
29
34
  default: 1,
@@ -33,8 +38,8 @@ const props = defineProps({
33
38
  default: configs.lineNumbers,
34
39
  },
35
40
  at: {
36
- type: Number,
37
- default: undefined,
41
+ type: [String, Number],
42
+ default: '+1',
38
43
  },
39
44
  maxHeight: {
40
45
  type: String,
@@ -42,39 +47,47 @@ const props = defineProps({
42
47
  },
43
48
  })
44
49
 
45
- const clicks = inject(injectionClicks)
46
- const elements = inject(injectionClicksElements)
47
- const disabled = inject(injectionClicksDisabled)
48
-
50
+ const clicks = inject(injectionClicksContext)?.value
49
51
  const el = ref<HTMLDivElement>()
50
- const vm = getCurrentInstance()
52
+ const id = makeId()
53
+
54
+ onUnmounted(() => {
55
+ clicks!.unregister(id)
56
+ })
51
57
 
52
58
  onMounted(() => {
53
- const prev = props.at == null ? elements?.value.length : props.at
59
+ if (!clicks || clicks.disabled)
60
+ return
61
+
62
+ const { start, end, delta } = clicks.resolve(props.at, props.ranges.length - 1)
63
+ clicks.register(id, { max: end, delta })
64
+
54
65
  const index = computed(() => {
55
- if (disabled?.value)
66
+ if (clicks.disabled)
56
67
  return props.ranges.length - 1
57
- return Math.min(Math.max(0, (clicks?.value || 0) - (prev || 0)), props.ranges.length - 1)
68
+ return Math.max(0, clicks.current - start + 1)
69
+ })
70
+
71
+ const finallyRange = computed(() => {
72
+ return props.finally === 'last' ? props.ranges.at(-1) : props.finally.toString()
58
73
  })
59
- const rangeStr = computed(() => props.ranges[index.value] || '')
60
- if (props.ranges.length >= 2 && !disabled?.value) {
61
- const id = makeId()
62
- const ids = range(props.ranges.length - 1).map(i => id + i)
63
- if (elements?.value) {
64
- elements.value.push(...ids)
65
- onUnmounted(() => ids.forEach(i => remove(elements.value, i)), vm)
66
- }
67
- }
68
74
 
69
75
  watchEffect(() => {
70
76
  if (!el.value)
71
77
  return
78
+
79
+ let rangeStr = props.ranges[index.value] ?? finallyRange.value
80
+ const hide = rangeStr === 'hide'
81
+ el.value.classList.toggle(CLASS_VCLICK_HIDDEN, hide)
82
+ if (hide)
83
+ rangeStr = props.ranges[index.value + 1] ?? finallyRange.value
84
+
72
85
  const isDuoTone = el.value.querySelector('.shiki-dark')
73
86
  const targets = isDuoTone ? Array.from(el.value.querySelectorAll('.shiki')) : [el.value]
74
87
  const startLine = props.startLine
75
88
  for (const target of targets) {
76
89
  const lines = Array.from(target.querySelectorAll('code > .line'))
77
- const highlights: number[] = parseRangeString(lines.length + startLine - 1, rangeStr.value)
90
+ const highlights: number[] = parseRangeString(lines.length + startLine - 1, rangeStr)
78
91
  lines.forEach((line, idx) => {
79
92
  const highlighted = highlights.includes(idx + startLine)
80
93
  line.classList.toggle(CLASS_VCLICK_TARGET, true)
@@ -107,11 +120,9 @@ function copyCode() {
107
120
 
108
121
  <template>
109
122
  <div
110
- ref="el" class="slidev-code-wrapper relative group"
111
- :class="{
123
+ ref="el" class="slidev-code-wrapper relative group" :class="{
112
124
  'slidev-code-line-numbers': props.lines,
113
- }"
114
- :style="{
125
+ }" :style="{
115
126
  'max-height': props.maxHeight,
116
127
  'overflow-y': props.maxHeight ? 'scroll' : undefined,
117
128
  '--start': props.startLine,
@@ -20,53 +20,66 @@ Learn more: https://sli.dev/guide/syntax.html#latex-line-highlighting
20
20
  -->
21
21
 
22
22
  <script setup lang="ts">
23
- import { range, remove } from '@antfu/utils'
24
- import { computed, getCurrentInstance, inject, onMounted, onUnmounted, ref, watchEffect } from 'vue'
23
+ import { computed, inject, onMounted, onUnmounted, ref, watchEffect } from 'vue'
24
+ import type { PropType } from 'vue'
25
25
  import { parseRangeString } from '@slidev/parser'
26
- import { CLASS_VCLICK_TARGET, injectionClicks, injectionClicksDisabled, injectionClicksElements } from '../constants'
26
+ import { CLASS_VCLICK_HIDDEN, CLASS_VCLICK_TARGET, injectionClicksContext } from '../constants'
27
27
  import { makeId } from '../logic/utils'
28
28
 
29
29
  const props = defineProps({
30
30
  ranges: {
31
+ type: Array as PropType<string[]>,
31
32
  default: () => [],
32
33
  },
34
+ finally: {
35
+ type: [String, Number],
36
+ default: 'last',
37
+ },
33
38
  startLine: {
34
39
  type: Number,
35
40
  default: 1,
36
41
  },
37
42
  at: {
38
- type: Number,
39
- default: undefined,
43
+ type: [String, Number],
44
+ default: '+1',
40
45
  },
41
46
  })
42
47
 
43
- const clicks = inject(injectionClicks)
44
- const elements = inject(injectionClicksElements)
45
- const disabled = inject(injectionClicksDisabled)
46
-
48
+ const clicks = inject(injectionClicksContext)?.value
47
49
  const el = ref<HTMLDivElement>()
48
- const vm = getCurrentInstance()
50
+ const id = makeId()
51
+
52
+ onUnmounted(() => {
53
+ clicks!.unregister(id)
54
+ })
49
55
 
50
56
  onMounted(() => {
51
- const prev = props.at == null ? elements?.value.length : props.at
57
+ if (!clicks || clicks.disabled)
58
+ return
59
+
60
+ const { start, end, delta } = clicks.resolve(props.at, props.ranges.length - 1)
61
+ clicks.register(id, { max: end, delta })
62
+
52
63
  const index = computed(() => {
53
- if (disabled?.value)
64
+ if (clicks.disabled)
54
65
  return props.ranges.length - 1
55
- return Math.min(Math.max(0, (clicks?.value || 0) - (prev || 0)), props.ranges.length - 1)
66
+ return Math.max(0, clicks.current - start + 1)
67
+ })
68
+
69
+ const finallyRange = computed(() => {
70
+ return props.finally === 'last' ? props.ranges.at(-1) : props.finally.toString()
56
71
  })
57
- const rangeStr = computed(() => props.ranges[index.value] || '')
58
- if (props.ranges.length >= 2 && !disabled?.value) {
59
- const id = makeId()
60
- const ids = range(props.ranges.length - 1).map(i => id + i)
61
- if (elements?.value) {
62
- elements.value.push(...ids)
63
- onUnmounted(() => ids.forEach(i => remove(elements.value, i)), vm)
64
- }
65
- }
66
72
 
67
73
  watchEffect(() => {
68
74
  if (!el.value)
69
75
  return
76
+
77
+ let rangeStr = props.ranges[index.value] ?? finallyRange.value
78
+ const hide = rangeStr === 'hide'
79
+ el.value.classList.toggle(CLASS_VCLICK_HIDDEN, hide)
80
+ if (hide)
81
+ rangeStr = props.ranges[index.value + 1] ?? finallyRange.value
82
+
70
83
  // KaTeX equations have col-align-XXX as parent
71
84
  const equationParents = el.value.querySelectorAll('.mtable > [class*=col-align]')
72
85
  if (!equationParents)
@@ -89,7 +102,7 @@ onMounted(() => {
89
102
  }
90
103
 
91
104
  const startLine = props.startLine
92
- const highlights: number[] = parseRangeString(lines.length + startLine - 1, rangeStr.value)
105
+ const highlights: number[] = parseRangeString(lines.length + startLine - 1, rangeStr)
93
106
  lines.forEach((line, idx) => {
94
107
  const highlighted = highlights.includes(idx + startLine)
95
108
  line.forEach((node) => {
@@ -103,9 +116,7 @@ onMounted(() => {
103
116
  </script>
104
117
 
105
118
  <template>
106
- <div
107
- ref="el" class="slidev-katex-wrapper"
108
- >
119
+ <div ref="el" class="slidev-katex-wrapper">
109
120
  <slot />
110
121
  </div>
111
122
  </template>
@@ -26,6 +26,7 @@ const props = defineProps<{
26
26
 
27
27
  const vm = getCurrentInstance()
28
28
  const el = ref<ShadowRoot>()
29
+ const error = ref<string | null>(null)
29
30
  const html = ref('')
30
31
 
31
32
  watchEffect(async (onCleanup) => {
@@ -33,15 +34,21 @@ watchEffect(async (onCleanup) => {
33
34
  onCleanup(() => {
34
35
  disposed = true
35
36
  })
36
- const svg = await renderMermaid(
37
- props.code || '',
38
- {
39
- theme: props.theme || (isDark.value ? 'dark' : undefined),
40
- ...vm!.attrs,
41
- },
42
- )
43
- if (!disposed)
44
- html.value = svg
37
+ error.value = null
38
+ try {
39
+ const svg = await renderMermaid(
40
+ props.code || '',
41
+ {
42
+ theme: props.theme || (isDark.value ? 'dark' : undefined),
43
+ ...vm!.attrs,
44
+ },
45
+ )
46
+ if (!disposed)
47
+ html.value = svg
48
+ }
49
+ catch (e) {
50
+ error.value = `${e}`
51
+ }
45
52
  })
46
53
 
47
54
  const actualHeight = ref<number>()
@@ -69,5 +76,6 @@ watchEffect(() => {
69
76
  </script>
70
77
 
71
78
  <template>
72
- <ShadowRoot class="mermaid" :inner-html="html" @shadow="el = $event" />
79
+ <pre v-if="error" border="1 red rounded" class="pa-3">{{ error }}</pre>
80
+ <ShadowRoot v-else class="mermaid" :inner-html="html" @shadow="el = $event" />
73
81
  </template>
@@ -1,7 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { computed, inject, onMounted, onUnmounted, ref, watch } from 'vue'
3
-
4
- import { injectionClicks, injectionClicksDisabled, injectionClicksElements, injectionRenderContext, injectionRoute, injectionSlidevContext } from '../constants'
3
+ import { injectionClicksContext, injectionRenderContext, injectionRoute, injectionSlidevContext } from '../constants'
5
4
 
6
5
  const props = defineProps<{
7
6
  autoPlay?: boolean | 'once' | 'resume' | 'resumeOnce'
@@ -12,9 +11,7 @@ const props = defineProps<{
12
11
  const $slidev = inject(injectionSlidevContext)
13
12
  const route = inject(injectionRoute)
14
13
  const currentContext = inject(injectionRenderContext)
15
- const clicks = inject(injectionClicks)
16
- const clicksDisabled = inject(injectionClicksDisabled)
17
- const clicksElements = inject(injectionClicksElements)
14
+ const clicks = inject(injectionClicksContext)?.value
18
15
 
19
16
  const video = ref<HTMLMediaElement>()
20
17
  const played = ref(false)
@@ -27,9 +24,9 @@ const matchRoute = computed(() => {
27
24
  })
28
25
 
29
26
  const matchClick = computed(() => {
30
- if (!video.value || currentContext?.value !== 'slide' || clicks?.value === undefined || clicksDisabled?.value)
27
+ if (!video.value || currentContext?.value !== 'slide' || clicks?.disabled || clicks?.current === undefined)
31
28
  return false
32
- return !clicksElements?.value.includes(video.value) || clicksElements?.value[clicks?.value - 1] === video.value
29
+ return clicks.map.get(video.value)?.isShown?.value ?? true
33
30
  })
34
31
 
35
32
  const matchRouteAndClick = computed(() => matchRoute.value && matchClick.value)
package/builtin/VClick.ts CHANGED
@@ -12,7 +12,7 @@ export default defineComponent({
12
12
  props: {
13
13
  at: {
14
14
  type: [Number, String],
15
- default: null,
15
+ default: '+1',
16
16
  },
17
17
  hide: {
18
18
  type: Boolean,
@@ -0,0 +1,38 @@
1
+ <script setup lang="ts">
2
+ import { Fragment, inject, onMounted, watchEffect } from 'vue'
3
+ import { injectionClicksContext } from '../constants'
4
+ import { makeId } from '../logic/utils'
5
+
6
+ const props = defineProps({
7
+ size: {
8
+ type: [String, Number],
9
+ default: 1,
10
+ },
11
+ })
12
+
13
+ const clicksRef = inject(injectionClicksContext)
14
+
15
+ onMounted(() => {
16
+ watchEffect((onCleanup) => {
17
+ const clicks = clicksRef?.value
18
+
19
+ if (!clicks || clicks.disabled)
20
+ return
21
+
22
+ let delta = +props.size
23
+ if (Number.isNaN(delta)) {
24
+ console.warn(`[slidev] Invalid size for VClickGap: ${props.size}`)
25
+ delta = 1
26
+ }
27
+ const max = clicks.currentOffset + delta - 1
28
+
29
+ const id = makeId()
30
+ clicks.register(id, { max, delta })
31
+ onCleanup(() => clicks.unregister(id))
32
+ })
33
+ })
34
+ </script>
35
+
36
+ <template>
37
+ <Fragment />
38
+ </template>
@@ -5,9 +5,10 @@
5
5
  */
6
6
 
7
7
  import { toArray } from '@antfu/utils'
8
- import type { Directive, VNode, VNodeArrayChildren } from 'vue'
9
-
10
- import { Comment, defineComponent, h, isVNode, resolveDirective, withDirectives } from 'vue'
8
+ import type { VNode, VNodeArrayChildren } from 'vue'
9
+ import { Comment, createVNode, defineComponent, h, isVNode, resolveDirective, withDirectives } from 'vue'
10
+ import { normalizeAtProp } from '../logic/utils'
11
+ import VClickGap from './VClickGap.vue'
11
12
 
12
13
  const listTags = ['ul', 'ol']
13
14
 
@@ -18,12 +19,12 @@ export default defineComponent({
18
19
  default: 1,
19
20
  },
20
21
  every: {
21
- type: Number,
22
+ type: [Number, String],
22
23
  default: 1,
23
24
  },
24
25
  at: {
25
26
  type: [Number, String],
26
- default: null,
27
+ default: '+1',
27
28
  },
28
29
  hide: {
29
30
  type: Boolean,
@@ -35,13 +36,15 @@ export default defineComponent({
35
36
  },
36
37
  },
37
38
  render() {
39
+ const every = +this.every
40
+ const [isRelative, at] = normalizeAtProp(this.at)
41
+
38
42
  const click = resolveDirective('click')!
39
- const after = resolveDirective('after')!
40
43
 
41
- const applyDirective = (node: VNode, directive: Directive, delta: number | string) => {
44
+ const applyDirective = (node: VNode, value: number | string) => {
42
45
  return withDirectives(node, [[
43
- directive,
44
- delta,
46
+ click,
47
+ value,
45
48
  '',
46
49
  {
47
50
  hide: this.hide,
@@ -66,76 +69,70 @@ export default defineComponent({
66
69
 
67
70
  defaults = openAllTopLevelSlots(toArray(defaults))
68
71
 
69
- const mapSubList = (children: VNodeArrayChildren, depth = 1): [VNodeArrayChildren, number] => {
70
- let idx = 0
72
+ const mapSubList = (children: VNodeArrayChildren, depth = 1): VNodeArrayChildren => {
71
73
  const vNodes = openAllTopLevelSlots(children).map((i) => {
72
74
  if (!isVNode(i))
73
75
  return i
74
76
  if (listTags.includes(i.type as string) && Array.isArray(i.children)) {
75
77
  // eslint-disable-next-line ts/no-use-before-define
76
- const [vNodes, total] = mapChildren(i.children, depth + 1)
77
- idx += total
78
- return h(i, {}, [vNodes])
78
+ const vNodes = mapChildren(i.children, depth + 1)
79
+ return h(i, {}, vNodes)
79
80
  }
80
81
  return h(i)
81
82
  })
82
- return [vNodes, idx]
83
+ return vNodes
83
84
  }
84
85
 
85
- let globalIdx = 0
86
- const mapChildren = (children: VNodeArrayChildren, depth = 1): [VNodeArrayChildren, number] => {
87
- let idx = 0
86
+ let globalIdx = 1
87
+ let execIdx = 0
88
+ const mapChildren = (children: VNodeArrayChildren, depth = 1): VNodeArrayChildren => {
88
89
  const vNodes = openAllTopLevelSlots(children).map((i) => {
89
90
  if (!isVNode(i) || i.type === Comment)
90
91
  return i
91
- const directive = idx % this.every === 0 ? click : after
92
+
93
+ const thisShowIdx = +at + Math.ceil(globalIdx++ / every) - 1
94
+
92
95
  let vNode
93
- let childCount = 0
94
- if (depth < +this.depth && Array.isArray(i.children)) {
95
- const [vNodes, total] = mapSubList(i.children, depth)
96
- vNode = h(i, {}, [vNodes])
97
- childCount = total
98
- idx += total + 1
99
- }
100
- else {
96
+ if (depth < +this.depth && Array.isArray(i.children))
97
+ vNode = h(i, {}, mapSubList(i.children, depth))
98
+ else
101
99
  vNode = h(i)
102
- idx++
103
- }
104
- const delta = this.at != null
105
- ? Number(this.at) + Math.floor(globalIdx / this.every) + depth
106
- : (depth - 1 - childCount).toString()
107
- globalIdx++
100
+
101
+ const delta = thisShowIdx - execIdx
102
+ execIdx = thisShowIdx
103
+
108
104
  return applyDirective(
109
105
  vNode,
110
- directive,
111
- (typeof delta === 'string' && !delta.startsWith('-')) ? `+${delta}` : delta,
106
+ isRelative
107
+ ? delta >= 0 ? `+${delta}` : `${delta}`
108
+ : thisShowIdx,
112
109
  )
113
110
  })
114
- return [vNodes, idx]
111
+ return vNodes
115
112
  }
116
113
 
114
+ const lastGap = () => createVNode(VClickGap, {
115
+ size: +at + Math.ceil((globalIdx - 1) / every) - 1 - execIdx,
116
+ })
117
+
117
118
  // handle ul, ol list
118
119
  if (defaults.length === 1 && listTags.includes(defaults[0].type as string) && Array.isArray(defaults[0].children))
119
- return h(defaults[0], {}, [mapChildren(defaults[0].children)[0]])
120
+ return h(defaults[0], {}, [mapChildren(defaults[0].children), lastGap()])
120
121
 
121
122
  if (defaults.length === 1 && defaults[0].type as string === 'table') {
122
123
  const tableNode = defaults[0]
123
124
  if (Array.isArray(tableNode.children)) {
124
125
  return h(tableNode, {}, tableNode.children.map((i) => {
125
- if (!isVNode(i)) {
126
+ if (!isVNode(i))
126
127
  return i
127
- }
128
- else {
129
- if (i.type === 'tbody' && Array.isArray(i.children))
130
- return h(i, {}, [mapChildren(i.children)[0]])
131
-
132
- else
133
- return h(i)
134
- }
128
+ else if (i.type === 'tbody' && Array.isArray(i.children))
129
+ return h(i, {}, [mapChildren(i.children), lastGap()])
130
+ else
131
+ return h(i)
135
132
  }))
136
133
  }
137
134
  }
138
135
 
139
- return mapChildren(defaults)[0]
136
+ return [mapChildren(defaults)[0], lastGap()]
140
137
  },
141
138
  })
@@ -0,0 +1,83 @@
1
+ import { sum } from '@antfu/utils'
2
+ import type { ClicksContext } from '@slidev/types'
3
+ import type { Ref } from 'vue'
4
+ import { ref, shallowReactive } from 'vue'
5
+ import type { RouteRecordRaw } from 'vue-router'
6
+ import { currentRoute, isPrintMode, isPrintWithClicks, queryClicks, routeForceRefresh } from '../logic/nav'
7
+ import { normalizeAtProp } from '../logic/utils'
8
+
9
+ function useClicksContextBase(route: RouteRecordRaw | undefined, getCurrent: () => number): ClicksContext {
10
+ const relativeOffsets: ClicksContext['relativeOffsets'] = new Map()
11
+ const map: ClicksContext['map'] = shallowReactive(new Map())
12
+
13
+ return {
14
+ get disabled() {
15
+ return isPrintMode.value && !isPrintWithClicks.value
16
+ },
17
+ get current() {
18
+ return getCurrent()
19
+ },
20
+ relativeOffsets,
21
+ map,
22
+ resolve(at, size = 1) {
23
+ const [isRelative, value] = normalizeAtProp(at)
24
+ if (isRelative) {
25
+ const offset = this.currentOffset
26
+ return {
27
+ start: offset + value,
28
+ end: offset + value + size - 1,
29
+ delta: value + size - 1,
30
+ }
31
+ }
32
+ else {
33
+ return {
34
+ start: value,
35
+ end: value + size - 1,
36
+ delta: 0,
37
+ }
38
+ }
39
+ },
40
+ register(el, resolved) {
41
+ relativeOffsets.set(el, resolved.delta)
42
+ map.set(el, resolved)
43
+ },
44
+ unregister(el) {
45
+ relativeOffsets.delete(el)
46
+ map.delete(el)
47
+ },
48
+ get currentOffset() {
49
+ // eslint-disable-next-line no-unused-expressions
50
+ routeForceRefresh.value
51
+ return sum(...relativeOffsets.values())
52
+ },
53
+ get total() {
54
+ // eslint-disable-next-line no-unused-expressions
55
+ routeForceRefresh.value
56
+ return route?.meta?.clicks
57
+ ?? Math.max(0, ...[...map.values()].map(v => v.max || 0))
58
+ },
59
+ }
60
+ }
61
+
62
+ export function usePrimaryClicks(route: RouteRecordRaw | undefined): ClicksContext {
63
+ if (route?.meta?.__clicksContext)
64
+ return route.meta.__clicksContext
65
+ const thisPath = +(route?.path ?? 99999)
66
+ const context = useClicksContextBase(route, () => {
67
+ const currentPath = +(currentRoute.value?.path ?? 99999)
68
+ if (currentPath === thisPath)
69
+ return queryClicks.value
70
+ else if (currentPath > thisPath)
71
+ return 99999
72
+ else
73
+ return 0
74
+ })
75
+ if (route?.meta)
76
+ route.meta.__clicksContext = context
77
+ return context
78
+ }
79
+
80
+ export function useFixedClicks(route: RouteRecordRaw | undefined, currentInit = 0): [Ref<number>, ClicksContext] {
81
+ const current = ref(currentInit)
82
+ return [current, useClicksContextBase(route, () => current.value)]
83
+ }
@@ -1,22 +1,16 @@
1
- import type { ComputedRef, WritableComputedRef } from 'vue'
1
+ import type { ComputedRef } from 'vue'
2
2
  import { computed } from 'vue'
3
3
  import type { RouteLocationNormalizedLoaded } from 'vue-router'
4
4
  import type { SlidevContext } from '../modules/context'
5
5
  import { configs } from '../env'
6
6
  import { useNav } from './useNav'
7
- import { useNavClicks } from './useNavClicks'
8
7
 
9
8
  export function useContext(
10
9
  route: ComputedRef<RouteLocationNormalizedLoaded>,
11
- clicks: WritableComputedRef<number>,
12
10
  ): SlidevContext {
13
11
  const nav = useNav(route)
14
- const navClicks = useNavClicks(clicks, nav.currentRoute, nav.currentPage)
15
12
  return {
16
- nav: {
17
- ...nav,
18
- ...navClicks,
19
- },
13
+ nav,
20
14
  configs,
21
15
  themeConfigs: computed(() => configs.themeConfig),
22
16
  }
@@ -3,7 +3,7 @@ import { computed } from 'vue'
3
3
  import type { RouteLocationNormalizedLoaded, RouteRecordRaw } from 'vue-router'
4
4
  import type { TocItem } from '@slidev/types'
5
5
  import type { SlidevContextNav } from '../modules/context'
6
- import { addToTree, downloadPDF, filterTree, getPath, getTreeWithActiveStatuses, go, next, nextSlide, openInEditor, prev, prevSlide } from '../logic/nav'
6
+ import { addToTree, clicks, clicksContext, clicksTotal, downloadPDF, filterTree, getPath, getTreeWithActiveStatuses, go, next, nextSlide, openInEditor, prev, prevSlide } from '../logic/nav'
7
7
  import { rawRoutes } from '../routes'
8
8
 
9
9
  export function useNav(route: ComputedRef<RouteRecordRaw | RouteLocationNormalizedLoaded>): SlidevContextNav {
@@ -12,7 +12,7 @@ export function useNav(route: ComputedRef<RouteRecordRaw | RouteLocationNormaliz
12
12
 
13
13
  const currentPage = computed(() => Number.parseInt(path.value.split(/\//g).slice(-1)[0]) || 1)
14
14
  const currentPath = computed(() => getPath(currentPage.value))
15
- const currentRoute = computed(() => rawRoutes.find(i => i.path === `${currentPage.value}`))
15
+ const currentRoute = computed(() => rawRoutes.find(i => i.path === `${currentPage.value}`) ?? rawRoutes.at(-1) ?? rawRoutes[0])
16
16
  const currentSlideId = computed(() => currentRoute.value?.meta?.slide?.id)
17
17
  const currentLayout = computed(() => currentRoute.value?.meta?.layout || (currentPage.value === 1 ? 'cover' : 'default'))
18
18
 
@@ -32,6 +32,9 @@ export function useNav(route: ComputedRef<RouteRecordRaw | RouteLocationNormaliz
32
32
  route,
33
33
  path,
34
34
  total,
35
+ clicksContext,
36
+ clicks,
37
+ clicksTotal,
35
38
  currentPage,
36
39
  currentPath,
37
40
  currentRoute,
package/constants.ts CHANGED
@@ -1,12 +1,9 @@
1
1
  import type { ComputedRef, InjectionKey, Ref, UnwrapNestedRefs } from 'vue'
2
2
  import type { RouteRecordRaw } from 'vue-router'
3
- import type { RenderContext } from '@slidev/types'
3
+ import type { ClicksContext, RenderContext } from '@slidev/types'
4
4
  import type { SlidevContext } from './modules/context'
5
5
 
6
- export const injectionClicks: InjectionKey<Ref<number>> = Symbol('v-click-clicks')
7
- export const injectionClicksElements: InjectionKey<Ref<(Element | string)[]>> = Symbol('v-click-clicks-elements')
8
- export const injectionClicksDisabled: InjectionKey<Ref<boolean>> = Symbol('v-click-clicks-disabled')
9
- export const injectionOrderMap: InjectionKey<Ref<Map<number, HTMLElement[]>>> = Symbol('v-click-clicks-order-map')
6
+ export const injectionClicksContext: InjectionKey<Ref<ClicksContext>> = Symbol('slidev-clicks-context')
10
7
  export const injectionCurrentPage: InjectionKey<Ref<number>> = Symbol('slidev-page')
11
8
  export const injectionSlideScale: InjectionKey<ComputedRef<number>> = Symbol('slidev-slide-scale')
12
9
  export const injectionSlidevContext: InjectionKey<UnwrapNestedRefs<SlidevContext>> = Symbol('slidev-slidev-context')
@@ -182,6 +182,6 @@ throttledWatch(
182
182
 
183
183
  <style lang="postcss">
184
184
  .CodeMirror {
185
- @apply px-3 py-2 h-full overflow-auto bg-transparent font-mono text-sm z-0;
185
+ @apply px-3 py-2 h-full overflow-hidden bg-transparent font-mono text-sm z-0;
186
186
  }
187
187
  </style>