@cshah18/sdk 4.8.0 → 4.10.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.
@@ -1,19 +1,137 @@
1
1
  import { CoBuyThemeOptions } from "../../core/types";
2
2
  /**
3
- * Merge global theme with optional widget-specific overrides
4
- * Priority: widgetTheme > globalTheme > defaults
3
+ * Merge global theme with widget-specific theme overrides
4
+ *
5
+ * Combines multiple theme objects with priority: widgetTheme > globalTheme > defaults.
6
+ * Validates all color and style values, falling back to defaults if invalid.
7
+ *
8
+ * @param {CoBuyThemeOptions} [globalTheme={}] - Global theme to apply to all widgets
9
+ * @param {string} [globalTheme.primaryColor] - Primary brand color (validated as CSS color)
10
+ * @param {string} [globalTheme.secondaryColor] - Secondary brand color
11
+ * @param {string} [globalTheme.textColor] - Text color for widget
12
+ * @param {string} [globalTheme.borderRadius] - Border radius for widget elements (CSS size value)
13
+ * @param {string} [globalTheme.fontFamily] - Font family for widget text
14
+ * @param {"none" | "fast" | "normal" | "slow"} [globalTheme.animationSpeed] - Animation speed
15
+ * @param {"none" | "subtle" | "smooth" | "bouncy"} [globalTheme.animationStyle] - Animation style
16
+ *
17
+ * @param {CoBuyThemeOptions} [widgetTheme={}] - Widget-specific theme overrides (takes priority over global)
18
+ * @param {string} [widgetTheme.primaryColor] - Override primary color
19
+ * @param {string} [widgetTheme.secondaryColor] - Override secondary color
20
+ * @param {string} [widgetTheme.textColor] - Override text color
21
+ * @param {string} [widgetTheme.borderRadius] - Override border radius
22
+ * @param {string} [widgetTheme.fontFamily] - Override font family
23
+ * @param {"none" | "fast" | "normal" | "slow"} [widgetTheme.animationSpeed] - Override animation speed
24
+ * @param {"none" | "subtle" | "smooth" | "bouncy"} [widgetTheme.animationStyle] - Override animation style
25
+ *
26
+ * @returns {Required<CoBuyThemeOptions>} Merged theme with all properties defined
27
+ *
28
+ * @description
29
+ * All theme values are validated:
30
+ * - Colors are checked against valid CSS color formats
31
+ * - Border radius is validated as a CSS size value
32
+ * - Font family is validated as a non-empty string
33
+ * - Animation speeds and styles are checked against allowed values
34
+ * - Invalid values are logged and replaced with defaults
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * // Merge global and widget themes
39
+ * const theme = mergeTheme(
40
+ * {
41
+ * primaryColor: '#4f46e5',
42
+ * fontFamily: 'Inter, sans-serif'
43
+ * },
44
+ * {
45
+ * primaryColor: '#ff0000' // Override primary color for this widget
46
+ * }
47
+ * );
48
+ * // Result: theme.primaryColor === '#ff0000'
49
+ *
50
+ * // With invalid color (falls back to default)
51
+ * const theme2 = mergeTheme(
52
+ * { primaryColor: 'notacolor' },
53
+ * {}
54
+ * );
55
+ * // Result: theme2.primaryColor === '#4f46e5' (default value)
56
+ * ```
5
57
  */
6
58
  export declare function mergeTheme(globalTheme?: CoBuyThemeOptions, widgetTheme?: CoBuyThemeOptions): Required<CoBuyThemeOptions>;
