@keepkit/ui 0.4.0 → 0.6.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 +50 -41
- package/dist/index.d.ts +108 -43
- package/dist/index.js +425 -179
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -3,23 +3,57 @@
|
|
|
3
3
|
// src/index.tsx
|
|
4
4
|
import {
|
|
5
5
|
KeepButton as CoreKeepButton,
|
|
6
|
+
KeepProvider as CoreKeepProvider,
|
|
7
|
+
createKeepKit as createCoreKeepKit,
|
|
6
8
|
useKeepContext,
|
|
7
9
|
useKeepItem,
|
|
8
10
|
useKeepList
|
|
9
11
|
} from "@keepkit/core/react";
|
|
10
12
|
import {
|
|
11
13
|
cloneElement,
|
|
12
|
-
createContext,
|
|
13
14
|
isValidElement,
|
|
14
15
|
useCallback,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
useMemo,
|
|
16
|
+
useEffect as useEffect2,
|
|
17
|
+
useMemo as useMemo2,
|
|
18
18
|
useRef,
|
|
19
|
-
useState
|
|
19
|
+
useState as useState2
|
|
20
20
|
} from "react";
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
|
|
22
|
+
// src/KeepItemCheckbox.tsx
|
|
23
|
+
import { jsx } from "react/jsx-runtime";
|
|
24
|
+
function KeepItemCheckbox({
|
|
25
|
+
item,
|
|
26
|
+
checked = false,
|
|
27
|
+
label,
|
|
28
|
+
onCheckedChange,
|
|
29
|
+
"aria-label": ariaLabel,
|
|
30
|
+
...props
|
|
31
|
+
}) {
|
|
32
|
+
const itemLabel = getItemLabel(item) ?? item.id;
|
|
33
|
+
const accessibleLabel = ariaLabel ?? (typeof label === "string" ? label : itemLabel);
|
|
34
|
+
return /* @__PURE__ */ jsx(
|
|
35
|
+
"input",
|
|
36
|
+
{
|
|
37
|
+
...props,
|
|
38
|
+
type: "checkbox",
|
|
39
|
+
checked,
|
|
40
|
+
"aria-label": accessibleLabel,
|
|
41
|
+
onChange: (event) => onCheckedChange?.(event.currentTarget.checked)
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
function getItemLabel(item) {
|
|
46
|
+
if (typeof item.meta !== "object" || item.meta === null || !("title" in item.meta)) return void 0;
|
|
47
|
+
const title = item.meta.title;
|
|
48
|
+
return typeof title === "string" && title.trim() ? title.trim() : void 0;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// src/query-controls.tsx
|
|
52
|
+
import { useEffect, useState } from "react";
|
|
53
|
+
|
|
54
|
+
// src/ui-context.tsx
|
|
55
|
+
import { createContext, useContext, useMemo } from "react";
|
|
56
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
23
57
|
var DEFAULT_LABELS = {
|
|
24
58
|
save: "Save",
|
|
25
59
|
saved: "Saved",
|
|
@@ -39,6 +73,10 @@ var DEFAULT_LABELS = {
|
|
|
39
73
|
sort: "Sort saved items",
|
|
40
74
|
newest: "Newest first",
|
|
41
75
|
oldest: "Oldest first",
|
|
76
|
+
savedNewest: "Saved newest first",
|
|
77
|
+
savedOldest: "Saved oldest first",
|
|
78
|
+
updatedNewest: "Updated newest first",
|
|
79
|
+
updatedOldest: "Updated oldest first",
|
|
42
80
|
previousPage: "Previous page",
|
|
43
81
|
nextPage: "Next page",
|
|
44
82
|
pagination: "Pagination",
|
|
@@ -58,7 +96,7 @@ function KeepUiProvider({ labels, locale, labelResolver, children }) {
|
|
|
58
96
|
const resolved = { ...DEFAULT_LABELS, ...labels };
|
|
59
97
|
return { locale, labels: resolved, labelResolver };
|
|
60
98
|
}, [labelResolver, labels, locale]);
|
|
61
|
-
return /* @__PURE__ */
|
|
99
|
+
return /* @__PURE__ */ jsx2(KeepUiLabelsContext.Provider, { value, children });
|
|
62
100
|
}
|
|
63
101
|
function useKeepUiLabels() {
|
|
64
102
|
return useContext(KeepUiLabelsContext);
|
|
@@ -67,17 +105,190 @@ function useUiLabel(key, override) {
|
|
|
67
105
|
const context = useKeepUiLabels();
|
|
68
106
|
return override ?? context.labelResolver?.(key, { locale: context.locale }) ?? context.labels[key];
|
|
69
107
|
}
|
|
108
|
+
|
|
109
|
+
// src/query-controls.tsx
|
|
110
|
+
import { Fragment, jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
111
|
+
function KeepSearchInput({
|
|
112
|
+
value: controlledValue,
|
|
113
|
+
defaultValue = "",
|
|
114
|
+
debounceMs = 300,
|
|
115
|
+
onValueChange,
|
|
116
|
+
"aria-label": ariaLabel,
|
|
117
|
+
placeholder,
|
|
118
|
+
...props
|
|
119
|
+
}) {
|
|
120
|
+
const label = useUiLabel("search");
|
|
121
|
+
const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
|
|
122
|
+
const value = controlledValue ?? uncontrolledValue;
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
if (!onValueChange) return;
|
|
125
|
+
if (debounceMs <= 0) {
|
|
126
|
+
onValueChange(value);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const timer = window.setTimeout(() => onValueChange(value), debounceMs);
|
|
130
|
+
return () => window.clearTimeout(timer);
|
|
131
|
+
}, [debounceMs, onValueChange, value]);
|
|
132
|
+
return /* @__PURE__ */ jsx3(
|
|
133
|
+
"input",
|
|
134
|
+
{
|
|
135
|
+
...props,
|
|
136
|
+
type: "search",
|
|
137
|
+
value,
|
|
138
|
+
"aria-label": ariaLabel ?? label,
|
|
139
|
+
placeholder: placeholder ?? label,
|
|
140
|
+
onChange: (event) => {
|
|
141
|
+
const nextValue = event.currentTarget.value;
|
|
142
|
+
if (controlledValue === void 0) setUncontrolledValue(nextValue);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
function KeepSortSelect({
|
|
148
|
+
value: controlledValue,
|
|
149
|
+
defaultValue = "updatedAt:desc",
|
|
150
|
+
onValueChange,
|
|
151
|
+
"aria-label": ariaLabel,
|
|
152
|
+
children,
|
|
153
|
+
...props
|
|
154
|
+
}) {
|
|
155
|
+
const label = useUiLabel("sort");
|
|
156
|
+
const updatedNewestLabel = useUiLabel("updatedNewest");
|
|
157
|
+
const updatedOldestLabel = useUiLabel("updatedOldest");
|
|
158
|
+
const savedNewestLabel = useUiLabel("savedNewest");
|
|
159
|
+
const savedOldestLabel = useUiLabel("savedOldest");
|
|
160
|
+
const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
|
|
161
|
+
const value = controlledValue ?? uncontrolledValue;
|
|
162
|
+
const options = children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
163
|
+
/* @__PURE__ */ jsx3("option", { value: "updatedAt:desc", children: updatedNewestLabel }),
|
|
164
|
+
/* @__PURE__ */ jsx3("option", { value: "updatedAt:asc", children: updatedOldestLabel }),
|
|
165
|
+
/* @__PURE__ */ jsx3("option", { value: "savedAt:desc", children: savedNewestLabel }),
|
|
166
|
+
/* @__PURE__ */ jsx3("option", { value: "savedAt:asc", children: savedOldestLabel })
|
|
167
|
+
] });
|
|
168
|
+
return /* @__PURE__ */ jsx3(
|
|
169
|
+
"select",
|
|
170
|
+
{
|
|
171
|
+
...props,
|
|
172
|
+
value,
|
|
173
|
+
"aria-label": ariaLabel ?? label,
|
|
174
|
+
onChange: (event) => {
|
|
175
|
+
const nextValue = event.currentTarget.value;
|
|
176
|
+
if (controlledValue === void 0) setUncontrolledValue(nextValue);
|
|
177
|
+
const [by, direction] = nextValue.split(":");
|
|
178
|
+
onValueChange?.(nextValue, { by, direction });
|
|
179
|
+
},
|
|
180
|
+
children: options
|
|
181
|
+
}
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
function KeepPagination({
|
|
185
|
+
totalCount,
|
|
186
|
+
pageSize,
|
|
187
|
+
page = 1,
|
|
188
|
+
maxPageButtons = 7,
|
|
189
|
+
onPageChange,
|
|
190
|
+
render,
|
|
191
|
+
...props
|
|
192
|
+
}) {
|
|
193
|
+
const previousPageLabel = useUiLabel("previousPage");
|
|
194
|
+
const nextPageLabel = useUiLabel("nextPage");
|
|
195
|
+
const pageLabel = useUiLabel("page");
|
|
196
|
+
const paginationLabel = useUiLabel("pagination");
|
|
197
|
+
const pageCount = Math.max(1, Math.ceil(totalCount / Math.max(1, pageSize)));
|
|
198
|
+
const currentPage = Math.min(Math.max(1, page), pageCount);
|
|
199
|
+
const goToPage = (nextPage) => {
|
|
200
|
+
const next = Math.min(Math.max(1, nextPage), pageCount);
|
|
201
|
+
onPageChange?.(next, (next - 1) * pageSize);
|
|
202
|
+
};
|
|
203
|
+
const navProps = { ...props, "aria-label": props["aria-label"] ?? paginationLabel };
|
|
204
|
+
if (render) return /* @__PURE__ */ jsx3("nav", { ...navProps, children: render({ page: currentPage, pageCount, goToPage }) });
|
|
205
|
+
const visiblePages = getVisiblePages(currentPage, pageCount, Math.max(1, maxPageButtons));
|
|
206
|
+
return /* @__PURE__ */ jsxs("nav", { ...navProps, children: [
|
|
207
|
+
/* @__PURE__ */ jsx3("button", { type: "button", onClick: () => goToPage(currentPage - 1), disabled: currentPage <= 1, children: previousPageLabel }),
|
|
208
|
+
visiblePages.map((nextPage) => /* @__PURE__ */ jsx3(
|
|
209
|
+
"button",
|
|
210
|
+
{
|
|
211
|
+
type: "button",
|
|
212
|
+
"aria-current": nextPage === currentPage ? "page" : void 0,
|
|
213
|
+
"aria-label": `${pageLabel} ${nextPage}`,
|
|
214
|
+
onClick: () => goToPage(nextPage),
|
|
215
|
+
children: nextPage
|
|
216
|
+
},
|
|
217
|
+
nextPage
|
|
218
|
+
)),
|
|
219
|
+
/* @__PURE__ */ jsx3("button", { type: "button", onClick: () => goToPage(currentPage + 1), disabled: currentPage >= pageCount, children: nextPageLabel })
|
|
220
|
+
] });
|
|
221
|
+
}
|
|
222
|
+
function getVisiblePages(currentPage, pageCount, maxPageButtons) {
|
|
223
|
+
if (pageCount <= maxPageButtons) return Array.from({ length: pageCount }, (_, index) => index + 1);
|
|
224
|
+
const half = Math.floor(maxPageButtons / 2);
|
|
225
|
+
const start = Math.min(Math.max(1, currentPage - half), pageCount - maxPageButtons + 1);
|
|
226
|
+
return Array.from({ length: maxPageButtons }, (_, index) => start + index);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// src/index.tsx
|
|
230
|
+
import { KeepProvider, useKeepContext as useKeepContext2, useKeepItem as useKeepItem2, useKeepList as useKeepList2, useKeepShortcut } from "@keepkit/core/react";
|
|
231
|
+
import {
|
|
232
|
+
createBrowserStorageAdapter,
|
|
233
|
+
createStorageAdapter,
|
|
234
|
+
FallbackStorageAdapter,
|
|
235
|
+
IndexedDBAdapter,
|
|
236
|
+
IndexedDBSyncQueueAdapter,
|
|
237
|
+
LocalStorageAdapter,
|
|
238
|
+
LocalStorageSyncQueueAdapter,
|
|
239
|
+
SyncStorageAdapter
|
|
240
|
+
} from "@keepkit/core/storage";
|
|
241
|
+
import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
242
|
+
function KeepKitProvider({
|
|
243
|
+
labels,
|
|
244
|
+
locale,
|
|
245
|
+
labelResolver,
|
|
246
|
+
children,
|
|
247
|
+
...providerProps
|
|
248
|
+
}) {
|
|
249
|
+
return /* @__PURE__ */ jsx4(KeepUiProvider, { labels, locale, labelResolver, children: /* @__PURE__ */ jsxs2(CoreKeepProvider, { ...providerProps, children: [
|
|
250
|
+
children,
|
|
251
|
+
/* @__PURE__ */ jsx4(KeepAnnouncements, {})
|
|
252
|
+
] }) });
|
|
253
|
+
}
|
|
254
|
+
function createKeepKit(options = {}) {
|
|
255
|
+
const { labels, locale, labelResolver, getTitle, getImageProps, ...coreOptions } = options;
|
|
256
|
+
const coreKit = createCoreKeepKit(coreOptions);
|
|
257
|
+
return {
|
|
258
|
+
Provider: (props) => /* @__PURE__ */ jsx4(
|
|
259
|
+
KeepKitProvider,
|
|
260
|
+
{
|
|
261
|
+
...coreOptions,
|
|
262
|
+
labels,
|
|
263
|
+
locale,
|
|
264
|
+
labelResolver,
|
|
265
|
+
...props
|
|
266
|
+
}
|
|
267
|
+
),
|
|
268
|
+
Button: (props) => /* @__PURE__ */ jsx4(KeepButton, { ...props }),
|
|
269
|
+
Collection: (props) => /* @__PURE__ */ jsx4(
|
|
270
|
+
KeepCollection,
|
|
271
|
+
{
|
|
272
|
+
...props,
|
|
273
|
+
itemCardProps: {
|
|
274
|
+
...getTitle ? { getTitle } : {},
|
|
275
|
+
...getImageProps ? { getImageProps } : {},
|
|
276
|
+
...props.itemCardProps
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
),
|
|
280
|
+
useContext: () => coreKit.useContext(),
|
|
281
|
+
useItem: (item) => coreKit.useItem(item),
|
|
282
|
+
useList: (query) => coreKit.useList(query),
|
|
283
|
+
useShortcut: (shortcutOptions) => coreKit.useShortcut(shortcutOptions)
|
|
284
|
+
};
|
|
285
|
+
}
|
|
70
286
|
function KeepButton({ labels, ...props }) {
|
|
71
287
|
const saveLabel = useUiLabel("save", typeof labels?.unsaved === "string" ? labels.unsaved : void 0);
|
|
72
288
|
const savedLabel = useUiLabel("saved", typeof labels?.saved === "string" ? labels.saved : void 0);
|
|
73
289
|
const loadingLabel = useUiLabel("loading", typeof labels?.loading === "string" ? labels.loading : void 0);
|
|
74
290
|
const errorLabel = useUiLabel("error", typeof labels?.error === "string" ? labels.error : void 0);
|
|
75
|
-
const buttonState = useKeepItem(props.item
|
|
76
|
-
meta: props.item.meta,
|
|
77
|
-
targetType: props.item.targetType,
|
|
78
|
-
note: props.item.note,
|
|
79
|
-
tags: props.item.tags
|
|
80
|
-
});
|
|
291
|
+
const buttonState = useKeepItem(props.item);
|
|
81
292
|
const customStateLabel = labels?.loading !== void 0 || labels?.error !== void 0;
|
|
82
293
|
const getStateContent = (state) => {
|
|
83
294
|
if (state.error) return labels?.error ?? errorLabel;
|
|
@@ -90,33 +301,34 @@ function KeepButton({ labels, ...props }) {
|
|
|
90
301
|
const sharedProps2 = {
|
|
91
302
|
...props,
|
|
92
303
|
"aria-busy": props["aria-busy"] ?? (buttonState.isLoading || buttonState.isMutating),
|
|
93
|
-
savedLabel: labels?.saved ?? savedLabel,
|
|
94
|
-
unsavedLabel: labels?.unsaved ?? saveLabel,
|
|
304
|
+
savedLabel: labels?.saved ?? props.savedLabel ?? savedLabel,
|
|
305
|
+
unsavedLabel: labels?.unsaved ?? props.unsavedLabel ?? saveLabel,
|
|
95
306
|
savedAriaLabel: labels?.savedAriaLabel ?? props.savedAriaLabel,
|
|
96
307
|
unsavedAriaLabel: labels?.unsavedAriaLabel ?? props.unsavedAriaLabel
|
|
97
308
|
};
|
|
98
|
-
if (!customStateLabel) return /* @__PURE__ */
|
|
309
|
+
if (!customStateLabel) return /* @__PURE__ */ jsx4(CoreKeepButton, { ...sharedProps2 });
|
|
99
310
|
const statefulProps2 = {
|
|
100
311
|
...sharedProps2,
|
|
101
|
-
children: (state) => /* @__PURE__ */
|
|
312
|
+
children: (state) => /* @__PURE__ */ jsx4(Fragment2, { children: getStateContent(state) })
|
|
102
313
|
};
|
|
103
|
-
return /* @__PURE__ */
|
|
314
|
+
return /* @__PURE__ */ jsx4(CoreKeepButton, { ...statefulProps2 });
|
|
104
315
|
}
|
|
105
316
|
const sharedProps = {
|
|
106
317
|
...props,
|
|
107
318
|
"aria-busy": props["aria-busy"] ?? (buttonState.isLoading || buttonState.isMutating),
|
|
108
|
-
savedLabel: labels?.saved ?? savedLabel,
|
|
109
|
-
unsavedLabel: labels?.unsaved ?? saveLabel,
|
|
319
|
+
savedLabel: labels?.saved ?? props.savedLabel ?? savedLabel,
|
|
320
|
+
unsavedLabel: labels?.unsaved ?? props.unsavedLabel ?? saveLabel,
|
|
110
321
|
savedAriaLabel: labels?.savedAriaLabel ?? props.savedAriaLabel,
|
|
111
322
|
unsavedAriaLabel: labels?.unsavedAriaLabel ?? props.unsavedAriaLabel
|
|
112
323
|
};
|
|
113
|
-
if (!customStateLabel) return /* @__PURE__ */
|
|
324
|
+
if (!customStateLabel) return /* @__PURE__ */ jsx4(CoreKeepButton, { ...sharedProps });
|
|
114
325
|
const statefulProps = { ...sharedProps, children: (state) => getStateContent(state) };
|
|
115
|
-
return /* @__PURE__ */
|
|
326
|
+
return /* @__PURE__ */ jsx4(CoreKeepButton, { ...statefulProps });
|
|
116
327
|
}
|
|
117
328
|
function KeepItemCard({
|
|
118
329
|
item,
|
|
119
330
|
title,
|
|
331
|
+
getTitle,
|
|
120
332
|
getImageProps,
|
|
121
333
|
imageComponent: ImageComponent,
|
|
122
334
|
renderImage,
|
|
@@ -134,7 +346,7 @@ function KeepItemCard({
|
|
|
134
346
|
}) {
|
|
135
347
|
const saveActionLabel = useUiLabel("save");
|
|
136
348
|
const removeActionLabel = useUiLabel("remove");
|
|
137
|
-
const itemState = useKeepItem(item
|
|
349
|
+
const itemState = useKeepItem(item);
|
|
138
350
|
const contentChildren = asChild && isValidElement(children) ? void 0 : children;
|
|
139
351
|
const state = {
|
|
140
352
|
item,
|
|
@@ -143,7 +355,7 @@ function KeepItemCard({
|
|
|
143
355
|
error: itemState.error,
|
|
144
356
|
remove: itemState.remove
|
|
145
357
|
};
|
|
146
|
-
const resolvedTitle = typeof title === "function" ? title(item) : title ?? getMetaTitle(item.meta) ?? item.id;
|
|
358
|
+
const resolvedTitle = typeof title === "function" ? title(item) : title ?? getTitle?.(item) ?? getMetaTitle(item.meta) ?? item.id;
|
|
147
359
|
const imageProps = getImageProps?.(item, resolvedTitle);
|
|
148
360
|
async function handleRemove() {
|
|
149
361
|
try {
|
|
@@ -153,10 +365,10 @@ function KeepItemCard({
|
|
|
153
365
|
onRemoveError?.(error);
|
|
154
366
|
}
|
|
155
367
|
}
|
|
156
|
-
const body = render ? render(state) : typeof contentChildren === "function" ? contentChildren(state) : contentChildren ?? /* @__PURE__ */
|
|
157
|
-
imageProps ? renderImage?.({ ...imageProps, alt: imageAlt ?? imageProps.alt }, item) ?? (ImageComponent ? /* @__PURE__ */
|
|
158
|
-
/* @__PURE__ */
|
|
159
|
-
showSaveButton ? /* @__PURE__ */
|
|
368
|
+
const body = render ? render(state) : typeof contentChildren === "function" ? contentChildren(state) : contentChildren ?? /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
369
|
+
imageProps ? renderImage?.({ ...imageProps, alt: imageAlt ?? imageProps.alt }, item) ?? (ImageComponent ? /* @__PURE__ */ jsx4(ImageComponent, { ...imageProps, alt: imageAlt ?? imageProps.alt }) : /* @__PURE__ */ jsx4("img", { ...imageProps, alt: imageAlt ?? imageProps.alt })) : null,
|
|
370
|
+
/* @__PURE__ */ jsx4("h3", { children: resolvedTitle }),
|
|
371
|
+
showSaveButton ? /* @__PURE__ */ jsx4(
|
|
160
372
|
KeepButton,
|
|
161
373
|
{
|
|
162
374
|
item: toKeepButtonItem(item),
|
|
@@ -164,7 +376,7 @@ function KeepItemCard({
|
|
|
164
376
|
getAriaLabel: (buttonState) => `${buttonState.isSaved ? removeActionLabel : saveActionLabel} ${String(resolvedTitle)}`
|
|
165
377
|
}
|
|
166
378
|
) : null,
|
|
167
|
-
/* @__PURE__ */
|
|
379
|
+
/* @__PURE__ */ jsx4("button", { type: "button", onClick: () => void handleRemove(), disabled: itemState.isMutating, children: removeLabel ?? removeActionLabel })
|
|
168
380
|
] });
|
|
169
381
|
return renderRoot(
|
|
170
382
|
asChild,
|
|
@@ -175,7 +387,7 @@ function KeepItemCard({
|
|
|
175
387
|
);
|
|
176
388
|
}
|
|
177
389
|
function KeepList({
|
|
178
|
-
|
|
390
|
+
query,
|
|
179
391
|
children,
|
|
180
392
|
renderItem,
|
|
181
393
|
loading,
|
|
@@ -189,7 +401,7 @@ function KeepList({
|
|
|
189
401
|
const defaultLoading = useUiLabel("loadingItems");
|
|
190
402
|
const defaultEmpty = useUiLabel("noItems");
|
|
191
403
|
const defaultError = useUiLabel("errorItems");
|
|
192
|
-
const state = useKeepList(
|
|
404
|
+
const state = useKeepList(query);
|
|
193
405
|
const body = getListBody(state, {
|
|
194
406
|
children,
|
|
195
407
|
renderItem,
|
|
@@ -214,12 +426,90 @@ function getListBody(state, options) {
|
|
|
214
426
|
if (typeof options.children === "function") return options.children(state);
|
|
215
427
|
if (options.children !== void 0 && !isValidElement(options.children)) return options.children;
|
|
216
428
|
const items = state.items.map(
|
|
217
|
-
(item) => options.renderItem ? options.renderItem(item, state) : /* @__PURE__ */
|
|
429
|
+
(item) => options.renderItem ? options.renderItem(item, state) : /* @__PURE__ */ jsx4("li", { children: /* @__PURE__ */ jsx4(KeepItemCard, { item, ...options.itemCardProps }) }, item.id)
|
|
430
|
+
);
|
|
431
|
+
return /* @__PURE__ */ jsx4("ul", { children: items });
|
|
432
|
+
}
|
|
433
|
+
function KeepCollection({
|
|
434
|
+
query = {},
|
|
435
|
+
pageSize = 20,
|
|
436
|
+
features,
|
|
437
|
+
renderItem,
|
|
438
|
+
itemCardProps,
|
|
439
|
+
loading,
|
|
440
|
+
empty,
|
|
441
|
+
error,
|
|
442
|
+
className,
|
|
443
|
+
...rootProps
|
|
444
|
+
}) {
|
|
445
|
+
const enabled = {
|
|
446
|
+
search: true,
|
|
447
|
+
sort: true,
|
|
448
|
+
pagination: true,
|
|
449
|
+
tagFilter: false,
|
|
450
|
+
bulkActions: false,
|
|
451
|
+
...features
|
|
452
|
+
};
|
|
453
|
+
const [searchValue, setSearchValue] = useState2(query.search?.query ?? "");
|
|
454
|
+
const [sort, setSort] = useState2(query.sort ?? { by: "updatedAt", direction: "desc" });
|
|
455
|
+
const [tag, setTag] = useState2(query.tags?.[0]);
|
|
456
|
+
const [page, setPage] = useState2(query.pagination?.page ?? 1);
|
|
457
|
+
const resolvedPageSize = query.pagination?.pageSize ?? pageSize;
|
|
458
|
+
const resolvedQuery = useMemo2(
|
|
459
|
+
() => ({
|
|
460
|
+
...query,
|
|
461
|
+
search: enabled.search ? { ...query.search, query: searchValue } : query.search,
|
|
462
|
+
sort: enabled.sort ? sort : query.sort,
|
|
463
|
+
tags: tag ? [.../* @__PURE__ */ new Set([...query.tags ?? [], tag])] : query.tags,
|
|
464
|
+
pagination: enabled.pagination ? { ...query.pagination, page, pageSize: resolvedPageSize } : query.pagination
|
|
465
|
+
}),
|
|
466
|
+
[enabled.pagination, enabled.search, enabled.sort, page, query, resolvedPageSize, searchValue, sort, tag]
|
|
467
|
+
);
|
|
468
|
+
const list = useKeepList(resolvedQuery);
|
|
469
|
+
useEffect2(() => {
|
|
470
|
+
if (searchValue !== void 0 || sort.by !== void 0 || sort.direction !== void 0 || tag !== void 0) {
|
|
471
|
+
setPage(1);
|
|
472
|
+
}
|
|
473
|
+
}, [searchValue, sort.by, sort.direction, tag]);
|
|
474
|
+
return /* @__PURE__ */ jsxs2(
|
|
475
|
+
"section",
|
|
476
|
+
{
|
|
477
|
+
...rootProps,
|
|
478
|
+
className,
|
|
479
|
+
"aria-busy": list.isLoading || list.isMutating || rootProps["aria-busy"],
|
|
480
|
+
children: [
|
|
481
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
482
|
+
enabled.search ? /* @__PURE__ */ jsx4(KeepSearchInput, { value: searchValue, onValueChange: setSearchValue }) : null,
|
|
483
|
+
enabled.sort ? /* @__PURE__ */ jsx4(KeepSortSelect, { value: sortToValue(sort), onValueChange: (_value, nextSort) => setSort(nextSort) }) : null,
|
|
484
|
+
enabled.tagFilter ? /* @__PURE__ */ jsx4(KeepTagFilter, { query, value: tag, onValueChange: setTag }) : null
|
|
485
|
+
] }),
|
|
486
|
+
/* @__PURE__ */ jsx4(
|
|
487
|
+
KeepList,
|
|
488
|
+
{
|
|
489
|
+
query: resolvedQuery,
|
|
490
|
+
renderItem,
|
|
491
|
+
itemCardProps,
|
|
492
|
+
loading,
|
|
493
|
+
empty,
|
|
494
|
+
error
|
|
495
|
+
}
|
|
496
|
+
),
|
|
497
|
+
enabled.pagination ? /* @__PURE__ */ jsx4(
|
|
498
|
+
KeepPagination,
|
|
499
|
+
{
|
|
500
|
+
totalCount: list.totalCount,
|
|
501
|
+
pageSize: resolvedPageSize,
|
|
502
|
+
page: list.page,
|
|
503
|
+
onPageChange: (_nextPage, nextPageOffset) => setPage(Math.floor(nextPageOffset / resolvedPageSize) + 1)
|
|
504
|
+
}
|
|
505
|
+
) : null,
|
|
506
|
+
enabled.bulkActions ? /* @__PURE__ */ jsx4(KeepBulkActions, { query: resolvedQuery }) : null
|
|
507
|
+
]
|
|
508
|
+
}
|
|
218
509
|
);
|
|
219
|
-
return /* @__PURE__ */ jsx("ul", { children: items });
|
|
220
510
|
}
|
|
221
511
|
function KeepTagFilter({
|
|
222
|
-
|
|
512
|
+
query,
|
|
223
513
|
value: controlledValue,
|
|
224
514
|
defaultValue,
|
|
225
515
|
onChange,
|
|
@@ -237,10 +527,10 @@ function KeepTagFilter({
|
|
|
237
527
|
const uiAriaLabel = useUiLabel("filterTags");
|
|
238
528
|
const defaultAllLabel = allLabel ?? uiAllLabel;
|
|
239
529
|
const defaultAriaLabel = ariaLabel ?? uiAriaLabel;
|
|
240
|
-
const list = useKeepList(listOptions);
|
|
241
530
|
const contentChildren = asChild && isValidElement(children) ? void 0 : children;
|
|
242
|
-
const [uncontrolledValue, setUncontrolledValue] =
|
|
531
|
+
const [uncontrolledValue, setUncontrolledValue] = useState2(defaultValue);
|
|
243
532
|
const value = controlledValue ?? uncontrolledValue;
|
|
533
|
+
const list = useKeepList({ ...query, tags: value ? [...query?.tags ?? [], value] : query?.tags });
|
|
244
534
|
const select = useCallback(
|
|
245
535
|
(tag) => {
|
|
246
536
|
if (controlledValue === void 0) setUncontrolledValue(tag);
|
|
@@ -249,16 +539,16 @@ function KeepTagFilter({
|
|
|
249
539
|
},
|
|
250
540
|
[controlledValue, onChange, onValueChange]
|
|
251
541
|
);
|
|
252
|
-
const state =
|
|
542
|
+
const state = useMemo2(
|
|
253
543
|
() => ({ tags: list.tags, tagCounts: list.tagCounts, value, select }),
|
|
254
544
|
[list.tagCounts, list.tags, select, value]
|
|
255
545
|
);
|
|
256
|
-
const body = render ? render(state) : typeof contentChildren === "function" ? contentChildren(state) : contentChildren ?? /* @__PURE__ */
|
|
257
|
-
/* @__PURE__ */
|
|
258
|
-
/* @__PURE__ */
|
|
259
|
-
list.tags.map((tag) => /* @__PURE__ */
|
|
546
|
+
const body = render ? render(state) : typeof contentChildren === "function" ? contentChildren(state) : contentChildren ?? /* @__PURE__ */ jsxs2("fieldset", { children: [
|
|
547
|
+
/* @__PURE__ */ jsx4("legend", { children: defaultAriaLabel }),
|
|
548
|
+
/* @__PURE__ */ jsx4("button", { type: "button", "aria-pressed": value === void 0, onClick: () => select(), children: defaultAllLabel }),
|
|
549
|
+
list.tags.map((tag) => /* @__PURE__ */ jsxs2("button", { type: "button", "aria-pressed": value === tag, onClick: () => select(tag), children: [
|
|
260
550
|
renderTag ? renderTag(tag, list.tagCounts[tag] ?? 0, value === tag) : tag,
|
|
261
|
-
/* @__PURE__ */
|
|
551
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
262
552
|
" (",
|
|
263
553
|
list.tagCounts[tag] ?? 0,
|
|
264
554
|
")"
|
|
@@ -288,10 +578,10 @@ function KeepNoteEditor({
|
|
|
288
578
|
}) {
|
|
289
579
|
const defaultLabel = useUiLabel("note");
|
|
290
580
|
const defaultSaveLabel = useUiLabel("saveNote");
|
|
291
|
-
const itemState = useKeepItem(item
|
|
581
|
+
const itemState = useKeepItem(item);
|
|
292
582
|
const contentChildren = asChild && isValidElement(children) ? void 0 : children;
|
|
293
|
-
const [note, setNote] =
|
|
294
|
-
|
|
583
|
+
const [note, setNote] = useState2(item.note ?? "");
|
|
584
|
+
useEffect2(() => setNote(itemState.item?.note ?? item.note ?? ""), [item.note, itemState.item?.note]);
|
|
295
585
|
const save = useCallback(async () => {
|
|
296
586
|
const nextNote = note.trim() || void 0;
|
|
297
587
|
try {
|
|
@@ -311,10 +601,10 @@ function KeepNoteEditor({
|
|
|
311
601
|
error: itemState.error,
|
|
312
602
|
save
|
|
313
603
|
};
|
|
314
|
-
const body = render ? render(state) : typeof contentChildren === "function" ? contentChildren(state) : contentChildren ?? /* @__PURE__ */
|
|
315
|
-
/* @__PURE__ */
|
|
604
|
+
const body = render ? render(state) : typeof contentChildren === "function" ? contentChildren(state) : contentChildren ?? /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
605
|
+
/* @__PURE__ */ jsxs2("label", { children: [
|
|
316
606
|
label ?? defaultLabel,
|
|
317
|
-
/* @__PURE__ */
|
|
607
|
+
/* @__PURE__ */ jsx4(
|
|
318
608
|
"textarea",
|
|
319
609
|
{
|
|
320
610
|
value: note,
|
|
@@ -324,14 +614,14 @@ function KeepNoteEditor({
|
|
|
324
614
|
}
|
|
325
615
|
)
|
|
326
616
|
] }),
|
|
327
|
-
/* @__PURE__ */
|
|
617
|
+
/* @__PURE__ */ jsx4("button", { type: "submit", disabled: itemState.isMutating, "aria-busy": itemState.isMutating, children: saveLabel ?? defaultSaveLabel })
|
|
328
618
|
] });
|
|
329
619
|
const handleSubmit = (event) => {
|
|
330
620
|
event.preventDefault();
|
|
331
621
|
void save().catch(() => void 0);
|
|
332
622
|
};
|
|
333
623
|
if (!asChild) {
|
|
334
|
-
return /* @__PURE__ */
|
|
624
|
+
return /* @__PURE__ */ jsx4(
|
|
335
625
|
"form",
|
|
336
626
|
{
|
|
337
627
|
...formProps,
|
|
@@ -350,100 +640,6 @@ function KeepNoteEditor({
|
|
|
350
640
|
"KeepNoteEditor"
|
|
351
641
|
);
|
|
352
642
|
}
|
|
353
|
-
function KeepSearchInput({
|
|
354
|
-
value: controlledValue,
|
|
355
|
-
defaultValue = "",
|
|
356
|
-
onValueChange,
|
|
357
|
-
"aria-label": ariaLabel,
|
|
358
|
-
placeholder,
|
|
359
|
-
...props
|
|
360
|
-
}) {
|
|
361
|
-
const label = useUiLabel("search");
|
|
362
|
-
const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
|
|
363
|
-
const value = controlledValue ?? uncontrolledValue;
|
|
364
|
-
return /* @__PURE__ */ jsx(
|
|
365
|
-
"input",
|
|
366
|
-
{
|
|
367
|
-
...props,
|
|
368
|
-
type: "search",
|
|
369
|
-
value,
|
|
370
|
-
"aria-label": ariaLabel ?? label,
|
|
371
|
-
placeholder: placeholder ?? label,
|
|
372
|
-
onChange: (event) => {
|
|
373
|
-
const nextValue = event.currentTarget.value;
|
|
374
|
-
if (controlledValue === void 0) setUncontrolledValue(nextValue);
|
|
375
|
-
onValueChange?.(nextValue);
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
);
|
|
379
|
-
}
|
|
380
|
-
function KeepSortSelect({
|
|
381
|
-
value: controlledValue,
|
|
382
|
-
defaultValue = "updatedAt:desc",
|
|
383
|
-
onValueChange,
|
|
384
|
-
"aria-label": ariaLabel,
|
|
385
|
-
children,
|
|
386
|
-
...props
|
|
387
|
-
}) {
|
|
388
|
-
const label = useUiLabel("sort");
|
|
389
|
-
const newestLabel = useUiLabel("newest");
|
|
390
|
-
const savedLabel = useUiLabel("saved");
|
|
391
|
-
const oldestLabel = useUiLabel("oldest");
|
|
392
|
-
const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
|
|
393
|
-
const value = controlledValue ?? uncontrolledValue;
|
|
394
|
-
const options = children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
395
|
-
/* @__PURE__ */ jsx("option", { value: "updatedAt:desc", children: newestLabel }),
|
|
396
|
-
/* @__PURE__ */ jsx("option", { value: "savedAt:desc", children: savedLabel }),
|
|
397
|
-
/* @__PURE__ */ jsx("option", { value: "updatedAt:asc", children: oldestLabel }),
|
|
398
|
-
/* @__PURE__ */ jsx("option", { value: "savedAt:asc", children: oldestLabel })
|
|
399
|
-
] });
|
|
400
|
-
return /* @__PURE__ */ jsx(
|
|
401
|
-
"select",
|
|
402
|
-
{
|
|
403
|
-
...props,
|
|
404
|
-
value,
|
|
405
|
-
"aria-label": ariaLabel ?? label,
|
|
406
|
-
onChange: (event) => {
|
|
407
|
-
const nextValue = event.currentTarget.value;
|
|
408
|
-
if (controlledValue === void 0) setUncontrolledValue(nextValue);
|
|
409
|
-
const [by, direction] = nextValue.split(":");
|
|
410
|
-
onValueChange?.(nextValue, { by, direction });
|
|
411
|
-
},
|
|
412
|
-
children: options
|
|
413
|
-
}
|
|
414
|
-
);
|
|
415
|
-
}
|
|
416
|
-
function KeepPagination({
|
|
417
|
-
totalCount,
|
|
418
|
-
pageSize,
|
|
419
|
-
page = 1,
|
|
420
|
-
onPageChange,
|
|
421
|
-
render,
|
|
422
|
-
...props
|
|
423
|
-
}) {
|
|
424
|
-
const previousPageLabel = useUiLabel("previousPage");
|
|
425
|
-
const nextPageLabel = useUiLabel("nextPage");
|
|
426
|
-
const pageLabel = useUiLabel("page");
|
|
427
|
-
const paginationLabel = useUiLabel("pagination");
|
|
428
|
-
const pageCount = Math.max(1, Math.ceil(totalCount / Math.max(1, pageSize)));
|
|
429
|
-
const currentPage = Math.min(Math.max(1, page), pageCount);
|
|
430
|
-
const goToPage = (nextPage) => {
|
|
431
|
-
const next = Math.min(Math.max(1, nextPage), pageCount);
|
|
432
|
-
onPageChange?.(next, (next - 1) * pageSize);
|
|
433
|
-
};
|
|
434
|
-
if (render) return /* @__PURE__ */ jsx("nav", { ...props, children: render({ page: currentPage, pageCount, goToPage }) });
|
|
435
|
-
return /* @__PURE__ */ jsxs("nav", { ...props, "aria-label": props["aria-label"] ?? paginationLabel, children: [
|
|
436
|
-
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => goToPage(currentPage - 1), disabled: currentPage <= 1, children: previousPageLabel }),
|
|
437
|
-
/* @__PURE__ */ jsxs("span", { "aria-current": "page", children: [
|
|
438
|
-
pageLabel,
|
|
439
|
-
" ",
|
|
440
|
-
currentPage,
|
|
441
|
-
" / ",
|
|
442
|
-
pageCount
|
|
443
|
-
] }),
|
|
444
|
-
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => goToPage(currentPage + 1), disabled: currentPage >= pageCount, children: nextPageLabel })
|
|
445
|
-
] });
|
|
446
|
-
}
|
|
447
643
|
function KeepTagEditor({
|
|
448
644
|
item,
|
|
449
645
|
availableTags = [],
|
|
@@ -455,10 +651,10 @@ function KeepTagEditor({
|
|
|
455
651
|
const tagsLabel = useUiLabel("tagsToApply");
|
|
456
652
|
const removeLabel = useUiLabel("remove");
|
|
457
653
|
const applyTagsLabel = useUiLabel("applyTags");
|
|
458
|
-
const itemState = useKeepItem(item
|
|
459
|
-
const [tags, setTags] =
|
|
460
|
-
const [input, setInput] =
|
|
461
|
-
|
|
654
|
+
const itemState = useKeepItem(item);
|
|
655
|
+
const [tags, setTags] = useState2(item.tags ?? []);
|
|
656
|
+
const [input, setInput] = useState2("");
|
|
657
|
+
useEffect2(() => setTags(itemState.item?.tags ?? item.tags ?? []), [item.tags, itemState.item?.tags]);
|
|
462
658
|
const save = useCallback(async () => {
|
|
463
659
|
const nextTags = normalizeUiTags(tags);
|
|
464
660
|
try {
|
|
@@ -475,10 +671,10 @@ function KeepTagEditor({
|
|
|
475
671
|
setTags(next);
|
|
476
672
|
setInput("");
|
|
477
673
|
};
|
|
478
|
-
const body = render ? render({ tags, setTags, save, isSaving: itemState.isMutating }) : /* @__PURE__ */
|
|
479
|
-
/* @__PURE__ */
|
|
674
|
+
const body = render ? render({ tags, setTags, save, isSaving: itemState.isMutating }) : /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
675
|
+
/* @__PURE__ */ jsxs2("label", { children: [
|
|
480
676
|
tagsLabel,
|
|
481
|
-
/* @__PURE__ */
|
|
677
|
+
/* @__PURE__ */ jsx4(
|
|
482
678
|
"input",
|
|
483
679
|
{
|
|
484
680
|
value: input,
|
|
@@ -488,19 +684,22 @@ function KeepTagEditor({
|
|
|
488
684
|
if (event.key === "Enter") {
|
|
489
685
|
event.preventDefault();
|
|
490
686
|
if (input.trim()) addTag(input);
|
|
687
|
+
} else if (event.key === "Backspace" && input.length === 0 && tags.length > 0) {
|
|
688
|
+
event.preventDefault();
|
|
689
|
+
setTags(tags.slice(0, -1));
|
|
491
690
|
}
|
|
492
691
|
}
|
|
493
692
|
}
|
|
494
693
|
)
|
|
495
694
|
] }),
|
|
496
|
-
availableTags.length > 0 ? /* @__PURE__ */
|
|
497
|
-
/* @__PURE__ */
|
|
695
|
+
availableTags.length > 0 ? /* @__PURE__ */ jsx4("datalist", { id: `keep-tags-${item.id}`, children: availableTags.map((tag) => /* @__PURE__ */ jsx4("option", { value: tag }, tag)) }) : null,
|
|
696
|
+
/* @__PURE__ */ jsx4("ul", { "aria-label": tagsLabel, children: tags.map((tag) => /* @__PURE__ */ jsxs2("li", { children: [
|
|
498
697
|
tag,
|
|
499
|
-
/* @__PURE__ */
|
|
698
|
+
/* @__PURE__ */ jsx4("button", { type: "button", onClick: () => setTags(tags.filter((current) => current !== tag)), children: removeLabel })
|
|
500
699
|
] }, tag)) }),
|
|
501
|
-
/* @__PURE__ */
|
|
700
|
+
/* @__PURE__ */ jsx4("button", { type: "submit", disabled: itemState.isMutating, "aria-busy": itemState.isMutating, children: applyTagsLabel })
|
|
502
701
|
] });
|
|
503
|
-
return /* @__PURE__ */
|
|
702
|
+
return /* @__PURE__ */ jsx4(
|
|
504
703
|
"form",
|
|
505
704
|
{
|
|
506
705
|
...props,
|
|
@@ -514,12 +713,14 @@ function KeepTagEditor({
|
|
|
514
713
|
);
|
|
515
714
|
}
|
|
516
715
|
function KeepBulkActions({
|
|
517
|
-
|
|
716
|
+
query,
|
|
518
717
|
selectedIds: controlledSelectedIds,
|
|
519
718
|
defaultSelectedIds = [],
|
|
520
719
|
onSelectedIdsChange,
|
|
521
720
|
renderItem,
|
|
522
721
|
onCompleted,
|
|
722
|
+
render,
|
|
723
|
+
children,
|
|
523
724
|
...props
|
|
524
725
|
}) {
|
|
525
726
|
const selectItemsLabel = useUiLabel("selectItems");
|
|
@@ -527,11 +728,11 @@ function KeepBulkActions({
|
|
|
527
728
|
const deleteSelectedLabel = useUiLabel("deleteSelected");
|
|
528
729
|
const tagsLabel = useUiLabel("tagsToApply");
|
|
529
730
|
const applyTagsLabel = useUiLabel("applyTags");
|
|
530
|
-
const list = useKeepList(
|
|
531
|
-
const [uncontrolledSelectedIds, setUncontrolledSelectedIds] =
|
|
731
|
+
const list = useKeepList(query);
|
|
732
|
+
const [uncontrolledSelectedIds, setUncontrolledSelectedIds] = useState2(defaultSelectedIds);
|
|
532
733
|
const selectedIds = controlledSelectedIds ?? uncontrolledSelectedIds;
|
|
533
734
|
const selected = new Set(selectedIds);
|
|
534
|
-
const [tagsInput, setTagsInput] =
|
|
735
|
+
const [tagsInput, setTagsInput] = useState2("");
|
|
535
736
|
const setSelectedIds = (ids) => {
|
|
536
737
|
if (controlledSelectedIds === void 0) setUncontrolledSelectedIds(ids);
|
|
537
738
|
onSelectedIdsChange?.(ids);
|
|
@@ -550,27 +751,56 @@ function KeepBulkActions({
|
|
|
550
751
|
onCompleted?.("tags", selectedIds);
|
|
551
752
|
setSelectedIds([]);
|
|
552
753
|
};
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
754
|
+
const state = {
|
|
755
|
+
items: list.items,
|
|
756
|
+
selectedIds,
|
|
757
|
+
selectedCount: selectedIds.length,
|
|
758
|
+
allSelected,
|
|
759
|
+
tagsInput,
|
|
760
|
+
setTagsInput,
|
|
761
|
+
toggle,
|
|
762
|
+
toggleAll,
|
|
763
|
+
remove,
|
|
764
|
+
updateTags,
|
|
765
|
+
isMutating: list.isMutating
|
|
766
|
+
};
|
|
767
|
+
const body = render ? render(state) : typeof children === "function" ? children(state) : children ?? /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
768
|
+
/* @__PURE__ */ jsxs2("fieldset", { children: [
|
|
769
|
+
/* @__PURE__ */ jsx4("legend", { children: selectItemsLabel }),
|
|
770
|
+
/* @__PURE__ */ jsxs2("label", { children: [
|
|
771
|
+
/* @__PURE__ */ jsx4("input", { type: "checkbox", checked: allSelected, onChange: toggleAll, "aria-label": selectItemsLabel }),
|
|
558
772
|
selectedIds.length,
|
|
559
773
|
" ",
|
|
560
774
|
selectedCountLabel
|
|
561
775
|
] }),
|
|
562
|
-
list.items.map((item) => /* @__PURE__ */
|
|
563
|
-
/* @__PURE__ */
|
|
776
|
+
list.items.map((item) => /* @__PURE__ */ jsxs2("span", { children: [
|
|
777
|
+
/* @__PURE__ */ jsx4(
|
|
778
|
+
KeepItemCheckbox,
|
|
779
|
+
{
|
|
780
|
+
item,
|
|
781
|
+
checked: selected.has(item.id),
|
|
782
|
+
onCheckedChange: () => toggle(item.id)
|
|
783
|
+
}
|
|
784
|
+
),
|
|
564
785
|
renderItem ? renderItem(item, selected.has(item.id)) : getMetaTitle(item.meta) ?? item.id
|
|
565
786
|
] }, item.id))
|
|
566
787
|
] }),
|
|
567
|
-
/* @__PURE__ */
|
|
568
|
-
/* @__PURE__ */
|
|
788
|
+
/* @__PURE__ */ jsx4("button", { type: "button", onClick: () => void remove(), disabled: selectedIds.length === 0 || list.isMutating, children: deleteSelectedLabel }),
|
|
789
|
+
/* @__PURE__ */ jsxs2("label", { children: [
|
|
569
790
|
tagsLabel,
|
|
570
|
-
/* @__PURE__ */
|
|
791
|
+
/* @__PURE__ */ jsx4("input", { value: tagsInput, onChange: (event) => setTagsInput(event.currentTarget.value) })
|
|
571
792
|
] }),
|
|
572
|
-
/* @__PURE__ */
|
|
793
|
+
/* @__PURE__ */ jsx4(
|
|
794
|
+
"button",
|
|
795
|
+
{
|
|
796
|
+
type: "button",
|
|
797
|
+
onClick: () => void updateTags(),
|
|
798
|
+
disabled: selectedIds.length === 0 || list.isMutating,
|
|
799
|
+
children: applyTagsLabel
|
|
800
|
+
}
|
|
801
|
+
)
|
|
573
802
|
] });
|
|
803
|
+
return /* @__PURE__ */ jsx4("section", { ...props, "aria-busy": list.isMutating || props["aria-busy"], children: body });
|
|
574
804
|
}
|
|
575
805
|
function KeepEmptyState({
|
|
576
806
|
title,
|
|
@@ -583,9 +813,9 @@ function KeepEmptyState({
|
|
|
583
813
|
}) {
|
|
584
814
|
const defaultTitle = useUiLabel("noItems").replace(/\.$/, "");
|
|
585
815
|
const contentChildren = asChild && isValidElement(children) ? void 0 : children;
|
|
586
|
-
const body = contentChildren ?? /* @__PURE__ */
|
|
587
|
-
/* @__PURE__ */
|
|
588
|
-
description ? /* @__PURE__ */
|
|
816
|
+
const body = contentChildren ?? /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
817
|
+
/* @__PURE__ */ jsx4("h2", { children: title ?? defaultTitle }),
|
|
818
|
+
description ? /* @__PURE__ */ jsx4("p", { children: description }) : null,
|
|
589
819
|
action
|
|
590
820
|
] });
|
|
591
821
|
return renderRoot(asChild, children, { ...rootProps, className }, body, "KeepEmptyState");
|
|
@@ -624,9 +854,9 @@ function KeepAnnouncements({ messages, ...props }) {
|
|
|
624
854
|
const savedMessage = useUiLabel("savedMessage", messages?.save);
|
|
625
855
|
const removedMessage = useUiLabel("removedMessage", messages?.remove);
|
|
626
856
|
const noteSavedMessage = useUiLabel("noteSavedMessage", messages?.note);
|
|
627
|
-
const [message, setMessage] =
|
|
857
|
+
const [message, setMessage] = useState2("");
|
|
628
858
|
const lastChangeRef = useRef(void 0);
|
|
629
|
-
|
|
859
|
+
useEffect2(() => {
|
|
630
860
|
const change = context.lastChange;
|
|
631
861
|
if (!change || change === lastChangeRef.current) return;
|
|
632
862
|
lastChangeRef.current = change;
|
|
@@ -634,7 +864,7 @@ function KeepAnnouncements({ messages, ...props }) {
|
|
|
634
864
|
else if (change.action === "remove" || change.action === "removeBatch") setMessage(removedMessage);
|
|
635
865
|
else if (change.action === "updateNote") setMessage(noteSavedMessage);
|
|
636
866
|
}, [context.lastChange, noteSavedMessage, removedMessage, savedMessage]);
|
|
637
|
-
return /* @__PURE__ */
|
|
867
|
+
return /* @__PURE__ */ jsx4("div", { ...props, role: props.role ?? "status", "aria-live": props["aria-live"] ?? "polite", "aria-atomic": "true", children: message });
|
|
638
868
|
}
|
|
639
869
|
function getDerivedStatus(context) {
|
|
640
870
|
if (context.error) return "error";
|
|
@@ -672,19 +902,28 @@ function getMetaTitle(meta) {
|
|
|
672
902
|
function normalizeUiTags(tags) {
|
|
673
903
|
return [...new Set(tags.map((tag) => tag.trim()).filter(Boolean))];
|
|
674
904
|
}
|
|
905
|
+
function sortToValue(sort) {
|
|
906
|
+
return `${sort?.by ?? "updatedAt"}:${sort?.direction ?? "desc"}`;
|
|
907
|
+
}
|
|
675
908
|
function renderRoot(asChild, child, props, body, componentName) {
|
|
676
909
|
if (asChild) {
|
|
677
910
|
if (!isValidElement(child)) throw new Error(`${componentName} with asChild requires a single React element child.`);
|
|
678
911
|
return cloneElement(child, { ...props, children: body });
|
|
679
912
|
}
|
|
680
|
-
return /* @__PURE__ */
|
|
913
|
+
return /* @__PURE__ */ jsx4("div", { ...props, children: body });
|
|
681
914
|
}
|
|
682
915
|
export {
|
|
916
|
+
FallbackStorageAdapter,
|
|
917
|
+
IndexedDBAdapter,
|
|
918
|
+
IndexedDBSyncQueueAdapter,
|
|
683
919
|
KeepAnnouncements,
|
|
684
920
|
KeepBulkActions,
|
|
685
921
|
KeepButton,
|
|
922
|
+
KeepCollection,
|
|
686
923
|
KeepEmptyState,
|
|
687
924
|
KeepItemCard,
|
|
925
|
+
KeepItemCheckbox,
|
|
926
|
+
KeepKitProvider,
|
|
688
927
|
KeepList,
|
|
689
928
|
KeepNoteEditor,
|
|
690
929
|
KeepPagination,
|
|
@@ -695,9 +934,16 @@ export {
|
|
|
695
934
|
KeepTagEditor,
|
|
696
935
|
KeepTagFilter,
|
|
697
936
|
KeepUiProvider,
|
|
937
|
+
LocalStorageAdapter,
|
|
938
|
+
LocalStorageSyncQueueAdapter,
|
|
939
|
+
SyncStorageAdapter,
|
|
940
|
+
createBrowserStorageAdapter,
|
|
941
|
+
createKeepKit,
|
|
942
|
+
createStorageAdapter,
|
|
698
943
|
useKeepContext2 as useKeepContext,
|
|
699
944
|
useKeepItem2 as useKeepItem,
|
|
700
945
|
useKeepList2 as useKeepList,
|
|
946
|
+
useKeepShortcut,
|
|
701
947
|
useKeepUiLabels
|
|
702
948
|
};
|
|
703
949
|
//# sourceMappingURL=index.js.map
|