@slidev/client 0.49.16 → 0.49.18

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.
package/builtin/VAfter.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * <v-after/> click animations component
3
3
  *
4
- * Learn more: https://sli.dev/guide/animations.html#click-animations
4
+ * Learn more: https://sli.dev/guide/animations.html#click-animation
5
5
  */
6
6
 
7
7
  import { toArray } from '@antfu/utils'
package/builtin/VClick.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * <v-click/> click animations component
3
3
  *
4
- * Learn more: https://sli.dev/guide/animations.html#click-animations
4
+ * Learn more: https://sli.dev/guide/animations.html#click-animation
5
5
  */
6
6
 
7
7
  import type { PropType, VNode } from 'vue'
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * <v-clicks/> click animations component
3
3
  *
4
- * Learn more: https://sli.dev/guide/animations.html#click-animations
4
+ * Learn more: https://sli.dev/guide/animations.html#click-animation
5
5
  */
6
6
 
7
7
  import { toArray } from '@antfu/utils'
@@ -1,8 +1,7 @@
1
1
  import { clamp, sum } from '@antfu/utils'
2
2
  import type { ClicksContext, NormalizedRangeClickValue, NormalizedSingleClickValue, RawAtValue, RawSingleAtValue, SlideRoute } from '@slidev/types'
3
3
  import type { Ref } from 'vue'
4
- import { computed, ref, shallowReactive } from 'vue'
5
- import { routeForceRefresh } from '../logic/route'
4
+ import { computed, onMounted, onUnmounted, ref, shallowReactive } from 'vue'
6
5
 
