Skip to content

Conversation

@jaruesink
Copy link
Contributor

@jaruesink jaruesink commented May 12, 2025

  • Updated Radix UI component versions in package.json and yarn.lock for improved functionality and performance.
  • Refactored DataTableRouterForm to utilize Bazza UI filter configurations, enhancing filtering capabilities.
  • Adjusted DataTableRouterToolbar to support new Bazza UI filter integration and improved search functionality.
  • Updated data-table-router-parsers to define and parse Bazza filter items.
  • Enhanced DataTableRouterFormExample story to demonstrate new filtering features.

Summary by CodeRabbit

  • New Features

    • Introduced a comprehensive, fully integrated data table filtering system with server-driven filtering, pagination, and sorting using Bazza UI filters.
    • Added Storybook examples and automated UI tests showcasing server-driven data table filtering.
    • Added reusable UI components including Calendar, Checkbox, Dialog, Slider, Tabs, DebouncedInput, and enhanced PopoverAnchor.
    • Implemented a robust, localized filter UI supporting text, number, date, option, and multi-option data types with advanced operators and controls.
    • Provided English localization and extensive filter operator metadata for the filter UI.
  • Improvements

    • Upgraded multiple @radix-ui/react-* dependencies and added new ones for improved functionality.
    • Refactored data table stories and components to adopt Bazza UI filter configurations, enhancing type safety and flexibility.
    • Decoupled filter and search state management from internal form context to allow external control and URL synchronization.
    • Introduced a new hook for managing filter state with controlled and uncontrolled modes.
    • Enhanced debouncing utilities with React hooks supporting control methods.
    • Added a new hook to synchronize filter state with URL search parameters.
  • Bug Fixes

    • Improved deep equality and uniqueness utilities for complex filter values.
    • Fixed filter operator transitions and value normalization across filter types.
  • Documentation

    • Added detailed Storybook stories and automated UI tests demonstrating new filtering capabilities.
  • Chores

    • Added "Bazza" to the custom spell checker dictionary.

…I filters

- Updated Radix UI component versions in package.json and yarn.lock for improved functionality and performance.
- Refactored DataTableRouterForm to utilize Bazza UI filter configurations, enhancing filtering capabilities.
- Adjusted DataTableRouterToolbar to support new Bazza UI filter integration and improved search functionality.
- Updated data-table-router-parsers to define and parse Bazza filter items.
- Enhanced DataTableRouterFormExample story to demonstrate new filtering features.
@bolt-new-by-stackblitz
Copy link

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@coderabbitai
Copy link

coderabbitai bot commented May 12, 2025

Walkthrough

This update introduces a comprehensive, type-safe, and localized data table filtering system centered around Bazza UI filters. It includes new filter UI components, core logic for filter configuration, operators, and state management hooks. The integration is applied to example stories, with server-driven and client-driven filtering, and extensive utility, localization, and React component enhancements.

Changes

File(s) Change Summary
.vscode/settings.json Added "Bazza" to spell checker custom words.
apps/docs/src/remix-hook-form/data-table-bazza-filters.stories.tsx Added a new Storybook story demonstrating server-driven filtering, pagination, and sorting with Bazza UI filters and React Router integration, including loader, filter configs, and automated UI tests.
apps/docs/src/remix-hook-form/data-table-router-form.stories.tsx Refactored to use Bazza UI filter configurations; updated loader and filtering logic for Bazza filter types and options; added debugging and logging for filter options.
packages/components/package.json Updated several @radix-ui/react-* dependencies to newer versions; added @radix-ui/react-slider and @radix-ui/react-tabs as new dependencies.
packages/components/src/remix-hook-form/data-table-router-form.tsx Integrated Bazza UI filtering: replaced TanStack Table's client-side filtering with Bazza's server-side filter state and synchronization; updated props and toolbar usage.
packages/components/src/remix-hook-form/data-table-router-parsers.ts Replaced FilterValue with BazzaFilterItem and BazzaFiltersState; updated filter parsing/serialization logic and types throughout.
packages/components/src/remix-hook-form/data-table-router-toolbar.tsx Refactored toolbar to be stateless; now controlled via explicit props for search, filters, and actions; switched to Bazza filter UI.
packages/components/src/ui/button.tsx Changed import from React namespace to type-only import for ButtonHTMLAttributes; simplified component return.
packages/components/src/ui/calendar.tsx Added new Calendar component wrapping react-day-picker with custom styles and icon navigation.
packages/components/src/ui/checkbox.tsx Added new Checkbox component using @radix-ui/react-checkbox and lucide-react icons.
packages/components/src/ui/data-table-filter/components/active-filters.tsx Added new components for displaying/removing active filters, including a mobile container with scroll/blur effects.
packages/components/src/ui/data-table-filter/components/data-table-filter.tsx Added main DataTableFilter component with responsive layouts, filter selector, active filters, and actions.
packages/components/src/ui/data-table-filter/components/filter-actions.tsx Added FilterActions component for clearing all filters, with localization and conditional visibility.
packages/components/src/ui/data-table-filter/components/filter-operator.tsx Added components for displaying and selecting filter operators, with per-type logic and localization.
packages/components/src/ui/data-table-filter/components/filter-selector.tsx Added filter selector with popover/command UI, property search, quick search, and prefetching.
packages/components/src/ui/data-table-filter/components/filter-subject.tsx Added FilterSubject component for rendering filter column subject with icon and label.
packages/components/src/ui/data-table-filter/components/filter-value.tsx Added comprehensive components for rendering and controlling filter values for all supported data types.
packages/components/src/ui/data-table-filter/core/filters.ts Introduced core filter configuration system: fluent builder, column helpers, option/value/faceted data extraction, and column creation.
packages/components/src/ui/data-table-filter/core/operators.ts Added definitions for all filter operators per data type, operator details, and operator transition logic.
packages/components/src/ui/data-table-filter/core/types.ts Added extensive type definitions for columns, filter models, operators, and filter actions.
packages/components/src/ui/data-table-filter/hooks/use-data-table-filters.tsx Added main filter state management hook with actions for adding/removing/setting filter values and operators, supporting controlled/uncontrolled usage.
packages/components/src/ui/data-table-filter/hooks/use-debounce-callback.tsx Added a hook for debounced callbacks with control methods and unmount cleanup.
packages/components/src/ui/data-table-filter/hooks/use-unmount.tsx Added hook to run a cleanup function on component unmount.
packages/components/src/ui/data-table-filter/index.tsx Added index file re-exporting useDataTableFilters and DataTableFilter.
packages/components/src/ui/data-table-filter/lib/array.ts Added deep equality and uniqueness utilities for arrays, including stable hashing and set operations.
packages/components/src/ui/data-table-filter/lib/debounce.ts Added robust debounce utility with leading/trailing/maxWait options and control methods.
packages/components/src/ui/data-table-filter/lib/filter-fns.ts Added filter functions for each data type/operator, including set, range, and substring logic.
packages/components/src/ui/data-table-filter/lib/helpers.ts Added helpers for column lookup, filter value normalization, and type guards.
packages/components/src/ui/data-table-filter/lib/i18n.ts Added i18n support with English locale and translation function.
packages/components/src/ui/data-table-filter/lib/memo.ts Added generic memoization utility for dependency-based computation.
packages/components/src/ui/data-table-filter/locales/en.json Added English localization strings for the data table filter UI.
packages/components/src/ui/debounced-input.tsx Added DebouncedInput component for debounced text input handling.
packages/components/src/ui/dialog.tsx Added dialog UI components wrapping Radix primitives with custom styles and accessibility.
packages/components/src/ui/popover.tsx Added export for PopoverAnchor from Radix UI.
packages/components/src/ui/slider.tsx Added Slider component wrapping Radix slider, supporting multi-thumb and range selection.
packages/components/src/ui/tabs.tsx Added tab UI components wrapping Radix tabs with custom styles.
packages/components/src/ui/utils/debounce.ts Refactored debounce function to use arrow function style and added lint ignore for any.
packages/components/src/ui/utils/filters.ts Added zod schemas and types for filter validation and typing.
packages/components/src/ui/utils/index.ts Added re-exports for debounce, filters, and use-filter-sync utilities.
packages/components/src/ui/utils/use-data-table-filters.ts Added proxy export for useDataTableFilters hook and type.
packages/components/src/ui/utils/use-filter-sync.ts Added useFilterSync hook to synchronize filter state with URL search parameters.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant DataTable
    participant DataTableFilter
    participant useDataTableFilters
    participant Loader (Server)
    participant URL

    User->>DataTable: Interacts with filters/search/pagination
    DataTable->>DataTableFilter: Passes current filter state, columns, actions
    DataTableFilter->>useDataTableFilters: Manages filter state/actions
    DataTable->>URL: Updates URL with filter/search/pagination state
    URL->>Loader (Server): Triggers data fetch with current state
    Loader (Server)->>DataTable: Returns filtered/sorted/paginated data + faceted counts
    DataTable->>DataTableFilter: Updates with new data and faceted info
    DataTableFilter->>User: Renders updated filters and table
Loading

Assessment against linked issues

Objective Addressed Explanation
Implement advanced data table filter components from Bazza UI canary branch into forms repository (LC-219)
Adopt new API structure using props: { columns, filters, actions, strategy, locale }
Integrate internationalization (i18n) support as provided in the canary branch
Preserve performance improvements and UI enhancements from Bazza UI canary branch
Manually extract and adapt necessary components, hooks, utilities, and localization files avoiding automated installs
Resolve dependencies including Tailwind CSS and shadcn/ui components, adapting responsive design as needed
Thoroughly test new filter components for functionality, i18n correctness, responsiveness, and performance Automated UI tests included in stories; i18n and responsiveness supported in components
Provide comprehensive documentation including usage examples, API details, localization options, and migration guidance Documentation presence not verifiable from code changes alone
Fix integration issues in bazza-filters branch: filter selections propagate correctly to table state and URL Filtering state synchronized with URL and server loader; callbacks and state updates implemented
Restore or implement callbacks (onValuesChange) in filter components to update TanStack table’s columnFilters state useDataTableFilters hook and integration replace direct TanStack filter state with Bazza filters
Ensure synchronization between filter UI state, URL query parameters, and backend loader filtering logic URL state sync hook and loader functions handle filtering and URL updates
Decide on filter query parameter strategy and update URL state and loader logic accordingly Uses combined JSON filters parameter with parsing and serialization consistent across layers
Ensure Remix router form integration watches and updates filter state, reflecting UI changes and triggering server filtering Loader functions and form integration updated to handle Bazza filter state
Implement reset functionality clearing all filters in UI and URL state Reset handlers clear filters and search state in UI and URL

Possibly related PRs

  • Standardize sort order param #66: Adds a Storybook story for server-driven filtering with Bazza UI filters and React Table, including URL synchronization and tests; related as it builds on sort order standardization in the same files.

Suggested labels

codex

Poem

In the warren of code, a filter was born,
With columns and options, so neatly adorned.
Operators and sliders, with tabs all anew,
Bazza the bunny hops in for the view!
From debounce to i18n, every bit in place—
This table’s now magic, with filters and grace.
🐇✨

