From 9e4650a28dab042f312acc1a0f832b01bb2bd233 Mon Sep 17 00:00:00 2001 From: Nicolas Gallagher <239676+necolas@users.noreply.github.com> Date: Wed, 22 Jul 2026 12:18:44 -0700 Subject: [PATCH 1/4] agents(diffs): Add package usage skill Give agents routed API references and recipes for files, diffs, CodeView surfaces, edit mode, SSR, and workers. Add the package README command that installs only the diffs skill from this repository. --- packages/diffs/README.md | 9 + skills/diffs/SKILL.md | 48 ++++ skills/diffs/references/api-core.md | 186 +++++++++++++++ skills/diffs/references/api-editor.md | 94 ++++++++ skills/diffs/references/api-highlighting.md | 113 ++++++++++ skills/diffs/references/api-react.md | 63 ++++++ skills/diffs/references/api-rendering.md | 183 +++++++++++++++ skills/diffs/references/api-ssr.md | 35 +++ skills/diffs/references/api-types.md | 176 +++++++++++++++ skills/diffs/references/api-worker.md | 91 ++++++++ skills/diffs/references/recipe-annotations.md | 32 +++ skills/diffs/references/recipe-code-view.md | 213 ++++++++++++++++++ .../references/recipe-custom-highlighting.md | 19 ++ skills/diffs/references/recipe-edit-react.md | 121 ++++++++++ .../diffs/references/recipe-edit-vanilla.md | 163 ++++++++++++++ skills/diffs/references/recipe-react.md | 37 +++ skills/diffs/references/recipe-ssr.md | 20 ++ skills/diffs/references/recipe-vanilla.md | 41 ++++ skills/diffs/references/recipe-workers.md | 28 +++ 19 files changed, 1672 insertions(+) create mode 100644 skills/diffs/SKILL.md create mode 100644 skills/diffs/references/api-core.md create mode 100644 skills/diffs/references/api-editor.md create mode 100644 skills/diffs/references/api-highlighting.md create mode 100644 skills/diffs/references/api-react.md create mode 100644 skills/diffs/references/api-rendering.md create mode 100644 skills/diffs/references/api-ssr.md create mode 100644 skills/diffs/references/api-types.md create mode 100644 skills/diffs/references/api-worker.md create mode 100644 skills/diffs/references/recipe-annotations.md create mode 100644 skills/diffs/references/recipe-code-view.md create mode 100644 skills/diffs/references/recipe-custom-highlighting.md create mode 100644 skills/diffs/references/recipe-edit-react.md create mode 100644 skills/diffs/references/recipe-edit-vanilla.md create mode 100644 skills/diffs/references/recipe-react.md create mode 100644 skills/diffs/references/recipe-ssr.md create mode 100644 skills/diffs/references/recipe-vanilla.md create mode 100644 skills/diffs/references/recipe-workers.md diff --git a/packages/diffs/README.md b/packages/diffs/README.md index cc61b819c..bc3717423 100644 --- a/packages/diffs/README.md +++ b/packages/diffs/README.md @@ -27,6 +27,15 @@ JavaScript and React components. pnpm add @pierre/diffs ``` +## Agent skill + +Install the agent skill for this package with the +[Skills CLI](https://skills.sh/docs/cli): + +```bash +npx skills add pierrecomputer/pierre --skill diffs +``` + ## Development We use pnpm for workspace package management and Bun for tests. diff --git a/skills/diffs/SKILL.md b/skills/diffs/SKILL.md new file mode 100644 index 000000000..25fd3e0a7 --- /dev/null +++ b/skills/diffs/SKILL.md @@ -0,0 +1,48 @@ +--- +name: diffs +description: + Use when an app uses @pierre/diffs to render or edit code files, diffs, + patches, merge conflicts, or CodeView review surfaces, including React, + vanilla JavaScript, SSR, workers, annotations, selection, and custom Shiki + languages or themes. +--- + +# `@pierre/diffs` + +Use `@pierre/diffs` to render syntax-highlighted files and diffs. Use its +optional editor, SSR, and worker entries for those capabilities. + +## Install + +```bash +pnpm add @pierre/diffs +``` + +Install `react` and `react-dom` when the app uses the React entry. + +## Select an API reference + +| Surface | Reference | +| ------------------------------------------------------------ | ------------------------------------------------------ | +| Root components, parsing, and file extension APIs | [Core API](references/api-core.md) | +| Languages, themes, highlighter state, and streams | [Highlighting API](references/api-highlighting.md) | +| Renderers, managers, DOM helpers, comparisons, and constants | [Low-level rendering API](references/api-rendering.md) | +| Shared data, option, render, selection, and editor types | [Shared types](references/api-types.md) | +| `@pierre/diffs/react` | [React API](references/api-react.md) | +| `@pierre/diffs/editor` | [Editor API](references/api-editor.md) | +| `@pierre/diffs/ssr` | [SSR API](references/api-ssr.md) | +| `@pierre/diffs/worker` and worker scripts | [Worker API](references/api-worker.md) | + +## Select a recipe + +| Task | Recipe | +| ----------------------------------- | ------------------------------------------------------------------------ | +| Render a file or diff in React | [Render with React](references/recipe-react.md) | +| Render a file or diff without React | [Render with vanilla JavaScript](references/recipe-vanilla.md) | +| Build a virtualized review surface | [Use CodeView](references/recipe-code-view.md) | +| Edit a React surface or CodeView | [Edit with React](references/recipe-edit-react.md) | +| Edit a vanilla surface or CodeView | [Edit with vanilla JavaScript](references/recipe-edit-vanilla.md) | +| Preload markup on the server | [Use SSR](references/recipe-ssr.md) | +| Highlight through a worker pool | [Use workers](references/recipe-workers.md) | +| Add line annotations and selection | [Add annotations and selection](references/recipe-annotations.md) | +| Register a Shiki language or theme | [Register custom highlighting](references/recipe-custom-highlighting.md) | diff --git a/skills/diffs/references/api-core.md b/skills/diffs/references/api-core.md new file mode 100644 index 000000000..22b012862 --- /dev/null +++ b/skills/diffs/references/api-core.md @@ -0,0 +1,186 @@ +# Core API + +This reference covers components, parsing, merge conflicts, and file extension +APIs from `@pierre/diffs`. + +## Contents + +- [File components](#file-components) +- [Virtualized components](#virtualized-components) +- [`File` members](#file-members) +- [`FileDiff` members](#filediff-members) +- [`CodeView` members](#codeview-members) +- [Parsing and patch APIs](#parsing-and-patch-apis) +- [Merge conflict APIs](#merge-conflict-apis) +- [Annotation APIs](#annotation-apis) +- [File extension APIs](#file-extension-apis) + +## File components + +| Export | Kind | Purpose | +| --------------------------------------- | -------- | ------------------------------------------------------------- | +| `File` | Class | Renders one syntax-highlighted file. | +| `FileOptions` | Type | Configures file display, interaction, slots, and callbacks. | +| `FileRenderProps` | Type | Defines file input and a render target. | +| `FileHydrateProps` | Type | Defines file input and preloaded markup for hydration. | +| `FileDiff` | Class | Renders a file diff from files or parsed metadata. | +| `FileDiffOptions` | Type | Configures diff display, interaction, slots, and callbacks. | +| `FileDiffRenderBaseProps` | Type | Defines shared diff render input. | +| `FileDiffRenderProps` | Type | Adds files or parsed metadata to diff render input. | +| `FileDiffHydrationProps` | Type | Defines diff input and preloaded markup for hydration. | +| `FileDiffType` | Type | Identifies a standard or unresolved diff instance. | +| `UnresolvedFile` | Class | Renders one file with merge conflict controls. | +| `UnresolvedFileOptions` | Type | Configures merge conflict display and callbacks. | +| `UnresolvedFileRenderProps` | Type | Defines merge conflict render input. | +| `UnresolvedFileHydrationProps` | Type | Defines merge conflict input for hydration. | +| `MergeConflictActionsTypeOption` | Type | Selects no actions, default actions, or a custom renderer. | +| `RenderMergeConflictActions` | Type | Defines a vanilla conflict action renderer. | +| `getUnresolvedDiffHunksRendererOptions` | Function | Converts unresolved-file options to hunk renderer options. | +| `CodeView` | Class | Renders a virtualized list of files and diffs. | +| `CodeViewOptions` | Type | Configures list layout, items, slots, selection, and editing. | +| `CodeViewLineSelection` | Type | Associates a selected range with one item ID. | +| `CodeViewRenderedFileItem` | Type | Describes one mounted file item. | +| `CodeViewRenderedDiffItem` | Type | Describes one mounted diff item. | +| `CodeViewRenderedItem` | Type | Represents a mounted file or diff item. | +| `CodeViewCoordinator` | Type | Coordinates React slots with the vanilla list. | +| `CodeViewSlotSnapshot` | Type | Describes mounted items and list header or footer hosts. | +| `CodeViewScrollListener` | Type | Receives list scroll changes. | +| `CODE_VIEW_FILE_OPTION_KEYS` | Value | Lists file options that `CodeView` passes to an item. | +| `CODE_VIEW_DIFF_OPTION_KEYS` | Value | Lists diff options that `CodeView` passes to an item. | + +## Virtualized components + +| Export | Kind | Purpose | +| -------------------------------------------------- | ----- | ----------------------------------------------------------- | +| `Virtualizer` | Class | Tracks a simple viewport and connected render instances. | +| `VirtualizerConfig` | Type | Configures overscroll, observation margin, and resize logs. | +| `VirtualizedFile` | Class | Adds simple viewport behavior to `File`. | +| `VirtualizedFileDiff` | Class | Adds simple viewport behavior to `FileDiff`. | +| `VIRTUALIZED_FILE_DIFF_LAYOUT_CHECKPOINT_INTERVAL` | Value | Sets the line interval for virtual diff layout checkpoints. | + +## `File` members + +| Member | Purpose | +| --------------------------------------------- | ---------------------------------------------------- | +| `new File(options?, workerManager?)` | Creates one file renderer. | +| `render(props)` | Renders file contents. | +| `hydrate(props)` | Attaches to preloaded file markup. | +| `rerender()` | Renders the current file again. | +| `setOptions(options)` | Replaces file options. | +| `setThemeType(themeType)` | Selects system, light, or dark theme mode. | +| `onThemeChange()` | Applies a changed theme. | +| `setLineAnnotations(annotations)` | Replaces file annotations. | +| `setSelectedLines(range, options?)` | Replaces the selected line range. | +| `setEditorActiveLine(line, options?)` | Marks the editor's active line. | +| `getHoveredLine()` | Gets the current hovered line. | +| `getOrCreateLineCache(file?)` | Gets cached source lines. | +| `attachEditor(editor)` | Attaches an editor and returns a detach function. | +| `applyDocumentChange(document, annotations?)` | Applies an editor document update. | +| `updateRenderCache(tokens, themeType)` | Updates highlighted token cache entries. | +| `primeHighlightCache()` | Preloads the highlighted file result. | +| `renderPlaceholder(height)` | Renders a fixed-height placeholder. | +| `virtualizedSetup()` | Prepares the instance for a virtualizer. | +| `flushManagers()` | Applies deferred interaction and size manager state. | +| `cleanUp(recycle?)` | Releases rendered resources. | + +## `FileDiff` members + +`FileDiff` supports the shared `File` update, selection, annotation, editor, +hydration, placeholder, and cleanup members with diff data. + +| Member | Purpose | +| -------------------------------------------- | ------------------------------------------------ | +| `new FileDiff(options?, workerManager?)` | Creates one diff renderer. | +| `render(props)` | Parses or renders diff input. | +| `hydrate(props)` | Attaches to preloaded diff markup. | +| `rerender()` | Renders the current diff again. | +| `setOptions(options)` | Replaces diff options. | +| `getLineIndex(line, side?)` | Maps a displayed line to row and column indexes. | +| `handleExpandHunk(index, direction, count?)` | Handles a hunk expansion request. | +| `expandHunk(index, direction, count?)` | Expands hidden context around one hunk. | +| `completeEditSession()` | Recomputes diff metadata after an edit session. | +| `isLineRenderable(line)` | Tests whether an additions line is visible. | +| `getNearestRenderableLine(line, direction)` | Finds a visible additions line. | +| `revealLine(line)` | Expands context to show an additions line. | +| `primeHighlightCache(diff?)` | Preloads the highlighted diff result. | + +## `CodeView` members + +| Member | Purpose | +| ---------------------------------------- | -------------------------------------------- | +| `new CodeView(options?, workerManager?)` | Creates one virtualized list. | +| `setup(root)` | Attaches the list to its scroll root. | +| `setItems(items)` | Replaces all items. | +| `addItem(item)` | Appends one item. | +| `addItems(items)` | Appends several items. | +| `getItem(id)` | Gets one item by ID. | +| `updateItem(item)` | Replaces one item by ID. | +| `updateItemId(oldId, newId)` | Changes one item ID. | +| `getEditor(id)` | Gets the active editor for an item. | +| `scrollTo(target)` | Scrolls to a position, item, line, or range. | +| `setSelectedLines(selection, options?)` | Sets the selected item and range. | +| `getSelectedLines()` | Gets the selected item and range. | +| `clearSelectedLines(options?)` | Clears the selected lines. | +| `setOptions(options)` | Replaces list options. | +| `onThemeChange()` | Applies a changed theme to list items. | +| `render(immediate?)` | Schedules or performs a render. | +| `getWindowSpecs()` | Gets the current virtual window. | +| `getContainerElement()` | Gets the scroll content element. | +| `getHeaderElement()` | Gets the list header host. | +| `getFooterElement()` | Gets the list footer host. | +| `getRenderedItems()` | Gets mounted items. | +| `setSlotCoordinator(coordinator?)` | Sets the external slot coordinator. | +| `getSlotSnapshot(coordinator)` | Gets the coordinator's mounted slot state. | +| `subscribeToScroll(listener)` | Subscribes to scroll changes. | +| `getLocalTopForInstance(instance)` | Gets an instance offset inside the list. | +| `getTopForItem(id)` | Gets an item offset inside the list. | +| `instanceChanged(instance, layoutDirty)` | Reports a render instance change. | +| `reset()` | Clears items and render state. | +| `cleanUp()` | Releases list resources. | + +## Parsing and patch APIs + +| Export | Purpose | +| ---------------------------- | ----------------------------------------------------- | +| `parseDiffFromFile` | Creates `FileDiffMetadata` from old and new files. | +| `parsePatchFiles` | Parses a patch string into file diff metadata. | +| `processPatch` | Parses one patch section. | +| `processFile` | Converts one parsed patch file to `FileDiffMetadata`. | +| `getSingularPatch` | Selects one file patch from a patch string. | +| `trimPatchContext` | Limits unchanged context in patch text. | +| `hydratePartialDiff` | Adds loaded file contents to partial diff metadata. | +| `cloneFileDiffMetadata` | Creates a structural copy of diff metadata. | +| `cleanLastNewline` | Normalizes the final newline for diff input. | +| `getLineEndingType` | Detects a file's line-ending sequence. | +| `getTotalLineCountFromHunks` | Counts rendered rows across hunks. | +| `parseLineType` | Parses one patch line marker and content. | +| `ParsedLine` | Describes the result from `parseLineType`. | + +## Merge conflict APIs + +| Export | Purpose | +| ---------------------- | --------------------------------------------------------------- | +| `resolveConflict` | Applies one current, incoming, or combined conflict resolution. | +| `resolveRegion` | Resolves one parsed merge conflict region. | +| `diffAcceptRejectHunk` | Applies accept or reject behavior to one change hunk. | + +## Annotation APIs + +| Export | Purpose | +| ---------------------------- | ---------------------------------------------------------- | +| `isFileAnnotation` | Tests whether one annotation targets a file line. | +| `isDiffAnnotation` | Tests whether one annotation targets a diff side and line. | +| `isFileAnnotationCollection` | Tests whether an array contains file annotations. | +| `isDiffAnnotationCollection` | Tests whether an array contains diff annotations. | + +## File extension APIs + +| Export | Purpose | +| ---------------------------- | ------------------------------------------------ | +| `getFiletypeFromFileName` | Infers a language from a file name. | +| `setCustomExtension` | Maps one file name or extension to a language. | +| `replaceCustomExtensions` | Replaces all custom mappings. | +| `getCustomExtensionsMap` | Gets a copy of custom mappings. | +| `getCustomExtensionsVersion` | Gets the mapping revision. | +| `EXTENSION_TO_FILE_FORMAT` | Maps built-in extensions and names to languages. | +| `setLanguageOverride` | Assigns a language to parsed diff files. | diff --git a/skills/diffs/references/api-editor.md b/skills/diffs/references/api-editor.md new file mode 100644 index 000000000..0a139d7b2 --- /dev/null +++ b/skills/diffs/references/api-editor.md @@ -0,0 +1,94 @@ +# Editor API + +This reference lists every export from `@pierre/diffs/editor` and every public +member of its classes. + +## Exports + +| Export | Kind | Purpose | +| --------------------- | ----- | --------------------------------------------------------- | +| `Editor` | Class | Adds text editing to a `File` or `FileDiff` instance. | +| `EditorOptions` | Type | Configures history, state, selections, and callbacks. | +| `TextDocument` | Class | Stores text, positions, edits, search, and undo history. | +| `TextDocumentChange` | Type | Describes the lines and characters changed by an edit. | +| `ResolvedTextEdit` | Type | Describes an edit with absolute offsets. | +| `IStateStorage` | Type | Defines asynchronous or synchronous editor state storage. | +| `PersistStateStorage` | Type | Selects memory, IndexedDB, or custom state storage. | +| `Position` | Type | Identifies a zero-based line and character. | +| `Range` | Type | Identifies a start and end position. | +| `TextEdit` | Type | Replaces one range with new text. | + +## `EditorOptions` fields + +| Field | Purpose | +| ------------------------ | -------------------------------------------------------- | +| `historyMaxEntries` | Limits the undo stack. | +| `persistState` | Keeps editor state for each file cache key. | +| `persistStateStorage` | Selects the state store. | +| `roundedSelection` | Controls rounded selection corners. | +| `matchBrackets` | Controls matching-bracket highlights. | +| `autoSurround` | Controls quote and bracket insertion around a selection. | +| `languageCommentConfig` | Overrides comment tokens by language. | +| `enabledSelectionAction` | Enables the selection action surface. | +| `clipboard` | Supplies a text clipboard reader. | +| `renderSelectionAction` | Produces the selection action element. | +| `onAttach` | Receives the editor and attached surface. | +| `onChange` | Receives changed file contents and line annotations. | +| `onFocus` | Runs after the editor gains focus. | +| `onBlur` | Runs after the editor loses focus. | + +## `Editor` members + +| Member | Purpose | +| ----------------------------------- | --------------------------------------------------------- | +| `new Editor(options?)` | Creates one editor. | +| `edit(instance)` | Attaches to a file or diff and returns a detach function. | +| `setOptions(options)` | Replaces editor options. | +| `applyEdits(edits, updateHistory?)` | Applies programmatic text edits. | +| `canUndo` | Reports whether undo has an entry. | +| `canRedo` | Reports whether redo has an entry. | +| `undo()` | Reverts the latest edit. | +| `redo()` | Reapplies the latest reverted edit. | +| `getFile()` | Gets the current file contents. | +| `getText()` | Gets the current text. | +| `getState()` | Gets selections and view state. | +| `setState(state)` | Sets selections and view state. | +| `setSelections(selections)` | Sets directed selection ranges. | +| `setMarkers(markers)` | Sets diagnostic markers. | +| `focus(options?)` | Focuses the editor. | +| `blur()` | Removes editor focus. | +| `cleanUp(recycle?)` | Releases editor resources. | + +## `TextDocument` members + +| Member | Purpose | +| ---------------------------------------------------- | ----------------------------------------------------- | +| `new TextDocument(uri, text, languageId?, version?)` | Creates a text document. | +| `uri` | Gets the document identifier. | +| `languageId` | Gets the language identifier. | +| `version` | Gets the document version. | +| `lineCount` | Gets the line count. | +| `eol` | Gets the line-ending sequence. | +| `canUndo` | Reports whether undo has an entry. | +| `canRedo` | Reports whether redo has an entry. | +| `positionAt(offset)` | Converts an offset to a position. | +| `positionsAt(offsets)` | Converts several offsets to positions. | +| `offsetAt(position)` | Converts a position to an offset. | +| `getText(range?)` | Gets all text or one range. | +| `getLineText(line, includeLineBreak?)` | Gets one line. | +| `normalizeEol(text)` | Converts text to the document line ending. | +| `getLineLength(line, includeLineBreak?)` | Gets one line length. | +| `charAt(offsetOrPosition)` | Gets one character. | +| `getTextSlice(start, end)` | Gets text between two offsets. | +| `findNextNonOverlappingSubstring(needle, occupied)` | Finds an unused substring range. | +| `search(params)` | Finds text ranges. | +| `applyEdits(edits, ...)` | Resolves and applies position-based edits. | +| `resolveEdits(edits)` | Converts position-based edits to offset edits. | +| `applyResolvedEdits(edits, ...)` | Applies offset-based edits. | +| `setLastUndoSelectionsAfter(selections)` | Associates selections with the latest history entry. | +| `setLastUndoLineAnnotations(before, after)` | Associates annotations with the latest history entry. | +| `undo()` | Reverts one document history entry. | +| `redo()` | Reapplies one document history entry. | +| `normalizePosition(position)` | Clamps a position to the document. | + +`IStateStorage` has `get(cacheKey)` and `set(cacheKey, state)` methods. diff --git a/skills/diffs/references/api-highlighting.md b/skills/diffs/references/api-highlighting.md new file mode 100644 index 000000000..861d8884f --- /dev/null +++ b/skills/diffs/references/api-highlighting.md @@ -0,0 +1,113 @@ +# Highlighting API + +This reference lists every language, theme, shared highlighter, and stream +export from `@pierre/diffs`. + +## Contents + +- [Shiki passthrough APIs](#shiki-passthrough-apis) +- [Language APIs](#language-apis) +- [Theme APIs](#theme-apis) +- [Shared highlighter APIs](#shared-highlighter-apis) +- [Render APIs](#render-apis) +- [Stream APIs](#stream-apis) + +## Shiki passthrough APIs + +| Export | Kind | Purpose | +| ------------------------- | -------- | ------------------------------------------------ | +| `codeToHtml` | Function | Re-exports Shiki's complete code-to-HTML helper. | +| `createCSSVariablesTheme` | Function | Re-exports Shiki's CSS variable theme factory. | + +## Language APIs + +| Export | Kind | Purpose | +| ------------------------------ | -------- | --------------------------------------------------------- | +| `registerCustomLanguage` | Function | Registers a lazy language and optional file mappings. | +| `resolveLanguage` | Function | Loads and caches one language registration. | +| `resolveLanguages` | Function | Loads and caches several language registrations. | +| `getResolvedOrResolveLanguage` | Function | Returns one cached language or starts its load. | +| `getResolvedLanguages` | Function | Gets cached registrations for the supplied languages. | +| `hasResolvedLanguages` | Function | Tests whether language registrations are cached. | +| `attachResolvedLanguages` | Function | Adds resolved registrations to a highlighter. | +| `areLanguagesAttached` | Function | Tests whether a highlighter has the supplied languages. | +| `cleanUpResolvedLanguages` | Function | Clears language resolution state. | +| `RegisteredCustomLanguages` | Map | Stores registered custom language loaders. | +| `ResolvedLanguages` | Map | Stores resolved language registrations. | +| `ResolvingLanguages` | Map | Stores active language load promises. | +| `AttachedLanguages` | Set | Stores language names attached to the shared highlighter. | + +## Theme APIs + +| Export | Kind | Purpose | +| -------------------------------- | -------- | ------------------------------------------------------ | +| `registerCustomTheme` | Function | Registers a lazy Shiki theme loader. | +| `CustomThemeLoader` | Type | Defines a raw or resolved Shiki theme loader. | +| `registerCustomCSSVariableTheme` | Function | Registers a theme that reads CSS variables. | +| `resolveTheme` | Function | Loads and caches one theme. | +| `resolveThemes` | Function | Loads and caches several themes. | +| `getResolvedOrResolveTheme` | Function | Returns one cached theme or starts its load. | +| `getResolvedThemes` | Function | Gets cached themes by name. | +| `hasResolvedThemes` | Function | Tests whether themes are cached. | +| `attachResolvedThemes` | Function | Adds resolved themes to a highlighter. | +| `areThemesAttached` | Function | Tests whether a highlighter has the supplied themes. | +| `cleanUpResolvedThemes` | Function | Clears theme resolution state. | +| `AttachedThemes` | Set | Stores theme names attached to the shared highlighter. | + +## Shared highlighter APIs + +| Export | Purpose | +| --------------------------- | ----------------------------------------------------------------- | +| `getSharedHighlighter` | Gets or creates the shared highlighter for themes and languages. | +| `preloadHighlighter` | Loads the shared highlighter before a render. | +| `getHighlighterIfLoaded` | Gets the shared highlighter after load. | +| `isHighlighterLoaded` | Tests a highlighter cache value for a loaded instance. | +| `isHighlighterLoading` | Tests a highlighter cache value for an active promise. | +| `isHighlighterNull` | Tests a highlighter cache value for an empty state. | +| `disposeHighlighter` | Disposes and clears the shared highlighter. | +| `getHighlighterOptions` | Converts one language and component options to highlighter input. | +| `getHighlighterThemeStyles` | Creates theme CSS from a loaded highlighter. | +| `getThemes` | Converts one theme or light/dark pair to a name list. | +| `isWorkerContext` | Tests whether code runs in a worker global scope. | + +## Render APIs + +| Export | Purpose | +| ---------------------------- | ------------------------------------------------------- | +| `renderFileWithHighlighter` | Creates a highlighted file syntax tree. | +| `renderDiffWithHighlighter` | Creates highlighted deletion and addition syntax trees. | +| `createTransformerWithState` | Creates Shiki transformers with shared render state. | + +## Stream APIs + +| Export | Kind | Purpose | +| ----------------------------------- | ----- | ------------------------------------------------------------- | +| `FileStream` | Class | Renders a readable code stream as highlighted rows. | +| `FileStreamOptions` | Type | Configures stream language, theme, start line, and callbacks. | +| `CodeToTokenTransformStream` | Class | Converts code chunks to themed or recall tokens. | +| `CodeToTokenTransformStreamOptions` | Type | Configures stream tokenization and recall tokens. | +| `ShikiStreamTokenizer` | Class | Tracks stable and unstable tokens across code chunks. | +| `ShikiStreamTokenizerOptions` | Type | Supplies Shiki token options and a highlighter. | +| `ShikiStreamTokenizerEnqueueResult` | Type | Returns recalled, stable, and unstable tokens for one chunk. | +| `RecallToken` | Type | Requests removal of prior unstable tokens. | + +## `FileStream` members + +| Member | Purpose | +| -------------------------- | ------------------------------------------ | +| `new FileStream(options?)` | Creates a stream renderer. | +| `setup(source, wrapper)` | Connects a readable code stream to a host. | +| `setThemeType(themeType)` | Selects system, light, or dark theme mode. | +| `cleanUp()` | Aborts the stream and releases resources. | + +## `ShikiStreamTokenizer` members + +| Member | Purpose | +| ----------------------------------- | ------------------------------------ | +| `new ShikiStreamTokenizer(options)` | Creates a stateful tokenizer. | +| `enqueue(chunk)` | Tokenizes one code chunk. | +| `close()` | Finalizes and returns stable tokens. | +| `clear()` | Clears accumulated token state. | +| `clone()` | Copies current tokenizer state. | + +`CodeToTokenTransformStream` exposes its `tokenizer` and `options` values. diff --git a/skills/diffs/references/api-react.md b/skills/diffs/references/api-react.md new file mode 100644 index 000000000..ba70538ac --- /dev/null +++ b/skills/diffs/references/api-react.md @@ -0,0 +1,63 @@ +# React API + +This reference lists the React-specific exports from `@pierre/diffs/react`. The +entry also re-exports every type in [Shared types](api-types.md). + +## Components and hooks + +| Export | Kind | Purpose | +| --------------------------- | --------- | --------------------------------------------------------- | +| `File` | Component | Renders one code file. | +| `FileDiff` | Component | Renders pre-parsed diff metadata. | +| `MultiFileDiff` | Component | Parses and renders an old and new file pair. | +| `PatchDiff` | Component | Parses and renders one unified patch string. | +| `UnresolvedFile` | Component | Renders and resolves merge conflicts in one file. | +| `CodeView` | Component | Renders a virtualized list of files and diffs. | +| `Virtualizer` | Component | Provides simple viewport virtualization. | +| `useVirtualizer` | Hook | Gets the nearest simple `Virtualizer` instance. | +| `EditProvider` | Component | Supplies an editor factory to editable surfaces. | +| `useCreateEditor` | Hook | Gets the nearest editor factory. | +| `WorkerPoolContextProvider` | Component | Creates and supplies a worker pool. | +| `useWorkerPool` | Hook | Gets the nearest worker pool. | +| `useFileInstance` | Hook | Creates and manages a vanilla `File` instance. | +| `useFileDiffInstance` | Hook | Creates and manages a vanilla `FileDiff` instance. | +| `useStableCallback` | Hook | Returns a stable callback that reads the latest function. | + +## Component and provider types + +| Export | Purpose | +| ----------------------------------- | ----------------------------------------------------------------- | +| `FileProps` | Defines props for `File`. | +| `FileOptions` | Defines vanilla file options and the React `options` prop. | +| `FileDiffProps` | Defines props for `FileDiff`. | +| `MultiFileDiffProps` | Defines props for `MultiFileDiff`. | +| `PatchDiffProps` | Defines props for `PatchDiff`. | +| `UnresolvedFileProps` | Defines props for `UnresolvedFile`. | +| `UnresolvedFileReactOptions` | Defines merge-conflict options for React. | +| `DiffBasePropsReact` | Defines props shared by React diff components. | +| `CodeViewProps` | Defines controlled or uncontrolled `CodeView` props. | +| `ControlledCodeViewProps` | Defines `CodeView` props with `items`. | +| `UncontrolledCodeViewProps` | Defines `CodeView` props with `initialItems`. | +| `CodeViewReactOptions` | Defines the React-safe `CodeView` option set. | +| `CodeViewHandle` | Defines imperative list, selection, scroll, and editor controls. | +| `CreateEditor` | Defines the editor factory. | +| `EditProviderProps` | Defines `EditProvider` props. | +| `MergeConflictActionsTypeOption` | Selects no actions, default actions, or a custom action renderer. | +| `RenderMergeConflictActionContext` | Supplies conflict resolution to a custom action renderer. | +| `RenderMergeConflictActions` | Defines a custom conflict action renderer. | +| `WorkerInitializationRenderOptions` | Defines initial worker languages and render options. | +| `WorkerPoolOptions` | Defines the worker factory, pool size, and cache size. | + +## Contexts and render helpers + +| Export | Kind | Purpose | +| ------------------------- | -------- | ------------------------------------------------------ | +| `EditContext` | Context | Holds the editor factory. | +| `WorkerPoolContext` | Context | Holds the worker pool. | +| `VirtualizerContext` | Context | Holds the simple virtualizer. | +| `GutterUtilitySlotStyles` | Value | Supplies style keys for gutter utility slots. | +| `MergeConflictSlotStyles` | Value | Supplies style keys for merge conflict slots. | +| `noopRender` | Function | Returns no React output for an optional render slot. | +| `renderDiffChildren` | Function | Builds React portals for diff slots. | +| `renderFileChildren` | Function | Builds React portals for file slots. | +| `templateRender` | Function | Renders React content through a managed template slot. | diff --git a/skills/diffs/references/api-rendering.md b/skills/diffs/references/api-rendering.md new file mode 100644 index 000000000..5e9de9707 --- /dev/null +++ b/skills/diffs/references/api-rendering.md @@ -0,0 +1,183 @@ +# Low-level rendering API + +This reference lists the renderer, manager, DOM helper, comparison, and constant +exports from `@pierre/diffs`. + +## Contents + +- [Renderers](#renderers) +- [Interaction manager](#interaction-manager) +- [Size, scroll, and render managers](#size-scroll-and-render-managers) +- [Comparison helpers](#comparison-helpers) +- [Syntax tree and DOM helpers](#syntax-tree-and-dom-helpers) +- [Layout and CSS helpers](#layout-and-css-helpers) +- [Constants](#constants) + +## Renderers + +| Export | Kind | Purpose | +| -------------------------------------- | ----- | ------------------------------------------------------- | +| `FileRenderer` | Class | Converts one file to highlighted HAST, CSS, and HTML. | +| `FileRendererOptions` | Type | Adds header mode to base code options. | +| `FileRenderResult` | Type | Holds file HAST, CSS, row counts, and buffers. | +| `DiffHunksRenderer` | Class | Converts diff hunks to highlighted column HAST and CSS. | +| `DiffHunksRendererOptions` | Type | Configures one hunk renderer. | +| `DiffHunksRendererOptionsWithDefaults` | Type | Describes resolved hunk renderer options. | +| `HunksRenderResult` | Type | Holds rendered diff columns, metadata, and row count. | +| `RenderedLineContext` | Type | Supplies line state to a line decoration. | +| `LineDecoration` | Type | Defines a custom line wrapper and injected rows. | +| `InjectedRow` | Type | Defines one row inserted around a unified line. | +| `SplitInjectedRow` | Type | Defines one row inserted around a split line. | +| `UnifiedInjectedRowPlacement` | Type | Selects placement before or after a unified row. | +| `SplitInjectedRowPlacement` | Type | Selects side and placement for a split row. | +| `UnifiedLineDecorationProps` | Type | Supplies one unified row to a decoration. | +| `SplitLineDecorationProps` | Type | Supplies paired split rows to a decoration. | + +## Interaction manager + +| Export | Kind | Purpose | +| ------------------------------- | -------- | ------------------------------------------------------------------------ | +| `InteractionManager` | Class | Handles hover, token, gutter, and line selection events. | +| `InteractionManagerMode` | Type | Selects file or diff interaction data. | +| `InteractionManagerBaseOptions` | Type | Defines interaction callbacks and enabled features. | +| `InteractionManagerOptions` | Type | Adds required DOM access to base interaction options. | +| `GetHoveredLineResult` | Type | Describes the current hovered file or diff line. | +| `GetLineIndexUtility` | Type | Maps a logical line to row and column indexes. | +| `OnLineClickProps` | Type | Describes a file line click. | +| `OnLineEnterLeaveProps` | Type | Describes file line pointer entry or exit. | +| `OnDiffLineClickProps` | Type | Describes a diff line click. | +| `OnDiffLineEnterLeaveProps` | Type | Describes diff line pointer entry or exit. | +| `OnTokenEventProps` | Type | Selects file or diff token event data. | +| `SelectionWriteOptions` | Type | Configures callback emission, the active side, and line-only highlights. | +| `MergeConflictActionTarget` | Type | Describes a merge conflict action element. | +| `LogTypes` | Type | Selects interaction log categories. | +| `pluckInteractionOptions` | Function | Selects interaction fields from component options. | + +## Size, scroll, and render managers + +| Export | Kind | Purpose | +| --------------------------------- | -------- | ------------------------------------------------------------- | +| `ResizeManager` | Class | Measures rows, annotations, and column CSS values. | +| `ResizeManagerColumnVariableMode` | Type | Selects column variable measurement or application. | +| `ResizeManagerSetupOptions` | Type | Configures annotation and column measurement. | +| `ScrollSyncManager` | Class | Synchronizes additions and deletions column scroll positions. | +| `queueRender` | Function | Adds a callback to the shared animation render queue. | +| `dequeueRender` | Function | Removes a callback from the shared render queue. | +| `clearRenderQueue` | Function | Removes all callbacks from the shared render queue. | + +## Comparison helpers + +| Export | Purpose | +| ----------------------------- | ------------------------------------------------- | +| `areDiffLineAnnotationsEqual` | Compares two diff annotation arrays. | +| `areLineAnnotationsEqual` | Compares two file annotation arrays. | +| `areDiffRenderOptionsEqual` | Compares resolved diff render options. | +| `areFileRenderOptionsEqual` | Compares resolved file render options. | +| `areDiffTargetsEqual` | Compares two diff interaction targets. | +| `areFilesEqual` | Compares two file inputs. | +| `areHunkDataEqual` | Compares two hunk data objects. | +| `areObjectsEqual` | Performs the package's shallow object comparison. | +| `areOptionsEqual` | Compares component option objects. | +| `arePrePropertiesEqual` | Compares calculated `pre` properties. | +| `areRenderRangesEqual` | Compares two render ranges. | +| `areSelectionsEqual` | Compares editor selection arrays. | +| `areThemesEqual` | Compares theme names or light/dark pairs. | +| `areVirtualWindowSpecsEqual` | Compares two virtual window descriptions. | +| `areWorkerStatsEqual` | Compares two worker statistics objects. | + +## Syntax tree and DOM helpers + +| Export | Kind | Purpose | +| -------------------------------- | -------- | ---------------------------------------------------------- | +| `createAnnotationElement` | Function | Creates a HAST annotation row from an annotation span. | +| `createAnnotationWrapperNode` | Function | Creates a DOM host for an annotation slot. | +| `createDiffSpanDecoration` | Function | Creates one Shiki inline diff decoration. | +| `pushOrJoinSpan` | Function | Adds or joins one inline diff span. | +| `createEmptyRowBuffer` | Function | Creates an empty virtual row buffer. | +| `createFileHeaderElement` | Function | Creates a file or diff header HAST element. | +| `CreateFileHeaderElementProps` | Type | Defines header source, mode, and sticky state. | +| `createGutterGap` | Function | Creates a gutter gap HAST element. | +| `createGutterItem` | Function | Creates a gutter item HAST element. | +| `createGutterWrapper` | Function | Creates a gutter wrapper HAST element. | +| `createGutterUtilityElement` | Function | Creates a gutter utility HAST element. | +| `createGutterUtilityContentNode` | Function | Creates a gutter utility DOM content host. | +| `createHastElement` | Function | Creates a typed HAST element. | +| `createIconElement` | Function | Creates a sprite icon HAST element. | +| `createTextNodeElement` | Function | Creates a HAST text node. | +| `createNoNewlineElement` | Function | Creates the missing-final-newline HAST element. | +| `createPreElement` | Function | Creates the outer HAST `pre` element. | +| `createPreWrapperProperties` | Function | Creates HAST properties for a `pre` wrapper. | +| `createRowNodes` | Function | Creates DOM row and content elements for one line. | +| `createSeparator` | Function | Creates a hunk separator HAST element. | +| `createSpanFromToken` | Function | Creates a HAST span from one highlighted token. | +| `createStyleElement` | Function | Creates a DOM style element with an attribute marker. | +| `createThemeStyleElement` | Function | Creates a marked theme style element. | +| `createUnsafeCSSStyleNode` | Function | Creates a marked custom CSS style element. | +| `findCodeElement` | Function | Finds the code element in a HAST tree. | +| `getLineNodes` | Function | Gets rendered line nodes from a HAST root. | +| `getOrCreateCodeNode` | Function | Reuses or creates a code column DOM node. | +| `getLineAnnotationName` | Function | Creates the slot name for a line annotation. | +| `getHunkSeparatorSlotName` | Function | Creates the slot name for a hunk separator. | +| `getIconForType` | Function | Maps a file change type to a sprite icon. | +| `processLine` | Function | Applies line render state to one HAST line. | +| `setPreNodeProperties` | Function | Applies resolved render properties to a DOM `pre` element. | +| `prerenderHTMLIfNecessary` | Function | Adds preloaded HTML to an empty host element. | + +## Layout and CSS helpers + +| Export | Purpose | +| -------------------------------- | ------------------------------------------------------------- | +| `createWindowFromScrollPosition` | Calculates a virtual window from scroll measurements. | +| `isDefaultRenderRange` | Tests whether a render range covers the default full range. | +| `prefersReducedMotion` | Reads the reduced-motion media preference. | +| `formatCSSVariablePrefix` | Creates the global or token CSS variable prefix. | +| `wrapCoreCSS` | Places core CSS in its cascade layer. | +| `wrapThemeCSS` | Places theme CSS in its layer and mode selector. | +| `wrapUnsafeCSS` | Places custom CSS in its cascade layer. | +| `patchScrollbarGutterSize` | Updates the measured scrollbar gutter in theme CSS. | +| `detachString` | Copies a retained substring to an independent backing string. | +| `releaseStringDetachBuffer` | Resets the reusable string copy buffer. | +| `SVGSpriteSheet` | Contains the SVG symbols used by rendered controls. | +| `SVGSpriteNames` | Names a symbol in `SVGSpriteSheet`. | + +## Constants + +| Export | Purpose | +| ------------------------------------------ | ----------------------------------------------------- | +| `DEFAULT_THEMES` | Provides the default light and dark theme names. | +| `DEFAULT_TOKENIZE_MAX_LENGTH` | Provides the default total tokenization limit. | +| `DEFAULT_COLLAPSED_CONTEXT_THRESHOLD` | Provides the default hidden-context threshold. | +| `DEFAULT_EXPANDED_REGION` | Provides the default hunk expansion state. | +| `DEFAULT_RENDER_RANGE` | Provides the full render range. | +| `EMPTY_RENDER_RANGE` | Provides an empty render range. | +| `DEFAULT_VIRTUAL_FILE_METRICS` | Provides estimated file header and line heights. | +| `DEFAULT_CODE_VIEW_FILE_METRICS` | Provides list item height estimates. | +| `DEFAULT_CODE_VIEW_LAYOUT` | Provides an empty list layout. | +| `DEFAULT_SMOOTH_SCROLL_SETTINGS` | Provides the default smooth scroll settings. | +| `DIFFS_TAG_NAME` | Provides the `diffs-container` custom element name. | +| `CORE_CSS_ATTRIBUTE` | Provides the core style marker attribute. | +| `THEME_CSS_ATTRIBUTE` | Provides the theme style marker attribute. | +| `UNSAFE_CSS_ATTRIBUTE` | Provides the custom style marker attribute. | +| `DIFFS_SCROLLBAR_MEASURE_ATTRIBUTE` | Provides the scrollbar measurement attribute. | +| `DIFFS_SCROLLBAR_GUTTER_MEASURED_PROPERTY` | Provides the measured scrollbar CSS property. | +| `CODE_VIEW_HEADER_ATTRIBUTE` | Provides the list header host attribute. | +| `CODE_VIEW_FOOTER_ATTRIBUTE` | Provides the list footer host attribute. | +| `CUSTOM_HEADER_SLOT_ID` | Provides the custom header slot ID. | +| `HEADER_PREFIX_SLOT_ID` | Provides the header prefix slot ID. | +| `HEADER_FILENAME_SUFFIX_SLOT_ID` | Provides the filename suffix slot ID. | +| `HEADER_METADATA_SLOT_ID` | Provides the header metadata slot ID. | +| `HUNK_HEADER` | Provides the patch hunk header marker. | +| `FILE_CONTEXT_BLOB` | Matches a patch hunk boundary. | +| `INDEX_LINE_METADATA` | Provides the patch index metadata marker. | +| `COMMIT_METADATA_SPLIT` | Provides the commit metadata separator expression. | +| `FILENAME_HEADER_REGEX` | Matches a standard patch file header. | +| `FILENAME_HEADER_REGEX_GIT` | Matches a Git patch file header. | +| `GIT_DIFF_FILE_BREAK_REGEX` | Matches a Git patch file boundary. | +| `UNIFIED_DIFF_FILE_BREAK_REGEX` | Matches a unified patch file boundary. | +| `ALTERNATE_FILE_NAMES_GIT` | Matches alternate file names in a Git patch header. | +| `MERGE_CONFLICT_START_MARKER_REGEX` | Matches a conflict start marker. | +| `MERGE_CONFLICT_BASE_MARKER_REGEX` | Matches a conflict base marker. | +| `MERGE_CONFLICT_SEPARATOR_MARKER_REGEX` | Matches a conflict separator marker. | +| `MERGE_CONFLICT_END_MARKER_REGEX` | Matches a conflict end marker. | +| `SPLIT_WITH_NEWLINES` | Splits text while it preserves newline tokens. | +| `DIFFS_DEVELOPMENT_BUILD` | Reports whether the package uses a development build. | diff --git a/skills/diffs/references/api-ssr.md b/skills/diffs/references/api-ssr.md new file mode 100644 index 000000000..6f5b7e61f --- /dev/null +++ b/skills/diffs/references/api-ssr.md @@ -0,0 +1,35 @@ +# SSR API + +This reference lists the SSR-specific exports from `@pierre/diffs/ssr`. The +entry also re-exports every type in [Shared types](api-types.md). + +## Functions + +| Export | Purpose | +| --------------------------- | ------------------------------------------------------------- | +| `preloadFile` | Renders one file and returns props with `prerenderedHTML`. | +| `preloadFileDiff` | Renders pre-parsed diff metadata and returns component props. | +| `preloadMultiFileDiff` | Parses and renders an old and new file pair. | +| `preloadPatchDiff` | Parses and renders one patch for `PatchDiff`. | +| `preloadPatchFile` | Parses a multi-file patch and returns one result per file. | +| `preloadUnresolvedFile` | Renders one merge-conflict file and returns component props. | +| `preloadDiffHTML` | Renders a diff directly to an HTML string. | +| `preloadUnresolvedFileHTML` | Renders a merge-conflict file directly to an HTML string. | +| `renderHTML` | Serializes rendered HAST elements to HTML. | + +## Types + +| Export | Purpose | +| ------------------------------ | -------------------------------------------------------- | +| `PreloadFileOptions` | Defines input for `preloadFile`. | +| `PreloadedFileResult` | Adds `prerenderedHTML` to file input. | +| `PreloadDiffOptions` | Defines parsed or file-pair input for `preloadDiffHTML`. | +| `PreloadFileDiffOptions` | Defines input for `preloadFileDiff`. | +| `PreloadFileDiffResult` | Adds `prerenderedHTML` to parsed diff input. | +| `PreloadMultiFileDiffOptions` | Defines input for `preloadMultiFileDiff`. | +| `PreloadMultiFileDiffResult` | Adds `prerenderedHTML` to file-pair input. | +| `PreloadPatchDiffOptions` | Defines input for `preloadPatchDiff`. | +| `PreloadPatchDiffResult` | Adds `prerenderedHTML` to patch input. | +| `PreloadPatchFileOptions` | Defines input for `preloadPatchFile`. | +| `PreloadUnresolvedFileOptions` | Defines input for `preloadUnresolvedFile`. | +| `PreloadUnresolvedFileResult` | Adds `prerenderedHTML` to merge-conflict input. | diff --git a/skills/diffs/references/api-types.md b/skills/diffs/references/api-types.md new file mode 100644 index 000000000..deed8152d --- /dev/null +++ b/skills/diffs/references/api-types.md @@ -0,0 +1,176 @@ +# Shared types + +This reference lists every export from the shared `@pierre/diffs` type module. +The root, React, and SSR entries re-export these types. + +## Contents + +- [Files and patches](#files-and-patches) +- [Themes and options](#themes-and-options) +- [Annotations and selection](#annotations-and-selection) +- [`CodeView` types](#codeview-types) +- [Lines, hunks, and render state](#lines-hunks-and-render-state) +- [Render results and virtualization](#render-results-and-virtualization) +- [Component and editor contracts](#component-and-editor-contracts) +- [Shiki and diff types](#shiki-and-diff-types) + +## Files and patches + +| Export | Purpose | +| ------------------------------- | ----------------------------------------------------------------- | +| `FileContents` | Describes a file name, text, language, header, and cache key. | +| `DiffFileInput` | Accepts an old and new file for changes, additions, or deletions. | +| `MaybeDiffFileInput` | Accepts a file pair or no file input. | +| `FileDiffContentsLoader` | Loads complete files for partial diff metadata. | +| `FileDiffLoadedChangedFiles` | Returns both files for a loaded changed diff. | +| `FileDiffLoadedPureRenamedFile` | Returns the new file for a loaded pure rename. | +| `FileDiffLoadedFiles` | Represents either loaded-file result. | +| `ChangeTypes` | Names changed, renamed, added, or deleted file states. | +| `ParsedPatch` | Holds patch metadata and parsed files. | +| `ContextContent` | Describes one unchanged hunk block. | +| `ChangeContent` | Describes one additions and deletions block. | +| `Hunk` | Describes one parsed patch hunk. | +| `FileDiffMetadata` | Holds parsed file names, lines, hunks, and change metadata. | +| `MergeConflictMarkerRowType` | Names a merge conflict marker row. | +| `MergeConflictMarkerRow` | Describes one marker row and its source line. | +| `MergeConflictRegion` | Describes one parsed merge conflict region. | +| `MergeConflictResolution` | Selects current, incoming, or both conflict contents. | +| `MergeConflictActionPayload` | Describes one conflict action and region. | +| `ProcessFileConflictData` | Holds state while patch parsing processes conflicts. | +| `ConflictResolverTypes` | Names current, incoming, or both conflict choices. | + +## Themes and options + +| Export | Purpose | +| ------------------------------------ | ------------------------------------------------------------ | +| `SupportedLanguages` | Accepts a bundled, text, ANSI, or custom language name. | +| `HighlighterTypes` | Selects the JavaScript or WebAssembly Shiki engine. | +| `HighlightedToken` | Stores a character index, foreground, and token text. | +| `DiffsThemeNames` | Accepts a bundled or custom theme name. | +| `ThemesType` | Maps light and dark schemes to theme names. | +| `ThemeTypes` | Selects system, light, or dark mode. | +| `DiffsHighlighter` | Defines the package's configured Shiki highlighter. | +| `BaseCodeOptions` | Configures themes, wrapping, headers, tokenization, and CSS. | +| `BaseDiffOptions` | Adds layout, indicators, context, and line diff options. | +| `BaseDiffOptionsWithDefaults` | Describes required diff options after defaults apply. | +| `DiffIndicators` | Selects classic, bar, or hidden diff indicators. | +| `HunkSeparators` | Selects the hunk separator presentation. | +| `LineDiffTypes` | Selects word, alternate word, character, or no inline diff. | +| `FileHeaderRenderMode` | Selects a default or custom file header. | +| `CustomPreProperties` | Defines custom properties for the rendered `pre` element. | +| `PrePropertiesConfig` | Describes calculated `pre` element properties. | +| `ExtensionFormatMap` | Maps file names or extensions to languages. | +| `RenderHeaderPrefixCallback` | Produces prefix content for a diff header. | +| `RenderHeaderFilenameSuffixCallback` | Produces filename suffix content for a diff header. | +| `RenderHeaderMetadataCallback` | Produces metadata content for a diff header. | +| `RenderFileMetadata` | Produces header content for a file. | +| `PostRenderPhase` | Names mount, update, or unmount callback phases. | + +## Annotations and selection + +| Export | Purpose | +| ------------------------- | ------------------------------------------------------------ | +| `AnnotationSide` | Selects deletions or additions for an annotation. | +| `LineAnnotation` | Associates metadata with one file line. | +| `DiffLineAnnotation` | Associates metadata with one side and line. | +| `AnnotationLineMap` | Groups diff annotations by line number. | +| `SelectedLineRange` | Describes a selected start and end across diff sides. | +| `SelectionSide` | Selects deletions or additions for a selection. | +| `SelectionPoint` | Describes one line and optional side. | +| `SelectionDirection` | Describes backward, neutral, or forward selection direction. | +| `EditorActiveLineOptions` | Configures reveal behavior for an editor active line. | + +## `CodeView` types + +| Export | Purpose | +| ------------------------------ | -------------------------------------------------------- | +| `CodeViewFileItem` | Describes one file item in a virtualized list. | +| `CodeViewDiffItem` | Describes one diff item in a virtualized list. | +| `CodeViewItem` | Represents a file or diff list item. | +| `CodeViewCreateEditorOptions` | Adds an item ID to editor creation options. | +| `CodeViewScrollBehavior` | Selects instant, smooth, or automatic smooth scroll. | +| `CodeViewScrollTarget` | Represents any supported list scroll target. | +| `CodeViewPositionScrollTarget` | Scrolls to an absolute list position. | +| `CodeViewLineScrollTarget` | Scrolls to one item line. | +| `CodeViewRangeScrollTarget` | Scrolls to one item line range. | +| `CodeViewItemScrollTarget` | Scrolls to one item boundary. | +| `NumericScrollLineAnchor` | Describes a numeric position inside a line. | +| `CodeViewLayout` | Stores item offsets, heights, and total list height. | +| `PendingCodeViewLayoutReset` | Describes a deferred list layout reset. | +| `SmoothScrollSettings` | Configures duration and distance for smooth list scroll. | + +## Lines, hunks, and render state + +| Export | Purpose | +| ---------------------------- | --------------------------------------------------------------- | +| `HunkLineType` | Names context, expanded, addition, deletion, or metadata lines. | +| `HunkData` | Describes one hunk's render indexes and line ranges. | +| `HunkExpansionRegion` | Describes expanded context above and below a hunk. | +| `ExpansionDirections` | Selects up, down, or both expansion directions. | +| `DiffAcceptRejectHunkType` | Selects accept, reject, or both hunk controls. | +| `DiffAcceptRejectHunkConfig` | Configures hunk accept and reject behavior. | +| `GapSpan` | Describes an empty row span. | +| `AnnotationSpan` | Describes an annotation row span. | +| `LineSpans` | Represents a gap or annotation span. | +| `LineTypes` | Names rendered context and change line classes. | +| `LineInfo` | Describes a rendered line number, side, and type. | +| `CodeColumnType` | Selects unified, additions, or deletions columns. | +| `LineEventBaseProps` | Supplies a file line to an interaction callback. | +| `DiffLineEventBaseProps` | Supplies a diff line and side to an interaction callback. | +| `TokenEventBase` | Supplies a token and source event. | +| `DiffTokenEventBaseProps` | Adds diff side data to a token event. | +| `ObservedAnnotationNodes` | Stores DOM nodes for observed annotations. | +| `ObservedGridNodes` | Stores DOM nodes for observed grid columns. | +| `SharedRenderState` | Holds shared token transformer render state. | +| `StickySpecs` | Describes sticky header position and height. | + +## Render results and virtualization + +| Export | Purpose | +| --------------------------- | ------------------------------------------------------- | +| `RenderFileOptions` | Defines the resolved options for a highlighted file. | +| `RenderDiffOptions` | Defines the resolved options for a highlighted diff. | +| `ForceFilePlainTextOptions` | Selects a plain-text file range. | +| `ForceDiffPlainTextOptions` | Selects a plain-text diff range and hunk state. | +| `ThemedFileResult` | Holds the highlighted file syntax tree and line count. | +| `ThemedDiffResult` | Holds highlighted additions and deletions syntax trees. | +| `RenderDiffFilesResult` | Holds the resolved old and new file inputs. | +| `RenderFileResult` | Holds file output and the options that produced it. | +| `RenderDiffResult` | Holds diff output and the options that produced it. | +| `RenderedFileASTCache` | Stores one cached file syntax tree by theme. | +| `RenderedDiffASTCache` | Stores one cached diff syntax tree by theme. | +| `AppliedThemeStyleCache` | Stores applied light and dark theme CSS. | +| `RenderRange` | Describes a start row, row count, and buffer sizes. | +| `RenderWindow` | Describes first and last rows in a render window. | +| `VirtualWindowSpecs` | Describes viewport position, height, and row window. | +| `VirtualFileMetrics` | Describes estimated header and line heights. | + +## Component and editor contracts + +| Export | Purpose | +| ------------------------ | ----------------------------------------------------------- | +| `DiffsComponentOptions` | Defines shared options for a render component. | +| `DiffsBaseComponent` | Defines the common file and diff component methods. | +| `DiffsEditableComponent` | Adds editor attachment and document updates to a component. | +| `EditableInstance` | Selects an editable file or diff instance. | +| `DiffsEditor` | Defines the editor interface that render components use. | +| `DiffsTextDocument` | Defines the text document interface that components use. | +| `Position` | Identifies a zero-based line and character. | +| `Range` | Identifies start and end positions. | +| `TextEdit` | Replaces one range with new text. | +| `EditorSelection` | Adds direction to a range. | +| `EditorState` | Holds editor selections and view state. | + +## Shiki and diff types + +| Export | Purpose | +| -------------------------------- | ----------------------------------------------- | +| `BundledLanguage` | Names a language bundled by Shiki. | +| `CodeToHastOptions` | Configures Shiki code-to-HAST output. | +| `DecorationItem` | Describes a Shiki source decoration. | +| `LanguageRegistration` | Describes a Shiki language grammar. | +| `ShikiTransformer` | Defines a Shiki syntax tree transformer. | +| `ThemeRegistration` | Describes a raw Shiki theme. | +| `ThemeRegistrationResolved` | Describes a normalized Shiki theme. | +| `ThemedToken` | Describes one Shiki token with its theme style. | +| `CreatePatchOptionsNonabortable` | Configures the underlying patch algorithm. | diff --git a/skills/diffs/references/api-worker.md b/skills/diffs/references/api-worker.md new file mode 100644 index 000000000..cb204dac6 --- /dev/null +++ b/skills/diffs/references/api-worker.md @@ -0,0 +1,91 @@ +# Worker API + +This reference lists every export from `@pierre/diffs/worker`, every public +`WorkerPoolManager` member, and both worker script entries. + +## Runtime exports + +| Export | Kind | Purpose | +| -------------------------------- | -------- | ----------------------------------------------------- | +| `WorkerPoolManager` | Class | Runs file and diff highlighting across a worker pool. | +| `getOrCreateWorkerPoolSingleton` | Function | Gets or creates the module-wide worker pool. | +| `terminateWorkerPoolSingleton` | Function | Terminates and clears the module-wide worker pool. | + +## `WorkerPoolManager` members + +| Member | Purpose | +| -------------------------------------------------------------- | ------------------------------------------------- | +| `new WorkerPoolManager(options, renderOptions)` | Creates a worker pool. | +| `initialize(languages?)` | Starts workers and loads languages. | +| `isInitialized()` | Reports whether initialization finished. | +| `isWorkingPool()` | Reports whether workers can accept work. | +| `setRenderOptions(options)` | Updates theme and render settings in each worker. | +| `getFileRenderOptions()` | Gets active file render options. | +| `getDiffRenderOptions()` | Gets active diff render options. | +| `highlightFileAST(instance, file)` | Queues a highlighted file result for an instance. | +| `highlightDiffAST(instance, diff)` | Queues a highlighted diff result for an instance. | +| `primeFileHighlightCache(file)` | Preloads one highlighted file result. | +| `primeDiffHighlightCache(diff)` | Preloads one highlighted diff result. | +| `getFileResultCache(file)` | Gets one cached file result. | +| `getDiffResultCache(diff)` | Gets one cached diff result. | +| `getPlainFileAST(file, start, total, lines?)` | Gets a plain-text file result. | +| `getPlainDiffAST(diff, start, total, expansions?, threshold?)` | Gets a plain-text diff result. | +| `inspectCaches()` | Gets both result caches. | +| `evictFileFromCache(cacheKey)` | Removes one file cache entry. | +| `evictDiffFromCache(cacheKey)` | Removes one diff cache entry. | +| `subscribeToThemeChanges(instance)` | Subscribes a render instance to theme changes. | +| `unsubscribeToThemeChanges(instance)` | Removes a theme subscription. | +| `subscribeToStatChanges(callback)` | Subscribes to worker statistics. | +| `cleanUpTasks(instance)` | Removes queued and active tasks for an instance. | +| `getStats()` | Gets worker and cache statistics. | +| `terminate()` | Stops workers and clears pool resources. | + +## Configuration and state types + +| Export | Purpose | +| ----------------------------------- | ----------------------------------------------------------------- | +| `SetupWorkerPoolProps` | Combines pool and highlighter options for the singleton. | +| `WorkerPoolOptions` | Defines the worker factory, pool size, and cache size. | +| `WorkerInitializationRenderOptions` | Defines initial languages, theme, highlighter, and diff settings. | +| `WorkerRenderingOptions` | Defines the complete worker render settings. | +| `WorkerStats` | Describes pool state, work counts, subscribers, and cache sizes. | +| `WorkerRequestId` | Identifies one worker request. | +| `ResolvedLanguage` | Holds a resolved language registration. | +| `FileRendererInstance` | Defines callbacks for a file render consumer. | +| `DiffRendererInstance` | Defines callbacks for a diff render consumer. | + +## Request and response types + +| Export | Purpose | +| ------------------------------- | ------------------------------------------------------- | +| `WorkerRequest` | Represents any request sent to a worker. | +| `InitializeWorkerRequest` | Starts a worker with themes, languages, and options. | +| `SetRenderOptionsWorkerRequest` | Updates render options and themes. | +| `RenderFileRequest` | Requests one file render. | +| `RenderDiffRequest` | Requests one diff render. | +| `SubmitRequest` | Represents a file or diff request before ID assignment. | +| `WorkerResponse` | Represents any worker response. | +| `InitializeSuccessResponse` | Confirms worker initialization. | +| `RegisterThemeSuccessResponse` | Confirms a render-option and theme update. | +| `RenderSuccessResponse` | Represents a successful file or diff render. | +| `RenderFileSuccessResponse` | Returns one file render result. | +| `RenderDiffSuccessResponse` | Returns one diff render result. | +| `RenderErrorResponse` | Returns a serialized worker error. | + +## Task types + +| Export | Purpose | +| ---------------------------- | ------------------------------------------------- | +| `AllWorkerTasks` | Represents any manager task. | +| `InitializeWorkerTask` | Tracks one initialization request. | +| `SetRenderOptionsWorkerTask` | Tracks one render-option update. | +| `RenderFileTask` | Tracks one file render request and its consumers. | +| `RenderDiffTask` | Tracks one diff render request and its consumers. | +| `RenderTaskCallbacks` | Resolves or rejects one render task consumer. | + +## Worker script entries + +| Import | Purpose | +| ----------------------------------------- | ---------------------------------------------------------- | +| `@pierre/diffs/worker/worker.js` | Supplies the module worker that uses package dependencies. | +| `@pierre/diffs/worker/worker-portable.js` | Supplies a bundled module worker. | diff --git a/skills/diffs/references/recipe-annotations.md b/skills/diffs/references/recipe-annotations.md new file mode 100644 index 000000000..7707e93f3 --- /dev/null +++ b/skills/diffs/references/recipe-annotations.md @@ -0,0 +1,32 @@ +# Recipe: add line annotations and selection + +Pass annotation data and a renderer to the surface: + +```tsx +import type { DiffLineAnnotation } from '@pierre/diffs/react'; +import { MultiFileDiff } from '@pierre/diffs/react'; + +const annotations: DiffLineAnnotation<{ message: string }>[] = [ + { + side: 'additions', + lineNumber: 8, + metadata: { message: 'Review this line.' }, + }, +]; + +

