@slidev/client 0.49.4 → 0.49.5

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/Arrow.vue CHANGED
@@ -9,6 +9,8 @@ Simple Arrow
9
9
  -->
10
10
 
11
11
  <script setup lang="ts">
12
+ import { ref } from 'vue'
13
+ import { onClickOutside } from '@vueuse/core'
12
14
  import { makeId } from '../logic/utils'
13
15
 
14
16
  defineProps<{
@@ -18,38 +20,53 @@ defineProps<{
18
20
  y2: number | string
19
21
  width?: number | string
20
22
  color?: string
23
+ twoWay?: boolean
21
24
  }>()
22
25
 
26
+ const emit = defineEmits(['dblclick', 'clickOutside'])
27
+
23
28
  const id = makeId()
29
+
30
+ const markerAttrs = {
31
+ markerUnits: 'strokeWidth',
32
+ markerHeight: 7,
33
+ refY: 3.5,
34
+ orient: 'auto',
35
+ }
36
+
37
+ const clickArea = ref<HTMLElement>()
38
+ onClickOutside(clickArea, () => emit('clickOutside'))
24
39
  </script>
25
40
 
26
41
  <template>
27
42
  <svg
28
- class="absolute left-0 top-0 pointer-events-none"
43
+ class="absolute left-0 top-0"
29
44
  :width="Math.max(+x1, +x2) + 50"
30
45
  :height="Math.max(+y1, +y2) + 50"
31
46
  >
32
47
  <defs>
33
- <marker
34
- :id="id"
35
- markerUnits="strokeWidth"
36
- :markerWidth="10"
37
- :markerHeight="7"
38
- refX="9"
39
- refY="3.5"
40
- orient="auto"
41
- >
42
- <polygon points="0 0, 10 3.5, 0 7" :fill="color || 'currentColor'" />
48
+ <marker :id="id" markerWidth="10" refX="9" v-bind="markerAttrs">
49
+ <polygon points="0 0, 10 3.5, 0 7" :fill="color || 'currentColor'" @dblclick="emit('dblclick')" />
50
+ </marker>
51
+ <marker v-if="twoWay" :id="`${id}-rev`" markerWidth="20" refX="11" v-bind="markerAttrs">
52
+ <polygon points="20 0, 10 3.5, 20 7" :fill="color || 'currentColor'" @dblclick="emit('dblclick')" />
43
53
  </marker>
44
54
  </defs>
45
55
  <line
46
- :x1="+x1"
47
- :y1="+y1"
48
- :x2="+x2"
49
- :y2="+y2"
56
+ :x1 :y1 :x2 :y2
50
57
  :stroke="color || 'currentColor'"
51
58
  :stroke-width="width || 2"
52
59
  :marker-end="`url(#${id})`"
60
+ :marker-start="twoWay ? `url(#${id}-rev)` : 'none'"
61
+ @dblclick="emit('dblclick')"
62
+ />
63
+ <line
64
+ ref="clickArea"
65
+ :x1 :y1 :x2 :y2
66
+ stroke="transparent"
67
+ stroke-linecap="round"
68
+ :stroke-width="20"
69
+ @dblclick="emit('dblclick')"
53
70
  />
54
71
  </svg>
55
72
  </template>
@@ -33,6 +33,7 @@ const props = withDefaults(defineProps<{
33
33
  editorOptions?: monaco.editor.IEditorOptions
34
34
  ata?: boolean
35
35
  runnable?: boolean
36
+ writable?: string
36
37
  autorun?: boolean | 'once'
37
38
  showOutputAt?: RawAtValue
38
39
  outputHeight?: string
@@ -52,6 +53,7 @@ const props = withDefaults(defineProps<{
52
53
 
53
54
  const code = ref(lz.decompressFromBase64(props.codeLz).trimEnd())
54
55
  const diff = props.diffLz && ref(lz.decompressFromBase64(props.diffLz).trimEnd())
56
+ const isWritable = computed(() => props.writable && !props.readonly && __DEV__)
55
57
 
56
58
  const langMap: Record<string, string> = {
57
59
  ts: 'typescript',
@@ -151,6 +153,7 @@ onMounted(async () => {
151
153
  contentHeight.value = newHeight
152
154
  nextTick(() => editableEditor.layout())
153
155
  })
156
+
154
157
  editableEditor = editor
155
158
  }
156
159
  loadTypes.value = () => {
@@ -173,6 +176,23 @@ onMounted(async () => {
173
176
  : /* BELOW */ `` // reset
174
177
  }
175
178
  }
179
+
180
+ editableEditor.addAction({
181
+ id: 'slidev-save',
182
+ label: 'Save',
183
+ keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS],
184
+ run: () => {
185
+ if (!isWritable.value || !import.meta.hot?.send) {
186
+ console.warn('[Slidev] this monaco editor is not writable, save action is ignored.')
187
+ return
188
+ }
189
+ import.meta.hot.send('slidev:monaco-write', {
190
+ file: props.writable!,
191
+ content: editableEditor.getValue(),
192
+ })
193
+ },
194
+ })
195
+
176
196
  nextTick(() => monaco.editor.remeasureFonts())
177
197
  })
178
198
  </script>
@@ -1,18 +1,33 @@
1
1
  <script setup lang="ts">
2
2
  import { ShikiMagicMovePrecompiled } from 'shiki-magic-move/vue'
3
3
  import type { KeyedTokensInfo } from 'shiki-magic-move/types'
4
+ import type { PropType } from 'vue'
4
5
  import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
5
6
  import lz from 'lz-string'
6
7
  import { useSlideContext } from '../context'
7
8
  import { makeId, updateCodeHighlightRange } from '../logic/utils'
8
9
  import { useNav } from '../composables/useNav'
9
10
  import { CLICKS_MAX } from '../constants'
11
+ import { configs } from '../env'
10
12
 
11
- const props = defineProps<{
12
- at?: string | number
13
- stepsLz: string
14
- stepRanges: string[][]
15
- }>()
13
+ const props = defineProps({
14
+ at: {
15
+ type: [String, Number],
16
+ default: '+1',
17
+ },
18
+ stepsLz: {
19
+ type: String,
20
+ required: true,
21
+ },
22
+ stepRanges: {
23
+ type: Array as PropType<string[][]>,
24
+ required: true,
25
+ },
26
+ lines: {
27
+ type: Boolean,
28
+ default: configs.lineNumbers,
29
+ },
30
+ })
16
31
 
17
32
  const steps = JSON.parse(lz.decompressFromBase64(props.stepsLz)) as KeyedTokensInfo[]
18
33
  const { $clicksContext: clicks, $scale: scale, $zoom: zoom } = useSlideContext()
@@ -37,7 +52,7 @@ onMounted(() => {
37
52
  throw new Error('[slidev] The length of stepRanges does not match the length of steps, this is an internal error.')
38
53
 
39
54
  const clickCounts = ranges.value.map(s => s.length).reduce((a, b) => a + b, 0)
40
- const clickInfo = clicks.calculateSince(props.at ?? '+1', clickCounts - 1)
55
+ const clickInfo = clicks.calculateSince(props.at, clickCounts - 1)
41
56
  clicks.register(id, clickInfo)
42
57
 
43
58
  watch(
package/builtin/VDrag.vue CHANGED
@@ -8,7 +8,7 @@ const props = defineProps<{
8
8
  markdownSource?: DragElementMarkdownSource
9
9
  }>()
10
10
 
11
- const { id, container, containerStyle, mounted, unmounted, startDragging } = useDragElement(null, props.pos, props.markdownSource)
11
+ const { dragId, container, containerStyle, mounted, unmounted, startDragging } = useDragElement(null, props.pos, props.markdownSource)
12
12
 
13
13
  onMounted(mounted)
14
14
  onUnmounted(unmounted)
@@ -17,7 +17,7 @@ onUnmounted(unmounted)
17
17
  <template>
18
18
  <div
19
19
  ref="container"
20
- :data-drag-id="id"
20
+ :data-drag-id="dragId"
21
21
  :style="containerStyle"
22
22
  class="p-1"
23
23
  @dblclick="startDragging"
@@ -0,0 +1,36 @@
1
+ <script setup lang="ts">
2
+ import { computed, onMounted, onUnmounted } from 'vue'
3
+ import type { DragElementMarkdownSource } from '../composables/useDragElements'
4
+ import { useDragElement } from '../composables/useDragElements'
5
+ import Arrow from './Arrow.vue'
6
+
7
+ const props = defineProps<{
8
+ pos?: string
9
+ markdownSource?: DragElementMarkdownSource
10
+ width?: number | string
11
+ color?: string
12
+ twoWay?: boolean
13
+ }>()
14
+
15
+ const { dragId, mounted, unmounted, startDragging, stopDragging, x0, y0, width, height } = useDragElement(null, props.pos ?? '100,100,300,300', props.markdownSource, true)
16
+
17
+ onMounted(mounted)
18
+ onUnmounted(unmounted)
19
+
20
+ const x1 = computed(() => x0.value - width.value / 2)
21
+ const y1 = computed(() => y0.value - height.value / 2)
22
+ const x2 = computed(() => x0.value + width.value / 2)
23
+ const y2 = computed(() => y0.value + height.value / 2)
24
+ </script>
25
+
26
+ <template>
27
+ <Arrow
28
+ :x1 :y1 :x2 :y2
29
+ :data-drag-id="dragId"
30
+ :width="props.width"
31
+ :color="props.color"
32
+ :two-way="props.twoWay"
33
+ @dblclick="startDragging"
34
+ @click-outside="stopDragging"
35
+ />
36
+ </template>
@@ -68,7 +68,8 @@ export function useDragElementsUpdater(no: number) {
68
68
  let replaced = false
69
69
 
70
70
  section = type === 'prop'
71
- ? section.replace(/<(v-?drag)(.*?)>/gi, (full, tag, attrs, index) => {
71
+ // eslint-disable-next-line regexp/no-super-linear-backtracking
72
+ ? section.replace(/<(v-?drag-?\w*)(.*?)>/gi, (full, tag, attrs, index) => {
72
73
  if (index === idx) {
73
74
  replaced = true
74
75
  const posMatch = attrs.match(/pos=".*?"/)
@@ -112,7 +113,7 @@ export function useDragElementsUpdater(no: number) {
112
113
  }
113
114
  }
114
115
 
115
- export function useDragElement(directive: DirectiveBinding | null, posRaw?: string | number | number[], markdownSource?: DragElementMarkdownSource) {
116
+ export function useDragElement(directive: DirectiveBinding | null, posRaw?: string | number | number[], markdownSource?: DragElementMarkdownSource, isArrow?: boolean) {
116
117
  function inject<T>(key: InjectionKey<T> | string): T | undefined {
117
118
  return directive
118
119
  ? directiveInject(directive, key)
@@ -129,7 +130,7 @@ export function useDragElement(directive: DirectiveBinding | null, posRaw?: stri
129
130
  const enabled = ['slide', 'presenter'].includes(renderContext.value)
130
131
 
131
132
  let dataSource: DragElementDataSource = directive ? 'directive' : 'prop'
132
- let id: string = makeId()
133
+ let dragId: string = makeId()
133
134
  let pos: number[] | undefined
134
135
  if (Array.isArray(posRaw)) {
135
136
  pos = posRaw
@@ -139,8 +140,8 @@ export function useDragElement(directive: DirectiveBinding | null, posRaw?: stri
139
140
  }
140
141
  else if (posRaw != null) {
141
142
  dataSource = 'frontmatter'
142
- id = `${posRaw}`
143
- posRaw = frontmatter?.dragPos?.[id]
143
+ dragId = `${posRaw}`
144
+ posRaw = frontmatter?.dragPos?.[dragId]
144
145
  pos = (posRaw as string)?.split(',').map(Number)
145
146
  }
146
147
 
@@ -149,12 +150,12 @@ export function useDragElement(directive: DirectiveBinding | null, posRaw?: stri
149
150
 
150
151
  const watchStopHandles: WatchStopHandle[] = [stopWatchBounds]
151
152
 
152
- const autoHeight = posRaw != null && !Number.isFinite(pos?.[3])
153
+ const autoHeight = !isArrow && posRaw != null && !Number.isFinite(pos?.[3])
153
154
  pos ??= [Number.NaN, Number.NaN, 0]
154
155
  const width = ref(pos[2])
155
156
  const x0 = ref(pos[0] + pos[2] / 2)
156
157
 
157
- const rotate = ref(pos[4] ?? 0)
158
+ const rotate = ref(isArrow ? 0 : (pos[4] ?? 0))
158
159
  const rotateRad = computed(() => rotate.value * Math.PI / 180)
159
160
  const rotateSin = computed(() => Math.sin(rotateRad.value))
160
161
  const rotateCos = computed(() => Math.cos(rotateRad.value))
@@ -163,7 +164,9 @@ export function useDragElement(directive: DirectiveBinding | null, posRaw?: stri
163
164
  const bounds = ref({ left: 0, top: 0, width: 0, height: 0 })
164
165
  const actualHeight = ref(0)
165
166
  function updateBounds() {
166
- const rect = container.value!.getBoundingClientRect()
167
+ if (!container.value)
168
+ return
169
+ const rect = container.value.getBoundingClientRect()
167
170
  bounds.value = {
168
171
  left: rect.left / zoom.value,
169
172
  top: rect.top / zoom.value,
@@ -175,32 +178,36 @@ export function useDragElement(directive: DirectiveBinding | null, posRaw?: stri
175
178
  watchStopHandles.push(watch(width, updateBounds, { flush: 'post' }))
176
179
 
177
180
  const configuredHeight = ref(pos[3] ?? 0)
178
- const height = computed({
179
- get: () => (autoHeight ? actualHeight.value : configuredHeight.value) || 0,
180
- set: v => !autoHeight && (configuredHeight.value = v),
181
- })
182
- const configuredY0 = ref(pos[1])
183
- const y0 = computed({
184
- get: () => configuredY0.value + height.value / 2,
185
- set: v => configuredY0.value = v - height.value / 2,
186
- })
187
-
188
- const containerStyle = computed<CSSProperties>(() => {
181
+ const height = autoHeight
182
+ ? computed({
183
+ get: () => (autoHeight ? actualHeight.value : configuredHeight.value) || 0,
184
+ set: v => !autoHeight && (configuredHeight.value = v),
185
+ })
186
+ : configuredHeight
187
+ const configuredY0 = autoHeight ? ref(pos[1]) : ref(pos[1] + pos[3] / 2)
188
+ const y0 = autoHeight
189
+ ? computed({
190
+ get: () => configuredY0.value + height.value / 2,
191
+ set: v => configuredY0.value = v - height.value / 2,
192
+ })
193
+ : configuredY0
194
+
195
+ const containerStyle = computed(() => {
189
196
  return Number.isFinite(x0.value)
190
197
  ? {
191
- position: 'absolute',
192
- zIndex: 100,
193
- left: `${x0.value - width.value / 2}px`,
194
- top: `${y0.value - height.value / 2}px`,
195
- width: `${width.value}px`,
196
- height: autoHeight ? undefined : `${height.value}px`,
197
- transformOrigin: 'center center',
198
- transform: `rotate(${rotate.value}deg)`,
199
- }
198
+ position: 'absolute',
199
+ zIndex: 100,
200
+ left: `${x0.value - width.value / 2}px`,
201
+ top: `${y0.value - height.value / 2}px`,
202
+ width: `${width.value}px`,
203
+ height: autoHeight ? undefined : `${height.value}px`,
204
+ transformOrigin: 'center center',
205
+ transform: `rotate(${rotate.value}deg)`,
206
+ } satisfies CSSProperties
200
207
  : {
201
- position: 'absolute',
202
- zIndex: 100,
203
- }
208
+ position: 'absolute',
209
+ zIndex: 100,
210
+ } satisfies CSSProperties
204
211
  })
205
212
 
206
213
  watchStopHandles.push(
@@ -218,15 +225,16 @@ export function useDragElement(directive: DirectiveBinding | null, posRaw?: stri
218
225
  if (dataSource === 'directive')
219
226
  posStr = `[${posStr}]`
220
227
 
221
- updater.value(id, posStr, dataSource, markdownSource)
228
+ updater.value(dragId, posStr, dataSource, markdownSource)
222
229
  },
223
230
  ),
224
231
  )
225
232
 
226
233
  const state = {
227
- id,
234
+ dragId,
228
235
  dataSource,
229
236
  markdownSource,
237
+ isArrow,
230
238
  zoom,
231
239
  autoHeight,
232
240
  x0,
package/env.ts CHANGED
@@ -17,4 +17,4 @@ export const themeVars = computed(() => {
17
17
  return objectMap(configs.themeConfig || {}, (k, v) => [`--slidev-theme-${k}`, v])
18
18
  })
19
19
 
20
- export const slidesTitle = configs.titleTemplate.replace('%s', configs.title || 'Slidev')
20
+ export const slidesTitle = configs.slidesTitle
@@ -10,14 +10,14 @@ import { slideHeight, slideWidth } from '../env'
10
10
  import { magicKeys } from '../state'
11
11
 
12
12
  const { data } = defineProps<{ data: DragElementState }>()
13
- const { id, zoom, autoHeight, x0, y0, width, height, rotate } = data
13
+ const { dragId, zoom, autoHeight, x0, y0, width, height, rotate, isArrow } = data
14
14
 
15
15
  const slideScale = inject(injectionSlideScale, ref(1))
16
16
  const scale = computed(() => slideScale.value * zoom.value)
17
17
  const { left: slideLeft, top: slideTop } = useSlideBounds()
18
18
 
19
19
  const ctrlSize = 10
20
- const minSize = 40
20
+ const minSize = isArrow ? Number.NEGATIVE_INFINITY : 40
21
21
  const minRemain = 10
22
22
 
23
23
  const rotateRad = computed(() => rotate.value * Math.PI / 180)
@@ -32,6 +32,9 @@ const boundingTop = computed(() => y0.value - boundingHeight.value / 2)
32
32
  const boundingRight = computed(() => x0.value + boundingWidth.value / 2)
33
33
  const boundingBottom = computed(() => y0.value + boundingHeight.value / 2)
34
34
 
35
+ const arrowRevX = computed(() => isArrow && width.value < 0)
36
+ const arrowRevY = computed(() => isArrow && height.value < 0)
37
+
35
38
  let currentDrag: {
36
39
  x0: number
37
40
  y0: number
@@ -206,11 +209,12 @@ function getCornerProps(isLeft: boolean, isTop: boolean) {
206
209
  width: `${ctrlSize}px`,
207
210
  height: `${ctrlSize}px`,
208
211
  margin: `-${ctrlSize / 2}px`,
209
- left: isLeft ? '0' : undefined,
210
- right: isLeft ? undefined : '0',
211
- top: isTop ? '0' : undefined,
212
- bottom: isTop ? undefined : '0',
213
- cursor: +isLeft + +isTop === 1 ? 'nesw-resize' : 'nwse-resize',
212
+ left: isLeft !== arrowRevX.value ? '0' : undefined,
213
+ right: isLeft !== arrowRevX.value ? undefined : '0',
214
+ top: isTop !== arrowRevY.value ? '0' : undefined,
215
+ bottom: isTop !== arrowRevY.value ? undefined : '0',
216
+ cursor: isArrow ? 'move' : +isLeft + +isTop === 1 ? 'nesw-resize' : 'nwse-resize',
217
+ borderRadius: isArrow ? '50%' : undefined,
214
218
  },
215
219
  class: ctrlClasses,
216
220
  }
@@ -356,14 +360,14 @@ watchEffect(() => {
356
360
  <div
357
361
  v-if="Number.isFinite(x0)"
358
362
  id="drag-control-container"
359
- :data-drag-id="id"
363
+ :data-drag-id="dragId"
360
364
  :style="{
361
365
  position: 'absolute',
362
366
  zIndex: 100,
363
- left: `${zoom * (x0 - width / 2)}px`,
364
- top: `${zoom * (y0 - height / 2)}px`,
365
- width: `${zoom * width}px`,
366
- height: `${zoom * height}px`,
367
+ left: `${zoom * (x0 - Math.abs(width) / 2)}px`,
368
+ top: `${zoom * (y0 - Math.abs(height) / 2)}px`,
369
+ width: `${zoom * Math.abs(width)}px`,
370
+ height: `${zoom * Math.abs(height)}px`,
367
371
  transformOrigin: 'center center',
368
372
  transform: `rotate(${rotate}deg)`,
369
373
  }"
@@ -371,27 +375,31 @@ watchEffect(() => {
371
375
  @pointermove="onPointermove"
372
376
  @pointerup="onPointerup"
373
377
  >
374
- <div class="absolute inset-0 z-100 b b-dark dark:b-gray-400">
378
+ <div class="absolute inset-0 z-100 dark:b-gray-400" :class="isArrow ? '' : 'b b-dark'">
375
379
  <template v-if="!autoHeight">
376
380
  <div v-bind="getCornerProps(true, true)" />
377
- <div v-bind="getCornerProps(true, false)" />
378
- <div v-bind="getCornerProps(false, true)" />
379
381
  <div v-bind="getCornerProps(false, false)" />
382
+ <template v-if="!isArrow">
383
+ <div v-bind="getCornerProps(true, false)" />
384
+ <div v-bind="getCornerProps(false, true)" />
385
+ </template>
380
386
  </template>
381
- <div v-bind="getBorderProps('l')" />
382
- <div v-bind="getBorderProps('r')" />
383
- <template v-if="!autoHeight">
384
- <div v-bind="getBorderProps('t')" />
385
- <div v-bind="getBorderProps('b')" />
387
+ <template v-if="!isArrow">
388
+ <div v-bind="getBorderProps('l')" />
389
+ <div v-bind="getBorderProps('r')" />
390
+ <template v-if="!autoHeight">
391
+ <div v-bind="getBorderProps('t')" />
392
+ <div v-bind="getBorderProps('b')" />
393
+ </template>
394
+ <div v-bind="getRotateProps()" />
395
+ <div
396
+ class="absolute -top-15px w-0 b b-dashed b-dark dark:b-gray-400"
397
+ :style="{
398
+ left: 'calc(50% - 1px)',
399
+ height: autoHeight ? '14px' : '10px',
400
+ }"
401
+ />
386
402
  </template>
387
- <div v-bind="getRotateProps()" />
388
- <div
389
- class="absolute -top-15px w-0 b b-dashed b-dark dark:b-gray-400"
390
- :style="{
391
- left: 'calc(50% - 1px)',
392
- height: autoHeight ? '14px' : '10px',
393
- }"
394
- />
395
403
  </div>
396
404
  </div>
397
405
  </template>
package/modules/v-drag.ts CHANGED
@@ -18,12 +18,12 @@ export function createVDragDirective() {
18
18
  }
19
19
  state.container.value = el
20
20
  el.draggingState = state
21
- el.dataset.dragId = state.id
21
+ el.dataset.dragId = state.dragId
22
22
  state.watchStopHandles.push(
23
23
  watch(state.containerStyle, (style) => {
24
24
  for (const [k, v] of Object.entries(style)) {
25
25
  if (v)
26
- el.style[k as any] = v
26
+ el.style[k as any] = v as any
27
27
  }
28
28
  }, { immediate: true }),
29
29
  )
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@slidev/client",
3
3
  "type": "module",
4
- "version": "0.49.4",
4
+ "version": "0.49.5",
5
5
  "description": "Presentation slides for developers",
6
6
  "author": "antfu <anthonyfu117@hotmail.com>",
7
7
  "license": "MIT",
@@ -32,14 +32,14 @@
32
32
  "@iconify-json/carbon": "^1.1.34",
33
33
  "@iconify-json/ph": "^1.1.13",
34
34
  "@iconify-json/svg-spinners": "^1.1.2",
35
- "@shikijs/monaco": "^1.6.0",
36
- "@shikijs/vitepress-twoslash": "^1.6.0",
35
+ "@shikijs/monaco": "^1.6.1",
36
+ "@shikijs/vitepress-twoslash": "^1.6.1",
37
37
  "@slidev/rough-notation": "^0.1.0",
38
38
  "@typescript/ata": "^0.9.4",
39
39
  "@unhead/vue": "^1.9.11",
40
40
  "@unocss/reset": "^0.60.3",
41
- "@vueuse/core": "^10.9.0",
42
- "@vueuse/math": "^10.9.0",
41
+ "@vueuse/core": "^10.10.0",
42
+ "@vueuse/math": "^10.10.0",
43
43
  "@vueuse/motion": "^2.1.0",
44
44
  "codemirror": "^5.65.16",
45
45
  "drauu": "^0.4.0",
@@ -52,17 +52,17 @@
52
52
  "monaco-editor": "^0.49.0",
53
53
  "prettier": "^3.2.5",
54
54
  "recordrtc": "^5.6.2",
55
- "shiki": "^1.6.0",
55
+ "shiki": "^1.6.1",
56
56
  "shiki-magic-move": "^0.4.2",
57
57
  "typescript": "^5.4.5",
58
58
  "unocss": "^0.60.3",
59
59
  "vue": "^3.4.27",
60
60
  "vue-router": "^4.3.2",
61
61
  "yaml": "^2.4.2",
62
- "@slidev/types": "0.49.4",
63
- "@slidev/parser": "0.49.4"
62
+ "@slidev/parser": "0.49.5",
63
+ "@slidev/types": "0.49.5"
64
64
  },
65
65
  "devDependencies": {
66
- "vite": "^5.2.11"
66
+ "vite": "^5.2.12"
67
67
  }
68
68
  }
package/setup/monaco.ts CHANGED
@@ -121,10 +121,21 @@ const setup = createSingletonPromise(async () => {
121
121
  }
122
122
  })
123
123
 
124
- export async function addFile(raw: Promise<{ default: string }>, path: string) {
124
+ async function _addFile(raw: Promise<{ default: string }>, path: string) {
125
+ const uri = monaco.Uri.file(path)
125
126
  const code = (await raw).default
126
127
  monaco.languages.typescript.typescriptDefaults.addExtraLib(code, `file:///${path}`)
127
- monaco.editor.createModel(code, 'javascript', monaco.Uri.file(path))
128
+ monaco.editor.createModel(code, 'javascript', uri)
129
+ }
130
+
131
+ const addFileCache = new Map<string, Promise<void>>()
132
+
133
+ export async function addFile(raw: Promise<{ default: string }>, path: string) {
134
+ if (addFileCache.has(path))
135
+ return addFileCache.get(path)
136
+ const promise = _addFile(raw, path)
137
+ addFileCache.set(path, promise)
138
+ return promise
128
139
  }
129
140
 
130
141
  export default setup
package/setup/routes.ts CHANGED
@@ -50,7 +50,7 @@ export default function setupRoutes() {
50
50
  )
51
51
  }
52
52
 
53
- if (__SLIDEV_HAS_SERVER__) {
53
+ if (__SLIDEV_FEATURE_PRINT__) {
54
54
  routes.push(
55
55
  {
56
56
  name: 'print',