fix #13459 fix #13707 fix #13924 #### PR Dependency Tree * **PR #14394** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Improved URL paste: text is split into segments, inserted correctly, and single-URL pastes create linked-page references. * **UI Improvements** * Redesigned layout selector with compact dynamic options. * Number-format options are always available in table headers and mobile menus. * **Bug Fixes** * More consistent paste behavior for mixed text+URL content. * Prevented recursive selection updates when exiting edit mode. * **Tests** * Added tests for URL splitting, paste insertion, number formatting, and selection behavior. * **Chores** * Removed number-formatting feature flag; formatting now applied by default. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
126 lines
3.2 KiB
TypeScript
126 lines
3.2 KiB
TypeScript
import { IS_MAC } from '@blocksuite/global/env';
|
|
import { html } from 'lit';
|
|
import { query } from 'lit/decorators.js';
|
|
|
|
import { BaseCellRenderer } from '../../core/property/index.js';
|
|
import { createFromBaseCellRenderer } from '../../core/property/renderer.js';
|
|
import { stopPropagation } from '../../core/utils/event.js';
|
|
import { createIcon } from '../../core/utils/uni-icon.js';
|
|
import { numberInputStyle, numberStyle } from './cell-renderer-css.js';
|
|
import { numberPropertyModelConfig } from './define.js';
|
|
import type { NumberPropertyDataType } from './types.js';
|
|
import {
|
|
formatNumber,
|
|
type NumberFormat,
|
|
parseNumber,
|
|
} from './utils/formatter.js';
|
|
|
|
export class NumberCell extends BaseCellRenderer<
|
|
number,
|
|
number,
|
|
NumberPropertyDataType
|
|
> {
|
|
@query('input')
|
|
private accessor _inputEle!: HTMLInputElement;
|
|
|
|
private _getFormattedString(value: number | undefined = this.value) {
|
|
const decimals = this.property.data$.value.decimal ?? 0;
|
|
const formatMode = (this.property.data$.value.format ??
|
|
'number') as NumberFormat;
|
|
|
|
return value != undefined ? formatNumber(value, formatMode, decimals) : '';
|
|
}
|
|
|
|
private readonly _keydown = (e: KeyboardEvent) => {
|
|
const ctrlKey = IS_MAC ? e.metaKey : e.ctrlKey;
|
|
|
|
if (e.key.toLowerCase() === 'z' && ctrlKey) {
|
|
e.stopPropagation();
|
|
return;
|
|
}
|
|
|
|
if (e.key === 'Enter' && !e.isComposing) {
|
|
requestAnimationFrame(() => {
|
|
this.selectCurrentCell(false);
|
|
});
|
|
}
|
|
};
|
|
|
|
private readonly _setValue = (str: string = this._inputEle?.value) => {
|
|
if (!str) {
|
|
this.valueSetNextTick(undefined);
|
|
return;
|
|
}
|
|
|
|
const value = parseNumber(str);
|
|
if (isNaN(value)) {
|
|
if (this._inputEle) {
|
|
this._inputEle.value = this.value
|
|
? this._getFormattedString(this.value)
|
|
: '';
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (this._inputEle) {
|
|
this._inputEle.value = this._getFormattedString(value);
|
|
}
|
|
this.valueSetNextTick(value);
|
|
};
|
|
|
|
focusEnd = () => {
|
|
if (!this._inputEle) return;
|
|
|
|
const end = this._inputEle.value.length;
|
|
this._inputEle.focus();
|
|
this._inputEle.setSelectionRange(end, end);
|
|
};
|
|
|
|
_blur() {
|
|
this.selectCurrentCell(false);
|
|
}
|
|
|
|
_focus() {
|
|
if (!this.isEditing$.value) {
|
|
this.selectCurrentCell(true);
|
|
}
|
|
}
|
|
|
|
override afterEnterEditingMode() {
|
|
this.focusEnd();
|
|
}
|
|
|
|
override beforeExitEditingMode() {
|
|
this._setValue();
|
|
}
|
|
|
|
override render() {
|
|
if (this.isEditing$.value) {
|
|
const formatted = this.value ? this._getFormattedString(this.value) : '';
|
|
|
|
return html`<input
|
|
type="text"
|
|
autocomplete="off"
|
|
.value="${formatted}"
|
|
@keydown="${this._keydown}"
|
|
@blur="${this._blur}"
|
|
@focus="${this._focus}"
|
|
class="${numberInputStyle} number"
|
|
@pointerdown="${stopPropagation}"
|
|
/>`;
|
|
} else {
|
|
return html` <div class="${numberStyle} number">
|
|
${this._getFormattedString()}
|
|
</div>`;
|
|
}
|
|
}
|
|
}
|
|
|
|
export const numberPropertyConfig =
|
|
numberPropertyModelConfig.createPropertyMeta({
|
|
icon: createIcon('NumberIcon'),
|
|
cellRenderer: {
|
|
view: createFromBaseCellRenderer(NumberCell),
|
|
},
|
|
});
|