diff --git a/.env.production b/.env.production index d25eb7dd4..e403f96b6 100644 --- a/.env.production +++ b/.env.production @@ -1 +1 @@ -NEXT_PUBLIC_GA_TRACKING_ID = 'UA-41298772-4' \ No newline at end of file +NEXT_PUBLIC_GA_TRACKING_ID = 'G-B1E83PJ3RT' \ No newline at end of file diff --git a/package.json b/package.json index 5ff6adbab..f75ffbb28 100644 --- a/package.json +++ b/package.json @@ -30,13 +30,12 @@ "classnames": "^2.2.6", "date-fns": "^2.16.1", "debounce": "^1.2.1", - "ga-lite": "^2.1.4", "github-slugger": "^1.3.0", "next": "^13.4.1", "next-remote-watch": "^1.0.0", "parse-numeric-range": "^1.2.0", "react": "^0.0.0-experimental-16d053d59-20230506", - "react-collapsed": "npm:@gaearon/react-collapsed@3.1.0-forked.1", + "react-collapsed": "4.0.4", "react-dom": "^0.0.0-experimental-16d053d59-20230506", "remark-frontmatter": "^4.0.1", "remark-gfm": "^3.0.1" @@ -92,7 +91,7 @@ "retext": "^7.0.1", "retext-smartypants": "^4.0.0", "rss": "^1.2.2", - "tailwindcss": "^3.3.2", + "tailwindcss": "^3.4.1", "typescript": "^4.0.2", "unist-util-visit": "^2.0.3", "webpack-bundle-analyzer": "^4.5.0" 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/public/images/docs/diagrams/conditional_render_tree.dark.png b/public/images/docs/diagrams/conditional_render_tree.dark.png new file mode 100644 index 000000000..5189a44c8 Binary files /dev/null and b/public/images/docs/diagrams/conditional_render_tree.dark.png differ diff --git a/public/images/docs/diagrams/conditional_render_tree.png b/public/images/docs/diagrams/conditional_render_tree.png new file mode 100644 index 000000000..c76e8cb63 Binary files /dev/null and b/public/images/docs/diagrams/conditional_render_tree.png differ diff --git a/public/images/docs/diagrams/generic_dependency_tree.dark.png b/public/images/docs/diagrams/generic_dependency_tree.dark.png new file mode 100644 index 000000000..64694f585 Binary files /dev/null and b/public/images/docs/diagrams/generic_dependency_tree.dark.png differ diff --git a/public/images/docs/diagrams/generic_dependency_tree.png b/public/images/docs/diagrams/generic_dependency_tree.png new file mode 100644 index 000000000..8ab6f1a34 Binary files /dev/null and b/public/images/docs/diagrams/generic_dependency_tree.png differ diff --git a/public/images/docs/diagrams/generic_render_tree.dark.png b/public/images/docs/diagrams/generic_render_tree.dark.png new file mode 100644 index 000000000..859fdaa96 Binary files /dev/null and b/public/images/docs/diagrams/generic_render_tree.dark.png differ diff --git a/public/images/docs/diagrams/generic_render_tree.png b/public/images/docs/diagrams/generic_render_tree.png new file mode 100644 index 000000000..952cf5faa Binary files /dev/null and b/public/images/docs/diagrams/generic_render_tree.png differ diff --git a/public/images/docs/diagrams/module_dependency_tree.dark.png b/public/images/docs/diagrams/module_dependency_tree.dark.png new file mode 100644 index 000000000..e8a85f7c0 Binary files /dev/null and b/public/images/docs/diagrams/module_dependency_tree.dark.png differ diff --git a/public/images/docs/diagrams/module_dependency_tree.png b/public/images/docs/diagrams/module_dependency_tree.png new file mode 100644 index 000000000..0dcaaa7aa Binary files /dev/null and b/public/images/docs/diagrams/module_dependency_tree.png differ diff --git a/public/images/docs/diagrams/render_tree.dark.png b/public/images/docs/diagrams/render_tree.dark.png new file mode 100644 index 000000000..117d7ff3e Binary files /dev/null and b/public/images/docs/diagrams/render_tree.dark.png differ diff --git a/public/images/docs/diagrams/render_tree.png b/public/images/docs/diagrams/render_tree.png new file mode 100644 index 000000000..1ea750bb0 Binary files /dev/null and b/public/images/docs/diagrams/render_tree.png differ diff --git a/public/images/docs/diagrams/use_client_module_dependency.dark.png b/public/images/docs/diagrams/use_client_module_dependency.dark.png new file mode 100644 index 000000000..c50e7308b Binary files /dev/null and b/public/images/docs/diagrams/use_client_module_dependency.dark.png differ diff --git a/public/images/docs/diagrams/use_client_module_dependency.png b/public/images/docs/diagrams/use_client_module_dependency.png new file mode 100644 index 000000000..d535246f7 Binary files /dev/null and b/public/images/docs/diagrams/use_client_module_dependency.png differ diff --git a/public/images/docs/diagrams/use_client_render_tree.dark.png b/public/images/docs/diagrams/use_client_render_tree.dark.png new file mode 100644 index 000000000..8d3e6a484 Binary files /dev/null and b/public/images/docs/diagrams/use_client_render_tree.dark.png differ diff --git a/public/images/docs/diagrams/use_client_render_tree.png b/public/images/docs/diagrams/use_client_render_tree.png new file mode 100644 index 000000000..ad3840681 Binary files /dev/null and b/public/images/docs/diagrams/use_client_render_tree.png differ diff --git a/src/components/DocsFooter.tsx b/src/components/DocsFooter.tsx index d0144c459..7d825b192 100644 --- a/src/components/DocsFooter.tsx +++ b/src/components/DocsFooter.tsx @@ -27,7 +27,7 @@ export const DocsPageFooter = memo( <> {prevRoute?.path || nextRoute?.path ? ( <> -
+
{prevRoute?.path ? ( >>>>>> 3563d95efe8719bdae8bbd258e6ab4134753348b /> - - +
+ {type} - {title} - + + {title} + +
); } diff --git a/src/components/ErrorDecoderContext.tsx b/src/components/ErrorDecoderContext.tsx new file mode 100644 index 000000000..080969efe --- /dev/null +++ b/src/components/ErrorDecoderContext.tsx @@ -0,0 +1,23 @@ +// Error Decoder requires reading pregenerated error message from getStaticProps, +// but MDX component doesn't support props. So we use React Context to populate +// the value without prop-drilling. +// TODO: Replace with React.cache + React.use when migrating to Next.js App Router + +import {createContext, useContext} from 'react'; + +const notInErrorDecoderContext = Symbol('not in error decoder context'); + +export const ErrorDecoderContext = createContext< + | {errorMessage: string | null; errorCode: string | null} + | typeof notInErrorDecoderContext +>(notInErrorDecoderContext); + +export const useErrorDecoderParams = () => { + const params = useContext(ErrorDecoderContext); + + if (params === notInErrorDecoderContext) { + throw new Error('useErrorDecoder must be used in error decoder pages only'); + } + + return params; +}; diff --git a/src/components/Icon/IconGitHub.tsx b/src/components/Icon/IconGitHub.tsx index de2a982bd..49d7fb460 100644 --- a/src/components/Icon/IconGitHub.tsx +++ b/src/components/Icon/IconGitHub.tsx @@ -9,8 +9,8 @@ export const IconGitHub = memo( return ( diff --git a/src/components/Icon/IconThreads.tsx b/src/components/Icon/IconThreads.tsx new file mode 100644 index 000000000..5a007657f --- /dev/null +++ b/src/components/Icon/IconThreads.tsx @@ -0,0 +1,24 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + */ + +import {memo} from 'react'; + +export const IconThreads = memo( + function IconThreads(props) { + return ( + + + + ); + } +); diff --git a/src/components/Layout/Feedback.tsx b/src/components/Layout/Feedback.tsx index d984ef584..3ef6bb2db 100644 --- a/src/components/Layout/Feedback.tsx +++ b/src/components/Layout/Feedback.tsx @@ -4,7 +4,7 @@ import {useState} from 'react'; import {useRouter} from 'next/router'; -import {ga} from '../../utils/analytics'; +import cn from 'classnames'; export function Feedback({onSubmit = () => {}}: {onSubmit?: () => void}) { const {asPath} = useRouter(); @@ -46,21 +46,22 @@ const thumbsDownIcon = ( ); function sendGAEvent(isPositive: boolean) { + const category = isPositive ? 'like_button' : 'dislike_button'; + const value = isPositive ? 1 : 0; // Fragile. Don't change unless you've tested the network payload // and verified that the right events actually show up in GA. - ga( - 'send', - 'event', - 'button', - 'feedback', - window.location.pathname, - isPositive ? '1' : '0' - ); + // @ts-ignore + gtag('event', 'feedback', { + event_category: category, + event_label: window.location.pathname, + event_value: value, + }); } function SendFeedback({onSubmit}: {onSubmit: () => void}) { const [isSubmitted, setIsSubmitted] = useState(false); return ( +<<<<<<< HEAD

{isSubmitted @@ -71,6 +72,20 @@ function SendFeedback({onSubmit}: {onSubmit: () => void}) { -

+
@@ -260,16 +260,16 @@ export default function TopNav({
-
+
@@ -313,7 +313,7 @@ export default function TopNav({ onClick={() => { window.__setPreferredTheme('dark'); }} - className="active:scale-95 transition-transform flex w-12 h-12 rounded-full items-center justify-center hover:bg-primary/5 hover:dark:bg-primary-dark/5 outline-link"> + className="flex items-center justify-center w-12 h-12 transition-transform rounded-full active:scale-95 hover:bg-primary/5 hover:dark:bg-primary-dark/5 outline-link"> {darkIcon}
@@ -324,7 +324,7 @@ export default function TopNav({ onClick={() => { window.__setPreferredTheme('light'); }} - className="active:scale-95 transition-transform flex w-12 h-12 rounded-full items-center justify-center hover:bg-primary/5 hover:dark:bg-primary-dark/5 outline-link"> + className="flex items-center justify-center w-12 h-12 transition-transform rounded-full active:scale-95 hover:bg-primary/5 hover:dark:bg-primary-dark/5 outline-link"> {lightIcon}
@@ -333,8 +333,13 @@ export default function TopNav({ href="https://github.com/facebook/react/releases" target="_blank" rel="noreferrer noopener" +<<<<<<< HEAD aria-label="Buka di GitHub" className="active:scale-95 transition-transform flex w-12 h-12 rounded-full items-center justify-center hover:bg-primary/5 hover:dark:bg-primary-dark/5 outline-link"> +======= + aria-label="Open on GitHub" + className="flex items-center justify-center w-12 h-12 transition-transform rounded-full active:scale-95 hover:bg-primary/5 hover:dark:bg-primary-dark/5 outline-link"> +>>>>>>> 3563d95efe8719bdae8bbd258e6ab4134753348b {githubIcon}
@@ -349,13 +354,13 @@ export default function TopNav({ className="overflow-y-scroll isolate no-bg-scrollbar lg:w-[342px] grow bg-wash dark:bg-wash-dark">