diff --git a/plugins/remark-smartypants.js b/plugins/remark-smartypants.js
index 7dd1b0c4a..4694ff674 100644
--- a/plugins/remark-smartypants.js
+++ b/plugins/remark-smartypants.js
@@ -1,3 +1,8 @@
+/*!
+ * Based on 'silvenon/remark-smartypants'
+ * https://github.com/silvenon/remark-smartypants/pull/80
+ */
+
const visit = require('unist-util-visit');
const retext = require('retext');
const smartypants = require('retext-smartypants');
@@ -9,12 +14,48 @@ function check(parent) {
}
module.exports = function (options) {
- const processor = retext().use(smartypants, options);
+ const processor = retext().use(smartypants, {
+ ...options,
+ // Do not replace ellipses, dashes, backticks because they change string
+ // length, and we couldn't guarantee right splice of text in second visit of
+ // tree
+ ellipses: false,
+ dashes: false,
+ backticks: false,
+ });
+
+ const processor2 = retext().use(smartypants, {
+ ...options,
+ // Do not replace quotes because they are already replaced in the first
+ // processor
+ quotes: false,
+ });
function transformer(tree) {
- visit(tree, 'text', (node, index, parent) => {
- if (check(parent)) node.value = String(processor.processSync(node.value));
+ let allText = '';
+ let startIndex = 0;
+ const textOrInlineCodeNodes = [];
+
+ visit(tree, ['text', 'inlineCode'], (node, _, parent) => {
+ if (check(parent)) {
+ if (node.type === 'text') allText += node.value;
+ // for the case when inlineCode contains just one part of quote: `foo'bar`
+ else allText += 'A'.repeat(node.value.length);
+ textOrInlineCodeNodes.push(node);
+ }
});
+
+ // Concat all text into one string, to properly replace quotes around non-"text" nodes
+ allText = String(processor.processSync(allText));
+
+ for (const node of textOrInlineCodeNodes) {
+ const endIndex = startIndex + node.value.length;
+ if (node.type === 'text') {
+ const processedText = allText.slice(startIndex, endIndex);
+ node.value = String(processor2.processSync(processedText));
+ }
+ startIndex = endIndex;
+ }
}
return transformer;
diff --git a/src/components/Layout/HomeContent.js b/src/components/Layout/HomeContent.js
index 93f2c0a4e..711e70a32 100644
--- a/src/components/Layout/HomeContent.js
+++ b/src/components/Layout/HomeContent.js
@@ -1507,7 +1507,7 @@ function ConferenceLayout({conf, children}) {
navigate(e.target.value);
});
}}
- className="appearance-none pe-8 bg-transparent text-primary-dark text-2xl font-bold mb-0.5"
+ className="appearance-none pe-8 ps-2 bg-transparent text-primary-dark text-2xl font-bold mb-0.5"
style={{
backgroundSize: '4px 4px, 4px 4px',
backgroundRepeat: 'no-repeat',
@@ -1516,8 +1516,16 @@ function ConferenceLayout({conf, children}) {
backgroundImage:
'linear-gradient(45deg,transparent 50%,currentColor 50%),linear-gradient(135deg,currentColor 50%,transparent 50%)',
}}>
-
-
+
+
diff --git a/src/components/MDX/Sandpack/Preview.tsx b/src/components/MDX/Sandpack/Preview.tsx
index 059645550..9669e5f4f 100644
--- a/src/components/MDX/Sandpack/Preview.tsx
+++ b/src/components/MDX/Sandpack/Preview.tsx
@@ -54,7 +54,7 @@ export function Preview({
// When throwing a new Error in Sandpack - we want to disable the dev error dialog
// to show the Error Boundary fallback
- if (rawError && rawError.message.includes(`throw Error('Example error')`)) {
+ if (rawError && rawError.message.includes('Example Error:')) {
rawError = null;
}
diff --git a/src/components/Seo.tsx b/src/components/Seo.tsx
index 5af169e13..dfc4f6104 100644
--- a/src/components/Seo.tsx
+++ b/src/components/Seo.tsx
@@ -24,6 +24,7 @@ const deployedTranslations = [
'es',
'fr',
'ja',
+ 'tr',
// We'll add more languages when they have enough content.
// Please DO NOT edit this list without a discussion in the reactjs/react.dev repo.
// It must be the same between all translations.
diff --git a/src/content/learn/understanding-your-ui-as-a-tree.md b/src/content/learn/understanding-your-ui-as-a-tree.md
index f4528b346..2abf7affc 100644
--- a/src/content/learn/understanding-your-ui-as-a-tree.md
+++ b/src/content/learn/understanding-your-ui-as-a-tree.md
@@ -22,7 +22,7 @@ React, and many other UI libraries, model UI as a tree. Thinking of your app as
Trees are a relationship model between items and UI is often represented using tree structures. For example, browsers use tree structures to model HTML ([DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model/Introduction)) and CSS ([CSSOM](https://developer.mozilla.org/docs/Web/API/CSS_Object_Model)). Mobile platforms also use trees to represent their view hierarchy.
-
+
React creates a UI tree from your components. In this example, the UI tree is then used to render to the DOM.
diff --git a/src/content/reference/react-dom/components/common.md b/src/content/reference/react-dom/components/common.md
index 11719112e..610742735 100644
--- a/src/content/reference/react-dom/components/common.md
+++ b/src/content/reference/react-dom/components/common.md
@@ -982,6 +982,8 @@ textarea { display: block; margin-top: 5px; margin-bottom: 10px; }
+The `{__html}` object should be created as close to where the HTML is generated as possible, like the above example does in the `renderMarkdownToHTML` function. This ensures that all raw HTML being used in your code is explicitly marked as such, and that only variables that you expect to contain HTML are passed to `dangerouslySetInnerHTML`. It is not recommended to create the object inline like ``.
+
To see why rendering arbitrary HTML is dangerous, replace the code above with this:
```js {1-4,7,8}
diff --git a/src/content/reference/react/use-server.md b/src/content/reference/react/use-server.md
index 638163369..0d0fc8404 100644
--- a/src/content/reference/react/use-server.md
+++ b/src/content/reference/react/use-server.md
@@ -153,7 +153,7 @@ export default async function requestUsername(formData) {
// UsernameForm.js
'use client';
-import {useFormState} from 'react-dom';
+import { useFormState } from 'react-dom';
import requestUsername from './requestUsername';
function UsernameForm() {
@@ -208,7 +208,7 @@ function LikeButton() {
'use server';
let likeCount = 0;
-export default async incrementLike() {
+export default async function incrementLike() {
likeCount++;
return likeCount;
}
diff --git a/src/content/reference/react/useTransition.md b/src/content/reference/react/useTransition.md
index 37e89c0c9..49df279fb 100644
--- a/src/content/reference/react/useTransition.md
+++ b/src/content/reference/react/useTransition.md
@@ -1520,15 +1520,15 @@ import { ErrorBoundary } from "react-error-boundary";
export function AddCommentContainer() {
return (
⚠️Something went wrong}>
-
+
);
}
function addComment(comment) {
// For demonstration purposes to show Error Boundary
- if(comment == null){
- throw Error('Example error')
+ if (comment == null) {
+ throw new Error("Example Error: An error thrown to trigger error boundary");
}
}
@@ -1544,9 +1544,10 @@ function AddCommentButton() {
// so error gets thrown
addComment();
});
- }}>
- Add comment
-
+ }}
+ >
+ Add comment
+
);
}
```
diff --git a/src/utils/prepareMDX.js b/src/utils/prepareMDX.js
index 6340c3b7f..677293ecd 100644
--- a/src/utils/prepareMDX.js
+++ b/src/utils/prepareMDX.js
@@ -7,7 +7,7 @@ import {Children} from 'react';
// TODO: This logic could be in MDX plugins instead.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-export const PREPARE_MDX_CACHE_BREAKER = 2;
+export const PREPARE_MDX_CACHE_BREAKER = 3;
// !!! IMPORTANT !!! Bump this if you change any logic.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~