ux_kit_core 0.0.1 copy "ux_kit_core: ^0.0.1" to clipboard
ux_kit_core: ^0.0.1 copied to clipboard

Essential components powering UX Kit

ux_kit_core lets you manage UI behavior configuration in one place, separate from styling and decoration. For now, it focuses on inputs and forms, using predefined and flexible blocks of configs and controllers to help you handle input lifecycles, validation, and sync and async updates.

Getting started #

Prerequisites:

  • Flutter 3.0 or higher
  • Dart 3.8 or higher

Usage #

class MyForm extends StatefulWidget {
  const MyForm({super.key});

  @override
  State<MyForm> createState() => _MyFormState();
}

class _MyFormState extends State<MyForm> {

  late EmailInput email;
  late PasswordInput password;

  @override
  void initState() {
    super.initState();
    email = EmailInput.init(EmailConfig());
    email.addDefaultListeners();
    password = PasswordInput.init(PasswordConfig());
    password.addDefaultListeners();
  }

  @override
  void dispose() {
    email.dispose();
    password.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        MyTextField(input: email),
        MyTextField(input: password),
        ElevatedButton(
          onPressed: () {
            if (email.validate() && password.validate()) {
              print('Email: ${email.formatted}');
              print('Password: ${password.formatted}');
            }
          },
          child: const Text('Submit'),
        ),
      ],
    );
  }
}

class MyTextField extends StatefulWidget {
  const MyTextField({super.key, required this.input});

  final FieldInput input;

  @override
  State<MyTextField> createState() => _MyTextFieldState();
}

class _MyTextFieldState extends State<MyTextField> {
  bool obscureText = false;

  String? errorText;

  @override
  void initState() {
    super.initState();
    widget.input.validationResult.addListener(errorTextListener);
    if (widget.input case PasswordInput password) {
      password.obscure.addListener(obscurePasswordListener);
    }
  }

  @override
  void dispose() {
    widget.input.validationResult.removeListener(errorTextListener);
    if (widget.input case PasswordInput password) {
      password.obscure.removeListener(obscurePasswordListener);
    }
    super.dispose();
  }

  void obscurePasswordListener() {
    setState(() {
      obscureText = (widget.input as PasswordInput).obscure.value;
    });
  }

  void errorTextListener() {
    setState(() {
      final validationResult = widget.input.validationResult.value;
      if (validationResult case HasMessage(isValid: final isValid, message: final message) when !isValid && message is String) {
        errorText = message;
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return TextField(
      controller: widget.input.textEditing,
      focusNode: widget.input.focusNode,
      autocorrect: widget.input is! PasswordInput,
      obscureText: obscureText,
      keyboardType: widget.input.keyboardType,
      inputFormatters: widget.input.inputFormatters,
      autofillHints: widget.input.autofillHints,
      decoration: InputDecoration(
        labelText: widget.input.config.label,
        hintText: widget.input.config.hint,
        errorText: errorText,
      ),
    );
  }
}

extension on FieldInput {
  TextInputType get keyboardType {
    return switch (this) {
      PasswordInput() => TextInputType.visiblePassword,
      PhoneInput() => TextInputType.phone,
      TextInput() => TextInputType.text,
      NumberInput() => TextInputType.number,
      EmailInput() => TextInputType.emailAddress,
      DateInput() => TextInputType.datetime,
      AddressInput() => TextInputType.streetAddress,
    };
  }

  List<TextInputFormatter>? get inputFormatters {
    return switch (this) {
      PhoneInput() ||
      NumberInput() => [FilteringTextInputFormatter.digitsOnly],
      _ => null,
    };
  }

  List<String>? get autofillHints {
    return switch (this) {
      PasswordInput() => [AutofillHints.password],
      PhoneInput() => [
        AutofillHints.telephoneNumberNational,
        AutofillHints.telephoneNumber,
      ],
      EmailInput() => [AutofillHints.email],
      DateInput() => [AutofillHints.birthday],
      AddressInput() => [AutofillHints.fullStreetAddress],
      _ => null,
    };
  }
}

0
likes
120
points
29
downloads

Publisher

unverified uploader

Weekly Downloads

Essential components powering UX Kit

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

email_validator, flutter, phone_numbers_parser

More

Packages that depend on ux_kit_core