Files
webstudio/packages/sdk-components-react/src/xml-node.tsx
T
Ivan Starkov ab2a985451 fix: Xml namespaces support (#4351)
## Description

closes #4343

## Steps for reproduction


https://p-cddc1d44-af37-4cb6-a430-d300cf6f932d-dot-sitemap.staging.webstudio.is/?pageId=FsnS9ui6btzM4W3YELE3Q&authToken=1cdc6026-dd5b-4624-b89b-9bd45e9bcc3d


<img width="423" alt="image"
src="https://github.com/user-attachments/assets/711bbda5-cf92-4421-853b-23eddcb8a8a7">


Resulting xml

https://webstudio-fixture-project-a-0su3o.wstd.work/sitemap.xml

```xml
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml"><url><loc>https://webstudio-fixture-project-a-0su3o.wstd.work/</loc><lastmod>2024-05-07</lastmod><xhtml:link rel="alternate" hreflang="en" href="https://webstudio-fixture-project-a-0su3o.wstd.work/en"></xhtml:link></url><url><loc>https://webstudio-fixture-project-a-0su3o.wstd.work/olegs-test</loc><lastmod>2024-05-07</lastmod><xhtml:link rel="alternate" hreflang="en" href="https://webstudio-fixture-project-a-0su3o.wstd.work/olegs-testen"></xhtml:link></url><url><loc>custom-hand-made-location</loc><lastmod>2020-10-10</lastmod><xhtml:link rel="alternate" hreflang="en" href="custom-en-location"></xhtml:link></url></urlset>
```

## Code Review

- [ ] hi @kof, I need you to do
  - conceptual review (architecture, feature-correctness)
  - detailed review (read every line)
  - test it on preview

## Before requesting a review

- [ ] made a self-review
- [ ] added inline comments where things may be not obvious (the "why",
not "what")

## Before merging

- [ ] tested locally and on preview environment (preview dev login:
5de6)
- [ ] updated [test
cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md)
document
- [ ] added tests
- [ ] if any new env variables are added, added them to `.env` file
2024-10-28 23:09:13 +03:00

81 lines
2.2 KiB
TypeScript

import { ReactSdkContext } 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 !== "tabIndex")
.filter(([, value]) => typeof value !== "function");
if (renderer === undefined) {
const attrProps = Object.fromEntries(attributeEntries);
return createElement(tag, attrProps, children);
}
const childrenArray = Children.toArray(children);
const isTextChild =
childrenArray.length > 0 &&
childrenArray.every((child) => typeof child === "string");
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, "");
const attributes = attributeEntries.map(
([key, value]) => `${key}=${JSON.stringify(value)}`
);
return (
<div {...props}>
<span style={{ color: "rgb(16, 23, 233)" }}>
&lt;{[elementName, ...attributes].join(" ")}&gt;
</span>
{childrenArray.length > 0 && (
<div
ref={ref}
style={{
display: isTextChild ? "inline" : "block",
marginLeft: isTextChild ? 0 : "1rem",
}}
>
{children}
</div>
)}
<span style={{ color: "rgb(16, 23, 233)" }}>
&lt;/{elementName}&gt;
</span>
</div>
);
}
);
XmlNode.displayName = "XmlNode";