chatgram-widget 1.0.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 +282 -0
- package/dist/chatgram-widget.cjs.js +2 -0
- package/dist/chatgram-widget.cjs.js.map +1 -0
- package/dist/chatgram-widget.css +0 -0
- package/dist/chatgram-widget.esm.js +2 -0
- package/dist/chatgram-widget.esm.js.map +1 -0
- package/dist/chatgram-widget.umd.js +2 -0
- package/dist/chatgram-widget.umd.js.map +1 -0
- package/dist/types/core/api.d.ts +15 -0
- package/dist/types/core/config.d.ts +6 -0
- package/dist/types/core/events.d.ts +15 -0
- package/dist/types/core/rate-limiter.d.ts +16 -0
- package/dist/types/core/types.d.ts +176 -0
- package/dist/types/index.d.ts +84 -0
- package/dist/types/styles/widget-css.d.ts +1 -0
- package/dist/types/ui/icons.d.ts +6 -0
- package/dist/types/ui/modal.d.ts +63 -0
- package/dist/types/ui/trigger.d.ts +14 -0
- package/dist/types/utils/dom.d.ts +26 -0
- package/dist/types/utils/sanitize.d.ts +38 -0
- package/package.json +81 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { ChatgramConfig, WidgetState } from '../core/types';
|
|
2
|
+
import { EventEmitter } from '../core/events';
|
|
3
|
+
/**
|
|
4
|
+
* The Modal class manages the entire widget UI lifecycle.
|
|
5
|
+
*
|
|
6
|
+
* Architecture:
|
|
7
|
+
* - Uses Shadow DOM for CSS isolation
|
|
8
|
+
* - Focus trap keeps Tab cycling within modal
|
|
9
|
+
* - Scroll lock prevents body scrolling without layout shift
|
|
10
|
+
* - Honeypot field catches bots
|
|
11
|
+
* - Rate limiter prevents spam
|
|
12
|
+
* - Anti-bot timing check
|
|
13
|
+
* - Full ARIA attributes for screen readers
|
|
14
|
+
* - Keyboard navigation (Escape to close, Tab to navigate, Enter to select)
|
|
15
|
+
*/
|
|
16
|
+
export declare class Modal {
|
|
17
|
+
private config;
|
|
18
|
+
private events;
|
|
19
|
+
private rateLimiter;
|
|
20
|
+
private hostEl;
|
|
21
|
+
private shadow;
|
|
22
|
+
private overlay;
|
|
23
|
+
private modalEl;
|
|
24
|
+
private bodyContainer;
|
|
25
|
+
private isOpen;
|
|
26
|
+
private state;
|
|
27
|
+
private selectedCategory;
|
|
28
|
+
private mountTime;
|
|
29
|
+
private instanceId;
|
|
30
|
+
private destroyFocusTrap;
|
|
31
|
+
private boundEscapeHandler;
|
|
32
|
+
private emailInput;
|
|
33
|
+
private nameInput;
|
|
34
|
+
private subjectInput;
|
|
35
|
+
private messageInput;
|
|
36
|
+
private honeypotInput;
|
|
37
|
+
private charCountText;
|
|
38
|
+
private charCountFill;
|
|
39
|
+
private submitBtn;
|
|
40
|
+
private categoryBtns;
|
|
41
|
+
constructor(config: ChatgramConfig, events: EventEmitter);
|
|
42
|
+
open(): void;
|
|
43
|
+
close(): void;
|
|
44
|
+
destroy(): void;
|
|
45
|
+
updateConfig(newConfig: ChatgramConfig): void;
|
|
46
|
+
updateTheme(theme: ChatgramConfig['theme']): void;
|
|
47
|
+
getState(): WidgetState;
|
|
48
|
+
isVisible(): boolean;
|
|
49
|
+
private mount;
|
|
50
|
+
private applyTheme;
|
|
51
|
+
private buildHeader;
|
|
52
|
+
private buildFormView;
|
|
53
|
+
private buildField;
|
|
54
|
+
private selectCategory;
|
|
55
|
+
private updateCharCount;
|
|
56
|
+
private validate;
|
|
57
|
+
private showFieldError;
|
|
58
|
+
private showTextareaError;
|
|
59
|
+
private clearFieldError;
|
|
60
|
+
private setState;
|
|
61
|
+
private showStateView;
|
|
62
|
+
private handleSubmit;
|
|
63
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ResolvedConfig } from '../core/types';
|
|
2
|
+
export declare class TriggerButton {
|
|
3
|
+
private el;
|
|
4
|
+
private hostEl;
|
|
5
|
+
private shadow;
|
|
6
|
+
private config;
|
|
7
|
+
private onClick;
|
|
8
|
+
constructor(config: ResolvedConfig, onClick: () => void);
|
|
9
|
+
mount(): void;
|
|
10
|
+
destroy(): void;
|
|
11
|
+
show(): void;
|
|
12
|
+
hide(): void;
|
|
13
|
+
updateTheme(primaryColor: string): void;
|
|
14
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a DOM element with attributes.
|
|
3
|
+
* - 'textContent' is always safe (no XSS)
|
|
4
|
+
* - 'innerHTML' is ONLY used for trusted SVG icons (never user input)
|
|
5
|
+
*/
|
|
6
|
+
export declare function el<K extends keyof HTMLElementTagNameMap>(tag: K, attrs?: Record<string, string>, children?: (HTMLElement | string)[]): HTMLElementTagNameMap[K];
|
|
7
|
+
/**
|
|
8
|
+
* Applies CSS custom properties to an element, sanitizing values.
|
|
9
|
+
*/
|
|
10
|
+
export declare function applyThemeVars(element: HTMLElement, vars: Record<string, string>): void;
|
|
11
|
+
/**
|
|
12
|
+
* Creates a focus trap within a container element.
|
|
13
|
+
* Returns a cleanup function to remove the trap.
|
|
14
|
+
*/
|
|
15
|
+
export declare function createFocusTrap(container: HTMLElement): () => void;
|
|
16
|
+
/**
|
|
17
|
+
* Locks body scroll without layout shift.
|
|
18
|
+
* Accounts for scrollbar width to prevent content jumping.
|
|
19
|
+
* Supports nested lock/unlock (reference counted).
|
|
20
|
+
*/
|
|
21
|
+
export declare function lockScroll(): void;
|
|
22
|
+
/**
|
|
23
|
+
* Unlocks body scroll, restoring previous state.
|
|
24
|
+
*/
|
|
25
|
+
export declare function unlockScroll(): void;
|
|
26
|
+
export declare function uid(prefix?: string): string;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Escapes HTML entities to prevent XSS.
|
|
3
|
+
* Used when inserting any dynamic text into the DOM.
|
|
4
|
+
*/
|
|
5
|
+
export declare function escapeHtml(str: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* Sanitizes user input for DOM display.
|
|
8
|
+
* Trims, removes null bytes, and escapes HTML.
|
|
9
|
+
*/
|
|
10
|
+
export declare function sanitizeForDom(input: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Sanitizes user input for API payload.
|
|
13
|
+
* Trims and strips null bytes, but does NOT escape HTML
|
|
14
|
+
* (server-side should handle its own escaping).
|
|
15
|
+
*/
|
|
16
|
+
export declare function sanitizeForPayload(input: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* RFC 5322 simplified email validation.
|
|
19
|
+
* Rejects emails > 254 chars and common injection patterns.
|
|
20
|
+
*/
|
|
21
|
+
export declare function isValidEmail(email: string): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Checks that a string is non-empty after trimming.
|
|
24
|
+
*/
|
|
25
|
+
export declare function isNonEmpty(value: unknown): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Checks that a string is within max length.
|
|
28
|
+
*/
|
|
29
|
+
export declare function isWithinLength(value: string, max: number): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Validates a CSS color value (basic check — hex, rgb, hsl, named colors).
|
|
32
|
+
* Used to prevent injection via theme config.
|
|
33
|
+
*/
|
|
34
|
+
export declare function isSafeCssValue(value: string): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Sanitizes a theme object to prevent CSS injection.
|
|
37
|
+
*/
|
|
38
|
+
export declare function sanitizeThemeValue(value: string): string;
|
package/package.json
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "chatgram-widget",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Production-grade embeddable contact form widget for Chatgram — React, Vue, vanilla JS",
|
|
5
|
+
"author": "brandID <brandid.ca@gmail.com>",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"main": "dist/chatgram-widget.cjs.js",
|
|
8
|
+
"module": "dist/chatgram-widget.esm.js",
|
|
9
|
+
"unpkg": "dist/chatgram-widget.umd.js",
|
|
10
|
+
"jsdelivr": "dist/chatgram-widget.umd.js",
|
|
11
|
+
"types": "dist/types/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"import": "./dist/chatgram-widget.esm.js",
|
|
15
|
+
"require": "./dist/chatgram-widget.cjs.js",
|
|
16
|
+
"types": "./dist/types/index.d.ts"
|
|
17
|
+
},
|
|
18
|
+
"./style.css": "./dist/chatgram-widget.css"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
23
|
+
"sideEffects": [
|
|
24
|
+
"*.css"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "rollup -c rollup.config.mjs",
|
|
28
|
+
"build:watch": "rollup -c rollup.config.mjs -w",
|
|
29
|
+
"dev": "rollup -c rollup.config.mjs -w",
|
|
30
|
+
"typecheck": "tsc --noEmit",
|
|
31
|
+
"test": "vitest run",
|
|
32
|
+
"test:watch": "vitest",
|
|
33
|
+
"test:coverage": "vitest run --coverage",
|
|
34
|
+
"lint": "eslint src/ --ext .ts",
|
|
35
|
+
"prepublishOnly": "npm run build",
|
|
36
|
+
"size": "size-limit",
|
|
37
|
+
"clean": "rm -rf dist"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
41
|
+
"@rollup/plugin-typescript": "^11.1.6",
|
|
42
|
+
"@size-limit/preset-small-lib": "^11.0.0",
|
|
43
|
+
"@vitest/coverage-v8": "^1.0.0",
|
|
44
|
+
"jsdom": "^23.0.0",
|
|
45
|
+
"rollup": "^4.9.0",
|
|
46
|
+
"rollup-plugin-postcss": "^4.0.2",
|
|
47
|
+
"size-limit": "^11.0.0",
|
|
48
|
+
"tslib": "^2.8.1",
|
|
49
|
+
"typescript": "^5.3.0",
|
|
50
|
+
"vitest": "^1.0.0"
|
|
51
|
+
},
|
|
52
|
+
"size-limit": [
|
|
53
|
+
{
|
|
54
|
+
"path": "dist/chatgram-widget.esm.js",
|
|
55
|
+
"limit": "10 kB"
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
"keywords": [
|
|
59
|
+
"chatgram",
|
|
60
|
+
"contact-form",
|
|
61
|
+
"widget",
|
|
62
|
+
"embeddable",
|
|
63
|
+
"support",
|
|
64
|
+
"feedback",
|
|
65
|
+
"brandid",
|
|
66
|
+
"modal",
|
|
67
|
+
"vanilla-js",
|
|
68
|
+
"react",
|
|
69
|
+
"vue",
|
|
70
|
+
"web-component",
|
|
71
|
+
"shadow-dom"
|
|
72
|
+
],
|
|
73
|
+
"repository": {
|
|
74
|
+
"type": "git",
|
|
75
|
+
"url": "https://github.com/brandid/chatgram-widget"
|
|
76
|
+
},
|
|
77
|
+
"homepage": "https://brandid.app/chatgram",
|
|
78
|
+
"bugs": {
|
|
79
|
+
"url": "https://github.com/brandid/chatgram-widget/issues"
|
|
80
|
+
}
|
|
81
|
+
}
|