Note

⚡️ AI Code Reviews for VS Code, Cursor, Windsurf

CodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback.
Learn more here.


Note

⚡️ Faster reviews with caching

CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.
Enjoy the performance boost—your workflow just got faster.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3c234af and 47f7768.

📒 Files selected for processing (1)
  • packages/components/src/ui/utils/use-filter-sync.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/components/src/ui/utils/use-filter-sync.ts
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate Unit Tests
  • Create PR with Unit Tests
  • Commit Unit Tests in branch bazza-filters
  • Post Copyable Unit Tests in Comment

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 21

🧹 Nitpick comments (28)
packages/components/src/ui/slider.tsx (1)

8-19: Well-structured component with good defaults.

The Slider component is correctly typed using React.ComponentProps from the Radix primitive. The useMemo implementation for calculating values is efficient, though the logic is somewhat complex in a single line.

Consider improving readability of the values calculation:

-  const _values = React.useMemo(
-    () => (Array.isArray(value) ? value : Array.isArray(defaultValue) ? defaultValue : [min, max]),
-    [value, defaultValue, min, max],
-  );
+  const _values = React.useMemo(() => {
+    if (Array.isArray(value)) return value;
+    if (Array.isArray(defaultValue)) return defaultValue;
+    return [min, max];
+  }, [value, defaultValue, min, max]);
packages/components/src/ui/data-table-filter/lib/i18n.ts (1)

11-13: Consider logging missing translation keys
Currently, missing keys silently fall back to the key itself. You may want to add a console warning or tracking mechanism in the fallback to surface untranslated strings during development.

packages/components/src/ui/data-table-filter/hooks/use-unmount.tsx (2)

3-7: Rename parameter for clarity
Rename func to callback or onUnmount to more clearly convey its purpose as the unmount callback.


8-13: Document intentional empty dependency array
Add a comment explaining that the empty deps array ensures the cleanup only runs on unmount, silencing ESLint warnings and clarifying intent:

// Run cleanup only on unmount; `funcRef` always points to the latest callback
useEffect(() => () => { funcRef.current() }, []);
packages/components/src/ui/data-table-filter/components/filter-actions.tsx (1)

1-26: Well-implemented FilterActions component with appropriate memoization

The FilterActions component is well-structured and serves a clear purpose - providing a button to clear all active filters. The implementation is clean and follows good practices.

Notable aspects:

  1. Proper use of memo to optimize rendering performance
  2. Good conditional visibility based on hasFilters state
  3. Responsive design with the text label hidden on mobile screens
  4. Appropriate use of the destructive button variant for the clear action
  5. Good implementation of localization support with fallback to English

One minor suggestion:

Consider adding a confirmation dialog or tooltip when clearing all filters, especially if users might have set up complex filter combinations that would be lost with a single click.

packages/components/src/ui/data-table-filter/lib/memo.ts (2)

1-8: Consider stricter typing for the memoization utility

The memoization utility uses any in the type definition which reduces type safety. Consider using more specific types or generic constraints.

-export function memo<TDeps extends readonly any[], TResult>(
+export function memo<TDeps extends readonly unknown[], TResult>(
  getDeps: () => TDeps,
  compute: (deps: TDeps) => TResult,
  options: { key: string },
): () => TResult {
  let prevDeps: TDeps | undefined
  let cachedResult: TResult | undefined
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-1: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


10-21: Remove commented-out console.logs

There are several commented-out console.log statements. These should be removed or replaced with a proper logging mechanism if debugging is needed.

  return () => {
-    // console.log(`[memo] Calling memoized function: ${options.key}`)
    const deps = getDeps()

    // If no previous deps or deps have changed, recompute
    if (!prevDeps || !shallowEqual(prevDeps, deps)) {
-      // console.log(`[memo] Cache MISS - ${options.key}`)
      cachedResult = compute(deps)
      prevDeps = deps
    } else {
-      // console.log(`[memo] Cache HIT - ${options.key}`)
    }
packages/components/src/ui/debounced-input.tsx (2)

22-29: Consider explaining why exhaustive dependencies are ignored

The comment biome-ignore lint/correctness/useExhaustiveDependencies: from Bazza UI doesn't provide a clear explanation of why this rule is being ignored. Consider adding more context about what dependencies might be missing and why they're intentionally omitted.

-  // biome-ignore lint/correctness/useExhaustiveDependencies: from Bazza UI
+  // biome-ignore lint/correctness/useExhaustiveDependencies: We only want to recreate the debounced function
+  // when debounceMs or onChange changes, not when the debounce function's internal implementation changes

31-35: Potential optimization for handleChange

Consider memoizing the handleChange function with useCallback to prevent unnecessary rerenders in child components that might receive this function as a prop.

-  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
+  const handleChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
    const newValue = e.target.value;
    setValue(newValue); // Update local state immediately
    debouncedOnChange(newValue); // Call debounced version
-  };
+  }, [debouncedOnChange]);
packages/components/src/ui/dialog.tsx (1)

36-56: DialogContent accessibility enhancement needed

The DialogContent implementation is comprehensive with proper positioning, animations, and a close button. The close button correctly includes an accessible label.

However, consider adding an aria-modal="true" attribute to the DialogContent to improve screen reader announcements.

 <DialogPrimitive.Content
   data-slot="dialog-content"
+  aria-modal="true"
   className={cn(
     'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg',
     className,
   )}
   {...props}
 >
packages/components/src/ui/data-table-filter/lib/helpers.ts (2)

39-54: Simplify the number range creation logic

The createNumberRange function has some redundant code that can be simplified.

 export function createNumberRange(values: number[] | undefined) {
-  let a = 0
-  let b = 0
-
   if (!values || values.length === 0) return [a, b]
+  
+  let a: number, b: number
+  
   if (values.length === 1) {
     a = values[0]
+    b = 0
   } else {
     a = values[0]
     b = values[1]
   }

   const [min, max] = a < b ? [a, b] : [b, a]

   return [min, max]
 }

73-90: Optimize Map type checking performance

The isColumnOptionMap function checks all keys and all values separately, which means iterating through the Map twice. Consider combining these checks for better performance.

 export function isColumnOptionMap(
   value: unknown,
 ): value is Map<string, number> {
   if (!(value instanceof Map)) {
     return false
   }
-  for (const key of value.keys()) {
-    if (typeof key !== 'string') {
-      return false
-    }
-  }
-  for (const val of value.values()) {
-    if (typeof val !== 'number') {
-      return false
-    }
-  }
+  for (const [key, val] of value.entries()) {
+    if (typeof key !== 'string' || typeof val !== 'number') {
+      return false
+    }
+  }
   return true
 }
packages/components/src/ui/data-table-filter/components/active-filters.tsx (2)

83-90: Add an accessible label to the delete-filter button.

The “X” icon alone is not screen-reader friendly. Provide aria-label (or title) so assistive technologies announce the action.

<Button
   variant="ghost"
   className="rounded-none rounded-r-2xl text-xs w-7 h-full"
-  onClick={() => actions.removeFilter(filter.columnId)}
+  onClick={() => actions.removeFilter(filter.columnId)}
+  aria-label={t('removeFilter', locale) /* e.g. “Remove filter” */}
>

145-153: Throttle onScroll handler to avoid excessive re-renders.

checkScroll runs on every scroll event which can fire dozens of times per frame, causing frequent setState calls.
Consider wrapping checkScroll in a small requestAnimationFrame / throttle wrapper or the new useDebounceCallback hook to improve scrolling performance on low-end devices.

packages/components/src/ui/data-table-filter/hooks/use-debounce-callback.tsx (1)

17-23: Avoid any in generic constraints.

(...args: any) loses all type-safety which this hook tries to preserve.

-export type DebouncedState<T extends (...args: any) => ReturnType<T>> =
+export type DebouncedState<T extends (...args: unknown[]) => ReturnType<T>> =

Repeat for other occurrences.
This aligns with the Biome lint error and preserves inference while still being permissive.

🧰 Tools
🪛 Biome (1.9.4)

[error] 17-17: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 22-22: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)

packages/components/src/ui/data-table-filter/components/filter-operator.tsx (2)

230-239: Add heading for Date operator list for consistency & accessibility.

All other controllers set heading={t('operators', locale)} on their CommandGroup; the Date controller omits it, so screen-readers and visual users lose contextual information.

