daply-ui 0.0.0 → 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 +395 -59
- package/dist/daply-ui.js +266 -3
- package/dist/daply-ui.umd.cjs +5 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,73 +1,409 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @daply-ui
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A React component library for building beautiful, modern forms that integrate seamlessly with the Daply backend. Features professional styling inspired by Daply forms with automatic light/dark theme support.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## ✨ Features
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
7
|
+
- 🎨 **Modern Design** - Clean, professional styling matching Daply form aesthetics
|
|
8
|
+
- 🌓 **Theme Support** - Automatic light/dark theme adaptation
|
|
9
|
+
- ✅ **Built-in Validation** - Required fields, email, URL validation
|
|
10
|
+
- 🔧 **Custom Validation** - Define your own validation rules
|
|
11
|
+
- 🚀 **API Integration** - Automatic submission to Daply backend
|
|
12
|
+
- 📱 **Responsive** - Mobile-first design that works everywhere
|
|
13
|
+
- 💪 **TypeScript** - Full type safety and IntelliSense support
|
|
14
|
+
- 🎯 **Customizable** - Override any styling with custom classes
|
|
9
15
|
|
|
10
|
-
##
|
|
16
|
+
## Installation
|
|
11
17
|
|
|
12
|
-
|
|
18
|
+
```bash
|
|
19
|
+
npm install daply-ui
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**No additional dependencies required!** The library uses inline styles, so it works out of the box without needing Tailwind CSS or any other CSS framework.
|
|
23
|
+
|
|
24
|
+
## Components
|
|
25
|
+
|
|
26
|
+
### Form Component
|
|
27
|
+
|
|
28
|
+
A fully-featured form component with built-in validation and Daply backend integration.
|
|
29
|
+
|
|
30
|
+
## Basic Usage
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import { Form } from 'daply-ui';
|
|
34
|
+
|
|
35
|
+
function App() {
|
|
36
|
+
return (
|
|
37
|
+
<Form
|
|
38
|
+
formId="contact-form"
|
|
39
|
+
siteId="my-website"
|
|
40
|
+
baseUrl="https://api.daply.com"
|
|
41
|
+
apiToken="your-api-token-here"
|
|
42
|
+
encryptedDbName="ff95d16da2340fe621ce03a61b9e6ee5b2c5dacbb12bd1914cb3dae6e5ad1bea73029edd7bf8bae1eefaa23cde52ea28"
|
|
43
|
+
theme="dark" // 'light', 'dark', or 'auto' (default)
|
|
44
|
+
fields={[
|
|
45
|
+
{
|
|
46
|
+
name: "name",
|
|
47
|
+
type: "text",
|
|
48
|
+
label: "Name",
|
|
49
|
+
required: true,
|
|
50
|
+
placeholder: "Enter your name"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: "email",
|
|
54
|
+
type: "email",
|
|
55
|
+
label: "Email",
|
|
56
|
+
required: true,
|
|
57
|
+
placeholder: "your.email@example.com"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: "subject",
|
|
61
|
+
type: "text",
|
|
62
|
+
label: "Subject",
|
|
63
|
+
required: true,
|
|
64
|
+
placeholder: "What's this about?"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: "message",
|
|
68
|
+
type: "textarea",
|
|
69
|
+
label: "Message",
|
|
70
|
+
required: true,
|
|
71
|
+
rows: 6,
|
|
72
|
+
placeholder: "Your message here..."
|
|
73
|
+
}
|
|
74
|
+
]}
|
|
75
|
+
onSuccess={(response) => {
|
|
76
|
+
console.log("Form submitted successfully!", response);
|
|
77
|
+
alert("Thank you for your submission!");
|
|
78
|
+
}}
|
|
79
|
+
onError={(error) => {
|
|
80
|
+
console.error("Form submission failed:", error);
|
|
81
|
+
alert("Something went wrong. Please try again.");
|
|
82
|
+
}}
|
|
83
|
+
/>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
```
|
|
13
87
|
|
|
14
|
-
##
|
|
88
|
+
## Advanced Usage
|
|
15
89
|
|
|
16
|
-
|
|
90
|
+
### Custom Styling
|
|
17
91
|
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
92
|
+
```tsx
|
|
93
|
+
<Form
|
|
94
|
+
formId="styled-form"
|
|
95
|
+
siteId="my-website"
|
|
96
|
+
baseUrl="https://api.daply.com"
|
|
97
|
+
apiToken="your-api-token-here"
|
|
98
|
+
fields={[
|
|
99
|
+
{
|
|
100
|
+
name: "username",
|
|
101
|
+
type: "text",
|
|
102
|
+
label: "Username",
|
|
103
|
+
required: true,
|
|
104
|
+
className: "custom-input-class"
|
|
105
|
+
}
|
|
106
|
+
]}
|
|
107
|
+
formClassName="my-custom-form"
|
|
108
|
+
submitButtonClassName="my-custom-button"
|
|
109
|
+
submitButtonText="Send Message"
|
|
110
|
+
loadingText="Sending..."
|
|
111
|
+
/>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### With Metadata and Tracking
|
|
25
115
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
116
|
+
```tsx
|
|
117
|
+
<Form
|
|
118
|
+
formId="contact-form"
|
|
119
|
+
siteId="my-website"
|
|
120
|
+
baseUrl="https://api.daply.com"
|
|
121
|
+
apiToken="your-api-token-here"
|
|
122
|
+
pageUrl={window.location.href}
|
|
123
|
+
pageId="contact-page"
|
|
124
|
+
sessionId="user-session-id"
|
|
125
|
+
metadata={{
|
|
126
|
+
source: "contact page",
|
|
127
|
+
campaign: "organic",
|
|
128
|
+
userAgent: navigator.userAgent
|
|
129
|
+
}}
|
|
130
|
+
fields={[
|
|
131
|
+
// ... your fields
|
|
132
|
+
]}
|
|
133
|
+
/>
|
|
134
|
+
```
|
|
32
135
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
136
|
+
### Custom Validation
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
<Form
|
|
140
|
+
formId="signup-form"
|
|
141
|
+
siteId="my-website"
|
|
142
|
+
baseUrl="https://api.daply.com"
|
|
143
|
+
apiToken="your-api-token-here"
|
|
144
|
+
fields={[
|
|
145
|
+
{
|
|
146
|
+
name: "password",
|
|
147
|
+
type: "text",
|
|
148
|
+
label: "Password",
|
|
149
|
+
required: true,
|
|
150
|
+
validation: (value) => {
|
|
151
|
+
if (value.length < 8) {
|
|
152
|
+
return "Password must be at least 8 characters";
|
|
153
|
+
}
|
|
154
|
+
if (!/[A-Z]/.test(value)) {
|
|
155
|
+
return "Password must contain at least one uppercase letter";
|
|
156
|
+
}
|
|
157
|
+
if (!/[0-9]/.test(value)) {
|
|
158
|
+
return "Password must contain at least one number";
|
|
159
|
+
}
|
|
160
|
+
return undefined; // No error
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
]}
|
|
164
|
+
/>
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### All Available Field Types
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
<Form
|
|
171
|
+
formId="all-fields-form"
|
|
172
|
+
siteId="my-website"
|
|
173
|
+
baseUrl="https://api.daply.com"
|
|
174
|
+
apiToken="your-api-token-here"
|
|
175
|
+
fields={[
|
|
176
|
+
{
|
|
177
|
+
name: "text_field",
|
|
178
|
+
type: "text",
|
|
179
|
+
label: "Text Input",
|
|
180
|
+
placeholder: "Enter text"
|
|
41
181
|
},
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
export default defineConfig([
|
|
54
|
-
globalIgnores(['dist']),
|
|
55
|
-
{
|
|
56
|
-
files: ['**/*.{ts,tsx}'],
|
|
57
|
-
extends: [
|
|
58
|
-
// Other configs...
|
|
59
|
-
// Enable lint rules for React
|
|
60
|
-
reactX.configs['recommended-typescript'],
|
|
61
|
-
// Enable lint rules for React DOM
|
|
62
|
-
reactDom.configs.recommended,
|
|
63
|
-
],
|
|
64
|
-
languageOptions: {
|
|
65
|
-
parserOptions: {
|
|
66
|
-
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
|
67
|
-
tsconfigRootDir: import.meta.dirname,
|
|
68
|
-
},
|
|
69
|
-
// other options...
|
|
182
|
+
{
|
|
183
|
+
name: "email_field",
|
|
184
|
+
type: "email",
|
|
185
|
+
label: "Email Input",
|
|
186
|
+
placeholder: "email@example.com"
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
name: "number_field",
|
|
190
|
+
type: "number",
|
|
191
|
+
label: "Number Input",
|
|
192
|
+
placeholder: "123"
|
|
70
193
|
},
|
|
194
|
+
{
|
|
195
|
+
name: "tel_field",
|
|
196
|
+
type: "tel",
|
|
197
|
+
label: "Phone Number",
|
|
198
|
+
placeholder: "+1 (555) 123-4567"
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
name: "url_field",
|
|
202
|
+
type: "url",
|
|
203
|
+
label: "Website URL",
|
|
204
|
+
placeholder: "https://example.com"
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
name: "textarea_field",
|
|
208
|
+
type: "textarea",
|
|
209
|
+
label: "Textarea",
|
|
210
|
+
rows: 5,
|
|
211
|
+
placeholder: "Enter multiple lines..."
|
|
212
|
+
}
|
|
213
|
+
]}
|
|
214
|
+
/>
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## API Reference
|
|
218
|
+
|
|
219
|
+
### FormConfig Props
|
|
220
|
+
|
|
221
|
+
| Prop | Type | Required | Description |
|
|
222
|
+
|------|------|----------|-------------|
|
|
223
|
+
| `formId` | `string` | Yes | Unique identifier for the form |
|
|
224
|
+
| `siteId` | `string` | Yes | Identifier for your site |
|
|
225
|
+
| `baseUrl` | `string` | Yes | Daply API base URL |
|
|
226
|
+
| `apiToken` | `string` | Yes | Bearer token for authentication |
|
|
227
|
+
| `encryptedDbName` | `string` | Yes | Encrypted database name for x-encrypted-db-name header |
|
|
228
|
+
| `fields` | `FormField[]` | Yes | Array of form fields (see below) |
|
|
229
|
+
| `theme` | `'light' \| 'dark' \| 'auto'` | No | Theme mode (default: 'auto') |
|
|
230
|
+
| `pageUrl` | `string` | No | Current page URL for tracking |
|
|
231
|
+
| `pageId` | `string` | No | Page identifier for tracking |
|
|
232
|
+
| `sessionId` | `string` | No | User session ID for tracking |
|
|
233
|
+
| `metadata` | `object` | No | Additional metadata to send with form |
|
|
234
|
+
| `onSuccess` | `(response: any) => void` | No | Callback when form submits successfully |
|
|
235
|
+
| `onError` | `(error: Error) => void` | No | Callback when form submission fails |
|
|
236
|
+
| `submitButtonText` | `string` | No | Submit button text (default: "Submit") |
|
|
237
|
+
| `submitButtonClassName` | `string` | No | Custom CSS class for submit button |
|
|
238
|
+
| `formClassName` | `string` | No | Custom CSS class for form wrapper |
|
|
239
|
+
| `loadingText` | `string` | No | Loading text (default: "Submitting...") |
|
|
240
|
+
|
|
241
|
+
### FormField Props
|
|
242
|
+
|
|
243
|
+
| Prop | Type | Required | Description |
|
|
244
|
+
|------|------|----------|-------------|
|
|
245
|
+
| `name` | `string` | Yes | Field name (must be unique) |
|
|
246
|
+
| `type` | `FieldType` | Yes | Field type: `text`, `email`, `textarea`, `number`, `tel`, `url` |
|
|
247
|
+
| `label` | `string` | No | Label text displayed above field |
|
|
248
|
+
| `required` | `boolean` | No | Whether field is required (default: false) |
|
|
249
|
+
| `placeholder` | `string` | No | Placeholder text |
|
|
250
|
+
| `defaultValue` | `string` | No | Default value for the field |
|
|
251
|
+
| `rows` | `number` | No | Number of rows (for textarea only) |
|
|
252
|
+
| `className` | `string` | No | Custom CSS class for input element |
|
|
253
|
+
| `validation` | `(value: string) => string \| undefined` | No | Custom validation function |
|
|
254
|
+
|
|
255
|
+
## Styling
|
|
256
|
+
|
|
257
|
+
The components use **inline styles** for maximum compatibility and zero dependencies. They work out of the box without requiring Tailwind CSS or any other CSS framework.
|
|
258
|
+
|
|
259
|
+
### Theme Support
|
|
260
|
+
|
|
261
|
+
The components automatically adapt to light and dark modes:
|
|
262
|
+
|
|
263
|
+
```tsx
|
|
264
|
+
// Light theme
|
|
265
|
+
<Form theme="light" {...props} />
|
|
266
|
+
|
|
267
|
+
// Dark theme (like Oasis Energy form)
|
|
268
|
+
<Form theme="dark" {...props} />
|
|
269
|
+
|
|
270
|
+
// Auto-detect user's system preference (default)
|
|
271
|
+
<Form theme="auto" {...props} />
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Default Styles
|
|
275
|
+
- **Form Container**: Clean white (light) / dark `#1a1a1a` (dark) with subtle shadows
|
|
276
|
+
- **Input Fields**: Large padding (16px), rounded corners, smooth transitions
|
|
277
|
+
- **Focus States**: Blue ring with smooth animations
|
|
278
|
+
- **Error States**: Red border and background tint
|
|
279
|
+
- **Submit Button**: Gradient blue with hover effects and uppercase text
|
|
280
|
+
|
|
281
|
+
### Customization Options
|
|
282
|
+
|
|
283
|
+
You can add custom classes for additional styling:
|
|
284
|
+
|
|
285
|
+
```tsx
|
|
286
|
+
<Form
|
|
287
|
+
formClassName="my-custom-form"
|
|
288
|
+
submitButtonClassName="my-custom-button"
|
|
289
|
+
fields={[
|
|
290
|
+
{
|
|
291
|
+
name: "email",
|
|
292
|
+
type: "email",
|
|
293
|
+
className: "my-custom-input"
|
|
294
|
+
// Add your own CSS classes
|
|
295
|
+
}
|
|
296
|
+
]}
|
|
297
|
+
/>
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
**Note:** Inline styles take precedence, but you can use `!important` in your custom CSS to override them if needed.
|
|
301
|
+
|
|
302
|
+
## TypeScript Support
|
|
303
|
+
|
|
304
|
+
Full TypeScript support with exported types:
|
|
305
|
+
|
|
306
|
+
```tsx
|
|
307
|
+
import type {
|
|
308
|
+
FormConfig,
|
|
309
|
+
FormField,
|
|
310
|
+
FormSchema,
|
|
311
|
+
FormData,
|
|
312
|
+
FieldType,
|
|
313
|
+
FieldSchema,
|
|
314
|
+
DaplyFormSubmission
|
|
315
|
+
} from 'daply-ui';
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
## API Endpoint
|
|
319
|
+
|
|
320
|
+
The form submits to:
|
|
321
|
+
```
|
|
322
|
+
POST {{baseUrl}}/api/v1/form-submissions
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
With the following payload structure:
|
|
326
|
+
|
|
327
|
+
```json
|
|
328
|
+
{
|
|
329
|
+
"formId": "contact-form",
|
|
330
|
+
"siteId": "my-website",
|
|
331
|
+
"formData": {
|
|
332
|
+
"name": "John Doe",
|
|
333
|
+
"email": "john@example.com",
|
|
334
|
+
"subject": "Inquiry",
|
|
335
|
+
"message": "This is a test message."
|
|
71
336
|
},
|
|
72
|
-
|
|
337
|
+
"formSchema": {
|
|
338
|
+
"name": { "type": "text", "required": true },
|
|
339
|
+
"email": { "type": "email", "required": true },
|
|
340
|
+
"subject": { "type": "text", "required": true },
|
|
341
|
+
"message": { "type": "textarea", "required": true }
|
|
342
|
+
},
|
|
343
|
+
"pageUrl": "https://example.com/contact",
|
|
344
|
+
"pageId": "contact-page",
|
|
345
|
+
"sessionId": "sess_123456789",
|
|
346
|
+
"metadata": {
|
|
347
|
+
"source": "contact page",
|
|
348
|
+
"campaign": "organic"
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
Headers:
|
|
354
|
+
```
|
|
355
|
+
Content-Type: application/json
|
|
356
|
+
Authorization: Bearer {your-api-token}
|
|
357
|
+
x-encrypted-db-name: {your-encrypted-db-name}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
**Important:** Store your `apiToken` and `encryptedDbName` securely in environment variables:
|
|
361
|
+
|
|
362
|
+
```tsx
|
|
363
|
+
<Form
|
|
364
|
+
apiToken={process.env.REACT_APP_DAPLY_TOKEN}
|
|
365
|
+
encryptedDbName={process.env.REACT_APP_ENCRYPTED_DB_NAME}
|
|
366
|
+
// ... other props
|
|
367
|
+
/>
|
|
73
368
|
```
|
|
369
|
+
|
|
370
|
+
## Features
|
|
371
|
+
|
|
372
|
+
- ✅ Built-in validation (required fields, email, URL)
|
|
373
|
+
- ✅ Custom validation functions
|
|
374
|
+
- ✅ Automatic form submission to Daply backend
|
|
375
|
+
- ✅ Loading states with smooth animations
|
|
376
|
+
- ✅ Error handling with user-friendly messages
|
|
377
|
+
- ✅ Success/error callbacks
|
|
378
|
+
- ✅ Full TypeScript support
|
|
379
|
+
- ✅ Modern, clean design inspired by Daply forms
|
|
380
|
+
- ✅ Light & Dark theme support (automatic)
|
|
381
|
+
- ✅ Customizable styling with Tailwind CSS
|
|
382
|
+
- ✅ Multiple field types (text, email, textarea, number, tel, url)
|
|
383
|
+
- ✅ Metadata and tracking support
|
|
384
|
+
- ✅ Smooth transitions and hover effects
|
|
385
|
+
- ✅ Mobile-responsive design
|
|
386
|
+
|
|
387
|
+
## Development
|
|
388
|
+
|
|
389
|
+
```bash
|
|
390
|
+
# Install dependencies
|
|
391
|
+
npm install
|
|
392
|
+
|
|
393
|
+
# Run development server
|
|
394
|
+
npm run dev
|
|
395
|
+
|
|
396
|
+
# Build library
|
|
397
|
+
npm run build
|
|
398
|
+
|
|
399
|
+
# Publish to npm
|
|
400
|
+
npm run publish
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
## License
|
|
404
|
+
|
|
405
|
+
MIT
|
|
406
|
+
|
|
407
|
+
## Support
|
|
408
|
+
|
|
409
|
+
For issues and questions, please visit our [GitHub repository](https://github.com/yourusername/daply-ui).
|
package/dist/daply-ui.js
CHANGED
|
@@ -1,5 +1,268 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
|
|
1
|
+
import { jsx as s, jsxs as y } from "react/jsx-runtime";
|
|
2
|
+
import { useState as I } from "react";
|
|
3
|
+
const J = ({ children: i }) => /* @__PURE__ */ s("button", { children: i }), W = ({ name: i, value: x, onChange: S, error: a, schema: w, theme: v = "auto" }) => {
|
|
4
|
+
const {
|
|
5
|
+
type: k = "text",
|
|
6
|
+
required: d = !1,
|
|
7
|
+
placeholder: m = "",
|
|
8
|
+
label: u,
|
|
9
|
+
className: b = ""
|
|
10
|
+
} = w, o = v === "dark" || v === "auto" && typeof window < "u" && window.matchMedia("(prefers-color-scheme: dark)").matches, l = {
|
|
11
|
+
width: "100%",
|
|
12
|
+
boxSizing: "border-box",
|
|
13
|
+
// 👈 CRITICAL
|
|
14
|
+
padding: "16px",
|
|
15
|
+
borderRadius: "8px",
|
|
16
|
+
outline: "none",
|
|
17
|
+
transition: "all 0.2s ease",
|
|
18
|
+
fontSize: "16px",
|
|
19
|
+
fontFamily: "inherit",
|
|
20
|
+
border: a ? `2px solid ${o ? "#f87171" : "#ef4444"}` : `1px solid ${o ? "#374151" : "#d1d5db"}`,
|
|
21
|
+
backgroundColor: a ? o ? "rgba(153, 27, 27, 0.1)" : "rgba(254, 226, 226, 1)" : o ? "#2a2a2a" : "#ffffff",
|
|
22
|
+
color: o ? "#ffffff" : "#111827"
|
|
23
|
+
}, F = {
|
|
24
|
+
...l,
|
|
25
|
+
borderColor: a ? o ? "#f87171" : "#ef4444" : "#3b82f6",
|
|
26
|
+
boxShadow: a ? `0 0 0 3px ${o ? "rgba(248, 113, 113, 0.2)" : "rgba(239, 68, 68, 0.2)"}` : "0 0 0 3px rgba(59, 130, 246, 0.2)"
|
|
27
|
+
}, $ = {
|
|
28
|
+
display: "block",
|
|
29
|
+
fontWeight: "500",
|
|
30
|
+
marginBottom: "8px",
|
|
31
|
+
color: o ? "#ffffff" : "#111827",
|
|
32
|
+
fontSize: "14px"
|
|
33
|
+
}, j = {
|
|
34
|
+
marginTop: "4px",
|
|
35
|
+
fontSize: "14px",
|
|
36
|
+
color: o ? "#f87171" : "#dc2626"
|
|
37
|
+
}, D = {
|
|
38
|
+
color: o ? "#f87171" : "#ef4444",
|
|
39
|
+
marginLeft: "4px"
|
|
40
|
+
}, p = {
|
|
41
|
+
marginBottom: "24px",
|
|
42
|
+
display: "flex",
|
|
43
|
+
flexDirection: "column",
|
|
44
|
+
alignItems: "flex-start",
|
|
45
|
+
width: "100%"
|
|
46
|
+
}, g = o ? "#6b7280" : "#9ca3af";
|
|
47
|
+
return k === "textarea" ? /* @__PURE__ */ y("div", { style: p, children: [
|
|
48
|
+
u ? /* @__PURE__ */ y("label", { htmlFor: i, style: $, children: [
|
|
49
|
+
u,
|
|
50
|
+
d ? /* @__PURE__ */ s("span", { style: D, children: "*" }) : null
|
|
51
|
+
] }) : null,
|
|
52
|
+
/* @__PURE__ */ s(
|
|
53
|
+
"textarea",
|
|
54
|
+
{
|
|
55
|
+
id: i,
|
|
56
|
+
name: i,
|
|
57
|
+
value: x,
|
|
58
|
+
onChange: S,
|
|
59
|
+
required: d,
|
|
60
|
+
placeholder: m,
|
|
61
|
+
rows: w.rows || 4,
|
|
62
|
+
style: l,
|
|
63
|
+
onFocus: (n) => {
|
|
64
|
+
Object.assign(n.target.style, F);
|
|
65
|
+
},
|
|
66
|
+
onBlur: (n) => {
|
|
67
|
+
Object.assign(n.target.style, l);
|
|
68
|
+
},
|
|
69
|
+
className: b
|
|
70
|
+
}
|
|
71
|
+
),
|
|
72
|
+
a ? /* @__PURE__ */ s("p", { style: j, children: a }) : null,
|
|
73
|
+
/* @__PURE__ */ s("style", { children: `
|
|
74
|
+
textarea::placeholder { color: ${g}; }
|
|
75
|
+
` })
|
|
76
|
+
] }) : /* @__PURE__ */ y("div", { style: p, children: [
|
|
77
|
+
u ? /* @__PURE__ */ y("label", { htmlFor: i, style: $, children: [
|
|
78
|
+
u,
|
|
79
|
+
d ? /* @__PURE__ */ s("span", { style: D, children: "*" }) : null
|
|
80
|
+
] }) : null,
|
|
81
|
+
/* @__PURE__ */ s(
|
|
82
|
+
"input",
|
|
83
|
+
{
|
|
84
|
+
id: i,
|
|
85
|
+
name: i,
|
|
86
|
+
type: k,
|
|
87
|
+
value: x,
|
|
88
|
+
onChange: S,
|
|
89
|
+
required: d,
|
|
90
|
+
placeholder: m,
|
|
91
|
+
style: l,
|
|
92
|
+
onFocus: (n) => {
|
|
93
|
+
Object.assign(n.target.style, F);
|
|
94
|
+
},
|
|
95
|
+
onBlur: (n) => {
|
|
96
|
+
Object.assign(n.target.style, l);
|
|
97
|
+
},
|
|
98
|
+
className: b
|
|
99
|
+
}
|
|
100
|
+
),
|
|
101
|
+
a ? /* @__PURE__ */ s("p", { style: j, children: a }) : null,
|
|
102
|
+
/* @__PURE__ */ s("style", { children: `
|
|
103
|
+
input::placeholder { color: ${g}; }
|
|
104
|
+
` })
|
|
105
|
+
] });
|
|
106
|
+
}, G = (i) => {
|
|
107
|
+
const {
|
|
108
|
+
formId: x,
|
|
109
|
+
siteId: S,
|
|
110
|
+
fields: a,
|
|
111
|
+
baseUrl: w,
|
|
112
|
+
apiToken: v,
|
|
113
|
+
encryptedDbName: k,
|
|
114
|
+
pageUrl: d,
|
|
115
|
+
pageId: m,
|
|
116
|
+
sessionId: u,
|
|
117
|
+
metadata: b,
|
|
118
|
+
onSuccess: o,
|
|
119
|
+
onError: l,
|
|
120
|
+
submitButtonText: F = "Submit",
|
|
121
|
+
submitButtonClassName: $ = "",
|
|
122
|
+
formClassName: j = "",
|
|
123
|
+
loadingText: D = "Submitting...",
|
|
124
|
+
theme: p = "auto"
|
|
125
|
+
} = i, g = a.reduce((t, e) => (t[e.name] = e.defaultValue || "", t), {}), [n, N] = I(g), [O, T] = I({}), [f, R] = I(!1), [z, q] = I(!1), C = p === "dark" || p === "auto" && typeof window < "u" && window.matchMedia("(prefers-color-scheme: dark)").matches, L = (t) => {
|
|
126
|
+
const { name: e, value: h } = t.target;
|
|
127
|
+
N((r) => ({
|
|
128
|
+
...r,
|
|
129
|
+
[e]: h
|
|
130
|
+
})), O[e] && T((r) => {
|
|
131
|
+
const c = { ...r };
|
|
132
|
+
return delete c[e], c;
|
|
133
|
+
});
|
|
134
|
+
}, M = () => {
|
|
135
|
+
const t = {};
|
|
136
|
+
return a.forEach((e) => {
|
|
137
|
+
const h = n[e.name], r = String(h || "");
|
|
138
|
+
if (e.required && !r.trim()) {
|
|
139
|
+
t[e.name] = `${e.label || e.name} is required`;
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (e.type === "email" && r && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(r)) {
|
|
143
|
+
t[e.name] = "Please enter a valid email address";
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (e.type === "url" && r)
|
|
147
|
+
try {
|
|
148
|
+
new URL(r);
|
|
149
|
+
} catch {
|
|
150
|
+
t[e.name] = "Please enter a valid URL";
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (e.validation && r) {
|
|
154
|
+
const c = e.validation(r);
|
|
155
|
+
if (c) {
|
|
156
|
+
t[e.name] = c;
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}), T(t), Object.keys(t).length === 0;
|
|
161
|
+
}, P = async (t) => {
|
|
162
|
+
if (t.preventDefault(), !!M()) {
|
|
163
|
+
R(!0);
|
|
164
|
+
try {
|
|
165
|
+
const e = a.reduce((B, E) => (B[E.name] = {
|
|
166
|
+
type: E.type,
|
|
167
|
+
required: E.required
|
|
168
|
+
}, B), {}), h = {
|
|
169
|
+
formId: x,
|
|
170
|
+
siteId: S,
|
|
171
|
+
formData: n,
|
|
172
|
+
formSchema: e,
|
|
173
|
+
...d && { pageUrl: d },
|
|
174
|
+
...m && { pageId: m },
|
|
175
|
+
...u && { sessionId: u },
|
|
176
|
+
...b && { metadata: b }
|
|
177
|
+
}, r = await fetch(`${w}/api/v1/form-submissions`, {
|
|
178
|
+
method: "POST",
|
|
179
|
+
headers: {
|
|
180
|
+
"Content-Type": "application/json",
|
|
181
|
+
Authorization: `Bearer ${v}`,
|
|
182
|
+
"x-encrypted-db-name": k
|
|
183
|
+
},
|
|
184
|
+
body: JSON.stringify(h)
|
|
185
|
+
});
|
|
186
|
+
if (!r.ok) {
|
|
187
|
+
const B = await r.json().catch(() => ({}));
|
|
188
|
+
throw new Error(B.message || `HTTP error! status: ${r.status}`);
|
|
189
|
+
}
|
|
190
|
+
const c = await r.json();
|
|
191
|
+
N(g), T({}), o && o(c);
|
|
192
|
+
} catch (e) {
|
|
193
|
+
console.error("Form submission error:", e), l && l(e);
|
|
194
|
+
} finally {
|
|
195
|
+
R(!1);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}, U = {
|
|
199
|
+
maxWidth: "612px",
|
|
200
|
+
margin: "0 auto",
|
|
201
|
+
padding: "32px",
|
|
202
|
+
backgroundColor: C ? "#1a1a1a" : "#ffffff",
|
|
203
|
+
borderRadius: "12px",
|
|
204
|
+
boxShadow: C ? "0 25px 50px -12px rgba(0, 0, 0, 0.5)" : "0 10px 15px -3px rgba(0, 0, 0, 0.1)",
|
|
205
|
+
border: `1px solid ${C ? "#1f2937" : "#e5e7eb"}`
|
|
206
|
+
}, H = {
|
|
207
|
+
width: "100%",
|
|
208
|
+
padding: "16px 24px",
|
|
209
|
+
background: f ? "linear-gradient(to right, #4b5563, #4b5563)" : z ? "linear-gradient(to right, #1d4ed8, #1e40af)" : "linear-gradient(to right, #2563eb, #1d4ed8)",
|
|
210
|
+
color: "#ffffff",
|
|
211
|
+
fontWeight: "bold",
|
|
212
|
+
fontSize: "18px",
|
|
213
|
+
textTransform: "uppercase",
|
|
214
|
+
letterSpacing: "0.05em",
|
|
215
|
+
borderRadius: "8px",
|
|
216
|
+
border: "none",
|
|
217
|
+
cursor: f ? "not-allowed" : "pointer",
|
|
218
|
+
opacity: f ? 0.5 : 1,
|
|
219
|
+
transition: "all 0.2s ease",
|
|
220
|
+
outline: "none",
|
|
221
|
+
fontFamily: "inherit"
|
|
222
|
+
};
|
|
223
|
+
return /* @__PURE__ */ y(
|
|
224
|
+
"form",
|
|
225
|
+
{
|
|
226
|
+
onSubmit: P,
|
|
227
|
+
style: U,
|
|
228
|
+
className: j,
|
|
229
|
+
children: [
|
|
230
|
+
a.map((t) => /* @__PURE__ */ s(
|
|
231
|
+
W,
|
|
232
|
+
{
|
|
233
|
+
name: t.name,
|
|
234
|
+
value: String(n[t.name] || ""),
|
|
235
|
+
onChange: L,
|
|
236
|
+
error: O[t.name],
|
|
237
|
+
schema: t,
|
|
238
|
+
theme: p
|
|
239
|
+
},
|
|
240
|
+
t.name
|
|
241
|
+
)),
|
|
242
|
+
/* @__PURE__ */ s(
|
|
243
|
+
"button",
|
|
244
|
+
{
|
|
245
|
+
type: "submit",
|
|
246
|
+
disabled: f,
|
|
247
|
+
style: H,
|
|
248
|
+
onMouseEnter: () => !f && q(!0),
|
|
249
|
+
onMouseLeave: () => q(!1),
|
|
250
|
+
onFocus: (t) => {
|
|
251
|
+
f || (t.target.style.boxShadow = "0 0 0 3px rgba(59, 130, 246, 0.3)");
|
|
252
|
+
},
|
|
253
|
+
onBlur: (t) => {
|
|
254
|
+
t.target.style.boxShadow = "none";
|
|
255
|
+
},
|
|
256
|
+
className: $,
|
|
257
|
+
children: f ? D : F
|
|
258
|
+
}
|
|
259
|
+
)
|
|
260
|
+
]
|
|
261
|
+
}
|
|
262
|
+
);
|
|
263
|
+
};
|
|
3
264
|
export {
|
|
4
|
-
|
|
265
|
+
J as Button,
|
|
266
|
+
G as Form,
|
|
267
|
+
W as InputField
|
|
5
268
|
};
|
package/dist/daply-ui.umd.cjs
CHANGED
|
@@ -1 +1,5 @@
|
|
|
1
|
-
(function(
|
|
1
|
+
(function(i,r){typeof exports=="object"&&typeof module<"u"?r(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],r):(i=typeof globalThis<"u"?globalThis:i||self,r(i["daply-ui"]={},i["react/jsx-runtime"],i.React))})(this,(function(i,r,x){"use strict";const P=({children:l})=>r.jsx("button",{children:l}),E=({name:l,value:S,onChange:w,error:n,schema:v,theme:F="auto"})=>{const{type:j="text",required:u=!1,placeholder:m="",label:f,className:y=""}=v,a=F==="dark"||F==="auto"&&typeof window<"u"&&window.matchMedia("(prefers-color-scheme: dark)").matches,d={width:"100%",boxSizing:"border-box",padding:"16px",borderRadius:"8px",outline:"none",transition:"all 0.2s ease",fontSize:"16px",fontFamily:"inherit",border:n?`2px solid ${a?"#f87171":"#ef4444"}`:`1px solid ${a?"#374151":"#d1d5db"}`,backgroundColor:n?a?"rgba(153, 27, 27, 0.1)":"rgba(254, 226, 226, 1)":a?"#2a2a2a":"#ffffff",color:a?"#ffffff":"#111827"},k={...d,borderColor:n?a?"#f87171":"#ef4444":"#3b82f6",boxShadow:n?`0 0 0 3px ${a?"rgba(248, 113, 113, 0.2)":"rgba(239, 68, 68, 0.2)"}`:"0 0 0 3px rgba(59, 130, 246, 0.2)"},T={display:"block",fontWeight:"500",marginBottom:"8px",color:a?"#ffffff":"#111827",fontSize:"14px"},$={marginTop:"4px",fontSize:"14px",color:a?"#f87171":"#dc2626"},B={color:a?"#f87171":"#ef4444",marginLeft:"4px"},b={marginBottom:"24px",display:"flex",flexDirection:"column",alignItems:"flex-start",width:"100%"},g=a?"#6b7280":"#9ca3af";return j==="textarea"?r.jsxs("div",{style:b,children:[f?r.jsxs("label",{htmlFor:l,style:T,children:[f,u?r.jsx("span",{style:B,children:"*"}):null]}):null,r.jsx("textarea",{id:l,name:l,value:S,onChange:w,required:u,placeholder:m,rows:v.rows||4,style:d,onFocus:s=>{Object.assign(s.target.style,k)},onBlur:s=>{Object.assign(s.target.style,d)},className:y}),n?r.jsx("p",{style:$,children:n}):null,r.jsx("style",{children:`
|
|
2
|
+
textarea::placeholder { color: ${g}; }
|
|
3
|
+
`})]}):r.jsxs("div",{style:b,children:[f?r.jsxs("label",{htmlFor:l,style:T,children:[f,u?r.jsx("span",{style:B,children:"*"}):null]}):null,r.jsx("input",{id:l,name:l,type:j,value:S,onChange:w,required:u,placeholder:m,style:d,onFocus:s=>{Object.assign(s.target.style,k)},onBlur:s=>{Object.assign(s.target.style,d)},className:y}),n?r.jsx("p",{style:$,children:n}):null,r.jsx("style",{children:`
|
|
4
|
+
input::placeholder { color: ${g}; }
|
|
5
|
+
`})]})},L=l=>{const{formId:S,siteId:w,fields:n,baseUrl:v,apiToken:F,encryptedDbName:j,pageUrl:u,pageId:m,sessionId:f,metadata:y,onSuccess:a,onError:d,submitButtonText:k="Submit",submitButtonClassName:T="",formClassName:$="",loadingText:B="Submitting...",theme:b="auto"}=l,g=n.reduce((t,e)=>(t[e.name]=e.defaultValue||"",t),{}),[s,O]=x.useState(g),[N,I]=x.useState({}),[p,z]=x.useState(!1),[U,M]=x.useState(!1),q=b==="dark"||b==="auto"&&typeof window<"u"&&window.matchMedia("(prefers-color-scheme: dark)").matches,H=t=>{const{name:e,value:h}=t.target;O(o=>({...o,[e]:h})),N[e]&&I(o=>{const c={...o};return delete c[e],c})},W=()=>{const t={};return n.forEach(e=>{const h=s[e.name],o=String(h||"");if(e.required&&!o.trim()){t[e.name]=`${e.label||e.name} is required`;return}if(e.type==="email"&&o&&!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(o)){t[e.name]="Please enter a valid email address";return}if(e.type==="url"&&o)try{new URL(o)}catch{t[e.name]="Please enter a valid URL";return}if(e.validation&&o){const c=e.validation(o);if(c){t[e.name]=c;return}}}),I(t),Object.keys(t).length===0},V=async t=>{if(t.preventDefault(),!!W()){z(!0);try{const e=n.reduce((D,C)=>(D[C.name]={type:C.type,required:C.required},D),{}),h={formId:S,siteId:w,formData:s,formSchema:e,...u&&{pageUrl:u},...m&&{pageId:m},...f&&{sessionId:f},...y&&{metadata:y}},o=await fetch(`${v}/api/v1/form-submissions`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${F}`,"x-encrypted-db-name":j},body:JSON.stringify(h)});if(!o.ok){const D=await o.json().catch(()=>({}));throw new Error(D.message||`HTTP error! status: ${o.status}`)}const c=await o.json();O(g),I({}),a&&a(c)}catch(e){console.error("Form submission error:",e),d&&d(e)}finally{z(!1)}}},A={maxWidth:"612px",margin:"0 auto",padding:"32px",backgroundColor:q?"#1a1a1a":"#ffffff",borderRadius:"12px",boxShadow:q?"0 25px 50px -12px rgba(0, 0, 0, 0.5)":"0 10px 15px -3px rgba(0, 0, 0, 0.1)",border:`1px solid ${q?"#1f2937":"#e5e7eb"}`},J={width:"100%",padding:"16px 24px",background:p?"linear-gradient(to right, #4b5563, #4b5563)":U?"linear-gradient(to right, #1d4ed8, #1e40af)":"linear-gradient(to right, #2563eb, #1d4ed8)",color:"#ffffff",fontWeight:"bold",fontSize:"18px",textTransform:"uppercase",letterSpacing:"0.05em",borderRadius:"8px",border:"none",cursor:p?"not-allowed":"pointer",opacity:p?.5:1,transition:"all 0.2s ease",outline:"none",fontFamily:"inherit"};return r.jsxs("form",{onSubmit:V,style:A,className:$,children:[n.map(t=>r.jsx(E,{name:t.name,value:String(s[t.name]||""),onChange:H,error:N[t.name],schema:t,theme:b},t.name)),r.jsx("button",{type:"submit",disabled:p,style:J,onMouseEnter:()=>!p&&M(!0),onMouseLeave:()=>M(!1),onFocus:t=>{p||(t.target.style.boxShadow="0 0 0 3px rgba(59, 130, 246, 0.3)")},onBlur:t=>{t.target.style.boxShadow="none"},className:T,children:p?B:k})]})};i.Button=P,i.Form=L,i.InputField=E,Object.defineProperty(i,Symbol.toStringTag,{value:"Module"})}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "daply-ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
17
|
"dev": "vite",
|
|
18
|
-
"prebuild": "
|
|
18
|
+
"prebuild": "rimraf dist",
|
|
19
19
|
"build": "tsc -b && vite build",
|
|
20
20
|
"lint": "eslint .",
|
|
21
21
|
"preview": "vite preview",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
37
37
|
"eslint-plugin-react-refresh": "^0.4.24",
|
|
38
38
|
"globals": "^16.5.0",
|
|
39
|
+
"rimraf": "^6.1.2",
|
|
39
40
|
"typescript": "~5.9.3",
|
|
40
41
|
"typescript-eslint": "^8.46.4",
|
|
41
42
|
"vite": "^7.2.4"
|