@slidev/client 52.17.2 → 52.18.1

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.
@@ -20,6 +20,7 @@ import lz from 'lz-string'
20
20
  import { computed, defineAsyncComponent, nextTick, onMounted, ref } from 'vue'
21
21
  import { useNav } from '../composables/useNav'
22
22
  import { useSlideContext } from '../context'
23
+ import { configs } from '../env'
23
24
  import { makeId } from '../logic/utils'
24
25
 
25
26
  const props = withDefaults(
@@ -28,6 +29,7 @@ const props = withDefaults(
28
29
  diffLz?: string
29
30
  lang?: string
30
31
  readonly?: boolean
32
+ lines?: boolean
31
33
  lineNumbers?: 'on' | 'off' | 'relative' | 'interval'
32
34
  height?: number | string // Posible values: 'initial', 'auto', '100%', '200px', etc.
33
35
  editorOptions?: monaco.editor.IEditorOptions
@@ -44,7 +46,7 @@ const props = withDefaults(
44
46
  codeLz: '',
45
47
  lang: 'typescript',
46
48
  readonly: false,
47
- lineNumbers: 'off',
49
+ lines: configs.lineNumbers,
48
50
  height: 'initial',
49
51
  ata: true,
50
52
  runnable: false,
@@ -58,6 +60,7 @@ const CodeRunner = defineAsyncComponent(() => import('../internals/CodeRunner.vu
58
60
  const code = ref(lz.decompressFromBase64(props.codeLz).trimEnd())
59
61
  const diff = props.diffLz && ref(lz.decompressFromBase64(props.diffLz).trimEnd())
60
62
  const isWritable = computed(() => props.writable && !props.readonly && __DEV__)
63
+ const lineNumbers = props.lineNumbers ?? (props.lines ? 'on' : 'off')
61
64
 
62
65
  const langMap: Record<string, string> = {
63
66
  ts: 'typescript',
@@ -106,7 +109,7 @@ onMounted(async () => {
106
109
  const commonOptions = {
107
110
  automaticLayout: true,
108
111
  readOnly: props.readonly,
109
- lineNumbers: props.lineNumbers,
112
+ lineNumbers,
110
113
  minimap: { enabled: false },
111
114
  overviewRulerBorder: false,
112
115
  overviewRulerLanes: 0,
@@ -0,0 +1,130 @@
1
+ import type { ClicksContext, SlideRoute } from '@slidev/types'
2
+ import type { SlidevContextNav } from './useNav'
3
+ import { renderToString } from '@vue/server-renderer'
4
+ import { provideLocal } from '@vueuse/core'
5
+ import { describe, expect, it, vi } from 'vitest'
6
+ import { computed, createSSRApp, defineComponent, h, reactive, ref } from 'vue'
7
+ import { injectionSlidevContext } from '../constants'
8
+ import { useNav, useNavBase } from './useNav'
9
+
10
+ vi.mock('#slidev/slides', async () => {
11
+ const { ref } = await import('vue')
12
+ return {
13
+ slides: ref([
14
+ {
15
+ no: 1,
16
+ meta: {
17
+ slide: { frontmatter: { title: 'First' } },
18
+ },
19
+ },
20
+ {
21
+ no: 2,
22
+ meta: {
23
+ slide: { frontmatter: { title: 'Second' } },
24
+ },
25
+ },
26
+ ]),
27
+ }
28
+ })
29
+
30
+ vi.mock('../env', async () => {
31
+ const { ref } = await import('vue')
32
+ return {
33
+ configs: { remote: false },
34
+ slideAspect: ref(16 / 9),
35
+ }
36
+ })
37
+
38
+ vi.mock('../state', async () => {
39
+ const { ref } = await import('vue')
40
+ return { hmrSkipTransition: ref(false) }
41
+ })
42
+
43
+ vi.mock('vue-router', async () => {
44
+ const { reactive, ref } = await import('vue')
45
+ const route = reactive({
46
+ name: 'export',
47
+ params: { no: '1' },
48
+ query: {},
49
+ })
50
+ const router = {
51
+ currentRoute: ref(route),
52
+ push: vi.fn(),
53
+ replace: vi.fn(),
54
+ }
55
+ return {
56
+ useRoute: () => route,
57
+ useRouter: () => router,
58
+ }
59
+ })
60
+
61
+ function route(no: number, frontmatter: Record<string, any>): SlideRoute {
62
+ return {
63
+ no,
64
+ meta: {
65
+ slide: { frontmatter },
66
+ },
67
+ } as unknown as SlideRoute
68
+ }
69
+
70
+ describe('useNavBase', () => {
71
+ it('exposes reactive frontmatter for the current slide', () => {
72
+ const currentRoute = ref(route(1, { title: 'Intro', section: 'start' }))
73
+ const nav = useNavBase(
74
+ computed(() => currentRoute.value),
75
+ computed(() => ({ current: 0, clicksStart: 0, total: 0 }) as ClicksContext),
76
+ ref(0),
77
+ ref(false),
78
+ ref(false),
79
+ )
80
+
81
+ expect(nav.currentFrontmatter.value).toEqual({
82
+ title: 'Intro',
83
+ section: 'start',
84
+ })
85
+
86
+ currentRoute.value = route(2, { title: 'Details', section: 'body' })
87
+
88
+ expect(nav.currentFrontmatter.value).toEqual({
89
+ title: 'Details',
90
+ section: 'body',
91
+ })
92
+ })
93
+
94
+ it('uses the slide-local navigation context while rendering exported slides', async () => {
95
+ vi.stubGlobal('location', { search: '' })
96
+ let observedNav: SlidevContextNav | undefined
97
+ const localNav = {
98
+ currentSlideNo: computed(() => 2),
99
+ currentPage: computed(() => 2),
100
+ currentSlideRoute: computed(() => route(2, { title: 'Second' })),
101
+ tocTree: computed(() => [
102
+ { no: 1, active: false },
103
+ { no: 2, active: true },
104
+ ]),
105
+ } as unknown as SlidevContextNav
106
+
107
+ const Child = defineComponent({
108
+ setup() {
109
+ observedNav = useNav()
110
+ return () => h('span')
111
+ },
112
+ })
113
+ const App = defineComponent({
114
+ setup() {
115
+ provideLocal(injectionSlidevContext, reactive({
116
+ nav: localNav,
117
+ configs: {},
118
+ themeConfigs: {},
119
+ }) as any)
120
+ return () => h(Child)
121
+ },
122
+ })
123
+
124
+ await renderToString(createSSRApp(App))
125
+
126
+ expect(observedNav?.currentSlideNo.value).toBe(2)
127
+ expect(observedNav?.currentSlideRoute.value.meta.slide.frontmatter.title).toBe('Second')
128
+ expect(observedNav?.tocTree.value[1].active).toBe(true)
129
+ })
130
+ })
@@ -3,11 +3,11 @@ import type { ComputedRef, Ref, TransitionGroupProps, WritableComputedRef } from
3
3
  import type { RouteLocationNormalized, Router } from 'vue-router'
4
4
  import { clamp } from '@antfu/utils'
5
5
  import { parseRangeString } from '@slidev/parser/utils'
6
- import { createSharedComposable } from '@vueuse/core'
7
- import { computed, ref, watch } from 'vue'
6
+ import { createSharedComposable, injectLocal } from '@vueuse/core'
7
+ import { computed, ref, toRaw, watch } from 'vue'
8
8
  import { useRoute, useRouter } from 'vue-router'
9
9
  import { slides } from '#slidev/slides'
10
- import { CLICKS_MAX } from '../constants'
10
+ import { CLICKS_MAX, injectionSlidevContext } from '../constants'
11
11
  import { configs } from '../env'
12
12
  import { useRouteQuery } from '../logic/route'
13
13
  import { getSlide, getSlidePath } from '../logic/slides'
@@ -26,6 +26,7 @@ export interface SlidevContextNav {
26
26
  currentSlideRoute: ComputedRef<SlideRoute>
27
27
  currentTransition: ComputedRef<TransitionGroupProps | undefined>
28
28
  currentLayout: ComputedRef<string>
29
+ currentFrontmatter: ComputedRef<Record<string, any>>
29
30
 
30
31
  nextRoute: ComputedRef<SlideRoute>
31
32
  prevRoute: ComputedRef<SlideRoute>
@@ -105,6 +106,7 @@ export function useNavBase(
105
106
  const currentPath = computed(() => getSlidePath(currentSlideRoute.value, isPresenter.value))
106
107
  const currentSlideNo = computed(() => currentSlideRoute.value.no)
107
108
  const currentLayout = computed(() => currentSlideRoute.value.meta?.layout || (currentSlideNo.value === 1 ? 'cover' : 'default'))
109
+ const currentFrontmatter = computed(() => currentSlideRoute.value.meta.slide.frontmatter)
108
110
 
109
111
  const clicks = computed(() => clicksContext.value.current)
110
112
  const clicksStart = computed(() => clicksContext.value.clicksStart)
@@ -223,6 +225,7 @@ export function useNavBase(
223
225
  currentPage: currentSlideNo,
224
226
  currentSlideRoute,
225
227
  currentLayout,
228
+ currentFrontmatter,
226
229
  currentTransition,
227
230
  clicksDirection,
228
231
  nextRoute,
@@ -362,7 +365,7 @@ const useNavState = createSharedComposable((): SlidevContextNavState => {
362
365
  }
363
366
  })
364
367
 
365
- export const useNav = createSharedComposable((): SlidevContextNavFull => {
368
+ const useSharedNav = createSharedComposable((): SlidevContextNavFull => {
366
369
  const state = useNavState()
367
370
  const router = useRouter()
368
371
 
@@ -398,3 +401,16 @@ export const useNav = createSharedComposable((): SlidevContextNavFull => {
398
401
  ...state,
399
402
  }
400
403
  })
404
+
405
+ export function useNav(): SlidevContextNavFull {
406
+ const nav = useSharedNav()
407
+ const context = injectLocal(injectionSlidevContext, undefined)
408
+ if (!context)
409
+ return nav
410
+
411
+ const localNav = toRaw(context).nav as unknown as SlidevContextNav
412
+ return {
413
+ ...nav,
414
+ ...localNav,
415
+ }
416
+ }
@@ -82,5 +82,5 @@ function matchIcon(title: string) {
82
82
  </script>
83
83
 
84
84
  <template>
85
- <div v-if="matchIcon(title)" :class="`${matchIcon(title)} w-3.5 h-3.5 relative`" />
85
+ <div v-if="matchIcon(title)" class="w-3.5 h-3.5 relative" :class="matchIcon(title)" />
86
86
  </template>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@slidev/client",
3
3
  "type": "module",
4
- "version": "52.17.2",
4
+ "version": "52.18.1",
5
5
  "description": "Presentation slides for developers",
6
6
  "author": "Anthony Fu <anthonyfu117@hotmail.com>",
7
7
  "license": "MIT",
@@ -39,36 +39,36 @@
39
39
  "@shikijs/vitepress-twoslash": "^4.3.1",
40
40
  "@slidev/rough-notation": "^0.1.0",
41
41
  "@typescript/ata": "^0.9.8",
42
- "@unhead/vue": "^3.1.7",
42
+ "@unhead/vue": "^3.2.3",
43
43
  "@unocss/extractor-mdc": "^66.7.5",
44
44
  "@unocss/preset-mini": "^66.7.5",
45
45
  "@unocss/reset": "^66.7.5",
46
- "@vueuse/core": "^14.3.0",
47
- "@vueuse/math": "^14.3.0",
46
+ "@vueuse/core": "^14.4.0",
47
+ "@vueuse/math": "^14.4.0",
48
48
  "@vueuse/motion": "^3.0.3",
49
49
  "ansis": "^4.3.1",
50
50
  "drauu": "^1.0.0",
51
51
  "file-saver": "^2.0.5",
52
52
  "fitty": "^2.4.2",
53
53
  "floating-vue": "^5.2.2",
54
- "fuse.js": "^7.4.2",
55
- "katex": "^0.17.0",
54
+ "fuse.js": "^7.5.0",
55
+ "katex": "^0.18.1",
56
56
  "lz-string": "^1.5.0",
57
57
  "mermaid": "^11.16.0",
58
- "monaco-editor": "^0.55.1",
58
+ "monaco-editor": "^0.56.0",
59
59
  "nanotar": "^0.3.0",
60
60
  "pptxgenjs": "^4.0.1",
61
61
  "recordrtc": "^5.6.2",
62
62
  "shiki": "^4.3.1",
63
63
  "typescript": "^6.0.3",
64
64
  "unocss": "^66.7.5",
65
- "vue": "^3.5.39",
66
- "vue-router": "^5.1.0",
65
+ "vue": "^3.5.40",
66
+ "vue-router": "^5.2.0",
67
67
  "yaml": "^2.9.0",
68
- "@slidev/parser": "52.17.2",
69
- "@slidev/types": "52.17.2"
68
+ "@slidev/parser": "52.18.1",
69
+ "@slidev/types": "52.18.1"
70
70
  },
71
71
  "devDependencies": {
72
- "vite": "^8.1.3"
72
+ "vite": "^8.1.5"
73
73
  }
74
74
  }
package/setup/monaco.ts CHANGED
@@ -3,18 +3,18 @@ import { createSingletonPromise } from '@antfu/utils'
3
3
  import { shikiToMonaco } from '@shikijs/monaco'
4
4
  import { setupTypeAcquisition } from '@typescript/ata'
5
5
  import * as monaco from 'monaco-editor'
6
- import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
6
+ import EditorWorker from 'monaco-editor/editor/editor.worker?worker'
7
7
  // @ts-expect-error missing types
8
- import { StandaloneServices } from 'monaco-editor/esm/vs/editor/standalone/browser/standaloneServices'
8
+ import { StandaloneServices } from 'monaco-editor/editor/standalone/browser/standaloneServices'
9
9
 
10
- import CssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker'
11
- import HtmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker'
12
- import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'
13
- import TsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'
10
+ import CssWorker from 'monaco-editor/language/css/css.worker?worker'
11
+ import HtmlWorker from 'monaco-editor/language/html/html.worker?worker'
12
+ import JsonWorker from 'monaco-editor/language/json/json.worker?worker'
13
+ import TsWorker from 'monaco-editor/language/typescript/ts.worker?worker'
14
14
  // @ts-expect-error missing types
15
- import { ContextViewService } from 'monaco-editor/esm/vs/platform/contextview/browser/contextViewService'
15
+ import { ContextViewService } from 'monaco-editor/platform/contextview/browser/contextViewService'
16
16
  // @ts-expect-error missing types
17
- import { SyncDescriptor } from 'monaco-editor/esm/vs/platform/instantiation/common/descriptors'
17
+ import { SyncDescriptor } from 'monaco-editor/platform/instantiation/common/descriptors'
18
18
  import ts from 'typescript'
19
19
  import { watchEffect } from 'vue'
20
20
 
package/shim.d.ts CHANGED
@@ -1,4 +1,18 @@
1
- /// <reference types="vite-plugin-pwa/client" />
1
+ // `vite-plugin-pwa` is an optional peer dependency (only needed when the `pwa`
2
+ // option is enabled), so declare the subset of `virtual:pwa-register` we use
3
+ // inline instead of `/// <reference types="vite-plugin-pwa/client" />`. When
4
+ // PWA is off, the CLI serves a no-op stub for this module.
5
+ declare module 'virtual:pwa-register' {
6
+ export interface RegisterSWOptions {
7
+ immediate?: boolean
8
+ onNeedRefresh?: () => void
9
+ onOfflineReady?: () => void
10
+ onRegisteredSW?: (swScriptUrl: string, registration: ServiceWorkerRegistration | undefined) => void
11
+ onRegisterError?: (error: any) => void
12
+ }
13
+
14
+ export function registerSW(options?: RegisterSWOptions): (reloadPage?: boolean) => Promise<void>
15
+ }
2
16
 
3
17
  declare module '*.md' {
4
18
  // with unplugin-vue-markdown, markdowns can be treat as Vue components