From 75d117d3bc57274713689e87ee5d006880c9664a Mon Sep 17 00:00:00 2001 From: glsdown Date: Sun, 15 Aug 2021 19:22:16 +0100 Subject: [PATCH 1/6] Accordion component and js test --- src/components/accordion/Accordion.js | 203 ++++++++++++++++++ src/components/accordion/AccordionItem.js | 63 ++++++ .../accordion/__tests__/Accordion.test.js | 128 +++++++++++ src/index.js | 2 + 4 files changed, 396 insertions(+) create mode 100644 src/components/accordion/Accordion.js create mode 100644 src/components/accordion/AccordionItem.js create mode 100644 src/components/accordion/__tests__/Accordion.test.js diff --git a/src/components/accordion/Accordion.js b/src/components/accordion/Accordion.js new file mode 100644 index 000000000..0a8ffc003 --- /dev/null +++ b/src/components/accordion/Accordion.js @@ -0,0 +1,203 @@ +import React, {useEffect} from 'react'; +import PropTypes from 'prop-types'; +import {omit} from 'ramda'; +import {default as RBAccordion} from 'react-bootstrap/Accordion'; + +const resolveChildProps = child => { + // This may need to change in the future if https://github.com/plotly/dash-renderer/issues/84 is addressed + if ( + child.props._dashprivate_layout && + child.props._dashprivate_layout.props + ) { + // props are coming from Dash + return child.props._dashprivate_layout.props; + } else { + // else props are coming from React (e.g. Demo.js, or Tabs.test.js) + return child.props; + } +}; + +const Accordion = props => { + const { + children, + active_item, + start_collapsed, + loading_state, + key, + setProps, + ...otherProps + } = props; + + // if active_item not set initially, choose first item + useEffect(() => { + if (setProps && active_item === undefined && !start_collapsed) { + setProps({ + active_item: + children && (resolveChildProps(children[0]).item_id || 'item-0') + }); + } + }, []); + + const toggle = item => { + if (setProps) { + if (active_item !== item) { + setProps({active_item: item}); + } + } + }; + + const items = + children && + children.map((child, idx) => { + const childProps = resolveChildProps(child); + const { + children, + title, + item_id, + loading_state, + ...otherProps + } = childProps; + const itemID = item_id || 'item-' + idx; + return ( + + { + toggle(itemID); + }} + > + {title} + + {children} + + ); + }); + return ( + + {items} + + ); +}; + +Accordion.defaultProps = { + persisted_props: ['active_item'], + persistence_type: 'local', + start_collapsed: false +}; + +Accordion.propTypes = { + /** + * The ID of this component, used to identify dash components + * in callbacks. The ID needs to be unique across all of the + * components in an app. + */ + id: PropTypes.string, + + /** + * The children of this component + */ + children: PropTypes.node, + + /** + * Defines CSS styles which will override styles previously set. + */ + style: PropTypes.object, + + /** + * Often used with CSS to style elements with common properties. + */ + class_name: PropTypes.string, + + /** + * A unique identifier for the component, used to improve + * performance by React.js while rendering components + * See https://reactjs.org/docs/lists-and-keys.html for more info + */ + key: PropTypes.string, + + /** + * Renders accordion edge-to-edge with its parent container + */ + flush: PropTypes.bool, + + /** + * The item_id of the currently active item. If item_id has not been specified + * for the active item, this will default to item-i, where i is the index + * (starting from 0) of the item. + */ + active_item: PropTypes.string, + + /** + * + */ + start_collapsed: PropTypes.bool, + + /** + * Object that holds the loading state object coming from dash-renderer + */ + loading_state: PropTypes.shape({ + /** + * Determines if the component is loading or not + */ + is_loading: PropTypes.bool, + /** + * Holds which property is loading + */ + prop_name: PropTypes.string, + /** + * Holds the name of the component that is loading + */ + component_name: PropTypes.string + }), + + /** + * Used to allow user interactions in this component to be persisted when + * the component - or the page - is refreshed. If `persisted` is truthy and + * hasn't changed from its previous value, a `value` that the user has + * changed while using the app will keep that change, as long as + * the new `value` also matches what was given originally. + * Used in conjunction with `persistence_type`. + */ + persistence: PropTypes.oneOfType([ + PropTypes.bool, + PropTypes.string, + PropTypes.number + ]), + + /** + * Properties whose user interactions will persist after refreshing the + * component or the page. Since only `value` is allowed this prop can + * normally be ignored. + */ + persisted_props: PropTypes.arrayOf(PropTypes.oneOf(['active_item'])), + + /** + * Where persisted user changes will be stored: + * memory: only kept in memory, reset on page refresh. + * local: window.localStorage, data is kept after the browser quit. + * session: window.sessionStorage, data is cleared once the browser quit. + */ + persistence_type: PropTypes.oneOf(['local', 'session', 'memory']) +}; + +export default Accordion; diff --git a/src/components/accordion/AccordionItem.js b/src/components/accordion/AccordionItem.js new file mode 100644 index 000000000..014cb43cb --- /dev/null +++ b/src/components/accordion/AccordionItem.js @@ -0,0 +1,63 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +const AccordionItem = props => { + return <>; +}; + +AccordionItem.propTypes = { + /** + * The ID of this component, used to identify dash components + * in callbacks. The ID needs to be unique across all of the + * components in an app. + */ + id: PropTypes.string, + + /** + * The children of this component + */ + children: PropTypes.node, + + /** + * Defines CSS styles which will override styles previously set. + */ + style: PropTypes.object, + + /** + * Often used with CSS to style elements with common properties. + */ + class_name: PropTypes.string, + + /** + * The title on display in the collapsed accordion item. + */ + title: PropTypes.string, + + /** + * Optional identifier for item used for determining which item is visible + * if not specified, and AccordionItem is being used inside Accordion component, the itemId + * will be set to "item-i" where i is (zero indexed) position of item in list + * items pased to Accordion component. + */ + item_id: PropTypes.string, + + /** + * Object that holds the loading state object coming from dash-renderer + */ + loading_state: PropTypes.shape({ + /** + * Determines if the component is loading or not + */ + is_loading: PropTypes.bool, + /** + * Holds which property is loading + */ + prop_name: PropTypes.string, + /** + * Holds the name of the component that is loading + */ + component_name: PropTypes.string + }) +}; + +export default AccordionItem; diff --git a/src/components/accordion/__tests__/Accordion.test.js b/src/components/accordion/__tests__/Accordion.test.js new file mode 100644 index 000000000..e087e93cc --- /dev/null +++ b/src/components/accordion/__tests__/Accordion.test.js @@ -0,0 +1,128 @@ +import React from 'react'; +import {render} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import Accordion from '../Accordion'; +import AccordionItem from '../AccordionItem'; + +jest.useFakeTimers(); + +describe('Accordion', () => { + test('renders a div with accordion class', () => { + const {container} = render(); + expect(container.querySelector('div.accordion')).not.toBe(null); + }); + + test('renders each item correctly, in order', () => { + const {container} = render( + + item-content-1 + item-content-2 + + ); + + const accordionItems = container.querySelector('div.accordion'); + + // Item class + expect(accordionItems.children[0]).toHaveClass('accordion-item'); + expect(accordionItems.children[1]).toHaveClass('accordion-item'); + + // Headers + expect( + accordionItems.children[0].querySelector('h2.accordion-header') + ).toHaveTextContent('item-label-1'); + expect( + accordionItems.children[1].querySelector('h2.accordion-header') + ).toHaveTextContent('item-label-2'); + + // Content + expect( + accordionItems.children[0].querySelector('div.accordion-collapse') + ).toHaveTextContent('item-content-1'); + expect( + accordionItems.children[1].querySelector('div.accordion-collapse') + ).toHaveTextContent('item-content-2'); + }); + + test('sets currently active item with "active_item" prop', () => { + const {container} = render( + + + item-content-1 + + + item-content-2 + + + ); + + const accordionItems = container.querySelector('div.accordion'); + + expect( + accordionItems.children[0].querySelector('div.accordion-collapse') + ).not.toHaveClass('show'); + expect( + accordionItems.children[1].querySelector('div.accordion-collapse') + ).toHaveClass('show'); + }); + + test('starts in a collapsed state with "start_collapsed" prop', () => { + const {container} = render( + + + item-content-1 + + + item-content-2 + + + ); + + const accordionItems = container.querySelector('div.accordion'); + + expect( + accordionItems.children[0].querySelector('div.accordion-collapse') + ).not.toHaveClass('show'); + expect( + accordionItems.children[1].querySelector('div.accordion-collapse') + ).not.toHaveClass('show'); + }); + + test('tracks most recently clicked item with "active_item" prop', () => { + const mockSetProps = jest.fn(); + const {container, rerender} = render( + + item-content-1 + item-content-2 + + ); + + let accordionItems = container.querySelector('div.accordion'); + + expect( + accordionItems.children[0].querySelector('div.accordion-collapse') + ).toHaveClass('show'); + expect( + accordionItems.children[1].querySelector('div.accordion-collapse') + ).not.toHaveClass('show'); + + userEvent.click( + accordionItems.children[1].querySelector('h2.accordion-header > button') + ); + expect(mockSetProps.mock.calls).toHaveLength(1); + + rerender( + + item-content-1 + item-content-2 + + ); + jest.runAllTimers(); + + expect( + accordionItems.children[0].querySelector('div.accordion-collapse') + ).not.toHaveClass('show'); + expect( + accordionItems.children[1].querySelector('div.accordion-collapse') + ).toHaveClass('show'); + }); +}); diff --git a/src/index.js b/src/index.js index 0e92b88e1..a84989f0a 100644 --- a/src/index.js +++ b/src/index.js @@ -1,3 +1,5 @@ +export {default as Accordion} from './components/accordion/Accordion'; +export {default as AccordionItem} from './components/accordion/AccordionItem'; export {default as Alert} from './components/Alert'; export {default as Badge} from './components/Badge'; export {default as Button} from './components/Button'; From dd23b40f4ca979faac5d3e2bbda4ba514ae6f6d6 Mon Sep 17 00:00:00 2001 From: glsdown Date: Sun, 15 Aug 2021 19:51:05 +0100 Subject: [PATCH 2/6] Added documentation for accordion --- demo/Demo.js | 34 +++++----- docs/components_page/__init__.py | 1 + .../components/__tests__/test_accordion.py | 68 +++++++++++++++++++ docs/components_page/components/accordion.md | 22 ++++++ .../components/accordion/collapsed.py | 25 +++++++ .../components/accordion/flush.py | 25 +++++++ .../components/accordion/simple.py | 56 +++++++++++++++ 7 files changed, 214 insertions(+), 17 deletions(-) create mode 100644 docs/components_page/components/__tests__/test_accordion.py create mode 100644 docs/components_page/components/accordion.md create mode 100644 docs/components_page/components/accordion/collapsed.py create mode 100644 docs/components_page/components/accordion/flush.py create mode 100644 docs/components_page/components/accordion/simple.py diff --git a/demo/Demo.js b/demo/Demo.js index f0a108ed3..43fe5fe88 100644 --- a/demo/Demo.js +++ b/demo/Demo.js @@ -110,7 +110,7 @@ const Demo = () => ( Entry 3 - +

Dash Bootstrap Components - Demo

This demonstrates all of the Dash Bootstrap Components as React @@ -202,8 +202,8 @@ const Demo = () => ( Header -

This card has a header
-

And some text in the body

+
This card has a header
+

And some text in the body

Footer @@ -215,16 +215,16 @@ const Demo = () => ( src="https://images.pexels.com/photos/457882/pexels-photo-457882.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=350" /> -
Card with image
-

This card has an image

+
Card with image
+

This card has an image

-
Here's another card
-

With some text, and a button

+
Here's another card
+

With some text, and a button

@@ -232,8 +232,8 @@ const Demo = () => ( -
Here's yet another card
-

With some text, and some links

+
Here's yet another card
+

With some text, and some links

External @@ -247,8 +247,8 @@ const Demo = () => ( -
The first card
-

+

The first card
+

This is a card with some text on it, it's the first one in the deck.

@@ -256,8 +256,8 @@ const Demo = () => (
-
The second card
-

+

The second card
+

This is a card with some text on it, it's the second one in the deck. It has a bit more text in it so that we can see how the vertical spacing will work. @@ -266,9 +266,9 @@ const Demo = () => ( -

The third card
-
...and the last :(
-

This card doesn't have much text...

+
The third card
+
...and the last :(
+

This card doesn't have much text...

@@ -365,7 +365,7 @@ const Demo = () => ( -

This content fades in and out

+

This content fades in and out

diff --git a/docs/components_page/__init__.py b/docs/components_page/__init__.py index 64daf3579..36b94bae7 100644 --- a/docs/components_page/__init__.py +++ b/docs/components_page/__init__.py @@ -59,6 +59,7 @@ def _get_label(slug): def register_apps(): component_bodies = { + "accordion": {"markdown_path": COMPONENTS / "accordion.md"}, "alert": {"markdown_path": COMPONENTS / "alert.md"}, "badge": {"markdown_path": COMPONENTS / "badge.md"}, "button": {"markdown_path": COMPONENTS / "button.md"}, diff --git a/docs/components_page/components/__tests__/test_accordion.py b/docs/components_page/components/__tests__/test_accordion.py new file mode 100644 index 000000000..34055de79 --- /dev/null +++ b/docs/components_page/components/__tests__/test_accordion.py @@ -0,0 +1,68 @@ +""" +Testing of callbacks in non-Python Accordion snippets. +""" +from pathlib import Path + +import dash.testing.wait as wait + +from .helpers import load_jl_app, load_r_app + +HERE = Path(__file__).parent + + +def test_r_simple(dashr): + r_app = load_r_app((HERE.parent / "accordion" / "simple.R"), "accordion") + dashr.start_server(r_app) + check_simple_callbacks(dashr) + + +def test_jl_simple(dashjl): + jl_app = load_jl_app( + (HERE.parent / "accordion" / "simple.jl"), "accordion" + ) + dashjl.start_server(jl_app) + check_simple_callbacks(dashjl) + + +def check_simple_callbacks(runner): + # Find the accordion object + accordion_comp = runner.find_element("#accordion") + accordion_text = runner.find_element("#accordion-contents") + + # Check it has 3 page-items objects in it + pages = accordion_comp.find_elements(".accordion-item") + wait.until( + lambda: len(pages) == 3, + timeout=4, + ) + + # Click the third section + wait.until( + lambda: pages[2].find_elements(".accordion-collapse").text + == "This is the content of the third section", + timeout=4, + ) + pages[2].find_elements(".accordion-button").click() + + # Check the text in contents changes to "Item selected: item-2" + wait.until( + lambda: accordion_text.text == "Item selected: item-2", + timeout=4, + ) + + # Change the slider to value 1 + runner.click_at_coord_fractions( + runner.find_element("#item-change"), 0.5, 0.25 + ) + + # Check the text in contents changes to "Item selected: item-1" + wait.until( + lambda: accordion_text.text == "Item selected: item-1", + timeout=4, + ) + + # Check that the right section is showing + item = accordion_comp.find_element(".show") + wait.until( + lambda: item.text == "This is the content of the second section" + ) diff --git a/docs/components_page/components/accordion.md b/docs/components_page/components/accordion.md new file mode 100644 index 000000000..d051b57d4 --- /dev/null +++ b/docs/components_page/components/accordion.md @@ -0,0 +1,22 @@ +--- +title: Accordion +lead: Use the Accordion component to create collapsible lists. +--- + +You can create an accordion using the `Accordion` and `AccordionItem` components. Each item in the accordion can be assiged a specific `item_id` which is used in the `active_item` property to determine which section is open. If no `item_id` is specified, the sections are labelled as `item-0`, `item-1`, ... consecutively. Each section header is determined by the `title` prop of the `AccordionItem`. + +{{example:components/accordion/simple.py:accordion}} + +## Start Collapsed + +You can set which item is opened when it is first started using the `active_item` property. If this is not defined, the first item will be open by default. If you want no items to be open on start up, you can specify `start_collapsed=True`. + +{{example:components/accordion/collapsed.py:accordion}} + +## Flush + +Add flush to change some of the styling, including removing borders, and rounding some of the edges to fit in line with the parent container. + +{{example:components/accordion/flush.py:accordion}} + +{{apidoc:src/components/accordion/Accordion.js}} diff --git a/docs/components_page/components/accordion/collapsed.py b/docs/components_page/components/accordion/collapsed.py new file mode 100644 index 000000000..894117d8d --- /dev/null +++ b/docs/components_page/components/accordion/collapsed.py @@ -0,0 +1,25 @@ +import dash_bootstrap_components as dbc +import dash_html_components as html + +accordion = html.Div( + dbc.Container( + dbc.Accordion( + [ + dbc.AccordionItem( + "This is the content of the first section", + title="Item 1", + ), + dbc.AccordionItem( + "This is the content of the second section", + title="Item 2", + ), + dbc.AccordionItem( + "This is the content of the third section", + title="Item 3", + ), + ], + start_collapsed=True, + ), + class_name="m-3", + ), +) diff --git a/docs/components_page/components/accordion/flush.py b/docs/components_page/components/accordion/flush.py new file mode 100644 index 000000000..3ca4e9cff --- /dev/null +++ b/docs/components_page/components/accordion/flush.py @@ -0,0 +1,25 @@ +import dash_bootstrap_components as dbc +import dash_html_components as html + +accordion = html.Div( + dbc.Container( + dbc.Accordion( + [ + dbc.AccordionItem( + "This is the content of the first section", + title="Item 1", + ), + dbc.AccordionItem( + "This is the content of the second section", + title="Item 2", + ), + dbc.AccordionItem( + "This is the content of the third section", + title="Item 3", + ), + ], + flush=True, + ), + class_name="m-3", + ), +) diff --git a/docs/components_page/components/accordion/simple.py b/docs/components_page/components/accordion/simple.py new file mode 100644 index 000000000..97086c96b --- /dev/null +++ b/docs/components_page/components/accordion/simple.py @@ -0,0 +1,56 @@ +import dash_bootstrap_components as dbc +import dash_core_components as dcc +import dash_html_components as html +from dash.dependencies import Input, Output + +accordion = html.Div( + [ + html.Div("Select an item", id="accordion-contents"), + dbc.Container( + dbc.Accordion( + [ + dbc.AccordionItem( + "This is the content of the first section", + title="Item 1", + ), + dbc.AccordionItem( + "This is the content of the second section", + title="Item 2", + ), + dbc.AccordionItem( + "This is the content of the third section", + title="Item 3", + ), + ], + id="accordion", + ), + class_name="m-3", + ), + html.Div("Or set the open item dynamically using the slider below"), + dcc.Slider( + id="item-change", + min=0, + max=2, + step=1, + value=0, + marks={i: str(i) for i in range(3)}, + ), + ] +) + + +@app.callback( + Output("accordion-contents", "children"), + [Input("accordion", "active_item")], +) +def change_item(item): + if item: + return f"Item selected: {item}" + return "Select an item" + + +@app.callback( + Output("accordion", "active_item"), [Input("item-change", "value")] +) +def change_active_item(value): + return f"item-{value}" From 593bb4d072ccc5685221b257f36fd32d447f1883 Mon Sep 17 00:00:00 2001 From: glsdown Date: Sun, 15 Aug 2021 20:11:26 +0100 Subject: [PATCH 3/6] R and Julia examples --- .../components/accordion/collapsed.R | 22 ++++++++ .../components/accordion/collapsed.jl | 21 +++++++ .../components/accordion/collapsed.py | 35 ++++++------ .../components/accordion/flush.R | 22 ++++++++ .../components/accordion/flush.jl | 21 +++++++ .../components/accordion/flush.py | 35 ++++++------ .../components/accordion/simple.R | 55 +++++++++++++++++++ .../components/accordion/simple.jl | 54 ++++++++++++++++++ .../components/accordion/simple.py | 40 +++++++------- 9 files changed, 247 insertions(+), 58 deletions(-) create mode 100644 docs/components_page/components/accordion/collapsed.R create mode 100644 docs/components_page/components/accordion/collapsed.jl create mode 100644 docs/components_page/components/accordion/flush.R create mode 100644 docs/components_page/components/accordion/flush.jl create mode 100644 docs/components_page/components/accordion/simple.R create mode 100644 docs/components_page/components/accordion/simple.jl diff --git a/docs/components_page/components/accordion/collapsed.R b/docs/components_page/components/accordion/collapsed.R new file mode 100644 index 000000000..1779a11bb --- /dev/null +++ b/docs/components_page/components/accordion/collapsed.R @@ -0,0 +1,22 @@ +library(dashBootstrapComponents) +library(dashHtmlComponents) + +accordion <- htmlDiv( + dbcAccordion( + list( + dbcAccordionItem( + "This is the content of the first section", + title="Item 1", + ), + dbcAccordionItem( + "This is the content of the second section", + title="Item 2", + ), + dbcAccordionItem( + "This is the content of the third section", + title="Item 3", + ), + ), + start_collapsed=TRUE, + ), +) diff --git a/docs/components_page/components/accordion/collapsed.jl b/docs/components_page/components/accordion/collapsed.jl new file mode 100644 index 000000000..faca13d56 --- /dev/null +++ b/docs/components_page/components/accordion/collapsed.jl @@ -0,0 +1,21 @@ +using DashBootstrapComponents, DashHtmlComponents + +accordion = html_div( + dbc_accordion( + [ + dbc_accordionitem( + "This is the content of the first section", + title="Item 1", + ), + dbc_accordionitem( + "This is the content of the second section", + title="Item 2", + ), + dbc_accordionitem( + "This is the content of the third section", + title="Item 3", + ), + ], + start_collapsed=true, + ), +) diff --git a/docs/components_page/components/accordion/collapsed.py b/docs/components_page/components/accordion/collapsed.py index 894117d8d..da0b0fd0f 100644 --- a/docs/components_page/components/accordion/collapsed.py +++ b/docs/components_page/components/accordion/collapsed.py @@ -2,24 +2,21 @@ import dash_html_components as html accordion = html.Div( - dbc.Container( - dbc.Accordion( - [ - dbc.AccordionItem( - "This is the content of the first section", - title="Item 1", - ), - dbc.AccordionItem( - "This is the content of the second section", - title="Item 2", - ), - dbc.AccordionItem( - "This is the content of the third section", - title="Item 3", - ), - ], - start_collapsed=True, - ), - class_name="m-3", + dbc.Accordion( + [ + dbc.AccordionItem( + "This is the content of the first section", + title="Item 1", + ), + dbc.AccordionItem( + "This is the content of the second section", + title="Item 2", + ), + dbc.AccordionItem( + "This is the content of the third section", + title="Item 3", + ), + ], + start_collapsed=True, ), ) diff --git a/docs/components_page/components/accordion/flush.R b/docs/components_page/components/accordion/flush.R new file mode 100644 index 000000000..ec3a6c724 --- /dev/null +++ b/docs/components_page/components/accordion/flush.R @@ -0,0 +1,22 @@ +library(dashBootstrapComponents) +library(dashHtmlComponents) + +accordion <- htmlDiv( + dbcAccordion( + list( + dbcAccordionItem( + "This is the content of the first section", + title="Item 1", + ), + dbcAccordionItem( + "This is the content of the second section", + title="Item 2", + ), + dbcAccordionItem( + "This is the content of the third section", + title="Item 3", + ), + ), + flush=TRUE, + ), +) diff --git a/docs/components_page/components/accordion/flush.jl b/docs/components_page/components/accordion/flush.jl new file mode 100644 index 000000000..3b32b9d5c --- /dev/null +++ b/docs/components_page/components/accordion/flush.jl @@ -0,0 +1,21 @@ +using DashBootstrapComponents, DashHtmlComponents + +accordion = html_div( + dbc_accordion( + [ + dbc_accordionitem( + "This is the content of the first section", + title="Item 1", + ), + dbc_accordionitem( + "This is the content of the second section", + title="Item 2", + ), + dbc_accordionitem( + "This is the content of the third section", + title="Item 3", + ), + ], + flush=true, + ), +) diff --git a/docs/components_page/components/accordion/flush.py b/docs/components_page/components/accordion/flush.py index 3ca4e9cff..15f80d311 100644 --- a/docs/components_page/components/accordion/flush.py +++ b/docs/components_page/components/accordion/flush.py @@ -2,24 +2,21 @@ import dash_html_components as html accordion = html.Div( - dbc.Container( - dbc.Accordion( - [ - dbc.AccordionItem( - "This is the content of the first section", - title="Item 1", - ), - dbc.AccordionItem( - "This is the content of the second section", - title="Item 2", - ), - dbc.AccordionItem( - "This is the content of the third section", - title="Item 3", - ), - ], - flush=True, - ), - class_name="m-3", + dbc.Accordion( + [ + dbc.AccordionItem( + "This is the content of the first section", + title="Item 1", + ), + dbc.AccordionItem( + "This is the content of the second section", + title="Item 2", + ), + dbc.AccordionItem( + "This is the content of the third section", + title="Item 3", + ), + ], + flush=True, ), ) diff --git a/docs/components_page/components/accordion/simple.R b/docs/components_page/components/accordion/simple.R new file mode 100644 index 000000000..e17c5b933 --- /dev/null +++ b/docs/components_page/components/accordion/simple.R @@ -0,0 +1,55 @@ +library(dashBootstrapComponents) +library(dashCoreComponents) +library(dashHtmlComponents) + +accordion <- htmlDiv( + list( + htmlDiv("Select an item", id="accordion-contents"), + dbcAccordion( + list( + dbcAccordionItem( + "This is the content of the first section", + title="Item 1", + ), + dbcAccordionItem( + "This is the content of the second section", + title="Item 2", + ), + dbcAccordionItem( + "This is the content of the third section", + title="Item 3", + ), + ), + id="accordion", + ), + htmlDiv( + "Or set the open item dynamically using the slider below", + class_name="py-2", + ), + dccSlider( + id="item-change", + min=0, + max=2, + step=1, + value=0, + marks=list(0="0", 1="1", 2="2") + ), + ) +) + + +@app.callback( + Output("accordion-contents", "children"), + [Input("accordion", "active_item")], +) +def change_item(item): + if item: + return f"Item selected: {item}" + return "Select an item" + + +@app.callback( + Output("accordion", "active_item"), [Input("item-change", "value")] +) +def change_active_item(value): + return f"item-{value}" diff --git a/docs/components_page/components/accordion/simple.jl b/docs/components_page/components/accordion/simple.jl new file mode 100644 index 000000000..15770cb11 --- /dev/null +++ b/docs/components_page/components/accordion/simple.jl @@ -0,0 +1,54 @@ +using DashBootstrapComponents, DashCoreComponents, DashHtmlComponents + +accordion = html_div( + [ + html_div("Select an item", id="accordion-contents"), + dbc_accordion( + [ + dbc_accordionitem( + "This is the content of the first section", + title="Item 1", + ), + dbc_accordionitem( + "This is the content of the second section", + title="Item 2", + ), + dbc_accordionitem( + "This is the content of the third section", + title="Item 3", + ), + ], + id="accordion", + ), + html_div( + "Or set the open item dynamically using the slider below", + class_name="py-2", + ), + dcc_slider( + id="item-change", + min=0, + max=2, + step=1, + value=0, + marks=Dict(0 => "0", 1 => "1", 2 => "2"), + ), + ] +) + + +callback( + app, + Output("accordion-contents", "children"), + Input("accordion", "active_item"), +) do item + return item ? "Item selected: $item" : "Select an item" +end; + + +callback( + app, + Output("accordion", "active_item"), + Input("item-change", "value") +) do value + return "item-$value" +end; diff --git a/docs/components_page/components/accordion/simple.py b/docs/components_page/components/accordion/simple.py index 97086c96b..042fefccd 100644 --- a/docs/components_page/components/accordion/simple.py +++ b/docs/components_page/components/accordion/simple.py @@ -6,27 +6,27 @@ accordion = html.Div( [ html.Div("Select an item", id="accordion-contents"), - dbc.Container( - dbc.Accordion( - [ - dbc.AccordionItem( - "This is the content of the first section", - title="Item 1", - ), - dbc.AccordionItem( - "This is the content of the second section", - title="Item 2", - ), - dbc.AccordionItem( - "This is the content of the third section", - title="Item 3", - ), - ], - id="accordion", - ), - class_name="m-3", + dbc.Accordion( + [ + dbc.AccordionItem( + "This is the content of the first section", + title="Item 1", + ), + dbc.AccordionItem( + "This is the content of the second section", + title="Item 2", + ), + dbc.AccordionItem( + "This is the content of the third section", + title="Item 3", + ), + ], + id="accordion", + ), + html.Div( + "Or set the open item dynamically using the slider below", + class_name="py-2", ), - html.Div("Or set the open item dynamically using the slider below"), dcc.Slider( id="item-change", min=0, From 51cab18c04e7bfa197475fadd1b302c9e9206956 Mon Sep 17 00:00:00 2001 From: glsdown Date: Sun, 15 Aug 2021 20:11:52 +0100 Subject: [PATCH 4/6] Fixed h2 formatting issues --- src/components/accordion/Accordion.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/accordion/Accordion.js b/src/components/accordion/Accordion.js index 0a8ffc003..8371aa883 100644 --- a/src/components/accordion/Accordion.js +++ b/src/components/accordion/Accordion.js @@ -74,6 +74,9 @@ const Accordion = props => { onClick={() => { toggle(itemID); }} + // .dbcd-main h2 has margins defined on it - we need to make + // sure to overwrite them + style={{marginTop: '0rem', marginBottom: '0rem'}} > {title} From 8ddcae5af0b5e13054b18a606e7ac3ac9c0efc05 Mon Sep 17 00:00:00 2001 From: glsdown Date: Sun, 15 Aug 2021 20:12:30 +0100 Subject: [PATCH 5/6] Added accordion folder for flake8 --- setup.cfg | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.cfg b/setup.cfg index 78566eb81..a6214b353 100644 --- a/setup.cfg +++ b/setup.cfg @@ -2,6 +2,9 @@ exclude = node_modules, dash_bootstrap_components/_components, + docs/components_page/components/accordion/collapsed.py, + docs/components_page/components/accordion/flush.py, + docs/components_page/components/accordion/simple.py, docs/components_page/components/alert/auto_dismiss.py, docs/components_page/components/alert/dismiss.py, docs/components_page/components/button/usage.py, From 45397a802052552bad3b2954ba276207597d612a Mon Sep 17 00:00:00 2001 From: Tom Begley Date: Sun, 15 Aug 2021 21:29:47 +0100 Subject: [PATCH 6/6] Update demo/Demo.js Co-authored-by: glsdown <52132406+glsdown@users.noreply.github.com> --- demo/Demo.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/Demo.js b/demo/Demo.js index 43fe5fe88..1f1044464 100644 --- a/demo/Demo.js +++ b/demo/Demo.js @@ -110,7 +110,7 @@ const Demo = () => ( Entry 3 - +

Dash Bootstrap Components - Demo

This demonstrates all of the Dash Bootstrap Components as React