@slidev/client 0.48.0-beta.15 → 0.48.0-beta.17

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.
@@ -56,8 +56,12 @@ onUnmounted(() => {
56
56
  clicks!.unregister(id)
57
57
  })
58
58
 
59
+ watchEffect(() => {
60
+ el.value?.classList.toggle('slidev-code-line-numbers', props.lines)
61
+ })
62
+
59
63
  onMounted(() => {
60
- if (!clicks || clicks.disabled)
64
+ if (!clicks || clicks.disabled || !props.ranges?.length)
61
65
  return
62
66
 
63
67
  const { start, end, delta } = clicks.resolve(props.at, props.ranges.length - 1)
@@ -121,9 +125,12 @@ function copyCode() {
121
125
 
122
126
  <template>
123
127
  <div
124
- ref="el" class="slidev-code-wrapper relative group" :class="{
128
+ ref="el"
129
+ class="slidev-code-wrapper relative group"
130
+ :class="{
125
131
  'slidev-code-line-numbers': props.lines,
126
- }" :style="{
132
+ }"
133
+ :style="{
127
134
  'max-height': props.maxHeight,
128
135
  'overflow-y': props.maxHeight ? 'scroll' : undefined,
129
136
  '--start': props.startLine,
@@ -12,11 +12,10 @@ Learn more: https://sli.dev/guide/syntax.html#monaco-editor
12
12
  -->
13
13
 
14
14
  <script setup lang="ts">
15
- import { computed, onMounted, ref } from 'vue'
16
- import { useEventListener } from '@vueuse/core'
17
15
  import type * as monaco from 'monaco-editor'
18
- import { decompressFromBase64 } from 'lz-string'
19
- import { isDark } from '../logic/dark'
16
+ import { computed, nextTick, onMounted, ref } from 'vue'
17
+ import { debounce } from '@antfu/utils'
18
+ import lz from 'lz-string'
20
19
  import { makeId } from '../logic/utils'
21
20
 
22
21
  const props = withDefaults(defineProps<{
@@ -25,109 +24,127 @@ const props = withDefaults(defineProps<{
25
24
  lang?: string
26
25
  readonly?: boolean
27
26
  lineNumbers?: 'on' | 'off' | 'relative' | 'interval'
28
- height?: number | string
27
+ height?: number | string // Posible values: 'initial', 'auto', '100%', '200px', etc.
29
28
  editorOptions?: monaco.editor.IEditorOptions
29
+ ata?: boolean
30
30
  }>(), {
31
31
  codeLz: '',
32
32
  lang: 'typescript',
33
33
  readonly: false,
34
34
  lineNumbers: 'off',
35
- height: 'auto',
35
+ height: 'initial',
36
+ ata: true,
36
37
  })
37
38
 
38
- const id = makeId()
39
- const code = ref(decompressFromBase64(props.codeLz))
40
- const diff = ref(props.diffLz ? decompressFromBase64(props.diffLz) : null)
41
- const lineHeight = +(getComputedStyle(document.body).getPropertyValue('--slidev-code-line-height') || '18').replace('px', '') || 18
42
- const editorHeight = ref(0)
43
- const calculatedHeight = computed(() => code.value.split(/\r?\n/g).length * lineHeight)
44
- const height = computed(() => {
45
- return props.height === 'auto' ? `${Math.max(calculatedHeight.value, editorHeight.value) + 20}px` : props.height
46
- })
47
-
48
- const iframe = ref<HTMLIFrameElement>()
39
+ const code = lz.decompressFromBase64(props.codeLz).trimEnd()
40
+ const diff = props.diffLz && lz.decompressFromBase64(props.diffLz).trimEnd()
49
41
 
50
- const cssVars = [
51
- '--slidev-code-font-size',
52
- '--slidev-code-font-family',
53
- '--slidev-code-background',
54
- '--slidev-code-line-height',
55
- '--slidev-code-padding',
56
- '--slidev-code-margin',
57
- '--slidev-code-radius',
58
- ]
59
-
60
- function getStyleObject(el: Element) {
61
- const object: Record<string, string> = {}
62
- const style = getComputedStyle(el)
63
- for (const v of cssVars)
64
- object[v] = style.getPropertyValue(v)
65
- return object
42
+ const langMap: Record<string, string> = {
43
+ ts: 'typescript',
44
+ js: 'javascript',
66
45
  }
46
+ const lang = langMap[props.lang] ?? props.lang
47
+ const extMap: Record<string, string> = {
48
+ typescript: 'mts',
49
+ javascript: 'mjs',
50
+ ts: 'mts',
51
+ js: 'mjs',
52
+ }
53
+ const ext = extMap[props.lang] ?? props.lang
67
54
 
68
- onMounted(() => {
69
- const frame = iframe.value!
70
- frame.setAttribute('sandbox', [
71
- 'allow-forms',
72
- 'allow-modals',
73
- 'allow-pointer-lock',
74
- 'allow-popups',
75
- 'allow-same-origin',
76
- 'allow-scripts',
77
- 'allow-top-navigation-by-user-activation',
78
- ].join(' '))
79
-
80
- let src = __DEV__
81
- ? `${location.origin}${__SLIDEV_CLIENT_ROOT__}/`
82
- : import.meta.env.BASE_URL
83
- src += `iframes/monaco/index.html?id=${id}&lineNumbers=${props.lineNumbers}&lang=${props.lang}`
84
- if (diff.value)
85
- src += '&diff=1'
86
- frame.src = src
55
+ const outer = ref<HTMLDivElement>()
56
+ const container = ref<HTMLDivElement>()
87
57
 
88
- frame.style.backgroundColor = 'transparent'
58
+ const contentHeight = ref(0)
59
+ const initialHeight = ref<number>()
60
+ const height = computed(() => {
61
+ if (props.height === 'auto')
62
+ return `${contentHeight.value}px`
63
+ if (props.height === 'initial')
64
+ return `${initialHeight.value}px`
65
+ return props.height
89
66
  })
90
67
 
91
- function post(payload: any) {
92
- iframe.value?.contentWindow?.postMessage(
93
- JSON.stringify({
94
- type: 'slidev-monaco',
95
- data: payload,
96
- id,
97
- }),
98
- location.origin,
99
- )
100
- }
68
+ onMounted(async () => {
69
+ // Lazy load monaco, so it will be bundled in async chunk
70
+ const { default: setup } = await import('../setup/monaco')
71
+ const { ata, monaco } = await setup()
72
+ const model = monaco.editor.createModel(code, lang, monaco.Uri.parse(`file:///${makeId()}.${ext}`))
73
+ const commonOptions = {
74
+ automaticLayout: true,
75
+ readOnly: props.readonly,
76
+ lineNumbers: props.lineNumbers,
77
+ minimap: { enabled: false },
78
+ overviewRulerBorder: false,
79
+ overviewRulerLanes: 0,
80
+ padding: { top: 10, bottom: 10 },
81
+ lineNumbersMinChars: 3,
82
+ bracketPairColorization: { enabled: false },
83
+ tabSize: 2,
84
+ fontSize: 11.5,
85
+ fontFamily: 'var(--slidev-code-font-family)',
86
+ scrollBeyondLastLine: false,
87
+ ...props.editorOptions,
88
+ } satisfies monaco.editor.IStandaloneEditorConstructionOptions & monaco.editor.IDiffEditorConstructionOptions
101
89
 
102
- useEventListener(window, 'message', ({ data: payload }) => {
103
- if (payload.id !== id)
104
- return
105
- if (payload.type === 'slidev-monaco-loaded') {
106
- if (iframe.value) {
107
- post({
108
- code: code.value,
109
- diff: diff.value,
110
- lang: props.lang,
111
- readonly: props.readonly,
112
- lineNumbers: props.lineNumbers,
113
- editorOptions: props.editorOptions,
114
- dark: isDark.value,
115
- style: Object.entries(getStyleObject(iframe.value)).map(([k, v]) => `${k}: ${v};`).join(''),
116
- })
90
+ let editableEditor: monaco.editor.IStandaloneCodeEditor
91
+ if (diff) {
92
+ const diffModel = monaco.editor.createModel(diff, lang, monaco.Uri.parse(`file:///${makeId()}.${ext}`))
93
+ const editor = monaco.editor.createDiffEditor(container.value!, {
94
+ renderOverviewRuler: false,
95
+ ...commonOptions,
96
+ })
97
+ editor.setModel({
98
+ original: model,
99
+ modified: diffModel,
100
+ })
101
+ const originalEditor = editor.getOriginalEditor()
102
+ const modifiedEditor = editor.getModifiedEditor()
103
+ const onContentSizeChange = () => {
104
+ const newHeight = Math.max(originalEditor.getContentHeight(), modifiedEditor.getContentHeight()) + 4
105
+ initialHeight.value ??= newHeight
106
+ contentHeight.value = newHeight
107
+ nextTick(() => editor.layout())
108
+ }
109
+ originalEditor.onDidContentSizeChange(onContentSizeChange)
110
+ modifiedEditor.onDidContentSizeChange(onContentSizeChange)
111
+ editableEditor = modifiedEditor
112
+ }
113
+ else {
114
+ const editor = monaco.editor.create(container.value!, {
115
+ model,
116
+ lineDecorationsWidth: 0,
117
+ ...commonOptions,
118
+ })
119
+ editor.onDidContentSizeChange((e) => {
120
+ const newHeight = e.contentHeight + 4
121
+ initialHeight.value ??= newHeight
122
+ contentHeight.value = newHeight
123
+ nextTick(() => editableEditor.layout())
124
+ })
125
+ editableEditor = editor
126
+ }
127
+ if (props.ata) {
128
+ ata(editableEditor.getValue())
129
+ editableEditor.onDidChangeModelContent(debounce(1000, () => {
130
+ ata(editableEditor.getValue())
131
+ }))
132
+ }
133
+ const originalLayoutContentWidget = editableEditor.layoutContentWidget.bind(editableEditor)
134
+ editableEditor.layoutContentWidget = (widget: any) => {
135
+ originalLayoutContentWidget(widget)
136
+ const id = widget.getId()
137
+ if (id === 'editor.contrib.resizableContentHoverWidget') {
138
+ widget._resizableNode.domNode.style.transform = widget._positionPreference === 1
139
+ ? /* ABOVE */ `translateY(calc(100% * (var(--slidev-slide-scale) - 1)))`
140
+ : /* BELOW */ `` // reset
117
141
  }
118
- return
119
142
  }
120
- if (payload.type !== 'slidev-monaco')
121
- return
122
- if (payload.data?.height)
123
- editorHeight.value = payload.data?.height
124
- if (payload?.data?.code && code.value !== payload.data.code)
125
- code.value = payload.data.code
126
- if (payload?.data?.diff && diff.value !== payload.data.diff)
127
- diff.value = payload.data.diff
128
143
  })
129
144
  </script>
130
145
 
131
146
  <template>
132
- <iframe ref="iframe" class="text-base w-full rounded" :style="{ height }" />
147
+ <div ref="outer" class="slidev-monaco-container" :style="{ height }">
148
+ <div ref="container" class="absolute inset-0.5" />
149
+ </div>
133
150
  </template>
@@ -2,7 +2,7 @@
2
2
  import { ShikiMagicMovePrecompiled } from 'shiki-magic-move/vue'
3
3
  import type { KeyedTokensInfo } from 'shiki-magic-move/types'
4
4
  import { onMounted, onUnmounted, ref, watchEffect } from 'vue'
5
- import { decompressFromBase64 } from 'lz-string'
5
+ import lz from 'lz-string'
6
6
  import { useSlideContext } from '../context'
7
7
  import { makeId } from '../logic/utils'
8
8
 
@@ -13,7 +13,7 @@ const props = defineProps<{
13
13
  at?: string | number
14
14
  }>()
15
15
 
16
- const steps = JSON.parse(decompressFromBase64(props.stepsLz)) as KeyedTokensInfo[]
16
+ const steps = JSON.parse(lz.decompressFromBase64(props.stepsLz)) as KeyedTokensInfo[]
17
17
  const { $clicksContext: clicks, $scale: scale } = useSlideContext()
18
18
  const id = makeId()
19
19
  const index = ref(0)
package/builtin/Tweet.vue CHANGED
@@ -7,9 +7,8 @@ Usage:
7
7
  -->
8
8
 
9
9
  <script setup lang="ts">
10
- import { getCurrentInstance, onMounted, ref } from 'vue'
10
+ import { onMounted, ref } from 'vue'
11
11
  import { isDark } from '../logic/dark'
12
- import { useTweetScript } from '../composables/useTweetScript'
13
12
 
14
13
  const props = defineProps<{
15
14
  id: string | number
@@ -20,11 +19,10 @@ const props = defineProps<{
20
19
 
21
20
  const tweet = ref<HTMLElement | null>()
22
21
 
23
- const vm = getCurrentInstance()!
24
22
  const loaded = ref(false)
25
23
  const tweetNotFound = ref(false)
26
24
 
27
- async function create() {
25
+ onMounted(async () => {
28
26
  // @ts-expect-error global
29
27
  const element = await window.twttr.widgets.createTweet(
30
28
  props.id.toString(),
@@ -38,13 +36,7 @@ async function create() {
38
36
  loaded.value = true
39
37
  if (element === undefined)
40
38
  tweetNotFound.value = true
41
- }
42
-
43
- // @ts-expect-error global
44
- if (window?.twttr?.widgets)
45
- onMounted(create)
46
- else
47
- useTweetScript(vm, create)
39
+ })
48
40
  </script>
49
41
 
50
42
  <template>
@@ -50,6 +50,6 @@ provideLocal(injectionSlideScale, scale)
50
50
  }
51
51
 
52
52
  .print-slide-container {
53
- @apply relative overflow-hidden break-after-page;
53
+ @apply relative overflow-hidden break-after-page translate-0;
54
54
  }
55
55
  </style>
package/logic/nav.ts CHANGED
@@ -135,16 +135,13 @@ export function go(page: number | string, clicks?: number) {
135
135
  export function useSwipeControls(root: Ref<HTMLElement | undefined>) {
136
136
  const swipeBegin = ref(0)
137
137
  const { direction, distanceX, distanceY } = usePointerSwipe(root, {
138
- onSwipeStart(e) {
139
- if (e.pointerType !== 'touch')
140
- return
138
+ pointerTypes: ['touch'],
139
+ onSwipeStart() {
141
140
  if (isDrawing.value)
142
141
  return
143
142
  swipeBegin.value = timestamp()
144
143
  },
145
- onSwipeEnd(e) {
146
- if (e.pointerType !== 'touch')
147
- return
144
+ onSwipeEnd() {
148
145
  if (!swipeBegin.value)
149
146
  return
150
147
  if (isDrawing.value)
@@ -1,5 +1,5 @@
1
1
  import mermaid from 'mermaid/dist/mermaid.esm.mjs'
2
- import { decompressFromBase64 } from 'lz-string'
2
+ import lz from 'lz-string'
3
3
  import { clearUndefined } from '@antfu/utils'
4
4
  import setupMermaid from '../setup/mermaid'
5
5
  import { makeId } from '../logic/utils'
@@ -20,7 +20,7 @@ export async function renderMermaid(lzEncoded: string, options: any) {
20
20
  ...clearUndefined(setupMermaid() || {}),
21
21
  ...clearUndefined(options),
22
22
  })
23
- const code = decompressFromBase64(lzEncoded)
23
+ const code = lz.decompressFromBase64(lzEncoded)
24
24
  const id = makeId()
25
25
  const { svg } = await mermaid.render(id, code)
26
26
  cache.set(key, svg)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@slidev/client",
3
3
  "type": "module",
4
- "version": "0.48.0-beta.15",
4
+ "version": "0.48.0-beta.17",
5
5
  "description": "Presentation slides for developers",
6
6
  "author": "antfu <anthonyfu117@hotmail.com>",
7
7
  "license": "MIT",
@@ -29,8 +29,10 @@
29
29
  "@antfu/utils": "^0.7.7",
30
30
  "@iconify-json/carbon": "^1.1.30",
31
31
  "@iconify-json/ph": "^1.1.11",
32
+ "@shikijs/monaco": "^1.1.7",
32
33
  "@shikijs/vitepress-twoslash": "^1.1.7",
33
34
  "@slidev/rough-notation": "^0.1.0",
35
+ "@typescript/ata": "^0.9.4",
34
36
  "@unhead/vue": "^1.8.10",
35
37
  "@unocss/reset": "^0.58.5",
36
38
  "@vueuse/core": "^10.8.0",
@@ -46,16 +48,18 @@
46
48
  "katex": "^0.16.9",
47
49
  "lz-string": "^1.5.0",
48
50
  "mermaid": "^10.8.0",
49
- "monaco-editor": "^0.37.1",
51
+ "monaco-editor": "^0.46.0",
52
+ "nanoid": "^5.0.6",
50
53
  "prettier": "^3.2.5",
51
54
  "recordrtc": "^5.6.2",
52
55
  "resolve": "^1.22.8",
56
+ "shiki": "^1.1.7",
53
57
  "shiki-magic-move": "^0.1.0",
54
58
  "unocss": "^0.58.5",
55
59
  "vue": "^3.4.20",
56
60
  "vue-router": "^4.3.0",
57
- "@slidev/types": "0.48.0-beta.15",
58
- "@slidev/parser": "0.48.0-beta.15"
61
+ "@slidev/parser": "0.48.0-beta.17",
62
+ "@slidev/types": "0.48.0-beta.17"
59
63
  },
60
64
  "devDependencies": {
61
65
  "vite": "^5.1.4"
package/setup/monaco.ts CHANGED
@@ -1,52 +1,114 @@
1
- import { getCurrentInstance, onMounted } from 'vue'
2
- import * as monaco from 'monaco-editor'
3
1
  import { createSingletonPromise } from '@antfu/utils'
4
2
  import type { MonacoSetupReturn } from '@slidev/types'
3
+ import * as monaco from 'monaco-editor'
4
+ import { watchEffect } from 'vue'
5
+ import { setupTypeAcquisition } from '@typescript/ata'
6
+ import ts from 'typescript'
7
+
8
+ import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
9
+ import CssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker'
10
+ import HtmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker'
11
+ import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'
12
+ import TsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'
13
+
14
+ // @ts-expect-error missing types
15
+ import { ContextViewService } from 'monaco-editor/esm/vs/platform/contextview/browser/contextViewService'
16
+
17
+ // @ts-expect-error missing types
18
+ import { SyncDescriptor } from 'monaco-editor/esm/vs/platform/instantiation/common/descriptors'
19
+
20
+ // @ts-expect-error missing types
21
+ import { StandaloneServices } from 'monaco-editor/esm/vs/editor/standalone/browser/standaloneServices'
22
+
23
+ import { isDark } from '../logic/dark'
24
+ import configs from '#slidev/configs'
5
25
 
6
26
  /* __imports__ */
27
+ window.MonacoEnvironment = {
28
+ getWorker(_, label) {
29
+ if (label === 'json')
30
+ return new JsonWorker()
31
+ if (label === 'css' || label === 'scss' || label === 'less')
32
+ return new CssWorker()
33
+ if (label === 'html' || label === 'handlebars' || label === 'razor')
34
+ return new HtmlWorker()
35
+ if (label === 'typescript' || label === 'javascript')
36
+ return new TsWorker()
37
+ return new EditorWorker()
38
+ },
39
+ }
40
+
41
+ class ContextViewService2 extends ContextViewService {
42
+ showContextView(...args: any) {
43
+ super.showContextView(...args)
44
+ // @ts-expect-error missing types
45
+ const contextView = this.contextView.view as HTMLElement
46
+ contextView.style.left = `calc(${contextView.style.left} / var(--slidev-slide-scale))`
47
+ contextView.style.top = `calc(${contextView.style.top} / var(--slidev-slide-scale))`
48
+ // Reset the scale to 1. Otherwise, the sub-menu will be in the wrong position.
49
+ contextView.style.transform = `scale(calc(1 / var(--slidev-slide-scale)))`
50
+ contextView.style.transformOrigin = '0 0'
51
+ }
52
+ }
7
53
 
8
54
  const setup = createSingletonPromise(async () => {
9
- monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
10
- ...monaco.languages.typescript.typescriptDefaults.getCompilerOptions(),
11
- noUnusedLocals: false,
12
- noUnusedParameters: false,
13
- allowUnreachableCode: true,
14
- allowUnusedLabels: true,
55
+ // Initialize services first, otherwise we can't override them.
56
+ StandaloneServices.initialize({
57
+ contextViewService: new SyncDescriptor(ContextViewService2, [], true),
58
+ })
59
+
60
+ const defaults = monaco.languages.typescript.typescriptDefaults
61
+
62
+ defaults.setCompilerOptions({
63
+ ...defaults.getCompilerOptions(),
15
64
  strict: true,
65
+ moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
66
+ module: monaco.languages.typescript.ModuleKind.ESNext,
16
67
  })
17
68
 
18
- await Promise.all([
19
- // load workers
20
- (async () => {
21
- const [
22
- { default: EditorWorker },
23
- { default: JsonWorker },
24
- { default: CssWorker },
25
- { default: HtmlWorker },
26
- { default: TsWorker },
27
- ] = await Promise.all([
28
- import('monaco-editor/esm/vs/editor/editor.worker?worker'),
29
- import('monaco-editor/esm/vs/language/json/json.worker?worker'),
30
- import('monaco-editor/esm/vs/language/css/css.worker?worker'),
31
- import('monaco-editor/esm/vs/language/html/html.worker?worker'),
32
- import('monaco-editor/esm/vs/language/typescript/ts.worker?worker'),
33
- ])
34
-
35
- window.MonacoEnvironment = {
36
- getWorker(_: any, label: string) {
37
- if (label === 'json')
38
- return new JsonWorker()
39
- if (label === 'css' || label === 'scss' || label === 'less')
40
- return new CssWorker()
41
- if (label === 'html' || label === 'handlebars' || label === 'razor')
42
- return new HtmlWorker()
43
- if (label === 'typescript' || label === 'javascript')
44
- return new TsWorker()
45
- return new EditorWorker()
69
+ // Load types from server
70
+ import('#slidev/monaco-types')
71
+
72
+ const ata = configs.monacoTypesSource === 'cdn'
73
+ ? setupTypeAcquisition({
74
+ projectName: 'TypeScript Playground',
75
+ typescript: ts as any, // Version mismatch. No problem found so far.
76
+ logger: console,
77
+ delegate: {
78
+ receivedFile: (code: string, path: string) => {
79
+ defaults.addExtraLib(code, `file://${path}`)
80
+ const uri = monaco.Uri.file(path)
81
+ if (monaco.editor.getModel(uri) === null)
82
+ monaco.editor.createModel(code, 'javascript', uri)
83
+ },
84
+ progress: (downloaded: number, total: number) => {
85
+ // eslint-disable-next-line no-console
86
+ console.debug(`[Typescript ATA] ${downloaded} / ${total}`)
46
87
  },
47
- }
48
- })(),
49
- ])
88
+ },
89
+ })
90
+ : () => { }
91
+
92
+ // monaco.languages.register({ id: 'vue' })
93
+ monaco.languages.register({ id: 'typescript' })
94
+ monaco.languages.register({ id: 'javascript' })
95
+
96
+ const { shiki, themes, shikiToMonaco } = await import('#slidev/shiki')
97
+ const highlighter = await shiki
98
+
99
+ // Use Shiki to highlight Monaco
100
+ shikiToMonaco(highlighter, monaco)
101
+
102
+ if (typeof themes === 'string') {
103
+ monaco.editor.setTheme(themes)
104
+ }
105
+ else {
106
+ watchEffect(() => {
107
+ monaco.editor.setTheme(isDark.value
108
+ ? themes.dark || 'vitesse-dark'
109
+ : themes.light || 'vitesse-light')
110
+ })
111
+ }
50
112
 
51
113
  // @ts-expect-error injected in runtime
52
114
  // eslint-disable-next-line unused-imports/no-unused-vars
@@ -56,15 +118,11 @@ const setup = createSingletonPromise(async () => {
56
118
 
57
119
  /* __async_injections__ */
58
120
 
59
- if (getCurrentInstance())
60
- await new Promise<void>(resolve => onMounted(resolve))
61
-
62
121
  return {
63
122
  monaco,
123
+ ata,
64
124
  ...injection_return,
65
125
  }
66
126
  })
67
127
 
68
128
  export default setup
69
-
70
- setup()
package/shim.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- // with unplugin-vue-markdown, markdowns can be treat as Vue components
2
1
  declare module '*.md' {
2
+ // with unplugin-vue-markdown, markdowns can be treat as Vue components
3
3
  import type { ComponentOptions } from 'vue'
4
4
 
5
5
  const component: ComponentOptions
@@ -0,0 +1,27 @@
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
+ }
@@ -1,17 +0,0 @@
1
- import { createSharedComposable, useScriptTag } from '@vueuse/core'
2
- import type { ComponentInternalInstance } from 'vue'
3
- import { onMounted } from 'vue'
4
-
5
- export const useTweetScript = createSharedComposable(
6
- (vm: ComponentInternalInstance, create: () => void) =>
7
- useScriptTag(
8
- 'https://platform.twitter.com/widgets.js',
9
- () => {
10
- if (vm.isMounted)
11
- create()
12
- else
13
- onMounted(create, vm)
14
- },
15
- { async: true },
16
- ),
17
- )
@@ -1,28 +0,0 @@
1
- html,
2
- body,
3
- #container {
4
- padding: 0;
5
- margin: 0;
6
- background: var(--slidev-code-background);
7
- width: 100%;
8
- height: 200%;
9
- }
10
-
11
- #container {
12
- padding: var(--slidev-code-padding);
13
- margin: var(--slidev-code-margin);
14
- border-radius: var(--slidev-code-radius);
15
- }
16
-
17
- .monaco-editor .monaco-hover {
18
- border-radius: var(--slidev-code-radius);
19
- overflow: hidden;
20
- border: none;
21
- outline: none;
22
- }
23
-
24
- .monaco-editor .lines-content,
25
- .monaco-editor .view-line,
26
- .monaco-editor .view-lines {
27
- user-select: none;
28
- }
@@ -1,7 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <body>
4
- <div id="container"></div>
5
- <script type="module" src="./index.ts"></script>
6
- </body>
7
- </html>
@@ -1,260 +0,0 @@
1
- import '/@slidev/styles'
2
- import './index.css'
3
-
4
- import type * as monaco from 'monaco-editor'
5
- import { formatCode } from '../../setup/prettier'
6
- import setupMonaco from '../../setup/monaco'
7
- import '/@slidev/monaco-types'
8
-
9
- const url = new URL(location.href)
10
- const props = {
11
- id: url.searchParams.get('id'),
12
- code: '',
13
- diff: '',
14
- lang: url.searchParams.get('lang') ?? 'typescript',
15
- readonly: false,
16
- lineNumbers: url.searchParams.get('lineNumbers') ?? 'off',
17
- dark: false,
18
- style: '',
19
- editorOptions: {},
20
- }
21
-
22
- const styleObject = document.createElement('style')
23
- let originalEditor: monaco.editor.IStandaloneCodeEditor
24
- let modifiedEditor: monaco.editor.IStandaloneCodeEditor
25
- let format: () => void = () => { }
26
- let update: () => void = () => { }
27
-
28
- document.body.appendChild(styleObject)
29
-
30
- function lang() {
31
- switch (props.lang) {
32
- case 'ts':
33
- case 'tsx':
34
- return 'typescript'
35
- case 'jsx':
36
- case 'js':
37
- return 'javascript'
38
- default:
39
- return props.lang
40
- }
41
- }
42
-
43
- function ext() {
44
- switch (lang()) {
45
- case 'typescript':
46
- return 'ts'
47
- case 'javascript':
48
- return 'js'
49
- default:
50
- return lang()
51
- }
52
- }
53
-
54
- function post(data: any, type = 'slidev-monaco') {
55
- if (window.parent === window)
56
- return
57
-
58
- window.parent.postMessage(
59
- {
60
- type,
61
- id: props.id,
62
- data,
63
- },
64
- location.origin,
65
- )
66
- }
67
-
68
- async function start() {
69
- const { monaco, theme = {}, editorOptions = {} } = await setupMonaco()
70
-
71
- const style = getComputedStyle(document.documentElement)
72
- const container = document.getElementById('container')!
73
-
74
- const model = monaco.editor.createModel(
75
- props.code,
76
- lang(),
77
- monaco.Uri.parse(`file:///root/${Date.now()}.${ext()}`),
78
- )
79
-
80
- if (url.searchParams.get('diff')) {
81
- // Diff editor
82
- const diffModel = monaco.editor.createModel(
83
- props.diff,
84
- lang(),
85
- monaco.Uri.parse(`file:///root/${Date.now()}.${ext()}`),
86
- )
87
- const monacoEditor = monaco.editor.createDiffEditor(container, {
88
- fontSize: +style.getPropertyValue('--slidev-code-font-size').replace(/px/g, ''),
89
- fontFamily: style.getPropertyValue('--slidev-code-font-family'),
90
- lineHeight: +style.getPropertyValue('--slidev-code-line-height').replace(/px/g, ''),
91
- lineDecorationsWidth: 0,
92
- lineNumbersMinChars: 0,
93
- scrollBeyondLastLine: false,
94
- scrollBeyondLastColumn: 0,
95
- automaticLayout: true,
96
- readOnly: props.readonly,
97
- theme: 'vitesse-dark',
98
- lineNumbers: props.lineNumbers as any,
99
- glyphMargin: false,
100
- scrollbar: {
101
- useShadows: false,
102
- vertical: 'hidden',
103
- horizontal: 'hidden',
104
- },
105
- overviewRulerLanes: 0,
106
- minimap: { enabled: false },
107
- enableSplitViewResizing: false,
108
- renderOverviewRuler: false,
109
- // renderSideBySide: false,
110
- ...editorOptions,
111
- })
112
- monacoEditor.setModel({
113
- original: model,
114
- modified: diffModel,
115
- })
116
- originalEditor = monacoEditor.getOriginalEditor()
117
- modifiedEditor = monacoEditor.getModifiedEditor()
118
-
119
- format = async () => {
120
- model.setValue((await formatCode(props.code, lang())).trim())
121
- diffModel.setValue((await formatCode(props.diff, lang())).trim())
122
- }
123
-
124
- // ctrl+s to format
125
- originalEditor.onKeyDown((e) => {
126
- if ((e.ctrlKey || e.metaKey) && e.code === 'KeyS') {
127
- e.preventDefault()
128
- format()
129
- }
130
- })
131
- modifiedEditor.onKeyDown((e) => {
132
- if ((e.ctrlKey || e.metaKey) && e.code === 'KeyS') {
133
- e.preventDefault()
134
- format()
135
- }
136
- })
137
-
138
- update = () => {
139
- monaco.editor.setTheme(props.dark
140
- ? (theme.dark || 'vitesse-dark')
141
- : (theme.light || 'vitesse-light'))
142
- styleObject.innerHTML = `:root { ${props.style} }`
143
-
144
- if (originalEditor.getValue().toString() !== props.code) {
145
- const selection = originalEditor.getSelection()
146
- originalEditor.setValue(props.code)
147
- if (selection)
148
- originalEditor.setSelection(selection)
149
- }
150
- originalEditor.updateOptions(props.editorOptions)
151
-
152
- if (modifiedEditor.getValue().toString() !== props.diff) {
153
- const selection = modifiedEditor.getSelection()
154
- modifiedEditor.setValue(props.diff)
155
- if (selection)
156
- modifiedEditor.setSelection(selection)
157
- }
158
- modifiedEditor.updateOptions(props.editorOptions)
159
- }
160
-
161
- diffModel.onDidChangeContent(() => {
162
- onCodeChange(diffModel.getValue().toString())
163
- })
164
-
165
- function onCodeChange(diff: string) {
166
- props.diff = diff
167
- post({ diff })
168
- }
169
- }
170
- else {
171
- // Normal editor
172
- originalEditor = monaco.editor.create(container, {
173
- model,
174
- tabSize: 2,
175
- insertSpaces: true,
176
- detectIndentation: false,
177
- folding: false,
178
- fontSize: +style.getPropertyValue('--slidev-code-font-size').replace(/px/g, ''),
179
- fontFamily: style.getPropertyValue('--slidev-code-font-family'),
180
- lineHeight: +style.getPropertyValue('--slidev-code-line-height').replace(/px/g, ''),
181
- lineDecorationsWidth: 0,
182
- lineNumbersMinChars: 0,
183
- scrollBeyondLastLine: false,
184
- scrollBeyondLastColumn: 0,
185
- automaticLayout: true,
186
- readOnly: props.readonly,
187
- theme: 'vitesse-dark',
188
- lineNumbers: props.lineNumbers as any,
189
- glyphMargin: false,
190
- scrollbar: {
191
- useShadows: false,
192
- vertical: 'hidden',
193
- horizontal: 'hidden',
194
- },
195
- overviewRulerLanes: 0,
196
- minimap: { enabled: false },
197
- ...editorOptions,
198
- })
199
-
200
- format = async () => {
201
- model.setValue((await formatCode(props.code, lang())).trim())
202
- }
203
-
204
- // ctrl+s to format
205
- originalEditor.onKeyDown((e) => {
206
- if ((e.ctrlKey || e.metaKey) && e.code === 'KeyS') {
207
- e.preventDefault()
208
- format()
209
- }
210
- })
211
-
212
- update = () => {
213
- monaco.editor.setTheme(props.dark
214
- ? (theme.dark || 'vitesse-dark')
215
- : (theme.light || 'vitesse-light'))
216
- styleObject.innerHTML = `:root { ${props.style} }`
217
-
218
- if (originalEditor.getValue().toString() !== props.code) {
219
- const selection = originalEditor.getSelection()
220
- originalEditor.setValue(props.code)
221
- if (selection)
222
- originalEditor.setSelection(selection)
223
- }
224
- originalEditor.updateOptions(props.editorOptions)
225
- }
226
- }
227
-
228
- originalEditor.onDidContentSizeChange(() => {
229
- post({ height: Math.max(originalEditor.getContentHeight(), modifiedEditor?.getContentHeight() ?? 0) })
230
- })
231
-
232
- model.onDidChangeContent(() => {
233
- onCodeChange(model.getValue().toString())
234
- })
235
-
236
- function onCodeChange(code: string) {
237
- props.code = code
238
- post({ code })
239
- }
240
-
241
- update()
242
-
243
- post({}, 'slidev-monaco-loaded')
244
- }
245
-
246
- window.addEventListener('message', (payload) => {
247
- if (payload.source === window)
248
- return
249
- if (payload.origin !== location.origin)
250
- return
251
- if (typeof payload.data !== 'string')
252
- return
253
- const { type, data, id } = JSON.parse(payload.data)
254
- if (type === 'slidev-monaco' && id === props.id) {
255
- Object.assign(props, data)
256
- update()
257
- }
258
- })
259
-
260
- start()