diff --git a/.changeset/thirty-swans-yawn.md b/.changeset/thirty-swans-yawn.md new file mode 100644 index 000000000..6ae4189e4 --- /dev/null +++ b/.changeset/thirty-swans-yawn.md @@ -0,0 +1,5 @@ +--- +'@primer/react-brand': patch +--- + +Added horizontal scrolling to `IDE` component when viewed on small viewports diff --git a/packages/react/src/IDE/IDE.module.css b/packages/react/src/IDE/IDE.module.css index fa8d08f4e..c1c155712 100644 --- a/packages/react/src/IDE/IDE.module.css +++ b/packages/react/src/IDE/IDE.module.css @@ -1,4 +1,5 @@ .IDE__inner { + --brand-IDE-lineNumber-width: 45px; background: var(--brand-IDE-default-bgColor); border: var(--brand-borderWidth-thin) solid var(--brand-IDE-borderColor); } @@ -170,10 +171,11 @@ } .IDE--default .IDE__Editor { - margin-left: var(--base-size-20); + padding-left: var(--base-size-20); } .IDE__Editor-tabs { + overflow-x: auto; display: inline-flex; background: var(--brand-IDE-default-editor-tabs-bgColor); } @@ -187,6 +189,7 @@ } .IDE__Editor-tab { + flex-shrink: 0; display: flex; padding: var(--base-size-8) var(--base-size-12); align-items: center; @@ -262,6 +265,7 @@ img.IDE__Editor-tab-icon { .IDE__Editor-content { height: 100%; padding-top: var(--base-size-16); + overflow-x: auto; } .IDE--default .IDE__Editor-content { @@ -281,6 +285,14 @@ img.IDE__Editor-tab-icon { margin: 0; } +.IDE__Editor-content-wrapper { + display: flex; +} + +.IDE__Editor-content-inner { + flex: 1; +} + .IDE__Editor--small .IDE__Editor-pane, .IDE__Editor--small .IDE__Editor-lineNumbers { font-size: calc(var(--base-size-12) - 1px) !important; /* workaround dotcom specificity */ @@ -300,18 +312,19 @@ img.IDE__Editor-tab-icon { } .IDE__Editor-pane--suggested { + margin-left: calc(-1 * var(--base-size-64)); + padding-left: calc((var(--base-size-64) * 2) - var(--brand-IDE-lineNumber-width)) !important; background-color: var(--brand-IDE-autoSuggestLine-bgColor); } .IDE__Editor-lineNumbers { - position: absolute; z-index: 1; font-family: var(--brand-fontStack-monospace); font-weight: var(--brand-text-weight-200); font-feature-settings: 'liga' 0, 'calt' 0; font-variation-settings: normal; letter-spacing: 0; - width: 45px; + flex: 0 0 var(--brand-IDE-lineNumber-width); } .IDE__Editor-lineNumber { @@ -341,20 +354,17 @@ img.IDE__Editor-tab-icon { .IDE__Editor pre { color: var(--brand-color-text-default); font-family: var(--brand-fontStack-monospace); - padding-left: var(--base-size-64); + padding-left: calc(var(--base-size-64) - var(--brand-IDE-lineNumber-width)); } pre.IDE__Chat-copilot-indicator { background-color: var(--brand-IDE-autoSuggest-bgColor); padding-left: 0; - position: absolute; display: inline-flex; padding: var(--base-size-8) var(--base-size-24); border-radius: var(--brand-borderRadius-small); gap: var(--base-size-16); - margin: 0; - margin-left: 60px; - margin-top: var(--base-size-4); + margin: var(--base-size-4) 0 0 var(--base-size-16); box-shadow: -9px 10px 39px 0px rgba(0, 0, 0, 0.25); } diff --git a/packages/react/src/IDE/IDE.module.css.d.ts b/packages/react/src/IDE/IDE.module.css.d.ts index 7305617c6..149202e03 100644 --- a/packages/react/src/IDE/IDE.module.css.d.ts +++ b/packages/react/src/IDE/IDE.module.css.d.ts @@ -23,6 +23,8 @@ declare const styles: { readonly "IDE__Editor-tab-icon": string; readonly "IDE__Editor-content": string; readonly "IDE__Editor-pane": string; + readonly "IDE__Editor-content-wrapper": string; + readonly "IDE__Editor-content-inner": string; readonly "IDE__Editor--small": string; readonly "IDE__Editor-lineNumbers": string; readonly "IDE__Editor--medium": string; diff --git a/packages/react/src/IDE/IDE.test.tsx b/packages/react/src/IDE/IDE.test.tsx index 9efa94ad1..be5615897 100644 --- a/packages/react/src/IDE/IDE.test.tsx +++ b/packages/react/src/IDE/IDE.test.tsx @@ -39,7 +39,14 @@ describe('IDE', () => { {name: 'File 3', alternativeText: 'Alt for File 3', code: 'Code for File 3'}, ] - afterEach(cleanup) + beforeEach(() => { + Element.prototype.scrollIntoView = jest.fn() + }) + + afterEach(() => { + cleanup() + jest.clearAllMocks() + }) it('renders main elements correctly into the document', () => { const {getByTestId} = render( diff --git a/packages/react/src/IDE/IDE.tsx b/packages/react/src/IDE/IDE.tsx index 99a5b22a5..ed7029d64 100644 --- a/packages/react/src/IDE/IDE.tsx +++ b/packages/react/src/IDE/IDE.tsx @@ -16,7 +16,7 @@ import React, { import {Avatar, Button, Text, TextInput} from '..' import type {BaseProps} from '../component-helpers' -import {useTabs} from '../hooks/useTabs' +import {useTabs, type OnTabActivate} from '../hooks/useTabs' /** * Design tokens @@ -404,9 +404,13 @@ const _Editor = memo( setTimeouts(prev => [...prev, animationEndTimeout]) }, [hasAnimated, isAnimating]) - const onTabActivate = useCallback(() => { - resetAnimation() - }, [resetAnimation]) + const onTabActivate = useCallback( + (_, activeTabRef) => { + activeTabRef?.scrollIntoView({behavior: 'smooth', block: 'nearest', inline: 'start'}) + resetAnimation() + }, + [resetAnimation], + ) const tabs = useTabs({ defaultTab: activeTab.toString(), @@ -454,7 +458,7 @@ const _Editor = memo( {files.map((file, fileIndex) => (
{file.alternativeText} -