-  return (
-    <CommandGroup>
+  return (
+    <CommandGroup heading={t('operators', locale)}>

288-296: Unify onSelect signature across controllers.

Number controller wraps changeOperator in an extra arrow, unlike the others.
It’s harmless but inconsistent and incurs an unnecessary closure per render.

-  <CommandItem onSelect={() => changeOperator(r.value)} value={r.value} key={r.value}>
+  <CommandItem onSelect={changeOperator} value={r.value} key={r.value}>
packages/components/src/ui/data-table-filter/hooks/use-data-table-filters.tsx (1)

326-329: Remove any cast by tightening generics.

values: newValues as any breaks type-safety and hides potential bugs.
Since newValues is already narrowed by branch logic, you can let TS infer without casting:

-            values: newValues as any,
+            values: newValues,

If the compiler still complains, consider parameterising setFilterValue with a concrete TType so inference succeeds.

🧰 Tools
🪛 Biome (1.9.4)

[error] 328-328: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)

packages/components/src/remix-hook-form/data-table-router-parsers.ts (1)

12-40: Minor: tighten the runtime validator to make intent explicit

parseBazzaFiltersState mutates an accumulator array inside reduce.
An immutable approach is a bit clearer and avoids accidental mutation bugs:

-  return value.reduce((acc: BazzaFiltersState, item) => {
-    if ( … all checks … ) {
-      acc.push({ …mappedFields });
-    }
-    return acc;
-  }, []);
+  return value
+    .filter(
+      (item): item is BazzaFilterItem =>
+        typeof item === 'object' &&
+        item !== null &&
+        typeof (item as any).columnId === 'string' &&
+        typeof (item as any).type === 'string' &&
+        typeof (item as any).operator === 'string' &&
+        Array.isArray((item as any).values),
+    )
+    .map((item) => ({
+      columnId: item.columnId,
+      type: item.type,
+      operator: item.operator,
+      values: item.values,
+    }));

Functionality stays identical but the intent (filter-then-map) is clearer and side-effect free.

packages/components/src/remix-hook-form/data-table-router-form.tsx (2)

108-131: getFilteredRowModel + manualFiltering: true = wasted CPU

React-Table will still run its filter pipeline on the client even though you always read server-filtered data. Remove the model getters you don’t need:

- getFilteredRowModel: getFilteredRowModel(),
- getFacetedRowModel: getFacetedRowModel(),
- getFacetedUniqueValues: getFacetedUniqueValues(),

This cuts render time on wide/long tables.


165-183: Reset handler may race with URL-state sync

Calling both dtfActions.setFiltersState([]) and setUrlState({ filters: [] }) can create a race
where the second call is cancelled by the first effect. Consider a single source of truth:

const handleReset = () => setUrlState(standardStateValues); // URL drives Bazza via the sync-effect

Less code, fewer surprises.

apps/docs/src/remix-hook-form/data-table-bazza-filters.stories.tsx (5)

350-356: Stale URLSearchParams captured in the handler

searchParams is created once per render, but the pagination handler is memo-free, so after navigation it may mutate an out-of-date params instance, dropping newer query keys.

Refactor the handlers to build a fresh URLSearchParams from location.search just before mutation:

-const handlePaginationChange: OnChangeFn<PaginationState> = (updaterOrValue) => {
-  const next = typeof updaterOrValue === 'function' ? updaterOrValue(pagination) : updaterOrValue;
-  searchParams.set('page', next.pageIndex.toString());
-  searchParams.set('pageSize', next.pageSize.toString());
-  navigate(`${location.pathname}?${searchParams.toString()}`, { replace: true });
-};
+const handlePaginationChange: OnChangeFn<PaginationState> = (updaterOrValue) => {
+  const next = typeof updaterOrValue === 'function' ? updaterOrValue(pagination) : updaterOrValue;
+  const params = new URLSearchParams(location.search);
+  params.set('page', String(next.pageIndex));
+  params.set('pageSize', String(next.pageSize));
+  navigate(`${location.pathname}?${params.toString()}`, { replace: true });
+};

358-368: Duplicate issue – sorting handler

Same stale-params risk as above; rebuild URLSearchParams inside the handler.
(Apply the same pattern shown in the previous diff.)


306-309: Avoid double parsing – Date already is a Date

row.getValue('createdDate') returns the original Date; wrapping it with new Date() is unnecessary and silently converts invalid dates to Invalid Date.

-cell: ({ row }) => <div>{new Date(row.getValue('createdDate')).toLocaleDateString()}</div>,
+cell: ({ row }) => {
+  const date = row.getValue<Date>('createdDate');
+  return <div>{date.toLocaleDateString()}</div>;
+},

437-448: Remove debug console.log statements before committing

Leaving console output in loader code clutters browser/dev-tools and leaks internal details to users.
Please drop or guard them behind a debug flag.


579-582: Make Storybook assertion deterministic

expect(rows.length).toBeGreaterThan(1) is brittle—if the pageSize ever changes to 0 the test still passes.
Prefer asserting the exact expected count:

-// First row is header, so we expect pageSize + 1 rows
-expect(rows.length).toBeGreaterThan(1);
+// Header row + 10 data rows (default pageSize = 10)
+expect(rows).toHaveLength(11);
packages/components/src/ui/data-table-filter/core/filters.ts (1)

53-57: Tighten icon() builder typing

Using any defeats the purpose of the strong generic API and triggers Biome errors.
Accept exactly what will be stored in ColumnConfig['icon'].

-  icon(value: any): ColumnConfigBuilder<TData, TType, TVal, TId> {
+  icon(value: LucideIcon | ElementType<unknown> | ReactElement): ColumnConfigBuilder<TData, TType, TVal, TId> {

LucideIcon is already used in the final config type; mirroring it here removes the explicit-any violations.

🧰 Tools
🪛 Biome (1.9.4)

[error] 53-53: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)

packages/components/src/ui/data-table-filter/core/types.ts (1)

29-31: Avoid any in icon prop

We can keep flexibility without sacrificing type-safety by using unknown instead of any.

-  // biome-ignore lint/suspicious/noExplicitAny: any for flexibility
-  icon?: ReactElement | ElementType<any>;
+  icon?: ReactElement | ElementType<unknown>;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2dc3e5b and 20b0070.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (37)
  • .vscode/settings.json (1 hunks)
  • apps/docs/src/remix-hook-form/data-table-bazza-filters.stories.tsx (1 hunks)
  • apps/docs/src/remix-hook-form/data-table-router-form.stories.tsx (7 hunks)
  • packages/components/package.json (1 hunks)
  • packages/components/src/remix-hook-form/data-table-router-form.tsx (3 hunks)
  • packages/components/src/remix-hook-form/data-table-router-parsers.ts (4 hunks)
  • packages/components/src/remix-hook-form/data-table-router-toolbar.tsx (1 hunks)
  • packages/components/src/ui/button.tsx (2 hunks)
  • packages/components/src/ui/calendar.tsx (1 hunks)
  • packages/components/src/ui/checkbox.tsx (1 hunks)
  • packages/components/src/ui/data-table-filter/components/active-filters.tsx (1 hunks)
  • packages/components/src/ui/data-table-filter/components/data-table-filter.tsx (1 hunks)
  • packages/components/src/ui/data-table-filter/components/filter-actions.tsx (1 hunks)
  • packages/components/src/ui/data-table-filter/components/filter-operator.tsx (1 hunks)
  • packages/components/src/ui/data-table-filter/components/filter-selector.tsx (1 hunks)
  • packages/components/src/ui/data-table-filter/components/filter-subject.tsx (1 hunks)
  • packages/components/src/ui/data-table-filter/components/filter-value.tsx (1 hunks)
  • packages/components/src/ui/data-table-filter/core/filters.ts (1 hunks)
  • packages/components/src/ui/data-table-filter/core/operators.ts (1 hunks)
  • packages/components/src/ui/data-table-filter/core/types.ts (1 hunks)
  • packages/components/src/ui/data-table-filter/hooks/use-data-table-filters.tsx (1 hunks)
  • packages/components/src/ui/data-table-filter/hooks/use-debounce-callback.tsx (1 hunks)
  • packages/components/src/ui/data-table-filter/hooks/use-unmount.tsx (1 hunks)
  • packages/components/src/ui/data-table-filter/index.tsx (1 hunks)
  • packages/components/src/ui/data-table-filter/lib/array.ts (1 hunks)
  • packages/components/src/ui/data-table-filter/lib/debounce.ts (1 hunks)
  • packages/components/src/ui/data-table-filter/lib/filter-fns.ts (1 hunks)
  • packages/components/src/ui/data-table-filter/lib/helpers.ts (1 hunks)
  • packages/components/src/ui/data-table-filter/lib/i18n.ts (1 hunks)
  • packages/components/src/ui/data-table-filter/lib/memo.ts (1 hunks)
  • packages/components/src/ui/data-table-filter/locales/en.json (1 hunks)
  • packages/components/src/ui/debounced-input.tsx (1 hunks)
  • packages/components/src/ui/dialog.tsx (1 hunks)
  • packages/components/src/ui/popover.tsx (2 hunks)
  • packages/components/src/ui/slider.tsx (1 hunks)
  • packages/components/src/ui/tabs.tsx (1 hunks)
  • packages/components/src/ui/utils/debounce.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (15)
packages/components/src/ui/utils/debounce.ts (1)
packages/components/src/ui/data-table-filter/lib/debounce.ts (1)
  • debounce (13-138)
packages/components/src/ui/button.tsx (1)
packages/components/src/ui/utils/index.ts (1)
  • cn (4-6)
packages/components/src/ui/checkbox.tsx (1)
packages/components/src/ui/utils/index.ts (1)
  • cn (4-6)
packages/components/src/ui/calendar.tsx (2)
packages/components/src/ui/utils/index.ts (1)
  • cn (4-6)
packages/components/src/ui/button.tsx (1)
  • buttonVariants (43-43)
packages/components/src/ui/data-table-filter/components/data-table-filter.tsx (6)
packages/components/src/ui/data-table-filter/core/types.ts (4)
  • Column (155-157)
  • FiltersState (250-250)
  • DataTableFilterActions (163-184)
  • FilterStrategy (186-186)
packages/components/src/ui/data-table-filter/lib/i18n.ts (1)
  • Locale (3-3)
packages/components/src/ui/data-table-filter/index.tsx (1)
  • DataTableFilter (2-2)
packages/components/src/ui/data-table-filter/components/filter-selector.tsx (1)
  • FilterSelector (30-30)
packages/components/src/ui/data-table-filter/components/filter-actions.tsx (1)
  • FilterActions (14-14)
packages/components/src/ui/data-table-filter/components/active-filters.tsx (2)
  • ActiveFiltersMobileContainer (94-156)
  • ActiveFilters (27-57)
packages/components/src/ui/tabs.tsx (1)
packages/components/src/ui/utils/index.ts (1)
  • cn (4-6)
packages/components/src/ui/data-table-filter/components/filter-actions.tsx (4)
packages/components/src/ui/data-table-filter/core/types.ts (1)
  • DataTableFilterActions (163-184)
packages/components/src/ui/data-table-filter/lib/i18n.ts (2)
  • Locale (3-3)
  • t (11-13)
packages/components/src/ui/button.tsx (1)
  • Button (36-39)
packages/components/src/ui/utils/index.ts (1)
  • cn (4-6)
packages/components/src/ui/slider.tsx (1)
packages/components/src/ui/utils/index.ts (1)
  • cn (4-6)
packages/components/src/ui/data-table-filter/lib/helpers.ts (1)
packages/components/src/ui/data-table-filter/core/types.ts (2)
  • Column (155-157)
  • ColumnOption (23-31)
packages/components/src/ui/data-table-filter/components/filter-subject.tsx (1)
packages/components/src/ui/data-table-filter/core/types.ts (2)
  • ColumnDataType (41-49)
  • Column (155-157)
packages/components/src/ui/dialog.tsx (1)
packages/components/src/ui/utils/index.ts (1)
  • cn (4-6)
packages/components/src/ui/data-table-filter/core/operators.ts (1)
packages/components/src/ui/data-table-filter/core/types.ts (6)
  • ColumnDataType (41-49)
  • FilterOperatorTarget (259-259)
  • FilterOperators (226-232)
  • FilterDetails (255-257)
  • FilterTypeOperatorDetails (303-305)
  • FilterValues (71-71)
packages/components/src/ui/data-table-filter/lib/filter-fns.ts (3)
packages/components/src/ui/data-table-filter/core/types.ts (1)
  • FilterModel (243-248)
packages/components/src/ui/data-table-filter/lib/array.ts (1)
  • intersection (1-3)
packages/components/src/ui/data-table-filter/core/operators.ts (1)
  • dateFilterOperators (136-227)
packages/components/src/ui/data-table-filter/lib/debounce.ts (1)
packages/components/src/ui/utils/debounce.ts (1)
  • debounce (10-25)
apps/docs/src/remix-hook-form/data-table-router-form.stories.tsx (1)
packages/components/src/remix-hook-form/data-table-router-parsers.ts (3)
  • dataTableRouterParsers (82-115)
  • BazzaFiltersState (9-9)
  • BazzaFilterItem (2-7)
🪛 Biome (1.9.4)
packages/components/src/ui/data-table-filter/lib/memo.ts

[error] 1-1: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 23-23: Forbidden non-null assertion.

(lint/style/noNonNullAssertion)

packages/components/src/ui/data-table-filter/hooks/use-data-table-filters.tsx

[error] 31-31: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 31-31: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 31-31: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 51-51: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 51-51: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 51-51: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 328-328: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)

packages/components/src/ui/data-table-filter/hooks/use-debounce-callback.tsx

[error] 17-17: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 22-22: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)

