claudius-chat-widget 1.6.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/LICENSE +21 -0
- package/README.md +89 -0
- package/dist/api/client.d.ts +24 -0
- package/dist/api/errors.d.ts +9 -0
- package/dist/api/index.d.ts +4 -0
- package/dist/api/types.d.ts +22 -0
- package/dist/claudius.cjs +2 -0
- package/dist/claudius.css +1 -0
- package/dist/claudius.iife.js +41 -0
- package/dist/claudius.js +1373 -0
- package/dist/components/ChatInput.d.ts +9 -0
- package/dist/components/ChatMessage.d.ts +10 -0
- package/dist/components/ChatSources.d.ts +7 -0
- package/dist/components/ChatToggleButton.d.ts +10 -0
- package/dist/components/ChatWidget.d.ts +29 -0
- package/dist/components/ChatWindow.d.ts +21 -0
- package/dist/components/GreetingBubble.d.ts +10 -0
- package/dist/components/SourceIcon.d.ts +7 -0
- package/dist/embed.d.ts +38 -0
- package/dist/hooks/useChat.d.ts +20 -0
- package/dist/hooks/useFocusTrap.d.ts +2 -0
- package/dist/hooks/useMediaQuery.d.ts +1 -0
- package/dist/hooks/useSwipeToDismiss.d.ts +4 -0
- package/dist/hooks/useTriggers.d.ts +32 -0
- package/dist/i18n.d.ts +21 -0
- package/dist/index.d.ts +12 -0
- package/dist/locales/de.d.ts +2 -0
- package/dist/locales/en.d.ts +2 -0
- package/dist/locales/es.d.ts +2 -0
- package/dist/locales/fr.d.ts +2 -0
- package/dist/locales/index.d.ts +9 -0
- package/dist/main.d.ts +1 -0
- package/dist/test-utils/MockChatApiClient.d.ts +64 -0
- package/dist/theme/index.d.ts +4 -0
- package/dist/theme/resolve.d.ts +19 -0
- package/dist/theme/themes.d.ts +8 -0
- package/dist/theme/types.d.ts +34 -0
- package/dist/theme/useTheme.d.ts +14 -0
- package/dist/utils/sanitize.d.ts +36 -0
- package/dist/utils/stripAnnouncementFormatting.d.ts +1 -0
- package/package.json +102 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ClaudiusTranslations } from "../i18n";
|
|
2
|
+
interface ChatInputProps {
|
|
3
|
+
onSend: (message: string) => void;
|
|
4
|
+
isLoading: boolean;
|
|
5
|
+
placeholder?: string;
|
|
6
|
+
translations?: ClaudiusTranslations;
|
|
7
|
+
}
|
|
8
|
+
export declare function ChatInput({ onSend, isLoading, placeholder, translations, }: ChatInputProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Source } from "../api/types";
|
|
2
|
+
interface ChatMessageProps {
|
|
3
|
+
role: "user" | "assistant";
|
|
4
|
+
content: string;
|
|
5
|
+
sources?: Source[];
|
|
6
|
+
onSourceClick?: () => void;
|
|
7
|
+
isSourceActive?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare const ChatMessage: import("react").NamedExoticComponent<ChatMessageProps>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { WidgetPosition } from "./ChatWidget";
|
|
2
|
+
import type { ClaudiusTranslations } from "../i18n";
|
|
3
|
+
interface ChatToggleButtonProps {
|
|
4
|
+
isOpen: boolean;
|
|
5
|
+
onClick: () => void;
|
|
6
|
+
position?: WidgetPosition;
|
|
7
|
+
translations?: ClaudiusTranslations;
|
|
8
|
+
}
|
|
9
|
+
export declare const ChatToggleButton: import("react").ForwardRefExoticComponent<ChatToggleButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type Trigger } from "../hooks/useTriggers";
|
|
2
|
+
import { ClaudiusTranslations, defaultTranslations, createTranslations } from "../i18n";
|
|
3
|
+
import { type LocaleCode } from "../locales";
|
|
4
|
+
import type { ClaudiusThemeInput } from "../theme/types";
|
|
5
|
+
export type WidgetPosition = "bottom-right" | "bottom-left" | "top-right" | "top-left";
|
|
6
|
+
export interface ChatWidgetProps {
|
|
7
|
+
apiUrl: string;
|
|
8
|
+
title?: string;
|
|
9
|
+
subtitle?: string;
|
|
10
|
+
welcomeMessage?: string;
|
|
11
|
+
placeholder?: string;
|
|
12
|
+
persistMessages?: boolean;
|
|
13
|
+
storageKeyPrefix?: string;
|
|
14
|
+
requestTimeoutMs?: number;
|
|
15
|
+
/**
|
|
16
|
+
* Color-scheme mode ("light" | "dark" | "auto"), a built-in theme name
|
|
17
|
+
* ("default" | "minimal" | "playful" | "corporate"), an inline
|
|
18
|
+
* ClaudiusTheme object, or a URL to a theme JSON file.
|
|
19
|
+
*/
|
|
20
|
+
theme?: ClaudiusThemeInput;
|
|
21
|
+
accentColor?: string;
|
|
22
|
+
position?: WidgetPosition;
|
|
23
|
+
locale?: LocaleCode;
|
|
24
|
+
translations?: Partial<ClaudiusTranslations>;
|
|
25
|
+
triggers?: Trigger[];
|
|
26
|
+
}
|
|
27
|
+
export declare function ChatWidget({ apiUrl, title, subtitle, welcomeMessage, placeholder, persistMessages, storageKeyPrefix, requestTimeoutMs, theme, accentColor, position, locale, translations: translationOverrides, triggers, }: ChatWidgetProps): import("react/jsx-runtime").JSX.Element;
|
|
28
|
+
export { defaultTranslations, createTranslations };
|
|
29
|
+
export type { ClaudiusTranslations };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { WidgetPosition } from "./ChatWidget";
|
|
2
|
+
import type { ClaudiusTranslations } from "../i18n";
|
|
3
|
+
import type { ChatMessage as ChatMessageData } from "../api/types";
|
|
4
|
+
interface ChatWindowProps {
|
|
5
|
+
messages: ChatMessageData[];
|
|
6
|
+
isLoading: boolean;
|
|
7
|
+
error: string | null;
|
|
8
|
+
canRetry?: boolean;
|
|
9
|
+
onSend: (message: string) => void;
|
|
10
|
+
onRetry?: () => void;
|
|
11
|
+
onClose: () => void;
|
|
12
|
+
title?: string;
|
|
13
|
+
subtitle?: string;
|
|
14
|
+
welcomeMessage?: string;
|
|
15
|
+
placeholder?: string;
|
|
16
|
+
position?: WidgetPosition;
|
|
17
|
+
translations?: ClaudiusTranslations;
|
|
18
|
+
isMobile?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare function ChatWindow({ messages, isLoading, error, canRetry, onSend, onRetry, onClose, title, subtitle, welcomeMessage, placeholder, position, translations, isMobile, }: ChatWindowProps): import("react/jsx-runtime").JSX.Element;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { WidgetPosition } from "./ChatWidget";
|
|
2
|
+
interface GreetingBubbleProps {
|
|
3
|
+
message: string;
|
|
4
|
+
position: WidgetPosition;
|
|
5
|
+
onOpen: () => void;
|
|
6
|
+
onDismiss: () => void;
|
|
7
|
+
dismissLabel: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function GreetingBubble({ message, position, onOpen, onDismiss, dismissLabel, }: GreetingBubbleProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export {};
|
package/dist/embed.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { WidgetPosition } from "./components/ChatWidget";
|
|
2
|
+
import type { Trigger } from "./hooks/useTriggers";
|
|
3
|
+
import type { LocaleCode } from "./locales";
|
|
4
|
+
import type { ClaudiusTranslations } from "./i18n";
|
|
5
|
+
import type { ClaudiusThemeInput } from "./theme/types";
|
|
6
|
+
import "./styles.css";
|
|
7
|
+
interface ClaudiusConfig {
|
|
8
|
+
apiUrl: string;
|
|
9
|
+
title?: string;
|
|
10
|
+
subtitle?: string;
|
|
11
|
+
welcomeMessage?: string;
|
|
12
|
+
placeholder?: string;
|
|
13
|
+
persistMessages?: boolean;
|
|
14
|
+
storageKeyPrefix?: string;
|
|
15
|
+
requestTimeoutMs?: number;
|
|
16
|
+
theme?: ClaudiusThemeInput;
|
|
17
|
+
accentColor?: string;
|
|
18
|
+
position?: WidgetPosition;
|
|
19
|
+
locale?: LocaleCode;
|
|
20
|
+
translations?: Partial<ClaudiusTranslations>;
|
|
21
|
+
triggers?: Trigger[];
|
|
22
|
+
}
|
|
23
|
+
declare global {
|
|
24
|
+
interface Window {
|
|
25
|
+
ClaudiusConfig?: ClaudiusConfig;
|
|
26
|
+
ClaudiusWidgetVersion?: string;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
declare class ClaudiusChat extends HTMLElement {
|
|
30
|
+
private root;
|
|
31
|
+
private container;
|
|
32
|
+
static get observedAttributes(): string[];
|
|
33
|
+
connectedCallback(): void;
|
|
34
|
+
disconnectedCallback(): void;
|
|
35
|
+
attributeChangedCallback(): void;
|
|
36
|
+
private render;
|
|
37
|
+
}
|
|
38
|
+
export { ClaudiusChat };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ClaudiusTranslations } from "../i18n";
|
|
2
|
+
import type { ChatMessage } from "../api/types";
|
|
3
|
+
interface UseChatOptions {
|
|
4
|
+
apiUrl: string;
|
|
5
|
+
persistMessages?: boolean;
|
|
6
|
+
storageKeyPrefix?: string;
|
|
7
|
+
timeoutMs?: number;
|
|
8
|
+
translations?: ClaudiusTranslations;
|
|
9
|
+
}
|
|
10
|
+
interface UseChatReturn {
|
|
11
|
+
messages: ChatMessage[];
|
|
12
|
+
isLoading: boolean;
|
|
13
|
+
error: string | null;
|
|
14
|
+
canRetry: boolean;
|
|
15
|
+
sendMessage: (content: string) => Promise<void>;
|
|
16
|
+
retry: () => Promise<void>;
|
|
17
|
+
clearMessages: () => void;
|
|
18
|
+
}
|
|
19
|
+
export declare function useChat({ apiUrl, persistMessages, storageKeyPrefix, timeoutMs, translations, }: UseChatOptions): UseChatReturn;
|
|
20
|
+
export type { ChatMessage };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useMediaQuery(query: string): boolean;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export type UrlPattern = string | RegExp;
|
|
2
|
+
export type TriggerAction = "open" | {
|
|
3
|
+
greeting: string;
|
|
4
|
+
};
|
|
5
|
+
export type Trigger = {
|
|
6
|
+
on: "time";
|
|
7
|
+
seconds: number;
|
|
8
|
+
matchUrl?: UrlPattern;
|
|
9
|
+
action: TriggerAction;
|
|
10
|
+
} | {
|
|
11
|
+
on: "scroll";
|
|
12
|
+
percent: number;
|
|
13
|
+
matchUrl?: UrlPattern;
|
|
14
|
+
action: TriggerAction;
|
|
15
|
+
} | {
|
|
16
|
+
on: "exit-intent";
|
|
17
|
+
matchUrl?: UrlPattern;
|
|
18
|
+
action: TriggerAction;
|
|
19
|
+
} | {
|
|
20
|
+
on: "url";
|
|
21
|
+
pattern: UrlPattern;
|
|
22
|
+
action: TriggerAction;
|
|
23
|
+
};
|
|
24
|
+
interface UseTriggersOptions {
|
|
25
|
+
triggers?: Trigger[];
|
|
26
|
+
enabled: boolean;
|
|
27
|
+
onOpen: () => void;
|
|
28
|
+
onGreeting: (message: string) => void;
|
|
29
|
+
}
|
|
30
|
+
export declare function matchesUrl(pattern: UrlPattern, url: string): boolean;
|
|
31
|
+
export declare function useTriggers({ triggers, enabled, onOpen, onGreeting, }: UseTriggersOptions): void;
|
|
32
|
+
export {};
|
package/dist/i18n.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface ClaudiusTranslations {
|
|
2
|
+
title: string;
|
|
3
|
+
subtitle: string;
|
|
4
|
+
welcomeMessage: string;
|
|
5
|
+
closeChat: string;
|
|
6
|
+
chatMessages: string;
|
|
7
|
+
typingIndicator: string;
|
|
8
|
+
placeholder: string;
|
|
9
|
+
sendMessage: string;
|
|
10
|
+
typeYourMessage: string;
|
|
11
|
+
openChat: string;
|
|
12
|
+
dismissGreeting: string;
|
|
13
|
+
errorGeneric: string;
|
|
14
|
+
errorConnection: string;
|
|
15
|
+
errorTimeout: string;
|
|
16
|
+
errorRateLimitMinute: string;
|
|
17
|
+
errorRateLimitHour: string;
|
|
18
|
+
errorRetry: string;
|
|
19
|
+
}
|
|
20
|
+
export declare const defaultTranslations: ClaudiusTranslations;
|
|
21
|
+
export declare function createTranslations(overrides?: Partial<ClaudiusTranslations>): ClaudiusTranslations;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { ChatWidget } from "./components/ChatWidget";
|
|
2
|
+
export type { ChatWidgetProps, WidgetPosition, ClaudiusTranslations, } from "./components/ChatWidget";
|
|
3
|
+
export { defaultTranslations, createTranslations } from "./i18n";
|
|
4
|
+
export { locales, detectLocale, resolveTranslations } from "./locales";
|
|
5
|
+
export type { LocaleCode } from "./locales";
|
|
6
|
+
export type { Trigger, TriggerAction, UrlPattern } from "./hooks/useTriggers";
|
|
7
|
+
export { builtinThemes } from "./theme";
|
|
8
|
+
export type { ClaudiusTheme, ClaudiusThemeInput, BuiltinThemeName, ThemeColorToken, ThemeRadiusToken, ThemeShadowToken, ThemeFontToken, } from "./theme";
|
|
9
|
+
export { ChatApiClient } from "./api/client";
|
|
10
|
+
export type { ChatApiClientOptions } from "./api/client";
|
|
11
|
+
export { ChatApiError, DebounceError } from "./api/errors";
|
|
12
|
+
export type { Source, ChatMessage, ChatRequest, ChatResponse, ChatErrorResponse, } from "./api/types";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ClaudiusTranslations } from "../i18n";
|
|
2
|
+
export type LocaleCode = "en" | "es" | "fr" | "de";
|
|
3
|
+
export declare const locales: Record<LocaleCode, ClaudiusTranslations>;
|
|
4
|
+
export declare function detectLocale(): LocaleCode;
|
|
5
|
+
export interface ResolveTranslationsOptions {
|
|
6
|
+
locale?: LocaleCode;
|
|
7
|
+
translations?: Partial<ClaudiusTranslations>;
|
|
8
|
+
}
|
|
9
|
+
export declare function resolveTranslations(options?: ResolveTranslationsOptions): ClaudiusTranslations;
|
package/dist/main.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "./styles.css";
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { ChatMessage, ChatResponse } from "../api/types";
|
|
2
|
+
import { ChatApiError, DebounceError } from "../api/errors";
|
|
3
|
+
/**
|
|
4
|
+
* Programmable test double for `ChatApiClient`. Tests queue responses with
|
|
5
|
+
* `mockReply` / `mockError` / `mockTimeout`; calls to `sendMessage` consume
|
|
6
|
+
* one queued response per call (FIFO). When the queue is empty the client
|
|
7
|
+
* blocks on a `pending` promise so tests can drive loading-state assertions
|
|
8
|
+
* before resolving.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* const mock = new MockChatApiClient();
|
|
12
|
+
* installChatApiClientMock(mock); // before render / hook init
|
|
13
|
+
* mock.mockReply({ reply: "Hi!" });
|
|
14
|
+
* ...
|
|
15
|
+
*/
|
|
16
|
+
export type QueuedResponse = {
|
|
17
|
+
kind: "reply";
|
|
18
|
+
response: ChatResponse;
|
|
19
|
+
} | {
|
|
20
|
+
kind: "error";
|
|
21
|
+
error: ChatApiError | DebounceError | Error;
|
|
22
|
+
} | {
|
|
23
|
+
kind: "timeout";
|
|
24
|
+
} | {
|
|
25
|
+
kind: "pending";
|
|
26
|
+
promise: Promise<ChatResponse>;
|
|
27
|
+
};
|
|
28
|
+
export declare class MockChatApiClient {
|
|
29
|
+
readonly calls: ChatMessage[][];
|
|
30
|
+
sendMessage: import("vitest").Mock<(messages: ChatMessage[]) => Promise<ChatResponse>>;
|
|
31
|
+
private queue;
|
|
32
|
+
/** Queue a successful reply for the next sendMessage call. */
|
|
33
|
+
mockReply(response: ChatResponse): this;
|
|
34
|
+
/** Queue a ChatApiError (or arbitrary Error) for the next call. */
|
|
35
|
+
mockError(error: ChatApiError | DebounceError | Error): this;
|
|
36
|
+
/** Queue a timeout-style failure (status 0, code "TIMEOUT"). */
|
|
37
|
+
mockTimeout(message?: string): this;
|
|
38
|
+
/** Queue a network failure (status 0, code "NETWORK_ERROR"). */
|
|
39
|
+
mockNetworkError(message?: string): this;
|
|
40
|
+
/**
|
|
41
|
+
* Queue a deferred reply. Returns a `resolve` function the test can call
|
|
42
|
+
* later to settle the in-flight request — useful for asserting the
|
|
43
|
+
* loading state mid-flight.
|
|
44
|
+
*/
|
|
45
|
+
mockPending(): {
|
|
46
|
+
resolve: (response: ChatResponse) => void;
|
|
47
|
+
reject: (err: unknown) => void;
|
|
48
|
+
};
|
|
49
|
+
/** Total messages received across all sendMessage calls (last call). */
|
|
50
|
+
get lastCall(): ChatMessage[] | undefined;
|
|
51
|
+
/** Clear queued responses and call history. */
|
|
52
|
+
reset(): void;
|
|
53
|
+
private handleSend;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Install the mock as the implementation of `ChatApiClient` for the current
|
|
57
|
+
* test. Must be paired with `vi.mock("../api/client", ...)` at module
|
|
58
|
+
* top-level, since vi.mock is hoisted; this helper just wires the
|
|
59
|
+
* already-mocked constructor to return our instance.
|
|
60
|
+
*
|
|
61
|
+
* Most tests should call `useMockChatApiClient()` instead — it bundles the
|
|
62
|
+
* vi.mock setup with creation.
|
|
63
|
+
*/
|
|
64
|
+
export declare function installChatApiClientMock(mock: MockChatApiClient): Promise<void>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { THEME_COLOR_TOKENS, THEME_RADIUS_TOKENS, THEME_SHADOW_TOKENS, THEME_FONT_TOKENS, } from "./types";
|
|
2
|
+
export type { ClaudiusTheme, ClaudiusThemeInput, BuiltinThemeName, ThemeColorToken, ThemeRadiusToken, ThemeShadowToken, ThemeFontToken, } from "./types";
|
|
3
|
+
export { builtinThemes, isBuiltinThemeName } from "./themes";
|
|
4
|
+
export { resolveThemeInput, themeToCssVars, type ResolvedThemeInput, type ColorSchemeMode, } from "./resolve";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type ClaudiusTheme, type ClaudiusThemeInput } from "./types";
|
|
2
|
+
export type ColorSchemeMode = "light" | "dark" | "auto";
|
|
3
|
+
export interface ResolvedThemeInput {
|
|
4
|
+
mode: ColorSchemeMode;
|
|
5
|
+
theme?: ClaudiusTheme;
|
|
6
|
+
/** Set when the input is a URL to a theme JSON file (fetched separately). */
|
|
7
|
+
url?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Classifies the `theme` option. Mode strings keep their original meaning;
|
|
11
|
+
* built-in names map to their theme objects; any other string is a URL.
|
|
12
|
+
*/
|
|
13
|
+
export declare function resolveThemeInput(input: ClaudiusThemeInput | undefined): ResolvedThemeInput;
|
|
14
|
+
/**
|
|
15
|
+
* Converts a theme object into the --cl-* custom-property map applied to the
|
|
16
|
+
* widget root. Light colors mirror into the -dark variables so themed tokens
|
|
17
|
+
* survive dark mode; `colorsDark` overrides the mirror per token.
|
|
18
|
+
*/
|
|
19
|
+
export declare function themeToCssVars(theme: ClaudiusTheme): Record<string, string>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { BuiltinThemeName, ClaudiusTheme } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Built-in themes. `default` is intentionally empty: the baked-in token
|
|
4
|
+
* defaults (see tailwind.config.ts fallbacks and the dark block in
|
|
5
|
+
* styles.css) ARE the default theme.
|
|
6
|
+
*/
|
|
7
|
+
export declare const builtinThemes: Record<BuiltinThemeName, ClaudiusTheme>;
|
|
8
|
+
export declare function isBuiltinThemeName(value: string): value is BuiltinThemeName;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export declare const THEME_COLOR_TOKENS: readonly ["accent", "accentText", "accentSoft", "accentTextMuted", "surface", "surfaceMuted", "text", "textMuted", "border", "userBubble", "userBubbleText", "assistantBubble", "assistantBubbleText", "field", "error", "errorSurface", "errorText", "link", "scrim"];
|
|
2
|
+
export declare const THEME_RADIUS_TOKENS: readonly ["sm", "md", "lg", "full", "tail"];
|
|
3
|
+
export declare const THEME_SHADOW_TOKENS: readonly ["elevated", "floating", "floatingHover"];
|
|
4
|
+
export declare const THEME_FONT_TOKENS: readonly ["heading", "body"];
|
|
5
|
+
export type ThemeColorToken = (typeof THEME_COLOR_TOKENS)[number];
|
|
6
|
+
export type ThemeRadiusToken = (typeof THEME_RADIUS_TOKENS)[number];
|
|
7
|
+
export type ThemeShadowToken = (typeof THEME_SHADOW_TOKENS)[number];
|
|
8
|
+
export type ThemeFontToken = (typeof THEME_FONT_TOKENS)[number];
|
|
9
|
+
/**
|
|
10
|
+
* A Claudius design-token theme. Every value is a CSS string applied via
|
|
11
|
+
* --cl-* custom properties. `colors` apply to both light and dark modes
|
|
12
|
+
* unless `colorsDark` overrides a token for dark mode specifically.
|
|
13
|
+
*
|
|
14
|
+
* JSON theme files validate against
|
|
15
|
+
* https://claudius-docs.pages.dev/schema/theme.v1.json
|
|
16
|
+
*/
|
|
17
|
+
export interface ClaudiusTheme {
|
|
18
|
+
$schema?: string;
|
|
19
|
+
name?: string;
|
|
20
|
+
/** Initial color scheme this theme is designed for. Defaults to "light". */
|
|
21
|
+
colorScheme?: "light" | "dark" | "auto";
|
|
22
|
+
colors?: Partial<Record<ThemeColorToken, string>>;
|
|
23
|
+
colorsDark?: Partial<Record<ThemeColorToken, string>>;
|
|
24
|
+
radii?: Partial<Record<ThemeRadiusToken, string>>;
|
|
25
|
+
shadows?: Partial<Record<ThemeShadowToken, string>>;
|
|
26
|
+
fonts?: Partial<Record<ThemeFontToken, string>>;
|
|
27
|
+
}
|
|
28
|
+
export type BuiltinThemeName = "default" | "minimal" | "playful" | "corporate";
|
|
29
|
+
/**
|
|
30
|
+
* Everything the `theme` option accepts: the original color-scheme modes, a
|
|
31
|
+
* built-in theme name, an inline theme object, or a URL to a theme JSON file.
|
|
32
|
+
* `(string & {})` keeps literal autocomplete while allowing URLs.
|
|
33
|
+
*/
|
|
34
|
+
export type ClaudiusThemeInput = "light" | "dark" | "auto" | BuiltinThemeName | ClaudiusTheme | (string & {});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type ColorSchemeMode } from "./resolve";
|
|
2
|
+
import type { ClaudiusThemeInput } from "./types";
|
|
3
|
+
export interface UseThemeResult {
|
|
4
|
+
mode: ColorSchemeMode;
|
|
5
|
+
/** --cl-* custom properties to apply inline on the widget root. */
|
|
6
|
+
cssVars: Record<string, string>;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Resolves the `theme` option into a color-scheme mode and a set of CSS
|
|
10
|
+
* custom properties. URL inputs are fetched; any failure (network, JSON,
|
|
11
|
+
* shape) logs one console.error and leaves the default theme active so the
|
|
12
|
+
* widget never breaks because a theme file is unreachable.
|
|
13
|
+
*/
|
|
14
|
+
export declare function useTheme(input: ClaudiusThemeInput | undefined): UseThemeResult;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sanitization utilities for XSS prevention.
|
|
3
|
+
*
|
|
4
|
+
* The widget uses React element rendering (not innerHTML) which is inherently
|
|
5
|
+
* safe for text content. These utilities handle edge cases like URL schemes.
|
|
6
|
+
*/
|
|
7
|
+
/** Maximum allowed message length */
|
|
8
|
+
export declare const MAX_MESSAGE_LENGTH = 2000;
|
|
9
|
+
/**
|
|
10
|
+
* Validates and sanitizes a URL to prevent javascript:, data:, vbscript: attacks.
|
|
11
|
+
*
|
|
12
|
+
* @param url - The URL to sanitize
|
|
13
|
+
* @returns The original URL if safe, or null if potentially malicious
|
|
14
|
+
*/
|
|
15
|
+
export declare function sanitizeUrl(url: string): string | null;
|
|
16
|
+
/**
|
|
17
|
+
* Checks if a URL is safe to use as an href.
|
|
18
|
+
*
|
|
19
|
+
* @param url - The URL to check
|
|
20
|
+
* @returns true if the URL is safe, false otherwise
|
|
21
|
+
*/
|
|
22
|
+
export declare function isUrlSafe(url: string): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Validates message content length.
|
|
25
|
+
*
|
|
26
|
+
* @param content - The message content to validate
|
|
27
|
+
* @returns true if the content is within the allowed length
|
|
28
|
+
*/
|
|
29
|
+
export declare function isValidMessageLength(content: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Sanitizes message content by trimming and enforcing length limits.
|
|
32
|
+
*
|
|
33
|
+
* @param content - The message content to sanitize
|
|
34
|
+
* @returns Sanitized content, or empty string if invalid
|
|
35
|
+
*/
|
|
36
|
+
export declare function sanitizeMessageContent(content: string): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function stripAnnouncementFormatting(content: string): string;
|
package/package.json
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "claudius-chat-widget",
|
|
3
|
+
"version": "1.6.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Embeddable AI chat widget powered by Claude. Drop-in React component or standalone script embed, backed by a Cloudflare Worker.",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"react",
|
|
8
|
+
"chat-widget",
|
|
9
|
+
"ai-chat",
|
|
10
|
+
"claude",
|
|
11
|
+
"anthropic",
|
|
12
|
+
"cloudflare-workers",
|
|
13
|
+
"embeddable-widget",
|
|
14
|
+
"customer-support",
|
|
15
|
+
"typescript"
|
|
16
|
+
],
|
|
17
|
+
"author": "PAMulligan",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"homepage": "https://claudius-docs.pages.dev",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/PMDevSolutions/Claudius.git",
|
|
23
|
+
"directory": "widget"
|
|
24
|
+
},
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/PMDevSolutions/Claudius/issues"
|
|
27
|
+
},
|
|
28
|
+
"sideEffects": [
|
|
29
|
+
"**/*.css"
|
|
30
|
+
],
|
|
31
|
+
"main": "./dist/claudius.cjs",
|
|
32
|
+
"module": "./dist/claudius.js",
|
|
33
|
+
"types": "./dist/index.d.ts",
|
|
34
|
+
"exports": {
|
|
35
|
+
".": {
|
|
36
|
+
"types": "./dist/index.d.ts",
|
|
37
|
+
"import": "./dist/claudius.js",
|
|
38
|
+
"require": "./dist/claudius.cjs"
|
|
39
|
+
},
|
|
40
|
+
"./embed": "./dist/claudius.iife.js",
|
|
41
|
+
"./style.css": "./dist/claudius.css"
|
|
42
|
+
},
|
|
43
|
+
"files": [
|
|
44
|
+
"dist"
|
|
45
|
+
],
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"dev": "vite",
|
|
51
|
+
"build": "vite build && vite build --config vite.config.embed.ts && tsc --emitDeclarationOnly",
|
|
52
|
+
"build:lib": "vite build && tsc --emitDeclarationOnly",
|
|
53
|
+
"build:embed": "vite build --config vite.config.embed.ts",
|
|
54
|
+
"test": "vitest run",
|
|
55
|
+
"test:watch": "vitest",
|
|
56
|
+
"test:coverage": "vitest run --coverage",
|
|
57
|
+
"e2e": "playwright test",
|
|
58
|
+
"e2e:ui": "playwright test --ui",
|
|
59
|
+
"e2e:install": "playwright install chromium",
|
|
60
|
+
"lint": "eslint src/",
|
|
61
|
+
"lint:fix": "eslint src/ --fix",
|
|
62
|
+
"format": "prettier --write \"src/**/*.{ts,tsx,css}\"",
|
|
63
|
+
"format:check": "prettier --check \"src/**/*.{ts,tsx,css}\"",
|
|
64
|
+
"typecheck": "tsc --noEmit",
|
|
65
|
+
"storybook": "storybook dev -p 6006",
|
|
66
|
+
"build-storybook": "storybook build"
|
|
67
|
+
},
|
|
68
|
+
"peerDependencies": {
|
|
69
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
70
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
71
|
+
},
|
|
72
|
+
"devDependencies": {
|
|
73
|
+
"@eslint/js": "^9.24.0",
|
|
74
|
+
"@playwright/test": "^1.59.1",
|
|
75
|
+
"@storybook/react-vite": "10.4.1",
|
|
76
|
+
"@testing-library/jest-dom": "^6.6.0",
|
|
77
|
+
"@testing-library/react": "^16.3.0",
|
|
78
|
+
"@testing-library/user-event": "^14.6.0",
|
|
79
|
+
"@types/react": "^18.3.0",
|
|
80
|
+
"@types/react-dom": "^18.3.0",
|
|
81
|
+
"@vitejs/plugin-react": "^4.4.0",
|
|
82
|
+
"@vitest/coverage-v8": "^4.1.5",
|
|
83
|
+
"ajv": "^8.20.0",
|
|
84
|
+
"autoprefixer": "^10.4.0",
|
|
85
|
+
"eslint": "^9.24.0",
|
|
86
|
+
"eslint-config-prettier": "^10.1.0",
|
|
87
|
+
"eslint-plugin-jsx-a11y": "^6.10.2",
|
|
88
|
+
"eslint-plugin-react-hooks": "^5.2.0",
|
|
89
|
+
"eslint-plugin-react-refresh": "^0.4.20",
|
|
90
|
+
"jsdom": "^26.0.0",
|
|
91
|
+
"postcss": "^8.5.0",
|
|
92
|
+
"prettier": "^3.5.0",
|
|
93
|
+
"react": "^18.3.0",
|
|
94
|
+
"react-dom": "^18.3.0",
|
|
95
|
+
"storybook": "10.4.1",
|
|
96
|
+
"tailwindcss": "^3.4.0",
|
|
97
|
+
"typescript": "^5.8.0",
|
|
98
|
+
"typescript-eslint": "^8.30.0",
|
|
99
|
+
"vite": "^6.2.0",
|
|
100
|
+
"vitest": "^4.1.0"
|
|
101
|
+
}
|
|
102
|
+
}
|