diff --git a/CHANGELOG.md b/CHANGELOG.md index 42577b98104dca..e69ac20ae69509 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8653,7 +8653,7 @@ _Nov 14, 2020_ A big thanks to the 34 contributors who made this release possible. Here are some highlights ✨: - 📅 Migrate the date picker to the lab (#22692) @dmtrKovalenko. - We have integrated the components with the code infrastructure. Next we will migrate all the GitHub issues from [material-ui-pickers](https://github.com/mui/material-ui-pickers) and archive the repository. This migration will help provide first-class support for the date picker components. The component will stay in the lab as long as necessary to reach the high quality bar we have for core components. You can find the [new documentation here](https://mui.com/components/pickers/). + We have integrated the components with the code infrastructure. Next we will migrate all the GitHub issues from [material-ui-pickers](https://github.com/mui/material-ui-pickers) and archive the repository. This migration will help provide first-class support for the date picker components. The component will stay in the lab as long as necessary to reach the high-quality bar we have for core components. You can find the [new documentation here](https://mui.com/components/pickers/). While the source code is currently hosted in the [main repository](https://github.com/mui/material-ui), we might move it to the [x repository](https://github.com/mui/mui-x) in the future, depending on what is easier for the commercial date range picker. The date picker will stay open source no matter what. diff --git a/docs/pages/pricing.tsx b/docs/pages/pricing.tsx index 9a44d5cc6d41a9..dd1648b49d284a 100644 --- a/docs/pages/pricing.tsx +++ b/docs/pages/pricing.tsx @@ -6,22 +6,16 @@ import AppHeader from 'docs/src/layouts/AppHeader'; import HeroPricing from 'docs/src/components/pricing/HeroPricing'; import PricingTable from 'docs/src/components/pricing/PricingTable'; import PricingList from 'docs/src/components/pricing/PricingList'; -import EarlyBird from 'docs/src/components/pricing/EarlyBird'; import Testimonials from 'docs/src/components/home/Testimonials'; -import WhatToExpect from 'docs/src/components/pricing/WhatToExpect'; -import FAQ from 'docs/src/components/pricing/FAQ'; +import PricingWhatToExpect from 'docs/src/components/pricing/PricingWhatToExpect'; +import PricingFAQ from 'docs/src/components/pricing/PricingFAQ'; import HeroEnd from 'docs/src/components/home/HeroEnd'; import AppFooter from 'docs/src/layouts/AppFooter'; import BrandingCssVarsProvider from 'docs/src/BrandingCssVarsProvider'; import AppHeaderBanner from 'docs/src/components/banner/AppHeaderBanner'; -import LicenseTypeWidget from 'docs/src/components/pricing/LicenseTypeWidget'; +import { LicenseTypeProvider } from 'docs/src/components/pricing/LicenseTypeContext'; export default function Pricing() { - const [licenseType, setLicenseType] = React.useState('Annual'); - const handleSubscriptionToggleChange = (newValue: string) => { - setLicenseType(newValue); - }; - return ( - {' '} - {/* Mobile, Tablet */} - - {' '} + + {/* Mobile, Tablet */} + + + {/* Desktop */} - - + + + + + - + diff --git a/docs/src/components/home/UserFeedbacks.tsx b/docs/src/components/home/UserFeedbacks.tsx index 8056aab5e013dc..c88f7eda695556 100644 --- a/docs/src/components/home/UserFeedbacks.tsx +++ b/docs/src/components/home/UserFeedbacks.tsx @@ -55,7 +55,7 @@ function Feedback({ const TESTIMONIALS = [ { quote: - '"MUI offers a wide variety of high quality components that have allowed us to ship features faster. MUI has been used by more than a hundred engineers in our organization. What\'s more, MUI\'s well architected customization system has allowed us to differentiate ourselves in the marketplace."', + '"MUI offers a wide variety of high-quality components that have allowed us to ship features faster. MUI has been used by more than a hundred engineers in our organization. What\'s more, MUI\'s well-architected customization system has allowed us to differentiate ourselves in the marketplace."', profile: { avatarSrc: 'https://avatars.githubusercontent.com/u/28296253?s=58', avatarSrcSet: 'https://avatars.githubusercontent.com/u/28296253?s=116 2x', diff --git a/docs/src/components/pricing/EarlyBird.tsx b/docs/src/components/pricing/EarlyBird.tsx deleted file mode 100644 index f9736ab0dcdb04..00000000000000 --- a/docs/src/components/pricing/EarlyBird.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import * as React from 'react'; -import Box from '@mui/material/Box'; -import Container from '@mui/material/Container'; -import Typography from '@mui/material/Typography'; -import Stack from '@mui/material/Stack'; -import Button from '@mui/material/Button'; -import Link from 'docs/src/modules/components/Link'; -import KeyboardArrowRightRounded from '@mui/icons-material/KeyboardArrowRightRounded'; - -export default function EarlyBird() { - return ( - - ({ - borderRadius: 1, - p: 2, - bgcolor: 'primary.50', - border: '1px solid', - borderColor: 'primary.100', - display: 'flex', - flexDirection: { - xs: 'column', - sm: 'row', - }, - justifyContent: 'space-between', - alignItems: { - xs: 'flex-start', - sm: 'center', - }, - ...theme.applyDarkStyles({ - bgcolor: 'primaryDark.900', - borderColor: 'primaryDark.500', - }), - })} - > - - - 🐦  Early bird special! - - - Buy now at a reduced price (~25% off), and get early access to MUI X Premium, with the - added opportunity to influence its development. The early bird special is available for - a limited time, so don't miss this opportunity! - - - - - - ); -} diff --git a/docs/src/components/pricing/HeroPricing.tsx b/docs/src/components/pricing/HeroPricing.tsx index 3073d3b35528ea..ff8fca68fc97a4 100644 --- a/docs/src/components/pricing/HeroPricing.tsx +++ b/docs/src/components/pricing/HeroPricing.tsx @@ -33,8 +33,7 @@ export default function HeroPricing() { Start using MUI for free! - Switch to an annual subscription or one-time purchase to access advanced features & - technical support. + Switch to a commercial plan to access advanced features & tec diff --git a/docs/src/components/pricing/LicenseTypeContext.tsx b/docs/src/components/pricing/LicenseTypeContext.tsx new file mode 100644 index 00000000000000..6648a49525a9aa --- /dev/null +++ b/docs/src/components/pricing/LicenseTypeContext.tsx @@ -0,0 +1,20 @@ +import * as React from 'react'; + +const LicenseType = React.createContext({}); + +if (process.env.NODE_ENV !== 'production') { + LicenseType.displayName = 'LicenseType'; +} + +export function LicenseTypeProvider(props: any) { + const [licenseType, setLicenseType] = React.useState('Annual'); + const value = React.useMemo( + () => ({ licenseType, setLicenseType }), + [licenseType, setLicenseType], + ); + return {props.children}; +} + +export function useLicenseType() { + return React.useContext(LicenseType); +} diff --git a/docs/src/components/pricing/LicenseTypeWidget.tsx b/docs/src/components/pricing/LicenseTypeWidget.tsx index 3c7c749baa95dc..ec206914a096a6 100644 --- a/docs/src/components/pricing/LicenseTypeWidget.tsx +++ b/docs/src/components/pricing/LicenseTypeWidget.tsx @@ -2,114 +2,115 @@ import * as React from 'react'; import Box from '@mui/material/Box'; import Tooltip from '@mui/material/Tooltip'; import { styled } from '@mui/material/styles'; +import Tabs from '@mui/material/Tabs'; +import Tab from '@mui/material/Tab'; +import { useLicenseType } from 'docs/src/components/pricing/LicenseTypeContext'; -const LicenseTypeWrapper = styled(Box)(({ theme }) => ({ - display: 'flex', - flexFlow: 'column', - justifyContent: 'center', - alignItems: 'center', - margin: '20px auto', - padding: '2px 0px', - maxWidth: '170px', - h2: { - color: theme.palette.primary.main, - fontSize: '1em', - margin: 0, - }, - background: theme.palette.mode === 'dark' ? '#5d5d5d66' : '#efefef', +const StyledTabs = styled(Tabs)(({ theme }) => ({ + margin: '14px auto 4px', + padding: 2, + maxWidth: 170, + minHeight: 0, + overflow: 'visible', + borderRadius: 20, border: '1px solid', - borderColor: theme.palette.mode === 'dark' ? '#4d4d4d' : '#dedede', - borderRadius: '20px', + borderColor: (theme.vars || theme).palette.grey[200], + backgroundColor: (theme.vars || theme).palette.grey[50], + '& .MuiTabs-scroller': { + overflow: 'visible!important', + }, + '& .MuiTab-root': { + padding: '2px 10px', + fontSize: theme.typography.pxToRem(14), + minWidth: 0, + minHeight: 0, + zIndex: 1, + color: (theme.vars || theme).palette.grey[500], + borderRadius: 20, + '&:hover': { + color: (theme.vars || theme).palette.grey[600], + }, + '&.Mui-focusVisible': { + outline: `2px solid ${(theme.vars || theme).palette.primary.main}`, + outlineOffset: 2, + }, + '&.Mui-selected': { + color: (theme.vars || theme).palette.grey[900], + }, + }, + '& .MuiTabs-indicator': { + backgroundColor: '#fff', + height: '100%', + borderRadius: 20, + }, + ...theme.applyDarkStyles({ + borderColor: (theme.vars || theme).palette.grey[700], + backgroundColor: (theme.vars || theme).palette.grey[800], + '& .MuiTab-root': { + '&:hover': { + color: (theme.vars || theme).palette.grey[400], + }, + '&.Mui-selected': { + color: (theme.vars || theme).palette.grey[900], + }, + }, + }), })); -const LicenseOption = styled(Box)<{ selected: boolean }>(({ theme, selected }) => ({ - textAlign: 'center', - h3: { - cursor: 'pointer', - color: selected ? '#333' : theme.palette.mode === 'dark' ? '#a0a0a0' : '#c0c0c0', - borderBottom: '0px solid', - borderColor: selected ? theme.palette.primary.main : 'transparent', - background: selected ? '#fff' : 'transparent', - borderRadius: '20px', - display: 'inline-block', - margin: 0, - padding: '0px 10px', - fontSize: '0.9em', - }, +const perpetualDescription = + 'One-time purchase to use the current released versions forever. 12 months of updates included.'; +const annualDescription = + 'Upon expiration, your permission to use the Software in development ends. The license is perpetual in production.'; - p: { - color: selected ? '' : theme.palette.mode === 'dark' ? '#5d5d5d' : '#c0c0c0', - display: 'inline-block', - padding: '0px 4px', - margin: 0, - fontSize: '0.9em', +const tooltipProps = { + enterDelay: 400, + enterNextDelay: 50, + enterTouchDelay: 500, + placement: 'top' as 'top', + describeChild: true, + slotProps: { + tooltip: { + sx: { + fontSize: 12, + }, + }, }, -})); +}; -export default function LicenseTypeWidget(props: { - selectedOption: string; - onChange: (newValue: string) => void; -}) { - const option1Title = 'Annual'; - const option1Description = - 'Get the lowest price on a long-term partnership or license for a short project. Move to Perpetual anytime.'; - const option2Title = 'Perpetual'; - const option2Description = - 'One-time purchase to use current released versions forever in development. 12 months of updates included.'; +export default function LicenseTypeWidget() { + const { licenseType, setLicenseType } = useLicenseType(); - const handleOptionClick = (title: string) => { - //setSelectedOption(title); - props.onChange(title); + const handleChange = (event: React.SyntheticEvent, newValue: number) => { + setLicenseType(newValue); }; - const subscriptionSelected = props.selectedOption === option1Title; return ( - - {/*

Commercial License types

*/} - + - handleOptionClick(option1Title)} - onKeyPress={(event) => { - if (event.key === 'Enter') { - handleOptionClick(option1Title); - } - }} - sx={{ - textAlign: 'right', - }} - > - -

