@slidev/client 52.7.0 → 52.9.0
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/ShikiMagicMove.vue +27 -3
- package/constants.ts +1 -0
- package/internals/QuickOverview.vue +1 -1
- package/internals/ShikiEditor.vue +10 -4
- package/internals/SlideContainer.vue +2 -1
- package/internals/SlideWrapper.vue +10 -11
- package/package.json +7 -6
- package/setup/code-runners.ts +11 -3
- package/setup/monaco.ts +11 -11
- package/setup/shiki-options.ts +125 -0
- package/setup/shiki.ts +30 -0
|
@@ -34,6 +34,10 @@ const props = defineProps({
|
|
|
34
34
|
type: String,
|
|
35
35
|
default: '',
|
|
36
36
|
},
|
|
37
|
+
duration: {
|
|
38
|
+
type: Number,
|
|
39
|
+
default: configs.magicMoveDuration,
|
|
40
|
+
},
|
|
37
41
|
})
|
|
38
42
|
|
|
39
43
|
const steps = JSON.parse(lz.decompressFromBase64(props.stepsLz)) as KeyedTokensInfo[]
|
|
@@ -42,6 +46,8 @@ const { isPrintMode } = useNav()
|
|
|
42
46
|
const id = makeId()
|
|
43
47
|
|
|
44
48
|
const stepIndex = ref(0)
|
|
49
|
+
// Used to skip the animation on the first tick.
|
|
50
|
+
const isFirstTick = ref(true)
|
|
45
51
|
const container = ref<HTMLElement>()
|
|
46
52
|
|
|
47
53
|
const showCopyButton = computed(() => {
|
|
@@ -89,6 +95,7 @@ onMounted(() => {
|
|
|
89
95
|
const clickInfo = clicks.calculateSince(props.at, clickCounts - 1)
|
|
90
96
|
clicks.register(id, clickInfo)
|
|
91
97
|
|
|
98
|
+
let cancelTick: () => void = () => { }
|
|
92
99
|
watch(
|
|
93
100
|
() => clicks.current,
|
|
94
101
|
() => {
|
|
@@ -107,9 +114,24 @@ onMounted(() => {
|
|
|
107
114
|
currentClickSum += current.length || 1
|
|
108
115
|
}
|
|
109
116
|
|
|
117
|
+
// It seems ticks may not be executed in order. Cancel previous ones, because
|
|
118
|
+
// clicks.current is first 0 then immediately updated when refreshing the slide.
|
|
119
|
+
cancelTick()
|
|
120
|
+
let isCanceled = false
|
|
121
|
+
cancelTick = () => {
|
|
122
|
+
isCanceled = true
|
|
123
|
+
}
|
|
124
|
+
|
|
110
125
|
nextTick(async () => {
|
|
126
|
+
if (isCanceled) {
|
|
127
|
+
return
|
|
128
|
+
}
|
|
111
129
|
stepIndex.value = step
|
|
112
|
-
|
|
130
|
+
if (isFirstTick.value) {
|
|
131
|
+
nextTick(() => {
|
|
132
|
+
isFirstTick.value = false
|
|
133
|
+
})
|
|
134
|
+
}
|
|
113
135
|
await sleep(0)
|
|
114
136
|
|
|
115
137
|
const pre = container.value?.querySelector('.shiki') as HTMLElement
|
|
@@ -158,8 +180,10 @@ onMounted(() => {
|
|
|
158
180
|
:animate="!isPrintMode"
|
|
159
181
|
:options="{
|
|
160
182
|
globalScale: scale * zoom,
|
|
161
|
-
//
|
|
162
|
-
|
|
183
|
+
// Use duration 0 to skip animation instead of using the animate prop,
|
|
184
|
+
// because moving from non-animated to animated causes issues with
|
|
185
|
+
// new elements. Unfortunately, this causes a flash.
|
|
186
|
+
duration: isFirstTick ? 0 : $props.duration,
|
|
163
187
|
stagger: 1,
|
|
164
188
|
}"
|
|
165
189
|
/>
|
package/constants.ts
CHANGED
|
@@ -84,7 +84,7 @@ useEventListener('keypress', (e) => {
|
|
|
84
84
|
keyboardBuffer.value += String(num)
|
|
85
85
|
|
|
86
86
|
// beyond the number of slides, reset
|
|
87
|
-
if (+keyboardBuffer.value
|
|
87
|
+
if (+keyboardBuffer.value > slides.value.length) {
|
|
88
88
|
keyboardBuffer.value = ''
|
|
89
89
|
return
|
|
90
90
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { getHighlighter } from '#slidev/shiki'
|
|
3
2
|
import { ref, shallowRef } from 'vue'
|
|
4
3
|
import { useIME } from '../composables/useIME'
|
|
5
4
|
|
|
@@ -11,14 +10,21 @@ const { composingContent, onInput, onCompositionEnd } = useIME(content)
|
|
|
11
10
|
|
|
12
11
|
const textareaEl = ref<HTMLTextAreaElement | null>(null)
|
|
13
12
|
|
|
14
|
-
const highlight = shallowRef<
|
|
15
|
-
|
|
13
|
+
const highlight = shallowRef<((code: string) => string) | null>(null)
|
|
14
|
+
import('../setup/shiki').then(async (m) => {
|
|
15
|
+
const { getEagerHighlighter, defaultHighlightOptions } = await m.default()
|
|
16
|
+
const highlighter = await getEagerHighlighter()
|
|
17
|
+
highlight.value = (code: string) => highlighter.codeToHtml(code, {
|
|
18
|
+
...defaultHighlightOptions,
|
|
19
|
+
lang: 'markdown',
|
|
20
|
+
})
|
|
21
|
+
})
|
|
16
22
|
</script>
|
|
17
23
|
|
|
18
24
|
<template>
|
|
19
25
|
<div class="absolute left-3 right-0 inset-y-2 font-mono overflow-x-hidden overflow-y-auto cursor-text">
|
|
20
26
|
<div v-if="highlight" class="relative w-full h-max min-h-full">
|
|
21
|
-
<div class="relative w-full h-max" v-html="`${highlight(composingContent
|
|
27
|
+
<div class="relative w-full h-max" v-html="`${highlight(composingContent)} `" />
|
|
22
28
|
<textarea
|
|
23
29
|
ref="textareaEl" v-model="composingContent" :placeholder="props.placeholder"
|
|
24
30
|
class="absolute inset-0 resize-none text-transparent bg-transparent focus:outline-none caret-black dark:caret-white overflow-y-hidden"
|
|
@@ -52,7 +52,6 @@ const contentStyle = computed(() => ({
|
|
|
52
52
|
...props.contentStyle,
|
|
53
53
|
'height': `${slideHeight.value}px`,
|
|
54
54
|
'width': `${slideWidth.value}px`,
|
|
55
|
-
'transform': `translate(-50%, -50%) scale(${scale.value})`,
|
|
56
55
|
'--slidev-slide-scale': scale.value,
|
|
57
56
|
}))
|
|
58
57
|
|
|
@@ -117,6 +116,8 @@ const snapshot = computed(() => {
|
|
|
117
116
|
}
|
|
118
117
|
|
|
119
118
|
.slidev-slide-content {
|
|
119
|
+
--slidev-slide-container-scale: var(--slidev-slide-scale);
|
|
120
|
+
transform: translate(-50%, -50%) scale(var(--slidev-slide-scale));
|
|
120
121
|
@apply absolute left-1/2 top-1/2 overflow-hidden bg-main;
|
|
121
122
|
}
|
|
122
123
|
</style>
|
|
@@ -32,19 +32,9 @@ provideLocal(injectionRenderContext, ref(props.renderContext))
|
|
|
32
32
|
provideLocal(injectionClicksContext, toRef(props, 'clicksContext'))
|
|
33
33
|
provideLocal(injectionSlideZoom, zoom)
|
|
34
34
|
|
|
35
|
-
const zoomStyle = computed(() => {
|
|
36
|
-
return zoom.value === 1
|
|
37
|
-
? undefined
|
|
38
|
-
: {
|
|
39
|
-
width: `${100 / zoom.value}%`,
|
|
40
|
-
height: `${100 / zoom.value}%`,
|
|
41
|
-
transformOrigin: 'top left',
|
|
42
|
-
transform: `scale(${zoom.value})`,
|
|
43
|
-
}
|
|
44
|
-
})
|
|
45
35
|
const style = computed<CSSProperties>(() => ({
|
|
46
|
-
...zoomStyle.value,
|
|
47
36
|
'user-select': configs.selectable ? undefined : 'none',
|
|
37
|
+
'--slidev-slide-zoom-scale': zoom.value === 1 ? undefined : zoom.value,
|
|
48
38
|
}))
|
|
49
39
|
</script>
|
|
50
40
|
|
|
@@ -69,5 +59,14 @@ const style = computed<CSSProperties>(() => ({
|
|
|
69
59
|
.slidev-page {
|
|
70
60
|
position: absolute;
|
|
71
61
|
inset: 0;
|
|
62
|
+
|
|
63
|
+
/* Zoom handling */
|
|
64
|
+
--slidev-slide-zoom-scale: 1;
|
|
65
|
+
width: calc(100% / var(--slidev-slide-zoom-scale));
|
|
66
|
+
height: calc(100% / var(--slidev-slide-zoom-scale));
|
|
67
|
+
transform-origin: top left;
|
|
68
|
+
transform: scale(var(--slidev-slide-zoom-scale));
|
|
69
|
+
/* slide scale = container scale * zoom scale */
|
|
70
|
+
--slidev-slide-scale: calc(var(--slidev-slide-container-scale) * var(--slidev-slide-zoom-scale));
|
|
72
71
|
}
|
|
73
72
|
</style>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slidev/client",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "52.
|
|
4
|
+
"version": "52.9.0",
|
|
5
5
|
"description": "Presentation slides for developers",
|
|
6
6
|
"author": "Anthony Fu <anthonyfu117@hotmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -38,10 +38,11 @@
|
|
|
38
38
|
"@slidev/rough-notation": "^0.1.0",
|
|
39
39
|
"@typescript/ata": "^0.9.8",
|
|
40
40
|
"@unhead/vue": "^2.0.19",
|
|
41
|
-
"@unocss/reset": "^66.5.
|
|
41
|
+
"@unocss/reset": "^66.5.5",
|
|
42
42
|
"@vueuse/core": "^14.0.0",
|
|
43
43
|
"@vueuse/math": "^14.0.0",
|
|
44
44
|
"@vueuse/motion": "^3.0.3",
|
|
45
|
+
"ansis": "^4.2.0",
|
|
45
46
|
"drauu": "^0.4.3",
|
|
46
47
|
"file-saver": "^2.0.5",
|
|
47
48
|
"floating-vue": "^5.2.2",
|
|
@@ -57,12 +58,12 @@
|
|
|
57
58
|
"shiki": "^3.15.0",
|
|
58
59
|
"shiki-magic-move": "^1.2.1",
|
|
59
60
|
"typescript": "^5.9.3",
|
|
60
|
-
"unocss": "^66.5.
|
|
61
|
-
"vue": "^3.5.
|
|
61
|
+
"unocss": "^66.5.5",
|
|
62
|
+
"vue": "^3.5.24",
|
|
62
63
|
"vue-router": "^4.6.3",
|
|
63
64
|
"yaml": "^2.8.1",
|
|
64
|
-
"@slidev/parser": "52.
|
|
65
|
-
"@slidev/types": "52.
|
|
65
|
+
"@slidev/parser": "52.9.0",
|
|
66
|
+
"@slidev/types": "52.9.0"
|
|
66
67
|
},
|
|
67
68
|
"devDependencies": {
|
|
68
69
|
"vite": "^7.2.2"
|
package/setup/code-runners.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CodeRunner, CodeRunnerOutput, CodeRunnerOutputs, CodeRunnerOutputText } from '@slidev/types'
|
|
2
|
+
import type { CodeToHastOptions } from 'shiki'
|
|
2
3
|
import type ts from 'typescript'
|
|
3
|
-
|
|
4
4
|
import deps from '#slidev/monaco-run-deps'
|
|
5
5
|
import setups from '#slidev/setups/code-runners'
|
|
6
6
|
import { createSingletonPromise } from '@antfu/utils'
|
|
@@ -15,8 +15,16 @@ export default createSingletonPromise(async () => {
|
|
|
15
15
|
ts: runTypeScript,
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
const {
|
|
19
|
-
|
|
18
|
+
const { defaultHighlightOptions, getEagerHighlighter } = await (await import('./shiki')).default()
|
|
19
|
+
|
|
20
|
+
const highlighter = await getEagerHighlighter()
|
|
21
|
+
const highlight = (code: string, lang: string, options?: Partial<CodeToHastOptions>) => {
|
|
22
|
+
return highlighter.codeToHtml(code, {
|
|
23
|
+
...defaultHighlightOptions,
|
|
24
|
+
lang,
|
|
25
|
+
...options,
|
|
26
|
+
})
|
|
27
|
+
}
|
|
20
28
|
|
|
21
29
|
const run = async (code: string, lang: string, options: Record<string, unknown>): Promise<CodeRunnerOutputs> => {
|
|
22
30
|
try {
|
package/setup/monaco.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { MonacoSetupReturn } from '@slidev/types'
|
|
|
2
2
|
import configs from '#slidev/configs'
|
|
3
3
|
import setups from '#slidev/setups/monaco'
|
|
4
4
|
import { createSingletonPromise } from '@antfu/utils'
|
|
5
|
+
import { shikiToMonaco } from '@shikijs/monaco'
|
|
5
6
|
import { setupTypeAcquisition } from '@typescript/ata'
|
|
6
7
|
import * as monaco from 'monaco-editor'
|
|
7
8
|
|
|
@@ -83,14 +84,16 @@ const setup = createSingletonPromise(async () => {
|
|
|
83
84
|
})
|
|
84
85
|
: () => { }
|
|
85
86
|
|
|
87
|
+
const { getEagerHighlighter, languageNames, themeOption } = await (await import('./shiki')).default()
|
|
88
|
+
|
|
86
89
|
monaco.languages.register({ id: 'vue' })
|
|
87
90
|
monaco.languages.register({ id: 'html' })
|
|
88
91
|
monaco.languages.register({ id: 'css' })
|
|
89
92
|
monaco.languages.register({ id: 'typescript' })
|
|
90
93
|
monaco.languages.register({ id: 'javascript' })
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
+
for (const lang of languageNames) {
|
|
95
|
+
monaco.languages.register({ id: lang })
|
|
96
|
+
}
|
|
94
97
|
|
|
95
98
|
const editorOptions: MonacoSetupReturn['editorOptions'] & object = {}
|
|
96
99
|
for (const setup of setups) {
|
|
@@ -111,21 +114,18 @@ const setup = createSingletonPromise(async () => {
|
|
|
111
114
|
})
|
|
112
115
|
|
|
113
116
|
// Use Shiki to highlight Monaco
|
|
117
|
+
const highlighter = await getEagerHighlighter()
|
|
114
118
|
shikiToMonaco(highlighter, monaco)
|
|
115
|
-
if (typeof
|
|
116
|
-
monaco.editor.setTheme(
|
|
119
|
+
if (typeof themeOption === 'string') {
|
|
120
|
+
monaco.editor.setTheme(themeOption)
|
|
117
121
|
}
|
|
118
122
|
else {
|
|
119
123
|
watchEffect(() => {
|
|
120
124
|
monaco.editor.setTheme(isDark.value
|
|
121
|
-
?
|
|
122
|
-
:
|
|
125
|
+
? themeOption.dark || 'vitesse-dark'
|
|
126
|
+
: themeOption.light || 'vitesse-light')
|
|
123
127
|
})
|
|
124
128
|
}
|
|
125
|
-
// Register all languages, otherwise Monaco will not highlight them
|
|
126
|
-
for (const lang of languages) {
|
|
127
|
-
monaco.languages.register({ id: lang })
|
|
128
|
-
}
|
|
129
129
|
|
|
130
130
|
return {
|
|
131
131
|
monaco,
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// This module also runs in the Node.js environment
|
|
2
|
+
|
|
3
|
+
import type { ResolvedSlidevUtils, ShikiContext, ShikiSetupReturn } from '@slidev/types'
|
|
4
|
+
import type { LanguageInput, ThemeInput, ThemeRegistrationAny } from 'shiki'
|
|
5
|
+
import { objectMap } from '@antfu/utils'
|
|
6
|
+
import { red, yellow } from 'ansis'
|
|
7
|
+
import { bundledLanguages, bundledThemes } from 'shiki'
|
|
8
|
+
|
|
9
|
+
export const shikiContext: ShikiContext = {
|
|
10
|
+
/** @deprecated */
|
|
11
|
+
loadTheme() {
|
|
12
|
+
throw new Error('`loadTheme` is no longer supported.')
|
|
13
|
+
},
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function resolveShikiOptions(options: (ShikiSetupReturn | void)[]) {
|
|
17
|
+
const mergedOptions: Record<string, any> = Object.assign({}, ...options)
|
|
18
|
+
|
|
19
|
+
if ('theme' in mergedOptions && 'themes' in mergedOptions)
|
|
20
|
+
delete mergedOptions.theme
|
|
21
|
+
|
|
22
|
+
// Rename theme to themes when provided in multiple themes format, but exclude when it's a theme object.
|
|
23
|
+
if (mergedOptions.theme && typeof mergedOptions.theme !== 'string' && !mergedOptions.theme.name && !mergedOptions.theme.tokenColors) {
|
|
24
|
+
mergedOptions.themes = mergedOptions.theme
|
|
25
|
+
delete mergedOptions.theme
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// No theme at all, apply the default
|
|
29
|
+
if (!mergedOptions.theme && !mergedOptions.themes) {
|
|
30
|
+
mergedOptions.themes = {
|
|
31
|
+
dark: 'vitesse-dark',
|
|
32
|
+
light: 'vitesse-light',
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (mergedOptions.themes)
|
|
37
|
+
mergedOptions.defaultColor = false
|
|
38
|
+
|
|
39
|
+
const themeOption = extractThemeName(mergedOptions.theme) || extractThemeNames(mergedOptions.themes || {})
|
|
40
|
+
const themeNames = typeof themeOption === 'string' ? [themeOption] : Object.values(themeOption)
|
|
41
|
+
|
|
42
|
+
const themeInput: Record<string, ThemeInput> = Object.assign({}, bundledThemes)
|
|
43
|
+
if (typeof mergedOptions.theme === 'object' && mergedOptions.theme?.name) {
|
|
44
|
+
themeInput[mergedOptions.theme.name] = mergedOptions.theme
|
|
45
|
+
}
|
|
46
|
+
if (mergedOptions.themes) {
|
|
47
|
+
for (const theme of Object.values<ThemeRegistrationAny | string>(mergedOptions.themes)) {
|
|
48
|
+
if (typeof theme === 'object' && theme?.name) {
|
|
49
|
+
themeInput[theme.name] = theme
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const languageNames = new Set<string>(['markdown', 'vue', 'javascript', 'typescript', 'html', 'css'])
|
|
55
|
+
const languageInput: Record<string, LanguageInput> = Object.assign({}, bundledLanguages)
|
|
56
|
+
for (const option of options) {
|
|
57
|
+
const langs = option?.langs
|
|
58
|
+
if (langs == null)
|
|
59
|
+
continue
|
|
60
|
+
if (Array.isArray(langs)) {
|
|
61
|
+
for (const lang of langs.flat()) {
|
|
62
|
+
if (typeof lang === 'function') {
|
|
63
|
+
console.error(red('[slidev] `langs` option returned by setup/shiki.ts cannot be an array containing functions. Please use the record format (`{ [name]: () => {...} }`) instead.'))
|
|
64
|
+
}
|
|
65
|
+
else if (typeof lang === 'string') {
|
|
66
|
+
// a name of a Shiki built-in language
|
|
67
|
+
// which can be loaded on demand without overhead, so all built-in languages are available.
|
|
68
|
+
// Only need to include them explicitly in browser environment.
|
|
69
|
+
languageNames.add(lang)
|
|
70
|
+
}
|
|
71
|
+
else if (lang.name) {
|
|
72
|
+
// a custom grammar object
|
|
73
|
+
languageNames.add(lang.name)
|
|
74
|
+
languageInput[lang.name] = lang
|
|
75
|
+
for (const alias of lang.aliases || []) {
|
|
76
|
+
languageNames.add(alias)
|
|
77
|
+
languageInput[alias] = lang
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
console.error(red('[slidev] Invalid lang option in shiki setup:'), lang)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
else if (typeof langs === 'object') {
|
|
86
|
+
// a map from name to loader or grammar object
|
|
87
|
+
for (const name of Object.keys(langs))
|
|
88
|
+
languageNames.add(name)
|
|
89
|
+
Object.assign(languageInput, langs)
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
console.error(red('[slidev] Invalid langs option in shiki setup:'), langs)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
options: mergedOptions as ResolvedSlidevUtils['shikiOptions'],
|
|
98
|
+
themeOption,
|
|
99
|
+
themeNames,
|
|
100
|
+
themeInput,
|
|
101
|
+
languageNames,
|
|
102
|
+
languageInput,
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function extractThemeName(theme?: ThemeRegistrationAny | string): string | undefined {
|
|
107
|
+
if (!theme)
|
|
108
|
+
return undefined
|
|
109
|
+
if (typeof theme === 'string')
|
|
110
|
+
return theme
|
|
111
|
+
if (!theme.name)
|
|
112
|
+
console.warn(yellow('[slidev] Theme'), theme, yellow('does not have a name, which may cause issues.'))
|
|
113
|
+
return theme.name
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function extractThemeNames(themes?: Record<string, ThemeRegistrationAny | string>): Record<string, string> {
|
|
117
|
+
if (!themes)
|
|
118
|
+
return {}
|
|
119
|
+
return objectMap(themes, (key, theme) => {
|
|
120
|
+
const name = extractThemeName(theme)
|
|
121
|
+
if (!name)
|
|
122
|
+
return undefined
|
|
123
|
+
return [key, name]
|
|
124
|
+
})
|
|
125
|
+
}
|
package/setup/shiki.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import setups from '#slidev/setups/shiki'
|
|
2
|
+
import { createSingletonPromise } from '@antfu/utils'
|
|
3
|
+
import { createJavaScriptRegexEngine } from '@shikijs/engine-javascript'
|
|
4
|
+
import { createdBundledHighlighter, createSingletonShorthands } from 'shiki/core'
|
|
5
|
+
import { resolveShikiOptions, shikiContext } from './shiki-options'
|
|
6
|
+
|
|
7
|
+
export default createSingletonPromise(async () => {
|
|
8
|
+
const { options, languageNames, languageInput, themeOption, themeNames, themeInput } = resolveShikiOptions(await Promise.all(setups.map(setup => setup(shikiContext))))
|
|
9
|
+
|
|
10
|
+
const createHighlighter = createdBundledHighlighter<string, string>({
|
|
11
|
+
engine: createJavaScriptRegexEngine,
|
|
12
|
+
langs: languageInput,
|
|
13
|
+
themes: themeInput,
|
|
14
|
+
})
|
|
15
|
+
const shorthands = createSingletonShorthands(createHighlighter)
|
|
16
|
+
const getEagerHighlighter = createSingletonPromise(() => shorthands.getSingletonHighlighter({
|
|
17
|
+
...options,
|
|
18
|
+
langs: [...languageNames],
|
|
19
|
+
themes: themeNames,
|
|
20
|
+
}))
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
defaultHighlightOptions: options,
|
|
24
|
+
getEagerHighlighter,
|
|
25
|
+
shorthands,
|
|
26
|
+
languageNames,
|
|
27
|
+
themeNames,
|
|
28
|
+
themeOption,
|
|
29
|
+
}
|
|
30
|
+
})
|