packages/components/src/remix-hook-form/data-table-router-toolbar.tsx

[error] 18-18: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 20-20: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)

packages/components/src/remix-hook-form/data-table-router-form.tsx

[error] 42-42: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 44-44: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 45-45: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)

packages/components/src/ui/data-table-filter/lib/array.ts

[error] 11-11: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 28-29: Forbidden non-null assertion.

(lint/style/noNonNullAssertion)


[error] 54-54: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 54-54: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 104-105: Forbidden non-null assertion.

(lint/style/noNonNullAssertion)

packages/components/src/ui/data-table-filter/lib/debounce.ts

[error] 13-13: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 13-13: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 21-21: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 93-93: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)

packages/components/src/ui/data-table-filter/core/filters.ts

[error] 19-19: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 36-36: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 42-42: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 53-53: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 63-63: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 72-72: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 83-83: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 94-94: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 105-105: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 163-163: Forbidden non-null assertion.

Unsafe fix: Replace with optional chain operator ?. This operator includes runtime checks, so it is safer than the compile-only non-null assertion operator

(lint/style/noNonNullAssertion)


[error] 171-171: Forbidden non-null assertion.

Unsafe fix: Replace with optional chain operator ?. This operator includes runtime checks, so it is safer than the compile-only non-null assertion operator

(lint/style/noNonNullAssertion)


[error] 290-290: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 290-290: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 290-290: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 296-296: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 296-296: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 300-300: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 308-308: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 308-308: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)

packages/components/src/ui/data-table-filter/core/types.ts

[error] 94-94: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 112-112: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 112-112: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 112-112: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 112-112: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 118-118: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 118-118: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 118-118: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 118-118: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 155-155: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 243-243: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)

🔇 Additional comments (55)
.vscode/settings.json (1)

4-4: LGTM: Appropriate dictionary addition.

Adding "Bazza" to the VS Code spell checker dictionary makes sense as this PR integrates Bazza UI filters throughout the codebase.

packages/components/src/ui/slider.tsx (1)

21-54: Well-implemented accessible Slider with responsive styling.

The component correctly implements:

  • Proper data attributes for styling and accessibility
  • Responsive layout for both horizontal and vertical orientations
  • Support for multiple thumbs based on values array length
  • Appropriate styling for interactive states (hover, focus, disabled)

The use of the cn utility ensures proper class composition and Tailwind compatibility.

packages/components/src/ui/popover.tsx (2)

9-10: LGTM: Appropriate addition of PopoverAnchor.

Exposing the PopoverAnchor component from Radix UI's primitive provides more flexibility for positioning popovers in the UI.


33-33: LGTM: Updated exports list.

The export list has been correctly updated to include the new PopoverAnchor component while maintaining alphabetical order.

packages/components/src/ui/utils/debounce.ts (2)

9-10: LGTM: Appropriate linter comment.

The added linter comment properly explains why any is used in the generic type, which provides clarity and prevents linting issues.


13-24: LGTM: Improved function style.

The debounce implementation has been refactored to use an arrow function and has better code spacing, improving readability without changing functionality.

This simpler implementation focuses on the core debounce functionality, while a more comprehensive version with additional features exists in the data-table-filter library.

packages/components/src/ui/data-table-filter/lib/i18n.ts (1)

1-9: Clean and type-safe translations mapping
The translations object and Locale type are correctly set up for English-only support, and importing en.json leverages TS module support.

packages/components/src/ui/data-table-filter/index.tsx (1)

1-2: Centralized exports for data-table-filter
Re-exporting the hook and component in a single entry point simplifies imports and aligns with module conventions.

packages/components/src/ui/button.tsx (4)

3-3: Verify JSX runtime configuration
Removing the namespace import of React relies on the automatic JSX transform (React 17+). Ensure your tsconfig ("jsx": "react-jsx") or Babel setup is configured accordingly.


32-34: Props extend standardized HTML attributes
Extending ButtonHTMLAttributes<HTMLButtonElement> aligns with React's built-in types and removes the need for namespace imports. Good move for tree-shaking and type clarity.


36-39: Simplify component JSX
The one-liner return maintains behavior while improving readability. Nice refactor.


43-43: Exporting buttonVariants for external composition
Re-exporting buttonVariants enables consumers to build custom components with shared styling logic. This enhances reusability.

packages/components/package.json (1)

45-57:

❓ Verification inconclusive

Bump Radix UI dependencies and add new components
Ensure the updated versions and newly added packages (slider, tabs) are correctly installed and there are no version conflicts.

Run this script to confirm installed versions match package.json:


🏁 Script executed:

#!/bin/bash
# Verify installed Radix UI versions
npm ls @radix-ui/react-checkbox \
       @radix-ui/react-dialog \
       @radix-ui/react-dropdown-menu \
       @radix-ui/react-label \
       @radix-ui/react-popover \
       @radix-ui/react-separator \
       @radix-ui/react-slider \
       @radix-ui/react-slot \
       @radix-ui/react-tabs

Length of output: 267


Verify Radix UI dependency installation and versions
The npm ls output showed an empty tree, indicating none of the Radix packages are currently installed. Please ensure you’ve installed dependencies and that the installed versions align with your packages/components/package.json (lines 45–57):

  • Run your package manager’s install command (e.g., npm install or yarn install).
  • Re-verify with a depth-restricted listing:
    npm ls @radix-ui/react-checkbox \
           @radix-ui/react-dialog \
           @radix-ui/react-dropdown-menu \
           @radix-ui/react-label \
           @radix-ui/react-popover \
           @radix-ui/react-separator \
           @radix-ui/react-slider \
           @radix-ui/react-slot \
           @radix-ui/react-tabs --depth=0
  • If packages still don’t appear, inspect your lockfile or node_modules to confirm the versions (^1.3.4 for slider, ^1.1.11 for tabs, etc.) match those in package.json.
packages/components/src/ui/data-table-filter/components/filter-subject.tsx (1)

1-17: Well-structured generic component for filter subject representation

This is a clean implementation of a reusable FilterSubject component. The component provides a consistent visual representation for filter subjects with proper handling of optional icons. Good use of TypeScript generics to maintain type safety with the data table column configuration.

A few notes for consideration:

  1. The component properly handles the case when column.icon is undefined with the hasIcon check.
  2. The CSS classes provide appropriate spacing, font styling, and ensure text doesn't wrap.
  3. The select-none class is a good UX choice to prevent accidental text selection.
packages/components/src/ui/checkbox.tsx (1)

1-27: Good implementation of accessible Checkbox component using Radix UI primitives

This Checkbox component is well-structured and follows best practices for creating accessible UI components. It properly wraps Radix UI's checkbox primitive with appropriate styling and behavior.

Some positive aspects:

  1. Uses the cn utility to combine class names efficiently
  2. Comprehensive styling covering various states (checked, focus, disabled, invalid)
  3. Proper support for dark mode
  4. Accessible styling with appropriate focus indicators
  5. Proper forwarding of props to the underlying Radix component
  6. Good use of semantic data attributes for styling and testing
packages/components/src/ui/data-table-filter/locales/en.json (1)

1-42: Comprehensive localization file with well-organized filter terminology

This English localization file provides a thorough set of translations for the data table filtering system. The organization is logical and covers all necessary UI elements and filter operations.

Positive aspects:

  1. Comprehensive coverage of all filter-related terminology
  2. Well-structured organization with clear key naming conventions
  3. Consistent terminology for similar operations across different data types
  4. Detailed operator descriptions that are user-friendly and precise

The localization keys follow a logical hierarchical structure (e.g., filters.text.contains, filters.number.is), making it easy to maintain and extend. This will provide a solid foundation for adding additional languages in the future.

packages/components/src/ui/calendar.tsx (1)

1-58: Great implementation of the Calendar component!

This is a well-structured implementation of a Calendar component that wraps the DayPicker from react-day-picker with consistent styling. The component:

  • Properly handles both single date and range selection modes
  • Uses custom icon components for navigation
  • Implements responsive styling with Tailwind CSS
  • Maintains full configurability by spreading remaining props

The use of the cn utility function for class merging and the buttonVariants for consistent styling shows good adherence to the design system.

packages/components/src/ui/data-table-filter/components/data-table-filter.tsx (1)

1-44: Well-structured responsive filter implementation

The component provides an excellent responsive design with separate mobile and desktop layouts. Good use of:

  • Conditional rendering based on screen size
  • Consistent prop passing to child components
  • Proper typing with generics
  • Default locale handling

The mobile experience includes a scrollable container for active filters, while the desktop version has a more spacious layout - demonstrating thoughtful UI/UX design.

packages/components/src/ui/debounced-input.tsx (1)

5-14: Clean implementation of DebouncedInput component

The component provides a well-structured debounced input with appropriate TypeScript typing, default debounce time, and proper prop passing. Good separation of immediate UI updates from debounced callbacks.

packages/components/src/ui/tabs.tsx (4)

1-10: Well-structured Tabs component with appropriate accessibility attributes

The implementation correctly uses Radix UI primitives and applies the client directive for Next.js compatibility. The Tabs component has appropriate data-slot attributes for styling/targeting and sensible default styling.


12-23: TabsList component follows best practices

The TabsList component properly wraps the Radix UI primitive with appropriate styling and semantic structure. The inline-flex container with proper padding and rounded corners provides a good foundation for tab navigation.


25-36: TabsTrigger has comprehensive state handling

The TabsTrigger component includes detailed styling for various states (active, focus, disabled) and handles SVG icons appropriately. The extensive Tailwind classes properly implement the component design system.


38-43: TabsContent and exports are well implemented

The TabsContent component and exports follow the established pattern. The component is minimal but functional with flex-grow and no outline when focused.

packages/components/src/ui/dialog.tsx (5)

1-21: Dialog primitives correctly implemented

The basic Dialog components (Dialog, DialogTrigger, DialogPortal, DialogClose) are properly implemented with appropriate data-slot attributes for styling and targeting.


23-34: DialogOverlay animation states well configured

The DialogOverlay component includes proper animation states for opening and closing transitions, which provides a smooth user experience.


58-76: Header and Footer components have responsive layout

The DialogHeader and DialogFooter components are implemented with responsive layouts that adjust based on screen size. The footer's column-reverse/row layout pattern is a good practice for mobile-first design.


78-96: Title and Description components properly styled

The DialogTitle and DialogDescription components follow the established pattern with appropriate text styling that matches the design system.


98-109: Export block is comprehensive and well-ordered

All dialog components are properly exported in an organized manner.

packages/components/src/ui/data-table-filter/lib/debounce.ts (7)

1-17: Type definitions for debounce are well structured

The control functions and options interfaces are clearly defined, providing a good API for the debounce function.

🧰 Tools
🪛 Biome (1.9.4)

[error] 13-13: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 13-13: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


18-27: State variables are properly initialized

The debounce function initializes all necessary state variables and correctly extracts options with sensible defaults.

🧰 Tools
🪛 Biome (1.9.4)

