Skip to content

Commit 6ca8431

Browse files
committed
post-rebase fixes to align experiment code with main
1 parent 18dacec commit 6ca8431

13 files changed

Lines changed: 72 additions & 238 deletions

File tree

apps/docs/app/trees-dev/bulk/page.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import { preloadFileTree } from '@pierre/trees/ssr';
1+
import {
2+
preloadFileTree,
3+
serializeFileTreeSsrPayload,
4+
} from '@pierre/trees/ssr';
25

36
import { BulkIngestDemoClient } from '../_demos/BulkIngestDemoClient';
47
import {
@@ -27,16 +30,16 @@ export default async function TreesDevBulkPage({
2730
routeState.workloadName,
2831
routeState.expansionMode
2932
),
33+
initialVisibleRowCount: FILE_TREE_PROOF_VIEWPORT_HEIGHT / 30,
3034
paths: previewData.previewPaths,
3135
preparedInput: createPresortedPreparedInput(previewData.previewPaths),
3236
search: true,
33-
viewportHeight: FILE_TREE_PROOF_VIEWPORT_HEIGHT,
3437
});
3538

3639
return (
3740
<BulkIngestDemoClient
3841
key={JSON.stringify(routeState)}
39-
payloadHtml={payload.html}
42+
payloadHtml={serializeFileTreeSsrPayload(payload, 'dom')}
4043
{...routeState}
4144
/>
4245
);

apps/docs/app/trees-dev/debug-static/page.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import { preloadFileTree } from '@pierre/trees/ssr';
1+
import {
2+
preloadFileTree,
3+
serializeFileTreeSsrPayload,
4+
} from '@pierre/trees/ssr';
25

36
import { DebugStaticClient } from '../_demos/DebugStaticClient';
47
import { createPresortedPreparedInput } from '../_lib/createPresortedPreparedInput';
@@ -11,16 +14,16 @@ export default function TreesDevDebugStaticPage() {
1114
const payload = preloadFileTree({
1215
flattenEmptyDirectories: false,
1316
id: 'trees-dev-debug-static',
17+
initialVisibleRowCount: FILE_TREE_PROOF_VIEWPORT_HEIGHT / 30,
1418
paths: DEBUG_STATIC_PATHS,
1519
preparedInput,
16-
viewportHeight: FILE_TREE_PROOF_VIEWPORT_HEIGHT,
1720
});
1821

1922
return (
2023
<DebugStaticClient
2124
mountId={mountId}
2225
mountMode="hydrate"
23-
payloadHtml={payload.html}
26+
payloadHtml={serializeFileTreeSsrPayload(payload, 'dom')}
2427
/>
2528
);
2629
}

apps/docs/app/trees-dev/reveal/page.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import { preloadFileTree } from '@pierre/trees/ssr';
1+
import {
2+
preloadFileTree,
3+
serializeFileTreeSsrPayload,
4+
} from '@pierre/trees/ssr';
25

36
import { RevealLoadingDemoClient } from '../_demos/RevealLoadingDemoClient';
47
import { createPresortedPreparedInput } from '../_lib/createPresortedPreparedInput';
@@ -10,13 +13,16 @@ export default function TreesDevRevealPage() {
1013
const payload = preloadFileTree({
1114
flattenEmptyDirectories: false,
1215
id: 'trees-dev-reveal-ssr',
16+
initialVisibleRowCount: FILE_TREE_PROOF_VIEWPORT_HEIGHT / 30,
1317
paths: REVEAL_DEMO_ROOT_PATHS,
1418
preparedInput: createPresortedPreparedInput(REVEAL_DEMO_ROOT_PATHS),
1519
search: true,
16-
viewportHeight: FILE_TREE_PROOF_VIEWPORT_HEIGHT,
1720
});
1821

1922
return (
20-
<RevealLoadingDemoClient mountId={mountId} payloadHtml={payload.html} />
23+
<RevealLoadingDemoClient
24+
mountId={mountId}
25+
payloadHtml={serializeFileTreeSsrPayload(payload, 'dom')}
26+
/>
2127
);
2228
}

apps/docs/app/trees/DemoContextMenuClient.tsx

Lines changed: 0 additions & 201 deletions
Original file line numberDiff line numberDiff line change
@@ -54,207 +54,6 @@ interface DemoContextMenuClientProps {
5454
preloadedDataById: Readonly<Record<string, FileTreePreloadedData>>;
5555
}
5656

