Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .agent/skills/s2-lint/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ description: After modifying S2 project code, you must run lint to ensure there
**After modifying any code files in the `packages/` directory, you must use this skill before finishing the task.**

This includes but is not limited to:

- Modifying `.ts`, `.tsx`, `.vue` files
- Adding new source code files
- Modifying type definition files (`.d.ts`)
Expand All @@ -26,10 +27,11 @@ pnpm lint
```

This command runs the following checks sequentially:

- `lint:type` - TypeScript type checking
- `lint:script` - ESLint code style checking
- `lint:style` - Stylelint CSS/LESS checking
- `lint:docs` - Markdownlint documentation checking
- `lint:docs` - MarkdownLint documentation checking
- `lint:word` - Case-police word casing checking

## Handling Errors
Expand Down
4 changes: 3 additions & 1 deletion .agent/skills/s2-unit-test/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ description: Guidelines for writing and maintaining unit tests in the S2 project
## When to Use This Skill

Use this skill when you:

- Modify code under `packages/*/src/`
- Fix bugs (especially with issue numbers)
- Add new features or functions
Expand All @@ -20,7 +21,7 @@ Use this skill when you:

Search for `__tests__` directories to find where tests for the modified file already exist:

```
```text
packages/s2-core/__tests__/unit/ # Unit tests organized by module
packages/s2-core/__tests__/bugs/ # Bug regression tests with issue numbers
packages/s2-core/__tests__/spreadsheet/ # Integration-level spreadsheet tests
Expand Down Expand Up @@ -150,6 +151,7 @@ pnpm --filter @antv/s2 test:coverage
## Goal

The primary goal of unit tests is to:

- **Increase line coverage** - Every line of src code should be exercised
- **Increase branch coverage** - Test all conditional paths
- **Prevent regressions** - Ensure bugs don't reappear
Expand Down
13 changes: 10 additions & 3 deletions packages/s2-vue/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,12 @@
"tsc": "vue-tsc --noEmit"
},
"dependencies": {
"@ant-design/icons-vue": "^6.1.0",
"@vueuse/core": "^10.5.0",
"lodash": "^4.17.21"
"lodash": "^4.17.21",
"tinycolor2": "^1.4.2",
"tinygradient": "^1.1.5",
"vuedraggable": "^4.1.0"
},
"devDependencies": {
"@antv/event-emitter": "^0.1.3",
Expand Down Expand Up @@ -85,11 +89,14 @@
{
"path": "./dist/s2-vue.min.js",
"import": "{ createComponent }",
"limit": "38 kB",
"limit": "65 kB",
"ignore": [
"S2",
"Vue",
"antd"
"ant-design-vue",
"lodash",
"@vueuse/core",
"@ant-design/icons-vue"
]
},
{
Expand Down
4 changes: 4 additions & 0 deletions packages/s2-vue/playground/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
// Import playground components
import BigDataSheetDemo from './components/BigDataSheet.vue';
import ChartSheetDemo from './components/ChartSheet.vue';
import ComponentsPlaygroundDemo from './components/ComponentsPlayground.vue';
import CustomGridDemo from './components/CustomGrid.vue';
import CustomTreeDemo from './components/CustomTree.vue';
import EditableSheetDemo from './components/EditableSheet.vue';
Expand Down Expand Up @@ -635,6 +636,9 @@ const setThemeCfg = (cb: any) => {
<a-tab-pane key="bigData" tab="100万数据">
<BigDataSheetDemo />
</a-tab-pane>
<a-tab-pane key="components" tab="组件扩展">
<ComponentsPlaygroundDemo />
</a-tab-pane>
</a-tabs>
</div>
</template>
Expand Down
243 changes: 243 additions & 0 deletions packages/s2-vue/playground/components/ComponentsPlayground.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
<script setup lang="ts">
/* eslint-disable no-console */
import {
type SpreadSheet,
type ThemeCfg,
type ThemeName,
type S2Options,
} from '@antv/s2';
import { Button, Space, Popover } from 'ant-design-vue';
import { ref, shallowRef, computed } from 'vue';
import {
SheetComponent,
ThemePanel,
TextAlignPanel,
FrozenPanel,
Switcher,
AdvancedSort,
DrillDown,
StrategyExport,
} from '../../src';
import type {
ThemePanelOptions,
TextAlignPanelOptions,
FrozenPanelOptions,
} from '../../src';
import { pivotSheetDataCfg, defaultOptions } from '../config';

const s2Ref = shallowRef<SpreadSheet>();
const themeCfg = ref<ThemeCfg>({
name: 'default',
});
const options = ref<S2Options>({
...defaultOptions,
width: 800,
height: 600,
});

const onSheetMounted = (instance: SpreadSheet) => {
s2Ref.value = instance;
console.log('onMounted:', instance);
};

const onThemeChange = (panelOptions: ThemePanelOptions, theme: any) => {
themeCfg.value = {
name: panelOptions.themeType as ThemeName,
theme,
};
if (s2Ref.value) {
s2Ref.value.setOptions({
hierarchyType: panelOptions.hierarchyType,
});
s2Ref.value.render(false);
}

console.log('ThemePanel onChange:', panelOptions, theme);
};

