|
1 | 1 | import { elementsByTag } from "@webstudio-is/html-data";
|
2 | 2 | import {
|
| 3 | + elementComponent, |
3 | 4 | parseComponentName,
|
4 | 5 | type ContentModel,
|
5 | 6 | type Instance,
|
@@ -416,6 +417,15 @@ export const richTextContentTags = new Set<undefined | string>([
|
416 | 417 | "span",
|
417 | 418 | ]);
|
418 | 419 |
|
| 420 | +export const richTextContentComponents = new Set<undefined | string>([ |
| 421 | + elementComponent, |
| 422 | + "Subscript", |
| 423 | + "Bold", |
| 424 | + "Italic", |
| 425 | + "RichTextLink", |
| 426 | + "Span", |
| 427 | +]); |
| 428 | + |
419 | 429 | /**
|
420 | 430 | * textual placeholder is used when no content specified while in builder
|
421 | 431 | * also signals to not insert components inside unless dropped explicitly
|
@@ -470,6 +480,34 @@ const findContentTags = ({
|
470 | 480 | return tags;
|
471 | 481 | };
|
472 | 482 |
|
| 483 | +const findContentComponents = ({ |
| 484 | + instances, |
| 485 | + instance, |
| 486 | + _components: components = new Set(), |
| 487 | +}: { |
| 488 | + instances: Instances; |
| 489 | + instance: Instance; |
| 490 | + _components?: Set<undefined | string>; |
| 491 | +}) => { |
| 492 | + for (const child of instance.children) { |
| 493 | + if (child.type === "id") { |
| 494 | + const childInstance = instances.get(child.value); |
| 495 | + // consider collection item as well |
| 496 | + if (childInstance === undefined) { |
| 497 | + components.add(undefined); |
| 498 | + continue; |
| 499 | + } |
| 500 | + components.add(childInstance.component); |
| 501 | + findContentComponents({ |
| 502 | + instances, |
| 503 | + instance: childInstance, |
| 504 | + _components: components, |
| 505 | + }); |
| 506 | + } |
| 507 | + } |
| 508 | + return components; |
| 509 | +}; |
| 510 | + |
473 | 511 | export const isRichTextTree = ({
|
474 | 512 | instanceId,
|
475 | 513 | instances,
|
@@ -510,10 +548,15 @@ export const isRichTextTree = ({
|
510 | 548 | metas,
|
511 | 549 | instance,
|
512 | 550 | });
|
| 551 | + const contentComponents = findContentComponents({ |
| 552 | + instances, |
| 553 | + instance, |
| 554 | + }); |
513 | 555 | return (
|
514 | 556 | isRichText &&
|
515 | 557 | // rich text must contain only supported elements in editor
|
516 | 558 | setIsSubsetOf(contentTags, richTextContentTags) &&
|
| 559 | + setIsSubsetOf(contentComponents, richTextContentComponents) && |
517 | 560 | // rich text cannot contain only span and only link
|
518 | 561 | // those links and spans are containers in such cases
|
519 | 562 | !setIsSubsetOf(contentTags, new Set(richTextPlaceholders.keys()))
|
@@ -675,7 +718,14 @@ export const findClosestNonTextualContainer = ({
|
675 | 718 | metas,
|
676 | 719 | instance,
|
677 | 720 | });
|
678 |
| - if (setIsSubsetOf(contentTags, richTextContentTags)) { |
| 721 | + const contentComponents = findContentComponents({ |
| 722 | + instances, |
| 723 | + instance, |
| 724 | + }); |
| 725 | + if ( |
| 726 | + setIsSubsetOf(contentTags, richTextContentTags) && |
| 727 | + setIsSubsetOf(contentComponents, richTextContentComponents) |
| 728 | + ) { |
679 | 729 | hasText = true;
|
680 | 730 | }
|
681 | 731 | if (!hasText) {
|
|
0 commit comments