@antv/infographic 0.2.17 → 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.
Files changed (97) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/dist/infographic.min.js +99 -99
  4. package/dist/infographic.min.js.map +1 -1
  5. package/esm/constants/service.d.ts +1 -1
  6. package/esm/constants/service.js +1 -1
  7. package/esm/designs/structures/chart-line.js +5 -3
  8. package/esm/editor/interactions/dblclick-edit-text.js +3 -3
  9. package/esm/editor/managers/interaction.js +6 -4
  10. package/esm/editor/plugins/components/button.d.ts +2 -1
  11. package/esm/editor/plugins/components/button.js +4 -4
  12. package/esm/editor/plugins/components/color-picker.d.ts +1 -0
  13. package/esm/editor/plugins/components/color-picker.js +3 -3
  14. package/esm/editor/plugins/components/popover.d.ts +3 -1
  15. package/esm/editor/plugins/components/popover.js +29 -9
  16. package/esm/editor/plugins/edit-bar/edit-bar.d.ts +3 -1
  17. package/esm/editor/plugins/edit-bar/edit-bar.js +17 -7
  18. package/esm/editor/plugins/edit-bar/edit-items/align-elements.js +6 -4
  19. package/esm/editor/plugins/edit-bar/edit-items/font-align.js +8 -5
  20. package/esm/editor/plugins/edit-bar/edit-items/font-color.js +7 -4
  21. package/esm/editor/plugins/edit-bar/edit-items/font-family.js +11 -9
  22. package/esm/editor/plugins/edit-bar/edit-items/font-size.js +8 -5
  23. package/esm/editor/plugins/edit-bar/edit-items/icon-color.js +7 -4
  24. package/esm/editor/plugins/edit-bar/edit-items/types.d.ts +5 -1
  25. package/esm/editor/plugins/reset-viewbox.d.ts +4 -1
  26. package/esm/editor/plugins/reset-viewbox.js +12 -6
  27. package/esm/editor/utils/index.d.ts +1 -0
  28. package/esm/editor/utils/index.js +1 -0
  29. package/esm/editor/utils/root.d.ts +3 -0
  30. package/esm/editor/utils/root.js +18 -0
  31. package/esm/exporter/svg.js +63 -3
  32. package/esm/resource/loaders/search.js +0 -3
  33. package/esm/templates/utils.js +11 -6
  34. package/esm/utils/padding.js +1 -1
  35. package/esm/utils/style.d.ts +3 -1
  36. package/esm/utils/style.js +27 -4
  37. package/esm/version.d.ts +1 -1
  38. package/esm/version.js +1 -1
  39. package/lib/constants/service.d.ts +1 -1
  40. package/lib/constants/service.js +1 -1
  41. package/lib/designs/structures/chart-line.js +5 -3
  42. package/lib/editor/interactions/dblclick-edit-text.js +3 -3
  43. package/lib/editor/managers/interaction.js +7 -5
  44. package/lib/editor/plugins/components/button.d.ts +2 -1
  45. package/lib/editor/plugins/components/button.js +4 -4
  46. package/lib/editor/plugins/components/color-picker.d.ts +1 -0
  47. package/lib/editor/plugins/components/color-picker.js +3 -3
  48. package/lib/editor/plugins/components/popover.d.ts +3 -1
  49. package/lib/editor/plugins/components/popover.js +32 -12
  50. package/lib/editor/plugins/edit-bar/edit-bar.d.ts +3 -1
  51. package/lib/editor/plugins/edit-bar/edit-bar.js +17 -7
  52. package/lib/editor/plugins/edit-bar/edit-items/align-elements.js +6 -4
  53. package/lib/editor/plugins/edit-bar/edit-items/font-align.js +8 -5
  54. package/lib/editor/plugins/edit-bar/edit-items/font-color.js +7 -4
  55. package/lib/editor/plugins/edit-bar/edit-items/font-family.js +11 -9
  56. package/lib/editor/plugins/edit-bar/edit-items/font-size.js +8 -5
  57. package/lib/editor/plugins/edit-bar/edit-items/icon-color.js +7 -4
  58. package/lib/editor/plugins/edit-bar/edit-items/types.d.ts +5 -1
  59. package/lib/editor/plugins/reset-viewbox.d.ts +4 -1
  60. package/lib/editor/plugins/reset-viewbox.js +12 -6
  61. package/lib/editor/utils/index.d.ts +1 -0
  62. package/lib/editor/utils/index.js +1 -0
  63. package/lib/editor/utils/root.d.ts +3 -0
  64. package/lib/editor/utils/root.js +22 -0
  65. package/lib/exporter/svg.js +63 -3
  66. package/lib/resource/loaders/search.js +0 -3
  67. package/lib/templates/utils.js +11 -6
  68. package/lib/utils/padding.js +1 -1
  69. package/lib/utils/style.d.ts +3 -1
  70. package/lib/utils/style.js +27 -4
  71. package/lib/version.d.ts +1 -1
  72. package/lib/version.js +1 -1
  73. package/package.json +1 -1
  74. package/src/constants/service.ts +1 -1
  75. package/src/designs/structures/chart-line.tsx +5 -3
  76. package/src/editor/interactions/dblclick-edit-text.ts +3 -2
  77. package/src/editor/managers/interaction.ts +9 -7
  78. package/src/editor/plugins/components/button.ts +5 -2
  79. package/src/editor/plugins/components/color-picker.ts +4 -2
  80. package/src/editor/plugins/components/popover.ts +31 -12
  81. package/src/editor/plugins/edit-bar/edit-bar.ts +26 -11
  82. package/src/editor/plugins/edit-bar/edit-items/align-elements.ts +7 -2
  83. package/src/editor/plugins/edit-bar/edit-items/font-align.ts +8 -3
  84. package/src/editor/plugins/edit-bar/edit-items/font-color.ts +7 -2
  85. package/src/editor/plugins/edit-bar/edit-items/font-family.ts +11 -7
  86. package/src/editor/plugins/edit-bar/edit-items/font-size.ts +8 -3
  87. package/src/editor/plugins/edit-bar/edit-items/icon-color.ts +7 -2
  88. package/src/editor/plugins/edit-bar/edit-items/types.ts +6 -1
  89. package/src/editor/plugins/reset-viewbox.ts +17 -8
  90. package/src/editor/utils/index.ts +1 -0
  91. package/src/editor/utils/root.ts +26 -0
  92. package/src/exporter/svg.ts +80 -3
  93. package/src/resource/loaders/search.ts +0 -3
  94. package/src/templates/utils.ts +30 -6
  95. package/src/utils/padding.ts +1 -1
  96. package/src/utils/style.ts +31 -4
  97. package/src/version.ts +1 -1
