From b4949eab0f10006f97e457257659d2fc45e59630 Mon Sep 17 00:00:00 2001 From: JSap0914 Date: Wed, 17 Jun 2026 21:01:04 +0900 Subject: [PATCH] fix(table-core): fix filterFn_between/betweenInclusive autoRemove never removing array filter values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit filterFn_between and filterFn_betweenInclusive had `autoRemove: (val: any) => !val`. Since any array is truthy in JavaScript, `!val` is always `false` for the `[min, max]` tuple these filters receive, meaning the filter is NEVER auto-removed — even when both endpoints are empty strings, null, or undefined. A user who clears both range inputs ends up with an active filter that passes all rows but can never be auto-removed from column filter state. Fix: align with the same pattern used by filterFn_inNumberRange: autoRemove: (val) => testFalsy(val) || (testFalsy(val[0]) && testFalsy(val[1])) This correctly removes the filter when both endpoints are falsy (undefined, null, or empty string) while preserving 0 as a valid endpoint value. Fixes: filterFns.between and filterFns.betweenInclusive auto-remove logic --- packages/table-core/src/fns/filterFns.ts | 10 +++- .../tests/unit/fns/filterFns.test.ts | 51 +++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/packages/table-core/src/fns/filterFns.ts b/packages/table-core/src/fns/filterFns.ts index 44c4fb02d2..7e85698890 100644 --- a/packages/table-core/src/fns/filterFns.ts +++ b/packages/table-core/src/fns/filterFns.ts @@ -217,7 +217,10 @@ const filterFn_between = Object.assign( Number(filterValues[0]) > Number(filterValues[1])) || (['', undefined] as Array).includes(filterValues[1]) || filterFn_lessThan(row, columnId, filterValues[1])), - { autoRemove: (val: any) => !val }, + { + autoRemove: (val: any) => + testFalsy(val) || (testFalsy(val[0]) && testFalsy(val[1])), + }, ) /** @@ -238,7 +241,10 @@ const filterFn_betweenInclusive = Object.assign( Number(filterValues[0]) > Number(filterValues[1])) || (['', undefined] as Array).includes(filterValues[1]) || filterFn_lessThanOrEqualTo(row, columnId, filterValues[1])), - { autoRemove: (val: any) => !val }, + { + autoRemove: (val: any) => + testFalsy(val) || (testFalsy(val[0]) && testFalsy(val[1])), + }, ) /** diff --git a/packages/table-core/tests/unit/fns/filterFns.test.ts b/packages/table-core/tests/unit/fns/filterFns.test.ts index 8b896576f7..1b6f74a092 100644 --- a/packages/table-core/tests/unit/fns/filterFns.test.ts +++ b/packages/table-core/tests/unit/fns/filterFns.test.ts @@ -12,6 +12,7 @@ import { filterFn_lessThan, filterFn_lessThanOrEqualTo, filterFn_weakEquals, + filterFns, } from '../../../src' import { getStaticTestData } from '../../fixtures/data/generateTestData' @@ -512,4 +513,54 @@ describe('Filter Functions', () => { }) }) }) + + describe('Range Filters', () => { + describe('filterFns.between.autoRemove', () => { + const autoRemove = filterFns.between.autoRemove! + + it('should auto-remove when both endpoints are undefined', () => { + expect(autoRemove([undefined, undefined])).toBe(true) + }) + it('should auto-remove when both endpoints are null', () => { + expect(autoRemove([null, null])).toBe(true) + }) + it('should auto-remove when both endpoints are empty strings', () => { + expect(autoRemove(['', ''])).toBe(true) + }) + it('should NOT auto-remove when both endpoints are valid numbers', () => { + expect(autoRemove([5, 10])).toBe(false) + }) + it('should NOT auto-remove when lower bound is 0 (falsy number)', () => { + expect(autoRemove([0, 10])).toBe(false) + }) + it('should NOT auto-remove when only one endpoint is provided', () => { + expect(autoRemove([undefined, 10])).toBe(false) + expect(autoRemove([5, undefined])).toBe(false) + }) + }) + + describe('filterFns.betweenInclusive.autoRemove', () => { + const autoRemove = filterFns.betweenInclusive.autoRemove! + + it('should auto-remove when both endpoints are undefined', () => { + expect(autoRemove([undefined, undefined])).toBe(true) + }) + it('should auto-remove when both endpoints are null', () => { + expect(autoRemove([null, null])).toBe(true) + }) + it('should auto-remove when both endpoints are empty strings', () => { + expect(autoRemove(['', ''])).toBe(true) + }) + it('should NOT auto-remove when both endpoints are valid numbers', () => { + expect(autoRemove([5, 10])).toBe(false) + }) + it('should NOT auto-remove when lower bound is 0 (falsy number)', () => { + expect(autoRemove([0, 10])).toBe(false) + }) + it('should NOT auto-remove when only one endpoint is provided', () => { + expect(autoRemove([undefined, 10])).toBe(false) + expect(autoRemove([5, undefined])).toBe(false) + }) + }) + }) })