,
31 | ) => {
32 | try {
33 | console.groupCollapsed('[html2sketch]开始转换...');
34 | let result;
35 | if (elements instanceof Array) {
36 | const objects: Object[] = [];
37 |
38 | for (let i = 0; i < elements.length; i += 1) {
39 | const el = elements[i];
40 | // eslint-disable-next-line no-await-in-loop
41 | const symbolJSON = await parserFunc(el);
42 | objects.push(symbolJSON);
43 | }
44 |
45 | result = objects;
46 | } else {
47 | result = await parserFunc(elements);
48 | }
49 | console.groupEnd();
50 | console.log('解析结果:', result);
51 | copy(JSON.stringify(result));
52 | setJSON(result);
53 | await message.success('转换成功🎉 已复制到剪切板');
54 | return result;
55 | } catch (e) {
56 | await message.error('解析失败,请检查 Console 输出 😶');
57 | console.groupEnd();
58 | console.groupEnd();
59 | console.error('报错如下:');
60 | console.error(e);
61 | }
62 | };
63 |
64 | /**
65 | * 生成 Group 的方法
66 | * @param elements
67 | */
68 |
69 | return {
70 | sketchJSON,
71 | generateSymbol: async (elements: Element | Element[]) => {
72 | await parserFactory(elements, async (el: Element) =>
73 | (await nodeToSymbol(el)).toSketchJSON(),
74 | );
75 | },
76 | generateGroup: async (elements: Element | Element[]) => {
77 | await parserFactory(elements, async (el: Element) =>
78 | (await nodeToGroup(el)).toSketchJSON(),
79 | );
80 | },
81 | };
82 | };
83 |
84 | export default useSketchJSON;
85 |
--------------------------------------------------------------------------------
/.dumirc.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'dumi';
2 | import { resolve } from 'path';
3 |
4 | import { nav, sidebar } from './config/routes';
5 |
6 | const isProdSite =
7 | // 不是预览模式 同时是生产环境
8 | process.env.PREVIEW !== '1' && process.env.NODE_ENV === 'production';
9 |
10 | export default defineConfig({
11 | themeConfig: {
12 | name: 'html2sketch',
13 | logo: 'https://gw.alipayobjects.com/zos/antfincdn/8AsXJa8sgo/Logo.svg',
14 | nav,
15 | sidebar,
16 | },
17 | theme: {
18 | '@c-primary': '#ff9800',
19 | },
20 | outputPath: 'docs-dist',
21 | // 部署在非根目录时, base 和 publicPath 都需要配置
22 | base: isProdSite ? '/html2sketch/' : '/',
23 | publicPath: isProdSite ? '/html2sketch/' : '/',
24 | alias: {
25 | '@docs-utils': resolve(__dirname, './.dumi/theme/builtins/ToSketch'),
26 | },
27 | hash: true,
28 | });
29 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
14 |
15 | [Makefile]
16 | indent_style = tab
17 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | /lambda/mock/**
2 | /scripts
3 | /config
4 | /example
5 | _test_
6 | __test__
7 |
8 | /node_modules
9 | jest*
10 | /es
11 | /lib
12 | /docs
13 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | const config = require('@umijs/max/eslint');
2 |
3 | module.exports = {
4 | ...config,
5 | rules: {
6 | ...config.rules,
7 | 'no-param-reassign': 0,
8 | },
9 | settings: {
10 | 'import/resolver': {
11 | alias: {
12 | map: [
13 | ['html2sketch', './src/'],
14 | ['html2sketch/*', './src/*'],
15 | ['@docs-utils', './docs/__utils__'],
16 | ['@test-utils', './tests/__utils__'],
17 | ],
18 | },
19 | typescript: {
20 | alwaysTryTypes: true,
21 | },
22 | },
23 | },
24 | };
25 |
--------------------------------------------------------------------------------
/.fatherrc.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'father';
2 |
3 | export default defineConfig({
4 | cjs: {
5 | output: 'lib',
6 | transformer: 'babel',
7 | },
8 | esm: {
9 | output: 'es',
10 | },
11 | umd: {
12 | entry: 'src/index.ts',
13 | output: 'dist',
14 | name: 'html2sketch',
15 | },
16 | });
17 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: '报告Bug 🐛'
3 | about: 报告 html2sketch 的 bug
4 | title: '🐛[BUG]'
5 | labels: '🐛 BUG'
6 | assignees: ''
7 | ---
8 |
9 | ### 🐛 bug 描述
10 |
11 |
14 |
15 | ### 📷 复现步骤
16 |
17 |
20 |
21 | ### 🏞 期望结果
22 |
23 |
26 |
27 | ### 💻 复现代码
28 |
29 |
33 |
34 | [可复现 demo](https://codesandbox.io/s/html2ksetch-demo-m53be?file=/src/Demo.tsx)
35 |
36 | ### © 版本信息
37 |
38 | - html2sketch 版本: [e.g. 1.0.0]
39 | - 浏览器环境
40 | - 开发环境 [e.g. mac OS]
41 |
42 | ### 🚑 其他信息
43 |
44 |
47 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: '功能需求 ✨'
3 | about: 对 html2sketch 的需求或建议
4 | title: '👑 [需求]'
5 | labels: '👑 Feature'
6 | assignees: ''
7 | ---
8 |
9 | ### 🥰 需求描述
10 |
11 |
14 |
15 | ### 🧐 解决方案
16 |
17 |
20 |
21 | ### 🚑 其他信息
22 |
23 |
26 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/question.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: '疑问或需要帮助 ❓'
3 | about: 对 html2sketch 使用的疑问或需要帮助
4 | title: '🧐[问题]'
5 | labels: '🧐 Question'
6 | assignees: ''
7 | ---
8 |
9 | ### 🧐 问题描述
10 |
11 |
14 |
15 | ### 💻 示例代码
16 |
17 |
20 |
21 | ### 🚑 其他信息
22 |
23 |
26 |
--------------------------------------------------------------------------------
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | name: Deploy CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 |
8 | jobs:
9 | build-and-deploy:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Checkout 🛎️
13 | uses: actions/checkout@v3
14 |
15 | - name: Install pnpm
16 | uses: pnpm/action-setup@v2
17 | with:
18 | version: 7
19 |
20 | - name: Setup Node.js environment
21 | uses: actions/setup-node@v3
22 | with:
23 | node-version: '16'
24 |
25 | - name: Install and Build 🔧
26 | run: |
27 | pnpm i
28 | pnpm run lint
29 | pnpm run docs:build
30 |
31 | - name: Deploy 🚀
32 | uses: JamesIves/github-pages-deploy-action@4.1.1
33 | with:
34 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
35 | BRANCH: gh-pages # The branch the action should deploy to.
36 | FOLDER: docs-dist # The folder the action should deploy.
37 | CLEAN: true # Automatically remove deleted files from the deploy branch
38 |
--------------------------------------------------------------------------------
/.github/workflows/preview.yml:
--------------------------------------------------------------------------------
1 | name: Surge PR Preview
2 |
3 | on: [pull_request]
4 |
5 | jobs:
6 | preview:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v3
10 |
11 | - name: Install pnpm
12 | uses: pnpm/action-setup@v2
13 | with:
14 | version: 7
15 |
16 | - uses: afc163/surge-preview@v1
17 | with:
18 | surge_token: ${{ secrets.SURGE_TOKEN }}
19 | github_token: ${{ secrets.GITHUB_TOKEN }}
20 | build: |
21 | pnpm i
22 | pnpm run docs:preview
23 | dist: docs-dist
24 |
25 | - name: Get the preview_url
26 | run: echo "url => ${{ steps.preview_step.outputs.preview_url }}"
27 |
28 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release CI
2 | on:
3 | push:
4 | branches:
5 | - master
6 | - beta
7 |
8 | jobs:
9 | test:
10 | name: Test
11 | runs-on: macos-latest
12 | steps:
13 | - uses: actions/checkout@v3
14 |
15 | - name: Install pnpm
16 | uses: pnpm/action-setup@v2
17 | with:
18 | version: 7
19 |
20 | - name: Setup Node.js environment
21 | uses: actions/setup-node@v3
22 | with:
23 | node-version: '16'
24 |
25 | - name: Install deps
26 | run: pnpm install
27 |
28 | - name: Test
29 | run: pnpm run test
30 |
31 | release:
32 | needs: test
33 | name: Release
34 | runs-on: ubuntu-latest
35 | steps:
36 | - uses: actions/checkout@v3
37 |
38 | - name: Install pnpm
39 | uses: pnpm/action-setup@v2
40 | with:
41 | version: 7
42 |
43 | - name: Setup Node.js environment
44 | uses: actions/setup-node@v3
45 | with:
46 | node-version: '16'
47 |
48 | - name: Install deps
49 | run: pnpm install
50 |
51 | - name: build
52 | run: pnpm run build
53 |
54 | - name: release
55 | run: pnpm run release
56 | env:
57 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
58 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
59 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Test CI
2 | on: [push, pull_request]
3 | jobs:
4 | test:
5 | runs-on: macos-latest
6 |
7 | steps:
8 | - uses: actions/checkout@v3
9 |
10 | - name: Install pnpm
11 | uses: pnpm/action-setup@v2
12 | with:
13 | version: 7
14 |
15 | - name: Setup Node.js environment
16 | uses: actions/setup-node@v3
17 | with:
18 | node-version: '16'
19 |
20 | - name: Install deps
21 | run: pnpm install
22 |
23 | - name: lint
24 | run: pnpm run ci
25 |
26 | - name: test
27 | run: pnpm run test:coverage
28 |
29 | - name: Generate coverage
30 | run: bash <(curl -s https://codecov.io/bash)
31 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | **/node_modules
5 | # roadhog-api-doc ignore
6 | /src/utils/request-temp.js
7 | _roadhog-api-doc
8 |
9 | # production
10 | **/dist
11 | /.vscode
12 | /es
13 | /lib
14 |
15 | # misc
16 | .DS_Store
17 | storybook-static
18 | npm-debug.log*
19 | yarn-error.log
20 |
21 | /coverage
22 | .idea
23 | package-lock.json
24 | *bak
25 | .vscode
26 |
27 | # visual studio code
28 | .history
29 | *.log
30 | functions/*
31 | lambda/mock/index.js
32 | .temp/**
33 |
34 | # umi
35 | .dumi/tmp
36 | .dumi/tmp-test
37 | .dumi/tmp-production
38 |
39 | # screenshot
40 | screenshot
41 | .firebase
42 | example/.temp/*
43 | .eslintcache
44 | techUI*
45 | docs-dist
46 | .env
47 |
--------------------------------------------------------------------------------
/.gitpod.yml:
--------------------------------------------------------------------------------
1 | tasks:
2 | - init: npm install
3 | command: npm start
4 |
--------------------------------------------------------------------------------
/.husky/commit-msg:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | . "$(dirname -- "$0")/_/husky.sh"
3 |
4 | npx --no-install commitlint --edit $1
5 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | . "$(dirname -- "$0")/_/husky.sh"
3 |
4 | npx --no-install lint-staged
5 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | registry=https://registry.npmmirror.com/
2 | electron_mirror=https://npmmirror.com/mirrors/electron/
3 | lockfile=false
4 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | **/*.svg
2 | .umi
3 | .umi-production
4 | /dist
5 | .dockerignore
6 | .DS_Store
7 | .eslintignore
8 | *.png
9 | *.toml
10 | docker
11 | .editorconfig
12 | Dockerfile*
13 | .gitignore
14 | .prettierignore
15 | LICENSE
16 | .eslintcache
17 | *.lock
18 | yarn-error.log
19 | tests/__tests__/antd/json
20 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | printWidth: 100,
3 | singleQuote: true,
4 | trailingComma: 'all',
5 | proseWrap: 'never',
6 | endOfLine: 'lf',
7 | overrides: [{ files: '.prettierrc', options: { parser: 'json' } }],
8 | plugins: [require.resolve('prettier-plugin-organize-imports')],
9 | pluginSearchDirs: false,
10 | };
11 |
--------------------------------------------------------------------------------
/.releaserc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [
3 | //负责解析 commit
4 | [
5 | '@semantic-release/commit-analyzer',
6 | {
7 | // 自定义配置,如果不填则是默认的 conventional-changelog-angular
8 | config: 'conventional-changelog-gitmoji-config',
9 | // build 会触发新的构建
10 | releaseRules: [{ type: 'build', release: 'patch' }],
11 | },
12 | ],
13 | [
14 | '@semantic-release/release-notes-generator', //此处生成 github-release 的日志
15 | {
16 | //指定配置,这里才是负责生成日志的,也就是说,如果自定义了writerOpts,只有在这里写才会生效
17 | config: 'conventional-changelog-gitmoji-config',
18 | },
19 | ],
20 | [
21 | '@semantic-release/changelog', //此处会调用上一个插件生成的新增日志,然后合并到原有日志中
22 | {
23 | changelogFile: 'CHANGELOG.md',
24 | changelogTitle: '# html2sketch 更新日志',
25 | },
26 | ],
27 | '@semantic-release/npm', // 如果是npm包会自动更新版本号并发布
28 | '@semantic-release/github', // 推送代码回到GitHub
29 | [
30 | '@semantic-release/git', //发布release
31 | {
32 | assets: ['CHANGELOG.md', 'package.json'],
33 | message:
34 | ':bookmark: chore(release): ${nextRelease.gitTag} [skip ci] \n\n${nextRelease.notes}',
35 | },
36 | ],
37 | ],
38 | };
39 |
--------------------------------------------------------------------------------
/.stylelintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = require('@umijs/max/stylelint');
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Arvin Xu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/docs/e2e/basic/background.md:
--------------------------------------------------------------------------------
1 | ## 说明
2 |
3 | 解析图片放在背景中的测试
4 |
5 | 加载方式:
6 |
7 | - 网址
8 | - Base64
9 |
10 | 图片类型
11 |
12 | - svg
13 | - png
14 |
15 | ## 背景图片为 image 不限制尺寸
16 |
17 |
18 |
19 | ## 背景图片为 image 限制尺寸
20 |
21 |
22 |
23 | ## 背景内联 Svg
24 |
25 |
26 |
27 | ## 背景内联 Png
28 |
29 |
30 |
--------------------------------------------------------------------------------
/docs/e2e/basic/canvas.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Canvas 解析
3 | ---
4 |
5 | ## 基本 Canvas 解析
6 |
7 |
8 |
9 | ## Canvas 跨域图片解析
10 |
11 |
12 |
13 | ### 跨域问题说明
14 |
15 | 某些 Canvas 由于绘制了跨域图片,因此无法使用 `toDataURL` 方法 ,会报错:
16 |
17 | ```
18 | Tainted canvases may not be exported
19 | ```
20 |
21 | ### 解决方案
22 |
23 | 这个时候解决方案有两种:
24 |
25 | #### 你可以控制 `img`
26 |
27 | 如果你可以控制提供 canvas 渲染的 img 节点,那一切都行相对容易,给 img 节点添加上 `crossOrigin` 属性即可
28 |
29 | ```html
30 |
31 |
32 |
33 |
38 | ```
39 |
40 | 不过这样的前提是你的图片服务器请求头中必须带有 `Access-Control-Allow-Origin "*"` ,否则就会提示跨域问题
41 |
42 | PS: 如果无法处理图片服务器,可以利用 `cors-anywhere` 进行中转,或自行搭建代理
43 |
44 | ```
45 | https://cors-anywhere.herokuapp.com/${url}
46 | ```
47 |
48 | #### 你不能控制 `img`
49 |
50 | 如果你没法拿到 image 的 src 只能通过禁用 chrome 的同源策略才能解决
51 |
52 | 禁用方法(以 macOS 为例):
53 |
54 | macOS:
55 |
56 | ```bash
57 | open -a "/Applications/Google Chrome.app" --args \
58 | --disable-web-security \
59 | --user-data-dir=/Users/{your account name}/chromeTempData/
60 | ```
61 |
62 | 第一次打开如下图,就说明已经禁用同源策略了: 
63 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/BackgroundImage/Inline.less:
--------------------------------------------------------------------------------
1 | .base {
2 | display: block;
3 | width: 14px;
4 | height: 14px;
5 | background-color: #006eff;
6 | background-repeat: no-repeat;
7 | background-position: center;
8 | background-size: 100% auto;
9 | }
10 | .checkSvg {
11 | .base;
12 |
13 | background-image: url('https://ue.qzone.qq.com/work/sketch-dev/sketch-test/tea-table-components/src/checkbox.svg');
14 | }
15 |
16 | .checkPng {
17 | .base;
18 |
19 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAASCAYAAABB7B6eAAAAAXNSR0IArs4c6QAAALtJREFUOBGtlDEOwyAMRbN06Uk69S65UY+TLj1Wl94gC3muYikBnEBsS5YVsN83EBiGQEspPQJxexTwFz7j434m4GuFE/4WKwJSOs/ty8Dd3TuQGvzH+LOAM3jDJ7xpD8nrhn8oEjvdQ3La4bIUCt5C3pgpQk4ffBUYKRTo1goRJvvhehgUH4q44A0icvi51f8WhVkRSm0lMXAVPRG51rnCNRoiMXBDJBaeicjbUl5/TfJG4P6Hy9uEVb8Awfj6IeYP7jsAAAAASUVORK5CYII=');
20 | }
21 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/BackgroundImage/InlinePng.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | // @ts-ignore
4 | import styles from './Inline.less';
5 |
6 | export default () => {
7 | return ;
8 | };
9 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/BackgroundImage/InlineSvg.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | // @ts-ignore
4 | import styles from './Inline.less';
5 |
6 | export default () => ;
7 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/BackgroundImage/WithSize.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default () => (
4 |
12 | );
13 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/BackgroundImage/WithoutSize.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default () => (
4 |
12 | );
13 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/CanvasCors.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * hideSketchLayout: true
3 | */
4 | import { TestLayout, useElements } from '@docs-utils';
5 | import React, { useEffect } from 'react';
6 |
7 | export default () => {
8 | const { elements, ref } = useElements();
9 |
10 | useEffect(() => {
11 | const canvas = ref.current;
12 | const ctx = canvas.getContext('2d');
13 | const image = document.getElementById('source');
14 |
15 | image!.onload = function () {
16 | ctx.drawImage(image, 0, 0);
17 | };
18 | }, []);
19 | return (
20 |
21 |
22 |
23 |
24 |
25 |

30 |
31 |
32 | );
33 | };
34 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/Checkbox.tsx:
--------------------------------------------------------------------------------
1 | import { Checkbox } from 'antd';
2 | import React, { FC } from 'react';
3 |
4 | const SwitchDemo: FC = () => (
5 | <>
6 | no checked
7 | Checkbox
8 | >
9 | );
10 |
11 | export default SwitchDemo;
12 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/Image/ImageNoProtocol.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | /**
4 | *
5 | */
6 | export default () => {
7 | return (
8 |
13 | );
14 | };
15 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/Image/ImagePng.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | /**
4 | *
5 | */
6 | export default () => {
7 | return (
8 |
9 |

14 |
15 | );
16 | };
17 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/Image/ImageSvg.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default () => (
4 | <>
5 |
9 |
10 |

15 | 开启引导
16 |

21 |
22 | >
23 | );
24 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/Overflow/switch.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './switch.css';
3 |
4 | export default () => (
5 |
9 | );
10 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/Position.less:
--------------------------------------------------------------------------------
1 | .ant-radio-inner {
2 | position: relative;
3 | top: 0;
4 | left: 0;
5 | display: block;
6 | width: 16px;
7 | height: 16px;
8 | background-color: #fff;
9 | border-color: #d9d9d9;
10 | border-style: solid;
11 | border-width: 1px;
12 | border-radius: 50%;
13 | transition: all 0.3s;
14 |
15 | &::after {
16 | position: absolute;
17 | top: 50%;
18 | left: 50%;
19 | display: block;
20 | width: 16px;
21 | height: 16px;
22 | margin-top: -8px;
23 | margin-left: -8px;
24 | background-color: #1890ff;
25 | border-top: 0;
26 | border-left: 0;
27 | border-radius: 16px;
28 | transform: scale(0.5);
29 | opacity: 1;
30 | transition: all 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
31 | content: ' ';
32 | z-index: 10;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/Position.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import './Position.less';
4 |
5 | export default () => (
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/Radio.tsx:
--------------------------------------------------------------------------------
1 | import { Radio } from 'antd';
2 | import React from 'react';
3 |
4 | export default () => (
5 |
6 | 内容
7 |
8 | );
9 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/Select.tsx:
--------------------------------------------------------------------------------
1 | import { Select } from 'antd';
2 | import React from 'react';
3 |
4 | const { Option } = Select;
5 |
6 | export default () => {
7 | return (
8 |
13 | );
14 | };
15 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/Switch.tsx:
--------------------------------------------------------------------------------
1 | import { Space, Switch } from 'antd';
2 | import React, { FC } from 'react';
3 |
4 | const SwitchDemo: FC = () => (
5 |
6 |
10 |
15 |
20 |
26 |
31 |
37 |
43 |
50 |
51 | );
52 |
53 | export default SwitchDemo;
54 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/Text/BlockAlign.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import './Text.less';
4 |
5 | /**
6 | *
7 | */
8 | export default () => {
9 | return (
10 | <>
11 | 左边
12 | 右边
13 |
14 | 中间
15 |
16 |
19 | 中间
20 |
21 | >
22 | );
23 | };
24 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/Text/Ellipsis.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | /**
4 | *
5 | */
6 | export default () => (
7 |
16 | 位全眼等越子亲作向下入第金社准。
17 |
18 | );
19 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/Text/Input.tsx:
--------------------------------------------------------------------------------
1 | import { Input } from 'antd';
2 | import React from 'react';
3 |
4 | /**
5 | *
6 | */
7 | export default () => ;
8 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/Text/InputAligin.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default () => (
4 | <>
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | >
15 | );
16 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/Text/InputVerticalAligin.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default () => (
4 |
5 |
6 |
7 | );
8 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/Text/Label.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import './Text.less';
4 |
5 | /**
6 | *
7 | */
8 | export default () => {
9 | return (
10 | <>
11 |
12 | 右边是冒号
13 |
14 |
15 | 左边是冒号
16 |
17 | >
18 | );
19 | };
20 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/Text/MutliLine.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | /**
4 | *
5 | */
6 | export default () => (
7 |
8 | 龙东何同三族府满于矿强更红表元组。 龙东何同三族府满于矿强更红表元组。
9 | 龙东何同三族府满于矿强更红表元组。 龙东何同三族府满于矿强更红表元组。
10 |
11 | );
12 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/Text/Span.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | /**
4 | *
5 | */
6 | export default () => (
7 |
8 | 共 2 条
9 |
10 | );
11 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/Text/SpanIcon.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import { AppleOutlined } from '@ant-design/icons';
4 |
5 | /**
6 | *
7 | */
8 | export default () => (
9 |
10 |
11 | Tab 1
12 |
13 | );
14 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/Text/SpanInlineBlock.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import './Text.less';
4 | /**
5 | *
6 | */
7 | export default () => (
8 |
9 | 共 1000 条
10 |
11 | );
12 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/Text/SpanLinkRow.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | /**
4 | *
5 | */
6 | export default () => (
7 |
10 | );
11 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/Text/TagInlineBlock.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | /**
4 | *
5 | */
6 | export default () => (
7 |
21 | 蓝色
22 |
23 | );
24 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/Text/Text.less:
--------------------------------------------------------------------------------
1 | .label::after {
2 | position: relative;
3 | top: -0.5px;
4 | margin: 0 8px 0 2px;
5 | content: ':';
6 | }
7 | .l-label::before {
8 | position: relative;
9 | top: -0.5px;
10 | margin-left: 2px;
11 | content: ':';
12 | }
13 |
14 | .inline-block {
15 | display: inline-block;
16 | margin-right: 10px;
17 | font-size: 12px;
18 | font-variant: normal;
19 | vertical-align: middle;
20 | background-color: navajowhite;
21 | }
22 |
23 | .row-item {
24 | display: flex;
25 | width: 60px;
26 | height: 40px;
27 | }
28 |
29 | .row-item-reverse {
30 | display: flex;
31 | width: 60px;
32 | height: 40px;
33 | }
34 | .column-item {
35 | display: flex;
36 | flex-direction: column;
37 | width: 60px;
38 | height: 40px;
39 | }
40 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/Text/TextAlignment/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import './style.css';
4 |
5 | /**
6 | *
7 | */
8 | export default () => (
9 |
10 | 前置对象
11 |
12 |
13 |
14 | -
15 | 基本信息
16 |
17 | -
18 | 弹性网卡
19 |
20 | -
21 | 安全组
22 |
23 |
24 |
25 |
26 |
基本信息
27 |
28 | );
29 |
--------------------------------------------------------------------------------
/docs/e2e/basic/demos/Text/TextArea.tsx:
--------------------------------------------------------------------------------
1 | import { Input } from 'antd';
2 | import React from 'react';
3 |
4 | const { TextArea } = Input;
5 |
6 | /**
7 | *
8 | */
9 | export default () => {
10 | return ;
11 | };
12 |
--------------------------------------------------------------------------------
/docs/e2e/basic/image.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 图片解析
3 | ---
4 |
5 | ## 说明
6 |
7 | 测试模块解析图片类型的能力
8 |
9 | 加载方式:
10 |
11 | - 网址
12 | - Base64
13 |
14 | 图片类型
15 |
16 | - svg
17 | - png
18 |
19 | ## 内联 Png 图片
20 |
21 |
22 |
23 | ## 内联 两个 Png 图片
24 |
25 |
26 |
27 | ## 外联 png 网址
28 |
29 |
30 |
31 | ## png 网址不带协议头
32 |
33 |
34 |
35 | ## 外联 svg 网址
36 |
37 |
38 |
--------------------------------------------------------------------------------
/docs/e2e/basic/overflow.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Overflow
3 | ---
4 |
5 | ## Overflow 测试
6 |
7 | ### Switch
8 |
9 |
10 |
--------------------------------------------------------------------------------
/docs/e2e/basic/position.md:
--------------------------------------------------------------------------------
1 | ## 坐标与尺寸
2 |
3 | 使用了 负值的 margin 和 padding
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/e2e/basic/pseudo.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 伪类解析
3 | ---
4 |
5 | ## Switch 切换器
6 |
7 | Switch 的按钮用了伪类
8 |
9 |
10 |
11 | ## Checkbox
12 |
13 | checkbox 的勾勾 用了伪类同时带有 transform 测试旋转的
14 |
15 |
16 |
17 | ## 选择器
18 |
19 | select 未选择时需要处理
20 |
21 |
22 |
--------------------------------------------------------------------------------
/docs/e2e/basic/text.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 文本解析
3 | ---
4 |
5 | ## 不同 display 测试
6 |
7 | ### InlineBlock
8 |
9 |
10 |
11 | ## 解析文本对齐
12 |
13 | ### 解析 Block 文本对齐
14 |
15 |
16 |
17 | ### 解析 Flex 文本对齐
18 |
19 |
20 |
21 | ### 文本高度上垂直居中
22 |
23 | 场景特征:
24 |
25 | ```css
26 | {
27 | display: inline-block;
28 | line-height: 20px;
29 | }
30 | ```
31 |
32 | 这种场景没有文本对齐参数,
33 |
34 | 可以直接使用 range 的 bcr 作为 text 的 XY 坐标和高度值
35 |
36 |
37 |
38 | ## 解析 span + Icon
39 |
40 | 测试 span 下带文本和 icon 的解析
41 |
42 |
43 |
44 | ## 解析省略号
45 |
46 | 测试带省略号的文本
47 |
48 | ### 一行省略号
49 |
50 | 测试样式:
51 |
52 | ```css
53 | {
54 | width: 190px;
55 | overflow: hidden;
56 | white-space: nowrap;
57 | text-overflow: ellipsis;
58 | }
59 | ```
60 |
61 |
62 |
63 | ## 文本行数
64 |
65 | ### 解析一行文本
66 |
67 |
68 |
69 | ### 解析多行文本
70 |
71 |
72 |
73 | ## 解析 span strong 文本
74 |
75 | span 是 inline;
76 |
77 | strong 也是 inline, 采用加粗样式
78 |
79 |
80 |
81 | 填的坑:
82 |
83 | 1. `b` 和 `strong`标签采用了 `bolder` , css 解析出来是 700 , 700 对应的是 `Bold` ,但是苹方没有 Bold,必须人为处理成 Semibold
84 | 2. 之前(`<=0.4.1`) trim 掉了文本所有的前后空格,但是这个场景下`2`和`条`的间距是用空格来填的, 所以去掉了 trim 空格的情况
85 |
86 | ## 文本伪类
87 |
88 | ### 解析 `after` 和 `before`
89 |
90 |
91 |
92 | ### 解析 Input `placeholder` 和 `value`
93 |
94 | placeholder 和输入的值都在伪类里
95 |
96 |
97 |
98 | ### 解析 TextArea `placeholder` 和 `value`
99 |
100 | placeholder 和输入的值都在伪类里
101 |
102 |
103 |
104 | ### Input 文本居中
105 |
106 |
107 |
108 | ### Input 文本垂直居中
109 |
110 | #### Case1: line-height 超过 input 高度
111 |
112 | 目前这种垂直居中是因为 `line-height` 值超过了 input 的高度使得文本默认在垂直轴上是居中的
113 |
114 |
115 |
116 | ### 文本对齐方式
117 |
118 | 原来在网页中设置了 `text-align: right` 的会得到 Sketch Alignment 为 `SketchFormat.TextHorizontalAlignment.Right`,而这个数据传入到 sketch 中则会导致 sketch 中文本位置的解析出错
119 |
120 | [用例来源](https://github.com/ant-design/html2sketch/issues/51)
121 |
122 |
123 |
--------------------------------------------------------------------------------
/docs/e2e/components/ant-design.md:
--------------------------------------------------------------------------------
1 | # Ant Design 组件
2 |
3 | ## Checkbox
4 |
5 |
6 |
7 | ## DatePicker
8 |
9 |
10 |
11 | ## Input
12 |
13 |
14 |
15 | ## Radio 单选器
16 |
17 |
18 |
19 | ## Rate
20 |
21 |
22 |
23 | ## Skeleton
24 |
25 |
26 |
27 | ## Steps
28 |
29 |
30 |
31 | ## Tabs
32 |
33 |
34 |
35 | ## Tooltip
36 |
37 |
38 |
39 | ## Table
40 |
41 |
42 |
--------------------------------------------------------------------------------
/docs/e2e/components/antd/Checkbox.tsx:
--------------------------------------------------------------------------------
1 | import { Checkbox } from 'antd';
2 | import React from 'react';
3 |
4 | export default () => (
5 |
6 | Apple
7 | Banana
8 | Car
9 |
10 | );
11 |
--------------------------------------------------------------------------------
/docs/e2e/components/antd/DatePicker.tsx:
--------------------------------------------------------------------------------
1 | import { DatePicker } from 'antd';
2 | import React from 'react';
3 |
4 | const { _InternalPanelDoNotUseOrYouWillBeFired: PureDatePicker } = DatePicker;
5 |
6 | const Demo = () => ;
7 |
8 | export default Demo;
9 |
--------------------------------------------------------------------------------
/docs/e2e/components/antd/DefaultModal.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * hideSketchLayout: true
3 | */
4 | import { TestLayout, useElements } from '@docs-utils';
5 | import { Modal } from 'antd';
6 | import React, { FC, useEffect } from 'react';
7 | // @ts-ignore
8 | import styles from './Modal.less';
9 |
10 | /**
11 | *
12 | */
13 | const ModalPage: FC = () => {
14 | const { elements, ref, setElements } = useElements();
15 |
16 | useEffect(() => {
17 | const modal = document.getElementsByClassName('ant-modal')?.item(0);
18 | if (modal) {
19 | setElements([modal]);
20 | }
21 | }, [ref.current]);
22 | return (
23 |
24 |
25 |
33 | 这是里面的内容
34 |
35 |
36 |
37 | );
38 | };
39 |
40 | export default ModalPage;
41 |
--------------------------------------------------------------------------------
/docs/e2e/components/antd/Input.tsx:
--------------------------------------------------------------------------------
1 | import { Input } from 'antd';
2 | import React from 'react';
3 |
4 | export default () => (
5 | <>
6 |
7 |
8 |
9 |
10 | >
11 | );
12 |
--------------------------------------------------------------------------------
/docs/e2e/components/antd/Modal.less:
--------------------------------------------------------------------------------
1 | .wrapper {
2 | position: relative;
3 | z-index: 0 !important;
4 | overflow: inherit;
5 | }
6 |
--------------------------------------------------------------------------------
/docs/e2e/components/antd/Radio.tsx:
--------------------------------------------------------------------------------
1 | import { Radio } from 'antd';
2 | import React from 'react';
3 |
4 | export default () => 单选项;
5 |
--------------------------------------------------------------------------------
/docs/e2e/components/antd/Rate.tsx:
--------------------------------------------------------------------------------
1 | import { Rate } from 'antd';
2 | import React from 'react';
3 |
4 | const App: React.FC = () => ;
5 |
6 | export default App;
7 |
--------------------------------------------------------------------------------
/docs/e2e/components/antd/Skeleton.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Skeleton } from 'antd';
3 |
4 | const App: React.FC = () => ;
5 |
6 | export default App;
7 |
--------------------------------------------------------------------------------
/docs/e2e/components/antd/Steps.tsx:
--------------------------------------------------------------------------------
1 | import { Steps } from 'antd';
2 | import React from 'react';
3 |
4 | const description = 'This is a description.';
5 | export default () => (
6 |
24 | );
25 |
--------------------------------------------------------------------------------
/docs/e2e/components/antd/Tabs.tsx:
--------------------------------------------------------------------------------
1 | import { AndroidOutlined, AppleOutlined } from '@ant-design/icons';
2 | import { Tabs } from 'antd';
3 | import React from 'react';
4 |
5 | const { TabPane } = Tabs;
6 |
7 | export default () => (
8 |
9 |
12 |
13 | Tab 1
14 |
15 | }
16 | key="1"
17 | >
18 | Tab 1
19 |
20 |
23 |
24 | Tab 2
25 |
26 | }
27 | key="2"
28 | >
29 | Tab 2
30 |
31 |
32 | );
33 |
--------------------------------------------------------------------------------
/docs/e2e/components/antd/Tooltip.tsx:
--------------------------------------------------------------------------------
1 | import { Tooltip } from 'antd';
2 | import React from 'react';
3 |
4 | const { _InternalPanelDoNotUseOrYouWillBeFired: PureTooltip } = Tooltip;
5 |
6 | const Demo = () => ;
7 |
8 | export default Demo;
9 |
--------------------------------------------------------------------------------
/docs/e2e/components/modal.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Modal 浮层
3 | ---
4 |
5 | ## 解析 默认 Modal 浮层
6 |
7 | 测试浮层解析
8 |
9 | 生成的 Symbol 默认带有 resizing 的配置项
10 |
11 |
12 |
--------------------------------------------------------------------------------
/docs/e2e/components/pro-components.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Pro Components
3 | ---
4 |
5 | # Pro Components
6 |
7 | ## ProCard
8 |
9 |
10 |
11 |
12 | ## ProTable
13 |
14 |
15 |
--------------------------------------------------------------------------------
/docs/e2e/components/procomponents/ProCard.tsx:
--------------------------------------------------------------------------------
1 | import ProCard from '@ant-design/pro-card';
2 | import React from 'react';
3 |
4 | export default () => (
5 |
10 |
11 | 内容一
12 |
13 |
14 | 内容二
15 |
16 |
17 | );
18 |
--------------------------------------------------------------------------------
/docs/e2e/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 测试用例说明
3 | ---
4 |
5 | ## 测试用例说明
6 |
7 | 本组页面收集了 html2sketch 需要解析的常见用例, 用于 `html2sketch` 模块的开发测试和端到端测试
8 |
9 | ### 开发测试
10 |
11 | 便于开发时快速测试, 建议搭配 [Sketch JSON](https://github.com/arvinxx/sketch-json) 插件测试使用
12 |
13 | 演示: 
14 |
15 | ### @docs-utils
16 |
17 | 用例代码显示上并不包括 `@docs-utils` 的代码
18 |
19 | 如果需要查看 `@docs-utils` 的代码, 请到 `docs/__utils__` 文件夹 [查看](https://github.com/ant-design/html2sketch/tree/master/docs/__utils__)
20 |
--------------------------------------------------------------------------------
/docs/e2e/styles/demos/LineGradient.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | /**
4 | *
5 | */
6 | export default () => {
7 | return (
8 |
15 | );
16 | };
17 |
--------------------------------------------------------------------------------
/docs/e2e/styles/demos/Scale.less:
--------------------------------------------------------------------------------
1 | .scale {
2 | position: relative;
3 | display: block;
4 | width: 16px;
5 | height: 16px;
6 | background-color: #fff;
7 | border-color: #d9d9d9;
8 | border-style: solid;
9 | border-width: 1px;
10 | border-radius: 50%;
11 |
12 | &::after {
13 | position: absolute;
14 | display: block;
15 | width: 16px;
16 | height: 16px;
17 | left: -1px;
18 | top: -1px;
19 | background-color: red;
20 | border-top: 0;
21 | border-left: 0;
22 | border-radius: 16px;
23 | transform: scale(0.5);
24 | content: ' ';
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/docs/e2e/styles/demos/Scale.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import './Scale.less';
4 |
5 | export default () => ;
6 |
--------------------------------------------------------------------------------
/docs/e2e/styles/gradient.md:
--------------------------------------------------------------------------------
1 | ## 线性渐变
2 |
3 | 测试线性渐变的解析
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/e2e/styles/transform.md:
--------------------------------------------------------------------------------
1 | ## Transform 解析
2 |
3 | 使用了 `transform: scale(0.5)`
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/e2e/svg.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Svg 解析逻辑
3 | ---
4 |
5 | # Svg 解析逻辑
6 |
7 | SVG 的解析是 `html2sketch` 中最复杂的一个解析模块,原因有三点:
8 |
9 | 一、svg 的解析入口存在两种:
10 |
11 | 1. Svg Element;
12 |
13 | 2. 样式的 `background-image` 或 `
` 加载的 URL;
14 |
15 | 二、svg 中包含诸多元素例如 `path`、`g`、`circle`、`rect` 等等基本图形元素,也有 `use`、`def` 等特殊元素
16 |
17 | 三、svg 也支持内联样式因此样式需要重新解析,同时存在例如 `currentColor` 的特殊填充颜色,使得解析难度再次提升
18 |
19 | 上述三点原因导致解析 Svg 约等于重新解析一种 DSL 语言.
20 |
21 | 整个解析的流程如下图所示:
22 |
23 |
24 |
--------------------------------------------------------------------------------
/docs/e2e/svg/basic.md:
--------------------------------------------------------------------------------
1 | # 基础解析
2 |
3 | ## 使用 use Symbol 的 svg
4 |
5 | `