@technoapple/ga4 1.0.4 → 1.1.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.
Files changed (74) hide show
  1. package/.github/workflows/node.js.yml +31 -31
  2. package/.prettierignore +1 -1
  3. package/LICENSE +21 -21
  4. package/README.md +386 -48
  5. package/REQUIREMENTS.md +548 -0
  6. package/babel.config.js +5 -5
  7. package/build/main/ga4/ga4.d.ts +13 -0
  8. package/build/main/ga4/ga4.js +24 -1
  9. package/build/main/helpers/debounce.d.ts +5 -0
  10. package/build/main/helpers/debounce.js +23 -0
  11. package/build/main/helpers/delegate.d.ts +8 -0
  12. package/build/main/helpers/delegate.js +37 -0
  13. package/build/main/helpers/dom-ready.d.ts +1 -0
  14. package/build/main/helpers/dom-ready.js +13 -0
  15. package/build/main/helpers/parse-url.d.ts +11 -0
  16. package/build/main/helpers/parse-url.js +32 -0
  17. package/build/main/helpers/session.d.ts +4 -0
  18. package/build/main/helpers/session.js +50 -0
  19. package/build/main/index.d.ts +9 -0
  20. package/build/main/index.js +19 -2
  21. package/build/main/plugins/clean-url-tracker.d.ts +17 -0
  22. package/build/main/plugins/clean-url-tracker.js +105 -0
  23. package/build/main/plugins/event-tracker.d.ts +27 -0
  24. package/build/main/plugins/event-tracker.js +76 -0
  25. package/build/main/plugins/impression-tracker.d.ts +32 -0
  26. package/build/main/plugins/impression-tracker.js +202 -0
  27. package/build/main/plugins/index.d.ts +8 -0
  28. package/build/main/plugins/index.js +20 -0
  29. package/build/main/plugins/media-query-tracker.d.ts +20 -0
  30. package/build/main/plugins/media-query-tracker.js +96 -0
  31. package/build/main/plugins/outbound-form-tracker.d.ts +17 -0
  32. package/build/main/plugins/outbound-form-tracker.js +55 -0
  33. package/build/main/plugins/outbound-link-tracker.d.ts +19 -0
  34. package/build/main/plugins/outbound-link-tracker.js +63 -0
  35. package/build/main/plugins/page-visibility-tracker.d.ts +24 -0
  36. package/build/main/plugins/page-visibility-tracker.js +93 -0
  37. package/build/main/plugins/url-change-tracker.d.ts +20 -0
  38. package/build/main/plugins/url-change-tracker.js +76 -0
  39. package/build/main/types/plugins.d.ts +78 -0
  40. package/build/main/types/plugins.js +3 -0
  41. package/build/tsconfig.tsbuildinfo +1 -1
  42. package/docs/examples/react.md +95 -0
  43. package/docs/examples/vanilla.md +65 -0
  44. package/docs/examples/vue.md +87 -0
  45. package/jest.config.ts +195 -195
  46. package/package.json +56 -56
  47. package/src/dataLayer.ts +85 -85
  48. package/src/ga4/ga4.ts +69 -40
  49. package/src/ga4/ga4option.ts +4 -4
  50. package/src/ga4/index.ts +4 -4
  51. package/src/helpers/debounce.ts +28 -0
  52. package/src/helpers/delegate.ts +51 -0
  53. package/src/helpers/dom-ready.ts +7 -0
  54. package/src/helpers/parse-url.ts +37 -0
  55. package/src/helpers/session.ts +39 -0
  56. package/src/index.ts +34 -7
  57. package/src/plugins/clean-url-tracker.ts +112 -0
  58. package/src/plugins/event-tracker.ts +90 -0
  59. package/src/plugins/impression-tracker.ts +230 -0
  60. package/src/plugins/index.ts +8 -0
  61. package/src/plugins/media-query-tracker.ts +116 -0
  62. package/src/plugins/outbound-form-tracker.ts +65 -0
  63. package/src/plugins/outbound-link-tracker.ts +72 -0
  64. package/src/plugins/page-visibility-tracker.ts +104 -0
  65. package/src/plugins/url-change-tracker.ts +84 -0
  66. package/src/types/dataLayer.ts +9 -9
  67. package/src/types/global.ts +12 -12
  68. package/src/types/gtag.ts +259 -259
  69. package/src/types/plugins.ts +98 -0
  70. package/src/util.ts +18 -18
  71. package/test/dataLayer.spec.ts +55 -55
  72. package/test/ga4.spec.ts +36 -36
  73. package/tsconfig.json +28 -28
  74. package/tsconfig.module.json +11 -11
