@amoa/hooks 0.1.2 → 0.1.4

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.
@@ -0,0 +1,7 @@
1
+ const format = (value, options) => {
2
+ const date = new Date(value);
3
+ if (isNaN(date.getTime())) return value;
4
+ return date.toLocaleDateString("fr-FR", options);
5
+ };
6
+
7
+ export { format };
@@ -0,0 +1,11 @@
1
+ import { format } from './date.js';
2
+
3
+ const dayOfMonth = value => {
4
+ const options = {
5
+ month: "long",
6
+ day: "numeric"
7
+ };
8
+ return format(value, options);
9
+ };
10
+
11
+ export { dayOfMonth };
@@ -0,0 +1,8 @@
1
+ import './year.js';
2
+
3
+ const valid = arg => {
4
+ const date = new Date(arg);
5
+ return !isNaN(date.getTime());
6
+ };
7
+
8
+ export { valid };
@@ -0,0 +1 @@
1
+ new Date().getFullYear();
@@ -0,0 +1,71 @@
1
+ import { serialize, extract, transform } from './strings/index.js';
2
+
3
+ const dates = (data, key, filter) => {
4
+ const {
5
+ before,
6
+ after
7
+ } = filter;
8
+ const preceding = before ? before > new Date(data[key]) : true;
9
+ const following = after ? after < new Date(data[key]) : true;
10
+ return preceding && following;
11
+ };
12
+ const search = (data, search) => {
13
+ if (!search) return data;
14
+ const words = serialize(search).split("-").filter(Boolean);
15
+ const {
16
+ precise,
17
+ shallow
18
+ } = data.reduce((acc, data) => {
19
+ const flattened = extract(data);
20
+ const transform$1 = transform(flattened);
21
+ const precise = serialize(transform$1).includes(serialize(search));
22
+ const shallow = words.filter(item => serialize(transform$1.join(" ")).includes(item));
23
+ if (precise) return {
24
+ ...acc,
25
+ precise: [...acc.precise, data]
26
+ };
27
+ if (shallow.length) return {
28
+ ...acc,
29
+ shallow: [...acc.shallow, data]
30
+ };
31
+ return acc;
32
+ }, {
33
+ precise: [],
34
+ shallow: []
35
+ });
36
+ return precise.length ? precise : shallow;
37
+ };
38
+ const filter = (data, filters, reference) => {
39
+ if (!Object.keys(filters).length) return data;
40
+ return data.reduce((acc, item) => {
41
+ const check = Object.entries(filters).every(([key, list]) => {
42
+ if (Array.isArray(list)) {
43
+ const {
44
+ together
45
+ } = reference?.find(filter => filter.key = key) || {};
46
+ const flat = list.map(value => together?.[value] || value).flat();
47
+ return flat.includes(item[key]);
48
+ }
49
+ if (typeof list === "object") {
50
+ const {
51
+ kind,
52
+ ...filter
53
+ } = list;
54
+ if (kind === "dates") return dates(item, key, filter);
55
+ }
56
+ });
57
+ return check ? [...acc, item] : acc;
58
+ }, []);
59
+ };
60
+ const sort = (data, {
61
+ key,
62
+ direction,
63
+ order
64
+ }) => {
65
+ return data.toSorted((a, b) => {
66
+ if (!order) return a[key] < b[key] === direction ? -1 : 1;
67
+ return order.indexOf(a[key]) < order.indexOf(b[key]) === direction ? -1 : 1;
68
+ });
69
+ };
70
+
71
+ export { filter, search, sort };
@@ -0,0 +1,20 @@
1
+ const throttle = (callback, delay = 300) => {
2
+ let last = 0;
3
+ let timeout = null;
4
+ return (...args) => {
5
+ const now = Date.now();
6
+ if (now - last >= delay) {
7
+ last = now;
8
+ callback(...args);
9
+ } else if (!timeout) {
10
+ const remaining = delay - (now - last);
11
+ timeout = setTimeout(() => {
12
+ last = Date.now();
13
+ timeout = null;
14
+ callback(...args);
15
+ }, remaining);
16
+ }
17
+ };
18
+ };
19
+
20
+ export { throttle };
@@ -0,0 +1,261 @@
1
+ const DIACRITICS_REMOVAL_MAP = [{
2
+ base: "A",
3
+ letters: "\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F"
4
+ }, {
5
+ base: "AA",
6
+ letters: "\uA732"
7
+ }, {
8
+ base: "AE",
9
+ letters: "\u00C6\u01FC\u01E2"
10
+ }, {
11
+ base: "AO",
12
+ letters: "\uA734"
13
+ }, {
14
+ base: "AU",
15
+ letters: "\uA736"
16
+ }, {
17
+ base: "AV",
18
+ letters: "\uA738\uA73A"
19
+ }, {
20
+ base: "AY",
21
+ letters: "\uA73C"
22
+ }, {
23
+ base: "B",
24
+ letters: "\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181"
25
+ }, {
26
+ base: "C",
27
+ letters: "\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E"
28
+ }, {
29
+ base: "D",
30
+ letters: "\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779\u00D0"
31
+ }, {
32
+ base: "DZ",
33
+ letters: "\u01F1\u01C4"
34
+ }, {
35
+ base: "Dz",
36
+ letters: "\u01F2\u01C5"
37
+ }, {
38
+ base: "E",
39
+ letters: "\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E"
40
+ }, {
41
+ base: "F",
42
+ letters: "\u0046\u24BB\uFF26\u1E1E\u0191\uA77B"
43
+ }, {
44
+ base: "G",
45
+ letters: "\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E"
46
+ }, {
47
+ base: "H",
48
+ letters: "\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D"
49
+ }, {
50
+ base: "I",
51
+ letters: "\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197"
52
+ }, {
53
+ base: "J",
54
+ letters: "\u004A\u24BF\uFF2A\u0134\u0248"
55
+ }, {
56
+ base: "K",
57
+ letters: "\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2"
58
+ }, {
59
+ base: "L",
60
+ letters: "\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780"
61
+ }, {
62
+ base: "LJ",
63
+ letters: "\u01C7"
64
+ }, {
65
+ base: "Lj",
66
+ letters: "\u01C8"
67
+ }, {
68
+ base: "M",
69
+ letters: "\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C"
70
+ }, {
71
+ base: "N",
72
+ letters: "\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4"
73
+ }, {
74
+ base: "NJ",
75
+ letters: "\u01CA"
76
+ }, {
77
+ base: "Nj",
78
+ letters: "\u01CB"
79
+ }, {
80
+ base: "O",
81
+ letters: "\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C"
82
+ }, {
83
+ base: "OI",
84
+ letters: "\u01A2"
85
+ }, {
86
+ base: "OO",
87
+ letters: "\uA74E"
88
+ }, {
89
+ base: "OU",
90
+ letters: "\u0222"
91
+ }, {
92
+ base: "OE",
93
+ letters: "\u008C\u0152"
94
+ }, {
95
+ base: "oe",
96
+ letters: "\u009C\u0153"
97
+ }, {
98
+ base: "P",
99
+ letters: "\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754"
100
+ }, {
101
+ base: "Q",
102
+ letters: "\u0051\u24C6\uFF31\uA756\uA758\u024A"
103
+ }, {
104
+ base: "R",
105
+ letters: "\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782"
106
+ }, {
107
+ base: "S",
108
+ letters: "\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784"
109
+ }, {
110
+ base: "T",
111
+ letters: "\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786"
112
+ }, {
113
+ base: "TZ",
114
+ letters: "\uA728"
115
+ }, {
116
+ base: "U",
117
+ letters: "\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244"
118
+ }, {
119
+ base: "V",
120
+ letters: "\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245"
121
+ }, {
122
+ base: "VY",
123
+ letters: "\uA760"
124
+ }, {
125
+ base: "W",
126
+ letters: "\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72"
127
+ }, {
128
+ base: "X",
129
+ letters: "\u0058\u24CD\uFF38\u1E8A\u1E8C"
130
+ }, {
131
+ base: "Y",
132
+ letters: "\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE"
133
+ }, {
134
+ base: "Z",
135
+ letters: "\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762"
136
+ }, {
137
+ base: "a",
138
+ letters: "\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250"
139
+ }, {
140
+ base: "aa",
141
+ letters: "\uA733"
142
+ }, {
143
+ base: "ae",
144
+ letters: "\u00E6\u01FD\u01E3"
145
+ }, {
146
+ base: "ao",
147
+ letters: "\uA735"
148
+ }, {
149
+ base: "au",
150
+ letters: "\uA737"
151
+ }, {
152
+ base: "av",
153
+ letters: "\uA739\uA73B"
154
+ }, {
155
+ base: "ay",
156
+ letters: "\uA73D"
157
+ }, {
158
+ base: "b",
159
+ letters: "\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253"
160
+ }, {
161
+ base: "c",
162
+ letters: "\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184"
163
+ }, {
164
+ base: "d",
165
+ letters: "\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A"
166
+ }, {
167
+ base: "dz",
168
+ letters: "\u01F3\u01C6"
169
+ }, {
170
+ base: "e",
171
+ letters: "\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD"
172
+ }, {
173
+ base: "f",
174
+ letters: "\u0066\u24D5\uFF46\u1E1F\u0192\uA77C"
175
+ }, {
176
+ base: "g",
177
+ letters: "\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F"
178
+ }, {
179
+ base: "h",
180
+ letters: "\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265"
181
+ }, {
182
+ base: "hv",
183
+ letters: "\u0195"
184
+ }, {
185
+ base: "i",
186
+ letters: "\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131"
187
+ }, {
188
+ base: "j",
189
+ letters: "\u006A\u24D9\uFF4A\u0135\u01F0\u0249"
190
+ }, {
191
+ base: "k",
192
+ letters: "\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3"
193
+ }, {
194
+ base: "l",
195
+ letters: "\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747"
196
+ }, {
197
+ base: "lj",
198
+ letters: "\u01C9"
199
+ }, {
200
+ base: "m",
201
+ letters: "\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F"
202
+ }, {
203
+ base: "n",
204
+ letters: "\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5"
205
+ }, {
206
+ base: "nj",
207
+ letters: "\u01CC"
208
+ }, {
209
+ base: "o",
210
+ letters: "\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275"
211
+ }, {
212
+ base: "oi",
213
+ letters: "\u01A3"
214
+ }, {
215
+ base: "ou",
216
+ letters: "\u0223"
217
+ }, {
218
+ base: "oo",
219
+ letters: "\uA74F"
220
+ }, {
221
+ base: "p",
222
+ letters: "\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755"
223
+ }, {
224
+ base: "q",
225
+ letters: "\u0071\u24E0\uFF51\u024B\uA757\uA759"
226
+ }, {
227
+ base: "r",
228
+ letters: "\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783"
229
+ }, {
230
+ base: "s",
231
+ letters: "\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B"
232
+ }, {
233
+ base: "t",
234
+ letters: "\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787"
235
+ }, {
236
+ base: "tz",
237
+ letters: "\uA729"
238
+ }, {
239
+ base: "u",
240
+ letters: "\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289"
241
+ }, {
242
+ base: "v",
243
+ letters: "\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C"
244
+ }, {
245
+ base: "vy",
246
+ letters: "\uA761"
247
+ }, {
248
+ base: "w",
249
+ letters: "\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73"
250
+ }, {
251
+ base: "x",
252
+ letters: "\u0078\u24E7\uFF58\u1E8B\u1E8D"
253
+ }, {
254
+ base: "y",
255
+ letters: "\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF"
256
+ }, {
257
+ base: "z",
258
+ letters: "\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763"
259
+ }];
260
+
261
+ export { DIACRITICS_REMOVAL_MAP as default };
@@ -0,0 +1,56 @@
1
+ import { valid } from '../dates/index.js';
2
+ import DIACRITICS_REMOVAL_MAP from './diacritics.js';
3
+ import { format } from '../dates/date.js';
4
+ import { dayOfMonth } from '../dates/day.js';
5
+
6
+ const diacritics = DIACRITICS_REMOVAL_MAP.reduce((acc, {
7
+ base,
8
+ letters
9
+ }) => {
10
+ const range = [...letters].reduce((acc, letter) => {
11
+ return {
12
+ ...acc,
13
+ [letter]: base
14
+ };
15
+ }, {});
16
+ return {
17
+ ...acc,
18
+ ...range
19
+ };
20
+ }, {});
21
+ const serialize = (...strings) => {
22
+ const flattened = strings.reduce((acc, current) => {
23
+ switch (typeof current) {
24
+ case "string":
25
+ return current.trim() !== "" ? [...acc, current] : acc;
26
+ case "number":
27
+ return acc;
28
+ case "object":
29
+ return [...acc, Object.values(current).join("-")];
30
+ }
31
+ }, []);
32
+ return flattened.join("-").replace(/[^\u0000-\u007E]/g, letter => diacritics[letter] || letter).replace(/[.,\/#!$%\^&\*;:{}=_`~()]/g, "").replace(/[^a-zA-Z0-9]+/g, "-").replace(/\s{2,}/g, " ").replace(/\s/g, "-").toLowerCase();
33
+ };
34
+ const extract = data => {
35
+ if (data === null) return [];
36
+ switch (typeof data) {
37
+ case "string":
38
+ case "number":
39
+ return [data];
40
+ case "object":
41
+ const iterable = Array.isArray(data) ? data : Object.values(data);
42
+ return iterable.reduce((acc, item) => [...acc, ...extract(item)], []);
43
+ }
44
+ return [];
45
+ };
46
+ const transform = (...args) => {
47
+ const result = args.flatMap(arg => {
48
+ if (Array.isArray(arg)) return arg.map(item => transform(item));
49
+ if (typeof arg === "number") return `${arg}`;
50
+ if (valid(arg)) return [format(arg), dayOfMonth(arg)];
51
+ return serialize(arg);
52
+ });
53
+ return result.flat();
54
+ };
55
+
56
+ export { extract, serialize, transform };
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { default as useLocalStorage } from './use-local-storage.js';
2
+ export { default as useSessionStorage } from './use-session-storage.js';
@@ -1,34 +1,28 @@
1
- import * as React from "react";
1
+ import * as React from 'react';
2
2
 
3
- export const useClickOutside = (callback) => {
3
+ const useClickOutside = callback => {
4
4
  const ref = React.useRef(null);
5
5
  const callbackRef = React.useRef(callback);
6
-
7
6
  React.useLayoutEffect(() => {
8
7
  callbackRef.current = callback;
9
8
  });
10
-
11
9
  React.useEffect(() => {
12
10
  if (ref.current) {
13
11
  const element = ref.current.parentNode;
14
-
15
- const handler = (e) => {
12
+ const handler = e => {
16
13
  if (element && !element.contains(e.target)) {
17
14
  callbackRef.current(e);
18
15
  }
19
16
  };
20
-
21
17
  document.addEventListener("mousedown", handler);
22
18
  document.addEventListener("touchstart", handler);
23
-
24
19
  return () => {
25
20
  document.removeEventListener("mousedown", handler);
26
21
  document.removeEventListener("touchstart", handler);
27
22
  };
28
23
  }
29
24
  }, []);
30
-
31
25
  return ref;
32
26
  };
33
27
 
34
- export default useClickOutside;
28
+ export { useClickOutside as default, useClickOutside };
@@ -1,13 +1,11 @@
1
- import * as React from "react";
1
+ import * as React from 'react';
2
2
 
3
- export const useClient = () => {
3
+ const useClient = () => {
4
4
  const [client, setClient] = React.useState(false);
5
-
6
5
  React.useEffect(() => {
7
6
  setClient(true);
8
7
  }, []);
9
-
10
8
  return client;
11
9
  };
12
10
 
13
- export default useClient;
11
+ export { useClient as default, useClient };
@@ -1,11 +1,9 @@
1
- import * as React from "react";
1
+ import * as React from 'react';
2
2
 
3
- export const useDebounce = (callback, time = 300, minimum = 3) => {
3
+ const useDebounce = (callback, time = 300, minimum = 3) => {
4
4
  const [value, setValue] = React.useState("");
5
5
  const [result, setResult] = React.useState();
6
-
7
6
  const clear = () => setResult();
8
-
9
7
  React.useEffect(() => {
10
8
  // setResult();
11
9
  if (typeof value !== "string" || value.length < minimum) return;
@@ -13,11 +11,9 @@ export const useDebounce = (callback, time = 300, minimum = 3) => {
13
11
  const result = await callback(value);
14
12
  setResult(result);
15
13
  }, time);
16
-
17
14
  return () => clearTimeout(delay);
18
15
  }, [value]);
19
-
20
16
  return [result, setValue, clear];
21
17
  };
22
18
 
23
- export default useDebounce;
19
+ export { useDebounce as default, useDebounce };
@@ -1,12 +1,10 @@
1
- import * as React from "react";
1
+ import * as React from 'react';
2
2
 
3
- export const useDragging = (callback, delay, state, layoff) => {
3
+ const useDragging = (callback, delay, state, layoff) => {
4
4
  const savedCallback = React.useRef();
5
-
6
5
  React.useEffect(() => {
7
6
  savedCallback.state = callback;
8
7
  }, [callback]);
9
-
10
8
  React.useEffect(() => {
11
9
  function tick() {
12
10
  savedCallback.state();
@@ -18,4 +16,4 @@ export const useDragging = (callback, delay, state, layoff) => {
18
16
  }, [state, delay, layoff]);
19
17
  };
20
18
 
21
- export default useDragging;
19
+ export { useDragging as default, useDragging };
@@ -0,0 +1,20 @@
1
+ import * as React from 'react';
2
+ import { search, filter, sort } from './forge/src/filters.js';
3
+
4
+ const useFilters = (data, filters, sort$1, reference) => {
5
+ const [filtered, setFiltered] = React.useState(data);
6
+ const {
7
+ search: search$1,
8
+ ...other
9
+ } = filters;
10
+ React.useEffect(() => {
11
+ if (!search$1 && !Object.keys(other).length) setFiltered(data);
12
+ const searched = search(data, search$1);
13
+ const filtered = filter(searched, other, reference);
14
+ const sorted = sort(filtered, sort$1);
15
+ setFiltered(sorted);
16
+ }, [data, filters, sort$1]);
17
+ return filtered;
18
+ };
19
+
20
+ export { useFilters as default, useFilters };
@@ -0,0 +1,26 @@
1
+ import * as React from 'react';
2
+
3
+ const useHover = () => {
4
+ const [hovering, setHovering] = React.useState(false);
5
+ const previousNode = React.useRef(null);
6
+ const handleMouseEnter = React.useCallback(() => {
7
+ setHovering(true);
8
+ }, []);
9
+ const handleMouseLeave = React.useCallback(() => {
10
+ setHovering(false);
11
+ }, []);
12
+ const customRef = React.useCallback(node => {
13
+ if (previousNode.current?.nodeType === Node.ELEMENT_NODE) {
14
+ previousNode.current.removeEventListener("mouseenter", handleMouseEnter);
15
+ previousNode.current.removeEventListener("mouseleave", handleMouseLeave);
16
+ }
17
+ if (node?.nodeType === Node.ELEMENT_NODE) {
18
+ node.addEventListener("mouseenter", handleMouseEnter);
19
+ node.addEventListener("mouseleave", handleMouseLeave);
20
+ }
21
+ previousNode.current = node;
22
+ }, [handleMouseEnter, handleMouseLeave]);
23
+ return [customRef, hovering];
24
+ };
25
+
26
+ export { useHover as default, useHover };
@@ -0,0 +1,39 @@
1
+ import * as React from 'react';
2
+
3
+ const OPTIONS = {
4
+ threshold: 1,
5
+ root: null,
6
+ rootMargin: "0px"
7
+ };
8
+ const useIntersection = (options = {}) => {
9
+ const [entry, setEntry] = React.useState(null);
10
+ const {
11
+ threshold,
12
+ root,
13
+ rootMargin
14
+ } = {
15
+ ...OPTIONS,
16
+ ...options
17
+ };
18
+ const reference = React.useRef(null);
19
+ const ref = React.useCallback(node => {
20
+ if (reference.current) {
21
+ reference.current.disconnect();
22
+ reference.current = null;
23
+ }
24
+ if (node?.nodeType === Node.ELEMENT_NODE) {
25
+ const observer = new IntersectionObserver(([entry]) => {
26
+ setEntry(entry);
27
+ }, {
28
+ threshold,
29
+ root,
30
+ rootMargin
31
+ });
32
+ observer.observe(node);
33
+ reference.current = observer;
34
+ }
35
+ }, [threshold, root, rootMargin]);
36
+ return [ref, entry];
37
+ };
38
+
39
+ export { useIntersection as default, useIntersection };
@@ -1,19 +1,14 @@
1
- "use client";
1
+ import * as React from 'react';
2
2
 
3
- import * as React from "react";
4
-
5
- export const useInterval = (callback, delay) => {
3
+ const useInterval = (callback, delay) => {
6
4
  const [id, setId] = React.useState();
7
5
  const savedCallback = React.useRef();
8
-
9
6
  const clear = () => {
10
7
  clearInterval(id);
11
8
  };
12
-
13
9
  React.useEffect(() => {
14
10
  savedCallback.current = callback;
15
11
  }, [callback]);
16
-
17
12
  React.useEffect(() => {
18
13
  function tick() {
19
14
  savedCallback.current();
@@ -24,8 +19,7 @@ export const useInterval = (callback, delay) => {
24
19
  return () => clearInterval(id);
25
20
  }
26
21
  }, [delay]);
27
-
28
22
  return [clear];
29
23
  };
30
24
 
31
- export default useInterval;
25
+ export { useInterval as default, useInterval };
@@ -0,0 +1,19 @@
1
+ import * as React from 'react';
2
+ import { throttle } from './forge/src/functions/index.js';
3
+
4
+ const OPTIONS = {
5
+ rootMargin: "200px 0px",
6
+ threshold: 0.1
7
+ };
8
+ const useLazyLoading = (ref, callback, delay = 300) => {
9
+ const throttle$1 = React.useMemo(() => throttle(callback, delay), [callback, delay]);
10
+ React.useEffect(() => {
11
+ const node = ref.current;
12
+ if (!node) return;
13
+ const observer = new IntersectionObserver(([e]) => e.isIntersecting && throttle$1(), OPTIONS);
14
+ observer.observe(node);
15
+ return () => observer.disconnect();
16
+ }, [ref.current, callback]);
17
+ };
18
+
19
+ export { useLazyLoading as default, useLazyLoading };
@@ -1,6 +1,6 @@
1
- import { useState, useEffect } from "react";
1
+ import { useState, useEffect } from 'react';
2
2
 
3
- export const useLocalStorage = (key, initialValue, session = false) => {
3
+ const useLocalStorage = (key, initialValue, session = false) => {
4
4
  const [storedValue, setStoredValue] = useState(() => {
5
5
  if (typeof window !== "undefined") {
6
6
  try {
@@ -12,8 +12,7 @@ export const useLocalStorage = (key, initialValue, session = false) => {
12
12
  }
13
13
  }
14
14
  });
15
-
16
- const setValue = (value) => {
15
+ const setValue = value => {
17
16
  if (typeof window === "undefined") return [];
18
17
  try {
19
18
  const valueToStore = value instanceof Function ? value(storedValue) : value;
@@ -37,7 +36,6 @@ export const useLocalStorage = (key, initialValue, session = false) => {
37
36
  console.info(error);
38
37
  }
39
38
  };
40
-
41
39
  useEffect(() => {
42
40
  const check = () => {
43
41
  const value = window.localStorage.getItem(key);
@@ -46,8 +44,7 @@ export const useLocalStorage = (key, initialValue, session = false) => {
46
44
  window.addEventListener(key, check);
47
45
  return () => window.removeEventListener(key, check);
48
46
  }, []);
49
-
50
47
  return [storedValue, setValue];
51
48
  };
52
49
 
53
- export default useLocalStorage;
50
+ export { useLocalStorage as default, useLocalStorage };
@@ -1,28 +1,24 @@
1
- import * as React from "react";
1
+ import * as React from 'react';
2
2
 
3
- export const useResize = () => {
3
+ const useResize = () => {
4
4
  const [size, setSize] = React.useState({
5
5
  width: null,
6
6
  height: null
7
7
  });
8
-
9
8
  const resize = React.useCallback(() => {
10
9
  setSize({
11
10
  width: window.innerWidth,
12
11
  height: window.innerHeight
13
12
  });
14
13
  }, []);
15
-
16
14
  React.useLayoutEffect(() => {
17
15
  resize();
18
16
  window.addEventListener("resize", resize);
19
-
20
17
  return () => {
21
18
  window.removeEventListener("resize", resize);
22
19
  };
23
20
  }, [resize]);
24
-
25
21
  return size;
26
22
  };
27
23
 
28
- export default useResize;
24
+ export { useResize as default, useResize };
@@ -1,66 +1,53 @@
1
- import * as React from "react";
1
+ import * as React from 'react';
2
2
 
3
3
  const dispatchEvent = (key, newValue) => {
4
- window.dispatchEvent(new StorageEvent("storage", { key, newValue }));
4
+ window.dispatchEvent(new StorageEvent("storage", {
5
+ key,
6
+ newValue
7
+ }));
5
8
  };
6
-
7
9
  const setSessionStorageItem = (key, value) => {
8
10
  const stringifiedValue = JSON.stringify(value);
9
11
  window.sessionStorage.setItem(key, stringifiedValue);
10
12
  dispatchEvent(key, stringifiedValue);
11
13
  };
12
-
13
- const removeSessionStorageItem = (key) => {
14
+ const removeSessionStorageItem = key => {
14
15
  window.sessionStorage.removeItem(key);
15
16
  dispatchEvent(key, null);
16
17
  };
17
-
18
- const getSessionStorageItem = (key) => {
18
+ const getSessionStorageItem = key => {
19
19
  return window.sessionStorage.getItem(key);
20
20
  };
21
-
22
- const useSessionStorageSubscribe = (callback) => {
21
+ const useSessionStorageSubscribe = callback => {
23
22
  window.addEventListener("storage", callback);
24
23
  return () => window.removeEventListener("storage", callback);
25
24
  };
26
-
27
25
  const getSessionStorageServerSnapshot = () => {
28
26
  // throw Error("Le Session Storage n'est utilisable que côté client.");
29
27
  };
30
-
31
- export const useSessionStorage = (key, initialValue, fallback) => {
28
+ const useSessionStorage = (key, initialValue, fallback) => {
32
29
  const getClientSnapshot = () => getSessionStorageItem(key);
33
-
34
30
  const getServerSnapshot = fallback !== undefined ? () => fallback : undefined;
35
-
36
31
  const getSnapshot = typeof window !== "undefined" ? getClientSnapshot : getServerSnapshot;
37
-
38
32
  const store = React.useSyncExternalStore(useSessionStorageSubscribe, getSnapshot, getSessionStorageServerSnapshot);
39
-
40
- const setState = React.useCallback(
41
- (callback) => {
42
- try {
43
- const nextState = typeof callback === "function" ? callback(JSON.parse(store)) : callback;
44
-
45
- if (nextState === undefined || nextState === null) {
46
- removeSessionStorageItem(key);
47
- } else {
48
- setSessionStorageItem(key, nextState);
49
- }
50
- } catch (e) {
51
- console.warn(e);
33
+ const setState = React.useCallback(callback => {
34
+ try {
35
+ const nextState = typeof callback === "function" ? callback(JSON.parse(store)) : callback;
36
+ if (nextState === undefined || nextState === null) {
37
+ removeSessionStorageItem(key);
38
+ } else {
39
+ setSessionStorageItem(key, nextState);
52
40
  }
53
- },
54
- [key, store]
55
- );
56
-
41
+ } catch (e) {
42
+ console.warn(e);
43
+ }
44
+ }, [key, store]);
57
45
  React.useEffect(() => {
58
46
  if (getSessionStorageItem(key) === null && typeof initialValue !== "undefined") {
59
47
  setSessionStorageItem(key, initialValue);
60
48
  }
61
49
  }, [key, initialValue]);
62
-
63
50
  return [store ? JSON.parse(store) : initialValue, setState];
64
51
  };
65
52
 
66
- export default useSessionStorage;
53
+ export { useSessionStorage as default, useSessionStorage };
@@ -1,34 +1,35 @@
1
- import * as React from "react";
1
+ import * as React from 'react';
2
2
 
3
- const OBSERVER = { childList: true, subtree: true, characterData: true };
4
-
5
- const leaves = (node) => {
3
+ const OBSERVER = {
4
+ childList: true,
5
+ subtree: true,
6
+ characterData: true
7
+ };
8
+ const leaves = node => {
6
9
  if (!node) return [];
7
-
8
- const { children } = node;
9
- const list = Array.from(children).filter((child) => child.tagName !== "svg" || child?.remove());
10
- const { length } = list;
11
-
10
+ const {
11
+ children
12
+ } = node;
13
+ const list = Array.from(children).filter(child => child.tagName !== "svg" || child?.remove());
14
+ const {
15
+ length
16
+ } = list;
12
17
  if (length) return list.reduce((acc, node) => [...acc, ...leaves(node)], []);
13
-
14
18
  const width = 80; // (Math.ceil(Math.random() * 4) + 4) * 10;
15
19
  const min = 50; // (Math.ceil(Math.random() * 3) + 4) * 10;
16
20
 
17
21
  if (node.style.backgroundColor !== null) node.style.backgroundColor = "var(--light-background)";
18
22
  if (node.style.borderRadius === "") node.style.borderRadius = "4px";
19
-
20
23
  node.style.display = "flex";
21
24
  node.style.flexDirection = "column";
22
25
  node.style.borderColor = "transparent";
23
26
  node.style.gap = "0.5px";
24
27
  node.innerHTML = `<span style='min-width:${min}px;width:${width}%;height:14.5px;margin:0.5px 0;background-color:var(--light-background);border-radius:4px;' />`;
25
28
  node.parentNode.style.gap = "1.5px";
26
-
27
29
  return [node];
28
30
  };
29
-
30
- const excarnate = (element) => {
31
- Array.from(element).forEach((child) => {
31
+ const excarnate = element => {
32
+ Array.from(element).forEach(child => {
32
33
  child.style.borderColor = "transparent";
33
34
  child.style.filter = "unset";
34
35
  child.style.cursor = "default";
@@ -36,19 +37,20 @@ const excarnate = (element) => {
36
37
  child.classList.add("skeleton");
37
38
  });
38
39
  };
39
-
40
- export const useSkeleton = (ref) => {
40
+ const useSkeleton = ref => {
41
41
  React.useEffect(() => {
42
42
  if (!ref.current) return;
43
-
44
43
  excarnate(ref.current.children);
45
44
  leaves(ref.current);
46
-
47
- const observer = new MutationObserver((mutations) => {
45
+ const observer = new MutationObserver(mutations => {
48
46
  observer.disconnect();
49
- mutations.forEach(({ addedNodes = [], type, target }) => {
47
+ mutations.forEach(({
48
+ addedNodes = [],
49
+ type,
50
+ target
51
+ }) => {
50
52
  const parent = target.parentElement;
51
- addedNodes.forEach?.((node) => {
53
+ addedNodes.forEach?.(node => {
52
54
  if (node.nodeType === 1) {
53
55
  excarnate([node]);
54
56
  leaves(node);
@@ -61,11 +63,9 @@ export const useSkeleton = (ref) => {
61
63
  });
62
64
  observer.observe(ref.current, OBSERVER);
63
65
  });
64
-
65
66
  observer.observe(ref.current, OBSERVER);
66
-
67
67
  return () => observer.disconnect();
68
68
  }, [ref.current]);
69
69
  };
70
70
 
71
- export default useSkeleton;
71
+ export { useSkeleton as default, useSkeleton };
@@ -0,0 +1,35 @@
1
+ import * as React from 'react';
2
+
3
+ const surface = ({
4
+ width,
5
+ height
6
+ }) => width * height;
7
+ const useSummary = (elements = [], options = {}, target) => {
8
+ const {
9
+ threshold = 1,
10
+ root = null,
11
+ rootMargin = "0px"
12
+ } = options;
13
+ const [visible, setVisible] = React.useState(null);
14
+ const reference = React.useRef(null);
15
+ React.useEffect(() => {
16
+ if (!elements.length) return;
17
+ const observer = new IntersectionObserver(entries => {
18
+ const [first] = entries.sort((a, b) => surface(b.intersectionRect) - surface(a.intersectionRect));
19
+ if (first?.intersectionRect.height > 0) {
20
+ setVisible(target(first));
21
+ }
22
+ }, {
23
+ threshold,
24
+ root,
25
+ rootMargin
26
+ });
27
+ reference.current?.disconnect();
28
+ elements.forEach(element => observer.observe(element));
29
+ reference.current = observer;
30
+ return () => observer.disconnect();
31
+ }, [elements, threshold, root, rootMargin, target]);
32
+ return visible;
33
+ };
34
+
35
+ export { useSummary as default, useSummary };
@@ -1,18 +1,15 @@
1
- import * as React from "react";
1
+ import * as React from 'react';
2
2
 
3
- export const useTimeout = (callback, time) => {
3
+ const useTimeout = (callback, time) => {
4
4
  const id = React.useRef(null);
5
-
6
5
  const clear = React.useCallback(() => {
7
6
  window.clearTimeout(id.current);
8
7
  }, []);
9
-
10
8
  React.useEffect(() => {
11
9
  id.current = window.setTimeout(callback, time);
12
10
  return clear;
13
11
  }, [time, clear]);
14
-
15
12
  return clear;
16
13
  };
17
14
 
18
- export default useTimeout;
15
+ export { useTimeout as default, useTimeout };
@@ -1,4 +1,4 @@
1
- import * as React from "react";
1
+ import * as React from 'react';
2
2
 
3
3
  const limits = {
4
4
  top: 60,
@@ -6,11 +6,15 @@ const limits = {
6
6
  right: 60,
7
7
  left: 60
8
8
  };
9
-
10
- export const useTooltip = (item, text, position) => {
9
+ const useTooltip = (item, text, position) => {
11
10
  React.useEffect(() => {
12
11
  if (text && item.current) {
13
- const { top, left, bottom, right } = item.current.getBoundingClientRect();
12
+ const {
13
+ top,
14
+ left,
15
+ bottom,
16
+ right
17
+ } = item.current.getBoundingClientRect();
14
18
  item.current.dataset.tooltip = text;
15
19
  if (position) item.current.dataset[position] = "";
16
20
  if (top < limits.top) item.current.dataset.tooltipTop = "";
@@ -21,4 +25,4 @@ export const useTooltip = (item, text, position) => {
21
25
  }, [item, text]);
22
26
  };
23
27
 
24
- export default useTooltip;
28
+ export { useTooltip as default, useTooltip };
package/package.json CHANGED
@@ -1,16 +1,20 @@
1
1
  {
2
2
  "name": "@amoa/hooks",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
+ "files": [
8
+ "dist"
9
+ ],
7
10
  "scripts": {
8
- "build": "webpack",
9
- "dev": "webpack",
11
+ "dev": "rollup --watch",
12
+ "build": "rollup",
10
13
  "clean": "rm -rf dist"
11
14
  },
12
15
  "exports": {
13
- "./*": "./dist/*.js"
16
+ ".": "./dist/index.js",
17
+ "./*": "./dist/*"
14
18
  },
15
19
  "dependencies": {
16
20
  "@amoa/forge": "^0.1.0"
package/index.js DELETED
@@ -1,2 +0,0 @@
1
- export { useLocalStorage } from "./src/use-local-storage";
2
- export { useSessionStorage } from "./src/use-session-storage";
@@ -1,20 +0,0 @@
1
- import * as React from "react";
2
-
3
- import * as Filters from "@amoa/forge/filters";
4
-
5
- export const useFilters = (data, filters, sort, reference) => {
6
- const [filtered, setFiltered] = React.useState(data);
7
- const { search, ...other } = filters;
8
-
9
- React.useEffect(() => {
10
- if (!search && !Object.keys(other).length) setFiltered(data);
11
- const searched = Filters.search(data, search);
12
- const filtered = Filters.filter(searched, other, reference);
13
- const sorted = Filters.sort(filtered, sort);
14
- setFiltered(sorted);
15
- }, [data, filters, sort]);
16
-
17
- return filtered;
18
- };
19
-
20
- export default useFilters;
package/src/use-hover.js DELETED
@@ -1,35 +0,0 @@
1
- import * as React from "react";
2
-
3
- export const useHover = () => {
4
- const [hovering, setHovering] = React.useState(false);
5
- const previousNode = React.useRef(null);
6
-
7
- const handleMouseEnter = React.useCallback(() => {
8
- setHovering(true);
9
- }, []);
10
-
11
- const handleMouseLeave = React.useCallback(() => {
12
- setHovering(false);
13
- }, []);
14
-
15
- const customRef = React.useCallback(
16
- (node) => {
17
- if (previousNode.current?.nodeType === Node.ELEMENT_NODE) {
18
- previousNode.current.removeEventListener("mouseenter", handleMouseEnter);
19
- previousNode.current.removeEventListener("mouseleave", handleMouseLeave);
20
- }
21
-
22
- if (node?.nodeType === Node.ELEMENT_NODE) {
23
- node.addEventListener("mouseenter", handleMouseEnter);
24
- node.addEventListener("mouseleave", handleMouseLeave);
25
- }
26
-
27
- previousNode.current = node;
28
- },
29
- [handleMouseEnter, handleMouseLeave]
30
- );
31
-
32
- return [customRef, hovering];
33
- };
34
-
35
- export default useHover;
@@ -1,38 +0,0 @@
1
- "use client";
2
-
3
- import * as React from "react";
4
-
5
- const OPTIONS = { threshold: 1, root: null, rootMargin: "0px" };
6
-
7
- export const useIntersection = (options = {}) => {
8
- const [entry, setEntry] = React.useState(null);
9
- const { threshold, root, rootMargin } = { ...OPTIONS, ...options };
10
-
11
- const reference = React.useRef(null);
12
-
13
- const ref = React.useCallback(
14
- (node) => {
15
- if (reference.current) {
16
- reference.current.disconnect();
17
- reference.current = null;
18
- }
19
-
20
- if (node?.nodeType === Node.ELEMENT_NODE) {
21
- const observer = new IntersectionObserver(
22
- ([entry]) => {
23
- setEntry(entry);
24
- },
25
- { threshold, root, rootMargin }
26
- );
27
-
28
- observer.observe(node);
29
- reference.current = observer;
30
- }
31
- },
32
- [threshold, root, rootMargin]
33
- );
34
-
35
- return [ref, entry];
36
- };
37
-
38
- export default useIntersection;
@@ -1,23 +0,0 @@
1
- import * as React from "react";
2
-
3
- import * as Functions from "@amoa/forge/functions";
4
-
5
- const OPTIONS = {
6
- rootMargin: "200px 0px",
7
- threshold: 0.1
8
- };
9
-
10
- export const useLazyLoading = (ref, callback, delay = 300) => {
11
- const throttle = React.useMemo(() => Functions.throttle(callback, delay), [callback, delay]);
12
-
13
- React.useEffect(() => {
14
- const node = ref.current;
15
- if (!node) return;
16
-
17
- const observer = new IntersectionObserver(([e]) => e.isIntersecting && throttle(), OPTIONS);
18
- observer.observe(node);
19
- return () => observer.disconnect();
20
- }, [ref.current, callback]);
21
- };
22
-
23
- export default useLazyLoading;
@@ -1,36 +0,0 @@
1
- "use client";
2
-
3
- import * as React from "react";
4
-
5
- const surface = ({ width, height }) => width * height;
6
-
7
- export const useSummary = (elements = [], options = {}, target) => {
8
- const { threshold = 1, root = null, rootMargin = "0px" } = options;
9
- const [visible, setVisible] = React.useState(null);
10
- const reference = React.useRef(null);
11
-
12
- React.useEffect(() => {
13
- if (!elements.length) return;
14
-
15
- const observer = new IntersectionObserver(
16
- (entries) => {
17
- const [first] = entries.sort((a, b) => surface(b.intersectionRect) - surface(a.intersectionRect));
18
- if (first?.intersectionRect.height > 0) {
19
- setVisible(target(first));
20
- }
21
- },
22
- { threshold, root, rootMargin }
23
- );
24
-
25
- reference.current?.disconnect();
26
-
27
- elements.forEach((element) => observer.observe(element));
28
- reference.current = observer;
29
-
30
- return () => observer.disconnect();
31
- }, [elements, threshold, root, rootMargin, target]);
32
-
33
- return visible;
34
- };
35
-
36
- export default useSummary;