@bagelink/vue 0.0.986 → 0.0.988

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 (61) hide show
  1. package/dist/components/Btn.vue.d.ts.map +1 -1
  2. package/dist/components/form/inputs/CodeEditor/CodeTypes.d.ts +197 -0
  3. package/dist/components/form/inputs/CodeEditor/CodeTypes.d.ts.map +1 -0
  4. package/dist/components/form/inputs/CodeEditor/Index.vue.d.ts +60 -0
  5. package/dist/components/form/inputs/CodeEditor/Index.vue.d.ts.map +1 -0
  6. package/dist/components/form/inputs/CodeEditor/format.d.ts +2 -0
  7. package/dist/components/form/inputs/CodeEditor/format.d.ts.map +1 -0
  8. package/dist/components/form/inputs/RichText/Toolbar.vue.d.ts +5 -3
  9. package/dist/components/form/inputs/RichText/Toolbar.vue.d.ts.map +1 -1
  10. package/dist/components/form/inputs/RichText/components/Toolbar.vue.d.ts +14 -0
  11. package/dist/components/form/inputs/RichText/components/Toolbar.vue.d.ts.map +1 -0
  12. package/dist/components/form/inputs/RichText/components/gridBox.vue.d.ts +11 -0
  13. package/dist/components/form/inputs/RichText/components/gridBox.vue.d.ts.map +1 -0
  14. package/dist/components/form/inputs/RichText/composables/useEditor.d.ts +86 -0
  15. package/dist/components/form/inputs/RichText/composables/useEditor.d.ts.map +1 -0
  16. package/dist/components/form/inputs/RichText/composables/useEditorKeyboard.d.ts +2 -0
  17. package/dist/components/form/inputs/RichText/composables/useEditorKeyboard.d.ts.map +1 -0
  18. package/dist/components/form/inputs/RichText/config.d.ts +5 -0
  19. package/dist/components/form/inputs/RichText/config.d.ts.map +1 -0
  20. package/dist/components/form/inputs/RichText/index.vue.d.ts +1 -1
  21. package/dist/components/form/inputs/RichText/index.vue.d.ts.map +1 -1
  22. package/dist/components/form/inputs/RichText/utils/formatting.d.ts +7 -0
  23. package/dist/components/form/inputs/RichText/utils/formatting.d.ts.map +1 -0
  24. package/dist/components/form/inputs/RichText/utils/media.d.ts +4 -0
  25. package/dist/components/form/inputs/RichText/utils/media.d.ts.map +1 -0
  26. package/dist/components/form/inputs/RichText/utils/selection.d.ts +4 -0
  27. package/dist/components/form/inputs/RichText/utils/selection.d.ts.map +1 -0
  28. package/dist/components/form/inputs/RichText/utils/table.d.ts +6 -0
  29. package/dist/components/form/inputs/RichText/utils/table.d.ts.map +1 -0
  30. package/dist/components/form/inputs/index.d.ts +1 -0
  31. package/dist/components/form/inputs/index.d.ts.map +1 -1
  32. package/dist/editor-CUDRLdmS.js +4 -0
  33. package/dist/editor-Cu374vEW.cjs +4 -0
  34. package/dist/index.cjs +53541 -763
  35. package/dist/index.mjs +53542 -764
  36. package/dist/style.css +19779 -97
  37. package/package.json +2 -1
  38. package/src/components/Btn.vue +3 -0
  39. package/src/components/form/inputs/CodeEditor/CodeTypes.ts +446 -0
  40. package/src/components/form/inputs/CodeEditor/Index.vue +440 -0
  41. package/src/components/form/inputs/CodeEditor/format.ts +98 -0
  42. package/src/components/form/inputs/CodeEditor/themes/brown-papersq.png +0 -0
  43. package/src/components/form/inputs/CodeEditor/themes/pojoaque.jpg +0 -0
  44. package/src/components/form/inputs/CodeEditor/themes/themes-base16.css +12809 -0
  45. package/src/components/form/inputs/CodeEditor/themes/themes.css +6740 -0
  46. package/src/components/form/inputs/RichText/components/Toolbar.vue +51 -0
  47. package/src/components/form/inputs/RichText/components/gridBox.vue +22 -0
  48. package/src/components/form/inputs/RichText/composables/useEditor.ts +208 -0
  49. package/src/components/form/inputs/RichText/composables/useEditorKeyboard.ts +21 -0
  50. package/src/components/form/inputs/RichText/config.ts +73 -0
  51. package/src/components/form/inputs/RichText/editor.css +25 -0
  52. package/src/components/form/inputs/RichText/index.vue +81 -193
  53. package/src/components/form/inputs/RichText/richTextTypes.d.ts +77 -0
  54. package/src/components/form/inputs/RichText/utils/formatting.ts +98 -0
  55. package/src/components/form/inputs/RichText/utils/media.ts +42 -0
  56. package/src/components/form/inputs/RichText/utils/selection.ts +48 -0
  57. package/src/components/form/inputs/RichText/utils/table.ts +79 -0
  58. package/src/components/form/inputs/index.ts +1 -0
  59. package/src/components/form/inputs/RichText/Toolbar.vue +0 -87
  60. package/src/components/form/inputs/RichText/formatting.ts +0 -246
  61. package/src/components/form/inputs/RichText/richtext-types.ts +0 -29
