@slidev/client 0.49.28 → 0.50.0-beta.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.
Files changed (86) hide show
  1. package/builtin/Arrow.vue +1 -1
  2. package/builtin/CodeBlockWrapper.vue +3 -3
  3. package/builtin/KaTexBlockWrapper.vue +2 -2
  4. package/builtin/Mermaid.vue +1 -1
  5. package/builtin/Monaco.vue +5 -5
  6. package/builtin/RenderWhen.vue +2 -2
  7. package/builtin/ShikiMagicMove.vue +5 -5
  8. package/builtin/SlidevVideo.vue +2 -2
  9. package/builtin/Toc.vue +1 -1
  10. package/builtin/TocList.vue +2 -2
  11. package/builtin/VAfter.ts +1 -1
  12. package/builtin/VClick.ts +1 -1
  13. package/builtin/VClickGap.vue +1 -1
  14. package/builtin/VClicks.ts +1 -1
  15. package/builtin/VDrag.vue +1 -1
  16. package/builtin/VDragArrow.vue +1 -1
  17. package/builtin/VSwitch.ts +4 -4
  18. package/composables/useClicks.ts +1 -1
  19. package/composables/useDragElements.ts +2 -2
  20. package/composables/useDrawings.ts +3 -3
  21. package/composables/useNav.ts +8 -8
  22. package/composables/useSlideInfo.ts +2 -2
  23. package/composables/useSwipeControls.ts +1 -1
  24. package/composables/useViewTransition.ts +1 -1
  25. package/constants.ts +2 -1
  26. package/context.ts +2 -2
  27. package/env.ts +2 -2
  28. package/index.ts +23 -5
  29. package/internals/CodeRunner.vue +4 -4
  30. package/internals/ContextMenu.vue +2 -2
  31. package/internals/Controls.vue +6 -6
  32. package/internals/DevicesList.vue +2 -2
  33. package/internals/DragControl.vue +2 -2
  34. package/internals/Draggable.vue +1 -1
  35. package/internals/DrawingControls.vue +140 -139
  36. package/internals/DrawingLayer.vue +1 -1
  37. package/internals/Goto.vue +3 -3
  38. package/internals/NavControls.vue +8 -8
  39. package/internals/NoteDisplay.vue +1 -1
  40. package/internals/NoteEditable.vue +2 -2
  41. package/internals/PrintContainer.vue +3 -3
  42. package/internals/PrintSlide.vue +1 -1
  43. package/internals/PrintSlideClick.vue +3 -3
  44. package/internals/QuickOverview.vue +9 -7
  45. package/internals/RecordingControls.vue +1 -1
  46. package/internals/RecordingDialog.vue +1 -1
  47. package/internals/SelectList.vue +1 -1
  48. package/internals/Settings.vue +1 -1
  49. package/internals/ShikiEditor.vue +1 -1
  50. package/internals/SideEditor.vue +12 -7
  51. package/internals/SlideContainer.vue +32 -3
  52. package/internals/SlideWrapper.vue +4 -4
  53. package/internals/SlidesShow.vue +6 -6
  54. package/internals/WebCamera.vue +1 -1
  55. package/logic/contextMenu.ts +3 -3
  56. package/logic/recording.ts +4 -4
  57. package/logic/shortcuts.ts +3 -3
  58. package/logic/slides.ts +2 -2
  59. package/logic/snapshot.ts +86 -0
  60. package/modules/context.ts +1 -1
  61. package/modules/mermaid.ts +3 -3
  62. package/modules/v-click.ts +1 -1
  63. package/modules/v-drag.ts +1 -1
  64. package/modules/v-mark.ts +2 -2
  65. package/modules/v-motion.ts +3 -3
  66. package/package.json +25 -24
  67. package/pages/notes.vue +7 -7
  68. package/pages/overview.vue +24 -11
  69. package/pages/play.vue +10 -10
  70. package/pages/presenter/print.vue +2 -2
  71. package/pages/presenter.vue +18 -18
  72. package/pages/print.vue +3 -3
  73. package/setup/code-runners.ts +4 -4
  74. package/setup/context-menu.ts +11 -11
  75. package/setup/main.ts +4 -4
  76. package/setup/mermaid.ts +1 -1
  77. package/setup/monaco.ts +13 -9
  78. package/setup/root.ts +9 -9
  79. package/setup/shortcuts.ts +5 -5
  80. package/state/drawings.ts +1 -0
  81. package/state/index.ts +1 -1
  82. package/state/shared.ts +2 -1
  83. package/state/snapshot.ts +13 -0
  84. package/state/syncState.ts +76 -24
  85. package/styles/index.css +1 -0
  86. package/uno.config.ts +3 -16
