kmod-cli 1.0.10

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.
Files changed (66) hide show
  1. package/README.md +53 -0
  2. package/bin/gen-components.js +68 -0
  3. package/bin/index.js +153 -0
  4. package/component-templates/components/access-denied.tsx +130 -0
  5. package/component-templates/components/breadcumb.tsx +42 -0
  6. package/component-templates/components/count-down.tsx +94 -0
  7. package/component-templates/components/count-input.tsx +221 -0
  8. package/component-templates/components/date-range-calendar/button.tsx +61 -0
  9. package/component-templates/components/date-range-calendar/calendar.tsx +132 -0
  10. package/component-templates/components/date-range-calendar/date-input.tsx +259 -0
  11. package/component-templates/components/date-range-calendar/date-range-picker.tsx +594 -0
  12. package/component-templates/components/date-range-calendar/label.tsx +31 -0
  13. package/component-templates/components/date-range-calendar/popover.tsx +32 -0
  14. package/component-templates/components/date-range-calendar/select.tsx +125 -0
  15. package/component-templates/components/date-range-calendar/switch.tsx +30 -0
  16. package/component-templates/components/datetime-picker/button.tsx +61 -0
  17. package/component-templates/components/datetime-picker/calendar.tsx +156 -0
  18. package/component-templates/components/datetime-picker/datetime-picker.tsx +75 -0
  19. package/component-templates/components/datetime-picker/input.tsx +20 -0
  20. package/component-templates/components/datetime-picker/label.tsx +18 -0
  21. package/component-templates/components/datetime-picker/period-input.tsx +62 -0
  22. package/component-templates/components/datetime-picker/popover.tsx +32 -0
  23. package/component-templates/components/datetime-picker/select.tsx +125 -0
  24. package/component-templates/components/datetime-picker/time-picker-input.tsx +131 -0
  25. package/component-templates/components/datetime-picker/time-picker-utils.tsx +204 -0
  26. package/component-templates/components/datetime-picker/time-picker.tsx +59 -0
  27. package/component-templates/components/gradient-outline.tsx +233 -0
  28. package/component-templates/components/gradient-svg.tsx +157 -0
  29. package/component-templates/components/grid-layout.tsx +69 -0
  30. package/component-templates/components/hydrate-guard.tsx +40 -0
  31. package/component-templates/components/image.tsx +92 -0
  32. package/component-templates/components/loader-slash-gradient.tsx +85 -0
  33. package/component-templates/components/masonry-gallery.tsx +221 -0
  34. package/component-templates/components/modal.tsx +110 -0
  35. package/component-templates/components/multi-select.tsx +447 -0
  36. package/component-templates/components/non-hydration.tsx +27 -0
  37. package/component-templates/components/portal.tsx +34 -0
  38. package/component-templates/components/segments-circle.tsx +235 -0
  39. package/component-templates/components/single-select.tsx +248 -0
  40. package/component-templates/components/stroke-circle.tsx +57 -0
  41. package/component-templates/components/table/column-table.tsx +15 -0
  42. package/component-templates/components/table/data-table.tsx +339 -0
  43. package/component-templates/components/table/readme.tsx +95 -0
  44. package/component-templates/components/table/table.tsx +60 -0
  45. package/component-templates/components/text-hover-effect.tsx +120 -0
  46. package/component-templates/components/timout-loader.tsx +52 -0
  47. package/component-templates/components/toast.tsx +994 -0
  48. package/component-templates/configs/config.ts +33 -0
  49. package/component-templates/configs/feature-config.tsx +432 -0
  50. package/component-templates/configs/keys.ts +7 -0
  51. package/component-templates/core/api-service.ts +202 -0
  52. package/component-templates/core/calculate.ts +18 -0
  53. package/component-templates/core/idb.ts +166 -0
  54. package/component-templates/core/storage.ts +213 -0
  55. package/component-templates/hooks/count-down.ts +38 -0
  56. package/component-templates/hooks/fade-on-scroll.ts +52 -0
  57. package/component-templates/hooks/safe-action.ts +59 -0
  58. package/component-templates/hooks/spam-guard.ts +31 -0
  59. package/component-templates/lib/utils.ts +6 -0
  60. package/component-templates/providers/feature-guard.tsx +432 -0
  61. package/component-templates/queries/query.tsx +775 -0
  62. package/component-templates/utils/colors/color-by-text.ts +307 -0
  63. package/component-templates/utils/colors/stripe-effect.ts +100 -0
  64. package/component-templates/utils/hash/hash-aes.ts +35 -0
  65. package/components.json +348 -0
  66. package/package.json +60 -0
@@ -0,0 +1,235 @@
1
+ // import {cn} from "@/lib/utils";
2
+ // import React from "react";
3
+
4
+ // type ProgressCircleProps = {
5
+ // dashCount: number;
6
+ // dashColor?: string;
7
+ // dashBorderColor?: string;
8
+ // dashBorderWidth?: number;
9
+ // strokeWidth?: number;
10
+ // radius?: number;
11
+ // gapLength?: number;
12
+ // dashColorList?: string[];
13
+ // angle?: any;
14
+ // className?: string;
15
+ // pathClass?: string;
16
+ // };
17
+
18
+ // export const ProgressCircle: React.FC<ProgressCircleProps> = ({
19
+ // dashCount,
20
+ // dashColor = "black",
21
+ // dashBorderColor = "white",
22
+ // dashBorderWidth = 0,
23
+ // strokeWidth = 4,
24
+ // radius = 24,
25
+ // gapLength = 7,
26
+ // dashColorList = [],
27
+ // angle = -83,
28
+ // className,
29
+ // pathClass,
30
+ // }) => {
31
+ // const circumference = 2 * Math.PI * radius;
32
+
33
+ // const totalGapLength = gapLength * dashCount;
34
+ // const totalDashLength = circumference - totalGapLength;
35
+
36
+ // const dashLength = totalDashLength / dashCount;
37
+ // const anglePerDash = (dashLength / circumference) * 360;
38
+
39
+ // const polarToCartesian = (
40
+ // cx: number,
41
+ // cy: number,
42
+ // r: number,
43
+ // angle: number
44
+ // ) => {
45
+ // const rad = (angle * Math.PI) / 180;
46
+ // return {
47
+ // x: cx + r * Math.cos(rad),
48
+ // y: cy + r * Math.sin(rad),
49
+ // };
50
+ // };
51
+
52
+ // const dashes = [];
53
+ // let currentAngle = angle;
54
+
55
+ // for (let i = 0; i < dashCount; i++) {
56
+ // const startAngle = currentAngle;
57
+ // const endAngle = startAngle + anglePerDash;
58
+
59
+ // const largeArcFlag = endAngle - startAngle > 180 ? 1 : 0;
60
+
61
+ // const start = polarToCartesian(
62
+ // radius + strokeWidth,
63
+ // radius + strokeWidth,
64
+ // radius,
65
+ // startAngle
66
+ // );
67
+ // const end = polarToCartesian(
68
+ // radius + strokeWidth,
69
+ // radius + strokeWidth,
70
+ // radius,
71
+ // endAngle
72
+ // );
73
+
74
+ // dashes.push(
75
+ // <path
76
+ // className={cn(pathClass)}
77
+ // key={i}
78
+ // d={`M ${start.x} ${start.y} A ${radius} ${radius} 0 ${largeArcFlag} 1 ${end.x} ${end.y}`}
79
+ // fill="none"
80
+ // stroke={dashColorList[i] || dashColor}
81
+ // strokeWidth={strokeWidth}
82
+ // strokeLinecap="round"
83
+ // strokeLinejoin="round"
84
+ // style={{
85
+ // strokeWidth: dashBorderWidth > 0 ? dashBorderWidth : strokeWidth,
86
+ // }}
87
+ // />
88
+ // );
89
+
90
+ // currentAngle = endAngle + (gapLength / circumference) * 360;
91
+ // }
92
+
93
+ // return (
94
+ // <svg
95
+ // className={cn(className)}
96
+ // height={radius * 2 + strokeWidth * 2}
97
+ // width={radius * 2 + strokeWidth * 2}
98
+ // >
99
+ // {dashes}
100
+ // </svg>
101
+ // );
102
+ // };
103
+
104
+ import React from 'react';
105
+
106
+ import { cn } from '../lib/utils';
107
+
108
+ export type SegmentCircleProps = {
109
+ dashCount: number;
110
+ colors?: string[]; // list of colors for each dash
111
+ color?: string; // fallback color if colors array is not provided
112
+ radius?: number;
113
+ strokeWidth?: number;
114
+ gapLength?: number;
115
+ startAngle?: number;
116
+ borderWidth?: number;
117
+ borderColor?: string;
118
+ className?: string;
119
+ pathClass?: string;
120
+ animate?: boolean; // animation rotation
121
+ speed?: number; // animation speed (s)
122
+ };
123
+
124
+ /**
125
+ * SegmentCircle component renders a circle with dashes (segments).
126
+ * It accepts various props to customize the appearance and behavior of the circle.
127
+ * @param {SegmentCircleProps} props - Properties for customizing the SegmentCircle component.
128
+ * @returns {JSX.Element} Rendered SegmentCircle component.
129
+ */
130
+ /**
131
+ * SegmentCircleProps:
132
+ * - dashCount: number of dashes (segments)
133
+ * - colors: list of colors for each dash (fallbacks to color if not provided)
134
+ * - color: fallback color if colors array is not provided
135
+ * - radius: radius of the circle
136
+ * - strokeWidth: stroke width of the dashes
137
+ * - gapLength: length of the gap between dashes
138
+ * - startAngle: starting angle of the first dash
139
+ * - borderWidth: border width (if needed)
140
+ * - borderColor: border color (if needed)
141
+ * - className: class name for the container element
142
+ * - pathClass: class name for each dash path
143
+ * - animate: whether to animate the rotation of the circle
144
+ * - speed: animation speed (seconds)
145
+ */
146
+ export const SegmentCircle: React.FC<SegmentCircleProps> = ({
147
+ dashCount,
148
+ colors = [],
149
+ color = "black",
150
+ radius = 24,
151
+ strokeWidth = 4,
152
+ gapLength = 7,
153
+ startAngle = -90,
154
+ borderWidth = 0,
155
+ borderColor = "white",
156
+ className,
157
+ pathClass,
158
+ animate = false,
159
+ speed = 2,
160
+ }) => {
161
+ const circumference = 2 * Math.PI * radius;
162
+ const totalGapLength = gapLength * dashCount;
163
+ const totalDashLength = circumference - totalGapLength;
164
+ const dashLength = totalDashLength / dashCount;
165
+ const anglePerDash = (dashLength / circumference) * 360;
166
+
167
+ const polarToCartesian = (cx: number, cy: number, r: number, angle: number) => {
168
+ const rad = (angle * Math.PI) / 180;
169
+ return {
170
+ x: cx + r * Math.cos(rad),
171
+ y: cy + r * Math.sin(rad),
172
+ };
173
+ };
174
+
175
+ const dashes: React.ReactNode[] = [];
176
+ let currentAngle = startAngle;
177
+
178
+ for (let i = 0; i < dashCount; i++) {
179
+ const start = polarToCartesian(radius, radius, radius, currentAngle);
180
+ const end = polarToCartesian(radius, radius, radius, currentAngle + anglePerDash);
181
+ const largeArcFlag = anglePerDash > 180 ? 1 : 0;
182
+
183
+ // border (if needed)
184
+ if (borderWidth > 0) {
185
+ dashes.push(
186
+ <path
187
+ key={`border-${i}`}
188
+ d={`M ${start.x} ${start.y} A ${radius} ${radius} 0 ${largeArcFlag} 1 ${end.x} ${end.y}`}
189
+ fill="none"
190
+ stroke={borderColor}
191
+ strokeWidth={strokeWidth + borderWidth * 2}
192
+ strokeLinecap="round"
193
+ />
194
+ );
195
+ }
196
+
197
+ // main dash
198
+ dashes.push(
199
+ <path
200
+ className={cn(pathClass)}
201
+ key={i}
202
+ d={`M ${start.x} ${start.y} A ${radius} ${radius} 0 ${largeArcFlag} 1 ${end.x} ${end.y}`}
203
+ fill="none"
204
+ stroke={colors[i] || color}
205
+ strokeWidth={strokeWidth}
206
+ strokeLinecap="round"
207
+ />
208
+ );
209
+
210
+ currentAngle += anglePerDash + (gapLength / circumference) * 360;
211
+ }
212
+
213
+ return (
214
+ <svg
215
+ className={cn(className)}
216
+ viewBox={`0 0 ${radius * 2} ${radius * 2}`}
217
+ width={radius * 2}
218
+ height={radius * 2}
219
+ style={
220
+ animate
221
+ ? { animation: `spin ${speed}s linear infinite` }
222
+ : undefined
223
+ }
224
+ >
225
+ {dashes}
226
+ {animate && (
227
+ <style>{`
228
+ @keyframes spin {
229
+ 100% { transform: rotate(360deg); }
230
+ }
231
+ `}</style>
232
+ )}
233
+ </svg>
234
+ );
235
+ };
@@ -0,0 +1,248 @@
1
+ "use client";
2
+
3
+ import * as React from 'react';
4
+
5
+ import {
6
+ CheckIcon,
7
+ ChevronDown,
8
+ Loader2,
9
+ Plus,
10
+ WandSparkles,
11
+ } from 'lucide-react';
12
+
13
+ import { cn } from '../lib/utils';
14
+ import { Button } from '../ui/button';
15
+ import {
16
+ Command,
17
+ CommandEmpty,
18
+ CommandGroup,
19
+ CommandInput,
20
+ CommandItem,
21
+ CommandList,
22
+ CommandSeparator,
23
+ } from '../ui/command';
24
+ import {
25
+ Popover,
26
+ PopoverContent,
27
+ PopoverTrigger,
28
+ } from '../ui/popover';
29
+ import { Separator } from '../ui/separator';
30
+
31
+ interface SingleSelectProps {
32
+ options: {
33
+ label: string;
34
+ value: string;
35
+ icon?: React.ComponentType<{ className?: string }>;
36
+ }[];
37
+
38
+ value?: string;
39
+ onValueChange: (value?: string) => void;
40
+
41
+ placeholder?: string;
42
+ animation?: number;
43
+ modalPopover?: boolean;
44
+ className?: string;
45
+
46
+ createNewWhenEmpty?: boolean;
47
+ onCreateNewWhenEmpty?: (
48
+ value: string,
49
+ ) => Promise<{ label: string; value: string; icon?: React.ComponentType<{ className?: string }> } | void>;
50
+ emptyLabel?: string;
51
+ newLabel?: React.ReactNode;
52
+ contentClassName?: string;
53
+ }
54
+
55
+ export const SingleSelect: React.FC<SingleSelectProps> = ({
56
+ options,
57
+ value,
58
+ onValueChange,
59
+ placeholder = "Select an option",
60
+ animation = 0,
61
+ modalPopover = false,
62
+ className,
63
+ createNewWhenEmpty = false,
64
+ onCreateNewWhenEmpty,
65
+ emptyLabel = "No options available",
66
+ contentClassName,
67
+ newLabel,
68
+ }) => {
69
+ const [isPopoverOpen, setIsPopoverOpen] = React.useState(false);
70
+ const [searchInput, setSearchInput] = React.useState("");
71
+ const [isCreating, setIsCreating] = React.useState(false);
72
+ const [isAnimating, setIsAnimating] = React.useState(false);
73
+
74
+ const triggerRef = React.useRef<HTMLButtonElement>(null);
75
+ const [triggerWidth, setTriggerWidth] = React.useState<number | undefined>();
76
+
77
+ const selectedOption = options.find((opt) => opt.value === value);
78
+
79
+
80
+ React.useEffect(() => {
81
+ const trigger = triggerRef.current;
82
+ if (!trigger) return;
83
+
84
+ const updateWidth = () => {
85
+ setTriggerWidth(trigger.offsetWidth);
86
+ };
87
+
88
+ updateWidth(); // set lần đầu
89
+
90
+ const resizeObserver = new ResizeObserver(updateWidth);
91
+ resizeObserver.observe(trigger);
92
+
93
+ return () => resizeObserver.disconnect();
94
+ }, []);
95
+
96
+
97
+
98
+ const handleClear = () => {
99
+ onValueChange(undefined);
100
+ };
101
+
102
+ const handleInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
103
+ if (event.key === "Enter") {
104
+ setIsPopoverOpen(true);
105
+ }
106
+ };
107
+
108
+ const handleCreate = async () => {
109
+ try {
110
+ setIsCreating(true);
111
+ const newItem = await onCreateNewWhenEmpty?.(searchInput);
112
+ if (newItem) {
113
+ onValueChange(newItem.value);
114
+ setSearchInput("");
115
+ setIsPopoverOpen(false);
116
+ }
117
+ } catch (err) {
118
+ console.error("create error:", err);
119
+ } finally {
120
+ setIsCreating(false);
121
+ }
122
+ };
123
+
124
+ return (
125
+ <Popover open={isPopoverOpen} onOpenChange={setIsPopoverOpen} modal={modalPopover}>
126
+ <PopoverTrigger asChild>
127
+ <Button
128
+ ref={triggerRef}
129
+ onClick={() => setIsPopoverOpen(true)}
130
+ className={cn(
131
+ "border-border flex h-auto min-h-10 w-full items-center justify-between rounded-md border bg-inherit p-1 hover:bg-inherit [&_svg]:pointer-events-auto",
132
+ className,
133
+ )}
134
+ >
135
+ {selectedOption ? (
136
+ <div className="flex w-full items-center justify-between">
137
+ <div className="flex items-center">
138
+ {selectedOption.icon && <selectedOption.icon className="mr-2 h-4 w-4" />}
139
+ <span className="text-foreground mx-3 text-sm">{selectedOption.label}</span>
140
+ </div>
141
+ <div className="flex items-center justify-between">
142
+ {/* <XIcon
143
+ className="text-muted-foreground mx-2 h-4 cursor-pointer"
144
+ onClick={(event) => {
145
+ event.stopPropagation();
146
+ handleClear();
147
+ }}
148
+ />
149
+ <Separator orientation="vertical" className="flex h-full min-h-6" /> */}
150
+ <ChevronDown className="text-muted-foreground mx-2 h-4 cursor-pointer" />
151
+ </div>
152
+ </div>
153
+ ) : (
154
+ <div className="mx-auto flex w-full items-center justify-between">
155
+ <span className="text-muted-foreground mx-3 text-sm">{placeholder}</span>
156
+ <ChevronDown className="text-muted-foreground mx-2 h-4 cursor-pointer" />
157
+ </div>
158
+ )}
159
+ </Button>
160
+ </PopoverTrigger>
161
+
162
+ <PopoverContent style={{ width: triggerWidth || "auto" }} className={cn("border-red-500 w-full p-0", contentClassName)} align="start">
163
+ <Command>
164
+ <CommandInput
165
+ placeholder="Search..."
166
+ value={searchInput}
167
+ onValueChange={setSearchInput}
168
+ onKeyDown={handleInputKeyDown}
169
+ />
170
+ <CommandList className={(createNewWhenEmpty && searchInput.trim() !== "" && "p-1") || ""}>
171
+ <CommandEmpty className={(createNewWhenEmpty && searchInput.trim() !== "" && "py-0") || ""}>
172
+ {createNewWhenEmpty && searchInput.trim() !== "" && onCreateNewWhenEmpty ? (
173
+ <div
174
+ className={cn(
175
+ "text-muted-foreground hover:bg-accent flex h-10 cursor-pointer items-center justify-center rounded-md px-4 text-sm",
176
+ isCreating && "pointer-events-none opacity-50",
177
+ )}
178
+ onClick={() => handleCreate()}
179
+ >
180
+ {isCreating ? (
181
+ <Loader2 className="h-4 w-4 animate-spin" />
182
+ ) : (
183
+ <>
184
+ {newLabel ?? <Plus className="mr-2 h-4 w-4" />}
185
+ <span className="font-medium">"{searchInput}"</span>
186
+ </>
187
+ )}
188
+ </div>
189
+ ) : (
190
+ <div className="py-2 text-center text-sm text-muted-foreground">{emptyLabel}</div>
191
+ )}
192
+ </CommandEmpty>
193
+
194
+ <CommandGroup>
195
+ {options.map((option) => {
196
+ const isSelected = option.value === value;
197
+ return (
198
+ <CommandItem
199
+ key={option.value}
200
+ onSelect={() => {
201
+ onValueChange(option.value);
202
+ setIsPopoverOpen(false);
203
+ }}
204
+ className="cursor-pointer"
205
+ >
206
+ <div
207
+ className={cn(
208
+ "border-border mr-2 flex h-4 w-4 items-center justify-center rounded-sm border",
209
+ isSelected ? "bg-primary text-foreground" : "opacity-50 [&_svg]:invisible",
210
+ )}
211
+ >
212
+ <CheckIcon className="h-4 w-4" />
213
+ </div>
214
+ {option.icon && <option.icon className="text-muted-foreground mr-2 h-4 w-4" />}
215
+ <span>{option.label}</span>
216
+ </CommandItem>
217
+ );
218
+ })}
219
+ </CommandGroup>
220
+ <CommandSeparator />
221
+ <CommandGroup>
222
+ <div className="flex items-center justify-between">
223
+ {value && (
224
+ <>
225
+ <CommandItem onSelect={handleClear} className="flex-1 cursor-pointer justify-center">
226
+ Clear
227
+ </CommandItem>
228
+ <Separator orientation="vertical" className="flex h-full min-h-6" />
229
+ </>
230
+ )}
231
+ <CommandItem onSelect={() => setIsPopoverOpen(false)} className="flex-1 cursor-pointer justify-center">
232
+ Close
233
+ </CommandItem>
234
+ </div>
235
+ </CommandGroup>
236
+ </CommandList>
237
+ </Command>
238
+ </PopoverContent>
239
+
240
+ {animation > 0 && value && (
241
+ <WandSparkles
242
+ className={cn("text-foreground bg-background my-2 h-3 w-3 cursor-pointer", isAnimating ? "" : "text-muted-foreground")}
243
+ onClick={() => setIsAnimating(!isAnimating)}
244
+ />
245
+ )}
246
+ </Popover>
247
+ );
248
+ };
@@ -0,0 +1,57 @@
1
+ import React from 'react';
2
+
3
+ export type CircleStrokeProps = {
4
+ radius?: number;
5
+ strokeColor?: string;
6
+ strokeWidth?: number;
7
+ dashCount?: number; // dash count
8
+ gapLength?: number; // dash gap length
9
+ strokeLinecap?: "butt" | "round" | "square";
10
+ strokeLinejoin?: "miter" | "round" | "bevel";
11
+ fill?: string;
12
+ className?: string;
13
+ style?: React.CSSProperties;
14
+ cx?: number;
15
+ cy?: number;
16
+ } & React.HTMLAttributes<SVGElement>;
17
+
18
+ export const CircleStroke: React.FC<CircleStrokeProps> = ({
19
+ radius = 40,
20
+ strokeWidth = 5,
21
+ strokeColor = "black",
22
+ dashCount = 12,
23
+ gapLength = 5,
24
+ strokeLinecap = "round",
25
+ strokeLinejoin = "round",
26
+ fill = "transparent",
27
+ cx = 50,
28
+ cy = 50,
29
+ className,
30
+ style,
31
+ ...props
32
+ }) => {
33
+ const circumference = 2 * Math.PI * radius;
34
+ const dashLength = (circumference - dashCount * gapLength) / dashCount;
35
+
36
+ return (
37
+ <svg
38
+ height={(radius + strokeWidth) * 2}
39
+ width={(radius + strokeWidth) * 2}
40
+ className={className}
41
+ style={style}
42
+ {...props}
43
+ >
44
+ <circle
45
+ cx={cx}
46
+ cy={cy}
47
+ r={radius}
48
+ stroke={strokeColor}
49
+ strokeWidth={strokeWidth}
50
+ fill={fill}
51
+ strokeDasharray={`${dashLength} ${gapLength}`}
52
+ strokeLinecap={strokeLinecap}
53
+ strokeLinejoin={strokeLinejoin}
54
+ />
55
+ </svg>
56
+ );
57
+ };
@@ -0,0 +1,15 @@
1
+ import { useEffect } from "react";
2
+
3
+ import { ColumnDef } from "@tanstack/react-table";
4
+
5
+ export interface DataColumnProps<TData, TValue> {
6
+ arr: ColumnDef<TData, TValue>[];
7
+ onReady?: (columns: ColumnDef<TData, TValue>[]) => void;
8
+ }
9
+
10
+ export const DataColumns = <TData, TValue>({ arr, onReady }: DataColumnProps<TData, TValue>): ColumnDef<TData, TValue>[] => {
11
+ useEffect(() => {
12
+ onReady?.(arr);
13
+ }, [arr]);
14
+ return arr;
15
+ };