refactor: consolidate browser workbench and remove E2E infrastructure (#7600)
@@ -1,17 +0,0 @@
|
||||
name: 📸 Update Snapshots
|
||||
description: Update snapshots and push a new commit.
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Install Playwright Browsers
|
||||
shell: bash
|
||||
run: pnpm exec playwright install --with-deps chromium
|
||||
|
||||
- name: Build E2E Client
|
||||
shell: bash
|
||||
run: pnpm build:e2e
|
||||
|
||||
- name: Update Snapshots
|
||||
shell: bash
|
||||
run: pnpm exec playwright test e2e/visual-comparison --update-snapshots
|
||||
@@ -1,56 +0,0 @@
|
||||
name: 🔭 Dev Performance Report
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
e2e-test:
|
||||
if: github.repository == 'dream-num/univer'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set Env
|
||||
run: |
|
||||
if [ "$GITHUB_EVENT_NAME" == "push" ] && [ "$GITHUB_REF" == "refs/heads/dev" ]; then
|
||||
echo "SHOULD_REPORT_TO_POSTHOG=true" >> $GITHUB_ENV
|
||||
elif [ "$GITHUB_EVENT_NAME" == "pull_request" ] && [ "$GITHUB_BASE_REF" == "dev" ]; then
|
||||
echo "SHOULD_REPORT_TO_POSTHOG=true" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: ./.github/actions/setup-node
|
||||
|
||||
- name: Cache Playwright browsers
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
- name: Install Playwright Browsers
|
||||
run: pnpm exec playwright install --with-deps chromium
|
||||
|
||||
- name: Build E2E Client
|
||||
run: pnpm build:e2e
|
||||
|
||||
- name: Run Playwright Tests
|
||||
env:
|
||||
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
|
||||
run: pnpm exec playwright test
|
||||
@@ -1,109 +0,0 @@
|
||||
name: 🎭 Playwright Tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- reopened
|
||||
- ready_for_review
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
env:
|
||||
TURBO_TELEMETRY_DISABLED: '1'
|
||||
|
||||
jobs:
|
||||
e2e-shard:
|
||||
name: e2e-test shard (${{ matrix.shard-index }}/${{ matrix.shard-total }})
|
||||
if: github.repository == 'dream-num/univer' && (github.event_name != 'pull_request' || !github.event.pull_request.draft)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
shard-index: [1, 2, 3, 4]
|
||||
shard-total: [4]
|
||||
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: ./.github/actions/setup-node
|
||||
|
||||
- name: Cache Playwright browsers
|
||||
id: playwright-cache
|
||||
uses: actions/cache/restore@v6
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
- name: Install Playwright Browsers
|
||||
run: pnpm exec playwright install --with-deps chromium
|
||||
|
||||
- name: Save Playwright browsers
|
||||
if: matrix.shard-index == 1 && steps.playwright-cache.outputs.cache-hit != 'true'
|
||||
uses: actions/cache/save@v6
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
- name: Build E2E Client
|
||||
run: pnpm build:e2e
|
||||
|
||||
- name: Run Playwright Tests
|
||||
run: pnpm exec playwright test --shard=${{ matrix.shard-index }}/${{ matrix.shard-total }}
|
||||
|
||||
- name: Write Playwright Report to PR Comment
|
||||
uses: daun/playwright-report-summary@v4
|
||||
if: always()
|
||||
with:
|
||||
report-file: playwright-report.json
|
||||
custom-info: 'For more information, [see full report and artifacts](https://github.com/dream-num/univer/actions/runs/${{ github.run_id }})'
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
if: ${{ !cancelled() }}
|
||||
with:
|
||||
name: playwright-report-${{ matrix.shard-index }}-of-${{ matrix.shard-total }}
|
||||
path: playwright-report/
|
||||
retention-days: 7
|
||||
|
||||
- name: Upload HeapSnapshots
|
||||
uses: actions/upload-artifact@v7
|
||||
if: ${{ failure() }}
|
||||
with:
|
||||
name: snapshots-${{ matrix.shard-index }}-of-${{ matrix.shard-total }}
|
||||
path: test-results/*.heapsnapshot
|
||||
retention-days: 3
|
||||
|
||||
e2e-test:
|
||||
name: e2e-test
|
||||
runs-on: minimum-runner
|
||||
timeout-minutes: 5
|
||||
needs: e2e-shard
|
||||
if: ${{ always() && github.repository == 'dream-num/univer' && (github.event_name != 'pull_request' || !github.event.pull_request.draft) }}
|
||||
|
||||
steps:
|
||||
- name: Check shard results
|
||||
run: |
|
||||
if [ "${{ needs.e2e-shard.result }}" != "success" ]; then
|
||||
echo "One or more e2e shards failed: ${{ needs.e2e-shard.result }}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "All e2e shards passed"
|
||||
@@ -1,42 +0,0 @@
|
||||
name: 📸 Manually Update Snapshots
|
||||
|
||||
# manual trigger
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
update-snapshots:
|
||||
if: github.repository == 'dream-num/univer'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: ./.github/actions/setup-node
|
||||
|
||||
- name: Update Snapshots
|
||||
uses: ./.github/actions/update-snapshots
|
||||
|
||||
- name: Commit Updated Snapshots
|
||||
shell: bash
|
||||
env:
|
||||
PUSH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
run: |
|
||||
git config --global user.email "actions@github.com"
|
||||
git config --global user.name "GitHub Actions"
|
||||
git remote set-url origin "https://x-access-token:${PUSH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
|
||||
|
||||
git status
|
||||
git add -A
|
||||
git commit -m "chore(snapshots): update snapshots" || exit 0
|
||||
git push origin "HEAD:${GITHUB_REF_NAME}"
|
||||
@@ -8,8 +8,8 @@
|
||||
"name": "Launch Sheet (Chrome)",
|
||||
"request": "launch",
|
||||
"type": "chrome",
|
||||
"url": "http://localhost:3002/sheets/",
|
||||
"webRoot": "${workspaceFolder}/examples/local/sheets",
|
||||
"url": "http://localhost:5173/#sheets",
|
||||
"webRoot": "${workspaceFolder}/examples",
|
||||
"presentation": {
|
||||
"group": "0_example",
|
||||
"order": 2
|
||||
@@ -19,8 +19,8 @@
|
||||
"name": "Launch Sheet (Edge)",
|
||||
"request": "launch",
|
||||
"type": "msedge",
|
||||
"url": "http://localhost:3002/sheets",
|
||||
"webRoot": "${workspaceFolder}/examples/sheets/local/",
|
||||
"url": "http://localhost:5173/#sheets",
|
||||
"webRoot": "${workspaceFolder}/examples",
|
||||
"presentation": {
|
||||
"group": "0_example",
|
||||
"order": 1
|
||||
@@ -30,8 +30,8 @@
|
||||
"name": "Launch Doc (Chrome)",
|
||||
"request": "launch",
|
||||
"type": "chrome",
|
||||
"url": "http://localhost:3002",
|
||||
"webRoot": "${workspaceFolder}/examples/local/docs",
|
||||
"url": "http://localhost:5173/#docs",
|
||||
"webRoot": "${workspaceFolder}/examples",
|
||||
"presentation": {
|
||||
"group": "0_example",
|
||||
"order": 4
|
||||
@@ -41,8 +41,8 @@
|
||||
"name": "Launch Doc (Edge)",
|
||||
"request": "launch",
|
||||
"type": "msedge",
|
||||
"url": "http://localhost:3002",
|
||||
"webRoot": "${workspaceFolder}/examples/local/docs",
|
||||
"url": "http://localhost:5173/#docs",
|
||||
"webRoot": "${workspaceFolder}/examples",
|
||||
"presentation": {
|
||||
"group": "0_example",
|
||||
"order": 3
|
||||
@@ -52,8 +52,8 @@
|
||||
"name": "Launch Slide (Chrome)",
|
||||
"request": "launch",
|
||||
"type": "chrome",
|
||||
"url": "http://localhost:3004",
|
||||
"webRoot": "${workspaceFolder}/examples/slides/local/",
|
||||
"url": "http://localhost:5173/#slides",
|
||||
"webRoot": "${workspaceFolder}/examples",
|
||||
"presentation": {
|
||||
"group": "0_example",
|
||||
"order": 6
|
||||
@@ -63,8 +63,8 @@
|
||||
"name": "Launch Slide (Edge)",
|
||||
"request": "launch",
|
||||
"type": "msedge",
|
||||
"url": "http://localhost:3004",
|
||||
"webRoot": "${workspaceFolder}/examples/slides/local/",
|
||||
"url": "http://localhost:5173/#slides",
|
||||
"webRoot": "${workspaceFolder}/examples",
|
||||
"presentation": {
|
||||
"group": "0_example",
|
||||
"order": 5
|
||||
|
||||
@@ -63,9 +63,7 @@ The structure of the repository is as follows:
|
||||
.
|
||||
├── common/ shared configuration and utilities
|
||||
├── docs/ documentation
|
||||
├── e2e/ e2e test cases
|
||||
├── examples/ demos running on the web
|
||||
├── mockdata/ mock data for development
|
||||
├── examples/ all-in-one Vite workbench for browser development
|
||||
├── packages/ Univer core and plugins
|
||||
```
|
||||
|
||||
@@ -172,25 +170,9 @@ Also, with the help of vscode and its rich ecosystem, you could directly debug u
|
||||
|
||||

|
||||
|
||||
### E2E test
|
||||
### Browser workbench
|
||||
|
||||
You may need to install dependencies of Playwright manually by running the following command:
|
||||
|
||||
```shell
|
||||
pnpm exec playwright install
|
||||
```
|
||||
|
||||
If you would like to develop E2E tests, you can use the following command to run the dev server:
|
||||
|
||||
```shell
|
||||
pnpm dev:e2e
|
||||
```
|
||||
|
||||
and then run the following command to run E2E tests:
|
||||
|
||||
```shell
|
||||
pnpm test:e2e
|
||||
```
|
||||
`pnpm dev` starts one Vite workbench with lazy-loaded Sheets, Docs, and Slides routes. Use the navigation bar or `#sheets`, `#docs`, and `#slides` URLs to switch products; only one Univer instance stays mounted. The Settings menu provides every built-in language, LTR/RTL direction, region, theme, appearance, ribbon, UI chrome, and zoom controls. Preferences are stored in localStorage and applied to the active instance through runtime APIs without remounting it. Development locale data is loaded on demand so unused product and language graphs do not remain in Vite's memory. End-to-end suites should consume built packages outside this repository instead of coupling tests to source examples.
|
||||
|
||||
### Build Preview
|
||||
|
||||
@@ -201,10 +183,6 @@ pnpm build
|
||||
pnpm dev:libs
|
||||
```
|
||||
|
||||
### Update Snapshots
|
||||
|
||||
Univer uses Playwright to perform visual comparison tests. If you have made changes to the UI, the CI may fail due to visual differences. You can update the snapshots by running this GitHub Action [📸 Manually Update Snapshots · Workflow runs · dream-num/univer (github.com)](https://github.com/dream-num/univer/actions/workflows/update-snapshots-manually.yml) on your branch.
|
||||
|
||||
### Clean code
|
||||
|
||||
> Programs are meant to be ready by humans and only incidentally for computers to execute. - Harold Abelson
|
||||
|
||||
@@ -290,9 +290,8 @@ Boundary principles:
|
||||
```text
|
||||
.
|
||||
├── packages/ Core packages, engines, document types, UI plugins, and feature plugins
|
||||
├── examples/ Local browser and Node.js demos used for development
|
||||
├── common/ Shared internal tooling, mock data, storybook, and utilities
|
||||
├── e2e/ Playwright and visual comparison tests
|
||||
├── examples/ All-in-one Vite workbench used for local browser development
|
||||
├── common/ Shared internal tooling, storybook, and utilities
|
||||
├── tests/ Additional integration test projects
|
||||
└── docs/ Architecture notes, images, and repository-local documentation
|
||||
```
|
||||
@@ -317,12 +316,11 @@ Useful commands:
|
||||
|
||||
| Command | Purpose |
|
||||
| --- | --- |
|
||||
| `pnpm dev` | Start the local examples app. |
|
||||
| `pnpm dev` | Start the all-in-one Sheets, Docs, and Slides workbench with Vite 8 Bundled Dev and HMR. |
|
||||
| `pnpm build` | Build workspace packages, excluding internal common packages. |
|
||||
| `pnpm test` | Run unit tests through Turbo. |
|
||||
| `pnpm typecheck` | Run TypeScript checks through Turbo. |
|
||||
| `pnpm lint` | Run ESLint. |
|
||||
| `pnpm test:e2e` | Run Playwright tests. |
|
||||
| `pnpm storybook:dev` | Start Storybook for UI component development. |
|
||||
|
||||
Read [CONTRIBUTING.md](./CONTRIBUTING.md) before opening a pull request.
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
"@univerjs/docs-drawing-ui": "workspace:*",
|
||||
"@univerjs/engine-render": "workspace:*",
|
||||
"@univerjs/icons": "1.38.0",
|
||||
"@univerjs/mockdata": "workspace:*",
|
||||
"@univerjs/sheets": "workspace:*",
|
||||
"@univerjs/sheets-drawing-ui": "workspace:*",
|
||||
"@univerjs/themes": "workspace:*",
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
import type { IWorkbookData } from '@univerjs/core';
|
||||
import { LocaleType } from '@univerjs/core';
|
||||
|
||||
export function getDefaultWorkbookData(): IWorkbookData {
|
||||
const DEFAULT_WORKBOOK_DATA_DEMO = {
|
||||
id: 'test',
|
||||
appVersion: '3.0.0-alpha',
|
||||
sheets: {
|
||||
sheet1: {
|
||||
id: 'sheet1',
|
||||
name: 'sheet1',
|
||||
cellData: {
|
||||
0: {
|
||||
3: {
|
||||
f: '=SUM(A1)',
|
||||
si: '3e4r5t',
|
||||
},
|
||||
},
|
||||
1: {
|
||||
3: {
|
||||
f: '=SUM(A2)',
|
||||
si: 'OSPtzm',
|
||||
},
|
||||
},
|
||||
2: {
|
||||
3: {
|
||||
si: 'OSPtzm',
|
||||
},
|
||||
},
|
||||
3: {
|
||||
3: {
|
||||
si: 'OSPtzm',
|
||||
},
|
||||
},
|
||||
},
|
||||
rowCount: 100,
|
||||
columnCount: 100,
|
||||
},
|
||||
},
|
||||
locale: LocaleType.ZH_CN,
|
||||
name: '',
|
||||
sheetOrder: [],
|
||||
styles: {},
|
||||
resources: [
|
||||
],
|
||||
};
|
||||
|
||||
return DEFAULT_WORKBOOK_DATA_DEMO;
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
import type { Univer } from '@univerjs/core';
|
||||
import type { FUniver } from '@univerjs/core/facade';
|
||||
import type { IBoundRectNoAngle, IScrollRenderInfo } from '@univerjs/engine-render';
|
||||
import { awaitTime, Disposable, DocumentFlavor, Inject, IUniverInstanceService, ThemeService, UniverInstanceType } from '@univerjs/core';
|
||||
import { scrollAndClearCanvas, UniverRenderingContext } from '@univerjs/engine-render';
|
||||
import { DEFAULT_WORKBOOK_DATA_DEMO, DEFAULT_WORKBOOK_DATA_DEMO_DEFAULT_STYLE } from '@univerjs/mockdata';
|
||||
import { getDefaultDocData } from './data/default-doc';
|
||||
import { getDefaultWorkbookData } from './data/default-sheet';
|
||||
|
||||
const AWAIT_LOADING_TIMEOUT = 5000;
|
||||
const AWAIT_DISPOSING_TIMEOUT = 5000;
|
||||
|
||||
// NOTE: this interface is copied to `e2e/e2e.d.ts`. When you modify this interface, make sure
|
||||
// the duplication is updated as well.
|
||||
export interface IE2EControllerAPI {
|
||||
loadAndRelease(id: number, loadTimeout?: number, disposeTimeout?: number): Promise<void>;
|
||||
loadDefaultSheet(loadTimeout?: number): Promise<void>;
|
||||
loadDemoSheet(loadTimeout?: number): Promise<void>;
|
||||
loadMergeCellSheet(loadTimeout?: number): Promise<void>;
|
||||
loadDefaultStyleSheet(loadTimeout?: number): Promise<void>;
|
||||
loadDefaultDoc(loadTimeout?: number,): Promise<void>;
|
||||
loadDocLayoutFixture(documentFlavor: DocumentFlavor, loadTimeout?: number): Promise<void>;
|
||||
setDarkMode(darkMode: boolean): void;
|
||||
disposeUniver(): Promise<void>;
|
||||
disposeCurrSheetUnit(disposeTimeout?: number): Promise<void>;
|
||||
scrollAndClearCanvas(
|
||||
canvas: HTMLCanvasElement,
|
||||
pixelRatio: number,
|
||||
scrollRenderInfos: IScrollRenderInfo[],
|
||||
dirtyBounds: IBoundRectNoAngle[]
|
||||
): void;
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
||||
interface Window {
|
||||
E2EControllerAPI: IE2EControllerAPI;
|
||||
univer?: Univer;
|
||||
univerAPI?: FUniver;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This controller expose a API on `Window` for the E2E tests.
|
||||
*/
|
||||
export class E2EController extends Disposable {
|
||||
constructor(
|
||||
@IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService,
|
||||
@Inject(ThemeService) private readonly _themeService: ThemeService
|
||||
) {
|
||||
super();
|
||||
|
||||
this._initPlugin();
|
||||
}
|
||||
|
||||
override dispose(): void {
|
||||
// @ts-ignore
|
||||
window.E2EControllerAPI = undefined;
|
||||
}
|
||||
|
||||
private _initPlugin(): void {
|
||||
window.E2EControllerAPI = {
|
||||
loadAndRelease: (id, loadTimeout, disposeTimeout) => this._loadAndRelease(id, loadTimeout, disposeTimeout),
|
||||
loadDefaultSheet: (loadTimeout) => this._loadDefaultSheet(loadTimeout),
|
||||
loadDemoSheet: () => this._loadDemoSheet(),
|
||||
loadMergeCellSheet: () => this._loadMergeCellSheet(2000),
|
||||
loadDefaultStyleSheet: (loadTimeout) => this._loadDefaultStyleSheet(loadTimeout),
|
||||
disposeCurrSheetUnit: (disposeTimeout?: number) => this._disposeDefaultSheetUnit(disposeTimeout),
|
||||
setDarkMode: (darkMode) => this._setDarkMode(darkMode),
|
||||
loadDefaultDoc: (loadTimeout) => this._loadDefaultDoc(loadTimeout),
|
||||
loadDocLayoutFixture: (documentFlavor, loadTimeout) => this._loadDocLayoutFixture(documentFlavor, loadTimeout),
|
||||
disposeUniver: () => this._disposeUniver(),
|
||||
scrollAndClearCanvas: (canvas, pixelRatio, scrollRenderInfos, dirtyBounds) =>
|
||||
this._scrollAndClearCanvas(canvas, pixelRatio, scrollRenderInfos, dirtyBounds),
|
||||
};
|
||||
}
|
||||
|
||||
private _scrollAndClearCanvas(
|
||||
canvas: HTMLCanvasElement,
|
||||
pixelRatio: number,
|
||||
scrollRenderInfos: IScrollRenderInfo[],
|
||||
dirtyBounds: IBoundRectNoAngle[]
|
||||
): void {
|
||||
const nativeContext = canvas.getContext('2d');
|
||||
if (nativeContext == null) {
|
||||
throw new Error('Canvas does not have a 2D context.');
|
||||
}
|
||||
|
||||
scrollAndClearCanvas(new UniverRenderingContext(nativeContext), pixelRatio, scrollRenderInfos, dirtyBounds);
|
||||
}
|
||||
|
||||
private _setDarkMode(darkMode: boolean): void {
|
||||
this._themeService.setDarkMode(darkMode);
|
||||
}
|
||||
|
||||
private async _loadAndRelease(releaseId: number, loadingTimeout: number = AWAIT_LOADING_TIMEOUT, disposingTimeout: number = AWAIT_DISPOSING_TIMEOUT): Promise<void> {
|
||||
const unitId = `e2e${releaseId}`;
|
||||
const snapshot = getDefaultWorkbookData();
|
||||
snapshot.id = unitId;
|
||||
|
||||
this._univerInstanceService.createUnit(UniverInstanceType.UNIVER_SHEET, snapshot);
|
||||
await awaitTime(loadingTimeout);
|
||||
|
||||
this._univerInstanceService.disposeUnit(unitId);
|
||||
await awaitTime(disposingTimeout);
|
||||
}
|
||||
|
||||
private async _loadDefaultSheet(loadingTimeout: number = AWAIT_LOADING_TIMEOUT): Promise<void> {
|
||||
this._univerInstanceService.createUnit(UniverInstanceType.UNIVER_SHEET, getDefaultWorkbookData());
|
||||
await awaitTime(loadingTimeout);
|
||||
}
|
||||
|
||||
private async _loadDemoSheet(): Promise<void> {
|
||||
this._univerInstanceService.createUnit(UniverInstanceType.UNIVER_SHEET, DEFAULT_WORKBOOK_DATA_DEMO);
|
||||
await awaitTime(AWAIT_LOADING_TIMEOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* sheet-003 in default data
|
||||
*/
|
||||
private async _loadMergeCellSheet(loadingTimeout: number = AWAIT_LOADING_TIMEOUT): Promise<void> {
|
||||
const data = { ...DEFAULT_WORKBOOK_DATA_DEMO };
|
||||
data.sheetOrder = ['sheet-0003'];
|
||||
this._univerInstanceService.createUnit(UniverInstanceType.UNIVER_SHEET, data);
|
||||
await awaitTime(loadingTimeout);
|
||||
}
|
||||
|
||||
private async _loadDefaultStyleSheet(loadingTimeout: number = AWAIT_LOADING_TIMEOUT): Promise<void> {
|
||||
const data = { ...DEFAULT_WORKBOOK_DATA_DEMO_DEFAULT_STYLE };
|
||||
this._univerInstanceService.createUnit(UniverInstanceType.UNIVER_SHEET, data);
|
||||
await awaitTime(loadingTimeout);
|
||||
}
|
||||
|
||||
private async _loadDefaultDoc(loadingTimeout: number = AWAIT_LOADING_TIMEOUT): Promise<void> {
|
||||
this._univerInstanceService.createUnit(UniverInstanceType.UNIVER_DOC, getDefaultDocData());
|
||||
await awaitTime(loadingTimeout);
|
||||
}
|
||||
|
||||
private async _loadDocLayoutFixture(documentFlavor: DocumentFlavor, loadingTimeout: number = AWAIT_LOADING_TIMEOUT): Promise<void> {
|
||||
if (documentFlavor !== DocumentFlavor.TRADITIONAL && documentFlavor !== DocumentFlavor.MODERN) {
|
||||
throw new Error(`Unsupported Doc E2E flavor: ${documentFlavor}`);
|
||||
}
|
||||
const snapshot = getDefaultDocData();
|
||||
snapshot.id = `e2e-doc-layout-${documentFlavor}`;
|
||||
snapshot.documentStyle = { ...snapshot.documentStyle, documentFlavor };
|
||||
this._univerInstanceService.createUnit(UniverInstanceType.UNIVER_DOC, snapshot);
|
||||
await awaitTime(loadingTimeout);
|
||||
}
|
||||
|
||||
private async _disposeUniver(): Promise<void> {
|
||||
window.univer?.dispose();
|
||||
window.univer = undefined;
|
||||
window.univerAPI = undefined;
|
||||
}
|
||||
|
||||
private async _disposeDefaultSheetUnit(disposingTimeout: number = AWAIT_DISPOSING_TIMEOUT): Promise<void> {
|
||||
const unit = this._univerInstanceService.getCurrentUnitOfType(UniverInstanceType.UNIVER_SHEET);
|
||||
const unitId = unit?.getUnitId();
|
||||
await this._univerInstanceService.disposeUnit(unitId || '');
|
||||
await awaitTime(disposingTimeout);
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import pkg from '../package.json';
|
||||
import { DEBUGGER_PLUGIN_CONFIG_KEY, defaultPluginConfig } from './config/config';
|
||||
import { ComponentsController } from './controllers/components.controller';
|
||||
import { DebuggerController } from './controllers/debugger.controller';
|
||||
import { E2EController } from './controllers/e2e/e2e.controller';
|
||||
import { PerformanceMonitorController } from './controllers/performance-monitor.controller';
|
||||
|
||||
export class UniverDebuggerPlugin extends Plugin {
|
||||
@@ -38,7 +37,6 @@ export class UniverDebuggerPlugin extends Plugin {
|
||||
const dependencies: Dependency[] = [
|
||||
[DebuggerController],
|
||||
[ComponentsController],
|
||||
[E2EController],
|
||||
];
|
||||
|
||||
if (this._config.performanceMonitor?.enabled !== false) {
|
||||
@@ -46,10 +44,6 @@ export class UniverDebuggerPlugin extends Plugin {
|
||||
}
|
||||
|
||||
registerDependencies(this._injector, dependencies);
|
||||
|
||||
touchDependencies(this._injector, [
|
||||
[E2EController],
|
||||
]);
|
||||
}
|
||||
|
||||
override onReady(): void {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { Univer } from '@univerjs/core';
|
||||
import { IUniverInstanceService } from '@univerjs/core';
|
||||
import { useDependency } from '@univerjs/ui';
|
||||
|
||||
@@ -17,9 +18,10 @@ export function useDispose() {
|
||||
|
||||
const onSelect = (value: string) => {
|
||||
if (value === 'univer') {
|
||||
window.univer?.dispose();
|
||||
window.univer = undefined;
|
||||
window.univerAPI = undefined;
|
||||
const debuggerWindow = window as typeof window & { univer?: Univer };
|
||||
debuggerWindow.univer?.dispose();
|
||||
Reflect.deleteProperty(debuggerWindow, 'univer');
|
||||
Reflect.deleteProperty(debuggerWindow, 'univerAPI');
|
||||
} else if (value === 'unit') {
|
||||
const focused = univerInstanceService.getFocusedUnit();
|
||||
if (!focused) return false;
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
src/locales
|
||||
@@ -1,5 +0,0 @@
|
||||
# @univerjs/mockdata
|
||||
|
||||
## Introduction
|
||||
|
||||
This package provides mock data for demo and e2e tests.
|
||||
@@ -1,80 +0,0 @@
|
||||
{
|
||||
"name": "@univerjs/mockdata",
|
||||
"version": "1.0.0-beta.2",
|
||||
"private": true,
|
||||
"description": "",
|
||||
"author": "DreamNum <developer@univer.ai>",
|
||||
"license": "Apache-2.0",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/univer"
|
||||
},
|
||||
"homepage": "https://univer.ai",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/dream-num/univer"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/dream-num/univer/issues"
|
||||
},
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./locales/*": "./src/locales/*.ts",
|
||||
"./*": "./src/*"
|
||||
},
|
||||
"main": "./src/index.ts",
|
||||
"scripts": {
|
||||
"prepare": "node --experimental-strip-types ./scripts/generate-locales.mts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@univerjs/action-recorder": "workspace:*",
|
||||
"@univerjs/core": "workspace:*",
|
||||
"@univerjs/data-validation": "workspace:*",
|
||||
"@univerjs/design": "workspace:*",
|
||||
"@univerjs/docs": "workspace:*",
|
||||
"@univerjs/docs-drawing": "workspace:*",
|
||||
"@univerjs/docs-drawing-ui": "workspace:*",
|
||||
"@univerjs/docs-hyper-link-ui": "workspace:*",
|
||||
"@univerjs/docs-quick-insert-ui": "workspace:*",
|
||||
"@univerjs/docs-thread-comment-ui": "workspace:*",
|
||||
"@univerjs/docs-ui": "workspace:*",
|
||||
"@univerjs/drawing": "workspace:*",
|
||||
"@univerjs/drawing-ui": "workspace:*",
|
||||
"@univerjs/engine-formula": "workspace:*",
|
||||
"@univerjs/engine-render": "workspace:*",
|
||||
"@univerjs/find-replace": "workspace:*",
|
||||
"@univerjs/sheets": "workspace:*",
|
||||
"@univerjs/sheets-conditional-formatting": "workspace:*",
|
||||
"@univerjs/sheets-conditional-formatting-ui": "workspace:*",
|
||||
"@univerjs/sheets-crosshair-highlight": "workspace:*",
|
||||
"@univerjs/sheets-data-validation": "workspace:*",
|
||||
"@univerjs/sheets-data-validation-ui": "workspace:*",
|
||||
"@univerjs/sheets-drawing": "workspace:*",
|
||||
"@univerjs/sheets-drawing-ui": "workspace:*",
|
||||
"@univerjs/sheets-filter": "workspace:*",
|
||||
"@univerjs/sheets-filter-ui": "workspace:*",
|
||||
"@univerjs/sheets-find-replace": "workspace:*",
|
||||
"@univerjs/sheets-formula": "workspace:*",
|
||||
"@univerjs/sheets-formula-ui": "workspace:*",
|
||||
"@univerjs/sheets-hyper-link": "workspace:*",
|
||||
"@univerjs/sheets-hyper-link-ui": "workspace:*",
|
||||
"@univerjs/sheets-note-ui": "workspace:*",
|
||||
"@univerjs/sheets-numfmt-ui": "workspace:*",
|
||||
"@univerjs/sheets-sort": "workspace:*",
|
||||
"@univerjs/sheets-sort-ui": "workspace:*",
|
||||
"@univerjs/sheets-table": "workspace:*",
|
||||
"@univerjs/sheets-table-ui": "workspace:*",
|
||||
"@univerjs/sheets-thread-comment": "workspace:*",
|
||||
"@univerjs/sheets-thread-comment-ui": "workspace:*",
|
||||
"@univerjs/sheets-ui": "workspace:*",
|
||||
"@univerjs/slides": "workspace:*",
|
||||
"@univerjs/slides-ui": "workspace:*",
|
||||
"@univerjs/thread-comment": "workspace:*",
|
||||
"@univerjs/thread-comment-ui": "workspace:*",
|
||||
"@univerjs/ui": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@univerjs-infra/shared": "workspace:*",
|
||||
"typescript": "^6.0.3"
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { discoverUniverUiLocales } from '@univerjs-infra/shared/locale';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const root = path.resolve(__dirname, '../../..');
|
||||
|
||||
type MockdataPackageJson = Record<string, unknown> & {
|
||||
dependencies: Record<string, string>;
|
||||
};
|
||||
|
||||
function readJsonFileSync<T>(filePath: string): T {
|
||||
return JSON.parse(fs.readFileSync(filePath, 'utf8')) as T;
|
||||
}
|
||||
|
||||
function writeJsonFileSync(filePath: string, value: unknown) {
|
||||
fs.writeFileSync(filePath, `${JSON.stringify(value, null, 4)}\n`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate locales files
|
||||
*/
|
||||
async function generateLocales() {
|
||||
const packageNames: string[] = [];
|
||||
|
||||
const pkgJsonFile = readJsonFileSync<MockdataPackageJson>(path.resolve(__dirname, '../package.json'));
|
||||
|
||||
const packagesRoot = path.resolve(__dirname, '../../../packages');
|
||||
const packageEntries = fs.existsSync(packagesRoot)
|
||||
? fs.readdirSync(packagesRoot, { withFileTypes: true })
|
||||
: [];
|
||||
const packages = packageEntries
|
||||
.filter((entry) => entry.isDirectory())
|
||||
.map((entry) => path.join(packagesRoot, entry.name))
|
||||
.filter((pkgPath) => fs.existsSync(pkgPath));
|
||||
|
||||
const allPackages = [...packages];
|
||||
for (const pkg of allPackages) {
|
||||
const localePath = path.join(pkg, 'src/locale');
|
||||
if (fs.existsSync(localePath)) {
|
||||
const pkgJsonPath = path.join(pkg, 'package.json');
|
||||
if (!fs.existsSync(pkgJsonPath)) {
|
||||
continue;
|
||||
}
|
||||
const pkgJson = readJsonFileSync<{ name: string }>(pkgJsonPath);
|
||||
packageNames.push(pkgJson.name);
|
||||
pkgJsonFile.dependencies[pkgJson.name] = 'workspace:*';
|
||||
}
|
||||
}
|
||||
|
||||
writeJsonFileSync(path.resolve(__dirname, '../package.json'), pkgJsonFile);
|
||||
|
||||
discoverUniverUiLocales({ rootDir: root }).forEach((locale) => {
|
||||
let statements = '/* eslint-disable */\n';
|
||||
|
||||
packageNames.forEach((pkg) => {
|
||||
const pkgName = pkg.replace(/@|univerjs|\/|-/g, '');
|
||||
statements += `import ${pkgName}Locale from '${pkg}/locale/${locale}';\n`;
|
||||
});
|
||||
|
||||
statements += '\nexport default Object.assign(\n';
|
||||
statements += ' {},\n';
|
||||
|
||||
packageNames.forEach((pkg) => {
|
||||
const pkgName = pkg.replace(/@|univerjs|\/|-/g, '');
|
||||
statements += ` ${pkgName}Locale,\n`;
|
||||
});
|
||||
statements += ');\n';
|
||||
|
||||
const outputPath = path.resolve(__dirname, `../src/locales/${locale}.ts`);
|
||||
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
||||
fs.writeFileSync(outputPath, statements);
|
||||
});
|
||||
}
|
||||
|
||||
generateLocales();
|
||||
@@ -1,291 +0,0 @@
|
||||
import type { IDocumentData } from '@univerjs/core';
|
||||
import {
|
||||
BooleanNumber,
|
||||
ColumnSeparatorType,
|
||||
DocumentFlavor,
|
||||
DrawingTypeEnum,
|
||||
ObjectRelativeFromH,
|
||||
ObjectRelativeFromV,
|
||||
PositionedObjectLayoutType,
|
||||
SectionType,
|
||||
WrapTextType,
|
||||
} from '@univerjs/core';
|
||||
import { ptToPixel } from '@univerjs/engine-render';
|
||||
|
||||
export const DEFAULT_DOCUMENT_DATA_DREAMER: IDocumentData = {
|
||||
id: 'd',
|
||||
drawings: {
|
||||
shapeTest1: {
|
||||
unitId: 'd',
|
||||
subUnitId: 'd',
|
||||
drawingType: DrawingTypeEnum.DRAWING_SHAPE,
|
||||
drawingId: 'shapeTest1',
|
||||
title: 'test shape',
|
||||
description: 'test shape',
|
||||
docTransform: {
|
||||
size: {
|
||||
width: 1484 * 0.15,
|
||||
height: 864 * 0.15,
|
||||
},
|
||||
positionH: {
|
||||
relativeFrom: ObjectRelativeFromH.COLUMN,
|
||||
posOffset: 130,
|
||||
},
|
||||
positionV: {
|
||||
relativeFrom: ObjectRelativeFromV.PAGE,
|
||||
posOffset: 510,
|
||||
},
|
||||
angle: 0,
|
||||
},
|
||||
layoutType: PositionedObjectLayoutType.WRAP_SQUARE,
|
||||
behindDoc: BooleanNumber.FALSE,
|
||||
wrapText: WrapTextType.BOTH_SIDES,
|
||||
},
|
||||
shapeTest2: {
|
||||
unitId: 'd',
|
||||
subUnitId: 'd',
|
||||
drawingType: DrawingTypeEnum.DRAWING_SHAPE,
|
||||
drawingId: 'shapeTest2',
|
||||
title: 'test shape',
|
||||
description: 'test shape',
|
||||
docTransform: {
|
||||
size: {
|
||||
width: 2548 * 0.1,
|
||||
height: 2343 * 0.1,
|
||||
},
|
||||
positionH: {
|
||||
relativeFrom: ObjectRelativeFromH.COLUMN,
|
||||
posOffset: 130,
|
||||
},
|
||||
positionV: {
|
||||
relativeFrom: ObjectRelativeFromV.PAGE,
|
||||
posOffset: 200,
|
||||
},
|
||||
angle: 0,
|
||||
},
|
||||
layoutType: PositionedObjectLayoutType.WRAP_SQUARE,
|
||||
behindDoc: BooleanNumber.FALSE,
|
||||
wrapText: WrapTextType.BOTH_SIDES,
|
||||
},
|
||||
},
|
||||
body: {
|
||||
dataStream:
|
||||
'The Dreamer\r\rGo with your passion.It has been said that who see the invisible can do the impossible.\r\rWhen I was nine years old living in a smaIl town in North Carolina I found an ad for selling greeting cards in the back of a children\'s magazine.I thought to myself I can do this.I begged my mother to let me send for the kit.Two weeks later when the kit arrived,I ripped off the brown paper wrapper,grabbed the cards and dashed from the house.Three hours later.I returned home with no card and a pocket full of money proclaiming,“Mama.all the people couldn\'t wait to buy my cards!”A salesperson was born.when I was twelve years old,my father took me to see Zig Ziegler.I remember sitting in that dark auditorium listening to Mr,Zigler raise everyone\'s spirits up to the ceiling,I left there feeling like I could do anything.When we got to the car,I turned to my father and said.“Dad.I want to make people feel like that.”My father asked me what I meant."I want to be a motivational speaker just like Mr.Zigler,“I replied.A dream was born.\r\rRecently,I began pursuing my dream of motivating others.After a four-year relationship with a major furtune 100company beginning as a salestrainer and ending as a regional sales manager,I left the company at the height of my career,Many people were astounded that I would leave after earning a six-figure income.And they asked why I would risk everything for a dream.\r\rI made my decision to start my own company and leave my secure position after attending a regional sales meeting.The vice-president of our company delivered a speech that changed my life.He asked us,“If a genie would grant you three wishes what would they be?”After giving us a moment to write down the three wishes.he then asked us,"why do you need a genie ?"I would never forget the empowerment I felt at that moment.\r\rI realized that everything I had accomplished一the graduate degree,the successful sales career,speaking engagements,training and managing for a fortune l00company had prepared me for this moment.I was ready and did not need a genie\'s help to become a motivational speaker.\r\rWhen I tearfully told my boss my plans this incredible leader whom Irespect so much replied,"Precede with reckless abandon and you will be successful“\r\rHaving made that decision,I was immediately tested.One week after I gave notice,my husband was“laid off from his job.We had recently bought a new home and needed both incomes to make the monthly mortgage payment and now we were done to no income.It was tempting to turn back to my former company,knowing they wanted me to stays but l was certain that if I went back,I would never leave.I decided I still wanted to move forward rather than end up with a mouth full of”if onlys"later on.A motivational speaker was born.\r\rWhen l held fast to my dream,even during the tough times.The miracles really began to happen.In a short time period my husband found a better job.We didn\'t miss a mortgage payment.And I was able to book several speaking engagements with new clients.I discovered the incredible power of dreams.I loved my old job,my peers and the company I left,but it was time to get on with my dream.To celebrate my success I had a local artist paint my new offlce as a garden.At the top of one wall she stenciled,“The world always makes way for the dreamer.\r\n”',
|
||||
textRuns: [
|
||||
{
|
||||
st: 0,
|
||||
ed: 11,
|
||||
ts: {
|
||||
bl: BooleanNumber.TRUE,
|
||||
fs: 24 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(0, 40, 86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 13,
|
||||
ed: 3318,
|
||||
ts: {
|
||||
fs: 14 * 0.75,
|
||||
ff: 'Times New Roman',
|
||||
cl: {
|
||||
rgb: 'rgb(0, 0, 0)',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
paragraphs: [
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_dreamer_1',
|
||||
startIndex: 11,
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 10 },
|
||||
lineSpacing: 2,
|
||||
spaceBelow: { v: 0 },
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_dreamer_2',
|
||||
startIndex: 12,
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 10 },
|
||||
lineSpacing: 2,
|
||||
spaceBelow: { v: 0 },
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_dreamer_3',
|
||||
startIndex: 100,
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 10 },
|
||||
lineSpacing: 2,
|
||||
spaceBelow: { v: 0 },
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_dreamer_4',
|
||||
startIndex: 101,
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 10 },
|
||||
lineSpacing: 2,
|
||||
spaceBelow: { v: 0 },
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_dreamer_5',
|
||||
startIndex: 1040,
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 10 },
|
||||
lineSpacing: 2,
|
||||
spaceBelow: { v: 0 },
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_dreamer_6',
|
||||
startIndex: 1041,
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 10 },
|
||||
lineSpacing: 2,
|
||||
spaceBelow: { v: 0 },
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_dreamer_7',
|
||||
startIndex: 1409,
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 10 },
|
||||
lineSpacing: 2,
|
||||
spaceBelow: { v: 0 },
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_dreamer_8',
|
||||
startIndex: 1410,
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 10 },
|
||||
lineSpacing: 2,
|
||||
spaceBelow: { v: 0 },
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_dreamer_9',
|
||||
startIndex: 1830,
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 10 },
|
||||
lineSpacing: 2,
|
||||
spaceBelow: { v: 0 },
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_dreamer_10',
|
||||
startIndex: 1831,
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 10 },
|
||||
lineSpacing: 2,
|
||||
spaceBelow: { v: 0 },
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_dreamer_11',
|
||||
startIndex: 2103,
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 10 },
|
||||
lineSpacing: 2,
|
||||
spaceBelow: { v: 0 },
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_dreamer_12',
|
||||
startIndex: 2104,
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 10 },
|
||||
lineSpacing: 2,
|
||||
spaceBelow: { v: 0 },
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_dreamer_13',
|
||||
startIndex: 2255,
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 10 },
|
||||
lineSpacing: 2,
|
||||
spaceBelow: { v: 0 },
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_dreamer_14',
|
||||
startIndex: 2256,
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 10 },
|
||||
lineSpacing: 2,
|
||||
spaceBelow: { v: 0 },
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_dreamer_15',
|
||||
startIndex: 2774,
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 10 },
|
||||
lineSpacing: 2,
|
||||
spaceBelow: { v: 0 },
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_dreamer_16',
|
||||
startIndex: 2775,
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 10 },
|
||||
lineSpacing: 2,
|
||||
spaceBelow: { v: 0 },
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_dreamer_17',
|
||||
startIndex: 3318,
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 10 },
|
||||
lineSpacing: 2,
|
||||
spaceBelow: { v: 0 },
|
||||
},
|
||||
},
|
||||
],
|
||||
sectionBreaks: [
|
||||
{
|
||||
sectionId: 'section_mockdata_default_document_dreamer_1',
|
||||
startIndex: 3319,
|
||||
columnProperties: [
|
||||
{
|
||||
width: ptToPixel(240),
|
||||
paddingEnd: ptToPixel(15),
|
||||
},
|
||||
],
|
||||
columnSeparatorType: ColumnSeparatorType.NONE,
|
||||
sectionType: SectionType.SECTION_TYPE_UNSPECIFIED,
|
||||
// textDirection: textDirectionDocument,
|
||||
// contentDirection: textDirection!,
|
||||
},
|
||||
],
|
||||
customBlocks: [
|
||||
{
|
||||
startIndex: 1243,
|
||||
blockId: 'shapeTest1',
|
||||
},
|
||||
],
|
||||
},
|
||||
documentStyle: {
|
||||
pageSize: {
|
||||
width: ptToPixel(595),
|
||||
height: ptToPixel(842),
|
||||
},
|
||||
documentFlavor: DocumentFlavor.TRADITIONAL,
|
||||
marginTop: ptToPixel(50),
|
||||
marginBottom: ptToPixel(50),
|
||||
marginRight: ptToPixel(50),
|
||||
marginLeft: ptToPixel(50),
|
||||
renderConfig: {
|
||||
vertexAngle: 0,
|
||||
centerAngle: 0,
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,403 +0,0 @@
|
||||
import type { IDocumentData } from '@univerjs/core';
|
||||
import {
|
||||
BooleanNumber,
|
||||
ColumnSeparatorType,
|
||||
DocumentFlavor,
|
||||
PresetListType,
|
||||
SectionType,
|
||||
} from '@univerjs/core';
|
||||
import { ptToPixel } from '@univerjs/engine-render';
|
||||
|
||||
export const DEFAULT_DOCUMENT_DATA_EN: IDocumentData = {
|
||||
id: 'd-en',
|
||||
drawings: {},
|
||||
drawingsOrder: [],
|
||||
body: {
|
||||
dataStream:
|
||||
'What’s New in the 2022 Gartner Hype Cycle for Emerging Technologies\rEmerging technologies for 2022 fit into three main themes: evolving/expanding immersive experiences, accelerated artificial intelligence automation, and OPTIMIZED technologist delivery.\rThe 2022 Gartner Hype Cycle identifies 25 must-know emerging technologies designed to help enterprise architecture and technology innovation leaders: \rExpand immersive experiences\rAccelerate artificial intelligence (AI) automation\rOptimize technologist delivery \rThese technologies are expected to greatly impact business and society over the next two to 10 years, but will especially enable CIOs and IT leaders to deliver on digital business transformation. \rThree Hype Cycle themes to think about in 2022 and beyond\rThe 2022 Gartner Hype Cycle features emerging technologies and distills insights from more than 2,000 technologies into a succinct high-potential set. Most technologies have multiple use cases but enterprise architecture and technology innovation leaders should prioritize those with the greatest potential benefit for their organization. (They will also need to launch a proof-of-concept project to demonstrate the feasibility of a technology for their target use case. )\r\nThe benefit of these technologies is that they provide individuals with more control over their identities and data, and expand their range of experiences into virtual venues and ecosystems that can be integrated with digital currencies. These technologies also provide new ways to reach customers to strengthen or open up new revenue streams.\rDigital twin of the customer (DToC) is a dynamic virtual representation of a customer that simulates and learns to emulate and anticipate behavior. It can be used to modify and enhance the customer experience (CX) and support new digitalization efforts, products, services and opportunities. DToC will take five to 10 years until mainstream adoption but will be transformational to organizations.\rOther critical technologies in immersive experiences include the following:\rDecentralized identity (DCI) allows an entity (typically a human user) to control their own digital identity by leveraging technologies such as blockchain or other distributed ledger technologies (DLTs), along with digital wallets.\rDigital humans are interactive, AI-driven representations that have some of the characteristics, personality, knowledge and mindset of a human.\rInternal talent marketplaces match internal employees and, in some cases, a pool of contingent workers, to time-boxed projects and various work opportunities, with no recruiter involvement.\r\n',
|
||||
textRuns: [
|
||||
{
|
||||
st: 0,
|
||||
ed: 67,
|
||||
ts: {
|
||||
bl: BooleanNumber.TRUE,
|
||||
fs: 24 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(0, 40, 86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 68,
|
||||
ed: 253,
|
||||
ts: {
|
||||
fs: 18 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(0, 40, 86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 254,
|
||||
ed: 404,
|
||||
ts: {
|
||||
fs: 16 * 0.75,
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 405,
|
||||
ed: 433,
|
||||
ts: {
|
||||
fs: 16 * 0.75,
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 434,
|
||||
ed: 484,
|
||||
ts: {
|
||||
fs: 16 * 0.75,
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 485,
|
||||
ed: 516,
|
||||
ts: {
|
||||
fs: 16 * 0.75,
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 517,
|
||||
ed: 679,
|
||||
ts: {
|
||||
fs: 16 * 0.75,
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 680,
|
||||
ed: 713,
|
||||
ts: {
|
||||
fs: 16 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(0, 0, 211)',
|
||||
},
|
||||
bl: BooleanNumber.TRUE,
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 714,
|
||||
ed: 771,
|
||||
ts: {
|
||||
fs: 24 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
bg: {
|
||||
rgb: 'rgb(0,40,86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 772,
|
||||
ed: 1244,
|
||||
ts: {
|
||||
fs: 16 * 0.75,
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 1246,
|
||||
ed: 1589,
|
||||
ts: {
|
||||
fs: 16 * 0.75,
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 1590,
|
||||
ed: 1986,
|
||||
ts: {
|
||||
fs: 16 * 0.75,
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 1987,
|
||||
ed: 2062,
|
||||
ts: {
|
||||
fs: 16 * 0.75,
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 2063,
|
||||
ed: 2086,
|
||||
ts: {
|
||||
fs: 16 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(0, 0, 211)',
|
||||
},
|
||||
bl: BooleanNumber.TRUE,
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 2086,
|
||||
ed: 2294,
|
||||
ts: {
|
||||
fs: 16 * 0.75,
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 2295,
|
||||
ed: 2310,
|
||||
ts: {
|
||||
fs: 16 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(0, 0, 211)',
|
||||
},
|
||||
bl: BooleanNumber.TRUE,
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 2310,
|
||||
ed: 2438,
|
||||
ts: {
|
||||
fs: 16 * 0.75,
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 2439,
|
||||
ed: 2468,
|
||||
ts: {
|
||||
fs: 16 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(0, 0, 0)',
|
||||
},
|
||||
bl: BooleanNumber.TRUE,
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 2468,
|
||||
ed: 2628,
|
||||
ts: {
|
||||
fs: 16 * 0.75,
|
||||
},
|
||||
},
|
||||
],
|
||||
paragraphs: [
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_en_1',
|
||||
startIndex: 67,
|
||||
},
|
||||
// Keep the English default demo aligned with the current docs default spacing.
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_en_2',
|
||||
startIndex: 253,
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 30 },
|
||||
lineSpacing: 1.5,
|
||||
suppressHyphenation: BooleanNumber.FALSE,
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_en_3',
|
||||
startIndex: 404,
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 20 },
|
||||
indentFirstLine: { v: 20 },
|
||||
lineSpacing: 1.5,
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_en_4',
|
||||
startIndex: 433,
|
||||
bullet: {
|
||||
listType: PresetListType.ORDER_LIST,
|
||||
listId: 'b',
|
||||
nestingLevel: 0,
|
||||
textStyle: {
|
||||
fs: 20,
|
||||
cl: {
|
||||
rgb: 'rgb(0, 255, 0)',
|
||||
},
|
||||
},
|
||||
},
|
||||
paragraphStyle: {
|
||||
lineSpacing: 1.5,
|
||||
spaceAbove: { v: 20 },
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_en_5',
|
||||
startIndex: 484,
|
||||
bullet: {
|
||||
listType: PresetListType.ORDER_LIST,
|
||||
listId: 'b',
|
||||
nestingLevel: 0,
|
||||
textStyle: {
|
||||
fs: 20,
|
||||
},
|
||||
},
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 10 },
|
||||
lineSpacing: 1.5,
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_en_6',
|
||||
startIndex: 516,
|
||||
bullet: {
|
||||
listType: PresetListType.ORDER_LIST,
|
||||
listId: 'b',
|
||||
nestingLevel: 0,
|
||||
textStyle: {
|
||||
fs: 20,
|
||||
},
|
||||
},
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 10 },
|
||||
lineSpacing: 1.5,
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_en_7',
|
||||
startIndex: 713,
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 20 },
|
||||
indentFirstLine: { v: 20 },
|
||||
lineSpacing: 1.5,
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_en_8',
|
||||
startIndex: 771,
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 20 },
|
||||
lineSpacing: 1.5,
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_en_9',
|
||||
startIndex: 1244,
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 20 },
|
||||
lineSpacing: 1.5,
|
||||
indentFirstLine: { v: 20 },
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_en_10',
|
||||
startIndex: 1589,
|
||||
paragraphStyle: {
|
||||
indentFirstLine: { v: 20 },
|
||||
lineSpacing: 1.5,
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_en_11',
|
||||
startIndex: 1986,
|
||||
paragraphStyle: {
|
||||
indentFirstLine: { v: 20 },
|
||||
lineSpacing: 1.5,
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_en_12',
|
||||
startIndex: 2062,
|
||||
paragraphStyle: {
|
||||
indentFirstLine: { v: 20 },
|
||||
lineSpacing: 1.5,
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_en_13',
|
||||
startIndex: 2294,
|
||||
paragraphStyle: {
|
||||
indentFirstLine: { v: 20 },
|
||||
lineSpacing: 1.5,
|
||||
},
|
||||
bullet: {
|
||||
listType: PresetListType.BULLET_LIST,
|
||||
listId: 'a',
|
||||
nestingLevel: 0,
|
||||
textStyle: {
|
||||
fs: 20,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_en_14',
|
||||
startIndex: 2438,
|
||||
paragraphStyle: {
|
||||
indentFirstLine: { v: 20 },
|
||||
lineSpacing: 1.5,
|
||||
},
|
||||
bullet: {
|
||||
listType: PresetListType.BULLET_LIST,
|
||||
listId: 'a',
|
||||
nestingLevel: 0,
|
||||
textStyle: {
|
||||
fs: 20,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_en_15',
|
||||
startIndex: 2628,
|
||||
paragraphStyle: {
|
||||
indentFirstLine: { v: 20 },
|
||||
lineSpacing: 1.5,
|
||||
},
|
||||
bullet: {
|
||||
listType: PresetListType.BULLET_LIST,
|
||||
listId: 'a',
|
||||
nestingLevel: 0,
|
||||
textStyle: {
|
||||
fs: 20,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
sectionBreaks: [
|
||||
{
|
||||
sectionId: 'section_mockdata_default_document_en_1',
|
||||
startIndex: 1245,
|
||||
// textDirection: textDirectionDocument,
|
||||
// contentDirection: textDirection!,
|
||||
},
|
||||
{
|
||||
sectionId: 'section_mockdata_default_document_en_2',
|
||||
startIndex: 2629,
|
||||
columnProperties: [
|
||||
{
|
||||
width: 300,
|
||||
paddingEnd: 5,
|
||||
},
|
||||
],
|
||||
columnSeparatorType: ColumnSeparatorType.NONE,
|
||||
sectionType: SectionType.SECTION_TYPE_UNSPECIFIED,
|
||||
// textDirection: textDirectionDocument,
|
||||
// contentDirection: textDirection!,
|
||||
},
|
||||
],
|
||||
customBlocks: [
|
||||
],
|
||||
},
|
||||
documentStyle: {
|
||||
pageSize: {
|
||||
width: ptToPixel(595),
|
||||
height: ptToPixel(842),
|
||||
},
|
||||
documentFlavor: DocumentFlavor.TRADITIONAL,
|
||||
marginTop: ptToPixel(50),
|
||||
marginBottom: ptToPixel(50),
|
||||
marginRight: ptToPixel(50),
|
||||
marginLeft: ptToPixel(50),
|
||||
renderConfig: {
|
||||
vertexAngle: 0,
|
||||
centerAngle: 0,
|
||||
},
|
||||
autoHyphenation: BooleanNumber.TRUE,
|
||||
doNotHyphenateCaps: BooleanNumber.FALSE,
|
||||
consecutiveHyphenLimit: 2,
|
||||
// hyphenationZone: 50,
|
||||
// gridType: GridType.LINES_AND_CHARS,
|
||||
// linePitch: 24,
|
||||
// charSpace: 12,
|
||||
},
|
||||
};
|
||||
@@ -1,203 +0,0 @@
|
||||
import type { IDocumentData } from '@univerjs/core';
|
||||
import {
|
||||
BaselineOffset,
|
||||
BooleanNumber,
|
||||
ColumnSeparatorType,
|
||||
DocumentFlavor,
|
||||
DrawingTypeEnum,
|
||||
ObjectRelativeFromH,
|
||||
ObjectRelativeFromV,
|
||||
PositionedObjectLayoutType,
|
||||
PresetListType,
|
||||
SectionType,
|
||||
WrapTextType,
|
||||
} from '@univerjs/core';
|
||||
|
||||
export const DEFAULT_DOCUMENT_DATA: IDocumentData = {
|
||||
id: 'd',
|
||||
drawings: {
|
||||
shapeTest1: {
|
||||
unitId: 'd',
|
||||
subUnitId: 'd',
|
||||
drawingType: DrawingTypeEnum.DRAWING_SHAPE,
|
||||
drawingId: 'shapeTest1',
|
||||
title: 'test shape',
|
||||
description: 'test shape',
|
||||
docTransform: {
|
||||
size: {
|
||||
width: 100,
|
||||
height: 400,
|
||||
},
|
||||
positionH: {
|
||||
relativeFrom: ObjectRelativeFromH.COLUMN,
|
||||
posOffset: 100,
|
||||
},
|
||||
positionV: {
|
||||
relativeFrom: ObjectRelativeFromV.PARAGRAPH,
|
||||
posOffset: 160,
|
||||
},
|
||||
angle: 0,
|
||||
// imageProperties: {
|
||||
// contentUrl: 'https://cnbabylon.com/assets/img/agents.png',
|
||||
// },
|
||||
},
|
||||
layoutType: PositionedObjectLayoutType.WRAP_SQUARE,
|
||||
behindDoc: BooleanNumber.FALSE,
|
||||
wrapText: WrapTextType.BOTH_SIDES,
|
||||
},
|
||||
},
|
||||
body: {
|
||||
dataStream: '在“第1题”工作表中完成以下操作\b上标日期列单元格数据验证,限制只能输入日期(介于1949年1月1日至2099年1月1日)\r细化埋点上报链路和指标方案梳理目前通过每日定时任务发送报告\r自2018年首届进博会举办以来,进博会已经成为全球新品的首发地、前沿技术的首选地、创新服务的首推地。中国这十年”对外开放成就展湖北展区主要以图文、图表、数据、视频、企业展品、实物模型、光电科技等体现湖北十年开放成就、重大开放平台及产业。湖北省共计17家企业、机构的展品将在这一展区展示\r国家主席习近平以视频方式出席在上海举行的第五届中国国际进口博览会开幕式并发表题为《共创开放繁荣的美好未来》的致辞中国将推动各国各方共享深化国际合作机遇,全面深入参与世界贸易组织改革谈判\r中国男排两名现役国手彭世坤和张秉龙分别效力的三得利太阳鸟和东京大熊本轮遭遇。双方经过激战,主场作战的卫冕冠军三得利技高一筹3-2逆转击败对手,力夺第3场胜利\r\n',
|
||||
textRuns: [
|
||||
{
|
||||
st: 0,
|
||||
ed: 15,
|
||||
ts: {
|
||||
fs: 12,
|
||||
bg: {
|
||||
rgb: 'rgb(200,0,90)',
|
||||
},
|
||||
cl: {
|
||||
rgb: 'rgb(255,130,0)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 17,
|
||||
ed: 18,
|
||||
ts: {
|
||||
fs: 14,
|
||||
bg: {
|
||||
rgb: 'rgb(2,128,2)',
|
||||
},
|
||||
cl: {
|
||||
rgb: 'rgb(0,1,55)',
|
||||
},
|
||||
va: BaselineOffset.SUPERSCRIPT,
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 19,
|
||||
ed: 60,
|
||||
ts: {
|
||||
fs: 14,
|
||||
bg: {
|
||||
rgb: 'rgb(90,128,255)',
|
||||
},
|
||||
cl: {
|
||||
rgb: 'rgb(0,1,255)',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
st: 62,
|
||||
ed: 90,
|
||||
},
|
||||
|
||||
{
|
||||
st: 92,
|
||||
ed: 233,
|
||||
},
|
||||
|
||||
{
|
||||
st: 235,
|
||||
ed: 326,
|
||||
},
|
||||
|
||||
{
|
||||
st: 328,
|
||||
ed: 405,
|
||||
},
|
||||
],
|
||||
paragraphs: [
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_1',
|
||||
startIndex: 60,
|
||||
bullet: {
|
||||
listType: PresetListType.ORDER_LIST,
|
||||
listId: 'a',
|
||||
nestingLevel: 0,
|
||||
textStyle: {
|
||||
fs: 20,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_2',
|
||||
startIndex: 91,
|
||||
bullet: {
|
||||
listType: PresetListType.ORDER_LIST,
|
||||
listId: 'a',
|
||||
nestingLevel: 1,
|
||||
textStyle: {
|
||||
fs: 20,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_3',
|
||||
startIndex: 234,
|
||||
bullet: {
|
||||
listType: PresetListType.ORDER_LIST,
|
||||
listId: 'a',
|
||||
nestingLevel: 1,
|
||||
textStyle: {
|
||||
fs: 20,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_4',
|
||||
startIndex: 327,
|
||||
bullet: {
|
||||
listType: PresetListType.ORDER_LIST,
|
||||
listId: 'a',
|
||||
nestingLevel: 1,
|
||||
textStyle: {
|
||||
fs: 20,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_docs_default_document_data_5',
|
||||
startIndex: 406,
|
||||
bullet: {
|
||||
listType: PresetListType.ORDER_LIST,
|
||||
listId: 'a',
|
||||
nestingLevel: 2,
|
||||
textStyle: {
|
||||
fs: 20,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
sectionBreaks: [
|
||||
{
|
||||
sectionId: 'section_mockdata_default_document_1',
|
||||
startIndex: 407,
|
||||
columnProperties: [
|
||||
{
|
||||
width: 200,
|
||||
paddingEnd: 20,
|
||||
},
|
||||
],
|
||||
columnSeparatorType: ColumnSeparatorType.NONE,
|
||||
sectionType: SectionType.SECTION_TYPE_UNSPECIFIED,
|
||||
// textDirection: textDirectionDocument,
|
||||
// contentDirection: textDirection!,
|
||||
},
|
||||
],
|
||||
},
|
||||
documentStyle: {
|
||||
pageSize: {
|
||||
width: 594.3,
|
||||
height: 840.51,
|
||||
},
|
||||
documentFlavor: DocumentFlavor.TRADITIONAL,
|
||||
marginTop: 72,
|
||||
marginBottom: 72,
|
||||
marginRight: 90,
|
||||
marginLeft: 90,
|
||||
},
|
||||
};
|
||||
@@ -1,347 +0,0 @@
|
||||
import type { IDocumentData, IParagraph, ISectionBreak, ITable, ITableCell, ITableColumn, ITableRow } from '@univerjs/core';
|
||||
import { BooleanNumber, createParagraphId, createSectionId, DocumentFlavor, HorizontalAlign, ObjectRelativeFromH, ObjectRelativeFromV, TableAlignmentType, TableRowHeightRule, TableSizeType, TableTextWrapType, Tools, VerticalAlignmentType } from '@univerjs/core';
|
||||
import { ptToPixel } from '@univerjs/engine-render';
|
||||
|
||||
const TABLE_START = '\x1A'; // 表格开始
|
||||
const TABLE_ROW_START = '\x1B'; // 表格行开始
|
||||
const TABLE_CELL_START = '\x1C'; // 表格单元格开始
|
||||
const TABLE_CELL_END = '\x1D'; // 表格单元格结束
|
||||
const TABLE_ROW_END = '\x0E'; // 表格行结束
|
||||
const TABLE_END = '\x0F'; // 表格结束
|
||||
|
||||
function createTableDataStream(tables: string[][]) {
|
||||
const row = tables.length;
|
||||
const col = tables[0].length;
|
||||
let dataStream = TABLE_START;
|
||||
|
||||
for (let i = 0; i < row; i++) {
|
||||
dataStream += TABLE_ROW_START;
|
||||
for (let j = 0; j < col; j++) {
|
||||
dataStream += `${TABLE_CELL_START + tables[i][j]}\r\n${TABLE_CELL_END}`;
|
||||
}
|
||||
dataStream += TABLE_ROW_END;
|
||||
}
|
||||
|
||||
return dataStream + TABLE_END;
|
||||
}
|
||||
|
||||
const exampleTables = [
|
||||
['Description', 'Date', 'Location'],
|
||||
['Academic Senate Meeting 1 Academic Senate Meeting 2 Academic Senate Meeting 3 Academic Senate Meeting 4 Academic Senate Meeting 5', 'May 25, 2205', 'Building 99 Room 1'],
|
||||
['Faculty Council', 'June 1, 2205', 'Building 35 Room 5'],
|
||||
['Faculty Council', 'June 15, 2205', 'Building 35 Room 5'],
|
||||
['Faculty Council', 'June 30, 2205', 'Building 35 Room 5'],
|
||||
['Commencement Meeting', 'December 15, 2205', 'Building 42 Room 10'],
|
||||
['Dean\'s Council', 'February 1, 2206', 'Building 35 Room 5'],
|
||||
['Faculty Council', 'March 1, 2206', 'Building 35 Room 5'],
|
||||
];
|
||||
|
||||
const title = 'Examples of Accessible Data Tables\r';
|
||||
const description = 'Basic Data Table with Column Headings\r';
|
||||
const underline = ['dash', 'dash dot dot heavy', 'dashed dot heavy', 'dashed heavy', 'dash long', 'dash long heavy', 'dot dash', 'dot dot dash', 'dotted', 'dotted heavy', 'double', 'none', 'single', 'thick', 'wave', 'wavy double', 'wavy heavy\r'];
|
||||
const summary = 'These example tables contain captions and summaries. When you copy any of these tables into your page you must edit the caption and summary. The caption can be edited in the Design view but the summary text must be edited in Code view. Click inside the table, then select the table tag on the tag selector, then switch to Code view and edit the text in the summary attribute.\r';
|
||||
const tableStream = createTableDataStream(exampleTables);
|
||||
|
||||
const dataStream = `${title}${description}${underline.join(', ')}${tableStream}${summary}\n`;
|
||||
|
||||
const startIndex = dataStream.indexOf(TABLE_START);
|
||||
const endIndex = tableStream.length + startIndex;
|
||||
|
||||
function createParagraphAndSectionBreaks(dataStream: string) {
|
||||
const paragraphs: IParagraph[] = [];
|
||||
const sectionBreaks: ISectionBreak[] = [];
|
||||
const existingParagraphIds = new Set<string>();
|
||||
const existingSectionIds = new Set<string>();
|
||||
for (let i = 0; i < dataStream.length; i++) {
|
||||
const char = dataStream[i];
|
||||
if (char === '\r') {
|
||||
paragraphs.push({
|
||||
startIndex: i,
|
||||
paragraphId: createParagraphId(existingParagraphIds),
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 5 },
|
||||
lineSpacing: 2,
|
||||
spaceBelow: { v: 0 },
|
||||
horizontalAlign: HorizontalAlign.LEFT,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (char === '\n') {
|
||||
sectionBreaks.push({
|
||||
sectionId: createSectionId(existingSectionIds),
|
||||
startIndex: i,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return { paragraphs, sectionBreaks };
|
||||
}
|
||||
|
||||
function createTextRuns() {
|
||||
const textRuns = [];
|
||||
let offset = 0;
|
||||
|
||||
textRuns.push({
|
||||
st: offset,
|
||||
ed: offset + title.length,
|
||||
ts: {
|
||||
fs: 16,
|
||||
ff: 'Helvetica Neue',
|
||||
cl: {
|
||||
rgb: '#154734',
|
||||
},
|
||||
bl: BooleanNumber.TRUE,
|
||||
ul: {
|
||||
s: BooleanNumber.TRUE,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
offset += title.length;
|
||||
|
||||
textRuns.push({
|
||||
st: offset,
|
||||
ed: offset + description.length,
|
||||
ts: {
|
||||
fs: 12,
|
||||
ff: 'Helvetica Neue',
|
||||
cl: {
|
||||
rgb: '#54585a',
|
||||
},
|
||||
bl: BooleanNumber.FALSE,
|
||||
},
|
||||
});
|
||||
|
||||
offset += description.length;
|
||||
|
||||
for (let i = 0; i < underline.length; i++) {
|
||||
textRuns.push({
|
||||
st: offset,
|
||||
ed: offset + underline[i].length,
|
||||
ts: {
|
||||
fs: 12,
|
||||
ff: 'Helvetica Neue',
|
||||
cl: {
|
||||
rgb: '#54585a',
|
||||
},
|
||||
ul: {
|
||||
s: 1,
|
||||
t: i,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
offset += underline[i].length + 2;
|
||||
}
|
||||
|
||||
textRuns.push({
|
||||
st: offset,
|
||||
ed: offset + tableStream.length,
|
||||
ts: {
|
||||
fs: 11,
|
||||
ff: 'Helvetica Neue',
|
||||
cl: {
|
||||
rgb: '#54585a',
|
||||
},
|
||||
bl: BooleanNumber.TRUE,
|
||||
},
|
||||
});
|
||||
|
||||
offset += tableStream.length;
|
||||
|
||||
textRuns.push({
|
||||
st: offset,
|
||||
ed: offset + summary.length,
|
||||
ts: {
|
||||
fs: 12,
|
||||
ff: 'Helvetica Neue',
|
||||
cl: {
|
||||
rgb: '#54585a',
|
||||
},
|
||||
bl: BooleanNumber.FALSE,
|
||||
},
|
||||
});
|
||||
|
||||
return textRuns;
|
||||
}
|
||||
|
||||
const { paragraphs, sectionBreaks } = createParagraphAndSectionBreaks(dataStream);
|
||||
|
||||
const tableCell: ITableCell = {
|
||||
rowSpan: 1,
|
||||
columnSpan: 1,
|
||||
vAlign: VerticalAlignmentType.TOP,
|
||||
margin: {
|
||||
start: {
|
||||
v: 10,
|
||||
},
|
||||
end: {
|
||||
v: 10,
|
||||
},
|
||||
top: {
|
||||
v: 5,
|
||||
},
|
||||
bottom: {
|
||||
v: 5,
|
||||
},
|
||||
},
|
||||
borderTop: {
|
||||
color: {
|
||||
rgb: '#dee0e3',
|
||||
},
|
||||
},
|
||||
borderBottom: {
|
||||
color: {
|
||||
rgb: '#dee0e3',
|
||||
},
|
||||
},
|
||||
borderLeft: {
|
||||
color: {
|
||||
rgb: '#dee0e3',
|
||||
},
|
||||
},
|
||||
borderRight: {
|
||||
color: {
|
||||
rgb: '#dee0e3',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const tableRow: ITableRow = {
|
||||
tableCells: [...new Array(exampleTables[0].length).fill(Tools.deepClone(tableCell))],
|
||||
trHeight: {
|
||||
val: { v: 50 },
|
||||
hRule: TableRowHeightRule.AUTO,
|
||||
},
|
||||
cantSplit: BooleanNumber.TRUE,
|
||||
};
|
||||
|
||||
const tableColumn: ITableColumn = {
|
||||
size: {
|
||||
type: TableSizeType.SPECIFIED,
|
||||
width: {
|
||||
v: 100,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const tableRows: ITableRow[] = [...new Array(exampleTables.length).fill(null).map((_, i) => {
|
||||
const row = Tools.deepClone(tableRow);
|
||||
const isFirstRow = i === 0 ? BooleanNumber.TRUE : BooleanNumber.FALSE;
|
||||
|
||||
if (isFirstRow === BooleanNumber.TRUE) {
|
||||
row.tableCells.forEach((cell) => {
|
||||
cell.backgroundColor = {
|
||||
rgb: 'rgba(245, 246, 247, 0.9)',
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
...row,
|
||||
isFirstRow,
|
||||
repeatHeaderRow: isFirstRow,
|
||||
};
|
||||
})];
|
||||
const tableColumns = [...new Array(exampleTables[0].length).fill(null).map(() => Tools.deepClone(tableColumn))];
|
||||
|
||||
tableColumns[0].size.width.v = 250;
|
||||
|
||||
const table: ITable = {
|
||||
tableRows,
|
||||
tableColumns,
|
||||
tableId: 'table-id',
|
||||
align: TableAlignmentType.START,
|
||||
indent: {
|
||||
v: 0,
|
||||
},
|
||||
textWrap: TableTextWrapType.WRAP,
|
||||
position: {
|
||||
positionH: {
|
||||
relativeFrom: ObjectRelativeFromH.PAGE,
|
||||
posOffset: 100,
|
||||
},
|
||||
positionV: {
|
||||
relativeFrom: ObjectRelativeFromV.PAGE,
|
||||
posOffset: 600,
|
||||
},
|
||||
},
|
||||
dist: {
|
||||
distB: 5,
|
||||
distL: 5,
|
||||
distR: 10,
|
||||
distT: 5,
|
||||
},
|
||||
cellMargin: {
|
||||
start: {
|
||||
v: 10,
|
||||
},
|
||||
end: {
|
||||
v: 10,
|
||||
},
|
||||
top: {
|
||||
v: 5,
|
||||
},
|
||||
bottom: {
|
||||
v: 5,
|
||||
},
|
||||
},
|
||||
size: {
|
||||
type: TableSizeType.UNSPECIFIED,
|
||||
width: {
|
||||
v: 1000,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const DEFAULT_DOCUMENT_DATA_SIMPLE: IDocumentData = {
|
||||
id: 'default-document-id',
|
||||
tableSource: {
|
||||
'table-id': table,
|
||||
},
|
||||
headers: {},
|
||||
footers: {},
|
||||
drawings: {},
|
||||
drawingsOrder: [],
|
||||
body: {
|
||||
dataStream,
|
||||
customBlocks: [],
|
||||
textRuns: createTextRuns(),
|
||||
paragraphs,
|
||||
tables: [{
|
||||
startIndex,
|
||||
endIndex,
|
||||
tableId: 'table-id',
|
||||
}],
|
||||
sectionBreaks,
|
||||
},
|
||||
documentStyle: {
|
||||
pageSize: {
|
||||
width: ptToPixel(595),
|
||||
height: ptToPixel(842),
|
||||
},
|
||||
documentFlavor: DocumentFlavor.TRADITIONAL,
|
||||
marginTop: ptToPixel(50),
|
||||
marginBottom: ptToPixel(50),
|
||||
marginRight: ptToPixel(50),
|
||||
marginLeft: ptToPixel(50),
|
||||
autoHyphenation: BooleanNumber.TRUE,
|
||||
consecutiveHyphenLimit: 3,
|
||||
doNotHyphenateCaps: BooleanNumber.TRUE,
|
||||
renderConfig: {
|
||||
vertexAngle: 0,
|
||||
centerAngle: 0,
|
||||
},
|
||||
defaultHeaderId: '',
|
||||
defaultFooterId: '',
|
||||
evenPageHeaderId: '',
|
||||
evenPageFooterId: '',
|
||||
firstPageHeaderId: '',
|
||||
firstPageFooterId: '',
|
||||
evenAndOddHeaders: BooleanNumber.FALSE,
|
||||
useFirstPageHeaderFooter: BooleanNumber.FALSE,
|
||||
marginHeader: 30,
|
||||
marginFooter: 30,
|
||||
},
|
||||
};
|
||||
@@ -1,4 +0,0 @@
|
||||
export * from './default-document-data';
|
||||
export * from './default-document-data-cn';
|
||||
export * from './default-document-data-en';
|
||||
export * from './default-document.data-simple';
|
||||
@@ -1,50 +0,0 @@
|
||||
import type { ILanguagePack, LocaleType } from '@univerjs/core';
|
||||
|
||||
export * from './docs';
|
||||
export * from './sheets';
|
||||
export * from './slides';
|
||||
|
||||
export async function loadDebuggerLocale(locale: LocaleType): Promise<ILanguagePack> {
|
||||
switch (locale) {
|
||||
case 'arSA':
|
||||
return (await import('./locales/ar-SA')).default;
|
||||
case 'caES':
|
||||
return (await import('./locales/ca-ES')).default;
|
||||
case 'deDE':
|
||||
return (await import('./locales/de-DE')).default;
|
||||
case 'enUS':
|
||||
return (await import('./locales/en-US')).default;
|
||||
case 'esES':
|
||||
return (await import('./locales/es-ES')).default;
|
||||
case 'faIR':
|
||||
return (await import('./locales/fa-IR')).default;
|
||||
case 'frFR':
|
||||
return (await import('./locales/fr-FR')).default;
|
||||
case 'idID':
|
||||
return (await import('./locales/id-ID')).default;
|
||||
case 'itIT':
|
||||
return (await import('./locales/it-IT')).default;
|
||||
case 'jaJP':
|
||||
return (await import('./locales/ja-JP')).default;
|
||||
case 'koKR':
|
||||
return (await import('./locales/ko-KR')).default;
|
||||
case 'plPL':
|
||||
return (await import('./locales/pl-PL')).default;
|
||||
case 'ptBR':
|
||||
return (await import('./locales/pt-BR')).default;
|
||||
case 'ruRU':
|
||||
return (await import('./locales/ru-RU')).default;
|
||||
case 'skSK':
|
||||
return (await import('./locales/sk-SK')).default;
|
||||
case 'viVN':
|
||||
return (await import('./locales/vi-VN')).default;
|
||||
case 'zhCN':
|
||||
return (await import('./locales/zh-CN')).default;
|
||||
case 'zhHK':
|
||||
return (await import('./locales/zh-HK')).default;
|
||||
case 'zhTW':
|
||||
return (await import('./locales/zh-TW')).default;
|
||||
default:
|
||||
return (await import('./locales/en-US')).default;
|
||||
}
|
||||
}
|
||||
@@ -1,941 +0,0 @@
|
||||
import type { IDocumentData, IWorkbookData } from '@univerjs/core';
|
||||
import {
|
||||
BaselineOffset,
|
||||
BooleanNumber,
|
||||
BorderStyleTypes,
|
||||
ColumnSeparatorType,
|
||||
DrawingTypeEnum,
|
||||
HorizontalAlign,
|
||||
LocaleType,
|
||||
ObjectRelativeFromH,
|
||||
ObjectRelativeFromV,
|
||||
PositionedObjectLayoutType,
|
||||
PresetListType,
|
||||
SectionType,
|
||||
Tools,
|
||||
VerticalAlign,
|
||||
WrapStrategy,
|
||||
WrapTextType,
|
||||
} from '@univerjs/core';
|
||||
|
||||
const richTextTestFloat: IDocumentData = {
|
||||
id: 'd',
|
||||
drawings: {
|
||||
shapeTest1: {
|
||||
unitId: 'd',
|
||||
subUnitId: 'd',
|
||||
drawingType: DrawingTypeEnum.DRAWING_SHAPE,
|
||||
drawingId: 'shapeTest1',
|
||||
title: 'test shape',
|
||||
description: 'test shape',
|
||||
docTransform: {
|
||||
size: {
|
||||
width: 100,
|
||||
height: 400,
|
||||
},
|
||||
positionH: {
|
||||
relativeFrom: ObjectRelativeFromH.COLUMN,
|
||||
posOffset: 100,
|
||||
},
|
||||
positionV: {
|
||||
relativeFrom: ObjectRelativeFromV.PARAGRAPH,
|
||||
posOffset: 160,
|
||||
},
|
||||
angle: 0,
|
||||
// imageProperties: {
|
||||
// contentUrl: 'https://cnbabylon.com/assets/img/agents.png',
|
||||
// },
|
||||
},
|
||||
layoutType: PositionedObjectLayoutType.WRAP_SQUARE,
|
||||
behindDoc: BooleanNumber.FALSE,
|
||||
wrapText: WrapTextType.BOTH_SIDES,
|
||||
},
|
||||
},
|
||||
body: {
|
||||
dataStream: '在“第1题”工作表中完成以下操作\b上标日期列单元格数据验证,限制只能输入日期(介于1949年1月1日至2099年1月1日)\r\n',
|
||||
textRuns: [
|
||||
{
|
||||
st: 0,
|
||||
ed: 15,
|
||||
ts: {
|
||||
fs: 12,
|
||||
bg: {
|
||||
rgb: 'rgb(200,0,90)',
|
||||
},
|
||||
cl: {
|
||||
rgb: 'rgb(255,130,0)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 17,
|
||||
ed: 18,
|
||||
ts: {
|
||||
fs: 14,
|
||||
bg: {
|
||||
rgb: 'rgb(2,128,2)',
|
||||
},
|
||||
cl: {
|
||||
rgb: 'rgb(0,1,55)',
|
||||
},
|
||||
va: BaselineOffset.SUPERSCRIPT,
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 19,
|
||||
ed: 60,
|
||||
ts: {
|
||||
fs: 14,
|
||||
bg: {
|
||||
rgb: 'rgb(90,128,255)',
|
||||
},
|
||||
cl: {
|
||||
rgb: 'rgb(0,1,255)',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
paragraphs: [
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_sheets_default_workbook_data_1',
|
||||
startIndex: 60,
|
||||
bullet: {
|
||||
listId: 'orderList',
|
||||
listType: PresetListType.ORDER_LIST,
|
||||
nestingLevel: 0,
|
||||
textStyle: {
|
||||
fs: 20,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
sectionBreaks: [
|
||||
{
|
||||
sectionId: 'section_mockdata_default_workbook_1',
|
||||
startIndex: 61,
|
||||
columnProperties: [
|
||||
{
|
||||
width: 200,
|
||||
paddingEnd: 20,
|
||||
},
|
||||
],
|
||||
columnSeparatorType: ColumnSeparatorType.NONE,
|
||||
sectionType: SectionType.SECTION_TYPE_UNSPECIFIED,
|
||||
// textDirection: textDirectionDocument,
|
||||
// contentDirection: textDirection!,
|
||||
},
|
||||
],
|
||||
},
|
||||
documentStyle: {
|
||||
pageSize: {
|
||||
width: Number.POSITIVE_INFINITY,
|
||||
height: Number.POSITIVE_INFINITY,
|
||||
},
|
||||
marginTop: 0,
|
||||
marginBottom: 0,
|
||||
marginRight: 2,
|
||||
marginLeft: 2,
|
||||
},
|
||||
};
|
||||
|
||||
const richTextTest: IDocumentData = {
|
||||
id: 'd',
|
||||
body: {
|
||||
dataStream: '在“第1题”工作表中完成以下操作\b上标日期列单元格数据验证,限制只能输入日期(介于1949年1月1日至2099年1月1日)\r\n',
|
||||
textRuns: [
|
||||
{
|
||||
st: 0,
|
||||
ed: 15,
|
||||
ts: {
|
||||
fs: 12,
|
||||
bg: {
|
||||
rgb: 'rgb(200,0,90)',
|
||||
},
|
||||
cl: {
|
||||
rgb: 'rgb(255,130,0)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 17,
|
||||
ed: 18,
|
||||
ts: {
|
||||
fs: 14,
|
||||
bg: {
|
||||
rgb: 'rgb(2,128,2)',
|
||||
},
|
||||
cl: {
|
||||
rgb: 'rgb(0,1,55)',
|
||||
},
|
||||
va: BaselineOffset.SUPERSCRIPT,
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 19,
|
||||
ed: 60,
|
||||
ts: {
|
||||
fs: 14,
|
||||
bg: {
|
||||
rgb: 'rgb(90,128,255)',
|
||||
},
|
||||
cl: {
|
||||
rgb: 'rgb(0,1,255)',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
paragraphs: [
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_sheets_default_workbook_data_2',
|
||||
startIndex: 60,
|
||||
bullet: {
|
||||
listId: 'orderList',
|
||||
listType: PresetListType.ORDER_LIST,
|
||||
nestingLevel: 0,
|
||||
textStyle: {
|
||||
fs: 20,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
sectionBreaks: [
|
||||
{
|
||||
sectionId: 'section_mockdata_default_workbook_2',
|
||||
startIndex: 61,
|
||||
columnProperties: [
|
||||
{
|
||||
width: 200,
|
||||
paddingEnd: 20,
|
||||
},
|
||||
],
|
||||
columnSeparatorType: ColumnSeparatorType.NONE,
|
||||
sectionType: SectionType.SECTION_TYPE_UNSPECIFIED,
|
||||
// textDirection: textDirectionDocument,
|
||||
// contentDirection: textDirection!,
|
||||
},
|
||||
],
|
||||
},
|
||||
documentStyle: {
|
||||
pageSize: {
|
||||
width: Number.POSITIVE_INFINITY,
|
||||
height: Number.POSITIVE_INFINITY,
|
||||
},
|
||||
marginTop: 0,
|
||||
marginBottom: 0,
|
||||
marginRight: 2,
|
||||
marginLeft: 2,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Default workbook data
|
||||
*/
|
||||
export const DEFAULT_WORKBOOK_DATA: IWorkbookData = {
|
||||
id: 'workbook-left',
|
||||
locale: LocaleType.ZH_CN,
|
||||
name: 'universheet',
|
||||
sheetOrder: ['sheet-01', 'sheet-02', 'sheet-03', 'sheet-04', 'sheet-05', 'sheet-06'],
|
||||
styles: {
|
||||
1: {
|
||||
cl: {
|
||||
rgb: 'blue',
|
||||
},
|
||||
fs: 16,
|
||||
bd: {
|
||||
t: {
|
||||
s: BorderStyleTypes.MEDIUM_DASHED,
|
||||
cl: {
|
||||
rgb: 'black',
|
||||
},
|
||||
},
|
||||
l: {
|
||||
s: BorderStyleTypes.MEDIUM_DASHED,
|
||||
cl: {
|
||||
rgb: 'black',
|
||||
},
|
||||
},
|
||||
r: {
|
||||
s: BorderStyleTypes.THICK,
|
||||
cl: {
|
||||
rgb: 'black',
|
||||
},
|
||||
},
|
||||
b: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'red',
|
||||
},
|
||||
},
|
||||
},
|
||||
ht: 3,
|
||||
},
|
||||
2: {
|
||||
bg: {
|
||||
rgb: 'rgb(200, 2, 0)',
|
||||
},
|
||||
fs: 24,
|
||||
ht: HorizontalAlign.RIGHT,
|
||||
vt: VerticalAlign.TOP,
|
||||
},
|
||||
3: {
|
||||
ht: HorizontalAlign.RIGHT,
|
||||
vt: VerticalAlign.MIDDLE,
|
||||
tb: WrapStrategy.WRAP,
|
||||
// va: BaselineOffset.SUPERSCRIPT,
|
||||
// cl: {
|
||||
// rgb: 'rgb(0, 255, 0)',
|
||||
// },
|
||||
// st: {
|
||||
// s: BooleanNumber.TRUE, // show
|
||||
// },
|
||||
bg: {
|
||||
rgb: 'rgb(255, 255, 0)',
|
||||
},
|
||||
tr: {
|
||||
a: 45,
|
||||
v: BooleanNumber.FALSE,
|
||||
},
|
||||
bd: {
|
||||
t: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'black',
|
||||
},
|
||||
},
|
||||
l: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'black',
|
||||
},
|
||||
},
|
||||
r: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'black',
|
||||
},
|
||||
},
|
||||
b: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'red',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
4: {
|
||||
bg: {
|
||||
rgb: 'rgb(0, 0, 255)',
|
||||
},
|
||||
},
|
||||
5: {
|
||||
tb: WrapStrategy.WRAP,
|
||||
},
|
||||
},
|
||||
appVersion: '3.0.0-alpha',
|
||||
sheets: {
|
||||
'sheet-01': {
|
||||
id: 'sheet-01',
|
||||
cellData: {
|
||||
0: {
|
||||
0: {
|
||||
s: '1',
|
||||
v: 1,
|
||||
},
|
||||
1: {
|
||||
s: '1',
|
||||
v: 1,
|
||||
},
|
||||
5: {
|
||||
s: '1',
|
||||
v: 8,
|
||||
},
|
||||
6: {
|
||||
s: '2',
|
||||
v: 8,
|
||||
},
|
||||
},
|
||||
1: {
|
||||
0: {
|
||||
v: 1,
|
||||
},
|
||||
1: {
|
||||
v: 1,
|
||||
},
|
||||
2: {
|
||||
v: 80,
|
||||
s: '3',
|
||||
},
|
||||
3: {
|
||||
v: '富文本编辑',
|
||||
s: '2',
|
||||
},
|
||||
},
|
||||
2: {
|
||||
0: {
|
||||
v: 1111,
|
||||
},
|
||||
1: {
|
||||
v: 1111,
|
||||
},
|
||||
5: {
|
||||
s: '1',
|
||||
v: 8,
|
||||
},
|
||||
6: {
|
||||
s: '1',
|
||||
v: 8,
|
||||
},
|
||||
7: {
|
||||
s: '1',
|
||||
v: 8,
|
||||
},
|
||||
8: {
|
||||
s: '1',
|
||||
v: 8,
|
||||
},
|
||||
},
|
||||
3: {
|
||||
0: {
|
||||
v: 1111,
|
||||
},
|
||||
1: {
|
||||
v: 1111,
|
||||
},
|
||||
},
|
||||
10: {
|
||||
9: {
|
||||
v: 1111,
|
||||
s: '2',
|
||||
},
|
||||
},
|
||||
13: {
|
||||
9: {
|
||||
v: 1111,
|
||||
s: '4',
|
||||
},
|
||||
},
|
||||
17: {
|
||||
3: {
|
||||
v: '做移动端开发和前端开发的人员,对 MVC、MVP、MVVM 这几个名词应该都不陌生,这是三个最常用的应用架构模式,目的都是为了将业务和视图的实现代码分离',
|
||||
s: '3',
|
||||
p: richTextTest,
|
||||
},
|
||||
},
|
||||
20: {
|
||||
10: {
|
||||
v: '北京马拉松组委会办公室一位接电话的女士证实,的确有这项规定,她还称2014年马拉松的预登记工作将在本周启动。北京马拉松比赛将在10月19日举行。',
|
||||
s: '3',
|
||||
},
|
||||
12: {
|
||||
s: '4',
|
||||
},
|
||||
},
|
||||
29: {
|
||||
13: {
|
||||
p: Tools.deepClone(richTextTest),
|
||||
s: '4',
|
||||
},
|
||||
},
|
||||
32: {
|
||||
3: {
|
||||
p: richTextTestFloat,
|
||||
s: '5',
|
||||
},
|
||||
},
|
||||
},
|
||||
name: 'sheet1',
|
||||
tabColor: 'red',
|
||||
hidden: BooleanNumber.FALSE,
|
||||
rowCount: 1000,
|
||||
columnCount: 20,
|
||||
zoomRatio: 1,
|
||||
scrollTop: 200,
|
||||
scrollLeft: 100,
|
||||
defaultColumnWidth: 93,
|
||||
defaultRowHeight: 27,
|
||||
mergeData: [
|
||||
{
|
||||
startRow: 0,
|
||||
endRow: 1,
|
||||
startColumn: 0,
|
||||
endColumn: 1,
|
||||
},
|
||||
{
|
||||
startRow: 2,
|
||||
endRow: 6,
|
||||
startColumn: 5,
|
||||
endColumn: 10,
|
||||
},
|
||||
{
|
||||
startRow: 10,
|
||||
endRow: 12,
|
||||
startColumn: 9,
|
||||
endColumn: 12,
|
||||
},
|
||||
{
|
||||
startRow: 10,
|
||||
endRow: 12,
|
||||
startColumn: 9,
|
||||
endColumn: 12,
|
||||
},
|
||||
{
|
||||
startRow: 17,
|
||||
endRow: 21,
|
||||
startColumn: 3,
|
||||
endColumn: 6,
|
||||
},
|
||||
{
|
||||
startRow: 13,
|
||||
endRow: 15,
|
||||
startColumn: 9,
|
||||
endColumn: 10,
|
||||
},
|
||||
{
|
||||
startRow: 24,
|
||||
endRow: 27,
|
||||
startColumn: 9,
|
||||
endColumn: 10,
|
||||
},
|
||||
{
|
||||
startRow: 32,
|
||||
endRow: 53,
|
||||
startColumn: 3,
|
||||
endColumn: 5,
|
||||
},
|
||||
],
|
||||
rowData: {
|
||||
3: {
|
||||
h: 50,
|
||||
hd: BooleanNumber.FALSE,
|
||||
},
|
||||
4: {
|
||||
h: 60,
|
||||
hd: BooleanNumber.FALSE,
|
||||
},
|
||||
29: {
|
||||
h: 200,
|
||||
hd: BooleanNumber.FALSE,
|
||||
},
|
||||
},
|
||||
columnData: {
|
||||
5: {
|
||||
w: 100,
|
||||
hd: BooleanNumber.FALSE,
|
||||
},
|
||||
6: {
|
||||
w: 200,
|
||||
hd: BooleanNumber.FALSE,
|
||||
},
|
||||
13: {
|
||||
w: 300,
|
||||
hd: BooleanNumber.FALSE,
|
||||
},
|
||||
},
|
||||
showGridlines: 1,
|
||||
rowHeader: {
|
||||
width: 46,
|
||||
hidden: BooleanNumber.FALSE,
|
||||
},
|
||||
columnHeader: {
|
||||
height: 20,
|
||||
hidden: BooleanNumber.FALSE,
|
||||
},
|
||||
rightToLeft: BooleanNumber.FALSE,
|
||||
},
|
||||
'sheet-02': {
|
||||
id: 'sheet-02',
|
||||
name: 'sheet2',
|
||||
cellData: {
|
||||
0: {
|
||||
0: {
|
||||
s: '1',
|
||||
v: 1,
|
||||
},
|
||||
1: {
|
||||
s: '1',
|
||||
v: 1,
|
||||
},
|
||||
5: {
|
||||
s: '1',
|
||||
v: 8,
|
||||
},
|
||||
6: {
|
||||
s: '2',
|
||||
v: 8,
|
||||
},
|
||||
},
|
||||
20: {
|
||||
0: {
|
||||
v: 'sheet2',
|
||||
},
|
||||
1: {
|
||||
v: 'sheet2 - 2',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'sheet-03': {
|
||||
id: 'sheet-03',
|
||||
name: 'sheet3',
|
||||
},
|
||||
'sheet-04': {
|
||||
id: 'sheet-04',
|
||||
name: 'sheet4',
|
||||
},
|
||||
'sheet-05': {
|
||||
id: 'sheet-05',
|
||||
name: 'sheet5',
|
||||
},
|
||||
'sheet-06': {
|
||||
id: 'sheet-06',
|
||||
name: 'sheet6',
|
||||
},
|
||||
},
|
||||
// namedRanges: [
|
||||
// {
|
||||
// namedRangeId: 'named-range-01',
|
||||
// name: 'namedRange01',
|
||||
// range: {
|
||||
// sheetId: 'sheet-01',
|
||||
// range: {
|
||||
// startRow: 0,
|
||||
// startColumn: 0,
|
||||
// endRow: 1,
|
||||
// endColumn: 1,
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// namedRangeId: 'named-range-02',
|
||||
// name: 'namedRange02',
|
||||
// range: {
|
||||
// sheetId: 'sheet-01',
|
||||
// range: {
|
||||
// startRow: 4,
|
||||
// startColumn: 2,
|
||||
// endRow: 5,
|
||||
// endColumn: 3,
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
};
|
||||
/**
|
||||
* Default workbook data
|
||||
*/
|
||||
export const DEFAULT_WORKBOOK_DATA_DOWN: IWorkbookData = {
|
||||
id: 'workbook-02',
|
||||
locale: LocaleType.ZH_CN,
|
||||
name: 'universheet',
|
||||
sheetOrder: [],
|
||||
styles: {
|
||||
1: {
|
||||
cl: {
|
||||
rgb: 'green',
|
||||
},
|
||||
fs: 16,
|
||||
bd: {
|
||||
t: {
|
||||
s: BorderStyleTypes.MEDIUM_DASHED,
|
||||
cl: {
|
||||
rgb: 'black',
|
||||
},
|
||||
},
|
||||
l: {
|
||||
s: BorderStyleTypes.MEDIUM_DASHED,
|
||||
cl: {
|
||||
rgb: 'black',
|
||||
},
|
||||
},
|
||||
r: {
|
||||
s: BorderStyleTypes.THICK,
|
||||
cl: {
|
||||
rgb: 'black',
|
||||
},
|
||||
},
|
||||
b: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'blue',
|
||||
},
|
||||
},
|
||||
},
|
||||
ht: 3,
|
||||
},
|
||||
2: {
|
||||
bg: {
|
||||
rgb: 'rgb(2, 200, 0)',
|
||||
},
|
||||
fs: 24,
|
||||
},
|
||||
3: {
|
||||
ht: HorizontalAlign.RIGHT,
|
||||
vt: VerticalAlign.TOP,
|
||||
tb: WrapStrategy.WRAP,
|
||||
// va: BaselineOffset.SUPERSCRIPT,
|
||||
// cl: {
|
||||
// rgb: 'rgb(0, 255, 0)',
|
||||
// },
|
||||
// st: {
|
||||
// s: BooleanNumber.TRUE, // show
|
||||
// },
|
||||
bg: {
|
||||
rgb: 'rgb(255, 255, 0)',
|
||||
},
|
||||
tr: {
|
||||
a: 45,
|
||||
v: BooleanNumber.FALSE,
|
||||
},
|
||||
bd: {
|
||||
t: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'black',
|
||||
},
|
||||
},
|
||||
l: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'black',
|
||||
},
|
||||
},
|
||||
r: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'black',
|
||||
},
|
||||
},
|
||||
b: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'red',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
4: {
|
||||
bg: {
|
||||
rgb: 'rgb(0, 0, 255)',
|
||||
},
|
||||
},
|
||||
},
|
||||
appVersion: '3.0.0-alpha',
|
||||
sheets: {
|
||||
'sheet-0001': {
|
||||
id: 'sheet-0001',
|
||||
cellData: {
|
||||
0: {
|
||||
0: {
|
||||
s: '1',
|
||||
v: 2,
|
||||
},
|
||||
1: {
|
||||
s: '1',
|
||||
v: 1,
|
||||
},
|
||||
5: {
|
||||
s: '1',
|
||||
v: 8,
|
||||
},
|
||||
6: {
|
||||
s: '2',
|
||||
v: 8,
|
||||
},
|
||||
},
|
||||
1: {
|
||||
0: {
|
||||
v: 22,
|
||||
},
|
||||
1: {
|
||||
v: 22,
|
||||
},
|
||||
2: {
|
||||
v: 80,
|
||||
s: '3',
|
||||
},
|
||||
3: {
|
||||
v: '富文本编辑',
|
||||
s: '2',
|
||||
},
|
||||
},
|
||||
2: {
|
||||
0: {
|
||||
v: 2222,
|
||||
},
|
||||
1: {
|
||||
v: 2222,
|
||||
},
|
||||
5: {
|
||||
s: '1',
|
||||
v: 8,
|
||||
},
|
||||
6: {
|
||||
s: '1',
|
||||
v: 8,
|
||||
},
|
||||
7: {
|
||||
s: '1',
|
||||
v: 8,
|
||||
},
|
||||
8: {
|
||||
s: '1',
|
||||
v: 8,
|
||||
},
|
||||
},
|
||||
3: {
|
||||
0: {
|
||||
v: 1111,
|
||||
},
|
||||
1: {
|
||||
v: 1111,
|
||||
},
|
||||
},
|
||||
10: {
|
||||
9: {
|
||||
v: 1111,
|
||||
s: '2',
|
||||
},
|
||||
},
|
||||
13: {
|
||||
9: {
|
||||
v: 1111,
|
||||
s: '4',
|
||||
},
|
||||
},
|
||||
17: {
|
||||
3: {
|
||||
v: '做移动端开发和前端开发的人员,对 MVC、MVP、MVVM 这几个名词应该都不陌生,这是三个最常用的应用架构模式,目的都是为了将业务和视图的实现代码分离',
|
||||
s: '3',
|
||||
p: richTextTest,
|
||||
},
|
||||
},
|
||||
20: {
|
||||
10: {
|
||||
v: '北京马拉松组委会办公室一位接电话的女士证实,的确有这项规定,她还称2014年马拉松的预登记工作将在本周启动。北京马拉松比赛将在10月19日举行。',
|
||||
s: '3',
|
||||
},
|
||||
12: {
|
||||
s: '4',
|
||||
},
|
||||
},
|
||||
29: {
|
||||
13: {
|
||||
p: Tools.deepClone(richTextTest),
|
||||
s: '4',
|
||||
},
|
||||
},
|
||||
},
|
||||
name: 'sheet0001',
|
||||
tabColor: 'green',
|
||||
hidden: BooleanNumber.FALSE,
|
||||
rowCount: 1000,
|
||||
columnCount: 20,
|
||||
zoomRatio: 1,
|
||||
scrollTop: 200,
|
||||
scrollLeft: 100,
|
||||
defaultColumnWidth: 93,
|
||||
defaultRowHeight: 27,
|
||||
mergeData: [
|
||||
{
|
||||
startRow: 0,
|
||||
endRow: 1,
|
||||
startColumn: 0,
|
||||
endColumn: 1,
|
||||
},
|
||||
{
|
||||
startRow: 2,
|
||||
endRow: 6,
|
||||
startColumn: 5,
|
||||
endColumn: 10,
|
||||
},
|
||||
{
|
||||
startRow: 10,
|
||||
endRow: 12,
|
||||
startColumn: 9,
|
||||
endColumn: 12,
|
||||
},
|
||||
{
|
||||
startRow: 10,
|
||||
endRow: 12,
|
||||
startColumn: 9,
|
||||
endColumn: 12,
|
||||
},
|
||||
{
|
||||
startRow: 17,
|
||||
endRow: 21,
|
||||
startColumn: 3,
|
||||
endColumn: 6,
|
||||
},
|
||||
{
|
||||
startRow: 13,
|
||||
endRow: 15,
|
||||
startColumn: 9,
|
||||
endColumn: 10,
|
||||
},
|
||||
{
|
||||
startRow: 24,
|
||||
endRow: 27,
|
||||
startColumn: 9,
|
||||
endColumn: 10,
|
||||
},
|
||||
],
|
||||
rowData: {
|
||||
3: {
|
||||
h: 50,
|
||||
hd: BooleanNumber.FALSE,
|
||||
},
|
||||
4: {
|
||||
h: 60,
|
||||
hd: BooleanNumber.FALSE,
|
||||
},
|
||||
29: {
|
||||
h: 200,
|
||||
hd: BooleanNumber.FALSE,
|
||||
},
|
||||
},
|
||||
columnData: {
|
||||
5: {
|
||||
w: 100,
|
||||
hd: BooleanNumber.FALSE,
|
||||
},
|
||||
6: {
|
||||
w: 200,
|
||||
hd: BooleanNumber.FALSE,
|
||||
},
|
||||
13: {
|
||||
w: 300,
|
||||
hd: BooleanNumber.FALSE,
|
||||
},
|
||||
},
|
||||
showGridlines: 1,
|
||||
rowHeader: {
|
||||
width: 46,
|
||||
hidden: BooleanNumber.FALSE,
|
||||
},
|
||||
columnHeader: {
|
||||
height: 20,
|
||||
hidden: BooleanNumber.FALSE,
|
||||
},
|
||||
rightToLeft: BooleanNumber.FALSE,
|
||||
},
|
||||
'sheet-0002': {
|
||||
id: 'sheet-0002',
|
||||
name: 'sheet0003',
|
||||
},
|
||||
},
|
||||
// namedRanges: [
|
||||
// {
|
||||
// namedRangeId: 'named-range-0001',
|
||||
// name: 'namedRange0001',
|
||||
// range: {
|
||||
// sheetId: 'sheet-0001',
|
||||
// range: {
|
||||
// startRow: 0,
|
||||
// startColumn: 0,
|
||||
// endRow: 1,
|
||||
// endColumn: 1,
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
};
|
||||
@@ -1,155 +0,0 @@
|
||||
export const DEFAULT_WORKBOOK_DATA_VALIDATION = {
|
||||
id: 'workbook-01',
|
||||
sheetOrder: [
|
||||
'80FIpJ1SdQLVIUEbrnC3J',
|
||||
],
|
||||
name: 'UniverSheet Demo',
|
||||
appVersion: '3.0.0-alpha',
|
||||
locale: 'zhCN',
|
||||
styles: {},
|
||||
sheets: {
|
||||
'80FIpJ1SdQLVIUEbrnC3J': {
|
||||
name: '工作表1',
|
||||
id: '80FIpJ1SdQLVIUEbrnC3J',
|
||||
tabColor: '',
|
||||
hidden: 0,
|
||||
rowCount: 1000,
|
||||
columnCount: 20,
|
||||
zoomRatio: 1,
|
||||
freeze: {
|
||||
xSplit: 0,
|
||||
ySplit: 0,
|
||||
startRow: -1,
|
||||
startColumn: -1,
|
||||
},
|
||||
scrollTop: 0,
|
||||
scrollLeft: 0,
|
||||
defaultColumnWidth: 73,
|
||||
defaultRowHeight: 19,
|
||||
mergeData: [],
|
||||
cellData: {
|
||||
0: {
|
||||
0: {
|
||||
v: 'YES',
|
||||
t: 1,
|
||||
},
|
||||
2: {
|
||||
v: 'IF',
|
||||
t: 1,
|
||||
},
|
||||
5: {
|
||||
v: '中文',
|
||||
t: 1,
|
||||
},
|
||||
6: {
|
||||
v: '一',
|
||||
t: 1,
|
||||
},
|
||||
7: {
|
||||
v: '二',
|
||||
t: 1,
|
||||
},
|
||||
8: {
|
||||
v: '三',
|
||||
t: 1,
|
||||
},
|
||||
},
|
||||
1: {
|
||||
5: {
|
||||
v: '数字',
|
||||
t: 1,
|
||||
},
|
||||
6: {
|
||||
v: 1,
|
||||
t: 2,
|
||||
},
|
||||
7: {
|
||||
v: 2,
|
||||
t: 2,
|
||||
},
|
||||
8: {
|
||||
v: 3,
|
||||
t: 2,
|
||||
},
|
||||
},
|
||||
2: {
|
||||
2: {
|
||||
v: '级联',
|
||||
t: 1,
|
||||
},
|
||||
3: {
|
||||
v: '中文',
|
||||
t: 1,
|
||||
},
|
||||
4: {
|
||||
v: '一',
|
||||
t: 1,
|
||||
},
|
||||
5: null,
|
||||
6: null,
|
||||
7: null,
|
||||
8: null,
|
||||
},
|
||||
3: {
|
||||
3: null,
|
||||
4: null,
|
||||
5: null,
|
||||
6: null,
|
||||
7: null,
|
||||
8: null,
|
||||
},
|
||||
},
|
||||
rowData: {
|
||||
0: {
|
||||
hd: 0,
|
||||
h: 19,
|
||||
ah: 20,
|
||||
},
|
||||
2: {
|
||||
hd: 0,
|
||||
h: 19,
|
||||
ah: 20,
|
||||
},
|
||||
3: {
|
||||
hd: 0,
|
||||
h: 19,
|
||||
ah: 19,
|
||||
},
|
||||
},
|
||||
columnData: {},
|
||||
showGridlines: 1,
|
||||
rowHeader: {
|
||||
width: 46,
|
||||
hidden: 0,
|
||||
},
|
||||
columnHeader: {
|
||||
height: 20,
|
||||
hidden: 0,
|
||||
},
|
||||
rightToLeft: 0,
|
||||
},
|
||||
},
|
||||
resources: [
|
||||
{
|
||||
name: 'SHEET_NUMFMT_PLUGIN',
|
||||
data: '',
|
||||
},
|
||||
{
|
||||
name: 'SHEET_DEFINED_NAME_PLUGIN',
|
||||
data: '',
|
||||
},
|
||||
{
|
||||
name: 'SHEET_DATA_VALIDATION',
|
||||
data: '{"sheet-0011":[{"uid":"xxx-1","type":"decimal","ranges":[{"startRow":0,"endRow":5,"startColumn":0,"endColumn":2}],"operator":"greaterThan","formula1":"111","errorStyle":1},{"uid":"xxx-0","type":"date","ranges":[{"startRow":0,"endRow":5,"startColumn":3,"endColumn":5}],"operator":"greaterThan","formula1":"100","errorStyle":1},{"uid":"xxx-2","type":"checkbox","ranges":[{"startRow":6,"endRow":10,"startColumn":0,"endColumn":5}]},{"uid":"xxx-3","type":"list","ranges":[{"startRow":11,"endRow":15,"startColumn":0,"endColumn":5}],"formula1":"1,2,3,hahaha"},{"uid":"xxx-4","type":"custom","ranges":[{"startRow":16,"endRow":20,"startColumn":0,"endColumn":5}],"formula1":"=A1"},{"uid":"xxx-5","type":"listMultiple","ranges":[{"startRow":21,"endRow":21,"startColumn":0,"endColumn":0}],"formula1":"1,2,3,4,5,哈哈哈哈"}],"80FIpJ1SdQLVIUEbrnC3J":[{"uid":"pQCe2q","type":"list","formula1":"=IF(A1=\\"YES\\",G1:I1,G2:I2)","ranges":[{"startRow":0,"endRow":0,"startColumn":3,"endColumn":3}],"formula2":""},{"uid":"JL6foF","type":"list","formula1":"=F1:F2","ranges":[{"startRow":2,"startColumn":3,"endRow":2,"endColumn":3,"rangeType":0}],"formula2":""},{"uid":"XlFuI6","type":"list","formula1":"=IF(D3=\\"中文\\",G1:I1,G2:I2)","ranges":[{"startRow":2,"startColumn":4,"endRow":2,"endColumn":4,"rangeType":0}],"formula2":""}]}',
|
||||
},
|
||||
{
|
||||
name: 'SHEET_CONDITIONAL_FORMATTING_PLUGIN',
|
||||
data: '',
|
||||
},
|
||||
],
|
||||
__env__: {
|
||||
gitHash: '840580212',
|
||||
gitBranch: 'feat/dv-list-formula',
|
||||
buildTime: '2024-04-10T11:19:00.298Z',
|
||||
},
|
||||
};
|
||||
@@ -1,10 +0,0 @@
|
||||
export * from './default-workbook-data-default-style';
|
||||
export * from './default-workbook-data-demo';
|
||||
export * from './default-workbook-data-demo1';
|
||||
export * from './default-workbook-data-demo2';
|
||||
export * from './default-workbook-data-demo3';
|
||||
export * from './default-workbook-data-demo4';
|
||||
export * from './default-workbook-data-demo5';
|
||||
export * from './default-workbook-data-demo6';
|
||||
export * from './default-workbook-data-demo7';
|
||||
export * from './default-workbook-data-demo8';
|
||||
@@ -1,3 +0,0 @@
|
||||
export * from './default-workbook-data';
|
||||
export * from './demo';
|
||||
export * from './slide-workbook-data';
|
||||
@@ -1,615 +0,0 @@
|
||||
import type { IWorkbookData } from '@univerjs/core';
|
||||
import { BooleanNumber, BorderStyleTypes, LocaleType } from '@univerjs/core';
|
||||
import { PAGE5_RICHTEXT_1 } from '../slides/rich-text/page5-richtext1';
|
||||
|
||||
export const SLIDE_WORKBOOK_DATA: IWorkbookData = {
|
||||
id: 'workbook-01',
|
||||
locale: LocaleType.ZH_CN,
|
||||
name: 'universheet',
|
||||
sheetOrder: ['sheet-0001'],
|
||||
styles: {
|
||||
1: {
|
||||
vt: 2,
|
||||
ht: 2,
|
||||
bl: 1,
|
||||
fs: 14 * 0.75,
|
||||
bg: {
|
||||
rgb: 'rgb(105,126,146)',
|
||||
},
|
||||
cl: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
},
|
||||
2: {
|
||||
vt: 2,
|
||||
ht: 2,
|
||||
bl: 1,
|
||||
fs: 20 * 0.75,
|
||||
bg: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
cl: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
bd: {
|
||||
t: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'rgb(217,217,217)',
|
||||
},
|
||||
},
|
||||
l: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'rgb(217,217,217)',
|
||||
},
|
||||
},
|
||||
r: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'rgb(217,217,217)',
|
||||
},
|
||||
},
|
||||
b: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'rgb(217,217,217)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
3: {
|
||||
vt: 2,
|
||||
bg: {
|
||||
rgb: 'rgb(105,126,146)',
|
||||
},
|
||||
cl: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
fs: 14 * 0.75,
|
||||
ht: 2,
|
||||
bd: {
|
||||
t: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'rgb(217,217,217)',
|
||||
},
|
||||
},
|
||||
l: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'rgb(217,217,217)',
|
||||
},
|
||||
},
|
||||
r: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'rgb(217,217,217)',
|
||||
},
|
||||
},
|
||||
b: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'rgb(217,217,217)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
4: {
|
||||
fs: 12 * 0.75,
|
||||
vt: 2,
|
||||
pd: {
|
||||
l: 5,
|
||||
},
|
||||
ht: 2,
|
||||
bd: {
|
||||
t: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'rgb(217,217,217)',
|
||||
},
|
||||
},
|
||||
l: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'rgb(217,217,217)',
|
||||
},
|
||||
},
|
||||
r: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'rgb(217,217,217)',
|
||||
},
|
||||
},
|
||||
b: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'rgb(217,217,217)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
5: {
|
||||
ht: 2,
|
||||
vt: 2,
|
||||
bd: {
|
||||
t: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'rgb(217,217,217)',
|
||||
},
|
||||
},
|
||||
l: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'rgb(217,217,217)',
|
||||
},
|
||||
},
|
||||
r: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'rgb(217,217,217)',
|
||||
},
|
||||
},
|
||||
b: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'rgb(217,217,217)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
6: {
|
||||
ht: 1,
|
||||
vt: 2,
|
||||
tb: 3,
|
||||
bg: {
|
||||
rgb: 'rgba(244,79,86)',
|
||||
},
|
||||
cl: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
bd: {
|
||||
t: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'rgb(217,217,217)',
|
||||
},
|
||||
},
|
||||
l: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'rgb(217,217,217)',
|
||||
},
|
||||
},
|
||||
r: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'rgb(217,217,217)',
|
||||
},
|
||||
},
|
||||
b: {
|
||||
s: BorderStyleTypes.THIN,
|
||||
cl: {
|
||||
rgb: 'rgb(217,217,217)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
appVersion: '3.0.0-alpha',
|
||||
sheets: {
|
||||
'sheet-0001': {
|
||||
id: 'sheet-0001',
|
||||
name: 'sheet-0001',
|
||||
tabColor: 'blue',
|
||||
hidden: BooleanNumber.FALSE,
|
||||
rowCount: 12,
|
||||
columnCount: 11,
|
||||
zoomRatio: 1,
|
||||
scrollTop: 200,
|
||||
scrollLeft: 100,
|
||||
defaultColumnWidth: 93,
|
||||
defaultRowHeight: 40,
|
||||
cellData: {
|
||||
1: {
|
||||
1: {
|
||||
v: 'Variants',
|
||||
s: '2',
|
||||
},
|
||||
2: {
|
||||
v: 'Platform',
|
||||
s: '2',
|
||||
},
|
||||
3: {
|
||||
v: 'UGC Buzz volume',
|
||||
s: '2',
|
||||
},
|
||||
9: {
|
||||
p: PAGE5_RICHTEXT_1,
|
||||
s: '6',
|
||||
},
|
||||
},
|
||||
2: {
|
||||
3: {
|
||||
v: "Jul'21",
|
||||
s: '1',
|
||||
},
|
||||
4: {
|
||||
v: "Aug'21",
|
||||
s: '1',
|
||||
},
|
||||
5: {
|
||||
v: "Sep'21",
|
||||
s: '1',
|
||||
},
|
||||
6: {
|
||||
v: "Oct'21",
|
||||
s: '1',
|
||||
},
|
||||
7: {
|
||||
v: "Nov'21",
|
||||
s: '1',
|
||||
},
|
||||
8: {
|
||||
v: "Dec'21",
|
||||
s: '1',
|
||||
},
|
||||
},
|
||||
3: {
|
||||
1: {
|
||||
v: 'Eleva',
|
||||
s: '3',
|
||||
},
|
||||
2: {
|
||||
v: 'Amazon',
|
||||
s: '4',
|
||||
},
|
||||
3: {
|
||||
v: '4',
|
||||
s: '5',
|
||||
},
|
||||
4: {
|
||||
v: '145',
|
||||
s: '5',
|
||||
},
|
||||
5: {
|
||||
v: '44',
|
||||
s: '5',
|
||||
},
|
||||
6: {
|
||||
v: '20',
|
||||
s: '5',
|
||||
},
|
||||
7: {
|
||||
v: '7',
|
||||
s: '5',
|
||||
},
|
||||
8: {
|
||||
v: '12',
|
||||
s: '5',
|
||||
},
|
||||
},
|
||||
4: {
|
||||
2: {
|
||||
v: 'Google',
|
||||
s: '4',
|
||||
},
|
||||
3: {
|
||||
v: '2',
|
||||
s: '5',
|
||||
},
|
||||
4: {
|
||||
v: '6',
|
||||
s: '5',
|
||||
},
|
||||
5: {
|
||||
v: '5',
|
||||
s: '5',
|
||||
},
|
||||
6: {
|
||||
v: '6',
|
||||
s: '5',
|
||||
},
|
||||
7: {
|
||||
v: '12',
|
||||
s: '5',
|
||||
},
|
||||
8: {
|
||||
v: '3113',
|
||||
s: '5',
|
||||
},
|
||||
},
|
||||
5: {
|
||||
2: {
|
||||
v: 'Amazon',
|
||||
s: '4',
|
||||
},
|
||||
3: {
|
||||
v: '14',
|
||||
s: '5',
|
||||
},
|
||||
4: {
|
||||
v: '13',
|
||||
s: '5',
|
||||
},
|
||||
5: {
|
||||
v: '6',
|
||||
s: '5',
|
||||
},
|
||||
6: {
|
||||
v: '6',
|
||||
s: '5',
|
||||
},
|
||||
7: {
|
||||
v: '11',
|
||||
s: '5',
|
||||
},
|
||||
8: {
|
||||
v: '2',
|
||||
s: '5',
|
||||
},
|
||||
},
|
||||
6: {
|
||||
1: {
|
||||
v: 'Similac',
|
||||
s: '3',
|
||||
},
|
||||
2: {
|
||||
v: 'SaleForce',
|
||||
s: '4',
|
||||
},
|
||||
3: {
|
||||
v: '451',
|
||||
s: '5',
|
||||
},
|
||||
4: {
|
||||
v: '255',
|
||||
s: '5',
|
||||
},
|
||||
5: {
|
||||
v: '72',
|
||||
s: '5',
|
||||
},
|
||||
6: {
|
||||
v: '23',
|
||||
s: '5',
|
||||
},
|
||||
7: {
|
||||
v: '163',
|
||||
s: '5',
|
||||
},
|
||||
8: {
|
||||
v: '22',
|
||||
s: '5',
|
||||
},
|
||||
},
|
||||
7: {
|
||||
2: {
|
||||
v: 'Oracle',
|
||||
s: '4',
|
||||
},
|
||||
3: {
|
||||
v: '0',
|
||||
s: '5',
|
||||
},
|
||||
4: {
|
||||
v: '1',
|
||||
s: '5',
|
||||
},
|
||||
5: {
|
||||
v: '1136',
|
||||
s: '5',
|
||||
},
|
||||
6: {
|
||||
v: '11',
|
||||
s: '5',
|
||||
},
|
||||
7: {
|
||||
v: '2',
|
||||
s: '5',
|
||||
},
|
||||
8: {
|
||||
v: '1',
|
||||
s: '5',
|
||||
},
|
||||
},
|
||||
8: {
|
||||
2: {
|
||||
v: 'Apple',
|
||||
s: '4',
|
||||
},
|
||||
3: {
|
||||
v: '7',
|
||||
s: '5',
|
||||
},
|
||||
4: {
|
||||
v: '2',
|
||||
s: '5',
|
||||
},
|
||||
5: {
|
||||
v: '10',
|
||||
s: '5',
|
||||
},
|
||||
6: {
|
||||
v: '5',
|
||||
s: '5',
|
||||
},
|
||||
7: {
|
||||
v: '6',
|
||||
s: '5',
|
||||
},
|
||||
8: {
|
||||
v: '3',
|
||||
s: '5',
|
||||
},
|
||||
},
|
||||
9: {
|
||||
1: {
|
||||
v: 'TC',
|
||||
s: '3',
|
||||
},
|
||||
2: {
|
||||
v: 'IBM',
|
||||
s: '4',
|
||||
},
|
||||
3: {
|
||||
v: '1',
|
||||
s: '5',
|
||||
},
|
||||
4: {
|
||||
v: '12',
|
||||
s: '5',
|
||||
},
|
||||
5: {
|
||||
v: '2',
|
||||
s: '5',
|
||||
},
|
||||
6: {
|
||||
v: '1',
|
||||
s: '5',
|
||||
},
|
||||
7: {
|
||||
v: '1',
|
||||
s: '5',
|
||||
},
|
||||
8: {
|
||||
v: '1',
|
||||
s: '5',
|
||||
},
|
||||
},
|
||||
10: {
|
||||
2: {
|
||||
v: 'Google',
|
||||
s: '4',
|
||||
},
|
||||
3: {
|
||||
v: '26',
|
||||
s: '5',
|
||||
},
|
||||
4: {
|
||||
v: '33',
|
||||
s: '5',
|
||||
},
|
||||
5: {
|
||||
v: '33',
|
||||
s: '5',
|
||||
},
|
||||
6: {
|
||||
v: '6',
|
||||
s: '5',
|
||||
},
|
||||
7: {
|
||||
v: '22',
|
||||
s: '5',
|
||||
},
|
||||
8: {
|
||||
v: '8',
|
||||
s: '5',
|
||||
},
|
||||
},
|
||||
},
|
||||
mergeData: [
|
||||
{
|
||||
startRow: 1,
|
||||
endRow: 2,
|
||||
startColumn: 1,
|
||||
endColumn: 1,
|
||||
},
|
||||
{
|
||||
startRow: 1,
|
||||
endRow: 2,
|
||||
startColumn: 2,
|
||||
endColumn: 2,
|
||||
},
|
||||
{
|
||||
startRow: 1,
|
||||
endRow: 1,
|
||||
startColumn: 3,
|
||||
endColumn: 8,
|
||||
},
|
||||
{
|
||||
startRow: 3,
|
||||
endRow: 5,
|
||||
startColumn: 1,
|
||||
endColumn: 1,
|
||||
},
|
||||
{
|
||||
startRow: 6,
|
||||
endRow: 8,
|
||||
startColumn: 1,
|
||||
endColumn: 1,
|
||||
},
|
||||
{
|
||||
startRow: 9,
|
||||
endRow: 10,
|
||||
startColumn: 1,
|
||||
endColumn: 1,
|
||||
},
|
||||
{
|
||||
startRow: 1,
|
||||
endRow: 10,
|
||||
startColumn: 9,
|
||||
endColumn: 10,
|
||||
},
|
||||
],
|
||||
|
||||
rowData: {
|
||||
0: {
|
||||
h: 20,
|
||||
},
|
||||
},
|
||||
columnData: {
|
||||
0: {
|
||||
w: 20,
|
||||
},
|
||||
2: {
|
||||
w: 120,
|
||||
},
|
||||
3: {
|
||||
w: 60,
|
||||
},
|
||||
4: {
|
||||
w: 60,
|
||||
},
|
||||
5: {
|
||||
w: 60,
|
||||
},
|
||||
6: {
|
||||
w: 60,
|
||||
},
|
||||
7: {
|
||||
w: 60,
|
||||
},
|
||||
8: {
|
||||
w: 60,
|
||||
},
|
||||
},
|
||||
showGridlines: 0,
|
||||
rowHeader: {
|
||||
width: 46,
|
||||
hidden: BooleanNumber.FALSE,
|
||||
},
|
||||
columnHeader: {
|
||||
height: 20,
|
||||
hidden: BooleanNumber.FALSE,
|
||||
},
|
||||
rightToLeft: BooleanNumber.FALSE,
|
||||
},
|
||||
},
|
||||
// namedRanges: [
|
||||
// {
|
||||
// namedRangeId: 'named-rang',
|
||||
// name: 'namedRange',
|
||||
// range: {
|
||||
// sheetId: 'sheet-0001',
|
||||
// range: {
|
||||
// startRow: 0,
|
||||
// startColumn: 0,
|
||||
// endRow: 1,
|
||||
// endColumn: 1,
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
};
|
||||
@@ -1,127 +0,0 @@
|
||||
import { BasicShapes, PageElementType, PageType } from '@univerjs/slides';
|
||||
|
||||
export const DEFAULT_FIRST_PAGE = {
|
||||
id: 'cover_1',
|
||||
pageType: PageType.SLIDE,
|
||||
zIndex: 1,
|
||||
title: 'cover',
|
||||
description: 'this is first page, cover',
|
||||
pageBackgroundFill: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
pageElements: {
|
||||
background1: {
|
||||
id: 'background1',
|
||||
zIndex: 0,
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: 960,
|
||||
height: 540,
|
||||
title: 'background',
|
||||
description: '',
|
||||
type: PageElementType.IMAGE,
|
||||
image: {
|
||||
imageProperties: {
|
||||
contentUrl: 'https://release-univer.oss-cn-shenzhen.aliyuncs.com/template-resource/jYGEpeogMHxvwoiSqIMMn_Picture1.jpg',
|
||||
},
|
||||
},
|
||||
},
|
||||
mask1: {
|
||||
id: 'mask1',
|
||||
zIndex: 1,
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: 960,
|
||||
height: 540,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.SHAPE,
|
||||
shape: {
|
||||
shapeType: BasicShapes.Rect,
|
||||
text: '',
|
||||
shapeProperties: {
|
||||
shapeBackgroundFill: {
|
||||
rgb: 'rgba(0,0,0,0.7)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
text1: {
|
||||
id: 'text1',
|
||||
zIndex: 2,
|
||||
left: 300,
|
||||
top: 200,
|
||||
width: 400,
|
||||
height: 100,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'Univer slide',
|
||||
fs: 64 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
bl: 1,
|
||||
},
|
||||
},
|
||||
centerRect1: {
|
||||
id: 'centerRect1',
|
||||
zIndex: 1,
|
||||
left: 378,
|
||||
top: 0,
|
||||
width: 204,
|
||||
height: 144,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.SHAPE,
|
||||
shape: {
|
||||
shapeType: BasicShapes.Rect,
|
||||
text: '',
|
||||
shapeProperties: {
|
||||
shapeBackgroundFill: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
year1: {
|
||||
id: 'year1',
|
||||
zIndex: 2,
|
||||
left: 430,
|
||||
top: 42,
|
||||
width: 130,
|
||||
height: 50,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: '2024',
|
||||
fs: 48 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
bl: 1,
|
||||
},
|
||||
},
|
||||
content1: {
|
||||
id: 'content1',
|
||||
zIndex: 2,
|
||||
left: 80,
|
||||
top: 300,
|
||||
width: 780,
|
||||
height: 140,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'The concepts national income and national product have roughly the same value and can be used interchangeably if our interest is in their sum total which is measured as the market value of the total output of goods and services of an economy in a given period, usually a year.',
|
||||
fs: 14 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
bl: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,392 +0,0 @@
|
||||
import { BasicShapes, PageElementType, PageType } from '@univerjs/slides';
|
||||
|
||||
export const DEFAULT_SECOND_PAGE = {
|
||||
id: 'catalog_1',
|
||||
pageType: PageType.SLIDE,
|
||||
zIndex: 2,
|
||||
title: 'catalog',
|
||||
description: 'this is second page, catalog',
|
||||
pageBackgroundFill: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
pageElements: {
|
||||
background1: {
|
||||
id: 'background1',
|
||||
zIndex: 0,
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: 960,
|
||||
height: 540,
|
||||
title: 'background',
|
||||
description: '',
|
||||
type: PageElementType.IMAGE,
|
||||
image: {
|
||||
imageProperties: {
|
||||
contentUrl: 'https://release-univer.oss-cn-shenzhen.aliyuncs.com/template-resource/jYGEpeogMHxvwoiSqIMMn_Picture1.jpg',
|
||||
},
|
||||
},
|
||||
},
|
||||
mask1: {
|
||||
id: 'mask1',
|
||||
zIndex: 1,
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: 960,
|
||||
height: 540,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.SHAPE,
|
||||
shape: {
|
||||
shapeType: BasicShapes.Rect,
|
||||
text: '',
|
||||
shapeProperties: {
|
||||
shapeBackgroundFill: {
|
||||
rgb: 'rgba(0,0,0,0.7)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
text1: {
|
||||
id: 'text1',
|
||||
zIndex: 3,
|
||||
left: 180,
|
||||
top: 240,
|
||||
width: 200,
|
||||
height: 40,
|
||||
title: 'Catalog',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'Catalog',
|
||||
fs: 42 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
},
|
||||
},
|
||||
centerRect1: {
|
||||
id: 'centerRect1',
|
||||
zIndex: 2,
|
||||
left: 140,
|
||||
top: 168,
|
||||
width: 203,
|
||||
height: 203,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.SHAPE,
|
||||
shape: {
|
||||
shapeType: BasicShapes.Rect,
|
||||
text: '',
|
||||
shapeProperties: {
|
||||
shapeBackgroundFill: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
firstRect1: {
|
||||
id: 'firstRect1',
|
||||
zIndex: 2,
|
||||
left: 547,
|
||||
top: 115,
|
||||
width: 44,
|
||||
height: 44,
|
||||
title: 'index1',
|
||||
description: '',
|
||||
type: PageElementType.SHAPE,
|
||||
shape: {
|
||||
shapeType: BasicShapes.Rect,
|
||||
text: '',
|
||||
shapeProperties: {
|
||||
shapeBackgroundFill: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
secondRect1: {
|
||||
id: 'secondRect1',
|
||||
zIndex: 2,
|
||||
left: 547,
|
||||
top: 210,
|
||||
width: 44,
|
||||
height: 44,
|
||||
title: 'index2',
|
||||
description: '',
|
||||
type: PageElementType.SHAPE,
|
||||
shape: {
|
||||
shapeType: BasicShapes.Rect,
|
||||
text: '',
|
||||
shapeProperties: {
|
||||
shapeBackgroundFill: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
thirdRect1: {
|
||||
id: 'thirdRect1',
|
||||
zIndex: 2,
|
||||
left: 547,
|
||||
top: 304,
|
||||
width: 44,
|
||||
height: 44,
|
||||
title: 'index2',
|
||||
description: '',
|
||||
type: PageElementType.SHAPE,
|
||||
shape: {
|
||||
shapeType: BasicShapes.Rect,
|
||||
text: '',
|
||||
shapeProperties: {
|
||||
shapeBackgroundFill: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
forth1: {
|
||||
id: 'forth1',
|
||||
zIndex: 2,
|
||||
left: 547,
|
||||
top: 397,
|
||||
width: 44,
|
||||
height: 44,
|
||||
title: 'index2',
|
||||
description: '',
|
||||
type: PageElementType.SHAPE,
|
||||
shape: {
|
||||
shapeType: BasicShapes.Rect,
|
||||
text: '',
|
||||
shapeProperties: {
|
||||
shapeBackgroundFill: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
first_index1: {
|
||||
id: 'first_index1',
|
||||
zIndex: 3,
|
||||
left: 557,
|
||||
top: 120,
|
||||
width: 44,
|
||||
height: 44,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: '01',
|
||||
fs: 28 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
bl: 1,
|
||||
},
|
||||
},
|
||||
first_title1: {
|
||||
id: 'first_title1',
|
||||
zIndex: 3,
|
||||
left: 610,
|
||||
top: 115,
|
||||
width: 248,
|
||||
height: 39,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'Strategic technology trends',
|
||||
fs: 20 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
bl: 1,
|
||||
},
|
||||
},
|
||||
first_detail1: {
|
||||
id: 'first_detail1',
|
||||
zIndex: 3,
|
||||
left: 610,
|
||||
top: 140,
|
||||
width: 300,
|
||||
height: 39,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'How they impact business goals.',
|
||||
fs: 14 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
},
|
||||
},
|
||||
second_index1: {
|
||||
id: 'second_index1',
|
||||
zIndex: 3,
|
||||
left: 557,
|
||||
top: 215,
|
||||
width: 44,
|
||||
height: 44,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: '02',
|
||||
fs: 28 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
bl: 1,
|
||||
},
|
||||
},
|
||||
second_title1: {
|
||||
id: 'second_title1',
|
||||
zIndex: 3,
|
||||
left: 610,
|
||||
top: 210,
|
||||
width: 248,
|
||||
height: 39,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'Technical profile',
|
||||
fs: 20 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
bl: 1,
|
||||
},
|
||||
},
|
||||
second_detail1: {
|
||||
id: 'second_detail1',
|
||||
zIndex: 3,
|
||||
left: 610,
|
||||
top: 235,
|
||||
width: 300,
|
||||
height: 39,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'What the technologies are and do.',
|
||||
fs: 14 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
},
|
||||
},
|
||||
third_index1: {
|
||||
id: 'third_index1',
|
||||
zIndex: 3,
|
||||
left: 557,
|
||||
top: 310,
|
||||
width: 44,
|
||||
height: 44,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: '03',
|
||||
fs: 28 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
bl: 1,
|
||||
},
|
||||
},
|
||||
third_title1: {
|
||||
id: 'third_title1',
|
||||
zIndex: 3,
|
||||
left: 610,
|
||||
top: 305,
|
||||
width: 248,
|
||||
height: 39,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'Opportunities',
|
||||
fs: 20 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
bl: 1,
|
||||
},
|
||||
},
|
||||
third_detail1: {
|
||||
id: 'third_detail1',
|
||||
zIndex: 3,
|
||||
left: 610,
|
||||
top: 330,
|
||||
width: 300,
|
||||
height: 39,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'What benefits and outcomes they drive.',
|
||||
fs: 14 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
},
|
||||
},
|
||||
forth_index1: {
|
||||
id: 'forth_index1',
|
||||
zIndex: 3,
|
||||
left: 557,
|
||||
top: 405,
|
||||
width: 44,
|
||||
height: 44,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: '04',
|
||||
fs: 28 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
bl: 1,
|
||||
},
|
||||
},
|
||||
forth_title1: {
|
||||
id: 'forth_title1',
|
||||
zIndex: 3,
|
||||
left: 610,
|
||||
top: 400,
|
||||
width: 248,
|
||||
height: 39,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'Implementation steps',
|
||||
fs: 20 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
bl: 1,
|
||||
},
|
||||
},
|
||||
forth_detail1: {
|
||||
id: 'forth_detail1',
|
||||
zIndex: 3,
|
||||
left: 610,
|
||||
top: 425,
|
||||
width: 300,
|
||||
height: 39,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'Action plans for implementation.',
|
||||
fs: 14 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,320 +0,0 @@
|
||||
import { BasicShapes, PageElementType, PageType } from '@univerjs/slides';
|
||||
import { PAGE3_RICHTEXT_1 } from '../rich-text/page3-richtext1';
|
||||
import { PAGE3_RICHTEXT_2 } from '../rich-text/page3-richtext2';
|
||||
import { PAGE3_RICHTEXT_3 } from '../rich-text/page3-richtext3';
|
||||
|
||||
export const DEFAULT_THIRD_PAGE = {
|
||||
id: 'strategic_1',
|
||||
pageType: PageType.SLIDE,
|
||||
zIndex: 1,
|
||||
title: 'cover',
|
||||
description: 'this is third page, strategic',
|
||||
pageBackgroundFill: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
pageElements: {
|
||||
background1: {
|
||||
id: 'background1',
|
||||
zIndex: 1,
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: 960,
|
||||
height: 540,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.SHAPE,
|
||||
shape: {
|
||||
shapeType: BasicShapes.Rect,
|
||||
text: '',
|
||||
shapeProperties: {
|
||||
shapeBackgroundFill: {
|
||||
rgb: 'rgba(237,237,237,1)',
|
||||
},
|
||||
outline: {
|
||||
outlineFill: {
|
||||
rgb: 'rgba(198,198,198,1)',
|
||||
},
|
||||
weight: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
titleIcon1: {
|
||||
id: 'titleIcon1',
|
||||
zIndex: 2,
|
||||
left: 48,
|
||||
top: 52,
|
||||
width: 117 * 0.3,
|
||||
height: 16 * 0.3,
|
||||
title: 'title Icon',
|
||||
description: '',
|
||||
type: PageElementType.IMAGE,
|
||||
image: {
|
||||
imageProperties: {
|
||||
contentUrl: 'https://release-univer.oss-cn-shenzhen.aliyuncs.com/template-resource/E1MC_gxuoxED7as5FCVcH_title.png',
|
||||
},
|
||||
},
|
||||
},
|
||||
title1: {
|
||||
id: 'title1',
|
||||
zIndex: 2,
|
||||
left: 44,
|
||||
top: 56,
|
||||
width: 454,
|
||||
height: 50,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'Strategic technology trends',
|
||||
fs: 32 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
subTitle1: {
|
||||
id: 'subTitle1',
|
||||
zIndex: 2,
|
||||
left: 44,
|
||||
top: 93,
|
||||
width: 889,
|
||||
height: 46,
|
||||
title: 'subTitle',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'We expect the 2023 trends to impact enterprise strategies in the coming three years by enabling organizations to address four key priorities:',
|
||||
fs: 18 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(127,127,127)',
|
||||
},
|
||||
},
|
||||
},
|
||||
chart1: {
|
||||
id: 'chart1',
|
||||
zIndex: 2,
|
||||
left: 53,
|
||||
top: 214,
|
||||
width: 125,
|
||||
height: 58,
|
||||
title: 'chart1',
|
||||
description: '',
|
||||
type: PageElementType.SHAPE,
|
||||
shape: {
|
||||
shapeType: BasicShapes.Rect,
|
||||
text: '',
|
||||
shapeProperties: {
|
||||
shapeBackgroundFill: {
|
||||
rgb: 'rgb(105,126,146)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
chartTitle1: {
|
||||
id: 'chartTitle1',
|
||||
zIndex: 3,
|
||||
left: 53,
|
||||
top: 186,
|
||||
width: 84,
|
||||
height: 28,
|
||||
title: 'chartTitle1',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'Optimize',
|
||||
fs: 16 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(127,127,127)',
|
||||
},
|
||||
},
|
||||
},
|
||||
chartNumber1: {
|
||||
id: 'chartNumber1',
|
||||
zIndex: 3,
|
||||
left: 63,
|
||||
top: 230,
|
||||
width: 61,
|
||||
height: 36,
|
||||
title: 'chartNumber1',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: '20%',
|
||||
fs: 22 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
},
|
||||
},
|
||||
chart2: {
|
||||
id: 'chart2',
|
||||
zIndex: 2,
|
||||
left: 178,
|
||||
top: 214,
|
||||
width: 428,
|
||||
height: 58,
|
||||
title: 'chart2',
|
||||
description: '',
|
||||
type: PageElementType.SHAPE,
|
||||
shape: {
|
||||
shapeType: BasicShapes.Rect,
|
||||
text: '',
|
||||
shapeProperties: {
|
||||
shapeBackgroundFill: {
|
||||
rgb: 'rgb(57,74,87)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
chartTitle2: {
|
||||
id: 'chartTitle2',
|
||||
zIndex: 3,
|
||||
left: 178,
|
||||
top: 186,
|
||||
width: 59,
|
||||
height: 28,
|
||||
title: 'chartTitle2',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'Scale',
|
||||
fs: 16 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(127,127,127)',
|
||||
},
|
||||
},
|
||||
},
|
||||
chartNumber2: {
|
||||
id: 'chartNumber2',
|
||||
zIndex: 3,
|
||||
left: 188,
|
||||
top: 230,
|
||||
width: 61,
|
||||
height: 36,
|
||||
title: 'chartNumber2',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: '50%',
|
||||
fs: 22 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
},
|
||||
},
|
||||
chart3: {
|
||||
id: 'chart3',
|
||||
zIndex: 2,
|
||||
left: 605,
|
||||
top: 214,
|
||||
width: 302,
|
||||
height: 58,
|
||||
title: 'chart3',
|
||||
description: '',
|
||||
type: PageElementType.SHAPE,
|
||||
shape: {
|
||||
shapeType: BasicShapes.Rect,
|
||||
text: '',
|
||||
shapeProperties: {
|
||||
shapeBackgroundFill: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
chartTitle3: {
|
||||
id: 'chartTitle3',
|
||||
zIndex: 3,
|
||||
left: 605,
|
||||
top: 186,
|
||||
width: 74,
|
||||
height: 28,
|
||||
title: 'chartTitle3',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'Scale',
|
||||
fs: 16 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(127,127,127)',
|
||||
},
|
||||
},
|
||||
},
|
||||
chartNumber3: {
|
||||
id: 'chartNumber3',
|
||||
zIndex: 3,
|
||||
left: 615,
|
||||
top: 230,
|
||||
width: 61,
|
||||
height: 36,
|
||||
title: 'chartNumber3',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: '30%',
|
||||
fs: 22 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
},
|
||||
},
|
||||
detailTitle1: {
|
||||
id: 'detailTitle1',
|
||||
zIndex: 3,
|
||||
left: 53,
|
||||
top: 326,
|
||||
width: 152,
|
||||
height: 28,
|
||||
title: 'detailTitle1',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'Theme 1: Optimize',
|
||||
fs: 16 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
detailContent1: PAGE3_RICHTEXT_1,
|
||||
detailTitle2: {
|
||||
id: 'detailTitle2',
|
||||
zIndex: 3,
|
||||
left: 334,
|
||||
top: 326,
|
||||
width: 129,
|
||||
height: 28,
|
||||
title: 'detailTitle2',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'Theme 2: Scale',
|
||||
fs: 16 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
detailContent2: PAGE3_RICHTEXT_2,
|
||||
detailTitle3: {
|
||||
id: 'detailTitle3',
|
||||
zIndex: 3,
|
||||
left: 652,
|
||||
top: 326,
|
||||
width: 143,
|
||||
height: 28,
|
||||
title: 'detailTitle3',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'Theme 2: Scale',
|
||||
fs: 16 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
detailContent3: PAGE3_RICHTEXT_3,
|
||||
},
|
||||
};
|
||||
@@ -1,112 +0,0 @@
|
||||
import type { IWorksheetData } from '@univerjs/core';
|
||||
import { BasicShapes, PageElementType, PageType } from '@univerjs/slides';
|
||||
import { SLIDE_WORKBOOK_DATA } from '../../sheets/slide-workbook-data';
|
||||
|
||||
const worksheetConfig = SLIDE_WORKBOOK_DATA.sheets[SLIDE_WORKBOOK_DATA.sheetOrder[0]] as IWorksheetData;
|
||||
const spreadStyles = SLIDE_WORKBOOK_DATA.styles;
|
||||
|
||||
export const DEFAULT_FORTH_PAGE = {
|
||||
id: 'business_1',
|
||||
pageType: PageType.SLIDE,
|
||||
zIndex: 2,
|
||||
title: 'business',
|
||||
description: 'this is second page, business',
|
||||
pageBackgroundFill: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
pageElements: {
|
||||
background1: {
|
||||
id: 'background1',
|
||||
zIndex: 1,
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: 960,
|
||||
height: 540,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.SHAPE,
|
||||
shape: {
|
||||
shapeType: BasicShapes.Rect,
|
||||
text: '',
|
||||
shapeProperties: {
|
||||
shapeBackgroundFill: {
|
||||
rgb: 'rgba(237,237,237,1)',
|
||||
},
|
||||
outline: {
|
||||
outlineFill: {
|
||||
rgb: 'rgba(198,198,198,1)',
|
||||
},
|
||||
weight: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
titleIcon1: {
|
||||
id: 'titleIcon1',
|
||||
zIndex: 2,
|
||||
left: 48,
|
||||
top: 52,
|
||||
width: 117 * 0.3,
|
||||
height: 16 * 0.3,
|
||||
title: 'title Icon',
|
||||
description: '',
|
||||
type: PageElementType.IMAGE,
|
||||
image: {
|
||||
imageProperties: {
|
||||
contentUrl: 'https://release-univer.oss-cn-shenzhen.aliyuncs.com/template-resource/E1MC_gxuoxED7as5FCVcH_title.png',
|
||||
},
|
||||
},
|
||||
},
|
||||
title1: {
|
||||
id: 'title1',
|
||||
zIndex: 2,
|
||||
left: 44,
|
||||
top: 56,
|
||||
width: 454,
|
||||
height: 50,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'The Business Objectives',
|
||||
fs: 32 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
subTitle1: {
|
||||
id: 'subTitle1',
|
||||
zIndex: 2,
|
||||
left: 44,
|
||||
top: 93,
|
||||
width: 889,
|
||||
height: 46,
|
||||
title: 'subTitle',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'What we hope to achieve in the short and long run',
|
||||
fs: 18 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(127,127,127)',
|
||||
},
|
||||
},
|
||||
},
|
||||
spreadSheet1: {
|
||||
id: 'table1',
|
||||
zIndex: 3,
|
||||
left: 30,
|
||||
top: 125,
|
||||
width: 900,
|
||||
height: 400,
|
||||
title: 'table1',
|
||||
description: '',
|
||||
type: PageElementType.SPREADSHEET,
|
||||
spreadsheet: {
|
||||
worksheet: worksheetConfig,
|
||||
styles: spreadStyles,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,314 +0,0 @@
|
||||
import { BasicShapes, PageElementType, PageType } from '@univerjs/slides';
|
||||
|
||||
export const DEFAULT_FIFTH_PAGE = {
|
||||
id: 'technology_1',
|
||||
pageType: PageType.SLIDE,
|
||||
zIndex: 2,
|
||||
title: 'technology',
|
||||
description: 'this is second page, technology',
|
||||
pageBackgroundFill: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
pageElements: {
|
||||
background1: {
|
||||
id: 'background1',
|
||||
zIndex: 1,
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: 960,
|
||||
height: 540,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.SHAPE,
|
||||
shape: {
|
||||
shapeType: BasicShapes.Rect,
|
||||
text: '',
|
||||
shapeProperties: {
|
||||
shapeBackgroundFill: {
|
||||
rgb: 'rgba(237,237,237,1)',
|
||||
},
|
||||
outline: {
|
||||
outlineFill: {
|
||||
rgb: 'rgba(198,198,198,1)',
|
||||
},
|
||||
weight: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
titleIcon1: {
|
||||
id: 'titleIcon1',
|
||||
zIndex: 2,
|
||||
left: 48,
|
||||
top: 52,
|
||||
width: 117 * 0.3,
|
||||
height: 16 * 0.3,
|
||||
title: 'title Icon',
|
||||
description: '',
|
||||
type: PageElementType.IMAGE,
|
||||
image: {
|
||||
imageProperties: {
|
||||
contentUrl: 'https://release-univer.oss-cn-shenzhen.aliyuncs.com/template-resource/E1MC_gxuoxED7as5FCVcH_title.png',
|
||||
},
|
||||
},
|
||||
},
|
||||
title1: {
|
||||
id: 'title1',
|
||||
zIndex: 2,
|
||||
left: 44,
|
||||
top: 56,
|
||||
width: 454,
|
||||
height: 50,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'Sustainable Technology',
|
||||
fs: 32 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
subTitle1: {
|
||||
id: 'subTitle1',
|
||||
zIndex: 2,
|
||||
left: 44,
|
||||
top: 93,
|
||||
width: 889,
|
||||
height: 46,
|
||||
title: 'subTitle',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'Delivering technology alone will not be enough in 2023',
|
||||
fs: 18 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(127,127,127)',
|
||||
},
|
||||
},
|
||||
},
|
||||
picture1: {
|
||||
id: 'picture1',
|
||||
zIndex: 2,
|
||||
left: 53,
|
||||
top: 151,
|
||||
width: 258,
|
||||
height: 156,
|
||||
title: 'title Icon',
|
||||
description: '',
|
||||
type: PageElementType.IMAGE,
|
||||
image: {
|
||||
imageProperties: {
|
||||
contentUrl: 'https://release-univer.oss-cn-shenzhen.aliyuncs.com/template-resource/ITU9ANLPCLVZayK4cai3F_P1.png',
|
||||
},
|
||||
},
|
||||
},
|
||||
picture2: {
|
||||
id: 'picture2',
|
||||
zIndex: 2,
|
||||
left: 315,
|
||||
top: 151,
|
||||
width: 241,
|
||||
height: 156,
|
||||
title: 'title Icon',
|
||||
description: '',
|
||||
type: PageElementType.IMAGE,
|
||||
image: {
|
||||
imageProperties: {
|
||||
contentUrl: 'https://release-univer.oss-cn-shenzhen.aliyuncs.com/template-resource/SPY91aael53o6PASWMISg_P2.png',
|
||||
},
|
||||
},
|
||||
},
|
||||
picture3: {
|
||||
id: 'picture3',
|
||||
zIndex: 2,
|
||||
left: 53,
|
||||
top: 310,
|
||||
width: 258,
|
||||
height: 156,
|
||||
title: 'title Icon',
|
||||
description: '',
|
||||
type: PageElementType.IMAGE,
|
||||
image: {
|
||||
imageProperties: {
|
||||
contentUrl: 'https://release-univer.oss-cn-shenzhen.aliyuncs.com/template-resource/ejART8fy6hJATqRPEwv0i_P3.png',
|
||||
},
|
||||
},
|
||||
},
|
||||
picture4: {
|
||||
id: 'picture4',
|
||||
zIndex: 2,
|
||||
left: 310,
|
||||
top: 315,
|
||||
width: 241,
|
||||
height: 156,
|
||||
title: 'title Icon',
|
||||
description: '',
|
||||
type: PageElementType.IMAGE,
|
||||
image: {
|
||||
imageProperties: {
|
||||
contentUrl: 'https://release-univer.oss-cn-shenzhen.aliyuncs.com/template-resource/dMWplOwGie39Rduf0IFlm_P4.jpg',
|
||||
},
|
||||
},
|
||||
},
|
||||
detailTitle1: {
|
||||
id: 'detailTitle1',
|
||||
zIndex: 3,
|
||||
left: 580,
|
||||
top: 138,
|
||||
width: 75,
|
||||
height: 28,
|
||||
title: 'detailTitle1',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'In short:',
|
||||
fs: 16 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
detailContent1: {
|
||||
id: 'detailContent1',
|
||||
zIndex: 3,
|
||||
left: 580,
|
||||
top: 167,
|
||||
width: 373,
|
||||
height: 81,
|
||||
title: 'detailContent1',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'Investments in sustainable technology also have the potential to create greater operational resiliency and financial performance, while providing new avenues for growth.',
|
||||
fs: 12 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(127,127,127)',
|
||||
},
|
||||
},
|
||||
},
|
||||
listTitle1: {
|
||||
id: 'listTitle1',
|
||||
zIndex: 3,
|
||||
left: 580,
|
||||
top: 138,
|
||||
width: 75,
|
||||
height: 28,
|
||||
title: 'listTitle1',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'In short:',
|
||||
fs: 16 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
listTitlePicture1: {
|
||||
id: 'listTitlePicture1',
|
||||
zIndex: 2,
|
||||
left: 572,
|
||||
top: 261,
|
||||
width: 53,
|
||||
height: 53,
|
||||
title: 'title Icon',
|
||||
description: '',
|
||||
type: PageElementType.IMAGE,
|
||||
image: {
|
||||
imageProperties: {
|
||||
contentUrl: 'https://release-univer.oss-cn-shenzhen.aliyuncs.com/template-resource/_Ae7XkF1f13c2bkxomlfV_icon1.png',
|
||||
},
|
||||
},
|
||||
},
|
||||
listContent1: {
|
||||
id: 'listContent1',
|
||||
zIndex: 3,
|
||||
left: 637,
|
||||
top: 265,
|
||||
width: 309,
|
||||
height: 61,
|
||||
title: 'listContent1',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'Gartner’s Top 10 Strategic Technology Trends will help fulfill your business needs to optimize, scale or pioneer.',
|
||||
fs: 12 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(127,127,127)',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
listTitlePicture2: {
|
||||
id: 'listTitlePicture2',
|
||||
zIndex: 2,
|
||||
left: 572,
|
||||
top: 341,
|
||||
width: 53,
|
||||
height: 53,
|
||||
title: 'title Icon',
|
||||
description: '',
|
||||
type: PageElementType.IMAGE,
|
||||
image: {
|
||||
imageProperties: {
|
||||
contentUrl: 'https://release-univer.oss-cn-shenzhen.aliyuncs.com/template-resource/G-OVAn8THqr-7u4OXZKJm_icon2.png',
|
||||
},
|
||||
},
|
||||
},
|
||||
listContent2: {
|
||||
id: 'listContent2',
|
||||
zIndex: 3,
|
||||
left: 637,
|
||||
top: 345,
|
||||
width: 309,
|
||||
height: 61,
|
||||
title: 'listContent2',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'The trends allow you to align your technology innovation with the future strategic objectives of your enterprise.',
|
||||
fs: 12 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(127,127,127)',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
listTitlePicture3: {
|
||||
id: 'listTitlePicture3',
|
||||
zIndex: 2,
|
||||
left: 572,
|
||||
top: 421,
|
||||
width: 53,
|
||||
height: 53,
|
||||
title: 'title Icon',
|
||||
description: '',
|
||||
type: PageElementType.IMAGE,
|
||||
image: {
|
||||
imageProperties: {
|
||||
contentUrl: 'https://release-univer.oss-cn-shenzhen.aliyuncs.com/template-resource/MPQJUz-b6yYfF-fa4TSSz_icon3.png',
|
||||
},
|
||||
},
|
||||
},
|
||||
listContent3: {
|
||||
id: 'listContent3',
|
||||
zIndex: 3,
|
||||
left: 637,
|
||||
top: 425,
|
||||
width: 309,
|
||||
height: 61,
|
||||
title: 'listContent3',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'Investments in sustainable technology provide operational and financial benefits, and can create growth opportunities.',
|
||||
fs: 12 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(127,127,127)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,105 +0,0 @@
|
||||
import { BasicShapes, PageElementType, PageType } from '@univerjs/slides';
|
||||
import { DEFAULT_DOCUMENT_DATA_EN } from '../../docs/default-document-data-en';
|
||||
|
||||
export const DEFAULT_SIXTH_PAGE = {
|
||||
id: 'richText_1',
|
||||
pageType: PageType.SLIDE,
|
||||
zIndex: 2,
|
||||
title: 'business',
|
||||
description: 'this is fix page, rich text',
|
||||
pageBackgroundFill: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
pageElements: {
|
||||
background1: {
|
||||
id: 'background1',
|
||||
zIndex: 1,
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: 960,
|
||||
height: 540,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.SHAPE,
|
||||
shape: {
|
||||
shapeType: BasicShapes.Rect,
|
||||
text: '',
|
||||
shapeProperties: {
|
||||
shapeBackgroundFill: {
|
||||
rgb: 'rgba(237,237,237,1)',
|
||||
},
|
||||
outline: {
|
||||
outlineFill: {
|
||||
rgb: 'rgba(198,198,198,1)',
|
||||
},
|
||||
weight: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
titleIcon1: {
|
||||
id: 'titleIcon1',
|
||||
zIndex: 2,
|
||||
left: 48,
|
||||
top: 52,
|
||||
width: 117 * 0.3,
|
||||
height: 16 * 0.3,
|
||||
title: 'title Icon',
|
||||
description: '',
|
||||
type: PageElementType.IMAGE,
|
||||
image: {
|
||||
imageProperties: {
|
||||
contentUrl: 'https://release-univer.oss-cn-shenzhen.aliyuncs.com/template-resource/E1MC_gxuoxED7as5FCVcH_title.png',
|
||||
},
|
||||
},
|
||||
},
|
||||
title1: {
|
||||
id: 'title1',
|
||||
zIndex: 2,
|
||||
left: 44,
|
||||
top: 56,
|
||||
width: 454,
|
||||
height: 50,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'The Work-like Editor',
|
||||
fs: 32 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
subTitle1: {
|
||||
id: 'subTitle1',
|
||||
zIndex: 2,
|
||||
left: 44,
|
||||
top: 93,
|
||||
width: 889,
|
||||
height: 46,
|
||||
title: 'subTitle',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'Open source WYSIWYG editor built for the modern web',
|
||||
fs: 18 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(127,127,127)',
|
||||
},
|
||||
},
|
||||
},
|
||||
document: {
|
||||
id: 'table1',
|
||||
zIndex: 3,
|
||||
left: 30,
|
||||
top: 125,
|
||||
width: 900,
|
||||
height: 400,
|
||||
title: 'table1',
|
||||
description: '',
|
||||
type: PageElementType.DOCUMENT,
|
||||
document: DEFAULT_DOCUMENT_DATA_EN,
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,163 +0,0 @@
|
||||
import { BasicShapes, PageElementType, PageType } from '@univerjs/slides';
|
||||
import { generateUnlimitedSlideData } from '../unlimited-slide-data';
|
||||
|
||||
export const DEFAULT_SEVEN_PAGE = {
|
||||
id: 'unlimited_1',
|
||||
pageType: PageType.SLIDE,
|
||||
zIndex: 1,
|
||||
title: 'unlimited',
|
||||
description: 'this is seven page, unlimited',
|
||||
pageBackgroundFill: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
pageElements: {
|
||||
background1: {
|
||||
id: 'background1',
|
||||
zIndex: 0,
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: 960,
|
||||
height: 540,
|
||||
title: 'background',
|
||||
description: '',
|
||||
type: PageElementType.IMAGE,
|
||||
image: {
|
||||
imageProperties: {
|
||||
contentUrl: 'https://release-univer.oss-cn-shenzhen.aliyuncs.com/template-resource/jYGEpeogMHxvwoiSqIMMn_Picture1.jpg',
|
||||
},
|
||||
},
|
||||
},
|
||||
mask1: {
|
||||
id: 'mask1',
|
||||
zIndex: 1,
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: 960,
|
||||
height: 540,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.SHAPE,
|
||||
shape: {
|
||||
shapeType: BasicShapes.Rect,
|
||||
text: '',
|
||||
shapeProperties: {
|
||||
shapeBackgroundFill: {
|
||||
rgb: 'rgba(0,0,0,0.7)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
text1: {
|
||||
id: 'text1',
|
||||
zIndex: 2,
|
||||
left: 300,
|
||||
top: 200,
|
||||
width: 400,
|
||||
height: 140,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'Univer slide',
|
||||
fs: 64 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
bl: 1,
|
||||
},
|
||||
},
|
||||
centerRect1: {
|
||||
id: 'centerRect1',
|
||||
zIndex: 1,
|
||||
left: 378,
|
||||
top: 0,
|
||||
width: 204,
|
||||
height: 144,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.SHAPE,
|
||||
shape: {
|
||||
shapeType: BasicShapes.Rect,
|
||||
text: '',
|
||||
shapeProperties: {
|
||||
shapeBackgroundFill: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
year1: {
|
||||
id: 'year1',
|
||||
zIndex: 2,
|
||||
left: 430,
|
||||
top: 42,
|
||||
width: 130,
|
||||
height: 50,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: '2024',
|
||||
fs: 48 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
bl: 1,
|
||||
},
|
||||
},
|
||||
content1: {
|
||||
id: 'content1',
|
||||
zIndex: 2,
|
||||
left: 80,
|
||||
top: 300,
|
||||
width: 780,
|
||||
height: 140,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'The concepts national income and national product have roughly the same value and can be used interchangeably if our interest is in their sum total which is measured as the market value of the total output of goods and services of an economy in a given period, usually a year.',
|
||||
fs: 14 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
bl: 1,
|
||||
},
|
||||
},
|
||||
slide1: {
|
||||
id: 'slide',
|
||||
zIndex: 3,
|
||||
left: (960 * (1 - 0.9)) / 2,
|
||||
top: (540 * (1 - 0.9)) / 2,
|
||||
width: 960,
|
||||
height: 540,
|
||||
scaleX: 0.9,
|
||||
scaleY: 0.9,
|
||||
title: 'slide',
|
||||
description: '',
|
||||
type: PageElementType.SLIDE,
|
||||
slide: generateUnlimitedSlideData(
|
||||
0.9,
|
||||
generateUnlimitedSlideData(
|
||||
0.9,
|
||||
generateUnlimitedSlideData(
|
||||
0.9,
|
||||
generateUnlimitedSlideData(
|
||||
0.9,
|
||||
generateUnlimitedSlideData(
|
||||
0.9,
|
||||
generateUnlimitedSlideData(
|
||||
0.9,
|
||||
generateUnlimitedSlideData(
|
||||
0.9,
|
||||
generateUnlimitedSlideData(0.9, generateUnlimitedSlideData(0.9))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,29 +0,0 @@
|
||||
import type { ISlideData } from '@univerjs/slides';
|
||||
import { DEFAULT_FIRST_PAGE } from './default-pages/page1';
|
||||
import { DEFAULT_SECOND_PAGE } from './default-pages/page2';
|
||||
import { DEFAULT_THIRD_PAGE } from './default-pages/page3';
|
||||
import { DEFAULT_FORTH_PAGE } from './default-pages/page4';
|
||||
import { DEFAULT_FIFTH_PAGE } from './default-pages/page5';
|
||||
import { DEFAULT_SIXTH_PAGE } from './default-pages/page6';
|
||||
import { DEFAULT_SEVEN_PAGE } from './default-pages/page7';
|
||||
|
||||
export const DEFAULT_SLIDE_DATA: ISlideData = {
|
||||
id: 'slide_test',
|
||||
title: 'UniverSlide',
|
||||
pageSize: {
|
||||
width: 960,
|
||||
height: 540,
|
||||
},
|
||||
body: {
|
||||
pages: {
|
||||
cover_1: DEFAULT_FIRST_PAGE,
|
||||
catalog_1: DEFAULT_SECOND_PAGE,
|
||||
strategic_1: DEFAULT_THIRD_PAGE,
|
||||
technology_1: DEFAULT_FIFTH_PAGE,
|
||||
richText_1: DEFAULT_SIXTH_PAGE,
|
||||
business_1: DEFAULT_FORTH_PAGE,
|
||||
unlimited_1: DEFAULT_SEVEN_PAGE,
|
||||
},
|
||||
pageOrder: ['cover_1', 'catalog_1', 'strategic_1', 'technology_1', 'richText_1', 'business_1', 'unlimited_1'],
|
||||
},
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
export * from './default-slide-data';
|
||||
@@ -1,77 +0,0 @@
|
||||
import { PresetListType } from '@univerjs/core';
|
||||
import { PageElementType } from '@univerjs/slides';
|
||||
|
||||
export const PAGE3_RICHTEXT_1 = {
|
||||
id: 'detailContent1',
|
||||
zIndex: 3,
|
||||
left: 53,
|
||||
top: 363,
|
||||
width: 273,
|
||||
height: 54,
|
||||
title: 'detailContent1',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
rich: {
|
||||
id: 'd',
|
||||
body: {
|
||||
dataStream: 'Digital Immune System\rApplied Observability\r\n',
|
||||
textRuns: [
|
||||
{
|
||||
st: 0,
|
||||
ed: 20,
|
||||
ts: {
|
||||
fs: 12 * 0.75,
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 22,
|
||||
ed: 42,
|
||||
ts: {
|
||||
fs: 12 * 0.75,
|
||||
},
|
||||
},
|
||||
],
|
||||
paragraphs: [
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_slides_rich_text_page3_richtext1_1',
|
||||
startIndex: 21,
|
||||
bullet: {
|
||||
listType: PresetListType.ORDER_LIST,
|
||||
listId: 'orderList',
|
||||
nestingLevel: 0,
|
||||
textStyle: {
|
||||
fs: 20 * 0.75,
|
||||
},
|
||||
},
|
||||
paragraphStyle: {
|
||||
spaceBelow: { v: 15 },
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_slides_rich_text_page3_richtext1_2',
|
||||
startIndex: 43,
|
||||
bullet: {
|
||||
listType: PresetListType.ORDER_LIST,
|
||||
listId: 'orderList',
|
||||
nestingLevel: 0,
|
||||
textStyle: {
|
||||
fs: 20 * 0.75,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
documentStyle: {
|
||||
pageSize: {
|
||||
width: undefined,
|
||||
height: undefined,
|
||||
},
|
||||
marginTop: 2,
|
||||
marginBottom: 2,
|
||||
marginRight: 0,
|
||||
marginLeft: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,77 +0,0 @@
|
||||
import { PresetListType } from '@univerjs/core';
|
||||
import { PageElementType } from '@univerjs/slides';
|
||||
|
||||
export const PAGE3_RICHTEXT_2 = {
|
||||
id: 'detailContent2',
|
||||
zIndex: 3,
|
||||
left: 334,
|
||||
top: 363,
|
||||
width: 273,
|
||||
height: 120,
|
||||
title: 'detailContent2',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
rich: {
|
||||
id: 'd',
|
||||
body: {
|
||||
dataStream: 'combine SaaS, PaaS and IaaS with tailored\rprovides a curated set of tools, capabilities and processes that are packaged for easy consumption by developers and end users\r\n',
|
||||
textRuns: [
|
||||
{
|
||||
st: 0,
|
||||
ed: 40,
|
||||
ts: {
|
||||
fs: 12 * 0.75,
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 42,
|
||||
ed: 167,
|
||||
ts: {
|
||||
fs: 12 * 0.75,
|
||||
},
|
||||
},
|
||||
],
|
||||
paragraphs: [
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_slides_rich_text_page3_richtext2_1',
|
||||
startIndex: 41,
|
||||
bullet: {
|
||||
listType: PresetListType.ORDER_LIST,
|
||||
listId: 'orderList',
|
||||
nestingLevel: 0,
|
||||
textStyle: {
|
||||
fs: 20 * 0.75,
|
||||
},
|
||||
},
|
||||
paragraphStyle: {
|
||||
spaceBelow: { v: 15 },
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_slides_rich_text_page3_richtext2_2',
|
||||
startIndex: 168,
|
||||
bullet: {
|
||||
listType: PresetListType.ORDER_LIST,
|
||||
listId: 'orderList',
|
||||
nestingLevel: 0,
|
||||
textStyle: {
|
||||
fs: 20 * 0.75,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
documentStyle: {
|
||||
pageSize: {
|
||||
width: undefined,
|
||||
height: undefined,
|
||||
},
|
||||
marginTop: 2,
|
||||
marginBottom: 2,
|
||||
marginRight: 0,
|
||||
marginLeft: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,77 +0,0 @@
|
||||
import { PresetListType } from '@univerjs/core';
|
||||
import { PageElementType } from '@univerjs/slides';
|
||||
|
||||
export const PAGE3_RICHTEXT_3 = {
|
||||
id: 'detailContent3',
|
||||
zIndex: 3,
|
||||
left: 652,
|
||||
top: 363,
|
||||
width: 273,
|
||||
height: 130,
|
||||
title: 'detailContent3',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
rich: {
|
||||
id: 'd',
|
||||
body: {
|
||||
dataStream: 'SuperApps are more than composite applications that aggregate services.\rAdaptive AI allows for model behavior change post-deployment by using real-time feedback\r\n',
|
||||
textRuns: [
|
||||
{
|
||||
st: 0,
|
||||
ed: 70,
|
||||
ts: {
|
||||
fs: 12 * 0.75,
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 72,
|
||||
ed: 159,
|
||||
ts: {
|
||||
fs: 12 * 0.75,
|
||||
},
|
||||
},
|
||||
],
|
||||
paragraphs: [
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_slides_rich_text_page3_richtext3_1',
|
||||
startIndex: 71,
|
||||
bullet: {
|
||||
listType: PresetListType.ORDER_LIST,
|
||||
listId: 'orderList',
|
||||
nestingLevel: 0,
|
||||
textStyle: {
|
||||
fs: 20 * 0.75,
|
||||
},
|
||||
},
|
||||
paragraphStyle: {
|
||||
spaceBelow: { v: 15 },
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_slides_rich_text_page3_richtext3_2',
|
||||
startIndex: 160,
|
||||
bullet: {
|
||||
listType: PresetListType.ORDER_LIST,
|
||||
listId: 'orderList',
|
||||
nestingLevel: 0,
|
||||
textStyle: {
|
||||
fs: 20 * 0.75,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
documentStyle: {
|
||||
pageSize: {
|
||||
width: undefined,
|
||||
height: undefined,
|
||||
},
|
||||
marginTop: 2,
|
||||
marginBottom: 2,
|
||||
marginRight: 0,
|
||||
marginLeft: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,166 +0,0 @@
|
||||
import type { IDocumentData } from '@univerjs/core';
|
||||
import { BooleanNumber, ColumnSeparatorType, PresetListType, SectionType } from '@univerjs/core';
|
||||
|
||||
export const PAGE5_RICHTEXT_1: IDocumentData = {
|
||||
id: 'd',
|
||||
body: {
|
||||
dataStream:
|
||||
'What’s New in the 2022 Gartner Hype Cycle for Emerging Technologies\rEmerging technologies for 2022 fit into three main themes: evolving/expanding immersive experiences, accelerated artificial intelligence automation, and optimized technologist delivery.\rThe 2022 Gartner Hype Cycle identifies 25 must-know emerging technologies designed to help enterprise architecture and technology innovation leaders: \rExpand immersive experiences\rAccelerate artificial intelligence (AI) automation\rOptimize technologist delivery \r\n',
|
||||
textRuns: [
|
||||
{
|
||||
st: 0,
|
||||
ed: 67,
|
||||
ts: {
|
||||
bl: BooleanNumber.TRUE,
|
||||
fs: 24 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(205, 40, 86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 68,
|
||||
ed: 253,
|
||||
ts: {
|
||||
fs: 16 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(0, 255, 86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 254,
|
||||
ed: 404,
|
||||
ts: {
|
||||
fs: 14 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(0, 255, 255)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 405,
|
||||
ed: 433,
|
||||
ts: {
|
||||
fs: 16 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(255, 255, 86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 434,
|
||||
ed: 484,
|
||||
ts: {
|
||||
fs: 16 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(0, 255, 186)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
st: 485,
|
||||
ed: 515,
|
||||
ts: {
|
||||
fs: 16 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(60, 255, 86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
paragraphs: [
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_slides_rich_text_page5_richtext1_1',
|
||||
startIndex: 67,
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_slides_rich_text_page5_richtext1_2',
|
||||
startIndex: 253,
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 20 },
|
||||
indentFirstLine: { v: 20 },
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_slides_rich_text_page5_richtext1_3',
|
||||
startIndex: 404,
|
||||
paragraphStyle: {
|
||||
spaceAbove: { v: 20 },
|
||||
indentFirstLine: { v: 20 },
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_slides_rich_text_page5_richtext1_4',
|
||||
startIndex: 433,
|
||||
bullet: {
|
||||
listType: PresetListType.BULLET_LIST,
|
||||
listId: 'testBullet',
|
||||
nestingLevel: 0,
|
||||
textStyle: {
|
||||
fs: 20 * 0.75,
|
||||
},
|
||||
},
|
||||
paragraphStyle: {
|
||||
lineSpacing: 1.5,
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_slides_rich_text_page5_richtext1_5',
|
||||
startIndex: 484,
|
||||
bullet: {
|
||||
listType: PresetListType.BULLET_LIST,
|
||||
listId: 'testBullet',
|
||||
nestingLevel: 0,
|
||||
textStyle: {
|
||||
fs: 20 * 0.75,
|
||||
},
|
||||
},
|
||||
paragraphStyle: {
|
||||
lineSpacing: 1.5,
|
||||
},
|
||||
},
|
||||
{
|
||||
paragraphId: 'para_common_mockdata_src_slides_rich_text_page5_richtext1_6',
|
||||
startIndex: 516,
|
||||
bullet: {
|
||||
listType: PresetListType.BULLET_LIST,
|
||||
listId: 'testBullet',
|
||||
nestingLevel: 0,
|
||||
textStyle: {
|
||||
fs: 20 * 0.75,
|
||||
},
|
||||
},
|
||||
paragraphStyle: {
|
||||
lineSpacing: 1.5,
|
||||
},
|
||||
},
|
||||
],
|
||||
sectionBreaks: [
|
||||
{
|
||||
sectionId: 'section_mockdata_slide_page5_richtext1_1',
|
||||
startIndex: 517,
|
||||
columnProperties: [
|
||||
{
|
||||
width: 200,
|
||||
paddingEnd: 5,
|
||||
},
|
||||
],
|
||||
columnSeparatorType: ColumnSeparatorType.NONE,
|
||||
sectionType: SectionType.SECTION_TYPE_UNSPECIFIED,
|
||||
// textDirection: textDirectionDocument,
|
||||
// contentDirection: textDirection!,
|
||||
},
|
||||
],
|
||||
},
|
||||
documentStyle: {
|
||||
pageSize: {
|
||||
width: undefined,
|
||||
height: undefined,
|
||||
},
|
||||
marginTop: 0,
|
||||
marginBottom: 0,
|
||||
marginRight: 2,
|
||||
marginLeft: 2,
|
||||
},
|
||||
};
|
||||
@@ -1,172 +0,0 @@
|
||||
import type { ISlideData } from '@univerjs/slides';
|
||||
import { BasicShapes, PageElementType, PageType } from '@univerjs/slides';
|
||||
import { DEFAULT_SECOND_PAGE } from './default-pages/page2';
|
||||
import { DEFAULT_THIRD_PAGE } from './default-pages/page3';
|
||||
import { DEFAULT_FORTH_PAGE } from './default-pages/page4';
|
||||
import { DEFAULT_FIFTH_PAGE } from './default-pages/page5';
|
||||
import { DEFAULT_SIXTH_PAGE } from './default-pages/page6';
|
||||
|
||||
export function generateUnlimitedSlideData(ratio: number = 1, slideData?: ISlideData): ISlideData {
|
||||
const result: ISlideData = {
|
||||
id: 'slide_unlimited',
|
||||
title: 'UniverSlide',
|
||||
pageSize: {
|
||||
width: 960,
|
||||
height: 540,
|
||||
},
|
||||
body: {
|
||||
pages: {
|
||||
unlimited_1: {
|
||||
id: 'unlimited_1',
|
||||
pageType: PageType.SLIDE,
|
||||
zIndex: 1,
|
||||
title: 'unlimited',
|
||||
description: 'this is seven page, unlimited',
|
||||
pageBackgroundFill: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
pageElements: {
|
||||
background1: {
|
||||
id: 'background1',
|
||||
zIndex: 0,
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: 960,
|
||||
height: 540,
|
||||
title: 'background',
|
||||
description: '',
|
||||
type: PageElementType.IMAGE,
|
||||
image: {
|
||||
imageProperties: {
|
||||
contentUrl: 'https://release-univer.oss-cn-shenzhen.aliyuncs.com/template-resource/jYGEpeogMHxvwoiSqIMMn_Picture1.jpg',
|
||||
},
|
||||
},
|
||||
},
|
||||
mask1: {
|
||||
id: 'mask1',
|
||||
zIndex: 1,
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: 960,
|
||||
height: 540,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.SHAPE,
|
||||
shape: {
|
||||
shapeType: BasicShapes.Rect,
|
||||
text: '',
|
||||
shapeProperties: {
|
||||
shapeBackgroundFill: {
|
||||
rgb: 'rgba(0,0,0,0.7)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
text1: {
|
||||
id: 'text1',
|
||||
zIndex: 2,
|
||||
left: 300,
|
||||
top: 200,
|
||||
width: 400,
|
||||
height: 140,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'Univer slide',
|
||||
fs: 64 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
bl: 1,
|
||||
},
|
||||
},
|
||||
centerRect1: {
|
||||
id: 'centerRect1',
|
||||
zIndex: 1,
|
||||
left: 378,
|
||||
top: 0,
|
||||
width: 204,
|
||||
height: 144,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.SHAPE,
|
||||
shape: {
|
||||
shapeType: BasicShapes.Rect,
|
||||
text: '',
|
||||
shapeProperties: {
|
||||
shapeBackgroundFill: {
|
||||
rgb: 'rgb(244,79,86)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
year1: {
|
||||
id: 'year1',
|
||||
zIndex: 2,
|
||||
left: 430,
|
||||
top: 42,
|
||||
width: 130,
|
||||
height: 50,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: '2024',
|
||||
fs: 48 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
bl: 1,
|
||||
},
|
||||
},
|
||||
content1: {
|
||||
id: 'content1',
|
||||
zIndex: 2,
|
||||
left: 80,
|
||||
top: 300,
|
||||
width: 780,
|
||||
height: 140,
|
||||
title: 'mask',
|
||||
description: '',
|
||||
type: PageElementType.TEXT,
|
||||
richText: {
|
||||
text: 'The concepts national income and national product have roughly the same value and can be used interchangeably if our interest is in their sum total which is measured as the market value of the total output of goods and services of an economy in a given period, usually a year.',
|
||||
fs: 14 * 0.75,
|
||||
cl: {
|
||||
rgb: 'rgb(255,255,255)',
|
||||
},
|
||||
bl: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
catalog_1: DEFAULT_SECOND_PAGE,
|
||||
strategic_1: DEFAULT_THIRD_PAGE,
|
||||
technology_1: DEFAULT_FIFTH_PAGE,
|
||||
richText_1: DEFAULT_SIXTH_PAGE,
|
||||
business_1: DEFAULT_FORTH_PAGE,
|
||||
},
|
||||
pageOrder: ['unlimited_1', 'catalog_1', 'strategic_1', 'technology_1', 'richText_1', 'business_1'],
|
||||
},
|
||||
};
|
||||
|
||||
if (slideData) {
|
||||
result.body!.pages.unlimited_1.pageElements.slide = {
|
||||
id: 'slide',
|
||||
zIndex: 3,
|
||||
left: (960 * (1 - ratio)) / 2,
|
||||
top: (540 * (1 - ratio)) / 2,
|
||||
width: 960,
|
||||
height: 540,
|
||||
scaleX: ratio,
|
||||
scaleY: ratio,
|
||||
title: 'slide',
|
||||
description: '',
|
||||
type: PageElementType.SLIDE,
|
||||
slide: slideData,
|
||||
};
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"extends": "@univerjs-infra/shared/tsconfigs/base",
|
||||
"compilerOptions": {
|
||||
"rootDir": ".",
|
||||
"outDir": "lib/types"
|
||||
},
|
||||
"include": ["src", "scripts"]
|
||||
}
|
||||
@@ -233,7 +233,6 @@ export const noBarrelImportPreset = (): Linter.Config => {
|
||||
'**/*.tsx',
|
||||
'**/*.d.ts',
|
||||
'**/tsdown.config.ts',
|
||||
'playwright.config.ts',
|
||||
'**/*.spec.ts',
|
||||
'**/*.spec.tsx',
|
||||
'**/*.test.ts',
|
||||
|
||||
@@ -2,27 +2,22 @@
|
||||
|
||||
## How to Investigate Memory Leak
|
||||
|
||||
First you need to run the demo in E2E mode:
|
||||
Start the workbench and select the smallest route that reproduces the leak from the navigation bar:
|
||||
|
||||
```shell
|
||||
pnpm dev:e2e
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
Then, you can use the Chrome DevTools to investigate the memory leak.
|
||||
|
||||
You can create a `Workbook` and then dispose it from Console by running:
|
||||
Take a baseline heap snapshot in Chrome DevTools, exercise the behavior, then dispose the mounted instance from the Console:
|
||||
|
||||
```javascript
|
||||
E2EControllerAPI.loadAndRelease()
|
||||
window.univer?.dispose();
|
||||
delete window.univer;
|
||||
delete window.univerAPI;
|
||||
document.querySelector('#app')?.replaceChildren();
|
||||
```
|
||||
|
||||
And you can take profiles of the application and see if `Workbook` instances are being retained.
|
||||
|
||||
You can also see if the `Univer` instance is being retained after we dispose it by running in Console:
|
||||
|
||||
```javascript
|
||||
E2EControllerAPI.disposeUniver()
|
||||
```
|
||||
Force garbage collection and take another snapshot. Reload the page between runs so each measurement starts from a fresh fixture.
|
||||
|
||||
## Frequent Reasons for Memory Leak
|
||||
|
||||
|
||||
@@ -290,9 +290,8 @@ Principios de separación:
|
||||
```text
|
||||
.
|
||||
├── packages/ Paquetes core, motores, tipos de documento, plugins UI y plugins de funciones
|
||||
├── examples/ Demos locales de navegador y Node.js usadas para desarrollo
|
||||
├── common/ Herramientas internas compartidas, mock data, storybook y utilidades
|
||||
├── e2e/ Pruebas Playwright y de comparación visual
|
||||
├── examples/ Banco de trabajo Vite todo-en-uno para desarrollo local en navegador
|
||||
├── common/ Herramientas internas compartidas, storybook y utilidades
|
||||
├── tests/ Proyectos adicionales de pruebas de integración
|
||||
└── docs/ Notas de arquitectura, imágenes y documentación local del repositorio
|
||||
```
|
||||
@@ -317,12 +316,12 @@ Comandos útiles:
|
||||
|
||||
| Comando | Propósito |
|
||||
| --- | --- |
|
||||
| `pnpm dev` | Inicia la aplicación local de ejemplos. |
|
||||
| `pnpm dev` | Compila y previsualiza el banco de trabajo todo-en-uno de bajo consumo sin HMR. |
|
||||
| `pnpm dev:source` | Inicia el banco de trabajo desde el código fuente con HMR; el arranque y el uso de memoria son mayores. |
|
||||
| `pnpm build` | Compila los paquetes del workspace, excluyendo paquetes internos de common. |
|
||||
| `pnpm test` | Ejecuta pruebas unitarias mediante Turbo. |
|
||||
| `pnpm typecheck` | Ejecuta comprobaciones TypeScript mediante Turbo. |
|
||||
| `pnpm lint` | Ejecuta ESLint. |
|
||||
| `pnpm test:e2e` | Ejecuta pruebas Playwright. |
|
||||
| `pnpm storybook:dev` | Inicia Storybook para desarrollo de componentes UI. |
|
||||
|
||||
Lee [CONTRIBUTING.md](../../CONTRIBUTING.md) antes de abrir un pull request.
|
||||
|
||||
@@ -291,9 +291,8 @@ Boundary principles:
|
||||
```text
|
||||
.
|
||||
├── packages/ コアパッケージ、エンジン、文書タイプ、UI プラグイン、機能プラグイン
|
||||
├── examples/ 開発用のローカルブラウザ/Node.js デモ
|
||||
├── common/ 共有内部ツール、mock data、storybook、ユーティリティ
|
||||
├── e2e/ Playwright とビジュアル比較テスト
|
||||
├── examples/ ローカルブラウザ開発用のオールインワン Vite ワークベンチ
|
||||
├── common/ 共有内部ツール、storybook、ユーティリティ
|
||||
├── tests/ 追加の統合テストプロジェクト
|
||||
└── docs/ アーキテクチャメモ、画像、リポジトリ内ドキュメント
|
||||
```
|
||||
@@ -318,12 +317,12 @@ pnpm dev
|
||||
|
||||
| コマンド | 用途 |
|
||||
| --- | --- |
|
||||
| `pnpm dev` | ローカル examples アプリを起動します。 |
|
||||
| `pnpm dev` | 低メモリのオールインワンワークベンチをビルドし、HMR なしでプレビューします。 |
|
||||
| `pnpm dev:source` | HMR 対応でソースから起動します。コールドスタートとメモリ使用量は増加します。 |
|
||||
| `pnpm build` | 内部 common パッケージを除いて workspace パッケージをビルドします。 |
|
||||
| `pnpm test` | Turbo 経由でユニットテストを実行します。 |
|
||||
| `pnpm typecheck` | Turbo 経由で TypeScript チェックを実行します。 |
|
||||
| `pnpm lint` | ESLint を実行します。 |
|
||||
| `pnpm test:e2e` | Playwright テストを実行します。 |
|
||||
| `pnpm storybook:dev` | UI コンポーネント開発用の Storybook を起動します。 |
|
||||
|
||||
Pull request を作成する前に [CONTRIBUTING.md](../../CONTRIBUTING.md) を読んでください。
|
||||
|
||||
@@ -291,9 +291,8 @@ Boundary principles:
|
||||
```text
|
||||
.
|
||||
├── packages/ Core packages, engines, document types, UI plugins, feature plugins
|
||||
├── examples/ 개발에 사용하는 로컬 브라우저 및 Node.js 데모
|
||||
├── common/ 공유 내부 도구, mock data, storybook, utilities
|
||||
├── e2e/ Playwright 및 visual comparison tests
|
||||
├── examples/ 로컬 브라우저 개발을 위한 올인원 Vite workbench
|
||||
├── common/ 공유 내부 도구, storybook, utilities
|
||||
├── tests/ 추가 integration test projects
|
||||
└── docs/ architecture notes, images, repository-local documentation
|
||||
```
|
||||
@@ -318,12 +317,12 @@ pnpm dev
|
||||
|
||||
| 명령 | 목적 |
|
||||
| --- | --- |
|
||||
| `pnpm dev` | 로컬 examples 앱을 시작합니다. |
|
||||
| `pnpm dev` | 저메모리 올인원 workbench를 빌드하고 HMR 없이 미리 봅니다. |
|
||||
| `pnpm dev:source` | HMR로 소스 workbench를 시작하며 콜드 스타트와 메모리 사용량이 더 큽니다. |
|
||||
| `pnpm build` | 내부 common 패키지를 제외하고 workspace 패키지를 빌드합니다. |
|
||||
| `pnpm test` | Turbo를 통해 unit tests를 실행합니다. |
|
||||
| `pnpm typecheck` | Turbo를 통해 TypeScript checks를 실행합니다. |
|
||||
| `pnpm lint` | ESLint를 실행합니다. |
|
||||
| `pnpm test:e2e` | Playwright tests를 실행합니다. |
|
||||
| `pnpm storybook:dev` | UI component 개발용 Storybook을 시작합니다. |
|
||||
|
||||
Pull request를 열기 전에 [CONTRIBUTING.md](../../CONTRIBUTING.md)를 읽어 주세요.
|
||||
|
||||
@@ -290,9 +290,8 @@ Pro 功能请参考 [Univer Pro 指南](https://docs.univer.ai/guides/pro)。这
|
||||
```text
|
||||
.
|
||||
├── packages/ 核心包、引擎、文档类型、UI 插件和功能插件
|
||||
├── examples/ 用于开发的本地浏览器和 Node.js 示例
|
||||
├── common/ 共享内部工具、mock 数据、storybook 和工具函数
|
||||
├── e2e/ Playwright 和视觉对比测试
|
||||
├── examples/ 用于本地浏览器开发的一体化 Vite 工作台
|
||||
├── common/ 共享内部工具、storybook 和工具函数
|
||||
├── tests/ 其他集成测试项目
|
||||
└── docs/ 架构说明、图片和仓库内文档
|
||||
```
|
||||
@@ -317,12 +316,12 @@ pnpm dev
|
||||
|
||||
| 命令 | 用途 |
|
||||
| --- | --- |
|
||||
| `pnpm dev` | 启动本地 examples 应用。 |
|
||||
| `pnpm dev` | 构建并预览低内存、无 HMR 的一体化工作台。 |
|
||||
| `pnpm dev:source` | 启动支持 HMR 的源码工作台,冷启动和内存占用更高。 |
|
||||
| `pnpm build` | 构建 workspace 包,不包含内部 common 包。 |
|
||||
| `pnpm test` | 通过 Turbo 运行单元测试。 |
|
||||
| `pnpm typecheck` | 通过 Turbo 运行 TypeScript 检查。 |
|
||||
| `pnpm lint` | 运行 ESLint。 |
|
||||
| `pnpm test:e2e` | 运行 Playwright 测试。 |
|
||||
| `pnpm storybook:dev` | 启动用于 UI 组件开发的 Storybook。 |
|
||||
|
||||
提交 pull request 前请阅读 [CONTRIBUTING.md](../../CONTRIBUTING.md)。
|
||||
|
||||
@@ -290,9 +290,8 @@ Pro 功能請參考 [Univer Pro 指南](https://docs.univer.ai/guides/pro)。這
|
||||
```text
|
||||
.
|
||||
├── packages/ 核心套件、引擎、文件類型、UI 外掛和功能外掛
|
||||
├── examples/ 用於開發的本地瀏覽器和 Node.js 示例
|
||||
├── common/ 共享內部工具、mock 資料、storybook 和工具函式
|
||||
├── e2e/ Playwright 和視覺比較測試
|
||||
├── examples/ 用於本地瀏覽器開發的一體化 Vite 工作台
|
||||
├── common/ 共享內部工具、storybook 和工具函式
|
||||
├── tests/ 其他整合測試專案
|
||||
└── docs/ 架構說明、圖片和倉庫內文件
|
||||
```
|
||||
@@ -317,12 +316,12 @@ pnpm dev
|
||||
|
||||
| 命令 | 用途 |
|
||||
| --- | --- |
|
||||
| `pnpm dev` | 啟動本地 examples 應用。 |
|
||||
| `pnpm dev` | 構建並預覽低記憶體、無 HMR 的一體化工作台。 |
|
||||
| `pnpm dev:source` | 啟動支援 HMR 的原始碼工作台,冷啟動和記憶體用量較高。 |
|
||||
| `pnpm build` | 構建 workspace 套件,不包含內部 common 套件。 |
|
||||
| `pnpm test` | 透過 Turbo 執行單元測試。 |
|
||||
| `pnpm typecheck` | 透過 Turbo 執行 TypeScript 檢查。 |
|
||||
| `pnpm lint` | 執行 ESLint。 |
|
||||
| `pnpm test:e2e` | 執行 Playwright 測試。 |
|
||||
| `pnpm storybook:dev` | 啟動用於 UI 元件開發的 Storybook。 |
|
||||
|
||||
提交 pull request 前請閱讀 [CONTRIBUTING.md](../../CONTRIBUTING.md)。
|
||||
|
||||
@@ -1,436 +0,0 @@
|
||||
interface ICellData {
|
||||
v: string | number | boolean;
|
||||
t: number;
|
||||
s: string;
|
||||
}
|
||||
|
||||
interface IDimensionData {
|
||||
w?: number;
|
||||
h?: number;
|
||||
hd: number;
|
||||
}
|
||||
|
||||
const ROW_COUNT = 1200;
|
||||
const COLUMN_COUNT = 80;
|
||||
const SHEET_ID = 'dense-text-scroll';
|
||||
const WORKBOOK_ID = 'workbook-dense-text-scroll';
|
||||
const CHART_ID = 'dense-text-chart-1';
|
||||
|
||||
const border = (rgb: string, s = 1) => ({
|
||||
t: { s, cl: { rgb } },
|
||||
r: { s, cl: { rgb } },
|
||||
b: { s, cl: { rgb } },
|
||||
l: { s, cl: { rgb } },
|
||||
});
|
||||
|
||||
const styles = {
|
||||
textLeftBlue: {
|
||||
ff: 'Arial',
|
||||
fs: 11,
|
||||
ht: 1,
|
||||
vt: 1,
|
||||
tb: 1,
|
||||
cl: { rgb: 'rgb(37,99,235)' },
|
||||
bg: { rgb: 'rgb(239,246,255)' },
|
||||
bd: border('rgb(147,197,253)'),
|
||||
pd: { t: 1, b: 1, l: 4, r: 4 },
|
||||
},
|
||||
textCenterGreen: {
|
||||
ff: 'Aptos',
|
||||
fs: 11,
|
||||
ht: 2,
|
||||
vt: 2,
|
||||
tb: 2,
|
||||
cl: { rgb: 'rgb(22,101,52)' },
|
||||
bg: { rgb: 'rgb(240,253,244)' },
|
||||
bd: border('rgb(134,239,172)'),
|
||||
pd: { t: 1, b: 1, l: 4, r: 4 },
|
||||
},
|
||||
textRightRose: {
|
||||
ff: 'Verdana',
|
||||
fs: 10,
|
||||
ht: 3,
|
||||
vt: 3,
|
||||
tb: 3,
|
||||
cl: { rgb: 'rgb(190,18,60)' },
|
||||
bg: { rgb: 'rgb(255,241,242)' },
|
||||
bd: border('rgb(253,164,175)'),
|
||||
pd: { t: 1, b: 1, l: 4, r: 4 },
|
||||
},
|
||||
overflowPurple: {
|
||||
ff: 'Arial',
|
||||
fs: 11,
|
||||
ht: 1,
|
||||
vt: 2,
|
||||
tb: 1,
|
||||
cl: { rgb: 'rgb(88,28,135)' },
|
||||
bg: { rgb: 'rgb(250,245,255)' },
|
||||
bd: border('rgb(216,180,254)', 2),
|
||||
pd: { t: 1, b: 1, l: 4, r: 4 },
|
||||
},
|
||||
clippedSlate: {
|
||||
ff: 'Aptos Narrow',
|
||||
fs: 10,
|
||||
ht: 2,
|
||||
vt: 1,
|
||||
tb: 2,
|
||||
cl: { rgb: 'rgb(51,65,85)' },
|
||||
bg: { rgb: 'rgb(248,250,252)' },
|
||||
bd: border('rgb(203,213,225)'),
|
||||
pd: { t: 1, b: 1, l: 4, r: 4 },
|
||||
},
|
||||
wrappedAmber: {
|
||||
ff: 'Arial',
|
||||
fs: 10,
|
||||
ht: 1,
|
||||
vt: 2,
|
||||
tb: 3,
|
||||
cl: { rgb: 'rgb(146,64,14)' },
|
||||
bg: { rgb: 'rgb(255,251,235)' },
|
||||
bd: border('rgb(251,191,36)'),
|
||||
pd: { t: 1, b: 1, l: 4, r: 4 },
|
||||
},
|
||||
};
|
||||
|
||||
const styleIds = Object.keys(styles);
|
||||
|
||||
function createCellText(row: number, column: number): string {
|
||||
if (column % 10 === 0) {
|
||||
return `R${row} C${column} overflow text carries across neighboring cells when there is enough room`;
|
||||
}
|
||||
|
||||
if (column % 7 === 0) {
|
||||
return `wrapped multiline candidate ${row}-${column} with enough words to exercise text layout`;
|
||||
}
|
||||
|
||||
if (column % 5 === 0) {
|
||||
return `colored styled value ${row}:${column}`;
|
||||
}
|
||||
|
||||
return `dense ${row}-${column}`;
|
||||
}
|
||||
|
||||
function createChartCell(row: number, column: number): ICellData | null {
|
||||
if (column > 5) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (row === 0) {
|
||||
return {
|
||||
v: ['Series', 'North', 'South', 'East', 'West', 'Total'][column],
|
||||
t: 1,
|
||||
s: 'textCenterGreen',
|
||||
};
|
||||
}
|
||||
|
||||
if (column === 0) {
|
||||
return {
|
||||
v: `Item ${row}`,
|
||||
t: 1,
|
||||
s: 'clippedSlate',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
v: ((row * 17 + column * 29) % 100) + column * 8,
|
||||
t: 2,
|
||||
s: styleIds[(row * 7 + column * 3) % styleIds.length],
|
||||
};
|
||||
}
|
||||
|
||||
function createCellData(): Record<number, Record<number, ICellData>> {
|
||||
const cellData: Record<number, Record<number, ICellData>> = {};
|
||||
|
||||
for (let row = 0; row < ROW_COUNT; row++) {
|
||||
const rowCells: Record<number, ICellData> = {};
|
||||
|
||||
for (let column = 0; column < COLUMN_COUNT; column++) {
|
||||
rowCells[column] = createChartCell(row, column) ?? {
|
||||
v: createCellText(row, column),
|
||||
t: 1,
|
||||
s: styleIds[(row * 7 + column * 3) % styleIds.length],
|
||||
};
|
||||
}
|
||||
|
||||
cellData[row] = rowCells;
|
||||
}
|
||||
|
||||
return cellData;
|
||||
}
|
||||
|
||||
function createColumnData(): Record<number, IDimensionData> {
|
||||
const columnData: Record<number, IDimensionData> = {};
|
||||
|
||||
for (let column = 0; column < COLUMN_COUNT; column++) {
|
||||
columnData[column] = {
|
||||
w: column % 10 === 0 ? 54 : column % 7 === 0 ? 118 : 82,
|
||||
hd: 0,
|
||||
};
|
||||
}
|
||||
|
||||
return columnData;
|
||||
}
|
||||
|
||||
function createRowData(): Record<number, IDimensionData> {
|
||||
const rowData: Record<number, IDimensionData> = {};
|
||||
|
||||
for (let row = 0; row < ROW_COUNT; row++) {
|
||||
rowData[row] = {
|
||||
h: row % 7 === 0 ? 28 : 22,
|
||||
hd: 0,
|
||||
};
|
||||
}
|
||||
|
||||
return rowData;
|
||||
}
|
||||
|
||||
function createConditionalFormattingResource() {
|
||||
return {
|
||||
[SHEET_ID]: [
|
||||
{
|
||||
ranges: [{ startRow: 1, startColumn: 1, endRow: 420, endColumn: 1, rangeType: 0 }],
|
||||
cfId: 'dense-cf-highlight',
|
||||
stopIfTrue: false,
|
||||
rule: {
|
||||
type: 'highlightCell',
|
||||
subType: 'number',
|
||||
operator: 'greaterThan',
|
||||
value: 80,
|
||||
style: {
|
||||
bg: { rgb: 'rgb(220,252,231)' },
|
||||
cl: { rgb: 'rgb(21,128,61)' },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ranges: [{ startRow: 1, startColumn: 2, endRow: 420, endColumn: 2, rangeType: 0 }],
|
||||
cfId: 'dense-cf-data-bar',
|
||||
stopIfTrue: false,
|
||||
rule: {
|
||||
type: 'dataBar',
|
||||
isShowValue: true,
|
||||
config: {
|
||||
min: { type: 'num', value: 0 },
|
||||
max: { type: 'num', value: 140 },
|
||||
isGradient: true,
|
||||
positiveColor: '#60a5fa',
|
||||
nativeColor: '#f97316',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ranges: [{ startRow: 1, startColumn: 3, endRow: 420, endColumn: 3, rangeType: 0 }],
|
||||
cfId: 'dense-cf-color-scale',
|
||||
stopIfTrue: false,
|
||||
rule: {
|
||||
type: 'colorScale',
|
||||
config: [
|
||||
{ index: 0, color: '#fee2e2', value: { type: 'min' } },
|
||||
{ index: 1, color: '#fef3c7', value: { type: 'percent', value: 50 } },
|
||||
{ index: 2, color: '#bbf7d0', value: { type: 'max' } },
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function createDataValidationResource() {
|
||||
return {
|
||||
[SHEET_ID]: [
|
||||
{
|
||||
uid: 'dense-dv-list',
|
||||
type: 'list',
|
||||
formula1: 'Open,In Progress,Blocked,Done',
|
||||
formula2: '',
|
||||
allowBlank: true,
|
||||
showErrorMessage: true,
|
||||
error: 'Choose a status from the list.',
|
||||
ranges: [{ startRow: 1, startColumn: 6, endRow: 250, endColumn: 6, rangeType: 0 }],
|
||||
},
|
||||
{
|
||||
uid: 'dense-dv-decimal',
|
||||
type: 'decimal',
|
||||
operator: 'between',
|
||||
formula1: '0',
|
||||
formula2: '150',
|
||||
allowBlank: false,
|
||||
showErrorMessage: true,
|
||||
error: 'Value must be between 0 and 150.',
|
||||
ranges: [{ startRow: 1, startColumn: 1, endRow: 420, endColumn: 5, rangeType: 0 }],
|
||||
},
|
||||
{
|
||||
uid: 'dense-dv-checkbox',
|
||||
type: 'checkbox',
|
||||
ranges: [{ startRow: 1, startColumn: 7, endRow: 250, endColumn: 7, rangeType: 0 }],
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function createRangeProtectionResource() {
|
||||
return {
|
||||
[SHEET_ID]: [
|
||||
{
|
||||
ranges: [
|
||||
{
|
||||
startRow: 30,
|
||||
startColumn: 10,
|
||||
endRow: 160,
|
||||
endColumn: 18,
|
||||
rangeType: 0,
|
||||
unitId: WORKBOOK_ID,
|
||||
sheetId: SHEET_ID,
|
||||
},
|
||||
{
|
||||
startRow: 260,
|
||||
startColumn: 28,
|
||||
endRow: 420,
|
||||
endColumn: 36,
|
||||
rangeType: 0,
|
||||
unitId: WORKBOOK_ID,
|
||||
sheetId: SHEET_ID,
|
||||
},
|
||||
],
|
||||
permissionId: 'dense-range-permission',
|
||||
id: 'dense-range-protection',
|
||||
name: 'Dense text protected ranges',
|
||||
unitType: 3,
|
||||
unitId: WORKBOOK_ID,
|
||||
subUnitId: SHEET_ID,
|
||||
viewState: 'othersCanView',
|
||||
editState: 'onlyMe',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function createDrawingResource() {
|
||||
return {
|
||||
[SHEET_ID]: {
|
||||
data: {
|
||||
[CHART_ID]: {
|
||||
unitId: WORKBOOK_ID,
|
||||
subUnitId: SHEET_ID,
|
||||
drawingId: CHART_ID,
|
||||
drawingType: 2,
|
||||
componentKey: 'SheetsChartComponent',
|
||||
sheetTransform: {
|
||||
from: { column: 9, columnOffset: 20, row: 2, rowOffset: 6 },
|
||||
to: { column: 18, columnOffset: 50, row: 20, rowOffset: 8 },
|
||||
},
|
||||
axisAlignSheetTransform: {
|
||||
from: { column: 9, columnOffset: 20, row: 2, rowOffset: 6 },
|
||||
to: { column: 18, columnOffset: 50, row: 20, rowOffset: 8 },
|
||||
},
|
||||
transform: {
|
||||
left: 800,
|
||||
top: 50,
|
||||
width: 520,
|
||||
height: 340,
|
||||
},
|
||||
data: {
|
||||
border: '#94a3b8',
|
||||
background: '#ffffff',
|
||||
},
|
||||
allowTransform: true,
|
||||
},
|
||||
},
|
||||
order: [CHART_ID],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function createChartResource() {
|
||||
return {
|
||||
[SHEET_ID]: [
|
||||
{
|
||||
id: CHART_ID,
|
||||
chartType: 4,
|
||||
rangeInfo: {
|
||||
rangeInfo: {
|
||||
unitId: WORKBOOK_ID,
|
||||
subUnitId: SHEET_ID,
|
||||
range: { startRow: 0, startColumn: 0, endRow: 36, endColumn: 5, rangeType: 0 },
|
||||
},
|
||||
isRowDirection: true,
|
||||
},
|
||||
context: {},
|
||||
style: {
|
||||
titles: {
|
||||
title: {
|
||||
content: 'Dense Scroll Metrics',
|
||||
},
|
||||
},
|
||||
},
|
||||
dataAggregation: {},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
export const sheetData = {
|
||||
id: WORKBOOK_ID,
|
||||
sheetOrder: [SHEET_ID],
|
||||
name: 'Dense text scroll perf',
|
||||
appVersion: '3.0.0-alpha',
|
||||
locale: 'zhCN',
|
||||
styles,
|
||||
sheets: {
|
||||
[SHEET_ID]: {
|
||||
name: 'Dense text',
|
||||
id: SHEET_ID,
|
||||
tabColor: '',
|
||||
hidden: 0,
|
||||
rowCount: ROW_COUNT,
|
||||
columnCount: COLUMN_COUNT,
|
||||
zoomRatio: 1,
|
||||
cellData: createCellData(),
|
||||
freeze: {
|
||||
xSplit: 0,
|
||||
ySplit: 0,
|
||||
startRow: -1,
|
||||
startColumn: -1,
|
||||
},
|
||||
scrollTop: 0,
|
||||
scrollLeft: 0,
|
||||
defaultColumnWidth: 82,
|
||||
defaultRowHeight: 22,
|
||||
mergeData: [],
|
||||
rowData: createRowData(),
|
||||
columnData: createColumnData(),
|
||||
rowHeader: {
|
||||
width: 46,
|
||||
hidden: 0,
|
||||
},
|
||||
columnHeader: {
|
||||
height: 20,
|
||||
hidden: 0,
|
||||
},
|
||||
showGridlines: 1,
|
||||
rightToLeft: 0,
|
||||
},
|
||||
},
|
||||
resources: [
|
||||
{
|
||||
name: 'SHEET_CONDITIONAL_FORMATTING_PLUGIN',
|
||||
data: JSON.stringify(createConditionalFormattingResource()),
|
||||
},
|
||||
{
|
||||
name: 'SHEET_DATA_VALIDATION_PLUGIN',
|
||||
data: JSON.stringify(createDataValidationResource()),
|
||||
},
|
||||
{
|
||||
name: 'SHEET_RANGE_PROTECTION_PLUGIN',
|
||||
data: JSON.stringify(createRangeProtectionResource()),
|
||||
},
|
||||
{
|
||||
name: 'SHEET_DRAWING_PLUGIN',
|
||||
data: JSON.stringify(createDrawingResource()),
|
||||
},
|
||||
{
|
||||
name: 'SHEET_CHART_PLUGIN',
|
||||
data: JSON.stringify(createChartResource()),
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
These tests ensure that no error is thrown when the user is disposing a unit or a Univer instance.
|
||||
@@ -1,67 +0,0 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
test('no error on constructing and disposing', async ({ page }) => {
|
||||
let errored = false;
|
||||
|
||||
page.on('pageerror', (error) => {
|
||||
console.error('Page error:', error);
|
||||
errored = true;
|
||||
});
|
||||
|
||||
await page.goto('http://localhost:3000/sheets/');
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadDemoSheet());
|
||||
await page.evaluate(() => window.E2EControllerAPI.disposeCurrSheetUnit());
|
||||
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadDemoSheet(0));
|
||||
await page.evaluate(() => window.E2EControllerAPI.disposeCurrSheetUnit(0));
|
||||
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadDemoSheet(2000));
|
||||
await page.evaluate(() => window.E2EControllerAPI.disposeCurrSheetUnit(0));
|
||||
|
||||
await page.evaluate(() => window.E2EControllerAPI.disposeUniver());
|
||||
expect(errored).toBeFalsy();
|
||||
});
|
||||
|
||||
test('no error on constructing and disposing sheet unit', async ({ page }) => {
|
||||
test.setTimeout(40 * 1000); // setTimeout(0) means Keep wait result forever
|
||||
|
||||
let errored = false;
|
||||
page.on('pageerror', (error) => {
|
||||
console.error('Page error:', error);
|
||||
errored = true;
|
||||
});
|
||||
|
||||
await page.goto('http://localhost:3000/sheets/');
|
||||
await page.evaluate(() => window.E2EControllerAPI.disposeCurrSheetUnit());
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadDemoSheet());
|
||||
|
||||
await page.evaluate(() => window.E2EControllerAPI.disposeCurrSheetUnit(0));
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadDemoSheet(0));
|
||||
|
||||
await page.evaluate(() => window.E2EControllerAPI.disposeCurrSheetUnit(500));
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadDemoSheet(1000));
|
||||
|
||||
await page.evaluate(() => window.E2EControllerAPI.disposeCurrSheetUnit(3000));
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadDemoSheet(1000));
|
||||
await page.evaluate(() => window.E2EControllerAPI.disposeUniver());
|
||||
|
||||
expect(errored).toBeFalsy();
|
||||
});
|
||||
|
||||
test('no error when dispose a unit', async ({ page }) => {
|
||||
let errored = false;
|
||||
|
||||
page.on('pageerror', (error) => {
|
||||
console.error('Page error:', error);
|
||||
errored = true;
|
||||
});
|
||||
|
||||
await page.goto('http://localhost:3000/sheets/');
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadAndRelease(1));
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadAndRelease(2));
|
||||
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadAndRelease(1, 1000, 1000));
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadAndRelease(2, 1000, 1000));
|
||||
|
||||
expect(errored).toBeFalsy();
|
||||
});
|
||||
@@ -1,51 +0,0 @@
|
||||
import type { IBoundRectNoAngle, IScrollRenderInfo } from '@univerjs/engine-render';
|
||||
|
||||
// The type definition is copied from:
|
||||
// common/debugger/src/controllers/e2e/e2e.controller.ts
|
||||
export interface IE2EControllerAPI {
|
||||
loadAndRelease(id: number, loadTimeout?: number, disposeTimeout?: number): Promise<void>;
|
||||
loadDefaultSheet(loadTimeout?: number): Promise<void>;
|
||||
loadDefaultDoc(loadTimeout?: number): Promise<void>;
|
||||
loadDocLayoutFixture(documentFlavor: 1 | 2, loadTimeout?: number): Promise<void>;
|
||||
loadDemoSheet(loadTimeout?: number): Promise<void>;
|
||||
loadMergeCellSheet(loadTimeout?: number): Promise<void>;
|
||||
loadDefaultStyleSheet(loadTimeout?: number): Promise<void>;
|
||||
setDarkMode(darkMode: boolean): void;
|
||||
disposeUniver(): Promise<void>;
|
||||
disposeCurrSheetUnit(disposeTimeout?: number): Promise<void>;
|
||||
scrollAndClearCanvas(
|
||||
canvas: HTMLCanvasElement,
|
||||
pixelRatio: number,
|
||||
scrollRenderInfos: IScrollRenderInfo[],
|
||||
dirtyBounds: IBoundRectNoAngle[]
|
||||
): void;
|
||||
}
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line ts/naming-convention
|
||||
interface Window {
|
||||
E2EControllerAPI: IE2EControllerAPI;
|
||||
univer: any;
|
||||
// eslint-disable-next-line ts/no-explicit-any
|
||||
univerAPI: any;
|
||||
floatDomContentBoxFixture?: {
|
||||
id: string;
|
||||
setContentBox: (contentBox: { wrapperInset?: number; contentInset?: number }) => void;
|
||||
setBorder: (border: boolean) => void;
|
||||
enableRotateHandle: () => void;
|
||||
getTransformerGeometry: () => {
|
||||
drawing: { left: number; top: number; width: number; height: number; angle: number };
|
||||
controls: Array<{ key: string; left: number; top: number; width: number; height: number; angle: number }>;
|
||||
};
|
||||
getLayout: () => {
|
||||
startX: number;
|
||||
startY: number;
|
||||
endX: number;
|
||||
endY: number;
|
||||
width: number;
|
||||
height: number;
|
||||
rotate: number;
|
||||
} | undefined;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,522 +0,0 @@
|
||||
/* eslint-disable no-console */
|
||||
import type { Page, TestInfo } from '@playwright/test';
|
||||
import { writeFile } from 'node:fs/promises';
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
type ContentBoxMode = 'legacy-inset' | 'exact-bounds';
|
||||
type ClippingCase = 'visible' | 'left-top' | 'right-bottom' | 'offscreen' | 're-entry';
|
||||
|
||||
interface IRectRecord {
|
||||
left: number;
|
||||
top: number;
|
||||
right: number;
|
||||
bottom: number;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
interface IFloatDomContentBoxEvidence {
|
||||
caseId: string;
|
||||
mode: ContentBoxMode;
|
||||
zoom: number;
|
||||
rotation: number;
|
||||
clipping: ClippingCase;
|
||||
border: boolean;
|
||||
logicalRect: IRectRecord;
|
||||
placementRect: IRectRecord;
|
||||
wrapperRect: IRectRecord;
|
||||
contentRect: IRectRecord;
|
||||
probeRect: IRectRecord;
|
||||
edgeDelta: { top: number; left: number; right: number; bottom: number; max: number };
|
||||
legacySnapshotMatched: boolean;
|
||||
}
|
||||
|
||||
interface ITransformerGeometry {
|
||||
drawing: { left: number; top: number; width: number; height: number; angle: number };
|
||||
controls: Array<{ key: string; left: number; top: number; width: number; height: number; angle: number }>;
|
||||
}
|
||||
|
||||
function positionForClipping(clipping: ClippingCase, zoom: number): { left: number; top: number } {
|
||||
switch (clipping) {
|
||||
case 'left-top':
|
||||
return { left: -240, top: -160 };
|
||||
case 'right-bottom':
|
||||
return { left: 1400 / zoom, top: 1000 / zoom };
|
||||
case 'offscreen':
|
||||
return { left: 1800 / zoom, top: 1400 / zoom };
|
||||
case 'visible':
|
||||
case 're-entry':
|
||||
return { left: 100, top: 80 };
|
||||
}
|
||||
}
|
||||
|
||||
function maxEdgeDelta(a: IRectRecord, b: IRectRecord): IFloatDomContentBoxEvidence['edgeDelta'] {
|
||||
const edgeDelta = {
|
||||
top: Math.abs(a.top - b.top),
|
||||
left: Math.abs(a.left - b.left),
|
||||
right: Math.abs(a.right - b.right),
|
||||
bottom: Math.abs(a.bottom - b.bottom),
|
||||
max: 0,
|
||||
};
|
||||
edgeDelta.max = Math.max(edgeDelta.top, edgeDelta.left, edgeDelta.right, edgeDelta.bottom);
|
||||
return edgeDelta;
|
||||
}
|
||||
|
||||
async function configureCase(
|
||||
page: Page,
|
||||
mode: ContentBoxMode,
|
||||
zoom: number,
|
||||
rotation: number,
|
||||
clipping: ClippingCase,
|
||||
border: boolean
|
||||
): Promise<void> {
|
||||
const position = positionForClipping(clipping, zoom);
|
||||
await page.evaluate(({ mode, zoom, rotation, position, border }) => {
|
||||
const fixture = window.floatDomContentBoxFixture!;
|
||||
const worksheet = window.univerAPI.getActiveWorkbook().getActiveSheet();
|
||||
fixture.setContentBox(mode === 'exact-bounds'
|
||||
? { wrapperInset: 0, contentInset: 0 }
|
||||
: {});
|
||||
fixture.setBorder(border);
|
||||
worksheet.zoom(zoom);
|
||||
worksheet.updateFloatDom(fixture.id, {
|
||||
position: {
|
||||
left: position.left,
|
||||
top: position.top,
|
||||
width: 480,
|
||||
height: 320,
|
||||
angle: rotation,
|
||||
},
|
||||
});
|
||||
}, { mode, zoom, rotation, position, border });
|
||||
await page.waitForTimeout(80);
|
||||
}
|
||||
|
||||
async function selectFloatDom(page: Page): Promise<void> {
|
||||
const center = await page.locator('[data-float-dom-content-box-probe]').evaluate((probe) => {
|
||||
const rect = probe.parentElement!.parentElement!.getBoundingClientRect();
|
||||
return { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 };
|
||||
});
|
||||
await page.mouse.click(center.x, center.y);
|
||||
await page.waitForTimeout(50);
|
||||
}
|
||||
|
||||
async function getTransformerControlPoint(page: Page, controlKey: string): Promise<{ x: number; y: number }> {
|
||||
return page.locator('[data-float-dom-content-box-probe]').evaluate((probe, key) => {
|
||||
const { controls } = window.floatDomContentBoxFixture!.getTransformerGeometry();
|
||||
const control = controls.find(({ key: currentKey }) => currentKey.startsWith(key));
|
||||
if (!control) {
|
||||
throw new Error(`Transformer control not found: ${key}`);
|
||||
}
|
||||
|
||||
const rect = probe.parentElement!.parentElement!.getBoundingClientRect();
|
||||
const intersectionLeft = Math.max(control.left, 0);
|
||||
const intersectionTop = Math.max(control.top, 0);
|
||||
const intersectionRight = Math.min(control.left + control.width, rect.width);
|
||||
const intersectionBottom = Math.min(control.top + control.height, rect.height);
|
||||
return {
|
||||
x: rect.left + (intersectionLeft <= intersectionRight
|
||||
? (intersectionLeft + intersectionRight) / 2
|
||||
: control.left + control.width / 2),
|
||||
y: rect.top + (intersectionTop <= intersectionBottom
|
||||
? (intersectionTop + intersectionBottom) / 2
|
||||
: control.top + control.height / 2),
|
||||
};
|
||||
}, controlKey);
|
||||
}
|
||||
|
||||
async function measureCase(
|
||||
page: Page,
|
||||
caseId: string,
|
||||
mode: ContentBoxMode,
|
||||
zoom: number,
|
||||
rotation: number,
|
||||
clipping: ClippingCase,
|
||||
border: boolean
|
||||
): Promise<IFloatDomContentBoxEvidence> {
|
||||
return page.evaluate(({ caseId, mode, zoom, rotation, clipping, border }) => {
|
||||
const toRect = (rect: DOMRect): IRectRecord => ({
|
||||
left: rect.left,
|
||||
top: rect.top,
|
||||
right: rect.right,
|
||||
bottom: rect.bottom,
|
||||
width: rect.width,
|
||||
height: rect.height,
|
||||
});
|
||||
const fixture = window.floatDomContentBoxFixture!;
|
||||
const probe = document.querySelector('[data-float-dom-content-box-probe]')! as HTMLDivElement;
|
||||
const inner = probe.parentElement! as HTMLDivElement;
|
||||
const wrapper = inner.parentElement! as HTMLDivElement;
|
||||
const layout = fixture.getLayout()!;
|
||||
const logical = window.univerAPI.getActiveWorkbook().getActiveSheet().getFloatDomById(fixture.id).position;
|
||||
|
||||
const placementProbe = document.createElement('div');
|
||||
placementProbe.style.position = 'absolute';
|
||||
placementProbe.style.pointerEvents = 'none';
|
||||
placementProbe.style.top = `${layout.startY}px`;
|
||||
placementProbe.style.left = `${layout.startX}px`;
|
||||
placementProbe.style.width = `${Math.max(layout.endX - layout.startX, 0)}px`;
|
||||
placementProbe.style.height = `${Math.max(layout.endY - layout.startY, 0)}px`;
|
||||
placementProbe.style.transform = `rotate(${layout.rotate}deg)`;
|
||||
placementProbe.style.transformOrigin = 'center center';
|
||||
wrapper.parentElement!.appendChild(placementProbe);
|
||||
|
||||
const placementRect = toRect(placementProbe.getBoundingClientRect());
|
||||
const wrapperRect = toRect(wrapper.getBoundingClientRect());
|
||||
const contentRect = toRect(inner.getBoundingClientRect());
|
||||
const probeRect = toRect(probe.getBoundingClientRect());
|
||||
placementProbe.remove();
|
||||
const edgeDelta = {
|
||||
top: Math.abs(placementRect.top - wrapperRect.top),
|
||||
left: Math.abs(placementRect.left - wrapperRect.left),
|
||||
right: Math.abs(placementRect.right - wrapperRect.right),
|
||||
bottom: Math.abs(placementRect.bottom - wrapperRect.bottom),
|
||||
max: 0,
|
||||
};
|
||||
edgeDelta.max = Math.max(edgeDelta.top, edgeDelta.left, edgeDelta.right, edgeDelta.bottom);
|
||||
|
||||
const record: IFloatDomContentBoxEvidence = {
|
||||
caseId,
|
||||
mode,
|
||||
zoom,
|
||||
rotation,
|
||||
clipping,
|
||||
border,
|
||||
logicalRect: {
|
||||
left: logical.left,
|
||||
top: logical.top,
|
||||
right: logical.left + logical.width,
|
||||
bottom: logical.top + logical.height,
|
||||
width: logical.width,
|
||||
height: logical.height,
|
||||
},
|
||||
placementRect,
|
||||
wrapperRect,
|
||||
contentRect,
|
||||
probeRect,
|
||||
edgeDelta,
|
||||
legacySnapshotMatched: mode !== 'legacy-inset' || (
|
||||
Math.abs(Number.parseFloat(wrapper.style.width) - Math.max(layout.endX - layout.startX - 2, 0)) < 0.001 &&
|
||||
Math.abs(Number.parseFloat(wrapper.style.height) - Math.max(layout.endY - layout.startY - 2, 0)) < 0.001 &&
|
||||
Math.abs(Number.parseFloat(inner.style.width) - (layout.width - 4)) < 0.001 &&
|
||||
Math.abs(Number.parseFloat(inner.style.height) - (layout.height - 4)) < 0.001
|
||||
),
|
||||
};
|
||||
console.debug(`[DEBUG-float-dom-content-box] ${JSON.stringify(record)}`);
|
||||
return record;
|
||||
}, { caseId, mode, zoom, rotation, clipping, border });
|
||||
}
|
||||
|
||||
test('FloatDom exact content box browser matrix', async ({ page }, testInfo: TestInfo) => {
|
||||
test.setTimeout(180_000);
|
||||
page.on('console', (message) => {
|
||||
if (message.text().startsWith('[DEBUG-float-dom-content-box]')) {
|
||||
console.log(message.text());
|
||||
}
|
||||
});
|
||||
page.on('pageerror', (error) => console.error(`[PAGE-ERROR] ${error.stack ?? error.message}`));
|
||||
|
||||
await page.setViewportSize({ width: 1600, height: 1200 });
|
||||
await page.goto('/sheets/?float-dom-content-box');
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadDefaultSheet());
|
||||
await page.waitForTimeout(1_000);
|
||||
await page.waitForFunction(() => Boolean(window.floatDomContentBoxFixture && document.querySelector('[data-float-dom-content-box-probe]')), undefined, { timeout: 15_000 });
|
||||
|
||||
const zooms = [0.75, 1, 1.25, 2];
|
||||
const rotations = [0, 30];
|
||||
const clippings: ClippingCase[] = ['visible', 'left-top', 'right-bottom', 'offscreen', 're-entry'];
|
||||
const records: IFloatDomContentBoxEvidence[] = [];
|
||||
|
||||
for (const zoom of zooms) {
|
||||
for (const rotation of rotations) {
|
||||
for (const clipping of clippings) {
|
||||
for (const border of [false, true]) {
|
||||
for (const mode of ['legacy-inset', 'exact-bounds'] as const) {
|
||||
const caseId = `${mode}-z${zoom}-r${rotation}-${clipping}-${border ? 'border' : 'no-border'}`;
|
||||
await configureCase(page, mode, zoom, rotation, clipping, border);
|
||||
const record = await measureCase(page, caseId, mode, zoom, rotation, clipping, border);
|
||||
records.push(record);
|
||||
|
||||
expect(record.logicalRect.width, caseId).toBe(480);
|
||||
expect(record.logicalRect.height, caseId).toBe(320);
|
||||
expect(record.legacySnapshotMatched, caseId).toBe(true);
|
||||
expect(maxEdgeDelta(record.contentRect, record.probeRect).max, caseId).toBeLessThanOrEqual(0.5);
|
||||
if (mode === 'exact-bounds') {
|
||||
expect(record.edgeDelta.max, caseId).toBeLessThanOrEqual(0.5);
|
||||
if (clipping === 'visible' || clipping === 're-entry') {
|
||||
expect(maxEdgeDelta(record.wrapperRect, record.contentRect).max, caseId).toBeLessThanOrEqual(0.5);
|
||||
const radians = rotation * Math.PI / 180;
|
||||
const expectedRenderedWidth = (480 * Math.abs(Math.cos(radians)) + 320 * Math.abs(Math.sin(radians))) * zoom;
|
||||
const expectedRenderedHeight = (480 * Math.abs(Math.sin(radians)) + 320 * Math.abs(Math.cos(radians))) * zoom;
|
||||
expect(record.wrapperRect.width, `${caseId} rendered width`).toBeCloseTo(expectedRenderedWidth, 2);
|
||||
expect(record.wrapperRect.height, `${caseId} rendered height`).toBeCloseTo(expectedRenderedHeight, 2);
|
||||
}
|
||||
}
|
||||
if (clipping === 'left-top') {
|
||||
expect(record.contentRect.left < record.wrapperRect.left || record.contentRect.top < record.wrapperRect.top, caseId).toBe(true);
|
||||
} else if (clipping === 'right-bottom') {
|
||||
expect(record.wrapperRect.left < 1600 && record.wrapperRect.right > 1600, caseId).toBe(true);
|
||||
expect(record.wrapperRect.top < 1200 && record.wrapperRect.bottom > 1200, caseId).toBe(true);
|
||||
} else if (clipping === 'offscreen') {
|
||||
expect(record.wrapperRect.left > 1600, caseId).toBe(true);
|
||||
expect(record.wrapperRect.top > 1200, caseId).toBe(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const reEntry of records.filter(({ clipping }) => clipping === 're-entry')) {
|
||||
const visible = records.find((record) => record.clipping === 'visible' &&
|
||||
record.mode === reEntry.mode && record.zoom === reEntry.zoom &&
|
||||
record.rotation === reEntry.rotation && record.border === reEntry.border)!;
|
||||
expect(maxEdgeDelta(reEntry.wrapperRect, visible.wrapperRect).max, `${reEntry.caseId} cumulative offset`).toBeLessThanOrEqual(0.5);
|
||||
expect(maxEdgeDelta(reEntry.contentRect, visible.contentRect).max, `${reEntry.caseId} content cumulative offset`).toBeLessThanOrEqual(0.5);
|
||||
}
|
||||
|
||||
const evidencePath = testInfo.outputPath('float-dom-content-box-evidence.json');
|
||||
await writeFile(evidencePath, JSON.stringify(records, null, 2));
|
||||
await testInfo.attach('float-dom-content-box-evidence', { path: evidencePath, contentType: 'application/json' });
|
||||
await page.screenshot({
|
||||
path: testInfo.outputPath('float-dom-content-box-re-entry.png'),
|
||||
fullPage: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('exact content box preserves transformer rendering and pointer resize/rotate behavior', async ({ page }, testInfo: TestInfo) => {
|
||||
test.setTimeout(120_000);
|
||||
await page.setViewportSize({ width: 1600, height: 1200 });
|
||||
await page.goto('/sheets/?float-dom-content-box');
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadDefaultSheet());
|
||||
await page.waitForFunction(() => Boolean(window.floatDomContentBoxFixture && document.querySelector('[data-float-dom-content-box-probe]')));
|
||||
|
||||
const canvas = page.locator('canvas[id^="univer-sheet-main-canvas_"]');
|
||||
const transformerRecords: Array<{ zoom: number; rotation: number; legacy: ITransformerGeometry; exact: ITransformerGeometry }> = [];
|
||||
const canvasPixelHash = () => page.locator('canvas[id^="univer-sheet-main-canvas_"]').evaluate((element: HTMLCanvasElement) => {
|
||||
const pixels = element.getContext('2d')!.getImageData(0, 0, element.width, element.height).data;
|
||||
let hash = 2166136261;
|
||||
for (let i = 0; i < pixels.length; i++) {
|
||||
hash ^= pixels[i];
|
||||
hash = Math.imul(hash, 16777619);
|
||||
}
|
||||
return { hash: hash >>> 0, width: element.width, height: element.height };
|
||||
});
|
||||
for (const zoom of [0.75, 1, 1.25, 2]) {
|
||||
for (const rotation of [0, 30]) {
|
||||
await configureCase(page, 'legacy-inset', zoom, rotation, 'visible', false);
|
||||
await selectFloatDom(page);
|
||||
await page.evaluate(() => window.floatDomContentBoxFixture!.enableRotateHandle());
|
||||
await page.waitForTimeout(20);
|
||||
const legacyGeometry = await page.evaluate(() => window.floatDomContentBoxFixture!.getTransformerGeometry());
|
||||
const legacyHash = await canvasPixelHash();
|
||||
const legacyCanvas = await canvas.screenshot();
|
||||
await page.evaluate(() => window.floatDomContentBoxFixture!.setContentBox({ wrapperInset: 0, contentInset: 0 }));
|
||||
await page.waitForTimeout(50);
|
||||
const exactHash = await canvasPixelHash();
|
||||
const exactGeometry = await page.evaluate(() => window.floatDomContentBoxFixture!.getTransformerGeometry());
|
||||
const exactCanvas = await canvas.screenshot();
|
||||
expect(exactHash, `transformer canvas z${zoom} r${rotation}`).toEqual(legacyHash);
|
||||
expect(exactGeometry, `transformer geometry z${zoom} r${rotation}`).toEqual(legacyGeometry);
|
||||
expect(legacyGeometry.controls.filter(({ key }) => key.includes('Resize')).length).toBe(8);
|
||||
expect(legacyGeometry.controls.some(({ key }) => key.includes('Outline'))).toBe(true);
|
||||
expect(legacyGeometry.controls.some(({ key }) => key.includes('Rotate__'))).toBe(true);
|
||||
transformerRecords.push({ zoom, rotation, legacy: legacyGeometry, exact: exactGeometry });
|
||||
|
||||
if (zoom === 1 && rotation === 0) {
|
||||
const legacyPath = testInfo.outputPath('transformer-legacy.png');
|
||||
const exactPath = testInfo.outputPath('transformer-exact.png');
|
||||
await writeFile(legacyPath, legacyCanvas);
|
||||
await writeFile(exactPath, exactCanvas);
|
||||
await testInfo.attach('transformer-legacy', { path: legacyPath, contentType: 'image/png' });
|
||||
await testInfo.attach('transformer-exact', { path: exactPath, contentType: 'image/png' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const resizeTargets = [
|
||||
{ name: 'left-top', controlKey: '__SpreadsheetTransformerResizeLT__' },
|
||||
{ name: 'center-top', controlKey: '__SpreadsheetTransformerResizeCT__' },
|
||||
{ name: 'right-top', controlKey: '__SpreadsheetTransformerResizeRT__' },
|
||||
{ name: 'left-middle', controlKey: '__SpreadsheetTransformerResizeLM__' },
|
||||
{ name: 'right-middle', controlKey: '__SpreadsheetTransformerResizeRM__' },
|
||||
{ name: 'left-bottom', controlKey: '__SpreadsheetTransformerResizeLB__' },
|
||||
{ name: 'center-bottom', controlKey: '__SpreadsheetTransformerResizeCB__' },
|
||||
{ name: 'right-bottom', controlKey: '__SpreadsheetTransformerResizeRB__' },
|
||||
];
|
||||
const pointerResults: Array<{ target: string; hit: boolean; action: string; cursor: string }> = [];
|
||||
|
||||
for (const target of resizeTargets) {
|
||||
await configureCase(page, 'exact-bounds', 1, 0, 'visible', false);
|
||||
await selectFloatDom(page);
|
||||
const start = await getTransformerControlPoint(page, target.controlKey);
|
||||
await page.mouse.move(start.x, start.y);
|
||||
await page.waitForTimeout(20);
|
||||
const cursor = await canvas.evaluate((element) => getComputedStyle(element).cursor);
|
||||
|
||||
const result = await page.evaluate(() => {
|
||||
const fixture = window.floatDomContentBoxFixture!;
|
||||
const logical = window.univerAPI.getActiveWorkbook().getActiveSheet().getFloatDomById(fixture.id).position;
|
||||
const probe = document.querySelector('[data-float-dom-content-box-probe]')!;
|
||||
const innerRect = probe.parentElement!.getBoundingClientRect();
|
||||
const wrapperRect = probe.parentElement!.parentElement!.getBoundingClientRect();
|
||||
return {
|
||||
logical,
|
||||
alignment: Math.max(
|
||||
Math.abs(innerRect.left - wrapperRect.left),
|
||||
Math.abs(innerRect.top - wrapperRect.top),
|
||||
Math.abs(innerRect.right - wrapperRect.right),
|
||||
Math.abs(innerRect.bottom - wrapperRect.bottom)
|
||||
),
|
||||
};
|
||||
});
|
||||
const hit = cursor.includes('resize');
|
||||
pointerResults.push({ target: target.name, hit, action: 'resize', cursor });
|
||||
expect(hit, target.name).toBe(true);
|
||||
expect(result.logical.width, `${target.name} logical width`).toBe(480);
|
||||
expect(result.logical.height, `${target.name} logical height`).toBe(320);
|
||||
expect(result.alignment, `${target.name} DOM alignment`).toBeLessThanOrEqual(0.5);
|
||||
}
|
||||
|
||||
await configureCase(page, 'exact-bounds', 1, 0, 'visible', false);
|
||||
await selectFloatDom(page);
|
||||
const resizeStart = await getTransformerControlPoint(page, '__SpreadsheetTransformerResizeLT__');
|
||||
await page.mouse.move(resizeStart.x, resizeStart.y);
|
||||
await page.mouse.down();
|
||||
// Keep the gesture inside the FloatDom so every move/up crosses the real
|
||||
// pointer-forwarding boundary while the top-left handle shrinks the drawing.
|
||||
await page.mouse.move(resizeStart.x + 20, resizeStart.y + 20, { steps: 4 });
|
||||
await page.mouse.up();
|
||||
await page.waitForTimeout(100);
|
||||
await selectFloatDom(page);
|
||||
const resized = await page.evaluate(() => {
|
||||
const fixture = window.floatDomContentBoxFixture!;
|
||||
const logical = window.univerAPI.getActiveWorkbook().getActiveSheet().getFloatDomById(fixture.id).position;
|
||||
const transformer = fixture.getTransformerGeometry();
|
||||
const probe = document.querySelector('[data-float-dom-content-box-probe]')!;
|
||||
const contentRect = probe.parentElement!.getBoundingClientRect();
|
||||
const wrapperRect = probe.parentElement!.parentElement!.getBoundingClientRect();
|
||||
const layout = fixture.getLayout()!;
|
||||
const placementProbe = document.createElement('div');
|
||||
placementProbe.style.cssText = `position:absolute;pointer-events:none;left:${layout.startX}px;top:${layout.startY}px;width:${Math.max(layout.endX - layout.startX, 0)}px;height:${Math.max(layout.endY - layout.startY, 0)}px;transform:rotate(${layout.rotate}deg);transform-origin:center center;`;
|
||||
probe.parentElement!.parentElement!.parentElement!.appendChild(placementProbe);
|
||||
const placementRect = placementProbe.getBoundingClientRect();
|
||||
placementProbe.remove();
|
||||
return { logical, transformer, wrapperWidth: wrapperRect.width, wrapperHeight: wrapperRect.height, placementAlignment: Math.max(
|
||||
Math.abs(placementRect.left - wrapperRect.left),
|
||||
Math.abs(placementRect.top - wrapperRect.top),
|
||||
Math.abs(placementRect.right - wrapperRect.right),
|
||||
Math.abs(placementRect.bottom - wrapperRect.bottom)
|
||||
), alignment: Math.max(
|
||||
Math.abs(contentRect.left - wrapperRect.left),
|
||||
Math.abs(contentRect.top - wrapperRect.top),
|
||||
Math.abs(contentRect.right - wrapperRect.right),
|
||||
Math.abs(contentRect.bottom - wrapperRect.bottom)
|
||||
) };
|
||||
});
|
||||
const resizeHit = Math.abs(resized.logical.width - 480) > 0.5 && Math.abs(resized.logical.height - 320) > 0.5;
|
||||
pointerResults.push({ target: 'left-top-drag', hit: resizeHit, action: 'resize', cursor: 'nw-resize' });
|
||||
expect(resizeHit).toBe(true);
|
||||
expect(resized.alignment).toBeLessThanOrEqual(0.5);
|
||||
expect(resized.placementAlignment).toBeLessThanOrEqual(0.5);
|
||||
expect(resized.transformer.drawing).toMatchObject({
|
||||
left: resized.logical.left,
|
||||
top: resized.logical.top,
|
||||
width: resized.logical.width,
|
||||
height: resized.logical.height,
|
||||
angle: resized.logical.angle,
|
||||
});
|
||||
const resizedTransformerGroup = resized.transformer.controls.find(({ key }) => key.startsWith('__SpreadsheetTransformer___'))!;
|
||||
expect(resizedTransformerGroup).toMatchObject({
|
||||
left: resized.logical.left,
|
||||
top: resized.logical.top,
|
||||
width: resized.logical.width,
|
||||
height: resized.logical.height,
|
||||
angle: resized.logical.angle,
|
||||
});
|
||||
expect(resized.wrapperWidth).toBeCloseTo(resized.logical.width, 2);
|
||||
expect(resized.wrapperHeight).toBeCloseTo(resized.logical.height, 2);
|
||||
|
||||
await configureCase(page, 'exact-bounds', 1, 0, 'visible', false);
|
||||
await selectFloatDom(page);
|
||||
await page.evaluate(() => window.floatDomContentBoxFixture!.enableRotateHandle());
|
||||
await page.waitForTimeout(20);
|
||||
const rotateStart = await getTransformerControlPoint(page, '__SpreadsheetTransformerRotate__');
|
||||
let rotateCursor = 'default';
|
||||
let rotateHitPoint: { x: number; y: number } | undefined;
|
||||
for (let offsetY = -8; offsetY <= 8 && !rotateHitPoint; offsetY += 2) {
|
||||
for (let offsetX = -8; offsetX <= 8 && !rotateHitPoint; offsetX += 2) {
|
||||
await page.mouse.move(rotateStart.x + offsetX, rotateStart.y + offsetY);
|
||||
rotateCursor = await canvas.evaluate((element) => getComputedStyle(element).cursor);
|
||||
if (rotateCursor === 'move') {
|
||||
rotateHitPoint = { x: rotateStart.x + offsetX, y: rotateStart.y + offsetY };
|
||||
}
|
||||
}
|
||||
}
|
||||
const rotateHit = Boolean(rotateHitPoint);
|
||||
pointerResults.push({ target: 'rotate', hit: rotateHit, action: 'rotate', cursor: rotateCursor });
|
||||
expect(rotateHit).toBe(true);
|
||||
if (!rotateHitPoint) throw new Error('Rotate handle was not found');
|
||||
await page.mouse.move(rotateHitPoint.x, rotateHitPoint.y);
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(rotateHitPoint.x + 80, rotateHitPoint.y + 40, { steps: 6 });
|
||||
await page.mouse.up();
|
||||
await page.waitForTimeout(100);
|
||||
await selectFloatDom(page);
|
||||
const rotated = await page.evaluate(() => {
|
||||
const fixture = window.floatDomContentBoxFixture!;
|
||||
const logical = window.univerAPI.getActiveWorkbook().getActiveSheet().getFloatDomById(fixture.id).position;
|
||||
const transformer = fixture.getTransformerGeometry();
|
||||
const probe = document.querySelector('[data-float-dom-content-box-probe]')!;
|
||||
const contentRect = probe.parentElement!.getBoundingClientRect();
|
||||
const wrapperRect = probe.parentElement!.parentElement!.getBoundingClientRect();
|
||||
const layout = fixture.getLayout()!;
|
||||
const placementProbe = document.createElement('div');
|
||||
placementProbe.style.cssText = `position:absolute;pointer-events:none;left:${layout.startX}px;top:${layout.startY}px;width:${Math.max(layout.endX - layout.startX, 0)}px;height:${Math.max(layout.endY - layout.startY, 0)}px;transform:rotate(${layout.rotate}deg);transform-origin:center center;`;
|
||||
probe.parentElement!.parentElement!.parentElement!.appendChild(placementProbe);
|
||||
const placementRect = placementProbe.getBoundingClientRect();
|
||||
placementProbe.remove();
|
||||
return { logical, transformer, wrapperWidth: wrapperRect.width, wrapperHeight: wrapperRect.height, placementAlignment: Math.max(
|
||||
Math.abs(placementRect.left - wrapperRect.left),
|
||||
Math.abs(placementRect.top - wrapperRect.top),
|
||||
Math.abs(placementRect.right - wrapperRect.right),
|
||||
Math.abs(placementRect.bottom - wrapperRect.bottom)
|
||||
), alignment: Math.max(
|
||||
Math.abs(contentRect.left - wrapperRect.left),
|
||||
Math.abs(contentRect.top - wrapperRect.top),
|
||||
Math.abs(contentRect.right - wrapperRect.right),
|
||||
Math.abs(contentRect.bottom - wrapperRect.bottom)
|
||||
) };
|
||||
});
|
||||
const rotateDragHit = Math.abs(rotated.logical.angle) > 0.5;
|
||||
pointerResults.push({ target: 'rotate-drag', hit: rotateDragHit, action: 'rotate', cursor: rotateCursor });
|
||||
expect(rotateDragHit).toBe(true);
|
||||
expect(rotated.alignment).toBeLessThanOrEqual(0.5);
|
||||
expect(rotated.placementAlignment).toBeLessThanOrEqual(0.5);
|
||||
expect(rotated.transformer.drawing.angle).toBeCloseTo(rotated.logical.angle, 5);
|
||||
const rotatedTransformerGroup = rotated.transformer.controls.find(({ key }) => key.startsWith('__SpreadsheetTransformer___'))!;
|
||||
expect(rotatedTransformerGroup).toMatchObject({
|
||||
left: rotated.transformer.drawing.left,
|
||||
top: rotated.transformer.drawing.top,
|
||||
width: rotated.transformer.drawing.width,
|
||||
height: rotated.transformer.drawing.height,
|
||||
angle: rotated.transformer.drawing.angle,
|
||||
});
|
||||
const rotatedRadians = rotated.transformer.drawing.angle * Math.PI / 180;
|
||||
const expectedRotatedWidth = rotated.transformer.drawing.width * Math.abs(Math.cos(rotatedRadians)) +
|
||||
rotated.transformer.drawing.height * Math.abs(Math.sin(rotatedRadians));
|
||||
const expectedRotatedHeight = rotated.transformer.drawing.width * Math.abs(Math.sin(rotatedRadians)) +
|
||||
rotated.transformer.drawing.height * Math.abs(Math.cos(rotatedRadians));
|
||||
expect(rotated.wrapperWidth).toBeCloseTo(expectedRotatedWidth, 2);
|
||||
expect(rotated.wrapperHeight).toBeCloseTo(expectedRotatedHeight, 2);
|
||||
console.debug(`[DEBUG-float-dom-content-box] ${JSON.stringify({ caseId: 'transformer-pointer-interactions', pointerResults })}`);
|
||||
const pointerResultsPath = testInfo.outputPath('float-dom-pointer-results.json');
|
||||
await writeFile(pointerResultsPath, JSON.stringify(pointerResults, null, 2));
|
||||
await testInfo.attach('float-dom-pointer-results', { path: pointerResultsPath, contentType: 'application/json' });
|
||||
const transformerGeometryPath = testInfo.outputPath('float-dom-transformer-geometry.json');
|
||||
await writeFile(transformerGeometryPath, JSON.stringify(transformerRecords, null, 2));
|
||||
await testInfo.attach('float-dom-transformer-geometry', { path: transformerGeometryPath, contentType: 'application/json' });
|
||||
|
||||
await page.evaluate(() => window.univer.dispose());
|
||||
await page.waitForFunction(() => window.floatDomContentBoxFixture === undefined);
|
||||
});
|
||||
@@ -1,155 +0,0 @@
|
||||
import type { CDPSession } from '@playwright/test';
|
||||
import { createWriteStream } from 'node:fs';
|
||||
import { expect, test } from '@playwright/test';
|
||||
import { reportToPosthog, shutdownPosthog } from '../utils/report-performance';
|
||||
import { getMetrics } from './util';
|
||||
|
||||
const MAX_UNIT_MEMORY_OVERFLOW = 1_000_000; // 1MB
|
||||
const MAX_SECOND_INSTANCE_OVERFLOW = 200_000; // 200 KB
|
||||
|
||||
// There are some compiled code and global cache, so we make some room
|
||||
// for this. But we need to make sure that a Univer object cannot fit
|
||||
// in this size.
|
||||
const MAX_UNIVER_MEMORY_OVERFLOW = 6_000_000;
|
||||
|
||||
interface IHeapSnapshotChunk {
|
||||
chunk: string;
|
||||
}
|
||||
|
||||
interface IHeapSnapshotProgress {
|
||||
done: number;
|
||||
total: number;
|
||||
finished?: boolean;
|
||||
}
|
||||
async function takeHeapSnapshot(client: CDPSession, filename: string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const file = createWriteStream(`./test-results/${filename}`);
|
||||
let isFinished = false;
|
||||
let error = null;
|
||||
let noChunkTimeout = null;
|
||||
let chunkHandler = (_: IHeapSnapshotChunk) => {};
|
||||
let progressHandler = (_: IHeapSnapshotProgress) => {};
|
||||
|
||||
// Cleanup function to remove listeners
|
||||
const cleanup = () => {
|
||||
client.off('HeapProfiler.addHeapSnapshotChunk', chunkHandler);
|
||||
client.off('HeapProfiler.reportHeapSnapshotProgress', progressHandler);
|
||||
};
|
||||
|
||||
// Handle file stream errors
|
||||
file.on('error', (err) => {
|
||||
error = err;
|
||||
reject(err);
|
||||
});
|
||||
|
||||
// Handle successful completion
|
||||
file.on('finish', () => {
|
||||
if (!error && isFinished) {
|
||||
resolve(0);
|
||||
}
|
||||
});
|
||||
|
||||
const scheduleEnd = () => {
|
||||
if (noChunkTimeout) {
|
||||
clearTimeout(noChunkTimeout);
|
||||
}
|
||||
|
||||
// Set new timeout
|
||||
noChunkTimeout = setTimeout(() => {
|
||||
cleanup();
|
||||
file.end();
|
||||
}, 1000); // Wait 1 second after last chunk
|
||||
};
|
||||
|
||||
// Set up the chunk handler
|
||||
chunkHandler = (payload: IHeapSnapshotChunk) => {
|
||||
try {
|
||||
if (payload.chunk) {
|
||||
file.write(payload.chunk);
|
||||
scheduleEnd();
|
||||
}
|
||||
} catch (err) {
|
||||
error = err;
|
||||
console.error('chunkHandler error', err);
|
||||
cleanup();
|
||||
reject(err);
|
||||
}
|
||||
};
|
||||
|
||||
// Set up the progress handler
|
||||
progressHandler = (params: IHeapSnapshotProgress) => {
|
||||
if (params.finished) {
|
||||
isFinished = true;
|
||||
}
|
||||
};
|
||||
|
||||
// Add event listeners
|
||||
client.on('HeapProfiler.addHeapSnapshotChunk', chunkHandler);
|
||||
client.on('HeapProfiler.reportHeapSnapshotProgress', progressHandler);
|
||||
|
||||
// Start the heap snapshot process
|
||||
client.send('HeapProfiler.enable')
|
||||
.then(() => client.send('HeapProfiler.takeHeapSnapshot', { reportProgress: true }))
|
||||
.catch((err) => {
|
||||
console.error('HeapProfiler.enable error', err);
|
||||
error = err;
|
||||
file.end();
|
||||
cleanup();
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// const isLocal = !process.env.CI;
|
||||
test('memory', async ({ page }) => {
|
||||
test.setTimeout(150_000);
|
||||
const client = await page.context().newCDPSession(page);
|
||||
|
||||
let errored = false;
|
||||
page.on('pageerror', (error) => {
|
||||
console.error('Page error:', error.name, error.message, error.stack);
|
||||
errored = true;
|
||||
});
|
||||
|
||||
await page.goto('http://localhost:3000/sheets/');
|
||||
await page.waitForTimeout(5000);
|
||||
const memoryAfterFirstInstance = (await getMetrics(client)).JSHeapUsedSize;
|
||||
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadAndRelease(1));
|
||||
await page.waitForTimeout(5000);
|
||||
const memoryAfterFirstLoad = (await getMetrics(client)).JSHeapUsedSize;
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadAndRelease(2));
|
||||
await page.waitForTimeout(5000);
|
||||
const memoryAfterSecondLoad = (await getMetrics(client)).JSHeapUsedSize;
|
||||
const unitMemoryOverflow = memoryAfterSecondLoad - memoryAfterFirstLoad;
|
||||
await reportToPosthog('unit_memory_overflow', { value: unitMemoryOverflow });
|
||||
|
||||
await page.evaluate(() => window.univer.dispose());
|
||||
await page.waitForTimeout(5000);
|
||||
await takeHeapSnapshot(client, 'memory-first.heapsnapshot');
|
||||
const memoryAfterDisposingFirstInstance = (await getMetrics(client)).JSHeapUsedSize;
|
||||
await page.evaluate(() => window.createNewInstance());
|
||||
await page.waitForTimeout(5000);
|
||||
await page.evaluate(() => window.univer.dispose());
|
||||
await page.waitForTimeout(5000);
|
||||
await takeHeapSnapshot(client, 'memory-second.heapsnapshot');
|
||||
const memoryAfterDisposingSecondUniver = (await getMetrics(client)).JSHeapUsedSize;
|
||||
const instanceMemoryOverflow = memoryAfterDisposingSecondUniver - memoryAfterDisposingFirstInstance;
|
||||
const univerMemoryOverflow = memoryAfterDisposingSecondUniver - memoryAfterFirstInstance;
|
||||
await reportToPosthog('instance_memory_overflow', { value: instanceMemoryOverflow });
|
||||
await reportToPosthog('univer_memory_overflow', { value: univerMemoryOverflow });
|
||||
await shutdownPosthog();
|
||||
|
||||
expect(unitMemoryOverflow).toBeLessThanOrEqual(MAX_UNIT_MEMORY_OVERFLOW);
|
||||
expect(instanceMemoryOverflow).toBeLessThanOrEqual(MAX_SECOND_INSTANCE_OVERFLOW);
|
||||
expect(univerMemoryOverflow).toBeLessThanOrEqual(MAX_UNIVER_MEMORY_OVERFLOW);
|
||||
|
||||
expect(errored).toBeFalsy();
|
||||
});
|
||||
|
||||
declare global {
|
||||
|
||||
interface Window {
|
||||
createNewInstance: () => void;
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
import type { CDPSession } from '@playwright/test';
|
||||
|
||||
interface IMetrics {
|
||||
JSHeapUsedSize: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a performance metric from the chrome cdp session.
|
||||
* Chrome only.
|
||||
* @param {Page} page page to attach cdpClient
|
||||
* @return {IMetrics}
|
||||
* @see {@link https://github.com/microsoft/playwright/issues/18071}
|
||||
*/
|
||||
export async function getMetrics(client: CDPSession): Promise<IMetrics> {
|
||||
await client.send('Performance.enable');
|
||||
|
||||
let metricObject: Record<string, number> = {};
|
||||
let previousHeapSize = Infinity;
|
||||
|
||||
// Run GC repeatedly until the heap size stabilizes (stops decreasing).
|
||||
// This compensates for non-deterministic GC behavior in Chromium.
|
||||
const MAX_GC_ITERATIONS = 3;
|
||||
for (let i = 0; i < MAX_GC_ITERATIONS; i++) {
|
||||
await client.send('HeapProfiler.collectGarbage');
|
||||
const perfMetricObject = await client.send('Performance.getMetrics');
|
||||
const extractedMetric = perfMetricObject?.metrics;
|
||||
metricObject = extractedMetric.reduce((acc, { name, value }) => {
|
||||
acc[name] = value;
|
||||
return acc;
|
||||
}, {} as Record<string, number>);
|
||||
|
||||
const currentHeapSize = metricObject.JSHeapUsedSize ?? Infinity;
|
||||
if (currentHeapSize >= previousHeapSize) {
|
||||
break;
|
||||
}
|
||||
previousHeapSize = currentHeapSize;
|
||||
}
|
||||
|
||||
return metricObject as unknown as IMetrics;
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
/* eslint-disable no-console */
|
||||
import type { Page } from '@playwright/test';
|
||||
import { expect, test } from '@playwright/test';
|
||||
import { sheetData as denseTextData } from '../__testing__/dense-text-scroll';
|
||||
import { sheetData as emptySheetData } from '../__testing__/emptysheet';
|
||||
import { sheetData as freezeData } from '../__testing__/freezesheet';
|
||||
import { sheetData as mergeCellData } from '../__testing__/mergecell';
|
||||
import { sheetData as overflowData } from '../__testing__/overflow';
|
||||
import { reportToPosthog } from '../utils/report-performance';
|
||||
|
||||
export interface IFPSData {
|
||||
fpsData: number[];
|
||||
avgFps: number;
|
||||
}
|
||||
|
||||
interface IJsonObject {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface IMeasureFPSParam { testDuration: number; deltaX: number; deltaY: number }
|
||||
|
||||
interface IFPSResult {
|
||||
fps: number;
|
||||
medianFrameTime: number;
|
||||
maxFrameTimes: number[];
|
||||
}
|
||||
|
||||
// const isCI = !!process.env.CI;
|
||||
/**
|
||||
* measure FPS of scrolling time.
|
||||
* @param page Page from playwright
|
||||
* @param testDuration fps test duration
|
||||
* @param deltaX scroll step of X
|
||||
* @param deltaY scroll step of Y
|
||||
* @returns {Promise<IFPSResult>} avg FPS value of test time.
|
||||
*/
|
||||
async function measureFPS(page: Page, testDuration: number, deltaX: number, deltaY: number) {
|
||||
const fpsCounterPromise = await page.evaluate(({ testDuration, deltaX, deltaY }: IMeasureFPSParam) => {
|
||||
let intervalID: number | undefined;
|
||||
// dispatch wheel event
|
||||
const dispatchWheelEvent = () => {
|
||||
const canvasElements = document.querySelectorAll('canvas[data-u-comp=render-canvas]') as unknown as HTMLElement[];
|
||||
const filteredCanvasElements = Array.from(canvasElements).filter((canvas) => canvas.offsetHeight > 500);
|
||||
|
||||
const interval = 30;
|
||||
const dispatchSimulateWheelEvent = (element: HTMLElement) => {
|
||||
const event = new WheelEvent('wheel', {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
deltaY,
|
||||
deltaX,
|
||||
clientX: 580,
|
||||
clientY: 580,
|
||||
});
|
||||
element.dispatchEvent(event);
|
||||
};
|
||||
|
||||
// mock wheel event.
|
||||
const continuousWheelSimulation = (element: HTMLElement, interval: number) => {
|
||||
intervalID = window.setInterval(function () {
|
||||
dispatchSimulateWheelEvent(element);
|
||||
}, interval);
|
||||
};
|
||||
|
||||
// start mock wheel event.
|
||||
if (filteredCanvasElements.length > 0) {
|
||||
continuousWheelSimulation(filteredCanvasElements[0], interval);
|
||||
} else {
|
||||
throw new Error('main canvas element not found');
|
||||
}
|
||||
};
|
||||
|
||||
const getMaxFrameTimes = (arr: number[], n: number) => {
|
||||
return arr.slice().sort((a, b) => b - a).slice(0, n);
|
||||
};
|
||||
|
||||
const calculateMedian = (arr: number[]) => {
|
||||
if (arr.length === 0) return 0;
|
||||
const sorted = arr.slice().sort((a, b) => a - b);
|
||||
const mid = Math.floor(sorted.length / 2);
|
||||
return sorted.length % 2 !== 0 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
|
||||
};
|
||||
|
||||
dispatchWheelEvent();
|
||||
|
||||
let frameCount = 0;
|
||||
const frameTimes: number[] = [];
|
||||
const startTime = performance.now();
|
||||
let lastFrameTime = performance.now();
|
||||
|
||||
return new Promise((resolve) => {
|
||||
function countFrames(_timestamp: number) {
|
||||
frameCount++;
|
||||
const currentFrameTime = performance.now();
|
||||
const deltaTime = currentFrameTime - lastFrameTime;
|
||||
lastFrameTime = currentFrameTime;
|
||||
if (deltaTime >= 1) {
|
||||
frameTimes.push(Math.round(deltaTime * 100) / 100);
|
||||
}
|
||||
|
||||
if (performance.now() - startTime < testDuration * 1000) {
|
||||
requestAnimationFrame(countFrames);
|
||||
} else {
|
||||
if (intervalID !== undefined) {
|
||||
window.clearInterval(intervalID);
|
||||
}
|
||||
|
||||
const elapsedTime = (performance.now() - startTime) / 1000;
|
||||
const fps = Math.round(frameCount / elapsedTime * 100) / 100;
|
||||
const maxFrameTimes = getMaxFrameTimes(frameTimes, 10);
|
||||
const medianFrameTime = calculateMedian(frameTimes);
|
||||
resolve({ fps, maxFrameTimes, medianFrameTime });
|
||||
}
|
||||
}
|
||||
|
||||
requestAnimationFrame(countFrames);
|
||||
});
|
||||
}, { testDuration, deltaX, deltaY });
|
||||
|
||||
return fpsCounterPromise as Promise<IFPSResult>;
|
||||
}
|
||||
|
||||
const createTest = (title: string, telemetryName: string, sheetData: IJsonObject, minFpsValue: number, deltaX = 0, deltaY = 0) => {
|
||||
// Default Size Of browser: 1280x720 pixels. And default DPR is 1.
|
||||
test(title, async ({ page }) => {
|
||||
await page.goto('http://localhost:3000/sheets/');
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
await test.step('create univer', async () => {
|
||||
await page.evaluate(async (sheetData) => {
|
||||
await window.E2EControllerAPI.disposeCurrSheetUnit();
|
||||
window.univerAPI.createWorkbook(sheetData);
|
||||
}, sheetData);
|
||||
// wait for canvas has data
|
||||
await page.waitForTimeout(2000);
|
||||
});
|
||||
|
||||
try {
|
||||
const resultOfFPS = await measureFPS(page, 5, deltaX, deltaY);
|
||||
await test.step('fps', async () => {
|
||||
console.log('FPS', resultOfFPS.fps);
|
||||
console.log('medianFrameTime', resultOfFPS.medianFrameTime);
|
||||
console.log('max10FrameTimes', resultOfFPS.maxFrameTimes);
|
||||
|
||||
await reportToPosthog(telemetryName, resultOfFPS);
|
||||
expect(resultOfFPS.fps).toBeGreaterThan(minFpsValue);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('error when exec scrolling test', error);
|
||||
throw error;
|
||||
} finally {
|
||||
// if you want to debug, use `await page.pause();` to pause browser
|
||||
console.log('Test case completed.');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
createTest('sheet scroll empty', 'perf.sheet.scroll.empty', emptySheetData, 50, 10, 100);
|
||||
createTest('sheet scroll after freeze', 'perf.sheet.scroll.freeze', freezeData, 30, 10, 100);
|
||||
createTest('sheet scroll in a lots of merge cell', 'perf.sheet.scroll.mergeCell', mergeCellData, 20, 10, 50);
|
||||
createTest('sheet X scroll in a lots of overflow', 'perf.sheet.scroll.overflow', overflowData, 50, 50, 5);
|
||||
createTest('sheet scroll in dense styled text', 'perf.sheet.scroll.denseText', denseTextData, 25, 0, 100);
|
||||
@@ -1,156 +0,0 @@
|
||||
import type { Page } from '@playwright/test';
|
||||
import { expect, test } from '@playwright/test';
|
||||
import * as RefRangeE2EProtocol from '../../examples/src/sheets/ref-range-e2e.protocol';
|
||||
|
||||
interface IStructuralCase {
|
||||
name: string;
|
||||
axis: RefRangeE2EProtocol.FixtureAxis;
|
||||
operation: RefRangeE2EProtocol.FixtureOperation;
|
||||
index: number;
|
||||
}
|
||||
|
||||
interface IFixtureRequestArguments {
|
||||
eventName: string;
|
||||
request: RefRangeE2EProtocol.RefRangeE2ERequest;
|
||||
}
|
||||
|
||||
const STRUCTURAL_CASES: IStructuralCase[] = [
|
||||
{ name: 'insert row', axis: 'row', operation: 'insert', index: 0 },
|
||||
{ name: 'delete row', axis: 'row', operation: 'delete', index: 0 },
|
||||
{ name: 'insert column', axis: 'column', operation: 'insert', index: 0 },
|
||||
{ name: 'delete column', axis: 'column', operation: 'delete', index: 0 },
|
||||
];
|
||||
|
||||
const POPUP_STRUCTURAL_CASES: IStructuralCase[] = [
|
||||
{ name: 'insert row before popup', axis: 'row', operation: 'insert', index: 0 },
|
||||
{ name: 'delete row before popup', axis: 'row', operation: 'delete', index: 0 },
|
||||
{ name: 'insert column before popup', axis: 'column', operation: 'insert', index: 0 },
|
||||
{ name: 'delete column before popup', axis: 'column', operation: 'delete', index: 0 },
|
||||
];
|
||||
|
||||
const RANGE_FEATURES = [
|
||||
'merge',
|
||||
'protection',
|
||||
'filter',
|
||||
'dataValidation',
|
||||
'conditionalFormatting',
|
||||
] as const;
|
||||
|
||||
const POINT_FEATURES = ['hyperlink', 'note', 'comment'] as const;
|
||||
|
||||
function executeFixture<T>(page: Page, request: RefRangeE2EProtocol.RefRangeE2ERequest): Promise<T> {
|
||||
return page.evaluate<T, IFixtureRequestArguments>(({ eventName, request: fixtureRequest }) => new Promise((resolve, reject) => {
|
||||
window.dispatchEvent(new CustomEvent(eventName, {
|
||||
detail: { request: fixtureRequest, resolve, reject },
|
||||
}));
|
||||
}), {
|
||||
eventName: RefRangeE2EProtocol.REF_RANGE_E2E_EVENT,
|
||||
request,
|
||||
});
|
||||
}
|
||||
|
||||
function snapshot(page: Page): Promise<RefRangeE2EProtocol.IFixtureSnapshot> {
|
||||
return executeFixture(page, { action: 'snapshot' });
|
||||
}
|
||||
|
||||
function modelSnapshot(value: RefRangeE2EProtocol.IFixtureSnapshot): Omit<RefRangeE2EProtocol.IFixtureSnapshot, 'popupRect'> {
|
||||
return {
|
||||
merge: value.merge,
|
||||
protection: value.protection,
|
||||
filter: value.filter,
|
||||
dataValidation: value.dataValidation,
|
||||
conditionalFormatting: value.conditionalFormatting,
|
||||
hyperlink: value.hyperlink,
|
||||
note: value.note,
|
||||
comment: value.comment,
|
||||
dataValidationFormula: value.dataValidationFormula,
|
||||
conditionalFormattingRule: value.conditionalFormattingRule,
|
||||
hyperlinkUrl: value.hyperlinkUrl,
|
||||
};
|
||||
}
|
||||
|
||||
function expectRangeShift(
|
||||
before: RefRangeE2EProtocol.IRangeRecord,
|
||||
after: RefRangeE2EProtocol.IRangeRecord,
|
||||
testCase: IStructuralCase,
|
||||
feature: string
|
||||
): void {
|
||||
const offset = testCase.operation === 'insert' ? 1 : -1;
|
||||
if (testCase.axis === 'row') {
|
||||
expect(after.startRow, `${testCase.name} ${feature} start row`).toBe(before.startRow + offset);
|
||||
expect(after.endRow, `${testCase.name} ${feature} end row`).toBe(before.endRow + offset);
|
||||
expect(after.startColumn, `${testCase.name} ${feature} start column`).toBe(before.startColumn);
|
||||
expect(after.endColumn, `${testCase.name} ${feature} end column`).toBe(before.endColumn);
|
||||
} else {
|
||||
expect(after.startColumn, `${testCase.name} ${feature} start column`).toBe(before.startColumn + offset);
|
||||
expect(after.endColumn, `${testCase.name} ${feature} end column`).toBe(before.endColumn + offset);
|
||||
expect(after.startRow, `${testCase.name} ${feature} start row`).toBe(before.startRow);
|
||||
expect(after.endRow, `${testCase.name} ${feature} end row`).toBe(before.endRow);
|
||||
}
|
||||
}
|
||||
|
||||
function expectPointShift(
|
||||
before: RefRangeE2EProtocol.IPointRecord,
|
||||
after: RefRangeE2EProtocol.IPointRecord,
|
||||
testCase: IStructuralCase,
|
||||
feature: string
|
||||
): void {
|
||||
const offset = testCase.operation === 'insert' ? 1 : -1;
|
||||
expect(after.row, `${testCase.name} ${feature} row`).toBe(before.row + (testCase.axis === 'row' ? offset : 0));
|
||||
expect(after.column, `${testCase.name} ${feature} column`).toBe(before.column + (testCase.axis === 'column' ? offset : 0));
|
||||
}
|
||||
|
||||
function expectPopupMove(
|
||||
before: RefRangeE2EProtocol.IRectRecord,
|
||||
after: RefRangeE2EProtocol.IRectRecord,
|
||||
testCase: IStructuralCase
|
||||
): void {
|
||||
const primaryPosition = testCase.axis === 'row' ? 'top' : 'left';
|
||||
const secondaryPosition = testCase.axis === 'row' ? 'left' : 'top';
|
||||
const direction = testCase.operation === 'insert' ? 1 : -1;
|
||||
expect(Math.sign(after[primaryPosition] - before[primaryPosition]), `${testCase.name} popup direction`).toBe(direction);
|
||||
expect(after[secondaryPosition], `${testCase.name} popup orthogonal position`).toBe(before[secondaryPosition]);
|
||||
expect(after.width, `${testCase.name} popup width`).toBe(before.width);
|
||||
expect(after.height, `${testCase.name} popup height`).toBe(before.height);
|
||||
}
|
||||
|
||||
test('RefRange consumers stay aligned across row and column edits', async ({ page }) => {
|
||||
const pageErrors: string[] = [];
|
||||
page.on('pageerror', (error) => pageErrors.push(error.stack ?? error.message));
|
||||
|
||||
await page.setViewportSize({ width: 1600, height: 1200 });
|
||||
await page.goto('/sheets/?ref-range-e2e');
|
||||
await page.locator(`html[${RefRangeE2EProtocol.REF_RANGE_E2E_READY_ATTRIBUTE}="true"]`).waitFor();
|
||||
const initial = await executeFixture<RefRangeE2EProtocol.IFixtureSnapshot>(page, { action: 'setup' });
|
||||
|
||||
for (const testCase of STRUCTURAL_CASES) {
|
||||
const before = await snapshot(page);
|
||||
await executeFixture<null>(page, { action: 'apply', ...testCase });
|
||||
const after = await snapshot(page);
|
||||
|
||||
for (const feature of RANGE_FEATURES) expectRangeShift(before[feature], after[feature], testCase, feature);
|
||||
for (const feature of POINT_FEATURES) expectPointShift(before[feature], after[feature], testCase, feature);
|
||||
expect(after.dataValidationFormula, `${testCase.name} data validation formula`).not.toBe(before.dataValidationFormula);
|
||||
expect(after.conditionalFormattingRule, `${testCase.name} conditional formatting formula`).not.toBe(before.conditionalFormattingRule);
|
||||
expect(after.hyperlinkUrl, `${testCase.name} hyperlink target`).not.toBe(before.hyperlinkUrl);
|
||||
expect(await executeFixture<boolean>(page, { action: 'undo' })).toBe(true);
|
||||
await expect.poll(async () => modelSnapshot(await snapshot(page))).toEqual(modelSnapshot(before));
|
||||
}
|
||||
|
||||
await expect.poll(async () => {
|
||||
const current = await snapshot(page);
|
||||
return current.popupRect.left > 0 && current.popupRect.top > 0;
|
||||
}).toBe(true);
|
||||
for (const testCase of POPUP_STRUCTURAL_CASES) {
|
||||
const before = await snapshot(page);
|
||||
await executeFixture<null>(page, { action: 'apply', ...testCase });
|
||||
const after = await snapshot(page);
|
||||
expectPopupMove(before.popupRect, after.popupRect, testCase);
|
||||
|
||||
expect(await executeFixture<boolean>(page, { action: 'undo' })).toBe(true);
|
||||
await expect.poll(() => snapshot(page), { message: `${testCase.name} undo` }).toEqual(before);
|
||||
}
|
||||
|
||||
expect(modelSnapshot(await snapshot(page))).toEqual(modelSnapshot(initial));
|
||||
expect(pageErrors).toEqual([]);
|
||||
});
|
||||
@@ -1,6 +0,0 @@
|
||||
# Notes on Smoking
|
||||
|
||||
These tests make sure that all the demo pages can be loaded without any errors. Some demos are implemented in visual comparison tests, so they are not included in this suite.
|
||||
|
||||
- docs
|
||||
- sheets
|
||||
@@ -1,44 +0,0 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
test('preserves pixels across independent viewport copies on a short canvas', async ({ page }) => {
|
||||
await page.goto('/sheets/');
|
||||
await page.waitForFunction(() => window.E2EControllerAPI != null);
|
||||
|
||||
const pixelAlphaByRatio = await page.evaluate(() => [1, 2].map((pixelRatio) => {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = 8 * pixelRatio;
|
||||
canvas.height = 4 * pixelRatio;
|
||||
const nativeContext = canvas.getContext('2d');
|
||||
if (nativeContext == null) {
|
||||
throw new Error('Failed to create the regression canvas.');
|
||||
}
|
||||
|
||||
nativeContext.fillStyle = '#2563eb';
|
||||
nativeContext.fillRect(0, 0, canvas.width, canvas.height);
|
||||
window.E2EControllerAPI.scrollAndClearCanvas(canvas, pixelRatio, [
|
||||
{
|
||||
bounds: { left: 2, top: 0, right: 8, bottom: 4 },
|
||||
offsetX: 0,
|
||||
offsetY: -1,
|
||||
},
|
||||
{
|
||||
bounds: { left: 0, top: 0, right: 2, bottom: 4 },
|
||||
offsetX: 0,
|
||||
offsetY: -1,
|
||||
},
|
||||
], [{ left: 0, top: 3, right: 8, bottom: 4 }]);
|
||||
|
||||
const getAlpha = (x: number, y: number) =>
|
||||
nativeContext.getImageData(x * pixelRatio, y * pixelRatio, 1, 1).data[3];
|
||||
return {
|
||||
main: getAlpha(4, 1),
|
||||
header: getAlpha(1, 1),
|
||||
dirty: getAlpha(4, 3),
|
||||
};
|
||||
}));
|
||||
|
||||
expect(pixelAlphaByRatio).toEqual([
|
||||
{ main: 255, header: 255, dirty: 0 },
|
||||
{ main: 255, header: 255, dirty: 0 },
|
||||
]);
|
||||
});
|
||||
@@ -1,15 +0,0 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
test('ensure mobile-s boots up without errors', async ({ page }) => {
|
||||
let errored = false;
|
||||
|
||||
page.on('pageerror', (error) => {
|
||||
console.error('Page error:', error);
|
||||
errored = true;
|
||||
});
|
||||
|
||||
await page.goto('http://localhost:3000/mobile-s/');
|
||||
await page.waitForTimeout(10000);
|
||||
|
||||
expect(errored).toBeFalsy();
|
||||
});
|
||||
@@ -1,36 +0,0 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
const SHEET_MAIN_CANVAS = '[id^="univer-sheet-main-canvas_"]';
|
||||
|
||||
test('bridges sheet pointer events when the workbook is created after the Facade', async ({ page }) => {
|
||||
const pageErrors: string[] = [];
|
||||
page.on('pageerror', (error) => pageErrors.push(error.message));
|
||||
|
||||
await page.goto('/sheets/');
|
||||
await page.waitForFunction(() => !!window.univerAPI && !!window.E2EControllerAPI);
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadDefaultSheet());
|
||||
|
||||
await page.evaluate(() => {
|
||||
document.documentElement.dataset.cellPointerDown = '0';
|
||||
document.documentElement.dataset.cellHovered = '0';
|
||||
window.univerAPI.addEvent(window.univerAPI.Event.CellPointerDown, () => {
|
||||
document.documentElement.dataset.cellPointerDown = '1';
|
||||
});
|
||||
window.univerAPI.addEvent(window.univerAPI.Event.CellHover, () => {
|
||||
document.documentElement.dataset.cellHovered = '1';
|
||||
});
|
||||
});
|
||||
|
||||
const canvas = page.locator(SHEET_MAIN_CANVAS);
|
||||
await expect(canvas).toBeVisible();
|
||||
const canvasBox = await canvas.boundingBox();
|
||||
if (!canvasBox) throw new Error('Sheet canvas is not visible');
|
||||
|
||||
await page.mouse.move(canvasBox.x + 160, canvasBox.y + 100);
|
||||
await page.mouse.move(canvasBox.x + 260, canvasBox.y + 140);
|
||||
await page.mouse.click(canvasBox.x + 260, canvasBox.y + 140, { delay: 50 });
|
||||
|
||||
await expect.poll(() => page.evaluate(() => document.documentElement.dataset.cellHovered)).toBe('1');
|
||||
await expect.poll(() => page.evaluate(() => document.documentElement.dataset.cellPointerDown)).toBe('1');
|
||||
expect(pageErrors).toEqual([]);
|
||||
});
|
||||
@@ -1,275 +0,0 @@
|
||||
import type { Page } from '@playwright/test';
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
const SHEET_MAIN_CANVAS = '[id^="univer-sheet-main-canvas_"]';
|
||||
const FORMULA_SUGGESTIONS = '[data-u-comp="sheets-formula-editor"]';
|
||||
const SHEET_EDITOR_INPUT = '#univer-doc-selection-container-__INTERNAL_EDITOR__DOCS_NORMAL';
|
||||
|
||||
interface IPoint {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
async function prepareFormulaSheet(page: Page): Promise<void> {
|
||||
await page.goto('/sheets/');
|
||||
await page.waitForFunction(() => !!window.univerAPI && !!window.E2EControllerAPI);
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadDefaultSheet(1000));
|
||||
await page.locator(SHEET_EDITOR_INPUT).waitFor({ state: 'attached' });
|
||||
await page.evaluate(async () => {
|
||||
const workbook = window.univerAPI.getActiveWorkbook();
|
||||
const worksheet = workbook.create('formula-e2e', 30, 12);
|
||||
await worksheet.getRange('A1:F6').setValues([
|
||||
[1, 2, 3, 4, 5, 6],
|
||||
[7, 8, 9, 10, 11, 12],
|
||||
[13, 14, 15, 16, 17, 18],
|
||||
[19, 20, 21, 22, 23, 24],
|
||||
[25, 26, 27, 28, 29, 30],
|
||||
[31, 32, 33, 34, 35, 36],
|
||||
]);
|
||||
const dataWorksheet = workbook.create('数据 表', 30, 12);
|
||||
await dataWorksheet.getRange('A1:C2').setValues([
|
||||
[10, 20, 30],
|
||||
[40, 50, 60],
|
||||
]);
|
||||
workbook.setActiveSheet(worksheet);
|
||||
});
|
||||
|
||||
await expect(page.locator(SHEET_MAIN_CANVAS)).toBeVisible();
|
||||
}
|
||||
|
||||
async function getCellCenter(page: Page, address: string): Promise<IPoint> {
|
||||
const canvasBox = await page.locator(SHEET_MAIN_CANVAS).boundingBox();
|
||||
if (!canvasBox) throw new Error('Sheet canvas is not visible');
|
||||
|
||||
const cellRect = await page.evaluate((cellAddress) => {
|
||||
const worksheet = window.univerAPI.getActiveWorkbook().getActiveSheet();
|
||||
return worksheet.getRange(cellAddress).getCellRect();
|
||||
}, address);
|
||||
|
||||
return {
|
||||
x: canvasBox.x + cellRect.left + cellRect.width / 2,
|
||||
y: canvasBox.y + cellRect.top + cellRect.height / 2,
|
||||
};
|
||||
}
|
||||
|
||||
async function doubleClickCell(page: Page, address: string): Promise<void> {
|
||||
const point = await getCellCenter(page, address);
|
||||
await page.mouse.dblclick(point.x, point.y, { delay: 80 });
|
||||
}
|
||||
|
||||
async function clickCell(page: Page, address: string): Promise<void> {
|
||||
const point = await getCellCenter(page, address);
|
||||
await page.mouse.click(point.x, point.y);
|
||||
}
|
||||
|
||||
async function dragRange(page: Page, startAddress: string, endAddress: string): Promise<void> {
|
||||
const start = await getCellCenter(page, startAddress);
|
||||
const end = await getCellCenter(page, endAddress);
|
||||
await page.mouse.move(start.x, start.y);
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(end.x, end.y, { steps: 8 });
|
||||
await page.mouse.up();
|
||||
}
|
||||
|
||||
async function getFormula(page: Page, address: string): Promise<string> {
|
||||
return page.evaluate((cellAddress) => {
|
||||
const worksheet = window.univerAPI.getActiveWorkbook().getActiveSheet();
|
||||
return worksheet.getRange(cellAddress).getFormula();
|
||||
}, address);
|
||||
}
|
||||
|
||||
async function getFormulaFromSheet(page: Page, sheetName: string, address: string): Promise<string> {
|
||||
return page.evaluate(({ cellAddress, name }) => {
|
||||
const worksheet = window.univerAPI.getActiveWorkbook().getSheetByName(name);
|
||||
if (!worksheet) throw new Error(`Worksheet ${name} is not available`);
|
||||
return worksheet.getRange(cellAddress).getFormula();
|
||||
}, { cellAddress: address, name: sheetName });
|
||||
}
|
||||
|
||||
async function getValue(page: Page, address: string): Promise<unknown> {
|
||||
return page.evaluate((cellAddress) => {
|
||||
const worksheet = window.univerAPI.getActiveWorkbook().getActiveSheet();
|
||||
return worksheet.getRange(cellAddress).getValue();
|
||||
}, address);
|
||||
}
|
||||
|
||||
async function insertSumFunction(page: Page): Promise<void> {
|
||||
await page.keyboard.type('=su');
|
||||
const suggestions = page.locator(FORMULA_SUGGESTIONS);
|
||||
await expect(suggestions).toBeVisible();
|
||||
await suggestions.locator('li').filter({ hasText: /^SUM/ }).first().click();
|
||||
await expect(suggestions).toBeHidden();
|
||||
await page.waitForTimeout(300);
|
||||
}
|
||||
|
||||
async function activateSheetByName(page: Page, sheetName: string): Promise<void> {
|
||||
const tab = page.getByRole('tab', { name: sheetName, exact: true });
|
||||
await expect(tab).toBeVisible();
|
||||
await tab.click();
|
||||
await expect(tab).toHaveAttribute('aria-selected', 'true');
|
||||
}
|
||||
|
||||
async function getShortcutModifier(page: Page): Promise<'Control' | 'Meta'> {
|
||||
return page.evaluate(() => /Mac/.test(navigator.appVersion) ? 'Meta' : 'Control');
|
||||
}
|
||||
|
||||
async function getRedoShortcut(page: Page): Promise<string> {
|
||||
return page.evaluate(() => /Mac/.test(navigator.appVersion) ? 'Meta+Shift+z' : 'Control+y');
|
||||
}
|
||||
|
||||
async function pasteFromSystemClipboard(page: Page): Promise<void> {
|
||||
await page.evaluate(async () => {
|
||||
const [clipboardItem] = await navigator.clipboard.read();
|
||||
if (!clipboardItem) throw new Error('The system clipboard is empty');
|
||||
|
||||
const clipboardData = new DataTransfer();
|
||||
for (const type of clipboardItem.types) {
|
||||
if (type === 'text/plain' || type === 'text/html') {
|
||||
clipboardData.setData(type, await (await clipboardItem.getType(type)).text());
|
||||
}
|
||||
}
|
||||
const pasteEvent = new ClipboardEvent('paste', {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
clipboardData,
|
||||
});
|
||||
(document.activeElement ?? document.body).dispatchEvent(pasteEvent);
|
||||
});
|
||||
}
|
||||
|
||||
test.describe('sheet formula reference selection', () => {
|
||||
test.describe.configure({ mode: 'serial' });
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await prepareFormulaSheet(page);
|
||||
});
|
||||
|
||||
test('builds multiple formula references with the mouse and commits them', async ({ page }) => {
|
||||
await doubleClickCell(page, 'H2');
|
||||
await insertSumFunction(page);
|
||||
|
||||
await dragRange(page, 'B2', 'D4');
|
||||
await page.keyboard.down('Control');
|
||||
await dragRange(page, 'F2', 'E3');
|
||||
await page.keyboard.up('Control');
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
await expect.poll(() => getFormula(page, 'H2')).toBe('=SUM(B2:D4,E2:F3)');
|
||||
await expect.poll(() => getValue(page, 'H2')).toBe(193);
|
||||
});
|
||||
|
||||
test('creates and expands formula references with the keyboard', async ({ page }) => {
|
||||
await doubleClickCell(page, 'H3');
|
||||
await insertSumFunction(page);
|
||||
|
||||
const firstReference = await getCellCenter(page, 'B2');
|
||||
await page.mouse.click(firstReference.x, firstReference.y);
|
||||
await page.waitForTimeout(100);
|
||||
await page.keyboard.press('Shift+ArrowRight');
|
||||
await page.waitForTimeout(100);
|
||||
await page.keyboard.press('Shift+ArrowRight');
|
||||
await page.waitForTimeout(100);
|
||||
await page.keyboard.press('Shift+ArrowDown');
|
||||
await page.waitForTimeout(100);
|
||||
await page.keyboard.type(',');
|
||||
await page.waitForTimeout(100);
|
||||
await page.keyboard.press('ArrowRight');
|
||||
await page.waitForTimeout(100);
|
||||
await page.keyboard.press('Shift+ArrowDown');
|
||||
await page.waitForTimeout(100);
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
await expect.poll(() => getFormula(page, 'H3')).toBe('=SUM(B2:D3,E2:E3)');
|
||||
await expect.poll(() => getValue(page, 'H3')).toBe(100);
|
||||
});
|
||||
|
||||
test('cycles a reference through every absolute state with F4', async ({ page }) => {
|
||||
const cases = [
|
||||
{ address: 'H5', presses: 1, expected: '=$B$2' },
|
||||
{ address: 'H6', presses: 2, expected: '=B$2' },
|
||||
{ address: 'H7', presses: 3, expected: '=$B2' },
|
||||
{ address: 'H8', presses: 4, expected: '=B2' },
|
||||
];
|
||||
|
||||
for (const testCase of cases) {
|
||||
await doubleClickCell(page, testCase.address);
|
||||
await page.keyboard.type('=B2');
|
||||
await page.waitForTimeout(100);
|
||||
for (let index = 0; index < testCase.presses; index++) {
|
||||
await page.keyboard.press('F4');
|
||||
await page.waitForTimeout(100);
|
||||
}
|
||||
await page.keyboard.press('Enter');
|
||||
await expect.poll(() => getFormula(page, testCase.address)).toBe(testCase.expected);
|
||||
}
|
||||
});
|
||||
|
||||
test('cancels formula editing with Escape without leaving reference-selection state behind', async ({ page }) => {
|
||||
await doubleClickCell(page, 'H9');
|
||||
await insertSumFunction(page);
|
||||
await dragRange(page, 'A1', 'C3');
|
||||
await page.keyboard.press('Escape');
|
||||
|
||||
await expect.poll(() => getFormula(page, 'H9')).toBe('');
|
||||
await expect(page.locator(FORMULA_SUGGESTIONS)).toBeHidden();
|
||||
|
||||
await clickCell(page, 'H10');
|
||||
await page.keyboard.type('42');
|
||||
await page.keyboard.press('Enter');
|
||||
await expect.poll(() => getValue(page, 'H10')).toBe(42);
|
||||
});
|
||||
|
||||
test('builds and commits a cross-sheet reference through sheet tabs', async ({ page }) => {
|
||||
await doubleClickCell(page, 'H11');
|
||||
await insertSumFunction(page);
|
||||
|
||||
await activateSheetByName(page, '数据 表');
|
||||
await page.waitForTimeout(300);
|
||||
await dragRange(page, 'A1', 'C2');
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
await expect.poll(() => getFormulaFromSheet(page, 'formula-e2e', 'H11'))
|
||||
.toBe("=SUM('数据 表'!A1:C2)");
|
||||
await activateSheetByName(page, 'formula-e2e');
|
||||
await expect.poll(() => getValue(page, 'H11')).toBe(210);
|
||||
});
|
||||
|
||||
test('edits an existing formula reference at the caret and preserves the other reference', async ({ page }) => {
|
||||
await page.evaluate(async () => {
|
||||
const worksheet = window.univerAPI.getActiveWorkbook().getActiveSheet();
|
||||
await worksheet.getRange('H12').setFormula('=SUM(B2:D3,E2:E3)');
|
||||
});
|
||||
|
||||
await doubleClickCell(page, 'H12');
|
||||
await page.keyboard.press('End');
|
||||
await page.keyboard.press('ArrowLeft');
|
||||
await page.keyboard.press('F4');
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
await expect.poll(() => getFormula(page, 'H12')).toBe('=SUM(B2:D3,E2:$E$3)');
|
||||
await expect.poll(() => getValue(page, 'H12')).toBe(100);
|
||||
});
|
||||
|
||||
test('keeps relative formula copy, undo, and redo in one user workflow', async ({ page }) => {
|
||||
await page.context().grantPermissions(['clipboard-read', 'clipboard-write']);
|
||||
const shortcutModifier = await getShortcutModifier(page);
|
||||
|
||||
await doubleClickCell(page, 'H13');
|
||||
await page.keyboard.type('=B2+C2');
|
||||
await page.keyboard.press('Enter');
|
||||
await expect.poll(() => getFormula(page, 'H13')).toBe('=B2+C2');
|
||||
|
||||
await clickCell(page, 'H13');
|
||||
await page.keyboard.press(`${shortcutModifier}+c`);
|
||||
await clickCell(page, 'I13');
|
||||
await pasteFromSystemClipboard(page);
|
||||
await expect.poll(() => getFormula(page, 'I13')).toBe('=C2+D2');
|
||||
await expect.poll(() => getValue(page, 'I13')).toBe(19);
|
||||
|
||||
await page.keyboard.press(`${shortcutModifier}+z`);
|
||||
await expect.poll(() => getFormula(page, 'I13')).toBe('');
|
||||
await page.keyboard.press(await getRedoShortcut(page));
|
||||
await expect.poll(() => getFormula(page, 'I13')).toBe('=C2+D2');
|
||||
await expect.poll(() => getValue(page, 'I13')).toBe(19);
|
||||
});
|
||||
});
|
||||
@@ -1,118 +0,0 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
const SHEET_MAIN_CANVAS = '[id^="univer-sheet-main-canvas_"]';
|
||||
const SHEET_EDITOR_INPUT_CONTAINER = '#univer-doc-selection-container-__INTERNAL_EDITOR__DOCS_NORMAL';
|
||||
|
||||
test('keeps the IME anchor on the active cell across edits', async ({ page }) => {
|
||||
await page.goto('/sheets/');
|
||||
await page.waitForTimeout(2000);
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadDefaultSheet());
|
||||
await page.waitForTimeout(3000);
|
||||
await page.locator('#app').evaluate((element) => {
|
||||
element.style.width = 'calc(100% - 240px)';
|
||||
element.style.transform = 'translateX(240px)';
|
||||
});
|
||||
await page.evaluate(() => window.dispatchEvent(new Event('resize')));
|
||||
|
||||
const canvas = page.locator(SHEET_MAIN_CANVAS);
|
||||
const canvasBox = await canvas.boundingBox();
|
||||
expect(canvasBox).not.toBeNull();
|
||||
|
||||
const inputContainer = page.locator(SHEET_EDITOR_INPUT_CONTAINER);
|
||||
const initialAnchorBox = await inputContainer.boundingBox();
|
||||
expect(initialAnchorBox).not.toBeNull();
|
||||
expect(initialAnchorBox!.x).toBeLessThan(canvasBox!.x);
|
||||
|
||||
await page.mouse.click(canvasBox!.x + 200, canvasBox!.y + 120);
|
||||
await expect.poll(async () => (await inputContainer.boundingBox())?.x).toBeGreaterThanOrEqual(canvasBox!.x);
|
||||
|
||||
const client = await page.context().newCDPSession(page);
|
||||
const anchorPositions: Array<{ x: number; y: number }> = [];
|
||||
for (const [composition, text] of [['a', '啊'], ['ai', '爱']]) {
|
||||
await client.send('Input.imeSetComposition', {
|
||||
text: composition,
|
||||
selectionStart: composition.length,
|
||||
selectionEnd: composition.length,
|
||||
replacementStart: 0,
|
||||
replacementEnd: 0,
|
||||
});
|
||||
|
||||
const anchorBox = await inputContainer.boundingBox();
|
||||
expect(anchorBox).not.toBeNull();
|
||||
expect(anchorBox!.x).toBeGreaterThanOrEqual(canvasBox!.x);
|
||||
expect(anchorBox!.x).toBeLessThan(canvasBox!.x + canvasBox!.width);
|
||||
expect(anchorBox!.y).toBeGreaterThanOrEqual(canvasBox!.y);
|
||||
expect(anchorBox!.y).toBeLessThan(canvasBox!.y + canvasBox!.height);
|
||||
anchorPositions.push({ x: anchorBox!.x, y: anchorBox!.y });
|
||||
|
||||
await client.send('Input.insertText', { text });
|
||||
await page.keyboard.press('Enter');
|
||||
}
|
||||
|
||||
expect(anchorPositions[1].y).toBeGreaterThan(anchorPositions[0].y);
|
||||
});
|
||||
|
||||
test('preserves cell styles after deleting all text and entering new IME text', async ({ page }) => {
|
||||
await page.goto('/sheets/');
|
||||
await page.waitForFunction(() => !!window.univerAPI && !!window.E2EControllerAPI);
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadDefaultSheet());
|
||||
|
||||
const canvas = page.locator(SHEET_MAIN_CANVAS);
|
||||
await expect(canvas).toBeVisible();
|
||||
const canvasBox = await canvas.boundingBox();
|
||||
if (!canvasBox) {
|
||||
throw new Error('Expected the sheet canvas to have a bounding box');
|
||||
}
|
||||
|
||||
await page.mouse.click(canvasBox.x + 200, canvasBox.y + 120);
|
||||
const cell = await page.evaluate(() => {
|
||||
const range = window.univerAPI.getActiveWorkbook().getActiveRange();
|
||||
if (!range) {
|
||||
throw new Error('Expected an active sheet range');
|
||||
}
|
||||
|
||||
range
|
||||
.setValue('A')
|
||||
.setHorizontalAlignment('center')
|
||||
.setVerticalAlignment('middle')
|
||||
.setFontSize(20)
|
||||
.setFontColor('#f05252');
|
||||
|
||||
return range.getA1Notation();
|
||||
});
|
||||
|
||||
await page.keyboard.press('F2');
|
||||
const inputContainer = page.locator(SHEET_EDITOR_INPUT_CONTAINER);
|
||||
await expect.poll(async () => (await inputContainer.boundingBox())?.x).toBeGreaterThanOrEqual(canvasBox.x);
|
||||
|
||||
await page.keyboard.press('Backspace');
|
||||
|
||||
const client = await page.context().newCDPSession(page);
|
||||
await client.send('Input.imeSetComposition', {
|
||||
text: 'xin',
|
||||
selectionStart: 3,
|
||||
selectionEnd: 3,
|
||||
replacementStart: 0,
|
||||
replacementEnd: 0,
|
||||
});
|
||||
await client.send('Input.insertText', { text: '新' });
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
await expect.poll(() => page.evaluate((a1Notation) => {
|
||||
const range = window.univerAPI.getActiveWorkbook().getActiveSheet().getRange(a1Notation);
|
||||
const style = range.getCellStyleData('cell');
|
||||
return {
|
||||
value: range.getValue(),
|
||||
horizontalAlignment: range.getHorizontalAlignment(),
|
||||
verticalAlignment: range.getVerticalAlignment(),
|
||||
fontSize: style?.fs,
|
||||
fontColor: style?.cl?.rgb,
|
||||
};
|
||||
}, cell)).toEqual({
|
||||
value: '新',
|
||||
horizontalAlignment: 'center',
|
||||
verticalAlignment: 'middle',
|
||||
fontSize: 20,
|
||||
fontColor: '#f05252',
|
||||
});
|
||||
});
|
||||
@@ -1,15 +0,0 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
test('ensure sheets-multi boots up without errors', async ({ page }) => {
|
||||
let errored = false;
|
||||
|
||||
page.on('pageerror', (error) => {
|
||||
console.error('Page error:', error);
|
||||
errored = true;
|
||||
});
|
||||
|
||||
await page.goto('http://localhost:3000/sheets-multi/');
|
||||
await page.waitForTimeout(10000);
|
||||
|
||||
expect(errored).toBeFalsy();
|
||||
});
|
||||
@@ -1,15 +0,0 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
test('ensure uni boots up without errors', async ({ page }) => {
|
||||
let errored = false;
|
||||
|
||||
page.on('pageerror', (error) => {
|
||||
console.error('Page error:', error);
|
||||
errored = true;
|
||||
});
|
||||
|
||||
await page.goto('http://localhost:3000/uni/');
|
||||
await page.waitForTimeout(10000);
|
||||
|
||||
expect(errored).toBeFalsy();
|
||||
});
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"extends": "../common/shared/tsconfigs/node.json",
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
"e2e.d.ts"
|
||||
]
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/* eslint-disable node/prefer-global/process */
|
||||
|
||||
import { PostHog } from 'posthog-node';
|
||||
|
||||
const SHOULD_REPORT_TO_POSTHOG = process.env.SHOULD_REPORT_TO_POSTHOG === 'true';
|
||||
const GIT_HASH = process.env.GITHUB_SHA;
|
||||
|
||||
let client: PostHog | null = null;
|
||||
|
||||
/**
|
||||
* Report an event to PostHog. For Univer members, you can visit https://us.posthog.com/project/133116/dashboard/332238
|
||||
* for the dashboard.
|
||||
* @param event
|
||||
* @param properties
|
||||
* @returns {Promise<void>} A promise that resolves when the event is reported.
|
||||
*/
|
||||
// eslint-disable-next-line ts/no-explicit-any
|
||||
export async function reportToPosthog(event: string, properties: Record<string | number, any>) {
|
||||
if (!SHOULD_REPORT_TO_POSTHOG) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!client) {
|
||||
const POSTHOG_API_KEY = process.env.POSTHOG_API_KEY;
|
||||
if (!POSTHOG_API_KEY) {
|
||||
return;
|
||||
}
|
||||
|
||||
client = new PostHog(POSTHOG_API_KEY, { host: 'https://us.i.posthog.com' });
|
||||
}
|
||||
|
||||
client.capture({
|
||||
timestamp: new Date(),
|
||||
event,
|
||||
distinctId: 'CI',
|
||||
properties: {
|
||||
...properties,
|
||||
git_hash: GIT_HASH,
|
||||
},
|
||||
});
|
||||
|
||||
await client.flush();
|
||||
}
|
||||
|
||||
export async function shutdownPosthog() {
|
||||
if (client) {
|
||||
await client.shutdown();
|
||||
client = null;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
# Notes on Visual Comparison
|
||||
|
||||
You should set `maxDiffPixels` on a minimum value. The cursor may be different in snapshots because it is blinking,
|
||||
especially in rich-text editors.
|
||||
|
||||
For more instructions, please read related part in [CONTRIBUTING.md](../../CONTRIBUTING.md).
|
||||
@@ -1,6 +0,0 @@
|
||||
// eslint-disable-next-line node/prefer-global/process
|
||||
export const IS_CI = !!process.env.CI;
|
||||
|
||||
export function generateSnapshotName(name: string): string {
|
||||
return IS_CI ? `${name}.ci.png` : `${name}.png`;
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
const DRAWING_SELECTED_OPERATION_ID = 'drawing.operation.set-drawing-selected';
|
||||
const SHAPE_SOURCE = `data:image/svg+xml;utf8,${encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="144" height="96"><rect x="4" y="4" width="136" height="88" rx="14" fill="#3A60F7" stroke="#1D3EA6" stroke-width="4" /></svg>')}`;
|
||||
const WRAPPING_STYLES = [
|
||||
'WRAP_SQUARE',
|
||||
'WRAP_TOP_AND_BOTTOM',
|
||||
'BEHIND_TEXT',
|
||||
'IN_FRONT_OF_TEXT',
|
||||
] as const;
|
||||
|
||||
for (const wrappingStyle of WRAPPING_STYLES) {
|
||||
test(`restores drawing layout across undo and redo for ${wrappingStyle}`, async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadDefaultDoc(0));
|
||||
const drawing = await page.evaluate(async ({ selectedOperationId, source }) => {
|
||||
const document = window.univerAPI.getActiveDocument();
|
||||
const image = await document.insertImage({
|
||||
source,
|
||||
imageSourceType: window.univerAPI.Enum.ImageSourceType.BASE64,
|
||||
width: 144,
|
||||
height: 96,
|
||||
wrappingStyle: window.univerAPI.Enum.TextWrappingStyle.INLINE,
|
||||
textRange: { startOffset: 50, endOffset: 50, collapsed: true, segmentId: '' },
|
||||
});
|
||||
if (!image) {
|
||||
throw new Error('Failed to insert the E2E drawing');
|
||||
}
|
||||
const unitId = document.getId();
|
||||
const drawingId = image.getId();
|
||||
await window.univerAPI.executeCommand(selectedOperationId, [{
|
||||
unitId,
|
||||
subUnitId: unitId,
|
||||
drawingId,
|
||||
}]);
|
||||
return { drawingId };
|
||||
}, { selectedOperationId: DRAWING_SELECTED_OPERATION_ID, source: SHAPE_SOURCE });
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
const clip = { x: 240, y: 300, width: 800, height: 300 };
|
||||
const inline = await page.screenshot({ clip });
|
||||
|
||||
await page.evaluate(({ drawingId, style }) => {
|
||||
const image = window.univerAPI.getActiveDocument().getImage(drawingId);
|
||||
if (!image?.setWrappingStyle(window.univerAPI.Enum.TextWrappingStyle[style])) {
|
||||
throw new Error(`Failed to set ${style} wrapping style`);
|
||||
}
|
||||
}, { drawingId: drawing.drawingId, style: wrappingStyle });
|
||||
await page.waitForTimeout(500);
|
||||
const wrapped = await page.screenshot({ clip });
|
||||
expect(wrapped.equals(inline)).toBe(false);
|
||||
|
||||
await page.evaluate(() => window.univerAPI.undo());
|
||||
await page.waitForTimeout(500);
|
||||
expect((await page.screenshot({ clip })).equals(inline)).toBe(true);
|
||||
|
||||
await page.evaluate(() => window.univerAPI.redo());
|
||||
await page.waitForTimeout(500);
|
||||
expect((await page.screenshot({ clip })).equals(wrapped)).toBe(true);
|
||||
});
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
import { generateSnapshotName } from '../const';
|
||||
|
||||
test('diff default doc content', async ({ page }) => {
|
||||
let errored = false;
|
||||
|
||||
page.on('pageerror', (error) => {
|
||||
console.error('Page error:', error);
|
||||
errored = true;
|
||||
});
|
||||
|
||||
await page.goto('http://localhost:3000/docs/');
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadDefaultDoc());
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
await expect(page).toHaveScreenshot(generateSnapshotName('default-doc'), { maxDiffPixels: 100 });
|
||||
expect(errored).toBeFalsy();
|
||||
});
|
||||
|
||||
test.describe('Doc layout flavors', () => {
|
||||
for (const fixture of [
|
||||
{ flavor: 1 as const, name: 'traditional' },
|
||||
{ flavor: 2 as const, name: 'modern' },
|
||||
]) {
|
||||
test(`${fixture.name} renders the representative layout fixture`, async ({ page }) => {
|
||||
const errors: Error[] = [];
|
||||
page.on('pageerror', (error) => errors.push(error));
|
||||
|
||||
await page.goto('http://localhost:3000/docs/');
|
||||
await page.waitForTimeout(2_000);
|
||||
await page.evaluate((flavor) => window.E2EControllerAPI.loadDocLayoutFixture(flavor), fixture.flavor);
|
||||
|
||||
await expect.poll(
|
||||
() => page.evaluate(() => window.univerAPI?.getActiveDocument()?.getDocumentFlavor()),
|
||||
{ timeout: 10_000 }
|
||||
).toBe(fixture.flavor);
|
||||
await expect.poll(async () => {
|
||||
const screenshot = await page.screenshot();
|
||||
return page.evaluate(async (base64) => {
|
||||
const blob = await (await fetch(`data:image/png;base64,${base64}`)).blob();
|
||||
const bitmap = await createImageBitmap(blob);
|
||||
const canvas = new OffscreenCanvas(bitmap.width, bitmap.height);
|
||||
const context = canvas.getContext('2d', { willReadFrequently: true });
|
||||
if (!context) return 0;
|
||||
context.drawImage(bitmap, 0, 0);
|
||||
const pixels = context.getImageData(0, 0, bitmap.width, bitmap.height).data;
|
||||
let ink = 0;
|
||||
for (let index = 0; index < pixels.length; index += 16) {
|
||||
const luminance = pixels[index] * 0.2126 + pixels[index + 1] * 0.7152 + pixels[index + 2] * 0.0722;
|
||||
if (pixels[index + 3] > 180 && luminance < 180) ink++;
|
||||
}
|
||||
return ink;
|
||||
}, screenshot.toString('base64'));
|
||||
}, { timeout: 10_000 }).toBeGreaterThan(1_000);
|
||||
expect(errors.map((error) => error.stack ?? error.message)).toEqual([]);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
Before Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 104 KiB |
|
Before Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 102 KiB |
@@ -1,161 +0,0 @@
|
||||
import { chromium, expect, test } from '@playwright/test';
|
||||
import { generateSnapshotName } from '../const';
|
||||
|
||||
const SHEET_MAIN_CANVAS_ID = '[id^="univer-sheet-main-canvas_"]';
|
||||
const isCI = !!process.env.CI;
|
||||
|
||||
test('diff formula related', async () => {
|
||||
const browser = await chromium.launch({
|
||||
headless: !!isCI, // Set to false to see the browser window
|
||||
});
|
||||
const context = await browser.newContext({
|
||||
viewport: { width: 1280, height: 1280 },
|
||||
deviceScaleFactor: 2, // Set your desired DPR
|
||||
});
|
||||
const page = await context.newPage();
|
||||
await page.goto('http://localhost:3000/sheets/');
|
||||
await page.waitForTimeout(2000);
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadDefaultSheet());
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
await page.evaluate(async () => {
|
||||
const worksheet = window.univerAPI.getActiveWorkbook().create('formula', 50, 20);
|
||||
worksheet.getRange('A1:C6').setValues({
|
||||
0: {
|
||||
0: {
|
||||
v: 1,
|
||||
t: 2,
|
||||
s: 'cYigQ9',
|
||||
},
|
||||
1: {
|
||||
v: 1,
|
||||
t: 2,
|
||||
s: 'cYigQ9',
|
||||
},
|
||||
},
|
||||
1: {
|
||||
0: {
|
||||
v: 2,
|
||||
t: 2,
|
||||
s: 'cYigQ9',
|
||||
},
|
||||
1: {
|
||||
v: 2,
|
||||
t: 2,
|
||||
s: 'cYigQ9',
|
||||
},
|
||||
},
|
||||
2: {
|
||||
0: {
|
||||
v: 3,
|
||||
t: 2,
|
||||
s: 'cYigQ9',
|
||||
},
|
||||
1: {
|
||||
v: 3,
|
||||
t: 2,
|
||||
s: 'cYigQ9',
|
||||
},
|
||||
},
|
||||
3: {
|
||||
0: {
|
||||
v: 4,
|
||||
t: 2,
|
||||
s: 'cYigQ9',
|
||||
},
|
||||
1: {
|
||||
v: 4,
|
||||
t: 2,
|
||||
s: 'cYigQ9',
|
||||
},
|
||||
},
|
||||
4: {
|
||||
0: {
|
||||
v: 5,
|
||||
t: 2,
|
||||
s: 'cYigQ9',
|
||||
},
|
||||
1: {
|
||||
v: 5,
|
||||
t: 2,
|
||||
s: 'cYigQ9',
|
||||
},
|
||||
},
|
||||
5: {
|
||||
0: {
|
||||
f: '=SUBTOTAL(109,A1:A5)',
|
||||
v: 15,
|
||||
t: 2,
|
||||
},
|
||||
1: {
|
||||
f: '=SUBTOTAL(109,B1:B5)',
|
||||
v: 15,
|
||||
t: 2,
|
||||
},
|
||||
2: {
|
||||
f: '=SUM(B1:B5)',
|
||||
v: 15,
|
||||
t: 2,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const worksheet2 = window.univerAPI.getActiveWorkbook().create('formula2', 50, 20);
|
||||
worksheet2.getRange('A1').setValue({ f: '=SUBTOTAL(109,formula!B1:B5)' });
|
||||
});
|
||||
|
||||
// The impact of hide row on the formula of the current worksheet
|
||||
await page.evaluate(async () => {
|
||||
const worksheet = window.univerAPI.getActiveWorkbook().getSheetByName('formula');
|
||||
window.univerAPI.getActiveWorkbook().setActiveSheet(worksheet);
|
||||
await worksheet.hideRows(3, 2);
|
||||
});
|
||||
|
||||
await page.waitForTimeout(100);
|
||||
|
||||
const filename1 = generateSnapshotName('formula-hide-row-current-worksheet');
|
||||
const screenshot1 = await page.locator(SHEET_MAIN_CANVAS_ID).screenshot();
|
||||
await expect(screenshot1).toMatchSnapshot(filename1, { maxDiffPixels: 150 });
|
||||
|
||||
// restore the hidden row
|
||||
await page.evaluate(async () => {
|
||||
const worksheet = window.univerAPI.getActiveWorkbook().getActiveSheet();
|
||||
await worksheet.showRows(3, 2);
|
||||
});
|
||||
|
||||
// The impact of filtering on the formula of the current worksheet
|
||||
await page.evaluate(async () => {
|
||||
const worksheet = window.univerAPI.getActiveWorkbook().getActiveSheet();
|
||||
const filter = await worksheet.getRange('A1:A5').createFilter();
|
||||
await filter.setColumnFilterCriteria(0, {
|
||||
colId: 0,
|
||||
filters: {
|
||||
filters: [
|
||||
'5',
|
||||
'4',
|
||||
'2',
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
await page.waitForTimeout(100);
|
||||
|
||||
const filename2 = generateSnapshotName('formula-filter-row-current-worksheet');
|
||||
const screenshot2 = await page.locator(SHEET_MAIN_CANVAS_ID).screenshot();
|
||||
await expect(screenshot2).toMatchSnapshot(filename2, { maxDiffPixels: 150 });
|
||||
|
||||
await page.evaluate(async () => {
|
||||
const worksheet2 = window.univerAPI.getActiveWorkbook().getSheetByName('formula2');
|
||||
window.univerAPI.getActiveWorkbook().setActiveSheet(worksheet2);
|
||||
});
|
||||
|
||||
await page.waitForTimeout(100);
|
||||
|
||||
const filename3 = generateSnapshotName('formula-filter-row-other-worksheet');
|
||||
const screenshot3 = await page.locator(SHEET_MAIN_CANVAS_ID).screenshot();
|
||||
await expect(screenshot3).toMatchSnapshot(filename3, { maxDiffPixels: 150 });
|
||||
|
||||
await page.waitForTimeout(1000);
|
||||
await browser.close();
|
||||
});
|
||||
|
Before Width: | Height: | Size: 81 KiB |
|
Before Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 81 KiB |
|
Before Width: | Height: | Size: 70 KiB |
@@ -1,31 +0,0 @@
|
||||
import { chromium, expect, test } from '@playwright/test';
|
||||
import { generateSnapshotName } from '../const';
|
||||
|
||||
const isCI = !!process.env.CI;
|
||||
|
||||
test('sheets no gridlines', async () => {
|
||||
const browser = await chromium.launch({
|
||||
headless: !!isCI, // Set to false to see the browser window
|
||||
});
|
||||
const context = await browser.newContext({
|
||||
viewport: { width: 1280, height: 720 },
|
||||
deviceScaleFactor: 2, // Set your desired DPR
|
||||
});
|
||||
const page = await context.newPage();
|
||||
await page.goto('http://localhost:3000/sheets/');
|
||||
await page.waitForTimeout(2000);
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadDefaultSheet());
|
||||
await page.waitForTimeout(5000);
|
||||
await page.evaluate(() => window.univerAPI.getActiveWorkbook().getActiveSheet().setHiddenGridlines(true));
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
const filename = generateSnapshotName('sheets-no-gridlines');
|
||||
const screenshot = await page.screenshot({
|
||||
mask: [
|
||||
page.locator('[data-u-comp=headerbar]'),
|
||||
page.locator('[data-u-comp=formula-bar]'),
|
||||
],
|
||||
fullPage: true,
|
||||
});
|
||||
expect(screenshot).toMatchSnapshot(filename, { maxDiffPixelRatio: 0.005 });
|
||||
});
|
||||