@helpway/react 0.4.2 → 0.5.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.
package/README.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  Official React SDK for [Helpway](https://helpway.ai) — AI-powered customer support widget with full programmatic control.
4
4
 
5
+ > **📚 Full documentation:** https://helpway.ai/docs
6
+ > · [Quick start](https://helpway.ai/docs/quick-start)
7
+ > · [React SDK](https://helpway.ai/docs/react-sdk)
8
+ > · [Customization & theming](https://helpway.ai/docs/customization)
9
+ > · [Widget API](https://helpway.ai/docs/widget-api)
10
+ > · [Integration notes (CSP, SSR, multi-tenant)](https://helpway.ai/docs/integration-notes)
11
+
5
12
  ## Install
6
13
 
7
14
  ```bash
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as _helpway_widget_core from '@helpway/widget-core';
3
- import { HelpwayMethods, WidgetStore } from '@helpway/widget-core';
4
- export { ConversationSummary, HelpwayAPI, RealtimeEvent, TimelineItem, WidgetEventName, WidgetEvents, WidgetState, WidgetStore, clearVisitorId, formatRelativeTime, formatTime, getInitials, getOrCreateVisitorId } from '@helpway/widget-core';
3
+ import { HelpwayMethods, WidgetTheme, WidgetStore } from '@helpway/widget-core';
4
+ export { ConversationSummary, HelpwayAPI, RealtimeEvent, TimelineItem, WidgetEventName, WidgetEvents, WidgetPosition, WidgetState, WidgetStore, WidgetTheme, clearVisitorId, formatRelativeTime, formatTime, getInitials, getOrCreateVisitorId } from '@helpway/widget-core';
5
5
  import * as react from 'react';
6
6
  import react__default, { ReactNode } from 'react';
7
7
  import * as _helpway_types from '@helpway/types';
@@ -52,6 +52,16 @@ interface HelpwayWidgetProps {
52
52
  onClose?: () => void;
53
53
  /** Fires when the unread count changes */
54
54
  onUnreadChange?: (count: number) => void;
55
+ /**
56
+ * Developer-side theme override. Most consumers should configure
57
+ * appearance from the dashboard so changes apply without a redeploy
58
+ * — see https://helpway.ai/docs/customization. Use this prop only
59
+ * for runtime-resolved theming (multi-tenant brand colors, dark/
60
+ * light sync with the host app, etc). Values map to CSS custom
61
+ * properties on the widget host. See the `WidgetTheme` type for
62
+ * the full set of supported keys.
63
+ */
64
+ theme?: WidgetTheme;
55
65
  /**
56
66
  * @deprecated Legacy prop from the v0.1 script-loader era. If set,
57
67
  * the `/widget.js` suffix is stripped to derive `apiUrl`. New code
@@ -66,7 +76,7 @@ type HelpwayPublicAPI = HelpwayMethods;
66
76
  * `layout.tsx`, or `main.tsx`). Unmounting cleanly tears down the
67
77
  * widget and its WebSocket connection — useful for route-scoped mounts.
68
78
  */
69
- declare function HelpwayWidget({ apiKey, apiUrl, locale, initialConversationId, onReady, hideLauncher, customLauncherSelector, onOpen, onClose, onUnreadChange, src, }: HelpwayWidgetProps): react_jsx_runtime.JSX.Element;
79
+ declare function HelpwayWidget({ apiKey, apiUrl, locale, initialConversationId, onReady, hideLauncher, customLauncherSelector, onOpen, onClose, onUnreadChange, theme, src, }: HelpwayWidgetProps): react_jsx_runtime.JSX.Element;
70
80
 
71
81
  interface IdentifyData {
72
82
  externalId: string;
@@ -89,6 +99,17 @@ interface SupportProviderProps {
89
99
  onOpen?: () => void;
90
100
  onClose?: () => void;
91
101
  onUnreadChange?: (count: number) => void;
102
+ /**
103
+ * Developer-side theme override. Most consumers should configure
104
+ * appearance in the Helpway dashboard (see
105
+ * https://helpway.ai/docs/customization) so changes apply without
106
+ * a redeploy. Use this prop only when you need the widget to inherit
107
+ * a host-app theme that the dashboard can't see (e.g. a tenant-
108
+ * specific brand color resolved at runtime). Values here are written
109
+ * as CSS custom properties on the widget host and override the
110
+ * dashboard config for this mount only.
111
+ */
112
+ theme?: WidgetTheme;
92
113
  children: ReactNode;
93
114
  }
94
115
  /**
@@ -98,7 +119,7 @@ interface SupportProviderProps {
98
119
  * Visitor identity is managed via server-side cookies (hw_visitor).
99
120
  * No localStorage or client-side ID management needed.
100
121
  */
101
- declare function SupportProvider({ apiKey, apiUrl, locale, initialConversationId, onReady, customLauncherSelector, onOpen, onClose, onUnreadChange, children, }: SupportProviderProps): react_jsx_runtime.JSX.Element;
122
+ declare function SupportProvider({ apiKey, apiUrl, locale, initialConversationId, onReady, customLauncherSelector, onOpen, onClose, onUnreadChange, theme, children, }: SupportProviderProps): react_jsx_runtime.JSX.Element;
102
123
 
103
124
  /**
104
125
  * Core widget state — connection status, visitor identity, website info.
package/dist/index.js CHANGED
@@ -585,6 +585,55 @@ function createHelpwayAPI(deps) {
585
585
  };
586
586
  }
587
587
 
588
+ // ../widget-core/src/theme.ts
589
+ function isValidHex(color) {
590
+ return /^#[0-9a-fA-F]{6}$/.test(color);
591
+ }
592
+ function lighten(hex) {
593
+ if (!isValidHex(hex)) return hex;
594
+ const r = Math.min(255, Number.parseInt(hex.slice(1, 3), 16) + 30);
595
+ const g = Math.min(255, Number.parseInt(hex.slice(3, 5), 16) + 30);
596
+ const b = Math.min(255, Number.parseInt(hex.slice(5, 7), 16) + 30);
597
+ const hex2 = (n) => n.toString(16).padStart(2, "0");
598
+ return `#${hex2(r)}${hex2(g)}${hex2(b)}`;
599
+ }
600
+ function setVar(host, name, value) {
601
+ if (value == null || value === "") return;
602
+ host.style.setProperty(name, value);
603
+ }
604
+ function applyTheme(host, theme) {
605
+ if (!host || !theme) return;
606
+ if (theme.primaryColor) {
607
+ setVar(host, "--hw-primary", theme.primaryColor);
608
+ setVar(host, "--hw-primary-hover", lighten(theme.primaryColor));
609
+ setVar(host, "--hw-brand", theme.primaryColor);
610
+ }
611
+ setVar(host, "--hw-on-brand", theme.onPrimaryColor);
612
+ setVar(host, "--hw-visitor-bubble-bg", theme.bubbleColor ?? theme.primaryColor);
613
+ setVar(host, "--hw-visitor-bubble-text", theme.bubbleTextColor ?? theme.onPrimaryColor);
614
+ setVar(host, "--hw-bg", theme.backgroundColor);
615
+ setVar(host, "--hw-text", theme.textColor);
616
+ setVar(host, "--hw-border", theme.borderColor);
617
+ setVar(host, "--hw-radius", theme.radius);
618
+ setVar(host, "--hw-font", theme.fontFamily);
619
+ if (theme.position === "bottom-left") {
620
+ setVar(host, "--hw-position-right", "auto");
621
+ setVar(host, "--hw-position-left", "20px");
622
+ setVar(host, "--hw-window-right", "auto");
623
+ setVar(host, "--hw-window-left", "0");
624
+ } else if (theme.position === "bottom-right") {
625
+ host.style.removeProperty("--hw-position-right");
626
+ host.style.removeProperty("--hw-position-left");
627
+ host.style.removeProperty("--hw-window-right");
628
+ host.style.removeProperty("--hw-window-left");
629
+ }
630
+ if (theme.cssVariables) {
631
+ for (const [key, value] of Object.entries(theme.cssVariables)) {
632
+ if (key.startsWith("--")) host.style.setProperty(key, value);
633
+ }
634
+ }
635
+ }
636
+
588
637
  // ../widget-core/src/events.ts
589
638
  var WidgetEventEmitter = class {
590
639
  listeners = /* @__PURE__ */ new Map();
@@ -884,6 +933,7 @@ function SupportProvider({
884
933
  onOpen,
885
934
  onClose,
886
935
  onUnreadChange,
936
+ theme,
887
937
  children
888
938
  }) {
889
939
  const initRef = useRef(null);
@@ -1080,6 +1130,11 @@ function SupportProvider({
1080
1130
  observer?.disconnect();
1081
1131
  };
1082
1132
  }, [customLauncherSelector, api]);
1133
+ useEffect(() => {
1134
+ if (!theme || typeof document === "undefined") return;
1135
+ const target = document.getElementById("helpway-widget") ?? document.documentElement;
1136
+ applyTheme(target, theme);
1137
+ }, [theme]);
1083
1138
  useEffect(() => {
1084
1139
  if (typeof window === "undefined") return;
1085
1140
  const callable = installCallable(api);
@@ -4589,6 +4644,7 @@ function HelpwayWidget({
4589
4644
  onOpen,
4590
4645
  onClose,
4591
4646
  onUnreadChange,
4647
+ theme,
4592
4648
  // eslint-disable-next-line @typescript-eslint/no-deprecated
4593
4649
  src
4594
4650
  }) {
@@ -4605,6 +4661,7 @@ function HelpwayWidget({
4605
4661
  onOpen,
4606
4662
  onClose,
4607
4663
  onUnreadChange,
4664
+ theme,
4608
4665
  children: /* @__PURE__ */ jsx14(DefaultWidget, { hideLauncher })
4609
4666
  }
4610
4667
  );