@mohasinac/react 0.1.0 → 1.1.0
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/index.cjs +408 -2
- package/dist/index.d.cts +270 -2
- package/dist/index.d.ts +270 -2
- package/dist/index.js +403 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defProps = Object.defineProperties;
|
|
3
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __spreadValues = (a, b) => {
|
|
9
|
+
for (var prop in b || (b = {}))
|
|
10
|
+
if (__hasOwnProp.call(b, prop))
|
|
11
|
+
__defNormalProp(a, prop, b[prop]);
|
|
12
|
+
if (__getOwnPropSymbols)
|
|
13
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
14
|
+
if (__propIsEnum.call(b, prop))
|
|
15
|
+
__defNormalProp(a, prop, b[prop]);
|
|
16
|
+
}
|
|
17
|
+
return a;
|
|
18
|
+
};
|
|
19
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
+
|
|
1
21
|
// src/hooks/useMediaQuery.ts
|
|
2
22
|
import { useState, useEffect } from "react";
|
|
3
23
|
function useMediaQuery(query) {
|
|
@@ -708,8 +728,386 @@ function useCamera() {
|
|
|
708
728
|
switchCamera
|
|
709
729
|
};
|
|
710
730
|
}
|
|
731
|
+
|
|
732
|
+
// src/hooks/useBulkSelection.ts
|
|
733
|
+
import { useState as useState5, useCallback as useCallback5, useMemo as useMemo2 } from "react";
|
|
734
|
+
var BULK_MAX_IDS = 100;
|
|
735
|
+
function useBulkSelection({
|
|
736
|
+
items,
|
|
737
|
+
keyExtractor,
|
|
738
|
+
maxSelection = BULK_MAX_IDS
|
|
739
|
+
}) {
|
|
740
|
+
const [selectedIds, setSelectedIds] = useState5([]);
|
|
741
|
+
const allIds = useMemo2(() => items.map(keyExtractor), [items, keyExtractor]);
|
|
742
|
+
const isSelected = useCallback5(
|
|
743
|
+
(id) => selectedIds.includes(id),
|
|
744
|
+
[selectedIds]
|
|
745
|
+
);
|
|
746
|
+
const toggle = useCallback5(
|
|
747
|
+
(id) => {
|
|
748
|
+
setSelectedIds((prev) => {
|
|
749
|
+
if (prev.includes(id)) return prev.filter((s) => s !== id);
|
|
750
|
+
if (prev.length >= maxSelection) return prev;
|
|
751
|
+
return [...prev, id];
|
|
752
|
+
});
|
|
753
|
+
},
|
|
754
|
+
[maxSelection]
|
|
755
|
+
);
|
|
756
|
+
const toggleAll = useCallback5(() => {
|
|
757
|
+
setSelectedIds((prev) => {
|
|
758
|
+
const allSelected = prev.length === allIds.length && allIds.length > 0;
|
|
759
|
+
if (allSelected) return [];
|
|
760
|
+
return allIds.slice(0, maxSelection);
|
|
761
|
+
});
|
|
762
|
+
}, [allIds, maxSelection]);
|
|
763
|
+
const clearSelection = useCallback5(() => setSelectedIds([]), []);
|
|
764
|
+
const isAllSelected = allIds.length > 0 && selectedIds.length === allIds.length;
|
|
765
|
+
const isIndeterminate = selectedIds.length > 0 && selectedIds.length < allIds.length;
|
|
766
|
+
return {
|
|
767
|
+
selectedIds,
|
|
768
|
+
selectedCount: selectedIds.length,
|
|
769
|
+
isSelected,
|
|
770
|
+
isAllSelected,
|
|
771
|
+
isIndeterminate,
|
|
772
|
+
toggle,
|
|
773
|
+
toggleAll,
|
|
774
|
+
clearSelection,
|
|
775
|
+
setSelectedIds
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
// src/hooks/useUrlTable.ts
|
|
780
|
+
import { useRouter, usePathname, useSearchParams } from "next/navigation";
|
|
781
|
+
import { useCallback as useCallback6 } from "react";
|
|
782
|
+
var NON_RESETTING_KEYS = ["page", "pageSize", "view"];
|
|
783
|
+
function useUrlTable(options) {
|
|
784
|
+
var _a;
|
|
785
|
+
const router = useRouter();
|
|
786
|
+
const pathname = usePathname();
|
|
787
|
+
const searchParams = useSearchParams();
|
|
788
|
+
const defaults = (_a = options == null ? void 0 : options.defaults) != null ? _a : {};
|
|
789
|
+
const get = useCallback6(
|
|
790
|
+
(key) => {
|
|
791
|
+
var _a2, _b;
|
|
792
|
+
return (_b = (_a2 = searchParams.get(key)) != null ? _a2 : defaults[key]) != null ? _b : "";
|
|
793
|
+
},
|
|
794
|
+
[searchParams, defaults]
|
|
795
|
+
);
|
|
796
|
+
const getNumber = useCallback6(
|
|
797
|
+
(key, fallback = 0) => {
|
|
798
|
+
const v = get(key);
|
|
799
|
+
if (!v) return fallback;
|
|
800
|
+
const n = Number(v);
|
|
801
|
+
return isNaN(n) ? fallback : n;
|
|
802
|
+
},
|
|
803
|
+
[get]
|
|
804
|
+
);
|
|
805
|
+
const buildParams = useCallback6(
|
|
806
|
+
(updates) => {
|
|
807
|
+
const p = new URLSearchParams(searchParams.toString());
|
|
808
|
+
for (const [k, v] of Object.entries(updates)) {
|
|
809
|
+
if (v === "" || v === void 0) p.delete(k);
|
|
810
|
+
else p.set(k, v);
|
|
811
|
+
}
|
|
812
|
+
return p;
|
|
813
|
+
},
|
|
814
|
+
[searchParams]
|
|
815
|
+
);
|
|
816
|
+
const set = useCallback6(
|
|
817
|
+
(key, value) => {
|
|
818
|
+
const p = buildParams({ [key]: value });
|
|
819
|
+
if (!NON_RESETTING_KEYS.includes(key)) {
|
|
820
|
+
p.set("page", "1");
|
|
821
|
+
}
|
|
822
|
+
router.replace(`${pathname}?${p.toString()}`);
|
|
823
|
+
},
|
|
824
|
+
[buildParams, pathname, router]
|
|
825
|
+
);
|
|
826
|
+
const setMany = useCallback6(
|
|
827
|
+
(updates) => {
|
|
828
|
+
const p = buildParams(updates);
|
|
829
|
+
const keys = Object.keys(updates);
|
|
830
|
+
const allNonResetting = keys.every(
|
|
831
|
+
(k) => NON_RESETTING_KEYS.includes(k)
|
|
832
|
+
);
|
|
833
|
+
if (!allNonResetting && !keys.includes("page")) {
|
|
834
|
+
p.set("page", "1");
|
|
835
|
+
}
|
|
836
|
+
router.replace(`${pathname}?${p.toString()}`);
|
|
837
|
+
},
|
|
838
|
+
[buildParams, pathname, router]
|
|
839
|
+
);
|
|
840
|
+
const clear = useCallback6(
|
|
841
|
+
(keys) => {
|
|
842
|
+
if (keys) {
|
|
843
|
+
const p = new URLSearchParams(searchParams.toString());
|
|
844
|
+
keys.forEach((k) => p.delete(k));
|
|
845
|
+
p.set("page", "1");
|
|
846
|
+
router.replace(`${pathname}?${p.toString()}`);
|
|
847
|
+
} else {
|
|
848
|
+
router.replace(pathname);
|
|
849
|
+
}
|
|
850
|
+
},
|
|
851
|
+
[searchParams, pathname, router]
|
|
852
|
+
);
|
|
853
|
+
const setPage = (page) => set("page", String(page));
|
|
854
|
+
const setPageSize = (size) => set("pageSize", String(size));
|
|
855
|
+
const setSort = (sort) => set("sort", sort);
|
|
856
|
+
const buildSieveParams = useCallback6(
|
|
857
|
+
(sieveFilters) => {
|
|
858
|
+
const page = get("page") || "1";
|
|
859
|
+
const pageSize = get("pageSize") || defaults["pageSize"] || "25";
|
|
860
|
+
const sort = get("sort") || defaults["sort"] || "-createdAt";
|
|
861
|
+
const parts = new URLSearchParams();
|
|
862
|
+
if (sieveFilters) parts.set("filters", sieveFilters);
|
|
863
|
+
parts.set("sorts", sort);
|
|
864
|
+
parts.set("page", page);
|
|
865
|
+
parts.set("pageSize", pageSize);
|
|
866
|
+
return `?${parts.toString()}`;
|
|
867
|
+
},
|
|
868
|
+
[get, defaults]
|
|
869
|
+
);
|
|
870
|
+
const buildSearchParams = useCallback6(() => {
|
|
871
|
+
const p = new URLSearchParams();
|
|
872
|
+
const addIfPresent = (k) => {
|
|
873
|
+
const v = get(k);
|
|
874
|
+
if (v) p.set(k, v);
|
|
875
|
+
};
|
|
876
|
+
["q", "category", "minPrice", "maxPrice"].forEach(addIfPresent);
|
|
877
|
+
p.set("sort", get("sort") || defaults["sort"] || "-createdAt");
|
|
878
|
+
p.set("page", get("page") || "1");
|
|
879
|
+
p.set("pageSize", get("pageSize") || defaults["pageSize"] || "24");
|
|
880
|
+
return `?${p.toString()}`;
|
|
881
|
+
}, [get, defaults]);
|
|
882
|
+
return {
|
|
883
|
+
params: searchParams,
|
|
884
|
+
get,
|
|
885
|
+
getNumber,
|
|
886
|
+
set,
|
|
887
|
+
setMany,
|
|
888
|
+
clear,
|
|
889
|
+
setPage,
|
|
890
|
+
setPageSize,
|
|
891
|
+
setSort,
|
|
892
|
+
buildSieveParams,
|
|
893
|
+
buildSearchParams
|
|
894
|
+
};
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
// src/hooks/usePendingFilters.ts
|
|
898
|
+
import { useCallback as useCallback7, useMemo as useMemo3, useState as useState6 } from "react";
|
|
899
|
+
function usePendingFilters({
|
|
900
|
+
table,
|
|
901
|
+
keys
|
|
902
|
+
}) {
|
|
903
|
+
const parseValues = useCallback7(
|
|
904
|
+
(key) => {
|
|
905
|
+
const raw = table.get(key);
|
|
906
|
+
return raw ? raw.split(",").filter(Boolean) : [];
|
|
907
|
+
},
|
|
908
|
+
[table]
|
|
909
|
+
);
|
|
910
|
+
const [pending, setPending] = useState6(
|
|
911
|
+
() => Object.fromEntries(keys.map((k) => [k, parseValues(k)]))
|
|
912
|
+
);
|
|
913
|
+
const applied = useMemo3(
|
|
914
|
+
() => Object.fromEntries(keys.map((k) => [k, parseValues(k)])),
|
|
915
|
+
[keys, parseValues]
|
|
916
|
+
);
|
|
917
|
+
const pendingCount = useMemo3(
|
|
918
|
+
() => Object.values(pending).reduce((sum, arr) => sum + arr.length, 0),
|
|
919
|
+
[pending]
|
|
920
|
+
);
|
|
921
|
+
const appliedCount = useMemo3(
|
|
922
|
+
() => Object.values(applied).reduce((sum, arr) => sum + arr.length, 0),
|
|
923
|
+
[applied]
|
|
924
|
+
);
|
|
925
|
+
const isDirty = useMemo3(() => {
|
|
926
|
+
return keys.some((k) => {
|
|
927
|
+
var _a, _b;
|
|
928
|
+
const p = ((_a = pending[k]) != null ? _a : []).slice().sort();
|
|
929
|
+
const a = ((_b = applied[k]) != null ? _b : []).slice().sort();
|
|
930
|
+
return p.length !== a.length || p.some((v, i) => v !== a[i]);
|
|
931
|
+
});
|
|
932
|
+
}, [keys, pending, applied]);
|
|
933
|
+
const set = useCallback7((key, values) => {
|
|
934
|
+
setPending((prev) => __spreadProps(__spreadValues({}, prev), { [key]: values }));
|
|
935
|
+
}, []);
|
|
936
|
+
const apply = useCallback7(() => {
|
|
937
|
+
var _a;
|
|
938
|
+
const updates = { page: "1" };
|
|
939
|
+
for (const k of keys) {
|
|
940
|
+
updates[k] = ((_a = pending[k]) != null ? _a : []).join(",");
|
|
941
|
+
}
|
|
942
|
+
table.setMany(updates);
|
|
943
|
+
}, [keys, pending, table]);
|
|
944
|
+
const reset = useCallback7(() => {
|
|
945
|
+
setPending(Object.fromEntries(keys.map((k) => [k, parseValues(k)])));
|
|
946
|
+
}, [keys, parseValues]);
|
|
947
|
+
const clear = useCallback7(() => {
|
|
948
|
+
const empty = Object.fromEntries(keys.map((k) => [k, []]));
|
|
949
|
+
setPending(empty);
|
|
950
|
+
const updates = { page: "1" };
|
|
951
|
+
for (const k of keys) updates[k] = "";
|
|
952
|
+
table.setMany(updates);
|
|
953
|
+
}, [keys, table]);
|
|
954
|
+
return {
|
|
955
|
+
pending,
|
|
956
|
+
applied,
|
|
957
|
+
isDirty,
|
|
958
|
+
pendingCount,
|
|
959
|
+
appliedCount,
|
|
960
|
+
set,
|
|
961
|
+
apply,
|
|
962
|
+
reset,
|
|
963
|
+
clear
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
// src/hooks/usePendingTable.ts
|
|
968
|
+
import { useMemo as useMemo4 } from "react";
|
|
969
|
+
function usePendingTable(table, keys) {
|
|
970
|
+
const filters = usePendingFilters({ table, keys });
|
|
971
|
+
const pendingTable = useMemo4(
|
|
972
|
+
() => ({
|
|
973
|
+
get: (key) => {
|
|
974
|
+
var _a, _b;
|
|
975
|
+
return (_b = (_a = filters.pending[key]) == null ? void 0 : _a[0]) != null ? _b : "";
|
|
976
|
+
},
|
|
977
|
+
set: (key, value) => {
|
|
978
|
+
filters.set(key, value ? [value] : []);
|
|
979
|
+
},
|
|
980
|
+
setMany: (updates) => {
|
|
981
|
+
for (const [k, v] of Object.entries(updates)) {
|
|
982
|
+
filters.set(k, v ? [v] : []);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
}),
|
|
986
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
987
|
+
[filters.pending, filters.set]
|
|
988
|
+
);
|
|
989
|
+
return {
|
|
990
|
+
pendingTable,
|
|
991
|
+
filterActiveCount: filters.appliedCount,
|
|
992
|
+
onFilterApply: filters.apply,
|
|
993
|
+
onFilterClear: filters.clear
|
|
994
|
+
};
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
// src/hooks/useUnsavedChanges.ts
|
|
998
|
+
import { useState as useState7, useEffect as useEffect10, useCallback as useCallback8, useRef as useRef8 } from "react";
|
|
999
|
+
var UNSAVED_CHANGES_EVENT = "unsaved-changes:confirm";
|
|
1000
|
+
function useUnsavedChanges({
|
|
1001
|
+
formValues,
|
|
1002
|
+
initialValues,
|
|
1003
|
+
extraDirty = false,
|
|
1004
|
+
confirmFn,
|
|
1005
|
+
beforeUnloadWarning = "You have unsaved changes. Leave?"
|
|
1006
|
+
}) {
|
|
1007
|
+
const [savedSnapshot, setSavedSnapshot] = useState7(initialValues);
|
|
1008
|
+
const savedSnapshotRef = useRef8(savedSnapshot);
|
|
1009
|
+
savedSnapshotRef.current = savedSnapshot;
|
|
1010
|
+
useEffect10(() => {
|
|
1011
|
+
if (initialValues && !savedSnapshotRef.current) {
|
|
1012
|
+
setSavedSnapshot(initialValues);
|
|
1013
|
+
}
|
|
1014
|
+
}, [initialValues]);
|
|
1015
|
+
const isFormDirty = (() => {
|
|
1016
|
+
if (!savedSnapshot) return false;
|
|
1017
|
+
return Object.keys(formValues).some(
|
|
1018
|
+
(key) => {
|
|
1019
|
+
var _a, _b;
|
|
1020
|
+
return ((_a = formValues[key]) != null ? _a : "") !== ((_b = savedSnapshot[key]) != null ? _b : "");
|
|
1021
|
+
}
|
|
1022
|
+
);
|
|
1023
|
+
})();
|
|
1024
|
+
const isDirty = isFormDirty || extraDirty;
|
|
1025
|
+
useEffect10(() => {
|
|
1026
|
+
if (!isDirty) return;
|
|
1027
|
+
const handler = (e) => {
|
|
1028
|
+
e.preventDefault();
|
|
1029
|
+
e.returnValue = beforeUnloadWarning;
|
|
1030
|
+
return beforeUnloadWarning;
|
|
1031
|
+
};
|
|
1032
|
+
window.addEventListener("beforeunload", handler);
|
|
1033
|
+
return () => window.removeEventListener("beforeunload", handler);
|
|
1034
|
+
}, [isDirty, beforeUnloadWarning]);
|
|
1035
|
+
const markClean = useCallback8(() => {
|
|
1036
|
+
setSavedSnapshot(__spreadValues({}, formValues));
|
|
1037
|
+
}, [formValues]);
|
|
1038
|
+
const confirmLeave = useCallback8(() => {
|
|
1039
|
+
if (!isDirty) return Promise.resolve(true);
|
|
1040
|
+
if (confirmFn) return confirmFn();
|
|
1041
|
+
return Promise.resolve(
|
|
1042
|
+
window.confirm("You have unsaved changes. Leave without saving?")
|
|
1043
|
+
);
|
|
1044
|
+
}, [isDirty, confirmFn]);
|
|
1045
|
+
return { isDirty, isFormDirty, markClean, confirmLeave };
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
// src/hooks/useBulkAction.ts
|
|
1049
|
+
import { useState as useState8, useCallback as useCallback9, useRef as useRef9 } from "react";
|
|
1050
|
+
function useBulkAction(options) {
|
|
1051
|
+
const [isLoading, setIsLoading] = useState8(false);
|
|
1052
|
+
const [result, setResult] = useState8(null);
|
|
1053
|
+
const [error, setError] = useState8(null);
|
|
1054
|
+
const [pendingPayload, setPendingPayload] = useState8(null);
|
|
1055
|
+
const optionsRef = useRef9(options);
|
|
1056
|
+
optionsRef.current = options;
|
|
1057
|
+
const runMutation = useCallback9(async (payload) => {
|
|
1058
|
+
var _a, _b, _c, _d, _e;
|
|
1059
|
+
setIsLoading(true);
|
|
1060
|
+
setError(null);
|
|
1061
|
+
try {
|
|
1062
|
+
const res = await optionsRef.current.mutationFn(payload);
|
|
1063
|
+
setResult(res);
|
|
1064
|
+
await ((_b = (_a = optionsRef.current).onSuccess) == null ? void 0 : _b.call(_a, res, payload));
|
|
1065
|
+
} catch (err) {
|
|
1066
|
+
const error2 = err instanceof Error ? err : new Error((_c = err == null ? void 0 : err.message) != null ? _c : "Unexpected error");
|
|
1067
|
+
setError(error2);
|
|
1068
|
+
(_e = (_d = optionsRef.current).onError) == null ? void 0 : _e.call(_d, error2, payload);
|
|
1069
|
+
} finally {
|
|
1070
|
+
setIsLoading(false);
|
|
1071
|
+
}
|
|
1072
|
+
}, []);
|
|
1073
|
+
const execute = useCallback9(
|
|
1074
|
+
async (payload) => {
|
|
1075
|
+
if (optionsRef.current.requiresConfirm) {
|
|
1076
|
+
setPendingPayload(payload);
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
1079
|
+
await runMutation(payload);
|
|
1080
|
+
},
|
|
1081
|
+
[runMutation]
|
|
1082
|
+
);
|
|
1083
|
+
const confirmAndExecute = useCallback9(async () => {
|
|
1084
|
+
if (!pendingPayload) return;
|
|
1085
|
+
const payload = pendingPayload;
|
|
1086
|
+
setPendingPayload(null);
|
|
1087
|
+
await runMutation(payload);
|
|
1088
|
+
}, [pendingPayload, runMutation]);
|
|
1089
|
+
const cancelConfirm = useCallback9(() => setPendingPayload(null), []);
|
|
1090
|
+
const reset = useCallback9(() => {
|
|
1091
|
+
setResult(null);
|
|
1092
|
+
setError(null);
|
|
1093
|
+
setPendingPayload(null);
|
|
1094
|
+
}, []);
|
|
1095
|
+
return {
|
|
1096
|
+
execute,
|
|
1097
|
+
isLoading,
|
|
1098
|
+
result,
|
|
1099
|
+
error,
|
|
1100
|
+
reset,
|
|
1101
|
+
pendingPayload,
|
|
1102
|
+
confirmAndExecute,
|
|
1103
|
+
cancelConfirm
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
711
1106
|
export {
|
|
1107
|
+
UNSAVED_CHANGES_EVENT,
|
|
712
1108
|
useBreakpoint,
|
|
1109
|
+
useBulkAction,
|
|
1110
|
+
useBulkSelection,
|
|
713
1111
|
useCamera,
|
|
714
1112
|
useClickOutside,
|
|
715
1113
|
useCountdown,
|
|
@@ -717,6 +1115,10 @@ export {
|
|
|
717
1115
|
useKeyPress,
|
|
718
1116
|
useLongPress,
|
|
719
1117
|
useMediaQuery,
|
|
1118
|
+
usePendingFilters,
|
|
1119
|
+
usePendingTable,
|
|
720
1120
|
usePullToRefresh,
|
|
721
|
-
useSwipe
|
|
1121
|
+
useSwipe,
|
|
1122
|
+
useUnsavedChanges,
|
|
1123
|
+
useUrlTable
|
|
722
1124
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mohasinac/react",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
27
|
"react": ">=18",
|
|
28
|
-
"react-dom": ">=18"
|
|
28
|
+
"react-dom": ">=18",
|
|
29
|
+
"next": ">=14"
|
|
29
30
|
},
|
|
30
31
|
"devDependencies": {
|
|
31
32
|
"tsup": "^8.5.0",
|