7
6
  export function normalizeSingleAtValue(at: RawSingleAtValue): NormalizedSingleClickValue {
8
7
  if (at === false || at === 'false')
@@ -54,17 +53,19 @@ export function createClicksContextBase(
54
53
  get isMounted() {
55
54
  return isMounted.value
56
55
  },
57
- onMounted: () => {
58
- isMounted.value = true
59
- // Convert maxMap to reactive
60
- maxMap = shallowReactive(maxMap)
61
- // Make sure the query is not greater than the total
62
- context.current = current.value
63
- },
64
- onUnmounted: () => {
65
- isMounted.value = false
66
- relativeSizeMap = new Map()
67
- maxMap = new Map()
56
+ setup() {
57
+ onMounted(() => {
58
+ isMounted.value = true
59
+ // Convert maxMap to reactive
60
+ maxMap = shallowReactive(maxMap)
61
+ // Make sure the query is not greater than the total
62
+ context.current = current.value
63
+ })
64
+ onUnmounted(() => {
65
+ isMounted.value = false
66
+ relativeSizeMap = new Map()
67
+ maxMap = new Map()
68
+ })
68
69
  },
69
70
  calculateSince(rawAt, size = 1) {
70
71
  const at = normalizeSingleAtValue(rawAt)
@@ -144,13 +145,9 @@ export function createClicksContextBase(
144
145
  maxMap.delete(el)
145
146
  },
146
147
  get currentOffset() {
147
- // eslint-disable-next-line no-unused-expressions
148
- routeForceRefresh.value
149
148
  return sum(...relativeSizeMap.values())
150
149
  },
151
150
  get total() {
152
- // eslint-disable-next-line no-unused-expressions
153
- routeForceRefresh.value
154
151
  return clicksTotalOverrides
155
152
  ?? (isMounted.value
156
153
  ? Math.max(0, ...maxMap.values())
@@ -113,7 +113,7 @@ export function useDragElementsUpdater(no: number) {
113
113
  }
114
114
  }
115
115
 
116
- export function useDragElement(directive: DirectiveBinding | null, posRaw?: string | number | number[], markdownSource?: DragElementMarkdownSource, isArrow?: boolean) {
116
+ export function useDragElement(directive: DirectiveBinding | null, posRaw?: string | number | number[], markdownSource?: DragElementMarkdownSource, isArrow = false) {
117
117
  function inject<T>(key: InjectionKey<T> | string): T | undefined {
118
118
  return directive
119
119
  ? directiveInject(directive, key)
@@ -275,7 +275,7 @@ const useNavState = createSharedComposable((): SlidevContextNavState => {
275
275
 
276
276
  const currentRoute = computed(() => router.currentRoute.value)
277
277
  const query = computed(() => {
278
- // eslint-disable-next-line no-unused-expressions
278
+ // eslint-disable-next-line ts/no-unused-expressions
279
279
  router.currentRoute.value.query
280
280
  return new URLSearchParams(location.search)
281
281
  })
@@ -17,7 +17,7 @@ export function useSlideInfo(no: number): UseSlideInfo {
17
17
  update: async () => {},
18
18
  }
19
19
  }
20
- const url = `/@slidev/slide/${no}.json`
20
+ const url = `/__slidev/slides/${no}.json`
21
21
  const { data: info, execute } = useFetch(url).json<SlideInfo>().get()
22
22
 
23
23
  execute()
package/env.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { computed, ref } from 'vue'
1
+ import { computed } from 'vue'
2
2
  import { objectMap } from '@antfu/utils'
3
3
  import configs from '#slidev/configs'
4
4
 
@@ -6,8 +6,8 @@ export { configs }
6
6
 
7
7
  export const mode = __DEV__ ? 'dev' : 'build'
8
8
 
9
- export const slideAspect = ref(configs.aspectRatio ?? (16 / 9))
10
- export const slideWidth = ref(configs.canvasWidth ?? 980)
9
+ export const slideAspect = computed(() => configs.aspectRatio)
10
+ export const slideWidth = computed(() => configs.canvasWidth)
11
11
 
12
12
  // To honor the aspect ratio more as possible, we need to approximate the height to the next integer.
13
13
  // Doing this, we will prevent on print, to create an additional empty white page after each page.
@@ -39,7 +39,6 @@ provideLocal(injectionSlidevContext, reactive({
39
39
  <GlobalBottom />
40
40
 
41
41
  <SlideWrapper
42
- :is="route.component!"
43
42
  :clicks-context="nav.clicksContext.value"
44
43
  :class="getSlideClass(route)"
45
44
  :route="route"
@@ -98,11 +98,6 @@ watchEffect(() => {
98
98
  // Watch rowCount, make sure up and down shortcut work correctly.
99
99
  overviewRowCount.value = rowCount.value
100
100
  })
101
-
102
- const activeSlidesLoaded = ref(false)
103
- setTimeout(() => {
104
- activeSlidesLoaded.value = true
105
- }, 3000)
106
101
  </script>
107
102
 
108
103
  <template>
@@ -113,8 +108,7 @@ setTimeout(() => {
113
108
  leave-to-class="opacity-0 scale-102 !backdrop-blur-0px"
114
109
  >
115
110
  <div
116
- v-if="showOverview || activeSlidesLoaded"
117
- v-show="showOverview"
111
+ v-if="showOverview"
118
112
  class="fixed left-0 right-0 top-0 h-[calc(var(--vh,1vh)*100)] z-20 bg-main !bg-opacity-75 p-16 py-20 overflow-y-auto backdrop-blur-5px"
119
113
  @click="close"
120
114
  >
@@ -1,12 +1,11 @@
1
1
  <script setup lang="ts">
2
- import { computed, defineAsyncComponent, defineComponent, h, ref, toRef } from 'vue'
2
+ import { computed, ref, toRef } from 'vue'
3
3
  import type { CSSProperties, PropType } from 'vue'
4
4
  import { provideLocal } from '@vueuse/core'
5
5
  import type { ClicksContext, RenderContext, SlideRoute } from '@slidev/types'
6
6
  import { injectionClicksContext, injectionCurrentPage, injectionFrontmatter, injectionRenderContext, injectionRoute, injectionSlideZoom } from '../constants'
7
7
  import { getSlideClass } from '../utils'
8
8
  import { configs } from '../env'
9
- import SlideLoading from './SlideLoading.vue'
10
9
  import { SlideBottom, SlideTop } from '#slidev/global-layers'
11
10
 
12
11
  const props = defineProps({
@@ -47,19 +46,6 @@ const style = computed<CSSProperties>(() => ({
47
46
  ...zoomStyle.value,
48
47
  'user-select': configs.selectable ? undefined : 'none',
49
48
  }))
50
-
51
- const SlideComponent = computed(() => props.route && defineAsyncComponent({
52
- loader: async () => {
53
- const component = await props.route.component()
54
- return defineComponent({
55
- mounted: props.clicksContext?.onMounted,
56
- unmounted: props.clicksContext?.onUnmounted,
57
- render: () => h(component.default),
58
- })
59
- },
60
- delay: 300,
61
- loadingComponent: SlideLoading,
62
- }))
63
49
  </script>
64
50
 
65
51
  <template>
@@ -69,7 +55,7 @@ const SlideComponent = computed(() => props.route && defineAsyncComponent({
69
55
  :style="style"
70
56
  >
71
57
  <SlideBottom />
72
- <SlideComponent />
58
+ <component :is="props.route.component" />
73
59
  <SlideTop />
74
60
  </div>
75
61
  </template>
@@ -1,6 +1,7 @@
1
1
  <script setup lang="ts">
2
- import { TransitionGroup, computed, shallowRef, watch } from 'vue'
2
+ import { TransitionGroup, computed, shallowRef, watchEffect } from 'vue'
3
3
  import { recomputeAllPoppers } from 'floating-vue'
4
+ import type { SlideRoute } from '@slidev/types'
4
5
  import { useNav } from '../composables/useNav'
5
6
  import { useViewTransition } from '../composables/useViewTransition'
6
7
  import { skipTransition } from '../logic/hmr'
@@ -19,6 +20,7 @@ const {
19
20
  currentSlideRoute,
20
21
  currentTransition,
21
22
  getPrimaryClicks,
23
+ prevRoute,
22
24
  nextRoute,
23
25
  slides,
24
26
  isPrintMode,
@@ -26,13 +28,26 @@ const {
26
28
  clicksDirection,
27
29
  } = useNav()
28
30
 
29
- // preload next route
30
- watch(currentSlideRoute, () => {
31
- if (currentSlideRoute.value?.meta && currentSlideRoute.value.meta.preload !== false)
32
- currentSlideRoute.value.meta.__preloaded = true
33
- if (nextRoute.value?.meta && nextRoute.value.meta.preload !== false)
34
- nextRoute.value.meta.__preloaded = true
35
- }, { immediate: true })
31
+ function preloadRoute(route: SlideRoute) {
32
+ if (route.meta.preload !== false) {
33
+ route.meta.__preloaded = true
34
+ route.load()
35
+ }
36
+ }
37
+ // preload current, prev and next slides
38
+ watchEffect(() => {
39
+ preloadRoute(currentSlideRoute.value)
40
+ preloadRoute(prevRoute.value)
41
+ preloadRoute(nextRoute.value)
42
+ })
43
+ // preload all slides after 3s
44
+ watchEffect((onCleanup) => {
45
+ const routes = slides.value
46
+ const timeout = setTimeout(() => {
47
+ routes.forEach(preloadRoute)
48
+ }, 3000)
49
+ onCleanup(() => clearTimeout(timeout))
50
+ })
36
51
 
37
52
  const hasViewTransition = useViewTransition()
38
53
 
@@ -67,14 +82,15 @@ function onAfterLeave() {
67
82
  }"
68
83
  @after-leave="onAfterLeave"
69
84
  >
70
- <SlideWrapper
71
- v-for="route of loadedRoutes"
72
- v-show="route === currentSlideRoute"
73
- :key="route.no"
74
- :clicks-context="isPrintMode && !isPrintWithClicks ? createFixedClicks(route, CLICKS_MAX) : getPrimaryClicks(route)"
75
- :route="route"
76
- :render-context="renderContext"
77
- />
85
+ <template v-for="route of loadedRoutes" :key="route.no">
86
+ <SlideWrapper
87
+ v-if="Math.abs(route.no - currentSlideRoute.no) <= 20"
88
+ v-show="route === currentSlideRoute"
89
+ :clicks-context="isPrintMode && !isPrintWithClicks ? createFixedClicks(route, CLICKS_MAX) : getPrimaryClicks(route)"
90
+ :route="route"
91
+ :render-context="renderContext"
92
+ />
93
+ </template>
78
94
  </component>
79
95
 
80
96
  <DragControl v-if="activeDragElement" :data="activeDragElement" />
package/logic/route.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { WritableComputedRef } from 'vue'
2
- import { computed, nextTick, ref, unref } from 'vue'
2
+ import { computed, nextTick, unref } from 'vue'
3
3
  import { useRouter } from 'vue-router'
4
4
 
5
5
  export function useRouteQuery<T extends string | string[]>(
@@ -35,6 +35,3 @@ export function useRouteQuery<T extends string | string[]>(
35
35
  },
36
36
  })
37
37
  }
38
-
39
- // force update collected elements when the route is fully resolved
40
- export const routeForceRefresh = ref(0)
@@ -19,7 +19,7 @@ export async function renderMermaid(lzEncoded: string, options: any) {
19
19
 
20
20
  mermaid.initialize({
21
21
  startOnLoad: false,
22
- ...clearUndefined(setupMermaid() || {}),
22
+ ...clearUndefined(await setupMermaid() || {}),
23
23
  ...clearUndefined(options),
24
24
  })
25
25
  const code = lz.decompressFromBase64(lzEncoded)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@slidev/client",
3
3
  "type": "module",
4
- "version": "0.49.16",
4
+ "version": "0.49.18",
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.36",
33
33
  "@iconify-json/ph": "^1.1.13",
34
34
  "@iconify-json/svg-spinners": "^1.1.2",
35
- "@shikijs/monaco": "^1.10.0",
36
- "@shikijs/vitepress-twoslash": "^1.10.0",
35
+ "@shikijs/monaco": "^1.10.3",
36
+ "@shikijs/vitepress-twoslash": "^1.10.3",
37
37
  "@slidev/rough-notation": "^0.1.0",
38
38
  "@typescript/ata": "^0.9.6",
39
- "@unhead/vue": "^1.9.14",
40
- "@unocss/reset": "^0.61.2",
39
+ "@unhead/vue": "^1.9.16",
40
+ "@unocss/reset": "^0.61.5",
41
41
  "@vueuse/core": "^10.11.0",
42
42
  "@vueuse/math": "^10.11.0",
43
43
  "@vueuse/motion": "^2.2.3",
@@ -45,23 +45,23 @@
45
45
  "file-saver": "^2.0.5",
46
46
  "floating-vue": "^5.2.2",
47
47
  "fuse.js": "^7.0.0",
48
- "katex": "^0.16.10",
48
+ "katex": "^0.16.11",
49
49
  "lz-string": "^1.5.0",
50
50
  "mermaid": "^10.9.1",
51
51
  "monaco-editor": "^0.50.0",
52
- "prettier": "^3.3.2",
52
+ "prettier": "^3.3.3",
53
53
  "recordrtc": "^5.6.2",
54
- "shiki": "^1.10.0",
55
- "shiki-magic-move": "^0.4.2",
56
- "typescript": "^5.5.2",
57
- "unocss": "^0.61.2",
58
- "vue": "^3.4.31",
54
+ "shiki": "^1.10.3",
55
+ "shiki-magic-move": "^0.4.3",
56
+ "typescript": "^5.5.3",
57
+ "unocss": "^0.61.5",
58
+ "vue": "^3.4.33",
59
59
  "vue-router": "^4.4.0",
60
60
  "yaml": "^2.4.5",
61
- "@slidev/parser": "0.49.16",
62
- "@slidev/types": "0.49.16"
61
+ "@slidev/parser": "0.49.18",
62
+ "@slidev/types": "0.49.18"
63
63
  },
64
64
  "devDependencies": {
65
- "vite": "^5.3.2"
65
+ "vite": "^5.3.4"
66
66
  }
67
67
  }
package/pages/play.vue CHANGED
@@ -37,18 +37,21 @@ registerShortcuts()
37
37
  if (__SLIDEV_FEATURE_WAKE_LOCK__)
38
38
  useWakeLock()
39
39
 
40
- useStyleTag(computed(() => `
41
- vite-error-overlay {
42
- --width: calc(100vw - ${isEditorVertical.value ? 0 : editorWidth.value}px);
43
- --height: calc(100vh - ${isEditorVertical.value ? editorHeight.value : 0}px);
44
- position: fixed;
45
- left: 0;
46
- top: 0;
47
- width: calc(var(--width) / var(--slidev-slide-scale));
48
- height: calc(var(--height) / var(--slidev-slide-scale));
49
- transform-origin: top left;
50
- transform: scale(var(--slidev-slide-scale));
51
- }`))
40
+ if (import.meta.hot) {
41
+ useStyleTag(computed(() => `
42
+ vite-error-overlay {
43
+ --width: calc(100vw - ${isEditorVertical.value ? 0 : editorWidth.value}px);
44
+ --height: calc(100vh - ${isEditorVertical.value ? editorHeight.value : 0}px);
45
+ position: fixed;
46
+ left: 0;
47
+ top: 0;
48
+ width: calc(var(--width) / var(--slidev-slide-scale));
49
+ height: calc(var(--height) / var(--slidev-slide-scale));
50
+ transform-origin: top left;
51
+ transform: scale(var(--slidev-slide-scale));
52
+ }`,
53
+ ))
54
+ }
52
55
 
53
56
  const persistNav = computed(() => isScreenVertical.value || showEditor.value)
54
57
 
@@ -56,7 +56,7 @@ const nextFrame = computed(() => {
56
56
  if (clicksContext.value.current < clicksContext.value.total)
57
57
  return [currentSlideRoute.value!, clicksContext.value.current + 1] as const
58
58
  else if (hasNext.value)
59
- return [nextRoute.value!, 0] as const
59
+ return [nextRoute.value, 0] as const
60
60
  else
61
61
  return null
62
62
  })
@@ -135,6 +135,11 @@ onMounted(() => {
135
135
  render-context="previewNext"
136
136
  />
137
137
  </SlideContainer>
138
+ <div v-else class="h-full flex justify-center items-center">
139
+ <div class="text-gray-500">
140
+ End of the presentation
141
+ </div>
142
+ </div>
138
143
  <div class="absolute left-0 top-0 bg-main border-b border-r border-main px2 py1 op50 text-sm">
139
144
  Next
140
145
  </div>
package/setup/main.ts CHANGED
@@ -1,10 +1,8 @@
1
1
  import type { AppContext } from '@slidev/types'
2
2
  import TwoSlashFloatingVue from '@shikijs/vitepress-twoslash/client'
3
3
  import type { App } from 'vue'
4
- import { nextTick } from 'vue'
5
4
  import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
6
5
  import { createHead } from '@unhead/vue'
7
- import { routeForceRefresh } from '../logic/route'
8
6
  import { createVClickDirectives } from '../modules/v-click'
9
7
  import { createVMarkDirective } from '../modules/v-mark'
10
8
  import { createVDragDirective } from '../modules/v-drag'
@@ -43,13 +41,6 @@ export default async function setupMain(app: App) {
43
41
  router,
44
42
  }
45
43
 
46
- nextTick(() => {
47
- router.afterEach(async () => {
48
- await nextTick()
49
- routeForceRefresh.value += 1
50
- })
51
- })
52
-
53
44
  for (const setup of setups)
54
45
  await setup(context)
55
46
  }
package/setup/mermaid.ts CHANGED
@@ -1,14 +1,14 @@
1
- import type { MermaidOptions } from '@slidev/types'
2
- import { defineMermaidSetup } from '@slidev/types'
1
+ import type { MermaidConfig } from 'mermaid'
2
+ import { createSingletonPromise } from '@antfu/utils'
3
3
  import setups from '#slidev/setups/mermaid'
4
4
 
5
- export default defineMermaidSetup(() => {
6
- const setupReturn: MermaidOptions = {
5
+ export default createSingletonPromise(async () => {
6
+ const setupReturn: MermaidConfig = {
7
7
  theme: 'default',
8
8
  }
9
9
 
10
10
  for (const setup of setups)
11
- Object.assign(setupReturn, setup())
11
+ Object.assign(setupReturn, await setup())
12
12
 
13
13
  return setupReturn
14
14
  })