helpdock 0.1.0 → 0.1.1

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 ADDED
@@ -0,0 +1,243 @@
1
+ # HelpDock
2
+
3
+ *A drop-in help desk widget. Bring your own backend.*
4
+
5
+ HelpDock is a lightweight, self-hosted help desk widget built as a TypeScript library. It provides an embeddable knowledge base and contact form that sits in the corner of any web page. Uses native Web Components with no React/Vue/Angular dependencies.
6
+
7
+ ## Features
8
+
9
+ - **Knowledge Base**: Searchable articles with categories and tags
10
+ - **Contact Form**: Configurable support ticket submission with file attachments
11
+ - **Mobile Responsive**: Adapts to desktop floating panel or mobile full-screen overlay
12
+ - **Self-Hosted**: Bring your own backend and datastore
13
+ - **TypeScript Support**: Full type definitions included
14
+ - **Analytics**: Track user interactions and events
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install helpdock
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ ```typescript
25
+ import { HelpDock, type AnalyticsEvent } from 'helpdock';
26
+
27
+ HelpDock.init({
28
+ articles: {
29
+ type: "function",
30
+ fetch: async () => ({
31
+ articles: [
32
+ {
33
+ id: "getting-started",
34
+ title: "Getting Started",
35
+ description: "Learn how to use HelpDock and integrate it into your application",
36
+ content: "# Getting Started\n\nWelcome to HelpDock! This guide will help you get up and running quickly.\n\n## Installation\n\n```bash\nnpm install helpdock\n```\n\n## Basic Setup\n\nImport and initialize the widget with your configuration.",
37
+ contentType: "markdown",
38
+ category: "Guide",
39
+ tags: ["introduction", "setup"],
40
+ },
41
+ {
42
+ id: "api-reference",
43
+ title: "API Reference",
44
+ description: "Complete API documentation for HelpDock configuration options",
45
+ content: "# API Reference\n\n## Configuration Options\n\n- `position`: Widget position ('topLeft', 'topRight', 'bottomLeft', 'bottomRight')\n- `closeOnEscape`: Close widget when Escape key is pressed\n- `analytics`: Track user interactions",
46
+ contentType: "markdown",
47
+ category: "Documentation",
48
+ tags: ["api", "reference"],
49
+ },
50
+ ],
51
+ }),
52
+ },
53
+
54
+ contact: {
55
+ title: "How can we help?",
56
+ subtitle: "We usually respond in a few hours",
57
+ fields: [
58
+ {
59
+ type: "text",
60
+ name: "name",
61
+ label: "Name",
62
+ required: true,
63
+ placeholder: "Enter your name",
64
+ },
65
+ {
66
+ type: "email",
67
+ name: "email",
68
+ label: "Email",
69
+ required: true,
70
+ placeholder: "your@email.com",
71
+ },
72
+ {
73
+ type: "select",
74
+ name: "topic",
75
+ label: "Topic",
76
+ required: true,
77
+ options: [
78
+ { value: "bug", label: "Bug Report" },
79
+ { value: "feature", label: "Feature Request" },
80
+ { value: "question", label: "Question" },
81
+ { value: "other", label: "Other" },
82
+ ],
83
+ },
84
+ {
85
+ type: "textarea",
86
+ name: "message",
87
+ label: "Message",
88
+ required: true,
89
+ placeholder: "How can we help you?",
90
+ rows: 5,
91
+ },
92
+ ],
93
+
94
+ attachments: {
95
+ mode: "inline",
96
+ maxFiles: 3,
97
+ maxSizeMB: 5,
98
+ accept: "image/*,.pdf,.doc,.docx",
99
+ },
100
+
101
+ submit: {
102
+ type: "function",
103
+ handler: async ({ fields, attachments }) => {
104
+ // Send to your backend
105
+ const response = await fetch('/api/contact', {
106
+ method: 'POST',
107
+ headers: { 'Content-Type': 'application/json' },
108
+ body: JSON.stringify({ fields, attachments }),
109
+ });
110
+
111
+ if (!response.ok) {
112
+ return {
113
+ success: false,
114
+ message: "Failed to send message. Please try again.",
115
+ };
116
+ }
117
+
118
+ return {
119
+ success: true,
120
+ message: "Thank you for contacting us!",
121
+ };
122
+ },
123
+ },
124
+ submitButtonText: "Send message",
125
+ },
126
+
127
+ analytics: {
128
+ enabled: true,
129
+ onEvent: (event: AnalyticsEvent) => {
130
+ console.log("[HelpDock Analytics]", event.type, event);
131
+
132
+ // Send to your analytics service
133
+ // analytics.track(event.type, event);
134
+ },
135
+ },
136
+
137
+ closeOnEscape: true,
138
+ position: "bottomRight",
139
+ });
140
+ ```
141
+
142
+ ## Script Tag Usage
143
+
144
+ ```html
145
+ <!DOCTYPE html>
146
+ <html lang="en">
147
+ <head>
148
+ <meta charset="UTF-8">
149
+ <title>My App</title>
150
+
151
+ <!-- Configure HelpDock before loading the script -->
152
+ <script>
153
+ window.HelpDockConfig = {
154
+ articles: {
155
+ type: "function",
156
+ fetch: async () => ({
157
+ articles: [
158
+ {
159
+ id: "getting-started",
160
+ title: "Getting Started",
161
+ description: "Learn how to use HelpDock and integrate it into your application",
162
+ content: "# Getting Started\n\nWelcome to HelpDock! This guide will help you get up and running quickly.\n\n## Installation\n\nInclude the script tag and configure the widget.",
163
+ contentType: "markdown",
164
+ category: "Guide",
165
+ tags: ["introduction", "setup"],
166
+ },
167
+ {
168
+ id: "troubleshooting",
169
+ title: "Troubleshooting",
170
+ description: "Common issues and how to resolve them",
171
+ content: "# Troubleshooting\n\n## Common Issues\n\n- **Widget not appearing**: Check that the script loaded successfully\n- **Articles not loading**: Verify your article data format\n- **Contact form errors**: Check your submit handler",
172
+ contentType: "markdown",
173
+ category: "Support",
174
+ tags: ["troubleshooting", "support"],
175
+ },
176
+ ],
177
+ }),
178
+ },
179
+
180
+ contact: {
181
+ title: "Need help?",
182
+ subtitle: "We're here to assist",
183
+ fields: [
184
+ {
185
+ type: "text",
186
+ name: "name",
187
+ label: "Name",
188
+ required: true,
189
+ placeholder: "Enter your name",
190
+ },
191
+ {
192
+ type: "email",
193
+ name: "email",
194
+ label: "Email",
195
+ required: true,
196
+ placeholder: "your@email.com",
197
+ },
198
+ {
199
+ type: "textarea",
200
+ name: "message",
201
+ label: "Message",
202
+ required: true,
203
+ placeholder: "How can we help you?",
204
+ rows: 4,
205
+ },
206
+ ],
207
+
208
+ submit: {
209
+ type: "function",
210
+ handler: async ({ fields }) => {
211
+ // Simulate API call
212
+ await new Promise(resolve => setTimeout(resolve, 1000));
213
+
214
+ console.log("Contact form submitted:", fields);
215
+
216
+ return {
217
+ success: true,
218
+ message: "Thank you for your message!",
219
+ };
220
+ },
221
+ },
222
+ },
223
+
224
+ closeOnEscape: true,
225
+ position: "bottomRight",
226
+ };
227
+ </script>
228
+
229
+ <!-- Load HelpDock -->
230
+ <script src="https://unpkg.com/helpdock/dist/helpdock.umd.js"></script>
231
+ </head>
232
+ <body>
233
+ <!-- Your app content -->
234
+ <h1>My Application</h1>
235
+
236
+ <!-- HelpDock will automatically initialize with the window.HelpDockConfig -->
237
+ </body>
238
+ </html>
239
+ ```
240
+
241
+ ## License
242
+
243
+ MIT
@@ -0,0 +1,20 @@
1
+ import { LitElement } from "lit";
2
+ /**
3
+ * An example element.
4
+ *
5
+ * @slot - This element has a slot
6
+ * @csspart button - The button
7
+ */
8
+ export declare class DemoPage extends LitElement {
9
+ /**
10
+ * Copy for the read the docs hint.
11
+ */
12
+ docsHint: string;
13
+ /**
14
+ * The number of times the button has been clicked.
15
+ */
16
+ count: number;
17
+ render(): import("lit-html").TemplateResult<1>;
18
+ private _onClick;
19
+ static styles: import("lit").CSSResult;
20
+ }
@@ -0,0 +1,18 @@
1
+ import { LitElement, nothing } from "lit";
2
+ /**
3
+ * Article detail view component
4
+ */
5
+ export declare class ArticleDetail extends LitElement {
6
+ expanded: boolean;
7
+ private articlesData?;
8
+ private get articles();
9
+ private get selectedArticle();
10
+ private closeArticle;
11
+ private toggleExpand;
12
+ private selectArticle;
13
+ private handleContentClick;
14
+ firstUpdated(): void;
15
+ disconnectedCallback(): void;
16
+ render(): import("lit-html").TemplateResult<1> | typeof nothing;
17
+ static styles: import("lit").CSSResult;
18
+ }
@@ -0,0 +1,19 @@
1
+ import { LitElement } from "lit";
2
+ /**
3
+ * Articles tab content - displays article list and article detail views
4
+ */
5
+ export declare class ArticlesTab extends LitElement {
6
+ expanded: boolean;
7
+ private articlesData?;
8
+ private config?;
9
+ private searchValue;
10
+ private hasTrackedArticlesView;
11
+ private get articles();
12
+ private get loading();
13
+ private selectArticle;
14
+ private handleSearchInput;
15
+ private handleContactClick;
16
+ updated(changedProperties: Map<string, any>): void;
17
+ render(): import("lit-html").TemplateResult<1>;
18
+ static styles: import("lit").CSSResult;
19
+ }
@@ -0,0 +1,31 @@
1
+ import { LitElement } from "lit";
2
+ /**
3
+ * Contact tab content - configurable contact form
4
+ */
5
+ export declare class ContactTab extends LitElement {
6
+ private config?;
7
+ private formValues;
8
+ private formErrors;
9
+ private isSubmitting;
10
+ private submitSuccess;
11
+ private submitError;
12
+ private attachedFiles;
13
+ private uploadedFiles;
14
+ private uploadingFiles;
15
+ private uploadErrors;
16
+ private hasTrackedContactView;
17
+ firstUpdated(): void;
18
+ private handleInput;
19
+ private handleFieldFocus;
20
+ private validateForm;
21
+ private handleFileSelect;
22
+ private handlePresignedUploads;
23
+ private removeAttachedFile;
24
+ private removeUploadedFile;
25
+ private clearUploadError;
26
+ private handleSubmit;
27
+ private renderField;
28
+ private renderAttachments;
29
+ render(): import("lit-html").TemplateResult<1>;
30
+ static styles: import("lit").CSSResult;
31
+ }
@@ -0,0 +1,33 @@
1
+ import { LitElement } from "lit";
2
+ import { type HelpDockConfig } from "../schema/config";
3
+ /**
4
+ * Main HelpDock widget component
5
+ *
6
+ * @slot - This element has a slot
7
+ * @csspart button - The button
8
+ */
9
+ export declare class HelpDock extends LitElement {
10
+ static init(config?: Partial<HelpDockConfig>, el?: HelpDock): void;
11
+ open: boolean;
12
+ private config;
13
+ private updateContextValue;
14
+ private articles;
15
+ private articlesLoading;
16
+ private selectedArticle;
17
+ private expanded;
18
+ private searchQuery;
19
+ private articleOpenTime;
20
+ private widgetOpenTrigger;
21
+ private articlesProvider;
22
+ connectedCallback(): void;
23
+ disconnectedCallback(): void;
24
+ private handleOpen;
25
+ private handleArticleOpen;
26
+ private handleArticleClose;
27
+ private handleToggleExpand;
28
+ private handleSearch;
29
+ updateConfig(config?: HelpDockConfig): void;
30
+ private fetchArticles;
31
+ render(): import("lit-html").TemplateResult<1>;
32
+ static styles: import("lit").CSSResult;
33
+ }
@@ -0,0 +1,20 @@
1
+ import { LitElement } from "lit";
2
+ import "./ArticlesTab";
3
+ import "./ArticleDetail";
4
+ import "./ContactTab";
5
+ /**
6
+ * Floating panel that slides up from the widget button
7
+ */
8
+ export declare class Panel extends LitElement {
9
+ open: boolean;
10
+ expanded: boolean;
11
+ articleOpen: boolean;
12
+ private config?;
13
+ private activeTab;
14
+ private setActiveTab;
15
+ private switchTabListener;
16
+ connectedCallback(): void;
17
+ disconnectedCallback(): void;
18
+ render(): import("lit-html").TemplateResult<1>;
19
+ static styles: import("lit").CSSResult;
20
+ }
@@ -0,0 +1,11 @@
1
+ import { LitElement } from "lit";
2
+ /**
3
+ * Floating button that appears in collapsed state
4
+ * Click opens the widget panel
5
+ */
6
+ export declare class WidgetButton extends LitElement {
7
+ open: boolean;
8
+ private _onClick;
9
+ render(): import("lit-html").TemplateResult<1>;
10
+ static styles: import("lit").CSSResult;
11
+ }
@@ -0,0 +1,11 @@
1
+ import type { Article } from "../schema/article";
2
+ export interface ArticlesContextValue {
3
+ articles: Article[];
4
+ loading: boolean;
5
+ searchQuery: string;
6
+ filteredArticles: Article[];
7
+ selectedArticle: Article | null;
8
+ }
9
+ export declare const articlesContext: {
10
+ __context__: ArticlesContextValue;
11
+ };
@@ -0,0 +1,242 @@
1
+ export declare const configContext: {
2
+ __context__: {
3
+ position: "bottomRight" | "bottomLeft";
4
+ offset: {
5
+ x: number;
6
+ y: number;
7
+ };
8
+ panelWidth: number;
9
+ panelHeight: number;
10
+ mobileBreakpoint: number;
11
+ articles: {
12
+ type: "function";
13
+ fetch: import("zod/v4/core").$InferOuterFunctionType<import("zod/mini").ZodMiniTuple<[], null>, import("zod/mini").ZodMiniPromise<import("zod/mini").ZodMiniObject<{
14
+ articles: import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
15
+ id: import("zod/mini").ZodMiniString<string>;
16
+ title: import("zod/mini").ZodMiniString<string>;
17
+ description: import("zod/mini").ZodMiniString<string>;
18
+ category: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
19
+ tags: import("zod/mini").ZodMiniDefault<import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniString<string>>>;
20
+ updatedAt: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniISODateTime>;
21
+ content: import("zod/mini").ZodMiniString<string>;
22
+ contentType: import("zod/mini").ZodMiniDefault<import("zod/mini").ZodMiniEnum<{
23
+ markdown: "markdown";
24
+ html: "html";
25
+ }>>;
26
+ }, import("zod/v4/core").$strip>>;
27
+ }, import("zod/v4/core").$strip>>>;
28
+ };
29
+ defaultTab: "articles" | "contact";
30
+ closeOnEscape: boolean;
31
+ closeOnClickOutside: boolean;
32
+ contact?: {
33
+ title: string;
34
+ fields: ({
35
+ name: string;
36
+ label: string;
37
+ required: boolean;
38
+ type: "text";
39
+ placeholder?: string | undefined;
40
+ } | {
41
+ name: string;
42
+ label: string;
43
+ required: boolean;
44
+ type: "email";
45
+ placeholder?: string | undefined;
46
+ } | {
47
+ name: string;
48
+ label: string;
49
+ required: boolean;
50
+ type: "textarea";
51
+ rows: number;
52
+ placeholder?: string | undefined;
53
+ } | {
54
+ name: string;
55
+ label: string;
56
+ required: boolean;
57
+ type: "select";
58
+ options: {
59
+ value: string;
60
+ label: string;
61
+ }[];
62
+ placeholder?: string | undefined;
63
+ })[];
64
+ attachments: {
65
+ mode: "disabled";
66
+ } | {
67
+ mode: "inline";
68
+ maxFiles: number;
69
+ maxSizeMB: number;
70
+ accept?: string | undefined;
71
+ } | {
72
+ mode: "presigned";
73
+ maxFiles: number;
74
+ maxSizeMB: number;
75
+ getUploadUrl: import("zod/v4/core").$InferOuterFunctionType<import("zod/mini").ZodMiniTuple<[import("zod/mini").ZodMiniObject<{
76
+ filename: import("zod/mini").ZodMiniString<string>;
77
+ contentType: import("zod/mini").ZodMiniString<string>;
78
+ size: import("zod/mini").ZodMiniNumber<number>;
79
+ }, import("zod/v4/core").$strip>], null>, import("zod/mini").ZodMiniPromise<import("zod/mini").ZodMiniObject<{
80
+ uploadUrl: import("zod/mini").ZodMiniString<string>;
81
+ fileUrl: import("zod/mini").ZodMiniString<string>;
82
+ }, import("zod/v4/core").$strip>>>;
83
+ accept?: string | undefined;
84
+ };
85
+ submit: {
86
+ type: "function";
87
+ handler: import("zod/v4/core").$InferOuterFunctionType<import("zod/mini").ZodMiniTuple<[import("zod/mini").ZodMiniObject<{
88
+ fields: import("zod/mini").ZodMiniRecord<import("zod/mini").ZodMiniString<string>, import("zod/mini").ZodMiniUnknown>;
89
+ attachments: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniCustom<File, File>>, import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
90
+ filename: import("zod/mini").ZodMiniString<string>;
91
+ url: import("zod/mini").ZodMiniString<string>;
92
+ contentType: import("zod/mini").ZodMiniString<string>;
93
+ size: import("zod/mini").ZodMiniNumber<number>;
94
+ }, import("zod/v4/core").$strip>>]>>;
95
+ }, import("zod/v4/core").$strip>], null>, import("zod/mini").ZodMiniPromise<import("zod/mini").ZodMiniObject<{
96
+ success: import("zod/mini").ZodMiniDefault<import("zod/mini").ZodMiniBoolean<boolean>>;
97
+ message: import("zod/mini").ZodMiniString<string>;
98
+ }, import("zod/v4/core").$strip>>>;
99
+ };
100
+ submitButtonText: string;
101
+ subtitle?: string | undefined;
102
+ } | undefined;
103
+ icons?: {
104
+ widget: string | import("lit-html").TemplateResult<1>;
105
+ close: string | import("lit-html").TemplateResult<1>;
106
+ } | undefined;
107
+ labels?: {
108
+ articlesTab: string;
109
+ contactTab: string;
110
+ searchPlaceholder: string;
111
+ noResults: string;
112
+ loading: string;
113
+ backToArticles: string;
114
+ emptyStateTitle: string;
115
+ emptyStateSearchMessage: string;
116
+ emptyStateNoArticlesMessage: string;
117
+ getInTouch: string;
118
+ } | undefined;
119
+ analytics?: {
120
+ enabled: boolean;
121
+ onEvent?: import("zod/v4/core").$InferOuterFunctionType<import("zod/mini").ZodMiniTuple<[import("zod/mini").ZodMiniDiscriminatedUnion<[import("zod/mini").ZodMiniObject<{
122
+ type: import("zod/mini").ZodMiniLiteral<"widget:open">;
123
+ trigger: import("zod/mini").ZodMiniEnum<{
124
+ button_click: "button_click";
125
+ programmatic: "programmatic";
126
+ auto: "auto";
127
+ }>;
128
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
129
+ type: import("zod/mini").ZodMiniLiteral<"widget:close">;
130
+ trigger: import("zod/mini").ZodMiniEnum<{
131
+ button_click: "button_click";
132
+ programmatic: "programmatic";
133
+ escape: "escape";
134
+ click_outside: "click_outside";
135
+ }>;
136
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
137
+ type: import("zod/mini").ZodMiniLiteral<"tab:change">;
138
+ from: import("zod/mini").ZodMiniEnum<{
139
+ articles: "articles";
140
+ contact: "contact";
141
+ }>;
142
+ to: import("zod/mini").ZodMiniEnum<{
143
+ articles: "articles";
144
+ contact: "contact";
145
+ }>;
146
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
147
+ type: import("zod/mini").ZodMiniLiteral<"articles:view">;
148
+ articleCount: import("zod/mini").ZodMiniNumber<number>;
149
+ hasSearchQuery: import("zod/mini").ZodMiniBoolean<boolean>;
150
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
151
+ type: import("zod/mini").ZodMiniLiteral<"article:click">;
152
+ articleId: import("zod/mini").ZodMiniString<string>;
153
+ articleTitle: import("zod/mini").ZodMiniString<string>;
154
+ articleCategory: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
155
+ fromSearch: import("zod/mini").ZodMiniBoolean<boolean>;
156
+ searchQuery: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
157
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
158
+ type: import("zod/mini").ZodMiniLiteral<"article:view">;
159
+ articleId: import("zod/mini").ZodMiniString<string>;
160
+ articleTitle: import("zod/mini").ZodMiniString<string>;
161
+ articleCategory: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
162
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
163
+ type: import("zod/mini").ZodMiniLiteral<"article:close">;
164
+ articleId: import("zod/mini").ZodMiniString<string>;
165
+ articleTitle: import("zod/mini").ZodMiniString<string>;
166
+ timeSpent: import("zod/mini").ZodMiniNumber<number>;
167
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
168
+ type: import("zod/mini").ZodMiniLiteral<"article:link:click">;
169
+ articleId: import("zod/mini").ZodMiniString<string>;
170
+ articleTitle: import("zod/mini").ZodMiniString<string>;
171
+ linkUrl: import("zod/mini").ZodMiniString<string>;
172
+ linkText: import("zod/mini").ZodMiniString<string>;
173
+ external: import("zod/mini").ZodMiniBoolean<boolean>;
174
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
175
+ type: import("zod/mini").ZodMiniLiteral<"search:query">;
176
+ query: import("zod/mini").ZodMiniString<string>;
177
+ resultCount: import("zod/mini").ZodMiniNumber<number>;
178
+ timeToResults: import("zod/mini").ZodMiniNumber<number>;
179
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
180
+ type: import("zod/mini").ZodMiniLiteral<"search:result:click">;
181
+ query: import("zod/mini").ZodMiniString<string>;
182
+ articleId: import("zod/mini").ZodMiniString<string>;
183
+ articleTitle: import("zod/mini").ZodMiniString<string>;
184
+ resultPosition: import("zod/mini").ZodMiniNumber<number>;
185
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
186
+ type: import("zod/mini").ZodMiniLiteral<"search:clear">;
187
+ previousQuery: import("zod/mini").ZodMiniString<string>;
188
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
189
+ type: import("zod/mini").ZodMiniLiteral<"contact:view">;
190
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
191
+ type: import("zod/mini").ZodMiniLiteral<"contact:field:focus">;
192
+ fieldName: import("zod/mini").ZodMiniString<string>;
193
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
194
+ type: import("zod/mini").ZodMiniLiteral<"contact:submit">;
195
+ hasName: import("zod/mini").ZodMiniBoolean<boolean>;
196
+ hasEmail: import("zod/mini").ZodMiniBoolean<boolean>;
197
+ hasMessage: import("zod/mini").ZodMiniBoolean<boolean>;
198
+ messageLength: import("zod/mini").ZodMiniNumber<number>;
199
+ attachmentCount: import("zod/mini").ZodMiniNumber<number>;
200
+ totalAttachmentSize: import("zod/mini").ZodMiniNumber<number>;
201
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
202
+ type: import("zod/mini").ZodMiniLiteral<"contact:success">;
203
+ responseTime: import("zod/mini").ZodMiniNumber<number>;
204
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
205
+ type: import("zod/mini").ZodMiniLiteral<"contact:error">;
206
+ errorType: import("zod/mini").ZodMiniString<string>;
207
+ errorMessage: import("zod/mini").ZodMiniString<string>;
208
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
209
+ type: import("zod/mini").ZodMiniLiteral<"contact:attachment:add">;
210
+ fileName: import("zod/mini").ZodMiniString<string>;
211
+ fileSize: import("zod/mini").ZodMiniNumber<number>;
212
+ fileType: import("zod/mini").ZodMiniString<string>;
213
+ attachmentCount: import("zod/mini").ZodMiniNumber<number>;
214
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
215
+ type: import("zod/mini").ZodMiniLiteral<"contact:attachment:remove">;
216
+ fileName: import("zod/mini").ZodMiniString<string>;
217
+ attachmentCount: import("zod/mini").ZodMiniNumber<number>;
218
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
219
+ type: import("zod/mini").ZodMiniLiteral<"contact:attachment:upload:start">;
220
+ fileName: import("zod/mini").ZodMiniString<string>;
221
+ fileSize: import("zod/mini").ZodMiniNumber<number>;
222
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
223
+ type: import("zod/mini").ZodMiniLiteral<"contact:attachment:upload:success">;
224
+ fileName: import("zod/mini").ZodMiniString<string>;
225
+ uploadTime: import("zod/mini").ZodMiniNumber<number>;
226
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
227
+ type: import("zod/mini").ZodMiniLiteral<"contact:attachment:upload:error">;
228
+ fileName: import("zod/mini").ZodMiniString<string>;
229
+ errorMessage: import("zod/mini").ZodMiniString<string>;
230
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
231
+ type: import("zod/mini").ZodMiniLiteral<"filter:category">;
232
+ category: import("zod/mini").ZodMiniString<string>;
233
+ resultCount: import("zod/mini").ZodMiniNumber<number>;
234
+ }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniObject<{
235
+ type: import("zod/mini").ZodMiniLiteral<"filter:tag">;
236
+ tag: import("zod/mini").ZodMiniString<string>;
237
+ resultCount: import("zod/mini").ZodMiniNumber<number>;
238
+ }, import("zod/v4/core").$strip>], "type">], null>, import("zod/mini").ZodMiniVoid> | undefined;
239
+ getSessionId?: import("zod/v4/core").$InferOuterFunctionType<import("zod/mini").ZodMiniTuple<[], null>, import("zod/mini").ZodMiniString<string>> | undefined;
240
+ } | undefined;
241
+ } | null;
242
+ };
package/dist/helpdock.js CHANGED
@@ -2208,8 +2208,8 @@ const ln = m({
2208
2208
  icons: S(ft(
2209
2209
  S(ht(Fn)),
2210
2210
  pt((t) => ({
2211
- widget: p`<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
2212
- <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/>
2211
+ widget: p`<svg width="24" height="24" viewBox="5 2 14 20" fill="currentColor">
2212
+ <path d="M12 4C9.243 4 7 6.243 7 9h2c0-1.654 1.346-3 3-3s3 1.346 3 3c0 1.069-.454 1.465-1.481 2.255-.382.294-.813.626-1.226 1.038C10.981 13.604 10.995 14.897 11 15v2h2v-2.009c0-.024.023-.601.707-1.284.32-.32.682-.598 1.031-.867C15.798 12.024 17 11.1 17 9c0-2.757-2.243-5-5-5zm-1 14h2v2h-2z"/>
2213
2213
  </svg>`,
2214
2214
  close: p`<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
2215
2215
  <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>