{option1Title}

-
- {/*

{option1Description}

*/} -
- handleOptionClick(option2Title)} - onKeyPress={(event) => { - if (event.key === 'Enter') { - handleOptionClick(option2Title); - } - }} - > - -

{option2Title}

-
- {/*

{option2Description}

*/} -
- {/* - - */} -
-
+ + Perpetual + + } + /> + + Annual + + } + /> + + ); } diff --git a/docs/src/components/pricing/FAQ.tsx b/docs/src/components/pricing/PricingFAQ.tsx similarity index 96% rename from docs/src/components/pricing/FAQ.tsx rename to docs/src/components/pricing/PricingFAQ.tsx index 562aa1ee1b5220..7ca5ca68054d84 100644 --- a/docs/src/components/pricing/FAQ.tsx +++ b/docs/src/components/pricing/PricingFAQ.tsx @@ -119,9 +119,9 @@ const faqData = [ summary: 'Am I allowed to use the product after the update entitlement expires?', detail: ( - Yes. You can continue to use the product in production environments after the entitlement - expires. But you will need to keep your subscription active to continue development, update - for new features, or gain access to technical support. + Yes. You can continue to use the product in production environments after + the entitlement expires. But you will need to keep your subscription active to continue + development, update for new features, or gain access to technical support.

To renew your license, please contact sales. @@ -231,7 +231,7 @@ const AccordionDetails = styled(MuiAccordionDetail)(({ theme }) => ({ padding: 0, })); -export default function FAQ() { +export default function PricingFAQ() { function renderItem(index: number) { const faq = faqData[index]; return ( @@ -258,7 +258,7 @@ export default function FAQ() { } return ( - + Frequently asked questions diff --git a/docs/src/components/pricing/PricingList.tsx b/docs/src/components/pricing/PricingList.tsx index 5755382a06d64e..ccdb32ce1bc2e1 100644 --- a/docs/src/components/pricing/PricingList.tsx +++ b/docs/src/components/pricing/PricingList.tsx @@ -2,7 +2,6 @@ import * as React from 'react'; import { useTheme } from '@mui/material/styles'; import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; -import Container from '@mui/material/Container'; import Fade from '@mui/material/Fade'; import Paper, { PaperProps } from '@mui/material/Paper'; import Typography from '@mui/material/Typography'; @@ -11,6 +10,7 @@ import Tab from '@mui/material/Tab'; import KeyboardArrowRightRounded from '@mui/icons-material/KeyboardArrowRightRounded'; import Link from 'docs/src/modules/components/Link'; import PricingTable, { PlanName, PlanPrice } from 'docs/src/components/pricing/PricingTable'; +import { useLicenseType } from 'docs/src/components/pricing/LicenseTypeContext'; const Plan = React.forwardRef< HTMLDivElement, @@ -18,15 +18,12 @@ const Plan = React.forwardRef< plan: 'community' | 'pro' | 'premium'; benefits?: Array; unavailable?: boolean; - selectedLicenseType: string; - onLicenseTypeChange: (newValue: string) => void; } & PaperProps ->(function Plan( - { plan, benefits, unavailable, sx, selectedLicenseType, onLicenseTypeChange, ...props }, - ref, -) { +>(function Plan({ plan, benefits, unavailable, sx, ...props }, ref) { const globalTheme = useTheme(); const mode = globalTheme.palette.mode; + const { licenseType } = useLicenseType(); + return ( - + {unavailable ? ( + ); +} + +function PricingTableBuyPremium() { + const { licenseType } = useLicenseType(); + + return ( + + ); +} + export default function PricingTable({ columnHeaderHidden, plans = ['community', 'pro', 'premium'], - selectedLicenseType, - onLicenseTypeChange, ...props }: BoxProps & { columnHeaderHidden?: boolean; plans?: Array<'community' | 'pro' | 'premium'>; - selectedLicenseType: string; - onLicenseTypeChange: (newValue: string) => void; }) { const router = useRouter(); const [dataGridCollapsed, setDataGridCollapsed] = React.useState(false); - const showSubscriptionPlans = selectedLicenseType === 'Annual'; React.useEffect(() => { if (router.query['expand-path'] === 'all') { @@ -1025,57 +1058,17 @@ export default function PricingTable({ /> ); - function renderRow(key: string) { - return ( - ({ - '&:hover': { - bgcolor: alpha(theme.palette.grey[50], 0.4), - '@media (hover: none)': { - bgcolor: 'initial', - }, - }, - }), - (theme) => - theme.applyDarkStyles({ - '&:hover': { - bgcolor: alpha(theme.palette.primaryDark[900], 0.3), - }, - }), - ]} - > - {rowHeaders[key]} - {plans.map((id, index) => ( - - {id === 'community' && communityData[key]} - {id === 'pro' && proData[key]} - {id === 'premium' && premiumData[key]} - - ))} - - ); - } + const renderRow = (key: string) => renderMasterRow(key, gridSx, plans); return ( - + {!columnHeaderHidden && ( Plans - + + - + - - + + )} @@ -1306,9 +1271,7 @@ export default function PricingTable({ {divider} {renderRow('mui-x-production')} {divider} - {showSubscriptionPlans - ? renderRow('mui-x-development') - : renderRow('mui-x-development-perpetual')} + {divider} {renderRow('mui-x-updates')} Support diff --git a/docs/src/components/pricing/WhatToExpect.tsx b/docs/src/components/pricing/PricingWhatToExpect.tsx similarity index 53% rename from docs/src/components/pricing/WhatToExpect.tsx rename to docs/src/components/pricing/PricingWhatToExpect.tsx index b7aeea97853aba..2cc4ec1dd18e26 100644 --- a/docs/src/components/pricing/WhatToExpect.tsx +++ b/docs/src/components/pricing/PricingWhatToExpect.tsx @@ -5,14 +5,24 @@ import Typography from '@mui/material/Typography'; import Paper from '@mui/material/Paper'; import Grid from '@mui/material/Grid'; import LocalOfferOutlinedIcon from '@mui/icons-material/LocalOfferOutlined'; +import FunctionsIcon from '@mui/icons-material/Functions'; import AllInclusiveOutlinedIcon from '@mui/icons-material/AllInclusiveOutlined'; import ReplayRoundedIcon from '@mui/icons-material/ReplayRounded'; +import AcUnitIcon from '@mui/icons-material/AcUnit'; import HelpOutlineOutlinedIcon from '@mui/icons-material/HelpOutlineOutlined'; import Link from 'docs/src/modules/components/Link'; -export default function WhatToExpect() { +export default function PricingWhatToExpect() { return ( - + ({ + width: '100%', + bgcolor: 'grey.50', + ...theme.applyDarkStyles({ + bgcolor: 'primaryDark.900', + }), + })} + > - + - Annual vs. Perpetual licenses + Volume discounts - On both license types, any version released before the end of your license term is - forever available for applications deployed in production. - - - The difference regards the right to use the components for development purposes, - that is new features or improvements on your application. - - - The Annual plans require an active subscription to keep the right - of use in development. It's perfect for a short project or companies planning to - adopt the components at a large scale relying on continuous improvements of the - library. - - - The Perpetual plans offer the right to keep using your licensed - versions forever in production and development. It's meant for projects that take - longer than a year in development and are satisfied with the current released - features. + The Pro plan is capped at 10 developers licensed; you do not need to pay for + additional licenses for more than 10 developers. +
+ You can contact sales for a volume discount + when licensing over 25 developers under the Premium plan.
- + - Volume discount + Required quantity - The licenses are sold on a per front-end developer basis. The Pro plan includes is - capped at 10 licenses; you do not need to pay for additional licenses for more than - 10 developers. You can contact sales for a - volume discount when licensing over 25 developers under the Premium plan. + The number of developers licensed must correspond to the maximum number of + concurrent developers contributing changes to the front-end code of the projects + that use the software. +
+ You can learn more about this in{' '} + + the EULA + + .
@@ -94,7 +100,7 @@ export default function WhatToExpect() {
- With your purchase you receive support and access to new versions for the duration + With your purchase, you receive support and access to new versions for the duration of your subscription. You can{' '} learn more about support @@ -105,6 +111,30 @@ export default function WhatToExpect() { + + + + + + Perpetual vs. Annual license type + + + + On both license types, any version released before the end of your license term is + forever available for applications deployed in production. +
+ The difference regards the right to use the components for development purposes. + Only the perpetual license type allows you to continue development once your license + expires. +
+
+
@@ -116,17 +146,20 @@ export default function WhatToExpect() { variant="body2" sx={{ ml: 1 }} > - Development license + Annual license type - Developers contributing changes to the front-end code of a project that includes MUI - X Pro or Premium need an active license. In case you choose an annual plan, you will - need to renew your license if you wish to continue active development after your - current license term expires. + The Annual license type requires an active license to use the software in + development. You will need to renew your license if you wish to continue active + development after your current license term expires. +
+
+ The license is perpetual in production so you {"don't"} need to renew your license + if you have stopped active development with the commercial components.
- {`You don't need to renew your license if you have stopped active development with the commercial components. You - can learn more about this in `} +
+ You can learn more about this in{' '}
+ + + + + + Perpetual license type + + + + The Perpetual license type offers the right to keep using your licensed versions + forever in production and development. It comes with 12 months of maintenance (free + updates & support). +
+ Upon expiration, you can renew your maintenance plan with a discount that depends on + when you renew: +
    +
  • before the suppord expires: 50% discount
  • +
  • up to 60 days after the support has expired: 25% discount
  • +
  • more than 60 days after the support has expired: 10% discount
  • +
+
+
+
diff --git a/docs/src/components/productDesignKit/DesignKitFAQ.tsx b/docs/src/components/productDesignKit/DesignKitFAQ.tsx index dcd8891eb65304..616d2b040f865c 100644 --- a/docs/src/components/productDesignKit/DesignKitFAQ.tsx +++ b/docs/src/components/productDesignKit/DesignKitFAQ.tsx @@ -50,12 +50,12 @@ const faqData = [ summary: 'Do you offer discounts to educational or non-profit organizations?', detail: ( - Yes, we offer a 50% discount on all products licensed to students, instructors, non-profit, - and charity entities. This special discount cannot be combined with any other type of - discount. To qualify for the discount, you need to send us a document clearly indicating - that you are a member of the respective institution. An email from your official account - which bears your signature is sufficient in most cases. For more information on how to - qualify for a discount, please contact sales. + Yes. We offer a 50% discount on all products licensed to students, + instructors, non-profit, and charity entities. This special discount cannot be combined with + any other type of discount. To qualify for the discount, you need to send us a document + clearly indicating that you are a member of the respective institution. An email from your + official account which bears your signature is sufficient in most cases. For more + information on how to qualify for a discount, please contact sales. ), }, @@ -138,7 +138,7 @@ export default function DesignKitFAQ() { } return ( - + Frequently asked questions @@ -153,9 +153,8 @@ export default function DesignKitFAQ() { ({ - pt: 2, + p: 2, pb: 1, - px: 2, borderStyle: 'dashed', borderColor: 'grey.300', bgcolor: 'white', diff --git a/docs/src/pages/careers/developer-advocate.md b/docs/src/pages/careers/developer-advocate.md index 548663be76c49d..9a02afa91a31c5 100644 --- a/docs/src/pages/careers/developer-advocate.md +++ b/docs/src/pages/careers/developer-advocate.md @@ -51,7 +51,7 @@ Our products empower React developers to build awesome applications faster – w Depending on the day, you'll: - **Content**. - - Produce high quality technical "how-to" content (blogs, webinars, demos, talks) addressing common user needs, latest technology advances, and emerging best practices. Videos might go to [our YouTube channel](https://www.youtube.com/@MUI_hq). + - Produce high-quality technical "how-to" content (blogs, webinars, demos, talks) addressing common user needs, latest technology advances, and emerging best practices. Videos might go to [our YouTube channel](https://www.youtube.com/@MUI_hq). - Distribute content and leverage pieces to broaden awareness of the MUI brand, via existing connections. - Rework the pages of the documentation that are confusing, base on feedback. - **Community**.