@posthog/browser-common 0.9.1 → 0.9.2

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/config.js CHANGED
@@ -27,7 +27,7 @@ var __webpack_require__ = {};
27
27
  })();
28
28
  var __webpack_exports__ = {};
29
29
  __webpack_require__.r(__webpack_exports__);
30
- const packageVersion = "0.9.1";
30
+ const packageVersion = "0.9.2";
31
31
  const Config = {
32
32
  DEBUG: false,
33
33
  LIB_VERSION: packageVersion,
package/dist/config.mjs CHANGED
@@ -1,4 +1,4 @@
1
- const packageVersion = "0.9.1";
1
+ const packageVersion = "0.9.2";
2
2
  const Config = {
3
3
  DEBUG: false,
4
4
  LIB_VERSION: packageVersion,
@@ -138,7 +138,17 @@ const DEFAULT_CONTENT_IGNORELIST = [
138
138
  'previous',
139
139
  'prev',
140
140
  '>',
141
- '<'
141
+ '<',
142
+ '→',
143
+ '←',
144
+ '›',
145
+ '‹',
146
+ '»',
147
+ '«',
148
+ '▶',
149
+ '◀',
150
+ '❯',
151
+ '❮'
142
152
  ];
143
153
  const DEFAULT_CONTENT_IGNORELIST_WITH_STEPPERS = [
144
154
  ...DEFAULT_CONTENT_IGNORELIST,
@@ -147,10 +157,27 @@ const DEFAULT_CONTENT_IGNORELIST_WITH_STEPPERS = [
147
157
  '−',
148
158
  '–'
149
159
  ];
150
- const MAX_CONTENT_IGNORELIST_ENTRIES = 10;
151
- const matchesContentKeyword = (text, keyword)=>/[a-z0-9]/i.test(keyword) ? text.includes(keyword) : text === keyword;
152
- function shouldIgnoreByContent(contentIgnorelist, elementsWithText) {
153
- if (false === contentIgnorelist || (0, core_namespaceObject.isUndefined)(contentIgnorelist)) return false;
160
+ const MAX_CONTENT_IGNORELIST_ENTRIES = DEFAULT_CONTENT_IGNORELIST_WITH_STEPPERS.length + 10;
161
+ const INTERACTIVE_TAGS = [
162
+ 'button',
163
+ 'a',
164
+ 'input',
165
+ 'select',
166
+ 'textarea',
167
+ 'label'
168
+ ];
169
+ const INTERACTIVE_ROLES = [
170
+ 'button',
171
+ 'link',
172
+ 'tab',
173
+ 'menuitem',
174
+ 'option'
175
+ ];
176
+ const matchesContentKeyword = (text, keyword)=>{
177
+ if (!/[a-z0-9]/i.test(keyword)) return text === keyword;
178
+ return (0, core_namespaceObject.includes)(DEFAULT_CONTENT_IGNORELIST_WITH_STEPPERS, keyword) ? new RegExp(`\\b${keyword}\\b`).test(text) : text.includes(keyword);
179
+ };
180
+ function shouldIgnoreByContent(contentIgnorelist, { safeText, ariaLabel }) {
154
181
  let keywords;
155
182
  if (true === contentIgnorelist) keywords = DEFAULT_CONTENT_IGNORELIST;
156
183
  else {
@@ -161,7 +188,40 @@ function shouldIgnoreByContent(contentIgnorelist, elementsWithText) {
161
188
  }
162
189
  keywords = contentIgnorelist.map((k)=>k.toLowerCase());
163
190
  }
164
- return elementsWithText.some(({ safeText, ariaLabel })=>keywords.some((keyword)=>matchesContentKeyword(safeText, keyword) || matchesContentKeyword(ariaLabel, keyword)));
191
+ return keywords.some((keyword)=>matchesContentKeyword(safeText, keyword) || matchesContentKeyword(ariaLabel, keyword));
192
+ }
193
+ const isInteractiveElement = (el)=>(0, core_namespaceObject.includes)(INTERACTIVE_TAGS, el.tagName.toLowerCase()) || (0, core_namespaceObject.includes)(INTERACTIVE_ROLES, (el.getAttribute('role') || '').toLowerCase());
194
+ function clickedControlText(el, targetElementList) {
195
+ for (const candidate of targetElementList)if (isInteractiveElement(candidate)) return controlLabelText(candidate);
196
+ for (const candidate of targetElementList){
197
+ try {
198
+ if (external_globals_js_namespaceObject.window?.getComputedStyle(candidate).getPropertyValue('cursor') !== 'pointer') break;
199
+ } catch {
200
+ break;
201
+ }
202
+ const label = controlLabelText(candidate);
203
+ if (label.safeText || label.ariaLabel) return label;
204
+ }
205
+ return controlLabelText(el);
206
+ }
207
+ function controlLabelText(control) {
208
+ let text = '';
209
+ let firstAriaLabel = '';
210
+ const collect = (node)=>{
211
+ if ((0, external_element_utils_js_namespaceObject.isElementNode)(node) && shouldCaptureElement(node) && !isSensitiveElement(node)) {
212
+ text += ` ${getSafeText(node)}`;
213
+ firstAriaLabel = firstAriaLabel || node.getAttribute('aria-label') || '';
214
+ (0, external_general_utils_js_namespaceObject.each)(node.childNodes, collect);
215
+ }
216
+ };
217
+ collect(control);
218
+ text = (0, core_namespaceObject.trim)(text.replace(/\s+/g, ' '));
219
+ const safeText = (shouldCaptureValue(text) ? text : '').toLowerCase();
220
+ const ariaLabel = control.getAttribute('aria-label') || (safeText ? '' : firstAriaLabel);
221
+ return {
222
+ safeText,
223
+ ariaLabel: (0, core_namespaceObject.trim)(ariaLabel).toLowerCase()
224
+ };
165
225
  }
166
226
  const DEFAULT_DEAD_CLICK_IGNORE_LIST = [
167
227
  '.ph-no-deadclick',
@@ -215,11 +275,7 @@ function shouldCaptureRageclick(el, _config) {
215
275
  if (false === selectorIgnoreList) return false;
216
276
  if (ignoreTextSelection && isTextSelectionTarget(el)) return false;
217
277
  const { targetElementList } = getElementAndParentsForElement(el, false);
218
- const elementsWithText = targetElementList.map((element)=>({
219
- safeText: getSafeText(element).toLowerCase(),
220
- ariaLabel: element.getAttribute('aria-label')?.toLowerCase().trim() || ''
221
- }));
222
- if (shouldIgnoreByContent(contentIgnorelist, elementsWithText)) return false;
278
+ if (contentIgnorelist && shouldIgnoreByContent(contentIgnorelist, clickedControlText(el, targetElementList))) return false;
223
279
  return !checkIfElementsMatchCSSSelector(targetElementList, selectorIgnoreList);
224
280
  }
225
281
  const cannotCheckForAutocapture = (el)=>!el || (0, external_element_utils_js_namespaceObject.isTag)(el, 'html') || !(0, external_element_utils_js_namespaceObject.isElementNode)(el);
@@ -84,7 +84,17 @@ const DEFAULT_CONTENT_IGNORELIST = [
84
84
  'previous',
85
85
  'prev',
86
86
  '>',
87
- '<'
87
+ '<',
88
+ '→',
89
+ '←',
90
+ '›',
91
+ '‹',
92
+ '»',
93
+ '«',
94
+ '▶',
95
+ '◀',
96
+ '❯',
97
+ '❮'
88
98
  ];
89
99
  const DEFAULT_CONTENT_IGNORELIST_WITH_STEPPERS = [
90
100
  ...DEFAULT_CONTENT_IGNORELIST,
@@ -93,10 +103,27 @@ const DEFAULT_CONTENT_IGNORELIST_WITH_STEPPERS = [
93
103
  '−',
94
104
  '–'
95
105
  ];
96
- const MAX_CONTENT_IGNORELIST_ENTRIES = 10;
97
- const matchesContentKeyword = (text, keyword)=>/[a-z0-9]/i.test(keyword) ? text.includes(keyword) : text === keyword;
98
- function shouldIgnoreByContent(contentIgnorelist, elementsWithText) {
99
- if (false === contentIgnorelist || isUndefined(contentIgnorelist)) return false;
106
+ const MAX_CONTENT_IGNORELIST_ENTRIES = DEFAULT_CONTENT_IGNORELIST_WITH_STEPPERS.length + 10;
107
+ const INTERACTIVE_TAGS = [
108
+ 'button',
109
+ 'a',
110
+ 'input',
111
+ 'select',
112
+ 'textarea',
113
+ 'label'
114
+ ];
115
+ const INTERACTIVE_ROLES = [
116
+ 'button',
117
+ 'link',
118
+ 'tab',
119
+ 'menuitem',
120
+ 'option'
121
+ ];
122
+ const matchesContentKeyword = (text, keyword)=>{
123
+ if (!/[a-z0-9]/i.test(keyword)) return text === keyword;
124
+ return includes(DEFAULT_CONTENT_IGNORELIST_WITH_STEPPERS, keyword) ? new RegExp(`\\b${keyword}\\b`).test(text) : text.includes(keyword);
125
+ };
126
+ function shouldIgnoreByContent(contentIgnorelist, { safeText, ariaLabel }) {
100
127
  let keywords;
101
128
  if (true === contentIgnorelist) keywords = DEFAULT_CONTENT_IGNORELIST;
102
129
  else {
@@ -107,7 +134,40 @@ function shouldIgnoreByContent(contentIgnorelist, elementsWithText) {
107
134
  }
108
135
  keywords = contentIgnorelist.map((k)=>k.toLowerCase());
109
136
  }
110
- return elementsWithText.some(({ safeText, ariaLabel })=>keywords.some((keyword)=>matchesContentKeyword(safeText, keyword) || matchesContentKeyword(ariaLabel, keyword)));
137
+ return keywords.some((keyword)=>matchesContentKeyword(safeText, keyword) || matchesContentKeyword(ariaLabel, keyword));
138
+ }
139
+ const isInteractiveElement = (el)=>includes(INTERACTIVE_TAGS, el.tagName.toLowerCase()) || includes(INTERACTIVE_ROLES, (el.getAttribute('role') || '').toLowerCase());
140
+ function clickedControlText(el, targetElementList) {
141
+ for (const candidate of targetElementList)if (isInteractiveElement(candidate)) return controlLabelText(candidate);
142
+ for (const candidate of targetElementList){
143
+ try {
144
+ if (external_globals_mjs_window?.getComputedStyle(candidate).getPropertyValue('cursor') !== 'pointer') break;
145
+ } catch {
146
+ break;
147
+ }
148
+ const label = controlLabelText(candidate);
149
+ if (label.safeText || label.ariaLabel) return label;
150
+ }
151
+ return controlLabelText(el);
152
+ }
153
+ function controlLabelText(control) {
154
+ let text = '';
155
+ let firstAriaLabel = '';
156
+ const collect = (node)=>{
157
+ if (isElementNode(node) && shouldCaptureElement(node) && !isSensitiveElement(node)) {
158
+ text += ` ${getSafeText(node)}`;
159
+ firstAriaLabel = firstAriaLabel || node.getAttribute('aria-label') || '';
160
+ each(node.childNodes, collect);
161
+ }
162
+ };
163
+ collect(control);
164
+ text = trim(text.replace(/\s+/g, ' '));
165
+ const safeText = (shouldCaptureValue(text) ? text : '').toLowerCase();
166
+ const ariaLabel = control.getAttribute('aria-label') || (safeText ? '' : firstAriaLabel);
167
+ return {
168
+ safeText,
169
+ ariaLabel: trim(ariaLabel).toLowerCase()
170
+ };
111
171
  }
112
172
  const DEFAULT_DEAD_CLICK_IGNORE_LIST = [
113
173
  '.ph-no-deadclick',
@@ -161,11 +221,7 @@ function shouldCaptureRageclick(el, _config) {
161
221
  if (false === selectorIgnoreList) return false;
162
222
  if (ignoreTextSelection && isTextSelectionTarget(el)) return false;
163
223
  const { targetElementList } = getElementAndParentsForElement(el, false);
164
- const elementsWithText = targetElementList.map((element)=>({
165
- safeText: getSafeText(element).toLowerCase(),
166
- ariaLabel: element.getAttribute('aria-label')?.toLowerCase().trim() || ''
167
- }));
168
- if (shouldIgnoreByContent(contentIgnorelist, elementsWithText)) return false;
224
+ if (contentIgnorelist && shouldIgnoreByContent(contentIgnorelist, clickedControlText(el, targetElementList))) return false;
169
225
  return !checkIfElementsMatchCSSSelector(targetElementList, selectorIgnoreList);
170
226
  }
171
227
  const cannotCheckForAutocapture = (el)=>!el || isTag(el, 'html') || !isElementNode(el);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@posthog/browser-common",
3
- "version": "0.9.1",
3
+ "version": "0.9.2",
4
4
  "description": "Internal shared browser utilities and extension primitives for PostHog Browser SDKs",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -73,8 +73,8 @@
73
73
  }
74
74
  },
75
75
  "dependencies": {
76
- "@posthog/core": "^1.55.3",
77
- "@posthog/types": "^1.413.0"
76
+ "@posthog/core": "^1.57.0",
77
+ "@posthog/types": "^1.415.1"
78
78
  },
79
79
  "devDependencies": {
80
80
  "@rslib/core": "0.23.2",