@keepkit/ui 0.15.0 → 0.16.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/README.md +46 -2
- package/dist/index.d.ts +383 -37
- package/dist/index.js +436 -115
- package/dist/index.js.map +1 -1
- package/dist/styles/collection.css +180 -8
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -6,12 +6,32 @@ import {
|
|
|
6
6
|
createKeepKit as createCoreKeepKit
|
|
7
7
|
} from "@keepkit/core/react";
|
|
8
8
|
|
|
9
|
+
// src/hooks/useKeepToastFeedback.ts
|
|
10
|
+
import { useCallback } from "react";
|
|
11
|
+
function useKeepToastFeedback(showToast) {
|
|
12
|
+
return useCallback(
|
|
13
|
+
(event) => {
|
|
14
|
+
if (!("undo" in event)) {
|
|
15
|
+
showToast(event.message);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
showToast(event.message, {
|
|
19
|
+
action: {
|
|
20
|
+
label: event.undoLabel,
|
|
21
|
+
onClick: () => void event.undo()
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
},
|
|
25
|
+
[showToast]
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
9
29
|
// src/hooks/useKeepBackup.ts
|
|
10
30
|
import { useKeepContext } from "@keepkit/core/react";
|
|
11
31
|
import { useRef, useState } from "react";
|
|
12
32
|
|
|
13
33
|
// src/ui-context.tsx
|
|
14
|
-
import { createContext, useContext, useMemo } from "react";
|
|
34
|
+
import { createContext, useCallback as useCallback2, useContext, useMemo } from "react";
|
|
15
35
|
|
|
16
36
|
// src/locales/de.ts
|
|
17
37
|
var DE_LABELS = {
|
|
@@ -49,6 +69,9 @@ var DE_LABELS = {
|
|
|
49
69
|
applyTags: "Tags anwenden",
|
|
50
70
|
savedMessage: "Element gespeichert.",
|
|
51
71
|
removedMessage: "Element entfernt.",
|
|
72
|
+
restoredMessage: "Element wiederhergestellt.",
|
|
73
|
+
syncFailedMessage: "Synchronisierung fehlgeschlagen.",
|
|
74
|
+
stalePrunedMessage: "Nicht verf\xFCgbare Elemente entfernt.",
|
|
52
75
|
undo: "R\xFCckg\xE4ngig",
|
|
53
76
|
undoAvailable: "Element entfernt. R\xFCckg\xE4ngig machen?",
|
|
54
77
|
selectionScope: "Auswahlbereich",
|
|
@@ -125,6 +148,9 @@ var EN_LABELS = {
|
|
|
125
148
|
applyTags: "Apply tags",
|
|
126
149
|
savedMessage: "Item saved.",
|
|
127
150
|
removedMessage: "Item removed.",
|
|
151
|
+
restoredMessage: "Item restored.",
|
|
152
|
+
syncFailedMessage: "Sync failed.",
|
|
153
|
+
stalePrunedMessage: "Unavailable items removed.",
|
|
128
154
|
undo: "Undo",
|
|
129
155
|
undoAvailable: "Item removed. Undo?",
|
|
130
156
|
selectionScope: "Selection scope",
|
|
@@ -201,6 +227,9 @@ var ES_LABELS = {
|
|
|
201
227
|
applyTags: "Aplicar etiquetas",
|
|
202
228
|
savedMessage: "Elemento guardado.",
|
|
203
229
|
removedMessage: "Elemento eliminado.",
|
|
230
|
+
restoredMessage: "Elemento restaurado.",
|
|
231
|
+
syncFailedMessage: "Error de sincronizaci\xF3n.",
|
|
232
|
+
stalePrunedMessage: "Elementos no disponibles eliminados.",
|
|
204
233
|
undo: "Deshacer",
|
|
205
234
|
undoAvailable: "Elemento eliminado. \xBFDeshacer?",
|
|
206
235
|
selectionScope: "\xC1mbito de selecci\xF3n",
|
|
@@ -277,6 +306,9 @@ var FIL_LABELS = {
|
|
|
277
306
|
applyTags: "Ilapat ang mga tag",
|
|
278
307
|
savedMessage: "Na-save ang item.",
|
|
279
308
|
removedMessage: "Inalis ang item.",
|
|
309
|
+
restoredMessage: "Naibalik ang item.",
|
|
310
|
+
syncFailedMessage: "Hindi nagtagumpay ang pag-sync.",
|
|
311
|
+
stalePrunedMessage: "Inalis ang mga hindi available na item.",
|
|
280
312
|
undo: "I-undo",
|
|
281
313
|
undoAvailable: "Inalis ang item. I-undo?",
|
|
282
314
|
selectionScope: "Saklaw ng pagpili",
|
|
@@ -353,6 +385,9 @@ var FR_LABELS = {
|
|
|
353
385
|
applyTags: "Appliquer les \xE9tiquettes",
|
|
354
386
|
savedMessage: "\xC9l\xE9ment enregistr\xE9.",
|
|
355
387
|
removedMessage: "\xC9l\xE9ment supprim\xE9.",
|
|
388
|
+
restoredMessage: "\xC9l\xE9ment restaur\xE9.",
|
|
389
|
+
syncFailedMessage: "\xC9chec de la synchronisation.",
|
|
390
|
+
stalePrunedMessage: "\xC9l\xE9ments indisponibles supprim\xE9s.",
|
|
356
391
|
undo: "Annuler",
|
|
357
392
|
undoAvailable: "\xC9l\xE9ment supprim\xE9. Annuler ?",
|
|
358
393
|
selectionScope: "Port\xE9e de la s\xE9lection",
|
|
@@ -429,6 +464,9 @@ var ID_LABELS = {
|
|
|
429
464
|
applyTags: "Terapkan tag",
|
|
430
465
|
savedMessage: "Item tersimpan.",
|
|
431
466
|
removedMessage: "Item dihapus.",
|
|
467
|
+
restoredMessage: "Item dipulihkan.",
|
|
468
|
+
syncFailedMessage: "Sinkronisasi gagal.",
|
|
469
|
+
stalePrunedMessage: "Item yang tidak tersedia dihapus.",
|
|
432
470
|
undo: "Urungkan",
|
|
433
471
|
undoAvailable: "Item dihapus. Urungkan?",
|
|
434
472
|
selectionScope: "Cakupan pilihan",
|
|
@@ -505,6 +543,9 @@ var IT_LABELS = {
|
|
|
505
543
|
applyTags: "Applica tag",
|
|
506
544
|
savedMessage: "Elemento salvato.",
|
|
507
545
|
removedMessage: "Elemento rimosso.",
|
|
546
|
+
restoredMessage: "Elemento ripristinato.",
|
|
547
|
+
syncFailedMessage: "Sincronizzazione non riuscita.",
|
|
548
|
+
stalePrunedMessage: "Elementi non disponibili rimossi.",
|
|
508
549
|
undo: "Annulla",
|
|
509
550
|
undoAvailable: "Elemento rimosso. Annullare?",
|
|
510
551
|
selectionScope: "Ambito della selezione",
|
|
@@ -581,6 +622,9 @@ var JA_LABELS = {
|
|
|
581
622
|
applyTags: "\u30BF\u30B0\u3092\u9069\u7528",
|
|
582
623
|
savedMessage: "\u30A2\u30A4\u30C6\u30E0\u3092\u4FDD\u5B58\u3057\u307E\u3057\u305F\u3002",
|
|
583
624
|
removedMessage: "\u30A2\u30A4\u30C6\u30E0\u3092\u524A\u9664\u3057\u307E\u3057\u305F\u3002",
|
|
625
|
+
restoredMessage: "\u30A2\u30A4\u30C6\u30E0\u3092\u5FA9\u5143\u3057\u307E\u3057\u305F\u3002",
|
|
626
|
+
syncFailedMessage: "\u540C\u671F\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002",
|
|
627
|
+
stalePrunedMessage: "\u5229\u7528\u3067\u304D\u306A\u3044\u30A2\u30A4\u30C6\u30E0\u3092\u524A\u9664\u3057\u307E\u3057\u305F\u3002",
|
|
584
628
|
undo: "\u5143\u306B\u623B\u3059",
|
|
585
629
|
undoAvailable: "\u30A2\u30A4\u30C6\u30E0\u3092\u524A\u9664\u3057\u307E\u3057\u305F\u3002\u5143\u306B\u623B\u3057\u307E\u3059\u304B\uFF1F",
|
|
586
630
|
selectionScope: "\u9078\u629E\u7BC4\u56F2",
|
|
@@ -657,6 +701,9 @@ var KO_LABELS = {
|
|
|
657
701
|
applyTags: "\uD0DC\uADF8 \uC801\uC6A9",
|
|
658
702
|
savedMessage: "\uD56D\uBAA9\uC744 \uC800\uC7A5\uD588\uC2B5\uB2C8\uB2E4.",
|
|
659
703
|
removedMessage: "\uD56D\uBAA9\uC744 \uC0AD\uC81C\uD588\uC2B5\uB2C8\uB2E4.",
|
|
704
|
+
restoredMessage: "\uD56D\uBAA9\uC744 \uBCF5\uC6D0\uD588\uC2B5\uB2C8\uB2E4.",
|
|
705
|
+
syncFailedMessage: "\uB3D9\uAE30\uD654\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.",
|
|
706
|
+
stalePrunedMessage: "\uC0AC\uC6A9\uD560 \uC218 \uC5C6\uB294 \uD56D\uBAA9\uC744 \uC0AD\uC81C\uD588\uC2B5\uB2C8\uB2E4.",
|
|
660
707
|
undo: "\uC2E4\uD589 \uCDE8\uC18C",
|
|
661
708
|
undoAvailable: "\uD56D\uBAA9\uC744 \uC0AD\uC81C\uD588\uC2B5\uB2C8\uB2E4. \uC2E4\uD589 \uCDE8\uC18C\uD560\uAE4C\uC694?",
|
|
662
709
|
selectionScope: "\uC120\uD0DD \uBC94\uC704",
|
|
@@ -733,6 +780,9 @@ var MS_LABELS = {
|
|
|
733
780
|
applyTags: "Gunakan tag",
|
|
734
781
|
savedMessage: "Item disimpan.",
|
|
735
782
|
removedMessage: "Item dibuang.",
|
|
783
|
+
restoredMessage: "Item dipulihkan.",
|
|
784
|
+
syncFailedMessage: "Penyegerakan gagal.",
|
|
785
|
+
stalePrunedMessage: "Item yang tidak tersedia dibuang.",
|
|
736
786
|
undo: "Buat asal",
|
|
737
787
|
undoAvailable: "Item dibuang. Buat asal?",
|
|
738
788
|
selectionScope: "Skop pilihan",
|
|
@@ -809,6 +859,9 @@ var PT_BR_LABELS = {
|
|
|
809
859
|
applyTags: "Aplicar tags",
|
|
810
860
|
savedMessage: "Item salvo.",
|
|
811
861
|
removedMessage: "Item removido.",
|
|
862
|
+
restoredMessage: "Item restaurado.",
|
|
863
|
+
syncFailedMessage: "Falha na sincroniza\xE7\xE3o.",
|
|
864
|
+
stalePrunedMessage: "Itens indispon\xEDveis removidos.",
|
|
812
865
|
undo: "Desfazer",
|
|
813
866
|
undoAvailable: "Item removido. Desfazer?",
|
|
814
867
|
selectionScope: "Escopo da sele\xE7\xE3o",
|
|
@@ -885,6 +938,9 @@ var RU_LABELS = {
|
|
|
885
938
|
applyTags: "\u041F\u0440\u0438\u043C\u0435\u043D\u0438\u0442\u044C \u0442\u0435\u0433\u0438",
|
|
886
939
|
savedMessage: "\u042D\u043B\u0435\u043C\u0435\u043D\u0442 \u0441\u043E\u0445\u0440\u0430\u043D\u0451\u043D.",
|
|
887
940
|
removedMessage: "\u042D\u043B\u0435\u043C\u0435\u043D\u0442 \u0443\u0434\u0430\u043B\u0451\u043D.",
|
|
941
|
+
restoredMessage: "\u042D\u043B\u0435\u043C\u0435\u043D\u0442 \u0432\u043E\u0441\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D.",
|
|
942
|
+
syncFailedMessage: "\u0421\u0438\u043D\u0445\u0440\u043E\u043D\u0438\u0437\u0430\u0446\u0438\u044F \u043D\u0435 \u0432\u044B\u043F\u043E\u043B\u043D\u0435\u043D\u0430.",
|
|
943
|
+
stalePrunedMessage: "\u041D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0435 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u044B \u0443\u0434\u0430\u043B\u0435\u043D\u044B.",
|
|
888
944
|
undo: "\u041E\u0442\u043C\u0435\u043D\u0438\u0442\u044C",
|
|
889
945
|
undoAvailable: "\u042D\u043B\u0435\u043C\u0435\u043D\u0442 \u0443\u0434\u0430\u043B\u0451\u043D. \u041E\u0442\u043C\u0435\u043D\u0438\u0442\u044C?",
|
|
890
946
|
selectionScope: "\u041E\u0431\u043B\u0430\u0441\u0442\u044C \u0432\u044B\u0431\u043E\u0440\u0430",
|
|
@@ -961,6 +1017,9 @@ var TH_LABELS = {
|
|
|
961
1017
|
applyTags: "\u0E43\u0E0A\u0E49\u0E41\u0E17\u0E47\u0E01",
|
|
962
1018
|
savedMessage: "\u0E1A\u0E31\u0E19\u0E17\u0E36\u0E01\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23\u0E41\u0E25\u0E49\u0E27",
|
|
963
1019
|
removedMessage: "\u0E25\u0E1A\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23\u0E41\u0E25\u0E49\u0E27",
|
|
1020
|
+
restoredMessage: "\u0E01\u0E39\u0E49\u0E04\u0E37\u0E19\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23\u0E41\u0E25\u0E49\u0E27",
|
|
1021
|
+
syncFailedMessage: "\u0E0B\u0E34\u0E07\u0E04\u0E4C\u0E44\u0E21\u0E48\u0E2A\u0E33\u0E40\u0E23\u0E47\u0E08",
|
|
1022
|
+
stalePrunedMessage: "\u0E25\u0E1A\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23\u0E17\u0E35\u0E48\u0E43\u0E0A\u0E49\u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E41\u0E25\u0E49\u0E27",
|
|
964
1023
|
undo: "\u0E40\u0E25\u0E34\u0E01\u0E17\u0E33",
|
|
965
1024
|
undoAvailable: "\u0E25\u0E1A\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23\u0E41\u0E25\u0E49\u0E27 \u0E15\u0E49\u0E2D\u0E07\u0E01\u0E32\u0E23\u0E40\u0E25\u0E34\u0E01\u0E17\u0E33\u0E2B\u0E23\u0E37\u0E2D\u0E44\u0E21\u0E48",
|
|
966
1025
|
selectionScope: "\u0E02\u0E2D\u0E1A\u0E40\u0E02\u0E15\u0E01\u0E32\u0E23\u0E40\u0E25\u0E37\u0E2D\u0E01",
|
|
@@ -1037,6 +1096,9 @@ var VI_LABELS = {
|
|
|
1037
1096
|
applyTags: "\xC1p d\u1EE5ng th\u1EBB",
|
|
1038
1097
|
savedMessage: "\u0110\xE3 l\u01B0u m\u1EE5c.",
|
|
1039
1098
|
removedMessage: "\u0110\xE3 x\xF3a m\u1EE5c.",
|
|
1099
|
+
restoredMessage: "\u0110\xE3 kh\xF4i ph\u1EE5c m\u1EE5c.",
|
|
1100
|
+
syncFailedMessage: "\u0110\u1ED3ng b\u1ED9 kh\xF4ng th\xE0nh c\xF4ng.",
|
|
1101
|
+
stalePrunedMessage: "\u0110\xE3 x\xF3a c\xE1c m\u1EE5c kh\xF4ng kh\u1EA3 d\u1EE5ng.",
|
|
1040
1102
|
undo: "Ho\xE0n t\xE1c",
|
|
1041
1103
|
undoAvailable: "\u0110\xE3 x\xF3a m\u1EE5c. Ho\xE0n t\xE1c?",
|
|
1042
1104
|
selectionScope: "Ph\u1EA1m vi l\u1EF1a ch\u1ECDn",
|
|
@@ -1113,6 +1175,9 @@ var ZH_HANS_LABELS = {
|
|
|
1113
1175
|
applyTags: "\u5E94\u7528\u6807\u7B7E",
|
|
1114
1176
|
savedMessage: "\u9879\u76EE\u5DF2\u4FDD\u5B58\u3002",
|
|
1115
1177
|
removedMessage: "\u9879\u76EE\u5DF2\u5220\u9664\u3002",
|
|
1178
|
+
restoredMessage: "\u9879\u76EE\u5DF2\u6062\u590D\u3002",
|
|
1179
|
+
syncFailedMessage: "\u540C\u6B65\u5931\u8D25\u3002",
|
|
1180
|
+
stalePrunedMessage: "\u4E0D\u53EF\u7528\u9879\u76EE\u5DF2\u5220\u9664\u3002",
|
|
1116
1181
|
undo: "\u64A4\u9500",
|
|
1117
1182
|
undoAvailable: "\u9879\u76EE\u5DF2\u5220\u9664\u3002\u8981\u64A4\u9500\u5417\uFF1F",
|
|
1118
1183
|
selectionScope: "\u9009\u62E9\u8303\u56F4",
|
|
@@ -1189,6 +1254,9 @@ var ZH_HANT_LABELS = {
|
|
|
1189
1254
|
applyTags: "\u5957\u7528\u6A19\u7C64",
|
|
1190
1255
|
savedMessage: "\u9805\u76EE\u5DF2\u5132\u5B58\u3002",
|
|
1191
1256
|
removedMessage: "\u9805\u76EE\u5DF2\u522A\u9664\u3002",
|
|
1257
|
+
restoredMessage: "\u9805\u76EE\u5DF2\u9084\u539F\u3002",
|
|
1258
|
+
syncFailedMessage: "\u540C\u6B65\u5931\u6557\u3002",
|
|
1259
|
+
stalePrunedMessage: "\u7121\u6CD5\u4F7F\u7528\u7684\u9805\u76EE\u5DF2\u522A\u9664\u3002",
|
|
1192
1260
|
undo: "\u5FA9\u539F",
|
|
1193
1261
|
undoAvailable: "\u9805\u76EE\u5DF2\u522A\u9664\u3002\u8981\u5FA9\u539F\u55CE\uFF1F",
|
|
1194
1262
|
selectionScope: "\u9078\u53D6\u7BC4\u570D",
|
|
@@ -1291,14 +1359,29 @@ function getKeepLocaleLabels(locale) {
|
|
|
1291
1359
|
// src/ui-context.tsx
|
|
1292
1360
|
import { jsx } from "react/jsx-runtime";
|
|
1293
1361
|
var DEFAULT_LABELS = KEEP_LOCALE_LABELS.en;
|
|
1294
|
-
var KeepUiLabelsContext = createContext({
|
|
1295
|
-
|
|
1362
|
+
var KeepUiLabelsContext = createContext({
|
|
1363
|
+
labels: DEFAULT_LABELS,
|
|
1364
|
+
emitFeedback: () => void 0
|
|
1365
|
+
});
|
|
1366
|
+
function KeepUiProvider({
|
|
1367
|
+
labels,
|
|
1368
|
+
locale,
|
|
1369
|
+
labelResolver,
|
|
1370
|
+
onFeedback,
|
|
1371
|
+
children
|
|
1372
|
+
}) {
|
|
1373
|
+
const emitFeedback = useCallback2(
|
|
1374
|
+
(event) => {
|
|
1375
|
+
onFeedback?.(event);
|
|
1376
|
+
},
|
|
1377
|
+
[onFeedback]
|
|
1378
|
+
);
|
|
1296
1379
|
const value = useMemo(() => {
|
|
1297
1380
|
const resolvedLocale = normalizeKeepLocale(locale);
|
|
1298
1381
|
const dictionary = getKeepLocaleLabels(resolvedLocale);
|
|
1299
1382
|
const resolved = { ...DEFAULT_LABELS, ...dictionary, ...labels };
|
|
1300
|
-
return { locale: locale ?? resolvedLocale, labels: resolved, customLabels: labels, labelResolver };
|
|
1301
|
-
}, [labelResolver, labels, locale]);
|
|
1383
|
+
return { locale: locale ?? resolvedLocale, labels: resolved, customLabels: labels, labelResolver, emitFeedback };
|
|
1384
|
+
}, [emitFeedback, labelResolver, labels, locale]);
|
|
1302
1385
|
return /* @__PURE__ */ jsx(KeepUiLabelsContext.Provider, { value, children });
|
|
1303
1386
|
}
|
|
1304
1387
|
function useKeepUiLabels() {
|
|
@@ -1308,6 +1391,10 @@ function useUiLabel(key, override) {
|
|
|
1308
1391
|
const context = useKeepUiLabels();
|
|
1309
1392
|
return override ?? context.customLabels?.[key] ?? context.labelResolver?.(key, { locale: context.locale }) ?? context.labels[key];
|
|
1310
1393
|
}
|
|
1394
|
+
function useKeepUiFeedback() {
|
|
1395
|
+
const { emitFeedback } = useKeepUiLabels();
|
|
1396
|
+
return useCallback2((event) => emitFeedback(event), [emitFeedback]);
|
|
1397
|
+
}
|
|
1311
1398
|
|
|
1312
1399
|
// src/hooks/useKeepBackup.ts
|
|
1313
1400
|
function useKeepBackup({ filename, onExport, onImported }) {
|
|
@@ -1732,19 +1819,24 @@ function KeepBulkActions({
|
|
|
1732
1819
|
import {
|
|
1733
1820
|
KeepButton as CoreKeepButton
|
|
1734
1821
|
} from "@keepkit/core/react";
|
|
1735
|
-
import { createElement } from "react";
|
|
1822
|
+
import { createElement, useEffect, useRef as useRef2 } from "react";
|
|
1736
1823
|
|
|
1737
1824
|
// src/hooks/useKeepButton.ts
|
|
1738
1825
|
import { useKeepItem } from "@keepkit/core/react";
|
|
1739
1826
|
function useKeepButton({ item, labels, icons, children }) {
|
|
1740
1827
|
return {
|
|
1741
1828
|
buttonState: useKeepItem(item),
|
|
1829
|
+
emitFeedback: useKeepUiFeedback(),
|
|
1742
1830
|
customStateLabel: labels?.loading !== void 0 || labels?.error !== void 0 || icons !== void 0 && children === void 0,
|
|
1743
1831
|
labels: {
|
|
1744
1832
|
save: useUiLabel("save", typeof labels?.unsaved === "string" ? labels.unsaved : void 0),
|
|
1745
1833
|
saved: useUiLabel("saved", typeof labels?.saved === "string" ? labels.saved : void 0),
|
|
1746
1834
|
loading: useUiLabel("loading", typeof labels?.loading === "string" ? labels.loading : void 0),
|
|
1747
|
-
error: useUiLabel("error", typeof labels?.error === "string" ? labels.error : void 0)
|
|
1835
|
+
error: useUiLabel("error", typeof labels?.error === "string" ? labels.error : void 0),
|
|
1836
|
+
savedMessage: useUiLabel("savedMessage"),
|
|
1837
|
+
removedMessage: useUiLabel("removedMessage"),
|
|
1838
|
+
restoredMessage: useUiLabel("restoredMessage"),
|
|
1839
|
+
undo: useUiLabel("undo")
|
|
1748
1840
|
}
|
|
1749
1841
|
};
|
|
1750
1842
|
}
|
|
@@ -1757,9 +1849,38 @@ function KeepButton({
|
|
|
1757
1849
|
iconOnly = false,
|
|
1758
1850
|
showLabel = true,
|
|
1759
1851
|
iconClassName,
|
|
1852
|
+
onClick,
|
|
1853
|
+
onToggleError,
|
|
1760
1854
|
...props
|
|
1761
1855
|
}) {
|
|
1762
1856
|
const view = useKeepButton({ item: props.item, labels, icons, children: props.children });
|
|
1857
|
+
const pendingToggle = useRef2(null);
|
|
1858
|
+
useEffect(() => {
|
|
1859
|
+
const pending = pendingToggle.current;
|
|
1860
|
+
if (!pending || view.buttonState.isMutating || pending.wasSaved === view.buttonState.isSaved) return;
|
|
1861
|
+
pendingToggle.current = null;
|
|
1862
|
+
if (view.buttonState.isSaved && view.buttonState.item) {
|
|
1863
|
+
view.emitFeedback({ type: "item-saved", item: view.buttonState.item, message: view.labels.savedMessage });
|
|
1864
|
+
return;
|
|
1865
|
+
}
|
|
1866
|
+
if (!pending.item) return;
|
|
1867
|
+
const removedItem = pending.item;
|
|
1868
|
+
view.emitFeedback({
|
|
1869
|
+
type: "item-removed",
|
|
1870
|
+
item: removedItem,
|
|
1871
|
+
message: view.labels.removedMessage,
|
|
1872
|
+
undoLabel: view.labels.undo,
|
|
1873
|
+
undo: async () => {
|
|
1874
|
+
await view.buttonState.save();
|
|
1875
|
+
view.emitFeedback({
|
|
1876
|
+
type: "item-restored",
|
|
1877
|
+
item: removedItem,
|
|
1878
|
+
items: [removedItem],
|
|
1879
|
+
message: view.labels.restoredMessage
|
|
1880
|
+
});
|
|
1881
|
+
}
|
|
1882
|
+
});
|
|
1883
|
+
}, [view]);
|
|
1763
1884
|
const getStateContent = (state) => {
|
|
1764
1885
|
if (typeof props.children === "function") return props.children(state);
|
|
1765
1886
|
if (props.children !== void 0) return props.children;
|
|
@@ -1773,6 +1894,16 @@ function KeepButton({
|
|
|
1773
1894
|
};
|
|
1774
1895
|
const sharedProps = {
|
|
1775
1896
|
...props,
|
|
1897
|
+
onClick: (event) => {
|
|
1898
|
+
onClick?.(event);
|
|
1899
|
+
if (!event.defaultPrevented) {
|
|
1900
|
+
pendingToggle.current = { wasSaved: view.buttonState.isSaved, item: view.buttonState.item };
|
|
1901
|
+
}
|
|
1902
|
+
},
|
|
1903
|
+
onToggleError: (error) => {
|
|
1904
|
+
pendingToggle.current = null;
|
|
1905
|
+
onToggleError?.(error);
|
|
1906
|
+
},
|
|
1776
1907
|
"data-keepkit": "button",
|
|
1777
1908
|
"data-keep-action": "toggle-save",
|
|
1778
1909
|
"data-has-custom-icon": icons ? "true" : void 0,
|
|
@@ -1804,7 +1935,7 @@ import {
|
|
|
1804
1935
|
decodeKeepListQuery,
|
|
1805
1936
|
encodeKeepListQuery
|
|
1806
1937
|
} from "@keepkit/core/core";
|
|
1807
|
-
import { useEffect, useRef as
|
|
1938
|
+
import { useEffect as useEffect2, useRef as useRef3 } from "react";
|
|
1808
1939
|
function createNextPagesRouterAdapter(router) {
|
|
1809
1940
|
const getUrl = () => router.asPath ?? (typeof window === "undefined" ? "/" : window.location.href);
|
|
1810
1941
|
return {
|
|
@@ -1825,13 +1956,13 @@ function useKeepUrlSync({
|
|
|
1825
1956
|
options = {},
|
|
1826
1957
|
adapter: providedAdapter
|
|
1827
1958
|
}) {
|
|
1828
|
-
const browserAdapterRef =
|
|
1959
|
+
const browserAdapterRef = useRef3(getBrowserAdapter());
|
|
1829
1960
|
const adapter = providedAdapter ?? browserAdapterRef.current;
|
|
1830
|
-
const onQueryChangeRef =
|
|
1961
|
+
const onQueryChangeRef = useRef3(onQueryChange);
|
|
1831
1962
|
onQueryChangeRef.current = onQueryChange;
|
|
1832
|
-
const skipWriteRef =
|
|
1963
|
+
const skipWriteRef = useRef3(true);
|
|
1833
1964
|
const params = options.params;
|
|
1834
|
-
|
|
1965
|
+
useEffect2(() => {
|
|
1835
1966
|
if (!enabled) return;
|
|
1836
1967
|
const read = () => {
|
|
1837
1968
|
const url = adapter.getUrl();
|
|
@@ -1848,7 +1979,7 @@ function useKeepUrlSync({
|
|
|
1848
1979
|
read();
|
|
1849
1980
|
return adapter.subscribe?.(read);
|
|
1850
1981
|
}, [adapter, enabled, params]);
|
|
1851
|
-
|
|
1982
|
+
useEffect2(() => {
|
|
1852
1983
|
if (!enabled) return;
|
|
1853
1984
|
if (skipWriteRef.current) {
|
|
1854
1985
|
skipWriteRef.current = false;
|
|
@@ -1968,7 +2099,10 @@ function useKeepListView(query) {
|
|
|
1968
2099
|
|
|
1969
2100
|
// src/KeepItemCard.tsx
|
|
1970
2101
|
import {
|
|
1971
|
-
|
|
2102
|
+
createContext as createContext2,
|
|
2103
|
+
createElement as createElement2,
|
|
2104
|
+
isValidElement as isValidElement2,
|
|
2105
|
+
useContext as useContext2
|
|
1972
2106
|
} from "react";
|
|
1973
2107
|
|
|
1974
2108
|
// src/hooks/useKeepItemCard.ts
|
|
@@ -1986,6 +2120,10 @@ function useKeepItemCard(options) {
|
|
|
1986
2120
|
onRemoved
|
|
1987
2121
|
} = options;
|
|
1988
2122
|
const itemState = useKeepItem2(item);
|
|
2123
|
+
const emitFeedback = useKeepUiFeedback();
|
|
2124
|
+
const removedMessage = useUiLabel("removedMessage");
|
|
2125
|
+
const restoredMessage = useUiLabel("restoredMessage");
|
|
2126
|
+
const undoLabel = useUiLabel("undo");
|
|
1989
2127
|
const resolvedTitle = typeof title === "function" ? title(item) : title ?? getTitle?.(item) ?? getMetaTitle(item.meta) ?? item.id;
|
|
1990
2128
|
const imageProps = getImageProps?.(item, resolvedTitle);
|
|
1991
2129
|
const href = typeof hrefOption === "function" ? hrefOption(item) : hrefOption;
|
|
@@ -1993,12 +2131,32 @@ function useKeepItemCard(options) {
|
|
|
1993
2131
|
const isExternalLink = href ? /^(?:[a-z][a-z\d+.-]*:|\/\/)/i.test(href) : false;
|
|
1994
2132
|
const statusLabelKey = item.status && item.status !== "available" ? getStatusLabelKey(item.status) : "statusUnknown";
|
|
1995
2133
|
const unavailableLabel = useUiLabel(statusLabelKey);
|
|
2134
|
+
const remove = async () => {
|
|
2135
|
+
const wasSaved = itemState.isSaved;
|
|
2136
|
+
try {
|
|
2137
|
+
await itemState.removeWithUndo();
|
|
2138
|
+
onRemoved?.(item);
|
|
2139
|
+
if (!wasSaved) return;
|
|
2140
|
+
emitFeedback({
|
|
2141
|
+
type: "item-removed",
|
|
2142
|
+
item,
|
|
2143
|
+
message: removedMessage,
|
|
2144
|
+
undoLabel,
|
|
2145
|
+
undo: async () => {
|
|
2146
|
+
await itemState.undo();
|
|
2147
|
+
emitFeedback({ type: "item-restored", item, items: [item], message: restoredMessage });
|
|
2148
|
+
}
|
|
2149
|
+
});
|
|
2150
|
+
} catch (cause) {
|
|
2151
|
+
onRemoveError?.(cause);
|
|
2152
|
+
}
|
|
2153
|
+
};
|
|
1996
2154
|
const state = {
|
|
1997
2155
|
item,
|
|
1998
2156
|
isSaved: itemState.isSaved,
|
|
1999
2157
|
isMutating: itemState.isMutating,
|
|
2000
2158
|
error: itemState.error,
|
|
2001
|
-
remove
|
|
2159
|
+
remove,
|
|
2002
2160
|
status: item.status
|
|
2003
2161
|
};
|
|
2004
2162
|
return {
|
|
@@ -2012,14 +2170,7 @@ function useKeepItemCard(options) {
|
|
|
2012
2170
|
resolvedLinkTarget: linkTargetAttribute ?? (isExternalLink ? "_blank" : void 0),
|
|
2013
2171
|
resolvedLinkRel: linkRel ?? (isExternalLink ? "noreferrer" : void 0),
|
|
2014
2172
|
statusLabel: item.status && item.status !== "available" ? unavailableLabel : void 0,
|
|
2015
|
-
remove
|
|
2016
|
-
try {
|
|
2017
|
-
await itemState.remove();
|
|
2018
|
-
onRemoved?.(item);
|
|
2019
|
-
} catch (cause) {
|
|
2020
|
-
onRemoveError?.(cause);
|
|
2021
|
-
}
|
|
2022
|
-
},
|
|
2173
|
+
remove,
|
|
2023
2174
|
labels: {
|
|
2024
2175
|
save: useUiLabel("save"),
|
|
2025
2176
|
savedAt: useUiLabel("saved"),
|
|
@@ -2055,6 +2206,10 @@ import { useKeepContext as useKeepContext2 } from "@keepkit/core/react";
|
|
|
2055
2206
|
import { useState as useState4 } from "react";
|
|
2056
2207
|
function useKeepStaleNotice({ item, onRetry, onRemoved }) {
|
|
2057
2208
|
const context = useKeepContext2();
|
|
2209
|
+
const emitFeedback = useKeepUiFeedback();
|
|
2210
|
+
const removedMessage = useUiLabel("removedMessage");
|
|
2211
|
+
const restoredMessage = useUiLabel("restoredMessage");
|
|
2212
|
+
const undoLabel = useUiLabel("undo");
|
|
2058
2213
|
const [isRetrying, setIsRetrying] = useState4(false);
|
|
2059
2214
|
const [error, setError] = useState4(null);
|
|
2060
2215
|
async function retry() {
|
|
@@ -2073,6 +2228,16 @@ function useKeepStaleNotice({ item, onRetry, onRemoved }) {
|
|
|
2073
2228
|
try {
|
|
2074
2229
|
await context.removeItemWithUndo(item.id);
|
|
2075
2230
|
onRemoved?.(item);
|
|
2231
|
+
emitFeedback({
|
|
2232
|
+
type: "item-removed",
|
|
2233
|
+
item,
|
|
2234
|
+
message: removedMessage,
|
|
2235
|
+
undoLabel,
|
|
2236
|
+
undo: async () => {
|
|
2237
|
+
await context.undoLastRemoval();
|
|
2238
|
+
emitFeedback({ type: "item-restored", item, items: [item], message: restoredMessage });
|
|
2239
|
+
}
|
|
2240
|
+
});
|
|
2076
2241
|
} catch (cause) {
|
|
2077
2242
|
setError(cause);
|
|
2078
2243
|
}
|
|
@@ -2093,15 +2258,34 @@ function useKeepStaleNotice({ item, onRetry, onRemoved }) {
|
|
|
2093
2258
|
}
|
|
2094
2259
|
function useKeepPruneStale({ statuses, onPruned }) {
|
|
2095
2260
|
const context = useKeepContext2();
|
|
2096
|
-
const
|
|
2261
|
+
const emitFeedback = useKeepUiFeedback();
|
|
2262
|
+
const staleItems = context.items.filter((item) => item.status && statuses.includes(item.status));
|
|
2263
|
+
const staleIds = staleItems.map((item) => item.id);
|
|
2264
|
+
const restoredMessage = useUiLabel("restoredMessage");
|
|
2265
|
+
const prunedMessage = useUiLabel("stalePrunedMessage");
|
|
2266
|
+
const undoLabel = useUiLabel("undo");
|
|
2097
2267
|
return {
|
|
2098
2268
|
staleIds,
|
|
2099
2269
|
isMutating: context.isMutating,
|
|
2100
2270
|
label: useUiLabel("pruneStale"),
|
|
2101
2271
|
prune: async () => {
|
|
2102
2272
|
const ids = [...staleIds];
|
|
2273
|
+
const items = [...staleItems];
|
|
2103
2274
|
await context.removeItemsWithUndo(ids);
|
|
2104
2275
|
onPruned?.(ids);
|
|
2276
|
+
if (items.length > 0) {
|
|
2277
|
+
emitFeedback({
|
|
2278
|
+
type: "stale-pruned",
|
|
2279
|
+
item: items[0],
|
|
2280
|
+
items,
|
|
2281
|
+
message: prunedMessage,
|
|
2282
|
+
undoLabel,
|
|
2283
|
+
undo: async () => {
|
|
2284
|
+
await context.undoLastRemoval();
|
|
2285
|
+
emitFeedback({ type: "item-restored", item: items[0], items, message: restoredMessage });
|
|
2286
|
+
}
|
|
2287
|
+
});
|
|
2288
|
+
}
|
|
2105
2289
|
}
|
|
2106
2290
|
};
|
|
2107
2291
|
}
|
|
@@ -2220,7 +2404,13 @@ function KeepPruneStaleButton({
|
|
|
2220
2404
|
|
|
2221
2405
|
// src/KeepItemCard.tsx
|
|
2222
2406
|
import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
2223
|
-
|
|
2407
|
+
var KeepItemCardContext = createContext2(null);
|
|
2408
|
+
function useKeepItemCardCompound(part) {
|
|
2409
|
+
const context = useContext2(KeepItemCardContext);
|
|
2410
|
+
if (!context) throw new Error(`KeepItemCard.${part} must be rendered inside KeepItemCard.`);
|
|
2411
|
+
return context;
|
|
2412
|
+
}
|
|
2413
|
+
function KeepItemCardRoot({
|
|
2224
2414
|
item,
|
|
2225
2415
|
title,
|
|
2226
2416
|
getTitle,
|
|
@@ -2272,21 +2462,26 @@ function KeepItemCard({
|
|
|
2272
2462
|
};
|
|
2273
2463
|
return LinkComponent ? /* @__PURE__ */ jsx9(LinkComponent, { ...linkProps }) : /* @__PURE__ */ jsx9("a", { ...linkProps });
|
|
2274
2464
|
}
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2465
|
+
function renderTitle(content) {
|
|
2466
|
+
if (linkTarget !== "title") return content;
|
|
2467
|
+
if (view.isAvailable) return renderLink(content);
|
|
2468
|
+
return view.href ? /* @__PURE__ */ jsx9("span", { "aria-disabled": "true", "data-link-disabled": "true", children: content }) : content;
|
|
2469
|
+
}
|
|
2470
|
+
const resolvedImageProps = view.imageProps ? { ...view.imageProps, alt: imageAlt ?? view.imageProps.alt } : void 0;
|
|
2471
|
+
const image = resolvedImageProps ? renderImage?.(resolvedImageProps, item) ?? (ImageComponent ? /* @__PURE__ */ jsx9(ImageComponent, { ...resolvedImageProps }) : /* @__PURE__ */ jsx9("img", { ...resolvedImageProps, alt: resolvedImageProps.alt })) : null;
|
|
2472
|
+
const tags = showTags ? item.tags ?? [] : [];
|
|
2473
|
+
const renderedTags = showTags && tags.length > 0 ? renderTags?.(tags, item) ?? null : null;
|
|
2474
|
+
const meta = showSavedAt ? /* @__PURE__ */ jsxs5("div", { "data-card-meta": true, children: [
|
|
2475
|
+
/* @__PURE__ */ jsxs5("span", { children: [
|
|
2476
|
+
view.labels.savedAt,
|
|
2477
|
+
":"
|
|
2478
|
+
] }),
|
|
2479
|
+
" ",
|
|
2480
|
+
/* @__PURE__ */ jsx9("time", { dateTime: new Date(item.savedAt).toISOString(), children: formatSavedAt(item.savedAt) })
|
|
2481
|
+
] }) : null;
|
|
2482
|
+
const error = view.itemState.error ? /* @__PURE__ */ jsx9("p", { role: "alert", children: getErrorMessage2(view.itemState.error, view.labels.error) }) : null;
|
|
2483
|
+
const actions = view.statusLabel ? /* @__PURE__ */ jsx9(KeepStaleNotice, { item, onRetry, onRemoved }) : /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
2484
|
+
showSaveButton ? /* @__PURE__ */ jsx9(
|
|
2290
2485
|
KeepButton,
|
|
2291
2486
|
{
|
|
2292
2487
|
item: toKeepButtonItem(item),
|
|
@@ -2294,7 +2489,7 @@ function KeepItemCard({
|
|
|
2294
2489
|
getAriaLabel: (buttonState) => `${buttonState.isSaved ? view.labels.remove : view.labels.save} ${String(view.resolvedTitle)}`
|
|
2295
2490
|
}
|
|
2296
2491
|
) : null,
|
|
2297
|
-
|
|
2492
|
+
/* @__PURE__ */ jsx9(
|
|
2298
2493
|
"button",
|
|
2299
2494
|
{
|
|
2300
2495
|
type: "button",
|
|
@@ -2303,10 +2498,28 @@ function KeepItemCard({
|
|
|
2303
2498
|
disabled: view.itemState.isMutating,
|
|
2304
2499
|
children: removeLabel ?? view.labels.remove
|
|
2305
2500
|
}
|
|
2306
|
-
)
|
|
2501
|
+
)
|
|
2502
|
+
] });
|
|
2503
|
+
const compoundValue = {
|
|
2504
|
+
resolvedTitle: view.resolvedTitle,
|
|
2505
|
+
renderTitle,
|
|
2506
|
+
image,
|
|
2507
|
+
fallbackLabel: String(view.resolvedTitle),
|
|
2508
|
+
tags,
|
|
2509
|
+
tagsLabel: view.labels.tags,
|
|
2510
|
+
renderedTags,
|
|
2511
|
+
meta,
|
|
2512
|
+
error,
|
|
2513
|
+
actions
|
|
2514
|
+
};
|
|
2515
|
+
const defaultBody = /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
2516
|
+
/* @__PURE__ */ jsx9(KeepItemCardMedia, {}),
|
|
2517
|
+
/* @__PURE__ */ jsx9(KeepItemCardContent, {}),
|
|
2518
|
+
/* @__PURE__ */ jsx9(KeepItemCardActions, {})
|
|
2307
2519
|
] });
|
|
2520
|
+
const body = render ? render(view.state) : typeof contentChildren === "function" ? contentChildren(view.state) : contentChildren ?? defaultBody;
|
|
2308
2521
|
const linkedBody = linkTarget === "card" && view.isAvailable ? renderLink(body) : body;
|
|
2309
|
-
|
|
2522
|
+
const root = renderRoot(
|
|
2310
2523
|
asChild,
|
|
2311
2524
|
isValidElement2(children) ? children : void 0,
|
|
2312
2525
|
{
|
|
@@ -2323,6 +2536,54 @@ function KeepItemCard({
|
|
|
2323
2536
|
linkedBody,
|
|
2324
2537
|
"KeepItemCard"
|
|
2325
2538
|
);
|
|
2539
|
+
return /* @__PURE__ */ jsx9(KeepItemCardContext.Provider, { value: compoundValue, children: root });
|
|
2540
|
+
}
|
|
2541
|
+
function KeepItemCardMedia({ children, fallback, ...props }) {
|
|
2542
|
+
const context = useKeepItemCardCompound("Media");
|
|
2543
|
+
return /* @__PURE__ */ jsx9("div", { ...props, "data-keep-card-part": "media", children: children ?? context.image ?? /* @__PURE__ */ jsx9("span", { role: "img", "aria-label": context.fallbackLabel, "data-keep-card-fallback": "true", children: fallback ?? context.fallbackLabel.slice(0, 1) }) });
|
|
2544
|
+
}
|
|
2545
|
+
function KeepItemCardContent({ children, ...props }) {
|
|
2546
|
+
const context = useKeepItemCardCompound("Content");
|
|
2547
|
+
return /* @__PURE__ */ jsx9("div", { ...props, "data-keep-card-part": "content", children: children ?? /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
2548
|
+
/* @__PURE__ */ jsx9(KeepItemCardTitle, {}),
|
|
2549
|
+
context.meta,
|
|
2550
|
+
/* @__PURE__ */ jsx9(KeepItemCardTags, {}),
|
|
2551
|
+
context.error
|
|
2552
|
+
] }) });
|
|
2553
|
+
}
|
|
2554
|
+
function KeepItemCardTitle({ as = "h3", children, ...props }) {
|
|
2555
|
+
const context = useKeepItemCardCompound("Title");
|
|
2556
|
+
return createElement2(
|
|
2557
|
+
as,
|
|
2558
|
+
{ ...props, "data-keep-card-part": "title" },
|
|
2559
|
+
context.renderTitle(children ?? context.resolvedTitle)
|
|
2560
|
+
);
|
|
2561
|
+
}
|
|
2562
|
+
function KeepItemCardTags({ children, ...props }) {
|
|
2563
|
+
const context = useKeepItemCardCompound("Tags");
|
|
2564
|
+
if (children === void 0 && context.renderedTags) return context.renderedTags;
|
|
2565
|
+
if (children === void 0 && context.tags.length === 0) return null;
|
|
2566
|
+
return /* @__PURE__ */ jsx9("ul", { ...props, "aria-label": props["aria-label"] ?? context.tagsLabel, "data-keep-card-part": "tags", children: children ?? context.tags.map((tag) => /* @__PURE__ */ jsx9("li", { children: tag }, tag)) });
|
|
2567
|
+
}
|
|
2568
|
+
function KeepItemCardActions({ children, ...props }) {
|
|
2569
|
+
const context = useKeepItemCardCompound("Actions");
|
|
2570
|
+
return /* @__PURE__ */ jsx9("div", { ...props, "data-keep-card-part": "actions", children: children ?? context.actions });
|
|
2571
|
+
}
|
|
2572
|
+
var KeepItemCard = Object.assign(KeepItemCardRoot, {
|
|
2573
|
+
Media: KeepItemCardMedia,
|
|
2574
|
+
Content: KeepItemCardContent,
|
|
2575
|
+
Title: KeepItemCardTitle,
|
|
2576
|
+
Tags: KeepItemCardTags,
|
|
2577
|
+
Actions: KeepItemCardActions
|
|
2578
|
+
});
|
|
2579
|
+
function KeepItemCardSkeleton({ layout = "list", ...props }) {
|
|
2580
|
+
return /* @__PURE__ */ jsxs5("article", { ...props, "aria-hidden": "true", "data-keepkit": "card-skeleton", "data-layout": layout, "data-state": "loading", children: [
|
|
2581
|
+
/* @__PURE__ */ jsx9("span", { "data-skeleton-part": "media" }),
|
|
2582
|
+
/* @__PURE__ */ jsx9("span", { "data-skeleton-part": "title" }),
|
|
2583
|
+
/* @__PURE__ */ jsx9("span", { "data-skeleton-part": "meta" }),
|
|
2584
|
+
/* @__PURE__ */ jsx9("span", { "data-skeleton-part": "tag" }),
|
|
2585
|
+
/* @__PURE__ */ jsx9("span", { "data-skeleton-part": "tag" })
|
|
2586
|
+
] });
|
|
2326
2587
|
}
|
|
2327
2588
|
function formatSavedAt(timestamp) {
|
|
2328
2589
|
return new Date(timestamp).toISOString().slice(0, 10);
|
|
@@ -2332,7 +2593,7 @@ function getErrorMessage2(error, fallback) {
|
|
|
2332
2593
|
}
|
|
2333
2594
|
|
|
2334
2595
|
// src/KeepList.tsx
|
|
2335
|
-
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
2596
|
+
import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2336
2597
|
function KeepList(props) {
|
|
2337
2598
|
const { fallback, onBoundaryError, boundaryResetKey, ...listProps } = props;
|
|
2338
2599
|
const content = /* @__PURE__ */ jsx10(KeepListContent, { ...listProps });
|
|
@@ -2344,6 +2605,8 @@ function KeepListContent({
|
|
|
2344
2605
|
children,
|
|
2345
2606
|
renderItem,
|
|
2346
2607
|
loading,
|
|
2608
|
+
renderLoading,
|
|
2609
|
+
loadingCount = 6,
|
|
2347
2610
|
empty,
|
|
2348
2611
|
error: errorContent,
|
|
2349
2612
|
itemCardProps,
|
|
@@ -2357,7 +2620,9 @@ function KeepListContent({
|
|
|
2357
2620
|
const body = getListBody(state, {
|
|
2358
2621
|
children,
|
|
2359
2622
|
renderItem,
|
|
2360
|
-
loading:
|
|
2623
|
+
loading: renderLoading !== void 0 ? renderLoading : loading,
|
|
2624
|
+
loadingCount,
|
|
2625
|
+
loadingLabel: view.labels.loading,
|
|
2361
2626
|
empty: empty ?? view.labels.empty,
|
|
2362
2627
|
error: errorContent ?? view.labels.error,
|
|
2363
2628
|
itemCardProps,
|
|
@@ -2387,7 +2652,17 @@ function getListState(state) {
|
|
|
2387
2652
|
}
|
|
2388
2653
|
function getListBody(state, options) {
|
|
2389
2654
|
if (state.error && state.items.length === 0) return resolveContent(options.error, state);
|
|
2390
|
-
if (state.isLoading && !state.isHydrated)
|
|
2655
|
+
if (state.isLoading && !state.isHydrated) {
|
|
2656
|
+
if (options.loading !== void 0) return resolveContent(options.loading, state);
|
|
2657
|
+
const count = Number.isFinite(options.loadingCount) ? Math.max(0, Math.floor(options.loadingCount)) : 6;
|
|
2658
|
+
return /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
2659
|
+
/* @__PURE__ */ jsx10("span", { role: "status", "data-keepkit": "loading-label", children: options.loadingLabel }),
|
|
2660
|
+
/* @__PURE__ */ jsx10("ul", { "data-keepkit": "skeleton-list", "data-layout": options.layout, children: Array.from({ length: count }, (_, index) => (
|
|
2661
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: Static loading placeholders never reorder.
|
|
2662
|
+
/* @__PURE__ */ jsx10("li", { children: /* @__PURE__ */ jsx10(KeepItemCardSkeleton, { layout: options.layout }) }, index)
|
|
2663
|
+
)) })
|
|
2664
|
+
] });
|
|
2665
|
+
}
|
|
2391
2666
|
if (state.isHydrated && state.items.length === 0) return resolveContent(options.empty, state);
|
|
2392
2667
|
if (typeof options.children === "function") return options.children(state);
|
|
2393
2668
|
if (options.children !== void 0 && !isValidElement3(options.children)) return options.children;
|
|
@@ -2401,7 +2676,7 @@ import { isValidElement as isValidElement4 } from "react";
|
|
|
2401
2676
|
|
|
2402
2677
|
// src/hooks/useKeepTagFilter.ts
|
|
2403
2678
|
import { useKeepList as useKeepList4 } from "@keepkit/core/react";
|
|
2404
|
-
import { useCallback, useMemo as useMemo3, useState as useState5 } from "react";
|
|
2679
|
+
import { useCallback as useCallback3, useMemo as useMemo3, useState as useState5 } from "react";
|
|
2405
2680
|
function useKeepTagFilter(options) {
|
|
2406
2681
|
const { query, controlledValue, defaultValue, onChange, onValueChange } = options;
|
|
2407
2682
|
const [uncontrolledValue, setUncontrolledValue] = useState5(defaultValue);
|
|
@@ -2410,7 +2685,7 @@ function useKeepTagFilter(options) {
|
|
|
2410
2685
|
...query,
|
|
2411
2686
|
tags: resolvedValue ? [...query?.tags ?? [], resolvedValue] : query?.tags
|
|
2412
2687
|
});
|
|
2413
|
-
const select =
|
|
2688
|
+
const select = useCallback3(
|
|
2414
2689
|
(tag) => {
|
|
2415
2690
|
if (controlledValue === void 0) setUncontrolledValue(tag);
|
|
2416
2691
|
onChange?.(tag);
|
|
@@ -2430,7 +2705,7 @@ function useKeepTagFilter(options) {
|
|
|
2430
2705
|
}
|
|
2431
2706
|
|
|
2432
2707
|
// src/KeepTagFilter.tsx
|
|
2433
|
-
import { jsx as jsx11, jsxs as
|
|
2708
|
+
import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2434
2709
|
function KeepTagFilter({
|
|
2435
2710
|
query,
|
|
2436
2711
|
value: controlledValue,
|
|
@@ -2448,7 +2723,7 @@ function KeepTagFilter({
|
|
|
2448
2723
|
}) {
|
|
2449
2724
|
const view = useKeepTagFilter({ query, controlledValue, defaultValue, onChange, onValueChange });
|
|
2450
2725
|
const contentChildren = asChild && isValidElement4(children) ? void 0 : children;
|
|
2451
|
-
const body = render ? render(view.state) : typeof contentChildren === "function" ? contentChildren(view.state) : contentChildren ?? /* @__PURE__ */
|
|
2726
|
+
const body = render ? render(view.state) : typeof contentChildren === "function" ? contentChildren(view.state) : contentChildren ?? /* @__PURE__ */ jsxs7("fieldset", { children: [
|
|
2452
2727
|
/* @__PURE__ */ jsx11("legend", { children: ariaLabel ?? view.labels.aria }),
|
|
2453
2728
|
/* @__PURE__ */ jsx11(
|
|
2454
2729
|
"button",
|
|
@@ -2460,7 +2735,7 @@ function KeepTagFilter({
|
|
|
2460
2735
|
children: allLabel ?? view.labels.all
|
|
2461
2736
|
}
|
|
2462
2737
|
),
|
|
2463
|
-
view.state.tags.map((tag) => /* @__PURE__ */
|
|
2738
|
+
view.state.tags.map((tag) => /* @__PURE__ */ jsxs7(
|
|
2464
2739
|
"button",
|
|
2465
2740
|
{
|
|
2466
2741
|
type: "button",
|
|
@@ -2469,7 +2744,7 @@ function KeepTagFilter({
|
|
|
2469
2744
|
onClick: () => view.state.select(tag),
|
|
2470
2745
|
children: [
|
|
2471
2746
|
renderTag ? renderTag(tag, view.state.tagCounts[tag] ?? 0, view.state.value === tag) : tag,
|
|
2472
|
-
/* @__PURE__ */
|
|
2747
|
+
/* @__PURE__ */ jsxs7("span", { children: [
|
|
2473
2748
|
" (",
|
|
2474
2749
|
view.state.tagCounts[tag] ?? 0,
|
|
2475
2750
|
")"
|
|
@@ -2495,12 +2770,12 @@ function KeepTagFilter({
|
|
|
2495
2770
|
}
|
|
2496
2771
|
|
|
2497
2772
|
// src/hooks/useQueryControls.ts
|
|
2498
|
-
import { useEffect as
|
|
2773
|
+
import { useEffect as useEffect3, useState as useState6 } from "react";
|
|
2499
2774
|
function useKeepSearchInput(options) {
|
|
2500
2775
|
const { controlledValue, defaultValue, debounceMs, onValueChange } = options;
|
|
2501
2776
|
const [uncontrolledValue, setUncontrolledValue] = useState6(defaultValue);
|
|
2502
2777
|
const value = controlledValue ?? uncontrolledValue;
|
|
2503
|
-
|
|
2778
|
+
useEffect3(() => {
|
|
2504
2779
|
if (!onValueChange) return;
|
|
2505
2780
|
if (debounceMs <= 0) {
|
|
2506
2781
|
onValueChange(value);
|
|
@@ -2567,7 +2842,7 @@ function getVisiblePages(currentPage, pageCount, maxPageButtons) {
|
|
|
2567
2842
|
}
|
|
2568
2843
|
|
|
2569
2844
|
// src/query-controls.tsx
|
|
2570
|
-
import { Fragment as
|
|
2845
|
+
import { Fragment as Fragment5, jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2571
2846
|
function KeepSearchInput({
|
|
2572
2847
|
value: controlledValue,
|
|
2573
2848
|
defaultValue = "",
|
|
@@ -2603,7 +2878,7 @@ function KeepSortSelect({
|
|
|
2603
2878
|
...props
|
|
2604
2879
|
}) {
|
|
2605
2880
|
const view = useKeepSortSelect({ controlledValue, defaultValue, onValueChange });
|
|
2606
|
-
const options = children ?? /* @__PURE__ */
|
|
2881
|
+
const options = children ?? /* @__PURE__ */ jsxs8(Fragment5, { children: [
|
|
2607
2882
|
/* @__PURE__ */ jsx12("option", { value: "updatedAt:desc", children: view.labels.updatedNewest }),
|
|
2608
2883
|
/* @__PURE__ */ jsx12("option", { value: "updatedAt:asc", children: view.labels.updatedOldest }),
|
|
2609
2884
|
/* @__PURE__ */ jsx12("option", { value: "savedAt:desc", children: view.labels.savedNewest }),
|
|
@@ -2642,7 +2917,7 @@ function KeepPagination({
|
|
|
2642
2917
|
};
|
|
2643
2918
|
if (render)
|
|
2644
2919
|
return /* @__PURE__ */ jsx12("nav", { ...navProps, children: render({ page: view.currentPage, pageCount: view.pageCount, goToPage: view.goToPage }) });
|
|
2645
|
-
return /* @__PURE__ */
|
|
2920
|
+
return /* @__PURE__ */ jsxs8("nav", { ...navProps, children: [
|
|
2646
2921
|
/* @__PURE__ */ jsx12(
|
|
2647
2922
|
"button",
|
|
2648
2923
|
{
|
|
@@ -2679,7 +2954,7 @@ function KeepPagination({
|
|
|
2679
2954
|
}
|
|
2680
2955
|
|
|
2681
2956
|
// src/KeepCollection.tsx
|
|
2682
|
-
import { jsx as jsx13, jsxs as
|
|
2957
|
+
import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2683
2958
|
function KeepCollection(props) {
|
|
2684
2959
|
const { fallback, onBoundaryError, boundaryResetKey, ...collectionProps } = props;
|
|
2685
2960
|
const content = /* @__PURE__ */ jsx13(KeepCollectionContent, { ...collectionProps });
|
|
@@ -2696,13 +2971,15 @@ function KeepCollectionContent({
|
|
|
2696
2971
|
renderItem,
|
|
2697
2972
|
itemCardProps,
|
|
2698
2973
|
loading,
|
|
2974
|
+
renderLoading,
|
|
2975
|
+
loadingCount,
|
|
2699
2976
|
empty,
|
|
2700
2977
|
error,
|
|
2701
2978
|
className,
|
|
2702
2979
|
...rootProps
|
|
2703
2980
|
}) {
|
|
2704
2981
|
const view = useKeepCollection({ query, pageSize, urlSync, urlAdapter, features });
|
|
2705
|
-
return /* @__PURE__ */
|
|
2982
|
+
return /* @__PURE__ */ jsxs9(
|
|
2706
2983
|
"section",
|
|
2707
2984
|
{
|
|
2708
2985
|
...rootProps,
|
|
@@ -2713,7 +2990,7 @@ function KeepCollectionContent({
|
|
|
2713
2990
|
"data-state": getCollectionState(view.list),
|
|
2714
2991
|
"data-loading": view.list.isLoading || view.list.isMutating ? "true" : void 0,
|
|
2715
2992
|
children: [
|
|
2716
|
-
/* @__PURE__ */
|
|
2993
|
+
/* @__PURE__ */ jsxs9("div", { children: [
|
|
2717
2994
|
view.enabled.search ? /* @__PURE__ */ jsx13(KeepSearchInput, { value: view.searchValue, onValueChange: view.setSearchValue }) : null,
|
|
2718
2995
|
view.enabled.sort ? /* @__PURE__ */ jsx13(KeepSortSelect, { value: view.sortValue, onValueChange: view.setSortValue }) : null,
|
|
2719
2996
|
view.enabled.tagFilter ? /* @__PURE__ */ jsx13(KeepTagFilter, { query, value: view.tag, onValueChange: view.setTag }) : null
|
|
@@ -2726,6 +3003,8 @@ function KeepCollectionContent({
|
|
|
2726
3003
|
itemCardProps,
|
|
2727
3004
|
layout,
|
|
2728
3005
|
loading,
|
|
3006
|
+
renderLoading,
|
|
3007
|
+
loadingCount,
|
|
2729
3008
|
empty,
|
|
2730
3009
|
error
|
|
2731
3010
|
}
|
|
@@ -2762,16 +3041,16 @@ import { isValidElement as isValidElement5 } from "react";
|
|
|
2762
3041
|
|
|
2763
3042
|
// src/hooks/useKeepNoteEditor.ts
|
|
2764
3043
|
import { useKeepItem as useKeepItem3 } from "@keepkit/core/react";
|
|
2765
|
-
import { useCallback as
|
|
3044
|
+
import { useCallback as useCallback4, useEffect as useEffect4, useRef as useRef4, useState as useState7 } from "react";
|
|
2766
3045
|
function useKeepNoteEditor({ item, debounceMs, onSaved, onSaveError }) {
|
|
2767
3046
|
const itemState = useKeepItem3(item);
|
|
2768
3047
|
const { error, isMutating, item: savedItem, updateNote } = itemState;
|
|
2769
3048
|
const [note, setNote] = useState7(item.note ?? "");
|
|
2770
3049
|
const baselineNote = savedItem?.note ?? item.note ?? "";
|
|
2771
3050
|
const isDirty = note !== baselineNote;
|
|
2772
|
-
const lastSavedNoteRef =
|
|
2773
|
-
|
|
2774
|
-
const save =
|
|
3051
|
+
const lastSavedNoteRef = useRef4(void 0);
|
|
3052
|
+
useEffect4(() => setNote(baselineNote), [baselineNote]);
|
|
3053
|
+
const save = useCallback4(async () => {
|
|
2775
3054
|
const nextNote = note.trim() || void 0;
|
|
2776
3055
|
try {
|
|
2777
3056
|
await updateNote(nextNote);
|
|
@@ -2782,7 +3061,7 @@ function useKeepNoteEditor({ item, debounceMs, onSaved, onSaveError }) {
|
|
|
2782
3061
|
throw cause;
|
|
2783
3062
|
}
|
|
2784
3063
|
}, [note, onSaveError, onSaved, updateNote]);
|
|
2785
|
-
|
|
3064
|
+
useEffect4(() => {
|
|
2786
3065
|
if (!isDirty || debounceMs <= 0 || lastSavedNoteRef.current === note) return;
|
|
2787
3066
|
const timer = window.setTimeout(() => void save().catch(() => void 0), debounceMs);
|
|
2788
3067
|
return () => window.clearTimeout(timer);
|
|
@@ -2817,7 +3096,7 @@ function useKeepNoteEditor({ item, debounceMs, onSaved, onSaveError }) {
|
|
|
2817
3096
|
}
|
|
2818
3097
|
|
|
2819
3098
|
// src/KeepNoteEditor.tsx
|
|
2820
|
-
import { Fragment as
|
|
3099
|
+
import { Fragment as Fragment6, jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2821
3100
|
function KeepNoteEditor({
|
|
2822
3101
|
item,
|
|
2823
3102
|
label,
|
|
@@ -2835,8 +3114,8 @@ function KeepNoteEditor({
|
|
|
2835
3114
|
const view = useKeepNoteEditor({ item, debounceMs, onSaved, onSaveError });
|
|
2836
3115
|
const { error, isDirty, isSaving, note, setNote } = view.state;
|
|
2837
3116
|
const contentChildren = asChild && isValidElement5(children) ? void 0 : children;
|
|
2838
|
-
const body = render ? render(view.state) : typeof contentChildren === "function" ? contentChildren(view.state) : contentChildren ?? /* @__PURE__ */
|
|
2839
|
-
/* @__PURE__ */
|
|
3117
|
+
const body = render ? render(view.state) : typeof contentChildren === "function" ? contentChildren(view.state) : contentChildren ?? /* @__PURE__ */ jsxs10(Fragment6, { children: [
|
|
3118
|
+
/* @__PURE__ */ jsxs10("label", { children: [
|
|
2840
3119
|
label ?? view.labels.note,
|
|
2841
3120
|
/* @__PURE__ */ jsx15(
|
|
2842
3121
|
"textarea",
|
|
@@ -2853,7 +3132,7 @@ function KeepNoteEditor({
|
|
|
2853
3132
|
/* @__PURE__ */ jsx15("button", { type: "submit", "data-keep-action": "save-note", disabled: isSaving, "aria-busy": isSaving, children: saveLabel ?? view.labels.save })
|
|
2854
3133
|
] });
|
|
2855
3134
|
if (!asChild) {
|
|
2856
|
-
return /* @__PURE__ */
|
|
3135
|
+
return /* @__PURE__ */ jsxs10(
|
|
2857
3136
|
"form",
|
|
2858
3137
|
{
|
|
2859
3138
|
...formProps,
|
|
@@ -2892,18 +3171,46 @@ function getErrorMessage3(error, fallback) {
|
|
|
2892
3171
|
return error instanceof Error ? error.message : fallback;
|
|
2893
3172
|
}
|
|
2894
3173
|
|
|
2895
|
-
// src/hooks/
|
|
3174
|
+
// src/hooks/useKeepSyncFeedback.ts
|
|
2896
3175
|
import { useKeepContext as useKeepContext3 } from "@keepkit/core/react";
|
|
2897
|
-
import { useEffect as
|
|
3176
|
+
import { useEffect as useEffect5, useRef as useRef5 } from "react";
|
|
3177
|
+
function useKeepSyncFeedback() {
|
|
3178
|
+
const { syncState } = useKeepContext3();
|
|
3179
|
+
const emitFeedback = useKeepUiFeedback();
|
|
3180
|
+
const completedMessage = useUiLabel("syncSynced");
|
|
3181
|
+
const failedMessage = useUiLabel("syncFailedMessage");
|
|
3182
|
+
const previousStatus = useRef5("idle");
|
|
3183
|
+
useEffect5(() => {
|
|
3184
|
+
const previous = previousStatus.current;
|
|
3185
|
+
previousStatus.current = syncState.status;
|
|
3186
|
+
if (syncState.status === "error" && previous !== "error") {
|
|
3187
|
+
emitFeedback({ type: "sync-failed", error: syncState.error, message: failedMessage });
|
|
3188
|
+
return;
|
|
3189
|
+
}
|
|
3190
|
+
if (syncState.status === "synced" && (previous === "pending" || previous === "syncing" || previous === "conflict" || previous === "error")) {
|
|
3191
|
+
emitFeedback({ type: "sync-completed", message: completedMessage });
|
|
3192
|
+
}
|
|
3193
|
+
}, [completedMessage, emitFeedback, failedMessage, syncState.error, syncState.status]);
|
|
3194
|
+
}
|
|
3195
|
+
|
|
3196
|
+
// src/KeepSyncFeedbackObserver.tsx
|
|
3197
|
+
function KeepSyncFeedbackObserver() {
|
|
3198
|
+
useKeepSyncFeedback();
|
|
3199
|
+
return null;
|
|
3200
|
+
}
|
|
3201
|
+
|
|
3202
|
+
// src/hooks/useKeepSyncRecoveryDialog.ts
|
|
3203
|
+
import { useKeepContext as useKeepContext4 } from "@keepkit/core/react";
|
|
3204
|
+
import { useEffect as useEffect6, useState as useState8 } from "react";
|
|
2898
3205
|
function useKeepSyncRecoveryDialog(options) {
|
|
2899
3206
|
const { open, onOpenChange, conflicts, onManualMerge } = options;
|
|
2900
|
-
const context =
|
|
3207
|
+
const context = useKeepContext4();
|
|
2901
3208
|
const conflictList = conflicts ?? context.syncState.conflicts ?? [];
|
|
2902
3209
|
const hasRecovery = conflictList.length > 0 || context.syncState.status === "error" || Boolean(context.error);
|
|
2903
3210
|
const [dismissed, setDismissed] = useState8(false);
|
|
2904
3211
|
const [busyId, setBusyId] = useState8();
|
|
2905
3212
|
const [error, setError] = useState8();
|
|
2906
|
-
|
|
3213
|
+
useEffect6(() => {
|
|
2907
3214
|
if (hasRecovery) setDismissed(false);
|
|
2908
3215
|
}, [hasRecovery]);
|
|
2909
3216
|
return {
|
|
@@ -2948,7 +3255,7 @@ function useKeepSyncRecoveryDialog(options) {
|
|
|
2948
3255
|
}
|
|
2949
3256
|
|
|
2950
3257
|
// src/KeepSyncRecoveryDialog.tsx
|
|
2951
|
-
import { jsx as jsx16, jsxs as
|
|
3258
|
+
import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2952
3259
|
function KeepSyncRecoveryDialog({
|
|
2953
3260
|
open,
|
|
2954
3261
|
onOpenChange,
|
|
@@ -2963,7 +3270,7 @@ function KeepSyncRecoveryDialog({
|
|
|
2963
3270
|
}) {
|
|
2964
3271
|
const view = useKeepSyncRecoveryDialog({ open, onOpenChange, conflicts, onManualMerge });
|
|
2965
3272
|
if (!view.isOpen) return null;
|
|
2966
|
-
return /* @__PURE__ */
|
|
3273
|
+
return /* @__PURE__ */ jsxs11(
|
|
2967
3274
|
"section",
|
|
2968
3275
|
{
|
|
2969
3276
|
...props,
|
|
@@ -2977,16 +3284,16 @@ function KeepSyncRecoveryDialog({
|
|
|
2977
3284
|
"data-state": view.conflictList.length > 0 ? "conflict" : "error",
|
|
2978
3285
|
"data-loading": view.busyId !== void 0 ? "true" : void 0,
|
|
2979
3286
|
children: [
|
|
2980
|
-
/* @__PURE__ */
|
|
3287
|
+
/* @__PURE__ */ jsxs11("header", { children: [
|
|
2981
3288
|
/* @__PURE__ */ jsx16("h2", { id: "keepkit-sync-recovery-title", children: title ?? view.labels.title }),
|
|
2982
3289
|
/* @__PURE__ */ jsx16("button", { type: "button", "data-keep-action": "close-dialog", onClick: view.close, "aria-label": view.labels.close, children: view.labels.close })
|
|
2983
3290
|
] }),
|
|
2984
3291
|
children,
|
|
2985
|
-
view.conflictList.length > 0 ? /* @__PURE__ */
|
|
3292
|
+
view.conflictList.length > 0 ? /* @__PURE__ */ jsxs11("div", { children: [
|
|
2986
3293
|
/* @__PURE__ */ jsx16("p", { children: view.labels.conflict }),
|
|
2987
|
-
view.conflictList.map((conflict) => /* @__PURE__ */
|
|
3294
|
+
view.conflictList.map((conflict) => /* @__PURE__ */ jsxs11("article", { "data-conflict-id": conflict.id, children: [
|
|
2988
3295
|
/* @__PURE__ */ jsx16("h3", { children: getMetaTitle(conflict.operation.item?.meta) ?? conflict.id }),
|
|
2989
|
-
/* @__PURE__ */
|
|
3296
|
+
/* @__PURE__ */ jsxs11("div", { "data-conflict-preview": true, children: [
|
|
2990
3297
|
/* @__PURE__ */ jsx16(
|
|
2991
3298
|
ConflictPreview,
|
|
2992
3299
|
{
|
|
@@ -3008,7 +3315,7 @@ function KeepSyncRecoveryDialog({
|
|
|
3008
3315
|
}
|
|
3009
3316
|
)
|
|
3010
3317
|
] }),
|
|
3011
|
-
/* @__PURE__ */
|
|
3318
|
+
/* @__PURE__ */ jsxs11("div", { children: [
|
|
3012
3319
|
/* @__PURE__ */ jsx16(
|
|
3013
3320
|
"button",
|
|
3014
3321
|
{
|
|
@@ -3042,7 +3349,7 @@ function KeepSyncRecoveryDialog({
|
|
|
3042
3349
|
] })
|
|
3043
3350
|
] }, conflict.id))
|
|
3044
3351
|
] }) : null,
|
|
3045
|
-
view.showBackupRecovery ? /* @__PURE__ */
|
|
3352
|
+
view.showBackupRecovery ? /* @__PURE__ */ jsxs11("section", { "data-recovery": "backup", children: [
|
|
3046
3353
|
/* @__PURE__ */ jsx16("h3", { children: view.labels.backupRecovery }),
|
|
3047
3354
|
/* @__PURE__ */ jsx16("p", { children: view.labels.backupRecoveryDescription }),
|
|
3048
3355
|
backup ?? (showBackupControls ? /* @__PURE__ */ jsx16(KeepBackup, {}) : null)
|
|
@@ -3059,14 +3366,14 @@ function ConflictPreview({
|
|
|
3059
3366
|
noteLabel,
|
|
3060
3367
|
side
|
|
3061
3368
|
}) {
|
|
3062
|
-
return /* @__PURE__ */
|
|
3369
|
+
return /* @__PURE__ */ jsxs11("article", { "data-conflict-version": side, "aria-label": heading, children: [
|
|
3063
3370
|
/* @__PURE__ */ jsx16("h4", { children: heading }),
|
|
3064
|
-
/* @__PURE__ */
|
|
3065
|
-
/* @__PURE__ */
|
|
3371
|
+
/* @__PURE__ */ jsxs11("dl", { children: [
|
|
3372
|
+
/* @__PURE__ */ jsxs11("div", { children: [
|
|
3066
3373
|
/* @__PURE__ */ jsx16("dt", { children: updatedAtLabel }),
|
|
3067
3374
|
/* @__PURE__ */ jsx16("dd", { children: item ? /* @__PURE__ */ jsx16("time", { dateTime: new Date(item.updatedAt).toISOString(), children: formatConflictDate(item.updatedAt) }) : "\u2014" })
|
|
3068
3375
|
] }),
|
|
3069
|
-
/* @__PURE__ */
|
|
3376
|
+
/* @__PURE__ */ jsxs11("div", { children: [
|
|
3070
3377
|
/* @__PURE__ */ jsx16("dt", { children: noteLabel }),
|
|
3071
3378
|
/* @__PURE__ */ jsx16("dd", { children: item?.note || "\u2014" })
|
|
3072
3379
|
] })
|
|
@@ -3078,9 +3385,9 @@ function formatConflictDate(timestamp) {
|
|
|
3078
3385
|
}
|
|
3079
3386
|
|
|
3080
3387
|
// src/hooks/useKeepSyncStatusBanner.ts
|
|
3081
|
-
import { useKeepContext as
|
|
3388
|
+
import { useKeepContext as useKeepContext5 } from "@keepkit/core/react";
|
|
3082
3389
|
function useKeepSyncStatusBanner({ onRetry, children }) {
|
|
3083
|
-
const context =
|
|
3390
|
+
const context = useKeepContext5();
|
|
3084
3391
|
const retryLabel = useUiLabel("retrySync");
|
|
3085
3392
|
const resolveLabel = useUiLabel("resolveSync");
|
|
3086
3393
|
const conflictLabel = useUiLabel("syncConflict");
|
|
@@ -3112,7 +3419,7 @@ function getErrorMessage4(error) {
|
|
|
3112
3419
|
}
|
|
3113
3420
|
|
|
3114
3421
|
// src/KeepSyncStatusBanner.tsx
|
|
3115
|
-
import { jsx as jsx17, jsxs as
|
|
3422
|
+
import { jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3116
3423
|
function KeepSyncStatusBanner({
|
|
3117
3424
|
onRetry,
|
|
3118
3425
|
onResolveConflicts,
|
|
@@ -3122,7 +3429,7 @@ function KeepSyncStatusBanner({
|
|
|
3122
3429
|
}) {
|
|
3123
3430
|
const view = useKeepSyncStatusBanner({ onRetry, children });
|
|
3124
3431
|
if (view.status === "idle" && !view.hasConflicts) return null;
|
|
3125
|
-
return /* @__PURE__ */
|
|
3432
|
+
return /* @__PURE__ */ jsxs12(
|
|
3126
3433
|
"aside",
|
|
3127
3434
|
{
|
|
3128
3435
|
...props,
|
|
@@ -3160,13 +3467,13 @@ function KeepSyncStatusBanner({
|
|
|
3160
3467
|
|
|
3161
3468
|
// src/hooks/useKeepTagEditor.ts
|
|
3162
3469
|
import { useKeepItem as useKeepItem4 } from "@keepkit/core/react";
|
|
3163
|
-
import { useCallback as
|
|
3470
|
+
import { useCallback as useCallback5, useEffect as useEffect7, useState as useState9 } from "react";
|
|
3164
3471
|
function useKeepTagEditor({ item, onSaved, onSaveError }) {
|
|
3165
3472
|
const itemState = useKeepItem4(item);
|
|
3166
3473
|
const [tags, setTags] = useState9(item.tags ?? []);
|
|
3167
3474
|
const [input, setInput] = useState9("");
|
|
3168
|
-
|
|
3169
|
-
const save =
|
|
3475
|
+
useEffect7(() => setTags(itemState.item?.tags ?? item.tags ?? []), [item.tags, itemState.item?.tags]);
|
|
3476
|
+
const save = useCallback5(async () => {
|
|
3170
3477
|
const nextTags = normalizeUiTags(tags);
|
|
3171
3478
|
try {
|
|
3172
3479
|
await itemState.updateTags(nextTags);
|
|
@@ -3212,7 +3519,7 @@ function useKeepTagEditor({ item, onSaved, onSaveError }) {
|
|
|
3212
3519
|
}
|
|
3213
3520
|
|
|
3214
3521
|
// src/KeepTagEditor.tsx
|
|
3215
|
-
import { Fragment as
|
|
3522
|
+
import { Fragment as Fragment7, jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
3216
3523
|
function KeepTagEditor({
|
|
3217
3524
|
item,
|
|
3218
3525
|
availableTags = [],
|
|
@@ -3223,8 +3530,8 @@ function KeepTagEditor({
|
|
|
3223
3530
|
}) {
|
|
3224
3531
|
const view = useKeepTagEditor({ item, onSaved, onSaveError });
|
|
3225
3532
|
const { isSaving, tags } = view.state;
|
|
3226
|
-
const body = render ? render(view.state) : /* @__PURE__ */
|
|
3227
|
-
/* @__PURE__ */
|
|
3533
|
+
const body = render ? render(view.state) : /* @__PURE__ */ jsxs13(Fragment7, { children: [
|
|
3534
|
+
/* @__PURE__ */ jsxs13("label", { children: [
|
|
3228
3535
|
view.labels.tags,
|
|
3229
3536
|
/* @__PURE__ */ jsx18(
|
|
3230
3537
|
"input",
|
|
@@ -3238,13 +3545,13 @@ function KeepTagEditor({
|
|
|
3238
3545
|
)
|
|
3239
3546
|
] }),
|
|
3240
3547
|
availableTags.length > 0 ? /* @__PURE__ */ jsx18("datalist", { id: `keep-tags-${item.id}`, children: availableTags.map((tag) => /* @__PURE__ */ jsx18("option", { value: tag }, tag)) }) : null,
|
|
3241
|
-
/* @__PURE__ */ jsx18("ul", { "aria-label": view.labels.tags, children: tags.map((tag) => /* @__PURE__ */
|
|
3548
|
+
/* @__PURE__ */ jsx18("ul", { "aria-label": view.labels.tags, children: tags.map((tag) => /* @__PURE__ */ jsxs13("li", { children: [
|
|
3242
3549
|
tag,
|
|
3243
3550
|
/* @__PURE__ */ jsx18("button", { type: "button", "data-keep-action": "remove-tag", onClick: () => view.removeTag(tag), children: view.labels.remove })
|
|
3244
3551
|
] }, tag)) }),
|
|
3245
3552
|
/* @__PURE__ */ jsx18("button", { type: "submit", "data-keep-action": "apply-tags", disabled: isSaving, "aria-busy": isSaving, children: view.labels.apply })
|
|
3246
3553
|
] });
|
|
3247
|
-
return /* @__PURE__ */
|
|
3554
|
+
return /* @__PURE__ */ jsxs13(
|
|
3248
3555
|
"form",
|
|
3249
3556
|
{
|
|
3250
3557
|
...props,
|
|
@@ -3266,23 +3573,31 @@ function getErrorMessage5(error, fallback) {
|
|
|
3266
3573
|
}
|
|
3267
3574
|
|
|
3268
3575
|
// src/hooks/useKeepUndo.ts
|
|
3269
|
-
import { useKeepContext as
|
|
3576
|
+
import { useKeepContext as useKeepContext6 } from "@keepkit/core/react";
|
|
3270
3577
|
function useKeepUndo() {
|
|
3271
|
-
const context =
|
|
3578
|
+
const context = useKeepContext6();
|
|
3579
|
+
const emitFeedback = useKeepUiFeedback();
|
|
3580
|
+
const restoredMessage = useUiLabel("restoredMessage");
|
|
3272
3581
|
return {
|
|
3273
3582
|
canUndo: context.undo.canUndo,
|
|
3274
|
-
undo: () =>
|
|
3583
|
+
undo: async () => {
|
|
3584
|
+
const items = context.lastChange?.items ?? (context.lastChange?.item ? [context.lastChange.item] : []);
|
|
3585
|
+
await context.undoLastRemoval();
|
|
3586
|
+
if (items.length > 0) {
|
|
3587
|
+
emitFeedback({ type: "item-restored", item: items[0], items, message: restoredMessage });
|
|
3588
|
+
}
|
|
3589
|
+
},
|
|
3275
3590
|
message: useUiLabel("undoAvailable"),
|
|
3276
3591
|
label: useUiLabel("undo")
|
|
3277
3592
|
};
|
|
3278
3593
|
}
|
|
3279
3594
|
|
|
3280
3595
|
// src/KeepUndo.tsx
|
|
3281
|
-
import { jsx as jsx19, jsxs as
|
|
3596
|
+
import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
3282
3597
|
function KeepUndo({ children, label, ...props }) {
|
|
3283
3598
|
const view = useKeepUndo();
|
|
3284
3599
|
if (!view.canUndo) return null;
|
|
3285
|
-
return /* @__PURE__ */
|
|
3600
|
+
return /* @__PURE__ */ jsxs14("div", { ...props, role: "status", "aria-live": "polite", "data-keepkit": "undo", "data-state": "available", children: [
|
|
3286
3601
|
children ?? view.message,
|
|
3287
3602
|
/* @__PURE__ */ jsx19("button", { type: "button", "data-keep-action": "undo", onClick: () => void view.undo(), children: label ?? view.label })
|
|
3288
3603
|
] });
|
|
@@ -3292,13 +3607,13 @@ function KeepUndo({ children, label, ...props }) {
|
|
|
3292
3607
|
import { isValidElement as isValidElement6 } from "react";
|
|
3293
3608
|
|
|
3294
3609
|
// src/hooks/useStatusViews.ts
|
|
3295
|
-
import { useKeepContext as
|
|
3296
|
-
import { useEffect as
|
|
3610
|
+
import { useKeepContext as useKeepContext7 } from "@keepkit/core/react";
|
|
3611
|
+
import { useEffect as useEffect8, useRef as useRef6, useState as useState10 } from "react";
|
|
3297
3612
|
function useKeepEmptyState() {
|
|
3298
3613
|
return useUiLabel("noItems").replace(/\.$/, "");
|
|
3299
3614
|
}
|
|
3300
3615
|
function useKeepStatus(status) {
|
|
3301
|
-
const context =
|
|
3616
|
+
const context = useKeepContext7();
|
|
3302
3617
|
const resolvedStatus = status ?? getDerivedStatus(context);
|
|
3303
3618
|
const state = {
|
|
3304
3619
|
status: resolvedStatus,
|
|
@@ -3309,13 +3624,13 @@ function useKeepStatus(status) {
|
|
|
3309
3624
|
return { state, defaultLabel: useUiLabel(getStatusLabelKey3(resolvedStatus)) };
|
|
3310
3625
|
}
|
|
3311
3626
|
function useKeepAnnouncements(messages) {
|
|
3312
|
-
const context =
|
|
3627
|
+
const context = useKeepContext7();
|
|
3313
3628
|
const savedMessage = useUiLabel("savedMessage", messages?.save);
|
|
3314
3629
|
const removedMessage = useUiLabel("removedMessage", messages?.remove);
|
|
3315
3630
|
const noteSavedMessage = useUiLabel("noteSavedMessage", messages?.note);
|
|
3316
3631
|
const [message, setMessage] = useState10("");
|
|
3317
|
-
const lastChangeRef =
|
|
3318
|
-
|
|
3632
|
+
const lastChangeRef = useRef6(void 0);
|
|
3633
|
+
useEffect8(() => {
|
|
3319
3634
|
const change = context.lastChange;
|
|
3320
3635
|
if (!change || change === lastChangeRef.current) return;
|
|
3321
3636
|
lastChangeRef.current = change;
|
|
@@ -3343,7 +3658,7 @@ function getStatusLabelKey3(status) {
|
|
|
3343
3658
|
}
|
|
3344
3659
|
|
|
3345
3660
|
// src/status.tsx
|
|
3346
|
-
import { Fragment as
|
|
3661
|
+
import { Fragment as Fragment8, jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
3347
3662
|
function KeepEmptyState({
|
|
3348
3663
|
title,
|
|
3349
3664
|
description,
|
|
@@ -3355,7 +3670,7 @@ function KeepEmptyState({
|
|
|
3355
3670
|
}) {
|
|
3356
3671
|
const defaultTitle = useKeepEmptyState();
|
|
3357
3672
|
const contentChildren = asChild && isValidElement6(children) ? void 0 : children;
|
|
3358
|
-
const body = contentChildren ?? /* @__PURE__ */
|
|
3673
|
+
const body = contentChildren ?? /* @__PURE__ */ jsxs15(Fragment8, { children: [
|
|
3359
3674
|
/* @__PURE__ */ jsx20("h2", { children: title ?? defaultTitle }),
|
|
3360
3675
|
description ? /* @__PURE__ */ jsx20("p", { children: description }) : null,
|
|
3361
3676
|
action
|
|
@@ -3483,7 +3798,7 @@ import { createAuthenticatedSyncKit } from "@keepkit/core/core";
|
|
|
3483
3798
|
import {
|
|
3484
3799
|
KeepErrorBoundary as KeepErrorBoundary3,
|
|
3485
3800
|
KeepProvider,
|
|
3486
|
-
useKeepContext as
|
|
3801
|
+
useKeepContext as useKeepContext8,
|
|
3487
3802
|
useKeepItem as useKeepItem5,
|
|
3488
3803
|
useKeepList as useKeepList5,
|
|
3489
3804
|
useKeepShortcut
|
|
@@ -3498,11 +3813,12 @@ import {
|
|
|
3498
3813
|
LocalStorageSyncQueueAdapter,
|
|
3499
3814
|
SyncStorageAdapter
|
|
3500
3815
|
} from "@keepkit/core/storage";
|
|
3501
|
-
import { jsx as jsx22, jsxs as
|
|
3816
|
+
import { jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
3502
3817
|
function KeepKitProvider({
|
|
3503
3818
|
labels,
|
|
3504
3819
|
locale,
|
|
3505
3820
|
labelResolver,
|
|
3821
|
+
onFeedback,
|
|
3506
3822
|
theme,
|
|
3507
3823
|
mode,
|
|
3508
3824
|
density,
|
|
@@ -3517,7 +3833,7 @@ function KeepKitProvider({
|
|
|
3517
3833
|
children,
|
|
3518
3834
|
...providerProps
|
|
3519
3835
|
}) {
|
|
3520
|
-
return /* @__PURE__ */ jsx22(KeepUiProvider, { labels, locale, labelResolver, children: /* @__PURE__ */ jsx22(
|
|
3836
|
+
return /* @__PURE__ */ jsx22(KeepUiProvider, { labels, locale, labelResolver, onFeedback, children: /* @__PURE__ */ jsx22(
|
|
3521
3837
|
KeepThemeProvider,
|
|
3522
3838
|
{
|
|
3523
3839
|
theme,
|
|
@@ -3531,7 +3847,8 @@ function KeepKitProvider({
|
|
|
3531
3847
|
className: themeClassName,
|
|
3532
3848
|
style: themeStyle,
|
|
3533
3849
|
asChild: themeAsChild,
|
|
3534
|
-
children: /* @__PURE__ */
|
|
3850
|
+
children: /* @__PURE__ */ jsxs16(CoreKeepProvider, { ...providerProps, children: [
|
|
3851
|
+
/* @__PURE__ */ jsx22(KeepSyncFeedbackObserver, {}),
|
|
3535
3852
|
children,
|
|
3536
3853
|
/* @__PURE__ */ jsx22(KeepAnnouncements, {})
|
|
3537
3854
|
] })
|
|
@@ -3543,6 +3860,7 @@ function createKeepKit(options = {}) {
|
|
|
3543
3860
|
labels,
|
|
3544
3861
|
locale,
|
|
3545
3862
|
labelResolver,
|
|
3863
|
+
onFeedback,
|
|
3546
3864
|
theme,
|
|
3547
3865
|
mode,
|
|
3548
3866
|
density,
|
|
@@ -3566,6 +3884,7 @@ function createKeepKit(options = {}) {
|
|
|
3566
3884
|
labels,
|
|
3567
3885
|
locale,
|
|
3568
3886
|
labelResolver,
|
|
3887
|
+
onFeedback,
|
|
3569
3888
|
theme,
|
|
3570
3889
|
mode,
|
|
3571
3890
|
density,
|
|
@@ -3611,6 +3930,7 @@ export {
|
|
|
3611
3930
|
KeepEmptyState,
|
|
3612
3931
|
KeepErrorBoundary3 as KeepErrorBoundary,
|
|
3613
3932
|
KeepItemCard,
|
|
3933
|
+
KeepItemCardSkeleton,
|
|
3614
3934
|
KeepItemCheckbox,
|
|
3615
3935
|
KeepItemStatusBadge,
|
|
3616
3936
|
KeepKitProvider,
|
|
@@ -3643,10 +3963,11 @@ export {
|
|
|
3643
3963
|
isAllSelected,
|
|
3644
3964
|
keepThemeNames,
|
|
3645
3965
|
toggleSelectAll,
|
|
3646
|
-
|
|
3966
|
+
useKeepContext8 as useKeepContext,
|
|
3647
3967
|
useKeepItem5 as useKeepItem,
|
|
3648
3968
|
useKeepList5 as useKeepList,
|
|
3649
3969
|
useKeepShortcut,
|
|
3970
|
+
useKeepToastFeedback,
|
|
3650
3971
|
useKeepUiLabels,
|
|
3651
3972
|
useKeepUrlSync
|
|
3652
3973
|
};
|