Skip to content

Commit

Permalink
feat: [DX-1801] Add TextArea component (#632)
Browse files Browse the repository at this point in the history
  • Loading branch information
witwash authored Jul 26, 2024
1 parent 8ebbcfa commit 7b46b55
Show file tree
Hide file tree
Showing 5 changed files with 252 additions and 1 deletion.
1 change: 1 addition & 0 deletions optimus/lib/optimus.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export 'src/form/password_form_field.dart';
export 'src/form/select_form_field.dart';
export 'src/form/select_input_form_field.dart';
export 'src/form/stepper_form_field.dart';
export 'src/form/text_area.dart';
export 'src/icon.dart';
export 'src/icon_list.dart';
export 'src/link/inline_link.dart';
Expand Down
2 changes: 1 addition & 1 deletion optimus/lib/src/form/input_field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ class _OptimusInputFieldState extends State<OptimusInputField>
hasBorders: widget.hasBorders,
isRequired: widget.isRequired,
inline: widget.inline,
multiline: (widget.minLines ?? 1) > 1,
multiline: widget.minLines != null,
inputCounter: widget.inline ? null : counter,
statusBarState: widget.statusBarState,
prefix: _shouldShowPrefix
Expand Down
212 changes: 212 additions & 0 deletions optimus/lib/src/form/text_area.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:optimus/optimus.dart';

class OptimusTextArea extends StatelessWidget {
const OptimusTextArea({
super.key,
this.onChanged,
this.placeholder,
this.placeholderStyle,
this.keyboardType = TextInputType.multiline,
this.isEnabled = true,
this.textInputAction,
this.onSubmitted,
this.focusNode,
this.label,
this.caption,
this.captionIcon,
this.helperMessage,
this.rows = 2,
this.maxCharacters,
this.controller,
this.error,
this.errorVariant = OptimusInputErrorVariant.bottomHint,
this.enableInteractiveSelection = true,
this.autofocus = false,
this.isFocused,
this.autocorrect = true,
this.isRequired = false,
this.inputKey,
this.fieldBoxKey,
this.readOnly = false,
this.onTap,
this.textAlign = TextAlign.start,
this.textCapitalization = TextCapitalization.none,
this.size = OptimusWidgetSize.large,
this.showCursor,
this.inputFormatters,
this.keyboardAppearance,
this.enableIMEPersonalizedLearning = true,
this.enableSuggestions = true,
this.inline = false,
this.autoSize = true,
this.autoCollapse = true,
});

/// {@macro flutter.widgets.editableText.onChanged}
final ValueChanged<String>? onChanged;

/// The placeholder text that will be displayed when the field is empty.
final String? placeholder;

/// The style of the placeholder text.
final TextStyle? placeholderStyle;

/// {@macro flutter.widgets.editableText.keyboardType}
/// Defaults to [TextInputType.multiline].
final TextInputType? keyboardType;

/// Controls whether the field is enabled.
final bool isEnabled;

/// The action the keyboard should take when the user presses the action key.
final TextInputAction? textInputAction;

/// The callback to call when the user submits the field.
final ValueChanged<String>? onSubmitted;

/// {@macro flutter.widgets.Focus.focusNode}
final FocusNode? focusNode;

/// The label that will be displayed above the field.
final String? label;

/// The caption that will be displayed under the field.
final Widget? caption;

/// The icon that will be displayed next to the caption.
final IconData? captionIcon;

/// The helper message that will be displayed under the field.
final Widget? helperMessage;

/// The number of lines that the field should have. Defaults to 2.
final int rows;

/// The maximum characters for the field. Current character count will be
/// displayed under the field.
final int? maxCharacters;

/// The optional controller for the input field.
final TextEditingController? controller;

/// The error message that will be displayed under the field.
final String? error;

/// The way error should be displayed. Will be set to the
/// [OptimusInputErrorVariant.bottomHint] if not provided.
final OptimusInputErrorVariant errorVariant;

/// Controls whether the text field should allow the user to interactively
/// select the text.
final bool enableInteractiveSelection;

/// {@macro flutter.widgets.editableText.autofocus}
final bool autofocus;

/// Controls whether the field is focused. Overrides [focusNode] focus.
final bool? isFocused;

/// {@macro flutter.widgets.editableText.autocorrect}
final bool autocorrect;

/// Defines whether the field is required.
final bool isRequired;

/// The key for the input field.
final Key? inputKey;

/// The [Key] for the field box.
final Key? fieldBoxKey;

/// {@macro flutter.widgets.editableText.readOnly}
final bool readOnly;

/// The callback that will be called when the field is tapped.
final VoidCallback? onTap;

/// The horizontal alignment of the text.
final TextAlign textAlign;

/// {@macro flutter.widgets.editableText.textCapitalization}
final TextCapitalization textCapitalization;

/// The size of the input field. Defaults to [OptimusWidgetSize.large].
final OptimusWidgetSize size;

/// {@macro flutter.widgets.editableText.showCursor}
final bool? showCursor;

/// {@macro flutter.widgets.editableText.inputFormatters}
final List<TextInputFormatter>? inputFormatters;

/// {@template optimus.input.keyboardAppearance}
/// The appearance of the keyboard.
///
/// This setting is only honored on iOS devices.
///
/// If null, defaults to the brightness provided by [OptimusTheme].
/// {@endtemplate}
final Brightness? keyboardAppearance;

/// {@macro flutter.services.TextInputConfiguration.enableIMEPersonalizedLearning}
final bool enableIMEPersonalizedLearning;

/// {@macro flutter.services.TextInputConfiguration.enableSuggestions}
final bool enableSuggestions;

/// Controls whether the components should be inside the input field or
/// outside, wrapping it. The inline variant is more dense and is smaller in
/// the vertical direction.
final bool inline;

/// Controls whether the text area should automatically adjust its height to
/// fit the content. Defaults to true.
final bool autoSize;

/// Controls whether the input should collapse to one line height if not
/// focused.
final bool autoCollapse;

@override
Widget build(BuildContext context) => OptimusInputField(
onChanged: onChanged,
placeholder: placeholder,
placeholderStyle: placeholderStyle,
keyboardType: keyboardType,
isEnabled: isEnabled,
textInputAction: textInputAction,
onSubmitted: onSubmitted,
focusNode: focusNode,
label: label,
caption: caption,
captionIcon: captionIcon,
helperMessage: helperMessage,
maxLines: rows,
maxCharacters: maxCharacters,
minLines: autoSize ? 1 : rows,
controller: controller,
error: error,
errorVariant: errorVariant,
enableInteractiveSelection: enableInteractiveSelection,
autofocus: autofocus,
isFocused: isFocused,
autocorrect: autocorrect,
isRequired: isRequired,
inputKey: inputKey,
fieldBoxKey: fieldBoxKey,
readOnly: readOnly,
onTap: onTap,
textAlign: textAlign,
textCapitalization: textCapitalization,
size: size,
showCursor: showCursor,
inputFormatters: inputFormatters,
keyboardAppearance: keyboardAppearance,
enableIMEPersonalizedLearning: enableIMEPersonalizedLearning,
enableSuggestions: enableSuggestions,
inline: inline,
autoCollapse: autoCollapse,
);
}
2 changes: 2 additions & 0 deletions storybook/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import 'package:storybook/stories/feedback/system_wide_banner.dart';
import 'package:storybook/stories/feedback/tags.dart';
import 'package:storybook/stories/form/form_story.dart';
import 'package:storybook/stories/form/password_form.dart';
import 'package:storybook/stories/form/text_area.dart';
import 'package:storybook/stories/icon/icon.dart';
import 'package:storybook/stories/icon/icon_list.dart';
import 'package:storybook/stories/icon/icons.dart';
Expand Down Expand Up @@ -169,6 +170,7 @@ class _MyAppState extends State<MyApp> {
systemWideBannerStory,
passwordStory,
toggleButtonStory,
textAreaStory,
],
),
},
Expand Down
36 changes: 36 additions & 0 deletions storybook/lib/stories/form/text_area.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import 'package:flutter/widgets.dart';
import 'package:optimus/optimus.dart';
import 'package:storybook_flutter/storybook_flutter.dart';

final textAreaStory = Story(
name: 'Forms/Text Area',
builder: (context) {
final k = context.knobs;

final label = k.text(label: 'Label', initial: 'Label');
final placeholder = k.text(label: 'Placeholder', initial: 'Placeholder');
final error = k.text(label: 'Error', initial: '');
final isEnabled = k.boolean(label: 'Enabled', initial: true);
final isRequired = k.boolean(label: 'Required', initial: false);
final rows = k.sliderInt(label: 'Rows', initial: 1, min: 1, max: 10);
final autoCollapse = k.boolean(label: 'Auto collapse', initial: true);
final autoSize = k.boolean(label: 'Auto size', initial: true);
final maxCharacters =
k.sliderInt(label: 'Max characters', initial: 100, min: 0, max: 100);

return Padding(
padding: EdgeInsets.all(context.tokens.spacing100),
child: OptimusTextArea(
label: label,
placeholder: placeholder,
isEnabled: isEnabled,
isRequired: isRequired,
rows: rows,
autoCollapse: autoCollapse,
autoSize: autoSize,
error: error.isNotEmpty ? error : null,
maxCharacters: maxCharacters == 0 ? null : maxCharacters,
),
);
},
);

0 comments on commit 7b46b55

Please sign in to comment.