@treelocator/runtime 0.1.7 → 0.1.8

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.
@@ -1,30 +1,30 @@
1
1
 
2
- > @treelocator/runtime@0.1.7 build /Users/wende/projects/locatorjs/packages/runtime
2
+ > @treelocator/runtime@0.1.8 build /Users/wende/projects/locatorjs/packages/runtime
3
3
  > concurrently pnpm:build:*
4
4
 
5
+ [tailwind]
6
+ [tailwind] > @treelocator/runtime@0.1.8 build:tailwind /Users/wende/projects/locatorjs/packages/runtime
7
+ [tailwind] > tailwindcss -i ./src/main.css -o ./dist/output.css
8
+ [tailwind]
5
9
  [babel]
6
- [babel] > @treelocator/runtime@0.1.7 build:babel /Users/wende/projects/locatorjs/packages/runtime
10
+ [babel] > @treelocator/runtime@0.1.8 build:babel /Users/wende/projects/locatorjs/packages/runtime
7
11
  [babel] > babel src --out-dir dist --extensions .js,.jsx,.ts,.tsx
8
12
  [babel]
9
13
  [ts]
10
- [ts] > @treelocator/runtime@0.1.7 build:ts /Users/wende/projects/locatorjs/packages/runtime
14
+ [ts] > @treelocator/runtime@0.1.8 build:ts /Users/wende/projects/locatorjs/packages/runtime
11
15
  [ts] > tsc --declaration --emitDeclarationOnly --noEmit false --outDir dist
12
16
  [ts]
13
17
  [wrapImage]
14
- [wrapImage] > @treelocator/runtime@0.1.7 build:wrapImage /Users/wende/projects/locatorjs/packages/runtime
18
+ [wrapImage] > @treelocator/runtime@0.1.8 build:wrapImage /Users/wende/projects/locatorjs/packages/runtime
15
19
  [wrapImage] > node ./scripts/wrapImage.js
16
20
  [wrapImage]
17
- [tailwind]
18
- [tailwind] > @treelocator/runtime@0.1.7 build:tailwind /Users/wende/projects/locatorjs/packages/runtime
19
- [tailwind] > tailwindcss -i ./src/main.css -o ./dist/output.css
20
- [tailwind]
21
21
  [wrapImage] Tree icon file generated
22
22
  [wrapImage] pnpm run build:wrapImage exited with code 0
23
23
  [tailwind]
24
24
  [tailwind] Rebuilding...
25
25
  [tailwind]
26
- [tailwind] Done in 180ms.
26
+ [tailwind] Done in 164ms.
27
27
  [tailwind] pnpm run build:tailwind exited with code 0
28
- [babel] Successfully compiled 72 files with Babel (691ms).
28
+ [babel] Successfully compiled 72 files with Babel (409ms).
29
29
  [babel] pnpm run build:babel exited with code 0
30
30
  [ts] pnpm run build:ts exited with code 0
@@ -8,7 +8,7 @@ export type ElementInfo = {
8
8
  };
