fix(editor): adjust black and white in shape text color palettes to pure black and pure white (#10450)

Closes: [BS-2697](https://linear.app/affine-design/issue/BS-2697/检查shape-text-color黑白不映射的pr合并状态)

https://github.com/user-attachments/assets/732612e9-5e43-453f-aef2-5f32f5a08614
This commit is contained in:
fundon
2025-02-27 06:05:42 +00:00
parent 18dfad28d7
commit caa4dfedfc
26 changed files with 277 additions and 107 deletions
@@ -1,5 +1,9 @@
import type { Color, ColorScheme, Palette } from '@blocksuite/affine-model'; import type { Color, ColorScheme, Palette } from '@blocksuite/affine-model';
import { isTransparent, resolveColor } from '@blocksuite/affine-model'; import {
DefaultTheme,
isTransparent,
resolveColor,
} from '@blocksuite/affine-model';
import { unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme'; import { unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme';
import { ColorEvent } from '@blocksuite/affine-shared/utils'; import { ColorEvent } from '@blocksuite/affine-shared/utils';
import { css, html, LitElement, nothing, svg, type TemplateResult } from 'lit'; import { css, html, LitElement, nothing, svg, type TemplateResult } from 'lit';
@@ -253,7 +257,7 @@ export class EdgelessColorPanel extends LitElement {
accessor openColorPicker!: (e: MouseEvent) => void; accessor openColorPicker!: (e: MouseEvent) => void;
@property({ type: Array }) @property({ type: Array })
accessor palettes: readonly Palette[] = []; accessor palettes: readonly Palette[] = DefaultTheme.Palettes;
@property({ attribute: false }) @property({ attribute: false })
accessor theme!: ColorScheme; accessor theme!: ColorScheme;
@@ -1,8 +1,4 @@
import { import { type ColorScheme, type StrokeStyle } from '@blocksuite/affine-model';
type ColorScheme,
DefaultTheme,
type StrokeStyle,
} from '@blocksuite/affine-model';
import type { ColorEvent } from '@blocksuite/affine-shared/utils'; import type { ColorEvent } from '@blocksuite/affine-shared/utils';
import { WithDisposable } from '@blocksuite/global/utils'; import { WithDisposable } from '@blocksuite/global/utils';
import { css, html, LitElement } from 'lit'; import { css, html, LitElement } from 'lit';
@@ -44,7 +40,6 @@ export class StrokeStylePanel extends WithDisposable(LitElement) {
aria-label="Border colors" aria-label="Border colors"
.value=${this.strokeColor} .value=${this.strokeColor}
.theme=${this.theme} .theme=${this.theme}
.palettes=${DefaultTheme.Palettes}
.hollowCircle=${this.hollowCircle} .hollowCircle=${this.hollowCircle}
@select=${(e: ColorEvent) => this.setStrokeColor(e)} @select=${(e: ColorEvent) => this.setStrokeColor(e)}
> >
@@ -65,7 +65,7 @@ export class EdgelessBrushMenu extends EdgelessToolbarToolMixin(
class="one-way" class="one-way"
.value=${this._props$.value.color} .value=${this._props$.value.color}
.theme=${this._theme$.value} .theme=${this._theme$.value}
.palettes=${DefaultTheme.StrokeColorPalettes} .palettes=${DefaultTheme.StrokeColorShortPalettes}
.hasTransparent=${!this.edgeless.doc .hasTransparent=${!this.edgeless.doc
.get(FeatureFlagService) .get(FeatureFlagService)
.getFlag('enable_color_picker')} .getFlag('enable_color_picker')}
@@ -133,7 +133,7 @@ export class EdgelessConnectorMenu extends EdgelessToolbarToolMixin(
class="one-way" class="one-way"
.value=${stroke} .value=${stroke}
.theme=${this._theme$.value} .theme=${this._theme$.value}
.palettes=${DefaultTheme.StrokeColorPalettes} .palettes=${DefaultTheme.StrokeColorShortPalettes}
.hasTransparent=${!this.edgeless.doc .hasTransparent=${!this.edgeless.doc
.get(FeatureFlagService) .get(FeatureFlagService)
.getFlag('enable_color_picker')} .getFlag('enable_color_picker')}
@@ -75,9 +75,10 @@ export class EdgelessShapeMenu extends SignalWatcher(
const filled = !isTransparent(value); const filled = !isTransparent(value);
const fillColor = value; const fillColor = value;
const strokeColor = filled const strokeColor = filled
? DefaultTheme.StrokeColorPalettes.find(palette => palette.key === key) ? DefaultTheme.StrokeColorShortPalettes.find(
?.value palette => palette.key === key
: DefaultTheme.StrokeColorMap.Grey; )?.value
: DefaultTheme.StrokeColorShortMap.Grey;
const { shapeName } = this._props$.value; const { shapeName } = this._props$.value;
this.edgeless.std this.edgeless.std
@@ -173,7 +174,7 @@ export class EdgelessShapeMenu extends SignalWatcher(
class="one-way" class="one-way"
.value=${fillColor} .value=${fillColor}
.theme=${this._theme$.value} .theme=${this._theme$.value}
.palettes=${DefaultTheme.FillColorPalettes} .palettes=${DefaultTheme.FillColorShortPalettes}
.hasTransparent=${!this.edgeless.doc .hasTransparent=${!this.edgeless.doc
.get(FeatureFlagService) .get(FeatureFlagService)
.getFlag('enable_color_picker')} .getFlag('enable_color_picker')}
@@ -33,7 +33,7 @@ export class EdgelessTextMenu extends EdgelessToolbarToolMixin(LitElement) {
class="one-way" class="one-way"
.value=${this.color} .value=${this.color}
.theme=${this._theme$.value} .theme=${this._theme$.value}
.palettes=${DefaultTheme.StrokeColorPalettes} .palettes=${DefaultTheme.StrokeColorShortPalettes}
@select=${(e: ColorEvent) => this.onChange({ color: e.detail })} @select=${(e: ColorEvent) => this.onChange({ color: e.detail })}
></edgeless-color-panel> ></edgeless-color-panel>
</div> </div>
@@ -134,13 +134,12 @@ export class EdgelessChangeBrushButton extends WithDisposable(LitElement) {
return html` return html`
<edgeless-color-picker-button <edgeless-color-picker-button
class="color" class="color"
.label=${'Color'} .label="${'Color'}"
.pick=${this.pickColor} .pick=${this.pickColor}
.color=${selectedColor} .color=${selectedColor}
.colors=${colors} .colors=${colors}
.colorType=${type} .colorType=${type}
.theme=${colorScheme} .theme=${colorScheme}
.palettes=${DefaultTheme.Palettes}
> >
</edgeless-color-picker-button> </edgeless-color-picker-button>
`; `;
@@ -159,7 +158,6 @@ export class EdgelessChangeBrushButton extends WithDisposable(LitElement) {
<edgeless-color-panel <edgeless-color-panel
.value=${selectedColor} .value=${selectedColor}
.theme=${colorScheme} .theme=${colorScheme}
.palettes=${DefaultTheme.Palettes}
@select=${this._setBrushColor} @select=${this._setBrushColor}
> >
</edgeless-color-panel> </edgeless-color-panel>
@@ -373,13 +373,12 @@ export class EdgelessChangeConnectorButton extends WithDisposable(LitElement) {
return html` return html`
<edgeless-color-picker-button <edgeless-color-picker-button
class="stroke-color" class="stroke-color"
.label=${'Stroke style'} .label="${'Stroke style'}"
.pick=${this.pickColor} .pick=${this.pickColor}
.color=${selectedColor} .color=${selectedColor}
.colors=${colors} .colors=${colors}
.colorType=${type} .colorType=${type}
.theme=${colorScheme} .theme=${colorScheme}
.palettes=${DefaultTheme.Palettes}
.hollowCircle=${true} .hollowCircle=${true}
> >
<div <div
@@ -13,7 +13,6 @@ import { renderToolbarSeparator } from '@blocksuite/affine-components/toolbar';
import { import {
type ColorScheme, type ColorScheme,
DEFAULT_NOTE_HEIGHT, DEFAULT_NOTE_HEIGHT,
DefaultTheme,
type FrameBlockModel, type FrameBlockModel,
NoteBlockModel, NoteBlockModel,
NoteDisplayMode, NoteDisplayMode,
@@ -201,13 +200,12 @@ export class EdgelessChangeFrameButton extends WithDisposable(LitElement) {
return html` return html`
<edgeless-color-picker-button <edgeless-color-picker-button
class="background" class="background"
.label=${'Background'} .label="${'Background'}"
.pick=${this.pickColor} .pick=${this.pickColor}
.color=${background} .color=${background}
.colors=${colors} .colors=${colors}
.colorType=${type} .colorType=${type}
.theme=${colorScheme} .theme=${colorScheme}
.palettes=${DefaultTheme.Palettes}
> >
</edgeless-color-picker-button> </edgeless-color-picker-button>
`; `;
@@ -229,7 +227,6 @@ export class EdgelessChangeFrameButton extends WithDisposable(LitElement) {
<edgeless-color-panel <edgeless-color-panel
.value=${background} .value=${background}
.theme=${colorScheme} .theme=${colorScheme}
.palettes=${DefaultTheme.Palettes}
@select=${this._setFrameBackground} @select=${this._setFrameBackground}
> >
</edgeless-color-panel> </edgeless-color-panel>
@@ -338,7 +338,6 @@ export class EdgelessChangeShapeButton extends WithDisposable(LitElement) {
.colors=${colors} .colors=${colors}
.colorType=${type} .colorType=${type}
.theme=${colorScheme} .theme=${colorScheme}
.palettes=${DefaultTheme.Palettes}
> >
</edgeless-color-picker-button> </edgeless-color-picker-button>
`; `;
@@ -362,7 +361,6 @@ export class EdgelessChangeShapeButton extends WithDisposable(LitElement) {
aria-label="Fill colors" aria-label="Fill colors"
.value=${selectedFillColor} .value=${selectedFillColor}
.theme=${colorScheme} .theme=${colorScheme}
.palettes=${DefaultTheme.Palettes}
@select=${this._setShapeFillColor} @select=${this._setShapeFillColor}
> >
</edgeless-color-panel> </edgeless-color-panel>
@@ -390,7 +388,6 @@ export class EdgelessChangeShapeButton extends WithDisposable(LitElement) {
.colors=${colors} .colors=${colors}
.colorType=${type} .colorType=${type}
.theme=${colorScheme} .theme=${colorScheme}
.palettes=${DefaultTheme.Palettes}
.hollowCircle=${true} .hollowCircle=${true}
> >
<div <div
@@ -453,8 +450,8 @@ export class EdgelessChangeShapeButton extends WithDisposable(LitElement) {
() => html` () => html`
<editor-icon-button <editor-icon-button
aria-label="Add text" aria-label="Add text"
.tooltip=${'Add text'} .tooltip="${'Add text'}"
.iconSize=${'20px'} .iconSize="${'20px'}"
@click=${this._addText} @click=${this._addText}
> >
${AddTextIcon()} ${AddTextIcon()}
@@ -465,7 +462,7 @@ export class EdgelessChangeShapeButton extends WithDisposable(LitElement) {
'menu', 'menu',
() => html` () => html`
<edgeless-change-text-menu <edgeless-change-text-menu
.elementType=${'shape'} .elementType="${'shape'}"
.elements=${elements} .elements=${elements}
.edgeless=${this.edgeless} .edgeless=${this.edgeless}
></edgeless-change-text-menu> ></edgeless-change-text-menu>
@@ -344,6 +344,10 @@ export class EdgelessChangeTextMenu extends WithDisposable(LitElement) {
matchFontFaces.length === 1 && matchFontFaces.length === 1 &&
matchFontFaces[0].style === selectedFontStyle && matchFontFaces[0].style === selectedFontStyle &&
matchFontFaces[0].weight === selectedFontWeight; matchFontFaces[0].weight === selectedFontWeight;
const palettes =
this.elementType === 'shape'
? DefaultTheme.ShapeTextColorPalettes
: DefaultTheme.Palettes;
return join( return join(
[ [
@@ -389,14 +393,14 @@ export class EdgelessChangeTextMenu extends WithDisposable(LitElement) {
return html` return html`
<edgeless-color-picker-button <edgeless-color-picker-button
class="text-color" class="text-color"
.label=${'Text color'} .label="${'Text color'}"
.pick=${this.pickColor} .pick=${this.pickColor}
.isText=${true} .isText=${true}
.color=${selectedColor} .color=${selectedColor}
.colors=${colors} .colors=${colors}
.colorType=${type} .colorType=${type}
.theme=${colorScheme} .theme=${colorScheme}
.palettes=${DefaultTheme.Palettes} .palettes=${palettes}
> >
</edgeless-color-picker-button> </edgeless-color-picker-button>
`; `;
@@ -418,7 +422,7 @@ export class EdgelessChangeTextMenu extends WithDisposable(LitElement) {
<edgeless-color-panel <edgeless-color-panel
.value=${selectedColor} .value=${selectedColor}
.theme=${colorScheme} .theme=${colorScheme}
.palettes=${DefaultTheme.Palettes} .palettes=${palettes}
@select=${this._setTextColor} @select=${this._setTextColor}
></edgeless-color-panel> ></edgeless-color-panel>
</editor-menu-button> </editor-menu-button>
@@ -1,5 +1,5 @@
import type { ColorScheme, Palette } from '@blocksuite/affine-model'; import type { ColorScheme, Palette } from '@blocksuite/affine-model';
import { resolveColor } from '@blocksuite/affine-model'; import { DefaultTheme, resolveColor } from '@blocksuite/affine-model';
import type { ColorEvent } from '@blocksuite/affine-shared/utils'; import type { ColorEvent } from '@blocksuite/affine-shared/utils';
import { WithDisposable } from '@blocksuite/global/utils'; import { WithDisposable } from '@blocksuite/global/utils';
import { html, LitElement } from 'lit'; import { html, LitElement } from 'lit';
@@ -188,7 +188,7 @@ export class EdgelessColorPickerButton extends WithDisposable(LitElement) {
accessor menuButton!: EditorMenuButton; accessor menuButton!: EditorMenuButton;
@property({ attribute: false }) @property({ attribute: false })
accessor palettes: Palette[] = []; accessor palettes: Palette[] = DefaultTheme.Palettes;
@property({ attribute: false }) @property({ attribute: false })
accessor pick!: (event: PickColorEvent) => void; accessor pick!: (event: PickColorEvent) => void;
+2 -2
View File
@@ -23,7 +23,7 @@ export const LINE_WIDTHS = [
]; ];
/** /**
* Use `DefaultTheme.StrokeColorMap` instead. * Use `DefaultTheme.StrokeColorShortMap` instead.
* *
* @deprecated * @deprecated
*/ */
@@ -44,7 +44,7 @@ export enum LineColor {
export const LineColorMap = createEnumMap(LineColor); export const LineColorMap = createEnumMap(LineColor);
/** /**
* Use `DefaultTheme.StrokeColorPalettes` instead. * Use `DefaultTheme.StrokeColorShortPalettes` instead.
* *
* @deprecated * @deprecated
*/ */
@@ -77,11 +77,11 @@ export abstract class MindmapStyleGetter {
export class StyleOne extends MindmapStyleGetter { export class StyleOne extends MindmapStyleGetter {
private readonly _colorOrders = [ private readonly _colorOrders = [
DefaultTheme.StrokeColorMap.Purple, DefaultTheme.StrokeColorShortMap.Purple,
DefaultTheme.StrokeColorMap.Magenta, DefaultTheme.StrokeColorShortMap.Magenta,
DefaultTheme.StrokeColorMap.Orange, DefaultTheme.StrokeColorShortMap.Orange,
DefaultTheme.StrokeColorMap.Yellow, DefaultTheme.StrokeColorShortMap.Yellow,
DefaultTheme.StrokeColorMap.Green, DefaultTheme.StrokeColorShortMap.Green,
'#7ae2d5', '#7ae2d5',
]; ];
@@ -188,9 +188,9 @@ export const styleOne = new StyleOne();
export class StyleTwo extends MindmapStyleGetter { export class StyleTwo extends MindmapStyleGetter {
private readonly _colorOrders = [ private readonly _colorOrders = [
DefaultTheme.StrokeColorMap.Blue, DefaultTheme.StrokeColorShortMap.Blue,
'#7ae2d5', '#7ae2d5',
DefaultTheme.StrokeColorMap.Yellow, DefaultTheme.StrokeColorShortMap.Yellow,
]; ];
readonly root = { readonly root = {
@@ -207,7 +207,7 @@ export class StyleTwo extends MindmapStyleGetter {
color: DefaultTheme.pureBlack, color: DefaultTheme.pureBlack,
filled: true, filled: true,
fillColor: DefaultTheme.StrokeColorMap.Yellow, fillColor: DefaultTheme.StrokeColorShortMap.Yellow,
padding: [11, 22] as [number, number], padding: [11, 22] as [number, number],
@@ -298,8 +298,8 @@ export const styleTwo = new StyleTwo();
export class StyleThree extends MindmapStyleGetter { export class StyleThree extends MindmapStyleGetter {
private readonly _strokeColor = [ private readonly _strokeColor = [
DefaultTheme.StrokeColorMap.Yellow, DefaultTheme.StrokeColorShortMap.Yellow,
DefaultTheme.StrokeColorMap.Green, DefaultTheme.StrokeColorShortMap.Green,
'#5cc7ba', '#5cc7ba',
]; ];
@@ -317,7 +317,7 @@ export class StyleThree extends MindmapStyleGetter {
color: DefaultTheme.pureBlack, color: DefaultTheme.pureBlack,
filled: true, filled: true,
fillColor: DefaultTheme.StrokeColorMap.Yellow, fillColor: DefaultTheme.StrokeColorShortMap.Yellow,
padding: [10, 22] as [number, number], padding: [10, 22] as [number, number],
@@ -407,12 +407,12 @@ export const styleThree = new StyleThree();
export class StyleFour extends MindmapStyleGetter { export class StyleFour extends MindmapStyleGetter {
private readonly _colors = [ private readonly _colors = [
DefaultTheme.StrokeColorMap.Purple, DefaultTheme.StrokeColorShortMap.Purple,
DefaultTheme.StrokeColorMap.Magenta, DefaultTheme.StrokeColorShortMap.Magenta,
DefaultTheme.StrokeColorMap.Orange, DefaultTheme.StrokeColorShortMap.Orange,
DefaultTheme.StrokeColorMap.Yellow, DefaultTheme.StrokeColorShortMap.Yellow,
DefaultTheme.StrokeColorMap.Green, DefaultTheme.StrokeColorShortMap.Green,
DefaultTheme.StrokeColorMap.Blue, DefaultTheme.StrokeColorShortMap.Blue,
]; ];
readonly root = { readonly root = {
+42 -12
View File
@@ -72,15 +72,44 @@ const NoteBackgroundColorPalettes: Palette[] = [
...buildPalettes(NoteBackgroundColorMap), ...buildPalettes(NoteBackgroundColorMap),
] as const; ] as const;
const StrokeColorMap = { ...Medium, Black, White } as const; const StrokeColorShortMap = { ...Medium, Black, White } as const;
const StrokeColorPalettes: Palette[] = [ const StrokeColorShortPalettes: Palette[] = [
...buildPalettes(StrokeColorMap), ...buildPalettes(StrokeColorShortMap),
] as const; ] as const;
const FillColorMap = { ...Medium, Black, White } as const; const FillColorShortMap = { ...Medium, Black, White } as const;
const FillColorPalettes: Palette[] = [...buildPalettes(FillColorMap)] as const; const FillColorShortPalettes: Palette[] = [
...buildPalettes(FillColorShortMap),
] as const;
const ShapeTextColorShortMap = {
...Medium,
Black: pureBlack,
White: pureWhite,
} as const;
const ShapeTextColorShortPalettes: Palette[] = [
...buildPalettes({ ...ShapeTextColorShortMap }),
] as const;
const ShapeTextColorPalettes: Palette[] = [
// Light
...buildPalettes(Light, 'Light'),
{ key: 'Transparent', value: Transparent },
// Medium
...buildPalettes(Medium, 'Medium'),
{ key: 'White', value: pureWhite },
// Heavy
...buildPalettes(Heavy, 'Heavy'),
{ key: 'Black', value: pureBlack },
] as const;
export const DefaultTheme: Theme = { export const DefaultTheme: Theme = {
pureBlack, pureBlack,
@@ -89,18 +118,19 @@ export const DefaultTheme: Theme = {
white: White, white: White,
transparent: Transparent, transparent: Transparent,
textColor: Medium.Blue, textColor: Medium.Blue,
// Custom button should be selected by default, shapeTextColor: pureBlack,
// add transparent `ff` to distinguish `#000000`.
shapeTextColor: '#000000ff',
shapeStrokeColor: Medium.Yellow, shapeStrokeColor: Medium.Yellow,
shapeFillColor: Medium.Yellow, shapeFillColor: Medium.Yellow,
connectorColor: Medium.Grey, connectorColor: Medium.Grey,
noteBackgrounColor: NoteBackgroundColorMap.White, noteBackgrounColor: NoteBackgroundColorMap.White,
Palettes, Palettes,
StrokeColorMap, ShapeTextColorPalettes,
StrokeColorPalettes,
FillColorMap,
FillColorPalettes,
NoteBackgroundColorMap, NoteBackgroundColorMap,
NoteBackgroundColorPalettes, NoteBackgroundColorPalettes,
StrokeColorShortMap,
StrokeColorShortPalettes,
FillColorShortMap,
FillColorShortPalettes,
ShapeTextColorShortMap,
ShapeTextColorShortPalettes,
} as const; } as const;
+11 -7
View File
@@ -21,16 +21,20 @@ export const ThemeSchema = z.object({
shapeFillColor: ColorSchema, shapeFillColor: ColorSchema,
connectorColor: ColorSchema, connectorColor: ColorSchema,
noteBackgrounColor: ColorSchema, noteBackgrounColor: ColorSchema,
// Universal color palette
// Universal color palettes
Palettes: z.array(PaletteSchema), Palettes: z.array(PaletteSchema),
StrokeColorMap: z.record(z.string(), ColorSchema), ShapeTextColorPalettes: z.array(PaletteSchema),
// Usually used in global toolbar and editor preview
StrokeColorPalettes: z.array(PaletteSchema),
FillColorMap: z.record(z.string(), ColorSchema),
// Usually used in global toolbar and editor preview
FillColorPalettes: z.array(PaletteSchema),
NoteBackgroundColorMap: z.record(z.string(), ColorSchema), NoteBackgroundColorMap: z.record(z.string(), ColorSchema),
NoteBackgroundColorPalettes: z.array(PaletteSchema), NoteBackgroundColorPalettes: z.array(PaletteSchema),
// Usually used in global toolbar and editor preview
StrokeColorShortMap: z.record(z.string(), ColorSchema),
StrokeColorShortPalettes: z.array(PaletteSchema),
FillColorShortMap: z.record(z.string(), ColorSchema),
FillColorShortPalettes: z.array(PaletteSchema),
ShapeTextColorShortMap: z.record(z.string(), ColorSchema),
ShapeTextColorShortPalettes: z.array(PaletteSchema),
}); });
export type Theme = z.infer<typeof ThemeSchema>; export type Theme = z.infer<typeof ThemeSchema>;
@@ -48,12 +48,12 @@ describe('apply last props', () => {
const rectShape = service.crud.getElementById(rectId) as ShapeElementModel; const rectShape = service.crud.getElementById(rectId) as ShapeElementModel;
expect(rectShape.fillColor).toBe(DefaultTheme.shapeFillColor); expect(rectShape.fillColor).toBe(DefaultTheme.shapeFillColor);
service.crud.updateElement(rectId, { service.crud.updateElement(rectId, {
fillColor: DefaultTheme.FillColorMap.Orange, fillColor: DefaultTheme.FillColorShortMap.Orange,
}); });
expect( expect(
std.get(EditPropsStore).lastProps$.value[`shape:${ShapeType.Rect}`] std.get(EditPropsStore).lastProps$.value[`shape:${ShapeType.Rect}`]
.fillColor .fillColor
).toBe(DefaultTheme.FillColorMap.Orange); ).toBe(DefaultTheme.FillColorShortMap.Orange);
// diamond shape // diamond shape
const diamondId = service.crud.addElement('shape', { const diamondId = service.crud.addElement('shape', {
@@ -63,14 +63,14 @@ describe('apply last props', () => {
const diamondShape = service.crud.getElementById( const diamondShape = service.crud.getElementById(
diamondId diamondId
) as ShapeElementModel; ) as ShapeElementModel;
expect(diamondShape.fillColor).toBe(DefaultTheme.FillColorMap.Yellow); expect(diamondShape.fillColor).toBe(DefaultTheme.FillColorShortMap.Yellow);
service.crud.updateElement(diamondId, { service.crud.updateElement(diamondId, {
fillColor: DefaultTheme.FillColorMap.Blue, fillColor: DefaultTheme.FillColorShortMap.Blue,
}); });
expect( expect(
std.get(EditPropsStore).lastProps$.value[`shape:${ShapeType.Diamond}`] std.get(EditPropsStore).lastProps$.value[`shape:${ShapeType.Diamond}`]
.fillColor .fillColor
).toBe(DefaultTheme.FillColorMap.Blue); ).toBe(DefaultTheme.FillColorShortMap.Blue);
// rounded rect shape // rounded rect shape
const roundedRectId = service.crud.addElement('shape', { const roundedRectId = service.crud.addElement('shape', {
@@ -81,13 +81,15 @@ describe('apply last props', () => {
const roundedRectShape = service.crud.getElementById( const roundedRectShape = service.crud.getElementById(
roundedRectId roundedRectId
) as ShapeElementModel; ) as ShapeElementModel;
expect(roundedRectShape.fillColor).toBe(DefaultTheme.FillColorMap.Yellow); expect(roundedRectShape.fillColor).toBe(
DefaultTheme.FillColorShortMap.Yellow
);
service.crud.updateElement(roundedRectId, { service.crud.updateElement(roundedRectId, {
fillColor: DefaultTheme.FillColorMap.Green, fillColor: DefaultTheme.FillColorShortMap.Green,
}); });
expect( expect(
std.get(EditPropsStore).lastProps$.value['shape:roundedRect'].fillColor std.get(EditPropsStore).lastProps$.value['shape:roundedRect'].fillColor
).toBe(DefaultTheme.FillColorMap.Green); ).toBe(DefaultTheme.FillColorShortMap.Green);
// apply last props // apply last props
const rectId2 = service.crud.addElement('shape', { const rectId2 = service.crud.addElement('shape', {
@@ -97,7 +99,7 @@ describe('apply last props', () => {
const rectShape2 = service.crud.getElementById( const rectShape2 = service.crud.getElementById(
rectId2 rectId2
) as ShapeElementModel; ) as ShapeElementModel;
expect(rectShape2.fillColor).toBe(DefaultTheme.FillColorMap.Orange); expect(rectShape2.fillColor).toBe(DefaultTheme.FillColorShortMap.Orange);
const diamondId2 = service.crud.addElement('shape', { const diamondId2 = service.crud.addElement('shape', {
shapeType: ShapeType.Diamond, shapeType: ShapeType.Diamond,
@@ -106,7 +108,7 @@ describe('apply last props', () => {
const diamondShape2 = service.crud.getElementById( const diamondShape2 = service.crud.getElementById(
diamondId2 diamondId2
) as ShapeElementModel; ) as ShapeElementModel;
expect(diamondShape2.fillColor).toBe(DefaultTheme.FillColorMap.Blue); expect(diamondShape2.fillColor).toBe(DefaultTheme.FillColorShortMap.Blue);
const roundedRectId2 = service.crud.addElement('shape', { const roundedRectId2 = service.crud.addElement('shape', {
shapeType: ShapeType.Rect, shapeType: ShapeType.Rect,
@@ -116,7 +118,9 @@ describe('apply last props', () => {
const roundedRectShape2 = service.crud.getElementById( const roundedRectShape2 = service.crud.getElementById(
roundedRectId2 roundedRectId2
) as ShapeElementModel; ) as ShapeElementModel;
expect(roundedRectShape2.fillColor).toBe(DefaultTheme.FillColorMap.Green); expect(roundedRectShape2.fillColor).toBe(
DefaultTheme.FillColorShortMap.Green
);
}); });
test('connector', () => { test('connector', () => {
@@ -204,14 +208,14 @@ describe('apply last props', () => {
expect(text.color).toBe(DefaultTheme.textColor); expect(text.color).toBe(DefaultTheme.textColor);
expect(text.fontFamily).toBe(FontFamily.Inter); expect(text.fontFamily).toBe(FontFamily.Inter);
service.crud.updateElement(id, { service.crud.updateElement(id, {
color: DefaultTheme.StrokeColorMap.Green, color: DefaultTheme.StrokeColorShortMap.Green,
fontFamily: FontFamily.OrelegaOne, fontFamily: FontFamily.OrelegaOne,
}); });
const id2 = service.crud.addBlock('affine:edgeless-text', {}, surface!.id); const id2 = service.crud.addBlock('affine:edgeless-text', {}, surface!.id);
assertExists(id2); assertExists(id2);
const text2 = service.crud.getElementById(id2) as EdgelessTextBlockModel; const text2 = service.crud.getElementById(id2) as EdgelessTextBlockModel;
expect(text2.color).toBe(DefaultTheme.StrokeColorMap.Green); expect(text2.color).toBe(DefaultTheme.StrokeColorShortMap.Green);
expect(text2.fontFamily).toBe(FontFamily.OrelegaOne); expect(text2.fontFamily).toBe(FontFamily.OrelegaOne);
}); });
@@ -246,13 +250,13 @@ describe('apply last props', () => {
const note = service.crud.getElementById(id) as FrameBlockModel; const note = service.crud.getElementById(id) as FrameBlockModel;
expect(note.background).toBe('transparent'); expect(note.background).toBe('transparent');
service.crud.updateElement(id, { service.crud.updateElement(id, {
background: DefaultTheme.StrokeColorMap.Purple, background: DefaultTheme.StrokeColorShortMap.Purple,
}); });
const id2 = service.crud.addBlock('affine:frame', {}, surface!.id); const id2 = service.crud.addBlock('affine:frame', {}, surface!.id);
assertExists(id2); assertExists(id2);
const frame2 = service.crud.getElementById(id2) as FrameBlockModel; const frame2 = service.crud.getElementById(id2) as FrameBlockModel;
expect(frame2.background).toBe(DefaultTheme.StrokeColorMap.Purple); expect(frame2.background).toBe(DefaultTheme.StrokeColorShortMap.Purple);
service.crud.updateElement(id2, { service.crud.updateElement(id2, {
background: { normal: '#def4e740' }, background: { normal: '#def4e740' },
}); });
@@ -51,14 +51,14 @@ export const ConnectorSettings = () => {
const { editorSetting } = framework.get(EditorSettingService); const { editorSetting } = framework.get(EditorSettingService);
const settings = useLiveData(editorSetting.settings$); const settings = useLiveData(editorSetting.settings$);
const { const {
palettes: strokeColorPalettes, palettes: StrokeColorShortPalettes,
getCurrentColor: getCurrentStrokeColor, getCurrentColor: getCurrentStrokeColor,
} = usePalettes( } = usePalettes(
DefaultTheme.StrokeColorPalettes, DefaultTheme.StrokeColorShortPalettes,
DefaultTheme.connectorColor DefaultTheme.connectorColor
); );
const { palettes: textColorPalettes, getCurrentColor: getCurrentTextColor } = const { palettes: textColorPalettes, getCurrentColor: getCurrentTextColor } =
usePalettes(DefaultTheme.StrokeColorPalettes, DefaultTheme.black); usePalettes(DefaultTheme.StrokeColorShortPalettes, DefaultTheme.black);
const connecterStyleItems = useMemo<RadioItem[]>( const connecterStyleItems = useMemo<RadioItem[]>(
() => [ () => [
@@ -165,7 +165,7 @@ export const ConnectorSettings = () => {
const colorItems = useMemo(() => { const colorItems = useMemo(() => {
const { stroke } = settings.connector; const { stroke } = settings.connector;
return strokeColorPalettes.map(({ key, value, resolvedValue }) => { return StrokeColorShortPalettes.map(({ key, value, resolvedValue }) => {
const handler = () => { const handler = () => {
editorSetting.set('connector', { stroke: value }); editorSetting.set('connector', { stroke: value });
}; };
@@ -181,7 +181,7 @@ export const ConnectorSettings = () => {
</MenuItem> </MenuItem>
); );
}); });
}, [editorSetting, settings, strokeColorPalettes]); }, [editorSetting, settings, StrokeColorShortPalettes]);
const startEndPointItems = useMemo(() => { const startEndPointItems = useMemo(() => {
const { frontEndpointStyle } = settings.connector; const { frontEndpointStyle } = settings.connector;
@@ -32,7 +32,7 @@
"e6t9tKz8Sy": { "e6t9tKz8Sy": {
"index": "a5", "index": "a5",
"seed": 338503204, "seed": 338503204,
"color": "#000000ff", "color": "#000000",
"fillColor": "#fcd34d", "fillColor": "#fcd34d",
"filled": true, "filled": true,
"fontFamily": "blocksuite:surface:Inter", "fontFamily": "blocksuite:surface:Inter",
@@ -56,7 +56,7 @@
"F8qB_zDC5Q": { "F8qB_zDC5Q": {
"index": "a6", "index": "a6",
"seed": 1896265661, "seed": 1896265661,
"color": "#000000ff", "color": "#000000",
"fillColor": "#fcd34d", "fillColor": "#fcd34d",
"filled": true, "filled": true,
"fontFamily": "blocksuite:surface:Inter", "fontFamily": "blocksuite:surface:Inter",
@@ -80,7 +80,7 @@
"mPR44JBpcd": { "mPR44JBpcd": {
"index": "a7", "index": "a7",
"seed": 2073974140, "seed": 2073974140,
"color": "#000000ff", "color": "#000000",
"fillColor": "#fcd34d", "fillColor": "#fcd34d",
"filled": true, "filled": true,
"fontFamily": "blocksuite:surface:Inter", "fontFamily": "blocksuite:surface:Inter",
@@ -104,7 +104,7 @@
"cmtluc3FWR": { "cmtluc3FWR": {
"index": "a8", "index": "a8",
"seed": 1457248130, "seed": 1457248130,
"color": "#000000ff", "color": "#000000",
"fillColor": "#fcd34d", "fillColor": "#fcd34d",
"filled": true, "filled": true,
"fontFamily": "blocksuite:surface:Inter", "fontFamily": "blocksuite:surface:Inter",
@@ -128,7 +128,7 @@
"knt_TKvACR": { "knt_TKvACR": {
"index": "a9", "index": "a9",
"seed": 1896265661, "seed": 1896265661,
"color": "#000000ff", "color": "#000000",
"fillColor": "#fcd34d", "fillColor": "#fcd34d",
"filled": true, "filled": true,
"fontFamily": "blocksuite:surface:Inter", "fontFamily": "blocksuite:surface:Inter",
@@ -22,7 +22,7 @@ export const FrameSettings = () => {
const { palettes, getCurrentColor } = usePalettes( const { palettes, getCurrentColor } = usePalettes(
[ [
{ key: 'Transparent', value: DefaultTheme.transparent }, { key: 'Transparent', value: DefaultTheme.transparent },
...DefaultTheme.FillColorPalettes, ...DefaultTheme.FillColorShortPalettes,
], ],
DefaultTheme.transparent DefaultTheme.transparent
); );
@@ -21,7 +21,7 @@ export const PenSettings = () => {
const { editorSetting } = framework.get(EditorSettingService); const { editorSetting } = framework.get(EditorSettingService);
const settings = useLiveData(editorSetting.settings$); const settings = useLiveData(editorSetting.settings$);
const { palettes, getCurrentColor } = usePalettes( const { palettes, getCurrentColor } = usePalettes(
DefaultTheme.StrokeColorPalettes, DefaultTheme.StrokeColorShortPalettes,
DefaultTheme.black DefaultTheme.black
); );
@@ -59,11 +59,19 @@ export const ShapeSettings = () => {
palettes: strokeColorPalettes, palettes: strokeColorPalettes,
getCurrentColor: getCurrentStrokeColor, getCurrentColor: getCurrentStrokeColor,
} = usePalettes( } = usePalettes(
DefaultTheme.StrokeColorPalettes, DefaultTheme.StrokeColorShortPalettes,
DefaultTheme.shapeStrokeColor DefaultTheme.shapeStrokeColor
); );
const { palettes: fillColorPalettes, getCurrentColor: getCurrentFillColor } = const { palettes: fillColorPalettes, getCurrentColor: getCurrentFillColor } =
usePalettes(DefaultTheme.FillColorPalettes, DefaultTheme.shapeFillColor); usePalettes(
DefaultTheme.FillColorShortPalettes,
DefaultTheme.shapeFillColor
);
const { palettes: textColorPalettes, getCurrentColor: getCurrentTextColor } =
usePalettes(
DefaultTheme.ShapeTextColorShortPalettes,
DefaultTheme.shapeTextColor
);
const [currentShape, setCurrentShape] = useState<ShapeName>(ShapeType.Rect); const [currentShape, setCurrentShape] = useState<ShapeName>(ShapeType.Rect);
@@ -317,7 +325,7 @@ export const ShapeSettings = () => {
const textColorItems = useMemo(() => { const textColorItems = useMemo(() => {
const { color } = settings[`shape:${currentShape}`]; const { color } = settings[`shape:${currentShape}`];
return strokeColorPalettes.map(({ key, value, resolvedValue }) => { return textColorPalettes.map(({ key, value, resolvedValue }) => {
const handler = () => { const handler = () => {
editorSetting.set(`shape:${currentShape}`, { color: value }); editorSetting.set(`shape:${currentShape}`, { color: value });
}; };
@@ -333,7 +341,7 @@ export const ShapeSettings = () => {
</MenuItem> </MenuItem>
); );
}); });
}, [editorSetting, settings, currentShape, strokeColorPalettes]); }, [editorSetting, settings, currentShape, textColorPalettes]);
const getElements = useCallback( const getElements = useCallback(
(doc: Store) => { (doc: Store) => {
@@ -379,8 +387,8 @@ export const ShapeSettings = () => {
const textColor = useMemo(() => { const textColor = useMemo(() => {
const color = settings[`shape:${currentShape}`].color; const color = settings[`shape:${currentShape}`].color;
return getCurrentStrokeColor(color); return getCurrentTextColor(color);
}, [currentShape, getCurrentStrokeColor, settings]); }, [currentShape, getCurrentTextColor, settings]);
const height = currentDoc === 'flow' ? 456 : 180; const height = currentDoc === 'flow' ? 456 : 180;
return ( return (
@@ -32,7 +32,7 @@ export const TextSettings = () => {
const { editorSetting } = framework.get(EditorSettingService); const { editorSetting } = framework.get(EditorSettingService);
const settings = useLiveData(editorSetting.settings$); const settings = useLiveData(editorSetting.settings$);
const { palettes, getCurrentColor } = usePalettes( const { palettes, getCurrentColor } = usePalettes(
DefaultTheme.StrokeColorPalettes, DefaultTheme.StrokeColorShortPalettes,
DefaultTheme.textColor DefaultTheme.textColor
); );
@@ -0,0 +1,113 @@
import { test } from '@affine-test/kit/playwright';
import {
clickEdgelessModeButton,
clickView,
dblclickView,
dragView,
locateEditorContainer,
setEdgelessTool,
} from '@affine-test/kit/utils/editor';
import { openHomePage } from '@affine-test/kit/utils/load-page';
import {
clickNewPageButton,
switchEdgelessTheme,
waitForEditorLoad,
} from '@affine-test/kit/utils/page-logic';
import { expect } from '@playwright/test';
test.beforeEach(async ({ page }) => {
await openHomePage(page);
await waitForEditorLoad(page);
await clickNewPageButton(page);
await clickEdgelessModeButton(page);
const container = locateEditorContainer(page);
await container.click();
});
test('should add text to shape, default to pure black', async ({ page }) => {
await setEdgelessTool(page, 'shape');
await dragView(page, [100, 300], [200, 400]);
await dblclickView(page, [150, 350]);
await expect(
page.locator('edgeless-shape-text-editor rich-text')
).toBeVisible();
await page.keyboard.type('text');
await page.keyboard.press('Escape');
const toolbar = page.locator(
'edgeless-element-toolbar-widget editor-toolbar'
);
const textColorContainer = toolbar.locator(
'edgeless-color-picker-button.text-color'
);
const textColorBtn = textColorContainer.getByLabel('Text color');
const blackBtn = textColorContainer
.locator('edgeless-color-button[active]')
.getByLabel('Black');
await expect(textColorContainer).toBeVisible();
await textColorBtn.click();
await expect(blackBtn).toHaveCount(1);
const svgFillColor = await blackBtn.locator('svg').getAttribute('fill');
expect(svgFillColor).toBe('#000000');
await switchEdgelessTheme(page, 'dark');
await clickView(page, [150, 350]);
await textColorBtn.click();
await expect(blackBtn).toHaveCount(1);
const svgFillColor2 = await blackBtn.locator('svg').getAttribute('fill');
expect(svgFillColor2).toBe('#000000');
});
test('should add text to shape with pure white', async ({ page }) => {
await setEdgelessTool(page, 'shape');
await dragView(page, [100, 300], [200, 400]);
await dblclickView(page, [150, 350]);
await expect(
page.locator('edgeless-shape-text-editor rich-text')
).toBeVisible();
await page.keyboard.type('text');
await page.keyboard.press('Escape');
const toolbar = page.locator(
'edgeless-element-toolbar-widget editor-toolbar'
);
const textColorContainer = toolbar.locator(
'edgeless-color-picker-button.text-color'
);
const textColorBtn = textColorContainer.getByLabel('Text color');
let currentColor = await textColorBtn
.locator('svg rect')
.getAttribute('fill');
expect(currentColor).toBe('#000000');
await textColorBtn.click();
const blackBtn = textColorContainer
.locator('edgeless-color-button[active]')
.getByLabel('Black');
await expect(blackBtn).toHaveCount(1);
const whiteBtn = textColorContainer
.locator('edgeless-color-button')
.getByLabel('White');
await whiteBtn.click();
currentColor = await textColorBtn.locator('svg rect').getAttribute('fill');
expect(currentColor).toBe('#ffffff');
await switchEdgelessTheme(page, 'dark');
await clickView(page, [150, 350]);
currentColor = await textColorBtn.locator('svg rect').getAttribute('fill');
expect(currentColor).toBe('#ffffff');
});
+12
View File
@@ -1,6 +1,8 @@
import type { Locator, Page } from '@playwright/test'; import type { Locator, Page } from '@playwright/test';
import { expect } from '@playwright/test'; import { expect } from '@playwright/test';
import { openEditorInfoPanel } from './setting';
export function getAllPage(page: Page) { export function getAllPage(page: Page) {
const newPageButton = page.getByTestId('new-page-button-trigger'); const newPageButton = page.getByTestId('new-page-button-trigger');
const newPageDropdown = newPageButton.locator('svg'); const newPageDropdown = newPageButton.locator('svg');
@@ -236,3 +238,13 @@ export const addDatabaseRow = async (page: Page, databaseTitle: string) => {
}); });
await db.locator('.data-view-table-group-add-row-button').click(); await db.locator('.data-view-table-group-add-row-button').click();
}; };
export const switchEdgelessTheme = async (
page: Page,
type: 'system' | 'light' | 'dark'
) => {
await openEditorInfoPanel(page);
const panel = page.getByTestId('info-modal');
await panel.locator(`button[value="${type}"]`).click();
await page.keyboard.press('Escape');
};
+4
View File
@@ -29,6 +29,10 @@ export async function openAboutPanel(page: Page) {
await page.getByTestId('about-panel-trigger').click(); await page.getByTestId('about-panel-trigger').click();
} }
export async function openEditorInfoPanel(page: Page) {
await page.getByTestId('header-info-button').click();
}
export async function openExperimentalFeaturesPanel(page: Page) { export async function openExperimentalFeaturesPanel(page: Page) {
await page.getByTestId('experimental-features-trigger').click(); await page.getByTestId('experimental-features-trigger').click();
} }