Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion apps/demo/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1064,6 +1064,8 @@ if (renderFileButton != null) {
overflow: wrap ? 'wrap' : 'scroll',
theme: DEMO_THEME,
themeType: getThemeType(),
// Folding starts disabled in the demo; the header toggle enables it.
folding: false,
renderAnnotation,
...(RENDER_FILENAME_SUFFIX
? {
Expand Down Expand Up @@ -1098,6 +1100,22 @@ if (renderFileButton != null) {
}
}
);
// Folding lives on the shared code options, so this flip reaches
// whichever side currently owns folding: the read-only file or an
// attached editor.
const foldingToggle = createToggle(
'Folding',
instance?.options.folding === true,
(checked) => {
instance?.setOptions({
...instance.options,
folding: checked,
});
if (!VIRTUALIZE) {
void instance.rerender();
}
}
);
editShortcutCallback = (): boolean | void => {
if (!isEditing) {
editableToggle.querySelector('input')?.click();
Expand All @@ -1107,7 +1125,7 @@ if (renderFileButton != null) {
const div = document.createElement('div');
div.style.display = 'flex';
div.style.gap = '8px';
div.append(collapsedToggle, editableToggle);
div.append(collapsedToggle, editableToggle, foldingToggle);
return div;
},

Expand Down
6 changes: 4 additions & 2 deletions apps/docs/app/(diffs)/docs/Edit/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1223,14 +1223,16 @@ const file: FileContents | undefined = editor.getFile();
// Full document text, or '' when nothing is attached.
const text: string = editor.getText();

// Snapshot selections and scroll positions for explicit restoration:
// Snapshot selections, active folds, and scroll positions for
// persistence or remount restore.
const state: EditorState = editor.getState();
// EditorState = {
// selections?: EditorSelection[];
// foldRanges?: LineRange[]; // zero-based; standalone closers stay visible
// view?: { scrollLeft: number; scrollTop?: number };
// }

// Restore selections and scroll positions after re-rendering.
// Restore selections, folds, and scroll positions after re-rendering.
editor.setState(state);

// Replace all cursors and ranges programmatically. Positions are zero-based;
Expand Down
25 changes: 25 additions & 0 deletions apps/docs/app/(diffs)/playground/PlaygroundClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
IconCodeStyleBars,
IconCodeStyleBg,
IconCodeStyleInline,
IconCollapsedRow,
IconColorAuto,
IconColorDark,
IconColorLight,
Expand Down Expand Up @@ -131,6 +132,7 @@ export type SharedRenderOptions = Pick<
| 'disableBackground'
| 'disableLineNumbers'
| 'overflow'
| 'folding'
| 'themeType'
| 'theme'
> & {
Expand Down Expand Up @@ -169,6 +171,8 @@ interface PlaygroundControlsContentProps {
setDisableLineNumbers: (v: boolean) => void;
overflow: 'wrap' | 'scroll';
setOverflow: (v: 'wrap' | 'scroll') => void;
folding: boolean;
setFolding: (v: boolean) => void;
enableLineSelection: boolean;
setEnableLineSelection: (v: boolean) => void;
enableGutterUtility: boolean;
Expand Down Expand Up @@ -213,6 +217,8 @@ function PlaygroundControlsContent({
setDisableLineNumbers,
overflow,
setOverflow,
folding,
setFolding,
enableLineSelection,
setEnableLineSelection,
enableGutterUtility,
Expand Down Expand Up @@ -493,6 +499,18 @@ function PlaygroundControlsContent({
}
/>

{/* Folding only applies to file surfaces (the Virtualizer README and
CodeView file items); diffs don't fold, so hide it in Normal. */}
{viewMode !== 'normal' && (
<ToggleButton
icon={<IconCollapsedRow />}
label="Folding"
checked={folding}
onCheckedChange={setFolding}
title="Code folding on file surfaces (diffs don't fold)"
/>
)}

<ToggleButton
icon={<IconInReview />}
label="Annotations"
Expand Down Expand Up @@ -686,6 +704,7 @@ export function PlaygroundClient({ prerenderedDiff }: PlaygroundClientProps) {
urlState.disableLineNumbers
);
const [overflow, setOverflow] = useState(urlState.overflow);
const [folding, setFolding] = useState(urlState.folding);
const [enableLineSelection, setEnableLineSelection] = useState(
urlState.enableLineSelection
);
Expand Down Expand Up @@ -795,6 +814,7 @@ export function PlaygroundClient({ prerenderedDiff }: PlaygroundClientProps) {
params.set('ln', disableLineNumbers ? '0' : '1');
if ((overflow === 'wrap') !== DEFAULTS.wrap)
params.set('wrap', overflow === 'wrap' ? '1' : '0');
if (folding !== DEFAULTS.folding) params.set('fold', folding ? '1' : '0');
if (interactionMode !== DEFAULTS.interactionMode)
params.set('lineMode', interactionMode);
if (enableLineSelection !== DEFAULTS.lineSelection)
Expand Down Expand Up @@ -833,6 +853,7 @@ export function PlaygroundClient({ prerenderedDiff }: PlaygroundClientProps) {
disableBackground,
disableLineNumbers,
overflow,
folding,
interactionMode,
enableLineSelection,
enableGutterUtility,
Expand Down Expand Up @@ -988,6 +1009,8 @@ export function PlaygroundClient({ prerenderedDiff }: PlaygroundClientProps) {
setDisableLineNumbers,
overflow,
setOverflow,
folding,
setFolding,
enableLineSelection,
setEnableLineSelection,
enableGutterUtility,
Expand Down Expand Up @@ -1026,6 +1049,7 @@ export function PlaygroundClient({ prerenderedDiff }: PlaygroundClientProps) {
disableBackground,
disableLineNumbers,
overflow,
folding,
themeType: effectiveColorMode,
theme: { dark: selectedDarkTheme, light: selectedLightTheme },
}),
Expand All @@ -1038,6 +1062,7 @@ export function PlaygroundClient({ prerenderedDiff }: PlaygroundClientProps) {
disableBackground,
disableLineNumbers,
overflow,
folding,
effectiveColorMode,
selectedDarkTheme,
selectedLightTheme,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
import { flushSync } from 'react-dom';

import type { PlaygroundAnnotationMetadata } from './constants';
import { ITEM_UNSAFE_CSS, LONG_README_FILE } from './constants';
import { ITEM_UNSAFE_CSS, LONG_CODE_FILE } from './constants';
import type { SharedRenderOptions } from './PlaygroundClient';
import { CommentForm, CommentThread } from './PlaygroundComments';

Expand All @@ -40,7 +40,7 @@ interface PlaygroundVirtualizerElementViewProps {
// fixed-height scroll region, in contrast to the window-scroll variant that
// drives the vanilla Virtualizer against `document`. Any React <FileDiff>
// nested under <Virtualizer> auto-virtualizes through context; no imperative
// wiring is needed. The long README plain file leads the list (as in
// wiring is needed. The long foldable plain file leads the list (as in
// CodeView), rendered through <File>, which virtualizes the same way.
export function PlaygroundVirtualizerElementView({
diffs,
Expand Down Expand Up @@ -75,7 +75,7 @@ const FILE_EDITOR_OPTIONS: EditorOptions<undefined> = {
},
};

// The long README plain-file surface leading the list. Carries the same
// The long foldable plain-file surface leading the list. Carries the same
// header Edit toggle as the diffs (the app-level EditProvider creates its
// editor); no comment wiring, since the demo file has no annotations.
function ElementVirtualizerFile({ options }: { options: SharedRenderOptions }) {
Expand Down Expand Up @@ -113,7 +113,7 @@ function ElementVirtualizerFile({ options }: { options: SharedRenderOptions }) {

return (
<File
file={LONG_README_FILE}
file={LONG_CODE_FILE}
edit={editing}
options={fileOptions}
editorOptions={FILE_EDITOR_OPTIONS}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { useEffect, useRef } from 'react';
import { flushSync } from 'react-dom';
import { createRoot, type Root } from 'react-dom/client';

import { ITEM_UNSAFE_CSS, LONG_README_FILE } from './constants';
import { ITEM_UNSAFE_CSS, LONG_CODE_FILE } from './constants';
import type { SharedRenderOptions } from './PlaygroundClient';
import { CommentForm, CommentThread } from './PlaygroundComments';

Expand Down Expand Up @@ -137,7 +137,7 @@ export function PlaygroundVirtualizerView({
// Passing `document` makes the page/window the scroll container.
virtualizer.setup(document);

// The long README plain file leads the window-scroll list (as in
// The long foldable plain file leads the window-scroll list (as in
// CodeView), driven by the vanilla VirtualizedFile. It carries the same
// header Edit toggle as the diffs below; no comment wiring, since the
// demo file has no annotations. Its container is appended first so it
Expand Down Expand Up @@ -175,7 +175,7 @@ export function PlaygroundVirtualizerView({
}
});
fileInstance.render({
file: LONG_README_FILE,
file: LONG_CODE_FILE,
fileContainer: readmeContainer,
});
fileInstanceRef.current = fileInstance;
Expand Down
23 changes: 19 additions & 4 deletions apps/docs/app/(diffs)/playground/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,15 @@ function buildLongFixtureContents(): {

const LONG_FIXTURE_CONTENTS = buildLongFixtureContents();

// The long generated TypeScript module as a ready-made plain file. Unlike the
// flat-markdown README it is deeply indented, so the file surfaces that lead
// the Virtualizer lists (and the CodeView item below) have blocks the
// read-only fold controls can actually collapse.
export const LONG_CODE_FILE: FileContents = {
name: LONG_FIXTURE_NAME,
contents: LONG_FIXTURE_CONTENTS.newContents,
};

// Fresh parse per call so each surface (Virtualizer list, CodeView items) gets
// its own FileDiffMetadata instance, matching how `variantDiff` builds the
// replicated fixtures. `context: 8` widens jsdiff's default of 4 so the added
Expand All @@ -578,11 +587,17 @@ export const VIRTUALIZER_FILE_DIFFS: FileDiffMetadata[] = [
).flat(),
];

// Items rendered in the CodeView mode: the long README file item leads,
// followed by the long single-file diff (as in the Virtualizer list), then
// each variant contributes two diffs and a plain file so the demo shows both
// item types scrolling within CodeView's own scroll container.
// Items rendered in the CodeView mode: the long foldable TypeScript file
// leads (as in the Virtualizer lists), followed by the long README file item
// and the long single-file diff, then each variant contributes two diffs and
// a plain file so the demo shows both item types scrolling within CodeView's
// own scroll container.
export const CODE_VIEW_ITEMS: CodeViewItem<PlaygroundAnnotationMetadata>[] = [
{
id: `file:${LONG_FIXTURE_NAME}`,
type: 'file',
file: LONG_CODE_FILE,
},
{
id: 'file:README.md',
type: 'file',
Expand Down
4 changes: 4 additions & 0 deletions apps/docs/app/(diffs)/playground/searchParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export const DEFAULTS = {
background: true,
lineNumbers: true,
wrap: true,
folding: true,
lineSelection: true,
gutterButton: true,
interactionMode: 'comment' as const,
Expand All @@ -99,6 +100,8 @@ export interface PlaygroundUrlState {
disableBackground: boolean;
disableLineNumbers: boolean;
overflow: 'wrap' | 'scroll';
// Code folding on file surfaces (diffs don't fold).
folding: boolean;
enableLineSelection: boolean;
enableGutterUtility: boolean;
showAnnotations: boolean;
Expand Down Expand Up @@ -176,6 +179,7 @@ export function parsePlaygroundSearchParams(
disableBackground: !pickBool(get('bg'), DEFAULTS.background),
disableLineNumbers: !pickBool(get('ln'), DEFAULTS.lineNumbers),
overflow: pickBool(get('wrap'), DEFAULTS.wrap) ? 'wrap' : 'scroll',
folding: pickBool(get('fold'), DEFAULTS.folding),
enableLineSelection,
enableGutterUtility,
showAnnotations: pickBool(get('annot'), DEFAULTS.annotations),
Expand Down
4 changes: 4 additions & 0 deletions packages/diffs/src/components/CodeView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ export const CODE_VIEW_DIFF_OPTION_KEYS = [
'themeType',
'disableFileHeader',
'disableVirtualizationBuffers',
'folding',
'preferredHighlighter',
'useCSSClasses',
'useTokenTransformer',
Expand Down Expand Up @@ -305,6 +306,7 @@ export const CODE_VIEW_FILE_OPTION_KEYS = [
'themeType',
'disableFileHeader',
'disableVirtualizationBuffers',
'folding',
'preferredHighlighter',
'useCSSClasses',
'useTokenTransformer',
Expand Down Expand Up @@ -4118,6 +4120,8 @@ function hasItemLayoutOptionChanged<LAnnotation>(
(previousOptions.disableFileHeader ?? false) !==
(nextOptions.disableFileHeader ?? false) ||
previousOptions.unsafeCSS !== nextOptions.unsafeCSS ||
// Disabling folding unfolds items, changing their heights.
(previousOptions.folding ?? true) !== (nextOptions.folding ?? true) ||
(previousOptions.diffStyle ?? 'split') !==
(nextOptions.diffStyle ?? 'split') ||
(previousOptions.diffIndicators ?? 'bars') !==
Expand Down
Loading