9
9
  export type FullElementInfo = {
10
10
  thisElement: ElementInfo;
11
- htmlElement: HTMLElement;
11
+ htmlElement: HTMLElement | SVGElement;
12
12
  parentElements: ElementInfo[];
13
13
  componentBox: SimpleDOMRect;
14
14
  componentsLabels: LabelData[];
@@ -1,2 +1,2 @@
1
1
  import type { ExpressionInfo, FileStorage } from "@locator/shared";
2
- export declare function getExpressionData(target: HTMLElement, fileData: FileStorage | null): ExpressionInfo | null;
2
+ export declare function getExpressionData(target: Element, fileData: FileStorage | null): ExpressionInfo | null;
@@ -1,8 +1,12 @@
1
1
  import { parseDataId, parseDataPath } from "../../functions/parseDataId";
2
2
  export function getExpressionData(target, fileData) {
3
+ // Use getAttribute instead of dataset to support both HTML and SVG elements
4
+ const dataLocatorjs = target.getAttribute("data-locatorjs");
5
+ const dataLocatorjsId = target.getAttribute("data-locatorjs-id");
6
+
3
7
  // First check for data-locatorjs (path-based, for server components)
4
- if (target.dataset.locatorjs) {
5
- const parsed = parseDataPath(target.dataset.locatorjs);
8
+ if (dataLocatorjs) {
9
+ const parsed = parseDataPath(dataLocatorjs);
6
10
  if (parsed) {
7
11
  const [, line, column] = parsed;
8
12
 
@@ -33,8 +37,8 @@ export function getExpressionData(target, fileData) {
33
37
  }
34
38
 
35
39
  // Fall back to data-locatorjs-id (ID-based, traditional approach)
36
- if (target.dataset.locatorjsId && fileData) {
37
- const [, id] = parseDataId(target.dataset.locatorjsId);
40
+ if (dataLocatorjsId && fileData) {
41
+ const [, id] = parseDataId(dataLocatorjsId);
38
42
  const expData = fileData.expressions[Number(id)];
39
43
  if (expData) {
40
44
  return expData;
@@ -1,5 +1,5 @@
1
1
  import type { FileStorage } from "@locator/shared";
2
2
  import type { SimpleDOMRect } from "../../types/types";
3
- export declare function getJSXComponentBoundingBox(found: HTMLElement, locatorData: {
3
+ export declare function getJSXComponentBoundingBox(found: Element, locatorData: {
4
4
  [filename: string]: FileStorage;
5
5
  }, componentFolder: string, componentId: number): SimpleDOMRect;
@@ -9,19 +9,24 @@ export function getJSXComponentBoundingBox(found, locatorData, componentFolder,
9
9
  if (!parent) {
10
10
  return;
11
11
  }
12
- if (parent instanceof HTMLElement) {
12
+ // Support both HTMLElement and SVGElement
13
+ if (parent instanceof HTMLElement || parent instanceof SVGElement) {
14
+ // Use getAttribute instead of dataset to support both HTML and SVG elements
15
+ const dataLocatorjs = parent.getAttribute("data-locatorjs");
16
+ const dataLocatorjsId = parent.getAttribute("data-locatorjs-id");
17
+
13
18
  // Check for either data-locatorjs (path-based) or data-locatorjs-id (ID-based)
14
- if (parent.dataset.locatorjs || parent.dataset.locatorjsId) {
19
+ if (dataLocatorjs || dataLocatorjsId) {
15
20
  let fileFullPath;
16
- if (parent.dataset.locatorjs) {
17
- const parsed = parseDataPath(parent.dataset.locatorjs);
21
+ if (dataLocatorjs) {
22
+ const parsed = parseDataPath(dataLocatorjs);
18
23
  if (!parsed) {
19
24
  goParent(parent);
20
25
  return;
21
26
  }
22
27
  [fileFullPath] = parsed;
23
- } else if (parent.dataset.locatorjsId) {
24
- [fileFullPath] = parseDataId(parent.dataset.locatorjsId);
28
+ } else if (dataLocatorjsId) {
29
+ [fileFullPath] = parseDataId(dataLocatorjsId);
25
30
  } else {
26
31
  goParent(parent);
27
32
  return;
@@ -5,10 +5,13 @@ import { getExpressionData } from "./getExpressionData";
5
5
  import { getJSXComponentBoundingBox } from "./getJSXComponentBoundingBox";
6
6
  export function getElementInfo(target) {
7
7
  const found = target.closest("[data-locatorjs-id], [data-locatorjs]");
8
- if (found && found instanceof HTMLElement && found.dataset && (found.dataset.locatorjsId || found.dataset.locatorjs || found.dataset.locatorjsStyled)) {
9
- const dataId = found.dataset.locatorjsId;
10
- const dataPath = found.dataset.locatorjs;
11
- const styledDataId = found.dataset.locatorjsStyled;
8
+
9
+ // Support both HTMLElement and SVGElement
10
+ // SVG elements don't have dataset, so use getAttribute instead
11
+ const dataId = found?.getAttribute("data-locatorjs-id");
12
+ const dataPath = found?.getAttribute("data-locatorjs");
13
+ const styledDataId = found?.getAttribute("data-locatorjs-styled");
14
+ if (found && (found instanceof HTMLElement || found instanceof SVGElement) && (dataId || dataPath || styledDataId)) {
12
15
  if (!dataId && !dataPath) {
13
16
  return null;
14
17
  }
@@ -89,8 +92,9 @@ export function getElementInfo(target) {
89
92
  }
90
93
  export class JSXTreeNodeElement extends HtmlElementTreeNode {
91
94
  getSource() {
92
- const dataId = this.element.dataset.locatorjsId;
93
- const dataPath = this.element.dataset.locatorjs;
95
+ // Use getAttribute instead of dataset to support both HTML and SVG elements
96
+ const dataId = this.element.getAttribute("data-locatorjs-id");
97
+ const dataPath = this.element.getAttribute("data-locatorjs");
94
98
  if (!dataId && !dataPath) {
95
99
  return null;
96
100
  }
@@ -131,8 +135,9 @@ export class JSXTreeNodeElement extends HtmlElementTreeNode {
131
135
  return null;
132
136
  }
133
137
  getComponent() {
134
- const dataId = this.element.dataset.locatorjsId;
135
- const dataPath = this.element.dataset.locatorjs;
138
+ // Use getAttribute instead of dataset to support both HTML and SVG elements
139
+ const dataId = this.element.getAttribute("data-locatorjs-id");
140
+ const dataPath = this.element.getAttribute("data-locatorjs");
136
141
  if (!dataId && !dataPath) {
137
142
  return null;
138
143
  }
@@ -64,7 +64,7 @@ function Runtime(props) {
64
64
  if (!element) {
65
65
  const target = e.target;
66
66
  if (target && (target instanceof HTMLElement || target instanceof SVGElement)) {
67
- element = target instanceof SVGElement ? target.closest('svg') ?? target : target;
67
+ element = target instanceof SVGElement ? target.closest('[data-locatorjs-id], [data-locatorjs]') ?? target.closest('svg') ?? target : target;
68
68
  }
69
69
  }
70
70
  if (element && !isLocatorsOwnElement(element)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treelocator/runtime",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "TreeLocatorJS runtime for component ancestry tracking. Alt+click any element to copy its component tree to clipboard. Exposes window.__treelocator__ API for browser automation (Playwright, Puppeteer, Selenium, Cypress).",
5
5
  "keywords": [
6
6
  "locator",
@@ -72,5 +72,5 @@
72
72
  "directory": "packages/runtime"
73
73
  },
74
74
  "license": "MIT",
75
- "gitHead": "233b05abf1f13da9e1d49b73db62bb8561636618"
75
+ "gitHead": "69fb05167bd689b2e3602fcbc74a70912695f136"
76
76
  }
@@ -10,7 +10,7 @@ export type ElementInfo = {
10
10
 
11
11
  export type FullElementInfo = {
12
12
  thisElement: ElementInfo;
13
- htmlElement: HTMLElement;
13
+ htmlElement: HTMLElement | SVGElement;
14
14
  parentElements: ElementInfo[];
15
15
  componentBox: SimpleDOMRect;
16
16
  componentsLabels: LabelData[];
@@ -2,12 +2,16 @@ import type { ExpressionInfo, FileStorage } from "@locator/shared";
2
2
  import { parseDataId, parseDataPath } from "../../functions/parseDataId";
3
3
 
4
4
  export function getExpressionData(
5
- target: HTMLElement,
5
+ target: Element,
6
6
  fileData: FileStorage | null
7
7
  ): ExpressionInfo | null {
8
+ // Use getAttribute instead of dataset to support both HTML and SVG elements
9
+ const dataLocatorjs = target.getAttribute("data-locatorjs");
10
+ const dataLocatorjsId = target.getAttribute("data-locatorjs-id");
11
+
8
12
  // First check for data-locatorjs (path-based, for server components)
9
- if (target.dataset.locatorjs) {
10
- const parsed = parseDataPath(target.dataset.locatorjs);
13
+ if (dataLocatorjs) {
14
+ const parsed = parseDataPath(dataLocatorjs);
11
15
  if (parsed) {
12
16
  const [, line, column] = parsed;
13
17
 
@@ -35,8 +39,8 @@ export function getExpressionData(
35
39
  }
36
40
 
37
41
  // Fall back to data-locatorjs-id (ID-based, traditional approach)
38
- if (target.dataset.locatorjsId && fileData) {
39
- const [, id] = parseDataId(target.dataset.locatorjsId);
42
+ if (dataLocatorjsId && fileData) {
43
+ const [, id] = parseDataId(dataLocatorjsId);
40
44
  const expData = fileData.expressions[Number(id)];
41
45
  if (expData) {
42
46
  return expData;
@@ -5,32 +5,37 @@ import type { SimpleDOMRect } from "../../types/types";
5
5
  import { getExpressionData } from "./getExpressionData";
6
6
 
7
7
  export function getJSXComponentBoundingBox(
8
- found: HTMLElement,
8
+ found: Element,
9
9
  locatorData: { [filename: string]: FileStorage },
10
10
  componentFolder: string,
11
11
  componentId: number
12
12
  ): SimpleDOMRect {
13
13
  let composedBox: SimpleDOMRect = found.getBoundingClientRect();
14
14
  // Currently it works well only for components with one root element, but for components with multiple root elements we would need to track instance ids.
15
- function goParent(current: HTMLElement) {
15
+ function goParent(current: Element) {
16
16
  const parent = current.parentNode;
17
17
  if (!parent) {
18
18
  return;
19
19
  }
20
- if (parent instanceof HTMLElement) {
20
+ // Support both HTMLElement and SVGElement
21
+ if (parent instanceof HTMLElement || parent instanceof SVGElement) {
22
+ // Use getAttribute instead of dataset to support both HTML and SVG elements
23
+ const dataLocatorjs = parent.getAttribute("data-locatorjs");
24
+ const dataLocatorjsId = parent.getAttribute("data-locatorjs-id");
25
+
21
26
  // Check for either data-locatorjs (path-based) or data-locatorjs-id (ID-based)
22
- if (parent.dataset.locatorjs || parent.dataset.locatorjsId) {
27
+ if (dataLocatorjs || dataLocatorjsId) {
23
28
  let fileFullPath: string;
24
29
 
25
- if (parent.dataset.locatorjs) {
26
- const parsed = parseDataPath(parent.dataset.locatorjs);
30
+ if (dataLocatorjs) {
31
+ const parsed = parseDataPath(dataLocatorjs);
27
32
  if (!parsed) {
28
33
  goParent(parent);
29
34
  return;
30
35
  }
31
36
  [fileFullPath] = parsed;
32
- } else if (parent.dataset.locatorjsId) {
33
- [fileFullPath] = parseDataId(parent.dataset.locatorjsId);
37
+ } else if (dataLocatorjsId) {
38
+ [fileFullPath] = parseDataId(dataLocatorjsId);
34
39
  } else {
35
40
  goParent(parent);
36
41
  return;
@@ -20,17 +20,17 @@ import { getJSXComponentBoundingBox } from "./getJSXComponentBoundingBox";
20
20
  export function getElementInfo(target: HTMLElement): FullElementInfo | null {
21
21
  const found = target.closest("[data-locatorjs-id], [data-locatorjs]");
22
22
 
23
+ // Support both HTMLElement and SVGElement
24
+ // SVG elements don't have dataset, so use getAttribute instead
25
+ const dataId = found?.getAttribute("data-locatorjs-id");
26
+ const dataPath = found?.getAttribute("data-locatorjs");
27
+ const styledDataId = found?.getAttribute("data-locatorjs-styled");
28
+
23
29
  if (
24
30
  found &&
25
- found instanceof HTMLElement &&
26
- found.dataset &&
27
- (found.dataset.locatorjsId ||
28
- found.dataset.locatorjs ||
29
- found.dataset.locatorjsStyled)
31
+ (found instanceof HTMLElement || found instanceof SVGElement) &&
32
+ (dataId || dataPath || styledDataId)
30
33
  ) {
31
- const dataId = found.dataset.locatorjsId;
32
- const dataPath = found.dataset.locatorjs;
33
- const styledDataId = found.dataset.locatorjsStyled;
34
34
 
35
35
  if (!dataId && !dataPath) {
36
36
  return null;
@@ -135,8 +135,9 @@ export function getElementInfo(target: HTMLElement): FullElementInfo | null {
135
135
 
136
136
  export class JSXTreeNodeElement extends HtmlElementTreeNode {
137
137
  getSource(): Source | null {
138
- const dataId = this.element.dataset.locatorjsId;
139
- const dataPath = this.element.dataset.locatorjs;
138
+ // Use getAttribute instead of dataset to support both HTML and SVG elements
139
+ const dataId = this.element.getAttribute("data-locatorjs-id");
140
+ const dataPath = this.element.getAttribute("data-locatorjs");
140
141
 
141
142
  if (!dataId && !dataPath) {
142
143
  return null;
@@ -184,8 +185,9 @@ export class JSXTreeNodeElement extends HtmlElementTreeNode {
184
185
  return null;
185
186
  }
186
187
  getComponent(): TreeNodeComponent | null {
187
- const dataId = this.element.dataset.locatorjsId;
188
- const dataPath = this.element.dataset.locatorjs;
188
+ // Use getAttribute instead of dataset to support both HTML and SVG elements
189
+ const dataId = this.element.getAttribute("data-locatorjs-id");
190
+ const dataPath = this.element.getAttribute("data-locatorjs");
189
191
 
190
192
  if (!dataId && !dataPath) {
191
193
  return null;
@@ -74,7 +74,9 @@ function Runtime(props: RuntimeProps) {
74
74
  const target = e.target;
75
75
  if (target && (target instanceof HTMLElement || target instanceof SVGElement)) {
76
76
  element = target instanceof SVGElement
77
- ? (target.closest('svg') as HTMLElement | null) ?? (target as unknown as HTMLElement)
77
+ ? (target.closest('[data-locatorjs-id], [data-locatorjs]') as HTMLElement | null) ??
78
+ (target.closest('svg') as HTMLElement | null) ??
79
+ (target as unknown as HTMLElement)
78
80
  : target;
79
81
  }
80
82
  }