refactor: 类型补充、优化

This commit is contained in:
pipipi-pikachu 2023-07-13 21:19:59 +08:00
parent e666c30c19
commit 2c22196501
24 changed files with 88 additions and 35 deletions

View File

@ -20,7 +20,10 @@ const props = defineProps({
},
})
const checkboardCache = {}
interface CheckboardCache {
[key: string]: string | null
}
const checkboardCache: CheckboardCache = {}
const renderCheckboard = (white: string, grey: string, size: number) => {
const canvas = document.createElement('canvas')

View File

@ -1,4 +1,4 @@
export const ELEMENT_TYPE_ZH = {
export const ELEMENT_TYPE_ZH: { [key: string]: string } = {
text: '文本',
image: '图片',
shape: '形状',
@ -10,7 +10,7 @@ export const ELEMENT_TYPE_ZH = {
latex: '公式',
}
export const MIN_SIZE = {
export const MIN_SIZE: { [key: string]: number } = {
text: 20,
image: 20,
shape: 15,

View File

@ -14,7 +14,17 @@ export const enum ClipPaths {
STAR = 'star',
}
export const CLIPPATHS = {
interface ClipPath {
[key: string]: {
name: string
type: ClipPathTypes
style: string
radius?: string
createPath?: (width: number, height: number) => string
}
}
export const CLIPPATHS: ClipPath = {
rect: {
name: '矩形',
type: ClipPathTypes.RECT,

View File

@ -5,6 +5,10 @@ import { ElementAlignCommands } from '@/types/edit'
import { getElementListRange, getRectRotatedOffset } from '@/utils/element'
import useHistorySnapshot from './useHistorySnapshot'
interface RangeMap {
[id: string]: ReturnType<typeof getElementListRange>
}
export default () => {
const slidesStore = useSlidesStore()
const { activeElementIdList, activeElementList } = storeToRefs(useMainStore())
@ -21,7 +25,7 @@ export default () => {
const elementList: PPTElement[] = JSON.parse(JSON.stringify(currentSlide.value.elements))
// 如果所选择的元素为组合元素的成员,需要计算该组合的整体范围
const groupElementRangeMap = {}
const groupElementRangeMap: RangeMap = {}
for (const activeElement of activeElementList.value) {
if (activeElement.groupId && !groupElementRangeMap[activeElement.groupId]) {
const groupElements = activeElementList.value.filter(item => item.groupId === activeElement.groupId)

View File

@ -88,7 +88,7 @@ export default () => {
let indent = 0
const slices: pptxgen.TextProps[] = []
const parse = (obj: AST[], baseStyleObj = {}) => {
const parse = (obj: AST[], baseStyleObj: { [key: string]: string } = {}) => {
for (const item of obj) {
const isBlockTag = 'tagName' in item && ['div', 'li', 'p'].includes(item.tagName)
@ -186,7 +186,7 @@ export default () => {
if (styleObj['vertical-align'] === 'super') options.superscript = true
if (styleObj['vertical-align'] === 'sub') options.subscript = true
}
if (styleObj['text-align']) options.align = styleObj['text-align']
if (styleObj['text-align']) options.align = styleObj['text-align'] as pptxgen.HAlign
if (styleObj['font-weight']) options.bold = styleObj['font-weight'] === 'bold'
if (styleObj['font-style']) options.italic = styleObj['font-style'] === 'italic'
if (styleObj['font-family']) options.fontFace = styleObj['font-family']

View File

@ -46,7 +46,7 @@ export default () => {
// 创建原颜色与新颜色的对应关系表
const createSlideThemeColorMap = (slide: Slide, newColors: string[]): { [key: string]: string } => {
const oldColors = getSlideAllColors(slide)
const themeColorMap = {}
const themeColorMap: { [key: string]: string } = {}
if (oldColors.length > newColors.length) {
const analogous = tinycolor(newColors[0]).analogous(oldColors.length - newColors.length + 10)

View File

@ -2,6 +2,10 @@ import { Directive, DirectiveBinding } from 'vue'
const CTX_CLICK_OUTSIDE_HANDLER = 'CTX_CLICK_OUTSIDE_HANDLER'
interface CustomHTMLElement extends HTMLElement {
[CTX_CLICK_OUTSIDE_HANDLER]?: (event: MouseEvent) => void
}
const clickListener = (el: HTMLElement, event: MouseEvent, binding: DirectiveBinding) => {
const handler = binding.value
@ -13,14 +17,14 @@ const clickListener = (el: HTMLElement, event: MouseEvent, binding: DirectiveBin
}
const ClickOutsideDirective: Directive = {
mounted(el: HTMLElement, binding) {
mounted(el: CustomHTMLElement, binding) {
el[CTX_CLICK_OUTSIDE_HANDLER] = (event: MouseEvent) => clickListener(el, event, binding)
setTimeout(() => {
document.addEventListener('click', el[CTX_CLICK_OUTSIDE_HANDLER])
document.addEventListener('click', el[CTX_CLICK_OUTSIDE_HANDLER]!)
}, 0)
},
unmounted(el: HTMLElement) {
unmounted(el: CustomHTMLElement) {
if (el[CTX_CLICK_OUTSIDE_HANDLER]) {
document.removeEventListener('click', el[CTX_CLICK_OUTSIDE_HANDLER])
delete el[CTX_CLICK_OUTSIDE_HANDLER]

View File

@ -3,6 +3,10 @@ import ContextmenuComponent from '@/components/Contextmenu/index.vue'
const CTX_CONTEXTMENU_HANDLER = 'CTX_CONTEXTMENU_HANDLER'
interface CustomHTMLElement extends HTMLElement {
[CTX_CONTEXTMENU_HANDLER]?: (event: MouseEvent) => void
}
const contextmenuListener = (el: HTMLElement, event: MouseEvent, binding: DirectiveBinding) => {
event.stopPropagation()
event.preventDefault()
@ -44,12 +48,12 @@ const contextmenuListener = (el: HTMLElement, event: MouseEvent, binding: Direct
}
const ContextmenuDirective: Directive = {
mounted(el: HTMLElement, binding) {
mounted(el: CustomHTMLElement, binding) {
el[CTX_CONTEXTMENU_HANDLER] = (event: MouseEvent) => contextmenuListener(el, event, binding)
el.addEventListener('contextmenu', el[CTX_CONTEXTMENU_HANDLER])
},
unmounted(el: HTMLElement) {
unmounted(el: CustomHTMLElement) {
if (el && el[CTX_CONTEXTMENU_HANDLER]) {
el.removeEventListener('contextmenu', el[CTX_CONTEXTMENU_HANDLER])
delete el[CTX_CONTEXTMENU_HANDLER]

View File

@ -114,7 +114,11 @@ import {
StopwatchStart,
} from '@icon-park/vue-next'
export const icons = {
interface Icons {
[key: string]: typeof PlayOne
}
export const icons: Icons = {
IconPlayOne: PlayOne,
IconFullScreenPlay: FullScreenPlay,
IconLock: Lock,

View File

@ -92,6 +92,8 @@ export interface CreatingLineElement {
}
export type CreatingElement = CreatingTextElement | CreatingShapeElement | CreatingLineElement
export type TextFormatPainterKeys = 'bold' | 'em' | 'underline' | 'strikethrough' | 'color' | 'backcolor' | 'fontsize' | 'fontname' | 'align'
export interface TextFormatPainter {
bold?: boolean
em?: boolean

View File

@ -194,6 +194,7 @@ export interface ImageOrShapeFlip {
*
* 'opacity'?: 100%
*/
export type ImageElementFilterKeys = 'blur' | 'brightness' | 'contrast' | 'grayscale' | 'saturate' | 'hue-rotate' | 'opacity'
export interface ImageElementFilters {
'blur'?: string
'brightness'?: string

View File

@ -10,6 +10,10 @@ interface RotatedElementData {
rotate: number
}
interface IdMap {
[id: string]: string
}
/**
*
* @param element
@ -158,7 +162,7 @@ export const uniqAlignLines = (lines: AlignLine[]) => {
* @param slides
*/
export const createSlideIdMap = (slides: Slide[]) => {
const slideIdMap = {}
const slideIdMap: IdMap = {}
for (const slide of slides) {
slideIdMap[slide.id] = nanoid(10)
}
@ -172,8 +176,8 @@ export const createSlideIdMap = (slides: Slide[]) => {
* @param elements
*/
export const createElementIdMap = (elements: PPTElement[]) => {
const groupIdMap = {}
const elIdMap = {}
const groupIdMap: IdMap = {}
const elIdMap: IdMap = {}
for (const element of elements) {
const groupId = element.groupId
if (groupId && !groupIdMap[groupId]) {

View File

@ -26,7 +26,7 @@ export const hasTerminalParent = (tagName: string, stack: StackItem[]) => {
while (currentIndex >= 0) {
const parentTagName = stack[currentIndex].tagName
if (parentTagName === tagName) break
if (tagParents.includes(parentTagName)) return true
if (parentTagName && tagParents.includes(parentTagName)) return true
currentIndex--
}
}

View File

@ -2,7 +2,11 @@ export const childlessTags = ['style', 'script', 'template']
export const closingTags = ['html', 'head', 'body', 'p', 'dt', 'dd', 'li', 'option', 'thead', 'th', 'tbody', 'tr', 'td', 'tfoot', 'colgroup']
export const closingTagAncestorBreakers = {
interface ClosingTagAncestorBreakers {
[key: string]: string[]
}
export const closingTagAncestorBreakers: ClosingTagAncestorBreakers = {
li: ['ul', 'ol', 'menu'],
dt: ['dl'],
dd: ['dl'],

View File

@ -15,8 +15,12 @@ import {
splitBlockKeepMarks,
} from 'prosemirror-commands'
interface Keys {
[key: string]: Command
}
export const buildKeymap = (schema: Schema) => {
const keys = {}
const keys: Keys = {}
const bind = (key: string, cmd: Command) => keys[key] = cmd
bind('Alt-ArrowUp', joinUp)

View File

@ -2,6 +2,10 @@ import { nodes } from 'prosemirror-schema-basic'
import { Node, NodeSpec } from 'prosemirror-model'
import { listItem as _listItem } from 'prosemirror-schema-list'
interface Attr {
[key: string]: number | string
}
const orderedList: NodeSpec = {
attrs: {
order: {
@ -18,7 +22,7 @@ const orderedList: NodeSpec = {
tag: 'ol',
getAttrs: dom => {
const order = ((dom as HTMLElement).hasAttribute('start') ? (dom as HTMLElement).getAttribute('start') : 1) || 1
const attr = { order: +order }
const attr: Attr = { order: +order }
const { listStyleType } = (dom as HTMLElement).style
if (listStyleType) attr['listStyleType'] = listStyleType
@ -32,7 +36,7 @@ const orderedList: NodeSpec = {
let style = ''
if (listStyleType) style += `list-style-type: ${listStyleType};`
const attr = { style }
const attr: Attr = { style }
if (order !== 1) attr['start'] = order
@ -111,7 +115,7 @@ const paragraph: NodeSpec = {
let style = ''
if (align && align !== 'left') style += `text-align: ${align};`
const attr = { style }
const attr: Attr = { style }
if (indent) attr['data-indent'] = indent
return ['p', attr, 0]

View File

@ -79,7 +79,7 @@ const getRotateElementPoints = (element: RotateElementData, angle: number) => {
* @param direction
* @param points
*/
const getOppositePoint = (direction: string, points: ReturnType<typeof getRotateElementPoints>): { left: number; top: number } => {
const getOppositePoint = (direction: OperateResizeHandlers, points: ReturnType<typeof getRotateElementPoints>): { left: number; top: number } => {
const oppositeMap = {
[OperateResizeHandlers.RIGHT_BOTTOM]: points.leftTopPoint,
[OperateResizeHandlers.LEFT_BOTTOM]: points.rightTopPoint,

View File

@ -53,7 +53,8 @@ const currentDialogComponent = computed(() => {
'pptx': ExportPPTX,
'pptist': ExportSpecificFile,
}
return dialogMap[dialogForExport.value] || null
if (dialogForExport.value) return dialogMap[dialogForExport.value] || null
return null
})
</script>

View File

@ -18,7 +18,7 @@
class="shape-clip-item"
v-for="(item, key) in shapeClipPathOptions"
:key="key"
@click="presetImageClip(key)"
@click="presetImageClip(key as string)"
>
<div class="shape" :style="{ clipPath: item.style }"></div>
</div>

View File

@ -29,14 +29,14 @@
import { ref, watch } from 'vue'
import { storeToRefs } from 'pinia'
import { useMainStore, useSlidesStore } from '@/store'
import { PPTImageElement } from '@/types/slides'
import { ImageElementFilterKeys, PPTImageElement } from '@/types/slides'
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
import { Slider, Switch } from 'ant-design-vue'
interface FilterOption {
label: string
key: string
key: ImageElementFilterKeys
default: number
value: number
unit: string
@ -68,7 +68,8 @@ watch(handleElement, () => {
const filters = handleElement.value.filters
if (filters) {
filterOptions.value = defaultFilters.map(item => {
if (filters[item.key] !== undefined) return { ...item, value: parseInt(filters[item.key]) }
const filterItem = filters[item.key]
if (filterItem) return { ...item, value: parseInt(filterItem) }
return item
})
hasFilters.value = true

View File

@ -18,7 +18,7 @@
:width="elementInfo.width"
:height="elementInfo.height"
:outline="elementInfo.outline"
:createPath="clipShape.createPath"
:createPath="clipShape.createPath!"
/>
</div>
</template>

View File

@ -1,11 +1,12 @@
import { computed, Ref } from 'vue'
import { ImageElementFilters } from '@/types/slides'
import { ImageElementFilters, ImageElementFilterKeys } from '@/types/slides'
export default (filters: Ref<ImageElementFilters | undefined>) => {
const filter = computed(() => {
if (!filters.value) return ''
let filter = ''
for (const key of Object.keys(filters.value)) {
const keys = Object.keys(filters.value) as ImageElementFilterKeys[]
for (const key of keys) {
filter += `${key}(${filters.value[key]}) `
}
return filter

View File

@ -45,7 +45,7 @@ const pathMap = {
dot: 'm0 5a5 5 0 1 0 10 0a5 5 0 1 0 -10 0z',
arrow: 'M0,0 L10,5 0,10 Z',
}
const rotateMap = {
const rotateMap: { [key: string]: number } = {
'arrow-start': 180,
'arrow-end': 0,
}

View File

@ -20,6 +20,7 @@ import emitter, { EmitterEvents, RichTextAction, RichTextCommand } from '@/utils
import { alignmentCommand } from '@/utils/prosemirror/commands/setTextAlign'
import { indentCommand } from '@/utils/prosemirror/commands/setTextIndent'
import { toggleList } from '@/utils/prosemirror/commands/toggleList'
import { TextFormatPainterKeys } from '@/types/edit'
const props = defineProps({
elementId: {
@ -242,10 +243,11 @@ const handleMouseup = () => {
if (!textFormatPainter.value) return
const actions: RichTextAction[] = [{ command: 'clear' }]
for (const key of Object.keys(textFormatPainter.value)) {
for (const key of Object.keys(textFormatPainter.value) as TextFormatPainterKeys[]) {
const command = key
const value = textFormatPainter.value[key]
if (value) actions.push({ command, value })
if (value === true) actions.push({ command })
else if (value) actions.push({ command, value })
}
execCommand({ action: actions })
mainStore.setTextFormatPainter(null)