From 5f0cd455c8e041d8c75ffcf82ba1685022aba158 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic <4390250+arminmeh@users.noreply.github.com> Date: Fri, 3 Jan 2025 14:12:01 +0100 Subject: [PATCH 01/25] [DataGrid] Fix number filter field formatting values while typing (#16062) --- .../headerFiltering/GridHeaderFilterCell.tsx | 8 ++- .../src/tests/filtering.DataGridPro.test.tsx | 55 +++++++++++++++++-- .../filterPanel/GridFilterInputValue.tsx | 22 ++++---- 3 files changed, 67 insertions(+), 18 deletions(-) diff --git a/packages/x-data-grid-pro/src/components/headerFiltering/GridHeaderFilterCell.tsx b/packages/x-data-grid-pro/src/components/headerFiltering/GridHeaderFilterCell.tsx index 1d40414b972ec..657e2effad511 100644 --- a/packages/x-data-grid-pro/src/components/headerFiltering/GridHeaderFilterCell.tsx +++ b/packages/x-data-grid-pro/src/components/headerFiltering/GridHeaderFilterCell.tsx @@ -89,7 +89,7 @@ const useUtilityClasses = (ownerState: OwnerState) => { return composeClasses(slots, getDataGridUtilityClass, classes); }; -const dateSx = { +const emptyFieldSx = { [`& input[value=""]:not(:focus)`]: { color: 'transparent' }, }; const defaultInputComponents: { [key in GridColType]: React.JSXElementConstructor | null } = { @@ -366,7 +366,11 @@ const GridHeaderFilterCell = forwardRef - Filter', () => { expect(getRows({ operator: 'is', value: null })).to.deep.equal(ALL_ROWS); expect(getRows({ operator: 'is', value: 'test' })).to.deep.equal(ALL_ROWS); // Ignores invalid values }); + + it('should allow temporary invalid values while updating the number filter', async () => { + clock.restore(); + const changeSpy = spy(); + const { user } = render( + , + ); + expect(getColumnValues(0)).to.deep.equal(['-10', '10', '100', '1,000']); + + const filterCell = getColumnHeaderCell(0, 1); + await user.click(within(filterCell).getByLabelText('Operator')); + await user.click(screen.getByRole('menuitem', { name: 'Greater than' })); + + const input = within(filterCell).getByLabelText('Greater than'); + await user.click(input); + expect(input).toHaveFocus(); + + await user.keyboard('0'); + await waitFor(() => expect(getColumnValues(0)).to.deep.equal(['10', '100', '1,000'])); + expect(changeSpy.lastCall.args[0].items[0].value).to.equal(0); + + await user.keyboard('.'); + await waitFor(() => expect(getColumnValues(0)).to.deep.equal(['10', '100', '1,000'])); + expect(changeSpy.lastCall.args[0].items[0].value).to.equal(0); // 0. + + await user.keyboard('1'); + await waitFor(() => expect(getColumnValues(0)).to.deep.equal(['10', '100', '1,000'])); + await waitFor(() => expect(changeSpy.lastCall.args[0].items[0].value).to.equal(0.1)); // 0.1 + + await user.keyboard('e'); + await waitFor(() => expect(getColumnValues(0)).to.deep.equal(['-10', '10', '100', '1,000'])); + expect(changeSpy.lastCall.args[0].items[0].value).to.equal(undefined); // 0.1e + + await user.keyboard('2'); + await waitFor(() => expect(getColumnValues(0)).to.deep.equal(['100', '1,000'])); + expect(changeSpy.lastCall.args[0].items[0].value).to.equal(10); // 0.1e2 + }); }); describe('Read-only filters', () => { diff --git a/packages/x-data-grid/src/components/panel/filterPanel/GridFilterInputValue.tsx b/packages/x-data-grid/src/components/panel/filterPanel/GridFilterInputValue.tsx index 32d76d2516114..826e0cef68a4f 100644 --- a/packages/x-data-grid/src/components/panel/filterPanel/GridFilterInputValue.tsx +++ b/packages/x-data-grid/src/components/panel/filterPanel/GridFilterInputValue.tsx @@ -37,8 +37,8 @@ function GridFilterInputValue(props: GridTypeFilterInputValueProps) { } = props; const filterTimeout = useTimeout(); - const [filterValueState, setFilterValueState] = React.useState( - sanitizeFilterItemValue(item.value, type), + const [filterValueState, setFilterValueState] = React.useState( + sanitizeFilterItemValue(item.value), ); const [applying, setIsApplying] = React.useState(false); const id = useId(); @@ -46,14 +46,14 @@ function GridFilterInputValue(props: GridTypeFilterInputValueProps) { const onFilterChange = React.useCallback( (event: React.ChangeEvent) => { - const value = sanitizeFilterItemValue(event.target.value, type); - setFilterValueState(value); + const value = sanitizeFilterItemValue(event.target.value); + setFilterValueState(value); setIsApplying(true); filterTimeout.start(rootProps.filterDebounceMs, () => { const newItem = { ...item, - value, + value: type === 'number' && !Number.isNaN(Number(value)) ? Number(value) : value, fromInput: id!, }; applyValue(newItem); @@ -66,16 +66,16 @@ function GridFilterInputValue(props: GridTypeFilterInputValueProps) { React.useEffect(() => { const itemPlusTag = item as ItemPlusTag; if (itemPlusTag.fromInput !== id || item.value == null) { - setFilterValueState(sanitizeFilterItemValue(item.value, type)); + setFilterValueState(sanitizeFilterItemValue(item.value)); } - }, [id, item, type]); + }, [id, item]); return ( Date: Fri, 3 Jan 2025 15:37:59 +0200 Subject: [PATCH 02/25] [pickers] Update `closeOnSelect` and `actionBar.actions` default values (#15944) Signed-off-by: Lukas Tyla Co-authored-by: Arthur Balduini Co-authored-by: arthurbalduini --- docs/data/date-pickers/lifecycle/lifecycle.md | 22 +++++++++------ .../migration-pickers-v7.md | 9 ++++++ .../x/api/date-pickers/date-time-picker.json | 5 +--- .../date-pickers/date-time-range-picker.json | 5 +--- .../api/date-pickers/desktop-date-picker.json | 5 +--- .../desktop-date-range-picker.json | 5 +--- .../desktop-date-time-picker.json | 5 +--- .../desktop-date-time-range-picker.json | 5 +--- .../api/date-pickers/desktop-time-picker.json | 5 +--- .../api/date-pickers/mobile-date-picker.json | 5 +--- .../mobile-date-range-picker.json | 5 +--- .../date-pickers/mobile-date-time-picker.json | 5 +--- .../mobile-date-time-range-picker.json | 5 +--- .../api/date-pickers/mobile-time-picker.json | 5 +--- .../api/date-pickers/pickers-action-bar.json | 2 +- .../pages/x/api/date-pickers/time-picker.json | 5 +--- .../date-pickers/date-picker/date-picker.json | 2 +- .../date-range-picker/date-range-picker.json | 2 +- .../date-time-picker/date-time-picker.json | 2 +- .../date-time-range-picker.json | 2 +- .../desktop-date-picker.json | 2 +- .../desktop-date-range-picker.json | 2 +- .../desktop-date-time-picker.json | 2 +- .../desktop-date-time-range-picker.json | 2 +- .../desktop-time-picker.json | 2 +- .../mobile-date-picker.json | 2 +- .../mobile-date-range-picker.json | 2 +- .../mobile-date-time-picker.json | 2 +- .../mobile-date-time-range-picker.json | 2 +- .../mobile-time-picker.json | 2 +- .../date-pickers/time-picker/time-picker.json | 2 +- .../src/DateRangePicker/DateRangePicker.tsx | 2 +- .../DateRangePicker/DateRangePicker.types.ts | 5 ++++ .../DateTimeRangePicker.tsx | 4 +-- .../DesktopDateRangePicker.tsx | 13 +++++++-- .../DesktopDateRangePicker.types.ts | 5 ++++ .../DesktopDateTimeRangePicker.tsx | 12 ++------ .../MobileDateRangePicker.tsx | 4 +-- .../MobileDateTimeRangePicker.tsx | 4 +-- .../src/DatePicker/DatePicker.tsx | 2 +- .../src/DatePicker/DatePicker.types.ts | 5 ++++ .../src/DateTimePicker/DateTimePicker.tsx | 4 +-- .../DesktopDatePicker/DesktopDatePicker.tsx | 13 +++++++-- .../DesktopDatePicker.types.ts | 5 ++++ .../DesktopDateTimePicker.tsx | 13 ++------- .../tests/DesktopDateTimePicker.test.tsx | 20 +++++++++++++ .../DesktopTimePicker/DesktopTimePicker.tsx | 12 ++------ .../tests/DesktopTimePicker.test.tsx | 28 ++++++++++++++++--- .../src/MobileDatePicker/MobileDatePicker.tsx | 4 +-- .../MobileDateTimePicker.tsx | 4 +-- .../src/MobileTimePicker/MobileTimePicker.tsx | 4 +-- .../src/PickersActionBar/PickersActionBar.tsx | 8 ++++-- .../src/PickersLayout/usePickerLayout.tsx | 4 +-- .../src/TimePicker/TimePicker.tsx | 4 +-- .../internals/hooks/usePicker/usePicker.ts | 1 - .../hooks/usePicker/usePicker.types.ts | 7 +++-- .../hooks/usePicker/usePickerValue.ts | 3 +- .../hooks/usePicker/usePickerValue.types.ts | 6 ++-- test/e2e/index.test.ts | 14 +++++++--- .../testPickerOpenCloseLifeCycle.tsx | 10 +++++-- 60 files changed, 195 insertions(+), 153 deletions(-) diff --git a/docs/data/date-pickers/lifecycle/lifecycle.md b/docs/data/date-pickers/lifecycle/lifecycle.md index 4d4bf1bc62ecf..2b57bc1d3b822 100644 --- a/docs/data/date-pickers/lifecycle/lifecycle.md +++ b/docs/data/date-pickers/lifecycle/lifecycle.md @@ -51,9 +51,12 @@ In all the below scenarios, the picker closes when `onClose` is called, except i #### When the last view is completed When a selection in the last view is made, `onClose` will be called only if the `closeOnSelect` prop is equal to `true`. -By default, it is set to `true` on desktop and `false` on mobile. +The default value of `closeOnSelect` depends on the component: -Here are a few examples: +- Date Picker and Date Range Picker: `true` on desktop and `false` on mobile variants; +- Time Picker, Date Time Picker, and Date Time Range Picker: `false` on desktop and mobile variants. + + Here are a few examples: :::info The examples below are using the desktop and mobile variants of the pickers, but the behavior is exactly the same when using the responsive variant (`DatePicker`, `TimePicker`, ...) on a mobile or desktop environment. @@ -75,7 +78,7 @@ The examples below are using the desktop and mobile variants of the pickers, but - Default `views` prop: `['year', 'day']` - Explicit `closeOnSelect` prop: `false` - **Behavior:** The picker won't close when selecting a day. The user will have to click on the _OK_ action to close it. + **Behavior:** The picker will not close when selecting a day. The user will have to click on the _OK_ action to close it. :::success If you want to set `closeOnSelect` to `false` on a desktop picker, you should consider enabling the action bar to allow the user to validate the value: @@ -96,7 +99,7 @@ The examples below are using the desktop and mobile variants of the pickers, but - Default `views` prop: `['year', 'day']` - Default `closeOnSelect` prop: `false` - **Behavior:** The picker won't close when selecting a day. The user will have to click on the _OK_ action to close it. + **Behavior:** The picker will not close when selecting a day. The user will have to click on the _OK_ action to close it. - ```tsx @@ -112,9 +115,9 @@ The examples below are using the desktop and mobile variants of the pickers, but ``` - Default `views` prop: `['hours', 'minutes']` (plus a `meridiem` view if the locale is in 12-hours format) - - Default `closeOnSelect` prop: `true` + - Default `closeOnSelect` prop: `false` - **Behavior:** The picker will close when selecting the minutes or meridiem (if a 12-hour clock is used). + **Behavior:** The picker will not close when selecting the minutes or meridiem (if a 12-hour clock is used). :::info You don't have to fill all the views for the picker to close automatically. @@ -225,7 +228,10 @@ You can use the second argument passed to the `onAccept` callback to get the val #### When the last view is completed When a selection in the last view is made, `onAccept` will be called only if the `closeOnSelect` prop is equal to `true` and the value has been modified since the last time `onAccept` was called. -By default, `closeOnSelect`, is set to `true` on desktop and `false` on mobile. +The default value of `closeOnSelect` depends on the component used: + +- Date Picker and Date Range Picker: `true` on desktop and `false` on mobile variants; +- Time Picker, Date Time Picker, and Date Time Range Picker: `false` on desktop and mobile variants. Here are a few examples: @@ -249,7 +255,7 @@ The examples below are using the desktop and mobile variants of the pickers, but - Default `views` prop: `['year', 'day']` - Explicit `closeOnSelect` prop: `false` - **Behavior:** The picker won't call `onAccept` when selecting a value. + **Behavior:** The picker will not call `onAccept` when selecting a value. :::success If you want to set `closeOnSelect` to `false` on a desktop picker, you should consider enabling the action bar to allow the user to validate the value: diff --git a/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md b/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md index 1e51554e6311c..5c6bdf2033eb2 100644 --- a/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md +++ b/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md @@ -344,6 +344,15 @@ This change causes a few breaking changes: - The button to render a single year is no longer wrapped in a `
`, the spacing are instead defined inside the `root` slot of the Year Calendar. +### Update default `closeOnSelect` and Action Bar `actions` values + +The default value of the `closeOnSelect` prop has been updated to `false` for all Picker components, except `` and ``, which still have `closeOnSelect` set to `true`. + +This change goes hand in hand with the new default `actions` prop value for the `` component. +The default value of the `actions` prop has been updated to `['cancel', 'accept']` for all Picker components, except `` and ``. + +If the updated values do not fit your use case, you can [override them](/x/react-date-pickers/custom-components/#component-props). + ## Slots breaking changes ### Slot: `layout` diff --git a/docs/pages/x/api/date-pickers/date-time-picker.json b/docs/pages/x/api/date-pickers/date-time-picker.json index b2443301cad98..4f43b0337b63c 100644 --- a/docs/pages/x/api/date-pickers/date-time-picker.json +++ b/docs/pages/x/api/date-pickers/date-time-picker.json @@ -3,10 +3,7 @@ "ampm": { "type": { "name": "bool" }, "default": "utils.is12HourCycleInCurrentLocale()" }, "ampmInClock": { "type": { "name": "bool" }, "default": "true on desktop, false on mobile" }, "autoFocus": { "type": { "name": "bool" } }, - "closeOnSelect": { - "type": { "name": "bool" }, - "default": "`true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop)." - }, + "closeOnSelect": { "type": { "name": "bool" }, "default": "false" }, "dayOfWeekFormatter": { "type": { "name": "func" }, "default": "(date: PickerValidDate) => adapter.format(date, 'weekdayShort').charAt(0).toUpperCase()", diff --git a/docs/pages/x/api/date-pickers/date-time-range-picker.json b/docs/pages/x/api/date-pickers/date-time-range-picker.json index add2fd7dede45..7487f6b6418ea 100644 --- a/docs/pages/x/api/date-pickers/date-time-range-picker.json +++ b/docs/pages/x/api/date-pickers/date-time-range-picker.json @@ -6,10 +6,7 @@ "type": { "name": "enum", "description": "1
| 2
| 3" }, "default": "1" }, - "closeOnSelect": { - "type": { "name": "bool" }, - "default": "`true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop)." - }, + "closeOnSelect": { "type": { "name": "bool" }, "default": "false" }, "currentMonthCalendarPosition": { "type": { "name": "enum", "description": "1
| 2
| 3" }, "default": "1" diff --git a/docs/pages/x/api/date-pickers/desktop-date-picker.json b/docs/pages/x/api/date-pickers/desktop-date-picker.json index 1418cf907e00a..22c0208dbcf29 100644 --- a/docs/pages/x/api/date-pickers/desktop-date-picker.json +++ b/docs/pages/x/api/date-pickers/desktop-date-picker.json @@ -1,10 +1,7 @@ { "props": { "autoFocus": { "type": { "name": "bool" } }, - "closeOnSelect": { - "type": { "name": "bool" }, - "default": "`true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop)." - }, + "closeOnSelect": { "type": { "name": "bool" }, "default": "true" }, "dayOfWeekFormatter": { "type": { "name": "func" }, "default": "(date: PickerValidDate) => adapter.format(date, 'weekdayShort').charAt(0).toUpperCase()", diff --git a/docs/pages/x/api/date-pickers/desktop-date-range-picker.json b/docs/pages/x/api/date-pickers/desktop-date-range-picker.json index 23fd6ab658165..76ac2bcbf93d6 100644 --- a/docs/pages/x/api/date-pickers/desktop-date-range-picker.json +++ b/docs/pages/x/api/date-pickers/desktop-date-range-picker.json @@ -5,10 +5,7 @@ "type": { "name": "enum", "description": "1
| 2
| 3" }, "default": "2" }, - "closeOnSelect": { - "type": { "name": "bool" }, - "default": "`true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop)." - }, + "closeOnSelect": { "type": { "name": "bool" }, "default": "true" }, "currentMonthCalendarPosition": { "type": { "name": "enum", "description": "1
| 2
| 3" }, "default": "1" diff --git a/docs/pages/x/api/date-pickers/desktop-date-time-picker.json b/docs/pages/x/api/date-pickers/desktop-date-time-picker.json index 98a3cad44b438..2b4133cb7a1ba 100644 --- a/docs/pages/x/api/date-pickers/desktop-date-time-picker.json +++ b/docs/pages/x/api/date-pickers/desktop-date-time-picker.json @@ -3,10 +3,7 @@ "ampm": { "type": { "name": "bool" }, "default": "utils.is12HourCycleInCurrentLocale()" }, "ampmInClock": { "type": { "name": "bool" }, "default": "true on desktop, false on mobile" }, "autoFocus": { "type": { "name": "bool" } }, - "closeOnSelect": { - "type": { "name": "bool" }, - "default": "`true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop)." - }, + "closeOnSelect": { "type": { "name": "bool" }, "default": "false" }, "dayOfWeekFormatter": { "type": { "name": "func" }, "default": "(date: PickerValidDate) => adapter.format(date, 'weekdayShort').charAt(0).toUpperCase()", diff --git a/docs/pages/x/api/date-pickers/desktop-date-time-range-picker.json b/docs/pages/x/api/date-pickers/desktop-date-time-range-picker.json index 6706455ebb5b6..0dfa110d2cff3 100644 --- a/docs/pages/x/api/date-pickers/desktop-date-time-range-picker.json +++ b/docs/pages/x/api/date-pickers/desktop-date-time-range-picker.json @@ -6,10 +6,7 @@ "type": { "name": "enum", "description": "1
| 2
| 3" }, "default": "1" }, - "closeOnSelect": { - "type": { "name": "bool" }, - "default": "`true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop)." - }, + "closeOnSelect": { "type": { "name": "bool" }, "default": "false" }, "currentMonthCalendarPosition": { "type": { "name": "enum", "description": "1
| 2
| 3" }, "default": "1" diff --git a/docs/pages/x/api/date-pickers/desktop-time-picker.json b/docs/pages/x/api/date-pickers/desktop-time-picker.json index d372b04bdfc0f..828c2fe408438 100644 --- a/docs/pages/x/api/date-pickers/desktop-time-picker.json +++ b/docs/pages/x/api/date-pickers/desktop-time-picker.json @@ -3,10 +3,7 @@ "ampm": { "type": { "name": "bool" }, "default": "utils.is12HourCycleInCurrentLocale()" }, "ampmInClock": { "type": { "name": "bool" }, "default": "true on desktop, false on mobile" }, "autoFocus": { "type": { "name": "bool" } }, - "closeOnSelect": { - "type": { "name": "bool" }, - "default": "`true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop)." - }, + "closeOnSelect": { "type": { "name": "bool" }, "default": "false" }, "defaultValue": { "type": { "name": "object" } }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableFuture": { "type": { "name": "bool" }, "default": "false" }, diff --git a/docs/pages/x/api/date-pickers/mobile-date-picker.json b/docs/pages/x/api/date-pickers/mobile-date-picker.json index 37e3b9e9be0b8..840d432dd53a4 100644 --- a/docs/pages/x/api/date-pickers/mobile-date-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-date-picker.json @@ -1,10 +1,7 @@ { "props": { "autoFocus": { "type": { "name": "bool" } }, - "closeOnSelect": { - "type": { "name": "bool" }, - "default": "`true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop)." - }, + "closeOnSelect": { "type": { "name": "bool" }, "default": "false" }, "dayOfWeekFormatter": { "type": { "name": "func" }, "default": "(date: PickerValidDate) => adapter.format(date, 'weekdayShort').charAt(0).toUpperCase()", diff --git a/docs/pages/x/api/date-pickers/mobile-date-range-picker.json b/docs/pages/x/api/date-pickers/mobile-date-range-picker.json index 82670cc2d753e..572302ff32749 100644 --- a/docs/pages/x/api/date-pickers/mobile-date-range-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-date-range-picker.json @@ -1,10 +1,7 @@ { "props": { "autoFocus": { "type": { "name": "bool" } }, - "closeOnSelect": { - "type": { "name": "bool" }, - "default": "`true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop)." - }, + "closeOnSelect": { "type": { "name": "bool" }, "default": "false" }, "currentMonthCalendarPosition": { "type": { "name": "enum", "description": "1
| 2
| 3" }, "default": "1" diff --git a/docs/pages/x/api/date-pickers/mobile-date-time-picker.json b/docs/pages/x/api/date-pickers/mobile-date-time-picker.json index 23adb960d841c..bfc1d0d67b717 100644 --- a/docs/pages/x/api/date-pickers/mobile-date-time-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-date-time-picker.json @@ -3,10 +3,7 @@ "ampm": { "type": { "name": "bool" }, "default": "utils.is12HourCycleInCurrentLocale()" }, "ampmInClock": { "type": { "name": "bool" }, "default": "true on desktop, false on mobile" }, "autoFocus": { "type": { "name": "bool" } }, - "closeOnSelect": { - "type": { "name": "bool" }, - "default": "`true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop)." - }, + "closeOnSelect": { "type": { "name": "bool" }, "default": "false" }, "dayOfWeekFormatter": { "type": { "name": "func" }, "default": "(date: PickerValidDate) => adapter.format(date, 'weekdayShort').charAt(0).toUpperCase()", diff --git a/docs/pages/x/api/date-pickers/mobile-date-time-range-picker.json b/docs/pages/x/api/date-pickers/mobile-date-time-range-picker.json index 32e3b7676d7d8..376a915a5a72d 100644 --- a/docs/pages/x/api/date-pickers/mobile-date-time-range-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-date-time-range-picker.json @@ -2,10 +2,7 @@ "props": { "ampm": { "type": { "name": "bool" }, "default": "utils.is12HourCycleInCurrentLocale()" }, "autoFocus": { "type": { "name": "bool" } }, - "closeOnSelect": { - "type": { "name": "bool" }, - "default": "`true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop)." - }, + "closeOnSelect": { "type": { "name": "bool" }, "default": "false" }, "currentMonthCalendarPosition": { "type": { "name": "enum", "description": "1
| 2
| 3" }, "default": "1" diff --git a/docs/pages/x/api/date-pickers/mobile-time-picker.json b/docs/pages/x/api/date-pickers/mobile-time-picker.json index c3898c0d4a927..42e778868e5eb 100644 --- a/docs/pages/x/api/date-pickers/mobile-time-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-time-picker.json @@ -3,10 +3,7 @@ "ampm": { "type": { "name": "bool" }, "default": "utils.is12HourCycleInCurrentLocale()" }, "ampmInClock": { "type": { "name": "bool" }, "default": "true on desktop, false on mobile" }, "autoFocus": { "type": { "name": "bool" } }, - "closeOnSelect": { - "type": { "name": "bool" }, - "default": "`true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop)." - }, + "closeOnSelect": { "type": { "name": "bool" }, "default": "false" }, "defaultValue": { "type": { "name": "object" } }, "disabled": { "type": { "name": "bool" }, "default": "false" }, "disableFuture": { "type": { "name": "bool" }, "default": "false" }, diff --git a/docs/pages/x/api/date-pickers/pickers-action-bar.json b/docs/pages/x/api/date-pickers/pickers-action-bar.json index 65d659121defb..85fc360d0d346 100644 --- a/docs/pages/x/api/date-pickers/pickers-action-bar.json +++ b/docs/pages/x/api/date-pickers/pickers-action-bar.json @@ -5,7 +5,7 @@ "name": "arrayOf", "description": "Array<'accept'
| 'cancel'
| 'clear'
| 'today'>" }, - "default": "`['cancel', 'accept']` for mobile and `[]` for desktop" + "default": "`[]` for Desktop Date Picker and Desktop Date Range Picker\n- `['cancel', 'accept']` for all other Pickers" }, "disableSpacing": { "type": { "name": "bool" }, "default": "false" }, "sx": { diff --git a/docs/pages/x/api/date-pickers/time-picker.json b/docs/pages/x/api/date-pickers/time-picker.json index 66c11b29ef3e0..af9663e29bc31 100644 --- a/docs/pages/x/api/date-pickers/time-picker.json +++ b/docs/pages/x/api/date-pickers/time-picker.json @@ -3,10 +3,7 @@ "ampm": { "type": { "name": "bool" }, "default": "utils.is12HourCycleInCurrentLocale()" }, "ampmInClock": { "type": { "name": "bool" }, "default": "true on desktop, false on mobile" }, "autoFocus": { "type": { "name": "bool" } }, - "closeOnSelect": { - "type": { "name": "bool" }, - "default": "`true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop)." - }, + "closeOnSelect": { "type": { "name": "bool" }, "default": "false" }, "defaultValue": { "type": { "name": "object" } }, "desktopModeMediaQuery": { "type": { "name": "string" }, diff --git a/docs/translations/api-docs/date-pickers/date-picker/date-picker.json b/docs/translations/api-docs/date-pickers/date-picker/date-picker.json index 9514745c08f3e..731849aad5ffb 100644 --- a/docs/translations/api-docs/date-pickers/date-picker/date-picker.json +++ b/docs/translations/api-docs/date-pickers/date-picker/date-picker.json @@ -5,7 +5,7 @@ "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered." }, "closeOnSelect": { - "description": "If true, the popover or modal will close after submitting the full date." + "description": "If true, the Picker will close after submitting the full date." }, "dayOfWeekFormatter": { "description": "Formats the day of week displayed in the calendar header.", diff --git a/docs/translations/api-docs/date-pickers/date-range-picker/date-range-picker.json b/docs/translations/api-docs/date-pickers/date-range-picker/date-range-picker.json index a9d12bb4de2f4..adedcbbffc868 100644 --- a/docs/translations/api-docs/date-pickers/date-range-picker/date-range-picker.json +++ b/docs/translations/api-docs/date-pickers/date-range-picker/date-range-picker.json @@ -8,7 +8,7 @@ "description": "The number of calendars to render on desktop." }, "closeOnSelect": { - "description": "If true, the popover or modal will close after submitting the full date." + "description": "If true, the Picker will close after submitting the full date." }, "currentMonthCalendarPosition": { "description": "Position the current month is rendered in." }, "dayOfWeekFormatter": { diff --git a/docs/translations/api-docs/date-pickers/date-time-picker/date-time-picker.json b/docs/translations/api-docs/date-pickers/date-time-picker/date-time-picker.json index a8c84c093916c..839a21257c150 100644 --- a/docs/translations/api-docs/date-pickers/date-time-picker/date-time-picker.json +++ b/docs/translations/api-docs/date-pickers/date-time-picker/date-time-picker.json @@ -9,7 +9,7 @@ "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered." }, "closeOnSelect": { - "description": "If true, the popover or modal will close after submitting the full date." + "description": "If true, the Picker will close after submitting the full date." }, "dayOfWeekFormatter": { "description": "Formats the day of week displayed in the calendar header.", diff --git a/docs/translations/api-docs/date-pickers/date-time-range-picker/date-time-range-picker.json b/docs/translations/api-docs/date-pickers/date-time-range-picker/date-time-range-picker.json index 1d11acb6a894c..fd318722ce60a 100644 --- a/docs/translations/api-docs/date-pickers/date-time-range-picker/date-time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/date-time-range-picker/date-time-range-picker.json @@ -9,7 +9,7 @@ "description": "The number of calendars to render on desktop." }, "closeOnSelect": { - "description": "If true, the popover or modal will close after submitting the full date." + "description": "If true, the Picker will close after submitting the full date." }, "currentMonthCalendarPosition": { "description": "Position the current month is rendered in." }, "dayOfWeekFormatter": { diff --git a/docs/translations/api-docs/date-pickers/desktop-date-picker/desktop-date-picker.json b/docs/translations/api-docs/date-pickers/desktop-date-picker/desktop-date-picker.json index 9c6f221a942f8..8639ca30f4a57 100644 --- a/docs/translations/api-docs/date-pickers/desktop-date-picker/desktop-date-picker.json +++ b/docs/translations/api-docs/date-pickers/desktop-date-picker/desktop-date-picker.json @@ -5,7 +5,7 @@ "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered." }, "closeOnSelect": { - "description": "If true, the popover or modal will close after submitting the full date." + "description": "If true, the Picker will close after submitting the full date." }, "dayOfWeekFormatter": { "description": "Formats the day of week displayed in the calendar header.", diff --git a/docs/translations/api-docs/date-pickers/desktop-date-range-picker/desktop-date-range-picker.json b/docs/translations/api-docs/date-pickers/desktop-date-range-picker/desktop-date-range-picker.json index 6ea03ed6bd8fb..33eff49be7159 100644 --- a/docs/translations/api-docs/date-pickers/desktop-date-range-picker/desktop-date-range-picker.json +++ b/docs/translations/api-docs/date-pickers/desktop-date-range-picker/desktop-date-range-picker.json @@ -8,7 +8,7 @@ "description": "The number of calendars to render on desktop." }, "closeOnSelect": { - "description": "If true, the popover or modal will close after submitting the full date." + "description": "If true, the Picker will close after submitting the full date." }, "currentMonthCalendarPosition": { "description": "Position the current month is rendered in." }, "dayOfWeekFormatter": { diff --git a/docs/translations/api-docs/date-pickers/desktop-date-time-picker/desktop-date-time-picker.json b/docs/translations/api-docs/date-pickers/desktop-date-time-picker/desktop-date-time-picker.json index 771d81f159fa9..6fb2e7506f34c 100644 --- a/docs/translations/api-docs/date-pickers/desktop-date-time-picker/desktop-date-time-picker.json +++ b/docs/translations/api-docs/date-pickers/desktop-date-time-picker/desktop-date-time-picker.json @@ -9,7 +9,7 @@ "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered." }, "closeOnSelect": { - "description": "If true, the popover or modal will close after submitting the full date." + "description": "If true, the Picker will close after submitting the full date." }, "dayOfWeekFormatter": { "description": "Formats the day of week displayed in the calendar header.", diff --git a/docs/translations/api-docs/date-pickers/desktop-date-time-range-picker/desktop-date-time-range-picker.json b/docs/translations/api-docs/date-pickers/desktop-date-time-range-picker/desktop-date-time-range-picker.json index c2386b5c30f3e..0173c32f50fc7 100644 --- a/docs/translations/api-docs/date-pickers/desktop-date-time-range-picker/desktop-date-time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/desktop-date-time-range-picker/desktop-date-time-range-picker.json @@ -9,7 +9,7 @@ "description": "The number of calendars to render on desktop." }, "closeOnSelect": { - "description": "If true, the popover or modal will close after submitting the full date." + "description": "If true, the Picker will close after submitting the full date." }, "currentMonthCalendarPosition": { "description": "Position the current month is rendered in." }, "dayOfWeekFormatter": { diff --git a/docs/translations/api-docs/date-pickers/desktop-time-picker/desktop-time-picker.json b/docs/translations/api-docs/date-pickers/desktop-time-picker/desktop-time-picker.json index 37e81ae3bd1fb..39dcd0e2ece99 100644 --- a/docs/translations/api-docs/date-pickers/desktop-time-picker/desktop-time-picker.json +++ b/docs/translations/api-docs/date-pickers/desktop-time-picker/desktop-time-picker.json @@ -9,7 +9,7 @@ "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered." }, "closeOnSelect": { - "description": "If true, the popover or modal will close after submitting the full date." + "description": "If true, the Picker will close after submitting the full date." }, "defaultValue": { "description": "The default value. Used when the component is not controlled." diff --git a/docs/translations/api-docs/date-pickers/mobile-date-picker/mobile-date-picker.json b/docs/translations/api-docs/date-pickers/mobile-date-picker/mobile-date-picker.json index de8638284e24b..d3bf52f7d9609 100644 --- a/docs/translations/api-docs/date-pickers/mobile-date-picker/mobile-date-picker.json +++ b/docs/translations/api-docs/date-pickers/mobile-date-picker/mobile-date-picker.json @@ -5,7 +5,7 @@ "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered." }, "closeOnSelect": { - "description": "If true, the popover or modal will close after submitting the full date." + "description": "If true, the Picker will close after submitting the full date." }, "dayOfWeekFormatter": { "description": "Formats the day of week displayed in the calendar header.", diff --git a/docs/translations/api-docs/date-pickers/mobile-date-range-picker/mobile-date-range-picker.json b/docs/translations/api-docs/date-pickers/mobile-date-range-picker/mobile-date-range-picker.json index e16c8eede9d45..a96abba90b05c 100644 --- a/docs/translations/api-docs/date-pickers/mobile-date-range-picker/mobile-date-range-picker.json +++ b/docs/translations/api-docs/date-pickers/mobile-date-range-picker/mobile-date-range-picker.json @@ -5,7 +5,7 @@ "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered." }, "closeOnSelect": { - "description": "If true, the popover or modal will close after submitting the full date." + "description": "If true, the Picker will close after submitting the full date." }, "currentMonthCalendarPosition": { "description": "Position the current month is rendered in." }, "dayOfWeekFormatter": { diff --git a/docs/translations/api-docs/date-pickers/mobile-date-time-picker/mobile-date-time-picker.json b/docs/translations/api-docs/date-pickers/mobile-date-time-picker/mobile-date-time-picker.json index 43e3030a0a438..e08489562eeb6 100644 --- a/docs/translations/api-docs/date-pickers/mobile-date-time-picker/mobile-date-time-picker.json +++ b/docs/translations/api-docs/date-pickers/mobile-date-time-picker/mobile-date-time-picker.json @@ -9,7 +9,7 @@ "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered." }, "closeOnSelect": { - "description": "If true, the popover or modal will close after submitting the full date." + "description": "If true, the Picker will close after submitting the full date." }, "dayOfWeekFormatter": { "description": "Formats the day of week displayed in the calendar header.", diff --git a/docs/translations/api-docs/date-pickers/mobile-date-time-range-picker/mobile-date-time-range-picker.json b/docs/translations/api-docs/date-pickers/mobile-date-time-range-picker/mobile-date-time-range-picker.json index 39d6d5ec53aed..f6e0766578042 100644 --- a/docs/translations/api-docs/date-pickers/mobile-date-time-range-picker/mobile-date-time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/mobile-date-time-range-picker/mobile-date-time-range-picker.json @@ -6,7 +6,7 @@ "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered." }, "closeOnSelect": { - "description": "If true, the popover or modal will close after submitting the full date." + "description": "If true, the Picker will close after submitting the full date." }, "currentMonthCalendarPosition": { "description": "Position the current month is rendered in." }, "dayOfWeekFormatter": { diff --git a/docs/translations/api-docs/date-pickers/mobile-time-picker/mobile-time-picker.json b/docs/translations/api-docs/date-pickers/mobile-time-picker/mobile-time-picker.json index 2f933308ab83f..8d76eacc2d628 100644 --- a/docs/translations/api-docs/date-pickers/mobile-time-picker/mobile-time-picker.json +++ b/docs/translations/api-docs/date-pickers/mobile-time-picker/mobile-time-picker.json @@ -9,7 +9,7 @@ "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered." }, "closeOnSelect": { - "description": "If true, the popover or modal will close after submitting the full date." + "description": "If true, the Picker will close after submitting the full date." }, "defaultValue": { "description": "The default value. Used when the component is not controlled." diff --git a/docs/translations/api-docs/date-pickers/time-picker/time-picker.json b/docs/translations/api-docs/date-pickers/time-picker/time-picker.json index 11ba6e87afc1a..ebe08c0aff48d 100644 --- a/docs/translations/api-docs/date-pickers/time-picker/time-picker.json +++ b/docs/translations/api-docs/date-pickers/time-picker/time-picker.json @@ -9,7 +9,7 @@ "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered." }, "closeOnSelect": { - "description": "If true, the popover or modal will close after submitting the full date." + "description": "If true, the Picker will close after submitting the full date." }, "defaultValue": { "description": "The default value. Used when the component is not controlled." diff --git a/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.tsx b/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.tsx index 76bb9c9804dff..81d561b7edc68 100644 --- a/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.tsx @@ -62,7 +62,7 @@ DateRangePicker.propTypes = { calendars: PropTypes.oneOf([1, 2, 3]), className: PropTypes.string, /** - * If `true`, the popover or modal will close after submitting the full date. + * If `true`, the Picker will close after submitting the full date. * @default `true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop). */ closeOnSelect: PropTypes.bool, diff --git a/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.types.ts b/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.types.ts index 013359cc8f084..77dae47f82368 100644 --- a/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/DateRangePicker/DateRangePicker.types.ts @@ -39,6 +39,11 @@ export interface DateRangePickerProps; + /** + * If `true`, the Picker will close after submitting the full date. + * @default `true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop). + */ + closeOnSelect?: boolean; } /** diff --git a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePicker.tsx index 048716130d041..84acb173919ae 100644 --- a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePicker.tsx @@ -67,8 +67,8 @@ DateTimeRangePicker.propTypes = { calendars: PropTypes.oneOf([1, 2, 3]), className: PropTypes.string, /** - * If `true`, the popover or modal will close after submitting the full date. - * @default `true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop). + * If `true`, the Picker will close after submitting the full date. + * @default false */ closeOnSelect: PropTypes.bool, /** diff --git a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.tsx index 13f7339a81caa..8573eea7c402f 100644 --- a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.tsx @@ -10,6 +10,8 @@ import { extractValidationProps } from '@mui/x-date-pickers/validation'; import { PickerOwnerState } from '@mui/x-date-pickers/models'; import resolveComponentProps from '@mui/utils/resolveComponentProps'; import { refType } from '@mui/utils'; +import { PickerLayoutOwnerState } from '@mui/x-date-pickers/PickersLayout'; +import { PickersActionBarAction } from '@mui/x-date-pickers/PickersActionBar'; import { rangeValueManager } from '../internals/utils/valueManagers'; import { DesktopDateRangePickerProps } from './DesktopDateRangePicker.types'; import { useDateRangePickerDefaultizedProps } from '../DateRangePicker/shared'; @@ -23,6 +25,8 @@ type DesktopDateRangePickerComponent = (, ) => React.JSX.Element) & { propTypes?: any }; +const emptyActions: PickersActionBarAction[] = []; + /** * Demos: * @@ -53,6 +57,7 @@ const DesktopDateRangePicker = React.forwardRef(function DesktopDateRangePicker< const props = { ...defaultizedProps, + closeOnSelect: defaultizedProps.closeOnSelect ?? true, viewRenderers, format: utils.formats.keyboardDate, calendars: defaultizedProps.calendars ?? 2, @@ -73,6 +78,10 @@ const DesktopDateRangePicker = React.forwardRef(function DesktopDateRangePicker< hidden: true, ...defaultizedProps.slotProps?.toolbar, }, + actionBar: (ownerState: PickerLayoutOwnerState) => ({ + actions: emptyActions, + ...resolveComponentProps(defaultizedProps.slotProps?.actionBar, ownerState), + }), }, }; @@ -109,8 +118,8 @@ DesktopDateRangePicker.propTypes = { calendars: PropTypes.oneOf([1, 2, 3]), className: PropTypes.string, /** - * If `true`, the popover or modal will close after submitting the full date. - * @default `true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop). + * If `true`, the Picker will close after submitting the full date. + * @default true */ closeOnSelect: PropTypes.bool, /** diff --git a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.types.ts b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.types.ts index 0ee5c02e826f3..d8521683e605f 100644 --- a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.types.ts @@ -37,4 +37,9 @@ export interface DesktopDateRangePickerProps< * @default {} */ slotProps?: DesktopDateRangePickerSlotProps; + /** + * If `true`, the Picker will close after submitting the full date. + * @default true + */ + closeOnSelect?: boolean; } diff --git a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/DesktopDateTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/DesktopDateTimeRangePicker.tsx index d2a0dd0454c43..4d37ff808be63 100644 --- a/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/DesktopDateTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopDateTimeRangePicker/DesktopDateTimeRangePicker.tsx @@ -13,7 +13,6 @@ import { } from '@mui/x-date-pickers/internals'; import { extractValidationProps } from '@mui/x-date-pickers/validation'; import { PickerOwnerState } from '@mui/x-date-pickers/models'; -import { PickerLayoutOwnerState } from '@mui/x-date-pickers/PickersLayout'; import resolveComponentProps from '@mui/utils/resolveComponentProps'; import { refType } from '@mui/utils'; import { @@ -26,7 +25,6 @@ import { } from '@mui/x-date-pickers/MultiSectionDigitalClock'; import Divider from '@mui/material/Divider'; import { digitalClockClasses } from '@mui/x-date-pickers/DigitalClock'; -import type { PickersActionBarAction } from '@mui/x-date-pickers/PickersActionBar'; import { DesktopDateTimePickerLayout } from '@mui/x-date-pickers/DesktopDateTimePicker'; import { rangeValueManager } from '../internals/utils/valueManagers'; import { DesktopDateTimeRangePickerProps } from './DesktopDateTimeRangePicker.types'; @@ -136,8 +134,6 @@ const DesktopDateTimeRangePicker = React.forwardRef(function DesktopDateTimeRang const views = !shouldHoursRendererContainMeridiemView ? defaultizedProps.views.filter((view) => view !== 'meridiem') : defaultizedProps.views; - const actionBarActions: PickersActionBarAction[] = - defaultizedProps.shouldRenderTimeInASingleColumn ? [] : ['accept']; const props = { ...defaultizedProps, @@ -167,10 +163,6 @@ const DesktopDateTimeRangePicker = React.forwardRef(function DesktopDateTimeRang hidden: true, ...defaultizedProps.slotProps?.toolbar, }, - actionBar: (ownerState: PickerLayoutOwnerState) => ({ - actions: actionBarActions, - ...resolveComponentProps(defaultizedProps.slotProps?.actionBar, ownerState), - }), }, }; @@ -213,8 +205,8 @@ DesktopDateTimeRangePicker.propTypes = { calendars: PropTypes.oneOf([1, 2, 3]), className: PropTypes.string, /** - * If `true`, the popover or modal will close after submitting the full date. - * @default `true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop). + * If `true`, the Picker will close after submitting the full date. + * @default false */ closeOnSelect: PropTypes.bool, /** diff --git a/packages/x-date-pickers-pro/src/MobileDateRangePicker/MobileDateRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileDateRangePicker/MobileDateRangePicker.tsx index d8f3841c606c0..0cb89cccebc7b 100644 --- a/packages/x-date-pickers-pro/src/MobileDateRangePicker/MobileDateRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/MobileDateRangePicker/MobileDateRangePicker.tsx @@ -105,8 +105,8 @@ MobileDateRangePicker.propTypes = { autoFocus: PropTypes.bool, className: PropTypes.string, /** - * If `true`, the popover or modal will close after submitting the full date. - * @default `true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop). + * If `true`, the Picker will close after submitting the full date. + * @default false */ closeOnSelect: PropTypes.bool, /** diff --git a/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/MobileDateTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/MobileDateTimeRangePicker.tsx index 65a4e101d1438..34c86d6f6c6b3 100644 --- a/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/MobileDateTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/MobileDateTimeRangePicker/MobileDateTimeRangePicker.tsx @@ -205,8 +205,8 @@ MobileDateTimeRangePicker.propTypes = { autoFocus: PropTypes.bool, className: PropTypes.string, /** - * If `true`, the popover or modal will close after submitting the full date. - * @default `true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop). + * If `true`, the Picker will close after submitting the full date. + * @default false */ closeOnSelect: PropTypes.bool, /** diff --git a/packages/x-date-pickers/src/DatePicker/DatePicker.tsx b/packages/x-date-pickers/src/DatePicker/DatePicker.tsx index 6efb2dc1d7e1e..de1dae1441e65 100644 --- a/packages/x-date-pickers/src/DatePicker/DatePicker.tsx +++ b/packages/x-date-pickers/src/DatePicker/DatePicker.tsx @@ -54,7 +54,7 @@ DatePicker.propTypes = { autoFocus: PropTypes.bool, className: PropTypes.string, /** - * If `true`, the popover or modal will close after submitting the full date. + * If `true`, the Picker will close after submitting the full date. * @default `true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop). */ closeOnSelect: PropTypes.bool, diff --git a/packages/x-date-pickers/src/DatePicker/DatePicker.types.ts b/packages/x-date-pickers/src/DatePicker/DatePicker.types.ts index bbccb00651e43..0ff8753f814b7 100644 --- a/packages/x-date-pickers/src/DatePicker/DatePicker.types.ts +++ b/packages/x-date-pickers/src/DatePicker/DatePicker.types.ts @@ -42,6 +42,11 @@ export interface DatePickerProps( props: DesktopDatePickerProps & React.RefAttributes, ) => React.JSX.Element) & { propTypes?: any }; +const emptyActions: PickersActionBarAction[] = []; + /** * Demos: * @@ -56,6 +60,7 @@ const DesktopDatePicker = React.forwardRef(function DesktopDatePicker< // Props with the default values specific to the desktop variant const props = { ...defaultizedProps, + closeOnSelect: defaultizedProps.closeOnSelect ?? true, viewRenderers, format: resolveDateFormat(utils, defaultizedProps, false), yearsPerRow: defaultizedProps.yearsPerRow ?? 4, @@ -75,6 +80,10 @@ const DesktopDatePicker = React.forwardRef(function DesktopDatePicker< hidden: true, ...defaultizedProps.slotProps?.toolbar, }, + actionBar: (ownerState: PickerLayoutOwnerState) => ({ + actions: emptyActions, + ...resolveComponentProps(defaultizedProps.slotProps?.actionBar, ownerState), + }), }, }; @@ -112,8 +121,8 @@ DesktopDatePicker.propTypes = { autoFocus: PropTypes.bool, className: PropTypes.string, /** - * If `true`, the popover or modal will close after submitting the full date. - * @default `true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop). + * If `true`, the Picker will close after submitting the full date. + * @default true */ closeOnSelect: PropTypes.bool, /** diff --git a/packages/x-date-pickers/src/DesktopDatePicker/DesktopDatePicker.types.ts b/packages/x-date-pickers/src/DesktopDatePicker/DesktopDatePicker.types.ts index 737f91ae3f46c..fb84789de0be9 100644 --- a/packages/x-date-pickers/src/DesktopDatePicker/DesktopDatePicker.types.ts +++ b/packages/x-date-pickers/src/DesktopDatePicker/DesktopDatePicker.types.ts @@ -38,4 +38,9 @@ export interface DesktopDatePickerProps, @@ -151,9 +149,6 @@ const DesktopDateTimePicker = React.forwardRef(function DesktopDateTimePicker< const views = !shouldHoursRendererContainMeridiemView ? resolvedViews.filter((view) => view !== 'meridiem') : resolvedViews; - const actionBarActions: PickersActionBarAction[] = shouldRenderTimeInASingleColumn - ? [] - : ['accept']; // Props with the default values specific to the desktop variant const props = { @@ -188,10 +183,6 @@ const DesktopDateTimePicker = React.forwardRef(function DesktopDateTimePicker< hidden: true, ...defaultizedProps.slotProps?.tabs, }, - actionBar: (ownerState: PickerLayoutOwnerState) => ({ - actions: actionBarActions, - ...resolveComponentProps(defaultizedProps.slotProps?.actionBar, ownerState), - }), }, }; @@ -240,8 +231,8 @@ DesktopDateTimePicker.propTypes = { autoFocus: PropTypes.bool, className: PropTypes.string, /** - * If `true`, the popover or modal will close after submitting the full date. - * @default `true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop). + * If `true`, the Picker will close after submitting the full date. + * @default false */ closeOnSelect: PropTypes.bool, /** diff --git a/packages/x-date-pickers/src/DesktopDateTimePicker/tests/DesktopDateTimePicker.test.tsx b/packages/x-date-pickers/src/DesktopDateTimePicker/tests/DesktopDateTimePicker.test.tsx index ea815c570641d..fda2d1f68cf0f 100644 --- a/packages/x-date-pickers/src/DesktopDateTimePicker/tests/DesktopDateTimePicker.test.tsx +++ b/packages/x-date-pickers/src/DesktopDateTimePicker/tests/DesktopDateTimePicker.test.tsx @@ -56,6 +56,12 @@ describe('', () => { // Change the meridiem (same value) fireEvent.click(screen.getByRole('option', { name: 'AM' })); expect(onChange.callCount).to.equal(1); // Don't call onChange again since the value did not change + // closeOnSelect false by default + expect(onAccept.callCount).to.equal(0); + expect(onClose.callCount).to.equal(0); + + // Click on 'accept' action to close the picker + fireEvent.click(screen.getByText(/ok/i)); expect(onAccept.callCount).to.equal(1); expect(onClose.callCount).to.equal(1); }); @@ -99,6 +105,12 @@ describe('', () => { // Change the meridiem fireEvent.click(screen.getByRole('option', { name: 'PM' })); expect(onChange.callCount).to.equal(8); + // closeOnSelect false by default + expect(onAccept.callCount).to.equal(0); + expect(onClose.callCount).to.equal(0); + + // Click on 'accept' action to close the picker + fireEvent.click(screen.getByText(/ok/i)); expect(onAccept.callCount).to.equal(1); expect(onClose.callCount).to.equal(1); }); @@ -123,6 +135,10 @@ describe('', () => { expect(onChange.callCount).to.equal(2); expect(onChange.lastCall.args[0]).toEqualDateTime(new Date(2018, 0, 2, 3, 0, 0)); + expect(onAccept.callCount).to.equal(0); // onAccept false by default + + // Click on 'accept' action to close the picker + fireEvent.click(screen.getByText(/ok/i)); expect(onAccept.callCount).to.equal(1); }); @@ -144,6 +160,10 @@ describe('', () => { expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.args[0]).toEqualDateTime(new Date(2018, 0, 1, 3, 0, 0)); + expect(onAccept.callCount).to.equal(0); // onAccept false by default + + // Click on 'accept' action to close the picker + fireEvent.click(screen.getByText(/ok/i)); expect(onAccept.callCount).to.equal(1); }); }); diff --git a/packages/x-date-pickers/src/DesktopTimePicker/DesktopTimePicker.tsx b/packages/x-date-pickers/src/DesktopTimePicker/DesktopTimePicker.tsx index 62a9eff77998f..01bcb39d8eccc 100644 --- a/packages/x-date-pickers/src/DesktopTimePicker/DesktopTimePicker.tsx +++ b/packages/x-date-pickers/src/DesktopTimePicker/DesktopTimePicker.tsx @@ -16,7 +16,6 @@ import { renderDigitalClockTimeView, renderMultiSectionDigitalClockTimeView, } from '../timeViewRenderers'; -import { PickersActionBarAction } from '../PickersActionBar'; import { TimeViewWithMeridiem } from '../internals/models'; import { resolveTimeFormat } from '../internals/utils/time-utils'; import { resolveTimeViewsResponse } from '../internals/utils/date-time-utils'; @@ -72,9 +71,6 @@ const DesktopTimePicker = React.forwardRef(function DesktopTimePicker< }; const ampmInClock = defaultizedProps.ampmInClock ?? true; - const actionBarActions: PickersActionBarAction[] = shouldRenderTimeInASingleColumn - ? [] - : ['accept']; // Need to avoid adding the `meridiem` view when unexpected renderer is specified const shouldHoursRendererContainMeridiemView = viewRenderers.hours?.name === renderMultiSectionDigitalClockTimeView.name; @@ -109,10 +105,6 @@ const DesktopTimePicker = React.forwardRef(function DesktopTimePicker< ampmInClock, ...defaultizedProps.slotProps?.toolbar, }, - actionBar: { - actions: actionBarActions, - ...defaultizedProps.slotProps?.actionBar, - }, }, }; @@ -160,8 +152,8 @@ DesktopTimePicker.propTypes = { autoFocus: PropTypes.bool, className: PropTypes.string, /** - * If `true`, the popover or modal will close after submitting the full date. - * @default `true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop). + * If `true`, the Picker will close after submitting the full date. + * @default false */ closeOnSelect: PropTypes.bool, /** diff --git a/packages/x-date-pickers/src/DesktopTimePicker/tests/DesktopTimePicker.test.tsx b/packages/x-date-pickers/src/DesktopTimePicker/tests/DesktopTimePicker.test.tsx index f6d1314d76942..096830e2565b8 100644 --- a/packages/x-date-pickers/src/DesktopTimePicker/tests/DesktopTimePicker.test.tsx +++ b/packages/x-date-pickers/src/DesktopTimePicker/tests/DesktopTimePicker.test.tsx @@ -80,8 +80,13 @@ describe('', () => { fireEvent.click(screen.getByRole('option', { name: '09:00 AM' })); expect(onChange.callCount).to.equal(1); expect(onChange.lastCall.args[0]).toEqualDateTime(new Date(2018, 0, 1, 9, 0)); + // closeOnSelect false by default + expect(onAccept.callCount).to.equal(0); + expect(onClose.callCount).to.equal(0); + + // Click on 'accept' action to close the picker + fireEvent.click(screen.getByText(/ok/i)); expect(onAccept.callCount).to.equal(1); - expect(onAccept.lastCall.args[0]).toEqualDateTime(new Date(2018, 0, 1, 9, 0)); expect(onClose.callCount).to.equal(1); }); @@ -113,8 +118,13 @@ describe('', () => { fireEvent.click(screen.getByRole('option', { name: 'PM' })); expect(onChange.callCount).to.equal(3); + // closeOnSelect false by default + expect(onAccept.callCount).to.equal(0); + expect(onClose.callCount).to.equal(0); + + // Click on 'accept' action to close the picker + fireEvent.click(screen.getByText(/ok/i)); expect(onAccept.callCount).to.equal(1); - expect(onAccept.lastCall.args[0]).toEqualDateTime(new Date(2018, 0, 1, 14, 15)); expect(onClose.callCount).to.equal(1); }); @@ -151,8 +161,13 @@ describe('', () => { fireEvent.click(screen.getByRole('option', { name: 'PM' })); expect(onChange.callCount).to.equal(4); + // closeOnSelect false by default + expect(onAccept.callCount).to.equal(0); + expect(onClose.callCount).to.equal(0); + + // Click on 'accept' action to close the picker + fireEvent.click(screen.getByText(/ok/i)); expect(onAccept.callCount).to.equal(1); - expect(onAccept.lastCall.args[0]).toEqualDateTime(new Date(2018, 0, 1, 14, 25)); expect(onClose.callCount).to.equal(1); }); @@ -174,8 +189,13 @@ describe('', () => { fireEvent.click(screen.getByRole('option', { name: 'PM' })); expect(onChange.callCount).to.equal(1); + // closeOnSelect false by default + expect(onAccept.callCount).to.equal(0); + expect(onClose.callCount).to.equal(0); + + // Click on 'accept' action to close the picker + fireEvent.click(screen.getByText(/ok/i)); expect(onAccept.callCount).to.equal(1); - expect(onAccept.lastCall.args[0]).toEqualDateTime(new Date(2018, 0, 1, 12, 0)); expect(onClose.callCount).to.equal(1); }); }); diff --git a/packages/x-date-pickers/src/MobileDatePicker/MobileDatePicker.tsx b/packages/x-date-pickers/src/MobileDatePicker/MobileDatePicker.tsx index ea6d1f4025415..3f40a6ad1f1f4 100644 --- a/packages/x-date-pickers/src/MobileDatePicker/MobileDatePicker.tsx +++ b/packages/x-date-pickers/src/MobileDatePicker/MobileDatePicker.tsx @@ -109,8 +109,8 @@ MobileDatePicker.propTypes = { autoFocus: PropTypes.bool, className: PropTypes.string, /** - * If `true`, the popover or modal will close after submitting the full date. - * @default `true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop). + * If `true`, the Picker will close after submitting the full date. + * @default false */ closeOnSelect: PropTypes.bool, /** diff --git a/packages/x-date-pickers/src/MobileDateTimePicker/MobileDateTimePicker.tsx b/packages/x-date-pickers/src/MobileDateTimePicker/MobileDateTimePicker.tsx index d6be60133594b..c0410f5d2499a 100644 --- a/packages/x-date-pickers/src/MobileDateTimePicker/MobileDateTimePicker.tsx +++ b/packages/x-date-pickers/src/MobileDateTimePicker/MobileDateTimePicker.tsx @@ -133,8 +133,8 @@ MobileDateTimePicker.propTypes = { autoFocus: PropTypes.bool, className: PropTypes.string, /** - * If `true`, the popover or modal will close after submitting the full date. - * @default `true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop). + * If `true`, the Picker will close after submitting the full date. + * @default false */ closeOnSelect: PropTypes.bool, /** diff --git a/packages/x-date-pickers/src/MobileTimePicker/MobileTimePicker.tsx b/packages/x-date-pickers/src/MobileTimePicker/MobileTimePicker.tsx index 1affd7d8f8992..e36e6cf1cd416 100644 --- a/packages/x-date-pickers/src/MobileTimePicker/MobileTimePicker.tsx +++ b/packages/x-date-pickers/src/MobileTimePicker/MobileTimePicker.tsx @@ -123,8 +123,8 @@ MobileTimePicker.propTypes = { autoFocus: PropTypes.bool, className: PropTypes.string, /** - * If `true`, the popover or modal will close after submitting the full date. - * @default `true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop). + * If `true`, the Picker will close after submitting the full date. + * @default false */ closeOnSelect: PropTypes.bool, /** diff --git a/packages/x-date-pickers/src/PickersActionBar/PickersActionBar.tsx b/packages/x-date-pickers/src/PickersActionBar/PickersActionBar.tsx index 8551bbf6d7fa5..de7ac68347456 100644 --- a/packages/x-date-pickers/src/PickersActionBar/PickersActionBar.tsx +++ b/packages/x-date-pickers/src/PickersActionBar/PickersActionBar.tsx @@ -13,7 +13,9 @@ export interface PickersActionBarProps extends DialogActionsProps { /** * Ordered array of actions to display. * If empty, does not display that action bar. - * @default `['cancel', 'accept']` for mobile and `[]` for desktop + * @default + * - `[]` for Desktop Date Picker and Desktop Date Range Picker + * - `['cancel', 'accept']` for all other Pickers */ actions?: PickersActionBarAction[]; } @@ -91,7 +93,9 @@ PickersActionBar.propTypes = { /** * Ordered array of actions to display. * If empty, does not display that action bar. - * @default `['cancel', 'accept']` for mobile and `[]` for desktop + * @default + * - `[]` for Desktop Date Picker and Desktop Date Range Picker + * - `['cancel', 'accept']` for all other Pickers */ actions: PropTypes.arrayOf(PropTypes.oneOf(['accept', 'cancel', 'clear', 'today']).isRequired), /** diff --git a/packages/x-date-pickers/src/PickersLayout/usePickerLayout.tsx b/packages/x-date-pickers/src/PickersLayout/usePickerLayout.tsx index 5c7fd96a32c5f..73845e01d611d 100644 --- a/packages/x-date-pickers/src/PickersLayout/usePickerLayout.tsx +++ b/packages/x-date-pickers/src/PickersLayout/usePickerLayout.tsx @@ -42,7 +42,7 @@ const usePickerLayout = ( props: PickersLayoutProps, ): UsePickerLayoutResponse => { const { ownerState: pickerOwnerState } = usePickerPrivateContext(); - const { variant, view } = usePickerContext(); + const { view } = usePickerContext(); const isRtl = useRtl(); const { children, slots, slotProps, classes: classesProp } = props; @@ -59,7 +59,7 @@ const usePickerLayout = ( elementType: ActionBar, externalSlotProps: slotProps?.actionBar, additionalProps: { - actions: variant === 'desktop' ? [] : (['cancel', 'accept'] as PickersActionBarAction[]), + actions: ['cancel', 'accept'] as PickersActionBarAction[], }, className: classes.actionBar, ownerState, diff --git a/packages/x-date-pickers/src/TimePicker/TimePicker.tsx b/packages/x-date-pickers/src/TimePicker/TimePicker.tsx index 6b3b60669aed6..17e60e3483e4a 100644 --- a/packages/x-date-pickers/src/TimePicker/TimePicker.tsx +++ b/packages/x-date-pickers/src/TimePicker/TimePicker.tsx @@ -64,8 +64,8 @@ TimePicker.propTypes = { autoFocus: PropTypes.bool, className: PropTypes.string, /** - * If `true`, the popover or modal will close after submitting the full date. - * @default `true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop). + * If `true`, the Picker will close after submitting the full date. + * @default false */ closeOnSelect: PropTypes.bool, /** diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.ts index 2b03fbc3cb073..3436c8aaca762 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.ts @@ -38,7 +38,6 @@ export const usePicker = < props, valueManager, valueType, - variant, validator, }); diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.types.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.types.ts index c8b0138a48a0e..b49ab3fbbd7f3 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePicker.types.ts @@ -45,13 +45,16 @@ export interface UsePickerParams< TExternalProps extends UsePickerProps, > extends Pick< UsePickerValueParams, - 'valueManager' | 'valueType' | 'variant' | 'validator' + 'valueManager' | 'valueType' | 'validator' >, Pick< UsePickerViewParams, 'autoFocusView' | 'rendererInterceptor' | 'fieldRef' >, - Pick>, 'localeText'> { + Pick< + UsePickerProviderParameters>, + 'localeText' | 'variant' + > { props: TExternalProps; } diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts index 9309b7b6c21a0..b6a0f8e911f08 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts @@ -145,7 +145,6 @@ export const usePickerValue = < props, valueManager, valueType, - variant, validator, }: UsePickerValueParams): UsePickerValueResponse< TValue, @@ -158,7 +157,7 @@ export const usePickerValue = < onChange, value: inValueWithoutRenderTimezone, defaultValue: inDefaultValue, - closeOnSelect = variant === 'desktop', + closeOnSelect = false, timezone: timezoneProp, referenceDate, } = props; diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts index 03c78458091f6..67a067c68f66c 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts @@ -2,7 +2,6 @@ import * as React from 'react'; import { MakeRequired } from '@mui/x-internals/types'; import { UseFieldInternalProps } from '../useField'; import { Validator } from '../../../validation'; -import { PickerVariant } from '../../models/common'; import { TimezoneProps, MuiPickersAdapter, @@ -225,8 +224,8 @@ export interface UsePickerValueBaseProps>; valueType: PickerValueType; - variant: PickerVariant; validator: Validator, TExternalProps>; } diff --git a/test/e2e/index.test.ts b/test/e2e/index.test.ts index f9145efca5033..a60c3ecfe0cb4 100644 --- a/test/e2e/index.test.ts +++ b/test/e2e/index.test.ts @@ -845,8 +845,8 @@ async function initializeEnvironment( await page.getByRole('option', { name: '30 minutes' }).click(); await page.getByRole('option', { name: 'PM' }).click(); - // assert that the dialog closes after selection is complete - // could run into race condition otherwise + // dialog closes after user actively closes it + await page.keyboard.press('Escape'); await page.waitForSelector('[role="dialog"]', { state: 'detached' }); expect(await page.getByRole('textbox', { includeHidden: true }).inputValue()).to.equal( '04/11/2022 03:30 PM', @@ -896,8 +896,14 @@ async function initializeEnvironment( await page.keyboard.press('ArrowDown'); await page.keyboard.press('Enter'); - // assert that the dialog closes after selection is complete - // could run into race condition otherwise + // check that the picker has not been closed + await page.waitForSelector('[role="dialog"]', { state: 'visible' }); + + // Click 'OK' button to close dialog + await page.keyboard.press('Tab'); // move focus to 'cancel' action + await page.keyboard.press('Tab'); // move focus to 'accept' action + await page.keyboard.press('Enter'); + await page.waitForSelector('[role="dialog"]', { state: 'detached' }); expect(await page.getByRole('textbox', { includeHidden: true }).inputValue()).to.equal( '04/21/2022 02:05 PM', diff --git a/test/utils/pickers/describeValue/testPickerOpenCloseLifeCycle.tsx b/test/utils/pickers/describeValue/testPickerOpenCloseLifeCycle.tsx index f545ad85ed1fd..6b2ccb35ea7e6 100644 --- a/test/utils/pickers/describeValue/testPickerOpenCloseLifeCycle.tsx +++ b/test/utils/pickers/describeValue/testPickerOpenCloseLifeCycle.tsx @@ -17,6 +17,9 @@ export const testPickerOpenCloseLifeCycle: DescribeValueTestSuite { it('should not open on mount if `props.open` is false', () => { @@ -45,7 +48,7 @@ export const testPickerOpenCloseLifeCycle: DescribeValueTestSuite { + it('should call onChange and onClose and onAccept (if `DesktopDatePicker` or `DesktopDateRangePicker`) when selecting a value', () => { const onChange = spy(); const onAccept = spy(); const onClose = spy(); @@ -82,8 +85,9 @@ export const testPickerOpenCloseLifeCycle: DescribeValueTestSuite Date: Fri, 3 Jan 2025 18:23:01 -0500 Subject: [PATCH 03/25] [DataGrid] Refactor: create base button props (#15930) --- .../GridHeaderFilterClearButton.tsx | 11 ++++--- .../GridHeaderFilterMenuContainer.tsx | 4 +-- .../components/cell/GridActionsCellItem.tsx | 11 ++++--- .../GridColumnHeaderFilterIconButton.tsx | 1 - .../GridColumnsManagement.tsx | 6 ++-- .../toolbar/GridToolbarQuickFilter.tsx | 6 ++-- .../x-data-grid/src/models/gridBaseSlots.ts | 31 +++++++++++++++++-- .../src/models/gridSlotsComponentsProps.ts | 10 ++++-- 8 files changed, 58 insertions(+), 22 deletions(-) diff --git a/packages/x-data-grid-pro/src/components/headerFiltering/GridHeaderFilterClearButton.tsx b/packages/x-data-grid-pro/src/components/headerFiltering/GridHeaderFilterClearButton.tsx index 1c4ad36c7c588..bb22108ee9025 100644 --- a/packages/x-data-grid-pro/src/components/headerFiltering/GridHeaderFilterClearButton.tsx +++ b/packages/x-data-grid-pro/src/components/headerFiltering/GridHeaderFilterClearButton.tsx @@ -1,10 +1,13 @@ import * as React from 'react'; -import { IconButtonProps } from '@mui/material/IconButton'; +import { GridSlotProps } from '@mui/x-data-grid'; import { useGridRootProps } from '../../hooks/utils/useGridRootProps'; -interface GridHeaderFilterClearIconProps extends IconButtonProps {} +type BaseIconButtonProps = GridSlotProps['baseIconButton']; -const sx = { padding: '2px' }; +// FIXME(v8:romgrk): Make parametric +interface GridHeaderFilterClearIconProps extends BaseIconButtonProps {} + +const style = { padding: '2px' }; function GridHeaderFilterClearButton(props: GridHeaderFilterClearIconProps) { const rootProps = useGridRootProps(); @@ -13,7 +16,7 @@ function GridHeaderFilterClearButton(props: GridHeaderFilterClearIconProps) { tabIndex={-1} aria-label="Clear filter" size="small" - sx={sx} + style={style} {...props} {...rootProps.slotProps?.baseIconButton} > diff --git a/packages/x-data-grid-pro/src/components/headerFiltering/GridHeaderFilterMenuContainer.tsx b/packages/x-data-grid-pro/src/components/headerFiltering/GridHeaderFilterMenuContainer.tsx index a09f307355e91..89b2cc023f00d 100644 --- a/packages/x-data-grid-pro/src/components/headerFiltering/GridHeaderFilterMenuContainer.tsx +++ b/packages/x-data-grid-pro/src/components/headerFiltering/GridHeaderFilterMenuContainer.tsx @@ -11,7 +11,7 @@ import { refType, unstable_useId as useId } from '@mui/utils'; import { gridHeaderFilteringMenuSelector } from '@mui/x-data-grid/internals'; import { useGridRootProps } from '../../hooks/utils/useGridRootProps'; -const sx = { +const style = { width: 22, height: 22, margin: 'auto 0 10px 5px', @@ -69,7 +69,7 @@ function GridHeaderFilterMenuContainer(props: { tabIndex={-1} size="small" onClick={handleClick} - sx={sx} + style={style} disabled={disabled} {...rootProps.slotProps?.baseIconButton} > diff --git a/packages/x-data-grid/src/components/cell/GridActionsCellItem.tsx b/packages/x-data-grid/src/components/cell/GridActionsCellItem.tsx index 4125db721da6f..0002aa61facc4 100644 --- a/packages/x-data-grid/src/components/cell/GridActionsCellItem.tsx +++ b/packages/x-data-grid/src/components/cell/GridActionsCellItem.tsx @@ -1,8 +1,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { IconButtonProps } from '@mui/material/IconButton'; -import { MenuItemProps } from '@mui/material/MenuItem'; import { forwardRef } from '@mui/x-internals/forwardRef'; +import { GridSlotProps } from '../../models/gridSlotsComponentsProps'; import { useGridRootProps } from '../../hooks/utils/useGridRootProps'; interface GridActionsCellItemCommonProps { @@ -12,9 +11,13 @@ interface GridActionsCellItemCommonProps { component?: React.ElementType; } +// FIXME(v8:romgrk): Make parametric export type GridActionsCellItemProps = GridActionsCellItemCommonProps & ( - | ({ showInMenu?: false; icon: React.ReactElement } & Omit) + | ({ showInMenu?: false; icon: React.ReactElement } & Omit< + GridSlotProps['baseIconButton'], + 'component' + >) | ({ showInMenu: true; /** @@ -23,7 +26,7 @@ export type GridActionsCellItemProps = GridActionsCellItemCommonProps & */ closeMenuOnClick?: boolean; closeMenu?: () => void; - } & Omit) + } & Omit) ); const GridActionsCellItem = forwardRef((props, ref) => { diff --git a/packages/x-data-grid/src/components/columnHeaders/GridColumnHeaderFilterIconButton.tsx b/packages/x-data-grid/src/components/columnHeaders/GridColumnHeaderFilterIconButton.tsx index 770a0d754d9d7..46853be122c98 100644 --- a/packages/x-data-grid/src/components/columnHeaders/GridColumnHeaderFilterIconButton.tsx +++ b/packages/x-data-grid/src/components/columnHeaders/GridColumnHeaderFilterIconButton.tsx @@ -71,7 +71,6 @@ function GridColumnHeaderFilterIconButton(props: ColumnHeaderFilterIconButtonPro diff --git a/packages/x-data-grid/src/models/gridBaseSlots.ts b/packages/x-data-grid/src/models/gridBaseSlots.ts index a7343eeb9f8a0..0fd571d9c0ab9 100644 --- a/packages/x-data-grid/src/models/gridBaseSlots.ts +++ b/packages/x-data-grid/src/models/gridBaseSlots.ts @@ -1,17 +1,43 @@ +type Ref = React.RefCallback | React.RefObject | null; + export type BadgeProps = { badgeContent?: React.ReactNode; children: React.ReactNode; color?: 'primary' | 'default' | 'error'; + invisible?: boolean; overlap?: 'circular'; variant?: 'dot'; - invisible?: boolean; + style?: React.CSSProperties; +}; + +export type ButtonProps = { + ref?: Ref; + children?: React.ReactNode; + className?: string; + disabled?: boolean; + id?: string; + onClick?: React.MouseEventHandler; + onKeyDown?: React.KeyboardEventHandler; + role?: string; + size?: 'small' | 'medium' | 'large'; + startIcon?: React.ReactNode; + style?: React.CSSProperties; + tabIndex?: number; + title?: string; + touchRippleRef?: any; // FIXME(v8:romgrk): find a way to remove +}; + +export type IconButtonProps = Omit & { + label?: string; + color?: 'default' | 'inherit' | 'primary'; + edge?: 'start' | 'end' | false; }; export type DividerProps = {}; export type MenuItemProps = { autoFocus?: boolean; - children: React.ReactNode; + children?: React.ReactNode; /** For items that aren't interactive themselves (but may contain an interactive widget) */ inert?: boolean; disabled?: boolean; @@ -20,6 +46,7 @@ export type MenuItemProps = { iconEnd?: React.ReactNode; selected?: boolean; value?: number | string | readonly string[]; + style?: React.CSSProperties; }; export type CircularProgressProps = { diff --git a/packages/x-data-grid/src/models/gridSlotsComponentsProps.ts b/packages/x-data-grid/src/models/gridSlotsComponentsProps.ts index b52a75c08e75e..661671952075d 100644 --- a/packages/x-data-grid/src/models/gridSlotsComponentsProps.ts +++ b/packages/x-data-grid/src/models/gridSlotsComponentsProps.ts @@ -1,5 +1,6 @@ import * as React from 'react'; import type { BadgeProps as MUIBadgeProps } from '@mui/material/Badge'; +import type { ButtonProps as MUIButtonProps } from '@mui/material/Button'; import type { CheckboxProps } from '@mui/material/Checkbox'; import type { CircularProgressProps as MUICircularProgressProps } from '@mui/material/CircularProgress'; import type { LinearProgressProps as MUILinearProgressProps } from '@mui/material/LinearProgress'; @@ -9,8 +10,7 @@ import type { TextFieldProps } from '@mui/material/TextField'; import type { FormControlProps } from '@mui/material/FormControl'; import type { SelectProps } from '@mui/material/Select'; import type { SwitchProps } from '@mui/material/Switch'; -import type { ButtonProps } from '@mui/material/Button'; -import type { IconButtonProps } from '@mui/material/IconButton'; +import type { IconButtonProps as MUIIconButtonProps } from '@mui/material/IconButton'; import type { InputAdornmentProps } from '@mui/material/InputAdornment'; import type { TooltipProps } from '@mui/material/Tooltip'; import type { InputLabelProps } from '@mui/material/InputLabel'; @@ -37,8 +37,10 @@ import type { GridRowCountProps } from '../components/GridRowCount'; import type { GridColumnHeaderSortIconProps } from '../components/columnHeaders/GridColumnHeaderSortIcon'; import type { BadgeProps, + ButtonProps, CircularProgressProps, DividerProps, + IconButtonProps, LinearProgressProps, MenuItemProps, SkeletonProps, @@ -118,8 +120,10 @@ interface BaseSlotProps { interface MaterialSlotProps { baseBadge: MUIBadgeProps; - baseCircularProgress: MUICircularProgressProps; + baseButton: MUIButtonProps; + baseIconButton: MUIIconButtonProps; baseLinearProgress: MUILinearProgressProps; + baseCircularProgress: MUICircularProgressProps; baseMenuItem: MUIMenuItemProps; } From 959dc9de7e7dcf52145219d69a78b05e3eefbf01 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 5 Jan 2025 04:42:38 +0000 Subject: [PATCH 04/25] Bump @types/lodash to ^4.17.14 (#16075) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docs/package.json | 2 +- package.json | 2 +- pnpm-lock.yaml | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/package.json b/docs/package.json index efe046ca7cb89..34e68d454a22e 100644 --- a/docs/package.json +++ b/docs/package.json @@ -109,7 +109,7 @@ "@types/d3-scale-chromatic": "^3.1.0", "@types/doctrine": "^0.0.9", "@types/gtag.js": "^0.0.20", - "@types/lodash": "^4.17.13", + "@types/lodash": "^4.17.14", "@types/luxon": "^3.4.2", "@types/moment-hijri": "^2.1.4", "@types/moment-jalaali": "^0.7.9", diff --git a/package.json b/package.json index f337baa672975..8f928dfb7a50c 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "@types/chai-dom": "^1.11.3", "@types/fs-extra": "^11.0.4", "@types/karma": "^6.3.9", - "@types/lodash": "^4.17.13", + "@types/lodash": "^4.17.14", "@types/mocha": "^10.0.10", "@types/node": "^20.17.10", "@types/react": "^19.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1c33a24c2018d..a90fdc7aabc9f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -135,8 +135,8 @@ importers: specifier: ^6.3.9 version: 6.3.9 '@types/lodash': - specifier: ^4.17.13 - version: 4.17.13 + specifier: ^4.17.14 + version: 4.17.14 '@types/mocha': specifier: ^10.0.10 version: 10.0.10 @@ -667,8 +667,8 @@ importers: specifier: ^0.0.20 version: 0.0.20 '@types/lodash': - specifier: ^4.17.13 - version: 4.17.13 + specifier: ^4.17.14 + version: 4.17.14 '@types/luxon': specifier: ^3.4.2 version: 3.4.2 @@ -4169,8 +4169,8 @@ packages: '@types/katex@0.16.7': resolution: {integrity: sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==} - '@types/lodash@4.17.13': - resolution: {integrity: sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==} + '@types/lodash@4.17.14': + resolution: {integrity: sha512-jsxagdikDiDBeIRaPYtArcT8my4tN1og7MtMRquFT3XNA6axxyHDRUemqDz/taRDdOUn0GnGHRCuff4q48sW9A==} '@types/luxon@3.4.2': resolution: {integrity: sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==} @@ -13297,7 +13297,7 @@ snapshots: '@types/katex@0.16.7': {} - '@types/lodash@4.17.13': {} + '@types/lodash@4.17.14': {} '@types/luxon@3.4.2': {} From 5a267e72343e10df66f44b4c36c61f6693bbeb88 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 5 Jan 2025 04:43:34 +0000 Subject: [PATCH 05/25] Bump @types/node to ^20.17.11 (#16076) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 4 +- packages/rsc-builder/package.json | 2 +- pnpm-lock.yaml | 134 +++++++++++++++--------------- 3 files changed, 70 insertions(+), 70 deletions(-) diff --git a/package.json b/package.json index 8f928dfb7a50c..645567521689a 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "@types/karma": "^6.3.9", "@types/lodash": "^4.17.14", "@types/mocha": "^10.0.10", - "@types/node": "^20.17.10", + "@types/node": "^20.17.11", "@types/react": "^19.0.2", "@types/react-dom": "^19.0.2", "@types/requestidlecallback": "^0.3.7", @@ -198,7 +198,7 @@ }, "resolutions": { "react-is": "^19.0.0", - "@types/node": "^20.17.10" + "@types/node": "^20.17.11" }, "packageManager": "pnpm@9.15.2", "engines": { diff --git a/packages/rsc-builder/package.json b/packages/rsc-builder/package.json index 5771501d07b71..ae162d9556022 100644 --- a/packages/rsc-builder/package.json +++ b/packages/rsc-builder/package.json @@ -9,6 +9,6 @@ }, "devDependencies": { "@types/mocha": "^10.0.10", - "@types/node": "^20.17.10" + "@types/node": "^20.17.11" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a90fdc7aabc9f..0cb3dc0ba3338 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,7 +6,7 @@ settings: overrides: react-is: ^19.0.0 - '@types/node': ^20.17.10 + '@types/node': ^20.17.11 patchedDependencies: babel-plugin-replace-imports@1.0.2: @@ -141,8 +141,8 @@ importers: specifier: ^10.0.10 version: 10.0.10 '@types/node': - specifier: ^20.17.10 - version: 20.17.10 + specifier: ^20.17.11 + version: 20.17.11 '@types/react': specifier: ^19.0.2 version: 19.0.2 @@ -725,8 +725,8 @@ importers: specifier: ^10.0.10 version: 10.0.10 '@types/node': - specifier: ^20.17.10 - version: 20.17.10 + specifier: ^20.17.11 + version: 20.17.11 packages/x-charts: dependencies: @@ -1653,7 +1653,7 @@ importers: devDependencies: '@codspeed/vitest-plugin': specifier: ^4.0.0 - version: 4.0.0(vite@5.4.11(@types/node@20.17.10)(terser@5.36.0))(vitest@2.1.8) + version: 4.0.0(vite@5.4.11(@types/node@20.17.11)(terser@5.36.0))(vitest@2.1.8) '@emotion/react': specifier: ^11.14.0 version: 11.14.0(@types/react@19.0.2)(react@19.0.0) @@ -1674,13 +1674,13 @@ importers: version: 14.5.2(@testing-library/dom@10.4.0) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@5.4.11(@types/node@20.17.10)(terser@5.36.0)) + version: 4.3.4(vite@5.4.11(@types/node@20.17.11)(terser@5.36.0)) '@vitejs/plugin-react-swc': specifier: ^3.7.2 - version: 3.7.2(@swc/helpers@0.5.15)(vite@5.4.11(@types/node@20.17.10)(terser@5.36.0)) + version: 3.7.2(@swc/helpers@0.5.15)(vite@5.4.11(@types/node@20.17.11)(terser@5.36.0)) '@vitest/browser': specifier: 2.1.8 - version: 2.1.8(@types/node@20.17.10)(playwright@1.49.1)(typescript@5.7.2)(vite@5.4.11(@types/node@20.17.10)(terser@5.36.0))(vitest@2.1.8) + version: 2.1.8(@types/node@20.17.11)(playwright@1.49.1)(typescript@5.7.2)(vite@5.4.11(@types/node@20.17.11)(terser@5.36.0))(vitest@2.1.8) '@vitest/ui': specifier: 2.1.8 version: 2.1.8(vitest@2.1.8) @@ -1695,7 +1695,7 @@ importers: version: 19.0.0(react@19.0.0) vitest: specifier: 2.1.8 - version: 2.1.8(@types/node@20.17.10)(@vitest/browser@2.1.8)(@vitest/ui@2.1.8)(jsdom@25.0.1)(msw@2.6.6(@types/node@20.17.10)(typescript@5.7.2))(terser@5.36.0) + version: 2.1.8(@types/node@20.17.11)(@vitest/browser@2.1.8)(@vitest/ui@2.1.8)(jsdom@25.0.1)(msw@2.6.6(@types/node@20.17.11)(typescript@5.7.2))(terser@5.36.0) packages: @@ -3023,7 +3023,7 @@ packages: resolution: {integrity: sha512-KJLUHOaKnNCYzwVbryj3TNBxyZIrr56fR5N45v6K9IPrbT6B7DcudBMfylkV1A8PUdJE15mybkEQyp2/ZUpxUA==} engines: {node: '>=18'} peerDependencies: - '@types/node': ^20.17.10 + '@types/node': ^20.17.11 '@inquirer/core@10.1.0': resolution: {integrity: sha512-I+ETk2AL+yAVbvuKx5AJpQmoaWhpiTFOg/UJb7ZkMAK4blmtG8ATh5ct+T/8xNld0CZG/2UhtkdMwpgvld92XQ==} @@ -3037,7 +3037,7 @@ packages: resolution: {integrity: sha512-+ksJMIy92sOAiAccGpcKZUc3bYO07cADnscIxHBknEm3uNts3movSmBofc1908BNy5edKscxYeAdaX1NXkHS6A==} engines: {node: '>=18'} peerDependencies: - '@types/node': ^20.17.10 + '@types/node': ^20.17.11 '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} @@ -4196,8 +4196,8 @@ packages: '@types/ms@0.7.34': resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} - '@types/node@20.17.10': - resolution: {integrity: sha512-/jrvh5h6NXhEauFFexRin69nA0uHJ5gwk4iDivp/DeoEua3uwCUto6PC86IpRITBOs4+6i2I56K5x5b6WYGXHA==} + '@types/node@20.17.11': + resolution: {integrity: sha512-Ept5glCK35R8yeyIeYlRIZtX6SLRyqMhOFTgj5SOkMpLTdw3SEHI9fHx60xaUZ+V1aJxQJODE+7/j5ocZydYTg==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -10077,7 +10077,7 @@ packages: engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: - '@types/node': ^20.17.10 + '@types/node': ^20.17.11 less: '*' lightningcss: ^1.21.0 sass: '*' @@ -10109,7 +10109,7 @@ packages: hasBin: true peerDependencies: '@edge-runtime/vm': '*' - '@types/node': ^20.17.10 + '@types/node': ^20.17.11 '@vitest/browser': 2.1.8 '@vitest/ui': 2.1.8 happy-dom: '*' @@ -11426,11 +11426,11 @@ snapshots: transitivePeerDependencies: - debug - '@codspeed/vitest-plugin@4.0.0(vite@5.4.11(@types/node@20.17.10)(terser@5.36.0))(vitest@2.1.8)': + '@codspeed/vitest-plugin@4.0.0(vite@5.4.11(@types/node@20.17.11)(terser@5.36.0))(vitest@2.1.8)': dependencies: '@codspeed/core': 4.0.0 - vite: 5.4.11(@types/node@20.17.10)(terser@5.36.0) - vitest: 2.1.8(@types/node@20.17.10)(@vitest/browser@2.1.8)(@vitest/ui@2.1.8)(jsdom@25.0.1)(msw@2.6.6(@types/node@20.17.10)(typescript@5.7.2))(terser@5.36.0) + vite: 5.4.11(@types/node@20.17.11)(terser@5.36.0) + vitest: 2.1.8(@types/node@20.17.11)(@vitest/browser@2.1.8)(@vitest/ui@2.1.8)(jsdom@25.0.1)(msw@2.6.6(@types/node@20.17.11)(typescript@5.7.2))(terser@5.36.0) transitivePeerDependencies: - debug @@ -11739,7 +11739,7 @@ snapshots: '@fast-csv/format@4.3.5': dependencies: - '@types/node': 20.17.10 + '@types/node': 20.17.11 lodash.escaperegexp: 4.1.2 lodash.isboolean: 3.0.3 lodash.isequal: 4.5.0 @@ -11748,7 +11748,7 @@ snapshots: '@fast-csv/parse@4.3.6': dependencies: - '@types/node': 20.17.10 + '@types/node': 20.17.11 lodash.escaperegexp: 4.1.2 lodash.groupby: 4.6.0 lodash.isfunction: 3.0.9 @@ -11887,16 +11887,16 @@ snapshots: '@img/sharp-win32-x64@0.33.5': optional: true - '@inquirer/confirm@5.0.2(@types/node@20.17.10)': + '@inquirer/confirm@5.0.2(@types/node@20.17.11)': dependencies: - '@inquirer/core': 10.1.0(@types/node@20.17.10) - '@inquirer/type': 3.0.1(@types/node@20.17.10) - '@types/node': 20.17.10 + '@inquirer/core': 10.1.0(@types/node@20.17.11) + '@inquirer/type': 3.0.1(@types/node@20.17.11) + '@types/node': 20.17.11 - '@inquirer/core@10.1.0(@types/node@20.17.10)': + '@inquirer/core@10.1.0(@types/node@20.17.11)': dependencies: '@inquirer/figures': 1.0.8 - '@inquirer/type': 3.0.1(@types/node@20.17.10) + '@inquirer/type': 3.0.1(@types/node@20.17.11) ansi-escapes: 4.3.2 cli-width: 4.1.0 mute-stream: 2.0.0 @@ -11909,9 +11909,9 @@ snapshots: '@inquirer/figures@1.0.8': {} - '@inquirer/type@3.0.1(@types/node@20.17.10)': + '@inquirer/type@3.0.1(@types/node@20.17.11)': dependencies: - '@types/node': 20.17.10 + '@types/node': 20.17.11 '@isaacs/cliui@8.0.2': dependencies: @@ -13017,14 +13017,14 @@ snapshots: '@slack/logger@4.0.0': dependencies: - '@types/node': 20.17.10 + '@types/node': 20.17.11 '@slack/oauth@3.0.2': dependencies: '@slack/logger': 4.0.0 '@slack/web-api': 7.8.0 '@types/jsonwebtoken': 9.0.7 - '@types/node': 20.17.10 + '@types/node': 20.17.11 jsonwebtoken: 9.0.2 lodash.isstring: 4.0.1 transitivePeerDependencies: @@ -13034,7 +13034,7 @@ snapshots: dependencies: '@slack/logger': 4.0.0 '@slack/web-api': 7.8.0 - '@types/node': 20.17.10 + '@types/node': 20.17.11 '@types/ws': 8.5.13 eventemitter3: 5.0.1 ws: 8.18.0 @@ -13049,7 +13049,7 @@ snapshots: dependencies: '@slack/logger': 4.0.0 '@slack/types': 2.14.0 - '@types/node': 20.17.10 + '@types/node': 20.17.11 '@types/retry': 0.12.0 axios: 1.7.8(debug@4.3.7) eventemitter3: 5.0.1 @@ -13208,7 +13208,7 @@ snapshots: '@types/cors@2.8.17': dependencies: - '@types/node': 20.17.10 + '@types/node': 20.17.11 '@types/d3-array@3.2.1': {} @@ -13261,7 +13261,7 @@ snapshots: '@types/fs-extra@11.0.4': dependencies: '@types/jsonfile': 6.1.4 - '@types/node': 20.17.10 + '@types/node': 20.17.11 '@types/gtag.js@0.0.20': {} @@ -13282,15 +13282,15 @@ snapshots: '@types/jsonfile@6.1.4': dependencies: - '@types/node': 20.17.10 + '@types/node': 20.17.11 '@types/jsonwebtoken@9.0.7': dependencies: - '@types/node': 20.17.10 + '@types/node': 20.17.11 '@types/karma@6.3.9': dependencies: - '@types/node': 20.17.10 + '@types/node': 20.17.11 log4js: 6.9.1 transitivePeerDependencies: - supports-color @@ -13321,7 +13321,7 @@ snapshots: '@types/ms@0.7.34': {} - '@types/node@20.17.10': + '@types/node@20.17.11': dependencies: undici-types: 6.19.8 @@ -13386,7 +13386,7 @@ snapshots: '@types/webpack-bundle-analyzer@4.7.0(@swc/core@1.9.3(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1))': dependencies: - '@types/node': 20.17.10 + '@types/node': 20.17.11 tapable: 2.2.1 webpack: 5.97.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) transitivePeerDependencies: @@ -13397,7 +13397,7 @@ snapshots: '@types/ws@8.5.13': dependencies: - '@types/node': 20.17.10 + '@types/node': 20.17.11 '@types/yargs-parser@21.0.3': {} @@ -13527,35 +13527,35 @@ snapshots: '@ungap/structured-clone@1.2.0': {} - '@vitejs/plugin-react-swc@3.7.2(@swc/helpers@0.5.15)(vite@5.4.11(@types/node@20.17.10)(terser@5.36.0))': + '@vitejs/plugin-react-swc@3.7.2(@swc/helpers@0.5.15)(vite@5.4.11(@types/node@20.17.11)(terser@5.36.0))': dependencies: '@swc/core': 1.9.3(@swc/helpers@0.5.15) - vite: 5.4.11(@types/node@20.17.10)(terser@5.36.0) + vite: 5.4.11(@types/node@20.17.11)(terser@5.36.0) transitivePeerDependencies: - '@swc/helpers' - '@vitejs/plugin-react@4.3.4(vite@5.4.11(@types/node@20.17.10)(terser@5.36.0))': + '@vitejs/plugin-react@4.3.4(vite@5.4.11(@types/node@20.17.11)(terser@5.36.0))': dependencies: '@babel/core': 7.26.0 '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0) '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 - vite: 5.4.11(@types/node@20.17.10)(terser@5.36.0) + vite: 5.4.11(@types/node@20.17.11)(terser@5.36.0) transitivePeerDependencies: - supports-color - '@vitest/browser@2.1.8(@types/node@20.17.10)(playwright@1.49.1)(typescript@5.7.2)(vite@5.4.11(@types/node@20.17.10)(terser@5.36.0))(vitest@2.1.8)': + '@vitest/browser@2.1.8(@types/node@20.17.11)(playwright@1.49.1)(typescript@5.7.2)(vite@5.4.11(@types/node@20.17.11)(terser@5.36.0))(vitest@2.1.8)': dependencies: '@testing-library/dom': 10.4.0 '@testing-library/user-event': 14.5.2(@testing-library/dom@10.4.0) - '@vitest/mocker': 2.1.8(msw@2.6.6(@types/node@20.17.10)(typescript@5.7.2))(vite@5.4.11(@types/node@20.17.10)(terser@5.36.0)) + '@vitest/mocker': 2.1.8(msw@2.6.6(@types/node@20.17.11)(typescript@5.7.2))(vite@5.4.11(@types/node@20.17.11)(terser@5.36.0)) '@vitest/utils': 2.1.8 magic-string: 0.30.14 - msw: 2.6.6(@types/node@20.17.10)(typescript@5.7.2) + msw: 2.6.6(@types/node@20.17.11)(typescript@5.7.2) sirv: 3.0.0 tinyrainbow: 1.2.0 - vitest: 2.1.8(@types/node@20.17.10)(@vitest/browser@2.1.8)(@vitest/ui@2.1.8)(jsdom@25.0.1)(msw@2.6.6(@types/node@20.17.10)(typescript@5.7.2))(terser@5.36.0) + vitest: 2.1.8(@types/node@20.17.11)(@vitest/browser@2.1.8)(@vitest/ui@2.1.8)(jsdom@25.0.1)(msw@2.6.6(@types/node@20.17.11)(typescript@5.7.2))(terser@5.36.0) ws: 8.18.0 optionalDependencies: playwright: 1.49.1 @@ -13573,14 +13573,14 @@ snapshots: chai: 5.1.2 tinyrainbow: 1.2.0 - '@vitest/mocker@2.1.8(msw@2.6.6(@types/node@20.17.10)(typescript@5.7.2))(vite@5.4.11(@types/node@20.17.10)(terser@5.36.0))': + '@vitest/mocker@2.1.8(msw@2.6.6(@types/node@20.17.11)(typescript@5.7.2))(vite@5.4.11(@types/node@20.17.11)(terser@5.36.0))': dependencies: '@vitest/spy': 2.1.8 estree-walker: 3.0.3 magic-string: 0.30.14 optionalDependencies: - msw: 2.6.6(@types/node@20.17.10)(typescript@5.7.2) - vite: 5.4.11(@types/node@20.17.10)(terser@5.36.0) + msw: 2.6.6(@types/node@20.17.11)(typescript@5.7.2) + vite: 5.4.11(@types/node@20.17.11)(terser@5.36.0) '@vitest/pretty-format@2.1.8': dependencies: @@ -13610,7 +13610,7 @@ snapshots: sirv: 3.0.0 tinyglobby: 0.2.10 tinyrainbow: 1.2.0 - vitest: 2.1.8(@types/node@20.17.10)(@vitest/browser@2.1.8)(@vitest/ui@2.1.8)(jsdom@25.0.1)(msw@2.6.6(@types/node@20.17.10)(typescript@5.7.2))(terser@5.36.0) + vitest: 2.1.8(@types/node@20.17.11)(@vitest/browser@2.1.8)(@vitest/ui@2.1.8)(jsdom@25.0.1)(msw@2.6.6(@types/node@20.17.11)(typescript@5.7.2))(terser@5.36.0) '@vitest/utils@2.1.8': dependencies: @@ -15187,7 +15187,7 @@ snapshots: dependencies: '@types/cookie': 0.4.1 '@types/cors': 2.8.17 - '@types/node': 20.17.10 + '@types/node': 20.17.11 accepts: 1.3.8 base64id: 2.0.0 cookie: 0.7.2 @@ -16911,7 +16911,7 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 20.17.10 + '@types/node': 20.17.11 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -18027,12 +18027,12 @@ snapshots: ms@2.1.3: {} - msw@2.6.6(@types/node@20.17.10)(typescript@5.7.2): + msw@2.6.6(@types/node@20.17.11)(typescript@5.7.2): dependencies: '@bundled-es-modules/cookie': 2.0.1 '@bundled-es-modules/statuses': 1.0.1 '@bundled-es-modules/tough-cookie': 0.1.6 - '@inquirer/confirm': 5.0.2(@types/node@20.17.10) + '@inquirer/confirm': 5.0.2(@types/node@20.17.11) '@mswjs/interceptors': 0.37.3 '@open-draft/deferred-promise': 2.2.0 '@open-draft/until': 2.1.0 @@ -20326,13 +20326,13 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.2 - vite-node@2.1.8(@types/node@20.17.10)(terser@5.36.0): + vite-node@2.1.8(@types/node@20.17.11)(terser@5.36.0): dependencies: cac: 6.7.14 debug: 4.3.7(supports-color@8.1.1) es-module-lexer: 1.5.4 pathe: 1.1.2 - vite: 5.4.11(@types/node@20.17.10)(terser@5.36.0) + vite: 5.4.11(@types/node@20.17.11)(terser@5.36.0) transitivePeerDependencies: - '@types/node' - less @@ -20344,20 +20344,20 @@ snapshots: - supports-color - terser - vite@5.4.11(@types/node@20.17.10)(terser@5.36.0): + vite@5.4.11(@types/node@20.17.11)(terser@5.36.0): dependencies: esbuild: 0.21.5 postcss: 8.4.49 rollup: 4.28.0 optionalDependencies: - '@types/node': 20.17.10 + '@types/node': 20.17.11 fsevents: 2.3.3 terser: 5.36.0 - vitest@2.1.8(@types/node@20.17.10)(@vitest/browser@2.1.8)(@vitest/ui@2.1.8)(jsdom@25.0.1)(msw@2.6.6(@types/node@20.17.10)(typescript@5.7.2))(terser@5.36.0): + vitest@2.1.8(@types/node@20.17.11)(@vitest/browser@2.1.8)(@vitest/ui@2.1.8)(jsdom@25.0.1)(msw@2.6.6(@types/node@20.17.11)(typescript@5.7.2))(terser@5.36.0): dependencies: '@vitest/expect': 2.1.8 - '@vitest/mocker': 2.1.8(msw@2.6.6(@types/node@20.17.10)(typescript@5.7.2))(vite@5.4.11(@types/node@20.17.10)(terser@5.36.0)) + '@vitest/mocker': 2.1.8(msw@2.6.6(@types/node@20.17.11)(typescript@5.7.2))(vite@5.4.11(@types/node@20.17.11)(terser@5.36.0)) '@vitest/pretty-format': 2.1.8 '@vitest/runner': 2.1.8 '@vitest/snapshot': 2.1.8 @@ -20373,12 +20373,12 @@ snapshots: tinyexec: 0.3.1 tinypool: 1.0.2 tinyrainbow: 1.2.0 - vite: 5.4.11(@types/node@20.17.10)(terser@5.36.0) - vite-node: 2.1.8(@types/node@20.17.10)(terser@5.36.0) + vite: 5.4.11(@types/node@20.17.11)(terser@5.36.0) + vite-node: 2.1.8(@types/node@20.17.11)(terser@5.36.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 20.17.10 - '@vitest/browser': 2.1.8(@types/node@20.17.10)(playwright@1.49.1)(typescript@5.7.2)(vite@5.4.11(@types/node@20.17.10)(terser@5.36.0))(vitest@2.1.8) + '@types/node': 20.17.11 + '@vitest/browser': 2.1.8(@types/node@20.17.11)(playwright@1.49.1)(typescript@5.7.2)(vite@5.4.11(@types/node@20.17.11)(terser@5.36.0))(vitest@2.1.8) '@vitest/ui': 2.1.8(vitest@2.1.8) jsdom: 25.0.1 transitivePeerDependencies: From 0219cb4649aa4bbc241c5e8868c97c1f4975edba Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 11:00:43 +0200 Subject: [PATCH 06/25] Bump MUI Internal (#16077) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docs/package.json | 4 +- package.json | 4 +- packages/x-charts/package.json | 2 +- packages/x-data-grid-premium/package.json | 2 +- packages/x-data-grid-pro/package.json | 2 +- packages/x-data-grid/package.json | 2 +- packages/x-date-pickers-pro/package.json | 2 +- packages/x-date-pickers/package.json | 2 +- packages/x-internals/package.json | 2 +- packages/x-license/package.json | 2 +- packages/x-tree-view-pro/package.json | 2 +- packages/x-tree-view/package.json | 2 +- pnpm-lock.yaml | 82 +++++++++++------------ 13 files changed, 55 insertions(+), 55 deletions(-) diff --git a/docs/package.json b/docs/package.json index 34e68d454a22e..56275eefa52d0 100644 --- a/docs/package.json +++ b/docs/package.json @@ -27,7 +27,7 @@ "@emotion/react": "^11.14.0", "@emotion/server": "^11.11.0", "@emotion/styled": "^11.14.0", - "@mui/docs": "6.3.0", + "@mui/docs": "6.3.1", "@mui/icons-material": "^5.16.13", "@mui/joy": "^5.0.0-beta.51", "@mui/lab": "^5.0.0-alpha.175", @@ -103,7 +103,7 @@ "@babel/plugin-transform-react-constant-elements": "^7.25.9", "@babel/preset-typescript": "^7.26.0", "@mui/internal-docs-utils": "^1.0.16", - "@mui/internal-scripts": "^1.0.31", + "@mui/internal-scripts": "^1.0.32", "@types/chance": "^1.1.6", "@types/d3-scale": "^4.0.8", "@types/d3-scale-chromatic": "^3.1.0", diff --git a/package.json b/package.json index 645567521689a..7c06cac6489a4 100644 --- a/package.json +++ b/package.json @@ -92,8 +92,8 @@ "@emotion/styled": "^11.14.0", "@mui/icons-material": "^5.16.13", "@mui/internal-babel-plugin-resolve-imports": "1.0.20", - "@mui/internal-markdown": "^1.0.23", - "@mui/internal-test-utils": "^1.0.24", + "@mui/internal-markdown": "^1.0.24", + "@mui/internal-test-utils": "^1.0.25", "@mui/material": "^5.16.13", "@mui/monorepo": "github:mui/material-ui#84d6ecfdccd10f204854beeef98bcc55dc99d117", "@mui/utils": "^5.16.13", diff --git a/packages/x-charts/package.json b/packages/x-charts/package.json index 0bfe2131f2c82..03562671c5200 100644 --- a/packages/x-charts/package.json +++ b/packages/x-charts/package.json @@ -68,7 +68,7 @@ } }, "devDependencies": { - "@mui/internal-test-utils": "^1.0.24", + "@mui/internal-test-utils": "^1.0.25", "@mui/material": "^5.16.13", "@mui/system": "^5.16.13", "@react-spring/core": "^9.7.5", diff --git a/packages/x-data-grid-premium/package.json b/packages/x-data-grid-premium/package.json index 73bdb0cb5118d..ac32b9aa1bd2f 100644 --- a/packages/x-data-grid-premium/package.json +++ b/packages/x-data-grid-premium/package.json @@ -72,7 +72,7 @@ } }, "devDependencies": { - "@mui/internal-test-utils": "^1.0.24", + "@mui/internal-test-utils": "^1.0.25", "@mui/material": "^5.16.13", "@mui/system": "^5.16.13", "@types/prop-types": "^15.7.14", diff --git a/packages/x-data-grid-pro/package.json b/packages/x-data-grid-pro/package.json index c7cabcdbff200..107890045a297 100644 --- a/packages/x-data-grid-pro/package.json +++ b/packages/x-data-grid-pro/package.json @@ -70,7 +70,7 @@ } }, "devDependencies": { - "@mui/internal-test-utils": "^1.0.24", + "@mui/internal-test-utils": "^1.0.25", "@mui/material": "^5.16.13", "@mui/system": "^5.16.13", "@types/prop-types": "^15.7.14", diff --git a/packages/x-data-grid/package.json b/packages/x-data-grid/package.json index 5df048b82a6a8..572fc9b3efff6 100644 --- a/packages/x-data-grid/package.json +++ b/packages/x-data-grid/package.json @@ -71,7 +71,7 @@ } }, "devDependencies": { - "@mui/internal-test-utils": "^1.0.24", + "@mui/internal-test-utils": "^1.0.25", "@mui/material": "^5.16.13", "@mui/system": "^5.16.13", "@mui/types": "^7.2.20", diff --git a/packages/x-date-pickers-pro/package.json b/packages/x-date-pickers-pro/package.json index a3dcf4d339a96..1931477618f5f 100644 --- a/packages/x-date-pickers-pro/package.json +++ b/packages/x-date-pickers-pro/package.json @@ -96,7 +96,7 @@ } }, "devDependencies": { - "@mui/internal-test-utils": "^1.0.24", + "@mui/internal-test-utils": "^1.0.25", "@mui/material": "^5.16.13", "@mui/system": "^5.16.13", "@types/luxon": "^3.4.2", diff --git a/packages/x-date-pickers/package.json b/packages/x-date-pickers/package.json index 264cacf9d5eac..2b456b6dc6186 100644 --- a/packages/x-date-pickers/package.json +++ b/packages/x-date-pickers/package.json @@ -98,7 +98,7 @@ } }, "devDependencies": { - "@mui/internal-test-utils": "^1.0.24", + "@mui/internal-test-utils": "^1.0.25", "@mui/material": "^5.16.13", "@mui/system": "^5.16.13", "@types/luxon": "^3.4.2", diff --git a/packages/x-internals/package.json b/packages/x-internals/package.json index fc896cfb28211..429678f13ed90 100644 --- a/packages/x-internals/package.json +++ b/packages/x-internals/package.json @@ -48,7 +48,7 @@ "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "devDependencies": { - "@mui/internal-test-utils": "^1.0.24", + "@mui/internal-test-utils": "^1.0.25", "rimraf": "^6.0.1" }, "engines": { diff --git a/packages/x-license/package.json b/packages/x-license/package.json index 31d1c10136d62..25e1d6ea4af62 100644 --- a/packages/x-license/package.json +++ b/packages/x-license/package.json @@ -41,7 +41,7 @@ "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "devDependencies": { - "@mui/internal-test-utils": "^1.0.24", + "@mui/internal-test-utils": "^1.0.25", "rimraf": "^6.0.1" }, "engines": { diff --git a/packages/x-tree-view-pro/package.json b/packages/x-tree-view-pro/package.json index 207de28b10a90..5b269168b652a 100644 --- a/packages/x-tree-view-pro/package.json +++ b/packages/x-tree-view-pro/package.json @@ -72,7 +72,7 @@ } }, "devDependencies": { - "@mui/internal-test-utils": "^1.0.24", + "@mui/internal-test-utils": "^1.0.25", "@mui/material": "^5.16.13", "@mui/system": "^5.16.13", "@types/prop-types": "^15.7.14", diff --git a/packages/x-tree-view/package.json b/packages/x-tree-view/package.json index f61f2f25eefbc..bc8cfb25a0d8e 100644 --- a/packages/x-tree-view/package.json +++ b/packages/x-tree-view/package.json @@ -70,7 +70,7 @@ } }, "devDependencies": { - "@mui/internal-test-utils": "^1.0.24", + "@mui/internal-test-utils": "^1.0.25", "@mui/material": "^5.16.13", "@mui/system": "^5.16.13", "@types/prop-types": "^15.7.14", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0cb3dc0ba3338..488bcfa998a2e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -90,11 +90,11 @@ importers: specifier: 1.0.20 version: 1.0.20(@babel/core@7.26.0) '@mui/internal-markdown': - specifier: ^1.0.23 - version: 1.0.23 - '@mui/internal-test-utils': specifier: ^1.0.24 - version: 1.0.24(@babel/core@7.26.0)(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: 1.0.24 + '@mui/internal-test-utils': + specifier: ^1.0.25 + version: 1.0.25(@babel/core@7.26.0)(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@mui/material': specifier: ^5.16.13 version: 5.16.13(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -426,8 +426,8 @@ importers: specifier: ^11.14.0 version: 11.14.0(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0) '@mui/docs': - specifier: 6.3.0 - version: 6.3.0(blv5x5f4uwinouobypxmqapbba) + specifier: 6.3.1 + version: 6.3.1(blv5x5f4uwinouobypxmqapbba) '@mui/icons-material': specifier: ^5.16.13 version: 5.16.13(@mui/material@5.16.13(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.2)(react@19.0.0) @@ -649,8 +649,8 @@ importers: specifier: ^1.0.16 version: 1.0.16 '@mui/internal-scripts': - specifier: ^1.0.31 - version: 1.0.31 + specifier: ^1.0.32 + version: 1.0.32 '@types/chance': specifier: ^1.1.6 version: 1.1.6 @@ -777,8 +777,8 @@ importers: version: 1.4.0(react@19.0.0) devDependencies: '@mui/internal-test-utils': - specifier: ^1.0.24 - version: 1.0.24(@babel/core@7.26.0)(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: ^1.0.25 + version: 1.0.25(@babel/core@7.26.0)(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@mui/material': specifier: ^5.16.13 version: 5.16.13(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -1030,8 +1030,8 @@ importers: version: 5.1.1 devDependencies: '@mui/internal-test-utils': - specifier: ^1.0.24 - version: 1.0.24(@babel/core@7.26.0)(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: ^1.0.25 + version: 1.0.25(@babel/core@7.26.0)(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@mui/material': specifier: ^5.16.13 version: 5.16.13(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -1139,8 +1139,8 @@ importers: version: 5.1.1 devDependencies: '@mui/internal-test-utils': - specifier: ^1.0.24 - version: 1.0.24(@babel/core@7.26.0)(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: ^1.0.25 + version: 1.0.25(@babel/core@7.26.0)(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@mui/material': specifier: ^5.16.13 version: 5.16.13(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -1201,8 +1201,8 @@ importers: version: 5.1.1 devDependencies: '@mui/internal-test-utils': - specifier: ^1.0.24 - version: 1.0.24(@babel/core@7.26.0)(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: ^1.0.25 + version: 1.0.25(@babel/core@7.26.0)(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@mui/material': specifier: ^5.16.13 version: 5.16.13(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -1254,8 +1254,8 @@ importers: version: 4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) devDependencies: '@mui/internal-test-utils': - specifier: ^1.0.24 - version: 1.0.24(@babel/core@7.26.0)(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: ^1.0.25 + version: 1.0.25(@babel/core@7.26.0)(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@mui/material': specifier: ^5.16.13 version: 5.16.13(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -1349,8 +1349,8 @@ importers: version: 4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) devDependencies: '@mui/internal-test-utils': - specifier: ^1.0.24 - version: 1.0.24(@babel/core@7.26.0)(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: ^1.0.25 + version: 1.0.25(@babel/core@7.26.0)(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@mui/material': specifier: ^5.16.13 version: 5.16.13(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -1396,8 +1396,8 @@ importers: version: 19.0.0 devDependencies: '@mui/internal-test-utils': - specifier: ^1.0.24 - version: 1.0.24(@babel/core@7.26.0)(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: ^1.0.25 + version: 1.0.25(@babel/core@7.26.0)(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) rimraf: specifier: ^6.0.1 version: 6.0.1 @@ -1416,8 +1416,8 @@ importers: version: 19.0.0 devDependencies: '@mui/internal-test-utils': - specifier: ^1.0.24 - version: 1.0.24(@babel/core@7.26.0)(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: ^1.0.25 + version: 1.0.25(@babel/core@7.26.0)(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) rimraf: specifier: ^6.0.1 version: 6.0.1 @@ -1466,8 +1466,8 @@ importers: version: 1.4.0(react@19.0.0) devDependencies: '@mui/internal-test-utils': - specifier: ^1.0.24 - version: 1.0.24(@babel/core@7.26.0)(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: ^1.0.25 + version: 1.0.25(@babel/core@7.26.0)(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@mui/material': specifier: ^5.16.13 version: 5.16.13(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -1534,8 +1534,8 @@ importers: version: 1.4.0(react@19.0.0) devDependencies: '@mui/internal-test-utils': - specifier: ^1.0.24 - version: 1.0.24(@babel/core@7.26.0)(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: ^1.0.25 + version: 1.0.25(@babel/core@7.26.0)(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@mui/material': specifier: ^5.16.13 version: 5.16.13(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -3101,8 +3101,8 @@ packages: '@mui/core-downloads-tracker@5.16.13': resolution: {integrity: sha512-xe5RwI0Q2O709Bd2Y7l1W1NIwNmln0y+xaGk5VgX3vDJbkQEqzdfTFZ73e0CkEZgJwyiWgk5HY0l8R4nysOxjw==} - '@mui/docs@6.3.0': - resolution: {integrity: sha512-JA3gVXUgstlb+RtacUx+x+oqdYP5+FNb4mQVuDu+nNfGYtb4gMjakZYriW0dBWw2jq/n9YXHjabf4QFil8HKfg==} + '@mui/docs@6.3.1': + resolution: {integrity: sha512-0JqU2+dEKX1b0MZTDG4qM+iiW5wgapwzq8Q1Joehlq91PrW9atddbKIDUpFdy7MY+DKSFDNB+QRT+pez42PGWA==} engines: {node: '>=14.0.0'} peerDependencies: '@mui/base': '*' @@ -3137,14 +3137,14 @@ packages: '@mui/internal-docs-utils@1.0.16': resolution: {integrity: sha512-GEq4dG9+10WGlQVrmXUfCWNe1FiWoMr2KXbgn2/00Da5hdvp4nIa3PXYYZF08Wh+FtnBbLHKGkPmZ7iw9WKtjQ==} - '@mui/internal-markdown@1.0.23': - resolution: {integrity: sha512-TX8RQR2w36NSWCWWWR0828bXUjYCn9RXJ4gq2/+95O67iIAQPwST0ZsIGAqIqjQU116oPefMbdID9nMAFrIV2A==} + '@mui/internal-markdown@1.0.24': + resolution: {integrity: sha512-bFjygozW3vhmnct9COgysXv5+afLzDgdt30LVUgPeDSaxZbAfSoyD0Q/b848Zl5WEaXpKrzg0TVKPoE8XAGoIg==} - '@mui/internal-scripts@1.0.31': - resolution: {integrity: sha512-I7Rw7AU064l8HCnR6SOwhlOpjwo7kEW8stIjp+HwTJ8PEUH0qWGV20it6Vvtau6zgGI3r9+t66z7tibsUNZ47Q==} + '@mui/internal-scripts@1.0.32': + resolution: {integrity: sha512-iYccvD8q4KB4VhX1DTNdSlvGTfkZBMoQ3JfKbEphQCAyLU8Fwb9FfCt1aJC71ViXyHzmGwEKuLRyDzBh7C3BOg==} - '@mui/internal-test-utils@1.0.24': - resolution: {integrity: sha512-+5FmCTcyBirtjG13nb72KOWhLf6fv98M57BSdnGoItEeJdLUpjLqh4DTVg3S0DP8tzNPSz+aQomJpsID2edHOQ==} + '@mui/internal-test-utils@1.0.25': + resolution: {integrity: sha512-j2FxdN9qMD+jJoeIPPXr/mmPGblDfUY37NwGDxh+tnhzRMql8NltoO0CBQ3eEyW9y0hYJC+xOuvwPjm/UI410Q==} peerDependencies: react: ^19.0.0 react-dom: ^19.0.0 @@ -12068,12 +12068,12 @@ snapshots: '@mui/core-downloads-tracker@5.16.13': {} - '@mui/docs@6.3.0(blv5x5f4uwinouobypxmqapbba)': + '@mui/docs@6.3.1(blv5x5f4uwinouobypxmqapbba)': dependencies: '@babel/runtime': 7.26.0 '@mui/base': 5.0.0-beta.40-0(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@mui/icons-material': 5.16.13(@mui/material@5.16.13(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.2)(react@19.0.0) - '@mui/internal-markdown': 1.0.23 + '@mui/internal-markdown': 1.0.24 '@mui/material': 5.16.13(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@mui/system': 5.16.13(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0) chai: 5.1.2 @@ -12105,14 +12105,14 @@ snapshots: rimraf: 6.0.1 typescript: 5.7.2 - '@mui/internal-markdown@1.0.23': + '@mui/internal-markdown@1.0.24': dependencies: '@babel/runtime': 7.26.0 lodash: 4.17.21 marked: 15.0.4 prismjs: 1.29.0 - '@mui/internal-scripts@1.0.31': + '@mui/internal-scripts@1.0.32': dependencies: '@babel/core': 7.26.0 '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.26.0) @@ -12127,7 +12127,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@mui/internal-test-utils@1.0.24(@babel/core@7.26.0)(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@mui/internal-test-utils@1.0.25(@babel/core@7.26.0)(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@babel/plugin-transform-modules-commonjs': 7.26.3(@babel/core@7.26.0) '@babel/preset-typescript': 7.26.0(@babel/core@7.26.0) From 7c41d425dccfd48f4508396eda7e9172c0e07691 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 11:04:23 +0200 Subject: [PATCH 07/25] Bump styled-components to ^6.1.14 (#16080) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docs/package.json | 2 +- pnpm-lock.yaml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/package.json b/docs/package.json index 56275eefa52d0..a17df142e9b5f 100644 --- a/docs/package.json +++ b/docs/package.json @@ -94,7 +94,7 @@ "rifm": "0.12.1", "rimraf": "^6.0.1", "rxjs": "^7.8.1", - "styled-components": "^6.1.13", + "styled-components": "^6.1.14", "stylis": "^4.3.4", "stylis-plugin-rtl": "^2.1.1", "webpack-bundle-analyzer": "^4.10.2" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 488bcfa998a2e..639562292bede 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -627,8 +627,8 @@ importers: specifier: ^7.8.1 version: 7.8.1 styled-components: - specifier: ^6.1.13 - version: 6.1.13(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: ^6.1.14 + version: 6.1.14(react-dom@19.0.0(react@19.0.0))(react@19.0.0) stylis: specifier: ^4.3.4 version: 4.3.4 @@ -9536,8 +9536,8 @@ packages: engines: {node: '>=4'} hasBin: true - styled-components@6.1.13: - resolution: {integrity: sha512-M0+N2xSnAtwcVAQeFEsGWFFxXDftHUD7XrKla06QbpUMmbmtFBMMTcKWvFXtWxuD5qQkB8iU5gk6QASlx2ZRMw==} + styled-components@6.1.14: + resolution: {integrity: sha512-KtfwhU5jw7UoxdM0g6XU9VZQFV4do+KrM8idiVCH5h4v49W+3p3yMe0icYwJgZQZepa5DbH04Qv8P0/RdcLcgg==} engines: {node: '>= 16'} peerDependencies: react: '>= 16.8.0' @@ -19814,7 +19814,7 @@ snapshots: minimist: 1.2.8 through: 2.3.8 - styled-components@6.1.13(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + styled-components@6.1.14(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: '@emotion/is-prop-valid': 1.2.2 '@emotion/unitless': 0.8.1 From b80d266f875ad597935bf7702f39f36c17d3b97c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 11:09:21 +0200 Subject: [PATCH 08/25] Bump @tanstack/query-core to ^5.62.15 (#16074) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docs/package.json | 2 +- pnpm-lock.yaml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/package.json b/docs/package.json index a17df142e9b5f..16a0d8e0fafac 100644 --- a/docs/package.json +++ b/docs/package.json @@ -46,7 +46,7 @@ "@mui/x-date-pickers-pro": "workspace:*", "@mui/x-tree-view": "workspace:*", "@react-spring/web": "^9.7.5", - "@tanstack/query-core": "^5.62.9", + "@tanstack/query-core": "^5.62.15", "ast-types": "^0.14.2", "autoprefixer": "^10.4.20", "babel-plugin-module-resolver": "^5.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 639562292bede..9cb56676bad19 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -483,8 +483,8 @@ importers: specifier: ^9.7.5 version: 9.7.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@tanstack/query-core': - specifier: ^5.62.9 - version: 5.62.9 + specifier: ^5.62.15 + version: 5.62.15 ast-types: specifier: ^0.14.2 version: 0.14.2 @@ -4002,8 +4002,8 @@ packages: '@swc/types@0.1.17': resolution: {integrity: sha512-V5gRru+aD8YVyCOMAjMpWR1Ui577DD5KSJsHP8RAxopAH22jFz6GZd/qxqjO6MJHQhcsjvjOFXyDhyLQUnMveQ==} - '@tanstack/query-core@5.62.9': - resolution: {integrity: sha512-lwePd8hNYhyQ4nM/iRQ+Wz2cDtspGeZZHFZmCzHJ7mfKXt+9S301fULiY2IR2byJYY6Z03T427E5PoVfMexHjw==} + '@tanstack/query-core@5.62.15': + resolution: {integrity: sha512-wT20X14CxcWY8YLJ/1pnsXn/y1Q2uRJZYWW93PWRtZt+3/JlGZyiyTcO4pGnqycnP7CokCROAyatsraosqZsDA==} '@testing-library/dom@10.4.0': resolution: {integrity: sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==} @@ -13121,7 +13121,7 @@ snapshots: dependencies: '@swc/counter': 0.1.3 - '@tanstack/query-core@5.62.9': {} + '@tanstack/query-core@5.62.15': {} '@testing-library/dom@10.4.0': dependencies: From 5189633e1d36164fd934b5597f336cfb30c51310 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 11:15:50 +0200 Subject: [PATCH 09/25] Bump concurrently to ^9.1.2 (#16078) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 7c06cac6489a4..4df51ea292e28 100644 --- a/package.json +++ b/package.json @@ -130,7 +130,7 @@ "chai": "^4.5.0", "chai-dom": "^1.12.0", "compression-webpack-plugin": "^11.1.0", - "concurrently": "^9.1.1", + "concurrently": "^9.1.2", "cpy-cli": "^5.0.0", "cross-env": "^7.0.3", "danger": "^12.3.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9cb56676bad19..68214af2d10fd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -204,8 +204,8 @@ importers: specifier: ^11.1.0 version: 11.1.0(webpack@5.97.1) concurrently: - specifier: ^9.1.1 - version: 9.1.1 + specifier: ^9.1.2 + version: 9.1.2 cpy-cli: specifier: ^5.0.0 version: 5.0.0 @@ -5303,8 +5303,8 @@ packages: resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==} engines: {'0': node >= 6.0} - concurrently@9.1.1: - resolution: {integrity: sha512-6VX8lrBIycgZKTwBsWS+bLrmkGRkDmvtGsYylRN9b93CygN6CbK46HmnQ3rdSOR8HRjdahDrxb5MqD9cEFOg5Q==} + concurrently@9.1.2: + resolution: {integrity: sha512-H9MWcoPsYddwbOGM6difjVwVZHl63nwMEwDJG/L7VGtuaJhb12h2caPG2tVPWs7emuYix252iGfqOyrz1GczTQ==} engines: {node: '>=18'} hasBin: true @@ -14622,7 +14622,7 @@ snapshots: readable-stream: 3.6.2 typedarray: 0.0.6 - concurrently@9.1.1: + concurrently@9.1.2: dependencies: chalk: 4.1.2 lodash: 4.17.21 From 82cf0ed3ae0738e1d21da3a09d75a0360398111d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 11:20:02 +0200 Subject: [PATCH 10/25] Bump markdownlint-cli2 to ^0.17.1 (#16079) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 25 +++++++++++++------------ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 4df51ea292e28..38dafae52f9d5 100644 --- a/package.json +++ b/package.json @@ -170,7 +170,7 @@ "karma-webpack": "^5.0.1", "lerna": "^8.1.9", "lodash": "^4.17.21", - "markdownlint-cli2": "^0.17.0", + "markdownlint-cli2": "^0.17.1", "mocha": "^11.0.1", "moment": "^2.30.1", "moment-timezone": "^0.5.46", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 68214af2d10fd..25d6c951a5691 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -324,8 +324,8 @@ importers: specifier: ^4.17.21 version: 4.17.21 markdownlint-cli2: - specifier: ^0.17.0 - version: 0.17.0 + specifier: ^0.17.1 + version: 0.17.1 mocha: specifier: ^11.0.1 version: 11.0.1 @@ -7724,13 +7724,13 @@ packages: peerDependencies: markdownlint-cli2: '>=0.0.4' - markdownlint-cli2@0.17.0: - resolution: {integrity: sha512-8Xz7wkkkV4wJTf+pvryU3J/fT3BZWD3ZykcjYBR0GuH0GHvrCbswaCdurbuUuAPDGFZy4cxBGYCJSAOW8jM4aQ==} + markdownlint-cli2@0.17.1: + resolution: {integrity: sha512-n1Im9lhKJJE12/u2N0GWBwPqeb0HGdylN8XpSFg9hbj35+QalY9Vi6mxwUQdG6wlSrrIq9ZDQ0Q85AQG9V2WOg==} engines: {node: '>=18'} hasBin: true - markdownlint@0.37.2: - resolution: {integrity: sha512-m8QhYnRA1ptbhIjhVVBUkKQcUelVxuyO/yXyLewnc1+xs4eXhST/+hIy29goO+EYVLmWtknH4SmYQ4s0caoKqw==} + markdownlint@0.37.3: + resolution: {integrity: sha512-eoQqH0291YCCjd+Pe1PUQ9AmWthlVmS0XWgcionkZ8q34ceZyRI+pYvsWksXJJL8OBkWCPwp1h/pnXxrPFC4oA==} engines: {node: '>=18'} marked@15.0.4: @@ -17579,25 +17579,26 @@ snapshots: dependencies: react: 19.0.0 - markdownlint-cli2-formatter-default@0.0.5(markdownlint-cli2@0.17.0): + markdownlint-cli2-formatter-default@0.0.5(markdownlint-cli2@0.17.1): dependencies: - markdownlint-cli2: 0.17.0 + markdownlint-cli2: 0.17.1 - markdownlint-cli2@0.17.0: + markdownlint-cli2@0.17.1: dependencies: globby: 14.0.2 js-yaml: 4.1.0 jsonc-parser: 3.3.1 - markdownlint: 0.37.2 - markdownlint-cli2-formatter-default: 0.0.5(markdownlint-cli2@0.17.0) + markdownlint: 0.37.3 + markdownlint-cli2-formatter-default: 0.0.5(markdownlint-cli2@0.17.1) micromatch: 4.0.8 transitivePeerDependencies: - supports-color - markdownlint@0.37.2: + markdownlint@0.37.3: dependencies: markdown-it: 14.1.0 micromark: 4.0.1 + micromark-core-commonmark: 2.0.2 micromark-extension-directive: 3.0.2 micromark-extension-gfm-autolink-literal: 2.1.0 micromark-extension-gfm-footnote: 2.1.0 From 8e785f9fd902e344e569db5c6b4a7cc8285f4bb1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 16:43:26 +0700 Subject: [PATCH 11/25] Bump @mui/monorepo digest to 5d892ca (#16073) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 38dafae52f9d5..073dfd23907b7 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "@mui/internal-markdown": "^1.0.24", "@mui/internal-test-utils": "^1.0.25", "@mui/material": "^5.16.13", - "@mui/monorepo": "github:mui/material-ui#84d6ecfdccd10f204854beeef98bcc55dc99d117", + "@mui/monorepo": "github:mui/material-ui#5d892caa7325fdc8679862f83804c541954fecbc", "@mui/utils": "^5.16.13", "@next/eslint-plugin-next": "15.1.3", "@octokit/plugin-retry": "^7.1.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 25d6c951a5691..0ae8a93a70e46 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -99,8 +99,8 @@ importers: specifier: ^5.16.13 version: 5.16.13(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@mui/monorepo': - specifier: github:mui/material-ui#84d6ecfdccd10f204854beeef98bcc55dc99d117 - version: https://codeload.github.com/mui/material-ui/tar.gz/84d6ecfdccd10f204854beeef98bcc55dc99d117(encoding@0.1.13) + specifier: github:mui/material-ui#5d892caa7325fdc8679862f83804c541954fecbc + version: https://codeload.github.com/mui/material-ui/tar.gz/5d892caa7325fdc8679862f83804c541954fecbc(encoding@0.1.13) '@mui/utils': specifier: ^5.16.13 version: 5.16.13(@types/react@19.0.2)(react@19.0.0) @@ -3219,10 +3219,10 @@ packages: '@types/react': optional: true - '@mui/monorepo@https://codeload.github.com/mui/material-ui/tar.gz/84d6ecfdccd10f204854beeef98bcc55dc99d117': - resolution: {tarball: https://codeload.github.com/mui/material-ui/tar.gz/84d6ecfdccd10f204854beeef98bcc55dc99d117} - version: 6.3.0 - engines: {pnpm: 9.14.4} + '@mui/monorepo@https://codeload.github.com/mui/material-ui/tar.gz/5d892caa7325fdc8679862f83804c541954fecbc': + resolution: {tarball: https://codeload.github.com/mui/material-ui/tar.gz/5d892caa7325fdc8679862f83804c541954fecbc} + version: 6.3.1 + engines: {pnpm: 9.15.2} '@mui/private-theming@5.16.13': resolution: {integrity: sha512-+s0FklvDvO7j0yBZn19DIIT3rLfub2fWvXGtMX49rG/xHfDFcP7fbWbZKHZMMP/2/IoTRDrZCbY1iP0xZlmuJA==} @@ -12226,7 +12226,7 @@ snapshots: '@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0) '@types/react': 19.0.2 - '@mui/monorepo@https://codeload.github.com/mui/material-ui/tar.gz/84d6ecfdccd10f204854beeef98bcc55dc99d117(encoding@0.1.13)': + '@mui/monorepo@https://codeload.github.com/mui/material-ui/tar.gz/5d892caa7325fdc8679862f83804c541954fecbc(encoding@0.1.13)': dependencies: '@googleapis/sheets': 9.3.1(encoding@0.1.13) '@netlify/functions': 2.8.2 From 0f66a5341616dd222247aa23d816c29005ad91df Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 12:25:52 +0200 Subject: [PATCH 12/25] Lock file maintenance (#16051) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- pnpm-lock.yaml | 1665 +++++++++++++++++++++++++----------------------- 1 file changed, 872 insertions(+), 793 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0ae8a93a70e46..b89f912df0080 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -271,7 +271,7 @@ importers: version: 7.1.1(eslint@8.57.1)(typescript@5.7.2) fast-glob: specifier: ^3.3.2 - version: 3.3.2 + version: 3.3.3 format-util: specifier: ^1.0.5 version: 1.0.5 @@ -319,7 +319,7 @@ importers: version: 5.0.1(webpack@5.97.1) lerna: specifier: ^8.1.9 - version: 8.1.9(@swc/core@1.9.3(@swc/helpers@0.5.15))(babel-plugin-macros@3.1.0)(encoding@0.1.13) + version: 8.1.9(@swc/core@1.10.4(@swc/helpers@0.5.15))(babel-plugin-macros@3.1.0)(encoding@0.1.13) lodash: specifier: ^4.17.21 version: 4.17.21 @@ -373,7 +373,7 @@ importers: version: 3.1.0(webpack@5.97.1) terser-webpack-plugin: specifier: ^5.3.11 - version: 5.3.11(@swc/core@1.9.3(@swc/helpers@0.5.15))(webpack@5.97.1) + version: 5.3.11(@swc/core@1.10.4(@swc/helpers@0.5.15))(webpack@5.97.1) tsx: specifier: ^4.19.2 version: 4.19.2 @@ -388,7 +388,7 @@ importers: version: 0.12.5 webpack: specifier: ^5.97.1 - version: 5.97.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) + version: 5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) webpack-bundle-analyzer: specifier: ^4.10.2 version: 4.10.2 @@ -412,7 +412,7 @@ importers: version: 7.26.0 '@docsearch/react': specifier: ^3.8.2 - version: 3.8.2(@algolia/client-search@5.15.0)(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(search-insights@2.17.3) + version: 3.8.2(@algolia/client-search@5.18.0)(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(search-insights@2.17.3) '@emotion/cache': specifier: ^11.14.0 version: 11.14.0 @@ -692,7 +692,7 @@ importers: version: 4.2.7 '@types/webpack-bundle-analyzer': specifier: ^4.7.0 - version: 4.7.0(@swc/core@1.9.3(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) + version: 4.7.0(@swc/core@1.10.4(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) gm: specifier: ^1.25.0 version: 1.25.0 @@ -895,7 +895,7 @@ importers: version: 4.0.8 '@types/d3-shape': specifier: ^3.1.6 - version: 3.1.6 + version: 3.1.7 '@types/d3-time': specifier: ^3.0.4 version: 3.0.4 @@ -1040,7 +1040,7 @@ importers: version: 5.16.13(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0) '@mui/types': specifier: ^7.2.20 - version: 7.2.20(@types/react@19.0.2) + version: 7.2.21(@types/react@19.0.2) '@types/prop-types': specifier: ^15.7.14 version: 15.7.14 @@ -1653,7 +1653,7 @@ importers: devDependencies: '@codspeed/vitest-plugin': specifier: ^4.0.0 - version: 4.0.0(vite@5.4.11(@types/node@20.17.11)(terser@5.36.0))(vitest@2.1.8) + version: 4.0.0(vite@5.4.11(@types/node@20.17.11)(terser@5.37.0))(vitest@2.1.8) '@emotion/react': specifier: ^11.14.0 version: 11.14.0(@types/react@19.0.2)(react@19.0.0) @@ -1674,13 +1674,13 @@ importers: version: 14.5.2(@testing-library/dom@10.4.0) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@5.4.11(@types/node@20.17.11)(terser@5.36.0)) + version: 4.3.4(vite@5.4.11(@types/node@20.17.11)(terser@5.37.0)) '@vitejs/plugin-react-swc': specifier: ^3.7.2 - version: 3.7.2(@swc/helpers@0.5.15)(vite@5.4.11(@types/node@20.17.11)(terser@5.36.0)) + version: 3.7.2(@swc/helpers@0.5.15)(vite@5.4.11(@types/node@20.17.11)(terser@5.37.0)) '@vitest/browser': specifier: 2.1.8 - version: 2.1.8(@types/node@20.17.11)(playwright@1.49.1)(typescript@5.7.2)(vite@5.4.11(@types/node@20.17.11)(terser@5.36.0))(vitest@2.1.8) + version: 2.1.8(@types/node@20.17.11)(playwright@1.49.1)(typescript@5.7.2)(vite@5.4.11(@types/node@20.17.11)(terser@5.37.0))(vitest@2.1.8) '@vitest/ui': specifier: 2.1.8 version: 2.1.8(vitest@2.1.8) @@ -1695,7 +1695,7 @@ importers: version: 19.0.0(react@19.0.0) vitest: specifier: 2.1.8 - version: 2.1.8(@types/node@20.17.11)(@vitest/browser@2.1.8)(@vitest/ui@2.1.8)(jsdom@25.0.1)(msw@2.6.6(@types/node@20.17.11)(typescript@5.7.2))(terser@5.36.0) + version: 2.1.8(@types/node@20.17.11)(@vitest/browser@2.1.8)(@vitest/ui@2.1.8)(jsdom@25.0.1)(msw@2.7.0(@types/node@20.17.11)(typescript@5.7.2))(terser@5.37.0) packages: @@ -1737,56 +1737,56 @@ packages: '@algolia/client-search': '>= 4.9.1 < 6' algoliasearch: '>= 4.9.1 < 6' - '@algolia/client-abtesting@5.15.0': - resolution: {integrity: sha512-FaEM40iuiv1mAipYyiptP4EyxkJ8qHfowCpEeusdHUC4C7spATJYArD2rX3AxkVeREkDIgYEOuXcwKUbDCr7Nw==} + '@algolia/client-abtesting@5.18.0': + resolution: {integrity: sha512-DLIrAukjsSrdMNNDx1ZTks72o4RH/1kOn8Wx5zZm8nnqFexG+JzY4SANnCNEjnFQPJTTvC+KpgiNW/CP2lumng==} engines: {node: '>= 14.0.0'} - '@algolia/client-analytics@5.15.0': - resolution: {integrity: sha512-lho0gTFsQDIdCwyUKTtMuf9nCLwq9jOGlLGIeQGKDxXF7HbiAysFIu5QW/iQr1LzMgDyM9NH7K98KY+BiIFriQ==} + '@algolia/client-analytics@5.18.0': + resolution: {integrity: sha512-0VpGG2uQW+h2aejxbG8VbnMCQ9ary9/ot7OASXi6OjE0SRkYQ/+pkW+q09+IScif3pmsVVYggmlMPtAsmYWHng==} engines: {node: '>= 14.0.0'} - '@algolia/client-common@5.15.0': - resolution: {integrity: sha512-IofrVh213VLsDkPoSKMeM9Dshrv28jhDlBDLRcVJQvlL8pzue7PEB1EZ4UoJFYS3NSn7JOcJ/V+olRQzXlJj1w==} + '@algolia/client-common@5.18.0': + resolution: {integrity: sha512-X1WMSC+1ve2qlMsemyTF5bIjwipOT+m99Ng1Tyl36ZjQKTa54oajBKE0BrmM8LD8jGdtukAgkUhFoYOaRbMcmQ==} engines: {node: '>= 14.0.0'} - '@algolia/client-insights@5.15.0': - resolution: {integrity: sha512-bDDEQGfFidDi0UQUCbxXOCdphbVAgbVmxvaV75cypBTQkJ+ABx/Npw7LkFGw1FsoVrttlrrQbwjvUB6mLVKs/w==} + '@algolia/client-insights@5.18.0': + resolution: {integrity: sha512-FAJRNANUOSs/FgYOJ/Njqp+YTe4TMz2GkeZtfsw1TMiA5mVNRS/nnMpxas9771aJz7KTEWvK9GwqPs0K6RMYWg==} engines: {node: '>= 14.0.0'} - '@algolia/client-personalization@5.15.0': - resolution: {integrity: sha512-LfaZqLUWxdYFq44QrasCDED5bSYOswpQjSiIL7Q5fYlefAAUO95PzBPKCfUhSwhb4rKxigHfDkd81AvEicIEoA==} + '@algolia/client-personalization@5.18.0': + resolution: {integrity: sha512-I2dc94Oiwic3SEbrRp8kvTZtYpJjGtg5y5XnqubgnA15AgX59YIY8frKsFG8SOH1n2rIhUClcuDkxYQNXJLg+w==} engines: {node: '>= 14.0.0'} - '@algolia/client-query-suggestions@5.15.0': - resolution: {integrity: sha512-wu8GVluiZ5+il8WIRsGKu8VxMK9dAlr225h878GGtpTL6VBvwyJvAyLdZsfFIpY0iN++jiNb31q2C1PlPL+n/A==} + '@algolia/client-query-suggestions@5.18.0': + resolution: {integrity: sha512-x6XKIQgKFTgK/bMasXhghoEjHhmgoP61pFPb9+TaUJ32aKOGc65b12usiGJ9A84yS73UDkXS452NjyP50Knh/g==} engines: {node: '>= 14.0.0'} - '@algolia/client-search@5.15.0': - resolution: {integrity: sha512-Z32gEMrRRpEta5UqVQA612sLdoqY3AovvUPClDfMxYrbdDAebmGDVPtSogUba1FZ4pP5dx20D3OV3reogLKsRA==} + '@algolia/client-search@5.18.0': + resolution: {integrity: sha512-qI3LcFsVgtvpsBGR7aNSJYxhsR+Zl46+958ODzg8aCxIcdxiK7QEVLMJMZAR57jGqW0Lg/vrjtuLFDMfSE53qA==} engines: {node: '>= 14.0.0'} - '@algolia/ingestion@1.15.0': - resolution: {integrity: sha512-MkqkAxBQxtQ5if/EX2IPqFA7LothghVyvPoRNA/meS2AW2qkHwcxjuiBxv4H6mnAVEPfJlhu9rkdVz9LgCBgJg==} + '@algolia/ingestion@1.18.0': + resolution: {integrity: sha512-bGvJg7HnGGm+XWYMDruZXWgMDPVt4yCbBqq8DM6EoaMBK71SYC4WMfIdJaw+ABqttjBhe6aKNRkWf/bbvYOGyw==} engines: {node: '>= 14.0.0'} - '@algolia/monitoring@1.15.0': - resolution: {integrity: sha512-QPrFnnGLMMdRa8t/4bs7XilPYnoUXDY8PMQJ1sf9ZFwhUysYYhQNX34/enoO0LBjpoOY6rLpha39YQEFbzgKyQ==} + '@algolia/monitoring@1.18.0': + resolution: {integrity: sha512-lBssglINIeGIR+8KyzH05NAgAmn1BCrm5D2T6pMtr/8kbTHvvrm1Zvcltc5dKUQEFyyx3J5+MhNc7kfi8LdjVw==} engines: {node: '>= 14.0.0'} - '@algolia/recommend@5.15.0': - resolution: {integrity: sha512-5eupMwSqMLDObgSMF0XG958zR6GJP3f7jHDQ3/WlzCM9/YIJiWIUoJFGsko9GYsA5xbLDHE/PhWtq4chcCdaGQ==} + '@algolia/recommend@5.18.0': + resolution: {integrity: sha512-uSnkm0cdAuFwdMp4pGT5vHVQ84T6AYpTZ3I0b3k/M3wg4zXDhl3aCiY8NzokEyRLezz/kHLEEcgb/tTTobOYVw==} engines: {node: '>= 14.0.0'} - '@algolia/requester-browser-xhr@5.15.0': - resolution: {integrity: sha512-Po/GNib6QKruC3XE+WKP1HwVSfCDaZcXu48kD+gwmtDlqHWKc7Bq9lrS0sNZ456rfCKhXksOmMfUs4wRM/Y96w==} + '@algolia/requester-browser-xhr@5.18.0': + resolution: {integrity: sha512-1XFjW0C3pV0dS/9zXbV44cKI+QM4ZIz9cpatXpsjRlq6SUCpLID3DZHsXyE6sTb8IhyPaUjk78GEJT8/3hviqg==} engines: {node: '>= 14.0.0'} - '@algolia/requester-fetch@5.15.0': - resolution: {integrity: sha512-rOZ+c0P7ajmccAvpeeNrUmEKoliYFL8aOR5qGW5pFq3oj3Iept7Y5mEtEsOBYsRt6qLnaXn4zUKf+N8nvJpcIw==} + '@algolia/requester-fetch@5.18.0': + resolution: {integrity: sha512-0uodeNdAHz1YbzJh6C5xeQ4T6x5WGiUxUq3GOaT/R4njh5t78dq+Rb187elr7KtnjUmETVVuCvmEYaThfTHzNg==} engines: {node: '>= 14.0.0'} - '@algolia/requester-node-http@5.15.0': - resolution: {integrity: sha512-b1jTpbFf9LnQHEJP5ddDJKE2sAlhYd7EVSOWgzo/27n/SfCoHfqD0VWntnWYD83PnOKvfe8auZ2+xCb0TXotrQ==} + '@algolia/requester-node-http@5.18.0': + resolution: {integrity: sha512-tZCqDrqJ2YE2I5ukCQrYN8oiF6u3JIdCxrtKq+eniuLkjkO78TKRnXrVcKZTmfFJyyDK8q47SfDcHzAA3nHi6w==} engines: {node: '>= 14.0.0'} '@ampproject/remapping@2.3.0': @@ -1816,8 +1816,8 @@ packages: resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.26.2': - resolution: {integrity: sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==} + '@babel/compat-data@7.26.3': + resolution: {integrity: sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g==} engines: {node: '>=6.9.0'} '@babel/core@7.26.0': @@ -1832,10 +1832,6 @@ packages: resolution: {integrity: sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==} engines: {node: '>=6.9.0'} - '@babel/helper-builder-binary-assignment-operator-visitor@7.25.9': - resolution: {integrity: sha512-C47lC7LIDCnz0h4vai/tpNOI95tCd5ZT3iBt/DBH5lXKHZsyNQv18yf1wIIg2ntiQNgmAvA+DgZ82iW8Qdym8g==} - engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.25.9': resolution: {integrity: sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==} engines: {node: '>=6.9.0'} @@ -1846,8 +1842,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-create-regexp-features-plugin@7.25.9': - resolution: {integrity: sha512-ORPNZ3h6ZRkOyAa/SaHU+XsLZr0UQzRwuDQ0cczIA17nAzZ+85G5cVkOJIj7QavLZGSe8QXUmNFxSZzjcZF9bw==} + '@babel/helper-create-regexp-features-plugin@7.26.3': + resolution: {integrity: sha512-G7ZRb40uUgdKOQqPLjfD12ZmGA54PzqDFUv2BKImnC9QIfGhIHKvVML0oN8IUiDq4iRqpq74ABpvOaerfWdong==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -2088,8 +2084,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-exponentiation-operator@7.25.9': - resolution: {integrity: sha512-KRhdhlVk2nObA5AYa7QMgTMTVJdfHprfpAk4DjZVtllqRg9qarilstTKEhpVjyt+Npi8ThRyiV8176Am3CodPA==} + '@babel/plugin-transform-exponentiation-operator@7.26.3': + resolution: {integrity: sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -2334,8 +2330,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-typescript@7.25.9': - resolution: {integrity: sha512-7PbZQZP50tzv2KGGnhh82GSyMB01yKY9scIjf1a+GfZCtInOWqUH5+1EBU4t9fyR5Oykkkc9vFTs4OHrhHXljQ==} + '@babel/plugin-transform-typescript@7.26.3': + resolution: {integrity: sha512-6+5hpdr6mETwSKjmJUdYw0EIkATiQhnELWlE3kJFBwSg/BGIVwVaVbX+gOXBCdc7Ln1RXZxyWGecIXhUfnl7oA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -3019,22 +3015,22 @@ packages: cpu: [x64] os: [win32] - '@inquirer/confirm@5.0.2': - resolution: {integrity: sha512-KJLUHOaKnNCYzwVbryj3TNBxyZIrr56fR5N45v6K9IPrbT6B7DcudBMfylkV1A8PUdJE15mybkEQyp2/ZUpxUA==} + '@inquirer/confirm@5.1.1': + resolution: {integrity: sha512-vVLSbGci+IKQvDOtzpPTCOiEJCNidHcAq9JYVoWTW0svb5FiwSLotkM+JXNXejfjnzVYV9n0DTBythl9+XgTxg==} engines: {node: '>=18'} peerDependencies: '@types/node': ^20.17.11 - '@inquirer/core@10.1.0': - resolution: {integrity: sha512-I+ETk2AL+yAVbvuKx5AJpQmoaWhpiTFOg/UJb7ZkMAK4blmtG8ATh5ct+T/8xNld0CZG/2UhtkdMwpgvld92XQ==} + '@inquirer/core@10.1.2': + resolution: {integrity: sha512-bHd96F3ezHg1mf/J0Rb4CV8ndCN0v28kUlrHqP7+ECm1C/A+paB7Xh2lbMk6x+kweQC+rZOxM/YeKikzxco8bQ==} engines: {node: '>=18'} - '@inquirer/figures@1.0.8': - resolution: {integrity: sha512-tKd+jsmhq21AP1LhexC0pPwsCxEhGgAkg28byjJAd+xhmIs8LUX8JbUc3vBf3PhLxWiB5EvyBE5X7JSPAqMAqg==} + '@inquirer/figures@1.0.9': + resolution: {integrity: sha512-BXvGj0ehzrngHTPTDqUoDT3NXL8U0RxUk2zJm2A66RhCEIWdtU1v6GuUqNAgArW4PQ9CinqIWyHdQgdwOj06zQ==} engines: {node: '>=18'} - '@inquirer/type@3.0.1': - resolution: {integrity: sha512-+ksJMIy92sOAiAccGpcKZUc3bYO07cADnscIxHBknEm3uNts3movSmBofc1908BNy5edKscxYeAdaX1NXkHS6A==} + '@inquirer/type@3.0.2': + resolution: {integrity: sha512-ZhQ4TvhwHZF+lGhQ2O/rsjo80XoZR5/5qhOY3t6FJuX5XBg5Be8YzYTvaUGJnc12AUGI2nr4QSUE4PhKSigx7g==} engines: {node: '>=18'} peerDependencies: '@types/node': ^20.17.11 @@ -3058,8 +3054,8 @@ packages: resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@jridgewell/gen-mapping@0.3.5': - resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + '@jridgewell/gen-mapping@0.3.8': + resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} engines: {node: '>=6.0.0'} '@jridgewell/resolve-uri@3.1.2': @@ -3083,8 +3079,8 @@ packages: resolution: {integrity: sha512-DPnl5lPX4v49eVxEbJnAizrpMdMTBz1qykZrAbBul9rfgk531v8oAt+Pm6O/rpAleRombNM7FJb5rYGzBJatOQ==} engines: {node: '>=18.0.0'} - '@mswjs/interceptors@0.37.3': - resolution: {integrity: sha512-USvgCL/uOGFtVa6SVyRrC8kIAedzRohxIXN5LISlg5C5vLZCn7dgMFVSNhSF9cuBEFrm/O2spDWEZeMnw4ZXYg==} + '@mswjs/interceptors@0.37.5': + resolution: {integrity: sha512-AAwRb5vXFcY4L+FvZ7LZusDuZ0vEe0Zm8ohn1FM6/X7A3bj4mqmkAcGRWuvC2JwSygNwHAAmMnAI73vPHeqsHA==} engines: {node: '>=18'} '@mui/base@5.0.0-beta.40-0': @@ -3273,8 +3269,8 @@ packages: '@types/react': optional: true - '@mui/types@7.2.20': - resolution: {integrity: sha512-straFHD7L8v05l/N5vcWk+y7eL9JF0C2mtph/y4BPm3gn2Eh61dDwDB65pa8DLss3WJfDXYC7Kx5yjP0EmXpgw==} + '@mui/types@7.2.21': + resolution: {integrity: sha512-6HstngiUxNqLU+/DPqlUJDIPbzUBxIVHb1MmXP0eTWDIROiCR2viugXpEif0PPe2mLqqakPzzRClWAnK+8UJww==} peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: @@ -3433,67 +3429,67 @@ packages: resolution: {integrity: sha512-y7efHHwghQfk28G2z3tlZ67pLG0XdfYbcVG26r7YIXALRsrVQcTq4/tdenSmdOrEsNahIYA/eh8aEVROWGFUDg==} engines: {node: ^16.14.0 || >=18.0.0} - '@nx/devkit@20.1.4': - resolution: {integrity: sha512-Opz7eRPmpt3e4SGkbwZbE9Bg3MhKeivh1QTNCj4tQVAB4gucz0lW/F3mdtRDFdj6gUbqIc5rRrbO/DGlNaEzYw==} + '@nx/devkit@20.3.0': + resolution: {integrity: sha512-u9oRd2F33DLNWPbzpYGW7xuMEYUAOwO9DLP9nGYpxbZXy6Z4AdoKeqhN+KBTyg8+DyQGuKUSEXcWriDyLLgcHw==} peerDependencies: nx: '>= 19 <= 21' - '@nx/nx-darwin-arm64@20.1.4': - resolution: {integrity: sha512-afyDOZbIyHi6BgKk+Bb4RI1t8dZ6/oIbOY89z4mBPNNevZkbGqUfMwO2vjKnaOoThcjT93SEMJfCLGL8i857ww==} + '@nx/nx-darwin-arm64@20.3.0': + resolution: {integrity: sha512-9PqSe1Sh7qNqA4GL0cZH0t3S0EZzb2Xn14XY9au7yf0+eoxyag1oETjjULrxLeUmSoXW2hDxzNtoqKFE9zF07Q==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@nx/nx-darwin-x64@20.1.4': - resolution: {integrity: sha512-aiYklAt95aX0EinepJRryMna8K53G52ngYOFuac1G8iLlguinJvg/YgSKCf7GOAzec8b7Hm7KauPjSJE/P3/iw==} + '@nx/nx-darwin-x64@20.3.0': + resolution: {integrity: sha512-gsGGhJVvi5QZVVTZie5sNMo1zOAU+A2edm6DGegObdFRLV41Ju/Yrm/gTaSp4yUtywd3UU4S/30C/nI2c55adA==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@nx/nx-freebsd-x64@20.1.4': - resolution: {integrity: sha512-WUh4bsLK+e7wuN3lE3ZQUj+xQKdWU4P4RymutfLQQnPYiilCMtFwITcvDmazmOHFWI2vPhzSyYJRbOu+YMIR3A==} + '@nx/nx-freebsd-x64@20.3.0': + resolution: {integrity: sha512-DiymYZBBu0upbiskdfn9KRyoXdyvKohezJiV3j4VkeRE8KR2p04NgwRQviDFbeD1cjWrDy9wk8y+G5PabLlqAA==} engines: {node: '>= 10'} cpu: [x64] os: [freebsd] - '@nx/nx-linux-arm-gnueabihf@20.1.4': - resolution: {integrity: sha512-9vPMw5s89v3od7aw3enTWjdMSCAmQ0tIA89Uz7xbbjB2kX2mAdihSzAKd9woi/cj+ROnY+ynNXzU9UjqhfxdBg==} + '@nx/nx-linux-arm-gnueabihf@20.3.0': + resolution: {integrity: sha512-Aksx66e8jmt/4rGJ/5z34SWXbPcYr9Ht52UonEeuCdQdoEvAOs7yBUbllYOjIcUsfZikEyZgvqfiQslsggSJdQ==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@nx/nx-linux-arm64-gnu@20.1.4': - resolution: {integrity: sha512-JUE4l8utr9KmQSG9tO2Qw5R5i/bZ16s1+J5xnEar7UfcSOfOLqxGHS7HCBUZcfr46dmtv6KjIC83uHMs19AwDQ==} + '@nx/nx-linux-arm64-gnu@20.3.0': + resolution: {integrity: sha512-Y5wmYEwF1bl014Ps8QjagI911VbViQSFHSTVOCNSObdAzig9E5o6NOkoWe+doT1UZLrrInnlkrggQUsbtdKjOg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@nx/nx-linux-arm64-musl@20.1.4': - resolution: {integrity: sha512-EaPUDqXvnPc/ure0x7N+5lRYvk5zqOQ3LzFOTRPWdqnFXejyTkGjZEYWbLFIJTFrvyEdpfaPTHyNmCHUrEz9TQ==} + '@nx/nx-linux-arm64-musl@20.3.0': + resolution: {integrity: sha512-yGcIkmImyOMfPkQSYH2EVjPmFE0VkLcO71Bbkpr3RlJ1N/vjYxsGbdnqPiBb8Wshib/hmwpiMHf/yzQtKH0SQw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@nx/nx-linux-x64-gnu@20.1.4': - resolution: {integrity: sha512-vaWV37ZayfyckVI/faWdQWIV9XQb06ZT8jHQnwgSd9tKbGz37vN30eYtgZlFL0P4bHfhjtmMXnLvADmfyO/KOw==} + '@nx/nx-linux-x64-gnu@20.3.0': + resolution: {integrity: sha512-nkA2DLI+rpmiuiy7dyXP4l9s7dgHkQWDX7lG1XltiT41RzAReJF1h8qBE6XrsAYE1CtI76DRWVphnc93+iZr+A==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@nx/nx-linux-x64-musl@20.1.4': - resolution: {integrity: sha512-wjq4Ea1oweBsIA9jq+jDT6BALxv/uac0aFykwoN23dOiwwSMFWMxbXUuBrxp0LjMFGV49S62kVDoRezukvkiZA==} + '@nx/nx-linux-x64-musl@20.3.0': + resolution: {integrity: sha512-sPMtTt9iTrCmFEIp9Qv27UX9PeL1aqKck2dz2TAFbXKVtF6+djOdTcNnTYw45KIP6izcUcOXXAq4G0QSQE7CLg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@nx/nx-win32-arm64-msvc@20.1.4': - resolution: {integrity: sha512-d9jN8biyEJh4Mjdc3RU1j/+WIOjrO9mCDxYuERXP2ELaNsOk0tJgcXE1xsa9AF88AHGpOkCOS2rxy61DKBtFKg==} + '@nx/nx-win32-arm64-msvc@20.3.0': + resolution: {integrity: sha512-ppfNa/8OfpWA9o26Pz3vArN4ulAC+Hx70/ghPRCP7ed1Mb3Z6yR2Ry9KfBRImbqajvuAExM0TePKMGq9LCdXmg==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@nx/nx-win32-x64-msvc@20.1.4': - resolution: {integrity: sha512-s3RwOkkWKzOflbTmc5MRc4EH2mk1AkJ/V8Gu3Qi2QncF9r1GrR7hDxROpu0MEoHfIhRG+d+n8OGX31nC9GZWUg==} + '@nx/nx-win32-x64-msvc@20.3.0': + resolution: {integrity: sha512-8FOejZ4emtLSVn3pYWs4PIc3n4//qMbwMDPVxmPE8us3ir91Qh0bzr5zRj7Q8sEdSgvneXRXqtBp2grY2KMJsw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -3524,12 +3520,12 @@ packages: resolution: {integrity: sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg==} engines: {node: '>= 18'} - '@octokit/core@6.1.2': - resolution: {integrity: sha512-hEb7Ma4cGJGEUNOAVmyfdB/3WirWMg5hDuNFVejGEDFqupeOysLc2sG6HJxY2etBp5YQu5Wtxwi020jS9xlUwg==} + '@octokit/core@6.1.3': + resolution: {integrity: sha512-z+j7DixNnfpdToYsOutStDgeRzJSMnbj8T1C/oQjB6Aa+kRfNjs/Fn7W6c8bmlt6mfy3FkgeKBRnDjxQow5dow==} engines: {node: '>= 18'} - '@octokit/endpoint@10.1.1': - resolution: {integrity: sha512-JYjh5rMOwXMJyUpj028cu0Gbp7qe/ihxfJMLc8VZBMMqSwLgOxDI1911gV4Enl1QSavAQNJcwmwBF9M0VvLh6Q==} + '@octokit/endpoint@10.1.2': + resolution: {integrity: sha512-XybpFv9Ms4hX5OCHMZqyODYqGTZ3H6K6Vva+M9LR7ib/xr1y1ZnlChYv9H680y77Vd/i/k+thXApeRASBQkzhA==} engines: {node: '>= 18'} '@octokit/endpoint@6.0.12': @@ -3554,8 +3550,8 @@ packages: resolution: {integrity: sha512-r+oZUH7aMFui1ypZnAvZmn0KSqAUgE1/tUXIWaqUCa1758ts/Jio84GZuzsvUkme98kv0WFY8//n0J1Z+vsIsQ==} engines: {node: '>= 18'} - '@octokit/graphql@8.1.1': - resolution: {integrity: sha512-ukiRmuHTi6ebQx/HFRCXKbDlOh/7xEV6QUXaE7MJEKGNAncGI/STSbOkl12qVXZrfZdpXctx5O9X1AIaebiDBg==} + '@octokit/graphql@8.1.2': + resolution: {integrity: sha512-bdlj/CJVjpaz06NBpfHhp4kGJaRZfz7AzC+6EwUImRtrwIw8dIgJ63Xg0OzV9pRn3rIzrt5c2sa++BL0JJ8GLw==} engines: {node: '>= 18'} '@octokit/openapi-types@12.11.0': @@ -3647,8 +3643,8 @@ packages: resolution: {integrity: sha512-GETXfE05J0+7H2STzekpKObFe765O5dlAKUTLNGeH+x47z7JjXHfsHKo5z21D/o/IOZTUEI6nyWyR+bZVP/n5Q==} engines: {node: '>= 18'} - '@octokit/request-error@6.1.5': - resolution: {integrity: sha512-IlBTfGX8Yn/oFPMwSfvugfncK2EwRLjzbrpifNaMY8o/HTEAFqCA1FZxjD9cWvSKBHgrIhc4CSBIzMxiLsbzFQ==} + '@octokit/request-error@6.1.6': + resolution: {integrity: sha512-pqnVKYo/at0NuOjinrgcQYpEbv4snvP3bKMRqHaD9kIsk9u1LCpb2smHZi8/qJfgeNqLo5hNW4Z7FezNdEo0xg==} engines: {node: '>= 18'} '@octokit/request@5.6.3': @@ -3662,8 +3658,8 @@ packages: resolution: {integrity: sha512-9Bb014e+m2TgBeEJGEbdplMVWwPmL1FPtggHQRkV+WVsMggPtEkLKPlcVYm/o8xKLkpJ7B+6N8WfQMtDLX2Dpw==} engines: {node: '>= 18'} - '@octokit/request@9.1.3': - resolution: {integrity: sha512-V+TFhu5fdF3K58rs1pGUJIDH5RZLbZm5BI+MNF+6o/ssFNT4vWlCh/tVpF3NxGtP15HUxTTMUbsG5llAuU2CZA==} + '@octokit/request@9.1.4': + resolution: {integrity: sha512-tMbOwGm6wDII6vygP3wUVqFTw3Aoo0FnVQyhihh8vVq12uO3P+vQZeo2CKMpWtPSogpACD0yyZAlVlQnjW71DA==} engines: {node: '>= 18'} '@octokit/rest@18.12.0': @@ -3754,93 +3750,98 @@ packages: resolution: {integrity: sha512-xfSkCAchbdG5PnbrKqFWwia4Bi61nH+wm8wLEqfHDyp7Y3dZzgqS2itV8i4gAq9pC2HsTpwyBC6Ds8VHZ96JlA==} engines: {node: '>=14.0.0'} - '@rollup/rollup-android-arm-eabi@4.28.0': - resolution: {integrity: sha512-wLJuPLT6grGZsy34g4N1yRfYeouklTgPhH1gWXCYspenKYD0s3cR99ZevOGw5BexMNywkbV3UkjADisozBmpPQ==} + '@rollup/rollup-android-arm-eabi@4.30.0': + resolution: {integrity: sha512-qFcFto9figFLz2g25DxJ1WWL9+c91fTxnGuwhToCl8BaqDsDYMl/kOnBXAyAqkkzAWimYMSWNPWEjt+ADAHuoQ==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.28.0': - resolution: {integrity: sha512-eiNkznlo0dLmVG/6wf+Ifi/v78G4d4QxRhuUl+s8EWZpDewgk7PX3ZyECUXU0Zq/Ca+8nU8cQpNC4Xgn2gFNDA==} + '@rollup/rollup-android-arm64@4.30.0': + resolution: {integrity: sha512-vqrQdusvVl7dthqNjWCL043qelBK+gv9v3ZiqdxgaJvmZyIAAXMjeGVSqZynKq69T7062T5VrVTuikKSAAVP6A==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.28.0': - resolution: {integrity: sha512-lmKx9yHsppblnLQZOGxdO66gT77bvdBtr/0P+TPOseowE7D9AJoBw8ZDULRasXRWf1Z86/gcOdpBrV6VDUY36Q==} + '@rollup/rollup-darwin-arm64@4.30.0': + resolution: {integrity: sha512-617pd92LhdA9+wpixnzsyhVft3szYiN16aNUMzVkf2N+yAk8UXY226Bfp36LvxYTUt7MO/ycqGFjQgJ0wlMaWQ==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.28.0': - resolution: {integrity: sha512-8hxgfReVs7k9Js1uAIhS6zq3I+wKQETInnWQtgzt8JfGx51R1N6DRVy3F4o0lQwumbErRz52YqwjfvuwRxGv1w==} + '@rollup/rollup-darwin-x64@4.30.0': + resolution: {integrity: sha512-Y3b4oDoaEhCypg8ajPqigKDcpi5ZZovemQl9Edpem0uNv6UUjXv7iySBpGIUTSs2ovWOzYpfw9EbFJXF/fJHWw==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.28.0': - resolution: {integrity: sha512-lA1zZB3bFx5oxu9fYud4+g1mt+lYXCoch0M0V/xhqLoGatbzVse0wlSQ1UYOWKpuSu3gyN4qEc0Dxf/DII1bhQ==} + '@rollup/rollup-freebsd-arm64@4.30.0': + resolution: {integrity: sha512-3REQJ4f90sFIBfa0BUokiCdrV/E4uIjhkWe1bMgCkhFXbf4D8YN6C4zwJL881GM818qVYE9BO3dGwjKhpo2ABA==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.28.0': - resolution: {integrity: sha512-aI2plavbUDjCQB/sRbeUZWX9qp12GfYkYSJOrdYTL/C5D53bsE2/nBPuoiJKoWp5SN78v2Vr8ZPnB+/VbQ2pFA==} + '@rollup/rollup-freebsd-x64@4.30.0': + resolution: {integrity: sha512-ZtY3Y8icbe3Cc+uQicsXG5L+CRGUfLZjW6j2gn5ikpltt3Whqjfo5mkyZ86UiuHF9Q3ZsaQeW7YswlHnN+lAcg==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.28.0': - resolution: {integrity: sha512-WXveUPKtfqtaNvpf0iOb0M6xC64GzUX/OowbqfiCSXTdi/jLlOmH0Ba94/OkiY2yTGTwteo4/dsHRfh5bDCZ+w==} + '@rollup/rollup-linux-arm-gnueabihf@4.30.0': + resolution: {integrity: sha512-bsPGGzfiHXMhQGuFGpmo2PyTwcrh2otL6ycSZAFTESviUoBOuxF7iBbAL5IJXc/69peXl5rAtbewBFeASZ9O0g==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.28.0': - resolution: {integrity: sha512-yLc3O2NtOQR67lI79zsSc7lk31xjwcaocvdD1twL64PK1yNaIqCeWI9L5B4MFPAVGEVjH5k1oWSGuYX1Wutxpg==} + '@rollup/rollup-linux-arm-musleabihf@4.30.0': + resolution: {integrity: sha512-kvyIECEhs2DrrdfQf++maCWJIQ974EI4txlz1nNSBaCdtf7i5Xf1AQCEJWOC5rEBisdaMFFnOWNLYt7KpFqy5A==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.28.0': - resolution: {integrity: sha512-+P9G9hjEpHucHRXqesY+3X9hD2wh0iNnJXX/QhS/J5vTdG6VhNYMxJ2rJkQOxRUd17u5mbMLHM7yWGZdAASfcg==} + '@rollup/rollup-linux-arm64-gnu@4.30.0': + resolution: {integrity: sha512-CFE7zDNrokaotXu+shwIrmWrFxllg79vciH4E/zeK7NitVuWEaXRzS0mFfFvyhZfn8WfVOG/1E9u8/DFEgK7WQ==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.28.0': - resolution: {integrity: sha512-1xsm2rCKSTpKzi5/ypT5wfc+4bOGa/9yI/eaOLW0oMs7qpC542APWhl4A37AENGZ6St6GBMWhCCMM6tXgTIplw==} + '@rollup/rollup-linux-arm64-musl@4.30.0': + resolution: {integrity: sha512-MctNTBlvMcIBP0t8lV/NXiUwFg9oK5F79CxLU+a3xgrdJjfBLVIEHSAjQ9+ipofN2GKaMLnFFXLltg1HEEPaGQ==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.28.0': - resolution: {integrity: sha512-zgWxMq8neVQeXL+ouSf6S7DoNeo6EPgi1eeqHXVKQxqPy1B2NvTbaOUWPn/7CfMKL7xvhV0/+fq/Z/J69g1WAQ==} + '@rollup/rollup-linux-loongarch64-gnu@4.30.0': + resolution: {integrity: sha512-fBpoYwLEPivL3q368+gwn4qnYnr7GVwM6NnMo8rJ4wb0p/Y5lg88vQRRP077gf+tc25akuqd+1Sxbn9meODhwA==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.30.0': + resolution: {integrity: sha512-1hiHPV6dUaqIMXrIjN+vgJqtfkLpqHS1Xsg0oUfUVD98xGp1wX89PIXgDF2DWra1nxAd8dfE0Dk59MyeKaBVAw==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.28.0': - resolution: {integrity: sha512-VEdVYacLniRxbRJLNtzwGt5vwS0ycYshofI7cWAfj7Vg5asqj+pt+Q6x4n+AONSZW/kVm+5nklde0qs2EUwU2g==} + '@rollup/rollup-linux-riscv64-gnu@4.30.0': + resolution: {integrity: sha512-U0xcC80SMpEbvvLw92emHrNjlS3OXjAM0aVzlWfar6PR0ODWCTQtKeeB+tlAPGfZQXicv1SpWwRz9Hyzq3Jx3g==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.28.0': - resolution: {integrity: sha512-LQlP5t2hcDJh8HV8RELD9/xlYtEzJkm/aWGsauvdO2ulfl3QYRjqrKW+mGAIWP5kdNCBheqqqYIGElSRCaXfpw==} + '@rollup/rollup-linux-s390x-gnu@4.30.0': + resolution: {integrity: sha512-VU/P/IODrNPasgZDLIFJmMiLGez+BN11DQWfTVlViJVabyF3JaeaJkP6teI8760f18BMGCQOW9gOmuzFaI1pUw==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.28.0': - resolution: {integrity: sha512-Nl4KIzteVEKE9BdAvYoTkW19pa7LR/RBrT6F1dJCV/3pbjwDcaOq+edkP0LXuJ9kflW/xOK414X78r+K84+msw==} + '@rollup/rollup-linux-x64-gnu@4.30.0': + resolution: {integrity: sha512-laQVRvdbKmjXuFA3ZiZj7+U24FcmoPlXEi2OyLfbpY2MW1oxLt9Au8q9eHd0x6Pw/Kw4oe9gwVXWwIf2PVqblg==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.28.0': - resolution: {integrity: sha512-eKpJr4vBDOi4goT75MvW+0dXcNUqisK4jvibY9vDdlgLx+yekxSm55StsHbxUsRxSTt3JEQvlr3cGDkzcSP8bw==} + '@rollup/rollup-linux-x64-musl@4.30.0': + resolution: {integrity: sha512-3wzKzduS7jzxqcOvy/ocU/gMR3/QrHEFLge5CD7Si9fyHuoXcidyYZ6jyx8OPYmCcGm3uKTUl+9jUSAY74Ln5A==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.28.0': - resolution: {integrity: sha512-Vi+WR62xWGsE/Oj+mD0FNAPY2MEox3cfyG0zLpotZdehPFXwz6lypkGs5y38Jd/NVSbOD02aVad6q6QYF7i8Bg==} + '@rollup/rollup-win32-arm64-msvc@4.30.0': + resolution: {integrity: sha512-jROwnI1+wPyuv696rAFHp5+6RFhXGGwgmgSfzE8e4xfit6oLRg7GyMArVUoM3ChS045OwWr9aTnU+2c1UdBMyw==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.28.0': - resolution: {integrity: sha512-kN/Vpip8emMLn/eOza+4JwqDZBL6MPNpkdaEsgUtW1NYN3DZvZqSQrbKzJcTL6hd8YNmFTn7XGWMwccOcJBL0A==} + '@rollup/rollup-win32-ia32-msvc@4.30.0': + resolution: {integrity: sha512-duzweyup5WELhcXx5H1jokpr13i3BV9b48FMiikYAwk/MT1LrMYYk2TzenBd0jj4ivQIt58JWSxc19y4SvLP4g==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.28.0': - resolution: {integrity: sha512-Bvno2/aZT6usSa7lRDL2+hMjVAGjuqaymF1ApZm31JXzniR/hvr14jpU+/z4X6Gt5BPlzosscyJZGUvguXIqeQ==} + '@rollup/rollup-win32-x64-msvc@4.30.0': + resolution: {integrity: sha512-DYvxS0M07PvgvavMIybCOBYheyrqlui6ZQBHJs6GqduVzHSZ06TPPvlfvnYstjODHQ8UUXFwt5YE+h0jFI8kwg==} cpu: [x64] os: [win32] @@ -3924,68 +3925,68 @@ packages: '@socket.io/component-emitter@3.1.2': resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} - '@swc/core-darwin-arm64@1.9.3': - resolution: {integrity: sha512-hGfl/KTic/QY4tB9DkTbNuxy5cV4IeejpPD4zo+Lzt4iLlDWIeANL4Fkg67FiVceNJboqg48CUX+APhDHO5G1w==} + '@swc/core-darwin-arm64@1.10.4': + resolution: {integrity: sha512-sV/eurLhkjn/197y48bxKP19oqcLydSel42Qsy2zepBltqUx+/zZ8+/IS0Bi7kaWVFxerbW1IPB09uq8Zuvm3g==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] - '@swc/core-darwin-x64@1.9.3': - resolution: {integrity: sha512-IaRq05ZLdtgF5h9CzlcgaNHyg4VXuiStnOFpfNEMuI5fm5afP2S0FHq8WdakUz5WppsbddTdplL+vpeApt/WCQ==} + '@swc/core-darwin-x64@1.10.4': + resolution: {integrity: sha512-gjYNU6vrAUO4+FuovEo9ofnVosTFXkF0VDuo1MKPItz6e2pxc2ale4FGzLw0Nf7JB1sX4a8h06CN16/pLJ8Q2w==} engines: {node: '>=10'} cpu: [x64] os: [darwin] - '@swc/core-linux-arm-gnueabihf@1.9.3': - resolution: {integrity: sha512-Pbwe7xYprj/nEnZrNBvZfjnTxlBIcfApAGdz2EROhjpPj+FBqBa3wOogqbsuGGBdCphf8S+KPprL1z+oDWkmSQ==} + '@swc/core-linux-arm-gnueabihf@1.10.4': + resolution: {integrity: sha512-zd7fXH5w8s+Sfvn2oO464KDWl+ZX1MJiVmE4Pdk46N3PEaNwE0koTfgx2vQRqRG4vBBobzVvzICC3618WcefOA==} engines: {node: '>=10'} cpu: [arm] os: [linux] - '@swc/core-linux-arm64-gnu@1.9.3': - resolution: {integrity: sha512-AQ5JZiwNGVV/2K2TVulg0mw/3LYfqpjZO6jDPtR2evNbk9Yt57YsVzS+3vHSlUBQDRV9/jqMuZYVU3P13xrk+g==} + '@swc/core-linux-arm64-gnu@1.10.4': + resolution: {integrity: sha512-+UGfoHDxsMZgFD3tABKLeEZHqLNOkxStu+qCG7atGBhS4Slri6h6zijVvf4yI5X3kbXdvc44XV/hrP/Klnui2A==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-arm64-musl@1.9.3': - resolution: {integrity: sha512-tzVH480RY6RbMl/QRgh5HK3zn1ZTFsThuxDGo6Iuk1MdwIbdFYUY034heWUTI4u3Db97ArKh0hNL0xhO3+PZdg==} + '@swc/core-linux-arm64-musl@1.10.4': + resolution: {integrity: sha512-cDDj2/uYsOH0pgAnDkovLZvKJpFmBMyXkxEG6Q4yw99HbzO6QzZ5HDGWGWVq/6dLgYKlnnmpjZCPPQIu01mXEg==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-x64-gnu@1.9.3': - resolution: {integrity: sha512-ivXXBRDXDc9k4cdv10R21ccBmGebVOwKXT/UdH1PhxUn9m/h8erAWjz5pcELwjiMf27WokqPgaWVfaclDbgE+w==} + '@swc/core-linux-x64-gnu@1.10.4': + resolution: {integrity: sha512-qJXh9D6Kf5xSdGWPINpLGixAbB5JX8JcbEJpRamhlDBoOcQC79dYfOMEIxWPhTS1DGLyFakAx2FX/b2VmQmj0g==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-linux-x64-musl@1.9.3': - resolution: {integrity: sha512-ILsGMgfnOz1HwdDz+ZgEuomIwkP1PHT6maigZxaCIuC6OPEhKE8uYna22uU63XvYcLQvZYDzpR3ms47WQPuNEg==} + '@swc/core-linux-x64-musl@1.10.4': + resolution: {integrity: sha512-A76lIAeyQnHCVt0RL/pG+0er8Qk9+acGJqSZOZm67Ve3B0oqMd871kPtaHBM0BW3OZAhoILgfHW3Op9Q3mx3Cw==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-win32-arm64-msvc@1.9.3': - resolution: {integrity: sha512-e+XmltDVIHieUnNJHtspn6B+PCcFOMYXNJB1GqoCcyinkEIQNwC8KtWgMqUucUbEWJkPc35NHy9k8aCXRmw9Kg==} + '@swc/core-win32-arm64-msvc@1.10.4': + resolution: {integrity: sha512-e6j5kBu4fIY7fFxFxnZI0MlEovRvp50Lg59Fw+DVbtqHk3C85dckcy5xKP+UoXeuEmFceauQDczUcGs19SRGSQ==} engines: {node: '>=10'} cpu: [arm64] os: [win32] - '@swc/core-win32-ia32-msvc@1.9.3': - resolution: {integrity: sha512-rqpzNfpAooSL4UfQnHhkW8aL+oyjqJniDP0qwZfGnjDoJSbtPysHg2LpcOBEdSnEH+uIZq6J96qf0ZFD8AGfXA==} + '@swc/core-win32-ia32-msvc@1.10.4': + resolution: {integrity: sha512-RSYHfdKgNXV/amY5Tqk1EWVsyQnhlsM//jeqMLw5Fy9rfxP592W9UTumNikNRPdjI8wKKzNMXDb1U29tQjN0dg==} engines: {node: '>=10'} cpu: [ia32] os: [win32] - '@swc/core-win32-x64-msvc@1.9.3': - resolution: {integrity: sha512-3YJJLQ5suIEHEKc1GHtqVq475guiyqisKSoUnoaRtxkDaW5g1yvPt9IoSLOe2mRs7+FFhGGU693RsBUSwOXSdQ==} + '@swc/core-win32-x64-msvc@1.10.4': + resolution: {integrity: sha512-1ujYpaqfqNPYdwKBlvJnOqcl+Syn3UrQ4XE0Txz6zMYgyh6cdU6a3pxqLqIUSJ12MtXRA9ZUhEz1ekU3LfLWXw==} engines: {node: '>=10'} cpu: [x64] os: [win32] - '@swc/core@1.9.3': - resolution: {integrity: sha512-oRj0AFePUhtatX+BscVhnzaAmWjpfAeySpM1TCbxA1rtBDeH/JDhi5yYzAKneDYtVtBvA7ApfeuzhMC9ye4xSg==} + '@swc/core@1.10.4': + resolution: {integrity: sha512-ut3zfiTLORMxhr6y/GBxkHmzcGuVpwJYX4qyXWuBKkpw/0g0S5iO1/wW7RnLnZbAi8wS/n0atRZoaZlXWBkeJg==} engines: {node: '>=10'} peerDependencies: '@swc/helpers': '*' @@ -4106,8 +4107,8 @@ packages: '@types/d3-scale@4.0.8': resolution: {integrity: sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==} - '@types/d3-shape@3.1.6': - resolution: {integrity: sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==} + '@types/d3-shape@3.1.7': + resolution: {integrity: sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==} '@types/d3-time-format@4.0.3': resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} @@ -4303,8 +4304,8 @@ packages: resolution: {integrity: sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/scope-manager@8.17.0': - resolution: {integrity: sha512-/ewp4XjvnxaREtqsZjF4Mfn078RD/9GmiEAtTeLQ7yFdKnqwTOgRMSvFz4et9U5RiJQ15WTGXPLj89zGusvxBg==} + '@typescript-eslint/scope-manager@8.19.0': + resolution: {integrity: sha512-hkoJiKQS3GQ13TSMEiuNmSCvhz7ujyqD1x3ShbaETATHrck+9RaDdUbt+osXaUuns9OFwrDTTrjtwsU8gJyyRA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typescript-eslint/type-utils@7.18.0': @@ -4321,8 +4322,8 @@ packages: resolution: {integrity: sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/types@8.17.0': - resolution: {integrity: sha512-gY2TVzeve3z6crqh2Ic7Cr+CAv6pfb0Egee7J5UAVWCpVvDI/F71wNfolIim4FE6hT15EbpZFVUj9j5i38jYXA==} + '@typescript-eslint/types@8.19.0': + resolution: {integrity: sha512-8XQ4Ss7G9WX8oaYvD4OOLCjIQYgRQxO+qCiR2V2s2GxI9AUpo7riNwo6jDhKtTcaJjT8PY54j2Yb33kWtSJsmA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typescript-eslint/typescript-estree@7.18.0': @@ -4334,14 +4335,11 @@ packages: typescript: optional: true - '@typescript-eslint/typescript-estree@8.17.0': - resolution: {integrity: sha512-JqkOopc1nRKZpX+opvKqnM3XUlM7LpFMD0lYxTqOTKQfCWAmxw45e3qlOCsEqEB2yuacujivudOFpCnqkBDNMw==} + '@typescript-eslint/typescript-estree@8.19.0': + resolution: {integrity: sha512-WW9PpDaLIFW9LCbucMSdYUuGeFUz1OkWYS/5fwZwTA+l2RwlWFdJvReQqMUMBw4yJWJOfqd7An9uwut2Oj8sLw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + typescript: '>=4.8.4 <5.8.0' '@typescript-eslint/utils@7.18.0': resolution: {integrity: sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==} @@ -4349,26 +4347,23 @@ packages: peerDependencies: eslint: ^8.56.0 - '@typescript-eslint/utils@8.17.0': - resolution: {integrity: sha512-bQC8BnEkxqG8HBGKwG9wXlZqg37RKSMY7v/X8VEWD8JG2JuTHuNK0VFvMPMUKQcbk6B+tf05k+4AShAEtCtJ/w==} + '@typescript-eslint/utils@8.19.0': + resolution: {integrity: sha512-PTBG+0oEMPH9jCZlfg07LCB2nYI0I317yyvXGfxnvGvw4SHIOuRnQ3kadyyXY6tGdChusIHIbM5zfIbp4M6tCg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + typescript: '>=4.8.4 <5.8.0' '@typescript-eslint/visitor-keys@7.18.0': resolution: {integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/visitor-keys@8.17.0': - resolution: {integrity: sha512-1Hm7THLpO6ww5QU6H/Qp+AusUUl+z/CAm3cNZZ0jQvon9yicgO7Rwd+/WWRpMKLYV6p2UvdbR27c86rzCPpreg==} + '@typescript-eslint/visitor-keys@8.19.0': + resolution: {integrity: sha512-mCFtBbFBJDCNCWUl5y6sZSCHXw1DEFEk3c/M3nRK2a4XUB8StGFtmcEMizdjKuBzB6e/smJAAWYug3VrdLMr1w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@ungap/structured-clone@1.2.0': - resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + '@ungap/structured-clone@1.2.1': + resolution: {integrity: sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==} '@vitejs/plugin-react-swc@3.7.2': resolution: {integrity: sha512-y0byko2b2tSVVf5Gpng1eEhX1OvPC7x8yns1Fx8jDzlJp4LS6CMkCPfLw47cjyoMrshQDoQw4qcgjsU9VvlCew==} @@ -4560,8 +4555,8 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} - agent-base@7.1.1: - resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} + agent-base@7.1.3: + resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} engines: {node: '>= 14'} aggregate-error@3.1.0: @@ -4599,8 +4594,8 @@ packages: ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} - algoliasearch@5.15.0: - resolution: {integrity: sha512-Yf3Swz1s63hjvBVZ/9f2P1Uu48GjmjCN+Esxb6MAONMGtZB1fRX8/S1AhUTtsuTlcGovbYLxpHgc7wEzstDZBw==} + algoliasearch@5.18.0: + resolution: {integrity: sha512-/tfpK2A4FpS0o+S78o3YSdlqXr0MavJIDlFK3XZrlXLy7vaRXJvW5jYg3v5e/wCaF8y0IpMjkYLhoV6QqfpOgw==} engines: {node: '>= 14.0.0'} amdefine@1.0.1: @@ -4730,8 +4725,8 @@ packages: resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} engines: {node: '>= 0.4'} - array.prototype.flat@1.3.2: - resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + array.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} engines: {node: '>= 0.4'} array.prototype.flatmap@1.3.3: @@ -4807,8 +4802,8 @@ packages: resolution: {integrity: sha512-RE3mdQ7P3FRSe7eqCWoeQ/Z9QXrtniSjp1wUjt5nRC3WIpz5rSCve6o3fsZ2aCpJtrZjSZgjwXAoTO5k4tEI0w==} engines: {node: '>=4'} - axios@1.7.8: - resolution: {integrity: sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw==} + axios@1.7.9: + resolution: {integrity: sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==} axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} @@ -4943,8 +4938,8 @@ packages: browser-stdout@1.3.1: resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} - browserslist@4.24.2: - resolution: {integrity: sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==} + browserslist@4.24.3: + resolution: {integrity: sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -5042,8 +5037,8 @@ packages: camelize@1.0.1: resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==} - caniuse-lite@1.0.30001686: - resolution: {integrity: sha512-Y7deg0Aergpa24M3qLC5xjNklnKnhsmSyR/V89dLZ1n0ucJIFNs7PgR2Yfa/Zf6W79SbBicgtGxZr2juHkEUIA==} + caniuse-lite@1.0.30001690: + resolution: {integrity: sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==} chai-dom@1.12.0: resolution: {integrity: sha512-pLP8h6IBR8z1AdeQ+EMcJ7dXPdsax/1Q7gdGZjsnAmSBl3/gItQUYSCo32br1qOy4SlcBjvqId7ilAf3uJ2K1w==} @@ -5627,6 +5622,15 @@ packages: supports-color: optional: true + debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + decamelize-keys@1.1.1: resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} engines: {node: '>=0.10.0'} @@ -5789,8 +5793,8 @@ packages: resolution: {integrity: sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==} engines: {node: '>=12'} - dotenv@16.4.6: - resolution: {integrity: sha512-JhcR/+KIjkkjiU8yEpaB/USlzVi3i5whwOjpIRNGi9svKEXZSe+Qp6IWAjFjv+2GViAoDRCUv/QLNziQxsLqDg==} + dotenv@16.4.7: + resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} engines: {node: '>=12'} dunder-proto@1.0.1: @@ -5817,8 +5821,8 @@ packages: engines: {node: '>=0.10.0'} hasBin: true - electron-to-chromium@1.5.68: - resolution: {integrity: sha512-FgMdJlma0OzUYlbrtZ4AeXjKxKPk6KT8WOP8BjcqxWtlg8qyJQjRzPJzUtUn5GBg1oQ26hFs7HOOHJMYiJRnvQ==} + electron-to-chromium@1.5.76: + resolution: {integrity: sha512-CjVQyG7n7Sr+eBXE86HIulnL5N8xZY1sgmOPGuq/F0Rr0FJq63lg0kEtOIDfZBk44FnDLf6FUJ+dsJcuiUDdDQ==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -5856,16 +5860,16 @@ packages: resolution: {integrity: sha512-kxpoMgrdtkXZ5h0SeraBS1iRntpTpQ3R8ussdb38+UAFnMGX5DDyJXePm+OCHOcoXvHDw7mc2erbJBpDnl7TPw==} engines: {node: '>=0.6'} - enhanced-resolve@5.17.1: - resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==} + enhanced-resolve@5.18.0: + resolution: {integrity: sha512-0/r0MySGYG8YqlayBZ6MuCfECmHFdJ5qyPh8s8wa5Hnm6SaFLSK1VYCbj+NKp090Nm1caZhD+QTnmxO7esYGyQ==} engines: {node: '>=10.13.0'} enquirer@2.3.6: resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==} engines: {node: '>=8.6'} - ent@2.2.1: - resolution: {integrity: sha512-QHuXVeZx9d+tIQAz/XztU0ZwZf2Agg9CcXcgE1rurqvdBeDBrpSwjl8/6XUqMg7tw2Y7uAdKb2sRv+bSEFqQ5A==} + ent@2.2.2: + resolution: {integrity: sha512-kKvD1tO6BM+oK9HzCPpUdRb4vKFQY/FPTFmurMvh6LlN68VMrdj77w8yp51/kDbpkFOS9J8w5W6zIzgM2H8/hw==} engines: {node: '>= 0.4'} entities@2.2.0: @@ -5895,8 +5899,8 @@ packages: error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - es-abstract@1.23.7: - resolution: {integrity: sha512-OygGC8kIcDhXX+6yAZRGLqwi2CmEXCbLQixeGUgYeR+Qwlppqmo7DIDr8XibtEBZp+fJcoYpoatp5qwLMEdcqQ==} + es-abstract@1.23.9: + resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==} engines: {node: '>= 0.4'} es-array-method-boxes-properly@1.0.0: @@ -5914,15 +5918,15 @@ packages: resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} engines: {node: '>= 0.4'} - es-module-lexer@1.5.4: - resolution: {integrity: sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==} + es-module-lexer@1.6.0: + resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==} es-object-atoms@1.0.0: resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} engines: {node: '>= 0.4'} - es-set-tostringtag@2.0.3: - resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} es-shim-unscopables@1.0.2: @@ -6238,6 +6242,9 @@ packages: resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} engines: {node: '>=4'} + fast-content-type-parse@2.0.1: + resolution: {integrity: sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q==} + fast-csv@4.3.6: resolution: {integrity: sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw==} engines: {node: '>=10.0.0'} @@ -6252,8 +6259,8 @@ packages: resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} engines: {node: '>=8.6.0'} - fast-glob@3.3.2: - resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} fast-json-patch@3.1.1: @@ -6265,15 +6272,15 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-uri@3.0.3: - resolution: {integrity: sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==} + fast-uri@3.0.4: + resolution: {integrity: sha512-G3iTQw1DizJQ5eEqj1CbFCWhq+pzum7qepkxU7rS1FGZDqjYKcrguo9XDRbV7EgPnn8CgaPigTq+NEjyioeYZQ==} fastest-levenshtein@1.0.16: resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} engines: {node: '>= 4.9.1'} - fastq@1.17.1: - resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + fastq@1.18.0: + resolution: {integrity: sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==} fdir@6.4.2: resolution: {integrity: sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==} @@ -6366,8 +6373,8 @@ packages: flatted@3.3.2: resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==} - flow-parser@0.255.0: - resolution: {integrity: sha512-7QHV2m2mIMh6yIMaAPOVbyNEW77IARwO69d4DgvfDCjuORiykdMLf7XBjF7Zeov7Cpe1OXJ8sB6/aaCE3xuRBw==} + flow-parser@0.258.0: + resolution: {integrity: sha512-/f3ui3WaPTRUtqnWaGzf/f352hn4VhqGOiuSVkgaW6SbHNp5EwdDoh6BF3zB9A6kcWhCpg/0x0A3aXU+KXugAA==} engines: {node: '>=0.4.0'} follow-redirects@1.15.9: @@ -6491,8 +6498,8 @@ packages: get-func-name@2.0.2: resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} - get-intrinsic@1.2.6: - resolution: {integrity: sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==} + get-intrinsic@1.2.7: + resolution: {integrity: sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==} engines: {node: '>= 0.4'} get-package-type@0.1.0: @@ -6508,6 +6515,10 @@ packages: resolution: {integrity: sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==} engines: {node: '>=8'} + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + get-stdin@6.0.0: resolution: {integrity: sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==} engines: {node: '>=4'} @@ -6640,8 +6651,8 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - graphql@16.9.0: - resolution: {integrity: sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==} + graphql@16.10.0: + resolution: {integrity: sha512-AjqGKbDGUFRKIRCP9tCKiIGHyriz2oHEbPIbEtcSLSs4YjReZOIPQQWek4+6hjw62H9QShXHyaGivGiYVLeYFQ==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} gtoken@7.1.0: @@ -6661,8 +6672,9 @@ packages: resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} engines: {node: '>=6'} - has-bigints@1.0.2: - resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} has-flag@1.0.0: resolution: {integrity: sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==} @@ -6791,8 +6803,8 @@ packages: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} - https-proxy-agent@7.0.5: - resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==} + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} human-signals@2.1.0: @@ -6914,8 +6926,8 @@ packages: is-alphanumerical@2.0.1: resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} - is-arguments@1.1.1: - resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} + is-arguments@1.2.0: + resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} engines: {node: '>= 0.4'} is-array-buffer@3.0.5: @@ -6928,8 +6940,8 @@ packages: is-arrayish@0.3.2: resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} - is-async-function@2.0.0: - resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} + is-async-function@2.1.0: + resolution: {integrity: sha512-GExz9MtyhlZyXYLxzlJRj5WUCE661zhDa1Yna52CN57AJsymh+DvXXjyveSioqSRdxvUrdKdvqB1b5cVKsNpWQ==} engines: {node: '>= 0.4'} is-bigint@1.1.0: @@ -6952,8 +6964,8 @@ packages: resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} hasBin: true - is-core-module@2.16.0: - resolution: {integrity: sha512-urTSINYfAYgcbLb0yDQ6egFm6h3Mo1DcF9EkyXSRjjzdHbsulg01qhwWuXdOoUBuTkbQ80KDboXa0vFJ+BDH+g==} + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} is-data-view@1.0.2: @@ -6983,16 +6995,16 @@ packages: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} - is-finalizationregistry@1.1.0: - resolution: {integrity: sha512-qfMdqbAQEwBw78ZyReKnlA8ezmPdb9BemzIIip/JkjaZUhitfXDkkr+3QTboW0JrSXT1QWyYShpvnNHGZ4c4yA==} + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} engines: {node: '>= 0.4'} is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} - is-generator-function@1.0.10: - resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + is-generator-function@1.1.0: + resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} engines: {node: '>= 0.4'} is-glob@4.0.3: @@ -7127,8 +7139,8 @@ packages: resolution: {integrity: sha512-SXM8Nwyys6nT5WP6pltOwKytLV7FqQ4UiibxVmW+EIosHcmCqkkjViTb5SNssDlkCiEYRP1/pdWUKVvZBmsR2Q==} engines: {node: '>= 0.4'} - is-weakset@2.0.3: - resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} engines: {node: '>= 0.4'} is-windows@1.0.2: @@ -7199,8 +7211,8 @@ packages: Visit https://istanbul.js.org/integrations for other alternatives. hasBin: true - iterator.prototype@1.1.4: - resolution: {integrity: sha512-x4WH0BWmrMmg4oHHl+duwubhrvczGlyuGAZu3nvrf0UXOfPu8IhZObFEr7DE/iv01YgVZrsOiRcqw2srkKEDIA==} + iterator.prototype@1.1.5: + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} engines: {node: '>= 0.4'} jackspeak@3.4.3: @@ -7272,6 +7284,11 @@ packages: engines: {node: '>=6'} hasBin: true + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + json-bigint@1.0.0: resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} @@ -7426,8 +7443,8 @@ packages: engines: {node: '>= 10'} hasBin: true - katex@0.16.18: - resolution: {integrity: sha512-LRuk0rPdXrecAFwQucYjMiIs0JFefk6N1q/04mlw14aVIVgxq1FO0MA9RiIIGVaKOB5GIP5GH4aBBNraZERmaQ==} + katex@0.16.19: + resolution: {integrity: sha512-3IA6DYVhxhBabjSLTNO9S4+OliA3Qvb8pBQXMfC4WxXJgLwZgnfDl0BmB4z6nBMdznBsZ+CGM8DrGZ5hcguDZg==} hasBin: true keyv@4.5.4: @@ -7678,8 +7695,8 @@ packages: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true - magic-string@0.30.14: - resolution: {integrity: sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==} + magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} make-array@1.0.5: resolution: {integrity: sha512-sgK2SAzxT19rWU+qxKUcn6PAh/swiIiz2F8C2cZjLc1z4iwYIfdoihqFIDQ8BDzAGtWPYJ6Sr13K1j/DXynDLA==} @@ -7733,8 +7750,8 @@ packages: resolution: {integrity: sha512-eoQqH0291YCCjd+Pe1PUQ9AmWthlVmS0XWgcionkZ8q34ceZyRI+pYvsWksXJJL8OBkWCPwp1h/pnXxrPFC4oA==} engines: {node: '>=18'} - marked@15.0.4: - resolution: {integrity: sha512-TCHvDqmb3ZJ4PWG7VEGVgtefA5/euFmsIhxtD0XsBxI39gUSKL81mIRFdt0AiNQozUahd4ke98ZdirExd/vSEw==} + marked@15.0.5: + resolution: {integrity: sha512-xN+kSuqHjxWg+Q47yhhZMUP+kO1qHobvXkkm6FX+7N6lDvanLDd8H7AQ0jWDDyq+fDt/cSrJaBGyWYHXy0KQWA==} engines: {node: '>= 18'} hasBin: true @@ -8033,8 +8050,8 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - msw@2.6.6: - resolution: {integrity: sha512-npfIIVRHKQX3Lw4aLWX4wBh+lQwpqdZNyJYB5K/+ktK8NhtkdsTxGK7WDrgknozcVyRI7TOqY6yBS9j2FTR+YQ==} + msw@2.7.0: + resolution: {integrity: sha512-BIodwZ19RWfCbYTxWTUfTXc+sg4OwjCAgxU1ZsgmggX/7S3LdUifsbUPJs61j0rWb19CZRGY5if77duhc0uXzw==} engines: {node: '>=18'} hasBin: true peerDependencies: @@ -8161,8 +8178,8 @@ packages: resolution: {integrity: sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==} engines: {node: '>=8'} - node-releases@2.0.18: - resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} nopt@3.0.6: resolution: {integrity: sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==} @@ -8237,8 +8254,8 @@ packages: nwsapi@2.2.16: resolution: {integrity: sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==} - nx@20.1.4: - resolution: {integrity: sha512-hyvGYxTzBkPxSXAB2tuqdv9TpVde5xOdGalsIdhF7j7PI3nwPpqtc3y28YTgRgpxtOE1Y6BfDNkXMO1SW0xu2w==} + nx@20.3.0: + resolution: {integrity: sha512-Nzi4k7tV22zwO2iBLk+pHxorLEWPJpPrVCACtz0SQ63j/LiAgfhoqruJO+VU+V+E9qdyPsvmqIL/Iaf/GRQlqA==} hasBin: true peerDependencies: '@swc-node/register': ^1.8.0 @@ -8356,6 +8373,10 @@ packages: override-require@1.1.1: resolution: {integrity: sha512-eoJ9YWxFcXbrn2U8FKT6RV+/Kj7fiGAB1VvHzbYKt8xM5ZuKZgCGvnHzDxmreEjcBH28ejg5MiOH4iyY1mQnkg==} + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + p-event@5.0.1: resolution: {integrity: sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -8986,8 +9007,8 @@ packages: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} - reflect.getprototypeof@1.0.9: - resolution: {integrity: sha512-r0Ay04Snci87djAsI4U+WNRcSw5S4pOH7qFjd/veA5gC7TbqESR3tcj28ia95L/fYUDw11JKP7uqUKUAfVvV5Q==} + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} regenerate-unicode-properties@10.2.0: @@ -9006,8 +9027,8 @@ packages: regenerator-transform@0.15.2: resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==} - regexp.prototype.flags@1.5.3: - resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} regexpu-core@6.2.0: @@ -9083,6 +9104,10 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + resolve.exports@2.0.3: + resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==} + engines: {node: '>=10'} + resolve@1.1.7: resolution: {integrity: sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==} @@ -9142,8 +9167,8 @@ packages: robust-predicates@3.0.2: resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} - rollup@4.28.0: - resolution: {integrity: sha512-G9GOrmgWHBma4YfCcX8PjH0qhXSdH8B4HDE2o4/jaxj93S4DPCIDoLcXz99eWMji4hB29UFCEd7B2gwGJDR9cQ==} + rollup@4.30.0: + resolution: {integrity: sha512-sDnr1pcjTgUT69qBksNF1N1anwfbyYG6TBQ22b03bII8EdiUQ7J0TlozVaTMjT/eEJAO49e1ndV7t+UZfL1+vA==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -9177,6 +9202,10 @@ packages: safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + safe-regex-test@1.1.0: resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} engines: {node: '>= 0.4'} @@ -9249,6 +9278,10 @@ packages: resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} engines: {node: '>= 0.4'} + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} @@ -9356,8 +9389,8 @@ packages: resolution: {integrity: sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==} engines: {node: '>=10.2.0'} - socks-proxy-agent@8.0.4: - resolution: {integrity: sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==} + socks-proxy-agent@8.0.5: + resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} engines: {node: '>= 14'} socks@2.8.3: @@ -9642,8 +9675,8 @@ packages: uglify-js: optional: true - terser@5.36.0: - resolution: {integrity: sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==} + terser@5.37.0: + resolution: {integrity: sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==} engines: {node: '>=10'} hasBin: true @@ -9683,8 +9716,8 @@ packages: tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinyexec@0.3.1: - resolution: {integrity: sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==} + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} tinyglobby@0.2.10: resolution: {integrity: sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==} @@ -9702,11 +9735,11 @@ packages: resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} engines: {node: '>=14.0.0'} - tldts-core@6.1.65: - resolution: {integrity: sha512-Uq5t0N0Oj4nQSbU8wFN1YYENvMthvwU13MQrMJRspYCGLSAZjAfoBOJki5IQpnBM/WFskxxC/gIOTwaedmHaSg==} + tldts-core@6.1.71: + resolution: {integrity: sha512-LRbChn2YRpic1KxY+ldL1pGXN/oVvKfCVufwfVzEQdFYNo39uF7AJa/WXdo+gYO7PTvdfkCPCed6Hkvz/kR7jg==} - tldts@6.1.65: - resolution: {integrity: sha512-xU9gLTfAGsADQ2PcWee6Hg8RFAv0DnjMGVJmDnUmI8a9+nYmapMQix4afwrdaCtT+AqP4MaxEzu7cCrYmBPbzQ==} + tldts@6.1.71: + resolution: {integrity: sha512-LQIHmHnuzfZgZWAf2HzL83TIIrD8NhhI0DVxqo9/FdOd4ilec+NTNZOlDZf7EwrTNoutccbsHjvWHYXLAtvxjw==} hasBin: true tmp@0.0.33: @@ -9845,8 +9878,8 @@ packages: resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} engines: {node: '>=12.20'} - type-fest@4.30.0: - resolution: {integrity: sha512-G6zXWS1dLj6eagy6sVhOMQiLtJdxQBHIA9Z6HFUNLOlr6MFOgzV8wvmidtPONfPtEUv0uZsy77XJNzTAfwPDaA==} + type-fest@4.31.0: + resolution: {integrity: sha512-yCxltHW07Nkhv/1F6wWBr8kz+5BGMfP+RbRSYFnegVb0qV/UMT0G0ElBloPVerqn4M2ZV80Ir1FtCcYv1cT6vQ==} engines: {node: '>=16'} type-is@1.6.18: @@ -9884,8 +9917,8 @@ packages: engines: {node: '>=14.17'} hasBin: true - ua-parser-js@0.7.39: - resolution: {integrity: sha512-IZ6acm6RhQHNibSt7+c09hhvsKy9WUr4DVbeq9U8o71qxyYtJpQeDxQnMrVqnIFMLcQjHO0I9wgfO2vIahht4w==} + ua-parser-js@0.7.40: + resolution: {integrity: sha512-us1E3K+3jJppDBa3Tl0L3MOJiGhe1C6P0+nIvQAFYbxlMAx0h81eOwLmU57xgqToduDDPx3y5QsdjPfDu+FgOQ==} hasBin: true uc.micro@2.1.0: @@ -10030,8 +10063,8 @@ packages: resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} hasBin: true - uuid@11.0.3: - resolution: {integrity: sha512-d0z310fCWv5dJwnX1Y/MncBAqGMKEzlBb1AOf7z9K8ALnd0utBX/msg/fA0+sbyN1ihbMsLhrBlnl1ak7Wa0rg==} + uuid@11.0.4: + resolution: {integrity: sha512-IzL6VtTTYcAhA/oghbFJ1Dkmqev+FpQWnCBaKq/gUluLxliWvO8DPFWfIviRmYbtaavtSQe4WBL++rFjdcGWEg==} hasBin: true uuid@8.3.2: @@ -10201,8 +10234,8 @@ packages: resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} engines: {node: '>=18'} - whatwg-url@14.0.0: - resolution: {integrity: sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==} + whatwg-url@14.1.0: + resolution: {integrity: sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==} engines: {node: '>=18'} whatwg-url@5.0.0: @@ -10373,6 +10406,11 @@ packages: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} + yaml@2.7.0: + resolution: {integrity: sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==} + engines: {node: '>= 14'} + hasBin: true + yargs-parser@18.1.3: resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} engines: {node: '>=6'} @@ -10427,8 +10465,8 @@ packages: peerDependencies: zod: ^3.18.0 - zod@3.23.8: - resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} + zod@3.24.1: + resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==} zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} @@ -10460,119 +10498,119 @@ snapshots: '@adobe/css-tools@4.4.1': {} - '@algolia/autocomplete-core@1.17.7(@algolia/client-search@5.15.0)(algoliasearch@5.15.0)(search-insights@2.17.3)': + '@algolia/autocomplete-core@1.17.7(@algolia/client-search@5.18.0)(algoliasearch@5.18.0)(search-insights@2.17.3)': dependencies: - '@algolia/autocomplete-plugin-algolia-insights': 1.17.7(@algolia/client-search@5.15.0)(algoliasearch@5.15.0)(search-insights@2.17.3) - '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.15.0)(algoliasearch@5.15.0) + '@algolia/autocomplete-plugin-algolia-insights': 1.17.7(@algolia/client-search@5.18.0)(algoliasearch@5.18.0)(search-insights@2.17.3) + '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.18.0)(algoliasearch@5.18.0) transitivePeerDependencies: - '@algolia/client-search' - algoliasearch - search-insights - '@algolia/autocomplete-plugin-algolia-insights@1.17.7(@algolia/client-search@5.15.0)(algoliasearch@5.15.0)(search-insights@2.17.3)': + '@algolia/autocomplete-plugin-algolia-insights@1.17.7(@algolia/client-search@5.18.0)(algoliasearch@5.18.0)(search-insights@2.17.3)': dependencies: - '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.15.0)(algoliasearch@5.15.0) + '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.18.0)(algoliasearch@5.18.0) search-insights: 2.17.3 transitivePeerDependencies: - '@algolia/client-search' - algoliasearch - '@algolia/autocomplete-preset-algolia@1.17.7(@algolia/client-search@5.15.0)(algoliasearch@5.15.0)': + '@algolia/autocomplete-preset-algolia@1.17.7(@algolia/client-search@5.18.0)(algoliasearch@5.18.0)': dependencies: - '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.15.0)(algoliasearch@5.15.0) - '@algolia/client-search': 5.15.0 - algoliasearch: 5.15.0 + '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.18.0)(algoliasearch@5.18.0) + '@algolia/client-search': 5.18.0 + algoliasearch: 5.18.0 - '@algolia/autocomplete-shared@1.17.7(@algolia/client-search@5.15.0)(algoliasearch@5.15.0)': + '@algolia/autocomplete-shared@1.17.7(@algolia/client-search@5.18.0)(algoliasearch@5.18.0)': dependencies: - '@algolia/client-search': 5.15.0 - algoliasearch: 5.15.0 + '@algolia/client-search': 5.18.0 + algoliasearch: 5.18.0 - '@algolia/client-abtesting@5.15.0': + '@algolia/client-abtesting@5.18.0': dependencies: - '@algolia/client-common': 5.15.0 - '@algolia/requester-browser-xhr': 5.15.0 - '@algolia/requester-fetch': 5.15.0 - '@algolia/requester-node-http': 5.15.0 + '@algolia/client-common': 5.18.0 + '@algolia/requester-browser-xhr': 5.18.0 + '@algolia/requester-fetch': 5.18.0 + '@algolia/requester-node-http': 5.18.0 - '@algolia/client-analytics@5.15.0': + '@algolia/client-analytics@5.18.0': dependencies: - '@algolia/client-common': 5.15.0 - '@algolia/requester-browser-xhr': 5.15.0 - '@algolia/requester-fetch': 5.15.0 - '@algolia/requester-node-http': 5.15.0 + '@algolia/client-common': 5.18.0 + '@algolia/requester-browser-xhr': 5.18.0 + '@algolia/requester-fetch': 5.18.0 + '@algolia/requester-node-http': 5.18.0 - '@algolia/client-common@5.15.0': {} + '@algolia/client-common@5.18.0': {} - '@algolia/client-insights@5.15.0': + '@algolia/client-insights@5.18.0': dependencies: - '@algolia/client-common': 5.15.0 - '@algolia/requester-browser-xhr': 5.15.0 - '@algolia/requester-fetch': 5.15.0 - '@algolia/requester-node-http': 5.15.0 + '@algolia/client-common': 5.18.0 + '@algolia/requester-browser-xhr': 5.18.0 + '@algolia/requester-fetch': 5.18.0 + '@algolia/requester-node-http': 5.18.0 - '@algolia/client-personalization@5.15.0': + '@algolia/client-personalization@5.18.0': dependencies: - '@algolia/client-common': 5.15.0 - '@algolia/requester-browser-xhr': 5.15.0 - '@algolia/requester-fetch': 5.15.0 - '@algolia/requester-node-http': 5.15.0 + '@algolia/client-common': 5.18.0 + '@algolia/requester-browser-xhr': 5.18.0 + '@algolia/requester-fetch': 5.18.0 + '@algolia/requester-node-http': 5.18.0 - '@algolia/client-query-suggestions@5.15.0': + '@algolia/client-query-suggestions@5.18.0': dependencies: - '@algolia/client-common': 5.15.0 - '@algolia/requester-browser-xhr': 5.15.0 - '@algolia/requester-fetch': 5.15.0 - '@algolia/requester-node-http': 5.15.0 + '@algolia/client-common': 5.18.0 + '@algolia/requester-browser-xhr': 5.18.0 + '@algolia/requester-fetch': 5.18.0 + '@algolia/requester-node-http': 5.18.0 - '@algolia/client-search@5.15.0': + '@algolia/client-search@5.18.0': dependencies: - '@algolia/client-common': 5.15.0 - '@algolia/requester-browser-xhr': 5.15.0 - '@algolia/requester-fetch': 5.15.0 - '@algolia/requester-node-http': 5.15.0 + '@algolia/client-common': 5.18.0 + '@algolia/requester-browser-xhr': 5.18.0 + '@algolia/requester-fetch': 5.18.0 + '@algolia/requester-node-http': 5.18.0 - '@algolia/ingestion@1.15.0': + '@algolia/ingestion@1.18.0': dependencies: - '@algolia/client-common': 5.15.0 - '@algolia/requester-browser-xhr': 5.15.0 - '@algolia/requester-fetch': 5.15.0 - '@algolia/requester-node-http': 5.15.0 + '@algolia/client-common': 5.18.0 + '@algolia/requester-browser-xhr': 5.18.0 + '@algolia/requester-fetch': 5.18.0 + '@algolia/requester-node-http': 5.18.0 - '@algolia/monitoring@1.15.0': + '@algolia/monitoring@1.18.0': dependencies: - '@algolia/client-common': 5.15.0 - '@algolia/requester-browser-xhr': 5.15.0 - '@algolia/requester-fetch': 5.15.0 - '@algolia/requester-node-http': 5.15.0 + '@algolia/client-common': 5.18.0 + '@algolia/requester-browser-xhr': 5.18.0 + '@algolia/requester-fetch': 5.18.0 + '@algolia/requester-node-http': 5.18.0 - '@algolia/recommend@5.15.0': + '@algolia/recommend@5.18.0': dependencies: - '@algolia/client-common': 5.15.0 - '@algolia/requester-browser-xhr': 5.15.0 - '@algolia/requester-fetch': 5.15.0 - '@algolia/requester-node-http': 5.15.0 + '@algolia/client-common': 5.18.0 + '@algolia/requester-browser-xhr': 5.18.0 + '@algolia/requester-fetch': 5.18.0 + '@algolia/requester-node-http': 5.18.0 - '@algolia/requester-browser-xhr@5.15.0': + '@algolia/requester-browser-xhr@5.18.0': dependencies: - '@algolia/client-common': 5.15.0 + '@algolia/client-common': 5.18.0 - '@algolia/requester-fetch@5.15.0': + '@algolia/requester-fetch@5.18.0': dependencies: - '@algolia/client-common': 5.15.0 + '@algolia/client-common': 5.18.0 - '@algolia/requester-node-http@5.15.0': + '@algolia/requester-node-http@5.18.0': dependencies: - '@algolia/client-common': 5.15.0 + '@algolia/client-common': 5.18.0 '@ampproject/remapping@2.3.0': dependencies: - '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/gen-mapping': 0.3.8 '@jridgewell/trace-mapping': 0.3.25 '@argos-ci/api-client@0.7.1': dependencies: - debug: 4.3.7(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) openapi-fetch: 0.13.1 transitivePeerDependencies: - supports-color @@ -10581,10 +10619,10 @@ snapshots: dependencies: '@argos-ci/api-client': 0.7.1 '@argos-ci/util': 2.2.1 - axios: 1.7.8(debug@4.3.7) + axios: 1.7.9(debug@4.4.0) convict: 6.2.4 - debug: 4.3.7(supports-color@8.1.1) - fast-glob: 3.3.2 + debug: 4.4.0(supports-color@8.1.1) + fast-glob: 3.3.3 sharp: 0.33.5 tmp: 0.2.3 transitivePeerDependencies: @@ -10612,7 +10650,7 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.26.2': {} + '@babel/compat-data@7.26.3': {} '@babel/core@7.26.0': dependencies: @@ -10627,7 +10665,7 @@ snapshots: '@babel/traverse': 7.26.4 '@babel/types': 7.26.3 convert-source-map: 2.0.0 - debug: 4.3.7(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -10638,26 +10676,19 @@ snapshots: dependencies: '@babel/parser': 7.26.3 '@babel/types': 7.26.3 - '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/gen-mapping': 0.3.8 '@jridgewell/trace-mapping': 0.3.25 - jsesc: 3.0.2 + jsesc: 3.1.0 '@babel/helper-annotate-as-pure@7.25.9': dependencies: '@babel/types': 7.26.3 - '@babel/helper-builder-binary-assignment-operator-visitor@7.25.9': - dependencies: - '@babel/traverse': 7.26.4 - '@babel/types': 7.26.3 - transitivePeerDependencies: - - supports-color - '@babel/helper-compilation-targets@7.25.9': dependencies: - '@babel/compat-data': 7.26.2 + '@babel/compat-data': 7.26.3 '@babel/helper-validator-option': 7.25.9 - browserslist: 4.24.2 + browserslist: 4.24.3 lru-cache: 5.1.1 semver: 6.3.1 @@ -10674,7 +10705,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helper-create-regexp-features-plugin@7.25.9(@babel/core@7.26.0)': + '@babel/helper-create-regexp-features-plugin@7.26.3(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 '@babel/helper-annotate-as-pure': 7.25.9 @@ -10686,7 +10717,7 @@ snapshots: '@babel/core': 7.26.0 '@babel/helper-compilation-targets': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - debug: 4.3.7(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) lodash.debounce: 4.0.8 resolve: 1.22.10 transitivePeerDependencies: @@ -10851,7 +10882,7 @@ snapshots: '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.0) '@babel/helper-plugin-utils': 7.25.9 '@babel/plugin-transform-arrow-functions@7.25.9(@babel/core@7.26.0)': @@ -10929,7 +10960,7 @@ snapshots: '@babel/plugin-transform-dotall-regex@7.25.9(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.0) '@babel/helper-plugin-utils': 7.25.9 '@babel/plugin-transform-duplicate-keys@7.25.9(@babel/core@7.26.0)': @@ -10940,7 +10971,7 @@ snapshots: '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.9(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.0) '@babel/helper-plugin-utils': 7.25.9 '@babel/plugin-transform-dynamic-import@7.25.9(@babel/core@7.26.0)': @@ -10948,13 +10979,10 @@ snapshots: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-exponentiation-operator@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-exponentiation-operator@7.26.3(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-builder-binary-assignment-operator-visitor': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color '@babel/plugin-transform-export-namespace-from@7.25.9(@babel/core@7.26.0)': dependencies: @@ -11041,7 +11069,7 @@ snapshots: '@babel/plugin-transform-named-capturing-groups-regex@7.25.9(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.0) '@babel/helper-plugin-utils': 7.25.9 '@babel/plugin-transform-new-target@7.25.9(@babel/core@7.26.0)': @@ -11167,7 +11195,7 @@ snapshots: '@babel/plugin-transform-regexp-modifiers@7.26.0(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.0) '@babel/helper-plugin-utils': 7.25.9 '@babel/plugin-transform-reserved-words@7.25.9(@babel/core@7.26.0)': @@ -11215,7 +11243,7 @@ snapshots: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-typescript@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-transform-typescript@7.26.3(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 '@babel/helper-annotate-as-pure': 7.25.9 @@ -11234,24 +11262,24 @@ snapshots: '@babel/plugin-transform-unicode-property-regex@7.25.9(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.0) '@babel/helper-plugin-utils': 7.25.9 '@babel/plugin-transform-unicode-regex@7.25.9(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.0) '@babel/helper-plugin-utils': 7.25.9 '@babel/plugin-transform-unicode-sets-regex@7.25.9(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 - '@babel/helper-create-regexp-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.0) '@babel/helper-plugin-utils': 7.25.9 '@babel/preset-env@7.26.0(@babel/core@7.26.0)': dependencies: - '@babel/compat-data': 7.26.2 + '@babel/compat-data': 7.26.3 '@babel/core': 7.26.0 '@babel/helper-compilation-targets': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 @@ -11279,7 +11307,7 @@ snapshots: '@babel/plugin-transform-duplicate-keys': 7.25.9(@babel/core@7.26.0) '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.0) '@babel/plugin-transform-dynamic-import': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-exponentiation-operator': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-exponentiation-operator': 7.26.3(@babel/core@7.26.0) '@babel/plugin-transform-export-namespace-from': 7.25.9(@babel/core@7.26.0) '@babel/plugin-transform-for-of': 7.25.9(@babel/core@7.26.0) '@babel/plugin-transform-function-name': 7.25.9(@babel/core@7.26.0) @@ -11357,7 +11385,7 @@ snapshots: '@babel/helper-validator-option': 7.25.9 '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0) '@babel/plugin-transform-modules-commonjs': 7.26.3(@babel/core@7.26.0) - '@babel/plugin-transform-typescript': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-typescript': 7.26.3(@babel/core@7.26.0) transitivePeerDependencies: - supports-color @@ -11392,7 +11420,7 @@ snapshots: '@babel/parser': 7.26.3 '@babel/template': 7.25.9 '@babel/types': 7.26.3 - debug: 4.3.7(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -11419,18 +11447,18 @@ snapshots: '@codspeed/core@4.0.0': dependencies: - axios: 1.7.8(debug@4.3.7) + axios: 1.7.9(debug@4.4.0) find-up: 6.3.0 form-data: 4.0.1 node-gyp-build: 4.8.4 transitivePeerDependencies: - debug - '@codspeed/vitest-plugin@4.0.0(vite@5.4.11(@types/node@20.17.11)(terser@5.36.0))(vitest@2.1.8)': + '@codspeed/vitest-plugin@4.0.0(vite@5.4.11(@types/node@20.17.11)(terser@5.37.0))(vitest@2.1.8)': dependencies: '@codspeed/core': 4.0.0 - vite: 5.4.11(@types/node@20.17.11)(terser@5.36.0) - vitest: 2.1.8(@types/node@20.17.11)(@vitest/browser@2.1.8)(@vitest/ui@2.1.8)(jsdom@25.0.1)(msw@2.6.6(@types/node@20.17.11)(typescript@5.7.2))(terser@5.36.0) + vite: 5.4.11(@types/node@20.17.11)(terser@5.37.0) + vitest: 2.1.8(@types/node@20.17.11)(@vitest/browser@2.1.8)(@vitest/ui@2.1.8)(jsdom@25.0.1)(msw@2.7.0(@types/node@20.17.11)(typescript@5.7.2))(terser@5.37.0) transitivePeerDependencies: - debug @@ -11442,12 +11470,12 @@ snapshots: '@docsearch/css@3.8.2': {} - '@docsearch/react@3.8.2(@algolia/client-search@5.15.0)(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(search-insights@2.17.3)': + '@docsearch/react@3.8.2(@algolia/client-search@5.18.0)(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(search-insights@2.17.3)': dependencies: - '@algolia/autocomplete-core': 1.17.7(@algolia/client-search@5.15.0)(algoliasearch@5.15.0)(search-insights@2.17.3) - '@algolia/autocomplete-preset-algolia': 1.17.7(@algolia/client-search@5.15.0)(algoliasearch@5.15.0) + '@algolia/autocomplete-core': 1.17.7(@algolia/client-search@5.18.0)(algoliasearch@5.18.0)(search-insights@2.17.3) + '@algolia/autocomplete-preset-algolia': 1.17.7(@algolia/client-search@5.18.0)(algoliasearch@5.18.0) '@docsearch/css': 3.8.2 - algoliasearch: 5.15.0 + algoliasearch: 5.18.0 optionalDependencies: '@types/react': 19.0.2 react: 19.0.0 @@ -11724,7 +11752,7 @@ snapshots: '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 - debug: 4.3.7(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) espree: 9.6.1 globals: 13.24.0 ignore: 5.3.2 @@ -11801,7 +11829,7 @@ snapshots: '@humanwhocodes/config-array@0.13.0': dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.3.7(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -11887,16 +11915,16 @@ snapshots: '@img/sharp-win32-x64@0.33.5': optional: true - '@inquirer/confirm@5.0.2(@types/node@20.17.11)': + '@inquirer/confirm@5.1.1(@types/node@20.17.11)': dependencies: - '@inquirer/core': 10.1.0(@types/node@20.17.11) - '@inquirer/type': 3.0.1(@types/node@20.17.11) + '@inquirer/core': 10.1.2(@types/node@20.17.11) + '@inquirer/type': 3.0.2(@types/node@20.17.11) '@types/node': 20.17.11 - '@inquirer/core@10.1.0(@types/node@20.17.11)': + '@inquirer/core@10.1.2(@types/node@20.17.11)': dependencies: - '@inquirer/figures': 1.0.8 - '@inquirer/type': 3.0.1(@types/node@20.17.11) + '@inquirer/figures': 1.0.9 + '@inquirer/type': 3.0.2(@types/node@20.17.11) ansi-escapes: 4.3.2 cli-width: 4.1.0 mute-stream: 2.0.0 @@ -11907,9 +11935,9 @@ snapshots: transitivePeerDependencies: - '@types/node' - '@inquirer/figures@1.0.8': {} + '@inquirer/figures@1.0.9': {} - '@inquirer/type@3.0.1(@types/node@20.17.11)': + '@inquirer/type@3.0.2(@types/node@20.17.11)': dependencies: '@types/node': 20.17.11 @@ -11938,7 +11966,7 @@ snapshots: dependencies: '@sinclair/typebox': 0.27.8 - '@jridgewell/gen-mapping@0.3.5': + '@jridgewell/gen-mapping@0.3.8': dependencies: '@jridgewell/set-array': 1.2.1 '@jridgewell/sourcemap-codec': 1.5.0 @@ -11950,7 +11978,7 @@ snapshots: '@jridgewell/source-map@0.3.6': dependencies: - '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/gen-mapping': 0.3.8 '@jridgewell/trace-mapping': 0.3.25 '@jridgewell/sourcemap-codec@1.5.0': {} @@ -11960,12 +11988,12 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 - '@lerna/create@8.1.9(@swc/core@1.9.3(@swc/helpers@0.5.15))(babel-plugin-macros@3.1.0)(encoding@0.1.13)(typescript@5.7.2)': + '@lerna/create@8.1.9(@swc/core@1.10.4(@swc/helpers@0.5.15))(babel-plugin-macros@3.1.0)(encoding@0.1.13)(typescript@5.7.2)': dependencies: '@npmcli/arborist': 7.5.4 '@npmcli/package-json': 5.2.0 '@npmcli/run-script': 8.1.0 - '@nx/devkit': 20.1.4(nx@20.1.4(@swc/core@1.9.3(@swc/helpers@0.5.15))) + '@nx/devkit': 20.3.0(nx@20.3.0(@swc/core@1.10.4(@swc/helpers@0.5.15))) '@octokit/plugin-enterprise-rest': 6.0.1 '@octokit/rest': 19.0.11(encoding@0.1.13) aproba: 2.0.0 @@ -12004,7 +12032,7 @@ snapshots: npm-package-arg: 11.0.2 npm-packlist: 8.0.2 npm-registry-fetch: 17.1.0 - nx: 20.1.4(@swc/core@1.9.3(@swc/helpers@0.5.15)) + nx: 20.3.0(@swc/core@1.10.4(@swc/helpers@0.5.15)) p-map: 4.0.0 p-map-series: 2.1.0 p-queue: 6.6.2 @@ -12043,7 +12071,7 @@ snapshots: - supports-color - typescript - '@mswjs/interceptors@0.37.3': + '@mswjs/interceptors@0.37.5': dependencies: '@open-draft/deferred-promise': 2.2.0 '@open-draft/logger': 0.3.0 @@ -12056,7 +12084,7 @@ snapshots: dependencies: '@babel/runtime': 7.26.0 '@floating-ui/react-dom': 2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@mui/types': 7.2.20(@types/react@19.0.2) + '@mui/types': 7.2.21(@types/react@19.0.2) '@mui/utils': 5.16.13(@types/react@19.0.2)(react@19.0.0) '@popperjs/core': 2.11.8 clsx: 2.1.1 @@ -12109,7 +12137,7 @@ snapshots: dependencies: '@babel/runtime': 7.26.0 lodash: 4.17.21 - marked: 15.0.4 + marked: 15.0.5 prismjs: 1.29.0 '@mui/internal-scripts@1.0.32': @@ -12123,7 +12151,7 @@ snapshots: doctrine: 3.0.0 lodash: 4.17.21 typescript: 5.7.2 - uuid: 11.0.3 + uuid: 11.0.4 transitivePeerDependencies: - supports-color @@ -12166,7 +12194,7 @@ snapshots: '@mui/base': 5.0.0-beta.40-0(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@mui/core-downloads-tracker': 5.16.13 '@mui/system': 5.16.13(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0) - '@mui/types': 7.2.20(@types/react@19.0.2) + '@mui/types': 7.2.21(@types/react@19.0.2) '@mui/utils': 5.16.13(@types/react@19.0.2)(react@19.0.0) clsx: 2.1.1 prop-types: 15.8.1 @@ -12183,7 +12211,7 @@ snapshots: '@mui/base': 5.0.0-beta.40-0(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@mui/material': 5.16.13(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@mui/system': 5.16.13(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0) - '@mui/types': 7.2.20(@types/react@19.0.2) + '@mui/types': 7.2.21(@types/react@19.0.2) '@mui/utils': 5.16.13(@types/react@19.0.2)(react@19.0.0) clsx: 2.1.1 prop-types: 15.8.1 @@ -12210,7 +12238,7 @@ snapshots: '@babel/runtime': 7.26.0 '@mui/core-downloads-tracker': 5.16.13 '@mui/system': 5.16.13(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0) - '@mui/types': 7.2.20(@types/react@19.0.2) + '@mui/types': 7.2.21(@types/react@19.0.2) '@mui/utils': 5.16.13(@types/react@19.0.2)(react@19.0.0) '@popperjs/core': 2.11.8 '@types/react-transition-group': 4.4.12(@types/react@19.0.2) @@ -12265,7 +12293,7 @@ snapshots: '@babel/runtime': 7.26.0 '@emotion/hash': 0.9.2 '@mui/private-theming': 5.16.13(@types/react@19.0.2)(react@19.0.0) - '@mui/types': 7.2.20(@types/react@19.0.2) + '@mui/types': 7.2.21(@types/react@19.0.2) '@mui/utils': 5.16.13(@types/react@19.0.2)(react@19.0.0) clsx: 2.1.1 csstype: 3.1.3 @@ -12288,7 +12316,7 @@ snapshots: '@babel/runtime': 7.26.0 '@mui/private-theming': 5.16.13(@types/react@19.0.2)(react@19.0.0) '@mui/styled-engine': 5.16.13(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0))(react@19.0.0) - '@mui/types': 7.2.20(@types/react@19.0.2) + '@mui/types': 7.2.21(@types/react@19.0.2) '@mui/utils': 5.16.13(@types/react@19.0.2)(react@19.0.0) clsx: 2.1.1 csstype: 3.1.3 @@ -12299,14 +12327,14 @@ snapshots: '@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0))(@types/react@19.0.2)(react@19.0.0) '@types/react': 19.0.2 - '@mui/types@7.2.20(@types/react@19.0.2)': + '@mui/types@7.2.21(@types/react@19.0.2)': optionalDependencies: '@types/react': 19.0.2 '@mui/utils@5.16.13(@types/react@19.0.2)(react@19.0.0)': dependencies: '@babel/runtime': 7.26.0 - '@mui/types': 7.2.20(@types/react@19.0.2) + '@mui/types': 7.2.21(@types/react@19.0.2) '@types/prop-types': 15.7.14 clsx: 2.1.1 prop-types: 15.8.1 @@ -12375,15 +12403,15 @@ snapshots: '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.17.1 + fastq: 1.18.0 '@npmcli/agent@2.2.2': dependencies: - agent-base: 7.1.1 + agent-base: 7.1.3 http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.5 + https-proxy-agent: 7.0.6 lru-cache: 10.4.3 - socks-proxy-agent: 8.0.4 + socks-proxy-agent: 8.0.5 transitivePeerDependencies: - supports-color @@ -12507,46 +12535,46 @@ snapshots: - bluebird - supports-color - '@nx/devkit@20.1.4(nx@20.1.4(@swc/core@1.9.3(@swc/helpers@0.5.15)))': + '@nx/devkit@20.3.0(nx@20.3.0(@swc/core@1.10.4(@swc/helpers@0.5.15)))': dependencies: ejs: 3.1.10 enquirer: 2.3.6 ignore: 5.3.2 minimatch: 9.0.3 - nx: 20.1.4(@swc/core@1.9.3(@swc/helpers@0.5.15)) + nx: 20.3.0(@swc/core@1.10.4(@swc/helpers@0.5.15)) semver: 7.6.3 tmp: 0.2.3 tslib: 2.8.1 yargs-parser: 21.1.1 - '@nx/nx-darwin-arm64@20.1.4': + '@nx/nx-darwin-arm64@20.3.0': optional: true - '@nx/nx-darwin-x64@20.1.4': + '@nx/nx-darwin-x64@20.3.0': optional: true - '@nx/nx-freebsd-x64@20.1.4': + '@nx/nx-freebsd-x64@20.3.0': optional: true - '@nx/nx-linux-arm-gnueabihf@20.1.4': + '@nx/nx-linux-arm-gnueabihf@20.3.0': optional: true - '@nx/nx-linux-arm64-gnu@20.1.4': + '@nx/nx-linux-arm64-gnu@20.3.0': optional: true - '@nx/nx-linux-arm64-musl@20.1.4': + '@nx/nx-linux-arm64-musl@20.3.0': optional: true - '@nx/nx-linux-x64-gnu@20.1.4': + '@nx/nx-linux-x64-gnu@20.3.0': optional: true - '@nx/nx-linux-x64-musl@20.1.4': + '@nx/nx-linux-x64-musl@20.3.0': optional: true - '@nx/nx-win32-arm64-msvc@20.1.4': + '@nx/nx-win32-arm64-msvc@20.3.0': optional: true - '@nx/nx-win32-x64-msvc@20.1.4': + '@nx/nx-win32-x64-msvc@20.3.0': optional: true '@octokit/auth-token@2.5.0': @@ -12593,17 +12621,17 @@ snapshots: before-after-hook: 2.2.3 universal-user-agent: 6.0.1 - '@octokit/core@6.1.2': + '@octokit/core@6.1.3': dependencies: '@octokit/auth-token': 5.1.1 - '@octokit/graphql': 8.1.1 - '@octokit/request': 9.1.3 - '@octokit/request-error': 6.1.5 + '@octokit/graphql': 8.1.2 + '@octokit/request': 9.1.4 + '@octokit/request-error': 6.1.6 '@octokit/types': 13.6.2 before-after-hook: 3.0.2 universal-user-agent: 7.0.2 - '@octokit/endpoint@10.1.1': + '@octokit/endpoint@10.1.2': dependencies: '@octokit/types': 13.6.2 universal-user-agent: 7.0.2 @@ -12647,9 +12675,9 @@ snapshots: '@octokit/types': 13.6.2 universal-user-agent: 6.0.1 - '@octokit/graphql@8.1.1': + '@octokit/graphql@8.1.2': dependencies: - '@octokit/request': 9.1.3 + '@octokit/request': 9.1.4 '@octokit/types': 13.6.2 universal-user-agent: 7.0.2 @@ -12663,9 +12691,9 @@ snapshots: '@octokit/plugin-enterprise-rest@6.0.1': {} - '@octokit/plugin-paginate-rest@11.3.6(@octokit/core@6.1.2)': + '@octokit/plugin-paginate-rest@11.3.6(@octokit/core@6.1.3)': dependencies: - '@octokit/core': 6.1.2 + '@octokit/core': 6.1.3 '@octokit/types': 13.6.2 '@octokit/plugin-paginate-rest@2.21.3(@octokit/core@3.6.0(encoding@0.1.13))': @@ -12692,18 +12720,18 @@ snapshots: dependencies: '@octokit/core': 4.2.4(encoding@0.1.13) - '@octokit/plugin-request-log@5.3.1(@octokit/core@6.1.2)': + '@octokit/plugin-request-log@5.3.1(@octokit/core@6.1.3)': dependencies: - '@octokit/core': 6.1.2 + '@octokit/core': 6.1.3 '@octokit/plugin-rest-endpoint-methods@10.4.1(@octokit/core@5.2.0)': dependencies: '@octokit/core': 5.2.0 '@octokit/types': 12.6.0 - '@octokit/plugin-rest-endpoint-methods@13.2.6(@octokit/core@6.1.2)': + '@octokit/plugin-rest-endpoint-methods@13.2.6(@octokit/core@6.1.3)': dependencies: - '@octokit/core': 6.1.2 + '@octokit/core': 6.1.3 '@octokit/types': 13.6.2 '@octokit/plugin-rest-endpoint-methods@5.16.2(@octokit/core@3.6.0(encoding@0.1.13))': @@ -12720,7 +12748,7 @@ snapshots: '@octokit/plugin-retry@7.1.2(@octokit/core@4.2.4(encoding@0.1.13))': dependencies: '@octokit/core': 4.2.4(encoding@0.1.13) - '@octokit/request-error': 6.1.5 + '@octokit/request-error': 6.1.6 '@octokit/types': 13.6.2 bottleneck: 2.19.5 @@ -12742,7 +12770,7 @@ snapshots: deprecation: 2.3.1 once: 1.4.0 - '@octokit/request-error@6.1.5': + '@octokit/request-error@6.1.6': dependencies: '@octokit/types': 13.6.2 @@ -12775,11 +12803,12 @@ snapshots: '@octokit/types': 13.6.2 universal-user-agent: 6.0.1 - '@octokit/request@9.1.3': + '@octokit/request@9.1.4': dependencies: - '@octokit/endpoint': 10.1.1 - '@octokit/request-error': 6.1.5 + '@octokit/endpoint': 10.1.2 + '@octokit/request-error': 6.1.6 '@octokit/types': 13.6.2 + fast-content-type-parse: 2.0.1 universal-user-agent: 7.0.2 '@octokit/rest@18.12.0(encoding@0.1.13)': @@ -12802,10 +12831,10 @@ snapshots: '@octokit/rest@21.0.2': dependencies: - '@octokit/core': 6.1.2 - '@octokit/plugin-paginate-rest': 11.3.6(@octokit/core@6.1.2) - '@octokit/plugin-request-log': 5.3.1(@octokit/core@6.1.2) - '@octokit/plugin-rest-endpoint-methods': 13.2.6(@octokit/core@6.1.2) + '@octokit/core': 6.1.3 + '@octokit/plugin-paginate-rest': 11.3.6(@octokit/core@6.1.3) + '@octokit/plugin-request-log': 5.3.1(@octokit/core@6.1.3) + '@octokit/plugin-rest-endpoint-methods': 13.2.6(@octokit/core@6.1.3) '@octokit/tsconfig@1.0.2': {} @@ -12885,58 +12914,61 @@ snapshots: '@remix-run/router@1.21.0': {} - '@rollup/rollup-android-arm-eabi@4.28.0': + '@rollup/rollup-android-arm-eabi@4.30.0': optional: true - '@rollup/rollup-android-arm64@4.28.0': + '@rollup/rollup-android-arm64@4.30.0': optional: true - '@rollup/rollup-darwin-arm64@4.28.0': + '@rollup/rollup-darwin-arm64@4.30.0': optional: true - '@rollup/rollup-darwin-x64@4.28.0': + '@rollup/rollup-darwin-x64@4.30.0': optional: true - '@rollup/rollup-freebsd-arm64@4.28.0': + '@rollup/rollup-freebsd-arm64@4.30.0': optional: true - '@rollup/rollup-freebsd-x64@4.28.0': + '@rollup/rollup-freebsd-x64@4.30.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.28.0': + '@rollup/rollup-linux-arm-gnueabihf@4.30.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.28.0': + '@rollup/rollup-linux-arm-musleabihf@4.30.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.28.0': + '@rollup/rollup-linux-arm64-gnu@4.30.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.28.0': + '@rollup/rollup-linux-arm64-musl@4.30.0': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.28.0': + '@rollup/rollup-linux-loongarch64-gnu@4.30.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.28.0': + '@rollup/rollup-linux-powerpc64le-gnu@4.30.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.28.0': + '@rollup/rollup-linux-riscv64-gnu@4.30.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.28.0': + '@rollup/rollup-linux-s390x-gnu@4.30.0': optional: true - '@rollup/rollup-linux-x64-musl@4.28.0': + '@rollup/rollup-linux-x64-gnu@4.30.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.28.0': + '@rollup/rollup-linux-x64-musl@4.30.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.28.0': + '@rollup/rollup-win32-arm64-msvc@4.30.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.28.0': + '@rollup/rollup-win32-ia32-msvc@4.30.0': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.30.0': optional: true '@rtsao/scc@1.1.0': {} @@ -13004,7 +13036,7 @@ snapshots: '@slack/socket-mode': 2.0.3 '@slack/types': 2.14.0 '@slack/web-api': 7.8.0 - axios: 1.7.8(debug@4.3.7) + axios: 1.7.9(debug@4.4.0) express: 5.0.1 path-to-regexp: 8.2.0 raw-body: 3.0.0 @@ -13051,7 +13083,7 @@ snapshots: '@slack/types': 2.14.0 '@types/node': 20.17.11 '@types/retry': 0.12.0 - axios: 1.7.8(debug@4.3.7) + axios: 1.7.9(debug@4.4.0) eventemitter3: 5.0.1 form-data: 4.0.1 is-electron: 2.2.2 @@ -13064,51 +13096,51 @@ snapshots: '@socket.io/component-emitter@3.1.2': {} - '@swc/core-darwin-arm64@1.9.3': + '@swc/core-darwin-arm64@1.10.4': optional: true - '@swc/core-darwin-x64@1.9.3': + '@swc/core-darwin-x64@1.10.4': optional: true - '@swc/core-linux-arm-gnueabihf@1.9.3': + '@swc/core-linux-arm-gnueabihf@1.10.4': optional: true - '@swc/core-linux-arm64-gnu@1.9.3': + '@swc/core-linux-arm64-gnu@1.10.4': optional: true - '@swc/core-linux-arm64-musl@1.9.3': + '@swc/core-linux-arm64-musl@1.10.4': optional: true - '@swc/core-linux-x64-gnu@1.9.3': + '@swc/core-linux-x64-gnu@1.10.4': optional: true - '@swc/core-linux-x64-musl@1.9.3': + '@swc/core-linux-x64-musl@1.10.4': optional: true - '@swc/core-win32-arm64-msvc@1.9.3': + '@swc/core-win32-arm64-msvc@1.10.4': optional: true - '@swc/core-win32-ia32-msvc@1.9.3': + '@swc/core-win32-ia32-msvc@1.10.4': optional: true - '@swc/core-win32-x64-msvc@1.9.3': + '@swc/core-win32-x64-msvc@1.10.4': optional: true - '@swc/core@1.9.3(@swc/helpers@0.5.15)': + '@swc/core@1.10.4(@swc/helpers@0.5.15)': dependencies: '@swc/counter': 0.1.3 '@swc/types': 0.1.17 optionalDependencies: - '@swc/core-darwin-arm64': 1.9.3 - '@swc/core-darwin-x64': 1.9.3 - '@swc/core-linux-arm-gnueabihf': 1.9.3 - '@swc/core-linux-arm64-gnu': 1.9.3 - '@swc/core-linux-arm64-musl': 1.9.3 - '@swc/core-linux-x64-gnu': 1.9.3 - '@swc/core-linux-x64-musl': 1.9.3 - '@swc/core-win32-arm64-msvc': 1.9.3 - '@swc/core-win32-ia32-msvc': 1.9.3 - '@swc/core-win32-x64-msvc': 1.9.3 + '@swc/core-darwin-arm64': 1.10.4 + '@swc/core-darwin-x64': 1.10.4 + '@swc/core-linux-arm-gnueabihf': 1.10.4 + '@swc/core-linux-arm64-gnu': 1.10.4 + '@swc/core-linux-arm64-musl': 1.10.4 + '@swc/core-linux-x64-gnu': 1.10.4 + '@swc/core-linux-x64-musl': 1.10.4 + '@swc/core-win32-arm64-msvc': 1.10.4 + '@swc/core-win32-ia32-msvc': 1.10.4 + '@swc/core-win32-x64-msvc': 1.10.4 '@swc/helpers': 0.5.15 '@swc/counter@0.1.3': {} @@ -13230,7 +13262,7 @@ snapshots: dependencies: '@types/d3-time': 3.0.4 - '@types/d3-shape@3.1.6': + '@types/d3-shape@3.1.7': dependencies: '@types/d3-path': 3.1.0 @@ -13384,11 +13416,11 @@ snapshots: '@types/use-sync-external-store@0.0.6': {} - '@types/webpack-bundle-analyzer@4.7.0(@swc/core@1.9.3(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1))': + '@types/webpack-bundle-analyzer@4.7.0(@swc/core@1.10.4(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1))': dependencies: '@types/node': 20.17.11 tapable: 2.2.1 - webpack: 5.97.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) + webpack: 5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) transitivePeerDependencies: - '@swc/core' - esbuild @@ -13429,7 +13461,7 @@ snapshots: '@typescript-eslint/types': 7.18.0 '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.7.2) '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.3.7(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) eslint: 8.57.1 optionalDependencies: typescript: 5.7.2 @@ -13441,16 +13473,16 @@ snapshots: '@typescript-eslint/types': 7.18.0 '@typescript-eslint/visitor-keys': 7.18.0 - '@typescript-eslint/scope-manager@8.17.0': + '@typescript-eslint/scope-manager@8.19.0': dependencies: - '@typescript-eslint/types': 8.17.0 - '@typescript-eslint/visitor-keys': 8.17.0 + '@typescript-eslint/types': 8.19.0 + '@typescript-eslint/visitor-keys': 8.19.0 '@typescript-eslint/type-utils@7.18.0(eslint@8.57.1)(typescript@5.7.2)': dependencies: '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.7.2) '@typescript-eslint/utils': 7.18.0(eslint@8.57.1)(typescript@5.7.2) - debug: 4.3.7(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) eslint: 8.57.1 ts-api-utils: 1.4.3(typescript@5.7.2) optionalDependencies: @@ -13460,13 +13492,13 @@ snapshots: '@typescript-eslint/types@7.18.0': {} - '@typescript-eslint/types@8.17.0': {} + '@typescript-eslint/types@8.19.0': {} '@typescript-eslint/typescript-estree@7.18.0(typescript@5.7.2)': dependencies: '@typescript-eslint/types': 7.18.0 '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.3.7(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.5 @@ -13477,17 +13509,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.17.0(typescript@5.7.2)': + '@typescript-eslint/typescript-estree@8.19.0(typescript@5.7.2)': dependencies: - '@typescript-eslint/types': 8.17.0 - '@typescript-eslint/visitor-keys': 8.17.0 - debug: 4.3.7(supports-color@8.1.1) - fast-glob: 3.3.2 + '@typescript-eslint/types': 8.19.0 + '@typescript-eslint/visitor-keys': 8.19.0 + debug: 4.4.0(supports-color@8.1.1) + fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.6.3 ts-api-utils: 1.4.3(typescript@5.7.2) - optionalDependencies: typescript: 5.7.2 transitivePeerDependencies: - supports-color @@ -13503,14 +13534,13 @@ snapshots: - supports-color - typescript - '@typescript-eslint/utils@8.17.0(eslint@8.57.1)(typescript@5.7.2)': + '@typescript-eslint/utils@8.19.0(eslint@8.57.1)(typescript@5.7.2)': dependencies: '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) - '@typescript-eslint/scope-manager': 8.17.0 - '@typescript-eslint/types': 8.17.0 - '@typescript-eslint/typescript-estree': 8.17.0(typescript@5.7.2) + '@typescript-eslint/scope-manager': 8.19.0 + '@typescript-eslint/types': 8.19.0 + '@typescript-eslint/typescript-estree': 8.19.0(typescript@5.7.2) eslint: 8.57.1 - optionalDependencies: typescript: 5.7.2 transitivePeerDependencies: - supports-color @@ -13520,42 +13550,42 @@ snapshots: '@typescript-eslint/types': 7.18.0 eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@8.17.0': + '@typescript-eslint/visitor-keys@8.19.0': dependencies: - '@typescript-eslint/types': 8.17.0 + '@typescript-eslint/types': 8.19.0 eslint-visitor-keys: 4.2.0 - '@ungap/structured-clone@1.2.0': {} + '@ungap/structured-clone@1.2.1': {} - '@vitejs/plugin-react-swc@3.7.2(@swc/helpers@0.5.15)(vite@5.4.11(@types/node@20.17.11)(terser@5.36.0))': + '@vitejs/plugin-react-swc@3.7.2(@swc/helpers@0.5.15)(vite@5.4.11(@types/node@20.17.11)(terser@5.37.0))': dependencies: - '@swc/core': 1.9.3(@swc/helpers@0.5.15) - vite: 5.4.11(@types/node@20.17.11)(terser@5.36.0) + '@swc/core': 1.10.4(@swc/helpers@0.5.15) + vite: 5.4.11(@types/node@20.17.11)(terser@5.37.0) transitivePeerDependencies: - '@swc/helpers' - '@vitejs/plugin-react@4.3.4(vite@5.4.11(@types/node@20.17.11)(terser@5.36.0))': + '@vitejs/plugin-react@4.3.4(vite@5.4.11(@types/node@20.17.11)(terser@5.37.0))': dependencies: '@babel/core': 7.26.0 '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0) '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 - vite: 5.4.11(@types/node@20.17.11)(terser@5.36.0) + vite: 5.4.11(@types/node@20.17.11)(terser@5.37.0) transitivePeerDependencies: - supports-color - '@vitest/browser@2.1.8(@types/node@20.17.11)(playwright@1.49.1)(typescript@5.7.2)(vite@5.4.11(@types/node@20.17.11)(terser@5.36.0))(vitest@2.1.8)': + '@vitest/browser@2.1.8(@types/node@20.17.11)(playwright@1.49.1)(typescript@5.7.2)(vite@5.4.11(@types/node@20.17.11)(terser@5.37.0))(vitest@2.1.8)': dependencies: '@testing-library/dom': 10.4.0 '@testing-library/user-event': 14.5.2(@testing-library/dom@10.4.0) - '@vitest/mocker': 2.1.8(msw@2.6.6(@types/node@20.17.11)(typescript@5.7.2))(vite@5.4.11(@types/node@20.17.11)(terser@5.36.0)) + '@vitest/mocker': 2.1.8(msw@2.7.0(@types/node@20.17.11)(typescript@5.7.2))(vite@5.4.11(@types/node@20.17.11)(terser@5.37.0)) '@vitest/utils': 2.1.8 - magic-string: 0.30.14 - msw: 2.6.6(@types/node@20.17.11)(typescript@5.7.2) + magic-string: 0.30.17 + msw: 2.7.0(@types/node@20.17.11)(typescript@5.7.2) sirv: 3.0.0 tinyrainbow: 1.2.0 - vitest: 2.1.8(@types/node@20.17.11)(@vitest/browser@2.1.8)(@vitest/ui@2.1.8)(jsdom@25.0.1)(msw@2.6.6(@types/node@20.17.11)(typescript@5.7.2))(terser@5.36.0) + vitest: 2.1.8(@types/node@20.17.11)(@vitest/browser@2.1.8)(@vitest/ui@2.1.8)(jsdom@25.0.1)(msw@2.7.0(@types/node@20.17.11)(typescript@5.7.2))(terser@5.37.0) ws: 8.18.0 optionalDependencies: playwright: 1.49.1 @@ -13573,14 +13603,14 @@ snapshots: chai: 5.1.2 tinyrainbow: 1.2.0 - '@vitest/mocker@2.1.8(msw@2.6.6(@types/node@20.17.11)(typescript@5.7.2))(vite@5.4.11(@types/node@20.17.11)(terser@5.36.0))': + '@vitest/mocker@2.1.8(msw@2.7.0(@types/node@20.17.11)(typescript@5.7.2))(vite@5.4.11(@types/node@20.17.11)(terser@5.37.0))': dependencies: '@vitest/spy': 2.1.8 estree-walker: 3.0.3 - magic-string: 0.30.14 + magic-string: 0.30.17 optionalDependencies: - msw: 2.6.6(@types/node@20.17.11)(typescript@5.7.2) - vite: 5.4.11(@types/node@20.17.11)(terser@5.36.0) + msw: 2.7.0(@types/node@20.17.11)(typescript@5.7.2) + vite: 5.4.11(@types/node@20.17.11)(terser@5.37.0) '@vitest/pretty-format@2.1.8': dependencies: @@ -13594,7 +13624,7 @@ snapshots: '@vitest/snapshot@2.1.8': dependencies: '@vitest/pretty-format': 2.1.8 - magic-string: 0.30.14 + magic-string: 0.30.17 pathe: 1.1.2 '@vitest/spy@2.1.8': @@ -13610,7 +13640,7 @@ snapshots: sirv: 3.0.0 tinyglobby: 0.2.10 tinyrainbow: 1.2.0 - vitest: 2.1.8(@types/node@20.17.11)(@vitest/browser@2.1.8)(@vitest/ui@2.1.8)(jsdom@25.0.1)(msw@2.6.6(@types/node@20.17.11)(typescript@5.7.2))(terser@5.36.0) + vitest: 2.1.8(@types/node@20.17.11)(@vitest/browser@2.1.8)(@vitest/ui@2.1.8)(jsdom@25.0.1)(msw@2.7.0(@types/node@20.17.11)(typescript@5.7.2))(terser@5.37.0) '@vitest/utils@2.1.8': dependencies: @@ -13696,17 +13726,17 @@ snapshots: '@webpack-cli/configtest@3.0.1(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1))(webpack@5.97.1)': dependencies: - webpack: 5.97.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) + webpack: 5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) webpack-cli: 6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1) '@webpack-cli/info@3.0.1(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1))(webpack@5.97.1)': dependencies: - webpack: 5.97.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) + webpack: 5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) webpack-cli: 6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1) '@webpack-cli/serve@3.0.1(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1))(webpack@5.97.1)': dependencies: - webpack: 5.97.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) + webpack: 5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) webpack-cli: 6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1) '@xtuc/ieee754@1.2.0': {} @@ -13759,15 +13789,11 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.3.7(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) transitivePeerDependencies: - supports-color - agent-base@7.1.1: - dependencies: - debug: 4.3.7(supports-color@8.1.1) - transitivePeerDependencies: - - supports-color + agent-base@7.1.3: {} aggregate-error@3.1.0: dependencies: @@ -13809,25 +13835,25 @@ snapshots: ajv@8.17.1: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.0.3 + fast-uri: 3.0.4 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - algoliasearch@5.15.0: - dependencies: - '@algolia/client-abtesting': 5.15.0 - '@algolia/client-analytics': 5.15.0 - '@algolia/client-common': 5.15.0 - '@algolia/client-insights': 5.15.0 - '@algolia/client-personalization': 5.15.0 - '@algolia/client-query-suggestions': 5.15.0 - '@algolia/client-search': 5.15.0 - '@algolia/ingestion': 1.15.0 - '@algolia/monitoring': 1.15.0 - '@algolia/recommend': 5.15.0 - '@algolia/requester-browser-xhr': 5.15.0 - '@algolia/requester-fetch': 5.15.0 - '@algolia/requester-node-http': 5.15.0 + algoliasearch@5.18.0: + dependencies: + '@algolia/client-abtesting': 5.18.0 + '@algolia/client-analytics': 5.18.0 + '@algolia/client-common': 5.18.0 + '@algolia/client-insights': 5.18.0 + '@algolia/client-personalization': 5.18.0 + '@algolia/client-query-suggestions': 5.18.0 + '@algolia/client-search': 5.18.0 + '@algolia/ingestion': 1.18.0 + '@algolia/monitoring': 1.18.0 + '@algolia/recommend': 5.18.0 + '@algolia/requester-browser-xhr': 5.18.0 + '@algolia/requester-fetch': 5.18.0 + '@algolia/requester-node-http': 5.18.0 amdefine@1.0.1: optional: true @@ -13942,9 +13968,9 @@ snapshots: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 es-object-atoms: 1.0.0 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 is-string: 1.1.1 array-parallel@0.1.3: {} @@ -13957,7 +13983,7 @@ snapshots: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 es-errors: 1.3.0 es-object-atoms: 1.0.0 es-shim-unscopables: 1.0.2 @@ -13966,30 +13992,30 @@ snapshots: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 es-errors: 1.3.0 es-object-atoms: 1.0.0 es-shim-unscopables: 1.0.2 - array.prototype.flat@1.3.2: + array.prototype.flat@1.3.3: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 es-shim-unscopables: 1.0.2 array.prototype.flatmap@1.3.3: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 es-shim-unscopables: 1.0.2 array.prototype.reduce@1.0.7: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 es-array-method-boxes-properly: 1.0.0 es-errors: 1.3.0 es-object-atoms: 1.0.0 @@ -13999,7 +14025,7 @@ snapshots: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 es-errors: 1.3.0 es-shim-unscopables: 1.0.2 @@ -14008,9 +14034,9 @@ snapshots: array-buffer-byte-length: 1.0.2 call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 es-errors: 1.3.0 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 is-array-buffer: 3.0.5 arrify@1.0.1: {} @@ -14045,8 +14071,8 @@ snapshots: autoprefixer@10.4.20(postcss@8.4.49): dependencies: - browserslist: 4.24.2 - caniuse-lite: 1.0.30001686 + browserslist: 4.24.3 + caniuse-lite: 1.0.30001690 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.1.1 @@ -14059,9 +14085,9 @@ snapshots: axe-core@4.10.2: {} - axios@1.7.8(debug@4.3.7): + axios@1.7.9(debug@4.4.0): dependencies: - follow-redirects: 1.15.9(debug@4.3.7) + follow-redirects: 1.15.9(debug@4.4.0) form-data: 4.0.1 proxy-from-env: 1.1.0 transitivePeerDependencies: @@ -14074,7 +14100,7 @@ snapshots: '@babel/core': 7.26.0 find-cache-dir: 4.0.0 schema-utils: 4.3.0 - webpack: 5.97.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) + webpack: 5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) babel-plugin-istanbul@7.0.0: dependencies: @@ -14111,7 +14137,7 @@ snapshots: babel-plugin-polyfill-corejs2@0.4.12(@babel/core@7.26.0): dependencies: - '@babel/compat-data': 7.26.2 + '@babel/compat-data': 7.26.3 '@babel/core': 7.26.0 '@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.26.0) semver: 6.3.1 @@ -14256,12 +14282,12 @@ snapshots: browser-stdout@1.3.1: {} - browserslist@4.24.2: + browserslist@4.24.3: dependencies: - caniuse-lite: 1.0.30001686 - electron-to-chromium: 1.5.68 - node-releases: 2.0.18 - update-browserslist-db: 1.1.1(browserslist@4.24.2) + caniuse-lite: 1.0.30001690 + electron-to-chromium: 1.5.76 + node-releases: 2.0.19 + update-browserslist-db: 1.1.1(browserslist@4.24.3) buffer-crc32@0.2.13: {} @@ -14338,13 +14364,13 @@ snapshots: dependencies: call-bind-apply-helpers: 1.0.1 es-define-property: 1.0.1 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 set-function-length: 1.2.2 call-bound@1.0.3: dependencies: call-bind-apply-helpers: 1.0.1 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 callsites@3.1.0: {} @@ -14367,7 +14393,7 @@ snapshots: camelize@1.0.1: {} - caniuse-lite@1.0.30001686: {} + caniuse-lite@1.0.30001690: {} chai-dom@1.12.0(chai@4.5.0): dependencies: @@ -14599,7 +14625,7 @@ snapshots: dependencies: schema-utils: 4.3.0 serialize-javascript: 6.0.2 - webpack: 5.97.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) + webpack: 5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) compression@1.7.4: dependencies: @@ -14722,7 +14748,7 @@ snapshots: core-js-compat@3.39.0: dependencies: - browserslist: 4.24.2 + browserslist: 4.24.3 core-js@2.6.12: {} @@ -14886,7 +14912,7 @@ snapshots: chalk: 2.4.2 commander: 2.20.3 core-js: 3.39.0 - debug: 4.3.7(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) fast-json-patch: 3.1.1 get-stdin: 6.0.0 http-proxy-agent: 5.0.0 @@ -14926,7 +14952,7 @@ snapshots: data-urls@5.0.0: dependencies: whatwg-mimetype: 4.0.0 - whatwg-url: 14.0.0 + whatwg-url: 14.1.0 data-view-buffer@1.0.2: dependencies: @@ -14982,7 +15008,11 @@ snapshots: dependencies: ms: 2.1.2 - debug@4.3.7(supports-color@8.1.1): + debug@4.3.7: + dependencies: + ms: 2.1.3 + + debug@4.4.0(supports-color@8.1.1): dependencies: ms: 2.1.3 optionalDependencies: @@ -15099,7 +15129,7 @@ snapshots: dom-serialize@2.2.1: dependencies: custom-event: 1.0.1 - ent: 2.2.1 + ent: 2.2.2 extend: 3.0.2 void-elements: 2.0.1 @@ -15132,9 +15162,9 @@ snapshots: dotenv-expand@11.0.7: dependencies: - dotenv: 16.4.6 + dotenv: 16.4.7 - dotenv@16.4.6: {} + dotenv@16.4.7: {} dunder-proto@1.0.1: dependencies: @@ -15160,7 +15190,7 @@ snapshots: dependencies: jake: 10.9.2 - electron-to-chromium@1.5.68: {} + electron-to-chromium@1.5.76: {} emoji-regex@8.0.0: {} @@ -15192,7 +15222,7 @@ snapshots: base64id: 2.0.0 cookie: 0.7.2 cors: 2.8.5 - debug: 4.3.7(supports-color@8.1.1) + debug: 4.3.7 engine.io-parser: 5.2.3 ws: 8.17.1 transitivePeerDependencies: @@ -15206,7 +15236,7 @@ snapshots: memory-fs: 0.2.0 tapable: 0.1.10 - enhanced-resolve@5.17.1: + enhanced-resolve@5.18.0: dependencies: graceful-fs: 4.2.11 tapable: 2.2.1 @@ -15215,9 +15245,12 @@ snapshots: dependencies: ansi-colors: 4.1.3 - ent@2.2.1: + ent@2.2.2: dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 punycode: 1.4.1 + safe-regex-test: 1.1.0 entities@2.2.0: {} @@ -15235,7 +15268,7 @@ snapshots: dependencies: is-arrayish: 0.2.1 - es-abstract@1.23.7: + es-abstract@1.23.9: dependencies: array-buffer-byte-length: 1.0.2 arraybuffer.prototype.slice: 1.0.4 @@ -15248,10 +15281,11 @@ snapshots: es-define-property: 1.0.1 es-errors: 1.3.0 es-object-atoms: 1.0.0 - es-set-tostringtag: 2.0.3 + es-set-tostringtag: 2.1.0 es-to-primitive: 1.3.0 function.prototype.name: 1.1.8 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 + get-proto: 1.0.1 get-symbol-description: 1.1.0 globalthis: 1.0.4 gopd: 1.2.0 @@ -15272,9 +15306,12 @@ snapshots: object-inspect: 1.13.3 object-keys: 1.1.1 object.assign: 4.1.7 - regexp.prototype.flags: 1.5.3 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 safe-regex-test: 1.1.0 + set-proto: 1.0.0 string.prototype.trim: 1.2.10 string.prototype.trimend: 1.0.9 string.prototype.trimstart: 1.0.8 @@ -15296,29 +15333,30 @@ snapshots: call-bind: 1.0.8 call-bound: 1.0.3 define-properties: 1.2.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 es-errors: 1.3.0 - es-set-tostringtag: 2.0.3 + es-set-tostringtag: 2.1.0 function-bind: 1.1.2 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 globalthis: 1.0.4 gopd: 1.2.0 has-property-descriptors: 1.0.2 has-proto: 1.2.0 has-symbols: 1.1.0 internal-slot: 1.1.0 - iterator.prototype: 1.1.4 + iterator.prototype: 1.1.5 safe-array-concat: 1.1.3 - es-module-lexer@1.5.4: {} + es-module-lexer@1.6.0: {} es-object-atoms@1.0.0: dependencies: es-errors: 1.3.0 - es-set-tostringtag@2.0.3: + es-set-tostringtag@2.1.0: dependencies: - get-intrinsic: 1.2.6 + es-errors: 1.3.0 + get-intrinsic: 1.2.7 has-tostringtag: 1.0.2 hasown: 2.0.2 @@ -15442,7 +15480,7 @@ snapshots: eslint-import-resolver-node@0.3.9: dependencies: debug: 3.2.7 - is-core-module: 2.16.0 + is-core-module: 2.16.1 resolve: 1.22.10 transitivePeerDependencies: - supports-color @@ -15455,12 +15493,12 @@ snapshots: find-root: 1.1.0 hasown: 2.0.2 interpret: 1.4.0 - is-core-module: 2.16.0 + is-core-module: 2.16.1 is-regex: 1.2.1 lodash: 4.17.21 resolve: 2.0.0-next.5 semver: 5.7.2 - webpack: 5.97.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) + webpack: 5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) transitivePeerDependencies: - supports-color @@ -15488,7 +15526,7 @@ snapshots: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 - array.prototype.flat: 1.3.2 + array.prototype.flat: 1.3.3 array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 @@ -15496,7 +15534,7 @@ snapshots: eslint-import-resolver-node: 0.3.9 eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-webpack@0.13.10)(eslint@8.57.1) hasown: 2.0.2 - is-core-module: 2.16.0 + is-core-module: 2.16.1 is-glob: 4.0.3 minimatch: 3.1.2 object.fromentries: 2.0.8 @@ -15517,7 +15555,7 @@ snapshots: '@es-joy/jsdoccomment': 0.49.0 are-docs-informative: 0.0.2 comment-parser: 1.4.1 - debug: 4.3.7(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) escape-string-regexp: 4.0.0 eslint: 8.57.1 espree: 10.3.0 @@ -15572,8 +15610,8 @@ snapshots: '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.26.0) eslint: 8.57.1 hermes-parser: 0.25.1 - zod: 3.23.8 - zod-validation-error: 3.4.0(zod@3.23.8) + zod: 3.24.1 + zod-validation-error: 3.4.0(zod@3.24.1) transitivePeerDependencies: - supports-color @@ -15605,8 +15643,8 @@ snapshots: eslint-plugin-testing-library@7.1.1(eslint@8.57.1)(typescript@5.7.2): dependencies: - '@typescript-eslint/scope-manager': 8.17.0 - '@typescript-eslint/utils': 8.17.0(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/scope-manager': 8.19.0 + '@typescript-eslint/utils': 8.19.0(eslint@8.57.1)(typescript@5.7.2) eslint: 8.57.1 transitivePeerDependencies: - supports-color @@ -15642,11 +15680,11 @@ snapshots: '@humanwhocodes/config-array': 0.13.0 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 - '@ungap/structured-clone': 1.2.0 + '@ungap/structured-clone': 1.2.1 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.3.7(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -15836,6 +15874,8 @@ snapshots: iconv-lite: 0.4.24 tmp: 0.0.33 + fast-content-type-parse@2.0.1: {} + fast-csv@4.3.6: dependencies: '@fast-csv/format': 4.3.5 @@ -15853,7 +15893,7 @@ snapshots: merge2: 1.4.1 micromatch: 4.0.8 - fast-glob@3.3.2: + fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 @@ -15867,11 +15907,11 @@ snapshots: fast-levenshtein@2.0.6: {} - fast-uri@3.0.3: {} + fast-uri@3.0.4: {} fastest-levenshtein@1.0.16: {} - fastq@1.17.1: + fastq@1.18.0: dependencies: reusify: 1.0.4 @@ -15983,11 +16023,11 @@ snapshots: flatted@3.3.2: {} - flow-parser@0.255.0: {} + flow-parser@0.258.0: {} - follow-redirects@1.15.9(debug@4.3.7): + follow-redirects@1.15.9(debug@4.4.0): optionalDependencies: - debug: 4.3.7(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) for-each@0.3.3: dependencies: @@ -16082,7 +16122,7 @@ snapshots: gaxios@6.7.1(encoding@0.1.13): dependencies: extend: 3.0.2 - https-proxy-agent: 7.0.5 + https-proxy-agent: 7.0.6 is-stream: 2.0.1 node-fetch: 2.7.0(encoding@0.1.13) uuid: 9.0.1 @@ -16104,14 +16144,14 @@ snapshots: get-func-name@2.0.2: {} - get-intrinsic@1.2.6: + get-intrinsic@1.2.7: dependencies: call-bind-apply-helpers: 1.0.1 - dunder-proto: 1.0.1 es-define-property: 1.0.1 es-errors: 1.3.0 es-object-atoms: 1.0.0 function-bind: 1.1.2 + get-proto: 1.0.1 gopd: 1.2.0 has-symbols: 1.1.0 hasown: 2.0.2 @@ -16128,6 +16168,11 @@ snapshots: get-port@5.1.1: {} + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.0.0 + get-stdin@6.0.0: {} get-stream@6.0.0: {} @@ -16143,7 +16188,7 @@ snapshots: dependencies: call-bound: 1.0.3 es-errors: 1.3.0 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 get-tsconfig@4.8.1: dependencies: @@ -16259,7 +16304,7 @@ snapshots: dependencies: array-union: 2.1.0 dir-glob: 3.0.1 - fast-glob: 3.3.2 + fast-glob: 3.3.3 ignore: 5.3.2 merge2: 1.4.1 slash: 3.0.0 @@ -16267,7 +16312,7 @@ snapshots: globby@13.2.2: dependencies: dir-glob: 3.0.1 - fast-glob: 3.3.2 + fast-glob: 3.3.3 ignore: 5.3.2 merge2: 1.4.1 slash: 4.0.0 @@ -16275,7 +16320,7 @@ snapshots: globby@14.0.2: dependencies: '@sindresorhus/merge-streams': 2.3.0 - fast-glob: 3.3.2 + fast-glob: 3.3.3 ignore: 5.3.2 path-type: 5.0.0 slash: 5.1.0 @@ -16320,7 +16365,7 @@ snapshots: graphemer@1.4.0: {} - graphql@16.9.0: {} + graphql@16.10.0: {} gtoken@7.1.0(encoding@0.1.13): dependencies: @@ -16345,7 +16390,7 @@ snapshots: hard-rejection@2.1.0: {} - has-bigints@1.0.2: {} + has-bigints@1.1.0: {} has-flag@1.0.0: {} @@ -16422,7 +16467,7 @@ snapshots: he: 1.2.0 param-case: 3.0.4 relateurl: 0.2.7 - terser: 5.36.0 + terser: 5.37.0 html-tokenize@2.0.1: dependencies: @@ -16440,7 +16485,7 @@ snapshots: pretty-error: 4.0.0 tapable: 2.2.1 optionalDependencies: - webpack: 5.97.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) + webpack: 5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) htmlparser2@6.1.0: dependencies: @@ -16463,21 +16508,21 @@ snapshots: dependencies: '@tootallnate/once': 2.0.0 agent-base: 6.0.2 - debug: 4.3.7(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) transitivePeerDependencies: - supports-color http-proxy-agent@7.0.2: dependencies: - agent-base: 7.1.1 - debug: 4.3.7(supports-color@8.1.1) + agent-base: 7.1.3 + debug: 4.4.0(supports-color@8.1.1) transitivePeerDependencies: - supports-color http-proxy@1.18.1: dependencies: eventemitter3: 4.0.7 - follow-redirects: 1.15.9(debug@4.3.7) + follow-redirects: 1.15.9(debug@4.4.0) requires-port: 1.0.0 transitivePeerDependencies: - debug @@ -16485,14 +16530,14 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.3.7(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) transitivePeerDependencies: - supports-color - https-proxy-agent@7.0.5: + https-proxy-agent@7.0.6: dependencies: - agent-base: 7.1.1 - debug: 4.3.7(supports-color@8.1.1) + agent-base: 7.1.3 + debug: 4.4.0(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -16614,28 +16659,31 @@ snapshots: is-alphabetical: 2.0.1 is-decimal: 2.0.1 - is-arguments@1.1.1: + is-arguments@1.2.0: dependencies: - call-bind: 1.0.8 + call-bound: 1.0.3 has-tostringtag: 1.0.2 is-array-buffer@3.0.5: dependencies: call-bind: 1.0.8 call-bound: 1.0.3 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 is-arrayish@0.2.1: {} is-arrayish@0.3.2: {} - is-async-function@2.0.0: + is-async-function@2.1.0: dependencies: + call-bound: 1.0.3 + get-proto: 1.0.1 has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 is-bigint@1.1.0: dependencies: - has-bigints: 1.0.2 + has-bigints: 1.1.0 is-binary-path@2.1.0: dependencies: @@ -16652,14 +16700,14 @@ snapshots: dependencies: ci-info: 3.9.0 - is-core-module@2.16.0: + is-core-module@2.16.1: dependencies: hasown: 2.0.2 is-data-view@1.0.2: dependencies: call-bound: 1.0.3 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 is-typed-array: 1.1.15 is-date-object@1.1.0: @@ -16677,15 +16725,18 @@ snapshots: is-extglob@2.1.1: {} - is-finalizationregistry@1.1.0: + is-finalizationregistry@1.1.1: dependencies: - call-bind: 1.0.8 + call-bound: 1.0.3 is-fullwidth-code-point@3.0.0: {} - is-generator-function@1.0.10: + is-generator-function@1.1.0: dependencies: + call-bound: 1.0.3 + get-proto: 1.0.1 has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 is-glob@4.0.3: dependencies: @@ -16786,10 +16837,10 @@ snapshots: dependencies: call-bound: 1.0.3 - is-weakset@2.0.3: + is-weakset@2.0.4: dependencies: - call-bind: 1.0.8 - get-intrinsic: 1.2.6 + call-bound: 1.0.3 + get-intrinsic: 1.2.7 is-windows@1.0.2: {} @@ -16844,7 +16895,7 @@ snapshots: istanbul-lib-source-maps@4.0.1: dependencies: - debug: 4.3.7(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: @@ -16872,13 +16923,13 @@ snapshots: which: 1.3.1 wordwrap: 1.0.0 - iterator.prototype@1.1.4: + iterator.prototype@1.1.5: dependencies: define-data-property: 1.1.4 es-object-atoms: 1.0.0 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 + get-proto: 1.0.1 has-symbols: 1.1.0 - reflect.getprototypeof: 1.0.9 set-function-name: 2.0.2 jackspeak@3.4.3: @@ -16940,7 +16991,7 @@ snapshots: '@babel/preset-flow': 7.25.9(@babel/core@7.26.0) '@babel/preset-typescript': 7.26.0(@babel/core@7.26.0) '@babel/register': 7.25.9(@babel/core@7.26.0) - flow-parser: 0.255.0 + flow-parser: 0.258.0 graceful-fs: 4.2.11 micromatch: 4.0.8 neo-async: 2.6.2 @@ -16963,7 +17014,7 @@ snapshots: form-data: 4.0.1 html-encoding-sniffer: 4.0.0 http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.5 + https-proxy-agent: 7.0.6 is-potential-custom-element-name: 1.0.1 nwsapi: 2.2.16 parse5: 7.2.1 @@ -16975,7 +17026,7 @@ snapshots: webidl-conversions: 7.0.0 whatwg-encoding: 3.1.1 whatwg-mimetype: 4.0.0 - whatwg-url: 14.0.0 + whatwg-url: 14.1.0 ws: 8.18.0 xml-name-validator: 5.0.0 transitivePeerDependencies: @@ -16985,6 +17036,8 @@ snapshots: jsesc@3.0.2: {} + jsesc@3.1.0: {} + json-bigint@1.0.0: dependencies: bignumber.js: 9.1.2 @@ -17104,7 +17157,7 @@ snapshots: jsx-ast-utils@3.3.5: dependencies: array-includes: 3.1.8 - array.prototype.flat: 1.3.2 + array.prototype.flat: 1.3.3 object.assign: 4.1.7 object.values: 1.2.1 @@ -17167,7 +17220,7 @@ snapshots: dependencies: glob: 7.2.3 minimatch: 9.0.5 - webpack: 5.97.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) + webpack: 5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) webpack-merge: 4.2.2 karma@6.4.4: @@ -17194,7 +17247,7 @@ snapshots: socket.io: 4.8.1 source-map: 0.6.1 tmp: 0.2.3 - ua-parser-js: 0.7.39 + ua-parser-js: 0.7.40 yargs: 16.2.0 transitivePeerDependencies: - bufferutil @@ -17202,7 +17255,7 @@ snapshots: - supports-color - utf-8-validate - katex@0.16.18: + katex@0.16.19: dependencies: commander: 8.3.0 @@ -17222,13 +17275,13 @@ snapshots: dependencies: readable-stream: 2.3.8 - lerna@8.1.9(@swc/core@1.9.3(@swc/helpers@0.5.15))(babel-plugin-macros@3.1.0)(encoding@0.1.13): + lerna@8.1.9(@swc/core@1.10.4(@swc/helpers@0.5.15))(babel-plugin-macros@3.1.0)(encoding@0.1.13): dependencies: - '@lerna/create': 8.1.9(@swc/core@1.9.3(@swc/helpers@0.5.15))(babel-plugin-macros@3.1.0)(encoding@0.1.13)(typescript@5.7.2) + '@lerna/create': 8.1.9(@swc/core@1.10.4(@swc/helpers@0.5.15))(babel-plugin-macros@3.1.0)(encoding@0.1.13)(typescript@5.7.2) '@npmcli/arborist': 7.5.4 '@npmcli/package-json': 5.2.0 '@npmcli/run-script': 8.1.0 - '@nx/devkit': 20.1.4(nx@20.1.4(@swc/core@1.9.3(@swc/helpers@0.5.15))) + '@nx/devkit': 20.3.0(nx@20.3.0(@swc/core@1.10.4(@swc/helpers@0.5.15))) '@octokit/plugin-enterprise-rest': 6.0.1 '@octokit/rest': 19.0.11(encoding@0.1.13) aproba: 2.0.0 @@ -17273,7 +17326,7 @@ snapshots: npm-package-arg: 11.0.2 npm-packlist: 8.0.2 npm-registry-fetch: 17.1.0 - nx: 20.1.4(@swc/core@1.9.3(@swc/helpers@0.5.15)) + nx: 20.3.0(@swc/core@1.10.4(@swc/helpers@0.5.15)) p-map: 4.0.0 p-map-series: 2.1.0 p-pipe: 3.1.0 @@ -17482,7 +17535,7 @@ snapshots: log4js@6.9.1: dependencies: date-format: 4.0.14 - debug: 4.3.7(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) flatted: 3.3.2 rfdc: 1.4.1 streamroller: 3.1.5 @@ -17526,7 +17579,7 @@ snapshots: lz-string@1.5.0: {} - magic-string@0.30.14: + magic-string@0.30.17: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 @@ -17608,7 +17661,7 @@ snapshots: transitivePeerDependencies: - supports-color - marked@15.0.4: {} + marked@15.0.5: {} math-intrinsics@1.1.0: {} @@ -17747,7 +17800,7 @@ snapshots: dependencies: '@types/katex': 0.16.7 devlop: 1.1.0 - katex: 0.16.18 + katex: 0.16.19 micromark-factory-space: 2.0.1 micromark-util-character: 2.1.1 micromark-util-symbol: 2.0.1 @@ -17848,7 +17901,7 @@ snapshots: micromark@4.0.1: dependencies: '@types/debug': 4.1.12 - debug: 4.3.7(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) decode-named-character-reference: 1.0.2 devlop: 1.1.0 micromark-core-commonmark: 2.0.2 @@ -17982,7 +18035,7 @@ snapshots: ansi-colors: 4.1.3 browser-stdout: 1.3.1 chokidar: 3.6.0 - debug: 4.3.7(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) diff: 5.2.0 escape-string-regexp: 4.0.0 find-up: 5.0.0 @@ -18028,25 +18081,25 @@ snapshots: ms@2.1.3: {} - msw@2.6.6(@types/node@20.17.11)(typescript@5.7.2): + msw@2.7.0(@types/node@20.17.11)(typescript@5.7.2): dependencies: '@bundled-es-modules/cookie': 2.0.1 '@bundled-es-modules/statuses': 1.0.1 '@bundled-es-modules/tough-cookie': 0.1.6 - '@inquirer/confirm': 5.0.2(@types/node@20.17.11) - '@mswjs/interceptors': 0.37.3 + '@inquirer/confirm': 5.1.1(@types/node@20.17.11) + '@mswjs/interceptors': 0.37.5 '@open-draft/deferred-promise': 2.2.0 '@open-draft/until': 2.1.0 '@types/cookie': 0.6.0 '@types/statuses': 2.0.5 - chalk: 4.1.2 - graphql: 16.9.0 + graphql: 16.10.0 headers-polyfill: 4.0.3 is-node-process: 1.2.0 outvariant: 1.4.3 path-to-regexp: 6.3.0 + picocolors: 1.1.1 strict-event-emitter: 0.5.1 - type-fest: 4.30.0 + type-fest: 4.31.0 yargs: 17.7.2 optionalDependencies: typescript: 5.7.2 @@ -18098,7 +18151,7 @@ snapshots: '@swc/counter': 0.1.3 '@swc/helpers': 0.5.15 busboy: 1.6.0 - caniuse-lite: 1.0.30001686 + caniuse-lite: 1.0.30001690 postcss: 8.4.31 react: 19.0.0 react-dom: 19.0.0(react@19.0.0) @@ -18177,7 +18230,7 @@ snapshots: dependencies: process-on-spawn: 1.1.0 - node-releases@2.0.18: {} + node-releases@2.0.19: {} nopt@3.0.6: dependencies: @@ -18197,7 +18250,7 @@ snapshots: normalize-package-data@3.0.3: dependencies: hosted-git-info: 4.1.0 - is-core-module: 2.16.0 + is-core-module: 2.16.1 semver: 7.6.3 validate-npm-package-license: 3.0.4 @@ -18269,18 +18322,18 @@ snapshots: nwsapi@2.2.16: {} - nx@20.1.4(@swc/core@1.9.3(@swc/helpers@0.5.15)): + nx@20.3.0(@swc/core@1.10.4(@swc/helpers@0.5.15)): dependencies: '@napi-rs/wasm-runtime': 0.2.4 '@yarnpkg/lockfile': 1.1.0 '@yarnpkg/parsers': 3.0.2 '@zkochan/js-yaml': 0.0.7 - axios: 1.7.8(debug@4.3.7) + axios: 1.7.9(debug@4.4.0) chalk: 4.1.2 cli-cursor: 3.1.0 cli-spinners: 2.6.1 cliui: 8.0.1 - dotenv: 16.4.6 + dotenv: 16.4.7 dotenv-expand: 11.0.7 enquirer: 2.3.6 figures: 3.2.0 @@ -18295,26 +18348,28 @@ snapshots: npm-run-path: 4.0.1 open: 8.4.2 ora: 5.3.0 + resolve.exports: 2.0.3 semver: 7.6.3 string-width: 4.2.3 tar-stream: 2.2.0 tmp: 0.2.3 tsconfig-paths: 4.2.0 tslib: 2.8.1 + yaml: 2.7.0 yargs: 17.7.2 yargs-parser: 21.1.1 optionalDependencies: - '@nx/nx-darwin-arm64': 20.1.4 - '@nx/nx-darwin-x64': 20.1.4 - '@nx/nx-freebsd-x64': 20.1.4 - '@nx/nx-linux-arm-gnueabihf': 20.1.4 - '@nx/nx-linux-arm64-gnu': 20.1.4 - '@nx/nx-linux-arm64-musl': 20.1.4 - '@nx/nx-linux-x64-gnu': 20.1.4 - '@nx/nx-linux-x64-musl': 20.1.4 - '@nx/nx-win32-arm64-msvc': 20.1.4 - '@nx/nx-win32-x64-msvc': 20.1.4 - '@swc/core': 1.9.3(@swc/helpers@0.5.15) + '@nx/nx-darwin-arm64': 20.3.0 + '@nx/nx-darwin-x64': 20.3.0 + '@nx/nx-freebsd-x64': 20.3.0 + '@nx/nx-linux-arm-gnueabihf': 20.3.0 + '@nx/nx-linux-arm64-gnu': 20.3.0 + '@nx/nx-linux-arm64-musl': 20.3.0 + '@nx/nx-linux-x64-gnu': 20.3.0 + '@nx/nx-linux-x64-musl': 20.3.0 + '@nx/nx-win32-arm64-msvc': 20.3.0 + '@nx/nx-win32-x64-msvc': 20.3.0 + '@swc/core': 1.10.4(@swc/helpers@0.5.15) transitivePeerDependencies: - debug @@ -18379,7 +18434,7 @@ snapshots: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 es-object-atoms: 1.0.0 object.getownpropertydescriptors@2.1.8: @@ -18387,7 +18442,7 @@ snapshots: array.prototype.reduce: 1.0.7 call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 es-object-atoms: 1.0.0 gopd: 1.2.0 safe-array-concat: 1.1.3 @@ -18396,7 +18451,7 @@ snapshots: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 object.values@1.2.1: dependencies: @@ -18484,6 +18539,12 @@ snapshots: override-require@1.1.1: {} + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.2.7 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + p-event@5.0.1: dependencies: p-timeout: 5.1.0 @@ -18645,7 +18706,7 @@ snapshots: parse-imports@2.2.1: dependencies: - es-module-lexer: 1.5.4 + es-module-lexer: 1.6.0 slashes: 3.0.12 parse-json@4.0.0: @@ -19108,15 +19169,15 @@ snapshots: indent-string: 4.0.0 strip-indent: 3.0.0 - reflect.getprototypeof@1.0.9: + reflect.getprototypeof@1.0.10: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - dunder-proto: 1.0.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 es-errors: 1.3.0 - get-intrinsic: 1.2.6 - gopd: 1.2.0 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.7 + get-proto: 1.0.1 which-builtin-type: 1.2.1 regenerate-unicode-properties@10.2.0: @@ -19133,11 +19194,13 @@ snapshots: dependencies: '@babel/runtime': 7.26.0 - regexp.prototype.flags@1.5.3: + regexp.prototype.flags@1.5.4: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 set-function-name: 2.0.2 regexpu-core@6.2.0: @@ -19224,17 +19287,19 @@ snapshots: resolve-pkg-maps@1.0.0: {} + resolve.exports@2.0.3: {} + resolve@1.1.7: {} resolve@1.22.10: dependencies: - is-core-module: 2.16.0 + is-core-module: 2.16.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 resolve@2.0.0-next.5: dependencies: - is-core-module: 2.16.0 + is-core-module: 2.16.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 @@ -19274,28 +19339,29 @@ snapshots: robust-predicates@3.0.2: {} - rollup@4.28.0: + rollup@4.30.0: dependencies: '@types/estree': 1.0.6 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.28.0 - '@rollup/rollup-android-arm64': 4.28.0 - '@rollup/rollup-darwin-arm64': 4.28.0 - '@rollup/rollup-darwin-x64': 4.28.0 - '@rollup/rollup-freebsd-arm64': 4.28.0 - '@rollup/rollup-freebsd-x64': 4.28.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.28.0 - '@rollup/rollup-linux-arm-musleabihf': 4.28.0 - '@rollup/rollup-linux-arm64-gnu': 4.28.0 - '@rollup/rollup-linux-arm64-musl': 4.28.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.28.0 - '@rollup/rollup-linux-riscv64-gnu': 4.28.0 - '@rollup/rollup-linux-s390x-gnu': 4.28.0 - '@rollup/rollup-linux-x64-gnu': 4.28.0 - '@rollup/rollup-linux-x64-musl': 4.28.0 - '@rollup/rollup-win32-arm64-msvc': 4.28.0 - '@rollup/rollup-win32-ia32-msvc': 4.28.0 - '@rollup/rollup-win32-x64-msvc': 4.28.0 + '@rollup/rollup-android-arm-eabi': 4.30.0 + '@rollup/rollup-android-arm64': 4.30.0 + '@rollup/rollup-darwin-arm64': 4.30.0 + '@rollup/rollup-darwin-x64': 4.30.0 + '@rollup/rollup-freebsd-arm64': 4.30.0 + '@rollup/rollup-freebsd-x64': 4.30.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.30.0 + '@rollup/rollup-linux-arm-musleabihf': 4.30.0 + '@rollup/rollup-linux-arm64-gnu': 4.30.0 + '@rollup/rollup-linux-arm64-musl': 4.30.0 + '@rollup/rollup-linux-loongarch64-gnu': 4.30.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.30.0 + '@rollup/rollup-linux-riscv64-gnu': 4.30.0 + '@rollup/rollup-linux-s390x-gnu': 4.30.0 + '@rollup/rollup-linux-x64-gnu': 4.30.0 + '@rollup/rollup-linux-x64-musl': 4.30.0 + '@rollup/rollup-win32-arm64-msvc': 4.30.0 + '@rollup/rollup-win32-ia32-msvc': 4.30.0 + '@rollup/rollup-win32-x64-msvc': 4.30.0 fsevents: 2.3.3 router@2.0.0: @@ -19328,7 +19394,7 @@ snapshots: dependencies: call-bind: 1.0.8 call-bound: 1.0.3 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 has-symbols: 1.1.0 isarray: 2.0.5 @@ -19336,6 +19402,11 @@ snapshots: safe-buffer@5.2.1: {} + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + safe-regex-test@1.1.0: dependencies: call-bound: 1.0.3 @@ -19377,7 +19448,7 @@ snapshots: send@1.1.0: dependencies: - debug: 4.3.7(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) destroy: 1.2.0 encodeurl: 2.0.0 escape-html: 1.0.3 @@ -19438,7 +19509,7 @@ snapshots: define-data-property: 1.1.4 es-errors: 1.3.0 function-bind: 1.1.2 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 gopd: 1.2.0 has-property-descriptors: 1.0.2 @@ -19449,6 +19520,12 @@ snapshots: functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + setimmediate@1.0.5: {} setprototypeof@1.2.0: {} @@ -19502,14 +19579,14 @@ snapshots: dependencies: call-bound: 1.0.3 es-errors: 1.3.0 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 object-inspect: 1.13.3 side-channel-weakmap@1.0.2: dependencies: call-bound: 1.0.3 es-errors: 1.3.0 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 object-inspect: 1.13.3 side-channel-map: 1.0.1 @@ -19577,7 +19654,7 @@ snapshots: socket.io-adapter@2.5.5: dependencies: - debug: 4.3.7(supports-color@8.1.1) + debug: 4.3.7 ws: 8.17.1 transitivePeerDependencies: - bufferutil @@ -19587,7 +19664,7 @@ snapshots: socket.io-parser@4.2.4: dependencies: '@socket.io/component-emitter': 3.1.2 - debug: 4.3.7(supports-color@8.1.1) + debug: 4.3.7 transitivePeerDependencies: - supports-color @@ -19596,7 +19673,7 @@ snapshots: accepts: 1.3.8 base64id: 2.0.0 cors: 2.8.5 - debug: 4.3.7(supports-color@8.1.1) + debug: 4.3.7 engine.io: 6.6.2 socket.io-adapter: 2.5.5 socket.io-parser: 4.2.4 @@ -19605,10 +19682,10 @@ snapshots: - supports-color - utf-8-validate - socks-proxy-agent@8.0.4: + socks-proxy-agent@8.0.5: dependencies: - agent-base: 7.1.1 - debug: 4.3.7(supports-color@8.1.1) + agent-base: 7.1.3 + debug: 4.4.0(supports-color@8.1.1) socks: 2.8.3 transitivePeerDependencies: - supports-color @@ -19698,7 +19775,7 @@ snapshots: streamroller@3.1.5: dependencies: date-format: 4.0.14 - debug: 4.3.7(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) fs-extra: 8.1.0 transitivePeerDependencies: - supports-color @@ -19711,7 +19788,7 @@ snapshots: dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.97.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) + webpack: 5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) string-width@4.2.3: dependencies: @@ -19729,28 +19806,28 @@ snapshots: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 string.prototype.matchall@4.0.12: dependencies: call-bind: 1.0.8 call-bound: 1.0.3 define-properties: 1.2.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 es-errors: 1.3.0 es-object-atoms: 1.0.0 - get-intrinsic: 1.2.6 + get-intrinsic: 1.2.7 gopd: 1.2.0 has-symbols: 1.1.0 internal-slot: 1.1.0 - regexp.prototype.flags: 1.5.3 + regexp.prototype.flags: 1.5.4 set-function-name: 2.0.2 side-channel: 1.1.0 string.prototype.repeat@1.0.0: dependencies: define-properties: 1.2.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 string.prototype.trim@1.2.10: dependencies: @@ -19758,7 +19835,7 @@ snapshots: call-bound: 1.0.3 define-data-property: 1.1.4 define-properties: 1.2.1 - es-abstract: 1.23.7 + es-abstract: 1.23.9 es-object-atoms: 1.0.0 has-property-descriptors: 1.0.2 @@ -19850,7 +19927,7 @@ snapshots: sucrase@3.35.0: dependencies: - '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/gen-mapping': 0.3.8 commander: 4.1.1 glob: 10.4.5 lines-and-columns: 1.2.4 @@ -19911,18 +19988,18 @@ snapshots: temp-dir@1.0.0: {} - terser-webpack-plugin@5.3.11(@swc/core@1.9.3(@swc/helpers@0.5.15))(webpack@5.97.1): + terser-webpack-plugin@5.3.11(@swc/core@1.10.4(@swc/helpers@0.5.15))(webpack@5.97.1): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 4.3.0 serialize-javascript: 6.0.2 - terser: 5.36.0 - webpack: 5.97.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) + terser: 5.37.0 + webpack: 5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) optionalDependencies: - '@swc/core': 1.9.3(@swc/helpers@0.5.15) + '@swc/core': 1.10.4(@swc/helpers@0.5.15) - terser@5.36.0: + terser@5.37.0: dependencies: '@jridgewell/source-map': 0.3.6 acorn: 8.14.0 @@ -19965,7 +20042,7 @@ snapshots: tinybench@2.9.0: {} - tinyexec@0.3.1: {} + tinyexec@0.3.2: {} tinyglobby@0.2.10: dependencies: @@ -19978,11 +20055,11 @@ snapshots: tinyspy@3.0.2: {} - tldts-core@6.1.65: {} + tldts-core@6.1.71: {} - tldts@6.1.65: + tldts@6.1.71: dependencies: - tldts-core: 6.1.65 + tldts-core: 6.1.71 tmp@0.0.33: dependencies: @@ -20007,7 +20084,7 @@ snapshots: tough-cookie@5.0.0: dependencies: - tldts: 6.1.65 + tldts: 6.1.71 tr46@0.0.3: {} @@ -20060,7 +20137,7 @@ snapshots: tuf-js@2.2.1: dependencies: '@tufjs/models': 2.0.1 - debug: 4.3.7(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) make-fetch-happen: 13.0.1 transitivePeerDependencies: - supports-color @@ -20093,7 +20170,7 @@ snapshots: type-fest@2.19.0: {} - type-fest@4.30.0: {} + type-fest@4.31.0: {} type-is@1.6.18: dependencies: @@ -20128,7 +20205,7 @@ snapshots: gopd: 1.2.0 has-proto: 1.2.0 is-typed-array: 1.1.15 - reflect.getprototypeof: 1.0.9 + reflect.getprototypeof: 1.0.10 typed-array-length@1.0.7: dependencies: @@ -20137,7 +20214,7 @@ snapshots: gopd: 1.2.0 is-typed-array: 1.1.15 possible-typed-array-names: 1.0.0 - reflect.getprototypeof: 1.0.9 + reflect.getprototypeof: 1.0.10 typedarray-to-buffer@3.1.5: dependencies: @@ -20147,7 +20224,7 @@ snapshots: typescript@5.7.2: {} - ua-parser-js@0.7.39: {} + ua-parser-js@0.7.40: {} uc.micro@2.1.0: {} @@ -20157,7 +20234,7 @@ snapshots: unbox-primitive@1.1.0: dependencies: call-bound: 1.0.3 - has-bigints: 1.0.2 + has-bigints: 1.1.0 has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 @@ -20246,9 +20323,9 @@ snapshots: upath@2.0.1: {} - update-browserslist-db@1.1.1(browserslist@4.24.2): + update-browserslist-db@1.1.1(browserslist@4.24.3): dependencies: - browserslist: 4.24.2 + browserslist: 4.24.3 escalade: 3.2.0 picocolors: 1.1.1 @@ -20281,8 +20358,8 @@ snapshots: util@0.12.5: dependencies: inherits: 2.0.4 - is-arguments: 1.1.1 - is-generator-function: 1.0.10 + is-arguments: 1.2.0 + is-generator-function: 1.1.0 is-typed-array: 1.1.15 which-typed-array: 1.1.18 @@ -20292,7 +20369,7 @@ snapshots: uuid@10.0.0: {} - uuid@11.0.3: {} + uuid@11.0.4: {} uuid@8.3.2: {} @@ -20327,13 +20404,13 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.2 - vite-node@2.1.8(@types/node@20.17.11)(terser@5.36.0): + vite-node@2.1.8(@types/node@20.17.11)(terser@5.37.0): dependencies: cac: 6.7.14 - debug: 4.3.7(supports-color@8.1.1) - es-module-lexer: 1.5.4 + debug: 4.4.0(supports-color@8.1.1) + es-module-lexer: 1.6.0 pathe: 1.1.2 - vite: 5.4.11(@types/node@20.17.11)(terser@5.36.0) + vite: 5.4.11(@types/node@20.17.11)(terser@5.37.0) transitivePeerDependencies: - '@types/node' - less @@ -20345,41 +20422,41 @@ snapshots: - supports-color - terser - vite@5.4.11(@types/node@20.17.11)(terser@5.36.0): + vite@5.4.11(@types/node@20.17.11)(terser@5.37.0): dependencies: esbuild: 0.21.5 postcss: 8.4.49 - rollup: 4.28.0 + rollup: 4.30.0 optionalDependencies: '@types/node': 20.17.11 fsevents: 2.3.3 - terser: 5.36.0 + terser: 5.37.0 - vitest@2.1.8(@types/node@20.17.11)(@vitest/browser@2.1.8)(@vitest/ui@2.1.8)(jsdom@25.0.1)(msw@2.6.6(@types/node@20.17.11)(typescript@5.7.2))(terser@5.36.0): + vitest@2.1.8(@types/node@20.17.11)(@vitest/browser@2.1.8)(@vitest/ui@2.1.8)(jsdom@25.0.1)(msw@2.7.0(@types/node@20.17.11)(typescript@5.7.2))(terser@5.37.0): dependencies: '@vitest/expect': 2.1.8 - '@vitest/mocker': 2.1.8(msw@2.6.6(@types/node@20.17.11)(typescript@5.7.2))(vite@5.4.11(@types/node@20.17.11)(terser@5.36.0)) + '@vitest/mocker': 2.1.8(msw@2.7.0(@types/node@20.17.11)(typescript@5.7.2))(vite@5.4.11(@types/node@20.17.11)(terser@5.37.0)) '@vitest/pretty-format': 2.1.8 '@vitest/runner': 2.1.8 '@vitest/snapshot': 2.1.8 '@vitest/spy': 2.1.8 '@vitest/utils': 2.1.8 chai: 5.1.2 - debug: 4.3.7(supports-color@8.1.1) + debug: 4.4.0(supports-color@8.1.1) expect-type: 1.1.0 - magic-string: 0.30.14 + magic-string: 0.30.17 pathe: 1.1.2 std-env: 3.8.0 tinybench: 2.9.0 - tinyexec: 0.3.1 + tinyexec: 0.3.2 tinypool: 1.0.2 tinyrainbow: 1.2.0 - vite: 5.4.11(@types/node@20.17.11)(terser@5.36.0) - vite-node: 2.1.8(@types/node@20.17.11)(terser@5.36.0) + vite: 5.4.11(@types/node@20.17.11)(terser@5.37.0) + vite-node: 2.1.8(@types/node@20.17.11)(terser@5.37.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 20.17.11 - '@vitest/browser': 2.1.8(@types/node@20.17.11)(playwright@1.49.1)(typescript@5.7.2)(vite@5.4.11(@types/node@20.17.11)(terser@5.36.0))(vitest@2.1.8) + '@vitest/browser': 2.1.8(@types/node@20.17.11)(playwright@1.49.1)(typescript@5.7.2)(vite@5.4.11(@types/node@20.17.11)(terser@5.37.0))(vitest@2.1.8) '@vitest/ui': 2.1.8(vitest@2.1.8) jsdom: 25.0.1 transitivePeerDependencies: @@ -20446,7 +20523,7 @@ snapshots: import-local: 3.2.0 interpret: 3.1.1 rechoir: 0.8.0 - webpack: 5.97.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) + webpack: 5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) webpack-merge: 6.0.1 optionalDependencies: webpack-bundle-analyzer: 4.10.2 @@ -20463,7 +20540,7 @@ snapshots: webpack-sources@3.2.3: {} - webpack@5.97.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)): + webpack@5.97.1(@swc/core@1.10.4(@swc/helpers@0.5.15))(webpack-cli@6.0.1(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.6 @@ -20471,10 +20548,10 @@ snapshots: '@webassemblyjs/wasm-edit': 1.14.1 '@webassemblyjs/wasm-parser': 1.14.1 acorn: 8.14.0 - browserslist: 4.24.2 + browserslist: 4.24.3 chrome-trace-event: 1.0.4 - enhanced-resolve: 5.17.1 - es-module-lexer: 1.5.4 + enhanced-resolve: 5.18.0 + es-module-lexer: 1.6.0 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 @@ -20485,7 +20562,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.11(@swc/core@1.9.3(@swc/helpers@0.5.15))(webpack@5.97.1) + terser-webpack-plugin: 5.3.11(@swc/core@1.10.4(@swc/helpers@0.5.15))(webpack@5.97.1) watchpack: 2.4.2 webpack-sources: 3.2.3 optionalDependencies: @@ -20501,7 +20578,7 @@ snapshots: whatwg-mimetype@4.0.0: {} - whatwg-url@14.0.0: + whatwg-url@14.1.0: dependencies: tr46: 5.0.0 webidl-conversions: 7.0.0 @@ -20524,10 +20601,10 @@ snapshots: call-bound: 1.0.3 function.prototype.name: 1.1.8 has-tostringtag: 1.0.2 - is-async-function: 2.0.0 + is-async-function: 2.1.0 is-date-object: 1.1.0 - is-finalizationregistry: 1.1.0 - is-generator-function: 1.0.10 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.0 is-regex: 1.2.1 is-weakref: 1.1.0 isarray: 2.0.5 @@ -20540,7 +20617,7 @@ snapshots: is-map: 2.0.3 is-set: 2.0.3 is-weakmap: 2.0.2 - is-weakset: 2.0.3 + is-weakset: 2.0.4 which-module@2.0.1: {} @@ -20669,6 +20746,8 @@ snapshots: yaml@1.10.2: {} + yaml@2.7.0: {} + yargs-parser@18.1.3: dependencies: camelcase: 5.3.1 @@ -20733,10 +20812,10 @@ snapshots: compress-commons: 4.1.2 readable-stream: 3.6.2 - zod-validation-error@3.4.0(zod@3.23.8): + zod-validation-error@3.4.0(zod@3.24.1): dependencies: - zod: 3.23.8 + zod: 3.24.1 - zod@3.23.8: {} + zod@3.24.1: {} zwitch@2.0.4: {} From 0a8dff6c944f928e8d8636b8f3df4f3731955e13 Mon Sep 17 00:00:00 2001 From: tomashauser <37981481+tomashauser@users.noreply.github.com> Date: Tue, 7 Jan 2025 09:23:10 +0100 Subject: [PATCH 13/25] [docs] Fix non-existing "adapter" property of LocalizationProvider (#16084) --- docs/src/modules/components/overview/DateLibraries.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/modules/components/overview/DateLibraries.tsx b/docs/src/modules/components/overview/DateLibraries.tsx index 3853930466d6c..9fafad78b5819 100644 --- a/docs/src/modules/components/overview/DateLibraries.tsx +++ b/docs/src/modules/components/overview/DateLibraries.tsx @@ -101,7 +101,7 @@ export default function DateLibraries() { `, + ``, ` `, ``, ].join('\n')} From fb23fd1e93bf07a564306f3cff212717ce6d9c0c Mon Sep 17 00:00:00 2001 From: Lukas Tyla Date: Tue, 7 Jan 2025 12:53:00 +0200 Subject: [PATCH 14/25] [l10n] Improve Norwegian (nb-NO) locale (#16083) (@josteinjhauge) (#16089) Signed-off-by: Jostein Hauge Co-authored-by: Jostein Hauge --- docs/data/date-pickers/localization/data.json | 2 +- packages/x-date-pickers/src/locales/nbNO.ts | 28 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/data/date-pickers/localization/data.json b/docs/data/date-pickers/localization/data.json index ff28faa14da27..fb6709dc7b2ef 100644 --- a/docs/data/date-pickers/localization/data.json +++ b/docs/data/date-pickers/localization/data.json @@ -187,7 +187,7 @@ "languageTag": "nb-NO", "importName": "nbNO", "localeName": "Norwegian (Bokmål)", - "missingKeysCount": 14, + "missingKeysCount": 0, "totalKeysCount": 50, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/nbNO.ts" }, diff --git a/packages/x-date-pickers/src/locales/nbNO.ts b/packages/x-date-pickers/src/locales/nbNO.ts index 57732c773daa8..1df1b24bcda5f 100644 --- a/packages/x-date-pickers/src/locales/nbNO.ts +++ b/packages/x-date-pickers/src/locales/nbNO.ts @@ -25,10 +25,10 @@ const nbNOPickers: Partial = { // DateRange labels start: 'Start', end: 'Slutt', - // startDate: 'Start date', - // startTime: 'Start time', - // endDate: 'End date', - // endTime: 'End time', + startDate: 'Startdato', + startTime: 'Starttid', + endDate: 'Sluttdato', + endTime: 'Slutttid', // Action bar cancelButtonLabel: 'Avbryt', @@ -63,7 +63,7 @@ const nbNOPickers: Partial = { formattedDate ? `Velg dato, valgt dato er ${formattedDate}` : 'Velg dato', openTimePickerDialogue: (formattedTime) => formattedTime ? `Velg tid, valgt tid er ${formattedTime}` : 'Velg tid', - // fieldClearLabel: 'Clear', + fieldClearLabel: 'Slett', // Table labels timeTableLabel: 'velg tid', @@ -80,17 +80,17 @@ const nbNOPickers: Partial = { fieldMeridiemPlaceholder: () => 'aa', // View names - // year: 'Year', - // month: 'Month', - // day: 'Day', - // weekDay: 'Week day', - // hours: 'Hours', - // minutes: 'Minutes', - // seconds: 'Seconds', - // meridiem: 'Meridiem', + year: 'År', + month: 'Måned', + day: 'Dag', + weekDay: 'Ukedag', + hours: 'Timer', + minutes: 'Minutter', + seconds: 'Sekunder', + meridiem: 'Meridiem', // Common - // empty: 'Empty', + empty: 'Tøm', }; export const nbNO = getPickersLocalization(nbNOPickers); From 011ccd01fb173b5fe9dd5b7316471c86cb3aa3d0 Mon Sep 17 00:00:00 2001 From: Lukas Tyla Date: Tue, 7 Jan 2025 13:32:27 +0200 Subject: [PATCH 15/25] [pickers] Memoize `` (#16071) --- .../tests/DesktopDatePicker.test.tsx | 43 +++++++++++++++++++ .../src/PickersActionBar/PickersActionBar.tsx | 6 ++- .../src/PickersLayout/usePickerLayout.tsx | 6 ++- scripts/x-date-pickers-pro.exports.json | 2 +- scripts/x-date-pickers.exports.json | 2 +- 5 files changed, 54 insertions(+), 5 deletions(-) diff --git a/packages/x-date-pickers/src/DesktopDatePicker/tests/DesktopDatePicker.test.tsx b/packages/x-date-pickers/src/DesktopDatePicker/tests/DesktopDatePicker.test.tsx index d9650084b2a90..1c55b5a4bbf50 100644 --- a/packages/x-date-pickers/src/DesktopDatePicker/tests/DesktopDatePicker.test.tsx +++ b/packages/x-date-pickers/src/DesktopDatePicker/tests/DesktopDatePicker.test.tsx @@ -7,6 +7,7 @@ import { fireEvent, screen } from '@mui/internal-test-utils'; import { DesktopDatePicker } from '@mui/x-date-pickers/DesktopDatePicker'; import { createPickerRenderer, adapterToUse, openPicker } from 'test/utils/pickers'; import { describeSkipIf, testSkipIf, isJSDOM } from 'test/utils/skipIf'; +import { PickersActionBar, PickersActionBarAction } from '@mui/x-date-pickers/PickersActionBar'; describe('', () => { const { render, clock } = createPickerRenderer({ clock: 'fake' }); @@ -349,4 +350,46 @@ describe('', () => { openPicker({ type: 'date', variant: 'desktop' }); }).toWarnDev('MUI X: `openTo="month"` is not a valid prop.'); }); + + describe('performance', () => { + it('should not re-render the `PickersActionBar` on date change', () => { + const RenderCount = spy((props) => ); + + render( + , + ); + + const renderCountBeforeChange = RenderCount.callCount; + fireEvent.click(screen.getByRole('gridcell', { name: '2' })); + fireEvent.click(screen.getByRole('gridcell', { name: '3' })); + expect(RenderCount.callCount - renderCountBeforeChange).to.equal(0); // no re-renders after selecting new values + }); + + it('should not re-render the `PickersActionBar` on date change with custom callback actions with root component updates', () => { + const RenderCount = spy((props) => ); + const actions: PickersActionBarAction[] = ['clear', 'today']; + + const { setProps } = render( + ({ actions }) }} + closeOnSelect={false} + open + />, + ); + + const renderCountBeforeChange = RenderCount.callCount; + + setProps({ defaultValue: adapterToUse.date('2018-01-04') }); + + fireEvent.click(screen.getByRole('gridcell', { name: '2' })); + fireEvent.click(screen.getByRole('gridcell', { name: '3' })); + expect(RenderCount.callCount - renderCountBeforeChange).to.equal(0); // no re-renders after selecting new values and causing a root component re-render + }); + }); }); diff --git a/packages/x-date-pickers/src/PickersActionBar/PickersActionBar.tsx b/packages/x-date-pickers/src/PickersActionBar/PickersActionBar.tsx index de7ac68347456..4d9a8a3fa07c9 100644 --- a/packages/x-date-pickers/src/PickersActionBar/PickersActionBar.tsx +++ b/packages/x-date-pickers/src/PickersActionBar/PickersActionBar.tsx @@ -36,7 +36,7 @@ const PickersActionBarRoot = styled(DialogActions, { * * - [PickersActionBar API](https://mui.com/x/api/date-pickers/pickers-action-bar/) */ -function PickersActionBar(props: PickersActionBarProps) { +function PickersActionBarComponent(props: PickersActionBarProps) { const { actions, ...other } = props; const translations = usePickerTranslations(); @@ -85,7 +85,7 @@ function PickersActionBar(props: PickersActionBarProps) { return {buttons}; } -PickersActionBar.propTypes = { +PickersActionBarComponent.propTypes = { // ----------------------------- Warning -------------------------------- // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "pnpm proptypes" | @@ -113,4 +113,6 @@ PickersActionBar.propTypes = { ]), } as any; +const PickersActionBar = React.memo(PickersActionBarComponent); + export { PickersActionBar }; diff --git a/packages/x-date-pickers/src/PickersLayout/usePickerLayout.tsx b/packages/x-date-pickers/src/PickersLayout/usePickerLayout.tsx index 73845e01d611d..4614d4875c4b9 100644 --- a/packages/x-date-pickers/src/PickersLayout/usePickerLayout.tsx +++ b/packages/x-date-pickers/src/PickersLayout/usePickerLayout.tsx @@ -55,7 +55,11 @@ const usePickerLayout = ( // Action bar const ActionBar = slots?.actionBar ?? PickersActionBar; - const actionBarProps = useSlotProps({ + const { + // PickersActionBar does not use it and providing it breaks memoization + ownerState: destructuredOwnerState, + ...actionBarProps + } = useSlotProps({ elementType: ActionBar, externalSlotProps: slotProps?.actionBar, additionalProps: { diff --git a/scripts/x-date-pickers-pro.exports.json b/scripts/x-date-pickers-pro.exports.json index 7ff9be95cd478..7ac4157713712 100644 --- a/scripts/x-date-pickers-pro.exports.json +++ b/scripts/x-date-pickers-pro.exports.json @@ -252,7 +252,7 @@ { "name": "PickerManager", "kind": "Interface" }, { "name": "PickerOwnerState", "kind": "Interface" }, { "name": "PickerRangeFieldSlotProps", "kind": "TypeAlias" }, - { "name": "PickersActionBar", "kind": "Function" }, + { "name": "PickersActionBar", "kind": "Variable" }, { "name": "PickersActionBarAction", "kind": "TypeAlias" }, { "name": "PickersActionBarProps", "kind": "Interface" }, { "name": "PickersCalendarHeader", "kind": "Variable" }, diff --git a/scripts/x-date-pickers.exports.json b/scripts/x-date-pickers.exports.json index 270eb6400692e..f39968054d183 100644 --- a/scripts/x-date-pickers.exports.json +++ b/scripts/x-date-pickers.exports.json @@ -167,7 +167,7 @@ { "name": "PickerLayoutOwnerState", "kind": "Interface" }, { "name": "PickerManager", "kind": "Interface" }, { "name": "PickerOwnerState", "kind": "Interface" }, - { "name": "PickersActionBar", "kind": "Function" }, + { "name": "PickersActionBar", "kind": "Variable" }, { "name": "PickersActionBarAction", "kind": "TypeAlias" }, { "name": "PickersActionBarProps", "kind": "Interface" }, { "name": "PickersCalendarHeader", "kind": "Variable" }, From cad579c88e729ceec526d7bbdb9c893a2d4b1646 Mon Sep 17 00:00:00 2001 From: Flavien DELANGLE Date: Tue, 7 Jan 2025 12:35:24 +0100 Subject: [PATCH 16/25] [pickers] Rename `ctx.onViewChange` to `ctx.setView` and add it to the actions context (#16044) --- .../migration-pickers-v7.md | 4 ++- .../DateTimeRangePickerTabs.tsx | 6 ++-- .../DateTimeRangePickerToolbar.tsx | 14 ++++----- .../useDesktopRangePicker.tsx | 1 - .../hooks/useEnrichedRangePickerFieldProps.ts | 8 ++--- .../src/DateTimePicker/DateTimePickerTabs.tsx | 4 +-- .../DateTimePicker/DateTimePickerToolbar.tsx | 18 ++++++------ .../PickersActionBar.test.tsx | 1 + .../src/TimePicker/TimePickerToolbar.tsx | 8 ++--- .../src/hooks/usePickerActionsContext.ts | 4 ++- .../internals/components/PickerProvider.tsx | 23 ++++++++++----- .../src/internals/hooks/useOpenState.ts | 28 +++++++++--------- .../hooks/usePicker/usePickerProvider.ts | 10 ++++++- .../hooks/usePicker/usePickerViews.tsx | 29 +++++++++++++------ 14 files changed, 94 insertions(+), 64 deletions(-) diff --git a/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md b/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md index 5c6bdf2033eb2..f4ea6934fdcbb 100644 --- a/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md +++ b/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md @@ -447,7 +447,9 @@ If the updated values do not fit your use case, you can [override them](/x/react +const { views } = usePickerContext(); -const { onViewChange } = props; - +const { onViewChange } = usePickerContext(); + -onViewChange('month'); + +const { setView } = usePickerContext(); + +setView('month'); ``` - The component passed to the `layout` slot no longer receives the `onClear`, `onSetToday`, `onAccept`, `onCancel`, `onOpen`, `onClose` `onDismiss`, `onChange` and `onSelectShortcut` props. diff --git a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerTabs.tsx b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerTabs.tsx index 2b83f8a4c4932..75befc777bafd 100644 --- a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerTabs.tsx +++ b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerTabs.tsx @@ -119,7 +119,7 @@ const DateTimeRangePickerTabs = function DateTimeRangePickerTabs( const translations = usePickerTranslations(); const { ownerState } = usePickerPrivateContext(); - const { view, onViewChange } = usePickerContext(); + const { view, setView } = usePickerContext(); const classes = useUtilityClasses(classesProp); const { rangePosition, onRangePositionChange } = usePickerRangePositionContext(); @@ -160,13 +160,13 @@ const DateTimeRangePickerTabs = function DateTimeRangePickerTabs( const changeToPreviousTab = useEventCallback(() => { const previousTab = value == null ? tabOptions[0] : tabOptions[tabOptions.indexOf(value) - 1]; - onViewChange(tabToView(previousTab)); + setView(tabToView(previousTab)); handleRangePositionChange(previousTab); }); const changeToNextTab = useEventCallback(() => { const nextTab = value == null ? tabOptions[0] : tabOptions[tabOptions.indexOf(value) + 1]; - onViewChange(tabToView(nextTab)); + setView(tabToView(nextTab)); handleRangePositionChange(nextTab); }); diff --git a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx index d421cc99d2359..2c2859863d024 100644 --- a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx @@ -99,7 +99,7 @@ const DateTimeRangePickerToolbar = React.forwardRef(function DateTimeRangePicker ...other } = props; - const { value, setValue, disabled, readOnly, view, onViewChange, views } = usePickerContext< + const { value, setValue, disabled, readOnly, view, setView, views } = usePickerContext< PickerRangeValue, DateTimeRangeViews >(); @@ -141,17 +141,17 @@ const DateTimeRangePickerToolbar = React.forwardRef(function DateTimeRangePicker if (rangePosition !== 'start') { onRangePositionChange('start'); } - onViewChange(newView); + setView(newView); }; return { value: value[0], setValue: wrappedSetValue, forceDesktopVariant: true, - onViewChange: handleStartRangeViewChange, + setView: handleStartRangeViewChange, view: rangePosition === 'start' ? view : null, }; - }, [value, wrappedSetValue, rangePosition, view, onRangePositionChange, onViewChange]); + }, [value, wrappedSetValue, rangePosition, view, onRangePositionChange, setView]); const endOverrides = React.useMemo(() => { const handleEndRangeViewChange = (newView: DateOrTimeViewWithMeridiem) => { @@ -161,17 +161,17 @@ const DateTimeRangePickerToolbar = React.forwardRef(function DateTimeRangePicker if (rangePosition !== 'end') { onRangePositionChange('end'); } - onViewChange(newView); + setView(newView); }; return { value: value[1], setValue: wrappedSetValue, forceDesktopVariant: true, - onViewChange: handleEndRangeViewChange, + setView: handleEndRangeViewChange, view: rangePosition === 'end' ? view : null, }; - }, [value, wrappedSetValue, rangePosition, view, onRangePositionChange, onViewChange]); + }, [value, wrappedSetValue, rangePosition, view, onRangePositionChange, setView]); if (hidden) { return null; diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx index beaaefb36f02f..c69f02d3fdd50 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx @@ -182,7 +182,6 @@ export const useDesktopRangePicker = < ? providerProps.contextValue.view : undefined, initialView: initialView.current ?? undefined, - onViewChange: providerProps.contextValue.onViewChange, ...rangePositionResponse, }); diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts b/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts index a4f1ab1bfd620..a333f91a68266 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts @@ -111,7 +111,7 @@ export interface UseEnrichedRangePickerFieldPropsParams< anchorRef?: React.Ref; currentView?: TView | null; initialView?: TView; - onViewChange?: (view: TView) => void; + setView?: (view: TView) => void; startFieldRef: React.RefObject | null>; endFieldRef: React.RefObject | null>; singleInputFieldRef: React.RefObject | null>; @@ -138,7 +138,7 @@ const useMultiInputFieldSlotProps = < anchorRef, currentView, initialView, - onViewChange, + setView, startFieldRef, endFieldRef, }: UseEnrichedRangePickerFieldPropsParams< @@ -198,7 +198,7 @@ const useMultiInputFieldSlotProps = < if (open) { onRangePositionChange('start'); if (previousRangePosition.current !== 'start' && initialView) { - onViewChange?.(initialView); + setView?.(initialView); } } }; @@ -207,7 +207,7 @@ const useMultiInputFieldSlotProps = < if (open) { onRangePositionChange('end'); if (previousRangePosition.current !== 'end' && initialView) { - onViewChange?.(initialView); + setView?.(initialView); } } }; diff --git a/packages/x-date-pickers/src/DateTimePicker/DateTimePickerTabs.tsx b/packages/x-date-pickers/src/DateTimePicker/DateTimePickerTabs.tsx index 2ae198b28f762..295d6097c6643 100644 --- a/packages/x-date-pickers/src/DateTimePicker/DateTimePickerTabs.tsx +++ b/packages/x-date-pickers/src/DateTimePicker/DateTimePickerTabs.tsx @@ -105,11 +105,11 @@ const DateTimePickerTabs = function DateTimePickerTabs(inProps: DateTimePickerTa const translations = usePickerTranslations(); const { ownerState } = usePickerPrivateContext(); - const { view, onViewChange } = usePickerContext(); + const { view, setView } = usePickerContext(); const classes = useUtilityClasses(classesProp); const handleChange = (event: React.SyntheticEvent, value: TabValue) => { - onViewChange(tabToView(value)); + setView(tabToView(value)); }; if (hidden) { diff --git a/packages/x-date-pickers/src/DateTimePicker/DateTimePickerToolbar.tsx b/packages/x-date-pickers/src/DateTimePicker/DateTimePickerToolbar.tsx index 0e45cc3584278..28ce3c21b7d12 100644 --- a/packages/x-date-pickers/src/DateTimePicker/DateTimePickerToolbar.tsx +++ b/packages/x-date-pickers/src/DateTimePicker/DateTimePickerToolbar.tsx @@ -243,7 +243,7 @@ export const DateTimePickerToolbarOverrideContext = React.createContext<{ value: PickerValue; setValue: (value: PickerValue, options?: SetValueActionOptions) => void; forceDesktopVariant: boolean; - onViewChange: (view: DateOrTimeViewWithMeridiem) => void; + setView: (view: DateOrTimeViewWithMeridiem) => void; view: DateOrTimeViewWithMeridiem | null; } | null>(null); @@ -278,7 +278,7 @@ function DateTimePickerToolbar(inProps: DateTimePickerToolbarProps) { variant, orientation, view: viewContext, - onViewChange: onViewChangeContext, + setView: setViewContext, views, } = usePickerContext(); @@ -291,7 +291,7 @@ function DateTimePickerToolbar(inProps: DateTimePickerToolbarProps) { const value = overrides ? overrides.value : valueContext; const setValue = overrides ? overrides.setValue : setValueContext; const view = overrides ? overrides.view : viewContext; - const onViewChange = overrides ? overrides.onViewChange : onViewChangeContext; + const setView = overrides ? overrides.setView : setViewContext; const { meridiemMode, handleMeridiemChange } = useMeridiemMode(value, ampm, (newValue) => setValue(newValue, { changeImportance: 'set' }), @@ -336,7 +336,7 @@ function DateTimePickerToolbar(inProps: DateTimePickerToolbarProps) { tabIndex={-1} variant="subtitle1" data-testid="datetimepicker-toolbar-year" - onClick={() => onViewChange('year')} + onClick={() => setView('year')} selected={view === 'year'} value={formatSection('year', '–')} /> @@ -347,7 +347,7 @@ function DateTimePickerToolbar(inProps: DateTimePickerToolbarProps) { tabIndex={-1} variant={isDesktop ? 'h5' : 'h4'} data-testid="datetimepicker-toolbar-day" - onClick={() => onViewChange('day')} + onClick={() => setView('day')} selected={view === 'day'} value={dateText} /> @@ -373,7 +373,7 @@ function DateTimePickerToolbar(inProps: DateTimePickerToolbarProps) { : undefined } data-testid="hours" - onClick={() => onViewChange('hours')} + onClick={() => setView('hours')} selected={view === 'hours'} value={formatSection(ampm ? 'hours12h' : 'hours24h', '--')} /> @@ -392,7 +392,7 @@ function DateTimePickerToolbar(inProps: DateTimePickerToolbarProps) { : undefined } data-testid="minutes" - onClick={() => onViewChange('minutes')} + onClick={() => setView('minutes')} selected={view === 'minutes' || (!views.includes('minutes') && view === 'hours')} value={formatSection('minutes', '--')} disabled={!views.includes('minutes')} @@ -417,7 +417,7 @@ function DateTimePickerToolbar(inProps: DateTimePickerToolbarProps) { : undefined } data-testid="seconds" - onClick={() => onViewChange('seconds')} + onClick={() => setView('seconds')} selected={view === 'seconds'} value={formatSection('seconds', '--')} /> @@ -452,7 +452,7 @@ function DateTimePickerToolbar(inProps: DateTimePickerToolbarProps) { onViewChange('meridiem')} + onClick={() => setView('meridiem')} selected={view === 'meridiem'} value={value && meridiemMode ? formatMeridiem(utils, meridiemMode) : '--'} width={MULTI_SECTION_CLOCK_SECTION_WIDTH} diff --git a/packages/x-date-pickers/src/PickersActionBar/PickersActionBar.test.tsx b/packages/x-date-pickers/src/PickersActionBar/PickersActionBar.test.tsx index 4c95cce547de9..d7ed44402e6aa 100644 --- a/packages/x-date-pickers/src/PickersActionBar/PickersActionBar.test.tsx +++ b/packages/x-date-pickers/src/PickersActionBar/PickersActionBar.test.tsx @@ -12,6 +12,7 @@ describe('', () => { const renderWithContext = (element: React.ReactElement) => { const spys = { setValue: spy(), + setView: spy(), setOpen: spy(), clearValue: spy(), setValueToToday: spy(), diff --git a/packages/x-date-pickers/src/TimePicker/TimePickerToolbar.tsx b/packages/x-date-pickers/src/TimePicker/TimePickerToolbar.tsx index 04a7ad695b7aa..7cecf4d09e3ab 100644 --- a/packages/x-date-pickers/src/TimePicker/TimePickerToolbar.tsx +++ b/packages/x-date-pickers/src/TimePicker/TimePickerToolbar.tsx @@ -157,7 +157,7 @@ function TimePickerToolbar(inProps: TimePickerToolbarProps) { const translations = usePickerTranslations(); const ownerState = useToolbarOwnerState(); const classes = useUtilityClasses(classesProp, ownerState); - const { value, setValue, disabled, readOnly, view, onViewChange, views } = usePickerContext< + const { value, setValue, disabled, readOnly, view, setView, views } = usePickerContext< PickerValue, TimeViewWithMeridiem >(); @@ -199,7 +199,7 @@ function TimePickerToolbar(inProps: TimePickerToolbarProps) { data-testid="hours" tabIndex={-1} variant="h3" - onClick={() => onViewChange('hours')} + onClick={() => setView('hours')} selected={view === 'hours'} value={formatSection(ampm ? 'hours12h' : 'hours24h')} /> @@ -211,7 +211,7 @@ function TimePickerToolbar(inProps: TimePickerToolbarProps) { data-testid="minutes" tabIndex={-1} variant="h3" - onClick={() => onViewChange('minutes')} + onClick={() => setView('minutes')} selected={view === 'minutes'} value={formatSection('minutes')} /> @@ -222,7 +222,7 @@ function TimePickerToolbar(inProps: TimePickerToolbarProps) { onViewChange('seconds')} + onClick={() => setView('seconds')} selected={view === 'seconds'} value={formatSection('seconds')} /> diff --git a/packages/x-date-pickers/src/hooks/usePickerActionsContext.ts b/packages/x-date-pickers/src/hooks/usePickerActionsContext.ts index 50d1155790b9a..546ef7da1b1e8 100644 --- a/packages/x-date-pickers/src/hooks/usePickerActionsContext.ts +++ b/packages/x-date-pickers/src/hooks/usePickerActionsContext.ts @@ -4,7 +4,7 @@ import { PickerActionsContext, PickerActionsContextValue, } from '../internals/components/PickerProvider'; -import { PickerValidValue, PickerValue } from '../internals/models'; +import { DateOrTimeViewWithMeridiem, PickerValidValue, PickerValue } from '../internals/models'; /** * Returns a subset of the context passed by the picker wrapping the current component. @@ -12,10 +12,12 @@ import { PickerValidValue, PickerValue } from '../internals/models'; */ export const usePickerActionsContext = < TValue extends PickerValidValue = PickerValue, + TView extends DateOrTimeViewWithMeridiem = DateOrTimeViewWithMeridiem, TError = string, >() => { const value = React.useContext(PickerActionsContext) as PickerActionsContextValue< TValue, + TView, TError > | null; if (value == null) { diff --git a/packages/x-date-pickers/src/internals/components/PickerProvider.tsx b/packages/x-date-pickers/src/internals/components/PickerProvider.tsx index e3642b186fdb6..8baf47d8a8662 100644 --- a/packages/x-date-pickers/src/internals/components/PickerProvider.tsx +++ b/packages/x-date-pickers/src/internals/components/PickerProvider.tsx @@ -13,14 +13,19 @@ import type { UsePickerValueContextValue, UsePickerValuePrivateContextValue, } from '../hooks/usePicker/usePickerValue.types'; -import { UsePickerViewsContextValue } from '../hooks/usePicker/usePickerViews'; +import { + UsePickerViewsActionsContextValue, + UsePickerViewsContextValue, +} from '../hooks/usePicker/usePickerViews'; import { IsValidValueContext } from '../../hooks/useIsValidValue'; export const PickerContext = React.createContext | null>(null); -export const PickerActionsContext = React.createContext | null>( - null, -); +export const PickerActionsContext = React.createContext | null>(null); export const PickerPrivateContext = React.createContext({ ownerState: { @@ -68,7 +73,7 @@ export function PickerProvider( export interface PickerProviderProps { contextValue: PickerContextValue; - actionsContextValue: PickerActionsContextValue; + actionsContextValue: PickerActionsContextValue; privateContextValue: PickerPrivateContextValue; isValidContextValue: (value: TValue) => boolean; localeText: PickersInputLocaleText | undefined; @@ -108,8 +113,12 @@ export interface PickerContextValue< orientation: PickerOrientation; } -export interface PickerActionsContextValue - extends UsePickerValueActionsContextValue {} +export interface PickerActionsContextValue< + TValue extends PickerValidValue, + TView extends DateOrTimeViewWithMeridiem, + TError = string, +> extends UsePickerValueActionsContextValue, + UsePickerViewsActionsContextValue {} export interface PickerPrivateContextValue extends UsePickerValuePrivateContextValue { /** diff --git a/packages/x-date-pickers/src/internals/hooks/useOpenState.ts b/packages/x-date-pickers/src/internals/hooks/useOpenState.ts index 93c9d7f733bcc..c698f9f208f72 100644 --- a/packages/x-date-pickers/src/internals/hooks/useOpenState.ts +++ b/packages/x-date-pickers/src/internals/hooks/useOpenState.ts @@ -1,4 +1,5 @@ import * as React from 'react'; +import useEventCallback from '@mui/utils/useEventCallback'; export interface OpenStateProps { open?: boolean; @@ -22,23 +23,20 @@ export const useOpenState = ({ open, onOpen, onClose }: OpenStateProps) => { } }, [isControllingOpenProp, open]); - const setOpen = React.useCallback( - (action: React.SetStateAction) => { - const newOpen = typeof action === 'function' ? action(openState) : action; - if (!isControllingOpenProp) { - setOpenState(newOpen); - } + const setOpen = useEventCallback((action: React.SetStateAction) => { + const newOpen = typeof action === 'function' ? action(openState) : action; + if (!isControllingOpenProp) { + setOpenState(newOpen); + } - if (newOpen && onOpen) { - onOpen(); - } + if (newOpen && onOpen) { + onOpen(); + } - if (!newOpen && onClose) { - onClose(); - } - }, - [isControllingOpenProp, onOpen, onClose, openState], - ); + if (!newOpen && onClose) { + onClose(); + } + }); return { open: openState, setOpen }; }; diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerProvider.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerProvider.ts index f907c589f527a..87845afcd6ef6 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerProvider.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerProvider.ts @@ -128,11 +128,19 @@ export function usePickerProvider< [paramsFromUsePickerValue, ownerState], ); + const actionsContextValue = React.useMemo( + () => ({ + ...paramsFromUsePickerValue.actionsContextValue, + ...paramsFromUsePickerViews.actionsContextValue, + }), + [paramsFromUsePickerValue.actionsContextValue, paramsFromUsePickerViews.actionsContextValue], + ); + return { localeText, contextValue, privateContextValue, - actionsContextValue: paramsFromUsePickerValue.actionsContextValue, + actionsContextValue, isValidContextValue: paramsFromUsePickerValue.isValidContextValue, }; } diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerViews.tsx b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerViews.tsx index 93dc3c32399ce..f8769c0109b27 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerViews.tsx +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerViews.tsx @@ -118,7 +118,17 @@ export interface UsePickerViewsResponse; } -export interface UsePickerViewsContextValue { +export interface UsePickerViewsActionsContextValue { + /** + * Set the current view. + * @template TView + * @param {TView} view The view to render + */ + setView: (view: TView) => void; +} + +export interface UsePickerViewsContextValue + extends UsePickerViewsActionsContextValue { /** * Available views. */ @@ -127,18 +137,13 @@ export interface UsePickerViewsContextValue void; } export interface UsePickerViewsProviderParams { hasUIView: boolean; views: readonly TView[]; contextValue: UsePickerViewsContextValue; + actionsContextValue: UsePickerViewsActionsContextValue; } /** @@ -256,19 +261,25 @@ export const usePickerViews = < setFocusedView(newView, true); }, [open]); // eslint-disable-line react-hooks/exhaustive-deps + const actionsContextValue = React.useMemo>( + () => ({ setView }), + [setView], + ); + const contextValue = React.useMemo>( () => ({ + ...actionsContextValue, views, view: popperView, - onViewChange: setView, }), - [views, popperView, setView], + [actionsContextValue, views, popperView], ); const providerParams: UsePickerViewsProviderParams = { hasUIView, views, contextValue, + actionsContextValue, }; return { From 0a7ba218d36174449ab5c057c72e1cdfd9ae16de Mon Sep 17 00:00:00 2001 From: Flavien DELANGLE Date: Tue, 7 Jan 2025 14:56:09 +0100 Subject: [PATCH 17/25] [pickers] Always use `setValue` internally to update the picker value (#16056) --- .../hooks/usePicker/usePickerValue.ts | 261 +++++------------- .../hooks/usePicker/usePickerValue.types.ts | 39 +-- 2 files changed, 73 insertions(+), 227 deletions(-) diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts index b6a0f8e911f08..a084d22df648c 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts @@ -8,12 +8,10 @@ import { UsePickerValueProps, UsePickerValueParams, UsePickerValueResponse, - PickerValueUpdateAction, UsePickerValueState, UsePickerValueFieldResponse, UsePickerValueViewsResponse, PickerSelectionState, - PickerValueUpdaterParams, UsePickerValueContextValue, UsePickerValueProviderParams, UsePickerValueActionsContextValue, @@ -23,118 +21,6 @@ import { import { useValueWithTimezone } from '../useValueWithTimezone'; import { PickerValidValue } from '../../models'; -/** - * Decide if the new value should be published - * The published value will be passed to `onChange` if defined. - */ -const shouldPublishValue = ( - params: PickerValueUpdaterParams, -): boolean => { - const { action, hasChanged, dateState, isControlled } = params; - - const isCurrentValueTheDefaultValue = !isControlled && !dateState.hasBeenModifiedSinceMount; - - if (action.name === 'setValueFromAction') { - // If the component is not controlled, and the value has not been modified since the mount, - // Then we want to publish the default value whenever the user pressed the "Accept", "Today" or "Clear" button. - if ( - isCurrentValueTheDefaultValue && - ['accept', 'today', 'clear'].includes(action.pickerAction) - ) { - return true; - } - - return hasChanged(dateState.lastPublishedValue); - } - - if (action.name === 'setValueFromView' && action.selectionState !== 'shallow') { - // On the first view, - // If the value is not controlled, then clicking on any value (including the one equal to `defaultValue`) should call `onChange` - if (isCurrentValueTheDefaultValue) { - return true; - } - - return hasChanged(dateState.lastPublishedValue); - } - - if (action.name === 'setExplicitValue') { - // On the first view, - // If the value is not controlled, then clicking on any value (including the one equal to `defaultValue`) should call `onChange` - if (isCurrentValueTheDefaultValue) { - return true; - } - - return hasChanged(dateState.lastPublishedValue); - } - - return false; -}; - -/** - * Decide if the new value should be committed. - * The committed value will be passed to `onAccept` if defined. - * It will also be used as a reset target when calling the `cancel` picker action (when clicking on the "Cancel" button). - */ -const shouldCommitValue = ( - params: PickerValueUpdaterParams, -): boolean => { - const { action, hasChanged, dateState, isControlled, closeOnSelect } = params; - - const isCurrentValueTheDefaultValue = !isControlled && !dateState.hasBeenModifiedSinceMount; - - if (action.name === 'setValueFromAction') { - // If the component is not controlled, and the value has not been modified since the mount, - // Then we want to commit the default value whenever the user pressed the "Accept", "Today" or "Clear" button. - if ( - isCurrentValueTheDefaultValue && - ['accept', 'today', 'clear'].includes(action.pickerAction) - ) { - return true; - } - - return hasChanged(dateState.lastCommittedValue); - } - - if (action.name === 'setValueFromView' && action.selectionState === 'finish' && closeOnSelect) { - // On picker where the 1st view is also the last view, - // If the value is not controlled, then clicking on any value (including the one equal to `defaultValue`) should call `onAccept` - if (isCurrentValueTheDefaultValue) { - return true; - } - - return hasChanged(dateState.lastCommittedValue); - } - - if (action.name === 'setExplicitValue') { - return action.options.changeImportance === 'accept' && hasChanged(dateState.lastCommittedValue); - } - - return false; -}; - -/** - * Decide if the picker should be closed after the value is updated. - */ -const shouldClosePicker = ( - params: PickerValueUpdaterParams, -): boolean => { - const { action, closeOnSelect } = params; - - if (action.name === 'setValueFromAction') { - return true; - } - - if (action.name === 'setValueFromView') { - return action.selectionState === 'finish' && closeOnSelect; - } - - if (action.name === 'setExplicitValue') { - return action.options.changeImportance === 'accept'; - } - - return false; -}; - /** * Manage the value lifecycle of all the pickers. */ @@ -254,43 +140,46 @@ export const usePickerValue = < onError: props.onError, }); - const updateDate = useEventCallback((action: PickerValueUpdateAction) => { - const updaterParams: PickerValueUpdaterParams = { - action, - dateState, - hasChanged: (comparison) => !valueManager.areValuesEqual(utils, action.value, comparison), - isControlled, - closeOnSelect, - }; - - const shouldPublish = shouldPublishValue(updaterParams); - const shouldCommit = shouldCommitValue(updaterParams); - const shouldClose = shouldClosePicker(updaterParams); + const setValue = useEventCallback((newValue: TValue, options?: SetValueActionOptions) => { + const { + changeImportance = 'accept', + skipPublicationIfPristine = false, + validationError, + shortcut, + } = options ?? {}; + + let shouldPublish: boolean; + let shouldCommit: boolean; + if (!skipPublicationIfPristine && !isControlled && !dateState.hasBeenModifiedSinceMount) { + // If the value is not controlled and the value has never been modified before, + // Then clicking on any value (including the one equal to `defaultValue`) should call `onChange` and `onAccept` + shouldPublish = true; + shouldCommit = changeImportance === 'accept'; + } else { + shouldPublish = !valueManager.areValuesEqual(utils, newValue, dateState.lastPublishedValue); + shouldCommit = + changeImportance === 'accept' && + !valueManager.areValuesEqual(utils, newValue, dateState.lastCommittedValue); + } setDateState((prev) => ({ ...prev, - draft: action.value, - lastPublishedValue: shouldPublish ? action.value : prev.lastPublishedValue, - lastCommittedValue: shouldCommit ? action.value : prev.lastCommittedValue, + draft: newValue, + lastPublishedValue: shouldPublish ? newValue : prev.lastPublishedValue, + lastCommittedValue: shouldCommit ? newValue : prev.lastCommittedValue, hasBeenModifiedSinceMount: true, })); let cachedContext: PickerChangeHandlerContext | null = null; const getContext = (): PickerChangeHandlerContext => { if (!cachedContext) { - const validationError = - action.name === 'setExplicitValue' && action.options.validationError != null - ? action.options.validationError - : getValidationErrorForNewValue(action.value); - cachedContext = { - validationError, + validationError: + validationError == null ? getValidationErrorForNewValue(newValue) : validationError, }; - if (action.name === 'setExplicitValue') { - if (action.options.shortcut) { - cachedContext.shortcut = action.options.shortcut; - } + if (shortcut) { + cachedContext.shortcut = shortcut; } } @@ -298,14 +187,14 @@ export const usePickerValue = < }; if (shouldPublish) { - handleValueChange(action.value, getContext()); + handleValueChange(newValue, getContext()); } if (shouldCommit && onAccept) { - onAccept(action.value, getContext()); + onAccept(newValue, getContext()); } - if (shouldClose) { + if (changeImportance === 'accept') { setOpen(false); } }); @@ -331,23 +220,6 @@ export const usePickerValue = < })); } - const handleChange = useEventCallback( - (newValue: TValue, selectionState: PickerSelectionState = 'partial') => - updateDate({ name: 'setValueFromView', value: newValue, selectionState }), - ); - - const valueWithoutError = React.useMemo( - () => valueManager.cleanValue(utils, dateState.draft), - [utils, valueManager, dateState.draft], - ); - - const viewResponse: UsePickerValueViewsResponse = { - value: valueWithoutError, - onChange: handleChange, - open, - setOpen, - }; - const isValid = (testedValue: TValue) => { const error = validator({ adapter, @@ -359,51 +231,21 @@ export const usePickerValue = < return !valueManager.hasError(error); }; - const setValue = useEventCallback((newValue: TValue, options?: SetValueActionOptions) => - updateDate({ - name: 'setExplicitValue', - value: newValue, - options: { changeImportance: 'accept', ...options }, - }), - ); - - const clearValue = useEventCallback(() => - updateDate({ - value: valueManager.emptyValue, - name: 'setValueFromAction', - pickerAction: 'clear', - }), - ); + const clearValue = useEventCallback(() => setValue(valueManager.emptyValue)); const setValueToToday = useEventCallback(() => - updateDate({ - value: valueManager.getTodayValue(utils, timezone, valueType), - name: 'setValueFromAction', - pickerAction: 'today', - }), + setValue(valueManager.getTodayValue(utils, timezone, valueType)), ); - const acceptValueChanges = useEventCallback(() => - updateDate({ - value: dateState.lastPublishedValue, - name: 'setValueFromAction', - pickerAction: 'accept', - }), - ); + const acceptValueChanges = useEventCallback(() => setValue(dateState.lastPublishedValue)); const cancelValueChanges = useEventCallback(() => - updateDate({ - value: dateState.lastCommittedValue, - name: 'setValueFromAction', - pickerAction: 'cancel', - }), + setValue(dateState.lastCommittedValue, { skipPublicationIfPristine: true }), ); const dismissViews = useEventCallback(() => { - updateDate({ - value: dateState.lastPublishedValue, - name: 'setValueFromAction', - pickerAction: 'dismiss', + setValue(dateState.lastPublishedValue, { + skipPublicationIfPristine: true, }); }); @@ -413,6 +255,35 @@ export const usePickerValue = < setValue(newValue, { validationError: context.validationError }), }; + const setValueFromView = useEventCallback( + (newValue: TValue, selectionState: PickerSelectionState = 'partial') => { + // TODO: Expose a new method (private?) like `setView` that only updates the draft value. + if (selectionState === 'shallow') { + setDateState((prev) => ({ + ...prev, + draft: newValue, + hasBeenModifiedSinceMount: true, + })); + } + + setValue(newValue, { + changeImportance: selectionState === 'finish' && closeOnSelect ? 'accept' : 'set', + }); + }, + ); + + const valueWithoutError = React.useMemo( + () => valueManager.cleanValue(utils, dateState.draft), + [utils, valueManager, dateState.draft], + ); + + const viewResponse: UsePickerValueViewsResponse = { + value: valueWithoutError, + onChange: setValueFromView, + open, + setOpen, + }; + const actionsContextValue = React.useMemo>( () => ({ setValue, diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts index 67a067c68f66c..f915a8171a89e 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts @@ -1,5 +1,4 @@ import * as React from 'react'; -import { MakeRequired } from '@mui/x-internals/types'; import { UseFieldInternalProps } from '../useField'; import { Validator } from '../../../validation'; import { @@ -155,37 +154,6 @@ export interface UsePickerValueState { hasBeenModifiedSinceMount: boolean; } -export interface PickerValueUpdaterParams { - action: PickerValueUpdateAction; - dateState: UsePickerValueState; - /** - * Check if the new draft value has changed compared to some given value. - * @template TValue The value type. It will be the same type as `value` or `null`. It can be in `[start, end]` format in case of range value. - * @param {TValue} comparisonValue The value to compare the new draft value with. - * @returns {boolean} `true` if the new draft value is equal to the comparison value. - */ - hasChanged: (comparisonValue: TValue) => boolean; - isControlled: boolean; - closeOnSelect: boolean; -} - -export type PickerValueUpdateAction = - | { - name: 'setValueFromView'; - value: TValue; - selectionState: PickerSelectionState; - } - | { - name: 'setValueFromAction'; - value: TValue; - pickerAction: 'accept' | 'today' | 'cancel' | 'dismiss' | 'clear'; - } - | { - name: 'setExplicitValue'; - value: TValue; - options: MakeRequired, 'changeImportance'>; - }; - /** * Props used to handle the value that are common to all pickers. */ @@ -376,4 +344,11 @@ export interface SetValueActionOptions { * Should not be defined if the change does not come from a shortcut. */ shortcut?: PickersShortcutsItemContext; + /** + * Decide if the value should call `onChange` and `onAccept` when the value is not controlled and has never been modified. + * If `true`, the `onChange` and `onAccept` callback will only be fired if the value has been modified (and is not equal to the last published value). + * If `false`, the `onChange` and `onAccept` callback will be fired when the value has never been modified (`onAccept` only if `changeImportance` is set to "accept"). + * @default false + */ + skipPublicationIfPristine?: boolean; } From f1332f17c2573230821c1c88f2f79cc31000f5aa Mon Sep 17 00:00:00 2001 From: Lukas Tyla Date: Tue, 7 Jan 2025 16:45:26 +0200 Subject: [PATCH 18/25] [pickers] Rename `AdapterDateFns` into `AdapterDateFnsV2` and `AdapterDateFnsV3` into `AdapterDateFns` (#16082) Signed-off-by: Lukas Tyla Co-authored-by: Michel Engelen <32863416+michelengelen@users.noreply.github.com> --- babel.config.js | 12 +- .../custom-columns/EditingWithDatePickers.js | 2 +- .../custom-columns/EditingWithDatePickers.tsx | 2 +- .../adapters-locale/adapters-locale.md | 14 +-- .../calendar-systems/calendar-systems.md | 8 +- .../migration-pickers-v7.md | 32 +++++- docs/package.json | 4 +- .../PickersRenderingInstructions.js | 8 +- package.json | 4 +- packages/x-codemod/README.md | 51 +++++++-- .../src/v8.0.0/pickers/preset-safe/index.ts | 2 + .../actual-community-import.spec.tsx | 5 + .../actual-pro-import.spec.tsx | 5 + .../expected-community-import.spec.tsx | 4 + .../expected-pro-import.spec.tsx | 4 + .../rename-adapter-date-fns-imports/index.ts | 49 ++++++++ .../rename-adapter-date-fns-imports.test.ts | 33 ++++++ packages/x-data-grid-premium/package.json | 2 +- .../tests/license.DataGridPremium.test.tsx | 2 +- packages/x-date-pickers-pro/package.json | 4 +- .../index.ts | 2 +- .../index.ts | 2 +- packages/x-date-pickers/package.json | 4 +- .../src/AdapterDateFns/AdapterDateFns.ts | 103 ++++++++--------- .../AdapterDateFnsBase/AdapterDateFnsBase.ts | 2 +- .../AdapterDateFnsJalali.test.tsx | 9 +- .../AdapterDateFnsJalali.ts | 101 +++++++++-------- .../AdapterDateFnsJalaliV2.test.tsx} | 4 +- .../AdapterDateFnsJalaliV2.ts} | 102 ++++++++--------- .../src/AdapterDateFnsJalaliV2/index.ts | 1 + .../src/AdapterDateFnsJalaliV3/index.ts | 1 - .../AdapterDateFnsV2.test.tsx} | 4 +- .../AdapterDateFnsV2.ts} | 105 ++++++++---------- .../src/AdapterDateFnsV2/index.ts | 1 + .../src/AdapterDateFnsV3/index.ts | 1 - pnpm-lock.yaml | 40 +++---- test/utils/pickers/createPickerRenderer.tsx | 2 +- 37 files changed, 436 insertions(+), 295 deletions(-) create mode 100644 packages/x-codemod/src/v8.0.0/pickers/rename-adapter-date-fns-imports/actual-community-import.spec.tsx create mode 100644 packages/x-codemod/src/v8.0.0/pickers/rename-adapter-date-fns-imports/actual-pro-import.spec.tsx create mode 100644 packages/x-codemod/src/v8.0.0/pickers/rename-adapter-date-fns-imports/expected-community-import.spec.tsx create mode 100644 packages/x-codemod/src/v8.0.0/pickers/rename-adapter-date-fns-imports/expected-pro-import.spec.tsx create mode 100644 packages/x-codemod/src/v8.0.0/pickers/rename-adapter-date-fns-imports/index.ts create mode 100644 packages/x-codemod/src/v8.0.0/pickers/rename-adapter-date-fns-imports/rename-adapter-date-fns-imports.test.ts rename packages/x-date-pickers-pro/src/{AdapterDateFnsJalaliV3 => AdapterDateFnsJalaliV2}/index.ts (77%) rename packages/x-date-pickers-pro/src/{AdapterDateFnsV3 => AdapterDateFnsV2}/index.ts (90%) rename packages/x-date-pickers/src/{AdapterDateFnsJalaliV3/AdapterDateFnsJalaliV3.test.tsx => AdapterDateFnsJalaliV2/AdapterDateFnsJalaliV2.test.tsx} (97%) rename packages/x-date-pickers/src/{AdapterDateFnsJalaliV3/AdapterDateFnsJalaliV3.ts => AdapterDateFnsJalaliV2/AdapterDateFnsJalaliV2.ts} (74%) create mode 100644 packages/x-date-pickers/src/AdapterDateFnsJalaliV2/index.ts delete mode 100644 packages/x-date-pickers/src/AdapterDateFnsJalaliV3/index.ts rename packages/x-date-pickers/src/{AdapterDateFnsV3/AdapterDateFnsV3.test.tsx => AdapterDateFnsV2/AdapterDateFnsV2.test.tsx} (87%) rename packages/x-date-pickers/src/{AdapterDateFnsV3/AdapterDateFnsV3.ts => AdapterDateFnsV2/AdapterDateFnsV2.ts} (73%) create mode 100644 packages/x-date-pickers/src/AdapterDateFnsV2/index.ts delete mode 100644 packages/x-date-pickers/src/AdapterDateFnsV3/index.ts diff --git a/babel.config.js b/babel.config.js index 548219255b525..c4f9bc38c963e 100644 --- a/babel.config.js +++ b/babel.config.js @@ -100,25 +100,23 @@ module.exports = function getBabelConfig(api) { if (process.env.NODE_ENV === 'test') { plugins.push(['@babel/plugin-transform-export-namespace-from']); - // We replace `date-fns` imports with an aliased `date-fns@v4` version installed as `date-fns-v4` for tests. - // The plugin is patched to only run on `AdapterDateFnsV3.ts`. - // TODO: remove when we upgrade to date-fns v4 by default. + // We replace `date-fns` imports with an aliased `date-fns@v2` version installed as `date-fns-v2` for tests. plugins.push([ 'babel-plugin-replace-imports', { test: /date-fns/i, - replacer: 'date-fns-v4', + replacer: 'date-fns-v2', // This option is provided by the `patches/babel-plugin-replace-imports@1.0.2.patch` patch - filenameIncludes: 'src/AdapterDateFnsV3/', + filenameIncludes: 'src/AdapterDateFnsV2/', }, ]); plugins.push([ 'babel-plugin-replace-imports', { test: /date-fns-jalali/i, - replacer: 'date-fns-jalali-v4', + replacer: 'date-fns-jalali-v2', // This option is provided by the `patches/babel-plugin-replace-imports@1.0.2.patch` patch - filenameIncludes: 'src/AdapterDateFnsJalaliV3/', + filenameIncludes: 'src/AdapterDateFnsJalaliV2/', }, 'replace-date-fns-jalali-imports', ]); diff --git a/docs/data/data-grid/custom-columns/EditingWithDatePickers.js b/docs/data/data-grid/custom-columns/EditingWithDatePickers.js index 8384fbb1d03d9..14da0d2c568ef 100644 --- a/docs/data/data-grid/custom-columns/EditingWithDatePickers.js +++ b/docs/data/data-grid/custom-columns/EditingWithDatePickers.js @@ -16,7 +16,7 @@ import { DatePicker } from '@mui/x-date-pickers/DatePicker'; import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker'; import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; import { enUS as locale } from 'date-fns/locale'; -import format from 'date-fns/format'; +import { format } from 'date-fns/format'; import { unstable_useEnhancedEffect as useEnhancedEffect } from '@mui/utils'; /** * `date` column diff --git a/docs/data/data-grid/custom-columns/EditingWithDatePickers.tsx b/docs/data/data-grid/custom-columns/EditingWithDatePickers.tsx index ff26d3a5a238c..12505f43ca9ea 100644 --- a/docs/data/data-grid/custom-columns/EditingWithDatePickers.tsx +++ b/docs/data/data-grid/custom-columns/EditingWithDatePickers.tsx @@ -21,7 +21,7 @@ import { DatePicker } from '@mui/x-date-pickers/DatePicker'; import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker'; import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; import { enUS as locale } from 'date-fns/locale'; -import format from 'date-fns/format'; +import { format } from 'date-fns/format'; import { unstable_useEnhancedEffect as useEnhancedEffect } from '@mui/utils'; /** * `date` column diff --git a/docs/data/date-pickers/adapters-locale/adapters-locale.md b/docs/data/date-pickers/adapters-locale/adapters-locale.md index 524ffb3df60c5..1bd9784e16292 100644 --- a/docs/data/date-pickers/adapters-locale/adapters-locale.md +++ b/docs/data/date-pickers/adapters-locale/adapters-locale.md @@ -45,18 +45,18 @@ We support `date-fns` package v2.x, v3.x, and v4.x major versions. A single adapter cannot work for all `date-fns` versions, because the way functions are exported has been changed in v3.x. -To use `date-fns` v3.x or v4.x, you need to import the adapter from `@mui/x-date-pickers/AdapterDateFnsV3` instead of `@mui/x-date-pickers/AdapterDateFns`. +To use `date-fns` v2.x, you need to import the adapter from `@mui/x-date-pickers/AdapterDateFnsV2` instead of `@mui/x-date-pickers/AdapterDateFns`. ::: ```tsx -// with date-fns v2.x -import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; // with date-fns v3.x or v4.x -import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFnsV3'; +import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; // with date-fns v2.x -import de from 'date-fns/locale/de'; +import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFnsV2'; // with date-fns v3.x or v4.x import { de } from 'date-fns/locale/de'; +// with date-fns v2.x +import de from 'date-fns/locale/de'; {children} @@ -303,10 +303,10 @@ For `date-fns`, override the `options.weekStartsOn` of the used locale: ```ts import { Locale } from 'date-fns'; +// with date-fns v3.x or v4.x +import { enUS } from 'date-fns/locale/en-US'; // with date-fns v2.x import enUS from 'date-fns/locale/en-US'; -// with date-fns v3.x -import { enUS } from 'date-fns/locale/en-US'; const customEnLocale: Locale = { ...enUS, diff --git a/docs/data/date-pickers/calendar-systems/calendar-systems.md b/docs/data/date-pickers/calendar-systems/calendar-systems.md index b2955aa95722b..7ae8b6d3f7f51 100644 --- a/docs/data/date-pickers/calendar-systems/calendar-systems.md +++ b/docs/data/date-pickers/calendar-systems/calendar-systems.md @@ -24,13 +24,13 @@ We support `date-fns-jalali` package v2.x, v3.x, and v4.x major versions. A single adapter cannot work for all `date-fns-jalali` versions, because the way functions are exported has been changed in v3.x. -To use `date-fns-jalali` v3.x or v4.x, you will have to import the adapter from `@mui/x-date-pickers/AdapterDateFnsJalaliV3` instead of `@mui/x-date-pickers/AdapterDateFnsJalali`. +To use `date-fns-jalali` v2.x, you need to import the adapter from `@mui/x-date-pickers/AdapterDateFnsJalaliV2` instead of `@mui/x-date-pickers/AdapterDateFnsJalali`. ```tsx -// with date-fns-jalali v2.x -import { AdapterDateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalali'; // with date-fns-jalali v3.x or v4.x -import { AdapterDateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalaliV3'; +import { AdapterDateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalali'; +// with date-fns-jalali v2.x +import { AdapterDateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalaliV2'; ``` ::: diff --git a/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md b/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md index f4ea6934fdcbb..e298abf79a036 100644 --- a/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md +++ b/docs/data/migration/migration-pickers-v7/migration-pickers-v7.md @@ -742,7 +742,7 @@ The following variables and types have been renamed to have a coherent `Picker` +const pickerContext = usePickerContext(); ``` -- `FieldValueType` +- ✅ `FieldValueType` ```diff -import { FieldValueType } from '@mui/x-date-pickers/models'; @@ -1131,6 +1131,36 @@ If you were using them, you need to replace them with the following code: + extends BaseMultiInputPickersTextFieldProps {} ``` +## ✅ Rename `date-fns` adapter imports + +:::warning +This codemod is not idempotent. Running it multiple times will rename the imports back and forth. + +In example: usage of `AdapterDateFnsV3` would be replaced by `AdapterDateFns` and a subsequent run would rename it to `AdapterDateFnsV2`. +::: + +- The `AdapterDateFns` and `AdapterDateFnsJalali` adapters have been renamed to `AdapterDateFnsV2` and `AdapterDateFnsJalaliV2` respectively. + If you were using the old imports, you need to update them: + + ```diff + -import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; + -import { AdapterDateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalali'; + +import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFnsV2'; + +import { AdapterDateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalaliV2'; + ``` + + Or consider updating the `date-fns` or `date-fns-jalali` package to the latest version and use the updated adapters. + +- The `AdapterDateFnsV3` and `AdapterDateFnsJalaliV3` adapters have been renamed to `AdapterDateFns` and `AdapterDateFnsJalali` respectively. + If you were using the old imports, you need to update them: + + ```diff + -import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFnsV3'; + -import { AdapterDateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalaliV3'; + +import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; + +import { AdapterDateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalali'; + ``` + ## Stop using `LicenseInfo` from `@mui/x-date-pickers-pro` The `LicenseInfo` object is no longer exported from the `@mui/x-date-pickers-pro` package. diff --git a/docs/package.json b/docs/package.json index 16a0d8e0fafac..40593e6d9252d 100644 --- a/docs/package.json +++ b/docs/package.json @@ -61,8 +61,8 @@ "core-js": "^2.6.12", "cross-env": "^7.0.3", "d3-scale-chromatic": "^3.1.0", - "date-fns": "^2.30.0", - "date-fns-jalali": "^2.30.0-0", + "date-fns": "^4.1.0", + "date-fns-jalali": "^4.1.0-0", "dayjs": "^1.11.13", "doctrine": "^3.0.0", "exceljs": "^4.4.0", diff --git a/docs/src/modules/components/PickersRenderingInstructions.js b/docs/src/modules/components/PickersRenderingInstructions.js index e9e2d709e18ce..6a79e5280e4ad 100644 --- a/docs/src/modules/components/PickersRenderingInstructions.js +++ b/docs/src/modules/components/PickersRenderingInstructions.js @@ -22,13 +22,13 @@ export default function PickersRenderingInstructions() { const commandLines = [ `import { LocalizationProvider } from '${componentPackage}';`, ...(libraryUsed === 'date-fns' - ? ['// If you are using date-fns v2.x, please import `AdapterDateFns`'] + ? ['// If you are using date-fns v3.x or v4.x, please import `AdapterDateFns`'] : []), - `import { ${adapterName} } from '${componentPackage}/${adapterName}'`, + `import { ${adapterName} } from '${componentPackage}/${adapterName}';`, ...(libraryUsed === 'date-fns' ? [ - '// If you are using date-fns v3.x or v4.x, please import the v3 adapter', - `import { ${adapterName} } from '${componentPackage}/AdapterDateFnsV3'`, + '// If you are using date-fns v2.x, please import the v2 adapter', + `import { ${adapterName} } from '${componentPackage}/AdapterDateFnsV2';`, ] : []), '', diff --git a/package.json b/package.json index 073dfd23907b7..c84ab7265ba46 100644 --- a/package.json +++ b/package.json @@ -134,8 +134,8 @@ "cpy-cli": "^5.0.0", "cross-env": "^7.0.3", "danger": "^12.3.3", - "date-fns-jalali-v4": "npm:date-fns-jalali@4.1.0-0", - "date-fns-v4": "npm:date-fns@4.1.0", + "date-fns-jalali-v2": "npm:date-fns-jalali@2.30.0-0", + "date-fns-v2": "npm:date-fns@2.30.0", "eslint": "^8.57.1", "eslint-config-airbnb": "^19.0.4", "eslint-config-airbnb-typescript": "^18.0.0", diff --git a/packages/x-codemod/README.md b/packages/x-codemod/README.md index 8f0442b8f0220..75d44cf98ab90 100644 --- a/packages/x-codemod/README.md +++ b/packages/x-codemod/README.md @@ -172,17 +172,15 @@ Renames `ResponsiveChartContainer` and `ResponsiveChartContainerPro` by `ChartCo + ``` -:::warning -If you imported both `ResponsiveChartContainer` and `ChartContainer` in the same file, you might end up with duplicated import. -Verify the git diff to remove the duplicate. - -```diff - import { ChartContainer } from '@mui/x-charts/ChartContainer'; --import { ResponsiveChartContainer } from '@mui/x-charts/ResponsiveChartContainer'; -+import { ChartContainer } from '@mui/x-charts/ChartContainer'; -``` - -::: +> [!WARNING] +> If you imported both `ResponsiveChartContainer` and `ChartContainer` in the same file, you might end up with duplicated import. +> Verify the git diff to remove the duplicate. +> +> ```diff +> import { ChartContainer } from '@mui/x-charts/ChartContainer'; +> -import { ResponsiveChartContainer } from '@mui/x-charts/ResponsiveChartContainer'; +> +import { ChartContainer } from '@mui/x-charts/ChartContainer'; +> ``` #### `rename-label-and-tick-font-size` @@ -249,8 +247,39 @@ npx @mui/x-codemod@next v8.0.0/pickers/preset-safe The list includes these transformers +- [`rename-adapter-date-fns-imports`](#rename-adapter-date-fns-imports) - [`rename-and-move-field-value-type`](#rename-and-move-field-value-type) +#### `rename-adapter-date-fns-imports` + +> [!WARNING] +> This codemod is not idempotent. Running it multiple times will rename the imports back and forth. +> Usage of `AdapterDateFnsV3` would be replaced by `AdapterDateFns` and a subsequent run would rename it to `AdapterDateFnsV2`. + +- Renames `AdapterDateFns` and `AdapterDateFnsJalali` imports to `AdapterDateFnsV2` and `AdapterDateFnsJalaliV2` respectfully. + + ```diff + -import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; + -import { AdapterDateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalali'; + +import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFnsV2'; + +import { AdapterDateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalaliV2'; + ``` + +- Renames `AdapterDateFnsV3` and `AdapterDateFnsJalaliV3` imports to `AdapterDateFns` and `AdapterDateFnsJalali` respectfully. + + ```diff + -import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFnsV3'; + -import { AdapterDateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalaliV3'; + +import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; + +import { AdapterDateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalali'; + ``` + + + +```bash +npx @mui/x-codemod@next v8.0.0/pickers/rename-adapter-date-fns-imports +``` + #### `rename-and-move-field-value-type` Renames `FieldValueType` to `PickerValueType`. diff --git a/packages/x-codemod/src/v8.0.0/pickers/preset-safe/index.ts b/packages/x-codemod/src/v8.0.0/pickers/preset-safe/index.ts index 38f3f1ff543be..2fdaaf49ca46e 100644 --- a/packages/x-codemod/src/v8.0.0/pickers/preset-safe/index.ts +++ b/packages/x-codemod/src/v8.0.0/pickers/preset-safe/index.ts @@ -1,8 +1,10 @@ +import transformAdapterDateFnsImports from '../rename-adapter-date-fns-imports'; import transformFieldValue from '../rename-and-move-field-value-type'; import { JsCodeShiftAPI, JsCodeShiftFileInfo } from '../../../types'; export default function transformer(file: JsCodeShiftFileInfo, api: JsCodeShiftAPI, options: any) { + file.source = transformAdapterDateFnsImports(file, api, options); file.source = transformFieldValue(file, api, options); return file.source; diff --git a/packages/x-codemod/src/v8.0.0/pickers/rename-adapter-date-fns-imports/actual-community-import.spec.tsx b/packages/x-codemod/src/v8.0.0/pickers/rename-adapter-date-fns-imports/actual-community-import.spec.tsx new file mode 100644 index 0000000000000..53e6dbde1a33f --- /dev/null +++ b/packages/x-codemod/src/v8.0.0/pickers/rename-adapter-date-fns-imports/actual-community-import.spec.tsx @@ -0,0 +1,5 @@ +// @ts-nocheck +import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFnsV3'; +import { AdapterDateFns as DateFns } from '@mui/x-date-pickers/AdapterDateFns'; +import { AdapterDateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalaliV3'; +import { AdapterDateFnsJalali as DateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalali'; diff --git a/packages/x-codemod/src/v8.0.0/pickers/rename-adapter-date-fns-imports/actual-pro-import.spec.tsx b/packages/x-codemod/src/v8.0.0/pickers/rename-adapter-date-fns-imports/actual-pro-import.spec.tsx new file mode 100644 index 0000000000000..ca85909296a2b --- /dev/null +++ b/packages/x-codemod/src/v8.0.0/pickers/rename-adapter-date-fns-imports/actual-pro-import.spec.tsx @@ -0,0 +1,5 @@ +// @ts-nocheck +import { AdapterDateFns } from '@mui/x-date-pickers-pro/AdapterDateFnsV3'; +import { AdapterDateFns as DateFns } from '@mui/x-date-pickers-pro/AdapterDateFns'; +import { AdapterDateFnsJalali } from '@mui/x-date-pickers-pro/AdapterDateFnsJalaliV3'; +import { AdapterDateFnsJalali as DateFnsJalali } from '@mui/x-date-pickers-pro/AdapterDateFnsJalali'; diff --git a/packages/x-codemod/src/v8.0.0/pickers/rename-adapter-date-fns-imports/expected-community-import.spec.tsx b/packages/x-codemod/src/v8.0.0/pickers/rename-adapter-date-fns-imports/expected-community-import.spec.tsx new file mode 100644 index 0000000000000..bb36e95b6e5e3 --- /dev/null +++ b/packages/x-codemod/src/v8.0.0/pickers/rename-adapter-date-fns-imports/expected-community-import.spec.tsx @@ -0,0 +1,4 @@ +import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; +import { AdapterDateFns as DateFns } from '@mui/x-date-pickers/AdapterDateFnsV2'; +import { AdapterDateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalali'; +import { AdapterDateFnsJalali as DateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalaliV2'; diff --git a/packages/x-codemod/src/v8.0.0/pickers/rename-adapter-date-fns-imports/expected-pro-import.spec.tsx b/packages/x-codemod/src/v8.0.0/pickers/rename-adapter-date-fns-imports/expected-pro-import.spec.tsx new file mode 100644 index 0000000000000..f1c056ca9a87e --- /dev/null +++ b/packages/x-codemod/src/v8.0.0/pickers/rename-adapter-date-fns-imports/expected-pro-import.spec.tsx @@ -0,0 +1,4 @@ +import { AdapterDateFns } from '@mui/x-date-pickers-pro/AdapterDateFns'; +import { AdapterDateFns as DateFns } from '@mui/x-date-pickers-pro/AdapterDateFnsV2'; +import { AdapterDateFnsJalali } from '@mui/x-date-pickers-pro/AdapterDateFnsJalali'; +import { AdapterDateFnsJalali as DateFnsJalali } from '@mui/x-date-pickers-pro/AdapterDateFnsJalaliV2'; diff --git a/packages/x-codemod/src/v8.0.0/pickers/rename-adapter-date-fns-imports/index.ts b/packages/x-codemod/src/v8.0.0/pickers/rename-adapter-date-fns-imports/index.ts new file mode 100644 index 0000000000000..904753d38107b --- /dev/null +++ b/packages/x-codemod/src/v8.0.0/pickers/rename-adapter-date-fns-imports/index.ts @@ -0,0 +1,49 @@ +import type { JsCodeShiftAPI, JsCodeShiftFileInfo } from '../../../types'; +import { renameImports } from '../../../util/renameImports'; + +export default function transformer(file: JsCodeShiftFileInfo, api: JsCodeShiftAPI, options: any) { + const j = api.jscodeshift; + const root = j(file.source); + + const printOptions = options.printOptions || { + quote: 'single', + trailingComma: true, + }; + + renameImports({ + j, + root, + packageNames: ['@mui/x-date-pickers', '@mui/x-date-pickers-pro'], + imports: [ + { + oldEndpoint: 'AdapterDateFns', + newEndpoint: 'AdapterDateFnsV2', + importsMapping: { + AdapterDateFns: 'AdapterDateFns', + }, + }, + { + oldEndpoint: 'AdapterDateFnsV3', + newEndpoint: 'AdapterDateFns', + importsMapping: { + AdapterDateFns: 'AdapterDateFns', + }, + }, + { + oldEndpoint: 'AdapterDateFnsJalali', + newEndpoint: 'AdapterDateFnsJalaliV2', + importsMapping: { + AdapterDateFnsJalali: 'AdapterDateFnsJalali', + }, + }, + { + oldEndpoint: 'AdapterDateFnsJalaliV3', + newEndpoint: 'AdapterDateFnsJalali', + importsMapping: { + AdapterDateFnsJalali: 'AdapterDateFnsJalali', + }, + }, + ], + }); + return root.toSource(printOptions); +} diff --git a/packages/x-codemod/src/v8.0.0/pickers/rename-adapter-date-fns-imports/rename-adapter-date-fns-imports.test.ts b/packages/x-codemod/src/v8.0.0/pickers/rename-adapter-date-fns-imports/rename-adapter-date-fns-imports.test.ts new file mode 100644 index 0000000000000..adf48ace48983 --- /dev/null +++ b/packages/x-codemod/src/v8.0.0/pickers/rename-adapter-date-fns-imports/rename-adapter-date-fns-imports.test.ts @@ -0,0 +1,33 @@ +import path from 'path'; +import { expect } from 'chai'; +import jscodeshift from 'jscodeshift'; +import transform from '.'; +import readFile from '../../../util/readFile'; + +function read(fileName) { + return readFile(path.join(__dirname, fileName)); +} + +const TEST_FILES = ['community-import', 'pro-import']; + +describe('v8.0.0/pickers', () => { + describe('rename-adapter-date-fns-imports', () => { + TEST_FILES.forEach((testFile) => { + const actualPath = `./actual-${testFile}.spec.tsx`; + const expectedPath = `./expected-${testFile}.spec.tsx`; + + describe(`${testFile.replace(/-/g, ' ')}`, () => { + it('transforms imports as needed', () => { + const actual = transform( + { source: read(actualPath) }, + { jscodeshift: jscodeshift.withParser('tsx') }, + {}, + ); + + const expected = read(expectedPath); + expect(actual).to.equal(expected, 'The transformed version should be correct'); + }); + }); + }); + }); +}); diff --git a/packages/x-data-grid-premium/package.json b/packages/x-data-grid-premium/package.json index ac32b9aa1bd2f..29e609742bd06 100644 --- a/packages/x-data-grid-premium/package.json +++ b/packages/x-data-grid-premium/package.json @@ -76,7 +76,7 @@ "@mui/material": "^5.16.13", "@mui/system": "^5.16.13", "@types/prop-types": "^15.7.14", - "date-fns": "^2.30.0", + "date-fns": "^4.1.0", "rimraf": "^6.0.1" }, "engines": { diff --git a/packages/x-data-grid-premium/src/tests/license.DataGridPremium.test.tsx b/packages/x-data-grid-premium/src/tests/license.DataGridPremium.test.tsx index d3e861a8e3535..9a230483cda99 100644 --- a/packages/x-data-grid-premium/src/tests/license.DataGridPremium.test.tsx +++ b/packages/x-data-grid-premium/src/tests/license.DataGridPremium.test.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import addYears from 'date-fns/addYears'; +import { addYears } from 'date-fns/addYears'; import { expect } from 'chai'; import { createRenderer, screen, waitFor } from '@mui/internal-test-utils'; import { DataGridPremium } from '@mui/x-data-grid-premium'; diff --git a/packages/x-date-pickers-pro/package.json b/packages/x-date-pickers-pro/package.json index 1931477618f5f..05c6ac1b23d79 100644 --- a/packages/x-date-pickers-pro/package.json +++ b/packages/x-date-pickers-pro/package.json @@ -101,8 +101,8 @@ "@mui/system": "^5.16.13", "@types/luxon": "^3.4.2", "@types/prop-types": "^15.7.14", - "date-fns": "^2.30.0", - "date-fns-jalali": "^2.30.0-0", + "date-fns": "^4.1.0", + "date-fns-jalali": "^4.1.0-0", "dayjs": "^1.11.13", "luxon": "^3.5.0", "moment": "^2.30.1", diff --git a/packages/x-date-pickers-pro/src/AdapterDateFnsJalaliV3/index.ts b/packages/x-date-pickers-pro/src/AdapterDateFnsJalaliV2/index.ts similarity index 77% rename from packages/x-date-pickers-pro/src/AdapterDateFnsJalaliV3/index.ts rename to packages/x-date-pickers-pro/src/AdapterDateFnsJalaliV2/index.ts index ee8f537fd113f..72e677e42e40d 100644 --- a/packages/x-date-pickers-pro/src/AdapterDateFnsJalaliV3/index.ts +++ b/packages/x-date-pickers-pro/src/AdapterDateFnsJalaliV2/index.ts @@ -1 +1 @@ -export { AdapterDateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalaliV3'; +export { AdapterDateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalaliV2'; diff --git a/packages/x-date-pickers-pro/src/AdapterDateFnsV3/index.ts b/packages/x-date-pickers-pro/src/AdapterDateFnsV2/index.ts similarity index 90% rename from packages/x-date-pickers-pro/src/AdapterDateFnsV3/index.ts rename to packages/x-date-pickers-pro/src/AdapterDateFnsV2/index.ts index 7291f164d3f4d..77983100b71ed 100644 --- a/packages/x-date-pickers-pro/src/AdapterDateFnsV3/index.ts +++ b/packages/x-date-pickers-pro/src/AdapterDateFnsV2/index.ts @@ -1 +1 @@ -export { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFnsV3'; +export { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFnsV2'; diff --git a/packages/x-date-pickers/package.json b/packages/x-date-pickers/package.json index 2b456b6dc6186..e76bb93630d2a 100644 --- a/packages/x-date-pickers/package.json +++ b/packages/x-date-pickers/package.json @@ -105,8 +105,8 @@ "@types/moment-hijri": "^2.1.4", "@types/moment-jalaali": "^0.7.9", "@types/prop-types": "^15.7.14", - "date-fns": "^2.30.0", - "date-fns-jalali": "^2.30.0-0", + "date-fns": "^4.1.0", + "date-fns-jalali": "^4.1.0-0", "dayjs": "^1.11.13", "luxon": "^3.5.0", "moment": "^2.30.1", diff --git a/packages/x-date-pickers/src/AdapterDateFns/AdapterDateFns.ts b/packages/x-date-pickers/src/AdapterDateFns/AdapterDateFns.ts index d3ed11b3e8d06..6004c385f7bac 100644 --- a/packages/x-date-pickers/src/AdapterDateFns/AdapterDateFns.ts +++ b/packages/x-date-pickers/src/AdapterDateFns/AdapterDateFns.ts @@ -1,54 +1,51 @@ /* eslint-disable class-methods-use-this */ -import addDays from 'date-fns/addDays'; -import addSeconds from 'date-fns/addSeconds'; -import addMinutes from 'date-fns/addMinutes'; -import addHours from 'date-fns/addHours'; -import addWeeks from 'date-fns/addWeeks'; -import addMonths from 'date-fns/addMonths'; -import addYears from 'date-fns/addYears'; -import endOfDay from 'date-fns/endOfDay'; -import endOfWeek from 'date-fns/endOfWeek'; -import endOfYear from 'date-fns/endOfYear'; -import dateFnsFormat from 'date-fns/format'; -import getDate from 'date-fns/getDate'; -import getDaysInMonth from 'date-fns/getDaysInMonth'; -import getHours from 'date-fns/getHours'; -import getMinutes from 'date-fns/getMinutes'; -import getMonth from 'date-fns/getMonth'; -import getSeconds from 'date-fns/getSeconds'; -import getMilliseconds from 'date-fns/getMilliseconds'; -import getWeek from 'date-fns/getWeek'; -import getYear from 'date-fns/getYear'; -import isAfter from 'date-fns/isAfter'; -import isBefore from 'date-fns/isBefore'; -import isEqual from 'date-fns/isEqual'; -import isSameDay from 'date-fns/isSameDay'; -import isSameYear from 'date-fns/isSameYear'; -import isSameMonth from 'date-fns/isSameMonth'; -import isSameHour from 'date-fns/isSameHour'; -import isValid from 'date-fns/isValid'; -import dateFnsParse from 'date-fns/parse'; -import setDate from 'date-fns/setDate'; -import setHours from 'date-fns/setHours'; -import setMinutes from 'date-fns/setMinutes'; -import setMonth from 'date-fns/setMonth'; -import setSeconds from 'date-fns/setSeconds'; -import setMilliseconds from 'date-fns/setMilliseconds'; -import setYear from 'date-fns/setYear'; -import startOfDay from 'date-fns/startOfDay'; -import startOfMonth from 'date-fns/startOfMonth'; -import endOfMonth from 'date-fns/endOfMonth'; -import startOfWeek from 'date-fns/startOfWeek'; -import startOfYear from 'date-fns/startOfYear'; -import isWithinInterval from 'date-fns/isWithinInterval'; -import defaultLocale from 'date-fns/locale/en-US'; -// @ts-ignore -import longFormatters from 'date-fns/_lib/format/longFormatters'; +import { addDays } from 'date-fns/addDays'; +import { addSeconds } from 'date-fns/addSeconds'; +import { addMinutes } from 'date-fns/addMinutes'; +import { addHours } from 'date-fns/addHours'; +import { addWeeks } from 'date-fns/addWeeks'; +import { addMonths } from 'date-fns/addMonths'; +import { addYears } from 'date-fns/addYears'; +import { endOfDay } from 'date-fns/endOfDay'; +import { endOfWeek } from 'date-fns/endOfWeek'; +import { endOfYear } from 'date-fns/endOfYear'; +import { format as dateFnsFormat, longFormatters } from 'date-fns/format'; +import { getDate } from 'date-fns/getDate'; +import { getDaysInMonth } from 'date-fns/getDaysInMonth'; +import { getHours } from 'date-fns/getHours'; +import { getMinutes } from 'date-fns/getMinutes'; +import { getMonth } from 'date-fns/getMonth'; +import { getSeconds } from 'date-fns/getSeconds'; +import { getMilliseconds } from 'date-fns/getMilliseconds'; +import { getWeek } from 'date-fns/getWeek'; +import { getYear } from 'date-fns/getYear'; +import { isAfter } from 'date-fns/isAfter'; +import { isBefore } from 'date-fns/isBefore'; +import { isEqual } from 'date-fns/isEqual'; +import { isSameDay } from 'date-fns/isSameDay'; +import { isSameYear } from 'date-fns/isSameYear'; +import { isSameMonth } from 'date-fns/isSameMonth'; +import { isSameHour } from 'date-fns/isSameHour'; +import { isValid } from 'date-fns/isValid'; +import { parse as dateFnsParse } from 'date-fns/parse'; +import { setDate } from 'date-fns/setDate'; +import { setHours } from 'date-fns/setHours'; +import { setMinutes } from 'date-fns/setMinutes'; +import { setMonth } from 'date-fns/setMonth'; +import { setSeconds } from 'date-fns/setSeconds'; +import { setMilliseconds } from 'date-fns/setMilliseconds'; +import { setYear } from 'date-fns/setYear'; +import { startOfDay } from 'date-fns/startOfDay'; +import { startOfMonth } from 'date-fns/startOfMonth'; +import { endOfMonth } from 'date-fns/endOfMonth'; +import { startOfWeek } from 'date-fns/startOfWeek'; +import { startOfYear } from 'date-fns/startOfYear'; +import { isWithinInterval } from 'date-fns/isWithinInterval'; +import { enUS } from 'date-fns/locale/en-US'; +import { Locale as DateFnsLocale } from 'date-fns/locale'; import { AdapterFormats, AdapterOptions, MuiPickersAdapter } from '../models'; import { AdapterDateFnsBase } from '../AdapterDateFnsBase'; -type DateFnsLocale = typeof defaultLocale; - declare module '@mui/x-date-pickers/models' { interface PickerValidDateLookup { 'date-fns': Date; @@ -90,15 +87,21 @@ export class AdapterDateFns if (typeof addDays !== 'function') { throw new Error( [ - 'MUI: This adapter is only compatible with `date-fns` v2.x package versions.', - 'Please, install v2.x of the package or use the `AdapterDateFnsV3` instead.', + 'MUI: The `date-fns` package v2.x is not compatible with this adapter.', + 'Please, install v3.x or v4.x of the package or use the `AdapterDateFnsV2` instead.', ].join('\n'), ); } + if (!longFormatters) { + throw new Error( + 'MUI: The minimum supported `date-fns` package version compatible with this adapter is `3.2.x`.', + ); + } } - super({ locale: locale ?? defaultLocale, formats, longFormatters }); + super({ locale: locale ?? enUS, formats, longFormatters }); } + // TODO: explicit return types can be removed once there is only one date-fns version supported public parse = (value: string, format: string): Date | null => { if (value === '') { return null; diff --git a/packages/x-date-pickers/src/AdapterDateFnsBase/AdapterDateFnsBase.ts b/packages/x-date-pickers/src/AdapterDateFnsBase/AdapterDateFnsBase.ts index 8696490f13b29..20504dc9eb489 100644 --- a/packages/x-date-pickers/src/AdapterDateFnsBase/AdapterDateFnsBase.ts +++ b/packages/x-date-pickers/src/AdapterDateFnsBase/AdapterDateFnsBase.ts @@ -9,7 +9,7 @@ import { } from '../models'; type DateFnsLocaleBase = { - formatLong?: { + formatLong: { date: (...args: Array) => any; time: (...args: Array) => any; dateTime: (...args: Array) => any; diff --git a/packages/x-date-pickers/src/AdapterDateFnsJalali/AdapterDateFnsJalali.test.tsx b/packages/x-date-pickers/src/AdapterDateFnsJalali/AdapterDateFnsJalali.test.tsx index aeebce13303b0..921f17ca2e7bf 100644 --- a/packages/x-date-pickers/src/AdapterDateFnsJalali/AdapterDateFnsJalali.test.tsx +++ b/packages/x-date-pickers/src/AdapterDateFnsJalali/AdapterDateFnsJalali.test.tsx @@ -8,8 +8,7 @@ import { buildFieldInteractions, } from 'test/utils/pickers'; import { enUS } from 'date-fns/locale'; -import faIR from 'date-fns-jalali/locale/fa-IR'; -import faJalaliIR from 'date-fns-jalali/locale/fa-jalali-IR'; +import { faIR } from 'date-fns-jalali/locale/fa-IR'; import { AdapterFormats } from '@mui/x-date-pickers/models'; describe('', () => { @@ -50,17 +49,11 @@ describe('', () => { placeholder: 'YYYY/MM/DD hh:mm aa', value: '1397/02/25 09:35 ق.ظ.', }, - faJalaliIR: { - // Not sure about what's the difference between this and fa-IR - placeholder: 'YYYY/MM/DD hh:mm aa', - value: '1397/02/25 09:35 ق.ظ.', - }, }; Object.keys(localizedTexts).forEach((localeKey) => { const localeObject = { faIR, - faJalaliIR, enUS, }[localeKey]; diff --git a/packages/x-date-pickers/src/AdapterDateFnsJalali/AdapterDateFnsJalali.ts b/packages/x-date-pickers/src/AdapterDateFnsJalali/AdapterDateFnsJalali.ts index 0f3b16e179f8d..c86cee6236136 100644 --- a/packages/x-date-pickers/src/AdapterDateFnsJalali/AdapterDateFnsJalali.ts +++ b/packages/x-date-pickers/src/AdapterDateFnsJalali/AdapterDateFnsJalali.ts @@ -1,54 +1,51 @@ /* eslint-disable class-methods-use-this */ -import addSeconds from 'date-fns-jalali/addSeconds'; -import addMinutes from 'date-fns-jalali/addMinutes'; -import addHours from 'date-fns-jalali/addHours'; -import addDays from 'date-fns-jalali/addDays'; -import addWeeks from 'date-fns-jalali/addWeeks'; -import addMonths from 'date-fns-jalali/addMonths'; -import addYears from 'date-fns-jalali/addYears'; -import endOfDay from 'date-fns-jalali/endOfDay'; -import endOfWeek from 'date-fns-jalali/endOfWeek'; -import endOfYear from 'date-fns-jalali/endOfYear'; -import dateFnsFormat from 'date-fns-jalali/format'; -import getHours from 'date-fns-jalali/getHours'; -import getSeconds from 'date-fns-jalali/getSeconds'; -import getMilliseconds from 'date-fns-jalali/getMilliseconds'; -import getWeek from 'date-fns-jalali/getWeek'; -import getYear from 'date-fns-jalali/getYear'; -import getMonth from 'date-fns-jalali/getMonth'; -import getDate from 'date-fns-jalali/getDate'; -import getDaysInMonth from 'date-fns-jalali/getDaysInMonth'; -import getMinutes from 'date-fns-jalali/getMinutes'; -import isAfter from 'date-fns-jalali/isAfter'; -import isBefore from 'date-fns-jalali/isBefore'; -import isEqual from 'date-fns-jalali/isEqual'; -import isSameDay from 'date-fns-jalali/isSameDay'; -import isSameYear from 'date-fns-jalali/isSameYear'; -import isSameMonth from 'date-fns-jalali/isSameMonth'; -import isSameHour from 'date-fns-jalali/isSameHour'; -import isValid from 'date-fns-jalali/isValid'; -import dateFnsParse from 'date-fns-jalali/parse'; -import setDate from 'date-fns-jalali/setDate'; -import setHours from 'date-fns-jalali/setHours'; -import setMinutes from 'date-fns-jalali/setMinutes'; -import setMonth from 'date-fns-jalali/setMonth'; -import setSeconds from 'date-fns-jalali/setSeconds'; -import setMilliseconds from 'date-fns-jalali/setMilliseconds'; -import setYear from 'date-fns-jalali/setYear'; -import startOfDay from 'date-fns-jalali/startOfDay'; -import startOfMonth from 'date-fns-jalali/startOfMonth'; -import endOfMonth from 'date-fns-jalali/endOfMonth'; -import startOfWeek from 'date-fns-jalali/startOfWeek'; -import startOfYear from 'date-fns-jalali/startOfYear'; -import isWithinInterval from 'date-fns-jalali/isWithinInterval'; -import defaultLocale from 'date-fns-jalali/locale/fa-IR'; -// @ts-ignore -import longFormatters from 'date-fns-jalali/_lib/format/longFormatters'; +import { addSeconds } from 'date-fns-jalali/addSeconds'; +import { addMinutes } from 'date-fns-jalali/addMinutes'; +import { addHours } from 'date-fns-jalali/addHours'; +import { addDays } from 'date-fns-jalali/addDays'; +import { addWeeks } from 'date-fns-jalali/addWeeks'; +import { addMonths } from 'date-fns-jalali/addMonths'; +import { addYears } from 'date-fns-jalali/addYears'; +import { endOfDay } from 'date-fns-jalali/endOfDay'; +import { endOfWeek } from 'date-fns-jalali/endOfWeek'; +import { endOfYear } from 'date-fns-jalali/endOfYear'; +import { format as dateFnsFormat, longFormatters } from 'date-fns-jalali/format'; +import { getHours } from 'date-fns-jalali/getHours'; +import { getSeconds } from 'date-fns-jalali/getSeconds'; +import { getMilliseconds } from 'date-fns-jalali/getMilliseconds'; +import { getWeek } from 'date-fns-jalali/getWeek'; +import { getYear } from 'date-fns-jalali/getYear'; +import { getMonth } from 'date-fns-jalali/getMonth'; +import { getDate } from 'date-fns-jalali/getDate'; +import { getDaysInMonth } from 'date-fns-jalali/getDaysInMonth'; +import { getMinutes } from 'date-fns-jalali/getMinutes'; +import { isAfter } from 'date-fns-jalali/isAfter'; +import { isBefore } from 'date-fns-jalali/isBefore'; +import { isEqual } from 'date-fns-jalali/isEqual'; +import { isSameDay } from 'date-fns-jalali/isSameDay'; +import { isSameYear } from 'date-fns-jalali/isSameYear'; +import { isSameMonth } from 'date-fns-jalali/isSameMonth'; +import { isSameHour } from 'date-fns-jalali/isSameHour'; +import { isValid } from 'date-fns-jalali/isValid'; +import { parse as dateFnsParse } from 'date-fns-jalali/parse'; +import { setDate } from 'date-fns-jalali/setDate'; +import { setHours } from 'date-fns-jalali/setHours'; +import { setMinutes } from 'date-fns-jalali/setMinutes'; +import { setMonth } from 'date-fns-jalali/setMonth'; +import { setSeconds } from 'date-fns-jalali/setSeconds'; +import { setMilliseconds } from 'date-fns-jalali/setMilliseconds'; +import { setYear } from 'date-fns-jalali/setYear'; +import { startOfDay } from 'date-fns-jalali/startOfDay'; +import { startOfMonth } from 'date-fns-jalali/startOfMonth'; +import { endOfMonth } from 'date-fns-jalali/endOfMonth'; +import { startOfWeek } from 'date-fns-jalali/startOfWeek'; +import { startOfYear } from 'date-fns-jalali/startOfYear'; +import { isWithinInterval } from 'date-fns-jalali/isWithinInterval'; +import { faIR as defaultLocale } from 'date-fns-jalali/locale/fa-IR'; +import { Locale as DateFnsLocale } from 'date-fns-jalali/locale'; import { AdapterFormats, AdapterOptions, MuiPickersAdapter } from '../models'; import { AdapterDateFnsBase } from '../AdapterDateFnsBase'; -type DateFnsLocale = typeof defaultLocale; - const defaultFormats: AdapterFormats = { year: 'yyyy', month: 'LLLL', @@ -131,11 +128,16 @@ export class AdapterDateFnsJalali if (typeof addDays !== 'function') { throw new Error( [ - 'MUI: The `date-fns-jalali` package v3.x is not compatible with this adapter.', - 'Please, install v2.x of the package or use the `AdapterDateFnsJalaliV3` instead.', + 'MUI: The `date-fns-jalali` package v2.x is not compatible with this adapter.', + 'Please, install v3.x or v4.x of the package or use the `AdapterDateFnsJalaliV2` instead.', ].join('\n'), ); } + if (!longFormatters) { + throw new Error( + 'MUI: The minimum supported `date-fns-jalali` package version compatible with this adapter is `3.2.x`.', + ); + } } super({ locale: locale ?? defaultLocale, @@ -147,6 +149,7 @@ export class AdapterDateFnsJalali }); } + // TODO: explicit return types can be removed once there is only one date-fns version supported public parse = (value: string, format: string): Date | null => { if (value === '') { return null; diff --git a/packages/x-date-pickers/src/AdapterDateFnsJalaliV3/AdapterDateFnsJalaliV3.test.tsx b/packages/x-date-pickers/src/AdapterDateFnsJalaliV2/AdapterDateFnsJalaliV2.test.tsx similarity index 97% rename from packages/x-date-pickers/src/AdapterDateFnsJalaliV3/AdapterDateFnsJalaliV3.test.tsx rename to packages/x-date-pickers/src/AdapterDateFnsJalaliV2/AdapterDateFnsJalaliV2.test.tsx index 59446a64a9c5e..bf338cda289a4 100644 --- a/packages/x-date-pickers/src/AdapterDateFnsJalaliV3/AdapterDateFnsJalaliV3.test.tsx +++ b/packages/x-date-pickers/src/AdapterDateFnsJalaliV2/AdapterDateFnsJalaliV2.test.tsx @@ -1,6 +1,6 @@ import { expect } from 'chai'; import { DateTimeField } from '@mui/x-date-pickers/DateTimeField'; -import { AdapterDateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalaliV3'; +import { AdapterDateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalaliV2'; import { createPickerRenderer, expectFieldValueV7, @@ -10,7 +10,7 @@ import { import { enUS, faIR } from 'date-fns-jalali/locale'; import { AdapterFormats } from '@mui/x-date-pickers/models'; -describe('', () => { +describe('', () => { describeJalaliAdapter(AdapterDateFnsJalali, {}); describe('Adapter localization', () => { diff --git a/packages/x-date-pickers/src/AdapterDateFnsJalaliV3/AdapterDateFnsJalaliV3.ts b/packages/x-date-pickers/src/AdapterDateFnsJalaliV2/AdapterDateFnsJalaliV2.ts similarity index 74% rename from packages/x-date-pickers/src/AdapterDateFnsJalaliV3/AdapterDateFnsJalaliV3.ts rename to packages/x-date-pickers/src/AdapterDateFnsJalaliV2/AdapterDateFnsJalaliV2.ts index 85a849e670dfb..f5dc85d1eccd0 100644 --- a/packages/x-date-pickers/src/AdapterDateFnsJalaliV3/AdapterDateFnsJalaliV3.ts +++ b/packages/x-date-pickers/src/AdapterDateFnsJalaliV2/AdapterDateFnsJalaliV2.ts @@ -1,52 +1,50 @@ /* eslint-disable class-methods-use-this */ -// TODO remove when date-fns-jalali-v3 is the default // @ts-nocheck -import { addSeconds } from 'date-fns-jalali/addSeconds'; -import { addMinutes } from 'date-fns-jalali/addMinutes'; -import { addHours } from 'date-fns-jalali/addHours'; -import { addDays } from 'date-fns-jalali/addDays'; -import { addWeeks } from 'date-fns-jalali/addWeeks'; -import { addMonths } from 'date-fns-jalali/addMonths'; -import { addYears } from 'date-fns-jalali/addYears'; -import { endOfDay } from 'date-fns-jalali/endOfDay'; -import { endOfWeek } from 'date-fns-jalali/endOfWeek'; -import { endOfYear } from 'date-fns-jalali/endOfYear'; -import { format as dateFnsFormat, longFormatters } from 'date-fns-jalali/format'; -import { getHours } from 'date-fns-jalali/getHours'; -import { getSeconds } from 'date-fns-jalali/getSeconds'; -import { getMilliseconds } from 'date-fns-jalali/getMilliseconds'; -import { getWeek } from 'date-fns-jalali/getWeek'; -import { getYear } from 'date-fns-jalali/getYear'; -import { getMonth } from 'date-fns-jalali/getMonth'; -import { getDate } from 'date-fns-jalali/getDate'; -import { getDaysInMonth } from 'date-fns-jalali/getDaysInMonth'; -import { getMinutes } from 'date-fns-jalali/getMinutes'; -import { isAfter } from 'date-fns-jalali/isAfter'; -import { isBefore } from 'date-fns-jalali/isBefore'; -import { isEqual } from 'date-fns-jalali/isEqual'; -import { isSameDay } from 'date-fns-jalali/isSameDay'; -import { isSameYear } from 'date-fns-jalali/isSameYear'; -import { isSameMonth } from 'date-fns-jalali/isSameMonth'; -import { isSameHour } from 'date-fns-jalali/isSameHour'; -import { isValid } from 'date-fns-jalali/isValid'; -import { parse as dateFnsParse } from 'date-fns-jalali/parse'; -import { setDate } from 'date-fns-jalali/setDate'; -import { setHours } from 'date-fns-jalali/setHours'; -import { setMinutes } from 'date-fns-jalali/setMinutes'; -import { setMonth } from 'date-fns-jalali/setMonth'; -import { setSeconds } from 'date-fns-jalali/setSeconds'; -import { setMilliseconds } from 'date-fns-jalali/setMilliseconds'; -import { setYear } from 'date-fns-jalali/setYear'; -import { startOfDay } from 'date-fns-jalali/startOfDay'; -import { startOfMonth } from 'date-fns-jalali/startOfMonth'; -import { endOfMonth } from 'date-fns-jalali/endOfMonth'; -import { startOfWeek } from 'date-fns-jalali/startOfWeek'; -import { startOfYear } from 'date-fns-jalali/startOfYear'; -import { isWithinInterval } from 'date-fns-jalali/isWithinInterval'; -import { faIR as defaultLocale } from 'date-fns-jalali/locale/fa-IR'; -// date-fns-jalali v2 does not export types -// @ts-ignore TODO remove when date-fns-jalali-v3 is the default -import { Locale as DateFnsLocale } from 'date-fns-jalali/locale/types'; +import addSeconds from 'date-fns-jalali/addSeconds'; +import addMinutes from 'date-fns-jalali/addMinutes'; +import addHours from 'date-fns-jalali/addHours'; +import addDays from 'date-fns-jalali/addDays'; +import addWeeks from 'date-fns-jalali/addWeeks'; +import addMonths from 'date-fns-jalali/addMonths'; +import addYears from 'date-fns-jalali/addYears'; +import endOfDay from 'date-fns-jalali/endOfDay'; +import endOfWeek from 'date-fns-jalali/endOfWeek'; +import endOfYear from 'date-fns-jalali/endOfYear'; +import dateFnsFormat from 'date-fns-jalali/format'; +import getHours from 'date-fns-jalali/getHours'; +import getSeconds from 'date-fns-jalali/getSeconds'; +import getMilliseconds from 'date-fns-jalali/getMilliseconds'; +import getWeek from 'date-fns-jalali/getWeek'; +import getYear from 'date-fns-jalali/getYear'; +import getMonth from 'date-fns-jalali/getMonth'; +import getDate from 'date-fns-jalali/getDate'; +import getDaysInMonth from 'date-fns-jalali/getDaysInMonth'; +import getMinutes from 'date-fns-jalali/getMinutes'; +import isAfter from 'date-fns-jalali/isAfter'; +import isBefore from 'date-fns-jalali/isBefore'; +import isEqual from 'date-fns-jalali/isEqual'; +import isSameDay from 'date-fns-jalali/isSameDay'; +import isSameYear from 'date-fns-jalali/isSameYear'; +import isSameMonth from 'date-fns-jalali/isSameMonth'; +import isSameHour from 'date-fns-jalali/isSameHour'; +import isValid from 'date-fns-jalali/isValid'; +import dateFnsParse from 'date-fns-jalali/parse'; +import setDate from 'date-fns-jalali/setDate'; +import setHours from 'date-fns-jalali/setHours'; +import setMinutes from 'date-fns-jalali/setMinutes'; +import setMonth from 'date-fns-jalali/setMonth'; +import setSeconds from 'date-fns-jalali/setSeconds'; +import setMilliseconds from 'date-fns-jalali/setMilliseconds'; +import setYear from 'date-fns-jalali/setYear'; +import startOfDay from 'date-fns-jalali/startOfDay'; +import startOfMonth from 'date-fns-jalali/startOfMonth'; +import endOfMonth from 'date-fns-jalali/endOfMonth'; +import startOfWeek from 'date-fns-jalali/startOfWeek'; +import startOfYear from 'date-fns-jalali/startOfYear'; +import isWithinInterval from 'date-fns-jalali/isWithinInterval'; +import defaultLocale from 'date-fns-jalali/locale/fa-IR'; +import { Locale as DateFnsLocale } from 'date-fns-jalali/locale'; +import longFormatters from 'date-fns-jalali/_lib/format/longFormatters'; import { AdapterFormats, AdapterOptions, MuiPickersAdapter } from '../models'; import { AdapterDateFnsBase } from '../AdapterDateFnsBase'; @@ -132,16 +130,11 @@ export class AdapterDateFnsJalali if (typeof addDays !== 'function') { throw new Error( [ - `MUI: The \`date-fns-jalali\` package v2.x is not compatible with this adapter.`, - 'Please, install v3.x of the package or use the `AdapterDateFnsJalali` instead.', + 'MUI: This adapter is only compatible with `date-fns-jalali` v2.x package versions.', + 'Please, install v2.x of the package or use the `AdapterDateFnsJalali` instead.', ].join('\n'), ); } - if (!longFormatters) { - throw new Error( - 'MUI: The minimum supported `date-fns-jalali` package version compatible with this adapter is `3.2.x`.', - ); - } } super({ locale: locale ?? defaultLocale, @@ -153,7 +146,6 @@ export class AdapterDateFnsJalali }); } - // TODO: explicit return types can be removed once there is only one date-fns version supported public parse = (value: string, format: string): Date | null => { if (value === '') { return null; diff --git a/packages/x-date-pickers/src/AdapterDateFnsJalaliV2/index.ts b/packages/x-date-pickers/src/AdapterDateFnsJalaliV2/index.ts new file mode 100644 index 0000000000000..f08527d92b750 --- /dev/null +++ b/packages/x-date-pickers/src/AdapterDateFnsJalaliV2/index.ts @@ -0,0 +1 @@ +export { AdapterDateFnsJalali } from './AdapterDateFnsJalaliV2'; diff --git a/packages/x-date-pickers/src/AdapterDateFnsJalaliV3/index.ts b/packages/x-date-pickers/src/AdapterDateFnsJalaliV3/index.ts deleted file mode 100644 index 056183daac31f..0000000000000 --- a/packages/x-date-pickers/src/AdapterDateFnsJalaliV3/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { AdapterDateFnsJalali } from './AdapterDateFnsJalaliV3'; diff --git a/packages/x-date-pickers/src/AdapterDateFnsV3/AdapterDateFnsV3.test.tsx b/packages/x-date-pickers/src/AdapterDateFnsV2/AdapterDateFnsV2.test.tsx similarity index 87% rename from packages/x-date-pickers/src/AdapterDateFnsV3/AdapterDateFnsV3.test.tsx rename to packages/x-date-pickers/src/AdapterDateFnsV2/AdapterDateFnsV2.test.tsx index f84af39c4472e..afd684d5c3883 100644 --- a/packages/x-date-pickers/src/AdapterDateFnsV3/AdapterDateFnsV3.test.tsx +++ b/packages/x-date-pickers/src/AdapterDateFnsV2/AdapterDateFnsV2.test.tsx @@ -1,8 +1,8 @@ -import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFnsV3'; +import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFnsV2'; import { describeGregorianAdapter } from 'test/utils/pickers/describeGregorianAdapter'; import { fr } from 'date-fns/locale'; -describe('', () => { +describe('', () => { describeGregorianAdapter(AdapterDateFns, { formatDateTime: 'yyyy-MM-dd HH:mm:ss', setDefaultTimezone: () => {}, diff --git a/packages/x-date-pickers/src/AdapterDateFnsV3/AdapterDateFnsV3.ts b/packages/x-date-pickers/src/AdapterDateFnsV2/AdapterDateFnsV2.ts similarity index 73% rename from packages/x-date-pickers/src/AdapterDateFnsV3/AdapterDateFnsV3.ts rename to packages/x-date-pickers/src/AdapterDateFnsV2/AdapterDateFnsV2.ts index ce2c4d8a664ce..4248dea27a069 100644 --- a/packages/x-date-pickers/src/AdapterDateFnsV3/AdapterDateFnsV3.ts +++ b/packages/x-date-pickers/src/AdapterDateFnsV2/AdapterDateFnsV2.ts @@ -1,53 +1,50 @@ /* eslint-disable class-methods-use-this */ -// TODO remove when date-fns-v3 is the default // @ts-nocheck -import { addDays } from 'date-fns/addDays'; -import { addSeconds } from 'date-fns/addSeconds'; -import { addMinutes } from 'date-fns/addMinutes'; -import { addHours } from 'date-fns/addHours'; -import { addWeeks } from 'date-fns/addWeeks'; -import { addMonths } from 'date-fns/addMonths'; -import { addYears } from 'date-fns/addYears'; -import { endOfDay } from 'date-fns/endOfDay'; -import { endOfWeek } from 'date-fns/endOfWeek'; -import { endOfYear } from 'date-fns/endOfYear'; -// @ts-ignore TODO remove when date-fns-v3 is the default -import { format as dateFnsFormat, longFormatters } from 'date-fns/format'; -import { getDate } from 'date-fns/getDate'; -import { getDaysInMonth } from 'date-fns/getDaysInMonth'; -import { getHours } from 'date-fns/getHours'; -import { getMinutes } from 'date-fns/getMinutes'; -import { getMonth } from 'date-fns/getMonth'; -import { getSeconds } from 'date-fns/getSeconds'; -import { getMilliseconds } from 'date-fns/getMilliseconds'; -import { getWeek } from 'date-fns/getWeek'; -import { getYear } from 'date-fns/getYear'; -import { isAfter } from 'date-fns/isAfter'; -import { isBefore } from 'date-fns/isBefore'; -import { isEqual } from 'date-fns/isEqual'; -import { isSameDay } from 'date-fns/isSameDay'; -import { isSameYear } from 'date-fns/isSameYear'; -import { isSameMonth } from 'date-fns/isSameMonth'; -import { isSameHour } from 'date-fns/isSameHour'; -import { isValid } from 'date-fns/isValid'; -import { parse as dateFnsParse } from 'date-fns/parse'; -import { setDate } from 'date-fns/setDate'; -import { setHours } from 'date-fns/setHours'; -import { setMinutes } from 'date-fns/setMinutes'; -import { setMonth } from 'date-fns/setMonth'; -import { setSeconds } from 'date-fns/setSeconds'; -import { setMilliseconds } from 'date-fns/setMilliseconds'; -import { setYear } from 'date-fns/setYear'; -import { startOfDay } from 'date-fns/startOfDay'; -import { startOfMonth } from 'date-fns/startOfMonth'; -import { endOfMonth } from 'date-fns/endOfMonth'; -import { startOfWeek } from 'date-fns/startOfWeek'; -import { startOfYear } from 'date-fns/startOfYear'; -import { isWithinInterval } from 'date-fns/isWithinInterval'; -import { enUS } from 'date-fns/locale/en-US'; -// date-fns v2 does not export types -// @ts-ignore TODO remove when date-fns-v3 is the default -import { Locale as DateFnsLocale } from 'date-fns/locale/types'; +import addDays from 'date-fns/addDays'; +import addSeconds from 'date-fns/addSeconds'; +import addMinutes from 'date-fns/addMinutes'; +import addHours from 'date-fns/addHours'; +import addWeeks from 'date-fns/addWeeks'; +import addMonths from 'date-fns/addMonths'; +import addYears from 'date-fns/addYears'; +import endOfDay from 'date-fns/endOfDay'; +import endOfWeek from 'date-fns/endOfWeek'; +import endOfYear from 'date-fns/endOfYear'; +import dateFnsFormat from 'date-fns/format'; +import getDate from 'date-fns/getDate'; +import getDaysInMonth from 'date-fns/getDaysInMonth'; +import getHours from 'date-fns/getHours'; +import getMinutes from 'date-fns/getMinutes'; +import getMonth from 'date-fns/getMonth'; +import getSeconds from 'date-fns/getSeconds'; +import getMilliseconds from 'date-fns/getMilliseconds'; +import getWeek from 'date-fns/getWeek'; +import getYear from 'date-fns/getYear'; +import isAfter from 'date-fns/isAfter'; +import isBefore from 'date-fns/isBefore'; +import isEqual from 'date-fns/isEqual'; +import isSameDay from 'date-fns/isSameDay'; +import isSameYear from 'date-fns/isSameYear'; +import isSameMonth from 'date-fns/isSameMonth'; +import isSameHour from 'date-fns/isSameHour'; +import isValid from 'date-fns/isValid'; +import dateFnsParse from 'date-fns/parse'; +import setDate from 'date-fns/setDate'; +import setHours from 'date-fns/setHours'; +import setMinutes from 'date-fns/setMinutes'; +import setMonth from 'date-fns/setMonth'; +import setSeconds from 'date-fns/setSeconds'; +import setMilliseconds from 'date-fns/setMilliseconds'; +import setYear from 'date-fns/setYear'; +import startOfDay from 'date-fns/startOfDay'; +import startOfMonth from 'date-fns/startOfMonth'; +import endOfMonth from 'date-fns/endOfMonth'; +import startOfWeek from 'date-fns/startOfWeek'; +import startOfYear from 'date-fns/startOfYear'; +import isWithinInterval from 'date-fns/isWithinInterval'; +import defaultLocale from 'date-fns/locale/en-US'; +import { Locale as DateFnsLocale } from 'date-fns/locale'; +import longFormatters from 'date-fns/_lib/format/longFormatters'; import { AdapterFormats, AdapterOptions, MuiPickersAdapter } from '../models'; import { AdapterDateFnsBase } from '../AdapterDateFnsBase'; @@ -92,21 +89,15 @@ export class AdapterDateFns if (typeof addDays !== 'function') { throw new Error( [ - `MUI: The \`date-fns\` package v2.x is not compatible with this adapter.`, - 'Please, install v3.x or v4.x of the package or use the `AdapterDateFns` instead.', + 'MUI: This adapter is only compatible with `date-fns` v2.x package versions.', + 'Please, install v2.x of the package or use the `AdapterDateFns` instead.', ].join('\n'), ); } - if (!longFormatters) { - throw new Error( - 'MUI: The minimum supported `date-fns` package version compatible with this adapter is `3.2.x`.', - ); - } } - super({ locale: locale ?? enUS, formats, longFormatters }); + super({ locale: locale ?? defaultLocale, formats, longFormatters }); } - // TODO: explicit return types can be removed once there is only one date-fns version supported public parse = (value: string, format: string): Date | null => { if (value === '') { return null; diff --git a/packages/x-date-pickers/src/AdapterDateFnsV2/index.ts b/packages/x-date-pickers/src/AdapterDateFnsV2/index.ts new file mode 100644 index 0000000000000..9576bf2cf010c --- /dev/null +++ b/packages/x-date-pickers/src/AdapterDateFnsV2/index.ts @@ -0,0 +1 @@ +export { AdapterDateFns } from './AdapterDateFnsV2'; diff --git a/packages/x-date-pickers/src/AdapterDateFnsV3/index.ts b/packages/x-date-pickers/src/AdapterDateFnsV3/index.ts deleted file mode 100644 index ebecde913f306..0000000000000 --- a/packages/x-date-pickers/src/AdapterDateFnsV3/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { AdapterDateFns } from './AdapterDateFnsV3'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b89f912df0080..fc277817f9b51 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -215,12 +215,12 @@ importers: danger: specifier: ^12.3.3 version: 12.3.3(encoding@0.1.13) - date-fns-jalali-v4: - specifier: npm:date-fns-jalali@4.1.0-0 - version: date-fns-jalali@4.1.0-0 - date-fns-v4: - specifier: npm:date-fns@4.1.0 - version: date-fns@4.1.0 + date-fns-jalali-v2: + specifier: npm:date-fns-jalali@2.30.0-0 + version: date-fns-jalali@2.30.0-0 + date-fns-v2: + specifier: npm:date-fns@2.30.0 + version: date-fns@2.30.0 eslint: specifier: ^8.57.1 version: 8.57.1 @@ -528,11 +528,11 @@ importers: specifier: ^3.1.0 version: 3.1.0 date-fns: - specifier: ^2.30.0 - version: 2.30.0 + specifier: ^4.1.0 + version: 4.1.0 date-fns-jalali: - specifier: ^2.30.0-0 - version: 2.30.0-0 + specifier: ^4.1.0-0 + version: 4.1.0-0 dayjs: specifier: ^1.11.13 version: 1.11.13 @@ -1151,8 +1151,8 @@ importers: specifier: ^15.7.14 version: 15.7.14 date-fns: - specifier: ^2.30.0 - version: 2.30.0 + specifier: ^4.1.0 + version: 4.1.0 rimraf: specifier: ^6.0.1 version: 6.0.1 @@ -1275,11 +1275,11 @@ importers: specifier: ^15.7.14 version: 15.7.14 date-fns: - specifier: ^2.30.0 - version: 2.30.0 + specifier: ^4.1.0 + version: 4.1.0 date-fns-jalali: - specifier: ^2.30.0-0 - version: 2.30.0-0 + specifier: ^4.1.0-0 + version: 4.1.0-0 dayjs: specifier: ^1.11.13 version: 1.11.13 @@ -1364,11 +1364,11 @@ importers: specifier: ^15.7.14 version: 15.7.14 date-fns: - specifier: ^2.30.0 - version: 2.30.0 + specifier: ^4.1.0 + version: 4.1.0 date-fns-jalali: - specifier: ^2.30.0-0 - version: 2.30.0-0 + specifier: ^4.1.0-0 + version: 4.1.0-0 dayjs: specifier: ^1.11.13 version: 1.11.13 diff --git a/test/utils/pickers/createPickerRenderer.tsx b/test/utils/pickers/createPickerRenderer.tsx index 9a353651b344e..a1a615586315c 100644 --- a/test/utils/pickers/createPickerRenderer.tsx +++ b/test/utils/pickers/createPickerRenderer.tsx @@ -5,7 +5,7 @@ import { AdapterClassToUse, AdapterName, adapterToUse, availableAdapters } from interface CreatePickerRendererOptions extends CreateRendererOptions { // Set-up locale with date-fns object. Other are deduced from `locale.code` - locale?: Locale; + locale?: { code: string } | any; adapterName?: AdapterName; instance?: any; } From 86d6e2a6660abc8aa8bbaa0f766aafd09ff3c8f7 Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Tue, 7 Jan 2025 17:39:23 -0500 Subject: [PATCH 19/25] [DataGrid] Refactor: create tooltip props (#16086) --- .../x-data-grid/src/models/gridBaseSlots.ts | 6 ++++++ .../src/models/gridSlotsComponentsProps.ts | 21 ++++++++++++------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/packages/x-data-grid/src/models/gridBaseSlots.ts b/packages/x-data-grid/src/models/gridBaseSlots.ts index 0fd571d9c0ab9..58175695e28eb 100644 --- a/packages/x-data-grid/src/models/gridBaseSlots.ts +++ b/packages/x-data-grid/src/models/gridBaseSlots.ts @@ -66,3 +66,9 @@ export type SkeletonProps = { width?: number | string; height?: number | string; }; + +export type TooltipProps = { + children: React.ReactElement; + enterDelay?: number; + title: React.ReactNode; +}; diff --git a/packages/x-data-grid/src/models/gridSlotsComponentsProps.ts b/packages/x-data-grid/src/models/gridSlotsComponentsProps.ts index 661671952075d..83ae4d9e924ff 100644 --- a/packages/x-data-grid/src/models/gridSlotsComponentsProps.ts +++ b/packages/x-data-grid/src/models/gridSlotsComponentsProps.ts @@ -12,7 +12,7 @@ import type { SelectProps } from '@mui/material/Select'; import type { SwitchProps } from '@mui/material/Switch'; import type { IconButtonProps as MUIIconButtonProps } from '@mui/material/IconButton'; import type { InputAdornmentProps } from '@mui/material/InputAdornment'; -import type { TooltipProps } from '@mui/material/Tooltip'; +import type { TooltipProps as MUITooltipProps } from '@mui/material/Tooltip'; import type { InputLabelProps } from '@mui/material/InputLabel'; import type { PopperProps } from '@mui/material/Popper'; import type { TablePaginationProps } from '@mui/material/TablePagination'; @@ -44,6 +44,7 @@ import type { LinearProgressProps, MenuItemProps, SkeletonProps, + TooltipProps, } from './gridBaseSlots'; type RootProps = React.HTMLAttributes & Record<`data-${string}`, string>; @@ -125,6 +126,7 @@ interface MaterialSlotProps { baseLinearProgress: MUILinearProgressProps; baseCircularProgress: MUICircularProgressProps; baseMenuItem: MUIMenuItemProps; + baseTooltip: MUITooltipProps; } interface ElementSlotProps { @@ -160,14 +162,17 @@ interface ElementSlotProps { } // Merge MUI types into base types to keep slotProps working. +type Select = K extends keyof A ? A[K] : K extends keyof B ? B[K] : never; type Merge = { - [K in keyof A | keyof B]: K extends keyof A & keyof B - ? A[K] & B[K] - : K extends keyof B - ? B[K] - : K extends keyof A - ? A[K] - : never; + [K in keyof A | keyof B]: K extends 'ref' + ? Select + : K extends keyof A & keyof B + ? A[K] & B[K] + : K extends keyof B + ? B[K] + : K extends keyof A + ? A[K] + : never; }; export type GridSlotProps = Merge & ElementSlotProps; From 3fe74a95d53dc96214fa7584e37f724da7785e13 Mon Sep 17 00:00:00 2001 From: Jose C Quintas Jr Date: Wed, 8 Jan 2025 16:18:31 +0100 Subject: [PATCH 20/25] [charts] New HTML legend & styles (#15733) Signed-off-by: Jose C Quintas Jr Co-authored-by: Alexandre Fauquette <45398769+alexfauquette@users.noreply.github.com> --- docs/data/charts/bars/BarGapNoSnap.js | 1 - docs/data/charts/bars/BarsDataset.js | 1 + docs/data/charts/bars/BarsDataset.tsx | 1 + docs/data/charts/bars/BorderRadius.js | 3 +- docs/data/charts/bars/BorderRadius.tsx | 3 +- docs/data/charts/bars/StackBars.js | 11 +- docs/data/charts/bars/StackBars.tsx | 13 +- docs/data/charts/bars/StackBars.tsx.preview | 4 +- docs/data/charts/components/HtmlLegend.js | 6 +- docs/data/charts/components/HtmlLegend.tsx | 6 +- docs/data/charts/components/components.md | 4 +- docs/data/charts/heatmap/ColorConfig.js | 1 + docs/data/charts/heatmap/ColorConfig.tsx | 1 + docs/data/charts/label/PieLabel.js | 2 +- docs/data/charts/label/PieLabel.tsx | 2 +- docs/data/charts/legend/BasicColorLegend.js | 22 +- docs/data/charts/legend/BasicColorLegend.tsx | 22 +- .../legend/ContinuousInteractiveDemoNoSnap.js | 185 +++--- docs/data/charts/legend/HiddenLegend.js | 26 +- docs/data/charts/legend/HiddenLegend.tsx | 26 +- .../charts/legend/HiddenLegend.tsx.preview | 16 +- docs/data/charts/legend/LegendClickNoSnap.js | 65 +- .../charts/legend/LegendDimensionNoSnap.js | 103 +-- .../charts/legend/LegendLabelPositions.js | 203 ++++++ .../charts/legend/LegendLabelPositions.tsx | 204 ++++++ .../charts/legend/LegendMarkTypeNoSnap.js | 64 ++ .../charts/legend/LegendPositionNoSnap.js | 67 +- .../data/charts/legend/LegendRoundedSymbol.js | 29 - .../charts/legend/LegendRoundedSymbol.tsx | 29 - .../legend/LegendRoundedSymbol.tsx.preview | 10 - .../charts/legend/LegendTextStylingNoSnap.js | 91 +-- .../legend/PiecewiseInteractiveDemoNoSnap.js | 197 +++--- docs/data/charts/legend/ScrollableLegend.js | 47 ++ docs/data/charts/legend/ScrollableLegend.tsx | 47 ++ .../legend/ScrollableLegend.tsx.preview | 15 + .../charts/legend/VeryBasicColorLegend.js | 62 ++ .../charts/legend/VeryBasicColorLegend.tsx | 62 ++ .../legend/VeryBasicColorLegend.tsx.preview | 15 + docs/data/charts/legend/legend.md | 93 ++- .../pie-demo/PieChartWithCenterLabel.js | 2 +- .../pie-demo/PieChartWithCenterLabel.tsx | 2 +- .../charts/pie-demo/StraightAnglePieChart.js | 1 + .../charts/pie-demo/StraightAnglePieChart.tsx | 1 + .../StraightAnglePieChart.tsx.preview | 1 + docs/data/charts/pie/BasicPie.js | 2 +- docs/data/charts/pie/BasicPie.tsx | 2 +- docs/data/charts/pie/BasicPie.tsx.preview | 2 +- docs/data/charts/pie/PieActiveArc.js | 1 + docs/data/charts/pie/PieActiveArc.tsx | 1 + docs/data/charts/pie/PieActiveArc.tsx.preview | 1 + docs/data/charts/pie/PieAnimation.js | 1 + docs/data/charts/pie/PieAnimation.tsx | 1 + docs/data/charts/pie/PieArcLabel.js | 2 +- docs/data/charts/pie/PieArcLabel.tsx | 2 +- docs/data/charts/pie/PieClickNoSnap.js | 2 +- docs/data/charts/scatter/ScatterDataset.js | 1 + docs/data/charts/scatter/ScatterDataset.tsx | 1 + docs/data/charts/styling/BasicColor.js | 2 +- docs/data/charts/styling/BasicColor.tsx | 2 +- docs/data/charts/styling/ColorTemplate.js | 6 +- docs/data/charts/styling/ColorTemplate.tsx | 6 +- docs/data/charts/styling/MuiColorTemplate.js | 8 +- docs/data/charts/styling/MuiColorTemplate.tsx | 8 +- docs/data/charts/styling/PatternPie.js | 75 +-- docs/data/charts/styling/PatternPie.tsx | 75 +-- docs/data/charts/tooltip/AxisFormatter.js | 1 + docs/data/charts/tooltip/AxisFormatter.tsx | 1 + docs/data/charts/tooltip/SeriesFormatter.js | 2 +- docs/data/charts/tooltip/SeriesFormatter.tsx | 2 +- docs/data/chartsApiPages.ts | 4 - .../migration-charts-v7.md | 19 + docs/pages/x/api/charts/bar-chart.json | 4 +- docs/pages/x/api/charts/bar-series-type.json | 1 + docs/pages/x/api/charts/charts-legend.json | 54 +- .../x/api/charts/continuous-color-legend.json | 113 +++- .../x/api/charts/default-charts-legend.js | 23 - .../x/api/charts/default-charts-legend.json | 91 --- docs/pages/x/api/charts/line-chart.json | 4 +- docs/pages/x/api/charts/line-series-type.json | 1 + docs/pages/x/api/charts/pie-chart.json | 4 +- docs/pages/x/api/charts/pie-series-type.json | 1 + .../x/api/charts/piecewise-color-legend.json | 98 +-- docs/pages/x/api/charts/scatter-chart.json | 4 +- .../x/api/charts/scatter-series-type.json | 1 + .../api-docs/charts/bar-series-type.json | 3 + .../charts/charts-legend/charts-legend.json | 26 +- .../continuous-color-legend.json | 59 +- .../default-charts-legend.json | 45 -- .../api-docs/charts/line-series-type.json | 3 + .../api-docs/charts/pie-series-type.json | 3 + .../piecewise-color-legend.json | 57 +- .../api-docs/charts/scatter-series-type.json | 3 + .../src/BarChartPro/BarChartPro.tsx | 45 +- .../src/LineChartPro/LineChartPro.tsx | 57 +- .../src/ScatterChartPro/ScatterChartPro.tsx | 47 +- .../x-charts/src/BarChart/BarChart.test.tsx | 1 + packages/x-charts/src/BarChart/BarChart.tsx | 43 +- packages/x-charts/src/BarChart/legend.ts | 3 +- .../x-charts/src/BarChart/useBarChartProps.ts | 16 +- .../src/ChartsLabel/ChartsLabel.test.tsx | 11 +- .../x-charts/src/ChartsLabel/ChartsLabel.tsx | 20 +- .../ChartsLabel/ChartsLabelGradient.test.tsx | 2 +- .../src/ChartsLabel/ChartsLabelGradient.tsx | 57 +- .../src/ChartsLabel/ChartsLabelMark.test.tsx | 2 +- .../src/ChartsLabel/ChartsLabelMark.tsx | 6 +- packages/x-charts/src/ChartsLabel/index.ts | 9 + .../x-charts/src/ChartsLabel/labelClasses.ts | 2 - .../src/ChartsLabel/labelGradientClasses.tsx | 11 +- .../src/ChartsLabel/labelMarkClasses.ts | 7 +- .../src/ChartsLegend/ChartsLegend.test.tsx | 43 ++ .../src/ChartsLegend/ChartsLegend.tsx | 266 ++++---- .../src/ChartsLegend/ChartsLegendItem.tsx | 87 --- .../ContinuousColorLegend.test.tsx | 53 ++ .../ChartsLegend/ContinuousColorLegend.tsx | 610 ++++++++---------- .../src/ChartsLegend/DefaultChartsLegend.tsx | 145 ----- .../src/ChartsLegend/LegendPerItem.tsx | 215 ------ .../PiecewiseColorLegend.test.tsx | 52 ++ .../src/ChartsLegend/PiecewiseColorLegend.tsx | 424 +++++++----- .../src/ChartsLegend/chartsLegend.types.ts | 91 +-- .../src/ChartsLegend/chartsLegendClasses.ts | 34 +- .../src/ChartsLegend/colorLegend.types.ts | 14 + .../continuousColorLegendClasses.ts | 64 ++ .../x-charts/src/ChartsLegend/direction.ts | 1 + packages/x-charts/src/ChartsLegend/index.ts | 17 +- .../x-charts/src/ChartsLegend/legend.types.ts | 68 +- .../src/ChartsLegend/legendContext.types.ts | 62 ++ .../src/ChartsLegend/legendItemsPlacement.ts | 92 --- .../src/ChartsLegend/onClickContextBuilder.ts | 10 + .../piecewiseColorDefaultLabelFormatter.ts | 11 + .../piecewiseColorLegend.types.ts | 26 + .../piecewiseColorLegendClasses.ts | 65 ++ packages/x-charts/src/ChartsLegend/useAxis.ts | 2 +- .../src/ChartsSurface/ChartsSurface.tsx | 1 - .../ChartsTooltip/contentDisplayed.test.tsx | 5 +- .../x-charts/src/LineChart/LineChart.test.tsx | 1 + packages/x-charts/src/LineChart/LineChart.tsx | 55 +- packages/x-charts/src/LineChart/legend.ts | 3 +- .../src/LineChart/useLineChartProps.ts | 16 +- .../x-charts/src/PieChart/PieArcLabelPlot.tsx | 1 + packages/x-charts/src/PieChart/PieArcPlot.tsx | 1 + .../x-charts/src/PieChart/PieChart.test.tsx | 1 + packages/x-charts/src/PieChart/PieChart.tsx | 78 ++- packages/x-charts/src/PieChart/legend.ts | 3 +- .../src/ScatterChart/ScatterChart.test.tsx | 1 + .../src/ScatterChart/ScatterChart.tsx | 45 +- packages/x-charts/src/ScatterChart/legend.ts | 3 +- .../src/ScatterChart/useScatterChartProps.ts | 16 +- packages/x-charts/src/constants/index.ts | 1 + .../PluginProvider/SeriesFormatter.types.ts | 2 +- packages/x-charts/src/hooks/index.ts | 1 + .../utils.ts => hooks/useLegend.ts} | 21 +- packages/x-charts/src/index.ts | 1 + .../src/internals/calculateMargins.ts | 51 ++ .../ChartsAxesGradients.tsx | 89 ++- .../ChartsContinuousGradient.tsx | 18 +- .../ChartsContinuousGradientObjectBound.tsx | 62 ++ .../ChartsPiecewiseGradient.tsx | 4 + .../ChartsWrapper/ChartsWrapper.tsx | 82 +++ .../components/ChartsWrapper/index.ts | 1 + .../src/internals/consumeSlots.test.tsx | 103 +++ .../x-charts/src/internals/consumeSlots.tsx | 121 ++++ .../src/internals/consumeThemeProps.test.tsx | 52 ++ .../src/internals/consumeThemeProps.tsx | 42 +- packages/x-charts/src/internals/index.ts | 1 + .../x-charts/src/models/seriesType/common.ts | 9 + .../x-charts/src/models/seriesType/pie.ts | 9 + .../themeAugmentation.spec.ts | 2 +- packages/x-codemod/README.md | 16 + .../v8.0.0/charts/preset-safe/actual.spec.tsx | 5 +- .../charts/preset-safe/expected.spec.tsx | 21 +- .../src/v8.0.0/charts/preset-safe/index.ts | 3 + .../actual.spec.tsx | 10 + .../expected.spec.tsx | 26 + .../replace-legend-direction-values/index.ts | 75 +++ .../replace-legend-direction-values.test.ts | 38 ++ packages/x-internals/src/types/AppendKeys.ts | 16 + packages/x-internals/src/types/PrependKeys.ts | 16 + packages/x-internals/src/types/index.ts | 2 + scripts/buildApiDocs/chartsSettings/index.ts | 1 - scripts/x-charts-pro.exports.json | 29 +- scripts/x-charts.exports.json | 36 +- 181 files changed, 4000 insertions(+), 2581 deletions(-) create mode 100644 docs/data/charts/legend/LegendLabelPositions.js create mode 100644 docs/data/charts/legend/LegendLabelPositions.tsx create mode 100644 docs/data/charts/legend/LegendMarkTypeNoSnap.js delete mode 100644 docs/data/charts/legend/LegendRoundedSymbol.js delete mode 100644 docs/data/charts/legend/LegendRoundedSymbol.tsx delete mode 100644 docs/data/charts/legend/LegendRoundedSymbol.tsx.preview create mode 100644 docs/data/charts/legend/ScrollableLegend.js create mode 100644 docs/data/charts/legend/ScrollableLegend.tsx create mode 100644 docs/data/charts/legend/ScrollableLegend.tsx.preview create mode 100644 docs/data/charts/legend/VeryBasicColorLegend.js create mode 100644 docs/data/charts/legend/VeryBasicColorLegend.tsx create mode 100644 docs/data/charts/legend/VeryBasicColorLegend.tsx.preview delete mode 100644 docs/pages/x/api/charts/default-charts-legend.js delete mode 100644 docs/pages/x/api/charts/default-charts-legend.json delete mode 100644 docs/translations/api-docs/charts/default-charts-legend/default-charts-legend.json create mode 100644 packages/x-charts/src/ChartsLabel/index.ts create mode 100644 packages/x-charts/src/ChartsLegend/ChartsLegend.test.tsx delete mode 100644 packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx create mode 100644 packages/x-charts/src/ChartsLegend/ContinuousColorLegend.test.tsx delete mode 100644 packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx delete mode 100644 packages/x-charts/src/ChartsLegend/LegendPerItem.tsx create mode 100644 packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.test.tsx create mode 100644 packages/x-charts/src/ChartsLegend/colorLegend.types.ts create mode 100644 packages/x-charts/src/ChartsLegend/continuousColorLegendClasses.ts create mode 100644 packages/x-charts/src/ChartsLegend/direction.ts create mode 100644 packages/x-charts/src/ChartsLegend/legendContext.types.ts delete mode 100644 packages/x-charts/src/ChartsLegend/legendItemsPlacement.ts create mode 100644 packages/x-charts/src/ChartsLegend/onClickContextBuilder.ts create mode 100644 packages/x-charts/src/ChartsLegend/piecewiseColorDefaultLabelFormatter.ts create mode 100644 packages/x-charts/src/ChartsLegend/piecewiseColorLegend.types.ts create mode 100644 packages/x-charts/src/ChartsLegend/piecewiseColorLegendClasses.ts rename packages/x-charts/src/{ChartsLegend/utils.ts => hooks/useLegend.ts} (57%) create mode 100644 packages/x-charts/src/internals/calculateMargins.ts create mode 100644 packages/x-charts/src/internals/components/ChartsAxesGradients/ChartsContinuousGradientObjectBound.tsx create mode 100644 packages/x-charts/src/internals/components/ChartsWrapper/ChartsWrapper.tsx create mode 100644 packages/x-charts/src/internals/components/ChartsWrapper/index.ts create mode 100644 packages/x-charts/src/internals/consumeSlots.test.tsx create mode 100644 packages/x-charts/src/internals/consumeSlots.tsx create mode 100644 packages/x-charts/src/internals/consumeThemeProps.test.tsx create mode 100644 packages/x-codemod/src/v8.0.0/charts/replace-legend-direction-values/actual.spec.tsx create mode 100644 packages/x-codemod/src/v8.0.0/charts/replace-legend-direction-values/expected.spec.tsx create mode 100644 packages/x-codemod/src/v8.0.0/charts/replace-legend-direction-values/index.ts create mode 100644 packages/x-codemod/src/v8.0.0/charts/replace-legend-direction-values/replace-legend-direction-values.test.ts create mode 100644 packages/x-internals/src/types/AppendKeys.ts create mode 100644 packages/x-internals/src/types/PrependKeys.ts diff --git a/docs/data/charts/bars/BarGapNoSnap.js b/docs/data/charts/bars/BarGapNoSnap.js index 630182ccf84ee..89f97e61378d0 100644 --- a/docs/data/charts/bars/BarGapNoSnap.js +++ b/docs/data/charts/bars/BarGapNoSnap.js @@ -35,7 +35,6 @@ export default function BarGapNoSnap() { = { }, slotProps: { legend: { - direction: 'row', + direction: 'horizontal', position: { vertical: 'bottom', horizontal: 'middle' }, - padding: -5, }, }, }; diff --git a/docs/data/charts/bars/StackBars.js b/docs/data/charts/bars/StackBars.js index 1a327b699d990..8ddb6023367df 100644 --- a/docs/data/charts/bars/StackBars.js +++ b/docs/data/charts/bars/StackBars.js @@ -16,9 +16,14 @@ export default function StackBars() { { dataKey: 'treas', stack: 'equity' }, ])} xAxis={[{ scaleType: 'band', dataKey: 'year' }]} - hideLegend - width={600} - height={350} + {...config} /> ); } + +const config = { + width: 600, + height: 350, + margin: { left: 70 }, + hideLegend: true, +}; diff --git a/docs/data/charts/bars/StackBars.tsx b/docs/data/charts/bars/StackBars.tsx index 1a327b699d990..0849d4933e74e 100644 --- a/docs/data/charts/bars/StackBars.tsx +++ b/docs/data/charts/bars/StackBars.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { BarChart } from '@mui/x-charts/BarChart'; +import { BarChart, BarChartProps } from '@mui/x-charts/BarChart'; import { addLabels, balanceSheet } from './netflixsBalanceSheet'; export default function StackBars() { @@ -16,9 +16,14 @@ export default function StackBars() { { dataKey: 'treas', stack: 'equity' }, ])} xAxis={[{ scaleType: 'band', dataKey: 'year' }]} - hideLegend - width={600} - height={350} + {...config} /> ); } + +const config: Partial = { + width: 600, + height: 350, + margin: { left: 70 }, + hideLegend: true, +}; diff --git a/docs/data/charts/bars/StackBars.tsx.preview b/docs/data/charts/bars/StackBars.tsx.preview index d959a8e274dcf..22bacafb6767a 100644 --- a/docs/data/charts/bars/StackBars.tsx.preview +++ b/docs/data/charts/bars/StackBars.tsx.preview @@ -10,7 +10,5 @@ { dataKey: 'treas', stack: 'equity' }, ])} xAxis={[{ scaleType: 'band', dataKey: 'year' }]} - hideLegend - width={600} - height={350} + {...config} /> \ No newline at end of file diff --git a/docs/data/charts/components/HtmlLegend.js b/docs/data/charts/components/HtmlLegend.js index a58701b379a8f..b716c8e433055 100644 --- a/docs/data/charts/components/HtmlLegend.js +++ b/docs/data/charts/components/HtmlLegend.js @@ -1,6 +1,6 @@ import * as React from 'react'; import Box from '@mui/material/Box'; -import { unstable_useBarSeries } from '@mui/x-charts/hooks'; +import { useLegend } from '@mui/x-charts/hooks'; import { ChartDataProvider } from '@mui/x-charts/context'; import { ChartsSurface } from '@mui/x-charts/ChartsSurface'; import { BarPlot } from '@mui/x-charts/BarChart'; @@ -8,7 +8,7 @@ import { ChartsXAxis } from '@mui/x-charts/ChartsXAxis'; import { ChartsYAxis } from '@mui/x-charts/ChartsYAxis'; function MyCustomLegend() { - const s = unstable_useBarSeries(); + const { items } = useLegend(); return ( - {Object.values(s?.series ?? []).map((v) => { + {items.map((v) => { return (
diff --git a/docs/data/charts/components/HtmlLegend.tsx b/docs/data/charts/components/HtmlLegend.tsx index a58701b379a8f..b716c8e433055 100644 --- a/docs/data/charts/components/HtmlLegend.tsx +++ b/docs/data/charts/components/HtmlLegend.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import Box from '@mui/material/Box'; -import { unstable_useBarSeries } from '@mui/x-charts/hooks'; +import { useLegend } from '@mui/x-charts/hooks'; import { ChartDataProvider } from '@mui/x-charts/context'; import { ChartsSurface } from '@mui/x-charts/ChartsSurface'; import { BarPlot } from '@mui/x-charts/BarChart'; @@ -8,7 +8,7 @@ import { ChartsXAxis } from '@mui/x-charts/ChartsXAxis'; import { ChartsYAxis } from '@mui/x-charts/ChartsYAxis'; function MyCustomLegend() { - const s = unstable_useBarSeries(); + const { items } = useLegend(); return ( - {Object.values(s?.series ?? []).map((v) => { + {items.map((v) => { return (
diff --git a/docs/data/charts/components/components.md b/docs/data/charts/components/components.md index 791c338ced4fe..c89a0ef699d0e 100644 --- a/docs/data/charts/components/components.md +++ b/docs/data/charts/components/components.md @@ -83,7 +83,7 @@ With the introduction of the `ChartDataProvider` in v8, the chart data can be ac This allows you to create HTML components that interact with the charts data. In the next example, notice that `MyCustomLegend` component displays the series names and colors. -This creates an html `table` element, which handles long series names better than the default legend. +This creates an html `table` element, which can be customized in any way. {{"demo": "HtmlLegend.js"}} @@ -91,7 +91,7 @@ This creates an html `table` element, which handles long series names better tha Note that the HTML components are not part of the SVG hierarchy. Hence, they should be: -- Outside the `` component to avoid mixing HTAM and SVG. +- Outside the `` component to avoid mixing HTML and SVG. - Inside the `` component to get access to the data. ::: diff --git a/docs/data/charts/heatmap/ColorConfig.js b/docs/data/charts/heatmap/ColorConfig.js index b20e75a7a1181..16b4f95bd98a4 100644 --- a/docs/data/charts/heatmap/ColorConfig.js +++ b/docs/data/charts/heatmap/ColorConfig.js @@ -107,6 +107,7 @@ export default function ColorConfig() { xAxis={[{ data: xData }]} yAxis={[{ data: yData }]} series={[{ data }]} + margin={{ left: 70 }} zAxis={[ { min: 20, diff --git a/docs/data/charts/heatmap/ColorConfig.tsx b/docs/data/charts/heatmap/ColorConfig.tsx index ee09304de139d..d71f65a9df85e 100644 --- a/docs/data/charts/heatmap/ColorConfig.tsx +++ b/docs/data/charts/heatmap/ColorConfig.tsx @@ -110,6 +110,7 @@ export default function ColorConfig() { xAxis={[{ data: xData }]} yAxis={[{ data: yData }]} series={[{ data }]} + margin={{ left: 70 }} zAxis={[ { min: 20, diff --git a/docs/data/charts/label/PieLabel.js b/docs/data/charts/label/PieLabel.js index f363fbac7e81d..78f4259cd41de 100644 --- a/docs/data/charts/label/PieLabel.js +++ b/docs/data/charts/label/PieLabel.js @@ -21,6 +21,6 @@ export default function PieLabel() { } const props = { - width: 500, + width: 200, height: 200, }; diff --git a/docs/data/charts/label/PieLabel.tsx b/docs/data/charts/label/PieLabel.tsx index f363fbac7e81d..78f4259cd41de 100644 --- a/docs/data/charts/label/PieLabel.tsx +++ b/docs/data/charts/label/PieLabel.tsx @@ -21,6 +21,6 @@ export default function PieLabel() { } const props = { - width: 500, + width: 200, height: 200, }; diff --git a/docs/data/charts/legend/BasicColorLegend.js b/docs/data/charts/legend/BasicColorLegend.js index cb3af11c0885b..481f6e61f62e2 100644 --- a/docs/data/charts/legend/BasicColorLegend.js +++ b/docs/data/charts/legend/BasicColorLegend.js @@ -3,11 +3,12 @@ import Typography from '@mui/material/Typography'; import { LineChart } from '@mui/x-charts/LineChart'; import { ChartsReferenceLine } from '@mui/x-charts/ChartsReferenceLine'; import { PiecewiseColorLegend } from '@mui/x-charts/ChartsLegend'; +import Stack from '@mui/material/Stack'; import { dataset } from './tempAnomaly'; export default function BasicColorLegend() { return ( -
+ Global temperature anomaly relative to 1961-1990 average @@ -43,16 +44,19 @@ export default function BasicColorLegend() { ]} grid={{ horizontal: true }} height={300} - margin={{ top: 30, right: 150 }} - hideLegend + margin={{ top: 20, right: 20 }} + slotProps={{ + legend: { + axisDirection: 'x', + direction: 'vertical', + }, + }} + slots={{ + legend: PiecewiseColorLegend, + }} > - -
+ ); } diff --git a/docs/data/charts/legend/BasicColorLegend.tsx b/docs/data/charts/legend/BasicColorLegend.tsx index cb3af11c0885b..481f6e61f62e2 100644 --- a/docs/data/charts/legend/BasicColorLegend.tsx +++ b/docs/data/charts/legend/BasicColorLegend.tsx @@ -3,11 +3,12 @@ import Typography from '@mui/material/Typography'; import { LineChart } from '@mui/x-charts/LineChart'; import { ChartsReferenceLine } from '@mui/x-charts/ChartsReferenceLine'; import { PiecewiseColorLegend } from '@mui/x-charts/ChartsLegend'; +import Stack from '@mui/material/Stack'; import { dataset } from './tempAnomaly'; export default function BasicColorLegend() { return ( -
+ Global temperature anomaly relative to 1961-1990 average @@ -43,16 +44,19 @@ export default function BasicColorLegend() { ]} grid={{ horizontal: true }} height={300} - margin={{ top: 30, right: 150 }} - hideLegend + margin={{ top: 20, right: 20 }} + slotProps={{ + legend: { + axisDirection: 'x', + direction: 'vertical', + }, + }} + slots={{ + legend: PiecewiseColorLegend, + }} > - -
+ ); } diff --git a/docs/data/charts/legend/ContinuousInteractiveDemoNoSnap.js b/docs/data/charts/legend/ContinuousInteractiveDemoNoSnap.js index 09feb0234a322..ad79ebd83f4c5 100644 --- a/docs/data/charts/legend/ContinuousInteractiveDemoNoSnap.js +++ b/docs/data/charts/legend/ContinuousInteractiveDemoNoSnap.js @@ -1,3 +1,4 @@ +// @ts-check import * as React from 'react'; import ChartsUsageDemo from 'docsx/src/modules/components/ChartsUsageDemo'; import { interpolateRdYlBu } from 'd3-scale-chromatic'; @@ -14,121 +15,113 @@ export default function ContinuousInteractiveDemoNoSnap() { { propName: 'direction', knob: 'select', - defaultValue: 'row', - options: ['row', 'column'], + defaultValue: 'horizontal', + options: ['horizontal', 'vertical'], + }, + { + propName: 'labelPosition', + knob: 'select', + defaultValue: 'end', + options: ['start', 'end', 'extremes'], }, { propName: 'length', knob: 'number', defaultValue: 50, min: 10, - max: 80, }, { propName: 'thickness', knob: 'number', - defaultValue: 5, + defaultValue: 12, min: 1, max: 20, }, { - propName: 'align', - knob: 'select', - defaultValue: 'middle', - options: ['start', 'middle', 'end'], - }, - { - propName: 'fontSize', - knob: 'number', - defaultValue: 10, - min: 8, - max: 20, + propName: 'reverse', + knob: 'switch', + defaultValue: false, }, ]} - renderDemo={(props) => ( -
- `${value?.toFixed(2)}°`, - }, - ]} - xAxis={[ - { - scaleType: 'time', - dataKey: 'year', - disableLine: true, - valueFormatter: (value) => value.getFullYear().toString(), + renderDemo={( + /** @type {{ direction: "horizontal" | "vertical"; length: number; thickness: number; labelPosition: 'start' | 'end' | 'extremes'; reverse: boolean; }} */ + props, + ) => ( + `${value?.toFixed(2)}°`, + }, + ]} + xAxis={[ + { + scaleType: 'time', + dataKey: 'year', + disableLine: true, + valueFormatter: (value) => value.getFullYear().toString(), + }, + ]} + yAxis={[ + { + disableLine: true, + disableTicks: true, + valueFormatter: (value) => `${value}°`, + colorMap: { + type: 'continuous', + min: -0.5, + max: 1.5, + color: (t) => interpolateRdYlBu(1 - t), }, - ]} - yAxis={[ - { - disableLine: true, - disableTicks: true, - valueFormatter: (value) => `${value}°`, - colorMap: { - type: 'continuous', - min: -0.5, - max: 1.5, - color: (t) => interpolateRdYlBu(1 - t), - }, + }, + ]} + grid={{ horizontal: true }} + height={300} + margin={{ top: 20, right: 20 }} + slots={{ legend: ContinuousColorLegend }} + slotProps={{ + legend: { + axisDirection: 'y', + direction: props.direction, + thickness: props.thickness, + labelPosition: props.labelPosition, + reverse: props.reverse, + sx: { + [props.direction === 'horizontal' ? 'width' : 'height']: + `${props.length}${props.direction === 'horizontal' ? '%' : 'px'}`, }, - ]} - grid={{ horizontal: true }} - height={300} - margin={{ - top: props.direction === 'row' ? 50 : 20, - right: props.direction === 'row' ? 20 : 50, - }} - hideLegend - > - - - -
+ }, + }} + > + + )} - getCode={({ props }) => { - return [ - `import { LineChart } from '@mui/x-charts/LineChart';`, - `import { ContinuousColorLegend } from '@mui/x-charts/ChartsLegend';`, - '', - `', - ` `, - '', - ].join('\n'); + getCode={( + /** @type {{props: { direction: "horizontal" | "vertical"; length: number; thickness: number; labelPosition: 'start' | 'end' | 'extremes'; reverse: boolean; }}} */ + { props }, + ) => { + return ` +import { ContinuousColorLegend } from '@mui/x-charts/ChartsLegend'; + + +`; }} /> ); diff --git a/docs/data/charts/legend/HiddenLegend.js b/docs/data/charts/legend/HiddenLegend.js index 80879da5f9bf5..d33b0ffa42de2 100644 --- a/docs/data/charts/legend/HiddenLegend.js +++ b/docs/data/charts/legend/HiddenLegend.js @@ -17,22 +17,20 @@ const series = [ export default function HiddenLegend() { const [isHidden, setIsHidden] = React.useState(false); + const Toggle = ( + setIsHidden(event.target.checked)} />} + label="hide the legend" + labelPlacement="end" + sx={{ margin: 'auto' }} + /> + ); + return ( - setIsHidden(event.target.checked)} /> - } - label="hide the legend" - labelPlacement="end" - /> - + {Toggle} + ); } diff --git a/docs/data/charts/legend/HiddenLegend.tsx b/docs/data/charts/legend/HiddenLegend.tsx index 80879da5f9bf5..d33b0ffa42de2 100644 --- a/docs/data/charts/legend/HiddenLegend.tsx +++ b/docs/data/charts/legend/HiddenLegend.tsx @@ -17,22 +17,20 @@ const series = [ export default function HiddenLegend() { const [isHidden, setIsHidden] = React.useState(false); + const Toggle = ( + setIsHidden(event.target.checked)} />} + label="hide the legend" + labelPlacement="end" + sx={{ margin: 'auto' }} + /> + ); + return ( - setIsHidden(event.target.checked)} /> - } - label="hide the legend" - labelPlacement="end" - /> - + {Toggle} + ); } diff --git a/docs/data/charts/legend/HiddenLegend.tsx.preview b/docs/data/charts/legend/HiddenLegend.tsx.preview index 52019cf368ffa..c20f9eec4e8c8 100644 --- a/docs/data/charts/legend/HiddenLegend.tsx.preview +++ b/docs/data/charts/legend/HiddenLegend.tsx.preview @@ -1,14 +1,2 @@ - setIsHidden(event.target.checked)} /> - } - label="hide the legend" - labelPlacement="end" -/> - \ No newline at end of file +{Toggle} + \ No newline at end of file diff --git a/docs/data/charts/legend/LegendClickNoSnap.js b/docs/data/charts/legend/LegendClickNoSnap.js index 968e601b061a7..f9ca1551987df 100644 --- a/docs/data/charts/legend/LegendClickNoSnap.js +++ b/docs/data/charts/legend/LegendClickNoSnap.js @@ -1,3 +1,5 @@ +// @ts-check + import * as React from 'react'; import Stack from '@mui/material/Stack'; import Box from '@mui/material/Box'; @@ -8,13 +10,13 @@ import UndoOutlinedIcon from '@mui/icons-material/UndoOutlined'; import { ChartsLegend, PiecewiseColorLegend } from '@mui/x-charts/ChartsLegend'; import { HighlightedCode } from '@mui/docs/HighlightedCode'; -import { ChartContainer } from '@mui/x-charts/ChartContainer'; +import { ChartDataProvider } from '@mui/x-charts/context'; +/** @type {import('@mui/x-charts/PieChart').PieChartProps['series']} */ const pieSeries = [ { type: 'pie', id: 'series-1', - label: 'Series 1', data: [ { label: 'Pie A', id: 'P1-A', value: 400 }, { label: 'Pie B', id: 'P2-B', value: 300 }, @@ -22,6 +24,7 @@ const pieSeries = [ }, ]; +/** @type {import('@mui/x-charts/BarChart').BarChartProps['series']} */ const barSeries = [ { type: 'bar', @@ -37,6 +40,7 @@ const barSeries = [ }, ]; +/** @type {import('@mui/x-charts/LineChart').LineChartProps['series']} */ const lineSeries = [ { type: 'line', @@ -61,31 +65,44 @@ export default function LegendClickNoSnap() { spacing={{ xs: 0, md: 4 }} sx={{ width: '100%' }} > - + Chart Legend - + setItemData([context, index])} /> - +
Pie Chart Legend - + setItemData([context, index])} /> - - Pie Chart Legend - + Piecewise Color Legend + setItemData([context, index])} /> - + @@ -127,6 +141,7 @@ export default function LegendClickNoSnap() { aria-label="reset" size="small" onClick={() => { + // @ts-ignore setItemData(null); }} > diff --git a/docs/data/charts/legend/LegendDimensionNoSnap.js b/docs/data/charts/legend/LegendDimensionNoSnap.js index 2581092596b58..f9dd92f87bb2c 100644 --- a/docs/data/charts/legend/LegendDimensionNoSnap.js +++ b/docs/data/charts/legend/LegendDimensionNoSnap.js @@ -1,6 +1,9 @@ +// @ts-check + import * as React from 'react'; import ChartsUsageDemo from 'docsx/src/modules/components/ChartsUsageDemo'; import { PieChart } from '@mui/x-charts/PieChart'; +import { legendClasses } from '@mui/x-charts/ChartsLegend'; const data = [ { id: 0, value: 10, label: 'Series A' }, @@ -13,7 +16,7 @@ const data = [ { id: 7, value: 15, label: 'Series H' }, ]; -const itemsNumber = 15; +const itemsNumber = 8; export default function LegendDimensionNoSnap() { return ( @@ -23,15 +26,17 @@ export default function LegendDimensionNoSnap() { { propName: 'direction', knob: 'select', - defaultValue: 'column', - options: ['row', 'column'], + defaultValue: 'horizontal', + options: ['horizontal', 'vertical'], }, - { propName: 'itemMarkWidth', knob: 'number', defaultValue: 20 }, - { propName: 'itemMarkHeight', knob: 'number', defaultValue: 2 }, - { propName: 'markGap', knob: 'number', defaultValue: 5 }, - { propName: 'itemGap', knob: 'number', defaultValue: 10 }, + { propName: 'markSize', knob: 'number', defaultValue: 15, min: 0 }, + { propName: 'markGap', knob: 'number', defaultValue: 8, min: 0 }, + { propName: 'itemGap', knob: 'number', defaultValue: 16, min: 0 }, ]} - renderDemo={(props) => ( + renderDemo={( + /** @type {{ direction: "horizontal" | "vertical"; markSize: number; markGap: number; itemGap: number; scrollable: boolean;}} */ + props, + ) => ( )} - getCode={({ props }) => { - return [ - `import { PieChart } from '@mui/x-charts/PieChart';`, - '', - `', - ].join('\n'); + getCode={( + /** @type {{ props: { direction: "horizontal" | "vertical"; markSize: number; markGap: number; itemGap: number; scrollable: boolean;}}} */ + { props }, + ) => { + return ` +import { PieChart } from '@mui/x-charts/PieChart'; +import { legendClasses } from '@mui/x-charts/ChartsLegend'; + + +`; }} /> ); diff --git a/docs/data/charts/legend/LegendLabelPositions.js b/docs/data/charts/legend/LegendLabelPositions.js new file mode 100644 index 0000000000000..4b1817806d249 --- /dev/null +++ b/docs/data/charts/legend/LegendLabelPositions.js @@ -0,0 +1,203 @@ +import * as React from 'react'; +import { interpolateRdYlBu } from 'd3-scale-chromatic'; +import { + ContinuousColorLegend, + piecewiseColorDefaultLabelFormatter, + PiecewiseColorLegend, +} from '@mui/x-charts/ChartsLegend'; +import { ChartDataProvider } from '@mui/x-charts/context'; +import { ChartsAxesGradients } from '@mui/x-charts/internals'; +import Stack from '@mui/material/Stack'; +import Typography from '@mui/material/Typography'; +import Divider from '@mui/material/Divider'; + +export default function LegendLabelPositions() { + const piecewiseFormatter = (params) => + params.index === 0 || params.index === params.length + ? piecewiseColorDefaultLabelFormatter(params) + : ''; + + return ( + `${value}°`, + colorMap: { + type: 'continuous', + min: -0.5, + max: 1.5, + color: (t) => interpolateRdYlBu(1 - t), + }, + }, + ]} + xAxis={[ + { + valueFormatter: (value) => `${value}°`, + colorMap: { + type: 'piecewise', + thresholds: [0, 1.5], + colors: [ + interpolateRdYlBu(0.9), + interpolateRdYlBu(0.5), + interpolateRdYlBu(0.1), + ], + }, + }, + ]} + > + + + Continuous + Horizontal + div': { flex: 1 } }}> +
+ start + +
+
+ end + +
+
+ extremes + +
+
+ + Vertical + div': { + flex: 1, + height: '100%', + display: 'flex', + flexDirection: 'column', + }, + '& .MuiContinuousColorLegend-root': { flex: 1 }, + }} + > +
+ start + +
+
+ end + +
+
+ extremes + +
+
+
+ + Piecewise + Horizontal + div': { flex: 1 } }}> +
+ start + +
+
+ end + +
+
+ extremes + +
+
+ + Vertical + div': { + flex: 1, + height: '100%', + display: 'flex', + flexDirection: 'column', + }, + }} + > +
+ start + +
+
+ end + +
+
+ extremes + +
+
+
+
+ + + +
+ ); +} diff --git a/docs/data/charts/legend/LegendLabelPositions.tsx b/docs/data/charts/legend/LegendLabelPositions.tsx new file mode 100644 index 0000000000000..9494cff502e70 --- /dev/null +++ b/docs/data/charts/legend/LegendLabelPositions.tsx @@ -0,0 +1,204 @@ +import * as React from 'react'; +import { interpolateRdYlBu } from 'd3-scale-chromatic'; +import { + ContinuousColorLegend, + piecewiseColorDefaultLabelFormatter, + PiecewiseColorLegend, + PiecewiseLabelFormatterParams, +} from '@mui/x-charts/ChartsLegend'; +import { ChartDataProvider } from '@mui/x-charts/context'; +import { ChartsAxesGradients } from '@mui/x-charts/internals'; +import Stack from '@mui/material/Stack'; +import Typography from '@mui/material/Typography'; +import Divider from '@mui/material/Divider'; + +export default function LegendLabelPositions() { + const piecewiseFormatter = (params: PiecewiseLabelFormatterParams) => + params.index === 0 || params.index === params.length + ? piecewiseColorDefaultLabelFormatter(params) + : ''; + + return ( + `${value}°`, + colorMap: { + type: 'continuous', + min: -0.5, + max: 1.5, + color: (t) => interpolateRdYlBu(1 - t), + }, + }, + ]} + xAxis={[ + { + valueFormatter: (value) => `${value}°`, + colorMap: { + type: 'piecewise', + thresholds: [0, 1.5], + colors: [ + interpolateRdYlBu(0.9), + interpolateRdYlBu(0.5), + interpolateRdYlBu(0.1), + ], + }, + }, + ]} + > + + + Continuous + Horizontal + div': { flex: 1 } }}> +
+ start + +
+
+ end + +
+
+ extremes + +
+
+ + Vertical + div': { + flex: 1, + height: '100%', + display: 'flex', + flexDirection: 'column', + }, + '& .MuiContinuousColorLegend-root': { flex: 1 }, + }} + > +
+ start + +
+
+ end + +
+
+ extremes + +
+
+
+ + Piecewise + Horizontal + div': { flex: 1 } }}> +
+ start + +
+
+ end + +
+
+ extremes + +
+
+ + Vertical + div': { + flex: 1, + height: '100%', + display: 'flex', + flexDirection: 'column', + }, + }} + > +
+ start + +
+
+ end + +
+
+ extremes + +
+
+
+
+ + + +
+ ); +} diff --git a/docs/data/charts/legend/LegendMarkTypeNoSnap.js b/docs/data/charts/legend/LegendMarkTypeNoSnap.js new file mode 100644 index 0000000000000..a73ca40fd4adf --- /dev/null +++ b/docs/data/charts/legend/LegendMarkTypeNoSnap.js @@ -0,0 +1,64 @@ +// @ts-check + +import * as React from 'react'; +import ChartsUsageDemo from 'docsx/src/modules/components/ChartsUsageDemo'; +import { BarChart } from '@mui/x-charts/BarChart'; + +const seriesConfig = [ + { id: 0, data: [10], label: 'Series A' }, + { id: 1, data: [15], label: 'Series B' }, + { id: 2, data: [20], label: 'Series C' }, + { id: 3, data: [10], label: 'Series D' }, +]; + +export default function LegendMarkTypeNoSnap() { + return ( + ( + ({ + ...seriesItem, + labelMarkType: props.markType, + }))} + xAxis={[ + { + scaleType: 'band', + data: ['A'], + }, + ]} + height={200} + /> + )} + getCode={( + /** @type {{props: { markType: "square" | "circle" | "line" }}} */ + { props }, + ) => { + return ` +import { BarChart } from '@mui/x-charts/BarChart'; + + ({ + ...seriesItem, + labelMarkType: '${props.markType}', + })) + } +/> +`; + }} + /> + ); +} diff --git a/docs/data/charts/legend/LegendPositionNoSnap.js b/docs/data/charts/legend/LegendPositionNoSnap.js index ac23970b9c43e..1a96d35c09952 100644 --- a/docs/data/charts/legend/LegendPositionNoSnap.js +++ b/docs/data/charts/legend/LegendPositionNoSnap.js @@ -1,3 +1,5 @@ +// @ts-check + import * as React from 'react'; import ChartsUsageDemo from 'docsx/src/modules/components/ChartsUsageDemo'; import { PieChart } from '@mui/x-charts/PieChart'; @@ -28,13 +30,13 @@ export default function LegendPositionNoSnap() { { propName: 'direction', knob: 'select', - defaultValue: 'row', - options: ['row', 'column'], + defaultValue: 'vertical', + options: ['horizontal', 'vertical'], }, { propName: 'vertical', knob: 'select', - defaultValue: 'top', + defaultValue: 'middle', options: ['top', 'middle', 'bottom'], }, { @@ -43,59 +45,54 @@ export default function LegendPositionNoSnap() { defaultValue: 'middle', options: ['left', 'middle', 'right'], }, - { - propName: 'padding', - knob: 'number', - defaultValue: 0, - }, { propName: 'itemsNumber', knob: 'number', - defaultValue: 5, + defaultValue: 3, min: 1, max: data.length, }, ]} - renderDemo={(props) => ( + renderDemo={( + /** @type {{ itemsNumber: number | undefined; direction: "horizontal" | "vertical"; vertical: "top" | "middle" | "bottom"; horizontal: "left" | "middle" | "right"; }} */ + props, + ) => ( )} - getCode={({ props }) => { - return [ - `import { PieChart } from '@mui/x-charts/PieChart';`, - '', - `', - ].join('\n'); + getCode={( + /** @type {{props:{ itemsNumber: number | undefined; direction: "horizontal" | "vertical"; vertical: "top" | "middle" | "bottom"; horizontal: "left" | "middle" | "right";}}} */ + { props }, + ) => { + return ` +import { PieChart } from '@mui/x-charts/PieChart'; + + +`; }} /> ); diff --git a/docs/data/charts/legend/LegendRoundedSymbol.js b/docs/data/charts/legend/LegendRoundedSymbol.js deleted file mode 100644 index d5f9b2b864431..0000000000000 --- a/docs/data/charts/legend/LegendRoundedSymbol.js +++ /dev/null @@ -1,29 +0,0 @@ -import * as React from 'react'; -import { PieChart } from '@mui/x-charts/PieChart'; -import { legendClasses } from '@mui/x-charts/ChartsLegend'; - -const series = [ - { - data: [ - { id: 0, value: 10, label: 'series A' }, - { id: 1, value: 15, label: 'series B' }, - { id: 2, value: 20, label: 'series C' }, - { id: 3, value: 30, label: 'series D' }, - ], - }, -]; - -export default function LegendRoundedSymbol() { - return ( - - ); -} diff --git a/docs/data/charts/legend/LegendRoundedSymbol.tsx b/docs/data/charts/legend/LegendRoundedSymbol.tsx deleted file mode 100644 index d5f9b2b864431..0000000000000 --- a/docs/data/charts/legend/LegendRoundedSymbol.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import * as React from 'react'; -import { PieChart } from '@mui/x-charts/PieChart'; -import { legendClasses } from '@mui/x-charts/ChartsLegend'; - -const series = [ - { - data: [ - { id: 0, value: 10, label: 'series A' }, - { id: 1, value: 15, label: 'series B' }, - { id: 2, value: 20, label: 'series C' }, - { id: 3, value: 30, label: 'series D' }, - ], - }, -]; - -export default function LegendRoundedSymbol() { - return ( - - ); -} diff --git a/docs/data/charts/legend/LegendRoundedSymbol.tsx.preview b/docs/data/charts/legend/LegendRoundedSymbol.tsx.preview deleted file mode 100644 index 7ed5a28c5642d..0000000000000 --- a/docs/data/charts/legend/LegendRoundedSymbol.tsx.preview +++ /dev/null @@ -1,10 +0,0 @@ - \ No newline at end of file diff --git a/docs/data/charts/legend/LegendTextStylingNoSnap.js b/docs/data/charts/legend/LegendTextStylingNoSnap.js index 9af402d6c16be..1ffc7be8bd4a2 100644 --- a/docs/data/charts/legend/LegendTextStylingNoSnap.js +++ b/docs/data/charts/legend/LegendTextStylingNoSnap.js @@ -1,20 +1,17 @@ +// @ts-check + import * as React from 'react'; import ChartsUsageDemo from 'docsx/src/modules/components/ChartsUsageDemo'; import { PieChart } from '@mui/x-charts/PieChart'; +import { labelMarkClasses } from '@mui/x-charts/ChartsLabel'; const data = [ { id: 0, value: 10, label: 'Series A' }, { id: 1, value: 15, label: 'Series B' }, { id: 2, value: 20, label: 'Series C' }, { id: 3, value: 10, label: 'Series D' }, - { id: 4, value: 15, label: 'Series E' }, - { id: 5, value: 20, label: 'Series F' }, - { id: 6, value: 10, label: 'Series G' }, - { id: 7, value: 15, label: 'Series H' }, ]; -const itemsNumber = 15; - export default function LegendTextStylingNoSnap() { return ( ( + renderDemo={( + /** @type {{ fontSize: number; color: string; markColor: string; }} */ + props, + ) => ( ({ - ...item, - label: item.label.replace(' ', props.breakLine ? '\n' : ' '), - })), + data, }, ]} + height={200} + width={200} slotProps={{ legend: { - labelStyle: { + sx: { fontSize: props.fontSize, - fill: props.fill, + color: props.color, + [`.${labelMarkClasses.fill}`]: { + fill: props.markColor, + }, }, }, }} - margin={{ - top: 10, - bottom: 10, - left: 10, - right: 200, - }} - width={400} - height={400} /> )} - getCode={({ props }) => { - return [ - `import { PieChart } from '@mui/x-charts/PieChart';`, - '', - `', - ].join('\n'); + getCode={( + /** @type {{props: { fontSize: number; color: string; markColor: string; }}} */ + { props }, + ) => { + return ` +import { PieChart } from '@mui/x-charts/PieChart'; +import { labelMarkClasses } from '@mui/x-charts/ChartsLabel'; + + +`; }} /> ); diff --git a/docs/data/charts/legend/PiecewiseInteractiveDemoNoSnap.js b/docs/data/charts/legend/PiecewiseInteractiveDemoNoSnap.js index 03ea6ccec047b..2dd1a9b8ae118 100644 --- a/docs/data/charts/legend/PiecewiseInteractiveDemoNoSnap.js +++ b/docs/data/charts/legend/PiecewiseInteractiveDemoNoSnap.js @@ -1,7 +1,11 @@ +// @ts-check import * as React from 'react'; import ChartsUsageDemo from 'docsx/src/modules/components/ChartsUsageDemo'; import { LineChart } from '@mui/x-charts/LineChart'; -import { PiecewiseColorLegend } from '@mui/x-charts/ChartsLegend'; +import { + piecewiseColorDefaultLabelFormatter, + PiecewiseColorLegend, +} from '@mui/x-charts/ChartsLegend'; import { ChartsReferenceLine } from '@mui/x-charts/ChartsReferenceLine'; import { dataset } from './tempAnomaly'; @@ -11,109 +15,120 @@ export default function PiecewiseInteractiveDemoNoSnap() { componentName="Legend" data={[ { - propName: 'hideFirst', - knob: 'switch', + propName: 'direction', + knob: 'select', + defaultValue: 'horizontal', + options: ['horizontal', 'vertical'], }, { - propName: 'direction', + propName: 'labelPosition', knob: 'select', - defaultValue: 'row', - options: ['row', 'column'], + defaultValue: 'extremes', + options: ['start', 'end', 'extremes'], }, { - propName: 'padding', - knob: 'number', - defaultValue: 0, + propName: 'markType', + knob: 'select', + defaultValue: 'square', + options: ['square', 'circle', 'line'], }, { - propName: 'fontSize', + propName: 'onlyShowExtremes', + knob: 'switch', + defaultValue: false, + }, + { + propName: 'padding', knob: 'number', - defaultValue: 10, - min: 8, - max: 20, + defaultValue: 0, }, ]} - renderDemo={(props) => ( -
- `${value?.toFixed(2)}°`, - }, - ]} - xAxis={[ - { - scaleType: 'time', - dataKey: 'year', - disableLine: true, - valueFormatter: (value) => value.getFullYear().toString(), - colorMap: { - type: 'piecewise', - thresholds: [new Date(1961, 0, 1), new Date(1990, 0, 1)], - colors: ['blue', 'gray', 'red'], - }, + renderDemo={( + /** @type {{ direction: "vertical" | "horizontal"; markType: 'square' | 'circle' | 'line'; labelPosition: 'start' | 'end' | 'extremes'; padding: number; onlyShowExtremes: boolean; }} */ + props, + ) => ( + `${value?.toFixed(2)}°`, + }, + ]} + xAxis={[ + { + scaleType: 'time', + dataKey: 'year', + disableLine: true, + valueFormatter: (value) => value.getFullYear().toString(), + colorMap: { + type: 'piecewise', + thresholds: [new Date(1961, 0, 1), new Date(1990, 0, 1)], + colors: ['blue', 'gray', 'red'], }, - ]} - yAxis={[ - { - disableLine: true, - disableTicks: true, - valueFormatter: (value) => `${value}°`, + }, + ]} + yAxis={[ + { + disableLine: true, + disableTicks: true, + valueFormatter: (value) => `${value}°`, + }, + ]} + grid={{ horizontal: true }} + height={300} + margin={{ top: 20, right: 20 }} + slots={{ + legend: PiecewiseColorLegend, + }} + slotProps={{ + legend: { + axisDirection: 'x', + direction: props.direction, + markType: props.markType, + labelPosition: props.labelPosition, + labelFormatter: props.onlyShowExtremes + ? (params) => + params.index === 0 || params.index === params.length + ? piecewiseColorDefaultLabelFormatter(params) + : '' + : undefined, + sx: { + padding: props.padding, }, - ]} - grid={{ horizontal: true }} - height={300} - margin={{ - top: props.direction === 'row' ? 50 : 20, - right: props.direction === 'row' ? 20 : 150, - }} - hideLegend - > - - - -
+ }, + }} + > + + )} - getCode={({ props }) => { - return [ - `import { LineChart } from '@mui/x-charts/LineChart';`, - `import { PiecewiseColorLegend } from '@mui/x-charts/ChartsLegend';`, - '', - `', - ` `, - '', - ].join('\n'); + getCode={( + /** @type {{props:{ direction: "vertical" | "horizontal"; markType: 'square' | 'circle' | 'line'; labelPosition: 'start' | 'end' | 'extremes'; padding: number; onlyShowExtremes: boolean; }}} */ + { props }, + ) => { + return ` +import { + PiecewiseColorLegend, + piecewiseColorDefaultLabelFormatter, +} from '@mui/x-charts/ChartsLegend'; + +\n params.index === 0 || params.index === params.length\n ? piecewiseColorDefaultLabelFormatter(params) \n : ''" : ''} + }, + }} +/> +`; }} /> ); diff --git a/docs/data/charts/legend/ScrollableLegend.js b/docs/data/charts/legend/ScrollableLegend.js new file mode 100644 index 0000000000000..954cf672ee553 --- /dev/null +++ b/docs/data/charts/legend/ScrollableLegend.js @@ -0,0 +1,47 @@ +import * as React from 'react'; +import Stack from '@mui/material/Stack'; +import { PieChart } from '@mui/x-charts/PieChart'; + +const series = [ + { + data: [ + { id: 0, value: 10, label: 'Series A' }, + { id: 1, value: 15, label: 'Series B' }, + { id: 2, value: 20, label: 'Series C' }, + { id: 3, value: 10, label: 'Series D' }, + { id: 4, value: 15, label: 'Series E' }, + { id: 5, value: 20, label: 'Series F' }, + { id: 6, value: 10, label: 'Series G' }, + { id: 7, value: 15, label: 'Series H' }, + { id: 8, value: 20, label: 'Series I' }, + { id: 9, value: 10, label: 'Series J' }, + { id: 10, value: 15, label: 'Series K' }, + { id: 11, value: 20, label: 'Series L' }, + { id: 12, value: 10, label: 'Series M' }, + { id: 13, value: 15, label: 'Series N' }, + { id: 14, value: 20, label: 'Series O' }, + ], + }, +]; + +export default function ScrollableLegend() { + return ( + + + + ); +} diff --git a/docs/data/charts/legend/ScrollableLegend.tsx b/docs/data/charts/legend/ScrollableLegend.tsx new file mode 100644 index 0000000000000..954cf672ee553 --- /dev/null +++ b/docs/data/charts/legend/ScrollableLegend.tsx @@ -0,0 +1,47 @@ +import * as React from 'react'; +import Stack from '@mui/material/Stack'; +import { PieChart } from '@mui/x-charts/PieChart'; + +const series = [ + { + data: [ + { id: 0, value: 10, label: 'Series A' }, + { id: 1, value: 15, label: 'Series B' }, + { id: 2, value: 20, label: 'Series C' }, + { id: 3, value: 10, label: 'Series D' }, + { id: 4, value: 15, label: 'Series E' }, + { id: 5, value: 20, label: 'Series F' }, + { id: 6, value: 10, label: 'Series G' }, + { id: 7, value: 15, label: 'Series H' }, + { id: 8, value: 20, label: 'Series I' }, + { id: 9, value: 10, label: 'Series J' }, + { id: 10, value: 15, label: 'Series K' }, + { id: 11, value: 20, label: 'Series L' }, + { id: 12, value: 10, label: 'Series M' }, + { id: 13, value: 15, label: 'Series N' }, + { id: 14, value: 20, label: 'Series O' }, + ], + }, +]; + +export default function ScrollableLegend() { + return ( + + + + ); +} diff --git a/docs/data/charts/legend/ScrollableLegend.tsx.preview b/docs/data/charts/legend/ScrollableLegend.tsx.preview new file mode 100644 index 0000000000000..6f7c38b28639a --- /dev/null +++ b/docs/data/charts/legend/ScrollableLegend.tsx.preview @@ -0,0 +1,15 @@ + \ No newline at end of file diff --git a/docs/data/charts/legend/VeryBasicColorLegend.js b/docs/data/charts/legend/VeryBasicColorLegend.js new file mode 100644 index 0000000000000..766603bb4b903 --- /dev/null +++ b/docs/data/charts/legend/VeryBasicColorLegend.js @@ -0,0 +1,62 @@ +import * as React from 'react'; +import { LineChart } from '@mui/x-charts/LineChart'; +import { PiecewiseColorLegend } from '@mui/x-charts/ChartsLegend'; +import Stack from '@mui/material/Stack'; +import { dataset } from './tempAnomaly'; + +const data = { + dataset, + series: [ + { + label: 'Global temperature anomaly relative to 1961-1990', + dataKey: 'anomaly', + showMark: false, + valueFormatter: (value) => `${value?.toFixed(2)}°`, + }, + ], + xAxis: [ + { + scaleType: 'time', + dataKey: 'year', + disableLine: true, + valueFormatter: (value) => value.getFullYear().toString(), + colorMap: { + type: 'piecewise', + thresholds: [new Date(1961, 0, 1), new Date(1990, 0, 1)], + colors: ['blue', 'gray', 'red'], + }, + }, + ], + yAxis: [ + { + disableLine: true, + disableTicks: true, + valueFormatter: (value) => `${value}°`, + }, + ], + grid: { horizontal: true }, + height: 300, + margin: { top: 20, right: 20 }, +}; + +export default function VeryBasicColorLegend() { + return ( + + + + ); +} diff --git a/docs/data/charts/legend/VeryBasicColorLegend.tsx b/docs/data/charts/legend/VeryBasicColorLegend.tsx new file mode 100644 index 0000000000000..8468e565f6f6f --- /dev/null +++ b/docs/data/charts/legend/VeryBasicColorLegend.tsx @@ -0,0 +1,62 @@ +import * as React from 'react'; +import { LineChart, LineChartProps } from '@mui/x-charts/LineChart'; +import { PiecewiseColorLegend } from '@mui/x-charts/ChartsLegend'; +import Stack from '@mui/material/Stack'; +import { dataset } from './tempAnomaly'; + +const data: LineChartProps = { + dataset, + series: [ + { + label: 'Global temperature anomaly relative to 1961-1990', + dataKey: 'anomaly', + showMark: false, + valueFormatter: (value) => `${value?.toFixed(2)}°`, + }, + ], + xAxis: [ + { + scaleType: 'time', + dataKey: 'year', + disableLine: true, + valueFormatter: (value) => value.getFullYear().toString(), + colorMap: { + type: 'piecewise', + thresholds: [new Date(1961, 0, 1), new Date(1990, 0, 1)], + colors: ['blue', 'gray', 'red'], + }, + }, + ], + yAxis: [ + { + disableLine: true, + disableTicks: true, + valueFormatter: (value) => `${value}°`, + }, + ], + grid: { horizontal: true }, + height: 300, + margin: { top: 20, right: 20 }, +}; + +export default function VeryBasicColorLegend() { + return ( + + + + ); +} diff --git a/docs/data/charts/legend/VeryBasicColorLegend.tsx.preview b/docs/data/charts/legend/VeryBasicColorLegend.tsx.preview new file mode 100644 index 0000000000000..183ce44d8eed9 --- /dev/null +++ b/docs/data/charts/legend/VeryBasicColorLegend.tsx.preview @@ -0,0 +1,15 @@ + \ No newline at end of file diff --git a/docs/data/charts/legend/legend.md b/docs/data/charts/legend/legend.md index 77c554482acaf..781c05e809656 100644 --- a/docs/data/charts/legend/legend.md +++ b/docs/data/charts/legend/legend.md @@ -1,7 +1,7 @@ --- title: Charts - Legend productId: x-charts -components: ChartsLegend, DefaultChartsLegend, ChartsText, ContinuousColorLegend, PiecewiseColorLegend +components: ChartsLegend, DefaultChartsLegend, ChartsText, ContinuousColorLegend, PiecewiseColorLegend, ChartsLabel, ChartsLabelMark, ChartsLabelGradient --- # Charts - Legend @@ -16,56 +16,69 @@ In chart components, the legend links series with `label` properties and their c ## Customization +This section explains how to customize the legend using classes and properties. + +In order to fully customize the legend with custom components, see an example at the [HTML components docs](https://mui.com/x/react-charts/components/#html-components). + +### Dimensions + +Much of the customization can be done using CSS properties. +There is a main class for the legend container, `.MuiChartsLegend-root`. +Alternatively the `legendClasses` variable can be used if using CSS-in-JS to target the elements. + +Each legend item is composed of two main elements: the `mark` and the `label`. + +The example below explains how it is possible to customize some parts the legend. +And shows how to use both the `legendClasses` variable and the CSS class directly. + +{{"demo": "LegendDimensionNoSnap.js", "hideToolbar": true, "bg": "playground"}} + ### Position -The legend can either be displayed in a `'column'` or `'row'` layout controlled with the `direction` property. +The legend can either be displayed in a `'vertical'` or `'horizontal'` layout controlled with the `direction` property. -It can also be moved with the `position: { vertical, horizontal }` property which defines how the legend aligns within the SVG. +It can also be moved with the `position: { vertical, horizontal }` property which defines how the legend aligns itself in the parent container. - `vertical` can be `'top'`, `'middle'`, or `'bottom'`. - `horizontal` can be `'left'`, `'middle'`, or `'right'`. -You can add spacing to a given `position` with the `padding` property, which can be either a number or an object `{ top, bottom, left, right }`. -This `padding` will add space between the SVG borders and the legend. - By default, the legend is placed above the charts. +:::warning +The `position` property is only available in the `slotProps`, but not in the ``. +In the second case, you are free to place the legend where you want. +::: + {{"demo": "LegendPositionNoSnap.js", "hideToolbar": true, "bg": "playground"}} ### Hiding -You can hide the legend with the property `slotProps.legend.hidden`. +You can hide the legend with the `hideLegend` property of the Chart. {{"demo": "HiddenLegend.js"}} -### Dimensions - -Inside the legend, you can customize the pixel value of the width and height of the mark with the `itemMarkWidth` and `itemMarkHeight` props. +### Label styling -You can also access the `markGap` prop to change the gap between the mark and its label, or the `itemGap` to change the gap between two legend items. -Both props impact the values defined in pixels. +Changing the `label` style can be done by targeting the root component's font properties. -{{"demo": "LegendDimensionNoSnap.js", "hideToolbar": true, "bg": "playground"}} +To change the `mark` color or shape, the `fill` class is used instead. +Keep in mind that the `mark` is an SVG element, so the `fill` property is used to change its color. -### Label styling +{{"demo": "LegendTextStylingNoSnap.js", "hideToolbar": true, "bg": "playground"}} -To break lines in legend labels, use the special `\n` character. To customize the label style, you should not use CSS. -Instead, pass a styling object to the `labelStyle` property. +### Change mark shape -{{"demo": "LegendTextStylingNoSnap.js", "hideToolbar": true, "bg": "playground"}} +To change the mark shape, you can use the `labelMarkType` property of the series item. +For the `pie` series, the `labelMarkType` property is available for each of the pie slices too. -:::info -The `labelStyle` property is needed to measure text size, and then place legend items at the correct position. -Style applied by other means will not be taken into account. -Which can lead to label overflow. -::: +{{"demo": "LegendMarkTypeNoSnap.js", "hideToolbar": true, "bg": "playground"}} -### Rounded symbol +### Scrollable legend -To create a rounded symbol, use the `legendClasses.mark` to apply CSS on marks. -Notice that SVG `rect` uses `ry` property to control the symbol's corner radius instead of `border-radius`. +The legend can be made scrollable by setting the `overflowY` for vertical legends or `overflowX` for horizontal legends. +Make sure that the legend container has a fixed height or width to enable scrolling. -{{"demo": "LegendRoundedSymbol.js"}} +{{"demo": "ScrollableLegend.js"}} ## Color legend @@ -74,6 +87,10 @@ To display legend associated to a [colorMap](https://mui.com/x/react-charts/styl - `` if you're using `colorMap.type='continuous'` - `` if you're using `colorMap.type='piecewise'`. +Then it is possible to override the `legend` slot to display the wanted legend, or use the [composition API](https://mui.com/x/react-charts/composition/) to add as many legends as needed. + +{{"demo": "VeryBasicColorLegend.js"}} + ### Select data To select the color mapping to represent, use the following props: @@ -87,16 +104,27 @@ To select the color mapping to represent, use the following props: This component position is done exactly the same way as the [legend for series](#position). +### Label position + +The labels can be positioned in relation to the marks or gradient with the `labelPosition` prop. +The values accepted are `'start'`, `'end'` or `'extremes'`. + +- With `direction='horizontal'`, using `'start'` places the labels above the visual marker, while `end` places them below. +- When `direction='vertical'`, is `'start'` or `'end'` the labels are positioned `left` and `right` of the visual markers, respectively. +- With the `'extremes'` value, the labels are positioned at both the beginning and end of the visual marker. + +{{"demo": "LegendLabelPositions.js"}} + ### Continuous color mapping To modify the shape of the gradient, use the `length` and `thickness` props. -The `length` can either be a number (in px) or a percentage string. The `"100%"` corresponds to the SVG dimension. +The `length` can either be a number (in px) or a percentage string. The `"100%"` corresponds to the parent dimension. To format labels use the `minLabel`/`maxLabel`. They accept either a string to display. Or a function `({value, formattedValue}) => string`. -The labels and gradient bar alignment can be modified by the `align` prop. +It is also possible to reverse the gradient with the `reverse` prop. {{"demo": "ContinuousInteractiveDemoNoSnap.js", "hideToolbar": true, "bg": "playground"}} @@ -105,18 +133,21 @@ The labels and gradient bar alignment can be modified by the `align` prop. The piecewise Legend is quite similar to the series legend. It accepts the same props for [customization](#dimensions). -The props `hideFirst` and `hideLast` allows to hide the two extreme pieces: values lower than the min threshold, and value higher than the max threshold. - To override labels generated by default, provide a `labelFormatter` prop. It takes the min/max of the piece and returns the label. Values can be `null` for the first and last pieces. And returning `null` removes the piece from the legend. +Returning an empty string removes any label, but still display the `mark`. ```ts -labelFormatter = ({ min, max, formattedMin, formattedMax }) => string | null; +labelFormatter = ({ index, length, min, max, formattedMin, formattedMax }) => + string | null; ``` +The `markType` can be changed with the `markType` prop. +Since the color values are based on the axis, and not the series, the `markType` has to be set directly on the legend. + {{"demo": "PiecewiseInteractiveDemoNoSnap.js", "hideToolbar": true, "bg": "playground"}} ## Click event diff --git a/docs/data/charts/pie-demo/PieChartWithCenterLabel.js b/docs/data/charts/pie-demo/PieChartWithCenterLabel.js index 41f892141c412..9e094cd1abca9 100644 --- a/docs/data/charts/pie-demo/PieChartWithCenterLabel.js +++ b/docs/data/charts/pie-demo/PieChartWithCenterLabel.js @@ -11,7 +11,7 @@ const data = [ ]; const size = { - width: 400, + width: 200, height: 200, }; diff --git a/docs/data/charts/pie-demo/PieChartWithCenterLabel.tsx b/docs/data/charts/pie-demo/PieChartWithCenterLabel.tsx index 3177a8e13c233..8d619a7e5b988 100644 --- a/docs/data/charts/pie-demo/PieChartWithCenterLabel.tsx +++ b/docs/data/charts/pie-demo/PieChartWithCenterLabel.tsx @@ -11,7 +11,7 @@ const data = [ ]; const size = { - width: 400, + width: 200, height: 200, }; diff --git a/docs/data/charts/pie-demo/StraightAnglePieChart.js b/docs/data/charts/pie-demo/StraightAnglePieChart.js index 444b0cac8fb88..9efd2ef122719 100644 --- a/docs/data/charts/pie-demo/StraightAnglePieChart.js +++ b/docs/data/charts/pie-demo/StraightAnglePieChart.js @@ -21,6 +21,7 @@ export default function StraightAnglePieChart() { }, ]} height={300} + width={300} /> ); } diff --git a/docs/data/charts/pie-demo/StraightAnglePieChart.tsx b/docs/data/charts/pie-demo/StraightAnglePieChart.tsx index 444b0cac8fb88..9efd2ef122719 100644 --- a/docs/data/charts/pie-demo/StraightAnglePieChart.tsx +++ b/docs/data/charts/pie-demo/StraightAnglePieChart.tsx @@ -21,6 +21,7 @@ export default function StraightAnglePieChart() { }, ]} height={300} + width={300} /> ); } diff --git a/docs/data/charts/pie-demo/StraightAnglePieChart.tsx.preview b/docs/data/charts/pie-demo/StraightAnglePieChart.tsx.preview index e75631909bfe8..7892941a06c16 100644 --- a/docs/data/charts/pie-demo/StraightAnglePieChart.tsx.preview +++ b/docs/data/charts/pie-demo/StraightAnglePieChart.tsx.preview @@ -7,4 +7,5 @@ }, ]} height={300} + width={300} /> \ No newline at end of file diff --git a/docs/data/charts/pie/BasicPie.js b/docs/data/charts/pie/BasicPie.js index 2899266e0316b..97d722784cda2 100644 --- a/docs/data/charts/pie/BasicPie.js +++ b/docs/data/charts/pie/BasicPie.js @@ -13,7 +13,7 @@ export default function BasicPie() { ], }, ]} - width={400} + width={200} height={200} /> ); diff --git a/docs/data/charts/pie/BasicPie.tsx b/docs/data/charts/pie/BasicPie.tsx index 2899266e0316b..97d722784cda2 100644 --- a/docs/data/charts/pie/BasicPie.tsx +++ b/docs/data/charts/pie/BasicPie.tsx @@ -13,7 +13,7 @@ export default function BasicPie() { ], }, ]} - width={400} + width={200} height={200} /> ); diff --git a/docs/data/charts/pie/BasicPie.tsx.preview b/docs/data/charts/pie/BasicPie.tsx.preview index 61ac8ef626f20..28431a59a1325 100644 --- a/docs/data/charts/pie/BasicPie.tsx.preview +++ b/docs/data/charts/pie/BasicPie.tsx.preview @@ -8,6 +8,6 @@ ], }, ]} - width={400} + width={200} height={200} /> \ No newline at end of file diff --git a/docs/data/charts/pie/PieActiveArc.js b/docs/data/charts/pie/PieActiveArc.js index 4e151e983c04f..8e6af13f69d65 100644 --- a/docs/data/charts/pie/PieActiveArc.js +++ b/docs/data/charts/pie/PieActiveArc.js @@ -14,6 +14,7 @@ export default function PieActiveArc() { }, ]} height={200} + width={200} /> ); } diff --git a/docs/data/charts/pie/PieActiveArc.tsx b/docs/data/charts/pie/PieActiveArc.tsx index 4e151e983c04f..8e6af13f69d65 100644 --- a/docs/data/charts/pie/PieActiveArc.tsx +++ b/docs/data/charts/pie/PieActiveArc.tsx @@ -14,6 +14,7 @@ export default function PieActiveArc() { }, ]} height={200} + width={200} /> ); } diff --git a/docs/data/charts/pie/PieActiveArc.tsx.preview b/docs/data/charts/pie/PieActiveArc.tsx.preview index 6e94368e1bbb3..3e5229579966b 100644 --- a/docs/data/charts/pie/PieActiveArc.tsx.preview +++ b/docs/data/charts/pie/PieActiveArc.tsx.preview @@ -8,4 +8,5 @@ }, ]} height={200} + width={200} /> \ No newline at end of file diff --git a/docs/data/charts/pie/PieAnimation.js b/docs/data/charts/pie/PieAnimation.js index 51584d139a45e..f8b488baa6a24 100644 --- a/docs/data/charts/pie/PieAnimation.js +++ b/docs/data/charts/pie/PieAnimation.js @@ -29,6 +29,7 @@ export default function PieAnimation() { setItemData(d)} diff --git a/docs/data/charts/scatter/ScatterDataset.js b/docs/data/charts/scatter/ScatterDataset.js index 5a50fdc796762..b767d2169ac9e 100644 --- a/docs/data/charts/scatter/ScatterDataset.js +++ b/docs/data/charts/scatter/ScatterDataset.js @@ -88,6 +88,7 @@ const chartSetting = { }, width: 500, height: 300, + margin: { left: 60 }, }; export default function ScatterDataset() { diff --git a/docs/data/charts/scatter/ScatterDataset.tsx b/docs/data/charts/scatter/ScatterDataset.tsx index 5a50fdc796762..b767d2169ac9e 100644 --- a/docs/data/charts/scatter/ScatterDataset.tsx +++ b/docs/data/charts/scatter/ScatterDataset.tsx @@ -88,6 +88,7 @@ const chartSetting = { }, width: 500, height: 300, + margin: { left: 60 }, }; export default function ScatterDataset() { diff --git a/docs/data/charts/styling/BasicColor.js b/docs/data/charts/styling/BasicColor.js index 49bb1619c9a45..a1325422ac1e8 100644 --- a/docs/data/charts/styling/BasicColor.js +++ b/docs/data/charts/styling/BasicColor.js @@ -29,7 +29,7 @@ export default function BasicColor() { }; return ( - + + - + - - - - + + + + + +
); } diff --git a/docs/data/charts/styling/PatternPie.tsx b/docs/data/charts/styling/PatternPie.tsx index 02f53eebf0161..8749891afa008 100644 --- a/docs/data/charts/styling/PatternPie.tsx +++ b/docs/data/charts/styling/PatternPie.tsx @@ -1,44 +1,47 @@ import * as React from 'react'; import { PieChart } from '@mui/x-charts/PieChart'; +import { Stack } from '@mui/system'; export default function PatternPie() { return ( - - + - - - - + + + + + + ); } diff --git a/docs/data/charts/tooltip/AxisFormatter.js b/docs/data/charts/tooltip/AxisFormatter.js index ec92663310f40..ef3ff43fb3fa1 100644 --- a/docs/data/charts/tooltip/AxisFormatter.js +++ b/docs/data/charts/tooltip/AxisFormatter.js @@ -48,6 +48,7 @@ const chartParams = { dataset, width: 600, height: 400, + margin: { left: 60 }, sx: { [`.${axisClasses.left} .${axisClasses.label}`]: { transform: 'translate(-20px, 0)', diff --git a/docs/data/charts/tooltip/AxisFormatter.tsx b/docs/data/charts/tooltip/AxisFormatter.tsx index 0a687484e96b9..d0781688dbdc4 100644 --- a/docs/data/charts/tooltip/AxisFormatter.tsx +++ b/docs/data/charts/tooltip/AxisFormatter.tsx @@ -48,6 +48,7 @@ const chartParams: BarChartProps = { dataset, width: 600, height: 400, + margin: { left: 60 }, sx: { [`.${axisClasses.left} .${axisClasses.label}`]: { transform: 'translate(-20px, 0)', diff --git a/docs/data/charts/tooltip/SeriesFormatter.js b/docs/data/charts/tooltip/SeriesFormatter.js index d876c031babbe..d1a841ec1c134 100644 --- a/docs/data/charts/tooltip/SeriesFormatter.js +++ b/docs/data/charts/tooltip/SeriesFormatter.js @@ -3,7 +3,7 @@ import { PieChart } from '@mui/x-charts/PieChart'; import { legendClasses } from '@mui/x-charts/ChartsLegend'; const otherProps = { - width: 400, + width: 200, height: 200, sx: { [`.${legendClasses.root}`]: { diff --git a/docs/data/charts/tooltip/SeriesFormatter.tsx b/docs/data/charts/tooltip/SeriesFormatter.tsx index 030064774ba97..b60633f83fe75 100644 --- a/docs/data/charts/tooltip/SeriesFormatter.tsx +++ b/docs/data/charts/tooltip/SeriesFormatter.tsx @@ -3,7 +3,7 @@ import { PieChart, PieChartProps } from '@mui/x-charts/PieChart'; import { legendClasses } from '@mui/x-charts/ChartsLegend'; const otherProps: Partial = { - width: 400, + width: 200, height: 200, sx: { [`.${legendClasses.root}`]: { diff --git a/docs/data/chartsApiPages.ts b/docs/data/chartsApiPages.ts index c4ec485b59c66..dbc2961b5e3d8 100644 --- a/docs/data/chartsApiPages.ts +++ b/docs/data/chartsApiPages.ts @@ -119,10 +119,6 @@ const chartsApiPages: MuiPage[] = [ pathname: '/x/api/charts/continuous-color-legend', title: 'ContinuousColorLegend', }, - { - pathname: '/x/api/charts/default-charts-legend', - title: 'DefaultChartsLegend', - }, { pathname: '/x/api/charts/gauge', title: 'Gauge', diff --git a/docs/data/migration/migration-charts-v7/migration-charts-v7.md b/docs/data/migration/migration-charts-v7/migration-charts-v7.md index e192355a5d389..68df47f3abe3e 100644 --- a/docs/data/migration/migration-charts-v7/migration-charts-v7.md +++ b/docs/data/migration/migration-charts-v7/migration-charts-v7.md @@ -92,6 +92,25 @@ To pass props to the legend, use the `slotProps.legend`. + ``` +## Legend direction value change ✅ + +The `direction` prop of the legend has been changed to accept `'vertical'` and `'horizontal'` instead of `'column'` and `'row'`. + +```diff + +``` + +## The `getSeriesToDisplay` function was removed + +The `getSeriesToDisplay` function was removed in favor of the `useLegend` hook. You can check the [HTML Components example](/x/react-charts/components/#html-components) for usage information. + ## Removing ResponsiveChartContainer ✅ The `ResponsiveChartContainer` has been removed. diff --git a/docs/pages/x/api/charts/bar-chart.json b/docs/pages/x/api/charts/bar-chart.json index 7cb920914914d..bc3bf924ede77 100644 --- a/docs/pages/x/api/charts/bar-chart.json +++ b/docs/pages/x/api/charts/bar-chart.json @@ -149,7 +149,7 @@ { "name": "legend", "description": "Custom rendering of the legend.", - "default": "DefaultChartsLegend", + "default": "ChartsLegend", "class": null }, { @@ -173,7 +173,7 @@ ], "classes": [], "spread": true, - "themeDefaultProps": true, + "themeDefaultProps": false, "muiName": "MuiBarChart", "forwardsRefTo": "SVGSVGElement", "filename": "/packages/x-charts/src/BarChart/BarChart.tsx", diff --git a/docs/pages/x/api/charts/bar-series-type.json b/docs/pages/x/api/charts/bar-series-type.json index de9972728689c..41abd5617c88d 100644 --- a/docs/pages/x/api/charts/bar-series-type.json +++ b/docs/pages/x/api/charts/bar-series-type.json @@ -14,6 +14,7 @@ "label": { "type": { "description": "string | ((location: 'tooltip' | 'legend') => string)" } }, + "labelMarkType": { "type": { "description": "ChartsLabelMarkProps['type']" } }, "layout": { "type": { "description": "'horizontal' | 'vertical'" }, "default": "'vertical'" }, "stack": { "type": { "description": "string" } }, "stackOffset": { "type": { "description": "StackOffsetType" }, "default": "'diverging'" }, diff --git a/docs/pages/x/api/charts/charts-legend.json b/docs/pages/x/api/charts/charts-legend.json index 8e58410c7fd64..b3326b90cf78b 100644 --- a/docs/pages/x/api/charts/charts-legend.json +++ b/docs/pages/x/api/charts/charts-legend.json @@ -1,33 +1,16 @@ { "props": { "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, - "direction": { "type": { "name": "enum", "description": "'column'
| 'row'" } }, - "hidden": { "type": { "name": "bool" }, "default": "false" }, - "itemGap": { "type": { "name": "number" }, "default": "10" }, - "itemMarkHeight": { "type": { "name": "number" }, "default": "20" }, - "itemMarkWidth": { "type": { "name": "number" }, "default": "20" }, - "labelStyle": { "type": { "name": "object" }, "default": "theme.typography.subtitle1" }, - "markGap": { "type": { "name": "number" }, "default": "5" }, + "direction": { + "type": { "name": "enum", "description": "'horizontal'
| 'vertical'" } + }, "onItemClick": { "type": { "name": "func" }, "signature": { - "type": "function(event: React.MouseEvent, legendItem: SeriesLegendItemContext, index: number) => void", + "type": "function(event: React.MouseEvent, legendItem: SeriesLegendItemContext, index: number) => void", "describedArgs": ["event", "legendItem", "index"] } }, - "padding": { - "type": { - "name": "union", - "description": "number
| { bottom?: number, left?: number, right?: number, top?: number }" - }, - "default": "10" - }, - "position": { - "type": { - "name": "shape", - "description": "{ horizontal: 'left'
| 'middle'
| 'right', vertical: 'bottom'
| 'middle'
| 'top' }" - } - }, "slotProps": { "type": { "name": "object" }, "default": "{}" }, "slots": { "type": { "name": "object" }, @@ -45,21 +28,15 @@ { "name": "legend", "description": "Custom rendering of the legend.", - "default": "DefaultChartsLegend", + "default": "ChartsLegend", "class": null } ], "classes": [ { - "key": "column", - "className": "MuiChartsLegend-column", - "description": "Styles applied to the legend with column layout.", - "isGlobal": false - }, - { - "key": "itemBackground", - "className": "MuiChartsLegend-itemBackground", - "description": "Styles applied to the item background.", + "key": "horizontal", + "className": "MuiChartsLegend-horizontal", + "description": "Styles applied to the legend in row layout.", "isGlobal": false }, { @@ -80,20 +57,23 @@ "description": "Styles applied to the root element.", "isGlobal": false }, - { - "key": "row", - "className": "MuiChartsLegend-row", - "description": "Styles applied to the legend with row layout.", - "isGlobal": false - }, { "key": "series", "className": "MuiChartsLegend-series", "description": "Styles applied to a series element.", "isGlobal": false + }, + { + "key": "vertical", + "className": "MuiChartsLegend-vertical", + "description": "Styles applied to the legend in column layout.", + "isGlobal": false } ], + "spread": true, + "themeDefaultProps": true, "muiName": "MuiChartsLegend", + "forwardsRefTo": "HTMLUListElement", "filename": "/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx", "inheritance": null, "demos": "", diff --git a/docs/pages/x/api/charts/continuous-color-legend.json b/docs/pages/x/api/charts/continuous-color-legend.json index 654a9fc15dfd1..ab6fee144fa9c 100644 --- a/docs/pages/x/api/charts/continuous-color-legend.json +++ b/docs/pages/x/api/charts/continuous-color-legend.json @@ -1,12 +1,5 @@ { "props": { - "align": { - "type": { - "name": "enum", - "description": "'end'
| 'middle'
| 'start'" - }, - "default": "'middle'" - }, "axisDirection": { "type": { "name": "enum", "description": "'x'
| 'y'
| 'z'" }, "default": "'z'" @@ -15,36 +8,30 @@ "type": { "name": "union", "description": "number
| string" }, "default": "The first axis item." }, - "direction": { "type": { "name": "enum", "description": "'column'
| 'row'" } }, - "id": { "type": { "name": "string" }, "default": "auto-generated id" }, - "labelStyle": { "type": { "name": "object" }, "default": "theme.typography.subtitle1" }, - "length": { - "type": { "name": "union", "description": "number
| string" }, - "default": "'50%'" + "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, + "direction": { + "type": { "name": "enum", "description": "'horizontal'
| 'vertical'" }, + "default": "'horizontal'" + }, + "gradientId": { "type": { "name": "string" }, "default": "auto-generated id" }, + "labelPosition": { + "type": { + "name": "enum", + "description": "'start'
| 'end'
| 'extremes'" + }, + "default": "'end'" }, "maxLabel": { "type": { "name": "union", "description": "func
| string" }, - "default": "({ formattedValue }) => formattedValue" + "default": "formattedValue" }, "minLabel": { "type": { "name": "union", "description": "func
| string" }, - "default": "({ formattedValue }) => formattedValue" - }, - "position": { - "type": { - "name": "shape", - "description": "{ horizontal: 'left'
| 'middle'
| 'right', vertical: 'bottom'
| 'middle'
| 'top' }" - } + "default": "formattedValue" }, - "scaleType": { - "type": { - "name": "enum", - "description": "'linear'
| 'log'
| 'pow'
| 'sqrt'
| 'time'
| 'utc'" - }, - "default": "'linear'" - }, - "spacing": { "type": { "name": "number" }, "default": "4" }, - "thickness": { "type": { "name": "number" }, "default": "5" } + "reverse": { "type": { "name": "bool" }, "default": "false" }, + "rotateGradient": { "type": { "name": "bool" } }, + "thickness": { "type": { "name": "number" }, "default": "12" } }, "name": "ContinuousColorLegend", "imports": [ @@ -52,8 +39,72 @@ "import { ContinuousColorLegend } from '@mui/x-charts';", "import { ContinuousColorLegend } from '@mui/x-charts-pro';" ], - "classes": [], + "classes": [ + { + "key": "end", + "className": "MuiContinuousColorLegend-end", + "description": "Styles applied to the legend with the labels after the gradient.", + "isGlobal": false + }, + { + "key": "extremes", + "className": "MuiContinuousColorLegend-extremes", + "description": "Styles applied to the legend with the labels on the extremes of the gradient.", + "isGlobal": false + }, + { + "key": "gradient", + "className": "MuiContinuousColorLegend-gradient", + "description": "Styles applied to the list item with the gradient.", + "isGlobal": false + }, + { + "key": "horizontal", + "className": "MuiContinuousColorLegend-horizontal", + "description": "Styles applied to the legend in row layout.", + "isGlobal": false + }, + { + "key": "label", + "className": "MuiContinuousColorLegend-label", + "description": "Styles applied to the series label.", + "isGlobal": false + }, + { + "key": "maxLabel", + "className": "MuiContinuousColorLegend-maxLabel", + "description": "Styles applied to the list item that renders the `maxLabel`.", + "isGlobal": false + }, + { + "key": "minLabel", + "className": "MuiContinuousColorLegend-minLabel", + "description": "Styles applied to the list item that renders the `minLabel`.", + "isGlobal": false + }, + { + "key": "root", + "className": "MuiContinuousColorLegend-root", + "description": "Styles applied to the root element.", + "isGlobal": false + }, + { + "key": "start", + "className": "MuiContinuousColorLegend-start", + "description": "Styles applied to the legend with the labels before the gradient.", + "isGlobal": false + }, + { + "key": "vertical", + "className": "MuiContinuousColorLegend-vertical", + "description": "Styles applied to the legend in column layout.", + "isGlobal": false + } + ], + "spread": true, + "themeDefaultProps": true, "muiName": "MuiContinuousColorLegend", + "forwardsRefTo": "HTMLUListElement", "filename": "/packages/x-charts/src/ChartsLegend/ContinuousColorLegend.tsx", "inheritance": null, "demos": "", diff --git a/docs/pages/x/api/charts/default-charts-legend.js b/docs/pages/x/api/charts/default-charts-legend.js deleted file mode 100644 index e29bddc9b5742..0000000000000 --- a/docs/pages/x/api/charts/default-charts-legend.js +++ /dev/null @@ -1,23 +0,0 @@ -import * as React from 'react'; -import ApiPage from 'docs/src/modules/components/ApiPage'; -import mapApiPageTranslations from 'docs/src/modules/utils/mapApiPageTranslations'; -import jsonPageContent from './default-charts-legend.json'; - -export default function Page(props) { - const { descriptions, pageContent } = props; - return ; -} - -Page.getInitialProps = () => { - const req = require.context( - 'docsx/translations/api-docs/charts/default-charts-legend', - false, - /\.\/default-charts-legend.*.json$/, - ); - const descriptions = mapApiPageTranslations(req); - - return { - descriptions, - pageContent: jsonPageContent, - }; -}; diff --git a/docs/pages/x/api/charts/default-charts-legend.json b/docs/pages/x/api/charts/default-charts-legend.json deleted file mode 100644 index 1c55aa4c7626f..0000000000000 --- a/docs/pages/x/api/charts/default-charts-legend.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "props": { - "direction": { - "type": { "name": "enum", "description": "'column'
| 'row'" }, - "required": true - }, - "position": { - "type": { - "name": "shape", - "description": "{ horizontal: 'left'
| 'middle'
| 'right', vertical: 'bottom'
| 'middle'
| 'top' }" - }, - "required": true - }, - "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, - "hidden": { "type": { "name": "bool" }, "default": "false" }, - "itemGap": { "type": { "name": "number" }, "default": "10" }, - "itemMarkHeight": { "type": { "name": "number" }, "default": "20" }, - "itemMarkWidth": { "type": { "name": "number" }, "default": "20" }, - "labelStyle": { "type": { "name": "object" }, "default": "theme.typography.subtitle1" }, - "markGap": { "type": { "name": "number" }, "default": "5" }, - "onItemClick": { - "type": { "name": "func" }, - "signature": { - "type": "function(event: React.MouseEvent, legendItem: SeriesLegendItemContext, index: number) => void", - "describedArgs": ["event", "legendItem", "index"] - } - }, - "padding": { - "type": { - "name": "union", - "description": "number
| { bottom?: number, left?: number, right?: number, top?: number }" - }, - "default": "10" - } - }, - "name": "DefaultChartsLegend", - "imports": [ - "import { DefaultChartsLegend } from '@mui/x-charts/ChartsLegend';", - "import { DefaultChartsLegend } from '@mui/x-charts';", - "import { DefaultChartsLegend } from '@mui/x-charts-pro';" - ], - "classes": [ - { - "key": "column", - "className": "MuiDefaultChartsLegend-column", - "description": "Styles applied to the legend with column layout.", - "isGlobal": false - }, - { - "key": "itemBackground", - "className": "MuiDefaultChartsLegend-itemBackground", - "description": "Styles applied to the item background.", - "isGlobal": false - }, - { - "key": "label", - "className": "MuiDefaultChartsLegend-label", - "description": "Styles applied to the series label.", - "isGlobal": false - }, - { - "key": "mark", - "className": "MuiDefaultChartsLegend-mark", - "description": "Styles applied to series mark element.", - "isGlobal": false - }, - { - "key": "root", - "className": "MuiDefaultChartsLegend-root", - "description": "Styles applied to the root element.", - "isGlobal": false - }, - { - "key": "row", - "className": "MuiDefaultChartsLegend-row", - "description": "Styles applied to the legend with row layout.", - "isGlobal": false - }, - { - "key": "series", - "className": "MuiDefaultChartsLegend-series", - "description": "Styles applied to a series element.", - "isGlobal": false - } - ], - "muiName": "MuiDefaultChartsLegend", - "filename": "/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx", - "inheritance": null, - "demos": "", - "cssComponent": false -} diff --git a/docs/pages/x/api/charts/line-chart.json b/docs/pages/x/api/charts/line-chart.json index a03a00045fa09..2fbaa24f937ff 100644 --- a/docs/pages/x/api/charts/line-chart.json +++ b/docs/pages/x/api/charts/line-chart.json @@ -136,7 +136,7 @@ { "name": "legend", "description": "Custom rendering of the legend.", - "default": "DefaultChartsLegend", + "default": "ChartsLegend", "class": null }, { @@ -168,7 +168,7 @@ ], "classes": [], "spread": true, - "themeDefaultProps": true, + "themeDefaultProps": false, "muiName": "MuiLineChart", "forwardsRefTo": "SVGSVGElement", "filename": "/packages/x-charts/src/LineChart/LineChart.tsx", diff --git a/docs/pages/x/api/charts/line-series-type.json b/docs/pages/x/api/charts/line-series-type.json index 85a484a515400..605b9697736aa 100644 --- a/docs/pages/x/api/charts/line-series-type.json +++ b/docs/pages/x/api/charts/line-series-type.json @@ -19,6 +19,7 @@ "label": { "type": { "description": "string | ((location: 'tooltip' | 'legend') => string)" } }, + "labelMarkType": { "type": { "description": "ChartsLabelMarkProps['type']" } }, "showMark": { "type": { "description": "boolean | ((params: ShowMarkParams) => boolean)" } }, "stack": { "type": { "description": "string" } }, "stackOffset": { "type": { "description": "StackOffsetType" }, "default": "'none'" }, diff --git a/docs/pages/x/api/charts/pie-chart.json b/docs/pages/x/api/charts/pie-chart.json index 090da6099a855..40c4623032918 100644 --- a/docs/pages/x/api/charts/pie-chart.json +++ b/docs/pages/x/api/charts/pie-chart.json @@ -65,7 +65,7 @@ { "name": "legend", "description": "Custom rendering of the legend.", - "default": "DefaultChartsLegend", + "default": "ChartsLegend", "class": null }, { @@ -91,7 +91,7 @@ ], "classes": [], "spread": true, - "themeDefaultProps": true, + "themeDefaultProps": false, "muiName": "MuiPieChart", "forwardsRefTo": "SVGSVGElement", "filename": "/packages/x-charts/src/PieChart/PieChart.tsx", diff --git a/docs/pages/x/api/charts/pie-series-type.json b/docs/pages/x/api/charts/pie-series-type.json index b644991437236..598ad4c27b0df 100644 --- a/docs/pages/x/api/charts/pie-series-type.json +++ b/docs/pages/x/api/charts/pie-series-type.json @@ -35,6 +35,7 @@ "highlightScope": { "type": { "description": "Partial<HighlightScope>" } }, "id": { "type": { "description": "SeriesId" } }, "innerRadius": { "type": { "description": "number | string" }, "default": "0" }, + "labelMarkType": { "type": { "description": "ChartsLabelMarkProps['type']" } }, "outerRadius": { "type": { "description": "number | string" }, "default": "'100%'" }, "paddingAngle": { "type": { "description": "number" }, "default": "0" }, "sortingValues": { "type": { "description": "ChartsPieSorting" }, "default": "'none'" }, diff --git a/docs/pages/x/api/charts/piecewise-color-legend.json b/docs/pages/x/api/charts/piecewise-color-legend.json index 18c41729f90c5..d4651729c8b1d 100644 --- a/docs/pages/x/api/charts/piecewise-color-legend.json +++ b/docs/pages/x/api/charts/piecewise-color-legend.json @@ -1,16 +1,5 @@ { "props": { - "direction": { - "type": { "name": "enum", "description": "'column'
| 'row'" }, - "required": true - }, - "position": { - "type": { - "name": "shape", - "description": "{ horizontal: 'left'
| 'middle'
| 'right', vertical: 'bottom'
| 'middle'
| 'top' }" - }, - "required": true - }, "axisDirection": { "type": { "name": "enum", "description": "'x'
| 'y'
| 'z'" }, "default": "'z'" @@ -20,11 +9,10 @@ "default": "The first axis item." }, "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, - "hideFirst": { "type": { "name": "bool" }, "default": "false" }, - "hideLast": { "type": { "name": "bool" }, "default": "false" }, - "itemGap": { "type": { "name": "number" }, "default": "10" }, - "itemMarkHeight": { "type": { "name": "number" }, "default": "20" }, - "itemMarkWidth": { "type": { "name": "number" }, "default": "20" }, + "direction": { + "type": { "name": "enum", "description": "'horizontal'
| 'vertical'" }, + "default": "'horizontal'" + }, "labelFormatter": { "type": { "name": "func" }, "signature": { @@ -33,21 +21,26 @@ "returned": "string | null" } }, - "labelStyle": { "type": { "name": "object" }, "default": "theme.typography.subtitle1" }, - "markGap": { "type": { "name": "number" }, "default": "5" }, + "labelPosition": { + "type": { + "name": "enum", + "description": "'start'
| 'end'
| 'extremes'" + }, + "default": "'extremes'" + }, + "markType": { + "type": { + "name": "enum", + "description": "'square'
| 'circle'
| 'line'" + }, + "default": "'square'" + }, "onItemClick": { "type": { "name": "func" }, "signature": { - "type": "function(event: React.MouseEvent, legendItem: PiecewiseColorLegendItemContext, index: number) => void", + "type": "function(event: React.MouseEvent, legendItem: PiecewiseColorLegendItemContext, index: number) => void", "describedArgs": ["event", "legendItem", "index"] } - }, - "padding": { - "type": { - "name": "union", - "description": "number
| { bottom?: number, left?: number, right?: number, top?: number }" - }, - "default": "10" } }, "name": "PiecewiseColorLegend", @@ -58,15 +51,27 @@ ], "classes": [ { - "key": "column", - "className": "MuiPiecewiseColorLegend-column", - "description": "Styles applied to the legend with column layout.", + "key": "end", + "className": "MuiPiecewiseColorLegend-end", + "description": "Styles applied to the legend with the labels after the color marks.", + "isGlobal": false + }, + { + "key": "extremes", + "className": "MuiPiecewiseColorLegend-extremes", + "description": "Styles applied to the legend with the labels on the extremes of the color marks.", + "isGlobal": false + }, + { + "key": "horizontal", + "className": "MuiPiecewiseColorLegend-horizontal", + "description": "Styles applied to the legend in row layout.", "isGlobal": false }, { - "key": "itemBackground", - "className": "MuiPiecewiseColorLegend-itemBackground", - "description": "Styles applied to the item background.", + "key": "item", + "className": "MuiPiecewiseColorLegend-item", + "description": "Styles applied to the list items.", "isGlobal": false }, { @@ -78,7 +83,19 @@ { "key": "mark", "className": "MuiPiecewiseColorLegend-mark", - "description": "Styles applied to series mark element.", + "description": "Styles applied to the marks.", + "isGlobal": false + }, + { + "key": "maxLabel", + "className": "MuiPiecewiseColorLegend-maxLabel", + "description": "Styles applied to the list item that renders the `maxLabel`.", + "isGlobal": false + }, + { + "key": "minLabel", + "className": "MuiPiecewiseColorLegend-minLabel", + "description": "Styles applied to the list item that renders the `minLabel`.", "isGlobal": false }, { @@ -88,19 +105,22 @@ "isGlobal": false }, { - "key": "row", - "className": "MuiPiecewiseColorLegend-row", - "description": "Styles applied to the legend with row layout.", + "key": "start", + "className": "MuiPiecewiseColorLegend-start", + "description": "Styles applied to the legend with the labels before the color marks.", "isGlobal": false }, { - "key": "series", - "className": "MuiPiecewiseColorLegend-series", - "description": "Styles applied to a series element.", + "key": "vertical", + "className": "MuiPiecewiseColorLegend-vertical", + "description": "Styles applied to the legend in column layout.", "isGlobal": false } ], + "spread": true, + "themeDefaultProps": true, "muiName": "MuiPiecewiseColorLegend", + "forwardsRefTo": "HTMLUListElement", "filename": "/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx", "inheritance": null, "demos": "", diff --git a/docs/pages/x/api/charts/scatter-chart.json b/docs/pages/x/api/charts/scatter-chart.json index 9826eff4a7fea..0c6730fcbd93e 100644 --- a/docs/pages/x/api/charts/scatter-chart.json +++ b/docs/pages/x/api/charts/scatter-chart.json @@ -133,7 +133,7 @@ { "name": "legend", "description": "Custom rendering of the legend.", - "default": "DefaultChartsLegend", + "default": "ChartsLegend", "class": null }, { @@ -158,7 +158,7 @@ ], "classes": [], "spread": true, - "themeDefaultProps": true, + "themeDefaultProps": false, "muiName": "MuiScatterChart", "forwardsRefTo": "SVGSVGElement", "filename": "/packages/x-charts/src/ScatterChart/ScatterChart.tsx", diff --git a/docs/pages/x/api/charts/scatter-series-type.json b/docs/pages/x/api/charts/scatter-series-type.json index 436b9311ec3f8..8fd3e00be1694 100644 --- a/docs/pages/x/api/charts/scatter-series-type.json +++ b/docs/pages/x/api/charts/scatter-series-type.json @@ -19,6 +19,7 @@ "label": { "type": { "description": "string | ((location: 'tooltip' | 'legend') => string)" } }, + "labelMarkType": { "type": { "description": "ChartsLabelMarkProps['type']" } }, "markerSize": { "type": { "description": "number" } }, "valueFormatter": { "type": { "description": "SeriesValueFormatter<TValue>" } }, "xAxisId": { "type": { "description": "string" } }, diff --git a/docs/translations/api-docs/charts/bar-series-type.json b/docs/translations/api-docs/charts/bar-series-type.json index ebb278d10e61c..d84b4ba782c5a 100644 --- a/docs/translations/api-docs/charts/bar-series-type.json +++ b/docs/translations/api-docs/charts/bar-series-type.json @@ -10,6 +10,9 @@ "label": { "description": "The label to display on the tooltip or the legend. It can be a string or a function." }, + "labelMarkType": { + "description": "Defines the mark type for the series.

There is a default mark type for each series type.

It allows custom values which will be passed to the mark component if it was customized." + }, "layout": { "description": "Layout of the bars. All bar should have the same layout." }, "stack": { "description": "The key that identifies the stacking group.
Series with the same stack property will be stacked together." diff --git a/docs/translations/api-docs/charts/charts-legend/charts-legend.json b/docs/translations/api-docs/charts/charts-legend/charts-legend.json index 697f19e692d3b..b558ebc1c7936 100644 --- a/docs/translations/api-docs/charts/charts-legend/charts-legend.json +++ b/docs/translations/api-docs/charts/charts-legend/charts-legend.json @@ -5,12 +5,6 @@ "direction": { "description": "The direction of the legend layout. The default depends on the chart." }, - "hidden": { "description": "Set to true to hide the legend." }, - "itemGap": { "description": "Space between two legend items (in px)." }, - "itemMarkHeight": { "description": "Height of the item mark (in px)." }, - "itemMarkWidth": { "description": "Width of the item mark (in px)." }, - "labelStyle": { "description": "Style applied to legend labels." }, - "markGap": { "description": "Space between the mark and the label (in px)." }, "onItemClick": { "description": "Callback fired when a legend item is clicked.", "typeDescriptions": { @@ -19,30 +13,22 @@ "index": "The index of the clicked legend item." } }, - "padding": { - "description": "Legend padding (in px). Can either be a single number, or an object with top, left, bottom, right properties." - }, - "position": { "description": "The position of the legend." }, "slotProps": { "description": "The props used for each component slot." }, "slots": { "description": "Overridable component slots." } }, "classDescriptions": { - "column": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the legend with column layout" - }, - "itemBackground": { + "horizontal": { "description": "Styles applied to {{nodeName}}.", - "nodeName": "the item background" + "nodeName": "the legend in row layout" }, "label": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the series label" }, "mark": { "description": "Styles applied to {{nodeName}}.", "nodeName": "series mark element" }, "root": { "description": "Styles applied to the root element." }, - "row": { + "series": { "description": "Styles applied to {{nodeName}}.", "nodeName": "a series element" }, + "vertical": { "description": "Styles applied to {{nodeName}}.", - "nodeName": "the legend with row layout" - }, - "series": { "description": "Styles applied to {{nodeName}}.", "nodeName": "a series element" } + "nodeName": "the legend in column layout" + } }, "slotDescriptions": { "legend": "Custom rendering of the legend." } } diff --git a/docs/translations/api-docs/charts/continuous-color-legend/continuous-color-legend.json b/docs/translations/api-docs/charts/continuous-color-legend/continuous-color-legend.json index 50156c88b2edb..9505bcab4804d 100644 --- a/docs/translations/api-docs/charts/continuous-color-legend/continuous-color-legend.json +++ b/docs/translations/api-docs/charts/continuous-color-legend/continuous-color-legend.json @@ -1,31 +1,64 @@ { "componentDescription": "", "propDescriptions": { - "align": { "description": "The alignment of the texts with the gradient bar." }, "axisDirection": { "description": "The axis direction containing the color configuration to represent." }, "axisId": { "description": "The id of the axis item with the color configuration to represent." }, - "direction": { - "description": "The direction of the legend layout. The default depends on the chart." - }, - "id": { "description": "A unique identifier for the gradient." }, - "labelStyle": { "description": "The style applied to labels." }, - "length": { - "description": "The length of the gradient bar. Can be a number (in px) or a string with a percentage such as '50%'. The '100%' is the length of the svg." + "classes": { "description": "Override or extend the styles applied to the component." }, + "direction": { "description": "The direction of the legend layout." }, + "gradientId": { + "description": "The id for the gradient to use. If not provided, it will use the generated gradient from the axis configuration. The gradientId will be used as fill="url(#gradientId)"." }, + "labelPosition": { "description": "Where to position the labels relative to the gradient." }, "maxLabel": { "description": "The label to display at the maximum side of the gradient. Can either be a string, or a function. If not defined, the formatted maximal value is display." }, "minLabel": { "description": "The label to display at the minimum side of the gradient. Can either be a string, or a function." }, - "position": { "description": "The position of the legend." }, - "scaleType": { "description": "The scale used to display gradient colors." }, - "spacing": { "description": "The space between the gradient bar and the labels." }, - "thickness": { "description": "The thickness of the gradient bar." } + "reverse": { "description": "If true, the gradient and labels will be reversed." }, + "rotateGradient": { + "description": "If provided, the gradient will be rotated by 90deg. Useful for linear gradients that are not in the correct orientation." + }, + "thickness": { "description": "The thickness of the gradient" } }, - "classDescriptions": {} + "classDescriptions": { + "end": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the legend with the labels after the gradient" + }, + "extremes": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the legend with the labels on the extremes of the gradient" + }, + "gradient": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the list item with the gradient" + }, + "horizontal": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the legend in row layout" + }, + "label": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the series label" }, + "maxLabel": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the list item that renders the maxLabel" + }, + "minLabel": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the list item that renders the minLabel" + }, + "root": { "description": "Styles applied to the root element." }, + "start": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the legend with the labels before the gradient" + }, + "vertical": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the legend in column layout" + } + } } diff --git a/docs/translations/api-docs/charts/default-charts-legend/default-charts-legend.json b/docs/translations/api-docs/charts/default-charts-legend/default-charts-legend.json deleted file mode 100644 index eea8fa28c58f3..0000000000000 --- a/docs/translations/api-docs/charts/default-charts-legend/default-charts-legend.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "componentDescription": "", - "propDescriptions": { - "classes": { "description": "Override or extend the styles applied to the component." }, - "direction": { - "description": "The direction of the legend layout. The default depends on the chart." - }, - "hidden": { "description": "Set to true to hide the legend." }, - "itemGap": { "description": "Space between two legend items (in px)." }, - "itemMarkHeight": { "description": "Height of the item mark (in px)." }, - "itemMarkWidth": { "description": "Width of the item mark (in px)." }, - "labelStyle": { "description": "Style applied to legend labels." }, - "markGap": { "description": "Space between the mark and the label (in px)." }, - "onItemClick": { - "description": "Callback fired when a legend item is clicked.", - "typeDescriptions": { - "event": "The click event.", - "legendItem": "The legend item data.", - "index": "The index of the clicked legend item." - } - }, - "padding": { - "description": "Legend padding (in px). Can either be a single number, or an object with top, left, bottom, right properties." - }, - "position": { "description": "The position of the legend." } - }, - "classDescriptions": { - "column": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the legend with column layout" - }, - "itemBackground": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the item background" - }, - "label": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the series label" }, - "mark": { "description": "Styles applied to {{nodeName}}.", "nodeName": "series mark element" }, - "root": { "description": "Styles applied to the root element." }, - "row": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the legend with row layout" - }, - "series": { "description": "Styles applied to {{nodeName}}.", "nodeName": "a series element" } - } -} diff --git a/docs/translations/api-docs/charts/line-series-type.json b/docs/translations/api-docs/charts/line-series-type.json index 62a540a7437ad..7855b3617b0ab 100644 --- a/docs/translations/api-docs/charts/line-series-type.json +++ b/docs/translations/api-docs/charts/line-series-type.json @@ -23,6 +23,9 @@ "label": { "description": "The label to display on the tooltip or the legend. It can be a string or a function." }, + "labelMarkType": { + "description": "Defines the mark type for the series.

There is a default mark type for each series type.

It allows custom values which will be passed to the mark component if it was customized." + }, "showMark": { "description": "Define which items of the series should display a mark.
If can be a boolean that applies to all items.
Or a callback that gets some item properties and returns true if the item should be displayed." }, diff --git a/docs/translations/api-docs/charts/pie-series-type.json b/docs/translations/api-docs/charts/pie-series-type.json index ecf2084ab1bc9..6624fb549e8de 100644 --- a/docs/translations/api-docs/charts/pie-series-type.json +++ b/docs/translations/api-docs/charts/pie-series-type.json @@ -26,6 +26,9 @@ "innerRadius": { "description": "The radius between circle center and the beginning of the arc.
Can be a number (in px) or a string with a percentage such as '50%'.
The '100%' is the maximal radius that fit into the drawing area." }, + "labelMarkType": { + "description": "Defines the mark type for the series.

There is a default mark type for each series type.

It allows custom values which will be passed to the mark component if it was customized." + }, "outerRadius": { "description": "The radius between circle center and the end of the arc.
Can be a number (in px) or a string with a percentage such as '50%'.
The '100%' is the maximal radius that fit into the drawing area." }, diff --git a/docs/translations/api-docs/charts/piecewise-color-legend/piecewise-color-legend.json b/docs/translations/api-docs/charts/piecewise-color-legend/piecewise-color-legend.json index eb233fb379f1f..0e5ee41db27e6 100644 --- a/docs/translations/api-docs/charts/piecewise-color-legend/piecewise-color-legend.json +++ b/docs/translations/api-docs/charts/piecewise-color-legend/piecewise-color-legend.json @@ -8,27 +8,16 @@ "description": "The id of the axis item with the color configuration to represent." }, "classes": { "description": "Override or extend the styles applied to the component." }, - "direction": { - "description": "The direction of the legend layout. The default depends on the chart." - }, - "hideFirst": { - "description": "Hide the first item of the legend, corresponding to the [-infinity, min] piece." - }, - "hideLast": { - "description": "Hide the last item of the legend, corresponding to the [max, +infinity] piece." - }, - "itemGap": { "description": "Space between two legend items (in px)." }, - "itemMarkHeight": { "description": "Height of the item mark (in px)." }, - "itemMarkWidth": { "description": "Width of the item mark (in px)." }, + "direction": { "description": "The direction of the legend layout." }, "labelFormatter": { "description": "Format the legend labels.", "typeDescriptions": { "params": "The bound of the piece to format.", - "string | null": "The displayed label, or null to skip the item." + "string | null": "The displayed label, '' to skip the label but show the color mark, or null to skip it entirely." } }, - "labelStyle": { "description": "Style applied to legend labels." }, - "markGap": { "description": "Space between the mark and the label (in px)." }, + "labelPosition": { "description": "Where to position the labels relative to the gradient." }, + "markType": { "description": "The type of the mark." }, "onItemClick": { "description": "Callback fired when a legend item is clicked.", "typeDescriptions": { @@ -36,28 +25,40 @@ "legendItem": "The legend item data.", "index": "The index of the clicked legend item." } - }, - "padding": { - "description": "Legend padding (in px). Can either be a single number, or an object with top, left, bottom, right properties." - }, - "position": { "description": "The position of the legend." } + } }, "classDescriptions": { - "column": { + "end": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the legend with the labels after the color marks" + }, + "extremes": { "description": "Styles applied to {{nodeName}}.", - "nodeName": "the legend with column layout" + "nodeName": "the legend with the labels on the extremes of the color marks" }, - "itemBackground": { + "horizontal": { "description": "Styles applied to {{nodeName}}.", - "nodeName": "the item background" + "nodeName": "the legend in row layout" }, + "item": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the list items" }, "label": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the series label" }, - "mark": { "description": "Styles applied to {{nodeName}}.", "nodeName": "series mark element" }, + "mark": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the marks" }, + "maxLabel": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the list item that renders the maxLabel" + }, + "minLabel": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the list item that renders the minLabel" + }, "root": { "description": "Styles applied to the root element." }, - "row": { + "start": { "description": "Styles applied to {{nodeName}}.", - "nodeName": "the legend with row layout" + "nodeName": "the legend with the labels before the color marks" }, - "series": { "description": "Styles applied to {{nodeName}}.", "nodeName": "a series element" } + "vertical": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the legend in column layout" + } } } diff --git a/docs/translations/api-docs/charts/scatter-series-type.json b/docs/translations/api-docs/charts/scatter-series-type.json index 58a593f0bdbf6..8a20f810ad506 100644 --- a/docs/translations/api-docs/charts/scatter-series-type.json +++ b/docs/translations/api-docs/charts/scatter-series-type.json @@ -15,6 +15,9 @@ "label": { "description": "The label to display on the tooltip or the legend. It can be a string or a function." }, + "labelMarkType": { + "description": "Defines the mark type for the series.

There is a default mark type for each series type.

It allows custom values which will be passed to the mark component if it was customized." + }, "markerSize": { "description": "" }, "valueFormatter": { "description": "Formatter used to render values in tooltip or other data display." diff --git a/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx b/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx index e05075227db07..75f4dc6e8a34a 100644 --- a/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx +++ b/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx @@ -11,11 +11,13 @@ import { ChartsLegend } from '@mui/x-charts/ChartsLegend'; import { ChartsAxisHighlight } from '@mui/x-charts/ChartsAxisHighlight'; import { ChartsTooltip } from '@mui/x-charts/ChartsTooltip'; import { ChartsClipPath } from '@mui/x-charts/ChartsClipPath'; -import { useBarChartProps } from '@mui/x-charts/internals'; -import { ChartContainerPro } from '../ChartContainerPro'; +import { useBarChartProps, ChartsWrapper } from '@mui/x-charts/internals'; +import { ChartsSurface } from '@mui/x-charts/ChartsSurface'; import { ZoomSetup } from '../context/ZoomProvider/ZoomSetup'; import { useZoom } from '../context/ZoomProvider/useZoom'; import { ZoomProps } from '../context/ZoomProvider'; +import { useChartContainerProProps } from '../ChartContainerPro/useChartContainerProProps'; +import { ChartDataProviderPro } from '../context/ChartDataProviderPro'; function BarChartPlotZoom(props: BarPlotProps) { const { isInteracting } = useZoom(); @@ -83,6 +85,7 @@ const BarChartPro = React.forwardRef(function BarChartPro( const props = useThemeProps({ props: inProps, name: 'MuiBarChartPro' }); const { zoom, onZoomChange, ...other } = props; const { + chartsWrapperProps, chartContainerProps, barPlotProps, axisClickHandlerProps, @@ -95,25 +98,33 @@ const BarChartPro = React.forwardRef(function BarChartPro( legendProps, children, } = useBarChartProps(other); + const { chartDataProviderProProps, chartsSurfaceProps } = useChartContainerProProps( + chartContainerProps, + ref, + ); const Tooltip = props.slots?.tooltip ?? ChartsTooltip; return ( - - {props.onAxisClick && } - - - - - - - - {!props.hideLegend && } - {!props.loading && } - - - {children} - + + + {!props.hideLegend && } + + {props.onAxisClick && } + + + + + + + + {!props.loading && } + + + {children} + + + ); }); diff --git a/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx b/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx index ff78f27a7b710..b56f0cc3ff725 100644 --- a/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx +++ b/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx @@ -20,11 +20,13 @@ import { ChartsAxisHighlight } from '@mui/x-charts/ChartsAxisHighlight'; import { ChartsLegend } from '@mui/x-charts/ChartsLegend'; import { ChartsTooltip } from '@mui/x-charts/ChartsTooltip'; import { ChartsClipPath } from '@mui/x-charts/ChartsClipPath'; -import { useLineChartProps } from '@mui/x-charts/internals'; -import { ChartContainerPro } from '../ChartContainerPro'; +import { ChartsSurface } from '@mui/x-charts/ChartsSurface'; +import { useLineChartProps, ChartsWrapper } from '@mui/x-charts/internals'; import { ZoomSetup } from '../context/ZoomProvider/ZoomSetup'; import { useZoom } from '../context/ZoomProvider/useZoom'; import { ZoomProps } from '../context/ZoomProvider'; +import { ChartDataProviderPro } from '../context/ChartDataProviderPro'; +import { useChartContainerProProps } from '../ChartContainerPro/useChartContainerProProps'; function AreaPlotZoom(props: AreaPlotProps) { const { isInteracting } = useZoom(); @@ -150,6 +152,7 @@ const LineChartPro = React.forwardRef(function LineChartPro( const props = useThemeProps({ props: inProps, name: 'MuiLineChartPro' }); const { zoom, onZoomChange, ...other } = props; const { + chartsWrapperProps, chartContainerProps, axisClickHandlerProps, gridProps, @@ -165,31 +168,39 @@ const LineChartPro = React.forwardRef(function LineChartPro( legendProps, children, } = useLineChartProps(other); + const { chartDataProviderProProps, chartsSurfaceProps } = useChartContainerProProps( + chartContainerProps, + ref, + ); const Tooltip = props.slots?.tooltip ?? ChartsTooltip; return ( - - {props.onAxisClick && } - - - - - - - - - - {/* The `data-drawing-container` indicates that children are part of the drawing area. Ref: https://github.com/mui/mui-x/issues/13659 */} - - - - {!props.hideLegend && } - {!props.loading && } - - - {children} - + + + {!props.hideLegend && } + + {props.onAxisClick && } + + + + + + + + + + {/* The `data-drawing-container` indicates that children are part of the drawing area. Ref: https://github.com/mui/mui-x/issues/13659 */} + + + + {!props.loading && } + + + {children} + + + ); }); diff --git a/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx b/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx index 5ec98b8eb79fe..f189dbffa3586 100644 --- a/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx +++ b/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx @@ -9,12 +9,14 @@ import { ChartsVoronoiHandler } from '@mui/x-charts/ChartsVoronoiHandler'; import { ChartsAxis } from '@mui/x-charts/ChartsAxis'; import { ChartsGrid } from '@mui/x-charts/ChartsGrid'; import { ChartsLegend } from '@mui/x-charts/ChartsLegend'; +import { ChartsSurface } from '@mui/x-charts/ChartsSurface'; import { ChartsAxisHighlight } from '@mui/x-charts/ChartsAxisHighlight'; import { ChartsTooltip } from '@mui/x-charts/ChartsTooltip'; -import { useScatterChartProps } from '@mui/x-charts/internals'; -import { ChartContainerPro } from '../ChartContainerPro'; +import { useScatterChartProps, ChartsWrapper } from '@mui/x-charts/internals'; import { ZoomSetup } from '../context/ZoomProvider/ZoomSetup'; import { ZoomProps } from '../context/ZoomProvider'; +import { ChartDataProviderPro } from '../context/ChartDataProviderPro'; +import { useChartContainerProProps } from '../ChartContainerPro/useChartContainerProProps'; export interface ScatterChartProProps extends ScatterChartProps, ZoomProps {} @@ -35,6 +37,7 @@ const ScatterChartPro = React.forwardRef(function ScatterChartPro( const props = useThemeProps({ props: inProps, name: 'MuiScatterChartPro' }); const { zoom, onZoomChange, ...other } = props; const { + chartsWrapperProps, chartContainerProps, zAxisProps, voronoiHandlerProps, @@ -46,27 +49,35 @@ const ScatterChartPro = React.forwardRef(function ScatterChartPro( axisHighlightProps, children, } = useScatterChartProps(other); + const { chartDataProviderProProps, chartsSurfaceProps } = useChartContainerProProps( + chartContainerProps, + ref, + ); const Tooltip = props.slots?.tooltip ?? ChartsTooltip; return ( - - - {!props.disableVoronoi && } - - - - {/* The `data-drawing-container` indicates that children are part of the drawing area. Ref: https://github.com/mui/mui-x/issues/13659 */} - - - + + {!props.hideLegend && } - - {!props.loading && } - - {children} - - + + + {!props.disableVoronoi && } + + + + {/* The `data-drawing-container` indicates that children are part of the drawing area. Ref: https://github.com/mui/mui-x/issues/13659 */} + + + + + {!props.loading && } + + {children} + + + + ); }); diff --git a/packages/x-charts/src/BarChart/BarChart.test.tsx b/packages/x-charts/src/BarChart/BarChart.test.tsx index f93e1352ca788..8f598d3d21d89 100644 --- a/packages/x-charts/src/BarChart/BarChart.test.tsx +++ b/packages/x-charts/src/BarChart/BarChart.test.tsx @@ -24,6 +24,7 @@ describe('', () => { 'themeStyleOverrides', 'themeVariants', 'themeCustomPalette', + 'themeDefaultProps', ], }), ); diff --git a/packages/x-charts/src/BarChart/BarChart.tsx b/packages/x-charts/src/BarChart/BarChart.tsx index 5722559367505..57a0504989463 100644 --- a/packages/x-charts/src/BarChart/BarChart.tsx +++ b/packages/x-charts/src/BarChart/BarChart.tsx @@ -4,7 +4,7 @@ import PropTypes from 'prop-types'; import { useThemeProps } from '@mui/material/styles'; import { MakeOptional } from '@mui/x-internals/types'; import { BarPlot, BarPlotProps, BarPlotSlotProps, BarPlotSlots } from './BarPlot'; -import { ChartContainer, ChartContainerProps } from '../ChartContainer'; +import { ChartContainerProps } from '../ChartContainer'; import { ChartsAxis, ChartsAxisProps } from '../ChartsAxis'; import { BarSeriesType } from '../models/seriesType/bar'; import { ChartsTooltip } from '../ChartsTooltip'; @@ -25,6 +25,10 @@ import { ChartsOverlaySlots, } from '../ChartsOverlay/ChartsOverlay'; import { useBarChartProps } from './useBarChartProps'; +import { ChartDataProvider } from '../context'; +import { ChartsSurface } from '../ChartsSurface'; +import { useChartContainerProps } from '../ChartContainer/useChartContainerProps'; +import { ChartsWrapper } from '../internals/components/ChartsWrapper'; export interface BarChartSlots extends ChartsAxisSlots, @@ -100,6 +104,7 @@ const BarChart = React.forwardRef(function BarChart( ) { const props = useThemeProps({ props: inProps, name: 'MuiBarChart' }); const { + chartsWrapperProps, chartContainerProps, barPlotProps, axisClickHandlerProps, @@ -112,24 +117,32 @@ const BarChart = React.forwardRef(function BarChart( legendProps, children, } = useBarChartProps(props); + const { chartDataProviderProps, chartsSurfaceProps } = useChartContainerProps( + chartContainerProps, + ref, + ); const Tooltip = props.slots?.tooltip ?? ChartsTooltip; return ( - - {props.onAxisClick && } - - - - - - - - {!props.hideLegend && } - {!props.loading && } - - {children} - + + + {!props.hideLegend && } + + {props.onAxisClick && } + + + + + + + + {!props.loading && } + + {children} + + + ); }); diff --git a/packages/x-charts/src/BarChart/legend.ts b/packages/x-charts/src/BarChart/legend.ts index e2ee7ae8c7e92..254e34c6a1170 100644 --- a/packages/x-charts/src/BarChart/legend.ts +++ b/packages/x-charts/src/BarChart/legend.ts @@ -1,4 +1,4 @@ -import { LegendItemParams } from '../ChartsLegend/chartsLegend.types'; +import type { LegendItemParams } from '../ChartsLegend'; import { LegendGetter } from '../context/PluginProvider'; import { getLabel } from '../internals/getLabel'; @@ -12,6 +12,7 @@ const legendGetter: LegendGetter<'bar'> = (params) => { } acc.push({ + markType: series[seriesId].labelMarkType ?? 'square', id: seriesId, seriesId, color: series[seriesId].color, diff --git a/packages/x-charts/src/BarChart/useBarChartProps.ts b/packages/x-charts/src/BarChart/useBarChartProps.ts index ab65c93ad40e0..a1194f7249804 100644 --- a/packages/x-charts/src/BarChart/useBarChartProps.ts +++ b/packages/x-charts/src/BarChart/useBarChartProps.ts @@ -10,7 +10,9 @@ import { ChartsClipPathProps } from '../ChartsClipPath'; import { ChartsOverlayProps } from '../ChartsOverlay'; import { ChartsAxisProps } from '../ChartsAxis'; import { ChartsAxisHighlightProps } from '../ChartsAxisHighlight'; -import { ChartsLegendProps } from '../ChartsLegend'; +import { ChartsLegendSlotExtension } from '../ChartsLegend'; +import type { ChartsWrapperProps } from '../internals/components/ChartsWrapper'; +import { calculateMargins } from '../internals/calculateMargins'; /** * A helper function that extracts BarChartProps from the input props @@ -77,7 +79,7 @@ export const useBarChartProps = (props: BarChartProps) => { })), width, height, - margin, + margin: calculateMargins({ margin, hideLegend, slotProps, series }), colors, dataset, xAxis: @@ -86,7 +88,6 @@ export const useBarChartProps = (props: BarChartProps) => { yAxis: yAxis ?? (hasHorizontalSeries ? [{ id: DEFAULT_Y_AXIS_KEY, ...defaultAxisConfig }] : undefined), - sx, highlightedItem, onHighlightChange, disableAxisListener: @@ -143,12 +144,19 @@ export const useBarChartProps = (props: BarChartProps) => { ...axisHighlight, }; - const legendProps: ChartsLegendProps = { + const legendProps: ChartsLegendSlotExtension = { slots, slotProps, }; + const chartsWrapperProps: Omit = { + sx, + legendPosition: props.slotProps?.legend?.position, + legendDirection: props.slotProps?.legend?.direction, + }; + return { + chartsWrapperProps, chartContainerProps, barPlotProps, axisClickHandlerProps, diff --git a/packages/x-charts/src/ChartsLabel/ChartsLabel.test.tsx b/packages/x-charts/src/ChartsLabel/ChartsLabel.test.tsx index ab8d649ac28fa..50692b9412d23 100644 --- a/packages/x-charts/src/ChartsLabel/ChartsLabel.test.tsx +++ b/packages/x-charts/src/ChartsLabel/ChartsLabel.test.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { createRenderer } from '@mui/internal-test-utils/createRenderer'; import { describeConformance } from 'test/utils/describeConformance'; import { ChartsLabel } from '@mui/x-charts/ChartsLabel/ChartsLabel'; -import { labelClasses } from '@mui/x-charts/ChartsLabel/labelClasses'; +import { labelClasses } from '@mui/x-charts/ChartsLabel'; import { createTheme, ThemeProvider } from '@mui/material/styles'; describe('', () => { @@ -18,6 +18,13 @@ describe('', () => { ThemeProvider, createTheme, // SKIP - skip: ['themeVariants', 'componentProp', 'componentsProp'], + skip: [ + 'themeVariants', + 'themeStyleOverrides', + 'themeCustomPalette', + 'themeDefaultProps', + 'componentProp', + 'componentsProp', + ], })); }); diff --git a/packages/x-charts/src/ChartsLabel/ChartsLabel.tsx b/packages/x-charts/src/ChartsLabel/ChartsLabel.tsx index 92989a60b2027..e133765cebb3c 100644 --- a/packages/x-charts/src/ChartsLabel/ChartsLabel.tsx +++ b/packages/x-charts/src/ChartsLabel/ChartsLabel.tsx @@ -1,7 +1,7 @@ 'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; -import { styled, SxProps, Theme } from '@mui/material/styles'; +import { SxProps, Theme } from '@mui/material/styles'; import clsx from 'clsx'; import { ChartsLabelClasses, useUtilityClasses } from './labelClasses'; import { consumeThemeProps } from '../internals/consumeThemeProps'; @@ -16,21 +16,9 @@ export interface ChartsLabelProps { sx?: SxProps; } -const Root = styled('span', { - name: 'MuiChartsLabel', - slot: 'Root', - overridesResolver: (props, styles) => styles.root, -})<{ ownerState: ChartsLabelProps }>(({ theme }) => ({ - ...theme.typography.caption, - color: (theme.vars || theme).palette.text.primary, - lineHeight: undefined, - display: 'flex', -})); - /** - * @ignore - internal component. - * * Generates the label mark for the tooltip and legend. + * @ignore - internal component. */ const ChartsLabel = consumeThemeProps( 'MuiChartsLabel', @@ -41,9 +29,9 @@ const ChartsLabel = consumeThemeProps( const { children, className, classes, ...other } = props; return ( - + {children} - + ); }, ); diff --git a/packages/x-charts/src/ChartsLabel/ChartsLabelGradient.test.tsx b/packages/x-charts/src/ChartsLabel/ChartsLabelGradient.test.tsx index 637a0b5763754..9e5ae7a6d0491 100644 --- a/packages/x-charts/src/ChartsLabel/ChartsLabelGradient.test.tsx +++ b/packages/x-charts/src/ChartsLabel/ChartsLabelGradient.test.tsx @@ -3,7 +3,7 @@ import { createRenderer } from '@mui/internal-test-utils/createRenderer'; import { describeConformance } from 'test/utils/describeConformance'; import { createTheme, ThemeProvider } from '@mui/material/styles'; import { ChartsLabelGradient } from '@mui/x-charts/ChartsLabel/ChartsLabelGradient'; -import { labelGradientClasses } from '@mui/x-charts/ChartsLabel/labelGradientClasses'; +import { labelGradientClasses } from '@mui/x-charts/ChartsLabel'; describe('', () => { const { render } = createRenderer(); diff --git a/packages/x-charts/src/ChartsLabel/ChartsLabelGradient.tsx b/packages/x-charts/src/ChartsLabel/ChartsLabelGradient.tsx index 65975624744f2..c842ab1ad7d8e 100644 --- a/packages/x-charts/src/ChartsLabel/ChartsLabelGradient.tsx +++ b/packages/x-charts/src/ChartsLabel/ChartsLabelGradient.tsx @@ -13,26 +13,28 @@ import { consumeThemeProps } from '../internals/consumeThemeProps'; export interface ChartsLabelGradientProps { /** * A unique identifier for the gradient. - * * The `gradientId` will be used as `fill="url(#gradientId)"`. */ gradientId: string; /** * The direction of the gradient. - * - * @default 'row' + * @default 'horizontal' */ - direction?: 'column' | 'row'; + direction?: 'vertical' | 'horizontal'; /** * If `true`, the gradient will be reversed. */ reverse?: boolean; /** * If provided, the gradient will be rotated by 90deg. - * * Useful for linear gradients that are not in the correct orientation. */ rotate?: boolean; + /** + * The thickness of the gradient + * @default 12 + */ + thickness?: number; /** * Override or extend the styles applied to the component. */ @@ -41,20 +43,24 @@ export interface ChartsLabelGradientProps { sx?: SxProps; } -const getRotation = (direction?: 'column' | 'row', reverse?: boolean, rotate?: boolean) => { +const getRotation = ( + direction?: 'vertical' | 'horizontal', + reverse?: boolean, + rotate?: boolean, +) => { if (!rotate && reverse) { - return direction === 'column' ? 90 : 180; + return direction === 'vertical' ? 90 : 180; } if (rotate && !reverse) { - return direction === 'column' ? 0 : 90; + return direction === 'vertical' ? 0 : 90; } if (rotate && reverse) { - return direction === 'column' ? 180 : -90; + return direction === 'vertical' ? 180 : -90; } - return direction === 'column' ? -90 : 0; + return direction === 'vertical' ? -90 : 0; }; const Root = styled('div', { @@ -72,17 +78,17 @@ const Root = styled('div', { borderRadius: 2, overflow: 'hidden', }, - [`&.${labelGradientClasses.row}`]: { + [`&.${labelGradientClasses.horizontal}`]: { width: '100%', [`.${labelGradientClasses.mask}`]: { - height: 12, + height: ownerState.thickness, width: '100%', }, }, - [`&.${labelGradientClasses.column}`]: { + [`&.${labelGradientClasses.vertical}`]: { height: '100%', [`.${labelGradientClasses.mask}`]: { - width: 12, + width: ownerState.thickness, height: '100%', '> svg': { height: '100%', @@ -97,20 +103,21 @@ const Root = styled('div', { }); /** - * @ignore - internal component. - * * Generates the label Gradient for the tooltip and legend. + * @ignore - internal component. */ const ChartsLabelGradient = consumeThemeProps( 'MuiChartsLabelGradient', { defaultProps: { - direction: 'row', + direction: 'horizontal', + thickness: 12, }, classesResolver: useUtilityClasses, }, function ChartsLabelGradient(props: ChartsLabelGradientProps, ref: React.Ref) { - const { gradientId, direction, classes, className, ...other } = props; + const { gradientId, direction, classes, className, rotate, reverse, thickness, ...other } = + props; return (
- +
@@ -141,13 +148,11 @@ ChartsLabelGradient.propTypes = { classes: PropTypes.object, /** * The direction of the gradient. - * - * @default 'row' + * @default 'horizontal' */ - direction: PropTypes.oneOf(['column', 'row']), + direction: PropTypes.oneOf(['vertical', 'horizontal']), /** * A unique identifier for the gradient. - * * The `gradientId` will be used as `fill="url(#gradientId)"`. */ gradientId: PropTypes.string.isRequired, @@ -157,10 +162,14 @@ ChartsLabelGradient.propTypes = { reverse: PropTypes.bool, /** * If provided, the gradient will be rotated by 90deg. - * * Useful for linear gradients that are not in the correct orientation. */ rotate: PropTypes.bool, + /** + * The thickness of the gradient + * @default 12 + */ + thickness: PropTypes.number, } as any; export { ChartsLabelGradient }; diff --git a/packages/x-charts/src/ChartsLabel/ChartsLabelMark.test.tsx b/packages/x-charts/src/ChartsLabel/ChartsLabelMark.test.tsx index 25d954881b7f6..66fa1d0ee9d0c 100644 --- a/packages/x-charts/src/ChartsLabel/ChartsLabelMark.test.tsx +++ b/packages/x-charts/src/ChartsLabel/ChartsLabelMark.test.tsx @@ -3,7 +3,7 @@ import { createRenderer } from '@mui/internal-test-utils/createRenderer'; import { describeConformance } from 'test/utils/describeConformance'; import { createTheme, ThemeProvider } from '@mui/material/styles'; import { ChartsLabelMark } from '@mui/x-charts/ChartsLabel/ChartsLabelMark'; -import { labelMarkClasses } from '@mui/x-charts/ChartsLabel/labelMarkClasses'; +import { labelMarkClasses } from '@mui/x-charts/ChartsLabel'; describe('', () => { const { render } = createRenderer(); diff --git a/packages/x-charts/src/ChartsLabel/ChartsLabelMark.tsx b/packages/x-charts/src/ChartsLabel/ChartsLabelMark.tsx index f8d6ad54dc04e..fbe440fc35cc1 100644 --- a/packages/x-charts/src/ChartsLabel/ChartsLabelMark.tsx +++ b/packages/x-charts/src/ChartsLabel/ChartsLabelMark.tsx @@ -66,13 +66,13 @@ const Root = styled('div', { }); /** - * @ignore - internal component. - * * Generates the label mark for the tooltip and legend. + * @ignore - internal component. */ const ChartsLabelMark = consumeThemeProps( 'MuiChartsLabelMark', { + defaultProps: { type: 'square' }, classesResolver: useUtilityClasses, }, function ChartsLabelMark(props: ChartsLabelMarkProps, ref: React.Ref) { @@ -88,7 +88,7 @@ const ChartsLabelMark = consumeThemeProps( >
- +
diff --git a/packages/x-charts/src/ChartsLabel/index.ts b/packages/x-charts/src/ChartsLabel/index.ts new file mode 100644 index 0000000000000..e50d5aba4022a --- /dev/null +++ b/packages/x-charts/src/ChartsLabel/index.ts @@ -0,0 +1,9 @@ +// export * from './ChartsLabel'; +export type { ChartsLabelMarkProps } from './ChartsLabelMark'; +// export * from './ChartsLabelGradient'; +export { labelClasses } from './labelClasses'; +export type { ChartsLabelClasses } from './labelClasses'; +export { labelMarkClasses } from './labelMarkClasses'; +export type { ChartsLabelMarkClasses } from './labelMarkClasses'; +export { labelGradientClasses } from './labelGradientClasses'; +export type { ChartsLabelGradientClasses } from './labelGradientClasses'; diff --git a/packages/x-charts/src/ChartsLabel/labelClasses.ts b/packages/x-charts/src/ChartsLabel/labelClasses.ts index 236d118902902..b0b89d5d69efe 100644 --- a/packages/x-charts/src/ChartsLabel/labelClasses.ts +++ b/packages/x-charts/src/ChartsLabel/labelClasses.ts @@ -8,8 +8,6 @@ export interface ChartsLabelClasses { root: string; } -export type ChartsLabelClassKey = keyof ChartsLabelClasses; - export function getLabelUtilityClass(slot: string) { return generateUtilityClass('MuiChartsLabel', slot); } diff --git a/packages/x-charts/src/ChartsLabel/labelGradientClasses.tsx b/packages/x-charts/src/ChartsLabel/labelGradientClasses.tsx index 808c653434bcc..03031ee6b7eca 100644 --- a/packages/x-charts/src/ChartsLabel/labelGradientClasses.tsx +++ b/packages/x-charts/src/ChartsLabel/labelGradientClasses.tsx @@ -9,20 +9,20 @@ export interface ChartsLabelGradientClasses { /** Styles applied to the "mask" that gives shape to the gradient. */ mask: string; /** Styles applied when direction is "column". */ - column: string; + vertical: string; /** Styles applied when direction is "row". */ - row: string; + horizontal: string; + /** Styles applied to the element filled by the gradient */ + fill: string; } -export type ChartsLabelGradientClassKey = keyof ChartsLabelGradientClasses; - export function getLabelGradientUtilityClass(slot: string) { return generateUtilityClass('MuiChartsLabelGradient', slot); } export const labelGradientClasses: ChartsLabelGradientClasses = generateUtilityClasses( 'MuiChartsLabelGradient', - ['root', 'column', 'row', 'mask'], + ['root', 'vertical', 'horizontal', 'mask', 'fill'], ); export const useUtilityClasses = (props: ChartsLabelGradientProps) => { @@ -31,6 +31,7 @@ export const useUtilityClasses = (props: ChartsLabelGradientProps) => { const slots = { root: ['root', direction], mask: ['mask'], + fill: ['fill'], }; return composeClasses(slots, getLabelGradientUtilityClass, props.classes); diff --git a/packages/x-charts/src/ChartsLabel/labelMarkClasses.ts b/packages/x-charts/src/ChartsLabel/labelMarkClasses.ts index 85004c38725a6..e0f54754d2e00 100644 --- a/packages/x-charts/src/ChartsLabel/labelMarkClasses.ts +++ b/packages/x-charts/src/ChartsLabel/labelMarkClasses.ts @@ -14,17 +14,17 @@ export interface ChartsLabelMarkClasses { square: string; /** Styles applied to the mark type "circle". */ circle: string; + /** Styles applied to the element with fill={color} attribute. */ + fill: string; } -export type ChartsLabelMarkClassKey = keyof ChartsLabelMarkClasses; - export function getLabelMarkUtilityClass(slot: string) { return generateUtilityClass('MuiChartsLabelMark', slot); } export const labelMarkClasses: ChartsLabelMarkClasses = generateUtilityClasses( 'MuiChartsLabelMark', - ['root', 'line', 'square', 'circle', 'mask'], + ['root', 'line', 'square', 'circle', 'mask', 'fill'], ); export const useUtilityClasses = (props: ChartsLabelMarkProps) => { @@ -32,6 +32,7 @@ export const useUtilityClasses = (props: ChartsLabelMarkProps) => { const slots = { root: ['root', type], mask: ['mask'], + fill: ['fill'], }; return composeClasses(slots, getLabelMarkUtilityClass, props.classes); diff --git a/packages/x-charts/src/ChartsLegend/ChartsLegend.test.tsx b/packages/x-charts/src/ChartsLegend/ChartsLegend.test.tsx new file mode 100644 index 0000000000000..b943131348948 --- /dev/null +++ b/packages/x-charts/src/ChartsLegend/ChartsLegend.test.tsx @@ -0,0 +1,43 @@ +import * as React from 'react'; +import { createRenderer, describeConformance } from '@mui/internal-test-utils'; +import { ChartsLegend, legendClasses } from '@mui/x-charts/ChartsLegend'; +import { ChartDataProvider } from '@mui/x-charts/context'; +import { ChartsSurface } from '@mui/x-charts/ChartsSurface'; +import { createTheme, ThemeProvider } from '@mui/material/styles'; + +describe('', () => { + const { render } = createRenderer(); + + describeConformance(, () => ({ + classes: legendClasses, + inheritComponent: 'ul', + render: (node) => + render(node, { + wrapper: ({ children }) => ( + + {/* Has to be first as describeConformance picks the "first child" */} + {/* https://github.com/mui/material-ui/blob/c0620e333641deda56f3cd68c7c3736098ee818c/packages-internal/test-utils/src/describeConformance.tsx#L257 */} + {children} + + + ), + }), + muiName: 'MuiChartsLegend', + testComponentPropWith: 'ul', + refInstanceof: window.HTMLUListElement, + ThemeProvider, + createTheme, + // SKIP + skip: ['themeVariants', 'componentProp', 'componentsProp'], + })); +}); diff --git a/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx b/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx index 1a68804b785fe..a6c4c0a24267e 100644 --- a/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/ChartsLegend.tsx @@ -1,97 +1,136 @@ 'use client'; import * as React from 'react'; +import { styled, SxProps, Theme } from '@mui/material/styles'; import PropTypes from 'prop-types'; -import useSlotProps from '@mui/utils/useSlotProps'; -import composeClasses from '@mui/utils/composeClasses'; -import { DefaultizedProps } from '@mui/x-internals/types'; -import { useThemeProps, useTheme, Theme } from '@mui/material/styles'; -import { getSeriesToDisplay } from './utils'; -import { getLegendUtilityClass } from './chartsLegendClasses'; -import { DefaultChartsLegend, LegendRendererProps } from './DefaultChartsLegend'; -import { useSeries } from '../hooks/useSeries'; -import { LegendPlacement } from './legend.types'; - -export type ChartsLegendPropsBase = Omit< - LegendRendererProps, - keyof LegendPlacement | 'series' | 'seriesToDisplay' | 'drawingArea' -> & - LegendPlacement; - -export interface ChartsLegendSlots { +import clsx from 'clsx'; +import { useLegend } from '../hooks/useLegend'; +import type { Direction } from './direction'; +import { SeriesLegendItemContext } from './legendContext.types'; +import { ChartsLabelMark } from '../ChartsLabel/ChartsLabelMark'; +import { seriesContextBuilder } from './onClickContextBuilder'; +import { legendClasses, useUtilityClasses, type ChartsLegendClasses } from './chartsLegendClasses'; +import { consumeSlots } from '../internals/consumeSlots'; +import { ChartsLabel } from '../ChartsLabel/ChartsLabel'; + +export interface ChartsLegendProps { /** - * Custom rendering of the legend. - * @default DefaultChartsLegend + * Callback fired when a legend item is clicked. + * @param {React.MouseEvent} event The click event. + * @param {SeriesLegendItemContext} legendItem The legend item data. + * @param {number} index The index of the clicked legend item. */ - legend?: React.JSXElementConstructor; -} - -export interface ChartsLegendSlotProps { - legend?: Partial; -} - -export interface ChartsLegendProps extends ChartsLegendPropsBase { + onItemClick?: ( + event: React.MouseEvent, + legendItem: SeriesLegendItemContext, + index: number, + ) => void; /** - * Overridable component slots. - * @default {} + * The direction of the legend layout. + * The default depends on the chart. */ - slots?: ChartsLegendSlots; + direction?: Direction; /** - * The props used for each component slot. - * @default {} + * Override or extend the styles applied to the component. */ - slotProps?: ChartsLegendSlotProps; + classes?: Partial; + className?: string; + sx?: SxProps; } -type DefaultizedChartsLegendProps = DefaultizedProps; - -const useUtilityClasses = (ownerState: DefaultizedChartsLegendProps & { theme: Theme }) => { - const { classes, direction } = ownerState; - const slots = { - root: ['root', direction], - mark: ['mark'], - label: ['label'], - series: ['series'], - itemBackground: ['itemBackground'], - }; - - return composeClasses(slots, getLegendUtilityClass, classes); -}; - -function ChartsLegend(inProps: ChartsLegendProps) { - const props = useThemeProps({ - props: inProps, - name: 'MuiChartsLegend', - }); - - const defaultizedProps: DefaultizedChartsLegendProps = { - direction: 'row', - ...props, - position: { horizontal: 'middle', vertical: 'top', ...props.position }, - }; - const { slots, slotProps, ...other } = defaultizedProps; - - const theme = useTheme(); - const classes = useUtilityClasses({ ...defaultizedProps, theme }); - - const series = useSeries(); - - const seriesToDisplay = getSeriesToDisplay(series); - - const ChartLegendRender = slots?.legend ?? DefaultChartsLegend; - const chartLegendRenderProps = useSlotProps({ - elementType: ChartLegendRender, - externalSlotProps: slotProps?.legend, - additionalProps: { - ...other, - classes, - series, - seriesToDisplay, - }, - ownerState: {}, - }); - - return ; -} +const RootElement = styled('ul', { + name: 'MuiChartsLegend', + slot: 'Root', + overridesResolver: (props, styles) => styles.root, +})<{ ownerState: ChartsLegendProps }>(({ ownerState, theme }) => ({ + ...theme.typography.caption, + color: (theme.vars || theme).palette.text.primary, + lineHeight: '100%', + display: 'flex', + flexDirection: ownerState.direction === 'vertical' ? 'column' : 'row', + alignItems: ownerState.direction === 'vertical' ? undefined : 'center', + flexShrink: 0, + gap: theme.spacing(2), + listStyleType: 'none', + paddingInlineStart: 0, + marginBlock: theme.spacing(1), + marginInline: theme.spacing(1), + flexWrap: 'wrap', + li: { + display: ownerState.direction === 'horizontal' ? 'inline-flex' : undefined, + }, + [`button.${legendClasses.series}`]: { + // Reset button styles + background: 'none', + border: 'none', + padding: 0, + fontFamily: 'inherit', + fontWeight: 'inherit', + fontSize: 'inherit', + letterSpacing: 'inherit', + color: 'inherit', + }, + [`& .${legendClasses.series}`]: { + display: ownerState.direction === 'vertical' ? 'flex' : 'inline-flex', + alignItems: 'center', + gap: theme.spacing(1), + }, +})); + +const ChartsLegend = consumeSlots( + 'MuiChartsLegend', + 'legend', + { + defaultProps: { direction: 'horizontal' }, + // @ts-expect-error position is used only in the slots, but it is passed to the SVG wrapper. + // We omit it here to avoid passing to slots. + omitProps: ['position'], + classesResolver: useUtilityClasses, + }, + function ChartsLegend(props: ChartsLegendProps, ref: React.Ref) { + const data = useLegend(); + const { direction, onItemClick, className, classes, ...other } = props; + + if (data.items.length === 0) { + return null; + } + + const Element = onItemClick ? 'button' : 'div'; + + return ( + + {data.items.map((item, i) => { + return ( +
  • + onItemClick(event, seriesContextBuilder(item), i) + : undefined + } + > + + {item.label} + +
  • + ); + })} +
    + ); + }, +); ChartsLegend.propTypes = { // ----------------------------- Warning -------------------------------- @@ -102,69 +141,19 @@ ChartsLegend.propTypes = { * Override or extend the styles applied to the component. */ classes: PropTypes.object, + className: PropTypes.string, /** * The direction of the legend layout. * The default depends on the chart. */ - direction: PropTypes.oneOf(['column', 'row']), - /** - * Set to true to hide the legend. - * @default false - */ - hidden: PropTypes.bool, - /** - * Space between two legend items (in px). - * @default 10 - */ - itemGap: PropTypes.number, - /** - * Height of the item mark (in px). - * @default 20 - */ - itemMarkHeight: PropTypes.number, - /** - * Width of the item mark (in px). - * @default 20 - */ - itemMarkWidth: PropTypes.number, - /** - * Style applied to legend labels. - * @default theme.typography.subtitle1 - */ - labelStyle: PropTypes.object, - /** - * Space between the mark and the label (in px). - * @default 5 - */ - markGap: PropTypes.number, + direction: PropTypes.oneOf(['horizontal', 'vertical']), /** * Callback fired when a legend item is clicked. - * @param {React.MouseEvent} event The click event. + * @param {React.MouseEvent} event The click event. * @param {SeriesLegendItemContext} legendItem The legend item data. * @param {number} index The index of the clicked legend item. */ onItemClick: PropTypes.func, - /** - * Legend padding (in px). - * Can either be a single number, or an object with top, left, bottom, right properties. - * @default 10 - */ - padding: PropTypes.oneOfType([ - PropTypes.number, - PropTypes.shape({ - bottom: PropTypes.number, - left: PropTypes.number, - right: PropTypes.number, - top: PropTypes.number, - }), - ]), - /** - * The position of the legend. - */ - position: PropTypes.shape({ - horizontal: PropTypes.oneOf(['left', 'middle', 'right']).isRequired, - vertical: PropTypes.oneOf(['bottom', 'middle', 'top']).isRequired, - }), /** * The props used for each component slot. * @default {} @@ -175,6 +164,11 @@ ChartsLegend.propTypes = { * @default {} */ slots: PropTypes.object, + sx: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), + PropTypes.func, + PropTypes.object, + ]), } as any; export { ChartsLegend }; diff --git a/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx b/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx deleted file mode 100644 index bf8521339daab..0000000000000 --- a/packages/x-charts/src/ChartsLegend/ChartsLegendItem.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import * as React from 'react'; -import clsx from 'clsx'; -import { useRtl } from '@mui/system/RtlProvider'; -import { ChartsText, ChartsTextStyle } from '../ChartsText'; -import { LegendItemParams } from './chartsLegend.types'; -import { ChartsLegendClasses } from './chartsLegendClasses'; - -export interface ChartsLegendItemProps extends LegendItemParams { - positionY: number; - label: string; - positionX: number; - innerHeight: number; - innerWidth: number; - color: string; - gapX: number; - gapY: number; - legendWidth: number; - itemMarkHeight: number; - itemMarkWidth: number; - markGap: number; - labelStyle: ChartsTextStyle; - classes?: Omit, 'column' | 'row' | 'label'>; - onClick?: (event: React.MouseEvent) => void; -} - -/** - * @ignore - internal component. - */ -function ChartsLegendItem(props: ChartsLegendItemProps) { - const isRTL = useRtl(); - const { - id, - positionY, - label, - positionX, - innerHeight, - innerWidth, - legendWidth, - color, - gapX, - gapY, - itemMarkHeight, - itemMarkWidth, - markGap, - labelStyle, - classes, - onClick, - } = props; - - return ( - - - - - - ); -} - -export { ChartsLegendItem }; diff --git a/packages/x-charts/src/ChartsLegend/ContinuousColorLegend.test.tsx b/packages/x-charts/src/ChartsLegend/ContinuousColorLegend.test.tsx new file mode 100644 index 0000000000000..baf93faeb0e46 --- /dev/null +++ b/packages/x-charts/src/ChartsLegend/ContinuousColorLegend.test.tsx @@ -0,0 +1,53 @@ +import * as React from 'react'; +import { createRenderer, describeConformance } from '@mui/internal-test-utils'; +import { ContinuousColorLegend, continuousColorLegendClasses } from '@mui/x-charts/ChartsLegend'; +import { ChartDataProvider } from '@mui/x-charts/context'; +import { ChartsSurface } from '@mui/x-charts/ChartsSurface'; +import { createTheme, ThemeProvider } from '@mui/material/styles'; + +describe('', () => { + const { render } = createRenderer(); + + describeConformance(, () => ({ + classes: continuousColorLegendClasses, + inheritComponent: 'ul', + render: (node) => + render(node, { + wrapper: ({ children }) => ( + `${t}`, + }, + }, + ]} + > + {/* Has to be first as describeConformance picks the "first child" */} + {/* https://github.com/mui/material-ui/blob/c0620e333641deda56f3cd68c7c3736098ee818c/packages-internal/test-utils/src/describeConformance.tsx#L257 */} + {children} + + + ), + }), + muiName: 'MuiContinuousColorLegend', + testComponentPropWith: 'ul', + refInstanceof: window.HTMLUListElement, + ThemeProvider, + createTheme, + // SKIP + skip: ['themeVariants', 'componentProp', 'componentsProp'], + })); +}); diff --git a/packages/x-charts/src/ChartsLegend/ContinuousColorLegend.tsx b/packages/x-charts/src/ChartsLegend/ContinuousColorLegend.tsx index e45d1480d8150..98c1cb1ed7c09 100644 --- a/packages/x-charts/src/ChartsLegend/ContinuousColorLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/ContinuousColorLegend.tsx @@ -1,352 +1,280 @@ 'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; -import { ScaleSequential } from '@mui/x-charts-vendor/d3-scale'; -import { useTheme } from '@mui/material/styles'; -import { useRtl } from '@mui/system/RtlProvider'; -import ChartsContinuousGradient from '../internals/components/ChartsAxesGradients/ChartsContinuousGradient'; -import { AxisDefaultized, ContinuousScaleName } from '../models/axis'; -import { useChartId, useDrawingArea } from '../hooks'; -import { getScale } from '../internals/getScale'; -import { getPercentageValue } from '../internals/getPercentageValue'; -import { ChartsText, ChartsTextProps } from '../ChartsText'; -import { getStringSize } from '../internals/domUtils'; +import { styled, SxProps, Theme } from '@mui/material/styles'; +import clsx from 'clsx'; +import { AppendKeys } from '@mui/x-internals/types'; +import { AxisDefaultized } from '../models/axis'; import { useAxis } from './useAxis'; +import { ColorLegendSelector } from './colorLegend.types'; +import { ChartsLabel } from '../ChartsLabel/ChartsLabel'; +import { ChartsLabelGradient, ChartsLabelGradientProps } from '../ChartsLabel/ChartsLabelGradient'; +import { Direction } from './direction'; +import { consumeThemeProps } from '../internals/consumeThemeProps'; import { - AnchorPosition, - BoundingBox, - ColorLegendSelector, - LegendPlacement, - Position, - TextPosition, -} from './legend.types'; - -function getPositionOffset(position: AnchorPosition, legendBox: BoundingBox, svgBox: BoundingBox) { - let offsetX = 0; - let offsetY = 0; - - switch (position.horizontal) { - case 'left': - offsetX = 0; - break; - case 'middle': - offsetX = (svgBox.width - legendBox.width) / 2; - break; - case 'right': - default: - offsetX = svgBox.width - legendBox.width; - break; - } - switch (position.vertical) { - case 'top': - offsetY = 0; - break; - case 'middle': - offsetY = (svgBox.height - legendBox.height) / 2; - break; - case 'bottom': - default: - offsetY = svgBox.height - legendBox.height; - break; - } - - return { offsetX, offsetY }; -} - -/** - * Takes placement parameters and element bounding boxes. - * Returns the x, y coordinates of the elements. And the textAnchor, dominantBaseline for texts. - */ -function getElementPositions( - text1Box: BoundingBox, - barBox: BoundingBox, - text2Box: BoundingBox, - params: { - spacing: number; - align: ContinuousColorLegendProps['align']; - direction: ContinuousColorLegendProps['direction']; - }, -): { - text1: TextPosition; - text2: TextPosition; - bar: Position; - boundingBox: BoundingBox; -} { - if (params.direction === 'column') { - const text1 = { y: text1Box.height, dominantBaseline: 'auto' } as const; - const text2 = { - y: text1Box.height + 2 * params.spacing + barBox.height, - dominantBaseline: 'hanging', - } as const; - const bar = { y: text1Box.height + params.spacing }; - - const totalWidth = Math.max(text1Box.width, barBox.width, text2Box.width); - const totalHeight = text1Box.height + barBox.height + text2Box.height + 2 * params.spacing; - - const boundingBox = { width: totalWidth, height: totalHeight }; - switch (params.align) { - case 'start': - return { - text1: { ...text1, textAnchor: 'start', x: 0 }, - text2: { ...text2, textAnchor: 'start', x: 0 }, - bar: { ...bar, x: 0 }, - boundingBox, - }; - case 'end': - return { - text1: { ...text1, textAnchor: 'end', x: totalWidth }, - text2: { ...text2, textAnchor: 'end', x: totalWidth }, - bar: { ...bar, x: totalWidth - barBox.width }, - boundingBox, - }; - case 'middle': - default: - return { - text1: { ...text1, textAnchor: 'middle', x: totalWidth / 2 }, - text2: { ...text2, textAnchor: 'middle', x: totalWidth / 2 }, - bar: { ...bar, x: totalWidth / 2 - barBox.width / 2 }, - boundingBox, - }; - } - } else { - const text1 = { x: text1Box.width, textAnchor: 'end' } as const; - const text2 = { - x: text1Box.width + 2 * params.spacing + barBox.width, - textAnchor: 'start', - } as const; - const bar = { x: text1Box.width + params.spacing }; - - const totalHeight = Math.max(text1Box.height, barBox.height, text2Box.height); - const totalWidth = text1Box.width + barBox.width + text2Box.width + 2 * params.spacing; - - const boundingBox = { width: totalWidth, height: totalHeight }; - - switch (params.align) { - case 'start': - return { - text1: { ...text1, dominantBaseline: 'hanging', y: 0 }, - text2: { ...text2, dominantBaseline: 'hanging', y: 0 }, - bar: { ...bar, y: 0 }, - boundingBox, - }; - case 'end': - return { - text1: { ...text1, dominantBaseline: 'auto', y: totalHeight }, - text2: { ...text2, dominantBaseline: 'auto', y: totalHeight }, - bar: { ...bar, y: totalHeight - barBox.height }, - boundingBox, - }; - case 'middle': - default: - return { - text1: { ...text1, dominantBaseline: 'central', y: totalHeight / 2 }, - text2: { ...text2, dominantBaseline: 'central', y: totalHeight / 2 }, - bar: { ...bar, y: totalHeight / 2 - barBox.height / 2 }, - boundingBox, - }; - } - } -} + continuousColorLegendClasses, + ContinuousColorLegendClasses, + useUtilityClasses, +} from './continuousColorLegendClasses'; +import { useChartGradientObjectBound } from '../internals/components/ChartsAxesGradients'; type LabelFormatter = (params: { value: number | Date; formattedValue: string }) => string; -export interface ContinuousColorLegendProps extends LegendPlacement, ColorLegendSelector { +export interface ContinuousColorLegendProps + extends ColorLegendSelector, + AppendKeys, 'gradient'>, + Pick { + /** + * The direction of the legend layout. + * @default 'horizontal' + */ + direction?: Direction; /** * The label to display at the minimum side of the gradient. * Can either be a string, or a function. - * @default ({ formattedValue }) => formattedValue + * @default formattedValue */ minLabel?: string | LabelFormatter; /** * The label to display at the maximum side of the gradient. * Can either be a string, or a function. * If not defined, the formatted maximal value is display. - * @default ({ formattedValue }) => formattedValue + * @default formattedValue */ maxLabel?: string | LabelFormatter; /** - * A unique identifier for the gradient. + * The id for the gradient to use. + * If not provided, it will use the generated gradient from the axis configuration. + * The `gradientId` will be used as `fill="url(#gradientId)"`. * @default auto-generated id */ - id?: string; - /** - * The scale used to display gradient colors. - * @default 'linear' - */ - scaleType?: ContinuousScaleName; - /** - * The length of the gradient bar. - * Can be a number (in px) or a string with a percentage such as '50%'. - * The '100%' is the length of the svg. - * @default '50%' - */ - length?: number | string; + gradientId?: string; /** - * The thickness of the gradient bar. - * @default 5 + * Where to position the labels relative to the gradient. + * @default 'end' */ - thickness?: number; + labelPosition?: 'start' | 'end' | 'extremes'; /** - * The alignment of the texts with the gradient bar. - * @default 'middle' + * If `true`, the gradient and labels will be reversed. + * @default false */ - align?: 'start' | 'middle' | 'end'; + reverse?: boolean; /** - * The space between the gradient bar and the labels. - * @default 4 + * Override or extend the styles applied to the component. */ - spacing?: number; - /** - * The style applied to labels. - * @default theme.typography.subtitle1 - */ - labelStyle?: ChartsTextProps['style']; + classes?: Partial; + className?: string; + sx?: SxProps; } -const defaultLabelFormatter: LabelFormatter = ({ formattedValue }) => formattedValue; - -function ContinuousColorLegend(props: ContinuousColorLegendProps) { - const theme = useTheme(); - const isRtl = useRtl(); - const { - id: idProp, - minLabel = defaultLabelFormatter, - maxLabel = defaultLabelFormatter, - scaleType = 'linear', - direction, - length = '50%', - thickness = 5, - spacing = 4, - align = 'middle', - labelStyle = theme.typography.subtitle1 as ChartsTextProps['style'], - position, - axisDirection, - axisId, - } = props; - - const chartId = useChartId(); - const id = idProp ?? `gradient-legend-${chartId}`; - - const axisItem = useAxis({ axisDirection, axisId }); - const { width, height, left, right, top, bottom } = useDrawingArea(); - - const refLength = direction === 'column' ? height + top + bottom : width + left + right; - const size = getPercentageValue(length, refLength); - - const isReversed = direction === 'column'; - - const colorMap = axisItem?.colorMap; - if (!colorMap || !colorMap.type || colorMap.type !== 'continuous') { - return null; +const templateAreas = (reverse?: boolean) => { + const startLabel = reverse ? 'max-label' : 'min-label'; + const endLabel = reverse ? 'min-label' : 'max-label'; + + return { + row: { + start: ` + '${startLabel} . ${endLabel}' + 'gradient gradient gradient' + `, + end: ` + 'gradient gradient gradient' + '${startLabel} . ${endLabel}' + `, + extremes: ` + '${startLabel} gradient ${endLabel}' + `, + }, + column: { + start: ` + '${endLabel} gradient' + '. gradient' + '${startLabel} gradient' + `, + end: ` + 'gradient ${endLabel}' + 'gradient .' + 'gradient ${startLabel}' + `, + extremes: ` + '${endLabel}' + 'gradient' + '${startLabel}' + `, + }, + }; +}; + +const RootElement = styled('ul', { + name: 'MuiContinuousColorLegend', + slot: 'Root', + overridesResolver: (props, styles) => styles.root, +})<{ ownerState: ContinuousColorLegendProps }>(({ theme, ownerState }) => ({ + ...theme.typography.caption, + color: (theme.vars || theme).palette.text.primary, + lineHeight: '100%', + display: 'grid', + flexShrink: 0, + gap: theme.spacing(0.5), + listStyleType: 'none', + paddingInlineStart: 0, + marginBlock: theme.spacing(1), + marginInline: theme.spacing(1), + [`&.${continuousColorLegendClasses.horizontal}`]: { + gridTemplateRows: 'min-content min-content', + gridTemplateColumns: 'min-content auto min-content', + [`&.${continuousColorLegendClasses.start}`]: { + gridTemplateAreas: templateAreas(ownerState.reverse).row.start, + }, + [`&.${continuousColorLegendClasses.end}`]: { + gridTemplateAreas: templateAreas(ownerState.reverse).row.end, + }, + [`&.${continuousColorLegendClasses.extremes}`]: { + gridTemplateAreas: templateAreas(ownerState.reverse).row.extremes, + gridTemplateRows: 'min-content', + alignItems: 'center', + }, + }, + [`&.${continuousColorLegendClasses.vertical}`]: { + gridTemplateRows: 'min-content auto min-content', + gridTemplateColumns: 'min-content min-content', + [`&.${continuousColorLegendClasses.start}`]: { + gridTemplateAreas: templateAreas(ownerState.reverse).column.start, + [`.${continuousColorLegendClasses.maxLabel}, .${continuousColorLegendClasses.minLabel}`]: { + justifySelf: 'end', + }, + }, + [`&.${continuousColorLegendClasses.end}`]: { + gridTemplateAreas: templateAreas(ownerState.reverse).column.end, + [`.${continuousColorLegendClasses.maxLabel}, .${continuousColorLegendClasses.minLabel}`]: { + justifySelf: 'start', + }, + }, + [`&.${continuousColorLegendClasses.extremes}`]: { + gridTemplateAreas: templateAreas(ownerState.reverse).column.extremes, + gridTemplateColumns: 'min-content', + [`.${continuousColorLegendClasses.maxLabel}, .${continuousColorLegendClasses.minLabel}`]: { + justifySelf: 'center', + }, + }, + }, + [`.${continuousColorLegendClasses.gradient}`]: { + gridArea: 'gradient', + }, + [`.${continuousColorLegendClasses.maxLabel}`]: { + gridArea: 'max-label', + }, + [`.${continuousColorLegendClasses.minLabel}`]: { + gridArea: 'min-label', + }, +})); + +const getText = ( + label: string | LabelFormatter | undefined, + value: number | Date, + formattedValue: string, +) => { + if (typeof label === 'string') { + return label; } + return label?.({ value, formattedValue }) ?? formattedValue; +}; + +const ContinuousColorLegend = consumeThemeProps( + 'MuiContinuousColorLegend', + { + defaultProps: { + direction: 'horizontal', + labelPosition: 'end', + axisDirection: 'z', + }, + classesResolver: useUtilityClasses, + }, + function ContinuousColorLegend( + props: ContinuousColorLegendProps, + ref: React.Ref, + ) { + const { + minLabel, + maxLabel, + direction, + axisDirection, + axisId, + rotateGradient, + reverse, + classes, + className, + gradientId, + labelPosition, + thickness, + ...other + } = props; + + const generateGradientId = useChartGradientObjectBound(); + const axisItem = useAxis({ axisDirection, axisId }); + + const colorMap = axisItem?.colorMap; + if (!colorMap || !colorMap.type || colorMap.type !== 'continuous') { + return null; + } - // Define the coordinate to color mapping - - const colorScale = axisItem.colorScale as ScaleSequential; - - const minValue = colorMap.min ?? 0; - const maxValue = colorMap.max ?? 100; - - const scale = getScale(scaleType, [minValue, maxValue], isReversed ? [size, 0] : [0, size]); - - // Get texts to display - - const formattedMin = - (axisItem as AxisDefaultized).valueFormatter?.(minValue, { location: 'legend' }) ?? - minValue.toLocaleString(); - - const formattedMax = - (axisItem as AxisDefaultized).valueFormatter?.(maxValue, { location: 'legend' }) ?? - maxValue.toLocaleString(); - - const minText = - typeof minLabel === 'string' - ? minLabel - : minLabel({ value: minValue ?? 0, formattedValue: formattedMin }); - - const maxText = - typeof maxLabel === 'string' - ? maxLabel - : maxLabel({ value: maxValue ?? 0, formattedValue: formattedMax }); - - const text1 = isReversed ? maxText : minText; - const text2 = isReversed ? minText : maxText; - - const text1Box = getStringSize(text1, { ...labelStyle }); - const text2Box = getStringSize(text2, { ...labelStyle }); - - // Place bar and texts - - const barBox = - direction === 'column' || (isRtl && direction === 'row') - ? { width: thickness, height: size } - : { width: size, height: thickness }; - - const legendPositions = getElementPositions(text1Box, barBox, text2Box, { - spacing, - align, - direction, - }); - const svgBoundingBox = { width: width + left + right, height: height + top + bottom }; - - const positionOffset = getPositionOffset( - { horizontal: 'middle', vertical: 'top', ...position }, - legendPositions.boundingBox, - svgBoundingBox, - ); - - return ( - - - - - - - ); -} + const minValue = colorMap.min ?? 0; + const maxValue = colorMap.max ?? 100; + + // Get texts to display + + const valueFormatter = (axisItem as AxisDefaultized)?.valueFormatter; + const formattedMin = valueFormatter + ? valueFormatter(minValue, { location: 'legend' }) + : minValue.toLocaleString(); + + const formattedMax = valueFormatter + ? valueFormatter(maxValue, { location: 'legend' }) + : maxValue.toLocaleString(); + + const minText = getText(minLabel, minValue, formattedMin); + const maxText = getText(maxLabel, maxValue, formattedMax); + + const minComponent = ( +
  • + {minText} +
  • + ); + + const maxComponent = ( +
  • + {maxText} +
  • + ); + + return ( + + {reverse ? maxComponent : minComponent} +
  • + +
  • + {reverse ? minComponent : maxComponent} +
    + ); + }, +); ContinuousColorLegend.propTypes = { // ----------------------------- Warning -------------------------------- // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "pnpm proptypes" | // ---------------------------------------------------------------------- - /** - * The alignment of the texts with the gradient bar. - * @default 'middle' - */ - align: PropTypes.oneOf(['end', 'middle', 'start']), /** * The axis direction containing the color configuration to represent. * @default 'z' @@ -358,62 +286,60 @@ ContinuousColorLegend.propTypes = { */ axisId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), /** - * The direction of the legend layout. - * The default depends on the chart. + * Override or extend the styles applied to the component. */ - direction: PropTypes.oneOf(['column', 'row']), + classes: PropTypes.object, + className: PropTypes.string, /** - * A unique identifier for the gradient. - * @default auto-generated id + * The direction of the legend layout. + * @default 'horizontal' */ - id: PropTypes.string, + direction: PropTypes.oneOf(['horizontal', 'vertical']), /** - * The style applied to labels. - * @default theme.typography.subtitle1 + * The id for the gradient to use. + * If not provided, it will use the generated gradient from the axis configuration. + * The `gradientId` will be used as `fill="url(#gradientId)"`. + * @default auto-generated id */ - labelStyle: PropTypes.object, + gradientId: PropTypes.string, /** - * The length of the gradient bar. - * Can be a number (in px) or a string with a percentage such as '50%'. - * The '100%' is the length of the svg. - * @default '50%' + * Where to position the labels relative to the gradient. + * @default 'end' */ - length: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), + labelPosition: PropTypes.oneOf(['start', 'end', 'extremes']), /** * The label to display at the maximum side of the gradient. * Can either be a string, or a function. * If not defined, the formatted maximal value is display. - * @default ({ formattedValue }) => formattedValue + * @default formattedValue */ maxLabel: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), /** * The label to display at the minimum side of the gradient. * Can either be a string, or a function. - * @default ({ formattedValue }) => formattedValue + * @default formattedValue */ minLabel: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), /** - * The position of the legend. - */ - position: PropTypes.shape({ - horizontal: PropTypes.oneOf(['left', 'middle', 'right']).isRequired, - vertical: PropTypes.oneOf(['bottom', 'middle', 'top']).isRequired, - }), - /** - * The scale used to display gradient colors. - * @default 'linear' + * If `true`, the gradient and labels will be reversed. + * @default false */ - scaleType: PropTypes.oneOf(['linear', 'log', 'pow', 'sqrt', 'time', 'utc']), + reverse: PropTypes.bool, /** - * The space between the gradient bar and the labels. - * @default 4 + * If provided, the gradient will be rotated by 90deg. + * Useful for linear gradients that are not in the correct orientation. */ - spacing: PropTypes.number, + rotateGradient: PropTypes.bool, /** - * The thickness of the gradient bar. - * @default 5 + * The thickness of the gradient + * @default 12 */ thickness: PropTypes.number, + sx: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), + PropTypes.func, + PropTypes.object, + ]), } as any; export { ContinuousColorLegend }; diff --git a/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx b/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx deleted file mode 100644 index ff2c62ade76bc..0000000000000 --- a/packages/x-charts/src/ChartsLegend/DefaultChartsLegend.tsx +++ /dev/null @@ -1,145 +0,0 @@ -'use client'; -import * as React from 'react'; -import PropTypes from 'prop-types'; -import { FormattedSeries } from '../context/SeriesProvider'; -import { LegendPerItem, LegendPerItemProps } from './LegendPerItem'; -import { LegendItemParams, SeriesLegendItemContext } from './chartsLegend.types'; - -const seriesContextBuilder = (context: LegendItemParams): SeriesLegendItemContext => - ({ - type: 'series', - color: context.color, - label: context.label, - seriesId: context.seriesId!, - itemId: context.itemId, - }) as const; - -export interface LegendRendererProps - extends Omit { - series: FormattedSeries; - seriesToDisplay: LegendPerItemProps['itemsToDisplay']; - /** - * Callback fired when a legend item is clicked. - * @param {React.MouseEvent} event The click event. - * @param {SeriesLegendItemContext} legendItem The legend item data. - * @param {number} index The index of the clicked legend item. - */ - onItemClick?: ( - event: React.MouseEvent, - legendItem: SeriesLegendItemContext, - index: number, - ) => void; - /** - * Set to true to hide the legend. - * @default false - */ - hidden?: boolean; -} - -function DefaultChartsLegend(props: LegendRendererProps) { - const { seriesToDisplay, hidden, onItemClick, ...other } = props; - - if (hidden) { - return null; - } - - return ( - onItemClick(event, seriesContextBuilder(seriesToDisplay[i]), i) - : undefined - } - /> - ); -} - -DefaultChartsLegend.propTypes = { - // ----------------------------- Warning -------------------------------- - // | These PropTypes are generated from the TypeScript type definitions | - // | To update them edit the TypeScript types and run "pnpm proptypes" | - // ---------------------------------------------------------------------- - /** - * Override or extend the styles applied to the component. - */ - classes: PropTypes.object, - /** - * The direction of the legend layout. - * The default depends on the chart. - */ - direction: PropTypes.oneOf(['column', 'row']).isRequired, - /** - * Set to true to hide the legend. - * @default false - */ - hidden: PropTypes.bool, - /** - * Space between two legend items (in px). - * @default 10 - */ - itemGap: PropTypes.number, - /** - * Height of the item mark (in px). - * @default 20 - */ - itemMarkHeight: PropTypes.number, - /** - * Width of the item mark (in px). - * @default 20 - */ - itemMarkWidth: PropTypes.number, - /** - * Style applied to legend labels. - * @default theme.typography.subtitle1 - */ - labelStyle: PropTypes.object, - /** - * Space between the mark and the label (in px). - * @default 5 - */ - markGap: PropTypes.number, - /** - * Callback fired when a legend item is clicked. - * @param {React.MouseEvent} event The click event. - * @param {SeriesLegendItemContext} legendItem The legend item data. - * @param {number} index The index of the clicked legend item. - */ - onItemClick: PropTypes.func, - /** - * Legend padding (in px). - * Can either be a single number, or an object with top, left, bottom, right properties. - * @default 10 - */ - padding: PropTypes.oneOfType([ - PropTypes.number, - PropTypes.shape({ - bottom: PropTypes.number, - left: PropTypes.number, - right: PropTypes.number, - top: PropTypes.number, - }), - ]), - /** - * The position of the legend. - */ - position: PropTypes.shape({ - horizontal: PropTypes.oneOf(['left', 'middle', 'right']).isRequired, - vertical: PropTypes.oneOf(['bottom', 'middle', 'top']).isRequired, - }).isRequired, - series: PropTypes.object.isRequired, - seriesToDisplay: PropTypes.arrayOf( - PropTypes.shape({ - color: PropTypes.string.isRequired, - id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, - itemId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), - label: PropTypes.string.isRequired, - maxValue: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), - minValue: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number]), - seriesId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), - }), - ).isRequired, -} as any; - -export { DefaultChartsLegend }; diff --git a/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx b/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx deleted file mode 100644 index a144358e6d875..0000000000000 --- a/packages/x-charts/src/ChartsLegend/LegendPerItem.tsx +++ /dev/null @@ -1,215 +0,0 @@ -'use client'; -import * as React from 'react'; -import { DefaultizedProps } from '@mui/x-internals/types'; -import NoSsr from '@mui/material/NoSsr'; -import { useTheme, styled } from '@mui/material/styles'; -import { DrawingAreaState } from '../context/DrawingAreaProvider'; -import { ChartsTextStyle } from '../ChartsText'; -import { CardinalDirections } from '../models/layout'; -import { getWordsByLines } from '../internals/getWordsByLines'; -import { GetItemSpaceType, LegendItemParams } from './chartsLegend.types'; -import { legendItemPlacements } from './legendItemsPlacement'; -import { useDrawingArea } from '../hooks/useDrawingArea'; -import { AnchorPosition, Direction, LegendPlacement } from './legend.types'; -import { ChartsLegendItem } from './ChartsLegendItem'; -import { ChartsLegendClasses } from './chartsLegendClasses'; - -export type ChartsLegendRootOwnerState = { - position: AnchorPosition; - direction: Direction; - drawingArea: DrawingAreaState; - offsetX?: number; - offsetY?: number; - seriesNumber: number; -}; - -export const ChartsLegendRoot = styled('g', { - name: 'MuiChartsLegend', - slot: 'Root', - overridesResolver: (props, styles) => styles.root, -})({}); - -export interface LegendPerItemProps - extends DefaultizedProps { - /** - * The ordered array of item to display in the legend. - */ - itemsToDisplay: LegendItemParams[]; - /** - * Override or extend the styles applied to the component. - */ - classes?: Partial; - /** - * Style applied to legend labels. - * @default theme.typography.subtitle1 - */ - labelStyle?: ChartsTextStyle; - /** - * Width of the item mark (in px). - * @default 20 - */ - itemMarkWidth?: number; - /** - * Height of the item mark (in px). - * @default 20 - */ - itemMarkHeight?: number; - /** - * Space between the mark and the label (in px). - * @default 5 - */ - markGap?: number; - /** - * Space between two legend items (in px). - * @default 10 - */ - itemGap?: number; - /** - * Legend padding (in px). - * Can either be a single number, or an object with top, left, bottom, right properties. - * @default 10 - */ - padding?: number | Partial>; - onItemClick?: (event: React.MouseEvent, index: number) => void; -} - -/** - * Transforms number or partial padding object to a defaultized padding object. - */ -const getStandardizedPadding = (padding: LegendPerItemProps['padding']) => { - if (typeof padding === 'number') { - return { - left: padding, - right: padding, - top: padding, - bottom: padding, - }; - } - return { - left: 0, - right: 0, - top: 0, - bottom: 0, - ...padding, - }; -}; - -/** - * Internal component to display an array of items as a legend. - * Used for series legend, and threshold color legend. - * @ignore - Do not document - */ -export function LegendPerItem(props: LegendPerItemProps) { - const { - position, - direction, - itemsToDisplay, - classes, - itemMarkWidth = 20, - itemMarkHeight = 20, - markGap = 5, - itemGap = 10, - padding: paddingProps = 10, - labelStyle: inLabelStyle, - onItemClick, - } = props; - const theme = useTheme(); - const drawingArea = useDrawingArea(); - - const labelStyle = React.useMemo( - () => - ({ - ...theme.typography.subtitle1, - color: 'inherit', - dominantBaseline: 'central', - textAnchor: 'start', - fill: (theme.vars || theme).palette.text.primary, - lineHeight: 1, - ...inLabelStyle, - }) as ChartsTextStyle, // To say to TS that the dominantBaseline and textAnchor are correct - [inLabelStyle, theme], - ); - - const padding = React.useMemo(() => getStandardizedPadding(paddingProps), [paddingProps]); - - const getItemSpace: GetItemSpaceType = React.useCallback( - (label, inStyle = {}) => { - const { rotate, dominantBaseline, ...style } = inStyle; - const linesSize = getWordsByLines({ style, needsComputation: true, text: label }); - const innerSize = { - innerWidth: itemMarkWidth + markGap + Math.max(...linesSize.map((size) => size.width)), - innerHeight: Math.max(itemMarkHeight, linesSize.length * linesSize[0].height), - }; - - return { - ...innerSize, - outerWidth: innerSize.innerWidth + itemGap, - outerHeight: innerSize.innerHeight + itemGap, - }; - }, - [itemGap, itemMarkHeight, itemMarkWidth, markGap], - ); - - const totalWidth = drawingArea.left + drawingArea.width + drawingArea.right; - const totalHeight = drawingArea.top + drawingArea.height + drawingArea.bottom; - const availableWidth = totalWidth - padding.left - padding.right; - const availableHeight = totalHeight - padding.top - padding.bottom; - - const [itemsWithPosition, legendWidth, legendHeight] = React.useMemo( - () => - legendItemPlacements( - itemsToDisplay, - getItemSpace, - labelStyle, - direction, - availableWidth, - availableHeight, - itemGap, - ), - [itemsToDisplay, getItemSpace, labelStyle, direction, availableWidth, availableHeight, itemGap], - ); - - const gapX = React.useMemo(() => { - switch (position.horizontal) { - case 'left': - return padding.left; - case 'right': - return totalWidth - padding.right - legendWidth; - default: - return (totalWidth - legendWidth) / 2; - } - }, [position.horizontal, padding.left, padding.right, totalWidth, legendWidth]); - - const gapY = React.useMemo(() => { - switch (position.vertical) { - case 'top': - return padding.top; - case 'bottom': - return totalHeight - padding.bottom - legendHeight; - default: - return (totalHeight - legendHeight) / 2; - } - }, [position.vertical, padding.top, padding.bottom, totalHeight, legendHeight]); - - return ( - - - {itemsWithPosition.map((item, i) => ( - onItemClick(event, i) : undefined} - /> - ))} - - - ); -} diff --git a/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.test.tsx b/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.test.tsx new file mode 100644 index 0000000000000..b42baa978eb5a --- /dev/null +++ b/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.test.tsx @@ -0,0 +1,52 @@ +import * as React from 'react'; +import { createRenderer, describeConformance } from '@mui/internal-test-utils'; +import { PiecewiseColorLegend, piecewiseColorLegendClasses } from '@mui/x-charts/ChartsLegend'; +import { ChartDataProvider } from '@mui/x-charts/context'; +import { ChartsSurface } from '@mui/x-charts/ChartsSurface'; +import { createTheme, ThemeProvider } from '@mui/material/styles'; + +describe('', () => { + const { render } = createRenderer(); + + describeConformance(, () => ({ + classes: piecewiseColorLegendClasses, + inheritComponent: 'ul', + render: (node) => + render(node, { + wrapper: ({ children }) => ( + + {/* Has to be first as describeConformance picks the "first child" */} + {/* https://github.com/mui/material-ui/blob/c0620e333641deda56f3cd68c7c3736098ee818c/packages-internal/test-utils/src/describeConformance.tsx#L257 */} + {children} + + + ), + }), + muiName: 'MuiPiecewiseColorLegend', + testComponentPropWith: 'ul', + refInstanceof: window.HTMLUListElement, + ThemeProvider, + createTheme, + // SKIP + skip: ['themeVariants', 'componentProp', 'componentsProp'], + })); +}); diff --git a/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx b/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx index fa94832fc4d38..c094ddf44173c 100644 --- a/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx +++ b/packages/x-charts/src/ChartsLegend/PiecewiseColorLegend.tsx @@ -1,132 +1,280 @@ 'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; +import { styled, SxProps, Theme } from '@mui/material/styles'; +import clsx from 'clsx'; +import { PrependKeys } from '@mui/x-internals/types'; +import { ChartsLabel } from '../ChartsLabel/ChartsLabel'; +import { ChartsLabelMark, ChartsLabelMarkProps } from '../ChartsLabel/ChartsLabelMark'; +import { Direction } from './direction'; +import { consumeThemeProps } from '../internals/consumeThemeProps'; +import { + piecewiseColorLegendClasses, + PiecewiseColorLegendClasses, + useUtilityClasses, +} from './piecewiseColorLegendClasses'; +import { ColorLegendSelector } from './colorLegend.types'; +import { PiecewiseLabelFormatterParams } from './piecewiseColorLegend.types'; import { AxisDefaultized } from '../models/axis'; import { useAxis } from './useAxis'; -import { ColorLegendSelector, PiecewiseLabelFormatterParams } from './legend.types'; -import { LegendPerItem, LegendPerItemProps } from './LegendPerItem'; -import { notNull } from '../internals/notNull'; -import { LegendItemParams, PiecewiseColorLegendItemContext } from './chartsLegend.types'; - -function defaultLabelFormatter(params: PiecewiseLabelFormatterParams) { - if (params.min === null) { - return `<${params.formattedMax}`; - } - if (params.max === null) { - return `>${params.formattedMin}`; - } - return `${params.formattedMin}-${params.formattedMax}`; -} +import { PiecewiseColorLegendItemContext } from './legendContext.types'; +import { piecewiseColorDefaultLabelFormatter } from './piecewiseColorDefaultLabelFormatter'; export interface PiecewiseColorLegendProps extends ColorLegendSelector, - Omit { - /** - * Hide the first item of the legend, corresponding to the [-infinity, min] piece. - * @default false - */ - hideFirst?: boolean; + PrependKeys, 'mark'> { /** - * Hide the last item of the legend, corresponding to the [max, +infinity] piece. - * @default false + * The direction of the legend layout. + * @default 'horizontal' */ - hideLast?: boolean; + direction?: Direction; /** * Format the legend labels. * @param {PiecewiseLabelFormatterParams} params The bound of the piece to format. - * @returns {string|null} The displayed label, or `null` to skip the item. + * @returns {string|null} The displayed label, `''` to skip the label but show the color mark, or `null` to skip it entirely. */ labelFormatter?: (params: PiecewiseLabelFormatterParams) => string | null; + /** + * Where to position the labels relative to the gradient. + * @default 'extremes' + */ + labelPosition?: 'start' | 'end' | 'extremes'; /** * Callback fired when a legend item is clicked. - * @param {React.MouseEvent} event The click event. + * @param {React.MouseEvent} event The click event. * @param {PiecewiseColorLegendItemContext} legendItem The legend item data. * @param {number} index The index of the clicked legend item. */ onItemClick?: ( - event: React.MouseEvent, + event: React.MouseEvent, legendItem: PiecewiseColorLegendItemContext, index: number, ) => void; + /** + * Override or extend the styles applied to the component. + */ + classes?: Partial; + className?: string; + sx?: SxProps; } -const piecewiseColorContextBuilder = (context: LegendItemParams): PiecewiseColorLegendItemContext => - ({ - type: 'piecewiseColor', - color: context.color, - label: context.label, - maxValue: context.maxValue!, - minValue: context.minValue!, - }) as const; - -function PiecewiseColorLegend(props: PiecewiseColorLegendProps) { - const { - axisDirection, - axisId, - hideFirst, - hideLast, - labelFormatter = defaultLabelFormatter, - onItemClick, - ...other - } = props; - - const axisItem = useAxis({ axisDirection, axisId }); - - const colorMap = axisItem?.colorMap; - if (!colorMap || !colorMap.type || colorMap.type !== 'piecewise') { - return null; - } - const valueFormatter = (v: number | Date) => - (axisItem as AxisDefaultized).valueFormatter?.(v, { location: 'legend' }) ?? v.toLocaleString(); - - const formattedLabels = colorMap.thresholds.map(valueFormatter); - - const itemsToDisplay = colorMap.colors - .map((color, index) => { - const isFirst = index === 0; - const isLast = index === colorMap.colors.length - 1; - - if ((hideFirst && isFirst) || (hideLast && isLast)) { - return null; - } - - const data = { - ...(isFirst - ? { min: null, formattedMin: null } - : { min: colorMap.thresholds[index - 1], formattedMin: formattedLabels[index - 1] }), - ...(isLast - ? { max: null, formattedMax: null } - : { max: colorMap.thresholds[index], formattedMax: formattedLabels[index] }), - }; - - const label = labelFormatter(data); - - if (label === null) { - return null; - } - - return { - id: label, - color, - label, - minValue: data.min, - maxValue: data.max, - }; - }) - .filter(notNull); - - return ( - onItemClick(event, piecewiseColorContextBuilder(itemsToDisplay[i]), i) - : undefined - } - /> - ); -} +const RootElement = styled('ul', { + name: 'MuiPiecewiseColorLegend', + slot: 'Root', + overridesResolver: (props, styles) => styles.root, +})<{ ownerState: PiecewiseColorLegendProps }>(({ theme, ownerState }) => { + return { + ...theme.typography.caption, + color: (theme.vars || theme).palette.text.primary, + lineHeight: '100%', + display: 'flex', + flexDirection: ownerState.direction === 'vertical' ? 'column' : 'row', + flexShrink: 0, + gap: theme.spacing(0.5), + listStyleType: 'none', + paddingInlineStart: 0, + marginBlock: theme.spacing(1), + marginInline: theme.spacing(1), + width: 'max-content', + [`button.${piecewiseColorLegendClasses.item}`]: { + // Reset button styles + background: 'none', + border: 'none', + padding: 0, + cursor: ownerState.onItemClick ? 'pointer' : 'unset', + fontFamily: 'inherit', + fontWeight: 'inherit', + fontSize: 'inherit', + letterSpacing: 'inherit', + color: 'inherit', + }, + [`.${piecewiseColorLegendClasses.item}`]: { + display: 'flex', + gap: theme.spacing(0.5), + }, + [`li :not(.${piecewiseColorLegendClasses.minLabel}, .${piecewiseColorLegendClasses.maxLabel}) .${piecewiseColorLegendClasses?.mark}`]: + { + alignSelf: 'center', + }, + [`&.${piecewiseColorLegendClasses.start}`]: { + alignItems: 'end', + }, + [`&.${piecewiseColorLegendClasses.end}`]: { + alignItems: 'start', + }, + [`&.${piecewiseColorLegendClasses.horizontal}`]: { + alignItems: 'center', + [`.${piecewiseColorLegendClasses.item}`]: { + flexDirection: 'column', + }, + [`&.${piecewiseColorLegendClasses.start}`]: { + alignItems: 'end', + }, + [`&.${piecewiseColorLegendClasses.end}`]: { + alignItems: 'start', + }, + [`.${piecewiseColorLegendClasses.minLabel}`]: { + alignItems: 'end', + }, + [`&.${piecewiseColorLegendClasses.extremes}`]: { + [`.${piecewiseColorLegendClasses.minLabel}, .${piecewiseColorLegendClasses.maxLabel}`]: { + alignItems: 'center', + display: 'flex', + flexDirection: 'row', + }, + }, + }, + [`&.${piecewiseColorLegendClasses.vertical}`]: { + [`.${piecewiseColorLegendClasses.item}`]: { + flexDirection: 'row', + alignItems: 'center', + }, + [`&.${piecewiseColorLegendClasses.start}`]: { + alignItems: 'end', + }, + [`&.${piecewiseColorLegendClasses.end}`]: { + alignItems: 'start', + }, + [`&.${piecewiseColorLegendClasses.extremes}`]: { + alignItems: 'center', + [`.${piecewiseColorLegendClasses.minLabel}, .${piecewiseColorLegendClasses.maxLabel}`]: { + alignItems: 'center', + display: 'flex', + flexDirection: 'column', + }, + }, + }, + }; +}); + +const PiecewiseColorLegend = consumeThemeProps( + 'MuiPiecewiseColorLegend', + { + defaultProps: { + direction: 'horizontal', + labelPosition: 'extremes', + labelFormatter: piecewiseColorDefaultLabelFormatter, + }, + classesResolver: useUtilityClasses, + }, + function PiecewiseColorLegend( + props: PiecewiseColorLegendProps, + ref: React.Ref, + ) { + const { + direction, + classes, + className, + markType, + labelPosition, + axisDirection, + axisId, + labelFormatter, + onItemClick, + ...other + } = props; + + const isVertical = direction === 'vertical'; + const isReverse = isVertical; + const axisItem = useAxis({ axisDirection, axisId }); + + const colorMap = axisItem?.colorMap; + if (!colorMap || !colorMap.type || colorMap.type !== 'piecewise') { + return null; + } + const valueFormatter = (v: number | Date) => + (axisItem as AxisDefaultized).valueFormatter?.(v, { location: 'legend' }) ?? + v.toLocaleString(); + + const formattedLabels = colorMap.thresholds.map(valueFormatter); + + const startClass = isReverse ? classes?.maxLabel : classes?.minLabel; + const endClass = isReverse ? classes?.minLabel : classes?.maxLabel; + + const colors = colorMap.colors.map((color, colorIndex) => ({ + color, + colorIndex, + })); + const orderedColors = isReverse ? colors.reverse() : colors; + + const isStart = labelPosition === 'start'; + const isEnd = labelPosition === 'end'; + const isExtremes = labelPosition === 'extremes'; + + return ( + + {orderedColors.map(({ color, colorIndex }, index) => { + const isFirst = index === 0; + const isLast = index === colorMap.colors.length - 1; + const isFirstColor = colorIndex === 0; + const isLastColor = colorIndex === colorMap.colors.length - 1; + + const data = { + index: colorIndex, + length: formattedLabels.length, + ...(isFirstColor + ? { min: null, formattedMin: null } + : { + min: colorMap.thresholds[colorIndex - 1], + formattedMin: formattedLabels[colorIndex - 1], + }), + ...(isLastColor + ? { max: null, formattedMax: null } + : { + max: colorMap.thresholds[colorIndex], + formattedMax: formattedLabels[colorIndex], + }), + }; + + const label = labelFormatter?.(data); + + if (label === null || label === undefined) { + return null; + } + + const isTextBefore = isStart || (isExtremes && isFirst); + const isTextAfter = isEnd || (isExtremes && isLast); + + const clickObject = { + type: 'piecewiseColor', + color, + label, + minValue: data.min, + maxValue: data.max, + } as const; + + const Element = onItemClick ? 'button' : 'div'; + + return ( +
  • + onItemClick(event, clickObject, index) : undefined + } + className={clsx(classes?.item, { + [`${startClass}`]: index === 0, + [`${endClass}`]: index === orderedColors.length - 1, + })} + > + {isTextBefore && {label}} + + {isTextAfter && {label}} + +
  • + ); + })} +
    + ); + }, +); PiecewiseColorLegend.propTypes = { // ----------------------------- Warning -------------------------------- @@ -147,80 +295,40 @@ PiecewiseColorLegend.propTypes = { * Override or extend the styles applied to the component. */ classes: PropTypes.object, + className: PropTypes.string, /** * The direction of the legend layout. - * The default depends on the chart. + * @default 'horizontal' */ - direction: PropTypes.oneOf(['column', 'row']).isRequired, - /** - * Hide the first item of the legend, corresponding to the [-infinity, min] piece. - * @default false - */ - hideFirst: PropTypes.bool, - /** - * Hide the last item of the legend, corresponding to the [max, +infinity] piece. - * @default false - */ - hideLast: PropTypes.bool, - /** - * Space between two legend items (in px). - * @default 10 - */ - itemGap: PropTypes.number, - /** - * Height of the item mark (in px). - * @default 20 - */ - itemMarkHeight: PropTypes.number, - /** - * Width of the item mark (in px). - * @default 20 - */ - itemMarkWidth: PropTypes.number, + direction: PropTypes.oneOf(['horizontal', 'vertical']), /** * Format the legend labels. * @param {PiecewiseLabelFormatterParams} params The bound of the piece to format. - * @returns {string|null} The displayed label, or `null` to skip the item. + * @returns {string|null} The displayed label, `''` to skip the label but show the color mark, or `null` to skip it entirely. */ labelFormatter: PropTypes.func, /** - * Style applied to legend labels. - * @default theme.typography.subtitle1 + * Where to position the labels relative to the gradient. + * @default 'extremes' */ - labelStyle: PropTypes.object, + labelPosition: PropTypes.oneOf(['start', 'end', 'extremes']), /** - * Space between the mark and the label (in px). - * @default 5 + * The type of the mark. + * @default 'square' */ - markGap: PropTypes.number, + markType: PropTypes.oneOf(['square', 'circle', 'line']), /** * Callback fired when a legend item is clicked. - * @param {React.MouseEvent} event The click event. + * @param {React.MouseEvent} event The click event. * @param {PiecewiseColorLegendItemContext} legendItem The legend item data. * @param {number} index The index of the clicked legend item. */ onItemClick: PropTypes.func, - /** - * Legend padding (in px). - * Can either be a single number, or an object with top, left, bottom, right properties. - * @default 10 - */ - padding: PropTypes.oneOfType([ - PropTypes.number, - PropTypes.shape({ - bottom: PropTypes.number, - left: PropTypes.number, - right: PropTypes.number, - top: PropTypes.number, - }), + sx: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), + PropTypes.func, + PropTypes.object, ]), - /** - * The position of the legend. - */ - position: PropTypes.shape({ - horizontal: PropTypes.oneOf(['left', 'middle', 'right']).isRequired, - vertical: PropTypes.oneOf(['bottom', 'middle', 'top']).isRequired, - }).isRequired, } as any; export { PiecewiseColorLegend }; diff --git a/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts b/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts index a898c70aefbc6..3305069e26fb1 100644 --- a/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts +++ b/packages/x-charts/src/ChartsLegend/chartsLegend.types.ts @@ -1,81 +1,34 @@ -import { ChartsTextStyle } from '../ChartsText'; -import { PieItemId } from '../models'; -import { SeriesId } from '../models/seriesType/common'; +import type { ChartsLegendProps } from './ChartsLegend'; +import { ContinuousColorLegendProps } from './ContinuousColorLegend'; +import { ChartsLegendPosition } from './legend.types'; +import { PiecewiseColorLegendProps } from './PiecewiseColorLegend'; -interface LegendItemContextBase { +export interface ChartsLegendSlots { /** - * The color used in the legend + * Custom rendering of the legend. + * @default ChartsLegend */ - color: string; - /** - * The label displayed in the legend - */ - label: string; + legend?: + | React.JSXElementConstructor + | React.JSXElementConstructor + | React.JSXElementConstructor; } -export interface LegendItemParams - extends Partial>, - Partial>, - LegendItemContextBase { - /** - * The identifier of the legend element. - * Used for internal purpose such as `key` props - */ - id: number | string; -} - -export interface SeriesLegendItemContext extends LegendItemContextBase { - /** - * The type of the legend item - * - `series` is used for series legend item - * - `piecewiseColor` is used for piecewise color legend item - */ - type: 'series'; - /** - * The identifier of the series - */ - seriesId: SeriesId; - /** - * The identifier of the pie item - */ - itemId?: PieItemId; +export interface ChartsLegendSlotProps { + legend?: Partial & + // We allow position only on slots. + ChartsLegendPosition; } -export interface PiecewiseColorLegendItemContext extends LegendItemContextBase { - /** - * The type of the legend item - * - `series` is used for series legend item - * - `piecewiseColor` is used for piecewise color legend item - */ - type: 'piecewiseColor'; +export interface ChartsLegendSlotExtension { /** - * The minimum value of the category + * Overridable component slots. + * @default {} */ - minValue: number | Date | null; + slots?: ChartsLegendSlots; /** - * The maximum value of the category + * The props used for each component slot. + * @default {} */ - maxValue: number | Date | null; + slotProps?: ChartsLegendSlotProps; } - -export type LegendItemContext = SeriesLegendItemContext | PiecewiseColorLegendItemContext; - -export interface LegendItemWithPosition extends LegendItemParams { - positionX: number; - positionY: number; - innerHeight: number; - innerWidth: number; - outerHeight: number; - outerWidth: number; - rowIndex: number; -} - -export type GetItemSpaceType = ( - label: string, - inStyle?: ChartsTextStyle, -) => { - innerWidth: number; - innerHeight: number; - outerWidth: number; - outerHeight: number; -}; diff --git a/packages/x-charts/src/ChartsLegend/chartsLegendClasses.ts b/packages/x-charts/src/ChartsLegend/chartsLegendClasses.ts index 7539c5caf6ac0..c36d3ac80a1ed 100644 --- a/packages/x-charts/src/ChartsLegend/chartsLegendClasses.ts +++ b/packages/x-charts/src/ChartsLegend/chartsLegendClasses.ts @@ -1,35 +1,45 @@ import generateUtilityClass from '@mui/utils/generateUtilityClass'; import generateUtilityClasses from '@mui/utils/generateUtilityClasses'; +import composeClasses from '@mui/utils/composeClasses'; +import type { ChartsLegendProps } from './ChartsLegend'; +import type { ChartsLegendSlotExtension } from './chartsLegend.types'; export interface ChartsLegendClasses { /** Styles applied to the root element. */ root: string; /** Styles applied to a series element. */ series: string; - /** Styles applied to the item background. */ - itemBackground: string; /** Styles applied to series mark element. */ mark: string; /** Styles applied to the series label. */ label: string; - /** Styles applied to the legend with column layout. */ - column: string; - /** Styles applied to the legend with row layout. */ - row: string; + /** Styles applied to the legend in column layout. */ + vertical: string; + /** Styles applied to the legend in row layout. */ + horizontal: string; } -export type ChartsLegendClassKey = keyof ChartsLegendClasses; - -export function getLegendUtilityClass(slot: string) { +function getLegendUtilityClass(slot: string) { return generateUtilityClass('MuiChartsLegend', slot); } +export const useUtilityClasses = (props: ChartsLegendProps & ChartsLegendSlotExtension) => { + const { classes, direction } = props; + const slots = { + root: ['root', direction], + mark: ['mark'], + label: ['label'], + series: ['series'], + }; + + return composeClasses(slots, getLegendUtilityClass, classes); +}; + export const legendClasses: ChartsLegendClasses = generateUtilityClasses('MuiChartsLegend', [ 'root', 'series', - 'itemBackground', 'mark', 'label', - 'column', - 'row', + 'vertical', + 'horizontal', ]); diff --git a/packages/x-charts/src/ChartsLegend/colorLegend.types.ts b/packages/x-charts/src/ChartsLegend/colorLegend.types.ts new file mode 100644 index 0000000000000..7b0fdb1655b25 --- /dev/null +++ b/packages/x-charts/src/ChartsLegend/colorLegend.types.ts @@ -0,0 +1,14 @@ +import { AxisId } from '../models/axis'; + +export interface ColorLegendSelector { + /** + * The axis direction containing the color configuration to represent. + * @default 'z' + */ + axisDirection?: 'x' | 'y' | 'z'; + /** + * The id of the axis item with the color configuration to represent. + * @default The first axis item. + */ + axisId?: AxisId; +} diff --git a/packages/x-charts/src/ChartsLegend/continuousColorLegendClasses.ts b/packages/x-charts/src/ChartsLegend/continuousColorLegendClasses.ts new file mode 100644 index 0000000000000..41ed0222e1749 --- /dev/null +++ b/packages/x-charts/src/ChartsLegend/continuousColorLegendClasses.ts @@ -0,0 +1,64 @@ +import generateUtilityClass from '@mui/utils/generateUtilityClass'; +import generateUtilityClasses from '@mui/utils/generateUtilityClasses'; +import composeClasses from '@mui/utils/composeClasses'; +import type { ContinuousColorLegendProps } from './ContinuousColorLegend'; +import type { ChartsLegendSlotExtension } from './chartsLegend.types'; + +export interface ContinuousColorLegendClasses { + /** Styles applied to the root element. */ + root: string; + /** Styles applied to the list item that renders the `minLabel`. */ + minLabel: string; + /** Styles applied to the list item that renders the `maxLabel`. */ + maxLabel: string; + /** Styles applied to the list item with the gradient. */ + gradient: string; + /** Styles applied to the legend in column layout. */ + vertical: string; + /** Styles applied to the legend in row layout. */ + horizontal: string; + /** Styles applied to the legend with the labels before the gradient. */ + start: string; + /** Styles applied to the legend with the labels after the gradient. */ + end: string; + /** Styles applied to the legend with the labels on the extremes of the gradient. */ + extremes: string; + /** Styles applied to the series label. */ + label: string; +} + +function getLegendUtilityClass(slot: string) { + return generateUtilityClass('MuiContinuousColorLegend', slot); +} + +export const useUtilityClasses = ( + props: ContinuousColorLegendProps & ChartsLegendSlotExtension, +) => { + const { classes, direction, labelPosition } = props; + const slots = { + root: ['root', direction, labelPosition], + minLabel: ['minLabel'], + maxLabel: ['maxLabel'], + gradient: ['gradient'], + mark: ['mark'], + label: ['label'], + }; + + return composeClasses(slots, getLegendUtilityClass, classes); +}; + +export const continuousColorLegendClasses: ContinuousColorLegendClasses = generateUtilityClasses( + 'MuiContinuousColorLegend', + [ + 'root', + 'minLabel', + 'maxLabel', + 'gradient', + 'vertical', + 'horizontal', + 'start', + 'end', + 'extremes', + 'label', + ], +); diff --git a/packages/x-charts/src/ChartsLegend/direction.ts b/packages/x-charts/src/ChartsLegend/direction.ts new file mode 100644 index 0000000000000..e52780972852f --- /dev/null +++ b/packages/x-charts/src/ChartsLegend/direction.ts @@ -0,0 +1 @@ +export type Direction = 'vertical' | 'horizontal'; diff --git a/packages/x-charts/src/ChartsLegend/index.ts b/packages/x-charts/src/ChartsLegend/index.ts index 24c38e1b8e17d..f8a0057266c23 100644 --- a/packages/x-charts/src/ChartsLegend/index.ts +++ b/packages/x-charts/src/ChartsLegend/index.ts @@ -1,7 +1,16 @@ export * from './ChartsLegend'; -export * from './DefaultChartsLegend'; +export * from './chartsLegend.types'; +export * from './direction'; +export * from './legendContext.types'; +export { legendClasses } from './chartsLegendClasses'; +export type { ChartsLegendClasses } from './chartsLegendClasses'; export * from './ContinuousColorLegend'; +export * from './colorLegend.types'; +export { continuousColorLegendClasses } from './continuousColorLegendClasses'; +export type { ContinuousColorLegendClasses } from './continuousColorLegendClasses'; export * from './PiecewiseColorLegend'; -export * from './chartsLegendClasses'; - -export * from './utils'; +export { piecewiseColorLegendClasses } from './piecewiseColorLegendClasses'; +export type { PiecewiseColorLegendClasses } from './piecewiseColorLegendClasses'; +export { piecewiseColorDefaultLabelFormatter } from './piecewiseColorDefaultLabelFormatter'; +export type { PiecewiseLabelFormatterParams } from './piecewiseColorLegend.types'; +export * from './legend.types'; diff --git a/packages/x-charts/src/ChartsLegend/legend.types.ts b/packages/x-charts/src/ChartsLegend/legend.types.ts index 84fa17530d739..fc180fae2013f 100644 --- a/packages/x-charts/src/ChartsLegend/legend.types.ts +++ b/packages/x-charts/src/ChartsLegend/legend.types.ts @@ -1,67 +1,19 @@ -import { ChartsTextBaseline, ChartsTextStyle } from '../internals/getWordsByLines'; -import { AxisId } from '../models/axis'; - -export type AnchorX = 'left' | 'right' | 'middle'; -export type AnchorY = 'top' | 'bottom' | 'middle'; - -export type AnchorPosition = { horizontal: AnchorX; vertical: AnchorY }; - -export type Direction = 'row' | 'column'; - -export interface ColorLegendSelector { - /** - * The axis direction containing the color configuration to represent. - * @default 'z' - */ - axisDirection?: 'x' | 'y' | 'z'; - /** - * The id of the axis item with the color configuration to represent. - * @default The first axis item. - */ - axisId?: AxisId; -} - -export interface LegendPlacement { +export type LegendPosition = { /** - * The position of the legend. + * The vertical position of the legend. */ - position?: AnchorPosition; + vertical?: 'top' | 'middle' | 'bottom'; /** - * The direction of the legend layout. - * The default depends on the chart. + * The horizontal position of the legend. */ - direction?: Direction; -} - -export type BoundingBox = { - width: number; - height: number; + horizontal?: 'left' | 'middle' | 'right'; }; -export interface Position { - x: number; - y: number; -} -export interface TextPosition extends Position { - dominantBaseline: ChartsTextBaseline; - textAnchor: ChartsTextStyle['textAnchor']; -} - -export type PiecewiseLabelFormatterParams = { - /** - * The min value of the piece. `null` is infinite. - */ - min: number | Date | null; - /** - * The max value of the piece. `null` is infinite. - */ - max: number | Date | null; - /** - * The formatted min value of the piece. `null` is infinite. - */ - formattedMin: string | null; +export type ChartsLegendPosition = { /** - * The formatted max value of the piece. `null` is infinite. + * The position of the legend in relation to the chart. + * This property is only passed to the Chart components, e.g. `ScatterChart`, and not the slots themselves. + * If customization is needed, simply use the composition pattern. */ - formattedMax: string | null; + position?: LegendPosition; }; diff --git a/packages/x-charts/src/ChartsLegend/legendContext.types.ts b/packages/x-charts/src/ChartsLegend/legendContext.types.ts new file mode 100644 index 0000000000000..7d8612ad5161f --- /dev/null +++ b/packages/x-charts/src/ChartsLegend/legendContext.types.ts @@ -0,0 +1,62 @@ +import { ChartsLabelMarkProps } from '../ChartsLabel/ChartsLabelMark'; +import { PieItemId } from '../models'; +import { SeriesId } from '../models/seriesType/common'; + +interface LegendItemContextBase { + /** + * The color used in the legend + */ + color: string; + /** + * The label displayed in the legend + */ + label: string; +} + +export interface LegendItemParams + extends Partial>, + Partial>, + LegendItemContextBase { + /** + * The identifier of the legend element. + * Used for internal purpose such as `key` props + */ + id: number | string; + markType: ChartsLabelMarkProps['type']; +} + +export interface SeriesLegendItemContext extends LegendItemContextBase { + /** + * The type of the legend item + * - `series` is used for series legend item + * - `piecewiseColor` is used for piecewise color legend item + */ + type: 'series'; + /** + * The identifier of the series + */ + seriesId: SeriesId; + /** + * The identifier of the pie item + */ + itemId?: PieItemId; +} + +export interface PiecewiseColorLegendItemContext extends LegendItemContextBase { + /** + * The type of the legend item + * - `series` is used for series legend item + * - `piecewiseColor` is used for piecewise color legend item + */ + type: 'piecewiseColor'; + /** + * The minimum value of the category + */ + minValue: number | Date | null; + /** + * The maximum value of the category + */ + maxValue: number | Date | null; +} + +export type LegendItemContext = SeriesLegendItemContext | PiecewiseColorLegendItemContext; diff --git a/packages/x-charts/src/ChartsLegend/legendItemsPlacement.ts b/packages/x-charts/src/ChartsLegend/legendItemsPlacement.ts deleted file mode 100644 index f482e3b9a244c..0000000000000 --- a/packages/x-charts/src/ChartsLegend/legendItemsPlacement.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { ChartsTextStyle } from '../ChartsText'; -import { GetItemSpaceType, LegendItemParams, LegendItemWithPosition } from './chartsLegend.types'; - -export function legendItemPlacements( - itemsToDisplay: LegendItemParams[], - getItemSpace: GetItemSpaceType, - labelStyle: ChartsTextStyle, - direction: string, - availableWidth: number, - availableHeight: number, - itemGap: number, -): [LegendItemWithPosition[], number, number] { - // Start at 0, 0. Will be modified later by padding and position. - let x = 0; - let y = 0; - - // total values used to align legend later. - let totalWidthUsed = 0; - let totalHeightUsed = 0; - let rowIndex = 0; - const rowMaxHeight = [0]; - - const seriesWithRawPosition = itemsToDisplay.map(({ label, ...other }) => { - const itemSpace = getItemSpace(label, labelStyle); - const rep = { - ...other, - label, - positionX: x, - positionY: y, - innerHeight: itemSpace.innerHeight, - innerWidth: itemSpace.innerWidth, - outerHeight: itemSpace.outerHeight, - outerWidth: itemSpace.outerWidth, - rowIndex, - }; - - if (direction === 'row') { - if (x + itemSpace.innerWidth > availableWidth) { - // This legend item would create overflow along the x-axis, so we start a new row. - x = 0; - y += rowMaxHeight[rowIndex]; - rowIndex += 1; - if (rowMaxHeight.length <= rowIndex) { - rowMaxHeight.push(0); - } - rep.positionX = x; - rep.positionY = y; - rep.rowIndex = rowIndex; - } - totalWidthUsed = Math.max(totalWidthUsed, x + itemSpace.outerWidth); - totalHeightUsed = Math.max(totalHeightUsed, y + itemSpace.outerHeight); - rowMaxHeight[rowIndex] = Math.max(rowMaxHeight[rowIndex], itemSpace.outerHeight); - - x += itemSpace.outerWidth; - } - - if (direction === 'column') { - if (y + itemSpace.innerHeight > availableHeight) { - // This legend item would create overflow along the y-axis, so we start a new column. - x = totalWidthUsed + itemGap; - y = 0; - rowIndex = 0; - rep.positionX = x; - rep.positionY = y; - rep.rowIndex = rowIndex; - } - if (rowMaxHeight.length <= rowIndex) { - rowMaxHeight.push(0); - } - totalWidthUsed = Math.max(totalWidthUsed, x + itemSpace.outerWidth); - totalHeightUsed = Math.max(totalHeightUsed, y + itemSpace.outerHeight); - - rowIndex += 1; - y += itemSpace.outerHeight; - } - - return rep; - }); - - return [ - seriesWithRawPosition.map((item) => ({ - ...item, - positionY: - item.positionY + - (direction === 'row' - ? rowMaxHeight[item.rowIndex] / 2 // Get the center of the entire row - : item.outerHeight / 2), // Get the center of the item - })), - totalWidthUsed, - totalHeightUsed, - ]; -} diff --git a/packages/x-charts/src/ChartsLegend/onClickContextBuilder.ts b/packages/x-charts/src/ChartsLegend/onClickContextBuilder.ts new file mode 100644 index 0000000000000..09cd72ce4f54c --- /dev/null +++ b/packages/x-charts/src/ChartsLegend/onClickContextBuilder.ts @@ -0,0 +1,10 @@ +import { LegendItemParams, SeriesLegendItemContext } from './legendContext.types'; + +export const seriesContextBuilder = (context: LegendItemParams): SeriesLegendItemContext => + ({ + type: 'series', + color: context.color, + label: context.label, + seriesId: context.seriesId!, + itemId: context.itemId, + }) as const; diff --git a/packages/x-charts/src/ChartsLegend/piecewiseColorDefaultLabelFormatter.ts b/packages/x-charts/src/ChartsLegend/piecewiseColorDefaultLabelFormatter.ts new file mode 100644 index 0000000000000..61a852dec16c0 --- /dev/null +++ b/packages/x-charts/src/ChartsLegend/piecewiseColorDefaultLabelFormatter.ts @@ -0,0 +1,11 @@ +import { PiecewiseLabelFormatterParams } from './piecewiseColorLegend.types'; + +export function piecewiseColorDefaultLabelFormatter(params: PiecewiseLabelFormatterParams) { + if (params.min === null) { + return `<${params.formattedMax}`; + } + if (params.max === null) { + return `>${params.formattedMin}`; + } + return `${params.formattedMin}-${params.formattedMax}`; +} diff --git a/packages/x-charts/src/ChartsLegend/piecewiseColorLegend.types.ts b/packages/x-charts/src/ChartsLegend/piecewiseColorLegend.types.ts new file mode 100644 index 0000000000000..ee935dde1278f --- /dev/null +++ b/packages/x-charts/src/ChartsLegend/piecewiseColorLegend.types.ts @@ -0,0 +1,26 @@ +export type PiecewiseLabelFormatterParams = { + /** + * The index of the entry. + */ + index: number; + /** + * The length of the entries array. + */ + length: number; + /** + * The min value of the piece. `null` is infinite. + */ + min: number | Date | null; + /** + * The max value of the piece. `null` is infinite. + */ + max: number | Date | null; + /** + * The formatted min value of the piece. `null` is infinite. + */ + formattedMin: string | null; + /** + * The formatted max value of the piece. `null` is infinite. + */ + formattedMax: string | null; +}; diff --git a/packages/x-charts/src/ChartsLegend/piecewiseColorLegendClasses.ts b/packages/x-charts/src/ChartsLegend/piecewiseColorLegendClasses.ts new file mode 100644 index 0000000000000..b5b55527633b9 --- /dev/null +++ b/packages/x-charts/src/ChartsLegend/piecewiseColorLegendClasses.ts @@ -0,0 +1,65 @@ +import generateUtilityClass from '@mui/utils/generateUtilityClass'; +import generateUtilityClasses from '@mui/utils/generateUtilityClasses'; +import composeClasses from '@mui/utils/composeClasses'; +import type { PiecewiseColorLegendProps } from './PiecewiseColorLegend'; +import type { ChartsLegendSlotExtension } from './chartsLegend.types'; + +export interface PiecewiseColorLegendClasses { + /** Styles applied to the root element. */ + root: string; + /** Styles applied to the list item that renders the `minLabel`. */ + minLabel: string; + /** Styles applied to the list item that renders the `maxLabel`. */ + maxLabel: string; + /** Styles applied to the list items. */ + item: string; + /** Styles applied to the legend in column layout. */ + vertical: string; + /** Styles applied to the legend in row layout. */ + horizontal: string; + /** Styles applied to the legend with the labels before the color marks. */ + start: string; + /** Styles applied to the legend with the labels after the color marks. */ + end: string; + /** Styles applied to the legend with the labels on the extremes of the color marks. */ + extremes: string; + /** Styles applied to the marks. */ + mark: string; + /** Styles applied to the series label. */ + label: string; +} + +function getLegendUtilityClass(slot: string) { + return generateUtilityClass('MuiPiecewiseColorLegendClasses', slot); +} + +export const useUtilityClasses = (props: PiecewiseColorLegendProps & ChartsLegendSlotExtension) => { + const { classes, direction, labelPosition } = props; + const slots = { + root: ['root', direction, labelPosition], + minLabel: ['minLabel'], + maxLabel: ['maxLabel'], + item: ['item'], + mark: ['mark'], + label: ['label'], + }; + + return composeClasses(slots, getLegendUtilityClass, classes); +}; + +export const piecewiseColorLegendClasses: PiecewiseColorLegendClasses = generateUtilityClasses( + 'MuiPiecewiseColorLegendClasses', + [ + 'root', + 'minLabel', + 'maxLabel', + 'item', + 'vertical', + 'horizontal', + 'start', + 'end', + 'extremes', + 'mark', + 'label', + ], +); diff --git a/packages/x-charts/src/ChartsLegend/useAxis.ts b/packages/x-charts/src/ChartsLegend/useAxis.ts index 4f80ddd8f3e1a..7cba0d0069377 100644 --- a/packages/x-charts/src/ChartsLegend/useAxis.ts +++ b/packages/x-charts/src/ChartsLegend/useAxis.ts @@ -3,8 +3,8 @@ import { AxisDefaultized } from '../models/axis'; import { useCartesianContext } from '../context/CartesianProvider/useCartesianContext'; import { ZAxisDefaultized } from '../models/z-axis'; -import { ColorLegendSelector } from './legend.types'; import { useZAxis } from '../hooks/useZAxis'; +import { ColorLegendSelector } from './colorLegend.types'; /** * Helper to select an axis definition according to its direction and id. diff --git a/packages/x-charts/src/ChartsSurface/ChartsSurface.tsx b/packages/x-charts/src/ChartsSurface/ChartsSurface.tsx index 2403575a9b649..207a159aebc9f 100644 --- a/packages/x-charts/src/ChartsSurface/ChartsSurface.tsx +++ b/packages/x-charts/src/ChartsSurface/ChartsSurface.tsx @@ -31,7 +31,6 @@ const ChartsSurfaceStyles = styled('svg', { height: ownerState.height ?? '100%', display: 'flex', position: 'relative', - flexGrow: 1, flexDirection: 'column', alignItems: 'center', justifyContent: 'center', diff --git a/packages/x-charts/src/ChartsTooltip/contentDisplayed.test.tsx b/packages/x-charts/src/ChartsTooltip/contentDisplayed.test.tsx index 2015a303c3dc6..ad25838c72d63 100644 --- a/packages/x-charts/src/ChartsTooltip/contentDisplayed.test.tsx +++ b/packages/x-charts/src/ChartsTooltip/contentDisplayed.test.tsx @@ -1,15 +1,16 @@ import * as React from 'react'; import { expect } from 'chai'; import { createRenderer, fireEvent } from '@mui/internal-test-utils'; -import { BarChart } from '@mui/x-charts/BarChart'; +import { BarChart, BarChartProps } from '@mui/x-charts/BarChart'; import { describeSkipIf, isJSDOM } from 'test/utils/skipIf'; -const config = { +const config: Partial = { dataset: [ { x: 'A', v1: 4, v2: 2 }, { x: 'B', v1: 1, v2: 1 }, ], margin: { top: 0, left: 0, bottom: 0, right: 0 }, + hideLegend: true, width: 400, height: 400, }; diff --git a/packages/x-charts/src/LineChart/LineChart.test.tsx b/packages/x-charts/src/LineChart/LineChart.test.tsx index 1ec0c3f8ac2a5..441d32c31e96c 100644 --- a/packages/x-charts/src/LineChart/LineChart.test.tsx +++ b/packages/x-charts/src/LineChart/LineChart.test.tsx @@ -23,6 +23,7 @@ describe('', () => { 'themeStyleOverrides', 'themeVariants', 'themeCustomPalette', + 'themeDefaultProps', ], }), ); diff --git a/packages/x-charts/src/LineChart/LineChart.tsx b/packages/x-charts/src/LineChart/LineChart.tsx index 80fa8dc686671..b6887f8937299 100644 --- a/packages/x-charts/src/LineChart/LineChart.tsx +++ b/packages/x-charts/src/LineChart/LineChart.tsx @@ -5,7 +5,7 @@ import { useThemeProps } from '@mui/material/styles'; import { MakeOptional } from '@mui/x-internals/types'; import { AreaPlot, AreaPlotProps, AreaPlotSlotProps, AreaPlotSlots } from './AreaPlot'; import { LinePlot, LinePlotProps, LinePlotSlotProps, LinePlotSlots } from './LinePlot'; -import { ChartContainer, ChartContainerProps } from '../ChartContainer'; +import { ChartContainerProps } from '../ChartContainer'; import { MarkPlot, MarkPlotProps, MarkPlotSlotProps, MarkPlotSlots } from './MarkPlot'; import { ChartsAxis, ChartsAxisProps } from '../ChartsAxis/ChartsAxis'; import { LineSeriesType } from '../models/seriesType/line'; @@ -32,6 +32,10 @@ import { ChartsOverlaySlots, } from '../ChartsOverlay'; import { useLineChartProps } from './useLineChartProps'; +import { useChartContainerProps } from '../ChartContainer/useChartContainerProps'; +import { ChartDataProvider } from '../context'; +import { ChartsSurface } from '../ChartsSurface'; +import { ChartsWrapper } from '../internals/components/ChartsWrapper'; export interface LineChartSlots extends ChartsAxisSlots, @@ -129,6 +133,7 @@ const LineChart = React.forwardRef(function LineChart( ) { const props = useThemeProps({ props: inProps, name: 'MuiLineChart' }); const { + chartsWrapperProps, chartContainerProps, axisClickHandlerProps, gridProps, @@ -144,30 +149,38 @@ const LineChart = React.forwardRef(function LineChart( legendProps, children, } = useLineChartProps(props); + const { chartDataProviderProps, chartsSurfaceProps } = useChartContainerProps( + chartContainerProps, + ref, + ); const Tooltip = props.slots?.tooltip ?? ChartsTooltip; return ( - - {props.onAxisClick && } - - - - - - - - - - {/* The `data-drawing-container` indicates that children are part of the drawing area. Ref: https://github.com/mui/mui-x/issues/13659 */} - - - - {!props.hideLegend && } - {!props.loading && } - - {children} - + + + {!props.hideLegend && } + + {props.onAxisClick && } + + + + + + + + + + {/* The `data-drawing-container` indicates that children are part of the drawing area. Ref: https://github.com/mui/mui-x/issues/13659 */} + + + + {!props.loading && } + + {children} + + + ); }); diff --git a/packages/x-charts/src/LineChart/legend.ts b/packages/x-charts/src/LineChart/legend.ts index 28d3ae4165461..0dcd25e97ae22 100644 --- a/packages/x-charts/src/LineChart/legend.ts +++ b/packages/x-charts/src/LineChart/legend.ts @@ -1,4 +1,4 @@ -import { LegendItemParams } from '../ChartsLegend/chartsLegend.types'; +import type { LegendItemParams } from '../ChartsLegend'; import { getLabel } from '../internals/getLabel'; import { LegendGetter } from '../context/PluginProvider'; @@ -12,6 +12,7 @@ const legendGetter: LegendGetter<'line'> = (params) => { } acc.push({ + markType: series[seriesId].labelMarkType ?? 'line', id: seriesId, seriesId, color: series[seriesId].color, diff --git a/packages/x-charts/src/LineChart/useLineChartProps.ts b/packages/x-charts/src/LineChart/useLineChartProps.ts index 05cef6fc627bc..09f084b96b962 100644 --- a/packages/x-charts/src/LineChart/useLineChartProps.ts +++ b/packages/x-charts/src/LineChart/useLineChartProps.ts @@ -4,7 +4,7 @@ import { ChartsAxisProps } from '../ChartsAxis'; import { ChartsAxisHighlightProps } from '../ChartsAxisHighlight'; import { ChartsClipPathProps } from '../ChartsClipPath'; import { ChartsGridProps } from '../ChartsGrid'; -import { ChartsLegendProps } from '../ChartsLegend'; +import { ChartsLegendSlotExtension } from '../ChartsLegend'; import { ChartsOnAxisClickHandlerProps } from '../ChartsOnAxisClickHandler'; import { ChartsOverlayProps } from '../ChartsOverlay'; import { DEFAULT_X_AXIS_KEY } from '../constants'; @@ -14,6 +14,8 @@ import type { LineChartProps } from './LineChart'; import { LineHighlightPlotProps } from './LineHighlightPlot'; import { LinePlotProps } from './LinePlot'; import { MarkPlotProps } from './MarkPlot'; +import type { ChartsWrapperProps } from '../internals/components/ChartsWrapper'; +import { calculateMargins } from '../internals/calculateMargins'; /** * A helper function that extracts LineChartProps from the input props @@ -69,7 +71,7 @@ export const useLineChartProps = (props: LineChartProps) => { })), width, height, - margin, + margin: calculateMargins({ margin, hideLegend, slotProps, series }), colors, dataset, xAxis: xAxis ?? [ @@ -83,7 +85,6 @@ export const useLineChartProps = (props: LineChartProps) => { }, ], yAxis, - sx, highlightedItem, onHighlightChange, disableAxisListener: @@ -157,12 +158,19 @@ export const useLineChartProps = (props: LineChartProps) => { slotProps, }; - const legendProps: ChartsLegendProps = { + const legendProps: ChartsLegendSlotExtension = { slots, slotProps, }; + const chartsWrapperProps: Omit = { + sx, + legendPosition: props.slotProps?.legend?.position, + legendDirection: props.slotProps?.legend?.direction, + }; + return { + chartsWrapperProps, chartContainerProps, axisClickHandlerProps, gridProps, diff --git a/packages/x-charts/src/PieChart/PieArcLabelPlot.tsx b/packages/x-charts/src/PieChart/PieArcLabelPlot.tsx index cd37e91b98813..a2adde4ea9e7f 100644 --- a/packages/x-charts/src/PieChart/PieArcLabelPlot.tsx +++ b/packages/x-charts/src/PieChart/PieArcLabelPlot.tsx @@ -206,6 +206,7 @@ PieArcLabelPlot.propTypes = { id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, index: PropTypes.number.isRequired, label: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), + labelMarkType: PropTypes.oneOf(['circle', 'line', 'square']), padAngle: PropTypes.number.isRequired, startAngle: PropTypes.number.isRequired, value: PropTypes.number.isRequired, diff --git a/packages/x-charts/src/PieChart/PieArcPlot.tsx b/packages/x-charts/src/PieChart/PieArcPlot.tsx index a1cbd0e955f7e..2c43b0879966b 100644 --- a/packages/x-charts/src/PieChart/PieArcPlot.tsx +++ b/packages/x-charts/src/PieChart/PieArcPlot.tsx @@ -168,6 +168,7 @@ PieArcPlot.propTypes = { id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, index: PropTypes.number.isRequired, label: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), + labelMarkType: PropTypes.oneOf(['circle', 'line', 'square']), padAngle: PropTypes.number.isRequired, startAngle: PropTypes.number.isRequired, value: PropTypes.number.isRequired, diff --git a/packages/x-charts/src/PieChart/PieChart.test.tsx b/packages/x-charts/src/PieChart/PieChart.test.tsx index d1d5c3fd55ff9..4eebddfa285cc 100644 --- a/packages/x-charts/src/PieChart/PieChart.test.tsx +++ b/packages/x-charts/src/PieChart/PieChart.test.tsx @@ -34,6 +34,7 @@ describe('', () => { 'themeStyleOverrides', 'themeVariants', 'themeCustomPalette', + 'themeDefaultProps', ], }), ); diff --git a/packages/x-charts/src/PieChart/PieChart.tsx b/packages/x-charts/src/PieChart/PieChart.tsx index 4af810a6ed04d..4a04bd20e7cb4 100644 --- a/packages/x-charts/src/PieChart/PieChart.tsx +++ b/packages/x-charts/src/PieChart/PieChart.tsx @@ -1,10 +1,9 @@ 'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; -import { useRtl } from '@mui/system/RtlProvider'; import { useThemeProps } from '@mui/material/styles'; import { MakeOptional } from '@mui/x-internals/types'; -import { ChartContainer, ChartContainerProps } from '../ChartContainer'; +import { ChartContainerProps } from '../ChartContainer'; import { PieSeriesType } from '../models/seriesType'; import { ChartsTooltip } from '../ChartsTooltip'; import { ChartsTooltipSlots, ChartsTooltipSlotProps } from '../ChartsTooltip/ChartTooltip.types'; @@ -17,6 +16,10 @@ import { ChartsOverlaySlotProps, ChartsOverlaySlots, } from '../ChartsOverlay'; +import { ChartsSurface } from '../ChartsSurface'; +import { ChartDataProvider } from '../context'; +import { useChartContainerProps } from '../ChartContainer/useChartContainerProps'; +import { ChartsWrapper } from '../internals/components/ChartsWrapper'; export interface PieChartSlots extends PiePlotSlots, @@ -59,8 +62,7 @@ export interface PieChartProps slotProps?: PieChartSlotProps; } -const defaultMargin = { top: 5, bottom: 5, left: 5, right: 100 }; -const defaultRTLMargin = { top: 5, bottom: 5, left: 100, right: 5 }; +const defaultMargin = { top: 5, bottom: 5, left: 5, right: 5 }; /** * Demos: @@ -98,40 +100,48 @@ const PieChart = React.forwardRef(function PieChart( className, ...other } = props; - const isRtl = useRtl(); + const margin = { ...defaultMargin, ...marginProps }; - const margin = { ...(isRtl ? defaultRTLMargin : defaultMargin), ...marginProps }; + const { chartDataProviderProps, chartsSurfaceProps } = useChartContainerProps( + { + ...other, + series: series.map((s) => ({ type: 'pie', ...s })), + width, + height, + margin, + colors, + disableAxisListener: true, + highlightedItem, + onHighlightChange, + className, + skipAnimation, + }, + ref, + ); const Tooltip = slots?.tooltip ?? ChartsTooltip; return ( - ({ type: 'pie', ...s }))} - width={width} - height={height} - margin={margin} - colors={colors} - sx={sx} - disableAxisListener - highlightedItem={highlightedItem} - onHighlightChange={onHighlightChange} - className={className} - skipAnimation={skipAnimation} - > - - - {!hideLegend && ( - - )} - {!loading && } - {children} - + + + {!hideLegend && ( + + )} + + + + {!loading && } + {children} + + + ); }); diff --git a/packages/x-charts/src/PieChart/legend.ts b/packages/x-charts/src/PieChart/legend.ts index 4d39cdd7235e7..89ed3254d4f6b 100644 --- a/packages/x-charts/src/PieChart/legend.ts +++ b/packages/x-charts/src/PieChart/legend.ts @@ -1,4 +1,4 @@ -import { LegendItemParams } from '../ChartsLegend/chartsLegend.types'; +import type { LegendItemParams } from '../ChartsLegend'; import { getLabel } from '../internals/getLabel'; import { LegendGetter } from '../context/PluginProvider'; @@ -13,6 +13,7 @@ const legendGetter: LegendGetter<'pie'> = (params) => { } acc.push({ + markType: item.labelMarkType ?? series[seriesId].labelMarkType ?? 'circle', id: item.id, seriesId, color: item.color, diff --git a/packages/x-charts/src/ScatterChart/ScatterChart.test.tsx b/packages/x-charts/src/ScatterChart/ScatterChart.test.tsx index 0648c513feb83..4528f7f1cb479 100644 --- a/packages/x-charts/src/ScatterChart/ScatterChart.test.tsx +++ b/packages/x-charts/src/ScatterChart/ScatterChart.test.tsx @@ -37,6 +37,7 @@ describe('', () => { 'themeStyleOverrides', 'themeVariants', 'themeCustomPalette', + 'themeDefaultProps', ], }), ); diff --git a/packages/x-charts/src/ScatterChart/ScatterChart.tsx b/packages/x-charts/src/ScatterChart/ScatterChart.tsx index 65d5e8bc460ee..553a948d17370 100644 --- a/packages/x-charts/src/ScatterChart/ScatterChart.tsx +++ b/packages/x-charts/src/ScatterChart/ScatterChart.tsx @@ -9,7 +9,7 @@ import { ScatterPlotSlotProps, ScatterPlotSlots, } from './ScatterPlot'; -import { ChartContainer, ChartContainerProps } from '../ChartContainer'; +import { ChartContainerProps } from '../ChartContainer'; import { ChartsAxis, ChartsAxisProps } from '../ChartsAxis'; import { ScatterSeriesType } from '../models/seriesType/scatter'; import { ChartsTooltip } from '../ChartsTooltip'; @@ -30,6 +30,10 @@ import { import { ChartsGrid, ChartsGridProps } from '../ChartsGrid'; import { ZAxisContextProvider, ZAxisContextProviderProps } from '../context/ZAxisContextProvider'; import { useScatterChartProps } from './useScatterChartProps'; +import { useChartContainerProps } from '../ChartContainer/useChartContainerProps'; +import { ChartDataProvider } from '../context'; +import { ChartsSurface } from '../ChartsSurface'; +import { ChartsWrapper } from '../internals/components/ChartsWrapper'; export interface ScatterChartSlots extends ChartsAxisSlots, @@ -108,6 +112,7 @@ const ScatterChart = React.forwardRef(function ScatterChart( ) { const props = useThemeProps({ props: inProps, name: 'MuiScatterChart' }); const { + chartsWrapperProps, chartContainerProps, zAxisProps, voronoiHandlerProps, @@ -119,26 +124,34 @@ const ScatterChart = React.forwardRef(function ScatterChart( axisHighlightProps, children, } = useScatterChartProps(props); + const { chartDataProviderProps, chartsSurfaceProps } = useChartContainerProps( + chartContainerProps, + ref, + ); const Tooltip = props.slots?.tooltip ?? ChartsTooltip; return ( - - - {!props.disableVoronoi && } - - - - {/* The `data-drawing-container` indicates that children are part of the drawing area. Ref: https://github.com/mui/mui-x/issues/13659 */} - - - + + {!props.hideLegend && } - - {!props.loading && } - {children} - - + + + {!props.disableVoronoi && } + + + + {/* The `data-drawing-container` indicates that children are part of the drawing area. Ref: https://github.com/mui/mui-x/issues/13659 */} + + + + + {!props.loading && } + {children} + + + + ); }); diff --git a/packages/x-charts/src/ScatterChart/legend.ts b/packages/x-charts/src/ScatterChart/legend.ts index 6a113642caf2b..c08d7e9bd5a65 100644 --- a/packages/x-charts/src/ScatterChart/legend.ts +++ b/packages/x-charts/src/ScatterChart/legend.ts @@ -1,4 +1,4 @@ -import { LegendItemParams } from '../ChartsLegend/chartsLegend.types'; +import type { LegendItemParams } from '../ChartsLegend'; import { getLabel } from '../internals/getLabel'; import { LegendGetter } from '../context/PluginProvider'; @@ -12,6 +12,7 @@ const legendGetter: LegendGetter<'scatter'> = (params) => { } acc.push({ + markType: series[seriesId].labelMarkType ?? 'circle', id: seriesId, seriesId, color: series[seriesId].color, diff --git a/packages/x-charts/src/ScatterChart/useScatterChartProps.ts b/packages/x-charts/src/ScatterChart/useScatterChartProps.ts index 0399f0543a968..38f06b5ddd994 100644 --- a/packages/x-charts/src/ScatterChart/useScatterChartProps.ts +++ b/packages/x-charts/src/ScatterChart/useScatterChartProps.ts @@ -2,13 +2,15 @@ import { ChartsAxisProps } from '../ChartsAxis'; import { ChartsAxisHighlightProps } from '../ChartsAxisHighlight'; import { ChartsGridProps } from '../ChartsGrid'; -import { ChartsLegendProps } from '../ChartsLegend'; +import { ChartsLegendSlotExtension } from '../ChartsLegend'; import { ChartsOverlayProps } from '../ChartsOverlay'; import type { ChartsVoronoiHandlerProps } from '../ChartsVoronoiHandler'; import { ChartContainerProps } from '../ChartContainer'; import { ZAxisContextProviderProps } from '../context'; import type { ScatterChartProps } from './ScatterChart'; import type { ScatterPlotProps } from './ScatterPlot'; +import type { ChartsWrapperProps } from '../internals/components/ChartsWrapper'; +import { calculateMargins } from '../internals/calculateMargins'; /** * A helper function that extracts ScatterChartProps from the input props @@ -53,11 +55,10 @@ export const useScatterChartProps = (props: ScatterChartProps) => { series: series.map((s) => ({ type: 'scatter' as const, ...s })), width, height, - margin, + margin: calculateMargins({ margin, hideLegend, slotProps, series }), colors, xAxis, yAxis, - sx, highlightedItem, onHighlightChange, className, @@ -95,7 +96,7 @@ export const useScatterChartProps = (props: ScatterChartProps) => { slotProps, }; - const legendProps: ChartsLegendProps = { + const legendProps: ChartsLegendSlotExtension = { slots, slotProps, }; @@ -106,7 +107,14 @@ export const useScatterChartProps = (props: ScatterChartProps) => { ...axisHighlight, }; + const chartsWrapperProps: Omit = { + sx, + legendPosition: props.slotProps?.legend?.position, + legendDirection: props.slotProps?.legend?.direction, + }; + return { + chartsWrapperProps, chartContainerProps, zAxisProps, voronoiHandlerProps, diff --git a/packages/x-charts/src/constants/index.ts b/packages/x-charts/src/constants/index.ts index a198b2fa8f8ff..67382090061a5 100644 --- a/packages/x-charts/src/constants/index.ts +++ b/packages/x-charts/src/constants/index.ts @@ -6,3 +6,4 @@ export const DEFAULT_MARGINS = { left: 50, right: 50, }; +export const DEFAULT_LEGEND_FACING_MARGIN = 20; diff --git a/packages/x-charts/src/context/PluginProvider/SeriesFormatter.types.ts b/packages/x-charts/src/context/PluginProvider/SeriesFormatter.types.ts index 6462da81a53b8..7bf783b923f9d 100644 --- a/packages/x-charts/src/context/PluginProvider/SeriesFormatter.types.ts +++ b/packages/x-charts/src/context/PluginProvider/SeriesFormatter.types.ts @@ -6,7 +6,7 @@ import type { } from '../../models/seriesType/config'; import type { SeriesId } from '../../models/seriesType/common'; import type { StackingGroupsType } from '../../internals/stackSeries'; -import type { LegendItemParams } from '../../ChartsLegend/chartsLegend.types'; +import type { LegendItemParams } from '../../ChartsLegend'; export type SeriesFormatterParams = { series: Record; diff --git a/packages/x-charts/src/hooks/index.ts b/packages/x-charts/src/hooks/index.ts index 7f6e5dcdbdafe..9ba0336f9586c 100644 --- a/packages/x-charts/src/hooks/index.ts +++ b/packages/x-charts/src/hooks/index.ts @@ -11,3 +11,4 @@ export { useBarSeries as unstable_useBarSeries, useScatterSeries as unstable_useScatterSeries, } from './useSeries'; +export * from './useLegend'; diff --git a/packages/x-charts/src/ChartsLegend/utils.ts b/packages/x-charts/src/hooks/useLegend.ts similarity index 57% rename from packages/x-charts/src/ChartsLegend/utils.ts rename to packages/x-charts/src/hooks/useLegend.ts index 0e4e0bf973c85..362ace3361eea 100644 --- a/packages/x-charts/src/ChartsLegend/utils.ts +++ b/packages/x-charts/src/hooks/useLegend.ts @@ -1,3 +1,4 @@ +'use client'; import { FormattedSeries } from '../context/SeriesProvider'; import { ChartSeriesType } from '../models/seriesType/config'; import { LegendGetter } from '../context/PluginProvider'; @@ -6,6 +7,8 @@ import getBarLegend from '../BarChart/legend'; import getScatterLegend from '../ScatterChart/legend'; import getLineLegend from '../LineChart/legend'; import getPieLegend from '../PieChart/legend'; +import { useSeries } from './useSeries'; +import type { LegendItemParams } from '../ChartsLegend'; const legendGetter: { [T in ChartSeriesType]?: LegendGetter } = { bar: getBarLegend, @@ -14,7 +17,7 @@ const legendGetter: { [T in ChartSeriesType]?: LegendGetter } = { pie: getPieLegend, }; -export function getSeriesToDisplay(series: FormattedSeries) { +function getSeriesToDisplay(series: FormattedSeries) { return (Object.keys(series) as ChartSeriesType[]).flatMap( (seriesType: T) => { const getter = legendGetter[seriesType as T]; @@ -22,3 +25,19 @@ export function getSeriesToDisplay(series: FormattedSeries) { }, ); } + +/** + * Get the legend items to display. + * + * This hook is used by the `ChartsLegend` component. And will return the legend items formatted for display. + * + * An alternative is to use the `useSeries` hook and format the legend items yourself. + * + * @returns legend data + */ +export function useLegend(): { items: LegendItemParams[] } { + const series = useSeries(); + return { + items: getSeriesToDisplay(series), + }; +} diff --git a/packages/x-charts/src/index.ts b/packages/x-charts/src/index.ts index 0b76b3b75b74f..485077ceba010 100644 --- a/packages/x-charts/src/index.ts +++ b/packages/x-charts/src/index.ts @@ -11,6 +11,7 @@ export * from './ChartsYAxis'; export * from './ChartsGrid'; export * from './ChartsText'; export * from './ChartsTooltip'; +export * from './ChartsLabel'; export * from './ChartsLegend'; export * from './ChartsAxisHighlight'; export * from './ChartsVoronoiHandler'; diff --git a/packages/x-charts/src/internals/calculateMargins.ts b/packages/x-charts/src/internals/calculateMargins.ts new file mode 100644 index 0000000000000..f2984dac071b6 --- /dev/null +++ b/packages/x-charts/src/internals/calculateMargins.ts @@ -0,0 +1,51 @@ +import type { ChartsLegendSlotExtension } from '../ChartsLegend'; +import { DEFAULT_MARGINS, DEFAULT_LEGEND_FACING_MARGIN } from '../constants'; +import type { LayoutConfig } from '../models'; +import type { CartesianChartSeriesType, ChartsSeriesConfig } from '../models/seriesType/config'; + +export const calculateMargins = < + T extends ChartsLegendSlotExtension & + Pick & { + hideLegend?: boolean; + series?: Partial[]; + }, +>( + props: T, +): Required => { + if (props.hideLegend || !props.series?.some((s) => s.label)) { + return { + ...DEFAULT_MARGINS, + ...props.margin, + }; + } + + if (props.slotProps?.legend?.direction === 'vertical') { + if (props.slotProps?.legend?.position?.horizontal === 'left') { + return { + ...DEFAULT_MARGINS, + left: DEFAULT_LEGEND_FACING_MARGIN, + ...props.margin, + }; + } + + return { + ...DEFAULT_MARGINS, + right: DEFAULT_LEGEND_FACING_MARGIN, + ...props.margin, + }; + } + + if (props.slotProps?.legend?.position?.vertical === 'bottom') { + return { + ...DEFAULT_MARGINS, + bottom: DEFAULT_LEGEND_FACING_MARGIN, + ...props.margin, + }; + } + + return { + ...DEFAULT_MARGINS, + top: DEFAULT_LEGEND_FACING_MARGIN, + ...props.margin, + }; +}; diff --git a/packages/x-charts/src/internals/components/ChartsAxesGradients/ChartsAxesGradients.tsx b/packages/x-charts/src/internals/components/ChartsAxesGradients/ChartsAxesGradients.tsx index 7443e5754dc5c..d7edb5b7f60fc 100644 --- a/packages/x-charts/src/internals/components/ChartsAxesGradients/ChartsAxesGradients.tsx +++ b/packages/x-charts/src/internals/components/ChartsAxesGradients/ChartsAxesGradients.tsx @@ -4,11 +4,23 @@ import { useChartId, useDrawingArea } from '../../../hooks'; import ChartsPiecewiseGradient from './ChartsPiecewiseGradient'; import ChartsContinuousGradient from './ChartsContinuousGradient'; import { AxisId } from '../../../models/axis'; +import ChartsContinuousGradientObjectBound from './ChartsContinuousGradientObjectBound'; +import { useZAxis } from '../../../hooks/useZAxis'; export function useChartGradient() { const chartId = useChartId(); return React.useCallback( - (axisId: AxisId, direction: 'x' | 'y') => `${chartId}-gradient-${direction}-${axisId}`, + (axisId: AxisId, direction: 'x' | 'y' | 'z') => `${chartId}-gradient-${direction}-${axisId}`, + [chartId], + ); +} + +// TODO: make public? +export function useChartGradientObjectBound() { + const chartId = useChartId(); + return React.useCallback( + (axisId: AxisId, direction: 'x' | 'y' | 'z') => + `${chartId}-gradient-${direction}-${axisId}-object-bound`, [chartId], ); } @@ -19,12 +31,19 @@ export function ChartsAxesGradients() { const svgHeight = top + height + bottom; const svgWidth = left + width + right; const getGradientId = useChartGradient(); + const getObjectBoundGradientId = useChartGradientObjectBound(); const { xAxisIds, xAxis, yAxisIds, yAxis } = useCartesianContext(); + const { zAxisIds, zAxis } = useZAxis(); const filteredYAxisIds = yAxisIds.filter((axisId) => yAxis[axisId].colorMap !== undefined); const filteredXAxisIds = xAxisIds.filter((axisId) => xAxis[axisId].colorMap !== undefined); + const filteredZAxisIds = zAxisIds.filter((axisId) => zAxis[axisId].colorMap !== undefined); - if (filteredYAxisIds.length === 0 && filteredXAxisIds.length === 0) { + if ( + filteredYAxisIds.length === 0 && + filteredXAxisIds.length === 0 && + filteredZAxisIds.length === 0 + ) { return null; } @@ -32,6 +51,7 @@ export function ChartsAxesGradients() { {filteredYAxisIds.map((axisId) => { const gradientId = getGradientId(axisId, 'y'); + const objectBoundGradientId = getObjectBoundGradientId(axisId, 'y'); const { colorMap, scale, colorScale, reverse } = yAxis[axisId]; if (colorMap?.type === 'piecewise') { return ( @@ -48,22 +68,31 @@ export function ChartsAxesGradients() { } if (colorMap?.type === 'continuous') { return ( - + + + + ); } return null; })} {filteredXAxisIds.map((axisId) => { const gradientId = getGradientId(axisId, 'x'); + const objectBoundGradientId = getObjectBoundGradientId(axisId, 'x'); + const { colorMap, scale, reverse, colorScale } = xAxis[axisId]; if (colorMap?.type === 'piecewise') { return ( @@ -80,15 +109,37 @@ export function ChartsAxesGradients() { } if (colorMap?.type === 'continuous') { return ( - + + + + ); + } + return null; + })} + {filteredZAxisIds.map((axisId) => { + const objectBoundGradientId = getObjectBoundGradientId(axisId, 'z'); + const { colorMap, colorScale } = zAxis[axisId]; + if (colorMap?.type === 'continuous') { + return ( + ); } diff --git a/packages/x-charts/src/internals/components/ChartsAxesGradients/ChartsContinuousGradient.tsx b/packages/x-charts/src/internals/components/ChartsAxesGradients/ChartsContinuousGradient.tsx index f78518a478c53..5eb3915bdf214 100644 --- a/packages/x-charts/src/internals/components/ChartsAxesGradients/ChartsContinuousGradient.tsx +++ b/packages/x-charts/src/internals/components/ChartsAxesGradients/ChartsContinuousGradient.tsx @@ -24,22 +24,24 @@ export default function ChartsContinuousGradient(props: ChartsContinuousGradient const { gradientUnits, isReversed, gradientId, size, direction, scale, colorScale, colorMap } = props; - const extremValues = [colorMap.min ?? 0, colorMap.max ?? 100] as [number, number] | [Date, Date]; - const extremPositions = extremValues.map(scale).filter((p): p is number => p !== undefined); + const extremumValues = [colorMap.min ?? 0, colorMap.max ?? 100] as + | [number, number] + | [Date, Date]; + const extremumPositions = extremumValues.map(scale).filter((p): p is number => p !== undefined); - if (extremPositions.length !== 2) { + if (extremumPositions.length !== 2) { return null; } const interpolator = - typeof extremValues[0] === 'number' - ? interpolateNumber(extremValues[0], extremValues[1]) - : interpolateDate(extremValues[0], extremValues[1] as Date); + typeof extremumValues[0] === 'number' + ? interpolateNumber(extremumValues[0], extremumValues[1]) + : interpolateDate(extremumValues[0], extremumValues[1] as Date); const numberOfPoints = Math.round( - (Math.max(...extremPositions) - Math.min(...extremPositions)) / PX_PRECISION, + (Math.max(...extremumPositions) - Math.min(...extremumPositions)) / PX_PRECISION, ); - const keyPrefix = `${extremValues[0]}-${extremValues[1]}-`; + const keyPrefix = `${extremumValues[0]}-${extremumValues[1]}-`; return ( string | null; +}; + +const getDirection = (isReversed?: boolean): Record<'x1' | 'x2' | 'y1' | 'y2', '0' | '1'> => { + if (isReversed) { + return { x1: '1', x2: '0', y1: '0', y2: '0' }; + } + return { x1: '0', x2: '1', y1: '0', y2: '0' }; +}; + +/** + * Generates gradients to be used in tooltips and legends. + */ +export default function ChartsContinuousGradientObjectBound( + props: ChartsContinuousGradientObjectBoundProps, +) { + const { isReversed, gradientId, colorScale, colorMap } = props; + + const extremumValues = [colorMap.min ?? 0, colorMap.max ?? 100] as + | [number, number] + | [Date, Date]; + + const interpolator = + typeof extremumValues[0] === 'number' + ? interpolateNumber(extremumValues[0], extremumValues[1]) + : interpolateDate(extremumValues[0], extremumValues[1] as Date); + const numberOfPoints = PX_PRECISION; + + const keyPrefix = `${extremumValues[0]}-${extremumValues[1]}-`; + return ( + + {Array.from({ length: numberOfPoints + 1 }, (_, index) => { + const offset = index / numberOfPoints; + const value = interpolator(offset); + if (value === undefined) { + return null; + } + + const color = colorScale(value); + + if (color === null) { + return null; + } + return ; + })} + + ); +} diff --git a/packages/x-charts/src/internals/components/ChartsAxesGradients/ChartsPiecewiseGradient.tsx b/packages/x-charts/src/internals/components/ChartsAxesGradients/ChartsPiecewiseGradient.tsx index 6b6957ab154d3..cd792c6c72d53 100644 --- a/packages/x-charts/src/internals/components/ChartsAxesGradients/ChartsPiecewiseGradient.tsx +++ b/packages/x-charts/src/internals/components/ChartsAxesGradients/ChartsPiecewiseGradient.tsx @@ -31,6 +31,10 @@ export default function ChartsPiecewiseGradient(props: ChartsPiecewiseGradientPr } const offset = isReversed ? 1 - x / size : x / size; + if (Number.isNaN(offset)) { + return null; + } + return ( diff --git a/packages/x-charts/src/internals/components/ChartsWrapper/ChartsWrapper.tsx b/packages/x-charts/src/internals/components/ChartsWrapper/ChartsWrapper.tsx new file mode 100644 index 0000000000000..a1b80b46ac0df --- /dev/null +++ b/packages/x-charts/src/internals/components/ChartsWrapper/ChartsWrapper.tsx @@ -0,0 +1,82 @@ +import * as React from 'react'; +import { styled, SxProps, Theme } from '@mui/material/styles'; +import { Direction, LegendPosition } from '../../../ChartsLegend'; + +export interface ChartsWrapperProps { + // eslint-disable-next-line react/no-unused-prop-types + legendPosition?: LegendPosition; + // eslint-disable-next-line react/no-unused-prop-types + legendDirection?: Direction; + children: React.ReactNode; + sx?: SxProps; +} + +const getDirection = (direction?: Direction, position?: LegendPosition) => { + if (direction === 'vertical') { + if (position?.horizontal === 'left') { + return 'row'; + } + + return 'row-reverse'; + } + + if (position?.vertical === 'bottom') { + return 'column-reverse'; + } + + return 'column'; +}; + +const getAlign = (direction?: Direction, position?: LegendPosition) => { + if (direction === 'vertical') { + if (position?.vertical === 'top') { + return 'flex-start'; + } + + if (position?.vertical === 'bottom') { + return 'flex-end'; + } + } + + if (direction === 'horizontal') { + if (position?.horizontal === 'left') { + return 'flex-start'; + } + + if (position?.horizontal === 'right') { + return 'flex-end'; + } + } + + return 'center'; +}; + +const Root = styled('div', { + name: 'MuiChartsWrapper', + slot: 'Root', + overridesResolver: (props, styles) => styles.root, +})<{ ownerState: ChartsWrapperProps }>(({ ownerState }) => ({ + display: 'flex', + flexDirection: getDirection(ownerState.legendDirection, ownerState.legendPosition), + flex: 1, + justifyContent: 'center', + alignItems: getAlign(ownerState.legendDirection, ownerState.legendPosition), +})); + +/** + * @ignore - internal component. + * + * Wrapper for the charts components. + * Its main purpose is to position the HTML legend in the correct place. + */ +function ChartsWrapper(props: ChartsWrapperProps) { + const { children, sx } = props; + + return ( + + {children} + + ); +} + +export { ChartsWrapper }; diff --git a/packages/x-charts/src/internals/components/ChartsWrapper/index.ts b/packages/x-charts/src/internals/components/ChartsWrapper/index.ts new file mode 100644 index 0000000000000..42c70e39f34fb --- /dev/null +++ b/packages/x-charts/src/internals/components/ChartsWrapper/index.ts @@ -0,0 +1 @@ +export * from './ChartsWrapper'; diff --git a/packages/x-charts/src/internals/consumeSlots.test.tsx b/packages/x-charts/src/internals/consumeSlots.test.tsx new file mode 100644 index 0000000000000..2ff5ac4003ee2 --- /dev/null +++ b/packages/x-charts/src/internals/consumeSlots.test.tsx @@ -0,0 +1,103 @@ +import * as React from 'react'; +import { createRenderer, screen } from '@mui/internal-test-utils'; +import { consumeSlots } from './consumeSlots'; + +type WrapperProps = { + data?: string; + shouldOmit?: boolean; + classes?: Record<'root', string>; + slots?: { + wrapper?: + | React.ElementType> + | React.ForwardRefRenderFunction>; + }; +}; + +const SlotsWrapper = consumeSlots( + 'MuiSlotsWrapper', + 'wrapper', + { + defaultProps: { data: 'test' }, + omitProps: ['shouldOmit'], + classesResolver: (props: WrapperProps) => ({ + root: ['wrapper-root', props.data, props.shouldOmit ? 'shouldOmit' : ''].join(' '), + }), + }, + function SlotsWrapper(props: WrapperProps, ref: React.Ref) { + return ( +
    +
    {props.data}
    +
    {props.shouldOmit ? 'not-omitted' : 'omitted'}
    +
    {props.classes?.root}
    +
    + ); + }, +); + +describe('consumeSlots', () => { + const { render } = createRenderer(); + + it('should render default props', async () => { + render(); + + await screen.findByText('test', { selector: '.data' }); + }); + + it('should render passed props', async () => { + render(); + + await screen.findByText('new', { selector: '.data' }); + }); + + it('should render omit props in omitProps', async () => { + render(); + + await screen.findByText('omitted', { selector: '.shouldOmit' }); + }); + + it('should resolve classes', async () => { + render(); + + await screen.findByText('wrapper-root test shouldOmit', { selector: '.classes' }); + }); + + it('should render function component passed as slot', async () => { + render( +
    function component
    , + }} + />, + ); + + await screen.findByText('function component'); + }); + + it('should render forward ref function passed as slot', async () => { + render( + ) => ( +
    forward ref
    + )), + }} + />, + ); + + await screen.findByText('forward ref'); + }); + + it('should render function with props and ref arguments passed as slot', async () => { + render( + ) => ( +
    props and ref arguments
    + ), + }} + />, + ); + + await screen.findByText('props and ref arguments'); + }); +}); diff --git a/packages/x-charts/src/internals/consumeSlots.tsx b/packages/x-charts/src/internals/consumeSlots.tsx new file mode 100644 index 0000000000000..178e2f40b4cdb --- /dev/null +++ b/packages/x-charts/src/internals/consumeSlots.tsx @@ -0,0 +1,121 @@ +import { useTheme, useThemeProps } from '@mui/material/styles'; +import resolveProps from '@mui/utils/resolveProps'; +import useSlotProps from '@mui/utils/useSlotProps'; +import * as React from 'react'; + +/** + * A higher order component that consumes a slot from the props and renders the component provided in the slot. + * + * This HOC will wrap a single component, and will render the component provided in the slot, if it exists. + * + * If you need to render multiple components, you can manually consume the slots from the props and render them in your component instead of using this HOC. + * + * In the example below, `MyComponent` will render the component provided in `mySlot` slot, if it exists. Otherwise, it will render the `DefaultComponent`. + * + * @example + * + * ```tsx + * type MyComponentProps = { + * direction: 'row' | 'column'; + * slots?: { + * mySlot?: React.JSXElementConstructor<{ direction: 'row' | 'column' }>; + * } + * }; + * + * const MyComponent = consumeSlots( + * 'MuiMyComponent', + * 'mySlot', + * function DefaultComponent(props: MyComponentProps) { + * return ( + *
    + * {props.direction} + *
    + * ); + * } + * ); + * ``` + * + * @param {string} name The mui component name. + * @param {string} slotPropName The name of the prop to retrieve the slot from. + * @param {object} options Options for the HOC. + * @param {boolean} options.propagateSlots Whether to propagate the slots to the component, this is always false if the slot is provided. + * @param {Record} options.defaultProps A set of defaults for the component, will be deep merged with the props. + * @param {Array} options.omitProps An array of props to omit from the component. + * @param {Function} options.classesResolver A function that returns the classes for the component. It receives the props, after theme props and defaults have been applied. And the theme object as the second argument. + * @param InComponent The component to render if the slot is not provided. + */ +export const consumeSlots = < + Props extends {}, + Ref extends {}, + RenderFunction = (props: Props, ref: React.Ref) => React.ElementType, +>( + name: string, + slotPropName: string, + options: { + propagateSlots?: boolean; + defaultProps?: + | Omit, 'slots' | 'slotProps'> + | ((props: Props) => Omit, 'slots' | 'slotProps'>); + omitProps?: Array; + classesResolver?: (props: Props, theme: any) => Record; + }, + InComponent: RenderFunction, +) => { + function ConsumeSlotsInternal(props: React.PropsWithoutRef, ref: React.ForwardedRef) { + const themedProps = useThemeProps({ + props, + // eslint-disable-next-line material-ui/mui-name-matches-component-name + name, + }); + + const defaultProps = + typeof options.defaultProps === 'function' + ? options.defaultProps(themedProps as Props) + : (options.defaultProps ?? {}); + + const defaultizedProps = resolveProps(defaultProps, themedProps) as Props; + const { slots, slotProps, ...other } = defaultizedProps as { + slots?: Record; + slotProps?: Record; + }; + + const theme = useTheme(); + const classes = options.classesResolver?.(defaultizedProps, theme); + + // Can be a function component or a forward ref component. + const Component = slots?.[slotPropName] ?? InComponent; + + const propagateSlots = options.propagateSlots && !slots?.[slotPropName]; + + const { ownerState, ...originalOutProps } = useSlotProps({ + elementType: Component, + externalSlotProps: slotProps?.[slotPropName], + additionalProps: { + ...other, + classes, + ...(propagateSlots && { slots, slotProps }), + }, + ownerState: {}, + }); + + const outProps = { ...originalOutProps } as unknown as Props; + + for (const prop of options.omitProps ?? []) { + delete (outProps as unknown as Props)[prop]; + } + + // Component can be wrapped in React.forwardRef or just a function that accepts (props, ref). + // If it is a plain function which accepts two arguments, we need to wrap it in React.forwardRef. + const OutComponent = ( + Component.length >= 2 ? React.forwardRef(Component) : Component + ) as React.FunctionComponent; + + if (process.env.NODE_ENV !== 'production') { + OutComponent.displayName = `${name}.slots.${slotPropName}`; + } + + return ; + } + + return React.forwardRef(ConsumeSlotsInternal); +}; diff --git a/packages/x-charts/src/internals/consumeThemeProps.test.tsx b/packages/x-charts/src/internals/consumeThemeProps.test.tsx new file mode 100644 index 0000000000000..f5b2d28dd7185 --- /dev/null +++ b/packages/x-charts/src/internals/consumeThemeProps.test.tsx @@ -0,0 +1,52 @@ +import * as React from 'react'; +import { createRenderer, screen } from '@mui/internal-test-utils'; +import { consumeThemeProps } from './consumeThemeProps'; + +type WrapperProps = { + data?: string; + shouldOmit?: boolean; + classes?: Record<'root', string>; + slots?: { + wrapper?: React.ElementType>; + }; +}; + +const SlotsWrapper = consumeThemeProps( + 'MuiSlotsWrapper', + { + defaultProps: { data: 'test' }, + classesResolver: (props: WrapperProps) => ({ + root: ['wrapper-root', props.data, props.shouldOmit ? 'shouldOmit' : ''].join(' '), + }), + }, + function SlotsWrapper(props: WrapperProps, ref: React.Ref) { + return ( +
    +
    {props.data}
    +
    {props.classes?.root}
    +
    + ); + }, +); + +describe('consumeThemeProps', () => { + const { render } = createRenderer(); + + it('should render default props', async function test() { + render(); + + await screen.findByText('test', { selector: '.data' }); + }); + + it('should render passed props', async function test() { + render(); + + await screen.findByText('new', { selector: '.data' }); + }); + + it('should resolve classes', async () => { + render(); + + await screen.findByText('wrapper-root test shouldOmit', { selector: '.classes' }); + }); +}); diff --git a/packages/x-charts/src/internals/consumeThemeProps.tsx b/packages/x-charts/src/internals/consumeThemeProps.tsx index 217550c1b07ad..29524a2ddb794 100644 --- a/packages/x-charts/src/internals/consumeThemeProps.tsx +++ b/packages/x-charts/src/internals/consumeThemeProps.tsx @@ -1,7 +1,6 @@ import { useTheme, useThemeProps } from '@mui/material/styles'; import resolveProps from '@mui/utils/resolveProps'; import * as React from 'react'; -import * as ReactIs from 'react-is'; /** * A higher order component that consumes and merges the theme `defaultProps` and handles the `classes` and renders the component. @@ -49,22 +48,23 @@ import * as ReactIs from 'react-is'; * @param InComponent The component to render if the slot is not provided. */ export const consumeThemeProps = < - Props extends { - slots?: Record; - slotProps?: Record; - classes?: Record; - }, + Props extends {}, + Ref extends {}, + RenderFunction = (props: Props, ref: React.Ref) => React.ElementType, >( name: string, options: { defaultProps?: | Omit, 'slots' | 'slotProps'> - | ((props: Props) => Omit, 'slots' | 'slotProps'>); + | ((props: T) => Omit, 'slots' | 'slotProps'>); classesResolver?: (props: Props, theme: any) => Record; }, - InComponent: React.ForwardRefRenderFunction, -) => { - function InternalComponent(props: React.PropsWithoutRef, ref: React.Ref) { + InComponent: RenderFunction, +) => + React.forwardRef(function ConsumeThemeInternal( + props: React.PropsWithoutRef, + ref: React.ForwardedRef, + ) { const themedProps = useThemeProps({ props, // eslint-disable-next-line material-ui/mui-name-matches-component-name @@ -76,24 +76,18 @@ export const consumeThemeProps = < ? options.defaultProps(themedProps as Props) : (options.defaultProps ?? {}); - const outProps = resolveProps(defaultProps, themedProps) as Props; + const outProps = resolveProps(defaultProps, themedProps) as React.PropsWithoutRef; const theme = useTheme(); - const classes = options.classesResolver?.(outProps, theme); + const classes = options.classesResolver?.(outProps as Props, theme); + + const OutComponent = React.forwardRef( + InComponent as React.ForwardRefRenderFunction>, + ); if (process.env.NODE_ENV !== 'production') { - // eslint-disable-next-line react-compiler/react-compiler - (InComponent as any).displayName = name; + OutComponent.displayName = `consumeThemeProps(${name})`; } - const OutComponent = ReactIs.isForwardRef(InComponent) - ? (InComponent as unknown as React.ElementType) - : // InComponent needs to be a function that accepts `(props, ref)` - // @ts-expect-error - React.forwardRef(InComponent); - return ; - } - - return React.forwardRef(InternalComponent); -}; + }); diff --git a/packages/x-charts/src/internals/index.ts b/packages/x-charts/src/internals/index.ts index b3079186b4810..93f32cab9e1e9 100644 --- a/packages/x-charts/src/internals/index.ts +++ b/packages/x-charts/src/internals/index.ts @@ -1,5 +1,6 @@ // Components export * from './components/ChartsAxesGradients'; +export * from './components/ChartsWrapper'; // hooks export { useSeries } from '../hooks/useSeries'; diff --git a/packages/x-charts/src/models/seriesType/common.ts b/packages/x-charts/src/models/seriesType/common.ts index 356c8a4b4b23b..084d3d302dd1a 100644 --- a/packages/x-charts/src/models/seriesType/common.ts +++ b/packages/x-charts/src/models/seriesType/common.ts @@ -1,3 +1,4 @@ +import type { ChartsLabelMarkProps } from '../../ChartsLabel'; import type { HighlightScope } from '../../context'; import type { StackOffsetType, StackOrderType } from '../stacking'; @@ -29,6 +30,14 @@ export type CommonSeriesType = { * The scope to apply when the series is highlighted. */ highlightScope?: Partial; + /** + * Defines the mark type for the series. + * + * There is a default mark type for each series type. + * + * It allows custom values which will be passed to the mark component if it was customized. + */ + labelMarkType?: ChartsLabelMarkProps['type']; }; export type CommonDefaultizedProps = 'id' | 'valueFormatter' | 'data'; diff --git a/packages/x-charts/src/models/seriesType/pie.ts b/packages/x-charts/src/models/seriesType/pie.ts index 1ab1a6a4b5a87..50d2447ec0cfc 100644 --- a/packages/x-charts/src/models/seriesType/pie.ts +++ b/packages/x-charts/src/models/seriesType/pie.ts @@ -1,6 +1,7 @@ import { PieArcDatum as D3PieArcDatum } from '@mui/x-charts-vendor/d3-shape'; import { DefaultizedProps } from '@mui/x-internals/types'; import { CommonDefaultizedProps, CommonSeriesType, SeriesId } from './common'; +import type { ChartsLabelMarkProps } from '../../ChartsLabel'; export type PieItemId = string | number; @@ -15,6 +16,14 @@ export type PieValueType = { */ label?: string | ((location: 'tooltip' | 'legend' | 'arc') => string); color?: string; + /** + * Defines the mark type for the pie item. + * + * It allows custom values which will be passed to the mark component if it was customized. + * + * @default 'circle' + */ + labelMarkType?: ChartsLabelMarkProps['type']; }; export type DefaultizedPieValueType = PieValueType & diff --git a/packages/x-charts/src/themeAugmentation/themeAugmentation.spec.ts b/packages/x-charts/src/themeAugmentation/themeAugmentation.spec.ts index 8412c5c669cf7..4e55e2684ac42 100644 --- a/packages/x-charts/src/themeAugmentation/themeAugmentation.spec.ts +++ b/packages/x-charts/src/themeAugmentation/themeAugmentation.spec.ts @@ -42,7 +42,7 @@ createTheme({ }, MuiChartsLegend: { defaultProps: { - direction: 'row', + direction: 'vertical', // @ts-expect-error invalid MuiChartsLegend prop someRandomProp: true, }, diff --git a/packages/x-codemod/README.md b/packages/x-codemod/README.md index 75d44cf98ab90..2ca0c8be18edc 100644 --- a/packages/x-codemod/README.md +++ b/packages/x-codemod/README.md @@ -143,6 +143,7 @@ npx @mui/x-codemod@next v8.0.0/charts/preset-safe The list includes these transformers - [`rename-legend-to-slots-legend`](#rename-legend-to-slots-legend) +- [`replace-legend-direction-values`](#replace-legend-direction-values) - [`rename-responsive-chart-container`](#rename-responsive-chart-container) - [`rename-label-and-tick-font-size`](#rename-label-and-tick-font-size) @@ -157,6 +158,21 @@ Renames legend props to the corresponding slotProps. /> ``` +#### `replace-legend-direction-values` + +Replace `row` and `column` values by `horizontal` and `vertical` respectively. + +```diff + +``` + #### `rename-responsive-chart-container` Renames `ResponsiveChartContainer` and `ResponsiveChartContainerPro` by `ChartContainer` and `ChartContainerPro` which have the same behavior in v8. diff --git a/packages/x-codemod/src/v8.0.0/charts/preset-safe/actual.spec.tsx b/packages/x-codemod/src/v8.0.0/charts/preset-safe/actual.spec.tsx index 849585a97e2fb..9e949121e03c7 100644 --- a/packages/x-codemod/src/v8.0.0/charts/preset-safe/actual.spec.tsx +++ b/packages/x-codemod/src/v8.0.0/charts/preset-safe/actual.spec.tsx @@ -1,7 +1,7 @@ // @ts-nocheck import * as React from 'react'; import { PieChart } from '@mui/x-charts/PieChart'; -import { BarPlot } from '@mui/x-charts/BarChart'; +import { BarPlot, BarChart } from '@mui/x-charts/BarChart'; import { ResponsiveChartContainer } from '@mui/x-charts/ResponsiveChartContainer'; import { ChartsXAxis } from '@mui/x-charts/ChartsXAxis'; @@ -25,4 +25,7 @@ import { ChartsXAxis } from '@mui/x-charts/ChartsXAxis'; labelStyle={{ fontWeight: 'bold', fontSize: 10 }} tickStyle={{ fontWeight: 'bold', fontSize: 12 }} /> + + + ; diff --git a/packages/x-codemod/src/v8.0.0/charts/preset-safe/expected.spec.tsx b/packages/x-codemod/src/v8.0.0/charts/preset-safe/expected.spec.tsx index 139cad04ca12c..b674eb48cbe82 100644 --- a/packages/x-codemod/src/v8.0.0/charts/preset-safe/expected.spec.tsx +++ b/packages/x-codemod/src/v8.0.0/charts/preset-safe/expected.spec.tsx @@ -1,7 +1,7 @@ // @ts-nocheck import * as React from 'react'; import { PieChart } from '@mui/x-charts/PieChart'; -import { BarPlot } from '@mui/x-charts/BarChart'; +import { BarPlot, BarChart } from '@mui/x-charts/BarChart'; import { ChartContainer } from '@mui/x-charts/ChartContainer'; import { ChartsXAxis } from '@mui/x-charts/ChartsXAxis'; @@ -44,4 +44,23 @@ import { ChartsXAxis } from '@mui/x-charts/ChartsXAxis'; fontWeight: 'bold', fontSize: 12 }} /> + + + ; diff --git a/packages/x-codemod/src/v8.0.0/charts/preset-safe/index.ts b/packages/x-codemod/src/v8.0.0/charts/preset-safe/index.ts index 3fdc6150db550..54cc36d4595ab 100644 --- a/packages/x-codemod/src/v8.0.0/charts/preset-safe/index.ts +++ b/packages/x-codemod/src/v8.0.0/charts/preset-safe/index.ts @@ -1,6 +1,7 @@ import transformLegendToSlots from '../rename-legend-to-slots-legend'; import transformRemoveResponsiveContainer from '../rename-responsive-chart-container'; import transformRenameLabelAndTickFontSize from '../rename-label-and-tick-font-size'; +import transformReplaceLegendDirectionValues from '../replace-legend-direction-values'; import { JsCodeShiftAPI, JsCodeShiftFileInfo } from '../../../types'; @@ -8,6 +9,8 @@ export default function transformer(file: JsCodeShiftFileInfo, api: JsCodeShiftA file.source = transformLegendToSlots(file, api, options); file.source = transformRemoveResponsiveContainer(file, api, options); file.source = transformRenameLabelAndTickFontSize(file, api, options); + file.source = transformRenameLabelAndTickFontSize(file, api, options); + file.source = transformReplaceLegendDirectionValues(file, api, options); return file.source; } diff --git a/packages/x-codemod/src/v8.0.0/charts/replace-legend-direction-values/actual.spec.tsx b/packages/x-codemod/src/v8.0.0/charts/replace-legend-direction-values/actual.spec.tsx new file mode 100644 index 0000000000000..930f06082a354 --- /dev/null +++ b/packages/x-codemod/src/v8.0.0/charts/replace-legend-direction-values/actual.spec.tsx @@ -0,0 +1,10 @@ +// @ts-nocheck +import * as React from 'react'; +import { BarChart } from '@mui/x-charts/BarChart'; + +// prettier-ignore +
    + + + +
    ; diff --git a/packages/x-codemod/src/v8.0.0/charts/replace-legend-direction-values/expected.spec.tsx b/packages/x-codemod/src/v8.0.0/charts/replace-legend-direction-values/expected.spec.tsx new file mode 100644 index 0000000000000..13791eaec74f8 --- /dev/null +++ b/packages/x-codemod/src/v8.0.0/charts/replace-legend-direction-values/expected.spec.tsx @@ -0,0 +1,26 @@ +// @ts-nocheck +import * as React from 'react'; +import { BarChart } from '@mui/x-charts/BarChart'; + +// prettier-ignore +
    + + + +
    ; diff --git a/packages/x-codemod/src/v8.0.0/charts/replace-legend-direction-values/index.ts b/packages/x-codemod/src/v8.0.0/charts/replace-legend-direction-values/index.ts new file mode 100644 index 0000000000000..2c1f748a75a3f --- /dev/null +++ b/packages/x-codemod/src/v8.0.0/charts/replace-legend-direction-values/index.ts @@ -0,0 +1,75 @@ +import { JSXAttribute, JSXExpressionContainer, ObjectExpression } from 'jscodeshift'; +import { JsCodeShiftAPI, JsCodeShiftFileInfo } from '../../../types'; +import { transformNestedProp } from '../../../util/addComponentsSlots'; +/** + * @param {import('jscodeshift').FileInfo} file + * @param {import('jscodeshift').API} api + */ +export default function transformer(file: JsCodeShiftFileInfo, api: JsCodeShiftAPI, options: any) { + const j = api.jscodeshift; + + const printOptions = options.printOptions; + + const root = j(file.source); + + root + .find(j.ImportDeclaration) + .filter(({ node }) => { + return typeof node.source.value === 'string' && node.source.value.startsWith('@mui/x-charts'); + }) + .forEach((path) => { + path.node.specifiers?.forEach((node) => { + root.findJSXElements(node.local?.name).forEach((elementPath) => { + if (elementPath.node.type !== 'JSXElement') { + return; + } + + const slotProps = elementPath.node.openingElement.attributes?.find( + (elementNode) => + elementNode.type === 'JSXAttribute' && elementNode.name.name === 'slotProps', + ) as JSXAttribute | null; + + if (slotProps === null) { + // No slotProps to manage + return; + } + + const direction = ( + (slotProps?.value as JSXExpressionContainer | null)?.expression as ObjectExpression + )?.properties + // @ts-expect-error + ?.find((v) => v?.key?.name === 'legend') + // @ts-expect-error + ?.value?.properties?.find((v) => v?.key?.name === 'direction'); + + if ( + direction === undefined || + direction?.value === undefined || + direction?.value?.value === undefined + ) { + return; + } + const directionValue = direction.value; + + directionValue.value = mapFix(directionValue.value); + + transformNestedProp(elementPath, 'slotProps', 'legend.direction', directionValue, j); + }); + }); + }); + + const transformed = root.findJSXElements(); + + return transformed.toSource(printOptions); +} + +function mapFix(v?: string) { + switch (v) { + case 'row': + return 'horizontal'; + case 'column': + return 'vertical'; + default: + return v; + } +} diff --git a/packages/x-codemod/src/v8.0.0/charts/replace-legend-direction-values/replace-legend-direction-values.test.ts b/packages/x-codemod/src/v8.0.0/charts/replace-legend-direction-values/replace-legend-direction-values.test.ts new file mode 100644 index 0000000000000..0d3f4daddffaa --- /dev/null +++ b/packages/x-codemod/src/v8.0.0/charts/replace-legend-direction-values/replace-legend-direction-values.test.ts @@ -0,0 +1,38 @@ +import path from 'path'; +import { expect } from 'chai'; +import jscodeshift from 'jscodeshift'; +import transform from '.'; +import readFile from '../../../util/readFile'; + +function read(fileName) { + return readFile(path.join(__dirname, fileName)); +} + +describe('v8.0.0/charts', () => { + describe('rename-label-and-tick-font-size.test', () => { + const actualPath = `./actual.spec.tsx`; + const expectedPath = `./expected.spec.tsx`; + + it('transforms imports as needed', () => { + const actual = transform( + { source: read(actualPath) }, + { jscodeshift: jscodeshift.withParser('tsx') }, + {}, + ); + + const expected = read(expectedPath); + expect(actual).to.equal(expected, 'The transformed version should be correct'); + }); + + it('should be idempotent', () => { + const actual = transform( + { source: read(expectedPath) }, + { jscodeshift: jscodeshift.withParser('tsx') }, + {}, + ); + + const expected = read(expectedPath); + expect(actual).to.equal(expected, 'The transformed version should be correct'); + }); + }); +}); diff --git a/packages/x-internals/src/types/AppendKeys.ts b/packages/x-internals/src/types/AppendKeys.ts new file mode 100644 index 0000000000000..49cf66082f6c8 --- /dev/null +++ b/packages/x-internals/src/types/AppendKeys.ts @@ -0,0 +1,16 @@ +// Uppercase first letter of a string +type CapitalizeFirstLetter = S extends `${infer First}${infer Rest}` + ? `${Uppercase}${Rest}` + : S; + +/** + * Append string P to all keys in T. + * If K is provided, only append P to keys in K. + * + * @template T - The type to append keys to. + * @template P - The string to append. + * @template K - The keys to append P to. + */ +export type AppendKeys = { + [key in keyof T as key extends K ? `${key}${CapitalizeFirstLetter

    }` : key]: T[key]; +}; diff --git a/packages/x-internals/src/types/PrependKeys.ts b/packages/x-internals/src/types/PrependKeys.ts new file mode 100644 index 0000000000000..f6eddd8ce5c75 --- /dev/null +++ b/packages/x-internals/src/types/PrependKeys.ts @@ -0,0 +1,16 @@ +// Uppercase first letter of a string +type CapitalizeFirstLetter = S extends `${infer First}${infer Rest}` + ? `${Uppercase}${Rest}` + : S; + +/** + * Prepend string P to all keys in T. + * If K is provided, only prepend P to keys in K. + * + * @template T - The type to prepend keys to. + * @template P - The string to prepend. + * @template K - The keys to prepend P to. + */ +export type PrependKeys = { + [key in keyof T as key extends K ? `${P}${CapitalizeFirstLetter}` : key]: T[key]; +}; diff --git a/packages/x-internals/src/types/index.ts b/packages/x-internals/src/types/index.ts index 43d0d70371584..8219e4271846e 100644 --- a/packages/x-internals/src/types/index.ts +++ b/packages/x-internals/src/types/index.ts @@ -1,4 +1,6 @@ +export * from './AppendKeys'; export * from './DefaultizedProps'; export * from './MakeOptional'; export * from './MakeRequired'; +export * from './PrependKeys'; export * from './SlotComponentPropsFromProps'; diff --git a/scripts/buildApiDocs/chartsSettings/index.ts b/scripts/buildApiDocs/chartsSettings/index.ts index 2c9dabdcb7e77..2ba7315b2f302 100644 --- a/scripts/buildApiDocs/chartsSettings/index.ts +++ b/scripts/buildApiDocs/chartsSettings/index.ts @@ -68,7 +68,6 @@ export default chartsApiPages; 'x-charts/src/ChartsOverlay/ChartsOverlay.tsx', 'x-charts/src/ChartsOverlay/ChartsNoDataOverlay.tsx', 'x-charts/src/ChartsOverlay/ChartsLoadingOverlay.tsx', - 'x-charts/src/ChartsLegend/LegendPerItem.tsx', 'x-charts/src/LineChart/CircleMarkElement.tsx', 'x-charts/src/BarChart/AnimatedBarElement.tsx', ].some((invalidPath) => filename.endsWith(invalidPath)); diff --git a/scripts/x-charts-pro.exports.json b/scripts/x-charts-pro.exports.json index 2404d9305ef6c..fcd6d9d961a59 100644 --- a/scripts/x-charts-pro.exports.json +++ b/scripts/x-charts-pro.exports.json @@ -82,11 +82,11 @@ { "name": "ChartsGridProps", "kind": "Interface" }, { "name": "ChartsItemTooltipContent", "kind": "Function" }, { "name": "ChartsItemTooltipContentProps", "kind": "Interface" }, - { "name": "ChartsLegend", "kind": "Function" }, + { "name": "ChartsLegend", "kind": "Variable" }, { "name": "ChartsLegendClasses", "kind": "Interface" }, - { "name": "ChartsLegendClassKey", "kind": "TypeAlias" }, + { "name": "ChartsLegendPosition", "kind": "TypeAlias" }, { "name": "ChartsLegendProps", "kind": "Interface" }, - { "name": "ChartsLegendPropsBase", "kind": "TypeAlias" }, + { "name": "ChartsLegendSlotExtension", "kind": "Interface" }, { "name": "ChartsLegendSlotProps", "kind": "Interface" }, { "name": "ChartsLegendSlots", "kind": "Interface" }, { "name": "ChartsOnAxisClickHandler", "kind": "Function" }, @@ -121,15 +121,18 @@ { "name": "cheerfulFiestaPalette", "kind": "Variable" }, { "name": "cheerfulFiestaPaletteDark", "kind": "Variable" }, { "name": "cheerfulFiestaPaletteLight", "kind": "Variable" }, + { "name": "ColorLegendSelector", "kind": "Interface" }, { "name": "ComputedPieRadius", "kind": "Interface" }, - { "name": "ContinuousColorLegend", "kind": "Function" }, + { "name": "ContinuousColorLegend", "kind": "Variable" }, + { "name": "continuousColorLegendClasses", "kind": "Variable" }, + { "name": "ContinuousColorLegendClasses", "kind": "Interface" }, { "name": "ContinuousColorLegendProps", "kind": "Interface" }, { "name": "ContinuousScaleName", "kind": "TypeAlias" }, { "name": "CurveType", "kind": "TypeAlias" }, + { "name": "DEFAULT_LEGEND_FACING_MARGIN", "kind": "Variable" }, { "name": "DEFAULT_MARGINS", "kind": "Variable" }, { "name": "DEFAULT_X_AXIS_KEY", "kind": "Variable" }, { "name": "DEFAULT_Y_AXIS_KEY", "kind": "Variable" }, - { "name": "DefaultChartsLegend", "kind": "Function" }, { "name": "DefaultizedBarSeriesType", "kind": "Interface" }, { "name": "DefaultizedCartesianSeriesType", "kind": "TypeAlias" }, { "name": "DefaultizedLineSeriesType", "kind": "Interface" }, @@ -137,6 +140,7 @@ { "name": "DefaultizedPieValueType", "kind": "TypeAlias" }, { "name": "DefaultizedScatterSeriesType", "kind": "Interface" }, { "name": "DefaultizedSeriesType", "kind": "TypeAlias" }, + { "name": "Direction", "kind": "TypeAlias" }, { "name": "FadeOptions", "kind": "TypeAlias" }, { "name": "Gauge", "kind": "Variable" }, { "name": "gaugeClasses", "kind": "Variable" }, @@ -160,14 +164,12 @@ { "name": "getGaugeUtilityClass", "kind": "Function" }, { "name": "getHeatmapUtilityClass", "kind": "Function" }, { "name": "getHighlightElementUtilityClass", "kind": "Function" }, - { "name": "getLegendUtilityClass", "kind": "Function" }, { "name": "getLineElementUtilityClass", "kind": "Function" }, { "name": "getMarkElementUtilityClass", "kind": "Function" }, { "name": "getPieArcLabelUtilityClass", "kind": "Function" }, { "name": "getPieArcUtilityClass", "kind": "Function" }, { "name": "getPieCoordinates", "kind": "Function" }, { "name": "getReferenceLineUtilityClass", "kind": "Function" }, - { "name": "getSeriesToDisplay", "kind": "Function" }, { "name": "getValueToPositionMapper", "kind": "Function" }, { "name": "Heatmap", "kind": "Variable" }, { "name": "heatmapClasses", "kind": "Variable" }, @@ -189,7 +191,9 @@ { "name": "ItemHighlightedState", "kind": "TypeAlias" }, { "name": "LayoutConfig", "kind": "TypeAlias" }, { "name": "legendClasses", "kind": "Variable" }, - { "name": "LegendRendererProps", "kind": "Interface" }, + { "name": "LegendItemContext", "kind": "TypeAlias" }, + { "name": "LegendItemParams", "kind": "Interface" }, + { "name": "LegendPosition", "kind": "TypeAlias" }, { "name": "LineChart", "kind": "Variable" }, { "name": "LineChartPro", "kind": "Variable" }, { "name": "LineChartProProps", "kind": "Interface" }, @@ -248,8 +252,13 @@ { "name": "PieArcPlotSlotProps", "kind": "Interface" }, { "name": "PieArcPlotSlots", "kind": "Interface" }, { "name": "PieArcProps", "kind": "TypeAlias" }, - { "name": "PiecewiseColorLegend", "kind": "Function" }, + { "name": "piecewiseColorDefaultLabelFormatter", "kind": "Function" }, + { "name": "PiecewiseColorLegend", "kind": "Variable" }, + { "name": "piecewiseColorLegendClasses", "kind": "Variable" }, + { "name": "PiecewiseColorLegendClasses", "kind": "Interface" }, + { "name": "PiecewiseColorLegendItemContext", "kind": "Interface" }, { "name": "PiecewiseColorLegendProps", "kind": "Interface" }, + { "name": "PiecewiseLabelFormatterParams", "kind": "TypeAlias" }, { "name": "PieChart", "kind": "Variable" }, { "name": "PieChartProps", "kind": "Interface" }, { "name": "PieChartSlotProps", "kind": "Interface" }, @@ -281,6 +290,7 @@ { "name": "ScatterSeriesType", "kind": "Interface" }, { "name": "ScatterValueType", "kind": "TypeAlias" }, { "name": "SeriesItemIdentifier", "kind": "TypeAlias" }, + { "name": "SeriesLegendItemContext", "kind": "Interface" }, { "name": "ShowMarkParams", "kind": "Interface" }, { "name": "SparkLineChart", "kind": "Variable" }, { "name": "SparkLineChartProps", "kind": "Interface" }, @@ -303,6 +313,7 @@ { "name": "useItemHighlighted", "kind": "Function" }, { "name": "useItemTooltip", "kind": "Function" }, { "name": "UseItemTooltipReturnValue", "kind": "Interface" }, + { "name": "useLegend", "kind": "Function" }, { "name": "useMouseTracker", "kind": "Function" }, { "name": "useSvgRef", "kind": "Function" }, { "name": "useXAxis", "kind": "Function" }, diff --git a/scripts/x-charts.exports.json b/scripts/x-charts.exports.json index 4081f5bdcb116..9ef2b3170bc35 100644 --- a/scripts/x-charts.exports.json +++ b/scripts/x-charts.exports.json @@ -80,11 +80,15 @@ { "name": "ChartsGridProps", "kind": "Interface" }, { "name": "ChartsItemTooltipContent", "kind": "Function" }, { "name": "ChartsItemTooltipContentProps", "kind": "Interface" }, - { "name": "ChartsLegend", "kind": "Function" }, + { "name": "ChartsLabelClasses", "kind": "Interface" }, + { "name": "ChartsLabelGradientClasses", "kind": "Interface" }, + { "name": "ChartsLabelMarkClasses", "kind": "Interface" }, + { "name": "ChartsLabelMarkProps", "kind": "Interface" }, + { "name": "ChartsLegend", "kind": "Variable" }, { "name": "ChartsLegendClasses", "kind": "Interface" }, - { "name": "ChartsLegendClassKey", "kind": "TypeAlias" }, + { "name": "ChartsLegendPosition", "kind": "TypeAlias" }, { "name": "ChartsLegendProps", "kind": "Interface" }, - { "name": "ChartsLegendPropsBase", "kind": "TypeAlias" }, + { "name": "ChartsLegendSlotExtension", "kind": "Interface" }, { "name": "ChartsLegendSlotProps", "kind": "Interface" }, { "name": "ChartsLegendSlots", "kind": "Interface" }, { "name": "ChartsOnAxisClickHandler", "kind": "Function" }, @@ -119,15 +123,18 @@ { "name": "cheerfulFiestaPalette", "kind": "Variable" }, { "name": "cheerfulFiestaPaletteDark", "kind": "Variable" }, { "name": "cheerfulFiestaPaletteLight", "kind": "Variable" }, + { "name": "ColorLegendSelector", "kind": "Interface" }, { "name": "ComputedPieRadius", "kind": "Interface" }, - { "name": "ContinuousColorLegend", "kind": "Function" }, + { "name": "ContinuousColorLegend", "kind": "Variable" }, + { "name": "continuousColorLegendClasses", "kind": "Variable" }, + { "name": "ContinuousColorLegendClasses", "kind": "Interface" }, { "name": "ContinuousColorLegendProps", "kind": "Interface" }, { "name": "ContinuousScaleName", "kind": "TypeAlias" }, { "name": "CurveType", "kind": "TypeAlias" }, + { "name": "DEFAULT_LEGEND_FACING_MARGIN", "kind": "Variable" }, { "name": "DEFAULT_MARGINS", "kind": "Variable" }, { "name": "DEFAULT_X_AXIS_KEY", "kind": "Variable" }, { "name": "DEFAULT_Y_AXIS_KEY", "kind": "Variable" }, - { "name": "DefaultChartsLegend", "kind": "Function" }, { "name": "DefaultizedBarSeriesType", "kind": "Interface" }, { "name": "DefaultizedCartesianSeriesType", "kind": "TypeAlias" }, { "name": "DefaultizedLineSeriesType", "kind": "Interface" }, @@ -135,6 +142,7 @@ { "name": "DefaultizedPieValueType", "kind": "TypeAlias" }, { "name": "DefaultizedScatterSeriesType", "kind": "Interface" }, { "name": "DefaultizedSeriesType", "kind": "TypeAlias" }, + { "name": "Direction", "kind": "TypeAlias" }, { "name": "FadeOptions", "kind": "TypeAlias" }, { "name": "Gauge", "kind": "Variable" }, { "name": "gaugeClasses", "kind": "Variable" }, @@ -157,14 +165,12 @@ { "name": "getChartsTooltipUtilityClass", "kind": "Function" }, { "name": "getGaugeUtilityClass", "kind": "Function" }, { "name": "getHighlightElementUtilityClass", "kind": "Function" }, - { "name": "getLegendUtilityClass", "kind": "Function" }, { "name": "getLineElementUtilityClass", "kind": "Function" }, { "name": "getMarkElementUtilityClass", "kind": "Function" }, { "name": "getPieArcLabelUtilityClass", "kind": "Function" }, { "name": "getPieArcUtilityClass", "kind": "Function" }, { "name": "getPieCoordinates", "kind": "Function" }, { "name": "getReferenceLineUtilityClass", "kind": "Function" }, - { "name": "getSeriesToDisplay", "kind": "Function" }, { "name": "getValueToPositionMapper", "kind": "Function" }, { "name": "HighlightedContext", "kind": "Variable" }, { "name": "HighlightedProvider", "kind": "Function" }, @@ -177,9 +183,14 @@ { "name": "isBarSeries", "kind": "Function" }, { "name": "isDefaultizedBarSeries", "kind": "Function" }, { "name": "ItemHighlightedState", "kind": "TypeAlias" }, + { "name": "labelClasses", "kind": "Variable" }, + { "name": "labelGradientClasses", "kind": "Variable" }, + { "name": "labelMarkClasses", "kind": "Variable" }, { "name": "LayoutConfig", "kind": "TypeAlias" }, { "name": "legendClasses", "kind": "Variable" }, - { "name": "LegendRendererProps", "kind": "Interface" }, + { "name": "LegendItemContext", "kind": "TypeAlias" }, + { "name": "LegendItemParams", "kind": "Interface" }, + { "name": "LegendPosition", "kind": "TypeAlias" }, { "name": "LineChart", "kind": "Variable" }, { "name": "LineChartProps", "kind": "Interface" }, { "name": "LineChartSlotProps", "kind": "Interface" }, @@ -236,8 +247,13 @@ { "name": "PieArcPlotSlotProps", "kind": "Interface" }, { "name": "PieArcPlotSlots", "kind": "Interface" }, { "name": "PieArcProps", "kind": "TypeAlias" }, - { "name": "PiecewiseColorLegend", "kind": "Function" }, + { "name": "piecewiseColorDefaultLabelFormatter", "kind": "Function" }, + { "name": "PiecewiseColorLegend", "kind": "Variable" }, + { "name": "piecewiseColorLegendClasses", "kind": "Variable" }, + { "name": "PiecewiseColorLegendClasses", "kind": "Interface" }, + { "name": "PiecewiseColorLegendItemContext", "kind": "Interface" }, { "name": "PiecewiseColorLegendProps", "kind": "Interface" }, + { "name": "PiecewiseLabelFormatterParams", "kind": "TypeAlias" }, { "name": "PieChart", "kind": "Variable" }, { "name": "PieChartProps", "kind": "Interface" }, { "name": "PieChartSlotProps", "kind": "Interface" }, @@ -267,6 +283,7 @@ { "name": "ScatterSeriesType", "kind": "Interface" }, { "name": "ScatterValueType", "kind": "TypeAlias" }, { "name": "SeriesItemIdentifier", "kind": "TypeAlias" }, + { "name": "SeriesLegendItemContext", "kind": "Interface" }, { "name": "ShowMarkParams", "kind": "Interface" }, { "name": "SparkLineChart", "kind": "Variable" }, { "name": "SparkLineChartProps", "kind": "Interface" }, @@ -289,6 +306,7 @@ { "name": "useItemHighlighted", "kind": "Function" }, { "name": "useItemTooltip", "kind": "Function" }, { "name": "UseItemTooltipReturnValue", "kind": "Interface" }, + { "name": "useLegend", "kind": "Function" }, { "name": "useMouseTracker", "kind": "Function" }, { "name": "useSvgRef", "kind": "Function" }, { "name": "useXAxis", "kind": "Function" }, From 068ab7854166cfa6faac2e85ce4d7d130d873338 Mon Sep 17 00:00:00 2001 From: Andrew Cherniavskii Date: Wed, 8 Jan 2025 21:52:57 +0100 Subject: [PATCH 21/25] [DataGridPremium] Improve aggregation performance for multiple columns (#16097) --- .../aggregation/createAggregationLookup.ts | 113 ++++++++---------- .../aggregation/gridAggregationUtils.ts | 20 ++-- .../aggregation/useGridAggregation.ts | 10 +- .../useGridAggregationPreProcessors.tsx | 20 ++-- 4 files changed, 75 insertions(+), 88 deletions(-) diff --git a/packages/x-data-grid-premium/src/hooks/features/aggregation/createAggregationLookup.ts b/packages/x-data-grid-premium/src/hooks/features/aggregation/createAggregationLookup.ts index 0e91f89ecee6a..4294bf38db5ca 100644 --- a/packages/x-data-grid-premium/src/hooks/features/aggregation/createAggregationLookup.ts +++ b/packages/x-data-grid-premium/src/hooks/features/aggregation/createAggregationLookup.ts @@ -19,23 +19,20 @@ import { import { getAggregationRules } from './gridAggregationUtils'; import { gridAggregationModelSelector } from './gridAggregationSelectors'; -const getAggregationCellValue = ({ - apiRef, - groupId, - field, - aggregationFunction, - aggregationRowsScope, -}: { - apiRef: React.MutableRefObject; - groupId: GridRowId; - field: string; - aggregationFunction: GridAggregationFunction; - aggregationRowsScope: DataGridPremiumProcessedProps['aggregationRowsScope']; -}) => { +const getGroupAggregatedValue = ( + groupId: GridRowId, + apiRef: React.MutableRefObject, + aggregationRowsScope: DataGridPremiumProcessedProps['aggregationRowsScope'], + aggregatedFields: string[], + aggregationRules: GridAggregationRules, + position: GridAggregationPosition, +) => { + const groupAggregationLookup: GridAggregationLookup[GridRowId] = {}; + const aggregatedValues: { aggregatedField: string; values: any[] }[] = []; + + const rowIds = apiRef.current.getRowGroupChildren({ groupId }); const filteredRowsLookup = gridFilteredRowsLookupSelector(apiRef); - const rowIds: GridRowId[] = apiRef.current.getRowGroupChildren({ groupId }); - const values: any[] = []; rowIds.forEach((rowId) => { if (aggregationRowsScope === 'filtered' && filteredRowsLookup[rowId] === false) { return; @@ -53,51 +50,43 @@ const getAggregationCellValue = ({ return; } - if (typeof aggregationFunction.getCellValue === 'function') { - const row = apiRef.current.getRow(rowId); - values.push(aggregationFunction.getCellValue({ row })); - } else { - values.push(apiRef.current.getCellValue(rowId, field)); - } - }); + const row = apiRef.current.getRow(rowId); - return aggregationFunction.apply({ - values, - groupId, - field, // Added per user request in https://github.com/mui/mui-x/issues/6995#issuecomment-1327423455 - }); -}; + for (let j = 0; j < aggregatedFields.length; j += 1) { + const aggregatedField = aggregatedFields[j]; + const columnAggregationRules = aggregationRules[aggregatedField]; -const getGroupAggregatedValue = ({ - groupId, - apiRef, - aggregationRowsScope, - aggregatedFields, - aggregationRules, - position, -}: { - groupId: GridRowId; - apiRef: React.MutableRefObject; - aggregationRowsScope: DataGridPremiumProcessedProps['aggregationRowsScope']; - aggregatedFields: string[]; - aggregationRules: GridAggregationRules; - position: GridAggregationPosition; -}) => { - const groupAggregationLookup: GridAggregationLookup[GridRowId] = {}; + const aggregationFunction = columnAggregationRules.aggregationFunction; + const field = aggregatedField; - for (let j = 0; j < aggregatedFields.length; j += 1) { - const aggregatedField = aggregatedFields[j]; - const columnAggregationRules = aggregationRules[aggregatedField]; + if (aggregatedValues[j] === undefined) { + aggregatedValues[j] = { + aggregatedField, + values: [], + }; + } + + if (typeof aggregationFunction.getCellValue === 'function') { + aggregatedValues[j].values.push(aggregationFunction.getCellValue({ row })); + } else { + const colDef = apiRef.current.getColumn(field); + aggregatedValues[j].values.push(apiRef.current.getRowValue(row, colDef)); + } + } + }); + + for (let i = 0; i < aggregatedValues.length; i += 1) { + const { aggregatedField, values } = aggregatedValues[i]; + const aggregationFunction = aggregationRules[aggregatedField].aggregationFunction; + const value = aggregationFunction.apply({ + values, + groupId, + field: aggregatedField, // Added per user request in https://github.com/mui/mui-x/issues/6995#issuecomment-1327423455 + }); groupAggregationLookup[aggregatedField] = { position, - value: getAggregationCellValue({ - apiRef, - groupId, - field: aggregatedField, - aggregationFunction: columnAggregationRules.aggregationFunction, - aggregationRowsScope, - }), + value, }; } @@ -115,11 +104,11 @@ export const createAggregationLookup = ({ aggregationRowsScope: DataGridPremiumProcessedProps['aggregationRowsScope']; getAggregationPosition: DataGridPremiumProcessedProps['getAggregationPosition']; }): GridAggregationLookup => { - const aggregationRules = getAggregationRules({ - columnsLookup: gridColumnLookupSelector(apiRef), - aggregationModel: gridAggregationModelSelector(apiRef), + const aggregationRules = getAggregationRules( + gridColumnLookupSelector(apiRef), + gridAggregationModelSelector(apiRef), aggregationFunctions, - }); + ); const aggregatedFields = Object.keys(aggregationRules); if (aggregatedFields.length === 0) { @@ -143,14 +132,14 @@ export const createAggregationLookup = ({ if (hasAggregableChildren) { const position = getAggregationPosition(groupNode); if (position != null) { - aggregationLookup[groupNode.id] = getGroupAggregatedValue({ - groupId: groupNode.id, + aggregationLookup[groupNode.id] = getGroupAggregatedValue( + groupNode.id, apiRef, - aggregatedFields, aggregationRowsScope, + aggregatedFields, aggregationRules, position, - }); + ); } } }; diff --git a/packages/x-data-grid-premium/src/hooks/features/aggregation/gridAggregationUtils.ts b/packages/x-data-grid-premium/src/hooks/features/aggregation/gridAggregationUtils.ts index 0f15aa74136b4..c84aae5d5e30b 100644 --- a/packages/x-data-grid-premium/src/hooks/features/aggregation/gridAggregationUtils.ts +++ b/packages/x-data-grid-premium/src/hooks/features/aggregation/gridAggregationUtils.ts @@ -86,18 +86,16 @@ export const mergeStateWithAggregationModel = aggregation: { ...state.aggregation, model: aggregationModel }, }); -export const getAggregationRules = ({ - columnsLookup, - aggregationModel, - aggregationFunctions, -}: { - columnsLookup: GridColumnRawLookup; - aggregationModel: GridAggregationModel; - aggregationFunctions: Record; -}) => { +export const getAggregationRules = ( + columnsLookup: GridColumnRawLookup, + aggregationModel: GridAggregationModel, + aggregationFunctions: Record, +) => { const aggregationRules: GridAggregationRules = {}; - Object.entries(aggregationModel).forEach(([field, columnItem]) => { + // eslint-disable-next-line guard-for-in + for (const field in aggregationModel) { + const columnItem = aggregationModel[field]; if ( columnsLookup[field] && canColumnHaveAggregationFunction({ @@ -111,7 +109,7 @@ export const getAggregationRules = ({ aggregationFunction: aggregationFunctions[columnItem], }; } - }); + } return aggregationRules; }; diff --git a/packages/x-data-grid-premium/src/hooks/features/aggregation/useGridAggregation.ts b/packages/x-data-grid-premium/src/hooks/features/aggregation/useGridAggregation.ts index 2a9e12601509a..8b41493cc2b96 100644 --- a/packages/x-data-grid-premium/src/hooks/features/aggregation/useGridAggregation.ts +++ b/packages/x-data-grid-premium/src/hooks/features/aggregation/useGridAggregation.ts @@ -103,11 +103,11 @@ export const useGridAggregation = ( const aggregationRules = props.disableAggregation ? {} - : getAggregationRules({ - columnsLookup: gridColumnLookupSelector(apiRef), - aggregationModel: gridAggregationModelSelector(apiRef), - aggregationFunctions: props.aggregationFunctions, - }); + : getAggregationRules( + gridColumnLookupSelector(apiRef), + gridAggregationModelSelector(apiRef), + props.aggregationFunctions, + ); // Re-apply the row hydration to add / remove the aggregation footers if (!areAggregationRulesEqual(rulesOnLastRowHydration, aggregationRules)) { diff --git a/packages/x-data-grid-premium/src/hooks/features/aggregation/useGridAggregationPreProcessors.tsx b/packages/x-data-grid-premium/src/hooks/features/aggregation/useGridAggregationPreProcessors.tsx index b0f1ab6933ae0..5ae196fb91ce1 100644 --- a/packages/x-data-grid-premium/src/hooks/features/aggregation/useGridAggregationPreProcessors.tsx +++ b/packages/x-data-grid-premium/src/hooks/features/aggregation/useGridAggregationPreProcessors.tsx @@ -36,11 +36,11 @@ export const useGridAggregationPreProcessors = ( (columnsState) => { const aggregationRules = props.disableAggregation ? {} - : getAggregationRules({ - columnsLookup: columnsState.lookup, - aggregationModel: gridAggregationModelSelector(apiRef), - aggregationFunctions: props.aggregationFunctions, - }); + : getAggregationRules( + columnsState.lookup, + gridAggregationModelSelector(apiRef), + props.aggregationFunctions, + ); columnsState.orderedFields.forEach((field) => { const shouldHaveAggregationValue = !!aggregationRules[field]; @@ -76,11 +76,11 @@ export const useGridAggregationPreProcessors = ( (value) => { const aggregationRules = props.disableAggregation ? {} - : getAggregationRules({ - columnsLookup: gridColumnLookupSelector(apiRef), - aggregationModel: gridAggregationModelSelector(apiRef), - aggregationFunctions: props.aggregationFunctions, - }); + : getAggregationRules( + gridColumnLookupSelector(apiRef), + gridAggregationModelSelector(apiRef), + props.aggregationFunctions, + ); const hasAggregationRule = Object.keys(aggregationRules).length > 0; From 3b0bba2453c8b7a052b2e434260a2f8d911f8c62 Mon Sep 17 00:00:00 2001 From: Rom Grk Date: Thu, 9 Jan 2025 04:18:25 -0500 Subject: [PATCH 22/25] [core] Update argos screenshots (#16111) From 296a499c56404f7a35e0699865a694170be0842d Mon Sep 17 00:00:00 2001 From: Bilal Shafi Date: Thu, 9 Jan 2025 17:13:03 +0500 Subject: [PATCH 23/25] [DataGridPremium] Server-side aggregation with data source (#15741) Co-authored-by: Armin Mehinovic <4390250+arminmeh@users.noreply.github.com> --- .../data/data-grid/aggregation/aggregation.md | 4 + .../ServerSideDataGridAggregation.js | 70 ++++++++ .../ServerSideDataGridAggregation.tsx | 70 ++++++++ .../ServerSideDataGridAggregation.tsx.preview | 8 + ...erverSideDataGridAggregationLazyLoading.js | 71 ++++++++ ...rverSideDataGridAggregationLazyLoading.tsx | 71 ++++++++ ...DataGridAggregationLazyLoading.tsx.preview | 7 + ...erverSideDataGridAggregationRowGrouping.js | 76 +++++++++ ...rverSideDataGridAggregationRowGrouping.tsx | 77 +++++++++ ...DataGridAggregationRowGrouping.tsx.preview | 7 + .../ServerSideDataGridAggregationTreeData.js | 75 +++++++++ .../ServerSideDataGridAggregationTreeData.tsx | 80 +++++++++ ...ideDataGridAggregationTreeData.tsx.preview | 8 + .../data-grid/server-side-data/aggregation.md | 99 ++++++++++- docs/data/pages.ts | 6 +- .../x/api/data-grid/data-grid-premium.json | 2 +- .../grid-aggregation-function-data-source.js | 26 +++ ...grid-aggregation-function-data-source.json | 19 +++ docs/pages/x/api/data-grid/index.md | 1 + docs/scripts/createXTypeScriptProjects.ts | 1 + ...grid-aggregation-function-data-source.json | 17 ++ .../data-grid/grid-aggregation-function.json | 6 +- .../src/hooks/serverUtils.ts | 118 ++++++++++++- .../src/hooks/useMockServer.ts | 17 +- .../src/DataGridPremium/DataGridPremium.tsx | 3 +- .../useDataGridPremiumComponent.tsx | 4 +- .../useDataGridPremiumProps.ts | 1 + .../GridColumnMenuAggregationItem.tsx | 6 +- .../aggregation/createAggregationLookup.ts | 55 ++++-- .../aggregation/gridAggregationInterfaces.ts | 25 ++- .../aggregation/gridAggregationUtils.ts | 29 +++- .../src/hooks/features/aggregation/index.ts | 18 +- .../aggregation/useGridAggregation.ts | 45 ++++- .../useGridAggregationPreProcessors.tsx | 22 ++- .../src/hooks/features/dataSource/cache.ts | 13 ++ .../src/hooks/features/dataSource/models.ts | 63 +++++++ .../dataSource/useGridDataSourcePremium.tsx | 102 ++++++++++++ packages/x-data-grid-premium/src/index.ts | 11 ++ .../src/models/dataGridPremiumProps.ts | 14 +- .../src/models/gridApiPremium.ts | 12 +- ...SourceAggregation.DataGridPremium.test.tsx | 157 ++++++++++++++++++ .../DataGridPro/useDataGridProComponent.tsx | 6 +- .../src/hooks/features/dataSource/cache.ts | 20 ++- .../hooks/features/dataSource/interfaces.ts | 4 +- ...DataSource.ts => useGridDataSourceBase.ts} | 68 ++++---- .../dataSource/useGridDataSourcePro.ts | 31 ++++ .../src/hooks/features/dataSource/utils.ts | 3 +- .../src/hooks/features/index.ts | 2 +- .../useGridDataSourceLazyLoader.ts | 5 + packages/x-data-grid-pro/src/index.ts | 14 ++ .../x-data-grid-pro/src/internals/index.ts | 4 +- .../x-data-grid-pro/src/models/gridApiPro.ts | 4 +- packages/x-data-grid-pro/src/models/index.ts | 6 - .../src/tests/dataSource.DataGridPro.test.tsx | 6 +- .../pipeProcessing/gridPipeProcessingApi.ts | 7 +- packages/x-data-grid/src/internals/index.ts | 5 +- scripts/x-data-grid-premium.exports.json | 1 + 57 files changed, 1579 insertions(+), 123 deletions(-) create mode 100644 docs/data/data-grid/server-side-data/ServerSideDataGridAggregation.js create mode 100644 docs/data/data-grid/server-side-data/ServerSideDataGridAggregation.tsx create mode 100644 docs/data/data-grid/server-side-data/ServerSideDataGridAggregation.tsx.preview create mode 100644 docs/data/data-grid/server-side-data/ServerSideDataGridAggregationLazyLoading.js create mode 100644 docs/data/data-grid/server-side-data/ServerSideDataGridAggregationLazyLoading.tsx create mode 100644 docs/data/data-grid/server-side-data/ServerSideDataGridAggregationLazyLoading.tsx.preview create mode 100644 docs/data/data-grid/server-side-data/ServerSideDataGridAggregationRowGrouping.js create mode 100644 docs/data/data-grid/server-side-data/ServerSideDataGridAggregationRowGrouping.tsx create mode 100644 docs/data/data-grid/server-side-data/ServerSideDataGridAggregationRowGrouping.tsx.preview create mode 100644 docs/data/data-grid/server-side-data/ServerSideDataGridAggregationTreeData.js create mode 100644 docs/data/data-grid/server-side-data/ServerSideDataGridAggregationTreeData.tsx create mode 100644 docs/data/data-grid/server-side-data/ServerSideDataGridAggregationTreeData.tsx.preview create mode 100644 docs/pages/x/api/data-grid/grid-aggregation-function-data-source.js create mode 100644 docs/pages/x/api/data-grid/grid-aggregation-function-data-source.json create mode 100644 docs/translations/api-docs/data-grid/grid-aggregation-function-data-source.json create mode 100644 packages/x-data-grid-premium/src/hooks/features/dataSource/cache.ts create mode 100644 packages/x-data-grid-premium/src/hooks/features/dataSource/models.ts create mode 100644 packages/x-data-grid-premium/src/hooks/features/dataSource/useGridDataSourcePremium.tsx create mode 100644 packages/x-data-grid-premium/src/tests/dataSourceAggregation.DataGridPremium.test.tsx rename packages/x-data-grid-pro/src/hooks/features/dataSource/{useGridDataSource.ts => useGridDataSourceBase.ts} (90%) create mode 100644 packages/x-data-grid-pro/src/hooks/features/dataSource/useGridDataSourcePro.ts diff --git a/docs/data/data-grid/aggregation/aggregation.md b/docs/data/data-grid/aggregation/aggregation.md index 0dad0c32852c2..0f9b5de14250b 100644 --- a/docs/data/data-grid/aggregation/aggregation.md +++ b/docs/data/data-grid/aggregation/aggregation.md @@ -12,6 +12,10 @@ The aggregated values are rendered in a footer row at the bottom of the Data Gri {{"demo": "AggregationInitialState.js", "bg": "inline", "defaultCodeOpen": false}} +:::info +If you're looking for aggregation on the server side, see [Server-side data—Aggregation](/x/react-data-grid/server-side-data/aggregation/). +::: + ## Pass aggregation to the Data Grid ### Structure of the model diff --git a/docs/data/data-grid/server-side-data/ServerSideDataGridAggregation.js b/docs/data/data-grid/server-side-data/ServerSideDataGridAggregation.js new file mode 100644 index 0000000000000..abeb33447b124 --- /dev/null +++ b/docs/data/data-grid/server-side-data/ServerSideDataGridAggregation.js @@ -0,0 +1,70 @@ +import * as React from 'react'; +import { DataGridPremium } from '@mui/x-data-grid-premium'; +import { useMockServer } from '@mui/x-data-grid-generator'; + +const aggregationFunctions = { + sum: { columnTypes: ['number'] }, + avg: { columnTypes: ['number'] }, + min: { columnTypes: ['number', 'date', 'dateTime'] }, + max: { columnTypes: ['number', 'date', 'dateTime'] }, + size: {}, +}; + +export default function ServerSideDataGridAggregation() { + const { columns, initialState, fetchRows } = useMockServer( + {}, + { useCursorPagination: false }, + ); + + const dataSource = React.useMemo( + () => ({ + getRows: async (params) => { + const urlParams = new URLSearchParams({ + paginationModel: JSON.stringify(params.paginationModel), + filterModel: JSON.stringify(params.filterModel), + sortModel: JSON.stringify(params.sortModel), + aggregationModel: JSON.stringify(params.aggregationModel), + }); + const getRowsResponse = await fetchRows( + `https://mui.com/x/api/data-grid?${urlParams.toString()}`, + ); + return { + rows: getRowsResponse.rows, + rowCount: getRowsResponse.rowCount, + aggregateRow: getRowsResponse.aggregateRow, + }; + }, + getAggregatedValue: (row, field) => { + return row[`${field}Aggregate`]; + }, + }), + [fetchRows], + ); + + const initialStateWithPagination = React.useMemo( + () => ({ + ...initialState, + pagination: { + paginationModel: { pageSize: 10, page: 0 }, + rowCount: 0, + }, + aggregation: { + model: { commodity: 'size', quantity: 'sum' }, + }, + }), + [initialState], + ); + + return ( +

    + +
    + ); +} diff --git a/docs/data/data-grid/server-side-data/ServerSideDataGridAggregation.tsx b/docs/data/data-grid/server-side-data/ServerSideDataGridAggregation.tsx new file mode 100644 index 0000000000000..c24b761cb58a9 --- /dev/null +++ b/docs/data/data-grid/server-side-data/ServerSideDataGridAggregation.tsx @@ -0,0 +1,70 @@ +import * as React from 'react'; +import { DataGridPremium, GridDataSource } from '@mui/x-data-grid-premium'; +import { useMockServer } from '@mui/x-data-grid-generator'; + +const aggregationFunctions = { + sum: { columnTypes: ['number'] }, + avg: { columnTypes: ['number'] }, + min: { columnTypes: ['number', 'date', 'dateTime'] }, + max: { columnTypes: ['number', 'date', 'dateTime'] }, + size: {}, +}; + +export default function ServerSideDataGridAggregation() { + const { columns, initialState, fetchRows } = useMockServer( + {}, + { useCursorPagination: false }, + ); + + const dataSource: GridDataSource = React.useMemo( + () => ({ + getRows: async (params) => { + const urlParams = new URLSearchParams({ + paginationModel: JSON.stringify(params.paginationModel), + filterModel: JSON.stringify(params.filterModel), + sortModel: JSON.stringify(params.sortModel), + aggregationModel: JSON.stringify(params.aggregationModel), + }); + const getRowsResponse = await fetchRows( + `https://mui.com/x/api/data-grid?${urlParams.toString()}`, + ); + return { + rows: getRowsResponse.rows, + rowCount: getRowsResponse.rowCount, + aggregateRow: getRowsResponse.aggregateRow, + }; + }, + getAggregatedValue: (row, field) => { + return row[`${field}Aggregate`]; + }, + }), + [fetchRows], + ); + + const initialStateWithPagination = React.useMemo( + () => ({ + ...initialState, + pagination: { + paginationModel: { pageSize: 10, page: 0 }, + rowCount: 0, + }, + aggregation: { + model: { commodity: 'size', quantity: 'sum' }, + }, + }), + [initialState], + ); + + return ( +
    + +
    + ); +} diff --git a/docs/data/data-grid/server-side-data/ServerSideDataGridAggregation.tsx.preview b/docs/data/data-grid/server-side-data/ServerSideDataGridAggregation.tsx.preview new file mode 100644 index 0000000000000..aee05887a7c35 --- /dev/null +++ b/docs/data/data-grid/server-side-data/ServerSideDataGridAggregation.tsx.preview @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationLazyLoading.js b/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationLazyLoading.js new file mode 100644 index 0000000000000..0b7c242658a8b --- /dev/null +++ b/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationLazyLoading.js @@ -0,0 +1,71 @@ +import * as React from 'react'; +import { DataGridPremium } from '@mui/x-data-grid-premium'; +import { useMockServer } from '@mui/x-data-grid-generator'; + +const aggregationFunctions = { + sum: { columnTypes: ['number'] }, + avg: { columnTypes: ['number'] }, + min: { columnTypes: ['number', 'date', 'dateTime'] }, + max: { columnTypes: ['number', 'date', 'dateTime'] }, + size: {}, +}; + +export default function ServerSideDataGridAggregationLazyLoading() { + const { + columns, + initialState: initState, + fetchRows, + } = useMockServer({}, { useCursorPagination: false }); + + const dataSource = React.useMemo( + () => ({ + getRows: async (params) => { + const urlParams = new URLSearchParams({ + filterModel: JSON.stringify(params.filterModel), + sortModel: JSON.stringify(params.sortModel), + aggregationModel: JSON.stringify(params.aggregationModel), + start: `${params.start}`, + end: `${params.end}`, + }); + const getRowsResponse = await fetchRows( + `https://mui.com/x/api/data-grid?${urlParams.toString()}`, + ); + return { + rows: getRowsResponse.rows, + rowCount: getRowsResponse.rowCount, + aggregateRow: getRowsResponse.aggregateRow, + }; + }, + getAggregatedValue: (row, field) => { + return row[`${field}Aggregate`]; + }, + }), + [fetchRows], + ); + + const initialState = React.useMemo( + () => ({ + ...initState, + pagination: { + paginationModel: { pageSize: 10, page: 0 }, + rowCount: 0, + }, + aggregation: { + model: { commodity: 'size', quantity: 'sum' }, + }, + }), + [initState], + ); + + return ( +
    + +
    + ); +} diff --git a/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationLazyLoading.tsx b/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationLazyLoading.tsx new file mode 100644 index 0000000000000..eaeda275e5281 --- /dev/null +++ b/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationLazyLoading.tsx @@ -0,0 +1,71 @@ +import * as React from 'react'; +import { DataGridPremium, GridDataSource } from '@mui/x-data-grid-premium'; +import { useMockServer } from '@mui/x-data-grid-generator'; + +const aggregationFunctions = { + sum: { columnTypes: ['number'] }, + avg: { columnTypes: ['number'] }, + min: { columnTypes: ['number', 'date', 'dateTime'] }, + max: { columnTypes: ['number', 'date', 'dateTime'] }, + size: {}, +}; + +export default function ServerSideDataGridAggregationLazyLoading() { + const { + columns, + initialState: initState, + fetchRows, + } = useMockServer({}, { useCursorPagination: false }); + + const dataSource: GridDataSource = React.useMemo( + () => ({ + getRows: async (params) => { + const urlParams = new URLSearchParams({ + filterModel: JSON.stringify(params.filterModel), + sortModel: JSON.stringify(params.sortModel), + aggregationModel: JSON.stringify(params.aggregationModel), + start: `${params.start}`, + end: `${params.end}`, + }); + const getRowsResponse = await fetchRows( + `https://mui.com/x/api/data-grid?${urlParams.toString()}`, + ); + return { + rows: getRowsResponse.rows, + rowCount: getRowsResponse.rowCount, + aggregateRow: getRowsResponse.aggregateRow, + }; + }, + getAggregatedValue: (row, field) => { + return row[`${field}Aggregate`]; + }, + }), + [fetchRows], + ); + + const initialState = React.useMemo( + () => ({ + ...initState, + pagination: { + paginationModel: { pageSize: 10, page: 0 }, + rowCount: 0, + }, + aggregation: { + model: { commodity: 'size', quantity: 'sum' }, + }, + }), + [initState], + ); + + return ( +
    + +
    + ); +} diff --git a/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationLazyLoading.tsx.preview b/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationLazyLoading.tsx.preview new file mode 100644 index 0000000000000..1856db25a89aa --- /dev/null +++ b/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationLazyLoading.tsx.preview @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationRowGrouping.js b/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationRowGrouping.js new file mode 100644 index 0000000000000..a2467cefcc01a --- /dev/null +++ b/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationRowGrouping.js @@ -0,0 +1,76 @@ +import * as React from 'react'; +import { + DataGridPremium, + useKeepGroupedColumnsHidden, + useGridApiRef, +} from '@mui/x-data-grid-premium'; +import { useMockServer } from '@mui/x-data-grid-generator'; + +const aggregationFunctions = { + sum: { columnTypes: ['number'] }, + avg: { columnTypes: ['number'] }, + min: { columnTypes: ['number', 'date', 'dateTime'] }, + max: { columnTypes: ['number', 'date', 'dateTime'] }, + size: {}, +}; + +export default function ServerSideDataGridAggregationRowGrouping() { + const apiRef = useGridApiRef(); + const { + columns, + initialState: initState, + fetchRows, + } = useMockServer({ rowGrouping: true }); + + const dataSource = React.useMemo( + () => ({ + getRows: async (params) => { + const urlParams = new URLSearchParams({ + paginationModel: JSON.stringify(params.paginationModel), + filterModel: JSON.stringify(params.filterModel), + sortModel: JSON.stringify(params.sortModel), + groupKeys: JSON.stringify(params.groupKeys), + groupFields: JSON.stringify(params.groupFields), + aggregationModel: JSON.stringify(params.aggregationModel), + }); + const getRowsResponse = await fetchRows( + `https://mui.com/x/api/data-grid?${urlParams.toString()}`, + ); + return { + rows: getRowsResponse.rows, + rowCount: getRowsResponse.rowCount, + aggregateRow: getRowsResponse.aggregateRow, + }; + }, + getGroupKey: (row) => row.group, + getChildrenCount: (row) => row.descendantCount, + getAggregatedValue: (row, field) => row[`${field}Aggregate`], + }), + [fetchRows], + ); + + const initialState = useKeepGroupedColumnsHidden({ + apiRef, + initialState: { + ...initState, + rowGrouping: { + model: ['company', 'director'], + }, + aggregation: { + model: { title: 'size', gross: 'sum', year: 'max' }, + }, + }, + }); + + return ( +
    + +
    + ); +} diff --git a/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationRowGrouping.tsx b/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationRowGrouping.tsx new file mode 100644 index 0000000000000..afca284bd7259 --- /dev/null +++ b/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationRowGrouping.tsx @@ -0,0 +1,77 @@ +import * as React from 'react'; +import { + DataGridPremium, + useKeepGroupedColumnsHidden, + useGridApiRef, + GridDataSource, +} from '@mui/x-data-grid-premium'; +import { useMockServer } from '@mui/x-data-grid-generator'; + +const aggregationFunctions = { + sum: { columnTypes: ['number'] }, + avg: { columnTypes: ['number'] }, + min: { columnTypes: ['number', 'date', 'dateTime'] }, + max: { columnTypes: ['number', 'date', 'dateTime'] }, + size: {}, +}; + +export default function ServerSideDataGridAggregationRowGrouping() { + const apiRef = useGridApiRef(); + const { + columns, + initialState: initState, + fetchRows, + } = useMockServer({ rowGrouping: true }); + + const dataSource: GridDataSource = React.useMemo( + () => ({ + getRows: async (params) => { + const urlParams = new URLSearchParams({ + paginationModel: JSON.stringify(params.paginationModel), + filterModel: JSON.stringify(params.filterModel), + sortModel: JSON.stringify(params.sortModel), + groupKeys: JSON.stringify(params.groupKeys), + groupFields: JSON.stringify(params.groupFields), + aggregationModel: JSON.stringify(params.aggregationModel), + }); + const getRowsResponse = await fetchRows( + `https://mui.com/x/api/data-grid?${urlParams.toString()}`, + ); + return { + rows: getRowsResponse.rows, + rowCount: getRowsResponse.rowCount, + aggregateRow: getRowsResponse.aggregateRow, + }; + }, + getGroupKey: (row) => row.group, + getChildrenCount: (row) => row.descendantCount, + getAggregatedValue: (row, field) => row[`${field}Aggregate`], + }), + [fetchRows], + ); + + const initialState = useKeepGroupedColumnsHidden({ + apiRef, + initialState: { + ...initState, + rowGrouping: { + model: ['company', 'director'], + }, + aggregation: { + model: { title: 'size', gross: 'sum', year: 'max' }, + }, + }, + }); + + return ( +
    + +
    + ); +} diff --git a/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationRowGrouping.tsx.preview b/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationRowGrouping.tsx.preview new file mode 100644 index 0000000000000..b2d4bf7135a06 --- /dev/null +++ b/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationRowGrouping.tsx.preview @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationTreeData.js b/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationTreeData.js new file mode 100644 index 0000000000000..3834980e55020 --- /dev/null +++ b/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationTreeData.js @@ -0,0 +1,75 @@ +import * as React from 'react'; +import { DataGridPremium, useGridApiRef } from '@mui/x-data-grid-premium'; +import { useMockServer } from '@mui/x-data-grid-generator'; + +const dataSetOptions = { + dataSet: 'Employee', + rowLength: 1000, + treeData: { maxDepth: 3, groupingField: 'name', averageChildren: 5 }, +}; + +const aggregationFunctions = { + sum: { columnTypes: ['number'] }, + avg: { columnTypes: ['number'] }, + min: { columnTypes: ['number', 'date', 'dateTime'] }, + max: { columnTypes: ['number', 'date', 'dateTime'] }, + size: {}, +}; + +export default function ServerSideDataGridAggregationTreeData() { + const apiRef = useGridApiRef(); + const { + fetchRows, + columns, + initialState: initState, + } = useMockServer(dataSetOptions); + + const initialState = React.useMemo( + () => ({ + ...initState, + aggregation: { + model: { rating: 'avg', website: 'size' }, + }, + }), + [initState], + ); + + const dataSource = React.useMemo( + () => ({ + getRows: async (params) => { + const urlParams = new URLSearchParams({ + paginationModel: JSON.stringify(params.paginationModel), + filterModel: JSON.stringify(params.filterModel), + sortModel: JSON.stringify(params.sortModel), + groupKeys: JSON.stringify(params.groupKeys), + aggregationModel: JSON.stringify(params.aggregationModel), + }); + const getRowsResponse = await fetchRows( + `https://mui.com/x/api/data-grid?${urlParams.toString()}`, + ); + return { + rows: getRowsResponse.rows, + rowCount: getRowsResponse.rowCount, + aggregateRow: getRowsResponse.aggregateRow, + }; + }, + getGroupKey: (row) => row[dataSetOptions.treeData.groupingField], + getChildrenCount: (row) => row.descendantCount, + getAggregatedValue: (row, field) => row[`${field}Aggregate`], + }), + [fetchRows], + ); + + return ( +
    + +
    + ); +} diff --git a/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationTreeData.tsx b/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationTreeData.tsx new file mode 100644 index 0000000000000..cf55fabc541d5 --- /dev/null +++ b/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationTreeData.tsx @@ -0,0 +1,80 @@ +import * as React from 'react'; +import { + DataGridPremium, + useGridApiRef, + GridInitialState, + GridDataSource, +} from '@mui/x-data-grid-premium'; +import { useMockServer } from '@mui/x-data-grid-generator'; + +const dataSetOptions = { + dataSet: 'Employee' as const, + rowLength: 1000, + treeData: { maxDepth: 3, groupingField: 'name', averageChildren: 5 }, +}; + +const aggregationFunctions = { + sum: { columnTypes: ['number'] }, + avg: { columnTypes: ['number'] }, + min: { columnTypes: ['number', 'date', 'dateTime'] }, + max: { columnTypes: ['number', 'date', 'dateTime'] }, + size: {}, +}; + +export default function ServerSideDataGridAggregationTreeData() { + const apiRef = useGridApiRef(); + const { + fetchRows, + columns, + initialState: initState, + } = useMockServer(dataSetOptions); + + const initialState: GridInitialState = React.useMemo( + () => ({ + ...initState, + aggregation: { + model: { rating: 'avg', website: 'size' }, + }, + }), + [initState], + ); + + const dataSource: GridDataSource = React.useMemo( + () => ({ + getRows: async (params) => { + const urlParams = new URLSearchParams({ + paginationModel: JSON.stringify(params.paginationModel), + filterModel: JSON.stringify(params.filterModel), + sortModel: JSON.stringify(params.sortModel), + groupKeys: JSON.stringify(params.groupKeys), + aggregationModel: JSON.stringify(params.aggregationModel), + }); + const getRowsResponse = await fetchRows( + `https://mui.com/x/api/data-grid?${urlParams.toString()}`, + ); + return { + rows: getRowsResponse.rows, + rowCount: getRowsResponse.rowCount, + aggregateRow: getRowsResponse.aggregateRow, + }; + }, + getGroupKey: (row) => row[dataSetOptions.treeData.groupingField], + getChildrenCount: (row) => row.descendantCount, + getAggregatedValue: (row, field) => row[`${field}Aggregate`], + }), + [fetchRows], + ); + + return ( +
    + +
    + ); +} diff --git a/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationTreeData.tsx.preview b/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationTreeData.tsx.preview new file mode 100644 index 0000000000000..6eee2299964e8 --- /dev/null +++ b/docs/data/data-grid/server-side-data/ServerSideDataGridAggregationTreeData.tsx.preview @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/docs/data/data-grid/server-side-data/aggregation.md b/docs/data/data-grid/server-side-data/aggregation.md index e11485b7d80ce..7b94fbaf0e76d 100644 --- a/docs/data/data-grid/server-side-data/aggregation.md +++ b/docs/data/data-grid/server-side-data/aggregation.md @@ -2,14 +2,103 @@ title: React Data Grid - Server-side aggregation --- -# Data Grid - Server-side aggregation [](/x/introduction/licensing/#premium-plan 'Premium plan')🚧 +# Data Grid - Server-side aggregation [](/x/introduction/licensing/#premium-plan 'Premium plan')🧪

    Aggregation with server-side data source.

    -:::warning -This feature isn't implemented yet. It's coming. +To dynamically load tree data from the server, you must create a data source and pass the `unstable_dataSource` prop to the Data Grid, as detailed in the [Server-side data overview](/x/react-data-grid/server-side-data/). -👍 Upvote [issue #10860](https://github.com/mui/mui-x/issues/10860) if you want to see it land faster. +:::info +If you're looking for aggregation on the client side, see [Aggregation](/x/react-data-grid/aggregation/). +::: + +Server-side aggregation requires some additional steps to implement: + +1. Pass the available aggregation functions of type `GridAggregationFunctionDataSource` to the Data Grid using the `aggregationFunctions` prop. Its default value is empty when the Data Grid is used with server-side data. + + ```tsx + const aggregationFunctions: Record = { + size: { label: 'Size' }, + sum: { label: 'Sum', columnTypes: ['number'] }, + } + + + ``` + + The `GridAggregationFunctionDataSource` interface is similar to `GridAggregationFunction`, but it doesn't have `apply` or `getCellValue` properties because the computation is done on the server. + + See the [GridAggregationFunctionDataSource API page](/x/api/data-grid/grid-aggregation-function-data-source/) for more details. + +2. Use `aggregationModel` passed in the `getRows` method of `GridDataSource` to fetch the aggregated values. + For the root level footer aggregation row, pass `aggregateRow` containing the aggregated values in the `GetRowsResponse`. + + ```diff + const dataSource = { + getRows: async ({ + sortModel, + filterModel, + paginationModel, + + aggregationModel, + }) => { + const rows = await fetchRows(); + - const response = await fetchData({ sortModel, filterModel, paginationModel }); + + const response = await fetchData({ sortModel, filterModel, paginationModel, aggregationModel }); + return { + rows: response.rows, + rowCount: getRowsResponse.totalCount, + + aggregateRow: response.aggregateRow, + } + } + } + ``` + +3. Pass the getter method `getAggregatedValue` in `GridDataSource` that defines how to get the aggregated value for a parent row (including the `aggregateRow`). + + ```tsx + const dataSource = { + getRows: async ({ + ... + }) => { + ... + }, + getAggregatedValue: (row, field) => { + return row[`${field}Aggregate`]; + }, + } + ``` + +The following example demonstrates basic server-side aggregation. -Don't hesitate to leave a comment on the same issue to influence what gets built. Especially if you already have a use case for this component, or if you are facing a pain point with your current solution. +{{"demo": "ServerSideDataGridAggregation.js", "bg": "inline"}} + +:::info +The data source mock server (`useMockServer()`) mocks the built-in aggregation functions listed in the [built-in functions section](/x/react-data-grid/aggregation/#built-in-functions) of the client-side aggregation documentation. +Provide the function names and minimal configuration to demonstrate the aggregation, as shown in the demo. ::: + +## Usage with lazy loading + +Server-side aggregation can be implemented along with [server-side lazy loading](/x/react-data-grid/server-side-data/lazy-loading/) as shown in the demo below. + +{{"demo": "ServerSideDataGridAggregationLazyLoading.js", "bg": "inline"}} + +## Usage with row grouping + +Server-side aggregation works with row grouping in a similar way as described in [Aggregation—usage with row grouping](/x/react-data-grid/aggregation/#usage-with-row-grouping). +The aggregated values are acquired from the parent rows using the `getAggregatedValue` method. + +{{"demo": "ServerSideDataGridAggregationRowGrouping.js", "bg": "inline"}} + +## Usage with tree data + +Server-side aggregation can be used with tree data in a similar way as described in [Aggregation—usage with tree data](/x/react-data-grid/aggregation/#usage-with-tree-data). +The aggregated values are acquired from the parent rows using the `getAggregatedValue` method. + +{{"demo": "ServerSideDataGridAggregationTreeData.js", "bg": "inline"}} + +## API + +- [DataGrid](/x/api/data-grid/data-grid/) +- [DataGridPro](/x/api/data-grid/data-grid-pro/) +- [DataGridPremium](/x/api/data-grid/data-grid-premium/) +- [GridAggregationFunctionDataSource](/x/api/data-grid/grid-aggregation-function-data-source/) diff --git a/docs/data/pages.ts b/docs/data/pages.ts index e0d0eabaaf69a..bb8364631030c 100644 --- a/docs/data/pages.ts +++ b/docs/data/pages.ts @@ -164,7 +164,7 @@ const pages: MuiPage[] = [ { pathname: '/x/react-data-grid/server-side-data/aggregation', plan: 'premium', - planned: true, + unstable: true, }, ], }, @@ -234,6 +234,10 @@ const pages: MuiPage[] = [ pathname: '/x/api/data-grid/grid-aggregation-function', title: 'GridAggregationFunction', }, + { + pathname: '/x/api/data-grid/grid-aggregation-function-data-source', + title: 'GridAggregationFunctionDataSource', + }, { pathname: '/x/api/data-grid/grid-csv-export-options', title: 'GridCsvExportOptions', diff --git a/docs/pages/x/api/data-grid/data-grid-premium.json b/docs/pages/x/api/data-grid/data-grid-premium.json index 950b63871a3ce..a2c48c6a533db 100644 --- a/docs/pages/x/api/data-grid/data-grid-premium.json +++ b/docs/pages/x/api/data-grid/data-grid-premium.json @@ -6,7 +6,7 @@ }, "aggregationFunctions": { "type": { "name": "object" }, - "default": "GRID_AGGREGATION_FUNCTIONS" + "default": "GRID_AGGREGATION_FUNCTIONS when `unstable_dataSource` is not provided, `{}` when `unstable_dataSource` is provided" }, "aggregationModel": { "type": { "name": "object" } }, "aggregationRowsScope": { diff --git a/docs/pages/x/api/data-grid/grid-aggregation-function-data-source.js b/docs/pages/x/api/data-grid/grid-aggregation-function-data-source.js new file mode 100644 index 0000000000000..c78470ce999b9 --- /dev/null +++ b/docs/pages/x/api/data-grid/grid-aggregation-function-data-source.js @@ -0,0 +1,26 @@ +import * as React from 'react'; +import InterfaceApiPage from 'docsx/src/modules/components/InterfaceApiPage'; +import layoutConfig from 'docsx/src/modules/utils/dataGridLayoutConfig'; +import mapApiPageTranslations from 'docs/src/modules/utils/mapApiPageTranslations'; +import jsonPageContent from './grid-aggregation-function-data-source.json'; + +export default function Page(props) { + const { descriptions, pageContent } = props; + return ( + + ); +} + +Page.getInitialProps = () => { + const req = require.context( + 'docsx/translations/api-docs/data-grid/', + false, + /\.\/grid-aggregation-function-data-source.*.json$/, + ); + const descriptions = mapApiPageTranslations(req); + + return { + descriptions, + pageContent: jsonPageContent, + }; +}; diff --git a/docs/pages/x/api/data-grid/grid-aggregation-function-data-source.json b/docs/pages/x/api/data-grid/grid-aggregation-function-data-source.json new file mode 100644 index 0000000000000..75ba83bcced16 --- /dev/null +++ b/docs/pages/x/api/data-grid/grid-aggregation-function-data-source.json @@ -0,0 +1,19 @@ +{ + "name": "GridAggregationFunctionDataSource", + "imports": ["import { GridAggregationFunctionDataSource } from '@mui/x-data-grid-premium'"], + "demos": "", + "properties": { + "columnTypes": { "type": { "description": "string[]" }, "isPremiumPlan": true }, + "hasCellUnit": { + "type": { "description": "boolean" }, + "default": "true", + "isPremiumPlan": true + }, + "label": { + "type": { "description": "string" }, + "default": "apiRef.current.getLocaleText('aggregationFunctionLabel{capitalize(name)})", + "isPremiumPlan": true + }, + "valueFormatter": { "type": { "description": "GridValueFormatter" }, "isPremiumPlan": true } + } +} diff --git a/docs/pages/x/api/data-grid/index.md b/docs/pages/x/api/data-grid/index.md index 59c68e9a9b1fe..b8b5142ec3fc5 100644 --- a/docs/pages/x/api/data-grid/index.md +++ b/docs/pages/x/api/data-grid/index.md @@ -26,6 +26,7 @@ - [GridRowParams](/x/api/data-grid/grid-row-params/) - [GridRowSpacingParams](/x/api/data-grid/grid-row-spacing-params/) - [GridAggregationFunction](/x/api/data-grid/grid-aggregation-function/) +- [GridAggregationFunctionDataSource](/x/api/data-grid/grid-aggregation-function-data-source/) - [GridCsvExportOptions](/x/api/data-grid/grid-csv-export-options/) - [GridPrintExportOptions](/x/api/data-grid/grid-print-export-options/) - [GridExcelExportOptions](/x/api/data-grid/grid-excel-export-options/) diff --git a/docs/scripts/createXTypeScriptProjects.ts b/docs/scripts/createXTypeScriptProjects.ts index c0f24cb61a2d5..8fc0a872f29ca 100644 --- a/docs/scripts/createXTypeScriptProjects.ts +++ b/docs/scripts/createXTypeScriptProjects.ts @@ -152,6 +152,7 @@ export const interfacesToDocument: InterfacesToDocumentType[] = [ // Aggregation 'GridAggregationFunction', + 'GridAggregationFunctionDataSource', ], }, { diff --git a/docs/translations/api-docs/data-grid/grid-aggregation-function-data-source.json b/docs/translations/api-docs/data-grid/grid-aggregation-function-data-source.json new file mode 100644 index 0000000000000..2491dd0ed1396 --- /dev/null +++ b/docs/translations/api-docs/data-grid/grid-aggregation-function-data-source.json @@ -0,0 +1,17 @@ +{ + "interfaceDescription": "Grid aggregation function data source definition interface.", + "propertiesDescriptions": { + "columnTypes": { + "description": "Column types supported by this aggregation function.
    If not defined, all types are supported (in most cases this property should be defined)." + }, + "hasCellUnit": { + "description": "Indicates if the aggregated value has the same unit as the cells used to generate it.
    It can be used to apply a custom cell renderer only if the aggregated value has the same unit." + }, + "label": { + "description": "Label of the aggregation function.
    Used for adding a label to the footer of the grouping column when this aggregation function is the only one being used." + }, + "valueFormatter": { + "description": "Function for applying a formatter to the aggregated value.
    If not defined, the grid uses the formatter of the column." + } + } +} diff --git a/docs/translations/api-docs/data-grid/grid-aggregation-function.json b/docs/translations/api-docs/data-grid/grid-aggregation-function.json index 4a5bee820d1e9..7cb6c76d06a19 100644 --- a/docs/translations/api-docs/data-grid/grid-aggregation-function.json +++ b/docs/translations/api-docs/data-grid/grid-aggregation-function.json @@ -11,13 +11,13 @@ "description": "Function that allows to transform the value of the cell passed to the aggregation function applier.
    Useful for aggregating data from multiple row fields." }, "hasCellUnit": { - "description": "Indicates if the aggregated value have the same unit as the cells used to generate it.
    It can be used to apply a custom cell renderer only if the aggregated value has the same unit." + "description": "Indicates if the aggregated value has the same unit as the cells used to generate it.
    It can be used to apply a custom cell renderer only if the aggregated value has the same unit." }, "label": { - "description": "Label of the aggregation function.
    Will be used to add a label on the footer of the grouping column when this aggregation function is the only one being used." + "description": "Label of the aggregation function.
    Used for adding a label to the footer of the grouping column when this aggregation function is the only one being used." }, "valueFormatter": { - "description": "Function that allows to apply a formatter to the aggregated value.
    If not defined, the grid will use the formatter of the column." + "description": "Function for applying a formatter to the aggregated value.
    If not defined, the grid uses the formatter of the column." } } } diff --git a/packages/x-data-grid-generator/src/hooks/serverUtils.ts b/packages/x-data-grid-generator/src/hooks/serverUtils.ts index c0643d608e923..b44a26a1bf7f4 100644 --- a/packages/x-data-grid-generator/src/hooks/serverUtils.ts +++ b/packages/x-data-grid-generator/src/hooks/serverUtils.ts @@ -8,12 +8,32 @@ import { GridRowId, GridPaginationModel, GridValidRowModel, -} from '@mui/x-data-grid-pro'; + GRID_AGGREGATION_FUNCTIONS, + GridAggregationModel, + GridAggregationFunction, +} from '@mui/x-data-grid-premium'; import { GridStateColDef } from '@mui/x-data-grid-pro/internals'; import { randomInt } from '../services/random-generator'; +const getAvailableAggregationFunctions = (columnType: GridColDef['type']) => { + const availableAggregationFunctions = new Map(); + Object.keys(GRID_AGGREGATION_FUNCTIONS).forEach((functionName) => { + const columnTypes = + GRID_AGGREGATION_FUNCTIONS[functionName as keyof typeof GRID_AGGREGATION_FUNCTIONS] + .columnTypes; + if (!columnTypes || columnTypes.includes(columnType ?? 'string')) { + availableAggregationFunctions.set( + functionName, + GRID_AGGREGATION_FUNCTIONS[functionName as keyof typeof GRID_AGGREGATION_FUNCTIONS], + ); + } + }); + return availableAggregationFunctions; +}; + export interface FakeServerResponse { returnedRows: GridRowModel[]; + aggregateRow?: GridValidRowModel; nextCursor?: string; hasNextPage?: boolean; totalRowCount: number; @@ -39,6 +59,7 @@ export interface QueryOptions { page?: number; pageSize?: number; filterModel?: GridFilterModel; + aggregationModel?: GridAggregationModel; sortModel?: GridSortModel; start?: number; end?: number; @@ -50,6 +71,7 @@ export interface ServerSideQueryOptions { groupKeys?: string[]; filterModel?: GridFilterModel; sortModel?: GridSortModel; + aggregationModel?: GridAggregationModel; start?: number; end?: number; groupFields?: string[]; @@ -261,6 +283,41 @@ const getFilteredRows = ( ); }; +const applyAggregation = ( + aggregationModel: GridAggregationModel, + colDefs: GridColDef[], + rows: GridRowModel[], + groupId: string = 'root', +) => { + const columnsToAggregate = Object.keys(aggregationModel); + if (columnsToAggregate.length === 0) { + return {}; + } + + const aggregateValues: GridValidRowModel = {}; + columnsToAggregate.forEach((field) => { + const type = colDefs.find(({ field: f }) => f === field)?.type; + if (!type) { + return; + } + const availableAggregationFunctions = getAvailableAggregationFunctions(type); + if (!availableAggregationFunctions.has(aggregationModel[field])) { + return; + } + const aggregationFunction = availableAggregationFunctions.get(aggregationModel[field]); + if (!aggregationFunction) { + return; + } + const values = rows.map((row) => row[field]); + aggregateValues[`${field}Aggregate`] = aggregationFunction.apply({ + values, + field, + groupId, + }); + }); + return aggregateValues; +}; + /** * Simulates server data loading */ @@ -288,6 +345,15 @@ export const loadServerRows = ( const rowComparator = getRowComparator(queryOptions.sortModel, columnsWithDefaultColDef); filteredRows = [...filteredRows].sort(rowComparator); + let aggregateRow = {}; + if (queryOptions.aggregationModel) { + aggregateRow = applyAggregation( + queryOptions.aggregationModel, + columnsWithDefaultColDef, + filteredRows, + ); + } + const totalRowCount = filteredRows.length; if (start !== undefined && end !== undefined) { firstRowIndex = start; @@ -311,6 +377,7 @@ export const loadServerRows = ( hasNextPage, nextCursor, totalRowCount, + ...(queryOptions.aggregationModel ? { aggregateRow } : {}), }; return new Promise((resolve) => { @@ -323,6 +390,7 @@ export const loadServerRows = ( interface NestedDataRowsResponse { rows: GridRowModel[]; rootRowCount: number; + aggregateRow?: GridRowModel; } const findTreeDataRowChildren = ( @@ -464,6 +532,19 @@ export const processTreeDataRows = ( let childRowsWithDescendantCounts = childRows.map((row) => { const descendants = findTreeDataRowChildren(filteredRows, row[pathKey], pathKey, -1); const descendantCount = descendants.length; + if (descendantCount > 0 && queryOptions.aggregationModel) { + // Parent row, compute aggregation + return { + ...row, + descendantCount, + ...applyAggregation( + queryOptions.aggregationModel, + columnsWithDefaultColDef, + descendants, + row.id, + ), + }; + } return { ...row, descendantCount } as GridRowModel; }); @@ -473,6 +554,15 @@ export const processTreeDataRows = ( childRowsWithDescendantCounts = [...childRowsWithDescendantCounts].sort(rowComparator); } + let aggregateRow: GridRowModel | undefined; + if (queryOptions.aggregationModel) { + aggregateRow = applyAggregation( + queryOptions.aggregationModel, + columnsWithDefaultColDef, + filteredRows, + ); + } + if (queryOptions.paginationModel && queryOptions.groupKeys.length === 0) { // Only paginate root rows, grid should refetch root rows when `paginationModel` updates const { pageSize, page } = queryOptions.paginationModel; @@ -486,7 +576,7 @@ export const processTreeDataRows = ( return new Promise((resolve) => { setTimeout(() => { - resolve({ rows: childRowsWithDescendantCounts, rootRowCount }); + resolve({ rows: childRowsWithDescendantCounts, rootRowCount, aggregateRow }); }, delay); // simulate network latency }); }; @@ -584,6 +674,19 @@ export const processRowGroupingRows = ( ({ id }) => typeof id !== 'string' || !id.startsWith('auto-generated-parent-'), ); const descendantCount = descendants.length; + if (descendantCount > 0 && queryOptions.aggregationModel) { + // Parent row, compute aggregation + return { + ...row, + descendantCount, + ...applyAggregation( + queryOptions.aggregationModel, + columnsWithDefaultColDef, + descendants, + row.id, + ), + }; + } return { ...row, descendantCount } as GridRowModel; }); @@ -594,6 +697,15 @@ export const processRowGroupingRows = ( childRowsWithDescendantCounts = [...sortedMissingGroups, ...sortedChildRows]; } + let aggregateRow: GridRowModel | undefined; + if (queryOptions.aggregationModel) { + aggregateRow = applyAggregation( + queryOptions.aggregationModel, + columnsWithDefaultColDef, + filteredRows, + ); + } + if (queryOptions.paginationModel && queryOptions.groupKeys.length === 0) { // Only paginate root rows, grid should refetch root rows when `paginationModel` updates const { pageSize, page } = queryOptions.paginationModel; @@ -607,7 +719,7 @@ export const processRowGroupingRows = ( return new Promise((resolve) => { setTimeout(() => { - resolve({ rows: childRowsWithDescendantCounts, rootRowCount }); + resolve({ rows: childRowsWithDescendantCounts, rootRowCount, aggregateRow }); }, delay); // simulate network latency }); }; diff --git a/packages/x-data-grid-generator/src/hooks/useMockServer.ts b/packages/x-data-grid-generator/src/hooks/useMockServer.ts index 9fb8aff79a8c2..a150839bb0eb4 100644 --- a/packages/x-data-grid-generator/src/hooks/useMockServer.ts +++ b/packages/x-data-grid-generator/src/hooks/useMockServer.ts @@ -7,7 +7,7 @@ import { GridColDef, GridInitialState, GridColumnVisibilityModel, -} from '@mui/x-data-grid-pro'; +} from '@mui/x-data-grid-premium'; import { extrapolateSeed, deepFreeze } from './useDemoData'; import { getCommodityColumns } from '../columns/commodities.columns'; import { getEmployeeColumns } from '../columns/employees.columns'; @@ -298,7 +298,7 @@ export const useMockServer = ( } if (isTreeData) { - const { rows, rootRowCount } = await processTreeDataRows( + const { rows, rootRowCount, aggregateRow } = await processTreeDataRows( data?.rows ?? [], params, serverOptionsWithDefault, @@ -308,9 +308,10 @@ export const useMockServer = ( getRowsResponse = { rows: rows.slice().map((row) => ({ ...row, path: undefined })), rowCount: rootRowCount, + ...(aggregateRow ? { aggregateRow } : {}), }; } else if (isRowGrouping) { - const { rows, rootRowCount } = await processRowGroupingRows( + const { rows, rootRowCount, aggregateRow } = await processRowGroupingRows( data?.rows ?? [], params, serverOptionsWithDefault, @@ -320,15 +321,21 @@ export const useMockServer = ( getRowsResponse = { rows: rows.slice().map((row) => ({ ...row, path: undefined })), rowCount: rootRowCount, + ...(aggregateRow ? { aggregateRow } : {}), }; } else { - const { returnedRows, nextCursor, totalRowCount } = await loadServerRows( + const { returnedRows, nextCursor, totalRowCount, aggregateRow } = await loadServerRows( data?.rows ?? [], { ...params, ...params.paginationModel }, serverOptionsWithDefault, columnsWithDefaultColDef, ); - getRowsResponse = { rows: returnedRows, rowCount: totalRowCount, pageInfo: { nextCursor } }; + getRowsResponse = { + rows: returnedRows, + rowCount: totalRowCount, + pageInfo: { nextCursor }, + ...(aggregateRow ? { aggregateRow } : {}), + }; } return new Promise((resolve) => { diff --git a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx index c91e68a462c5a..6160575fb7ff9 100644 --- a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx +++ b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx @@ -80,7 +80,7 @@ DataGridPremiumRaw.propTypes = { // ---------------------------------------------------------------------- /** * Aggregation functions available on the grid. - * @default GRID_AGGREGATION_FUNCTIONS + * @default GRID_AGGREGATION_FUNCTIONS when `unstable_dataSource` is not provided, `{}` when `unstable_dataSource` is provided */ aggregationFunctions: PropTypes.object, /** @@ -1080,6 +1080,7 @@ DataGridPremiumRaw.propTypes = { */ treeData: PropTypes.bool, unstable_dataSource: PropTypes.shape({ + getAggregatedValue: PropTypes.func, getChildrenCount: PropTypes.func, getGroupKey: PropTypes.func, getRows: PropTypes.func.isRequired, diff --git a/packages/x-data-grid-premium/src/DataGridPremium/useDataGridPremiumComponent.tsx b/packages/x-data-grid-premium/src/DataGridPremium/useDataGridPremiumComponent.tsx index 5e3f20c6ea49d..d1b931e524a69 100644 --- a/packages/x-data-grid-premium/src/DataGridPremium/useDataGridPremiumComponent.tsx +++ b/packages/x-data-grid-premium/src/DataGridPremium/useDataGridPremiumComponent.tsx @@ -67,7 +67,6 @@ import { virtualizationStateInitializer, useGridVirtualization, useGridDataSourceTreeDataPreProcessors, - useGridDataSource, dataSourceStateInitializer, useGridRowSpanning, rowSpanningStateInitializer, @@ -76,6 +75,7 @@ import { } from '@mui/x-data-grid-pro/internals'; import { GridApiPremium, GridPrivateApiPremium } from '../models/gridApiPremium'; import { DataGridPremiumProcessedProps } from '../models/dataGridPremiumProps'; +import { useGridDataSourcePremium as useGridDataSource } from '../hooks/features/dataSource/useGridDataSourcePremium'; // Premium-only features import { useGridAggregation, @@ -153,6 +153,7 @@ export const useDataGridPremiumComponent = ( useGridRowGrouping(apiRef, props); useGridHeaderFiltering(apiRef, props); useGridTreeData(apiRef, props); + useGridDataSource(apiRef, props); useGridAggregation(apiRef, props); useGridKeyboardNavigation(apiRef, props); useGridRowSelection(apiRef, props); @@ -190,7 +191,6 @@ export const useDataGridPremiumComponent = ( useGridDimensions(apiRef, props); useGridEvents(apiRef, props); useGridStatePersistence(apiRef); - useGridDataSource(apiRef, props); useGridVirtualization(apiRef, props); useGridListView(apiRef, props); diff --git a/packages/x-data-grid-premium/src/DataGridPremium/useDataGridPremiumProps.ts b/packages/x-data-grid-premium/src/DataGridPremium/useDataGridPremiumProps.ts index c047e56429235..bb316ad4c9e3e 100644 --- a/packages/x-data-grid-premium/src/DataGridPremium/useDataGridPremiumProps.ts +++ b/packages/x-data-grid-premium/src/DataGridPremium/useDataGridPremiumProps.ts @@ -84,6 +84,7 @@ export const useDataGridPremiumProps = (inProps: DataGridPremiumProps) => { return React.useMemo( () => ({ ...DATA_GRID_PREMIUM_PROPS_DEFAULT_VALUES, + ...(themedProps.unstable_dataSource ? { aggregationFunctions: {} } : {}), ...themedProps, localeText, slots, diff --git a/packages/x-data-grid-premium/src/components/GridColumnMenuAggregationItem.tsx b/packages/x-data-grid-premium/src/components/GridColumnMenuAggregationItem.tsx index 522edfd53b492..4bbe750029925 100644 --- a/packages/x-data-grid-premium/src/components/GridColumnMenuAggregationItem.tsx +++ b/packages/x-data-grid-premium/src/components/GridColumnMenuAggregationItem.tsx @@ -27,8 +27,9 @@ function GridColumnMenuAggregationItem(props: GridColumnMenuItemProps) { getAvailableAggregationFunctions({ aggregationFunctions: rootProps.aggregationFunctions, colDef, + isDataSource: !!rootProps.unstable_dataSource, }), - [colDef, rootProps.aggregationFunctions], + [colDef, rootProps.aggregationFunctions, rootProps.unstable_dataSource], ); const { native: isBaseSelectNative = false, ...baseSelectProps } = rootProps.slotProps?.baseSelect || {}; @@ -45,13 +46,14 @@ function GridColumnMenuAggregationItem(props: GridColumnMenuItemProps) { colDef, aggregationFunctionName, aggregationFunction: rootProps.aggregationFunctions[aggregationFunctionName], + isDataSource: !!rootProps.unstable_dataSource, }) ) { return aggregationFunctionName; } return ''; - }, [rootProps.aggregationFunctions, aggregationModel, colDef]); + }, [rootProps.aggregationFunctions, rootProps.unstable_dataSource, aggregationModel, colDef]); const handleAggregationItemChange = (event: SelectChangeEvent) => { const newAggregationItem = (event.target as HTMLSelectElement | null)?.value || undefined; diff --git a/packages/x-data-grid-premium/src/hooks/features/aggregation/createAggregationLookup.ts b/packages/x-data-grid-premium/src/hooks/features/aggregation/createAggregationLookup.ts index 4294bf38db5ca..1a8b81c3585fd 100644 --- a/packages/x-data-grid-premium/src/hooks/features/aggregation/createAggregationLookup.ts +++ b/packages/x-data-grid-premium/src/hooks/features/aggregation/createAggregationLookup.ts @@ -8,10 +8,11 @@ import { gridRowTreeSelector, GRID_ROOT_GROUP_ID, } from '@mui/x-data-grid-pro'; -import { GridApiPremium } from '../../../models/gridApiPremium'; +import { GridPrivateApiPremium } from '../../../models/gridApiPremium'; import { DataGridPremiumProcessedProps } from '../../../models/dataGridPremiumProps'; import { GridAggregationFunction, + GridAggregationFunctionDataSource, GridAggregationLookup, GridAggregationPosition, GridAggregationRules, @@ -21,7 +22,7 @@ import { gridAggregationModelSelector } from './gridAggregationSelectors'; const getGroupAggregatedValue = ( groupId: GridRowId, - apiRef: React.MutableRefObject, + apiRef: React.MutableRefObject, aggregationRowsScope: DataGridPremiumProcessedProps['aggregationRowsScope'], aggregatedFields: string[], aggregationRules: GridAggregationRules, @@ -56,7 +57,8 @@ const getGroupAggregatedValue = ( const aggregatedField = aggregatedFields[j]; const columnAggregationRules = aggregationRules[aggregatedField]; - const aggregationFunction = columnAggregationRules.aggregationFunction; + const aggregationFunction = + columnAggregationRules.aggregationFunction as GridAggregationFunction; const field = aggregatedField; if (aggregatedValues[j] === undefined) { @@ -77,7 +79,8 @@ const getGroupAggregatedValue = ( for (let i = 0; i < aggregatedValues.length; i += 1) { const { aggregatedField, values } = aggregatedValues[i]; - const aggregationFunction = aggregationRules[aggregatedField].aggregationFunction; + const aggregationFunction = aggregationRules[aggregatedField] + .aggregationFunction as GridAggregationFunction; const value = aggregationFunction.apply({ values, groupId, @@ -93,21 +96,46 @@ const getGroupAggregatedValue = ( return groupAggregationLookup; }; +const getGroupAggregatedValueDataSource = ( + groupId: GridRowId, + apiRef: React.MutableRefObject, + aggregatedFields: string[], + position: GridAggregationPosition, +) => { + const groupAggregationLookup: GridAggregationLookup[GridRowId] = {}; + + for (let j = 0; j < aggregatedFields.length; j += 1) { + const aggregatedField = aggregatedFields[j]; + + groupAggregationLookup[aggregatedField] = { + position, + value: apiRef.current.resolveGroupAggregation(groupId, aggregatedField), + }; + } + + return groupAggregationLookup; +}; + export const createAggregationLookup = ({ apiRef, aggregationFunctions, aggregationRowsScope, getAggregationPosition, + isDataSource, }: { - apiRef: React.MutableRefObject; - aggregationFunctions: Record; + apiRef: React.MutableRefObject; + aggregationFunctions: + | Record + | Record; aggregationRowsScope: DataGridPremiumProcessedProps['aggregationRowsScope']; getAggregationPosition: DataGridPremiumProcessedProps['getAggregationPosition']; + isDataSource: boolean; }): GridAggregationLookup => { const aggregationRules = getAggregationRules( gridColumnLookupSelector(apiRef), gridAggregationModelSelector(apiRef), aggregationFunctions, + isDataSource, ); const aggregatedFields = Object.keys(aggregationRules); @@ -128,10 +156,17 @@ export const createAggregationLookup = ({ } } - const hasAggregableChildren = groupNode.children.length; - if (hasAggregableChildren) { - const position = getAggregationPosition(groupNode); - if (position != null) { + const position = getAggregationPosition(groupNode); + + if (position !== null) { + if (isDataSource) { + aggregationLookup[groupNode.id] = getGroupAggregatedValueDataSource( + groupNode.id, + apiRef, + aggregatedFields, + position, + ); + } else if (groupNode.children.length) { aggregationLookup[groupNode.id] = getGroupAggregatedValue( groupNode.id, apiRef, diff --git a/packages/x-data-grid-premium/src/hooks/features/aggregation/gridAggregationInterfaces.ts b/packages/x-data-grid-premium/src/hooks/features/aggregation/gridAggregationInterfaces.ts index 212bdef1a0083..96e584d233037 100644 --- a/packages/x-data-grid-premium/src/hooks/features/aggregation/gridAggregationInterfaces.ts +++ b/packages/x-data-grid-premium/src/hooks/features/aggregation/gridAggregationInterfaces.ts @@ -22,6 +22,13 @@ export interface GridAggregationApi { setAggregationModel: (model: GridAggregationModel) => void; } +export interface GridAggregationPrivateApi { + /** + * Applies the aggregation to the rows. + */ + applyAggregation: () => void; +} + export interface GridAggregationGetCellValueParams { /** * The row model of the row that the current cell belongs to. @@ -44,7 +51,7 @@ export interface GridAggregationFunction { apply: (params: GridAggregationParams) => AV | null | undefined; /** * Label of the aggregation function. - * Will be used to add a label on the footer of the grouping column when this aggregation function is the only one being used. + * Used for adding a label to the footer of the grouping column when this aggregation function is the only one being used. * @default apiRef.current.getLocaleText('aggregationFunctionLabel{capitalize(name)}) */ label?: string; @@ -54,12 +61,12 @@ export interface GridAggregationFunction { */ columnTypes?: string[]; /** - * Function that allows to apply a formatter to the aggregated value. - * If not defined, the grid will use the formatter of the column. + * Function for applying a formatter to the aggregated value. + * If not defined, the grid uses the formatter of the column. */ valueFormatter?: GridValueFormatter; /** - * Indicates if the aggregated value have the same unit as the cells used to generate it. + * Indicates if the aggregated value has the same unit as the cells used to generate it. * It can be used to apply a custom cell renderer only if the aggregated value has the same unit. * @default true */ @@ -74,6 +81,14 @@ export interface GridAggregationFunction { getCellValue?: (params: GridAggregationGetCellValueParams) => V; } +/** + * Grid aggregation function data source definition interface. + * @demos + * - [Server-side aggregation](/x/react-data-grid/server-side-data/aggregation/) + */ +export interface GridAggregationFunctionDataSource + extends Omit {} + export interface GridAggregationParams { values: (V | undefined)[]; groupId: GridRowId; @@ -115,7 +130,7 @@ export interface GridAggregationHeaderMeta { export interface GridAggregationRule { aggregationFunctionName: string; - aggregationFunction: GridAggregationFunction; + aggregationFunction: GridAggregationFunction | GridAggregationFunctionDataSource; } /** diff --git a/packages/x-data-grid-premium/src/hooks/features/aggregation/gridAggregationUtils.ts b/packages/x-data-grid-premium/src/hooks/features/aggregation/gridAggregationUtils.ts index c84aae5d5e30b..408b7e1950d6d 100644 --- a/packages/x-data-grid-premium/src/hooks/features/aggregation/gridAggregationUtils.ts +++ b/packages/x-data-grid-premium/src/hooks/features/aggregation/gridAggregationUtils.ts @@ -18,6 +18,7 @@ import { } from '@mui/x-data-grid-pro/internals'; import { GridAggregationFunction, + GridAggregationFunctionDataSource, GridAggregationModel, GridAggregationRule, GridAggregationRules, @@ -36,20 +37,29 @@ export const getAggregationFooterRowIdFromGroupId = (groupId: GridRowId | null) return `auto-generated-group-footer-${groupId}`; }; +type AggregationFunction = GridAggregationFunction | GridAggregationFunctionDataSource | undefined; + +const isClientSideAggregateFunction = ( + aggregationFunction: AggregationFunction, +): aggregationFunction is GridAggregationFunction => + !!aggregationFunction && 'apply' in aggregationFunction; + export const canColumnHaveAggregationFunction = ({ colDef, aggregationFunctionName, aggregationFunction, + isDataSource, }: { colDef: GridColDef | undefined; aggregationFunctionName: string; - aggregationFunction: GridAggregationFunction | undefined; + aggregationFunction: AggregationFunction; + isDataSource: boolean; }): boolean => { if (!colDef) { return false; } - if (!aggregationFunction) { + if (!isClientSideAggregateFunction(aggregationFunction) && !isDataSource) { return false; } @@ -57,7 +67,7 @@ export const canColumnHaveAggregationFunction = ({ return colDef.availableAggregationFunctions.includes(aggregationFunctionName); } - if (!aggregationFunction.columnTypes) { + if (!aggregationFunction?.columnTypes) { return true; } @@ -67,15 +77,20 @@ export const canColumnHaveAggregationFunction = ({ export const getAvailableAggregationFunctions = ({ aggregationFunctions, colDef, + isDataSource, }: { - aggregationFunctions: Record; + aggregationFunctions: + | Record + | Record; colDef: GridColDef; + isDataSource: boolean; }) => Object.keys(aggregationFunctions).filter((aggregationFunctionName) => canColumnHaveAggregationFunction({ colDef, aggregationFunctionName, aggregationFunction: aggregationFunctions[aggregationFunctionName], + isDataSource, }), ); @@ -89,7 +104,10 @@ export const mergeStateWithAggregationModel = export const getAggregationRules = ( columnsLookup: GridColumnRawLookup, aggregationModel: GridAggregationModel, - aggregationFunctions: Record, + aggregationFunctions: + | Record + | Record, + isDataSource: boolean, ) => { const aggregationRules: GridAggregationRules = {}; @@ -102,6 +120,7 @@ export const getAggregationRules = ( colDef: columnsLookup[field], aggregationFunctionName: columnItem, aggregationFunction: aggregationFunctions[columnItem], + isDataSource, }) ) { aggregationRules[field] = { diff --git a/packages/x-data-grid-premium/src/hooks/features/aggregation/index.ts b/packages/x-data-grid-premium/src/hooks/features/aggregation/index.ts index 0334e48bacb90..ee9155e14144c 100644 --- a/packages/x-data-grid-premium/src/hooks/features/aggregation/index.ts +++ b/packages/x-data-grid-premium/src/hooks/features/aggregation/index.ts @@ -1,4 +1,20 @@ -export * from './gridAggregationInterfaces'; +export type { + GridAggregationState, + GridAggregationInitialState, + GridAggregationInternalCache, + GridAggregationApi, + GridAggregationGetCellValueParams, + GridAggregationFunction, + GridAggregationFunctionDataSource, + GridAggregationParams, + GridAggregationModel, + GridAggregationLookup, + GridAggregationPosition, + GridAggregationCellMeta, + GridAggregationHeaderMeta, + GridAggregationRule, + GridAggregationRules, +} from './gridAggregationInterfaces'; export * from './gridAggregationSelectors'; export * from './gridAggregationFunctions'; export { diff --git a/packages/x-data-grid-premium/src/hooks/features/aggregation/useGridAggregation.ts b/packages/x-data-grid-premium/src/hooks/features/aggregation/useGridAggregation.ts index 8b41493cc2b96..345f9b718509f 100644 --- a/packages/x-data-grid-premium/src/hooks/features/aggregation/useGridAggregation.ts +++ b/packages/x-data-grid-premium/src/hooks/features/aggregation/useGridAggregation.ts @@ -4,11 +4,15 @@ import { useGridApiEventHandler, useGridApiMethod, } from '@mui/x-data-grid-pro'; -import { GridStateInitializer } from '@mui/x-data-grid-pro/internals'; +import { + useGridRegisterPipeProcessor, + GridStateInitializer, + GridPipeProcessor, +} from '@mui/x-data-grid-pro/internals'; import { DataGridPremiumProcessedProps } from '../../../models/dataGridPremiumProps'; import { GridPrivateApiPremium } from '../../../models/gridApiPremium'; import { gridAggregationModelSelector } from './gridAggregationSelectors'; -import { GridAggregationApi } from './gridAggregationInterfaces'; +import { GridAggregationApi, GridAggregationPrivateApi } from './gridAggregationInterfaces'; import { getAggregationRules, mergeStateWithAggregationModel, @@ -45,6 +49,7 @@ export const useGridAggregation = ( | 'aggregationRowsScope' | 'disableAggregation' | 'rowGroupingColumnMode' + | 'unstable_dataSource' >, ) => { apiRef.current.registerControlState({ @@ -75,6 +80,7 @@ export const useGridAggregation = ( getAggregationPosition: props.getAggregationPosition, aggregationFunctions: props.aggregationFunctions, aggregationRowsScope: props.aggregationRowsScope, + isDataSource: !!props.unstable_dataSource, }); apiRef.current.setState((state) => ({ @@ -86,13 +92,31 @@ export const useGridAggregation = ( props.getAggregationPosition, props.aggregationFunctions, props.aggregationRowsScope, + props.unstable_dataSource, ]); const aggregationApi: GridAggregationApi = { setAggregationModel, }; + const aggregationPrivateApi: GridAggregationPrivateApi = { + applyAggregation, + }; + useGridApiMethod(apiRef, aggregationApi, 'public'); + useGridApiMethod(apiRef, aggregationPrivateApi, 'private'); + + const addGetRowsParams = React.useCallback>( + (params) => { + return { + ...params, + aggregationModel: gridAggregationModelSelector(apiRef), + }; + }, + [apiRef], + ); + + useGridRegisterPipeProcessor(apiRef, 'getRowsParams', addGetRowsParams); /** * EVENTS @@ -107,12 +131,17 @@ export const useGridAggregation = ( gridColumnLookupSelector(apiRef), gridAggregationModelSelector(apiRef), props.aggregationFunctions, + !!props.unstable_dataSource, ); // Re-apply the row hydration to add / remove the aggregation footers if (!areAggregationRulesEqual(rulesOnLastRowHydration, aggregationRules)) { - apiRef.current.requestPipeProcessorsApplication('hydrateRows'); - applyAggregation(); + if (props.unstable_dataSource) { + apiRef.current.unstable_dataSource.fetchRows(); + } else { + apiRef.current.requestPipeProcessorsApplication('hydrateRows'); + applyAggregation(); + } } // Re-apply the column hydration to wrap / unwrap the aggregated columns @@ -120,7 +149,13 @@ export const useGridAggregation = ( apiRef.current.caches.aggregation.rulesOnLastColumnHydration = aggregationRules; apiRef.current.requestPipeProcessorsApplication('hydrateColumns'); } - }, [apiRef, applyAggregation, props.aggregationFunctions, props.disableAggregation]); + }, [ + apiRef, + applyAggregation, + props.aggregationFunctions, + props.disableAggregation, + props.unstable_dataSource, + ]); useGridApiEventHandler(apiRef, 'aggregationModelChange', checkAggregationRulesDiff); useGridApiEventHandler(apiRef, 'columnsChange', checkAggregationRulesDiff); diff --git a/packages/x-data-grid-premium/src/hooks/features/aggregation/useGridAggregationPreProcessors.tsx b/packages/x-data-grid-premium/src/hooks/features/aggregation/useGridAggregationPreProcessors.tsx index 5ae196fb91ce1..b40cfb1ac99b6 100644 --- a/packages/x-data-grid-premium/src/hooks/features/aggregation/useGridAggregationPreProcessors.tsx +++ b/packages/x-data-grid-premium/src/hooks/features/aggregation/useGridAggregationPreProcessors.tsx @@ -25,7 +25,12 @@ export const useGridAggregationPreProcessors = ( apiRef: React.MutableRefObject, props: Pick< DataGridPremiumProcessedProps, - 'aggregationFunctions' | 'disableAggregation' | 'getAggregationPosition' | 'slotProps' | 'slots' + | 'aggregationFunctions' + | 'disableAggregation' + | 'getAggregationPosition' + | 'slotProps' + | 'slots' + | 'unstable_dataSource' >, ) => { // apiRef.current.caches.aggregation.rulesOnLastColumnHydration is not used because by the time @@ -40,6 +45,7 @@ export const useGridAggregationPreProcessors = ( columnsState.lookup, gridAggregationModelSelector(apiRef), props.aggregationFunctions, + !!props.unstable_dataSource, ); columnsState.orderedFields.forEach((field) => { @@ -69,7 +75,7 @@ export const useGridAggregationPreProcessors = ( return columnsState; }, - [apiRef, props.aggregationFunctions, props.disableAggregation], + [apiRef, props.aggregationFunctions, props.disableAggregation, props.unstable_dataSource], ); const addGroupFooterRows = React.useCallback>( @@ -80,6 +86,7 @@ export const useGridAggregationPreProcessors = ( gridColumnLookupSelector(apiRef), gridAggregationModelSelector(apiRef), props.aggregationFunctions, + !!props.unstable_dataSource, ); const hasAggregationRule = Object.keys(aggregationRules).length > 0; @@ -102,7 +109,13 @@ export const useGridAggregationPreProcessors = ( hasAggregationRule, }); }, - [apiRef, props.disableAggregation, props.getAggregationPosition, props.aggregationFunctions], + [ + apiRef, + props.disableAggregation, + props.getAggregationPosition, + props.aggregationFunctions, + props.unstable_dataSource, + ], ); const addColumnMenuButtons = React.useCallback>( @@ -114,6 +127,7 @@ export const useGridAggregationPreProcessors = ( const availableAggregationFunctions = getAvailableAggregationFunctions({ aggregationFunctions: props.aggregationFunctions, colDef, + isDataSource: !!props.unstable_dataSource, }); if (availableAggregationFunctions.length === 0) { @@ -122,7 +136,7 @@ export const useGridAggregationPreProcessors = ( return [...columnMenuItems, 'columnMenuAggregationItem']; }, - [props.aggregationFunctions, props.disableAggregation], + [props.aggregationFunctions, props.disableAggregation, props.unstable_dataSource], ); const stateExportPreProcessing = React.useCallback>( diff --git a/packages/x-data-grid-premium/src/hooks/features/dataSource/cache.ts b/packages/x-data-grid-premium/src/hooks/features/dataSource/cache.ts new file mode 100644 index 0000000000000..db35e1db051d9 --- /dev/null +++ b/packages/x-data-grid-premium/src/hooks/features/dataSource/cache.ts @@ -0,0 +1,13 @@ +import { GridGetRowsParamsPremium } from './models'; + +export function getKeyPremium(params: GridGetRowsParamsPremium) { + return JSON.stringify([ + params.filterModel, + params.sortModel, + params.groupKeys, + params.groupFields, + params.start, + params.end, + params.aggregationModel, + ]); +} diff --git a/packages/x-data-grid-premium/src/hooks/features/dataSource/models.ts b/packages/x-data-grid-premium/src/hooks/features/dataSource/models.ts new file mode 100644 index 0000000000000..ef69f680ad459 --- /dev/null +++ b/packages/x-data-grid-premium/src/hooks/features/dataSource/models.ts @@ -0,0 +1,63 @@ +import type { + GridColDef, + GridRowId, + GridValidRowModel, + GridDataSource, + GridGetRowsResponse, + GridGetRowsParams, + GridDataSourceApiBase, + GridDataSourcePrivateApi, +} from '@mui/x-data-grid-pro'; + +import type { GridAggregationModel } from '../aggregation/gridAggregationInterfaces'; + +export interface GridGetRowsResponsePremium extends GridGetRowsResponse { + /** + * Row to be used for aggregation footer row. + * It must provide the values for the aggregated columns passed in + * `GridGetRowsParams.aggregationModel`. + */ + aggregateRow?: GridValidRowModel; +} + +export interface GridGetRowsParamsPremium extends GridGetRowsParams { + aggregationModel?: GridAggregationModel; +} + +export interface GridDataSourcePremium extends Omit { + /** + * This method will be called when the grid needs to fetch some rows. + * @param {GridGetRowsParamsPremium} params The parameters required to fetch the rows. + * @returns {Promise} A promise that resolves to the data of type [GridGetRowsResponsePremium]. + */ + getRows(params: GridGetRowsParamsPremium): Promise; + /** + * Used to get the aggregated value for a parent row. + * @param {GridValidRowModel} row The row to extract the aggregated value from. + * @param {GridColDef['field']} field The field to extract the aggregated value for. + * @returns {string} The aggregated value for a specific aggregated column. + */ + getAggregatedValue?: (row: GridValidRowModel, field: GridColDef['field']) => string; +} + +export interface GridDataSourceApiBasePremium extends Omit { + /** + * Fetches the rows from the server. + * If no `parentId` option is provided, it fetches the root rows. + * Any missing parameter from `params` will be filled from the state (sorting, filtering, etc.). + * @param {GridRowId} parentId The id of the parent node (default: `GRID_ROOT_GROUP_ID`). + * @param {Partial} params Request parameters override. + */ + fetchRows: (parentId?: GridRowId, params?: Partial) => void; +} + +export interface GridDataSourceApiPremium { + /** + * The data source API. + */ + unstable_dataSource: GridDataSourceApiBasePremium; +} + +export interface GridDataSourcePremiumPrivateApi extends GridDataSourcePrivateApi { + resolveGroupAggregation: (groupId: GridRowId, field: string) => any; +} diff --git a/packages/x-data-grid-premium/src/hooks/features/dataSource/useGridDataSourcePremium.tsx b/packages/x-data-grid-premium/src/hooks/features/dataSource/useGridDataSourcePremium.tsx new file mode 100644 index 0000000000000..09bfb1d025279 --- /dev/null +++ b/packages/x-data-grid-premium/src/hooks/features/dataSource/useGridDataSourcePremium.tsx @@ -0,0 +1,102 @@ +import * as React from 'react'; +import { + useGridApiEventHandler as addEventHandler, + useGridApiMethod, + GridEventLookup, + GRID_ROOT_GROUP_ID, + GridValidRowModel, +} from '@mui/x-data-grid-pro'; +import { + useGridDataSourceBase, + useGridRegisterStrategyProcessor, + GridPipeProcessor, + useGridRegisterPipeProcessor, +} from '@mui/x-data-grid-pro/internals'; +import { GridPrivateApiPremium } from '../../../models/gridApiPremium'; +import { DataGridPremiumProcessedProps } from '../../../models/dataGridPremiumProps'; +import { + GridDataSourcePremiumPrivateApi, + GridGetRowsParamsPremium, + GridGetRowsResponsePremium, +} from './models'; +import { getKeyPremium } from './cache'; + +const options = { + cacheOptions: { + getKey: getKeyPremium, + }, +}; + +export const useGridDataSourcePremium = ( + apiRef: React.MutableRefObject, + props: DataGridPremiumProcessedProps, +) => { + const { api, strategyProcessor, events } = useGridDataSourceBase( + apiRef, + props, + options, + ); + const aggregateRowRef = React.useRef({}); + + const processDataSourceRows = React.useCallback>( + ( + { + params, + response, + }: { + params: GridGetRowsParamsPremium; + response: GridGetRowsResponsePremium; + }, + applyRowHydration: boolean, + ) => { + if (response.aggregateRow) { + aggregateRowRef.current = response.aggregateRow; + } + if (Object.keys(params.aggregationModel || {}).length > 0) { + if (applyRowHydration) { + apiRef.current.requestPipeProcessorsApplication('hydrateRows'); + } + apiRef.current.applyAggregation(); + } + + return { + params, + response, + }; + }, + [apiRef], + ); + + const resolveGroupAggregation = React.useCallback< + GridDataSourcePremiumPrivateApi['resolveGroupAggregation'] + >( + (groupId, field) => { + if (groupId === GRID_ROOT_GROUP_ID) { + return props.unstable_dataSource?.getAggregatedValue?.(aggregateRowRef.current, field); + } + const row = apiRef.current.getRow(groupId); + return props.unstable_dataSource?.getAggregatedValue?.(row, field); + }, + [apiRef, props.unstable_dataSource], + ); + + const privateApi: GridDataSourcePremiumPrivateApi = { + ...api.private, + resolveGroupAggregation, + }; + + useGridApiMethod(apiRef, api.public, 'public'); + useGridApiMethod(apiRef, privateApi, 'private'); + + useGridRegisterStrategyProcessor( + apiRef, + strategyProcessor.strategyName, + strategyProcessor.group, + strategyProcessor.processor, + ); + useGridRegisterPipeProcessor(apiRef, 'processDataSourceRows', processDataSourceRows); + + Object.entries(events).forEach(([event, handler]) => { + addEventHandler(apiRef, event as keyof GridEventLookup, handler); + }); +}; diff --git a/packages/x-data-grid-premium/src/index.ts b/packages/x-data-grid-premium/src/index.ts index 0def4c628a755..36842cea3ac1a 100644 --- a/packages/x-data-grid-premium/src/index.ts +++ b/packages/x-data-grid-premium/src/index.ts @@ -40,3 +40,14 @@ export { GRID_COLUMN_MENU_SLOTS, GRID_COLUMN_MENU_SLOT_PROPS, } from './components/reexports'; + +export type { GridDataSourceCache } from '@mui/x-data-grid-pro'; + +export type { + GridGetRowsParamsPremium as GridGetRowsParams, + GridGetRowsResponsePremium as GridGetRowsResponse, + GridDataSourcePremium as GridDataSource, + GridDataSourceApiPremium as GridDataSourceApi, + GridDataSourceApiBasePremium as GridDataSourceApiBase, + GridDataSourcePremiumPrivateApi as GridDataSourcePrivateApi, +} from './hooks/features/dataSource/models'; diff --git a/packages/x-data-grid-premium/src/models/dataGridPremiumProps.ts b/packages/x-data-grid-premium/src/models/dataGridPremiumProps.ts index 8ed5498364dab..da879f08ed001 100644 --- a/packages/x-data-grid-premium/src/models/dataGridPremiumProps.ts +++ b/packages/x-data-grid-premium/src/models/dataGridPremiumProps.ts @@ -17,12 +17,14 @@ import type { GridRowGroupingModel } from '../hooks/features/rowGrouping'; import type { GridAggregationModel, GridAggregationFunction, + GridAggregationFunctionDataSource, GridAggregationPosition, } from '../hooks/features/aggregation'; import { GridPremiumSlotsComponent } from './gridPremiumSlotsComponent'; import { GridInitialStatePremium } from './gridStatePremium'; import { GridApiPremium } from './gridApiPremium'; import { GridCellSelectionModel } from '../hooks/features/cellSelection'; +import { GridDataSourcePremium as GridDataSource } from '../hooks/features/dataSource/models'; export interface GridExperimentalPremiumFeatures extends GridExperimentalProFeatures {} @@ -86,9 +88,11 @@ export interface DataGridPremiumPropsWithDefaultValue; + aggregationFunctions: + | Record + | Record; /** * Rows used to generate the aggregated value. * If `filtered`, the aggregated values are generated using only the rows currently passing the filtering process. @@ -118,7 +122,10 @@ export interface DataGridPremiumPropsWithDefaultValue - extends Omit, 'initialState' | 'apiRef'> { + extends Omit< + DataGridProPropsWithoutDefaultValue, + 'initialState' | 'apiRef' | 'unstable_dataSource' + > { /** * The ref object that allows grid manipulation. Can be instantiated with `useGridApiRef()`. */ @@ -188,4 +195,5 @@ export interface DataGridPremiumPropsWithoutDefaultValue; + unstable_dataSource?: GridDataSource; } diff --git a/packages/x-data-grid-premium/src/models/gridApiPremium.ts b/packages/x-data-grid-premium/src/models/gridApiPremium.ts index 98ec11cdd1dce..1ea6dd05158ce 100644 --- a/packages/x-data-grid-premium/src/models/gridApiPremium.ts +++ b/packages/x-data-grid-premium/src/models/gridApiPremium.ts @@ -8,13 +8,16 @@ import { GridRowMultiSelectionApi, GridColumnReorderApi, GridRowProApi, - GridDataSourceApi, - GridDataSourcePrivateApi, } from '@mui/x-data-grid-pro'; import { GridInitialStatePremium, GridStatePremium } from './gridStatePremium'; import type { GridRowGroupingApi, GridExcelExportApi, GridAggregationApi } from '../hooks'; import { GridCellSelectionApi } from '../hooks/features/cellSelection/gridCellSelectionInterfaces'; import type { DataGridPremiumProcessedProps } from './dataGridPremiumProps'; +import type { + GridDataSourcePremiumPrivateApi, + GridDataSourceApiPremium, +} from '../hooks/features/dataSource/models'; +import type { GridAggregationPrivateApi } from '../hooks/features/aggregation/gridAggregationInterfaces'; /** * The api of Data Grid Premium. @@ -29,7 +32,7 @@ export interface GridApiPremium GridExcelExportApi, GridAggregationApi, GridRowPinningApi, - GridDataSourceApi, + GridDataSourceApiPremium, GridCellSelectionApi, // APIs that are private in Community plan, but public in Pro and Premium plans GridRowMultiSelectionApi, @@ -38,5 +41,6 @@ export interface GridApiPremium export interface GridPrivateApiPremium extends GridApiPremium, GridPrivateOnlyApiCommon, - GridDataSourcePrivateApi, + GridDataSourcePremiumPrivateApi, + GridAggregationPrivateApi, GridDetailPanelPrivateApi {} diff --git a/packages/x-data-grid-premium/src/tests/dataSourceAggregation.DataGridPremium.test.tsx b/packages/x-data-grid-premium/src/tests/dataSourceAggregation.DataGridPremium.test.tsx new file mode 100644 index 0000000000000..f5cd1c40ee08d --- /dev/null +++ b/packages/x-data-grid-premium/src/tests/dataSourceAggregation.DataGridPremium.test.tsx @@ -0,0 +1,157 @@ +import * as React from 'react'; +import { useMockServer } from '@mui/x-data-grid-generator'; +import { createRenderer, waitFor, screen, within } from '@mui/internal-test-utils'; +import { expect } from 'chai'; +import { + DataGridPremium, + DataGridPremiumProps, + GridApi, + GridDataSource, + GridGetRowsParams, + useGridApiRef, + GRID_AGGREGATION_ROOT_FOOTER_ROW_ID, + GRID_ROOT_GROUP_ID, +} from '@mui/x-data-grid-premium'; +import { SinonSpy, spy } from 'sinon'; +import { getColumnHeaderCell } from 'test/utils/helperFn'; + +const isJSDOM = /jsdom/.test(window.navigator.userAgent); + +describe(' - Data source aggregation', () => { + const { render } = createRenderer(); + + let apiRef: React.MutableRefObject; + let getRowsSpy: SinonSpy; + let mockServer: ReturnType; + + function TestDataSourceAggregation( + props: Partial & { + getAggregatedValue?: GridDataSource['getAggregatedValue']; + }, + ) { + apiRef = useGridApiRef(); + const { getAggregatedValue: getAggregatedValueProp, ...rest } = props; + mockServer = useMockServer( + { rowLength: 10, maxColumns: 1 }, + { useCursorPagination: false, minDelay: 0, maxDelay: 0, verbose: false }, + ); + + const { fetchRows } = mockServer; + + const dataSource: GridDataSource = React.useMemo( + () => ({ + getRows: async (params: GridGetRowsParams) => { + const urlParams = new URLSearchParams({ + filterModel: JSON.stringify(params.filterModel), + sortModel: JSON.stringify(params.sortModel), + paginationModel: JSON.stringify(params.paginationModel), + aggregationModel: JSON.stringify(params.aggregationModel), + }); + + const getRowsResponse = await fetchRows( + `https://mui.com/x/api/data-grid?${urlParams.toString()}`, + ); + + return { + rows: getRowsResponse.rows, + rowCount: getRowsResponse.rowCount, + aggregateRow: getRowsResponse.aggregateRow, + }; + }, + getAggregatedValue: + getAggregatedValueProp ?? + ((row, field) => { + return row[`${field}Aggregate`]; + }), + }), + [fetchRows, getAggregatedValueProp], + ); + + getRowsSpy?.restore(); + getRowsSpy = spy(dataSource, 'getRows'); + + const baselineProps = { + unstable_dataSource: dataSource, + columns: mockServer.columns, + disableVirtualization: true, + aggregationFunctions: { + sum: { columnTypes: ['number'] }, + avg: { columnTypes: ['number'] }, + min: { columnTypes: ['number', 'date', 'dateTime'] }, + max: { columnTypes: ['number', 'date', 'dateTime'] }, + size: {}, + }, + }; + + return ( +
    + +
    + ); + } + + beforeEach(function beforeTest() { + if (isJSDOM) { + this.skip(); // Needs layout + } + }); + + it('should show aggregation option in the column menu', async () => { + const { user } = render(); + await user.click(within(getColumnHeaderCell(0)).getByLabelText('Menu')); + expect(screen.queryByLabelText('Aggregation')).not.to.equal(null); + }); + + it('should not show aggregation option in the column menu when no aggregation function is defined', async () => { + const { user } = render(); + await user.click(within(getColumnHeaderCell(0)).getByLabelText('Menu')); + expect(screen.queryByLabelText('Aggregation')).to.equal(null); + }); + + it('should provide the `aggregationModel` in the `getRows` params', async () => { + render( + , + ); + await waitFor(() => { + expect(getRowsSpy.callCount).to.be.greaterThan(0); + }); + expect(getRowsSpy.args[0][0].aggregationModel).to.deep.equal({ id: 'size' }); + }); + + it('should show the aggregation footer row when aggregation is enabled', async () => { + render( + , + ); + await waitFor(() => { + expect(Object.keys(apiRef.current.state.aggregation.lookup).length).to.be.greaterThan(0); + }); + expect(apiRef.current.state.rows.tree[GRID_AGGREGATION_ROOT_FOOTER_ROW_ID]).not.to.equal(null); + const footerRow = apiRef.current.state.aggregation.lookup[GRID_ROOT_GROUP_ID]; + expect(footerRow.id).to.deep.equal({ position: 'footer', value: 10 }); + }); + + it('should derive the aggregation values using `dataSource.getAggregatedValue`', async () => { + render( + 'Agg value'} + />, + ); + await waitFor(() => { + expect(Object.keys(apiRef.current.state.aggregation.lookup).length).to.be.greaterThan(0); + }); + expect(apiRef.current.state.aggregation.lookup[GRID_ROOT_GROUP_ID].id.value).to.equal( + 'Agg value', + ); + }); +}); diff --git a/packages/x-data-grid-pro/src/DataGridPro/useDataGridProComponent.tsx b/packages/x-data-grid-pro/src/DataGridPro/useDataGridProComponent.tsx index c423c5f58d566..58a36ea9d2b21 100644 --- a/packages/x-data-grid-pro/src/DataGridPro/useDataGridProComponent.tsx +++ b/packages/x-data-grid-pro/src/DataGridPro/useDataGridProComponent.tsx @@ -82,10 +82,8 @@ import { rowPinningStateInitializer, } from '../hooks/features/rowPinning/useGridRowPinning'; import { useGridRowPinningPreProcessors } from '../hooks/features/rowPinning/useGridRowPinningPreProcessors'; -import { - useGridDataSource, - dataSourceStateInitializer, -} from '../hooks/features/dataSource/useGridDataSource'; +import { useGridDataSourcePro as useGridDataSource } from '../hooks/features/dataSource/useGridDataSourcePro'; +import { dataSourceStateInitializer } from '../hooks/features/dataSource/useGridDataSourceBase'; import { useGridDataSourceLazyLoader } from '../hooks/features/serverSideLazyLoader/useGridDataSourceLazyLoader'; export const useDataGridProComponent = ( diff --git a/packages/x-data-grid-pro/src/hooks/features/dataSource/cache.ts b/packages/x-data-grid-pro/src/hooks/features/dataSource/cache.ts index e6e0c02e48d35..4e9757c2a4456 100644 --- a/packages/x-data-grid-pro/src/hooks/features/dataSource/cache.ts +++ b/packages/x-data-grid-pro/src/hooks/features/dataSource/cache.ts @@ -1,4 +1,4 @@ -import { GridGetRowsParams, GridGetRowsResponse } from '../../../models'; +import { GridGetRowsParams, GridGetRowsResponse } from '@mui/x-data-grid/internals'; export type GridDataSourceCacheDefaultConfig = { /** @@ -7,9 +7,16 @@ export type GridDataSourceCacheDefaultConfig = { * @default 300000 (5 minutes) */ ttl?: number; + /** + * Function to generate a cache key from the params. + * @param {GridGetRowsParams} params The params to generate the cache key from. + * @returns {string} The cache key. + * @default `getKeyDefault()` + */ + getKey?: (params: GridGetRowsParams) => string; }; -export function getKey(params: GridGetRowsParams) { +export function getKeyDefault(params: GridGetRowsParams) { return JSON.stringify([ params.filterModel, params.sortModel, @@ -25,19 +32,22 @@ export class GridDataSourceCacheDefault { private ttl: number; - constructor({ ttl = 300000 }: GridDataSourceCacheDefaultConfig) { + private getKey: (params: GridGetRowsParams) => string; + + constructor({ ttl = 300000, getKey = getKeyDefault }: GridDataSourceCacheDefaultConfig) { this.cache = {}; this.ttl = ttl; + this.getKey = getKey; } set(key: GridGetRowsParams, value: GridGetRowsResponse) { - const keyString = getKey(key); + const keyString = this.getKey(key); const expiry = Date.now() + this.ttl; this.cache[keyString] = { value, expiry }; } get(key: GridGetRowsParams): GridGetRowsResponse | undefined { - const keyString = getKey(key); + const keyString = this.getKey(key); const entry = this.cache[keyString]; if (!entry) { return undefined; diff --git a/packages/x-data-grid-pro/src/hooks/features/dataSource/interfaces.ts b/packages/x-data-grid-pro/src/hooks/features/dataSource/interfaces.ts index 08eaf7c33f42d..c83b5f8219552 100644 --- a/packages/x-data-grid-pro/src/hooks/features/dataSource/interfaces.ts +++ b/packages/x-data-grid-pro/src/hooks/features/dataSource/interfaces.ts @@ -1,5 +1,5 @@ import { GridRowId } from '@mui/x-data-grid'; -import { GridDataSourceCache, GridGetRowsParams } from '../../../models'; +import { GridDataSourceCache, GridGetRowsParams } from '@mui/x-data-grid/internals'; export interface GridDataSourceState { loading: Record; @@ -26,7 +26,7 @@ export interface GridDataSourceApiBase { * Fetches the rows from the server. * If no `parentId` option is provided, it fetches the root rows. * Any missing parameter from `params` will be filled from the state (sorting, filtering, etc.). - * @param {GridRowId} parentId The id of the parent node. + * @param {GridRowId} parentId The id of the parent node (default: `GRID_ROOT_GROUP_ID`). * @param {Partial} params Request parameters override. */ fetchRows: (parentId?: GridRowId, params?: Partial) => void; diff --git a/packages/x-data-grid-pro/src/hooks/features/dataSource/useGridDataSource.ts b/packages/x-data-grid-pro/src/hooks/features/dataSource/useGridDataSourceBase.ts similarity index 90% rename from packages/x-data-grid-pro/src/hooks/features/dataSource/useGridDataSource.ts rename to packages/x-data-grid-pro/src/hooks/features/dataSource/useGridDataSourceBase.ts index d13d64e1895d7..d98f319e7b2b1 100644 --- a/packages/x-data-grid-pro/src/hooks/features/dataSource/useGridDataSource.ts +++ b/packages/x-data-grid-pro/src/hooks/features/dataSource/useGridDataSourceBase.ts @@ -1,8 +1,6 @@ import * as React from 'react'; import useLazyRef from '@mui/utils/useLazyRef'; import { - useGridApiEventHandler, - useGridApiMethod, GridDataSourceGroupNode, useGridSelector, gridPaginationModelSelector, @@ -15,7 +13,7 @@ import { GridStateInitializer, GridStrategyGroup, GridStrategyProcessor, - useGridRegisterStrategyProcessor, + GridDataSourceCache, runIf, } from '@mui/x-data-grid/internals'; import { GridPrivateApiPro } from '../../../models/gridApiPro'; @@ -28,7 +26,6 @@ import { NestedDataManager, RequestStatus, } from './utils'; -import { GridDataSourceCache } from '../../../models'; import { GridDataSourceCacheDefault, GridDataSourceCacheDefaultConfig } from './cache'; const INITIAL_STATE = { @@ -59,8 +56,8 @@ export const dataSourceStateInitializer: GridStateInitializer = (state) => { }; }; -export const useGridDataSource = ( - apiRef: React.MutableRefObject, +export const useGridDataSourceBase = ( + apiRef: React.MutableRefObject, props: Pick< DataGridProProcessedProps, | 'unstable_dataSource' @@ -73,6 +70,9 @@ export const useGridDataSource = ( | 'treeData' | 'unstable_lazyLoading' >, + options: { + cacheOptions?: GridDataSourceCacheDefaultConfig; + } = {}, ) => { const setStrategyAvailability = React.useCallback(() => { apiRef.current.setStrategyAvailability( @@ -103,7 +103,7 @@ export const useGridDataSource = ( return new CacheChunkManager(cacheChunkSize); }).current; const [cache, setCache] = React.useState(() => - getCache(props.unstable_dataSourceCache), + getCache(props.unstable_dataSourceCache, options.cacheOptions), ); const fetchRows = React.useCallback( @@ -344,6 +344,11 @@ export const useGridDataSource = ( apiRef.current.setRowCount(response.rowCount); } apiRef.current.setRows(response.rows); + apiRef.current.unstable_applyPipeProcessors( + 'processDataSourceRows', + { params: params.fetchParams, response }, + true, + ); }, [apiRef], ); @@ -371,42 +376,18 @@ export const useGridDataSource = ( resetDataSourceState, }; - useGridApiMethod(apiRef, dataSourceApi, 'public'); - useGridApiMethod(apiRef, dataSourcePrivateApi, 'private'); - - useGridRegisterStrategyProcessor( - apiRef, - DataSourceRowsUpdateStrategy.Default, - 'dataSourceRowsUpdate', - handleDataUpdate, - ); - - useGridApiEventHandler(apiRef, 'strategyAvailabilityChange', handleStrategyActivityChange); - useGridApiEventHandler( - apiRef, - 'sortModelChange', - runIf(defaultRowsUpdateStrategyActive, () => fetchRows()), - ); - useGridApiEventHandler( - apiRef, - 'filterModelChange', - runIf(defaultRowsUpdateStrategyActive, () => fetchRows()), - ); - useGridApiEventHandler( - apiRef, - 'paginationModelChange', - runIf(defaultRowsUpdateStrategyActive, () => fetchRows()), - ); - const isFirstRender = React.useRef(true); React.useEffect(() => { if (isFirstRender.current) { isFirstRender.current = false; return; } - const newCache = getCache(props.unstable_dataSourceCache); + if (props.unstable_dataSourceCache === undefined) { + return; + } + const newCache = getCache(props.unstable_dataSourceCache, options.cacheOptions); setCache((prevCache) => (prevCache !== newCache ? newCache : prevCache)); - }, [props.unstable_dataSourceCache]); + }, [props.unstable_dataSourceCache, options.cacheOptions]); React.useEffect(() => { setStrategyAvailability(); @@ -430,4 +411,19 @@ export const useGridDataSource = ( scheduledGroups.current = groupsToAutoFetch.length; } }, [apiRef, nestedDataManager, groupsToAutoFetch]); + + return { + api: { public: dataSourceApi, private: dataSourcePrivateApi }, + strategyProcessor: { + strategyName: DataSourceRowsUpdateStrategy.Default, + group: 'dataSourceRowsUpdate' as const, + processor: handleDataUpdate, + }, + events: { + strategyAvailabilityChange: handleStrategyActivityChange, + sortModelChange: runIf(defaultRowsUpdateStrategyActive, () => fetchRows()), + filterModelChange: runIf(defaultRowsUpdateStrategyActive, () => fetchRows()), + paginationModelChange: runIf(defaultRowsUpdateStrategyActive, () => fetchRows()), + }, + }; }; diff --git a/packages/x-data-grid-pro/src/hooks/features/dataSource/useGridDataSourcePro.ts b/packages/x-data-grid-pro/src/hooks/features/dataSource/useGridDataSourcePro.ts new file mode 100644 index 0000000000000..5b3ee2b7c4c3d --- /dev/null +++ b/packages/x-data-grid-pro/src/hooks/features/dataSource/useGridDataSourcePro.ts @@ -0,0 +1,31 @@ +import * as React from 'react'; +import { + useGridApiEventHandler as addEventHandler, + useGridApiMethod, + GridEventLookup, +} from '@mui/x-data-grid'; +import { useGridRegisterStrategyProcessor } from '@mui/x-data-grid/internals'; +import { GridPrivateApiPro } from '../../../models/gridApiPro'; +import { DataGridProProcessedProps } from '../../../models/dataGridProProps'; +import { useGridDataSourceBase } from './useGridDataSourceBase'; + +export const useGridDataSourcePro = ( + apiRef: React.MutableRefObject, + props: DataGridProProcessedProps, +) => { + const { api, strategyProcessor, events } = useGridDataSourceBase(apiRef, props); + + useGridApiMethod(apiRef, api.public, 'public'); + useGridApiMethod(apiRef, api.private, 'private'); + + useGridRegisterStrategyProcessor( + apiRef, + strategyProcessor.strategyName, + strategyProcessor.group, + strategyProcessor.processor, + ); + + Object.entries(events).forEach(([event, handler]) => { + addEventHandler(apiRef, event as keyof GridEventLookup, handler); + }); +}; diff --git a/packages/x-data-grid-pro/src/hooks/features/dataSource/utils.ts b/packages/x-data-grid-pro/src/hooks/features/dataSource/utils.ts index ce2d8de133391..d542538f584da 100644 --- a/packages/x-data-grid-pro/src/hooks/features/dataSource/utils.ts +++ b/packages/x-data-grid-pro/src/hooks/features/dataSource/utils.ts @@ -1,5 +1,6 @@ import { GridRowId } from '@mui/x-data-grid'; -import { GridPrivateApiPro, GridGetRowsParams, GridGetRowsResponse } from '../../../models'; +import { GridGetRowsParams, GridGetRowsResponse } from '@mui/x-data-grid/internals'; +import { GridPrivateApiPro } from '../../../models'; const MAX_CONCURRENT_REQUESTS = Infinity; diff --git a/packages/x-data-grid-pro/src/hooks/features/index.ts b/packages/x-data-grid-pro/src/hooks/features/index.ts index 456da75b157c1..a09be50773318 100644 --- a/packages/x-data-grid-pro/src/hooks/features/index.ts +++ b/packages/x-data-grid-pro/src/hooks/features/index.ts @@ -5,5 +5,5 @@ export * from './rowReorder'; export * from './treeData'; export * from './detailPanel'; export * from './rowPinning'; -export * from './dataSource/interfaces'; +export type { GridDataSourceState } from './dataSource/interfaces'; export { GridDataSourceCacheDefault } from './dataSource/cache'; diff --git a/packages/x-data-grid-pro/src/hooks/features/serverSideLazyLoader/useGridDataSourceLazyLoader.ts b/packages/x-data-grid-pro/src/hooks/features/serverSideLazyLoader/useGridDataSourceLazyLoader.ts index c36a874f5ef82..d6f0b1d800f57 100644 --- a/packages/x-data-grid-pro/src/hooks/features/serverSideLazyLoader/useGridDataSourceLazyLoader.ts +++ b/packages/x-data-grid-pro/src/hooks/features/serverSideLazyLoader/useGridDataSourceLazyLoader.ts @@ -285,6 +285,11 @@ export const useGridDataSourceLazyLoader = ( addSkeletonRows(); privateApiRef.current.setLoading(false); + privateApiRef.current.unstable_applyPipeProcessors( + 'processDataSourceRows', + { params: params.fetchParams, response }, + false, + ); privateApiRef.current.requestPipeProcessorsApplication('hydrateRows'); }, [ diff --git a/packages/x-data-grid-pro/src/index.ts b/packages/x-data-grid-pro/src/index.ts index 0b9505fd84d70..e5910805e2ba0 100644 --- a/packages/x-data-grid-pro/src/index.ts +++ b/packages/x-data-grid-pro/src/index.ts @@ -35,3 +35,17 @@ export { export { GridColumnHeaders } from './components/GridColumnHeaders'; export type { GridColumnHeadersProps } from './components/GridColumnHeaders'; + +// Reexportable exports +export type { + GridGetRowsParams, + GridGetRowsResponse, + GridDataSource, + GridDataSourceCache, +} from '@mui/x-data-grid/internals'; + +export type { + GridDataSourceApiBase, + GridDataSourceApi, + GridDataSourcePrivateApi, +} from './hooks/features/dataSource/interfaces'; diff --git a/packages/x-data-grid-pro/src/internals/index.ts b/packages/x-data-grid-pro/src/internals/index.ts index f821f34170111..6db29e8ae55d2 100644 --- a/packages/x-data-grid-pro/src/internals/index.ts +++ b/packages/x-data-grid-pro/src/internals/index.ts @@ -45,9 +45,9 @@ export { useGridLazyLoader } from '../hooks/features/lazyLoader/useGridLazyLoade export { useGridLazyLoaderPreProcessors } from '../hooks/features/lazyLoader/useGridLazyLoaderPreProcessors'; export { useGridDataSourceLazyLoader } from '../hooks/features/serverSideLazyLoader/useGridDataSourceLazyLoader'; export { - useGridDataSource, + useGridDataSourceBase, dataSourceStateInitializer, -} from '../hooks/features/dataSource/useGridDataSource'; +} from '../hooks/features/dataSource/useGridDataSourceBase'; export type { GridExperimentalProFeatures, diff --git a/packages/x-data-grid-pro/src/models/gridApiPro.ts b/packages/x-data-grid-pro/src/models/gridApiPro.ts index 07f0d250f57a5..f0e0159eaf799 100644 --- a/packages/x-data-grid-pro/src/models/gridApiPro.ts +++ b/packages/x-data-grid-pro/src/models/gridApiPro.ts @@ -11,9 +11,11 @@ import type { GridDetailPanelApi, GridRowPinningApi, GridDetailPanelPrivateApi, +} from '../hooks'; +import type { GridDataSourceApi, GridDataSourcePrivateApi, -} from '../hooks'; +} from '../hooks/features/dataSource/interfaces'; import type { DataGridProProcessedProps } from './dataGridProProps'; /** diff --git a/packages/x-data-grid-pro/src/models/index.ts b/packages/x-data-grid-pro/src/models/index.ts index 8110b6c70a918..36deff5c944b6 100644 --- a/packages/x-data-grid-pro/src/models/index.ts +++ b/packages/x-data-grid-pro/src/models/index.ts @@ -1,9 +1,3 @@ -export type { - GridGetRowsParams, - GridGetRowsResponse, - GridDataSource, - GridDataSourceCache, -} from '@mui/x-data-grid/internals'; export * from './gridApiPro'; export * from './gridGroupingColDefOverride'; export * from './gridRowScrollEndParams'; diff --git a/packages/x-data-grid-pro/src/tests/dataSource.DataGridPro.test.tsx b/packages/x-data-grid-pro/src/tests/dataSource.DataGridPro.test.tsx index fbbc993501f36..ec14b20f1daa2 100644 --- a/packages/x-data-grid-pro/src/tests/dataSource.DataGridPro.test.tsx +++ b/packages/x-data-grid-pro/src/tests/dataSource.DataGridPro.test.tsx @@ -14,13 +14,13 @@ import { } from '@mui/x-data-grid-pro'; import { SinonSpy, spy } from 'sinon'; import { describeSkipIf, isJSDOM } from 'test/utils/skipIf'; -import { getKey } from '../hooks/features/dataSource/cache'; +import { getKeyDefault } from '../hooks/features/dataSource/cache'; const cache = new Map(); const testCache: GridDataSourceCache = { - set: (key, value) => cache.set(getKey(key), value), - get: (key) => cache.get(getKey(key)), + set: (key, value) => cache.set(getKeyDefault(key), value), + get: (key) => cache.get(getKeyDefault(key)), clear: () => cache.clear(), }; diff --git a/packages/x-data-grid/src/hooks/core/pipeProcessing/gridPipeProcessingApi.ts b/packages/x-data-grid/src/hooks/core/pipeProcessing/gridPipeProcessingApi.ts index 78300aa77e2a1..7b9eb49a37b0b 100644 --- a/packages/x-data-grid/src/hooks/core/pipeProcessing/gridPipeProcessingApi.ts +++ b/packages/x-data-grid/src/hooks/core/pipeProcessing/gridPipeProcessingApi.ts @@ -20,7 +20,7 @@ import { import { GridRowEntry, GridRowId } from '../../../models/gridRows'; import { GridHydrateRowsValue } from '../../features/rows/gridRowsInterfaces'; import { GridPreferencePanelsValue } from '../../features/preferencesPanel'; -import { GridGetRowsParams } from '../../../models/gridDataSource'; +import { GridGetRowsParams, GridGetRowsResponse } from '../../../models/gridDataSource'; import { HeightEntry } from '../../features/rows/gridRowsMetaInterfaces'; export type GridPipeProcessorGroup = keyof GridPipeProcessingLookup; @@ -68,6 +68,11 @@ export interface GridPipeProcessingLookup { context: { event: React.KeyboardEvent; cellParams: GridCellParams; editMode: GridEditMode }; }; isColumnPinned: { value: GridPinnedColumnPosition | false; context: string }; + processDataSourceRows: { + value: { params: GridGetRowsParams; response: GridGetRowsResponse }; + // `true` if the row hydration should be re-applied + context: boolean; + }; } export type GridPipeProcessor

    = ( diff --git a/packages/x-data-grid/src/internals/index.ts b/packages/x-data-grid/src/internals/index.ts index 60848709e1927..6b7457bd3c945 100644 --- a/packages/x-data-grid/src/internals/index.ts +++ b/packages/x-data-grid/src/internals/index.ts @@ -21,7 +21,10 @@ export { useGridRegisterStrategyProcessor, GRID_DEFAULT_STRATEGY, } from '../hooks/core/strategyProcessing'; -export type { GridStrategyProcessor } from '../hooks/core/strategyProcessing'; +export type { + GridStrategyProcessor, + GridStrategyProcessorName, +} from '../hooks/core/strategyProcessing'; export { useGridInitialization } from '../hooks/core/useGridInitialization'; export { unwrapPrivateAPI } from '../hooks/core/useGridApiInitialization'; diff --git a/scripts/x-data-grid-premium.exports.json b/scripts/x-data-grid-premium.exports.json index b19e1c6650c81..e9d6c4df85d34 100644 --- a/scripts/x-data-grid-premium.exports.json +++ b/scripts/x-data-grid-premium.exports.json @@ -94,6 +94,7 @@ { "name": "GridAggregationApi", "kind": "Interface" }, { "name": "GridAggregationCellMeta", "kind": "Interface" }, { "name": "GridAggregationFunction", "kind": "Interface" }, + { "name": "GridAggregationFunctionDataSource", "kind": "Interface" }, { "name": "GridAggregationGetCellValueParams", "kind": "Interface" }, { "name": "GridAggregationHeaderMeta", "kind": "Interface" }, { "name": "GridAggregationInitialState", "kind": "Interface" }, From 6412b8c0a29f205a76a233ec4f07d89d179a4d8f Mon Sep 17 00:00:00 2001 From: Armin Mehinovic <4390250+arminmeh@users.noreply.github.com> Date: Thu, 9 Jan 2025 15:49:00 +0100 Subject: [PATCH 24/25] v8.0.0-alpha.7 (#16110) Signed-off-by: Armin Mehinovic <4390250+arminmeh@users.noreply.github.com> Co-authored-by: Bilal Shafi Co-authored-by: Lukas Tyla Co-authored-by: Alexandre Fauquette <45398769+alexfauquette@users.noreply.github.com> --- CHANGELOG.md | 126 ++++++++++++++++++++ package.json | 2 +- packages/x-charts-pro/package.json | 2 +- packages/x-charts-vendor/package.json | 2 +- packages/x-charts/package.json | 2 +- packages/x-codemod/package.json | 2 +- packages/x-data-grid-generator/package.json | 2 +- packages/x-data-grid-premium/package.json | 2 +- packages/x-data-grid-pro/package.json | 2 +- packages/x-data-grid/package.json | 2 +- packages/x-date-pickers-pro/package.json | 2 +- packages/x-date-pickers/package.json | 2 +- packages/x-internals/package.json | 2 +- packages/x-license/package.json | 2 +- packages/x-tree-view-pro/package.json | 2 +- packages/x-tree-view/package.json | 2 +- 16 files changed, 141 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8e6af73aad21..ab86f3fc1ea91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,132 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## 8.0.0-alpha.7 + +_Jan 9, 2025_ + +We'd like to offer a big thanks to the 13 contributors who made this release possible. Here are some highlights ✨: + +- 📊 Charts legend is now an HTML element which can be styled more easily +- 💫 Support [aggregation with server-side data](/x/react-data-grid/server-side-data/aggregation/) +- 🏎️ Improve Data Grid aggregation performance +- 🌍 Add Chinese (Taiwan) (zh-TW) locale on the Date and Time Pickers +- 🌍 Improve Norwegian (nb-NO) locale on the Date and Time Pickers +- 🐞 Bugfixes + +Special thanks go out to the community contributors who have helped make this release possible: +@derek-0000, @josteinjhauge, @k-rajat19, @nusr, @tomashauser. +Following are all team members who have contributed to this release: +@cherniavskii, @flaviendelangle, @JCQuintas, @LukasTy, @MBilalShafi, @arminmeh, @romgrk, @oliviertassinari. + + + +### Data Grid + +#### `@mui/x-data-grid@8.0.0-alpha.7` + +- [DataGrid] Improve React 19 support (#15769) @LukasTy +- [DataGrid] Add `name` attribute to the checkbox selection column (#15178) @derek-0000 +- [DataGrid] Fix number filter field formatting values while typing (#16062) @arminmeh +- [DataGrid] Fix select all checkbox state reset with server side data (#16034) @MBilalShafi +- [DataGrid] Refactor: create base button props (#15930) @romgrk +- [DataGrid] Refactor: create tooltip props (#16086) @romgrk +- [DataGrid] Fix TS error (#16046) @cherniavskii + +#### `@mui/x-data-grid-pro@8.0.0-alpha.7` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan') + +Same changes as in `@mui/x-data-grid@8.0.0-alpha.7`. + +#### `@mui/x-data-grid-premium@8.0.0-alpha.7` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan') + +Same changes as in `@mui/x-data-grid-pro@8.0.0-alpha.7`, plus: + +- [DataGridPremium] Improve aggregation performance for multiple columns (#16097) @cherniavskii +- [DataGridPremium] Make Aggregation keyboard accessible in the column menu (#15934) @k-rajat19 +- [DataGridPremium] Server-side aggregation with data source (#15741) @MBilalShafi + +### Date and Time Pickers + +#### Breaking changes + +- The `date-fns` and `date-fns-jalali` date library adapters have been renamed to better align with the current stable major versions — [Learn more](https://next.mui.com/x/migration/migration-pickers-v7/#✅-rename-date-fns-adapter-imports) +- Update default `closeOnSelect` and Action Bar `actions` values - [Learn more](https://next.mui.com/x/migration/migration-pickers-v7/#update-default-closeonselect-and-action-bar-actions-values) +- The component passed to the `layout` slot no longer receives the `value`, `onChange` and `onSelectShortcut` props — [Learn more](https://next.mui.com/x/migration/migration-pickers-v7/#slot-layout). +- The component passed to the `toolbar` slot no longer receives the `value`, `onChange` and `isLandscape` props — [Learn more](https://next.mui.com/x/migration/migration-pickers-v7/#slot-toolbar). +- The component passed to the `shortcuts` slot no longer receives the `onChange`, `isValid` and `isLandscape` props — [Learn more](https://next.mui.com/x/migration/migration-pickers-v7/#slot-shortcuts). +- The `PickerShortcutChangeImportance` type has been renamed `PickerChangeImportance` — [Learn more](https://next.mui.com/x/migration/migration-pickers-v7/#renamed-variables-and-types). +- The component passed to the `layout` slot no longer receives the `rangePosition` and `onRangePositionChange` on range pickers — [Learn more](https://next.mui.com/x/migration/migration-pickers-v7/#slot-layout). +- The component passed to the `toolbar` slot no longer receives the `rangePosition` and `onRangePositionChange` on range pickers — [Learn more](https://next.mui.com/x/migration/migration-pickers-v7/#slot-toolbar). +- The component passed to the `tabs` slot no longer receives the `rangePosition` and `onRangePositionChange` on range pickers — [Learn more](https://next.mui.com/x/migration/migration-pickers-v7/#slot-tabs). + +#### `@mui/x-date-pickers@8.0.0-alpha.7` + +- [fields] Handle focusing container with `inputRef.current.focus` on `accessibleFieldDOMStructure` (#15985) @LukasTy +- [pickers] Always use `setValue` internally to update the picker value (#16056) @flaviendelangle +- [pickers] Create a new context to pass the range position props to the layout components and to the views (#15846) @flaviendelangle +- [pickers] Introduce a new concept of `manager` (#15339) @flaviendelangle +- [pickers] Improve React 19 support (#15769) @LukasTy +- [pickers] Memoize `` (#16071) @LukasTy +- [pickers] Remove `NonEmptyDateRange` type (#16035) @flaviendelangle +- [pickers] Rename `AdapterDateFns` into `AdapterDateFnsV2` and `AdapterDateFnsV3` into `AdapterDateFns` (#16082) @LukasTy +- [pickers] Rename `ctx.onViewChange` to `ctx.setView` and add it to the actions context (#16044) @flaviendelangle +- [pickers] Support `date-fns-jalali` v4 (#16011) @LukasTy +- [pickers] Update `closeOnSelect` and `actionBar.actions` default values (#15944) @LukasTy +- [pickers] Use `usePickerContext()` and `usePickerActionsContext()` instead of passing props to the `shortcuts` and `toolbar` slots (#15948) @flaviendelangle +- [l10n] Add Chinese (Taiwan) (zh-TW) locale (#16033) @nusr +- [l10n] Improve Norwegian (nb-NO) locale (#16089) @josteinjhauge + +#### `@mui/x-date-pickers-pro@8.0.0-alpha.7` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan') + +Same changes as in `@mui/x-date-pickers@8.0.0-alpha.7`. + +### Charts + +#### Breaking changes + +- Removed `DefaultChartsLegend` component, since it is now easier to create custom legends — [Learn more](https://next.mui.com/x/react-charts/components/#html-components). +- The default legend is now an HTML element and can be styled more easily. +- The `width` and `height` properties of the charts now only apply to the `svg` element, and not their wrappers, this might cause some layout shifts. +- `slotProps.legend.direction` now accepts `'horizontal' | 'vertical'` instead of `'row' | 'column'` — [Learn more](https://next.mui.com/x/migration/migration-charts-v7/#legend-direction-value-change-✅). +- The `getSeriesToDisplay` function was removed in favor of the `useLegend` hook. — [Learn more](https://next.mui.com/x/migration/migration-charts-v7/#the-getseriestodisplay-function-was-removed). + +#### `@mui/x-charts@8.0.0-alpha.7` + +- [charts] New HTML legend & styles (#15733) @JCQuintas +- [charts] Improve React 19 support (#15769) @LukasTy +- [charts] Fix 301 redirection in the API documentation @oliviertassinari + +#### `@mui/x-charts-pro@8.0.0-alpha.7` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan') + +Same changes as in `@mui/x-charts@8.0.0-alpha.7`. + +### Tree View + +#### `@mui/x-tree-view@8.0.0-alpha.7` + +- [TreeView] Improve React 19 support (#15769) @LukasTy + +#### `@mui/x-tree-view-pro@8.0.0-alpha.7` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan') + +Same changes as in `@mui/x-tree-view@8.0.0-alpha.7`. + +### Docs + +- [docs] Fix `EditingWithDatePickers` demo (#15967) @k-rajat19 +- [docs] Fix inconsistent multi input range field separators (#16043) @flaviendelangle +- [docs] Fix non-existing "adapter" property of `LocalizationProvider` (#16084) @tomashauser +- [docs] Refactor Data Grid with Date Pickers example (#15992) @LukasTy +- [docs] Unify the wording of the pickers slots breaking changes (#16036) @flaviendelangle + +### Core + +- [core] Clarify the release strategy (#16014) @MBilalShafi +- [core] Small fixes on docs @oliviertassinari +- [core] Sync with other repos @oliviertassinari +- [core] Update the `release:version` docs (#16038) @cherniavskii +- [code-infra] Add `testSkipIf` and `describeSkipIf` (#16049) @JCQuintas +- [test] Stabilize flaky Data Grid tests (#16053) @LukasTy + ## 8.0.0-alpha.6 _Dec 26, 2024_ diff --git a/package.json b/package.json index c84ab7265ba46..82c549817cd7a 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "8.0.0-alpha.6", + "version": "8.0.0-alpha.7", "private": true, "scripts": { "preinstall": "npx only-allow pnpm", diff --git a/packages/x-charts-pro/package.json b/packages/x-charts-pro/package.json index a9c9de0ca921b..5a7e12a30e73d 100644 --- a/packages/x-charts-pro/package.json +++ b/packages/x-charts-pro/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-charts-pro", - "version": "8.0.0-alpha.6", + "version": "8.0.0-alpha.7", "description": "The Pro plan edition of the Charts components (MUI X).", "author": "MUI Team", "main": "src/index.ts", diff --git a/packages/x-charts-vendor/package.json b/packages/x-charts-vendor/package.json index 1c0b3758191bd..beb6650fb488c 100644 --- a/packages/x-charts-vendor/package.json +++ b/packages/x-charts-vendor/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-charts-vendor", - "version": "8.0.0-alpha.5", + "version": "8.0.0-alpha.7", "description": "Vendored dependencies for MUI X Charts", "author": "MUI Team", "keywords": [ diff --git a/packages/x-charts/package.json b/packages/x-charts/package.json index 03562671c5200..6fdc3011cb739 100644 --- a/packages/x-charts/package.json +++ b/packages/x-charts/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-charts", - "version": "8.0.0-alpha.6", + "version": "8.0.0-alpha.7", "description": "The community edition of the Charts components (MUI X).", "author": "MUI Team", "main": "src/index.js", diff --git a/packages/x-codemod/package.json b/packages/x-codemod/package.json index c12b47838aa14..4ba5dbdf60d34 100644 --- a/packages/x-codemod/package.json +++ b/packages/x-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-codemod", - "version": "8.0.0-alpha.6", + "version": "8.0.0-alpha.7", "bin": "./codemod.js", "private": false, "author": "MUI Team", diff --git a/packages/x-data-grid-generator/package.json b/packages/x-data-grid-generator/package.json index 09cf9d7b0b063..65778ff4a9c23 100644 --- a/packages/x-data-grid-generator/package.json +++ b/packages/x-data-grid-generator/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-data-grid-generator", - "version": "8.0.0-alpha.6", + "version": "8.0.0-alpha.7", "description": "Generate fake data for demo purposes only.", "author": "MUI Team", "main": "src/index.ts", diff --git a/packages/x-data-grid-premium/package.json b/packages/x-data-grid-premium/package.json index 29e609742bd06..0e6a91e96f627 100644 --- a/packages/x-data-grid-premium/package.json +++ b/packages/x-data-grid-premium/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-data-grid-premium", - "version": "8.0.0-alpha.6", + "version": "8.0.0-alpha.7", "description": "The Premium plan edition of the Data Grid Components (MUI X).", "author": "MUI Team", "main": "src/index.ts", diff --git a/packages/x-data-grid-pro/package.json b/packages/x-data-grid-pro/package.json index 107890045a297..65e8daee41016 100644 --- a/packages/x-data-grid-pro/package.json +++ b/packages/x-data-grid-pro/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-data-grid-pro", - "version": "8.0.0-alpha.6", + "version": "8.0.0-alpha.7", "description": "The Pro plan edition of the Data Grid components (MUI X).", "author": "MUI Team", "main": "src/index.ts", diff --git a/packages/x-data-grid/package.json b/packages/x-data-grid/package.json index 572fc9b3efff6..7f97269acefb8 100644 --- a/packages/x-data-grid/package.json +++ b/packages/x-data-grid/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-data-grid", - "version": "8.0.0-alpha.6", + "version": "8.0.0-alpha.7", "description": "The Community plan edition of the Data Grid components (MUI X).", "author": "MUI Team", "main": "src/index.ts", diff --git a/packages/x-date-pickers-pro/package.json b/packages/x-date-pickers-pro/package.json index 05c6ac1b23d79..7d1110749809e 100644 --- a/packages/x-date-pickers-pro/package.json +++ b/packages/x-date-pickers-pro/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-date-pickers-pro", - "version": "8.0.0-alpha.6", + "version": "8.0.0-alpha.7", "description": "The Pro plan edition of the Date and Time Picker components (MUI X).", "author": "MUI Team", "main": "src/index.ts", diff --git a/packages/x-date-pickers/package.json b/packages/x-date-pickers/package.json index e76bb93630d2a..56781abac6f33 100644 --- a/packages/x-date-pickers/package.json +++ b/packages/x-date-pickers/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-date-pickers", - "version": "8.0.0-alpha.6", + "version": "8.0.0-alpha.7", "description": "The community edition of the Date and Time Picker components (MUI X).", "author": "MUI Team", "main": "src/index.ts", diff --git a/packages/x-internals/package.json b/packages/x-internals/package.json index 429678f13ed90..7f6bf17b78491 100644 --- a/packages/x-internals/package.json +++ b/packages/x-internals/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-internals", - "version": "8.0.0-alpha.6", + "version": "8.0.0-alpha.7", "description": "Utility functions for the MUI X packages (internal use only).", "author": "MUI Team", "license": "MIT", diff --git a/packages/x-license/package.json b/packages/x-license/package.json index 25e1d6ea4af62..4d80321e87540 100644 --- a/packages/x-license/package.json +++ b/packages/x-license/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-license", - "version": "8.0.0-alpha.6", + "version": "8.0.0-alpha.7", "description": "MUI X License verification", "author": "MUI Team", "main": "src/index.ts", diff --git a/packages/x-tree-view-pro/package.json b/packages/x-tree-view-pro/package.json index 5b269168b652a..9476c29501938 100644 --- a/packages/x-tree-view-pro/package.json +++ b/packages/x-tree-view-pro/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-tree-view-pro", - "version": "8.0.0-alpha.6", + "version": "8.0.0-alpha.7", "description": "The Pro plan edition of the Tree View components (MUI X).", "author": "MUI Team", "main": "src/index.ts", diff --git a/packages/x-tree-view/package.json b/packages/x-tree-view/package.json index bc8cfb25a0d8e..edf0358f35f56 100644 --- a/packages/x-tree-view/package.json +++ b/packages/x-tree-view/package.json @@ -1,6 +1,6 @@ { "name": "@mui/x-tree-view", - "version": "8.0.0-alpha.6", + "version": "8.0.0-alpha.7", "description": "The community edition of the Tree View components (MUI X).", "author": "MUI Team", "main": "src/index.ts", From 9e07e0f0f997640bc41128050ded2e04d6872024 Mon Sep 17 00:00:00 2001 From: Flavien DELANGLE Date: Fri, 10 Jan 2025 09:18:12 +0100 Subject: [PATCH 25/25] [pickers] Use context to pass props from the picker to the field (#16042) Signed-off-by: Flavien DELANGLE Co-authored-by: Lukas Tyla --- .../calendar-systems/AdapterHijri.js | 13 +-- .../calendar-systems/AdapterHijri.tsx | 13 +-- .../BrowserV7MultiInputRangeField.js | 12 --- .../BrowserV7MultiInputRangeField.tsx | 12 --- .../date-pickers/custom-field/JoyV6Field.js | 6 +- .../date-pickers/custom-field/JoyV6Field.tsx | 6 +- .../custom-field/JoyV6MultiInputRangeField.js | 13 +-- .../JoyV6MultiInputRangeField.tsx | 13 +-- .../JoyV6SingleInputRangeField.js | 6 +- .../JoyV6SingleInputRangeField.tsx | 6 +- .../MaterialDatePicker.js | 8 +- .../MaterialDatePicker.tsx | 8 +- .../behavior-button/MaterialDatePicker.js | 13 +-- .../behavior-button/MaterialDatePicker.tsx | 13 +-- .../MaterialDateRangePicker.js | 14 +-- .../MaterialDateRangePicker.tsx | 14 +-- .../MaskedMaterialTextField.js | 39 +++++---- .../MaskedMaterialTextField.tsx | 39 +++++---- .../MaterialDatePicker.js | 14 +-- .../MaterialDatePicker.tsx | 14 +-- .../migration-pickers-v7.md | 63 ++++++++++++++ .../overview/mainDemo/PickerButton.tsx | 12 +-- .../MultiInputDateRangeField.tsx | 17 ++-- .../MultiInputDateTimeRangeField.tsx | 17 ++-- .../MultiInputTimeRangeField.tsx | 17 ++-- .../SingleInputDateRangeField.tsx | 9 +- .../SingleInputDateTimeRangeField.tsx | 9 +- .../SingleInputTimeRangeField.tsx | 9 +- .../internals/hooks/models/useRangePicker.ts | 9 +- .../useDesktopRangePicker.tsx | 48 ++++------- ...rops.ts => useEnrichedRangePickerField.ts} | 68 ++++++++------- .../useMobileRangePicker.tsx | 47 ++++------ .../src/internals/models/fields.ts | 20 +---- .../src/DateField/DateField.tsx | 9 +- .../src/DateTimeField/DateTimeField.tsx | 9 +- .../src/TimeField/TimeField.tsx | 9 +- .../src/hooks/useParsedFormat.ts | 37 ++++---- .../src/hooks/usePickerActionsContext.ts | 2 +- .../src/hooks/usePickerContext.ts | 6 +- .../internals/components/PickerProvider.tsx | 31 +++++-- .../useDesktopPicker/useDesktopPicker.tsx | 29 ++----- .../useDesktopPicker.types.ts | 4 +- .../src/internals/hooks/useField/index.ts | 4 +- .../src/internals/hooks/useField/useField.ts | 30 +------ .../useFieldInternalPropsWithDefaults.ts | 86 +++++++++++++++++++ .../hooks/useMobilePicker/useMobilePicker.tsx | 27 ++---- .../useMobilePicker/useMobilePicker.types.ts | 4 +- .../hooks/useNullablePickerContext.ts | 9 ++ .../internals/hooks/usePicker/usePicker.ts | 10 +-- .../hooks/usePicker/usePicker.types.ts | 5 +- .../hooks/usePicker/usePickerProvider.ts | 29 ++++++- .../hooks/usePicker/usePickerValue.ts | 15 +--- .../hooks/usePicker/usePickerValue.types.ts | 7 +- .../x-date-pickers/src/internals/index.ts | 8 +- .../src/internals/models/fields.ts | 21 +---- .../src/internals/models/manager.ts | 6 ++ .../models/props/basePickerProps.tsx | 21 ----- 57 files changed, 539 insertions(+), 500 deletions(-) rename packages/x-date-pickers-pro/src/internals/hooks/{useEnrichedRangePickerFieldProps.ts => useEnrichedRangePickerField.ts} (88%) create mode 100644 packages/x-date-pickers/src/internals/hooks/useField/useFieldInternalPropsWithDefaults.ts create mode 100644 packages/x-date-pickers/src/internals/hooks/useNullablePickerContext.ts diff --git a/docs/data/date-pickers/calendar-systems/AdapterHijri.js b/docs/data/date-pickers/calendar-systems/AdapterHijri.js index 377759e113758..3260e904fba9b 100644 --- a/docs/data/date-pickers/calendar-systems/AdapterHijri.js +++ b/docs/data/date-pickers/calendar-systems/AdapterHijri.js @@ -24,7 +24,6 @@ const cacheRtl = createCache({ function ButtonDateTimeField(props) { const { internalProps, forwardedProps } = useSplitFieldProps(props, 'date'); - const { value, timezone, format } = internalProps; const { InputProps, slotProps, @@ -37,16 +36,18 @@ function ButtonDateTimeField(props) { } = forwardedProps; const pickerContext = usePickerContext(); - - const parsedFormat = useParsedFormat(internalProps); + const parsedFormat = useParsedFormat(); const { hasValidationError } = useValidation({ validator: validateDate, - value, - timezone, + value: pickerContext.value, + timezone: pickerContext.timezone, props: internalProps, }); - const valueStr = value == null ? parsedFormat : value.format(format); + const valueStr = + pickerContext.value == null + ? parsedFormat + : pickerContext.value.format(pickerContext.fieldFormat); return (