package/setup/monaco.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { createSingletonPromise } from '@antfu/utils'
2
1
  import type { MonacoSetupReturn } from '@slidev/types'
3
- import * as monaco from 'monaco-editor'
4
- import { watchEffect } from 'vue'
2
+ import configs from '#slidev/configs'
3
+ import setups from '#slidev/setups/monaco'
4
+ import { createSingletonPromise } from '@antfu/utils'
5
5
  import { setupTypeAcquisition } from '@typescript/ata'
6
- import ts from 'typescript'
6
+ import * as monaco from 'monaco-editor'
7
7
 
8
8
  import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
9
9
  import CssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker'
@@ -11,18 +11,18 @@ import HtmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker'
11
11
  import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'
12
12
  import TsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'
13
13
 
14
+ import ts from 'typescript'
15
+
16
+ import { watchEffect } from 'vue'
17
+
14
18
  // @ts-expect-error missing types
15
19
  import { ContextViewService } from 'monaco-editor/esm/vs/platform/contextview/browser/contextViewService'
16
20
 
17
21
  // @ts-expect-error missing types
18
22
  import { SyncDescriptor } from 'monaco-editor/esm/vs/platform/instantiation/common/descriptors'
19
-
20
23
  // @ts-expect-error missing types
21
24
  import { StandaloneServices } from 'monaco-editor/esm/vs/editor/standalone/browser/standaloneServices'
22
-
23
25
  import { isDark } from '../logic/dark'
24
- import configs from '#slidev/configs'
25
- import setups from '#slidev/setups/monaco'
26
26
 
