UNPKG

@cloudgpt/timeline-editor

Version:

Enhanced React timeline editor with advanced features including theme system, max duration controls, cursor customization, handle styling, and media support for video editing applications.

582 lines (581 loc) 15.2 kB
import React, { ReactNode } from 'react'; import { OnScrollParams } from 'react-virtualized'; import { ITimelineEngine } from '..'; import { Emitter } from '../engine/emitter'; import { EventTypes } from '../engine/events'; import { TimelineAction, TimelineRow } from './action'; import { TimelineEffect } from './effect'; export * from './action'; export * from './effect'; export interface ThemeConfig { /** * @description 主背景色 * @default '#191b1d' */ backgroundColor?: string; /** * @description 主前景色(文字颜色) * @default '#ffffff' */ foregroundColor?: string; /** * @description 网格线颜色 * @default 'rgba(255, 255, 255, 0.08)' */ gridColor?: string; /** * @description 光标颜色 * @default '#ff6b35' */ cursorColor?: string; /** * @description 选中状态颜色 * @default '#0078d4' */ selectionColor?: string; /** * @description 行背景色 * @default 'transparent' */ rowBackgroundColor?: string; /** * @description 行边框色 * @default 'rgba(255, 255, 255, 0.1)' */ rowBorderColor?: string; /** * @description 动作默认背景色 * @default '#2f3134' */ actionBackgroundColor?: string; /** * @description 动作边框色 * @default 'rgba(255, 255, 255, 0.2)' */ actionBorderColor?: string; /** * @description 拖拽辅助线颜色 * @default '#ff6b35' */ dragLineColor?: string; /** * @description 时间刻度文字颜色 * @default '#ffffff' */ scaleTextColor?: string; /** * @description 时间刻度背景色 * @default '#242629' */ scaleBackgroundColor?: string; } export interface CursorConfig { /** * @description 光标颜色 * @default '#ff6b35' */ cursorColor?: string; /** * @description 光标宽度 * @default 2 */ cursorWidth?: number; /** * @description 光标样式(实线、虚线等) * @default 'solid' */ cursorStyle?: 'solid' | 'dashed' | 'dotted'; /** * @description 光标透明度 * @default 1 */ cursorOpacity?: number; /** * @description 光标头部显示 * @default true */ showCursorHead?: boolean; /** * @description 光标头部颜色 * @default 'inherit' */ cursorHeadColor?: string; /** * @description 光标头部大小 * @default 10 */ cursorHeadSize?: number; /** * @description 光标阴影 * @default 'none' */ cursorShadow?: string; /** * @description 光标z-index * @default 100 */ cursorZIndex?: number; } export interface SizingConfig { /** * @description 动作圆角半径 * @default 4 */ actionBorderRadius?: number; /** * @description 动作边框宽度 * @default 1 */ actionBorderWidth?: number; /** * @description 拖拽手柄宽度 * @default 14 */ handleWidth?: number; /** * @description 拖拽手柄高度占比(0-1) * @default 0.7 */ handleHeightRatio?: number; /** * @description 拖拽手柄圆角半径 * @default 999 */ handleBorderRadius?: number; /** * @description 时间区域高度 * @default 32 */ timeAreaHeight?: number; /** * @description 控制区域宽度 * @default 200 */ controlAreaWidth?: number; } export interface HandleConfig { /** * @description 拖拽手柄背景色 * @default 'linear-gradient(180deg, rgba(255,255,255,.18), rgba(255,255,255,.08))' */ handleBackground?: string; /** * @description 拖拽手柄边框色 * @default 'rgba(255,255,255,.2)' */ handleBorderColor?: string; /** * @description 拖拽手柄悬浮时透明度 * @default 1 */ handleHoverOpacity?: number; /** * @description 拖拽手柄默认透明度 * @default 0 */ handleOpacity?: number; /** * @description 是否显示拖拽手柄 * @default true */ showHandles?: boolean; } export interface AnimationConfig { /** * @description 拖拽手柄显示/隐藏动画持续时间(ms) * @default 120 */ handleTransitionDuration?: number; /** * @description 拖拽手柄动画缓动函数 * @default 'ease-in-out' */ handleTransitionEasing?: string; /** * @description 动作悬浮时缩放比例 * @default 1.02 */ actionHoverScale?: number; /** * @description 动作悬浮动画持续时间(ms) * @default 150 */ actionHoverDuration?: number; /** * @description 光标移动动画持续时间(ms) * @default 300 */ cursorTransitionDuration?: number; /** * @description 是否启用动画 * @default true */ enableAnimations?: boolean; } export interface BehaviorConfig { /** * @description 动作拖拽灵敏度 * @default 1 */ dragSensitivity?: number; /** * @description 缩放灵敏度 * @default 1 */ resizeSensitivity?: number; /** * @description 双击动作时的行为('select' | 'edit' | 'none') * @default 'select' */ doubleClickAction?: 'select' | 'edit' | 'none'; /** * @description 右键菜单行为('show' | 'hide') * @default 'show' */ contextMenuBehavior?: 'show' | 'hide'; /** * @description 是否允许多选 * @default false */ allowMultiSelection?: boolean; /** * @description 选择模式('single' | 'multiple' | 'range') * @default 'single' */ selectionMode?: 'single' | 'multiple' | 'range'; /** * @description 拖拽越界时的行为('clamp' | 'reject' | 'allow') * @default 'clamp' */ dragBoundsBehavior?: 'clamp' | 'reject' | 'allow'; } export interface EditData { /** * @description 时间轴编辑数据 */ editorData: TimelineRow[]; /** * @description 时间轴动作效果map */ effects: Record<string, TimelineEffect>; /** * @description 主题配置 */ theme?: ThemeConfig; /** * @description 尺寸配置 */ sizing?: SizingConfig; /** * @description 手柄配置 */ handles?: HandleConfig; /** * @description 光标配置 */ cursor?: CursorConfig; /** * @description 动画配置 */ animations?: AnimationConfig; /** * @description 交互行为配置 */ behavior?: BehaviorConfig; /** * @description 单个刻度标记范畴(>0) * @default 1 */ scale?: number; /** * @description 最少刻度个数(>=1) * @default 20 */ minScaleCount?: number; /** * @description 最大刻度个数(>=minScaleCount) * @default Infinity */ maxScaleCount?: number; /** * @description 时间轴最大持续时间(秒) * @default Infinity */ maxDuration?: number; /** * @description 单个刻度细分单元数(>0整数) * @default 10 */ scaleSplitCount?: number; /** * @description 单个刻度的显示宽度(>0, 单位:px) * @default 160 */ scaleWidth?: number; /** * @description 刻度开始距离左侧的距离(>=0, 单位:px) * @default 20 */ startLeft?: number; /** * @description 每个编辑行默认高度(>0, 单位:px) * @default 32 */ rowHeight?: number; /** * @description 行内上下留白(>=0, 单位:px)。用于控制action在行内的上下间距,避免视觉上顶到边缘 * @default 0 */ rowGap?: number; /** * @description 是否启动网格移动吸附 * @default false */ gridSnap?: boolean; /** * @description 启动拖拽辅助线吸附 * @default false */ dragLine?: boolean; /** * @description 是否隐藏光标 * @default false */ hideCursor?: boolean; /** * @description 禁止全部动作区域拖动 * @default false */ disableDrag?: boolean; /** * @description timeline运行器,不传则使用内置运行器 */ engine?: ITimelineEngine; /** * @description 自定义action区域渲染 */ getActionRender?: (action: TimelineAction, row: TimelineRow) => ReactNode; /** * @description 自定义scale渲染 */ getScaleRender?: (scale: number) => ReactNode; /** * @description 开始移动回调 */ onActionMoveStart?: (params: { action: TimelineAction; row: TimelineRow; }) => void; /** * @description 移动回调(return false可阻止移动) */ onActionMoving?: (params: { action: TimelineAction; row: TimelineRow; start: number; end: number; }) => void | boolean; /** * @description 移动结束回调(return false可阻止onChange触发) */ onActionMoveEnd?: (params: { action: TimelineAction; row: TimelineRow; start: number; end: number; }) => void; /** * @description 开始改变大小回调 */ onActionResizeStart?: (params: { action: TimelineAction; row: TimelineRow; dir: 'right' | 'left'; }) => void; /** * @description 开始大小回调(return false可阻止改变) */ onActionResizing?: (params: { action: TimelineAction; row: TimelineRow; start: number; end: number; dir: 'right' | 'left'; }) => void | boolean; /** * @description 改变大小结束回调(return false可阻止onChange触发) */ onActionResizeEnd?: (params: { action: TimelineAction; row: TimelineRow; start: number; end: number; dir: 'right' | 'left'; }) => void; /** * @description 点击行回调 */ onClickRow?: (e: React.MouseEvent<HTMLElement, MouseEvent>, param: { row: TimelineRow; time: number; }) => void; /** * @description 点击动作回调 */ onClickAction?: (e: React.MouseEvent<HTMLElement, MouseEvent>, param: { action: TimelineAction; row: TimelineRow; time: number; }) => void; /** * @description 点击动作回调(触发drag时不执行) */ onClickActionOnly?: (e: React.MouseEvent<HTMLElement, MouseEvent>, param: { action: TimelineAction; row: TimelineRow; time: number; }) => void; /** * @description 双击行回调 */ onDoubleClickRow?: (e: React.MouseEvent<HTMLElement, MouseEvent>, param: { row: TimelineRow; time: number; }) => void; /** * @description 双击动作回调 */ onDoubleClickAction?: (e: React.MouseEvent<HTMLElement, MouseEvent>, param: { action: TimelineAction; row: TimelineRow; time: number; }) => void; /** * @description 右键行回调 */ onContextMenuRow?: (e: React.MouseEvent<HTMLElement, MouseEvent>, param: { row: TimelineRow; time: number; }) => void; /** * @description 右键动作回调 */ onContextMenuAction?: (e: React.MouseEvent<HTMLElement, MouseEvent>, param: { action: TimelineAction; row: TimelineRow; time: number; }) => void; /** * @description 获取要提示辅助线的action id列表,在move/resize start 时进行计算,默认获取除当前移动action的全部 */ getAssistDragLineActionIds?: (params: { action: TimelineAction; editorData: TimelineRow[]; row: TimelineRow; }) => string[]; /** * @description cursor开始拖拽事件 */ onCursorDragStart?: (time: number) => void; /** * @description cursor结束拖拽事件 */ onCursorDragEnd?: (time: number) => void; /** * @description cursor拖拽事件 */ onCursorDrag?: (time: number) => void; /** * @description 点击时间区域事件, 返回false时阻止设置时间 */ onClickTimeArea?: (time: number, e: React.MouseEvent<HTMLDivElement, MouseEvent>) => boolean | undefined; /** * @description 验证动作开始/结束时间变更(移动或缩放中)。返回false将阻止变更 */ validateActionChange?: (params: { action: TimelineAction; row: TimelineRow; start: number; end: number; dir?: 'right' | 'left'; }) => boolean; } export interface TimelineState { /** dom节点 */ target: HTMLElement; /** 运行监听器 */ listener: Emitter<EventTypes>; /** 是否正在播放 */ isPlaying: boolean; /** 是否暂停中 */ isPaused: boolean; /** 设置当前播放时间 */ setTime: (time: number) => void; /** 获取当前播放时间 */ getTime: () => number; /** 设置播放速率 */ setPlayRate: (rate: number) => void; /** 设置播放速率 */ getPlayRate: () => number; /** 重新渲染当前时间 */ reRender: () => void; /** 播放 */ play: (param: { /** 默认从头运行到尾, 优先级大于autoEnd */ toTime?: number; /** 是否播放完后自动结束 */ autoEnd?: boolean; /** 运行的actionId列表,不穿默认全部运行 */ runActionIds?: string[]; }) => boolean; /** 暂停 */ pause: () => void; /** 设置scroll left */ setScrollLeft: (val: number) => void; /** 设置scroll top */ setScrollTop: (val: number) => void; } /** * 动画编辑器参数 * @export * @interface TimelineProp */ export interface TimelineEditor extends EditData { /** * @description 编辑区域距离顶部滚动距离 (请使用ref.setScrollTop代替) * @deprecated */ scrollTop?: number; /** * @description 编辑区域滚动回调 (用于控制与编辑行滚动同步) */ onScroll?: (params: OnScrollParams) => void; /** * @description 拖拽时是否启动自动滚动 * @default false */ autoScroll?: boolean; /** * @description 自定义timeline样式 */ style?: React.CSSProperties; /** * @description 是否自动重新渲染(当数据改变或光标时间改变时update tick) * @default true */ autoReRender?: boolean; /** * @description 数据改变回调,会在操作动作end改变数据后触发(返回false会阻止自动engine同步,用于减少性能开销) */ onChange?: (editorData: TimelineRow[]) => void | boolean; /** * @description 播放时自动跟随光标滚动 * @default false */ followCursor?: boolean; /** * @description 跟随滚动的边缘留白(px) * @default 80 */ followCursorMargin?: number; }