@@ -0,0 +1,98 @@
1
+ export type SendFunction = (eventName: string, params: Record<string, unknown>) => void;
2
+
3
+ export interface GA4Plugin {
4
+ remove(): void;
5
+ }
6
+
7
+ // --- Event Tracker ---
8
+
9
+ export interface EventTrackerOptions {
10
+ events?: string[];
11
+ attributePrefix?: string;
12
+ hitFilter?: (params: Record<string, unknown>, element: Element, event: Event) => Record<string, unknown> | null;
13
+ }
14
+
15
+ // --- Outbound Link Tracker ---
16
+
17
+ export interface OutboundLinkTrackerOptions {
18
+ events?: string[];
19
+ linkSelector?: string;
20
+ shouldTrackOutboundLink?: (link: Element, parseUrl: (url: string) => { hostname: string; protocol: string; href: string }) => boolean;
21
+ eventName?: string;
22
+ attributePrefix?: string;
23
+ hitFilter?: (params: Record<string, unknown>, element: Element, event: Event) => Record<string, unknown> | null;
24
+ }
25
+
26
+ // --- Outbound Form Tracker ---
27
+
28
+ export interface OutboundFormTrackerOptions {
29
+ formSelector?: string;
30
+ shouldTrackOutboundForm?: (form: HTMLFormElement, parseUrl: (url: string) => { hostname: string; protocol: string; href: string }) => boolean;
31
+ eventName?: string;
32
+ hitFilter?: (params: Record<string, unknown>, element: Element, event: Event) => Record<string, unknown> | null;
33
+ }
34
+
35
+ // --- Page Visibility Tracker ---
36
+
37
+ export interface PageVisibilityTrackerOptions {
38
+ sendInitialPageview?: boolean;
39
+ sessionTimeout?: number;
40
+ timeZone?: string;
41
+ eventName?: string;
42
+ hitFilter?: (params: Record<string, unknown>) => Record<string, unknown> | null;
43
+ }
44
+
45
+ // --- URL Change Tracker ---
46
+
47
+ export interface UrlChangeTrackerOptions {
48
+ shouldTrackUrlChange?: (newPath: string, oldPath: string) => boolean;
49
+ trackReplaceState?: boolean;
50
+ hitFilter?: (params: Record<string, unknown>) => Record<string, unknown> | null;
51
+ }
52
+
53
+ // --- Impression Tracker ---
54
+
55
+ export interface ImpressionElementConfig {
56
+ id: string;
57
+ threshold?: number;
58
+ trackFirstImpressionOnly?: boolean;
59
+ }
60
+
61
+ export interface ImpressionTrackerOptions {
62
+ elements?: Array<string | ImpressionElementConfig>;
63
+ rootMargin?: string;
64
+ attributePrefix?: string;
65
+ eventName?: string;
66
+ hitFilter?: (params: Record<string, unknown>, element: Element) => Record<string, unknown> | null;
67
+ }
68
+
69
+ // --- Clean URL Tracker ---
70
+
71
+ export interface CleanUrlTrackerOptions {
72
+ stripQuery?: boolean;
73
+ queryParamsAllowlist?: string[];
74
+ queryParamsDenylist?: string[];
75
+ trailingSlash?: 'add' | 'remove';
76
+ urlFilter?: (url: string) => string;
77
+ }
78
+
79
+ // --- Media Query Tracker ---
80
+
81
+ export interface MediaQueryDefinitionItem {
82
+ name: string;
83
+ media: string;
84
+ }
85
+
86
+ export interface MediaQueryDefinition {
87
+ name: string;
88
+ dimensionIndex?: number;
89
+ items: MediaQueryDefinitionItem[];
90
+ }
91
+
92
+ export interface MediaQueryTrackerOptions {
93
+ definitions?: MediaQueryDefinition[];
94
+ changeTemplate?: (oldValue: string, newValue: string) => string;
95
+ changeTimeout?: number;
96
+ eventName?: string;
97
+ hitFilter?: (params: Record<string, unknown>) => Record<string, unknown> | null;
98
+ }
package/src/util.ts CHANGED
@@ -1,18 +1,18 @@
1
- function findLast<T>(
2
- list: Array<T>
3
- , predicate: (value: T, index: number, obj: T[]) => unknown)
4
- : T | undefined {
5
-
6
- for (let index = list.length - 1; index >= 0; index--) {
7
- let currentValue = list[index];
8
- let predicateResult = predicate(currentValue, index, list);
9
- if (predicateResult) {
10
- return currentValue;
11
- }
12
- }
13
-
14
- return undefined;
15
- }
16
-
17
- export {findLast};
18
-
1
+ function findLast<T>(
2
+ list: Array<T>
3
+ , predicate: (value: T, index: number, obj: T[]) => unknown)
4
+ : T | undefined {
5
+
6
+ for (let index = list.length - 1; index >= 0; index--) {
7
+ let currentValue = list[index];
8
+ let predicateResult = predicate(currentValue, index, list);
9
+ if (predicateResult) {
10
+ return currentValue;
11
+ }
12
+ }
13
+
14
+ return undefined;
15
+ }
16
+
17
+ export {findLast};
18
+
@@ -1,56 +1,56 @@
1
- import {} from '../src/types/global';
2
- import {dataLayerHelper} from '../src/index';
3
- import {findLast} from '../src/util';
4
-
5
- describe('test dataLayer get function', () => {
6
- beforeEach(() => {
7
- window.dataLayer = [];
8
- });
9
-
10
- test('by default dataLayer get should return the 1st item', () => {
11
-
12
- window.dataLayer = window.dataLayer || [];
13
-
14
- window.dataLayer.push({
15
- 'test': 1
16
- });
17
- window.dataLayer.push({
18
- 'test': 11
19
- });
20
-
21
- const result = dataLayerHelper.get('test');
22
- expect(result).toBe(1);
23
-
24
- });
25
-
26
- test('If dataLayer array has object use the key should get the value', () => {
27
-
28
- const data = [
29
- {event: 'test'},
30
- ['js'],
31
- ['config', 'g-123'],
32
- ['event', 'conversion', {'allow': true}]
33
- ];
34
- window.dataLayer = data;
35
-
36
- const result = dataLayerHelper.get('allow');
37
- expect(result).toBe(true);
38
-
39
- });
40
-
41
- test('if get last is true should return the last item', () => {
42
-
43
- window.dataLayer = window.dataLayer || [];
44
-
45
- window.dataLayer.push({
46
- 'test': 1
47
- });
48
- window.dataLayer.push({
49
- 'test': 11
50
- });
51
-
52
- const result = dataLayerHelper.get('test', true);
53
- expect(result).toBe(11);
54
-
55
- });
1
+ import {} from '../src/types/global';
2
+ import {dataLayerHelper} from '../src/index';
3
+ import {findLast} from '../src/util';
4
+
5
+ describe('test dataLayer get function', () => {
6
+ beforeEach(() => {
7
+ window.dataLayer = [];
8
+ });
9
+
10
+ test('by default dataLayer get should return the 1st item', () => {
11
+
12
+ window.dataLayer = window.dataLayer || [];
13
+
14
+ window.dataLayer.push({
15
+ 'test': 1
16
+ });
17
+ window.dataLayer.push({
18
+ 'test': 11
19
+ });
20
+
21
+ const result = dataLayerHelper.get('test');
22
+ expect(result).toBe(1);
23
+
24
+ });
25
+
26
+ test('If dataLayer array has object use the key should get the value', () => {
27
+
28
+ const data = [
29
+ {event: 'test'},
30
+ ['js'],
31
+ ['config', 'g-123'],
32
+ ['event', 'conversion', {'allow': true}]
33
+ ];
34
+ window.dataLayer = data;
35
+
36
+ const result = dataLayerHelper.get('allow');
37
+ expect(result).toBe(true);
38
+
39
+ });
40
+
41
+ test('if get last is true should return the last item', () => {
42
+
43
+ window.dataLayer = window.dataLayer || [];
44
+
45
+ window.dataLayer.push({
46
+ 'test': 1
47
+ });
48
+ window.dataLayer.push({
49
+ 'test': 11
50
+ });
51
+
52
+ const result = dataLayerHelper.get('test', true);
53
+ expect(result).toBe(11);
54
+
55
+ });
56
56
  });
package/test/ga4.spec.ts CHANGED
@@ -1,37 +1,37 @@
1
- import {} from '../src/types/global';
2
- import { ga4 } from '../src/index';
3
- import { ga4Option } from '../src/ga4/ga4option';
4
-
5
- describe('test ga4', () => {
6
- test('init ga4 should call gtag', () => {
7
-
8
- window.gtag = jest.fn();
9
-
10
- ga4.init({
11
- targetId: 'g-123'
12
- } as ga4Option);
13
-
14
- ga4.send('test', {
15
- 'test': 1
16
- });
17
-
18
- expect(window.gtag).toBeCalledTimes(3);
19
-
20
- });
21
-
22
- test('init ga4 able to use gtag at ga4', () => {
23
-
24
- window.gtag = jest.fn();
25
-
26
- ga4.init({
27
- targetId: 'g-123'
28
- } as ga4Option);
29
-
30
- ga4.gtag('event', 'test', {
31
- 'test': 1
32
- });
33
-
34
- expect(window.gtag).toBeCalledTimes(3);
35
-
36
- });
1
+ import {} from '../src/types/global';
2
+ import { ga4 } from '../src/index';
3
+ import { ga4Option } from '../src/ga4/ga4option';
4
+
5
+ describe('test ga4', () => {
6
+ test('init ga4 should call gtag', () => {
7
+
8
+ window.gtag = jest.fn();
9
+
10
+ ga4.init({
11
+ targetId: 'g-123'
12
+ } as ga4Option);
13
+
14
+ ga4.send('test', {
15
+ 'test': 1
16
+ });
17
+
18
+ expect(window.gtag).toBeCalledTimes(3);
19
+
20
+ });
21
+
22
+ test('init ga4 able to use gtag at ga4', () => {
23
+
24
+ window.gtag = jest.fn();
25
+
26
+ ga4.init({
27
+ targetId: 'g-123'
28
+ } as ga4Option);
29
+
30
+ ga4.gtag('event', 'test', {
31
+ 'test': 1
32
+ });
33
+
34
+ expect(window.gtag).toBeCalledTimes(3);
35
+
36
+ });
37
37
  });
package/tsconfig.json CHANGED
@@ -1,29 +1,29 @@
1
- {
2
- "compilerOptions": {
3
- "incremental": true,
4
- "target": "ES2022",
5
- "outDir": "build/main",
6
- "rootDir": "src",
7
- "moduleResolution": "node",
8
- "module": "commonjs",
9
- "declaration": true,
10
- "inlineSourceMap": true,
11
- "esModuleInterop": true,
12
- "resolveJsonModule": true,
13
- "strict": true,
14
- "noUnusedLocals": true,
15
- "noUnusedParameters": true,
16
- "noImplicitReturns": true,
17
- "noFallthroughCasesInSwitch": true,
18
- "traceResolution": false,
19
- "listEmittedFiles": false,
20
- "listFiles": false,
21
- "pretty": true,
22
- "lib": ["es2017", "dom"],
23
- "types": ["node"],
24
- "typeRoots": ["node_modules/@types", "src/types"]
25
- },
26
- "include": ["src/**/*.ts"],
27
- "exclude": ["node_modules/**"],
28
- "compileOnSave": false
1
+ {
2
+ "compilerOptions": {
3
+ "incremental": true,
4
+ "target": "ES2022",
5
+ "outDir": "build/main",
6
+ "rootDir": "src",
7
+ "moduleResolution": "node",
8
+ "module": "commonjs",
9
+ "declaration": true,
10
+ "inlineSourceMap": true,
11
+ "esModuleInterop": true,
12
+ "resolveJsonModule": true,
13
+ "strict": true,
14
+ "noUnusedLocals": true,
15
+ "noUnusedParameters": true,
16
+ "noImplicitReturns": true,
17
+ "noFallthroughCasesInSwitch": true,
18
+ "traceResolution": false,
19
+ "listEmittedFiles": false,
20
+ "listFiles": false,
21
+ "pretty": true,
22
+ "lib": ["es2017", "dom"],
23
+ "types": ["node"],
24
+ "typeRoots": ["node_modules/@types", "src/types"]
25
+ },
26
+ "include": ["src/**/*.ts"],
27
+ "exclude": ["node_modules/**"],
28
+ "compileOnSave": false
29
29
  }
@@ -1,12 +1,12 @@
1
- {
2
- "extends": "./tsconfig",
3
- "compilerOptions": {
4
- "target": "esnext",
5
- "outDir": "build/module",
6
- "module": "esnext"
7
- },
8
- "exclude": [
9
- "node_modules/**",
10
- "src/cli/**/*.ts"
11
- ]
1
+ {
2
+ "extends": "./tsconfig",
3
+ "compilerOptions": {
4
+ "target": "esnext",
5
+ "outDir": "build/module",
6
+ "module": "esnext"
7
+ },
8
+ "exclude": [
9
+ "node_modules/**",
10
+ "src/cli/**/*.ts"
11
+ ]
12
12
  }