This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
BQuery is a Blazor helper library for JavaScript interop, inspired by jQuery. It provides:
- DOM manipulation (attributes, classes, styles)
- Viewport measurements
- Window event handling (resize, scroll, mouse, keyboard, touch)
- Element drag functionality
The library is multi-targeted: .NET 8.0 and .NET 10.0.
dotnet build # Build the solution
dotnet build -c Release # Release build (triggers JS build automatically)
dotnet pack src/BQuery/BQuery.csproj -c Release # Create NuGet packagecd src/BQuery/wwwroot
pnpm install # Install dependencies
pnpm run build # Production build (minified, no sourcemap)
pnpm run dev # Development build (with sourcemap, watch mode)The release build automatically runs pnpm run build via MSBuild target.
| File | Purpose |
|---|---|
Bq.cs |
Main scoped service exposing WindowEvents, Viewport, Drag, and window listener registration |
BqEvents.cs |
Window event hub - partial class augmented by source generator; manages per-scope event listeners |
BqViewport.cs |
Viewport measurement APIs (width, height, scroll positions) |
BqDrag.cs |
Drag-and-drop functionality binding |
ElementReferenceExtensions.cs |
Extension methods on ElementReference for DOM operations |
Constants/JsModuleConstants.cs |
JavaScript function name constants for interop calls |
Constants/WindowEvents.cs |
WindowEvent struct with event definitions decorated with [WindowEventHandler] |
SourceGeneration/ |
Source-generator attributes consumed by the main library |
ServiceExtension.cs |
AddBQuery() DI registration extension |
| Generator | Purpose |
|---|---|
JsInteropMethodsGenerator.cs |
Generates *Method constants from JsModuleConstants nested groups via [GenerateJsInteropMethods] |
WindowEventsGenerator.cs |
Generates event members and [JSInvokable] callbacks in BqEvents from WindowEvent fields decorated with [WindowEventHandler] |
| Module | Purpose |
|---|---|
index.ts |
Entry point - constructs and exports the bQuery object |
module/Viewport.ts |
Viewport measurement functions |
module/HtmlElementHelper.ts |
Element dimension and position helpers |
module/DragHelper.ts |
Drag-and-drop functionality |
module/eventHelper.ts |
Window event binding for Blazor callbacks |
module/domHelper.ts |
DOM attribute, class, and style manipulation |
module/common.ts |
throttle and debounce utilities |
- C# → JS: C# calls
IJSRuntime.InvokeAsyncusing generated*Methodconstants derived fromJsModuleConstants - JS → C#: JavaScript calls
DotNetObjectReference.invokeMethodAsyncon the scopedBqEventsinstance, which raises the matching .NET events
The JavaScript module path is ./_content/BQuery/dist/bQuery.min.mjs (ES module format).
Bq and BqEvents are registered as scoped services. Each scope receives:
- A unique
_listenerId(GUID) for tracking event subscriptions - An independent
EventSlotsdictionary for event handler management - Automatic cleanup via
IAsyncDisposablewhen the scope ends
The library uses UnsafeAccessor to extract IJSRuntime from WebElementReferenceContext, allowing extension methods to work without explicit JSRuntime injection:
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "<JSRuntime>k__BackingField")]
private static extern ref IJSRuntime GetJsRuntime(WebElementReferenceContext context);- JavaScript function names: camelCase (e.g.,
getWidth,getScrollTop) - C# method names: PascalCase with
Asyncsuffix (e.g.,GetWidthAsync,GetScrollTopAsync)
- Prefer the JS interop source generator over manually calling
JsModuleConstants.GetMethod(...). - To enable generation for a constant group, declare a local partial marker class with
[GenerateJsInteropMethods(typeof(...))]. - Use generated fields in the form
<MethodName>Method, for exampleElementConstants.GetWidthMethodorDragConstants.BindDragMethod. - For nested constant groups such as
JsModuleConstants.ElementExtensionsorJsModuleConstants.Drag, create a dedicated marker class such asElementConstantsorDragConstants. - For top-level methods on
JsModuleConstants, use a marker class such asBqConstants. - Keep marker classes close to the consuming code unless there is a clear shared location that improves discoverability.
- When adding new JS interop APIs, add the method name to
JsModuleConstantsfirst, then consume it through the generated constant class rather than string concatenation. - Do not introduce new direct
JsModuleConstants.GetMethod(...)calls in application code unless the usage is too dynamic for source generation.
- Define new window events as
static readonly WindowEventfields inWindowEvents.cs. - Decorate each field with
[WindowEventHandler(typeof(EventArgsType))]to trigger source generation. - The generator produces sync (
Action<T>) and async (Func<T, Task>) events plus[JSInvokable]callback methods inBqEvents. - For events requiring two arguments, use
[WindowEventHandler(typeof(T1), typeof(T2))]. - When a generator depends on constants metadata, prefer extending the constants definition with attributes over hard-coding parallel lookup tables inside the generator.
The Sample/ directory contains:
BQuery.Sample.Wasm- WebAssembly demoBQuery.Sample.Server- Blazor Server demoBQuery.Sample.Common- Shared Razor componentsBlazorAppAuto/- Auto render mode demo
The GitHub workflow (.github/workflows/dotnet-tag.yml) triggers on tag push, builds for .NET 8/10, and publishes to NuGet.