diff --git a/CHANGELOG.md b/CHANGELOG.md index f7d9bcd5..f99c91f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,11 +8,10 @@ - Added `InputWrapper` component #491 by @Godisemo - ### Fixed - fixed debounce on DatePickerInput that stopped working in 0.15.2 #496 by @AnnMarie - +- enable components to be used in `children` and `icon` in the `closeButtonProps` and `clearButtonProps`. #493 by @AnnMarieW # 0.15.2 diff --git a/src/ts/components/core/combobox/MultiSelect.tsx b/src/ts/components/core/combobox/MultiSelect.tsx index 3a6c11c8..20bc43f1 100644 --- a/src/ts/components/core/combobox/MultiSelect.tsx +++ b/src/ts/components/core/combobox/MultiSelect.tsx @@ -3,6 +3,7 @@ import { useDebouncedValue, useDidUpdate, useFocusWithin } from "@mantine/hooks" import { BoxProps } from "props/box"; import { ComboboxLikeProps } from "props/combobox"; import { DashBaseProps, PersistenceProps, DebounceProps } from "props/dash"; +import { __ClearButtonProps } from "props/button"; import { __BaseInputProps } from "props/input"; import { ScrollAreaProps } from "props/scrollarea"; import { StylesApiProps } from "props/styles"; @@ -36,7 +37,7 @@ interface Props /** Determines whether the clear button should be displayed in the right section when the component has value, `false` by default */ clearable?: boolean; /** Props passed down to the clear button */ - clearButtonProps?: object; + clearButtonProps?: __ClearButtonProps; /** Props passed down to the hidden input */ hiddenInputProps?: object; /** Divider used to separate values in the hidden input `value` attribute, `','` by default */ diff --git a/src/ts/components/core/combobox/Select.tsx b/src/ts/components/core/combobox/Select.tsx index c84f0c43..8849048c 100644 --- a/src/ts/components/core/combobox/Select.tsx +++ b/src/ts/components/core/combobox/Select.tsx @@ -3,6 +3,7 @@ import { useDebouncedValue, useDidUpdate } from "@mantine/hooks"; import { BoxProps } from "props/box"; import { ComboboxLikeProps } from "props/combobox"; import { DashBaseProps, PersistenceProps, DebounceProps } from "props/dash"; +import { __ClearButtonProps } from "props/button"; import { __BaseInputProps } from "props/input"; import { ScrollAreaProps } from "props/scrollarea"; import { StylesApiProps } from "props/styles"; @@ -34,7 +35,7 @@ interface Props /** Determines whether the clear button should be displayed in the right section when the component has value, `false` by default */ clearable?: boolean; /** Props passed down to the clear button */ - clearButtonProps?: object; + clearButtonProps?: __ClearButtonProps; /** Props passed down to the hidden input */ hiddenInputProps?: object; /** Props passed down to the underlying `ScrollArea` component in the dropdown */ diff --git a/src/ts/components/core/combobox/TagsInput.tsx b/src/ts/components/core/combobox/TagsInput.tsx index c4efc689..a8610463 100644 --- a/src/ts/components/core/combobox/TagsInput.tsx +++ b/src/ts/components/core/combobox/TagsInput.tsx @@ -6,6 +6,7 @@ import { useDidUpdate } from "@mantine/hooks"; import { BoxProps } from "props/box"; import { ComboboxLikeProps } from "props/combobox"; import { DashBaseProps, PersistenceProps } from "props/dash"; +import { __ClearButtonProps } from "props/button"; import { __BaseInputProps } from "props/input"; import { ScrollAreaProps } from "props/scrollarea"; import { StylesApiProps } from "props/styles"; @@ -34,7 +35,7 @@ interface Props /** Determines whether the clear button should be displayed in the right section when the component has value, `false` by default */ clearable?: boolean; /** Props passed down to the clear button */ - clearButtonProps?: object; + clearButtonProps?: __ClearButtonProps; /** Props passed down to the hidden input */ hiddenInputProps?: object; /** Divider used to separate values in the hidden input `value` attribute, `','` by default */ diff --git a/src/ts/components/dates/DateInput.tsx b/src/ts/components/dates/DateInput.tsx index fdc6f693..3ac20e54 100644 --- a/src/ts/components/dates/DateInput.tsx +++ b/src/ts/components/dates/DateInput.tsx @@ -8,6 +8,7 @@ import { MonthLevelSettings, YearLevelSettings, } from "props/dates"; +import { __ClearButtonProps } from "props/button"; import { __BaseInputProps } from "props/input"; import { PopoverProps } from "props/popover"; import { StylesApiProps } from "props/styles"; @@ -35,7 +36,7 @@ interface Props /** Determines whether input value can be cleared, adds clear button to right section, false by default */ clearable?: boolean; /** Props added to clear button */ - clearButtonProps?: object; + clearButtonProps?: __ClearButtonProps; /** Dayjs format to display input value, "MMMM D, YYYY" by default */ valueFormat?: string; /** Determines whether input value should be reverted to last known valid value on blur, true by default */ diff --git a/src/ts/props/button.ts b/src/ts/props/button.ts new file mode 100644 index 00000000..b2732d0c --- /dev/null +++ b/src/ts/props/button.ts @@ -0,0 +1,25 @@ +import { MantineRadius, MantineSize } from "@mantine/core"; +import React from "react"; + +export interface __BaseButtonProps { + /** Key of `theme.radius` or any valid CSS value to set border-radius. Numbers are converted to rem. `theme.defaultRadius` by default. */ + radius?: MantineRadius; + /** Sets `disabled` and `data-disabled` attributes on the button element */ + disabled?: boolean; + /** `X` icon `width` and `height`, `80%` by default */ + iconSize?: number | string; + /** Content rendered inside the button, for example `VisuallyHidden` with label for screen readers */ + children?: React.ReactNode; + /** Replaces default close icon. If set, `iconSize` prop is ignored. */ + icon?: React.ReactNode; +} + +export interface __CloseButtonProps extends __BaseButtonProps { + /** Controls width and height of the button. Numbers are converted to rem. `'md'` by default. */ + size?: MantineSize | (string & {}) | number; +} + +export interface __ClearButtonProps extends __BaseButtonProps { + /** Size of the button, by default value is based on input context */ + size?: MantineSize | (string & {}); +} \ No newline at end of file diff --git a/src/ts/props/dates.ts b/src/ts/props/dates.ts index 1caff3a7..9fe0bc9c 100644 --- a/src/ts/props/dates.ts +++ b/src/ts/props/dates.ts @@ -7,6 +7,7 @@ import { } from "@mantine/dates"; import { BoxProps } from "./box"; import { __BaseInputProps } from "./input"; +import { __ClearButtonProps } from "./button"; import { ModalProps } from "./modal"; import { PopoverProps } from "./popover"; import { StylesApiProps } from "./styles"; @@ -126,7 +127,7 @@ export interface DateInputSharedProps extends Omit<__BaseInputProps, "size"> { /** Determines whether input value can be cleared, adds clear button to right section, false by default */ clearable?: boolean; /** Props passed down to clear button */ - clearButtonProps?: object; + clearButtonProps?: __ClearButtonProps; /** Determines whether the user can modify the value */ readOnly?: boolean; /** Determines whether dates value should be sorted before onChange call, only applicable when type="multiple", true by default */ diff --git a/src/ts/props/modal.ts b/src/ts/props/modal.ts index 1b7e28ab..c9eec7b6 100644 --- a/src/ts/props/modal.ts +++ b/src/ts/props/modal.ts @@ -5,9 +5,11 @@ import { MantineSpacing, } from "@mantine/core"; import { BoxProps } from "./box"; +import { __CloseButtonProps } from "./button"; import { OverlayProps } from "./overlay"; import { TransitionProps } from "./transition"; + export interface ModalBaseProps extends BoxProps { /** If set modal/drawer will not be unmounted from the DOM when it is hidden, `display: none` styles will be added instead, `false` by default */ keepMounted?: boolean; @@ -50,6 +52,10 @@ export interface ModalBaseOverlayProps } +export interface ModalBaseCloseButtonProps + extends __CloseButtonProps, + BoxProps {} + export interface ModalProps extends ModalBaseProps { /** Modal title */ title?: React.ReactNode; @@ -62,7 +68,7 @@ export interface ModalProps extends ModalBaseProps { /** Determines whether the close button should be rendered, `true` by default */ withCloseButton?: boolean; /** Props passed down to the close button */ - closeButtonProps?: object; + closeButtonProps?: ModalBaseCloseButtonProps; /** Top/bottom modal offset, `5dvh` by default */ yOffset?: React.CSSProperties["marginTop"]; /** Left/right modal offset, `5vw` by default */ diff --git a/tests/dates/test_date_input.py b/tests/dates/test_date_input.py index 93930d01..9dc9247f 100644 --- a/tests/dates/test_date_input.py +++ b/tests/dates/test_date_input.py @@ -24,6 +24,17 @@ debounce=2000, ), dmc.Box(id="out-2000"), + + # ensure clearButton children and icon can render with components without error + dmc.DateInput( + id="date-input-clearable", + value="2025-01-01", + clearable=True, + clearButtonProps = { + "children": html.Div("x", id="id1"), + "icon": html.Div("y", id="id2"), + } + ) ] ) diff --git a/tests/dates/test_date_picker.py b/tests/dates/test_date_picker.py index 93e956fa..a181d468 100644 --- a/tests/dates/test_date_picker.py +++ b/tests/dates/test_date_picker.py @@ -40,6 +40,16 @@ def make_app(**kwargs): maxDate="2024-10-31", **kwargs ), + # ensure clearButton children and icon can render with components without error + dmc.DatePickerInput( + id="date-picker-input-clearable", + value="2025-01-01", + clearable=True, + clearButtonProps={ + "children": html.Div("x", id="id1"), + "icon": html.Div("y", id="id2"), + } + ) ] ) diff --git a/tests/test_modal.py b/tests/test_modal.py new file mode 100644 index 00000000..a2c9bd2e --- /dev/null +++ b/tests/test_modal.py @@ -0,0 +1,50 @@ +from dash import Dash, html, Output, Input, State, _dash_renderer +import dash_mantine_components as dmc + +_dash_renderer._set_react_version("18.2.0") + + +def test_001mo_modal(dash_duo): + app = Dash(__name__) + + component = html.Div( + [ + dmc.Button("Open Modal", id="modal-demo-button"), + dmc.Modal( + title="New Modal", + id="modal-simple", + closeButtonProps={ + "children": html.Div(" close", id="my-component"), + "icon": html.Div("x", id="modal-custom-close"), + }, + children=[ + dmc.Text("I am in a modal component."), + ], + ), + ] + ) + + app.layout = dmc.MantineProvider( + component + ) + + @app.callback( + Output("modal-simple", "opened"), + Input("modal-demo-button", "n_clicks"), + State("modal-simple", "opened"), + prevent_initial_call=True, + ) + def modal_demo(_, opened): + return not opened + + dash_duo.start_server(app) + + # Open modal + modal_btn = dash_duo.find_element("#modal-demo-button") + modal_btn.click() + + # Close modal + modal_close_btn = dash_duo.find_element("#modal-custom-close") + modal_close_btn.click() + + assert dash_duo.get_logs() == []