{annotation.metadata.message}

} + options={{ + enableLineSelection: true, + onLineSelectionEnd(range) { + saveSelection(range); + }, + }} +/>; +``` + +Use `LineAnnotation` for a single file. Use `DiffLineAnnotation` for a diff. +Control the active selection with the `selectedLines` prop. diff --git a/skills/diffs/references/recipe-code-view.md b/skills/diffs/references/recipe-code-view.md new file mode 100644 index 000000000..36d818c0a --- /dev/null +++ b/skills/diffs/references/recipe-code-view.md @@ -0,0 +1,213 @@ +# Recipe: build a `CodeView` + +Use `CodeView` when one scroll region contains many files, diffs, or both. It +manages item virtualization, sticky headers, list-wide selection, and item or +line scroll targets. + +## Contents + +- [Select item ownership](#select-item-ownership) +- [Define items](#define-items) +- [Use controlled React state](#use-controlled-react-state) +- [Use imperative ownership](#use-imperative-ownership) +- [Enable item edit mode](#enable-item-edit-mode) + +## Select item ownership + +| Host and data flow | Input | Update API | +| ------------------------------------------- | ----------------- | ------------------------------------ | +| React owns the complete list | `items` | Publish a new `items` array. | +| React hosts a large or append-only list | `initialItems` | Use the `CodeViewHandle` methods. | +| Vanilla JavaScript owns the viewer instance | `setItems(items)` | Use the `CodeView` instance methods. | + +Keep one ownership mode for the life of a mounted React viewer. Use controlled +state when item data already belongs to React. Use imperative ownership for a +large or streamed list. + +## Define items + +Give each item a stable and unique `id`. Use a `file` item for `FileContents`. +Use a `diff` item for `FileDiffMetadata`. + +Increment `version` when an existing item changes its contents, annotations, +collapsed state, or edit state. `CodeView` uses the ID and version to select the +item that it must update. + +## Use controlled React state + +```tsx +import { + parseDiffFromFile, + type CodeViewItem, + type CodeViewLineSelection, +} from '@pierre/diffs'; +import { CodeView, type CodeViewHandle } from '@pierre/diffs/react'; +import { useRef, useState } from 'react'; + +const oldFile = { + name: 'src/value.ts', + contents: 'export const value = 1;', +}; +const newFile = { + name: 'src/value.ts', + contents: 'export const value = 2;', +}; +const codeViewStyle = { height: 600, overflow: 'auto' } as const; +const codeViewOptions = { + theme: { light: 'pierre-light', dark: 'pierre-dark' }, + stickyHeaders: true, + enableLineSelection: true, + layout: { paddingTop: 16, paddingBottom: 16, gap: 12 }, +} as const; + +export function ReviewSurface() { + const viewerRef = useRef | null>(null); + const [selection, setSelection] = useState( + null + ); + const [items, setItems] = useState(() => [ + { + id: 'diff:src/value.ts', + type: 'diff', + fileDiff: parseDiffFromFile(oldFile, newFile), + version: 0, + }, + { + id: 'file:README.md', + type: 'file', + file: { name: 'README.md', contents: '# Review notes' }, + version: 0, + }, + ]); + + function toggleDiff() { + setItems((current) => + current.map((item) => + item.id === 'diff:src/value.ts' + ? { + ...item, + collapsed: !item.collapsed, + version: (item.version ?? 0) + 1, + } + : item + ) + ); + } + + return ( + <> + + + + + ); +} +``` + +## Use imperative ownership + +In React, pass `initialItems` and keep `items` unset. Use the component ref to +call `addItems`, `getItem`, `updateItem`, `updateItemId`, or `scrollTo`. + +In vanilla JavaScript, configure and populate the instance directly: + +```ts +import { CodeView, parseDiffFromFile } from '@pierre/diffs'; + +const root = document.querySelector('#review'); +if (root == null) throw new Error('Missing review host'); + +const oldFile = { + name: 'src/value.ts', + contents: 'export const value = 1;', +}; +const newFile = { + name: 'src/value.ts', + contents: 'export const value = 2;', +}; + +const viewer = new CodeView({ + theme: { light: 'pierre-light', dark: 'pierre-dark' }, + stickyHeaders: true, + enableLineSelection: true, + onSelectedLinesChange(selection) { + console.log('selected lines', selection); + }, +}); + +root.style.height = '600px'; +root.style.overflow = 'auto'; +viewer.setup(root); +viewer.setItems([ + { + id: 'diff:src/value.ts', + type: 'diff', + fileDiff: parseDiffFromFile(oldFile, newFile), + version: 0, + }, +]); + +viewer.addItems([ + { + id: 'file:README.md', + type: 'file', + file: { name: 'README.md', contents: '# Review notes' }, + version: 0, + }, +]); +viewer.scrollTo({ + type: 'item', + id: 'diff:src/value.ts', + align: 'start', +}); + +const item = viewer.getItem('diff:src/value.ts'); +if (item != null) { + viewer.updateItem({ + ...item, + collapsed: true, + version: (item.version ?? 0) + 1, + }); +} + +export function removeReviewSurface() { + viewer.cleanUp(); +} +``` + +## Enable item edit mode + +In React, wrap `CodeView` in `EditProvider`. In vanilla JavaScript, pass +`createEditor` in `CodeViewOptions`. Set `edit: true` on each editable item and +increment its version. + +Use `onItemEditChange` for live contents and annotation changes. Use +`onItemEditComplete` to write the final contents into the item, disable edit +mode, assign a fresh `cacheKey`, and increment `version`. Use `getEditor(id)` +for editor commands such as undo, redo, markers, or programmatic edits. + +Read [Edit with React](recipe-edit-react.md) or +[Edit with vanilla JavaScript](recipe-edit-vanilla.md) for the complete editor +lifecycle. diff --git a/skills/diffs/references/recipe-custom-highlighting.md b/skills/diffs/references/recipe-custom-highlighting.md new file mode 100644 index 000000000..22efc967f --- /dev/null +++ b/skills/diffs/references/recipe-custom-highlighting.md @@ -0,0 +1,19 @@ +# Recipe: register custom highlighting + +Register a language or theme before the first surface uses it: + +```ts +import { registerCustomLanguage, registerCustomTheme } from '@pierre/diffs'; + +registerCustomLanguage( + 'my-language', + () => import('./my-language.tmLanguage.json'), + ['myext'] +); + +registerCustomTheme('my-theme', () => import('./my-theme.json')); +``` + +Set `file.lang` to the custom language name. Set `options.theme` to the custom +theme name. Use `registerCustomCSSVariableTheme` when CSS variables supply the +theme colors. diff --git a/skills/diffs/references/recipe-edit-react.md b/skills/diffs/references/recipe-edit-react.md new file mode 100644 index 000000000..1d8fcf87a --- /dev/null +++ b/skills/diffs/references/recipe-edit-react.md @@ -0,0 +1,121 @@ +# Recipe: edit with React + +Mount one stable `EditProvider` above the editable surfaces. The provider +supplies an editor factory. Each active surface or `CodeView` item owns a +separate editor instance. + +## Contents + +- [Edit a standalone file or diff](#edit-a-standalone-file-or-diff) +- [Keep annotations synchronized](#keep-annotations-synchronized) +- [Edit CodeView items](#edit-codeview-items) + +## Edit a standalone file or diff + +Set `edit` on `File`, `FileDiff`, `MultiFileDiff`, or `PatchDiff`. Pass editor +behavior through `editOptions`. + +```tsx +import type { FileContents, FileDiffOptions } from '@pierre/diffs'; +import { Editor, type EditorOptions } from '@pierre/diffs/editor'; +import { EditProvider, MultiFileDiff, Virtualizer } from '@pierre/diffs/react'; +import { useMemo, useRef, useState } from 'react'; + +const oldFile: FileContents = { + name: 'src/value.ts', + contents: 'export const value = 1;', +}; +const initialNewFile: FileContents = { + name: 'src/value.ts', + contents: 'export const value = 2;', +}; +const diffOptions: FileDiffOptions = { + theme: { light: 'pierre-light', dark: 'pierre-dark' }, + diffStyle: 'split', +}; + +function createEditor(options: EditorOptions) { + return new Editor(options); +} + +export function EditableDiff() { + const [edit, setEdit] = useState(false); + const [newFile, setNewFile] = useState(initialNewFile); + const draftRef = useRef(newFile); + const editorRef = useRef | null>(null); + const editOptions = useMemo>( + () => ({ + onAttach(editor) { + editorRef.current = editor; + }, + onChange(file) { + draftRef.current = file; + saveDraft(file); + }, + }), + [] + ); + + function toggleEdit() { + if (edit) setNewFile(draftRef.current); + setEdit((value) => !value); + } + + return ( + + + + + + + + ); +} +``` + +Mount the provider near the application root when many surfaces use edit mode. +Keep `createEditor` and `editOptions` stable. Use `onAttach` when controls need +`undo`, `redo`, `applyEdits`, selections, markers, focus, or other editor APIs. + +## Keep annotations synchronized + +The `onChange` callback can supply the complete current annotation collection. +Replace the application collection when the callback supplies a different array. +Use `isFileAnnotationCollection` or `isDiffAnnotationCollection` to narrow its +type. + +Publish a changed React annotation array inside `flushSync`. This keeps its +coordinates aligned with the edited contents before paint. Store annotation UI +state by a stable metadata ID instead of a line number. + +## Edit `CodeView` items + +Wrap `CodeView` in the same `EditProvider`. Set `edit: true` on an item and +increment its `version`. Pass shared creation options through the `CodeView` +`editOptions` prop. + +Use `onItemEditChange` for live contents and annotation changes. Use +`onItemEditComplete` to commit the final `file` or rebuild the `fileDiff`. In +the same item update, set `edit: false`, assign a fresh `cacheKey`, and +increment `version`. + +Use the `CodeViewHandle.getEditor(id)` method for imperative editor commands. +The item editor keeps its document and history when virtualization removes the +item from the rendered window. + +When a worker pool highlights an editable surface, set +`useTokenTransformer: true` in the worker `highlighterOptions`. diff --git a/skills/diffs/references/recipe-edit-vanilla.md b/skills/diffs/references/recipe-edit-vanilla.md new file mode 100644 index 000000000..35f705928 --- /dev/null +++ b/skills/diffs/references/recipe-edit-vanilla.md @@ -0,0 +1,163 @@ +# Recipe: edit with vanilla JavaScript + +Render a standalone surface first. Then attach one `Editor` to it. Use one +editor for each surface that can be edited at the same time. + +## Contents + +- [Edit a standalone diff](#edit-a-standalone-diff) +- [Edit CodeView items](#edit-codeview-items) + +## Edit a standalone diff + +```ts +import { + FileDiff, + isDiffAnnotationCollection, + type DiffLineAnnotation, + type FileContents, +} from '@pierre/diffs'; +import { Editor } from '@pierre/diffs/editor'; + +interface ThreadMetadata { + id: string; +} + +const hostElement = document.querySelector('#diff'); +if (hostElement == null) throw new Error('Missing diff host'); +const host: HTMLElement = hostElement; + +const oldFile: FileContents = { + name: 'src/value.ts', + contents: 'export const value = 1;', +}; +let newFile: FileContents = { + name: 'src/value.ts', + contents: 'export const value = 2;', +}; +let annotations: DiffLineAnnotation[] = [ + { + side: 'additions', + lineNumber: 1, + metadata: { id: 'value-review' }, + }, +]; + +const view = new FileDiff({ + theme: { light: 'pierre-light', dark: 'pierre-dark' }, + renderAnnotation(annotation) { + const element = document.createElement('p'); + element.textContent = 'Thread ' + annotation.metadata.id; + return element; + }, +}); + +function render() { + view.render({ + fileContainer: host, + oldFile, + newFile, + lineAnnotations: annotations, + }); +} + +render(); + +const editor = new Editor({ + onChange(file, nextAnnotations) { + newFile = { ...newFile, contents: file.contents }; + saveDraft(newFile); + + if ( + nextAnnotations != null && + isDiffAnnotationCollection(nextAnnotations) && + nextAnnotations !== annotations + ) { + annotations = nextAnnotations; + queueMicrotask(render); + } + }, +}); + +const detach = editor.edit(view); + +export function stopEditing() { + detach(); +} + +export function removeSurface() { + editor.cleanUp(); + view.cleanUp(); +} +``` + +The annotation array from `onChange` is the complete current collection. Save it +before a later render can apply old coordinates. Use stable metadata IDs for +application state that belongs to an annotation. + +Use `VirtualizedFile` or `VirtualizedFileDiff` with a `Virtualizer` for a large +standalone surface. Load `@pierre/diffs/editor` with `import()` when edit mode +is optional and the initial bundle must omit the editor. + +## Edit `CodeView` items + +Pass a factory through `CodeViewOptions.createEditor`: + +```ts +import { CodeView } from '@pierre/diffs'; +import { Editor } from '@pierre/diffs/editor'; + +export function mountEditableCodeView(root: HTMLElement) { + const viewer = new CodeView({ + createEditor(options) { + return new Editor(options); + }, + onItemEditChange(item, file, nextAnnotations) { + saveItemDraft(item.id, file, nextAnnotations); + }, + onItemEditComplete(item, file) { + const current = viewer.getItem(item.id); + if (current?.type !== 'file') return; + + const version = (current.version ?? 0) + 1; + viewer.updateItem({ + ...current, + edit: false, + version, + file: { + ...file, + cacheKey: current.id + ':v' + version, + }, + }); + }, + }); + + viewer.setup(root); + viewer.setItems([ + { + id: 'file:src/value.ts', + type: 'file', + file: { + name: 'src/value.ts', + contents: 'export const value = 1;', + }, + edit: true, + version: 0, + }, + ]); + + return viewer; +} +``` + +Set `edit: true` on an item and increment its `version`. In +`onItemEditComplete`, write the final contents into that item, set +`edit: false`, assign a fresh `cacheKey`, and increment `version` again. +`CodeView` creates and removes the item editors. + +Call `viewer.getEditor(id)` for `undo`, `redo`, `applyEdits`, selections, +markers, focus, or other editor commands. Call `viewer.cleanUp()` when the host +removes the viewer. + +When a worker pool highlights an editable surface, set +`useTokenTransformer: true` in the worker `highlighterOptions`. diff --git a/skills/diffs/references/recipe-react.md b/skills/diffs/references/recipe-react.md new file mode 100644 index 000000000..f1048230f --- /dev/null +++ b/skills/diffs/references/recipe-react.md @@ -0,0 +1,37 @@ +# Recipe: render with React + +## Select a surface + +| Input or layout | Component | +| ------------------------------------------- | ---------------- | +| One `FileContents` object | `File` | +| Old and new `FileContents` objects | `MultiFileDiff` | +| Existing `FileDiffMetadata` | `FileDiff` | +| One unified patch string | `PatchDiff` | +| One file with merge conflicts | `UnresolvedFile` | +| One scroll region with many files and diffs | `CodeView` | + +Use `MultiFileDiff` when the app has old and new file contents: + +```tsx +import { MultiFileDiff } from '@pierre/diffs/react'; + +; +``` + +Pass source data, annotations, and slot renderers as component props. Pass +display, theme, interaction, and highlighting settings through `options`. + +Keep file objects and option objects stable when their values do not change. +Wrap a large standalone surface in `Virtualizer`. Use `CodeView` when one scroll +region contains a list of files or diffs. + +Use the matching preload function from `@pierre/diffs/ssr` when the server must +render the initial highlighted markup. diff --git a/skills/diffs/references/recipe-ssr.md b/skills/diffs/references/recipe-ssr.md new file mode 100644 index 000000000..6899453e3 --- /dev/null +++ b/skills/diffs/references/recipe-ssr.md @@ -0,0 +1,20 @@ +# Recipe: preload a diff on the server + +Create props on the server and pass the result to the matching React component: + +```tsx +import { preloadMultiFileDiff } from '@pierre/diffs/ssr'; +import { MultiFileDiff } from '@pierre/diffs/react'; + +const preloaded = await preloadMultiFileDiff({ + oldFile: { name: 'src/value.ts', contents: oldSource }, + newFile: { name: 'src/value.ts', contents: newSource }, + options: { theme: 'pierre-dark', diffStyle: 'split' }, +}); + +; +``` + +Select the preload function that matches the client component. Use +`preloadDiffHTML` or `preloadUnresolvedFileHTML` when the host needs an HTML +string only. diff --git a/skills/diffs/references/recipe-vanilla.md b/skills/diffs/references/recipe-vanilla.md new file mode 100644 index 000000000..ebb8841b1 --- /dev/null +++ b/skills/diffs/references/recipe-vanilla.md @@ -0,0 +1,41 @@ +# Recipe: render with vanilla JavaScript + +## Select a surface + +| Input or layout | Class | +| ------------------------------------------- | --------------------- | +| One `FileContents` object | `File` | +| Existing or parsed `FileDiffMetadata` | `FileDiff` | +| One file with merge conflicts | `UnresolvedFile` | +| One large file | `VirtualizedFile` | +| One large diff | `VirtualizedFileDiff` | +| One scroll region with many files and diffs | `CodeView` | + +Parse the files, create the view, and render it into a host: + +```ts +import { FileDiff, parseDiffFromFile } from '@pierre/diffs'; + +const host = document.querySelector('#diff'); +if (host == null) throw new Error('Missing diff host'); + +const fileDiff = parseDiffFromFile( + { name: 'src/value.ts', contents: oldSource }, + { name: 'src/value.ts', contents: newSource } +); + +const view = new FileDiff({ + diffStyle: 'split', + theme: 'pierre-dark', +}); + +view.render({ fileContainer: host, fileDiff }); +``` + +Keep the class instance while the host remains mounted. Call `render` again when +the source data changes. Call `setOptions`, `setThemeType`, +`setLineAnnotations`, or `setSelectedLines` for targeted updates. + +Use a `Virtualizer` with `VirtualizedFile` or `VirtualizedFileDiff` for one +large surface. Use `CodeView` for a list that shares one scroll region. Call +`cleanUp()` when the host removes the surface. diff --git a/skills/diffs/references/recipe-workers.md b/skills/diffs/references/recipe-workers.md new file mode 100644 index 000000000..fbe7cc6f8 --- /dev/null +++ b/skills/diffs/references/recipe-workers.md @@ -0,0 +1,28 @@ +# Recipe: use a worker pool + +Wrap React diff surfaces in one provider: + +```tsx +import { WorkerPoolContextProvider } from '@pierre/diffs/react'; + + + new Worker(new URL('@pierre/diffs/worker/worker.js', import.meta.url), { + type: 'module', + }), + }} + highlighterOptions={{ + langs: ['typescript', 'tsx'], + theme: { light: 'pierre-light', dark: 'pierre-dark' }, + }} +> + {children} +; +``` + +For vanilla JavaScript, call `getOrCreateWorkerPoolSingleton` and pass the +result as the second constructor argument to a render class. Call +`terminateWorkerPoolSingleton()` when the application tears down the shared +pool. From 42a741387ee9f238d50d0360625f4f9da71bf70c Mon Sep 17 00:00:00 2001 From: Nicolas Gallagher <239676+necolas@users.noreply.github.com> Date: Wed, 22 Jul 2026 12:19:02 -0700 Subject: [PATCH 2/4] agents(theme): Add package usage skill Document every theme entry and help agents select a variant for Shiki or an editor. Add the package README command that installs only the theme skill from this repository. --- packages/theme/README.md | 9 +++++ skills/theme/SKILL.md | 35 ++++++++++++++++++ skills/theme/references/api.md | 45 ++++++++++++++++++++++++ skills/theme/references/recipe-editor.md | 16 +++++++++ skills/theme/references/recipe-shiki.md | 22 ++++++++++++ skills/theme/references/variants.md | 17 +++++++++ 6 files changed, 144 insertions(+) create mode 100644 skills/theme/SKILL.md create mode 100644 skills/theme/references/api.md create mode 100644 skills/theme/references/recipe-editor.md create mode 100644 skills/theme/references/recipe-shiki.md create mode 100644 skills/theme/references/variants.md diff --git a/packages/theme/README.md b/packages/theme/README.md index 2e51b77e5..5123feae0 100644 --- a/packages/theme/README.md +++ b/packages/theme/README.md @@ -45,6 +45,15 @@ Usage: ``` +## Agent skill + +Install the agent skill for this package with the +[Skills CLI](https://skills.sh/docs/cli): + +```bash +npx skills add pierrecomputer/pierre --skill theme +``` + Contributing: - Development, build, and testing: [CONTRIBUTING.md](CONTRIBUTING.md) diff --git a/skills/theme/SKILL.md b/skills/theme/SKILL.md new file mode 100644 index 000000000..8b69b1c19 --- /dev/null +++ b/skills/theme/SKILL.md @@ -0,0 +1,35 @@ +--- +name: theme +description: + Use when an app needs a Pierre light or dark theme from @pierre/theme for + Shiki, VS Code, Cursor, or Zed, including soft, vibrant, protanopia, + deuteranopia, and tritanopia variants. +--- + +# `@pierre/theme` + +Use `@pierre/theme` for Pierre syntax and editor themes. The package supplies +ten immutable Shiki and VS Code theme objects. + +## Install + +```bash +pnpm add @pierre/theme +``` + +## Select an API reference + +| Need | Reference | +| --------------------------------------- | ---------------------------------------- | +| List every package entry and export | [API reference](references/api.md) | +| Compare all themes and select a variant | [Theme variants](references/variants.md) | + +## Select a recipe + +| Task | Recipe | +| ----------------------------------- | ------------------------------------------------------- | +| Load a Pierre theme in Shiki | [Use a theme with Shiki](references/recipe-shiki.md) | +| Install a Pierre theme in an editor | [Use a theme in an editor](references/recipe-editor.md) | + +Use the `theming` skill when the app must switch themes at runtime or follow a +color mode. diff --git a/skills/theme/references/api.md b/skills/theme/references/api.md new file mode 100644 index 000000000..e9f41981f --- /dev/null +++ b/skills/theme/references/api.md @@ -0,0 +1,45 @@ +# `@pierre/theme` API reference + +This reference lists every public package entry. + +## Main entry + +| Import | Export | Purpose | +| --------------- | ------------ | ------------------------------------------- | +| `@pierre/theme` | `themeNames` | Lists the ten theme names in package order. | + +## Theme entries + +Each entry has one default export. The export is an immutable Pierre theme +object. + +| Import | Theme name | Color scheme | Purpose | +| ---------------------------------------------------- | -------------------------------------- | ------------ | ---------------------------------------------------- | +| `@pierre/theme/pierre-light` | `pierre-light` | Light | Supplies the standard light theme. | +| `@pierre/theme/pierre-dark` | `pierre-dark` | Dark | Supplies the standard dark theme. | +| `@pierre/theme/pierre-light-soft` | `pierre-light-soft` | Light | Supplies the soft light theme. | +| `@pierre/theme/pierre-dark-soft` | `pierre-dark-soft` | Dark | Supplies the soft dark theme. | +| `@pierre/theme/pierre-light-vibrant` | `pierre-light-vibrant` | Light | Supplies the Display-P3 light theme. | +| `@pierre/theme/pierre-dark-vibrant` | `pierre-dark-vibrant` | Dark | Supplies the Display-P3 dark theme. | +| `@pierre/theme/pierre-light-protanopia-deuteranopia` | `pierre-light-protanopia-deuteranopia` | Light | Supplies the light red-green color-vision variant. | +| `@pierre/theme/pierre-dark-protanopia-deuteranopia` | `pierre-dark-protanopia-deuteranopia` | Dark | Supplies the dark red-green color-vision variant. | +| `@pierre/theme/pierre-light-tritanopia` | `pierre-light-tritanopia` | Light | Supplies the light blue-yellow color-vision variant. | +| `@pierre/theme/pierre-dark-tritanopia` | `pierre-dark-tritanopia` | Dark | Supplies the dark blue-yellow color-vision variant. | + +## Raw theme entries + +`@pierre/theme/themes/*` exposes each generated JSON file. Replace `*` with a +theme file name, including `.json`. + +## Theme object + +Each default export has these immutable fields: + +| Field | Purpose | +| --------------------- | ---------------------------------------------- | +| `name` | Provides the stable theme identifier. | +| `displayName` | Provides the label for a theme selector. | +| `type` | Identifies the `light` or `dark` color scheme. | +| `colors` | Maps VS Code workbench color keys to colors. | +| `tokenColors` | Defines TextMate token styles. | +| `semanticTokenColors` | Defines semantic token styles. | diff --git a/skills/theme/references/recipe-editor.md b/skills/theme/references/recipe-editor.md new file mode 100644 index 000000000..40fa45392 --- /dev/null +++ b/skills/theme/references/recipe-editor.md @@ -0,0 +1,16 @@ +# Recipe: use a Pierre theme in an editor + +## VS Code or Cursor + +1. Install the **Pierre Theme** extension from the editor marketplace. +2. Open the color theme selector. +3. Select a `Pierre` theme. + +## Zed + +1. Install the **Pierre** extension from the Zed extension registry. +2. Open the theme selector. +3. Select a `Pierre` theme. + +The editor extensions include the standard, soft, protanopia and deuteranopia, +and tritanopia treatments. diff --git a/skills/theme/references/recipe-shiki.md b/skills/theme/references/recipe-shiki.md new file mode 100644 index 000000000..0f3fdda7e --- /dev/null +++ b/skills/theme/references/recipe-shiki.md @@ -0,0 +1,22 @@ +# Recipe: use a Pierre theme with Shiki + +Install the package: + +```bash +pnpm add @pierre/theme shiki +``` + +Import the theme object and pass it to Shiki: + +```ts +import pierreDark from '@pierre/theme/pierre-dark'; +import { codeToHtml } from 'shiki'; + +const html = await codeToHtml(source, { + lang: 'typescript', + theme: pierreDark, +}); +``` + +Import a matching light and dark pair when the app supports both color schemes. +Use the `theming` skill when the user can change the active theme at runtime. diff --git a/skills/theme/references/variants.md b/skills/theme/references/variants.md new file mode 100644 index 000000000..1986a4142 --- /dev/null +++ b/skills/theme/references/variants.md @@ -0,0 +1,17 @@ +# Pierre theme variants + +Select one treatment and use its light and dark entries as a pair. + +| Treatment | Light entry | Dark entry | Select it for | +| --------------------------- | -------------------------------------- | ------------------------------------- | ----------------------------------------- | +| Standard | `pierre-light` | `pierre-dark` | The default Pierre appearance. | +| Soft | `pierre-light-soft` | `pierre-dark-soft` | A lower-contrast appearance. | +| Vibrant | `pierre-light-vibrant` | `pierre-dark-vibrant` | Display-P3 output in Shiki or a web page. | +| Protanopia and deuteranopia | `pierre-light-protanopia-deuteranopia` | `pierre-dark-protanopia-deuteranopia` | Red-green color-vision support. | +| Tritanopia | `pierre-light-tritanopia` | `pierre-dark-tritanopia` | Blue-yellow color-vision support. | + +The editor extensions include the eight sRGB themes. The vibrant themes use CSS +Display-P3 color syntax and target web output. + +Use the standard pair unless the product specifies another treatment. Use the +same treatment for both color schemes. From 52b767608fa5bef6f40c8bfed7f7a14280ebb2cc Mon Sep 17 00:00:00 2001 From: Nicolas Gallagher <239676+necolas@users.noreply.github.com> Date: Wed, 22 Jul 2026 12:19:16 -0700 Subject: [PATCH 3/4] agents(theming): Add package usage skill Separate the collection, resolver, controller, color, and React APIs. Add recipes for one or several controllers and each supported host. Add the package README command that installs only the theming skill. --- packages/theming/README.md | 9 +++ skills/theming/SKILL.md | 49 +++++++++++++++ skills/theming/references/collections.md | 61 +++++++++++++++++++ skills/theming/references/colors.md | 30 +++++++++ skills/theming/references/controller.md | 59 ++++++++++++++++++ skills/theming/references/react.md | 10 +++ .../references/recipe-multiple-controllers.md | 39 ++++++++++++ .../references/recipe-one-controller.md | 26 ++++++++ skills/theming/references/recipe-react.md | 34 +++++++++++ skills/theming/references/recipe-vanilla.md | 32 ++++++++++ skills/theming/references/resolver.md | 35 +++++++++++ 11 files changed, 384 insertions(+) create mode 100644 skills/theming/SKILL.md create mode 100644 skills/theming/references/collections.md create mode 100644 skills/theming/references/colors.md create mode 100644 skills/theming/references/controller.md create mode 100644 skills/theming/references/react.md create mode 100644 skills/theming/references/recipe-multiple-controllers.md create mode 100644 skills/theming/references/recipe-one-controller.md create mode 100644 skills/theming/references/recipe-react.md create mode 100644 skills/theming/references/recipe-vanilla.md create mode 100644 skills/theming/references/resolver.md diff --git a/packages/theming/README.md b/packages/theming/README.md index 5457578b6..7fc683c1e 100644 --- a/packages/theming/README.md +++ b/packages/theming/README.md @@ -68,6 +68,15 @@ pnpm add @pierre/theming Add the optional peers only for the entries you use, e.g., `react` for `/react`, and `@pierre/theme`, `@shikijs/themes`, and `shiki` for `/themes`. +## Agent skill + +Install the agent skill for this package with the +[Skills CLI](https://skills.sh/docs/cli): + +```bash +npx skills add pierrecomputer/pierre --skill theming +``` + ## Collections and catalogs The core entry exports two closely-related composition primitives: diff --git a/skills/theming/SKILL.md b/skills/theming/SKILL.md new file mode 100644 index 000000000..230562d65 --- /dev/null +++ b/skills/theming/SKILL.md @@ -0,0 +1,49 @@ +--- +name: theming +description: + Use when an app uses @pierre/theming to list, resolve, select, switch, + persist, or apply themes, including color modes, theme controllers, React + state, UI colors, and bundled Pierre or Shiki collections. +--- + +# `@pierre/theming` + +Use `@pierre/theming` to manage runtime themes. The package separates theme +metadata, theme resolution, selected state, and UI color mapping. + +## Install + +```bash +pnpm add @pierre/theming +``` + +Install optional peer dependencies only for the selected entry. The React entry +needs `react`. The themes entry needs `@pierre/theme`, `@shikijs/themes`, and +`shiki`. + +## Select an API reference + +| Need | Reference | +| -------------------------------------------------------------- | -------------------------------------------- | +| Create a collection, catalog, descriptor, or bundled theme set | [Collections API](references/collections.md) | +| Register, load, seed, or cache theme objects | [Resolver API](references/resolver.md) | +| Track the color mode and selected light and dark themes | [Controller API](references/controller.md) | +| Normalize workbench colors or derive colors | [Colors API](references/colors.md) | +| Read controller state in React | [React API](references/react.md) | + +## Select a controller recipe + +| Situation | Recipe | +| ---------------------------------------------------------------------------- | --------------------------------------------------------------------- | +| One app or page shares one color mode and one light/dark selection | [Use one controller](references/recipe-one-controller.md) | +| Independent areas need separate selections or separate controller lifecycles | [Use multiple controllers](references/recipe-multiple-controllers.md) | + +Use one controller by default. Use multiple controllers only when the theme +state must differ between areas. + +## Select a framework recipe + +| Host | Recipe | +| --------------------------------------- | ------------------------------------------------------ | +| Vanilla JavaScript or another framework | [Use vanilla JavaScript](references/recipe-vanilla.md) | +| React | [Use React](references/recipe-react.md) | diff --git a/skills/theming/references/collections.md b/skills/theming/references/collections.md new file mode 100644 index 000000000..a5e1aa095 --- /dev/null +++ b/skills/theming/references/collections.md @@ -0,0 +1,61 @@ +# Collections API + +This reference covers collection APIs from `@pierre/theming` and all exports +from `@pierre/theming/themes`. + +## `@pierre/theming` exports + +| Export | Kind | Purpose | +| --------------------------- | -------- | ------------------------------------------------------------------ | +| `createThemeCollection` | Function | Creates an immutable ordered set of theme descriptors. | +| `ThemeCollection` | Type | Defines collection queries, transforms, and resolver registration. | +| `ThemeCollectionComparator` | Type | Compares two descriptors for `orderBy`. | +| `ThemeCollectionEntry` | Type | Accepts one descriptor or collection source. | +| `ThemeCollectionFilter` | Type | Filters by `collection` and `colorScheme`. | +| `ThemeCollectionInput` | Type | Accepts one entry or an iterable of entries. | +| `ThemeCollectionSource` | Type | Defines an object that returns theme descriptors. | +| `ThemeDescriptor` | Type | Describes one named theme and its lazy loader. | +| `createThemeCatalog` | Function | Creates a collection with default light and dark theme names. | +| `ThemeCatalog` | Type | Adds default theme names to `ThemeCollection`. | + +## `ThemeDescriptor` fields + +| Field | Purpose | +| ------------- | --------------------------------------- | +| `name` | Stores the stable theme identifier. | +| `load` | Loads the theme object. | +| `colorScheme` | Labels the descriptor as light or dark. | +| `collection` | Groups related themes. | +| `displayName` | Supplies a user-facing label. | + +## `ThemeCollection` methods + +| Method | Purpose | +| ------------------------ | ---------------------------------------------------- | +| `getTheme(name)` | Gets one descriptor by name. | +| `getThemes(filter?)` | Lists descriptors that match an optional filter. | +| `getThemeNames(filter?)` | Lists names that match an optional filter. | +| `hasTheme(name)` | Tests whether the collection has a name. | +| `orderBy(compare)` | Returns a new collection in comparator order. | +| `pick(names)` | Returns a new collection in the supplied name order. | +| `registerInto(resolver)` | Adds every descriptor loader to a resolver. | + +## `ThemeCatalog` fields + +| Field | Purpose | +| ----------------------- | ------------------------------ | +| `defaultLightThemeName` | Names the initial light theme. | +| `defaultDarkThemeName` | Names the initial dark theme. | + +## `@pierre/theming/themes` exports + +| Export | Kind | Purpose | +| -------------------- | -------- | ----------------------------------------------------------------------------- | +| `themes` | Value | Combines the Pierre and Shiki collections in stable order. | +| `pierreThemes` | Value | Provides lazy descriptors for the ten Pierre themes. | +| `shikiThemes` | Value | Provides lazy descriptors for the bundled Shiki themes. | +| `createTheme` | Function | Creates a descriptor whose loader normalizes a raw Shiki or VS Code theme. | +| `CreateThemeOptions` | Type | Defines the name, loader, and optional descriptor metadata for `createTheme`. | + +Use `createTheme` for a raw Shiki or VS Code theme. Use a `ThemeDescriptor` +directly when the loader already returns a compatible `ThemeLike` object. diff --git a/skills/theming/references/colors.md b/skills/theming/references/colors.md new file mode 100644 index 000000000..6c5156873 --- /dev/null +++ b/skills/theming/references/colors.md @@ -0,0 +1,30 @@ +# Colors API + +This reference covers every export from `@pierre/theming/color`. + +## Exports + +| Export | Kind | Purpose | +| ---------------------- | -------- | -------------------------------------------------------------- | +| `normalizeThemeColors` | Function | Resolves the UI color fallback chains in a `ThemeLike` object. | +| `colorUtils` | Object | Groups pure color checks and transforms. | + +`normalizeThemeColors(theme)` returns a memoized `ThemeLike` object. Use its +`colors` map for the UI around syntax-highlighted code. + +## `colorUtils` methods + +| Method | Purpose | +| ---------------------------------------------------- | -------------------------------------------------------------- | +| `relativeLuminance(color)` | Calculates WCAG luminance for a hex color. | +| `contrastRatio(a, b)` | Calculates the contrast ratio between two luminance values. | +| `compositeOverBg(foreground, background?)` | Flattens a translucent hex color over a background. | +| `isFullyTransparent(color?)` | Tests whether a hex color has zero alpha. | +| `isDarkSurface(background?, foregroundHint?)` | Classifies a surface as dark or light. | +| `surfacesMatch(a?, b?)` | Tests whether two hex surfaces produce the same visible color. | +| `hoverWouldEraseText(hover, background, foreground)` | Tests whether a hover surface removes text contrast. | +| `pickReadableForeground(background, candidates)` | Selects the candidate with the best readable contrast. | +| `deriveMutedFg(foreground, background)` | Derives a muted foreground with readable contrast. | + +The color methods measure hex colors. A method returns its documented empty +result when it cannot measure another CSS color format. diff --git a/skills/theming/references/controller.md b/skills/theming/references/controller.md new file mode 100644 index 000000000..fa94b39f8 --- /dev/null +++ b/skills/theming/references/controller.md @@ -0,0 +1,59 @@ +# Controller API + +This reference covers controller and shared theme types from `@pierre/theming`. + +## Exports + +| Export | Kind | Purpose | +| ----------------------------- | -------- | ------------------------------------------------------------------ | +| `createThemeController` | Function | Creates state for a color mode and selected light and dark themes. | +| `ThemeController` | Type | Defines controller state, mutations, subscription, and cleanup. | +| `ThemeControllerOptions` | Type | Selects a catalog or resolver and configures initial state. | +| `ThemeControllerState` | Type | Describes the current selection and resolved theme. | +| `PendingThemeResolution` | Type | Identifies the active theme load. | +| `ThemeResolutionError` | Type | Describes a failed active theme load. | +| `ThemeResolutionErrorContext` | Type | Identifies the name and scheme for a failed load callback. | +| `ThemePersistence` | Type | Defines custom `load` and `save` methods. | +| `ThemeSelection` | Type | Describes the persisted mode and theme names. | +| `ColorMode` | Type | Accepts `light`, `dark`, or `system`. | +| `ColorScheme` | Type | Accepts concrete `light` or `dark`. | +| `ThemeLike` | Type | Defines the shared resolved-theme shape. | + +## `ThemeControllerOptions` fields + +| Field | Purpose | +| ----------------------- | ------------------------------------------------------------------- | +| `catalog` | Supplies descriptors and catalog default names. | +| `resolver` | Supplies an existing resolver or shares one with other controllers. | +| `defaultLightThemeName` | Overrides the initial light theme name. | +| `defaultDarkThemeName` | Overrides the initial dark theme name. | +| `defaultMode` | Sets the initial color mode. | +| `storageKey` | Stores the selection in browser local storage. | +| `persistence` | Supplies custom selection storage. | +| `preloadInactive` | Resolves the inactive color-scheme theme too. | +| `onResolutionError` | Receives an active theme load error. | + +Pass a `catalog`, a `resolver`, or a catalog with a shared resolver. + +## `ThemeController` members + +| Member | Purpose | +| ------------------------------------- | ---------------------------------------------------------------- | +| `resolver` | Exposes the controller's resolver. | +| `getState()` | Returns the current immutable state object. | +| `setColorMode(mode)` | Selects light, dark, or system mode. | +| `setThemeNameForScheme(scheme, name)` | Selects the theme for one color scheme. | +| `subscribe(listener)` | Subscribes to state changes and returns an unsubscribe function. | +| `destroy()` | Removes the system color-scheme listener. | + +## `ThemeControllerState` fields + +| Field | Purpose | +| ------------------------ | -------------------------------------------------- | +| `lightThemeName` | Stores the selected light theme name. | +| `darkThemeName` | Stores the selected dark theme name. | +| `mode` | Stores the selected color mode. | +| `resolvedColorScheme` | Provides the active concrete light or dark scheme. | +| `resolvedTheme` | Provides the active resolved theme object. | +| `pendingThemeResolution` | Identifies an active theme load. | +| `resolutionError` | Describes the latest active load failure. | diff --git a/skills/theming/references/react.md b/skills/theming/references/react.md new file mode 100644 index 000000000..94e3bccb7 --- /dev/null +++ b/skills/theming/references/react.md @@ -0,0 +1,10 @@ +# React API + +This reference lists every export from `@pierre/theming/react`. + +| Export | Kind | Purpose | +| -------------------- | ---- | ------------------------------------------------------------------------- | +| `useThemeController` | Hook | Subscribes to a `ThemeController` and returns its `ThemeControllerState`. | + +The hook uses the controller state for both client and server snapshots. Create +the controller outside the component that reads it. diff --git a/skills/theming/references/recipe-multiple-controllers.md b/skills/theming/references/recipe-multiple-controllers.md new file mode 100644 index 000000000..8dfa29942 --- /dev/null +++ b/skills/theming/references/recipe-multiple-controllers.md @@ -0,0 +1,39 @@ +# Recipe: use multiple theme controllers + +Use multiple controllers when independent areas need different modes, +selections, storage, or lifecycles. Share one resolver when those areas use the +same theme loaders and cache. + +```ts +import { + createThemeCatalog, + createThemeController, + createThemeResolver, +} from '@pierre/theming'; +import { themes } from '@pierre/theming/themes'; + +const catalog = createThemeCatalog({ + themes, + defaultLightThemeName: 'pierre-light', + defaultDarkThemeName: 'pierre-dark', +}); + +const resolver = createThemeResolver(); + +export const workspaceTheme = createThemeController({ + catalog, + resolver, + storageKey: 'workspace-theme', +}); + +export const previewTheme = createThemeController({ + catalog, + resolver, + defaultMode: 'light', + storageKey: 'preview-theme', +}); +``` + +Subscribe each area to its own controller. Call `destroy()` on each controller +when its area is removed. Use distinct storage keys when selections must remain +independent. diff --git a/skills/theming/references/recipe-one-controller.md b/skills/theming/references/recipe-one-controller.md new file mode 100644 index 000000000..01e4ce9ed --- /dev/null +++ b/skills/theming/references/recipe-one-controller.md @@ -0,0 +1,26 @@ +# Recipe: use one theme controller + +Use one controller when the app shares one color mode and one light/dark theme +selection. + +Create the catalog and controller in one module: + +```ts +import { createThemeCatalog, createThemeController } from '@pierre/theming'; +import { themes } from '@pierre/theming/themes'; + +export const themeCatalog = createThemeCatalog({ + themes, + defaultLightThemeName: 'pierre-light', + defaultDarkThemeName: 'pierre-dark', +}); + +export const themeController = createThemeController({ + catalog: themeCatalog, + defaultMode: 'system', + storageKey: 'app-theme', +}); +``` + +Import the same controller wherever the app reads or changes theme state. Call +`destroy()` when the application tears down the controller module. diff --git a/skills/theming/references/recipe-react.md b/skills/theming/references/recipe-react.md new file mode 100644 index 000000000..b486b5637 --- /dev/null +++ b/skills/theming/references/recipe-react.md @@ -0,0 +1,34 @@ +# Recipe: use a theme controller in React + +Create the controller in a module. Read it with `useThemeController`: + +```tsx +import { useEffect } from 'react'; +import { useThemeController } from '@pierre/theming/react'; + +import { themeController } from './theme-controller'; + +export function ThemeControls() { + const state = useThemeController(themeController); + + useEffect(() => { + document.documentElement.dataset.colorScheme = state.resolvedColorScheme; + }, [state.resolvedColorScheme]); + + return ( + + ); +} +``` + +Pass `state.resolvedTheme` to code or tree surfaces. Use `normalizeThemeColors` +when a React component needs workbench UI colors. diff --git a/skills/theming/references/recipe-vanilla.md b/skills/theming/references/recipe-vanilla.md new file mode 100644 index 000000000..1a9a21f9e --- /dev/null +++ b/skills/theming/references/recipe-vanilla.md @@ -0,0 +1,32 @@ +# Recipe: use a theme controller in vanilla JavaScript + +Create a controller with the one-controller or multiple-controller recipe. Apply +each state change to the document: + +```ts +import { normalizeThemeColors } from '@pierre/theming/color'; +import { themeController } from './theme-controller'; + +function applyTheme() { + const state = themeController.getState(); + document.documentElement.dataset.colorScheme = state.resolvedColorScheme; + + if (state.resolvedTheme == null) return; + const { colors } = normalizeThemeColors(state.resolvedTheme); + document.documentElement.style.setProperty( + '--app-background', + colors?.['editor.background'] ?? state.resolvedTheme.bg ?? '' + ); + document.documentElement.style.setProperty( + '--app-foreground', + colors?.['editor.foreground'] ?? state.resolvedTheme.fg ?? '' + ); +} + +applyTheme(); +const unsubscribe = themeController.subscribe(applyTheme); +``` + +Call `themeController.setColorMode(mode)` from a mode control. Call +`setThemeNameForScheme(scheme, name)` from a theme selector. Call +`unsubscribe()` when the host no longer needs updates. diff --git a/skills/theming/references/resolver.md b/skills/theming/references/resolver.md new file mode 100644 index 000000000..73568b4f0 --- /dev/null +++ b/skills/theming/references/resolver.md @@ -0,0 +1,35 @@ +# Resolver API + +This reference covers the resolver exports from `@pierre/theming`. + +## Exports + +| Export | Kind | Purpose | +| ------------------------ | -------- | ------------------------------------------------------------- | +| `createThemeResolver` | Function | Creates an isolated loader registry and resolved-theme cache. | +| `ThemeResolver` | Type | Defines the resolver methods. | +| `ThemeLoader` | Type | Defines an asynchronous theme loader. | +| `DuplicateThemeError` | Class | Reports a second registration for the same name. | +| `UnregisteredThemeError` | Class | Reports a resolve request for a name with no loader. | +| `UnresolvedThemeError` | Class | Reports a synchronous batch read with an unresolved name. | + +## `ThemeResolver` methods + +| Method | Purpose | +| ------------------------------------- | -------------------------------------------------------- | +| `registerTheme(name, loader)` | Registers one loader. | +| `registerThemeIfAbsent(name, loader)` | Registers one loader only when the name is free. | +| `hasRegisteredTheme(name)` | Tests whether a loader exists. | +| `resolveTheme(name)` | Loads and caches one theme. | +| `resolveThemes(names)` | Loads and caches themes in input order. | +| `getResolvedTheme(name)` | Reads one cached theme or returns `undefined`. | +| `getResolvedThemes(names)` | Reads cached themes in input order. | +| `getResolvedOrResolveTheme(name)` | Returns a cached theme or starts its load. | +| `hasResolvedTheme(name)` | Tests whether one cached theme exists. | +| `hasResolvedThemes(names)` | Tests whether all named themes exist in the cache. | +| `seedResolvedTheme(name, theme)` | Adds one resolved object without a loader. | +| `seedResolvedThemes(entries)` | Adds several resolved objects without loaders. | +| `clearResolvedThemes()` | Clears cached themes and active loads but keeps loaders. | + +Each loader returns a `ThemeLike` object or a module object with that value on +`default`. From 167f7f1e46e3e063b9ef7c23dd1497ab6f44ad3a Mon Sep 17 00:00:00 2001 From: Nicolas Gallagher <239676+necolas@users.noreply.github.com> Date: Wed, 22 Jul 2026 12:19:30 -0700 Subject: [PATCH 4/4] agents(trees): Add package usage skill Document the core, React, SSR, and web-component APIs. Add recipes for rendering, interactions, themes, and server preload. Add the package README install command and the shared package skill index. --- packages/trees/README.md | 9 + skills/INDEX.md | 18 ++ skills/trees/SKILL.md | 39 ++++ skills/trees/references/api-core.md | 173 ++++++++++++++++++ skills/trees/references/api-react.md | 27 +++ skills/trees/references/api-ssr.md | 12 ++ skills/trees/references/api-web-components.md | 11 ++ .../trees/references/recipe-interactions.md | 30 +++ skills/trees/references/recipe-react.md | 22 +++ skills/trees/references/recipe-ssr.md | 31 ++++ skills/trees/references/recipe-theme.md | 18 ++ skills/trees/references/recipe-vanilla.md | 23 +++ 12 files changed, 413 insertions(+) create mode 100644 skills/INDEX.md create mode 100644 skills/trees/SKILL.md create mode 100644 skills/trees/references/api-core.md create mode 100644 skills/trees/references/api-react.md create mode 100644 skills/trees/references/api-ssr.md create mode 100644 skills/trees/references/api-web-components.md create mode 100644 skills/trees/references/recipe-interactions.md create mode 100644 skills/trees/references/recipe-react.md create mode 100644 skills/trees/references/recipe-ssr.md create mode 100644 skills/trees/references/recipe-theme.md create mode 100644 skills/trees/references/recipe-vanilla.md diff --git a/packages/trees/README.md b/packages/trees/README.md index f062b8185..bbd70c544 100644 --- a/packages/trees/README.md +++ b/packages/trees/README.md @@ -19,6 +19,15 @@ path strings, not internal numeric IDs. pnpm add @pierre/trees ``` +## Agent skill + +Install the agent skill for this package with the +[Skills CLI](https://skills.sh/docs/cli): + +```bash +npx skills add pierrecomputer/pierre --skill trees +``` + ## Vanilla usage ```ts diff --git a/skills/INDEX.md b/skills/INDEX.md new file mode 100644 index 000000000..a84aa54b8 --- /dev/null +++ b/skills/INDEX.md @@ -0,0 +1,18 @@ +# Pierre package skills + +Use these skills when an app or site consumes a Pierre package. Read the +selected `SKILL.md` first. Load only the API or recipe reference that matches +the task. + +| Skill | Use it for | +| --------------------------- | --------------------------------------------------------------------------------------------------- | +| [diffs](diffs/SKILL.md) | Render or edit code files, diffs, patches, and merge conflicts with `@pierre/diffs`. | +| [theme](theme/SKILL.md) | Select and load a Pierre syntax or editor theme from `@pierre/theme`. | +| [theming](theming/SKILL.md) | Build runtime theme collections, resolvers, controllers, and color mappings with `@pierre/theming`. | +| [trees](trees/SKILL.md) | Render and control an interactive file tree with `@pierre/trees`. | + +## Package relationship + +`@pierre/theme` supplies theme objects. `@pierre/theming` selects, resolves, and +maps those objects. `@pierre/diffs` and `@pierre/trees` render code and file +trees with the selected theme. diff --git a/skills/trees/SKILL.md b/skills/trees/SKILL.md new file mode 100644 index 000000000..d3cc23fb7 --- /dev/null +++ b/skills/trees/SKILL.md @@ -0,0 +1,39 @@ +--- +name: trees +description: + Use when an app uses @pierre/trees to render or control a file tree, including + React, vanilla JavaScript, SSR, web components, selection, search, rename, + drag and drop, icons, git status, and themes. +--- + +# `@pierre/trees` + +Use `@pierre/trees` for an interactive file tree. Public state and callbacks use +path strings. + +## Install + +```bash +pnpm add @pierre/trees +``` + +Install `react` and `react-dom` when the app uses the React entry. + +## Select an API reference + +| Entry | Reference | +| ------------------------------ | ------------------------------------------------------ | +| `@pierre/trees` | [Core API](references/api-core.md) | +| `@pierre/trees/react` | [React API](references/api-react.md) | +| `@pierre/trees/ssr` | [SSR API](references/api-ssr.md) | +| `@pierre/trees/web-components` | [Web components API](references/api-web-components.md) | + +## Select a recipe + +| Task | Recipe | +| ------------------------------------------------------- | ------------------------------------------------------ | +| Render and update a tree in React | [Use React](references/recipe-react.md) | +| Render and update a tree without React | [Use vanilla JavaScript](references/recipe-vanilla.md) | +| Preload a tree on the server | [Use SSR](references/recipe-ssr.md) | +| Apply a resolved Shiki or VS Code theme | [Apply a theme](references/recipe-theme.md) | +| Configure search, rename, drag and drop, and git status | [Add interactions](references/recipe-interactions.md) | diff --git a/skills/trees/references/api-core.md b/skills/trees/references/api-core.md new file mode 100644 index 000000000..22727767e --- /dev/null +++ b/skills/trees/references/api-core.md @@ -0,0 +1,173 @@ +# Core API + +This reference lists every export from `@pierre/trees` and every public +`FileTree` member. + +## Contents + +- [Runtime values](#runtime-values) +- [`FileTree` members](#filetree-members) +- [Configuration and state types](#configuration-and-state-types) +- [Mutation types](#mutation-types) +- [Interaction types](#interaction-types) +- [Presentation types](#presentation-types) +- [Constants](#constants) + +## Runtime values + +| Export | Kind | Purpose | +| ------------------------------- | -------- | ----------------------------------------------------------------- | +| `FileTree` | Class | Owns the tree model, renders it, and exposes path-based controls. | +| `prepareFileTreeInput` | Function | Prepares and optionally sorts a path list for reuse. | +| `preparePresortedFileTreeInput` | Function | Prepares a path list that already has final order. | +| `preloadFileTree` | Function | Creates server-rendered tree markup and hydration data. | +| `serializeFileTreeSsrPayload` | Function | Joins an SSR payload into one host markup string. | +| `themeToTreeStyles` | Function | Maps a resolved theme to tree host CSS properties. | +| `getBuiltInSpriteSheet` | Function | Gets the SVG sprite for a built-in icon set. | +| `createFileTreeIconResolver` | Function | Creates an icon resolver from an icon configuration. | + +## `FileTree` members + +| Member | Purpose | +| -------------------------------- | ----------------------------------------------------------- | +| `new FileTree(options)` | Creates a model from paths or prepared input. | +| `FileTree.LoadedCustomComponent` | Reports whether the file-tree custom element module loaded. | +| `render(props)` | Mounts the tree into a wrapper or host element. | +| `hydrate(props)` | Attaches the model to preloaded host markup. | +| `unmount()` | Removes the mounted view and keeps the model. | +| `cleanUp()` | Removes the view and destroys model resources. | +| `getFileTreeContainer()` | Gets the mounted host element. | +| `getItem(path)` | Gets a path handle or `null`. | +| `getFocusedItem()` | Gets the focused item handle or `null`. | +| `getFocusedPath()` | Gets the focused path or `null`. | +| `getSelectedPaths()` | Gets the selected paths. | +| `getComposition()` | Gets the current header and context-menu configuration. | +| `getItemHeight()` | Gets the resolved row height. | +| `getDensityFactor()` | Gets the resolved density factor. | +| `subscribe(listener)` | Subscribes to model changes. | +| `focusPath(path)` | Focuses a path. | +| `focusNearestPath(path)` | Focuses and returns the nearest available path. | +| `scrollToPath(path, options?)` | Scrolls a path into view. | +| `add(path)` | Adds one path. | +| `remove(path, options?)` | Removes one path. | +| `move(from, to, options?)` | Moves one path. | +| `batch(operations)` | Applies several path mutations together. | +| `resetPaths(paths, options?)` | Replaces the full path set. | +| `onMutation(type, handler)` | Subscribes to mutation events. | +| `setSearch(value)` | Sets or clears the search query. | +| `openSearch(initialValue?)` | Opens the search session. | +| `closeSearch()` | Closes the search session. | +| `isSearchOpen()` | Tests whether search is open. | +| `getSearchValue()` | Gets the search query. | +| `getSearchMatchingPaths()` | Gets paths that match the query. | +| `focusNextSearchMatch()` | Focuses the next search match. | +| `focusPreviousSearchMatch()` | Focuses the previous search match. | +| `startRenaming(path?, options?)` | Starts inline rename and reports whether it started. | +| `setGitStatus(status?)` | Replaces all git status entries. | +| `applyGitStatusPatch(patch)` | Applies a partial git status update. | +| `setIcons(icons?)` | Replaces the icon configuration. | +| `setComposition(composition?)` | Replaces header and context-menu configuration. | + +## Configuration and state types + +| Export | Purpose | +| -------------------------- | --------------------------------------------------------------- | +| `FileTreeOptions` | Defines input, behavior, rendering, and presentation options. | +| `FileTreePreparedInput` | Holds a reusable prepared path list. | +| `FileTreeInitialExpansion` | Selects closed, open, or depth-based initial expansion. | +| `FileTreeSortComparator` | Compares two path entries. | +| `FileTreeSortEntry` | Describes one path for a sort comparator. | +| `FileTreeRenderOptions` | Configures row height, row count, overscan, and sticky folders. | +| `FileTreeRenderProps` | Selects the wrapper or existing host for `render`. | +| `FileTreeHydrationProps` | Selects the host for `hydrate`. | +| `FileTreeVisibleRow` | Describes one visible tree row. | +| `FileTreeItemHandle` | Represents a file or directory item. | +| `FileTreeFileHandle` | Controls one file item. | +| `FileTreeDirectoryHandle` | Controls one directory item and its expansion. | +| `FileTreeListener` | Defines a model subscription callback. | +| `FileTreeSsrPayload` | Holds the host and shadow markup for server output. | + +## Mutation types + +| Export | Purpose | +| ----------------------------------- | -------------------------------------------------------------- | +| `FileTreeMutationHandle` | Defines the public path mutation methods. | +| `FileTreeBatchOperation` | Describes one add, remove, or move in a batch. | +| `FileTreeCollisionStrategy` | Selects error, replace, or skip behavior for a move collision. | +| `FileTreeMoveOptions` | Configures move collision behavior. | +| `FileTreeRemoveOptions` | Configures recursive removal. | +| `FileTreeResetOptions` | Configures a path reset and optional prepared input. | +| `FileTreeResetPreparedOptions` | Configures a reset that uses prepared input. | +| `FileTreeMutationEvent` | Represents any mutation event. | +| `FileTreeMutationSemanticEvent` | Represents an add, remove, move, or reset event. | +| `FileTreeMutationEventType` | Names a mutation operation. | +| `FileTreeMutationEventForType` | Selects the event shape for an operation name. | +| `FileTreeMutationEventInvalidation` | Describes the state invalidation from a mutation. | +| `FileTreeAddEvent` | Describes one add result. | +| `FileTreeRemoveEvent` | Describes one remove result. | +| `FileTreeMoveEvent` | Describes one move result. | +| `FileTreeResetEvent` | Describes one reset result. | +| `FileTreeBatchEvent` | Describes one batch result. | + +## Interaction types + +| Export | Purpose | +| --------------------------------- | -------------------------------------------------- | +| `FileTreeSelectionChangeListener` | Receives the selected path list. | +| `FileTreeSearchChangeListener` | Receives the current search query. | +| `FileTreeSearchSessionHandle` | Defines search session methods. | +| `FileTreeSearchMode` | Selects how nonmatching rows appear. | +| `FileTreeSearchBlurBehavior` | Selects search behavior after focus leaves. | +| `FileTreeScrollOffset` | Selects top, center, or nearest scroll alignment. | +| `FileTreeScrollToPathOptions` | Configures focus and alignment for `scrollToPath`. | +| `FileTreeDragAndDropConfig` | Configures drag rules and completion callbacks. | +| `FileTreeDropTarget` | Describes the current drop target. | +| `FileTreeDropContext` | Describes dragged paths and their target. | +| `FileTreeDropResult` | Describes the completed move or batch operation. | +| `FileTreeRenamingConfig` | Configures rename rules and callbacks. | +| `FileTreeRenamingItem` | Describes the item offered to a rename rule. | +| `FileTreeRenameEvent` | Describes a completed rename. | + +## Presentation types + +| Export | Purpose | +| ---------------------------------- | ----------------------------------------------------------- | +| `FileTreeCompositionOptions` | Configures header and context-menu composition. | +| `FileTreeHeaderCompositionOptions` | Supplies header HTML or a header renderer. | +| `ContextMenuItem` | Describes the file or directory for a context menu. | +| `ContextMenuOpenContext` | Supplies menu position, close, and focus controls. | +| `ContextMenuAnchorRect` | Describes the menu anchor rectangle. | +| `ContextMenuTriggerMode` | Selects right-click, button, or both triggers. | +| `ContextMenuButtonVisibility` | Selects when the row menu button appears. | +| `FileTreeRowDecoration` | Describes text or icon content in the decoration lane. | +| `FileTreeRowDecorationContext` | Supplies the item and visible row to a decoration renderer. | +| `FileTreeRowDecorationRenderer` | Produces one row decoration. | +| `GitStatus` | Names a supported git status. | +| `GitStatusEntry` | Assigns a git status to one path. | +| `FileTreeGitStatusPatch` | Adds, changes, or removes git status entries. | +| `FileTreeBuiltInIconSet` | Names a built-in icon set. | +| `FileTreeIconConfig` | Configures built-in and custom icon rules. | +| `FileTreeIcons` | Accepts an icon set name or icon configuration. | +| `RemappedIcon` | Names or defines a replacement SVG symbol. | +| `FileTreeDensity` | Accepts a density keyword or numeric factor. | +| `FileTreeDensityKeyword` | Names compact, default, or relaxed density. | +| `FileTreeDensityPreset` | Holds a density factor and row height. | +| `TreeThemeInput` | Defines the resolved theme accepted by `themeToTreeStyles`. | +| `TreeThemeStyles` | Maps tree CSS property names to values. | + +## Constants + +| Export | Purpose | +| ---------------------------------------------- | --------------------------------------------------------------- | +| `FILE_TREE_TAG_NAME` | Provides the `file-tree-container` element name. | +| `FILE_TREE_STYLE_ATTRIBUTE` | Provides the core style marker attribute. | +| `FILE_TREE_UNSAFE_CSS_ATTRIBUTE` | Provides the custom style marker attribute. | +| `FILE_TREE_SCROLLBAR_MEASURE_ATTRIBUTE` | Provides the scrollbar measurement attribute. | +| `FILE_TREE_SCROLLBAR_GUTTER_STYLE_ATTRIBUTE` | Provides the measured scrollbar style attribute. | +| `FILE_TREE_SCROLLBAR_GUTTER_MEASURED_PROPERTY` | Provides the measured scrollbar CSS property. | +| `FILE_TREE_DEFAULT_ITEM_HEIGHT` | Provides the default row height. | +| `FILE_TREE_DENSITY_PRESETS` | Maps each density keyword to its preset. | +| `FLATTENED_PREFIX` | Provides the identifier prefix for a flattened directory chain. | +| `HEADER_SLOT_NAME` | Provides the header slot name. | +| `CONTEXT_MENU_SLOT_NAME` | Provides the context-menu slot name. | +| `CONTEXT_MENU_TRIGGER_TYPE` | Provides the context-menu trigger type. | diff --git a/skills/trees/references/api-react.md b/skills/trees/references/api-react.md new file mode 100644 index 000000000..39ba73da3 --- /dev/null +++ b/skills/trees/references/api-react.md @@ -0,0 +1,27 @@ +# React API + +This reference lists every export from `@pierre/trees/react`. + +| Export | Kind | Purpose | +| -------------------------- | --------- | ---------------------------------------------------------------------- | +| `FileTree` | Component | Mounts a `FileTree` model in a React host element. | +| `FileTreeProps` | Type | Defines the model, header, context menu, preload data, and host props. | +| `FileTreePreloadedData` | Type | Selects the `id` and `shadowHtml` fields for hydration. | +| `useFileTree` | Hook | Creates one stable `FileTree` model. | +| `UseFileTreeResult` | Type | Holds the model returned by `useFileTree`. | +| `useFileTreeSelection` | Hook | Returns the selected path list and updates with the model. | +| `useFileTreeSearch` | Hook | Returns search state and search actions. | +| `FileTreeSearchState` | Type | Defines the search snapshot and actions. | +| `useFileTreeSelector` | Hook | Subscribes to a selected part of model state. | +| `FileTreeSelector` | Type | Selects a value from a model. | +| `FileTreeSelectorEquality` | Type | Compares two selected values. | + +`FileTreeProps` extends React host attributes except `children`. Its specific +fields are: + +| Field | Purpose | +| ------------------- | --------------------------------------------------- | +| `model` | Supplies the required `FileTree` model. | +| `header` | Supplies React content for the header slot. | +| `renderContextMenu` | Produces React content for the active context menu. | +| `preloadedData` | Supplies server markup for hydration. | diff --git a/skills/trees/references/api-ssr.md b/skills/trees/references/api-ssr.md new file mode 100644 index 000000000..3ef00b4c3 --- /dev/null +++ b/skills/trees/references/api-ssr.md @@ -0,0 +1,12 @@ +# SSR API + +This reference lists every export from `@pierre/trees/ssr`. + +| Export | Kind | Purpose | +| ----------------------------- | -------- | --------------------------------------------------------------- | +| `preloadFileTree` | Function | Renders a tree to a `FileTreeSsrPayload`. | +| `serializeFileTreeSsrPayload` | Function | Creates declarative or DOM-inserted host markup from a payload. | +| `FileTreeSsrPayload` | Type | Holds the host start, shadow HTML, host end, and stable ID. | + +`preloadFileTree` and `serializeFileTreeSsrPayload` are also available from +`@pierre/trees`. diff --git a/skills/trees/references/api-web-components.md b/skills/trees/references/api-web-components.md new file mode 100644 index 000000000..b03a9635b --- /dev/null +++ b/skills/trees/references/api-web-components.md @@ -0,0 +1,11 @@ +# Web components API + +Import `@pierre/trees/web-components` to register the `file-tree-container` +custom element. The entry exports these APIs: + +| Export | Kind | Purpose | +| --------------------------- | -------- | ------------------------------------------------------------------------- | +| `FileTreeContainerLoaded` | Value | Confirms that the registration module ran. | +| `adoptDeclarativeShadowDom` | Function | Copies a declarative template into an empty shadow root. | +| `ensureFileTreeStyles` | Function | Installs the core tree stylesheet in a shadow root. | +| `prepareFileTreeShadowRoot` | Function | Adopts server markup, installs styles, and measures the scrollbar gutter. | diff --git a/skills/trees/references/recipe-interactions.md b/skills/trees/references/recipe-interactions.md new file mode 100644 index 000000000..b96d98af4 --- /dev/null +++ b/skills/trees/references/recipe-interactions.md @@ -0,0 +1,30 @@ +# Recipe: add file tree interactions + +Enable only the interactions that the product exposes: + +```ts +const tree = new FileTree({ + paths, + search: true, + renaming: { + onRename(event) { + renamePath(event.sourcePath, event.destinationPath); + }, + }, + dragAndDrop: { + canDrop({ target }) { + return target.kind === 'directory'; + }, + onDropComplete(event) { + saveMove(event); + }, + }, + gitStatus, +}); +``` + +Use `openSearch()` to open search from an application command. Use +`startRenaming(path)` to start rename from a menu. Use `setGitStatus()` or +`applyGitStatusPatch()` after repository state changes. + +Directory input paths end with `/`. File input paths do not end with `/`. diff --git a/skills/trees/references/recipe-react.md b/skills/trees/references/recipe-react.md new file mode 100644 index 000000000..393c78e22 --- /dev/null +++ b/skills/trees/references/recipe-react.md @@ -0,0 +1,22 @@ +# Recipe: use a file tree in React + +Create the model once and pass it to the component: + +```tsx +'use client'; + +import { FileTree, useFileTree } from '@pierre/trees/react'; + +export function ProjectFiles({ paths }: { paths: readonly string[] }) { + const { model } = useFileTree({ + paths, + initialExpansion: 'open', + search: true, + }); + + return ; +} +``` + +Call model methods for updates after model creation. For example, call +`model.resetPaths(paths)` after the source path list changes. diff --git a/skills/trees/references/recipe-ssr.md b/skills/trees/references/recipe-ssr.md new file mode 100644 index 000000000..9b225804f --- /dev/null +++ b/skills/trees/references/recipe-ssr.md @@ -0,0 +1,31 @@ +# Recipe: preload a file tree on the server + +Create one payload and pass it to the React tree: + +```tsx +import { preloadFileTree } from '@pierre/trees/ssr'; +import { FileTree, useFileTree } from '@pierre/trees/react'; + +const options = { + id: 'project-files', + paths: ['README.md', 'src/', 'src/index.ts'], + initialExpansion: 'open' as const, + initialVisibleRowCount: 8, +}; + +const preloadedData = preloadFileTree(options); + +export function ProjectFiles() { + const { model } = useFileTree(options); + return ( + + ); +} +``` + +For a direct HTML response, call `serializeFileTreeSsrPayload(payload)`. Pass +`dom` as the second argument when a DOM API inserts the complete markup string. diff --git a/skills/trees/references/recipe-theme.md b/skills/trees/references/recipe-theme.md new file mode 100644 index 000000000..b7d90fbc5 --- /dev/null +++ b/skills/trees/references/recipe-theme.md @@ -0,0 +1,18 @@ +# Recipe: apply a resolved theme + +Convert one resolved Shiki or VS Code theme to host styles: + +```tsx +import { themeToTreeStyles } from '@pierre/trees'; +import { FileTree } from '@pierre/trees/react'; + +const treeStyle = { + height: 320, + ...themeToTreeStyles(resolvedTheme), +}; + +; +``` + +Recalculate the styles when the resolved theme changes. Set tree override CSS +properties on the same host style when the product needs a local color choice. diff --git a/skills/trees/references/recipe-vanilla.md b/skills/trees/references/recipe-vanilla.md new file mode 100644 index 000000000..ea258f439 --- /dev/null +++ b/skills/trees/references/recipe-vanilla.md @@ -0,0 +1,23 @@ +# Recipe: use a file tree in vanilla JavaScript + +Create the model and mount it in an element with a height: + +```ts +import { FileTree } from '@pierre/trees'; + +const mount = document.querySelector('#files'); +if (mount == null) throw new Error('Missing file tree mount'); + +mount.style.height = '320px'; + +const tree = new FileTree({ + paths: ['README.md', 'src/', 'src/index.ts'], + initialExpansion: 'open', + search: true, +}); + +tree.render({ containerWrapper: mount }); +``` + +Use `add`, `remove`, `move`, or `resetPaths` to update paths. Call `cleanUp()` +when the host removes the tree.