import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; import { AngularSvgIconModule, SvgIconRegistryService } from 'angular-svg-icon'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { CommonModule } from '@angular/common'; import { HttpClientModule } from '@angular/common/http'; import { FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators, } from '@angular/forms'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { NgxMaskModule } from 'ngx-mask'; import moment from 'moment'; // component import { InputTestComponent } from './input-test.component'; // validators import { emailWithTLDValidator } from './custom-validators/email-custom.validator'; import { urlWithTLDValidator } from './custom-validators/url-custom.validator'; import { CaModalButtonComponent } from '../ca-modal-button/ca-modal-button.component'; const meta: Meta = { title: 'Example/InputTest', component: InputTestComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ imports: [ // Module CommonModule, FormsModule, ReactiveFormsModule, AngularSvgIconModule.forRoot(), NgxMaskModule.forRoot(), HttpClientModule, NgbModule, // components CaModalButtonComponent, ], providers: [SvgIconRegistryService], schemas: [CUSTOM_ELEMENTS_SCHEMA], }), ], argTypes: { inputConfig: { control: { type: 'object' }, }, }, args: { inputConfig: { name: 'Business Names', type: 'text', label: 'Account Name', }, }, }; export default meta; type Story = StoryObj; const yearRange = parseInt(moment().add(1, 'year').format('YY').substring(1)); const yPattern = new RegExp(`^(19[0-9]\\d|20[0-2][0-${yearRange}])$`); const formGroup = new FormGroup({ testInput: new FormControl('', [Validators.required]), autoFocusInput: new FormControl(''), password: new FormControl(undefined, [ Validators.required, Validators.minLength(8), ]), thousandSeparator: new FormControl(null, [ Validators.minLength(4), Validators.maxLength(6), ]), price: new FormControl(undefined, [Validators.required]), priceWithLimit: new FormControl(undefined, [Validators.required]), priceWithDelay: new FormControl('', [Validators.required]), email: new FormControl(null, [ Validators.required, emailWithTLDValidator(), ]), phone: new FormControl( '', // Start with an empty string (instead of null) [ Validators.pattern(/^\(\d{3}\)\s\d{3}-\d{4}$/), // ✅ Regex for (123) 456-7890 ] ), usdot: new FormControl('123456', [ Validators.required, Validators.minLength(6), Validators.maxLength(8), ]), webUrl: new FormControl('', [ Validators.minLength(6), Validators.maxLength(255), urlWithTLDValidator(), ]), year: new FormControl(null, [ Validators.required, Validators.minLength(4), Validators.maxLength(4), Validators.pattern(yPattern), ]), controls: new FormControl('', [Validators.required]), controlsThousandSeparator: new FormControl('', [Validators.required]), controlsReset: new FormControl('', [Validators.required]), ssn: new FormControl(null, [ Validators.required, Validators.pattern(/^\d{3}\-\d{2}\-\d{4}$/), ]), maxminlength: new FormControl(null, [ Validators.minLength(9), Validators.maxLength(9), ]), routing: new FormControl(undefined, [ Validators.minLength(9), Validators.maxLength(9), ]), }); const formTemplate: string = `
`; export const Input: Story = { render: (args) => ({ props: { ...args, config: args.inputConfig, formControlName: 'testInput', form: formGroup, }, template: formTemplate, }), }; const autoFocusTemplate: string = `
`; export const AutoFocusInput: Story = { render: (args) => ({ props: { ...args, config: { ...args.inputConfig, autoFocus: true, }, formControlName: 'autoFocusInput', form: formGroup, }, template: autoFocusTemplate, }), }; const thousandTemplate: string = `
`; export const ThousandSeparatorWithPlaceholder: Story = { render: (args) => ({ props: { ...args, config: { name: 'Empty Weight', type: 'text', label: 'Empty Weight', maxLength: 5, placeholderText: 'ibs', thousandSeparator: true, }, formControlName: 'thousandSeparator', form: formGroup, }, template: thousandTemplate, }), }; const priceTemplate: string = `
`; export const Price: Story = { render: (args) => ({ props: { ...args, config: { ...args.inputConfig, name: 'price-separator', type: 'text', label: 'Base Rate', labelInInput: true, isRequired: true, priceSeparator: true, priceSeparatorLimitation: 16, placeholderIconRightSide: 'dollar', placeholderIconColor: 'blue', inputCursorOnRightSide: true, hideErrorMessage: true, errorInsideInput: true, hideRequiredCheck: true, maxLength: 7, }, formControlName: 'price', form: formGroup, }, template: priceTemplate, }), }; const priceWithLimitTemplate: string = `
{{form.get('priceWithLimit').value}}
`; export const PriceWithLimit: Story = { render: (args) => ({ props: { ...args, config: { ...args.inputConfig, name: 'price-separator', type: 'text', label: 'Base Rate', labelInInput: true, isRequired: true, priceParseFormat: true, priceSeparator: true, priceSeparatorLimitation: 16, placeholderIconRightSide: 'dollar', placeholderIconColor: 'blue', inputCursorOnRightSide: true, hideErrorMessage: true, errorInsideInput: true, hideRequiredCheck: true, max: 11111.11, maxLength: 5, }, formControlName: 'priceWithLimit', form: formGroup, }, template: priceWithLimitTemplate, }), }; const priceWithDelayTemplate: string = `
`; export const PriceWithDelay: Story = { render: (args) => { setTimeout(() => { formGroup.get('priceWithDelay')?.setValue('4444.33'); // ✅ Simulates user input }, 2000); return { props: { ...args, config: { ...args.inputConfig, name: 'price-separator', type: 'text', label: 'Base Rate', labelInInput: true, isRequired: true, priceParseFormat: true, priceSeparator: true, priceSeparatorLimitation: 16, placeholderIconRightSide: 'dollar', placeholderIconColor: 'blue', inputCursorOnRightSide: true, hideErrorMessage: true, errorInsideInput: true, hideRequiredCheck: true, maxLength: 5, }, formControlName: 'priceWithDelay', form: formGroup, }, template: priceWithDelayTemplate, }; }, }; const passwordTemplate: string = `
`; export const Password: Story = { render: (args) => ({ props: { ...args, config: { ...args.inputConfig, name: 'Password', type: 'password', label: 'Password', placeholderIcon: 'password', isRequired: true, autocomplete: 'off', minLength: 8, maxLength: 20, }, formControlName: 'password', form: formGroup, }, template: passwordTemplate, }), }; const emailTemplate: string = `
`; export const Email: Story = { render: (args) => ({ props: { config: { name: 'Email', type: 'email', label: 'Email', placeholderIcon: 'email', isRequired: true, autocomplete: 'off', minLength: 5, maxLength: 20, textTransform: 'lowercase', }, formControlName: 'email', form: formGroup, }, template: emailTemplate, }), }; const phoneTemplate: string = `
`; export const Phone: Story = { render: (args) => { setTimeout(() => { formGroup.get('phone')?.setValue('0601587876'); // ✅ Simulates user input }, 2000); return { props: { config: { name: 'Phone', type: 'text', label: 'Phone', mask: '(000) 000-0000', placeholderIcon: 'phone', }, formControlName: 'phone', form: formGroup, }, template: phoneTemplate, }; }, }; const usdotTemplate: string = `
`; export const UsDot: Story = { name: 'Input With Delayed Value', render: (args) => { setTimeout(() => { // formGroup.get('usdot')?.setValue('123456'); // ✅ Simulates user input }, 2000); return { props: { config: { name: 'USDOT', type: 'text', label: 'USDOT', isRequired: true, textTransform: 'capitalize', minLength: 6, maxLength: 8, minValue: 1, }, formControlName: 'usdot', form: formGroup, }, template: usdotTemplate, }; }, }; const hiperLinkTemplate: string = `
`; export const HiperLink: Story = { render: (args) => ({ props: { config: { name: 'Url', type: 'text', label: 'Hyperlink', minLength: 4, maxLength: 255, placeholderIcon: 'hyperlink', }, formControlName: 'webUrl', form: formGroup, }, template: hiperLinkTemplate, }), }; const yearTemplate: string = `
`; export const YearInput: Story = { render: (args) => ({ props: { ...args, config: { name: 'Year', type: 'text', label: 'Year', isRequired: true, }, formControlName: 'year', form: formGroup, }, template: yearTemplate, }), }; const controlsTemplate: string = `
`; export const ControlsInput: Story = { render: (args) => ({ props: { ...args, config: { name: 'months', type: 'text', placeholderText: 'months', label: 'FHWA Exp.', isRequired: true, hideClear: true, removeLeadingZero: true, minValue: 1, maxValue: 12, commands: { active: true, type: 'months', firstCommand: { name: 'minus', svg: 'assets/ca-components/svg/input/ic_pm_decrement.svg', }, secondCommand: { name: 'plus', svg: 'assets/ca-components/svg/input/ic_pm_increment.svg', }, }, }, formControlName: 'controls', form: formGroup, }, template: controlsTemplate, }), }; const controlsThousandSeparatorTemplate: string = `
`; export const ControlsThousandSeparatorInput: Story = { render: (args) => ({ props: { ...args, config: { name: 'months', type: 'text', placeholderText: 'payments', label: 'FHWA Exp.', isRequired: true, minLength: 1, maxLength: 5, hideClear: true, thousandSeparator: true, commands: { active: true, type: 'months', firstCommand: { name: 'minus', svg: 'assets/ca-components/svg/input/ic_pm_decrement.svg', }, secondCommand: { name: 'plus', svg: 'assets/ca-components/svg/input/ic_pm_increment.svg', }, }, }, formControlName: 'controls', form: formGroup, }, template: controlsThousandSeparatorTemplate, }), }; const controlsResetTemplate: string = `
`; export const ControlsResetInput: Story = { render: (args) => ({ props: { ...args, config: { name: 'MONTHS', type: 'text', commands: { active: true, type: 'pm-increment-decrement', blueCommands: true, firstCommand: { name: 'decrement', svg: 'assets/ca-components/svg/input/ic_pm_decrement.svg', }, secondCommand: { name: 'increment', svg: 'assets/ca-components/svg/input/ic_pm_increment.svg', }, thirdCommand: { name: 'reset', svg: 'assets/ca-components/svg/input/ic_input_reset.svg', }, }, thousandSeparator: true, hideErrorMessage: true, blueInput: true, hideRequiredCheck: true, defaultValue: 15000, maxValue: 500000, }, formControlName: 'controlsReset', form: formGroup, }, template: controlsResetTemplate, }), }; const ssnTemplate: string = `
`; export const SSNInput: Story = { render: (args) => ({ props: { ...args, config: { name: 'SSN', type: 'text', label: 'SSN', isRequired: true, mask: '000-00-0000', maxLength: 11, }, formControlName: 'ssn', form: formGroup, }, template: ssnTemplate, }), }; const formSubmitGroup = new FormGroup({ submitValue: new FormControl('', [Validators.required]), submitValueSecond: new FormControl('', [Validators.required]), }); const formSubmitTemplate: string = `
`; export const SummitButton: Story = { render: (args) => { setTimeout(() => { formSubmitGroup.patchValue({ submitValue: 'Test1234', submitValueSecond: 'Testicc', }); // ✅ Simulates user input }, 2000); return { props: { ...args, config: { name: 'First Names', type: 'text', label: 'First Name', }, configSecond: { name: 'Last Names', type: 'text', label: 'Last Name', }, form: formSubmitGroup, }, template: formSubmitTemplate, }; }, }; const formSetErrorGroup = new FormGroup({ fieldWithError: new FormControl('', [Validators.required]), }); const formInputWithErrorTemplate: string = `
`; export const SetInputErrorButton: Story = { name: 'Set Input Error With Delay', render: (args) => { return { props: { ...args, config: { name: 'Password', type: 'password', label: 'Password', placeholderIcon: 'password', isRequired: true, autocomplete: 'off', minLength: 8, maxLength: 64, }, form: formSetErrorGroup, setCustomError: () => { console.log('SET ERROR'); setTimeout(() => { formSetErrorGroup.get('fieldWithError')?.setErrors({ wrongPassword: true, }); }, 1200); }, }, template: formInputWithErrorTemplate, }; }, }; const maxMinValueTemplate: string = `
`; export const maxMinValueTemplatePlaceholder: Story = { render: (args) => ({ props: { ...args, config: { name: 'routing-bank', type: 'text', label: 'Routing #', isDisabled: false, isRequired: true, minLength: 9, maxLength: 9, }, form: formGroup, }, template: maxMinValueTemplate, }), }; const routingTemplate: string = `
`; export const routingTemplatePlaceholder: Story = { render: (args) => ({ props: { ...args, config: { name: 'routing-bank', type: 'text', label: 'Routing', minLength: 9, maxLength: 9, }, form: formGroup, }, template: routingTemplate, }), };