@keepkit/ui 0.19.0 → 0.21.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,25 @@ 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",
100
110
  save: "Speichern",
101
111
  saved: "Gespeichert",
102
112
  remove: "Entfernen",
@@ -183,6 +193,17 @@ var DE_LABELS = {
183
193
 
184
194
  // src/locales/en.ts
185
195
  var EN_LABELS = {
196
+ archive: "Archive",
197
+ unarchive: "Unarchive",
198
+ archived: "Archived",
199
+ pin: "Pin",
200
+ unpin: "Unpin",
201
+ pinned: "Pinned",
202
+ collection: "Collection",
203
+ allCollections: "All collections",
204
+ filterCollections: "Filter collections",
205
+ uncategorized: "Uncategorized",
206
+ saveWithNote: "Save with note",
186
207
  save: "Save",
187
208
  saved: "Saved",
188
209
  remove: "Remove",
@@ -269,6 +290,17 @@ var EN_LABELS = {
269
290
 
270
291
  // src/locales/es.ts
271
292
  var ES_LABELS = {
293
+ archive: "Archivar",
294
+ unarchive: "Desarchivar",
295
+ archived: "Archivado",
296
+ pin: "Fijar",
297
+ unpin: "Desfijar",
298
+ pinned: "Fijado",
299
+ collection: "Colecci\xF3n",
300
+ allCollections: "Todas las colecciones",
301
+ filterCollections: "Filtrar por colecci\xF3n",
302
+ uncategorized: "Sin categor\xEDa",
303
+ saveWithNote: "Guardar con nota",
272
304
  save: "Guardar",
273
305
  saved: "Guardado",
274
306
  remove: "Eliminar",
@@ -355,6 +387,17 @@ var ES_LABELS = {
355
387
 
356
388
  // src/locales/fil.ts
357
389
  var FIL_LABELS = {
390
+ archive: "I-archive",
391
+ unarchive: "Alisin sa archive",
392
+ archived: "Naka-archive",
393
+ pin: "I-pin",
394
+ unpin: "Alisin ang pin",
395
+ pinned: "Naka-pin",
396
+ collection: "Koleksyon",
397
+ allCollections: "Lahat ng koleksyon",
398
+ filterCollections: "I-filter ayon sa koleksyon",
399
+ uncategorized: "Walang kategorya",
400
+ saveWithNote: "I-save na may tala",
358
401
  save: "I-save",
359
402
  saved: "Nai-save",
360
403
  remove: "Alisin",
@@ -441,6 +484,17 @@ var FIL_LABELS = {
441
484
 
442
485
  // src/locales/fr.ts
443
486
  var FR_LABELS = {
487
+ archive: "Archiver",
488
+ unarchive: "D\xE9sarchiver",
489
+ archived: "Archiv\xE9",
490
+ pin: "\xC9pingler",
491
+ unpin: "D\xE9s\xE9pingler",
492
+ pinned: "\xC9pingl\xE9",
493
+ collection: "Collection",
494
+ allCollections: "Toutes les collections",
495
+ filterCollections: "Filtrer par collection",
496
+ uncategorized: "Non class\xE9",
497
+ saveWithNote: "Enregistrer avec une note",
444
498
  save: "Enregistrer",
445
499
  saved: "Enregistr\xE9",
446
500
  remove: "Supprimer",
@@ -527,6 +581,17 @@ var FR_LABELS = {
527
581
 
528
582
  // src/locales/id.ts
529
583
  var ID_LABELS = {
584
+ archive: "Arsipkan",
585
+ unarchive: "Batalkan arsip",
586
+ archived: "Diarsipkan",
587
+ pin: "Sematkan",
588
+ unpin: "Lepas sematan",
589
+ pinned: "Disematkan",
590
+ collection: "Koleksi",
591
+ allCollections: "Semua koleksi",
592
+ filterCollections: "Filter koleksi",
593
+ uncategorized: "Tanpa kategori",
594
+ saveWithNote: "Simpan dengan catatan",
530
595
  save: "Simpan",
531
596
  saved: "Tersimpan",
532
597
  remove: "Hapus",
@@ -613,6 +678,17 @@ var ID_LABELS = {
613
678
 
614
679
  // src/locales/it.ts
615
680
  var IT_LABELS = {
681
+ archive: "Archivia",
682
+ unarchive: "Rimuovi dall'archivio",
683
+ archived: "Archiviato",
684
+ pin: "Fissa",
685
+ unpin: "Rimuovi fissaggio",
686
+ pinned: "Fissato",
687
+ collection: "Raccolta",
688
+ allCollections: "Tutte le raccolte",
689
+ filterCollections: "Filtra per raccolta",
690
+ uncategorized: "Senza categoria",
691
+ saveWithNote: "Salva con nota",
616
692
  save: "Salva",
617
693
  saved: "Salvato",
618
694
  remove: "Rimuovi",
@@ -699,6 +775,17 @@ var IT_LABELS = {
699
775
 
700
776
  // src/locales/ja.ts
701
777
  var JA_LABELS = {
778
+ archive: "\u30A2\u30FC\u30AB\u30A4\u30D6",
779
+ unarchive: "\u30A2\u30FC\u30AB\u30A4\u30D6\u3092\u89E3\u9664",
780
+ archived: "\u30A2\u30FC\u30AB\u30A4\u30D6\u6E08\u307F",
781
+ pin: "\u30D4\u30F3\u7559\u3081",
782
+ unpin: "\u30D4\u30F3\u7559\u3081\u3092\u89E3\u9664",
783
+ pinned: "\u30D4\u30F3\u7559\u3081\u6E08\u307F",
784
+ collection: "\u30B3\u30EC\u30AF\u30B7\u30E7\u30F3",
785
+ allCollections: "\u3059\u3079\u3066\u306E\u30B3\u30EC\u30AF\u30B7\u30E7\u30F3",
786
+ filterCollections: "\u30B3\u30EC\u30AF\u30B7\u30E7\u30F3\u3067\u7D5E\u308A\u8FBC\u3080",
787
+ uncategorized: "\u672A\u5206\u985E",
788
+ saveWithNote: "\u30E1\u30E2\u4ED8\u304D\u3067\u4FDD\u5B58",
702
789
  save: "\u4FDD\u5B58",
703
790
  saved: "\u4FDD\u5B58\u6E08\u307F",
704
791
  remove: "\u524A\u9664",
@@ -785,6 +872,17 @@ var JA_LABELS = {
785
872
 
786
873
  // src/locales/ko.ts
787
874
  var KO_LABELS = {
875
+ archive: "\uBCF4\uAD00",
876
+ unarchive: "\uBCF4\uAD00 \uD574\uC81C",
877
+ archived: "\uBCF4\uAD00\uB428",
878
+ pin: "\uACE0\uC815",
879
+ unpin: "\uACE0\uC815 \uD574\uC81C",
880
+ pinned: "\uACE0\uC815\uB428",
881
+ collection: "\uCEEC\uB809\uC158",
882
+ allCollections: "\uBAA8\uB4E0 \uCEEC\uB809\uC158",
883
+ filterCollections: "\uCEEC\uB809\uC158 \uD544\uD130",
884
+ uncategorized: "\uBBF8\uBD84\uB958",
885
+ saveWithNote: "\uBA54\uBAA8\uC640 \uD568\uAED8 \uC800\uC7A5",
788
886
  save: "\uC800\uC7A5",
789
887
  saved: "\uC800\uC7A5\uB428",
790
888
  remove: "\uC0AD\uC81C",
@@ -871,6 +969,17 @@ var KO_LABELS = {
871
969
 
872
970
  // src/locales/ms.ts
873
971
  var MS_LABELS = {
972
+ archive: "Arkibkan",
973
+ unarchive: "Nyaharkib",
974
+ archived: "Diarkibkan",
975
+ pin: "Pin",
976
+ unpin: "Nyahpin",
977
+ pinned: "Dipinkan",
978
+ collection: "Koleksi",
979
+ allCollections: "Semua koleksi",
980
+ filterCollections: "Tapis koleksi",
981
+ uncategorized: "Tiada kategori",
982
+ saveWithNote: "Simpan dengan nota",
874
983
  save: "Simpan",
875
984
  saved: "Disimpan",
876
985
  remove: "Buang",
@@ -957,6 +1066,17 @@ var MS_LABELS = {
957
1066
 
958
1067
  // src/locales/pt-BR.ts
959
1068
  var PT_BR_LABELS = {
1069
+ archive: "Arquivar",
1070
+ unarchive: "Desarquivar",
1071
+ archived: "Arquivado",
1072
+ pin: "Fixar",
1073
+ unpin: "Desafixar",
1074
+ pinned: "Fixado",
1075
+ collection: "Cole\xE7\xE3o",
1076
+ allCollections: "Todas as cole\xE7\xF5es",
1077
+ filterCollections: "Filtrar por cole\xE7\xE3o",
1078
+ uncategorized: "Sem categoria",
1079
+ saveWithNote: "Salvar com nota",
960
1080
  save: "Salvar",
961
1081
  saved: "Salvo",
962
1082
  remove: "Remover",
@@ -1043,6 +1163,17 @@ var PT_BR_LABELS = {
1043
1163
 
1044
1164
  // src/locales/ru.ts
1045
1165
  var RU_LABELS = {
1166
+ archive: "\u0410\u0440\u0445\u0438\u0432\u0438\u0440\u043E\u0432\u0430\u0442\u044C",
1167
+ unarchive: "\u0420\u0430\u0437\u0430\u0440\u0445\u0438\u0432\u0438\u0440\u043E\u0432\u0430\u0442\u044C",
1168
+ archived: "\u0412 \u0430\u0440\u0445\u0438\u0432\u0435",
1169
+ pin: "\u0417\u0430\u043A\u0440\u0435\u043F\u0438\u0442\u044C",
1170
+ unpin: "\u041E\u0442\u043A\u0440\u0435\u043F\u0438\u0442\u044C",
1171
+ pinned: "\u0417\u0430\u043A\u0440\u0435\u043F\u043B\u0435\u043D\u043E",
1172
+ collection: "\u041A\u043E\u043B\u043B\u0435\u043A\u0446\u0438\u044F",
1173
+ allCollections: "\u0412\u0441\u0435 \u043A\u043E\u043B\u043B\u0435\u043A\u0446\u0438\u0438",
1174
+ filterCollections: "\u0424\u0438\u043B\u044C\u0442\u0440 \u043A\u043E\u043B\u043B\u0435\u043A\u0446\u0438\u0439",
1175
+ uncategorized: "\u0411\u0435\u0437 \u043A\u0430\u0442\u0435\u0433\u043E\u0440\u0438\u0438",
1176
+ saveWithNote: "\u0421\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C \u0441 \u0437\u0430\u043C\u0435\u0442\u043A\u043E\u0439",
1046
1177
  save: "\u0421\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C",
1047
1178
  saved: "\u0421\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u043E",
1048
1179
  remove: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C",
@@ -1129,6 +1260,17 @@ var RU_LABELS = {
1129
1260
 
1130
1261
  // src/locales/th.ts
1131
1262
  var TH_LABELS = {
1263
+ archive: "\u0E40\u0E01\u0E47\u0E1A\u0E16\u0E32\u0E27\u0E23",
1264
+ unarchive: "\u0E22\u0E01\u0E40\u0E25\u0E34\u0E01\u0E01\u0E32\u0E23\u0E40\u0E01\u0E47\u0E1A\u0E16\u0E32\u0E27\u0E23",
1265
+ archived: "\u0E40\u0E01\u0E47\u0E1A\u0E16\u0E32\u0E27\u0E23\u0E41\u0E25\u0E49\u0E27",
1266
+ pin: "\u0E1B\u0E31\u0E01\u0E2B\u0E21\u0E38\u0E14",
1267
+ unpin: "\u0E40\u0E25\u0E34\u0E01\u0E1B\u0E31\u0E01\u0E2B\u0E21\u0E38\u0E14",
1268
+ pinned: "\u0E1B\u0E31\u0E01\u0E2B\u0E21\u0E38\u0E14\u0E41\u0E25\u0E49\u0E27",
1269
+ collection: "\u0E04\u0E2D\u0E25\u0E40\u0E25\u0E01\u0E0A\u0E31\u0E19",
1270
+ allCollections: "\u0E04\u0E2D\u0E25\u0E40\u0E25\u0E01\u0E0A\u0E31\u0E19\u0E17\u0E31\u0E49\u0E07\u0E2B\u0E21\u0E14",
1271
+ filterCollections: "\u0E01\u0E23\u0E2D\u0E07\u0E04\u0E2D\u0E25\u0E40\u0E25\u0E01\u0E0A\u0E31\u0E19",
1272
+ uncategorized: "\u0E44\u0E21\u0E48\u0E21\u0E35\u0E2B\u0E21\u0E27\u0E14\u0E2B\u0E21\u0E39\u0E48",
1273
+ saveWithNote: "\u0E1A\u0E31\u0E19\u0E17\u0E36\u0E01\u0E1E\u0E23\u0E49\u0E2D\u0E21\u0E42\u0E19\u0E49\u0E15",
1132
1274
  save: "\u0E1A\u0E31\u0E19\u0E17\u0E36\u0E01",
1133
1275
  saved: "\u0E1A\u0E31\u0E19\u0E17\u0E36\u0E01\u0E41\u0E25\u0E49\u0E27",
1134
1276
  remove: "\u0E25\u0E1A",
@@ -1215,6 +1357,17 @@ var TH_LABELS = {
1215
1357
 
1216
1358
  // src/locales/vi.ts
1217
1359
  var VI_LABELS = {
1360
+ archive: "L\u01B0u tr\u1EEF",
1361
+ unarchive: "B\u1ECF l\u01B0u tr\u1EEF",
1362
+ archived: "\u0110\xE3 l\u01B0u tr\u1EEF",
1363
+ pin: "Ghim",
1364
+ unpin: "B\u1ECF ghim",
1365
+ pinned: "\u0110\xE3 ghim",
1366
+ collection: "B\u1ED9 s\u01B0u t\u1EADp",
1367
+ allCollections: "T\u1EA5t c\u1EA3 b\u1ED9 s\u01B0u t\u1EADp",
1368
+ filterCollections: "L\u1ECDc theo b\u1ED9 s\u01B0u t\u1EADp",
1369
+ uncategorized: "Ch\u01B0a ph\xE2n lo\u1EA1i",
1370
+ saveWithNote: "L\u01B0u k\xE8m ghi ch\xFA",
1218
1371
  save: "L\u01B0u",
1219
1372
  saved: "\u0110\xE3 l\u01B0u",
1220
1373
  remove: "X\xF3a",
@@ -1301,6 +1454,17 @@ var VI_LABELS = {
1301
1454
 
1302
1455
  // src/locales/zh-Hans.ts
1303
1456
  var ZH_HANS_LABELS = {
1457
+ archive: "\u5F52\u6863",
1458
+ unarchive: "\u53D6\u6D88\u5F52\u6863",
1459
+ archived: "\u5DF2\u5F52\u6863",
1460
+ pin: "\u7F6E\u9876",
1461
+ unpin: "\u53D6\u6D88\u7F6E\u9876",
1462
+ pinned: "\u5DF2\u7F6E\u9876",
1463
+ collection: "\u96C6\u5408",
1464
+ allCollections: "\u6240\u6709\u96C6\u5408",
1465
+ filterCollections: "\u6309\u96C6\u5408\u7B5B\u9009",
1466
+ uncategorized: "\u672A\u5206\u7C7B",
1467
+ saveWithNote: "\u4FDD\u5B58\u5E76\u6DFB\u52A0\u5907\u6CE8",
1304
1468
  save: "\u4FDD\u5B58",
1305
1469
  saved: "\u5DF2\u4FDD\u5B58",
1306
1470
  remove: "\u5220\u9664",
@@ -1387,6 +1551,17 @@ var ZH_HANS_LABELS = {
1387
1551
 
1388
1552
  // src/locales/zh-Hant.ts
1389
1553
  var ZH_HANT_LABELS = {
1554
+ archive: "\u5C01\u5B58",
1555
+ unarchive: "\u53D6\u6D88\u5C01\u5B58",
1556
+ archived: "\u5DF2\u5C01\u5B58",
1557
+ pin: "\u91D8\u9078",
1558
+ unpin: "\u53D6\u6D88\u91D8\u9078",
1559
+ pinned: "\u5DF2\u91D8\u9078",
1560
+ collection: "\u6536\u85CF\u96C6",
1561
+ allCollections: "\u6240\u6709\u6536\u85CF\u96C6",
1562
+ filterCollections: "\u4F9D\u6536\u85CF\u96C6\u7BE9\u9078",
1563
+ uncategorized: "\u672A\u5206\u985E",
1564
+ saveWithNote: "\u5132\u5B58\u4E26\u52A0\u5099\u8A3B",
1390
1565
  save: "\u5132\u5B58",
1391
1566
  saved: "\u5DF2\u5132\u5B58",
1392
1567
  remove: "\u522A\u9664",
@@ -1570,7 +1745,84 @@ function useKeepUiFeedback() {
1570
1745
  return useCallback((event) => emitFeedback(event), [emitFeedback]);
1571
1746
  }
1572
1747
 
1748
+ // src/features/actions/KeepArchiveButton.tsx
1749
+ import { jsxs } from "react/jsx-runtime";
1750
+ function KeepArchiveButton({
1751
+ item,
1752
+ children,
1753
+ archiveLabel,
1754
+ unarchiveLabel,
1755
+ onToggleError,
1756
+ disabled,
1757
+ ...props
1758
+ }) {
1759
+ const state = useKeepItem(item);
1760
+ const archive = useUiLabel("archive");
1761
+ const unarchive = useUiLabel("unarchive");
1762
+ const archivedLabel = useUiLabel("archived");
1763
+ const isArchived = state.item?.archived === true;
1764
+ const isDisabled = disabled ?? state.isMutating;
1765
+ return /* @__PURE__ */ jsxs(
1766
+ "button",
1767
+ {
1768
+ ...props,
1769
+ type: props.type ?? "button",
1770
+ disabled: isDisabled,
1771
+ "aria-pressed": isArchived,
1772
+ "data-archived": isArchived ? "true" : "false",
1773
+ "data-keep-action": "toggle-archive",
1774
+ onClick: () => void state.toggleArchive().catch((error) => onToggleError?.(error)),
1775
+ children: [
1776
+ typeof children === "function" ? children(state) : children ?? (isArchived ? unarchiveLabel ?? unarchive : archiveLabel ?? archive),
1777
+ isArchived && children === void 0 ? /* @__PURE__ */ jsxs("span", { "aria-hidden": "true", children: [
1778
+ " (",
1779
+ archivedLabel,
1780
+ ")"
1781
+ ] }) : null
1782
+ ]
1783
+ }
1784
+ );
1785
+ }
1786
+ function KeepPinButton({
1787
+ item,
1788
+ children,
1789
+ pinLabel,
1790
+ unpinLabel,
1791
+ onToggleError,
1792
+ disabled,
1793
+ ...props
1794
+ }) {
1795
+ const state = useKeepItem(item);
1796
+ const pin = useUiLabel("pin");
1797
+ const unpin = useUiLabel("unpin");
1798
+ const pinnedLabel = useUiLabel("pinned");
1799
+ const isPinned = state.item?.pinned === true;
1800
+ const isDisabled = disabled ?? state.isMutating;
1801
+ return /* @__PURE__ */ jsxs(
1802
+ "button",
1803
+ {
1804
+ ...props,
1805
+ type: props.type ?? "button",
1806
+ disabled: isDisabled,
1807
+ "aria-pressed": isPinned,
1808
+ "data-pinned": isPinned ? "true" : "false",
1809
+ "data-keep-action": "toggle-pin",
1810
+ onClick: () => void state.togglePin().catch((error) => onToggleError?.(error)),
1811
+ children: [
1812
+ typeof children === "function" ? children(state) : children ?? (isPinned ? unpinLabel ?? unpin : pinLabel ?? pin),
1813
+ isPinned && children === void 0 ? /* @__PURE__ */ jsxs("span", { "aria-hidden": "true", children: [
1814
+ " (",
1815
+ pinnedLabel,
1816
+ ")"
1817
+ ] }) : null
1818
+ ]
1819
+ }
1820
+ );
1821
+ }
1822
+
1573
1823
  // src/features/actions/hooks/useKeepBackup.ts
1824
+ import { useKeepContext } from "@keepkit/core/react";
1825
+ import { useRef as useRef2, useState } from "react";
1574
1826
  function useKeepBackup({ filename, onExport, onImported }) {
1575
1827
  const context = useKeepContext();
1576
1828
  const inputRef = useRef2(null);
@@ -1631,7 +1883,7 @@ function useKeepBackup({ filename, onExport, onImported }) {
1631
1883
  }
1632
1884
 
1633
1885
  // src/features/actions/KeepBackup.tsx
1634
- import { jsx as jsx2, jsxs } from "react/jsx-runtime";
1886
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
1635
1887
  function KeepBackup({
1636
1888
  filename = "keepkit-backup.json",
1637
1889
  onExport,
@@ -1639,7 +1891,7 @@ function KeepBackup({
1639
1891
  ...props
1640
1892
  }) {
1641
1893
  const view = useKeepBackup({ filename, onExport, onImported });
1642
- return /* @__PURE__ */ jsxs(
1894
+ return /* @__PURE__ */ jsxs2(
1643
1895
  "section",
1644
1896
  {
1645
1897
  ...props,
@@ -1657,9 +1909,9 @@ function KeepBackup({
1657
1909
  children: view.labels.export
1658
1910
  }
1659
1911
  ),
1660
- /* @__PURE__ */ jsxs("label", { children: [
1912
+ /* @__PURE__ */ jsxs2("label", { children: [
1661
1913
  view.labels.importMode,
1662
- /* @__PURE__ */ jsxs(
1914
+ /* @__PURE__ */ jsxs2(
1663
1915
  "select",
1664
1916
  {
1665
1917
  "data-keep-action": "select-import-mode",
@@ -1684,7 +1936,7 @@ function KeepBackup({
1684
1936
  onChange: (event) => void view.importBackup(event)
1685
1937
  }
1686
1938
  ),
1687
- view.result ? /* @__PURE__ */ jsxs("p", { role: "status", children: [
1939
+ view.result ? /* @__PURE__ */ jsxs2("p", { role: "status", children: [
1688
1940
  view.result.imported,
1689
1941
  " ",
1690
1942
  view.labels.importedCount,
@@ -1712,7 +1964,8 @@ import {
1712
1964
  cloneElement,
1713
1965
  createContext as createContext2,
1714
1966
  isValidElement,
1715
- useContext as useContext2
1967
+ useContext as useContext2,
1968
+ useMemo as useMemo2
1716
1969
  } from "react";
1717
1970
  import { Fragment, jsx as jsx3 } from "react/jsx-runtime";
1718
1971
  var KeepSearchQueryContext = createContext2(void 0);
@@ -1725,8 +1978,11 @@ function useKeepSearchQuery() {
1725
1978
  function KeepHighlight({ children, query }) {
1726
1979
  const contextQuery = useKeepSearchQuery();
1727
1980
  const resolvedQuery = query ?? contextQuery;
1728
- if (typeof children !== "string" || !resolvedQuery?.trim()) return children ?? null;
1729
- return highlightText(children, resolvedQuery);
1981
+ const normalizedQuery = resolvedQuery?.trim() ?? "";
1982
+ return useMemo2(() => {
1983
+ if (typeof children !== "string" || !normalizedQuery) return children ?? null;
1984
+ return highlightText(children, normalizedQuery);
1985
+ }, [children, normalizedQuery]);
1730
1986
  }
1731
1987
  function highlightText(text, query) {
1732
1988
  const normalizedQuery = query.trim();
@@ -1759,7 +2015,10 @@ function toKeepButtonItem(item) {
1759
2015
  meta: item.meta,
1760
2016
  targetType: item.targetType,
1761
2017
  note: item.note,
1762
- tags: item.tags
2018
+ tags: item.tags,
2019
+ archived: item.archived,
2020
+ pinned: item.pinned,
2021
+ collectionId: item.collectionId
1763
2022
  };
1764
2023
  }
1765
2024
  function getMetaTitle(meta) {
@@ -1776,6 +2035,17 @@ function sortToValue(sort) {
1776
2035
  function resolveContent(content, state) {
1777
2036
  return typeof content === "function" ? content(state) : content;
1778
2037
  }
2038
+ function composeRefs(...refs) {
2039
+ return (value) => {
2040
+ for (const ref of refs) {
2041
+ if (typeof ref === "function") {
2042
+ ref(value);
2043
+ } else if (ref !== null && ref !== void 0) {
2044
+ ref.current = value;
2045
+ }
2046
+ }
2047
+ };
2048
+ }
1779
2049
  function chainedFunction(childHandler, parentHandler) {
1780
2050
  if (!childHandler) return parentHandler;
1781
2051
  if (!parentHandler) return childHandler;
@@ -1786,6 +2056,12 @@ function chainedFunction(childHandler, parentHandler) {
1786
2056
  }
1787
2057
  function mergeProps(childProps, parentProps) {
1788
2058
  const merged = { ...parentProps, ...childProps };
2059
+ if ("ref" in childProps || "ref" in parentProps) {
2060
+ merged.ref = composeRefs(
2061
+ childProps.ref,
2062
+ parentProps.ref
2063
+ );
2064
+ }
1789
2065
  const className = mergeClassNames(childProps.className, parentProps.className);
1790
2066
  if (className) merged.className = className;
1791
2067
  const style = mergeStyles(childProps.style, parentProps.style);
@@ -1965,7 +2241,7 @@ function getItemLabel(item) {
1965
2241
  }
1966
2242
 
1967
2243
  // src/features/actions/KeepBulkActions.tsx
1968
- import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
2244
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1969
2245
  function KeepBulkActions({
1970
2246
  query,
1971
2247
  selectedIds: controlledSelectedIds,
@@ -1988,12 +2264,12 @@ function KeepBulkActions({
1988
2264
  controlledScope,
1989
2265
  onSelectionScopeChange
1990
2266
  });
1991
- const body = render ? render(state) : typeof children === "function" ? children(state) : children ?? /* @__PURE__ */ jsxs2(Fragment2, { children: [
1992
- /* @__PURE__ */ jsxs2("fieldset", { children: [
2267
+ const body = render ? render(state) : typeof children === "function" ? children(state) : children ?? /* @__PURE__ */ jsxs3(Fragment2, { children: [
2268
+ /* @__PURE__ */ jsxs3("fieldset", { children: [
1993
2269
  /* @__PURE__ */ jsx5("legend", { children: labels.selectItems }),
1994
- /* @__PURE__ */ jsxs2("label", { children: [
2270
+ /* @__PURE__ */ jsxs3("label", { children: [
1995
2271
  labels.selectionScope,
1996
- /* @__PURE__ */ jsxs2(
2272
+ /* @__PURE__ */ jsxs3(
1997
2273
  "select",
1998
2274
  {
1999
2275
  "data-keep-action": "select-scope",
@@ -2007,7 +2283,7 @@ function KeepBulkActions({
2007
2283
  }
2008
2284
  )
2009
2285
  ] }),
2010
- /* @__PURE__ */ jsxs2("label", { children: [
2286
+ /* @__PURE__ */ jsxs3("label", { children: [
2011
2287
  /* @__PURE__ */ jsx5(
2012
2288
  "input",
2013
2289
  {
@@ -2022,7 +2298,7 @@ function KeepBulkActions({
2022
2298
  " ",
2023
2299
  labels.selectedCount
2024
2300
  ] }),
2025
- state.items.map((item) => /* @__PURE__ */ jsxs2("span", { children: [
2301
+ state.items.map((item) => /* @__PURE__ */ jsxs3("span", { children: [
2026
2302
  /* @__PURE__ */ jsx5(
2027
2303
  KeepItemCheckbox,
2028
2304
  {
@@ -2044,7 +2320,7 @@ function KeepBulkActions({
2044
2320
  children: labels.deleteSelected
2045
2321
  }
2046
2322
  ),
2047
- /* @__PURE__ */ jsxs2("label", { children: [
2323
+ /* @__PURE__ */ jsxs3("label", { children: [
2048
2324
  labels.tags,
2049
2325
  /* @__PURE__ */ jsx5(
2050
2326
  "input",
@@ -2086,10 +2362,10 @@ import {
2086
2362
  import { createElement, useEffect as useEffect2, useRef as useRef3 } from "react";
2087
2363
 
2088
2364
  // src/features/actions/hooks/useKeepButton.ts
2089
- import { useKeepItem } from "@keepkit/core/react";
2365
+ import { useKeepItem as useKeepItem2 } from "@keepkit/core/react";
2090
2366
  function useKeepButton({ item, labels, icons, children }) {
2091
2367
  return {
2092
- buttonState: useKeepItem(item),
2368
+ buttonState: useKeepItem2(item),
2093
2369
  emitFeedback: useKeepUiFeedback(),
2094
2370
  customStateLabel: labels?.loading !== void 0 || labels?.error !== void 0 || icons !== void 0 && children === void 0,
2095
2371
  labels: {
@@ -2106,7 +2382,7 @@ function useKeepButton({ item, labels, icons, children }) {
2106
2382
  }
2107
2383
 
2108
2384
  // src/features/actions/KeepButton.tsx
2109
- import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
2385
+ import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
2110
2386
  function KeepButton({
2111
2387
  labels,
2112
2388
  icons,
@@ -2151,7 +2427,7 @@ function KeepButton({
2151
2427
  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;
2152
2428
  if (!icons) return label;
2153
2429
  const icon = state.error ? icons.error : state.isMutating ? icons.loading : state.isSaved ? icons.remove ?? icons.saved : icons.save;
2154
- return /* @__PURE__ */ jsxs3(Fragment3, { children: [
2430
+ return /* @__PURE__ */ jsxs4(Fragment3, { children: [
2155
2431
  renderIcon(icon, iconClassName),
2156
2432
  showLabel && !iconOnly ? label : null
2157
2433
  ] });
@@ -2186,16 +2462,259 @@ function renderIcon(icon, className) {
2186
2462
  return icon ?? null;
2187
2463
  }
2188
2464
 
2465
+ // src/features/actions/KeepSavePopover.tsx
2466
+ import { useKeepItem as useKeepItem4 } from "@keepkit/core/react";
2467
+ import { useCallback as useCallback3, useEffect as useEffect4, useRef as useRef5, useState as useState4 } from "react";
2468
+
2469
+ // src/features/editor/KeepQuickEditor.tsx
2470
+ import { useKeepContext as useKeepContext2, useKeepItem as useKeepItem3 } from "@keepkit/core/react";
2471
+ import {
2472
+ useCallback as useCallback2,
2473
+ useEffect as useEffect3,
2474
+ useRef as useRef4,
2475
+ useState as useState3
2476
+ } from "react";
2477
+ import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
2478
+ function useKeepQuickEditor(item, options = {}) {
2479
+ const { debounceMs = 300, onSaved, onSaveError } = options;
2480
+ const itemState = useKeepItem3(item);
2481
+ const { error, isMutating, moveToCollection, updateNote, updateTags } = itemState;
2482
+ const baseline = itemState.item ?? item;
2483
+ const [note, setNote] = useState3(baseline.note ?? "");
2484
+ const [tags, setTags] = useState3(baseline.tags ?? []);
2485
+ const [collectionId, setCollectionId] = useState3(baseline.collectionId);
2486
+ const baselineRef = useRef4({
2487
+ note: baseline.note ?? "",
2488
+ tags: baseline.tags ?? [],
2489
+ collectionId: baseline.collectionId
2490
+ });
2491
+ const draftRef = useRef4({ note, tags, collectionId });
2492
+ draftRef.current = { note, tags, collectionId };
2493
+ useEffect3(() => {
2494
+ if (draftRef.current.note === baselineRef.current.note && sameTags(draftRef.current.tags, baselineRef.current.tags) && draftRef.current.collectionId === baselineRef.current.collectionId) {
2495
+ setNote(baseline.note ?? "");
2496
+ setTags(baseline.tags ?? []);
2497
+ setCollectionId(baseline.collectionId);
2498
+ baselineRef.current = {
2499
+ note: baseline.note ?? "",
2500
+ tags: baseline.tags ?? [],
2501
+ collectionId: baseline.collectionId
2502
+ };
2503
+ }
2504
+ }, [baseline]);
2505
+ const isDirty = note !== baselineRef.current.note || !sameTags(tags, baselineRef.current.tags) || collectionId !== baselineRef.current.collectionId;
2506
+ const flush = useCallback2(async () => {
2507
+ const draft = draftRef.current;
2508
+ try {
2509
+ if (draft.note !== baselineRef.current.note) await updateNote(draft.note.trim() || void 0);
2510
+ if (!sameTags(draft.tags, baselineRef.current.tags)) await updateTags(draft.tags);
2511
+ if (draft.collectionId !== baselineRef.current.collectionId) await moveToCollection(draft.collectionId);
2512
+ baselineRef.current = { note: draft.note, tags: [...draft.tags], collectionId: draft.collectionId };
2513
+ const { collectionId: _oldCollectionId, ...withoutCollection } = baseline;
2514
+ onSaved?.({
2515
+ ...withoutCollection,
2516
+ note: draft.note.trim() || void 0,
2517
+ tags: draft.tags,
2518
+ ...draft.collectionId ? { collectionId: draft.collectionId } : {}
2519
+ });
2520
+ } catch (error2) {
2521
+ onSaveError?.(error2);
2522
+ throw error2;
2523
+ }
2524
+ }, [baseline, moveToCollection, onSaveError, onSaved, updateNote, updateTags]);
2525
+ useEffect3(() => {
2526
+ if (!isDirty || debounceMs <= 0) return;
2527
+ const timer = window.setTimeout(() => void flush().catch(() => void 0), debounceMs);
2528
+ return () => window.clearTimeout(timer);
2529
+ }, [debounceMs, flush, isDirty]);
2530
+ return {
2531
+ state: {
2532
+ item,
2533
+ note,
2534
+ tags,
2535
+ collectionId,
2536
+ setNote,
2537
+ setTags,
2538
+ setCollectionId,
2539
+ isDirty,
2540
+ isSaving: isMutating,
2541
+ error,
2542
+ flush
2543
+ }
2544
+ };
2545
+ }
2546
+ function KeepQuickEditor({
2547
+ item,
2548
+ debounceMs = 300,
2549
+ collectionIds,
2550
+ collectionLabels,
2551
+ children,
2552
+ onClose,
2553
+ onSaved,
2554
+ onSaveError,
2555
+ ...props
2556
+ }) {
2557
+ const view = useKeepQuickEditor(item, { debounceMs, onSaved, onSaveError });
2558
+ const context = useKeepContext2();
2559
+ const { state } = view;
2560
+ const rootRef = useRef4(null);
2561
+ const noteLabel = useUiLabel("note");
2562
+ const tagsLabel = useUiLabel("tags");
2563
+ const collectionLabel = useUiLabel("collection");
2564
+ const uncategorizedLabel = useUiLabel("uncategorized");
2565
+ const saveLabel = useUiLabel("saveWithNote");
2566
+ const closeLabel = useUiLabel("close");
2567
+ const submit = (event) => {
2568
+ event.preventDefault();
2569
+ void state.flush().catch(() => void 0);
2570
+ };
2571
+ const onKeyDown = (event) => {
2572
+ if (event.key === "Escape") {
2573
+ event.preventDefault();
2574
+ void state.flush().then(() => onClose?.()).catch(() => void 0);
2575
+ }
2576
+ if (event.key === "Tab") trapFocus(event, rootRef.current);
2577
+ };
2578
+ const body = typeof children === "function" ? children(state) : children ?? /* @__PURE__ */ jsxs5(Fragment4, { children: [
2579
+ /* @__PURE__ */ jsxs5("label", { children: [
2580
+ noteLabel,
2581
+ /* @__PURE__ */ jsx7("textarea", { value: state.note, onChange: (event) => state.setNote(event.currentTarget.value) })
2582
+ ] }),
2583
+ /* @__PURE__ */ jsxs5("label", { children: [
2584
+ tagsLabel,
2585
+ /* @__PURE__ */ jsx7(
2586
+ "input",
2587
+ {
2588
+ value: state.tags.join(", "),
2589
+ onChange: (event) => state.setTags(
2590
+ event.currentTarget.value.split(",").map((tag) => tag.trim()).filter(Boolean)
2591
+ )
2592
+ }
2593
+ )
2594
+ ] }),
2595
+ /* @__PURE__ */ jsxs5("label", { children: [
2596
+ collectionLabel,
2597
+ /* @__PURE__ */ jsxs5(
2598
+ "select",
2599
+ {
2600
+ value: state.collectionId ?? "",
2601
+ onChange: (event) => state.setCollectionId(event.currentTarget.value || void 0),
2602
+ children: [
2603
+ /* @__PURE__ */ jsx7("option", { value: "", children: uncategorizedLabel }),
2604
+ (collectionIds ?? [
2605
+ ...new Set(
2606
+ context.items.map((entry) => entry.collectionId).filter((id) => Boolean(id))
2607
+ )
2608
+ ].sort()).map((id) => /* @__PURE__ */ jsx7("option", { value: id, children: collectionLabels?.[id] ?? id }, id))
2609
+ ]
2610
+ }
2611
+ )
2612
+ ] }),
2613
+ /* @__PURE__ */ jsx7("button", { type: "submit", disabled: state.isSaving, "data-keep-action": "save-quick-edit", children: saveLabel }),
2614
+ /* @__PURE__ */ jsx7(
2615
+ "button",
2616
+ {
2617
+ type: "button",
2618
+ onClick: () => void state.flush().then(() => onClose?.()).catch(() => void 0),
2619
+ disabled: state.isSaving,
2620
+ "data-keep-action": "close-quick-edit",
2621
+ children: closeLabel
2622
+ }
2623
+ )
2624
+ ] });
2625
+ return /* @__PURE__ */ jsx7(
2626
+ "form",
2627
+ {
2628
+ ...props,
2629
+ ref: rootRef,
2630
+ onSubmit: submit,
2631
+ onKeyDown,
2632
+ "data-keepkit": "quick-editor",
2633
+ "data-state": state.isDirty ? "dirty" : "clean",
2634
+ "aria-busy": state.isSaving || props["aria-busy"],
2635
+ children: body
2636
+ }
2637
+ );
2638
+ }
2639
+ function sameTags(left, right) {
2640
+ return left.length === right.length && left.every((tag, index) => tag === right[index]);
2641
+ }
2642
+ function trapFocus(event, root) {
2643
+ if (!root) return;
2644
+ const elements = [
2645
+ ...root.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])')
2646
+ ].filter((element) => !element.hasAttribute("disabled"));
2647
+ if (elements.length === 0) return;
2648
+ const first = elements[0];
2649
+ const last = elements[elements.length - 1];
2650
+ if (event.shiftKey && document.activeElement === first) {
2651
+ event.preventDefault();
2652
+ last.focus();
2653
+ } else if (!event.shiftKey && document.activeElement === last) {
2654
+ event.preventDefault();
2655
+ first.focus();
2656
+ }
2657
+ }
2658
+
2659
+ // src/features/actions/KeepSavePopover.tsx
2660
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
2661
+ function KeepSavePopover({
2662
+ item,
2663
+ open: controlledOpen,
2664
+ defaultOpen = false,
2665
+ onOpenChange,
2666
+ buttonProps,
2667
+ editorProps,
2668
+ children,
2669
+ ...props
2670
+ }) {
2671
+ const state = useKeepItem4(item);
2672
+ const [internalOpen, setInternalOpen] = useState4(defaultOpen);
2673
+ const isOpen = controlledOpen ?? internalOpen;
2674
+ const triggerRef = useRef5(null);
2675
+ const previousSaved = useRef5(state.isSaved);
2676
+ const observedHydration = useRef5(!state.isLoading);
2677
+ const closeLabel = useUiLabel("close");
2678
+ const { ref: _buttonRef, ...resolvedButtonProps } = buttonProps ?? {};
2679
+ const setOpen = useCallback3(
2680
+ (next) => {
2681
+ if (controlledOpen === void 0) setInternalOpen(next);
2682
+ onOpenChange?.(next);
2683
+ if (!next) window.setTimeout(() => triggerRef.current?.focus(), 0);
2684
+ },
2685
+ [controlledOpen, onOpenChange]
2686
+ );
2687
+ useEffect4(() => {
2688
+ if (!observedHydration.current) {
2689
+ if (state.isLoading) return;
2690
+ observedHydration.current = true;
2691
+ previousSaved.current = state.isSaved;
2692
+ return;
2693
+ }
2694
+ if (!previousSaved.current && state.isSaved) setOpen(true);
2695
+ previousSaved.current = state.isSaved;
2696
+ }, [setOpen, state.isLoading, state.isSaved]);
2697
+ const currentItem = state.item;
2698
+ return /* @__PURE__ */ jsxs6("div", { ...props, "data-keepkit": "save-popover", "data-open": isOpen ? "true" : "false", children: [
2699
+ /* @__PURE__ */ jsx8(KeepButton, { ...resolvedButtonProps, item, asChild: false, ref: triggerRef }),
2700
+ isOpen && currentItem ? /* @__PURE__ */ jsxs6("div", { role: "dialog", "aria-label": children ? void 0 : closeLabel, "data-keep-popover-panel": "true", children: [
2701
+ children,
2702
+ /* @__PURE__ */ jsx8(KeepQuickEditor, { ...editorProps, item: currentItem, onClose: () => setOpen(false) }),
2703
+ /* @__PURE__ */ jsx8("button", { type: "button", onClick: () => setOpen(false), "data-keep-action": "close-save-popover", children: closeLabel })
2704
+ ] }) : null
2705
+ ] });
2706
+ }
2707
+
2189
2708
  // src/features/actions/hooks/useKeepUndo.ts
2190
- import { useKeepContext as useKeepContext2 } from "@keepkit/core/react";
2191
- import { useEffect as useEffect3, useState as useState3 } from "react";
2709
+ import { useKeepContext as useKeepContext3 } from "@keepkit/core/react";
2710
+ import { useEffect as useEffect5, useState as useState5 } from "react";
2192
2711
  function useKeepUndo() {
2193
- const context = useKeepContext2();
2712
+ const context = useKeepContext3();
2194
2713
  const emitFeedback = useKeepUiFeedback();
2195
2714
  const restoredMessage = useUiLabel("restoredMessage");
2196
2715
  const { canUndo, startedAt, expiresAt } = context.undo;
2197
- const [now, setNow] = useState3(() => Date.now());
2198
- useEffect3(() => {
2716
+ const [now, setNow] = useState5(() => Date.now());
2717
+ useEffect5(() => {
2199
2718
  if (!canUndo || expiresAt === void 0) return;
2200
2719
  setNow(Date.now());
2201
2720
  const timer = setInterval(() => setNow(Date.now()), 250);
@@ -2224,17 +2743,17 @@ function useKeepUndo() {
2224
2743
  }
2225
2744
 
2226
2745
  // src/features/actions/KeepUndo.tsx
2227
- import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
2746
+ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
2228
2747
  function KeepUndo({ children, label, ...props }) {
2229
2748
  const view = useKeepUndo();
2230
2749
  if (!view.canUndo) return null;
2231
- return /* @__PURE__ */ jsxs4("div", { ...props, role: "status", "aria-live": "polite", "data-keepkit": "undo", "data-state": "available", children: [
2232
- /* @__PURE__ */ jsx7("span", { "data-keepkit": "undo-message", children: children ?? view.message }),
2233
- /* @__PURE__ */ jsxs4("span", { "data-keepkit": "undo-countdown", "aria-hidden": "true", children: [
2750
+ return /* @__PURE__ */ jsxs7("div", { ...props, role: "status", "aria-live": "polite", "data-keepkit": "undo", "data-state": "available", children: [
2751
+ /* @__PURE__ */ jsx9("span", { "data-keepkit": "undo-message", children: children ?? view.message }),
2752
+ /* @__PURE__ */ jsxs7("span", { "data-keepkit": "undo-countdown", "aria-hidden": "true", children: [
2234
2753
  view.remainingSeconds,
2235
2754
  "s"
2236
2755
  ] }),
2237
- /* @__PURE__ */ jsx7(
2756
+ /* @__PURE__ */ jsx9(
2238
2757
  "progress",
2239
2758
  {
2240
2759
  "data-keepkit": "undo-progress",
@@ -2244,7 +2763,7 @@ function KeepUndo({ children, label, ...props }) {
2244
2763
  "aria-valuetext": `${view.remainingSeconds}s`
2245
2764
  }
2246
2765
  ),
2247
- /* @__PURE__ */ jsx7("button", { type: "button", "data-keep-action": "undo", onClick: () => void view.undo(), children: label ?? view.label })
2766
+ /* @__PURE__ */ jsx9("button", { type: "button", "data-keep-action": "undo", onClick: () => void view.undo(), children: label ?? view.label })
2248
2767
  ] });
2249
2768
  }
2250
2769
 
@@ -2252,8 +2771,11 @@ function KeepUndo({ children, label, ...props }) {
2252
2771
  import { KeepErrorBoundary as KeepErrorBoundary2 } from "@keepkit/core/react";
2253
2772
 
2254
2773
  // src/features/query/KeepActiveFiltersSummary.tsx
2255
- import { isValidElement as isValidElement2 } from "react";
2256
- import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
2774
+ import {
2775
+ isValidElement as isValidElement2,
2776
+ useRef as useRef6
2777
+ } from "react";
2778
+ import { Fragment as Fragment5, jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
2257
2779
  function KeepActiveFiltersSummary({
2258
2780
  query,
2259
2781
  search: providedSearch,
@@ -2273,6 +2795,38 @@ function KeepActiveFiltersSummary({
2273
2795
  const clearAllLabel = useUiLabel("clearAllFilters");
2274
2796
  const clearLabel = useUiLabel("clearFilters");
2275
2797
  const removeLabel = useUiLabel("removeFilter");
2798
+ const chipRefs = useRef6([]);
2799
+ const filterCount = Number(Boolean(search)) + tags.length;
2800
+ function focusChip(index) {
2801
+ chipRefs.current[index]?.focus();
2802
+ }
2803
+ function focusAfterRemoval(index, source) {
2804
+ const summaryRoot = source.closest('[data-keepkit="active-filters"]');
2805
+ const fallbackScope = source.closest('[data-keepkit="collection"]') ?? summaryRoot?.parentElement ?? source.parentElement;
2806
+ queueMicrotask(() => {
2807
+ const nextIndex = index < filterCount - 1 ? index : index - 1;
2808
+ const nextChip = nextIndex >= 0 ? chipRefs.current[nextIndex] : null;
2809
+ if (nextChip?.isConnected) {
2810
+ nextChip.focus();
2811
+ return;
2812
+ }
2813
+ focusFilterFallback(fallbackScope);
2814
+ });
2815
+ }
2816
+ function handleChipKeyDown(event, index) {
2817
+ const nextIndex = event.key === "ArrowRight" ? index + 1 : event.key === "ArrowLeft" ? index - 1 : -1;
2818
+ if (nextIndex < 0 || nextIndex >= filterCount || !chipRefs.current[nextIndex]) return;
2819
+ event.preventDefault();
2820
+ focusChip(nextIndex);
2821
+ }
2822
+ function removeSearch(event) {
2823
+ focusAfterRemoval(0, event.currentTarget);
2824
+ onSearchChange?.("");
2825
+ }
2826
+ function removeTag(tag, index, event) {
2827
+ focusAfterRemoval(index, event.currentTarget);
2828
+ onTagChange?.(tag);
2829
+ }
2276
2830
  const state = {
2277
2831
  search,
2278
2832
  tags,
@@ -2282,37 +2836,45 @@ function KeepActiveFiltersSummary({
2282
2836
  removeTag: (tag) => onTagChange?.(tag)
2283
2837
  };
2284
2838
  const contentChildren = asChild && isElement(children) ? void 0 : children;
2285
- const body = typeof contentChildren === "function" ? contentChildren(state) : contentChildren ?? (hasFilters ? /* @__PURE__ */ jsxs5(Fragment4, { children: [
2286
- /* @__PURE__ */ jsx8("span", { "data-active-filters-label": "true", children: activeFiltersLabel }),
2287
- /* @__PURE__ */ jsxs5("ul", { "data-active-filters-list": "true", children: [
2288
- search ? /* @__PURE__ */ jsxs5("li", { "data-filter-kind": "search", children: [
2289
- /* @__PURE__ */ jsx8("span", { "data-filter-value": "true", children: search }),
2290
- /* @__PURE__ */ jsx8(
2839
+ const body = typeof contentChildren === "function" ? contentChildren(state) : contentChildren ?? (hasFilters ? /* @__PURE__ */ jsxs8(Fragment5, { children: [
2840
+ /* @__PURE__ */ jsx10("span", { "data-active-filters-label": "true", children: activeFiltersLabel }),
2841
+ /* @__PURE__ */ jsxs8("ul", { "data-active-filters-list": "true", children: [
2842
+ search ? /* @__PURE__ */ jsxs8("li", { "data-filter-kind": "search", children: [
2843
+ /* @__PURE__ */ jsx10("span", { "data-filter-value": "true", children: search }),
2844
+ /* @__PURE__ */ jsx10(
2291
2845
  "button",
2292
2846
  {
2293
2847
  type: "button",
2294
2848
  "data-keep-action": "remove-search-filter",
2295
2849
  "aria-label": `${search} ${removeLabel}`,
2296
- onClick: state.removeSearch,
2850
+ ref: (element) => {
2851
+ chipRefs.current[0] = element;
2852
+ },
2853
+ onKeyDown: (event) => handleChipKeyDown(event, 0),
2854
+ onClick: removeSearch,
2297
2855
  children: "\xD7"
2298
2856
  }
2299
2857
  )
2300
2858
  ] }) : null,
2301
- tags.map((tag) => /* @__PURE__ */ jsxs5("li", { "data-filter-kind": "tag", children: [
2302
- /* @__PURE__ */ jsx8("span", { "data-filter-value": "true", children: tag }),
2303
- /* @__PURE__ */ jsx8(
2859
+ tags.map((tag, tagIndex) => /* @__PURE__ */ jsxs8("li", { "data-filter-kind": "tag", children: [
2860
+ /* @__PURE__ */ jsx10("span", { "data-filter-value": "true", children: tag }),
2861
+ /* @__PURE__ */ jsx10(
2304
2862
  "button",
2305
2863
  {
2306
2864
  type: "button",
2307
2865
  "data-keep-action": "remove-tag-filter",
2308
2866
  "aria-label": `${tag} ${removeLabel}`,
2309
- onClick: () => state.removeTag(tag),
2867
+ ref: (element) => {
2868
+ chipRefs.current[tagIndex + Number(Boolean(search))] = element;
2869
+ },
2870
+ onKeyDown: (event) => handleChipKeyDown(event, tagIndex + Number(Boolean(search))),
2871
+ onClick: (event) => removeTag(tag, tagIndex + Number(Boolean(search)), event),
2310
2872
  children: "\xD7"
2311
2873
  }
2312
2874
  )
2313
2875
  ] }, tag))
2314
2876
  ] }),
2315
- /* @__PURE__ */ jsx8("button", { type: "button", "data-keep-action": "clear-filters", onClick: state.clear, children: clearAllLabel || clearLabel })
2877
+ /* @__PURE__ */ jsx10("button", { type: "button", "data-keep-action": "clear-filters", onClick: state.clear, children: clearAllLabel || clearLabel })
2316
2878
  ] }) : null);
2317
2879
  if (!hasFilters && !asChild && contentChildren === void 0) return null;
2318
2880
  return renderRoot(
@@ -2335,22 +2897,131 @@ function normalizeTags(tags) {
2335
2897
  function isElement(value) {
2336
2898
  return isValidElement2(value);
2337
2899
  }
2900
+ function focusFilterFallback(scope) {
2901
+ const searchInput = scope?.querySelector('[data-keep-action="search"]');
2902
+ if (searchInput) {
2903
+ searchInput.focus();
2904
+ return;
2905
+ }
2906
+ const listCard = scope?.querySelector('[data-keepkit="card"][tabindex="0"]');
2907
+ if (listCard) {
2908
+ listCard.focus();
2909
+ return;
2910
+ }
2911
+ const list = scope?.querySelector('[data-keepkit="list"]');
2912
+ if (list) {
2913
+ if (!list.hasAttribute("tabindex")) list.tabIndex = -1;
2914
+ list.focus();
2915
+ }
2916
+ }
2917
+
2918
+ // src/features/query/KeepCollectionFilter.tsx
2919
+ import { useKeepContext as useKeepContext4 } from "@keepkit/core/react";
2920
+ import { useMemo as useMemo3, useState as useState6 } from "react";
2921
+ import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
2922
+ function useCollectionOptions(collectionLabels, items) {
2923
+ const ids = useMemo3(
2924
+ () => [...new Set((items ?? []).map((item) => item.collectionId).filter((id) => Boolean(id)))].sort(),
2925
+ [items]
2926
+ );
2927
+ return ids.map((id) => ({ id, label: collectionLabels?.[id] ?? id }));
2928
+ }
2929
+ function KeepCollectionSelect({
2930
+ item,
2931
+ value,
2932
+ defaultValue,
2933
+ onValueChange,
2934
+ onChange,
2935
+ collectionLabels,
2936
+ uncategorizedLabel,
2937
+ ...props
2938
+ }) {
2939
+ const context = useKeepContext4();
2940
+ const state = useState6(value ?? defaultValue ?? item.collectionId ?? "");
2941
+ const selected = value ?? state[0];
2942
+ const options = useCollectionOptions(collectionLabels, context.items);
2943
+ const defaultUncategorizedLabel = useUiLabel("uncategorized");
2944
+ const uncategorized = uncategorizedLabel ?? defaultUncategorizedLabel;
2945
+ const handleChange = (next) => {
2946
+ const resolved = next || void 0;
2947
+ if (value === void 0) state[1](next);
2948
+ onValueChange?.(resolved);
2949
+ onChange?.(resolved);
2950
+ void context.moveToCollection(item.id, resolved);
2951
+ };
2952
+ return /* @__PURE__ */ jsxs9(
2953
+ "select",
2954
+ {
2955
+ ...props,
2956
+ value: selected,
2957
+ onChange: (event) => handleChange(event.currentTarget.value),
2958
+ "data-keep-action": "move-collection",
2959
+ children: [
2960
+ /* @__PURE__ */ jsx11("option", { value: "", children: uncategorized }),
2961
+ options.map((option) => /* @__PURE__ */ jsx11("option", { value: option.id, children: option.label }, option.id))
2962
+ ]
2963
+ }
2964
+ );
2965
+ }
2966
+ function KeepCollectionFilter({
2967
+ value,
2968
+ defaultValue,
2969
+ onValueChange,
2970
+ onChange,
2971
+ collectionLabels,
2972
+ allLabel,
2973
+ uncategorizedLabel,
2974
+ ...props
2975
+ }) {
2976
+ const context = useKeepContext4();
2977
+ const [internalValue, setInternalValue] = useState6(value ?? defaultValue ?? "");
2978
+ const selected = value ?? internalValue;
2979
+ const options = useCollectionOptions(collectionLabels, context.items);
2980
+ const collectionLabel = useUiLabel("collection");
2981
+ const defaultAllLabel = useUiLabel("allCollections");
2982
+ const defaultUncategorizedLabel = useUiLabel("uncategorized");
2983
+ const all = allLabel ?? defaultAllLabel;
2984
+ const uncategorized = uncategorizedLabel ?? defaultUncategorizedLabel;
2985
+ const handleChange = (next) => {
2986
+ if (value === void 0) setInternalValue(next);
2987
+ const resolved = next || void 0;
2988
+ onValueChange?.(resolved);
2989
+ onChange?.(resolved);
2990
+ };
2991
+ return /* @__PURE__ */ jsxs9("label", { "data-keepkit": "collection-filter", children: [
2992
+ /* @__PURE__ */ jsx11("span", { children: collectionLabel }),
2993
+ /* @__PURE__ */ jsxs9(
2994
+ "select",
2995
+ {
2996
+ ...props,
2997
+ value: selected,
2998
+ onChange: (event) => handleChange(event.currentTarget.value),
2999
+ "data-keep-action": "filter-collection",
3000
+ children: [
3001
+ /* @__PURE__ */ jsx11("option", { value: "", children: all }),
3002
+ /* @__PURE__ */ jsx11("option", { value: "__uncategorized__", children: uncategorized }),
3003
+ options.map((option) => /* @__PURE__ */ jsx11("option", { value: option.id, children: option.label }, option.id))
3004
+ ]
3005
+ }
3006
+ )
3007
+ ] });
3008
+ }
2338
3009
 
2339
3010
  // src/features/query/KeepTagFilter.tsx
2340
3011
  import { isValidElement as isValidElement3 } from "react";
2341
3012
 
2342
3013
  // src/features/query/hooks/useKeepTagFilter.ts
2343
3014
  import { useKeepList as useKeepList2 } from "@keepkit/core/react";
2344
- import { useCallback as useCallback2, useMemo as useMemo2, useState as useState4 } from "react";
3015
+ import { useCallback as useCallback4, useMemo as useMemo4, useState as useState7 } from "react";
2345
3016
  function useKeepTagFilter(options) {
2346
3017
  const { query, controlledValue, defaultValue, onChange, onValueChange } = options;
2347
- const [uncontrolledValue, setUncontrolledValue] = useState4(defaultValue);
3018
+ const [uncontrolledValue, setUncontrolledValue] = useState7(defaultValue);
2348
3019
  const resolvedValue = controlledValue ?? uncontrolledValue;
2349
3020
  const list = useKeepList2({
2350
3021
  ...query,
2351
3022
  tags: resolvedValue ? [...query?.tags ?? [], resolvedValue] : query?.tags
2352
3023
  });
2353
- const select = useCallback2(
3024
+ const select = useCallback4(
2354
3025
  (tag) => {
2355
3026
  if (controlledValue === void 0) setUncontrolledValue(tag);
2356
3027
  onChange?.(tag);
@@ -2358,7 +3029,7 @@ function useKeepTagFilter(options) {
2358
3029
  },
2359
3030
  [controlledValue, onChange, onValueChange]
2360
3031
  );
2361
- const state = useMemo2(
3032
+ const state = useMemo4(
2362
3033
  () => ({ tags: list.tags, tagCounts: list.tagCounts, value: resolvedValue, select }),
2363
3034
  [list.tagCounts, list.tags, resolvedValue, select]
2364
3035
  );
@@ -2370,7 +3041,7 @@ function useKeepTagFilter(options) {
2370
3041
  }
2371
3042
 
2372
3043
  // src/features/query/KeepTagFilter.tsx
2373
- import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
3044
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
2374
3045
  function KeepTagFilter({
2375
3046
  query,
2376
3047
  value: controlledValue,
@@ -2388,9 +3059,9 @@ function KeepTagFilter({
2388
3059
  }) {
2389
3060
  const view = useKeepTagFilter({ query, controlledValue, defaultValue, onChange, onValueChange });
2390
3061
  const contentChildren = asChild && isValidElement3(children) ? void 0 : children;
2391
- const body = render ? render(view.state) : typeof contentChildren === "function" ? contentChildren(view.state) : contentChildren ?? /* @__PURE__ */ jsxs6("fieldset", { children: [
2392
- /* @__PURE__ */ jsx9("legend", { children: ariaLabel ?? view.labels.aria }),
2393
- /* @__PURE__ */ jsx9(
3062
+ const body = render ? render(view.state) : typeof contentChildren === "function" ? contentChildren(view.state) : contentChildren ?? /* @__PURE__ */ jsxs10("fieldset", { children: [
3063
+ /* @__PURE__ */ jsx12("legend", { children: ariaLabel ?? view.labels.aria }),
3064
+ /* @__PURE__ */ jsx12(
2394
3065
  "button",
2395
3066
  {
2396
3067
  type: "button",
@@ -2400,7 +3071,7 @@ function KeepTagFilter({
2400
3071
  children: allLabel ?? view.labels.all
2401
3072
  }
2402
3073
  ),
2403
- view.state.tags.map((tag) => /* @__PURE__ */ jsxs6(
3074
+ view.state.tags.map((tag) => /* @__PURE__ */ jsxs10(
2404
3075
  "button",
2405
3076
  {
2406
3077
  type: "button",
@@ -2409,7 +3080,7 @@ function KeepTagFilter({
2409
3080
  onClick: () => view.state.select(tag),
2410
3081
  children: [
2411
3082
  renderTag ? renderTag(tag, view.state.tagCounts[tag] ?? 0, view.state.value === tag) : tag,
2412
- /* @__PURE__ */ jsxs6("span", { children: [
3083
+ /* @__PURE__ */ jsxs10("span", { children: [
2413
3084
  " (",
2414
3085
  view.state.tagCounts[tag] ?? 0,
2415
3086
  ")"
@@ -2435,12 +3106,12 @@ function KeepTagFilter({
2435
3106
  }
2436
3107
 
2437
3108
  // src/features/query/hooks/useQueryControls.ts
2438
- import { useEffect as useEffect4, useState as useState5 } from "react";
3109
+ import { useEffect as useEffect6, useState as useState8 } from "react";
2439
3110
  function useKeepSearchInput(options) {
2440
3111
  const { controlledValue, defaultValue, debounceMs, onValueChange } = options;
2441
- const [uncontrolledValue, setUncontrolledValue] = useState5(defaultValue);
3112
+ const [uncontrolledValue, setUncontrolledValue] = useState8(defaultValue);
2442
3113
  const value = controlledValue ?? uncontrolledValue;
2443
- useEffect4(() => {
3114
+ useEffect6(() => {
2444
3115
  if (!onValueChange) return;
2445
3116
  if (debounceMs <= 0) {
2446
3117
  onValueChange(value);
@@ -2459,7 +3130,7 @@ function useKeepSearchInput(options) {
2459
3130
  }
2460
3131
  function useKeepSortSelect(options) {
2461
3132
  const { controlledValue, defaultValue, onValueChange } = options;
2462
- const [uncontrolledValue, setUncontrolledValue] = useState5(defaultValue);
3133
+ const [uncontrolledValue, setUncontrolledValue] = useState8(defaultValue);
2463
3134
  const value = controlledValue ?? uncontrolledValue;
2464
3135
  return {
2465
3136
  value,
@@ -2507,7 +3178,7 @@ function getVisiblePages(currentPage, pageCount, maxPageButtons) {
2507
3178
  }
2508
3179
 
2509
3180
  // src/features/query/query-controls.tsx
2510
- import { Fragment as Fragment5, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
3181
+ import { Fragment as Fragment6, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
2511
3182
  function KeepSearchInput({
2512
3183
  value: controlledValue,
2513
3184
  defaultValue = "",
@@ -2518,7 +3189,7 @@ function KeepSearchInput({
2518
3189
  ...props
2519
3190
  }) {
2520
3191
  const view = useKeepSearchInput({ controlledValue, defaultValue, debounceMs, onValueChange });
2521
- return /* @__PURE__ */ jsx10(
3192
+ return /* @__PURE__ */ jsx13(
2522
3193
  "input",
2523
3194
  {
2524
3195
  ...props,
@@ -2543,13 +3214,13 @@ function KeepSortSelect({
2543
3214
  ...props
2544
3215
  }) {
2545
3216
  const view = useKeepSortSelect({ controlledValue, defaultValue, onValueChange });
2546
- const options = children ?? /* @__PURE__ */ jsxs7(Fragment5, { children: [
2547
- /* @__PURE__ */ jsx10("option", { value: "updatedAt:desc", children: view.labels.updatedNewest }),
2548
- /* @__PURE__ */ jsx10("option", { value: "updatedAt:asc", children: view.labels.updatedOldest }),
2549
- /* @__PURE__ */ jsx10("option", { value: "savedAt:desc", children: view.labels.savedNewest }),
2550
- /* @__PURE__ */ jsx10("option", { value: "savedAt:asc", children: view.labels.savedOldest })
3217
+ const options = children ?? /* @__PURE__ */ jsxs11(Fragment6, { children: [
3218
+ /* @__PURE__ */ jsx13("option", { value: "updatedAt:desc", children: view.labels.updatedNewest }),
3219
+ /* @__PURE__ */ jsx13("option", { value: "updatedAt:asc", children: view.labels.updatedOldest }),
3220
+ /* @__PURE__ */ jsx13("option", { value: "savedAt:desc", children: view.labels.savedNewest }),
3221
+ /* @__PURE__ */ jsx13("option", { value: "savedAt:asc", children: view.labels.savedOldest })
2551
3222
  ] });
2552
- return /* @__PURE__ */ jsx10(
3223
+ return /* @__PURE__ */ jsx13(
2553
3224
  "select",
2554
3225
  {
2555
3226
  ...props,
@@ -2581,9 +3252,9 @@ function KeepPagination({
2581
3252
  "data-state": view.pageCount > 1 ? "active" : "idle"
2582
3253
  };
2583
3254
  if (render)
2584
- return /* @__PURE__ */ jsx10("nav", { ...navProps, children: render({ page: view.currentPage, pageCount: view.pageCount, goToPage: view.goToPage }) });
2585
- return /* @__PURE__ */ jsxs7("nav", { ...navProps, children: [
2586
- /* @__PURE__ */ jsx10(
3255
+ return /* @__PURE__ */ jsx13("nav", { ...navProps, children: render({ page: view.currentPage, pageCount: view.pageCount, goToPage: view.goToPage }) });
3256
+ return /* @__PURE__ */ jsxs11("nav", { ...navProps, children: [
3257
+ /* @__PURE__ */ jsx13(
2587
3258
  "button",
2588
3259
  {
2589
3260
  type: "button",
@@ -2593,7 +3264,7 @@ function KeepPagination({
2593
3264
  children: view.labels.previous
2594
3265
  }
2595
3266
  ),
2596
- view.visiblePages.map((nextPage) => /* @__PURE__ */ jsx10(
3267
+ view.visiblePages.map((nextPage) => /* @__PURE__ */ jsx13(
2597
3268
  "button",
2598
3269
  {
2599
3270
  type: "button",
@@ -2605,7 +3276,7 @@ function KeepPagination({
2605
3276
  },
2606
3277
  nextPage
2607
3278
  )),
2608
- /* @__PURE__ */ jsx10(
3279
+ /* @__PURE__ */ jsx13(
2609
3280
  "button",
2610
3281
  {
2611
3282
  type: "button",
@@ -2620,7 +3291,7 @@ function KeepPagination({
2620
3291
 
2621
3292
  // src/features/collection/hooks/useKeepCollection.ts
2622
3293
  import { useKeepList as useKeepList3 } from "@keepkit/core/react";
2623
- import { useMemo as useMemo3, useState as useState6 } from "react";
3294
+ import { useMemo as useMemo5, useState as useState9 } from "react";
2624
3295
  function useKeepCollection({
2625
3296
  query,
2626
3297
  pageSize,
@@ -2633,23 +3304,38 @@ function useKeepCollection({
2633
3304
  sort: true,
2634
3305
  pagination: true,
2635
3306
  tagFilter: false,
3307
+ collectionFilter: false,
2636
3308
  bulkActions: false,
2637
3309
  ...features
2638
3310
  };
2639
- const [searchValue, setSearchValue] = useState6(query.search?.query ?? "");
2640
- const [sort, setSort] = useState6(query.sort ?? { by: "updatedAt", direction: "desc" });
2641
- const [activeTags, setActiveTags] = useState6(query.tags ?? []);
2642
- const [page, setPage] = useState6(query.pagination?.page ?? 1);
3311
+ const [searchValue, setSearchValue] = useState9(query.search?.query ?? "");
3312
+ const [sort, setSort] = useState9(query.sort ?? { by: "updatedAt", direction: "desc" });
3313
+ const [activeTags, setActiveTags] = useState9(query.tags ?? []);
3314
+ const [activeCollection, setActiveCollection] = useState9(query.collectionId);
3315
+ const [page, setPage] = useState9(query.pagination?.page ?? 1);
2643
3316
  const resolvedPageSize = query.pagination?.pageSize ?? pageSize;
2644
- const resolvedQuery = useMemo3(
3317
+ const resolvedQuery = useMemo5(
2645
3318
  () => ({
2646
3319
  ...query,
2647
3320
  search: enabled.search ? { ...query.search, query: searchValue } : query.search,
2648
3321
  sort: enabled.sort ? sort : query.sort,
2649
3322
  tags: activeTags.length > 0 ? activeTags : void 0,
3323
+ collectionId: activeCollection && activeCollection !== "__uncategorized__" ? activeCollection : void 0,
3324
+ filter: activeCollection === "__uncategorized__" ? (item) => item.collectionId === void 0 && (query.filter?.(item) ?? true) : query.filter,
2650
3325
  pagination: enabled.pagination ? { ...query.pagination, page, pageSize: resolvedPageSize } : query.pagination
2651
3326
  }),
2652
- [activeTags, enabled.pagination, enabled.search, enabled.sort, page, query, resolvedPageSize, searchValue, sort]
3327
+ [
3328
+ activeCollection,
3329
+ activeTags,
3330
+ enabled.pagination,
3331
+ enabled.search,
3332
+ enabled.sort,
3333
+ page,
3334
+ query,
3335
+ resolvedPageSize,
3336
+ searchValue,
3337
+ sort
3338
+ ]
2653
3339
  );
2654
3340
  useKeepUrlSync({
2655
3341
  enabled: Boolean(urlSync),
@@ -2659,6 +3345,7 @@ function useKeepCollection({
2659
3345
  setSearchValue(next.search?.query ?? "");
2660
3346
  setSort(next.sort ?? { by: "updatedAt", direction: "desc" });
2661
3347
  setActiveTags(next.tags ?? []);
3348
+ setActiveCollection(next.collectionId);
2662
3349
  setPage(next.pagination?.page ?? 1);
2663
3350
  },
2664
3351
  options: typeof urlSync === "object" ? urlSync : {},
@@ -2671,6 +3358,7 @@ function useKeepCollection({
2671
3358
  searchValue,
2672
3359
  sortValue: sortToValue(sort),
2673
3360
  activeTags,
3361
+ activeCollection,
2674
3362
  resolvedPageSize,
2675
3363
  resolvedQuery,
2676
3364
  list,
@@ -2687,6 +3375,10 @@ function useKeepCollection({
2687
3375
  setActiveTags(value ? [value] : []);
2688
3376
  setPage(1);
2689
3377
  },
3378
+ setCollection: (value) => {
3379
+ setActiveCollection(value);
3380
+ setPage(1);
3381
+ },
2690
3382
  removeTag: (tagToRemove) => {
2691
3383
  setActiveTags((current) => current.filter((tag) => tag !== tagToRemove));
2692
3384
  setPage(1);
@@ -2694,6 +3386,7 @@ function useKeepCollection({
2694
3386
  clearFilters: () => {
2695
3387
  setSearchValue("");
2696
3388
  setActiveTags([]);
3389
+ setActiveCollection(void 0);
2697
3390
  setPage(1);
2698
3391
  },
2699
3392
  setPage
@@ -2710,8 +3403,8 @@ import {
2710
3403
  createElement as createElement2,
2711
3404
  isValidElement as isValidElement4,
2712
3405
  useContext as useContext3,
2713
- useEffect as useEffect5,
2714
- useState as useState8
3406
+ useEffect as useEffect7,
3407
+ useState as useState11
2715
3408
  } from "react";
2716
3409
 
2717
3410
  // src/features/item/hooks/useKeepItemStatusBadge.ts
@@ -2754,10 +3447,10 @@ function getDisplayStatus(status) {
2754
3447
  }
2755
3448
 
2756
3449
  // src/features/item/KeepItemStatusBadge.tsx
2757
- import { Fragment as Fragment6, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
3450
+ import { Fragment as Fragment7, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
2758
3451
  function KeepItemStatusBadge({ status = "available", label, className, ...props }) {
2759
3452
  const view = useKeepItemStatusBadge(status);
2760
- return /* @__PURE__ */ jsxs8(
3453
+ return /* @__PURE__ */ jsxs12(
2761
3454
  "span",
2762
3455
  {
2763
3456
  ...props,
@@ -2768,14 +3461,14 @@ function KeepItemStatusBadge({ status = "available", label, className, ...props
2768
3461
  "data-status": status,
2769
3462
  "data-item-status": view.resolvedStatus,
2770
3463
  children: [
2771
- /* @__PURE__ */ jsx11(StatusIcon, { name: view.icon }),
2772
- /* @__PURE__ */ jsx11("span", { "data-status-label": "true", children: label ?? view.statusLabel })
3464
+ /* @__PURE__ */ jsx14(StatusIcon, { name: view.icon }),
3465
+ /* @__PURE__ */ jsx14("span", { "data-status-label": "true", children: label ?? view.statusLabel })
2773
3466
  ]
2774
3467
  }
2775
3468
  );
2776
3469
  }
2777
3470
  function StatusIcon({ name }) {
2778
- return /* @__PURE__ */ jsxs8(
3471
+ return /* @__PURE__ */ jsxs12(
2779
3472
  "svg",
2780
3473
  {
2781
3474
  "data-status-icon": name,
@@ -2790,18 +3483,18 @@ function StatusIcon({ name }) {
2790
3483
  "aria-hidden": "true",
2791
3484
  focusable: "false",
2792
3485
  children: [
2793
- name === "check" ? /* @__PURE__ */ jsx11("path", { d: "m5 12 4 4L19 6" }) : null,
2794
- name === "clock" ? /* @__PURE__ */ jsxs8(Fragment6, { children: [
2795
- /* @__PURE__ */ jsx11("circle", { cx: "12", cy: "12", r: "8" }),
2796
- /* @__PURE__ */ jsx11("path", { d: "M12 7v5l3 2" })
3486
+ name === "check" ? /* @__PURE__ */ jsx14("path", { d: "m5 12 4 4L19 6" }) : null,
3487
+ name === "clock" ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
3488
+ /* @__PURE__ */ jsx14("circle", { cx: "12", cy: "12", r: "8" }),
3489
+ /* @__PURE__ */ jsx14("path", { d: "M12 7v5l3 2" })
2797
3490
  ] }) : null,
2798
- name === "ban" ? /* @__PURE__ */ jsxs8(Fragment6, { children: [
2799
- /* @__PURE__ */ jsx11("circle", { cx: "12", cy: "12", r: "8" }),
2800
- /* @__PURE__ */ jsx11("path", { d: "m6.5 6.5 11 11" })
3491
+ name === "ban" ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
3492
+ /* @__PURE__ */ jsx14("circle", { cx: "12", cy: "12", r: "8" }),
3493
+ /* @__PURE__ */ jsx14("path", { d: "m6.5 6.5 11 11" })
2801
3494
  ] }) : null,
2802
- name === "lock" ? /* @__PURE__ */ jsxs8(Fragment6, { children: [
2803
- /* @__PURE__ */ jsx11("rect", { x: "5", y: "10", width: "14", height: "10", rx: "2" }),
2804
- /* @__PURE__ */ jsx11("path", { d: "M8 10V7a4 4 0 0 1 8 0v3" })
3495
+ name === "lock" ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
3496
+ /* @__PURE__ */ jsx14("rect", { x: "5", y: "10", width: "14", height: "10", rx: "2" }),
3497
+ /* @__PURE__ */ jsx14("path", { d: "M8 10V7a4 4 0 0 1 8 0v3" })
2805
3498
  ] }) : null
2806
3499
  ]
2807
3500
  }
@@ -2809,16 +3502,16 @@ function StatusIcon({ name }) {
2809
3502
  }
2810
3503
 
2811
3504
  // src/features/status/hooks/useKeepStaleNotice.ts
2812
- import { useKeepContext as useKeepContext3 } from "@keepkit/core/react";
2813
- import { useState as useState7 } from "react";
3505
+ import { useKeepContext as useKeepContext5 } from "@keepkit/core/react";
3506
+ import { useState as useState10 } from "react";
2814
3507
  function useKeepStaleNotice({ item, onRetry, onRemoved }) {
2815
- const context = useKeepContext3();
3508
+ const context = useKeepContext5();
2816
3509
  const emitFeedback = useKeepUiFeedback();
2817
3510
  const removedMessage = useUiLabel("removedMessage");
2818
3511
  const restoredMessage = useUiLabel("restoredMessage");
2819
3512
  const undoLabel = useUiLabel("undo");
2820
- const [isRetrying, setIsRetrying] = useState7(false);
2821
- const [error, setError] = useState7(null);
3513
+ const [isRetrying, setIsRetrying] = useState10(false);
3514
+ const [error, setError] = useState10(null);
2822
3515
  async function retry() {
2823
3516
  setError(null);
2824
3517
  setIsRetrying(true);
@@ -2864,7 +3557,7 @@ function useKeepStaleNotice({ item, onRetry, onRemoved }) {
2864
3557
  };
2865
3558
  }
2866
3559
  function useKeepPruneStale({ statuses, onPruned }) {
2867
- const context = useKeepContext3();
3560
+ const context = useKeepContext5();
2868
3561
  const emitFeedback = useKeepUiFeedback();
2869
3562
  const staleItems = context.items.filter((item) => item.status && statuses.includes(item.status));
2870
3563
  const staleIds = staleItems.map((item) => item.id);
@@ -2898,7 +3591,7 @@ function useKeepPruneStale({ statuses, onPruned }) {
2898
3591
  }
2899
3592
 
2900
3593
  // src/features/status/KeepStaleNotice.tsx
2901
- import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
3594
+ import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
2902
3595
  function KeepStaleNotice({
2903
3596
  item,
2904
3597
  onRetry,
@@ -2910,11 +3603,11 @@ function KeepStaleNotice({
2910
3603
  ...props
2911
3604
  }) {
2912
3605
  const view = useKeepStaleNotice({ item, onRetry, onRemoved });
2913
- return /* @__PURE__ */ jsxs9("aside", { ...props, className, "data-keepkit": "stale-notice", "data-state": view.error ? "error" : "stale", children: [
2914
- /* @__PURE__ */ jsx12(KeepItemStatusBadge, { status: view.status }),
2915
- children ?? (item.statusReason ? /* @__PURE__ */ jsx12("p", { children: item.statusReason }) : null),
2916
- /* @__PURE__ */ jsxs9("div", { children: [
2917
- /* @__PURE__ */ jsx12(
3606
+ return /* @__PURE__ */ jsxs13("aside", { ...props, className, "data-keepkit": "stale-notice", "data-state": view.error ? "error" : "stale", children: [
3607
+ /* @__PURE__ */ jsx15(KeepItemStatusBadge, { status: view.status }),
3608
+ children ?? (item.statusReason ? /* @__PURE__ */ jsx15("p", { children: item.statusReason }) : null),
3609
+ /* @__PURE__ */ jsxs13("div", { children: [
3610
+ /* @__PURE__ */ jsx15(
2918
3611
  "button",
2919
3612
  {
2920
3613
  type: "button",
@@ -2924,7 +3617,7 @@ function KeepStaleNotice({
2924
3617
  children: retryLabel ?? view.labels.retry
2925
3618
  }
2926
3619
  ),
2927
- /* @__PURE__ */ jsx12(
3620
+ /* @__PURE__ */ jsx15(
2928
3621
  "button",
2929
3622
  {
2930
3623
  type: "button",
@@ -2935,7 +3628,7 @@ function KeepStaleNotice({
2935
3628
  }
2936
3629
  )
2937
3630
  ] }),
2938
- view.error ? /* @__PURE__ */ jsx12("p", { role: "alert", children: view.error instanceof Error ? view.error.message : view.labels.error }) : null
3631
+ view.error ? /* @__PURE__ */ jsx15("p", { role: "alert", children: view.error instanceof Error ? view.error.message : view.labels.error }) : null
2939
3632
  ] });
2940
3633
  }
2941
3634
  function KeepPruneStaleButton({
@@ -2947,7 +3640,7 @@ function KeepPruneStaleButton({
2947
3640
  ...props
2948
3641
  }) {
2949
3642
  const view = useKeepPruneStale({ statuses, onPruned });
2950
- return /* @__PURE__ */ jsx12(
3643
+ return /* @__PURE__ */ jsx15(
2951
3644
  "button",
2952
3645
  {
2953
3646
  ...props,
@@ -2964,7 +3657,7 @@ function KeepPruneStaleButton({
2964
3657
  }
2965
3658
 
2966
3659
  // src/features/item/hooks/useKeepItemCard.ts
2967
- import { useKeepItem as useKeepItem2 } from "@keepkit/core/react";
3660
+ import { useKeepItem as useKeepItem5 } from "@keepkit/core/react";
2968
3661
  function useKeepItemCard(options) {
2969
3662
  const {
2970
3663
  item,
@@ -2977,7 +3670,7 @@ function useKeepItemCard(options) {
2977
3670
  onRemoveError,
2978
3671
  onRemoved
2979
3672
  } = options;
2980
- const itemState = useKeepItem2(item);
3673
+ const itemState = useKeepItem5(item);
2981
3674
  const emitFeedback = useKeepUiFeedback();
2982
3675
  const removedMessage = useUiLabel("removedMessage");
2983
3676
  const restoredMessage = useUiLabel("restoredMessage");
@@ -3060,7 +3753,7 @@ function getDisplayStatus2(status) {
3060
3753
  }
3061
3754
 
3062
3755
  // src/features/item/KeepItemCard.tsx
3063
- import { Fragment as Fragment7, jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
3756
+ import { Fragment as Fragment8, jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
3064
3757
  var KeepItemCardContext = createContext3(null);
3065
3758
  function useKeepItemCardCompound(part) {
3066
3759
  const context = useContext3(KeepItemCardContext);
@@ -3077,6 +3770,7 @@ function KeepItemCardRoot({
3077
3770
  renderTags,
3078
3771
  showTags = true,
3079
3772
  showSavedAt = true,
3773
+ collectionLabels,
3080
3774
  imageAlt,
3081
3775
  render,
3082
3776
  children,
@@ -3120,17 +3814,17 @@ function KeepItemCardRoot({
3120
3814
  onClick: (event) => onOpen?.(item, event),
3121
3815
  children: content
3122
3816
  };
3123
- return LinkComponent ? /* @__PURE__ */ jsx13(LinkComponent, { ...linkProps }) : /* @__PURE__ */ jsx13("a", { ...linkProps });
3817
+ return LinkComponent ? /* @__PURE__ */ jsx16(LinkComponent, { ...linkProps }) : /* @__PURE__ */ jsx16("a", { ...linkProps });
3124
3818
  }
3125
3819
  function renderTitle(content) {
3126
3820
  if (linkTarget !== "title") return content;
3127
3821
  if (view.isAvailable) return renderLink(content);
3128
- return view.href ? /* @__PURE__ */ jsx13("span", { "aria-disabled": "true", "data-link-disabled": "true", children: content }) : content;
3822
+ return view.href ? /* @__PURE__ */ jsx16("span", { "aria-disabled": "true", "data-link-disabled": "true", children: content }) : content;
3129
3823
  }
3130
3824
  const resolvedImageProps = view.imageProps ? { ...view.imageProps, alt: imageAlt ?? view.imageProps.alt } : void 0;
3131
3825
  const imageSource = resolvedImageProps?.src;
3132
- const [imageStatus, setImageStatus] = useState8(imageSource ? "loading" : "error");
3133
- useEffect5(() => {
3826
+ const [imageStatus, setImageStatus] = useState11(imageSource ? "loading" : "error");
3827
+ useEffect7(() => {
3134
3828
  setImageStatus(imageSource ? "loading" : "error");
3135
3829
  }, [imageSource]);
3136
3830
  let image = null;
@@ -3148,21 +3842,21 @@ function KeepItemCardRoot({
3148
3842
  setImageStatus("error");
3149
3843
  }
3150
3844
  };
3151
- image = renderImage?.(imagePropsWithHandlers, item) ?? (ImageComponent ? /* @__PURE__ */ jsx13(ImageComponent, { ...imagePropsWithHandlers }) : /* @__PURE__ */ jsx13("img", { ...imagePropsWithHandlers, alt: imagePropsWithHandlers.alt }));
3845
+ image = renderImage?.(imagePropsWithHandlers, item) ?? (ImageComponent ? /* @__PURE__ */ jsx16(ImageComponent, { ...imagePropsWithHandlers }) : /* @__PURE__ */ jsx16("img", { ...imagePropsWithHandlers, alt: imagePropsWithHandlers.alt }));
3152
3846
  }
3153
3847
  const tags = showTags ? item.tags ?? [] : [];
3154
3848
  const renderedTags = showTags && tags.length > 0 ? renderTags?.(tags, item) ?? null : null;
3155
- const meta = showSavedAt ? /* @__PURE__ */ jsxs10("div", { "data-card-meta": true, children: [
3156
- /* @__PURE__ */ jsxs10("span", { children: [
3849
+ const meta = showSavedAt ? /* @__PURE__ */ jsxs14("div", { "data-card-meta": true, children: [
3850
+ /* @__PURE__ */ jsxs14("span", { children: [
3157
3851
  view.labels.savedAt,
3158
3852
  ":"
3159
3853
  ] }),
3160
3854
  " ",
3161
- /* @__PURE__ */ jsx13("time", { dateTime: new Date(item.savedAt).toISOString(), children: formatSavedAt(item.savedAt) })
3855
+ /* @__PURE__ */ jsx16("time", { dateTime: new Date(item.savedAt).toISOString(), children: formatSavedAt(item.savedAt) })
3162
3856
  ] }) : null;
3163
- const error = view.itemState.error ? /* @__PURE__ */ jsx13("p", { role: "alert", children: getErrorMessage2(view.itemState.error, view.labels.error) }) : null;
3164
- const actions = view.statusLabel ? /* @__PURE__ */ jsx13(KeepStaleNotice, { item, onRetry, onRemoved }) : /* @__PURE__ */ jsxs10(Fragment7, { children: [
3165
- showSaveButton ? /* @__PURE__ */ jsx13(
3857
+ const error = view.itemState.error ? /* @__PURE__ */ jsx16("p", { role: "alert", children: getErrorMessage2(view.itemState.error, view.labels.error) }) : null;
3858
+ const actions = view.statusLabel ? /* @__PURE__ */ jsx16(KeepStaleNotice, { item, onRetry, onRemoved }) : /* @__PURE__ */ jsxs14(Fragment8, { children: [
3859
+ showSaveButton ? /* @__PURE__ */ jsx16(
3166
3860
  KeepButton,
3167
3861
  {
3168
3862
  item: toKeepButtonItem(item),
@@ -3170,7 +3864,7 @@ function KeepItemCardRoot({
3170
3864
  getAriaLabel: (buttonState) => `${buttonState.isSaved ? view.labels.remove : view.labels.save} ${String(view.resolvedTitle)}`
3171
3865
  }
3172
3866
  ) : null,
3173
- /* @__PURE__ */ jsx13(
3867
+ /* @__PURE__ */ jsx16(
3174
3868
  "button",
3175
3869
  {
3176
3870
  type: "button",
@@ -3182,6 +3876,8 @@ function KeepItemCardRoot({
3182
3876
  )
3183
3877
  ] });
3184
3878
  const compoundValue = {
3879
+ item,
3880
+ collectionLabel: item.collectionId ? collectionLabels?.[item.collectionId] ?? item.collectionId : void 0,
3185
3881
  resolvedTitle: view.resolvedTitle,
3186
3882
  renderTitle,
3187
3883
  image: imageStatus === "error" ? null : image,
@@ -3193,12 +3889,12 @@ function KeepItemCardRoot({
3193
3889
  meta,
3194
3890
  error,
3195
3891
  actions,
3196
- renderText: (content) => /* @__PURE__ */ jsx13(KeepHighlight, { query: searchQuery, children: content })
3892
+ renderText: (content) => /* @__PURE__ */ jsx16(KeepHighlight, { query: searchQuery, children: content })
3197
3893
  };
3198
- const defaultBody = /* @__PURE__ */ jsxs10(Fragment7, { children: [
3199
- /* @__PURE__ */ jsx13(KeepItemCardMedia, {}),
3200
- /* @__PURE__ */ jsx13(KeepItemCardContent, {}),
3201
- /* @__PURE__ */ jsx13(KeepItemCardActions, {})
3894
+ const defaultBody = /* @__PURE__ */ jsxs14(Fragment8, { children: [
3895
+ /* @__PURE__ */ jsx16(KeepItemCardMedia, {}),
3896
+ /* @__PURE__ */ jsx16(KeepItemCardContent, {}),
3897
+ /* @__PURE__ */ jsx16(KeepItemCardActions, {})
3202
3898
  ] });
3203
3899
  const body = render ? render(view.state) : typeof contentChildren === "function" ? contentChildren(view.state) : contentChildren ?? defaultBody;
3204
3900
  const linkedBody = linkTarget === "card" && view.isAvailable ? renderLink(body) : body;
@@ -3219,18 +3915,18 @@ function KeepItemCardRoot({
3219
3915
  linkedBody,
3220
3916
  "KeepItemCard"
3221
3917
  );
3222
- return /* @__PURE__ */ jsx13(KeepItemCardContext.Provider, { value: compoundValue, children: root });
3918
+ return /* @__PURE__ */ jsx16(KeepItemCardContext.Provider, { value: compoundValue, children: root });
3223
3919
  }
3224
3920
  function KeepItemCardMedia({ children, fallback, ...props }) {
3225
3921
  const context = useKeepItemCardCompound("Media");
3226
- 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, {}) }) });
3922
+ 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, {}) }) });
3227
3923
  }
3228
3924
  function KeepItemCardContent({ children, ...props }) {
3229
3925
  const context = useKeepItemCardCompound("Content");
3230
- return /* @__PURE__ */ jsx13("div", { ...props, "data-keep-card-part": "content", children: children === void 0 ? /* @__PURE__ */ jsxs10(Fragment7, { children: [
3231
- /* @__PURE__ */ jsx13(KeepItemCardTitle, {}),
3926
+ return /* @__PURE__ */ jsx16("div", { ...props, "data-keep-card-part": "content", children: children === void 0 ? /* @__PURE__ */ jsxs14(Fragment8, { children: [
3927
+ /* @__PURE__ */ jsx16(KeepItemCardTitle, {}),
3232
3928
  context.meta,
3233
- /* @__PURE__ */ jsx13(KeepItemCardTags, {}),
3929
+ /* @__PURE__ */ jsx16(KeepItemCardTags, {}),
3234
3930
  context.error
3235
3931
  ] }) : context.renderText(children) });
3236
3932
  }
@@ -3243,8 +3939,8 @@ function KeepItemCardTitle({ as = "h3", children, ...props }) {
3243
3939
  );
3244
3940
  }
3245
3941
  function KeepMediaPlaceholderIcon() {
3246
- return /* @__PURE__ */ jsxs10("svg", { "data-media-fallback-icon": "true", viewBox: "0 0 24 24", "aria-hidden": "true", children: [
3247
- /* @__PURE__ */ jsx13(
3942
+ return /* @__PURE__ */ jsxs14("svg", { "data-media-fallback-icon": "true", viewBox: "0 0 24 24", "aria-hidden": "true", children: [
3943
+ /* @__PURE__ */ jsx16(
3248
3944
  "path",
3249
3945
  {
3250
3946
  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",
@@ -3252,34 +3948,53 @@ function KeepMediaPlaceholderIcon() {
3252
3948
  stroke: "currentColor"
3253
3949
  }
3254
3950
  ),
3255
- /* @__PURE__ */ jsx13("circle", { cx: "9", cy: "9", r: "1.5", fill: "currentColor" }),
3256
- /* @__PURE__ */ jsx13("path", { d: "m5.5 18 4.5-4.5 3 3 2-2L19 18", fill: "none", stroke: "currentColor" })
3951
+ /* @__PURE__ */ jsx16("circle", { cx: "9", cy: "9", r: "1.5", fill: "currentColor" }),
3952
+ /* @__PURE__ */ jsx16("path", { d: "m5.5 18 4.5-4.5 3 3 2-2L19 18", fill: "none", stroke: "currentColor" })
3257
3953
  ] });
3258
3954
  }
3259
3955
  function KeepItemCardTags({ children, ...props }) {
3260
3956
  const context = useKeepItemCardCompound("Tags");
3261
3957
  if (children === void 0 && context.renderedTags) return context.renderedTags;
3262
3958
  if (children === void 0 && context.tags.length === 0) return null;
3263
- 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)) });
3959
+ 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)) });
3264
3960
  }
3265
3961
  function KeepItemCardActions({ children, ...props }) {
3266
3962
  const context = useKeepItemCardCompound("Actions");
3267
- return /* @__PURE__ */ jsx13("div", { ...props, "data-keep-card-part": "actions", children: children ?? context.actions });
3963
+ return /* @__PURE__ */ jsx16("div", { ...props, "data-keep-card-part": "actions", children: children ?? context.actions });
3964
+ }
3965
+ function KeepItemCardPin({ children, ...props }) {
3966
+ const context = useKeepItemCardCompound("Pin");
3967
+ return /* @__PURE__ */ jsx16(KeepPinButton, { ...props, item: context.item, children });
3968
+ }
3969
+ function KeepItemCardArchive({
3970
+ children,
3971
+ ...props
3972
+ }) {
3973
+ const context = useKeepItemCardCompound("Archive");
3974
+ return /* @__PURE__ */ jsx16(KeepArchiveButton, { ...props, item: context.item, children });
3975
+ }
3976
+ function KeepItemCardCollectionBadge({ children, ...props }) {
3977
+ const context = useKeepItemCardCompound("CollectionBadge");
3978
+ if (!context.item.collectionId) return null;
3979
+ return /* @__PURE__ */ jsx16("span", { ...props, "data-keep-card-part": "collection-badge", children: children ?? context.collectionLabel });
3268
3980
  }
3269
3981
  var KeepItemCard = Object.assign(KeepItemCardRoot, {
3270
3982
  Media: KeepItemCardMedia,
3271
3983
  Content: KeepItemCardContent,
3272
3984
  Title: KeepItemCardTitle,
3273
3985
  Tags: KeepItemCardTags,
3274
- Actions: KeepItemCardActions
3986
+ Actions: KeepItemCardActions,
3987
+ Pin: KeepItemCardPin,
3988
+ Archive: KeepItemCardArchive,
3989
+ CollectionBadge: KeepItemCardCollectionBadge
3275
3990
  });
3276
3991
  function KeepItemCardSkeleton({ layout = "list", ...props }) {
3277
- return /* @__PURE__ */ jsxs10("article", { ...props, "aria-hidden": "true", "data-keepkit": "card-skeleton", "data-layout": layout, "data-state": "loading", children: [
3278
- /* @__PURE__ */ jsx13("span", { "data-skeleton-part": "media" }),
3279
- /* @__PURE__ */ jsx13("span", { "data-skeleton-part": "title" }),
3280
- /* @__PURE__ */ jsx13("span", { "data-skeleton-part": "meta" }),
3281
- /* @__PURE__ */ jsx13("span", { "data-skeleton-part": "tag" }),
3282
- /* @__PURE__ */ jsx13("span", { "data-skeleton-part": "tag" })
3992
+ return /* @__PURE__ */ jsxs14("article", { ...props, "aria-hidden": "true", "data-keepkit": "card-skeleton", "data-layout": layout, "data-state": "loading", children: [
3993
+ /* @__PURE__ */ jsx16("span", { "data-skeleton-part": "media" }),
3994
+ /* @__PURE__ */ jsx16("span", { "data-skeleton-part": "title" }),
3995
+ /* @__PURE__ */ jsx16("span", { "data-skeleton-part": "meta" }),
3996
+ /* @__PURE__ */ jsx16("span", { "data-skeleton-part": "tag" }),
3997
+ /* @__PURE__ */ jsx16("span", { "data-skeleton-part": "tag" })
3283
3998
  ] });
3284
3999
  }
3285
4000
  function formatSavedAt(timestamp) {
@@ -3291,7 +4006,7 @@ function getErrorMessage2(error, fallback) {
3291
4006
 
3292
4007
  // src/features/status/KeepEmptyState.tsx
3293
4008
  import { isValidElement as isValidElement5 } from "react";
3294
- import { Fragment as Fragment8, jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
4009
+ import { Fragment as Fragment9, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
3295
4010
  function KeepEmptyState({
3296
4011
  title,
3297
4012
  description,
@@ -3310,10 +4025,10 @@ function KeepEmptyState({
3310
4025
  );
3311
4026
  const clearLabel = useUiLabel("clearFilters");
3312
4027
  const contentChildren = asChild && isValidElement5(children) ? void 0 : children;
3313
- const body = contentChildren ?? /* @__PURE__ */ jsxs11(Fragment8, { children: [
3314
- /* @__PURE__ */ jsx14("h2", { children: title ?? defaultTitle }),
3315
- description ?? /* @__PURE__ */ jsx14("p", { children: defaultDescription }),
3316
- action ?? (resolvedVariant === "empty-filtered" && onClearFilters ? /* @__PURE__ */ jsx14("button", { type: "button", "data-keep-action": "clear-filters", onClick: onClearFilters, children: clearLabel }) : null)
4028
+ const body = contentChildren ?? /* @__PURE__ */ jsxs15(Fragment9, { children: [
4029
+ /* @__PURE__ */ jsx17("h2", { children: title ?? defaultTitle }),
4030
+ description ?? /* @__PURE__ */ jsx17("p", { children: defaultDescription }),
4031
+ action ?? (resolvedVariant === "empty-filtered" && onClearFilters ? /* @__PURE__ */ jsx17("button", { type: "button", "data-keep-action": "clear-filters", onClick: onClearFilters, children: clearLabel }) : null)
3317
4032
  ] });
3318
4033
  return renderRoot(
3319
4034
  asChild,
@@ -3339,17 +4054,17 @@ function useKeepListView(query) {
3339
4054
  }
3340
4055
 
3341
4056
  // src/features/collection/hooks/useRovingTabIndex.ts
3342
- import { useCallback as useCallback3, useEffect as useEffect6, useRef as useRef4 } from "react";
4057
+ import { useCallback as useCallback5, useEffect as useEffect8, useRef as useRef7 } from "react";
3343
4058
  function useRovingTabIndex() {
3344
- const ref = useRef4(null);
3345
- const getItems = useCallback3(() => {
4059
+ const ref = useRef7(null);
4060
+ const getItems = useCallback5(() => {
3346
4061
  const root = ref.current;
3347
4062
  if (!root) return [];
3348
4063
  return Array.from(root.querySelectorAll('[data-keepkit="card"]')).filter(
3349
4064
  (item) => item.getAttribute("aria-hidden") !== "true" && item.getAttribute("data-roving-disabled") !== "true"
3350
4065
  );
3351
4066
  }, []);
3352
- const syncTabIndices = useCallback3(() => {
4067
+ const syncTabIndices = useCallback5(() => {
3353
4068
  const items = getItems();
3354
4069
  if (items.length === 0) return;
3355
4070
  const activeElement = document.activeElement;
@@ -3359,7 +4074,7 @@ function useRovingTabIndex() {
3359
4074
  item.tabIndex = index === activeIndex ? 0 : -1;
3360
4075
  });
3361
4076
  }, [getItems]);
3362
- useEffect6(() => {
4077
+ useEffect8(() => {
3363
4078
  const root = ref.current;
3364
4079
  if (!root) return;
3365
4080
  syncTabIndices();
@@ -3367,7 +4082,7 @@ function useRovingTabIndex() {
3367
4082
  observer.observe(root, { childList: true, subtree: true });
3368
4083
  return () => observer.disconnect();
3369
4084
  }, [syncTabIndices]);
3370
- const onFocusCapture = useCallback3(
4085
+ const onFocusCapture = useCallback5(
3371
4086
  (event) => {
3372
4087
  if (!(event.target instanceof HTMLElement)) return;
3373
4088
  const item = event.target.closest('[data-keepkit="card"]');
@@ -3378,7 +4093,7 @@ function useRovingTabIndex() {
3378
4093
  },
3379
4094
  [getItems]
3380
4095
  );
3381
- const onKeyDown = useCallback3(
4096
+ const onKeyDown = useCallback5(
3382
4097
  (event) => {
3383
4098
  if (event.defaultPrevented) return;
3384
4099
  const items = getItems();
@@ -3404,12 +4119,12 @@ function useRovingTabIndex() {
3404
4119
  }
3405
4120
 
3406
4121
  // src/features/collection/KeepList.tsx
3407
- import { Fragment as Fragment9, jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
4122
+ import { Fragment as Fragment10, jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
3408
4123
  function KeepList(props) {
3409
4124
  const { fallback, onBoundaryError, boundaryResetKey, ...listProps } = props;
3410
- const content = /* @__PURE__ */ jsx15(KeepListContent, { ...listProps });
4125
+ const content = /* @__PURE__ */ jsx18(KeepListContent, { ...listProps });
3411
4126
  if (fallback === void 0 && onBoundaryError === void 0) return content;
3412
- return /* @__PURE__ */ jsx15(KeepErrorBoundary, { fallback, onError: onBoundaryError, resetKey: boundaryResetKey, children: content });
4127
+ return /* @__PURE__ */ jsx18(KeepErrorBoundary, { fallback, onError: onBoundaryError, resetKey: boundaryResetKey, children: content });
3413
4128
  }
3414
4129
  function KeepListContent({
3415
4130
  query,
@@ -3459,7 +4174,7 @@ function KeepListContent({
3459
4174
  "data-loading": state.isLoading ? "true" : void 0,
3460
4175
  "data-roving-tabindex": "true",
3461
4176
  role: rootProps.role ?? "group",
3462
- ref: roving.ref,
4177
+ ref: composeRefs(roving.ref, rootProps.ref),
3463
4178
  onKeyDown: (event) => {
3464
4179
  onKeyDown?.(event);
3465
4180
  if (!event.defaultPrevented) roving.onKeyDown(event);
@@ -3469,7 +4184,7 @@ function KeepListContent({
3469
4184
  if (!event.defaultPrevented) roving.onFocusCapture(event);
3470
4185
  }
3471
4186
  },
3472
- /* @__PURE__ */ jsx15(KeepSearchQueryProvider, { query: query?.search?.query, children: body }),
4187
+ /* @__PURE__ */ jsx18(KeepSearchQueryProvider, { query: query?.search?.query, children: body }),
3473
4188
  "KeepList"
3474
4189
  );
3475
4190
  }
@@ -3484,17 +4199,17 @@ function getListBody(state, options) {
3484
4199
  if (state.isLoading && !state.isHydrated) {
3485
4200
  if (options.loading !== void 0) return resolveContent(options.loading, state);
3486
4201
  const count = Number.isFinite(options.loadingCount) ? Math.max(0, Math.floor(options.loadingCount)) : 6;
3487
- return /* @__PURE__ */ jsxs12(Fragment9, { children: [
3488
- /* @__PURE__ */ jsx15("span", { role: "status", "data-keepkit": "loading-label", children: options.loadingLabel }),
3489
- /* @__PURE__ */ jsx15("ul", { "data-keepkit": "skeleton-list", "data-layout": options.layout, children: Array.from({ length: count }, (_, index) => (
4202
+ return /* @__PURE__ */ jsxs16(Fragment10, { children: [
4203
+ /* @__PURE__ */ jsx18("span", { role: "status", "data-keepkit": "loading-label", children: options.loadingLabel }),
4204
+ /* @__PURE__ */ jsx18("ul", { "data-keepkit": "skeleton-list", "data-layout": options.layout, children: Array.from({ length: count }, (_, index) => (
3490
4205
  // biome-ignore lint/suspicious/noArrayIndexKey: Static loading placeholders never reorder.
3491
- /* @__PURE__ */ jsx15("li", { children: /* @__PURE__ */ jsx15(KeepItemCardSkeleton, { layout: options.layout }) }, index)
4206
+ /* @__PURE__ */ jsx18("li", { children: /* @__PURE__ */ jsx18(KeepItemCardSkeleton, { layout: options.layout }) }, index)
3492
4207
  )) })
3493
4208
  ] });
3494
4209
  }
3495
4210
  if (state.isHydrated && state.items.length === 0) {
3496
4211
  if (options.empty !== void 0) return resolveContent(options.empty, state);
3497
- return /* @__PURE__ */ jsx15(
4212
+ return /* @__PURE__ */ jsx18(
3498
4213
  KeepEmptyState,
3499
4214
  {
3500
4215
  variant: options.allItemCount > 0 && hasActiveQueryFilters(options.query) ? "empty-filtered" : "empty-storage",
@@ -3504,24 +4219,24 @@ function getListBody(state, options) {
3504
4219
  }
3505
4220
  if (typeof options.children === "function") return options.children(state);
3506
4221
  if (options.children !== void 0 && !isValidElement6(options.children)) return options.children;
3507
- return /* @__PURE__ */ jsx15("ul", { "data-layout": options.layout, children: state.items.map(
3508
- (item) => options.renderItem ? options.renderItem(item, state) : /* @__PURE__ */ jsx15("li", { children: /* @__PURE__ */ jsx15(KeepItemCard, { item, ...options.itemCardProps }) }, item.id)
4222
+ return /* @__PURE__ */ jsx18("ul", { "data-layout": options.layout, children: state.items.map(
4223
+ (item) => options.renderItem ? options.renderItem(item, state) : /* @__PURE__ */ jsx18("li", { children: /* @__PURE__ */ jsx18(KeepItemCard, { item, ...options.itemCardProps }) }, item.id)
3509
4224
  ) });
3510
4225
  }
3511
4226
  function hasActiveQueryFilters(query) {
3512
4227
  if (!query) return false;
3513
4228
  return Boolean(
3514
- query.search?.query?.trim() || query.tags?.some((tag) => tag.trim()) || query.targetType || query.savedBetween || query.filter
4229
+ query.search?.query?.trim() || query.tags?.some((tag) => tag.trim()) || query.targetType || query.savedBetween || query.archived !== void 0 || query.collectionId || query.filter
3515
4230
  );
3516
4231
  }
3517
4232
 
3518
4233
  // src/features/collection/KeepCollection.tsx
3519
- import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
4234
+ import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
3520
4235
  function KeepCollection(props) {
3521
4236
  const { fallback, onBoundaryError, boundaryResetKey, ...collectionProps } = props;
3522
- const content = /* @__PURE__ */ jsx16(KeepCollectionContent, { ...collectionProps });
4237
+ const content = /* @__PURE__ */ jsx19(KeepCollectionContent, { ...collectionProps });
3523
4238
  if (fallback === void 0 && onBoundaryError === void 0) return content;
3524
- return /* @__PURE__ */ jsx16(KeepErrorBoundary2, { fallback, onError: onBoundaryError, resetKey: boundaryResetKey, children: content });
4239
+ return /* @__PURE__ */ jsx19(KeepErrorBoundary2, { fallback, onError: onBoundaryError, resetKey: boundaryResetKey, children: content });
3525
4240
  }
3526
4241
  function KeepCollectionContent({
3527
4242
  query = {},
@@ -3530,6 +4245,7 @@ function KeepCollectionContent({
3530
4245
  urlSync = false,
3531
4246
  urlAdapter,
3532
4247
  features,
4248
+ collectionLabels,
3533
4249
  renderItem,
3534
4250
  itemCardProps,
3535
4251
  loading,
@@ -3542,7 +4258,7 @@ function KeepCollectionContent({
3542
4258
  ...rootProps
3543
4259
  }) {
3544
4260
  const view = useKeepCollection({ query, pageSize, urlSync, urlAdapter, features });
3545
- return /* @__PURE__ */ jsxs13(
4261
+ return /* @__PURE__ */ jsxs17(
3546
4262
  "section",
3547
4263
  {
3548
4264
  ...rootProps,
@@ -3553,12 +4269,20 @@ function KeepCollectionContent({
3553
4269
  "data-state": getCollectionState(view.list),
3554
4270
  "data-loading": view.list.isLoading || view.list.isMutating ? "true" : void 0,
3555
4271
  children: [
3556
- /* @__PURE__ */ jsxs13("div", { children: [
3557
- view.enabled.search ? /* @__PURE__ */ jsx16(KeepSearchInput, { value: view.searchValue, onValueChange: view.setSearchValue }) : null,
3558
- view.enabled.sort ? /* @__PURE__ */ jsx16(KeepSortSelect, { value: view.sortValue, onValueChange: view.setSortValue }) : null,
3559
- view.enabled.tagFilter ? /* @__PURE__ */ jsx16(KeepTagFilter, { query, value: view.activeTags[0], onValueChange: view.setTag }) : null
4272
+ /* @__PURE__ */ jsxs17("div", { children: [
4273
+ view.enabled.search ? /* @__PURE__ */ jsx19(KeepSearchInput, { value: view.searchValue, onValueChange: view.setSearchValue }) : null,
4274
+ view.enabled.sort ? /* @__PURE__ */ jsx19(KeepSortSelect, { value: view.sortValue, onValueChange: view.setSortValue }) : null,
4275
+ view.enabled.tagFilter ? /* @__PURE__ */ jsx19(KeepTagFilter, { query, value: view.activeTags[0], onValueChange: view.setTag }) : null,
4276
+ view.enabled.collectionFilter ? /* @__PURE__ */ jsx19(
4277
+ KeepCollectionFilter,
4278
+ {
4279
+ value: view.activeCollection,
4280
+ onValueChange: view.setCollection,
4281
+ collectionLabels
4282
+ }
4283
+ ) : null
3560
4284
  ] }),
3561
- activeFilters === void 0 ? /* @__PURE__ */ jsx16(
4285
+ activeFilters === void 0 ? /* @__PURE__ */ jsx19(
3562
4286
  KeepActiveFiltersSummary,
3563
4287
  {
3564
4288
  search: view.searchValue,
@@ -3568,7 +4292,7 @@ function KeepCollectionContent({
3568
4292
  onClear: view.clearFilters
3569
4293
  }
3570
4294
  ) : resolveContent(activeFilters, view.list),
3571
- /* @__PURE__ */ jsx16(
4295
+ /* @__PURE__ */ jsx19(
3572
4296
  KeepList,
3573
4297
  {
3574
4298
  query: view.resolvedQuery,
@@ -3583,7 +4307,7 @@ function KeepCollectionContent({
3583
4307
  error
3584
4308
  }
3585
4309
  ),
3586
- view.enabled.pagination ? /* @__PURE__ */ jsx16(
4310
+ view.enabled.pagination ? /* @__PURE__ */ jsx19(
3587
4311
  KeepPagination,
3588
4312
  {
3589
4313
  totalCount: view.list.totalCount,
@@ -3592,7 +4316,7 @@ function KeepCollectionContent({
3592
4316
  onPageChange: view.setPage
3593
4317
  }
3594
4318
  ) : null,
3595
- view.enabled.bulkActions ? /* @__PURE__ */ jsx16(KeepBulkActions, { query: view.resolvedQuery }) : null
4319
+ view.enabled.bulkActions ? /* @__PURE__ */ jsx19(KeepBulkActions, { query: view.resolvedQuery }) : null
3596
4320
  ]
3597
4321
  }
3598
4322
  );
@@ -3605,12 +4329,12 @@ function getCollectionState(list) {
3605
4329
  }
3606
4330
 
3607
4331
  // src/features/collection/KeepLayout.tsx
3608
- import { jsx as jsx17 } from "react/jsx-runtime";
4332
+ import { jsx as jsx20 } from "react/jsx-runtime";
3609
4333
  function KeepLayout({ layout = "list", children, onKeyDown, onFocusCapture, ...props }) {
3610
4334
  const roving = useRovingTabIndex();
3611
4335
  return (
3612
4336
  // biome-ignore lint/a11y/noStaticElementInteractions: The group manages keyboard focus for descendant cards.
3613
- /* @__PURE__ */ jsx17(
4337
+ /* @__PURE__ */ jsx20(
3614
4338
  "div",
3615
4339
  {
3616
4340
  ...props,
@@ -3634,8 +4358,8 @@ function KeepLayout({ layout = "list", children, onKeyDown, onFocusCapture, ...p
3634
4358
  }
3635
4359
 
3636
4360
  // src/features/collection/KeepReorderableList.tsx
3637
- import { useState as useState9 } from "react";
3638
- import { jsx as jsx18 } from "react/jsx-runtime";
4361
+ import { useState as useState12 } from "react";
4362
+ import { jsx as jsx21 } from "react/jsx-runtime";
3639
4363
  function KeepReorderableList({
3640
4364
  items,
3641
4365
  onReorder,
@@ -3643,8 +4367,8 @@ function KeepReorderableList({
3643
4367
  itemLabel = (_item, index) => `Move item ${index + 1}`,
3644
4368
  ...props
3645
4369
  }) {
3646
- const [draggedId, setDraggedId] = useState9(null);
3647
- const [dropTargetIndex, setDropTargetIndex] = useState9(null);
4370
+ const [draggedId, setDraggedId] = useState12(null);
4371
+ const [dropTargetIndex, setDropTargetIndex] = useState12(null);
3648
4372
  const ids = items.map((item) => item.id);
3649
4373
  function commit(nextIds) {
3650
4374
  void onReorder(nextIds);
@@ -3669,7 +4393,7 @@ function KeepReorderableList({
3669
4393
  if (next[index] === id) return;
3670
4394
  commit(next);
3671
4395
  }
3672
- return /* @__PURE__ */ jsx18("ul", { ...props, "data-keepkit": "reorderable-list", children: items.map((item, index) => {
4396
+ return /* @__PURE__ */ jsx21("ul", { ...props, "data-keepkit": "reorderable-list", children: items.map((item, index) => {
3673
4397
  const moveUp = () => move(index, index - 1);
3674
4398
  const moveDown = () => move(index, index + 1);
3675
4399
  const onHandleKeyDown = (event) => {
@@ -3704,7 +4428,7 @@ function KeepReorderableList({
3704
4428
  onKeyDown: onHandleKeyDown
3705
4429
  }
3706
4430
  };
3707
- return /* @__PURE__ */ jsx18(
4431
+ return /* @__PURE__ */ jsx21(
3708
4432
  "li",
3709
4433
  {
3710
4434
  "data-reorder-index": index,
@@ -3739,7 +4463,7 @@ function KeepReorderableList({
3739
4463
  import { isValidElement as isValidElement7 } from "react";
3740
4464
 
3741
4465
  // src/features/navigation/KeepShortcutHint.tsx
3742
- import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
4466
+ import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
3743
4467
  function KeepShortcutHint({ shortcut, separator = "+", ...props }) {
3744
4468
  const keys = typeof shortcut === "string" ? shortcut.split("+") : [...shortcut];
3745
4469
  const occurrences = /* @__PURE__ */ new Map();
@@ -3748,24 +4472,24 @@ function KeepShortcutHint({ shortcut, separator = "+", ...props }) {
3748
4472
  occurrences.set(key, occurrence + 1);
3749
4473
  return { id: `${key}-${occurrence}`, value: key };
3750
4474
  });
3751
- return /* @__PURE__ */ jsx19("span", { ...props, "data-keepkit": "shortcut-hint", "aria-hidden": props["aria-hidden"] ?? true, children: keyedKeys.map((key, index) => /* @__PURE__ */ jsxs14("span", { children: [
3752
- index > 0 ? /* @__PURE__ */ jsx19("span", { "data-shortcut-separator": "true", children: separator }) : null,
3753
- /* @__PURE__ */ jsx19("kbd", { children: key.value.trim() })
4475
+ return /* @__PURE__ */ jsx22("span", { ...props, "data-keepkit": "shortcut-hint", "aria-hidden": props["aria-hidden"] ?? true, children: keyedKeys.map((key, index) => /* @__PURE__ */ jsxs18("span", { children: [
4476
+ index > 0 ? /* @__PURE__ */ jsx22("span", { "data-shortcut-separator": "true", children: separator }) : null,
4477
+ /* @__PURE__ */ jsx22("kbd", { children: key.value.trim() })
3754
4478
  ] }, key.id)) });
3755
4479
  }
3756
4480
 
3757
4481
  // src/features/editor/hooks/useKeepNoteEditor.ts
3758
- import { useKeepItem as useKeepItem3 } from "@keepkit/core/react";
3759
- import { useCallback as useCallback4, useEffect as useEffect7, useRef as useRef5, useState as useState10 } from "react";
4482
+ import { useKeepItem as useKeepItem6 } from "@keepkit/core/react";
4483
+ import { useCallback as useCallback6, useEffect as useEffect9, useRef as useRef8, useState as useState13 } from "react";
3760
4484
  function useKeepNoteEditor({ item, debounceMs, onSaved, onSaveError }) {
3761
- const itemState = useKeepItem3(item);
4485
+ const itemState = useKeepItem6(item);
3762
4486
  const { error, isMutating, item: savedItem, updateNote } = itemState;
3763
- const [note, setNote] = useState10(item.note ?? "");
4487
+ const [note, setNote] = useState13(item.note ?? "");
3764
4488
  const baselineNote = savedItem?.note ?? item.note ?? "";
3765
4489
  const isDirty = note !== baselineNote;
3766
- const lastSavedNoteRef = useRef5(void 0);
3767
- useEffect7(() => setNote(baselineNote), [baselineNote]);
3768
- const save = useCallback4(async () => {
4490
+ const lastSavedNoteRef = useRef8(void 0);
4491
+ useEffect9(() => setNote(baselineNote), [baselineNote]);
4492
+ const save = useCallback6(async () => {
3769
4493
  const nextNote = note.trim() || void 0;
3770
4494
  try {
3771
4495
  await updateNote(nextNote);
@@ -3776,7 +4500,7 @@ function useKeepNoteEditor({ item, debounceMs, onSaved, onSaveError }) {
3776
4500
  throw cause;
3777
4501
  }
3778
4502
  }, [note, onSaveError, onSaved, updateNote]);
3779
- useEffect7(() => {
4503
+ useEffect9(() => {
3780
4504
  if (!isDirty || debounceMs <= 0 || lastSavedNoteRef.current === note) return;
3781
4505
  const timer = window.setTimeout(() => void save().catch(() => void 0), debounceMs);
3782
4506
  return () => window.clearTimeout(timer);
@@ -3811,7 +4535,7 @@ function useKeepNoteEditor({ item, debounceMs, onSaved, onSaveError }) {
3811
4535
  }
3812
4536
 
3813
4537
  // src/features/editor/KeepNoteEditor.tsx
3814
- import { Fragment as Fragment10, jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
4538
+ import { Fragment as Fragment11, jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
3815
4539
  function KeepNoteEditor({
3816
4540
  item,
3817
4541
  label,
@@ -3830,10 +4554,10 @@ function KeepNoteEditor({
3830
4554
  const view = useKeepNoteEditor({ item, debounceMs, onSaved, onSaveError });
3831
4555
  const { error, isDirty, isSaving, note, setNote } = view.state;
3832
4556
  const contentChildren = asChild && isValidElement7(children) ? void 0 : children;
3833
- const body = render ? render(view.state) : typeof contentChildren === "function" ? contentChildren(view.state) : contentChildren ?? /* @__PURE__ */ jsxs15(Fragment10, { children: [
3834
- /* @__PURE__ */ jsxs15("label", { children: [
4557
+ const body = render ? render(view.state) : typeof contentChildren === "function" ? contentChildren(view.state) : contentChildren ?? /* @__PURE__ */ jsxs19(Fragment11, { children: [
4558
+ /* @__PURE__ */ jsxs19("label", { children: [
3835
4559
  label ?? view.labels.note,
3836
- /* @__PURE__ */ jsx20(
4560
+ /* @__PURE__ */ jsx23(
3837
4561
  "textarea",
3838
4562
  {
3839
4563
  "data-keep-action": "edit-note",
@@ -3845,13 +4569,13 @@ function KeepNoteEditor({
3845
4569
  }
3846
4570
  )
3847
4571
  ] }),
3848
- /* @__PURE__ */ jsxs15("button", { type: "submit", "data-keep-action": "save-note", disabled: isSaving, "aria-busy": isSaving, children: [
4572
+ /* @__PURE__ */ jsxs19("button", { type: "submit", "data-keep-action": "save-note", disabled: isSaving, "aria-busy": isSaving, children: [
3849
4573
  saveLabel ?? view.labels.save,
3850
- showShortcutHint ? /* @__PURE__ */ jsx20(KeepShortcutHint, { shortcut: "Ctrl+Enter" }) : null
4574
+ showShortcutHint ? /* @__PURE__ */ jsx23(KeepShortcutHint, { shortcut: "Ctrl+Enter" }) : null
3851
4575
  ] })
3852
4576
  ] });
3853
4577
  if (!asChild) {
3854
- return /* @__PURE__ */ jsxs15(
4578
+ return /* @__PURE__ */ jsxs19(
3855
4579
  "form",
3856
4580
  {
3857
4581
  ...formProps,
@@ -3864,7 +4588,7 @@ function KeepNoteEditor({
3864
4588
  "data-disabled": isSaving ? "true" : void 0,
3865
4589
  children: [
3866
4590
  body,
3867
- error ? /* @__PURE__ */ jsx20("p", { role: "alert", children: getErrorMessage3(error, view.labels.error) }) : null
4591
+ error ? /* @__PURE__ */ jsx23("p", { role: "alert", children: getErrorMessage3(error, view.labels.error) }) : null
3868
4592
  ]
3869
4593
  }
3870
4594
  );
@@ -3891,14 +4615,14 @@ function getErrorMessage3(error, fallback) {
3891
4615
  }
3892
4616
 
3893
4617
  // src/features/editor/hooks/useKeepTagEditor.ts
3894
- import { useKeepItem as useKeepItem4 } from "@keepkit/core/react";
3895
- import { useCallback as useCallback5, useEffect as useEffect8, useState as useState11 } from "react";
4618
+ import { useKeepItem as useKeepItem7 } from "@keepkit/core/react";
4619
+ import { useCallback as useCallback7, useEffect as useEffect10, useState as useState14 } from "react";
3896
4620
  function useKeepTagEditor({ item, onSaved, onSaveError }) {
3897
- const itemState = useKeepItem4(item);
3898
- const [tags, setTags] = useState11(item.tags ?? []);
3899
- const [input, setInput] = useState11("");
3900
- useEffect8(() => setTags(itemState.item?.tags ?? item.tags ?? []), [item.tags, itemState.item?.tags]);
3901
- const save = useCallback5(async () => {
4621
+ const itemState = useKeepItem7(item);
4622
+ const [tags, setTags] = useState14(item.tags ?? []);
4623
+ const [input, setInput] = useState14("");
4624
+ useEffect10(() => setTags(itemState.item?.tags ?? item.tags ?? []), [item.tags, itemState.item?.tags]);
4625
+ const save = useCallback7(async () => {
3902
4626
  const nextTags = normalizeUiTags(tags);
3903
4627
  try {
3904
4628
  await itemState.updateTags(nextTags);
@@ -3944,7 +4668,7 @@ function useKeepTagEditor({ item, onSaved, onSaveError }) {
3944
4668
  }
3945
4669
 
3946
4670
  // src/features/editor/KeepTagEditor.tsx
3947
- import { Fragment as Fragment11, jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
4671
+ import { Fragment as Fragment12, jsx as jsx24, jsxs as jsxs20 } from "react/jsx-runtime";
3948
4672
  function KeepTagEditor({
3949
4673
  item,
3950
4674
  availableTags = [],
@@ -3955,10 +4679,10 @@ function KeepTagEditor({
3955
4679
  }) {
3956
4680
  const view = useKeepTagEditor({ item, onSaved, onSaveError });
3957
4681
  const { isSaving, tags } = view.state;
3958
- const body = render ? render(view.state) : /* @__PURE__ */ jsxs16(Fragment11, { children: [
3959
- /* @__PURE__ */ jsxs16("label", { children: [
4682
+ const body = render ? render(view.state) : /* @__PURE__ */ jsxs20(Fragment12, { children: [
4683
+ /* @__PURE__ */ jsxs20("label", { children: [
3960
4684
  view.labels.tags,
3961
- /* @__PURE__ */ jsx21(
4685
+ /* @__PURE__ */ jsx24(
3962
4686
  "input",
3963
4687
  {
3964
4688
  "data-keep-action": "edit-tags",
@@ -3969,14 +4693,14 @@ function KeepTagEditor({
3969
4693
  }
3970
4694
  )
3971
4695
  ] }),
3972
- availableTags.length > 0 ? /* @__PURE__ */ jsx21("datalist", { id: `keep-tags-${item.id}`, children: availableTags.map((tag) => /* @__PURE__ */ jsx21("option", { value: tag }, tag)) }) : null,
3973
- /* @__PURE__ */ jsx21("ul", { "aria-label": view.labels.tags, children: tags.map((tag) => /* @__PURE__ */ jsxs16("li", { children: [
4696
+ availableTags.length > 0 ? /* @__PURE__ */ jsx24("datalist", { id: `keep-tags-${item.id}`, children: availableTags.map((tag) => /* @__PURE__ */ jsx24("option", { value: tag }, tag)) }) : null,
4697
+ /* @__PURE__ */ jsx24("ul", { "aria-label": view.labels.tags, children: tags.map((tag) => /* @__PURE__ */ jsxs20("li", { children: [
3974
4698
  tag,
3975
- /* @__PURE__ */ jsx21("button", { type: "button", "data-keep-action": "remove-tag", onClick: () => view.removeTag(tag), children: view.labels.remove })
4699
+ /* @__PURE__ */ jsx24("button", { type: "button", "data-keep-action": "remove-tag", onClick: () => view.removeTag(tag), children: view.labels.remove })
3976
4700
  ] }, tag)) }),
3977
- /* @__PURE__ */ jsx21("button", { type: "submit", "data-keep-action": "apply-tags", disabled: isSaving, "aria-busy": isSaving, children: view.labels.apply })
4701
+ /* @__PURE__ */ jsx24("button", { type: "submit", "data-keep-action": "apply-tags", disabled: isSaving, "aria-busy": isSaving, children: view.labels.apply })
3978
4702
  ] });
3979
- return /* @__PURE__ */ jsxs16(
4703
+ return /* @__PURE__ */ jsxs20(
3980
4704
  "form",
3981
4705
  {
3982
4706
  ...props,
@@ -3988,7 +4712,7 @@ function KeepTagEditor({
3988
4712
  "data-disabled": isSaving ? "true" : void 0,
3989
4713
  children: [
3990
4714
  body,
3991
- view.error ? /* @__PURE__ */ jsx21("p", { role: "alert", children: getErrorMessage4(view.error, view.labels.error) }) : null
4715
+ view.error ? /* @__PURE__ */ jsx24("p", { role: "alert", children: getErrorMessage4(view.error, view.labels.error) }) : null
3992
4716
  ]
3993
4717
  }
3994
4718
  );
@@ -3998,9 +4722,9 @@ function getErrorMessage4(error, fallback) {
3998
4722
  }
3999
4723
 
4000
4724
  // src/features/feedback/useKeepToastFeedback.ts
4001
- import { useCallback as useCallback6 } from "react";
4725
+ import { useCallback as useCallback8 } from "react";
4002
4726
  function useKeepToastFeedback(showToast) {
4003
- return useCallback6(
4727
+ return useCallback8(
4004
4728
  (event) => {
4005
4729
  if (!("undo" in event)) {
4006
4730
  showToast(event.message);
@@ -4022,7 +4746,7 @@ import { useKeepNavigator } from "@keepkit/core/react";
4022
4746
  import { useId } from "react";
4023
4747
 
4024
4748
  // src/features/navigation/hooks/useKeepTourShortcuts.ts
4025
- import { useEffect as useEffect9 } from "react";
4749
+ import { useEffect as useEffect11 } from "react";
4026
4750
  function useKeepTourShortcuts({
4027
4751
  onNext,
4028
4752
  onPrev,
@@ -4033,7 +4757,7 @@ function useKeepTourShortcuts({
4033
4757
  prevKeys = ["k", "["],
4034
4758
  onError
4035
4759
  }) {
4036
- useEffect9(() => {
4760
+ useEffect11(() => {
4037
4761
  if (!enabled) return;
4038
4762
  const handleKeyDown = (event) => {
4039
4763
  if (!allowInEditable && isEditableTarget(event.target)) return;
@@ -4054,7 +4778,7 @@ function isEditableTarget(target) {
4054
4778
  }
4055
4779
 
4056
4780
  // src/features/navigation/KeepTourBar.tsx
4057
- import { Fragment as Fragment12, jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
4781
+ import { Fragment as Fragment13, jsx as jsx25, jsxs as jsxs21 } from "react/jsx-runtime";
4058
4782
  function KeepTourBar({
4059
4783
  navigation: providedNavigation,
4060
4784
  currentId,
@@ -4096,9 +4820,9 @@ function KeepTourBar({
4096
4820
  return resolvedPrev();
4097
4821
  }
4098
4822
  });
4099
- const body = /* @__PURE__ */ jsxs17(Fragment12, { children: [
4100
- showProgress ? /* @__PURE__ */ jsx22("span", { "data-keepkit": "tour-progress", "aria-live": "polite", children: progress ?? `${navigation.currentPosition ?? 0} / ${navigation.items.length}` }) : null,
4101
- /* @__PURE__ */ jsx22(
4823
+ const body = /* @__PURE__ */ jsxs21(Fragment13, { children: [
4824
+ showProgress ? /* @__PURE__ */ jsx25("span", { "data-keepkit": "tour-progress", "aria-live": "polite", children: progress ?? `${navigation.currentPosition ?? 0} / ${navigation.items.length}` }) : null,
4825
+ /* @__PURE__ */ jsx25(
4102
4826
  TourAction,
4103
4827
  {
4104
4828
  href: prevHref,
@@ -4106,7 +4830,7 @@ function KeepTourBar({
4106
4830
  onClick: prevHref ? onPrev : resolvedPrev,
4107
4831
  "data-keep-action": "tour-prev",
4108
4832
  shortcut: showShortcutHint ? shortcutOptions?.prevKeys?.[0] ?? "K" : void 0,
4109
- preview: navigation.prevItem ? /* @__PURE__ */ jsxs17(Fragment12, { children: [
4833
+ preview: navigation.prevItem ? /* @__PURE__ */ jsxs21(Fragment13, { children: [
4110
4834
  previousLabel,
4111
4835
  ": ",
4112
4836
  getItemTitle(navigation.prevItem)
@@ -4114,7 +4838,7 @@ function KeepTourBar({
4114
4838
  children: previousLabel
4115
4839
  }
4116
4840
  ),
4117
- /* @__PURE__ */ jsx22(
4841
+ /* @__PURE__ */ jsx25(
4118
4842
  TourAction,
4119
4843
  {
4120
4844
  href: nextHref,
@@ -4122,7 +4846,7 @@ function KeepTourBar({
4122
4846
  onClick: nextHref ? onNext : resolvedNext,
4123
4847
  "data-keep-action": "tour-next",
4124
4848
  shortcut: showShortcutHint ? shortcutOptions?.nextKeys?.[0] ?? "J" : void 0,
4125
- preview: navigation.nextItem ? /* @__PURE__ */ jsxs17(Fragment12, { children: [
4849
+ preview: navigation.nextItem ? /* @__PURE__ */ jsxs21(Fragment13, { children: [
4126
4850
  nextItemLabel,
4127
4851
  ": ",
4128
4852
  getItemTitle(navigation.nextItem)
@@ -4130,7 +4854,7 @@ function KeepTourBar({
4130
4854
  children: nextItemLabel
4131
4855
  }
4132
4856
  ),
4133
- backHref || onBack ? /* @__PURE__ */ jsx22(TourAction, { href: backHref, onClick: onBack, "data-keep-action": "tour-back", children: listLabel }) : null
4857
+ backHref || onBack ? /* @__PURE__ */ jsx25(TourAction, { href: backHref, onClick: onBack, "data-keep-action": "tour-back", children: listLabel }) : null
4134
4858
  ] });
4135
4859
  return renderRoot(
4136
4860
  asChild,
@@ -4142,13 +4866,13 @@ function KeepTourBar({
4142
4866
  }
4143
4867
  function TourAction({ href, disabled = false, onClick, children, preview, shortcut, ...props }) {
4144
4868
  const previewId = useId();
4145
- const content = /* @__PURE__ */ jsxs17(Fragment12, { children: [
4146
- /* @__PURE__ */ jsx22("span", { "data-tour-label": "true", children }),
4147
- shortcut ? /* @__PURE__ */ jsx22(KeepShortcutHint, { shortcut }) : null,
4148
- preview ? /* @__PURE__ */ jsx22("small", { id: previewId, "data-tour-preview": "true", children: preview }) : null
4869
+ const content = /* @__PURE__ */ jsxs21(Fragment13, { children: [
4870
+ /* @__PURE__ */ jsx25("span", { "data-tour-label": "true", children }),
4871
+ shortcut ? /* @__PURE__ */ jsx25(KeepShortcutHint, { shortcut }) : null,
4872
+ preview ? /* @__PURE__ */ jsx25("small", { id: previewId, "data-tour-preview": "true", children: preview }) : null
4149
4873
  ] });
4150
4874
  if (href && !disabled) {
4151
- return /* @__PURE__ */ jsx22(
4875
+ return /* @__PURE__ */ jsx25(
4152
4876
  "a",
4153
4877
  {
4154
4878
  ...props,
@@ -4160,7 +4884,7 @@ function TourAction({ href, disabled = false, onClick, children, preview, shortc
4160
4884
  }
4161
4885
  );
4162
4886
  }
4163
- return /* @__PURE__ */ jsx22(
4887
+ return /* @__PURE__ */ jsx25(
4164
4888
  "button",
4165
4889
  {
4166
4890
  ...props,
@@ -4183,10 +4907,10 @@ function navigateTo(item, href) {
4183
4907
  import { isValidElement as isValidElement8 } from "react";
4184
4908
 
4185
4909
  // src/features/status/hooks/useStatusViews.ts
4186
- import { useKeepContext as useKeepContext4 } from "@keepkit/core/react";
4187
- import { useEffect as useEffect10, useRef as useRef6, useState as useState12 } from "react";
4910
+ import { useKeepContext as useKeepContext6 } from "@keepkit/core/react";
4911
+ import { useEffect as useEffect12, useRef as useRef9, useState as useState15 } from "react";
4188
4912
  function useKeepStatus(status) {
4189
- const context = useKeepContext4();
4913
+ const context = useKeepContext6();
4190
4914
  const resolvedStatus = status ?? getDerivedStatus(context);
4191
4915
  const state = {
4192
4916
  status: resolvedStatus,
@@ -4197,13 +4921,13 @@ function useKeepStatus(status) {
4197
4921
  return { state, defaultLabel: useUiLabel(getStatusLabelKey3(resolvedStatus)) };
4198
4922
  }
4199
4923
  function useKeepAnnouncements(messages) {
4200
- const context = useKeepContext4();
4924
+ const context = useKeepContext6();
4201
4925
  const savedMessage = useUiLabel("savedMessage", messages?.save);
4202
4926
  const removedMessage = useUiLabel("removedMessage", messages?.remove);
4203
4927
  const noteSavedMessage = useUiLabel("noteSavedMessage", messages?.note);
4204
- const [message, setMessage] = useState12("");
4205
- const lastChangeRef = useRef6(void 0);
4206
- useEffect10(() => {
4928
+ const [message, setMessage] = useState15("");
4929
+ const lastChangeRef = useRef9(void 0);
4930
+ useEffect12(() => {
4207
4931
  const change = context.lastChange;
4208
4932
  if (!change || change === lastChangeRef.current) return;
4209
4933
  lastChangeRef.current = change;
@@ -4231,7 +4955,7 @@ function getStatusLabelKey3(status) {
4231
4955
  }
4232
4956
 
4233
4957
  // src/features/status/status.tsx
4234
- import { jsx as jsx23 } from "react/jsx-runtime";
4958
+ import { jsx as jsx26 } from "react/jsx-runtime";
4235
4959
  function KeepStatus({
4236
4960
  status,
4237
4961
  labels,
@@ -4263,7 +4987,7 @@ function KeepStatus({
4263
4987
  }
4264
4988
  function KeepAnnouncements({ messages, ...props }) {
4265
4989
  const message = useKeepAnnouncements(messages);
4266
- return /* @__PURE__ */ jsx23(
4990
+ return /* @__PURE__ */ jsx26(
4267
4991
  "div",
4268
4992
  {
4269
4993
  ...props,
@@ -4279,15 +5003,15 @@ function KeepAnnouncements({ messages, ...props }) {
4279
5003
  var KeepAnnouncer = KeepAnnouncements;
4280
5004
 
4281
5005
  // src/features/sync/hooks/useKeepSyncFeedback.ts
4282
- import { useKeepContext as useKeepContext5 } from "@keepkit/core/react";
4283
- import { useEffect as useEffect11, useRef as useRef7 } from "react";
5006
+ import { useKeepContext as useKeepContext7 } from "@keepkit/core/react";
5007
+ import { useEffect as useEffect13, useRef as useRef10 } from "react";
4284
5008
  function useKeepSyncFeedback() {
4285
- const { syncState } = useKeepContext5();
5009
+ const { syncState } = useKeepContext7();
4286
5010
  const emitFeedback = useKeepUiFeedback();
4287
5011
  const completedMessage = useUiLabel("syncSynced");
4288
5012
  const failedMessage = useUiLabel("syncFailedMessage");
4289
- const previousStatus = useRef7("idle");
4290
- useEffect11(() => {
5013
+ const previousStatus = useRef10("idle");
5014
+ useEffect13(() => {
4291
5015
  const previous = previousStatus.current;
4292
5016
  previousStatus.current = syncState.status;
4293
5017
  if (syncState.status === "error" && previous !== "error") {
@@ -4307,17 +5031,17 @@ function KeepSyncFeedbackObserver() {
4307
5031
  }
4308
5032
 
4309
5033
  // src/features/sync/hooks/useKeepSyncRecoveryDialog.ts
4310
- import { useKeepContext as useKeepContext6 } from "@keepkit/core/react";
4311
- import { useEffect as useEffect12, useState as useState13 } from "react";
5034
+ import { useKeepContext as useKeepContext8 } from "@keepkit/core/react";
5035
+ import { useEffect as useEffect14, useState as useState16 } from "react";
4312
5036
  function useKeepSyncRecoveryDialog(options) {
4313
5037
  const { open, onOpenChange, conflicts, onManualMerge } = options;
4314
- const context = useKeepContext6();
5038
+ const context = useKeepContext8();
4315
5039
  const conflictList = conflicts ?? context.syncState.conflicts ?? [];
4316
5040
  const hasRecovery = conflictList.length > 0 || context.syncState.status === "error" || Boolean(context.error);
4317
- const [dismissed, setDismissed] = useState13(false);
4318
- const [busyId, setBusyId] = useState13();
4319
- const [error, setError] = useState13();
4320
- useEffect12(() => {
5041
+ const [dismissed, setDismissed] = useState16(false);
5042
+ const [busyId, setBusyId] = useState16();
5043
+ const [error, setError] = useState16();
5044
+ useEffect14(() => {
4321
5045
  if (hasRecovery) setDismissed(false);
4322
5046
  }, [hasRecovery]);
4323
5047
  return {
@@ -4362,7 +5086,7 @@ function useKeepSyncRecoveryDialog(options) {
4362
5086
  }
4363
5087
 
4364
5088
  // src/features/sync/KeepSyncRecoveryDialog.tsx
4365
- import { jsx as jsx24, jsxs as jsxs18 } from "react/jsx-runtime";
5089
+ import { jsx as jsx27, jsxs as jsxs22 } from "react/jsx-runtime";
4366
5090
  function KeepSyncRecoveryDialog({
4367
5091
  open,
4368
5092
  onOpenChange,
@@ -4377,7 +5101,7 @@ function KeepSyncRecoveryDialog({
4377
5101
  }) {
4378
5102
  const view = useKeepSyncRecoveryDialog({ open, onOpenChange, conflicts, onManualMerge });
4379
5103
  if (!view.isOpen) return null;
4380
- return /* @__PURE__ */ jsxs18(
5104
+ return /* @__PURE__ */ jsxs22(
4381
5105
  "section",
4382
5106
  {
4383
5107
  ...props,
@@ -4391,17 +5115,17 @@ function KeepSyncRecoveryDialog({
4391
5115
  "data-state": view.conflictList.length > 0 ? "conflict" : "error",
4392
5116
  "data-loading": view.busyId !== void 0 ? "true" : void 0,
4393
5117
  children: [
4394
- /* @__PURE__ */ jsxs18("header", { children: [
4395
- /* @__PURE__ */ jsx24("h2", { id: "keepkit-sync-recovery-title", children: title ?? view.labels.title }),
4396
- /* @__PURE__ */ jsx24("button", { type: "button", "data-keep-action": "close-dialog", onClick: view.close, "aria-label": view.labels.close, children: view.labels.close })
5118
+ /* @__PURE__ */ jsxs22("header", { children: [
5119
+ /* @__PURE__ */ jsx27("h2", { id: "keepkit-sync-recovery-title", children: title ?? view.labels.title }),
5120
+ /* @__PURE__ */ jsx27("button", { type: "button", "data-keep-action": "close-dialog", onClick: view.close, "aria-label": view.labels.close, children: view.labels.close })
4397
5121
  ] }),
4398
5122
  children,
4399
- view.conflictList.length > 0 ? /* @__PURE__ */ jsxs18("div", { children: [
4400
- /* @__PURE__ */ jsx24("p", { children: view.labels.conflict }),
4401
- view.conflictList.map((conflict) => /* @__PURE__ */ jsxs18("article", { "data-conflict-id": conflict.id, children: [
4402
- /* @__PURE__ */ jsx24("h3", { children: getMetaTitle(conflict.operation.item?.meta) ?? conflict.id }),
4403
- /* @__PURE__ */ jsxs18("div", { "data-conflict-preview": true, children: [
4404
- /* @__PURE__ */ jsx24(
5123
+ view.conflictList.length > 0 ? /* @__PURE__ */ jsxs22("div", { children: [
5124
+ /* @__PURE__ */ jsx27("p", { children: view.labels.conflict }),
5125
+ view.conflictList.map((conflict) => /* @__PURE__ */ jsxs22("article", { "data-conflict-id": conflict.id, children: [
5126
+ /* @__PURE__ */ jsx27("h3", { children: getMetaTitle(conflict.operation.item?.meta) ?? conflict.id }),
5127
+ /* @__PURE__ */ jsxs22("div", { "data-conflict-preview": true, children: [
5128
+ /* @__PURE__ */ jsx27(
4405
5129
  ConflictPreview,
4406
5130
  {
4407
5131
  item: conflict.operation.item,
@@ -4411,7 +5135,7 @@ function KeepSyncRecoveryDialog({
4411
5135
  side: "local"
4412
5136
  }
4413
5137
  ),
4414
- /* @__PURE__ */ jsx24(
5138
+ /* @__PURE__ */ jsx27(
4415
5139
  ConflictPreview,
4416
5140
  {
4417
5141
  item: conflict.remote,
@@ -4422,8 +5146,8 @@ function KeepSyncRecoveryDialog({
4422
5146
  }
4423
5147
  )
4424
5148
  ] }),
4425
- /* @__PURE__ */ jsxs18("div", { children: [
4426
- /* @__PURE__ */ jsx24(
5149
+ /* @__PURE__ */ jsxs22("div", { children: [
5150
+ /* @__PURE__ */ jsx27(
4427
5151
  "button",
4428
5152
  {
4429
5153
  type: "button",
@@ -4433,7 +5157,7 @@ function KeepSyncRecoveryDialog({
4433
5157
  children: view.labels.keepLocal
4434
5158
  }
4435
5159
  ),
4436
- /* @__PURE__ */ jsx24(
5160
+ /* @__PURE__ */ jsx27(
4437
5161
  "button",
4438
5162
  {
4439
5163
  type: "button",
@@ -4443,7 +5167,7 @@ function KeepSyncRecoveryDialog({
4443
5167
  children: view.labels.useServer
4444
5168
  }
4445
5169
  ),
4446
- /* @__PURE__ */ jsx24(
5170
+ /* @__PURE__ */ jsx27(
4447
5171
  "button",
4448
5172
  {
4449
5173
  type: "button",
@@ -4456,12 +5180,12 @@ function KeepSyncRecoveryDialog({
4456
5180
  ] })
4457
5181
  ] }, conflict.id))
4458
5182
  ] }) : null,
4459
- view.showBackupRecovery ? /* @__PURE__ */ jsxs18("section", { "data-recovery": "backup", children: [
4460
- /* @__PURE__ */ jsx24("h3", { children: view.labels.backupRecovery }),
4461
- /* @__PURE__ */ jsx24("p", { children: view.labels.backupRecoveryDescription }),
4462
- backup ?? (showBackupControls ? /* @__PURE__ */ jsx24(KeepBackup, {}) : null)
5183
+ view.showBackupRecovery ? /* @__PURE__ */ jsxs22("section", { "data-recovery": "backup", children: [
5184
+ /* @__PURE__ */ jsx27("h3", { children: view.labels.backupRecovery }),
5185
+ /* @__PURE__ */ jsx27("p", { children: view.labels.backupRecoveryDescription }),
5186
+ backup ?? (showBackupControls ? /* @__PURE__ */ jsx27(KeepBackup, {}) : null)
4463
5187
  ] }) : null,
4464
- 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
5188
+ 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
4465
5189
  ]
4466
5190
  }
4467
5191
  );
@@ -4473,16 +5197,16 @@ function ConflictPreview({
4473
5197
  noteLabel,
4474
5198
  side
4475
5199
  }) {
4476
- return /* @__PURE__ */ jsxs18("article", { "data-conflict-version": side, "aria-label": heading, children: [
4477
- /* @__PURE__ */ jsx24("h4", { children: heading }),
4478
- /* @__PURE__ */ jsxs18("dl", { children: [
4479
- /* @__PURE__ */ jsxs18("div", { children: [
4480
- /* @__PURE__ */ jsx24("dt", { children: updatedAtLabel }),
4481
- /* @__PURE__ */ jsx24("dd", { children: item ? /* @__PURE__ */ jsx24("time", { dateTime: new Date(item.updatedAt).toISOString(), children: formatConflictDate(item.updatedAt) }) : "\u2014" })
5200
+ return /* @__PURE__ */ jsxs22("article", { "data-conflict-version": side, "aria-label": heading, children: [
5201
+ /* @__PURE__ */ jsx27("h4", { children: heading }),
5202
+ /* @__PURE__ */ jsxs22("dl", { children: [
5203
+ /* @__PURE__ */ jsxs22("div", { children: [
5204
+ /* @__PURE__ */ jsx27("dt", { children: updatedAtLabel }),
5205
+ /* @__PURE__ */ jsx27("dd", { children: item ? /* @__PURE__ */ jsx27("time", { dateTime: new Date(item.updatedAt).toISOString(), children: formatConflictDate(item.updatedAt) }) : "\u2014" })
4482
5206
  ] }),
4483
- /* @__PURE__ */ jsxs18("div", { children: [
4484
- /* @__PURE__ */ jsx24("dt", { children: noteLabel }),
4485
- /* @__PURE__ */ jsx24("dd", { children: item?.note || "\u2014" })
5207
+ /* @__PURE__ */ jsxs22("div", { children: [
5208
+ /* @__PURE__ */ jsx27("dt", { children: noteLabel }),
5209
+ /* @__PURE__ */ jsx27("dd", { children: item?.note || "\u2014" })
4486
5210
  ] })
4487
5211
  ] })
4488
5212
  ] });
@@ -4492,9 +5216,9 @@ function formatConflictDate(timestamp) {
4492
5216
  }
4493
5217
 
4494
5218
  // src/features/sync/hooks/useKeepSyncStatusBanner.ts
4495
- import { useKeepContext as useKeepContext7 } from "@keepkit/core/react";
5219
+ import { useKeepContext as useKeepContext9 } from "@keepkit/core/react";
4496
5220
  function useKeepSyncStatusBanner({ onRetry, children }) {
4497
- const context = useKeepContext7();
5221
+ const context = useKeepContext9();
4498
5222
  const retryLabel = useUiLabel("retrySync");
4499
5223
  const resolveLabel = useUiLabel("resolveSync");
4500
5224
  const conflictLabel = useUiLabel("syncConflict");
@@ -4526,7 +5250,7 @@ function getErrorMessage5(error) {
4526
5250
  }
4527
5251
 
4528
5252
  // src/features/sync/KeepSyncStatusBanner.tsx
4529
- import { jsx as jsx25, jsxs as jsxs19 } from "react/jsx-runtime";
5253
+ import { jsx as jsx28, jsxs as jsxs23 } from "react/jsx-runtime";
4530
5254
  function KeepSyncStatusBanner({
4531
5255
  onRetry,
4532
5256
  onResolveConflicts,
@@ -4536,7 +5260,7 @@ function KeepSyncStatusBanner({
4536
5260
  }) {
4537
5261
  const view = useKeepSyncStatusBanner({ onRetry, children });
4538
5262
  if (view.status === "idle" && !view.hasConflicts) return null;
4539
- return /* @__PURE__ */ jsxs19(
5263
+ return /* @__PURE__ */ jsxs23(
4540
5264
  "aside",
4541
5265
  {
4542
5266
  ...props,
@@ -4546,8 +5270,8 @@ function KeepSyncStatusBanner({
4546
5270
  "data-keepkit": "sync-status",
4547
5271
  "data-state": view.status,
4548
5272
  children: [
4549
- /* @__PURE__ */ jsx25("p", { children: view.message }),
4550
- view.showRetry ? /* @__PURE__ */ jsx25(
5273
+ /* @__PURE__ */ jsx28("p", { children: view.message }),
5274
+ view.showRetry ? /* @__PURE__ */ jsx28(
4551
5275
  "button",
4552
5276
  {
4553
5277
  type: "button",
@@ -4557,7 +5281,7 @@ function KeepSyncStatusBanner({
4557
5281
  children: view.retryLabel
4558
5282
  }
4559
5283
  ) : null,
4560
- view.hasConflicts ? /* @__PURE__ */ jsx25(
5284
+ view.hasConflicts ? /* @__PURE__ */ jsx28(
4561
5285
  "button",
4562
5286
  {
4563
5287
  type: "button",
@@ -4574,7 +5298,7 @@ function KeepSyncStatusBanner({
4574
5298
 
4575
5299
  // src/foundation/theme.tsx
4576
5300
  import { isValidElement as isValidElement9 } from "react";
4577
- import { jsx as jsx26 } from "react/jsx-runtime";
5301
+ import { jsx as jsx29 } from "react/jsx-runtime";
4578
5302
  var keepThemeNames = [
4579
5303
  "default",
4580
5304
  "ocean",
@@ -4633,7 +5357,7 @@ function KeepThemeProvider({
4633
5357
  throw new Error("KeepThemeProvider with asChild requires a single React element child.");
4634
5358
  return createSlot(children, rootProps);
4635
5359
  }
4636
- return /* @__PURE__ */ jsx26("div", { ...rootProps, children });
5360
+ return /* @__PURE__ */ jsx29("div", { ...rootProps, children });
4637
5361
  }
4638
5362
 
4639
5363
  // src/index.tsx
@@ -4641,8 +5365,8 @@ import { createAuthenticatedSyncKit } from "@keepkit/core/core";
4641
5365
  import {
4642
5366
  KeepErrorBoundary as KeepErrorBoundary3,
4643
5367
  KeepProvider,
4644
- useKeepContext as useKeepContext8,
4645
- useKeepItem as useKeepItem5,
5368
+ useKeepContext as useKeepContext10,
5369
+ useKeepItem as useKeepItem8,
4646
5370
  useKeepList as useKeepList5,
4647
5371
  useKeepNavigator as useKeepNavigator2,
4648
5372
  useKeepShortcut
@@ -4657,7 +5381,7 @@ import {
4657
5381
  LocalStorageSyncQueueAdapter,
4658
5382
  SyncStorageAdapter
4659
5383
  } from "@keepkit/core/storage";
4660
- import { jsx as jsx27, jsxs as jsxs20 } from "react/jsx-runtime";
5384
+ import { jsx as jsx30, jsxs as jsxs24 } from "react/jsx-runtime";
4661
5385
  function KeepKitProvider({
4662
5386
  labels,
4663
5387
  locale,
@@ -4677,7 +5401,7 @@ function KeepKitProvider({
4677
5401
  children,
4678
5402
  ...providerProps
4679
5403
  }) {
4680
- return /* @__PURE__ */ jsx27(KeepUiProvider, { labels, locale, labelResolver, onFeedback, children: /* @__PURE__ */ jsx27(
5404
+ return /* @__PURE__ */ jsx30(KeepUiProvider, { labels, locale, labelResolver, onFeedback, children: /* @__PURE__ */ jsx30(
4681
5405
  KeepThemeProvider,
4682
5406
  {
4683
5407
  theme,
@@ -4691,10 +5415,10 @@ function KeepKitProvider({
4691
5415
  className: themeClassName,
4692
5416
  style: themeStyle,
4693
5417
  asChild: themeAsChild,
4694
- children: /* @__PURE__ */ jsxs20(CoreKeepProvider, { ...providerProps, children: [
4695
- /* @__PURE__ */ jsx27(KeepSyncFeedbackObserver, {}),
5418
+ children: /* @__PURE__ */ jsxs24(CoreKeepProvider, { ...providerProps, children: [
5419
+ /* @__PURE__ */ jsx30(KeepSyncFeedbackObserver, {}),
4696
5420
  children,
4697
- /* @__PURE__ */ jsx27(KeepAnnouncements, {})
5421
+ /* @__PURE__ */ jsx30(KeepAnnouncements, {})
4698
5422
  ] })
4699
5423
  }
4700
5424
  ) });
@@ -4721,7 +5445,7 @@ function createKeepKit(options = {}) {
4721
5445
  } = options;
4722
5446
  const coreKit = createCoreKeepKit(coreOptions);
4723
5447
  return {
4724
- Provider: (props) => /* @__PURE__ */ jsx27(
5448
+ Provider: (props) => /* @__PURE__ */ jsx30(
4725
5449
  KeepKitProvider,
4726
5450
  {
4727
5451
  ...coreOptions,
@@ -4742,9 +5466,9 @@ function createKeepKit(options = {}) {
4742
5466
  ...props
4743
5467
  }
4744
5468
  ),
4745
- Button: (props) => /* @__PURE__ */ jsx27(KeepButton, { ...props }),
4746
- Backup: (props) => /* @__PURE__ */ jsx27(KeepBackup, { ...props }),
4747
- Collection: (props) => /* @__PURE__ */ jsx27(
5469
+ Button: (props) => /* @__PURE__ */ jsx30(KeepButton, { ...props }),
5470
+ Backup: (props) => /* @__PURE__ */ jsx30(KeepBackup, { ...props }),
5471
+ Collection: (props) => /* @__PURE__ */ jsx30(
4748
5472
  KeepCollection,
4749
5473
  {
4750
5474
  ...props,
@@ -4769,10 +5493,13 @@ export {
4769
5493
  KeepActiveFiltersSummary,
4770
5494
  KeepAnnouncements,
4771
5495
  KeepAnnouncer,
5496
+ KeepArchiveButton,
4772
5497
  KeepBackup,
4773
5498
  KeepBulkActions,
4774
5499
  KeepButton,
4775
5500
  KeepCollection,
5501
+ KeepCollectionFilter,
5502
+ KeepCollectionSelect,
4776
5503
  KeepEmptyState,
4777
5504
  KeepErrorBoundary3 as KeepErrorBoundary,
4778
5505
  KeepHighlight,
@@ -4786,9 +5513,12 @@ export {
4786
5513
  KeepNavigator,
4787
5514
  KeepNoteEditor,
4788
5515
  KeepPagination,
5516
+ KeepPinButton,
4789
5517
  KeepProvider,
4790
5518
  KeepPruneStaleButton,
5519
+ KeepQuickEditor,
4791
5520
  KeepReorderableList,
5521
+ KeepSavePopover,
4792
5522
  KeepSearchInput,
4793
5523
  KeepShortcutHint,
4794
5524
  KeepSortSelect,
@@ -4806,6 +5536,7 @@ export {
4806
5536
  LocalStorageSyncQueueAdapter,
4807
5537
  SyncStorageAdapter,
4808
5538
  chainedFunction,
5539
+ composeRefs,
4809
5540
  createAuthenticatedSyncKit,
4810
5541
  createBrowserStorageAdapter,
4811
5542
  createKeepKit,
@@ -4818,10 +5549,11 @@ export {
4818
5549
  keepThemeNames,
4819
5550
  mergeProps,
4820
5551
  toggleSelectAll,
4821
- useKeepContext8 as useKeepContext,
4822
- useKeepItem5 as useKeepItem,
5552
+ useKeepContext10 as useKeepContext,
5553
+ useKeepItem8 as useKeepItem,
4823
5554
  useKeepList5 as useKeepList,
4824
5555
  useKeepNavigator2 as useKeepNavigator,
5556
+ useKeepQuickEditor,
4825
5557
  useKeepShortcut,
4826
5558
  useKeepToastFeedback,
4827
5559
  useKeepTourShortcuts,