27
27
  window.MonacoEnvironment = {
28
28
  getWorker(_, label) {
@@ -92,7 +92,7 @@ const setup = createSingletonPromise(async () => {
92
92
  monaco.languages.register({ id: 'typescript' })
93
93
  monaco.languages.register({ id: 'javascript' })
94
94
 
95
- const { shiki, themes, shikiToMonaco } = await import('#slidev/shiki')
95
+ const { shiki, languages, themes, shikiToMonaco } = await import('#slidev/shiki')
96
96
  const highlighter = await shiki
97
97
 
98
98
  const editorOptions: MonacoSetupReturn['editorOptions'] & object = {}
@@ -113,6 +113,10 @@ const setup = createSingletonPromise(async () => {
113
113
  : themes.light || 'vitesse-light')
114
114
  })
115
115
  }
116
+ // Register all languages, otherwise Monaco will not highlight them
117
+ for (const lang of languages) {
118
+ monaco.languages.register({ id: lang })
119
+ }
116
120
 
117
121
  return {
118
122
  monaco,
package/setup/root.ts CHANGED
@@ -1,17 +1,17 @@
1
- import { computed, getCurrentInstance, reactive, ref, shallowRef, watch } from 'vue'
1
+ import setups from '#slidev/setups/root'
2
2
  import { useHead } from '@unhead/vue'
3
+ import { computed, getCurrentInstance, reactive, ref, shallowRef, watch } from 'vue'
3
4
  import { useRouter } from 'vue-router'
5
+ import { createFixedClicks } from '../composables/useClicks'
6
+ import { useEmbeddedControl } from '../composables/useEmbeddedCtrl'
7
+ import { useNav } from '../composables/useNav'
8
+ import { injectionClicksContext, injectionCurrentPage, injectionRenderContext, injectionSlidevContext, TRUST_ORIGINS } from '../constants'
4
9
  import { configs, slidesTitle } from '../env'
5
- import { initSharedState, onPatch, patch } from '../state/shared'
6
- import { initDrawingState } from '../state/drawings'
7
- import { TRUST_ORIGINS, injectionClicksContext, injectionCurrentPage, injectionRenderContext, injectionSlidevContext } from '../constants'
8
10
  import { skipTransition } from '../logic/hmr'
9
- import { makeId } from '../logic/utils'
10
11
  import { getSlidePath } from '../logic/slides'
11
- import { createFixedClicks } from '../composables/useClicks'
12
- import { useNav } from '../composables/useNav'
13
- import { useEmbeddedControl } from '../composables/useEmbeddedCtrl'
14
- import setups from '#slidev/setups/root'
12
+ import { makeId } from '../logic/utils'
13
+ import { initDrawingState } from '../state/drawings'
14
+ import { initSharedState, onPatch, patch } from '../state/shared'
15
15
 
16
16
  export default function setupRoot() {
17
17
  const app = getCurrentInstance()!.appContext.app
@@ -1,12 +1,12 @@
1
- import { and, not, or } from '@vueuse/math'
2
1
  import type { NavOperations, ShortcutOptions } from '@slidev/types'
3
- import { downloadPDF } from '../utils'
2
+ import setups from '#slidev/setups/shortcuts'
3
+ import { and, not, or } from '@vueuse/math'
4
+ import { useDrawings } from '../composables/useDrawings'
5
+ import { useNav } from '../composables/useNav'
4
6
  import { toggleDark } from '../logic/dark'
5
7
  import { activeDragElement, magicKeys, showGotoDialog, showOverview, toggleOverview } from '../state'
6
- import { useNav } from '../composables/useNav'
7
- import { useDrawings } from '../composables/useDrawings'
8
+ import { downloadPDF } from '../utils'
8
9
  import { currentOverviewPage, downOverviewPage, nextOverviewPage, prevOverviewPage, upOverviewPage } from './../logic/overview'
9
- import setups from '#slidev/setups/shortcuts'
10
10
 
11
11
  export default function setupShortcuts() {
12
12
  const { go, goFirst, goLast, next, nextSlide, prev, prevSlide } = useNav()
package/state/drawings.ts CHANGED
@@ -6,6 +6,7 @@ export type DrawingsState = Record<number, string | undefined>
6
6
  export const {
7
7
  init: initDrawingState,
8
8
  onPatch: onPatchDrawingState,
9
+ onUpdate: onDrawingUpdate,
9
10
  patch: patchDrawingState,
10
11
  state: drawingState,
11
12
  } = createSyncState<DrawingsState>(serverDrawingState, serverDrawingState, __SLIDEV_FEATURE_DRAWINGS_PERSIST__)
package/state/index.ts CHANGED
@@ -1,7 +1,7 @@
1
+ import type { DragElementState } from '../composables/useDragElements'
1
2
  import { breakpointsTailwind, isClient, useActiveElement, useBreakpoints, useFullscreen, useLocalStorage, useMagicKeys, useToggle, useWindowSize } from '@vueuse/core'
2
3
  import { computed, ref, shallowRef } from 'vue'
3
4
  import { slideAspect } from '../env'
4
- import type { DragElementState } from '../composables/useDragElements'
5
5
 
6
6
  export const showRecordingDialog = ref(false)
7
7
  export const showInfoDialog = ref(false)
package/state/shared.ts CHANGED
@@ -22,7 +22,7 @@ export interface SharedState {
22
22
  }
23
23
  }
24
24
 
25
- const { init, onPatch, patch, state } = createSyncState<SharedState>(serverState, {
25
+ const { init, onPatch, onUpdate, patch, state } = createSyncState<SharedState>(serverState, {
26
26
  page: 1,
27
27
  clicks: 0,
28
28
  clicksTotal: 0,
@@ -34,6 +34,7 @@ const { init, onPatch, patch, state } = createSyncState<SharedState>(serverState
34
34
  export {
35
35
  init as initSharedState,
36
36
  onPatch,
37
+ onUpdate as onSharedUpdate,
37
38
  patch,
38
39
  state as sharedState,
39
40
  }
@@ -0,0 +1,13 @@
1
+ import serverSnapshotState from 'server-reactive:snapshots?diff'
2
+ import { createSyncState } from './syncState'
3
+
4
+ export type SnapshotState = Record<number, {
5
+ revision: string
6
+ image: string
7
+ }>
8
+
9
+ export const snapshotState = createSyncState<SnapshotState>(
10
+ serverSnapshotState,
11
+ serverSnapshotState,
12
+ true,
13
+ )
@@ -1,4 +1,72 @@
1
- import { reactive, toRaw, watch } from 'vue'
1
+ import { reactive, ref, toRaw, watch } from 'vue'
2
+
3
+ export type SyncWrite<State extends object> = (state: State, updating?: boolean) => void
4
+
5
+ export interface Sync {
6
+ enabled?: boolean
7
+ init: <State extends object>(channelKey: string, onUpdate: (data: Partial<State>) => void, state: State, persist?: boolean) => SyncWrite<State> | undefined
8
+ }
9
+
10
+ interface BuiltinSync extends Sync {
11
+ channels: BroadcastChannel[]
12
+ disable: () => void
13
+ listener?: (event: StorageEvent) => void
14
+ }
15
+
16
+ const builtinSync: BuiltinSync = {
17
+ channels: [],
18
+ enabled: true,
19
+ init<State extends object>(channelKey: string, onUpdate: (data: Partial<State>) => void, state: State, persist = false) {
20
+ let stateChannel: BroadcastChannel
21
+ if (!__SLIDEV_HAS_SERVER__ && !persist) {
22
+ stateChannel = new BroadcastChannel(channelKey)
23
+ stateChannel.addEventListener('message', (event: MessageEvent<Partial<State>>) => onUpdate(event.data))
24
+ this.channels.push(stateChannel)
25
+ }
26
+ else if (!__SLIDEV_HAS_SERVER__ && persist) {
27
+ this.listener = function (event: StorageEvent) {
28
+ if (event && event.key === channelKey && event.newValue)
29
+ onUpdate(JSON.parse(event.newValue) as Partial<State>)
30
+ }
31
+ window.addEventListener('storage', this.listener)
32
+ const serializedState = window.localStorage.getItem(channelKey)
33
+ if (serializedState)
34
+ onUpdate(JSON.parse(serializedState) as Partial<State>)
35
+ }
36
+ return (state: State, updating = false) => {
37
+ if (this.enabled) {
38
+ if (!persist && stateChannel && !updating)
39
+ stateChannel.postMessage(toRaw(state))
40
+ if (persist && !updating)
41
+ window.localStorage.setItem(channelKey, JSON.stringify(state))
42
+ }
43
+ }
44
+ },
45
+ disable() {
46
+ this.enabled = false
47
+ this.channels.forEach(channel => channel.close())
48
+ if (this.listener) {
49
+ window.removeEventListener('storage', this.listener)
50
+ }
51
+ },
52
+ }
53
+ const syncInterfaces: Sync[] = reactive([builtinSync])
54
+ const channels: Map<string, { onUpdate: (data: Partial<object>) => void, persist?: boolean, state: object }> = new Map()
55
+ const syncWrites = ref<Record<string, SyncWrite<object>[]>>({})
56
+
57
+ export function disableBuiltinSync() {
58
+ builtinSync.disable()
59
+ }
60
+
61
+ export function addSyncMethod(sync: Sync) {
62
+ syncInterfaces.push(sync)
63
+ for (const [channelKey, { onUpdate, persist, state }] of channels.entries()) {
64
+ const write = sync.init(channelKey, onUpdate, state, persist)
65
+ if (write) {
66
+ syncWrites.value[channelKey].push(write)
67
+ }
68
+ }
69
+ }
2
70
 
3
71
  export function createSyncState<State extends object>(serverState: State, defaultState: State, persist = false) {
4
72
  const onPatchCallbacks: ((state: State) => void)[] = []
@@ -36,35 +104,19 @@ export function createSyncState<State extends object>(serverState: State, defaul
36
104
  }
37
105
 
38
106
  function init(channelKey: string) {
39
- let stateChannel: BroadcastChannel
40
- if (!__SLIDEV_HAS_SERVER__ && !persist) {
41
- stateChannel = new BroadcastChannel(channelKey)
42
- stateChannel.addEventListener('message', (event: MessageEvent<Partial<State>>) => onUpdate(event.data))
43
- }
44
- else if (!__SLIDEV_HAS_SERVER__ && persist) {
45
- window.addEventListener('storage', (event) => {
46
- if (event && event.key === channelKey && event.newValue)
47
- onUpdate(JSON.parse(event.newValue) as Partial<State>)
48
- })
49
- }
107
+ channels.set(channelKey, { onUpdate, persist, state })
108
+ syncWrites.value[channelKey] = syncInterfaces
109
+ .map(sync => sync.init<State>(channelKey, onUpdate, state, persist))
110
+ .filter((x): x is SyncWrite<object> => Boolean(x))
50
111
 
51
112
  function onStateChanged() {
52
- if (!persist && stateChannel && !updating)
53
- stateChannel.postMessage(toRaw(state))
54
- else if (persist && !updating)
55
- window.localStorage.setItem(channelKey, JSON.stringify(state))
113
+ syncWrites.value[channelKey].forEach(write => write?.(toRaw(state), updating))
56
114
  if (!patching)
57
115
  onPatchCallbacks.forEach((fn: (state: State) => void) => fn(state))
58
116
  }
59
117
 
60
- watch(state, onStateChanged, { deep: true, flush: 'sync' })
61
-
62
- if (!__SLIDEV_HAS_SERVER__ && persist) {
63
- const serialzedState = window.localStorage.getItem(channelKey)
64
- if (serialzedState)
65
- onUpdate(JSON.parse(serialzedState) as Partial<State>)
66
- }
118
+ watch(state, onStateChanged, { deep: true })
67
119
  }
68
120
 
69
- return { init, onPatch, patch, state }
121
+ return { init, onPatch, onUpdate, patch, state }
70
122
  }
package/styles/index.css CHANGED
@@ -23,6 +23,7 @@ html {
23
23
  cursor: pointer;
24
24
  @apply opacity-75 transition duration-200 ease-in-out align-middle rounded p-1;
25
25
  @apply hover:(opacity-100 bg-gray-400 bg-opacity-10);
26
+ @apply focus-visible:(opacity-100 outline outline-2 outline-offset-2 outline-black dark:outline-white);
26
27
  @apply md:p-2;
27
28
  }
28
29
 
package/uno.config.ts CHANGED
@@ -1,16 +1,13 @@
1
- import { fileURLToPath } from 'node:url'
2
- import { readFileSync } from 'node:fs'
1
+ import extractorMdc from '@unocss/extractor-mdc'
2
+ import { variantMatcher } from '@unocss/preset-mini/utils'
3
3
  import {
4
4
  defineConfig,
5
5
  presetAttributify,
6
- presetIcons,
7
6
  presetTypography,
8
7
  presetUno,
9
8
  transformerDirectives,
10
9
  transformerVariantGroup,
11
10
  } from 'unocss'
12
- import { variantMatcher } from '@unocss/preset-mini/utils'
13
- import extractorMdc from '@unocss/extractor-mdc'
14
11
 
15
12
  export default defineConfig({
16
13
  safelist: [
@@ -41,18 +38,8 @@ export default defineConfig({
41
38
  presets: [
42
39
  presetUno(),
43
40
  presetAttributify(),
44
- presetIcons({
45
- collectionsNodeResolvePath: fileURLToPath(import.meta.url),
46
- collections: {
47
- slidev: {
48
- logo: async () => {
49
- const content = readFileSync(fileURLToPath(new URL('assets/logo.svg', import.meta.url)), 'utf-8')
50
- return content
51
- },
52
- },
53
- },
54
- }),
55
41
  presetTypography(),
42
+ /* Preset Icons is added in ../node/setups/unocss.ts */
56
43
  ],
57
44
  transformers: [
58
45
  transformerDirectives({ enforce: 'pre' }),