Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(edgeless): add font isolation on canvas text #5403

Merged
merged 7 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
"@commitlint/cli": "^18.2.0",
"@commitlint/config-conventional": "^18.1.0",
"@open-wc/dev-server-hmr": "^0.2.0",
"@playwright/test": "^1.39.0",
"@playwright/test": "^1.40.0",
"@types/node": "^20.8.10",
"@typescript-eslint/eslint-plugin": "^6.10.0",
"@typescript-eslint/parser": "^6.10.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,9 @@ import {
} from '../panel/color-panel.js';
import type { EdgelessFontFamilyPanel } from '../panel/font-family-panel.js';
import type { EdgelessFontSizePanel } from '../panel/font-size-panel.js';
import {
type EdgelessCanvasTextElement,
type EdgelessCanvasTextElementType,
TEXT_FONT_SIZE,
import type {
EdgelessCanvasTextElement,
EdgelessCanvasTextElementType,
} from '../text/types.js';
import { createButtonPopper } from '../utils.js';
import { ShapeArrowDownSmallIcon } from './../../../../_common/icons/index.js';
Expand Down Expand Up @@ -222,9 +221,7 @@ export class EdgelessChangeTextMenu extends WithDisposable(LitElement) {
(element: EdgelessCanvasTextElement) => element.fontSize
);
const max = maxBy(Object.entries(fontSizes), ([_k, count]) => count);
return max
? (Number(max[0]) as EdgelessCanvasTextElement['fontSize'])
: TEXT_FONT_SIZE.MEDIUM;
return max ? (Number(max[0]) as EdgelessCanvasTextElement['fontSize']) : 16;
};

private _getMostCommonFontWeight = (
Expand Down Expand Up @@ -362,21 +359,6 @@ export class EdgelessChangeTextMenu extends WithDisposable(LitElement) {
});
};

private _getFontSizeLabel = (fontSize: number) => {
switch (fontSize) {
case TEXT_FONT_SIZE.SMALL:
return 'Small';
case TEXT_FONT_SIZE.MEDIUM:
return 'Middle';
case TEXT_FONT_SIZE.LARGE:
return 'Large';
case TEXT_FONT_SIZE.XLARGE:
return 'Huge';
default:
return Math.trunc(fontSize);
}
};

