@xapp/form-widget 1.79.0 → 1.79.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 +363 -0
- package/dist/components/FormFieldDropdown/FormFieldDropdown.d.ts +0 -0
- package/dist/components/FormFieldDropdown/FormFieldDropdown.stories.d.ts +8 -0
- package/dist/index.es.js +54 -54
- package/dist/index.es.js.map +1 -1
- package/dist/utils/__test__/tracking.test.d.ts +1 -0
- package/dist/utils/index.d.ts +0 -0
- package/dist/utils/tracking.d.ts +0 -0
- package/dist/xapp-form-widget.js +26 -26
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -70,3 +70,366 @@ Tracking is enabled by default. The system handles:
|
|
|
70
70
|
- Error handling for malformed data
|
|
71
71
|
|
|
72
72
|
No additional configuration is required - the widget will automatically capture and pass through any UTM parameters, click IDs, or custom tracking parameters present in the page URL.
|
|
73
|
+
|
|
74
|
+
### Implementation Notes
|
|
75
|
+
|
|
76
|
+
**When used standalone:** The widget extracts tracking parameters from the page URL on mount and stores them in localStorage with the prefix `xa_tracking_`.
|
|
77
|
+
|
|
78
|
+
**When embedded in contact-app:** Both the contact-app and form-widget will extract and store tracking parameters. This is safe and intentional:
|
|
79
|
+
- Both extract from the same URL (`window.location.href`)
|
|
80
|
+
- Both write to the same localStorage keys (`xa_tracking_utm_source`, etc.)
|
|
81
|
+
- The function is idempotent - the second extraction just refreshes stored values with identical data
|
|
82
|
+
- No data corruption occurs; it's just a minor inefficiency
|
|
83
|
+
|
|
84
|
+
**Storage format:** Parameters are stored as JSON objects with expiration:
|
|
85
|
+
```javascript
|
|
86
|
+
localStorage.getItem('xa_tracking_utm_source')
|
|
87
|
+
// Returns: {"value":"google","expires":1234567890,"stored":1234567890}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Form Field Types
|
|
91
|
+
|
|
92
|
+
The form widget supports multiple field types for building dynamic forms. Below are JSON examples for each supported field type.
|
|
93
|
+
|
|
94
|
+
### Text Input
|
|
95
|
+
|
|
96
|
+
Basic text input field with optional formatting (phone, email, address).
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"name": "full_name",
|
|
101
|
+
"type": "TEXT",
|
|
102
|
+
"title": "Full Name",
|
|
103
|
+
"placeholder": "Enter your name",
|
|
104
|
+
"mandatory": true,
|
|
105
|
+
"mandatoryError": "Name is required"
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
#### Phone Number Input
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"name": "phone",
|
|
114
|
+
"type": "TEXT",
|
|
115
|
+
"title": "Phone Number",
|
|
116
|
+
"format": "PHONE",
|
|
117
|
+
"placeholder": "(555) 555-5555",
|
|
118
|
+
"mandatory": true
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### Email Input
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"name": "email",
|
|
127
|
+
"type": "TEXT",
|
|
128
|
+
"title": "Email Address",
|
|
129
|
+
"format": "EMAIL",
|
|
130
|
+
"placeholder": "you@example.com"
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
#### Multiline Text
|
|
135
|
+
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"name": "description",
|
|
139
|
+
"type": "TEXT",
|
|
140
|
+
"title": "Description",
|
|
141
|
+
"multiline": true,
|
|
142
|
+
"rows": 4,
|
|
143
|
+
"rowsMax": 8,
|
|
144
|
+
"placeholder": "Tell us more..."
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
#### Address Input with Autocomplete
|
|
149
|
+
|
|
150
|
+
```json
|
|
151
|
+
{
|
|
152
|
+
"name": "address",
|
|
153
|
+
"type": "TEXT",
|
|
154
|
+
"title": "Service Address",
|
|
155
|
+
"format": "ADDRESS",
|
|
156
|
+
"mapsBaseUrl": "https://maps.googleapis.com/maps/api/place/autocomplete",
|
|
157
|
+
"googleMapsApiKey": "YOUR_API_KEY",
|
|
158
|
+
"mapsUrlQueryParams": {
|
|
159
|
+
"components": "country:us",
|
|
160
|
+
"language": "en"
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Dropdown
|
|
166
|
+
|
|
167
|
+
Single-select dropdown menu.
|
|
168
|
+
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"name": "service_type",
|
|
172
|
+
"type": "DROPDOWN",
|
|
173
|
+
"title": "Select a service",
|
|
174
|
+
"mandatory": true,
|
|
175
|
+
"items": [
|
|
176
|
+
{
|
|
177
|
+
"id": "plumbing",
|
|
178
|
+
"label": "Plumbing"
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"id": "electrical",
|
|
182
|
+
"label": "Electrical"
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"id": "hvac",
|
|
186
|
+
"label": "HVAC"
|
|
187
|
+
}
|
|
188
|
+
]
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
#### Dropdown with Freeform Input
|
|
193
|
+
|
|
194
|
+
Allows users to enter custom text when they select specific options.
|
|
195
|
+
|
|
196
|
+
```json
|
|
197
|
+
{
|
|
198
|
+
"name": "issue",
|
|
199
|
+
"type": "DROPDOWN",
|
|
200
|
+
"title": "What issue are you experiencing?",
|
|
201
|
+
"items": [
|
|
202
|
+
{
|
|
203
|
+
"id": "installation",
|
|
204
|
+
"label": "Installation"
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"id": "repair",
|
|
208
|
+
"label": "Repair"
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
"id": "maintenance",
|
|
212
|
+
"label": "Maintenance"
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
"id": "other",
|
|
216
|
+
"label": "Other",
|
|
217
|
+
"freeFormInput": true
|
|
218
|
+
}
|
|
219
|
+
]
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
When `freeFormInput: true`, selecting that option displays a text input field. The user's typed text becomes the field value instead of the item's ID.
|
|
224
|
+
|
|
225
|
+
### Chips
|
|
226
|
+
|
|
227
|
+
Visual chip-based selection, supports both single and multi-select.
|
|
228
|
+
|
|
229
|
+
#### Multi-select Chips
|
|
230
|
+
|
|
231
|
+
```json
|
|
232
|
+
{
|
|
233
|
+
"name": "services",
|
|
234
|
+
"type": "CHIPS",
|
|
235
|
+
"title": "Select services you need",
|
|
236
|
+
"minRequired": 1,
|
|
237
|
+
"maxAllowed": 3,
|
|
238
|
+
"items": [
|
|
239
|
+
{
|
|
240
|
+
"id": "service1",
|
|
241
|
+
"label": "Service 1"
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
"id": "service2",
|
|
245
|
+
"label": "Service 2",
|
|
246
|
+
"selected": true
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
"id": "service3",
|
|
250
|
+
"label": "Service 3"
|
|
251
|
+
}
|
|
252
|
+
]
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
#### Single-select Chips (Radio)
|
|
257
|
+
|
|
258
|
+
```json
|
|
259
|
+
{
|
|
260
|
+
"name": "membership",
|
|
261
|
+
"type": "CHIPS",
|
|
262
|
+
"title": "Are you a member?",
|
|
263
|
+
"radio": true,
|
|
264
|
+
"items": [
|
|
265
|
+
{
|
|
266
|
+
"id": "yes",
|
|
267
|
+
"label": "Yes"
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
"id": "no",
|
|
271
|
+
"label": "No",
|
|
272
|
+
"selected": true
|
|
273
|
+
}
|
|
274
|
+
]
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
#### Chips with Actionable Items
|
|
279
|
+
|
|
280
|
+
```json
|
|
281
|
+
{
|
|
282
|
+
"name": "options",
|
|
283
|
+
"type": "CHIPS",
|
|
284
|
+
"title": "Choose an option",
|
|
285
|
+
"items": [
|
|
286
|
+
{
|
|
287
|
+
"id": "option1",
|
|
288
|
+
"label": "Option 1"
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
"id": "learn_more",
|
|
292
|
+
"label": "Learn More",
|
|
293
|
+
"url": "https://example.com/info"
|
|
294
|
+
}
|
|
295
|
+
]
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Checkboxes / Radio Buttons
|
|
300
|
+
|
|
301
|
+
Traditional checkbox or radio button selection.
|
|
302
|
+
|
|
303
|
+
#### Checkboxes (Multi-select)
|
|
304
|
+
|
|
305
|
+
```json
|
|
306
|
+
{
|
|
307
|
+
"name": "preferences",
|
|
308
|
+
"type": "CHECK",
|
|
309
|
+
"title": "Select your preferences",
|
|
310
|
+
"items": [
|
|
311
|
+
{
|
|
312
|
+
"id": "email_updates",
|
|
313
|
+
"label": "Email Updates"
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
"id": "sms_notifications",
|
|
317
|
+
"label": "SMS Notifications"
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
"id": "phone_calls",
|
|
321
|
+
"label": "Phone Calls"
|
|
322
|
+
}
|
|
323
|
+
]
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
#### Radio Buttons (Single-select)
|
|
328
|
+
|
|
329
|
+
```json
|
|
330
|
+
{
|
|
331
|
+
"name": "contact_method",
|
|
332
|
+
"type": "CHECK",
|
|
333
|
+
"title": "Preferred contact method",
|
|
334
|
+
"radio": true,
|
|
335
|
+
"items": [
|
|
336
|
+
{
|
|
337
|
+
"id": "email",
|
|
338
|
+
"label": "Email"
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
"id": "phone",
|
|
342
|
+
"label": "Phone"
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
"id": "sms",
|
|
346
|
+
"label": "SMS"
|
|
347
|
+
}
|
|
348
|
+
]
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### Date Picker
|
|
353
|
+
|
|
354
|
+
Single date selection with optional busy day configuration.
|
|
355
|
+
|
|
356
|
+
```json
|
|
357
|
+
{
|
|
358
|
+
"name": "appointment_date",
|
|
359
|
+
"type": "DATE",
|
|
360
|
+
"title": "Select appointment date",
|
|
361
|
+
"mandatory": true,
|
|
362
|
+
"defaultBusyDays": {
|
|
363
|
+
"blockWeekends": true,
|
|
364
|
+
"blockCurrentDay": true,
|
|
365
|
+
"blockNextBusinessDays": 1
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
#### Date with Available Days
|
|
371
|
+
|
|
372
|
+
```json
|
|
373
|
+
{
|
|
374
|
+
"name": "service_date",
|
|
375
|
+
"type": "DATE",
|
|
376
|
+
"title": "Preferred service date",
|
|
377
|
+
"defaultBusyDays": {
|
|
378
|
+
"availableDays": ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY"]
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### Date Range Picker
|
|
384
|
+
|
|
385
|
+
Select a start and end date.
|
|
386
|
+
|
|
387
|
+
```json
|
|
388
|
+
{
|
|
389
|
+
"name": "vacation_dates",
|
|
390
|
+
"type": "DATERANGE",
|
|
391
|
+
"title": "Select date range",
|
|
392
|
+
"preselecteDates": {
|
|
393
|
+
"from": "2024-01-01",
|
|
394
|
+
"to": "2024-01-07"
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### Card
|
|
400
|
+
|
|
401
|
+
Display-only card with optional image, header, and text content.
|
|
402
|
+
|
|
403
|
+
```json
|
|
404
|
+
{
|
|
405
|
+
"name": "info_card",
|
|
406
|
+
"type": "CARD",
|
|
407
|
+
"header": {
|
|
408
|
+
"title": "Service Information",
|
|
409
|
+
"subheader": "What to expect"
|
|
410
|
+
},
|
|
411
|
+
"media": {
|
|
412
|
+
"imageUrl": "https://example.com/image.jpg",
|
|
413
|
+
"alt": "Service image",
|
|
414
|
+
"height": 200,
|
|
415
|
+
"width": 400
|
|
416
|
+
},
|
|
417
|
+
"text": "Our technicians will arrive within the scheduled time window.",
|
|
418
|
+
"variant": "outlined",
|
|
419
|
+
"color": "primary"
|
|
420
|
+
}
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
## Common Field Properties
|
|
424
|
+
|
|
425
|
+
All field types support these common properties:
|
|
426
|
+
|
|
427
|
+
- `name` (string, required) - Field identifier used in form data
|
|
428
|
+
- `type` (string, required) - Field type (TEXT, DROPDOWN, CHIPS, CHECK, DATE, DATERANGE, CARD)
|
|
429
|
+
- `title` (string, optional) - Display label for the field
|
|
430
|
+
- `mandatory` (boolean, optional) - Whether the field is required
|
|
431
|
+
- `mandatoryError` (string, optional) - Custom error message when required field is empty
|
|
432
|
+
- `condition` (string, optional) - JavaScript expression to conditionally show field (e.g., `"service === 'repair'"`)
|
|
433
|
+
- `style` (object, optional) - React CSSProperties object for custom styling
|
|
434
|
+
- `shape` (string, optional) - Visual shape: "ROUND" or "SQUARE"
|
|
435
|
+
- `mandatoryGroup` (string, optional) - Group name for "one of" validation
|
|
Binary file
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Meta } from "@storybook/react";
|
|
2
|
+
declare const _default: Meta;
|
|
3
|
+
export default _default;
|
|
4
|
+
export declare const Default: any;
|
|
5
|
+
export declare const WithManyOptions: any;
|
|
6
|
+
export declare const NoTitle: any;
|
|
7
|
+
export declare const WithFreeFormInput: any;
|
|
8
|
+
export declare const MultipleFreeFormOptions: any;
|