webmarker-js 0.3.0 → 0.5.0

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.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
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>;
2
+ type StyleFunction = (element: Element, index: number) => Partial<CSSStyleDeclaration>;
3
3
  type StyleObject = Partial<CSSStyleDeclaration>;
4
4
  interface MarkOptions {
5
5
  /**
@@ -51,13 +51,21 @@ interface MarkOptions {
51
51
  * @default false
52
52
  */
53
53
  viewPortOnly?: boolean;
54
+ /**
55
+ * Additional class to apply to the mark elements.
56
+ */
57
+ markClass?: string;
58
+ /**
59
+ * Additional class to apply to the bounding box elements.
60
+ */
61
+ boundingBoxClass?: string;
54
62
  }
55
63
  interface MarkedElement {
56
64
  element: Element;
57
65
  markElement: HTMLElement;
58
66
  boundingBoxElement?: HTMLElement;
59
67
  }
60
- declare function mark(options?: MarkOptions): Promise<Record<string, MarkedElement>>;
68
+ declare function mark(options?: MarkOptions): Record<string, MarkedElement>;
61
69
  declare function unmark(): void;
62
70
  declare function isMarked(): boolean;
63
71
  export { mark, unmark, isMarked };
package/dist/main.js CHANGED
@@ -928,8 +928,8 @@ var WebMarker = (() => {
928
928
 
929
929
  // src/index.ts
930
930
  var cleanupFns = [];
931
- function mark() {
932
- return __async(this, arguments, function* (options = {}) {
931
+ function mark(options = {}) {
932
+ try {
933
933
  const {
934
934
  selector = "button, input, a, select, textarea",
935
935
  getLabel = (_, index) => index.toString(),
@@ -948,34 +948,57 @@ var WebMarker = (() => {
948
948
  },
949
949
  showBoundingBoxes = true,
950
950
  containerElement = document.body,
951
- viewPortOnly = false
951
+ viewPortOnly = false,
952
+ markClass = "",
953
+ boundingBoxClass = ""
952
954
  } = options;
955
+ const isInViewport = (el) => {
956
+ const rect = el.getBoundingClientRect();
957
+ return rect.top < window.innerHeight && rect.bottom >= 0;
958
+ };
953
959
  const elements = Array.from(
954
960
  containerElement.querySelectorAll(selector)
955
- ).filter(
956
- (el) => !viewPortOnly || el.getBoundingClientRect().top < window.innerHeight
957
- );
961
+ ).filter((el) => !viewPortOnly || isInViewport(el));
958
962
  const markedElements = {};
959
- yield Promise.all(
960
- elements.map((element, index) => __async(this, null, function* () {
961
- const label = getLabel(element, index);
962
- const markElement = createMark(element, markStyle, label, markPlacement);
963
- const boundingBoxElement = showBoundingBoxes ? createBoundingBox(element, boundingBoxStyle, label) : void 0;
964
- markedElements[label] = { element, markElement, boundingBoxElement };
965
- element.setAttribute(markAttribute, label);
966
- }))
967
- );
963
+ const fragment = document.createDocumentFragment();
964
+ elements.forEach((element, index) => {
965
+ const label = getLabel(element, index);
966
+ const markElement = createMark(
967
+ element,
968
+ index,
969
+ markStyle,
970
+ label,
971
+ markPlacement,
972
+ markClass
973
+ );
974
+ fragment.appendChild(markElement);
975
+ const boundingBoxElement = showBoundingBoxes ? createBoundingBox(element, boundingBoxStyle, label, boundingBoxClass) : void 0;
976
+ if (boundingBoxElement) {
977
+ fragment.appendChild(boundingBoxElement);
978
+ }
979
+ markedElements[label] = { element, markElement, boundingBoxElement };
980
+ element.setAttribute(markAttribute, label);
981
+ });
982
+ document.body.appendChild(fragment);
968
983
  document.documentElement.setAttribute("data-marked", "true");
969
984
  return markedElements;
970
- });
985
+ } catch (error) {
986
+ console.error("Error in mark function:", error);
987
+ throw error;
988
+ }
971
989
  }
972
- function createMark(element, style, label, markPlacement = "top-start") {
990
+ function createMark(element, index, style, label, markPlacement = "top-start", markClass) {
973
991
  const markElement = document.createElement("div");
974
- markElement.className = "webmarker";
992
+ markElement.className = `webmarker ${markClass}`.trim();
975
993
  markElement.id = `webmarker-${label}`;
976
994
  markElement.textContent = label;
977
- document.body.appendChild(markElement);
978
- positionMark(markElement, element, markPlacement);
995
+ markElement.setAttribute("aria-hidden", "true");
996
+ positionElement(markElement, element, markPlacement, (x, y) => {
997
+ Object.assign(markElement.style, {
998
+ left: `${x}px`,
999
+ top: `${y}px`
1000
+ });
1001
+ });
979
1002
  applyStyle(
980
1003
  markElement,
981
1004
  {
@@ -983,16 +1006,24 @@ var WebMarker = (() => {
983
1006
  position: "absolute",
984
1007
  pointerEvents: "none"
985
1008
  },
986
- typeof style === "function" ? style(element) : style
1009
+ typeof style === "function" ? style(element, index) : style
987
1010
  );
988
1011
  return markElement;
989
1012
  }
990
- function createBoundingBox(element, style, label) {
1013
+ function createBoundingBox(element, style, label, boundingBoxClass) {
991
1014
  const boundingBoxElement = document.createElement("div");
992
- boundingBoxElement.className = "webmarker-bounding-box";
1015
+ boundingBoxElement.className = `webmarker-bounding-box ${boundingBoxClass}`.trim();
993
1016
  boundingBoxElement.id = `webmarker-bounding-box-${label}`;
994
- document.body.appendChild(boundingBoxElement);
995
- positionBoundingBox(boundingBoxElement, element);
1017
+ boundingBoxElement.setAttribute("aria-hidden", "true");
1018
+ positionElement(boundingBoxElement, element, "top-start", (x, y) => {
1019
+ const { width, height } = element.getBoundingClientRect();
1020
+ Object.assign(boundingBoxElement.style, {
1021
+ left: `${x}px`,
1022
+ top: `${y + height}px`,
1023
+ width: `${width}px`,
1024
+ height: `${height}px`
1025
+ });
1026
+ });
996
1027
  applyStyle(
997
1028
  boundingBoxElement,
998
1029
  {
@@ -1000,47 +1031,27 @@ var WebMarker = (() => {
1000
1031
  position: "absolute",
1001
1032
  pointerEvents: "none"
1002
1033
  },
1003
- typeof style === "function" ? style(element) : style
1034
+ typeof style === "function" ? style(element, parseInt(label)) : style
1004
1035
  );
1005
1036
  return boundingBoxElement;
1006
1037
  }
1007
- function positionMark(markElement, element, markPlacement) {
1038
+ function positionElement(target, anchor, placement, updateCallback) {
1008
1039
  function updatePosition() {
1009
- return __async(this, null, function* () {
1010
- const { x, y } = yield computePosition2(element, markElement, {
1011
- placement: markPlacement
1012
- });
1013
- Object.assign(markElement.style, {
1014
- left: `${x}px`,
1015
- top: `${y}px`
1016
- });
1040
+ computePosition2(anchor, target, { placement }).then(({ x, y }) => {
1041
+ updateCallback(x, y);
1017
1042
  });
1018
1043
  }
1019
- cleanupFns.push(autoUpdate(element, markElement, updatePosition));
1020
- }
1021
- function positionBoundingBox(boundingBox, element) {
1022
- return __async(this, null, function* () {
1023
- const { width, height } = element.getBoundingClientRect();
1024
- function updatePosition() {
1025
- return __async(this, null, function* () {
1026
- const { x, y } = yield computePosition2(element, boundingBox, {
1027
- placement: "top-start"
1028
- });
1029
- Object.assign(boundingBox.style, {
1030
- left: `${x}px`,
1031
- top: `${y + height}px`,
1032
- width: `${width}px`,
1033
- height: `${height}px`
1034
- });
1035
- });
1036
- }
1037
- cleanupFns.push(autoUpdate(element, boundingBox, updatePosition));
1038
- });
1044
+ cleanupFns.push(autoUpdate(anchor, target, updatePosition));
1039
1045
  }
1040
1046
  function applyStyle(element, defaultStyle, customStyle) {
1041
1047
  Object.assign(element.style, defaultStyle, customStyle);
1042
1048
  }
1043
1049
  function unmark() {
1050
+ var _a;
1051
+ const markAttribute = ((_a = document.querySelector("[data-mark-label]")) == null ? void 0 : _a.getAttribute("data-mark-label")) ? "data-mark-label" : "data-webmarker-label";
1052
+ document.querySelectorAll(`[${markAttribute}]`).forEach((el) => {
1053
+ el.removeAttribute(markAttribute);
1054
+ });
1044
1055
  document.querySelectorAll(".webmarker, .webmarker-bounding-box").forEach((el) => el.remove());
1045
1056
  document.documentElement.removeAttribute("data-marked");
1046
1057
  cleanupFns.forEach((fn) => fn());
package/dist/module.js CHANGED
@@ -904,8 +904,8 @@ var computePosition2 = (reference, floating, options) => {
904
904
 
905
905
  // src/index.ts
906
906
  var cleanupFns = [];
907
- function mark() {
908
- return __async(this, arguments, function* (options = {}) {
907
+ function mark(options = {}) {
908
+ try {
909
909
  const {
910
910
  selector = "button, input, a, select, textarea",
911
911
  getLabel = (_, index) => index.toString(),
@@ -924,34 +924,57 @@ function mark() {
924
924
  },
925
925
  showBoundingBoxes = true,
926
926
  containerElement = document.body,
927
- viewPortOnly = false
927
+ viewPortOnly = false,
928
+ markClass = "",
929
+ boundingBoxClass = ""
928
930
  } = options;
931
+ const isInViewport = (el) => {
932
+ const rect = el.getBoundingClientRect();
933
+ return rect.top < window.innerHeight && rect.bottom >= 0;
934
+ };
929
935
  const elements = Array.from(
930
936
  containerElement.querySelectorAll(selector)
931
- ).filter(
932
- (el) => !viewPortOnly || el.getBoundingClientRect().top < window.innerHeight
933
- );
937
+ ).filter((el) => !viewPortOnly || isInViewport(el));
934
938
  const markedElements = {};
935
- yield Promise.all(
936
- elements.map((element, index) => __async(this, null, function* () {
937
- const label = getLabel(element, index);
938
- const markElement = createMark(element, markStyle, label, markPlacement);
939
- const boundingBoxElement = showBoundingBoxes ? createBoundingBox(element, boundingBoxStyle, label) : void 0;
940
- markedElements[label] = { element, markElement, boundingBoxElement };
941
- element.setAttribute(markAttribute, label);
942
- }))
943
- );
939
+ const fragment = document.createDocumentFragment();
940
+ elements.forEach((element, index) => {
941
+ const label = getLabel(element, index);
942
+ const markElement = createMark(
943
+ element,
944
+ index,
945
+ markStyle,
946
+ label,
947
+ markPlacement,
948
+ markClass
949
+ );
950
+ fragment.appendChild(markElement);
951
+ const boundingBoxElement = showBoundingBoxes ? createBoundingBox(element, boundingBoxStyle, label, boundingBoxClass) : void 0;
952
+ if (boundingBoxElement) {
953
+ fragment.appendChild(boundingBoxElement);
954
+ }
955
+ markedElements[label] = { element, markElement, boundingBoxElement };
956
+ element.setAttribute(markAttribute, label);
957
+ });
958
+ document.body.appendChild(fragment);
944
959
  document.documentElement.setAttribute("data-marked", "true");
945
960
  return markedElements;
946
- });
961
+ } catch (error) {
962
+ console.error("Error in mark function:", error);
963
+ throw error;
964
+ }
947
965
  }
948
- function createMark(element, style, label, markPlacement = "top-start") {
966
+ function createMark(element, index, style, label, markPlacement = "top-start", markClass) {
949
967
  const markElement = document.createElement("div");
950
- markElement.className = "webmarker";
968
+ markElement.className = `webmarker ${markClass}`.trim();
951
969
  markElement.id = `webmarker-${label}`;
952
970
  markElement.textContent = label;
953
- document.body.appendChild(markElement);
954
- positionMark(markElement, element, markPlacement);
971
+ markElement.setAttribute("aria-hidden", "true");
972
+ positionElement(markElement, element, markPlacement, (x, y) => {
973
+ Object.assign(markElement.style, {
974
+ left: `${x}px`,
975
+ top: `${y}px`
976
+ });
977
+ });
955
978
  applyStyle(
956
979
  markElement,
957
980
  {
@@ -959,16 +982,24 @@ function createMark(element, style, label, markPlacement = "top-start") {
959
982
  position: "absolute",
960
983
  pointerEvents: "none"
961
984
  },
962
- typeof style === "function" ? style(element) : style
985
+ typeof style === "function" ? style(element, index) : style
963
986
  );
964
987
  return markElement;
965
988
  }
966
- function createBoundingBox(element, style, label) {
989
+ function createBoundingBox(element, style, label, boundingBoxClass) {
967
990
  const boundingBoxElement = document.createElement("div");
968
- boundingBoxElement.className = "webmarker-bounding-box";
991
+ boundingBoxElement.className = `webmarker-bounding-box ${boundingBoxClass}`.trim();
969
992
  boundingBoxElement.id = `webmarker-bounding-box-${label}`;
970
- document.body.appendChild(boundingBoxElement);
971
- positionBoundingBox(boundingBoxElement, element);
993
+ boundingBoxElement.setAttribute("aria-hidden", "true");
994
+ positionElement(boundingBoxElement, element, "top-start", (x, y) => {
995
+ const { width, height } = element.getBoundingClientRect();
996
+ Object.assign(boundingBoxElement.style, {
997
+ left: `${x}px`,
998
+ top: `${y + height}px`,
999
+ width: `${width}px`,
1000
+ height: `${height}px`
1001
+ });
1002
+ });
972
1003
  applyStyle(
973
1004
  boundingBoxElement,
974
1005
  {
@@ -976,47 +1007,27 @@ function createBoundingBox(element, style, label) {
976
1007
  position: "absolute",
977
1008
  pointerEvents: "none"
978
1009
  },
979
- typeof style === "function" ? style(element) : style
1010
+ typeof style === "function" ? style(element, parseInt(label)) : style
980
1011
  );
981
1012
  return boundingBoxElement;
982
1013
  }
983
- function positionMark(markElement, element, markPlacement) {
1014
+ function positionElement(target, anchor, placement, updateCallback) {
984
1015
  function updatePosition() {
985
- return __async(this, null, function* () {
986
- const { x, y } = yield computePosition2(element, markElement, {
987
- placement: markPlacement
988
- });
989
- Object.assign(markElement.style, {
990
- left: `${x}px`,
991
- top: `${y}px`
992
- });
1016
+ computePosition2(anchor, target, { placement }).then(({ x, y }) => {
1017
+ updateCallback(x, y);
993
1018
  });
994
1019
  }
995
- cleanupFns.push(autoUpdate(element, markElement, updatePosition));
996
- }
997
- function positionBoundingBox(boundingBox, element) {
998
- return __async(this, null, function* () {
999
- const { width, height } = element.getBoundingClientRect();
1000
- function updatePosition() {
1001
- return __async(this, null, function* () {
1002
- const { x, y } = yield computePosition2(element, boundingBox, {
1003
- placement: "top-start"
1004
- });
1005
- Object.assign(boundingBox.style, {
1006
- left: `${x}px`,
1007
- top: `${y + height}px`,
1008
- width: `${width}px`,
1009
- height: `${height}px`
1010
- });
1011
- });
1012
- }
1013
- cleanupFns.push(autoUpdate(element, boundingBox, updatePosition));
1014
- });
1020
+ cleanupFns.push(autoUpdate(anchor, target, updatePosition));
1015
1021
  }
1016
1022
  function applyStyle(element, defaultStyle, customStyle) {
1017
1023
  Object.assign(element.style, defaultStyle, customStyle);
1018
1024
  }
1019
1025
  function unmark() {
1026
+ var _a;
1027
+ const markAttribute = ((_a = document.querySelector("[data-mark-label]")) == null ? void 0 : _a.getAttribute("data-mark-label")) ? "data-mark-label" : "data-webmarker-label";
1028
+ document.querySelectorAll(`[${markAttribute}]`).forEach((el) => {
1029
+ el.removeAttribute(markAttribute);
1030
+ });
1020
1031
  document.querySelectorAll(".webmarker, .webmarker-bounding-box").forEach((el) => el.remove());
1021
1032
  document.documentElement.removeAttribute("data-marked");
1022
1033
  cleanupFns.forEach((fn) => fn());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webmarker-js",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
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",
@@ -26,6 +26,7 @@
26
26
  "@mdx-js/react": "^3.0.1",
27
27
  "@next/mdx": "^14.2.3",
28
28
  "@playwright/test": "^1.46.1",
29
+ "@types/jest": "^29.5.13",
29
30
  "@types/mdx": "^2.0.13",
30
31
  "@types/node": "^22.5.1",
31
32
  "autoprefixer": "^10.4.19",
package/src/index.ts CHANGED
@@ -14,7 +14,10 @@ type Placement =
14
14
  | "left-start"
15
15
  | "left-end";
16
16
 
17
- type StyleFunction = (element: Element) => Partial<CSSStyleDeclaration>;
17
+ type StyleFunction = (
18
+ element: Element,
19
+ index: number
20
+ ) => Partial<CSSStyleDeclaration>;
18
21
  type StyleObject = Partial<CSSStyleDeclaration>;
19
22
 
20
23
  interface MarkOptions {
@@ -67,6 +70,14 @@ interface MarkOptions {
67
70
  * @default false
68
71
  */
69
72
  viewPortOnly?: boolean;
73
+ /**
74
+ * Additional class to apply to the mark elements.
75
+ */
76
+ markClass?: string;
77
+ /**
78
+ * Additional class to apply to the bounding box elements.
79
+ */
80
+ boundingBoxClass?: string;
70
81
  }
71
82
 
72
83
  interface MarkedElement {
@@ -77,68 +88,94 @@ interface MarkedElement {
77
88
 
78
89
  let cleanupFns: (() => void)[] = [];
79
90
 
80
- async function mark(
81
- options: MarkOptions = {}
82
- ): Promise<Record<string, MarkedElement>> {
83
- const {
84
- selector = "button, input, a, select, textarea",
85
- getLabel = (_, index) => index.toString(),
86
- markAttribute = "data-mark-label",
87
- markPlacement = "top-start",
88
- markStyle = {
89
- backgroundColor: "red",
90
- color: "white",
91
- padding: "2px 4px",
92
- fontSize: "12px",
93
- fontWeight: "bold",
94
- },
95
- boundingBoxStyle = {
96
- outline: "2px dashed red",
97
- backgroundColor: "transparent",
98
- },
99
- showBoundingBoxes = true,
100
- containerElement = document.body,
101
- viewPortOnly = false,
102
- } = options;
103
-
104
- const elements = Array.from(
105
- containerElement.querySelectorAll(selector)
106
- ).filter(
107
- (el) => !viewPortOnly || el.getBoundingClientRect().top < window.innerHeight
108
- );
91
+ function mark(options: MarkOptions = {}): Record<string, MarkedElement> {
92
+ try {
93
+ const {
94
+ selector = "button, input, a, select, textarea",
95
+ getLabel = (_, index) => index.toString(),
96
+ markAttribute = "data-mark-label",
97
+ markPlacement = "top-start",
98
+ markStyle = {
99
+ backgroundColor: "red",
100
+ color: "white",
101
+ padding: "2px 4px",
102
+ fontSize: "12px",
103
+ fontWeight: "bold",
104
+ },
105
+ boundingBoxStyle = {
106
+ outline: "2px dashed red",
107
+ backgroundColor: "transparent",
108
+ },
109
+ showBoundingBoxes = true,
110
+ containerElement = document.body,
111
+ viewPortOnly = false,
112
+ markClass = "",
113
+ boundingBoxClass = "",
114
+ } = options;
115
+
116
+ const isInViewport = (el: Element) => {
117
+ const rect = el.getBoundingClientRect();
118
+ return rect.top < window.innerHeight && rect.bottom >= 0;
119
+ };
120
+
121
+ const elements = Array.from(
122
+ containerElement.querySelectorAll(selector)
123
+ ).filter((el) => !viewPortOnly || isInViewport(el));
109
124
 
110
- const markedElements: Record<string, MarkedElement> = {};
125
+ const markedElements: Record<string, MarkedElement> = {};
126
+ const fragment = document.createDocumentFragment();
111
127
 
112
- await Promise.all(
113
- elements.map(async (element, index) => {
128
+ elements.forEach((element, index) => {
114
129
  const label = getLabel(element, index);
115
- const markElement = createMark(element, markStyle, label, markPlacement);
130
+ const markElement = createMark(
131
+ element,
132
+ index,
133
+ markStyle,
134
+ label,
135
+ markPlacement,
136
+ markClass
137
+ );
138
+ fragment.appendChild(markElement);
116
139
 
117
140
  const boundingBoxElement = showBoundingBoxes
118
- ? createBoundingBox(element, boundingBoxStyle, label)
141
+ ? createBoundingBox(element, boundingBoxStyle, label, boundingBoxClass)
119
142
  : undefined;
143
+ if (boundingBoxElement) {
144
+ fragment.appendChild(boundingBoxElement);
145
+ }
120
146
 
121
147
  markedElements[label] = { element, markElement, boundingBoxElement };
122
148
  element.setAttribute(markAttribute, label);
123
- })
124
- );
149
+ });
125
150
 
126
- document.documentElement.setAttribute("data-marked", "true");
127
- return markedElements;
151
+ document.body.appendChild(fragment);
152
+ document.documentElement.setAttribute("data-marked", "true");
153
+ return markedElements;
154
+ } catch (error) {
155
+ console.error("Error in mark function:", error);
156
+ throw error;
157
+ }
128
158
  }
129
159
 
130
160
  function createMark(
131
161
  element: Element,
162
+ index: number,
132
163
  style: StyleObject | StyleFunction,
133
164
  label: string,
134
- markPlacement: Placement = "top-start"
165
+ markPlacement: Placement = "top-start",
166
+ markClass: string
135
167
  ): HTMLElement {
136
168
  const markElement = document.createElement("div");
137
- markElement.className = "webmarker";
169
+ markElement.className = `webmarker ${markClass}`.trim();
138
170
  markElement.id = `webmarker-${label}`;
139
171
  markElement.textContent = label;
140
- document.body.appendChild(markElement);
141
- positionMark(markElement, element, markPlacement);
172
+ markElement.setAttribute("aria-hidden", "true");
173
+ positionElement(markElement, element, markPlacement, (x, y) => {
174
+ Object.assign(markElement.style, {
175
+ left: `${x}px`,
176
+ top: `${y}px`,
177
+ });
178
+ });
142
179
  applyStyle(
143
180
  markElement,
144
181
  {
@@ -146,7 +183,7 @@ function createMark(
146
183
  position: "absolute",
147
184
  pointerEvents: "none",
148
185
  },
149
- typeof style === "function" ? style(element) : style
186
+ typeof style === "function" ? style(element, index) : style
150
187
  );
151
188
  return markElement;
152
189
  }
@@ -154,13 +191,23 @@ function createMark(
154
191
  function createBoundingBox(
155
192
  element: Element,
156
193
  style: StyleObject | StyleFunction,
157
- label: string
194
+ label: string,
195
+ boundingBoxClass: string
158
196
  ): HTMLElement {
159
197
  const boundingBoxElement = document.createElement("div");
160
- boundingBoxElement.className = "webmarker-bounding-box";
198
+ boundingBoxElement.className =
199
+ `webmarker-bounding-box ${boundingBoxClass}`.trim();
161
200
  boundingBoxElement.id = `webmarker-bounding-box-${label}`;
162
- document.body.appendChild(boundingBoxElement);
163
- positionBoundingBox(boundingBoxElement, element);
201
+ boundingBoxElement.setAttribute("aria-hidden", "true");
202
+ positionElement(boundingBoxElement, element, "top-start", (x, y) => {
203
+ const { width, height } = element.getBoundingClientRect();
204
+ Object.assign(boundingBoxElement.style, {
205
+ left: `${x}px`,
206
+ top: `${y + height}px`,
207
+ width: `${width}px`,
208
+ height: `${height}px`,
209
+ });
210
+ });
164
211
  applyStyle(
165
212
  boundingBoxElement,
166
213
  {
@@ -168,43 +215,23 @@ function createBoundingBox(
168
215
  position: "absolute",
169
216
  pointerEvents: "none",
170
217
  },
171
- typeof style === "function" ? style(element) : style
218
+ typeof style === "function" ? style(element, parseInt(label)) : style
172
219
  );
173
220
  return boundingBoxElement;
174
221
  }
175
222
 
176
- function positionMark(
177
- markElement: HTMLElement,
178
- element: Element,
179
- markPlacement: Placement
223
+ function positionElement(
224
+ target: HTMLElement,
225
+ anchor: Element,
226
+ placement: Placement,
227
+ updateCallback: (x: number, y: number) => void
180
228
  ) {
181
- async function updatePosition() {
182
- const { x, y } = await computePosition(element, markElement, {
183
- placement: markPlacement,
184
- });
185
- Object.assign(markElement.style, {
186
- left: `${x}px`,
187
- top: `${y}px`,
229
+ function updatePosition() {
230
+ computePosition(anchor, target, { placement }).then(({ x, y }) => {
231
+ updateCallback(x, y);
188
232
  });
189
233
  }
190
-
191
- cleanupFns.push(autoUpdate(element, markElement, updatePosition));
192
- }
193
-
194
- async function positionBoundingBox(boundingBox: HTMLElement, element: Element) {
195
- const { width, height } = element.getBoundingClientRect();
196
- async function updatePosition() {
197
- const { x, y } = await computePosition(element, boundingBox, {
198
- placement: "top-start",
199
- });
200
- Object.assign(boundingBox.style, {
201
- left: `${x}px`,
202
- top: `${y + height}px`,
203
- width: `${width}px`,
204
- height: `${height}px`,
205
- });
206
- }
207
- cleanupFns.push(autoUpdate(element, boundingBox, updatePosition));
234
+ cleanupFns.push(autoUpdate(anchor, target, updatePosition));
208
235
  }
209
236
 
210
237
  function applyStyle(
@@ -216,6 +243,15 @@ function applyStyle(
216
243
  }
217
244
 
218
245
  function unmark(): void {
246
+ const markAttribute = document
247
+ .querySelector("[data-mark-label]")
248
+ ?.getAttribute("data-mark-label")
249
+ ? "data-mark-label"
250
+ : "data-webmarker-label";
251
+
252
+ document.querySelectorAll(`[${markAttribute}]`).forEach((el) => {
253
+ el.removeAttribute(markAttribute);
254
+ });
219
255
  document
220
256
  .querySelectorAll(".webmarker, .webmarker-bounding-box")
221
257
  .forEach((el) => el.remove());