@antv/infographic 0.2.16 → 0.2.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/infographic.min.js +121 -120
- package/dist/infographic.min.js.map +1 -1
- package/esm/constants/service.d.ts +1 -1
- package/esm/constants/service.js +1 -1
- package/esm/designs/structures/chart-line.js +7 -4
- package/esm/editor/interactions/dblclick-edit-text.js +3 -3
- package/esm/editor/managers/interaction.js +6 -4
- package/esm/editor/plugins/components/button.d.ts +2 -1
- package/esm/editor/plugins/components/button.js +4 -4
- package/esm/editor/plugins/components/color-picker.d.ts +1 -0
- package/esm/editor/plugins/components/color-picker.js +3 -3
- package/esm/editor/plugins/components/popover.d.ts +3 -1
- package/esm/editor/plugins/components/popover.js +29 -9
- package/esm/editor/plugins/edit-bar/edit-bar.d.ts +3 -1
- package/esm/editor/plugins/edit-bar/edit-bar.js +17 -7
- package/esm/editor/plugins/edit-bar/edit-items/align-elements.js +6 -4
- package/esm/editor/plugins/edit-bar/edit-items/font-align.js +8 -5
- package/esm/editor/plugins/edit-bar/edit-items/font-color.js +7 -4
- package/esm/editor/plugins/edit-bar/edit-items/font-family.js +11 -9
- package/esm/editor/plugins/edit-bar/edit-items/font-size.js +8 -5
- package/esm/editor/plugins/edit-bar/edit-items/icon-color.js +7 -4
- package/esm/editor/plugins/edit-bar/edit-items/types.d.ts +5 -1
- package/esm/editor/plugins/reset-viewbox.d.ts +4 -1
- package/esm/editor/plugins/reset-viewbox.js +12 -6
- package/esm/editor/utils/index.d.ts +1 -0
- package/esm/editor/utils/index.js +1 -0
- package/esm/editor/utils/root.d.ts +3 -0
- package/esm/editor/utils/root.js +18 -0
- package/esm/exporter/svg.js +229 -3
- package/esm/options/parser.js +8 -6
- package/esm/options/types.d.ts +3 -3
- package/esm/renderer/renderer.js +1 -1
- package/esm/resource/loaders/search.js +2 -6
- package/esm/runtime/options.js +1 -1
- package/esm/syntax/index.js +56 -10
- package/esm/syntax/mapper.js +20 -6
- package/esm/syntax/parser.js +9 -0
- package/esm/syntax/types.d.ts +1 -1
- package/esm/templates/registry.d.ts +1 -0
- package/esm/templates/registry.js +6 -0
- package/esm/templates/utils.d.ts +1 -0
- package/esm/templates/utils.js +68 -0
- package/esm/themes/built-in.js +3 -0
- package/esm/utils/padding.js +1 -1
- package/esm/utils/style.d.ts +3 -1
- package/esm/utils/style.js +27 -4
- package/esm/version.d.ts +1 -1
- package/esm/version.js +1 -1
- package/lib/constants/service.d.ts +1 -1
- package/lib/constants/service.js +1 -1
- package/lib/designs/structures/chart-line.js +7 -4
- package/lib/editor/interactions/dblclick-edit-text.js +3 -3
- package/lib/editor/managers/interaction.js +7 -5
- package/lib/editor/plugins/components/button.d.ts +2 -1
- package/lib/editor/plugins/components/button.js +4 -4
- package/lib/editor/plugins/components/color-picker.d.ts +1 -0
- package/lib/editor/plugins/components/color-picker.js +3 -3
- package/lib/editor/plugins/components/popover.d.ts +3 -1
- package/lib/editor/plugins/components/popover.js +32 -12
- package/lib/editor/plugins/edit-bar/edit-bar.d.ts +3 -1
- package/lib/editor/plugins/edit-bar/edit-bar.js +17 -7
- package/lib/editor/plugins/edit-bar/edit-items/align-elements.js +6 -4
- package/lib/editor/plugins/edit-bar/edit-items/font-align.js +8 -5
- package/lib/editor/plugins/edit-bar/edit-items/font-color.js +7 -4
- package/lib/editor/plugins/edit-bar/edit-items/font-family.js +11 -9
- package/lib/editor/plugins/edit-bar/edit-items/font-size.js +8 -5
- package/lib/editor/plugins/edit-bar/edit-items/icon-color.js +7 -4
- package/lib/editor/plugins/edit-bar/edit-items/types.d.ts +5 -1
- package/lib/editor/plugins/reset-viewbox.d.ts +4 -1
- package/lib/editor/plugins/reset-viewbox.js +12 -6
- package/lib/editor/utils/index.d.ts +1 -0
- package/lib/editor/utils/index.js +1 -0
- package/lib/editor/utils/root.d.ts +3 -0
- package/lib/editor/utils/root.js +22 -0
- package/lib/exporter/svg.js +229 -3
- package/lib/options/parser.js +7 -5
- package/lib/options/types.d.ts +3 -3
- package/lib/renderer/renderer.js +1 -1
- package/lib/resource/loaders/search.js +2 -6
- package/lib/runtime/options.js +1 -1
- package/lib/syntax/index.js +56 -10
- package/lib/syntax/mapper.js +20 -6
- package/lib/syntax/parser.js +9 -0
- package/lib/syntax/types.d.ts +1 -1
- package/lib/templates/registry.d.ts +1 -0
- package/lib/templates/registry.js +7 -0
- package/lib/templates/utils.d.ts +1 -0
- package/lib/templates/utils.js +71 -0
- package/lib/themes/built-in.js +3 -0
- package/lib/utils/padding.js +1 -1
- package/lib/utils/style.d.ts +3 -1
- package/lib/utils/style.js +27 -4
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +1 -1
- package/src/constants/service.ts +1 -1
- package/src/designs/structures/chart-line.tsx +8 -4
- package/src/editor/interactions/dblclick-edit-text.ts +3 -2
- package/src/editor/managers/interaction.ts +9 -7
- package/src/editor/plugins/components/button.ts +5 -2
- package/src/editor/plugins/components/color-picker.ts +4 -2
- package/src/editor/plugins/components/popover.ts +31 -12
- package/src/editor/plugins/edit-bar/edit-bar.ts +26 -11
- package/src/editor/plugins/edit-bar/edit-items/align-elements.ts +7 -2
- package/src/editor/plugins/edit-bar/edit-items/font-align.ts +8 -3
- package/src/editor/plugins/edit-bar/edit-items/font-color.ts +7 -2
- package/src/editor/plugins/edit-bar/edit-items/font-family.ts +11 -7
- package/src/editor/plugins/edit-bar/edit-items/font-size.ts +8 -3
- package/src/editor/plugins/edit-bar/edit-items/icon-color.ts +7 -2
- package/src/editor/plugins/edit-bar/edit-items/types.ts +6 -1
- package/src/editor/plugins/reset-viewbox.ts +17 -8
- package/src/editor/utils/index.ts +1 -0
- package/src/editor/utils/root.ts +26 -0
- package/src/exporter/svg.ts +274 -3
- package/src/options/parser.ts +7 -6
- package/src/options/types.ts +3 -3
- package/src/renderer/renderer.ts +1 -1
- package/src/resource/loaders/search.ts +2 -5
- package/src/runtime/options.ts +1 -1
- package/src/syntax/index.ts +71 -10
- package/src/syntax/mapper.ts +20 -6
- package/src/syntax/parser.ts +10 -0
- package/src/syntax/types.ts +1 -0
- package/src/templates/registry.ts +6 -0
- package/src/templates/utils.ts +111 -0
- package/src/themes/built-in.ts +4 -0
- package/src/utils/padding.ts +1 -1
- package/src/utils/style.ts +31 -4
- package/src/version.ts +1 -1
|
@@ -25,13 +25,14 @@ const GRID_STYLES = `
|
|
|
25
25
|
gap: 2px;
|
|
26
26
|
}
|
|
27
27
|
`;
|
|
28
|
-
const FontAlign = (selection, attrs, commander) => {
|
|
29
|
-
|
|
28
|
+
const FontAlign = (selection, attrs, commander, options) => {
|
|
29
|
+
const root = options === null || options === void 0 ? void 0 : options.root;
|
|
30
|
+
(0, utils_1.injectStyleOnce)(GRID_STYLE_ID, GRID_STYLES, root);
|
|
30
31
|
const state = {
|
|
31
32
|
horizontal: attrs['data-horizontal-align'],
|
|
32
33
|
vertical: attrs['data-vertical-align'],
|
|
33
34
|
};
|
|
34
|
-
const button = (0, components_1.IconButton)({ icon: components_1.TEXT_ICONS.align });
|
|
35
|
+
const button = (0, components_1.IconButton)({ icon: components_1.TEXT_ICONS.align, root });
|
|
35
36
|
const content = createAlignContent(state, (align) => {
|
|
36
37
|
const attributes = {};
|
|
37
38
|
if (align.horizontal)
|
|
@@ -43,16 +44,17 @@ const FontAlign = (selection, attrs, commander) => {
|
|
|
43
44
|
commander.executeBatch(selection.map((text) => new commands_1.UpdateElementCommand(text, {
|
|
44
45
|
attributes,
|
|
45
46
|
})));
|
|
46
|
-
});
|
|
47
|
+
}, root);
|
|
47
48
|
return (0, components_1.Popover)({
|
|
48
49
|
target: button,
|
|
49
50
|
content,
|
|
51
|
+
getContainer: root,
|
|
50
52
|
placement: 'top',
|
|
51
53
|
offset: 12,
|
|
52
54
|
});
|
|
53
55
|
};
|
|
54
56
|
exports.FontAlign = FontAlign;
|
|
55
|
-
function createAlignContent(state, onAlignChange) {
|
|
57
|
+
function createAlignContent(state, onAlignChange, root) {
|
|
56
58
|
const content = document.createElement('div');
|
|
57
59
|
content.classList.add(GRID_CLASS);
|
|
58
60
|
const buttons = {};
|
|
@@ -65,6 +67,7 @@ function createAlignContent(state, onAlignChange) {
|
|
|
65
67
|
const createButtons = (options, stateKey) => {
|
|
66
68
|
options.forEach(({ icon, align }) => {
|
|
67
69
|
const button = (0, components_1.IconButton)({
|
|
70
|
+
root,
|
|
68
71
|
icon,
|
|
69
72
|
onClick: () => {
|
|
70
73
|
if (state[stateKey] === align)
|
|
@@ -7,8 +7,9 @@ const components_1 = require("../../components");
|
|
|
7
7
|
const FONT_COLOR_BUTTON_CLASS = 'infographic-font-color-btn';
|
|
8
8
|
const FONT_COLOR_STYLE_ID = 'infographic-font-color-style';
|
|
9
9
|
const DEFAULT_COLOR = '#1f1f1f';
|
|
10
|
-
const FontColor = (selection, attrs, commander) => {
|
|
11
|
-
|
|
10
|
+
const FontColor = (selection, attrs, commander, options) => {
|
|
11
|
+
const root = options === null || options === void 0 ? void 0 : options.root;
|
|
12
|
+
ensureFontColorStyles(root);
|
|
12
13
|
const color = normalizeColor(attrs.fill);
|
|
13
14
|
const isMixed = attrs.fill === undefined && selection.length > 1;
|
|
14
15
|
const button = document.createElement('button');
|
|
@@ -16,6 +17,7 @@ const FontColor = (selection, attrs, commander) => {
|
|
|
16
17
|
button.classList.add(FONT_COLOR_BUTTON_CLASS);
|
|
17
18
|
setButtonColor(button, color !== null && color !== void 0 ? color : DEFAULT_COLOR, isMixed);
|
|
18
19
|
const picker = (0, components_1.ColorPicker)({
|
|
20
|
+
root,
|
|
19
21
|
value: color !== null && color !== void 0 ? color : DEFAULT_COLOR,
|
|
20
22
|
onChange: (nextColor) => {
|
|
21
23
|
setButtonColor(button, nextColor, false);
|
|
@@ -27,6 +29,7 @@ const FontColor = (selection, attrs, commander) => {
|
|
|
27
29
|
return (0, components_1.Popover)({
|
|
28
30
|
target: button,
|
|
29
31
|
content: picker,
|
|
32
|
+
getContainer: root,
|
|
30
33
|
placement: ['top', 'bottom'],
|
|
31
34
|
offset: 12,
|
|
32
35
|
trigger: 'hover',
|
|
@@ -48,7 +51,7 @@ function setButtonColor(button, color, mixed) {
|
|
|
48
51
|
else
|
|
49
52
|
button.removeAttribute('data-mixed');
|
|
50
53
|
}
|
|
51
|
-
function ensureFontColorStyles() {
|
|
54
|
+
function ensureFontColorStyles(target) {
|
|
52
55
|
(0, utils_1.injectStyleOnce)(FONT_COLOR_STYLE_ID, `
|
|
53
56
|
.${FONT_COLOR_BUTTON_CLASS} {
|
|
54
57
|
position: relative;
|
|
@@ -77,5 +80,5 @@ function ensureFontColorStyles() {
|
|
|
77
80
|
#f5f5f5 12px
|
|
78
81
|
);
|
|
79
82
|
}
|
|
80
|
-
|
|
83
|
+
`, target);
|
|
81
84
|
}
|
|
@@ -9,22 +9,23 @@ const FONT_LIST_CLASS = 'infographic-font-family-list';
|
|
|
9
9
|
const FONT_OPTION_CLASS = `${FONT_LIST_CLASS}__option`;
|
|
10
10
|
const FONT_LIST_STYLE_ID = 'infographic-font-family-list-style';
|
|
11
11
|
const DEFAULT_FONT_LABEL = '默认';
|
|
12
|
-
const FontFamily = (selection, attrs, commander) => {
|
|
13
|
-
|
|
12
|
+
const FontFamily = (selection, attrs, commander, editItemOptions) => {
|
|
13
|
+
const root = editItemOptions === null || editItemOptions === void 0 ? void 0 : editItemOptions.root;
|
|
14
|
+
ensureFontFamilyListStyle(root);
|
|
14
15
|
const fonts = (0, renderer_1.getFonts)();
|
|
15
16
|
const current = normalizeFontFamily(attrs['font-family']);
|
|
16
|
-
const
|
|
17
|
+
const fontOptions = fonts.map((font) => ({
|
|
17
18
|
label: font.name || font.fontFamily,
|
|
18
19
|
value: font.fontFamily,
|
|
19
20
|
}));
|
|
20
|
-
if (!
|
|
21
|
-
|
|
21
|
+
if (!fontOptions.some((option) => normalizeFontFamily(option.value) === current)) {
|
|
22
|
+
fontOptions.unshift({
|
|
22
23
|
label: DEFAULT_FONT_LABEL,
|
|
23
24
|
value: current,
|
|
24
25
|
});
|
|
25
26
|
}
|
|
26
27
|
let selected = current;
|
|
27
|
-
const content = createFontList(
|
|
28
|
+
const content = createFontList(fontOptions, selected, (value) => {
|
|
28
29
|
if (selected === value)
|
|
29
30
|
return;
|
|
30
31
|
selected = value;
|
|
@@ -32,10 +33,11 @@ const FontFamily = (selection, attrs, commander) => {
|
|
|
32
33
|
attributes: { 'font-family': (0, utils_1.decodeFontFamily)(value) },
|
|
33
34
|
})));
|
|
34
35
|
});
|
|
35
|
-
const button = (0, components_1.IconButton)({ icon: components_1.TEXT_ICONS.fontFamily });
|
|
36
|
+
const button = (0, components_1.IconButton)({ icon: components_1.TEXT_ICONS.fontFamily, root });
|
|
36
37
|
const popover = (0, components_1.Popover)({
|
|
37
38
|
target: button,
|
|
38
39
|
content,
|
|
40
|
+
getContainer: root,
|
|
39
41
|
placement: ['top', 'bottom'],
|
|
40
42
|
offset: 12,
|
|
41
43
|
trigger: 'hover',
|
|
@@ -85,7 +87,7 @@ function normalizeFontFamily(font) {
|
|
|
85
87
|
return (0, utils_1.encodeFontFamily)(font.join(', '));
|
|
86
88
|
return (0, utils_1.encodeFontFamily)(String(font));
|
|
87
89
|
}
|
|
88
|
-
function ensureFontFamilyListStyle() {
|
|
90
|
+
function ensureFontFamilyListStyle(target) {
|
|
89
91
|
(0, utils_1.injectStyleOnce)(FONT_LIST_STYLE_ID, `
|
|
90
92
|
.${FONT_LIST_CLASS} {
|
|
91
93
|
display: flex;
|
|
@@ -115,5 +117,5 @@ function ensureFontFamilyListStyle() {
|
|
|
115
117
|
background: #e6f4ff;
|
|
116
118
|
color: #0958d9;
|
|
117
119
|
}
|
|
118
|
-
|
|
120
|
+
`, target);
|
|
119
121
|
}
|
|
@@ -21,24 +21,26 @@ const FONT_SIZE_STYLES = `
|
|
|
21
21
|
gap: 2px;
|
|
22
22
|
}
|
|
23
23
|
`;
|
|
24
|
-
const FontSize = (selection, attrs, commander) => {
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
const FontSize = (selection, attrs, commander, options) => {
|
|
25
|
+
const root = options === null || options === void 0 ? void 0 : options.root;
|
|
26
|
+
(0, utils_1.injectStyleOnce)(FONT_SIZE_STYLE_ID, FONT_SIZE_STYLES, root);
|
|
27
|
+
const button = (0, components_1.IconButton)({ icon: components_1.TEXT_ICONS.fontSize, root });
|
|
27
28
|
const currentSize = normalizeFontSize(attrs['font-size']);
|
|
28
29
|
const content = createFontSizeContent(currentSize, (size) => {
|
|
29
30
|
commander.executeBatch(selection.map((text) => new commands_1.UpdateElementCommand(text, {
|
|
30
31
|
attributes: { 'font-size': size },
|
|
31
32
|
})));
|
|
32
|
-
});
|
|
33
|
+
}, root);
|
|
33
34
|
return (0, components_1.Popover)({
|
|
34
35
|
target: button,
|
|
35
36
|
content,
|
|
37
|
+
getContainer: root,
|
|
36
38
|
placement: 'top',
|
|
37
39
|
offset: 12,
|
|
38
40
|
});
|
|
39
41
|
};
|
|
40
42
|
exports.FontSize = FontSize;
|
|
41
|
-
function createFontSizeContent(defaultSize, onSizeChange) {
|
|
43
|
+
function createFontSizeContent(defaultSize, onSizeChange, root) {
|
|
42
44
|
const content = document.createElement('div');
|
|
43
45
|
content.classList.add(FONT_SIZE_CLASS);
|
|
44
46
|
let selected = defaultSize;
|
|
@@ -51,6 +53,7 @@ function createFontSizeContent(defaultSize, onSizeChange) {
|
|
|
51
53
|
};
|
|
52
54
|
FONT_SIZE_OPTIONS.forEach(({ label, value }) => {
|
|
53
55
|
const button = (0, components_1.IconButton)({
|
|
56
|
+
root,
|
|
54
57
|
icon: createLabelIcon(label),
|
|
55
58
|
onClick: () => {
|
|
56
59
|
if (selected === value)
|
|
@@ -7,8 +7,9 @@ const components_1 = require("../../components");
|
|
|
7
7
|
const ICON_COLOR_BUTTON_CLASS = 'infographic-icon-color-btn';
|
|
8
8
|
const ICON_COLOR_STYLE_ID = 'infographic-icon-color-style';
|
|
9
9
|
const DEFAULT_COLOR = '#1f1f1f';
|
|
10
|
-
const IconColor = (selection, attrs, commander) => {
|
|
11
|
-
|
|
10
|
+
const IconColor = (selection, attrs, commander, options) => {
|
|
11
|
+
const root = options === null || options === void 0 ? void 0 : options.root;
|
|
12
|
+
ensureIconColorStyles(root);
|
|
12
13
|
const color = normalizeColor(attrs.fill);
|
|
13
14
|
const isMixed = attrs.fill === undefined && selection.length > 1;
|
|
14
15
|
const button = document.createElement('button');
|
|
@@ -16,6 +17,7 @@ const IconColor = (selection, attrs, commander) => {
|
|
|
16
17
|
button.classList.add(ICON_COLOR_BUTTON_CLASS);
|
|
17
18
|
setButtonColor(button, color !== null && color !== void 0 ? color : DEFAULT_COLOR, isMixed);
|
|
18
19
|
const picker = (0, components_1.ColorPicker)({
|
|
20
|
+
root,
|
|
19
21
|
value: color !== null && color !== void 0 ? color : DEFAULT_COLOR,
|
|
20
22
|
onChange: (nextColor) => {
|
|
21
23
|
setButtonColor(button, nextColor, false);
|
|
@@ -27,6 +29,7 @@ const IconColor = (selection, attrs, commander) => {
|
|
|
27
29
|
return (0, components_1.Popover)({
|
|
28
30
|
target: button,
|
|
29
31
|
content: picker,
|
|
32
|
+
getContainer: root,
|
|
30
33
|
placement: ['top', 'bottom'],
|
|
31
34
|
offset: 12,
|
|
32
35
|
trigger: 'hover',
|
|
@@ -48,7 +51,7 @@ function setButtonColor(button, color, mixed) {
|
|
|
48
51
|
else
|
|
49
52
|
button.removeAttribute('data-mixed');
|
|
50
53
|
}
|
|
51
|
-
function ensureIconColorStyles() {
|
|
54
|
+
function ensureIconColorStyles(target) {
|
|
52
55
|
(0, utils_1.injectStyleOnce)(ICON_COLOR_STYLE_ID, `
|
|
53
56
|
.${ICON_COLOR_BUTTON_CLASS} {
|
|
54
57
|
position: relative;
|
|
@@ -77,5 +80,5 @@ function ensureIconColorStyles() {
|
|
|
77
80
|
#f5f5f5 12px
|
|
78
81
|
);
|
|
79
82
|
}
|
|
80
|
-
|
|
83
|
+
`, target);
|
|
81
84
|
}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
import type { BaseAttributes } from '../../../../types';
|
|
2
2
|
import type { ICommandManager, Selection } from '../../../types';
|
|
3
|
-
export type
|
|
3
|
+
export type EditItemOptions = {
|
|
4
|
+
root?: HTMLElement | ShadowRoot;
|
|
5
|
+
[key: string]: any;
|
|
6
|
+
};
|
|
7
|
+
export type EditItem<T extends BaseAttributes = BaseAttributes> = (selection: Selection, attrs: T, commander: ICommandManager, options?: EditItemOptions) => HTMLElement;
|
|
@@ -3,8 +3,9 @@ import { Plugin } from './base';
|
|
|
3
3
|
export interface ResetViewBoxOptions {
|
|
4
4
|
style?: Partial<CSSStyleDeclaration>;
|
|
5
5
|
className?: string;
|
|
6
|
-
getContainer?:
|
|
6
|
+
getContainer?: OverlayRoot | (() => OverlayRoot);
|
|
7
7
|
}
|
|
8
|
+
type OverlayRoot = HTMLElement | ShadowRoot;
|
|
8
9
|
export declare class ResetViewBox extends Plugin implements IPlugin {
|
|
9
10
|
private options?;
|
|
10
11
|
name: string;
|
|
@@ -29,5 +30,7 @@ export declare class ResetViewBox extends Plugin implements IPlugin {
|
|
|
29
30
|
private showButton;
|
|
30
31
|
private hideButton;
|
|
31
32
|
private removeButton;
|
|
33
|
+
private resolveOverlayRoot;
|
|
32
34
|
private ensureButtonStyle;
|
|
33
35
|
}
|
|
36
|
+
export {};
|
|
@@ -4,6 +4,7 @@ exports.ResetViewBox = void 0;
|
|
|
4
4
|
const constants_1 = require("../../constants");
|
|
5
5
|
const utils_1 = require("../../utils");
|
|
6
6
|
const commands_1 = require("../commands");
|
|
7
|
+
const utils_2 = require("../utils");
|
|
7
8
|
const base_1 = require("./base");
|
|
8
9
|
const components_1 = require("./components");
|
|
9
10
|
const icons_1 = require("./components/icons");
|
|
@@ -36,9 +37,12 @@ class ResetViewBox extends base_1.Plugin {
|
|
|
36
37
|
if (this.resetButton)
|
|
37
38
|
return this.resetButton;
|
|
38
39
|
const { style, className } = this.options || {};
|
|
40
|
+
const containerParent = this.resolveOverlayRoot();
|
|
41
|
+
this.ensureButtonStyle(containerParent);
|
|
39
42
|
const button = (0, components_1.IconButton)({
|
|
40
43
|
icon: icons_1.RESET_ICON,
|
|
41
44
|
onClick: this.resetViewBox,
|
|
45
|
+
root: containerParent,
|
|
42
46
|
});
|
|
43
47
|
button.classList.add(RESET_BUTTON_CLASS);
|
|
44
48
|
if (className) {
|
|
@@ -49,9 +53,6 @@ class ResetViewBox extends base_1.Plugin {
|
|
|
49
53
|
}
|
|
50
54
|
(0, utils_1.setElementRole)(button, constants_1.COMPONENT_ROLE);
|
|
51
55
|
this.resetButton = button;
|
|
52
|
-
const { getContainer } = this.options || {};
|
|
53
|
-
const resolvedContainer = typeof getContainer === 'function' ? getContainer() : getContainer;
|
|
54
|
-
const containerParent = resolvedContainer !== null && resolvedContainer !== void 0 ? resolvedContainer : document.body;
|
|
55
56
|
containerParent === null || containerParent === void 0 ? void 0 : containerParent.appendChild(button);
|
|
56
57
|
return button;
|
|
57
58
|
};
|
|
@@ -142,7 +143,7 @@ class ResetViewBox extends base_1.Plugin {
|
|
|
142
143
|
init(options) {
|
|
143
144
|
super.init(options);
|
|
144
145
|
// Initialize originViewBox
|
|
145
|
-
this.ensureButtonStyle();
|
|
146
|
+
this.ensureButtonStyle(this.resolveOverlayRoot());
|
|
146
147
|
this.updateOriginViewBox();
|
|
147
148
|
this.unregisterSync = this.editor.registerSync('viewBox', this.handleViewBoxChange);
|
|
148
149
|
window.addEventListener('resize', this.handleResize);
|
|
@@ -164,7 +165,12 @@ class ResetViewBox extends base_1.Plugin {
|
|
|
164
165
|
const { padding } = this.state.getOptions();
|
|
165
166
|
this.originViewBox = (0, utils_1.getBoundViewBox)(svg, (0, utils_1.parsePadding)(padding));
|
|
166
167
|
}
|
|
167
|
-
|
|
168
|
+
resolveOverlayRoot() {
|
|
169
|
+
const { getContainer } = this.options || {};
|
|
170
|
+
const resolvedContainer = typeof getContainer === 'function' ? getContainer() : getContainer;
|
|
171
|
+
return resolvedContainer !== null && resolvedContainer !== void 0 ? resolvedContainer : (0, utils_2.getOverlayContainer)(this.editor.getDocument());
|
|
172
|
+
}
|
|
173
|
+
ensureButtonStyle(target) {
|
|
168
174
|
(0, utils_1.injectStyleOnce)(RESET_BUTTON_STYLE_ID, `
|
|
169
175
|
button.${RESET_BUTTON_CLASS} {
|
|
170
176
|
visibility: hidden;
|
|
@@ -182,7 +188,7 @@ class ResetViewBox extends base_1.Plugin {
|
|
|
182
188
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
183
189
|
cursor: pointer;
|
|
184
190
|
}
|
|
185
|
-
|
|
191
|
+
`, target);
|
|
186
192
|
}
|
|
187
193
|
}
|
|
188
194
|
exports.ResetViewBox = ResetViewBox;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getOverlayContainer = getOverlayContainer;
|
|
4
|
+
exports.eventPathContains = eventPathContains;
|
|
5
|
+
function getConnectedRoot(node) {
|
|
6
|
+
if (!(node === null || node === void 0 ? void 0 : node.isConnected))
|
|
7
|
+
return document;
|
|
8
|
+
const root = node.getRootNode();
|
|
9
|
+
return root instanceof ShadowRoot ? root : document;
|
|
10
|
+
}
|
|
11
|
+
function getOverlayContainer(node) {
|
|
12
|
+
const root = getConnectedRoot(node);
|
|
13
|
+
return root instanceof ShadowRoot ? root : document.body;
|
|
14
|
+
}
|
|
15
|
+
function eventPathContains(event, node) {
|
|
16
|
+
const path = typeof event.composedPath === 'function' ? event.composedPath() : [];
|
|
17
|
+
if (path.length > 0) {
|
|
18
|
+
return path.some((current) => current === node || (current instanceof Node && node.contains(current)));
|
|
19
|
+
}
|
|
20
|
+
const target = event.target;
|
|
21
|
+
return target instanceof Node && (target === node || node.contains(target));
|
|
22
|
+
}
|
package/lib/exporter/svg.js
CHANGED
|
@@ -13,6 +13,7 @@ exports.exportToSVGString = exportToSVGString;
|
|
|
13
13
|
exports.exportToSVG = exportToSVG;
|
|
14
14
|
const utils_1 = require("../utils");
|
|
15
15
|
const font_1 = require("./font");
|
|
16
|
+
const VIEWBOX_CHANGE_TOLERANCE = 0.5;
|
|
16
17
|
function exportToSVGString(svg_1) {
|
|
17
18
|
return __awaiter(this, arguments, void 0, function* (svg, options = {}) {
|
|
18
19
|
const node = yield exportToSVG(svg, options);
|
|
@@ -20,11 +21,179 @@ function exportToSVGString(svg_1) {
|
|
|
20
21
|
return 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(str);
|
|
21
22
|
});
|
|
22
23
|
}
|
|
24
|
+
function getExportViewBox(svg) {
|
|
25
|
+
if (svg.hasAttribute('viewBox'))
|
|
26
|
+
return (0, utils_1.getViewBox)(svg);
|
|
27
|
+
const width = parseAbsoluteLength(svg.getAttribute('width'));
|
|
28
|
+
const height = parseAbsoluteLength(svg.getAttribute('height'));
|
|
29
|
+
if (!Number.isNaN(width) &&
|
|
30
|
+
width > 0 &&
|
|
31
|
+
!Number.isNaN(height) &&
|
|
32
|
+
height > 0) {
|
|
33
|
+
return { x: 0, y: 0, width, height };
|
|
34
|
+
}
|
|
35
|
+
const rect = svg.getBoundingClientRect();
|
|
36
|
+
if (rect.width > 0 && rect.height > 0) {
|
|
37
|
+
return { x: 0, y: 0, width: rect.width, height: rect.height };
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
function parseAbsoluteLength(value) {
|
|
42
|
+
if (!value)
|
|
43
|
+
return Number.NaN;
|
|
44
|
+
const trimmed = value.trim();
|
|
45
|
+
if (!trimmed)
|
|
46
|
+
return Number.NaN;
|
|
47
|
+
if (!/^[-+]?(?:\d+\.?\d*|\.\d+)(?:px)?$/.test(trimmed))
|
|
48
|
+
return Number.NaN;
|
|
49
|
+
return Number.parseFloat(trimmed);
|
|
50
|
+
}
|
|
51
|
+
function measureSpanContentHeight(span) {
|
|
52
|
+
const prevHeight = span.style.height;
|
|
53
|
+
const prevOverflow = span.style.overflow;
|
|
54
|
+
try {
|
|
55
|
+
span.style.height = 'max-content';
|
|
56
|
+
span.style.overflow = 'hidden';
|
|
57
|
+
void span.offsetHeight; // force reflow
|
|
58
|
+
return span.scrollHeight;
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
span.style.height = prevHeight;
|
|
62
|
+
span.style.overflow = prevOverflow;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function measureSpanContentWidth(span) {
|
|
66
|
+
const prevWidth = span.style.width;
|
|
67
|
+
const prevOverflow = span.style.overflow;
|
|
68
|
+
try {
|
|
69
|
+
span.style.width = 'max-content';
|
|
70
|
+
span.style.overflow = 'hidden';
|
|
71
|
+
void span.offsetWidth; // force reflow
|
|
72
|
+
return span.scrollWidth;
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
span.style.width = prevWidth;
|
|
76
|
+
span.style.overflow = prevOverflow;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Returns [left, top, right, bottom] in SVG coordinates for a foreignObject,
|
|
80
|
+
// accounting for flex alignment: bottom/center-aligned content can overflow,
|
|
81
|
+
// and horizontally aligned content can overflow as well.
|
|
82
|
+
function getFOContentBoundsInSVG(fo, content, toSVGCoord) {
|
|
83
|
+
const foRect = fo.getBoundingClientRect();
|
|
84
|
+
const foTopLeft = toSVGCoord(foRect.left, foRect.top);
|
|
85
|
+
const foBottomRight = toSVGCoord(foRect.right, foRect.bottom);
|
|
86
|
+
const foLeftSVG = foTopLeft.x;
|
|
87
|
+
const foTopSVG = foTopLeft.y;
|
|
88
|
+
const foRightSVG = foBottomRight.x;
|
|
89
|
+
const foBottomSVG = foBottomRight.y;
|
|
90
|
+
const foWidthSVG = foRightSVG - foLeftSVG;
|
|
91
|
+
const foHeightSVG = foBottomSVG - foTopSVG;
|
|
92
|
+
const svgUnitsPerClientPxY = foRect.height > 0 ? foHeightSVG / foRect.height : 1;
|
|
93
|
+
const svgUnitsPerClientPxX = foRect.width > 0 ? foWidthSVG / foRect.width : 1;
|
|
94
|
+
// Measure actual content dimensions
|
|
95
|
+
const realScrollHeight = measureSpanContentHeight(content);
|
|
96
|
+
const contentHeightSVG = realScrollHeight > 0
|
|
97
|
+
? realScrollHeight * svgUnitsPerClientPxY
|
|
98
|
+
: foHeightSVG;
|
|
99
|
+
const realScrollWidth = measureSpanContentWidth(content);
|
|
100
|
+
const contentWidthSVG = realScrollWidth > 0 ? realScrollWidth * svgUnitsPerClientPxX : foWidthSVG;
|
|
101
|
+
const computedStyle = window.getComputedStyle(content);
|
|
102
|
+
const alignItems = computedStyle.alignItems;
|
|
103
|
+
const justifyContent = computedStyle.justifyContent;
|
|
104
|
+
// Calculate vertical bounds
|
|
105
|
+
let top, bottom;
|
|
106
|
+
if (alignItems === 'flex-end' || alignItems === 'end') {
|
|
107
|
+
top = foBottomSVG - contentHeightSVG;
|
|
108
|
+
bottom = foBottomSVG;
|
|
109
|
+
}
|
|
110
|
+
else if (alignItems === 'center') {
|
|
111
|
+
const overflowY = contentHeightSVG - foHeightSVG;
|
|
112
|
+
top = foTopSVG - overflowY / 2;
|
|
113
|
+
bottom = foBottomSVG + overflowY / 2;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
top = foTopSVG;
|
|
117
|
+
bottom = foTopSVG + contentHeightSVG;
|
|
118
|
+
}
|
|
119
|
+
// Calculate horizontal bounds
|
|
120
|
+
let left, right;
|
|
121
|
+
if (justifyContent === 'flex-end' ||
|
|
122
|
+
justifyContent === 'end' ||
|
|
123
|
+
justifyContent === 'right') {
|
|
124
|
+
left = foRightSVG - contentWidthSVG;
|
|
125
|
+
right = foRightSVG;
|
|
126
|
+
}
|
|
127
|
+
else if (justifyContent === 'center') {
|
|
128
|
+
const overflowX = contentWidthSVG - foWidthSVG;
|
|
129
|
+
left = foLeftSVG - overflowX / 2;
|
|
130
|
+
right = foRightSVG + overflowX / 2;
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
left = foLeftSVG;
|
|
134
|
+
right = foLeftSVG + contentWidthSVG;
|
|
135
|
+
}
|
|
136
|
+
return [left, top, right, bottom];
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Computes a viewBox that fully covers all foreignObject text content,
|
|
140
|
+
* accounting for overflow caused by flex alignment (bottom/center align
|
|
141
|
+
* can push content outside the foreignObject bounds).
|
|
142
|
+
*/
|
|
143
|
+
function computeFullViewBox(svg) {
|
|
144
|
+
const viewBox = getExportViewBox(svg);
|
|
145
|
+
if (!viewBox)
|
|
146
|
+
return null;
|
|
147
|
+
if (typeof svg.getScreenCTM !== 'function')
|
|
148
|
+
return null;
|
|
149
|
+
const screenCTM = svg.getScreenCTM();
|
|
150
|
+
if (!screenCTM)
|
|
151
|
+
return null;
|
|
152
|
+
const inverseCTM = screenCTM.inverse();
|
|
153
|
+
const toSVGCoord = (clientX, clientY) => {
|
|
154
|
+
const pt = svg.createSVGPoint();
|
|
155
|
+
pt.x = clientX;
|
|
156
|
+
pt.y = clientY;
|
|
157
|
+
return pt.matrixTransform(inverseCTM);
|
|
158
|
+
};
|
|
159
|
+
let minX = viewBox.x;
|
|
160
|
+
let minY = viewBox.y;
|
|
161
|
+
let maxX = viewBox.x + viewBox.width;
|
|
162
|
+
let maxY = viewBox.y + viewBox.height;
|
|
163
|
+
svg
|
|
164
|
+
.querySelectorAll('foreignObject')
|
|
165
|
+
.forEach((fo) => {
|
|
166
|
+
const content = fo.firstElementChild;
|
|
167
|
+
if (!content)
|
|
168
|
+
return;
|
|
169
|
+
const [left, top, right, bottom] = getFOContentBoundsInSVG(fo, content, toSVGCoord);
|
|
170
|
+
minX = Math.min(minX, left);
|
|
171
|
+
minY = Math.min(minY, top);
|
|
172
|
+
maxX = Math.max(maxX, right);
|
|
173
|
+
maxY = Math.max(maxY, bottom);
|
|
174
|
+
});
|
|
175
|
+
const newX = minX;
|
|
176
|
+
const newY = minY;
|
|
177
|
+
const newWidth = maxX - newX;
|
|
178
|
+
const newHeight = maxY - newY;
|
|
179
|
+
if (newWidth <= viewBox.width + VIEWBOX_CHANGE_TOLERANCE &&
|
|
180
|
+
newHeight <= viewBox.height + VIEWBOX_CHANGE_TOLERANCE &&
|
|
181
|
+
newX >= viewBox.x - VIEWBOX_CHANGE_TOLERANCE &&
|
|
182
|
+
newY >= viewBox.y - VIEWBOX_CHANGE_TOLERANCE)
|
|
183
|
+
return null;
|
|
184
|
+
return `${newX} ${newY} ${newWidth} ${newHeight}`;
|
|
185
|
+
}
|
|
23
186
|
function exportToSVG(svg_1) {
|
|
24
187
|
return __awaiter(this, arguments, void 0, function* (svg, options = {}) {
|
|
25
188
|
const { removeBackground = false, embedResources = true, removeIds = false, } = options;
|
|
26
189
|
const clonedSVG = svg.cloneNode(true);
|
|
27
|
-
|
|
190
|
+
if (typeof document !== 'undefined') {
|
|
191
|
+
const fullViewBox = computeFullViewBox(svg);
|
|
192
|
+
if (fullViewBox) {
|
|
193
|
+
clonedSVG.setAttribute('viewBox', fullViewBox);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
const { width, height } = (0, utils_1.getViewBox)(clonedSVG);
|
|
28
197
|
(0, utils_1.setAttributes)(clonedSVG, { width, height });
|
|
29
198
|
if (removeIds) {
|
|
30
199
|
inlineUseElements(clonedSVG);
|
|
@@ -52,8 +221,9 @@ function embedIcons(svg) {
|
|
|
52
221
|
const existsSymbol = svg.querySelector(href);
|
|
53
222
|
if (!existsSymbol) {
|
|
54
223
|
const symbolElement = document.querySelector(href);
|
|
55
|
-
if (symbolElement)
|
|
224
|
+
if (symbolElement) {
|
|
56
225
|
defs.appendChild(symbolElement.cloneNode(true));
|
|
226
|
+
}
|
|
57
227
|
}
|
|
58
228
|
});
|
|
59
229
|
});
|
|
@@ -261,6 +431,8 @@ function collectDefElements(svg, ids) {
|
|
|
261
431
|
};
|
|
262
432
|
while (queue.length) {
|
|
263
433
|
const id = queue.shift();
|
|
434
|
+
if (!id)
|
|
435
|
+
continue;
|
|
264
436
|
if (visited.has(id))
|
|
265
437
|
continue;
|
|
266
438
|
visited.add(id);
|
|
@@ -275,11 +447,65 @@ function collectDefElements(svg, ids) {
|
|
|
275
447
|
}
|
|
276
448
|
return collected;
|
|
277
449
|
}
|
|
450
|
+
// Fallback implementation based on the CSS.escape algorithm
|
|
451
|
+
function cssEscape(value) {
|
|
452
|
+
const string = String(value);
|
|
453
|
+
const length = string.length;
|
|
454
|
+
let result = '';
|
|
455
|
+
if (length === 0) {
|
|
456
|
+
return '';
|
|
457
|
+
}
|
|
458
|
+
for (let i = 0; i < length; i++) {
|
|
459
|
+
const codeUnit = string.charCodeAt(i);
|
|
460
|
+
// Null character
|
|
461
|
+
if (codeUnit === 0x0000) {
|
|
462
|
+
result += '\uFFFD';
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
// Control characters or DEL
|
|
466
|
+
if ((codeUnit >= 0x0001 && codeUnit <= 0x001f) || codeUnit === 0x007f) {
|
|
467
|
+
result += '\\' + codeUnit.toString(16) + ' ';
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
// Escape if first character is a digit
|
|
471
|
+
if (i === 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) {
|
|
472
|
+
result += '\\' + codeUnit.toString(16) + ' ';
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
// Escape if second character is a digit and first is a hyphen
|
|
476
|
+
if (i === 1 &&
|
|
477
|
+
codeUnit >= 0x0030 &&
|
|
478
|
+
codeUnit <= 0x0039 &&
|
|
479
|
+
string.charCodeAt(0) === 0x002d) {
|
|
480
|
+
result += '\\' + codeUnit.toString(16) + ' ';
|
|
481
|
+
continue;
|
|
482
|
+
}
|
|
483
|
+
// If the character is the first and is a hyphen followed by end of string, escape it
|
|
484
|
+
if (i === 0 && length === 1 && codeUnit === 0x002d) {
|
|
485
|
+
result += '\\' + string.charAt(i);
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
// Characters that are safe to use unescaped
|
|
489
|
+
if (codeUnit >= 0x0080 ||
|
|
490
|
+
(codeUnit >= 0x0030 && codeUnit <= 0x0039) || // 0-9
|
|
491
|
+
(codeUnit >= 0x0041 && codeUnit <= 0x005a) || // A-Z
|
|
492
|
+
(codeUnit >= 0x0061 && codeUnit <= 0x007a) || // a-z
|
|
493
|
+
codeUnit === 0x002d || // -
|
|
494
|
+
codeUnit === 0x005f // _
|
|
495
|
+
) {
|
|
496
|
+
result += string.charAt(i);
|
|
497
|
+
continue;
|
|
498
|
+
}
|
|
499
|
+
// All other characters
|
|
500
|
+
result += '\\' + string.charAt(i);
|
|
501
|
+
}
|
|
502
|
+
return result;
|
|
503
|
+
}
|
|
278
504
|
function escapeCssId(id) {
|
|
279
505
|
if (globalThis.CSS && typeof globalThis.CSS.escape === 'function') {
|
|
280
506
|
return globalThis.CSS.escape(id);
|
|
281
507
|
}
|
|
282
|
-
return id
|
|
508
|
+
return cssEscape(id);
|
|
283
509
|
}
|
|
284
510
|
function removeDefs(svg) {
|
|
285
511
|
const defsList = Array.from(svg.querySelectorAll('defs'));
|
package/lib/options/parser.js
CHANGED
|
@@ -16,15 +16,17 @@ exports.parseData = parseData;
|
|
|
16
16
|
const lodash_es_1 = require("lodash-es");
|
|
17
17
|
const designs_1 = require("../designs");
|
|
18
18
|
const renderer_1 = require("../renderer");
|
|
19
|
+
const registry_1 = require("../templates/registry");
|
|
19
20
|
const themes_1 = require("../themes");
|
|
20
21
|
const utils_1 = require("../utils");
|
|
21
22
|
function parseOptions(options) {
|
|
22
23
|
const { container = '#container', padding = 0, template, design, theme, themeConfig, data } = options, restOptions = __rest(options, ["container", "padding", "template", "design", "theme", "themeConfig", "data"]);
|
|
24
|
+
const resolvedTemplate = template ? (0, registry_1.resolveTemplateKey)(template) : undefined;
|
|
23
25
|
const parsedContainer = typeof container === 'string'
|
|
24
26
|
? document.querySelector(container) || document.createElement('div')
|
|
25
27
|
: container;
|
|
26
|
-
const templateOptions =
|
|
27
|
-
? (0,
|
|
28
|
+
const templateOptions = resolvedTemplate
|
|
29
|
+
? (0, registry_1.getTemplate)(resolvedTemplate)
|
|
28
30
|
: undefined;
|
|
29
31
|
const mergedThemeConfig = (0, lodash_es_1.merge)({}, templateOptions === null || templateOptions === void 0 ? void 0 : templateOptions.themeConfig, themeConfig);
|
|
30
32
|
const resolvedThemeConfig = theme || themeConfig || (templateOptions === null || templateOptions === void 0 ? void 0 : templateOptions.themeConfig)
|
|
@@ -39,11 +41,11 @@ function parseOptions(options) {
|
|
|
39
41
|
Object.assign(parsed, restTemplateOptions);
|
|
40
42
|
}
|
|
41
43
|
Object.assign(parsed, restOptions);
|
|
42
|
-
const parsedData = parseData(data,
|
|
44
|
+
const parsedData = parseData(data, resolvedTemplate);
|
|
43
45
|
if (parsedData)
|
|
44
46
|
parsed.data = parsedData;
|
|
45
|
-
if (
|
|
46
|
-
parsed.template =
|
|
47
|
+
if (resolvedTemplate)
|
|
48
|
+
parsed.template = resolvedTemplate;
|
|
47
49
|
if ((templateOptions === null || templateOptions === void 0 ? void 0 : templateOptions.design) || design) {
|
|
48
50
|
const designOptions = Object.assign(Object.assign({}, (resolvedThemeConfig
|
|
49
51
|
? Object.assign(Object.assign({}, options), { themeConfig: resolvedThemeConfig }) : options)), { data: parsedData || data });
|