mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-11-09 05:26:24 +09:00
Fixes https://discord.com/channels/955905230107738152/1398319996832059574/1398319996832059574 Here explicitly specified black color for text in xml and head slot. This prevents white color on root to override text.
105 lines
2.9 KiB
TypeScript
105 lines
2.9 KiB
TypeScript
import {
|
|
ReactSdkContext,
|
|
xmlNodeTagSuffix,
|
|
} from "@webstudio-is/react-sdk/runtime";
|
|
import {
|
|
Children,
|
|
createElement,
|
|
forwardRef,
|
|
useContext,
|
|
type ElementRef,
|
|
type ReactNode,
|
|
} from "react";
|
|
|
|
export const defaultTag = "div";
|
|
|
|
// We don't want to enable all tags because Box is usually a container and we have specific components for many tags.
|
|
type Props = {
|
|
tag: string;
|
|
xmlns?: string;
|
|
children?: ReactNode;
|
|
rel?: string;
|
|
hreflang?: string;
|
|
href?: string;
|
|
"xmlns:xhtml"?: string;
|
|
};
|
|
|
|
export const XmlNode = forwardRef<ElementRef<"div">, Props>(
|
|
({ tag = "", children, ...props }, ref) => {
|
|
const { renderer } = useContext(ReactSdkContext);
|
|
|
|
const attributeEntries = Object.entries(props)
|
|
.filter(
|
|
([key]) =>
|
|
key.startsWith("data-") === false && key.startsWith("aria-") === false
|
|
)
|
|
.filter(([key]) => key.toLowerCase() !== "tabindex")
|
|
.filter(([, value]) => typeof value !== "function");
|
|
|
|
const elementName = tag
|
|
// Must start from letter or underscore
|
|
.replace(/^[^\p{L}_]+/u, "")
|
|
// Clear all non letter, number, underscore, dot, and dash
|
|
.replaceAll(/[^\p{L}\p{N}\-._:]+/gu, "")
|
|
.trim();
|
|
|
|
if (renderer === undefined) {
|
|
const attrProps = Object.fromEntries(attributeEntries);
|
|
return createElement(
|
|
`${elementName}${xmlNodeTagSuffix}`,
|
|
attrProps,
|
|
children
|
|
);
|
|
}
|
|
|
|
const childrenArray = Children.toArray(children);
|
|
const isTextChild =
|
|
childrenArray.length > 0 &&
|
|
childrenArray.every((child) => typeof child === "string");
|
|
|
|
const renderAttributes = (attrs: [string, string][]) => {
|
|
return attrs.map(([name, value], index) => {
|
|
return (
|
|
<span key={index}>
|
|
{" "}
|
|
<span style={{ color: "#FF0000" }}>{name}</span>
|
|
<span style={{ color: "#000000" }}>=</span>
|
|
<span style={{ color: "#0000FF" }}>"{value}"</span>
|
|
</span>
|
|
);
|
|
});
|
|
};
|
|
|
|
return (
|
|
<div {...props} style={{ backgroundColor: "rgba(255,255,255,1)" }}>
|
|
<span>
|
|
<span style={{ color: "#800000" }}><{elementName}</span>
|
|
{attributeEntries.length > 0 && renderAttributes(attributeEntries)}
|
|
{childrenArray.length === 0 ? (
|
|
<span style={{ color: "#800000" }}>/></span>
|
|
) : (
|
|
<span style={{ color: "#800000" }}>></span>
|
|
)}
|
|
</span>
|
|
{childrenArray.length > 0 && (
|
|
<>
|
|
<div
|
|
ref={ref}
|
|
style={{
|
|
display: isTextChild ? "inline" : "block",
|
|
marginLeft: isTextChild ? 0 : "1rem",
|
|
color: "#000000",
|
|
}}
|
|
>
|
|
{children}
|
|
</div>
|
|
<span style={{ color: "#800000" }}></{elementName}></span>
|
|
</>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
);
|
|
|
|
XmlNode.displayName = "XmlNode";
|