@@ -1,11 +1,34 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.injectStyleOnce = injectStyleOnce;
4
- function injectStyleOnce(id, styles) {
5
- if (document.getElementById(id))
4
+ function resolveStyleRoot(target) {
5
+ if (!target)
6
+ return document;
7
+ if (target instanceof Document || target instanceof ShadowRoot)
8
+ return target;
9
+ if (!target.isConnected)
10
+ return document;
11
+ const root = target.getRootNode();
12
+ return root instanceof ShadowRoot ? root : document;
13
+ }
14
+ function hasStyle(root, id) {
15
+ if (root instanceof Document)
16
+ return Boolean(root.getElementById(id));
17
+ return Boolean(root.querySelector(`#${id}`));
18
+ }
19
+ function injectStyleOnce(id, styles, target) {
20
+ var _a;
21
+ const root = resolveStyleRoot(target);
22
+ if (hasStyle(root, id))
6
23
  return;
7
- const style = document.createElement('style');
24
+ const doc = root instanceof Document ? root : ((_a = root.ownerDocument) !== null && _a !== void 0 ? _a : document);
25
+ const style = doc.createElement('style');
8
26
  style.id = id;
9
27
  style.textContent = styles;
10
- document.head.appendChild(style);
28
+ if (root instanceof Document) {
29
+ root.head.appendChild(style);
30
+ }
31
+ else {
32
+ root.appendChild(style);
33
+ }
11
34
  }
package/lib/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "0.2.17";
1
+ export declare const VERSION = "0.2.18";
package/lib/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = void 0;
4
- exports.VERSION = '0.2.17';
4
+ exports.VERSION = '0.2.18';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antv/infographic",
3
- "version": "0.2.17",
3
+ "version": "0.2.18",
4
4
  "description": "An Infographic Generation and Rendering Framework, bring words to life!",
5
5
  "keywords": [
6
6
  "antv",
@@ -1 +1 @@
1
- export const ICON_SERVICE_URL = 'https://lab.weavefox.cn/api/v1/infographic/icon';
1
+ export const ICON_SERVICE_URL = 'https://www.weavefox.cn/api/v1/infographic/icon';
@@ -18,6 +18,9 @@ export interface ChartLineProps extends BaseStructureProps {
18
18
  valueFormatter?: (value: number, datum: ItemDatum) => string;
19
19
  }
20
20
 
21
+ const ITEM_POSITION_H = 'center' as const;
22
+ const ITEM_POSITION_V = 'normal' as const;
23
+
21
24
  export const ChartLine: ComponentType<ChartLineProps> = (props) => {
22
25
  const {
23
26
  Title,
@@ -55,8 +58,8 @@ export const ChartLine: ComponentType<ChartLineProps> = (props) => {
55
58
  indexes: [0],
56
59
  datum: items[0],
57
60
  data,
58
- positionH: 'center',
59
- positionV: 'normal',
61
+ positionH: ITEM_POSITION_H,
62
+ positionV: ITEM_POSITION_V,
60
63
  };
61
64
  const sampleBounds = getElementBounds(<Item {...itemProps} />);
62
65
  const labelWidth = sampleBounds.width;
@@ -396,7 +399,6 @@ export const ChartLine: ComponentType<ChartLineProps> = (props) => {
396
399
  </linearGradient>
397
400
  <linearGradient id={gradientAreaId} x1="0%" y1="0%" x2="100%" y2="0%">
398
401
  {areaStops}
399
- <stop offset="100%" stopColor={colorPrimary} stopOpacity="0.04" />
400
402
  </linearGradient>
401
403
  </Defs>
402
404
  <Group>{gridElements}</Group>
@@ -92,7 +92,7 @@ function editText(text: TextElement, options?: EditTextOptions) {
92
92
  const entity = getTextEntity(text);
93
93
  if (!entity) return;
94
94
 
95
- ensureEditorStyles();
95
+ ensureEditorStyles(entity);
96
96
  new InlineTextEditor(entity, options).start();
97
97
  }
98
98
 
@@ -240,7 +240,7 @@ class InlineTextEditor {
240
240
  }
241
241
  }
242
242
 
243
- function ensureEditorStyles() {
243
+ function ensureEditorStyles(target?: Node) {
244
244
  injectStyleOnce(
245
245
  EDITOR_STYLE_ID,
246
246
  `
@@ -256,5 +256,6 @@ function ensureEditorStyles() {
256
256
  background-color: #b3d4fc;
257
257
  }
258
258
  `,
259
+ target,
259
260
  );
260
261
  }
@@ -16,6 +16,7 @@ import type {
16
16
  SelectionChangePayload,
17
17
  SelectMode,
18
18
  } from '../types';
19
+ import { eventPathContains } from '../utils';
19
20
  import { Extension } from '../utils';
20
21
 
21
22
  export class InteractionManager implements IInteractionManager {
@@ -129,18 +130,19 @@ export class InteractionManager implements IInteractionManager {
129
130
 
130
131
  private handleClick = (event: MouseEvent) => {
131
132
  const doc = this.editor.getDocument();
132
- const target = event.target;
133
+ const path = typeof event.composedPath === 'function' ? event.composedPath() : [];
134
+ const insideInfographic =
135
+ eventPathContains(event, doc) ||
136
+ path.some(
137
+ (node) => node instanceof HTMLElement && isInfographicComponent(node),
138
+ );
133
139
 
134
- if (!target) {
140
+ if (!event.target) {
135
141
  this.deactivate();
136
142
  return;
137
143
  }
138
144
  // 点击画布 SVG 或者标记为组件的元素
139
- if (
140
- doc.contains(target as Node) ||
141
- isInfographicComponent(target as HTMLElement)
142
- )
143
- this.activate();
145
+ if (insideInfographic) this.activate();
144
146
  else this.deactivate();
145
147
  };
146
148
 
@@ -7,6 +7,7 @@ export interface IconButtonProps {
7
7
  icon: Icon;
8
8
  onClick?: () => void;
9
9
  activate?: boolean;
10
+ root?: Node;
10
11
  }
11
12
 
12
13
  export interface IconButtonHandle {
@@ -18,8 +19,9 @@ export const IconButton = ({
18
19
  icon,
19
20
  onClick,
20
21
  activate = false,
22
+ root,
21
23
  }: IconButtonProps): Button => {
22
- ensureIconButtonStyle();
24
+ ensureIconButtonStyle(root);
23
25
 
24
26
  const button = document.createElement('button');
25
27
  button.type = 'button';
@@ -44,7 +46,7 @@ export const IconButton = ({
44
46
  const ICON_BUTTON_CLASS = 'infographic-edit-bar-icon-btn';
45
47
  const ICON_BUTTON_STYLE_ID = 'infographic-edit-bar-icon-btn-style';
46
48
 
47
- function ensureIconButtonStyle() {
49
+ function ensureIconButtonStyle(target?: Node) {
48
50
  injectStyleOnce(
49
51
  ICON_BUTTON_STYLE_ID,
50
52
  `
@@ -73,5 +75,6 @@ function ensureIconButtonStyle() {
73
75
  background-color: #d9d9d9;
74
76
  }
75
77
  `,
78
+ target,
76
79
  );
77
80
  }
@@ -6,6 +6,7 @@ export type ColorPickerProps = {
6
6
  value?: string;
7
7
  swatches?: string[];
8
8
  onChange?: (value: string) => void;
9
+ root?: Node;
9
10
  };
10
11
 
11
12
  export type ColorPickerHandle = {
@@ -66,7 +67,7 @@ export function ColorPicker(
66
67
  throw new Error('ColorPicker can only be used in the browser.');
67
68
  }
68
69
 
69
- ensureColorPickerStyles();
70
+ ensureColorPickerStyles(props.root);
70
71
 
71
72
  const container = document.createElement('div');
72
73
  container.classList.add(COLOR_PICKER_CLASS);
@@ -279,7 +280,7 @@ function createSwitchLabel(text: string): HTMLSpanElement {
279
280
  return span;
280
281
  }
281
282
 
282
- function ensureColorPickerStyles() {
283
+ function ensureColorPickerStyles(target?: Node) {
283
284
  injectStyleOnce(
284
285
  COLOR_PICKER_STYLE_ID,
285
286
  `
@@ -393,5 +394,6 @@ function ensureColorPickerStyles() {
393
394
  color: #ffffff;
394
395
  }
395
396
  `,
397
+ target,
396
398
  );
397
399
  }
@@ -1,3 +1,4 @@
1
+ import { eventPathContains, getOverlayContainer } from '../../utils';
1
2
  import { COMPONENT_ROLE } from '../../../constants';
2
3
  import { injectStyleOnce, setElementRole } from '../../../utils';
3
4
 
@@ -7,7 +8,7 @@ export type PopoverPlacementPreference = PopoverPlacement | PopoverPlacement[];
7
8
  export interface PopoverProps {
8
9
  content: HTMLElement | string | (() => HTMLElement | string);
9
10
  target?: HTMLElement;
10
- getContainer?: HTMLElement | (() => HTMLElement);
11
+ getContainer?: OverlayRoot | (() => OverlayRoot);
11
12
  placement?: PopoverPlacementPreference;
12
13
  padding?: number | string;
13
14
  open?: boolean;
@@ -18,6 +19,8 @@ export interface PopoverProps {
18
19
  offset?: number;
19
20
  }
20
21
 
22
+ type OverlayRoot = HTMLElement | ShadowRoot;
23
+
21
24
  export interface PopoverHandle {
22
25
  setOpen: (open: boolean) => void;
23
26
  toggle: () => void;
@@ -32,8 +35,6 @@ const POPOVER_ARROW_CLASS = `${POPOVER_CLASS}__arrow`;
32
35
  const POPOVER_STYLE_ID = 'infographic-edit-popover-style';
33
36
 
34
37
  export function Popover(props: PopoverProps): HTMLDivElement & PopoverHandle {
35
- ensurePopoverStyle();
36
-
37
38
  const placement = props.placement ?? 'top';
38
39
  const closeOnOutsideClick = props.closeOnOutsideClick ?? true;
39
40
  const triggerActions = Array.isArray(props.trigger)
@@ -60,7 +61,7 @@ export function Popover(props: PopoverProps): HTMLDivElement & PopoverHandle {
60
61
  typeof props.getContainer === 'function'
61
62
  ? props.getContainer()
62
63
  : props.getContainer;
63
- return next ?? document.body;
64
+ return next ?? getOverlayContainer(trigger);
64
65
  };
65
66
 
66
67
  const content = document.createElement('div');
@@ -78,8 +79,17 @@ export function Popover(props: PopoverProps): HTMLDivElement & PopoverHandle {
78
79
  );
79
80
 
80
81
  const contentContainer = getContentContainer();
82
+ ensurePopoverStyle(contentContainer);
81
83
  const isPortal = contentContainer !== container;
82
84
 
85
+ const getPortalOffsetParent = () => {
86
+ const offsetParent = content.offsetParent as HTMLElement | null;
87
+ if (offsetParent) return offsetParent;
88
+ if (contentContainer instanceof ShadowRoot) return contentContainer.host;
89
+ if (contentContainer instanceof HTMLElement) return contentContainer;
90
+ return document.documentElement as HTMLElement;
91
+ };
92
+
83
93
  const arrow = document.createElement('div');
84
94
  arrow.classList.add(POPOVER_ARROW_CLASS);
85
95
  content.appendChild(arrow);
@@ -170,8 +180,18 @@ export function Popover(props: PopoverProps): HTMLDivElement & PopoverHandle {
170
180
  if (!isPortal) return;
171
181
 
172
182
  ({ left, top } = position);
173
- content.style.left = `${left}px`;
174
- content.style.top = `${top}px`;
183
+ const offsetParent = getPortalOffsetParent();
184
+ if (
185
+ offsetParent === document.body ||
186
+ offsetParent === document.documentElement
187
+ ) {
188
+ content.style.left = `${left}px`;
189
+ content.style.top = `${top}px`;
190
+ } else {
191
+ const parentRect = offsetParent.getBoundingClientRect();
192
+ content.style.left = `${left - parentRect.left + offsetParent.scrollLeft}px`;
193
+ content.style.top = `${top - parentRect.top + offsetParent.scrollTop}px`;
194
+ }
175
195
  content.style.right = 'auto';
176
196
  content.style.bottom = 'auto';
177
197
  content.style.transform = 'translate(0, 0)';
@@ -217,11 +237,9 @@ export function Popover(props: PopoverProps): HTMLDivElement & PopoverHandle {
217
237
  const toggle = () => setOpen(!open);
218
238
 
219
239
  const handleOutsideClick = (event: MouseEvent) => {
220
- const targetNode = event.target as Node;
221
- if (
222
- !container.contains(targetNode) &&
223
- (isPortal ? !content.contains(targetNode) : true)
224
- ) {
240
+ const insideTrigger = eventPathContains(event, container);
241
+ const insideContent = eventPathContains(event, content);
242
+ if (!insideTrigger && !insideContent) {
225
243
  setOpen(false);
226
244
  }
227
245
  };
@@ -296,7 +314,7 @@ export function Popover(props: PopoverProps): HTMLDivElement & PopoverHandle {
296
314
  return Object.assign(container, api);
297
315
  }
298
316
 
299
- function ensurePopoverStyle() {
317
+ function ensurePopoverStyle(target?: Node) {
300
318
  injectStyleOnce(
301
319
  POPOVER_STYLE_ID,
302
320
  `
@@ -442,5 +460,6 @@ function ensurePopoverStyle() {
442
460
  transform: translate(0, -50%);
443
461
  }
444
462
  `,
463
+ target,
445
464
  );
446
465
  }
@@ -10,6 +10,7 @@ import {
10
10
  isIconElement,
11
11
  setElementRole,
12
12
  } from '../../../utils';
13
+ import { getOverlayContainer } from '../../utils';
13
14
  import type {
14
15
  IPlugin,
15
16
  PluginInitOptions,
@@ -29,9 +30,11 @@ import {
29
30
  export interface EditBarOptions {
30
31
  style?: Partial<CSSStyleDeclaration>;
31
32
  className?: string;
32
- getContainer?: HTMLElement | (() => HTMLElement);
33
+ getContainer?: OverlayRoot | (() => OverlayRoot);
33
34
  }
34
35
 
36
+ type OverlayRoot = HTMLElement | ShadowRoot;
37
+
35
38
  type EditItem = HTMLElement;
36
39
 
37
40
  export class EditBar extends Plugin implements IPlugin {
@@ -169,12 +172,7 @@ export class EditBar extends Plugin implements IPlugin {
169
172
  setElementRole(container, COMPONENT_ROLE);
170
173
 
171
174
  this.container = container;
172
-
173
- const { getContainer } = this.options || {};
174
- const resolvedContainer =
175
- typeof getContainer === 'function' ? getContainer() : getContainer;
176
- const containerParent = resolvedContainer ?? document.body;
177
-
175
+ const containerParent = this.resolveOverlayRoot();
178
176
  containerParent?.appendChild(container);
179
177
 
180
178
  return container;
@@ -182,8 +180,9 @@ export class EditBar extends Plugin implements IPlugin {
182
180
 
183
181
  protected getTextEditItems(text: TextElement): EditItem[] {
184
182
  const { attributes = {} } = getTextElementProps(text);
183
+ const root = this.resolveOverlayRoot();
185
184
  return [FontColor, FontSize, FontAlign, FontFamily].map((item) =>
186
- item([text], attributes, this.commander),
185
+ item([text], attributes, this.commander, { root }),
187
186
  );
188
187
  }
189
188
 
@@ -191,8 +190,9 @@ export class EditBar extends Plugin implements IPlugin {
191
190
  const attrs = getCommonAttrs(
192
191
  selection.map((text) => getTextElementProps(text).attributes || {}),
193
192
  );
193
+ const root = this.resolveOverlayRoot();
194
194
  const items = [FontColor, FontSize, FontAlign, FontFamily].map((item) =>
195
- item(selection, attrs, this.commander),
195
+ item(selection, attrs, this.commander, { root }),
196
196
  );
197
197
  const commonItems = this.getElementCollectionEditItems(selection);
198
198
  return [...items, ...commonItems];
@@ -200,13 +200,19 @@ export class EditBar extends Plugin implements IPlugin {
200
200
 
201
201
  protected getIconEditItems(selection: Selection): EditItem[] {
202
202
  const attrs = getIconAttrs(selection[0] as IconElement);
203
- return [IconColor].map((item) => item(selection, attrs, this.commander));
203
+ const root = this.resolveOverlayRoot();
204
+ return [IconColor].map((item) =>
205
+ item(selection, attrs, this.commander, { root }),
206
+ );
204
207
  }
205
208
  protected getIconCollectionEditItems(selection: Selection): EditItem[] {
206
209
  const attrs = getCommonAttrs(
207
210
  selection.map((icon) => getIconAttrs(icon as IconElement)),
208
211
  );
209
- return [IconColor].map((item) => item(selection, attrs, this.commander));
212
+ const root = this.resolveOverlayRoot();
213
+ return [IconColor].map((item) =>
214
+ item(selection, attrs, this.commander, { root }),
215
+ );
210
216
  }
211
217
 
212
218
  protected getGeometryEditItems(_selection: Selection): EditItem[] {
@@ -220,13 +226,22 @@ export class EditBar extends Plugin implements IPlugin {
220
226
 
221
227
  protected getElementCollectionEditItems(selection: Selection): EditItem[] {
222
228
  if (selection.length <= 1) return [];
229
+ const root = this.resolveOverlayRoot();
223
230
  return [
224
231
  ElementAlign(selection, {}, this.commander, {
225
232
  enableDistribution: selection.length > 2,
233
+ root,
226
234
  }),
227
235
  ];
228
236
  }
229
237
 
238
+ private resolveOverlayRoot(): OverlayRoot {
239
+ const { getContainer } = this.options || {};
240
+ const resolvedContainer =
241
+ typeof getContainer === 'function' ? getContainer() : getContainer;
242
+ return resolvedContainer ?? getOverlayContainer(this.editor.getDocument());
243
+ }
244
+
230
245
  private placeEditBar(container: HTMLDivElement, selection: Selection) {
231
246
  if (selection.length === 0) return;
232
247
 
@@ -40,6 +40,7 @@ type AlignAction =
40
40
 
41
41
  type AlignOptions = {
42
42
  enableDistribution?: boolean;
43
+ root?: HTMLElement | ShadowRoot;
43
44
  };
44
45
 
45
46
  type TransformParts = {
@@ -79,17 +80,19 @@ export const ElementAlign: EditItem = (
79
80
  commander: ICommandManager,
80
81
  options?: AlignOptions,
81
82
  ) => {
82
- injectStyleOnce(GRID_STYLE_ID, GRID_STYLES);
83
+ injectStyleOnce(GRID_STYLE_ID, GRID_STYLES, options?.root);
83
84
  const enableDistribution = options?.enableDistribution ?? true;
84
85
 
85
86
  const content = createAlignContent(
86
87
  (action) => alignSelection(selection, action, commander),
87
88
  enableDistribution,
89
+ options?.root,
88
90
  );
89
91
 
90
92
  return Popover({
91
- target: IconButton({ icon: ELEMENT_ICONS.align }),
93
+ target: IconButton({ icon: ELEMENT_ICONS.align, root: options?.root }),
92
94
  content,
95
+ getContainer: options?.root,
93
96
  placement: 'top',
94
97
  offset: 12,
95
98
  });
@@ -98,6 +101,7 @@ export const ElementAlign: EditItem = (
98
101
  function createAlignContent(
99
102
  onSelect: (action: AlignAction) => void,
100
103
  enableDistribution: boolean,
104
+ root?: Node,
101
105
  ) {
102
106
  const content = document.createElement('div');
103
107
  content.classList.add(GRID_CLASS);
@@ -111,6 +115,7 @@ function createAlignContent(
111
115
 
112
116
  visibleOptions.forEach(({ icon, action }) => {
113
117
  const button = IconButton({
118
+ root,
114
119
  icon,
115
120
  onClick: () => onSelect(action),
116
121
  });
@@ -48,15 +48,17 @@ export const FontAlign: EditItem<TextAttributes> = (
48
48
  selection,
49
49
  attrs,
50
50
  commander,
51
+ options,
51
52
  ) => {
52
- injectStyleOnce(GRID_STYLE_ID, GRID_STYLES);
53
+ const root = options?.root;
54
+ injectStyleOnce(GRID_STYLE_ID, GRID_STYLES, root);
53
55
 
54
56
  const state: AlignState = {
55
57
  horizontal: attrs['data-horizontal-align'],
56
58
  vertical: attrs['data-vertical-align'],
57
59
  };
58
60
 
59
- const button = IconButton({ icon: TEXT_ICONS.align });
61
+ const button = IconButton({ icon: TEXT_ICONS.align, root });
60
62
 
61
63
  const content = createAlignContent(state, (align) => {
62
64
  const attributes: Partial<TextAttributes> = {};
@@ -74,11 +76,12 @@ export const FontAlign: EditItem<TextAttributes> = (
74
76
  }),
75
77
  ),
76
78
  );
77
- });
79
+ }, root);
78
80
 
79
81
  return Popover({
80
82
  target: button,
81
83
  content,
84
+ getContainer: root,
82
85
  placement: 'top',
83
86
  offset: 12,
84
87
  });
@@ -87,6 +90,7 @@ export const FontAlign: EditItem<TextAttributes> = (
87
90
  function createAlignContent(
88
91
  state: AlignState,
89
92
  onAlignChange: (align: AlignState) => void,
93
+ root?: Node,
90
94
  ) {
91
95
  const content = document.createElement('div');
92
96
  content.classList.add(GRID_CLASS);
@@ -106,6 +110,7 @@ function createAlignContent(
106
110
  ) => {
107
111
  options.forEach(({ icon, align }) => {
108
112
  const button = IconButton({
113
+ root,
109
114
  icon,
110
115
  onClick: () => {
111
116
  if (state[stateKey] === align) return;
@@ -12,8 +12,10 @@ export const FontColor: EditItem<TextAttributes> = (
12
12
  selection,
13
13
  attrs,
14
14
  commander,
15
+ options,
15
16
  ) => {
16
- ensureFontColorStyles();
17
+ const root = options?.root;
18
+ ensureFontColorStyles(root);
17
19
 
18
20
  const color = normalizeColor(attrs.fill);
19
21
  const isMixed = attrs.fill === undefined && selection.length > 1;
@@ -24,6 +26,7 @@ export const FontColor: EditItem<TextAttributes> = (
24
26
  setButtonColor(button, color ?? DEFAULT_COLOR, isMixed);
25
27
 
26
28
  const picker = ColorPicker({
29
+ root,
27
30
  value: color ?? DEFAULT_COLOR,
28
31
  onChange: (nextColor) => {
29
32
  setButtonColor(button, nextColor, false);
@@ -41,6 +44,7 @@ export const FontColor: EditItem<TextAttributes> = (
41
44
  return Popover({
42
45
  target: button,
43
46
  content: picker,
47
+ getContainer: root,
44
48
  placement: ['top', 'bottom'],
45
49
  offset: 12,
46
50
  trigger: 'hover',
@@ -65,7 +69,7 @@ function setButtonColor(
65
69
  else button.removeAttribute('data-mixed');
66
70
  }
67
71
 
68
- function ensureFontColorStyles() {
72
+ function ensureFontColorStyles(target?: Node) {
69
73
  injectStyleOnce(
70
74
  FONT_COLOR_STYLE_ID,
71
75
  `
@@ -97,5 +101,6 @@ function ensureFontColorStyles() {
97
101
  );
98
102
  }
99
103
  `,
104
+ target,
100
105
  );
101
106
  }
@@ -18,27 +18,29 @@ export const FontFamily: EditItem<TextAttributes> = (
18
18
  selection,
19
19
  attrs,
20
20
  commander,
21
+ editItemOptions,
21
22
  ) => {
22
- ensureFontFamilyListStyle();
23
+ const root = editItemOptions?.root;
24
+ ensureFontFamilyListStyle(root);
23
25
 
24
26
  const fonts = getFonts();
25
27
  const current = normalizeFontFamily(attrs['font-family']);
26
28
 
27
- const options = fonts.map((font) => ({
29
+ const fontOptions = fonts.map((font) => ({
28
30
  label: font.name || font.fontFamily,
29
31
  value: font.fontFamily,
30
32
  }));
31
33
  if (
32
- !options.some((option) => normalizeFontFamily(option.value) === current)
34
+ !fontOptions.some((option) => normalizeFontFamily(option.value) === current)
33
35
  ) {
34
- options.unshift({
36
+ fontOptions.unshift({
35
37
  label: DEFAULT_FONT_LABEL,
36
38
  value: current,
37
39
  });
38
40
  }
39
41
 
40
42
  let selected = current;
41
- const content = createFontList(options, selected, (value) => {
43
+ const content = createFontList(fontOptions, selected, (value) => {
42
44
  if (selected === value) return;
43
45
  selected = value;
44
46
  commander.executeBatch(
@@ -51,11 +53,12 @@ export const FontFamily: EditItem<TextAttributes> = (
51
53
  );
52
54
  });
53
55
 
54
- const button = IconButton({ icon: TEXT_ICONS.fontFamily });
56
+ const button = IconButton({ icon: TEXT_ICONS.fontFamily, root });
55
57
 
56
58
  const popover = Popover({
57
59
  target: button,
58
60
  content,
61
+ getContainer: root,
59
62
  placement: ['top', 'bottom'],
60
63
  offset: 12,
61
64
  trigger: 'hover',
@@ -110,7 +113,7 @@ function normalizeFontFamily(font: TextAttributes['font-family']) {
110
113
  return encodeFontFamily(String(font));
111
114
  }
112
115
 
113
- function ensureFontFamilyListStyle() {
116
+ function ensureFontFamilyListStyle(target?: Node) {
114
117
  injectStyleOnce(
115
118
  FONT_LIST_STYLE_ID,
116
119
  `
@@ -143,5 +146,6 @@ function ensureFontFamilyListStyle() {
143
146
  color: #0958d9;
144
147
  }
145
148
  `,
149
+ target,
146
150
  );
147
151
  }
@@ -30,10 +30,12 @@ export const FontSize: EditItem<TextAttributes> = (
30
30
  selection,
31
31
  attrs,
32
32
  commander,
33
+ options,
33
34
  ) => {
34
- injectStyleOnce(FONT_SIZE_STYLE_ID, FONT_SIZE_STYLES);
35
+ const root = options?.root;
36
+ injectStyleOnce(FONT_SIZE_STYLE_ID, FONT_SIZE_STYLES, root);
35
37
 
36
- const button = IconButton({ icon: TEXT_ICONS.fontSize });
38
+ const button = IconButton({ icon: TEXT_ICONS.fontSize, root });
37
39
  const currentSize = normalizeFontSize(attrs['font-size']);
38
40
  const content = createFontSizeContent(currentSize, (size) => {
39
41
  commander.executeBatch(
@@ -44,11 +46,12 @@ export const FontSize: EditItem<TextAttributes> = (
44
46
  }),
45
47
  ),
46
48
  );
47
- });
49
+ }, root);
48
50
 
49
51
  return Popover({
50
52
  target: button,
51
53
  content,
54
+ getContainer: root,
52
55
  placement: 'top',
53
56
  offset: 12,
54
57
  });
@@ -57,6 +60,7 @@ export const FontSize: EditItem<TextAttributes> = (
57
60
  function createFontSizeContent(
58
61
  defaultSize: number,
59
62
  onSizeChange: (size: number) => void,
63
+ root?: Node,
60
64
  ) {
61
65
  const content = document.createElement('div');
62
66
  content.classList.add(FONT_SIZE_CLASS);
@@ -73,6 +77,7 @@ function createFontSizeContent(
73
77
 
74
78
  FONT_SIZE_OPTIONS.forEach(({ label, value }) => {
75
79
  const button = IconButton({
80
+ root,
76
81
  icon: createLabelIcon(label),
77
82
  onClick: () => {
78
83
  if (selected === value) return;