@bagelink/vue 0.0.984 → 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.
- package/dist/components/Btn.vue.d.ts.map +1 -1
- package/dist/components/DropDown.vue.d.ts +2 -2
- package/dist/components/DropDown.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/CodeEditor/CodeTypes.d.ts +197 -0
- package/dist/components/form/inputs/CodeEditor/CodeTypes.d.ts.map +1 -0
- package/dist/components/form/inputs/CodeEditor/Index.vue.d.ts +60 -0
- package/dist/components/form/inputs/CodeEditor/Index.vue.d.ts.map +1 -0
- package/dist/components/form/inputs/CodeEditor/format.d.ts +2 -0
- package/dist/components/form/inputs/CodeEditor/format.d.ts.map +1 -0
- package/dist/components/form/inputs/RichText/Toolbar.vue.d.ts +5 -3
- package/dist/components/form/inputs/RichText/Toolbar.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/components/Toolbar.vue.d.ts +14 -0
- package/dist/components/form/inputs/RichText/components/Toolbar.vue.d.ts.map +1 -0
- package/dist/components/form/inputs/RichText/components/gridBox.vue.d.ts +11 -0
- package/dist/components/form/inputs/RichText/components/gridBox.vue.d.ts.map +1 -0
- package/dist/components/form/inputs/RichText/composables/useEditor.d.ts +86 -0
- package/dist/components/form/inputs/RichText/composables/useEditor.d.ts.map +1 -0
- package/dist/components/form/inputs/RichText/composables/useEditorKeyboard.d.ts +2 -0
- package/dist/components/form/inputs/RichText/composables/useEditorKeyboard.d.ts.map +1 -0
- package/dist/components/form/inputs/RichText/config.d.ts +5 -0
- package/dist/components/form/inputs/RichText/config.d.ts.map +1 -0
- package/dist/components/form/inputs/RichText/index.vue.d.ts +1 -1
- package/dist/components/form/inputs/RichText/index.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/utils/formatting.d.ts +7 -0
- package/dist/components/form/inputs/RichText/utils/formatting.d.ts.map +1 -0
- package/dist/components/form/inputs/RichText/utils/media.d.ts +4 -0
- package/dist/components/form/inputs/RichText/utils/media.d.ts.map +1 -0
- package/dist/components/form/inputs/RichText/utils/selection.d.ts +4 -0
- package/dist/components/form/inputs/RichText/utils/selection.d.ts.map +1 -0
- package/dist/components/form/inputs/RichText/utils/table.d.ts +6 -0
- package/dist/components/form/inputs/RichText/utils/table.d.ts.map +1 -0
- package/dist/components/form/inputs/SelectInput.vue.d.ts +2 -2
- package/dist/components/form/inputs/index.d.ts +1 -0
- package/dist/components/form/inputs/index.d.ts.map +1 -1
- package/dist/editor-CUDRLdmS.js +4 -0
- package/dist/editor-Cu374vEW.cjs +4 -0
- package/dist/index.cjs +53544 -766
- package/dist/index.mjs +53545 -767
- package/dist/style.css +19779 -97
- package/package.json +2 -1
- package/src/components/Btn.vue +3 -0
- package/src/components/Dropdown.vue +1 -1
- package/src/components/form/inputs/CodeEditor/CodeTypes.ts +446 -0
- package/src/components/form/inputs/CodeEditor/Index.vue +440 -0
- package/src/components/form/inputs/CodeEditor/format.ts +98 -0
- package/src/components/form/inputs/CodeEditor/themes/brown-papersq.png +0 -0
- package/src/components/form/inputs/CodeEditor/themes/pojoaque.jpg +0 -0
- package/src/components/form/inputs/CodeEditor/themes/themes-base16.css +12809 -0
- package/src/components/form/inputs/CodeEditor/themes/themes.css +6740 -0
- package/src/components/form/inputs/RichText/components/Toolbar.vue +51 -0
- package/src/components/form/inputs/RichText/components/gridBox.vue +22 -0
- package/src/components/form/inputs/RichText/composables/useEditor.ts +208 -0
- package/src/components/form/inputs/RichText/composables/useEditorKeyboard.ts +21 -0
- package/src/components/form/inputs/RichText/config.ts +73 -0
- package/src/components/form/inputs/RichText/editor.css +25 -0
- package/src/components/form/inputs/RichText/index.vue +81 -193
- package/src/components/form/inputs/RichText/richTextTypes.d.ts +77 -0
- package/src/components/form/inputs/RichText/utils/formatting.ts +98 -0
- package/src/components/form/inputs/RichText/utils/media.ts +42 -0
- package/src/components/form/inputs/RichText/utils/selection.ts +48 -0
- package/src/components/form/inputs/RichText/utils/table.ts +79 -0
- package/src/components/form/inputs/index.ts +1 -0
- package/src/components/form/inputs/RichText/Toolbar.vue +0 -87
- package/src/components/form/inputs/RichText/formatting.ts +0 -246
- package/src/components/form/inputs/RichText/richtext-types.ts +0 -29
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import type { ToolbarConfig, ToolbarConfigOption, ToolbarOption } from '../richTextTypes'
|
|
3
|
+
import { Btn, Dropdown } from '@bagelink/vue'
|
|
4
|
+
import { defaultToolbarConfig, toolbarOptions } from '../config'
|
|
5
|
+
import GridBox from './gridBox.vue'
|
|
6
|
+
|
|
7
|
+
const { config = defaultToolbarConfig, selectedStyles } = defineProps<{
|
|
8
|
+
config?: ToolbarConfig
|
|
9
|
+
selectedStyles: Set<string>
|
|
10
|
+
}>()
|
|
11
|
+
const emit = defineEmits(['action'])
|
|
12
|
+
|
|
13
|
+
const configToOption = (action: ToolbarConfigOption) => toolbarOptions.find(option => option.name === action) as ToolbarOption
|
|
14
|
+
|
|
15
|
+
function runAction(name: ToolbarConfigOption, value?: string) {
|
|
16
|
+
emit('action', name, value)
|
|
17
|
+
}
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<div class="toolbar flex gap-025 pb-05 flex-wrap" role="toolbar">
|
|
22
|
+
<template v-for="(action, index) in config.map(configToOption).filter(Boolean)" :key="index">
|
|
23
|
+
<Dropdown v-if="action.name === 'insertTable'" placement="bottom-start" thin flat icon="table">
|
|
24
|
+
<template #default="{ hide }">
|
|
25
|
+
<GridBox
|
|
26
|
+
:gridSize="5" @select="$event => {
|
|
27
|
+
runAction('insertTable', $event);
|
|
28
|
+
($event.target as any)?.blur();
|
|
29
|
+
hide()
|
|
30
|
+
}"
|
|
31
|
+
/>
|
|
32
|
+
</template>
|
|
33
|
+
</Dropdown>
|
|
34
|
+
<Btn
|
|
35
|
+
v-if="action.name !== 'separator'" v-tooltip="action.label" :icon="action.icon" thin flat
|
|
36
|
+
:aria-label="action.name" :class="[action.class, { active: selectedStyles.has(action.name) }]"
|
|
37
|
+
@click="runAction(action.name)"
|
|
38
|
+
/>
|
|
39
|
+
<span v-else-if="action.name === 'separator'" :key="`separator-${index}`" class="opacity-2 mb-025">|</span>
|
|
40
|
+
</template>
|
|
41
|
+
</div>
|
|
42
|
+
</template>
|
|
43
|
+
|
|
44
|
+
<style scoped>
|
|
45
|
+
.toolbar :deep(.active) {
|
|
46
|
+
background: var(--bgl-primary);
|
|
47
|
+
color: white;
|
|
48
|
+
}
|
|
49
|
+
</style>
|
|
50
|
+
|
|
51
|
+
<style scoped></style>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
defineProps<{ gridSize: number }>()
|
|
3
|
+
const emit = defineEmits(['select'])
|
|
4
|
+
const hoveredRow = $ref(-1)
|
|
5
|
+
const hoveredCol = $ref(-1)
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<template>
|
|
9
|
+
<div class="grid grid-wrap p-05">
|
|
10
|
+
<div
|
|
11
|
+
v-for="row in gridSize" :key="`row-${row}`" class="flex" @mouseout="hoveredRow = -1; hoveredCol = -1"
|
|
12
|
+
@focusout="hoveredRow = -1; hoveredCol = -1"
|
|
13
|
+
>
|
|
14
|
+
<div
|
|
15
|
+
v-for="col in 6" :key="`col-${col}`" role="button" tabindex="0" aria-label="Insert Table"
|
|
16
|
+
:style="{ width: '20px', height: '20px' }" class="border flex pointer"
|
|
17
|
+
:class="{ 'bg-gray-80': hoveredRow >= row && hoveredCol >= col }"
|
|
18
|
+
@mousemove="hoveredRow = row; hoveredCol = col" @click="emit('select', `${row}x${col}`)"
|
|
19
|
+
/>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
</template>
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import type { EditorState, Modal } from '../richTextTypes'
|
|
2
|
+
import { reactive } from 'vue'
|
|
3
|
+
import { formatting } from '../utils/formatting'
|
|
4
|
+
import { insertImage, insertLink } from '../utils/media'
|
|
5
|
+
import { isStyleActive } from '../utils/selection'
|
|
6
|
+
import { addRow, deleteRow, mergeCells, splitCell } from '../utils/table'
|
|
7
|
+
|
|
8
|
+
export function useEditor() {
|
|
9
|
+
const state = reactive<
|
|
10
|
+
EditorState
|
|
11
|
+
>({
|
|
12
|
+
isFullscreen: false,
|
|
13
|
+
hasInit: false,
|
|
14
|
+
isCodeView: false,
|
|
15
|
+
isSplitView: false,
|
|
16
|
+
selectedStyles: new Set<string>(),
|
|
17
|
+
rangeCount: 0,
|
|
18
|
+
content: '',
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const updateListStyles = (styles: Set<string>) => {
|
|
22
|
+
if (state.selection?.rangeCount) {
|
|
23
|
+
const node = state.selection.getRangeAt(0).commonAncestorContainer
|
|
24
|
+
const parentElement = node.nodeType === 3 ? node.parentElement : node
|
|
25
|
+
if (parentElement) {
|
|
26
|
+
const list = (parentElement as Element).closest('ul, ol')
|
|
27
|
+
if (list) {
|
|
28
|
+
styles.add(
|
|
29
|
+
list.tagName.toLowerCase() === 'ul'
|
|
30
|
+
? 'unorderedList'
|
|
31
|
+
: 'orderedList'
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const updateActiveStyles = () => {
|
|
39
|
+
if (!state.doc) return
|
|
40
|
+
const styles = new Set<string>()
|
|
41
|
+
const styleTypes = [
|
|
42
|
+
'bold',
|
|
43
|
+
'italic',
|
|
44
|
+
'underline',
|
|
45
|
+
'h1',
|
|
46
|
+
'h2',
|
|
47
|
+
'h3',
|
|
48
|
+
'h4',
|
|
49
|
+
'h5',
|
|
50
|
+
'h6',
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
styleTypes.forEach((style) => {
|
|
54
|
+
if (state.doc && isStyleActive(style, state.doc)) {
|
|
55
|
+
styles.add(style)
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
updateListStyles(styles)
|
|
60
|
+
state.selectedStyles = styles
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const updateSelection = () => {
|
|
64
|
+
if (!state.doc) return
|
|
65
|
+
state.selection = state.doc.getSelection()
|
|
66
|
+
if (!state.selection) return
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
if (!state.doc.body.contains(state.selection.anchorNode)) {
|
|
70
|
+
state.doc.body.focus()
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
state.rangeCount = state.selection.rangeCount
|
|
75
|
+
if (!state.rangeCount) {
|
|
76
|
+
const range = state.doc.createRange()
|
|
77
|
+
range.selectNodeContents(state.doc.body)
|
|
78
|
+
range.collapse(false)
|
|
79
|
+
state.selection.removeAllRanges()
|
|
80
|
+
state.selection.addRange(range)
|
|
81
|
+
}
|
|
82
|
+
state.range = state.selection.getRangeAt(0).cloneRange()
|
|
83
|
+
updateActiveStyles()
|
|
84
|
+
} catch (e) {
|
|
85
|
+
console.warn('Selection error:', e)
|
|
86
|
+
state.selection = null
|
|
87
|
+
state.range = null
|
|
88
|
+
state.rangeCount = 0
|
|
89
|
+
state.selectedStyles = new Set()
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const format = () => formatting(state)
|
|
94
|
+
|
|
95
|
+
const updateContent = (type?: string) => {
|
|
96
|
+
if (!state.doc) return
|
|
97
|
+
if (type === 'html') {
|
|
98
|
+
state.doc.body.innerHTML = state.content
|
|
99
|
+
} else {
|
|
100
|
+
state.content = state.doc.body.innerHTML
|
|
101
|
+
}
|
|
102
|
+
updateActiveStyles()
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const handleToolbarAction = (action: string, value?: string) => {
|
|
106
|
+
if (!state.doc) return
|
|
107
|
+
if (action === 'fullScreen') {
|
|
108
|
+
state.isFullscreen = !state.isFullscreen
|
|
109
|
+
return
|
|
110
|
+
}
|
|
111
|
+
if (action === 'splitView') {
|
|
112
|
+
state.isSplitView = !state.isSplitView
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
if (action === 'codeView') {
|
|
116
|
+
state.isCodeView = !state.isCodeView
|
|
117
|
+
return
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const applyFormatting = (command: string, value?: string) => {
|
|
121
|
+
const { selection, range } = state
|
|
122
|
+
if (!state.doc || !state.modal || !selection || !range) return
|
|
123
|
+
|
|
124
|
+
// Check if there is a selection or just a caret position
|
|
125
|
+
const isCaret = selection.isCollapsed
|
|
126
|
+
|
|
127
|
+
if (!state.doc.body.contains(selection.anchorNode)) {
|
|
128
|
+
state.doc.body.focus()
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
switch (command) {
|
|
132
|
+
case 'mergeCells':
|
|
133
|
+
if (isCaret) return
|
|
134
|
+
mergeCells(range, state.doc)
|
|
135
|
+
break
|
|
136
|
+
case 'splitCells':
|
|
137
|
+
if (isCaret) return
|
|
138
|
+
splitCell(range, state.doc)
|
|
139
|
+
break
|
|
140
|
+
case 'addRowBefore':
|
|
141
|
+
case 'addRowAfter':
|
|
142
|
+
if (isCaret) return
|
|
143
|
+
addRow(
|
|
144
|
+
command === 'addRowBefore' ? 'before' : 'after',
|
|
145
|
+
range,
|
|
146
|
+
state.doc
|
|
147
|
+
)
|
|
148
|
+
break
|
|
149
|
+
case 'deleteRow':
|
|
150
|
+
if (isCaret) return
|
|
151
|
+
deleteRow(range)
|
|
152
|
+
break
|
|
153
|
+
case 'bold':
|
|
154
|
+
case 'italic':
|
|
155
|
+
case 'underline':
|
|
156
|
+
format().text(command)
|
|
157
|
+
break
|
|
158
|
+
case 'orderedList':
|
|
159
|
+
case 'unorderedList':
|
|
160
|
+
format().list(command)
|
|
161
|
+
break
|
|
162
|
+
case 'image':
|
|
163
|
+
case 'youtube':
|
|
164
|
+
if (isCaret) return
|
|
165
|
+
insertImage(state.modal, state.doc, range)
|
|
166
|
+
break
|
|
167
|
+
case 'link':
|
|
168
|
+
if (isCaret) return
|
|
169
|
+
insertLink(state.modal, state.doc, range)
|
|
170
|
+
break
|
|
171
|
+
default:
|
|
172
|
+
if (/^h[1-6]$/.test(command)) {
|
|
173
|
+
format().block(command, value || command)
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
state.doc.body.focus()
|
|
178
|
+
applyFormatting(action, value)
|
|
179
|
+
updateContent()
|
|
180
|
+
updateActiveStyles()
|
|
181
|
+
}
|
|
182
|
+
const setupEventListeners = () => {
|
|
183
|
+
if (!state.doc) return
|
|
184
|
+
state.doc.addEventListener('selectionchange', () => { updateSelection() })
|
|
185
|
+
state.doc.addEventListener('input', () => { updateContent() })
|
|
186
|
+
state.doc.addEventListener('mouseup', () => { updateSelection() })
|
|
187
|
+
state.doc.addEventListener('keyup', (e) => {
|
|
188
|
+
if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(e.key)) {
|
|
189
|
+
updateSelection()
|
|
190
|
+
}
|
|
191
|
+
})
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const init = (doc: Document, modal: Modal) => {
|
|
195
|
+
state.doc = doc
|
|
196
|
+
state.modal = modal
|
|
197
|
+
setupEventListeners()
|
|
198
|
+
updateContent('html')
|
|
199
|
+
state.hasInit = true
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
state,
|
|
204
|
+
init,
|
|
205
|
+
handleToolbarAction,
|
|
206
|
+
updateContent,
|
|
207
|
+
}
|
|
208
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
export function useEditorKeyboard(doc: Document, handleToolbarAction: (action: string, value?: string) => void): void {
|
|
3
|
+
doc.addEventListener('keydown', (e) => {
|
|
4
|
+
if (e.ctrlKey || e.metaKey) {
|
|
5
|
+
switch (e.key) {
|
|
6
|
+
case 'b':
|
|
7
|
+
e.preventDefault()
|
|
8
|
+
handleToolbarAction('bold')
|
|
9
|
+
break
|
|
10
|
+
case 'i':
|
|
11
|
+
e.preventDefault()
|
|
12
|
+
handleToolbarAction('italic')
|
|
13
|
+
break
|
|
14
|
+
case 'u':
|
|
15
|
+
e.preventDefault()
|
|
16
|
+
handleToolbarAction('underline')
|
|
17
|
+
break
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
})
|
|
21
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { ToolbarConfig, ToolbarOption } from './richTextTypes'
|
|
2
|
+
|
|
3
|
+
export const tableTools: ToolbarConfig = [
|
|
4
|
+
'mergeCells',
|
|
5
|
+
'splitCells',
|
|
6
|
+
'addRowBefore',
|
|
7
|
+
'addRowAfter',
|
|
8
|
+
'deleteRow'
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
export const defaultToolbarConfig: ToolbarConfig = [
|
|
12
|
+
'h2',
|
|
13
|
+
'h3',
|
|
14
|
+
'h4',
|
|
15
|
+
'h5',
|
|
16
|
+
'h6',
|
|
17
|
+
'separator',
|
|
18
|
+
'bold',
|
|
19
|
+
'italic',
|
|
20
|
+
'underline',
|
|
21
|
+
'separator',
|
|
22
|
+
'orderedList',
|
|
23
|
+
'unorderedList',
|
|
24
|
+
'separator',
|
|
25
|
+
'link',
|
|
26
|
+
'image',
|
|
27
|
+
'youtube',
|
|
28
|
+
'separator',
|
|
29
|
+
'splitView',
|
|
30
|
+
'clear',
|
|
31
|
+
'insertTable',
|
|
32
|
+
...tableTools, // Adding table tools to the default toolbar
|
|
33
|
+
'fullScreen',
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
export const toolbarOptions: ToolbarOption[] = [
|
|
37
|
+
{ name: 'h2', label: 'h2', icon: 'format_h2' },
|
|
38
|
+
{ name: 'h3', label: 'h3', icon: 'format_h3' },
|
|
39
|
+
{ name: 'h4', label: 'h4', icon: 'format_h4' },
|
|
40
|
+
{ name: 'h5', label: 'h5', icon: 'format_h5' },
|
|
41
|
+
{ name: 'h6', label: 'h6', icon: 'format_h6' },
|
|
42
|
+
{ name: 'bold', label: 'Bold', icon: 'format_bold' },
|
|
43
|
+
{ name: 'italic', label: 'Italic', icon: 'format_italic' },
|
|
44
|
+
{ name: 'underline', label: 'Underline', icon: 'format_underlined' },
|
|
45
|
+
{ name: 'orderedList', label: 'Ordered List', icon: 'format_list_numbered' },
|
|
46
|
+
{ name: 'unorderedList', label: 'Unordered List', icon: 'format_list_bulleted' },
|
|
47
|
+
{ name: 'link', label: 'Link', icon: 'add_link' },
|
|
48
|
+
{ name: 'image', label: 'Image', icon: 'add_photo_alternate' },
|
|
49
|
+
{ name: 'youtube', label: 'YouTube', icon: 'youtube_activity' },
|
|
50
|
+
{ name: 'splitView', label: 'Split View', icon: 'code' },
|
|
51
|
+
{ name: 'clear', label: 'Clear Formatting', icon: 'format_clear' },
|
|
52
|
+
{ name: 'alignLeft', label: 'Align Left', icon: 'format_align_left' },
|
|
53
|
+
{ name: 'alignCenter', label: 'Align Center', icon: 'format_align_center' },
|
|
54
|
+
{ name: 'alignRight', label: 'Align Right', icon: 'format_align_right' },
|
|
55
|
+
{ name: 'alignJustify', label: 'Align Justify', icon: 'format_align_justify' },
|
|
56
|
+
{ name: 'indent', label: 'Indent', icon: 'format_indent_increase' },
|
|
57
|
+
{ name: 'outdent', label: 'Outdent', icon: 'format_indent_decrease' },
|
|
58
|
+
{ name: 'fontColor', label: 'Font Color', icon: 'format_color_text' },
|
|
59
|
+
{ name: 'bgColor', label: 'Background Color', icon: 'format_color_fill' },
|
|
60
|
+
{ name: 'insertTable', label: 'Insert Table', icon: 'table' },
|
|
61
|
+
{ name: 'deleteTable', label: 'Delete Table', icon: 'table_rows' },
|
|
62
|
+
{ name: 'insertRowAbove', label: 'Insert Row Above', icon: 'table_rows' },
|
|
63
|
+
{ name: 'insertRowBelow', label: 'Insert Row Below', icon: 'table_rows' },
|
|
64
|
+
{ name: 'deleteRow', label: 'Delete Row', icon: 'table_rows' },
|
|
65
|
+
{ name: 'insertColumnLeft', label: 'Insert Column Left', icon: 'add_column_left' },
|
|
66
|
+
{ name: 'insertColumnRight', label: 'Insert Column Right', icon: 'add_column_right' },
|
|
67
|
+
{ name: 'deleteColumn', label: 'Delete Column', icon: 'view_column' },
|
|
68
|
+
{ name: 'separator' },
|
|
69
|
+
{ name: 'undo', label: 'Undo', icon: 'undo' },
|
|
70
|
+
{ name: 'redo', label: 'Redo', icon: 'redo' },
|
|
71
|
+
{ name: 'separator' },
|
|
72
|
+
{ name: 'fullScreen', label: 'Full Screen', icon: 'fullscreen', class: 'ms-auto' },
|
|
73
|
+
]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
body {
|
|
2
|
+
margin: 0;
|
|
3
|
+
padding: 8px;
|
|
4
|
+
min-height: 200px;
|
|
5
|
+
font-family: sans-serif;
|
|
6
|
+
color: inherit;
|
|
7
|
+
background: transparent;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
table {
|
|
11
|
+
border-collapse: collapse;
|
|
12
|
+
margin-bottom: 1rem;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
th,
|
|
16
|
+
td {
|
|
17
|
+
padding: 1rem;
|
|
18
|
+
text-align: left;
|
|
19
|
+
border: 1px solid #ddd;
|
|
20
|
+
line-height: 1.5;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
th {
|
|
24
|
+
background-color: #f4f4f4;
|
|
25
|
+
}
|