@slidev/client 0.48.0-beta.21 → 0.48.0-beta.23
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/CodeBlockWrapper.vue +23 -25
- package/builtin/Monaco.vue +64 -8
- package/builtin/ShikiMagicMove.vue +69 -16
- package/builtin/Tweet.vue +12 -1
- package/composables/useClicks.ts +10 -2
- package/composables/useNav.ts +12 -8
- package/{logic/note.ts → composables/useSlideInfo.ts} +11 -14
- package/composables/useViewTransition.ts +7 -4
- package/context.ts +4 -5
- package/env.ts +4 -4
- package/index.html +1 -0
- package/internals/CodeRunner.vue +139 -0
- package/internals/DomElement.vue +18 -0
- package/internals/IconButton.vue +1 -1
- package/internals/NoteEditable.vue +4 -3
- package/internals/NoteStatic.vue +2 -2
- package/internals/PrintContainer.vue +4 -4
- package/internals/PrintSlideClick.vue +3 -3
- package/internals/QuickOverview.vue +2 -1
- package/internals/SideEditor.vue +1 -1
- package/internals/SlideContainer.vue +6 -6
- package/internals/SlideLoading.vue +1 -1
- package/internals/SlideWrapper.vue +79 -0
- package/internals/SlidesShow.vue +1 -1
- package/logic/nav.ts +1 -1
- package/logic/route.ts +6 -1
- package/logic/utils.ts +25 -1
- package/main.ts +1 -0
- package/modules/context.ts +4 -2
- package/modules/mermaid.ts +3 -1
- package/package.json +10 -9
- package/pages/overview.vue +7 -6
- package/pages/presenter.vue +1 -1
- package/setup/code-runners.ts +169 -0
- package/setup/monaco.ts +11 -10
- package/shim-vue.d.ts +4 -8
- package/state/index.ts +1 -1
- package/styles/code.css +2 -2
- package/internals/SlideWrapper.ts +0 -58
- package/styles/monaco.css +0 -27
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/* __imports__ */
|
|
2
|
+
import { createSingletonPromise } from '@antfu/utils'
|
|
3
|
+
import type { CodeRunner, CodeRunnerContext, CodeRunnerOutput, CodeRunnerOutputText, CodeRunnerOutputs, CodeRunnerProviders } from '@slidev/types'
|
|
4
|
+
import type { CodeToHastOptions } from 'shiki'
|
|
5
|
+
import { isDark } from '../logic/dark'
|
|
6
|
+
|
|
7
|
+
export default createSingletonPromise(async () => {
|
|
8
|
+
const runners: Record<string, CodeRunner> = {
|
|
9
|
+
javascript: runJavaScript,
|
|
10
|
+
js: runJavaScript,
|
|
11
|
+
typescript: runTypeScript,
|
|
12
|
+
ts: runTypeScript,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { shiki, themes } = await import('#slidev/shiki')
|
|
16
|
+
const highlighter = await shiki
|
|
17
|
+
const highlight = (code: string, lang: string, options: Partial<CodeToHastOptions> = {}) => highlighter.codeToHtml(code, {
|
|
18
|
+
lang,
|
|
19
|
+
theme: typeof themes === 'string'
|
|
20
|
+
? themes
|
|
21
|
+
: isDark.value
|
|
22
|
+
? themes.dark || 'vitesse-dark'
|
|
23
|
+
: themes.light || 'vitesse-light',
|
|
24
|
+
...options,
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
const run = async (code: string, lang: string, options: Record<string, unknown>): Promise<CodeRunnerOutputs> => {
|
|
28
|
+
try {
|
|
29
|
+
const runner = runners[lang]
|
|
30
|
+
if (!runner)
|
|
31
|
+
throw new Error(`Runner for language "${lang}" not found`)
|
|
32
|
+
return await runner(
|
|
33
|
+
code,
|
|
34
|
+
{
|
|
35
|
+
options,
|
|
36
|
+
highlight,
|
|
37
|
+
run: async (code, lang) => {
|
|
38
|
+
return await run(code, lang, options)
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
console.error(e)
|
|
45
|
+
return {
|
|
46
|
+
error: `${e}`,
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// @ts-expect-error injected in runtime
|
|
52
|
+
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
53
|
+
const injection_arg = runners
|
|
54
|
+
// eslint-disable-next-line prefer-const
|
|
55
|
+
let injection_return: CodeRunnerProviders = {}
|
|
56
|
+
|
|
57
|
+
/* __async_injections__ */
|
|
58
|
+
|
|
59
|
+
Object.assign(runners, injection_return)
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
highlight,
|
|
63
|
+
run,
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
// Ported from https://github.com/microsoft/TypeScript-Website/blob/v2/packages/playground/src/sidebar/runtime.ts
|
|
68
|
+
export async function runJavaScript(code: string): Promise<CodeRunnerOutputs> {
|
|
69
|
+
const allLogs: CodeRunnerOutput[] = []
|
|
70
|
+
|
|
71
|
+
const replace = {} as any
|
|
72
|
+
const logger = function (...objs: any[]) {
|
|
73
|
+
allLogs.push(objs.map(printObject))
|
|
74
|
+
}
|
|
75
|
+
replace.info = replace.log = replace.debug = replace.warn = replace.error = logger
|
|
76
|
+
replace.clear = () => allLogs.length = 0
|
|
77
|
+
const vmConsole = Object.assign({}, console, replace)
|
|
78
|
+
try {
|
|
79
|
+
const safeJS = `return async (console) => {${sanitizeJS(code)}}`
|
|
80
|
+
// eslint-disable-next-line no-new-func
|
|
81
|
+
await (new Function(safeJS)())(vmConsole)
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
return {
|
|
85
|
+
error: `ERROR: ${error}`,
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function printObject(arg: any): CodeRunnerOutputText {
|
|
90
|
+
if (typeof arg === 'string') {
|
|
91
|
+
return {
|
|
92
|
+
text: arg,
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
text: objectToText(arg),
|
|
97
|
+
highlightLang: 'javascript',
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function objectToText(arg: any): string {
|
|
102
|
+
let textRep = ''
|
|
103
|
+
if (arg instanceof Error) {
|
|
104
|
+
textRep = `Error: ${JSON.stringify(arg.message)}`
|
|
105
|
+
}
|
|
106
|
+
else if (arg === null || arg === undefined || typeof arg === 'symbol') {
|
|
107
|
+
textRep = String(arg)
|
|
108
|
+
}
|
|
109
|
+
else if (Array.isArray(arg)) {
|
|
110
|
+
textRep = `[${arg.map(objectToText).join(', ')}]`
|
|
111
|
+
}
|
|
112
|
+
else if (arg instanceof Set) {
|
|
113
|
+
const setIter = [...arg]
|
|
114
|
+
textRep = `Set (${arg.size}) {${setIter.map(objectToText).join(', ')}}`
|
|
115
|
+
}
|
|
116
|
+
else if (arg instanceof Map) {
|
|
117
|
+
const mapIter = [...arg.entries()]
|
|
118
|
+
textRep
|
|
119
|
+
= `Map (${arg.size}) {${mapIter
|
|
120
|
+
.map(([k, v]) => `${objectToText(k)} => ${objectToText(v)}`)
|
|
121
|
+
.join(', ')
|
|
122
|
+
}}`
|
|
123
|
+
}
|
|
124
|
+
else if (arg instanceof RegExp) {
|
|
125
|
+
textRep = arg.toString()
|
|
126
|
+
}
|
|
127
|
+
else if (typeof arg === 'string') {
|
|
128
|
+
textRep = JSON.stringify(arg)
|
|
129
|
+
}
|
|
130
|
+
else if (typeof arg === 'object') {
|
|
131
|
+
const name = arg.constructor?.name ?? ''
|
|
132
|
+
// No one needs to know an obj is an obj
|
|
133
|
+
const nameWithoutObject = name && name === 'Object' ? '' : name
|
|
134
|
+
const prefix = nameWithoutObject ? `${nameWithoutObject}: ` : ''
|
|
135
|
+
|
|
136
|
+
// JSON.stringify omits any keys with a value of undefined. To get around this, we replace undefined with the text __undefined__ and then do a global replace using regex back to keyword undefined
|
|
137
|
+
textRep
|
|
138
|
+
= prefix
|
|
139
|
+
+ JSON.stringify(arg, (_, value) => (value === undefined ? '__undefined__' : value), 2).replace(
|
|
140
|
+
/"__undefined__"/g,
|
|
141
|
+
'undefined',
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
textRep = String(textRep)
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
textRep = String(arg)
|
|
148
|
+
}
|
|
149
|
+
return textRep
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// The reflect-metadata runtime is available, so allow that to go through
|
|
153
|
+
function sanitizeJS(code: string) {
|
|
154
|
+
return code.replace(`import "reflect-metadata"`, '').replace(`require("reflect-metadata")`, '')
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return allLogs
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
let tsModule: typeof import('typescript') | undefined
|
|
161
|
+
|
|
162
|
+
export async function runTypeScript(code: string, context: CodeRunnerContext) {
|
|
163
|
+
const { transpile } = tsModule ??= await import('typescript')
|
|
164
|
+
code = transpile(code, {
|
|
165
|
+
module: tsModule.ModuleKind.ESNext,
|
|
166
|
+
target: tsModule.ScriptTarget.ES2022,
|
|
167
|
+
})
|
|
168
|
+
return await context.run(code, 'javascript')
|
|
169
|
+
}
|
package/setup/monaco.ts
CHANGED
|
@@ -89,16 +89,25 @@ const setup = createSingletonPromise(async () => {
|
|
|
89
89
|
})
|
|
90
90
|
: () => { }
|
|
91
91
|
|
|
92
|
-
|
|
92
|
+
monaco.languages.register({ id: 'vue' })
|
|
93
|
+
monaco.languages.register({ id: 'html' })
|
|
94
|
+
monaco.languages.register({ id: 'css' })
|
|
93
95
|
monaco.languages.register({ id: 'typescript' })
|
|
94
96
|
monaco.languages.register({ id: 'javascript' })
|
|
95
97
|
|
|
96
98
|
const { shiki, themes, shikiToMonaco } = await import('#slidev/shiki')
|
|
97
99
|
const highlighter = await shiki
|
|
98
100
|
|
|
101
|
+
// @ts-expect-error injected in runtime
|
|
102
|
+
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
103
|
+
const injection_arg = monaco
|
|
104
|
+
// eslint-disable-next-line prefer-const
|
|
105
|
+
let injection_return: MonacoSetupReturn = {}
|
|
106
|
+
|
|
107
|
+
/* __async_injections__ */
|
|
108
|
+
|
|
99
109
|
// Use Shiki to highlight Monaco
|
|
100
110
|
shikiToMonaco(highlighter, monaco)
|
|
101
|
-
|
|
102
111
|
if (typeof themes === 'string') {
|
|
103
112
|
monaco.editor.setTheme(themes)
|
|
104
113
|
}
|
|
@@ -110,14 +119,6 @@ const setup = createSingletonPromise(async () => {
|
|
|
110
119
|
})
|
|
111
120
|
}
|
|
112
121
|
|
|
113
|
-
// @ts-expect-error injected in runtime
|
|
114
|
-
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
115
|
-
const injection_arg = monaco
|
|
116
|
-
// eslint-disable-next-line prefer-const
|
|
117
|
-
let injection_return: MonacoSetupReturn = {}
|
|
118
|
-
|
|
119
|
-
/* __async_injections__ */
|
|
120
|
-
|
|
121
122
|
return {
|
|
122
123
|
monaco,
|
|
123
124
|
ata,
|
package/shim-vue.d.ts
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
declare module 'vue' {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
interface ComponentCustomProperties {
|
|
6
|
-
$slidev: UnwrapNestedRefs<SlidevContext>
|
|
2
|
+
type SlideContext = import('./context').SlideContext
|
|
3
|
+
interface ComponentCustomProperties extends SlideContext {
|
|
7
4
|
}
|
|
8
5
|
}
|
|
9
6
|
|
|
10
7
|
declare module 'vue-router' {
|
|
11
8
|
import type { TransitionGroupProps } from 'vue'
|
|
12
|
-
import type { ClicksContext, SlideInfo } from '@slidev/types'
|
|
13
9
|
|
|
14
10
|
interface RouteMeta {
|
|
15
11
|
// inherited from frontmatter
|
|
@@ -21,7 +17,7 @@ declare module 'vue-router' {
|
|
|
21
17
|
preload?: boolean
|
|
22
18
|
|
|
23
19
|
// slide info
|
|
24
|
-
slide?: Omit<SlideInfo, 'source'> & {
|
|
20
|
+
slide?: Omit<import('@slidev/types').SlideInfo, 'source'> & {
|
|
25
21
|
noteHTML: string
|
|
26
22
|
filepath: string
|
|
27
23
|
start: number
|
|
@@ -30,7 +26,7 @@ declare module 'vue-router' {
|
|
|
30
26
|
}
|
|
31
27
|
|
|
32
28
|
// private fields
|
|
33
|
-
__clicksContext:
|
|
29
|
+
__clicksContext: import('@slidev/types').ClicksContext | undefined
|
|
34
30
|
__preloaded?: boolean
|
|
35
31
|
}
|
|
36
32
|
}
|
package/state/index.ts
CHANGED
|
@@ -14,7 +14,7 @@ export const breakpoints = useBreakpoints({
|
|
|
14
14
|
})
|
|
15
15
|
export const windowSize = useWindowSize()
|
|
16
16
|
export const magicKeys = useMagicKeys()
|
|
17
|
-
export const isScreenVertical = computed(() => windowSize.height.value - windowSize.width.value / slideAspect > 120)
|
|
17
|
+
export const isScreenVertical = computed(() => windowSize.height.value - windowSize.width.value / slideAspect.value > 120)
|
|
18
18
|
export const fullscreen = useFullscreen(isClient ? document.body : null)
|
|
19
19
|
|
|
20
20
|
export const activeElement = useActiveElement()
|
package/styles/code.css
CHANGED
|
@@ -44,9 +44,9 @@ html:not(.dark) .shiki span {
|
|
|
44
44
|
overflow: auto;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
.slidev-code .
|
|
47
|
+
.slidev-code .slidev-code-highlighted {
|
|
48
48
|
}
|
|
49
|
-
.slidev-code .
|
|
49
|
+
.slidev-code .slidev-code-dishonored {
|
|
50
50
|
opacity: 0.3;
|
|
51
51
|
pointer-events: none;
|
|
52
52
|
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { computed, defineAsyncComponent, defineComponent, h, ref, toRef } from 'vue'
|
|
2
|
-
import type { PropType } from 'vue'
|
|
3
|
-
import { provideLocal } from '@vueuse/core'
|
|
4
|
-
import type { ClicksContext, RenderContext, SlideRoute } from '@slidev/types'
|
|
5
|
-
import { injectionActive, injectionClicksContext, injectionCurrentPage, injectionRenderContext, injectionRoute } from '../constants'
|
|
6
|
-
import SlideLoading from './SlideLoading.vue'
|
|
7
|
-
|
|
8
|
-
export default defineComponent({
|
|
9
|
-
name: 'SlideWrapper',
|
|
10
|
-
props: {
|
|
11
|
-
clicksContext: {
|
|
12
|
-
type: Object as PropType<ClicksContext>,
|
|
13
|
-
required: true,
|
|
14
|
-
},
|
|
15
|
-
renderContext: {
|
|
16
|
-
type: String,
|
|
17
|
-
default: 'main',
|
|
18
|
-
},
|
|
19
|
-
active: {
|
|
20
|
-
type: Boolean,
|
|
21
|
-
default: false,
|
|
22
|
-
},
|
|
23
|
-
is: {
|
|
24
|
-
required: true,
|
|
25
|
-
},
|
|
26
|
-
route: {
|
|
27
|
-
type: Object as PropType<SlideRoute>,
|
|
28
|
-
required: true,
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
setup(props) {
|
|
32
|
-
provideLocal(injectionRoute, props.route)
|
|
33
|
-
provideLocal(injectionCurrentPage, ref(props.route.no))
|
|
34
|
-
provideLocal(injectionRenderContext, ref(props.renderContext as RenderContext))
|
|
35
|
-
provideLocal(injectionActive, toRef(props, 'active'))
|
|
36
|
-
provideLocal(injectionClicksContext, toRef(props, 'clicksContext'))
|
|
37
|
-
|
|
38
|
-
const style = computed(() => {
|
|
39
|
-
const zoom = props.route.meta?.slide?.frontmatter.zoom ?? 1
|
|
40
|
-
return zoom === 1
|
|
41
|
-
? undefined
|
|
42
|
-
: {
|
|
43
|
-
width: `${100 / zoom}%`,
|
|
44
|
-
height: `${100 / zoom}%`,
|
|
45
|
-
transformOrigin: 'top left',
|
|
46
|
-
transform: `scale(${zoom})`,
|
|
47
|
-
}
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
const SlideComponent = defineAsyncComponent({
|
|
51
|
-
loader: (props.is as any),
|
|
52
|
-
delay: 300,
|
|
53
|
-
loadingComponent: SlideLoading,
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
return () => h(SlideComponent, { style: style.value })
|
|
57
|
-
},
|
|
58
|
-
})
|
package/styles/monaco.css
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
div[widgetid='messageoverlay'] {
|
|
2
|
-
transform: translateY(calc(100% * (var(--slidev-slide-scale) - 1)));
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
.slidev-monaco-container {
|
|
6
|
-
position: relative;
|
|
7
|
-
margin: var(--slidev-code-margin);
|
|
8
|
-
padding: var(--slidev-code-padding);
|
|
9
|
-
line-height: var(--slidev-code-line-height);
|
|
10
|
-
border-radius: var(--slidev-code-radius);
|
|
11
|
-
background: var(--slidev-code-background);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
.slidev-monaco-container .monaco-editor {
|
|
15
|
-
--monaco-monospace-font: var(--slidev-code-font-family);
|
|
16
|
-
--vscode-editor-background: var(--slidev-code-background);
|
|
17
|
-
--vscode-editorGutter-background: var(--slidev-code-background);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/** Revert styles */
|
|
21
|
-
.slidev-monaco-container .monaco-editor a {
|
|
22
|
-
border-bottom: none;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
.slidev-monaco-container .monaco-editor a:hover {
|
|
26
|
-
border-bottom: none;
|
|
27
|
-
}
|