diff --git a/docs/platforms/javascript/guides/react/index.mdx b/docs/platforms/javascript/guides/react/index.mdx index c87a1ab2890cc..84b3aae3aad26 100644 --- a/docs/platforms/javascript/guides/react/index.mdx +++ b/docs/platforms/javascript/guides/react/index.mdx @@ -89,8 +89,8 @@ Sentry.init({ // Enable logs to be sent to Sentry enableLogs: true, // ___PRODUCT_OPTION_END___ logs - // ___PRODUCT_OPTION_START___ performance + // Set tracesSampleRate to 1.0 to capture 100% // of transactions for tracing. // Learn more at diff --git a/src/components/codeBlock/code-blocks.module.scss b/src/components/codeBlock/code-blocks.module.scss index 6141d51d990e3..edd6290f14bc5 100644 --- a/src/components/codeBlock/code-blocks.module.scss +++ b/src/components/codeBlock/code-blocks.module.scss @@ -8,10 +8,9 @@ border-radius: 0 0 6px 6px; margin-top: 0; margin-bottom: 0; - /* Wrap overly long lines so blocks never expand layout */ - white-space: pre-wrap; - word-break: break-word; - overflow-wrap: anywhere; + /* Use horizontal scroll instead of wrapping */ + white-space: pre; + overflow-x: auto; max-width: 100%; tab-size: 2; } @@ -26,10 +25,9 @@ border: 1px solid var(--accent-11); border-radius: 6px; margin: 0; - /* Ensure syntax-highlighted pre behaves like above */ - white-space: pre-wrap; - word-break: break-word; - overflow-wrap: anywhere; + /* Use horizontal scroll instead of wrapping */ + white-space: pre; + overflow-x: auto; } /** @@ -76,10 +74,8 @@ float: left; min-width: 100%; box-sizing: border-box; - /* Allow wrapping inside each highlighted line */ - white-space: pre-wrap; - word-break: break-word; - overflow-wrap: anywhere; + /* Use horizontal scroll instead of wrapping */ + white-space: pre; // Set placeholder for highlight accent border color to transparent border-left: 4px solid rgba(0, 0, 0, 0); diff --git a/src/components/codeBlock/index.tsx b/src/components/codeBlock/index.tsx index 68d319191b3e3..b7cc64c2927e4 100644 --- a/src/components/codeBlock/index.tsx +++ b/src/components/codeBlock/index.tsx @@ -25,9 +25,17 @@ function getCopiableText(element: HTMLDivElement) { let text = ''; const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, { acceptNode: function (node) { - // Skip if parent has .no-copy class - if (node.parentElement?.classList.contains('no-copy')) { - return NodeFilter.FILTER_REJECT; + let parent = node.parentElement; + // Walk up the tree to check if any parent has .no-copy, .hidden, or data-onboarding-option-hidden + while (parent && parent !== element) { + if ( + parent.classList.contains('no-copy') || + parent.classList.contains('hidden') || + parent.hasAttribute('data-onboarding-option-hidden') + ) { + return NodeFilter.FILTER_REJECT; + } + parent = parent.parentElement; } return NodeFilter.FILTER_ACCEPT; }, diff --git a/src/components/codeKeywords/styles.ts b/src/components/codeKeywords/styles.ts index 771bce96652c1..6556856b10b5d 100644 --- a/src/components/codeKeywords/styles.ts +++ b/src/components/codeKeywords/styles.ts @@ -162,7 +162,7 @@ export const KeywordSpan = styled(motion.span, { grid-row: 1; grid-column: 1; display: inline-block; - margin-top: ${p => (p.hasPreview ? '24px' : '0')}; + margin-top: 0; `; export const KeywordSearchInput = styled('input')<{dark: boolean}>` diff --git a/src/components/docPage/type.scss b/src/components/docPage/type.scss index f3fb03d0c7916..2245773b2767f 100644 --- a/src/components/docPage/type.scss +++ b/src/components/docPage/type.scss @@ -206,7 +206,9 @@ margin-top: 0; } - [data-onboarding-option].hidden { + [data-onboarding-option].hidden, + [data-integrations-wrapper].hidden, + [data-empty-line-hidden].hidden { display: none; } // force hide markers (___PRODUCT_OPTION_START___ and ___PRODUCT_OPTION_END___) diff --git a/src/components/onboarding/index.tsx b/src/components/onboarding/index.tsx index 886e0785bb29d..e2e3e1e886d14 100644 --- a/src/components/onboarding/index.tsx +++ b/src/components/onboarding/index.tsx @@ -229,6 +229,86 @@ export function updateElementsVisibilityForOptions( }); } }); + + // Handle integrations wrapper: hide opening/closing brackets if no integrations are visible + const openWrappers = document.querySelectorAll( + '[data-integrations-wrapper="open"]' + ); + + openWrappers.forEach(openLine => { + const codeBlock = openLine.closest('code.code-highlight'); + if (!codeBlock) return; + + const allLines = Array.from(codeBlock.children) as HTMLElement[]; + const openIndex = allLines.indexOf(openLine); + + // Find the matching close line in the same code block + let closeIndex = -1; + for (let i = openIndex + 1; i < allLines.length; i++) { + if (allLines[i].dataset.integrationsWrapper === 'close') { + closeIndex = i; + break; + } + } + + if (closeIndex === -1) return; + + // Check if any lines between open and close are visible (non-marker lines) + let hasVisibleIntegrations = false; + for (let i = openIndex + 1; i < closeIndex; i++) { + const line = allLines[i]; + const isHidden = line.classList.contains('hidden'); + const isMarker = line.dataset.onboardingOptionHidden; + + // Count any visible non-marker line + if (!isMarker && !isHidden) { + hasVisibleIntegrations = true; + break; + } + } + + // Toggle visibility of both open and close lines + openLine.classList.toggle('hidden', !hasVisibleIntegrations); + allLines[closeIndex].classList.toggle('hidden', !hasVisibleIntegrations); + + // Hide empty lines adjacent to the wrapper when no integrations are visible + if (!hasVisibleIntegrations) { + // Check line before open wrapper + if (openIndex > 0) { + const prevLine = allLines[openIndex - 1]; + if (!prevLine.textContent?.trim()) { + prevLine.classList.add('hidden'); + prevLine.dataset.emptyLineHidden = 'true'; + } + } + + // Check line after close wrapper + if (closeIndex < allLines.length - 1) { + const nextLine = allLines[closeIndex + 1]; + if (!nextLine.textContent?.trim()) { + nextLine.classList.add('hidden'); + nextLine.dataset.emptyLineHidden = 'true'; + } + } + } else { + // Show empty lines when integrations are visible + if (openIndex > 0) { + const prevLine = allLines[openIndex - 1]; + if (prevLine.dataset.emptyLineHidden === 'true') { + prevLine.classList.remove('hidden'); + delete prevLine.dataset.emptyLineHidden; + } + } + + if (closeIndex < allLines.length - 1) { + const nextLine = allLines[closeIndex + 1]; + if (nextLine.dataset.emptyLineHidden === 'true') { + nextLine.classList.remove('hidden'); + delete nextLine.dataset.emptyLineHidden; + } + } + } + }); } export function OnboardingOptionButtons({ diff --git a/src/rehype-onboarding-lines.js b/src/rehype-onboarding-lines.js index d84bb93b8bf22..b834945cf4594 100644 --- a/src/rehype-onboarding-lines.js +++ b/src/rehype-onboarding-lines.js @@ -42,6 +42,8 @@ function handle_inline_options(node) { // ___PRODUCT_OPTION_END___ session-replay const PRODUCT_OPTION_START = '___PRODUCT_OPTION_START___'; const PRODUCT_OPTION_END = '___PRODUCT_OPTION_END___'; + + // First pass: mark lines with options node.children?.forEach(line => { const lineStr = toString(line); if (lineStr.includes(PRODUCT_OPTION_START)) { @@ -55,4 +57,40 @@ function handle_inline_options(node) { line.properties['data-onboarding-option'] = currentOption; } }); + + // Second pass: Mark integrations array opening/closing lines + // These should be hidden if all content inside is from options that are disabled + for (let i = 0; i < (node.children?.length ?? 0); i++) { + const line = node.children[i]; + const lineStr = toString(line).trim(); + + // Found "integrations: [" + if (lineStr.match(/integrations:\s*\[/)) { + // Mark the opening line and hide it by default + line.properties['data-integrations-wrapper'] = 'open'; + const openClasses = Array.isArray(line.properties.className) + ? line.properties.className + : line.properties.className + ? [line.properties.className] + : []; + line.properties.className = [...openClasses, 'hidden']; + + // Find the closing "]," - must be exactly ], + for (let j = i + 1; j < node.children.length; j++) { + const closeStr = toString(node.children[j]).trim(); + if (closeStr === '],') { + // Mark the closing line and hide it by default + node.children[j].properties['data-integrations-wrapper'] = 'close'; + const closeClasses = Array.isArray(node.children[j].properties.className) + ? node.children[j].properties.className + : node.children[j].properties.className + ? [node.children[j].properties.className] + : []; + node.children[j].properties.className = [...closeClasses, 'hidden']; + break; + } + } + break; // Only handle first integrations array + } + } }