From 556f7e43a71ddb95ad76ebadd0d7ca91308ae017 Mon Sep 17 00:00:00 2001 From: Xiao Yijun Date: Fri, 26 Jul 2024 15:54:58 +0800 Subject: [PATCH] fix(console): dragging anchor in the color picker on application branding page (#6340) --- packages/console/package.json | 2 +- packages/console/src/App.tsx | 2 + .../ColorPicker/index.module.scss | 4 + .../src/ds-components/ColorPicker/index.tsx | 17 ++-- .../Branding/NonThirdPartyBrandingForm.tsx | 94 +++++++++++++++++++ .../Branding/index.tsx | 87 +---------------- .../Branding/BrandingForm/index.tsx | 6 +- .../console/sign-in-experience/helpers.ts | 2 +- pnpm-lock.yaml | 63 ++++--------- 9 files changed, 135 insertions(+), 142 deletions(-) create mode 100644 packages/console/src/pages/ApplicationDetails/ApplicationDetailsContent/Branding/NonThirdPartyBrandingForm.tsx diff --git a/packages/console/package.json b/packages/console/package.json index 4e24b8687..55a82dd6f 100644 --- a/packages/console/package.json +++ b/packages/console/package.json @@ -93,7 +93,7 @@ "property-information": "^6.2.0", "react": "^18.3.1", "react-animate-height": "^3.0.4", - "react-color": "^2.19.3", + "react-color-palette": "^7.2.1", "react-confetti": "^6.1.0", "react-dnd": "^16.0.0", "react-dnd-html5-backend": "^16.0.0", diff --git a/packages/console/src/App.tsx b/packages/console/src/App.tsx index 96ff5ed71..30830308c 100644 --- a/packages/console/src/App.tsx +++ b/packages/console/src/App.tsx @@ -16,6 +16,8 @@ import './scss/normalized.scss'; import './scss/overlayscrollbars.scss'; // eslint-disable-next-line import/no-unassigned-import import '@fontsource/roboto-mono'; +// eslint-disable-next-line import/no-unassigned-import +import 'react-color-palette/css'; import CloudAppRoutes from '@/cloud/AppRoutes'; import AppLoading from '@/components/AppLoading'; diff --git a/packages/console/src/ds-components/ColorPicker/index.module.scss b/packages/console/src/ds-components/ColorPicker/index.module.scss index bca61d8f7..1cd1d6a04 100644 --- a/packages/console/src/ds-components/ColorPicker/index.module.scss +++ b/packages/console/src/ds-components/ColorPicker/index.module.scss @@ -28,3 +28,7 @@ margin-right: _.unit(2); } } + +.palette { + width: 400px; +} diff --git a/packages/console/src/ds-components/ColorPicker/index.tsx b/packages/console/src/ds-components/ColorPicker/index.tsx index d3c6a19c7..1ece096c5 100644 --- a/packages/console/src/ds-components/ColorPicker/index.tsx +++ b/packages/console/src/ds-components/ColorPicker/index.tsx @@ -1,6 +1,6 @@ import classNames from 'classnames'; import { useRef, useState } from 'react'; -import { ChromePicker } from 'react-color'; +import { ColorPicker as ColorPalette, useColor } from 'react-color-palette'; import { onKeyDownHandler } from '@/utils/a11y'; @@ -17,6 +17,7 @@ type Props = { function ColorPicker({ name, onChange, value = '#000000' }: Props) { const anchorRef = useRef(null); const [isOpen, setIsOpen] = useState(false); + const [color] = useColor(value); return (
- { - onChange(hex); - }} - /> +
+ { + onChange(hex); + }} + /> +
); diff --git a/packages/console/src/pages/ApplicationDetails/ApplicationDetailsContent/Branding/NonThirdPartyBrandingForm.tsx b/packages/console/src/pages/ApplicationDetails/ApplicationDetailsContent/Branding/NonThirdPartyBrandingForm.tsx new file mode 100644 index 000000000..788d145a4 --- /dev/null +++ b/packages/console/src/pages/ApplicationDetails/ApplicationDetailsContent/Branding/NonThirdPartyBrandingForm.tsx @@ -0,0 +1,94 @@ +import { generateDarkColor } from '@logto/core-kit'; +import { Theme } from '@logto/schemas'; +import { useMemo, useCallback } from 'react'; +import { Controller, useFormContext } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; + +import LogoAndFavicon from '@/components/ImageInputs/LogoAndFavicon'; +import Button from '@/ds-components/Button'; +import ColorPicker from '@/ds-components/ColorPicker'; +import FormField from '@/ds-components/FormField'; + +import styles from './index.module.scss'; +import { type ApplicationSignInExperienceForm } from './utils'; + +function NonThirdPartyBrandingForm() { + const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); + const { + control, + register, + formState: { errors }, + watch, + setValue, + } = useFormContext(); + + const [primaryColor, darkPrimaryColor] = watch(['color.primaryColor', 'color.darkPrimaryColor']); + + const calculatedDarkPrimaryColor = useMemo(() => { + return primaryColor && generateDarkColor(primaryColor); + }, [primaryColor]); + + const handleResetColor = useCallback(() => { + setValue('color.darkPrimaryColor', calculatedDarkPrimaryColor, { shouldDirty: true }); + }, [calculatedDarkPrimaryColor, setValue]); + + return ( + <> + + +
+ ( + + + + )} + /> + ( + + + + )} + /> + {calculatedDarkPrimaryColor !== darkPrimaryColor && ( +
+ {t('sign_in_exp.color.dark_mode_reset_tip')} +
+ )} +
+ + ); +} + +export default NonThirdPartyBrandingForm; diff --git a/packages/console/src/pages/ApplicationDetails/ApplicationDetailsContent/Branding/index.tsx b/packages/console/src/pages/ApplicationDetails/ApplicationDetailsContent/Branding/index.tsx index 910bf0bb6..b50ab4971 100644 --- a/packages/console/src/pages/ApplicationDetails/ApplicationDetailsContent/Branding/index.tsx +++ b/packages/console/src/pages/ApplicationDetails/ApplicationDetailsContent/Branding/index.tsx @@ -5,20 +5,17 @@ import { type Application, type ApplicationSignInExperience, } from '@logto/schemas'; -import { useCallback, useEffect, useMemo } from 'react'; -import { useForm, FormProvider, Controller } from 'react-hook-form'; +import { useCallback, useEffect } from 'react'; +import { useForm, FormProvider } from 'react-hook-form'; import { toast } from 'react-hot-toast'; import { useTranslation } from 'react-i18next'; import DetailsForm from '@/components/DetailsForm'; import FormCard, { FormCardSkeleton } from '@/components/FormCard'; import ImageInputs, { themeToLogoName } from '@/components/ImageInputs'; -import LogoAndFavicon from '@/components/ImageInputs/LogoAndFavicon'; import RequestDataError from '@/components/RequestDataError'; import UnsavedChangesAlertModal from '@/components/UnsavedChangesAlertModal'; import { appSpecificBrandingLink, logtoThirdPartyAppBrandingLink } from '@/consts'; -import Button from '@/ds-components/Button'; -import ColorPicker from '@/ds-components/ColorPicker'; import FormField from '@/ds-components/FormField'; import Switch from '@/ds-components/Switch'; import TextInput from '@/ds-components/TextInput'; @@ -28,7 +25,7 @@ import { emptyBranding } from '@/types/sign-in-experience'; import { trySubmitSafe } from '@/utils/form'; import { uriValidator } from '@/utils/validator'; -import styles from './index.module.scss'; +import NonThirdPartyBrandingForm from './NonThirdPartyBrandingForm'; import useApplicationSignInExperienceSWR from './use-application-sign-in-experience-swr'; import useSignInExperienceSWR from './use-sign-in-experience-swr'; import { type ApplicationSignInExperienceForm, formatFormToSubmitData } from './utils'; @@ -119,84 +116,6 @@ function Branding({ application, isActive }: Props) { } }, [color, isBrandingEnabled, setValue]); - const [primaryColor, darkPrimaryColor] = watch(['color.primaryColor', 'color.darkPrimaryColor']); - const calculatedDarkPrimaryColor = useMemo(() => { - return primaryColor && generateDarkColor(primaryColor); - }, [primaryColor]); - - const handleResetColor = useCallback(() => { - setValue('color.darkPrimaryColor', calculatedDarkPrimaryColor); - }, [calculatedDarkPrimaryColor, setValue]); - - const NonThirdPartyBrandingForm = useCallback( - () => ( - <> - - -
- ( - - - - )} - /> - ( - - - - )} - /> - {calculatedDarkPrimaryColor !== darkPrimaryColor && ( -
- {t('sign_in_exp.color.dark_mode_reset_tip')} -
- )} -
- - ), - [ - control, - errors.branding, - register, - calculatedDarkPrimaryColor, - darkPrimaryColor, - handleResetColor, - t, - ] - ); - if (isLoading) { return ; } diff --git a/packages/console/src/pages/SignInExperience/PageContent/Branding/BrandingForm/index.tsx b/packages/console/src/pages/SignInExperience/PageContent/Branding/BrandingForm/index.tsx index 2859092b2..df7d72b87 100644 --- a/packages/console/src/pages/SignInExperience/PageContent/Branding/BrandingForm/index.tsx +++ b/packages/console/src/pages/SignInExperience/PageContent/Branding/BrandingForm/index.tsx @@ -35,7 +35,7 @@ function BrandingForm() { }, [primaryColor]); const handleResetColor = useCallback(() => { - setValue('color.darkPrimaryColor', calculatedDarkPrimaryColor); + setValue('color.darkPrimaryColor', calculatedDarkPrimaryColor, { shouldDirty: true }); }, [calculatedDarkPrimaryColor, setValue]); useEffect(() => { @@ -56,8 +56,8 @@ function BrandingForm() { ( - + render={({ field: { name, onChange, value } }) => ( + )} /> diff --git a/packages/integration-tests/src/tests/console/sign-in-experience/helpers.ts b/packages/integration-tests/src/tests/console/sign-in-experience/helpers.ts index 84bd90045..6f6e83900 100644 --- a/packages/integration-tests/src/tests/console/sign-in-experience/helpers.ts +++ b/packages/integration-tests/src/tests/console/sign-in-experience/helpers.ts @@ -31,7 +31,7 @@ export const expectToSelectColor = async ( await expect(colorField).toClick('div[role=button]'); - await expect(page).toFill('input[id^=rc-editable-input]', color); + await expect(page).toFill('input[id=hex][class=rcp-field-input]', color); // Close the color input await page.keyboard.press('Escape'); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d46ec3066..7ec723e6d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3058,9 +3058,9 @@ importers: react-animate-height: specifier: ^3.0.4 version: 3.0.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-color: - specifier: ^2.19.3 - version: 2.19.3(react@18.3.1) + react-color-palette: + specifier: ^7.2.1 + version: 7.2.1(react@18.3.1) react-confetti: specifier: ^6.1.0 version: 6.1.0(react@18.3.1) @@ -4453,6 +4453,7 @@ packages: '@azure/core-http@3.0.4': resolution: {integrity: sha512-Fok9VVhMdxAFOtqiiAtg74fL0UJkt0z3D+ouUUxcRLzZNBioPRAMJFVxiWoJljYpXsRi4GDQHzQHDc9AiYaIUQ==} engines: {node: '>=14.0.0'} + deprecated: deprecating as we migrated to core v2 '@azure/core-lro@2.5.1': resolution: {integrity: sha512-JHQy/bA3NOz2WuzOi5zEk6n/TJdAropupxUT521JIJvW7EXV2YN2SFYZrf/2RHeD28QAClGdynYadZsbmP+nyQ==} @@ -5282,11 +5283,6 @@ packages: resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} deprecated: Use @eslint/object-schema instead - '@icons/material@0.2.4': - resolution: {integrity: sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==} - peerDependencies: - react: '*' - '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -10319,9 +10315,6 @@ packages: markdown-table@3.0.2: resolution: {integrity: sha512-y8j3a5/DkJCmS5x4dMCQL+OR0+2EAq3DOtio1COSHsmW2BGXnNCK3v12hJt1LrUz5iZH5g0LmuYOjDdI+czghA==} - material-colors@1.2.6: - resolution: {integrity: sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==} - mathml-tag-names@2.1.3: resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==} @@ -11480,6 +11473,7 @@ packages: puppeteer@22.6.5: resolution: {integrity: sha512-YuoRKGj3MxHhUwrey7vmNvU4odGdUdNsj1ee8pfcqQlLWIXfMOXZCAXh8xdzpZESHH3tCGWp2xmPZE8E6iUEWg==} engines: {node: '>=18'} + deprecated: < 22.8.2 is no longer supported hasBin: true pure-rand@6.0.0: @@ -11545,10 +11539,11 @@ packages: react: '>=16.8.0' react-dom: '>=16.8.0' - react-color@2.19.3: - resolution: {integrity: sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA==} + react-color-palette@7.2.1: + resolution: {integrity: sha512-wulPqPc6qblr/bsjbW50t/je9keTRrouzPhimktCzBleNUxVJNN84cOZX5XzuS8ubQPg3h57gUT6vAKlBUDhUQ==} + engines: {node: '>=10'} peerDependencies: - react: '*' + react: '>=16.8' react-confetti@6.1.0: resolution: {integrity: sha512-7Ypx4vz0+g8ECVxr88W9zhcQpbeujJAVqL14ZnXJ3I23mOI9/oBVTQ3dkJhUmB0D6XOtCZEM6N0Gm9PMngkORw==} @@ -11751,11 +11746,6 @@ packages: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} - reactcss@1.2.3: - resolution: {integrity: sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==} - peerDependencies: - react: '*' - read-pkg-up@7.0.1: resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} engines: {node: '>=8'} @@ -12555,9 +12545,6 @@ packages: tinybench@2.8.0: resolution: {integrity: sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==} - tinycolor2@1.6.0: - resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} - tinypool@1.0.0: resolution: {integrity: sha512-KIKExllK7jp3uvrNtvRBYBWBOAXSX8ZvoaD8T+7KB/QHIuoJW3Pmr60zucywjAlMb5TeXUkcs/MWeWLu0qvuAQ==} engines: {node: ^18.0.0 || >=20.0.0} @@ -14833,10 +14820,6 @@ snapshots: '@humanwhocodes/object-schema@2.0.3': {} - '@icons/material@0.2.4(react@18.3.1)': - dependencies: - react: 18.3.1 - '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -18197,6 +18180,10 @@ snapshots: debounce@1.2.1: {} + debug@3.2.7: + dependencies: + ms: 2.1.3 + debug@3.2.7(supports-color@5.5.0): dependencies: ms: 2.1.3 @@ -18672,7 +18659,7 @@ snapshots: eslint-import-resolver-node@0.3.9: dependencies: - debug: 3.2.7(supports-color@5.5.0) + debug: 3.2.7 is-core-module: 2.13.1 resolve: 1.22.8 transitivePeerDependencies: @@ -18697,7 +18684,7 @@ snapshots: eslint-module-utils@2.8.1(@typescript-eslint/parser@7.7.0(eslint@8.57.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.7.0(eslint@8.57.0)(typescript@5.5.3))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.0(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): dependencies: - debug: 3.2.7(supports-color@5.5.0) + debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 7.7.0(eslint@8.57.0)(typescript@5.5.3) eslint: 8.57.0 @@ -18730,7 +18717,7 @@ snapshots: array.prototype.findlastindex: 1.2.5 array.prototype.flat: 1.3.2 array.prototype.flatmap: 1.3.2 - debug: 3.2.7(supports-color@5.5.0) + debug: 3.2.7 doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 @@ -21264,8 +21251,6 @@ snapshots: markdown-table@3.0.2: {} - material-colors@1.2.6: {} - mathml-tag-names@2.1.3: {} mdast-util-find-and-replace@3.0.1: @@ -22887,16 +22872,9 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-color@2.19.3(react@18.3.1): + react-color-palette@7.2.1(react@18.3.1): dependencies: - '@icons/material': 0.2.4(react@18.3.1) - lodash: 4.17.21 - lodash-es: 4.17.21 - material-colors: 1.2.6 - prop-types: 15.8.1 react: 18.3.1 - reactcss: 1.2.3(react@18.3.1) - tinycolor2: 1.6.0 react-confetti@6.1.0(react@18.3.1): dependencies: @@ -23099,11 +23077,6 @@ snapshots: dependencies: loose-envify: 1.4.0 - reactcss@1.2.3(react@18.3.1): - dependencies: - lodash: 4.17.21 - react: 18.3.1 - read-pkg-up@7.0.1: dependencies: find-up: 4.1.0 @@ -24135,8 +24108,6 @@ snapshots: tinybench@2.8.0: {} - tinycolor2@1.6.0: {} - tinypool@1.0.0: {} tinyspy@3.0.0: {}