57-
function LocalProjectHeader({
58-
projectName,
59-
onAddFile,
60-
onAddFolder,
61-
}: {
62-
projectName: string;
63-
onAddFile: () => void;
64-
onAddFolder: () => void;
65-
}) {
66-
return (
67-
<div className="flex items-center justify-between gap-2 px-3 py-2">
68-
<div className="min-w-0 truncate text-sm font-medium text-neutral-200">
69-
{projectName}/
70-
</div>
71-
<div className="flex items-center gap-3">
72-
<button
73-
type="button"
74-
title="New file"
75-
onClick={onAddFile}
76-
className="h-4 w-4 text-neutral-400 hover:text-neutral-100"
77-
>
78-
<IconFilePlus aria-hidden="true" />
79-
</button>
80-
<button
81-
type="button"
82-
title="New folder"
83-
onClick={onAddFolder}
84-
className="h-4 w-4 text-neutral-400 hover:text-neutral-100"
85-
>
86-
<IconFolderPlus aria-hidden="true" />
87-
</button>
88-
</div>
89-
</div>
90-
);
91-
}
92-
93-
function getParentPath(path: string): string {
94-
const normalizedPath = path.endsWith('/') ? path.slice(0, -1) : path;
95-
const lastSlashIndex = normalizedPath.lastIndexOf('/');
96-
return lastSlashIndex < 0
97-
? ''
98-
: `${normalizedPath.slice(0, lastSlashIndex + 1)}`;
99-
}
100-
101-
function getUniquePath(model: FileTreeModel, basePath: string): string {
102-
let suffix = 0;
103-
let candidate = basePath;
104-
while (model.getItem(candidate) != null) {
105-
suffix += 1;
106-
if (basePath.endsWith('/')) {
107-
candidate = `${basePath.slice(0, -1)}-${String(suffix)}/`;
108-
continue;
109-
}
110-
111-
const dotIndex = basePath.lastIndexOf('.');
112-
const slashIndex = basePath.lastIndexOf('/');
113-
if (dotIndex > slashIndex) {
114-
candidate = `${basePath.slice(0, dotIndex)}-${String(suffix)}${basePath.slice(dotIndex)}`;
115-
continue;
116-
}
117-
118-
candidate = `${basePath}-${String(suffix)}`;
119-
}
120-
return candidate;
121-
}
122-
123-
function ContextMenuContents({
124-
context,
125-
portalContainer,
126-
onAddFile,
127-
onAddFolder,
128-
onDelete,
129-
onRename,
130-
}: {
131-
context: Pick<
132-
ContextMenuOpenContext,
133-
'anchorRect' | 'close' | 'restoreFocus'
134-
>;
135-
portalContainer?: HTMLElement | null;
136-
onAddFile: () => void;
137-
onAddFolder: () => void;
138-
onDelete: () => void;
139-
onRename: () => void;
140-
}) {
141-
const closeAfter = (action: () => void) => {
142-
action();
143-
context.close();
144-
};
145-
146-
return (
147-
<DropdownMenu
148-
open
149-
modal={false}
150-
onOpenChange={(open) => !open && context.close()}
151-
>
152-
<DropdownMenuTrigger asChild>
153-
<button
154-
type="button"
155-
aria-hidden="true"
156-
tabIndex={-1}
157-
style={getFloatingContextMenuTriggerStyle(context.anchorRect)}
158-
/>
159-
</DropdownMenuTrigger>
160-
<DropdownMenuContent
161-
container={portalContainer}
162-
data-file-tree-context-menu-root="true"
163-
align="center"
164-
side="bottom"
165-
sideOffset={4}
166-
className="min-w-[180px]"
167-
onCloseAutoFocus={(event) => {
168-
event.preventDefault();
169-
context.restoreFocus();
170-
}}
171-
>
172-
<DropdownMenuItem
173-
onSelect={() => {
174-
closeAfter(onAddFile);
175-
}}
176-
>
177-
New file
178-
</DropdownMenuItem>
179-
<DropdownMenuItem
180-
onSelect={() => {
181-
closeAfter(onAddFolder);
182-
}}
183-
>
184-
New folder
185-
</DropdownMenuItem>
186-
<DropdownMenuItem
187-
onSelect={() => {
188-
context.close({ restoreFocus: false });
189-
onRename();
190-
}}
191-
>
192-
Rename
193-
</DropdownMenuItem>
194-
<DropdownMenuSeparator />
195-
<DropdownMenuItem
196-
variant="danger"
197-
onSelect={() => {
198-
closeAfter(onDelete);
199-
}}
200-
>
201-
Delete
202-
</DropdownMenuItem>
203-
</DropdownMenuContent>
204-
</DropdownMenu>
205-
);
206-
}
207-
208-
function clearContextMenuSlot({
209-
menuRootRef,
210-
slotElement,
211-
}: {
212-
menuRootRef: { current: ReactDomRoot | null };
213-
slotElement: HTMLDivElement;
214-
}): void {
215-
const currentRoot = menuRootRef.current;
216-
if (currentRoot == null) {
217-
return;
218-
}
219-
220-
slotElement.style.display = 'none';
221-
currentRoot.render(null);
222-
}
223-
224-
function useHeaderSlotRenderer(
225-
modelRef: { current: FileTreeModel | null },
226-
projectName: string
227-
) {
228-
const slotElementRef = useRef<HTMLDivElement | null>(null);
229-
const headerRootRef = useRef<ReactDomRoot | null>(null);
230-
231-
return useCallback(() => {
232-
const slotElement = slotElementRef.current ?? document.createElement('div');
233-
slotElementRef.current = slotElement;
234-
slotElement.style.display = 'block';
235-
headerRootRef.current ??= createRoot(slotElement);
236-
237-
const model = modelRef.current;
238-
if (model == null) {
239-
return slotElement;
240-
}
241-
242-
headerRootRef.current.render(
243-
<LocalProjectHeader
244-
projectName={projectName}
245-
onAddFile={() => {
246-
model.add(getUniquePath(model, 'new-file.ts'));
247-
}}
248-
onAddFolder={() => {
249-
model.add(getUniquePath(model, 'new-folder/'));
250-
}}
251-
/>
252-
);
253-
254-
return slotElement;
255-
}, [modelRef, projectName]);
256-
}
257-
25857
function getProjectNameForMode(mode: ContextMenuTriggerMode): string {
25958
switch (mode) {
26059
case 'button':

packages/path-store/src/store.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,6 @@ import { getFlattenedChildDirectoryId } from './flatten';
4545
import {
4646
getNodeDepth,
4747
isDirectoryNode,
48-
PATH_STORE_NODE_FLAG_ROOT,
49-
PATH_STORE_NODE_KIND_DIRECTORY,
5048
type NodeId,
5149
type PreparedPath,
5250
} from './internal-types';
@@ -1222,7 +1220,7 @@ export class PathStore {
12221220

12231221
while (true) {
12241222
const node = requireNode(this.#state, nodeId);
1225-
if (node.kind !== PATH_STORE_NODE_KIND_DIRECTORY) {
1223+
if (!isDirectoryNode(node)) {
12261224
return materializeNodePath(this.#state, nodeId);
12271225
}
12281226

packages/trees/src/index.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,15 @@ export {
1818
prepareFileTreeInput,
1919
preparePresortedFileTreeInput,
2020
} from './preparedInput';
21-
export { FILE_TREE_DEFAULT_ITEM_HEIGHT } from './model/virtualization';
21+
export {
22+
computeStickyWindowLayout,
23+
computeVisibleRange,
24+
computeWindowRange,
25+
FILE_TREE_DEFAULT_ITEM_HEIGHT,
26+
FILE_TREE_DEFAULT_OVERSCAN,
27+
FILE_TREE_DEFAULT_VIEWPORT_HEIGHT,
28+
} from './model/virtualization';
29+
export { FileTreeController } from './model/FileTreeController';
2230
export {
2331
FILE_TREE_DENSITY_PRESETS,
2432
type FileTreeDensity,

packages/trees/src/model/FileTreeController.ts

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ import type {
1111
PathStoreVisibleTreeProjectionData,
1212
} from '@pierre/path-store';
1313

14-
import type { FileTreePreparedInput } from '../preparedInput';
14+
import {
15+
type FileTreePreparedInput,
16+
preparePresortedFileTreeInput,
17+
toPathStorePreparedInput,
18+
} from '../preparedInput';
1519
import { renameFileTreePaths } from '../utils/renameFileTreePaths';
1620
import {
1721
buildDropOperations,
@@ -687,15 +691,18 @@ export class FileTreeController
687691
loading,
688692
renaming,
689693
onSearchChange,
690-
paths = [],
694+
paths,
691695
preparedInput,
692696
...storeOptions
693697
} = options;
694-
const resolvedInput = resolveFileTreeInput(
695-
{ paths, preparedInput },
696-
'constructor',
697-
storeOptions.sort
698-
);
698+
const resolvedInput =
699+
paths == null && preparedInput == null
700+
? { paths: [] as readonly string[], preparedInput: undefined }
701+
: resolveFileTreeInput(
702+
{ paths, preparedInput },
703+
'constructor',
704+
storeOptions.sort
705+
);
699706
this.#loading = loading;
700707
this.#storeOptions = storeOptions as Omit<
701708
PathStoreConstructorOptions,
@@ -2067,7 +2074,7 @@ export class FileTreeController
20672074

20682075
this.resetPaths(this.#bulkSeedPaths, {
20692076
initialExpandedPaths: this.#getExpandedDirectoryPaths(),
2070-
preparedInput: PathStore.preparePresortedInput(this.#bulkSeedPaths),
2077+
preparedInput: preparePresortedFileTreeInput(this.#bulkSeedPaths),
20712078
});
20722079
}
20732080

@@ -2130,7 +2137,7 @@ export class FileTreeController
21302137
preparedInput:
21312138
preparedInput == null
21322139
? undefined
2133-
: (preparedInput as unknown as { paths: readonly string[] }),
2140+
: toPathStorePreparedInput(preparedInput),
21342141
...(initialExpandedPathsOverride !== undefined
21352142
? { initialExpandedPaths: initialExpandedPathsOverride }
21362143
: {}),

packages/trees/src/model/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { PathStoreDirectoryLoadState } from '@pierre/path-store';
2+
23
import type { FileTreeIcons, RemappedIcon } from '../iconConfig';
34
import type { FileTreePreparedInput } from '../preparedInput';
45
import type {

0 commit comments

Comments
 (0)