chore: merge blocksuite source code (#9213)

This commit is contained in:
Mirone
2024-12-20 15:38:06 +08:00
committed by GitHub
parent 2c9ef916f4
commit 30200ff86d
2031 changed files with 238888 additions and 229 deletions
@@ -0,0 +1,74 @@
import {
getNextContentBlock,
matchFlavours,
} from '@blocksuite/affine-shared/utils';
import type { BlockStdScope } from '@blocksuite/block-std';
import type { Text } from '@blocksuite/store';
// When deleting at line end of a list block,
// check current block's children and siblings
/**
* Example:
- Line1 <-(cursor here)
- Line2
- Line3
- Line4
- Line5
- Line6
- Line7
- Line8
- Line9
*/
export function forwardDelete(std: BlockStdScope): true | undefined {
const text = std.selection.find('text');
if (!text) return;
const isCollapsed = text.isCollapsed();
const doc = std.doc;
const model = doc.getBlock(text.from.blockId)?.model;
if (!model || !matchFlavours(model, ['affine:list'])) return;
const isEnd = isCollapsed && text.from.index === model.text.length;
if (!isEnd) return;
// Has children in list
const firstChild = model.firstChild();
if (firstChild) {
model.text.join(firstChild.text as Text);
const grandChildren = firstChild.children;
if (grandChildren) {
doc.moveBlocks(grandChildren, model);
doc.deleteBlock(firstChild);
return true;
}
doc.deleteBlock(firstChild);
return true;
}
const parent = doc.getParent(model);
// Has text sibling
const nextSibling = doc.getNext(model);
const nextText = nextSibling?.text;
if (nextSibling && nextText) {
model.text.join(nextText);
if (nextSibling.children) {
if (!parent) return;
doc.moveBlocks(nextSibling.children, parent, model, false);
}
doc.deleteBlock(nextSibling);
return true;
}
// Has next text block in other note block
const nextBlock = getNextContentBlock(std.host, model);
const nextBlockText = nextBlock?.text;
if (nextBlock && nextBlockText) {
model.text.join(nextBlock.text as Text);
if (nextBlock.children) {
const nextBlockParent = doc.getParent(nextBlock);
if (!nextBlockParent) return;
doc.moveBlocks(nextBlock.children, nextBlockParent, parent, false);
}
doc.deleteBlock(nextBlock);
}
return true;
}
@@ -0,0 +1,66 @@
import {
BulletIcons,
checkboxChecked,
checkboxUnchecked,
toggleDown,
toggleRight,
} from '@blocksuite/affine-components/icons';
import type { ListBlockModel } from '@blocksuite/affine-model';
import { html } from 'lit';
import { getNumberPrefix } from './get-number-prefix.js';
const getListDeep = (model: ListBlockModel): number => {
let deep = 0;
let parent = model.doc.getParent(model);
while (parent?.flavour === model.flavour) {
deep++;
parent = model.doc.getParent(parent);
}
return deep;
};
export function getListIcon(
model: ListBlockModel,
showChildren: boolean,
onClick: (e: MouseEvent) => void
) {
const deep = getListDeep(model);
switch (model.type) {
case 'bulleted':
return html`<div
contenteditable="false"
class="affine-list-block__prefix"
@click=${onClick}
>
${BulletIcons[deep % BulletIcons.length]}
</div>`;
case 'numbered':
return html`<div
contenteditable="false"
class="affine-list-block__prefix affine-list-block__numbered"
@click=${onClick}
>
${model.order ? getNumberPrefix(model.order, deep) : '1.'}
</div>`;
case 'todo':
return html`<div
contenteditable="false"
class=${`affine-list-block__prefix affine-list-block__todo-prefix ${model.doc.readonly ? 'readonly' : ''}`}
@click=${onClick}
>
${model.checked ? checkboxChecked() : checkboxUnchecked()}
</div>`;
case 'toggle':
return html`<div
contenteditable="false"
class="affine-list-block__prefix"
@click=${onClick}
>
${showChildren ? toggleDown : toggleRight}
</div>`;
default:
console.error('Unknown list type', model.type, model);
return null;
}
}
@@ -0,0 +1,52 @@
function number2letter(n: number) {
const ordA = 'a'.charCodeAt(0);
const ordZ = 'z'.charCodeAt(0);
const len = ordZ - ordA + 1;
let s = '';
while (n >= 0) {
s = String.fromCharCode((n % len) + ordA) + s;
n = Math.floor(n / len) - 1;
}
return s;
}
// Derive from https://gist.github.com/imilu/00f32c61e50b7ca296f91e9d96d8e976
export function number2roman(num: number) {
const lookup: Record<string, number> = {
M: 1000,
CM: 900,
D: 500,
CD: 400,
C: 100,
XC: 90,
L: 50,
XL: 40,
X: 10,
IX: 9,
V: 5,
IV: 4,
I: 1,
};
let romanStr = '';
for (const i in lookup) {
while (num >= lookup[i]) {
romanStr += i;
num -= lookup[i];
}
}
return romanStr;
}
function getPrefix(depth: number, index: number) {
const map = [
() => index,
() => number2letter(index - 1),
() => number2roman(index),
];
return map[depth % map.length]();
}
export function getNumberPrefix(index: number, depth: number) {
const prefix = getPrefix(depth, index);
return `${prefix}.`;
}