fumadocs-core 15.6.11 → 15.7.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.
@@ -1,3 +1,8 @@
1
+ import {
2
+ joinPath,
3
+ slash,
4
+ splitPath
5
+ } from "../chunk-3JSIVMCJ.js";
1
6
  import {
2
7
  basename,
3
8
  dirname,
@@ -5,14 +10,72 @@ import {
5
10
  parseFilePath,
6
11
  parseFolderPath
7
12
  } from "../chunk-7GNSIKII.js";
8
- import {
9
- joinPath,
10
- slash,
11
- splitPath
12
- } from "../chunk-3JSIVMCJ.js";
13
13
  import "../chunk-JSBRDJBE.js";
14
14
 
15
- // src/source/page-tree-builder.ts
15
+ // src/source/page-tree/legacy.ts
16
+ function legacyTransformer(transformer) {
17
+ return {
18
+ file(node, file) {
19
+ if (!transformer.attachFile) return node;
20
+ const content = file ? this.storage.read(file) : void 0;
21
+ return transformer.attachFile(
22
+ node,
23
+ content?.format === "page" ? content : void 0
24
+ );
25
+ },
26
+ folder(node, folderPath, metaPath) {
27
+ if (!transformer.attachFolder) return node;
28
+ const files = this.storage.readDir(folderPath) ?? [];
29
+ const meta = metaPath ? this.storage.read(metaPath) : void 0;
30
+ return transformer.attachFolder(
31
+ node,
32
+ {
33
+ children: files.flatMap((file) => this.storage.read(file) ?? [])
34
+ },
35
+ meta?.format === "meta" ? meta : void 0
36
+ );
37
+ },
38
+ separator(node) {
39
+ if (!transformer.attachSeparator) return node;
40
+ return transformer.attachSeparator(node);
41
+ }
42
+ };
43
+ }
44
+
45
+ // src/source/page-tree/transformer-fallback.ts
46
+ function transformerFallback() {
47
+ const addedFiles = /* @__PURE__ */ new Set();
48
+ return {
49
+ name: "fumadocs:fallback",
50
+ root(root) {
51
+ const isolatedStorage = new FileSystem();
52
+ for (const file of this.storage.getFiles()) {
53
+ if (addedFiles.has(file)) continue;
54
+ const content = this.storage.read(file);
55
+ if (content) isolatedStorage.write(file, content);
56
+ }
57
+ if (isolatedStorage.getFiles().length === 0) return root;
58
+ root.fallback = this.builder.build({
59
+ ...this.options,
60
+ id: `fallback-${root.$id ?? ""}`,
61
+ storage: isolatedStorage,
62
+ generateFallback: false
63
+ });
64
+ addedFiles.clear();
65
+ return root;
66
+ },
67
+ file(node, file) {
68
+ if (file) addedFiles.add(file);
69
+ return node;
70
+ },
71
+ folder(node, _dir, metaPath) {
72
+ if (metaPath) addedFiles.add(metaPath);
73
+ return node;
74
+ }
75
+ };
76
+ }
77
+
78
+ // src/source/page-tree/builder.ts
16
79
  var group = /^\((?<name>.+)\)$/;
17
80
  var link = /^(?:\[(?<icon>[^\]]+)])?\[(?<name>[^\]]+)]\((?<url>[^)]+)\)$/;
18
81
  var separator = /^---(?:\[(?<icon>[^\]]+)])?(?<name>.+)---|^---$/;
