@se-studio/core-ui 1.0.14 → 1.0.15
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/README.md +33 -14
- package/dist/CmsRendererConfig.d.ts +122 -0
- package/dist/CmsRendererConfig.d.ts.map +1 -1
- package/dist/analytics/AnalyticsProvider.d.ts +7 -0
- package/dist/analytics/AnalyticsProvider.d.ts.map +1 -1
- package/dist/analytics/AnalyticsProvider.js +7 -0
- package/dist/analytics/AnalyticsProvider.js.map +1 -1
- package/dist/analytics/adapters/ConsoleAnalyticsAdapter.d.ts +4 -0
- package/dist/analytics/adapters/ConsoleAnalyticsAdapter.d.ts.map +1 -1
- package/dist/analytics/adapters/ConsoleAnalyticsAdapter.js +5 -0
- package/dist/analytics/adapters/ConsoleAnalyticsAdapter.js.map +1 -1
- package/dist/analytics/types.d.ts +23 -0
- package/dist/analytics/types.d.ts.map +1 -1
- package/dist/analytics/useAnalytics.d.ts +35 -0
- package/dist/analytics/useAnalytics.d.ts.map +1 -1
- package/dist/analytics/useAnalytics.js +35 -0
- package/dist/analytics/useAnalytics.js.map +1 -1
- package/dist/components/ClientMonitor.js +36 -0
- package/dist/components/ClientMonitor.js.map +1 -1
- package/dist/components/CmsCollection.d.ts +47 -0
- package/dist/components/CmsCollection.d.ts.map +1 -1
- package/dist/components/CmsCollection.js +7 -0
- package/dist/components/CmsCollection.js.map +1 -1
- package/dist/components/CmsComponent.d.ts +47 -0
- package/dist/components/CmsComponent.d.ts.map +1 -1
- package/dist/components/CmsComponent.js +7 -0
- package/dist/components/CmsComponent.js.map +1 -1
- package/dist/components/CmsContent.d.ts +62 -0
- package/dist/components/CmsContent.d.ts.map +1 -1
- package/dist/components/CmsContent.js +53 -0
- package/dist/components/CmsContent.js.map +1 -1
- package/dist/components/CmsConversionErrors.js +2 -0
- package/dist/components/CmsConversionErrors.js.map +1 -1
- package/dist/components/CmsEmbeddedContent.d.ts +3 -0
- package/dist/components/CmsEmbeddedContent.d.ts.map +1 -1
- package/dist/components/CmsEmbeddedContent.js +3 -0
- package/dist/components/CmsEmbeddedContent.js.map +1 -1
- package/dist/components/CmsExternalComponent.d.ts +44 -0
- package/dist/components/CmsExternalComponent.d.ts.map +1 -1
- package/dist/components/CmsExternalComponent.js +7 -0
- package/dist/components/CmsExternalComponent.js.map +1 -1
- package/dist/components/ImageKitClientVideo.js +1 -0
- package/dist/components/ImageKitClientVideo.js.map +1 -1
- package/dist/components/SvgComponent.js +3 -1
- package/dist/components/SvgComponent.js.map +1 -1
- package/dist/components/VisualComponent.d.ts +47 -0
- package/dist/components/VisualComponent.d.ts.map +1 -1
- package/dist/components/VisualComponent.js +47 -0
- package/dist/components/VisualComponent.js.map +1 -1
- package/dist/elements/TrackedLink.d.ts +8 -0
- package/dist/elements/TrackedLink.d.ts.map +1 -1
- package/dist/elements/TrackedLink.js +13 -0
- package/dist/elements/TrackedLink.js.map +1 -1
- package/dist/framework/BackgroundMedia.js +5 -1
- package/dist/framework/BackgroundMedia.js.map +1 -1
- package/dist/framework/ComponentErrorIndicator.js +7 -4
- package/dist/framework/ComponentErrorIndicator.js.map +1 -1
- package/dist/framework/componentErrors.d.ts +8 -0
- package/dist/framework/componentErrors.d.ts.map +1 -1
- package/dist/framework/componentErrors.js +10 -0
- package/dist/framework/componentErrors.js.map +1 -1
- package/dist/hooks/useClickTracking.d.ts +39 -0
- package/dist/hooks/useClickTracking.d.ts.map +1 -1
- package/dist/hooks/useClickTracking.js +29 -0
- package/dist/hooks/useClickTracking.js.map +1 -1
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -1
- package/dist/rtf/rtf.d.ts +41 -0
- package/dist/rtf/rtf.d.ts.map +1 -1
- package/dist/rtf/rtf.js +36 -0
- package/dist/rtf/rtf.js.map +1 -1
- package/dist/utils/UnsupportedWarning.d.ts +23 -0
- package/dist/utils/UnsupportedWarning.d.ts.map +1 -1
- package/dist/utils/UnsupportedWarning.js +24 -0
- package/dist/utils/UnsupportedWarning.js.map +1 -1
- package/dist/utils/UnusedChecker.d.ts +39 -0
- package/dist/utils/UnusedChecker.d.ts.map +1 -1
- package/dist/utils/UnusedChecker.js +47 -3
- package/dist/utils/UnusedChecker.js.map +1 -1
- package/dist/utils/buildPageMetadata.d.ts +45 -0
- package/dist/utils/buildPageMetadata.d.ts.map +1 -1
- package/dist/utils/buildPageMetadata.js +37 -0
- package/dist/utils/buildPageMetadata.js.map +1 -1
- package/dist/utils/cn.d.ts +26 -0
- package/dist/utils/cn.d.ts.map +1 -1
- package/dist/utils/cn.js +26 -0
- package/dist/utils/cn.js.map +1 -1
- package/dist/utils/componentUtils.d.ts +121 -0
- package/dist/utils/componentUtils.d.ts.map +1 -1
- package/dist/utils/componentUtils.js +80 -0
- package/dist/utils/componentUtils.js.map +1 -1
- package/dist/utils/convertText.js +10 -2
- package/dist/utils/convertText.js.map +1 -1
- package/dist/utils/errorHandling.d.ts +27 -0
- package/dist/utils/errorHandling.d.ts.map +1 -1
- package/dist/utils/errorHandling.js +33 -0
- package/dist/utils/errorHandling.js.map +1 -1
- package/dist/utils/previewUtils.js +2 -0
- package/dist/utils/previewUtils.js.map +1 -1
- package/package.json +17 -4
package/README.md
CHANGED
|
@@ -323,20 +323,39 @@ const previewConfig = mergeCmsRendererConfig(
|
|
|
323
323
|
);
|
|
324
324
|
```
|
|
325
325
|
|
|
326
|
-
## API
|
|
327
|
-
|
|
328
|
-
###
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
-
|
|
332
|
-
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
-
|
|
326
|
+
## API Reference
|
|
327
|
+
|
|
328
|
+
### Main Exports
|
|
329
|
+
|
|
330
|
+
#### Components
|
|
331
|
+
- **`CmsContent`** - Main component for rendering CMS content with automatic component mapping
|
|
332
|
+
- **`CmsComponent`** - Renders individual CMS components with type-based routing
|
|
333
|
+
- **`CmsCollection`** - Renders CMS collections (arrays of components)
|
|
334
|
+
- **`Visual`** - Optimized image/video/animation component with Next.js Image integration
|
|
335
|
+
- **`RTF`** - Renders Contentful rich text with support for embedded entries and assets
|
|
336
|
+
- **`UnusedChecker`** - Development utility to detect unused CMS content types
|
|
337
|
+
|
|
338
|
+
#### Hooks
|
|
339
|
+
- **`useAnalytics`** - Hook for accessing analytics functions (trackEvent, trackPage, trackClick)
|
|
340
|
+
- **`useClickTracking`** - Hook for tracking click events with analytics
|
|
341
|
+
- **`useDocumentVisible`** - Hook for tracking document visibility
|
|
342
|
+
|
|
343
|
+
#### Utilities
|
|
344
|
+
- **`buildPageMetadata`** - Generates Next.js metadata object from CMS page model
|
|
345
|
+
- **`handleCmsError`** - Error handling utility for CMS operations
|
|
346
|
+
- **`extractComponentInfo`** - Extract specific component information fields
|
|
347
|
+
- **`extractCollectionInfo`** - Extract specific collection information fields
|
|
348
|
+
- **`extractPageContext`** - Extract specific page context fields
|
|
349
|
+
- **`cn`** - Utility function for merging Tailwind CSS classes
|
|
350
|
+
|
|
351
|
+
#### Types
|
|
352
|
+
- **`CmsRendererConfig`** - Complete renderer configuration type
|
|
353
|
+
- **`ComponentRenderer<T>`** - Type for component renderer functions
|
|
354
|
+
- **`CollectionRenderer<T>`** - Type for collection renderer functions
|
|
355
|
+
- **`ComponentConfig<T>`** - Type-safe component configuration
|
|
356
|
+
- **`CollectionConfig<T>`** - Type-safe collection configuration
|
|
357
|
+
|
|
358
|
+
For detailed JSDoc documentation on all exports, see the TypeScript declaration files (`.d.ts`) in the package.
|
|
340
359
|
|
|
341
360
|
## Advanced Usage
|
|
342
361
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** biome-ignore-all lint/suspicious/noExplicitAny: Any is allowed */
|
|
1
2
|
import type { IContentContext } from '@se-studio/core-data-types';
|
|
2
3
|
import type { React } from 'next/dist/server/route-modules/app-page/vendored/rsc/entrypoints';
|
|
3
4
|
import type { CollectionMap, CollectionRenderer, EmbeddedCollectionMap } from './components/CmsCollection';
|
|
@@ -12,20 +13,141 @@ export type CmsRendererTypes = {
|
|
|
12
13
|
ExternaComponentNameType: string;
|
|
13
14
|
ExternalComponentType: any;
|
|
14
15
|
};
|
|
16
|
+
/**
|
|
17
|
+
* Configuration object that bundles all CMS renderer maps and display options.
|
|
18
|
+
* Create this once at the project level and pass it to CmsContent.
|
|
19
|
+
*
|
|
20
|
+
* This provides a clean, extensible API for configuring how CMS content is rendered,
|
|
21
|
+
* making it easy to add new renderer types without breaking existing code.
|
|
22
|
+
*
|
|
23
|
+
* @example Basic configuration
|
|
24
|
+
* ```tsx
|
|
25
|
+
* const rendererConfig = createCmsRendererConfig<MyProjectConfig>({
|
|
26
|
+
* componentMap: {
|
|
27
|
+
* "Hero": HeroComponent,
|
|
28
|
+
* "CTA": CTAComponent,
|
|
29
|
+
* "Content Block": ContentBlock,
|
|
30
|
+
* },
|
|
31
|
+
* collectionMap: {
|
|
32
|
+
* "FAQs": FAQCollection,
|
|
33
|
+
* "Related Articles": RelatedArticles,
|
|
34
|
+
* },
|
|
35
|
+
* showUnknownTypeErrors: process.env.NODE_ENV === 'development',
|
|
36
|
+
* });
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @example With all renderer types
|
|
40
|
+
* ```tsx
|
|
41
|
+
* const rendererConfig = createCmsRendererConfig<MyProjectConfig>({
|
|
42
|
+
* componentMap: { ... },
|
|
43
|
+
* collectionMap: { ... },
|
|
44
|
+
* externalComponentMap: {
|
|
45
|
+
* "Contact Form": ContactFormRenderer,
|
|
46
|
+
* "Newsletter": NewsletterRenderer,
|
|
47
|
+
* },
|
|
48
|
+
* visualComponentRenderer: VisualRenderer,
|
|
49
|
+
* internalLinkRenderer: InternalLinkRenderer,
|
|
50
|
+
* showUnknownTypeErrors: true,
|
|
51
|
+
* showRenderErrors: true,
|
|
52
|
+
* });
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
15
55
|
export interface CmsRendererConfig<TConfig extends CmsRendererTypes = CmsRendererTypes> {
|
|
56
|
+
/**
|
|
57
|
+
* Map of component types to their renderers.
|
|
58
|
+
* Each key should match a ComponentType from your CMS configuration.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```tsx
|
|
62
|
+
* componentMap: {
|
|
63
|
+
* "Hero": HeroComponent,
|
|
64
|
+
* "CTA": CTAComponent,
|
|
65
|
+
* }
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
16
68
|
componentMap: ComponentMap<TConfig['ComponentNameType'], TConfig['ComponentType']>;
|
|
17
69
|
embeddedComponentMap: EmbeddedComponentMap<TConfig['ComponentNameType'], TConfig['ComponentType']>;
|
|
70
|
+
/**
|
|
71
|
+
* Map of collection types to their renderers.
|
|
72
|
+
* Each key should match a CollectionType from your CMS configuration.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```tsx
|
|
76
|
+
* collectionMap: {
|
|
77
|
+
* "FAQs": FAQCollection,
|
|
78
|
+
* "Related Articles": RelatedArticles,
|
|
79
|
+
* }
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
18
82
|
collectionMap: CollectionMap<TConfig['CollectionNameType'], TConfig['CollectionType']>;
|
|
19
83
|
embeddedCollectionMap: EmbeddedCollectionMap<TConfig['CollectionNameType'], TConfig['CollectionType']>;
|
|
84
|
+
/**
|
|
85
|
+
* Map of external component types to their renderers (optional).
|
|
86
|
+
* Use this for third-party integrations, forms, widgets, etc.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```tsx
|
|
90
|
+
* externalComponentMap: {
|
|
91
|
+
* "Contact Form": ContactFormRenderer,
|
|
92
|
+
* "Newsletter": NewsletterRenderer,
|
|
93
|
+
* }
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
20
96
|
externalComponentMap: ExternalComponentMap<TConfig['ExternaComponentNameType'], TConfig['ExternalComponentType']>;
|
|
21
97
|
embeddedExternalComponentMap: EmbeddedExternalComponentMap<TConfig['ExternaComponentNameType'], TConfig['ExternalComponentType']>;
|
|
98
|
+
/**
|
|
99
|
+
* Renderer for Visual content types (optional).
|
|
100
|
+
* Use this to define how images, videos, and other visual assets are rendered.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```tsx
|
|
104
|
+
* visualComponentRenderer: ({ information, contentContext }) => (
|
|
105
|
+
* <VisualComponent visual={information} />
|
|
106
|
+
* )
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
22
109
|
visualComponentRenderer: VisualComponentRenderer;
|
|
110
|
+
/**
|
|
111
|
+
* Renderer for Internal Link content types (optional).
|
|
112
|
+
* Use this to define how internal navigation links are rendered.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```tsx
|
|
116
|
+
* internalLinkRenderer: ({ information }) => (
|
|
117
|
+
* <Link href={information.href}>{information.text}</Link>
|
|
118
|
+
* )
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
23
121
|
internalLinkRenderer: InternalLinkRenderer;
|
|
122
|
+
/**
|
|
123
|
+
* Map of custom content types to their renderers (optional).
|
|
124
|
+
* Use this for project-specific content types that extend the base CMS content model.
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```tsx
|
|
128
|
+
* customContentMap: {
|
|
129
|
+
* "pricingPlan": PricingPlanRenderer,
|
|
130
|
+
* "testimonial": TestimonialRenderer,
|
|
131
|
+
* }
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
24
134
|
customContentMap?: Partial<Record<string, React.FC<{
|
|
25
135
|
information: any;
|
|
26
136
|
contentContext: IContentContext;
|
|
27
137
|
}>>>;
|
|
138
|
+
/**
|
|
139
|
+
* Show error panels for unknown content types in development mode (default: false).
|
|
140
|
+
* When true, displays a visual warning when a component/collection type is not mapped.
|
|
141
|
+
*
|
|
142
|
+
* Recommended: Set to `process.env.NODE_ENV === 'development'`
|
|
143
|
+
*/
|
|
28
144
|
showUnknownTypeErrors: boolean;
|
|
145
|
+
/**
|
|
146
|
+
* Show error panels for rendering errors (default: false).
|
|
147
|
+
* When true, displays error details when a component throws during rendering.
|
|
148
|
+
*
|
|
149
|
+
* Recommended: Set to `process.env.NODE_ENV === 'development'`
|
|
150
|
+
*/
|
|
29
151
|
showRenderErrors: boolean;
|
|
30
152
|
defaultComponentRenderer: ComponentRenderer<any>;
|
|
31
153
|
defaultCollectionRenderer: CollectionRenderer<any>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CmsRendererConfig.d.ts","sourceRoot":"","sources":["../src/CmsRendererConfig.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CmsRendererConfig.d.ts","sourceRoot":"","sources":["../src/CmsRendererConfig.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kEAAkE,CAAC;AAC9F,OAAO,KAAK,EACV,aAAa,EACb,kBAAkB,EAClB,qBAAqB,EACtB,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EACV,YAAY,EACZ,iBAAiB,EACjB,oBAAoB,EACrB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAC7F,OAAO,KAAK,EACV,4BAA4B,EAC5B,oBAAoB,EACrB,MAAM,mCAAmC,CAAC;AAE3C,MAAM,MAAM,gBAAgB,GAAG;IAC7B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,GAAG,CAAC;IACnB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,GAAG,CAAC;IACpB,wBAAwB,EAAE,MAAM,CAAC;IACjC,qBAAqB,EAAE,GAAG,CAAC;CAC5B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,MAAM,WAAW,iBAAiB,CAAC,OAAO,SAAS,gBAAgB,GAAG,gBAAgB;IACpF;;;;;;;;;;;OAWG;IACH,YAAY,EAAE,YAAY,CAAC,OAAO,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC;IAEnF,oBAAoB,EAAE,oBAAoB,CACxC,OAAO,CAAC,mBAAmB,CAAC,EAC5B,OAAO,CAAC,eAAe,CAAC,CACzB,CAAC;IAEF;;;;;;;;;;;OAWG;IACH,aAAa,EAAE,aAAa,CAAC,OAAO,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACvF,qBAAqB,EAAE,qBAAqB,CAC1C,OAAO,CAAC,oBAAoB,CAAC,EAC7B,OAAO,CAAC,gBAAgB,CAAC,CAC1B,CAAC;IAEF;;;;;;;;;;;OAWG;IACH,oBAAoB,EAAE,oBAAoB,CACxC,OAAO,CAAC,0BAA0B,CAAC,EACnC,OAAO,CAAC,uBAAuB,CAAC,CACjC,CAAC;IACF,4BAA4B,EAAE,4BAA4B,CACxD,OAAO,CAAC,0BAA0B,CAAC,EACnC,OAAO,CAAC,uBAAuB,CAAC,CACjC,CAAC;IAEF;;;;;;;;;;OAUG;IACH,uBAAuB,EAAE,uBAAuB,CAAC;IAEjD;;;;;;;;;;OAUG;IACH,oBAAoB,EAAE,oBAAoB,CAAC;IAE3C;;;;;;;;;;;OAWG;IACH,gBAAgB,CAAC,EAAE,OAAO,CACxB,MAAM,CACJ,MAAM,EACN,KAAK,CAAC,EAAE,CAAC;QACP,WAAW,EAAE,GAAG,CAAC;QACjB,cAAc,EAAE,eAAe,CAAC;KACjC,CAAC,CACH,CACF,CAAC;IAEF;;;;;OAKG;IACH,qBAAqB,EAAE,OAAO,CAAC;IAE/B;;;;;OAKG;IACH,gBAAgB,EAAE,OAAO,CAAC;IAE1B,wBAAwB,EAAE,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACjD,yBAAyB,EAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC;CACpD"}
|
|
@@ -4,6 +4,13 @@ export interface AnalyticsProviderProps {
|
|
|
4
4
|
adapter: AnalyticsAdapter;
|
|
5
5
|
children: React.ReactNode;
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* Provider component that makes analytics adapter available to child components
|
|
9
|
+
*/
|
|
7
10
|
export declare function AnalyticsProvider({ adapter, children }: AnalyticsProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
/**
|
|
12
|
+
* Hook to access the analytics adapter from context
|
|
13
|
+
* @throws Error if used outside of AnalyticsProvider
|
|
14
|
+
*/
|
|
8
15
|
export declare function useAnalyticsContext(): AnalyticsAdapter;
|
|
9
16
|
//# sourceMappingURL=AnalyticsProvider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnalyticsProvider.d.ts","sourceRoot":"","sources":["../../src/analytics/AnalyticsProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAIhD,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,gBAAgB,CAAC;IAC1B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;
|
|
1
|
+
{"version":3,"file":"AnalyticsProvider.d.ts","sourceRoot":"","sources":["../../src/analytics/AnalyticsProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAIhD,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,gBAAgB,CAAC;IAC1B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,sBAAsB,2CAE9E;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,gBAAgB,CAMtD"}
|
|
@@ -2,9 +2,16 @@
|
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { createContext, useContext } from 'react';
|
|
4
4
|
const AnalyticsContext = createContext(null);
|
|
5
|
+
/**
|
|
6
|
+
* Provider component that makes analytics adapter available to child components
|
|
7
|
+
*/
|
|
5
8
|
export function AnalyticsProvider({ adapter, children }) {
|
|
6
9
|
return _jsx(AnalyticsContext.Provider, { value: adapter, children: children });
|
|
7
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Hook to access the analytics adapter from context
|
|
13
|
+
* @throws Error if used outside of AnalyticsProvider
|
|
14
|
+
*/
|
|
8
15
|
export function useAnalyticsContext() {
|
|
9
16
|
const adapter = useContext(AnalyticsContext);
|
|
10
17
|
if (!adapter) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnalyticsProvider.js","sourceRoot":"","sources":["../../src/analytics/AnalyticsProvider.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAGb,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAGlD,MAAM,gBAAgB,GAAG,aAAa,CAA0B,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"AnalyticsProvider.js","sourceRoot":"","sources":["../../src/analytics/AnalyticsProvider.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAGb,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAGlD,MAAM,gBAAgB,GAAG,aAAa,CAA0B,IAAI,CAAC,CAAC;AAOtE;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAAE,OAAO,EAAE,QAAQ,EAA0B;IAC7E,OAAO,KAAC,gBAAgB,CAAC,QAAQ,IAAC,KAAK,EAAE,OAAO,YAAG,QAAQ,GAA6B,CAAC;AAC3F,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB;IACjC,MAAM,OAAO,GAAG,UAAU,CAAC,gBAAgB,CAAC,CAAC;IAC7C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;IAClF,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { AnalyticsAdapter, ClickTrackingProperties, PageTrackingProperties } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Console adapter used as the default/example implementation.
|
|
4
|
+
* Customer projects should provide their own adapter that satisfies `AnalyticsAdapter`.
|
|
5
|
+
*/
|
|
2
6
|
export declare class ConsoleAnalyticsAdapter implements AnalyticsAdapter {
|
|
3
7
|
private log;
|
|
4
8
|
trackEvent(event: string, properties: Record<string, unknown>): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConsoleAnalyticsAdapter.d.ts","sourceRoot":"","sources":["../../../src/analytics/adapters/ConsoleAnalyticsAdapter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"ConsoleAnalyticsAdapter.d.ts","sourceRoot":"","sources":["../../../src/analytics/adapters/ConsoleAnalyticsAdapter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAElG;;;GAGG;AACH,qBAAa,uBAAwB,YAAW,gBAAgB;IAC9D,OAAO,CAAC,GAAG;IAKX,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIpE,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,sBAAsB,GAAG,IAAI;IAIhE,UAAU,CAAC,UAAU,EAAE,uBAAuB,GAAG,IAAI;CAGtD"}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
'use client';
|
|
2
|
+
/**
|
|
3
|
+
* Console adapter used as the default/example implementation.
|
|
4
|
+
* Customer projects should provide their own adapter that satisfies `AnalyticsAdapter`.
|
|
5
|
+
*/
|
|
2
6
|
export class ConsoleAnalyticsAdapter {
|
|
3
7
|
log(...args) {
|
|
8
|
+
// eslint-disable-next-line no-console -- intentional logging adapter
|
|
4
9
|
console.log('[Analytics]', ...args);
|
|
5
10
|
}
|
|
6
11
|
trackEvent(event, properties) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConsoleAnalyticsAdapter.js","sourceRoot":"","sources":["../../../src/analytics/adapters/ConsoleAnalyticsAdapter.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"ConsoleAnalyticsAdapter.js","sourceRoot":"","sources":["../../../src/analytics/adapters/ConsoleAnalyticsAdapter.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAIb;;;GAGG;AACH,MAAM,OAAO,uBAAuB;IAC1B,GAAG,CAAC,GAAG,IAAe;QAC5B,qEAAqE;QACrE,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,GAAG,IAAI,CAAC,CAAC;IACtC,CAAC;IAED,UAAU,CAAC,KAAa,EAAE,UAAmC;QAC3D,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;IACvC,CAAC;IAED,SAAS,CAAC,GAAW,EAAE,UAAkC;QACvD,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,GAAG,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED,UAAU,CAAC,UAAmC;QAC5C,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAChC,CAAC;CACF"}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import type { IAnalyticsContext } from '@se-studio/core-data-types';
|
|
2
|
+
/**
|
|
3
|
+
* Properties for tracking a click event
|
|
4
|
+
*/
|
|
2
5
|
export interface ClickTrackingProperties extends IAnalyticsContext {
|
|
3
6
|
componentType: string;
|
|
4
7
|
url: string;
|
|
@@ -6,13 +9,33 @@ export interface ClickTrackingProperties extends IAnalyticsContext {
|
|
|
6
9
|
linkText: string;
|
|
7
10
|
location?: string;
|
|
8
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Properties for tracking a page view
|
|
14
|
+
*/
|
|
9
15
|
export interface PageTrackingProperties extends IAnalyticsContext {
|
|
10
16
|
url: string;
|
|
11
17
|
pathname: string;
|
|
12
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Interface that analytics adapters must implement
|
|
21
|
+
*/
|
|
13
22
|
export interface AnalyticsAdapter {
|
|
23
|
+
/**
|
|
24
|
+
* Track a custom event
|
|
25
|
+
* @param event - Event name
|
|
26
|
+
* @param properties - Event properties
|
|
27
|
+
*/
|
|
14
28
|
trackEvent(event: string, properties: Record<string, unknown>): void;
|
|
29
|
+
/**
|
|
30
|
+
* Track a page view
|
|
31
|
+
* @param url - Full URL of the page
|
|
32
|
+
* @param properties - Page properties
|
|
33
|
+
*/
|
|
15
34
|
trackPage(url: string, properties: PageTrackingProperties): void;
|
|
35
|
+
/**
|
|
36
|
+
* Track a component click
|
|
37
|
+
* @param properties - Click tracking properties
|
|
38
|
+
*/
|
|
16
39
|
trackClick(properties: ClickTrackingProperties): void;
|
|
17
40
|
}
|
|
18
41
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/analytics/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/analytics/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAEpE;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,iBAAiB;IAChE,aAAa,EAAE,MAAM,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAuB,SAAQ,iBAAiB;IAC/D,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAErE;;;;OAIG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,sBAAsB,GAAG,IAAI,CAAC;IAEjE;;;OAGG;IACH,UAAU,CAAC,UAAU,EAAE,uBAAuB,GAAG,IAAI,CAAC;CACvD"}
|
|
@@ -1,4 +1,39 @@
|
|
|
1
1
|
import type { IAnalyticsContext } from '@se-studio/core-data-types';
|
|
2
|
+
/**
|
|
3
|
+
* Hook for accessing analytics functions.
|
|
4
|
+
*
|
|
5
|
+
* Provides a clean API for tracking events, pages, and clicks. Must be used
|
|
6
|
+
* within an AnalyticsProvider context.
|
|
7
|
+
*
|
|
8
|
+
* @returns Object with tracking functions:
|
|
9
|
+
* - `trackEvent` - Track custom events
|
|
10
|
+
* - `trackPage` - Track page views
|
|
11
|
+
* - `trackClick` - Track click interactions
|
|
12
|
+
*
|
|
13
|
+
* @throws {Error} If used outside of AnalyticsProvider
|
|
14
|
+
*
|
|
15
|
+
* @example Basic usage
|
|
16
|
+
* ```tsx
|
|
17
|
+
* import { useAnalytics } from '@se-studio/core-ui';
|
|
18
|
+
*
|
|
19
|
+
* function MyComponent() {
|
|
20
|
+
* const { trackClick, trackPage } = useAnalytics();
|
|
21
|
+
*
|
|
22
|
+
* useEffect(() => {
|
|
23
|
+
* trackPage(window.location.href, window.location.pathname, {
|
|
24
|
+
* page_title: 'Home',
|
|
25
|
+
* page_type: 'landing',
|
|
26
|
+
* });
|
|
27
|
+
* }, []);
|
|
28
|
+
*
|
|
29
|
+
* return (
|
|
30
|
+
* <button onClick={() => trackClick('Button', 'Sign up', { page_title: 'Home' })}>
|
|
31
|
+
* Sign up
|
|
32
|
+
* </button>
|
|
33
|
+
* );
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
2
37
|
export declare function useAnalytics(): {
|
|
3
38
|
trackEvent: (event: string, properties: Record<string, unknown>) => void;
|
|
4
39
|
trackPage: (url: string, pathname: string, analyticsContext: IAnalyticsContext) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAnalytics.d.ts","sourceRoot":"","sources":["../../src/analytics/useAnalytics.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"useAnalytics.d.ts","sourceRoot":"","sources":["../../src/analytics/useAnalytics.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAKpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,YAAY;wBAIhB,MAAM,cAAc,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;qBAO7C,MAAM,YAAY,MAAM,oBAAoB,iBAAiB;gCAalD,MAAM,YACX,MAAM,oBACE,iBAAiB,YACzB;QACR,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB;EAqBN"}
|
|
@@ -1,6 +1,41 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { useCallback } from 'react';
|
|
3
3
|
import { useAnalyticsContext } from './AnalyticsProvider';
|
|
4
|
+
/**
|
|
5
|
+
* Hook for accessing analytics functions.
|
|
6
|
+
*
|
|
7
|
+
* Provides a clean API for tracking events, pages, and clicks. Must be used
|
|
8
|
+
* within an AnalyticsProvider context.
|
|
9
|
+
*
|
|
10
|
+
* @returns Object with tracking functions:
|
|
11
|
+
* - `trackEvent` - Track custom events
|
|
12
|
+
* - `trackPage` - Track page views
|
|
13
|
+
* - `trackClick` - Track click interactions
|
|
14
|
+
*
|
|
15
|
+
* @throws {Error} If used outside of AnalyticsProvider
|
|
16
|
+
*
|
|
17
|
+
* @example Basic usage
|
|
18
|
+
* ```tsx
|
|
19
|
+
* import { useAnalytics } from '@se-studio/core-ui';
|
|
20
|
+
*
|
|
21
|
+
* function MyComponent() {
|
|
22
|
+
* const { trackClick, trackPage } = useAnalytics();
|
|
23
|
+
*
|
|
24
|
+
* useEffect(() => {
|
|
25
|
+
* trackPage(window.location.href, window.location.pathname, {
|
|
26
|
+
* page_title: 'Home',
|
|
27
|
+
* page_type: 'landing',
|
|
28
|
+
* });
|
|
29
|
+
* }, []);
|
|
30
|
+
*
|
|
31
|
+
* return (
|
|
32
|
+
* <button onClick={() => trackClick('Button', 'Sign up', { page_title: 'Home' })}>
|
|
33
|
+
* Sign up
|
|
34
|
+
* </button>
|
|
35
|
+
* );
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
4
39
|
export function useAnalytics() {
|
|
5
40
|
const adapter = useAnalyticsContext();
|
|
6
41
|
const trackEvent = useCallback((event, properties) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAnalytics.js","sourceRoot":"","sources":["../../src/analytics/useAnalytics.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAGb,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"useAnalytics.js","sourceRoot":"","sources":["../../src/analytics/useAnalytics.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAGb,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAG1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,OAAO,GAAG,mBAAmB,EAAE,CAAC;IAEtC,MAAM,UAAU,GAAG,WAAW,CAC5B,CAAC,KAAa,EAAE,UAAmC,EAAE,EAAE;QACrD,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IACxC,CAAC,EACD,CAAC,OAAO,CAAC,CACV,CAAC;IAEF,MAAM,SAAS,GAAG,WAAW,CAC3B,CAAC,GAAW,EAAE,QAAgB,EAAE,gBAAmC,EAAE,EAAE;QACrE,MAAM,UAAU,GAA2B;YACzC,GAAG;YACH,QAAQ;YACR,GAAG,gBAAgB;SACpB,CAAC;QACF,OAAO,CAAC,SAAS,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IACrC,CAAC,EACD,CAAC,OAAO,CAAC,CACV,CAAC;IAEF,MAAM,UAAU,GAAG,WAAW,CAC5B,CACE,aAAqB,EACrB,QAAgB,EAChB,gBAAmC,EACnC,OAGC,EACD,EAAE;QACF,MAAM,GAAG,GAAG,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QACtE,MAAM,UAAU,GAA4B;YAC1C,aAAa;YACb,GAAG;YACH,QAAQ;YACR,QAAQ,EAAE,OAAO,EAAE,QAAQ;YAC3B,SAAS,EAAE,OAAO,EAAE,SAAS;YAC7B,GAAG,gBAAgB;SACpB,CAAC;QACF,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IACjC,CAAC,EACD,CAAC,OAAO,CAAC,CACV,CAAC;IAEF,OAAO;QACL,UAAU;QACV,SAAS;QACT,UAAU;KACX,CAAC;AACJ,CAAC"}
|
|
@@ -3,13 +3,17 @@ import { usePathname } from 'next/navigation';
|
|
|
3
3
|
import { useEffect } from 'react';
|
|
4
4
|
import { useDocumentVisible } from '../hooks/useDocumentVisible';
|
|
5
5
|
const _observers = new Map();
|
|
6
|
+
// Maps to store element metadata for scroll progress calculation
|
|
6
7
|
const _sectionHeights = new Map();
|
|
7
8
|
const _sectionThresholds = new Map();
|
|
9
|
+
// Dense thresholds for IntersectionObserver (0, 0.05, 0.1, ... 1.0)
|
|
8
10
|
const SECTION_THRESHOLDS = Array.from({ length: 21 }, (_, i) => i * 0.05);
|
|
11
|
+
// Tracking for tall elements that need scroll listener
|
|
9
12
|
const _intersectingTallElements = new Set();
|
|
10
13
|
let _scrollRAFId = null;
|
|
11
14
|
let _scrollListenerAttached = false;
|
|
12
15
|
const isDevelopment = process.env.NODE_ENV === 'development';
|
|
16
|
+
// Module-level debug flag, set by ClientMonitor component
|
|
13
17
|
let _debugEnabled = false;
|
|
14
18
|
function shouldDebug(element) {
|
|
15
19
|
if (!isDevelopment)
|
|
@@ -20,6 +24,7 @@ function shouldDebug(element) {
|
|
|
20
24
|
return true;
|
|
21
25
|
return false;
|
|
22
26
|
}
|
|
27
|
+
// Updates scroll progress for a single element (used by scroll handler)
|
|
23
28
|
function updateScrollProgress(element) {
|
|
24
29
|
const elementHeight = _sectionHeights.get(element);
|
|
25
30
|
const threshold = _sectionThresholds.get(element);
|
|
@@ -42,6 +47,7 @@ function updateScrollProgress(element) {
|
|
|
42
47
|
element.dataset.debugIsTallElement = 'true';
|
|
43
48
|
}
|
|
44
49
|
}
|
|
50
|
+
// RAF-throttled scroll handler for tall elements
|
|
45
51
|
function handleScroll() {
|
|
46
52
|
if (_scrollRAFId !== null)
|
|
47
53
|
return;
|
|
@@ -52,6 +58,7 @@ function handleScroll() {
|
|
|
52
58
|
}
|
|
53
59
|
});
|
|
54
60
|
}
|
|
61
|
+
// Attach scroll listener if not already attached
|
|
55
62
|
function attachScrollListener() {
|
|
56
63
|
if (!_scrollListenerAttached) {
|
|
57
64
|
window.addEventListener('scroll', handleScroll, { passive: true });
|
|
@@ -61,6 +68,7 @@ function attachScrollListener() {
|
|
|
61
68
|
}
|
|
62
69
|
}
|
|
63
70
|
}
|
|
71
|
+
// Detach scroll listener if no tall elements are being tracked
|
|
64
72
|
function detachScrollListener() {
|
|
65
73
|
if (_scrollListenerAttached && _intersectingTallElements.size === 0) {
|
|
66
74
|
window.removeEventListener('scroll', handleScroll);
|
|
@@ -90,21 +98,26 @@ function getElementThreshold(element, defaultThreshold) {
|
|
|
90
98
|
function handleVideo(video, isIntersecting) {
|
|
91
99
|
if (!isIntersecting) {
|
|
92
100
|
if (!video.paused) {
|
|
101
|
+
// console.log("pause video", video.src);
|
|
93
102
|
video.pause();
|
|
94
103
|
}
|
|
95
104
|
}
|
|
96
105
|
else if (video.paused) {
|
|
106
|
+
// console.log("play video", video.src);
|
|
97
107
|
video
|
|
98
108
|
.play()
|
|
99
109
|
.then(() => {
|
|
100
110
|
video.controls = false;
|
|
101
111
|
})
|
|
102
112
|
.catch(() => {
|
|
113
|
+
// console.log("failed to play", error);
|
|
114
|
+
// video.controls = true;
|
|
103
115
|
});
|
|
104
116
|
}
|
|
105
117
|
}
|
|
106
118
|
function handleAnimation(animation, isIntersecting) {
|
|
107
119
|
const currentState = animation.currentState;
|
|
120
|
+
// console.log('current state', currentState)
|
|
108
121
|
if (!isIntersecting) {
|
|
109
122
|
if (currentState === 'playing') {
|
|
110
123
|
animation.pause();
|
|
@@ -112,9 +125,11 @@ function handleAnimation(animation, isIntersecting) {
|
|
|
112
125
|
}
|
|
113
126
|
else {
|
|
114
127
|
if (currentState === 'paused') {
|
|
128
|
+
// console.log('play animation')
|
|
115
129
|
animation.play();
|
|
116
130
|
}
|
|
117
131
|
if (!currentState || currentState === 'loading') {
|
|
132
|
+
// console.log('set to autoplay')
|
|
118
133
|
if (animation.play) {
|
|
119
134
|
animation.play();
|
|
120
135
|
}
|
|
@@ -126,6 +141,7 @@ function handleAnimatedSection(section, isIntersecting, entry) {
|
|
|
126
141
|
const elementHeight = _sectionHeights.get(section);
|
|
127
142
|
const threshold = _sectionThresholds.get(section);
|
|
128
143
|
if (elementHeight === undefined || threshold === undefined) {
|
|
144
|
+
// Fallback to intersection-based behavior if height/threshold not available
|
|
129
145
|
section.dataset.visible = isIntersecting ? 'true' : 'false';
|
|
130
146
|
if (isIntersecting && !section.dataset.seen) {
|
|
131
147
|
section.dataset.seen = 'true';
|
|
@@ -143,15 +159,18 @@ function handleAnimatedSection(section, isIntersecting, entry) {
|
|
|
143
159
|
return;
|
|
144
160
|
}
|
|
145
161
|
const isTallElement = elementHeight > window.innerHeight;
|
|
162
|
+
// For tall elements, use scroll listener for continuous tracking
|
|
146
163
|
if (isTallElement) {
|
|
147
164
|
if (isIntersecting) {
|
|
148
165
|
_intersectingTallElements.add(section);
|
|
149
166
|
attachScrollListener();
|
|
167
|
+
// Immediately update scroll progress
|
|
150
168
|
updateScrollProgress(section);
|
|
151
169
|
}
|
|
152
170
|
else {
|
|
153
171
|
_intersectingTallElements.delete(section);
|
|
154
172
|
detachScrollListener();
|
|
173
|
+
// Mark as not visible when leaving viewport
|
|
155
174
|
section.dataset.visible = 'false';
|
|
156
175
|
}
|
|
157
176
|
if (shouldDebug(section)) {
|
|
@@ -161,6 +180,7 @@ function handleAnimatedSection(section, isIntersecting, entry) {
|
|
|
161
180
|
}
|
|
162
181
|
return;
|
|
163
182
|
}
|
|
183
|
+
// For normal-sized elements, IntersectionObserver provides enough granularity
|
|
164
184
|
const scrollProgress = (window.innerHeight - entry.boundingClientRect.top) / elementHeight;
|
|
165
185
|
const shouldTrigger = scrollProgress >= threshold;
|
|
166
186
|
section.dataset.visible = shouldTrigger ? 'true' : 'false';
|
|
@@ -181,6 +201,7 @@ function handleAnimatedSection(section, isIntersecting, entry) {
|
|
|
181
201
|
}
|
|
182
202
|
function intersectionHandler(entries) {
|
|
183
203
|
for (const entry of entries) {
|
|
204
|
+
// console.log("target", entry.target.localName, entry.target);
|
|
184
205
|
const target = entry.target;
|
|
185
206
|
switch (target.localName) {
|
|
186
207
|
case 'video':
|
|
@@ -232,6 +253,7 @@ function findAllVideos(defaultThreshold) {
|
|
|
232
253
|
observer.observe(video);
|
|
233
254
|
}
|
|
234
255
|
return () => {
|
|
256
|
+
// console.log("clear down video observers");
|
|
235
257
|
for (const [observer, videoList] of videoObservers) {
|
|
236
258
|
for (const video of videoList) {
|
|
237
259
|
observer.unobserve(video);
|
|
@@ -261,6 +283,7 @@ function findAllAnimations(defaultThreshold) {
|
|
|
261
283
|
observer.observe(animation);
|
|
262
284
|
}
|
|
263
285
|
return () => {
|
|
286
|
+
// console.log("clear down animation observers");
|
|
264
287
|
for (const [observer, animationList] of animationObservers) {
|
|
265
288
|
for (const animation of animationList) {
|
|
266
289
|
observer.unobserve(animation);
|
|
@@ -274,12 +297,15 @@ function findAllAnimatedSections(defaultThreshold) {
|
|
|
274
297
|
if (shouldDebug()) {
|
|
275
298
|
console.log(`[ClientMonitor] Found ${sections.length} animated section(s)`);
|
|
276
299
|
}
|
|
300
|
+
// Create a shared observer with dense thresholds for all sections
|
|
301
|
+
// This gives us callbacks at every 5% intersection change
|
|
277
302
|
const sectionObserver = new IntersectionObserver((entries) => {
|
|
278
303
|
for (const entry of entries) {
|
|
279
304
|
const element = entry.target;
|
|
280
305
|
handleAnimatedSection(element, entry.isIntersecting, entry);
|
|
281
306
|
}
|
|
282
307
|
}, { threshold: SECTION_THRESHOLDS });
|
|
308
|
+
// Set up ResizeObserver to track element heights
|
|
283
309
|
const resizeObserver = new ResizeObserver((entries) => {
|
|
284
310
|
for (const entry of entries) {
|
|
285
311
|
const element = entry.target;
|
|
@@ -289,25 +315,34 @@ function findAllAnimatedSections(defaultThreshold) {
|
|
|
289
315
|
for (const section of sections) {
|
|
290
316
|
const sectionElement = section;
|
|
291
317
|
const threshold = getElementThreshold(sectionElement, defaultThreshold);
|
|
318
|
+
// Store threshold for this element
|
|
292
319
|
_sectionThresholds.set(sectionElement, threshold);
|
|
320
|
+
// Get initial height and store it
|
|
293
321
|
const height = sectionElement.offsetHeight;
|
|
294
322
|
_sectionHeights.set(sectionElement, height);
|
|
323
|
+
// Observe element for size changes
|
|
295
324
|
resizeObserver.observe(sectionElement);
|
|
325
|
+
// Track element for cleanup
|
|
296
326
|
sectionElements.push(sectionElement);
|
|
297
327
|
if (shouldDebug(sectionElement)) {
|
|
298
328
|
sectionElement.setAttribute('data-monitor-threshold', threshold.toString());
|
|
299
329
|
sectionElement.setAttribute('data-monitor-observed', 'true');
|
|
300
330
|
}
|
|
331
|
+
// Observe with shared dense-threshold observer
|
|
301
332
|
sectionObserver.observe(sectionElement);
|
|
302
333
|
}
|
|
303
334
|
return () => {
|
|
335
|
+
// Clean up IntersectionObserver
|
|
304
336
|
sectionObserver.disconnect();
|
|
337
|
+
// Clean up ResizeObserver and maps
|
|
305
338
|
for (const sectionElement of sectionElements) {
|
|
306
339
|
resizeObserver.unobserve(sectionElement);
|
|
307
340
|
_sectionHeights.delete(sectionElement);
|
|
308
341
|
_sectionThresholds.delete(sectionElement);
|
|
342
|
+
// Remove from tall element tracking if present
|
|
309
343
|
_intersectingTallElements.delete(sectionElement);
|
|
310
344
|
}
|
|
345
|
+
// Clean up scroll listener
|
|
311
346
|
if (_scrollListenerAttached) {
|
|
312
347
|
window.removeEventListener('scroll', handleScroll);
|
|
313
348
|
_scrollListenerAttached = false;
|
|
@@ -332,6 +367,7 @@ function findAll(defaultThreshold) {
|
|
|
332
367
|
};
|
|
333
368
|
}
|
|
334
369
|
export const ClientMonitor = ({ defaultThreshold = 0.2, enableDebug = false, }) => {
|
|
370
|
+
// Set module-level flag on mount/update
|
|
335
371
|
_debugEnabled = enableDebug;
|
|
336
372
|
const isDocumentVisible = useDocumentVisible();
|
|
337
373
|
const pathname = usePathname();
|