@keepkit/ui 0.20.0 → 0.22.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.js CHANGED
@@ -88,15 +88,27 @@ function getBrowserAdapter() {
88
88
  };
89
89
  }
90
90
 
91
- // src/features/actions/hooks/useKeepBackup.ts
92
- import { useKeepContext } from "@keepkit/core/react";
93
- import { useRef as useRef2, useState } from "react";
91
+ // src/features/actions/KeepArchiveButton.tsx
92
+ import { useKeepItem } from "@keepkit/core/react";
94
93
 
95
94
  // src/foundation/ui-context.tsx
96
95
  import { createContext, useCallback, useContext, useMemo } from "react";
97
96
 
98
97
  // src/locales/de.ts
99
98
  var DE_LABELS = {
99
+ archive: "Archivieren",
100
+ unarchive: "Archivierung aufheben",
101
+ archived: "Archiviert",
102
+ pin: "Anheften",
103
+ unpin: "Anheften l\xF6sen",
104
+ pinned: "Angeheftet",
105
+ collection: "Sammlung",
106
+ allCollections: "Alle Sammlungen",
107
+ filterCollections: "Nach Sammlung filtern",
108
+ uncategorized: "Nicht kategorisiert",
109
+ saveWithNote: "Mit Notiz speichern",
110
+ editSavedItem: "Gespeichertes Element bearbeiten",
111
+ unsavedChanges: "Nicht gespeicherte \xC4nderungen",
100
112
  save: "Speichern",
101
113
  saved: "Gespeichert",
102
114
  remove: "Entfernen",
@@ -183,6 +195,19 @@ var DE_LABELS = {
183
195
 
184
196
  // src/locales/en.ts
185
197
  var EN_LABELS = {
198
+ archive: "Archive",
199
+ unarchive: "Unarchive",
200
+ archived: "Archived",
201
+ pin: "Pin",
202
+ unpin: "Unpin",
203
+ pinned: "Pinned",
204
+ collection: "Collection",
205
+ allCollections: "All collections",
206
+ filterCollections: "Filter collections",
207
+ uncategorized: "Uncategorized",
208
+ saveWithNote: "Save with note",
209
+ editSavedItem: "Edit saved item",
210
+ unsavedChanges: "Unsaved changes",
186
211
  save: "Save",
187
212
  saved: "Saved",
188
213
  remove: "Remove",
@@ -269,6 +294,19 @@ var EN_LABELS = {
269
294
 
270
295
  // src/locales/es.ts
271
296
  var ES_LABELS = {
297
+ archive: "Archivar",
298
+ unarchive: "Desarchivar",
299
+ archived: "Archivado",
300
+ pin: "Fijar",
301
+ unpin: "Desfijar",
302
+ pinned: "Fijado",
303
+ collection: "Colecci\xF3n",
304
+ allCollections: "Todas las colecciones",
305
+ filterCollections: "Filtrar por colecci\xF3n",
306
+ uncategorized: "Sin categor\xEDa",
307
+ saveWithNote: "Guardar con nota",
308
+ editSavedItem: "Editar elemento guardado",
309
+ unsavedChanges: "Cambios sin guardar",
272
310
  save: "Guardar",
273
311
  saved: "Guardado",
274
312
  remove: "Eliminar",
@@ -355,6 +393,19 @@ var ES_LABELS = {
355
393
 
356
394
  // src/locales/fil.ts
357
395
  var FIL_LABELS = {
396
+ archive: "I-archive",
397
+ unarchive: "Alisin sa archive",
398
+ archived: "Naka-archive",
399
+ pin: "I-pin",
400
+ unpin: "Alisin ang pin",
401
+ pinned: "Naka-pin",
402
+ collection: "Koleksyon",
403
+ allCollections: "Lahat ng koleksyon",
404
+ filterCollections: "I-filter ayon sa koleksyon",
405
+ uncategorized: "Walang kategorya",
406
+ saveWithNote: "I-save na may tala",
407
+ editSavedItem: "I-edit ang naka-save na item",
408
+ unsavedChanges: "Mga hindi pa nai-save na pagbabago",
358
409
  save: "I-save",
359
410
  saved: "Nai-save",
360
411
  remove: "Alisin",
@@ -441,6 +492,19 @@ var FIL_LABELS = {
441
492
 
442
493
  // src/locales/fr.ts
443
494
  var FR_LABELS = {
495
+ archive: "Archiver",
496
+ unarchive: "D\xE9sarchiver",
497
+ archived: "Archiv\xE9",
498
+ pin: "\xC9pingler",
499
+ unpin: "D\xE9s\xE9pingler",
500
+ pinned: "\xC9pingl\xE9",
501
+ collection: "Collection",
502
+ allCollections: "Toutes les collections",
503
+ filterCollections: "Filtrer par collection",
504
+ uncategorized: "Non class\xE9",
505
+ saveWithNote: "Enregistrer avec une note",
506
+ editSavedItem: "Modifier l\u2019\xE9l\xE9ment enregistr\xE9",
507
+ unsavedChanges: "Modifications non enregistr\xE9es",
444
508
  save: "Enregistrer",
445
509
  saved: "Enregistr\xE9",
446
510
  remove: "Supprimer",
@@ -527,6 +591,19 @@ var FR_LABELS = {
527
591
 
528
592
  // src/locales/id.ts
529
593
  var ID_LABELS = {
594
+ archive: "Arsipkan",
595
+ unarchive: "Batalkan arsip",
596
+ archived: "Diarsipkan",
597
+ pin: "Sematkan",
598
+ unpin: "Lepas sematan",
599
+ pinned: "Disematkan",
600
+ collection: "Koleksi",
601
+ allCollections: "Semua koleksi",
602
+ filterCollections: "Filter koleksi",
603
+ uncategorized: "Tanpa kategori",
604
+ saveWithNote: "Simpan dengan catatan",
605
+ editSavedItem: "Edit item tersimpan",
606
+ unsavedChanges: "Perubahan belum disimpan",
530
607
  save: "Simpan",
531
608
  saved: "Tersimpan",
532
609
  remove: "Hapus",
@@ -613,6 +690,19 @@ var ID_LABELS = {
613
690
 
614
691
  // src/locales/it.ts
615
692
  var IT_LABELS = {
693
+ archive: "Archivia",
694
+ unarchive: "Rimuovi dall'archivio",
695
+ archived: "Archiviato",
696
+ pin: "Fissa",
697
+ unpin: "Rimuovi fissaggio",
698
+ pinned: "Fissato",
699
+ collection: "Raccolta",
700
+ allCollections: "Tutte le raccolte",
701
+ filterCollections: "Filtra per raccolta",
702
+ uncategorized: "Senza categoria",
703
+ saveWithNote: "Salva con nota",
704
+ editSavedItem: "Modifica elemento salvato",
705
+ unsavedChanges: "Modifiche non salvate",
616
706
  save: "Salva",
617
707
  saved: "Salvato",
618
708
  remove: "Rimuovi",
@@ -699,6 +789,19 @@ var IT_LABELS = {
699
789
 
700
790
  // src/locales/ja.ts
701
791
  var JA_LABELS = {
792
+ archive: "\u30A2\u30FC\u30AB\u30A4\u30D6",
793
+ unarchive: "\u30A2\u30FC\u30AB\u30A4\u30D6\u3092\u89E3\u9664",
794
+ archived: "\u30A2\u30FC\u30AB\u30A4\u30D6\u6E08\u307F",
795
+ pin: "\u30D4\u30F3\u7559\u3081",
796
+ unpin: "\u30D4\u30F3\u7559\u3081\u3092\u89E3\u9664",
797
+ pinned: "\u30D4\u30F3\u7559\u3081\u6E08\u307F",
798
+ collection: "\u30B3\u30EC\u30AF\u30B7\u30E7\u30F3",
799
+ allCollections: "\u3059\u3079\u3066\u306E\u30B3\u30EC\u30AF\u30B7\u30E7\u30F3",
800
+ filterCollections: "\u30B3\u30EC\u30AF\u30B7\u30E7\u30F3\u3067\u7D5E\u308A\u8FBC\u3080",
801
+ uncategorized: "\u672A\u5206\u985E",
802
+ saveWithNote: "\u30E1\u30E2\u4ED8\u304D\u3067\u4FDD\u5B58",
803
+ editSavedItem: "\u4FDD\u5B58\u3057\u305F\u30A2\u30A4\u30C6\u30E0\u3092\u7DE8\u96C6",
804
+ unsavedChanges: "\u672A\u4FDD\u5B58\u306E\u5909\u66F4\u304C\u3042\u308A\u307E\u3059",
702
805
  save: "\u4FDD\u5B58",
703
806
  saved: "\u4FDD\u5B58\u6E08\u307F",
704
807
  remove: "\u524A\u9664",
@@ -785,6 +888,19 @@ var JA_LABELS = {
785
888
 
786
889
  // src/locales/ko.ts
787
890
  var KO_LABELS = {
891
+ archive: "\uBCF4\uAD00",
892
+ unarchive: "\uBCF4\uAD00 \uD574\uC81C",
893
+ archived: "\uBCF4\uAD00\uB428",
894
+ pin: "\uACE0\uC815",
895
+ unpin: "\uACE0\uC815 \uD574\uC81C",
896
+ pinned: "\uACE0\uC815\uB428",
897
+ collection: "\uCEEC\uB809\uC158",
898
+ allCollections: "\uBAA8\uB4E0 \uCEEC\uB809\uC158",
899
+ filterCollections: "\uCEEC\uB809\uC158 \uD544\uD130",
900
+ uncategorized: "\uBBF8\uBD84\uB958",
901
+ saveWithNote: "\uBA54\uBAA8\uC640 \uD568\uAED8 \uC800\uC7A5",
902
+ editSavedItem: "\uC800\uC7A5\uB41C \uD56D\uBAA9 \uD3B8\uC9D1",
903
+ unsavedChanges: "\uC800\uC7A5\uB418\uC9C0 \uC54A\uC740 \uBCC0\uACBD \uC0AC\uD56D",
788
904
  save: "\uC800\uC7A5",
789
905
  saved: "\uC800\uC7A5\uB428",
790
906
  remove: "\uC0AD\uC81C",
@@ -871,6 +987,19 @@ var KO_LABELS = {
871
987
 
872
988
  // src/locales/ms.ts
873
989
  var MS_LABELS = {
990
+ archive: "Arkibkan",
991
+ unarchive: "Nyaharkib",
992
+ archived: "Diarkibkan",
993
+ pin: "Pin",
994
+ unpin: "Nyahpin",
995
+ pinned: "Dipinkan",
996
+ collection: "Koleksi",
997
+ allCollections: "Semua koleksi",
998
+ filterCollections: "Tapis koleksi",
999
+ uncategorized: "Tiada kategori",
1000
+ saveWithNote: "Simpan dengan nota",
1001
+ editSavedItem: "Edit item yang disimpan",
1002
+ unsavedChanges: "Perubahan belum disimpan",
874
1003
  save: "Simpan",
875
1004
  saved: "Disimpan",
876
1005
  remove: "Buang",
@@ -957,6 +1086,19 @@ var MS_LABELS = {
957
1086
 
958
1087
  // src/locales/pt-BR.ts
959
1088
  var PT_BR_LABELS = {
1089
+ archive: "Arquivar",
1090
+ unarchive: "Desarquivar",
1091
+ archived: "Arquivado",
1092
+ pin: "Fixar",
1093
+ unpin: "Desafixar",
1094
+ pinned: "Fixado",
1095
+ collection: "Cole\xE7\xE3o",
1096
+ allCollections: "Todas as cole\xE7\xF5es",
1097
+ filterCollections: "Filtrar por cole\xE7\xE3o",
1098
+ uncategorized: "Sem categoria",
1099
+ saveWithNote: "Salvar com nota",
1100
+ editSavedItem: "Editar item salvo",
1101
+ unsavedChanges: "Altera\xE7\xF5es n\xE3o salvas",
960
1102
  save: "Salvar",
961
1103
  saved: "Salvo",
962
1104
  remove: "Remover",
@@ -1043,6 +1185,19 @@ var PT_BR_LABELS = {
1043
1185
 
1044
1186
  // src/locales/ru.ts
1045
1187
  var RU_LABELS = {
1188
+ archive: "\u0410\u0440\u0445\u0438\u0432\u0438\u0440\u043E\u0432\u0430\u0442\u044C",
1189
+ unarchive: "\u0420\u0430\u0437\u0430\u0440\u0445\u0438\u0432\u0438\u0440\u043E\u0432\u0430\u0442\u044C",
1190
+ archived: "\u0412 \u0430\u0440\u0445\u0438\u0432\u0435",
1191
+ pin: "\u0417\u0430\u043A\u0440\u0435\u043F\u0438\u0442\u044C",
1192
+ unpin: "\u041E\u0442\u043A\u0440\u0435\u043F\u0438\u0442\u044C",
1193
+ pinned: "\u0417\u0430\u043A\u0440\u0435\u043F\u043B\u0435\u043D\u043E",
1194
+ collection: "\u041A\u043E\u043B\u043B\u0435\u043A\u0446\u0438\u044F",
1195
+ allCollections: "\u0412\u0441\u0435 \u043A\u043E\u043B\u043B\u0435\u043A\u0446\u0438\u0438",
1196
+ filterCollections: "\u0424\u0438\u043B\u044C\u0442\u0440 \u043A\u043E\u043B\u043B\u0435\u043A\u0446\u0438\u0439",
1197
+ uncategorized: "\u0411\u0435\u0437 \u043A\u0430\u0442\u0435\u0433\u043E\u0440\u0438\u0438",
1198
+ saveWithNote: "\u0421\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C \u0441 \u0437\u0430\u043C\u0435\u0442\u043A\u043E\u0439",
1199
+ editSavedItem: "\u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0441\u043E\u0445\u0440\u0430\u043D\u0451\u043D\u043D\u044B\u0439 \u044D\u043B\u0435\u043C\u0435\u043D\u0442",
1200
+ unsavedChanges: "\u041D\u0435\u0441\u043E\u0445\u0440\u0430\u043D\u0451\u043D\u043D\u044B\u0435 \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u044F",
1046
1201
  save: "\u0421\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C",
1047
1202
  saved: "\u0421\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u043E",
1048
1203
  remove: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C",
@@ -1129,6 +1284,19 @@ var RU_LABELS = {
1129
1284
 
1130
1285
  // src/locales/th.ts
1131
1286
  var TH_LABELS = {
1287
+ archive: "\u0E40\u0E01\u0E47\u0E1A\u0E16\u0E32\u0E27\u0E23",
1288
+ unarchive: "\u0E22\u0E01\u0E40\u0E25\u0E34\u0E01\u0E01\u0E32\u0E23\u0E40\u0E01\u0E47\u0E1A\u0E16\u0E32\u0E27\u0E23",
1289
+ archived: "\u0E40\u0E01\u0E47\u0E1A\u0E16\u0E32\u0E27\u0E23\u0E41\u0E25\u0E49\u0E27",
1290
+ pin: "\u0E1B\u0E31\u0E01\u0E2B\u0E21\u0E38\u0E14",
1291
+ unpin: "\u0E40\u0E25\u0E34\u0E01\u0E1B\u0E31\u0E01\u0E2B\u0E21\u0E38\u0E14",
1292
+ pinned: "\u0E1B\u0E31\u0E01\u0E2B\u0E21\u0E38\u0E14\u0E41\u0E25\u0E49\u0E27",
1293
+ collection: "\u0E04\u0E2D\u0E25\u0E40\u0E25\u0E01\u0E0A\u0E31\u0E19",
1294
+ allCollections: "\u0E04\u0E2D\u0E25\u0E40\u0E25\u0E01\u0E0A\u0E31\u0E19\u0E17\u0E31\u0E49\u0E07\u0E2B\u0E21\u0E14",
1295
+ filterCollections: "\u0E01\u0E23\u0E2D\u0E07\u0E04\u0E2D\u0E25\u0E40\u0E25\u0E01\u0E0A\u0E31\u0E19",
1296
+ uncategorized: "\u0E44\u0E21\u0E48\u0E21\u0E35\u0E2B\u0E21\u0E27\u0E14\u0E2B\u0E21\u0E39\u0E48",
1297
+ saveWithNote: "\u0E1A\u0E31\u0E19\u0E17\u0E36\u0E01\u0E1E\u0E23\u0E49\u0E2D\u0E21\u0E42\u0E19\u0E49\u0E15",
1298
+ editSavedItem: "\u0E41\u0E01\u0E49\u0E44\u0E02\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23\u0E17\u0E35\u0E48\u0E1A\u0E31\u0E19\u0E17\u0E36\u0E01\u0E44\u0E27\u0E49",
1299
+ unsavedChanges: "\u0E21\u0E35\u0E01\u0E32\u0E23\u0E40\u0E1B\u0E25\u0E35\u0E48\u0E22\u0E19\u0E41\u0E1B\u0E25\u0E07\u0E17\u0E35\u0E48\u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E1A\u0E31\u0E19\u0E17\u0E36\u0E01",
1132
1300
  save: "\u0E1A\u0E31\u0E19\u0E17\u0E36\u0E01",
1133
1301
  saved: "\u0E1A\u0E31\u0E19\u0E17\u0E36\u0E01\u0E41\u0E25\u0E49\u0E27",
1134
1302
  remove: "\u0E25\u0E1A",
@@ -1215,6 +1383,19 @@ var TH_LABELS = {
1215
1383
 
1216
1384
  // src/locales/vi.ts
1217
1385
  var VI_LABELS = {
1386
+ archive: "L\u01B0u tr\u1EEF",
1387
+ unarchive: "B\u1ECF l\u01B0u tr\u1EEF",
1388
+ archived: "\u0110\xE3 l\u01B0u tr\u1EEF",
1389
+ pin: "Ghim",
1390
+ unpin: "B\u1ECF ghim",
1391
+ pinned: "\u0110\xE3 ghim",
1392
+ collection: "B\u1ED9 s\u01B0u t\u1EADp",
1393
+ allCollections: "T\u1EA5t c\u1EA3 b\u1ED9 s\u01B0u t\u1EADp",
1394
+ filterCollections: "L\u1ECDc theo b\u1ED9 s\u01B0u t\u1EADp",
1395
+ uncategorized: "Ch\u01B0a ph\xE2n lo\u1EA1i",
1396
+ saveWithNote: "L\u01B0u k\xE8m ghi ch\xFA",
1397
+ editSavedItem: "Ch\u1EC9nh s\u1EEDa m\u1EE5c \u0111\xE3 l\u01B0u",
1398
+ unsavedChanges: "Thay \u0111\u1ED5i ch\u01B0a \u0111\u01B0\u1EE3c l\u01B0u",
1218
1399
  save: "L\u01B0u",
1219
1400
  saved: "\u0110\xE3 l\u01B0u",
1220
1401
  remove: "X\xF3a",
@@ -1301,6 +1482,19 @@ var VI_LABELS = {
1301
1482
 
1302
1483
  // src/locales/zh-Hans.ts
1303
1484
  var ZH_HANS_LABELS = {
1485
+ archive: "\u5F52\u6863",
1486
+ unarchive: "\u53D6\u6D88\u5F52\u6863",
1487
+ archived: "\u5DF2\u5F52\u6863",
1488
+ pin: "\u7F6E\u9876",
1489
+ unpin: "\u53D6\u6D88\u7F6E\u9876",
1490
+ pinned: "\u5DF2\u7F6E\u9876",
1491
+ collection: "\u96C6\u5408",
1492
+ allCollections: "\u6240\u6709\u96C6\u5408",
1493
+ filterCollections: "\u6309\u96C6\u5408\u7B5B\u9009",
1494
+ uncategorized: "\u672A\u5206\u7C7B",
1495
+ saveWithNote: "\u4FDD\u5B58\u5E76\u6DFB\u52A0\u5907\u6CE8",
1496
+ editSavedItem: "\u7F16\u8F91\u5DF2\u4FDD\u5B58\u9879\u76EE",
1497
+ unsavedChanges: "\u6709\u672A\u4FDD\u5B58\u7684\u66F4\u6539",
1304
1498
  save: "\u4FDD\u5B58",
1305
1499
  saved: "\u5DF2\u4FDD\u5B58",
1306
1500
  remove: "\u5220\u9664",
@@ -1387,6 +1581,19 @@ var ZH_HANS_LABELS = {
1387
1581
 
1388
1582
  // src/locales/zh-Hant.ts
1389
1583
  var ZH_HANT_LABELS = {
1584
+ archive: "\u5C01\u5B58",
1585
+ unarchive: "\u53D6\u6D88\u5C01\u5B58",
1586
+ archived: "\u5DF2\u5C01\u5B58",
1587
+ pin: "\u91D8\u9078",
1588
+ unpin: "\u53D6\u6D88\u91D8\u9078",
1589
+ pinned: "\u5DF2\u91D8\u9078",
1590
+ collection: "\u6536\u85CF\u96C6",
1591
+ allCollections: "\u6240\u6709\u6536\u85CF\u96C6",
1592
+ filterCollections: "\u4F9D\u6536\u85CF\u96C6\u7BE9\u9078",
1593
+ uncategorized: "\u672A\u5206\u985E",
1594
+ saveWithNote: "\u5132\u5B58\u4E26\u52A0\u5099\u8A3B",
1595
+ editSavedItem: "\u7DE8\u8F2F\u5DF2\u5132\u5B58\u9805\u76EE",
1596
+ unsavedChanges: "\u6709\u672A\u5132\u5B58\u7684\u8B8A\u66F4",
1390
1597
  save: "\u5132\u5B58",
1391
1598
  saved: "\u5DF2\u5132\u5B58",
1392
1599
  remove: "\u522A\u9664",
@@ -1570,7 +1777,84 @@ function useKeepUiFeedback() {
1570
1777
  return useCallback((event) => emitFeedback(event), [emitFeedback]);
1571
1778
  }
1572
1779
 
1780
+ // src/features/actions/KeepArchiveButton.tsx
1781
+ import { jsxs } from "react/jsx-runtime";
1782
+ function KeepArchiveButton({
1783
+ item,
1784
+ children,
1785
+ archiveLabel,
1786
+ unarchiveLabel,
1787
+ onToggleError,
1788
+ disabled,
1789
+ ...props
1790
+ }) {
1791
+ const state = useKeepItem(item);
1792
+ const archive = useUiLabel("archive");
1793
+ const unarchive = useUiLabel("unarchive");
1794
+ const archivedLabel = useUiLabel("archived");
1795
+ const isArchived = state.item?.archived === true;
1796
+ const isDisabled = disabled ?? state.isMutating;
1797
+ return /* @__PURE__ */ jsxs(
1798
+ "button",
1799
+ {
1800
+ ...props,
1801
+ type: props.type ?? "button",
1802
+ disabled: isDisabled,
1803
+ "aria-pressed": isArchived,
1804
+ "data-archived": isArchived ? "true" : "false",
1805
+ "data-keep-action": "toggle-archive",
1806
+ onClick: () => void state.toggleArchive().catch((error) => onToggleError?.(error)),
1807
+ children: [
1808
+ typeof children === "function" ? children(state) : children ?? (isArchived ? unarchiveLabel ?? unarchive : archiveLabel ?? archive),
1809
+ isArchived && children === void 0 ? /* @__PURE__ */ jsxs("span", { "aria-hidden": "true", children: [
1810
+ " (",
1811
+ archivedLabel,
1812
+ ")"
1813
+ ] }) : null
1814
+ ]
1815
+ }
1816
+ );
1817
+ }
1818
+ function KeepPinButton({
1819
+ item,
1820
+ children,
1821
+ pinLabel,
1822
+ unpinLabel,
1823
+ onToggleError,
1824
+ disabled,
1825
+ ...props
1826
+ }) {
1827
+ const state = useKeepItem(item);
1828
+ const pin = useUiLabel("pin");
1829
+ const unpin = useUiLabel("unpin");
1830
+ const pinnedLabel = useUiLabel("pinned");
1831
+ const isPinned = state.item?.pinned === true;
1832
+ const isDisabled = disabled ?? state.isMutating;
1833
+ return /* @__PURE__ */ jsxs(
1834
+ "button",
1835
+ {
1836
+ ...props,
1837
+ type: props.type ?? "button",
1838
+ disabled: isDisabled,
1839
+ "aria-pressed": isPinned,
1840
+ "data-pinned": isPinned ? "true" : "false",
1841
+ "data-keep-action": "toggle-pin",
1842
+ onClick: () => void state.togglePin().catch((error) => onToggleError?.(error)),
1843
+ children: [
1844
+ typeof children === "function" ? children(state) : children ?? (isPinned ? unpinLabel ?? unpin : pinLabel ?? pin),
1845
+ isPinned && children === void 0 ? /* @__PURE__ */ jsxs("span", { "aria-hidden": "true", children: [
1846
+ " (",
1847
+ pinnedLabel,
1848
+ ")"
1849
+ ] }) : null
1850
+ ]
1851
+ }
1852
+ );
1853
+ }
1854
+
1573
1855
  // src/features/actions/hooks/useKeepBackup.ts
1856
+ import { useKeepContext } from "@keepkit/core/react";
1857
+ import { useRef as useRef2, useState } from "react";
1574
1858
  function useKeepBackup({ filename, onExport, onImported }) {
1575
1859
  const context = useKeepContext();
1576
1860
  const inputRef = useRef2(null);
@@ -1631,7 +1915,7 @@ function useKeepBackup({ filename, onExport, onImported }) {
1631
1915
  }
1632
1916
 
1633
1917
  // src/features/actions/KeepBackup.tsx
1634
- import { jsx as jsx2, jsxs } from "react/jsx-runtime";
1918
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
1635
1919
  function KeepBackup({
1636
1920
  filename = "keepkit-backup.json",
1637
1921
  onExport,
@@ -1639,7 +1923,7 @@ function KeepBackup({
1639
1923
  ...props
1640
1924
  }) {
1641
1925
  const view = useKeepBackup({ filename, onExport, onImported });
1642
- return /* @__PURE__ */ jsxs(
1926
+ return /* @__PURE__ */ jsxs2(
1643
1927
  "section",
1644
1928
  {
1645
1929
  ...props,
@@ -1657,9 +1941,9 @@ function KeepBackup({
1657
1941
  children: view.labels.export
1658
1942
  }
1659
1943
  ),
1660
- /* @__PURE__ */ jsxs("label", { children: [
1944
+ /* @__PURE__ */ jsxs2("label", { children: [
1661
1945
  view.labels.importMode,
1662
- /* @__PURE__ */ jsxs(
1946
+ /* @__PURE__ */ jsxs2(
1663
1947
  "select",
1664
1948
  {
1665
1949
  "data-keep-action": "select-import-mode",
@@ -1684,7 +1968,7 @@ function KeepBackup({
1684
1968
  onChange: (event) => void view.importBackup(event)
1685
1969
  }
1686
1970
  ),
1687
- view.result ? /* @__PURE__ */ jsxs("p", { role: "status", children: [
1971
+ view.result ? /* @__PURE__ */ jsxs2("p", { role: "status", children: [
1688
1972
  view.result.imported,
1689
1973
  " ",
1690
1974
  view.labels.importedCount,
@@ -1763,7 +2047,10 @@ function toKeepButtonItem(item) {
1763
2047
  meta: item.meta,
1764
2048
  targetType: item.targetType,
1765
2049
  note: item.note,
1766
- tags: item.tags
2050
+ tags: item.tags,
2051
+ archived: item.archived,
2052
+ pinned: item.pinned,
2053
+ collectionId: item.collectionId
1767
2054
  };
1768
2055
  }
1769
2056
  function getMetaTitle(meta) {
@@ -1986,7 +2273,7 @@ function getItemLabel(item) {
1986
2273
  }
1987
2274
 
1988
2275
  // src/features/actions/KeepBulkActions.tsx
1989
- import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
2276
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1990
2277
  function KeepBulkActions({
1991
2278
  query,
1992
2279
  selectedIds: controlledSelectedIds,
@@ -2009,12 +2296,12 @@ function KeepBulkActions({
2009
2296
  controlledScope,
2010
2297
  onSelectionScopeChange
2011
2298
  });
2012
- const body = render ? render(state) : typeof children === "function" ? children(state) : children ?? /* @__PURE__ */ jsxs2(Fragment2, { children: [
2013
- /* @__PURE__ */ jsxs2("fieldset", { children: [
2299
+ const body = render ? render(state) : typeof children === "function" ? children(state) : children ?? /* @__PURE__ */ jsxs3(Fragment2, { children: [
2300
+ /* @__PURE__ */ jsxs3("fieldset", { children: [
2014
2301
  /* @__PURE__ */ jsx5("legend", { children: labels.selectItems }),
2015
- /* @__PURE__ */ jsxs2("label", { children: [
2302
+ /* @__PURE__ */ jsxs3("label", { children: [
2016
2303
  labels.selectionScope,
2017
- /* @__PURE__ */ jsxs2(
2304
+ /* @__PURE__ */ jsxs3(
2018
2305
  "select",
2019
2306
  {
2020
2307
  "data-keep-action": "select-scope",
@@ -2028,7 +2315,7 @@ function KeepBulkActions({
2028
2315
  }
2029
2316
  )
2030
2317
  ] }),
2031
- /* @__PURE__ */ jsxs2("label", { children: [
2318
+ /* @__PURE__ */ jsxs3("label", { children: [
2032
2319
  /* @__PURE__ */ jsx5(
2033
2320
  "input",
2034
2321
  {
@@ -2043,7 +2330,7 @@ function KeepBulkActions({
2043
2330
  " ",
2044
2331
  labels.selectedCount
2045
2332
  ] }),
2046
- state.items.map((item) => /* @__PURE__ */ jsxs2("span", { children: [
2333
+ state.items.map((item) => /* @__PURE__ */ jsxs3("span", { children: [
2047
2334
  /* @__PURE__ */ jsx5(
2048
2335
  KeepItemCheckbox,
2049
2336
  {
@@ -2065,7 +2352,7 @@ function KeepBulkActions({
2065
2352
  children: labels.deleteSelected
2066
2353
  }
2067
2354
  ),
2068
- /* @__PURE__ */ jsxs2("label", { children: [
2355
+ /* @__PURE__ */ jsxs3("label", { children: [
2069
2356
  labels.tags,
2070
2357
  /* @__PURE__ */ jsx5(
2071
2358
  "input",
@@ -2107,10 +2394,10 @@ import {
2107
2394
  import { createElement, useEffect as useEffect2, useRef as useRef3 } from "react";
2108
2395
 
2109
2396
  // src/features/actions/hooks/useKeepButton.ts
2110
- import { useKeepItem } from "@keepkit/core/react";
2397
+ import { useKeepItem as useKeepItem2 } from "@keepkit/core/react";
2111
2398
  function useKeepButton({ item, labels, icons, children }) {
2112
2399
  return {
2113
- buttonState: useKeepItem(item),
2400
+ buttonState: useKeepItem2(item),
2114
2401
  emitFeedback: useKeepUiFeedback(),
2115
2402
  customStateLabel: labels?.loading !== void 0 || labels?.error !== void 0 || icons !== void 0 && children === void 0,
2116
2403
  labels: {
@@ -2127,7 +2414,7 @@ function useKeepButton({ item, labels, icons, children }) {
2127
2414
  }
2128
2415
 
2129
2416
  // src/features/actions/KeepButton.tsx
2130
- import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
2417
+ import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
2131
2418
  function KeepButton({
2132
2419
  labels,
2133
2420
  icons,
@@ -2172,7 +2459,7 @@ function KeepButton({
2172
2459
  const label = state.error ? labels?.error ?? view.labels.error : state.isMutating ? labels?.loading ?? view.labels.loading : state.isSaved ? labels?.saved ?? view.labels.saved : labels?.unsaved ?? view.labels.save;
2173
2460
  if (!icons) return label;
2174
2461
  const icon = state.error ? icons.error : state.isMutating ? icons.loading : state.isSaved ? icons.remove ?? icons.saved : icons.save;
2175
- return /* @__PURE__ */ jsxs3(Fragment3, { children: [
2462
+ return /* @__PURE__ */ jsxs4(Fragment3, { children: [
2176
2463
  renderIcon(icon, iconClassName),
2177
2464
  showLabel && !iconOnly ? label : null
2178
2465
  ] });
@@ -2207,16 +2494,442 @@ function renderIcon(icon, className) {
2207
2494
  return icon ?? null;
2208
2495
  }
2209
2496
 
2497
+ // src/features/actions/KeepSavePopover.tsx
2498
+ import { useKeepItem as useKeepItem4 } from "@keepkit/core/react";
2499
+ import {
2500
+ useCallback as useCallback3,
2501
+ useEffect as useEffect4,
2502
+ useId,
2503
+ useRef as useRef5,
2504
+ useState as useState4
2505
+ } from "react";
2506
+
2507
+ // src/features/editor/KeepQuickEditor.tsx
2508
+ import { useKeepContext as useKeepContext2, useKeepItem as useKeepItem3 } from "@keepkit/core/react";
2509
+ import {
2510
+ useCallback as useCallback2,
2511
+ useEffect as useEffect3,
2512
+ useRef as useRef4,
2513
+ useState as useState3
2514
+ } from "react";
2515
+ import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
2516
+ function useKeepQuickEditor(item, options = {}) {
2517
+ const { debounceMs = 300, onSaved, onSaveError } = options;
2518
+ const itemState = useKeepItem3(item);
2519
+ const { error, isMutating, moveToCollection, updateNote, updateTags } = itemState;
2520
+ const baseline = itemState.item ?? item;
2521
+ const [note, setNote] = useState3(baseline.note ?? "");
2522
+ const [tags, setTags] = useState3(baseline.tags ?? []);
2523
+ const [collectionId, setCollectionId] = useState3(baseline.collectionId);
2524
+ const [saveStatus, setSaveStatus] = useState3("idle");
2525
+ const [saveError, setSaveError] = useState3(null);
2526
+ const baselineRef = useRef4({
2527
+ note: baseline.note ?? "",
2528
+ tags: baseline.tags ?? [],
2529
+ collectionId: baseline.collectionId
2530
+ });
2531
+ const draftRef = useRef4({ note, tags, collectionId });
2532
+ const flushRequestedRef = useRef4(false);
2533
+ const flushPromiseRef = useRef4(null);
2534
+ draftRef.current = { note, tags, collectionId };
2535
+ useEffect3(() => {
2536
+ if (draftRef.current.note === baselineRef.current.note && sameTags(draftRef.current.tags, baselineRef.current.tags) && draftRef.current.collectionId === baselineRef.current.collectionId) {
2537
+ setNote(baseline.note ?? "");
2538
+ setTags(baseline.tags ?? []);
2539
+ setCollectionId(baseline.collectionId);
2540
+ baselineRef.current = {
2541
+ note: baseline.note ?? "",
2542
+ tags: baseline.tags ?? [],
2543
+ collectionId: baseline.collectionId
2544
+ };
2545
+ }
2546
+ }, [baseline]);
2547
+ const isDirty = note !== baselineRef.current.note || !sameTags(tags, baselineRef.current.tags) || collectionId !== baselineRef.current.collectionId;
2548
+ useEffect3(() => {
2549
+ if (!isDirty && saveStatus === "dirty" && !flushPromiseRef.current) setSaveStatus("idle");
2550
+ }, [isDirty, saveStatus]);
2551
+ const flush = useCallback2(() => {
2552
+ flushRequestedRef.current = true;
2553
+ if (flushPromiseRef.current) return flushPromiseRef.current;
2554
+ const run = async () => {
2555
+ let saved = false;
2556
+ while (flushRequestedRef.current || !sameDraft(draftRef.current, baselineRef.current)) {
2557
+ flushRequestedRef.current = false;
2558
+ const draft = { ...draftRef.current, tags: [...draftRef.current.tags] };
2559
+ const previous = baselineRef.current;
2560
+ if (sameDraft(draft, previous)) continue;
2561
+ setSaveError(null);
2562
+ setSaveStatus("saving");
2563
+ try {
2564
+ if (draft.note !== previous.note) await updateNote(draft.note.trim() || void 0);
2565
+ if (!sameTags(draft.tags, previous.tags)) await updateTags(draft.tags);
2566
+ if (draft.collectionId !== previous.collectionId) await moveToCollection(draft.collectionId);
2567
+ } catch (error2) {
2568
+ setSaveError(error2);
2569
+ setSaveStatus("error");
2570
+ onSaveError?.(error2);
2571
+ throw error2;
2572
+ }
2573
+ baselineRef.current = draft;
2574
+ saved = true;
2575
+ const { collectionId: _oldCollectionId, ...withoutCollection } = baseline;
2576
+ onSaved?.({
2577
+ ...withoutCollection,
2578
+ note: draft.note.trim() || void 0,
2579
+ tags: draft.tags,
2580
+ ...draft.collectionId ? { collectionId: draft.collectionId } : {}
2581
+ });
2582
+ if (!sameDraft(draftRef.current, baselineRef.current)) flushRequestedRef.current = true;
2583
+ }
2584
+ if (saved) setSaveStatus("saved");
2585
+ };
2586
+ const promise = run().finally(() => {
2587
+ flushPromiseRef.current = null;
2588
+ });
2589
+ flushPromiseRef.current = promise;
2590
+ return promise;
2591
+ }, [baseline, moveToCollection, onSaveError, onSaved, updateNote, updateTags]);
2592
+ useEffect3(() => {
2593
+ if (!isDirty || debounceMs <= 0) return;
2594
+ const timer = window.setTimeout(() => void flush().catch(() => void 0), debounceMs);
2595
+ return () => window.clearTimeout(timer);
2596
+ }, [debounceMs, flush, isDirty]);
2597
+ return {
2598
+ state: {
2599
+ item,
2600
+ note,
2601
+ tags,
2602
+ collectionId,
2603
+ setNote: (value) => {
2604
+ setSaveError(null);
2605
+ setSaveStatus("dirty");
2606
+ setNote(value);
2607
+ },
2608
+ setTags: (value) => {
2609
+ setSaveError(null);
2610
+ setSaveStatus("dirty");
2611
+ setTags(value);
2612
+ },
2613
+ setCollectionId: (value) => {
2614
+ setSaveError(null);
2615
+ setSaveStatus("dirty");
2616
+ setCollectionId(value);
2617
+ },
2618
+ isDirty,
2619
+ isSaving: isMutating || saveStatus === "saving",
2620
+ saveStatus,
2621
+ error: saveError ?? error,
2622
+ flush
2623
+ }
2624
+ };
2625
+ }
2626
+ function KeepQuickEditor({
2627
+ item,
2628
+ debounceMs = 300,
2629
+ onSaved,
2630
+ onSaveError,
2631
+ ...props
2632
+ }) {
2633
+ const view = useKeepQuickEditor(item, { debounceMs, onSaved, onSaveError });
2634
+ return /* @__PURE__ */ jsx7(KeepQuickEditorView, { ...props, state: view.state });
2635
+ }
2636
+ function KeepQuickEditorView({
2637
+ state,
2638
+ collectionIds,
2639
+ collectionLabels,
2640
+ showSaveButton = true,
2641
+ children,
2642
+ onClose,
2643
+ focusScopeRef,
2644
+ ...props
2645
+ }) {
2646
+ const context = useKeepContext2();
2647
+ const rootRef = useRef4(null);
2648
+ const noteLabel = useUiLabel("note");
2649
+ const tagsLabel = useUiLabel("tags");
2650
+ const collectionLabel = useUiLabel("collection");
2651
+ const uncategorizedLabel = useUiLabel("uncategorized");
2652
+ const saveLabel = useUiLabel("saveWithNote");
2653
+ const closeLabel = useUiLabel("close");
2654
+ const unsavedChangesLabel = useUiLabel("unsavedChanges");
2655
+ const savingLabel = useUiLabel("saving");
2656
+ const savedLabel = useUiLabel("saved");
2657
+ const errorLabel = useUiLabel("error");
2658
+ const submit = (event) => {
2659
+ event.preventDefault();
2660
+ void state.flush().catch(() => void 0);
2661
+ };
2662
+ const onKeyDown = (event) => {
2663
+ props.onKeyDown?.(event);
2664
+ if (event.defaultPrevented) return;
2665
+ if (event.key === "Escape") {
2666
+ event.preventDefault();
2667
+ void state.flush().then(() => onClose?.()).catch(() => void 0);
2668
+ }
2669
+ if (event.key === "Tab") trapFocus(event, focusScopeRef?.current ?? rootRef.current);
2670
+ };
2671
+ const statusMessage = state.saveStatus === "dirty" ? unsavedChangesLabel : state.saveStatus === "saving" ? savingLabel : state.saveStatus === "saved" ? savedLabel : state.saveStatus === "error" ? getErrorMessage2(state.error, errorLabel) : null;
2672
+ const body = typeof children === "function" ? children(state) : children ?? /* @__PURE__ */ jsxs5(Fragment4, { children: [
2673
+ /* @__PURE__ */ jsxs5("label", { children: [
2674
+ noteLabel,
2675
+ /* @__PURE__ */ jsx7("textarea", { value: state.note, onChange: (event) => state.setNote(event.currentTarget.value) })
2676
+ ] }),
2677
+ /* @__PURE__ */ jsxs5("label", { children: [
2678
+ tagsLabel,
2679
+ /* @__PURE__ */ jsx7(
2680
+ "input",
2681
+ {
2682
+ value: state.tags.join(", "),
2683
+ onChange: (event) => state.setTags(
2684
+ event.currentTarget.value.split(",").map((tag) => tag.trim()).filter(Boolean)
2685
+ )
2686
+ }
2687
+ )
2688
+ ] }),
2689
+ /* @__PURE__ */ jsxs5("label", { children: [
2690
+ collectionLabel,
2691
+ /* @__PURE__ */ jsxs5(
2692
+ "select",
2693
+ {
2694
+ value: state.collectionId ?? "",
2695
+ onChange: (event) => state.setCollectionId(event.currentTarget.value || void 0),
2696
+ children: [
2697
+ /* @__PURE__ */ jsx7("option", { value: "", children: uncategorizedLabel }),
2698
+ (collectionIds ?? [
2699
+ ...new Set(
2700
+ context.items.map((entry) => entry.collectionId).filter((id) => Boolean(id))
2701
+ )
2702
+ ].sort()).map((id) => /* @__PURE__ */ jsx7("option", { value: id, children: collectionLabels?.[id] ?? id }, id))
2703
+ ]
2704
+ }
2705
+ )
2706
+ ] }),
2707
+ statusMessage ? /* @__PURE__ */ jsx7(
2708
+ "p",
2709
+ {
2710
+ role: state.saveStatus === "error" ? "alert" : "status",
2711
+ "aria-live": state.saveStatus === "error" ? "assertive" : "polite",
2712
+ tabIndex: state.saveStatus === "error" ? -1 : void 0,
2713
+ "data-keep-editor-status": "true",
2714
+ "data-state": state.saveStatus,
2715
+ children: statusMessage
2716
+ }
2717
+ ) : null,
2718
+ showSaveButton ? /* @__PURE__ */ jsx7("button", { type: "submit", disabled: state.isSaving, "data-keep-action": "save-quick-edit", children: saveLabel }) : null,
2719
+ onClose ? /* @__PURE__ */ jsx7(
2720
+ "button",
2721
+ {
2722
+ type: "button",
2723
+ onClick: () => void state.flush().then(onClose).catch(() => void 0),
2724
+ disabled: state.isSaving,
2725
+ "data-keep-action": "close-quick-edit",
2726
+ children: closeLabel
2727
+ }
2728
+ ) : null
2729
+ ] });
2730
+ return /* @__PURE__ */ jsx7(
2731
+ "form",
2732
+ {
2733
+ ...props,
2734
+ ref: rootRef,
2735
+ onSubmit: submit,
2736
+ onKeyDown,
2737
+ "data-keepkit": "quick-editor",
2738
+ "data-state": state.isDirty ? "dirty" : "clean",
2739
+ "data-save-status": state.saveStatus,
2740
+ "aria-busy": state.isSaving || props["aria-busy"],
2741
+ children: body
2742
+ }
2743
+ );
2744
+ }
2745
+ function sameDraft(left, right) {
2746
+ return left.note === right.note && sameTags(left.tags, right.tags) && left.collectionId === right.collectionId;
2747
+ }
2748
+ function getErrorMessage2(error, fallback) {
2749
+ return error instanceof Error ? error.message : fallback;
2750
+ }
2751
+ function sameTags(left, right) {
2752
+ return left.length === right.length && left.every((tag, index) => tag === right[index]);
2753
+ }
2754
+ function trapFocus(event, root) {
2755
+ if (!root) return;
2756
+ const elements = [
2757
+ ...root.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])')
2758
+ ].filter((element) => !element.hasAttribute("disabled"));
2759
+ if (elements.length === 0) return;
2760
+ const first = elements[0];
2761
+ const last = elements[elements.length - 1];
2762
+ if (event.shiftKey && document.activeElement === first) {
2763
+ event.preventDefault();
2764
+ last.focus();
2765
+ } else if (!event.shiftKey && document.activeElement === last) {
2766
+ event.preventDefault();
2767
+ first.focus();
2768
+ }
2769
+ }
2770
+
2771
+ // src/features/actions/KeepSavePopover.tsx
2772
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
2773
+ function KeepSavePopover({
2774
+ item,
2775
+ open: controlledOpen,
2776
+ defaultOpen = false,
2777
+ onOpenChange,
2778
+ dialogLabel,
2779
+ buttonProps,
2780
+ editorProps,
2781
+ children,
2782
+ ...props
2783
+ }) {
2784
+ const state = useKeepItem4(item);
2785
+ const [internalOpen, setInternalOpen] = useState4(defaultOpen);
2786
+ const isOpen = controlledOpen ?? internalOpen;
2787
+ const triggerRef = useRef5(null);
2788
+ const wasOpenRef = useRef5(isOpen);
2789
+ const previousSaved = useRef5(state.isSaved);
2790
+ const observedHydration = useRef5(!state.isLoading);
2791
+ const panelId = useId();
2792
+ const titleId = `${panelId}-title`;
2793
+ const editSavedItemLabel = useUiLabel("editSavedItem");
2794
+ const { ref: _buttonRef, ...resolvedButtonProps } = buttonProps ?? {};
2795
+ const setOpen = useCallback3(
2796
+ (next) => {
2797
+ if (controlledOpen === void 0) setInternalOpen(next);
2798
+ onOpenChange?.(next);
2799
+ },
2800
+ [controlledOpen, onOpenChange]
2801
+ );
2802
+ useEffect4(() => {
2803
+ if (wasOpenRef.current && !isOpen) window.setTimeout(() => triggerRef.current?.focus(), 0);
2804
+ wasOpenRef.current = isOpen;
2805
+ }, [isOpen]);
2806
+ useEffect4(() => {
2807
+ if (!observedHydration.current) {
2808
+ if (state.isLoading) return;
2809
+ observedHydration.current = true;
2810
+ previousSaved.current = state.isSaved;
2811
+ return;
2812
+ }
2813
+ if (!previousSaved.current && state.isSaved) setOpen(true);
2814
+ previousSaved.current = state.isSaved;
2815
+ }, [setOpen, state.isLoading, state.isSaved]);
2816
+ useEffect4(() => {
2817
+ if (isOpen && observedHydration.current && !state.isSaved) setOpen(false);
2818
+ }, [isOpen, setOpen, state.isSaved]);
2819
+ const currentItem = state.item;
2820
+ return /* @__PURE__ */ jsxs6("div", { ...props, "data-keepkit": "save-popover", "data-open": isOpen ? "true" : "false", children: [
2821
+ /* @__PURE__ */ jsx8(
2822
+ KeepButton,
2823
+ {
2824
+ ...resolvedButtonProps,
2825
+ item,
2826
+ asChild: false,
2827
+ ref: triggerRef,
2828
+ "aria-haspopup": "dialog",
2829
+ "aria-expanded": isOpen,
2830
+ "aria-controls": panelId
2831
+ }
2832
+ ),
2833
+ isOpen && currentItem ? /* @__PURE__ */ jsx8(
2834
+ KeepSavePopoverPanel,
2835
+ {
2836
+ id: panelId,
2837
+ titleId,
2838
+ dialogLabel: dialogLabel ?? editSavedItemLabel,
2839
+ item: currentItem,
2840
+ editorProps,
2841
+ triggerRef,
2842
+ onClose: () => setOpen(false),
2843
+ children
2844
+ }
2845
+ ) : null
2846
+ ] });
2847
+ }
2848
+ function KeepSavePopoverPanel({
2849
+ id,
2850
+ titleId,
2851
+ dialogLabel,
2852
+ item,
2853
+ editorProps,
2854
+ triggerRef,
2855
+ onClose,
2856
+ children
2857
+ }) {
2858
+ const { debounceMs, onSaved, onSaveError, ...editorViewProps } = editorProps ?? {};
2859
+ const { state } = useKeepQuickEditor(item, { debounceMs, onSaved, onSaveError });
2860
+ const panelRef = useRef5(null);
2861
+ const closingRef = useRef5(null);
2862
+ const closeLabel = useUiLabel("close");
2863
+ const requestClose = useCallback3(() => {
2864
+ if (closingRef.current) return closingRef.current;
2865
+ const promise = state.flush().then(onClose).catch(() => {
2866
+ window.setTimeout(() => panelRef.current?.querySelector('[role="alert"]')?.focus(), 0);
2867
+ }).finally(() => {
2868
+ closingRef.current = null;
2869
+ });
2870
+ closingRef.current = promise;
2871
+ return promise;
2872
+ }, [onClose, state]);
2873
+ useEffect4(() => {
2874
+ const frame = window.requestAnimationFrame(() => {
2875
+ panelRef.current?.querySelector('[data-keepkit="quick-editor"] :is(textarea, input, select, button)')?.focus();
2876
+ });
2877
+ return () => window.cancelAnimationFrame(frame);
2878
+ }, []);
2879
+ useEffect4(() => {
2880
+ const closeFromOutside = (event) => {
2881
+ const target = event.target;
2882
+ if (!(target instanceof Node) || panelRef.current?.contains(target) || triggerRef.current?.contains(target))
2883
+ return;
2884
+ void requestClose();
2885
+ };
2886
+ document.addEventListener("pointerdown", closeFromOutside);
2887
+ return () => document.removeEventListener("pointerdown", closeFromOutside);
2888
+ }, [requestClose, triggerRef]);
2889
+ return /* @__PURE__ */ jsxs6(
2890
+ "div",
2891
+ {
2892
+ ref: panelRef,
2893
+ id,
2894
+ role: "dialog",
2895
+ "aria-labelledby": titleId,
2896
+ "data-keep-popover-panel": "true",
2897
+ "data-save-status": state.saveStatus,
2898
+ onKeyDownCapture: (event) => {
2899
+ if (event.key !== "Escape") return;
2900
+ event.preventDefault();
2901
+ event.stopPropagation();
2902
+ void requestClose();
2903
+ },
2904
+ children: [
2905
+ /* @__PURE__ */ jsx8("h2", { id: titleId, "data-keep-popover-title": "true", children: dialogLabel }),
2906
+ children,
2907
+ /* @__PURE__ */ jsx8(KeepQuickEditorView, { ...editorViewProps, state, focusScopeRef: panelRef }),
2908
+ /* @__PURE__ */ jsx8(
2909
+ "button",
2910
+ {
2911
+ type: "button",
2912
+ onClick: () => void requestClose(),
2913
+ disabled: state.isSaving,
2914
+ "data-keep-action": "close-save-popover",
2915
+ children: closeLabel
2916
+ }
2917
+ )
2918
+ ]
2919
+ }
2920
+ );
2921
+ }
2922
+
2210
2923
  // src/features/actions/hooks/useKeepUndo.ts
2211
- import { useKeepContext as useKeepContext2 } from "@keepkit/core/react";
2212
- import { useEffect as useEffect3, useState as useState3 } from "react";
2924
+ import { useKeepContext as useKeepContext3 } from "@keepkit/core/react";
2925
+ import { useEffect as useEffect5, useState as useState5 } from "react";
2213
2926
  function useKeepUndo() {
2214
- const context = useKeepContext2();
2927
+ const context = useKeepContext3();
2215
2928
  const emitFeedback = useKeepUiFeedback();
2216
2929
  const restoredMessage = useUiLabel("restoredMessage");
2217
2930
  const { canUndo, startedAt, expiresAt } = context.undo;
2218
- const [now, setNow] = useState3(() => Date.now());
2219
- useEffect3(() => {
2931
+ const [now, setNow] = useState5(() => Date.now());
2932
+ useEffect5(() => {
2220
2933
  if (!canUndo || expiresAt === void 0) return;
2221
2934
  setNow(Date.now());
2222
2935
  const timer = setInterval(() => setNow(Date.now()), 250);
@@ -2245,17 +2958,17 @@ function useKeepUndo() {
2245
2958
  }
2246
2959
 
2247
2960
  // src/features/actions/KeepUndo.tsx
2248
- import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
2961
+ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
2249
2962
  function KeepUndo({ children, label, ...props }) {
2250
2963
  const view = useKeepUndo();
2251
2964
  if (!view.canUndo) return null;
2252
- return /* @__PURE__ */ jsxs4("div", { ...props, role: "status", "aria-live": "polite", "data-keepkit": "undo", "data-state": "available", children: [
2253
- /* @__PURE__ */ jsx7("span", { "data-keepkit": "undo-message", children: children ?? view.message }),
2254
- /* @__PURE__ */ jsxs4("span", { "data-keepkit": "undo-countdown", "aria-hidden": "true", children: [
2965
+ return /* @__PURE__ */ jsxs7("div", { ...props, role: "status", "aria-live": "polite", "data-keepkit": "undo", "data-state": "available", children: [
2966
+ /* @__PURE__ */ jsx9("span", { "data-keepkit": "undo-message", children: children ?? view.message }),
2967
+ /* @__PURE__ */ jsxs7("span", { "data-keepkit": "undo-countdown", "aria-hidden": "true", children: [
2255
2968
  view.remainingSeconds,
2256
2969
  "s"
2257
2970
  ] }),
2258
- /* @__PURE__ */ jsx7(
2971
+ /* @__PURE__ */ jsx9(
2259
2972
  "progress",
2260
2973
  {
2261
2974
  "data-keepkit": "undo-progress",
@@ -2265,7 +2978,7 @@ function KeepUndo({ children, label, ...props }) {
2265
2978
  "aria-valuetext": `${view.remainingSeconds}s`
2266
2979
  }
2267
2980
  ),
2268
- /* @__PURE__ */ jsx7("button", { type: "button", "data-keep-action": "undo", onClick: () => void view.undo(), children: label ?? view.label })
2981
+ /* @__PURE__ */ jsx9("button", { type: "button", "data-keep-action": "undo", onClick: () => void view.undo(), children: label ?? view.label })
2269
2982
  ] });
2270
2983
  }
2271
2984
 
@@ -2275,9 +2988,9 @@ import { KeepErrorBoundary as KeepErrorBoundary2 } from "@keepkit/core/react";
2275
2988
  // src/features/query/KeepActiveFiltersSummary.tsx
2276
2989
  import {
2277
2990
  isValidElement as isValidElement2,
2278
- useRef as useRef4
2991
+ useRef as useRef6
2279
2992
  } from "react";
2280
- import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
2993
+ import { Fragment as Fragment5, jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
2281
2994
  function KeepActiveFiltersSummary({
2282
2995
  query,
2283
2996
  search: providedSearch,
@@ -2297,7 +3010,7 @@ function KeepActiveFiltersSummary({
2297
3010
  const clearAllLabel = useUiLabel("clearAllFilters");
2298
3011
  const clearLabel = useUiLabel("clearFilters");
2299
3012
  const removeLabel = useUiLabel("removeFilter");
2300
- const chipRefs = useRef4([]);
3013
+ const chipRefs = useRef6([]);
2301
3014
  const filterCount = Number(Boolean(search)) + tags.length;
2302
3015
  function focusChip(index) {
2303
3016
  chipRefs.current[index]?.focus();
@@ -2338,12 +3051,12 @@ function KeepActiveFiltersSummary({
2338
3051
  removeTag: (tag) => onTagChange?.(tag)
2339
3052
  };
2340
3053
  const contentChildren = asChild && isElement(children) ? void 0 : children;
2341
- const body = typeof contentChildren === "function" ? contentChildren(state) : contentChildren ?? (hasFilters ? /* @__PURE__ */ jsxs5(Fragment4, { children: [
2342
- /* @__PURE__ */ jsx8("span", { "data-active-filters-label": "true", children: activeFiltersLabel }),
2343
- /* @__PURE__ */ jsxs5("ul", { "data-active-filters-list": "true", children: [
2344
- search ? /* @__PURE__ */ jsxs5("li", { "data-filter-kind": "search", children: [
2345
- /* @__PURE__ */ jsx8("span", { "data-filter-value": "true", children: search }),
2346
- /* @__PURE__ */ jsx8(
3054
+ const body = typeof contentChildren === "function" ? contentChildren(state) : contentChildren ?? (hasFilters ? /* @__PURE__ */ jsxs8(Fragment5, { children: [
3055
+ /* @__PURE__ */ jsx10("span", { "data-active-filters-label": "true", children: activeFiltersLabel }),
3056
+ /* @__PURE__ */ jsxs8("ul", { "data-active-filters-list": "true", children: [
3057
+ search ? /* @__PURE__ */ jsxs8("li", { "data-filter-kind": "search", children: [
3058
+ /* @__PURE__ */ jsx10("span", { "data-filter-value": "true", children: search }),
3059
+ /* @__PURE__ */ jsx10(
2347
3060
  "button",
2348
3061
  {
2349
3062
  type: "button",
@@ -2358,9 +3071,9 @@ function KeepActiveFiltersSummary({
2358
3071
  }
2359
3072
  )
2360
3073
  ] }) : null,
2361
- tags.map((tag, tagIndex) => /* @__PURE__ */ jsxs5("li", { "data-filter-kind": "tag", children: [
2362
- /* @__PURE__ */ jsx8("span", { "data-filter-value": "true", children: tag }),
2363
- /* @__PURE__ */ jsx8(
3074
+ tags.map((tag, tagIndex) => /* @__PURE__ */ jsxs8("li", { "data-filter-kind": "tag", children: [
3075
+ /* @__PURE__ */ jsx10("span", { "data-filter-value": "true", children: tag }),
3076
+ /* @__PURE__ */ jsx10(
2364
3077
  "button",
2365
3078
  {
2366
3079
  type: "button",
@@ -2376,7 +3089,7 @@ function KeepActiveFiltersSummary({
2376
3089
  )
2377
3090
  ] }, tag))
2378
3091
  ] }),
2379
- /* @__PURE__ */ jsx8("button", { type: "button", "data-keep-action": "clear-filters", onClick: state.clear, children: clearAllLabel || clearLabel })
3092
+ /* @__PURE__ */ jsx10("button", { type: "button", "data-keep-action": "clear-filters", onClick: state.clear, children: clearAllLabel || clearLabel })
2380
3093
  ] }) : null);
2381
3094
  if (!hasFilters && !asChild && contentChildren === void 0) return null;
2382
3095
  return renderRoot(
@@ -2417,21 +3130,113 @@ function focusFilterFallback(scope) {
2417
3130
  }
2418
3131
  }
2419
3132
 
3133
+ // src/features/query/KeepCollectionFilter.tsx
3134
+ import { useKeepContext as useKeepContext4 } from "@keepkit/core/react";
3135
+ import { useMemo as useMemo3, useState as useState6 } from "react";
3136
+ import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
3137
+ function useCollectionOptions(collectionLabels, items) {
3138
+ const ids = useMemo3(
3139
+ () => [...new Set((items ?? []).map((item) => item.collectionId).filter((id) => Boolean(id)))].sort(),
3140
+ [items]
3141
+ );
3142
+ return ids.map((id) => ({ id, label: collectionLabels?.[id] ?? id }));
3143
+ }
3144
+ function KeepCollectionSelect({
3145
+ item,
3146
+ value,
3147
+ defaultValue,
3148
+ onValueChange,
3149
+ onChange,
3150
+ collectionLabels,
3151
+ uncategorizedLabel,
3152
+ ...props
3153
+ }) {
3154
+ const context = useKeepContext4();
3155
+ const state = useState6(value ?? defaultValue ?? item.collectionId ?? "");
3156
+ const selected = value ?? state[0];
3157
+ const options = useCollectionOptions(collectionLabels, context.items);
3158
+ const defaultUncategorizedLabel = useUiLabel("uncategorized");
3159
+ const uncategorized = uncategorizedLabel ?? defaultUncategorizedLabel;
3160
+ const handleChange = (next) => {
3161
+ const resolved = next || void 0;
3162
+ if (value === void 0) state[1](next);
3163
+ onValueChange?.(resolved);
3164
+ onChange?.(resolved);
3165
+ void context.moveToCollection(item.id, resolved);
3166
+ };
3167
+ return /* @__PURE__ */ jsxs9(
3168
+ "select",
3169
+ {
3170
+ ...props,
3171
+ value: selected,
3172
+ onChange: (event) => handleChange(event.currentTarget.value),
3173
+ "data-keep-action": "move-collection",
3174
+ children: [
3175
+ /* @__PURE__ */ jsx11("option", { value: "", children: uncategorized }),
3176
+ options.map((option) => /* @__PURE__ */ jsx11("option", { value: option.id, children: option.label }, option.id))
3177
+ ]
3178
+ }
3179
+ );
3180
+ }
3181
+ function KeepCollectionFilter({
3182
+ value,
3183
+ defaultValue,
3184
+ onValueChange,
3185
+ onChange,
3186
+ collectionLabels,
3187
+ allLabel,
3188
+ uncategorizedLabel,
3189
+ ...props
3190
+ }) {
3191
+ const context = useKeepContext4();
3192
+ const [internalValue, setInternalValue] = useState6(value ?? defaultValue ?? "");
3193
+ const selected = value ?? internalValue;
3194
+ const options = useCollectionOptions(collectionLabels, context.items);
3195
+ const collectionLabel = useUiLabel("collection");
3196
+ const defaultAllLabel = useUiLabel("allCollections");
3197
+ const defaultUncategorizedLabel = useUiLabel("uncategorized");
3198
+ const all = allLabel ?? defaultAllLabel;
3199
+ const uncategorized = uncategorizedLabel ?? defaultUncategorizedLabel;
3200
+ const handleChange = (next) => {
3201
+ if (value === void 0) setInternalValue(next);
3202
+ const resolved = next || void 0;
3203
+ onValueChange?.(resolved);
3204
+ onChange?.(resolved);
3205
+ };
3206
+ return /* @__PURE__ */ jsxs9("label", { "data-keepkit": "collection-filter", children: [
3207
+ /* @__PURE__ */ jsx11("span", { children: collectionLabel }),
3208
+ /* @__PURE__ */ jsxs9(
3209
+ "select",
3210
+ {
3211
+ ...props,
3212
+ value: selected,
3213
+ onChange: (event) => handleChange(event.currentTarget.value),
3214
+ "data-keep-action": "filter-collection",
3215
+ children: [
3216
+ /* @__PURE__ */ jsx11("option", { value: "", children: all }),
3217
+ /* @__PURE__ */ jsx11("option", { value: "__uncategorized__", children: uncategorized }),
3218
+ options.map((option) => /* @__PURE__ */ jsx11("option", { value: option.id, children: option.label }, option.id))
3219
+ ]
3220
+ }
3221
+ )
3222
+ ] });
3223
+ }
3224
+
2420
3225
  // src/features/query/KeepTagFilter.tsx
2421
3226
  import { isValidElement as isValidElement3 } from "react";
2422
3227
 
2423
3228
  // src/features/query/hooks/useKeepTagFilter.ts
2424
3229
  import { useKeepList as useKeepList2 } from "@keepkit/core/react";
2425
- import { useCallback as useCallback2, useMemo as useMemo3, useState as useState4 } from "react";
3230
+ import { useCallback as useCallback4, useMemo as useMemo4, useState as useState7 } from "react";
2426
3231
  function useKeepTagFilter(options) {
2427
3232
  const { query, controlledValue, defaultValue, onChange, onValueChange } = options;
2428
- const [uncontrolledValue, setUncontrolledValue] = useState4(defaultValue);
3233
+ const [uncontrolledValue, setUncontrolledValue] = useState7(defaultValue);
2429
3234
  const resolvedValue = controlledValue ?? uncontrolledValue;
2430
3235
  const list = useKeepList2({
2431
3236
  ...query,
2432
3237
  tags: resolvedValue ? [...query?.tags ?? [], resolvedValue] : query?.tags
2433
3238
  });
2434
- const select = useCallback2(
3239
+ const select = useCallback4(
2435
3240
  (tag) => {
2436
3241
  if (controlledValue === void 0) setUncontrolledValue(tag);
2437
3242
  onChange?.(tag);
@@ -2439,7 +3244,7 @@ function useKeepTagFilter(options) {
2439
3244
  },
2440
3245
  [controlledValue, onChange, onValueChange]
2441
3246
  );
2442
- const state = useMemo3(
3247
+ const state = useMemo4(
2443
3248
  () => ({ tags: list.tags, tagCounts: list.tagCounts, value: resolvedValue, select }),
2444
3249
  [list.tagCounts, list.tags, resolvedValue, select]
2445
3250
  );
@@ -2451,7 +3256,7 @@ function useKeepTagFilter(options) {
2451
3256
  }
2452
3257
 
2453
3258
  // src/features/query/KeepTagFilter.tsx
2454
- import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
3259
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
2455
3260
  function KeepTagFilter({
2456
3261
  query,
2457
3262
  value: controlledValue,
@@ -2469,9 +3274,9 @@ function KeepTagFilter({
2469
3274
  }) {
2470
3275
  const view = useKeepTagFilter({ query, controlledValue, defaultValue, onChange, onValueChange });
2471
3276
  const contentChildren = asChild && isValidElement3(children) ? void 0 : children;
2472
- const body = render ? render(view.state) : typeof contentChildren === "function" ? contentChildren(view.state) : contentChildren ?? /* @__PURE__ */ jsxs6("fieldset", { children: [
2473
- /* @__PURE__ */ jsx9("legend", { children: ariaLabel ?? view.labels.aria }),
2474
- /* @__PURE__ */ jsx9(
3277
+ const body = render ? render(view.state) : typeof contentChildren === "function" ? contentChildren(view.state) : contentChildren ?? /* @__PURE__ */ jsxs10("fieldset", { children: [
3278
+ /* @__PURE__ */ jsx12("legend", { children: ariaLabel ?? view.labels.aria }),
3279
+ /* @__PURE__ */ jsx12(
2475
3280
  "button",
2476
3281
  {
2477
3282
  type: "button",
@@ -2481,7 +3286,7 @@ function KeepTagFilter({
2481
3286
  children: allLabel ?? view.labels.all
2482
3287
  }
2483
3288
  ),
2484
- view.state.tags.map((tag) => /* @__PURE__ */ jsxs6(
3289
+ view.state.tags.map((tag) => /* @__PURE__ */ jsxs10(
2485
3290
  "button",
2486
3291
  {
2487
3292
  type: "button",
@@ -2490,7 +3295,7 @@ function KeepTagFilter({
2490
3295
  onClick: () => view.state.select(tag),
2491
3296
  children: [
2492
3297
  renderTag ? renderTag(tag, view.state.tagCounts[tag] ?? 0, view.state.value === tag) : tag,
2493
- /* @__PURE__ */ jsxs6("span", { children: [
3298
+ /* @__PURE__ */ jsxs10("span", { children: [
2494
3299
  " (",
2495
3300
  view.state.tagCounts[tag] ?? 0,
2496
3301
  ")"
@@ -2516,12 +3321,12 @@ function KeepTagFilter({
2516
3321
  }
2517
3322
 
2518
3323
  // src/features/query/hooks/useQueryControls.ts
2519
- import { useEffect as useEffect4, useState as useState5 } from "react";
3324
+ import { useEffect as useEffect6, useState as useState8 } from "react";
2520
3325
  function useKeepSearchInput(options) {
2521
3326
  const { controlledValue, defaultValue, debounceMs, onValueChange } = options;
2522
- const [uncontrolledValue, setUncontrolledValue] = useState5(defaultValue);
3327
+ const [uncontrolledValue, setUncontrolledValue] = useState8(defaultValue);
2523
3328
  const value = controlledValue ?? uncontrolledValue;
2524
- useEffect4(() => {
3329
+ useEffect6(() => {
2525
3330
  if (!onValueChange) return;
2526
3331
  if (debounceMs <= 0) {
2527
3332
  onValueChange(value);
@@ -2540,7 +3345,7 @@ function useKeepSearchInput(options) {
2540
3345
  }
2541
3346
  function useKeepSortSelect(options) {
2542
3347
  const { controlledValue, defaultValue, onValueChange } = options;
2543
- const [uncontrolledValue, setUncontrolledValue] = useState5(defaultValue);
3348
+ const [uncontrolledValue, setUncontrolledValue] = useState8(defaultValue);
2544
3349
  const value = controlledValue ?? uncontrolledValue;
2545
3350
  return {
2546
3351
  value,
@@ -2588,7 +3393,7 @@ function getVisiblePages(currentPage, pageCount, maxPageButtons) {
2588
3393
  }
2589
3394
 
2590
3395
  // src/features/query/query-controls.tsx
2591
- import { Fragment as Fragment5, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
3396
+ import { Fragment as Fragment6, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
2592
3397
  function KeepSearchInput({
2593
3398
  value: controlledValue,
2594
3399
  defaultValue = "",
@@ -2599,7 +3404,7 @@ function KeepSearchInput({
2599
3404
  ...props
2600
3405
  }) {
2601
3406
  const view = useKeepSearchInput({ controlledValue, defaultValue, debounceMs, onValueChange });
2602
- return /* @__PURE__ */ jsx10(
3407
+ return /* @__PURE__ */ jsx13(
2603
3408
  "input",
2604
3409
  {
2605
3410
  ...props,
@@ -2624,13 +3429,13 @@ function KeepSortSelect({
2624
3429
  ...props
2625
3430
  }) {
2626
3431
  const view = useKeepSortSelect({ controlledValue, defaultValue, onValueChange });
2627
- const options = children ?? /* @__PURE__ */ jsxs7(Fragment5, { children: [
2628
- /* @__PURE__ */ jsx10("option", { value: "updatedAt:desc", children: view.labels.updatedNewest }),
2629
- /* @__PURE__ */ jsx10("option", { value: "updatedAt:asc", children: view.labels.updatedOldest }),
2630
- /* @__PURE__ */ jsx10("option", { value: "savedAt:desc", children: view.labels.savedNewest }),
2631
- /* @__PURE__ */ jsx10("option", { value: "savedAt:asc", children: view.labels.savedOldest })
3432
+ const options = children ?? /* @__PURE__ */ jsxs11(Fragment6, { children: [
3433
+ /* @__PURE__ */ jsx13("option", { value: "updatedAt:desc", children: view.labels.updatedNewest }),
3434
+ /* @__PURE__ */ jsx13("option", { value: "updatedAt:asc", children: view.labels.updatedOldest }),
3435
+ /* @__PURE__ */ jsx13("option", { value: "savedAt:desc", children: view.labels.savedNewest }),
3436
+ /* @__PURE__ */ jsx13("option", { value: "savedAt:asc", children: view.labels.savedOldest })
2632
3437
  ] });
2633
- return /* @__PURE__ */ jsx10(
3438
+ return /* @__PURE__ */ jsx13(
2634
3439
  "select",
2635
3440
  {
2636
3441
  ...props,
@@ -2662,9 +3467,9 @@ function KeepPagination({
2662
3467
  "data-state": view.pageCount > 1 ? "active" : "idle"
2663
3468
  };
2664
3469
  if (render)
2665
- return /* @__PURE__ */ jsx10("nav", { ...navProps, children: render({ page: view.currentPage, pageCount: view.pageCount, goToPage: view.goToPage }) });
2666
- return /* @__PURE__ */ jsxs7("nav", { ...navProps, children: [
2667
- /* @__PURE__ */ jsx10(
3470
+ return /* @__PURE__ */ jsx13("nav", { ...navProps, children: render({ page: view.currentPage, pageCount: view.pageCount, goToPage: view.goToPage }) });
3471
+ return /* @__PURE__ */ jsxs11("nav", { ...navProps, children: [
3472
+ /* @__PURE__ */ jsx13(
2668
3473
  "button",
2669
3474
  {
2670
3475
  type: "button",
@@ -2674,7 +3479,7 @@ function KeepPagination({
2674
3479
  children: view.labels.previous
2675
3480
  }
2676
3481
  ),
2677
- view.visiblePages.map((nextPage) => /* @__PURE__ */ jsx10(
3482
+ view.visiblePages.map((nextPage) => /* @__PURE__ */ jsx13(
2678
3483
  "button",
2679
3484
  {
2680
3485
  type: "button",
@@ -2686,7 +3491,7 @@ function KeepPagination({
2686
3491
  },
2687
3492
  nextPage
2688
3493
  )),
2689
- /* @__PURE__ */ jsx10(
3494
+ /* @__PURE__ */ jsx13(
2690
3495
  "button",
2691
3496
  {
2692
3497
  type: "button",
@@ -2701,7 +3506,7 @@ function KeepPagination({
2701
3506
 
2702
3507
  // src/features/collection/hooks/useKeepCollection.ts
2703
3508
  import { useKeepList as useKeepList3 } from "@keepkit/core/react";
2704
- import { useMemo as useMemo4, useState as useState6 } from "react";
3509
+ import { useMemo as useMemo5, useState as useState9 } from "react";
2705
3510
  function useKeepCollection({
2706
3511
  query,
2707
3512
  pageSize,
@@ -2714,23 +3519,38 @@ function useKeepCollection({
2714
3519
  sort: true,
2715
3520
  pagination: true,
2716
3521
  tagFilter: false,
3522
+ collectionFilter: false,
2717
3523
  bulkActions: false,
2718
3524
  ...features
2719
3525
  };
2720
- const [searchValue, setSearchValue] = useState6(query.search?.query ?? "");
2721
- const [sort, setSort] = useState6(query.sort ?? { by: "updatedAt", direction: "desc" });
2722
- const [activeTags, setActiveTags] = useState6(query.tags ?? []);
2723
- const [page, setPage] = useState6(query.pagination?.page ?? 1);
3526
+ const [searchValue, setSearchValue] = useState9(query.search?.query ?? "");
3527
+ const [sort, setSort] = useState9(query.sort ?? { by: "updatedAt", direction: "desc" });
3528
+ const [activeTags, setActiveTags] = useState9(query.tags ?? []);
3529
+ const [activeCollection, setActiveCollection] = useState9(query.collectionId);
3530
+ const [page, setPage] = useState9(query.pagination?.page ?? 1);
2724
3531
  const resolvedPageSize = query.pagination?.pageSize ?? pageSize;
2725
- const resolvedQuery = useMemo4(
3532
+ const resolvedQuery = useMemo5(
2726
3533
  () => ({
2727
3534
  ...query,
2728
3535
  search: enabled.search ? { ...query.search, query: searchValue } : query.search,
2729
3536
  sort: enabled.sort ? sort : query.sort,
2730
3537
  tags: activeTags.length > 0 ? activeTags : void 0,
3538
+ collectionId: activeCollection && activeCollection !== "__uncategorized__" ? activeCollection : void 0,
3539
+ filter: activeCollection === "__uncategorized__" ? (item) => item.collectionId === void 0 && (query.filter?.(item) ?? true) : query.filter,
2731
3540
  pagination: enabled.pagination ? { ...query.pagination, page, pageSize: resolvedPageSize } : query.pagination
2732
3541
  }),
2733
- [activeTags, enabled.pagination, enabled.search, enabled.sort, page, query, resolvedPageSize, searchValue, sort]
3542
+ [
3543
+ activeCollection,
3544
+ activeTags,
3545
+ enabled.pagination,
3546
+ enabled.search,
3547
+ enabled.sort,
3548
+ page,
3549
+ query,
3550
+ resolvedPageSize,
3551
+ searchValue,
3552
+ sort
3553
+ ]
2734
3554
  );
2735
3555
  useKeepUrlSync({
2736
3556
  enabled: Boolean(urlSync),
@@ -2740,6 +3560,7 @@ function useKeepCollection({
2740
3560
  setSearchValue(next.search?.query ?? "");
2741
3561
  setSort(next.sort ?? { by: "updatedAt", direction: "desc" });
2742
3562
  setActiveTags(next.tags ?? []);
3563
+ setActiveCollection(next.collectionId);
2743
3564
  setPage(next.pagination?.page ?? 1);
2744
3565
  },
2745
3566
  options: typeof urlSync === "object" ? urlSync : {},
@@ -2752,6 +3573,7 @@ function useKeepCollection({
2752
3573
  searchValue,
2753
3574
  sortValue: sortToValue(sort),
2754
3575
  activeTags,
3576
+ activeCollection,
2755
3577
  resolvedPageSize,
2756
3578
  resolvedQuery,
2757
3579
  list,
@@ -2768,6 +3590,10 @@ function useKeepCollection({
2768
3590
  setActiveTags(value ? [value] : []);
2769
3591
  setPage(1);
2770
3592
  },
3593
+ setCollection: (value) => {
3594
+ setActiveCollection(value);
3595
+ setPage(1);
3596
+ },
2771
3597
  removeTag: (tagToRemove) => {
2772
3598
  setActiveTags((current) => current.filter((tag) => tag !== tagToRemove));
2773
3599
  setPage(1);
@@ -2775,6 +3601,7 @@ function useKeepCollection({
2775
3601
  clearFilters: () => {
2776
3602
  setSearchValue("");
2777
3603
  setActiveTags([]);
3604
+ setActiveCollection(void 0);
2778
3605
  setPage(1);
2779
3606
  },
2780
3607
  setPage
@@ -2791,8 +3618,8 @@ import {
2791
3618
  createElement as createElement2,
2792
3619
  isValidElement as isValidElement4,
2793
3620
  useContext as useContext3,
2794
- useEffect as useEffect5,
2795
- useState as useState8
3621
+ useEffect as useEffect7,
3622
+ useState as useState11
2796
3623
  } from "react";
2797
3624
 
2798
3625
  // src/features/item/hooks/useKeepItemStatusBadge.ts
@@ -2835,10 +3662,10 @@ function getDisplayStatus(status) {
2835
3662
  }
2836
3663
 
2837
3664
  // src/features/item/KeepItemStatusBadge.tsx
2838
- import { Fragment as Fragment6, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
3665
+ import { Fragment as Fragment7, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
2839
3666
  function KeepItemStatusBadge({ status = "available", label, className, ...props }) {
2840
3667
  const view = useKeepItemStatusBadge(status);
2841
- return /* @__PURE__ */ jsxs8(
3668
+ return /* @__PURE__ */ jsxs12(
2842
3669
  "span",
2843
3670
  {
2844
3671
  ...props,
@@ -2849,14 +3676,14 @@ function KeepItemStatusBadge({ status = "available", label, className, ...props
2849
3676
  "data-status": status,
2850
3677
  "data-item-status": view.resolvedStatus,
2851
3678
  children: [
2852
- /* @__PURE__ */ jsx11(StatusIcon, { name: view.icon }),
2853
- /* @__PURE__ */ jsx11("span", { "data-status-label": "true", children: label ?? view.statusLabel })
3679
+ /* @__PURE__ */ jsx14(StatusIcon, { name: view.icon }),
3680
+ /* @__PURE__ */ jsx14("span", { "data-status-label": "true", children: label ?? view.statusLabel })
2854
3681
  ]
2855
3682
  }
2856
3683
  );
2857
3684
  }
2858
3685
  function StatusIcon({ name }) {
2859
- return /* @__PURE__ */ jsxs8(
3686
+ return /* @__PURE__ */ jsxs12(
2860
3687
  "svg",
2861
3688
  {
2862
3689
  "data-status-icon": name,
@@ -2871,18 +3698,18 @@ function StatusIcon({ name }) {
2871
3698
  "aria-hidden": "true",
2872
3699
  focusable: "false",
2873
3700
  children: [
2874
- name === "check" ? /* @__PURE__ */ jsx11("path", { d: "m5 12 4 4L19 6" }) : null,
2875
- name === "clock" ? /* @__PURE__ */ jsxs8(Fragment6, { children: [
2876
- /* @__PURE__ */ jsx11("circle", { cx: "12", cy: "12", r: "8" }),
2877
- /* @__PURE__ */ jsx11("path", { d: "M12 7v5l3 2" })
3701
+ name === "check" ? /* @__PURE__ */ jsx14("path", { d: "m5 12 4 4L19 6" }) : null,
3702
+ name === "clock" ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
3703
+ /* @__PURE__ */ jsx14("circle", { cx: "12", cy: "12", r: "8" }),
3704
+ /* @__PURE__ */ jsx14("path", { d: "M12 7v5l3 2" })
2878
3705
  ] }) : null,
2879
- name === "ban" ? /* @__PURE__ */ jsxs8(Fragment6, { children: [
2880
- /* @__PURE__ */ jsx11("circle", { cx: "12", cy: "12", r: "8" }),
2881
- /* @__PURE__ */ jsx11("path", { d: "m6.5 6.5 11 11" })
3706
+ name === "ban" ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
3707
+ /* @__PURE__ */ jsx14("circle", { cx: "12", cy: "12", r: "8" }),
3708
+ /* @__PURE__ */ jsx14("path", { d: "m6.5 6.5 11 11" })
2882
3709
  ] }) : null,
2883
- name === "lock" ? /* @__PURE__ */ jsxs8(Fragment6, { children: [
2884
- /* @__PURE__ */ jsx11("rect", { x: "5", y: "10", width: "14", height: "10", rx: "2" }),
2885
- /* @__PURE__ */ jsx11("path", { d: "M8 10V7a4 4 0 0 1 8 0v3" })
3710
+ name === "lock" ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
3711
+ /* @__PURE__ */ jsx14("rect", { x: "5", y: "10", width: "14", height: "10", rx: "2" }),
3712
+ /* @__PURE__ */ jsx14("path", { d: "M8 10V7a4 4 0 0 1 8 0v3" })
2886
3713
  ] }) : null
2887
3714
  ]
2888
3715
  }
@@ -2890,16 +3717,16 @@ function StatusIcon({ name }) {
2890
3717
  }
2891
3718
 
2892
3719
  // src/features/status/hooks/useKeepStaleNotice.ts
2893
- import { useKeepContext as useKeepContext3 } from "@keepkit/core/react";
2894
- import { useState as useState7 } from "react";
3720
+ import { useKeepContext as useKeepContext5 } from "@keepkit/core/react";
3721
+ import { useState as useState10 } from "react";
2895
3722
  function useKeepStaleNotice({ item, onRetry, onRemoved }) {
2896
- const context = useKeepContext3();
3723
+ const context = useKeepContext5();
2897
3724
  const emitFeedback = useKeepUiFeedback();
2898
3725
  const removedMessage = useUiLabel("removedMessage");
2899
3726
  const restoredMessage = useUiLabel("restoredMessage");
2900
3727
  const undoLabel = useUiLabel("undo");
2901
- const [isRetrying, setIsRetrying] = useState7(false);
2902
- const [error, setError] = useState7(null);
3728
+ const [isRetrying, setIsRetrying] = useState10(false);
3729
+ const [error, setError] = useState10(null);
2903
3730
  async function retry() {
2904
3731
  setError(null);
2905
3732
  setIsRetrying(true);
@@ -2945,7 +3772,7 @@ function useKeepStaleNotice({ item, onRetry, onRemoved }) {
2945
3772
  };
2946
3773
  }
2947
3774
  function useKeepPruneStale({ statuses, onPruned }) {
2948
- const context = useKeepContext3();
3775
+ const context = useKeepContext5();
2949
3776
  const emitFeedback = useKeepUiFeedback();
2950
3777
  const staleItems = context.items.filter((item) => item.status && statuses.includes(item.status));
2951
3778
  const staleIds = staleItems.map((item) => item.id);
@@ -2979,7 +3806,7 @@ function useKeepPruneStale({ statuses, onPruned }) {
2979
3806
  }
2980
3807
 
2981
3808
  // src/features/status/KeepStaleNotice.tsx
2982
- import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
3809
+ import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
2983
3810
  function KeepStaleNotice({
2984
3811
  item,
2985
3812
  onRetry,
@@ -2991,11 +3818,11 @@ function KeepStaleNotice({
2991
3818
  ...props
2992
3819
  }) {
2993
3820
  const view = useKeepStaleNotice({ item, onRetry, onRemoved });
2994
- return /* @__PURE__ */ jsxs9("aside", { ...props, className, "data-keepkit": "stale-notice", "data-state": view.error ? "error" : "stale", children: [
2995
- /* @__PURE__ */ jsx12(KeepItemStatusBadge, { status: view.status }),
2996
- children ?? (item.statusReason ? /* @__PURE__ */ jsx12("p", { children: item.statusReason }) : null),
2997
- /* @__PURE__ */ jsxs9("div", { children: [
2998
- /* @__PURE__ */ jsx12(
3821
+ return /* @__PURE__ */ jsxs13("aside", { ...props, className, "data-keepkit": "stale-notice", "data-state": view.error ? "error" : "stale", children: [
3822
+ /* @__PURE__ */ jsx15(KeepItemStatusBadge, { status: view.status }),
3823
+ children ?? (item.statusReason ? /* @__PURE__ */ jsx15("p", { children: item.statusReason }) : null),
3824
+ /* @__PURE__ */ jsxs13("div", { children: [
3825
+ /* @__PURE__ */ jsx15(
2999
3826
  "button",
3000
3827
  {
3001
3828
  type: "button",
@@ -3005,7 +3832,7 @@ function KeepStaleNotice({
3005
3832
  children: retryLabel ?? view.labels.retry
3006
3833
  }
3007
3834
  ),
3008
- /* @__PURE__ */ jsx12(
3835
+ /* @__PURE__ */ jsx15(
3009
3836
  "button",
3010
3837
  {
3011
3838
  type: "button",
@@ -3016,7 +3843,7 @@ function KeepStaleNotice({
3016
3843
  }
3017
3844
  )
3018
3845
  ] }),
3019
- view.error ? /* @__PURE__ */ jsx12("p", { role: "alert", children: view.error instanceof Error ? view.error.message : view.labels.error }) : null
3846
+ view.error ? /* @__PURE__ */ jsx15("p", { role: "alert", children: view.error instanceof Error ? view.error.message : view.labels.error }) : null
3020
3847
  ] });
3021
3848
  }
3022
3849
  function KeepPruneStaleButton({
@@ -3028,7 +3855,7 @@ function KeepPruneStaleButton({
3028
3855
  ...props
3029
3856
  }) {
3030
3857
  const view = useKeepPruneStale({ statuses, onPruned });
3031
- return /* @__PURE__ */ jsx12(
3858
+ return /* @__PURE__ */ jsx15(
3032
3859
  "button",
3033
3860
  {
3034
3861
  ...props,
@@ -3045,7 +3872,7 @@ function KeepPruneStaleButton({
3045
3872
  }
3046
3873
 
3047
3874
  // src/features/item/hooks/useKeepItemCard.ts
3048
- import { useKeepItem as useKeepItem2 } from "@keepkit/core/react";
3875
+ import { useKeepItem as useKeepItem5 } from "@keepkit/core/react";
3049
3876
  function useKeepItemCard(options) {
3050
3877
  const {
3051
3878
  item,
@@ -3058,7 +3885,7 @@ function useKeepItemCard(options) {
3058
3885
  onRemoveError,
3059
3886
  onRemoved
3060
3887
  } = options;
3061
- const itemState = useKeepItem2(item);
3888
+ const itemState = useKeepItem5(item);
3062
3889
  const emitFeedback = useKeepUiFeedback();
3063
3890
  const removedMessage = useUiLabel("removedMessage");
3064
3891
  const restoredMessage = useUiLabel("restoredMessage");
@@ -3141,7 +3968,7 @@ function getDisplayStatus2(status) {
3141
3968
  }
3142
3969
 
3143
3970
  // src/features/item/KeepItemCard.tsx
3144
- import { Fragment as Fragment7, jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
3971
+ import { Fragment as Fragment8, jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
3145
3972
  var KeepItemCardContext = createContext3(null);
3146
3973
  function useKeepItemCardCompound(part) {
3147
3974
  const context = useContext3(KeepItemCardContext);
@@ -3158,6 +3985,7 @@ function KeepItemCardRoot({
3158
3985
  renderTags,
3159
3986
  showTags = true,
3160
3987
  showSavedAt = true,
3988
+ collectionLabels,
3161
3989
  imageAlt,
3162
3990
  render,
3163
3991
  children,
@@ -3201,17 +4029,17 @@ function KeepItemCardRoot({
3201
4029
  onClick: (event) => onOpen?.(item, event),
3202
4030
  children: content
3203
4031
  };
3204
- return LinkComponent ? /* @__PURE__ */ jsx13(LinkComponent, { ...linkProps }) : /* @__PURE__ */ jsx13("a", { ...linkProps });
4032
+ return LinkComponent ? /* @__PURE__ */ jsx16(LinkComponent, { ...linkProps }) : /* @__PURE__ */ jsx16("a", { ...linkProps });
3205
4033
  }
3206
4034
  function renderTitle(content) {
3207
4035
  if (linkTarget !== "title") return content;
3208
4036
  if (view.isAvailable) return renderLink(content);
3209
- return view.href ? /* @__PURE__ */ jsx13("span", { "aria-disabled": "true", "data-link-disabled": "true", children: content }) : content;
4037
+ return view.href ? /* @__PURE__ */ jsx16("span", { "aria-disabled": "true", "data-link-disabled": "true", children: content }) : content;
3210
4038
  }
3211
4039
  const resolvedImageProps = view.imageProps ? { ...view.imageProps, alt: imageAlt ?? view.imageProps.alt } : void 0;
3212
4040
  const imageSource = resolvedImageProps?.src;
3213
- const [imageStatus, setImageStatus] = useState8(imageSource ? "loading" : "error");
3214
- useEffect5(() => {
4041
+ const [imageStatus, setImageStatus] = useState11(imageSource ? "loading" : "error");
4042
+ useEffect7(() => {
3215
4043
  setImageStatus(imageSource ? "loading" : "error");
3216
4044
  }, [imageSource]);
3217
4045
  let image = null;
@@ -3229,40 +4057,26 @@ function KeepItemCardRoot({
3229
4057
  setImageStatus("error");
3230
4058
  }
3231
4059
  };
3232
- image = renderImage?.(imagePropsWithHandlers, item) ?? (ImageComponent ? /* @__PURE__ */ jsx13(ImageComponent, { ...imagePropsWithHandlers }) : /* @__PURE__ */ jsx13("img", { ...imagePropsWithHandlers, alt: imagePropsWithHandlers.alt }));
4060
+ image = renderImage?.(imagePropsWithHandlers, item) ?? (ImageComponent ? /* @__PURE__ */ jsx16(ImageComponent, { ...imagePropsWithHandlers }) : /* @__PURE__ */ jsx16("img", { ...imagePropsWithHandlers, alt: imagePropsWithHandlers.alt }));
3233
4061
  }
3234
4062
  const tags = showTags ? item.tags ?? [] : [];
3235
4063
  const renderedTags = showTags && tags.length > 0 ? renderTags?.(tags, item) ?? null : null;
3236
- const meta = showSavedAt ? /* @__PURE__ */ jsxs10("div", { "data-card-meta": true, children: [
3237
- /* @__PURE__ */ jsxs10("span", { children: [
4064
+ const meta = showSavedAt ? /* @__PURE__ */ jsxs14("div", { "data-card-meta": true, children: [
4065
+ /* @__PURE__ */ jsxs14("span", { children: [
3238
4066
  view.labels.savedAt,
3239
4067
  ":"
3240
4068
  ] }),
3241
4069
  " ",
3242
- /* @__PURE__ */ jsx13("time", { dateTime: new Date(item.savedAt).toISOString(), children: formatSavedAt(item.savedAt) })
4070
+ /* @__PURE__ */ jsx16("time", { dateTime: new Date(item.savedAt).toISOString(), children: formatSavedAt(item.savedAt) })
3243
4071
  ] }) : null;
3244
- const error = view.itemState.error ? /* @__PURE__ */ jsx13("p", { role: "alert", children: getErrorMessage2(view.itemState.error, view.labels.error) }) : null;
3245
- const actions = view.statusLabel ? /* @__PURE__ */ jsx13(KeepStaleNotice, { item, onRetry, onRemoved }) : /* @__PURE__ */ jsxs10(Fragment7, { children: [
3246
- showSaveButton ? /* @__PURE__ */ jsx13(
3247
- KeepButton,
3248
- {
3249
- item: toKeepButtonItem(item),
3250
- labels: saveButtonLabels,
3251
- getAriaLabel: (buttonState) => `${buttonState.isSaved ? view.labels.remove : view.labels.save} ${String(view.resolvedTitle)}`
3252
- }
3253
- ) : null,
3254
- /* @__PURE__ */ jsx13(
3255
- "button",
3256
- {
3257
- type: "button",
3258
- "data-keep-action": "remove-item",
3259
- onClick: () => void view.remove(),
3260
- disabled: view.itemState.isMutating,
3261
- children: removeLabel ?? view.labels.remove
3262
- }
3263
- )
4072
+ const error = view.itemState.error ? /* @__PURE__ */ jsx16("p", { role: "alert", children: getErrorMessage3(view.itemState.error, view.labels.error) }) : null;
4073
+ const actions = view.statusLabel ? /* @__PURE__ */ jsx16(KeepStaleNotice, { item, onRetry, onRemoved }) : /* @__PURE__ */ jsxs14(Fragment8, { children: [
4074
+ showSaveButton ? /* @__PURE__ */ jsx16(KeepItemCardSave, {}) : null,
4075
+ /* @__PURE__ */ jsx16(KeepItemCardRemove, {})
3264
4076
  ] });
3265
4077
  const compoundValue = {
4078
+ item,
4079
+ collectionLabel: item.collectionId ? collectionLabels?.[item.collectionId] ?? item.collectionId : void 0,
3266
4080
  resolvedTitle: view.resolvedTitle,
3267
4081
  renderTitle,
3268
4082
  image: imageStatus === "error" ? null : image,
@@ -3274,12 +4088,17 @@ function KeepItemCardRoot({
3274
4088
  meta,
3275
4089
  error,
3276
4090
  actions,
3277
- renderText: (content) => /* @__PURE__ */ jsx13(KeepHighlight, { query: searchQuery, children: content })
4091
+ saveButtonLabels,
4092
+ removeLabel: removeLabel ?? view.labels.remove,
4093
+ remove: view.remove,
4094
+ isMutating: view.itemState.isMutating,
4095
+ saveAriaLabel: `${view.labels.remove} ${String(view.resolvedTitle)}`,
4096
+ renderText: (content) => /* @__PURE__ */ jsx16(KeepHighlight, { query: searchQuery, children: content })
3278
4097
  };
3279
- const defaultBody = /* @__PURE__ */ jsxs10(Fragment7, { children: [
3280
- /* @__PURE__ */ jsx13(KeepItemCardMedia, {}),
3281
- /* @__PURE__ */ jsx13(KeepItemCardContent, {}),
3282
- /* @__PURE__ */ jsx13(KeepItemCardActions, {})
4098
+ const defaultBody = /* @__PURE__ */ jsxs14(Fragment8, { children: [
4099
+ /* @__PURE__ */ jsx16(KeepItemCardMedia, {}),
4100
+ /* @__PURE__ */ jsx16(KeepItemCardContent, {}),
4101
+ /* @__PURE__ */ jsx16(KeepItemCardActions, {})
3283
4102
  ] });
3284
4103
  const body = render ? render(view.state) : typeof contentChildren === "function" ? contentChildren(view.state) : contentChildren ?? defaultBody;
3285
4104
  const linkedBody = linkTarget === "card" && view.isAvailable ? renderLink(body) : body;
@@ -3300,18 +4119,18 @@ function KeepItemCardRoot({
3300
4119
  linkedBody,
3301
4120
  "KeepItemCard"
3302
4121
  );
3303
- return /* @__PURE__ */ jsx13(KeepItemCardContext.Provider, { value: compoundValue, children: root });
4122
+ return /* @__PURE__ */ jsx16(KeepItemCardContext.Provider, { value: compoundValue, children: root });
3304
4123
  }
3305
4124
  function KeepItemCardMedia({ children, fallback, ...props }) {
3306
4125
  const context = useKeepItemCardCompound("Media");
3307
- return /* @__PURE__ */ jsx13("div", { ...props, "data-keep-card-part": "media", "data-media-status": context.imageStatus, "data-aspect-ratio": "1/1", children: children ?? context.image ?? /* @__PURE__ */ jsx13("span", { role: "img", "aria-label": context.fallbackLabel, "data-keep-card-fallback": "true", children: fallback ?? /* @__PURE__ */ jsx13(KeepMediaPlaceholderIcon, {}) }) });
4126
+ return /* @__PURE__ */ jsx16("div", { ...props, "data-keep-card-part": "media", "data-media-status": context.imageStatus, "data-aspect-ratio": "1/1", children: children ?? context.image ?? /* @__PURE__ */ jsx16("span", { role: "img", "aria-label": context.fallbackLabel, "data-keep-card-fallback": "true", children: fallback ?? /* @__PURE__ */ jsx16(KeepMediaPlaceholderIcon, {}) }) });
3308
4127
  }
3309
4128
  function KeepItemCardContent({ children, ...props }) {
3310
4129
  const context = useKeepItemCardCompound("Content");
3311
- return /* @__PURE__ */ jsx13("div", { ...props, "data-keep-card-part": "content", children: children === void 0 ? /* @__PURE__ */ jsxs10(Fragment7, { children: [
3312
- /* @__PURE__ */ jsx13(KeepItemCardTitle, {}),
4130
+ return /* @__PURE__ */ jsx16("div", { ...props, "data-keep-card-part": "content", children: children === void 0 ? /* @__PURE__ */ jsxs14(Fragment8, { children: [
4131
+ /* @__PURE__ */ jsx16(KeepItemCardTitle, {}),
3313
4132
  context.meta,
3314
- /* @__PURE__ */ jsx13(KeepItemCardTags, {}),
4133
+ /* @__PURE__ */ jsx16(KeepItemCardTags, {}),
3315
4134
  context.error
3316
4135
  ] }) : context.renderText(children) });
3317
4136
  }
@@ -3324,8 +4143,8 @@ function KeepItemCardTitle({ as = "h3", children, ...props }) {
3324
4143
  );
3325
4144
  }
3326
4145
  function KeepMediaPlaceholderIcon() {
3327
- return /* @__PURE__ */ jsxs10("svg", { "data-media-fallback-icon": "true", viewBox: "0 0 24 24", "aria-hidden": "true", children: [
3328
- /* @__PURE__ */ jsx13(
4146
+ return /* @__PURE__ */ jsxs14("svg", { "data-media-fallback-icon": "true", viewBox: "0 0 24 24", "aria-hidden": "true", children: [
4147
+ /* @__PURE__ */ jsx16(
3329
4148
  "path",
3330
4149
  {
3331
4150
  d: "M4 5.5A1.5 1.5 0 0 1 5.5 4h13A1.5 1.5 0 0 1 20 5.5v13a1.5 1.5 0 0 1-1.5 1.5h-13A1.5 1.5 0 0 1 4 18.5v-13Z",
@@ -3333,46 +4152,97 @@ function KeepMediaPlaceholderIcon() {
3333
4152
  stroke: "currentColor"
3334
4153
  }
3335
4154
  ),
3336
- /* @__PURE__ */ jsx13("circle", { cx: "9", cy: "9", r: "1.5", fill: "currentColor" }),
3337
- /* @__PURE__ */ jsx13("path", { d: "m5.5 18 4.5-4.5 3 3 2-2L19 18", fill: "none", stroke: "currentColor" })
4155
+ /* @__PURE__ */ jsx16("circle", { cx: "9", cy: "9", r: "1.5", fill: "currentColor" }),
4156
+ /* @__PURE__ */ jsx16("path", { d: "m5.5 18 4.5-4.5 3 3 2-2L19 18", fill: "none", stroke: "currentColor" })
3338
4157
  ] });
3339
4158
  }
3340
4159
  function KeepItemCardTags({ children, ...props }) {
3341
4160
  const context = useKeepItemCardCompound("Tags");
3342
4161
  if (children === void 0 && context.renderedTags) return context.renderedTags;
3343
4162
  if (children === void 0 && context.tags.length === 0) return null;
3344
- return /* @__PURE__ */ jsx13("ul", { ...props, "aria-label": props["aria-label"] ?? context.tagsLabel, "data-keep-card-part": "tags", children: children ?? context.tags.map((tag) => /* @__PURE__ */ jsx13("li", { children: tag }, tag)) });
4163
+ return /* @__PURE__ */ jsx16("ul", { ...props, "aria-label": props["aria-label"] ?? context.tagsLabel, "data-keep-card-part": "tags", children: children ?? context.tags.map((tag) => /* @__PURE__ */ jsx16("li", { children: tag }, tag)) });
3345
4164
  }
3346
4165
  function KeepItemCardActions({ children, ...props }) {
3347
4166
  const context = useKeepItemCardCompound("Actions");
3348
- return /* @__PURE__ */ jsx13("div", { ...props, "data-keep-card-part": "actions", children: children ?? context.actions });
4167
+ return /* @__PURE__ */ jsx16("div", { ...props, "data-keep-card-part": "actions", children: children ?? context.actions });
4168
+ }
4169
+ function KeepItemCardSave({ labels, getAriaLabel, ...props }) {
4170
+ const context = useKeepItemCardCompound("Save");
4171
+ return /* @__PURE__ */ jsx16(
4172
+ KeepButton,
4173
+ {
4174
+ ...props,
4175
+ item: toKeepButtonItem(context.item),
4176
+ asChild: false,
4177
+ labels: labels ?? context.saveButtonLabels,
4178
+ getAriaLabel: getAriaLabel ?? (() => context.saveAriaLabel)
4179
+ }
4180
+ );
4181
+ }
4182
+ function KeepItemCardRemove({ children, disabled, onClick, ...props }) {
4183
+ const context = useKeepItemCardCompound("Remove");
4184
+ return /* @__PURE__ */ jsx16(
4185
+ "button",
4186
+ {
4187
+ ...props,
4188
+ type: props.type ?? "button",
4189
+ "data-keep-action": "remove-item",
4190
+ disabled: disabled ?? context.isMutating,
4191
+ onClick: (event) => {
4192
+ onClick?.(event);
4193
+ if (!event.defaultPrevented) void context.remove();
4194
+ },
4195
+ children: children ?? context.removeLabel
4196
+ }
4197
+ );
4198
+ }
4199
+ function KeepItemCardPin({ children, ...props }) {
4200
+ const context = useKeepItemCardCompound("Pin");
4201
+ return /* @__PURE__ */ jsx16(KeepPinButton, { ...props, item: context.item, children });
4202
+ }
4203
+ function KeepItemCardArchive({
4204
+ children,
4205
+ ...props
4206
+ }) {
4207
+ const context = useKeepItemCardCompound("Archive");
4208
+ return /* @__PURE__ */ jsx16(KeepArchiveButton, { ...props, item: context.item, children });
4209
+ }
4210
+ function KeepItemCardCollectionBadge({ children, ...props }) {
4211
+ const context = useKeepItemCardCompound("CollectionBadge");
4212
+ if (!context.item.collectionId) return null;
4213
+ return /* @__PURE__ */ jsx16("span", { ...props, "data-keep-card-part": "collection-badge", children: children ?? context.collectionLabel });
3349
4214
  }
3350
4215
  var KeepItemCard = Object.assign(KeepItemCardRoot, {
3351
4216
  Media: KeepItemCardMedia,
3352
4217
  Content: KeepItemCardContent,
3353
4218
  Title: KeepItemCardTitle,
3354
4219
  Tags: KeepItemCardTags,
3355
- Actions: KeepItemCardActions
4220
+ Actions: KeepItemCardActions,
4221
+ Save: KeepItemCardSave,
4222
+ Remove: KeepItemCardRemove,
4223
+ Pin: KeepItemCardPin,
4224
+ Archive: KeepItemCardArchive,
4225
+ CollectionBadge: KeepItemCardCollectionBadge
3356
4226
  });
3357
4227
  function KeepItemCardSkeleton({ layout = "list", ...props }) {
3358
- return /* @__PURE__ */ jsxs10("article", { ...props, "aria-hidden": "true", "data-keepkit": "card-skeleton", "data-layout": layout, "data-state": "loading", children: [
3359
- /* @__PURE__ */ jsx13("span", { "data-skeleton-part": "media" }),
3360
- /* @__PURE__ */ jsx13("span", { "data-skeleton-part": "title" }),
3361
- /* @__PURE__ */ jsx13("span", { "data-skeleton-part": "meta" }),
3362
- /* @__PURE__ */ jsx13("span", { "data-skeleton-part": "tag" }),
3363
- /* @__PURE__ */ jsx13("span", { "data-skeleton-part": "tag" })
4228
+ return /* @__PURE__ */ jsxs14("article", { ...props, "aria-hidden": "true", "data-keepkit": "card-skeleton", "data-layout": layout, "data-state": "loading", children: [
4229
+ /* @__PURE__ */ jsx16("span", { "data-skeleton-part": "media" }),
4230
+ /* @__PURE__ */ jsx16("span", { "data-skeleton-part": "title" }),
4231
+ /* @__PURE__ */ jsx16("span", { "data-skeleton-part": "meta" }),
4232
+ /* @__PURE__ */ jsx16("span", { "data-skeleton-part": "tag" }),
4233
+ /* @__PURE__ */ jsx16("span", { "data-skeleton-part": "tag" })
3364
4234
  ] });
3365
4235
  }
3366
4236
  function formatSavedAt(timestamp) {
3367
4237
  return new Date(timestamp).toISOString().slice(0, 10);
3368
4238
  }
3369
- function getErrorMessage2(error, fallback) {
4239
+ function getErrorMessage3(error, fallback) {
3370
4240
  return error instanceof Error ? error.message : fallback;
3371
4241
  }
3372
4242
 
3373
4243
  // src/features/status/KeepEmptyState.tsx
3374
4244
  import { isValidElement as isValidElement5 } from "react";
3375
- import { Fragment as Fragment8, jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
4245
+ import { Fragment as Fragment9, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
3376
4246
  function KeepEmptyState({
3377
4247
  title,
3378
4248
  description,
@@ -3391,10 +4261,10 @@ function KeepEmptyState({
3391
4261
  );
3392
4262
  const clearLabel = useUiLabel("clearFilters");
3393
4263
  const contentChildren = asChild && isValidElement5(children) ? void 0 : children;
3394
- const body = contentChildren ?? /* @__PURE__ */ jsxs11(Fragment8, { children: [
3395
- /* @__PURE__ */ jsx14("h2", { children: title ?? defaultTitle }),
3396
- description ?? /* @__PURE__ */ jsx14("p", { children: defaultDescription }),
3397
- action ?? (resolvedVariant === "empty-filtered" && onClearFilters ? /* @__PURE__ */ jsx14("button", { type: "button", "data-keep-action": "clear-filters", onClick: onClearFilters, children: clearLabel }) : null)
4264
+ const body = contentChildren ?? /* @__PURE__ */ jsxs15(Fragment9, { children: [
4265
+ /* @__PURE__ */ jsx17("h2", { children: title ?? defaultTitle }),
4266
+ description ?? /* @__PURE__ */ jsx17("p", { children: defaultDescription }),
4267
+ action ?? (resolvedVariant === "empty-filtered" && onClearFilters ? /* @__PURE__ */ jsx17("button", { type: "button", "data-keep-action": "clear-filters", onClick: onClearFilters, children: clearLabel }) : null)
3398
4268
  ] });
3399
4269
  return renderRoot(
3400
4270
  asChild,
@@ -3420,17 +4290,17 @@ function useKeepListView(query) {
3420
4290
  }
3421
4291
 
3422
4292
  // src/features/collection/hooks/useRovingTabIndex.ts
3423
- import { useCallback as useCallback3, useEffect as useEffect6, useRef as useRef5 } from "react";
4293
+ import { useCallback as useCallback5, useEffect as useEffect8, useRef as useRef7 } from "react";
3424
4294
  function useRovingTabIndex() {
3425
- const ref = useRef5(null);
3426
- const getItems = useCallback3(() => {
4295
+ const ref = useRef7(null);
4296
+ const getItems = useCallback5(() => {
3427
4297
  const root = ref.current;
3428
4298
  if (!root) return [];
3429
4299
  return Array.from(root.querySelectorAll('[data-keepkit="card"]')).filter(
3430
4300
  (item) => item.getAttribute("aria-hidden") !== "true" && item.getAttribute("data-roving-disabled") !== "true"
3431
4301
  );
3432
4302
  }, []);
3433
- const syncTabIndices = useCallback3(() => {
4303
+ const syncTabIndices = useCallback5(() => {
3434
4304
  const items = getItems();
3435
4305
  if (items.length === 0) return;
3436
4306
  const activeElement = document.activeElement;
@@ -3440,7 +4310,7 @@ function useRovingTabIndex() {
3440
4310
  item.tabIndex = index === activeIndex ? 0 : -1;
3441
4311
  });
3442
4312
  }, [getItems]);
3443
- useEffect6(() => {
4313
+ useEffect8(() => {
3444
4314
  const root = ref.current;
3445
4315
  if (!root) return;
3446
4316
  syncTabIndices();
@@ -3448,7 +4318,7 @@ function useRovingTabIndex() {
3448
4318
  observer.observe(root, { childList: true, subtree: true });
3449
4319
  return () => observer.disconnect();
3450
4320
  }, [syncTabIndices]);
3451
- const onFocusCapture = useCallback3(
4321
+ const onFocusCapture = useCallback5(
3452
4322
  (event) => {
3453
4323
  if (!(event.target instanceof HTMLElement)) return;
3454
4324
  const item = event.target.closest('[data-keepkit="card"]');
@@ -3459,7 +4329,7 @@ function useRovingTabIndex() {
3459
4329
  },
3460
4330
  [getItems]
3461
4331
  );
3462
- const onKeyDown = useCallback3(
4332
+ const onKeyDown = useCallback5(
3463
4333
  (event) => {
3464
4334
  if (event.defaultPrevented) return;
3465
4335
  const items = getItems();
@@ -3485,12 +4355,12 @@ function useRovingTabIndex() {
3485
4355
  }
3486
4356
 
3487
4357
  // src/features/collection/KeepList.tsx
3488
- import { Fragment as Fragment9, jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
4358
+ import { Fragment as Fragment10, jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
3489
4359
  function KeepList(props) {
3490
4360
  const { fallback, onBoundaryError, boundaryResetKey, ...listProps } = props;
3491
- const content = /* @__PURE__ */ jsx15(KeepListContent, { ...listProps });
4361
+ const content = /* @__PURE__ */ jsx18(KeepListContent, { ...listProps });
3492
4362
  if (fallback === void 0 && onBoundaryError === void 0) return content;
3493
- return /* @__PURE__ */ jsx15(KeepErrorBoundary, { fallback, onError: onBoundaryError, resetKey: boundaryResetKey, children: content });
4363
+ return /* @__PURE__ */ jsx18(KeepErrorBoundary, { fallback, onError: onBoundaryError, resetKey: boundaryResetKey, children: content });
3494
4364
  }
3495
4365
  function KeepListContent({
3496
4366
  query,
@@ -3550,7 +4420,7 @@ function KeepListContent({
3550
4420
  if (!event.defaultPrevented) roving.onFocusCapture(event);
3551
4421
  }
3552
4422
  },
3553
- /* @__PURE__ */ jsx15(KeepSearchQueryProvider, { query: query?.search?.query, children: body }),
4423
+ /* @__PURE__ */ jsx18(KeepSearchQueryProvider, { query: query?.search?.query, children: body }),
3554
4424
  "KeepList"
3555
4425
  );
3556
4426
  }
@@ -3565,17 +4435,17 @@ function getListBody(state, options) {
3565
4435
  if (state.isLoading && !state.isHydrated) {
3566
4436
  if (options.loading !== void 0) return resolveContent(options.loading, state);
3567
4437
  const count = Number.isFinite(options.loadingCount) ? Math.max(0, Math.floor(options.loadingCount)) : 6;
3568
- return /* @__PURE__ */ jsxs12(Fragment9, { children: [
3569
- /* @__PURE__ */ jsx15("span", { role: "status", "data-keepkit": "loading-label", children: options.loadingLabel }),
3570
- /* @__PURE__ */ jsx15("ul", { "data-keepkit": "skeleton-list", "data-layout": options.layout, children: Array.from({ length: count }, (_, index) => (
4438
+ return /* @__PURE__ */ jsxs16(Fragment10, { children: [
4439
+ /* @__PURE__ */ jsx18("span", { role: "status", "data-keepkit": "loading-label", children: options.loadingLabel }),
4440
+ /* @__PURE__ */ jsx18("ul", { "data-keepkit": "skeleton-list", "data-layout": options.layout, children: Array.from({ length: count }, (_, index) => (
3571
4441
  // biome-ignore lint/suspicious/noArrayIndexKey: Static loading placeholders never reorder.
3572
- /* @__PURE__ */ jsx15("li", { children: /* @__PURE__ */ jsx15(KeepItemCardSkeleton, { layout: options.layout }) }, index)
4442
+ /* @__PURE__ */ jsx18("li", { children: /* @__PURE__ */ jsx18(KeepItemCardSkeleton, { layout: options.layout }) }, index)
3573
4443
  )) })
3574
4444
  ] });
3575
4445
  }
3576
4446
  if (state.isHydrated && state.items.length === 0) {
3577
4447
  if (options.empty !== void 0) return resolveContent(options.empty, state);
3578
- return /* @__PURE__ */ jsx15(
4448
+ return /* @__PURE__ */ jsx18(
3579
4449
  KeepEmptyState,
3580
4450
  {
3581
4451
  variant: options.allItemCount > 0 && hasActiveQueryFilters(options.query) ? "empty-filtered" : "empty-storage",
@@ -3585,24 +4455,24 @@ function getListBody(state, options) {
3585
4455
  }
3586
4456
  if (typeof options.children === "function") return options.children(state);
3587
4457
  if (options.children !== void 0 && !isValidElement6(options.children)) return options.children;
3588
- return /* @__PURE__ */ jsx15("ul", { "data-layout": options.layout, children: state.items.map(
3589
- (item) => options.renderItem ? options.renderItem(item, state) : /* @__PURE__ */ jsx15("li", { children: /* @__PURE__ */ jsx15(KeepItemCard, { item, ...options.itemCardProps }) }, item.id)
4458
+ return /* @__PURE__ */ jsx18("ul", { "data-layout": options.layout, children: state.items.map(
4459
+ (item) => options.renderItem ? options.renderItem(item, state) : /* @__PURE__ */ jsx18("li", { children: /* @__PURE__ */ jsx18(KeepItemCard, { item, ...options.itemCardProps }) }, item.id)
3590
4460
  ) });
3591
4461
  }
3592
4462
  function hasActiveQueryFilters(query) {
3593
4463
  if (!query) return false;
3594
4464
  return Boolean(
3595
- query.search?.query?.trim() || query.tags?.some((tag) => tag.trim()) || query.targetType || query.savedBetween || query.filter
4465
+ query.search?.query?.trim() || query.tags?.some((tag) => tag.trim()) || query.targetType || query.savedBetween || query.archived !== void 0 || query.collectionId || query.filter
3596
4466
  );
3597
4467
  }
3598
4468
 
3599
4469
  // src/features/collection/KeepCollection.tsx
3600
- import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
4470
+ import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
3601
4471
  function KeepCollection(props) {
3602
4472
  const { fallback, onBoundaryError, boundaryResetKey, ...collectionProps } = props;
3603
- const content = /* @__PURE__ */ jsx16(KeepCollectionContent, { ...collectionProps });
4473
+ const content = /* @__PURE__ */ jsx19(KeepCollectionContent, { ...collectionProps });
3604
4474
  if (fallback === void 0 && onBoundaryError === void 0) return content;
3605
- return /* @__PURE__ */ jsx16(KeepErrorBoundary2, { fallback, onError: onBoundaryError, resetKey: boundaryResetKey, children: content });
4475
+ return /* @__PURE__ */ jsx19(KeepErrorBoundary2, { fallback, onError: onBoundaryError, resetKey: boundaryResetKey, children: content });
3606
4476
  }
3607
4477
  function KeepCollectionContent({
3608
4478
  query = {},
@@ -3611,6 +4481,7 @@ function KeepCollectionContent({
3611
4481
  urlSync = false,
3612
4482
  urlAdapter,
3613
4483
  features,
4484
+ collectionLabels,
3614
4485
  renderItem,
3615
4486
  itemCardProps,
3616
4487
  loading,
@@ -3623,7 +4494,7 @@ function KeepCollectionContent({
3623
4494
  ...rootProps
3624
4495
  }) {
3625
4496
  const view = useKeepCollection({ query, pageSize, urlSync, urlAdapter, features });
3626
- return /* @__PURE__ */ jsxs13(
4497
+ return /* @__PURE__ */ jsxs17(
3627
4498
  "section",
3628
4499
  {
3629
4500
  ...rootProps,
@@ -3634,12 +4505,20 @@ function KeepCollectionContent({
3634
4505
  "data-state": getCollectionState(view.list),
3635
4506
  "data-loading": view.list.isLoading || view.list.isMutating ? "true" : void 0,
3636
4507
  children: [
3637
- /* @__PURE__ */ jsxs13("div", { children: [
3638
- view.enabled.search ? /* @__PURE__ */ jsx16(KeepSearchInput, { value: view.searchValue, onValueChange: view.setSearchValue }) : null,
3639
- view.enabled.sort ? /* @__PURE__ */ jsx16(KeepSortSelect, { value: view.sortValue, onValueChange: view.setSortValue }) : null,
3640
- view.enabled.tagFilter ? /* @__PURE__ */ jsx16(KeepTagFilter, { query, value: view.activeTags[0], onValueChange: view.setTag }) : null
4508
+ /* @__PURE__ */ jsxs17("div", { children: [
4509
+ view.enabled.search ? /* @__PURE__ */ jsx19(KeepSearchInput, { value: view.searchValue, onValueChange: view.setSearchValue }) : null,
4510
+ view.enabled.sort ? /* @__PURE__ */ jsx19(KeepSortSelect, { value: view.sortValue, onValueChange: view.setSortValue }) : null,
4511
+ view.enabled.tagFilter ? /* @__PURE__ */ jsx19(KeepTagFilter, { query, value: view.activeTags[0], onValueChange: view.setTag }) : null,
4512
+ view.enabled.collectionFilter ? /* @__PURE__ */ jsx19(
4513
+ KeepCollectionFilter,
4514
+ {
4515
+ value: view.activeCollection,
4516
+ onValueChange: view.setCollection,
4517
+ collectionLabels
4518
+ }
4519
+ ) : null
3641
4520
  ] }),
3642
- activeFilters === void 0 ? /* @__PURE__ */ jsx16(
4521
+ activeFilters === void 0 ? /* @__PURE__ */ jsx19(
3643
4522
  KeepActiveFiltersSummary,
3644
4523
  {
3645
4524
  search: view.searchValue,
@@ -3649,7 +4528,7 @@ function KeepCollectionContent({
3649
4528
  onClear: view.clearFilters
3650
4529
  }
3651
4530
  ) : resolveContent(activeFilters, view.list),
3652
- /* @__PURE__ */ jsx16(
4531
+ /* @__PURE__ */ jsx19(
3653
4532
  KeepList,
3654
4533
  {
3655
4534
  query: view.resolvedQuery,
@@ -3664,7 +4543,7 @@ function KeepCollectionContent({
3664
4543
  error
3665
4544
  }
3666
4545
  ),
3667
- view.enabled.pagination ? /* @__PURE__ */ jsx16(
4546
+ view.enabled.pagination ? /* @__PURE__ */ jsx19(
3668
4547
  KeepPagination,
3669
4548
  {
3670
4549
  totalCount: view.list.totalCount,
@@ -3673,7 +4552,7 @@ function KeepCollectionContent({
3673
4552
  onPageChange: view.setPage
3674
4553
  }
3675
4554
  ) : null,
3676
- view.enabled.bulkActions ? /* @__PURE__ */ jsx16(KeepBulkActions, { query: view.resolvedQuery }) : null
4555
+ view.enabled.bulkActions ? /* @__PURE__ */ jsx19(KeepBulkActions, { query: view.resolvedQuery }) : null
3677
4556
  ]
3678
4557
  }
3679
4558
  );
@@ -3686,12 +4565,12 @@ function getCollectionState(list) {
3686
4565
  }
3687
4566
 
3688
4567
  // src/features/collection/KeepLayout.tsx
3689
- import { jsx as jsx17 } from "react/jsx-runtime";
4568
+ import { jsx as jsx20 } from "react/jsx-runtime";
3690
4569
  function KeepLayout({ layout = "list", children, onKeyDown, onFocusCapture, ...props }) {
3691
4570
  const roving = useRovingTabIndex();
3692
4571
  return (
3693
4572
  // biome-ignore lint/a11y/noStaticElementInteractions: The group manages keyboard focus for descendant cards.
3694
- /* @__PURE__ */ jsx17(
4573
+ /* @__PURE__ */ jsx20(
3695
4574
  "div",
3696
4575
  {
3697
4576
  ...props,
@@ -3715,8 +4594,8 @@ function KeepLayout({ layout = "list", children, onKeyDown, onFocusCapture, ...p
3715
4594
  }
3716
4595
 
3717
4596
  // src/features/collection/KeepReorderableList.tsx
3718
- import { useState as useState9 } from "react";
3719
- import { jsx as jsx18 } from "react/jsx-runtime";
4597
+ import { useState as useState12 } from "react";
4598
+ import { jsx as jsx21 } from "react/jsx-runtime";
3720
4599
  function KeepReorderableList({
3721
4600
  items,
3722
4601
  onReorder,
@@ -3724,8 +4603,8 @@ function KeepReorderableList({
3724
4603
  itemLabel = (_item, index) => `Move item ${index + 1}`,
3725
4604
  ...props
3726
4605
  }) {
3727
- const [draggedId, setDraggedId] = useState9(null);
3728
- const [dropTargetIndex, setDropTargetIndex] = useState9(null);
4606
+ const [draggedId, setDraggedId] = useState12(null);
4607
+ const [dropTargetIndex, setDropTargetIndex] = useState12(null);
3729
4608
  const ids = items.map((item) => item.id);
3730
4609
  function commit(nextIds) {
3731
4610
  void onReorder(nextIds);
@@ -3750,7 +4629,7 @@ function KeepReorderableList({
3750
4629
  if (next[index] === id) return;
3751
4630
  commit(next);
3752
4631
  }
3753
- return /* @__PURE__ */ jsx18("ul", { ...props, "data-keepkit": "reorderable-list", children: items.map((item, index) => {
4632
+ return /* @__PURE__ */ jsx21("ul", { ...props, "data-keepkit": "reorderable-list", children: items.map((item, index) => {
3754
4633
  const moveUp = () => move(index, index - 1);
3755
4634
  const moveDown = () => move(index, index + 1);
3756
4635
  const onHandleKeyDown = (event) => {
@@ -3785,7 +4664,7 @@ function KeepReorderableList({
3785
4664
  onKeyDown: onHandleKeyDown
3786
4665
  }
3787
4666
  };
3788
- return /* @__PURE__ */ jsx18(
4667
+ return /* @__PURE__ */ jsx21(
3789
4668
  "li",
3790
4669
  {
3791
4670
  "data-reorder-index": index,
@@ -3820,7 +4699,7 @@ function KeepReorderableList({
3820
4699
  import { isValidElement as isValidElement7 } from "react";
3821
4700
 
3822
4701
  // src/features/navigation/KeepShortcutHint.tsx
3823
- import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
4702
+ import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
3824
4703
  function KeepShortcutHint({ shortcut, separator = "+", ...props }) {
3825
4704
  const keys = typeof shortcut === "string" ? shortcut.split("+") : [...shortcut];
3826
4705
  const occurrences = /* @__PURE__ */ new Map();
@@ -3829,24 +4708,24 @@ function KeepShortcutHint({ shortcut, separator = "+", ...props }) {
3829
4708
  occurrences.set(key, occurrence + 1);
3830
4709
  return { id: `${key}-${occurrence}`, value: key };
3831
4710
  });
3832
- return /* @__PURE__ */ jsx19("span", { ...props, "data-keepkit": "shortcut-hint", "aria-hidden": props["aria-hidden"] ?? true, children: keyedKeys.map((key, index) => /* @__PURE__ */ jsxs14("span", { children: [
3833
- index > 0 ? /* @__PURE__ */ jsx19("span", { "data-shortcut-separator": "true", children: separator }) : null,
3834
- /* @__PURE__ */ jsx19("kbd", { children: key.value.trim() })
4711
+ return /* @__PURE__ */ jsx22("span", { ...props, "data-keepkit": "shortcut-hint", "aria-hidden": props["aria-hidden"] ?? true, children: keyedKeys.map((key, index) => /* @__PURE__ */ jsxs18("span", { children: [
4712
+ index > 0 ? /* @__PURE__ */ jsx22("span", { "data-shortcut-separator": "true", children: separator }) : null,
4713
+ /* @__PURE__ */ jsx22("kbd", { children: key.value.trim() })
3835
4714
  ] }, key.id)) });
3836
4715
  }
3837
4716
 
3838
4717
  // src/features/editor/hooks/useKeepNoteEditor.ts
3839
- import { useKeepItem as useKeepItem3 } from "@keepkit/core/react";
3840
- import { useCallback as useCallback4, useEffect as useEffect7, useRef as useRef6, useState as useState10 } from "react";
4718
+ import { useKeepItem as useKeepItem6 } from "@keepkit/core/react";
4719
+ import { useCallback as useCallback6, useEffect as useEffect9, useRef as useRef8, useState as useState13 } from "react";
3841
4720
  function useKeepNoteEditor({ item, debounceMs, onSaved, onSaveError }) {
3842
- const itemState = useKeepItem3(item);
4721
+ const itemState = useKeepItem6(item);
3843
4722
  const { error, isMutating, item: savedItem, updateNote } = itemState;
3844
- const [note, setNote] = useState10(item.note ?? "");
4723
+ const [note, setNote] = useState13(item.note ?? "");
3845
4724
  const baselineNote = savedItem?.note ?? item.note ?? "";
3846
4725
  const isDirty = note !== baselineNote;
3847
- const lastSavedNoteRef = useRef6(void 0);
3848
- useEffect7(() => setNote(baselineNote), [baselineNote]);
3849
- const save = useCallback4(async () => {
4726
+ const lastSavedNoteRef = useRef8(void 0);
4727
+ useEffect9(() => setNote(baselineNote), [baselineNote]);
4728
+ const save = useCallback6(async () => {
3850
4729
  const nextNote = note.trim() || void 0;
3851
4730
  try {
3852
4731
  await updateNote(nextNote);
@@ -3857,7 +4736,7 @@ function useKeepNoteEditor({ item, debounceMs, onSaved, onSaveError }) {
3857
4736
  throw cause;
3858
4737
  }
3859
4738
  }, [note, onSaveError, onSaved, updateNote]);
3860
- useEffect7(() => {
4739
+ useEffect9(() => {
3861
4740
  if (!isDirty || debounceMs <= 0 || lastSavedNoteRef.current === note) return;
3862
4741
  const timer = window.setTimeout(() => void save().catch(() => void 0), debounceMs);
3863
4742
  return () => window.clearTimeout(timer);
@@ -3892,7 +4771,7 @@ function useKeepNoteEditor({ item, debounceMs, onSaved, onSaveError }) {
3892
4771
  }
3893
4772
 
3894
4773
  // src/features/editor/KeepNoteEditor.tsx
3895
- import { Fragment as Fragment10, jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
4774
+ import { Fragment as Fragment11, jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
3896
4775
  function KeepNoteEditor({
3897
4776
  item,
3898
4777
  label,
@@ -3911,10 +4790,10 @@ function KeepNoteEditor({
3911
4790
  const view = useKeepNoteEditor({ item, debounceMs, onSaved, onSaveError });
3912
4791
  const { error, isDirty, isSaving, note, setNote } = view.state;
3913
4792
  const contentChildren = asChild && isValidElement7(children) ? void 0 : children;
3914
- const body = render ? render(view.state) : typeof contentChildren === "function" ? contentChildren(view.state) : contentChildren ?? /* @__PURE__ */ jsxs15(Fragment10, { children: [
3915
- /* @__PURE__ */ jsxs15("label", { children: [
4793
+ const body = render ? render(view.state) : typeof contentChildren === "function" ? contentChildren(view.state) : contentChildren ?? /* @__PURE__ */ jsxs19(Fragment11, { children: [
4794
+ /* @__PURE__ */ jsxs19("label", { children: [
3916
4795
  label ?? view.labels.note,
3917
- /* @__PURE__ */ jsx20(
4796
+ /* @__PURE__ */ jsx23(
3918
4797
  "textarea",
3919
4798
  {
3920
4799
  "data-keep-action": "edit-note",
@@ -3926,13 +4805,13 @@ function KeepNoteEditor({
3926
4805
  }
3927
4806
  )
3928
4807
  ] }),
3929
- /* @__PURE__ */ jsxs15("button", { type: "submit", "data-keep-action": "save-note", disabled: isSaving, "aria-busy": isSaving, children: [
4808
+ /* @__PURE__ */ jsxs19("button", { type: "submit", "data-keep-action": "save-note", disabled: isSaving, "aria-busy": isSaving, children: [
3930
4809
  saveLabel ?? view.labels.save,
3931
- showShortcutHint ? /* @__PURE__ */ jsx20(KeepShortcutHint, { shortcut: "Ctrl+Enter" }) : null
4810
+ showShortcutHint ? /* @__PURE__ */ jsx23(KeepShortcutHint, { shortcut: "Ctrl+Enter" }) : null
3932
4811
  ] })
3933
4812
  ] });
3934
4813
  if (!asChild) {
3935
- return /* @__PURE__ */ jsxs15(
4814
+ return /* @__PURE__ */ jsxs19(
3936
4815
  "form",
3937
4816
  {
3938
4817
  ...formProps,
@@ -3945,7 +4824,7 @@ function KeepNoteEditor({
3945
4824
  "data-disabled": isSaving ? "true" : void 0,
3946
4825
  children: [
3947
4826
  body,
3948
- error ? /* @__PURE__ */ jsx20("p", { role: "alert", children: getErrorMessage3(error, view.labels.error) }) : null
4827
+ error ? /* @__PURE__ */ jsx23("p", { role: "alert", children: getErrorMessage4(error, view.labels.error) }) : null
3949
4828
  ]
3950
4829
  }
3951
4830
  );
@@ -3967,19 +4846,19 @@ function KeepNoteEditor({
3967
4846
  "KeepNoteEditor"
3968
4847
  );
3969
4848
  }
3970
- function getErrorMessage3(error, fallback) {
4849
+ function getErrorMessage4(error, fallback) {
3971
4850
  return error instanceof Error ? error.message : fallback;
3972
4851
  }
3973
4852
 
3974
4853
  // src/features/editor/hooks/useKeepTagEditor.ts
3975
- import { useKeepItem as useKeepItem4 } from "@keepkit/core/react";
3976
- import { useCallback as useCallback5, useEffect as useEffect8, useState as useState11 } from "react";
4854
+ import { useKeepItem as useKeepItem7 } from "@keepkit/core/react";
4855
+ import { useCallback as useCallback7, useEffect as useEffect10, useState as useState14 } from "react";
3977
4856
  function useKeepTagEditor({ item, onSaved, onSaveError }) {
3978
- const itemState = useKeepItem4(item);
3979
- const [tags, setTags] = useState11(item.tags ?? []);
3980
- const [input, setInput] = useState11("");
3981
- useEffect8(() => setTags(itemState.item?.tags ?? item.tags ?? []), [item.tags, itemState.item?.tags]);
3982
- const save = useCallback5(async () => {
4857
+ const itemState = useKeepItem7(item);
4858
+ const [tags, setTags] = useState14(item.tags ?? []);
4859
+ const [input, setInput] = useState14("");
4860
+ useEffect10(() => setTags(itemState.item?.tags ?? item.tags ?? []), [item.tags, itemState.item?.tags]);
4861
+ const save = useCallback7(async () => {
3983
4862
  const nextTags = normalizeUiTags(tags);
3984
4863
  try {
3985
4864
  await itemState.updateTags(nextTags);
@@ -4025,7 +4904,7 @@ function useKeepTagEditor({ item, onSaved, onSaveError }) {
4025
4904
  }
4026
4905
 
4027
4906
  // src/features/editor/KeepTagEditor.tsx
4028
- import { Fragment as Fragment11, jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
4907
+ import { Fragment as Fragment12, jsx as jsx24, jsxs as jsxs20 } from "react/jsx-runtime";
4029
4908
  function KeepTagEditor({
4030
4909
  item,
4031
4910
  availableTags = [],
@@ -4036,10 +4915,10 @@ function KeepTagEditor({
4036
4915
  }) {
4037
4916
  const view = useKeepTagEditor({ item, onSaved, onSaveError });
4038
4917
  const { isSaving, tags } = view.state;
4039
- const body = render ? render(view.state) : /* @__PURE__ */ jsxs16(Fragment11, { children: [
4040
- /* @__PURE__ */ jsxs16("label", { children: [
4918
+ const body = render ? render(view.state) : /* @__PURE__ */ jsxs20(Fragment12, { children: [
4919
+ /* @__PURE__ */ jsxs20("label", { children: [
4041
4920
  view.labels.tags,
4042
- /* @__PURE__ */ jsx21(
4921
+ /* @__PURE__ */ jsx24(
4043
4922
  "input",
4044
4923
  {
4045
4924
  "data-keep-action": "edit-tags",
@@ -4050,14 +4929,14 @@ function KeepTagEditor({
4050
4929
  }
4051
4930
  )
4052
4931
  ] }),
4053
- availableTags.length > 0 ? /* @__PURE__ */ jsx21("datalist", { id: `keep-tags-${item.id}`, children: availableTags.map((tag) => /* @__PURE__ */ jsx21("option", { value: tag }, tag)) }) : null,
4054
- /* @__PURE__ */ jsx21("ul", { "aria-label": view.labels.tags, children: tags.map((tag) => /* @__PURE__ */ jsxs16("li", { children: [
4932
+ availableTags.length > 0 ? /* @__PURE__ */ jsx24("datalist", { id: `keep-tags-${item.id}`, children: availableTags.map((tag) => /* @__PURE__ */ jsx24("option", { value: tag }, tag)) }) : null,
4933
+ /* @__PURE__ */ jsx24("ul", { "aria-label": view.labels.tags, children: tags.map((tag) => /* @__PURE__ */ jsxs20("li", { children: [
4055
4934
  tag,
4056
- /* @__PURE__ */ jsx21("button", { type: "button", "data-keep-action": "remove-tag", onClick: () => view.removeTag(tag), children: view.labels.remove })
4935
+ /* @__PURE__ */ jsx24("button", { type: "button", "data-keep-action": "remove-tag", onClick: () => view.removeTag(tag), children: view.labels.remove })
4057
4936
  ] }, tag)) }),
4058
- /* @__PURE__ */ jsx21("button", { type: "submit", "data-keep-action": "apply-tags", disabled: isSaving, "aria-busy": isSaving, children: view.labels.apply })
4937
+ /* @__PURE__ */ jsx24("button", { type: "submit", "data-keep-action": "apply-tags", disabled: isSaving, "aria-busy": isSaving, children: view.labels.apply })
4059
4938
  ] });
4060
- return /* @__PURE__ */ jsxs16(
4939
+ return /* @__PURE__ */ jsxs20(
4061
4940
  "form",
4062
4941
  {
4063
4942
  ...props,
@@ -4069,19 +4948,19 @@ function KeepTagEditor({
4069
4948
  "data-disabled": isSaving ? "true" : void 0,
4070
4949
  children: [
4071
4950
  body,
4072
- view.error ? /* @__PURE__ */ jsx21("p", { role: "alert", children: getErrorMessage4(view.error, view.labels.error) }) : null
4951
+ view.error ? /* @__PURE__ */ jsx24("p", { role: "alert", children: getErrorMessage5(view.error, view.labels.error) }) : null
4073
4952
  ]
4074
4953
  }
4075
4954
  );
4076
4955
  }
4077
- function getErrorMessage4(error, fallback) {
4956
+ function getErrorMessage5(error, fallback) {
4078
4957
  return error instanceof Error ? error.message : fallback;
4079
4958
  }
4080
4959
 
4081
4960
  // src/features/feedback/useKeepToastFeedback.ts
4082
- import { useCallback as useCallback6 } from "react";
4961
+ import { useCallback as useCallback8 } from "react";
4083
4962
  function useKeepToastFeedback(showToast) {
4084
- return useCallback6(
4963
+ return useCallback8(
4085
4964
  (event) => {
4086
4965
  if (!("undo" in event)) {
4087
4966
  showToast(event.message);
@@ -4100,10 +4979,10 @@ function useKeepToastFeedback(showToast) {
4100
4979
 
4101
4980
  // src/features/navigation/KeepTourBar.tsx
4102
4981
  import { useKeepNavigator } from "@keepkit/core/react";
4103
- import { useId } from "react";
4982
+ import { useId as useId2 } from "react";
4104
4983
 
4105
4984
  // src/features/navigation/hooks/useKeepTourShortcuts.ts
4106
- import { useEffect as useEffect9 } from "react";
4985
+ import { useEffect as useEffect11 } from "react";
4107
4986
  function useKeepTourShortcuts({
4108
4987
  onNext,
4109
4988
  onPrev,
@@ -4114,7 +4993,7 @@ function useKeepTourShortcuts({
4114
4993
  prevKeys = ["k", "["],
4115
4994
  onError
4116
4995
  }) {
4117
- useEffect9(() => {
4996
+ useEffect11(() => {
4118
4997
  if (!enabled) return;
4119
4998
  const handleKeyDown = (event) => {
4120
4999
  if (!allowInEditable && isEditableTarget(event.target)) return;
@@ -4135,7 +5014,7 @@ function isEditableTarget(target) {
4135
5014
  }
4136
5015
 
4137
5016
  // src/features/navigation/KeepTourBar.tsx
4138
- import { Fragment as Fragment12, jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
5017
+ import { Fragment as Fragment13, jsx as jsx25, jsxs as jsxs21 } from "react/jsx-runtime";
4139
5018
  function KeepTourBar({
4140
5019
  navigation: providedNavigation,
4141
5020
  currentId,
@@ -4177,9 +5056,9 @@ function KeepTourBar({
4177
5056
  return resolvedPrev();
4178
5057
  }
4179
5058
  });
4180
- const body = /* @__PURE__ */ jsxs17(Fragment12, { children: [
4181
- showProgress ? /* @__PURE__ */ jsx22("span", { "data-keepkit": "tour-progress", "aria-live": "polite", children: progress ?? `${navigation.currentPosition ?? 0} / ${navigation.items.length}` }) : null,
4182
- /* @__PURE__ */ jsx22(
5059
+ const body = /* @__PURE__ */ jsxs21(Fragment13, { children: [
5060
+ showProgress ? /* @__PURE__ */ jsx25("span", { "data-keepkit": "tour-progress", "aria-live": "polite", children: progress ?? `${navigation.currentPosition ?? 0} / ${navigation.items.length}` }) : null,
5061
+ /* @__PURE__ */ jsx25(
4183
5062
  TourAction,
4184
5063
  {
4185
5064
  href: prevHref,
@@ -4187,7 +5066,7 @@ function KeepTourBar({
4187
5066
  onClick: prevHref ? onPrev : resolvedPrev,
4188
5067
  "data-keep-action": "tour-prev",
4189
5068
  shortcut: showShortcutHint ? shortcutOptions?.prevKeys?.[0] ?? "K" : void 0,
4190
- preview: navigation.prevItem ? /* @__PURE__ */ jsxs17(Fragment12, { children: [
5069
+ preview: navigation.prevItem ? /* @__PURE__ */ jsxs21(Fragment13, { children: [
4191
5070
  previousLabel,
4192
5071
  ": ",
4193
5072
  getItemTitle(navigation.prevItem)
@@ -4195,7 +5074,7 @@ function KeepTourBar({
4195
5074
  children: previousLabel
4196
5075
  }
4197
5076
  ),
4198
- /* @__PURE__ */ jsx22(
5077
+ /* @__PURE__ */ jsx25(
4199
5078
  TourAction,
4200
5079
  {
4201
5080
  href: nextHref,
@@ -4203,7 +5082,7 @@ function KeepTourBar({
4203
5082
  onClick: nextHref ? onNext : resolvedNext,
4204
5083
  "data-keep-action": "tour-next",
4205
5084
  shortcut: showShortcutHint ? shortcutOptions?.nextKeys?.[0] ?? "J" : void 0,
4206
- preview: navigation.nextItem ? /* @__PURE__ */ jsxs17(Fragment12, { children: [
5085
+ preview: navigation.nextItem ? /* @__PURE__ */ jsxs21(Fragment13, { children: [
4207
5086
  nextItemLabel,
4208
5087
  ": ",
4209
5088
  getItemTitle(navigation.nextItem)
@@ -4211,7 +5090,7 @@ function KeepTourBar({
4211
5090
  children: nextItemLabel
4212
5091
  }
4213
5092
  ),
4214
- backHref || onBack ? /* @__PURE__ */ jsx22(TourAction, { href: backHref, onClick: onBack, "data-keep-action": "tour-back", children: listLabel }) : null
5093
+ backHref || onBack ? /* @__PURE__ */ jsx25(TourAction, { href: backHref, onClick: onBack, "data-keep-action": "tour-back", children: listLabel }) : null
4215
5094
  ] });
4216
5095
  return renderRoot(
4217
5096
  asChild,
@@ -4222,14 +5101,14 @@ function KeepTourBar({
4222
5101
  );
4223
5102
  }
4224
5103
  function TourAction({ href, disabled = false, onClick, children, preview, shortcut, ...props }) {
4225
- const previewId = useId();
4226
- const content = /* @__PURE__ */ jsxs17(Fragment12, { children: [
4227
- /* @__PURE__ */ jsx22("span", { "data-tour-label": "true", children }),
4228
- shortcut ? /* @__PURE__ */ jsx22(KeepShortcutHint, { shortcut }) : null,
4229
- preview ? /* @__PURE__ */ jsx22("small", { id: previewId, "data-tour-preview": "true", children: preview }) : null
5104
+ const previewId = useId2();
5105
+ const content = /* @__PURE__ */ jsxs21(Fragment13, { children: [
5106
+ /* @__PURE__ */ jsx25("span", { "data-tour-label": "true", children }),
5107
+ shortcut ? /* @__PURE__ */ jsx25(KeepShortcutHint, { shortcut }) : null,
5108
+ preview ? /* @__PURE__ */ jsx25("small", { id: previewId, "data-tour-preview": "true", children: preview }) : null
4230
5109
  ] });
4231
5110
  if (href && !disabled) {
4232
- return /* @__PURE__ */ jsx22(
5111
+ return /* @__PURE__ */ jsx25(
4233
5112
  "a",
4234
5113
  {
4235
5114
  ...props,
@@ -4241,7 +5120,7 @@ function TourAction({ href, disabled = false, onClick, children, preview, shortc
4241
5120
  }
4242
5121
  );
4243
5122
  }
4244
- return /* @__PURE__ */ jsx22(
5123
+ return /* @__PURE__ */ jsx25(
4245
5124
  "button",
4246
5125
  {
4247
5126
  ...props,
@@ -4264,10 +5143,10 @@ function navigateTo(item, href) {
4264
5143
  import { isValidElement as isValidElement8 } from "react";
4265
5144
 
4266
5145
  // src/features/status/hooks/useStatusViews.ts
4267
- import { useKeepContext as useKeepContext4 } from "@keepkit/core/react";
4268
- import { useEffect as useEffect10, useRef as useRef7, useState as useState12 } from "react";
5146
+ import { useKeepContext as useKeepContext6 } from "@keepkit/core/react";
5147
+ import { useEffect as useEffect12, useRef as useRef9, useState as useState15 } from "react";
4269
5148
  function useKeepStatus(status) {
4270
- const context = useKeepContext4();
5149
+ const context = useKeepContext6();
4271
5150
  const resolvedStatus = status ?? getDerivedStatus(context);
4272
5151
  const state = {
4273
5152
  status: resolvedStatus,
@@ -4278,13 +5157,13 @@ function useKeepStatus(status) {
4278
5157
  return { state, defaultLabel: useUiLabel(getStatusLabelKey3(resolvedStatus)) };
4279
5158
  }
4280
5159
  function useKeepAnnouncements(messages) {
4281
- const context = useKeepContext4();
5160
+ const context = useKeepContext6();
4282
5161
  const savedMessage = useUiLabel("savedMessage", messages?.save);
4283
5162
  const removedMessage = useUiLabel("removedMessage", messages?.remove);
4284
5163
  const noteSavedMessage = useUiLabel("noteSavedMessage", messages?.note);
4285
- const [message, setMessage] = useState12("");
4286
- const lastChangeRef = useRef7(void 0);
4287
- useEffect10(() => {
5164
+ const [message, setMessage] = useState15("");
5165
+ const lastChangeRef = useRef9(void 0);
5166
+ useEffect12(() => {
4288
5167
  const change = context.lastChange;
4289
5168
  if (!change || change === lastChangeRef.current) return;
4290
5169
  lastChangeRef.current = change;
@@ -4312,7 +5191,7 @@ function getStatusLabelKey3(status) {
4312
5191
  }
4313
5192
 
4314
5193
  // src/features/status/status.tsx
4315
- import { jsx as jsx23 } from "react/jsx-runtime";
5194
+ import { jsx as jsx26 } from "react/jsx-runtime";
4316
5195
  function KeepStatus({
4317
5196
  status,
4318
5197
  labels,
@@ -4344,7 +5223,7 @@ function KeepStatus({
4344
5223
  }
4345
5224
  function KeepAnnouncements({ messages, ...props }) {
4346
5225
  const message = useKeepAnnouncements(messages);
4347
- return /* @__PURE__ */ jsx23(
5226
+ return /* @__PURE__ */ jsx26(
4348
5227
  "div",
4349
5228
  {
4350
5229
  ...props,
@@ -4360,15 +5239,15 @@ function KeepAnnouncements({ messages, ...props }) {
4360
5239
  var KeepAnnouncer = KeepAnnouncements;
4361
5240
 
4362
5241
  // src/features/sync/hooks/useKeepSyncFeedback.ts
4363
- import { useKeepContext as useKeepContext5 } from "@keepkit/core/react";
4364
- import { useEffect as useEffect11, useRef as useRef8 } from "react";
5242
+ import { useKeepContext as useKeepContext7 } from "@keepkit/core/react";
5243
+ import { useEffect as useEffect13, useRef as useRef10 } from "react";
4365
5244
  function useKeepSyncFeedback() {
4366
- const { syncState } = useKeepContext5();
5245
+ const { syncState } = useKeepContext7();
4367
5246
  const emitFeedback = useKeepUiFeedback();
4368
5247
  const completedMessage = useUiLabel("syncSynced");
4369
5248
  const failedMessage = useUiLabel("syncFailedMessage");
4370
- const previousStatus = useRef8("idle");
4371
- useEffect11(() => {
5249
+ const previousStatus = useRef10("idle");
5250
+ useEffect13(() => {
4372
5251
  const previous = previousStatus.current;
4373
5252
  previousStatus.current = syncState.status;
4374
5253
  if (syncState.status === "error" && previous !== "error") {
@@ -4388,17 +5267,17 @@ function KeepSyncFeedbackObserver() {
4388
5267
  }
4389
5268
 
4390
5269
  // src/features/sync/hooks/useKeepSyncRecoveryDialog.ts
4391
- import { useKeepContext as useKeepContext6 } from "@keepkit/core/react";
4392
- import { useEffect as useEffect12, useState as useState13 } from "react";
5270
+ import { useKeepContext as useKeepContext8 } from "@keepkit/core/react";
5271
+ import { useEffect as useEffect14, useState as useState16 } from "react";
4393
5272
  function useKeepSyncRecoveryDialog(options) {
4394
5273
  const { open, onOpenChange, conflicts, onManualMerge } = options;
4395
- const context = useKeepContext6();
5274
+ const context = useKeepContext8();
4396
5275
  const conflictList = conflicts ?? context.syncState.conflicts ?? [];
4397
5276
  const hasRecovery = conflictList.length > 0 || context.syncState.status === "error" || Boolean(context.error);
4398
- const [dismissed, setDismissed] = useState13(false);
4399
- const [busyId, setBusyId] = useState13();
4400
- const [error, setError] = useState13();
4401
- useEffect12(() => {
5277
+ const [dismissed, setDismissed] = useState16(false);
5278
+ const [busyId, setBusyId] = useState16();
5279
+ const [error, setError] = useState16();
5280
+ useEffect14(() => {
4402
5281
  if (hasRecovery) setDismissed(false);
4403
5282
  }, [hasRecovery]);
4404
5283
  return {
@@ -4443,7 +5322,7 @@ function useKeepSyncRecoveryDialog(options) {
4443
5322
  }
4444
5323
 
4445
5324
  // src/features/sync/KeepSyncRecoveryDialog.tsx
4446
- import { jsx as jsx24, jsxs as jsxs18 } from "react/jsx-runtime";
5325
+ import { jsx as jsx27, jsxs as jsxs22 } from "react/jsx-runtime";
4447
5326
  function KeepSyncRecoveryDialog({
4448
5327
  open,
4449
5328
  onOpenChange,
@@ -4458,7 +5337,7 @@ function KeepSyncRecoveryDialog({
4458
5337
  }) {
4459
5338
  const view = useKeepSyncRecoveryDialog({ open, onOpenChange, conflicts, onManualMerge });
4460
5339
  if (!view.isOpen) return null;
4461
- return /* @__PURE__ */ jsxs18(
5340
+ return /* @__PURE__ */ jsxs22(
4462
5341
  "section",
4463
5342
  {
4464
5343
  ...props,
@@ -4472,17 +5351,17 @@ function KeepSyncRecoveryDialog({
4472
5351
  "data-state": view.conflictList.length > 0 ? "conflict" : "error",
4473
5352
  "data-loading": view.busyId !== void 0 ? "true" : void 0,
4474
5353
  children: [
4475
- /* @__PURE__ */ jsxs18("header", { children: [
4476
- /* @__PURE__ */ jsx24("h2", { id: "keepkit-sync-recovery-title", children: title ?? view.labels.title }),
4477
- /* @__PURE__ */ jsx24("button", { type: "button", "data-keep-action": "close-dialog", onClick: view.close, "aria-label": view.labels.close, children: view.labels.close })
5354
+ /* @__PURE__ */ jsxs22("header", { children: [
5355
+ /* @__PURE__ */ jsx27("h2", { id: "keepkit-sync-recovery-title", children: title ?? view.labels.title }),
5356
+ /* @__PURE__ */ jsx27("button", { type: "button", "data-keep-action": "close-dialog", onClick: view.close, "aria-label": view.labels.close, children: view.labels.close })
4478
5357
  ] }),
4479
5358
  children,
4480
- view.conflictList.length > 0 ? /* @__PURE__ */ jsxs18("div", { children: [
4481
- /* @__PURE__ */ jsx24("p", { children: view.labels.conflict }),
4482
- view.conflictList.map((conflict) => /* @__PURE__ */ jsxs18("article", { "data-conflict-id": conflict.id, children: [
4483
- /* @__PURE__ */ jsx24("h3", { children: getMetaTitle(conflict.operation.item?.meta) ?? conflict.id }),
4484
- /* @__PURE__ */ jsxs18("div", { "data-conflict-preview": true, children: [
4485
- /* @__PURE__ */ jsx24(
5359
+ view.conflictList.length > 0 ? /* @__PURE__ */ jsxs22("div", { children: [
5360
+ /* @__PURE__ */ jsx27("p", { children: view.labels.conflict }),
5361
+ view.conflictList.map((conflict) => /* @__PURE__ */ jsxs22("article", { "data-conflict-id": conflict.id, children: [
5362
+ /* @__PURE__ */ jsx27("h3", { children: getMetaTitle(conflict.operation.item?.meta) ?? conflict.id }),
5363
+ /* @__PURE__ */ jsxs22("div", { "data-conflict-preview": true, children: [
5364
+ /* @__PURE__ */ jsx27(
4486
5365
  ConflictPreview,
4487
5366
  {
4488
5367
  item: conflict.operation.item,
@@ -4492,7 +5371,7 @@ function KeepSyncRecoveryDialog({
4492
5371
  side: "local"
4493
5372
  }
4494
5373
  ),
4495
- /* @__PURE__ */ jsx24(
5374
+ /* @__PURE__ */ jsx27(
4496
5375
  ConflictPreview,
4497
5376
  {
4498
5377
  item: conflict.remote,
@@ -4503,8 +5382,8 @@ function KeepSyncRecoveryDialog({
4503
5382
  }
4504
5383
  )
4505
5384
  ] }),
4506
- /* @__PURE__ */ jsxs18("div", { children: [
4507
- /* @__PURE__ */ jsx24(
5385
+ /* @__PURE__ */ jsxs22("div", { children: [
5386
+ /* @__PURE__ */ jsx27(
4508
5387
  "button",
4509
5388
  {
4510
5389
  type: "button",
@@ -4514,7 +5393,7 @@ function KeepSyncRecoveryDialog({
4514
5393
  children: view.labels.keepLocal
4515
5394
  }
4516
5395
  ),
4517
- /* @__PURE__ */ jsx24(
5396
+ /* @__PURE__ */ jsx27(
4518
5397
  "button",
4519
5398
  {
4520
5399
  type: "button",
@@ -4524,7 +5403,7 @@ function KeepSyncRecoveryDialog({
4524
5403
  children: view.labels.useServer
4525
5404
  }
4526
5405
  ),
4527
- /* @__PURE__ */ jsx24(
5406
+ /* @__PURE__ */ jsx27(
4528
5407
  "button",
4529
5408
  {
4530
5409
  type: "button",
@@ -4537,12 +5416,12 @@ function KeepSyncRecoveryDialog({
4537
5416
  ] })
4538
5417
  ] }, conflict.id))
4539
5418
  ] }) : null,
4540
- view.showBackupRecovery ? /* @__PURE__ */ jsxs18("section", { "data-recovery": "backup", children: [
4541
- /* @__PURE__ */ jsx24("h3", { children: view.labels.backupRecovery }),
4542
- /* @__PURE__ */ jsx24("p", { children: view.labels.backupRecoveryDescription }),
4543
- backup ?? (showBackupControls ? /* @__PURE__ */ jsx24(KeepBackup, {}) : null)
5419
+ view.showBackupRecovery ? /* @__PURE__ */ jsxs22("section", { "data-recovery": "backup", children: [
5420
+ /* @__PURE__ */ jsx27("h3", { children: view.labels.backupRecovery }),
5421
+ /* @__PURE__ */ jsx27("p", { children: view.labels.backupRecoveryDescription }),
5422
+ backup ?? (showBackupControls ? /* @__PURE__ */ jsx27(KeepBackup, {}) : null)
4544
5423
  ] }) : null,
4545
- view.error ? /* @__PURE__ */ jsx24("p", { id: "keepkit-sync-recovery-error", role: "alert", "aria-live": "assertive", children: view.error instanceof Error ? view.error.message : view.labels.error }) : null
5424
+ view.error ? /* @__PURE__ */ jsx27("p", { id: "keepkit-sync-recovery-error", role: "alert", "aria-live": "assertive", children: view.error instanceof Error ? view.error.message : view.labels.error }) : null
4546
5425
  ]
4547
5426
  }
4548
5427
  );
@@ -4554,16 +5433,16 @@ function ConflictPreview({
4554
5433
  noteLabel,
4555
5434
  side
4556
5435
  }) {
4557
- return /* @__PURE__ */ jsxs18("article", { "data-conflict-version": side, "aria-label": heading, children: [
4558
- /* @__PURE__ */ jsx24("h4", { children: heading }),
4559
- /* @__PURE__ */ jsxs18("dl", { children: [
4560
- /* @__PURE__ */ jsxs18("div", { children: [
4561
- /* @__PURE__ */ jsx24("dt", { children: updatedAtLabel }),
4562
- /* @__PURE__ */ jsx24("dd", { children: item ? /* @__PURE__ */ jsx24("time", { dateTime: new Date(item.updatedAt).toISOString(), children: formatConflictDate(item.updatedAt) }) : "\u2014" })
5436
+ return /* @__PURE__ */ jsxs22("article", { "data-conflict-version": side, "aria-label": heading, children: [
5437
+ /* @__PURE__ */ jsx27("h4", { children: heading }),
5438
+ /* @__PURE__ */ jsxs22("dl", { children: [
5439
+ /* @__PURE__ */ jsxs22("div", { children: [
5440
+ /* @__PURE__ */ jsx27("dt", { children: updatedAtLabel }),
5441
+ /* @__PURE__ */ jsx27("dd", { children: item ? /* @__PURE__ */ jsx27("time", { dateTime: new Date(item.updatedAt).toISOString(), children: formatConflictDate(item.updatedAt) }) : "\u2014" })
4563
5442
  ] }),
4564
- /* @__PURE__ */ jsxs18("div", { children: [
4565
- /* @__PURE__ */ jsx24("dt", { children: noteLabel }),
4566
- /* @__PURE__ */ jsx24("dd", { children: item?.note || "\u2014" })
5443
+ /* @__PURE__ */ jsxs22("div", { children: [
5444
+ /* @__PURE__ */ jsx27("dt", { children: noteLabel }),
5445
+ /* @__PURE__ */ jsx27("dd", { children: item?.note || "\u2014" })
4567
5446
  ] })
4568
5447
  ] })
4569
5448
  ] });
@@ -4573,9 +5452,9 @@ function formatConflictDate(timestamp) {
4573
5452
  }
4574
5453
 
4575
5454
  // src/features/sync/hooks/useKeepSyncStatusBanner.ts
4576
- import { useKeepContext as useKeepContext7 } from "@keepkit/core/react";
5455
+ import { useKeepContext as useKeepContext9 } from "@keepkit/core/react";
4577
5456
  function useKeepSyncStatusBanner({ onRetry, children }) {
4578
- const context = useKeepContext7();
5457
+ const context = useKeepContext9();
4579
5458
  const retryLabel = useUiLabel("retrySync");
4580
5459
  const resolveLabel = useUiLabel("resolveSync");
4581
5460
  const conflictLabel = useUiLabel("syncConflict");
@@ -4583,7 +5462,7 @@ function useKeepSyncStatusBanner({ onRetry, children }) {
4583
5462
  const syncedLabel = useUiLabel("syncSynced");
4584
5463
  const status = context.syncState.status;
4585
5464
  const hasConflicts = (context.syncState.conflicts?.length ?? 0) > 0 || context.syncState.conflictIds.length > 0;
4586
- const message = children ?? (status === "error" ? getErrorMessage5(context.syncState.error) : status === "conflict" || hasConflicts ? conflictLabel : status === "pending" || status === "syncing" ? pendingLabel : syncedLabel);
5465
+ const message = children ?? (status === "error" ? getErrorMessage6(context.syncState.error) : status === "conflict" || hasConflicts ? conflictLabel : status === "pending" || status === "syncing" ? pendingLabel : syncedLabel);
4587
5466
  return {
4588
5467
  status,
4589
5468
  hasConflicts,
@@ -4602,12 +5481,12 @@ function useKeepSyncStatusBanner({ onRetry, children }) {
4602
5481
  }
4603
5482
  };
4604
5483
  }
4605
- function getErrorMessage5(error) {
5484
+ function getErrorMessage6(error) {
4606
5485
  return error instanceof Error ? error.message : "Sync failed.";
4607
5486
  }
4608
5487
 
4609
5488
  // src/features/sync/KeepSyncStatusBanner.tsx
4610
- import { jsx as jsx25, jsxs as jsxs19 } from "react/jsx-runtime";
5489
+ import { jsx as jsx28, jsxs as jsxs23 } from "react/jsx-runtime";
4611
5490
  function KeepSyncStatusBanner({
4612
5491
  onRetry,
4613
5492
  onResolveConflicts,
@@ -4617,7 +5496,7 @@ function KeepSyncStatusBanner({
4617
5496
  }) {
4618
5497
  const view = useKeepSyncStatusBanner({ onRetry, children });
4619
5498
  if (view.status === "idle" && !view.hasConflicts) return null;
4620
- return /* @__PURE__ */ jsxs19(
5499
+ return /* @__PURE__ */ jsxs23(
4621
5500
  "aside",
4622
5501
  {
4623
5502
  ...props,
@@ -4627,8 +5506,8 @@ function KeepSyncStatusBanner({
4627
5506
  "data-keepkit": "sync-status",
4628
5507
  "data-state": view.status,
4629
5508
  children: [
4630
- /* @__PURE__ */ jsx25("p", { children: view.message }),
4631
- view.showRetry ? /* @__PURE__ */ jsx25(
5509
+ /* @__PURE__ */ jsx28("p", { children: view.message }),
5510
+ view.showRetry ? /* @__PURE__ */ jsx28(
4632
5511
  "button",
4633
5512
  {
4634
5513
  type: "button",
@@ -4638,7 +5517,7 @@ function KeepSyncStatusBanner({
4638
5517
  children: view.retryLabel
4639
5518
  }
4640
5519
  ) : null,
4641
- view.hasConflicts ? /* @__PURE__ */ jsx25(
5520
+ view.hasConflicts ? /* @__PURE__ */ jsx28(
4642
5521
  "button",
4643
5522
  {
4644
5523
  type: "button",
@@ -4655,7 +5534,7 @@ function KeepSyncStatusBanner({
4655
5534
 
4656
5535
  // src/foundation/theme.tsx
4657
5536
  import { isValidElement as isValidElement9 } from "react";
4658
- import { jsx as jsx26 } from "react/jsx-runtime";
5537
+ import { jsx as jsx29 } from "react/jsx-runtime";
4659
5538
  var keepThemeNames = [
4660
5539
  "default",
4661
5540
  "ocean",
@@ -4714,7 +5593,7 @@ function KeepThemeProvider({
4714
5593
  throw new Error("KeepThemeProvider with asChild requires a single React element child.");
4715
5594
  return createSlot(children, rootProps);
4716
5595
  }
4717
- return /* @__PURE__ */ jsx26("div", { ...rootProps, children });
5596
+ return /* @__PURE__ */ jsx29("div", { ...rootProps, children });
4718
5597
  }
4719
5598
 
4720
5599
  // src/index.tsx
@@ -4722,8 +5601,8 @@ import { createAuthenticatedSyncKit } from "@keepkit/core/core";
4722
5601
  import {
4723
5602
  KeepErrorBoundary as KeepErrorBoundary3,
4724
5603
  KeepProvider,
4725
- useKeepContext as useKeepContext8,
4726
- useKeepItem as useKeepItem5,
5604
+ useKeepContext as useKeepContext10,
5605
+ useKeepItem as useKeepItem8,
4727
5606
  useKeepList as useKeepList5,
4728
5607
  useKeepNavigator as useKeepNavigator2,
4729
5608
  useKeepShortcut
@@ -4738,7 +5617,7 @@ import {
4738
5617
  LocalStorageSyncQueueAdapter,
4739
5618
  SyncStorageAdapter
4740
5619
  } from "@keepkit/core/storage";
4741
- import { jsx as jsx27, jsxs as jsxs20 } from "react/jsx-runtime";
5620
+ import { jsx as jsx30, jsxs as jsxs24 } from "react/jsx-runtime";
4742
5621
  function KeepKitProvider({
4743
5622
  labels,
4744
5623
  locale,
@@ -4758,7 +5637,7 @@ function KeepKitProvider({
4758
5637
  children,
4759
5638
  ...providerProps
4760
5639
  }) {
4761
- return /* @__PURE__ */ jsx27(KeepUiProvider, { labels, locale, labelResolver, onFeedback, children: /* @__PURE__ */ jsx27(
5640
+ return /* @__PURE__ */ jsx30(KeepUiProvider, { labels, locale, labelResolver, onFeedback, children: /* @__PURE__ */ jsx30(
4762
5641
  KeepThemeProvider,
4763
5642
  {
4764
5643
  theme,
@@ -4772,10 +5651,10 @@ function KeepKitProvider({
4772
5651
  className: themeClassName,
4773
5652
  style: themeStyle,
4774
5653
  asChild: themeAsChild,
4775
- children: /* @__PURE__ */ jsxs20(CoreKeepProvider, { ...providerProps, children: [
4776
- /* @__PURE__ */ jsx27(KeepSyncFeedbackObserver, {}),
5654
+ children: /* @__PURE__ */ jsxs24(CoreKeepProvider, { ...providerProps, children: [
5655
+ /* @__PURE__ */ jsx30(KeepSyncFeedbackObserver, {}),
4777
5656
  children,
4778
- /* @__PURE__ */ jsx27(KeepAnnouncements, {})
5657
+ /* @__PURE__ */ jsx30(KeepAnnouncements, {})
4779
5658
  ] })
4780
5659
  }
4781
5660
  ) });
@@ -4802,7 +5681,7 @@ function createKeepKit(options = {}) {
4802
5681
  } = options;
4803
5682
  const coreKit = createCoreKeepKit(coreOptions);
4804
5683
  return {
4805
- Provider: (props) => /* @__PURE__ */ jsx27(
5684
+ Provider: (props) => /* @__PURE__ */ jsx30(
4806
5685
  KeepKitProvider,
4807
5686
  {
4808
5687
  ...coreOptions,
@@ -4823,9 +5702,9 @@ function createKeepKit(options = {}) {
4823
5702
  ...props
4824
5703
  }
4825
5704
  ),
4826
- Button: (props) => /* @__PURE__ */ jsx27(KeepButton, { ...props }),
4827
- Backup: (props) => /* @__PURE__ */ jsx27(KeepBackup, { ...props }),
4828
- Collection: (props) => /* @__PURE__ */ jsx27(
5705
+ Button: (props) => /* @__PURE__ */ jsx30(KeepButton, { ...props }),
5706
+ Backup: (props) => /* @__PURE__ */ jsx30(KeepBackup, { ...props }),
5707
+ Collection: (props) => /* @__PURE__ */ jsx30(
4829
5708
  KeepCollection,
4830
5709
  {
4831
5710
  ...props,
@@ -4850,10 +5729,13 @@ export {
4850
5729
  KeepActiveFiltersSummary,
4851
5730
  KeepAnnouncements,
4852
5731
  KeepAnnouncer,
5732
+ KeepArchiveButton,
4853
5733
  KeepBackup,
4854
5734
  KeepBulkActions,
4855
5735
  KeepButton,
4856
5736
  KeepCollection,
5737
+ KeepCollectionFilter,
5738
+ KeepCollectionSelect,
4857
5739
  KeepEmptyState,
4858
5740
  KeepErrorBoundary3 as KeepErrorBoundary,
4859
5741
  KeepHighlight,
@@ -4867,9 +5749,12 @@ export {
4867
5749
  KeepNavigator,
4868
5750
  KeepNoteEditor,
4869
5751
  KeepPagination,
5752
+ KeepPinButton,
4870
5753
  KeepProvider,
4871
5754
  KeepPruneStaleButton,
5755
+ KeepQuickEditor,
4872
5756
  KeepReorderableList,
5757
+ KeepSavePopover,
4873
5758
  KeepSearchInput,
4874
5759
  KeepShortcutHint,
4875
5760
  KeepSortSelect,
@@ -4900,10 +5785,11 @@ export {
4900
5785
  keepThemeNames,
4901
5786
  mergeProps,
4902
5787
  toggleSelectAll,
4903
- useKeepContext8 as useKeepContext,
4904
- useKeepItem5 as useKeepItem,
5788
+ useKeepContext10 as useKeepContext,
5789
+ useKeepItem8 as useKeepItem,
4905
5790
  useKeepList5 as useKeepList,
4906
5791
  useKeepNavigator2 as useKeepNavigator,
5792
+ useKeepQuickEditor,
4907
5793
  useKeepShortcut,
4908
5794
  useKeepToastFeedback,
4909
5795
  useKeepTourShortcuts,