override firstUpdated(changedProperties: Map<string, unknown>) {
const _disposables = this._disposables;

Expand Down Expand Up @@ -503,9 +485,7 @@ export class EdgelessChangeTextMenu extends WithDisposable(LitElement) {
@click=${() => this._textFontSizePopper?.toggle()}
>
<div class="font-size-button-group">
<div class="selected-font-size-label">
${this._getFontSizeLabel(selectedFontSize)}
</div>
<div class="selected-font-size-label">${selectedFontSize}</div>
<div class="arrow-down-icon">${ShapeArrowDownSmallIcon}</div>
</div>
</edgeless-tool-icon-button>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { css, html, LitElement } from 'lit';
import { css, html, LitElement, unsafeCSS } from 'lit';
import { customElement, property } from 'lit/decorators.js';

import { CanvasTextFontFamily } from '../../../../surface-block/consts.js';
import { wrapFontFamily } from '../../../../surface-block/elements/text/utils.js';

@customElement('edgeless-font-family-panel')
export class EdgelessFontFamilyPanel extends LitElement {
Expand All @@ -25,31 +26,38 @@ export class EdgelessFontFamilyPanel extends LitElement {
}

.inter {
font-family: 'Inter', sans-serif;
font-family: ${unsafeCSS(wrapFontFamily(CanvasTextFontFamily.Inter))},
sans-serif;
}

.kalam {
font-family: 'Kalam', sans-serif;
font-family: ${unsafeCSS(wrapFontFamily(CanvasTextFontFamily.Kalam))},
sans-serif;
}

.satoshi {
font-family: 'Satoshi', sans-serif;
font-family: ${unsafeCSS(wrapFontFamily(CanvasTextFontFamily.Satoshi))},
sans-serif;
}

.poppins {
font-family: 'Poppins', sans-serif;
font-family: ${unsafeCSS(wrapFontFamily(CanvasTextFontFamily.Poppins))},
sans-serif;
}

.lora {
font-family: 'Lora', sans-serif;
font-family: ${unsafeCSS(wrapFontFamily(CanvasTextFontFamily.Lora))},
sans-serif;
}

.bebas-neue {
font-family: 'BebasNeue', sans-serif;
font-family: ${unsafeCSS(wrapFontFamily(CanvasTextFontFamily.BebasNeue))},
sans-serif;
}

.orelega-one {
font-family: 'OrelegaOne', sans-serif;
font-family: ${unsafeCSS(wrapFontFamily(CanvasTextFontFamily.OrelegaOne))},
sans-serif;
}
`;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { css, html, LitElement } from 'lit';
import { customElement, property } from 'lit/decorators.js';

import { stopPropagation } from '../../../../_common/utils/event.js';
import { TEXT_FONT_SIZE } from '../text/types.js';

const MIN_FONT_SIZE = 1;
const MAX_FONT_SIZE = 2000;
Expand Down Expand Up @@ -137,46 +136,20 @@ export class EdgelessFontSizePanel extends LitElement {
return html`
<div class="font-size-container">
<div class="font-size-content">
<div
class="font-size-button"
role="button"
?active=${this.fontSize === TEXT_FONT_SIZE.SMALL}
@click=${() => {
this._onSelect(TEXT_FONT_SIZE.SMALL);
}}
>
<div class="font-size-button-label">Small</div>
</div>
<div
class="font-size-button"
role="button"
?active=${this.fontSize === TEXT_FONT_SIZE.MEDIUM}
@click=${() => {
this._onSelect(TEXT_FONT_SIZE.MEDIUM);
}}
>
<div class="font-size-button-label">Middle</div>
</div>
<div
class="font-size-button"
role="button"
?active=${this.fontSize === TEXT_FONT_SIZE.LARGE}
@click=${() => {
this._onSelect(TEXT_FONT_SIZE.LARGE);
}}
>
<div class="font-size-button-label">Large</div>
</div>
<div
class="font-size-button"
role="button"
?active=${this.fontSize === TEXT_FONT_SIZE.XLARGE}
@click=${() => {
this._onSelect(TEXT_FONT_SIZE.XLARGE);
}}
>
<div class="font-size-button-label">Huge</div>
</div>
${[16, 24, 32, 36, 40, 64, 128].map(
fontSize => html`
<div
class="font-size-button"
role="button"
?active=${this.fontSize === fontSize}
@click=${() => {
this._onSelect(fontSize);
}}
>
<div class="font-size-button-label">${fontSize}</div>
</div>
`
)}

<div
class="font-size-input-container"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,12 @@ export class EdgelessFontWeightAndStylePanel extends LitElement {
}

override render() {
const fontFaces = getFontFacesByFontFamily(this.fontFamily);
let fontFaces = getFontFacesByFontFamily(this.fontFamily);
// Compatible with old data
if (fontFaces.length === 0) {
fontFaces = getFontFacesByFontFamily(CanvasTextFontFamily.Inter);
}

const fontFacesWithNormal = fontFaces.filter(fontFace => {
return fontFace.style === CanvasTextFontStyle.Normal;
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { styleMap } from 'lit/directives/style-map.js';
import type { RichText } from '../../../../_common/components/rich-text/rich-text.js';
import { isCssVariable } from '../../../../_common/theme/css-variables.js';
import { SHAPE_TEXT_PADDING } from '../../../../surface-block/elements/shape/consts.js';
import { wrapFontFamily } from '../../../../surface-block/elements/text/utils.js';
import type {
PhasorElementType,
ShapeElement,
Expand Down Expand Up @@ -162,7 +163,7 @@ export class EdgelessShapeTextEditor extends WithDisposable(ShadowlessElement) {
width: rect.width + 'px',
minHeight: rect.height + 'px',
fontSize: this.element.fontSize + 'px',
fontFamily: this.element.fontFamily,
fontFamily: wrapFontFamily(this.element.fontFamily),
lineHeight: 'initial',
outline: 'none',
transform: `scale(${zoom}, ${zoom}) rotate(${rotate}deg)`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { styleMap } from 'lit/directives/style-map.js';

import type { RichText } from '../../../../_common/components/rich-text/rich-text.js';
import { isCssVariable } from '../../../../_common/theme/css-variables.js';
import { wrapFontFamily } from '../../../../surface-block/elements/text/utils.js';
import {
Bound,
type TextElement,
Expand Down Expand Up @@ -421,7 +422,7 @@ export class EdgelessTextEditor extends WithDisposable(ShadowlessElement) {
return html`<div
style=${styleMap({
textAlign,
fontFamily,
fontFamily: wrapFontFamily(fontFamily),
minWidth: hasMaxWidth ? `${rect.width}px` : 'none',
maxWidth: hasMaxWidth ? `${w}px` : 'none',
fontSize: `${fontSize}px`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,3 @@ export type EdgelessCanvasTextEditor =

export type EdgelessCanvasTextElement = ShapeElement | TextElement;
export type EdgelessCanvasTextElementType = 'shape' | 'text';

export enum TEXT_FONT_SIZE {
SMALL = 12,
MEDIUM = 20,
LARGE = 28,
XLARGE = 36,
}
26 changes: 9 additions & 17 deletions packages/blocks/src/surface-block/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,16 @@ export interface IModelCoord {
y: number;
}

export const CANVAS_TEXT_FONT_FAMILY: string[] = [
'Inter',
'Kalam',
'Satoshi',
'Poppins',
'Lora',
'BebasNeue',
'OrelegaOne',
];
export const enum CanvasTextFontFamily {
Inter = 'Inter',
Kalam = 'Kalam',
Satoshi = 'Satoshi',
Poppins = 'Poppins',
Lora = 'Lora',
BebasNeue = 'BebasNeue',
OrelegaOne = 'OrelegaOne',
export enum CanvasTextFontFamily {
Inter = 'blocksuite:surface:Inter',
Kalam = 'blocksuite:surface:Kalam',
Satoshi = 'blocksuite:surface:Satoshi',
Poppins = 'blocksuite:surface:Poppins',
Lora = 'blocksuite:surface:Lora',
BebasNeue = 'blocksuite:surface:BebasNeue',
OrelegaOne = 'blocksuite:surface:OrelegaOne',
}
export const CANVAS_TEXT_FONT_FAMILY = Object.values(CanvasTextFontFamily);

export const enum CanvasTextFontWeight {
Light = '300',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { assertExists } from '@blocksuite/global/utils';

import { CanvasTextFontStyle, CanvasTextFontWeight } from '../../consts.js';
import {
CanvasTextFontFamily,
CanvasTextFontStyle,
CanvasTextFontWeight,
} from '../../consts.js';
import type { RoughCanvas } from '../../rough/canvas.js';
import { Bound } from '../../utils/bound.js';
import { linePolygonIntersects } from '../../utils/math-utils.js';
Expand All @@ -22,7 +26,7 @@ export class GroupElement extends SurfaceElement<IGroup, IGroupLocalRecord> {
// unable to find the children and id.
private _cachedChildren: string[] = [];

private _titleHeight = getLineHeight("'Kalam', cursive", 16);
private _titleHeight = getLineHeight(CanvasTextFontFamily.Kalam, 16);
private _titleWidth = 0;
private _padding = [0, 0];
private _radius = 0;
Expand Down Expand Up @@ -157,7 +161,7 @@ export class GroupElement extends SurfaceElement<IGroup, IGroupLocalRecord> {
const zoom = this.renderer!.zoom;
const bound = Bound.deserialize(this.xywh);
const fontSize = 16 / zoom;
const fontFamily = 'sans-serif';
const fontFamily = CanvasTextFontFamily.Inter;
const offset = Math.max(4 / zoom, 2);
ctx.translate(0, -offset);

Expand Down
17 changes: 13 additions & 4 deletions packages/blocks/src/surface-block/elements/text/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,21 @@ export const isChrome =
export const isSafari =
!isChrome && globalThis.navigator?.userAgent.indexOf('Safari') !== -1;

export function getLineHeight(fontFamily: string, fontSize: number) {
export function wrapFontFamily(fontFamily: CanvasTextFontFamily): string {
return `"${fontFamily}"`;
}

export function getLineHeight(
fontFamily: CanvasTextFontFamily,
fontSize: number
) {
// Browser may have minimum font size setting
// so we need to multiple the multiplier between the actual size and the expected size
const actualFontSize = Math.max(fontSize, 12);
const div = document.createElement('div');
const span = document.createElement('span');

span.style.fontFamily = fontFamily;
span.style.fontFamily = wrapFontFamily(fontFamily);
span.style.fontSize = actualFontSize + 'px';
span.style.lineHeight = 'initial';
span.textContent = 'M';
Expand All @@ -51,10 +58,12 @@ export function getFontString({
fontStyle: string;
fontWeight: string;
fontSize: number;
fontFamily: string;
fontFamily: CanvasTextFontFamily;
}): string {
const lineHeight = getLineHeight(fontFamily, fontSize);
return `${fontStyle} ${fontWeight} ${fontSize}px/${lineHeight}px ${fontFamily}`.trim();
return `${fontStyle} ${fontWeight} ${fontSize}px/${lineHeight}px ${wrapFontFamily(
fontFamily
)}`.trim();
}

export function normalizeText(text: string): string {
Expand Down
Loading
Loading