@@ -42,26 +105,34 @@ function resolveFolderItem(folderPath, item, ctx, idx, restNodePaths) {
42
105
  const { options, resolveName } = ctx;
43
106
  let match = separator.exec(item);
44
107
  if (match?.groups) {
45
- const node = {
108
+ let node = {
46
109
  $id: `${folderPath}#${idx}`,
47
110
  type: "separator",
48
111
  icon: options.resolveIcon?.(match.groups.icon),
49
112
  name: match.groups.name
50
113
  };
51
- return [options.attachSeparator?.(node) ?? node];
114
+ for (const transformer of ctx.transformers) {
115
+ if (!transformer.separator) continue;
116
+ node = transformer.separator.call(ctx, node);
117
+ }
118
+ return [node];
52
119
  }
53
120
  match = link.exec(item);
54
121
  if (match?.groups) {
55
122
  const { icon, url, name } = match.groups;
56
123
  const isRelative = url.startsWith("/") || url.startsWith("#") || url.startsWith(".");
57
- const node = {
124
+ let node = {
58
125
  type: "page",
59
126
  icon: options.resolveIcon?.(icon),
60
127
  name,
61
128
  url,
62
129
  external: !isRelative
63
130
  };
64
- return [options.attachFile?.(node) ?? node];
131
+ for (const transformer of ctx.transformers) {
132
+ if (!transformer.file) continue;
133
+ node = transformer.file.call(ctx, node);
134
+ }
135
+ return [node];
65
136
  }
66
137
  const isExcept = item.startsWith(excludePrefix);
67
138
  const isExtract = !isExcept && item.startsWith(extractPrefix);
@@ -82,24 +153,27 @@ function resolveFolderItem(folderPath, item, ctx, idx, restNodePaths) {
82
153
  return fileNode ? [fileNode] : [];
83
154
  }
84
155
  function buildFolderNode(folderPath, isGlobalRoot, ctx) {
85
- const { storage, localeStorage, options, resolveName } = ctx;
156
+ const { storage, options, resolveName, transformers } = ctx;
86
157
  const files = storage.readDir(folderPath);
87
158
  if (!files) return;
88
159
  const metaPath = resolveName(joinPath(folderPath, "meta"), "meta");
89
160
  const indexPath = resolveName(joinPath(folderPath, "index"), "page");
90
- let meta = localeStorage?.read(metaPath) ?? storage.read(metaPath);
161
+ let meta = storage.read(metaPath);
91
162
  if (meta?.format !== "meta") {
92
163
  meta = void 0;
93
164
  }
94
- const isRoot = meta?.data.root ?? isGlobalRoot;
95
- let indexDisabled = false;
165
+ let indexDisabled = meta?.data.root ?? isGlobalRoot;
96
166
  let children;
97
167
  if (!meta?.data.pages) {
98
- children = buildAll(files, ctx, (file) => isRoot || file !== indexPath);
168
+ children = buildAll(
169
+ files,
170
+ ctx,
171
+ (file) => indexDisabled || file !== indexPath
172
+ );
99
173
  } else {
100
174
  const restItems = new Set(files);
101
175
  const resolved = meta.data.pages.flatMap((item, i) => resolveFolderItem(folderPath, item, ctx, i, restItems));
102
- if (!isRoot && !restItems.has(indexPath)) {
176
+ if (!indexDisabled && !restItems.has(indexPath)) {
103
177
  indexDisabled = true;
104
178
  }
105
179
  for (let i = 0; i < resolved.length; i++) {
@@ -108,8 +182,7 @@ function buildFolderNode(folderPath, isGlobalRoot, ctx) {
108
182
  const items = buildAll(
109
183
  files,
110
184
  ctx,
111
- // index files are not included in ... unless it's a root folder
112
- (file) => (file !== indexPath || isRoot) && restItems.has(file),
185
+ (file) => (indexDisabled || file !== indexPath) && restItems.has(file),
113
186
  item === restReversed
114
187
  );
115
188
  resolved.splice(i, 1, ...items);
@@ -123,7 +196,7 @@ function buildFolderNode(folderPath, isGlobalRoot, ctx) {
123
196
  const folderName = basename(folderPath);
124
197
  name = pathToName(group.exec(folderName)?.[1] ?? folderName);
125
198
  }
126
- const node = {
199
+ let node = {
127
200
  type: "folder",
128
201
  name,
129
202
  icon: options.resolveIcon?.(meta?.data.icon) ?? index?.icon,
@@ -137,21 +210,18 @@ function buildFolderNode(folderPath, isGlobalRoot, ctx) {
137
210
  metaFile: metaPath
138
211
  } : void 0
139
212
  };
140
- return options.attachFolder?.(
141
- node,
142
- {
143
- get children() {
144
- return files.flatMap((file) => storage.read(file) ?? []);
145
- }
146
- },
147
- meta
148
- ) ?? node;
213
+ for (const transformer of transformers) {
214
+ if (!transformer.folder) continue;
215
+ node = transformer.folder.call(ctx, node, folderPath, metaPath);
216
+ }
217
+ return node;
149
218
  }
150
- function buildFileNode(path, { options, getUrl, storage, localeStorage, locale }) {
151
- const page = localeStorage?.read(path) ?? storage.read(path);
219
+ function buildFileNode(path, ctx) {
220
+ const { options, getUrl, storage, locale, transformers } = ctx;
221
+ const page = storage.read(path);
152
222
  if (page?.format !== "page") return;
153
223
  const { title, description, icon } = page.data;
154
- const item = {
224
+ let item = {
155
225
  $id: path,
156
226
  type: "page",
157
227
  name: title ?? pathToName(basename(path, extname(path))),
@@ -162,17 +232,36 @@ function buildFileNode(path, { options, getUrl, storage, localeStorage, locale }
162
232
  file: path
163
233
  } : void 0
164
234
  };
165
- return options.attachFile?.(item, page) ?? item;
235
+ for (const transformer of transformers) {
236
+ if (!transformer.file) continue;
237
+ item = transformer.file.call(ctx, item, path);
238
+ }
239
+ return item;
166
240
  }
167
- function build(ctx) {
241
+ function build(id, ctx) {
168
242
  const folder = buildFolderNode("", true, ctx);
169
- return {
170
- $id: ctx.locale ?? "root",
243
+ let root = {
244
+ $id: id,
171
245
  name: folder.name,
172
246
  children: folder.children
173
247
  };
248
+ for (const transformer of ctx.transformers) {
249
+ if (!transformer.root) continue;
250
+ root = transformer.root.call(ctx, root);
251
+ }
252
+ return root;
174
253
  }
175
254
  function createPageTreeBuilder(getUrl) {
255
+ function getTransformers(options, generateFallback = true) {
256
+ const transformers = [legacyTransformer(options)];
257
+ if (options.transformers) {
258
+ transformers.push(...options.transformers);
259
+ }
260
+ if (generateFallback) {
261
+ transformers.push(transformerFallback());
262
+ }
263
+ return transformers;
264
+ }
176
265
  function createFlattenPathResolver(storage) {
177
266
  const map = /* @__PURE__ */ new Map();
178
267
  const files = storage.getFiles();
@@ -186,36 +275,38 @@ function createPageTreeBuilder(getUrl) {
186
275
  };
187
276
  }
188
277
  return {
189
- build(options) {
190
- const resolve = createFlattenPathResolver(options.storage);
191
- return build({
278
+ build({ storage, id, generateFallback, ...options }) {
279
+ const resolve = createFlattenPathResolver(storage);
280
+ return build(id ?? "root", {
281
+ transformers: getTransformers(options, generateFallback),
192
282
  options,
193
283
  builder: this,
194
- storage: options.storage,
284
+ storage,
195
285
  getUrl,
196
286
  resolveName(name, format) {
197
287
  return resolve(name, format) ?? name;
198
288
  }
199
289
  });
200
290
  },
201
- buildI18n({ i18n, ...options }) {
202
- const storage = options.storages[i18n.defaultLanguage];
203
- const resolve = createFlattenPathResolver(storage);
204
- const entries = i18n.languages.map((lang) => {
205
- const tree = build({
291
+ buildI18n({ id, storages, ...options }) {
292
+ const transformers = getTransformers(options);
293
+ const out = {};
294
+ for (const [locale, storage] of Object.entries(storages)) {
295
+ const resolve = createFlattenPathResolver(storage);
296
+ out[locale] = build(id ?? (locale.length === 0 ? "root" : locale), {
297
+ transformers,
298
+ builder: this,
206
299
  options,
207
300
  getUrl,
208
- builder: this,
209
- locale: lang,
301
+ locale,
210
302
  storage,
211
- localeStorage: options.storages[lang],
303
+ storages,
212
304
  resolveName(name, format) {
213
305
  return resolve(name, format) ?? name;
214
306
  }
215
307
  });
216
- return [lang, tree];
217
- });
218
- return Object.fromEntries(entries);
308
+ }
309
+ return out;
219
310
  }
220
311
  };
221
312
  }
@@ -231,10 +322,19 @@ function pathToName(name) {
231
322
 
232
323
  // src/source/file-system.ts
233
324
  var FileSystem = class {
234
- constructor() {
325
+ constructor(inherit) {
235
326
  this.files = /* @__PURE__ */ new Map();
236
327
  this.folders = /* @__PURE__ */ new Map();
237
- this.folders.set("", []);
328
+ if (inherit) {
329
+ for (const [k, v] of inherit.folders) {
330
+ this.folders.set(k, v);
331
+ }
332
+ for (const [k, v] of inherit.files) {
333
+ this.files.set(k, v);
334
+ }
335
+ } else {
336
+ this.folders.set("", []);
337
+ }
238
338
  }
239
339
  read(path) {
240
340
  return this.files.get(path);
@@ -246,11 +346,21 @@ var FileSystem = class {
246
346
  return this.folders.get(path);
247
347
  }
248
348
  write(path, file) {
349
+ if (this.files.has(path)) {
350
+ this.files.set(path, file);
351
+ return;
352
+ }
249
353
  const dir = dirname(path);
250
354
  this.makeDir(dir);
251
355
  this.readDir(dir)?.push(path);
252
356
  this.files.set(path, file);
253
357
  }
358
+ delete(path) {
359
+ return this.files.delete(path);
360
+ }
361
+ deleteDir(path) {
362
+ return this.folders.delete(path);
363
+ }
254
364
  getFiles() {
255
365
  return Array.from(this.files.keys());
256
366
  }
@@ -266,62 +376,59 @@ var FileSystem = class {
266
376
  };
267
377
 
268
378
  // src/source/load-files.ts
269
- function loadFiles(files, options) {
270
- const { transformers = [] } = options;
271
- const storage = new FileSystem();
272
- const normalized = files.map((file) => ({
273
- ...file,
274
- path: normalizePath(file.path)
275
- }));
276
- for (const item of options.buildFiles(normalized)) {
277
- storage.write(item.path, item);
278
- }
279
- for (const transformer of transformers) {
280
- transformer({
281
- storage,
282
- options
283
- });
284
- }
285
- return storage;
379
+ function isLocaleValid(locale) {
380
+ return locale.length > 0 && !/\d+/.test(locale);
286
381
  }
287
- function loadFilesI18n(files, options, i18n) {
288
- const parser = i18n.parser === "dir" ? dirParser : dotParser;
382
+ var parsers = {
383
+ dir(path) {
384
+ const [locale, ...segs] = path.split("/");
385
+ if (locale && segs.length > 0 && isLocaleValid(locale))
386
+ return [segs.join("/"), locale];
387
+ return [path];
388
+ },
389
+ dot(path) {
390
+ const dir = dirname(path);
391
+ const base = basename(path);
392
+ const parts = base.split(".");
393
+ if (parts.length < 3) return [path];
394
+ const [locale] = parts.splice(parts.length - 2, 1);
395
+ if (!isLocaleValid(locale)) return [path];
396
+ return [joinPath(dir, parts.join(".")), locale];
397
+ },
398
+ none(path) {
399
+ return [path];
400
+ }
401
+ };
402
+ function loadFiles(files, options, i18n) {
403
+ const { buildFile, transformers = [] } = options;
404
+ const parser = parsers[i18n.parser];
289
405
  const storages = {};
406
+ const normalized = files.map(
407
+ (file) => buildFile({
408
+ ...file,
409
+ path: normalizePath(file.path)
410
+ })
411
+ );
412
+ function scan(lang, fallback) {
413
+ const storage = new FileSystem(fallback);
414
+ for (const item of normalized) {
415
+ const [path, locale = i18n.defaultLanguage] = parser(item.path);
416
+ if (locale === lang) storage.write(path, item);
417
+ }
418
+ for (const transformer of transformers) {
419
+ transformer({
420
+ storage,
421
+ options
422
+ });
423
+ }
424
+ return storage;
425
+ }
426
+ storages[i18n.defaultLanguage] = scan(i18n.defaultLanguage);
290
427
  for (const lang of i18n.languages) {
291
- storages[lang] = loadFiles(
292
- files.flatMap((file) => {
293
- const [path, locale] = parser(normalizePath(file.path));
294
- if ((locale ?? i18n.defaultLanguage) === lang) {
295
- return {
296
- ...file,
297
- path
298
- };
299
- }
300
- return [];
301
- }),
302
- options
303
- );
428
+ storages[lang] ??= scan(lang, storages[i18n.defaultLanguage]);
304
429
  }
305
430
  return storages;
306
431
  }
307
- function dirParser(path) {
308
- const parsed = path.split("/");
309
- if (parsed.length >= 2) return [parsed.slice(1).join("/"), parsed[0]];
310
- return [path];
311
- }
312
- function dotParser(path) {
313
- const segs = path.split("/");
314
- if (segs.length === 0) return [path];
315
- const name = segs[segs.length - 1].split(".");
316
- if (name.length >= 3) {
317
- const locale = name.splice(name.length - 2, 1)[0];
318
- if (locale.length > 0 && !/\d+/.test(locale)) {
319
- segs[segs.length - 1] = name.join(".");
320
- return [segs.join("/"), locale];
321
- }
322
- }
323
- return [path];
324
- }
325
432
  function normalizePath(path) {
326
433
  const segments = splitPath(slash(path));
327
434
  if (segments[0] === "." || segments[0] === "..")
@@ -330,7 +437,7 @@ function normalizePath(path) {
330
437
  }
331
438
 
332
439
  // src/source/loader.ts
333
- function indexPages(storages, getUrl, i18n) {
440
+ function indexPages(storages, getUrl) {
334
441
  const result = {
335
442
  // (locale.slugs -> page)
336
443
  pages: /* @__PURE__ */ new Map(),
@@ -339,36 +446,17 @@ function indexPages(storages, getUrl, i18n) {
339
446
  // (locale.path -> meta)
340
447
  pathToPage: /* @__PURE__ */ new Map()
341
448
  };
342
- const defaultLanguage = i18n?.defaultLanguage ?? "";
343
- for (const filePath of storages[defaultLanguage].getFiles()) {
344
- const item = storages[defaultLanguage].read(filePath);
345
- if (item.format === "meta") {
346
- result.pathToMeta.set(
347
- `${defaultLanguage}.${item.path}`,
348
- fileToMeta(item)
349
- );
350
- }
351
- if (item.format === "page") {
352
- const page = fileToPage(item, getUrl, defaultLanguage);
353
- result.pathToPage.set(`${defaultLanguage}.${item.path}`, page);
354
- result.pages.set(`${defaultLanguage}.${page.slugs.join("/")}`, page);
355
- if (!i18n) continue;
356
- for (const lang of i18n.languages) {
357
- if (lang === defaultLanguage) continue;
358
- const localizedItem = storages[lang].read(filePath);
359
- const localizedPage = fileToPage(
360
- localizedItem?.format === "page" ? localizedItem : item,
361
- getUrl,
362
- lang
363
- );
364
- if (localizedItem) {
365
- result.pathToPage.set(`${lang}.${item.path}`, localizedPage);
366
- }
367
- result.pages.set(
368
- `${lang}.${localizedPage.slugs.join("/")}`,
369
- localizedPage
370
- );
449
+ for (const [lang, storage] of Object.entries(storages)) {
450
+ for (const filePath of storage.getFiles()) {
451
+ const item = storage.read(filePath);
452
+ const path = `${lang}.${filePath}`;
453
+ if (item.format === "meta") {
454
+ result.pathToMeta.set(path, fileToMeta(item));
455
+ continue;
371
456
  }
457
+ const page = fileToPage(item, getUrl, lang);
458
+ result.pathToPage.set(path, page);
459
+ result.pages.set(`${lang}.${page.slugs.join("/")}`, page);
372
460
  }
373
461
  }
374
462
  return result;
@@ -401,86 +489,84 @@ function createOutput(options) {
401
489
  i18n,
402
490
  slugs: slugsFn,
403
491
  url: getUrl = createGetUrl(baseUrl ?? "/", i18n),
404
- transformers
492
+ transformers = []
405
493
  } = options;
406
494
  const defaultLanguage = i18n?.defaultLanguage ?? "";
407
495
  const files = typeof source.files === "function" ? source.files() : source.files;
408
- function buildFiles(files2) {
409
- const indexFiles = [];
496
+ const transformerSlugs = ({ storage }) => {
497
+ const indexFiles = /* @__PURE__ */ new Set();
410
498
  const taken = /* @__PURE__ */ new Set();
411
- for (const file of files2) {
412
- if (file.type !== "page" || file.slugs) continue;
413
- if (isIndex(file.path) && !slugsFn) {
414
- indexFiles.push(file);
499
+ for (const path of storage.getFiles()) {
500
+ const file = storage.read(path);
501
+ if (!file || file.format !== "page" || file.slugs) continue;
502
+ if (isIndex(path) && !slugsFn) {
503
+ indexFiles.add(path);
415
504
  continue;
416
505
  }
417
- file.slugs = slugsFn ? slugsFn(parseFilePath(file.path)) : getSlugs(file.path);
506
+ file.slugs = slugsFn ? slugsFn(parseFilePath(path)) : getSlugs(path);
418
507
  const key = file.slugs.join("/");
419
508
  if (taken.has(key)) throw new Error("Duplicated slugs");
420
509
  taken.add(key);
421
510
  }
422
- for (const file of indexFiles) {
423
- file.slugs = getSlugs(file.path);
511
+ for (const path of indexFiles) {
512
+ const file = storage.read(path);
513
+ if (file?.format !== "page") continue;
514
+ file.slugs = getSlugs(path);
424
515
  if (taken.has(file.slugs.join("/"))) file.slugs.push("index");
425
516
  }
426
- return files2.map((file) => {
427
- if (file.type === "page") {
517
+ };
518
+ const storages = loadFiles(
519
+ files,
520
+ {
521
+ buildFile(file) {
522
+ if (file.type === "page") {
523
+ return {
524
+ format: "page",
525
+ path: file.path,
526
+ slugs: file.slugs,
527
+ data: file.data,
528
+ absolutePath: file.absolutePath ?? ""
529
+ };
530
+ }
428
531
  return {
429
- format: "page",
532
+ format: "meta",
430
533
  path: file.path,
431
- slugs: file.slugs,
432
- data: file.data,
433
- absolutePath: file.absolutePath ?? ""
534
+ absolutePath: file.absolutePath ?? "",
535
+ data: file.data
434
536
  };
435
- }
436
- return {
437
- format: "meta",
438
- path: file.path,
439
- absolutePath: file.absolutePath ?? "",
440
- data: file.data
441
- };
442
- });
443
- }
444
- const storages = i18n ? loadFilesI18n(
445
- files,
446
- {
447
- buildFiles,
448
- transformers
537
+ },
538
+ transformers: [transformerSlugs, ...transformers]
449
539
  },
450
- {
540
+ i18n ? {
451
541
  ...i18n,
452
542
  parser: i18n.parser ?? "dot"
543
+ } : {
544
+ defaultLanguage,
545
+ parser: "none",
546
+ languages: [defaultLanguage]
453
547
  }
454
- ) : {
455
- "": loadFiles(files, {
456
- transformers,
457
- buildFiles
458
- })
459
- };
460
- const walker = indexPages(storages, getUrl, i18n);
548
+ );
549
+ const walker = indexPages(storages, getUrl);
461
550
  const builder = createPageTreeBuilder(getUrl);
462
551
  let pageTree;
463
552
  return {
464
553
  _i18n: i18n,
465
554
  get pageTree() {
555
+ pageTree ??= builder.buildI18n({
556
+ storages,
557
+ resolveIcon: options.icon,
558
+ ...options.pageTree
559
+ });
560
+ return i18n ? pageTree : pageTree[defaultLanguage];
561
+ },
562
+ set pageTree(v) {
466
563
  if (i18n) {
467
- pageTree ??= builder.buildI18n({
468
- storages,
469
- resolveIcon: options.icon,
470
- i18n,
471
- ...options.pageTree
472
- });
564
+ pageTree = v;
473
565
  } else {
474
- pageTree ??= builder.build({
475
- storage: storages[""],
476
- resolveIcon: options.icon,
477
- ...options.pageTree
478
- });
566
+ pageTree = {
567
+ defaultLanguage: v
568
+ };
479
569
  }
480
- return pageTree;
481
- },
482
- set pageTree(v) {
483
- pageTree = v;
484
570
  },
485
571
  getPageByHref(href, { dir = "", language } = {}) {
486
572
  const [value, hash] = href.split("#", 2);
@@ -6,7 +6,7 @@ import { useCallback, useRef } from "react";
6
6
  function useEffectEvent(callback) {
7
7
  const ref = useRef(callback);
8
8
  ref.current = callback;
9
- return useCallback((...params) => ref.current(...params), []);
9
+ return useCallback(((...params) => ref.current(...params)), []);
10
10
  }
11
11
  export {
12
12
  useEffectEvent