Browse Source

Type callback events (#6710)

* Allow skipping nodes during HTML parsing

* Type canvas events

* Type commands event callbacks

* Type device event callbacks

* Add callback events to i18n

* Add callbacks types to keymaps

* Add callback types to modal

* Add callback types to layers

* Add callback types for pages

* Add callback types to parser

* Add callback type to RTE

* Add callback types to selectors

* Add callback types for storage

* Add callback types to StyleManager

* Add callback types to traits

* Add callback events to Components

* Add callbacks types to editor

* Up types

* Fix API docs generation

* Format
fix-6707-focus
Artur Arseniev 1 month ago
committed by GitHub
parent
commit
095b3ecde4
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 19
      docs/api.mjs
  2. 2
      docs/api/assets.md
  3. 16
      docs/api/canvas.md
  4. 4
      docs/api/commands.md
  5. 21
      docs/api/datasources.md
  6. 8
      docs/api/device_manager.md
  7. 6
      docs/api/layer_manager.md
  8. 2
      docs/api/rich_text_editor.md
  9. 2
      docs/api/selector_manager.md
  10. 6
      packages/core/src/asset_manager/index.ts
  11. 2
      packages/core/src/canvas/index.ts
  12. 88
      packages/core/src/canvas/types.ts
  13. 6
      packages/core/src/canvas/view/CanvasView.ts
  14. 4
      packages/core/src/canvas/view/FrameView.ts
  15. 14
      packages/core/src/commands/index.ts
  16. 37
      packages/core/src/commands/types.ts
  17. 7
      packages/core/src/commands/view/CanvasMove.ts
  18. 10
      packages/core/src/commands/view/CommandAbstract.ts
  19. 3
      packages/core/src/commands/view/ComponentDrag.ts
  20. 3
      packages/core/src/commands/view/OpenTraitManager.ts
  21. 3
      packages/core/src/commands/view/PasteComponent.ts
  22. 11
      packages/core/src/commands/view/SelectComponent.ts
  23. 28
      packages/core/src/device_manager/types.ts
  24. 31
      packages/core/src/dom_components/index.ts
  25. 12
      packages/core/src/dom_components/model/Component.ts
  26. 3
      packages/core/src/dom_components/model/ComponentVideo.ts
  27. 2
      packages/core/src/dom_components/model/Components.ts
  28. 2
      packages/core/src/dom_components/model/Symbols.ts
  29. 186
      packages/core/src/dom_components/types.ts
  30. 3
      packages/core/src/domain_abstract/ui/InputColor.ts
  31. 33
      packages/core/src/editor/model/Editor.ts
  32. 105
      packages/core/src/editor/types.ts
  33. 8
      packages/core/src/i18n/types.ts
  34. 5
      packages/core/src/keymaps/index.ts
  35. 15
      packages/core/src/keymaps/types.ts
  36. 3
      packages/core/src/modal_dialog/index.ts
  37. 18
      packages/core/src/modal_dialog/types.ts
  38. 7
      packages/core/src/navigator/index.ts
  39. 27
      packages/core/src/navigator/types.ts
  40. 3
      packages/core/src/navigator/view/ItemView.ts
  41. 26
      packages/core/src/pages/types.ts
  42. 2
      packages/core/src/parser/index.ts
  43. 2
      packages/core/src/parser/model/ParserHtml.ts
  44. 17
      packages/core/src/parser/types.ts
  45. 2
      packages/core/src/rich_text_editor/index.ts
  46. 16
      packages/core/src/rich_text_editor/types.ts
  47. 4
      packages/core/src/selector_manager/index.ts
  48. 37
      packages/core/src/selector_manager/types.ts
  49. 6
      packages/core/src/selector_manager/view/ClassTagsView.ts
  50. 7
      packages/core/src/storage_manager/index.ts
  51. 23
      packages/core/src/storage_manager/types.ts
  52. 8
      packages/core/src/style_manager/index.ts
  53. 42
      packages/core/src/style_manager/types.ts
  54. 5
      packages/core/src/trait_manager/index.ts
  55. 2
      packages/core/src/trait_manager/model/Trait.ts
  56. 45
      packages/core/src/trait_manager/types.ts
  57. 3
      packages/core/src/trait_manager/view/TraitsView.ts
  58. 11
      packages/core/src/utils/Droppable.ts
  59. 8
      packages/core/test/specs/pages/index.ts

19
docs/api.mjs

@ -15,13 +15,28 @@ const REPLACE_EVENTS = '{REPLACE\\_EVENTS}';
const log = (...args) => console.log(...args); const log = (...args) => console.log(...args);
const hasTemplateLiteralType = (value) => {
if (!value || typeof value !== 'object') return false;
if (value.type === 'TemplateLiteralType') return true;
return Object.values(value).some((item) =>
Array.isArray(item) ? item.some((nested) => hasTemplateLiteralType(nested)) : hasTemplateLiteralType(item),
);
};
const sanitizeUnsupportedTypes = (comments = []) =>
comments.map((comment) =>
comment.kind === 'typedef' && hasTemplateLiteralType(comment.type)
? { ...comment, type: { type: 'NameExpression', name: 'string' } }
: comment,
);
const getEventsMdFromTypes = async (filePath) => { const getEventsMdFromTypes = async (filePath) => {
const dirname = filePath.replace(basename(filePath), ''); const dirname = filePath.replace(basename(filePath), '');
const typesFilePath = `${dirname}types.ts`; const typesFilePath = `${dirname}types.ts`;
if (existsSync(typesFilePath)) { if (existsSync(typesFilePath)) {
const resTypes = await build([typesFilePath], { shallow: true }).then((cm) => const resTypes = await build([typesFilePath], { shallow: true }).then((cm) =>
formats.md(cm /*{ markdownToc: true }*/), formats.md(sanitizeUnsupportedTypes(cm) /*{ markdownToc: true }*/),
); );
const indexFrom = resTypes.indexOf(START_EVENTS) + START_EVENTS.length; const indexFrom = resTypes.indexOf(START_EVENTS) + START_EVENTS.length;
const indexTo = resTypes.indexOf(END_EVENTS); const indexTo = resTypes.indexOf(END_EVENTS);
@ -31,10 +46,12 @@ const getEventsMdFromTypes = async (filePath) => {
.replace(/\n### Examples\n/gi, '') .replace(/\n### Examples\n/gi, '')
.replace(/\n## types\n/gi, '') .replace(/\n## types\n/gi, '')
.replace(/## /gi, '* ') .replace(/## /gi, '* ')
.replace(/^\* [A-Za-z][A-Za-z0-9]*Event\s*$/gm, '')
.replace(/\\`/gi, '`') .replace(/\\`/gi, '`')
.replace(/##/gi, '') .replace(/##/gi, '')
.replace(/\\\[/gi, '[') .replace(/\\\[/gi, '[')
.replace(/\]\\\(/gi, '](') .replace(/\]\\\(/gi, '](')
.replace(/\n{3,}/g, '\n\n')
.trim(); .trim();
return result; return result;

2
docs/api/assets.md

@ -85,6 +85,8 @@ editor.on('asset:custom', ({ container, assets, ... }) => { ... });
editor.on('asset', ({ event, model, ... }) => { ... }); editor.on('asset', ({ event, model, ... }) => { ... });
``` ```
* AssetsEventCallback
## Methods ## Methods
* [open][2] * [open][2]

16
docs/api/canvas.md

@ -24,11 +24,11 @@ canvas.setCoords(...);
``` ```
## Available Events ## Available Events
* `canvas:dragenter` Something is dragged inside the canvas, `DataTransfer` instance passed as an argument. * `canvas:dragenter` Something is dragged inside the canvas. `DataTransfer` instance and dragged content are passed as arguments.
* `canvas:dragover` Something is dragging on the canvas, `DataTransfer` instance passed as an argument. * `canvas:dragover` Something is dragging on the canvas. Triggering event is passed as an argument.
* `canvas:dragend` When a drag operation is ended, `DataTransfer` instance passed as an argument. * `canvas:dragend` When a drag operation is ended, triggering event is passed as an argument.
* `canvas:dragdata` On any dataTransfer parse, `DataTransfer` instance and the `result` are passed as arguments. By changing `result.content` you're able to customize what is dropped. * `canvas:dragdata` On any dataTransfer parse, `DataTransfer` instance and the `result` are passed as arguments. By changing `result.content` you're able to customize what is dropped.
@ -98,6 +98,16 @@ editor.on('canvas:refresh', (canvasRefreshOptions) => {
}); });
``` ```
* `canvas:update` Canvas was updated.
* `canvas:tools:update` Canvas tools were updated.
* `canvas:move:start` Canvas move started.
* `canvas:move` Canvas is moving.
* `canvas:move:end` Canvas move ended.
* `canvas:frame:load` Frame loaded in canvas. The event is triggered right after iframe's `onload`. * `canvas:frame:load` Frame loaded in canvas. The event is triggered right after iframe's `onload`.
```javascript ```javascript

4
docs/api/commands.md

@ -16,7 +16,7 @@ Once the editor is instantiated you can use its API and listen to its events. Be
```js ```js
// Listen to events // Listen to events
editor.on('run', () => { ... }); editor.on('command:run', () => { ... });
// Use the API // Use the API
const commands = editor.Commands; const commands = editor.Commands;
@ -91,6 +91,8 @@ editor.on('command:call', ({ id, result, options, type }) => {
editor.on('command:call:my-command', ({ result, options, type }) => { ... }); editor.on('command:call:my-command', ({ result, options, type }) => { ... });
``` ```
* CommandEventOptions
## Methods ## Methods
* [add][2] * [add][2]

21
docs/api/datasources.md

@ -113,6 +113,18 @@ const ds = dsm.get('my_data_source_id');
Returns **[DataSource]** Data source. Returns **[DataSource]** Data source.
## getAll
Return all data sources.
### Examples
```javascript
const ds = dsm.getAll();
```
Returns **[Array][8]<[DataSource]>**&#x20;
## getValue ## getValue
Get value from data sources by path. Get value from data sources by path.
@ -121,6 +133,7 @@ Get value from data sources by path.
* `path` **[String][7]** Path to value. * `path` **[String][7]** Path to value.
* `defValue` **any** Default value if the path is not found. * `defValue` **any** Default value if the path is not found.
* `opts` **{context: Record<[string][7], any>?}?**&#x20;
Returns **any** const value = dsm.getValue('ds\_id.record\_id.propName', 'defaultValue'); Returns **any** const value = dsm.getValue('ds\_id.record\_id.propName', 'defaultValue');
@ -139,7 +152,7 @@ Set value in data sources by path.
dsm.setValue('ds_id.record_id.propName', 'new value'); dsm.setValue('ds_id.record_id.propName', 'new value');
``` ```
Returns **[Boolean][8]** Returns true if the value was set successfully Returns **[Boolean][9]** Returns true if the value was set successfully
## remove ## remove
@ -183,7 +196,7 @@ data record, and optional property path.
Store data sources to a JSON object. Store data sources to a JSON object.
Returns **[Array][9]** Stored data sources. Returns **[Array][8]** Stored data sources.
## load ## load
@ -209,6 +222,6 @@ Returns **[Object][6]** Loaded data sources.
[7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String [7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
[8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean [8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
[9]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array [9]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean

8
docs/api/device_manager.md

@ -31,16 +31,16 @@ editor.on('device:add', (device) => { ... });
editor.on('device:remove', (device) => { ... }); editor.on('device:remove', (device) => { ... });
``` ```
* `device:select` A new device is selected. The `Device` is passed as an argument. * `device:select` A new device is selected. Current and previous `Device` are passed as arguments.
```javascript ```javascript
editor.on('device:select', (device) => { ... }); editor.on('device:select', (newDevice, prevDevice) => { ... });
``` ```
* `device:update` Device updated. The `Device` and the object containing changes are passed as arguments. * `device:update` Device updated. The `Device`, changed properties, and update options are passed as arguments.
```javascript ```javascript
editor.on('device:update', (device) => { ... }); editor.on('device:update', (device, changes, options) => { ... });
``` ```
* `device` Catch-all event for all the events mentioned above. * `device` Catch-all event for all the events mentioned above.

6
docs/api/layer_manager.md

@ -38,6 +38,12 @@ editor.on('layer:component', (component, opts) => { ... });
editor.on('layer:custom', ({ container, root }) => { ... }); editor.on('layer:custom', ({ container, root }) => { ... });
``` ```
* `layer:render` Component layer rendered. Object with component and rendered layer element is passed as an argument.
```javascript
editor.on('layer:render', ({ component, el }) => { ... });
```
## Methods ## Methods
* [setRoot][1] * [setRoot][1]

2
docs/api/rich_text_editor.md

@ -40,6 +40,8 @@ editor.on('rte:disable', (view, rte) => { ... });
editor.on('rte:custom', ({ enabled, container, actions }) => { ... }); editor.on('rte:custom', ({ enabled, container, actions }) => { ... });
``` ```
* RichTextEditorEventCallback
## Methods ## Methods
* [add][3] * [add][3]

2
docs/api/selector_manager.md

@ -84,8 +84,6 @@ editor.on('selector:custom', ({ states, selected, container }) => { ... });
editor.on('selector', ({ event, selector, changes, ... }) => { ... }); editor.on('selector', ({ event, selector, changes, ... }) => { ... });
``` ```
* SelectorStringObject
## Methods ## Methods
* [getConfig][2] * [getConfig][2]

6
packages/core/src/asset_manager/index.ts

@ -40,7 +40,7 @@ import { ProjectData } from '../storage_manager';
import defConfig, { AssetManagerConfig } from './config/config'; import defConfig, { AssetManagerConfig } from './config/config';
import Asset from './model/Asset'; import Asset from './model/Asset';
import Assets from './model/Assets'; import Assets from './model/Assets';
import AssetsEvents, { AssetAddInput, AssetOpenOptions, AssetProps } from './types'; import AssetsEvents, { AssetAddInput, AssetOpenOptions, AssetProps, AssetsCustomData } from './types';
import AssetsView from './view/AssetsView'; import AssetsView from './view/AssetsView';
import FileUploaderView from './view/FileUploader'; import FileUploaderView from './view/FileUploader';
@ -381,7 +381,7 @@ export default class AssetManager extends ItemManagerModule<AssetManagerConfig,
this.em.trigger(this.events.custom, this.__customData()); this.em.trigger(this.events.custom, this.__customData());
} }
__customData() { __customData(): AssetsCustomData {
const bhv = this.__getBehaviour(); const bhv = this.__getBehaviour();
return { return {
am: this as AssetManager, am: this as AssetManager,
@ -391,7 +391,7 @@ export default class AssetManager extends ItemManagerModule<AssetManagerConfig,
container: bhv.container, container: bhv.container,
close: () => this.close(), close: () => this.close(),
remove: (asset: string | Asset, opts?: Record<string, any>) => this.remove(asset, opts), remove: (asset: string | Asset, opts?: Record<string, any>) => this.remove(asset, opts),
select: (asset: Asset, complete: boolean) => { select: (asset: Asset, complete?: boolean) => {
const res = this.add(asset); const res = this.add(asset);
isFunction(bhv.select) && bhv.select(res, complete); isFunction(bhv.select) && bhv.select(res, complete);
}, },

2
packages/core/src/canvas/index.ts

@ -911,7 +911,7 @@ export default class CanvasModule extends Module<CanvasConfig> {
if (opts.spots || opts.all) { if (opts.spots || opts.all) {
this.refreshSpots(); this.refreshSpots();
em.trigger('canvas:updateTools'); // this should be deprecated em.trigger(CanvasEvents.updateTools); // this should be deprecated
} }
em.set('canvasOffset', this.getOffset()); // this should be deprecated em.set('canvasOffset', this.getOffset()); // this should be deprecated

88
packages/core/src/canvas/types.ts

@ -1,4 +1,10 @@
import { SetOptions } from '../common'; import type Component from '../dom_components/model/Component';
import type Dragger from '../utils/Dragger';
import type { DraggableContent } from '../utils/sorter/types';
import type CanvasSpot from './model/CanvasSpot';
import type Frame from './model/Frame';
import type FrameView from './view/FrameView';
import { ObjectAny, SetOptions } from '../common';
export interface ToScreenOption { export interface ToScreenOption {
toScreen?: boolean; toScreen?: boolean;
@ -24,20 +30,40 @@ export interface SetZoomOptions extends SetOptions {
from?: string; from?: string;
} }
export interface CanvasDragDataResult {
content: DraggableContent['content'];
setContent: (content: DraggableContent['content']) => void;
}
export interface CanvasSpotEventProps {
spot: CanvasSpot;
}
export interface CanvasFrameEventProps {
el: HTMLIFrameElement;
model: Frame;
view: FrameView;
window: Window;
}
export interface CanvasToolsUpdateEventProps extends ObjectAny {
type: string;
}
/**{START_EVENTS}*/ /**{START_EVENTS}*/
export enum CanvasEvents { export enum CanvasEvents {
/** /**
* @event `canvas:dragenter` Something is dragged inside the canvas, `DataTransfer` instance passed as an argument. * @event `canvas:dragenter` Something is dragged inside the canvas. `DataTransfer` instance and dragged content are passed as arguments.
*/ */
dragEnter = 'canvas:dragenter', dragEnter = 'canvas:dragenter',
/** /**
* @event `canvas:dragover` Something is dragging on the canvas, `DataTransfer` instance passed as an argument. * @event `canvas:dragover` Something is dragging on the canvas. Triggering event is passed as an argument.
*/ */
dragOver = 'canvas:dragover', dragOver = 'canvas:dragover',
/** /**
* @event `canvas:dragend` When a drag operation is ended, `DataTransfer` instance passed as an argument. * @event `canvas:dragend` When a drag operation is ended, triggering event is passed as an argument.
*/ */
dragEnd = 'canvas:dragend', dragEnd = 'canvas:dragend',
@ -123,6 +149,32 @@ export enum CanvasEvents {
*/ */
refresh = 'canvas:refresh', refresh = 'canvas:refresh',
/**
* @event `canvas:update` Canvas was updated.
*/
update = 'canvas:update',
updateTools = 'canvas:updateTools',
/**
* @event `canvas:tools:update` Canvas tools were updated.
*/
toolsUpdate = 'canvas:tools:update',
/**
* @event `canvas:move:start` Canvas move started.
*/
moveStart = 'canvas:move:start',
/**
* @event `canvas:move` Canvas is moving.
*/
move = 'canvas:move',
/**
* @event `canvas:move:end` Canvas move ended.
*/
moveEnd = 'canvas:move:end',
/** /**
* @event `canvas:frame:load` Frame loaded in canvas. The event is triggered right after iframe's `onload`. * @event `canvas:frame:load` Frame loaded in canvas. The event is triggered right after iframe's `onload`.
* @example * @example
@ -161,5 +213,33 @@ export enum CanvasEvents {
} }
/**{END_EVENTS}*/ /**{END_EVENTS}*/
export type CanvasEvent = `${CanvasEvents}`;
export interface CanvasEventCallback {
[CanvasEvents.dragEnter]: [DataTransfer | null | undefined, NonNullable<DraggableContent['content']>];
[CanvasEvents.dragOver]: [Event];
[CanvasEvents.dragEnd]: [Event | undefined];
[CanvasEvents.dragData]: [DataTransfer | null | undefined, CanvasDragDataResult];
[CanvasEvents.drop]: [DataTransfer | null | undefined, Component | Component[]];
[CanvasEvents.spot]: [];
[CanvasEvents.spotAdd]: [CanvasSpotEventProps];
[CanvasEvents.spotUpdate]: [CanvasSpotEventProps];
[CanvasEvents.spotRemove]: [CanvasSpotEventProps];
[CanvasEvents.coords]: [];
[CanvasEvents.zoom]: [{ options: SetZoomOptions }];
[CanvasEvents.pointer]: [];
[CanvasEvents.refresh]: [CanvasRefreshOptions];
[CanvasEvents.update]: [Event | { options: SetZoomOptions } | undefined];
[CanvasEvents.updateTools]: [];
[CanvasEvents.toolsUpdate]: [CanvasToolsUpdateEventProps];
[CanvasEvents.moveStart]: [Dragger];
[CanvasEvents.move]: [Dragger];
[CanvasEvents.moveEnd]: [Dragger];
[CanvasEvents.frameLoad]: [CanvasFrameEventProps];
[CanvasEvents.frameLoadHead]: [CanvasFrameEventProps];
[CanvasEvents.frameLoadBody]: [CanvasFrameEventProps];
[CanvasEvents.frameUnload]: [{ frame: Frame }];
}
// need this to avoid the TS documentation generator to break // need this to avoid the TS documentation generator to break
export default CanvasEvents; export default CanvasEvents;

6
packages/core/src/canvas/view/CanvasView.ts

@ -16,7 +16,7 @@ import {
import { getComponentView, getElement, getUiClass } from '../../utils/mixins'; import { getComponentView, getElement, getUiClass } from '../../utils/mixins';
import Canvas from '../model/Canvas'; import Canvas from '../model/Canvas';
import Frame from '../model/Frame'; import Frame from '../model/Frame';
import { GetBoxRectOptions, ToWorldOption } from '../types'; import { CanvasEvents, GetBoxRectOptions, ToWorldOption } from '../types';
import FrameView from './FrameView'; import FrameView from './FrameView';
import FramesView from './FramesView'; import FramesView from './FramesView';
import { ComponentsEvents } from '../../dom_components/types'; import { ComponentsEvents } from '../../dom_components/types';
@ -98,7 +98,7 @@ export default class CanvasView extends ModuleView<Canvas> {
this.clsUnscale = `${pfx}unscale`; this.clsUnscale = `${pfx}unscale`;
this._initFrames(); this._initFrames();
this.listenTo(em, events.refresh, this.clearOff); this.listenTo(em, events.refresh, this.clearOff);
this.listenTo(em, 'component:selected', this.checkSelected); this.listenTo(em, ComponentsEvents.selected, this.checkSelected);
this.listenTo(em, `${events.coords} ${events.zoom}`, this.updateFrames); this.listenTo(em, `${events.coords} ${events.zoom}`, this.updateFrames);
this.listenTo(model, 'change:frames', this._onFramesUpdate); this.listenTo(model, 'change:frames', this._onFramesUpdate);
this.toggleListeners(true); this.toggleListeners(true);
@ -242,7 +242,7 @@ export default class CanvasView extends ModuleView<Canvas> {
this.updateFramesArea(); this.updateFramesArea();
this.clearOff(); this.clearOff();
toolsWrpEl.style.display = 'none'; toolsWrpEl.style.display = 'none';
em.trigger('canvas:update', ev); em.trigger(CanvasEvents.update, ev);
clearTimeout(this.timerZoom); clearTimeout(this.timerZoom);
this.timerZoom = setTimeout(() => { this.timerZoom = setTimeout(() => {
em.stopDefault(defOpts); em.stopDefault(defOpts);

4
packages/core/src/canvas/view/FrameView.ts

@ -11,7 +11,7 @@ import { append, appendVNodes, createCustomEvent, createEl, motionsEv, off, on }
import { hasDnd, setViewEl } from '../../utils/mixins'; import { hasDnd, setViewEl } from '../../utils/mixins';
import Canvas from '../model/Canvas'; import Canvas from '../model/Canvas';
import Frame from '../model/Frame'; import Frame from '../model/Frame';
import CanvasEvents from '../types'; import CanvasEvents, { CanvasFrameEventProps } from '../types';
import FrameWrapView from './FrameWrapView'; import FrameWrapView from './FrameWrapView';
export default class FrameView extends ModuleView<Frame, HTMLIFrameElement> { export default class FrameView extends ModuleView<Frame, HTMLIFrameElement> {
@ -252,7 +252,7 @@ export default class FrameView extends ModuleView<Frame, HTMLIFrameElement> {
renderScripts() { renderScripts() {
const { el, model, em } = this; const { el, model, em } = this;
const evLoad = 'frame:load'; const evLoad = 'frame:load';
const evOpts: ObjectAny = { el, model, view: this }; const evOpts = { el, model, view: this } as unknown as CanvasFrameEventProps;
const canvas = this.getCanvasModel(); const canvas = this.getCanvasModel();
const appendScript = (scripts: any[]) => { const appendScript = (scripts: any[]) => {
if (scripts.length > 0) { if (scripts.length > 0) {

14
packages/core/src/commands/index.ts

@ -12,7 +12,7 @@
* *
* ```js * ```js
* // Listen to events * // Listen to events
* editor.on('run', () => { ... }); * editor.on('command:run', () => { ... });
* *
* // Use the API * // Use the API
* const commands = editor.Commands; * const commands = editor.Commands;
@ -39,12 +39,12 @@ import { isFunction, includes } from 'underscore';
import CommandAbstract, { Command, CommandOptions, CommandObject, CommandFunction } from './view/CommandAbstract'; import CommandAbstract, { Command, CommandOptions, CommandObject, CommandFunction } from './view/CommandAbstract';
import defConfig, { CommandsConfig } from './config/config'; import defConfig, { CommandsConfig } from './config/config';
import { Module } from '../abstract'; import { Module } from '../abstract';
import Component, { eventDrag } from '../dom_components/model/Component'; import Component from '../dom_components/model/Component';
import { ComponentsEvents } from '../dom_components/types';
import type Editor from '../editor/model/Editor'; import type Editor from '../editor/model/Editor';
import type { ObjectAny } from '../common'; import type { ObjectAny } from '../common';
import CommandsEvents from './types'; import CommandsEvents from './types';
export type { CommandEvent } from './types';
export type CommandEvent = 'run' | 'stop' | `run:${string}` | `stop:${string}` | `abort:${string}`;
const commandsDef = [ const commandsDef = [
['preview', 'Preview', 'preview'], ['preview', 'Preview', 'preview'],
@ -75,9 +75,9 @@ const commandsDef = [
const defComOptions = { preserveSelected: 1 }; const defComOptions = { preserveSelected: 1 };
export const getOnComponentDragStart = (em: Editor) => (data: any) => em.trigger(`${eventDrag}:start`, data); export const getOnComponentDragStart = (em: Editor) => (data: any) => em.trigger(ComponentsEvents.dragStart, data);
export const getOnComponentDrag = (em: Editor) => (data: any) => em.trigger(eventDrag, data); export const getOnComponentDrag = (em: Editor) => (data: any) => em.trigger(ComponentsEvents.drag, data);
export const getOnComponentDragEnd = export const getOnComponentDragEnd =
(em: Editor, targets: Component[], opts: { altMode?: boolean } = {}) => (em: Editor, targets: Component[], opts: { altMode?: boolean } = {}) =>
@ -87,7 +87,7 @@ export const getOnComponentDragEnd =
em.setSelected(targets); em.setSelected(targets);
targets[0].emitUpdate(); targets[0].emitUpdate();
}); });
em.trigger(`${eventDrag}:end`, data); em.trigger(ComponentsEvents.dragEnd, data);
// Defer selectComponent in order to prevent canvas "freeze" #2692 // Defer selectComponent in order to prevent canvas "freeze" #2692
setTimeout(() => em.runDefault(defComOptions)); setTimeout(() => em.runDefault(defComOptions));

37
packages/core/src/commands/types.ts

@ -78,5 +78,42 @@ export enum CommandsEvents {
} }
/**{END_EVENTS}*/ /**{END_EVENTS}*/
export type CommandEventOptions = Record<string, any>;
export interface CommandEventBeforeData {
options: CommandEventOptions;
}
export interface CommandEventData {
id: string | number;
result: any;
options: CommandEventOptions;
}
export interface CommandCallEventData extends CommandEventData {
type: 'run' | 'stop';
}
export type CommandEvent =
| `${CommandsEvents.run}`
| `${CommandsEvents.stop}`
| `${CommandsEvents.call}`
| `${CommandsEvents.runCommand}${string}`
| `${CommandsEvents.runBeforeCommand}${string}`
| `${CommandsEvents.abort}${string}`
| `${CommandsEvents.stopCommand}${string}`
| `${CommandsEvents.stopBeforeCommand}${string}`
| `${CommandsEvents.callCommand}${string}`;
export interface CommandsEventCallback {
[CommandsEvents.run]: [CommandEventData];
[CommandsEvents.stop]: [CommandEventData];
[CommandsEvents.call]: [CommandCallEventData];
[key: `${CommandsEvents.runCommand}${string}`]: [CommandEventData | CommandEventBeforeData];
[key: `${CommandsEvents.abort}${string}`]: [CommandEventBeforeData];
[key: `${CommandsEvents.stopCommand}${string}`]: [CommandEventData | CommandEventBeforeData];
[key: `${CommandsEvents.callCommand}${string}`]: [CommandCallEventData];
}
// need this to avoid the TS documentation generator to break // need this to avoid the TS documentation generator to break
export default CommandsEvents; export default CommandsEvents;

7
packages/core/src/commands/view/CanvasMove.ts

@ -1,4 +1,5 @@
import { bindAll } from 'underscore'; import { bindAll } from 'underscore';
import { CanvasEvents } from '../../canvas/types';
import Dragger from '../../utils/Dragger'; import Dragger from '../../utils/Dragger';
import { getKeyChar, off, on } from '../../utils/dom'; import { getKeyChar, off, on } from '../../utils/dom';
import { CommandObject } from './CommandAbstract'; import { CommandObject } from './CommandAbstract';
@ -47,13 +48,13 @@ export default {
canvasModel.set({ x, y }); canvasModel.set({ x, y });
}, },
onStart(ev, dragger) { onStart(ev, dragger) {
em.trigger('canvas:move:start', dragger); em.trigger(CanvasEvents.moveStart, dragger);
}, },
onDrag(ev, dragger) { onDrag(ev, dragger) {
em.trigger('canvas:move', dragger); em.trigger(CanvasEvents.move, dragger);
}, },
onEnd(ev, dragger) { onEnd(ev, dragger) {
em.trigger('canvas:move:end', dragger); em.trigger(CanvasEvents.moveEnd, dragger);
}, },
}); });
this.dragger = dragger; this.dragger = dragger;

10
packages/core/src/commands/view/CommandAbstract.ts

@ -2,7 +2,7 @@ import CanvasModule from '../../canvas';
import { Model, ObjectAny } from '../../common'; import { Model, ObjectAny } from '../../common';
import Editor from '../../editor'; import Editor from '../../editor';
import EditorModel from '../../editor/model/Editor'; import EditorModel from '../../editor/model/Editor';
import CommandsEvents from '../types'; import CommandsEvents, { type CommandCallEventData, type CommandEventData } from '../types';
interface ICommand<O extends ObjectAny = any> { interface ICommand<O extends ObjectAny = any> {
run?: CommandAbstract<O>['run']; run?: CommandAbstract<O>['run'];
@ -120,8 +120,8 @@ export default class CommandAbstract<O extends ObjectAny = any> extends Model {
const sender = options.sender || editor; const sender = options.sender || editor;
const result = this.run(editor, sender, options); const result = this.run(editor, sender, options);
const data = { id, result, options }; const data: CommandEventData = { id, result, options };
const dataCall = { ...data, type: 'run' }; const dataCall: CommandCallEventData = { ...data, type: 'run' };
if (!this.noStop) { if (!this.noStop) {
editor.Commands.active[id] = result; editor.Commands.active[id] = result;
@ -146,8 +146,8 @@ export default class CommandAbstract<O extends ObjectAny = any> extends Model {
const sender = options.sender || editor; const sender = options.sender || editor;
editor.trigger(`${CommandsEvents.stopBeforeCommand}${id}`, { options }); editor.trigger(`${CommandsEvents.stopBeforeCommand}${id}`, { options });
const result = this.stop(editor, sender, options); const result = this.stop(editor, sender, options);
const data = { id, result, options }; const data: CommandEventData = { id, result, options };
const dataCall = { ...data, type: 'stop' }; const dataCall: CommandCallEventData = { ...data, type: 'stop' };
delete editor.Commands.active[id]; delete editor.Commands.active[id];
editor.trigger(`${CommandsEvents.stopCommand}${id}`, data); editor.trigger(`${CommandsEvents.stopCommand}${id}`, data);
editor.trigger(`${CommandsEvents.callCommand}${id}`, dataCall); editor.trigger(`${CommandsEvents.callCommand}${id}`, dataCall);

3
packages/core/src/commands/view/ComponentDrag.ts

@ -1,4 +1,5 @@
import { keys, bindAll, each, isUndefined, debounce } from 'underscore'; import { keys, bindAll, each, isUndefined, debounce } from 'underscore';
import { CanvasEvents } from '../../canvas/types';
import Dragger, { DraggerOptions } from '../../utils/Dragger'; import Dragger, { DraggerOptions } from '../../utils/Dragger';
import type { CommandObject } from './CommandAbstract'; import type { CommandObject } from './CommandAbstract';
import type Editor from '../../editor'; import type Editor from '../../editor';
@ -115,7 +116,7 @@ export default {
this.elGuideInfoContentY = elInfoY.querySelector(`.${pfx}guide-info__content`) ?? undefined; this.elGuideInfoContentY = elInfoY.querySelector(`.${pfx}guide-info__content`) ?? undefined;
em.on( em.on(
'canvas:update frame:scroll', `${CanvasEvents.update} frame:scroll`,
debounce(() => { debounce(() => {
this.updateGuides(); this.updateGuides();
opts.debug && this.guides?.forEach((item) => this.renderGuide(item)); opts.debug && this.guides?.forEach((item) => this.renderGuide(item));

3
packages/core/src/commands/view/OpenTraitManager.ts

@ -1,5 +1,6 @@
import { CommandObject } from './CommandAbstract'; import { CommandObject } from './CommandAbstract';
import { $ } from '../../common'; import { $ } from '../../common';
import { ComponentsEvents } from '../../dom_components/types';
export default { export default {
run(editor, sender) { run(editor, sender) {
@ -40,7 +41,7 @@ export default {
panelC?.set('appendContent', this.$cn.get(0)).trigger('change:appendContent'); panelC?.set('appendContent', this.$cn.get(0)).trigger('change:appendContent');
this.target = editor.getModel(); this.target = editor.getModel();
this.listenTo(this.target, 'component:toggled', this.toggleTm); this.listenTo(this.target, ComponentsEvents.toggled, this.toggleTm);
} }
this.toggleTm(); this.toggleTm();

3
packages/core/src/commands/view/PasteComponent.ts

@ -1,5 +1,6 @@
import { isArray, contains } from 'underscore'; import { isArray, contains } from 'underscore';
import Component from '../../dom_components/model/Component'; import Component from '../../dom_components/model/Component';
import { ComponentsEvents } from '../../dom_components/types';
import { CommandObject } from './CommandAbstract'; import { CommandObject } from './CommandAbstract';
import Editor from '../../editor'; import Editor from '../../editor';
@ -33,7 +34,7 @@ export default {
} }
added = isArray(added) ? added : [added]; added = isArray(added) ? added : [added];
added.forEach((add) => ed.trigger('component:paste', add)); added.forEach((add) => ed.trigger(ComponentsEvents.paste, add));
}); });
lastSelected.emitUpdate(); lastSelected.emitUpdate();

11
packages/core/src/commands/view/SelectComponent.ts

@ -1,8 +1,9 @@
import { bindAll, debounce, isElement } from 'underscore'; import { bindAll, debounce, isElement } from 'underscore';
import { CanvasSpotBuiltInTypes } from '../../canvas/model/CanvasSpot'; import { CanvasSpotBuiltInTypes } from '../../canvas/model/CanvasSpot';
import { CanvasEvents } from '../../canvas/types';
import Component from '../../dom_components/model/Component'; import Component from '../../dom_components/model/Component';
import Toolbar from '../../dom_components/model/Toolbar'; import Toolbar from '../../dom_components/model/Toolbar';
import { ComponentsEvents } from '../../dom_components/types'; import { ComponentResizeInitEventData, ComponentsEvents } from '../../dom_components/types';
import ToolbarView from '../../dom_components/view/ToolbarView'; import ToolbarView from '../../dom_components/view/ToolbarView';
import { isDoc, isTaggableNode, isVisible, off, on } from '../../utils/dom'; import { isDoc, isTaggableNode, isVisible, off, on } from '../../utils/dom';
import { getComponentModel, getComponentView, hasWin, isObject } from '../../utils/mixins'; import { getComponentModel, getComponentView, hasWin, isObject } from '../../utils/mixins';
@ -93,12 +94,12 @@ export default {
}; };
methods[method](window, 'resize', this.onFrameUpdated); methods[method](window, 'resize', this.onFrameUpdated);
methods[method](listenToEl, 'scroll', this.onContainerChange); methods[method](listenToEl, 'scroll', this.onContainerChange);
em[method](`component:toggled ${eventCmpUpdate} undo redo`, this.onSelect, this); em[method](`${ComponentsEvents.toggled} ${eventCmpUpdate} undo redo`, this.onSelect, this);
em[method]('change:componentHovered', this.onHovered, this); em[method]('change:componentHovered', this.onHovered, this);
em[method](`${ComponentsEvents.resize} styleable:change ${ComponentsEvents.input}`, this.updateGlobalPos, this); em[method](`${ComponentsEvents.resize} styleable:change ${ComponentsEvents.input}`, this.updateGlobalPos, this);
em[method](`${eventCmpUpdate}:toolbar`, this._upToolbar, this); em[method](`${eventCmpUpdate}:toolbar`, this._upToolbar, this);
em[method]('frame:updated', this.onFrameUpdated, this); em[method]('frame:updated', this.onFrameUpdated, this);
em[method]('canvas:updateTools', this.onFrameUpdated, this); em[method](CanvasEvents.updateTools, this.onFrameUpdated, this);
em[method](em.Canvas.events.refresh, this.updateAttached, this); em[method](em.Canvas.events.refresh, this.updateAttached, this);
em.Canvas.getFrames().forEach((frame) => { em.Canvas.getFrames().forEach((frame) => {
const { view } = frame; const { view } = frame;
@ -403,7 +404,7 @@ export default {
component, component,
hasCustomResize, hasCustomResize,
resizable, resizable,
}; } as ComponentResizeInitEventData;
component && em.trigger(ComponentsEvents.resizeInit, initEventOpts); component && em.trigger(ComponentsEvents.resizeInit, initEventOpts);
const resizableResult = initEventOpts.resizable; const resizableResult = initEventOpts.resizable;
@ -596,7 +597,7 @@ export default {
}, 0), }, 0),
_trgToolUp(type: string, opts = {}) { _trgToolUp(type: string, opts = {}) {
this.em.trigger('canvas:tools:update', { this.em.trigger(CanvasEvents.toolsUpdate, {
type, type,
...opts, ...opts,
}); });

28
packages/core/src/device_manager/types.ts

@ -1,3 +1,12 @@
import {
EventCallbackAdd,
EventCallbackAll,
EventCallbackRemove,
EventCallbackRemoveBefore,
SetOptions,
} from '../common';
import Device, { DeviceProperties } from './model/Device';
/**{START_EVENTS}*/ /**{START_EVENTS}*/
export enum DeviceEvents { export enum DeviceEvents {
/** /**
@ -17,17 +26,17 @@ export enum DeviceEvents {
removeBefore = 'device:remove:before', removeBefore = 'device:remove:before',
/** /**
* @event `device:select` A new device is selected. The `Device` is passed as an argument. * @event `device:select` A new device is selected. Current and previous `Device` are passed as arguments.
* @example * @example
* editor.on('device:select', (device) => { ... }); * editor.on('device:select', (newDevice, prevDevice) => { ... });
*/ */
select = 'device:select', select = 'device:select',
selectBefore = 'device:select:before', selectBefore = 'device:select:before',
/** /**
* @event `device:update` Device updated. The `Device` and the object containing changes are passed as arguments. * @event `device:update` Device updated. The `Device`, changed properties, and update options are passed as arguments.
* @example * @example
* editor.on('device:update', (device) => { ... }); * editor.on('device:update', (device, changes, options) => { ... });
*/ */
update = 'device:update', update = 'device:update',
@ -40,5 +49,16 @@ export enum DeviceEvents {
} }
/**{END_EVENTS}*/ /**{END_EVENTS}*/
export type DeviceEvent = `${DeviceEvents}`;
export interface DevicesEventCallback {
[DeviceEvents.add]: EventCallbackAdd<Device>;
[DeviceEvents.remove]: EventCallbackRemove<Device>;
[DeviceEvents.removeBefore]: EventCallbackRemoveBefore<Device>;
[DeviceEvents.select]: [Device | null | undefined, Device | null | undefined];
[DeviceEvents.update]: [Device, Partial<DeviceProperties>, SetOptions];
[DeviceEvents.all]: EventCallbackAll<DeviceEvent, Device>;
}
// This is necessary to prevent the TS documentation generator from breaking. // This is necessary to prevent the TS documentation generator from breaking.
export default DeviceEvents; export default DeviceEvents;

31
packages/core/src/dom_components/index.ts

@ -131,24 +131,7 @@ 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';
export type ComponentEvent = export type { ComponentEvent } from './types';
| 'component:create'
| 'component:mount'
| 'component:add'
| 'component:remove'
| 'component:remove:before'
| 'component:clone'
| 'component:update'
| 'component:styleUpdate'
| 'component:selected'
| 'component:deselected'
| 'component:toggled'
| 'component:type:add'
| 'component:type:update'
| 'component:drag:start'
| 'component:drag'
| 'component:drag:end'
| 'component:resize';
export interface ComponentModelDefinition extends IComponent { export interface ComponentModelDefinition extends IComponent {
defaults?: ComponentDefinition | (() => ComponentDefinition); defaults?: ComponentDefinition | (() => ComponentDefinition);
@ -634,8 +617,8 @@ export default class ComponentManager extends ItemManagerModule<DomComponentsCon
em.Blocks.add(blockProps.id || type, blockProps); em.Blocks.add(blockProps.id || type, blockProps);
} }
const event = `component:type:${compType ? 'update' : 'add'}`; const event = compType ? ComponentsEvents.typeUpdate : ComponentsEvents.typeAdd;
em?.trigger(event, compType || methods); em?.trigger(event, (compType || methods) as any);
return this; return this;
} }
@ -687,7 +670,7 @@ export default class ComponentManager extends ItemManagerModule<DomComponentsCon
component.set({ component.set({
status: 'selected', status: 'selected',
}); });
['component:selected', 'component:toggled'].forEach((event) => this.em.trigger(event, component, opts)); [ComponentsEvents.selected, ComponentsEvents.toggled].forEach((event) => this.em.trigger(event, component, opts));
} }
} }
@ -698,7 +681,9 @@ export default class ComponentManager extends ItemManagerModule<DomComponentsCon
status: '', status: '',
state: '', state: '',
}); });
['component:deselected', 'component:toggled'].forEach((event) => this.em.trigger(event, component, opts)); [ComponentsEvents.deselected, ComponentsEvents.toggled].forEach((event) =>
this.em.trigger(event, component, opts),
);
} }
} }
@ -775,7 +760,7 @@ export default class ComponentManager extends ItemManagerModule<DomComponentsCon
const symbol = component.clone({ symbol: true }); const symbol = component.clone({ symbol: true });
isSymbolMain(symbol) && this.symbols.add(symbol); isSymbolMain(symbol) && this.symbols.add(symbol);
this.em.trigger('component:toggled'); this.em.trigger(ComponentsEvents.toggled);
return symbol; return symbol;
} }

12
packages/core/src/dom_components/model/Component.ts

@ -84,7 +84,7 @@ const escapeRegExp = (str: string) => {
export const avoidInline = (em: EditorModel) => !!em?.getConfig().avoidInlineStyle; export const avoidInline = (em: EditorModel) => !!em?.getConfig().avoidInlineStyle;
export const eventDrag = 'component:drag'; export const eventDrag = ComponentsEvents.drag;
export const keySymbols = '__symbols'; export const keySymbols = '__symbols';
export const keySymbol = '__symbol'; export const keySymbol = '__symbol';
export const keySymbolOvrd = '__symbol_ovrd'; export const keySymbolOvrd = '__symbol_ovrd';
@ -1048,7 +1048,7 @@ export default class Component extends StyleableModel<ComponentProperties> {
const resolvedAttributes = this.dataResolverWatchers.getValueOrResolver('attributes', attrs); const resolvedAttributes = this.dataResolverWatchers.getValueOrResolver('attributes', attrs);
traits.length && this.setAttributes(resolvedAttributes); traits.length && this.setAttributes(resolvedAttributes);
this.on(event, this.initTraits); this.on(event, this.initTraits);
changed && em && em.trigger('component:toggled'); changed && em && em.trigger(ComponentsEvents.toggled);
return this; return this;
} }
@ -1310,7 +1310,7 @@ export default class Component extends StyleableModel<ComponentProperties> {
updateTrait(id: string, props: Partial<TraitProperties>) { updateTrait(id: string, props: Partial<TraitProperties>) {
const trait = this.getTrait(id); const trait = this.getTrait(id);
trait && trait.set(props); trait && trait.set(props);
this.em?.trigger('component:toggled'); this.em?.trigger(ComponentsEvents.toggled);
return this; return this;
} }
@ -1341,7 +1341,7 @@ export default class Component extends StyleableModel<ComponentProperties> {
const toRemove = ids.map((id) => this.getTrait(id)); const toRemove = ids.map((id) => this.getTrait(id));
const { traits } = this; const { traits } = this;
const removed = toRemove.length ? traits.remove(toRemove) : []; const removed = toRemove.length ? traits.remove(toRemove) : [];
this.em?.trigger('component:toggled'); this.em?.trigger(ComponentsEvents.toggled);
return isArray(removed) ? removed : [removed]; return isArray(removed) ? removed : [removed];
} }
@ -1361,7 +1361,7 @@ export default class Component extends StyleableModel<ComponentProperties> {
addTrait(trait: Parameters<Traits['add']>[0], opts: AddOptions = {}) { addTrait(trait: Parameters<Traits['add']>[0], opts: AddOptions = {}) {
this.__loadTraits(); this.__loadTraits();
const added = this.traits.add(trait, opts); const added = this.traits.add(trait, opts);
this.em?.trigger('component:toggled'); this.em?.trigger(ComponentsEvents.toggled);
return isArray(added) ? added : [added]; return isArray(added) ? added : [added];
} }
@ -1467,7 +1467,7 @@ export default class Component extends StyleableModel<ComponentProperties> {
} }
} }
const event = 'component:clone'; const event = ComponentsEvents.clone;
em && em.trigger(event, cloned); em && em.trigger(event, cloned);
this.trigger(event, cloned); this.trigger(event, cloned);

3
packages/core/src/dom_components/model/ComponentVideo.ts

@ -1,5 +1,6 @@
import { ObjectAny } from '../../common'; import { ObjectAny } from '../../common';
import { isDef, isEmptyObj, toLowerCase } from '../../utils/mixins'; import { isDef, isEmptyObj, toLowerCase } from '../../utils/mixins';
import { ComponentsEvents } from '../types';
import ComponentImage from './ComponentImage'; import ComponentImage from './ComponentImage';
import { ComponentOptions, ComponentProperties } from './types'; import { ComponentOptions, ComponentProperties } from './types';
@ -90,7 +91,7 @@ export default class ComponentVideo extends ComponentImage {
this.set({ tagName }, { silent: true }); // avoid break in view this.set({ tagName }, { silent: true }); // avoid break in view
// @ts-ignore // @ts-ignore
this.set({ traits }); this.set({ traits });
em.get('ready') && em.trigger('component:toggled'); em.get('ready') && em.trigger(ComponentsEvents.toggled);
} }
/** /**

2
packages/core/src/dom_components/model/Components.ts

@ -168,7 +168,7 @@ Component> {
Components.cloneCssRules(em, fromDefOpts.visitedCmps); Components.cloneCssRules(em, fromDefOpts.visitedCmps);
this.reset(newCmps, opts as any); this.reset(newCmps, opts as any);
em?.trigger('component:content', parent, opts, input); em?.trigger(ComponentsEvents.content, parent, opts, input);
(parent as ComponentText).__checkInnerChilds?.(); (parent as ComponentText).__checkInnerChilds?.();
} }

2
packages/core/src/dom_components/model/Symbols.ts

@ -50,7 +50,7 @@ export default class Symbols extends Components {
const { em, events } = this; const { em, events } = this;
const eventType = isInstance ? events.symbolInstance : events.symbolMain; const eventType = isInstance ? events.symbolInstance : events.symbolMain;
em.trigger(event, props); em.trigger(event, props);
em.trigger(eventType, { ...props, event }); em.trigger(eventType, { ...props, event } as any);
this.refreshDbn(); this.refreshDbn();
} }
} }

186
packages/core/src/dom_components/types.ts

@ -1,5 +1,24 @@
import { AddOptions, OptionAsDocument, WithHTMLParserOptions } from '../common'; import type {
import Component from './model/Component'; AddOptions,
EventCallbackAdd,
EventCallbackRemoveBefore,
ObjectAny,
OptionAsDocument,
WithHTMLParserOptions,
} from '../common';
import type CssRule from '../css_composer/model/CssRule';
import type {
ComponentResizeEventEndProps,
ComponentResizeEventMoveProps,
ComponentResizeEventStartProps,
ComponentResizeEventUpdateProps,
} from '../commands/view/Resize';
import type { StyleProps } from '../domain_abstract/model/StyleableModel';
import type Selector from '../selector_manager/model/Selector';
import type Component from './model/Component';
import type { ResetFromStringOptions } from './model/Components';
import type { ComponentOptions, ComponentStackItem } from './model/types';
import type ComponentView from './view/ComponentView';
export enum ActionLabelComponents { export enum ActionLabelComponents {
remove = 'component:remove', remove = 'component:remove',
@ -38,6 +57,7 @@ export enum ComponentsEvents {
remove = 'component:remove', remove = 'component:remove',
removeBefore = 'component:remove:before', removeBefore = 'component:remove:before',
removed = 'component:removed', removed = 'component:removed',
clone = 'component:clone',
/** /**
* @event `component:create` Component created. * @event `component:create` Component created.
@ -52,6 +72,7 @@ export enum ComponentsEvents {
* editor.on('component:update', (component) => { ... }); * editor.on('component:update', (component) => { ... });
*/ */
update = 'component:update', update = 'component:update',
updateProperty = 'component:update:',
updateInside = 'component:update-inside', updateInside = 'component:update-inside',
/** /**
@ -69,6 +90,20 @@ export enum ComponentsEvents {
*/ */
select = 'component:select', select = 'component:select',
selectBefore = 'component:select:before', selectBefore = 'component:select:before',
selected = 'component:selected',
deselected = 'component:deselected',
toggled = 'component:toggled',
hover = 'component:hover',
hoverBefore = 'component:hover:before',
hovered = 'component:hovered',
unhovered = 'component:unhovered',
paste = 'component:paste',
syncStyle = 'component:sync-style',
typeAdd = 'component:type:add',
typeUpdate = 'component:type:update',
dragStart = 'component:drag:start',
drag = 'component:drag',
dragEnd = 'component:drag:end',
/** /**
* @event `component:mount` Component is mounted in the canvas. * @event `component:mount` Component is mounted in the canvas.
@ -105,6 +140,7 @@ export enum ComponentsEvents {
* editor.on('component:input', (component) => { ... }); * editor.on('component:input', (component) => { ... });
*/ */
input = 'component:input', input = 'component:input',
content = 'component:content',
/** /**
* @event `component:resize` Component resized. This event is triggered when the component is resized in the canvas. * @event `component:resize` Component resized. This event is triggered when the component is resized in the canvas.
@ -214,3 +250,149 @@ export enum ComponentsEvents {
*/ */
symbol = 'symbol', symbol = 'symbol',
} }
type ComponentEventStatic = Exclude<
`${ComponentsEvents}`,
`${ComponentsEvents.updateProperty}` | `${ComponentsEvents.styleUpdateProperty}`
>;
type SymbolMainEvent =
| ComponentsEvents.symbolMainAdd
| ComponentsEvents.symbolMainUpdate
| ComponentsEvents.symbolMainUpdateDeep
| ComponentsEvents.symbolMainRemove;
type SymbolInstanceEvent = ComponentsEvents.symbolInstanceAdd | ComponentsEvents.symbolInstanceRemove;
export type ComponentEvent =
| ComponentEventStatic
| `${ComponentsEvents.updateProperty}${string}`
| `${ComponentsEvents.styleUpdateProperty}${string}`;
export interface ComponentScriptEventData {
component: Component;
view: ComponentView;
el: HTMLElement;
}
export interface ComponentStyleUpdateEventData {
style: StyleProps;
}
export interface ComponentUpdateEventData {
component: Component;
changed: ObjectAny;
options: ObjectAny;
}
export interface ComponentTypeEventData extends Partial<Omit<ComponentStackItem, 'id'>> {
id: string;
[key: string]: any;
}
export interface ComponentDragEventData {
target?: Component;
parent?: Component;
index?: number;
cancelled?: boolean;
[key: string]: unknown;
}
export interface ComponentResizeEventEndData {
type: 'end';
component: Component;
el: HTMLElement;
}
export type ComponentResizeEventData =
| ({ type: 'start' } & ComponentResizeEventStartProps)
| ({ type: 'move' } & ComponentResizeEventMoveProps)
| ComponentResizeEventEndData;
export interface ComponentResizeInitEventData {
component: Component;
hasCustomResize: boolean;
resizable: Component['resizable'];
}
export interface ComponentRemovedEventData {
removeOptions: ObjectAny;
}
export interface ComponentSyncStyleEventData {
component: Component | undefined;
selectors: Selector[];
mediaText: string;
rule: CssRule;
ruleComponents: CssRule[];
state: string;
}
export interface SymbolEventData {
component: Component;
changed?: ObjectAny;
options?: ObjectAny;
}
export interface SymbolMainEventData extends SymbolEventData {
event: SymbolMainEvent;
}
export interface SymbolInstanceEventData extends SymbolEventData {
event: SymbolInstanceEvent;
}
export interface ComponentsEventCallback {
[ComponentsEvents.add]: EventCallbackAdd<Component>;
[ComponentsEvents.remove]: [Component];
[ComponentsEvents.removeBefore]: EventCallbackRemoveBefore<Component>;
[ComponentsEvents.removed]: [Component, ComponentRemovedEventData | undefined];
[ComponentsEvents.clone]: [Component];
[ComponentsEvents.create]: [Component, ComponentOptions];
[ComponentsEvents.update]: [Component, ...any[]];
[ComponentsEvents.updateInside]: [ComponentUpdateEventData];
[ComponentsEvents.styleUpdate]: [Component, ComponentStyleUpdateEventData];
[ComponentsEvents.select]: [Component, ObjectAny];
[ComponentsEvents.selectBefore]: [Component, ObjectAny];
[ComponentsEvents.selected]: [Component, ObjectAny];
[ComponentsEvents.deselected]: [Component, ObjectAny];
[ComponentsEvents.toggled]: [Component?, ObjectAny?];
[ComponentsEvents.hover]: [Component | undefined, ObjectAny];
[ComponentsEvents.hoverBefore]: [Component, ObjectAny];
[ComponentsEvents.hovered]: [Component, ObjectAny];
[ComponentsEvents.unhovered]: [Component, ObjectAny];
[ComponentsEvents.paste]: [Component];
[ComponentsEvents.syncStyle]: [ComponentSyncStyleEventData];
[ComponentsEvents.typeAdd]: [ComponentTypeEventData];
[ComponentsEvents.typeUpdate]: [ComponentTypeEventData];
[ComponentsEvents.dragStart]: [ComponentDragEventData];
[ComponentsEvents.drag]: [ComponentDragEventData];
[ComponentsEvents.dragEnd]: [ComponentDragEventData];
[ComponentsEvents.mount]: [Component];
[ComponentsEvents.scriptMount]: [ComponentScriptEventData];
[ComponentsEvents.scriptMountBefore]: [ComponentScriptEventData];
[ComponentsEvents.scriptUnmount]: [ComponentScriptEventData];
[ComponentsEvents.render]: [ComponentScriptEventData];
[ComponentsEvents.input]: [Component];
[ComponentsEvents.content]: [Component | undefined, ResetFromStringOptions, string];
[ComponentsEvents.resize]: [ComponentResizeEventData];
[ComponentsEvents.resizeStart]: [ComponentResizeEventStartProps | ComponentResizeEventMoveProps];
[ComponentsEvents.resizeMove]: [ComponentResizeEventMoveProps];
[ComponentsEvents.resizeEnd]: [ComponentResizeEventEndProps];
[ComponentsEvents.resizeUpdate]: [ComponentResizeEventUpdateProps];
[ComponentsEvents.resizeInit]: [ComponentResizeInitEventData];
[ComponentsEvents.symbolMainAdd]: [SymbolEventData];
[ComponentsEvents.symbolMainUpdate]: [ComponentUpdateEventData];
[ComponentsEvents.symbolMainUpdateDeep]: [ComponentUpdateEventData];
[ComponentsEvents.symbolMainRemove]: [SymbolEventData];
[ComponentsEvents.symbolMain]: [SymbolMainEventData];
[ComponentsEvents.symbolInstanceAdd]: [SymbolEventData];
[ComponentsEvents.symbolInstanceRemove]: [SymbolEventData];
[ComponentsEvents.symbolInstance]: [SymbolInstanceEventData];
[ComponentsEvents.symbol]: [];
[key: `${ComponentsEvents.updateProperty}${string}`]: [Component, ...any[]];
[key: `${ComponentsEvents.styleUpdateProperty}${string}`]: [Component, ComponentStyleUpdateEventData];
}
// need this to avoid the TS documentation generator to break
export default ComponentsEvents;

3
packages/core/src/domain_abstract/ui/InputColor.ts

@ -1,4 +1,5 @@
import { isUndefined } from 'underscore'; import { isUndefined } from 'underscore';
import { ComponentsEvents } from '../../dom_components/types';
import ColorPicker from '../../utils/ColorPicker'; import ColorPicker from '../../utils/ColorPicker';
import $ from '../../utils/cash-dom'; import $ from '../../utils/cash-dom';
import Input from './Input'; import Input from './Input';
@ -166,7 +167,7 @@ export default class InputColor extends Input {
}); });
if (em && em.on!) { if (em && em.on!) {
this.listenTo(em, 'component:selected', () => { this.listenTo(em, ComponentsEvents.selected, () => {
this.movedColor && handleChange(this.movedColor); this.movedColor && handleChange(this.movedColor);
changed = true; changed = true;
this.movedColor = ''; this.movedColor = '';

33
packages/core/src/editor/model/Editor.ts

@ -46,6 +46,7 @@ import DataSourceManager from '../../data_sources';
import { ComponentsEvents } from '../../dom_components/types'; import { ComponentsEvents } from '../../dom_components/types';
import { InitEditorConfig } from '../..'; import { InitEditorConfig } from '../..';
import { EditorEvents, SelectComponentOptions } from '../types'; import { EditorEvents, SelectComponentOptions } from '../types';
import type { EditorEvent, EditorEventCallbacks, EditorEventHandler } from '../types';
Backbone.$ = $; Backbone.$ = $;
@ -242,6 +243,25 @@ export default class EditorModel extends Model {
return this.get('DataSources'); return this.get('DataSources');
} }
on<E extends EditorEvent>(event: E, callback: EditorEventHandler<E>, context?: any) {
return super.on(event, callback, context);
}
once<E extends EditorEvent>(event: E, callback: EditorEventHandler<E>, context?: any) {
return super.once(event, callback, context);
}
off<E extends EditorEvent>(event?: E, callback?: EditorEventHandler<E>, context?: any) {
return super.off(event, callback, context);
}
trigger<E extends EditorEvent>(
event: E,
...args: E extends keyof EditorEventCallbacks ? EditorEventCallbacks[E] : any[]
) {
return super.trigger(event, ...args);
}
constructor(conf: EditorConfig = {}) { constructor(conf: EditorConfig = {}) {
super(); super();
this._config = conf; this._config = conf;
@ -284,11 +304,11 @@ export default class EditorModel extends Model {
toLog.forEach((e) => this.listenLog(e as keyof typeof logs)); toLog.forEach((e) => this.listenLog(e as keyof typeof logs));
// Deprecations // Deprecations
[{ from: 'change:selectedComponent', to: 'component:toggled' }].forEach((event) => { [{ from: 'change:selectedComponent', to: ComponentsEvents.toggled }].forEach((event) => {
const eventFrom = event.from; const eventFrom = event.from;
const eventTo = event.to; const eventTo = event.to;
this.listenTo(this, eventFrom, (...args) => { this.listenTo(this, eventFrom, (...args) => {
this.trigger(eventTo, ...args); this.trigger(eventTo, ...(args as any));
this.logWarning(`The event '${eventFrom}' is deprecated, replace it with '${eventTo}'`); this.logWarning(`The event '${eventFrom}' is deprecated, replace it with '${eventTo}'`);
}); });
}); });
@ -492,8 +512,8 @@ export default class EditorModel extends Model {
* */ * */
componentHovered(editor: any, component: any, options: any) { componentHovered(editor: any, component: any, options: any) {
const prev = this.previous('componentHovered'); const prev = this.previous('componentHovered');
prev && this.trigger('component:unhovered', prev, options); prev && this.trigger(ComponentsEvents.unhovered, prev, options);
component && this.trigger('component:hovered', component, options); component && this.trigger(ComponentsEvents.hovered, component, options);
} }
/** /**
@ -711,9 +731,8 @@ export default class EditorModel extends Model {
return upHovered(); return upHovered();
} }
const ev = 'component:hover';
opts.forceChange && upHovered(); opts.forceChange && upHovered();
this.trigger(`${ev}:before`, cmp, opts); this.trigger(ComponentsEvents.hoverBefore, cmp, opts);
// Check for valid hoverable // Check for valid hoverable
if (!cmp.get('hoverable')) { if (!cmp.get('hoverable')) {
@ -728,7 +747,7 @@ export default class EditorModel extends Model {
if (!opts.abort) { if (!opts.abort) {
upHovered(cmp, opts); upHovered(cmp, opts);
this.trigger(ev, cmp, opts); this.trigger(ComponentsEvents.hover, cmp, opts);
} }
} }

105
packages/core/src/editor/types.ts

@ -1,34 +1,54 @@
import { AssetEvent, AssetsEventCallback } from '../asset_manager/types'; import { AssetEvent, AssetsEventCallback } from '../asset_manager/types';
import { BlockEvent, BlocksEventCallback } from '../block_manager/types'; import { BlockEvent, BlocksEventCallback } from '../block_manager/types';
import { CanvasEvent } from '../canvas'; import type { LiteralUnion, ObjectAny } from '../common';
import { CommandEvent } from '../commands'; import { CanvasEvent, CanvasEventCallback } from '../canvas/types';
import { LiteralUnion } from '../common'; import { CommandEvent, CommandsEventCallback } from '../commands/types';
import { DataSourceEvent, DataSourcesEventCallback } from '../data_sources/types'; import { DataSourceEvent, DataSourcesEventCallback } from '../data_sources/types';
import { ComponentEvent } from '../dom_components'; import { DeviceEvent, DevicesEventCallback } from '../device_manager/types';
import { KeymapEvent } from '../keymaps'; import { ComponentEvent, ComponentsEventCallback } from '../dom_components/types';
import { ModalEvent } from '../modal_dialog'; import { I18nEvent, I18nEventCallback } from '../i18n/types';
import { RichTextEditorEvent } from '../rich_text_editor'; import { KeymapEvent, KeymapsEventCallback } from '../keymaps/types';
import { SelectorEvent } from '../selector_manager'; import { ModalEvent, ModalEventCallback } from '../modal_dialog/types';
import { StyleManagerEvent } from '../style_manager'; import { LayerEvent, LayerEventCallback } from '../navigator/types';
import { PageEvent, PagesEventCallback } from '../pages/types';
import { ParserEvent, ParserEventCallback } from '../parser/types';
import { RichTextEditorEvent, RichTextEditorEventCallback } from '../rich_text_editor';
import { SelectorEvent, SelectorEventCallback } from '../selector_manager/types';
import type { ProjectData } from '../storage_manager';
import { StorageEvent, StorageEventCallback } from '../storage_manager/types';
import { StyleManagerEvent, StyleManagerEventCallback } from '../style_manager/types';
import { TraitEvent, TraitEventCallback } from '../trait_manager/types';
import { EditorConfig } from './config/config'; import { EditorConfig } from './config/config';
import EditorModel from './model/Editor'; import type EditorModel from './model/Editor';
import type { EditorLoadOptions } from './model/Editor';
type GeneralEvent = 'canvasScroll' | 'undo' | 'redo' | 'load' | 'update'; type EditorLogEvent =
| `${EditorEvents.log}:${string}`
| `${EditorEvents.log}-${string}`
| `${EditorEvents.log}-${string}:${string}`;
type EditorCoreEvent = `${EditorEvents}` | EditorLogEvent | 'canvasScroll';
type EditorBuiltInEvents = type EditorBuiltInEvents =
| EditorCoreEvent
| DataSourceEvent | DataSourceEvent
| DeviceEvent
| I18nEvent
| ComponentEvent | ComponentEvent
| BlockEvent | BlockEvent
| AssetEvent | AssetEvent
| KeymapEvent | KeymapEvent
| LayerEvent
| PageEvent
| ParserEvent
| StyleManagerEvent | StyleManagerEvent
| StorageEvent | StorageEvent
| CanvasEvent | CanvasEvent
| SelectorEvent | SelectorEvent
| RichTextEditorEvent | RichTextEditorEvent
| TraitEvent
| ModalEvent | ModalEvent
| CommandEvent | CommandEvent;
| GeneralEvent;
export type EditorEvent = LiteralUnion<EditorBuiltInEvents, string>; export type EditorEvent = LiteralUnion<EditorBuiltInEvents, string>;
@ -36,7 +56,64 @@ export type EditorConfigType = EditorConfig & { pStylePrefix?: string };
export type EditorModelParam<T extends keyof EditorModel, N extends number> = Parameters<EditorModel[T]>[N]; export type EditorModelParam<T extends keyof EditorModel, N extends number> = Parameters<EditorModel[T]>[N];
export interface EditorEventCallbacks extends AssetsEventCallback, BlocksEventCallback, DataSourcesEventCallback { export interface EditorProjectEventData {
project: ProjectData;
options: EditorLoadOptions;
initial: boolean;
}
export interface EditorProjectLoadEventData extends EditorProjectEventData {
loaded: boolean;
}
export interface EditorProjectGetEventData {
project: ProjectData;
}
export interface EditorLogEventOptions extends ObjectAny {
ns?: string;
level?: string;
}
export interface EditorEventCoreCallbacks {
[EditorEvents.update]: [];
[EditorEvents.updateBefore]: [Record<string, any>];
[EditorEvents.undo]: [];
[EditorEvents.redo]: [];
[EditorEvents.load]: [EditorModel['Editor']];
[EditorEvents.projectLoad]: [EditorProjectLoadEventData];
[EditorEvents.projectLoaded]: [EditorProjectEventData];
[EditorEvents.projectGet]: [EditorProjectGetEventData];
[EditorEvents.log]: [string, EditorLogEventOptions];
[EditorEvents.telemetryInit]: [];
[EditorEvents.destroy]: [];
[EditorEvents.destroyed]: [];
[key: `log:${string}`]: [string, EditorLogEventOptions];
[key: `log-${string}`]: [string, EditorLogEventOptions];
[key: `log-${string}:${string}`]: [string, EditorLogEventOptions];
canvasScroll: [];
}
export interface EditorEventCallbacks
extends EditorEventCoreCallbacks,
AssetsEventCallback,
BlocksEventCallback,
CanvasEventCallback,
CommandsEventCallback,
DataSourcesEventCallback,
DevicesEventCallback,
ComponentsEventCallback,
I18nEventCallback,
KeymapsEventCallback,
LayerEventCallback,
ModalEventCallback,
PagesEventCallback,
ParserEventCallback,
RichTextEditorEventCallback,
SelectorEventCallback,
StorageEventCallback,
StyleManagerEventCallback,
TraitEventCallback {
[key: string]: any[]; [key: string]: any[];
} }

8
packages/core/src/i18n/types.ts

@ -27,5 +27,13 @@ export enum I18nEvents {
} }
/**{END_EVENTS}*/ /**{END_EVENTS}*/
export type I18nEvent = `${I18nEvents}`;
export interface I18nEventCallback {
[I18nEvents.add]: [Messages];
[I18nEvents.update]: [Messages];
[I18nEvents.locale]: [{ value: string; valuePrev: string | undefined }];
}
// need this to avoid the TS documentation generator to break // need this to avoid the TS documentation generator to break
export default I18nEvents; export default I18nEvents;

5
packages/core/src/keymaps/index.ts

@ -41,8 +41,7 @@ import keymaster from '../utils/keymaster';
import { hasWin } from '../utils/mixins'; import { hasWin } from '../utils/mixins';
import defConfig, { Keymap, KeymapOptions, KeymapsConfig } from './config'; import defConfig, { Keymap, KeymapOptions, KeymapsConfig } from './config';
import { KeymapsEvents } from './types'; import { KeymapsEvents } from './types';
export type { KeymapEvent } from './types';
export type KeymapEvent = `${KeymapsEvents}`;
hasWin() && keymaster.init(window); hasWin() && keymaster.init(window);
@ -118,7 +117,9 @@ export default class KeymapsModule extends Module<KeymapsConfig & { name?: strin
opts.prevent && canvas.getCanvasView()?.preventDefault(e); opts.prevent && canvas.getCanvasView()?.preventDefault(e);
isFunction(handlerRes) ? handlerRes(editor, 0, opt) : cmd.runCommand(handlerRes, opt); isFunction(handlerRes) ? handlerRes(editor, 0, opt) : cmd.runCommand(handlerRes, opt);
const args = [id, h.shortcut, e]; const args = [id, h.shortcut, e];
// @ts-ignore
em.trigger(events.emit, ...args); em.trigger(events.emit, ...args);
// @ts-ignore
em.trigger(`${events.emitId}${id}`, ...args); em.trigger(`${events.emitId}${id}`, ...args);
} }
}, },

15
packages/core/src/keymaps/types.ts

@ -1,3 +1,5 @@
import { Keymap } from './config';
/**{START_EVENTS}*/ /**{START_EVENTS}*/
export enum KeymapsEvents { export enum KeymapsEvents {
/** /**
@ -24,5 +26,18 @@ export enum KeymapsEvents {
} }
/**{END_EVENTS}*/ /**{END_EVENTS}*/
export type KeymapEvent =
| `${KeymapsEvents.add}`
| `${KeymapsEvents.remove}`
| `${KeymapsEvents.emit}`
| `${KeymapsEvents.emitId}${string}`;
export interface KeymapsEventCallback {
[KeymapsEvents.add]: [Keymap];
[KeymapsEvents.remove]: [Keymap];
[KeymapsEvents.emit]: [Keymap['id'], string, Event];
[key: `${KeymapsEvents.emitId}${string}`]: [Keymap['id'], string, Event];
}
// need this to avoid the TS documentation generator to break // need this to avoid the TS documentation generator to break
export default KeymapsEvents; export default KeymapsEvents;

3
packages/core/src/modal_dialog/index.ts

@ -40,8 +40,7 @@ import defConfig, { ModalConfig } from './config/config';
import ModalM from './model/Modal'; import ModalM from './model/Modal';
import { ModalEvents } from './types'; import { ModalEvents } from './types';
import ModalView from './view/ModalView'; import ModalView from './view/ModalView';
export type { ModalEvent } from './types';
export type ModalEvent = `${ModalEvents}`;
export default class ModalModule extends Module<ModalConfig> { export default class ModalModule extends Module<ModalConfig> {
modal?: ModalView; modal?: ModalView;

18
packages/core/src/modal_dialog/types.ts

@ -1,3 +1,5 @@
import { ObjectAny } from '../common';
/**{START_EVENTS}*/ /**{START_EVENTS}*/
export enum ModalEvents { export enum ModalEvents {
/** /**
@ -23,5 +25,21 @@ export enum ModalEvents {
} }
/**{END_EVENTS}*/ /**{END_EVENTS}*/
export type ModalEvent = `${ModalEvents}`;
export interface ModalEventData {
open: boolean;
attributes: ObjectAny;
title: Node;
content: Node;
close: () => void;
}
export interface ModalEventCallback {
[ModalEvents.open]: [];
[ModalEvents.close]: [];
[ModalEvents.all]: [ModalEventData];
}
// need this to avoid the TS documentation generator to break // need this to avoid the TS documentation generator to break
export default ModalEvents; export default ModalEvents;

7
packages/core/src/navigator/index.ts

@ -47,8 +47,7 @@ import { hasWin, isComponent, isDef } from '../utils/mixins';
import defConfig, { LayerManagerConfig } from './config/config'; import defConfig, { LayerManagerConfig } from './config/config';
import { LayerData, LayerEvents } from './types'; import { LayerData, LayerEvents } from './types';
import View from './view/ItemView'; import View from './view/ItemView';
export type { LayerEvent } from './types';
export type LayerEvent = `${LayerEvents}`;
const styleOpts = { mediaText: '' }; const styleOpts = { mediaText: '' };
@ -79,7 +78,7 @@ export default class LayerManager extends Module<LayerManagerConfig> {
onLoad() { onLoad() {
const { em, config, model } = this; const { em, config, model } = this;
model.listenTo(em, 'component:selected', this.componentChanged); model.listenTo(em, ComponentsEvents.selected, this.componentChanged);
model.on('change:root', this.__onRootChange); model.on('change:root', this.__onRootChange);
model.listenTo(em, propsToListen, this.__onComponent); model.listenTo(em, propsToListen, this.__onComponent);
this.componentChanged(); this.componentChanged();
@ -180,7 +179,7 @@ export default class LayerManager extends Module<LayerManagerConfig> {
component.setStyle(style, styleOpts as any); component.setStyle(style, styleOpts as any);
this.updateLayer(component); this.updateLayer(component);
this.em.trigger('component:toggled'); // Updates Style Manager #2938 this.em.trigger(ComponentsEvents.toggled); // Updates Style Manager #2938
} }
/** /**

27
packages/core/src/navigator/types.ts

@ -1,3 +1,4 @@
import { ObjectAny } from '../common';
import Component from '../dom_components/model/Component'; import Component from '../dom_components/model/Component';
export interface LayerData { export interface LayerData {
@ -32,8 +33,34 @@ export enum LayerEvents {
* editor.on('layer:custom', ({ container, root }) => { ... }); * editor.on('layer:custom', ({ container, root }) => { ... });
*/ */
custom = 'layer:custom', custom = 'layer:custom',
/**
* @event `layer:render` Component layer rendered. Object with component and rendered layer element is passed as an argument.
* @example
* editor.on('layer:render', ({ component, el }) => { ... });
*/
render = 'layer:render',
} }
/**{END_EVENTS}*/ /**{END_EVENTS}*/
export type LayerEvent = `${LayerEvents}`;
export interface LayerCustomEventData {
container: HTMLElement | undefined;
root: Component;
}
export interface LayerRenderEventData {
component: Component;
el: HTMLElement;
}
export interface LayerEventCallback {
[LayerEvents.root]: [Component];
[LayerEvents.component]: [Component, ObjectAny?];
[LayerEvents.custom]: [LayerCustomEventData];
[LayerEvents.render]: [LayerRenderEventData];
}
// need this to avoid the TS documentation generator to break // need this to avoid the TS documentation generator to break
export default LayerEvents; export default LayerEvents;

3
packages/core/src/navigator/view/ItemView.ts

@ -5,6 +5,7 @@ import ComponentView from '../../dom_components/view/ComponentView';
import EditorModel from '../../editor/model/Editor'; import EditorModel from '../../editor/model/Editor';
import { isEnterKey, isEscKey } from '../../utils/dom'; import { isEnterKey, isEscKey } from '../../utils/dom';
import LayerManager from '../index'; import LayerManager from '../index';
import { LayerEvents } from '../types';
import ItemsView from './ItemsView'; import ItemsView from './ItemsView';
import { getOnComponentDrag, getOnComponentDragEnd, getOnComponentDragStart } from '../../commands'; import { getOnComponentDrag, getOnComponentDragEnd, getOnComponentDragStart } from '../../commands';
import Sorter from '../../utils/sorter/Sorter'; import Sorter from '../../utils/sorter/Sorter';
@ -450,6 +451,6 @@ export default class ItemView extends View {
const { onRender } = config; const { onRender } = config;
const opt = { component: model, el }; const opt = { component: model, el };
onRender.bind(this)(opt); onRender.bind(this)(opt);
this.em.trigger('layer:render', opt); this.em.trigger(LayerEvents.render, opt);
} }
} }

26
packages/core/src/pages/types.ts

@ -1,4 +1,13 @@
import {
AddOptions,
EventCallbackRemove,
EventCallbackRemoveBefore,
EventCallbackUpdate,
ObjectAny,
SetOptions,
} from '../common';
import { ModuleConfig } from '../abstract/Module'; import { ModuleConfig } from '../abstract/Module';
import Page from './model/Page';
import { PageProperties } from './model/Page'; import { PageProperties } from './model/Page';
export interface PageManagerConfig extends ModuleConfig { export interface PageManagerConfig extends ModuleConfig {
@ -66,5 +75,22 @@ export enum PagesEvents {
} }
/**{END_EVENTS}*/ /**{END_EVENTS}*/
export type PageEvent = `${PagesEvents}`;
export interface PagesEventCallback {
[PagesEvents.add]: [Page, AddOptions];
[PagesEvents.addBefore]: [
PageProperties,
AddPage: () => Page | undefined,
AddOptions & SelectableOption & AbortOption,
];
[PagesEvents.remove]: EventCallbackRemove<Page>;
[PagesEvents.removeBefore]: EventCallbackRemoveBefore<Page | undefined>;
[PagesEvents.select]: [Page, Page | undefined];
[PagesEvents.selectBefore]: [Page, SetOptions];
[PagesEvents.update]: EventCallbackUpdate<Page>;
[PagesEvents.all]: [{ event: string; page: Page; options: ObjectAny }];
}
// need this to avoid the TS documentation generator to break // need this to avoid the TS documentation generator to break
export default PagesEvents; export default PagesEvents;

2
packages/core/src/parser/index.ts

@ -96,7 +96,7 @@ export default class ParserModule extends Module<ParserConfig & { name?: string
__emitEvent(event: string, data: ObjectAny) { __emitEvent(event: string, data: ObjectAny) {
const { em, events } = this; const { em, events } = this;
em.trigger(event, data); em.trigger(event, data);
em.trigger(events.all, { event, ...data }); em.trigger(events.all, { event, ...data } as any);
} }
destroy() {} destroy() {}

2
packages/core/src/parser/model/ParserHtml.ts

@ -206,7 +206,7 @@ const ParserHtml = (em?: EditorModel, config: ParserConfig & { returnArray?: boo
const nodesLen = nodes.length; const nodesLen = nodes.length;
let model = this.detectNode(node, opts); let model = this.detectNode(node, opts);
if (!model.tagName) { if (!model.tagName && model.tagName !== '') {
const tag = node.tagName || ''; const tag = node.tagName || '';
const ns = node.namespaceURI || ''; const ns = node.namespaceURI || '';
model.tagName = tag && ns === 'http://www.w3.org/1999/xhtml' ? tag.toLowerCase() : tag; model.tagName = tag && ns === 'http://www.w3.org/1999/xhtml' ? tag.toLowerCase() : tag;

17
packages/core/src/parser/types.ts

@ -1,3 +1,7 @@
import { ObjectAny } from '../common';
import { CssRuleJSON } from '../css_composer/model/CssRule';
import { HTMLParseResult, HTMLParserOptions, ParsedCssRule } from './config/config';
/**{START_EVENTS}*/ /**{START_EVENTS}*/
export enum ParserEvents { export enum ParserEvents {
/** /**
@ -46,5 +50,18 @@ export enum ParserEvents {
} }
/**{END_EVENTS}*/ /**{END_EVENTS}*/
export type ParserEvent = `${ParserEvents}`;
export interface ParserEventCallback {
[ParserEvents.htmlBefore]: [{ input: string }];
[ParserEvents.htmlRoot]: [{ input: string; root: HTMLElement }];
[ParserEvents.html]: [{ input: string; output: HTMLParseResult; options: HTMLParserOptions }];
[ParserEvents.cssBefore]: [{ input: string }];
[ParserEvents.css]: [
{ input: string; output: CssRuleJSON[]; nodes: Array<CssRuleJSON | ParsedCssRule>; error: unknown },
];
[ParserEvents.all]: [{ event: ParserEvent; input: string } & ObjectAny];
}
// need this to avoid the TS documentation generator to break // need this to avoid the TS documentation generator to break
export default ParserEvents; export default ParserEvents;

2
packages/core/src/rich_text_editor/index.ts

@ -43,7 +43,7 @@ import defConfig, { CustomRTE, CustomRteOptions, RichTextEditorConfig } from './
import RichTextEditor, { RichTextEditorAction } from './model/RichTextEditor'; import RichTextEditor, { RichTextEditorAction } from './model/RichTextEditor';
import { ModelRTE, RichTextEditorEvents, RteDisableResult } from './types'; import { ModelRTE, RichTextEditorEvents, RteDisableResult } from './types';
export type { RichTextEditorEvent, RteDisableResult } from './types'; export type { RichTextEditorEvent, RichTextEditorEventCallback, RteDisableResult } from './types';
const eventsUp = `${CanvasEvents.refresh} frame:scroll ${ComponentsEvents.update}`; const eventsUp = `${CanvasEvents.refresh} frame:scroll ${ComponentsEvents.update}`;

16
packages/core/src/rich_text_editor/types.ts

@ -1,4 +1,6 @@
import ComponentTextView from '../dom_components/view/ComponentTextView'; import type ComponentTextView from '../dom_components/view/ComponentTextView';
import type RichTextEditor from './model/RichTextEditor';
import type { RichTextEditorAction } from './model/RichTextEditor';
export interface ModelRTE { export interface ModelRTE {
currentView?: ComponentTextView; currentView?: ComponentTextView;
@ -10,6 +12,12 @@ export interface RteDisableResult {
forceSync?: boolean; forceSync?: boolean;
} }
export interface RichTextEditorCustomEventProps {
enabled: boolean;
container: HTMLElement;
actions: RichTextEditorAction[];
}
/**{START_EVENTS}*/ /**{START_EVENTS}*/
export enum RichTextEditorEvents { export enum RichTextEditorEvents {
/** /**
@ -35,5 +43,11 @@ export enum RichTextEditorEvents {
} }
/**{END_EVENTS}*/ /**{END_EVENTS}*/
export interface RichTextEditorEventCallback {
[RichTextEditorEvents.enable]: [ComponentTextView, RichTextEditor];
[RichTextEditorEvents.disable]: [ComponentTextView, RichTextEditor | undefined];
[RichTextEditorEvents.custom]: [RichTextEditorCustomEventProps];
}
// need this to avoid the TS documentation generator to break // need this to avoid the TS documentation generator to break
export default RichTextEditorEvents; export default RichTextEditorEvents;

4
packages/core/src/selector_manager/index.ts

@ -127,8 +127,8 @@ export default class SelectorManager extends ItemManagerModule<SelectorManagerCo
em.on('change:state', (m, value) => em.trigger(events.state, value)); em.on('change:state', (m, value) => em.trigger(events.state, value));
this.model.on('change:cFirst', (m, value) => em.trigger('selector:type', value)); this.model.on('change:cFirst', (m, value) => em.trigger('selector:type', value));
const eventCmpUpdateCls = `${ComponentsEvents.update}:classes`; const eventCmpUpdateCls = `${ComponentsEvents.update}:classes`;
em.on(`component:toggled ${eventCmpUpdateCls}`, this.__updateSelectedByComponents); em.on(`${ComponentsEvents.toggled} ${eventCmpUpdateCls}`, this.__updateSelectedByComponents);
const listenTo = `component:toggled ${eventCmpUpdateCls} change:device styleManager:update selector:state selector:type style:target`; const listenTo = `${ComponentsEvents.toggled} ${eventCmpUpdateCls} change:device styleManager:update selector:state selector:type style:target`;
this.model.listenTo(em, listenTo, () => this.__update()); this.model.listenTo(em, listenTo, () => this.__update());
} }

37
packages/core/src/selector_manager/types.ts

@ -1,3 +1,16 @@
import {
Collection,
EventCallbackAdd,
EventCallbackAll,
EventCallbackRemove,
EventCallbackRemoveBefore,
EventCallbackUpdate,
ObjectAny,
} from '../common';
import Selector from './model/Selector';
import Selectors from './model/Selectors';
import State from './model/State';
/**{START_EVENTS}*/ /**{START_EVENTS}*/
export enum SelectorEvents { export enum SelectorEvents {
/** /**
@ -51,7 +64,31 @@ export enum SelectorEvents {
} }
/**{END_EVENTS}*/ /**{END_EVENTS}*/
export type SelectorEvent = `${SelectorEvents}`;
export type SelectorStringObject = string | { name?: string; label?: string; type?: number }; export type SelectorStringObject = string | { name?: string; label?: string; type?: number };
export type SelectorStateEventData = State | Collection<State> | string;
export interface SelectorStateEventOptions extends ObjectAny {
event?: string;
}
export interface SelectorCustomEventData {
states: State[];
selected: Selector[];
container: HTMLElement | undefined;
}
export interface SelectorEventCallback {
[SelectorEvents.add]: EventCallbackAdd<Selector>;
[SelectorEvents.remove]: EventCallbackRemove<Selector>;
[SelectorEvents.removeBefore]: EventCallbackRemoveBefore<Selector | undefined>;
[SelectorEvents.update]: EventCallbackUpdate<Selector>;
[SelectorEvents.state]: [SelectorStateEventData, SelectorStateEventOptions?];
[SelectorEvents.custom]: [SelectorCustomEventData];
[SelectorEvents.all]: EventCallbackAll<SelectorEvent, Selector | Selectors>;
}
// need this to avoid the TS documentation generator to break // need this to avoid the TS documentation generator to break
export default SelectorEvents; export default SelectorEvents;

6
packages/core/src/selector_manager/view/ClassTagsView.ts

@ -86,7 +86,7 @@ export default class ClassTagsView extends View<Selector> {
this.checkSync = debounce(this.checkSync.bind(this), 0); this.checkSync = debounce(this.checkSync.bind(this), 0);
const eventCmpUpdate = ComponentsEvents.update; const eventCmpUpdate = ComponentsEvents.update;
const evClsUp = `${eventCmpUpdate}:classes`; const evClsUp = `${eventCmpUpdate}:classes`;
const toList = `component:toggled ${evClsUp}`; const toList = `${ComponentsEvents.toggled} ${evClsUp}`;
const toListCls = `${evClsUp} ${eventCmpUpdate}:attributes:id change:state`; const toListCls = `${evClsUp} ${eventCmpUpdate}:attributes:id change:state`;
this.listenTo(em, toList, this.componentChanged); this.listenTo(em, toList, this.componentChanged);
this.listenTo(em, 'styleManager:update', this.componentChanged); this.listenTo(em, 'styleManager:update', this.componentChanged);
@ -126,8 +126,8 @@ export default class ClassTagsView extends View<Selector> {
}); });
style && rule.addStyle(style); style && rule.addStyle(style);
em.trigger('component:toggled'); em.trigger(ComponentsEvents.toggled);
em.trigger('component:sync-style', { em.trigger(ComponentsEvents.syncStyle, {
component: target, component: target,
selectors, selectors,
mediaText, mediaText,

7
packages/core/src/storage_manager/index.ts

@ -47,13 +47,10 @@ import LocalStorage from './model/LocalStorage';
import RemoteStorage from './model/RemoteStorage'; import RemoteStorage from './model/RemoteStorage';
import EditorModel from '../editor/model/Editor'; import EditorModel from '../editor/model/Editor';
import IStorage, { StorageOptions, ProjectData } from './model/IStorage'; import IStorage, { StorageOptions, ProjectData } from './model/IStorage';
import StorageEvents from './types'; import StorageEvents, { StorageEventType } from './types';
export type { StorageOptions, ProjectData } from './model/IStorage'; export type { StorageOptions, ProjectData } from './model/IStorage';
export type { StorageEvent, StorageEventCallback, StorageEventType } from './types';
export type StorageEvent = `${StorageEvents}`;
type StorageEventType = 'store' | 'load';
const STORAGE_LOCAL = 'local'; const STORAGE_LOCAL = 'local';
const STORAGE_REMOTE = 'remote'; const STORAGE_REMOTE = 'remote';

23
packages/core/src/storage_manager/types.ts

@ -1,3 +1,7 @@
import { ProjectData } from './model/IStorage';
export type StorageEventType = 'store' | 'load';
/**{START_EVENTS}*/ /**{START_EVENTS}*/
export enum StorageEvents { export enum StorageEvents {
/** /**
@ -112,5 +116,24 @@ export enum StorageEvents {
} }
/**{END_EVENTS}*/ /**{END_EVENTS}*/
export type StorageEvent = `${StorageEvents}`;
export interface StorageEventCallback {
[StorageEvents.start]: [StorageEventType, ProjectData | undefined];
[StorageEvents.startStore]: [ProjectData];
[StorageEvents.startLoad]: [ProjectData | undefined];
[StorageEvents.load]: [ProjectData, unknown];
[StorageEvents.store]: [ProjectData, unknown];
[StorageEvents.after]: [];
[StorageEvents.afterStore]: [ProjectData, unknown];
[StorageEvents.afterLoad]: [ProjectData, unknown];
[StorageEvents.end]: [StorageEventType, unknown, unknown?];
[StorageEvents.endStore]: [unknown, unknown?];
[StorageEvents.endLoad]: [unknown, unknown?];
[StorageEvents.error]: [unknown, StorageEventType];
[StorageEvents.errorStore]: [unknown];
[StorageEvents.errorLoad]: [unknown];
}
// need this to avoid the TS documentation generator to break // need this to avoid the TS documentation generator to break
export default StorageEvents; export default StorageEvents;

8
packages/core/src/style_manager/index.ts

@ -68,9 +68,7 @@ import { PropertyTypes, StyleManagerEvents, StyleTarget } from './types';
import { CustomPropertyView } from './view/PropertyView'; import { CustomPropertyView } from './view/PropertyView';
import SectorsView from './view/SectorsView'; import SectorsView from './view/SectorsView';
export type { PropertyTypes, StyleModuleParam, StyleTarget } from './types'; export type { PropertyTypes, StyleManagerEventCallback, StyleModuleParam, StyleTarget } from './types';
export type StyleManagerEvent = `${StyleManagerEvents}`;
const propDef = (value: any) => value || value === 0; const propDef = (value: any) => value || value === 0;
@ -116,11 +114,11 @@ export default class StyleManager extends ItemManagerModule<
// Triggers for the selection refresh and properties // Triggers for the selection refresh and properties
const eventCmpUpdate = ComponentsEvents.update; const eventCmpUpdate = ComponentsEvents.update;
const ev = `component:toggled ${eventCmpUpdate}:classes change:state change:device frame:resized selector:type`; const ev = `${ComponentsEvents.toggled} ${eventCmpUpdate}:classes change:state change:device frame:resized selector:type`;
this.upAll = debounce(() => this.__upSel(), 0); this.upAll = debounce(() => this.__upSel(), 0);
model.listenTo(em, ev, this.upAll as any); model.listenTo(em, ev, this.upAll as any);
// Clear state target on any component selection change, without debounce (#4208) // Clear state target on any component selection change, without debounce (#4208)
model.listenTo(em, 'component:toggled', this.__clearStateTarget); model.listenTo(em, ComponentsEvents.toggled, this.__clearStateTarget);
// Triggers only for properties (avoid selection refresh) // Triggers only for properties (avoid selection refresh)
const upProps = debounce(() => { const upProps = debounce(() => {

42
packages/core/src/style_manager/types.ts

@ -1,5 +1,10 @@
import StyleManager from '.'; import StyleManager from '.';
import { AddOptions, ObjectAny, RemoveOptions } from '../common';
import StyleableModel from '../domain_abstract/model/StyleableModel'; import StyleableModel from '../domain_abstract/model/StyleableModel';
import Property, { PropertyProps } from './model/Property';
import PropertyStack from './model/PropertyStack';
import Sector, { SectorProperties } from './model/Sector';
import Sectors from './model/Sectors';
import { PropertyNumberProps } from './model/PropertyNumber'; import { PropertyNumberProps } from './model/PropertyNumber';
import { PropertySelectProps } from './model/PropertySelect'; import { PropertySelectProps } from './model/PropertySelect';
import { PropertyStackProps } from './model/PropertyStack'; import { PropertyStackProps } from './model/PropertyStack';
@ -84,5 +89,42 @@ export enum StyleManagerEvents {
} }
/**{END_EVENTS}*/ /**{END_EVENTS}*/
export type StyleManagerEvent = `${StyleManagerEvents}`;
export interface StyleManagerPropertyUpdateEventData {
property: Property;
from: Partial<PropertyProps>;
to: Partial<PropertyProps>;
value: any;
opts: ObjectAny;
}
export interface StyleManagerLayerSelectEventData {
property: PropertyStack;
}
export interface StyleManagerCustomEventData {
container: HTMLElement | undefined;
}
export interface StyleManagerAllEventData {
event: string;
model?: Sector | Sectors;
options: ObjectAny;
}
export interface StyleManagerEventCallback {
[StyleManagerEvents.sectorAdd]: [Sector, AddOptions];
[StyleManagerEvents.sectorRemove]: [Sector, RemoveOptions];
[StyleManagerEvents.sectorUpdate]: [Sector, Partial<SectorProperties>, ObjectAny];
[StyleManagerEvents.propertyAdd]: [Property, AddOptions];
[StyleManagerEvents.propertyRemove]: [Property, RemoveOptions];
[StyleManagerEvents.propertyUpdate]: [StyleManagerPropertyUpdateEventData];
[StyleManagerEvents.target]: [StyleTarget | undefined];
[StyleManagerEvents.layerSelect]: [StyleManagerLayerSelectEventData];
[StyleManagerEvents.custom]: [StyleManagerCustomEventData];
[StyleManagerEvents.all]: [StyleManagerAllEventData];
}
// need this to avoid the TS documentation generator to break // need this to avoid the TS documentation generator to break
export default StyleManagerEvents; export default StyleManagerEvents;

5
packages/core/src/trait_manager/index.ts

@ -32,6 +32,7 @@ import { bindAll, debounce } from 'underscore';
import { Module } from '../abstract'; import { Module } from '../abstract';
import { Model } from '../common'; import { Model } from '../common';
import Component from '../dom_components/model/Component'; import Component from '../dom_components/model/Component';
import { ComponentsEvents } from '../dom_components/types';
import EditorModel from '../editor/model/Editor'; import EditorModel from '../editor/model/Editor';
import defConfig from './config/config'; import defConfig from './config/config';
import { import {
@ -89,7 +90,7 @@ export default class TraitManager extends Module<TraitManagerConfigModule> {
const upAll = debounce(() => this.__upSel(), 0); const upAll = debounce(() => this.__upSel(), 0);
const update = debounce(() => this.__onUp(), 0); const update = debounce(() => this.__onUp(), 0);
state.listenTo(em, 'component:toggled', upAll); state.listenTo(em, ComponentsEvents.toggled, upAll);
state.listenTo(em, events.value, update); state.listenTo(em, events.value, update);
state.on('change:traits', this.__onSelect); state.on('change:traits', this.__onSelect);
@ -226,7 +227,7 @@ export default class TraitManager extends Module<TraitManagerConfigModule> {
__onSelect() { __onSelect() {
const { em, events, state } = this; const { em, events, state } = this;
const { component, traits } = state.attributes; const { component, traits } = state.attributes;
em.trigger(events.select, { component, traits }); em.trigger(events.select, { component, traits: traits as Trait[] });
} }
__trgCustom(opts: TraitCustomData = {}) { __trgCustom(opts: TraitCustomData = {}) {

2
packages/core/src/trait_manager/model/Trait.ts

@ -257,7 +257,7 @@ export default class Trait extends Model<TraitProperties> {
component.trigger(TraitsEvents.value, props); component.trigger(TraitsEvents.value, props);
em?.trigger(TraitsEvents.value, props); em?.trigger(TraitsEvents.value, props);
// This should be triggered for any trait prop change // This should be triggered for any trait prop change
em?.trigger('trait:update', props); em?.trigger(TraitsEvents.update, props);
} }
getTargetValue(opts: TraitGetValueOptions = {}) { getTargetValue(opts: TraitGetValueOptions = {}) {

45
packages/core/src/trait_manager/types.ts

@ -1,4 +1,5 @@
import { CategoryProperties, ItemsByCategory } from '../abstract/ModuleCategory'; import Category, { CategoryProperties, ItemsByCategory } from '../abstract/ModuleCategory';
import { ObjectAny } from '../common';
import Component from '../dom_components/model/Component'; import Component from '../dom_components/model/Component';
import Editor from '../editor'; import Editor from '../editor';
import EditorModel from '../editor/model/Editor'; import EditorModel from '../editor/model/Editor';
@ -38,6 +39,34 @@ export interface TraitCustomData {
container?: HTMLElement; container?: HTMLElement;
} }
export interface TraitSelectEventData {
component?: Component;
traits: Trait[];
}
export interface TraitValueEventData {
trait: Trait;
component: Component;
value: any;
}
export interface TraitCategoryUpdateEventData {
category: Category;
changes: Partial<CategoryProperties>;
options: ObjectAny;
}
export interface TraitAllEventData {
event: string;
trait?: Trait;
component?: Component;
value?: any;
category?: Category;
changes?: Partial<CategoryProperties>;
options?: ObjectAny;
container?: HTMLElement;
}
export interface TraitProperties { export interface TraitProperties {
/** /**
* Trait type, defines how the trait should be rendered. * Trait type, defines how the trait should be rendered.
@ -177,8 +206,6 @@ export interface TraitOption {
[key: string]: unknown; [key: string]: unknown;
} }
export type TraitsEvent = `${TraitsEvents}`;
/**{START_EVENTS}*/ /**{START_EVENTS}*/
export enum TraitsEvents { export enum TraitsEvents {
/** /**
@ -194,6 +221,7 @@ export enum TraitsEvents {
* editor.on('trait:value', ({ trait, component, value }) => { ... }); * editor.on('trait:value', ({ trait, component, value }) => { ... });
*/ */
value = 'trait:value', value = 'trait:value',
update = 'trait:update',
/** /**
* @event `trait:category:update` Trait category updated. * @event `trait:category:update` Trait category updated.
@ -218,5 +246,16 @@ export enum TraitsEvents {
} }
/**{END_EVENTS}*/ /**{END_EVENTS}*/
export type TraitEvent = `${TraitsEvents}`;
export interface TraitEventCallback {
[TraitsEvents.select]: [TraitSelectEventData];
[TraitsEvents.value]: [TraitValueEventData];
[TraitsEvents.update]: [TraitValueEventData];
[TraitsEvents.categoryUpdate]: [TraitCategoryUpdateEventData];
[TraitsEvents.custom]: [TraitCustomData];
[TraitsEvents.all]: [TraitAllEventData];
}
// need this to avoid the TS documentation generator to break // need this to avoid the TS documentation generator to break
export default TraitsEvents; export default TraitsEvents;

3
packages/core/src/trait_manager/view/TraitsView.ts

@ -1,5 +1,6 @@
import TraitManager from '..'; import TraitManager from '..';
import CategoryView from '../../abstract/ModuleCategoryView'; import CategoryView from '../../abstract/ModuleCategoryView';
import { ComponentsEvents } from '../../dom_components/types';
import DomainViews from '../../domain_abstract/view/DomainViews'; import DomainViews from '../../domain_abstract/view/DomainViews';
import EditorModel from '../../editor/model/Editor'; import EditorModel from '../../editor/model/Editor';
import Trait from '../model/Trait'; import Trait from '../model/Trait';
@ -49,7 +50,7 @@ export default class TraitsView extends DomainViews {
this.classNoCat = `${ppfx}traits-empty-c`; this.classNoCat = `${ppfx}traits-empty-c`;
this.catsClass = `${ppfx}trait-categories`; this.catsClass = `${ppfx}trait-categories`;
this.collection = new Traits([], { em }); this.collection = new Traits([], { em });
this.listenTo(em, 'component:toggled', this.updatedCollection); this.listenTo(em, ComponentsEvents.toggled, this.updatedCollection);
this.updatedCollection(); this.updatedCollection();
} }

11
packages/core/src/utils/Droppable.ts

@ -1,5 +1,6 @@
import { bindAll, indexOf } from 'underscore'; import { bindAll, indexOf } from 'underscore';
import CanvasModule from '../canvas'; import CanvasModule from '../canvas';
import CanvasEvents from '../canvas/types';
import { ObjectStrings } from '../common'; import { ObjectStrings } from '../common';
import Component from '../dom_components/model/Component'; import Component from '../dom_components/model/Component';
import EditorModel from '../editor/model/Editor'; import EditorModel from '../editor/model/Editor';
@ -94,7 +95,7 @@ export default class Droppable {
this.counter = 0; this.counter = 0;
dragStop && dragStop(cancel || !this.over); dragStop && dragStop(cancel || !this.over);
this.__customTglEff(false); this.__customTglEff(false);
em.trigger('canvas:dragend', ev); em.trigger(CanvasEvents.dragEnd, ev);
} }
handleDragLeave(ev: Event) { handleDragLeave(ev: Event) {
@ -204,7 +205,7 @@ export default class Droppable {
} }
this.dragStop = dragStop; this.dragStop = dragStop;
em.trigger('canvas:dragenter', dt, content); em.trigger(CanvasEvents.dragEnter, dt, content);
} }
handleDragEnd(model: any, dt: any) { handleDragEnd(model: any, dt: any) {
@ -212,7 +213,7 @@ export default class Droppable {
this.over = false; this.over = false;
if (model) { if (model) {
em.set('dragResult', model); em.set('dragResult', model);
em.trigger('canvas:drop', dt, model); em.trigger(CanvasEvents.drop, dt, model);
} }
em.runDefault({ preserveSelected: 1 }); em.runDefault({ preserveSelected: 1 });
} }
@ -223,7 +224,7 @@ export default class Droppable {
*/ */
handleDragOver(ev: Event) { handleDragOver(ev: Event) {
ev.preventDefault(); ev.preventDefault();
this.em.trigger('canvas:dragover', ev); this.em.trigger(CanvasEvents.dragOver, ev);
} }
/** /**
@ -286,7 +287,7 @@ export default class Droppable {
result.content = content; result.content = content;
}, },
}; };
em.trigger('canvas:dragdata', dt, result); em.trigger(CanvasEvents.dragData, dt, result);
return result; return result;
} }
} }

8
packages/core/test/specs/pages/index.ts

@ -197,7 +197,7 @@ describe('Managing pages', () => {
test('Abort add page', () => { test('Abort add page', () => {
em.on(pm.events.addBefore, (p, c, opts) => { em.on(pm.events.addBefore, (p, c, opts) => {
opts.abort = 1; opts.abort = true;
}); });
pm.add({}); pm.add({});
expect(pm.getAll().length).toBe(1); expect(pm.getAll().length).toBe(1);
@ -205,7 +205,7 @@ describe('Managing pages', () => {
test('Abort add page and complete', () => { test('Abort add page and complete', () => {
em.on(pm.events.addBefore, (p, complete, opts) => { em.on(pm.events.addBefore, (p, complete, opts) => {
opts.abort = 1; opts.abort = true;
complete(); complete();
}); });
pm.add({}); pm.add({});
@ -223,7 +223,7 @@ describe('Managing pages', () => {
test('Abort remove page', () => { test('Abort remove page', () => {
em.on(pm.events.removeBefore, (p, c, opts) => { em.on(pm.events.removeBefore, (p, c, opts) => {
opts.abort = 1; (opts as any).abort = true;
}); });
const page = pm.add({})!; const page = pm.add({})!;
pm.remove(`${page.id}`); pm.remove(`${page.id}`);
@ -232,7 +232,7 @@ describe('Managing pages', () => {
test('Abort remove page and complete', () => { test('Abort remove page and complete', () => {
em.on(pm.events.removeBefore, (p, complete, opts) => { em.on(pm.events.removeBefore, (p, complete, opts) => {
opts.abort = 1; (opts as any).abort = true;
complete(); complete();
}); });
const page = pm.add({})!; const page = pm.add({})!;

Loading…
Cancel
Save