7
59
  /**
8
- * Apply theme to widget container using scoped CSS custom properties
9
- * This approach ensures:
10
- * 1. Styles are isolated to this widget instance
11
- * 2. No conflicts with merchant's global styles
12
- * 3. Easy runtime theme updates
13
- * 4. Browser handles invalid values gracefully
60
+ * Apply theme to widget container using CSS custom properties
61
+ *
62
+ * Sets scoped CSS variables on the container element to apply theme colors,
63
+ * sizing, fonts, and animations. This approach isolates styles to the widget
64
+ * instance and prevents conflicts with merchant's global styles.
65
+ *
66
+ * @param {HTMLElement} container - The DOM element to apply theme to
67
+ * @param {Required<CoBuyThemeOptions>} theme - The theme configuration to apply
68
+ * @param {string} theme.primaryColor - Primary brand color (applied to --cobuy-primary-color)
69
+ * @param {string} theme.secondaryColor - Secondary color (applied to --cobuy-secondary-color)
70
+ * @param {string} theme.textColor - Text color (applied to --cobuy-text-color)
71
+ * @param {string} theme.borderRadius - Border radius (applied to --cobuy-border-radius)
72
+ * @param {string} theme.fontFamily - Font family (applied to --cobuy-font-family)
73
+ * @param {AnimationSpeed} theme.animationSpeed - Animation speed for transitions
74
+ * @param {AnimationStyle} theme.animationStyle - Animation style/easing
75
+ *
76
+ * @returns {void}
77
+ *
78
+ * @description
79
+ * Sets the following CSS custom properties on the container:
80
+ * - `--cobuy-primary-color`: Primary brand color
81
+ * - `--cobuy-secondary-color`: Secondary color
82
+ * - `--cobuy-text-color`: Text color
83
+ * - `--cobuy-border-radius`: Border radius value
84
+ * - `--cobuy-font-family`: Font family stack
85
+ * - `--cobuy-animation-duration`: Duration in milliseconds
86
+ * - `--cobuy-animation-easing`: CSS easing function
87
+ * - `--cobuy-animation-transform`: CSS transform for animations
88
+ *
89
+ * @example
90
+ * ```typescript
91
+ * const container = document.getElementById('cobuy-widget');
92
+ * const theme = {
93
+ * primaryColor: '#4f46e5',
94
+ * secondaryColor: '#6366f1',
95
+ * textColor: '#111827',
96
+ * borderRadius: '8px',
97
+ * fontFamily: 'Inter, sans-serif',
98
+ * animationSpeed: 'normal',
99
+ * animationStyle: 'smooth'
100
+ * };
101
+ *
102
+ * applyTheme(container, theme);
103
+ * // Now all widget styles use the applied theme colors and animations
104
+ * ```
14
105
  */
15
106
  export declare function applyTheme(container: HTMLElement, theme: Required<CoBuyThemeOptions>): void;
16
107
  /**
17
- * Get the default theme (useful for testing and documentation)
108
+ * Get the default theme configuration
109
+ *
110
+ * Returns a copy of the default theme used when no custom theme is provided.
111
+ * Useful for documentation, testing, or as a baseline for customization.
112
+ *
113
+ * @returns {Required<CoBuyThemeOptions>} Default theme with all properties defined
114
+ *
115
+ * @description
116
+ * Default values:
117
+ * - Primary Color: #4f46e5 (Indigo-600)
118
+ * - Secondary Color: #6366f1 (Indigo-500)
119
+ * - Text Color: #111827 (Gray-900)
120
+ * - Border Radius: 8px
121
+ * - Font Family: Inter, system-ui, -apple-system, sans-serif
122
+ * - Animation Speed: normal (300ms)
123
+ * - Animation Style: subtle (fade only)
124
+ *
125
+ * @example
126
+ * ```typescript
127
+ * const defaults = getDefaultTheme();
128
+ * console.log(defaults.primaryColor); // #4f46e5
129
+ *
130
+ * // Use default as base and customize
131
+ * const customTheme = {
132
+ * ...getDefaultTheme(),
133
+ * primaryColor: '#ff0000'
134
+ * };
135
+ * ```
18
136
  */
19
137
  export declare function getDefaultTheme(): Required<CoBuyThemeOptions>;
@@ -5,17 +5,16 @@ import { AnalyticsClient } from "../../core/analytics";
5
5
  * WidgetRoot handles rendering of the CoBuy widget into a DOM container
6
6
  */
