@usereq/widget 0.2.24 → 0.2.25
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/package.json
CHANGED
|
@@ -1,12 +1,81 @@
|
|
|
1
1
|
import type { CSSProperties } from "react";
|
|
2
2
|
|
|
3
|
+
export type ChatWidgetGradient = {
|
|
4
|
+
from: string;
|
|
5
|
+
to: string;
|
|
6
|
+
angle?: number | null;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
/** Solid hex or gradient. Mirrors `ChatColor` in `@usereq/ui`. */
|
|
10
|
+
export type ChatWidgetColor = string | ChatWidgetGradient;
|
|
11
|
+
|
|
12
|
+
export type ChatWidgetIconPack = "lucide" | "heroicons" | "phosphor";
|
|
13
|
+
|
|
14
|
+
export type ChatWidgetIconSlot =
|
|
15
|
+
| "launcher"
|
|
16
|
+
| "send"
|
|
17
|
+
| "close"
|
|
18
|
+
| "minimize"
|
|
19
|
+
| "attach"
|
|
20
|
+
| "mic";
|
|
21
|
+
|
|
22
|
+
export type ChatWidgetIcons = {
|
|
23
|
+
pack?: ChatWidgetIconPack | null;
|
|
24
|
+
overrides?: Partial<Record<ChatWidgetIconSlot, string>> | null;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Every appearance token the agents row can store.
|
|
29
|
+
*
|
|
30
|
+
* This deliberately mirrors `ChatAppearance` in `@usereq/ui` field-for-field,
|
|
31
|
+
* but is declared standalone rather than imported: `shared/widget-config` is
|
|
32
|
+
* consumed by `apps/api`, which has no `@usereq/ui` dependency. Structural
|
|
33
|
+
* typing means the two still line up where they meet.
|
|
34
|
+
*
|
|
35
|
+
* Keep in sync with `widgetAppearanceSchema` in the API's `widget.model.ts`
|
|
36
|
+
* and `AgentWidgetAppearance` in the dashboard.
|
|
37
|
+
*/
|
|
3
38
|
export type ChatWidgetAppearance = {
|
|
39
|
+
// — Legacy gradient (still the fallback when `primary` is unset) —
|
|
4
40
|
avatarOrbColor1?: string | null;
|
|
5
41
|
avatarOrbColor2?: string | null;
|
|
42
|
+
|
|
43
|
+
// — Brand —
|
|
44
|
+
primary?: ChatWidgetColor | null;
|
|
45
|
+
primaryForeground?: string | null;
|
|
46
|
+
secondary?: string | null;
|
|
47
|
+
secondaryForeground?: string | null;
|
|
6
48
|
actionText?: string | null;
|
|
49
|
+
|
|
50
|
+
// — Surface tokens (panel) —
|
|
51
|
+
background?: string | null;
|
|
52
|
+
foreground?: string | null;
|
|
53
|
+
muted?: string | null;
|
|
54
|
+
mutedForeground?: string | null;
|
|
55
|
+
border?: string | null;
|
|
56
|
+
ring?: string | null;
|
|
57
|
+
|
|
58
|
+
// — Granular text overrides —
|
|
59
|
+
textPrimary?: string | null;
|
|
60
|
+
textForeground?: string | null;
|
|
61
|
+
textMutedForeground?: string | null;
|
|
62
|
+
|
|
63
|
+
// — Icon pack swap (persist-only for now) —
|
|
64
|
+
icons?: ChatWidgetIcons | null;
|
|
7
65
|
};
|
|
8
66
|
|
|
9
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Only the three legacy fields are guaranteed present — every other token
|
|
69
|
+
* stays optional on purpose, because `undefined` means "not customized, use
|
|
70
|
+
* the design-system default". Filling them with defaults here would emit
|
|
71
|
+
* `--chat-*` variables for tokens the user never set and lock the panel out
|
|
72
|
+
* of the host theme.
|
|
73
|
+
*/
|
|
74
|
+
export type ResolvedChatWidgetAppearance = ChatWidgetAppearance & {
|
|
75
|
+
avatarOrbColor1: string;
|
|
76
|
+
avatarOrbColor2: string;
|
|
77
|
+
actionText: string;
|
|
78
|
+
};
|
|
10
79
|
|
|
11
80
|
export const DEFAULT_CHAT_WIDGET_APPEARANCE: ResolvedChatWidgetAppearance = {
|
|
12
81
|
avatarOrbColor1: "#2563eb",
|
|
@@ -14,10 +83,20 @@ export const DEFAULT_CHAT_WIDGET_APPEARANCE: ResolvedChatWidgetAppearance = {
|
|
|
14
83
|
actionText: "Need help?",
|
|
15
84
|
};
|
|
16
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Fills defaults for the three legacy fields and passes every other token
|
|
88
|
+
* through untouched.
|
|
89
|
+
*
|
|
90
|
+
* The spread is load-bearing: this function used to construct a fresh
|
|
91
|
+
* three-key object, which silently discarded the entire saved theme
|
|
92
|
+
* (background, primary, text colors…) on its way to the embed. Any new token
|
|
93
|
+
* added to `ChatWidgetAppearance` now survives without editing this function.
|
|
94
|
+
*/
|
|
17
95
|
export function resolveChatWidgetAppearance(
|
|
18
96
|
appearance?: Partial<ChatWidgetAppearance> | null,
|
|
19
97
|
): ResolvedChatWidgetAppearance {
|
|
20
98
|
return {
|
|
99
|
+
...(appearance ?? {}),
|
|
21
100
|
avatarOrbColor1:
|
|
22
101
|
normalizeString(appearance?.avatarOrbColor1) ??
|
|
23
102
|
DEFAULT_CHAT_WIDGET_APPEARANCE.avatarOrbColor1,
|
|
@@ -168,7 +168,13 @@ export class AgentWidgetElement extends HTMLElement {
|
|
|
168
168
|
const base =
|
|
169
169
|
this.sessionConfig?.widgetConfig.widgetAppearance ?? DEFAULT_WIDGET_APPEARANCE;
|
|
170
170
|
|
|
171
|
+
// Spread first, then apply the three attribute-overridable fields on top.
|
|
172
|
+
// Only those three are exposed as HTML attributes; every other token
|
|
173
|
+
// (surface colors, brand, text) comes from the agent config and must
|
|
174
|
+
// pass through untouched — rebuilding a fixed-key object here is what
|
|
175
|
+
// used to drop a customer's saved theme on the floor.
|
|
171
176
|
return {
|
|
177
|
+
...base,
|
|
172
178
|
avatarOrbColor1:
|
|
173
179
|
this.appearanceAttributes.avatarOrbColor1?.trim() ||
|
|
174
180
|
base.avatarOrbColor1,
|
|
@@ -255,12 +255,22 @@ function mapPreset(preset: WidgetPreset): ChatWidgetConfig["preset"] {
|
|
|
255
255
|
return preset;
|
|
256
256
|
}
|
|
257
257
|
|
|
258
|
+
/**
|
|
259
|
+
* `WidgetAppearance` mirrors `ChatAppearance` field-for-field (see
|
|
260
|
+
* `chat-widget/chat-widget-appearance.ts` for why it's declared separately),
|
|
261
|
+
* so this is a structural pass-through rather than a field-by-field copy.
|
|
262
|
+
*
|
|
263
|
+
* It used to rebuild a three-key object, which meant that even once the API
|
|
264
|
+
* started sending the full theme, the surface and brand tokens were dropped
|
|
265
|
+
* again right here — one strip point behind the other.
|
|
266
|
+
*/
|
|
258
267
|
function toChatAppearance(appearance: WidgetAppearance): ChatAppearance {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
268
|
+
// Deliberately NOT a cast. Returning the value unasserted makes the
|
|
269
|
+
// compiler verify that `WidgetAppearance` is still structurally
|
|
270
|
+
// assignable to `ChatAppearance` — so if the two ever drift (a token
|
|
271
|
+
// added to one and not the other), this fails typecheck instead of
|
|
272
|
+
// silently dropping the field the way the old field-by-field copy did.
|
|
273
|
+
return appearance;
|
|
264
274
|
}
|
|
265
275
|
|
|
266
276
|
function isHtmlElement(
|