[error] 21-21: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


28-49: Core utility functions well implemented

The invokeFunc and shouldInvoke utility functions properly handle the debounce timing logic with appropriate conditions.


51-66: Timer management functions handle edge cases

The timer functions correctly manage scheduling and calculate remaining wait times. The remainingWait function properly handles the maxWaitTime option.


68-90: Edge handling for leading and trailing execution

The timerExpired, leadingEdge, and trailingEdge functions implement the core debounce behavior with proper handling of leading and trailing execution options.


92-116: Main debounced function has correct behavior

The main debounced function correctly implements the debounce pattern with proper timing and execution control based on the provided options.

🧰 Tools
🪛 Biome (1.9.4)

[error] 93-93: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


118-137: Control functions properly implemented

The control functions (cancel, flush, isPending) provide a comprehensive API for controlling the debounced function's behavior.

packages/components/src/ui/data-table-filter/lib/helpers.ts (5)

4-12: Column retrieval function has proper error handling

The getColumn function correctly finds a column by ID and throws a descriptive error if not found, which helps with debugging.


14-21: Number filter value creation handles various cases

The createNumberFilterValue function correctly handles empty, single value, and range cases for number filters.


23-30: Date filter value creation has proper validation

The createDateFilterValue function correctly handles valid date filter cases and throws an error for invalid inputs.


32-54: Range creation functions ensure proper ordering

Both createDateRange and createNumberRange correctly ensure that the returned ranges are in ascending order, which is important for filtering operations.


56-99: Type guards improve runtime type safety

The type guard functions are well implemented and provide runtime validation for complex types, which is essential for robust filtering operations.

packages/components/src/remix-hook-form/data-table-router-form.tsx (1)

66-79: useDataTableFilters call: sending data on strategy: "server" is misleading

When strategy is "server" the hook is expected to treat data as faceted meta, not the
full table rows ­– otherwise the hook might memoize large datasets unnecessarily.

If the rows are already filtered server-side, consider:

-  data: data,
+  data: [],          // or omit the param if optional

(or rename the prop in the hook to initialData vs serverData to make the intent clearer).

packages/components/src/ui/data-table-filter/lib/filter-fns.ts (1)

55-63: exclude vs exclude if any of behave identically

Both branches return true when no filter value overlaps.
exclude if any of should only exclude when at least one value matches.

-   case 'exclude if any of':
-     return !(intersection(values, filterValues).length > 0)
+   case 'exclude if any of':
+     return intersection(values, filterValues).length === 0

Verify the business rule and adjust the predicate (or operators meta) accordingly.

packages/components/src/ui/data-table-filter/lib/array.ts (5)

11-18: Avoid any – preserve type–safety of helper utilities

deepHash accepts value: any, which propagates loss of type information throughout the helper stack and triggers Biome’s noExplicitAny warning.
Because this helper is only ever read-only, switching to unknown (and narrowing via typeof / Array.isArray) maintains safety at no cost:

