@bagelink/vue 0.0.998 → 0.0.1004
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/dist/components/BglVideo.vue.d.ts.map +1 -1
- package/dist/components/IframeVue.vue.d.ts +47 -0
- package/dist/components/IframeVue.vue.d.ts.map +1 -0
- package/dist/components/form/inputs/CodeEditor/CodeTypes.d.ts +12 -1
- package/dist/components/form/inputs/CodeEditor/CodeTypes.d.ts.map +1 -1
- package/dist/components/form/inputs/CodeEditor/Index.vue.d.ts +18 -4
- package/dist/components/form/inputs/CodeEditor/Index.vue.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/heic2any-BrqcNzfV.js +935 -0
- package/dist/heic2any-C8KwH72N.cjs +934 -0
- package/dist/index.cjs +33573 -99
- package/dist/index.mjs +33573 -99
- package/dist/style.css +24 -135
- package/dist/utils/index.d.ts +4 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/package.json +1 -3
- package/src/components/BglVideo.vue +5 -2
- package/src/components/IframeVue.vue +72 -0
- package/src/components/form/inputs/CodeEditor/CodeTypes.ts +10 -250
- package/src/components/form/inputs/CodeEditor/Index.vue +109 -86
- package/src/components/index.ts +2 -1
- package/src/utils/index.ts +25 -4
|
@@ -1,139 +1,162 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import
|
|
2
|
+
import type { Language, HilightJS } from './CodeTypes'
|
|
3
|
+
|
|
4
|
+
declare global {
|
|
5
|
+
interface Window {
|
|
6
|
+
hljs: HilightJS
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
import { appendStyle, appendScript } from '@bagelink/vue'
|
|
3
10
|
import { nextTick, onMounted, watch } from 'vue'
|
|
4
11
|
|
|
5
|
-
|
|
6
|
-
|
|
12
|
+
// Props
|
|
13
|
+
const { language, readonly = false, modelValue = '', autodetect, ignoreIllegals = true } = defineProps<{
|
|
14
|
+
language?: Language
|
|
7
15
|
readonly?: boolean
|
|
8
16
|
modelValue?: string
|
|
17
|
+
autodetect?: boolean
|
|
18
|
+
ignoreIllegals?: boolean
|
|
9
19
|
}>()
|
|
10
20
|
|
|
21
|
+
const emit = defineEmits(['update:modelValue'])
|
|
22
|
+
|
|
23
|
+
let hljs = $ref<HilightJS | null>(null)
|
|
24
|
+
|
|
25
|
+
// State and refs
|
|
11
26
|
let code = $ref('')
|
|
27
|
+
const textarea = $ref<HTMLTextAreaElement>()
|
|
28
|
+
let height = $ref('300px')
|
|
29
|
+
let loaded = $ref(false)
|
|
30
|
+
|
|
31
|
+
// Computed properties
|
|
32
|
+
const cannotDetectLanguage = $computed(() => {
|
|
33
|
+
const lang = language || ''
|
|
34
|
+
return !(autodetect ?? !lang) && !hljs?.getLanguage(lang)
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
const className = $computed(() => {
|
|
38
|
+
if (cannotDetectLanguage) return ''
|
|
39
|
+
return `hljs ${language || ''}`
|
|
40
|
+
})
|
|
12
41
|
|
|
13
|
-
|
|
42
|
+
const highlightedCode = $computed(() => {
|
|
43
|
+
if (cannotDetectLanguage) {
|
|
44
|
+
console.warn(`The language "${language}" you specified could not be found.`)
|
|
45
|
+
return escapeHtml(code)
|
|
46
|
+
}
|
|
47
|
+
const lang = language || ''
|
|
48
|
+
const result = autodetect
|
|
49
|
+
? hljs?.highlightAuto(code)
|
|
50
|
+
: hljs?.highlight(code, { language: lang, ignoreIllegals })
|
|
51
|
+
return result?.value || ''
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
// Methods
|
|
55
|
+
function escapeHtml(unsafe: string) {
|
|
56
|
+
return unsafe.replace(/[&<>"']/g, (m) => {
|
|
57
|
+
const replacements: { [key: string]: string } = {
|
|
58
|
+
'&': '&',
|
|
59
|
+
'<': '<',
|
|
60
|
+
'>': '>',
|
|
61
|
+
'"': '"',
|
|
62
|
+
'\'': '''
|
|
63
|
+
}
|
|
64
|
+
return replacements[m] || ''
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function handleTab(event: KeyboardEvent) {
|
|
14
69
|
const target = event.target as HTMLTextAreaElement
|
|
15
70
|
const start = target.selectionStart
|
|
16
|
-
const end = target.selectionEnd
|
|
17
71
|
const tab = ' '
|
|
18
|
-
code = code.slice(0, start) + tab + code.slice(
|
|
72
|
+
code = code.slice(0, start) + tab + code.slice(start)
|
|
19
73
|
nextTick(() => {
|
|
20
|
-
target.selectionStart = target.selectionEnd = start +
|
|
74
|
+
target.selectionStart = target.selectionEnd = start + tab.length
|
|
21
75
|
})
|
|
22
76
|
}
|
|
23
77
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (!textarea) return
|
|
29
|
-
const { scrollHeight } = textarea
|
|
30
|
-
height = `${scrollHeight}px`
|
|
78
|
+
function adjustHeight() {
|
|
79
|
+
if (textarea?.scrollHeight && textarea.scrollHeight > 300) {
|
|
80
|
+
height = `${textarea.scrollHeight}px`
|
|
81
|
+
}
|
|
31
82
|
}
|
|
32
83
|
|
|
33
|
-
|
|
34
|
-
|
|
84
|
+
// Lifecycle
|
|
35
85
|
onMounted(async () => {
|
|
36
|
-
|
|
37
|
-
await
|
|
38
|
-
|
|
86
|
+
// Append scripts and styles for Highlight.js
|
|
87
|
+
await appendScript('https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.0/highlight.min.js', { id: 'hljs-cdn' })
|
|
88
|
+
await appendStyle('https://cdn.jsdelivr.net/npm/highlight.js/styles/atom-one-dark.min.css')
|
|
89
|
+
|
|
90
|
+
// Initialize hljs
|
|
91
|
+
if (window.hljs) {
|
|
92
|
+
hljs = window.hljs as HilightJS
|
|
93
|
+
loaded = true
|
|
94
|
+
} else {
|
|
95
|
+
console.error('Highlight.js failed to load.')
|
|
96
|
+
}
|
|
39
97
|
})
|
|
40
98
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
99
|
+
watch(() => modelValue, (newVal) => {
|
|
100
|
+
adjustHeight()
|
|
101
|
+
if (newVal !== code) {
|
|
102
|
+
code = newVal
|
|
103
|
+
}
|
|
45
104
|
}, { immediate: true })
|
|
46
105
|
</script>
|
|
47
106
|
|
|
48
107
|
<template>
|
|
49
|
-
<div v-if="loaded" class="code-editor-wrap
|
|
108
|
+
<div v-if="loaded" class="code-editor-wrap grid rounded p-1 overflow hm-300px ">
|
|
50
109
|
<div class="relative block h-100" :style="{ height }">
|
|
51
|
-
<
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
:key="index"
|
|
55
|
-
class="number txt-end"
|
|
56
|
-
>
|
|
57
|
-
{{ index + 1 }}
|
|
58
|
-
</div>
|
|
59
|
-
</div>
|
|
60
|
-
<Highlightjs
|
|
61
|
-
class="highlighted-code absolute inset-0"
|
|
62
|
-
:autodetect="!language"
|
|
63
|
-
:code="code"
|
|
64
|
-
:wrap="true"
|
|
65
|
-
:language="language"
|
|
66
|
-
/>
|
|
110
|
+
<pre class=" overflow-hidden absolute inset-0 p-0 m-0 h-100 codeText">
|
|
111
|
+
<code :class="className" v-html="highlightedCode" />
|
|
112
|
+
</pre>
|
|
67
113
|
<textarea
|
|
68
114
|
v-if="!readonly"
|
|
69
115
|
ref="textarea"
|
|
70
116
|
v-model="code"
|
|
71
|
-
|
|
72
|
-
|
|
117
|
+
class="code-editor absolute inset-0 bg-transparent overflow-hidden h-100 p-0 m-0 codeText border-none"
|
|
118
|
+
spellcheck="false"
|
|
73
119
|
placeholder="Write your code here"
|
|
74
120
|
aria-label="Code Editor"
|
|
75
121
|
data-gramm="false"
|
|
76
|
-
@
|
|
77
|
-
@
|
|
122
|
+
@keydown.tab.prevent="handleTab"
|
|
123
|
+
@input="emit('update:modelValue', code)"
|
|
78
124
|
/>
|
|
79
125
|
</div>
|
|
80
126
|
</div>
|
|
81
127
|
</template>
|
|
82
128
|
|
|
83
129
|
<style>
|
|
84
|
-
.
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
max-height: 300px;
|
|
130
|
+
pre code.hljs{
|
|
131
|
+
padding: 0 !important;
|
|
132
|
+
inset: 0 !important;
|
|
133
|
+
position: absolute;
|
|
89
134
|
}
|
|
135
|
+
</style>
|
|
90
136
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
137
|
+
<style scoped>
|
|
138
|
+
.codeText{
|
|
139
|
+
font-family: monospace;
|
|
140
|
+
white-space: pre-wrap;
|
|
141
|
+
word-wrap: break-word;
|
|
142
|
+
caret-color: var(--bgl-white);
|
|
94
143
|
}
|
|
95
|
-
.
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
/* Highlight.js styles */
|
|
99
|
-
.highlighted-code {
|
|
100
|
-
white-space: pre-wrap;
|
|
101
|
-
word-wrap: break-word;
|
|
102
|
-
overflow: hidden;
|
|
103
|
-
margin: 0;
|
|
104
|
-
padding: 0;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
.highlighted-code code {
|
|
108
|
-
padding-left: 70px !important;
|
|
109
|
-
overflow: hidden !important;
|
|
144
|
+
.code-editor-wrap {
|
|
145
|
+
background: #282c34;
|
|
146
|
+
height: max-content;
|
|
110
147
|
}
|
|
111
148
|
|
|
112
|
-
/* Textarea aligned with Highlight.js */
|
|
113
149
|
.code-editor {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
resize: none;
|
|
117
|
-
white-space: pre-wrap;
|
|
118
|
-
word-wrap: break-word;
|
|
119
|
-
caret-color: var(--bgl-white);
|
|
120
|
-
font-size: 16px;
|
|
121
|
-
padding: 1rem;
|
|
122
|
-
padding-left: 70px !important;
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
.code-editor::-moz-selection {
|
|
127
|
-
background: #2466bc30;
|
|
128
|
-
color: inherit;
|
|
150
|
+
color: transparent;
|
|
151
|
+
resize: none;
|
|
129
152
|
}
|
|
130
153
|
|
|
131
154
|
.code-editor::selection {
|
|
132
|
-
|
|
133
|
-
|
|
155
|
+
background: #2466bc30;
|
|
156
|
+
color: inherit;
|
|
134
157
|
}
|
|
135
158
|
|
|
136
159
|
.code-editor:focus {
|
|
137
|
-
|
|
160
|
+
outline: none;
|
|
138
161
|
}
|
|
139
162
|
</style>
|
package/src/components/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ export { default as DataPreview } from './DataPreview.vue'
|
|
|
13
13
|
export { default as Dropdown } from './Dropdown.vue'
|
|
14
14
|
export { default as Flag } from './Flag.vue'
|
|
15
15
|
export * from './form'
|
|
16
|
+
export { default as IframeVue } from './IframeVue.vue'
|
|
16
17
|
export { default as Image } from './Image.vue'
|
|
17
18
|
export * from './layout'
|
|
18
19
|
export { default as ListItem } from './ListItem.vue'
|
|
@@ -24,8 +25,8 @@ export { default as Icon } from './MaterialIcon.vue'
|
|
|
24
25
|
export { default as Modal } from './Modal.vue'
|
|
25
26
|
export { default as ModalConfirm } from './ModalConfirm.vue'
|
|
26
27
|
export { default as ModalForm } from './ModalForm.vue'
|
|
27
|
-
export { default as NavBar } from './NavBar.vue'
|
|
28
28
|
|
|
29
|
+
export { default as NavBar } from './NavBar.vue'
|
|
29
30
|
export { default as PageTitle } from './PageTitle.vue'
|
|
30
31
|
export { default as Pill } from './Pill.vue'
|
|
31
32
|
export { default as RouterWrapper } from './RouterWrapper.vue'
|
package/src/utils/index.ts
CHANGED
|
@@ -111,22 +111,43 @@ export function sleep(ms: number = 100) {
|
|
|
111
111
|
return new Promise(resolve => setTimeout(resolve, ms))
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
export function appendScript(src: string): Promise<void> {
|
|
114
|
+
export function appendScript(src: string, options?: { id?: string }): Promise<void> {
|
|
115
115
|
return new Promise((resolve, reject) => {
|
|
116
|
-
if (
|
|
116
|
+
if (options?.id) {
|
|
117
|
+
if (document.getElementById(options.id)) {
|
|
118
|
+
resolve()
|
|
119
|
+
return
|
|
120
|
+
}
|
|
121
|
+
} else if (document.querySelector(`script[src="${src}"]`)) {
|
|
117
122
|
resolve()
|
|
118
123
|
return
|
|
119
124
|
}
|
|
120
125
|
const script = document.createElement('script')
|
|
121
126
|
script.src = src
|
|
122
|
-
|
|
123
|
-
|
|
127
|
+
if (options?.id) {
|
|
128
|
+
script.id = options.id
|
|
124
129
|
}
|
|
130
|
+
script.onload = () => { resolve() }
|
|
125
131
|
script.onerror = reject
|
|
126
132
|
document.head.append(script)
|
|
127
133
|
})
|
|
128
134
|
}
|
|
129
135
|
|
|
136
|
+
export function appendStyle(src: string): Promise<void> {
|
|
137
|
+
return new Promise((resolve, reject) => {
|
|
138
|
+
if (document.querySelector(`link[href="${src}"]`)) {
|
|
139
|
+
resolve()
|
|
140
|
+
return
|
|
141
|
+
}
|
|
142
|
+
const link = document.createElement('link')
|
|
143
|
+
link.href = src
|
|
144
|
+
link.rel = 'stylesheet'
|
|
145
|
+
link.onload = () => { resolve() }
|
|
146
|
+
link.onerror = reject
|
|
147
|
+
document.head.append(link)
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
|
|
130
151
|
export function normalizeURL(url: string) {
|
|
131
152
|
if (url.startsWith('https://')) return url
|
|
132
153
|
url = url.replace(/http:\/\//, '')
|