From 9d03253670ad64fccd933e859af6fa0f8e3a8daf Mon Sep 17 00:00:00 2001 From: Swanand Mathekar Date: Fri, 16 Feb 2024 10:31:15 +0530 Subject: [PATCH 01/29] Add textColor attribute to TextElement --- packages/element-library/src/text/constants.js | 1 + packages/element-library/src/types/elements/textElement.ts | 1 + packages/elements/src/types/element.ts | 1 + 3 files changed, 3 insertions(+) diff --git a/packages/element-library/src/text/constants.js b/packages/element-library/src/text/constants.js index 7d6bb2b80b70..8dbd8b31b942 100644 --- a/packages/element-library/src/text/constants.js +++ b/packages/element-library/src/text/constants.js @@ -42,6 +42,7 @@ export const defaultAttributes = { horizontal: 0, locked: true, }, + textColor: createSolid(0, 0, 0), }; export const hasEditMode = true; diff --git a/packages/element-library/src/types/elements/textElement.ts b/packages/element-library/src/types/elements/textElement.ts index 2b417a1107a8..4e3fe6792be2 100644 --- a/packages/element-library/src/types/elements/textElement.ts +++ b/packages/element-library/src/types/elements/textElement.ts @@ -47,4 +47,5 @@ export interface TextElement extends Element { tagName?: 'h1' | 'h2' | 'h3' | 'p'; padding?: Padding; marginOffset?: number; + textColor?: Pattern; } diff --git a/packages/elements/src/types/element.ts b/packages/elements/src/types/element.ts index d6caaf6509bf..10b2bb53d0c2 100644 --- a/packages/elements/src/types/element.ts +++ b/packages/elements/src/types/element.ts @@ -193,4 +193,5 @@ export interface TextElement extends Element { marginOffset: number; lineHeight: number; textAlign: TextAlign; + textColor: Solid; } From 734bd44e9c02ed849a9d0c4eaf2e22ad88cfee90 Mon Sep 17 00:00:00 2001 From: Swanand Mathekar Date: Fri, 16 Feb 2024 10:37:49 +0530 Subject: [PATCH 02/29] Add `generateTextColorCSS` for generating CSS styles from textColor --- packages/element-library/src/text/util.ts | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/packages/element-library/src/text/util.ts b/packages/element-library/src/text/util.ts index 9f2c8ab1cdd9..dd22cbbb57e0 100644 --- a/packages/element-library/src/text/util.ts +++ b/packages/element-library/src/text/util.ts @@ -24,6 +24,7 @@ import type { TextElement, TextElementFont, } from '@googleforcreators/elements'; +import { generatePatternStyles, type Pattern } from '@googleforcreators/patterns'; type DataToStyle = (prop: number) => string; interface Props { @@ -108,9 +109,8 @@ export const getHighlightLineheight = ( if (verticalPadding === 0) { return `${lineHeight}em`; } - return `calc(${lineHeight}em ${verticalPadding > 0 ? '+' : '-'} ${ - 2 * Math.abs(verticalPadding) - }${unit})`; + return `calc(${lineHeight}em ${verticalPadding > 0 ? '+' : '-'} ${2 * Math.abs(verticalPadding) + }${unit})`; }; export function calcFontMetrics(element: TextElement) { @@ -142,3 +142,19 @@ export function calcFontMetrics(element: TextElement) { lineBoxPx, }; } + +export function generateTextColorCSS(textColor: Pattern) { + if (!textColor) return ''; + + const patternStyles = generatePatternStyles(textColor); + + const css = textColor.type ? ` + background: ${patternStyles.backgroundImage}; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + ` : ` + color: ${patternStyles.backgroundColor}; + `; + + return css; +} From ecf99c03fc746a15366101b2e027e415acf0de83 Mon Sep 17 00:00:00 2001 From: Swanand Mathekar Date: Fri, 16 Feb 2024 10:40:00 +0530 Subject: [PATCH 03/29] Get color using `useCommonColorValue` and use `pushUpdate` instead of `handleSetColor` on changing the color --- .../components/panels/design/textStyle/color.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/story-editor/src/components/panels/design/textStyle/color.js b/packages/story-editor/src/components/panels/design/textStyle/color.js index b95738734079..7b15a19e7c8b 100644 --- a/packages/story-editor/src/components/panels/design/textStyle/color.js +++ b/packages/story-editor/src/components/panels/design/textStyle/color.js @@ -25,25 +25,35 @@ import { __ } from '@googleforcreators/i18n'; */ import { Color, Row } from '../../../form'; import useRichTextFormatting from './useRichTextFormatting'; +import useCommonColorValue from '../../shared/useCommonColorValue'; function ColorControls({ selectedElements, pushUpdate, textColorRef }) { const { textInfo: { color }, - handlers: { handleSetColor }, } = useRichTextFormatting(selectedElements, pushUpdate); + const textColor = useCommonColorValue(selectedElements, 'textColor'); + return ( { + pushUpdate( + { + textColor: value, + }, + true + ); + }} allowsSavedColors label={__('Text color', 'web-stories')} labelId="text-color-label" changedStyle="color" ref={textColorRef} hasEyedropper + allowsGradient /> ); From 81328b3283ca29f8c8dbd8fb7ddcbd52ddf42176 Mon Sep 17 00:00:00 2001 From: Swanand Mathekar Date: Fri, 16 Feb 2024 10:40:40 +0530 Subject: [PATCH 04/29] Generate and apply textColor styles to `EditTextBox` --- packages/element-library/src/text/edit.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/element-library/src/text/edit.js b/packages/element-library/src/text/edit.js index 8f86e603eeee..1af5006ae281 100644 --- a/packages/element-library/src/text/edit.js +++ b/packages/element-library/src/text/edit.js @@ -61,6 +61,7 @@ import useColorTransformHandler from '../shared/useColorTransformHandler'; import { calcFontMetrics, generateParagraphTextStyle, + generateTextColorCSS, getHighlightLineheight, } from './util'; @@ -99,7 +100,8 @@ const EditTextBox = styled(TextBox)( hasHighlightBackgroundTextMode && { paddingTop: 0, paddingBottom: 0, - } + }, + ({ textColor }) => generateTextColorCSS(textColor) ); const Highlight = styled.span` @@ -136,6 +138,7 @@ function TextEdit({ borderRadius, opacity, height: elementHeight, + textColor, ...rest } = element; const { font } = rest; @@ -185,6 +188,7 @@ function TextEdit({ ...(backgroundTextMode === BACKGROUND_TEXT_MODE.NONE && { backgroundColor: null, }), + textColor, }; const { padding: _, ...highlightTextProps } = textProps; From 92466683a7744e7a3250c66e1712d02b8846dcd1 Mon Sep 17 00:00:00 2001 From: Swanand Mathekar Date: Fri, 16 Feb 2024 10:46:48 +0530 Subject: [PATCH 05/29] Remove `useColorTransformHandler` for `color` property. Generate and apply textColor styles to `FillElement` --- packages/element-library/src/text/display.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/element-library/src/text/display.js b/packages/element-library/src/text/display.js index 156fd435f8ea..82629ce9f712 100644 --- a/packages/element-library/src/text/display.js +++ b/packages/element-library/src/text/display.js @@ -51,6 +51,7 @@ import { generateParagraphTextStyle, calcFontMetrics, generateFontFamily, + generateTextColorCSS, } from './util'; const OutsideBorder = styled.div` @@ -136,6 +137,7 @@ const FillElement = styled.p.attrs( ${elementFillContent} ${({ previewMode }) => !previewMode && elementWithFont} ${({ previewMode }) => !previewMode && elementWithTextParagraphStyle} + ${({ textColor }) => generateTextColorCSS(textColor)} `; const Background = styled.div` @@ -154,6 +156,7 @@ function TextDisplay({ backgroundTextMode, border, borderRadius, + textColor, ...rest }, previewMode, @@ -162,7 +165,6 @@ function TextDisplay({ const ref = useRef(null); const outerBorderRef = useRef(null); const bgRef = useRef(null); - const fgRef = useRef(null); const { dataToEditorX, dataToEditorY } = useUnits((state) => ({ dataToEditorX: state.actions.dataToEditorX, @@ -196,6 +198,7 @@ function TextDisplay({ ), horizontalPadding: dataToEditorX(rest.padding?.horizontal || 0), verticalPadding: dataToEditorX(rest.padding?.vertical || 0), + textColor, }; useEffect(() => { maybeEnqueueFontStyle([{ ...fontFaceSetConfigs, font }]); @@ -205,8 +208,8 @@ function TextDisplay({ const refWithBorder = isHighLight ? outerBorderRef : bgRef; useTransformHandler(id, (transform) => { - // Ref is set in case of high-light mode only, use the fgRef if that's missing. - const target = ref?.current || fgRef.current; + // Ref is set in case of high-light mode only. + const target = ref?.current; if (!target) { return; } @@ -241,7 +244,6 @@ function TextDisplay({ targetRef: bgRef, expectedStyle: 'background', }); - useColorTransformHandler({ id, targetRef: fgRef, expectedStyle: 'color' }); useColorTransformHandler({ id, targetRef: refWithBorder, @@ -284,7 +286,6 @@ function TextDisplay({ Date: Thu, 22 Feb 2024 10:57:07 +0530 Subject: [PATCH 06/29] =?UTF-8?q?=E2=8F=AA=20Revert=20the=20added=20`textC?= =?UTF-8?q?olor`=20attribute?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/element-library/src/text/constants.js | 1 - packages/element-library/src/types/elements/textElement.ts | 1 - packages/elements/src/types/element.ts | 1 - 3 files changed, 3 deletions(-) diff --git a/packages/element-library/src/text/constants.js b/packages/element-library/src/text/constants.js index 8dbd8b31b942..7d6bb2b80b70 100644 --- a/packages/element-library/src/text/constants.js +++ b/packages/element-library/src/text/constants.js @@ -42,7 +42,6 @@ export const defaultAttributes = { horizontal: 0, locked: true, }, - textColor: createSolid(0, 0, 0), }; export const hasEditMode = true; diff --git a/packages/element-library/src/types/elements/textElement.ts b/packages/element-library/src/types/elements/textElement.ts index 4e3fe6792be2..2b417a1107a8 100644 --- a/packages/element-library/src/types/elements/textElement.ts +++ b/packages/element-library/src/types/elements/textElement.ts @@ -47,5 +47,4 @@ export interface TextElement extends Element { tagName?: 'h1' | 'h2' | 'h3' | 'p'; padding?: Padding; marginOffset?: number; - textColor?: Pattern; } diff --git a/packages/elements/src/types/element.ts b/packages/elements/src/types/element.ts index 10b2bb53d0c2..d6caaf6509bf 100644 --- a/packages/elements/src/types/element.ts +++ b/packages/elements/src/types/element.ts @@ -193,5 +193,4 @@ export interface TextElement extends Element { marginOffset: number; lineHeight: number; textAlign: TextAlign; - textColor: Solid; } From 861e8ad09745b76dc8c5795df6407e11497d5211 Mon Sep 17 00:00:00 2001 From: Swanand Mathekar Date: Thu, 22 Feb 2024 10:58:01 +0530 Subject: [PATCH 07/29] =?UTF-8?q?=E2=8F=AA=20Revert=20the=20added=20`gener?= =?UTF-8?q?ateTextColorCSS`=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/element-library/src/text/util.ts | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/packages/element-library/src/text/util.ts b/packages/element-library/src/text/util.ts index dd22cbbb57e0..0efbb78b99cf 100644 --- a/packages/element-library/src/text/util.ts +++ b/packages/element-library/src/text/util.ts @@ -24,7 +24,6 @@ import type { TextElement, TextElementFont, } from '@googleforcreators/elements'; -import { generatePatternStyles, type Pattern } from '@googleforcreators/patterns'; type DataToStyle = (prop: number) => string; interface Props { @@ -142,19 +141,3 @@ export function calcFontMetrics(element: TextElement) { lineBoxPx, }; } - -export function generateTextColorCSS(textColor: Pattern) { - if (!textColor) return ''; - - const patternStyles = generatePatternStyles(textColor); - - const css = textColor.type ? ` - background: ${patternStyles.backgroundImage}; - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - ` : ` - color: ${patternStyles.backgroundColor}; - `; - - return css; -} From d9df571efb83b215b20e2d7fbc6c26d0795baca0 Mon Sep 17 00:00:00 2001 From: Swanand Mathekar Date: Thu, 22 Feb 2024 11:11:14 +0530 Subject: [PATCH 08/29] =?UTF-8?q?=E2=8F=AA=20Revert=20the=20used=20`textCo?= =?UTF-8?q?lor`=20attribute?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/element-library/src/text/display.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/element-library/src/text/display.js b/packages/element-library/src/text/display.js index 82629ce9f712..1797073254fd 100644 --- a/packages/element-library/src/text/display.js +++ b/packages/element-library/src/text/display.js @@ -51,7 +51,6 @@ import { generateParagraphTextStyle, calcFontMetrics, generateFontFamily, - generateTextColorCSS, } from './util'; const OutsideBorder = styled.div` @@ -137,7 +136,6 @@ const FillElement = styled.p.attrs( ${elementFillContent} ${({ previewMode }) => !previewMode && elementWithFont} ${({ previewMode }) => !previewMode && elementWithTextParagraphStyle} - ${({ textColor }) => generateTextColorCSS(textColor)} `; const Background = styled.div` @@ -156,7 +154,6 @@ function TextDisplay({ backgroundTextMode, border, borderRadius, - textColor, ...rest }, previewMode, @@ -165,6 +162,7 @@ function TextDisplay({ const ref = useRef(null); const outerBorderRef = useRef(null); const bgRef = useRef(null); + const fgRef = useRef(null); const { dataToEditorX, dataToEditorY } = useUnits((state) => ({ dataToEditorX: state.actions.dataToEditorX, @@ -198,7 +196,6 @@ function TextDisplay({ ), horizontalPadding: dataToEditorX(rest.padding?.horizontal || 0), verticalPadding: dataToEditorX(rest.padding?.vertical || 0), - textColor, }; useEffect(() => { maybeEnqueueFontStyle([{ ...fontFaceSetConfigs, font }]); @@ -208,8 +205,8 @@ function TextDisplay({ const refWithBorder = isHighLight ? outerBorderRef : bgRef; useTransformHandler(id, (transform) => { - // Ref is set in case of high-light mode only. - const target = ref?.current; + // Ref is set in case of high-light mode only, use the fgRef if that's missing. + const target = ref?.current || fgRef.current; if (!target) { return; } @@ -286,6 +283,7 @@ function TextDisplay({ Date: Thu, 22 Feb 2024 11:17:15 +0530 Subject: [PATCH 09/29] Add rich-text formatter (getter and setter) for gradient color --- packages/rich-text/src/customConstants.ts | 1 + .../rich-text/src/formatters/gradientColor.ts | 121 ++++++++++++++++++ packages/rich-text/src/formatters/index.ts | 2 + .../design/textStyle/useRichTextFormatting.js | 3 + 4 files changed, 127 insertions(+) create mode 100644 packages/rich-text/src/formatters/gradientColor.ts diff --git a/packages/rich-text/src/customConstants.ts b/packages/rich-text/src/customConstants.ts index 1ba45323be1b..2f692a8a4b3e 100644 --- a/packages/rich-text/src/customConstants.ts +++ b/packages/rich-text/src/customConstants.ts @@ -21,5 +21,6 @@ export const WEIGHT = 'CUSTOM-WEIGHT'; export const COLOR = 'CUSTOM-COLOR'; export const LETTERSPACING = 'CUSTOM-LETTERSPACING'; export const UPPERCASE = 'CUSTOM-UPPERCASE'; +export const GRADIENT_COLOR = 'CUSTOM-GRADIENT-COLOR'; export const MULTIPLE_VALUE = '((MULTIPLE))'; diff --git a/packages/rich-text/src/formatters/gradientColor.ts b/packages/rich-text/src/formatters/gradientColor.ts new file mode 100644 index 000000000000..bed12485dc38 --- /dev/null +++ b/packages/rich-text/src/formatters/gradientColor.ts @@ -0,0 +1,121 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * External dependencies + */ +import { + createSolid, + generatePatternStyles, + getGradientStyleFromColor, + isPatternEqual, + getColorFromGradientStyle, +} from '@googleforcreators/patterns'; +import type { Gradient, Pattern } from '@googleforcreators/patterns'; +import type { EditorState, DraftInlineStyle } from 'draft-js'; +import type { CSSProperties } from 'react'; + +/** + * Internal dependencies + */ +import { NONE, MULTIPLE_VALUE, GRADIENT_COLOR } from '../customConstants'; +import { + togglePrefixStyle, + getPrefixStylesInSelection, +} from '../styleManipulation'; +import { isStyle, getVariable } from './util'; + +const styleToColor = (style: string): Gradient => + getColorFromGradientStyle(getVariable(style, GRADIENT_COLOR)); + +const colorToStyle = (color: Gradient): string => + `${GRADIENT_COLOR}-${getGradientStyleFromColor(color)}`; + +function elementToStyle(element: HTMLElement): string | null { + const isSpan = element.tagName.toLowerCase() === 'span'; + const rawBackground = element.style.background; + const hasBackground = Boolean(rawBackground); + + if (isSpan && hasBackground) { + const gradient = getColorFromGradientStyle(rawBackground); + return colorToStyle(gradient); + } + + return null; +} + +function stylesToCSS(styles: DraftInlineStyle): null | CSSProperties { + const colorStyle = styles.find((someStyle) => + isStyle(someStyle, GRADIENT_COLOR) + ); + + if (!colorStyle) { + return null; + } + + let color: Pattern; + try { + color = styleToColor(colorStyle); + } catch (e) { + return null; + } + + const css = generatePatternStyles(color); + + return { + background: css.backgroundImage, + WebkitBackgroundClip: 'text', + WebkitTextFillColor: 'transparent', + }; +} + +function getColor(editorState: EditorState): Pattern | '((MULTIPLE))' { + const styles = getPrefixStylesInSelection(editorState, GRADIENT_COLOR); + if (styles.length > 1) { + return MULTIPLE_VALUE; + } + const colorStyle = styles[0]; + if (colorStyle === NONE) { + return createSolid(0, 0, 0); + } + return styleToColor(colorStyle); +} + +function setColor(editorState: EditorState, color: Gradient) { + const isBlack = isPatternEqual(createSolid(0, 0, 0), color); + const shouldSetStyle = () => !isBlack; + const getStyleToSet = () => colorToStyle(color); + return togglePrefixStyle( + editorState, + GRADIENT_COLOR, + shouldSetStyle, + getStyleToSet + ); +} + +const formatter = { + elementToStyle, + stylesToCSS, + autoFocus: false, + getters: { + gradientColor: getColor, + }, + setters: { + setGradientColor: setColor, + }, +}; + +export default formatter; diff --git a/packages/rich-text/src/formatters/index.ts b/packages/rich-text/src/formatters/index.ts index 178caea2e1c4..65debe4b95ef 100644 --- a/packages/rich-text/src/formatters/index.ts +++ b/packages/rich-text/src/formatters/index.ts @@ -22,6 +22,7 @@ import weightFormatter from './weight'; import italicFormatter from './italic'; import underlineFormatter from './underline'; import colorFormatter from './color'; +import gradientColorFormatter from './gradientColor'; import letterSpacingFormatter from './letterSpacing'; import uppercaseFormatter from './uppercase'; @@ -32,6 +33,7 @@ const formatters: Formatter[] = [ colorFormatter, letterSpacingFormatter, uppercaseFormatter, + gradientColorFormatter ]; export default formatters; diff --git a/packages/story-editor/src/components/panels/design/textStyle/useRichTextFormatting.js b/packages/story-editor/src/components/panels/design/textStyle/useRichTextFormatting.js index b27402f376a4..9f08641fed7c 100644 --- a/packages/story-editor/src/components/panels/design/textStyle/useRichTextFormatting.js +++ b/packages/story-editor/src/components/panels/design/textStyle/useRichTextFormatting.js @@ -151,6 +151,7 @@ function useRichTextFormatting(selectedElements, pushUpdate) { handleClickUppercase: selectionActions.toggleUppercaseInSelection, handleSetLetterSpacing: selectionActions.setLetterSpacingInSelection, handleSetColor: selectionActions.setColorInSelection, + handleSetGradientColor: selectionActions.setGradientColorInSelection, // when editing, resetting font weight needs to save before resetting handleResetFontWeight: async (weight) => { // clear editing to save any pending updates @@ -173,6 +174,8 @@ function useRichTextFormatting(selectedElements, pushUpdate) { handleSetLetterSpacing: (letterSpacing) => push(htmlFormatters.setLetterSpacing, letterSpacing), handleSetColor: (color) => push(htmlFormatters.setColor, color), + handleSetGradientColor: (color) => + push(htmlFormatters.setGradientColor, color), handleResetFontWeight: (weight) => push(htmlFormatters.setFontWeight, weight), }; From cbb9ce0cc4f9d0e2d231152657bb12b4df35d76d Mon Sep 17 00:00:00 2001 From: Swanand Mathekar Date: Thu, 22 Feb 2024 11:20:11 +0530 Subject: [PATCH 10/29] Add `getColorFromGradientStyle` and `getGradientStyleFromColor` utility functions --- .../patterns/src/getColorFromGradientStyle.ts | 126 ++++++++++++++++++ .../patterns/src/getGradientStyleFromColor.ts | 26 ++++ packages/patterns/src/index.ts | 2 + 3 files changed, 154 insertions(+) create mode 100644 packages/patterns/src/getColorFromGradientStyle.ts create mode 100644 packages/patterns/src/getGradientStyleFromColor.ts diff --git a/packages/patterns/src/getColorFromGradientStyle.ts b/packages/patterns/src/getColorFromGradientStyle.ts new file mode 100644 index 000000000000..c6f6c58a3b5e --- /dev/null +++ b/packages/patterns/src/getColorFromGradientStyle.ts @@ -0,0 +1,126 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Internal dependencies + */ +import createSolidFromString from './createSolidFromString'; +import { PatternType, type Gradient, type Linear } from './types'; + +const DEFAULT_GRADIENT: Linear = { + type: PatternType.Linear, + stops: [ + { + color: { + r: 0, + g: 0, + b: 0, + }, + position: 0, + }, + { + color: { + r: 0, + g: 0, + b: 0, + }, + position: 1, + }, + ], +}; + +const GRADIENT = { + LINEAR: 'linear-gradient', + RADIAL: 'radial-gradient', +}; + +const REGEX = { + [GRADIENT.LINEAR]: + /linear-gradient\((?:-?\d*\.?\d+turn,\s*)?(?:rgba?\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),?\s*(\d*\.?\d+)?\)|#([0-9a-fA-F]{6}))\s*0%,\s*(?:rgba?\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),?\s*(\d*\.?\d+)?\)|#([0-9a-fA-F]{6}))\s*100%\)/, + [GRADIENT.RADIAL]: + /radial-gradient\((?:rgba?\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),?\s*(\d*\.?\d+)?\)|#([0-9a-fA-F]{6}))\s*0%,\s*(?:rgba?\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),?\s*(\d*\.?\d+)?\)|#([0-9a-fA-F]{6}))\s*100%\)/, +}; + +export default function getColorFromGradientStyle(style: string): Gradient { + if (style.includes(GRADIENT.LINEAR)) { + return parseGradient(style, GRADIENT.LINEAR); + } + return parseGradient(style, GRADIENT.RADIAL); +} + +function parseGradient(style: string, gradient: string): Gradient { + const regex = REGEX[gradient]; + const matches = style.match(regex); + if (!matches) { + return DEFAULT_GRADIENT; + } + + const { startColor, endColor } = getColorRange(matches); + + if (gradient === GRADIENT.LINEAR) { + const rotationMatch = style.match(/-?\d*\.?\d+turn/); + return { + type: PatternType.Linear, + stops: [ + { color: startColor, position: 0 }, + { color: endColor, position: 1 }, + ], + rotation: rotationMatch ? parseFloat(rotationMatch[0]) : 0, + }; + } + + return { + type: PatternType.Radial, + stops: [ + { color: startColor, position: 0 }, + { color: endColor, position: 1 }, + ], + }; +} + +function getColorRange(matches: RegExpMatchArray) { + const [ + , + startColorR, + startColorG, + startColorB, + startAlpha, + startHex, + endColorR, + endColorG, + endColorB, + endAlpha, + endHex, + ] = matches; + + const startColor = startHex + ? createSolidFromString(`#${startHex}`).color + : parseColor(startColorR, startColorG, startColorB, startAlpha); + + const endColor = endHex + ? createSolidFromString(`#${endHex}`).color + : parseColor(endColorR, endColorG, endColorB, endAlpha); + + return { startColor, endColor }; +} + +function parseColor(r: string, g: string, b: string, a: string) { + return { + r: parseInt(r), + g: parseInt(g), + b: parseInt(b), + a: a ? parseFloat(a) : undefined, + }; +} diff --git a/packages/patterns/src/getGradientStyleFromColor.ts b/packages/patterns/src/getGradientStyleFromColor.ts new file mode 100644 index 000000000000..05d6af9dc723 --- /dev/null +++ b/packages/patterns/src/getGradientStyleFromColor.ts @@ -0,0 +1,26 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Internal dependencies + */ +import generatePatternStyles from './generatePatternStyles'; +import type { Gradient } from './types'; + +export default function getGradientStyleFromColor(color: Gradient) { + const gradient = generatePatternStyles(color); + + return gradient.backgroundImage; +} diff --git a/packages/patterns/src/index.ts b/packages/patterns/src/index.ts index db78e9444787..aef39652bd1d 100644 --- a/packages/patterns/src/index.ts +++ b/packages/patterns/src/index.ts @@ -30,3 +30,5 @@ export { default as hasGradient } from './hasGradient'; export { default as hasOpacity } from './hasOpacity'; export { default as isPatternEqual } from './isPatternEqual'; export { default as isHexColorString } from './isHexColorString'; +export { default as getGradientStyleFromColor } from './getGradientStyleFromColor'; +export { default as getColorFromGradientStyle } from './getColorFromGradientStyle'; From 987ad71a5fe4473e98eb8cdd06e4d25be4062b18 Mon Sep 17 00:00:00 2001 From: Swanand Mathekar Date: Thu, 22 Feb 2024 11:22:54 +0530 Subject: [PATCH 11/29] =?UTF-8?q?=E2=8F=AA=20Revert=20the=20used=20`textCo?= =?UTF-8?q?lor`=20attribute=20in=20`edit.js`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/element-library/src/text/edit.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/element-library/src/text/edit.js b/packages/element-library/src/text/edit.js index 1af5006ae281..8f86e603eeee 100644 --- a/packages/element-library/src/text/edit.js +++ b/packages/element-library/src/text/edit.js @@ -61,7 +61,6 @@ import useColorTransformHandler from '../shared/useColorTransformHandler'; import { calcFontMetrics, generateParagraphTextStyle, - generateTextColorCSS, getHighlightLineheight, } from './util'; @@ -100,8 +99,7 @@ const EditTextBox = styled(TextBox)( hasHighlightBackgroundTextMode && { paddingTop: 0, paddingBottom: 0, - }, - ({ textColor }) => generateTextColorCSS(textColor) + } ); const Highlight = styled.span` @@ -138,7 +136,6 @@ function TextEdit({ borderRadius, opacity, height: elementHeight, - textColor, ...rest } = element; const { font } = rest; @@ -188,7 +185,6 @@ function TextEdit({ ...(backgroundTextMode === BACKGROUND_TEXT_MODE.NONE && { backgroundColor: null, }), - textColor, }; const { padding: _, ...highlightTextProps } = textProps; From eec3e967f6a10d87bd0da7105607fea1e2836f09 Mon Sep 17 00:00:00 2001 From: Swanand Mathekar Date: Thu, 22 Feb 2024 11:29:37 +0530 Subject: [PATCH 12/29] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor=20to=20use?= =?UTF-8?q?=20the=20gradientColor=20formatters?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../floatingMenu/elements/textColor.js | 22 +++++++++++---- .../panels/design/textStyle/color.js | 27 ++++++++++--------- 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/packages/story-editor/src/components/floatingMenu/elements/textColor.js b/packages/story-editor/src/components/floatingMenu/elements/textColor.js index 69ec0f74c6fc..aa20f2fa75d2 100644 --- a/packages/story-editor/src/components/floatingMenu/elements/textColor.js +++ b/packages/story-editor/src/components/floatingMenu/elements/textColor.js @@ -20,6 +20,7 @@ import { __ } from '@googleforcreators/i18n'; import { useCallback } from '@googleforcreators/react'; import { trackEvent } from '@googleforcreators/tracking'; +import { hasGradient, createSolid } from '@googleforcreators/patterns'; /** * Internal dependencies @@ -51,22 +52,33 @@ function TextColor() { }, [updateElementsById, selectedElementIds] ); + + const onColorChange = (color) => { + if (hasGradient(color)) { + handleSetColor(createSolid(0, 0, 0)); + handleSetGradientColor(color); + } else { + handleSetGradientColor(createSolid(0, 0, 0)); + handleSetColor(color); + } + }; + const { - textInfo: { color }, - handlers: { handleSetColor }, + textInfo: { color, gradientColor }, + handlers: { handleSetColor, handleSetGradientColor }, } = useRichTextFormatting([{ content, type: 'text' }], pushUpdate); return ( ); } diff --git a/packages/story-editor/src/components/panels/design/textStyle/color.js b/packages/story-editor/src/components/panels/design/textStyle/color.js index 7b15a19e7c8b..3768ca1562f1 100644 --- a/packages/story-editor/src/components/panels/design/textStyle/color.js +++ b/packages/story-editor/src/components/panels/design/textStyle/color.js @@ -19,38 +19,39 @@ */ import PropTypes from 'prop-types'; import { __ } from '@googleforcreators/i18n'; +import { hasGradient, createSolid } from '@googleforcreators/patterns'; /** * Internal dependencies */ import { Color, Row } from '../../../form'; import useRichTextFormatting from './useRichTextFormatting'; -import useCommonColorValue from '../../shared/useCommonColorValue'; function ColorControls({ selectedElements, pushUpdate, textColorRef }) { const { - textInfo: { color }, + textInfo: { color, gradientColor }, + handlers: { handleSetColor, handleSetGradientColor }, } = useRichTextFormatting(selectedElements, pushUpdate); - const textColor = useCommonColorValue(selectedElements, 'textColor'); + const onColorChange = (colorValue) => { + if (hasGradient(colorValue)) { + handleSetColor(createSolid(0, 0, 0)); + handleSetGradientColor(colorValue); + } else { + handleSetGradientColor(createSolid(0, 0, 0)); + handleSetColor(colorValue); + } + }; return ( { - pushUpdate( - { - textColor: value, - }, - true - ); - }} + value={hasGradient(gradientColor) ? gradientColor : color} + onChange={onColorChange} allowsSavedColors label={__('Text color', 'web-stories')} labelId="text-color-label" - changedStyle="color" ref={textColorRef} hasEyedropper allowsGradient From 09ba44d8c6f07b03309ca3d8d13b0bcce019abf7 Mon Sep 17 00:00:00 2001 From: Swanand Mathekar Date: Mon, 4 Mar 2024 12:32:24 +0530 Subject: [PATCH 13/29] Update regex for rotation in linear gradient --- packages/patterns/src/getColorFromGradientStyle.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/patterns/src/getColorFromGradientStyle.ts b/packages/patterns/src/getColorFromGradientStyle.ts index c6f6c58a3b5e..d67d8ac0ee99 100644 --- a/packages/patterns/src/getColorFromGradientStyle.ts +++ b/packages/patterns/src/getColorFromGradientStyle.ts @@ -70,7 +70,7 @@ function parseGradient(style: string, gradient: string): Gradient { const { startColor, endColor } = getColorRange(matches); if (gradient === GRADIENT.LINEAR) { - const rotationMatch = style.match(/-?\d*\.?\d+turn/); + const rotationMatch = style.match(/-?\d+(\.\d+)?turn/); return { type: PatternType.Linear, stops: [ From e587b085256832424eada84e07a4f9b91f40014c Mon Sep 17 00:00:00 2001 From: Swanand Mathekar Date: Mon, 4 Mar 2024 12:34:24 +0530 Subject: [PATCH 14/29] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Remove=20use=20of=20?= =?UTF-8?q?shorthand=20css=20styles?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/rich-text/src/formatters/gradientColor.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/rich-text/src/formatters/gradientColor.ts b/packages/rich-text/src/formatters/gradientColor.ts index bed12485dc38..8717f2bf39be 100644 --- a/packages/rich-text/src/formatters/gradientColor.ts +++ b/packages/rich-text/src/formatters/gradientColor.ts @@ -46,7 +46,7 @@ const colorToStyle = (color: Gradient): string => function elementToStyle(element: HTMLElement): string | null { const isSpan = element.tagName.toLowerCase() === 'span'; - const rawBackground = element.style.background; + const rawBackground = element.style.backgroundImage; const hasBackground = Boolean(rawBackground); if (isSpan && hasBackground) { @@ -73,10 +73,11 @@ function stylesToCSS(styles: DraftInlineStyle): null | CSSProperties { return null; } - const css = generatePatternStyles(color); + const { backgroundImage } = generatePatternStyles(color); return { - background: css.backgroundImage, + backgroundImage, + backgroundClip: 'text', WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent', }; From 6ad55fac1cd26b1d77a5a9408f15f9d7d7582a04 Mon Sep 17 00:00:00 2001 From: Swanand Mathekar Date: Mon, 4 Mar 2024 12:35:59 +0530 Subject: [PATCH 15/29] Unset WebkitTextFillColor on selecting text --- packages/rich-text/src/fauxSelection.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/rich-text/src/fauxSelection.ts b/packages/rich-text/src/fauxSelection.ts index f8783ccb3cb8..f0dd553141dc 100644 --- a/packages/rich-text/src/fauxSelection.ts +++ b/packages/rich-text/src/fauxSelection.ts @@ -138,6 +138,7 @@ export function fauxStylesToCSS(styles: DraftInlineStyle, css: CSSProperties) { backgroundColor: 'rgba(169, 169, 169, 0.7)', }; if (css?.color) { + style.WebkitTextFillColor = 'unset'; style.color = `var(--faux-selection-color, ${css.color})`; } return style; From 9e0b841e1a21b4562cfeccadae8b38ad77d422cf Mon Sep 17 00:00:00 2001 From: Swanand Mathekar Date: Mon, 4 Mar 2024 13:23:40 +0530 Subject: [PATCH 16/29] Refine rotation regex for linear gradient --- packages/patterns/src/getColorFromGradientStyle.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/patterns/src/getColorFromGradientStyle.ts b/packages/patterns/src/getColorFromGradientStyle.ts index d67d8ac0ee99..48b87a8a2971 100644 --- a/packages/patterns/src/getColorFromGradientStyle.ts +++ b/packages/patterns/src/getColorFromGradientStyle.ts @@ -70,7 +70,7 @@ function parseGradient(style: string, gradient: string): Gradient { const { startColor, endColor } = getColorRange(matches); if (gradient === GRADIENT.LINEAR) { - const rotationMatch = style.match(/-?\d+(\.\d+)?turn/); + const rotationMatch = style.match(/0(\.((25|5|75)))?turn/); return { type: PatternType.Linear, stops: [ From 3e5fa35676105cd9153f50cb7aba7be217b58e80 Mon Sep 17 00:00:00 2001 From: Swanand Mathekar Date: Wed, 6 Mar 2024 10:59:03 +0530 Subject: [PATCH 17/29] Export and use `DEFAULT_GRADIENT` --- packages/patterns/src/getColorFromGradientStyle.ts | 8 ++++---- packages/patterns/src/index.ts | 5 ++++- packages/rich-text/src/formatters/gradientColor.ts | 8 ++++++-- .../src/components/panels/design/textStyle/color.js | 8 ++++++-- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/packages/patterns/src/getColorFromGradientStyle.ts b/packages/patterns/src/getColorFromGradientStyle.ts index 48b87a8a2971..a737072c8ebf 100644 --- a/packages/patterns/src/getColorFromGradientStyle.ts +++ b/packages/patterns/src/getColorFromGradientStyle.ts @@ -19,7 +19,7 @@ import createSolidFromString from './createSolidFromString'; import { PatternType, type Gradient, type Linear } from './types'; -const DEFAULT_GRADIENT: Linear = { +export const DEFAULT_GRADIENT: Linear = { type: PatternType.Linear, stops: [ { @@ -32,9 +32,9 @@ const DEFAULT_GRADIENT: Linear = { }, { color: { - r: 0, - g: 0, - b: 0, + r: 1, + g: 1, + b: 1, }, position: 1, }, diff --git a/packages/patterns/src/index.ts b/packages/patterns/src/index.ts index aef39652bd1d..209e9284ba39 100644 --- a/packages/patterns/src/index.ts +++ b/packages/patterns/src/index.ts @@ -31,4 +31,7 @@ export { default as hasOpacity } from './hasOpacity'; export { default as isPatternEqual } from './isPatternEqual'; export { default as isHexColorString } from './isHexColorString'; export { default as getGradientStyleFromColor } from './getGradientStyleFromColor'; -export { default as getColorFromGradientStyle } from './getColorFromGradientStyle'; +export { + default as getColorFromGradientStyle, + DEFAULT_GRADIENT, +} from './getColorFromGradientStyle'; diff --git a/packages/rich-text/src/formatters/gradientColor.ts b/packages/rich-text/src/formatters/gradientColor.ts index 8717f2bf39be..192a3fb9953d 100644 --- a/packages/rich-text/src/formatters/gradientColor.ts +++ b/packages/rich-text/src/formatters/gradientColor.ts @@ -24,7 +24,11 @@ import { isPatternEqual, getColorFromGradientStyle, } from '@googleforcreators/patterns'; -import type { Gradient, Pattern } from '@googleforcreators/patterns'; +import { + type Gradient, + type Pattern, + DEFAULT_GRADIENT, +} from '@googleforcreators/patterns'; import type { EditorState, DraftInlineStyle } from 'draft-js'; import type { CSSProperties } from 'react'; @@ -96,7 +100,7 @@ function getColor(editorState: EditorState): Pattern | '((MULTIPLE))' { } function setColor(editorState: EditorState, color: Gradient) { - const isBlack = isPatternEqual(createSolid(0, 0, 0), color); + const isBlack = isPatternEqual(DEFAULT_GRADIENT, color); const shouldSetStyle = () => !isBlack; const getStyleToSet = () => colorToStyle(color); return togglePrefixStyle( diff --git a/packages/story-editor/src/components/panels/design/textStyle/color.js b/packages/story-editor/src/components/panels/design/textStyle/color.js index 3768ca1562f1..e8424af866a3 100644 --- a/packages/story-editor/src/components/panels/design/textStyle/color.js +++ b/packages/story-editor/src/components/panels/design/textStyle/color.js @@ -19,7 +19,11 @@ */ import PropTypes from 'prop-types'; import { __ } from '@googleforcreators/i18n'; -import { hasGradient, createSolid } from '@googleforcreators/patterns'; +import { + hasGradient, + createSolid, + DEFAULT_GRADIENT, +} from '@googleforcreators/patterns'; /** * Internal dependencies @@ -38,7 +42,7 @@ function ColorControls({ selectedElements, pushUpdate, textColorRef }) { handleSetColor(createSolid(0, 0, 0)); handleSetGradientColor(colorValue); } else { - handleSetGradientColor(createSolid(0, 0, 0)); + handleSetGradientColor(DEFAULT_GRADIENT); handleSetColor(colorValue); } }; From 387d45dc1f877c7cd0c184d5ec3d02880c1755c6 Mon Sep 17 00:00:00 2001 From: Swanand01 Date: Mon, 18 Mar 2024 16:15:11 +0530 Subject: [PATCH 18/29] Fix: Show `Mixed` in color input on selecting two text elements with gradients --- .../src/components/floatingMenu/elements/textColor.js | 10 +++++++++- .../src/components/panels/design/textStyle/color.js | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/story-editor/src/components/floatingMenu/elements/textColor.js b/packages/story-editor/src/components/floatingMenu/elements/textColor.js index aa20f2fa75d2..5f60dab6aa26 100644 --- a/packages/story-editor/src/components/floatingMenu/elements/textColor.js +++ b/packages/story-editor/src/components/floatingMenu/elements/textColor.js @@ -28,6 +28,7 @@ import { hasGradient, createSolid } from '@googleforcreators/patterns'; import useRichTextFormatting from '../../panels/design/textStyle/useRichTextFormatting'; import updateProperties from '../../style/updateProperties'; import { useStory } from '../../../app'; +import { MULTIPLE_VALUE } from '../../../constants'; import { Color, useProperties } from './shared'; function TextColor() { @@ -68,12 +69,19 @@ function TextColor() { handlers: { handleSetColor, handleSetGradientColor }, } = useRichTextFormatting([{ content, type: 'text' }], pushUpdate); + const colorInputValue = + gradientColor === MULTIPLE_VALUE + ? MULTIPLE_VALUE + : hasGradient(gradientColor) + ? gradientColor + : color; + return ( Date: Tue, 19 Mar 2024 01:47:21 +0530 Subject: [PATCH 19/29] Fix redundant imports --- packages/rich-text/src/formatters/gradientColor.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/rich-text/src/formatters/gradientColor.ts b/packages/rich-text/src/formatters/gradientColor.ts index 192a3fb9953d..c48f4b43b670 100644 --- a/packages/rich-text/src/formatters/gradientColor.ts +++ b/packages/rich-text/src/formatters/gradientColor.ts @@ -23,8 +23,6 @@ import { getGradientStyleFromColor, isPatternEqual, getColorFromGradientStyle, -} from '@googleforcreators/patterns'; -import { type Gradient, type Pattern, DEFAULT_GRADIENT, From b9189431078d279d4f12364e50034340936e40f0 Mon Sep 17 00:00:00 2001 From: Swanand01 Date: Tue, 19 Mar 2024 01:48:39 +0530 Subject: [PATCH 20/29] Use `DEFAULT_GRADIENT` in `textColor.js` --- .../src/components/floatingMenu/elements/textColor.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/story-editor/src/components/floatingMenu/elements/textColor.js b/packages/story-editor/src/components/floatingMenu/elements/textColor.js index 5f60dab6aa26..efa458bce5f7 100644 --- a/packages/story-editor/src/components/floatingMenu/elements/textColor.js +++ b/packages/story-editor/src/components/floatingMenu/elements/textColor.js @@ -20,7 +20,11 @@ import { __ } from '@googleforcreators/i18n'; import { useCallback } from '@googleforcreators/react'; import { trackEvent } from '@googleforcreators/tracking'; -import { hasGradient, createSolid } from '@googleforcreators/patterns'; +import { + hasGradient, + createSolid, + DEFAULT_GRADIENT, +} from '@googleforcreators/patterns'; /** * Internal dependencies @@ -59,7 +63,7 @@ function TextColor() { handleSetColor(createSolid(0, 0, 0)); handleSetGradientColor(color); } else { - handleSetGradientColor(createSolid(0, 0, 0)); + handleSetGradientColor(DEFAULT_GRADIENT); handleSetColor(color); } }; From ac339b36a9767481447c7a4b9d061af1260c1d94 Mon Sep 17 00:00:00 2001 From: Swanand01 Date: Tue, 19 Mar 2024 01:49:02 +0530 Subject: [PATCH 21/29] Add unit tests --- .../panels/design/textStyle/test/textStyle.js | 46 +++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/packages/story-editor/src/components/panels/design/textStyle/test/textStyle.js b/packages/story-editor/src/components/panels/design/textStyle/test/textStyle.js index 96186acb9827..e207ea83776c 100644 --- a/packages/story-editor/src/components/panels/design/textStyle/test/textStyle.js +++ b/packages/story-editor/src/components/panels/design/textStyle/test/textStyle.js @@ -433,7 +433,7 @@ describe('Panels/TextStyle', () => { it('should set color', () => { const { pushUpdate } = arrange([textElement]); act(() => mockControls['text.color'].onChange(createSolid(0, 255, 0))); - const updatingFunction = pushUpdate.mock.calls[0][0]; + const updatingFunction = pushUpdate.mock.calls[1][0]; const resultOfUpdating = updatingFunction({ content: 'Hello world', }); @@ -445,6 +445,45 @@ describe('Panels/TextStyle', () => { ); }); + it('should set gradient color', () => { + const { pushUpdate } = arrange([textElement]); + act(() => + mockControls['text.color'].onChange({ + type: 'linear', + stops: [ + { + color: { + r: 0, + g: 0, + b: 0, + }, + position: 0, + }, + { + color: { + r: 1, + g: 1, + b: 1, + }, + position: 1, + }, + ], + rotation: 0.5, + }) + ); + const updatingFunction = pushUpdate.mock.calls[1][0]; + const resultOfUpdating = updatingFunction({ + content: 'Hello world', + }); + expect(resultOfUpdating).toStrictEqual( + { + content: + 'Hello world', + }, + true + ); + }); + it('should detect color with multi selection, same values', () => { const textWithColor1 = { ...textElement, @@ -460,14 +499,15 @@ describe('Panels/TextStyle', () => { ); }); - it('should set color with multi selection, different values', () => { + it('should set color with multi selection, mixed values', () => { const textWithColor1 = { ...textElement, content: 'Hello world', }; const textWithColor2 = { ...textElement, - content: 'Hello world', + content: + 'Hello world', }; arrange([textWithColor1, textWithColor2]); expect(mockControls['text.color'].value).toStrictEqual(MULTIPLE_VALUE); From 5ad437d89b6023ecb4d1ffb042ca12605a02e817 Mon Sep 17 00:00:00 2001 From: Swanand01 Date: Tue, 19 Mar 2024 01:49:57 +0530 Subject: [PATCH 22/29] Add gradient button getters to `ColorPicker` container --- .../src/karma/fixture/containers/common/color.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/story-editor/src/karma/fixture/containers/common/color.js b/packages/story-editor/src/karma/fixture/containers/common/color.js index 45a4224dcd76..094ccc38ae79 100644 --- a/packages/story-editor/src/karma/fixture/containers/common/color.js +++ b/packages/story-editor/src/karma/fixture/containers/common/color.js @@ -66,7 +66,7 @@ class ColorPicker extends Container { } get hexInput() { - return this.getByRole('textbox', { name: /Edit hex value/i }); + return this.getByRole('button', { name: /Edit hex value/i }); } get opacityButton() { @@ -127,5 +127,17 @@ class ColorPicker extends Container { return this.getByRole('option', { name }); } + get linearGradientPickerButton() { + return this.getByRole('button', { name: /Linear gradient pattern type/i }); + } + + get radialGradientPickerButton() { + return this.getByRole('button', { name: /Radial gradient pattern type/i }); + } + + get gradientStopEndButton() { + return this.getByRole('button', { name: /Gradient stop at 100%/i }); + } + // @todo: add accessors for remaining options } From 55e14a8a56a9abc9b765826ddf90c68481bcfa70 Mon Sep 17 00:00:00 2001 From: Swanand01 Date: Tue, 19 Mar 2024 01:50:08 +0530 Subject: [PATCH 23/29] Add karma tests --- .../floatingMenu/elements/karma/text.karma.js | 258 ++++++++++++++---- 1 file changed, 205 insertions(+), 53 deletions(-) diff --git a/packages/story-editor/src/components/floatingMenu/elements/karma/text.karma.js b/packages/story-editor/src/components/floatingMenu/elements/karma/text.karma.js index a89ac337ff94..a730bc1cdf41 100644 --- a/packages/story-editor/src/components/floatingMenu/elements/karma/text.karma.js +++ b/packages/story-editor/src/components/floatingMenu/elements/karma/text.karma.js @@ -51,6 +51,92 @@ describe('Design Menu: Text Styles', () => { return storyContext.state.selectedElements[0]; }; + const setLinearGradient = async () => { + await fixture.events.click( + fixture.editor.canvas.designMenu.fontColor.button + ); + + await fixture.events.click( + fixture.editor.canvas.designMenu.fontColor.picker.custom + ); + + await fixture.events.click( + fixture.editor.canvas.designMenu.fontColor.picker + .linearGradientPickerButton + ); + }; + + const setRadialGradient = async () => { + await fixture.events.click( + fixture.editor.canvas.designMenu.fontColor.button + ); + + await fixture.events.click( + fixture.editor.canvas.designMenu.fontColor.picker.custom + ); + + await fixture.events.click( + fixture.editor.canvas.designMenu.fontColor.picker + .radialGradientPickerButton + ); + await fixture.events.click( + fixture.editor.canvas.designMenu.fontColor.picker + .radialGradientPickerButton + ); + + await fixture.events.click( + fixture.editor.canvas.designMenu.fontColor.picker.gradientStopEndButton + ); + + await fixture.events.click( + fixture.editor.canvas.designMenu.fontColor.picker.hexInput + ); + await fixture.events.keyboard.type('b05151'); + await new Promise((r) => setTimeout(r, 100)); + }; + + const addText = async () => { + // Enter edit-mode + await fixture.events.keyboard.press('Enter'); + await fixture.screen.findByTestId('textEditor'); + + // Increase the font size for making sure setting selection works as expected. + await fixture.events.click(fixture.editor.canvas.designMenu.fontSize, { + clickCount: 3, + }); + await fixture.events.keyboard.type('30'); + await fixture.events.keyboard.press('tab'); + }; + + const closeColorPicker = async () => { + const colorPicker = fixture.screen.queryByRole('dialog', { + name: /Color and gradient picker/, + }); + const dismissPicker = within(colorPicker).queryByRole('button', { + name: 'Close', + }); + await fixture.events.click(dismissPicker); + }; + + const setSolidColor = async () => { + await fixture.events.click( + fixture.editor.canvas.designMenu.fontColor.button + ); + + await fixture.events.click( + fixture.editor.canvas.designMenu.fontColor.picker.defaultColor('#ff7096') + ); + }; + + const exitEditMode = async () => { + // Click on background to exit edit mode. + await fixture.events.mouse.clickOn( + fixture.editor.canvas.framesLayer.frames[0].node, + '10%', + '10%' + ); + }; + it('should allow whole number font sizes', async () => { const fontSize = fixture.editor.canvas.designMenu.fontSize; @@ -80,67 +166,147 @@ describe('Design Menu: Text Styles', () => { describe('Text Color', () => { const { setSelection } = initHelpers(data); it('should allow changing text color from the design menu', async () => { - await fixture.events.click( - fixture.editor.canvas.designMenu.fontColor.button + await setSolidColor(); + const element = await getSelectedElement(); + expect(element.content).toBe( + 'Fill in some text' ); + }); - await fixture.events.click( - fixture.editor.canvas.designMenu.fontColor.picker.defaultColor( - '#ff7096' - ) + it('should allow changing linear gradient text color from the design menu', async () => { + await setLinearGradient(); + const element = await getSelectedElement(); + expect(element.content).toBe( + 'Fill in some text' ); + }); + it('should allow changing radial gradient text color from the design menu', async () => { + await setRadialGradient(); const element = await getSelectedElement(); expect(element.content).toBe( - 'Fill in some text' + 'Fill in some text' ); }); it('should allow changing text color for a selection from the design menu', async () => { - // Enter edit-mode - await fixture.events.keyboard.press('Enter'); - await fixture.screen.findByTestId('textEditor'); + await addText(); + + // Select character 6 and 7 (the part "in" in "Fill in some text") + await setSelection(5, 7); + await setSolidColor(); + await closeColorPicker(); + await exitEditMode(); + + const element = await getSelectedElement(); + expect(element.content).toBe( + 'Fill in some text' + ); + + await fixture.snapshot('Mixed color value in the floating menu'); + }); - // Increase the font size for making sure setting selection works as expected. - await fixture.events.click(fixture.editor.canvas.designMenu.fontSize, { - clickCount: 3, - }); - await fixture.events.keyboard.type('30'); - await fixture.events.keyboard.press('tab'); + it('should allow changing linear gradient color for a selection from the design menu', async () => { + await addText(); // Select character 6 and 7 (the part "in" in "Fill in some text") await setSelection(5, 7); - await fixture.events.click( - fixture.editor.canvas.designMenu.fontColor.button + await setLinearGradient(); + await closeColorPicker(); + await exitEditMode(); + + const element = await getSelectedElement(); + expect(element.content).toBe( + 'Fill in some text' ); + }); - await fixture.events.click( - fixture.editor.canvas.designMenu.fontColor.picker.defaultColor( - '#ff7096' - ) + it('should allow changing radial gradient color for a selection from the design menu', async () => { + await addText(); + + // Select character 6 and 7 (the part "in" in "Fill in some text") + await setSelection(5, 7); + await setRadialGradient(); + await closeColorPicker(); + await exitEditMode(); + + const element = await getSelectedElement(); + expect(element.content).toBe( + 'Fill in some text' ); + }); + + it('should allow adding solid and linear gradient color for a selection from the design menu', async () => { + await addText(); + + await setSelection(0, 4); + await setSolidColor(); + + // Select character 6 and 7 (the part "in" in "Fill in some text") + await setSelection(5, 7); + await setLinearGradient(); + await closeColorPicker(); + await exitEditMode(); - const colorPicker = fixture.screen.queryByRole('dialog', { - name: /Color and gradient picker/, - }); - const dismissPicker = within(colorPicker).queryByRole('button', { - name: 'Close', - }); - await fixture.events.click(dismissPicker); - - // Click on background to exit edit mode. - await fixture.events.mouse.clickOn( - fixture.editor.canvas.framesLayer.frames[0].node, - '10%', - '10%' + const element = await getSelectedElement(); + expect(element.content).toBe( + 'Fill in some text' ); + }); + + it('should allow adding solid and radial gradient color for a selection from the design menu', async () => { + await addText(); + await setSelection(0, 4); + await setSolidColor(); + + // Select character 6 and 7 (the part "in" in "Fill in some text") + await setSelection(5, 7); + await setRadialGradient(); + await closeColorPicker(); + await exitEditMode(); const element = await getSelectedElement(); expect(element.content).toBe( - 'Fill in some text' + 'Fill in some text' ); + }); - await fixture.snapshot('Mixed color value in the floating menu'); + it('should allow adding linear and radial gradient color for a selection from the design menu', async () => { + await addText(); + await setSelection(0, 4); + await setLinearGradient(); + + // Select character 6 and 7 (the part "in" in "Fill in some text") + await setSelection(5, 7); + await setRadialGradient(); + await closeColorPicker(); + await exitEditMode(); + + const element = await getSelectedElement(); + expect(element.content).toBe( + 'Fill in some text' + ); + }); + + it('should allow adding solid, linear and radial gradient color for a selection from the design menu', async () => { + await addText(); + await setSelection(0, 4); + await setLinearGradient(); + + // Select character 6 and 7 (the part "in" in "Fill in some text") + await setSelection(5, 7); + await setRadialGradient(); + + await setSelection(8, 12); + await setSolidColor(); + + await closeColorPicker(); + await exitEditMode(); + + const element = await getSelectedElement(); + expect(element.content).toBe( + 'Fill in some text' + ); }); }); @@ -179,16 +345,7 @@ describe('Design Menu: Text Styles', () => { }); it('should allow format a selection of a text from the design menu', async () => { - // Enter edit-mode - await fixture.events.keyboard.press('Enter'); - await fixture.screen.findByTestId('textEditor'); - - // Increase the font size for making sure setting selection works as expected. - await fixture.events.click(fixture.editor.canvas.designMenu.fontSize, { - clickCount: 3, - }); - await fixture.events.keyboard.type('30'); - await fixture.events.keyboard.press('tab'); + await addText(); // Select character 6 and 7 (the part "in" in "Fill in some text") await setSelection(5, 7); @@ -203,12 +360,7 @@ describe('Design Menu: Text Styles', () => { expect(fixture.editor.canvas.designMenu.italic.checked).toBeTrue(); expect(fixture.editor.canvas.designMenu.underline.checked).toBeTrue(); - // Click on background to exit edit mode. - await fixture.events.mouse.clickOn( - fixture.editor.canvas.framesLayer.frames[0].node, - '10%', - '10%' - ); + await exitEditMode(); const formattedText = await getSelectedElement(); expect(formattedText.content).toBe( From af4583fd256048f50d8f6c8d765cb77a8eee29c9 Mon Sep 17 00:00:00 2001 From: Swanand01 Date: Tue, 19 Mar 2024 01:53:18 +0530 Subject: [PATCH 24/29] Fix linting issues --- packages/element-library/src/text/util.ts | 5 +++-- packages/rich-text/src/formatters/index.ts | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/element-library/src/text/util.ts b/packages/element-library/src/text/util.ts index 0efbb78b99cf..9f2c8ab1cdd9 100644 --- a/packages/element-library/src/text/util.ts +++ b/packages/element-library/src/text/util.ts @@ -108,8 +108,9 @@ export const getHighlightLineheight = ( if (verticalPadding === 0) { return `${lineHeight}em`; } - return `calc(${lineHeight}em ${verticalPadding > 0 ? '+' : '-'} ${2 * Math.abs(verticalPadding) - }${unit})`; + return `calc(${lineHeight}em ${verticalPadding > 0 ? '+' : '-'} ${ + 2 * Math.abs(verticalPadding) + }${unit})`; }; export function calcFontMetrics(element: TextElement) { diff --git a/packages/rich-text/src/formatters/index.ts b/packages/rich-text/src/formatters/index.ts index 65debe4b95ef..3ec6992bbdb5 100644 --- a/packages/rich-text/src/formatters/index.ts +++ b/packages/rich-text/src/formatters/index.ts @@ -33,7 +33,7 @@ const formatters: Formatter[] = [ colorFormatter, letterSpacingFormatter, uppercaseFormatter, - gradientColorFormatter + gradientColorFormatter, ]; export default formatters; From 06e066094e422dc66dd99b62b43ec98aa95a426c Mon Sep 17 00:00:00 2001 From: Swanand01 Date: Tue, 19 Mar 2024 15:20:48 +0530 Subject: [PATCH 25/29] Move `DEFAULT_GRADIENT`, `GRADIENT` and `GRADIENT_REGEX` to `constants.ts` --- packages/patterns/src/constants.ts | 54 +++++++++++++++++++ .../patterns/src/getColorFromGradientStyle.ts | 40 ++------------ packages/patterns/src/index.ts | 6 +-- 3 files changed, 60 insertions(+), 40 deletions(-) create mode 100644 packages/patterns/src/constants.ts diff --git a/packages/patterns/src/constants.ts b/packages/patterns/src/constants.ts new file mode 100644 index 000000000000..6a531dd5b149 --- /dev/null +++ b/packages/patterns/src/constants.ts @@ -0,0 +1,54 @@ +/* + * Copyright 2021 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Internal dependencies + */ +import { PatternType, type Linear } from './types'; + +export const DEFAULT_GRADIENT: Linear = { + type: PatternType.Linear, + stops: [ + { + color: { + r: 0, + g: 0, + b: 0, + }, + position: 0, + }, + { + color: { + r: 1, + g: 1, + b: 1, + }, + position: 1, + }, + ], +}; + +export const GRADIENT = { + LINEAR: 'linear-gradient', + RADIAL: 'radial-gradient', +}; + +export const GRADIENT_REGEX = { + [GRADIENT.LINEAR]: + /linear-gradient\((?:-?\d*\.?\d+turn,\s*)?(?:rgba?\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),?\s*(\d*\.?\d+)?\)|#([0-9a-fA-F]{6}))\s*0%,\s*(?:rgba?\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),?\s*(\d*\.?\d+)?\)|#([0-9a-fA-F]{6}))\s*100%\)/, + [GRADIENT.RADIAL]: + /radial-gradient\((?:rgba?\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),?\s*(\d*\.?\d+)?\)|#([0-9a-fA-F]{6}))\s*0%,\s*(?:rgba?\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),?\s*(\d*\.?\d+)?\)|#([0-9a-fA-F]{6}))\s*100%\)/, +}; diff --git a/packages/patterns/src/getColorFromGradientStyle.ts b/packages/patterns/src/getColorFromGradientStyle.ts index a737072c8ebf..7229811e877c 100644 --- a/packages/patterns/src/getColorFromGradientStyle.ts +++ b/packages/patterns/src/getColorFromGradientStyle.ts @@ -13,45 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + /** * Internal dependencies */ +import { DEFAULT_GRADIENT, GRADIENT, GRADIENT_REGEX } from './constants'; import createSolidFromString from './createSolidFromString'; -import { PatternType, type Gradient, type Linear } from './types'; - -export const DEFAULT_GRADIENT: Linear = { - type: PatternType.Linear, - stops: [ - { - color: { - r: 0, - g: 0, - b: 0, - }, - position: 0, - }, - { - color: { - r: 1, - g: 1, - b: 1, - }, - position: 1, - }, - ], -}; - -const GRADIENT = { - LINEAR: 'linear-gradient', - RADIAL: 'radial-gradient', -}; - -const REGEX = { - [GRADIENT.LINEAR]: - /linear-gradient\((?:-?\d*\.?\d+turn,\s*)?(?:rgba?\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),?\s*(\d*\.?\d+)?\)|#([0-9a-fA-F]{6}))\s*0%,\s*(?:rgba?\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),?\s*(\d*\.?\d+)?\)|#([0-9a-fA-F]{6}))\s*100%\)/, - [GRADIENT.RADIAL]: - /radial-gradient\((?:rgba?\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),?\s*(\d*\.?\d+)?\)|#([0-9a-fA-F]{6}))\s*0%,\s*(?:rgba?\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),?\s*(\d*\.?\d+)?\)|#([0-9a-fA-F]{6}))\s*100%\)/, -}; +import { PatternType, type Gradient } from './types'; export default function getColorFromGradientStyle(style: string): Gradient { if (style.includes(GRADIENT.LINEAR)) { @@ -61,7 +29,7 @@ export default function getColorFromGradientStyle(style: string): Gradient { } function parseGradient(style: string, gradient: string): Gradient { - const regex = REGEX[gradient]; + const regex = GRADIENT_REGEX[gradient]; const matches = style.match(regex); if (!matches) { return DEFAULT_GRADIENT; diff --git a/packages/patterns/src/index.ts b/packages/patterns/src/index.ts index 209e9284ba39..e12a8a5ac123 100644 --- a/packages/patterns/src/index.ts +++ b/packages/patterns/src/index.ts @@ -15,6 +15,7 @@ */ export * from './types'; +export * from './constants'; export { default as convertToCSS } from './convertToCSS'; export { default as createSolid } from './createSolid'; @@ -31,7 +32,4 @@ export { default as hasOpacity } from './hasOpacity'; export { default as isPatternEqual } from './isPatternEqual'; export { default as isHexColorString } from './isHexColorString'; export { default as getGradientStyleFromColor } from './getGradientStyleFromColor'; -export { - default as getColorFromGradientStyle, - DEFAULT_GRADIENT, -} from './getColorFromGradientStyle'; +export { default as getColorFromGradientStyle } from './getColorFromGradientStyle'; From a949b4ad0aecff136705dc22a96f230336d315c6 Mon Sep 17 00:00:00 2001 From: Swanand01 Date: Tue, 19 Mar 2024 15:24:37 +0530 Subject: [PATCH 26/29] Fix order of styles in `stylesToCSS` --- packages/rich-text/src/formatters/gradientColor.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rich-text/src/formatters/gradientColor.ts b/packages/rich-text/src/formatters/gradientColor.ts index c48f4b43b670..b5719257c846 100644 --- a/packages/rich-text/src/formatters/gradientColor.ts +++ b/packages/rich-text/src/formatters/gradientColor.ts @@ -78,10 +78,10 @@ function stylesToCSS(styles: DraftInlineStyle): null | CSSProperties { const { backgroundImage } = generatePatternStyles(color); return { - backgroundImage, - backgroundClip: 'text', WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent', + backgroundImage, + backgroundClip: 'text', }; } From 8cb55a86f82b8d6585fa4bc6541731d8e916779e Mon Sep 17 00:00:00 2001 From: Swanand01 Date: Tue, 19 Mar 2024 16:25:06 +0530 Subject: [PATCH 27/29] Throw error if invalid style string is passed to `getColorFromGradientStyle` --- packages/patterns/src/getColorFromGradientStyle.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/patterns/src/getColorFromGradientStyle.ts b/packages/patterns/src/getColorFromGradientStyle.ts index 7229811e877c..3e8cf5801e12 100644 --- a/packages/patterns/src/getColorFromGradientStyle.ts +++ b/packages/patterns/src/getColorFromGradientStyle.ts @@ -24,8 +24,10 @@ import { PatternType, type Gradient } from './types'; export default function getColorFromGradientStyle(style: string): Gradient { if (style.includes(GRADIENT.LINEAR)) { return parseGradient(style, GRADIENT.LINEAR); + } else if (style.includes(GRADIENT.RADIAL)) { + return parseGradient(style, GRADIENT.RADIAL); } - return parseGradient(style, GRADIENT.RADIAL); + throw new Error('Invalid style string passed.'); } function parseGradient(style: string, gradient: string): Gradient { From 4610988417b6a0814f6f0a027c3d89d2e9e23e01 Mon Sep 17 00:00:00 2001 From: Swanand01 Date: Tue, 19 Mar 2024 16:26:02 +0530 Subject: [PATCH 28/29] Add unit tests for `getColorFromGradientStyle` --- .../src/test/getColorFromGradientStyle.ts | 383 ++++++++++++++++++ 1 file changed, 383 insertions(+) create mode 100644 packages/patterns/src/test/getColorFromGradientStyle.ts diff --git a/packages/patterns/src/test/getColorFromGradientStyle.ts b/packages/patterns/src/test/getColorFromGradientStyle.ts new file mode 100644 index 000000000000..46c32440c865 --- /dev/null +++ b/packages/patterns/src/test/getColorFromGradientStyle.ts @@ -0,0 +1,383 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Internal dependencies + */ +import getColorFromGradientStyle from '../getColorFromGradientStyle'; +import { PatternType } from '../types'; + +describe('getColorFromGradientStyle', () => { + describe('Linear Gradient', () => { + describe('with rotation', () => { + it('should return Linear gradient with two stops', () => { + expect( + getColorFromGradientStyle( + 'linear-gradient(0.25turn, #883030 0%, #1cb59b 100%)' + ) + ).toStrictEqual({ + type: PatternType.Linear, + rotation: 0.25, + stops: [ + { + color: { + r: 136, + g: 48, + b: 48, + }, + position: 0, + }, + { + color: { + r: 28, + g: 181, + b: 155, + }, + position: 1, + }, + ], + }); + }); + + it('should return Linear gradient with first stop with transparency', () => { + expect( + getColorFromGradientStyle( + 'linear-gradient(0.25turn, rgba(60,171,152,0.57) 0%, #c41d1d 100%)' + ) + ).toStrictEqual({ + type: PatternType.Linear, + rotation: 0.25, + stops: [ + { + color: { + r: 60, + g: 171, + b: 152, + a: 0.57, + }, + position: 0, + }, + { + color: { + r: 196, + g: 29, + b: 29, + }, + position: 1, + }, + ], + }); + }); + + it('should return Linear gradient with second stop with transparency', () => { + expect( + getColorFromGradientStyle( + 'linear-gradient(0.25turn, #a32929 0%, rgba(14,37,33,0.78) 100%)' + ) + ).toStrictEqual({ + type: PatternType.Linear, + rotation: 0.25, + stops: [ + { + color: { + r: 163, + g: 41, + b: 41, + }, + position: 0, + }, + { + color: { + r: 14, + g: 37, + b: 33, + a: 0.78, + }, + position: 1, + }, + ], + }); + }); + + it('should return Linear gradient with both stops with transparency', () => { + expect( + getColorFromGradientStyle( + 'linear-gradient(0.5turn, rgba(60,171,152,0.57) 0%, rgba(196,29,29,0.66) 100%)' + ) + ).toStrictEqual({ + type: PatternType.Linear, + rotation: 0.5, + stops: [ + { + color: { + r: 60, + g: 171, + b: 152, + a: 0.57, + }, + position: 0, + }, + { + color: { + r: 196, + g: 29, + b: 29, + a: 0.66, + }, + position: 1, + }, + ], + }); + }); + }); + + describe('without rotation', () => { + it('should return Linear gradient with two stops', () => { + expect( + getColorFromGradientStyle('linear-gradient(#883030 0%, #1cb59b 100%)') + ).toStrictEqual({ + type: PatternType.Linear, + rotation: 0, + stops: [ + { + color: { + r: 136, + g: 48, + b: 48, + }, + position: 0, + }, + { + color: { + r: 28, + g: 181, + b: 155, + }, + position: 1, + }, + ], + }); + }); + + it('should return Linear gradient with first stop with transparency', () => { + expect( + getColorFromGradientStyle( + 'linear-gradient(rgba(60,171,152,0.57) 0%, #c41d1d 100%)' + ) + ).toStrictEqual({ + type: PatternType.Linear, + rotation: 0, + stops: [ + { + color: { + r: 60, + g: 171, + b: 152, + a: 0.57, + }, + position: 0, + }, + { + color: { + r: 196, + g: 29, + b: 29, + }, + position: 1, + }, + ], + }); + }); + + it('should return Linear gradient with second stop with transparency', () => { + expect( + getColorFromGradientStyle( + 'linear-gradient(#a32929 0%, rgba(14,37,33,0.78) 100%)' + ) + ).toStrictEqual({ + type: PatternType.Linear, + rotation: 0, + stops: [ + { + color: { + r: 163, + g: 41, + b: 41, + }, + position: 0, + }, + { + color: { + r: 14, + g: 37, + b: 33, + a: 0.78, + }, + position: 1, + }, + ], + }); + }); + + it('should return Linear gradient with both stops with transparency', () => { + expect( + getColorFromGradientStyle( + 'linear-gradient(rgba(60,171,152,0.57) 0%, rgba(196,29,29,0.66) 100%)' + ) + ).toStrictEqual({ + type: PatternType.Linear, + rotation: 0, + stops: [ + { + color: { + r: 60, + g: 171, + b: 152, + a: 0.57, + }, + position: 0, + }, + { + color: { + r: 196, + g: 29, + b: 29, + a: 0.66, + }, + position: 1, + }, + ], + }); + }); + }); + }); + + describe('Radial Gradient', () => { + it('should return Radial gradient with two stops', () => { + expect( + getColorFromGradientStyle('radial-gradient(#a971a3 0%, #c1d3aa 100%)') + ).toStrictEqual({ + type: PatternType.Radial, + stops: [ + { + color: { + r: 169, + g: 113, + b: 163, + }, + position: 0, + }, + { + color: { + r: 193, + g: 211, + b: 170, + }, + position: 1, + }, + ], + }); + }); + + it('should return Radial gradient with first stop with transparency', () => { + expect( + getColorFromGradientStyle( + 'radial-gradient(rgba(178,75,100,0.56) 0%, #c1d3aa 100%)' + ) + ).toStrictEqual({ + type: PatternType.Radial, + stops: [ + { + color: { + r: 178, + g: 75, + b: 100, + a: 0.56, + }, + position: 0, + }, + { + color: { + r: 193, + g: 211, + b: 170, + }, + position: 1, + }, + ], + }); + }); + + it('should return Radial gradient with second stop with transparency', () => { + expect( + getColorFromGradientStyle( + 'radial-gradient(#c1d3aa 0%, rgba(178,75,100,0.56) 100%)' + ) + ).toStrictEqual({ + type: PatternType.Radial, + stops: [ + { + color: { + r: 193, + g: 211, + b: 170, + }, + position: 0, + }, + { + color: { + r: 178, + g: 75, + b: 100, + a: 0.56, + }, + position: 1, + }, + ], + }); + }); + + it('should return Radial gradient with both stops with transparency', () => { + expect( + getColorFromGradientStyle( + 'radial-gradient(rgba(60,171,152,0.25) 0%, rgba(196,29,29,0.3) 100%)' + ) + ).toStrictEqual({ + type: PatternType.Radial, + stops: [ + { + color: { + r: 60, + g: 171, + b: 152, + a: 0.25, + }, + position: 0, + }, + { + color: { + r: 196, + g: 29, + b: 29, + a: 0.3, + }, + position: 1, + }, + ], + }); + }); + }); +}); From 64710d2f0960b2bcd9036921412b127fa72874fe Mon Sep 17 00:00:00 2001 From: Swanand01 Date: Tue, 19 Mar 2024 16:42:39 +0530 Subject: [PATCH 29/29] Update the order of styles in unit tests and karma tests --- .../floatingMenu/elements/karma/text.karma.js | 16 ++++++++-------- .../panels/design/textStyle/test/textStyle.js | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/story-editor/src/components/floatingMenu/elements/karma/text.karma.js b/packages/story-editor/src/components/floatingMenu/elements/karma/text.karma.js index a730bc1cdf41..028c7a01e5b7 100644 --- a/packages/story-editor/src/components/floatingMenu/elements/karma/text.karma.js +++ b/packages/story-editor/src/components/floatingMenu/elements/karma/text.karma.js @@ -177,7 +177,7 @@ describe('Design Menu: Text Styles', () => { await setLinearGradient(); const element = await getSelectedElement(); expect(element.content).toBe( - 'Fill in some text' + 'Fill in some text' ); }); @@ -185,7 +185,7 @@ describe('Design Menu: Text Styles', () => { await setRadialGradient(); const element = await getSelectedElement(); expect(element.content).toBe( - 'Fill in some text' + 'Fill in some text' ); }); @@ -217,7 +217,7 @@ describe('Design Menu: Text Styles', () => { const element = await getSelectedElement(); expect(element.content).toBe( - 'Fill in some text' + 'Fill in some text' ); }); @@ -232,7 +232,7 @@ describe('Design Menu: Text Styles', () => { const element = await getSelectedElement(); expect(element.content).toBe( - 'Fill in some text' + 'Fill in some text' ); }); @@ -250,7 +250,7 @@ describe('Design Menu: Text Styles', () => { const element = await getSelectedElement(); expect(element.content).toBe( - 'Fill in some text' + 'Fill in some text' ); }); @@ -267,7 +267,7 @@ describe('Design Menu: Text Styles', () => { const element = await getSelectedElement(); expect(element.content).toBe( - 'Fill in some text' + 'Fill in some text' ); }); @@ -284,7 +284,7 @@ describe('Design Menu: Text Styles', () => { const element = await getSelectedElement(); expect(element.content).toBe( - 'Fill in some text' + 'Fill in some text' ); }); @@ -305,7 +305,7 @@ describe('Design Menu: Text Styles', () => { const element = await getSelectedElement(); expect(element.content).toBe( - 'Fill in some text' + 'Fill in some text' ); }); }); diff --git a/packages/story-editor/src/components/panels/design/textStyle/test/textStyle.js b/packages/story-editor/src/components/panels/design/textStyle/test/textStyle.js index e207ea83776c..4da5fadad3c2 100644 --- a/packages/story-editor/src/components/panels/design/textStyle/test/textStyle.js +++ b/packages/story-editor/src/components/panels/design/textStyle/test/textStyle.js @@ -478,7 +478,7 @@ describe('Panels/TextStyle', () => { expect(resultOfUpdating).toStrictEqual( { content: - 'Hello world', + 'Hello world', }, true );