-function deepHash(value: any, cache = new WeakMap<object, string>()): string {
+function deepHash(value: unknown, cache = new WeakMap<object, string>()): string {

Do the same for deepEqual and any other helpers that currently fall back to any.
[ suggest_essential_refactor ]

🧰 Tools
🪛 Biome (1.9.4)

[error] 11-11: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


26-34: Cache is rebuilt on every top-level call – reconsider scope

deepHash creates a new WeakMap for each invocation, meaning identical objects hashed in separate calls do not benefit from memoisation.
If cross-call caching is desired, lift the WeakMap out of the function:

const _deepHashCache = new WeakMap<object, string>();

function deepHash(value: unknown, cache: WeakMap<object,string> = _deepHashCache) { ... }

Otherwise please add a comment clarifying the intentional per-call cache so future readers don’t assume inter-call memoisation.
[ suggest_optional_refactor ]

🧰 Tools
🪛 Biome (1.9.4)

[error] 28-29: Forbidden non-null assertion.

(lint/style/noNonNullAssertion)


54-86: deepEqual edge-cases: dates, NaN, and other iterables

The current implementation:

  • Treats Date objects as plain objects – two equal dates (new Date('…')) will compare false.
  • Fails for NaN (NaN !== NaN).
  • Skips Map, Set, RegExp, typed-arrays, etc.

If these utilities will be reused outside the simple filter use-case, consider delegating to a battle-tested library (fast-deep-equal, dequal, etc.) or extend the switch with the missing branches.
[ request_verification ]

🧰 Tools
🪛 Biome (1.9.4)

[error] 54-54: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 54-54: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


95-123: uniq still O(n²) in worst case

Although a Map is used, the inner duplicateFound scan is linear in the number of collisions, which for adversarial data regresses to quadratic behaviour.
Since deepEqual is already deterministic, you can store a single representative per hash and skip the nested loop:

-const seen = new Map<string, T[]>()
+const seen = new Map<string, T>()

...
- if (seen.has(hash)) {
-     const existing = seen.get(hash)!
-     if (!deepEqual(existing, item)) {
-        result.push(item)
-     }
- } else {
-     seen.set(hash, item)
-     result.push(item)
- }
+ if (!seen.has(hash) || !deepEqual(seen.get(hash), item)) {
+     seen.set(hash, item)
+     result.push(item)
+ }

[ suggest_optional_refactor ]

🧰 Tools
🪛 Biome (1.9.4)

[error] 104-105: Forbidden non-null assertion.

(lint/style/noNonNullAssertion)


138-140: removeUniq uses shallow comparison – breaks for objects

values.includes(v) compares by reference; for filter value objects identical–by-content but different-by-reference this will fail.

Reuse the deep-equality helpers:

-export function removeUniq<T>(arr: T[], values: T[]): T[] {
-  return arr.filter((v) => !values.includes(v))
+export function removeUniq<T>(arr: T[], values: T[]): T[] {
+  return arr.filter(
+    (v) => !values.some((val) => deepEqual(val, v)),
+  )
 }

[ raise_critical_issue ]

apps/docs/src/remix-hook-form/data-table-router-form.stories.tsx (5)

90-98: Duplicate type / filterType fields – consider consolidating

BazzaFilterColumnConfig defines both type and filterType, each seemingly holding the same discriminator ('text' | 'option' | …). Having two sources of truth invites drift. If they are indeed identical, drop one or derive the second (typefilterType as const).
[ suggest_optional_refactor ]


100-133: Hard-coded strings – prefer string literals / enums

Operator strings such as 'option', 'text' etc. are sprinkled throughout. Extract them into a shared union/enumeration (already present in core filter types) to obtain full type-safety and auto-completion.
[ suggest_optional_refactor ]


135-149: Remove console debugging before commit

Multiple console.log / console.warn statements remain:

bazzaFilterColumnConfigs.forEach((config) => {
  console.log('>>>>> config', config);
  ...
});

Leftover logging clutters Storybook output, leaks internal data to the console and can incur performance costs. Please clean them up or guard behind a dev flag.
[ suggest_nitpick ]


156-169: Duplicate runtime option validation

The second bazzaFilterColumnConfigs.forEach loop repeats the same label-validation logic executed just above. If you need this at render time, factor it into a reusable helper; otherwise delete to avoid needless work every render.
[ suggest_nitpick ]


217-246: Default-pass branches mask unsupported operators

When an unknown operator is encountered, the filter currently returns true, effectively disabling filtering for that criterion. This can silently hide bugs. Instead, fail fast:

- default:
-   return true;
+ default:
+   console.warn(`Unhandled operator '${operator}' for type '${type}'`);
+   return false;

This surfaces mis-configurations during development.
[ suggest_essential_refactor ]

packages/components/src/ui/data-table-filter/components/filter-value.tsx (3)

156-160: isValidElement(Icon) always false – use element, not component

isValidElement expects a JSX element, yet Icon is a component reference. The predicate will therefore always return false, making the ternary redundant.

-{hasIcon && (isValidElement(Icon) ? Icon : <Icon className="size-4 text-primary" />)}
+{hasIcon && <Icon className="size-4 text-primary" />}

Apply the same change everywhere isValidElement(Icon) or cloneElement(Icon, …) is used. If you need to accept both a ready-made element and a component, use React.isValidElement(icon) ? icon : <Icon … />.
[ raise_critical_issue ]


626-630: useEffect update condition inverted – state never refreshes

The effect only runs setValues when filter.values and values are already equal. The intention was presumably the opposite:

-if (filter?.values && filter.values.length === values.length && filter.values.every((v,i)=>v===values[i])) {
-  setValues(filter.values);
-}
+if (filter?.values && !filter.values.every((v, i) => v === values[i])) {
+  setValues(filter.values);
+}

Without this fix, external updates to the filter are ignored, causing slider & inputs to desynchronise.
[ raise_critical_issue ]


658-684: Cancel debounce before state change to avoid stale closures

Great job cancelling pending debounced calls before switching operator/type 👏.
Minor: the actions.setFilterOperator call uses column.id, whereas setFilterValue uses the entire column object. Consider unifying (pass column object everywhere or expose operator setter that accepts the object) to keep APIs coherent.
[ suggest_nitpick ]

Comment on lines +9 to +24
return () => {
// console.log(`[memo] Calling memoized function: ${options.key}`)

const deps = getDeps()

// If no previous deps or deps have changed, recompute
if (!prevDeps || !shallowEqual(prevDeps, deps)) {
// console.log(`[memo] Cache MISS - ${options.key}`)
cachedResult = compute(deps)
prevDeps = deps
} else {
// console.log(`[memo] Cache HIT - ${options.key}`)
}

return cachedResult!
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove non-null assertion and handle undefined case properly

The code uses a non-null assertion on line 23 when returning cachedResult!. This could be problematic if compute() returns undefined. Consider handling this case explicitly.

  return () => {
    // console.log(`[memo] Calling memoized function: ${options.key}`)

    const deps = getDeps()

    // If no previous deps or deps have changed, recompute
    if (!prevDeps || !shallowEqual(prevDeps, deps)) {
      // console.log(`[memo] Cache MISS - ${options.key}`)
      cachedResult = compute(deps)
      prevDeps = deps
    } else {
      // console.log(`[memo] Cache HIT - ${options.key}`)
    }

-    return cachedResult!
+    return cachedResult as TResult
  }

Alternatively, you could initialize cachedResult with the result of the first computation:

export function memo<TDeps extends readonly unknown[], TResult>(
  getDeps: () => TDeps,
  compute: (deps: TDeps) => TResult,
  options: { key: string },
): () => TResult {
-  let prevDeps: TDeps | undefined
-  let cachedResult: TResult | undefined
+  let prevDeps: TDeps = getDeps()
+  let cachedResult: TResult = compute(prevDeps)

  return () => {
    // console.log(`[memo] Calling memoized function: ${options.key}`)

    const deps = getDeps()

    // If no previous deps or deps have changed, recompute
-    if (!prevDeps || !shallowEqual(prevDeps, deps)) {
+    if (!shallowEqual(prevDeps, deps)) {
      // console.log(`[memo] Cache MISS - ${options.key}`)
      cachedResult = compute(deps)
      prevDeps = deps
    } else {
      // console.log(`[memo] Cache HIT - ${options.key}`)
    }

-    return cachedResult!
+    return cachedResult
  }
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return () => {
// console.log(`[memo] Calling memoized function: ${options.key}`)
const deps = getDeps()
// If no previous deps or deps have changed, recompute
if (!prevDeps || !shallowEqual(prevDeps, deps)) {
// console.log(`[memo] Cache MISS - ${options.key}`)
cachedResult = compute(deps)
prevDeps = deps
} else {
// console.log(`[memo] Cache HIT - ${options.key}`)
}
return cachedResult!
}
export function memo<TDeps extends readonly unknown[], TResult>(
getDeps: () => TDeps,
compute: (deps: TDeps) => TResult,
options: { key: string },
): () => TResult {
let prevDeps: TDeps = getDeps()
let cachedResult: TResult = compute(prevDeps)
return () => {
// console.log(`[memo] Calling memoized function: ${options.key}`)
const deps = getDeps()
if (!shallowEqual(prevDeps, deps)) {
// console.log(`[memo] Cache MISS - ${options.key}`)
cachedResult = compute(deps)
prevDeps = deps
} else {
// console.log(`[memo] Cache HIT - ${options.key}`)
}
return cachedResult
}
}
🧰 Tools
🪛 Biome (1.9.4)

[error] 23-23: Forbidden non-null assertion.

(lint/style/noNonNullAssertion)

🤖 Prompt for AI Agents (early access)
In packages/components/src/ui/data-table-filter/lib/memo.ts around lines 9 to
24, the return statement uses a non-null assertion on cachedResult, which can
cause issues if compute() returns undefined. To fix this, remove the non-null
assertion and explicitly handle the case where cachedResult might be undefined
by initializing cachedResult with the result of the first compute call before
returning it, ensuring the function always returns a defined value or handles
undefined safely.

Comment on lines 13 to 17
export function debounce<T extends (...args: any[]) => any>(
func: T,
wait: number,
options: DebounceOptions = {},
): ((...args: Parameters<T>) => ReturnType<T> | undefined) & ControlFunctions {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Replace any with more specific types

The use of any in the function signature reduces type safety. Consider using generic types with constraints instead.

-export function debounce<T extends (...args: any[]) => any>(
+export function debounce<T extends (...args: unknown[]) => unknown>(
   func: T,
   wait: number,
   options: DebounceOptions = {},
 ): ((...args: Parameters<T>) => ReturnType<T> | undefined) & ControlFunctions {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function debounce<T extends (...args: any[]) => any>(
func: T,
wait: number,
options: DebounceOptions = {},
): ((...args: Parameters<T>) => ReturnType<T> | undefined) & ControlFunctions {
export function debounce<T extends (...args: unknown[]) => unknown>(
func: T,
wait: number,
options: DebounceOptions = {},
): ((...args: Parameters<T>) => ReturnType<T> | undefined) & ControlFunctions {
🧰 Tools
🪛 Biome (1.9.4)

[error] 13-13: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 13-13: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)

🤖 Prompt for AI Agents (early access)
In packages/components/src/ui/data-table-filter/lib/debounce.ts around lines 13
to 17, replace the use of 'any' in the function signature with more specific
generic types and constraints to improve type safety. Adjust the generic
parameter to better capture the function's argument and return types without
resorting to 'any', ensuring the debounce function signature is strongly typed.

}

function debounced(
this: any,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Replace any with more specific type for this

Using any for the this type reduces type safety. Consider using a more specific type or unknown.

-  function debounced(
-    this: any,
+  function debounced(
+    this: unknown,
     ...args: Parameters<T>
   ): ReturnType<T> | undefined {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
this: any,
function debounced(
this: unknown,
...args: Parameters<T>
): ReturnType<T> | undefined {
🧰 Tools
🪛 Biome (1.9.4)

[error] 93-93: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)

🤖 Prompt for AI Agents (early access)
In packages/components/src/ui/data-table-filter/lib/debounce.ts at line 93,
replace the `this` type annotation from `any` to a more specific type that
accurately reflects the context in which the function is called, or use
`unknown` if the exact type is not known. This will improve type safety by
avoiding the overly permissive `any` type.

Comment on lines +41 to +44
// Skip if no filter value
if (!filter.values) return null;

return (
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Skip filters with empty values as well, not only undefined.

(!filter.values) prevents rendering filters whose values field is undefined, but still renders when it is an empty array ([]).
Down-stream components assume at least one value exists and may mis-render or throw.

-// Skip if no filter value
-if (!filter.values) return null;
+// Skip if no filter value(s)
+if (!filter.values || filter.values.length === 0) return null;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Skip if no filter value
if (!filter.values) return null;
return (
// Skip if no filter value(s)
if (!filter.values || filter.values.length === 0) return null;
return (
🤖 Prompt for AI Agents (early access)
In packages/components/src/ui/data-table-filter/components/active-filters.tsx
around lines 41 to 44, the current check only skips filters with undefined
`values` but does not skip those with empty arrays. Update the condition to also
check if `filter.values` is an empty array and skip rendering in that case to
prevent downstream components from mis-rendering or throwing errors.

Comment on lines +71 to +78
if (!filterValue || filterValue.values.length === 0) return true

if (
dateFilterOperators[filterValue.operator].target === 'single' &&
filterValue.values.length > 1
)
throw new Error('Singular operators require at most one filter value')

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Runtime error guard uses wrong operator grouping

if (filterValue.operator in ['is between', 'is not between'] && ...) – same issue as above.
Apply Array.includes for correct validation or remove the guard and rely on TypeScript to
prevent invalid combinations.

🤖 Prompt for AI Agents (early access)
In packages/components/src/ui/data-table-filter/lib/filter-fns.ts around lines
71 to 78, the runtime error guard incorrectly uses the 'in' operator to check if
filterValue.operator is in an array, which is invalid. Replace this with
Array.includes to correctly check membership, or alternatively remove this guard
and rely on TypeScript's type checking to prevent invalid operator and value
combinations.

Comment on lines +80 to +83
filterValue.operator in ['is between', 'is not between'] &&
filterValue.values.length !== 2
)
throw new Error('Plural operators require two filter values')
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Incorrect operator check – in checks keys, not array inclusion

filterValue.operator in ['is between', 'is not between'] always returns false because it
compares against array indices.

- filterValue.operator in ['is between', 'is not between'] &&
+ ['is between', 'is not between'].includes(filterValue.operator) &&

This allows invalid value counts to slip through undetected.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
filterValue.operator in ['is between', 'is not between'] &&
filterValue.values.length !== 2
)
throw new Error('Plural operators require two filter values')
// … earlier in this function …
if (
['is between', 'is not between'].includes(filterValue.operator) &&
filterValue.values.length !== 2
) {
throw new Error('Plural operators require two filter values')
}
// … later in this function …
🤖 Prompt for AI Agents (early access)
In packages/components/src/ui/data-table-filter/lib/filter-fns.ts around lines
80 to 83, the code incorrectly uses the 'in' operator to check if
filterValue.operator is in the array ['is between', 'is not between'], which
actually checks for keys and always returns false. Replace this with a proper
array inclusion check using Array.prototype.includes to correctly verify if
filterValue.operator matches either 'is between' or 'is not between' before
validating the length of filterValue.values.

Comment on lines +370 to +372
// --- Bazza UI Filter Setup ---
const bazzaProcessedColumns = useMemo<DataTableColumnConfig<MockIssue>>(() => columnConfigs, []);

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Fix generic – useMemo should return an array, not a single config

columnConfigs is an array, so the generic argument needs [].
Without this, TypeScript infers DataTableColumnConfig<MockIssue> & never[], causing downstream type-errors.

-const bazzaProcessedColumns = useMemo<DataTableColumnConfig<MockIssue>>(() => columnConfigs, []);
+const bazzaProcessedColumns = useMemo<DataTableColumnConfig<MockIssue>[]>(() => columnConfigs, []);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// --- Bazza UI Filter Setup ---
const bazzaProcessedColumns = useMemo<DataTableColumnConfig<MockIssue>>(() => columnConfigs, []);
// --- Bazza UI Filter Setup ---
const bazzaProcessedColumns = useMemo<DataTableColumnConfig<MockIssue>[]>(() => columnConfigs, []);
🤖 Prompt for AI Agents (early access)
In apps/docs/src/remix-hook-form/data-table-bazza-filters.stories.tsx around
lines 370 to 372, the useMemo hook is typed to return a single
DataTableColumnConfig<MockIssue> instead of an array. Update the generic type
argument to DataTableColumnConfig<MockIssue>[] to correctly reflect that
columnConfigs is an array. This will fix the TypeScript type errors caused by
the incorrect generic type.

Comment on lines +161 to +165
if (column.orderFn) {
models = models.sort((m1, m2) =>
column.orderFn!(m1 as ElementType<NonNullable<TVal>>, m2 as ElementType<NonNullable<TVal>>),
);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Replace non-null assertions with optional chaining

The ! operator suppresses safety checks; if orderFn is missing we still call it, defeating the earlier guard.

-    models = models.sort((m1, m2) =>
-      column.orderFn!(m1 as ElementType<NonNullable<TVal>>, m2 as ElementType<NonNullable<TVal>>),
-    );
+    models = models.sort((m1, m2) =>
+      column.orderFn?.(m1 as ElementType<NonNullable<TVal>>, m2 as ElementType<NonNullable<TVal>>) ?? 0,
+    );

Apply the same pattern to transformOptionFn below (lines 167-173).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (column.orderFn) {
models = models.sort((m1, m2) =>
column.orderFn!(m1 as ElementType<NonNullable<TVal>>, m2 as ElementType<NonNullable<TVal>>),
);
}
if (column.orderFn) {
models = models.sort((m1, m2) =>
column.orderFn?.(m1 as ElementType<NonNullable<TVal>>, m2 as ElementType<NonNullable<TVal>>) ?? 0,
);
}
🧰 Tools
🪛 Biome (1.9.4)

[error] 163-163: Forbidden non-null assertion.

Unsafe fix: Replace with optional chain operator ?. This operator includes runtime checks, so it is safer than the compile-only non-null assertion operator

(lint/style/noNonNullAssertion)

🤖 Prompt for AI Agents (early access)
In packages/components/src/ui/data-table-filter/core/filters.ts around lines 161
to 165, replace the non-null assertion operator (!) used on column.orderFn with
optional chaining to safely call the function only if it exists, preventing
runtime errors. Similarly, update the usage of transformOptionFn in lines 167 to
173 to use optional chaining instead of non-null assertions for safer function
calls.

Comment on lines +94 to +106
export type ColumnConfig<TData, TType extends ColumnDataType = any, TVal = unknown, TId extends string = string> = {
id: TId;
accessor: TAccessorFn<TData, TVal>;
displayName: string;
icon: LucideIcon;
type: TType;
options?: TType extends OptionBasedColumnDataType ? ColumnOption[] : never;
facetedOptions?: TType extends OptionBasedColumnDataType ? Map<string, number> : never;
min?: TType extends 'number' ? number : never;
max?: TType extends 'number' ? number : never;
transformOptionFn?: TType extends OptionBasedColumnDataType ? TTransformOptionFn<TVal> : never;
orderFn?: TType extends OptionBasedColumnDataType ? TOrderFn<TVal> : never;
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Eliminate default any on ColumnConfig generics

Defaulting to any leaks through the entire type system and defeats the Biome rule.
Consider a safer default:

-export type ColumnConfig<TData, TType extends ColumnDataType = any, TVal = unknown, TId extends string = string> = {
+export type ColumnConfig<
+  TData,
+  TType extends ColumnDataType = ColumnDataType,
+  TVal = ColumnDataNativeMap[TType],
+  TId extends string = string,
+> = {

This removes the explicit any, improves inference for TVal, and keeps backward compatibility.

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 Biome (1.9.4)

[error] 94-94: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)

🤖 Prompt for AI Agents (early access)
In packages/components/src/ui/data-table-filter/core/types.ts around lines 94 to
106, the generic parameter TType currently defaults to any, which can cause
unsafe type inference and violate the Biome rule. To fix this, remove the
default any for TType and instead provide a safer default that improves type
inference for TVal while maintaining backward compatibility. Adjust the generic
defaults accordingly to avoid leaking any through the type system.

@jaruesink jaruesink changed the title WIP: chore(dependencies): update Radix UI components and integrate Bazza UI filters WIP: chore(dependencies): update Radix UI components and integrate Bazza UI filters [LC-219] May 16, 2025
@codegen-sh
Copy link
Contributor

codegen-sh bot commented May 16, 2025

I see a check failed - I'm on it! 🫡

💻 View my work

@codegen-sh
Copy link
Contributor

codegen-sh bot commented May 16, 2025

✅ Fixed failing check in this commit.

The issue was that the story was importing useDataTableFilters from @lambdacurry/forms/ui/utils/use-data-table-filters, but the file was actually located at ./packages/components/src/ui/data-table-filter/hooks/use-data-table-filters.tsx. I created a barrel file to re-export the hook from the expected location.

@github-actions
Copy link
Contributor

github-actions bot commented May 16, 2025

📝 Storybook Preview: View Storybook

This preview will be updated automatically when you push new changes to this PR.

Note: The preview will be available after the workflow completes and the PR is approved for deployment.

@codegen-sh
Copy link
Contributor

codegen-sh bot commented May 16, 2025

I see a check failed - I'm on it! 🫡

💻 View my work

@codegen-sh
Copy link
Contributor

codegen-sh bot commented May 16, 2025

✅ Fixed failing check in this commit.

The issue was TypeScript errors in the debounce.ts file where it was using NodeJS.Timeout which wasn't available in the build environment. I replaced it with ReturnType<typeof setTimeout> which is more compatible and doesn't require the Node.js types.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (4)
packages/components/src/remix-hook-form/data-table-router-form.tsx (2)

23-29: 🛠️ Refactor suggestion

Replace any types with proper type definitions

The use of any type for Bazza UI components disables type checking and reduces code quality.

-  filterColumnConfigs: any[]; // Placeholder type for Bazza UI ColumnConfig[]
-  dtfOptions?: Record<string, any[]>;
-  dtfFacetedData?: Record<string, any>;
+  filterColumnConfigs: ColumnConfig[]; // Import the type from your UI lib
+  dtfOptions?: Record<string, readonly OptionItem[]>;
+  dtfFacetedData?: Record<string, FacetedMeta>;

Make sure to import these types from your UI library. This will improve type safety, enable auto-completion, and resolve the Biome lint errors.


135-138: ⚠️ Potential issue

window.crypto.randomUUID() will break during SSR

Using window.crypto.randomUUID() will cause errors during server-side rendering as window is undefined in Node environments.

-    return Array.from({ length: count }, () => window.crypto.randomUUID());
+    return Array.from({ length: count }, (_, i) => `skeleton-${i}`);

This change generates deterministic IDs that work in both browser and server environments while maintaining the same visual result.

packages/components/src/ui/data-table-filter/lib/debounce.ts (2)

7-10: Replace any with more specific types

The use of any in the function signature reduces type safety. Consider using unknown or more specific generic types.

-export function debounce<T extends (...args: any[]) => any>(
+export function debounce<T extends (...args: unknown[]) => unknown>(
  fn: T,
  delay: number
): (...args: Parameters<T>) => void {
🧰 Tools
🪛 Biome (1.9.4)

[error] 7-7: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 7-7: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


21-32: Improve type safety and remove unnecessary this aliasing

This implementation has two issues: using any for the this parameter type and creating an unnecessary alias for this.

-  return function (this: any, ...args: Parameters<T>): void {
-    const context = this
+  return function (this: unknown, ...args: Parameters<T>): void {
 
     if (timeout) {
       clearTimeout(timeout)
     }
 
     timeout = setTimeout(() => {
-      fn.apply(context, args)
+      fn.apply(this, args)
       timeout = null
     }, delay)
   }
🧰 Tools
🪛 Biome (1.9.4)

[error] 21-21: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 22-22: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 20b0070 and 8a9619c.

📒 Files selected for processing (6)
  • packages/components/src/remix-hook-form/data-table-router-form.tsx (3 hunks)
  • packages/components/src/ui/data-table-filter/lib/debounce.ts (1 hunks)
  • packages/components/src/ui/utils/filters.ts (1 hunks)
  • packages/components/src/ui/utils/index.ts (1 hunks)
  • packages/components/src/ui/utils/use-data-table-filters.ts (1 hunks)
  • packages/components/src/ui/utils/use-filter-sync.ts (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • packages/components/src/ui/utils/use-data-table-filters.ts
  • packages/components/src/ui/utils/index.ts
  • packages/components/src/ui/utils/filters.ts
🧰 Additional context used
🧬 Code Graph Analysis (2)
packages/components/src/ui/utils/use-filter-sync.ts (1)
packages/components/src/remix-hook-form/data-table-router-parsers.ts (2)
  • BazzaFiltersState (9-9)
  • dataTableRouterParsers (82-115)
packages/components/src/ui/data-table-filter/lib/debounce.ts (1)
packages/components/src/ui/utils/debounce.ts (1)
  • debounce (10-25)
🪛 Biome (1.9.4)
packages/components/src/remix-hook-form/data-table-router-form.tsx

[error] 42-42: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 44-44: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 45-45: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)

packages/components/src/ui/data-table-filter/lib/debounce.ts

[error] 7-7: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 7-7: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 21-21: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 41-41: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 41-41: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 57-57: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 22-22: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)


[error] 60-60: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)

🔇 Additional comments (7)
packages/components/src/ui/utils/use-filter-sync.ts (2)

1-13: Well-structured imports and clear documentation

The hook is properly documented with clear JSDoc comments that explain its purpose and return values. The imports are organized logically, grouping React hooks together and importing the necessary types and utilities from related modules.


14-39: LGTM! Clean implementation of URL synchronization

The hook implementation is well-organized and follows best practices:

  1. It uses useSearchParams to read and update URL parameters
  2. It properly serializes/deserializes filters using the parsers
  3. It handles empty filter state by removing the parameter
  4. It uses the replace option with setSearchParams to avoid polluting browser history
  5. The function is properly memoized with useCallback

This pattern will enable consistent filter state across page reloads and browser navigation.

packages/components/src/remix-hook-form/data-table-router-form.tsx (5)

1-17: Clean up of imports reflects the architecture shift

Good job updating the imports to remove unused components and add comments explaining the changes. Removing the direct use of ColumnFilter and commenting out the z import shows the transition from direct TanStack Table filtering to server-side filtering with Bazza UI.


66-82: Good implementation of the Bazza UI filter integration

The integration with useDataTableFilters is well-structured:

  1. Destructuring the returned values for clarity
  2. Setting the strategy to 'server'
  3. Properly passing data, configurations, and options
  4. Using URL filters as the source of truth
  5. Updating URL state when filters change

This maintains a clear data flow and responsibility separation.


97-131: Table configuration updated for server-side filtering

The table configuration has been properly updated to work with server-side filtering:

  1. Removed columnFilters from state
  2. Set manualFiltering to true
  3. Kept getFilteredRowModel for table structure
  4. Removed onColumnFiltersChange handler

This ensures the table correctly relies on server-filtered data while maintaining UI functionality.


154-173: Well-implemented handlers for search and filter reset

The new handlers for search changes and filter/search reset are well-implemented:

  1. handleSearchChange updates URL state and resets pagination
  2. handleResetFiltersAndSearch properly uses Bazza UI's removeAllFilters action
  3. Helper variables are created to track filter/search state

This maintains a clean separation between UI actions and state updates.


177-188: Proper integration with the DataTableRouterToolbar

The toolbar integration is complete with all necessary props:

  1. Search state and handlers
  2. Reset functionality
  3. Bazza UI filter components, state, and actions

This ensures the toolbar can fully utilize the new filtering capabilities.

Comment on lines 35 to 46
export interface DataTableRouterFormProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[];
data: TData[];
filterableColumns?: DataTableRouterToolbarProps<TData>['filterableColumns'];
searchableColumns?: DataTableRouterToolbarProps<TData>['searchableColumns'];
columns: ColumnDef<TData, TValue>[]; // For TanStack Table display
data: TData[]; // Data from server (already filtered/sorted/paginated)
pageCount?: number;
defaultStateValues?: Partial<DataTableRouterState>;
// New prop for Bazza UI filter configurations
// This should be typed according to bazza/ui's ColumnConfig type (e.g., from createColumnConfigHelper(...).build())
filterColumnConfigs: any[]; // Placeholder type for Bazza UI ColumnConfig[]
// Props for server-fetched options/faceted data for bazza/ui, if needed for server strategy
dtfOptions?: Record<string, any[]>;
dtfFacetedData?: Record<string, any>;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Interface updated with new props but needs proper typing

The interface correctly reflects the new functionality with added props for Bazza UI integration. However, using any types loses type safety benefits.

Import and use the proper types from your UI library for these props to ensure type safety and better developer experience.

🧰 Tools
🪛 Biome (1.9.4)

[error] 42-42: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 44-44: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 45-45: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)

🤖 Prompt for AI Agents
In packages/components/src/remix-hook-form/data-table-router-form.tsx around
lines 35 to 46, the DataTableRouterFormProps interface uses 'any' for the
filterColumnConfigs and related props, losing type safety. To fix this, import
the appropriate ColumnConfig type from the bazza/ui library and replace the
'any[]' types with these specific types. This will enforce type safety and
improve developer experience by providing accurate typings for these props.

Comment on lines +1 to +74
/**
* Debounce function for handling user input
* @param fn Function to debounce
* @param delay Delay in milliseconds
* @returns Debounced function
*/
export function debounce<T extends (...args: any[]) => any>(
fn: T,
delay: number
): (...args: Parameters<T>) => void {
/**
* Timeout ID for the debounced function
* Using ReturnType<typeof setTimeout> instead of NodeJS.Timeout for better compatibility
*/
let timeout: ReturnType<typeof setTimeout> | null = null

/**
* Debounced function
* @param args Arguments to pass to the original function
*/
return function (this: any, ...args: Parameters<T>): void {
const context = this

if (timeout) {
clearTimeout(timeout)
}

timeout = setTimeout(() => {
fn.apply(context, args)
timeout = null
}, delay)
}
}

/**
* Debounce function that returns a promise
* @param fn Function to debounce
* @param delay Delay in milliseconds
* @returns Debounced function that returns a promise
*/
export function debouncePromise<T extends (...args: any[]) => Promise<any>>(
fn: T,
delay: number
): (...args: Parameters<T>) => Promise<ReturnType<T>> {
/**
* Timeout ID for the debounced function
* Using ReturnType<typeof setTimeout> instead of NodeJS.Timeout for better compatibility
*/
let timeout: ReturnType<typeof setTimeout> | null = null

/**
* Debounced function that returns a promise
* @param args Arguments to pass to the original function
* @returns Promise that resolves with the result of the original function
*/
return function (
this: any,
...args: Parameters<T>
): ReturnType<typeof setTimeout> {
const context = this

return new Promise((resolve) => {
if (timeout) {
clearTimeout(timeout)
}

timeout = setTimeout(() => {
resolve(fn.apply(context, args))
timeout = null
}, delay)
}) as unknown as ReturnType<typeof setTimeout>
}
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider consolidating with existing debounce utility

This file introduces new debounce utilities while there's already a similar implementation in packages/components/src/ui/utils/debounce.ts. Consider either:

  1. Extending the existing utility to support promises
  2. Replacing the existing implementation with this more comprehensive one
  3. Consolidating both implementations to avoid duplication
🧰 Tools
🪛 Biome (1.9.4)

[error] 7-7: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 7-7: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 21-21: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 41-41: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 41-41: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 57-57: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 22-22: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)


[error] 60-60: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)

🤖 Prompt for AI Agents
In packages/components/src/ui/data-table-filter/lib/debounce.ts lines 1 to 74,
the debounce utilities duplicate functionality already present in
packages/components/src/ui/utils/debounce.ts. To fix this, review the existing
debounce utility and either extend it to support promise-based functions or
replace it with this more comprehensive implementation. Consolidate the code to
avoid duplication by merging the two implementations, ensuring all required
features are covered in a single utility module.

Comment on lines +41 to +44
export function debouncePromise<T extends (...args: any[]) => Promise<any>>(
fn: T,
delay: number
): (...args: Parameters<T>) => Promise<ReturnType<T>> {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Replace any with more specific types in debouncePromise

Similar to the first function, using any reduces type safety.

-export function debouncePromise<T extends (...args: any[]) => Promise<any>>(
+export function debouncePromise<T extends (...args: unknown[]) => Promise<unknown>>(
  fn: T,
  delay: number
): (...args: Parameters<T>) => Promise<ReturnType<T>> {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function debouncePromise<T extends (...args: any[]) => Promise<any>>(
fn: T,
delay: number
): (...args: Parameters<T>) => Promise<ReturnType<T>> {
export function debouncePromise<T extends (...args: unknown[]) => Promise<unknown>>(
fn: T,
delay: number
): (...args: Parameters<T>) => Promise<ReturnType<T>> {
🧰 Tools
🪛 Biome (1.9.4)

[error] 41-41: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 41-41: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)

🤖 Prompt for AI Agents
In packages/components/src/ui/data-table-filter/lib/debounce.ts around lines 41
to 44, the debouncePromise function uses 'any' in the type definition for the
function parameters, which reduces type safety. Replace 'any' with a more
specific generic type or constraint that accurately reflects the expected
argument types of the function 'fn' to improve type safety and maintain proper
typings throughout the debouncePromise function.

Comment on lines +56 to +72
return function (
this: any,
...args: Parameters<T>
): ReturnType<typeof setTimeout> {
const context = this

return new Promise((resolve) => {
if (timeout) {
clearTimeout(timeout)
}

timeout = setTimeout(() => {
resolve(fn.apply(context, args))
timeout = null
}, delay)
}) as unknown as ReturnType<typeof setTimeout>
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix return type and improve implementation of debouncePromise

There are several issues with this implementation:

  1. Using any for the this parameter type
  2. Unnecessary this aliasing
  3. Incorrect return type - it's returning a Promise cast to ReturnType<typeof setTimeout>
-  return function (
-    this: any,
+  return function (
+    this: unknown,
     ...args: Parameters<T>
-  ): ReturnType<typeof setTimeout> {
-    const context = this
+  ): Promise<ReturnType<T>> {
 
-    return new Promise((resolve) => {
+    return new Promise<ReturnType<T>>((resolve) => {
       if (timeout) {
         clearTimeout(timeout)
       }
 
       timeout = setTimeout(() => {
-        resolve(fn.apply(context, args))
+        resolve(fn.apply(this, args) as ReturnType<T>)
         timeout = null
       }, delay)
-    }) as unknown as ReturnType<typeof setTimeout>
+    })
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return function (
this: any,
...args: Parameters<T>
): ReturnType<typeof setTimeout> {
const context = this
return new Promise((resolve) => {
if (timeout) {
clearTimeout(timeout)
}
timeout = setTimeout(() => {
resolve(fn.apply(context, args))
timeout = null
}, delay)
}) as unknown as ReturnType<typeof setTimeout>
}
return function (
this: unknown,
...args: Parameters<T>
): Promise<ReturnType<T>> {
return new Promise<ReturnType<T>>((resolve) => {
if (timeout) {
clearTimeout(timeout)
}
timeout = setTimeout(() => {
resolve(fn.apply(this, args) as ReturnType<T>)
timeout = null
}, delay)
})
}
🧰 Tools
🪛 Biome (1.9.4)

[error] 57-57: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 60-60: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)

🤖 Prompt for AI Agents
In packages/components/src/ui/data-table-filter/lib/debounce.ts around lines 56
to 72, fix the debouncePromise function by removing the use of 'any' for the
'this' parameter and avoid aliasing 'this' to a separate variable. Correct the
return type to properly reflect that the function returns a Promise of the
original function's return type, not a ReturnType of setTimeout. Adjust the
implementation so the returned function returns a Promise that resolves with the
result of the debounced function without incorrect type casting.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
apps/docs/src/remix-hook-form/data-table-bazza-filters.stories.tsx (1)

370-372: Fix generic – useMemo should return an array, not a single config

The returned value is an array (columnConfigs), so the generic needs []:

-const bazzaProcessedColumns = useMemo<DataTableColumnConfig<MockIssue>>(() => columnConfigs, []);
+const bazzaProcessedColumns = useMemo<DataTableColumnConfig<MockIssue>[]>(() => columnConfigs, []);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8a9619c and 3c234af.

📒 Files selected for processing (3)
  • apps/docs/src/remix-hook-form/data-table-bazza-filters.stories.tsx (1 hunks)
  • packages/components/src/remix-hook-form/data-table-router-parsers.ts (4 hunks)
  • packages/components/src/remix-hook-form/use-data-table-url-state.ts (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/components/src/remix-hook-form/use-data-table-url-state.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/components/src/remix-hook-form/data-table-router-parsers.ts
🔇 Additional comments (2)
apps/docs/src/remix-hook-form/data-table-bazza-filters.stories.tsx (2)

351-368: Potential state desync by mutating a stale URLSearchParams instance

searchParams is instantiated once from the initial location.search and then mutated inside the pagination/sorting handlers. If the location changes elsewhere (e.g. back/forward navigation) the cached instance no longer reflects the URL, causing incorrect updates or lost parameters.

Safer pattern:

-const handlePaginationChange: OnChangeFn<PaginationState> = (updaterOrValue) => {
-  const next = typeof updaterOrValue === 'function' ? updaterOrValue(pagination) : updaterOrValue;
-  searchParams.set('page', next.pageIndex.toString());
-  searchParams.set('pageSize', next.pageSize.toString());
-  navigate(`${location.pathname}?${searchParams.toString()}`, { replace: true });
-};
+const handlePaginationChange: OnChangeFn<PaginationState> = (updaterOrValue) => {
+  const next = typeof updaterOrValue === 'function' ? updaterOrValue(pagination) : updaterOrValue;
+  const params = new URLSearchParams(location.search);
+  params.set('page', next.pageIndex.toString());
+  params.set('pageSize', next.pageSize.toString());
+  navigate({ pathname: location.pathname, search: params.toString() }, { replace: true });
+};

Same applies to handleSortingChange.
[ suggest_essential_refactor ]


424-425: Verify DataTable API – passing columns={columns.length} looks off

Most table components expect either the column definitions or nothing at all; supplying the count may break sizing or otherwise mis-configure the component. If DataTable really needs the number of columns for grid measurement, rename the prop (columnCount?) to avoid confusion.

Please double-check the component contract and update accordingly.

Comment on lines +24 to +25
import { type LoaderFunctionArgs, useLoaderData, useLocation, useNavigate } from 'react-router'; // Added LoaderFunctionArgs, useLoaderData, useNavigate, useLocation
import { withReactRouterStubDecorator } from '../lib/storybook/react-router-stub'; // FIX: Add withReactRouterStubDecorator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Incorrect router import will break at runtime/build

useLoaderData, useNavigate, and useLocation are exported from react-router-dom (or @remix-run/react when using Remix), not from react-router. Importing from the wrong package will cause TypeScript errors and, at runtime, the hooks will be undefined, crashing Storybook.

-import { type LoaderFunctionArgs, useLoaderData, useLocation, useNavigate } from 'react-router';
+import { type LoaderFunctionArgs } from '@remix-run/router';          // <-- data APIs
+import { useLoaderData, useLocation, useNavigate } from 'react-router-dom'; // <-- hooks

Please adjust the paths (and any tsconfig alias) accordingly.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { type LoaderFunctionArgs, useLoaderData, useLocation, useNavigate } from 'react-router'; // Added LoaderFunctionArgs, useLoaderData, useNavigate, useLocation
import { withReactRouterStubDecorator } from '../lib/storybook/react-router-stub'; // FIX: Add withReactRouterStubDecorator
import { type LoaderFunctionArgs } from '@remix-run/router'; // <-- data APIs
import { useLoaderData, useLocation, useNavigate } from 'react-router-dom'; // <-- hooks
import { withReactRouterStubDecorator } from '../lib/storybook/react-router-stub'; // FIX: Add withReactRouterStubDecorator
🤖 Prompt for AI Agents
In apps/docs/src/remix-hook-form/data-table-bazza-filters.stories.tsx at lines
24-25, the hooks useLoaderData, useNavigate, and useLocation are incorrectly
imported from 'react-router' instead of 'react-router-dom' or
'@remix-run/react'. To fix this, change the import source for these hooks to the
correct package, ensuring the imports come from 'react-router-dom' or
'@remix-run/react' as appropriate for the project setup, so the hooks are
properly defined and avoid runtime errors.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants