sprintify-ui 0.10.61 → 0.10.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/sprintify-ui.es.js +617 -577
- package/dist/types/components/BaseDataTable.vue.d.ts +30 -0
- package/dist/types/utils/deepIncludes.d.ts +14 -0
- package/package.json +1 -1
- package/src/components/BaseDataIterator.vue +2 -10
- package/src/components/BaseDataTable.vue +9 -0
- package/src/utils/deepIncludes.ts +77 -0
|
@@ -1778,6 +1778,13 @@ declare const __VLS_self: import("vue").DefineComponent<import("vue").ExtractPro
|
|
|
1778
1778
|
type: StringConstructor;
|
|
1779
1779
|
default(): string;
|
|
1780
1780
|
};
|
|
1781
|
+
/**
|
|
1782
|
+
* Function to search local data
|
|
1783
|
+
*/
|
|
1784
|
+
search: {
|
|
1785
|
+
default: undefined;
|
|
1786
|
+
type: PropType<(items: Collection, search: string | null) => Collection>;
|
|
1787
|
+
};
|
|
1781
1788
|
}>, {
|
|
1782
1789
|
t: typeof t;
|
|
1783
1790
|
BaseDataIterator: typeof BaseDataIterator;
|
|
@@ -2066,11 +2073,19 @@ declare const __VLS_self: import("vue").DefineComponent<import("vue").ExtractPro
|
|
|
2066
2073
|
type: StringConstructor;
|
|
2067
2074
|
default(): string;
|
|
2068
2075
|
};
|
|
2076
|
+
/**
|
|
2077
|
+
* Function to search local data
|
|
2078
|
+
*/
|
|
2079
|
+
search: {
|
|
2080
|
+
default: undefined;
|
|
2081
|
+
type: PropType<(items: Collection, search: string | null) => Collection>;
|
|
2082
|
+
};
|
|
2069
2083
|
}>> & Readonly<{
|
|
2070
2084
|
onDelete?: ((...args: any[]) => any) | undefined;
|
|
2071
2085
|
"onUpdate:checked-rows"?: ((...args: any[]) => any) | undefined;
|
|
2072
2086
|
onFetch?: ((...args: any[]) => any) | undefined;
|
|
2073
2087
|
}>, {
|
|
2088
|
+
search: (items: Collection, search: string | null) => Collection;
|
|
2074
2089
|
size: "xs" | "sm" | "md" | "lg" | "xl";
|
|
2075
2090
|
items: CollectionItem[] | undefined;
|
|
2076
2091
|
actions: ActionItem[];
|
|
@@ -2360,6 +2375,13 @@ declare const __VLS_component: import("vue").DefineComponent<import("vue").Extra
|
|
|
2360
2375
|
type: StringConstructor;
|
|
2361
2376
|
default(): string;
|
|
2362
2377
|
};
|
|
2378
|
+
/**
|
|
2379
|
+
* Function to search local data
|
|
2380
|
+
*/
|
|
2381
|
+
search: {
|
|
2382
|
+
default: undefined;
|
|
2383
|
+
type: PropType<(items: Collection, search: string | null) => Collection>;
|
|
2384
|
+
};
|
|
2363
2385
|
}>, {
|
|
2364
2386
|
fetch: typeof fetch;
|
|
2365
2387
|
fetchWithoutLoading: typeof fetchWithoutLoading;
|
|
@@ -2620,11 +2642,19 @@ declare const __VLS_component: import("vue").DefineComponent<import("vue").Extra
|
|
|
2620
2642
|
type: StringConstructor;
|
|
2621
2643
|
default(): string;
|
|
2622
2644
|
};
|
|
2645
|
+
/**
|
|
2646
|
+
* Function to search local data
|
|
2647
|
+
*/
|
|
2648
|
+
search: {
|
|
2649
|
+
default: undefined;
|
|
2650
|
+
type: PropType<(items: Collection, search: string | null) => Collection>;
|
|
2651
|
+
};
|
|
2623
2652
|
}>> & Readonly<{
|
|
2624
2653
|
onDelete?: ((...args: any[]) => any) | undefined;
|
|
2625
2654
|
"onUpdate:checked-rows"?: ((...args: any[]) => any) | undefined;
|
|
2626
2655
|
onFetch?: ((...args: any[]) => any) | undefined;
|
|
2627
2656
|
}>, {
|
|
2657
|
+
search: (items: Collection, search: string | null) => Collection;
|
|
2628
2658
|
size: "xs" | "sm" | "md" | "lg" | "xl";
|
|
2629
2659
|
items: CollectionItem[] | undefined;
|
|
2630
2660
|
actions: ActionItem[];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface SearchOpts {
|
|
2
|
+
maxDepth?: number;
|
|
3
|
+
maxCharsPerItem?: number;
|
|
4
|
+
maxArray?: number;
|
|
5
|
+
cache?: WeakMap<object, string>;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Recursively searches an item (object, array, primitive) for a case-insensitive match of the query string.
|
|
9
|
+
* Limits can be set to avoid excessive CPU usage on large/deep items.
|
|
10
|
+
* @param item The item to search within.
|
|
11
|
+
* @param queryRaw The query string to search for.
|
|
12
|
+
* @param opts Optional search options.
|
|
13
|
+
*/
|
|
14
|
+
export declare function deepIncludes(item: any, queryRaw: string, opts?: SearchOpts): boolean;
|
package/package.json
CHANGED
|
@@ -188,6 +188,7 @@ type Direction = 'asc' | 'desc';
|
|
|
188
188
|
import { Size } from '@/utils/sizes';
|
|
189
189
|
import BaseInput from './BaseInput.vue';
|
|
190
190
|
import { useInputSize } from '@/composables/inputSize';
|
|
191
|
+
import { deepIncludes } from '@/utils/deepIncludes';
|
|
191
192
|
|
|
192
193
|
const DEFAULT_QUERY = {
|
|
193
194
|
page: 1,
|
|
@@ -785,20 +786,11 @@ function searchItems(items: Collection | undefined) {
|
|
|
785
786
|
return [];
|
|
786
787
|
}
|
|
787
788
|
|
|
788
|
-
const searchWords = searchKeywords.value.toLowerCase();
|
|
789
|
-
|
|
790
789
|
if (props.search) {
|
|
791
790
|
return props.search(items, searchKeywords.value);
|
|
792
791
|
}
|
|
793
792
|
|
|
794
|
-
return items
|
|
795
|
-
return Object.values(item).some((value) => {
|
|
796
|
-
if (typeof value === 'string') {
|
|
797
|
-
return value.toLowerCase().includes(searchWords);
|
|
798
|
-
}
|
|
799
|
-
return false;
|
|
800
|
-
});
|
|
801
|
-
});
|
|
793
|
+
return items.filter((it) => deepIncludes(it, searchKeywords.value));
|
|
802
794
|
}
|
|
803
795
|
|
|
804
796
|
function sortItems(items: Collection | undefined) {
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
:sections="sectionsInternal"
|
|
15
15
|
:scroll-top-on-fetch="maxHeight ? false : scrollTopOnFetch"
|
|
16
16
|
:filters-position="filtersPosition"
|
|
17
|
+
:search="search"
|
|
17
18
|
@fetch="onFetch"
|
|
18
19
|
@will-scroll-top="onWillScrollTop"
|
|
19
20
|
>
|
|
@@ -562,6 +563,14 @@ const props = defineProps({
|
|
|
562
563
|
return window.location.pathname;
|
|
563
564
|
},
|
|
564
565
|
},
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Function to search local data
|
|
569
|
+
*/
|
|
570
|
+
search: {
|
|
571
|
+
default: undefined,
|
|
572
|
+
type: Function as PropType<(items: Collection, search: string | null) => Collection>,
|
|
573
|
+
}
|
|
565
574
|
});
|
|
566
575
|
|
|
567
576
|
const sizeInternal = useInputSize(props.size);
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export interface SearchOpts {
|
|
2
|
+
maxDepth?: number; // stop descending after this depth
|
|
3
|
+
maxCharsPerItem?: number; // stop scanning item after reading this many chars
|
|
4
|
+
maxArray?: number; // cap how many array items to inspect per array
|
|
5
|
+
cache?: WeakMap<object, string>; // optional: lazy per-item cache of a “search blob”
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Recursively searches an item (object, array, primitive) for a case-insensitive match of the query string.
|
|
10
|
+
* Limits can be set to avoid excessive CPU usage on large/deep items.
|
|
11
|
+
* @param item The item to search within.
|
|
12
|
+
* @param queryRaw The query string to search for.
|
|
13
|
+
* @param opts Optional search options.
|
|
14
|
+
*/
|
|
15
|
+
export function deepIncludes(item: any, queryRaw: string, opts: SearchOpts = {}): boolean {
|
|
16
|
+
const q = queryRaw.toLowerCase();
|
|
17
|
+
const {
|
|
18
|
+
maxDepth = 3,
|
|
19
|
+
maxCharsPerItem = 3000,
|
|
20
|
+
maxArray = 64,
|
|
21
|
+
cache,
|
|
22
|
+
} = opts;
|
|
23
|
+
|
|
24
|
+
let consumed = 0;
|
|
25
|
+
const seen = new WeakSet<object>();
|
|
26
|
+
|
|
27
|
+
const feed = (s: string): boolean => {
|
|
28
|
+
// consume without allocating new strings repeatedly
|
|
29
|
+
consumed += s.length;
|
|
30
|
+
return s.toLowerCase().includes(q) || consumed >= maxCharsPerItem;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const visit = (val: any, depth: number): boolean => {
|
|
34
|
+
if (val == null) return false;
|
|
35
|
+
if (consumed >= maxCharsPerItem) return false;
|
|
36
|
+
|
|
37
|
+
const t = typeof val;
|
|
38
|
+
|
|
39
|
+
if (t === 'string') return feed(val);
|
|
40
|
+
if (t === 'number' || t === 'boolean') return feed(String(val));
|
|
41
|
+
if (t === 'bigint') return feed(val.toString());
|
|
42
|
+
if (t === 'symbol' || t === 'function') return false;
|
|
43
|
+
|
|
44
|
+
// objects & arrays
|
|
45
|
+
if (t === 'object') {
|
|
46
|
+
if (seen.has(val)) return false;
|
|
47
|
+
seen.add(val);
|
|
48
|
+
|
|
49
|
+
// Optional lazy cache: build once per object identity
|
|
50
|
+
if (cache && cache.has(val)) {
|
|
51
|
+
return feed(cache.get(val)!); // already lowercased when stored? not necessary since feed lowercases
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (depth >= maxDepth) return false;
|
|
55
|
+
|
|
56
|
+
if (Array.isArray(val)) {
|
|
57
|
+
const len = Math.min(val.length, maxArray);
|
|
58
|
+
for (let i = 0; i < len; i++) {
|
|
59
|
+
if (visit(val[i], depth + 1)) return true;
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// plain object: iterate own enumerable keys only
|
|
65
|
+
for (const k in val) {
|
|
66
|
+
// match on key names too (often helpful if values are IDs)
|
|
67
|
+
if (feed(k)) return true;
|
|
68
|
+
if (visit(val[k], depth + 1)) return true;
|
|
69
|
+
}
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return false;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
return visit(item, 0);
|
|
77
|
+
}
|