formshell 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Lorenzo Caputo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,665 @@
1
+ # FormShell
2
+
3
+ An elegant framework for creating interactive multi-step forms directly in the browser console.
4
+
5
+ ![Version](https://img.shields.io/badge/version-1.0.0-blue.svg)
6
+ ![TypeScript](https://img.shields.io/badge/TypeScript-5.x-blue.svg)
7
+ ![License](https://img.shields.io/badge/license-MIT-green.svg)
8
+ ![Browser](https://img.shields.io/badge/browser-Chrome%20%7C%20Firefox%20%7C%20Safari-orange.svg)
9
+
10
+ ## Features
11
+
12
+ - **Multi-Step Forms**: One-question-at-a-time flow
13
+ - **Built-in Validation**: Validation for every field type
14
+ - **Conditional Logic**: Show/hide steps based on previous answers
15
+ - **Progress Tracking**: Progress bar, step counter, and estimated time
16
+ - **Non-blocking Help**: Call `formShell.help()` at any time without losing your place
17
+ - **Zero Dependencies**: No external libraries required
18
+ - **Endpoint Ready**: POST JSON to custom endpoints with response handling
19
+ - **TypeScript**: Full type definitions included
20
+ - **Vite**: Modern dev server and build tool
21
+
22
+ ---
23
+
24
+ ## Quick Start
25
+
26
+ ### 1. Installation
27
+
28
+ ```bash
29
+ pnpm install formshell
30
+ ```
31
+
32
+ Or clone and install locally:
33
+
34
+ ```bash
35
+ git clone <repository-url>
36
+ cd formshell
37
+ pnpm install
38
+ ```
39
+
40
+ ### 2. Development
41
+
42
+ ```bash
43
+ pnpm dev
44
+ ```
45
+
46
+ Then open your browser and navigate to `http://localhost:5173`.
47
+
48
+ ### 3. Build
49
+
50
+ ```bash
51
+ pnpm build
52
+ ```
53
+
54
+ ---
55
+
56
+ ## Step-by-Step Guide
57
+
58
+ This section walks through the entire flow, from configuration to API response.
59
+
60
+ ### Step 1 -- Create a FormConfig
61
+
62
+ A `FormConfig` object defines everything about your form. Here is the full interface with every available option:
63
+
64
+ ```typescript
65
+ import { FormShell } from 'formshell';
66
+ import type { FormConfig, FormData } from 'formshell';
67
+
68
+ const config: FormConfig = {
69
+ // (required) The form title, displayed on the welcome and help screens
70
+ title: 'Feedback Form',
71
+
72
+ // (optional) A subtitle shown below the title
73
+ subtitle: 'We value your opinion',
74
+
75
+ // (optional) POST endpoint -- when set, formShell.submit() sends data here
76
+ endpoint: '/api/feedback',
77
+
78
+ // (required) Array of field configurations (see "Supported Field Types" below)
79
+ steps: [
80
+ {
81
+ id: 'name',
82
+ type: 'text',
83
+ label: 'What is your name?',
84
+ description: 'Enter your full name',
85
+ required: true,
86
+ minLength: 2,
87
+ maxLength: 100
88
+ },
89
+ {
90
+ id: 'email',
91
+ type: 'email',
92
+ label: 'Your email address?',
93
+ required: true
94
+ },
95
+ {
96
+ id: 'rating',
97
+ type: 'rating',
98
+ label: 'How satisfied are you?',
99
+ required: true,
100
+ min: 1,
101
+ max: 5
102
+ },
103
+ {
104
+ id: 'subscribe',
105
+ type: 'yesno',
106
+ label: 'Subscribe to our newsletter?',
107
+ required: false,
108
+ defaultValue: false
109
+ }
110
+ ],
111
+
112
+ // (optional) Called after successful submission
113
+ // When an endpoint is set, `data` contains the server's JSON response.
114
+ // When no endpoint is set, `data` contains the collected form answers.
115
+ onComplete: (data: FormData) => {
116
+ console.log('Received:', data);
117
+ }
118
+ };
119
+ ```
120
+
121
+ ### Step 2 -- Instantiate FormShell
122
+
123
+ ```typescript
124
+ const form = new FormShell(config);
125
+ ```
126
+
127
+ > **TypeScript autocomplete:** FormShell includes global type definitions for `window.formShell`.
128
+ >
129
+ > To enable them in your TypeScript project, reference the global declarations at the top of your main file:
130
+ >
131
+ > ```typescript
132
+ > /// <reference types="formshell/global" />
133
+ >
134
+ > // Now window.formShell has full type support!
135
+ > const form = new FormShell(config);
136
+ > ```
137
+ >
138
+ > If you want to use a **custom name** for your brand instead of `formShell`:
139
+ >
140
+ > ```typescript
141
+ > // global.d.ts in your project root
142
+ > import type { FormShell } from 'formshell';
143
+ >
144
+ > declare global {
145
+ > interface Window {
146
+ > myBrandName: FormShell; // Use your custom name
147
+ > }
148
+ > }
149
+ >
150
+ > export {};
151
+ > ```
152
+ >
153
+ > Then assign it manually:
154
+ > ```typescript
155
+ > const form = new FormShell(config);
156
+ > window.myBrandName = form;
157
+ > ```
158
+
159
+ ### Step 3 -- Include in HTML
160
+
161
+ ```html
162
+ <script type="module" src="./my-form.ts"></script>
163
+ ```
164
+
165
+ That is all. The form renders entirely inside the browser console -- no visible UI is needed.
166
+
167
+ ### Step 4 -- Open the Console
168
+
169
+ - **Chrome/Edge**: `F12` or `Ctrl+Shift+J` (`Cmd+Option+J` on Mac)
170
+ - **Firefox**: `F12` or `Ctrl+Shift+K` (`Cmd+Option+K` on Mac)
171
+ - **Safari**: Enable Developer menu, then `Cmd+Option+C`
172
+
173
+ When the page loads you will see:
174
+
175
+ ```
176
+ Feedback Form
177
+ We value your opinion
178
+
179
+ Type formShell.start() to begin or formShell.help() for available commands
180
+ ```
181
+
182
+ ### Step 5 -- Interact with the Form
183
+
184
+ ```javascript
185
+ // Show all available commands (non-blocking, does not interrupt the form)
186
+ formShell.help()
187
+
188
+ // Start the form
189
+ formShell.start()
190
+
191
+ // Answer questions
192
+ formShell.answer("John Doe")
193
+ formShell.answer("john@example.com")
194
+ formShell.answer(4) // rating
195
+ formShell.y() // yes/no shortcut
196
+
197
+ // Navigate
198
+ formShell.back() // go to previous question
199
+ formShell.skip() // skip optional question
200
+
201
+ // After the last answer the summary screen appears
202
+ formShell.submit() // send data to the endpoint (or log it)
203
+
204
+ // At any point
205
+ formShell.help() // show commands -- does NOT lose your progress
206
+ formShell.continue() // resume where you left off after help
207
+ formShell.reset() // start over from scratch
208
+ ```
209
+
210
+ ### Step 6 -- What Happens on Submit
211
+
212
+ When `formShell.submit()` is called:
213
+
214
+ 1. **With an endpoint** -- a `POST` request is sent:
215
+
216
+ ```
217
+ POST /api/feedback
218
+ Content-Type: application/json
219
+
220
+ {
221
+ "name": "John Doe",
222
+ "email": "john@example.com",
223
+ "rating": 4,
224
+ "subscribe": true
225
+ }
226
+ ```
227
+
228
+ The server's JSON response is passed to `onComplete(response)` and printed in the console:
229
+
230
+ ```
231
+ Response: { success: true, feedbackId: "fb-1707562800000", ... }
232
+ ```
233
+
234
+ 2. **Without an endpoint** -- the collected data is passed directly to `onComplete(data)` and printed:
235
+
236
+ ```
237
+ Data: { name: "John Doe", email: "john@example.com", rating: 4, subscribe: true }
238
+ ```
239
+
240
+ ---
241
+
242
+ ## Supported Field Types
243
+
244
+ ### Text Field
245
+
246
+ Free text with length and pattern validation.
247
+
248
+ ```typescript
249
+ {
250
+ id: 'name',
251
+ type: 'text',
252
+ label: 'What is your name?',
253
+ description: 'Optional help text',
254
+ required: true,
255
+ minLength: 2,
256
+ maxLength: 100,
257
+ pattern: /^[A-Za-z\s]+$/ // optional regex
258
+ }
259
+ ```
260
+
261
+ ### Number Field
262
+
263
+ Numbers with range and integer validation.
264
+
265
+ ```typescript
266
+ {
267
+ id: 'age',
268
+ type: 'number',
269
+ label: 'How old are you?',
270
+ required: true,
271
+ min: 18,
272
+ max: 120,
273
+ integer: true
274
+ }
275
+ ```
276
+
277
+ ### Email Field
278
+
279
+ Email with automatic pattern validation.
280
+
281
+ ```typescript
282
+ {
283
+ id: 'email',
284
+ type: 'email',
285
+ label: 'What is your email?',
286
+ required: true
287
+ }
288
+ ```
289
+
290
+ ### URL Field
291
+
292
+ URL with http/https format validation.
293
+
294
+ ```typescript
295
+ {
296
+ id: 'website',
297
+ type: 'url',
298
+ label: 'Your website address?',
299
+ required: false
300
+ }
301
+ ```
302
+
303
+ ### Date Field
304
+
305
+ Date in DD/MM/YYYY format with validation.
306
+
307
+ ```typescript
308
+ {
309
+ id: 'birthdate',
310
+ type: 'date',
311
+ label: 'Date of birth?',
312
+ required: true
313
+ }
314
+ ```
315
+
316
+ ### Choice Field
317
+
318
+ Single choice from a list of options.
319
+
320
+ ```typescript
321
+ {
322
+ id: 'service',
323
+ type: 'choice',
324
+ label: 'Which service are you interested in?',
325
+ required: true,
326
+ options: [
327
+ 'Web Development',
328
+ 'Mobile App',
329
+ 'UI/UX Design',
330
+ 'Consulting'
331
+ ]
332
+ }
333
+ // Answer: formShell.answer(2) selects "Mobile App"
334
+ ```
335
+
336
+ Options can also use `{ value, label }` objects:
337
+
338
+ ```typescript
339
+ options: [
340
+ { value: 'web', label: 'Web Development' },
341
+ { value: 'mobile', label: 'Mobile App' }
342
+ ]
343
+ ```
344
+
345
+ ### Multiple Choice Field
346
+
347
+ Multiple selections from a list.
348
+
349
+ ```typescript
350
+ {
351
+ id: 'interests',
352
+ type: 'multiple-choice',
353
+ label: 'Which technologies do you use?',
354
+ required: true,
355
+ options: ['JavaScript', 'Python', 'Java', 'Go', 'Rust'],
356
+ minChoices: 1,
357
+ maxChoices: 3
358
+ }
359
+ // Answer: formShell.answer("1,3,5") selects JavaScript, Java, Rust
360
+ ```
361
+
362
+ ### Rating Field
363
+
364
+ Numeric scale with star visualization.
365
+
366
+ ```typescript
367
+ {
368
+ id: 'satisfaction',
369
+ type: 'rating',
370
+ label: 'How satisfied are you?',
371
+ required: true,
372
+ min: 1,
373
+ max: 5
374
+ }
375
+ // Answer: formShell.answer(4)
376
+ ```
377
+
378
+ ### Yes/No Field
379
+
380
+ Binary Yes/No question.
381
+
382
+ ```typescript
383
+ {
384
+ id: 'newsletter',
385
+ type: 'yesno',
386
+ label: 'Subscribe to newsletter?',
387
+ required: true,
388
+ defaultValue: false
389
+ }
390
+ // Answer: formShell.y() or formShell.n()
391
+ ```
392
+
393
+ ---
394
+
395
+ ## Conditional Logic
396
+
397
+ Steps can be shown or hidden based on previous answers using the `condition` callback:
398
+
399
+ ```typescript
400
+ {
401
+ id: 'react_rating',
402
+ type: 'rating',
403
+ label: 'Rate your React experience',
404
+ required: true,
405
+ min: 1,
406
+ max: 5,
407
+ condition: (data) => {
408
+ return data.position === 'Frontend Developer'
409
+ || data.position === 'Full-stack Developer';
410
+ }
411
+ }
412
+ ```
413
+
414
+ When a step's `condition` returns `false`, it is skipped during navigation, excluded from the progress bar, and hidden in the summary.
415
+
416
+ See `examples/job-application.ts` for a complete conditional-logic example.
417
+
418
+ ---
419
+
420
+ ## Commands Reference
421
+
422
+ | Command | Description |
423
+ |---------|-------------|
424
+ | `formShell.start()` | Start the form from the welcome screen |
425
+ | `formShell.help()` | Show all commands (can be called at any time) |
426
+ | `formShell.continue()` | Resume the form after viewing help |
427
+ | `formShell.answer(value)` | Answer the current question and proceed |
428
+ | `formShell.y()` / `formShell.n()` | Shortcut for yes/no questions |
429
+ | `formShell.skip()` | Skip the current question (if optional) |
430
+ | `formShell.back()` | Go to the previous question |
431
+ | `formShell.submit()` | Submit data to the endpoint (after completing all steps) |
432
+ | `formShell.reset()` | Start over from scratch |
433
+ | `formShell.destroy()` | Cleanup and destroy the instance |
434
+
435
+ ---
436
+
437
+ ## Customization
438
+
439
+ ### Modify the Theme
440
+
441
+ Customize colors and styles by editing `src/formshell/theme.ts`:
442
+
443
+ ```typescript
444
+ export const Theme = {
445
+ colors: {
446
+ primary: '#6366f1',
447
+ secondary: '#8b5cf6',
448
+ success: '#10b981',
449
+ error: '#ef4444',
450
+ // ...
451
+ }
452
+ };
453
+ ```
454
+
455
+ ---
456
+
457
+ ## Project Structure
458
+
459
+ ```
460
+ formshell/
461
+ ├── src/
462
+ │ └── formshell/
463
+ │ ├── types.ts # TypeScript type definitions
464
+ │ ├── theme.ts # Design system (colors, icons, styles)
465
+ │ ├── tui-renderer.ts # Console rendering engine
466
+ │ ├── field-types.ts # Field types and validators
467
+ │ ├── form-framework.ts # Core framework (FormShell class)
468
+ │ └── index.ts # Main entry point and exports
469
+ ├── examples/
470
+ │ ├── contact-form.ts # Contact form example
471
+ │ ├── survey-form.ts # Satisfaction survey example
472
+ │ └── job-application.ts # Job application with conditional logic
473
+ ├── dist/ # Build output
474
+ │ ├── index.js # ESM bundle
475
+ │ └── index.d.ts # Type definitions
476
+ ├── vite.config.ts # Vite config (includes mock API endpoints)
477
+ ├── tsconfig.json # TypeScript configuration
478
+ ├── package.json # Package configuration
479
+ ├── index.html # Demo page
480
+ └── README.md # This documentation
481
+ ```
482
+
483
+ ---
484
+
485
+ ## API Reference
486
+
487
+ ### FormShell
488
+
489
+ #### Constructor
490
+
491
+ ```typescript
492
+ new FormShell(config: FormConfig)
493
+ ```
494
+
495
+ **FormConfig:**
496
+
497
+ | Property | Type | Required | Description |
498
+ |----------|------|----------|-------------|
499
+ | `title` | `string` | yes | Form title shown on welcome/help screens |
500
+ | `subtitle` | `string` | no | Subtitle shown below the title |
501
+ | `endpoint` | `string` | no | POST endpoint for `formShell.submit()` |
502
+ | `steps` | `FieldConfig[]` | yes | Array of field configurations |
503
+ | `onComplete` | `(data: FormData) => void \| Promise<void>` | no | Callback after successful submission |
504
+
505
+ #### Public Methods
506
+
507
+ | Method | Return | Description |
508
+ |--------|--------|-------------|
509
+ | `start()` | `void` | Start the form |
510
+ | `help()` | `void` | Show help (non-blocking) |
511
+ | `continue()` | `void` | Resume after help |
512
+ | `answer(value)` | `void` | Answer current question |
513
+ | `y()` / `n()` | `void` | Yes/No shortcuts |
514
+ | `skip()` | `void` | Skip optional question |
515
+ | `back()` | `void` | Go to previous question |
516
+ | `submit()` | `Promise<void>` | Submit data |
517
+ | `reset()` | `void` | Start over |
518
+ | `destroy()` | `void` | Cleanup instance |
519
+ | `getProgress()` | `ProgressInfo` | Get current progress |
520
+ | `getEstimatedTime()` | `string \| null` | Estimated remaining time |
521
+
522
+ ---
523
+
524
+ ## Data Submission
525
+
526
+ ### POST to Endpoint
527
+
528
+ ```typescript
529
+ const form = new FormShell({
530
+ title: 'My Form',
531
+ endpoint: 'https://api.yoursite.com/submit',
532
+ steps: [/* ... */],
533
+ onComplete: (serverResponse) => {
534
+ // serverResponse is the parsed JSON from the endpoint
535
+ console.log('Server says:', serverResponse);
536
+ }
537
+ });
538
+ ```
539
+
540
+ When `formShell.submit()` is called, FormShell sends:
541
+
542
+ ```
543
+ POST https://api.yoursite.com/submit
544
+ Content-Type: application/json
545
+ Body: { "field_id_1": "value1", "field_id_2": "value2", ... }
546
+ ```
547
+
548
+ ### Without Endpoint
549
+
550
+ ```typescript
551
+ const form = new FormShell({
552
+ title: 'My Form',
553
+ steps: [/* ... */],
554
+ onComplete: (collectedData) => {
555
+ // collectedData is a plain object with all answers
556
+ console.log('Collected:', collectedData);
557
+ }
558
+ });
559
+ ```
560
+
561
+ ### JSON Data Format
562
+
563
+ ```json
564
+ {
565
+ "name": "John Doe",
566
+ "email": "john@example.com",
567
+ "service": "Web Development",
568
+ "rating": 5,
569
+ "newsletter": true,
570
+ "technologies": ["JavaScript", "Python"]
571
+ }
572
+ ```
573
+
574
+ ---
575
+
576
+ ## Complete Examples
577
+
578
+ ### Contact Form
579
+
580
+ See `examples/contact-form.ts` -- a complete contact form with:
581
+ - Name (text, required), Email (email, required), Phone (text, optional)
582
+ - Service selection (choice), Budget (choice), Urgency (choice)
583
+ - Satisfaction rating (rating), Message (text, optional)
584
+ - Newsletter (yes/no), Privacy consent (yes/no)
585
+
586
+ ### Satisfaction Survey
587
+
588
+ See `examples/survey-form.ts` -- a questionnaire with:
589
+ - Single and multiple choice questions
590
+ - Multiple rating scales
591
+ - Text feedback fields
592
+ - Automatic average rating calculation
593
+
594
+ ### Job Application (Conditional Logic)
595
+
596
+ See `examples/job-application.ts` -- a technical interview form with:
597
+ - Position selection drives which questions appear
598
+ - Frontend-specific questions (TypeScript, React, CSS frameworks)
599
+ - Backend-specific questions (Node.js, databases, API design)
600
+ - DevOps-specific questions (cloud, containers, CI/CD)
601
+ - Full-stack candidates see both frontend and backend sections
602
+
603
+ ---
604
+
605
+ ## Validation
606
+
607
+ Each field type has built-in validation:
608
+
609
+ - **Required**: Mandatory field
610
+ - **Min/Max Length**: For text fields
611
+ - **Min/Max Value**: For number and rating fields
612
+ - **Pattern**: Regex for email, URL, date
613
+ - **Options**: Valid choices for choice/multiple-choice
614
+
615
+ Error messages are clear and contextual:
616
+
617
+ ```javascript
618
+ formShell.answer("ab") // minLength: 3 -> "Minimum 3 characters required"
619
+ formShell.answer("bad-email") // -> "Invalid email address"
620
+ formShell.answer(10) // 5 options -> "Choose a number between 1 and 5"
621
+ ```
622
+
623
+ ---
624
+
625
+ ## Browser Compatibility
626
+
627
+ | Browser | Minimum Version | Notes |
628
+ |---------|----------------|-------|
629
+ | Chrome | 88+ | Full support |
630
+ | Firefox | 85+ | Full support |
631
+ | Safari | 14+ | Full support |
632
+ | Edge | 88+ | Full support |
633
+
634
+ **Requirements:**
635
+ - ES6 Modules support
636
+ - `console.log` CSS styling support
637
+ - Active JavaScript console
638
+
639
+ ---
640
+
641
+ ## Troubleshooting
642
+
643
+ ### Form does not appear
644
+ - Make sure you have opened the Browser Console
645
+ - Check for JavaScript errors in the console
646
+ - Verify files are served via HTTP(S), not `file://`
647
+
648
+ ### Colors do not show
649
+ - Some browsers may not support console styling
650
+ - Check browser console settings
651
+
652
+ ### Endpoint does not receive data
653
+ - Check CORS configuration on the server
654
+ - Verify the endpoint accepts `POST` with `Content-Type: application/json`
655
+ - Inspect the Network tab for request details
656
+
657
+ ---
658
+
659
+ ## License
660
+
661
+ MIT License -- Feel free to use this framework in your projects!
662
+
663
+ ## Contributing
664
+
665
+ Contributions, issues, and feature requests are welcome!
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Global TypeScript declarations for FormShell
3
+ *
4
+ * This file provides type definitions for the global `formShell` object
5
+ * attached to the window for console interaction.
6
+ *
7
+ * @example
8
+ * // Access formShell in the console with full type support
9
+ * formShell.start()
10
+ * formShell.answer("response")
11
+ * formShell.submit()
12
+ */
13
+
14
+ import type { FormShell } from './index';
15
+
16
+ declare global {
17
+ interface Window {
18
+ /**
19
+ * Global FormShell instance for console interaction
20
+ * Automatically assigned by the library for development and testing
21
+ */
22
+ formShell: FormShell;
23
+ }
24
+ }
25
+
26
+ export {};