Browse Source

Improve TS for `Components.addType`. Closes #5053

pull/5087/head
Artur Arseniev 3 years ago
parent
commit
cb04b97cf6
  1. 4
      src/common/index.ts
  2. 36
      src/dom_components/index.ts
  3. 6
      src/dom_components/model/Component.ts
  4. 4
      src/dom_components/view/ComponentView.ts

4
src/common/index.ts

@ -35,3 +35,7 @@ export class Model<T extends ObjectHash = any, S = SetOptions, E = any> extends
export class Collection<T extends Model = Model> extends Backbone.Collection<T> {} export class Collection<T extends Model = Model> extends Backbone.Collection<T> {}
export class View<T extends Model | undefined = Model, E extends Element = HTMLElement> extends Backbone.View<T, E> {} export class View<T extends Model | undefined = Model, E extends Element = HTMLElement> extends Backbone.View<T, E> {}
export type PickMatching<T, V> = { [K in keyof T as T[K] extends V ? K : never]: T[K] };
export type ExtractMethods<T> = PickMatching<T, Function>;

36
src/dom_components/index.ts

@ -54,9 +54,9 @@
*/ */
import { isEmpty, isObject, isArray, isFunction, isString, result, debounce } from 'underscore'; import { isEmpty, isObject, isArray, isFunction, isString, result, debounce } from 'underscore';
import defaults, { DomComponentsConfig } from './config/config'; import defaults, { DomComponentsConfig } from './config/config';
import Component, { keyUpdate, keyUpdateInside } from './model/Component'; import Component, { IComponent, keyUpdate, keyUpdateInside } from './model/Component';
import Components from './model/Components'; import Components from './model/Components';
import ComponentView from './view/ComponentView'; import ComponentView, { IComponentView } from './view/ComponentView';
import ComponentWrapperView from './view/ComponentWrapperView'; import ComponentWrapperView from './view/ComponentWrapperView';
import ComponentsView from './view/ComponentsView'; import ComponentsView from './view/ComponentsView';
import ComponentTableCell from './model/ComponentTableCell'; import ComponentTableCell from './model/ComponentTableCell';
@ -97,7 +97,7 @@ import ComponentFrame from './model/ComponentFrame';
import ComponentFrameView from './view/ComponentFrameView'; import ComponentFrameView from './view/ComponentFrameView';
import { ItemManagerModule } from '../abstract/Module'; import { ItemManagerModule } from '../abstract/Module';
import EditorModel from '../editor/model/Editor'; import EditorModel from '../editor/model/Editor';
import { ComponentAdd } from './model/types'; import { ComponentAdd, ComponentDefinitionDefined } from './model/types';
export type ComponentEvent = export type ComponentEvent =
| 'component:create' | 'component:create'
@ -117,6 +117,25 @@ export type ComponentEvent =
| 'component:drag' | 'component:drag'
| 'component:drag:end'; | 'component:drag:end';
export interface ComponentModelDefinition extends IComponent {
defaults?: ComponentDefinitionDefined;
[key: string]: any;
}
export interface ComponentViewDefinition extends IComponentView {
[key: string]: any;
}
export interface AddComponentTypeOptions {
isComponent?: (el: HTMLElement) => boolean | ComponentDefinitionDefined | undefined;
model?: Partial<ComponentModelDefinition> & ThisType<ComponentModelDefinition & Component>;
view?: Partial<ComponentViewDefinition> & ThisType<ComponentViewDefinition & ComponentView>;
extend?: string;
extendView?: string;
extendFn?: string[];
extendFnView?: string[];
}
export default class ComponentManager extends ItemManagerModule<DomComponentsConfig, any> { export default class ComponentManager extends ItemManagerModule<DomComponentsConfig, any> {
componentTypes = [ componentTypes = [
{ {
@ -433,12 +452,12 @@ export default class ComponentManager extends ItemManagerModule<DomComponentsCon
* @param {Object} methods Component methods * @param {Object} methods Component methods
* @return {this} * @return {this}
*/ */
addType(type: string, methods: any) { addType(type: string, methods: AddComponentTypeOptions) {
const { em } = this; const { em } = this;
const { model = {}, view = {}, isComponent, extend, extendView, extendFn = [], extendFnView = [] } = methods; const { model = {}, view = {}, isComponent, extend, extendView, extendFn = [], extendFnView = [] } = methods;
const compType = this.getType(type); const compType = this.getType(type);
const extendType = this.getType(extend); const extendType = this.getType(extend!);
const extendViewType = this.getType(extendView); const extendViewType = this.getType(extendView!);
const typeToExtend = extendType ? extendType : compType ? compType : this.getType('default'); const typeToExtend = extendType ? extendType : compType ? compType : this.getType('default');
const modelToExt = typeToExtend.model; const modelToExt = typeToExtend.model;
const viewToExt = extendViewType ? extendViewType.view : typeToExtend.view; const viewToExt = extendViewType ? extendViewType.view : typeToExtend.view;
@ -460,6 +479,7 @@ export default class ComponentManager extends ItemManagerModule<DomComponentsCon
// If the model/view is a simple object I need to extend it // If the model/view is a simple object I need to extend it
if (typeof model === 'object') { if (typeof model === 'object') {
const defaults = result(model, 'defaults'); const defaults = result(model, 'defaults');
// @ts-ignore
delete model.defaults; delete model.defaults;
methods.model = modelToExt.extend( methods.model = modelToExt.extend(
{ {
@ -470,6 +490,7 @@ export default class ComponentManager extends ItemManagerModule<DomComponentsCon
isComponent: compType && !extendType && !isComponent ? modelToExt.isComponent : isComponent || (() => 0), isComponent: compType && !extendType && !isComponent ? modelToExt.isComponent : isComponent || (() => 0),
} }
); );
// @ts-ignore
Object.defineProperty(methods.model.prototype, 'defaults', { Object.defineProperty(methods.model.prototype, 'defaults', {
value: { value: {
...(result(modelToExt.prototype, 'defaults') || {}), ...(result(modelToExt.prototype, 'defaults') || {}),
@ -489,8 +510,9 @@ export default class ComponentManager extends ItemManagerModule<DomComponentsCon
compType.model = methods.model; compType.model = methods.model;
compType.view = methods.view; compType.view = methods.view;
} else { } else {
// @ts-ignore
methods.id = type; methods.id = type;
this.componentTypes.unshift(methods); this.componentTypes.unshift(methods as any);
} }
const event = `component:type:${compType ? 'update' : 'add'}`; const event = `component:type:${compType ? 'update' : 'add'}`;

6
src/dom_components/model/Component.ts

@ -32,11 +32,13 @@ import {
import Frame from '../../canvas/model/Frame'; import Frame from '../../canvas/model/Frame';
import { DomComponentsConfig } from '../config/config'; import { DomComponentsConfig } from '../config/config';
import ComponentView from '../view/ComponentView'; import ComponentView from '../view/ComponentView';
import { AddOptions, ObjectAny, ObjectStrings, SetOptions } from '../../common'; import { AddOptions, ExtractMethods, ObjectAny, ObjectStrings, SetOptions } from '../../common';
import CssRule, { CssRuleJSON, CssRuleProperties } from '../../css_composer/model/CssRule'; import CssRule, { CssRuleJSON } from '../../css_composer/model/CssRule';
import Trait, { TraitProperties } from '../../trait_manager/model/Trait'; import Trait, { TraitProperties } from '../../trait_manager/model/Trait';
import { ToolbarButtonProps } from './ToolbarButton'; import { ToolbarButtonProps } from './ToolbarButton';
export interface IComponent extends ExtractMethods<Component> {}
const escapeRegExp = (str: string) => { const escapeRegExp = (str: string) => {
return str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'); return str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');
}; };

4
src/dom_components/view/ComponentView.ts

@ -5,7 +5,7 @@ import ComponentsView from './ComponentsView';
import Selectors from '../../selector_manager/model/Selectors'; import Selectors from '../../selector_manager/model/Selectors';
import { replaceWith } from '../../utils/dom'; import { replaceWith } from '../../utils/dom';
import { setViewEl } from '../../utils/mixins'; import { setViewEl } from '../../utils/mixins';
import { ObjectAny, View } from '../../common'; import { ExtractMethods, ObjectAny, View } from '../../common';
import { ComponentOptions } from '../model/types'; import { ComponentOptions } from '../model/types';
import EditorModel from '../../editor/model/Editor'; import EditorModel from '../../editor/model/Editor';
import { DomComponentsConfig } from '../config/config'; import { DomComponentsConfig } from '../config/config';
@ -20,6 +20,8 @@ interface Rect {
right?: number; right?: number;
} }
export interface IComponentView extends ExtractMethods<ComponentView> {}
export default class ComponentView extends View</** export default class ComponentView extends View</**
* Keep this format to avoid errors in TS bundler */ * Keep this format to avoid errors in TS bundler */
/** @ts-ignore */ /** @ts-ignore */

Loading…
Cancel
Save