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 +21 -0
- package/README.md +665 -0
- package/dist/global.d.ts +26 -0
- package/dist/index.d.ts +615 -0
- package/dist/index.js +1070 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/formshell/theme.ts","../src/formshell/field-types.ts","../src/formshell/tui-renderer.ts","../src/formshell/form-framework.ts"],"sourcesContent":["/**\n * FormShell Theme - Elegant Design System\n * Color palette, Unicode icons, box styles for elegant console rendering\n */\n\n// Type definitions for the theme\ninterface ColorPalette {\n primary: string;\n secondary: string;\n accent: string;\n success: string;\n error: string;\n warning: string;\n info: string;\n text: {\n primary: string;\n secondary: string;\n muted: string;\n dark: string;\n };\n background: {\n main: string;\n secondary: string;\n accent: string;\n };\n}\n\ninterface Icons {\n checkmark: string;\n cross: string;\n star: string;\n starEmpty: string;\n arrow: string;\n bullet: string;\n bulletEmpty: string;\n chevron: string;\n heart: string;\n info: string;\n warning: string;\n question: string;\n cursor: string;\n cursorBlink: string;\n spinner: string[];\n}\n\ninterface BoxCharacters {\n // Single lines\n topLeft: string;\n topRight: string;\n bottomLeft: string;\n bottomRight: string;\n horizontal: string;\n vertical: string;\n // Double lines (for emphasis)\n doubleTopLeft: string;\n doubleTopRight: string;\n doubleBottomLeft: string;\n doubleBottomRight: string;\n doubleHorizontal: string;\n doubleVertical: string;\n // Progress bar characters\n filled: string;\n empty: string;\n halfFilled: string;\n // Shadow/gradient characters\n shadow: string[];\n fade: string[];\n}\n\ninterface TextFormatters {\n bold: (text: string) => string;\n italic: (text: string) => string;\n underline: (text: string) => string;\n boldUnicode: (text: string) => string;\n}\n\ninterface StylePreset {\n [key: string]: string | undefined;\n color: string;\n fontSize: string;\n fontWeight?: string;\n fontStyle?: string;\n lineHeight?: string;\n textShadow?: string;\n}\n\ninterface StylePresets {\n title: StylePreset;\n subtitle: StylePreset;\n body: StylePreset;\n success: StylePreset;\n error: StylePreset;\n muted: StylePreset;\n highlight: StylePreset;\n}\n\ninterface FormatFunctions {\n title: (text: string) => [string, string];\n subtitle: (text: string) => [string, string];\n body: (text: string) => [string, string];\n success: (text: string) => [string, string];\n error: (text: string) => [string, string];\n muted: (text: string) => [string, string];\n highlight: (text: string) => [string, string];\n colored: (text: string, color: string) => [string, string];\n}\n\ninterface ThemeType {\n colors: ColorPalette;\n icons: Icons;\n box: BoxCharacters;\n text: TextFormatters;\n styles: StylePresets;\n createStyle: (styleObj: Record<string, string | undefined>) => string;\n format: FormatFunctions;\n}\n\nexport const Theme: ThemeType = {\n // Main color palette (CSS styling for console.log)\n colors: {\n primary: '#6366f1', // Indigo\n secondary: '#8b5cf6', // Purple\n accent: '#ec4899', // Pink\n success: '#10b981', // Green\n error: '#ef4444', // Red\n warning: '#f59e0b', // Orange\n info: '#3b82f6', // Blue\n \n text: {\n primary: '#f8fafc', // Almost pure white\n secondary: '#cbd5e1', // Light gray\n muted: '#64748b', // Medium gray\n dark: '#1e293b' // Dark gray for background\n },\n \n background: {\n main: '#0f172a', // Dark blue\n secondary: '#1e293b', // Lighter dark blue\n accent: '#334155' // Blue gray\n }\n },\n\n // Unicode icons for UI elements\n icons: {\n checkmark: '✓',\n cross: '✗',\n star: '★',\n starEmpty: '☆',\n arrow: '➤',\n bullet: '◆',\n bulletEmpty: '◇',\n chevron: '▸',\n heart: '♥',\n info: 'ℹ',\n warning: '⚠',\n question: '?',\n cursor: '█',\n cursorBlink: '▊',\n spinner: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']\n },\n\n // Box drawing characters (Unicode)\n box: {\n // Single lines\n topLeft: '┌',\n topRight: '┐',\n bottomLeft: '└',\n bottomRight: '┘',\n horizontal: '─',\n vertical: '│',\n \n // Double lines (for emphasis)\n doubleTopLeft: '╔',\n doubleTopRight: '╗',\n doubleBottomLeft: '╚',\n doubleBottomRight: '╝',\n doubleHorizontal: '═',\n doubleVertical: '║',\n \n // Progress bar characters\n filled: '▓',\n empty: '░',\n halfFilled: '▒',\n \n // Shadow/gradient characters\n shadow: ['░', '▒', '▓'],\n fade: ['⣀', '⣄', '⣤', '⣦', '⣶', '⣷', '⣿']\n },\n\n // Text styles (using Unicode characters or ANSI)\n text: {\n bold: (text: string): string => `\\x1b[1m${text}\\x1b[0m`,\n italic: (text: string): string => `\\x1b[3m${text}\\x1b[0m`,\n underline: (text: string): string => `\\x1b[4m${text}\\x1b[0m`,\n \n // Alternative using Unicode mathematical characters (fallback)\n boldUnicode: (text: string): string => {\n const bold: Record<string, string> = {\n 'a': '𝗮', 'b': '𝗯', 'c': '𝗰', 'd': '𝗱', 'e': '𝗲', 'f': '𝗳', 'g': '𝗴', \n 'h': '𝗵', 'i': '𝗶', 'j': '𝗷', 'k': '𝗸', 'l': '𝗹', 'm': '𝗺', 'n': '𝗻',\n 'o': '𝗼', 'p': '𝗽', 'q': '𝗾', 'r': '𝗿', 's': '𝘀', 't': '𝘁', 'u': '𝘂',\n 'v': '𝘃', 'w': '𝘄', 'x': '𝘅', 'y': '𝘆', 'z': '𝘇',\n 'A': '𝗔', 'B': '𝗕', 'C': '𝗖', 'D': '𝗗', 'E': '𝗘', 'F': '𝗙', 'G': '𝗚',\n 'H': '𝗛', 'I': '𝗜', 'J': '𝗝', 'K': '𝗞', 'L': '𝗟', 'M': '𝗠', 'N': '𝗡',\n 'O': '𝗢', 'P': '𝗣', 'Q': '𝗤', 'R': '𝗥', 'S': '𝗦', 'T': '𝗧', 'U': '𝗨',\n 'V': '𝗩', 'W': '𝗪', 'X': '𝗫', 'Y': '𝗬', 'Z': '𝗭',\n '0': '𝟬', '1': '𝟭', '2': '𝟮', '3': '𝟯', '4': '𝟰', '5': '𝟱',\n '6': '𝟲', '7': '𝟳', '8': '𝟴', '9': '𝟵'\n };\n return text.split('').map(char => bold[char] || char).join('');\n }\n },\n\n // Style presets for common elements\n styles: {\n title: {\n color: '#6366f1',\n fontSize: '20px',\n fontWeight: 'bold',\n textShadow: '0 0 10px rgba(99, 102, 241, 0.5)'\n },\n \n subtitle: {\n color: '#8b5cf6',\n fontSize: '16px',\n fontWeight: '600'\n },\n \n body: {\n color: '#f8fafc',\n fontSize: '14px',\n lineHeight: '1.5'\n },\n \n success: {\n color: '#10b981',\n fontSize: '14px',\n fontWeight: 'bold'\n },\n \n error: {\n color: '#ef4444',\n fontSize: '14px',\n fontWeight: 'bold'\n },\n \n muted: {\n color: '#64748b',\n fontSize: '13px',\n fontStyle: 'italic'\n },\n \n highlight: {\n color: '#ec4899',\n fontSize: '14px',\n fontWeight: 'bold',\n textShadow: '0 0 8px rgba(236, 72, 153, 0.4)'\n }\n },\n\n // Helper to create CSS style string for console.log\n createStyle: (styleObj: Record<string, string | undefined>): string => {\n return Object.entries(styleObj)\n .filter((entry): entry is [string, string] => entry[1] !== undefined)\n .map(([key, value]) => {\n // Convert camelCase to kebab-case\n const cssKey = key.replace(/([A-Z])/g, '-$1').toLowerCase();\n return `${cssKey}: ${value}`;\n })\n .join('; ');\n },\n\n // Preset messages with styles\n format: {\n title: (text: string): [string, string] => \n [`%c${text}`, Theme.createStyle(Theme.styles.title)],\n subtitle: (text: string): [string, string] => \n [`%c${text}`, Theme.createStyle(Theme.styles.subtitle)],\n body: (text: string): [string, string] => \n [`%c${text}`, Theme.createStyle(Theme.styles.body)],\n success: (text: string): [string, string] => \n [`%c${Theme.icons.checkmark} ${text}`, Theme.createStyle(Theme.styles.success)],\n error: (text: string): [string, string] => \n [`%c${Theme.icons.cross} ${text}`, Theme.createStyle(Theme.styles.error)],\n muted: (text: string): [string, string] => \n [`%c${text}`, Theme.createStyle(Theme.styles.muted)],\n highlight: (text: string): [string, string] => \n [`%c${text}`, Theme.createStyle(Theme.styles.highlight)],\n \n // Quick custom colors\n colored: (text: string, color: string): [string, string] => \n [`%c${text}`, `color: ${color}; font-size: 14px;`]\n }\n};\n","/**\n * FormShell Field Types\n * Field types with validation for multi-step forms\n * Includes: text, number, email, URL, date, choice, multiple-choice, rating, yes/no\n */\n\nimport { Theme } from './theme.js';\nimport type { \n FieldType,\n FieldValue,\n ValidationResult, \n FieldConfig,\n TextFieldConfig,\n NumberFieldConfig,\n ChoiceFieldConfig,\n MultipleChoiceFieldConfig,\n RatingFieldConfig,\n FormData\n} from './types.js';\n\n/**\n * Base class for all field types\n */\nexport class BaseField {\n readonly type: FieldType;\n id: string;\n label: string;\n required: boolean;\n value: FieldValue;\n error: string | null;\n condition?: (formData: FormData) => boolean;\n\n constructor(config: FieldConfig) {\n this.type = config.type;\n this.id = config.id;\n this.label = config.label;\n this.required = config.required !== false; // Default true\n this.value = config.defaultValue ?? null;\n this.error = null;\n this.condition = 'condition' in config ? config.condition : undefined;\n }\n\n /**\n * Validate the field (to be overridden in subclasses)\n */\n validate(value: FieldValue): ValidationResult {\n if (this.required && (value === null || value === undefined || value === '')) {\n return {\n valid: false,\n error: 'This field is required'\n };\n }\n return { valid: true };\n }\n\n /**\n * Format the value for display\n */\n format(value: FieldValue): string {\n return String(value ?? '');\n }\n\n /**\n * Get the current value\n */\n getValue(): FieldValue {\n return this.value;\n }\n\n /**\n * Set the value\n */\n setValue(value: FieldValue): boolean {\n const validation = this.validate(value);\n if (validation.valid) {\n this.value = value;\n this.error = null;\n return true;\n } else {\n this.error = validation.error!;\n return false;\n }\n }\n}\n\n/**\n * Free text field\n */\nexport class TextField extends BaseField {\n minLength: number | null;\n maxLength: number | null;\n pattern: RegExp | null;\n\n constructor(config: TextFieldConfig | FieldConfig) {\n super(config);\n this.minLength = 'minLength' in config ? (config.minLength ?? null) : null;\n this.maxLength = 'maxLength' in config ? (config.maxLength ?? null) : null;\n this.pattern = 'pattern' in config ? (config.pattern ?? null) : null;\n }\n\n validate(value: FieldValue): ValidationResult {\n // Base validation\n const baseValidation = super.validate(value);\n if (!baseValidation.valid) return baseValidation;\n\n // If empty and not required, it's valid\n if (!value && !this.required) {\n return { valid: true };\n }\n\n const strValue = String(value);\n\n // Validate minimum length\n if (this.minLength && strValue.length < this.minLength) {\n return {\n valid: false,\n error: `Minimum ${this.minLength} characters required`\n };\n }\n\n // Validate maximum length\n if (this.maxLength && strValue.length > this.maxLength) {\n return {\n valid: false,\n error: `Maximum ${this.maxLength} characters allowed`\n };\n }\n\n // Validate pattern\n if (this.pattern && !this.pattern.test(strValue)) {\n return {\n valid: false,\n error: 'Invalid format'\n };\n }\n\n return { valid: true };\n }\n}\n\n/**\n * Numeric field\n */\nexport class NumberField extends BaseField {\n min: number | null;\n max: number | null;\n integer: boolean;\n\n constructor(config: NumberFieldConfig | FieldConfig) {\n super(config);\n this.min = 'min' in config && config.min !== undefined ? config.min : null;\n this.max = 'max' in config && config.max !== undefined ? config.max : null;\n this.integer = 'integer' in config ? (config.integer ?? false) : false;\n }\n\n validate(value: FieldValue): ValidationResult {\n // Base validation\n const baseValidation = super.validate(value);\n if (!baseValidation.valid) return baseValidation;\n\n // If empty and not required, it's valid\n if (!value && !this.required) {\n return { valid: true };\n }\n\n // Convert to number\n const numValue = Number(value);\n if (isNaN(numValue)) {\n return {\n valid: false,\n error: 'Must be a valid number'\n };\n }\n\n // Validate integer\n if (this.integer && !Number.isInteger(numValue)) {\n return {\n valid: false,\n error: 'Must be an integer'\n };\n }\n\n // Validate min\n if (this.min !== null && numValue < this.min) {\n return {\n valid: false,\n error: `Minimum value: ${this.min}`\n };\n }\n\n // Validate max\n if (this.max !== null && numValue > this.max) {\n return {\n valid: false,\n error: `Maximum value: ${this.max}`\n };\n }\n\n return { valid: true };\n }\n\n format(value: FieldValue): string {\n return value !== null && value !== undefined ? String(value) : '';\n }\n}\n\n/**\n * Email field\n */\nexport class EmailField extends TextField {\n constructor(config: FieldConfig) {\n super(config);\n // Simplified but effective email regex pattern\n this.pattern = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n }\n\n validate(value: FieldValue): ValidationResult {\n const baseValidation = super.validate(value);\n if (!baseValidation.valid) {\n return {\n valid: false,\n error: baseValidation.error === 'Invalid format' \n ? 'Invalid email address'\n : baseValidation.error!\n };\n }\n return baseValidation;\n }\n}\n\n/**\n * URL field\n */\nexport class URLField extends TextField {\n constructor(config: FieldConfig) {\n super(config);\n // URL regex pattern\n this.pattern = /^https?:\\/\\/.+\\..+/;\n }\n\n validate(value: FieldValue): ValidationResult {\n const baseValidation = super.validate(value);\n if (!baseValidation.valid) {\n return {\n valid: false,\n error: baseValidation.error === 'Invalid format' \n ? 'Invalid URL (must start with http:// or https://)'\n : baseValidation.error!\n };\n }\n return baseValidation;\n }\n}\n\n/**\n * Date field (format DD/MM/YYYY)\n */\nexport class DateField extends TextField {\n constructor(config: FieldConfig) {\n super(config);\n // Pattern for DD/MM/YYYY date\n this.pattern = /^(0[1-9]|[12][0-9]|3[01])\\/(0[1-9]|1[012])\\/(19|20)\\d\\d$/;\n }\n\n validate(value: FieldValue): ValidationResult {\n const baseValidation = super.validate(value);\n if (!baseValidation.valid) {\n return {\n valid: false,\n error: baseValidation.error === 'Invalid format' \n ? 'Invalid date (format: DD/MM/YYYY)'\n : baseValidation.error!\n };\n }\n\n // Additional validation: check if date is real\n if (value && typeof value === 'string' && this.pattern!.test(value)) {\n const [day, month, year] = value.split('/').map(Number);\n const date = new Date(year, month - 1, day);\n \n if (date.getDate() !== day || date.getMonth() !== month - 1 || date.getFullYear() !== year) {\n return {\n valid: false,\n error: 'Invalid date (format: DD/MM/YYYY)'\n };\n }\n }\n\n return baseValidation;\n }\n}\n\n/**\n * Single choice field\n */\nexport class ChoiceField extends BaseField {\n options: Array<string | { value: string; label: string }>;\n\n constructor(config: ChoiceFieldConfig | FieldConfig) {\n super(config);\n this.options = 'options' in config ? (config.options ?? []) : [];\n }\n\n validate(value: FieldValue): ValidationResult {\n const baseValidation = super.validate(value);\n if (!baseValidation.valid) return baseValidation;\n\n // If empty and not required, it's valid\n if (!value && !this.required) {\n return { valid: true };\n }\n\n // Accept both index (number) and direct value\n if (typeof value === 'number') {\n if (value < 1 || value > this.options.length) {\n return {\n valid: false,\n error: `Choose a number between 1 and ${this.options.length}`\n };\n }\n return { valid: true };\n }\n\n // Check if value is among options\n const validOptions = this.options.map(opt => \n typeof opt === 'string' ? opt : opt.value\n );\n \n if (typeof value === 'string' && !validOptions.includes(value)) {\n return {\n valid: false,\n error: 'Invalid choice'\n };\n }\n\n return { valid: true };\n }\n\n setValue(value: FieldValue): boolean {\n // Convert number to actual value\n if (typeof value === 'number') {\n const index = value - 1;\n if (index >= 0 && index < this.options.length) {\n const option = this.options[index];\n const actualValue = typeof option === 'string' ? option : option.value;\n return super.setValue(actualValue);\n }\n }\n return super.setValue(value);\n }\n\n format(value: FieldValue): string {\n if (!value) return '';\n const option = this.options.find(opt => \n (typeof opt === 'string' ? opt : opt.value) === value\n );\n return typeof option === 'string' ? option : (option?.label || String(value));\n }\n}\n\n/**\n * Multiple choice field\n */\nexport class MultipleChoiceField extends BaseField {\n options: Array<string | { value: string; label: string }>;\n minChoices: number;\n maxChoices: number;\n\n constructor(config: MultipleChoiceFieldConfig | FieldConfig) {\n super(config);\n this.options = 'options' in config ? (config.options ?? []) : [];\n this.minChoices = 'minChoices' in config ? (config.minChoices ?? (this.required ? 1 : 0)) : (this.required ? 1 : 0);\n this.maxChoices = 'maxChoices' in config ? (config.maxChoices ?? this.options.length) : this.options.length;\n }\n\n validate(value: FieldValue): ValidationResult {\n // Value must be an array\n if (!Array.isArray(value)) {\n if (this.required) {\n return {\n valid: false,\n error: 'Select at least 1 option(s)'\n };\n }\n return { valid: true };\n }\n\n // Validate minimum number of choices\n if (value.length < this.minChoices) {\n return {\n valid: false,\n error: `Select at least ${this.minChoices} option(s)`\n };\n }\n\n // Validate maximum number of choices\n if (value.length > this.maxChoices) {\n return {\n valid: false,\n error: `Select maximum ${this.maxChoices} option(s)`\n };\n }\n\n // Validate each individual choice\n const validOptions = this.options.map(opt => \n typeof opt === 'string' ? opt : opt.value\n );\n\n for (const choice of value) {\n if (!validOptions.includes(choice)) {\n return {\n valid: false,\n error: 'One or more choices are invalid'\n };\n }\n }\n\n return { valid: true };\n }\n\n setValue(value: FieldValue): boolean {\n // Convert comma or space separated input to array\n if (typeof value === 'string') {\n const indices = value.split(/[,\\s]+/).map(v => v.trim()).filter(v => v);\n const values: string[] = [];\n for (const idx of indices) {\n const num = Number(idx);\n if (!isNaN(num) && num >= 1 && num <= this.options.length) {\n const option = this.options[num - 1];\n values.push(typeof option === 'string' ? option : option.value);\n }\n }\n return super.setValue(values);\n }\n\n return super.setValue(value);\n }\n\n format(value: FieldValue): string {\n if (!Array.isArray(value) || value.length === 0) return 'No selection';\n \n const formatted = value.map(v => {\n const option = this.options.find(opt => \n (typeof opt === 'string' ? opt : opt.value) === v\n );\n return typeof option === 'string' ? option : (option?.label || v);\n });\n \n return formatted.join(', ');\n }\n}\n\n/**\n * Rating field (scale 1-5 with stars)\n */\nexport class RatingField extends NumberField {\n constructor(config: RatingFieldConfig | FieldConfig) {\n super(config);\n this.min = 'min' in config && config.min !== undefined ? config.min : 1;\n this.max = 'max' in config && config.max !== undefined ? config.max : 5;\n this.integer = true;\n }\n\n validate(value: FieldValue): ValidationResult {\n const numValidation = super.validate(value);\n if (!numValidation.valid) {\n return {\n valid: false,\n error: numValidation.error!.includes('number')\n ? `Enter a number from ${this.min} to ${this.max}`\n : numValidation.error!\n };\n }\n return numValidation;\n }\n\n format(value: FieldValue): string {\n if (!value || typeof value !== 'number') return '';\n const stars = Theme.icons.star.repeat(value) + Theme.icons.starEmpty.repeat((this.max ?? 5) - value);\n return `${stars} (${value}/${this.max})`;\n }\n}\n\n/**\n * Yes/No field\n */\nexport class YesNoField extends BaseField {\n constructor(config: FieldConfig) {\n super(config);\n this.value = config.defaultValue || null;\n }\n\n validate(value: FieldValue): ValidationResult {\n const baseValidation = super.validate(value);\n if (!baseValidation.valid) return baseValidation;\n\n // Accept boolean, 'y', 'n', 'yes', 'no', 's', 'si', 'sì'\n if (typeof value === 'boolean') {\n return { valid: true };\n }\n\n if (typeof value === 'string') {\n const normalized = value.toLowerCase().trim();\n if (['y', 'yes', 's', 'si', 'sì', 'n', 'no'].includes(normalized)) {\n return { valid: true };\n }\n }\n\n return {\n valid: false,\n error: 'Answer with Y (yes) or N (no)'\n };\n }\n\n setValue(value: FieldValue): boolean {\n // Normalize value to boolean\n if (typeof value === 'string') {\n const normalized = value.toLowerCase().trim();\n if (['y', 'yes', 's', 'si', 'sì'].includes(normalized)) {\n this.value = true;\n this.error = null;\n return true;\n } else if (['n', 'no'].includes(normalized)) {\n this.value = false;\n this.error = null;\n return true;\n }\n }\n \n if (typeof value === 'boolean') {\n this.value = value;\n this.error = null;\n return true;\n }\n\n this.error = 'Answer with Y (yes) or N (no)';\n return false;\n }\n\n format(value: FieldValue): string {\n if (value === true) return 'Yes';\n if (value === false) return 'No';\n return '';\n }\n}\n\n/**\n * Factory to create fields from type\n */\nexport const FieldFactory = {\n create(config: FieldConfig): BaseField {\n const type = (config.type || 'text').toLowerCase();\n \n switch (type) {\n case 'text':\n return new TextField(config);\n case 'number':\n return new NumberField(config);\n case 'email':\n return new EmailField(config);\n case 'url':\n return new URLField(config);\n case 'date':\n return new DateField(config);\n case 'choice':\n return new ChoiceField(config);\n case 'multiple-choice':\n case 'multiplechoice':\n return new MultipleChoiceField(config);\n case 'rating':\n return new RatingField(config);\n case 'yesno':\n case 'yes-no':\n return new YesNoField(config);\n default:\n console.warn(`Unknown field type: ${type}, defaulting to text`);\n return new TextField(config);\n }\n }\n};\n","/**\n * FormShell TUI Renderer\n * Handles elegant rendering in the browser console\n * Includes blinking cursor, animations, Unicode boxes, and CSS styling\n */\n\nimport { Theme } from './theme.js';\n\n// ANSI escape character (ESC) used in terminal color codes\nconst ANSI_ESC = '\\x1b';\n\ninterface ProgressBarResult {\n bar: string;\n percentage: number;\n text: string;\n}\n\nexport class TUIRenderer {\n private cursorVisible: boolean;\n private cursorInterval: number | null;\n\n constructor() {\n this.cursorVisible = true;\n this.cursorInterval = null;\n }\n\n /**\n * Initialize the renderer and start cursor blinking\n */\n init(): void {\n this.startCursorBlink();\n }\n\n /**\n * Clear the console\n */\n clear(): void {\n console.clear();\n }\n\n /**\n * Start the cursor blinking animation\n */\n startCursorBlink(): void {\n if (this.cursorInterval) {\n clearInterval(this.cursorInterval);\n }\n \n this.cursorInterval = window.setInterval(() => {\n this.cursorVisible = !this.cursorVisible;\n }, 530); // Standard blink speed\n }\n\n /**\n * Stop the cursor animation\n */\n stopCursorBlink(): void {\n if (this.cursorInterval) {\n clearInterval(this.cursorInterval);\n this.cursorInterval = null;\n }\n }\n\n /**\n * Get the current cursor character\n */\n getCursor(): string {\n return this.cursorVisible ? Theme.icons.cursor : ' ';\n }\n\n /**\n * Create a decorative horizontal line\n */\n createHorizontalLine(width: number = 60, char: string = Theme.box.horizontal): string {\n return char.repeat(width);\n }\n\n /**\n * Create a box with Unicode borders\n */\n createBox(content: string | string[], width: number = 60, style: 'single' | 'double' = 'single'): string[] {\n const lines: string[] = [];\n const useDouble = style === 'double';\n \n const topLeft = useDouble ? Theme.box.doubleTopLeft : Theme.box.topLeft;\n const topRight = useDouble ? Theme.box.doubleTopRight : Theme.box.topRight;\n const bottomLeft = useDouble ? Theme.box.doubleBottomLeft : Theme.box.bottomLeft;\n const bottomRight = useDouble ? Theme.box.doubleBottomRight : Theme.box.bottomRight;\n const horizontal = useDouble ? Theme.box.doubleHorizontal : Theme.box.horizontal;\n const vertical = useDouble ? Theme.box.doubleVertical : Theme.box.vertical;\n \n // Top border\n lines.push(topLeft + horizontal.repeat(width - 2) + topRight);\n \n // Content lines\n const contentLines = Array.isArray(content) ? content : [content];\n contentLines.forEach(line => {\n const lineStr = String(line);\n // Remove ANSI style characters to calculate correct length\n // Remove ANSI escape codes (ESC[...m pattern) - ESC character is \\x1b (ASCII 27)\n const ansiEscapePattern = new RegExp(`${ANSI_ESC}\\\\[[0-9;]*m`, 'g');\n const plainText = lineStr.replace(ansiEscapePattern, '');\n const padding = width - 2 - plainText.length;\n const leftPad = Math.floor(padding / 2);\n const rightPad = padding - leftPad;\n \n lines.push(vertical + ' '.repeat(leftPad) + lineStr + ' '.repeat(rightPad) + vertical);\n });\n \n // Bottom border\n lines.push(bottomLeft + horizontal.repeat(width - 2) + bottomRight);\n \n return lines;\n }\n\n /**\n * Create an elegant progress bar\n */\n createProgressBar(current: number, total: number, width: number = 40): ProgressBarResult {\n const percentage = Math.round((current / total) * 100);\n const filledWidth = Math.round((current / total) * width);\n const emptyWidth = width - filledWidth;\n \n const filled = Theme.box.filled.repeat(filledWidth);\n const empty = Theme.box.empty.repeat(emptyWidth);\n \n return {\n bar: filled + empty,\n percentage: percentage,\n text: `${current}/${total}`\n };\n }\n\n /**\n * Render the main title with style\n */\n renderTitle(title: string): void {\n const [format, style] = Theme.format.title(title);\n console.log(format, style);\n }\n\n /**\n * Render the subtitle with style\n */\n renderSubtitle(subtitle: string): void {\n const [format, style] = Theme.format.subtitle(subtitle);\n console.log(format, style);\n }\n\n /**\n * Render normal text\n */\n renderText(text: string, color: string | null = null): void {\n if (color) {\n const [format, style] = Theme.format.colored(text, color);\n console.log(format, style);\n } else {\n const [format, style] = Theme.format.body(text);\n console.log(format, style);\n }\n }\n\n /**\n * Render a success message\n */\n renderSuccess(message: string): void {\n const [format, style] = Theme.format.success(message);\n console.log(format, style);\n }\n\n /**\n * Render an error message\n */\n renderError(message: string): void {\n const [format, style] = Theme.format.error(message);\n console.log(format, style);\n }\n\n /**\n * Render muted/secondary text\n */\n renderMuted(text: string): void {\n const [format, style] = Theme.format.muted(text);\n console.log(format, style);\n }\n\n /**\n * Render highlighted text\n */\n renderHighlight(text: string): void {\n const [format, style] = Theme.format.highlight(text);\n console.log(format, style);\n }\n\n /**\n * Render a complete box\n */\n renderBox(content: string | string[], width: number = 60, style: 'single' | 'double' = 'single'): void {\n const boxLines = this.createBox(content, width, style);\n boxLines.forEach(line => {\n this.renderText(line, Theme.colors.text.secondary);\n });\n }\n\n /**\n * Render a separator line\n */\n renderSeparator(width: number = 60, char: string = Theme.box.horizontal): void {\n const line = this.createHorizontalLine(width, char);\n this.renderMuted(line);\n }\n\n /**\n * Render the progress bar with info\n */\n renderProgress(current: number, total: number, label: string = 'Progress'): void {\n const progress = this.createProgressBar(current, total);\n \n console.log('');\n this.renderMuted(`${label}: ${progress.text} (${progress.percentage}%)`);\n this.renderHighlight(progress.bar);\n console.log('');\n }\n\n /**\n * Render a list of options\n */\n renderOptions(options: string[], highlightIndex: number | null = null): void {\n options.forEach((option, index) => {\n const number = index + 1;\n const isHighlighted = highlightIndex === index;\n \n if (isHighlighted) {\n this.renderHighlight(` ${number}. ${option}`);\n } else {\n this.renderText(` ${number}. ${option}`, Theme.colors.text.secondary);\n }\n });\n }\n\n /**\n * Render an input field with cursor\n */\n renderInput(label: string, value: string = '', showCursor: boolean = true): void {\n const cursor = showCursor ? this.getCursor() : '';\n const displayValue = value + cursor;\n \n console.log('');\n this.renderHighlight(`${Theme.icons.chevron} ${label}`);\n console.log('');\n this.renderText(` ${displayValue}`, Theme.colors.primary);\n console.log('');\n }\n\n /**\n * Render a yes/no question\n */\n renderYesNo(question: string, value: boolean | null = null, yesLabel: string = 'Yes', noLabel: string = 'No'): void {\n console.log('');\n this.renderHighlight(`${Theme.icons.question} ${question}`);\n console.log('');\n \n const yesText = ` ${Theme.icons.bulletEmpty} Y - ${yesLabel}`;\n const noText = ` ${Theme.icons.bulletEmpty} N - ${noLabel}`;\n \n if (value === true) {\n this.renderHighlight(yesText);\n this.renderMuted(noText);\n } else if (value === false) {\n this.renderMuted(yesText);\n this.renderHighlight(noText);\n } else {\n this.renderMuted(yesText);\n this.renderMuted(noText);\n }\n \n console.log('');\n }\n\n /**\n * Render rating with stars\n */\n renderRating(label: string, value: number = 0, max: number = 5): void {\n console.log('');\n this.renderHighlight(`${Theme.icons.star} ${label}`);\n console.log('');\n \n let stars = '';\n for (let i = 1; i <= max; i++) {\n if (i <= value) {\n stars += Theme.icons.star + ' ';\n } else {\n stars += Theme.icons.starEmpty + ' ';\n }\n }\n \n this.renderText(` ${stars}`, Theme.colors.warning);\n this.renderMuted(` (${value}/${max})`);\n console.log('');\n }\n\n /**\n * Render a summary with key-value data\n */\n renderSummary(title: string, data: Record<string, unknown>): void {\n console.log('');\n this.renderTitle(title);\n this.renderSeparator(60);\n console.log('');\n \n Object.entries(data).forEach(([key, value]) => {\n const displayKey = key.charAt(0).toUpperCase() + key.slice(1);\n this.renderText(`${Theme.icons.bullet} ${displayKey}:`, Theme.colors.text.secondary);\n this.renderHighlight(` ${value}`);\n console.log('');\n });\n \n this.renderSeparator(60);\n }\n\n /**\n * Render a help/commands message\n */\n renderHelp(commands: Array<{ command: string; description: string }>, title: string = 'Available Commands'): void {\n console.log('');\n this.renderTitle(`📋 ${title}`);\n this.renderSeparator(60);\n console.log('');\n \n commands.forEach(({ command, description }) => {\n this.renderHighlight(` ${Theme.icons.chevron} ${command}`);\n this.renderMuted(` ${description}`);\n console.log('');\n });\n \n this.renderSeparator(60);\n }\n\n /**\n * Render an animated welcome message\n */\n renderWelcome(title: string, subtitle: string | null = null): void {\n this.clear();\n console.log('');\n console.log('');\n \n this.renderTitle(`✨ ${title} ✨`);\n \n if (subtitle) {\n console.log('');\n this.renderSubtitle(subtitle);\n }\n \n console.log('');\n this.renderSeparator(60, Theme.box.doubleHorizontal);\n console.log('');\n }\n\n /**\n * Render a spinner/loader (static, not animated)\n */\n renderLoader(message: string = 'Loading...'): void {\n const spinner = Theme.icons.spinner[0];\n this.renderText(`${spinner} ${message}`, Theme.colors.info);\n }\n\n /**\n * Cleanup the renderer\n */\n destroy(): void {\n this.stopCursorBlink();\n }\n}\n","/**\n * FormShell - Form Framework\n * Framework for interactive multi-step forms in the browser console\n * One-question-at-a-time style with simple API for interaction\n */\n\nimport {\n ChoiceField,\n FieldFactory,\n MultipleChoiceField,\n NumberField,\n RatingField,\n} from \"./field-types.js\";\nimport { Theme } from \"./theme.js\";\nimport { TUIRenderer } from \"./tui-renderer.js\";\nimport type {\n FieldConfig,\n FieldInstance,\n FormConfig,\n FormData,\n ProgressInfo,\n Step,\n} from \"./types.js\";\n\nexport class FormShell {\n\ttitle: string;\n\tsubtitle: string | null;\n\tendpoint: string | null;\n\tonComplete: ((data: FormData) => void | Promise<void>) | null;\n\tsteps: Step[];\n\n\tprivate currentStepIndex: number;\n\tprivate renderer: TUIRenderer;\n\tprivate started: boolean;\n\tprivate completed: boolean;\n\tprivate startTime: number | null;\n\tprivate helpActive: boolean;\n\n\tconstructor(config: FormConfig) {\n\t\tthis.title = config.title || \"Form\";\n\t\tthis.subtitle = config.subtitle || null;\n\t\tthis.endpoint = config.endpoint || null;\n\t\tthis.onComplete = config.onComplete || null;\n\t\tthis.steps = this.initializeSteps(config.steps || []);\n\n\t\tthis.currentStepIndex = -1; // -1 = welcome screen\n\t\tthis.renderer = new TUIRenderer();\n\t\tthis.started = false;\n\t\tthis.completed = false;\n\t\tthis.startTime = null;\n\t\tthis.helpActive = false;\n\n\t\t// Initialize the renderer\n\t\tthis.renderer.init();\n\n\t\t// Show welcome screen\n\t\tthis.showWelcome();\n\t}\n\n\t/**\n\t * Initialize steps with appropriate field types\n\t */\n\tprivate initializeSteps(stepsConfig: FieldConfig[]): Step[] {\n\t\treturn stepsConfig.map((stepConfig, index) => {\n\t\t\tconst field = FieldFactory.create(stepConfig);\n\t\t\treturn {\n\t\t\t\tid: stepConfig.id || `step_${index}`,\n\t\t\t\tfield,\n\t\t\t\tdescription: stepConfig.description ?? null,\n\t\t\t\tanswered: false,\n\t\t\t};\n\t\t});\n\t}\n\n\t/**\n\t * Show welcome screen\n\t */\n\tprivate showWelcome(): void {\n\t\tthis.renderer.clear();\n\t\tconsole.log(\"\");\n\t\tthis.renderer.renderTitle(this.title);\n\t\tif (this.subtitle) {\n\t\t\tthis.renderer.renderMuted(this.subtitle);\n\t\t}\n\t\tconsole.log(\"\");\n\t\tthis.renderer.renderMuted(\"Type formShell.start() to begin or formShell.help() for available commands\");\n\t\tconsole.log(\"\");\n\t}\n\n\t/**\n\t * Show help screen with commands.\n\t * Can be called at any time without interrupting the form flow.\n\t * Use formShell.continue() to resume where you left off.\n\t */\n\thelp(): void {\n\t\tthis.helpActive = true;\n\n\t\tthis.renderer.clear();\n\t\tconsole.log(\"\");\n\n\t\tthis.renderer.renderTitle(this.title);\n\t\tif (this.subtitle) {\n\t\t\tthis.renderer.renderMuted(this.subtitle);\n\t\t}\n\t\tconsole.log(\"\");\n\n\t\tthis.renderer.renderHighlight(\"Commands:\");\n\t\tthis.renderer.renderMuted(\" formShell.start() Start the form\");\n\t\tthis.renderer.renderMuted(\" formShell.continue() Resume the form\");\n\t\tthis.renderer.renderMuted(\" formShell.answer(...) Answer and proceed\");\n\t\tthis.renderer.renderMuted(\" formShell.skip() Skip (if optional)\");\n\t\tthis.renderer.renderMuted(\" formShell.y() / formShell.n() Yes / No\");\n\t\tthis.renderer.renderMuted(\" formShell.back() Go back\");\n\t\tthis.renderer.renderMuted(\" formShell.submit() Submit (at the end)\");\n\t\tthis.renderer.renderMuted(\" formShell.reset() Start over\");\n\t\tthis.renderer.renderMuted(\" formShell.help() Show this help\");\n\t\tconsole.log(\"\");\n\n\t\tthis.renderer.renderMuted(\"Type formShell.continue() to resume\");\n\t\tconsole.log(\"\");\n\t}\n\n\t/**\n\t * Start the form (only from welcome screen)\n\t */\n\tstart(): void {\n\t\tif (this.helpActive) {\n\t\t\tthis.renderer.renderError(\"Use formShell.continue() to resume the form first\");\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.started) {\n\t\t\tthis.renderer.renderError(\"Form already started. Use formShell.reset() to start over\");\n\t\t\treturn;\n\t\t}\n\n\t\tconst firstVisibleIndex = this.getNextVisibleStep(-1);\n\t\tif (firstVisibleIndex >= this.steps.length) {\n\t\t\tthis.renderer.renderError(\"No visible steps in form\");\n\t\t\treturn;\n\t\t}\n\n\t\tthis.currentStepIndex = firstVisibleIndex;\n\t\tthis.started = true;\n\t\tthis.startTime = Date.now();\n\t\tthis.renderCurrentStep();\n\t}\n\n\t/**\n\t * Resume the form after viewing help\n\t */\n\tcontinue(): void {\n\t\tif (!this.helpActive) {\n\t\t\tif (!this.started) {\n\t\t\t\tthis.renderer.renderError(\"Use formShell.start() to begin the form\");\n\t\t\t} else {\n\t\t\t\tthis.renderer.renderError(\"Use formShell.answer() to respond to the current question\");\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tthis.helpActive = false;\n\n\t\t// Restore the appropriate view\n\t\tif (!this.started) {\n\t\t\tthis.showWelcome();\n\t\t} else if (this.completed) {\n\t\t\tthis.showSummary();\n\t\t} else {\n\t\t\tthis.renderCurrentStep();\n\t\t}\n\t}\n\n\t/**\n\t * Check if a step should be shown based on its condition\n\t */\n\tprivate shouldShowStep(stepIndex: number): boolean {\n\t\tconst step = this.steps[stepIndex];\n\t\tif (!step.field.condition) {\n\t\t\treturn true; // No condition = always show\n\t\t}\n\n\t\t// Collect current form data to evaluate condition\n\t\tconst currentData = this.collectData();\n\t\treturn step.field.condition(currentData);\n\t}\n\n\t/**\n\t * Get next visible step index\n\t */\n\tprivate getNextVisibleStep(fromIndex: number): number {\n\t\tfor (let i = fromIndex + 1; i < this.steps.length; i++) {\n\t\t\tif (this.shouldShowStep(i)) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn this.steps.length; // End of form\n\t}\n\n\t/**\n\t * Get previous visible step index\n\t */\n\tprivate getPreviousVisibleStep(fromIndex: number): number {\n\t\tfor (let i = fromIndex - 1; i >= 0; i--) {\n\t\t\tif (this.shouldShowStep(i)) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn -1; // Start of form\n\t}\n\n\t/**\n\t * Advance to next step (internal method)\n\t */\n\tprivate _advanceStep(): void {\n\t\tif (this.completed) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Get next visible step\n\t\tconst nextIndex = this.getNextVisibleStep(this.currentStepIndex);\n\n\t\tif (nextIndex < this.steps.length) {\n\t\t\tthis.currentStepIndex = nextIndex;\n\t\t\tthis.renderCurrentStep();\n\t\t} else {\n\t\t\t// Form completed, show summary\n\t\t\tthis.completed = true;\n\t\t\tthis.showSummary();\n\t\t}\n\t}\n\n\t/**\n\t * Go back to previous step\n\t */\n\tback(): void {\n\t\tif (this.helpActive) {\n\t\t\tthis.renderer.renderError(\"Use formShell.continue() to resume the form first\");\n\t\t\treturn;\n\t\t}\n\n\t\tconst prevIndex = this.getPreviousVisibleStep(this.currentStepIndex);\n\n\t\tif (prevIndex < 0) {\n\t\t\tthis.renderer.renderError(\"Already at first question. Use formShell.help() for commands\");\n\t\t\treturn;\n\t\t}\n\n\t\tthis.currentStepIndex = prevIndex;\n\t\tthis.completed = false;\n\t\tthis.renderCurrentStep();\n\t}\n\n\t/**\n\t * Answer the current question\n\t */\n\tanswer(value: string | number): void {\n\t\tif (this.helpActive) {\n\t\t\tthis.renderer.renderError(\"Use formShell.continue() to resume the form first\");\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.started) {\n\t\t\tthis.renderer.renderError(\"Use formShell.start() to begin the form\");\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.completed) {\n\t\t\tthis.renderer.renderError(\"Form already completed! Use formShell.submit() to send or formShell.reset() to start over\");\n\t\t\treturn;\n\t\t}\n\n\t\tconst step = this.steps[this.currentStepIndex];\n\t\tconst field = step.field;\n\n\t\t// Try to set the value\n\t\tconst success = field.setValue(value);\n\n\t\tif (success) {\n\t\t\tstep.answered = true;\n\t\t\tthis.renderer.renderSuccess(`${field.format(field.getValue())}`);\n\t\t\tconsole.log(\"\");\n\n\t\t\t// Automatically advance to next step after 1 second\n\t\t\tsetTimeout(() => {\n\t\t\t\tthis._advanceStep();\n\t\t\t}, 1000);\n\t\t} else {\n\t\t\tthis.renderer.renderError(field.error ?? \"Invalid value\");\n\t\t\tconsole.log(\"\");\n\t\t}\n\t}\n\n\t/**\n\t * Shortcut to answer \"Yes\"\n\t */\n\ty(): void {\n\t\tthis.answer(\"y\");\n\t}\n\n\t/**\n\t * Shortcut to answer \"No\"\n\t */\n\tn(): void {\n\t\tthis.answer(\"n\");\n\t}\n\n\t/**\n\t * Skip the current question (only if not required)\n\t */\n\tskip(): void {\n\t\tif (this.helpActive) {\n\t\t\tthis.renderer.renderError(\"Use formShell.continue() to resume the form first\");\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.started) {\n\t\t\tthis.renderer.renderError(\"Use formShell.start() to begin the form\");\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.completed) {\n\t\t\tthis.renderer.renderError(\"Form already completed! Use formShell.submit() to send or formShell.reset() to start over\");\n\t\t\treturn;\n\t\t}\n\n\t\tconst step = this.steps[this.currentStepIndex];\n\t\tconst field = step.field;\n\n\t\tif (field.required) {\n\t\t\tthis.renderer.renderError(\"This question is required and cannot be skipped\");\n\t\t\tconsole.log(\"\");\n\t\t\treturn;\n\t\t}\n\n\t\t// Mark as answered (with null value)\n\t\tstep.answered = true;\n\t\tfield.value = null;\n\t\tthis.renderer.renderMuted(\"Skipped\");\n\t\tconsole.log(\"\");\n\n\t\t// Automatically advance to next step after 1 second\n\t\tsetTimeout(() => {\n\t\t\tthis._advanceStep();\n\t\t}, 1000);\n\t}\n\n\t/**\n\t * Reset the form\n\t */\n\treset(): void {\n\t\tthis.currentStepIndex = -1;\n\t\tthis.started = false;\n\t\tthis.completed = false;\n\t\tthis.startTime = null;\n\t\tthis.helpActive = false;\n\n\t\t// Reset all steps\n\t\tthis.steps.forEach((step) => {\n\t\t\tstep.answered = false;\n\t\t\tstep.field.value = null;\n\t\t\tstep.field.error = null;\n\t\t});\n\n\t\tthis.showWelcome();\n\t}\n\n\t/**\n\t * Submit data to server\n\t */\n\tasync submit(): Promise<void> {\n\t\tif (this.helpActive) {\n\t\t\tthis.renderer.renderError(\"Use formShell.continue() to resume the form first\");\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.completed) {\n\t\t\tthis.renderer.renderError(\"Complete all questions first!\");\n\t\t\treturn;\n\t\t}\n\n\t\tconst data = this.collectData();\n\t\tconsole.log(\"\");\n\t\tthis.renderer.renderMuted(\"Submitting...\");\n\n\t\ttry {\n\t\t\tif (this.endpoint) {\n\t\t\t\tconst response = await fetch(this.endpoint, {\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\theaders: {\n\t\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t},\n\t\t\t\t\tbody: JSON.stringify(data),\n\t\t\t\t});\n\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(`HTTP error! status: ${response.status}`);\n\t\t\t\t}\n\n\t\t\t\tconst result = await response.json();\n\t\t\t\tthis.renderer.renderSuccess(\"Submitted!\");\n\t\t\t\tconsole.log(\"\");\n\n\t\t\t\tif (this.onComplete) {\n\t\t\t\t\tawait this.onComplete(result);\n\t\t\t\t}\n\n\t\t\t\tconsole.log(\"Response:\", result);\n\t\t\t} else {\n\t\t\t\tthis.renderer.renderSuccess(\"Completed!\");\n\t\t\t\tconsole.log(\"\");\n\t\t\t\tconsole.log(\"Data:\", data);\n\n\t\t\t\tif (this.onComplete) {\n\t\t\t\t\tawait this.onComplete(data);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error: unknown) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthis.renderer.renderError(`Error: ${message}`);\n\t\t\tconsole.log(\"\");\n\t\t}\n\t}\n\n\t/**\n\t * Collect all form data\n\t */\n\tprivate collectData(): FormData {\n\t\tconst data: FormData = {};\n\t\tthis.steps.forEach((step) => {\n\t\t\tdata[step.field.id] = step.field.getValue();\n\t\t});\n\t\treturn data;\n\t}\n\n\t/**\n\t * Calculate completion percentage\n\t */\n\tgetProgress(): ProgressInfo {\n\t\t// Only count visible steps\n\t\tconst visibleSteps = this.steps.filter((_, idx) =>\n\t\t\tthis.shouldShowStep(idx),\n\t\t);\n\t\tconst answeredVisible = visibleSteps.filter((s) => s.answered).length;\n\n\t\treturn {\n\t\t\tcurrent: answeredVisible,\n\t\t\ttotal: visibleSteps.length,\n\t\t\tpercentage:\n\t\t\t\tvisibleSteps.length > 0\n\t\t\t\t\t? Math.round((answeredVisible / visibleSteps.length) * 100)\n\t\t\t\t\t: 0,\n\t\t};\n\t}\n\n\t/**\n\t * Estimate remaining time\n\t */\n\tgetEstimatedTime(): string | null {\n\t\tif (!this.startTime || this.currentStepIndex < 1) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst elapsed = Date.now() - this.startTime;\n\t\tconst avgTimePerStep = elapsed / (this.currentStepIndex + 1);\n\t\tconst remainingSteps = this.steps.length - this.currentStepIndex - 1;\n\t\tconst estimatedMs = avgTimePerStep * remainingSteps;\n\n\t\tconst seconds = Math.round(estimatedMs / 1000);\n\t\tif (seconds < 60) {\n\t\t\treturn `~${seconds}s`;\n\t\t} else {\n\t\t\tconst minutes = Math.round(seconds / 60);\n\t\t\treturn `~${minutes}m`;\n\t\t}\n\t}\n\n\t/**\n\t * Render the current step\n\t */\n\tprivate renderCurrentStep(): void {\n\t\tthis.renderer.clear();\n\n\t\tconst step = this.steps[this.currentStepIndex];\n\t\tconst field = step.field;\n\n\t\tconsole.log(\"\");\n\n\t\t// Calculate progress for visible steps only\n\t\tconst progress = this.getProgress();\n\t\tconst visibleStepNumber = this.getVisibleStepNumber(this.currentStepIndex);\n\n\t\t// Compact progress bar\n\t\tconst progressBar = this.renderer.createProgressBar(\n\t\t\tvisibleStepNumber,\n\t\t\tprogress.total,\n\t\t\t30,\n\t\t);\n\t\tthis.renderer.renderMuted(`[${progressBar.bar}] ${progressBar.text}`);\n\t\tconsole.log(\"\");\n\n\t\t// Question title\n\t\tthis.renderer.renderHighlight(`${visibleStepNumber}. ${field.label}`);\n\n\t\t// Additional description if present\n\t\tif (step.description) {\n\t\t\tthis.renderer.renderMuted(` ${step.description}`);\n\t\t}\n\t\tconsole.log(\"\");\n\n\t\t// Render field based on type\n\t\tthis.renderField(field);\n\t}\n\n\t/**\n\t * Get the visible step number (position among visible steps)\n\t */\n\tprivate getVisibleStepNumber(stepIndex: number): number {\n\t\tlet visibleCount = 0;\n\t\tfor (let i = 0; i <= stepIndex; i++) {\n\t\t\tif (this.shouldShowStep(i)) {\n\t\t\t\tvisibleCount++;\n\t\t\t}\n\t\t}\n\t\treturn visibleCount;\n\t}\n\n\t/**\n\t * Render a field based on its type\n\t */\n\tprivate renderField(field: FieldInstance): void {\n\t\tif (field instanceof RatingField) {\n\t\t\tthis.renderer.renderMuted(` formShell.answer(1-${field.max})`);\n\t\t\tconst stars = Theme.icons.starEmpty.repeat(field.max ?? 5);\n\t\t\tthis.renderer.renderText(` ${stars}`, Theme.colors.warning);\n\t\t} else if (field instanceof ChoiceField) {\n\t\t\tthis.renderer.renderOptions(\n\t\t\t\tfield.options.map((opt) =>\n\t\t\t\t\ttypeof opt === \"string\" ? opt : opt.label,\n\t\t\t\t),\n\t\t\t);\n\t\t\tthis.renderer.renderMuted(\" formShell.answer(number)\");\n\t\t} else if (field instanceof MultipleChoiceField) {\n\t\t\tthis.renderer.renderOptions(\n\t\t\t\tfield.options.map((opt) =>\n\t\t\t\t\ttypeof opt === \"string\" ? opt : opt.label,\n\t\t\t\t),\n\t\t\t);\n\t\t\tthis.renderer.renderMuted(' formShell.answer(\"1,2,3\")');\n\t\t} else if (field.type === \"yesno\") {\n\t\t\tthis.renderer.renderMuted(\" formShell.y() / formShell.n()\");\n\t\t} else {\n\t\t\t// Text, Number, Email, URL, Date\n\t\t\tconst placeholder = this.getPlaceholder(field);\n\t\t\tthis.renderer.renderMuted(` formShell.answer(\"${placeholder}\")`);\n\t\t}\n\n\t\t// Show skip option if field is optional\n\t\tif (!field.required) {\n\t\t\tthis.renderer.renderMuted(\" formShell.skip() to skip\");\n\t\t}\n\n\t\tconsole.log(\"\");\n\t}\n\n\t/**\n\t * Get a placeholder for the field\n\t */\n\tprivate getPlaceholder(field: FieldInstance): string {\n\t\tswitch (field.type) {\n\t\t\tcase \"email\":\n\t\t\t\treturn \"email@example.com\";\n\t\t\tcase \"url\":\n\t\t\t\treturn \"https://...\";\n\t\t\tcase \"date\":\n\t\t\t\treturn \"DD/MM/YYYY\";\n\t\t\tcase \"number\": {\n\t\t\t\tif (field instanceof NumberField) {\n\t\t\t\t\treturn field.min !== null\n\t\t\t\t\t\t? `${field.min}-${field.max ?? \"...\"}`\n\t\t\t\t\t\t: \"number\";\n\t\t\t\t}\n\t\t\t\treturn \"number\";\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\treturn \"your answer\";\n\t\t}\n\t}\n\n\t/**\n\t * Show final summary\n\t */\n\tprivate showSummary(): void {\n\t\tthis.renderer.clear();\n\t\tconsole.log(\"\");\n\t\tthis.renderer.renderTitle(\"Summary\");\n\t\tconsole.log(\"\");\n\n\t\t// Only show visible (answered) steps\n\t\tlet displayIndex = 1;\n\t\tthis.steps.forEach((step) => {\n\t\t\t// Skip steps that don't meet their condition\n\t\t\tif (step.field.condition) {\n\t\t\t\tconst currentData = this.collectData();\n\t\t\t\tif (!step.field.condition(currentData)) {\n\t\t\t\t\treturn; // Skip this step in summary\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst field = step.field;\n\t\t\tconst value = field.getValue();\n\t\t\tconst formattedValue = field.format(value);\n\n\t\t\tthis.renderer.renderMuted(`${displayIndex}. ${field.label}`);\n\t\t\tthis.renderer.renderHighlight(` ${formattedValue}`);\n\t\t\tdisplayIndex++;\n\t\t});\n\n\t\tconsole.log(\"\");\n\t\tthis.renderer.renderSuccess(\"Completed!\");\n\t\tthis.renderer.renderMuted(\"formShell.submit() to send | formShell.back() to modify\");\n\t\tconsole.log(\"\");\n\t}\n\n\t/**\n\t * Cleanup when form is destroyed\n\t */\n\tdestroy(): void {\n\t\tthis.renderer.destroy();\n\t}\n}\n\n// Export for use as module\nexport default FormShell;\n"],"names":["Theme","text","bold","char","styleObj","entry","key","value","color","BaseField","config","validation","TextField","baseValidation","strValue","NumberField","numValue","EmailField","URLField","DateField","day","month","year","date","ChoiceField","validOptions","opt","index","option","actualValue","MultipleChoiceField","choice","indices","v","values","idx","num","RatingField","numValidation","YesNoField","normalized","FieldFactory","type","ANSI_ESC","TUIRenderer","width","content","style","lines","useDouble","topLeft","topRight","bottomLeft","bottomRight","horizontal","vertical","line","lineStr","ansiEscapePattern","plainText","padding","leftPad","rightPad","current","total","percentage","filledWidth","emptyWidth","filled","empty","title","format","subtitle","message","label","progress","options","highlightIndex","number","showCursor","cursor","displayValue","question","yesLabel","noLabel","yesText","noText","max","stars","i","data","displayKey","commands","command","description","spinner","FormShell","stepsConfig","stepConfig","field","firstVisibleIndex","stepIndex","step","currentData","fromIndex","nextIndex","prevIndex","response","result","error","visibleSteps","_","answeredVisible","s","avgTimePerStep","remainingSteps","estimatedMs","seconds","visibleStepNumber","progressBar","visibleCount","placeholder","displayIndex","formattedValue"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "formshell",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Elegant framework for creating interactive multi-step forms directly in the browser console",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./global": {
|
|
14
|
+
"types": "./dist/global.d.ts"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"sideEffects": false,
|
|
21
|
+
"scripts": {
|
|
22
|
+
"dev": "vite",
|
|
23
|
+
"types": "tsc -b",
|
|
24
|
+
"build": "tsc && vite build && cp src/formshell/global.d.ts dist/global.d.ts",
|
|
25
|
+
"preview": "vite preview",
|
|
26
|
+
"type-check": "tsc --noEmit"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"formshell",
|
|
30
|
+
"console",
|
|
31
|
+
"shell",
|
|
32
|
+
"tui",
|
|
33
|
+
"form",
|
|
34
|
+
"interactive",
|
|
35
|
+
"cli",
|
|
36
|
+
"browser",
|
|
37
|
+
"survey",
|
|
38
|
+
"questionnaire"
|
|
39
|
+
],
|
|
40
|
+
"author": "Kasbrut",
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/node": "^25.2.2",
|
|
44
|
+
"typescript": "^5.3.3",
|
|
45
|
+
"vite": "^5.0.12",
|
|
46
|
+
"vite-plugin-dts": "^3.7.2"
|
|
47
|
+
}
|
|
48
|
+
}
|