@keepkit/ui 0.8.0 → 0.10.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 +24 -0
- package/dist/index.d.ts +38 -9
- package/dist/index.js +439 -182
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -6,12 +6,176 @@ import {
|
|
|
6
6
|
createKeepKit as createCoreKeepKit
|
|
7
7
|
} from "@keepkit/core/react";
|
|
8
8
|
|
|
9
|
+
// src/KeepBackup.tsx
|
|
10
|
+
import { useKeepContext } from "@keepkit/core/react";
|
|
11
|
+
import { useRef, useState } from "react";
|
|
12
|
+
|
|
13
|
+
// src/ui-context.tsx
|
|
14
|
+
import { createContext, useContext, useMemo } from "react";
|
|
15
|
+
import { jsx } from "react/jsx-runtime";
|
|
16
|
+
var DEFAULT_LABELS = {
|
|
17
|
+
save: "Save",
|
|
18
|
+
saved: "Saved",
|
|
19
|
+
remove: "Remove",
|
|
20
|
+
loading: "Loading\u2026",
|
|
21
|
+
saving: "Saving\u2026",
|
|
22
|
+
syncing: "Syncing\u2026",
|
|
23
|
+
error: "Something went wrong.",
|
|
24
|
+
allTags: "All",
|
|
25
|
+
filterTags: "Filter saved items by tag",
|
|
26
|
+
note: "Note",
|
|
27
|
+
saveNote: "Save note",
|
|
28
|
+
noItems: "No saved items.",
|
|
29
|
+
loadingItems: "Loading saved items\u2026",
|
|
30
|
+
errorItems: "Could not load saved items.",
|
|
31
|
+
search: "Search saved items",
|
|
32
|
+
sort: "Sort saved items",
|
|
33
|
+
newest: "Newest first",
|
|
34
|
+
oldest: "Oldest first",
|
|
35
|
+
savedNewest: "Saved newest first",
|
|
36
|
+
savedOldest: "Saved oldest first",
|
|
37
|
+
updatedNewest: "Updated newest first",
|
|
38
|
+
updatedOldest: "Updated oldest first",
|
|
39
|
+
previousPage: "Previous page",
|
|
40
|
+
nextPage: "Next page",
|
|
41
|
+
pagination: "Pagination",
|
|
42
|
+
page: "Page",
|
|
43
|
+
selectItems: "Select saved items",
|
|
44
|
+
selectedCount: "selected",
|
|
45
|
+
deleteSelected: "Delete selected",
|
|
46
|
+
tagsToApply: "Tags to apply",
|
|
47
|
+
applyTags: "Apply tags",
|
|
48
|
+
savedMessage: "Item saved.",
|
|
49
|
+
removedMessage: "Item removed.",
|
|
50
|
+
noteSavedMessage: "Note saved.",
|
|
51
|
+
exportData: "Export JSON",
|
|
52
|
+
importData: "Import JSON",
|
|
53
|
+
importMode: "Import mode",
|
|
54
|
+
merge: "Merge",
|
|
55
|
+
replace: "Replace",
|
|
56
|
+
importedCount: "items imported",
|
|
57
|
+
failedCount: "items failed",
|
|
58
|
+
storageQuotaError: "Storage is full. Free space and try again.",
|
|
59
|
+
statusExpired: "Expired",
|
|
60
|
+
statusRemoved: "Removed",
|
|
61
|
+
statusDeleted: "Deleted",
|
|
62
|
+
statusPrivate: "Private",
|
|
63
|
+
statusUnknown: "Unavailable"
|
|
64
|
+
};
|
|
65
|
+
var KeepUiLabelsContext = createContext({ labels: DEFAULT_LABELS });
|
|
66
|
+
function KeepUiProvider({ labels, locale, labelResolver, children }) {
|
|
67
|
+
const value = useMemo(() => {
|
|
68
|
+
const resolved = { ...DEFAULT_LABELS, ...labels };
|
|
69
|
+
return { locale, labels: resolved, labelResolver };
|
|
70
|
+
}, [labelResolver, labels, locale]);
|
|
71
|
+
return /* @__PURE__ */ jsx(KeepUiLabelsContext.Provider, { value, children });
|
|
72
|
+
}
|
|
73
|
+
function useKeepUiLabels() {
|
|
74
|
+
return useContext(KeepUiLabelsContext);
|
|
75
|
+
}
|
|
76
|
+
function useUiLabel(key, override) {
|
|
77
|
+
const context = useKeepUiLabels();
|
|
78
|
+
return override ?? context.labelResolver?.(key, { locale: context.locale }) ?? context.labels[key];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/KeepBackup.tsx
|
|
82
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
83
|
+
function KeepBackup({
|
|
84
|
+
filename = "keepkit-backup.json",
|
|
85
|
+
onExport,
|
|
86
|
+
onImported,
|
|
87
|
+
...props
|
|
88
|
+
}) {
|
|
89
|
+
const context = useKeepContext();
|
|
90
|
+
const exportLabel = useUiLabel("exportData");
|
|
91
|
+
const importLabel = useUiLabel("importData");
|
|
92
|
+
const importModeLabel = useUiLabel("importMode");
|
|
93
|
+
const mergeLabel = useUiLabel("merge");
|
|
94
|
+
const replaceLabel = useUiLabel("replace");
|
|
95
|
+
const importedCountLabel = useUiLabel("importedCount");
|
|
96
|
+
const failedCountLabel = useUiLabel("failedCount");
|
|
97
|
+
const quotaErrorLabel = useUiLabel("storageQuotaError");
|
|
98
|
+
const inputRef = useRef(null);
|
|
99
|
+
const [mode, setMode] = useState("merge");
|
|
100
|
+
const [result, setResult] = useState();
|
|
101
|
+
const [error, setError] = useState();
|
|
102
|
+
async function handleExport() {
|
|
103
|
+
setError(void 0);
|
|
104
|
+
try {
|
|
105
|
+
const data = await context.exportBackup();
|
|
106
|
+
onExport?.(data);
|
|
107
|
+
if (typeof document === "undefined") return;
|
|
108
|
+
const url = URL.createObjectURL(new Blob([data], { type: "application/json" }));
|
|
109
|
+
const anchor = document.createElement("a");
|
|
110
|
+
anchor.href = url;
|
|
111
|
+
anchor.download = filename;
|
|
112
|
+
anchor.click();
|
|
113
|
+
URL.revokeObjectURL(url);
|
|
114
|
+
} catch (cause) {
|
|
115
|
+
setError(cause);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async function handleImport(event) {
|
|
119
|
+
const file = event.currentTarget.files?.[0];
|
|
120
|
+
event.currentTarget.value = "";
|
|
121
|
+
if (!file) return;
|
|
122
|
+
setError(void 0);
|
|
123
|
+
setResult(void 0);
|
|
124
|
+
try {
|
|
125
|
+
const imported = await context.importBackup(await file.text(), { mode });
|
|
126
|
+
setResult(imported);
|
|
127
|
+
onImported?.(imported);
|
|
128
|
+
} catch (cause) {
|
|
129
|
+
setError(cause);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return /* @__PURE__ */ jsxs("section", { ...props, "data-state": error ? "error" : result ? "complete" : "idle", children: [
|
|
133
|
+
/* @__PURE__ */ jsx2("button", { type: "button", onClick: () => void handleExport(), disabled: context.isMutating, children: exportLabel }),
|
|
134
|
+
/* @__PURE__ */ jsxs("label", { children: [
|
|
135
|
+
importModeLabel,
|
|
136
|
+
/* @__PURE__ */ jsxs("select", { value: mode, onChange: (event) => setMode(event.currentTarget.value), children: [
|
|
137
|
+
/* @__PURE__ */ jsx2("option", { value: "merge", children: mergeLabel }),
|
|
138
|
+
/* @__PURE__ */ jsx2("option", { value: "replace", children: replaceLabel })
|
|
139
|
+
] })
|
|
140
|
+
] }),
|
|
141
|
+
/* @__PURE__ */ jsx2("button", { type: "button", onClick: () => inputRef.current?.click(), disabled: context.isMutating, children: importLabel }),
|
|
142
|
+
/* @__PURE__ */ jsx2(
|
|
143
|
+
"input",
|
|
144
|
+
{
|
|
145
|
+
ref: inputRef,
|
|
146
|
+
type: "file",
|
|
147
|
+
accept: "application/json,.json",
|
|
148
|
+
"aria-label": importLabel,
|
|
149
|
+
onChange: (event) => void handleImport(event)
|
|
150
|
+
}
|
|
151
|
+
),
|
|
152
|
+
result ? /* @__PURE__ */ jsxs("p", { role: "status", children: [
|
|
153
|
+
result.imported,
|
|
154
|
+
" ",
|
|
155
|
+
importedCountLabel,
|
|
156
|
+
"; ",
|
|
157
|
+
result.failed,
|
|
158
|
+
" ",
|
|
159
|
+
failedCountLabel
|
|
160
|
+
] }) : null,
|
|
161
|
+
error ? /* @__PURE__ */ jsx2("p", { role: "alert", children: isQuotaError(error) ? quotaErrorLabel : getErrorMessage(error) }) : null
|
|
162
|
+
] });
|
|
163
|
+
}
|
|
164
|
+
function isQuotaError(error) {
|
|
165
|
+
if (error instanceof Error && error.name === "KeepStorageQuotaError") return true;
|
|
166
|
+
if (error && typeof error === "object" && "cause" in error) return isQuotaError(error.cause);
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
function getErrorMessage(error) {
|
|
170
|
+
return error instanceof Error ? error.message : "Something went wrong.";
|
|
171
|
+
}
|
|
172
|
+
|
|
9
173
|
// src/KeepBulkActions.tsx
|
|
10
174
|
import { useKeepList } from "@keepkit/core/react";
|
|
11
|
-
import { useState } from "react";
|
|
175
|
+
import { useState as useState2 } from "react";
|
|
12
176
|
|
|
13
177
|
// src/KeepItemCheckbox.tsx
|
|
14
|
-
import { jsx } from "react/jsx-runtime";
|
|
178
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
15
179
|
function KeepItemCheckbox({
|
|
16
180
|
item,
|
|
17
181
|
checked = false,
|
|
@@ -22,12 +186,14 @@ function KeepItemCheckbox({
|
|
|
22
186
|
}) {
|
|
23
187
|
const itemLabel = getItemLabel(item) ?? item.id;
|
|
24
188
|
const accessibleLabel = ariaLabel ?? (typeof label === "string" ? label : itemLabel);
|
|
25
|
-
return /* @__PURE__ */
|
|
189
|
+
return /* @__PURE__ */ jsx3(
|
|
26
190
|
"input",
|
|
27
191
|
{
|
|
28
192
|
...props,
|
|
29
193
|
type: "checkbox",
|
|
30
194
|
checked,
|
|
195
|
+
"data-state": checked ? "checked" : "unchecked",
|
|
196
|
+
"data-disabled": props.disabled ? "true" : void 0,
|
|
31
197
|
"aria-label": accessibleLabel,
|
|
32
198
|
onChange: (event) => onCheckedChange?.(event.currentTarget.checked)
|
|
33
199
|
}
|
|
@@ -44,7 +210,7 @@ import {
|
|
|
44
210
|
cloneElement,
|
|
45
211
|
isValidElement
|
|
46
212
|
} from "react";
|
|
47
|
-
import { jsx as
|
|
213
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
48
214
|
function toKeepButtonItem(item) {
|
|
49
215
|
return {
|
|
50
216
|
id: item.id,
|
|
@@ -73,66 +239,11 @@ function renderRoot(asChild, child, props, body, componentName) {
|
|
|
73
239
|
if (!isValidElement(child)) throw new Error(`${componentName} with asChild requires a single React element child.`);
|
|
74
240
|
return cloneElement(child, { ...props, children: body });
|
|
75
241
|
}
|
|
76
|
-
return /* @__PURE__ */
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// src/ui-context.tsx
|
|
80
|
-
import { createContext, useContext, useMemo } from "react";
|
|
81
|
-
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
82
|
-
var DEFAULT_LABELS = {
|
|
83
|
-
save: "Save",
|
|
84
|
-
saved: "Saved",
|
|
85
|
-
remove: "Remove",
|
|
86
|
-
loading: "Loading\u2026",
|
|
87
|
-
saving: "Saving\u2026",
|
|
88
|
-
syncing: "Syncing\u2026",
|
|
89
|
-
error: "Something went wrong.",
|
|
90
|
-
allTags: "All",
|
|
91
|
-
filterTags: "Filter saved items by tag",
|
|
92
|
-
note: "Note",
|
|
93
|
-
saveNote: "Save note",
|
|
94
|
-
noItems: "No saved items.",
|
|
95
|
-
loadingItems: "Loading saved items\u2026",
|
|
96
|
-
errorItems: "Could not load saved items.",
|
|
97
|
-
search: "Search saved items",
|
|
98
|
-
sort: "Sort saved items",
|
|
99
|
-
newest: "Newest first",
|
|
100
|
-
oldest: "Oldest first",
|
|
101
|
-
savedNewest: "Saved newest first",
|
|
102
|
-
savedOldest: "Saved oldest first",
|
|
103
|
-
updatedNewest: "Updated newest first",
|
|
104
|
-
updatedOldest: "Updated oldest first",
|
|
105
|
-
previousPage: "Previous page",
|
|
106
|
-
nextPage: "Next page",
|
|
107
|
-
pagination: "Pagination",
|
|
108
|
-
page: "Page",
|
|
109
|
-
selectItems: "Select saved items",
|
|
110
|
-
selectedCount: "selected",
|
|
111
|
-
deleteSelected: "Delete selected",
|
|
112
|
-
tagsToApply: "Tags to apply",
|
|
113
|
-
applyTags: "Apply tags",
|
|
114
|
-
savedMessage: "Item saved.",
|
|
115
|
-
removedMessage: "Item removed.",
|
|
116
|
-
noteSavedMessage: "Note saved."
|
|
117
|
-
};
|
|
118
|
-
var KeepUiLabelsContext = createContext({ labels: DEFAULT_LABELS });
|
|
119
|
-
function KeepUiProvider({ labels, locale, labelResolver, children }) {
|
|
120
|
-
const value = useMemo(() => {
|
|
121
|
-
const resolved = { ...DEFAULT_LABELS, ...labels };
|
|
122
|
-
return { locale, labels: resolved, labelResolver };
|
|
123
|
-
}, [labelResolver, labels, locale]);
|
|
124
|
-
return /* @__PURE__ */ jsx3(KeepUiLabelsContext.Provider, { value, children });
|
|
125
|
-
}
|
|
126
|
-
function useKeepUiLabels() {
|
|
127
|
-
return useContext(KeepUiLabelsContext);
|
|
128
|
-
}
|
|
129
|
-
function useUiLabel(key, override) {
|
|
130
|
-
const context = useKeepUiLabels();
|
|
131
|
-
return override ?? context.labelResolver?.(key, { locale: context.locale }) ?? context.labels[key];
|
|
242
|
+
return /* @__PURE__ */ jsx4("div", { ...props, children: body });
|
|
132
243
|
}
|
|
133
244
|
|
|
134
245
|
// src/KeepBulkActions.tsx
|
|
135
|
-
import { Fragment, jsx as
|
|
246
|
+
import { Fragment, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
136
247
|
function isAllSelected(items, selectedIds) {
|
|
137
248
|
if (items.length === 0) return false;
|
|
138
249
|
const selected = new Set(selectedIds);
|
|
@@ -164,10 +275,10 @@ function KeepBulkActions({
|
|
|
164
275
|
const tagsLabel = useUiLabel("tagsToApply");
|
|
165
276
|
const applyTagsLabel = useUiLabel("applyTags");
|
|
166
277
|
const list = useKeepList(query);
|
|
167
|
-
const [uncontrolledSelectedIds, setUncontrolledSelectedIds] =
|
|
278
|
+
const [uncontrolledSelectedIds, setUncontrolledSelectedIds] = useState2(defaultSelectedIds);
|
|
168
279
|
const selectedIds = controlledSelectedIds ?? uncontrolledSelectedIds;
|
|
169
280
|
const selected = new Set(selectedIds);
|
|
170
|
-
const [tagsInput, setTagsInput] =
|
|
281
|
+
const [tagsInput, setTagsInput] = useState2("");
|
|
171
282
|
const setSelectedIds = (ids) => {
|
|
172
283
|
if (controlledSelectedIds === void 0) setUncontrolledSelectedIds(ids);
|
|
173
284
|
onSelectedIdsChange?.(ids);
|
|
@@ -202,17 +313,17 @@ function KeepBulkActions({
|
|
|
202
313
|
updateTags,
|
|
203
314
|
isMutating: list.isMutating
|
|
204
315
|
};
|
|
205
|
-
const body = render ? render(state) : typeof children === "function" ? children(state) : children ?? /* @__PURE__ */
|
|
206
|
-
/* @__PURE__ */
|
|
207
|
-
/* @__PURE__ */
|
|
208
|
-
/* @__PURE__ */
|
|
209
|
-
/* @__PURE__ */
|
|
316
|
+
const body = render ? render(state) : typeof children === "function" ? children(state) : children ?? /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
317
|
+
/* @__PURE__ */ jsxs2("fieldset", { children: [
|
|
318
|
+
/* @__PURE__ */ jsx5("legend", { children: selectItemsLabel }),
|
|
319
|
+
/* @__PURE__ */ jsxs2("label", { children: [
|
|
320
|
+
/* @__PURE__ */ jsx5("input", { type: "checkbox", checked: allSelected, onChange: toggleAll, "aria-label": selectItemsLabel }),
|
|
210
321
|
selectedIds.length,
|
|
211
322
|
" ",
|
|
212
323
|
selectedCountLabel
|
|
213
324
|
] }),
|
|
214
|
-
list.items.map((item) => /* @__PURE__ */
|
|
215
|
-
/* @__PURE__ */
|
|
325
|
+
list.items.map((item) => /* @__PURE__ */ jsxs2("span", { children: [
|
|
326
|
+
/* @__PURE__ */ jsx5(
|
|
216
327
|
KeepItemCheckbox,
|
|
217
328
|
{
|
|
218
329
|
item,
|
|
@@ -223,12 +334,12 @@ function KeepBulkActions({
|
|
|
223
334
|
renderItem ? renderItem(item, selected.has(item.id)) : getMetaTitle(item.meta) ?? item.id
|
|
224
335
|
] }, item.id))
|
|
225
336
|
] }),
|
|
226
|
-
/* @__PURE__ */
|
|
227
|
-
/* @__PURE__ */
|
|
337
|
+
/* @__PURE__ */ jsx5("button", { type: "button", onClick: () => void remove(), disabled: selectedIds.length === 0 || list.isMutating, children: deleteSelectedLabel }),
|
|
338
|
+
/* @__PURE__ */ jsxs2("label", { children: [
|
|
228
339
|
tagsLabel,
|
|
229
|
-
/* @__PURE__ */
|
|
340
|
+
/* @__PURE__ */ jsx5("input", { value: tagsInput, onChange: (event) => setTagsInput(event.currentTarget.value) })
|
|
230
341
|
] }),
|
|
231
|
-
/* @__PURE__ */
|
|
342
|
+
/* @__PURE__ */ jsx5(
|
|
232
343
|
"button",
|
|
233
344
|
{
|
|
234
345
|
type: "button",
|
|
@@ -238,7 +349,16 @@ function KeepBulkActions({
|
|
|
238
349
|
}
|
|
239
350
|
)
|
|
240
351
|
] });
|
|
241
|
-
return /* @__PURE__ */
|
|
352
|
+
return /* @__PURE__ */ jsx5(
|
|
353
|
+
"section",
|
|
354
|
+
{
|
|
355
|
+
...props,
|
|
356
|
+
"aria-busy": list.isMutating || props["aria-busy"],
|
|
357
|
+
"data-state": selectedIds.length > 0 ? "selected" : "idle",
|
|
358
|
+
"data-loading": list.isLoading || list.isMutating ? "true" : void 0,
|
|
359
|
+
children: body
|
|
360
|
+
}
|
|
361
|
+
);
|
|
242
362
|
}
|
|
243
363
|
|
|
244
364
|
// src/KeepButton.tsx
|
|
@@ -246,7 +366,7 @@ import {
|
|
|
246
366
|
KeepButton as CoreKeepButton,
|
|
247
367
|
useKeepItem
|
|
248
368
|
} from "@keepkit/core/react";
|
|
249
|
-
import { Fragment as Fragment2, jsx as
|
|
369
|
+
import { Fragment as Fragment2, jsx as jsx6 } from "react/jsx-runtime";
|
|
250
370
|
function KeepButton({ labels, ...props }) {
|
|
251
371
|
const saveLabel = useUiLabel("save", typeof labels?.unsaved === "string" ? labels.unsaved : void 0);
|
|
252
372
|
const savedLabel = useUiLabel("saved", typeof labels?.saved === "string" ? labels.saved : void 0);
|
|
@@ -269,22 +389,27 @@ function KeepButton({ labels, ...props }) {
|
|
|
269
389
|
savedAriaLabel: labels?.savedAriaLabel ?? props.savedAriaLabel,
|
|
270
390
|
unsavedAriaLabel: labels?.unsavedAriaLabel ?? props.unsavedAriaLabel
|
|
271
391
|
};
|
|
272
|
-
if (!customStateLabel) return /* @__PURE__ */
|
|
273
|
-
return /* @__PURE__ */
|
|
392
|
+
if (!customStateLabel) return /* @__PURE__ */ jsx6(CoreKeepButton, { ...sharedProps });
|
|
393
|
+
return /* @__PURE__ */ jsx6(CoreKeepButton, { ...sharedProps, children: (state) => /* @__PURE__ */ jsx6(Fragment2, { children: getStateContent(state) }) });
|
|
274
394
|
}
|
|
275
395
|
|
|
276
396
|
// src/KeepCollection.tsx
|
|
277
|
-
import { useKeepList as useKeepList4 } from "@keepkit/core/react";
|
|
278
|
-
import { useMemo as useMemo3, useState as
|
|
397
|
+
import { KeepErrorBoundary as KeepErrorBoundary2, useKeepList as useKeepList4 } from "@keepkit/core/react";
|
|
398
|
+
import { useMemo as useMemo3, useState as useState5 } from "react";
|
|
279
399
|
|
|
280
400
|
// src/KeepList.tsx
|
|
281
|
-
import {
|
|
401
|
+
import {
|
|
402
|
+
KeepErrorBoundary,
|
|
403
|
+
useKeepList as useKeepList2
|
|
404
|
+
} from "@keepkit/core/react";
|
|
282
405
|
import { isValidElement as isValidElement3 } from "react";
|
|
283
406
|
|
|
284
407
|
// src/KeepItemCard.tsx
|
|
285
408
|
import { useKeepItem as useKeepItem2 } from "@keepkit/core/react";
|
|
286
|
-
import {
|
|
287
|
-
|
|
409
|
+
import {
|
|
410
|
+
isValidElement as isValidElement2
|
|
411
|
+
} from "react";
|
|
412
|
+
import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
288
413
|
function KeepItemCard({
|
|
289
414
|
item,
|
|
290
415
|
title,
|
|
@@ -301,6 +426,12 @@ function KeepItemCard({
|
|
|
301
426
|
showSaveButton = true,
|
|
302
427
|
saveButtonLabels,
|
|
303
428
|
asChild = false,
|
|
429
|
+
href: hrefOption,
|
|
430
|
+
onOpen,
|
|
431
|
+
linkTarget = "title",
|
|
432
|
+
linkComponent: LinkComponent,
|
|
433
|
+
linkTargetAttribute,
|
|
434
|
+
linkRel,
|
|
304
435
|
className,
|
|
305
436
|
...rootProps
|
|
306
437
|
}) {
|
|
@@ -313,10 +444,27 @@ function KeepItemCard({
|
|
|
313
444
|
isSaved: itemState.isSaved,
|
|
314
445
|
isMutating: itemState.isMutating,
|
|
315
446
|
error: itemState.error,
|
|
316
|
-
remove: itemState.remove
|
|
447
|
+
remove: itemState.remove,
|
|
448
|
+
status: item.status
|
|
317
449
|
};
|
|
318
450
|
const resolvedTitle = typeof title === "function" ? title(item) : title ?? getTitle?.(item) ?? getMetaTitle(item.meta) ?? item.id;
|
|
319
451
|
const imageProps = getImageProps?.(item, resolvedTitle);
|
|
452
|
+
const href = typeof hrefOption === "function" ? hrefOption(item) : hrefOption;
|
|
453
|
+
const isAvailable = item.status === void 0 || item.status === "available";
|
|
454
|
+
const statusLabelKey = item.status && item.status !== "available" ? getStatusLabelKey(item.status) : "statusUnknown";
|
|
455
|
+
const unavailableLabel = useUiLabel(statusLabelKey);
|
|
456
|
+
const statusLabel = item.status && item.status !== "available" ? unavailableLabel : void 0;
|
|
457
|
+
function renderLink(content) {
|
|
458
|
+
if (!href || !isAvailable) return content;
|
|
459
|
+
const linkProps = {
|
|
460
|
+
href,
|
|
461
|
+
target: linkTargetAttribute,
|
|
462
|
+
rel: linkRel,
|
|
463
|
+
onClick: (event) => onOpen?.(item, event),
|
|
464
|
+
children: content
|
|
465
|
+
};
|
|
466
|
+
return LinkComponent ? /* @__PURE__ */ jsx7(LinkComponent, { ...linkProps }) : /* @__PURE__ */ jsx7("a", { ...linkProps });
|
|
467
|
+
}
|
|
320
468
|
async function handleRemove() {
|
|
321
469
|
try {
|
|
322
470
|
await itemState.remove();
|
|
@@ -325,10 +473,11 @@ function KeepItemCard({
|
|
|
325
473
|
onRemoveError?.(error);
|
|
326
474
|
}
|
|
327
475
|
}
|
|
328
|
-
const body = render ? render(state) : typeof contentChildren === "function" ? contentChildren(state) : contentChildren ?? /* @__PURE__ */
|
|
329
|
-
imageProps ? renderImage?.({ ...imageProps, alt: imageAlt ?? imageProps.alt }, item) ?? (ImageComponent ? /* @__PURE__ */
|
|
330
|
-
/* @__PURE__ */
|
|
331
|
-
|
|
476
|
+
const body = render ? render(state) : typeof contentChildren === "function" ? contentChildren(state) : contentChildren ?? /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
477
|
+
imageProps ? renderImage?.({ ...imageProps, alt: imageAlt ?? imageProps.alt }, item) ?? (ImageComponent ? /* @__PURE__ */ jsx7(ImageComponent, { ...imageProps, alt: imageAlt ?? imageProps.alt }) : /* @__PURE__ */ jsx7("img", { ...imageProps, alt: imageAlt ?? imageProps.alt })) : null,
|
|
478
|
+
/* @__PURE__ */ jsx7("h3", { children: linkTarget === "title" ? renderLink(resolvedTitle) : resolvedTitle }),
|
|
479
|
+
statusLabel ? /* @__PURE__ */ jsx7("p", { "data-status": item.status, children: statusLabel }) : null,
|
|
480
|
+
showSaveButton ? /* @__PURE__ */ jsx7(
|
|
332
481
|
KeepButton,
|
|
333
482
|
{
|
|
334
483
|
item: toKeepButtonItem(item),
|
|
@@ -336,20 +485,48 @@ function KeepItemCard({
|
|
|
336
485
|
getAriaLabel: (buttonState) => `${buttonState.isSaved ? removeActionLabel : saveActionLabel} ${String(resolvedTitle)}`
|
|
337
486
|
}
|
|
338
487
|
) : null,
|
|
339
|
-
/* @__PURE__ */
|
|
488
|
+
/* @__PURE__ */ jsx7("button", { type: "button", onClick: () => void handleRemove(), disabled: itemState.isMutating, children: removeLabel ?? removeActionLabel })
|
|
340
489
|
] });
|
|
490
|
+
const linkedBody = linkTarget === "card" ? renderLink(body) : body;
|
|
341
491
|
return renderRoot(
|
|
342
492
|
asChild,
|
|
343
493
|
isValidElement2(children) ? children : void 0,
|
|
344
|
-
{
|
|
345
|
-
|
|
494
|
+
{
|
|
495
|
+
...rootProps,
|
|
496
|
+
className,
|
|
497
|
+
"aria-busy": itemState.isMutating || rootProps["aria-busy"],
|
|
498
|
+
"data-state": itemState.isSaved ? "saved" : "unsaved",
|
|
499
|
+
"data-status": item.status ?? "available",
|
|
500
|
+
"data-loading": itemState.isMutating ? "true" : void 0
|
|
501
|
+
},
|
|
502
|
+
linkedBody,
|
|
346
503
|
"KeepItemCard"
|
|
347
504
|
);
|
|
348
505
|
}
|
|
506
|
+
function getStatusLabelKey(status) {
|
|
507
|
+
switch (status) {
|
|
508
|
+
case "expired":
|
|
509
|
+
return "statusExpired";
|
|
510
|
+
case "removed":
|
|
511
|
+
return "statusRemoved";
|
|
512
|
+
case "deleted":
|
|
513
|
+
return "statusDeleted";
|
|
514
|
+
case "private":
|
|
515
|
+
return "statusPrivate";
|
|
516
|
+
default:
|
|
517
|
+
return "statusUnknown";
|
|
518
|
+
}
|
|
519
|
+
}
|
|
349
520
|
|
|
350
521
|
// src/KeepList.tsx
|
|
351
|
-
import { jsx as
|
|
352
|
-
function KeepList({
|
|
522
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
523
|
+
function KeepList(props) {
|
|
524
|
+
const { fallback, onBoundaryError, boundaryResetKey, ...listProps } = props;
|
|
525
|
+
const content = /* @__PURE__ */ jsx8(KeepListContent, { ...listProps });
|
|
526
|
+
if (fallback === void 0 && onBoundaryError === void 0) return content;
|
|
527
|
+
return /* @__PURE__ */ jsx8(KeepErrorBoundary, { fallback, onError: onBoundaryError, resetKey: boundaryResetKey, children: content });
|
|
528
|
+
}
|
|
529
|
+
function KeepListContent({
|
|
353
530
|
query,
|
|
354
531
|
children,
|
|
355
532
|
renderItem,
|
|
@@ -376,26 +553,38 @@ function KeepList({
|
|
|
376
553
|
return renderRoot(
|
|
377
554
|
asChild,
|
|
378
555
|
asChild && isValidElement3(children) ? children : void 0,
|
|
379
|
-
{
|
|
556
|
+
{
|
|
557
|
+
...rootProps,
|
|
558
|
+
className,
|
|
559
|
+
"aria-busy": state.isLoading || rootProps["aria-busy"],
|
|
560
|
+
"data-state": getListState(state),
|
|
561
|
+
"data-loading": state.isLoading ? "true" : void 0
|
|
562
|
+
},
|
|
380
563
|
body,
|
|
381
564
|
"KeepList"
|
|
382
565
|
);
|
|
383
566
|
}
|
|
567
|
+
function getListState(state) {
|
|
568
|
+
if (state.error && state.items.length === 0) return "error";
|
|
569
|
+
if (state.isLoading && !state.isHydrated) return "loading";
|
|
570
|
+
if (state.isHydrated && state.items.length === 0) return "empty";
|
|
571
|
+
return "ready";
|
|
572
|
+
}
|
|
384
573
|
function getListBody(state, options) {
|
|
385
574
|
if (state.error && state.items.length === 0) return resolveContent(options.error, state);
|
|
386
575
|
if (state.isLoading && !state.isHydrated) return resolveContent(options.loading, state);
|
|
387
576
|
if (state.isHydrated && state.items.length === 0) return resolveContent(options.empty, state);
|
|
388
577
|
if (typeof options.children === "function") return options.children(state);
|
|
389
578
|
if (options.children !== void 0 && !isValidElement3(options.children)) return options.children;
|
|
390
|
-
return /* @__PURE__ */
|
|
391
|
-
(item) => options.renderItem ? options.renderItem(item, state) : /* @__PURE__ */
|
|
579
|
+
return /* @__PURE__ */ jsx8("ul", { children: state.items.map(
|
|
580
|
+
(item) => options.renderItem ? options.renderItem(item, state) : /* @__PURE__ */ jsx8("li", { children: /* @__PURE__ */ jsx8(KeepItemCard, { item, ...options.itemCardProps }) }, item.id)
|
|
392
581
|
) });
|
|
393
582
|
}
|
|
394
583
|
|
|
395
584
|
// src/KeepTagFilter.tsx
|
|
396
585
|
import { useKeepList as useKeepList3 } from "@keepkit/core/react";
|
|
397
|
-
import { isValidElement as isValidElement4, useCallback, useMemo as useMemo2, useState as
|
|
398
|
-
import { jsx as
|
|
586
|
+
import { isValidElement as isValidElement4, useCallback, useMemo as useMemo2, useState as useState3 } from "react";
|
|
587
|
+
import { jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
399
588
|
function KeepTagFilter({
|
|
400
589
|
query,
|
|
401
590
|
value: controlledValue,
|
|
@@ -413,7 +602,7 @@ function KeepTagFilter({
|
|
|
413
602
|
}) {
|
|
414
603
|
const uiAllLabel = useUiLabel("allTags");
|
|
415
604
|
const uiAriaLabel = useUiLabel("filterTags");
|
|
416
|
-
const [uncontrolledValue, setUncontrolledValue] =
|
|
605
|
+
const [uncontrolledValue, setUncontrolledValue] = useState3(defaultValue);
|
|
417
606
|
const resolvedValue = controlledValue ?? uncontrolledValue;
|
|
418
607
|
const list = useKeepList3({
|
|
419
608
|
...query,
|
|
@@ -432,12 +621,12 @@ function KeepTagFilter({
|
|
|
432
621
|
[list.tagCounts, list.tags, resolvedValue, select]
|
|
433
622
|
);
|
|
434
623
|
const contentChildren = asChild && isValidElement4(children) ? void 0 : children;
|
|
435
|
-
const body = render ? render(state) : typeof contentChildren === "function" ? contentChildren(state) : contentChildren ?? /* @__PURE__ */
|
|
436
|
-
/* @__PURE__ */
|
|
437
|
-
/* @__PURE__ */
|
|
438
|
-
list.tags.map((tag) => /* @__PURE__ */
|
|
624
|
+
const body = render ? render(state) : typeof contentChildren === "function" ? contentChildren(state) : contentChildren ?? /* @__PURE__ */ jsxs4("fieldset", { children: [
|
|
625
|
+
/* @__PURE__ */ jsx9("legend", { children: ariaLabel ?? uiAriaLabel }),
|
|
626
|
+
/* @__PURE__ */ jsx9("button", { type: "button", "aria-pressed": resolvedValue === void 0, onClick: () => select(), children: allLabel ?? uiAllLabel }),
|
|
627
|
+
list.tags.map((tag) => /* @__PURE__ */ jsxs4("button", { type: "button", "aria-pressed": resolvedValue === tag, onClick: () => select(tag), children: [
|
|
439
628
|
renderTag ? renderTag(tag, list.tagCounts[tag] ?? 0, resolvedValue === tag) : tag,
|
|
440
|
-
/* @__PURE__ */
|
|
629
|
+
/* @__PURE__ */ jsxs4("span", { children: [
|
|
441
630
|
" (",
|
|
442
631
|
list.tagCounts[tag] ?? 0,
|
|
443
632
|
")"
|
|
@@ -447,15 +636,20 @@ function KeepTagFilter({
|
|
|
447
636
|
return renderRoot(
|
|
448
637
|
asChild,
|
|
449
638
|
isValidElement4(children) ? children : void 0,
|
|
450
|
-
{
|
|
639
|
+
{
|
|
640
|
+
...rootProps,
|
|
641
|
+
className,
|
|
642
|
+
"data-state": resolvedValue === void 0 ? "all" : "filtered",
|
|
643
|
+
"data-loading": list.isLoading ? "true" : void 0
|
|
644
|
+
},
|
|
451
645
|
body,
|
|
452
646
|
"KeepTagFilter"
|
|
453
647
|
);
|
|
454
648
|
}
|
|
455
649
|
|
|
456
650
|
// src/query-controls.tsx
|
|
457
|
-
import { useEffect, useState as
|
|
458
|
-
import { Fragment as Fragment4, jsx as
|
|
651
|
+
import { useEffect, useState as useState4 } from "react";
|
|
652
|
+
import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
459
653
|
function KeepSearchInput({
|
|
460
654
|
value: controlledValue,
|
|
461
655
|
defaultValue = "",
|
|
@@ -466,7 +660,7 @@ function KeepSearchInput({
|
|
|
466
660
|
...props
|
|
467
661
|
}) {
|
|
468
662
|
const label = useUiLabel("search");
|
|
469
|
-
const [uncontrolledValue, setUncontrolledValue] =
|
|
663
|
+
const [uncontrolledValue, setUncontrolledValue] = useState4(defaultValue);
|
|
470
664
|
const value = controlledValue ?? uncontrolledValue;
|
|
471
665
|
useEffect(() => {
|
|
472
666
|
if (!onValueChange) return;
|
|
@@ -477,12 +671,14 @@ function KeepSearchInput({
|
|
|
477
671
|
const timer = window.setTimeout(() => onValueChange(value), debounceMs);
|
|
478
672
|
return () => window.clearTimeout(timer);
|
|
479
673
|
}, [debounceMs, onValueChange, value]);
|
|
480
|
-
return /* @__PURE__ */
|
|
674
|
+
return /* @__PURE__ */ jsx10(
|
|
481
675
|
"input",
|
|
482
676
|
{
|
|
483
677
|
...props,
|
|
484
678
|
type: "search",
|
|
485
679
|
value,
|
|
680
|
+
"data-state": value ? "active" : "idle",
|
|
681
|
+
"data-disabled": props.disabled ? "true" : void 0,
|
|
486
682
|
"aria-label": ariaLabel ?? label,
|
|
487
683
|
placeholder: placeholder ?? label,
|
|
488
684
|
onChange: (event) => {
|
|
@@ -505,19 +701,21 @@ function KeepSortSelect({
|
|
|
505
701
|
const updatedOldestLabel = useUiLabel("updatedOldest");
|
|
506
702
|
const savedNewestLabel = useUiLabel("savedNewest");
|
|
507
703
|
const savedOldestLabel = useUiLabel("savedOldest");
|
|
508
|
-
const [uncontrolledValue, setUncontrolledValue] =
|
|
704
|
+
const [uncontrolledValue, setUncontrolledValue] = useState4(defaultValue);
|
|
509
705
|
const value = controlledValue ?? uncontrolledValue;
|
|
510
|
-
const options = children ?? /* @__PURE__ */
|
|
511
|
-
/* @__PURE__ */
|
|
512
|
-
/* @__PURE__ */
|
|
513
|
-
/* @__PURE__ */
|
|
514
|
-
/* @__PURE__ */
|
|
706
|
+
const options = children ?? /* @__PURE__ */ jsxs5(Fragment4, { children: [
|
|
707
|
+
/* @__PURE__ */ jsx10("option", { value: "updatedAt:desc", children: updatedNewestLabel }),
|
|
708
|
+
/* @__PURE__ */ jsx10("option", { value: "updatedAt:asc", children: updatedOldestLabel }),
|
|
709
|
+
/* @__PURE__ */ jsx10("option", { value: "savedAt:desc", children: savedNewestLabel }),
|
|
710
|
+
/* @__PURE__ */ jsx10("option", { value: "savedAt:asc", children: savedOldestLabel })
|
|
515
711
|
] });
|
|
516
|
-
return /* @__PURE__ */
|
|
712
|
+
return /* @__PURE__ */ jsx10(
|
|
517
713
|
"select",
|
|
518
714
|
{
|
|
519
715
|
...props,
|
|
520
716
|
value,
|
|
717
|
+
"data-state": "selected",
|
|
718
|
+
"data-disabled": props.disabled ? "true" : void 0,
|
|
521
719
|
"aria-label": ariaLabel ?? label,
|
|
522
720
|
onChange: (event) => {
|
|
523
721
|
const nextValue = event.currentTarget.value;
|
|
@@ -548,12 +746,16 @@ function KeepPagination({
|
|
|
548
746
|
const next = Math.min(Math.max(1, nextPage), pageCount);
|
|
549
747
|
onPageChange?.(next, (next - 1) * pageSize);
|
|
550
748
|
};
|
|
551
|
-
const navProps = {
|
|
552
|
-
|
|
749
|
+
const navProps = {
|
|
750
|
+
...props,
|
|
751
|
+
"aria-label": props["aria-label"] ?? paginationLabel,
|
|
752
|
+
"data-state": pageCount > 1 ? "active" : "idle"
|
|
753
|
+
};
|
|
754
|
+
if (render) return /* @__PURE__ */ jsx10("nav", { ...navProps, children: render({ page: currentPage, pageCount, goToPage }) });
|
|
553
755
|
const visiblePages = getVisiblePages(currentPage, pageCount, Math.max(1, maxPageButtons));
|
|
554
|
-
return /* @__PURE__ */
|
|
555
|
-
/* @__PURE__ */
|
|
556
|
-
visiblePages.map((nextPage) => /* @__PURE__ */
|
|
756
|
+
return /* @__PURE__ */ jsxs5("nav", { ...navProps, children: [
|
|
757
|
+
/* @__PURE__ */ jsx10("button", { type: "button", onClick: () => goToPage(currentPage - 1), disabled: currentPage <= 1, children: previousPageLabel }),
|
|
758
|
+
visiblePages.map((nextPage) => /* @__PURE__ */ jsx10(
|
|
557
759
|
"button",
|
|
558
760
|
{
|
|
559
761
|
type: "button",
|
|
@@ -564,7 +766,7 @@ function KeepPagination({
|
|
|
564
766
|
},
|
|
565
767
|
nextPage
|
|
566
768
|
)),
|
|
567
|
-
/* @__PURE__ */
|
|
769
|
+
/* @__PURE__ */ jsx10("button", { type: "button", onClick: () => goToPage(currentPage + 1), disabled: currentPage >= pageCount, children: nextPageLabel })
|
|
568
770
|
] });
|
|
569
771
|
}
|
|
570
772
|
function getVisiblePages(currentPage, pageCount, maxPageButtons) {
|
|
@@ -575,8 +777,14 @@ function getVisiblePages(currentPage, pageCount, maxPageButtons) {
|
|
|
575
777
|
}
|
|
576
778
|
|
|
577
779
|
// src/KeepCollection.tsx
|
|
578
|
-
import { jsx as
|
|
579
|
-
function KeepCollection({
|
|
780
|
+
import { jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
781
|
+
function KeepCollection(props) {
|
|
782
|
+
const { fallback, onBoundaryError, boundaryResetKey, ...collectionProps } = props;
|
|
783
|
+
const content = /* @__PURE__ */ jsx11(KeepCollectionContent, { ...collectionProps });
|
|
784
|
+
if (fallback === void 0 && onBoundaryError === void 0) return content;
|
|
785
|
+
return /* @__PURE__ */ jsx11(KeepErrorBoundary2, { fallback, onError: onBoundaryError, resetKey: boundaryResetKey, children: content });
|
|
786
|
+
}
|
|
787
|
+
function KeepCollectionContent({
|
|
580
788
|
query = {},
|
|
581
789
|
pageSize = 20,
|
|
582
790
|
features,
|
|
@@ -596,10 +804,10 @@ function KeepCollection({
|
|
|
596
804
|
bulkActions: false,
|
|
597
805
|
...features
|
|
598
806
|
};
|
|
599
|
-
const [searchValue, setSearchValue] =
|
|
600
|
-
const [sort, setSort] =
|
|
601
|
-
const [tag, setTag] =
|
|
602
|
-
const [page, setPage] =
|
|
807
|
+
const [searchValue, setSearchValue] = useState5(query.search?.query ?? "");
|
|
808
|
+
const [sort, setSort] = useState5(query.sort ?? { by: "updatedAt", direction: "desc" });
|
|
809
|
+
const [tag, setTag] = useState5(query.tags?.[0]);
|
|
810
|
+
const [page, setPage] = useState5(query.pagination?.page ?? 1);
|
|
603
811
|
const resolvedPageSize = query.pagination?.pageSize ?? pageSize;
|
|
604
812
|
const resolvedQuery = useMemo3(
|
|
605
813
|
() => ({
|
|
@@ -612,15 +820,17 @@ function KeepCollection({
|
|
|
612
820
|
[enabled.pagination, enabled.search, enabled.sort, page, query, resolvedPageSize, searchValue, sort, tag]
|
|
613
821
|
);
|
|
614
822
|
const list = useKeepList4(resolvedQuery);
|
|
615
|
-
return /* @__PURE__ */
|
|
823
|
+
return /* @__PURE__ */ jsxs6(
|
|
616
824
|
"section",
|
|
617
825
|
{
|
|
618
826
|
...rootProps,
|
|
619
827
|
className,
|
|
620
828
|
"aria-busy": list.isLoading || list.isMutating || rootProps["aria-busy"],
|
|
829
|
+
"data-state": getCollectionState(list),
|
|
830
|
+
"data-loading": list.isLoading || list.isMutating ? "true" : void 0,
|
|
621
831
|
children: [
|
|
622
|
-
/* @__PURE__ */
|
|
623
|
-
enabled.search ? /* @__PURE__ */
|
|
832
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
833
|
+
enabled.search ? /* @__PURE__ */ jsx11(
|
|
624
834
|
KeepSearchInput,
|
|
625
835
|
{
|
|
626
836
|
value: searchValue,
|
|
@@ -630,7 +840,7 @@ function KeepCollection({
|
|
|
630
840
|
}
|
|
631
841
|
}
|
|
632
842
|
) : null,
|
|
633
|
-
enabled.sort ? /* @__PURE__ */
|
|
843
|
+
enabled.sort ? /* @__PURE__ */ jsx11(
|
|
634
844
|
KeepSortSelect,
|
|
635
845
|
{
|
|
636
846
|
value: sortToValue(sort),
|
|
@@ -640,7 +850,7 @@ function KeepCollection({
|
|
|
640
850
|
}
|
|
641
851
|
}
|
|
642
852
|
) : null,
|
|
643
|
-
enabled.tagFilter ? /* @__PURE__ */
|
|
853
|
+
enabled.tagFilter ? /* @__PURE__ */ jsx11(
|
|
644
854
|
KeepTagFilter,
|
|
645
855
|
{
|
|
646
856
|
query,
|
|
@@ -652,7 +862,7 @@ function KeepCollection({
|
|
|
652
862
|
}
|
|
653
863
|
) : null
|
|
654
864
|
] }),
|
|
655
|
-
/* @__PURE__ */
|
|
865
|
+
/* @__PURE__ */ jsx11(
|
|
656
866
|
KeepList,
|
|
657
867
|
{
|
|
658
868
|
query: resolvedQuery,
|
|
@@ -663,7 +873,7 @@ function KeepCollection({
|
|
|
663
873
|
error
|
|
664
874
|
}
|
|
665
875
|
),
|
|
666
|
-
enabled.pagination ? /* @__PURE__ */
|
|
876
|
+
enabled.pagination ? /* @__PURE__ */ jsx11(
|
|
667
877
|
KeepPagination,
|
|
668
878
|
{
|
|
669
879
|
totalCount: list.totalCount,
|
|
@@ -672,11 +882,17 @@ function KeepCollection({
|
|
|
672
882
|
onPageChange: (nextPage) => setPage(nextPage)
|
|
673
883
|
}
|
|
674
884
|
) : null,
|
|
675
|
-
enabled.bulkActions ? /* @__PURE__ */
|
|
885
|
+
enabled.bulkActions ? /* @__PURE__ */ jsx11(KeepBulkActions, { query: resolvedQuery }) : null
|
|
676
886
|
]
|
|
677
887
|
}
|
|
678
888
|
);
|
|
679
889
|
}
|
|
890
|
+
function getCollectionState(list) {
|
|
891
|
+
if (list.error && list.items.length === 0) return "error";
|
|
892
|
+
if (list.isLoading && !list.isHydrated) return "loading";
|
|
893
|
+
if (list.isHydrated && list.items.length === 0) return "empty";
|
|
894
|
+
return "ready";
|
|
895
|
+
}
|
|
680
896
|
|
|
681
897
|
// src/KeepNoteEditor.tsx
|
|
682
898
|
import { useKeepItem as useKeepItem3 } from "@keepkit/core/react";
|
|
@@ -684,10 +900,10 @@ import {
|
|
|
684
900
|
isValidElement as isValidElement5,
|
|
685
901
|
useCallback as useCallback2,
|
|
686
902
|
useEffect as useEffect2,
|
|
687
|
-
useRef,
|
|
688
|
-
useState as
|
|
903
|
+
useRef as useRef2,
|
|
904
|
+
useState as useState6
|
|
689
905
|
} from "react";
|
|
690
|
-
import { Fragment as Fragment5, jsx as
|
|
906
|
+
import { Fragment as Fragment5, jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
691
907
|
function KeepNoteEditor({
|
|
692
908
|
item,
|
|
693
909
|
label,
|
|
@@ -707,10 +923,10 @@ function KeepNoteEditor({
|
|
|
707
923
|
const itemState = useKeepItem3(item);
|
|
708
924
|
const { error, isMutating, item: savedItem, updateNote } = itemState;
|
|
709
925
|
const contentChildren = asChild && isValidElement5(children) ? void 0 : children;
|
|
710
|
-
const [note, setNote] =
|
|
926
|
+
const [note, setNote] = useState6(item.note ?? "");
|
|
711
927
|
const baselineNote = savedItem?.note ?? item.note ?? "";
|
|
712
928
|
const isDirty = note !== baselineNote;
|
|
713
|
-
const lastSavedNoteRef =
|
|
929
|
+
const lastSavedNoteRef = useRef2(void 0);
|
|
714
930
|
useEffect2(() => setNote(baselineNote), [baselineNote]);
|
|
715
931
|
const save = useCallback2(async () => {
|
|
716
932
|
const nextNote = note.trim() || void 0;
|
|
@@ -737,10 +953,10 @@ function KeepNoteEditor({
|
|
|
737
953
|
error,
|
|
738
954
|
save
|
|
739
955
|
};
|
|
740
|
-
const body = render ? render(state) : typeof contentChildren === "function" ? contentChildren(state) : contentChildren ?? /* @__PURE__ */
|
|
741
|
-
/* @__PURE__ */
|
|
956
|
+
const body = render ? render(state) : typeof contentChildren === "function" ? contentChildren(state) : contentChildren ?? /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
957
|
+
/* @__PURE__ */ jsxs7("label", { children: [
|
|
742
958
|
label ?? defaultLabel,
|
|
743
|
-
/* @__PURE__ */
|
|
959
|
+
/* @__PURE__ */ jsx12(
|
|
744
960
|
"textarea",
|
|
745
961
|
{
|
|
746
962
|
value: note,
|
|
@@ -756,20 +972,23 @@ function KeepNoteEditor({
|
|
|
756
972
|
}
|
|
757
973
|
)
|
|
758
974
|
] }),
|
|
759
|
-
/* @__PURE__ */
|
|
975
|
+
/* @__PURE__ */ jsx12("button", { type: "submit", disabled: isMutating, "aria-busy": isMutating, children: saveLabel ?? defaultSaveLabel })
|
|
760
976
|
] });
|
|
761
977
|
const handleSubmit = (event) => {
|
|
762
978
|
event.preventDefault();
|
|
763
979
|
void save().catch(() => void 0);
|
|
764
980
|
};
|
|
765
981
|
if (!asChild) {
|
|
766
|
-
return /* @__PURE__ */
|
|
982
|
+
return /* @__PURE__ */ jsx12(
|
|
767
983
|
"form",
|
|
768
984
|
{
|
|
769
985
|
...formProps,
|
|
770
986
|
className,
|
|
771
987
|
onSubmit: handleSubmit,
|
|
772
988
|
"aria-busy": isMutating || formProps["aria-busy"],
|
|
989
|
+
"data-state": isDirty ? "dirty" : "clean",
|
|
990
|
+
"data-loading": isMutating ? "true" : void 0,
|
|
991
|
+
"data-disabled": isMutating ? "true" : void 0,
|
|
773
992
|
children: body
|
|
774
993
|
}
|
|
775
994
|
);
|
|
@@ -777,7 +996,15 @@ function KeepNoteEditor({
|
|
|
777
996
|
return renderRoot(
|
|
778
997
|
true,
|
|
779
998
|
isValidElement5(children) ? children : void 0,
|
|
780
|
-
{
|
|
999
|
+
{
|
|
1000
|
+
...formProps,
|
|
1001
|
+
className,
|
|
1002
|
+
onSubmit: handleSubmit,
|
|
1003
|
+
"aria-busy": isMutating || formProps["aria-busy"],
|
|
1004
|
+
"data-state": isDirty ? "dirty" : "clean",
|
|
1005
|
+
"data-loading": isMutating ? "true" : void 0,
|
|
1006
|
+
"data-disabled": isMutating ? "true" : void 0
|
|
1007
|
+
},
|
|
781
1008
|
body,
|
|
782
1009
|
"KeepNoteEditor"
|
|
783
1010
|
);
|
|
@@ -785,8 +1012,8 @@ function KeepNoteEditor({
|
|
|
785
1012
|
|
|
786
1013
|
// src/KeepTagEditor.tsx
|
|
787
1014
|
import { useKeepItem as useKeepItem4 } from "@keepkit/core/react";
|
|
788
|
-
import { useCallback as useCallback3, useEffect as useEffect3, useState as
|
|
789
|
-
import { Fragment as Fragment6, jsx as
|
|
1015
|
+
import { useCallback as useCallback3, useEffect as useEffect3, useState as useState7 } from "react";
|
|
1016
|
+
import { Fragment as Fragment6, jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
790
1017
|
function KeepTagEditor({
|
|
791
1018
|
item,
|
|
792
1019
|
availableTags = [],
|
|
@@ -799,8 +1026,8 @@ function KeepTagEditor({
|
|
|
799
1026
|
const removeLabel = useUiLabel("remove");
|
|
800
1027
|
const applyTagsLabel = useUiLabel("applyTags");
|
|
801
1028
|
const itemState = useKeepItem4(item);
|
|
802
|
-
const [tags, setTags] =
|
|
803
|
-
const [input, setInput] =
|
|
1029
|
+
const [tags, setTags] = useState7(item.tags ?? []);
|
|
1030
|
+
const [input, setInput] = useState7("");
|
|
804
1031
|
useEffect3(() => setTags(itemState.item?.tags ?? item.tags ?? []), [item.tags, itemState.item?.tags]);
|
|
805
1032
|
const save = useCallback3(async () => {
|
|
806
1033
|
const nextTags = normalizeUiTags(tags);
|
|
@@ -817,10 +1044,10 @@ function KeepTagEditor({
|
|
|
817
1044
|
setTags(normalizeUiTags([...tags, tag]));
|
|
818
1045
|
setInput("");
|
|
819
1046
|
};
|
|
820
|
-
const body = render ? render({ tags, setTags, save, isSaving: itemState.isMutating }) : /* @__PURE__ */
|
|
821
|
-
/* @__PURE__ */
|
|
1047
|
+
const body = render ? render({ tags, setTags, save, isSaving: itemState.isMutating }) : /* @__PURE__ */ jsxs8(Fragment6, { children: [
|
|
1048
|
+
/* @__PURE__ */ jsxs8("label", { children: [
|
|
822
1049
|
tagsLabel,
|
|
823
|
-
/* @__PURE__ */
|
|
1050
|
+
/* @__PURE__ */ jsx13(
|
|
824
1051
|
"input",
|
|
825
1052
|
{
|
|
826
1053
|
value: input,
|
|
@@ -839,14 +1066,14 @@ function KeepTagEditor({
|
|
|
839
1066
|
}
|
|
840
1067
|
)
|
|
841
1068
|
] }),
|
|
842
|
-
availableTags.length > 0 ? /* @__PURE__ */
|
|
843
|
-
/* @__PURE__ */
|
|
1069
|
+
availableTags.length > 0 ? /* @__PURE__ */ jsx13("datalist", { id: `keep-tags-${item.id}`, children: availableTags.map((tag) => /* @__PURE__ */ jsx13("option", { value: tag }, tag)) }) : null,
|
|
1070
|
+
/* @__PURE__ */ jsx13("ul", { "aria-label": tagsLabel, children: tags.map((tag) => /* @__PURE__ */ jsxs8("li", { children: [
|
|
844
1071
|
tag,
|
|
845
|
-
/* @__PURE__ */
|
|
1072
|
+
/* @__PURE__ */ jsx13("button", { type: "button", onClick: () => setTags(tags.filter((current) => current !== tag)), children: removeLabel })
|
|
846
1073
|
] }, tag)) }),
|
|
847
|
-
/* @__PURE__ */
|
|
1074
|
+
/* @__PURE__ */ jsx13("button", { type: "submit", disabled: itemState.isMutating, "aria-busy": itemState.isMutating, children: applyTagsLabel })
|
|
848
1075
|
] });
|
|
849
|
-
return /* @__PURE__ */
|
|
1076
|
+
return /* @__PURE__ */ jsx13(
|
|
850
1077
|
"form",
|
|
851
1078
|
{
|
|
852
1079
|
...props,
|
|
@@ -855,15 +1082,18 @@ function KeepTagEditor({
|
|
|
855
1082
|
void save().catch(() => void 0);
|
|
856
1083
|
},
|
|
857
1084
|
"aria-busy": itemState.isMutating || props["aria-busy"],
|
|
1085
|
+
"data-state": itemState.isMutating ? "saving" : "idle",
|
|
1086
|
+
"data-loading": itemState.isMutating ? "true" : void 0,
|
|
1087
|
+
"data-disabled": itemState.isMutating ? "true" : void 0,
|
|
858
1088
|
children: body
|
|
859
1089
|
}
|
|
860
1090
|
);
|
|
861
1091
|
}
|
|
862
1092
|
|
|
863
1093
|
// src/status.tsx
|
|
864
|
-
import { useKeepContext } from "@keepkit/core/react";
|
|
865
|
-
import { isValidElement as isValidElement6, useEffect as useEffect4, useRef as
|
|
866
|
-
import { Fragment as Fragment7, jsx as
|
|
1094
|
+
import { useKeepContext as useKeepContext2 } from "@keepkit/core/react";
|
|
1095
|
+
import { isValidElement as isValidElement6, useEffect as useEffect4, useRef as useRef3, useState as useState8 } from "react";
|
|
1096
|
+
import { Fragment as Fragment7, jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
867
1097
|
function KeepEmptyState({
|
|
868
1098
|
title,
|
|
869
1099
|
description,
|
|
@@ -875,12 +1105,12 @@ function KeepEmptyState({
|
|
|
875
1105
|
}) {
|
|
876
1106
|
const defaultTitle = useUiLabel("noItems").replace(/\.$/, "");
|
|
877
1107
|
const contentChildren = asChild && isValidElement6(children) ? void 0 : children;
|
|
878
|
-
const body = contentChildren ?? /* @__PURE__ */
|
|
879
|
-
/* @__PURE__ */
|
|
880
|
-
description ? /* @__PURE__ */
|
|
1108
|
+
const body = contentChildren ?? /* @__PURE__ */ jsxs9(Fragment7, { children: [
|
|
1109
|
+
/* @__PURE__ */ jsx14("h2", { children: title ?? defaultTitle }),
|
|
1110
|
+
description ? /* @__PURE__ */ jsx14("p", { children: description }) : null,
|
|
881
1111
|
action
|
|
882
1112
|
] });
|
|
883
|
-
return renderRoot(asChild, children, { ...rootProps, className }, body, "KeepEmptyState");
|
|
1113
|
+
return renderRoot(asChild, children, { ...rootProps, className, "data-state": "empty" }, body, "KeepEmptyState");
|
|
884
1114
|
}
|
|
885
1115
|
function KeepStatus({
|
|
886
1116
|
status,
|
|
@@ -891,10 +1121,10 @@ function KeepStatus({
|
|
|
891
1121
|
className,
|
|
892
1122
|
...rootProps
|
|
893
1123
|
}) {
|
|
894
|
-
const context =
|
|
1124
|
+
const context = useKeepContext2();
|
|
895
1125
|
const contentChildren = asChild && isValidElement6(children) ? void 0 : children;
|
|
896
1126
|
const resolvedStatus = status ?? getDerivedStatus(context);
|
|
897
|
-
const defaultLabel = useUiLabel(
|
|
1127
|
+
const defaultLabel = useUiLabel(getStatusLabelKey2(resolvedStatus));
|
|
898
1128
|
const state = {
|
|
899
1129
|
status: resolvedStatus,
|
|
900
1130
|
error: context.error,
|
|
@@ -906,18 +1136,25 @@ function KeepStatus({
|
|
|
906
1136
|
return renderRoot(
|
|
907
1137
|
asChild,
|
|
908
1138
|
isValidElement6(children) ? children : void 0,
|
|
909
|
-
{
|
|
1139
|
+
{
|
|
1140
|
+
...rootProps,
|
|
1141
|
+
className,
|
|
1142
|
+
role,
|
|
1143
|
+
"aria-live": rootProps["aria-live"] ?? "polite",
|
|
1144
|
+
"data-state": resolvedStatus,
|
|
1145
|
+
"data-loading": resolvedStatus === "loading" || resolvedStatus === "saving" || resolvedStatus === "syncing" ? "true" : void 0
|
|
1146
|
+
},
|
|
910
1147
|
body,
|
|
911
1148
|
"KeepStatus"
|
|
912
1149
|
);
|
|
913
1150
|
}
|
|
914
1151
|
function KeepAnnouncements({ messages, ...props }) {
|
|
915
|
-
const context =
|
|
1152
|
+
const context = useKeepContext2();
|
|
916
1153
|
const savedMessage = useUiLabel("savedMessage", messages?.save);
|
|
917
1154
|
const removedMessage = useUiLabel("removedMessage", messages?.remove);
|
|
918
1155
|
const noteSavedMessage = useUiLabel("noteSavedMessage", messages?.note);
|
|
919
|
-
const [message, setMessage] =
|
|
920
|
-
const lastChangeRef =
|
|
1156
|
+
const [message, setMessage] = useState8("");
|
|
1157
|
+
const lastChangeRef = useRef3(void 0);
|
|
921
1158
|
useEffect4(() => {
|
|
922
1159
|
const change = context.lastChange;
|
|
923
1160
|
if (!change || change === lastChangeRef.current) return;
|
|
@@ -926,7 +1163,17 @@ function KeepAnnouncements({ messages, ...props }) {
|
|
|
926
1163
|
else if (change.action === "remove" || change.action === "removeBatch") setMessage(removedMessage);
|
|
927
1164
|
else if (change.action === "updateNote") setMessage(noteSavedMessage);
|
|
928
1165
|
}, [context.lastChange, noteSavedMessage, removedMessage, savedMessage]);
|
|
929
|
-
return /* @__PURE__ */
|
|
1166
|
+
return /* @__PURE__ */ jsx14(
|
|
1167
|
+
"div",
|
|
1168
|
+
{
|
|
1169
|
+
...props,
|
|
1170
|
+
role: props.role ?? "status",
|
|
1171
|
+
"aria-live": props["aria-live"] ?? "polite",
|
|
1172
|
+
"aria-atomic": "true",
|
|
1173
|
+
"data-state": "announcing",
|
|
1174
|
+
children: message
|
|
1175
|
+
}
|
|
1176
|
+
);
|
|
930
1177
|
}
|
|
931
1178
|
var KeepAnnouncer = KeepAnnouncements;
|
|
932
1179
|
function getDerivedStatus(context) {
|
|
@@ -937,7 +1184,7 @@ function getDerivedStatus(context) {
|
|
|
937
1184
|
if (context.isHydrated && context.items.length === 0) return "empty";
|
|
938
1185
|
return "idle";
|
|
939
1186
|
}
|
|
940
|
-
function
|
|
1187
|
+
function getStatusLabelKey2(status) {
|
|
941
1188
|
if (status === "empty") return "noItems";
|
|
942
1189
|
if (status === "loading") return "loadingItems";
|
|
943
1190
|
if (status === "error") return "error";
|
|
@@ -947,7 +1194,14 @@ function getStatusLabelKey(status) {
|
|
|
947
1194
|
}
|
|
948
1195
|
|
|
949
1196
|
// src/index.tsx
|
|
950
|
-
import {
|
|
1197
|
+
import {
|
|
1198
|
+
KeepErrorBoundary as KeepErrorBoundary3,
|
|
1199
|
+
KeepProvider,
|
|
1200
|
+
useKeepContext as useKeepContext3,
|
|
1201
|
+
useKeepItem as useKeepItem5,
|
|
1202
|
+
useKeepList as useKeepList5,
|
|
1203
|
+
useKeepShortcut
|
|
1204
|
+
} from "@keepkit/core/react";
|
|
951
1205
|
import {
|
|
952
1206
|
createBrowserStorageAdapter,
|
|
953
1207
|
createStorageAdapter,
|
|
@@ -958,7 +1212,7 @@ import {
|
|
|
958
1212
|
LocalStorageSyncQueueAdapter,
|
|
959
1213
|
SyncStorageAdapter
|
|
960
1214
|
} from "@keepkit/core/storage";
|
|
961
|
-
import { jsx as
|
|
1215
|
+
import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
962
1216
|
function KeepKitProvider({
|
|
963
1217
|
labels,
|
|
964
1218
|
locale,
|
|
@@ -966,16 +1220,16 @@ function KeepKitProvider({
|
|
|
966
1220
|
children,
|
|
967
1221
|
...providerProps
|
|
968
1222
|
}) {
|
|
969
|
-
return /* @__PURE__ */
|
|
1223
|
+
return /* @__PURE__ */ jsx15(KeepUiProvider, { labels, locale, labelResolver, children: /* @__PURE__ */ jsxs10(CoreKeepProvider, { ...providerProps, children: [
|
|
970
1224
|
children,
|
|
971
|
-
/* @__PURE__ */
|
|
1225
|
+
/* @__PURE__ */ jsx15(KeepAnnouncements, {})
|
|
972
1226
|
] }) });
|
|
973
1227
|
}
|
|
974
1228
|
function createKeepKit(options = {}) {
|
|
975
1229
|
const { labels, locale, labelResolver, getTitle, getImageProps, ...coreOptions } = options;
|
|
976
1230
|
const coreKit = createCoreKeepKit(coreOptions);
|
|
977
1231
|
return {
|
|
978
|
-
Provider: (props) => /* @__PURE__ */
|
|
1232
|
+
Provider: (props) => /* @__PURE__ */ jsx15(
|
|
979
1233
|
KeepKitProvider,
|
|
980
1234
|
{
|
|
981
1235
|
...coreOptions,
|
|
@@ -985,8 +1239,9 @@ function createKeepKit(options = {}) {
|
|
|
985
1239
|
...props
|
|
986
1240
|
}
|
|
987
1241
|
),
|
|
988
|
-
Button: (props) => /* @__PURE__ */
|
|
989
|
-
|
|
1242
|
+
Button: (props) => /* @__PURE__ */ jsx15(KeepButton, { ...props }),
|
|
1243
|
+
Backup: (props) => /* @__PURE__ */ jsx15(KeepBackup, { ...props }),
|
|
1244
|
+
Collection: (props) => /* @__PURE__ */ jsx15(
|
|
990
1245
|
KeepCollection,
|
|
991
1246
|
{
|
|
992
1247
|
...props,
|
|
@@ -1009,10 +1264,12 @@ export {
|
|
|
1009
1264
|
IndexedDBSyncQueueAdapter,
|
|
1010
1265
|
KeepAnnouncements,
|
|
1011
1266
|
KeepAnnouncer,
|
|
1267
|
+
KeepBackup,
|
|
1012
1268
|
KeepBulkActions,
|
|
1013
1269
|
KeepButton,
|
|
1014
1270
|
KeepCollection,
|
|
1015
1271
|
KeepEmptyState,
|
|
1272
|
+
KeepErrorBoundary3 as KeepErrorBoundary,
|
|
1016
1273
|
KeepItemCard,
|
|
1017
1274
|
KeepItemCheckbox,
|
|
1018
1275
|
KeepKitProvider,
|
|
@@ -1034,7 +1291,7 @@ export {
|
|
|
1034
1291
|
createStorageAdapter,
|
|
1035
1292
|
isAllSelected,
|
|
1036
1293
|
toggleSelectAll,
|
|
1037
|
-
|
|
1294
|
+
useKeepContext3 as useKeepContext,
|
|
1038
1295
|
useKeepItem5 as useKeepItem,
|
|
1039
1296
|
useKeepList5 as useKeepList,
|
|
1040
1297
|
useKeepShortcut,
|