hypercrm 1.0.4 → 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 {
@@ -1291,15 +1295,19 @@
1291
1295
 
1292
1296
  @media (max-width: 640px) {
1293
1297
  .hypercrm-widget-container {
1294
- bottom: 16px;
1295
- right: 16px;
1298
+ bottom: calc(16px + var(--hypercrm-offset-bottom-mobile, 0px));
1299
+ right: calc(16px + var(--hypercrm-offset-side-mobile, 0px));
1296
1300
  }
1297
1301
 
1298
1302
  .hypercrm-widget-container.hypercrm-position-left {
1299
- left: 16px;
1303
+ left: calc(16px + var(--hypercrm-offset-side-mobile, 0px));
1300
1304
  right: auto;
1301
1305
  }
1302
1306
 
1307
+ .hypercrm-widget-container.hypercrm-mobile-disabled {
1308
+ display: none;
1309
+ }
1310
+
1303
1311
  .hypercrm-toggle-btn {
1304
1312
  width: 56px;
1305
1313
  height: 56px;
@@ -1331,6 +1339,10 @@
1331
1339
  this.theme = { ...DEFAULT_THEME, ...(this.options.theme || {}) };
1332
1340
  this.colorModePreference = this.options.colorMode || 'light';
1333
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);
1334
1346
  this.mediaColorQuery = null;
1335
1347
  this.systemColorListener = null;
1336
1348
  this.systemColorListenerAttached = false;
@@ -1401,6 +1413,22 @@
1401
1413
  return value === 'left' ? 'left' : 'right';
1402
1414
  }
1403
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
+
1404
1432
  applyPosition() {
1405
1433
  if (!this.container) return;
1406
1434
  const position = this.normalizePosition(this.position || this.options.position);
@@ -1414,6 +1442,41 @@
1414
1442
  this.applyPosition();
1415
1443
  }
1416
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
+
1417
1480
  absUrl(url) {
1418
1481
  if (!url) return url;
1419
1482
  if (/^https?:/i.test(url)) return url;
@@ -1618,6 +1681,8 @@
1618
1681
  document.body.appendChild(container);
1619
1682
  this.container = container;
1620
1683
  this.applyPosition();
1684
+ this.applyOffsets();
1685
+ this.applyMobileVisibility();
1621
1686
 
1622
1687
  // Lightbox overlay
1623
1688
  const lightbox = document.createElement('div');
@@ -2371,6 +2436,17 @@
2371
2436
  if (!this.options.position && this.orgInfo?.widget?.position) {
2372
2437
  this.setPosition(this.orgInfo.widget.position);
2373
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
+ }
2374
2450
  const iconUrl = this.orgInfo?.widget?.iconUrl;
2375
2451
  this.orgIconUrl = iconUrl ? this.absUrl(iconUrl) : null;
2376
2452
  this.updateHeaderIcons();
@@ -2954,6 +3030,15 @@
2954
3030
  setPosition(position) {
2955
3031
  if (activeWidget) activeWidget.setPosition(position);
2956
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
+ },
2957
3042
  open() {
2958
3043
  if (activeWidget) activeWidget.openWidget();
2959
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.4",
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",