diff --git a/apps/docs/app/trees-dev/_components/TreesDevSidebar.tsx b/apps/docs/app/trees-dev/_components/TreesDevSidebar.tsx
index 6773e1e9b..e766e2a41 100644
--- a/apps/docs/app/trees-dev/_components/TreesDevSidebar.tsx
+++ b/apps/docs/app/trees-dev/_components/TreesDevSidebar.tsx
@@ -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' },
diff --git a/apps/docs/app/trees-dev/icon-tiers/page.tsx b/apps/docs/app/trees-dev/icon-tiers/page.tsx
new file mode 100644
index 000000000..950b6ffdf
--- /dev/null
+++ b/apps/docs/app/trees-dev/icon-tiers/page.tsx
@@ -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 (
+ <>
+
Icon Tiers
+
+ {TIERS.map(({ set, label }) => (
+
+ ))}
+
+ >
+ );
+}
diff --git a/apps/docs/app/trees/demo-data.ts b/apps/docs/app/trees/demo-data.ts
index 9a49405e7..5447957bd 100644
--- a/apps/docs/app/trees/demo-data.ts
+++ b/apps/docs/app/trees/demo-data.ts
@@ -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',
diff --git a/apps/docs/app/trees/docs/CoreTypes/constants.ts b/apps/docs/app/trees/docs/CoreTypes/constants.ts
index 6f2fee5d2..0f775b3db 100644
--- a/apps/docs/app/trees/docs/CoreTypes/constants.ts
+++ b/apps/docs/app/trees/docs/CoreTypes/constants.ts
@@ -172,7 +172,7 @@ export const FILE_TREE_ICON_CONFIG_TYPE: PreloadFileOptions = {
// or inject your own SVG symbols.
interface FileTreeIconConfig {
// Optional: use one of the built-in sets, or "none" for custom-only rules.
- set?: 'simple' | 'file-type' | 'duo-tone' | 'none';
+ set?: 'minimal' | 'standard' | 'complete' | 'none';
// Optional: enable built-in per-file-type colors. Default: true.
colored?: boolean;
@@ -213,7 +213,7 @@ interface FileTreeIconConfig {
const options = {
initialFiles: ['src/index.ts', 'src/components/Button.tsx'],
icons: {
- set: 'file-type',
+ set: 'standard',
colored: true,
spriteSheet: \`
\`);
}
+const STANDARD_SVG_SPRITE_SHEET = appendSymbols(
+ MINIMAL_SVG_SPRITE_SHEET,
+ standardTierSymbols,
+);
+
const BUILT_IN_SVG_SPRITE_SHEETS: Record = {
- simple: SIMPLE_SVG_SPRITE_SHEET,
- 'file-type': appendSymbols(SIMPLE_SVG_SPRITE_SHEET, fileTypeSetSymbols),
- 'duo-tone': appendSymbols(SIMPLE_SVG_SPRITE_SHEET, duoToneSetSymbols),
+ minimal: MINIMAL_SVG_SPRITE_SHEET,
+ standard: STANDARD_SVG_SPRITE_SHEET,
+ complete: appendSymbols(STANDARD_SVG_SPRITE_SHEET, completeOnlySymbols),
};
const BUILT_IN_FILE_NAME_TOKENS: Partial> =
@@ -276,51 +344,77 @@ const BUILT_IN_FILE_EXTENSION_TOKENS: Partial<
> = {
${formatRecord(extensionTokens, ' ')}
};
-
-const COLORED_ICON_SET_PALETTES = new Set([
- 'file-type',
- 'duo-tone',
+${
+ Object.keys(completeExtOverrides).length > 0
+ ? `
+const COMPLETE_EXTENSION_OVERRIDES: Partial<
+ Record
+> = {
+${formatRecord(completeExtOverrides, ' ')}
+};
+`
+ : `
+const COMPLETE_EXTENSION_OVERRIDES: Partial<
+ Record
+> = {};
+`
+}
+const STANDARD_TIER_TOKENS = new Set([
+${standardTokensList.map((t) => ` '${t}',`).join('\n')}
]);
+const COLORED_SETS = new Set(['complete']);
+
export function getBuiltInSpriteSheet(
- set: FileTreeBuiltInIconSet | 'none'
+ set: FileTreeBuiltInIconSet | 'none',
): string {
- const builtInSet = set === 'none' ? 'simple' : set;
+ const builtInSet = set === 'none' ? 'minimal' : set;
return BUILT_IN_SVG_SPRITE_SHEETS[builtInSet];
}
export function getBuiltInFileIconName(
- set: FileTreeBuiltInIconSet,
- token: BuiltInFileIconToken
+ token: BuiltInFileIconToken,
): string {
- return \`file-tree-builtin-\${set}-\${token}\`;
+ return \`file-tree-builtin-\${token}\`;
}
export function isColoredBuiltInIconSet(
- set: FileTreeBuiltInIconSet | 'none'
+ set: FileTreeBuiltInIconSet | 'none',
): boolean {
- return set !== 'none' && COLORED_ICON_SET_PALETTES.has(set);
+ return set !== 'none' && COLORED_SETS.has(set);
}
export function resolveBuiltInFileIconToken(
set: FileTreeBuiltInIconSet | 'none',
fileName: string,
- extensionCandidates: string[]
+ extensionCandidates: string[],
): BuiltInFileIconToken | undefined {
- if (set === 'simple' || set === 'none') {
+ if (set === 'minimal' || set === 'none') {
return undefined;
}
+ const isComplete = set === 'complete';
+
const lowerFileName = fileName.toLowerCase();
- const exactMatch = BUILT_IN_FILE_NAME_TOKENS[lowerFileName];
- if (exactMatch != null) {
- return exactMatch;
+ const fileNameToken = BUILT_IN_FILE_NAME_TOKENS[lowerFileName];
+ if (fileNameToken != null) {
+ if (isComplete || STANDARD_TIER_TOKENS.has(fileNameToken)) {
+ return fileNameToken;
+ }
}
for (const extension of extensionCandidates) {
+ if (isComplete) {
+ const override = COMPLETE_EXTENSION_OVERRIDES[extension];
+ if (override != null) {
+ return override;
+ }
+ }
const match = BUILT_IN_FILE_EXTENSION_TOKENS[extension];
if (match != null) {
- return match;
+ if (isComplete || STANDARD_TIER_TOKENS.has(match)) {
+ return match;
+ }
}
}
diff --git a/packages/trees/src/builtInIcons.ts b/packages/trees/src/builtInIcons.ts
index 40a8b8422..a0b66efc3 100644
--- a/packages/trees/src/builtInIcons.ts
+++ b/packages/trees/src/builtInIcons.ts
@@ -2,19 +2,59 @@
import type { FileTreeBuiltInIconSet } from './iconConfig';
export type BuiltInFileIconToken =
+ | 'astro'
+ | 'babel'
+ | 'bash'
+ | 'biome'
+ | 'bootstrap'
+ | 'browserslist'
+ | 'bun'
+ | 'claude'
| 'css'
+ | 'database'
| 'default'
+ | 'docker'
+ | 'eslint'
+ | 'font'
| 'git'
+ | 'go'
+ | 'graphql'
+ | 'html'
| 'image'
| 'javascript'
| 'json'
| 'markdown'
| 'mcp'
+ | 'nextjs'
| 'npm'
+ | 'oxc'
+ | 'postcss'
+ | 'prettier'
+ | 'python'
| 'react'
- | 'typescript';
+ | 'ruby'
+ | 'rust'
+ | 'sass'
+ | 'stylelint'
+ | 'svelte'
+ | 'svg'
+ | 'svgo'
+ | 'swift'
+ | 'table'
+ | 'tailwind'
+ | 'terraform'
+ | 'text'
+ | 'typescript'
+ | 'vite'
+ | 'vscode'
+ | 'vue'
+ | 'wasm'
+ | 'webpack'
+ | 'yml'
+ | 'zig'
+ | 'zip';
-const SIMPLE_SVG_SPRITE_SHEET = `
+const MINIMAL_SVG_SPRITE_SHEET = `
@@ -22,7 +62,8 @@ const SIMPLE_SVG_SPRITE_SHEET = `
-
+
+
@@ -32,124 +73,309 @@ const SIMPLE_SVG_SPRITE_SHEET = `
`;
-const ft_css = `
-
+const sym_astro = `
+
+
`;
-const dt_css = `
-
-
+
+const sym_babel = `
+
+`;
+
+const sym_bash = `
+
+
+`;
+
+const sym_biome = `
+
+`;
+
+const sym_bootstrap = `
+
+
+`;
+
+const sym_browserslist = `
+
+
+
+`;
+
+const sym_bun = `
+
+
+`;
+
+const sym_claude = `
+
`;
-const ft_default = `
-
+const sym_css = `
+
+
`;
-const dt_default = `
-
+
+const sym_database = `
+
+
+
+`;
+
+const sym_default = `
+
`;
-const ft_git = `
-
+const sym_docker = `
+
+
+`;
+
+const sym_eslint = `
+
+
`;
-const dt_git = ft_git.replaceAll(
- 'file-tree-builtin-file-type-git',
- 'file-tree-builtin-duo-tone-git'
-);
-const ft_image = `
-
-
+const sym_font = `
+
`;
-const dt_image = `
-
-
+
+const sym_git = `
+
`;
-const ft_javascript = `
-
+const sym_go = `
+
`;
-const dt_javascript = `
-
-
+
+const sym_graphql = `
+
`;
-const ft_json = `
-
+const sym_html = `
+
+
+`;
+
+const sym_image = `
+
+
+`;
+
+const sym_javascript = `
+
+
+`;
+
+const sym_json = `
+
`;
-const dt_json = ft_json.replaceAll(
- 'file-tree-builtin-file-type-json',
- 'file-tree-builtin-duo-tone-json'
-);
-const ft_markdown = `
+const sym_markdown = `
`;
-const dt_markdown = ft_markdown.replaceAll(
- 'file-tree-builtin-file-type-markdown',
- 'file-tree-builtin-duo-tone-markdown'
-);
-const ft_mcp = `
-
-
+const sym_mcp = `
+
+
`;
-const dt_mcp = ft_mcp.replaceAll(
- 'file-tree-builtin-file-type-mcp',
- 'file-tree-builtin-duo-tone-mcp'
-);
-const ft_npm = `
-
+const sym_nextjs = `
+
+
+
+
+
+
+
+
+
`;
-const dt_npm = ft_npm.replaceAll(
- 'file-tree-builtin-file-type-npm',
- 'file-tree-builtin-duo-tone-npm'
-);
-const ft_react = `
-
-
+const sym_npm = `
+
+
+`;
+
+const sym_oxc = `
+
+`;
+
+const sym_postcss = `
+
+`;
+
+const sym_prettier = `
+
+
+
+
+`;
+
+const sym_python = `
+
+
+`;
+
+const sym_react = `
+
+
+`;
+
+const sym_ruby = `
+
+`;
+
+const sym_rust = `
+
+`;
+
+const sym_sass = `
+
+`;
+
+const sym_stylelint = `
+
+
`;
-const dt_react = ft_react.replaceAll(
- 'file-tree-builtin-file-type-react',
- 'file-tree-builtin-duo-tone-react'
-);
-const ft_typescript = `
-
-
-`;
-const dt_typescript = `
-
-
-`;
-
-const fileTypeSetSymbols = [
- ft_css,
- ft_default,
- ft_git,
- ft_image,
- ft_javascript,
- ft_json,
- ft_markdown,
- ft_mcp,
- ft_npm,
- ft_react,
- ft_typescript,
+const sym_svelte = `
+
+`;
+
+const sym_svg = `
+
+
+`;
+
+const sym_svgo = `
+
+
+`;
+
+const sym_swift = `
+
+`;
+
+const sym_table = `
+
+
+`;
+
+const sym_tailwind = `
+
+`;
+
+const sym_terraform = `
+
+`;
+
+const sym_text = `
+
+
+`;
+
+const sym_typescript = `
+
+
+`;
+
+const sym_vite = `
+
+`;
+
+const sym_vscode = `
+
+
+
+`;
+
+const sym_vue = `
+
+
+`;
+
+const sym_wasm = `
+
+
+
+`;
+
+const sym_webpack = `
+
+
+`;
+
+const sym_yml = `
+
+`;
+
+const sym_zig = `
+
+
+`;
+
+const sym_zip = `
+
+
+`;
+
+const standardTierSymbols = [
+ sym_bash,
+ sym_css,
+ sym_database,
+ sym_default,
+ sym_font,
+ sym_git,
+ sym_go,
+ sym_html,
+ sym_image,
+ sym_javascript,
+ sym_json,
+ sym_markdown,
+ sym_mcp,
+ sym_python,
+ sym_ruby,
+ sym_rust,
+ sym_swift,
+ sym_table,
+ sym_text,
+ sym_typescript,
+ sym_zip,
];
-const duoToneSetSymbols = [
- dt_css,
- dt_default,
- dt_git,
- dt_image,
- dt_javascript,
- dt_json,
- dt_markdown,
- dt_mcp,
- dt_npm,
- dt_react,
- dt_typescript,
+const completeOnlySymbols = [
+ sym_astro,
+ sym_babel,
+ sym_biome,
+ sym_bootstrap,
+ sym_browserslist,
+ sym_bun,
+ sym_claude,
+ sym_docker,
+ sym_eslint,
+ sym_graphql,
+ sym_nextjs,
+ sym_npm,
+ sym_oxc,
+ sym_postcss,
+ sym_prettier,
+ sym_react,
+ sym_sass,
+ sym_stylelint,
+ sym_svelte,
+ sym_svg,
+ sym_svgo,
+ sym_tailwind,
+ sym_terraform,
+ sym_vite,
+ sym_vscode,
+ sym_vue,
+ sym_wasm,
+ sym_webpack,
+ sym_yml,
+ sym_zig,
];
function appendSymbols(spriteSheet: string, symbols: string[]): string {
@@ -157,36 +383,166 @@ function appendSymbols(spriteSheet: string, symbols: string[]): string {
return spriteSheet.replace('', `\n ${symbols.join('\n ')}\n`);
}
+const STANDARD_SVG_SPRITE_SHEET = appendSymbols(
+ MINIMAL_SVG_SPRITE_SHEET,
+ standardTierSymbols
+);
+
const BUILT_IN_SVG_SPRITE_SHEETS: Record = {
- simple: SIMPLE_SVG_SPRITE_SHEET,
- 'file-type': appendSymbols(SIMPLE_SVG_SPRITE_SHEET, fileTypeSetSymbols),
- 'duo-tone': appendSymbols(SIMPLE_SVG_SPRITE_SHEET, duoToneSetSymbols),
+ minimal: MINIMAL_SVG_SPRITE_SHEET,
+ standard: STANDARD_SVG_SPRITE_SHEET,
+ complete: appendSymbols(STANDARD_SVG_SPRITE_SHEET, completeOnlySymbols),
};
const BUILT_IN_FILE_NAME_TOKENS: Partial> =
{
+ '.babelrc': 'babel',
+ '.babelrc.json': 'babel',
+ '.bash_profile': 'bash',
+ '.bashrc': 'bash',
+ '.browserslistrc': 'browserslist',
+ '.dockerignore': 'docker',
+ '.eslintignore': 'eslint',
+ '.eslintrc': 'eslint',
+ '.eslintrc.cjs': 'eslint',
+ '.eslintrc.js': 'eslint',
+ '.eslintrc.json': 'eslint',
+ '.eslintrc.yaml': 'eslint',
+ '.eslintrc.yml': 'eslint',
'.gitattributes': 'git',
'.gitignore': 'git',
'.gitkeep': 'git',
'.gitmodules': 'git',
- '.npmignore': 'npm',
- '.npmrc': 'npm',
- 'package-lock.json': 'npm',
- 'package.json': 'npm',
+ '.oxlintrc.json': 'oxc',
+ '.postcssrc': 'postcss',
+ '.postcssrc.json': 'postcss',
+ '.postcssrc.yaml': 'postcss',
+ '.postcssrc.yml': 'postcss',
+ '.prettierignore': 'prettier',
+ '.prettierrc': 'prettier',
+ '.prettierrc.cjs': 'prettier',
+ '.prettierrc.js': 'prettier',
+ '.prettierrc.json': 'prettier',
+ '.prettierrc.mjs': 'prettier',
+ '.prettierrc.toml': 'prettier',
+ '.prettierrc.yaml': 'prettier',
+ '.prettierrc.yml': 'prettier',
+ '.stylelintignore': 'stylelint',
+ '.stylelintrc': 'stylelint',
+ '.stylelintrc.cjs': 'stylelint',
+ '.stylelintrc.js': 'stylelint',
+ '.stylelintrc.json': 'stylelint',
+ '.stylelintrc.mjs': 'stylelint',
+ '.stylelintrc.yaml': 'stylelint',
+ '.stylelintrc.yml': 'stylelint',
+ '.terraform.lock.hcl': 'terraform',
+ '.zprofile': 'bash',
+ '.zshenv': 'bash',
+ '.zshrc': 'bash',
+ 'babel.config.cjs': 'babel',
+ 'babel.config.js': 'babel',
+ 'babel.config.json': 'babel',
+ 'babel.config.mjs': 'babel',
+ 'biome.json': 'biome',
+ 'biome.jsonc': 'biome',
+ 'bootstrap.bundle.js': 'bootstrap',
+ 'bootstrap.bundle.min.js': 'bootstrap',
+ 'bootstrap.css': 'bootstrap',
+ 'bootstrap.js': 'bootstrap',
+ 'bootstrap.min.css': 'bootstrap',
+ 'bootstrap.min.js': 'bootstrap',
+ 'bun.lock': 'bun',
+ 'bun.lockb': 'bun',
+ 'bunfig.toml': 'bun',
+ 'claude.md': 'claude',
+ 'compose.yaml': 'docker',
+ 'compose.yml': 'docker',
+ 'docker-compose.override.yml': 'docker',
+ 'docker-compose.yaml': 'docker',
+ 'docker-compose.yml': 'docker',
+ dockerfile: 'docker',
+ 'eslint.config.cjs': 'eslint',
+ 'eslint.config.js': 'eslint',
+ 'eslint.config.mjs': 'eslint',
+ 'eslint.config.mts': 'eslint',
+ 'eslint.config.ts': 'eslint',
+ gemfile: 'ruby',
+ 'next.config.js': 'nextjs',
+ 'next.config.mjs': 'nextjs',
+ 'next.config.mts': 'nextjs',
+ 'next.config.ts': 'nextjs',
+ 'postcss.config.cjs': 'postcss',
+ 'postcss.config.js': 'postcss',
+ 'postcss.config.mjs': 'postcss',
+ 'postcss.config.ts': 'postcss',
+ 'prettier.config.cjs': 'prettier',
+ 'prettier.config.js': 'prettier',
+ 'prettier.config.mjs': 'prettier',
+ rakefile: 'ruby',
'readme.md': 'markdown',
+ 'stylelint.config.cjs': 'stylelint',
+ 'stylelint.config.js': 'stylelint',
+ 'stylelint.config.mjs': 'stylelint',
+ 'svgo.config.cjs': 'svgo',
+ 'svgo.config.js': 'svgo',
+ 'svgo.config.mjs': 'svgo',
+ 'svgo.config.ts': 'svgo',
+ 'tailwind.config.cjs': 'tailwind',
+ 'tailwind.config.js': 'tailwind',
+ 'tailwind.config.mjs': 'tailwind',
+ 'tailwind.config.ts': 'tailwind',
+ 'vite.config.js': 'vite',
+ 'vite.config.mjs': 'vite',
+ 'vite.config.mts': 'vite',
+ 'vite.config.ts': 'vite',
+ 'webpack.config.babel.js': 'webpack',
+ 'webpack.config.cjs': 'webpack',
+ 'webpack.config.js': 'webpack',
+ 'webpack.config.mjs': 'webpack',
+ 'webpack.config.ts': 'webpack',
};
const BUILT_IN_FILE_EXTENSION_TOKENS: Partial<
Record
> = {
+ '7z': 'zip',
+ astro: 'astro',
+ AUTHORS: 'text',
avif: 'image',
+ bash: 'bash',
bmp: 'image',
+ bz2: 'zip',
+ cfg: 'text',
+ CHANGELOG: 'text',
cjs: 'javascript',
+ 'code-workspace': 'vscode',
+ conf: 'text',
+ CONTRIBUTORS: 'text',
+ csh: 'bash',
css: 'css',
+ csv: 'table',
cts: 'typescript',
+ db: 'database',
+ editorconfig: 'text',
+ env: 'text',
+ 'env.development': 'text',
+ 'env.local': 'text',
+ 'env.production': 'text',
+ eot: 'font',
+ erb: 'ruby',
+ fish: 'bash',
+ gemspec: 'ruby',
gif: 'image',
+ go: 'go',
+ gql: 'graphql',
+ graphql: 'graphql',
+ gz: 'zip',
+ htm: 'html',
+ html: 'html',
icns: 'image',
ico: 'image',
+ ini: 'text',
+ jar: 'zip',
jpeg: 'image',
jpg: 'image',
js: 'javascript',
@@ -194,8 +550,11 @@ const BUILT_IN_FILE_EXTENSION_TOKENS: Partial<
json5: 'json',
jsonc: 'json',
jsonl: 'json',
- jsx: 'react',
+ jsx: 'javascript',
+ ksh: 'bash',
less: 'css',
+ LICENSE: 'text',
+ log: 'text',
markdown: 'markdown',
mcp: 'mcp',
md: 'markdown',
@@ -203,42 +562,111 @@ const BUILT_IN_FILE_EXTENSION_TOKENS: Partial<
'mdx.tsx': 'markdown',
mjs: 'javascript',
mts: 'typescript',
+ ods: 'table',
+ otf: 'font',
png: 'image',
postcss: 'css',
+ py: 'python',
+ pyi: 'python',
+ pyw: 'python',
+ pyx: 'python',
+ rake: 'ruby',
+ rar: 'zip',
+ rb: 'ruby',
+ rs: 'rust',
+ rst: 'text',
+ rtf: 'text',
sass: 'css',
scss: 'css',
+ sh: 'bash',
+ sql: 'database',
+ sqlite: 'database',
+ sqlite3: 'database',
styl: 'css',
- svg: 'image',
+ svelte: 'svelte',
+ svg: 'svg',
+ swift: 'swift',
+ tar: 'zip',
+ tf: 'terraform',
+ tfstate: 'terraform',
+ tfvars: 'terraform',
+ tgz: 'zip',
tif: 'image',
tiff: 'image',
ts: 'typescript',
- tsx: 'react',
+ tsv: 'table',
+ tsx: 'typescript',
+ ttf: 'font',
+ txt: 'text',
+ vue: 'vue',
+ war: 'zip',
+ wasm: 'wasm',
+ wast: 'wasm',
+ wat: 'wasm',
webp: 'image',
+ woff: 'font',
+ woff2: 'font',
+ xhtml: 'html',
+ xls: 'table',
+ xlsx: 'table',
+ xz: 'zip',
+ yaml: 'yml',
+ yml: 'yml',
+ zig: 'zig',
+ zip: 'zip',
+ zsh: 'bash',
+};
+
+const COMPLETE_EXTENSION_OVERRIDES: Partial<
+ Record
+> = {
+ jsx: 'react',
+ sass: 'sass',
+ scss: 'sass',
+ tsx: 'react',
};
-const COLORED_ICON_SET_PALETTES = new Set([
- 'file-type',
- 'duo-tone',
+const STANDARD_TIER_TOKENS = new Set([
+ 'bash',
+ 'css',
+ 'database',
+ 'default',
+ 'font',
+ 'git',
+ 'go',
+ 'html',
+ 'image',
+ 'javascript',
+ 'json',
+ 'markdown',
+ 'mcp',
+ 'python',
+ 'ruby',
+ 'rust',
+ 'swift',
+ 'table',
+ 'text',
+ 'typescript',
+ 'zip',
]);
+const COLORED_SETS = new Set(['complete']);
+
export function getBuiltInSpriteSheet(
set: FileTreeBuiltInIconSet | 'none'
): string {
- const builtInSet = set === 'none' ? 'simple' : set;
+ const builtInSet = set === 'none' ? 'minimal' : set;
return BUILT_IN_SVG_SPRITE_SHEETS[builtInSet];
}
-export function getBuiltInFileIconName(
- set: FileTreeBuiltInIconSet,
- token: BuiltInFileIconToken
-): string {
- return `file-tree-builtin-${set}-${token}`;
+export function getBuiltInFileIconName(token: BuiltInFileIconToken): string {
+ return `file-tree-builtin-${token}`;
}
export function isColoredBuiltInIconSet(
set: FileTreeBuiltInIconSet | 'none'
): boolean {
- return set !== 'none' && COLORED_ICON_SET_PALETTES.has(set);
+ return set !== 'none' && COLORED_SETS.has(set);
}
export function resolveBuiltInFileIconToken(
@@ -246,20 +674,32 @@ export function resolveBuiltInFileIconToken(
fileName: string,
extensionCandidates: string[]
): BuiltInFileIconToken | undefined {
- if (set === 'simple' || set === 'none') {
+ if (set === 'minimal' || set === 'none') {
return undefined;
}
+ const isComplete = set === 'complete';
+
const lowerFileName = fileName.toLowerCase();
- const exactMatch = BUILT_IN_FILE_NAME_TOKENS[lowerFileName];
- if (exactMatch != null) {
- return exactMatch;
+ const fileNameToken = BUILT_IN_FILE_NAME_TOKENS[lowerFileName];
+ if (fileNameToken != null) {
+ if (isComplete || STANDARD_TIER_TOKENS.has(fileNameToken)) {
+ return fileNameToken;
+ }
}
for (const extension of extensionCandidates) {
+ if (isComplete) {
+ const override = COMPLETE_EXTENSION_OVERRIDES[extension];
+ if (override != null) {
+ return override;
+ }
+ }
const match = BUILT_IN_FILE_EXTENSION_TOKENS[extension];
if (match != null) {
- return match;
+ if (isComplete || STANDARD_TIER_TOKENS.has(match)) {
+ return match;
+ }
}
}
diff --git a/packages/trees/src/components/Icon.tsx b/packages/trees/src/components/Icon.tsx
index d756c57c3..d6e3be56b 100644
--- a/packages/trees/src/components/Icon.tsx
+++ b/packages/trees/src/components/Icon.tsx
@@ -7,23 +7,7 @@ const DEFAULT_HEIGHT = 16;
const ICON_SIZE_OVERRIDES: Record<
string,
{ width: number; height: number; viewBox?: string } | undefined
-> = {
- 'file-tree-icon-chevron': {
- width: 12,
- height: 12,
- viewBox: '0 0 16 16',
- },
- 'file-tree-icon-file': {
- width: 12,
- height: 12,
- viewBox: '0 0 16 16',
- },
- 'file-tree-icon-lock': {
- width: 12,
- height: 12,
- viewBox: '0 0 16 16',
- },
-};
+> = {};
export function Icon({
name,
diff --git a/packages/trees/src/components/Root.tsx b/packages/trees/src/components/Root.tsx
index 6510b1cf4..57353b06d 100644
--- a/packages/trees/src/components/Root.tsx
+++ b/packages/trees/src/components/Root.tsx
@@ -229,7 +229,7 @@ export function Root({
);
if (builtInToken != null && normalizedIcons.set !== 'none') {
return {
- name: getBuiltInFileIconName(normalizedIcons.set, builtInToken),
+ name: getBuiltInFileIconName(builtInToken),
remappedFrom: name,
token: builtInToken,
};
diff --git a/packages/trees/src/iconConfig.ts b/packages/trees/src/iconConfig.ts
index aa2f64d17..bf65a7864 100644
--- a/packages/trees/src/iconConfig.ts
+++ b/packages/trees/src/iconConfig.ts
@@ -7,7 +7,7 @@ export type RemappedIcon =
viewBox?: string;
};
-export type FileTreeBuiltInIconSet = 'simple' | 'file-type' | 'duo-tone';
+export type FileTreeBuiltInIconSet = 'minimal' | 'standard' | 'complete';
export interface FileTreeIconConfig {
/** Use one of the built-in icon sets, or `none` for custom-only icon rules. */
@@ -48,7 +48,7 @@ export function normalizeFileTreeIcons(
): NormalizedFileTreeIconConfig {
if (icons == null) {
return {
- set: 'simple',
+ set: 'complete',
colored: true,
};
}
@@ -62,7 +62,7 @@ export function normalizeFileTreeIcons(
return {
...icons,
- set: icons.set ?? (hasCustomIconOverrides(icons) ? 'none' : 'simple'),
+ set: icons.set ?? (hasCustomIconOverrides(icons) ? 'none' : 'complete'),
colored: icons.colored ?? true,
};
}
diff --git a/packages/trees/src/style.css b/packages/trees/src/style.css
index a0a10eb0e..336dfd805 100644
--- a/packages/trees/src/style.css
+++ b/packages/trees/src/style.css
@@ -45,17 +45,54 @@
// Built-in File Icon Color Overrides
--trees-file-icon-color
+ --trees-file-icon-color-astro
+ --trees-file-icon-color-babel
+ --trees-file-icon-color-bash
+ --trees-file-icon-color-biome
+ --trees-file-icon-color-bootstrap
+ --trees-file-icon-color-browserslist
+ --trees-file-icon-color-bun
+ --trees-file-icon-color-claude
--trees-file-icon-color-css
+ --trees-file-icon-color-database
--trees-file-icon-color-default
+ --trees-file-icon-color-docker
+ --trees-file-icon-color-eslint
--trees-file-icon-color-git
+ --trees-file-icon-color-go
+ --trees-file-icon-color-graphql
+ --trees-file-icon-color-html
--trees-file-icon-color-image
--trees-file-icon-color-javascript
--trees-file-icon-color-json
--trees-file-icon-color-markdown
--trees-file-icon-color-mcp
--trees-file-icon-color-npm
+ --trees-file-icon-color-oxc
+ --trees-file-icon-color-postcss
+ --trees-file-icon-color-prettier
+ --trees-file-icon-color-python
--trees-file-icon-color-react
+ --trees-file-icon-color-ruby
+ --trees-file-icon-color-rust
+ --trees-file-icon-color-sass
+ --trees-file-icon-color-svg
+ --trees-file-icon-color-svelte
+ --trees-file-icon-color-svgo
+ --trees-file-icon-color-swift
+ --trees-file-icon-color-table
+ --trees-file-icon-color-text
+ --trees-file-icon-color-tailwind
+ --trees-file-icon-color-terraform
--trees-file-icon-color-typescript
+ --trees-file-icon-color-vite
+ --trees-file-icon-color-vscode
+ --trees-file-icon-color-vue
+ --trees-file-icon-color-wasm
+ --trees-file-icon-color-webpack
+ --trees-file-icon-color-yml
+ --trees-file-icon-color-zig
+ --trees-file-icon-color-zip
// Available CSS Layout Overrides
--trees-gap-override
@@ -206,6 +243,7 @@
--trees-icon-gray: light-dark(#84848a, #adadb1);
--trees-icon-red: light-dark(#d52c36, #ff6762);
+ --trees-icon-vermilion: light-dark(#ff8c5b, #d5512f);
--trees-icon-orange: light-dark(#d47628, #ffa359);
--trees-icon-yellow: light-dark(#d5a910, #ffd452);
--trees-icon-green: light-dark(#199f43, #5ecc71);
@@ -213,17 +251,74 @@
--trees-icon-cyan: light-dark(#1ca1c7, #68cdf2);
--trees-icon-blue: light-dark(#1a85d4, #69b1ff);
--trees-icon-indigo: light-dark(#693acf, #9d6afb);
+ --trees-icon-purple: light-dark(#a631be, #d568ea);
--trees-icon-pink: light-dark(#d32a61, #ff678d);
--trees-file-icon-color-default: var(
--trees-file-icon-color,
var(--trees-icon-gray)
);
+ --trees-file-icon-color-astro: var(
+ --trees-file-icon-color,
+ var(--trees-icon-purple)
+ );
+ --trees-file-icon-color-babel: var(
+ --trees-file-icon-color,
+ var(--trees-icon-yellow)
+ );
+ --trees-file-icon-color-bash: var(
+ --trees-file-icon-color,
+ var(--trees-icon-green)
+ );
+ --trees-file-icon-color-biome: var(
+ --trees-file-icon-color,
+ var(--trees-icon-blue)
+ );
+ --trees-file-icon-color-bootstrap: var(
+ --trees-file-icon-color,
+ var(--trees-icon-indigo)
+ );
+ --trees-file-icon-color-browserslist: var(
+ --trees-file-icon-color,
+ var(--trees-icon-yellow)
+ );
+ --trees-file-icon-color-bun: var(
+ --trees-file-icon-color,
+ var(--trees-icon-pink)
+ );
+ --trees-file-icon-color-claude: var(
+ --trees-file-icon-color,
+ var(--trees-icon-orange)
+ );
--trees-file-icon-color-css: var(
--trees-file-icon-color,
var(--trees-icon-indigo)
);
+ --trees-file-icon-color-database: var(
+ --trees-file-icon-color,
+ var(--trees-icon-purple)
+ );
+ --trees-file-icon-color-docker: var(
+ --trees-file-icon-color,
+ var(--trees-icon-blue)
+ );
+ --trees-file-icon-color-eslint: var(
+ --trees-file-icon-color,
+ var(--trees-icon-indigo)
+ );
--trees-file-icon-color-git: var(
+ --trees-file-icon-vermilion,
+ var(--trees-icon-vermilion)
+ );
+ --trees-file-icon-color-go: var(
+ --trees-file-icon-color,
+ var(--trees-icon-cyan)
+ );
+ --trees-file-icon-color-graphql: var(
+ --trees-file-icon-color,
+ var(--trees-icon-pink)
+ );
+ --trees-file-icon-color-html: var(
--trees-file-icon-color,
var(--trees-icon-orange)
);
@@ -251,14 +346,106 @@
--trees-file-icon-color,
var(--trees-icon-red)
);
+ --trees-file-icon-color-oxc: var(
+ --trees-file-icon-cyan,
+ var(--trees-icon-cyan)
+ );
+ --trees-file-icon-color-postcss: var(
+ --trees-file-icon-color,
+ var(--trees-icon-red)
+ );
+ --trees-file-icon-color-prettier: var(
+ --trees-file-icon-color,
+ var(--trees-icon-teal)
+ );
+ --trees-file-icon-color-python: var(
+ --trees-file-icon-color,
+ var(--trees-icon-blue)
+ );
--trees-file-icon-color-react: var(
--trees-file-icon-color,
var(--trees-icon-cyan)
);
+ --trees-file-icon-color-ruby: var(
+ --trees-file-icon-color,
+ var(--trees-icon-red)
+ );
+ --trees-file-icon-color-rust: var(
+ --trees-file-icon-color,
+ var(--trees-icon-orange)
+ );
+ --trees-file-icon-color-sass: var(
+ --trees-file-icon-color,
+ var(--trees-icon-pink)
+ );
+ --trees-file-icon-color-svg: var(
+ --trees-file-icon-color,
+ var(--trees-icon-orange)
+ );
+ --trees-file-icon-color-svelte: var(
+ --trees-file-icon-color,
+ var(--trees-icon-red)
+ );
+ --trees-file-icon-color-svgo: var(
+ --trees-file-icon-color,
+ var(--trees-icon-green)
+ );
+ --trees-file-icon-color-swift: var(
+ --trees-file-icon-color,
+ var(--trees-icon-orange)
+ );
+ --trees-file-icon-color-table: var(
+ --trees-file-icon-color,
+ var(--trees-icon-teal)
+ );
+ --trees-file-icon-color-text: var(
+ --trees-file-icon-color,
+ var(--trees-icon-gray)
+ );
+ --trees-file-icon-color-tailwind: var(
+ --trees-file-icon-color,
+ var(--trees-icon-cyan)
+ );
+ --trees-file-icon-color-terraform: var(
+ --trees-file-icon-color,
+ var(--trees-icon-indigo)
+ );
--trees-file-icon-color-typescript: var(
--trees-file-icon-color,
var(--trees-icon-blue)
);
+ --trees-file-icon-color-vite: var(
+ --trees-file-icon-color,
+ var(--trees-icon-purple)
+ );
+ --trees-file-icon-color-vscode: var(
+ --trees-file-icon-color,
+ var(--trees-icon-blue)
+ );
+ --trees-file-icon-color-vue: var(
+ --trees-file-icon-color,
+ var(--trees-icon-green)
+ );
+ --trees-file-icon-color-wasm: var(
+ --trees-file-icon-color,
+ var(--trees-icon-indigo)
+ );
+ --trees-file-icon-color-webpack: var(
+ --trees-file-icon-color,
+ var(--trees-icon-blue)
+ );
+ --trees-file-icon-color-yml: var(
+ --trees-file-icon-color,
+ var(--trees-icon-red)
+ );
+ --trees-file-icon-color-zig: var(
+ --trees-file-icon-color,
+ var(--trees-icon-orange)
+ );
+ --trees-file-icon-color-zip: var(
+ --trees-file-icon-color,
+ var(--trees-icon-orange)
+ );
--trees-level-gap: var(--trees-level-gap-override, 8px);
--trees-item-padding-x: var(--trees-item-padding-x-override, 8px);
@@ -454,15 +641,57 @@
}
[data-file-tree-colored-icons='true'] {
+ [data-icon-token='astro'] {
+ color: var(--trees-file-icon-color-astro);
+ }
+ [data-icon-token='babel'] {
+ color: var(--trees-file-icon-color-babel);
+ }
+ [data-icon-token='bash'] {
+ color: var(--trees-file-icon-color-bash);
+ }
+ [data-icon-token='biome'] {
+ color: var(--trees-file-icon-color-biome);
+ }
+ [data-icon-token='bootstrap'] {
+ color: var(--trees-file-icon-color-bootstrap);
+ }
+ [data-icon-token='browserslist'] {
+ color: var(--trees-file-icon-color-browserslist);
+ }
+ [data-icon-token='bun'] {
+ color: var(--trees-file-icon-color-bun);
+ }
+ [data-icon-token='claude'] {
+ color: var(--trees-file-icon-color-claude);
+ }
[data-icon-token='css'] {
color: var(--trees-file-icon-color-css);
}
+ [data-icon-token='database'] {
+ color: var(--trees-file-icon-color-database);
+ }
[data-icon-token='default'] {
color: var(--trees-file-icon-color-default);
}
+ [data-icon-token='docker'] {
+ color: var(--trees-file-icon-color-docker);
+ }
+ [data-icon-token='eslint'] {
+ color: var(--trees-file-icon-color-eslint);
+ }
[data-icon-token='git'] {
color: var(--trees-file-icon-color-git);
}
+ [data-icon-token='go'] {
+ color: var(--trees-file-icon-color-go);
+ }
+ [data-icon-token='graphql'] {
+ color: var(--trees-file-icon-color-graphql);
+ }
+ [data-icon-token='html'] {
+ color: var(--trees-file-icon-color-html);
+ }
[data-icon-token='image'] {
color: var(--trees-file-icon-color-image);
}
@@ -481,12 +710,81 @@
[data-icon-token='npm'] {
color: var(--trees-file-icon-color-npm);
}
+ [data-icon-token='oxc'] {
+ color: var(--trees-file-icon-color-oxc);
+ }
+ [data-icon-token='postcss'] {
+ color: var(--trees-file-icon-color-postcss);
+ }
+ [data-icon-token='prettier'] {
+ color: var(--trees-file-icon-color-prettier);
+ }
+ [data-icon-token='python'] {
+ color: var(--trees-file-icon-color-python);
+ }
[data-icon-token='react'] {
color: var(--trees-file-icon-color-react);
}
+ [data-icon-token='ruby'] {
+ color: var(--trees-file-icon-color-ruby);
+ }
+ [data-icon-token='rust'] {
+ color: var(--trees-file-icon-color-rust);
+ }
+ [data-icon-token='sass'] {
+ color: var(--trees-file-icon-color-sass);
+ }
+ [data-icon-token='svg'] {
+ color: var(--trees-file-icon-color-svg);
+ }
+ [data-icon-token='svelte'] {
+ color: var(--trees-file-icon-color-svelte);
+ }
+ [data-icon-token='svgo'] {
+ color: var(--trees-file-icon-color-svgo);
+ }
+ [data-icon-token='swift'] {
+ color: var(--trees-file-icon-color-swift);
+ }
+ [data-icon-token='table'] {
+ color: var(--trees-file-icon-color-table);
+ }
+ [data-icon-token='text'] {
+ color: var(--trees-file-icon-color-text);
+ }
+ [data-icon-token='tailwind'] {
+ color: var(--trees-file-icon-color-tailwind);
+ }
+ [data-icon-token='terraform'] {
+ color: var(--trees-file-icon-color-terraform);
+ }
[data-icon-token='typescript'] {
color: var(--trees-file-icon-color-typescript);
}
+ [data-icon-token='vite'] {
+ color: var(--trees-file-icon-color-vite);
+ }
+ [data-icon-token='vscode'] {
+ color: var(--trees-file-icon-color-vscode);
+ }
+ [data-icon-token='vue'] {
+ color: var(--trees-file-icon-color-vue);
+ }
+ [data-icon-token='wasm'] {
+ color: var(--trees-file-icon-color-wasm);
+ }
+ [data-icon-token='webpack'] {
+ color: var(--trees-file-icon-color-webpack);
+ }
+ [data-icon-token='yml'] {
+ color: var(--trees-file-icon-color-yml);
+ }
+ [data-icon-token='zig'] {
+ color: var(--trees-file-icon-color-zig);
+ }
+ [data-icon-token='zip'] {
+ color: var(--trees-file-icon-color-zip);
+ }
}
/* Chevron rotation and visual alignment */
@@ -625,8 +923,8 @@
[data-item-git-status='added'] {
&
- > [data-item-section='icon']
- > :not([data-icon-name='file-tree-icon-chevron']) {
+ > :where([data-item-section='icon'])
+ > :where(:not([data-icon-name='file-tree-icon-chevron'])) {
color: var(--trees-git-added-color);
}
& > [data-item-section='content'] {
@@ -639,8 +937,8 @@
[data-item-git-status='deleted'] {
&
- > [data-item-section='icon']
- > :not([data-icon-name='file-tree-icon-chevron']) {
+ > :where([data-item-section='icon'])
+ > :where(:not([data-icon-name='file-tree-icon-chevron'])) {
color: var(--trees-git-deleted-color);
}
& > [data-item-section='content'] {
@@ -653,8 +951,8 @@
[data-item-git-status='modified'] {
&
- > [data-item-section='icon']
- > :not([data-icon-name='file-tree-icon-chevron']) {
+ > :where([data-item-section='icon'])
+ > :where(:not([data-icon-name='file-tree-icon-chevron'])) {
color: var(--trees-git-modified-color);
}
& > [data-item-section='content'] {
diff --git a/packages/trees/test/ssr-declarative-shadow-dom.test.ts b/packages/trees/test/ssr-declarative-shadow-dom.test.ts
index 542267bc2..dfef00bc7 100644
--- a/packages/trees/test/ssr-declarative-shadow-dom.test.ts
+++ b/packages/trees/test/ssr-declarative-shadow-dom.test.ts
@@ -551,7 +551,7 @@ describe('SSR + declarative shadow DOM', () => {
expect(getIconHref('README.md')).toBe('#custom-default');
});
- test('preloadFileTree uses the simple icon set when icons are unset', () => {
+ test('preloadFileTree uses the complete icon set when icons are unset', () => {
const payload = preloadFileTree({
initialFiles: [
'package.json',
@@ -594,19 +594,19 @@ describe('SSR + declarative shadow DOM', () => {
return href;
};
- expect(getIconHref('package.json')).toBe('#file-tree-icon-file');
- expect(getIconHref('index.ts')).toBe('#file-tree-icon-file');
- expect(getIconHref('app.tsx')).toBe('#file-tree-icon-file');
- expect(getIconHref('card.module.css')).toBe('#file-tree-icon-file');
- expect(getIconHref('README.md')).toBe('#file-tree-icon-file');
- expect(getIconHref('image.png')).toBe('#file-tree-icon-file');
- expect(getIconHref('agent.mcp')).toBe('#file-tree-icon-file');
+ expect(getIconHref('package.json')).toBe('#file-tree-builtin-json');
+ expect(getIconHref('index.ts')).toBe('#file-tree-builtin-typescript');
+ expect(getIconHref('app.tsx')).toBe('#file-tree-builtin-react');
+ expect(getIconHref('card.module.css')).toBe('#file-tree-builtin-css');
+ expect(getIconHref('README.md')).toBe('#file-tree-builtin-markdown');
+ expect(getIconHref('image.png')).toBe('#file-tree-builtin-image');
+ expect(getIconHref('agent.mcp')).toBe('#file-tree-builtin-mcp');
});
- test('preloadFileTree uses the simple icon set when requested', () => {
+ test('preloadFileTree uses the minimal icon set when requested', () => {
const payload = preloadFileTree({
initialFiles: ['package.json', 'index.ts', 'app.tsx'],
- icons: 'simple',
+ icons: 'minimal',
});
const container = document.createElement('file-tree-container');
@@ -633,7 +633,7 @@ describe('SSR + declarative shadow DOM', () => {
]);
});
- test('preloadFileTree uses the file-type icon set when requested', () => {
+ test('preloadFileTree uses the standard icon set when requested', () => {
const payload = preloadFileTree({
initialFiles: [
'package.json',
@@ -644,7 +644,7 @@ describe('SSR + declarative shadow DOM', () => {
'image.png',
'agent.mcp',
],
- icons: 'file-type',
+ icons: 'standard',
});
const container = document.createElement('file-tree-container');
@@ -677,28 +677,20 @@ describe('SSR + declarative shadow DOM', () => {
return href;
};
- expect(getIconHref('package.json')).toBe(
- '#file-tree-builtin-file-type-npm'
- );
- expect(getIconHref('index.ts')).toBe(
- '#file-tree-builtin-file-type-typescript'
- );
- expect(getIconHref('app.tsx')).toBe('#file-tree-builtin-file-type-react');
- expect(getIconHref('card.module.css')).toBe(
- '#file-tree-builtin-file-type-css'
- );
- expect(getIconHref('README.md')).toBe(
- '#file-tree-builtin-file-type-markdown'
- );
- expect(getIconHref('image.png')).toBe('#file-tree-builtin-file-type-image');
- expect(getIconHref('agent.mcp')).toBe('#file-tree-builtin-file-type-mcp');
+ expect(getIconHref('package.json')).toBe('#file-tree-builtin-json');
+ expect(getIconHref('index.ts')).toBe('#file-tree-builtin-typescript');
+ expect(getIconHref('app.tsx')).toBe('#file-tree-builtin-typescript');
+ expect(getIconHref('card.module.css')).toBe('#file-tree-builtin-css');
+ expect(getIconHref('README.md')).toBe('#file-tree-builtin-markdown');
+ expect(getIconHref('image.png')).toBe('#file-tree-builtin-image');
+ expect(getIconHref('agent.mcp')).toBe('#file-tree-builtin-mcp');
});
test('setOptions swaps built-in icon sets and colored mode at runtime', () => {
const container = document.createElement('file-tree-container');
const ft = new FileTree({
initialFiles: ['index.ts'],
- icons: 'simple',
+ icons: 'minimal',
});
const origRender = preactRenderer.renderRoot;
@@ -712,19 +704,19 @@ describe('SSR + declarative shadow DOM', () => {
) as HTMLElement | null;
expect(wrapper).not.toBeNull();
expect(
- shadowRoot?.querySelector('#file-tree-builtin-file-type-typescript')
+ shadowRoot?.querySelector('#file-tree-builtin-typescript')
).toBeNull();
expect(wrapper?.dataset.fileTreeColoredIcons).toBeUndefined();
ft.setOptions({
icons: {
- set: 'duo-tone',
+ set: 'complete',
colored: true,
},
});
expect(
- shadowRoot?.querySelector('#file-tree-builtin-duo-tone-typescript')
+ shadowRoot?.querySelector('#file-tree-builtin-typescript')
).not.toBeNull();
expect(wrapper?.dataset.fileTreeColoredIcons).toBe('true');
} finally {