diff --git a/blocksuite/affine/blocks/block-note/src/components/edgeless-note-border-dropdown-menu.ts b/blocksuite/affine/blocks/block-note/src/components/edgeless-note-border-dropdown-menu.ts index 2cea67a0c9..5eb655ea3c 100644 --- a/blocksuite/affine/blocks/block-note/src/components/edgeless-note-border-dropdown-menu.ts +++ b/blocksuite/affine/blocks/block-note/src/components/edgeless-note-border-dropdown-menu.ts @@ -20,10 +20,10 @@ export class EdgelessNoteBorderDropdownMenu extends ShadowlessElement { `} > - + > `; } diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/components/panel/line-styles-panel.ts b/blocksuite/affine/blocks/block-root/src/edgeless/components/panel/line-styles-panel.ts deleted file mode 100644 index bc164712a0..0000000000 --- a/blocksuite/affine/blocks/block-root/src/edgeless/components/panel/line-styles-panel.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { LineWidth, StrokeStyle } from '@blocksuite/affine-model'; -import { BanIcon, DashLineIcon, StraightLineIcon } from '@blocksuite/icons/lit'; -import { html } from 'lit'; -import { classMap } from 'lit/directives/class-map.js'; -import { repeat } from 'lit/directives/repeat.js'; - -import type { LineWidthEvent } from './line-width-panel.js'; - -export type LineStyleEvent = - | { - type: 'size'; - value: LineWidth; - } - | { - type: 'lineStyle'; - value: StrokeStyle; - }; - -interface LineStylesPanelProps { - onClick?: (e: LineStyleEvent) => void; - selectedLineSize?: LineWidth; - selectedLineStyle?: StrokeStyle; - lineStyles?: StrokeStyle[]; -} - -const LINE_STYLE_LIST = [ - { - name: 'Solid', - value: StrokeStyle.Solid, - icon: StraightLineIcon(), - }, - { - name: 'Dash', - value: StrokeStyle.Dash, - icon: DashLineIcon(), - }, - { - name: 'None', - value: StrokeStyle.None, - icon: BanIcon(), - }, -]; - -export function LineStylesPanel({ - onClick, - selectedLineStyle, - selectedLineSize = LineWidth.Two, - lineStyles = [StrokeStyle.Solid, StrokeStyle.Dash, StrokeStyle.None], -}: LineStylesPanelProps = {}) { - const lineSizePanel = html` - { - onClick?.({ - type: 'size', - value: e.detail, - }); - }} - > - `; - - const lineStyleButtons = repeat( - LINE_STYLE_LIST.filter(item => lineStyles.includes(item.value)), - item => item.value, - ({ name, icon, value }) => { - const active = selectedLineStyle === value; - const classInfo = { - 'line-style-button': true, - [`mode-${value}`]: true, - }; - if (active) classInfo['active'] = true; - - return html` - - onClick?.({ - type: 'lineStyle', - value, - })} - > - ${icon} - - `; - } - ); - - return html` - ${lineSizePanel} - - ${lineStyleButtons} - `; -} diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/components/panel/line-width-panel.ts b/blocksuite/affine/blocks/block-root/src/edgeless/components/panel/line-width-panel.ts deleted file mode 100644 index 1879df7aae..0000000000 --- a/blocksuite/affine/blocks/block-root/src/edgeless/components/panel/line-width-panel.ts +++ /dev/null @@ -1,239 +0,0 @@ -import { LINE_WIDTHS, LineWidth } from '@blocksuite/affine-model'; -import { on, once } from '@blocksuite/affine-shared/utils'; -import { WithDisposable } from '@blocksuite/global/lit'; -import { css, html, LitElement, nothing, type PropertyValues } from 'lit'; -import { property, query } from 'lit/decorators.js'; -import { repeat } from 'lit/directives/repeat.js'; -import clamp from 'lodash-es/clamp'; - -interface Config { - width: number; - itemSize: number; - itemIconSize: number; - dragHandleSize: number; - count: number; -} - -export class LineWidthEvent extends CustomEvent {} - -export class EdgelessLineWidthPanel extends WithDisposable(LitElement) { - static override styles = css` - :host { - display: flex; - align-items: center; - justify-content: center; - align-self: stretch; - - --width: 140px; - --item-size: 16px; - --item-icon-size: 8px; - --drag-handle-size: 14px; - --cursor: 0; - --count: 6; - /* (16 - 14) / 2 + (cursor / (count - 1)) * (140 - 16) */ - --drag-handle-center-x: calc( - (var(--item-size) - var(--drag-handle-size)) / 2 + - (var(--cursor) / (var(--count) - 1)) * - (var(--width) - var(--item-size)) - ); - } - - :host([disabled]) { - opacity: 0.5; - pointer-events: none; - } - - .line-width-panel { - width: var(--width); - height: 24px; - display: flex; - flex-direction: row; - align-items: center; - justify-content: space-between; - position: relative; - cursor: default; - } - - .line-width-button { - display: flex; - align-items: center; - justify-content: center; - width: var(--item-size); - height: var(--item-size); - z-index: 2; - } - - .line-width-icon { - width: var(--item-icon-size); - height: var(--item-icon-size); - background-color: var(--affine-border-color); - border-radius: 50%; - } - - .line-width-button[data-selected] .line-width-icon { - background-color: var(--affine-icon-color); - } - - .drag-handle { - position: absolute; - width: var(--drag-handle-size); - height: var(--drag-handle-size); - border-radius: 50%; - background-color: var(--affine-icon-color); - z-index: 3; - transform: translateX(var(--drag-handle-center-x)); - } - - .bottom-line, - .line-width-overlay { - position: absolute; - height: 1px; - left: calc(var(--item-size) / 2); - } - - .bottom-line { - width: calc(100% - var(--item-size)); - background-color: var(--affine-border-color); - } - - .line-width-overlay { - background-color: var(--affine-icon-color); - z-index: 1; - width: var(--drag-handle-center-x); - } - `; - - private readonly _getDragHandlePosition = (e: PointerEvent) => { - return clamp(e.offsetX, 0, this.config.width); - }; - - private readonly _onPointerDown = (e: PointerEvent) => { - e.preventDefault(); - this._onPointerMove(e); - - const dispose = on(this, 'pointermove', this._onPointerMove); - this._disposables.add(once(this, 'pointerup', dispose)); - this._disposables.add(once(this, 'pointerout', dispose)); - }; - - private readonly _onPointerMove = (e: PointerEvent) => { - e.preventDefault(); - - const x = this._getDragHandlePosition(e); - - this._updateLineWidthPanelByDragHandlePosition(x); - }; - - private _onSelect(lineWidth: LineWidth) { - // If the selected size is the same as the previous one, do nothing. - if (lineWidth === this.selectedSize) return; - this.dispatchEvent( - new LineWidthEvent('select', { - detail: lineWidth, - composed: true, - bubbles: true, - }) - ); - this.selectedSize = lineWidth; - } - - private _updateLineWidthPanel(selectedSize: LineWidth) { - if (!this._lineWidthOverlay) return; - const index = this.lineWidths.findIndex(w => w === selectedSize); - if (index === -1) return; - - this.style.setProperty('--cursor', `${index}`); - } - - private _updateLineWidthPanelByDragHandlePosition(x: number) { - // Calculate the selected size based on the drag handle position. - // Need to select the nearest size. - - const { - config: { width, itemSize, count }, - lineWidths, - } = this; - const targetWidth = width - itemSize; - const halfItemSize = itemSize / 2; - const offsetX = halfItemSize + (width - itemSize * count) / (count - 1) / 2; - const selectedSize = lineWidths.findLast((_, n) => { - const cx = halfItemSize + (n / (count - 1)) * targetWidth; - return x >= cx - offsetX && x < cx + offsetX; - }); - if (!selectedSize) return; - - this._updateLineWidthPanel(selectedSize); - this._onSelect(selectedSize); - } - - override connectedCallback() { - super.connectedCallback(); - const { - style, - config: { width, itemSize, itemIconSize, dragHandleSize, count }, - } = this; - style.setProperty('--width', `${width}px`); - style.setProperty('--item-size', `${itemSize}px`); - style.setProperty('--item-icon-size', `${itemIconSize}px`); - style.setProperty('--drag-handle-size', `${dragHandleSize}px`); - style.setProperty('--count', `${count}`); - } - - override firstUpdated() { - this._updateLineWidthPanel(this.selectedSize); - this._disposables.addFromEvent(this, 'pointerdown', this._onPointerDown); - } - - override render() { - return html`
- ${repeat( - this.lineWidths, - w => w, - (w, n) => - html`
-
-
` - )} -
-
-
- ${this.hasTooltip - ? html`Thickness` - : nothing} -
`; - } - - override willUpdate(changedProperties: PropertyValues) { - if (changedProperties.has('selectedSize')) { - this._updateLineWidthPanel(this.selectedSize); - } - } - - @query('.line-width-overlay') - private accessor _lineWidthOverlay!: HTMLElement; - - accessor config: Config = { - width: 140, - itemSize: 16, - itemIconSize: 8, - dragHandleSize: 14, - count: LINE_WIDTHS.length, - }; - - @property({ attribute: false, type: Boolean }) - accessor disabled = false; - - @property({ attribute: false }) - accessor hasTooltip = true; - - @property({ attribute: false }) - accessor lineWidths: LineWidth[] = LINE_WIDTHS; - - @property({ attribute: false }) - accessor selectedSize: LineWidth = LineWidth.Two; -} diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/components/panel/stroke-style-panel.ts b/blocksuite/affine/blocks/block-root/src/edgeless/components/panel/stroke-style-panel.ts index 407c924129..1c35d6c216 100644 --- a/blocksuite/affine/blocks/block-root/src/edgeless/components/panel/stroke-style-panel.ts +++ b/blocksuite/affine/blocks/block-root/src/edgeless/components/panel/stroke-style-panel.ts @@ -1,11 +1,10 @@ +import type { LineDetailType } from '@blocksuite/affine-components/edgeless-line-styles-panel'; import { type ColorScheme, type StrokeStyle } from '@blocksuite/affine-model'; import type { ColorEvent } from '@blocksuite/affine-shared/utils'; import { WithDisposable } from '@blocksuite/global/lit'; import { css, html, LitElement } from 'lit'; import { property } from 'lit/decorators.js'; -import { type LineStyleEvent, LineStylesPanel } from './line-styles-panel.js'; - export class StrokeStylePanel extends WithDisposable(LitElement) { static override styles = css` :host { @@ -26,11 +25,12 @@ export class StrokeStylePanel extends WithDisposable(LitElement) { override render() { return html`
- ${LineStylesPanel({ - selectedLineSize: this.strokeWidth, - selectedLineStyle: this.strokeStyle, - onClick: e => this.setStrokeStyle(e), - })} + +
void; @property({ attribute: false }) - accessor setStrokeStyle!: (e: LineStyleEvent) => void; + accessor setStrokeStyle!: (e: LineDetailType) => void; @property({ attribute: false }) accessor strokeColor!: string; diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/components/toolbar/brush/brush-menu.ts b/blocksuite/affine/blocks/block-root/src/edgeless/components/toolbar/brush/brush-menu.ts index a34ab309c3..f95f2d77e1 100644 --- a/blocksuite/affine/blocks/block-root/src/edgeless/components/toolbar/brush/brush-menu.ts +++ b/blocksuite/affine/blocks/block-root/src/edgeless/components/toolbar/brush/brush-menu.ts @@ -1,4 +1,4 @@ -import { DefaultTheme } from '@blocksuite/affine-model'; +import { DefaultTheme, type LineWidth } from '@blocksuite/affine-model'; import { EditPropsStore, FeatureFlagService, @@ -11,7 +11,6 @@ import { computed } from '@preact/signals-core'; import { css, html, LitElement } from 'lit'; import { property } from 'lit/decorators.js'; -import type { LineWidthEvent } from '../../panel/line-width-panel.js'; import { EdgelessToolbarToolMixin } from '../mixins/tool.mixin.js'; export class EdgelessBrushMenu extends EdgelessToolbarToolMixin( @@ -56,7 +55,7 @@ export class EdgelessBrushMenu extends EdgelessToolbarToolMixin(