7
7
  export declare class WidgetRoot {
8
- private logger;
9
- private apiClient;
10
- private analyticsClient;
11
- private config;
12
- private events?;
8
+ private readonly logger;
9
+ private readonly apiClient;
10
+ private readonly analyticsClient;
11
+ private readonly config;
12
+ private readonly events?;
13
13
  private state;
14
14
  private retryCount;
15
- private readonly MAX_RETRIES;
16
15
  private currentProductId;
17
16
  private currentContainer;
18
- private debouncedCTAClick;
17
+ private readonly debouncedCTAClick;
19
18
  private currentGroupData;
20
19
  private groupFulfilled;
21
20
  private frozenReward;
@@ -31,13 +30,25 @@ export declare class WidgetRoot {
31
30
  private groupExpiryRefreshTriggered;
32
31
  private offlineRedemption;
33
32
  private offlineRedemptionModal;
33
+ private isRendering;
34
+ private renderPromise;
35
+ private liveRegionAnnouncer;
36
+ private lastRenderedProductId;
37
+ private lastRenderedContainer;
38
+ private renderDebounceTimer;
39
+ private pendingRenderOptions;
40
+ private readonly RENDER_DEBOUNCE_MS;
41
+ /**
42
+ * Get max retries from config (configurable via performance options)
43
+ */
44
+ private get MAX_RETRIES();
34
45
  constructor(config: InternalConfig, apiClient: ApiClient | null, analyticsClient?: AnalyticsClient | null);
35
46
  /** Subscribe once to backend socket events routed through the host page */
36
47
  private subscribeToSocketEvents;
37
48
  /** Handle backend fulfillment notifications */
38
- private handleGroupFulfilledEvent;
49
+ private readonly handleGroupFulfilledEvent;
39
50
  /** Handle realtime group creation/join events by refreshing group UI */
40
- private handleGroupUpdatedEvent;
51
+ private readonly handleGroupUpdatedEvent;
41
52
  /** Fetch latest group data and re-render containers */
42
53
  private refreshGroupDataFromRealtime;
43
54
  /** Update widget and any external containers after realtime refresh */
@@ -59,10 +70,45 @@ export declare class WidgetRoot {
59
70
  private getGroupListModal;
60
71
  /**
61
72
  * Render the widget into the specified container
73
+ *
74
+ * Asynchronous method that renders the collaborative buying widget.
75
+ * Automatically fetches product data, groups, and set up event listeners.
76
+ * Includes request deduplication to prevent redundant API calls from rapid re-renders
77
+ * (e.g., React component re-rendering).
78
+ *
79
+ * @param {RenderWidgetOptions} options - Widget rendering options
80
+ * @returns {Promise<void>} Rejects if rendering fails
81
+ *
82
+ * @throws {CoBuyRenderError} If container not found or rendering fails
83
+ * @throws {CoBuyValidationError} If productId validation fails
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * try {
88
+ * const widget = new WidgetRoot(config, apiClient, analyticsClient);
89
+ * await widget.render({
90
+ * productId: 'prod_123',
91
+ * container: '#widget-container'
92
+ * });
93
+ * } catch (error) {
94
+ * if (error instanceof CoBuyRenderError) {
95
+ * console.error('Widget render failed:', error.message);
96
+ * }
97
+ * }
98
+ * ```
62
99
  */
63
100
  render(options: RenderWidgetOptions): Promise<void>;
101
+ /**
102
+ * Queued render that handles concurrent render protection
103
+ */
104
+ private doQueuedRender;
105
+ private doRender;
64
106
  /**
65
107
  * Fetch reward data with automatic retry on failure
108
+ *
109
+ * @param productId The product ID to fetch reward for
110
+ * @returns Promise with reward data on success, null on failure
111
+ * @internal State updates (LOADED/ERROR) are handled by the caller
66
112
  */
67
113
  private fetchRewardWithRetry;
68
114
  /**
@@ -97,6 +143,14 @@ export declare class WidgetRoot {
97
143
  * Handle retry button click - reset retry count and re-fetch
98
144
  */
99
145
  private handleRetry;
146
+ /**
147
+ * Get or create a live region announcer for screen reader announcements
148
+ */
149
+ private getOrCreateLiveRegion;
150
+ /**
151
+ * Announce a message to screen readers via live region
152
+ */
153
+ private announceToScreenReaders;
100
154
  private createWidget;
101
155
  /**
102
156
  * Inject base layout styles for responsive widget rendering
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cshah18/sdk",
3
- "version": "4.8.0",
3
+ "version": "4.10.0",
4
4
  "description": "CoBuy Embedded SDK for browser JavaScript integration",
5
5
  "type": "module",
6
6
  "main": "dist/cobuy-sdk.umd.js",
@@ -11,6 +11,7 @@
11
11
  ],
12
12
  "scripts": {
13
13
  "build": "rollup -c",
14
+ "build:analyze": "ANALYZE=true rollup -c && echo '📊 Bundle analysis: open dist/stats.html'",
14
15
  "build:watch": "rollup -c -w",
15
16
  "lint": "eslint \"src/**/*.{ts,tsx}\"",
16
17
  "lint:fix": "eslint \"src/**/*.{ts,tsx}\" --fix",
@@ -29,6 +30,7 @@
29
30
  "author": "CoBuy",
30
31
  "license": "MIT",
31
32
  "dependencies": {
33
+ "@fingerprintjs/botd": "^2.0.0",
32
34
  "socket.io-client": "^4.7.5"
33
35
  },
34
36
  "devDependencies": {
@@ -46,6 +48,7 @@
46
48
  "prettier": "^3.7.4",
47
49
  "rollup": "^4.9.4",
48
50
  "rollup-plugin-postcss": "^4.0.2",
51
+ "rollup-plugin-visualizer": "^5.12.0",
49
52
  "tslib": "^2.6.2",
50
53
  "typescript": "^5.3.3"
51
54
  }