@mohasinac/react 1.0.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 CHANGED
@@ -1,8 +1,25 @@
1
1
  "use strict";
2
2
  var __defProp = Object.defineProperty;
3
+ var __defProps = Object.defineProperties;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
10
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
11
+ var __spreadValues = (a, b) => {
12
+ for (var prop in b || (b = {}))
13
+ if (__hasOwnProp.call(b, prop))
14
+ __defNormalProp(a, prop, b[prop]);
15
+ if (__getOwnPropSymbols)
16
+ for (var prop of __getOwnPropSymbols(b)) {
17
+ if (__propIsEnum.call(b, prop))
18
+ __defNormalProp(a, prop, b[prop]);
19
+ }
20
+ return a;
21
+ };
22
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
6
23
  var __export = (target, all) => {
7
24
  for (var name in all)
8
25
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -20,7 +37,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
37
  // src/index.ts
21
38
  var index_exports = {};
22
39
  __export(index_exports, {
40
+ UNSAVED_CHANGES_EVENT: () => UNSAVED_CHANGES_EVENT,
23
41
  useBreakpoint: () => useBreakpoint,
42
+ useBulkAction: () => useBulkAction,
43
+ useBulkSelection: () => useBulkSelection,
24
44
  useCamera: () => useCamera,
25
45
  useClickOutside: () => useClickOutside,
26
46
  useCountdown: () => useCountdown,
@@ -28,8 +48,12 @@ __export(index_exports, {
28
48
  useKeyPress: () => useKeyPress,
29
49
  useLongPress: () => useLongPress,
30
50
  useMediaQuery: () => useMediaQuery,
51
+ usePendingFilters: () => usePendingFilters,
52
+ usePendingTable: () => usePendingTable,
31
53
  usePullToRefresh: () => usePullToRefresh,
32
- useSwipe: () => useSwipe
54
+ useSwipe: () => useSwipe,
55
+ useUnsavedChanges: () => useUnsavedChanges,
56
+ useUrlTable: () => useUrlTable
33
57
  });
34
58
  module.exports = __toCommonJS(index_exports);
35
59
 
@@ -743,9 +767,387 @@ function useCamera() {
743
767
  switchCamera
744
768
  };
745
769
  }
770
+
771
+ // src/hooks/useBulkSelection.ts
772
+ var import_react10 = require("react");
773
+ var BULK_MAX_IDS = 100;
774
+ function useBulkSelection({
775
+ items,
776
+ keyExtractor,
777
+ maxSelection = BULK_MAX_IDS
778
+ }) {
779
+ const [selectedIds, setSelectedIds] = (0, import_react10.useState)([]);
780
+ const allIds = (0, import_react10.useMemo)(() => items.map(keyExtractor), [items, keyExtractor]);
781
+ const isSelected = (0, import_react10.useCallback)(
782
+ (id) => selectedIds.includes(id),
783
+ [selectedIds]
784
+ );
785
+ const toggle = (0, import_react10.useCallback)(
786
+ (id) => {
787
+ setSelectedIds((prev) => {
788
+ if (prev.includes(id)) return prev.filter((s) => s !== id);
789
+ if (prev.length >= maxSelection) return prev;
790
+ return [...prev, id];
791
+ });
792
+ },
793
+ [maxSelection]
794
+ );
795
+ const toggleAll = (0, import_react10.useCallback)(() => {
796
+ setSelectedIds((prev) => {
797
+ const allSelected = prev.length === allIds.length && allIds.length > 0;
798
+ if (allSelected) return [];
799
+ return allIds.slice(0, maxSelection);
800
+ });
801
+ }, [allIds, maxSelection]);
802
+ const clearSelection = (0, import_react10.useCallback)(() => setSelectedIds([]), []);
803
+ const isAllSelected = allIds.length > 0 && selectedIds.length === allIds.length;
804
+ const isIndeterminate = selectedIds.length > 0 && selectedIds.length < allIds.length;
805
+ return {
806
+ selectedIds,
807
+ selectedCount: selectedIds.length,
808
+ isSelected,
809
+ isAllSelected,
810
+ isIndeterminate,
811
+ toggle,
812
+ toggleAll,
813
+ clearSelection,
814
+ setSelectedIds
815
+ };
816
+ }
817
+
818
+ // src/hooks/useUrlTable.ts
819
+ var import_navigation = require("next/navigation");
820
+ var import_react11 = require("react");
821
+ var NON_RESETTING_KEYS = ["page", "pageSize", "view"];
822
+ function useUrlTable(options) {
823
+ var _a;
824
+ const router = (0, import_navigation.useRouter)();
825
+ const pathname = (0, import_navigation.usePathname)();
826
+ const searchParams = (0, import_navigation.useSearchParams)();
827
+ const defaults = (_a = options == null ? void 0 : options.defaults) != null ? _a : {};
828
+ const get = (0, import_react11.useCallback)(
829
+ (key) => {
830
+ var _a2, _b;
831
+ return (_b = (_a2 = searchParams.get(key)) != null ? _a2 : defaults[key]) != null ? _b : "";
832
+ },
833
+ [searchParams, defaults]
834
+ );
835
+ const getNumber = (0, import_react11.useCallback)(
836
+ (key, fallback = 0) => {
837
+ const v = get(key);
838
+ if (!v) return fallback;
839
+ const n = Number(v);
840
+ return isNaN(n) ? fallback : n;
841
+ },
842
+ [get]
843
+ );
844
+ const buildParams = (0, import_react11.useCallback)(
845
+ (updates) => {
846
+ const p = new URLSearchParams(searchParams.toString());
847
+ for (const [k, v] of Object.entries(updates)) {
848
+ if (v === "" || v === void 0) p.delete(k);
849
+ else p.set(k, v);
850
+ }
851
+ return p;
852
+ },
853
+ [searchParams]
854
+ );
855
+ const set = (0, import_react11.useCallback)(
856
+ (key, value) => {
857
+ const p = buildParams({ [key]: value });
858
+ if (!NON_RESETTING_KEYS.includes(key)) {
859
+ p.set("page", "1");
860
+ }
861
+ router.replace(`${pathname}?${p.toString()}`);
862
+ },
863
+ [buildParams, pathname, router]
864
+ );
865
+ const setMany = (0, import_react11.useCallback)(
866
+ (updates) => {
867
+ const p = buildParams(updates);
868
+ const keys = Object.keys(updates);
869
+ const allNonResetting = keys.every(
870
+ (k) => NON_RESETTING_KEYS.includes(k)
871
+ );
872
+ if (!allNonResetting && !keys.includes("page")) {
873
+ p.set("page", "1");
874
+ }
875
+ router.replace(`${pathname}?${p.toString()}`);
876
+ },
877
+ [buildParams, pathname, router]
878
+ );
879
+ const clear = (0, import_react11.useCallback)(
880
+ (keys) => {
881
+ if (keys) {
882
+ const p = new URLSearchParams(searchParams.toString());
883
+ keys.forEach((k) => p.delete(k));
884
+ p.set("page", "1");
885
+ router.replace(`${pathname}?${p.toString()}`);
886
+ } else {
887
+ router.replace(pathname);
888
+ }
889
+ },
890
+ [searchParams, pathname, router]
891
+ );
892
+ const setPage = (page) => set("page", String(page));
893
+ const setPageSize = (size) => set("pageSize", String(size));
894
+ const setSort = (sort) => set("sort", sort);
895
+ const buildSieveParams = (0, import_react11.useCallback)(
896
+ (sieveFilters) => {
897
+ const page = get("page") || "1";
898
+ const pageSize = get("pageSize") || defaults["pageSize"] || "25";
899
+ const sort = get("sort") || defaults["sort"] || "-createdAt";
900
+ const parts = new URLSearchParams();
901
+ if (sieveFilters) parts.set("filters", sieveFilters);
902
+ parts.set("sorts", sort);
903
+ parts.set("page", page);
904
+ parts.set("pageSize", pageSize);
905
+ return `?${parts.toString()}`;
906
+ },
907
+ [get, defaults]
908
+ );
909
+ const buildSearchParams = (0, import_react11.useCallback)(() => {
910
+ const p = new URLSearchParams();
911
+ const addIfPresent = (k) => {
912
+ const v = get(k);
913
+ if (v) p.set(k, v);
914
+ };
915
+ ["q", "category", "minPrice", "maxPrice"].forEach(addIfPresent);
916
+ p.set("sort", get("sort") || defaults["sort"] || "-createdAt");
917
+ p.set("page", get("page") || "1");
918
+ p.set("pageSize", get("pageSize") || defaults["pageSize"] || "24");
919
+ return `?${p.toString()}`;
920
+ }, [get, defaults]);
921
+ return {
922
+ params: searchParams,
923
+ get,
924
+ getNumber,
925
+ set,
926
+ setMany,
927
+ clear,
928
+ setPage,
929
+ setPageSize,
930
+ setSort,
931
+ buildSieveParams,
932
+ buildSearchParams
933
+ };
934
+ }
935
+
936
+ // src/hooks/usePendingFilters.ts
937
+ var import_react12 = require("react");
938
+ function usePendingFilters({
939
+ table,
940
+ keys
941
+ }) {
942
+ const parseValues = (0, import_react12.useCallback)(
943
+ (key) => {
944
+ const raw = table.get(key);
945
+ return raw ? raw.split(",").filter(Boolean) : [];
946
+ },
947
+ [table]
948
+ );
949
+ const [pending, setPending] = (0, import_react12.useState)(
950
+ () => Object.fromEntries(keys.map((k) => [k, parseValues(k)]))
951
+ );
952
+ const applied = (0, import_react12.useMemo)(
953
+ () => Object.fromEntries(keys.map((k) => [k, parseValues(k)])),
954
+ [keys, parseValues]
955
+ );
956
+ const pendingCount = (0, import_react12.useMemo)(
957
+ () => Object.values(pending).reduce((sum, arr) => sum + arr.length, 0),
958
+ [pending]
959
+ );
960
+ const appliedCount = (0, import_react12.useMemo)(
961
+ () => Object.values(applied).reduce((sum, arr) => sum + arr.length, 0),
962
+ [applied]
963
+ );
964
+ const isDirty = (0, import_react12.useMemo)(() => {
965
+ return keys.some((k) => {
966
+ var _a, _b;
967
+ const p = ((_a = pending[k]) != null ? _a : []).slice().sort();
968
+ const a = ((_b = applied[k]) != null ? _b : []).slice().sort();
969
+ return p.length !== a.length || p.some((v, i) => v !== a[i]);
970
+ });
971
+ }, [keys, pending, applied]);
972
+ const set = (0, import_react12.useCallback)((key, values) => {
973
+ setPending((prev) => __spreadProps(__spreadValues({}, prev), { [key]: values }));
974
+ }, []);
975
+ const apply = (0, import_react12.useCallback)(() => {
976
+ var _a;
977
+ const updates = { page: "1" };
978
+ for (const k of keys) {
979
+ updates[k] = ((_a = pending[k]) != null ? _a : []).join(",");
980
+ }
981
+ table.setMany(updates);
982
+ }, [keys, pending, table]);
983
+ const reset = (0, import_react12.useCallback)(() => {
984
+ setPending(Object.fromEntries(keys.map((k) => [k, parseValues(k)])));
985
+ }, [keys, parseValues]);
986
+ const clear = (0, import_react12.useCallback)(() => {
987
+ const empty = Object.fromEntries(keys.map((k) => [k, []]));
988
+ setPending(empty);
989
+ const updates = { page: "1" };
990
+ for (const k of keys) updates[k] = "";
991
+ table.setMany(updates);
992
+ }, [keys, table]);
993
+ return {
994
+ pending,
995
+ applied,
996
+ isDirty,
997
+ pendingCount,
998
+ appliedCount,
999
+ set,
1000
+ apply,
1001
+ reset,
1002
+ clear
1003
+ };
1004
+ }
1005
+
1006
+ // src/hooks/usePendingTable.ts
1007
+ var import_react13 = require("react");
1008
+ function usePendingTable(table, keys) {
1009
+ const filters = usePendingFilters({ table, keys });
1010
+ const pendingTable = (0, import_react13.useMemo)(
1011
+ () => ({
1012
+ get: (key) => {
1013
+ var _a, _b;
1014
+ return (_b = (_a = filters.pending[key]) == null ? void 0 : _a[0]) != null ? _b : "";
1015
+ },
1016
+ set: (key, value) => {
1017
+ filters.set(key, value ? [value] : []);
1018
+ },
1019
+ setMany: (updates) => {
1020
+ for (const [k, v] of Object.entries(updates)) {
1021
+ filters.set(k, v ? [v] : []);
1022
+ }
1023
+ }
1024
+ }),
1025
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1026
+ [filters.pending, filters.set]
1027
+ );
1028
+ return {
1029
+ pendingTable,
1030
+ filterActiveCount: filters.appliedCount,
1031
+ onFilterApply: filters.apply,
1032
+ onFilterClear: filters.clear
1033
+ };
1034
+ }
1035
+
1036
+ // src/hooks/useUnsavedChanges.ts
1037
+ var import_react14 = require("react");
1038
+ var UNSAVED_CHANGES_EVENT = "unsaved-changes:confirm";
1039
+ function useUnsavedChanges({
1040
+ formValues,
1041
+ initialValues,
1042
+ extraDirty = false,
1043
+ confirmFn,
1044
+ beforeUnloadWarning = "You have unsaved changes. Leave?"
1045
+ }) {
1046
+ const [savedSnapshot, setSavedSnapshot] = (0, import_react14.useState)(initialValues);
1047
+ const savedSnapshotRef = (0, import_react14.useRef)(savedSnapshot);
1048
+ savedSnapshotRef.current = savedSnapshot;
1049
+ (0, import_react14.useEffect)(() => {
1050
+ if (initialValues && !savedSnapshotRef.current) {
1051
+ setSavedSnapshot(initialValues);
1052
+ }
1053
+ }, [initialValues]);
1054
+ const isFormDirty = (() => {
1055
+ if (!savedSnapshot) return false;
1056
+ return Object.keys(formValues).some(
1057
+ (key) => {
1058
+ var _a, _b;
1059
+ return ((_a = formValues[key]) != null ? _a : "") !== ((_b = savedSnapshot[key]) != null ? _b : "");
1060
+ }
1061
+ );
1062
+ })();
1063
+ const isDirty = isFormDirty || extraDirty;
1064
+ (0, import_react14.useEffect)(() => {
1065
+ if (!isDirty) return;
1066
+ const handler = (e) => {
1067
+ e.preventDefault();
1068
+ e.returnValue = beforeUnloadWarning;
1069
+ return beforeUnloadWarning;
1070
+ };
1071
+ window.addEventListener("beforeunload", handler);
1072
+ return () => window.removeEventListener("beforeunload", handler);
1073
+ }, [isDirty, beforeUnloadWarning]);
1074
+ const markClean = (0, import_react14.useCallback)(() => {
1075
+ setSavedSnapshot(__spreadValues({}, formValues));
1076
+ }, [formValues]);
1077
+ const confirmLeave = (0, import_react14.useCallback)(() => {
1078
+ if (!isDirty) return Promise.resolve(true);
1079
+ if (confirmFn) return confirmFn();
1080
+ return Promise.resolve(
1081
+ window.confirm("You have unsaved changes. Leave without saving?")
1082
+ );
1083
+ }, [isDirty, confirmFn]);
1084
+ return { isDirty, isFormDirty, markClean, confirmLeave };
1085
+ }
1086
+
1087
+ // src/hooks/useBulkAction.ts
1088
+ var import_react15 = require("react");
1089
+ function useBulkAction(options) {
1090
+ const [isLoading, setIsLoading] = (0, import_react15.useState)(false);
1091
+ const [result, setResult] = (0, import_react15.useState)(null);
1092
+ const [error, setError] = (0, import_react15.useState)(null);
1093
+ const [pendingPayload, setPendingPayload] = (0, import_react15.useState)(null);
1094
+ const optionsRef = (0, import_react15.useRef)(options);
1095
+ optionsRef.current = options;
1096
+ const runMutation = (0, import_react15.useCallback)(async (payload) => {
1097
+ var _a, _b, _c, _d, _e;
1098
+ setIsLoading(true);
1099
+ setError(null);
1100
+ try {
1101
+ const res = await optionsRef.current.mutationFn(payload);
1102
+ setResult(res);
1103
+ await ((_b = (_a = optionsRef.current).onSuccess) == null ? void 0 : _b.call(_a, res, payload));
1104
+ } catch (err) {
1105
+ const error2 = err instanceof Error ? err : new Error((_c = err == null ? void 0 : err.message) != null ? _c : "Unexpected error");
1106
+ setError(error2);
1107
+ (_e = (_d = optionsRef.current).onError) == null ? void 0 : _e.call(_d, error2, payload);
1108
+ } finally {
1109
+ setIsLoading(false);
1110
+ }
1111
+ }, []);
1112
+ const execute = (0, import_react15.useCallback)(
1113
+ async (payload) => {
1114
+ if (optionsRef.current.requiresConfirm) {
1115
+ setPendingPayload(payload);
1116
+ return;
1117
+ }
1118
+ await runMutation(payload);
1119
+ },
1120
+ [runMutation]
1121
+ );
1122
+ const confirmAndExecute = (0, import_react15.useCallback)(async () => {
1123
+ if (!pendingPayload) return;
1124
+ const payload = pendingPayload;
1125
+ setPendingPayload(null);
1126
+ await runMutation(payload);
1127
+ }, [pendingPayload, runMutation]);
1128
+ const cancelConfirm = (0, import_react15.useCallback)(() => setPendingPayload(null), []);
1129
+ const reset = (0, import_react15.useCallback)(() => {
1130
+ setResult(null);
1131
+ setError(null);
1132
+ setPendingPayload(null);
1133
+ }, []);
1134
+ return {
1135
+ execute,
1136
+ isLoading,
1137
+ result,
1138
+ error,
1139
+ reset,
1140
+ pendingPayload,
1141
+ confirmAndExecute,
1142
+ cancelConfirm
1143
+ };
1144
+ }
746
1145
  // Annotate the CommonJS export names for ESM import in node:
747
1146
  0 && (module.exports = {
1147
+ UNSAVED_CHANGES_EVENT,
748
1148
  useBreakpoint,
1149
+ useBulkAction,
1150
+ useBulkSelection,
749
1151
  useCamera,
750
1152
  useClickOutside,
751
1153
  useCountdown,
@@ -753,6 +1155,10 @@ function useCamera() {
753
1155
  useKeyPress,
754
1156
  useLongPress,
755
1157
  useMediaQuery,
1158
+ usePendingFilters,
1159
+ usePendingTable,
756
1160
  usePullToRefresh,
757
- useSwipe
1161
+ useSwipe,
1162
+ useUnsavedChanges,
1163
+ useUrlTable
758
1164
  });