@@ -0,0 +1,440 @@
1
+ <script setup lang="ts">
2
+ import type { Directive } from 'vue'
3
+ import { Btn, Dropdown, copyText } from '@bagelink/vue'
4
+ import hljs from 'highlight.js'
5
+ import { defineEmits, defineProps, nextTick, onMounted, watch } from 'vue'
6
+ import { type CodeTheme, type Language, codeLanguages } from './CodeTypes'
7
+ import { formatCode } from './format'
8
+ import './themes/themes-base16.css'
9
+ import './themes/themes.css'
10
+
11
+ const {
12
+ showLineNumbers = false,
13
+ modelValue = '',
14
+ theme = 'github-dark',
15
+ tabSpaces = 2,
16
+ wrap = true,
17
+ readOnly = false,
18
+ autofocus = false,
19
+ header = true,
20
+ width = '400px',
21
+ height = '600px',
22
+ maxWidth,
23
+ minWidth,
24
+ maxHeight,
25
+ minHeight,
26
+ borderRadius = '12px',
27
+ languages = ['javascript'],
28
+ displayLanguage = true,
29
+ copyCode = true,
30
+ fontSize = '17px',
31
+ padding = '20px'
32
+ } = defineProps<{
33
+ showLineNumbers?: boolean
34
+ modelValue?: string
35
+ theme?: CodeTheme
36
+ tabSpaces?: number
37
+ wrap?: boolean
38
+ readOnly?: boolean
39
+ autofocus?: boolean
40
+ header?: boolean
41
+ width?: string
42
+ height?: string
43
+ maxWidth?: string
44
+ minWidth?: string
45
+ maxHeight?: string
46
+ minHeight?: string
47
+ borderRadius?: string
48
+ languages?: Language[]
49
+ displayLanguage?: boolean
50
+ copyCode?: boolean
51
+ fontSize?: string
52
+ padding?: string
53
+ }>()
54
+
55
+ const emit = defineEmits(['update:modelValue', 'lang', 'content', 'textarea', 'search'])
56
+
57
+ let scrollBarWidth = $ref(0)
58
+ let scrollBarHeight = $ref(0)
59
+ let top = $ref(0)
60
+ let left = $ref(0)
61
+ let currentLanguage = $ref(languages[0])
62
+ let content = $ref(formatCode(modelValue, currentLanguage))
63
+ let cursorPosition = $ref(0)
64
+ let insertTab = $ref(false)
65
+ let lineNum = $ref(0)
66
+ let lineNumsWidth = $ref(0)
67
+ let scrolling = $ref(false)
68
+ let textareaHeight = $ref(0)
69
+ const langListHeight = $ref('200px') // Define langListHeight with a default value
70
+
71
+ const textarea = $ref<HTMLTextAreaElement>()
72
+ const code = $ref<HTMLElement>()
73
+ const lineNums = $ref<HTMLElement>()
74
+
75
+ const languageClass = $computed(() => `hljs language-${currentLanguage}`)
76
+ const languageTitle = $computed(() => codeLanguages[currentLanguage as Language])
77
+ const tabWidth = $computed(() => ' '.repeat(tabSpaces))
78
+ const scroll = $computed(() => height !== 'auto')
79
+
80
+ const showLineNums = $computed(() => showLineNumbers || wrap)
81
+
82
+ const autoClosePairs = {
83
+ '(': ')',
84
+ '[': ']',
85
+ '{': '}',
86
+ '"': '"',
87
+ '\'': '\'',
88
+ '`': '`'
89
+ }
90
+
91
+ function updateValue(e: Event) {
92
+ const target = e.target as HTMLTextAreaElement
93
+ const char = target.value[target.selectionStart - 1]
94
+
95
+ if (char && autoClosePairs[char as keyof typeof autoClosePairs]) {
96
+ const closingChar = autoClosePairs[char as keyof typeof autoClosePairs]
97
+ const cursorPos = target.selectionStart
98
+ target.value = target.value.slice(0, cursorPos) + closingChar + target.value.slice(cursorPos)
99
+ target.selectionStart = cursorPos
100
+ target.selectionEnd = cursorPos
101
+ }
102
+ const cursorPos = target.selectionStart
103
+ content = target.value
104
+ emit('update:modelValue', content)
105
+ nextTick(() => {
106
+ target.setSelectionRange(cursorPos, cursorPos)
107
+ })
108
+ }
109
+
110
+ function changeLang(lang: Language) {
111
+ currentLanguage = lang
112
+ emit('lang', lang)
113
+ }
114
+
115
+ function tab() {
116
+ if (document.execCommand('insertText')) {
117
+ document.execCommand('insertText', false, tabWidth)
118
+ } else {
119
+ const cursorPos = textarea?.selectionStart ?? 0
120
+ content
121
+ = content.substring(0, cursorPos) + tabWidth + content.substring(cursorPos)
122
+ cursorPosition = cursorPos + tabWidth.length
123
+ insertTab = true
124
+ }
125
+ }
126
+
127
+ function calcScrollDistance(e: Event) {
128
+ const target = e.target as HTMLTextAreaElement
129
+ code?.setAttribute('scrolling', 'true')
130
+ scrolling = true
131
+ top = -target.scrollTop
132
+ left = -target.scrollLeft
133
+ }
134
+
135
+ function resizer() {
136
+ const textareaResizer = new ResizeObserver((entries) => {
137
+ const target = entries[0].target as HTMLElement
138
+ scrollBarWidth = target.offsetWidth - target.clientWidth
139
+ scrollBarHeight = target.offsetHeight - target.clientHeight
140
+ textareaHeight = target.offsetHeight
141
+ })
142
+ if (textarea) {
143
+ textareaResizer.observe(textarea)
144
+ }
145
+
146
+ const lineNumsResizer = new ResizeObserver((entries) => {
147
+ lineNumsWidth = (entries[0].target as HTMLElement).offsetWidth
148
+ })
149
+ if (lineNums) {
150
+ lineNumsResizer.observe(lineNums)
151
+ }
152
+ }
153
+
154
+ function getLineNum() {
155
+ const str = textarea!.value
156
+ let lineNumCount = 0
157
+ let position = str.indexOf('\n')
158
+ while (position !== -1) {
159
+ lineNumCount++
160
+ position = str.indexOf('\n', position + 1)
161
+ }
162
+ const firstChild = lineNums!.firstChild as HTMLElement
163
+ const singleLineHeight = firstChild!.offsetHeight
164
+ const heightNum = Math.floor(textareaHeight / singleLineHeight) - 1
165
+ lineNum = height === 'auto' ? lineNumCount : Math.max(lineNumCount, heightNum)
166
+ }
167
+
168
+ watch(() => modelValue, (newVal) => {
169
+ if (newVal !== undefined) {
170
+ content = newVal
171
+ }
172
+ })
173
+
174
+ onMounted(() => {
175
+ emit('lang', languages[0])
176
+ emit('content', content)
177
+ emit('textarea', textarea)
178
+ resizer()
179
+ })
180
+
181
+ watch(() => insertTab, (newVal) => {
182
+ if (newVal) {
183
+ textarea!.setSelectionRange(cursorPosition, cursorPosition)
184
+ insertTab = false
185
+ }
186
+ })
187
+
188
+ watch(() => showLineNumbers, (newVal) => {
189
+ if (newVal) {
190
+ if (scrolling) scrolling = false
191
+ else getLineNum()
192
+ }
193
+ })
194
+
195
+ const highlight: Directive = {
196
+ mounted(el, binding) {
197
+ el.textContent = binding
198
+ hljs.highlightElement(el)
199
+ },
200
+ updated(el, binding) {
201
+ if (el.getAttribute('data-scrolling') === 'true') {
202
+ el.setAttribute('data-scrolling', 'false')
203
+ } else {
204
+ el.textContent = binding
205
+ hljs.highlightElement(el)
206
+ }
207
+ },
208
+ }
209
+
210
+ defineExpose({ highlight })
211
+ </script>
212
+
213
+ <template>
214
+ <div
215
+ :theme="theme" class="code-editor" :class="{
216
+ 'hide-header': !header,
217
+ 'scroll': scroll,
218
+ 'read-only': readOnly,
219
+ 'wrap': wrap,
220
+ }" :style="{
221
+ width,
222
+ height,
223
+ maxWidth,
224
+ minWidth,
225
+ maxHeight,
226
+ minHeight,
227
+ }"
228
+ >
229
+ <div class="hljs" :style="{ borderRadius }">
230
+ <div
231
+ v-if="header" class="p-025 flex space-between" :class="{ border: showLineNums }"
232
+ :style="{ borderRadius: `${borderRadius} ${borderRadius} 0 0` }"
233
+ >
234
+ <Dropdown v-if="displayLanguage" :value="languageTitle" flat thin :disabled="languages.length <= 1">
235
+ <ul class="lang-list hljs" :style="{ height: langListHeight }">
236
+ <li v-for="(lang, index) in languages" :key="index" @click="changeLang(lang)">
237
+ {{ codeLanguages[lang] }}
238
+ </li>
239
+ </ul>
240
+ </Dropdown>
241
+ <Btn v-if="copyCode" v-tooltip.left="'Copy'" class="color-white" flat thin icon="content_copy" @click="copyText(content)" />
242
+ </div>
243
+ <div class="code-area" :style="{ borderRadius: header ? `0 0 ${borderRadius} ${borderRadius}` : borderRadius }">
244
+ <div
245
+ v-if="showLineNums" ref="lineNums" class="line-nums hljs" :style="{
246
+ fontSize,
247
+ paddingTop: header ? '10px' : padding,
248
+ paddingBottom: padding,
249
+ top: `${top}px`,
250
+ }"
251
+ >
252
+ <div>1</div>
253
+ <div v-for="num in lineNum" :key="num">
254
+ {{ num + 1 }}
255
+ </div>
256
+ <div>&nbsp;</div>
257
+ </div>
258
+ <textarea
259
+ ref="textarea" title="textarea" :readOnly="readOnly" :style="{
260
+ fontSize,
261
+ padding: !header ? padding : lineNums ? `10px ${padding} ${padding}` : `0 ${padding} ${padding}`,
262
+ marginLeft: showLineNums ? `${lineNumsWidth}px` : '0',
263
+ width: showLineNums ? `calc(100% - ${lineNumsWidth}px)` : '100%',
264
+ }" :autofocus="autofocus" spellcheck="false" :value="content"
265
+ @keydown.tab.prevent.stop="tab" @scroll="calcScrollDistance" @input="updateValue"
266
+ />
267
+ <pre
268
+ :style="{
269
+ paddingRight: `${scrollBarWidth}px`,
270
+ paddingBottom: `${scrollBarHeight}px`,
271
+ marginLeft: showLineNums ? `${lineNumsWidth}px` : '0',
272
+ width: showLineNums ? `calc(100% - ${lineNumsWidth}px)` : '100%',
273
+ }"
274
+ >
275
+ <code
276
+ ref="code"
277
+ :innerHTML="hljs.highlight(content, { language: currentLanguage }).value"
278
+ :class="languageClass"
279
+ :style="{
280
+ top: `${top}px`,
281
+ left: `${left}px`,
282
+ fontSize,
283
+ padding: !header ? padding : lineNums ? `10px ${padding} ${padding}` : `0 ${padding} ${padding}`,
284
+ }"
285
+ />
286
+ </pre>
287
+ </div>
288
+ </div>
289
+ </div>
290
+ </template>
291
+
292
+ <style>
293
+ .code-editor {
294
+ position: relative;
295
+ }
296
+
297
+ .code-editor>div {
298
+ width: 100%;
299
+ height: 100%;
300
+ }
301
+
302
+ .code-editor .code-area {
303
+ position: relative;
304
+ z-index: 0;
305
+ text-align: left;
306
+ overflow: hidden;
307
+ }
308
+
309
+ /* Common styles for text elements */
310
+ .code-editor .code-area>textarea,
311
+ .code-editor .code-area>pre>code,
312
+ .code-editor .line-nums>div {
313
+ font-family: Consolas, Monaco, monospace;
314
+ line-height: 1.5;
315
+ }
316
+
317
+ .code-editor .code-area>textarea:focus-within {
318
+ background: rgba(255, 255, 255, 0.05);
319
+ }
320
+
321
+ /* Textarea styles */
322
+ .code-editor .code-area>textarea {
323
+ position: absolute;
324
+ z-index: 1;
325
+ inset: 0;
326
+ box-sizing: border-box;
327
+ caret-color: rgb(127, 127, 127);
328
+ color: transparent;
329
+ white-space: pre;
330
+ word-wrap: normal;
331
+ border: 0;
332
+ width: 100%;
333
+ height: 100%;
334
+ background: none;
335
+ resize: none;
336
+ outline: none;
337
+ }
338
+
339
+ /* Pre and code styles */
340
+ .code-editor .code-area>pre {
341
+ box-sizing: border-box;
342
+ position: relative;
343
+ margin: 0;
344
+ font-size: 0;
345
+ }
346
+
347
+ .code-editor .code-area>pre>code {
348
+ display: block;
349
+ position: relative;
350
+ overflow-x: visible !important;
351
+ background: none;
352
+ margin: 0;
353
+ box-sizing: border-box;
354
+ }
355
+
356
+ /* Wrap styles */
357
+ .code-editor.wrap .code-area>textarea,
358
+ .code-editor.wrap .code-area>pre>code {
359
+ white-space: pre-wrap;
360
+ word-wrap: break-word;
361
+ word-break: break-all;
362
+ }
363
+
364
+ /* Scroll styles */
365
+ .code-editor.scroll .code-area {
366
+ height: calc(100% - 34px);
367
+ }
368
+
369
+ .code-editor.hide-header.scroll .code-area {
370
+ height: 100%;
371
+ }
372
+
373
+ .code-editor.scroll .code-area>textarea {
374
+ overflow: auto;
375
+ }
376
+
377
+ /* Language list styles */
378
+ .code-editor .list {
379
+ user-select: none;
380
+ height: 100%;
381
+ font-family: sans-serif;
382
+ }
383
+
384
+ .code-editor .list>.lang-list {
385
+ border-radius: 5px;
386
+ padding: 0;
387
+ margin: 0;
388
+ list-style: none;
389
+ font-size: 13px;
390
+ overflow: auto;
391
+ }
392
+
393
+ .code-editor .list>.lang-list>li {
394
+ padding: 0 12px;
395
+ line-height: 30px;
396
+ white-space: nowrap;
397
+ overflow: hidden;
398
+ text-overflow: ellipsis;
399
+ transition: background 0.16s ease;
400
+ }
401
+
402
+ .code-editor .list>.lang-list>li:first-child {
403
+ padding-top: 5px;
404
+ }
405
+
406
+ .code-editor .list>.lang-list>li:last-child {
407
+ padding-bottom: 5px;
408
+ }
409
+
410
+ .code-editor .list>.lang-list>li:hover {
411
+ background: rgba(160, 160, 160, 0.4);
412
+ }
413
+
414
+ /* Line numbers */
415
+ .code-editor .line-nums {
416
+ min-width: 36px;
417
+ position: absolute;
418
+ left: 0;
419
+ padding: 0 8px;
420
+ text-align: right;
421
+ opacity: 0.3;
422
+ }
423
+
424
+ .code-editor .line-nums::after {
425
+ content: "";
426
+ position: absolute;
427
+ inset: 0;
428
+ border-right: 1px solid currentColor;
429
+ opacity: 0.5;
430
+ }
431
+
432
+ .code-editor .header.border::after {
433
+ content: "";
434
+ position: absolute;
435
+ inset: auto 0 0;
436
+ height: 1px;
437
+ background: currentColor;
438
+ opacity: 0.15;
439
+ }
440
+ </style>
@@ -0,0 +1,98 @@
1
+ const format = {
2
+ html: (html: string) => {
3
+ const formatted = []
4
+ const reg = /(>)(<)(\/*)/g
5
+ const tab = ' '
6
+ let level = 0
7
+
8
+ html = html.replace(reg, '$1\n$2$3')
9
+
10
+ const lines = html.split('\n')
11
+
12
+ for (const line of lines) {
13
+ if (line.match(/<\/\w+/) && !line.match(/\/>/)) {
14
+ level--
15
+ }
16
+ formatted.push(tab.repeat(Math.max(level, 0)) + line)
17
+ if (line.match(/<\w[^>]*[^/]>/)) {
18
+ level++
19
+ }
20
+ }
21
+ return formatted.join('\n')
22
+ },
23
+ json: (jsonString: string, indent = 4) => {
24
+ try {
25
+ const jsonObject = JSON.parse(jsonString)
26
+ return JSON.stringify(jsonObject, null, indent)
27
+ } catch (error) {
28
+ return `Invalid JSON: ${(error as Error).message}`
29
+ }
30
+ },
31
+ javascript: (jsCode: string, indent = 4) => {
32
+ try {
33
+ const tab = ' '.repeat(indent)
34
+ let formatted = ''
35
+ let level = 0
36
+ let inString = ''
37
+
38
+ for (let i = 0; i < jsCode.length; i++) {
39
+ const char = jsCode[i]
40
+ const nextChar = jsCode[i + 1]
41
+ if (char === '"' || char === '\'' || char === '`') {
42
+ formatted += char
43
+ if (inString.length && inString === char) {
44
+ inString = ''
45
+ } else if (!inString.length) {
46
+ inString = char
47
+ }
48
+ continue
49
+ }
50
+ if (inString) {
51
+ formatted += char
52
+ continue
53
+ }
54
+ if (char === '{' || char === '[') {
55
+ formatted += `${char}\n${tab.repeat(++level)}`
56
+ continue
57
+ }
58
+ if (char === '}' || char === ']') {
59
+ formatted += `\n${tab.repeat(--level)}${char}`
60
+ continue
61
+ }
62
+ if (char === ';' || char === ',') {
63
+ formatted += `${char}\n${tab.repeat(level)}`
64
+ continue
65
+ }
66
+ if (char === '\n') {
67
+ formatted += `\n${tab.repeat(level)}`
68
+ continue
69
+ }
70
+ if (
71
+ (char === ')' && nextChar === '{') ||
72
+ (char === ')' && nextChar === ' ')
73
+ ) {
74
+ formatted += `${char}\n${tab.repeat(level)}`
75
+ continue
76
+ }
77
+ formatted += char
78
+ }
79
+
80
+ return formatted
81
+ } catch (error) {
82
+ return `Error formatting JavaScript: ${(error as Error).message}`
83
+ }
84
+ }
85
+ }
86
+
87
+ export function formatCode(code: string, language: string) {
88
+ switch (language) {
89
+ case 'html':
90
+ return format.html(code)
91
+ case 'json':
92
+ return format.json(code)
93
+ case 'javascript':
94
+ return format.javascript(code)
95
+ default:
96
+ return code
97
+ }
98
+ }