Skip to content
Merged
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
1 change: 1 addition & 0 deletions apps/docs/app/trees-dev/_components/TreesDevSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const DEMO_PAGES = [
{ slug: 'drag-and-drop', label: 'Drag and Drop' },
{ slug: 'git-status', label: 'Git Status' },
{ slug: 'custom-icons', label: 'Custom Icons' },
{ slug: 'icon-tiers', label: 'Icon Tiers' },
{ slug: 'header-slot', label: 'Header Slot' },
{ slug: 'context-menu', label: 'Context Menu' },
{ slug: 'virtualization', label: 'Virtualization' },
Expand Down
103 changes: 103 additions & 0 deletions apps/docs/app/trees-dev/icon-tiers/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
'use client';

import type { FileTreeBuiltInIconSet } from '@pierre/trees';
import { FileTree as FileTreeReact } from '@pierre/trees/react';

const TIER_FILES = [
// Folder states
'closed-folder/placeholder',
'open-folder/placeholder',

// Standard tier — languages & common file types
'index.ts',
'app.js',
'App.tsx',
'style.css',
'page.html',
'data.json',
'README.md',
'main.go',
'main.py',
'app.rb',
'lib.rs',
'app.swift',
'script.sh',
'logo.png',
'font.woff2',
'.gitignore',
'config.mcp',
'notes.txt',
'data.csv',
'schema.sql',
'archive.zip',

// Complete tier — frameworks, brands, tooling
'Layout.astro',
'.babelrc',
'biome.json',
'bootstrap.min.js',
'.browserslistrc',
'bun.lock',
'claude.md',
'Dockerfile',
'eslint.config.js',
'schema.graphql',
'next.config.ts',
'package.json',
'.oxlintrc.json',
'postcss.config.js',
'.prettierrc',
'styles.scss',
'.stylelintrc',
'icon.svg',
'App.svelte',
'svgo.config.js',
'tailwind.config.ts',
'main.tf',
'vite.config.ts',
'settings.code-workspace',
'App.vue',
'module.wasm',
'webpack.config.js',
'config.yml',
'main.zig',

// Falls through to `default` token
'unknown.xyz',
];

const TIERS: { set: FileTreeBuiltInIconSet; label: string }[] = [
{ set: 'minimal', label: 'Minimal' },
{ set: 'standard', label: 'Standard' },
{ set: 'complete', label: 'Complete' },
];

export default function IconTiersPage() {
return (
<>
<h1 className="mb-4 text-2xl font-bold">Icon Tiers</h1>
<div className="grid grid-cols-3 gap-6">
{TIERS.map(({ set, label }) => (
<div key={set}>
<h2 className="mb-2 text-sm font-bold">{label}</h2>
<div
className="overflow-hidden rounded-md p-3"
style={{
boxShadow: '0 0 0 1px var(--color-border), 0 1px 3px #0000000d',
}}
>
<FileTreeReact
options={{
id: `icon-tier-${set}`,
icons: set,
}}
initialFiles={TIER_FILES}
initialExpandedItems={['open-folder']}
/>
</div>
</div>
))}
</div>
</>
);
}
9 changes: 9 additions & 0 deletions apps/docs/app/trees/demo-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,25 @@ import type {
export const sampleFileList: string[] = [
'README.md',
'package.json',
'bunfig.toml',
'stylelint.config.js',
'.browserslistrc',
'.oxlintrc.json',
'.github/workflows/ci.yml',
'build/index.mjs',
'build/scripts.js',
'build/assets/images/social/logo.png',
'config/project/app.config.json',
'public/404.html',
'public/favicon.ico',
'scripts/deploy.sh',
'src/components/Button.tsx',
'src/components/Card.tsx',
'src/components/Header.tsx',
'src/components/Sidebar.tsx',
'src/lib/mdx.tsx',
'src/lib/utils.ts',
'src/styles/globals.css',
'src/utils/stream.ts',
'src/utils/worker.ts',
'src/utils/worker/index.ts',
Expand Down
44 changes: 38 additions & 6 deletions apps/docs/app/trees/docs/CoreTypes/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const FILE_TREE_OPTIONS_TYPE: PreloadFileOptions<undefined> = {
name: 'FileTreeOptions.ts',
contents: `import type {
FileTreeOptions,
FileTreeIconConfig,
FileTreeIcons,
FileTreeStateConfig,
FileTreeSearchMode,
FileTreeCollision,
Expand Down Expand Up @@ -48,8 +48,8 @@ interface FileTreeOptions {
// Optional: Git status entries for file status indicators.
gitStatus?: GitStatusEntry[];

// Optional: custom SVG sprite sheet and icon remapping.
icons?: FileTreeIconConfig;
// Optional: built-in icon set selection, colors, and custom remapping.
icons?: FileTreeIcons;

// Optional: paths that cannot be dragged when drag and drop is enabled.
lockedPaths?: string[];
Expand Down Expand Up @@ -168,8 +168,15 @@ export const FILE_TREE_ICON_CONFIG_TYPE: PreloadFileOptions<undefined> = {
name: 'FileTreeIconConfig.ts',
contents: `import type { FileTreeIconConfig } from '@pierre/trees';

// FileTreeIconConfig lets you replace built-in icons with custom SVG symbols.
// FileTreeIconConfig lets you pick a built-in set, enable semantic colors,
// or inject your own SVG symbols.
interface FileTreeIconConfig {
// Optional: use one of the built-in sets, or "none" for custom-only rules.
set?: 'minimal' | 'standard' | 'complete' | 'none';

// Optional: enable built-in per-file-type colors. Default: true.
colored?: boolean;

// An SVG string with <symbol> definitions injected into the shadow DOM.
spriteSheet?: string;

Expand All @@ -179,12 +186,35 @@ interface FileTreeIconConfig {
| string
| { name: string; width?: number; height?: number; viewBox?: string }
>;

// Remap file icons by exact basename (e.g. package.json, .gitignore).
byFileName?: Record<
string,
| string
| { name: string; width?: number; height?: number; viewBox?: string }
>;

// Remap file icons by extension (e.g. ts, tsx, spec.ts).
byFileExtension?: Record<
string,
| string
| { name: string; width?: number; height?: number; viewBox?: string }
>;

// Remap file icons when filename contains a substring (e.g. dockerfile).
byFileNameContains?: Record<
string,
| string
| { name: string; width?: number; height?: number; viewBox?: string }
>;
}

// Example: replace the file and chevron icons with custom symbols.
// Example: use the built-in file-type set with colors enabled, then override one icon.
const options = {
initialFiles: ['src/index.ts', 'src/components/Button.tsx'],
icons: {
set: 'standard',
colored: true,
spriteSheet: \`
<svg data-icon-sprite aria-hidden="true" width="0" height="0">
<symbol id="my-file" viewBox="0 0 24 24" fill="none"
Expand All @@ -198,8 +228,10 @@ const options = {
</symbol>
</svg>
\`,
byFileExtension: {
ts: 'my-file',
},
remap: {
'file-tree-icon-file': 'my-file',
'file-tree-icon-chevron': { name: 'my-folder', width: 16, height: 16 },
},
},
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/app/trees/docs/CoreTypes/content.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ folder containing `index.ts`, `utils/helpers.ts`, and a `components` folder with
| `lockedPaths` | Optional list of file/folder paths that cannot be dragged when drag and drop is enabled. |
| `onCollision` | Optional callback for drag collisions. Return `true` to overwrite destination. |
| `gitStatus` | Optional `GitStatusEntry[]` used to show Git-style file status (`added`, `modified`, `deleted`). Folders with changed descendants also receive a change indicator. [Live demo](/preview/trees#path-colors). |
| `icons` | Optional `FileTreeIconConfig` to provide a custom SVG sprite sheet and remap built-in icon names to your own symbols. [Live demo](/preview/trees#custom-icons). |
| `icons` | Optional built-in icon set selection or `FileTreeIconConfig` for semantic colors, CSS-themable palettes, and custom sprite overrides. [Live demo](/preview/trees#custom-icons). |
| `sort` | Sort children within each directory. `true` (default) uses the standard sort (folders first, dot-prefixed next, case-insensitive alphabetical). `false` preserves insertion order. `{ comparator: fn }` for custom sorting. |
| `virtualize` | Enable virtualized rendering so only visible items are rendered. Pass `{ threshold: number }` to activate when item count exceeds the threshold, or `false` to disable. Default: `undefined` (off). |

Expand Down
31 changes: 25 additions & 6 deletions apps/docs/app/trees/docs/Icons/content.mdx
Original file line number Diff line number Diff line change
@@ -1,16 +1,35 @@
## Custom Icons
## Icons

Use the `icons` option inside `FileTreeOptions` to swap built-in icons with your
own SVG symbols. Try the live demo at
Use the `icons` option inside `FileTreeOptions` to choose one of the built-in
icon sets or inject your own SVG sprite. Try the live demo at
[/preview/trees#custom-icons](/preview/trees#custom-icons).

- `icons: 'minimal' | 'standard' | 'complete'` — use one of the shipped icon
tiers. Each tier is cumulative: `standard` includes everything in `minimal`
plus language icons, and `complete` adds brands and tooling on top.
- `set` — use the object form to combine a built-in set with `colored`,
`spriteSheet`, or file-specific overrides.
- `colored` — semantic per-file-type colors for built-in `standard` and
`complete` icons. Defaults to `true`; set `colored: false` to disable it.
Override the palette with CSS variables like
`--trees-file-icon-color-javascript`.
- `spriteSheet` — an SVG string containing `<symbol>` definitions. It is
injected into the shadow DOM alongside the default sprite sheet.
injected into the shadow DOM alongside the selected built-in sprite sheet.
- `remap` — a map from a built-in icon name to either a replacement symbol id
(string) or an object with `name`, optional `width`, `height`, and `viewBox`.
- `byFileName` — remap the file icon for exact basenames (for example
`package.json` or `.gitignore`).
- `byFileNameContains` — remap the file icon when a basename contains a pattern
(for example `dockerfile` or `license`).
- `byFileExtension` — remap the file icon by extension (for example `ts`, `tsx`,
`spec.ts`, or `json`).

You can re-map any of the existing, default icons (listed below) by creating new
SVG symbols that use the same IDs.
You can remap any of the existing built-in icon slots (listed below) by creating
new SVG symbols that use the same IDs.

For file rows, icon resolution order is: `byFileName` → `byFileNameContains` →
`byFileExtension` (most specific suffix first) → built-in set mapping →
`remap['file-tree-icon-file']` → fallback file icon.

| Icon ID | Description |
| ------------------------ | ------------------------------------------------------------------- |
Expand Down
20 changes: 4 additions & 16 deletions apps/docs/app/trees/docs/ReactAPI/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,26 +83,14 @@ export const REACT_API_CUSTOM_ICONS_EXAMPLE: PreloadFileOptions<undefined> = {
name: 'custom_icons_file_tree.tsx',
contents: `import { FileTree } from '@pierre/trees/react';

const customSpriteSheet = \`
<svg data-icon-sprite aria-hidden="true" width="0" height="0">
<symbol id="my-file" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2">
<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/>
<path d="M14 2v4a2 2 0 0 0 2 2h4"/>
</symbol>
</svg>
\`;

export function CustomIconsTree() {
export function IconSetTree() {
return (
<FileTree
options={{
id: 'custom-icons-tree',
id: 'icon-set-tree',
icons: {
spriteSheet: customSpriteSheet,
remap: {
'file-tree-icon-file': 'my-file',
},
set: 'standard',
colored: true,
},
}}
initialFiles={[
Expand Down
16 changes: 2 additions & 14 deletions apps/docs/app/trees/docs/VanillaAPI/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,27 +130,15 @@ export const VANILLA_API_CUSTOM_ICONS_EXAMPLE: PreloadFileOptions<undefined> = {
name: 'custom_icons_file_tree.ts',
contents: `import { FileTree } from '@pierre/trees';

const customSpriteSheet = \`
<svg data-icon-sprite aria-hidden="true" width="0" height="0">
<symbol id="my-file" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2">
<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/>
<path d="M14 2v4a2 2 0 0 0 2 2h4"/>
</symbol>
</svg>
\`;

const fileTree = new FileTree({
initialFiles: [
'src/index.ts',
'src/components/Button.tsx',
'package.json',
],
icons: {
spriteSheet: customSpriteSheet,
remap: {
'file-tree-icon-file': 'my-file',
},
set: 'standard',
colored: true,
},
});

Expand Down
Loading
Loading