A component that renders a Bootstrap List Group element using OverReact’s statically-typed React prop API.
The most basic ListGroup
component is simply list ListGroupItem
components.
The components encapsulate the complexity of the underlying HTML, ensuring that all the default CSS classes and other HTML attributes are present, leaving you with minimal markup.
part of over_react.web.demos;
ReactElement listGroupBasicDemo() =>
ListGroup()(
ListGroupItem()('Dapibus ac facilisis in'),
ListGroupItem()('Cras sit amet nibh libero'),
ListGroupItem()('Porta ac consectetur ac'),
ListGroupItem()('Vestibulum at eros')
);
part of over_react.web.demo_components;
/// Bootstrap's `ListGroup` component is flexible and powerful for
/// displaying lists of [ListGroupItem] components.
///
/// See: <http://v4-alpha.getbootstrap.com/components/list-group/>
@Factory()
UiFactory<ListGroupProps> ListGroup;
@Props()
class ListGroupProps extends UiProps {
/// The HTML element type for the [ListGroup], specifying its
/// DOM representation when rendered.
///
/// Default: [ListGroupElementType.DIV]
ListGroupElementType elementType;
}
@Component()
class ListGroupComponent extends UiComponent<ListGroupProps> {
@override
Map getDefaultProps() => (newProps()
..elementType = ListGroupElementType.DIV
);
@override
render() {
var classes = forwardingClassNameBuilder()
..add('list-group');
return (props.elementType.componentBuilderFactory()
..addProps(copyUnconsumedDomProps())
..className = classes.toClassName()
)(props.children);
}
}
/// Options for the [Element] that will be used when
/// rendering a [ListGroup] component.
class ListGroupElementType {
final BuilderOnlyUiFactory<DomProps> componentBuilderFactory;
ListGroupElementType._internal(this.componentBuilderFactory);
/// A [Dom.ul] (HTML `<ul>` element)
static final ListGroupElementType UL = new ListGroupElementType._internal(Dom.ul);
/// A [Dom.div] (HTML `<div>` element)
static final ListGroupElementType DIV = new ListGroupElementType._internal(Dom.div);
}
part of over_react.web.demo_components;
/// Nest one or more `ListGroupItem` components within a [ListGroup]
/// to render individual items within a list.
///
/// See: <http://v4-alpha.getbootstrap.com/components/list-group/>
@Factory()
UiFactory<ListGroupItemProps> ListGroupItem;
@Props()
class ListGroupItemProps extends UiProps {
/// The HTML element type for the [ListGroupItem], specifying its DOM
/// representation when rendered.
///
/// Will only be used if [href] and [onClick] are both `null`.
///
/// Default: [ListGroupItemElementType.SPAN]
ListGroupItemElementType elementType;
/// Optional header text to display within the [ListGroupItem] above
/// the value of [children].
///
/// See: <http://v4-alpha.getbootstrap.com/components/list-group/#custom-content>.
dynamic header;
/// The size of the [header] text you desire.
///
/// Default: [ListGroupItemHeaderElementSize.H5]
ListGroupItemHeaderElementSize headerSize;
/// Additional props to be added to the [header] element _(if specified)_.
Map headerProps;
/// The skin / "context" for the [ListGroupItem].
///
/// See: <http://v4-alpha.getbootstrap.com/components/list-group/#contextual-classes>.
///
/// Default: [ListGroupItemSkin.DEFAULT]
ListGroupItemSkin skin;
/// Whether the [ListGroupItem] should appear "active".
///
/// See: <http://v4-alpha.getbootstrap.com/components/list-group/#anchors-and-buttons>
///
/// Default: false
bool isActive;
/// Whether the [ListGroupItem] is disabled.
///
/// See: <http://v4-alpha.getbootstrap.com/components/list-group/#disabled-items>
///
/// Default: false
@Accessor(key: 'disabled', keyNamespace: '')
bool isDisabled;
/// The HTML `href` attribute value for the [ListGroupItem].
///
/// If set, the item will render via [Dom.a].
///
/// _Proxies [DomProps.href]_
@Accessor(keyNamespace: '')
String href;
/// The HTML `target` attribute value for the [ListGroupItem].
///
/// If set, the item will render via [Dom.a].
///
/// _Proxies [DomProps.target]_
@Accessor(keyNamespace: '')
String target;
/// The HTML `type` attribute value for the [ListGroupItem] when
/// rendered via [Dom.button].
///
/// This will only be applied if [onClick] is also set.
///
/// _Proxies [DomProps.type]_
///
/// Default: [ButtonType.BUTTON]
ButtonType type;
}
@Component()
class ListGroupItemComponent extends UiComponent<ListGroupItemProps> {
@override
Map getDefaultProps() => (newProps()
..elementType = ListGroupItemElementType.SPAN
..skin = ListGroupItemSkin.DEFAULT
..isActive = false
..isDisabled = false
..type = ButtonType.BUTTON
..headerSize = ListGroupItemHeaderElementSize.H5
);
@override
render() {
var children = props.children;
if (props.header != null) {
children = [
renderItemHeader(),
(Dom.p()
..className = 'list-group-item-text'
..key = 'item-text'
)(props.children)
];
}
BuilderOnlyUiFactory<DomProps> factory = _getItemDomNodeFactory();
return (factory()
..addProps(copyUnconsumedDomProps())
..className = _getItemClasses().toClassName()
..href = props.href
..target = props.target
..type = _isActionItem ? props.type.typeName : null
..disabled = _useDisabledAttr ? props.isDisabled : null
..addProps(ariaProps()
..disabled = !_useDisabledAttr ? props.isDisabled : null
)
)(children);
}
ReactElement renderItemHeader() {
if (props.header == null) return null;
var headerClasses = new ClassNameBuilder.fromProps(props.headerProps)
..add('list-group-item-heading');
return (props.headerSize.componentBuilderFactory()
..addProps(props.headerProps)
..className = headerClasses.toClassName()
..key = 'item-header'
)(props.header);
}
BuilderOnlyUiFactory<DomProps> _getItemDomNodeFactory() {
var factory;
if (props.href != null) {
factory = Dom.a;
} else if (props.onClick != null) {
factory = Dom.button;
} else {
factory = props.elementType.componentBuilderFactory;
}
return factory;
}
ClassNameBuilder _getItemClasses() {
return forwardingClassNameBuilder()
..add('list-group-item')
..add('list-group-item-action', _isActionItem)
..add('active', props.isActive)
..add('disabled', props.isDisabled)
..add(props.skin.className);
}
bool get _useDisabledAttr => _getItemDomNodeFactory() == Dom.button;
bool get _isActionItem => (props.href ?? props.onClick) != null;
}
/// Contextual skin options for a [ListGroupItem] component.
class ListGroupItemSkin extends ClassNameConstant {
const ListGroupItemSkin._(String name, String className) : super(name, className);
/// [className] value: null
static const ListGroupItemSkin DEFAULT =
const ListGroupItemSkin._('DEFAULT', null);
/// [className] value: 'list-group-item-danger'
static const ListGroupItemSkin DANGER =
const ListGroupItemSkin._('DANGER', 'list-group-item-danger');
/// [className] value: 'list-group-item-success'
static const ListGroupItemSkin SUCCESS =
const ListGroupItemSkin._('SUCCESS', 'list-group-item-success');
/// [className] value: 'list-group-item-warning'
static const ListGroupItemSkin WARNING =
const ListGroupItemSkin._('WARNING', 'list-group-item-warning');
/// [className] value: 'list-group-item-info'
static const ListGroupItemSkin INFO =
const ListGroupItemSkin._('INFO', 'list-group-item-info');
}
/// Options for the [Element] that will be used when rendering a [ListGroupItem] component.
class ListGroupItemElementType {
final BuilderOnlyUiFactory<DomProps> componentBuilderFactory;
ListGroupItemElementType._internal(this.componentBuilderFactory);
/// A [Dom.li] (HTML `<li>` element)
///
/// Will only be used if [ListGroupItemProps.href] and
/// [ListGroupItemProps.onClick] are both `null`.
///
/// Only use this when the parent [ListGroup] has
/// [ListGroupProps.elementType] set to [ListGroupElementType.UL].
static final ListGroupItemElementType LI =
new ListGroupItemElementType._internal(Dom.li);
/// A [Dom.span] (HTML `<span>` element)
///
/// Will only be used if [ListGroupItemProps.href] and
/// [ListGroupItemProps.onClick] are both `null`.
static final ListGroupItemElementType SPAN =
new ListGroupItemElementType._internal(Dom.span);
}
/// Options for the [Element] that will be used when rendering a [ListGroupItemProps.header].
class ListGroupItemHeaderElementSize {
final BuilderOnlyUiFactory<DomProps> componentBuilderFactory;
ListGroupItemHeaderElementSize._internal(this.componentBuilderFactory);
/// A [Dom.h1] (HTML `<h1>` element)
static final ListGroupItemHeaderElementSize H1 =
new ListGroupItemHeaderElementSize._internal(Dom.h1);
/// A [Dom.h2] (HTML `<h2>` element)
static final ListGroupItemHeaderElementSize H2 =
new ListGroupItemHeaderElementSize._internal(Dom.h2);
/// A [Dom.h3] (HTML `<h3>` element)
static final ListGroupItemHeaderElementSize H3 =
new ListGroupItemHeaderElementSize._internal(Dom.h3);
/// A [Dom.h4] (HTML `<h4>` element)
static final ListGroupItemHeaderElementSize H4 =
new ListGroupItemHeaderElementSize._internal(Dom.h4);
/// A [Dom.h5] (HTML `<h5>` element)
static final ListGroupItemHeaderElementSize H5 =
new ListGroupItemHeaderElementSize._internal(Dom.h5);
/// A [Dom.h6] (HTML `<h6>` element)
static final ListGroupItemHeaderElementSize H6 =
new ListGroupItemHeaderElementSize._internal(Dom.h6);
}
Nest a Tag
component within any `ListGroupItem` to show unread counts, activity,
etc.
part of over_react.web.demos;
ReactElement listGroupTagsDemo() =>
ListGroup()(
ListGroupItem()(
(Tag()
..className = 'float-xs-right'
..isPill = true
)(14),
'Cras justo odio'
),
ListGroupItem()(
(Tag()
..className = 'float-xs-right'
..isPill = true
)(2),
'Dapibus ac facilisis in'
),
ListGroupItem()(
(Tag()
..className = 'float-xs-right'
..isPill = true
)(1),
'Morbi leo risus'
)
);
Set props.onClick
to render an HTML <button>
element, or props.href
to render an HTML <a>
element with hover, disabled, and active states.
Set props.isDisabled
to disable an item, and props.isActive
to make an item appear active.
part of over_react.web.demos;
ReactElement listGroupAnchorsAndButtonsDemo() =>
ListGroup()(
(ListGroupItem()
..isActive = true
..href = '#'
)('Cras justo odio'),
(ListGroupItem()
..onClick = (_) {}
)('Dapibus ac facilisis in'),
(ListGroupItem()
..onClick = (_) {}
)('Morbi leo risus'),
(ListGroupItem()
..onClick = (_) {}
)('Porta ac consectetur ac'),
(ListGroupItem()
..isDisabled = true
..onClick = (_) {}
)('Vestibulum at eros')
);
Set props.skin
to style a ListGroupItem
using contextual colors.
part of over_react.web.demos;
ReactElement listGroupContextualSkinDemo() =>
ListGroup()(
(ListGroupItem()
..onClick = (_) {}
..skin = ListGroupItemSkin.SUCCESS
)('Dapibus ac facilisis in'),
(ListGroupItem()
..onClick = (_) {}
..skin = ListGroupItemSkin.INFO
)('Cras sit amet nibh libero'),
(ListGroupItem()
..onClick = (_) {}
..skin = ListGroupItemSkin.WARNING
)('Porta ac consectetur ac'),
(ListGroupItem()
..onClick = (_) {}
..skin = ListGroupItemSkin.DANGER
)('Vestibulum at eros')
);
Set props.header
to render a ListGroupItem
that has a distinct header and body content
region.
Optionally, set props.headerSize
to modify the size of the header itself.
part of over_react.web.demos;
ReactElement listGroupHeaderDemo() =>
ListGroup()(
(ListGroupItem()
..header = 'List group item heading'
..onClick = (_) {}
..isActive = true
)(
'Donec id elit non mi porta gravida at eget metus. '
'Maecenas sed diam eget risus varius blandit.'
),
(ListGroupItem()
..header = 'List group item heading'
..headerSize = ListGroupItemHeaderElementSize.H4
..onClick = (_) {}
)(
'Donec id elit non mi porta gravida at eget metus. '
'Maecenas sed diam eget risus varius blandit.'
),
(ListGroupItem()
..header = 'List group item heading'
..headerSize = ListGroupItemHeaderElementSize.H3
..onClick = (_) {}
)(
'Donec id elit non mi porta gravida at eget metus. '
'Maecenas sed diam eget risus varius blandit.'
)
);