@slidev/client 0.48.7 → 0.48.8

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.
@@ -1,4 +1,4 @@
1
- import { sum } from '@antfu/utils'
1
+ import { clamp, sum } from '@antfu/utils'
2
2
  import type { ClicksContext, SlideRoute } from '@slidev/types'
3
3
  import type { Ref } from 'vue'
4
4
  import { ref, shallowReactive } from 'vue'
@@ -7,18 +7,21 @@ import { routeForceRefresh } from '../logic/route'
7
7
 
8
8
  export function createClicksContextBase(
9
9
  current: Ref<number>,
10
- clicksOverrides?: number,
10
+ clicksStart = 0,
11
+ clicksTotalOverrides?: number,
11
12
  ): ClicksContext {
12
13
  const relativeOffsets: ClicksContext['relativeOffsets'] = new Map()
13
14
  const map: ClicksContext['map'] = shallowReactive(new Map())
14
15
 
15
16
  return {
16
17
  get current() {
17
- return +current.value
18
+ // Here we haven't know clicksTotal yet.
19
+ return clamp(+current.value, clicksStart, this.total)
18
20
  },
19
21
  set current(value) {
20
- current.value = +value
22
+ current.value = clamp(+value, clicksStart, this.total)
21
23
  },
24
+ clicksStart,
22
25
  relativeOffsets,
23
26
  map,
24
27
  onMounted() { },
@@ -56,7 +59,7 @@ export function createClicksContextBase(
56
59
  get total() {
57
60
  // eslint-disable-next-line no-unused-expressions
58
61
  routeForceRefresh.value
59
- return clicksOverrides ?? Math.max(0, ...[...map.values()].map(v => v.max || 0))
62
+ return clicksTotalOverrides ?? Math.max(0, ...[...map.values()].map(v => v.max || 0))
60
63
  },
61
64
  }
62
65
  }
@@ -65,5 +68,10 @@ export function createFixedClicks(
65
68
  route?: SlideRoute | undefined,
66
69
  currentInit = 0,
67
70
  ): ClicksContext {
68
- return createClicksContextBase(ref(currentInit), route?.meta?.clicks)
71
+ const clicksStart = route?.meta.slide?.frontmatter.clicksStart ?? 0
72
+ return createClicksContextBase(
73
+ ref(Math.max(currentInit, clicksStart)),
74
+ clicksStart,
75
+ route?.meta?.clicks,
76
+ )
69
77
  }
@@ -5,6 +5,7 @@ import { useRouter } from 'vue-router'
5
5
  import type { RouteLocationNormalized, Router } from 'vue-router'
6
6
  import { createSharedComposable } from '@vueuse/core'
7
7
  import { logicOr } from '@vueuse/math'
8
+ import { clamp } from '@antfu/utils'
8
9
  import { getCurrentTransition } from '../logic/transition'
9
10
  import { getSlide, getSlidePath } from '../logic/slides'
10
11
  import { CLICKS_MAX } from '../constants'
@@ -33,6 +34,7 @@ export interface SlidevContextNav {
33
34
 
34
35
  clicksContext: ComputedRef<ClicksContext>
35
36
  clicks: ComputedRef<number>
37
+ clicksStart: ComputedRef<number>
36
38
  clicksTotal: ComputedRef<number>
37
39
 
38
40
  /** The table of content tree */
@@ -99,6 +101,7 @@ export function useNavBase(
99
101
  const currentLayout = computed(() => currentSlideRoute.value.meta?.layout || (currentSlideNo.value === 1 ? 'cover' : 'default'))
100
102
 
101
103
  const clicks = computed(() => clicksContext.value.current)
104
+ const clicksStart = computed(() => clicksContext.value.clicksStart)
102
105
  const clicksTotal = computed(() => clicksContext.value.total)
103
106
  const nextRoute = computed(() => slides.value[Math.min(slides.value.length, currentSlideNo.value + 1) - 1])
104
107
  const prevRoute = computed(() => slides.value[Math.max(1, currentSlideNo.value - 1) - 1])
@@ -140,7 +143,7 @@ export function useNavBase(
140
143
 
141
144
  async function prev() {
142
145
  clicksDirection.value = -1
143
- if (queryClicks.value <= 0)
146
+ if (queryClicks.value <= clicksStart.value)
144
147
  await prevSlide()
145
148
  else
146
149
  queryClicks.value -= 1
@@ -177,6 +180,9 @@ export function useNavBase(
177
180
  skipTransition.value = false
178
181
  const pageChanged = currentSlideNo.value !== page
179
182
  const clicksChanged = clicks !== queryClicks.value
183
+ const meta = getSlide(page)?.meta
184
+ const clicksStart = meta?.slide?.frontmatter.clicksStart ?? 0
185
+ clicks = clamp(clicks, clicksStart, meta?.__clicksContext?.total ?? CLICKS_MAX)
180
186
  if (pageChanged || clicksChanged) {
181
187
  await router?.push({
182
188
  path: getSlidePath(page, isPresenter.value),
@@ -202,6 +208,7 @@ export function useNavBase(
202
208
  prevRoute,
203
209
  clicksContext,
204
210
  clicks,
211
+ clicksStart,
205
212
  clicksTotal,
206
213
  hasNext,
207
214
  hasPrev,
@@ -289,24 +296,25 @@ const useNavState = createSharedComposable((): SlidevContextNavState => {
289
296
  computed({
290
297
  get() {
291
298
  if (currentSlideNo.value === thisNo)
292
- return +(queryClicksRaw.value || 0) || 0
299
+ return Math.max(+(queryClicksRaw.value ?? 0), context.clicksStart)
293
300
  else if (currentSlideNo.value > thisNo)
294
301
  return CLICKS_MAX
295
302
  else
296
- return 0
303
+ return context.clicksStart
297
304
  },
298
305
  set(v) {
299
306
  if (currentSlideNo.value === thisNo)
300
- queryClicksRaw.value = Math.min(v, context.total).toString()
307
+ queryClicksRaw.value = clamp(v, context.clicksStart, context.total).toString()
301
308
  },
302
309
  }),
303
- route?.meta?.clicks,
310
+ route?.meta.slide?.frontmatter.clicksStart ?? 0,
311
+ route?.meta.clicks,
304
312
  )
305
313
 
306
314
  // On slide mounted, make sure the query is not greater than the total
307
315
  context.onMounted = () => {
308
- if (queryClicksRaw.value)
309
- queryClicksRaw.value = Math.min(+queryClicksRaw.value, context.total).toString()
316
+ if (currentSlideNo.value === thisNo)
317
+ queryClicksRaw.value = clamp(+queryClicksRaw.value, context.clicksStart, context.total).toString()
310
318
  }
311
319
 
312
320
  if (route?.meta)
package/constants.ts CHANGED
@@ -31,6 +31,7 @@ export const TRUST_ORIGINS = [
31
31
 
32
32
  export const FRONTMATTER_FIELDS = [
33
33
  'clicks',
34
+ 'clicksStart',
34
35
  'disabled',
35
36
  'hide',
36
37
  'hideInToc',
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { ClicksContext } from '@slidev/types'
3
+ import { clamp, range } from '@antfu/utils'
3
4
  import { computed } from 'vue'
4
5
  import { CLICKS_MAX } from '../constants'
5
6
 
@@ -8,6 +9,8 @@ const props = defineProps<{
8
9
  }>()
9
10
 
10
11
  const total = computed(() => props.clicksContext.total)
12
+ const start = computed(() => clamp(0, props.clicksContext.clicksStart, total.value))
13
+ const length = computed(() => total.value - start.value + 1)
11
14
  const current = computed({
12
15
  get() {
13
16
  return props.clicksContext.current > total.value ? -1 : props.clicksContext.current
@@ -18,7 +21,7 @@ const current = computed({
18
21
  },
19
22
  })
20
23
 
21
- const range = computed(() => Array.from({ length: total.value + 1 }, (_, i) => i))
24
+ const clicksRange = computed(() => range(start.value, total.value + 1))
22
25
 
23
26
  function onMousedown() {
24
27
  if (current.value < 0 || current.value > total.value)
@@ -29,8 +32,8 @@ function onMousedown() {
29
32
  <template>
30
33
  <div
31
34
  class="flex gap-1 items-center select-none"
32
- :title="`Clicks in this slide: ${total}`"
33
- :class="total ? '' : 'op50'"
35
+ :title="`Clicks in this slide: ${length}`"
36
+ :class="length ? '' : 'op50'"
34
37
  >
35
38
  <div class="flex gap-0.5 items-center min-w-16 font-mono mr1">
36
39
  <carbon:cursor-1 text-sm op50 />
@@ -46,13 +49,13 @@ function onMousedown() {
46
49
  @dblclick="current = clicksContext.total"
47
50
  >
48
51
  <div
49
- v-for="i of range" :key="i"
52
+ v-for="i of clicksRange" :key="i"
50
53
  border="y main" of-hidden relative
51
54
  :class="[
52
55
  i === 0 ? 'rounded-l border-l' : '',
53
56
  i === total ? 'rounded-r border-r' : '',
54
57
  ]"
55
- :style="{ width: total > 0 ? `${1 / total * 100}%` : '100%' }"
58
+ :style="{ width: length > 0 ? `${1 / length * 100}%` : '100%' }"
56
59
  >
57
60
  <div absolute inset-0 :class="i <= current ? 'bg-primary op15' : ''" />
58
61
  <div
@@ -69,8 +72,8 @@ function onMousedown() {
69
72
  <input
70
73
  v-model="current"
71
74
  class="range" absolute inset-0
72
- type="range" :min="0" :max="total" :step="1" z-10 op0
73
- :style="{ '--thumb-width': `${1 / (total + 1) * 100}%` }"
75
+ type="range" :min="start" :max="total" :step="1" z-10 op0
76
+ :style="{ '--thumb-width': `${1 / (length + 1) * 100}%` }"
74
77
  @mousedown="onMousedown"
75
78
  @focus="event => (event.currentTarget as HTMLElement)?.blur()"
76
79
  >
@@ -3,7 +3,7 @@ import { computed, ref, watch } from 'vue'
3
3
  import Fuse from 'fuse.js'
4
4
  import { activeElement, showGotoDialog } from '../state'
5
5
  import { useNav } from '../composables/useNav'
6
- import Titles from '#slidev/title-renderer'
6
+ import TitleRenderer from '#slidev/title-renderer'
7
7
 
8
8
  const container = ref<HTMLDivElement>()
9
9
  const input = ref<HTMLInputElement>()
@@ -161,7 +161,7 @@ watch(activeElement, () => {
161
161
  <div w-4 text-right op50 text-sm>
162
162
  {{ item.no }}
163
163
  </div>
164
- <Titles :no="item.no" />
164
+ <TitleRenderer :no="item.no" />
165
165
  </li>
166
166
  </ul>
167
167
  </div>
@@ -8,8 +8,12 @@ import { sharedState } from '../state/shared'
8
8
  class="absolute top-0 left-0 right-0 bottom-0 pointer-events-none text-xl"
9
9
  >
10
10
  <ph-cursor-fill
11
- class="absolute"
12
- :style="{ left: `${sharedState.cursor.x}%`, top: `${sharedState.cursor.y}%` }"
11
+ class="absolute stroke-white dark:stroke-black"
12
+ :style="{
13
+ left: `${sharedState.cursor.x}%`,
14
+ top: `${sharedState.cursor.y}%`,
15
+ strokeWidth: 16,
16
+ }"
13
17
  />
14
18
  </div>
15
19
  </template>
@@ -16,10 +16,14 @@ const clicks0 = createFixedClicks(route, isPrintWithClicks.value ? 0 : CLICKS_MA
16
16
  :nav="useFixedNav(route, clicks0)"
17
17
  />
18
18
  <template v-if="isPrintWithClicks">
19
+ <!--
20
+ clicks0.total can be any number >=0 when rendering.
21
+ So total-clicksStart can be negative in intermediate states.
22
+ -->
19
23
  <PrintSlideClick
20
- v-for="i of clicks0.total"
24
+ v-for="i in Math.max(0, clicks0.total - clicks0.clicksStart)"
21
25
  :key="i"
22
- :nav="useFixedNav(route, createFixedClicks(route, i))"
26
+ :nav="useFixedNav(route, createFixedClicks(route, i + clicks0.clicksStart))"
23
27
  />
24
28
  </template>
25
29
  </template>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@slidev/client",
3
3
  "type": "module",
4
- "version": "0.48.7",
4
+ "version": "0.48.8",
5
5
  "description": "Presentation slides for developers",
6
6
  "author": "antfu <anthonyfu117@hotmail.com>",
7
7
  "license": "MIT",
@@ -32,12 +32,12 @@
32
32
  "@iconify-json/carbon": "^1.1.31",
33
33
  "@iconify-json/ph": "^1.1.11",
34
34
  "@iconify-json/svg-spinners": "^1.1.2",
35
- "@shikijs/monaco": "^1.1.7",
36
- "@shikijs/vitepress-twoslash": "^1.1.7",
35
+ "@shikijs/monaco": "^1.2.1",
36
+ "@shikijs/vitepress-twoslash": "^1.2.1",
37
37
  "@slidev/rough-notation": "^0.1.0",
38
38
  "@typescript/ata": "^0.9.4",
39
- "@unhead/vue": "^1.8.18",
40
- "@unocss/reset": "^0.58.5",
39
+ "@unhead/vue": "^1.9.3",
40
+ "@unocss/reset": "^0.58.8",
41
41
  "@vueuse/core": "^10.9.0",
42
42
  "@vueuse/math": "^10.9.0",
43
43
  "@vueuse/motion": "^2.1.0",
@@ -47,23 +47,23 @@
47
47
  "floating-vue": "^5.2.2",
48
48
  "fuse.js": "^7.0.0",
49
49
  "js-yaml": "^4.1.0",
50
- "katex": "^0.16.9",
50
+ "katex": "^0.16.10",
51
51
  "lz-string": "^1.5.0",
52
52
  "mermaid": "^10.9.0",
53
53
  "monaco-editor": "^0.47.0",
54
54
  "prettier": "^3.2.5",
55
55
  "recordrtc": "^5.6.2",
56
- "shiki": "^1.1.7",
56
+ "shiki": "^1.2.1",
57
57
  "shiki-magic-move": "^0.3.4",
58
- "typescript": "^5.4.2",
59
- "unocss": "^0.58.5",
58
+ "typescript": "^5.4.3",
59
+ "unocss": "^0.58.8",
60
60
  "vue": "^3.4.21",
61
61
  "vue-demi": "^0.14.7",
62
62
  "vue-router": "^4.3.0",
63
- "@slidev/types": "0.48.7",
64
- "@slidev/parser": "0.48.7"
63
+ "@slidev/parser": "0.48.8",
64
+ "@slidev/types": "0.48.8"
65
65
  },
66
66
  "devDependencies": {
67
- "vite": "^5.1.6"
67
+ "vite": "^5.2.7"
68
68
  }
69
69
  }
package/pages/print.vue CHANGED
@@ -28,8 +28,8 @@ onMounted(() => {
28
28
  :style="{ background: 'var(--slidev-slide-container-background, black)' }"
29
29
  :width="windowSize.width.value"
30
30
  />
31
+ <div id="twoslash-container" />
31
32
  </div>
32
- <div id="twoslash-container" />
33
33
  </template>
34
34
 
35
35
  <style lang="postcss">
@@ -144,9 +144,13 @@ export async function runJavaScript(code: string): Promise<CodeRunnerOutputs> {
144
144
  return textRep
145
145
  }
146
146
 
147
- // The reflect-metadata runtime is available, so allow that to go through
148
147
  function sanitizeJS(code: string) {
149
- return code.replace(`import "reflect-metadata"`, '').replace(`require("reflect-metadata")`, '')
148
+ // The reflect-metadata runtime is available, so allow that to go through
149
+ code = code.replace(`import "reflect-metadata"`, '').replace(`require("reflect-metadata")`, '')
150
+ // Transpiled typescript sometimes contains an empty export, remove it.
151
+ code = code.replace('export {};', '')
152
+
153
+ return code
150
154
  }
151
155
 
152
156
  return allLogs