webmarker-js 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Reid Barber
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -11,11 +11,10 @@ Mark web pages for use with vision-language models.
11
11
 
12
12
  ## Overview
13
13
 
14
- **WebMarker** adds visual markings with labels to elements on a web page. This can be used for [Set-of-Mark (SoM)](https://github.com/microsoft/SoM) prompting, which improves visual grounding abilities of vision-language models such as GPT-4o, Claude 3.5, and Google Gemini 1.5.
14
+ **WebMarker** adds visual markings with labels to elements on a web page. This can be used for [Set-of-Mark](https://github.com/microsoft/SoM) prompting, which improves visual grounding abilities of vision-language models such as GPT-4o, Claude 3.5, and Google Gemini 1.5.
15
15
 
16
16
  ![Screenshot of marked Google homepage](https://github.com/user-attachments/assets/722e1034-06d4-4ccd-a7d6-f03749435681)
17
17
 
18
-
19
18
  ## How it works
20
19
 
21
20
  **1. Call the `mark()` function**
@@ -24,7 +23,7 @@ This marks the interactive elements on the page, and returns an object containin
24
23
 
25
24
  - `element`: The interactive element that was marked.
26
25
  - `markElement`: The label element that was added to the page.
27
- - `maskElement`: The bounding box element that was added to the page.
26
+ - `boundingBoxElement`: The bounding box element that was added to the page.
28
27
 
29
28
  You can use this information to build your prompt for the vision-language model.
30
29
 
@@ -58,7 +57,7 @@ Example response: click 0
58
57
 
59
58
  In a web browser (i.e. via Playwright), interact with elements as needed.
60
59
 
61
- For prompting or agent ideas, see the [WebVoyager](https://arxiv.org/abs/2401.13919) paper.
60
+ For prompting or agent ideas, see the [WebVoyager](https://github.com/MinorJerry/WebVoyager) paper.
62
61
 
63
62
  ## Playwright example
64
63
 
@@ -71,6 +70,9 @@ await page.addScriptTag({
71
70
  // Mark the page and get the marked elements
72
71
  let markedElements = await page.evaluate(async () => await WebMarker.mark());
73
72
 
73
+ // Click a marked element
74
+ await page.locator('[data-mark-label="0"]').click();
75
+
74
76
  // (Optional) Check if page is marked
75
77
  let isMarked = await page.evaluate(async () => await WebMarker.isMarked());
76
78
 
@@ -87,19 +89,19 @@ A custom CSS selector to specify which elements to mark.
87
89
  - Type: `string`
88
90
  - Default: `"button, input, a, select, textarea"`
89
91
 
90
- ### markAttribute
92
+ ### getLabel
91
93
 
92
- A custom attribute to add to the marked elements. This attribute contains the label of the mark.
94
+ Provide a function for generating labels. By default, labels are generated as integers starting from 0.
93
95
 
94
- - Type: `string`
95
- - Default: `"data-mark-id"`
96
+ - Type: `(element: Element, index: number) => string`
97
+ - Default: `(_, index) => index.toString()`
96
98
 
97
- ### markStyle
99
+ ### markAttribute
98
100
 
99
- A CSS style to apply to the label element. You can also specify a function that returns a CSS style object.
101
+ A custom attribute to add to the marked elements. This attribute contains the label of the mark.
100
102
 
101
- - Type: `Readonly<Partial<CSSStyleDeclaration>> or (element: Element) => Readonly<Partial<CSSStyleDeclaration>>`
102
- - Default: `{backgroundColor: "red", color: "white", padding: "2px 4px", fontSize: "12px", fontWeight: "bold"}`
103
+ - Type: `string`
104
+ - Default: `"data-mark-label"`
103
105
 
104
106
  ### markPlacement
105
107
 
@@ -108,27 +110,27 @@ The placement of the mark relative to the element.
108
110
  - Type: `'top' | 'top-start' | 'top-end' | 'right' | 'right-start' | 'right-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end'`
109
111
  - Default: `'top-start'`
110
112
 
111
- ### maskStyle
113
+ ### markStyle
114
+
115
+ A CSS style to apply to the label element. You can also specify a function that returns a CSS style object.
116
+
117
+ - Type: `Partial<CSSStyleDeclaration> | (element: Element) => Partial<CSSStyleDeclaration>`
118
+ - Default: `{backgroundColor: "red", color: "white", padding: "2px 4px", fontSize: "12px", fontWeight: "bold"}`
119
+
120
+ ### boundingBoxStyle
112
121
 
113
- A CSS style to apply to the bounding box element. You can also specify a function that returns a CSS style object. Bounding boxes are only shown if showMasks is true.
122
+ A CSS style to apply to the bounding box element. You can also specify a function that returns a CSS style object. Bounding boxes are only shown if showBoundingBoxes is true.
114
123
 
115
- - Type: `Readonly<Partial<CSSStyleDeclaration>> or (element: Element) => Readonly<Partial<CSSStyleDeclaration>>`
124
+ - Type: `Partial<CSSStyleDeclaration> | (element: Element) => Partial<CSSStyleDeclaration>`
116
125
  - Default: `{outline: "2px dashed red", backgroundColor: "transparent"}`
117
126
 
118
- ### showMasks
127
+ ### showBoundingBoxes
119
128
 
120
129
  Whether or not to show bounding boxes around the elements.
121
130
 
122
131
  - Type: `boolean`
123
132
  - Default: `true`
124
133
 
125
- ### labelGenerator
126
-
127
- Provide a function for generating labels. By default, labels are generated as integers starting from 0.
128
-
129
- - Type: `(element: Element, index: number) => string`
130
- - Default: `(_, index) => index.toString()`
131
-
132
134
  ### containerElement
133
135
 
134
136
  Provide a container element to query the elements to be marked. By default, the container element is document.body.
@@ -153,15 +155,15 @@ const markedElements = await mark({
153
155
  markAttribute: "data-test-id",
154
156
  // Use a blue mark with white text
155
157
  markStyle: { color: "white", backgroundColor: "blue", padding: 5 },
156
- // Use a blue dashed outline mask with a transparent and slighly blue background
157
- maskStyle: { outline: "2px dashed blue", backgroundColor: "rgba(0, 0, 255, 0.1)"},
158
+ // Use a blue dashed outline with a transparent and slighly blue background
159
+ boundingBoxStyle: { outline: "2px dashed blue", backgroundColor: "rgba(0, 0, 255, 0.1)"},
158
160
  // Place the mark at the top right corner of the element
159
161
  markPlacement: "top-end";
160
- // Show masks over elements (defaults to true)
161
- showMasks: true,
162
+ // Show bounding boxes over elements (defaults to true)
163
+ showBoundingBoxes: true,
162
164
  // Generate labels as 'Element 0', 'Element 1', 'Element 2'...
163
165
  // Defaults to '0', '1', '2'... if not provided.
164
- labelGenerator: (element, index) => `Element ${index}`,
166
+ getLabel: (element, index) => `Element ${index}`,
165
167
  // A custom container element to query the elements to be marked.
166
168
  // Defaults to the document.body.
167
169
  containerElement: document.body.querySelector("main"),
package/dist/index.d.ts CHANGED
@@ -1,43 +1,45 @@
1
1
  type Placement = "top" | "top-start" | "top-end" | "right" | "right-start" | "right-end" | "bottom" | "bottom-start" | "bottom-end" | "left" | "left-start" | "left-end";
2
+ type StyleFunction = (element: Element) => Partial<CSSStyleDeclaration>;
3
+ type StyleObject = Partial<CSSStyleDeclaration>;
2
4
  interface MarkOptions {
3
5
  /**
4
- * A CSS selector to specify the elements to be marked.
6
+ * A CSS selector to query the elements to be marked.
5
7
  */
6
8
  selector?: string;
7
9
  /**
8
- * Name for the attribute added to the marked elements. This attribute is used to store the label.
9
- *
10
- * @default 'data-mark-id'
10
+ * Provide a function for generating labels.
11
+ * By default, labels are generated as numbers starting from 0.
11
12
  */
12
- markAttribute?: string;
13
+ getLabel?: (element: Element, index: number) => string;
13
14
  /**
14
- * A CSS style to apply to the label element.
15
- * You can also specify a function that returns a CSS style object.
15
+ * Name for the attribute added to the marked elements to store the mark label.
16
+ *
17
+ * @default 'data-mark-label'
16
18
  */
17
- markStyle?: Readonly<Partial<CSSStyleDeclaration>> | ((element: Element) => Readonly<Partial<CSSStyleDeclaration>>);
19
+ markAttribute?: string;
18
20
  /**
19
21
  * The placement of the mark relative to the element.
20
22
  *
21
23
  * @default 'top-start'
22
24
  */
23
25
  markPlacement?: Placement;
26
+ /**
27
+ * A CSS style to apply to the label element.
28
+ * You can also specify a function that returns a CSS style object.
29
+ */
30
+ markStyle?: StyleObject | StyleFunction;
24
31
  /**
25
32
  * A CSS style to apply to the bounding box element.
26
33
  * You can also specify a function that returns a CSS style object.
27
- * Bounding boxes are only shown if `showMasks` is `true`.
34
+ * Bounding boxes are only shown if `showBoundingBoxes` is `true`.
28
35
  */
29
- maskStyle?: Readonly<Partial<CSSStyleDeclaration>> | ((element: Element) => Readonly<Partial<CSSStyleDeclaration>>);
36
+ boundingBoxStyle?: StyleObject | StyleFunction;
30
37
  /**
31
38
  * Whether or not to show bounding boxes around the elements.
32
39
  *
33
40
  * @default true
34
41
  */
35
- showMasks?: boolean;
36
- /**
37
- * Provide a function for generating labels.
38
- * By default, labels are generated as numbers starting from 0.
39
- */
40
- labelGenerator?: (element: Element, index: number) => string;
42
+ showBoundingBoxes?: boolean;
41
43
  /**
42
44
  * Provide a container element to query the elements to be marked.
43
45
  * By default, the container element is `document.body`.
@@ -53,7 +55,7 @@ interface MarkOptions {
53
55
  interface MarkedElement {
54
56
  element: Element;
55
57
  markElement: HTMLElement;
56
- maskElement?: HTMLElement;
58
+ boundingBoxElement?: HTMLElement;
57
59
  }
58
60
  declare function mark(options?: MarkOptions): Promise<Record<string, MarkedElement>>;
59
61
  declare function unmark(): void;
package/dist/main.js CHANGED
@@ -932,7 +932,9 @@ var WebMarker = (() => {
932
932
  return __async(this, arguments, function* (options = {}) {
933
933
  const {
934
934
  selector = "button, input, a, select, textarea",
935
- markAttribute = "data-mark-id",
935
+ getLabel = (_, index) => index.toString(),
936
+ markAttribute = "data-mark-label",
937
+ markPlacement = "top-start",
936
938
  markStyle = {
937
939
  backgroundColor: "red",
938
940
  color: "white",
@@ -940,13 +942,11 @@ var WebMarker = (() => {
940
942
  fontSize: "12px",
941
943
  fontWeight: "bold"
942
944
  },
943
- markPlacement = "top-start",
944
- maskStyle = {
945
+ boundingBoxStyle = {
945
946
  outline: "2px dashed red",
946
947
  backgroundColor: "transparent"
947
948
  },
948
- showMasks = true,
949
- labelGenerator = (_, index) => index.toString(),
949
+ showBoundingBoxes = true,
950
950
  containerElement = document.body,
951
951
  viewPortOnly = false
952
952
  } = options;
@@ -958,14 +958,14 @@ var WebMarker = (() => {
958
958
  const markedElements = {};
959
959
  yield Promise.all(
960
960
  elements.map((element, index) => __async(this, null, function* () {
961
- const label = labelGenerator(element, index);
961
+ const label = getLabel(element, index);
962
962
  const markElement = createMark(element, markStyle, label, markPlacement);
963
- const maskElement = showMasks ? createMask(element, maskStyle, label) : void 0;
964
- markedElements[label] = { element, markElement, maskElement };
963
+ const boundingBoxElement = showBoundingBoxes ? createBoundingBox(element, boundingBoxStyle, label) : void 0;
964
+ markedElements[label] = { element, markElement, boundingBoxElement };
965
965
  element.setAttribute(markAttribute, label);
966
966
  }))
967
967
  );
968
- document.documentElement.dataset.webmarkered = "true";
968
+ document.documentElement.setAttribute("data-marked", "true");
969
969
  return markedElements;
970
970
  });
971
971
  }
@@ -987,14 +987,14 @@ var WebMarker = (() => {
987
987
  );
988
988
  return markElement;
989
989
  }
990
- function createMask(element, style, label) {
991
- const maskElement = document.createElement("div");
992
- maskElement.className = "webmarker-mask";
993
- maskElement.id = `webmarker-mask-${label}`;
994
- document.body.appendChild(maskElement);
995
- positionMask(maskElement, element);
990
+ function createBoundingBox(element, style, label) {
991
+ const boundingBoxElement = document.createElement("div");
992
+ boundingBoxElement.className = "webmarker-bounding-box";
993
+ boundingBoxElement.id = `webmarker-bounding-box-${label}`;
994
+ document.body.appendChild(boundingBoxElement);
995
+ positionBoundingBox(boundingBoxElement, element);
996
996
  applyStyle(
997
- maskElement,
997
+ boundingBoxElement,
998
998
  {
999
999
  zIndex: "999999999",
1000
1000
  position: "absolute",
@@ -1002,7 +1002,7 @@ var WebMarker = (() => {
1002
1002
  },
1003
1003
  typeof style === "function" ? style(element) : style
1004
1004
  );
1005
- return maskElement;
1005
+ return boundingBoxElement;
1006
1006
  }
1007
1007
  function positionMark(markElement, element, markPlacement) {
1008
1008
  function updatePosition() {
@@ -1018,36 +1018,36 @@ var WebMarker = (() => {
1018
1018
  }
1019
1019
  cleanupFns.push(autoUpdate(element, markElement, updatePosition));
1020
1020
  }
1021
- function positionMask(mask, element) {
1021
+ function positionBoundingBox(boundingBox, element) {
1022
1022
  return __async(this, null, function* () {
1023
1023
  const { width, height } = element.getBoundingClientRect();
1024
1024
  function updatePosition() {
1025
1025
  return __async(this, null, function* () {
1026
- const { x: maskX, y: maskY } = yield computePosition2(element, mask, {
1026
+ const { x, y } = yield computePosition2(element, boundingBox, {
1027
1027
  placement: "top-start"
1028
1028
  });
1029
- Object.assign(mask.style, {
1030
- left: `${maskX}px`,
1031
- top: `${maskY + height}px`,
1029
+ Object.assign(boundingBox.style, {
1030
+ left: `${x}px`,
1031
+ top: `${y + height}px`,
1032
1032
  width: `${width}px`,
1033
1033
  height: `${height}px`
1034
1034
  });
1035
1035
  });
1036
1036
  }
1037
- cleanupFns.push(autoUpdate(element, mask, updatePosition));
1037
+ cleanupFns.push(autoUpdate(element, boundingBox, updatePosition));
1038
1038
  });
1039
1039
  }
1040
1040
  function applyStyle(element, defaultStyle, customStyle) {
1041
1041
  Object.assign(element.style, defaultStyle, customStyle);
1042
1042
  }
1043
1043
  function unmark() {
1044
- document.querySelectorAll(".webmarker, .webmarker-mask").forEach((el) => el.remove());
1045
- document.documentElement.removeAttribute("data-webmarkered");
1044
+ document.querySelectorAll(".webmarker, .webmarker-bounding-box").forEach((el) => el.remove());
1045
+ document.documentElement.removeAttribute("data-marked");
1046
1046
  cleanupFns.forEach((fn) => fn());
1047
1047
  cleanupFns = [];
1048
1048
  }
1049
1049
  function isMarked() {
1050
- return document.documentElement.hasAttribute("data-webmarkered");
1050
+ return document.documentElement.hasAttribute("data-marked");
1051
1051
  }
1052
1052
  if (typeof window !== "undefined") {
1053
1053
  window["mark"] = mark;
package/dist/module.js CHANGED
@@ -908,7 +908,9 @@ function mark() {
908
908
  return __async(this, arguments, function* (options = {}) {
909
909
  const {
910
910
  selector = "button, input, a, select, textarea",
911
- markAttribute = "data-mark-id",
911
+ getLabel = (_, index) => index.toString(),
912
+ markAttribute = "data-mark-label",
913
+ markPlacement = "top-start",
912
914
  markStyle = {
913
915
  backgroundColor: "red",
914
916
  color: "white",
@@ -916,13 +918,11 @@ function mark() {
916
918
  fontSize: "12px",
917
919
  fontWeight: "bold"
918
920
  },
919
- markPlacement = "top-start",
920
- maskStyle = {
921
+ boundingBoxStyle = {
921
922
  outline: "2px dashed red",
922
923
  backgroundColor: "transparent"
923
924
  },
924
- showMasks = true,
925
- labelGenerator = (_, index) => index.toString(),
925
+ showBoundingBoxes = true,
926
926
  containerElement = document.body,
927
927
  viewPortOnly = false
928
928
  } = options;
@@ -934,14 +934,14 @@ function mark() {
934
934
  const markedElements = {};
935
935
  yield Promise.all(
936
936
  elements.map((element, index) => __async(this, null, function* () {
937
- const label = labelGenerator(element, index);
937
+ const label = getLabel(element, index);
938
938
  const markElement = createMark(element, markStyle, label, markPlacement);
939
- const maskElement = showMasks ? createMask(element, maskStyle, label) : void 0;
940
- markedElements[label] = { element, markElement, maskElement };
939
+ const boundingBoxElement = showBoundingBoxes ? createBoundingBox(element, boundingBoxStyle, label) : void 0;
940
+ markedElements[label] = { element, markElement, boundingBoxElement };
941
941
  element.setAttribute(markAttribute, label);
942
942
  }))
943
943
  );
944
- document.documentElement.dataset.webmarkered = "true";
944
+ document.documentElement.setAttribute("data-marked", "true");
945
945
  return markedElements;
946
946
  });
947
947
  }
@@ -963,14 +963,14 @@ function createMark(element, style, label, markPlacement = "top-start") {
963
963
  );
964
964
  return markElement;
965
965
  }
966
- function createMask(element, style, label) {
967
- const maskElement = document.createElement("div");
968
- maskElement.className = "webmarker-mask";
969
- maskElement.id = `webmarker-mask-${label}`;
970
- document.body.appendChild(maskElement);
971
- positionMask(maskElement, element);
966
+ function createBoundingBox(element, style, label) {
967
+ const boundingBoxElement = document.createElement("div");
968
+ boundingBoxElement.className = "webmarker-bounding-box";
969
+ boundingBoxElement.id = `webmarker-bounding-box-${label}`;
970
+ document.body.appendChild(boundingBoxElement);
971
+ positionBoundingBox(boundingBoxElement, element);
972
972
  applyStyle(
973
- maskElement,
973
+ boundingBoxElement,
974
974
  {
975
975
  zIndex: "999999999",
976
976
  position: "absolute",
@@ -978,7 +978,7 @@ function createMask(element, style, label) {
978
978
  },
979
979
  typeof style === "function" ? style(element) : style
980
980
  );
981
- return maskElement;
981
+ return boundingBoxElement;
982
982
  }
983
983
  function positionMark(markElement, element, markPlacement) {
984
984
  function updatePosition() {
@@ -994,36 +994,36 @@ function positionMark(markElement, element, markPlacement) {
994
994
  }
995
995
  cleanupFns.push(autoUpdate(element, markElement, updatePosition));
996
996
  }
997
- function positionMask(mask, element) {
997
+ function positionBoundingBox(boundingBox, element) {
998
998
  return __async(this, null, function* () {
999
999
  const { width, height } = element.getBoundingClientRect();
1000
1000
  function updatePosition() {
1001
1001
  return __async(this, null, function* () {
1002
- const { x: maskX, y: maskY } = yield computePosition2(element, mask, {
1002
+ const { x, y } = yield computePosition2(element, boundingBox, {
1003
1003
  placement: "top-start"
1004
1004
  });
1005
- Object.assign(mask.style, {
1006
- left: `${maskX}px`,
1007
- top: `${maskY + height}px`,
1005
+ Object.assign(boundingBox.style, {
1006
+ left: `${x}px`,
1007
+ top: `${y + height}px`,
1008
1008
  width: `${width}px`,
1009
1009
  height: `${height}px`
1010
1010
  });
1011
1011
  });
1012
1012
  }
1013
- cleanupFns.push(autoUpdate(element, mask, updatePosition));
1013
+ cleanupFns.push(autoUpdate(element, boundingBox, updatePosition));
1014
1014
  });
1015
1015
  }
1016
1016
  function applyStyle(element, defaultStyle, customStyle) {
1017
1017
  Object.assign(element.style, defaultStyle, customStyle);
1018
1018
  }
1019
1019
  function unmark() {
1020
- document.querySelectorAll(".webmarker, .webmarker-mask").forEach((el) => el.remove());
1021
- document.documentElement.removeAttribute("data-webmarkered");
1020
+ document.querySelectorAll(".webmarker, .webmarker-bounding-box").forEach((el) => el.remove());
1021
+ document.documentElement.removeAttribute("data-marked");
1022
1022
  cleanupFns.forEach((fn) => fn());
1023
1023
  cleanupFns = [];
1024
1024
  }
1025
1025
  function isMarked() {
1026
- return document.documentElement.hasAttribute("data-webmarkered");
1026
+ return document.documentElement.hasAttribute("data-marked");
1027
1027
  }
1028
1028
  if (typeof window !== "undefined") {
1029
1029
  window["mark"] = mark;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "webmarker-js",
3
- "version": "0.1.0",
4
- "description": "A library for marking web pages for Set-of-Mark (SoM) prompting with vision-language models.",
3
+ "version": "0.3.0",
4
+ "description": "A library for marking web pages for Set-of-Mark prompting with vision-language models.",
5
5
  "source": "src/index.ts",
6
6
  "main": "dist/main.js",
7
7
  "module": "dist/module.js",
package/src/index.ts CHANGED
@@ -14,49 +14,48 @@ type Placement =
14
14
  | "left-start"
15
15
  | "left-end";
16
16
 
17
+ type StyleFunction = (element: Element) => Partial<CSSStyleDeclaration>;
18
+ type StyleObject = Partial<CSSStyleDeclaration>;
19
+
17
20
  interface MarkOptions {
18
21
  /**
19
- * A CSS selector to specify the elements to be marked.
22
+ * A CSS selector to query the elements to be marked.
20
23
  */
21
24
  selector?: string;
22
25
  /**
23
- * Name for the attribute added to the marked elements. This attribute is used to store the label.
24
- *
25
- * @default 'data-mark-id'
26
+ * Provide a function for generating labels.
27
+ * By default, labels are generated as numbers starting from 0.
26
28
  */
27
- markAttribute?: string;
29
+ getLabel?: (element: Element, index: number) => string;
28
30
  /**
29
- * A CSS style to apply to the label element.
30
- * You can also specify a function that returns a CSS style object.
31
+ * Name for the attribute added to the marked elements to store the mark label.
32
+ *
33
+ * @default 'data-mark-label'
31
34
  */
32
- markStyle?:
33
- | Readonly<Partial<CSSStyleDeclaration>>
34
- | ((element: Element) => Readonly<Partial<CSSStyleDeclaration>>);
35
+ markAttribute?: string;
35
36
  /**
36
37
  * The placement of the mark relative to the element.
37
38
  *
38
39
  * @default 'top-start'
39
40
  */
40
41
  markPlacement?: Placement;
42
+ /**
43
+ * A CSS style to apply to the label element.
44
+ * You can also specify a function that returns a CSS style object.
45
+ */
46
+ markStyle?: StyleObject | StyleFunction;
41
47
  /**
42
48
  * A CSS style to apply to the bounding box element.
43
49
  * You can also specify a function that returns a CSS style object.
44
- * Bounding boxes are only shown if `showMasks` is `true`.
50
+ * Bounding boxes are only shown if `showBoundingBoxes` is `true`.
45
51
  */
46
- maskStyle?:
47
- | Readonly<Partial<CSSStyleDeclaration>>
48
- | ((element: Element) => Readonly<Partial<CSSStyleDeclaration>>);
52
+ boundingBoxStyle?: StyleObject | StyleFunction;
49
53
  /**
50
54
  * Whether or not to show bounding boxes around the elements.
51
55
  *
52
56
  * @default true
53
57
  */
54
- showMasks?: boolean;
55
- /**
56
- * Provide a function for generating labels.
57
- * By default, labels are generated as numbers starting from 0.
58
- */
59
- labelGenerator?: (element: Element, index: number) => string;
58
+ showBoundingBoxes?: boolean;
60
59
  /**
61
60
  * Provide a container element to query the elements to be marked.
62
61
  * By default, the container element is `document.body`.
@@ -73,7 +72,7 @@ interface MarkOptions {
73
72
  interface MarkedElement {
74
73
  element: Element;
75
74
  markElement: HTMLElement;
76
- maskElement?: HTMLElement;
75
+ boundingBoxElement?: HTMLElement;
77
76
  }
78
77
 
79
78
  let cleanupFns: (() => void)[] = [];
@@ -83,7 +82,9 @@ async function mark(
83
82
  ): Promise<Record<string, MarkedElement>> {
84
83
  const {
85
84
  selector = "button, input, a, select, textarea",
86
- markAttribute = "data-mark-id",
85
+ getLabel = (_, index) => index.toString(),
86
+ markAttribute = "data-mark-label",
87
+ markPlacement = "top-start",
87
88
  markStyle = {
88
89
  backgroundColor: "red",
89
90
  color: "white",
@@ -91,13 +92,11 @@ async function mark(
91
92
  fontSize: "12px",
92
93
  fontWeight: "bold",
93
94
  },
94
- markPlacement = "top-start",
95
- maskStyle = {
95
+ boundingBoxStyle = {
96
96
  outline: "2px dashed red",
97
97
  backgroundColor: "transparent",
98
98
  },
99
- showMasks = true,
100
- labelGenerator = (_, index) => index.toString(),
99
+ showBoundingBoxes = true,
101
100
  containerElement = document.body,
102
101
  viewPortOnly = false,
103
102
  } = options;
@@ -112,27 +111,25 @@ async function mark(
112
111
 
113
112
  await Promise.all(
114
113
  elements.map(async (element, index) => {
115
- const label = labelGenerator(element, index);
114
+ const label = getLabel(element, index);
116
115
  const markElement = createMark(element, markStyle, label, markPlacement);
117
116
 
118
- const maskElement = showMasks
119
- ? createMask(element, maskStyle, label)
117
+ const boundingBoxElement = showBoundingBoxes
118
+ ? createBoundingBox(element, boundingBoxStyle, label)
120
119
  : undefined;
121
120
 
122
- markedElements[label] = { element, markElement, maskElement };
121
+ markedElements[label] = { element, markElement, boundingBoxElement };
123
122
  element.setAttribute(markAttribute, label);
124
123
  })
125
124
  );
126
125
 
127
- document.documentElement.dataset.webmarkered = "true";
126
+ document.documentElement.setAttribute("data-marked", "true");
128
127
  return markedElements;
129
128
  }
130
129
 
131
130
  function createMark(
132
131
  element: Element,
133
- style:
134
- | Readonly<Partial<CSSStyleDeclaration>>
135
- | ((element: Element) => Readonly<Partial<CSSStyleDeclaration>>),
132
+ style: StyleObject | StyleFunction,
136
133
  label: string,
137
134
  markPlacement: Placement = "top-start"
138
135
  ): HTMLElement {
@@ -154,20 +151,18 @@ function createMark(
154
151
  return markElement;
155
152
  }
156
153
 
157
- function createMask(
154
+ function createBoundingBox(
158
155
  element: Element,
159
- style:
160
- | Readonly<Partial<CSSStyleDeclaration>>
161
- | ((element: Element) => Readonly<Partial<CSSStyleDeclaration>>),
156
+ style: StyleObject | StyleFunction,
162
157
  label: string
163
158
  ): HTMLElement {
164
- const maskElement = document.createElement("div");
165
- maskElement.className = "webmarker-mask";
166
- maskElement.id = `webmarker-mask-${label}`;
167
- document.body.appendChild(maskElement);
168
- positionMask(maskElement, element);
159
+ const boundingBoxElement = document.createElement("div");
160
+ boundingBoxElement.className = "webmarker-bounding-box";
161
+ boundingBoxElement.id = `webmarker-bounding-box-${label}`;
162
+ document.body.appendChild(boundingBoxElement);
163
+ positionBoundingBox(boundingBoxElement, element);
169
164
  applyStyle(
170
- maskElement,
165
+ boundingBoxElement,
171
166
  {
172
167
  zIndex: "999999999",
173
168
  position: "absolute",
@@ -175,7 +170,7 @@ function createMask(
175
170
  },
176
171
  typeof style === "function" ? style(element) : style
177
172
  );
178
- return maskElement;
173
+ return boundingBoxElement;
179
174
  }
180
175
 
181
176
  function positionMark(
@@ -196,41 +191,41 @@ function positionMark(
196
191
  cleanupFns.push(autoUpdate(element, markElement, updatePosition));
197
192
  }
198
193
 
199
- async function positionMask(mask: HTMLElement, element: Element) {
194
+ async function positionBoundingBox(boundingBox: HTMLElement, element: Element) {
200
195
  const { width, height } = element.getBoundingClientRect();
201
196
  async function updatePosition() {
202
- const { x: maskX, y: maskY } = await computePosition(element, mask, {
197
+ const { x, y } = await computePosition(element, boundingBox, {
203
198
  placement: "top-start",
204
199
  });
205
- Object.assign(mask.style, {
206
- left: `${maskX}px`,
207
- top: `${maskY + height}px`,
200
+ Object.assign(boundingBox.style, {
201
+ left: `${x}px`,
202
+ top: `${y + height}px`,
208
203
  width: `${width}px`,
209
204
  height: `${height}px`,
210
205
  });
211
206
  }
212
- cleanupFns.push(autoUpdate(element, mask, updatePosition));
207
+ cleanupFns.push(autoUpdate(element, boundingBox, updatePosition));
213
208
  }
214
209
 
215
210
  function applyStyle(
216
211
  element: HTMLElement,
217
- defaultStyle: Readonly<Partial<CSSStyleDeclaration>>,
218
- customStyle: Readonly<Partial<CSSStyleDeclaration>>
212
+ defaultStyle: Partial<CSSStyleDeclaration>,
213
+ customStyle: Partial<CSSStyleDeclaration>
219
214
  ): void {
220
215
  Object.assign(element.style, defaultStyle, customStyle);
221
216
  }
222
217
 
223
218
  function unmark(): void {
224
219
  document
225
- .querySelectorAll(".webmarker, .webmarker-mask")
220
+ .querySelectorAll(".webmarker, .webmarker-bounding-box")
226
221
  .forEach((el) => el.remove());
227
- document.documentElement.removeAttribute("data-webmarkered");
222
+ document.documentElement.removeAttribute("data-marked");
228
223
  cleanupFns.forEach((fn) => fn());
229
224
  cleanupFns = [];
230
225
  }
231
226
 
232
227
  function isMarked(): boolean {
233
- return document.documentElement.hasAttribute("data-webmarkered");
228
+ return document.documentElement.hasAttribute("data-marked");
234
229
  }
235
230
 
236
231
  if (typeof window !== "undefined") {
@@ -1,6 +1,4 @@
1
1
  {
2
- "status": "failed",
3
- "failedTests": [
4
- "bcbd25456d68a5d49fac-61d7a7d69e576e88625b"
5
- ]
2
+ "status": "passed",
3
+ "failedTests": []
6
4
  }