Skip to content
Closed

Dash 3 #1074

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
{
"presets": ["@babel/preset-env", "@babel/preset-react"],
"plugins": [
"@babel/plugin-transform-object-rest-spread",
"@babel/plugin-transform-runtime"
],
"plugins": ["@babel/plugin-transform-runtime"],
"env": {
"test": {
"plugins": ["@babel/plugin-transform-class-properties"]
Expand Down
4 changes: 2 additions & 2 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
dash>=2.0.0
dash_bootstrap_components==ci-fixes
dash==3.0.0rc1
dash_bootstrap_components==1.7.1-dev
gunicorn
markdown
pandas
Expand Down
2 changes: 1 addition & 1 deletion justfile
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ deploy-docs: _copy-examples
git branch -D just-push-docs docs-deploy

_build-py: && _move-generated-files _build-package
uv run dash-generate-components ./src/components dash_bootstrap_components
uv run dash-generate-components ./src/components dash_bootstrap_components -i "^_|__tests__"
cp dash_bootstrap_components/_components/dash_bootstrap_components.min.js dist

_build-package:
Expand Down
13,512 changes: 5,333 additions & 8,179 deletions package-lock.json

Large diffs are not rendered by default.

61 changes: 29 additions & 32 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,44 +28,41 @@
},
"homepage": "https://dash-bootstrap-components.opensource.faculty.ai",
"license": "Apache-2.0",
"devDependencies": {
"@babel/core": "^7.15.0",
"@babel/plugin-transform-class-properties": "^7.24.1",
"@babel/plugin-transform-object-rest-spread": "^7.24.1",
"@babel/plugin-transform-runtime": "^7.15.0",
"@babel/preset-env": "^7.15.0",
"@babel/preset-react": "^7.14.5",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^12.1.1",
"@testing-library/user-event": "^13.2.1",
"babel-jest": "^27.2.4",
"babel-loader": "^8.1.0",
"css-loader": "^6.6.0",
"jest": "^27.2.4",
"jsdom": "^17.0.0",
"npm-run-all": "^4.1.5",
"prettier": "^3.4.2",
"react-docgen": "^4.1.1",
"style-loader": "^0.23.1",
"webpack": "^5.68.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.7.4"
},
"dependencies": {
"@plotly/dash-component-plugins": "^1.2.0",
"classnames": "^2.2.6",
"fast-isnumeric": "^1.1.3",
"is-absolute-url": "^2.1.0",
"prop-types": "^15.7.2",
"ramda": "^0.27.1",
"react": "^16.14.0",
"react-bootstrap": "^2.2.2",
"react-dom": "^16.14.0"
"@plotly/dash-component-plugins": "^1.2.3",
"classnames": "^2.5.1",
"fast-isnumeric": "^1.1.4",
"prop-types": "^15.8.1",
"ramda": "^0.30.1",
"react": "^18.3.1",
"react-bootstrap": "^2.10.9",
"react-dom": "^18.3.1"
},
"jest": {
"testEnvironment": "jsdom",
"setupFilesAfterEnv": [
"<rootDir>/src/setupTests.js"
]
},
"devDependencies": {
"@babel/core": "^7.26.7",
"@babel/plugin-transform-runtime": "^7.25.9",
"@babel/preset-env": "^7.26.7",
"@babel/preset-react": "^7.26.3",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.2.0",
"@testing-library/user-event": "^14.6.1",
"babel-jest": "^29.7.0",
"babel-loader": "^9.2.1",
"css-loader": "^7.1.2",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"prettier": "^3.4.2",
"react-docgen": "^5.4.3",
"style-loader": "^4.0.0",
"webpack": "^5.97.1",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.2.0"
}
}
4 changes: 3 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ authors = [
]
maintainers = [{ name = "Tom Begley", email = "[email protected]" }]
requires-python = ">=3.9, <4"
dependencies = ["dash>=2.0.0"]
dependencies = [
"dash==3.0.0rc1",
]
classifiers = [
"Framework :: Dash",
"License :: OSI Approved :: Apache Software License",
Expand Down
10 changes: 4 additions & 6 deletions src/components/accordion/Accordion.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ const Accordion = props => {
let {
children,
active_item,
always_open,
start_collapsed,
loading_state,
key,
setProps,
class_name,
className,
always_open = false,
start_collapsed = false,
...otherProps
} = props;
children = parseChildrenToArray(children);
Expand Down Expand Up @@ -87,11 +87,9 @@ const Accordion = props => {
);
};

Accordion.defaultProps = {
Accordion.dashPersistence = {
persisted_props: ['active_item'],
persistence_type: 'local',
start_collapsed: false,
always_open: false
persistence_type: 'local'
};

Accordion.propTypes = {
Expand Down
6 changes: 1 addition & 5 deletions src/components/accordion/AccordionItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,7 @@ const AccordionItem = ({
(loading_state && loading_state.is_loading) || undefined
}
>
<RBAccordion.Header
onClick={() => {
toggle(itemID);
}}
>
<RBAccordion.Header onClick={() => toggle(itemID)}>
{title}
</RBAccordion.Header>
<RBAccordion.Body>{children}</RBAccordion.Body>
Expand Down
64 changes: 28 additions & 36 deletions src/components/accordion/__tests__/Accordion.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*/

import React from 'react';
import {render} from '@testing-library/react';
import {act, render, screen, waitFor} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import Accordion from '../Accordion';
import AccordionItem from '../AccordionItem';
Expand Down Expand Up @@ -91,7 +91,8 @@ describe('Accordion', () => {
).not.toHaveClass('show');
});

test('tracks most recently clicked item with "active_item" prop', () => {
test('tracks most recently clicked item with "active_item" prop', async () => {
const user = userEvent.setup({advanceTimers: jest.advanceTimersByTime});
const mockSetProps = jest.fn();
const {container, rerender} = render(
<Accordion setProps={mockSetProps} active_item="item-0">
Expand All @@ -109,9 +110,7 @@ describe('Accordion', () => {
accordionItems.children[1].querySelector('div.accordion-collapse')
).not.toHaveClass('show');

userEvent.click(
accordionItems.children[1].querySelector('h2.accordion-header > button')
);
await user.click(await screen.findByText('item-title-2'));
expect(mockSetProps.mock.calls).toHaveLength(1);

rerender(
Expand All @@ -120,7 +119,7 @@ describe('Accordion', () => {
<AccordionItem title="item-title-2">item-content-2</AccordionItem>
</Accordion>
);
jest.runAllTimers();
act(() => jest.runAllTimers());

expect(
accordionItems.children[0].querySelector('div.accordion-collapse')
Expand All @@ -130,9 +129,7 @@ describe('Accordion', () => {
).toHaveClass('show');

// clicking on an open item closes it
userEvent.click(
accordionItems.children[1].querySelector('h2.accordion-header > button')
);
await user.click(await screen.findByText('item-title-2'));
expect(mockSetProps.mock.calls).toHaveLength(2);

rerender(
Expand All @@ -141,7 +138,7 @@ describe('Accordion', () => {
<AccordionItem title="item-title-2">item-content-2</AccordionItem>
</Accordion>
);
jest.runAllTimers();
act(() => jest.runAllTimers());

expect(
accordionItems.children[0].querySelector('div.accordion-collapse')
Expand All @@ -151,7 +148,8 @@ describe('Accordion', () => {
).not.toHaveClass('show');
});

test('keeps item open with "always_open" prop', () => {
test('keeps item open with "always_open" prop', async () => {
const user = userEvent.setup({advanceTimers: jest.advanceTimersByTime});
const mockSetProps = jest.fn();

const {container} = render(
Expand All @@ -172,34 +170,31 @@ describe('Accordion', () => {
).not.toHaveClass('show');

// Click on the second item
userEvent.click(
accordionItems.children[1].querySelector('h2.accordion-header > button')
);
await user.click(await screen.findByText('item-title-2'));
expect(mockSetProps.mock.calls).toHaveLength(1);

// Allow the click to take effect
jest.runAllTimers();
// wait for transition to complete
await waitFor(() =>
expect(
accordionItems.children[1].querySelector('div.accordion-collapse')
).toHaveClass('show')
);

// Check just the second item is open
expect(
accordionItems.children[0].querySelector('div.accordion-collapse')
).not.toHaveClass('show');
expect(
accordionItems.children[1].querySelector('div.accordion-collapse')
).toHaveClass('show');

// Click on the first item
userEvent.click(
accordionItems.children[0].querySelector('h2.accordion-header > button')
);
await user.click(await screen.findByText('item-title-1'));
expect(mockSetProps.mock.calls).toHaveLength(2);
// Allow the click to take effect
jest.runAllTimers();

// Check that the first child is now open, and the second remains open
expect(
accordionItems.children[0].querySelector('div.accordion-collapse')
).toHaveClass('show');
await waitFor(() =>
expect(
accordionItems.children[0].querySelector('div.accordion-collapse')
).toHaveClass('show')
);
expect(
accordionItems.children[1].querySelector('div.accordion-collapse')
).toHaveClass('show');
Expand All @@ -224,7 +219,8 @@ describe('Accordion', () => {
).toHaveClass('show');
});

test('tracks most recently clicked item with "active_item" prop when always_open', () => {
test('tracks most recently clicked item with "active_item" prop when always_open', async () => {
const user = userEvent.setup({advanceTimers: jest.advanceTimersByTime});
const mockSetProps = jest.fn();
const {container, rerender} = render(
<Accordion setProps={mockSetProps} active_item={['item-0']} always_open>
Expand All @@ -248,9 +244,7 @@ describe('Accordion', () => {
).not.toHaveClass('show');

// Click the middle option
userEvent.click(
accordionItems.children[1].querySelector('h2.accordion-header > button')
);
await user.click(await screen.getByText('item-title-2'));
expect(mockSetProps.mock.calls).toHaveLength(1);

rerender(
Expand All @@ -264,7 +258,7 @@ describe('Accordion', () => {
<AccordionItem title="item-title-3">item-content-3</AccordionItem>
</Accordion>
);
jest.runAllTimers();
act(() => jest.runAllTimers());

// Check first option stayed open, middle option now open but third still
// closed
Expand All @@ -279,9 +273,7 @@ describe('Accordion', () => {
).not.toHaveClass('show');

// clicking on 1st item closes it, but keeps second item open and 3rd closed
userEvent.click(
accordionItems.children[0].querySelector('h2.accordion-header > button')
);
await user.click(await screen.getByText('item-title-1'));
expect(mockSetProps.mock.calls).toHaveLength(2);

rerender(
Expand All @@ -295,7 +287,7 @@ describe('Accordion', () => {
<AccordionItem title="item-title-3">item-content-3</AccordionItem>
</Accordion>
);
jest.runAllTimers();
act(() => jest.runAllTimers());

// Check that 1 and 3 now closed, and 2 is open
expect(
Expand Down
35 changes: 15 additions & 20 deletions src/components/alert/Alert.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,20 @@ import {bootstrapColors} from '../../private/BootstrapColors';
* Control the visibility using callbacks with the `is_open` prop, or set it to
* auto-dismiss with the `duration` prop.
*/
const Alert = props => {
const {
children,
dismissable,
duration,
is_open,
loading_state,
setProps,
color,
style,
class_name,
className,
fade,
...otherProps
} = props;

const Alert = ({
children,
dismissable,
loading_state,
setProps,
style,
class_name,
className,
fade,
color = 'success',
is_open = true,
duration = null,
...otherProps
}) => {
const timeout = useRef(null);

useEffect(() => {
Expand Down Expand Up @@ -69,10 +67,7 @@ const Alert = props => {
);
};

Alert.defaultProps = {
color: 'success',
is_open: true,
duration: null,
Alert.dashPersistence = {
persisted_props: ['is_open'],
persistence_type: 'local'
};
Expand Down
Loading