From d823792f85d30c59778c49054d49a043b20b05f6 Mon Sep 17 00:00:00 2001 From: fundon Date: Wed, 12 Mar 2025 05:17:04 +0000 Subject: [PATCH] refactor(editor): simplify color picker (#10776) ### What's Changed! * Added `enableCustomColor` property into `EdgelessColorPickerButton` component * Removed redundant code --- .../element-toolbar/change-brush-button.ts | 69 ++---- .../change-connector-button.ts | 118 +++------- .../element-toolbar/change-frame-button.ts | 76 ++----- .../element-toolbar/change-note-button.ts | 81 ++----- .../element-toolbar/change-shape-button.ts | 208 +++++------------- .../element-toolbar/change-text-menu.ts | 85 ++----- .../components/src/color-picker/button.ts | 121 +++++----- .../src/color-picker/color-panel.ts | 3 - 8 files changed, 236 insertions(+), 525 deletions(-) diff --git a/blocksuite/affine/blocks/block-root/src/widgets/element-toolbar/change-brush-button.ts b/blocksuite/affine/blocks/block-root/src/widgets/element-toolbar/change-brush-button.ts index 7cb1cd4e3..9b628a831 100644 --- a/blocksuite/affine/blocks/block-root/src/widgets/element-toolbar/change-brush-button.ts +++ b/blocksuite/affine/blocks/block-root/src/widgets/element-toolbar/change-brush-button.ts @@ -3,10 +3,7 @@ import type { EdgelessColorPickerButton, PickColorEvent, } from '@blocksuite/affine-components/color-picker'; -import { - packColor, - packColorsWithColorScheme, -} from '@blocksuite/affine-components/color-picker'; +import { packColor } from '@blocksuite/affine-components/color-picker'; import type { BrushElementModel, BrushProps, @@ -18,11 +15,9 @@ import { resolveColor, } from '@blocksuite/affine-model'; import { FeatureFlagService } from '@blocksuite/affine-shared/services'; -import type { ColorEvent } from '@blocksuite/affine-shared/utils'; import { WithDisposable } from '@blocksuite/global/lit'; import { html, LitElement, nothing } from 'lit'; import { property, query } from 'lit/decorators.js'; -import { when } from 'lit/directives/when.js'; import countBy from 'lodash-es/countBy'; import maxBy from 'lodash-es/maxBy'; @@ -53,11 +48,6 @@ function notEqual(key: K, value: BrushProps[K]) { } export class EdgelessChangeBrushButton extends WithDisposable(LitElement) { - private readonly _setBrushColor = ({ detail }: ColorEvent) => { - const color = detail.value; - this._setBrushProp('color', color); - }; - private readonly _setLineWidth = ({ detail: lineWidth }: LineWidthEvent) => { this._setBrushProp('lineWidth', lineWidth); }; @@ -112,6 +102,9 @@ export class EdgelessChangeBrushButton extends WithDisposable(LitElement) { const elements = this.elements; const selectedColor = getMostCommonColor(elements, colorScheme); const selectedSize = getMostCommonSize(elements); + const enableCustomColor = this.edgeless.doc + .get(FeatureFlagService) + .getFlag('enable_color_picker'); return html` - ${when( - this.edgeless.doc - .get(FeatureFlagService) - .getFlag('enable_color_picker'), - () => { - const { type, colors } = packColorsWithColorScheme( - colorScheme, - selectedColor, - elements[0].color - ); - - return html` - - - `; - }, - () => html` - - - - `} - > - - - - ` - )} + + `; } diff --git a/blocksuite/affine/blocks/block-root/src/widgets/element-toolbar/change-connector-button.ts b/blocksuite/affine/blocks/block-root/src/widgets/element-toolbar/change-connector-button.ts index bf2a8f5b4..d2cba7ee1 100644 --- a/blocksuite/affine/blocks/block-root/src/widgets/element-toolbar/change-connector-button.ts +++ b/blocksuite/affine/blocks/block-root/src/widgets/element-toolbar/change-connector-button.ts @@ -3,10 +3,7 @@ import type { EdgelessColorPickerButton, PickColorEvent, } from '@blocksuite/affine-components/color-picker'; -import { - packColor, - packColorsWithColorScheme, -} from '@blocksuite/affine-components/color-picker'; +import { packColor } from '@blocksuite/affine-components/color-picker'; import { renderToolbarSeparator } from '@blocksuite/affine-components/toolbar'; import { type ColorScheme, @@ -24,7 +21,6 @@ import { StrokeStyle, } from '@blocksuite/affine-model'; import { FeatureFlagService } from '@blocksuite/affine-shared/services'; -import type { ColorEvent } from '@blocksuite/affine-shared/utils'; import { WithDisposable } from '@blocksuite/global/lit'; import { AddTextIcon, @@ -50,7 +46,6 @@ import { choose } from 'lit/directives/choose.js'; import { join } from 'lit/directives/join.js'; import { repeat } from 'lit/directives/repeat.js'; import { styleMap } from 'lit/directives/style-map.js'; -import { when } from 'lit/directives/when.js'; import countBy from 'lodash-es/countBy'; import maxBy from 'lodash-es/maxBy'; @@ -232,11 +227,6 @@ export class EdgelessChangeConnectorButton extends WithDisposable(LitElement) { return this.edgeless.std.get(EdgelessCRUDIdentifier); } - private readonly _setConnectorColor = (e: ColorEvent) => { - const stroke = e.detail.value; - this._setConnectorProp('stroke', stroke); - }; - private readonly _setConnectorStroke = ({ type, value }: LineStyleEvent) => { if (type === 'size') { this._setConnectorStrokeWidth(value); @@ -358,81 +348,45 @@ export class EdgelessChangeConnectorButton extends WithDisposable(LitElement) { ConnectorEndpoint.Rear, DEFAULT_REAR_END_POINT_STYLE ); + const enableCustomColor = this.edgeless.doc + .get(FeatureFlagService) + .getFlag('enable_color_picker'); return join( [ - when( - this.edgeless.doc - .get(FeatureFlagService) - .getFlag('enable_color_picker'), - () => { - const { type, colors } = packColorsWithColorScheme( - colorScheme, - selectedColor, - elements[0].stroke - ); - - return html` - -
- ${LineStylesPanel({ - selectedLineSize: selectedLineSize, - selectedLineStyle: selectedLineStyle, - onClick: this._setConnectorStroke, - })} -
- -
- `; - }, - () => html` - - - - `} + html` + +
- - - - ` - ), + ${LineStylesPanel({ + selectedLineSize: selectedLineSize, + selectedLineStyle: selectedLineStyle, + onClick: this._setConnectorStroke, + })} +
+ +
+ `, html` { - const background = e.detail.value; - this.frames.forEach(frame => { - this.crud.updateElement(frame.id, { background }); - }); - }; - pickColor = (e: PickColorEvent) => { const field = 'background'; @@ -128,6 +116,9 @@ export class EdgelessChangeFrameButton extends WithDisposable(LitElement) { const onlyOne = len === 1; const colorScheme = this.edgeless.surface.renderer.getColorScheme(); const background = getMostCommonColor(frames, colorScheme); + const enableCustomColor = this.edgeless.doc + .get(FeatureFlagService) + .getFlag('enable_color_picker'); return join( [ @@ -183,53 +174,18 @@ export class EdgelessChangeFrameButton extends WithDisposable(LitElement) { `, - when( - this.edgeless.doc - .get(FeatureFlagService) - .getFlag('enable_color_picker'), - () => { - const { type, colors } = packColorsWithColorScheme( - colorScheme, - background, - this.frames[0].background - ); - - return html` - - - `; - }, - () => html` - - - - `} - > - - - - ` - ), + html` + + + `, ].filter(button => button !== nothing), renderToolbarSeparator ); diff --git a/blocksuite/affine/blocks/block-root/src/widgets/element-toolbar/change-note-button.ts b/blocksuite/affine/blocks/block-root/src/widgets/element-toolbar/change-note-button.ts index 95a9449b3..b9fb0fd04 100644 --- a/blocksuite/affine/blocks/block-root/src/widgets/element-toolbar/change-note-button.ts +++ b/blocksuite/affine/blocks/block-root/src/widgets/element-toolbar/change-note-button.ts @@ -7,10 +7,7 @@ import type { EdgelessColorPickerButton, PickColorEvent, } from '@blocksuite/affine-components/color-picker'; -import { - packColor, - packColorsWithColorScheme, -} from '@blocksuite/affine-components/color-picker'; +import { packColor } from '@blocksuite/affine-components/color-picker'; import { type EditorMenuButton, renderToolbarSeparator, @@ -46,7 +43,6 @@ import { html, LitElement, nothing, type TemplateResult } from 'lit'; import { property, query } from 'lit/decorators.js'; import { join } from 'lit/directives/join.js'; import { createRef, type Ref, ref } from 'lit/directives/ref.js'; -import { when } from 'lit/directives/when.js'; import countBy from 'lodash-es/countBy'; import maxBy from 'lodash-es/maxBy'; @@ -90,12 +86,6 @@ export class EdgelessChangeNoteButton extends WithDisposable(LitElement) { return this.edgeless.std.get(EdgelessCRUDIdentifier); } - private readonly _setBackground = (background: string) => { - this.notes.forEach(element => { - this.crud.updateElement(element.id, { background }); - }); - }; - private readonly _setBorderRadius = (borderRadius: number) => { this.notes.forEach(note => { const props = { @@ -348,6 +338,10 @@ export class EdgelessChangeNoteButton extends WithDisposable(LitElement) { NoteConfigExtension.identifier )?.edgelessNoteHeader; + const enableCustomColor = this.edgeless.doc + .get(FeatureFlagService) + .getFlag('enable_color_picker'); + const theme = this.edgeless.std.get(ThemeProvider).theme; const buttonIconSize = { width: '20px', height: '20px' }; const buttons = [ @@ -403,57 +397,20 @@ export class EdgelessChangeNoteButton extends WithDisposable(LitElement) { isDocOnly ? nothing - : when( - this.edgeless.doc - .get(FeatureFlagService) - .getFlag('enable_color_picker'), - () => { - const { type, colors } = packColorsWithColorScheme( - colorScheme, - background, - note.background - ); - - return html` - - - `; - }, - () => html` - - - - `} - > - - - - ` - ), + : html` + + + `, isDocOnly ? nothing diff --git a/blocksuite/affine/blocks/block-root/src/widgets/element-toolbar/change-shape-button.ts b/blocksuite/affine/blocks/block-root/src/widgets/element-toolbar/change-shape-button.ts index 92b0cdab8..40da84f0c 100644 --- a/blocksuite/affine/blocks/block-root/src/widgets/element-toolbar/change-shape-button.ts +++ b/blocksuite/affine/blocks/block-root/src/widgets/element-toolbar/change-shape-button.ts @@ -3,10 +3,7 @@ import type { EdgelessColorPickerButton, PickColorEvent, } from '@blocksuite/affine-components/color-picker'; -import { - packColor, - packColorsWithColorScheme, -} from '@blocksuite/affine-components/color-picker'; +import { packColor } from '@blocksuite/affine-components/color-picker'; import { renderToolbarSeparator } from '@blocksuite/affine-components/toolbar'; import type { Color, @@ -28,7 +25,6 @@ import { StrokeStyle, } from '@blocksuite/affine-model'; import { FeatureFlagService } from '@blocksuite/affine-shared/services'; -import type { ColorEvent } from '@blocksuite/affine-shared/utils'; import { WithDisposable } from '@blocksuite/global/lit'; import { AddTextIcon, @@ -42,7 +38,6 @@ import { cache } from 'lit/directives/cache.js'; import { choose } from 'lit/directives/choose.js'; import { join } from 'lit/directives/join.js'; import { styleMap } from 'lit/directives/style-map.js'; -import { when } from 'lit/directives/when.js'; import countBy from 'lodash-es/countBy'; import isEqual from 'lodash-es/isEqual'; import maxBy from 'lodash-es/maxBy'; @@ -143,22 +138,6 @@ function getMostCommonShapeStyle(elements: ShapeElementModel[]): ShapeStyle { export class EdgelessChangeShapeButton extends WithDisposable(LitElement) { static override styles = [changeShapeButtonStyles]; - private readonly _setShapeFillColor = (e: ColorEvent) => { - const fillColor = e.detail.value; - const filled = !isTransparent(fillColor); - const color = this._getTextColor(fillColor, filled); - this.elements.forEach(ele => - this.crud.updateElement(ele.id, { filled, fillColor, color }) - ); - }; - - private readonly _setShapeStrokeColor = (e: ColorEvent) => { - const strokeColor = e.detail.value; - this.elements.forEach(ele => - this.crud.updateElement(ele.id, { strokeColor }) - ); - }; - private readonly _setShapeStyles = ({ type, value }: LineStyleEvent) => { if (type === 'size') { this._setShapeStrokeWidth(value); @@ -191,10 +170,15 @@ export class EdgelessChangeShapeButton extends WithDisposable(LitElement) { return DefaultTheme.white; } else if (isEqual(fillColor, DefaultTheme.white)) { return DefaultTheme.black; + } else if (isEqual(fillColor, DefaultTheme.pureBlack)) { + return DefaultTheme.pureWhite; + } else if (isEqual(fillColor, DefaultTheme.pureWhite)) { + return DefaultTheme.pureBlack; } } - return DefaultTheme.black; + // aka `DefaultTheme.pureBlack` + return DefaultTheme.shapeTextColor; } private _setShapeStrokeStyle(strokeStyle: StrokeStyle) { @@ -249,12 +233,14 @@ export class EdgelessChangeShapeButton extends WithDisposable(LitElement) { ) { return (e: PickColorEvent) => { if (e.type === 'pick') { - const color = e.detail.value; + const value = e.detail.value; + const filled = field === 'fillColor' && !isTransparent(value); this.elements.forEach(ele => { - const props = packColor(field, color); + const props = packColor(field, value); // If `filled` can be set separately, this logic can be removed - if (field === 'fillColor' && !ele.filled) { - Object.assign(props, { filled: true }); + if (field && !ele.filled) { + const color = this._getTextColor(value, filled); + Object.assign(props, { filled, color }); } this.crud.updateElement(ele.id, props); }); @@ -277,6 +263,9 @@ export class EdgelessChangeShapeButton extends WithDisposable(LitElement) { const selectedLineStyle = getMostCommonLineStyle(elements); const selectedShapeStyle = getMostCommonShapeStyle(elements); const iconSize = { width: '20px', height: '20px' }; + const enableCustomColor = this.edgeless.doc + .get(FeatureFlagService) + .getFlag('enable_color_picker'); return join( [ @@ -320,129 +309,52 @@ export class EdgelessChangeShapeButton extends WithDisposable(LitElement) { `, - when( - this.edgeless.doc - .get(FeatureFlagService) - .getFlag('enable_color_picker'), - () => { - const { type, colors } = packColorsWithColorScheme( - colorScheme, - selectedFillColor, - elements[0].fillColor - ); + html` + + + `, - return html` - - - `; - }, - () => html` - - - - `} + html` + +
- - - - ` - ), - - when( - this.edgeless.doc - .get(FeatureFlagService) - .getFlag('enable_color_picker'), - () => { - const { type, colors } = packColorsWithColorScheme( - colorScheme, - selectedStrokeColor, - elements[0].strokeColor - ); - - return html` - -
- ${LineStylesPanel({ - selectedLineSize: selectedLineSize, - selectedLineStyle: selectedLineStyle, - onClick: this._setShapeStyles, - })} -
- -
- `; - }, - () => html` - - - - `} - > - - - - ` - ), + ${LineStylesPanel({ + selectedLineSize: selectedLineSize, + selectedLineStyle: selectedLineStyle, + onClick: this._setShapeStyles, + })} +
+ +
+ `, choose | typeof nothing>( this._showAddButtonOrTextMenu(), diff --git a/blocksuite/affine/blocks/block-root/src/widgets/element-toolbar/change-text-menu.ts b/blocksuite/affine/blocks/block-root/src/widgets/element-toolbar/change-text-menu.ts index 7f40f041c..95d025265 100644 --- a/blocksuite/affine/blocks/block-root/src/widgets/element-toolbar/change-text-menu.ts +++ b/blocksuite/affine/blocks/block-root/src/widgets/element-toolbar/change-text-menu.ts @@ -8,10 +8,7 @@ import type { EdgelessColorPickerButton, PickColorEvent, } from '@blocksuite/affine-components/color-picker'; -import { - packColor, - packColorsWithColorScheme, -} from '@blocksuite/affine-components/color-picker'; +import { packColor } from '@blocksuite/affine-components/color-picker'; import { renderToolbarSeparator } from '@blocksuite/affine-components/toolbar'; import { type ColorScheme, @@ -30,7 +27,6 @@ import { type TextStyleProps, } from '@blocksuite/affine-model'; import { FeatureFlagService } from '@blocksuite/affine-shared/services'; -import type { ColorEvent } from '@blocksuite/affine-shared/utils'; import { Bound } from '@blocksuite/global/gfx'; import { WithDisposable } from '@blocksuite/global/lit'; import { @@ -42,7 +38,6 @@ import { css, html, LitElement, nothing, type TemplateResult } from 'lit'; import { property, query } from 'lit/decorators.js'; import { choose } from 'lit/directives/choose.js'; import { join } from 'lit/directives/join.js'; -import { when } from 'lit/directives/when.js'; import countBy from 'lodash-es/countBy'; import maxBy from 'lodash-es/maxBy'; @@ -229,14 +224,6 @@ export class EdgelessChangeTextMenu extends WithDisposable(LitElement) { }); }; - private readonly _setTextColor = (e: ColorEvent) => { - const color = e.detail.value; - const props = { color }; - this.elements.forEach(element => { - this.crud.updateElement(element.id, buildProps(element, props)); - }); - }; - private readonly _updateElementBound = (element: SurfaceTextModel) => { const elementType = this.elementType; if (elementType === 'text' && element instanceof TextElementModel) { @@ -346,6 +333,9 @@ export class EdgelessChangeTextMenu extends WithDisposable(LitElement) { this.elementType === 'shape' ? DefaultTheme.ShapeTextColorPalettes : DefaultTheme.Palettes; + const enableCustomColor = this.edgeless.doc + .get(FeatureFlagService) + .getFlag('enable_color_picker'); return join( [ @@ -375,57 +365,22 @@ export class EdgelessChangeTextMenu extends WithDisposable(LitElement) {
`, - when( - this.edgeless.doc - .get(FeatureFlagService) - .getFlag('enable_color_picker'), - () => { - const { type, colors } = packColorsWithColorScheme( - colorScheme, - selectedColor, - elements[0] instanceof ConnectorElementModel - ? elements[0].labelStyle.color - : elements[0].color - ); - - return html` - - - `; - }, - () => html` - - - - `} - > - - - ` - ), + html` + + + `, html` { + e.stopPropagation(); this.#pick(e.detail); }; switchToCustomTab = (e: MouseEvent) => { e.stopPropagation(); - if (this.colorType === 'palette') { - this.colorType = 'normal'; - } + this.tabType = 'custom'; // refresh menu's position this.menuButton.show(true); @@ -82,12 +87,16 @@ export class EdgelessColorPickerButton extends WithDisposable(LitElement) { } override firstUpdated() { - this.disposables.addFromEvent(this.menuButton, 'toggle', (e: Event) => { - const opened = (e as CustomEvent).detail; - if (!opened && this.tabType !== 'normal') { - this.tabType = 'normal'; + this.disposables.addFromEvent( + this.menuButton, + 'toggle', + (e: CustomEvent) => { + const opened = e.detail; + if (!opened && this.tabType !== 'normal') { + this.tabType = 'normal'; + } } - }); + ); } override render() { @@ -99,18 +108,20 @@ export class EdgelessColorPickerButton extends WithDisposable(LitElement) { aria-label=${this.label} .tooltip=${this.tooltip || this.label} > - ${this.isText - ? html` - - ` - : html` - - `} + ${when( + this.isText, + () => html` + + `, + () => html` + + ` + )} `} > @@ -128,53 +139,60 @@ export class EdgelessColorPickerButton extends WithDisposable(LitElement) { .theme=${this.theme} .palettes=${this.palettes} .hollowCircle=${this.hollowCircle} - .openColorPicker=${this.switchToCustomTab} .hasTransparent=${false} @select=${this.#select} > - + ${when( + this.enableCustomColor, + () => html` + + ` + )} `, ], [ 'custom', - () => html` - - `, + () => { + const packed = packColorsWithColorScheme( + this.theme, + this.color, + this.originalColor + ); + const type = packed.type === 'palette' ? 'normal' : packed.type; + const modes = packed.colors.map( + preprocessColor(window.getComputedStyle(this)) + ); + + return html` + + `; + }, ], ])} `; } + @property() + accessor originalColor!: Color; + @property() accessor color!: string; @property() accessor colorPanelClass: string | undefined = undefined; - @property({ attribute: false }) - accessor colors: { type: ModeType; value: string }[] = []; - - @property() - accessor colorType: PickColorType = 'palette'; - @property({ attribute: false }) accessor hollowCircle: boolean = false; @@ -201,4 +219,7 @@ export class EdgelessColorPickerButton extends WithDisposable(LitElement) { @property() accessor tooltip: string | undefined = undefined; + + @property() + accessor enableCustomColor: boolean = true; } diff --git a/blocksuite/affine/components/src/color-picker/color-panel.ts b/blocksuite/affine/components/src/color-picker/color-panel.ts index b0eab1d77..bd9eeeaae 100644 --- a/blocksuite/affine/components/src/color-picker/color-panel.ts +++ b/blocksuite/affine/components/src/color-picker/color-panel.ts @@ -253,9 +253,6 @@ export class EdgelessColorPanel extends LitElement { @property({ attribute: false }) accessor hollowCircle = false; - @property() - accessor openColorPicker!: (e: MouseEvent) => void; - @property({ type: Array }) accessor palettes: readonly Palette[] = DefaultTheme.Palettes;