const onThemeReset = (
panelOptions: ThemePanelOptions,
prevOptions: ThemePanelOptions,
theme: any,
) => {
console.log('ThemePanel onReset:', panelOptions, prevOptions, theme);
};

const onTextAlignChange = (panelOptions: TextAlignPanelOptions, theme: any) => {
themeCfg.value = {
...themeCfg.value,
theme,
};
if (s2Ref.value) {
s2Ref.value.render(false);
}

console.log('TextAlignPanel onChange:', panelOptions, theme);
};

const onTextAlignReset = (
panelOptions: TextAlignPanelOptions,
prevOptions: TextAlignPanelOptions,
theme: any,
) => {
console.log('TextAlignPanel onReset:', panelOptions, prevOptions, theme);
};

const onFrozenChange = (panelOptions: FrozenPanelOptions) => {
const [rowCount = 0, trailingRowCount = 0] = panelOptions.frozenRow;
const [colCount = 0, trailingColCount = 0] = panelOptions.frozenCol;

if (s2Ref.value) {
s2Ref.value.setOptions({
frozen: {
rowHeader: panelOptions.frozenRowHeader,
rowCount,
colCount,
trailingRowCount,
trailingColCount,
},
});
s2Ref.value.render(false);
}

console.log('FrozenPanel onChange:', panelOptions);
};

const onFrozenReset = (
panelOptions: FrozenPanelOptions,
prevOptions: FrozenPanelOptions,
) => {
console.log('FrozenPanel onReset:', panelOptions, prevOptions);
};

const toSwitcherItems = (fields: any[] = []) => {
return fields.map((f) => {
return typeof f === 'string' ? { id: f } : { id: f.field, ...f };
});
};

// Switcher Logic
const switcherFields = ref({
rows: pivotSheetDataCfg.fields.rows,
columns: pivotSheetDataCfg.fields.columns,
values: pivotSheetDataCfg.fields.values,
});

const dataCfg = computed(() => {
return {
...pivotSheetDataCfg,
fields: {
...pivotSheetDataCfg.fields,
...switcherFields.value,
},
};
});

const onSwitcherSubmit = ({ rows, columns, values }: any) => {
console.log('Switcher onSubmit:', rows, columns, values);
switcherFields.value = {
rows: rows.items.map((i: any) => i.id),
columns: columns.items.map((i: any) => i.id),
values: values.items.map((i: any) => i.id),
};
if (s2Ref.value) {
s2Ref.value.render(false);
}
};

// Advanced Sort Logic
const onSortConfirm = (ruleValues: any[], sortParams: any[]) => {
console.log('AdvancedSort onConfirm:', ruleValues, sortParams);
if (s2Ref.value) {
s2Ref.value.setDataCfg({
...s2Ref.value.dataCfg,
sortParams,
});
s2Ref.value.render(false);
}
};

// Drill Down Logic
const drillFields = ref<string[]>([]);
</script>

<template>
<div class="components-playground">
<Space direction="horizontal" class="config-panels">
<ThemePanel
title="主题配置"
:disableCustomPrimaryColorPicker="false"
:defaultCollapsed="false"
@change="onThemeChange"
@reset="onThemeReset"
/>
<TextAlignPanel
title="文字对齐"
:defaultCollapsed="false"
@change="onTextAlignChange"
@reset="onTextAlignReset"
/>
<FrozenPanel
title="冻结行列头"
:defaultCollapsed="false"
:inputNumberProps="{
size: 'small',
step: 1,
}"
:defaultOptions="{
frozenRow: [1, 2],
}"
@change="onFrozenChange"
@reset="onFrozenReset"
/>
<Switcher
title="行列切换"
:rows="{ items: toSwitcherItems(dataCfg.fields.rows) }"
:columns="{ items: toSwitcherItems(dataCfg.fields.columns) }"
:values="{ items: toSwitcherItems(dataCfg.fields.values) }"
@submit="onSwitcherSubmit"
/>
<AdvancedSort
v-if="s2Ref"
:sheetInstance="s2Ref"
@sort-confirm="onSortConfirm"
/>
<Popover trigger="click" placement="bottomLeft">
<template #content>
<DrillDown
:dataSet="[
{ name: '地区', value: 'area', type: 'location' },
{ name: '城市', value: 'city', type: 'location' },
{ name: '日期', value: 'date', type: 'date' },
]"
v-model:drillFields="drillFields"
/>
</template>
<Button>下钻</Button>
</Popover>
<StrategyExport v-if="s2Ref" :sheetInstance="s2Ref" />
</Space>
<SheetComponent
:dataCfg="dataCfg"
:options="options"
:themeCfg="themeCfg"
sheetType="pivot"
@mounted="onSheetMounted"
adaptive
/>
</div>
</template>

<style lang="less" scoped>
.components-playground {
display: flex;
flex-direction: column;
gap: 20px;

.config-panels {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
}
}
</style>
1 change: 1 addition & 0 deletions packages/s2-vue/src/common-extra/constants/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './theme';
Loading
Loading