hypercrm 1.0.3 → 1.0.5

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/assets/widget.js CHANGED
@@ -53,8 +53,8 @@
53
53
  const styles = `
54
54
  .hypercrm-widget-container {
55
55
  position: fixed;
56
- bottom: 24px;
57
- right: 24px;
56
+ bottom: calc(24px + var(--hypercrm-offset-bottom, 0px));
57
+ right: calc(24px + var(--hypercrm-offset-side, 0px));
58
58
  z-index: 2147483000;
59
59
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
60
60
  color: var(--hypercrm-text-primary, #111827);
@@ -78,13 +78,17 @@
78
78
  --hypercrm-radius-lg: 20px;
79
79
  --hypercrm-radius-md: 16px;
80
80
  --hypercrm-radius-sm: 12px;
81
+ --hypercrm-offset-bottom: 0px;
82
+ --hypercrm-offset-side: 0px;
83
+ --hypercrm-offset-bottom-mobile: 0px;
84
+ --hypercrm-offset-side-mobile: 0px;
81
85
  color-scheme: light;
82
86
  -webkit-font-smoothing: antialiased;
83
87
  }
84
88
 
85
89
  .hypercrm-widget-container.hypercrm-position-left {
86
90
  right: auto;
87
- left: 24px;
91
+ left: calc(24px + var(--hypercrm-offset-side, 0px));
88
92
  }
89
93
 
90
94
  .hypercrm-widget-container.hypercrm-position-left .hypercrm-widget-panel {
@@ -106,6 +110,7 @@
106
110
  .hypercrm-toggle-btn {
107
111
  width: 50px;
108
112
  height: 50px;
113
+ padding: 0;
109
114
  border-radius: 50%;
110
115
  border: none;
111
116
  display: flex;
@@ -1290,15 +1295,19 @@
1290
1295
 
1291
1296
  @media (max-width: 640px) {
1292
1297
  .hypercrm-widget-container {
1293
- bottom: 16px;
1294
- right: 16px;
1298
+ bottom: calc(16px + var(--hypercrm-offset-bottom-mobile, 0px));
1299
+ right: calc(16px + var(--hypercrm-offset-side-mobile, 0px));
1295
1300
  }
1296
1301
 
1297
1302
  .hypercrm-widget-container.hypercrm-position-left {
1298
- left: 16px;
1303
+ left: calc(16px + var(--hypercrm-offset-side-mobile, 0px));
1299
1304
  right: auto;
1300
1305
  }
1301
1306
 
1307
+ .hypercrm-widget-container.hypercrm-mobile-disabled {
1308
+ display: none;
1309
+ }
1310
+
1302
1311
  .hypercrm-toggle-btn {
1303
1312
  width: 56px;
1304
1313
  height: 56px;
@@ -1330,6 +1339,10 @@
1330
1339
  this.theme = { ...DEFAULT_THEME, ...(this.options.theme || {}) };
1331
1340
  this.colorModePreference = this.options.colorMode || 'light';
1332
1341
  this.position = this.normalizePosition(this.options.position);
1342
+ this.offset = this.normalizeOffsets(this.options.offset);
1343
+ const mobileOptions = this.options && typeof this.options.mobile === 'object' ? this.options.mobile : {};
1344
+ this.mobileEnabled = mobileOptions?.enabled !== false;
1345
+ this.mobileOffset = this.normalizeOffsets(mobileOptions?.offset);
1333
1346
  this.mediaColorQuery = null;
1334
1347
  this.systemColorListener = null;
1335
1348
  this.systemColorListenerAttached = false;
@@ -1400,6 +1413,22 @@
1400
1413
  return value === 'left' ? 'left' : 'right';
1401
1414
  }
1402
1415
 
1416
+ normalizeOffsetValue(value) {
1417
+ if (value === null || value === undefined || value === '') return 0;
1418
+ const num = Number(value);
1419
+ return Number.isFinite(num) ? num : 0;
1420
+ }
1421
+
1422
+ normalizeOffsets(value) {
1423
+ if (!value || typeof value !== 'object') {
1424
+ return { bottom: 0, side: 0 };
1425
+ }
1426
+ return {
1427
+ bottom: this.normalizeOffsetValue(value.bottom),
1428
+ side: this.normalizeOffsetValue(value.side),
1429
+ };
1430
+ }
1431
+
1403
1432
  applyPosition() {
1404
1433
  if (!this.container) return;
1405
1434
  const position = this.normalizePosition(this.position || this.options.position);
@@ -1413,6 +1442,41 @@
1413
1442
  this.applyPosition();
1414
1443
  }
1415
1444
 
1445
+ applyOffsets() {
1446
+ if (!this.container) return;
1447
+ const offset = this.offset || { bottom: 0, side: 0 };
1448
+ const mobileOffset = this.mobileOffset || { bottom: 0, side: 0 };
1449
+ this.container.style.setProperty('--hypercrm-offset-bottom', `${offset.bottom}px`);
1450
+ this.container.style.setProperty('--hypercrm-offset-side', `${offset.side}px`);
1451
+ this.container.style.setProperty('--hypercrm-offset-bottom-mobile', `${mobileOffset.bottom}px`);
1452
+ this.container.style.setProperty('--hypercrm-offset-side-mobile', `${mobileOffset.side}px`);
1453
+ }
1454
+
1455
+ applyMobileVisibility() {
1456
+ if (!this.container) return;
1457
+ this.container.classList.toggle('hypercrm-mobile-disabled', this.mobileEnabled === false);
1458
+ }
1459
+
1460
+ setOffset(offset) {
1461
+ this.offset = this.normalizeOffsets(offset);
1462
+ this.options.offset = this.offset;
1463
+ this.applyOffsets();
1464
+ }
1465
+
1466
+ setMobileOffset(offset) {
1467
+ this.mobileOffset = this.normalizeOffsets(offset);
1468
+ const current = this.options.mobile && typeof this.options.mobile === 'object' ? this.options.mobile : {};
1469
+ this.options.mobile = { ...current, offset: this.mobileOffset };
1470
+ this.applyOffsets();
1471
+ }
1472
+
1473
+ setMobileEnabled(enabled) {
1474
+ this.mobileEnabled = enabled !== false;
1475
+ const current = this.options.mobile && typeof this.options.mobile === 'object' ? this.options.mobile : {};
1476
+ this.options.mobile = { ...current, enabled: this.mobileEnabled };
1477
+ this.applyMobileVisibility();
1478
+ }
1479
+
1416
1480
  absUrl(url) {
1417
1481
  if (!url) return url;
1418
1482
  if (/^https?:/i.test(url)) return url;
@@ -1617,6 +1681,8 @@
1617
1681
  document.body.appendChild(container);
1618
1682
  this.container = container;
1619
1683
  this.applyPosition();
1684
+ this.applyOffsets();
1685
+ this.applyMobileVisibility();
1620
1686
 
1621
1687
  // Lightbox overlay
1622
1688
  const lightbox = document.createElement('div');
@@ -2370,6 +2436,17 @@
2370
2436
  if (!this.options.position && this.orgInfo?.widget?.position) {
2371
2437
  this.setPosition(this.orgInfo.widget.position);
2372
2438
  }
2439
+ const orgOffset = this.orgInfo?.widget?.offset;
2440
+ if (!this.options.offset && orgOffset) {
2441
+ this.setOffset(orgOffset);
2442
+ }
2443
+ const orgMobile = this.orgInfo?.widget?.mobile || {};
2444
+ if (typeof this.options.mobile?.enabled !== 'boolean' && typeof orgMobile.enabled === 'boolean') {
2445
+ this.setMobileEnabled(orgMobile.enabled);
2446
+ }
2447
+ if (!this.options.mobile?.offset && orgMobile.offset) {
2448
+ this.setMobileOffset(orgMobile.offset);
2449
+ }
2373
2450
  const iconUrl = this.orgInfo?.widget?.iconUrl;
2374
2451
  this.orgIconUrl = iconUrl ? this.absUrl(iconUrl) : null;
2375
2452
  this.updateHeaderIcons();
@@ -2953,6 +3030,15 @@
2953
3030
  setPosition(position) {
2954
3031
  if (activeWidget) activeWidget.setPosition(position);
2955
3032
  },
3033
+ setOffset(offset) {
3034
+ if (activeWidget) activeWidget.setOffset(offset);
3035
+ },
3036
+ setMobileOffset(offset) {
3037
+ if (activeWidget) activeWidget.setMobileOffset(offset);
3038
+ },
3039
+ setMobileEnabled(enabled) {
3040
+ if (activeWidget) activeWidget.setMobileEnabled(enabled);
3041
+ },
2956
3042
  open() {
2957
3043
  if (activeWidget) activeWidget.openWidget();
2958
3044
  },
package/dist/index.d.ts CHANGED
@@ -6,6 +6,17 @@ export interface WidgetOptions {
6
6
  theme?: Record<string, string>;
7
7
  colorMode?: 'light' | 'dark' | 'auto';
8
8
  position?: 'left' | 'right';
9
+ offset?: {
10
+ bottom?: number;
11
+ side?: number;
12
+ };
13
+ mobile?: {
14
+ enabled?: boolean;
15
+ offset?: {
16
+ bottom?: number;
17
+ side?: number;
18
+ };
19
+ };
9
20
  autoOpen?: boolean;
10
21
  debug?: boolean;
11
22
  scriptUrl?: string;
@@ -15,12 +26,30 @@ export declare const destroyWidget: () => void;
15
26
  export declare const setWidgetTheme: (theme: Record<string, string>) => Promise<void>;
16
27
  export declare const setWidgetColorMode: (mode: "light" | "dark" | "auto") => Promise<void>;
17
28
  export declare const setWidgetPosition: (position: "left" | "right") => Promise<void>;
29
+ export declare const setWidgetOffset: (offset: {
30
+ bottom?: number;
31
+ side?: number;
32
+ }) => Promise<void>;
33
+ export declare const setWidgetMobileOffset: (offset: {
34
+ bottom?: number;
35
+ side?: number;
36
+ }) => Promise<void>;
37
+ export declare const setWidgetMobileEnabled: (enabled: boolean) => Promise<void>;
18
38
  declare const _default: {
19
39
  init: (options?: WidgetOptions) => Promise<any>;
20
40
  destroy: () => void;
21
41
  setTheme: (theme: Record<string, string>) => Promise<void>;
22
42
  setColorMode: (mode: "light" | "dark" | "auto") => Promise<void>;
23
43
  setPosition: (position: "left" | "right") => Promise<void>;
44
+ setOffset: (offset: {
45
+ bottom?: number;
46
+ side?: number;
47
+ }) => Promise<void>;
48
+ setMobileOffset: (offset: {
49
+ bottom?: number;
50
+ side?: number;
51
+ }) => Promise<void>;
52
+ setMobileEnabled: (enabled: boolean) => Promise<void>;
24
53
  };
25
54
  export default _default;
26
55
  declare global {
@@ -31,6 +60,15 @@ declare global {
31
60
  setTheme: (theme?: Record<string, string>) => void;
32
61
  setColorMode: (mode: 'light' | 'dark' | 'auto') => void;
33
62
  setPosition: (position: 'left' | 'right') => void;
63
+ setOffset: (offset: {
64
+ bottom?: number;
65
+ side?: number;
66
+ }) => void;
67
+ setMobileOffset: (offset: {
68
+ bottom?: number;
69
+ side?: number;
70
+ }) => void;
71
+ setMobileEnabled: (enabled: boolean) => void;
34
72
  open: () => void;
35
73
  close: () => void;
36
74
  toggle: () => void;
package/dist/index.js CHANGED
@@ -95,10 +95,25 @@ export const setWidgetPosition = async (position) => {
95
95
  await ensureScriptLoaded();
96
96
  window.HyperCRMWidget.setPosition(position);
97
97
  };
98
+ export const setWidgetOffset = async (offset) => {
99
+ await ensureScriptLoaded();
100
+ window.HyperCRMWidget.setOffset(offset || {});
101
+ };
102
+ export const setWidgetMobileOffset = async (offset) => {
103
+ await ensureScriptLoaded();
104
+ window.HyperCRMWidget.setMobileOffset(offset || {});
105
+ };
106
+ export const setWidgetMobileEnabled = async (enabled) => {
107
+ await ensureScriptLoaded();
108
+ window.HyperCRMWidget.setMobileEnabled(enabled);
109
+ };
98
110
  export default {
99
111
  init: initWidget,
100
112
  destroy: destroyWidget,
101
113
  setTheme: setWidgetTheme,
102
114
  setColorMode: setWidgetColorMode,
103
115
  setPosition: setWidgetPosition,
116
+ setOffset: setWidgetOffset,
117
+ setMobileOffset: setWidgetMobileOffset,
118
+ setMobileEnabled: setWidgetMobileEnabled,
104
119
  };
package/dist/react.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import { useEffect, useRef } from 'react';
2
- import { initWidget, destroyWidget, setWidgetTheme, setWidgetColorMode, setWidgetPosition, } from './index';
2
+ import { initWidget, destroyWidget, setWidgetTheme, setWidgetColorMode, setWidgetPosition, setWidgetOffset, setWidgetMobileOffset, setWidgetMobileEnabled, } from './index';
3
3
  export const useHyperCRMWidget = (options = {}) => {
4
- const { apiUrl, apiKey, orgId, mount, theme, colorMode, position, autoOpen, debug, scriptUrl, } = options;
4
+ const { apiUrl, apiKey, orgId, mount, theme, colorMode, position, offset, mobile, autoOpen, debug, scriptUrl, } = options;
5
5
  const readyRef = useRef(false);
6
- const latestRef = useRef({ theme, colorMode, position });
6
+ const latestRef = useRef({ theme, colorMode, position, offset, mobile });
7
7
  useEffect(() => {
8
- latestRef.current = { theme, colorMode, position };
9
- }, [theme, colorMode, position]);
8
+ latestRef.current = { theme, colorMode, position, offset, mobile };
9
+ }, [theme, colorMode, position, offset, mobile]);
10
10
  useEffect(() => {
11
11
  let cancelled = false;
12
12
  readyRef.current = false;
@@ -18,11 +18,14 @@ export const useHyperCRMWidget = (options = {}) => {
18
18
  theme: latestRef.current.theme,
19
19
  colorMode: latestRef.current.colorMode,
20
20
  position: latestRef.current.position,
21
+ offset: latestRef.current.offset,
22
+ mobile: latestRef.current.mobile,
21
23
  autoOpen,
22
24
  debug,
23
25
  scriptUrl,
24
26
  })
25
27
  .then(() => {
28
+ var _a, _b;
26
29
  if (cancelled)
27
30
  return;
28
31
  readyRef.current = true;
@@ -32,6 +35,12 @@ export const useHyperCRMWidget = (options = {}) => {
32
35
  setWidgetColorMode(latest.colorMode);
33
36
  if (latest.position)
34
37
  setWidgetPosition(latest.position);
38
+ if (latest.offset)
39
+ setWidgetOffset(latest.offset);
40
+ if ((_a = latest.mobile) === null || _a === void 0 ? void 0 : _a.offset)
41
+ setWidgetMobileOffset(latest.mobile.offset);
42
+ if (typeof ((_b = latest.mobile) === null || _b === void 0 ? void 0 : _b.enabled) === 'boolean')
43
+ setWidgetMobileEnabled(latest.mobile.enabled);
35
44
  })
36
45
  .catch((err) => {
37
46
  if (debug)
@@ -58,6 +67,19 @@ export const useHyperCRMWidget = (options = {}) => {
58
67
  return;
59
68
  setWidgetPosition(position);
60
69
  }, [position]);
70
+ useEffect(() => {
71
+ if (!readyRef.current || !offset)
72
+ return;
73
+ setWidgetOffset(offset);
74
+ }, [offset]);
75
+ useEffect(() => {
76
+ if (!readyRef.current)
77
+ return;
78
+ if (mobile === null || mobile === void 0 ? void 0 : mobile.offset)
79
+ setWidgetMobileOffset(mobile.offset);
80
+ if (typeof (mobile === null || mobile === void 0 ? void 0 : mobile.enabled) === 'boolean')
81
+ setWidgetMobileEnabled(mobile.enabled);
82
+ }, [mobile]);
61
83
  };
62
84
  export const HyperCRMWidget = (props) => {
63
85
  useHyperCRMWidget(props);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hypercrm",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "HyperCRM widget loader with optional React component.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",