From 1a7020a21c90d77f6a9665979d29d859ee8bfb55 Mon Sep 17 00:00:00 2001 From: Aaron Lademann Date: Tue, 25 Oct 2016 10:27:07 -0700 Subject: [PATCH 1/7] Bring demo components in from gh-pages branch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Squashed commit of the following: commit 38df3b685961b1df5ba34f27657a77c0b72b1ef7 Author: Aaron Lademann Date: Tue Oct 25 09:12:14 2016 -0700 Fix size prop in button demo component commit 7120e0dde624b0e094a4143746c0f4a2b062cfc7 Author: Aaron Lademann Date: Tue Oct 25 09:10:43 2016 -0700 Add analytics for demo hash links + Also fixed some indentation issues commit a55b6306134789f750c5d5d8c1a8d593aef3bc94 Author: Aaron Lademann Date: Tue Oct 25 08:37:38 2016 -0700 Add analytics handlers for external links commit ebe34b787c8e4313f36667463a76bf77e5c1d3de Author: Aaron Lademann Date: Mon Oct 24 15:36:07 2016 -0700 Bump version commit 54b02b975c17669a21cf1740f591fca88c1a00af Merge: aa85533 58682a4 Author: Aaron Lademann Date: Mon Oct 24 15:35:17 2016 -0700 Merge remote-tracking branch 'upstream/master' into gh-pages commit aa85533d66bbee22f45a374217e26348d9d8af51 Author: Aaron Lademann Date: Mon Oct 24 11:29:45 2016 -0700 Update favicons commit 5170c1bb5ce64fc089c0e3dbf0b8e322307ad658 Author: Aaron Lademann Date: Mon Oct 24 11:29:39 2016 -0700 Add attribution for dart / react logo usage commit 3d22dd97837a1b3570a85e1b00a8c88b4cbe1bcf Author: Aaron Lademann Date: Mon Oct 24 08:03:33 2016 -0700 Minify CSS commit 3b0cddf11cdf55d07e7a8be7622e557cbc2e3e9c Author: Aaron Lademann Date: Fri Oct 21 14:52:28 2016 -0700 Add button demo component commit 7b1a357688c1fd51d106d3fe2a8e840e419b57ef Author: Aaron Lademann Date: Fri Oct 21 14:38:12 2016 -0700 Fix demo landing page card spacing commit 558aac94d9fdec6e260d6e0da5724121ff0d0b0f Merge: dc41101 def0106 Author: Aaron Lademann Date: Fri Oct 21 14:19:44 2016 -0700 Merge branch 'readmes' into gh-pages commit dc4110144c852321be9a98e4718152b7ef2d3f45 Author: Aaron Lademann Date: Fri Oct 21 13:57:01 2016 -0700 framework -> library commit f5042c5d5b92bb6c5f4a604b97ed06e637afa31f Merge: 051f336 99d980d Author: Aaron Lademann Date: Fri Oct 21 13:54:11 2016 -0700 Merge branch 'readmes' into gh-pages # Conflicts: # pubspec.yaml commit 051f3366a582e589ad3a0b87a41b049e5ae2b1b2 Author: Aaron Lademann Date: Fri Oct 21 13:11:10 2016 -0700 Fix page title commit 75f5929d3b7e8cc161375bd6e5616d17611aaec5 Author: Aaron Lademann Date: Fri Oct 21 12:07:35 2016 -0700 Add ProgressBar component demo commit 7275a096a846cf270bddcbfb454d5b9f5f3d3ee1 Author: Aaron Lademann Date: Fri Oct 21 10:42:17 2016 -0700 Wire up demos landing page + Created a jekyll data structure to iterate over + Also fixed an issue with open graph url value commit add97553f07389664d2deaa31ec54d8218d9b329 Author: Aaron Lademann Date: Fri Oct 21 07:36:56 2016 -0700 Use page.lead for og description commit ba1cda5cdeca7b8eb82dea4bfeeb2aaa5abd690b Author: Aaron Lademann Date: Fri Oct 21 06:51:41 2016 -0700 Only render type attribute if its a link commit d0b7684a8ec91a41dc597806683626ff5d9b094a Author: Aaron Lademann Date: Fri Oct 21 06:42:50 2016 -0700 Commit root packages directory for docs demos commit 0bdd8e56830dbd0463fce4bcd7ba54341593a791 Author: Aaron Lademann Date: Fri Oct 21 06:28:38 2016 -0700 Change to https to appease gh-pages commit cf09afa112791f3454c46b13718f41efa3884fae Merge: 3a3e4e2 1f52f0d Author: Aaron Lademann Date: Fri Oct 21 05:27:11 2016 -0700 Update docs site commit 3a3e4e2a230e818d8f51829a20ec10d40b33951d Author: Aaron Lademann Date: Fri Oct 21 05:17:18 2016 -0700 Remove TODO url commit a0b94978ef2b2badb14c19df9de3afd9a96b7f6b Author: Aaron Lademann Date: Thu Oct 20 16:15:38 2016 -0700 Initial docs site commit / testing for gh-pages branch Squashed commit of the following: commit 6b35e0770907cf52db345ca8f7b186a2db12c244 Author: Aaron Lademann Date: Wed Oct 19 15:24:25 2016 -0700 Stub in dart / react component demo files commit 83e5e4d3a086a3efa905796e60857bd0d38c11fc Author: Aaron Lademann Date: Wed Oct 19 15:01:21 2016 -0700 Allow scripts in head and body commit 4c656e78b63f40e8929bb39153143f084b7e6405 Author: Aaron Lademann Date: Wed Oct 19 13:09:39 2016 -0700 Update some docs urls commit d3a90742b983c6d308dffcf3742d8ccaa279a14d Author: Aaron Lademann Date: Tue Oct 18 13:00:51 2016 -0700 DOCS: Add home page content commit 2648fc522148c893aa45dafe6ab23cb5507461a2 Author: Aaron Lademann Date: Tue Oct 18 07:51:00 2016 -0700 DOCS: Don’t write custom styles using bs classes commit a1b0caacbeda25b021809ba1e17ad3da1abf3265 Author: Aaron Lademann Date: Tue Oct 18 07:38:36 2016 -0700 DOCS: Improve inline svg accessibility commit 3b767514ed3660ec2c03d08b8bac2ed926fa0c0f Author: Aaron Lademann Date: Tue Oct 18 07:33:58 2016 -0700 DOCS: Use SVG for navbar brand name + Otherwise we’re at the mercy of the font within the stack that the user’s system actually has, which can cause the text size to vary a great deal. commit 287a58c3848d09ae249c7b7e4b3d303ea85e75ce Author: Aaron Lademann Date: Tue Oct 18 06:59:39 2016 -0700 Improve docs site footer + Add workiva W symbol + Tweak item spacing + Add link to license commit ad994f82191e3692512d2c7d3451734cff9429ea Author: Aaron Lademann Date: Tue Oct 18 06:58:49 2016 -0700 Make inline svgs accessible commit 621661076c9f9f0a9eaf9b584894bd7715c3a545 Author: Aaron Lademann Date: Mon Oct 17 08:28:31 2016 -0700 Add Google Analytics tracking code for docs site commit 0f668b5af9dc40bcd2a89a19ee3ee35b83bd5150 Author: Aaron Lademann Date: Fri Oct 14 16:17:19 2016 -0700 Update logo commit 7d608031945adacbac6cf17f6e8fbe698cf9061d Author: Aaron Lademann Date: Fri Oct 14 16:08:21 2016 -0700 Add home / misc page layouts and styles commit 2d75b68d3c728123230a56f63b5a8e5cf755e7c5 Author: Aaron Lademann Date: Fri Oct 14 10:10:47 2016 -0700 Add brand assets commit 266cc47bfbacaea65597726ccdada22eb62a2162 Author: Aaron Lademann Date: Thu Oct 13 16:46:42 2016 -0700 Stub in a jekyll docs site skeleton commit 972ce7ddadc9ffc6eddebe9cfd5c1f9ddafb494e Author: Aaron Lademann Date: Thu Oct 13 15:26:19 2016 -0700 Add twbs submodule + So we can build some docs! commit 1f52f0d6938888729d64c1f36dbe286574fadf9c Author: Aaron Lademann Date: Thu Oct 20 16:12:00 2016 -0700 Fix typo, comment out todo commit 9dc2e8bb9d2143892292b4da2d3d2e0dc57015d0 Author: Aaron Lademann Date: Thu Oct 20 16:10:47 2016 -0700 DOCS: Commit build/ dir for gh-pages push commit ff894b3e468144898244b06e3eeaad2e6334e651 Author: Aaron Lademann Date: Thu Oct 20 16:10:14 2016 -0700 DOCS: Add ListGroup / ListGroupItem / Tag components & demos commit 6b35e0770907cf52db345ca8f7b186a2db12c244 Author: Aaron Lademann Date: Wed Oct 19 15:24:25 2016 -0700 Stub in dart / react component demo files commit 83e5e4d3a086a3efa905796e60857bd0d38c11fc Author: Aaron Lademann Date: Wed Oct 19 15:01:21 2016 -0700 Allow scripts in head and body commit 4c656e78b63f40e8929bb39153143f084b7e6405 Author: Aaron Lademann Date: Wed Oct 19 13:09:39 2016 -0700 Update some docs urls commit d3a90742b983c6d308dffcf3742d8ccaa279a14d Author: Aaron Lademann Date: Tue Oct 18 13:00:51 2016 -0700 DOCS: Add home page content commit 2648fc522148c893aa45dafe6ab23cb5507461a2 Author: Aaron Lademann Date: Tue Oct 18 07:51:00 2016 -0700 DOCS: Don’t write custom styles using bs classes commit a1b0caacbeda25b021809ba1e17ad3da1abf3265 Author: Aaron Lademann Date: Tue Oct 18 07:38:36 2016 -0700 DOCS: Improve inline svg accessibility commit 3b767514ed3660ec2c03d08b8bac2ed926fa0c0f Author: Aaron Lademann Date: Tue Oct 18 07:33:58 2016 -0700 DOCS: Use SVG for navbar brand name + Otherwise we’re at the mercy of the font within the stack that the user’s system actually has, which can cause the text size to vary a great deal. commit 287a58c3848d09ae249c7b7e4b3d303ea85e75ce Author: Aaron Lademann Date: Tue Oct 18 06:59:39 2016 -0700 Improve docs site footer + Add workiva W symbol + Tweak item spacing + Add link to license commit ad994f82191e3692512d2c7d3451734cff9429ea Author: Aaron Lademann Date: Tue Oct 18 06:58:49 2016 -0700 Make inline svgs accessible commit 621661076c9f9f0a9eaf9b584894bd7715c3a545 Author: Aaron Lademann Date: Mon Oct 17 08:28:31 2016 -0700 Add Google Analytics tracking code for docs site commit 0f668b5af9dc40bcd2a89a19ee3ee35b83bd5150 Author: Aaron Lademann Date: Fri Oct 14 16:17:19 2016 -0700 Update logo commit 7d608031945adacbac6cf17f6e8fbe698cf9061d Author: Aaron Lademann Date: Fri Oct 14 16:08:21 2016 -0700 Add home / misc page layouts and styles commit 2d75b68d3c728123230a56f63b5a8e5cf755e7c5 Author: Aaron Lademann Date: Fri Oct 14 10:10:47 2016 -0700 Add brand assets commit 266cc47bfbacaea65597726ccdada22eb62a2162 Author: Aaron Lademann Date: Thu Oct 13 16:46:42 2016 -0700 Stub in a jekyll docs site skeleton commit 972ce7ddadc9ffc6eddebe9cfd5c1f9ddafb494e Author: Aaron Lademann Date: Thu Oct 13 15:26:19 2016 -0700 Add twbs submodule + So we can build some docs! --- web/demos/button/button-active.dart | 12 + web/demos/button/button-block.dart | 11 + web/demos/button/button-disabled.dart | 13 + web/demos/button/button-examples.dart | 12 + web/demos/button/button-outline.dart | 11 + web/demos/button/button-sizes.dart | 8 + web/demos/button/button-types.dart | 9 + web/demos/button/index.dart | 33 +++ web/demos/constants.dart | 1 + web/demos/demos.dart | 30 +++ web/demos/list-group/index.dart | 27 ++ .../list-group-anchors-and-buttons.dart | 29 +++ web/demos/list-group/list-group-basic.dart | 9 + .../list-group/list-group-contextual.dart | 21 ++ web/demos/list-group/list-group-header.dart | 29 +++ web/demos/list-group/list-group-tags.dart | 26 ++ web/demos/progress/index.dart | 24 ++ .../progress/progress-animated-stripes.dart | 8 + web/demos/progress/progress-basic.dart | 33 +++ web/demos/progress/progress-contextual.dart | 20 ++ web/demos/progress/progress-striped.dart | 28 ++ web/demos/tag/index.dart | 18 ++ web/demos/tag/tag-basic.dart | 10 + web/demos/tag/tag-contextual.dart | 10 + web/demos/tag/tag-pills.dart | 28 ++ web/src/demo_components.dart | 18 ++ web/src/demo_components/button.dart | 190 ++++++++++++++ web/src/demo_components/list_group.dart | 49 ++++ web/src/demo_components/list_group_item.dart | 241 ++++++++++++++++++ web/src/demo_components/progress.dart | 195 ++++++++++++++ web/src/demo_components/shared.dart | 21 ++ web/src/demo_components/tag.dart | 77 ++++++ 32 files changed, 1251 insertions(+) create mode 100644 web/demos/button/button-active.dart create mode 100644 web/demos/button/button-block.dart create mode 100644 web/demos/button/button-disabled.dart create mode 100644 web/demos/button/button-examples.dart create mode 100644 web/demos/button/button-outline.dart create mode 100644 web/demos/button/button-sizes.dart create mode 100644 web/demos/button/button-types.dart create mode 100644 web/demos/button/index.dart create mode 100644 web/demos/constants.dart create mode 100644 web/demos/demos.dart create mode 100644 web/demos/list-group/index.dart create mode 100644 web/demos/list-group/list-group-anchors-and-buttons.dart create mode 100644 web/demos/list-group/list-group-basic.dart create mode 100644 web/demos/list-group/list-group-contextual.dart create mode 100644 web/demos/list-group/list-group-header.dart create mode 100644 web/demos/list-group/list-group-tags.dart create mode 100644 web/demos/progress/index.dart create mode 100644 web/demos/progress/progress-animated-stripes.dart create mode 100644 web/demos/progress/progress-basic.dart create mode 100644 web/demos/progress/progress-contextual.dart create mode 100644 web/demos/progress/progress-striped.dart create mode 100644 web/demos/tag/index.dart create mode 100644 web/demos/tag/tag-basic.dart create mode 100644 web/demos/tag/tag-contextual.dart create mode 100644 web/demos/tag/tag-pills.dart create mode 100644 web/src/demo_components.dart create mode 100644 web/src/demo_components/button.dart create mode 100644 web/src/demo_components/list_group.dart create mode 100644 web/src/demo_components/list_group_item.dart create mode 100644 web/src/demo_components/progress.dart create mode 100644 web/src/demo_components/shared.dart create mode 100644 web/src/demo_components/tag.dart diff --git a/web/demos/button/button-active.dart b/web/demos/button/button-active.dart new file mode 100644 index 000000000..7d7f0e867 --- /dev/null +++ b/web/demos/button/button-active.dart @@ -0,0 +1,12 @@ +part of over_react.web.demos; + +ReactElement buttonActiveDemo() => + (Dom.div()..className = 'btn-toolbar')( + (Button() + ..isActive = true + )('Primary button'), + (Button() + ..isActive = true + ..skin = ButtonSkin.SECONDARY + )('Button') + ); diff --git a/web/demos/button/button-block.dart b/web/demos/button/button-block.dart new file mode 100644 index 000000000..a540b60bd --- /dev/null +++ b/web/demos/button/button-block.dart @@ -0,0 +1,11 @@ +part of over_react.web.demos; + +ReactElement buttonBlockDemo() => Dom.div()( + (Button() + ..isBlock = true + )('Block level button'), + (Button() + ..isBlock = true + ..skin = ButtonSkin.SECONDARY + )('Block level button') +); diff --git a/web/demos/button/button-disabled.dart b/web/demos/button/button-disabled.dart new file mode 100644 index 000000000..3ceef26e0 --- /dev/null +++ b/web/demos/button/button-disabled.dart @@ -0,0 +1,13 @@ +part of over_react.web.demos; + +ReactElement buttonDisabledDemo() => + (Dom.div()..className = 'btn-toolbar')( + (Button() + ..isDisabled = true + )('Primary button'), + (Button() + ..href = '#' + ..isDisabled = true + ..skin = ButtonSkin.SECONDARY + )('Link') + ); diff --git a/web/demos/button/button-examples.dart b/web/demos/button/button-examples.dart new file mode 100644 index 000000000..fc5fd0a50 --- /dev/null +++ b/web/demos/button/button-examples.dart @@ -0,0 +1,12 @@ +part of over_react.web.demos; + +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()..skin = ButtonSkin.LINK)('Link') + ); diff --git a/web/demos/button/button-outline.dart b/web/demos/button/button-outline.dart new file mode 100644 index 000000000..7fea8d724 --- /dev/null +++ b/web/demos/button/button-outline.dart @@ -0,0 +1,11 @@ +part of over_react.web.demos; + +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') + ); diff --git a/web/demos/button/button-sizes.dart b/web/demos/button/button-sizes.dart new file mode 100644 index 000000000..278d8d443 --- /dev/null +++ b/web/demos/button/button-sizes.dart @@ -0,0 +1,8 @@ +part of over_react.web.demos; + +ReactElement buttonSizesDemo() => + (Dom.div()..className = 'btn-toolbar')( + (Button()..size = ButtonSize.SMALL)('Small'), + Button()('Default'), + (Button()..size = ButtonSize.LARGE)('Large') + ); diff --git a/web/demos/button/button-types.dart b/web/demos/button/button-types.dart new file mode 100644 index 000000000..cbb7e458d --- /dev/null +++ b/web/demos/button/button-types.dart @@ -0,0 +1,9 @@ +part of over_react.web.demos; + +ReactElement buttonTypesDemo() => + (Dom.div()..className = 'btn-toolbar')( + Button()('Button'), + (Button()..href = '#')('Link'), + (Button()..type = ButtonType.SUBMIT)('Submit'), + (Button()..type = ButtonType.RESET)('Reset') + ); diff --git a/web/demos/button/index.dart b/web/demos/button/index.dart new file mode 100644 index 000000000..4d34be70e --- /dev/null +++ b/web/demos/button/index.dart @@ -0,0 +1,33 @@ +import 'dart:html'; +import 'package:react/react.dart' as react; +import 'package:react/react_dom.dart' as react_dom; +import 'package:react/react_client.dart'; +import 'package:over_react/over_react.dart'; + +import '../demos.dart'; +import '../constants.dart'; + +main() { + setClientConfiguration(); + + react_dom.render(buttonExamplesDemo(), + querySelector('$demoMountNodeSelectorPrefix--button-examples')); + + react_dom.render(buttonTypesDemo(), + querySelector('$demoMountNodeSelectorPrefix--button-types')); + + react_dom.render(buttonOutlineDemo(), + querySelector('$demoMountNodeSelectorPrefix--button-outline')); + + react_dom.render(buttonSizesDemo(), + querySelector('$demoMountNodeSelectorPrefix--button-sizes')); + + react_dom.render(buttonBlockDemo(), + querySelector('$demoMountNodeSelectorPrefix--button-block')); + + react_dom.render(buttonActiveDemo(), + querySelector('$demoMountNodeSelectorPrefix--button-active')); + + react_dom.render(buttonDisabledDemo(), + querySelector('$demoMountNodeSelectorPrefix--button-disabled')); +} diff --git a/web/demos/constants.dart b/web/demos/constants.dart new file mode 100644 index 000000000..1a87c4968 --- /dev/null +++ b/web/demos/constants.dart @@ -0,0 +1 @@ +const String demoMountNodeSelectorPrefix = '.component-demo__mount'; diff --git a/web/demos/demos.dart b/web/demos/demos.dart new file mode 100644 index 000000000..6cf54007d --- /dev/null +++ b/web/demos/demos.dart @@ -0,0 +1,30 @@ +library over_react.web.demos; + +// Imports +import 'package:react/react_client.dart'; +import 'package:over_react/over_react.dart'; +import '../src/demo_components.dart'; + +// Parts +part 'button/button-examples.dart'; +part 'button/button-types.dart'; +part 'button/button-outline.dart'; +part 'button/button-sizes.dart'; +part 'button/button-block.dart'; +part 'button/button-active.dart'; +part 'button/button-disabled.dart'; + +part 'list-group/list-group-basic.dart'; +part 'list-group/list-group-tags.dart'; +part 'list-group/list-group-anchors-and-buttons.dart'; +part 'list-group/list-group-contextual.dart'; +part 'list-group/list-group-header.dart'; + +part 'progress/progress-basic.dart'; +part 'progress/progress-contextual.dart'; +part 'progress/progress-striped.dart'; +part 'progress/progress-animated-stripes.dart'; + +part 'tag/tag-basic.dart'; +part 'tag/tag-contextual.dart'; +part 'tag/tag-pills.dart'; diff --git a/web/demos/list-group/index.dart b/web/demos/list-group/index.dart new file mode 100644 index 000000000..435c87dc5 --- /dev/null +++ b/web/demos/list-group/index.dart @@ -0,0 +1,27 @@ +import 'dart:html'; +import 'package:react/react.dart' as react; +import 'package:react/react_dom.dart' as react_dom; +import 'package:react/react_client.dart'; +import 'package:over_react/over_react.dart'; + +import '../demos.dart'; +import '../constants.dart'; + +main() { + setClientConfiguration(); + + react_dom.render(listGroupBasicDemo(), + querySelector('$demoMountNodeSelectorPrefix--list-group-basic')); + + react_dom.render(listGroupTagsDemo(), + querySelector('$demoMountNodeSelectorPrefix--list-group-tags')); + + react_dom.render(listGroupAnchorsAndButtonsDemo(), + querySelector('$demoMountNodeSelectorPrefix--list-group-anchors-and-buttons')); + + react_dom.render(listGroupContextualSkinDemo(), + querySelector('$demoMountNodeSelectorPrefix--list-group-contextual')); + + react_dom.render(listGroupHeaderDemo(), + querySelector('$demoMountNodeSelectorPrefix--list-group-header')); +} diff --git a/web/demos/list-group/list-group-anchors-and-buttons.dart b/web/demos/list-group/list-group-anchors-and-buttons.dart new file mode 100644 index 000000000..d9fd6c7e9 --- /dev/null +++ b/web/demos/list-group/list-group-anchors-and-buttons.dart @@ -0,0 +1,29 @@ +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') + ); + + + + + + + diff --git a/web/demos/list-group/list-group-basic.dart b/web/demos/list-group/list-group-basic.dart new file mode 100644 index 000000000..f485172ce --- /dev/null +++ b/web/demos/list-group/list-group-basic.dart @@ -0,0 +1,9 @@ +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') + ); diff --git a/web/demos/list-group/list-group-contextual.dart b/web/demos/list-group/list-group-contextual.dart new file mode 100644 index 000000000..4d3ac3ecc --- /dev/null +++ b/web/demos/list-group/list-group-contextual.dart @@ -0,0 +1,21 @@ +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') + ); diff --git a/web/demos/list-group/list-group-header.dart b/web/demos/list-group/list-group-header.dart new file mode 100644 index 000000000..6e1d3b4d4 --- /dev/null +++ b/web/demos/list-group/list-group-header.dart @@ -0,0 +1,29 @@ +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.' + ) + ); diff --git a/web/demos/list-group/list-group-tags.dart b/web/demos/list-group/list-group-tags.dart new file mode 100644 index 000000000..9a3e66c63 --- /dev/null +++ b/web/demos/list-group/list-group-tags.dart @@ -0,0 +1,26 @@ +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' + ) + ); diff --git a/web/demos/progress/index.dart b/web/demos/progress/index.dart new file mode 100644 index 000000000..952d9822e --- /dev/null +++ b/web/demos/progress/index.dart @@ -0,0 +1,24 @@ +import 'dart:html'; +import 'package:react/react.dart' as react; +import 'package:react/react_dom.dart' as react_dom; +import 'package:react/react_client.dart'; +import 'package:over_react/over_react.dart'; + +import '../demos.dart'; +import '../constants.dart'; + +main() { + setClientConfiguration(); + + react_dom.render(progressBasicDemo(), + querySelector('$demoMountNodeSelectorPrefix--progress-basic')); + + react_dom.render(progressContextualDemo(), + querySelector('$demoMountNodeSelectorPrefix--progress-contextual')); + + react_dom.render(progressStripedDemo(), + querySelector('$demoMountNodeSelectorPrefix--progress-striped')); + + react_dom.render(progressAnimatedStripesDemo(), + querySelector('$demoMountNodeSelectorPrefix--progress-animated-stripes')); +} diff --git a/web/demos/progress/progress-animated-stripes.dart b/web/demos/progress/progress-animated-stripes.dart new file mode 100644 index 000000000..adcf66748 --- /dev/null +++ b/web/demos/progress/progress-animated-stripes.dart @@ -0,0 +1,8 @@ +part of over_react.web.demos; + +ReactElement progressAnimatedStripesDemo() => + (Progress() + ..value = 25.0 + ..isStriped = true + ..isAnimated = true + )(); diff --git a/web/demos/progress/progress-basic.dart b/web/demos/progress/progress-basic.dart new file mode 100644 index 000000000..be7160c58 --- /dev/null +++ b/web/demos/progress/progress-basic.dart @@ -0,0 +1,33 @@ +part of over_react.web.demos; + +ReactElement progressBasicDemo() => Dom.div()( + (Progress() + ..showCaption = true + ..captionProps = (domProps()..className = 'text-xs-center') + ..caption = 'Reticulating splines...' + )(), + (Progress() + ..value = 25.0 + ..showCaption = true + ..captionProps = (domProps()..className = 'text-xs-center') + ..caption = 'Reticulating splines...' + )(), + (Progress() + ..value = 50.0 + ..showCaption = true + ..captionProps = (domProps()..className = 'text-xs-center') + ..caption = 'Reticulating splines...' + )(), + (Progress() + ..value = 75.0 + ..showCaption = true + ..captionProps = (domProps()..className = 'text-xs-center') + ..caption = 'Reticulating splines...' + )(), + (Progress() + ..value = 100.0 + ..showCaption = true + ..captionProps = (domProps()..className = 'text-xs-center') + ..caption = 'Reticulating splines...' + )() +); diff --git a/web/demos/progress/progress-contextual.dart b/web/demos/progress/progress-contextual.dart new file mode 100644 index 000000000..9ccfd77f5 --- /dev/null +++ b/web/demos/progress/progress-contextual.dart @@ -0,0 +1,20 @@ +part of over_react.web.demos; + +ReactElement progressContextualDemo() => Dom.div()( + (Progress() + ..value = 25.0 + ..skin = ProgressSkin.SUCCESS + )(), + (Progress() + ..value = 50.0 + ..skin = ProgressSkin.INFO + )(), + (Progress() + ..value = 75.0 + ..skin = ProgressSkin.WARNING + )(), + (Progress() + ..value = 100.0 + ..skin = ProgressSkin.DANGER + )() +); diff --git a/web/demos/progress/progress-striped.dart b/web/demos/progress/progress-striped.dart new file mode 100644 index 000000000..326f953b6 --- /dev/null +++ b/web/demos/progress/progress-striped.dart @@ -0,0 +1,28 @@ +part of over_react.web.demos; + +ReactElement progressStripedDemo() => Dom.div()( + (Progress() + ..value = 10.0 + ..isStriped = true + )(), + (Progress() + ..value = 25.0 + ..skin = ProgressSkin.SUCCESS + ..isStriped = true + )(), + (Progress() + ..value = 50.0 + ..skin = ProgressSkin.INFO + ..isStriped = true + )(), + (Progress() + ..value = 75.0 + ..skin = ProgressSkin.WARNING + ..isStriped = true + )(), + (Progress() + ..value = 100.0 + ..skin = ProgressSkin.DANGER + ..isStriped = true + )() +); diff --git a/web/demos/tag/index.dart b/web/demos/tag/index.dart new file mode 100644 index 000000000..dac106d2c --- /dev/null +++ b/web/demos/tag/index.dart @@ -0,0 +1,18 @@ +import 'dart:html'; +import 'package:react/react.dart' as react; +import 'package:react/react_dom.dart' as react_dom; +import 'package:react/react_client.dart'; +import 'package:over_react/over_react.dart'; + +import '../demos.dart'; +import '../constants.dart'; + +main() { + setClientConfiguration(); + + react_dom.render(tagBasicDemo(), querySelector('$demoMountNodeSelectorPrefix--tag-basic')); + + react_dom.render(tagContextualDemo(), querySelector('$demoMountNodeSelectorPrefix--tag-contextual')); + + react_dom.render(tagPillsDemo(), querySelector('$demoMountNodeSelectorPrefix--tag-pills')); +} diff --git a/web/demos/tag/tag-basic.dart b/web/demos/tag/tag-basic.dart new file mode 100644 index 000000000..d347f3b76 --- /dev/null +++ b/web/demos/tag/tag-basic.dart @@ -0,0 +1,10 @@ +part of over_react.web.demos; + +ReactElement tagBasicDemo() => Dom.div()( + Dom.h1()('Example heading ', Tag()('New')), + Dom.h2()('Example heading ', Tag()('New')), + Dom.h3()('Example heading ', Tag()('New')), + Dom.h4()('Example heading ', Tag()('New')), + Dom.h5()('Example heading ', Tag()('New')), + Dom.h6()('Example heading ', Tag()('New')) +); diff --git a/web/demos/tag/tag-contextual.dart b/web/demos/tag/tag-contextual.dart new file mode 100644 index 000000000..8eb6a4ca4 --- /dev/null +++ b/web/demos/tag/tag-contextual.dart @@ -0,0 +1,10 @@ +part of over_react.web.demos; + +ReactElement tagContextualDemo() => Dom.div()( + (Tag()..skin = TagSkin.DEFAULT)('Default'), + (Tag()..skin = TagSkin.PRIMARY)('Primary'), + (Tag()..skin = TagSkin.SUCCESS)('Success'), + (Tag()..skin = TagSkin.INFO)('Info'), + (Tag()..skin = TagSkin.WARNING)('Warning'), + (Tag()..skin = TagSkin.DANGER)('Danger') +); diff --git a/web/demos/tag/tag-pills.dart b/web/demos/tag/tag-pills.dart new file mode 100644 index 000000000..c6e087d68 --- /dev/null +++ b/web/demos/tag/tag-pills.dart @@ -0,0 +1,28 @@ +part of over_react.web.demos; + +ReactElement tagPillsDemo() => Dom.div()( + (Tag() + ..isPill = true + ..skin = TagSkin.DEFAULT + )('Default'), + (Tag() + ..isPill = true + ..skin = TagSkin.PRIMARY + )('Primary'), + (Tag() + ..isPill = true + ..skin = TagSkin.SUCCESS + )('Success'), + (Tag() + ..isPill = true + ..skin = TagSkin.INFO + )('Info'), + (Tag() + ..isPill = true + ..skin = TagSkin.WARNING + )('Warning'), + (Tag() + ..isPill = true + ..skin = TagSkin.DANGER + )('Danger') +); diff --git a/web/src/demo_components.dart b/web/src/demo_components.dart new file mode 100644 index 000000000..670454712 --- /dev/null +++ b/web/src/demo_components.dart @@ -0,0 +1,18 @@ +library over_react.web.demo_components; + +// Imports +import 'dart:html'; +import 'dart:math'; +import 'package:react/react.dart' as react; +import 'package:react/react_dom.dart' as react_dom; +import 'package:react/react_client.dart'; +import 'package:over_react/over_react.dart'; + +// Parts +part 'demo_components/shared.dart'; + +part 'demo_components/button.dart'; +part 'demo_components/list_group.dart'; +part 'demo_components/list_group_item.dart'; +part 'demo_components/progress.dart'; +part 'demo_components/tag.dart'; diff --git a/web/src/demo_components/button.dart b/web/src/demo_components/button.dart new file mode 100644 index 000000000..20e4c2125 --- /dev/null +++ b/web/src/demo_components/button.dart @@ -0,0 +1,190 @@ +part of over_react.web.demo_components; + +/// Nest one or more `Button` components within a [ListGroup] +/// to render individual items within a list. +/// +/// See: +@Factory() +UiFactory Button; + +@Props() +class ButtonProps extends UiProps { + /// The skin / "context" for the [Button]. + /// + /// See: . + /// + /// Default: [ButtonSkin.PRIMARY] + ButtonSkin skin; + + /// The size of the [Button]. + /// + /// See: . + /// + /// Default: [ButtonSize.DEFAULT] + ButtonSize size; + + /// Whether the [Button] should appear "active". + /// + /// See: + /// + /// Default: false + bool isActive; + + /// Whether the [Button] is disabled. + /// + /// See: + /// + /// 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; +} + +@Component() +class ButtonComponent extends UiComponent { + @override + Map getDefaultProps() => (newProps() + ..skin = ButtonSkin.PRIMARY + ..size = ButtonSize.DEFAULT + ..isActive = false + ..isDisabled = false + ..isBlock = false + ..type = ButtonType.BUTTON + ); + + @override + render() { + BuilderOnlyUiFactory factory = _buttonDomNodeFactory; + + return (factory() + ..addProps(copyUnconsumedDomProps()) + ..className = _getButtonClasses().toClassName() + ..href = props.href + ..target = props.target + ..type = _isAnchorLink ? null : props.type.typeName + ..disabled = _isAnchorLink ? null : props.isDisabled + ..addProps(ariaProps() + ..disabled = _isAnchorLink ? props.isDisabled : null + ) + )(props.children); + } + + ClassNameBuilder _getButtonClasses() { + return forwardingClassNameBuilder() + ..add('btn') + ..add('btn-block', props.isBlock) + ..add('active', props.isActive) + ..add('disabled', props.isDisabled) + ..add(props.skin.className) + ..add(props.size.className); + } + + BuilderOnlyUiFactory get _buttonDomNodeFactory => _isAnchorLink ? Dom.a : Dom.button; + + bool get _isAnchorLink => props.href != null; +} + +/// Contextual skin options for a [Button] component. +class ButtonSkin extends ClassNameConstant { + const ButtonSkin._(String name, String className) : super(name, className); + + /// [className] value: 'btn-primary' + static const ButtonSkin PRIMARY = + const ButtonSkin._('PRIMARY', 'btn-primary'); + + /// [className] value: 'btn-secondary' + static const ButtonSkin SECONDARY = + const ButtonSkin._('SECONDARY', 'btn-secondary'); + + /// [className] value: 'btn-danger' + static const ButtonSkin DANGER = + const ButtonSkin._('DANGER', 'btn-danger'); + + /// [className] value: 'btn-success' + static const ButtonSkin SUCCESS = + const ButtonSkin._('SUCCESS', 'btn-success'); + + /// [className] value: 'btn-warning' + static const ButtonSkin WARNING = + const ButtonSkin._('WARNING', 'btn-warning'); + + /// [className] value: 'btn-info' + static const ButtonSkin INFO = + const ButtonSkin._('INFO', 'btn-info'); + + /// [className] value: 'btn-link' + static const ButtonSkin LINK = + const ButtonSkin._('LINK', 'btn-link'); + + /// [className] value: 'btn-outline-primary' + static const ButtonSkin PRIMARY_OUTLINE = + const ButtonSkin._('PRIMARY', 'btn-outline-primary'); + + /// [className] value: 'btn-outline-secondary' + static const ButtonSkin SECONDARY_OUTLINE = + const ButtonSkin._('SECONDARY', 'btn-outline-secondary'); + + /// [className] value: 'btn-outline-danger' + static const ButtonSkin DANGER_OUTLINE = + const ButtonSkin._('DANGER', 'btn-outline-danger'); + + /// [className] value: 'btn-outline-success' + static const ButtonSkin SUCCESS_OUTLINE = + const ButtonSkin._('SUCCESS', 'btn-outline-success'); + + /// [className] value: 'btn-outline-warning' + static const ButtonSkin WARNING_OUTLINE = + const ButtonSkin._('WARNING', 'btn-outline-warning'); + + /// [className] value: 'btn-outline-info' + static const ButtonSkin INFO_OUTLINE = + const ButtonSkin._('INFO', 'btn-outline-info'); +} + +/// Size options for a [Button] component. +class ButtonSize extends ClassNameConstant { + const ButtonSize._(String name, String className) : super(name, className); + + /// [className] value: '' + static const ButtonSize DEFAULT = + const ButtonSize._('DEFAULT', ''); + + /// [className] value: 'btn-lg' + static const ButtonSize LARGE = + const ButtonSize._('LARGE', 'btn-lg'); + + /// [className] value: 'btn-sm' + static const ButtonSize SMALL = + const ButtonSize._('SMALL', 'btn-sm'); +} diff --git a/web/src/demo_components/list_group.dart b/web/src/demo_components/list_group.dart new file mode 100644 index 000000000..1e1192ba9 --- /dev/null +++ b/web/src/demo_components/list_group.dart @@ -0,0 +1,49 @@ +part of over_react.web.demo_components; + +/// Bootstrap's `ListGroup` component is flexible and powerful for +/// displaying lists of [ListGroupItem] components. +/// +/// See: +@Factory() +UiFactory 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 { + @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 componentBuilderFactory; + ListGroupElementType._internal(this.componentBuilderFactory); + + /// A [Dom.ul] (HTML `
    ` element) + static final ListGroupElementType UL = new ListGroupElementType._internal(Dom.ul); + + /// A [Dom.div] (HTML `
    ` element) + static final ListGroupElementType DIV = new ListGroupElementType._internal(Dom.div); +} diff --git a/web/src/demo_components/list_group_item.dart b/web/src/demo_components/list_group_item.dart new file mode 100644 index 000000000..a9b69234a --- /dev/null +++ b/web/src/demo_components/list_group_item.dart @@ -0,0 +1,241 @@ +part of over_react.web.demo_components; + +/// Nest one or more `ListGroupItem` components within a [ListGroup] +/// to render individual items within a list. +/// +/// See: +@Factory() +UiFactory 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: . + 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: . + /// + /// Default: [ListGroupItemSkin.DEFAULT] + ListGroupItemSkin skin; + + /// Whether the [ListGroupItem] should appear "active". + /// + /// See: + /// + /// Default: false + bool isActive; + + /// Whether the [ListGroupItem] is disabled. + /// + /// See: + /// + /// 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 { + @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 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 _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 componentBuilderFactory; + ListGroupItemElementType._internal(this.componentBuilderFactory); + + /// A [Dom.li] (HTML `
  • ` 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 `` 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 componentBuilderFactory; + ListGroupItemHeaderElementSize._internal(this.componentBuilderFactory); + + /// A [Dom.h1] (HTML `

    ` element) + static final ListGroupItemHeaderElementSize H1 = + new ListGroupItemHeaderElementSize._internal(Dom.h1); + + /// A [Dom.h2] (HTML `

    ` element) + static final ListGroupItemHeaderElementSize H2 = + new ListGroupItemHeaderElementSize._internal(Dom.h2); + + /// A [Dom.h3] (HTML `

    ` element) + static final ListGroupItemHeaderElementSize H3 = + new ListGroupItemHeaderElementSize._internal(Dom.h3); + + /// A [Dom.h4] (HTML `

    ` element) + static final ListGroupItemHeaderElementSize H4 = + new ListGroupItemHeaderElementSize._internal(Dom.h4); + + /// A [Dom.h5] (HTML `

    ` element) + static final ListGroupItemHeaderElementSize H5 = + new ListGroupItemHeaderElementSize._internal(Dom.h5); + + /// A [Dom.h6] (HTML `
    ` element) + static final ListGroupItemHeaderElementSize H6 = + new ListGroupItemHeaderElementSize._internal(Dom.h6); +} diff --git a/web/src/demo_components/progress.dart b/web/src/demo_components/progress.dart new file mode 100644 index 000000000..975cb1c1b --- /dev/null +++ b/web/src/demo_components/progress.dart @@ -0,0 +1,195 @@ +part of over_react.web.demo_components; + +/// Bootstrap's `Progress` component stylizes the HTML5 `` element with a +/// few extra CSS classes and some crafty browser-specific CSS. +/// +/// See: +@Factory() +UiFactory Progress; + +@Props() +class ProgressProps extends UiProps { + /// The id for the [Progress] component. + /// + /// If left unspecified one will be auto-generated for you to ensure + /// that the [caption] element is properly linked for accessibility purposes. + @override + String get id; + + /// The current value of the [Progress] component. + /// + /// This value should be between the [min] and [max] values. + /// + /// Default: `0.0` + double value; + + /// The min value of the [Progress] component. + /// + /// Default: `0.0` + double min; + + /// The max value of the [Progress] component. + /// + /// Default: `100.0` + double max; + + /// The skin / "context" for the [Progress] component. + /// + /// See: . + /// + /// Default: [ProgressSkin.DEFAULT] + ProgressSkin skin; + + /// Whether to render a "Barber Pole" gradient stripe effect in the [Progress] component. + /// + /// Default: false + bool isStriped; + + /// Whether to animate the "Barber Pole" gradient stripe effect in the [Progress] component. + /// + /// __Note:__ Has no effect if [isStriped] is `false`. + /// + /// Default: false + bool isAnimated; + + /// Optionally add a caption that describes the context of the [Progress] component. + /// + /// See: . + /// + /// Default: [ProgressComponent._getPercentComplete]% + String caption; + + /// Additional props to be added to the [caption] element _(if specified)_. + Map captionProps; + + /// Whether the [caption] should be visible. + /// + /// Default: false + bool showCaption; + + /// Whether the [caption] should be appended with the value of [value]. + /// + /// Default: true + bool showPercentComplete; + + /// Additional props to be added to the [Dom.div] that wraps around the [caption] element and `` element. + Map rootNodeProps; +} + +@State() +class ProgressState extends UiState { + /// An autogenerated GUID, used as a fallback when [ProgressProps.id] is unspecified, and + /// saved on the state so it will persist across remounts. + /// + /// HTML id attributes are needed on `` elements for proper accessibility support, + /// so this state value ensures there's always a valid ID value to use. + String id; +} + +@Component() +class ProgressComponent extends UiStatefulComponent { + @override + Map getDefaultProps() => (newProps() + ..value = 0.0 + ..min = 0.0 + ..max = 100.0 + ..skin = ProgressSkin.DEFAULT + ..isStriped = false + ..isAnimated = false + ..showCaption = false + ..showPercentComplete = true + ); + + @override + Map getInitialState() => (newState() + ..id = 'progress_' + generateGuid(4) + ); + + @override + render() { + return (Dom.div()..addProps(props.rootNodeProps))( + renderCaptionNode(), + renderProgressNode(), + props.children + ); + } + + ReactElement renderProgressNode() { + return (Dom.progress() + ..addProps(copyUnconsumedDomProps()) + ..addProps(ariaProps() + ..labelledby = captionId + ) + ..className = _getProgressNodeClasses().toClassName() + ..id = id + ..value = currentValue + ..max = props.max + )(); + } + + ReactElement renderCaptionNode() { + var captionClasses = new ClassNameBuilder.fromProps(props.captionProps) + ..add('sr-only', !props.showCaption); + + var captionText = props.caption ?? ''; + + if (props.showPercentComplete) { + captionText += ' ${_getPercentComplete()}%'; + } + + return (Dom.div() + ..addProps(props.captionProps) + ..id = captionId + ..className = captionClasses.toClassName() + )(captionText); + } + + ClassNameBuilder _getProgressNodeClasses() { + return new ClassNameBuilder() + ..add('progress') + ..add('progress-striped', props.isStriped) + ..add('progress-animated', props.isAnimated) + ..add(props.skin.className); + } + + /// Get the percentage complete based on [ProgressProps.min], [ProgressProps.max] and [ProgressProps.value]. + double _getPercentComplete() { + return (props.value - props.min) / (props.max - props.min) * 100; + } + + /// Returns the value that determines the width of the progress bar + /// within the rendered [Progress] component via [DomPropsMixin.value]. + /// + /// Note that the value of the HTML `` element's value + /// attribute will never be less than the value of [ProgressProps.min]. + double get currentValue => max(props.min, props.value); + + String get id => props.id ?? state.id; + + String get captionId => '${id}_caption'; +} + +/// Contextual skin options for a [Progress] component. +class ProgressSkin extends ClassNameConstant { + const ProgressSkin._(String name, String className) : super(name, className); + + /// [className] value: '' + static const ProgressSkin DEFAULT = + const ProgressSkin._('DEFAULT', ''); + + /// [className] value: 'progress-danger' + static const ProgressSkin DANGER = + const ProgressSkin._('DANGER', 'progress-danger'); + + /// [className] value: 'progress-success' + static const ProgressSkin SUCCESS = + const ProgressSkin._('SUCCESS', 'progress-success'); + + /// [className] value: 'progress-warning' + static const ProgressSkin WARNING = + const ProgressSkin._('WARNING', 'progress-warning'); + + /// [className] value: 'progress-info' + static const ProgressSkin INFO = + const ProgressSkin._('INFO', 'progress-info'); +} diff --git a/web/src/demo_components/shared.dart b/web/src/demo_components/shared.dart new file mode 100644 index 000000000..2bc99b99b --- /dev/null +++ b/web/src/demo_components/shared.dart @@ -0,0 +1,21 @@ +part of over_react.web.demo_components; + +/// A class of possible HTML `type` attribute values to be placed on a [Dom.button]. +class ButtonType extends DebugFriendlyConstant { + /// The DOM `