@node-projects/web-component-designer 0.0.185 → 0.0.187

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4 @@
1
+ export declare function copyTextToClipboard(text: any): Promise<void>;
2
+ export declare function copyToClipboard(items: [format: string, data: string][]): Promise<void>;
3
+ export declare function getTextFromClipboard(): Promise<string>;
4
+ export declare function getFromClipboard(): Promise<ClipboardItems>;
@@ -0,0 +1,84 @@
1
+ export async function copyTextToClipboard(text) {
2
+ copyToClipboard(['text/plain', text]);
3
+ }
4
+ export async function copyToClipboard(items) {
5
+ if (navigator.clipboard) {
6
+ try {
7
+ let data = [];
8
+ for (let n of items) {
9
+ data.push(new ClipboardItem({ [n[0]]: new Blob([n[1]], { type: n[0] }) }));
10
+ }
11
+ await navigator.clipboard.write(data);
12
+ }
13
+ catch (err) {
14
+ await navigator.clipboard.writeText(items[0][1]);
15
+ }
16
+ console.info('Copy to clipboard successful');
17
+ }
18
+ else {
19
+ const textArea = document.createElement('textarea');
20
+ textArea.style.position = 'fixed';
21
+ textArea.style.top = '0';
22
+ textArea.style.left = '0';
23
+ textArea.style.width = '2em';
24
+ textArea.style.height = '2em';
25
+ textArea.style.padding = '0';
26
+ textArea.style.border = 'none';
27
+ textArea.style.outline = 'none';
28
+ textArea.style.boxShadow = 'none';
29
+ textArea.style.background = 'transparent';
30
+ textArea.value = items[0][1];
31
+ document.body.appendChild(textArea);
32
+ textArea.select();
33
+ try {
34
+ document.execCommand('copy');
35
+ }
36
+ catch (err) {
37
+ try {
38
+ document.execCommand('copy');
39
+ }
40
+ catch (err) {
41
+ console.error(err);
42
+ }
43
+ }
44
+ document.body.removeChild(textArea);
45
+ }
46
+ }
47
+ export async function getTextFromClipboard() {
48
+ if (navigator.clipboard) {
49
+ return new Promise(async (resolve, reject) => {
50
+ const clipText = await navigator.clipboard.readText();
51
+ resolve(clipText);
52
+ });
53
+ }
54
+ else {
55
+ return new Promise(async (resolve, reject) => {
56
+ const textArea = document.createElement('textarea');
57
+ textArea.style.position = 'fixed';
58
+ textArea.style.top = '0';
59
+ textArea.style.left = '0';
60
+ textArea.style.width = '2em';
61
+ textArea.style.height = '2em';
62
+ textArea.style.padding = '0';
63
+ textArea.style.border = 'none';
64
+ textArea.style.outline = 'none';
65
+ textArea.style.boxShadow = 'none';
66
+ textArea.style.background = 'transparent';
67
+ document.body.appendChild(textArea);
68
+ textArea.focus();
69
+ textArea.select();
70
+ document.execCommand('paste');
71
+ let value = textArea.value;
72
+ document.body.removeChild(textArea);
73
+ resolve(value);
74
+ });
75
+ }
76
+ }
77
+ export async function getFromClipboard() {
78
+ if (navigator.clipboard) {
79
+ return await navigator.clipboard.read();
80
+ }
81
+ else {
82
+ return null;
83
+ }
84
+ }
@@ -6,7 +6,7 @@ export declare class NpmPackageLoader {
6
6
  private _dependecies;
7
7
  constructor(packageSource?: string);
8
8
  static patchCustomElementsRegistryToHandleErrors(): void;
9
- loadNpmPackage(pkg: string, serviceContainer: ServiceContainer, paletteTree: PaletteTreeView, reportState?: (state: string) => void): Promise<void>;
9
+ loadNpmPackage(pkg: string, serviceContainer: ServiceContainer, paletteTree: PaletteTreeView, loadAllImports: boolean, reportState?: (state: string) => void): Promise<void>;
10
10
  loadDependency(dependency: string, version?: string, reportState?: (state: string) => void): Promise<void>;
11
11
  addToImportmap(baseUrl: string, packageJsonObj: {
12
12
  name?: string;
@@ -41,7 +41,7 @@ export class NpmPackageLoader {
41
41
  }
42
42
  }
43
43
  //TODO: remove paletteTree form params. elements should be added to serviceconatiner, and the container should notify
44
- async loadNpmPackage(pkg, serviceContainer, paletteTree, reportState) {
44
+ async loadNpmPackage(pkg, serviceContainer, paletteTree, loadAllImports, reportState) {
45
45
  const baseUrl = window.location.protocol + this._packageSource + pkg + '/';
46
46
  const packageJsonUrl = baseUrl + 'package.json';
47
47
  if (reportState)
@@ -106,7 +106,7 @@ export class NpmPackageLoader {
106
106
  serviceContainer.register('elementsService', elements);
107
107
  let properties = new WebcomponentManifestPropertiesService(packageJsonObj.name, customElementsJsonObj);
108
108
  serviceContainer.register('propertyService', properties);
109
- if (window.location.search.includes("loadAllImports")) {
109
+ if (loadAllImports) {
110
110
  for (let e of await elements.getElements()) {
111
111
  //@ts-ignore
112
112
  importShim(e.import);
@@ -17,6 +17,7 @@ export declare class DesignItem implements IDesignItem {
17
17
  appliedDesignerExtensions: Map<ExtensionType, IDesignerExtension[]>;
18
18
  shouldAppliedDesignerExtensions: Map<ExtensionType, IDesignerExtensionProvider[]>;
19
19
  clone(): Promise<IDesignItem>;
20
+ allMatching(selectors: string): Generator<IDesignItem, void, undefined>;
20
21
  replaceNode(newNode: Node): void;
21
22
  get nodeType(): NodeType;
22
23
  private _attributes;
@@ -31,6 +31,15 @@ export class DesignItem {
31
31
  }
32
32
  return null;
33
33
  }
34
+ *allMatching(selectors) {
35
+ if (this.hasChildren) {
36
+ for (let d of this.children()) {
37
+ if (d.element.matches(selectors))
38
+ yield d;
39
+ yield* d.allMatching(selectors);
40
+ }
41
+ }
42
+ }
34
43
  replaceNode(newNode) {
35
44
  DesignItem._designItemMap.delete(this.node);
36
45
  DesignItem._designItemMap.set(newNode, this);
@@ -19,6 +19,7 @@ export interface IDesignItem {
19
19
  readonly hasStyles: boolean;
20
20
  readonly hasChildren: boolean;
21
21
  children(): IterableIterator<IDesignItem>;
22
+ allMatching(selectors: string): IterableIterator<IDesignItem>;
22
23
  readonly childCount: number;
23
24
  readonly firstChild: IDesignItem;
24
25
  readonly parent: IDesignItem;
@@ -1,32 +1,32 @@
1
1
  import { DomConverter } from "../../widgets/designerView/DomConverter.js";
2
+ import { copyToClipboard, getFromClipboard, getTextFromClipboard } from "../../helper/ClipboardHelper.js";
2
3
  export const positionsJsonMime = 'web text/positions';
3
4
  export class CopyPasteService {
4
5
  async copyItems(designItems) {
5
6
  const copyText = DomConverter.ConvertToString(designItems, null, false);
6
- try {
7
- const positions = designItems.map(x => x.instanceServiceContainer.designerCanvas.getNormalizedElementCoordinates(x.element));
8
- const data = [new ClipboardItem({ ["text/html"]: new Blob([copyText], { type: 'text/html' }), [positionsJsonMime]: new Blob([JSON.stringify(positions)], { type: positionsJsonMime }) })];
9
- await navigator.clipboard.write(data);
10
- }
11
- catch (err) {
12
- await navigator.clipboard.writeText(copyText);
13
- }
7
+ const positions = designItems.map(x => x.instanceServiceContainer.designerCanvas.getNormalizedElementCoordinates(x.element));
8
+ copyToClipboard([["text/html", copyText], [positionsJsonMime, JSON.stringify(positions)]]);
14
9
  }
15
10
  async getPasteItems(serviceContainer, instanceServiceContainer) {
16
- const items = await navigator.clipboard.read();
17
11
  let html = '';
18
- try {
19
- html = await (await items[0].getType('text/html'))?.text();
20
- }
21
- catch { }
22
- if (!html)
23
- html = await (await items[0].getType('text/plain'))?.text();
24
12
  let positions = null;
25
- try {
26
- let positionsJson = await (await items[0].getType(positionsJsonMime))?.text();
27
- positions = JSON.parse(positionsJson);
13
+ const items = await getFromClipboard();
14
+ if (items != null) {
15
+ try {
16
+ html = await (await items[0].getType('text/html'))?.text();
17
+ }
18
+ catch { }
19
+ if (!html)
20
+ html = await (await items[0].getType('text/plain'))?.text();
21
+ try {
22
+ let positionsJson = await (await items[0].getType(positionsJsonMime))?.text();
23
+ positions = JSON.parse(positionsJson);
24
+ }
25
+ catch { }
26
+ }
27
+ else {
28
+ html = await getTextFromClipboard();
28
29
  }
29
- catch { }
30
30
  const parserService = serviceContainer.htmlParserService;
31
31
  return [await parserService.parse(html, serviceContainer, instanceServiceContainer), positions];
32
32
  }
@@ -0,0 +1,12 @@
1
+ import { InstanceServiceContainer } from '../InstanceServiceContainer.js';
2
+ import { ServiceContainer } from '../ServiceContainer.js';
3
+ import { IHtmlParserService } from './IHtmlParserService.js';
4
+ import { IDesignItem } from '../../item/IDesignItem.js';
5
+ export declare abstract class AbstractClassElementParserService implements IHtmlParserService {
6
+ private _parserUrl;
7
+ private _esprimaUrl;
8
+ constructor(parserUrl?: string, esprimaUrl?: string);
9
+ parse(module: string, serviceContainer: ServiceContainer, instanceServiceContainer: InstanceServiceContainer): Promise<IDesignItem[]>;
10
+ private _parseDiv;
11
+ _createDesignItemsRecursive(item: any, serviceContainer: ServiceContainer, instanceServiceContainer: InstanceServiceContainer, namespace: string): IDesignItem;
12
+ }
@@ -0,0 +1,121 @@
1
+ import { DesignItem } from '../../item/DesignItem.js';
2
+ import { CssAttributeParser } from '../../helper/CssAttributeParser.js';
3
+ import { newElementFromString } from '../../helper/ElementHelper.js';
4
+ function* getChildNodes(node) {
5
+ switch (node.type) {
6
+ case 'Program':
7
+ yield node.body;
8
+ break;
9
+ case 'ClassDeclaration':
10
+ yield node.body;
11
+ break;
12
+ case 'MethodDefinition':
13
+ yield node.value;
14
+ break;
15
+ }
16
+ }
17
+ //WIP - not yet workin
18
+ //Parse HTML inside of Javascript Classes
19
+ export class AbstractClassElementParserService {
20
+ _parserUrl;
21
+ _esprimaUrl;
22
+ constructor(parserUrl = '../../../../../node-html-parser-esm/dist/index.js', esprimaUrl = '../../../../../esprima-next/dist/esm/esprima.js') {
23
+ this._parserUrl = parserUrl;
24
+ this._esprimaUrl = esprimaUrl;
25
+ }
26
+ async parse(module, serviceContainer, instanceServiceContainer) {
27
+ let esprima = await import(this._esprimaUrl);
28
+ const parsedModule = esprima.parseModule(module);
29
+ const classDecl = parsedModule.body.find(x => x.type == esprima.Syntax.ClassDeclaration);
30
+ const renderMethod = classDecl.body.body.find(x => x.type == esprima.Syntax.MethodDefinition && x.key.name == 'render');
31
+ const renderMethodStatement = renderMethod.value.body.body[0];
32
+ const taggedTemplate = renderMethodStatement.argument;
33
+ const templateLiteral = taggedTemplate.quasi;
34
+ //@ts-ignore
35
+ const tmp = getChildNodes(parsedModule);
36
+ const html = templateLiteral.quasis.map(x => x.value.raw).join();
37
+ //@ts-ignore
38
+ let parser = await import(this._parserUrl);
39
+ const parsed = parser.parse(html, { comment: true });
40
+ let designItems = [];
41
+ for (let p of parsed.childNodes) {
42
+ let di = this._createDesignItemsRecursive(p, serviceContainer, instanceServiceContainer, null);
43
+ if (di != null)
44
+ designItems.push(di);
45
+ else
46
+ console.warn("NodeHtmlParserService - could not parse element", p);
47
+ }
48
+ return designItems;
49
+ }
50
+ _parseDiv = document.createElement("div");
51
+ _createDesignItemsRecursive(item, serviceContainer, instanceServiceContainer, namespace) {
52
+ let designItem = null;
53
+ if (item.nodeType == 1) {
54
+ let element;
55
+ let manualCreatedElement = false;
56
+ if (!namespace)
57
+ element = newElementFromString('<' + item.rawTagName + ' ' + item.rawAttrs + '></' + item.rawTagName + '>'); // some custom elements only parse attributes during constructor call
58
+ if (!element) {
59
+ if (namespace)
60
+ element = document.createElementNS(namespace, item.rawTagName);
61
+ else
62
+ element = document.createElement(item.rawTagName);
63
+ manualCreatedElement = true;
64
+ }
65
+ designItem = new DesignItem(element, item, serviceContainer, instanceServiceContainer);
66
+ let hideAtDesignTime = false;
67
+ let hideAtRunTime = false;
68
+ let lockAtDesignTime = false;
69
+ let style = '';
70
+ let attr = item.attributes;
71
+ for (let a in attr) {
72
+ if (a !== 'style') {
73
+ designItem._withoutUndoSetAttribute(a, attr[a]);
74
+ if (manualCreatedElement) {
75
+ element.setAttribute(a, attr[a]);
76
+ }
77
+ if (a === 'node-projects-hide-at-design-time')
78
+ hideAtDesignTime = true;
79
+ else if (a === 'node-projects-hide-at-run-time')
80
+ hideAtRunTime = true;
81
+ else if (a === 'node-projects-lock-at-design-time')
82
+ lockAtDesignTime = true;
83
+ }
84
+ else {
85
+ style = attr[a];
86
+ }
87
+ }
88
+ if ((element instanceof HTMLElement || element instanceof SVGElement) && style) {
89
+ let styleParser = new CssAttributeParser();
90
+ styleParser.parse(style);
91
+ for (let s of styleParser.entries) {
92
+ designItem._withoutUndoSetStyle(s.name, s.value);
93
+ if (manualCreatedElement) {
94
+ element.style[s.name] = s.value;
95
+ }
96
+ }
97
+ }
98
+ if (!lockAtDesignTime && (element instanceof HTMLElement || element instanceof SVGElement)) {
99
+ requestAnimationFrame(() => element.style.pointerEvents = 'auto');
100
+ }
101
+ designItem.hideAtDesignTime = hideAtDesignTime;
102
+ designItem.hideAtRunTime = hideAtRunTime;
103
+ designItem.lockAtDesignTime = lockAtDesignTime;
104
+ element.draggable = false; //even if it should be true, for better designer exp.
105
+ for (let c of item.childNodes) {
106
+ let di = this._createDesignItemsRecursive(c, serviceContainer, instanceServiceContainer, element instanceof SVGElement ? 'http://www.w3.org/2000/svg' : null);
107
+ designItem._insertChildInternal(di);
108
+ }
109
+ }
110
+ else if (item.nodeType == 3) {
111
+ this._parseDiv.innerHTML = item.rawText;
112
+ let element = this._parseDiv.childNodes[0];
113
+ designItem = new DesignItem(element, item, serviceContainer, instanceServiceContainer);
114
+ }
115
+ else if (item.nodeType == 8) {
116
+ let element = document.createComment(item.rawText);
117
+ designItem = new DesignItem(element, item, serviceContainer, instanceServiceContainer);
118
+ }
119
+ return designItem;
120
+ }
121
+ }
@@ -35,6 +35,7 @@ export declare class DesignerCanvas extends BaseCustomWebComponentLazyAppend imp
35
35
  private _additionalStyle;
36
36
  private _currentContextMenu;
37
37
  private _backgroundImage;
38
+ private _enableSelectTextNodesOnClick;
38
39
  get zoomFactor(): number;
39
40
  set zoomFactor(value: number);
40
41
  get scaleFactor(): number;
@@ -40,6 +40,7 @@ export class DesignerCanvas extends BaseCustomWebComponentLazyAppend {
40
40
  _additionalStyle;
41
41
  _currentContextMenu;
42
42
  _backgroundImage;
43
+ _enableSelectTextNodesOnClick = false;
43
44
  get zoomFactor() {
44
45
  return this._zoomFactor;
45
46
  }
@@ -910,6 +911,18 @@ export class DesignerCanvas extends BaseCustomWebComponentLazyAppend {
910
911
  if (!currentElement) {
911
912
  currentElement = this._canvas;
912
913
  }
914
+ else if (this._enableSelectTextNodesOnClick) {
915
+ const norm = this.getNormalizedEventCoordinates(event);
916
+ for (let n of currentElement.childNodes) {
917
+ if (n.nodeType == NodeType.TextNode) {
918
+ let nc = this.getNormalizedElementCoordinates(n);
919
+ if (nc.x <= norm.x && nc.x + nc.width >= norm.x && nc.y <= norm.y && nc.y + nc.height >= norm.y) {
920
+ currentElement = n;
921
+ break;
922
+ }
923
+ }
924
+ }
925
+ }
913
926
  }
914
927
  if (this._activeTool) {
915
928
  this._activeTool.pointerEventHandler(this, event, currentElement);
package/dist/index.d.ts CHANGED
@@ -7,6 +7,7 @@ export * from "./elements/helper/ElementHelper.js";
7
7
  export * from "./elements/helper/IndentedTextWriter.js";
8
8
  export * from "./elements/helper/PathDataPolyfill.js";
9
9
  export * from "./elements/helper/Screenshot.js";
10
+ export * from "./elements/helper/ClipboardHelper.js";
10
11
  export * from "./elements/loader/OldCustomElementsManifestLoader.js";
11
12
  export * from "./elements/helper/w3color.js";
12
13
  export * from "./elements/helper/contextMenu/ContextMenu.js";
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@ export * from "./elements/helper/ElementHelper.js";
7
7
  export * from "./elements/helper/IndentedTextWriter.js";
8
8
  export * from "./elements/helper/PathDataPolyfill.js";
9
9
  export * from "./elements/helper/Screenshot.js";
10
+ export * from "./elements/helper/ClipboardHelper.js";
10
11
  export * from "./elements/loader/OldCustomElementsManifestLoader.js";
11
12
  export * from "./elements/helper/w3color.js";
12
13
  export * from "./elements/helper/contextMenu/ContextMenu.js";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "description": "A UI designer for Polymer apps",
3
3
  "name": "@node-projects/web-component-designer",
4
- "version": "0.0.185",
4
+ "version": "0.0.187",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "author": "",
@@ -14,7 +14,6 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "@node-projects/base-custom-webcomponent": "^0.10.9",
17
- "@types/node": "^18.11.19",
18
17
  "construct-style-sheets-polyfill": "^3.1.0"
19
18
  },
20
19
  "devDependencies": {
@@ -23,19 +22,20 @@
23
22
  "@node-projects/node-html-parser-esm": "^2.5.1",
24
23
  "@papyrs/stylo": "^0.0.42",
25
24
  "@types/codemirror": "^5.60.7",
26
- "@types/css-tree": "^2.0.1",
25
+ "@types/css-tree": "^2.3.0",
27
26
  "@types/jquery": "^3.5.16",
28
27
  "@types/jquery.fancytree": "0.0.7",
28
+ "@types/node": "^18.13.0",
29
29
  "ace-builds": "^1.15.0",
30
30
  "codemirror": "^6.0.1",
31
31
  "css-tree": "^2.3.1",
32
32
  "esprima-next": "^5.8.4",
33
33
  "html2canvas": "*",
34
- "jest": "^29.4.1",
34
+ "jest": "^29.4.2",
35
35
  "jquery": "^3.6.3",
36
36
  "jquery.fancytree": "^2.38.3",
37
37
  "mdn-data": "^2.0.31",
38
- "monaco-editor": "^0.34.1",
38
+ "monaco-editor": "^0.35.0",
39
39
  "ts-jest": "^29.0.5",
40
40
  "typescript": "^4.9.5",
41
41
  "typescript-lit-html-plugin": "^0.9.0"