A component that renders a Bootstrap Button element using OverReact’s statically-typed React prop API.
Use props.skin
to choose from one of six predefined styles for the
Button
component, each serving its own semantic purpose.
import 'package:over_react/over_react.dart';
import '../../demo_components.dart';
ReactElement buttonExamplesDemo() =>
(Dom.div()..className = 'btn-toolbar')(
Button()('Primary'),
(Button()..skin = ButtonSkin.SECONDARY)('Secondary'),
(Button()..skin = ButtonSkin.SUCCESS)('Success'),
(Button()..skin = ButtonSkin.INFO)('Info'),
(Button()..skin = ButtonSkin.WARNING)('Warning'),
(Button()..skin = ButtonSkin.DANGER)('Danger'),
(Button()
..href = '#'
..skin = ButtonSkin.LINK
)('Link')
);
import 'package:over_react/over_react.dart';
import '../demo_components.dart';
part 'button.over_react.g.dart';
UiFactory<ButtonProps> Button = _$Button;
mixin ButtonProps on UiProps {
/// The skin / "context" for the [Button].
///
/// See: <https://getbootstrap.com/docs/4.4/components/buttons/#examples>.
///
/// Default: [ButtonSkin.PRIMARY]
ButtonSkin skin;
/// The size of the [Button].
///
/// See: <https://getbootstrap.com/docs/4.4/components/buttons/#sizes>.
///
/// Default: [ButtonSize.DEFAULT]
ButtonSize size;
/// Whether the [Button] should appear "active".
///
/// See: <https://getbootstrap.com/docs/4.4/components/buttons/#active-state>
///
/// Default: false
bool isActive;
/// Whether the [Button] is disabled.
///
/// See: <https://getbootstrap.com/docs/4.4/components/buttons/#disabled-state>
///
/// Default: false
@Accessor(key: 'disabled', keyNamespace: '')
bool isDisabled;
/// Whether the [Button] is a block level button -- that which spans the full
/// width of its parent.
///
/// Default: false
bool isBlock;
/// The HTML `href` attribute value for the [Button].
///
/// If set, the item will render via [Dom.a].
///
/// _Proxies [DomProps.href]_
@Accessor(keyNamespace: '')
String href;
/// The HTML `target` attribute value for the [Button].
///
/// If set, the item will render via [Dom.a].
///
/// _Proxies [DomProps.target]_
@Accessor(keyNamespace: '')
String target;
/// The HTML `type` attribute value for the [Button] when
/// rendered via [Dom.button].
///
/// This will only be applied if [href] is not set.
///
/// _Proxies [DomProps.type]_
///
/// Default: [ButtonType.BUTTON]
ButtonType type;
}
mixin ButtonState on UiState {}
class ButtonComponent<T extends ButtonProps, S extends ButtonState>
extends UiStatefulComponent2<T, S> {
@override
get defaultProps => (newProps()
..skin = ButtonSkin.PRIMARY
..size = ButtonSize.DEFAULT
..isActive = false
..isDisabled = false
..isBlock = false
..type = ButtonType.BUTTON
);
@override
render() {
return renderButton(props.children);
}
ReactElement renderButton(dynamic children) {
BuilderOnlyUiFactory<DomProps> factory = buttonDomNodeFactory;
return (factory()
..modifyProps(addUnconsumedDomProps)
..className = getButtonClasses().toClassName()
..href = props.href
..target = props.target
..type = type
..disabled = isAnchorLink ? null : props.isDisabled
..aria.disabled = isAnchorLink ? props.isDisabled : null
)(children);
}
ClassNameBuilder getButtonClasses() {
return forwardingClassNameBuilder()
..add('btn')
..add('btn-block', props.isBlock)
..add('active', isActive)
..add('disabled', props.isDisabled)
..add(props.skin.className)
..add(props.size.className);
}
BuilderOnlyUiFactory<DomProps> get buttonDomNodeFactory => isAnchorLink ? Dom.a : Dom.button;
bool get isAnchorLink => props.href != null;
bool get isActive => props.isActive;
String get type => isAnchorLink ? null : props.type.typeName;
}
class ButtonSkin extends ClassNameConstant {
const ButtonSkin._(String name, String className) : super(name, className);
/// [className] value: 'btn-primary'
static const ButtonSkin PRIMARY =
ButtonSkin._('PRIMARY', 'btn-primary');
/// [className] value: 'btn-secondary'
static const ButtonSkin SECONDARY =
ButtonSkin._('SECONDARY', 'btn-secondary');
/// [className] value: 'btn-danger'
static const ButtonSkin DANGER =
ButtonSkin._('DANGER', 'btn-danger');
/// [className] value: 'btn-success'
static const ButtonSkin SUCCESS =
ButtonSkin._('SUCCESS', 'btn-success');
/// [className] value: 'btn-warning'
static const ButtonSkin WARNING =
ButtonSkin._('WARNING', 'btn-warning');
/// [className] value: 'btn-info'
static const ButtonSkin INFO =
ButtonSkin._('INFO', 'btn-info');
/// [className] value: 'btn-link'
static const ButtonSkin LINK =
ButtonSkin._('LINK', 'btn-link');
/// [className] value: 'btn-outline-primary'
static const ButtonSkin PRIMARY_OUTLINE =
ButtonSkin._('PRIMARY_OUTLINE', 'btn-outline-primary');
/// [className] value: 'btn-outline-secondary'
static const ButtonSkin SECONDARY_OUTLINE =
ButtonSkin._('SECONDARY_OUTLINE', 'btn-outline-secondary');
/// [className] value: 'btn-outline-danger'
static const ButtonSkin DANGER_OUTLINE =
ButtonSkin._('DANGER_OUTLINE', 'btn-outline-danger');
/// [className] value: 'btn-outline-success'
static const ButtonSkin SUCCESS_OUTLINE =
ButtonSkin._('SUCCESS_OUTLINE', 'btn-outline-success');
/// [className] value: 'btn-outline-warning'
static const ButtonSkin WARNING_OUTLINE =
ButtonSkin._('WARNING_OUTLINE', 'btn-outline-warning');
/// [className] value: 'btn-outline-info'
static const ButtonSkin INFO_OUTLINE =
ButtonSkin._('INFO_OUTLINE', 'btn-outline-info');
}
class ButtonSize extends ClassNameConstant {
const ButtonSize._(String name, String className) : super(name, className);
/// [className] value: ''
static const ButtonSize DEFAULT =
ButtonSize._('DEFAULT', '');
/// [className] value: 'btn-lg'
static const ButtonSize LARGE =
ButtonSize._('LARGE', 'btn-lg');
/// [className] value: 'btn-sm'
static const ButtonSize SMALL =
ButtonSize._('SMALL', 'btn-sm');
}
By default, the Button
component renders a <button>
element.
However, if props.href
is set, an <a>
will be rendered instead.
Optionally, set props.type
to ButtonType.SUBMIT
or ButtonType.RESET
to
render a submit / reset form button, respectively.
import 'package:over_react/over_react.dart';
import '../../demo_components.dart';
ReactElement buttonTypesDemo() =>
(Dom.div()..className = 'btn-toolbar')(
Button()('Button'),
(Button()..href = '#')('Link'),
(Button()..type = ButtonType.SUBMIT)('Submit'),
(Button()..type = ButtonType.RESET)('Reset')
);
Set props.skin
to one of the "outline" options when you are in need of a
Button
, but not the ones that come with a hefty background color.
import 'package:over_react/over_react.dart';
import '../../demo_components.dart';
ReactElement buttonOutlineDemo() =>
(Dom.div()..className = 'btn-toolbar')(
(Button()..skin = ButtonSkin.PRIMARY_OUTLINE)('Primary'),
(Button()..skin = ButtonSkin.SECONDARY_OUTLINE)('Secondary'),
(Button()..skin = ButtonSkin.SUCCESS_OUTLINE)('Success'),
(Button()..skin = ButtonSkin.INFO_OUTLINE)('Info'),
(Button()..skin = ButtonSkin.WARNING_OUTLINE)('Warning'),
(Button()..skin = ButtonSkin.DANGER_OUTLINE)('Danger')
);
Set props.size
if you fancy larger or smaller Button
s.
import 'package:over_react/over_react.dart';
import '../../demo_components.dart';
ReactElement buttonSizesDemo() =>
(Dom.div()..className = 'btn-toolbar')(
(Button()..size = ButtonSize.SMALL)('Small'),
Button()('Default'),
(Button()..size = ButtonSize.LARGE)('Large')
);
Set props.isBlock
to render Button
s that span the
full width of a parent element.
import 'package:over_react/over_react.dart';
import '../../demo_components.dart';
ReactElement buttonBlockDemo() => Dom.div()(
(Button()
..isBlock = true
)('Block level button'),
(Button()
..isBlock = true
..skin = ButtonSkin.SECONDARY
)('Block level button')
);
Set props.isActive
to make a Button
appear active.
import 'package:over_react/over_react.dart';
import '../../demo_components.dart';
ReactElement buttonActiveDemo() =>
(Dom.div()..className = 'btn-toolbar')(
(Button()
..isActive = true
)('Primary button'),
(Button()
..isActive = true
..skin = ButtonSkin.SECONDARY
)('Button')
);
Set props.isDisabled
to disable a Button
.
import 'package:over_react/over_react.dart';
import '../../demo_components.dart';
ReactElement buttonDisabledDemo() =>
(Dom.div()..className = 'btn-toolbar')(
(Button()
..isDisabled = true
)('Primary button'),
(Button()
..href = '#'
..isDisabled = true
..skin = ButtonSkin.SECONDARY
)('Link')
);