@keepkit/ui 0.4.0 → 0.5.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 +51 -16
- package/dist/index.js +164 -21
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -4,76 +4,85 @@
|
|
|
4
4
|
|
|
5
5
|
## 日本語
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Reactアプリケーション向けの標準利用パッケージです。`@keepkit/core`を内包し、Provider、保存ボタン、検索・ソート・ページング付きの一覧を少ないコードで構成できます。
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
pnpm add @keepkit/
|
|
10
|
+
pnpm add @keepkit/ui
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
```tsx
|
|
14
|
-
import {
|
|
14
|
+
import { createBrowserStorageAdapter, createKeepKit } from "@keepkit/ui";
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
type ArticleMeta = { title: string; url: string };
|
|
17
|
+
const keep = createKeepKit<ArticleMeta>({
|
|
18
|
+
storage: createBrowserStorageAdapter({ key: "articles" }),
|
|
19
|
+
locale: "ja-JP",
|
|
20
|
+
labels: { save: "保存", remove: "削除" },
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
function SavedArticles() {
|
|
17
24
|
return (
|
|
18
|
-
<
|
|
19
|
-
<
|
|
20
|
-
|
|
21
|
-
|
|
25
|
+
<keep.Provider>
|
|
26
|
+
<keep.Collection
|
|
27
|
+
query={{ targetType: "article" }}
|
|
28
|
+
renderItem={(item) => <keep.Button item={{ id: item.id, targetType: item.targetType, meta: item.meta }} />}
|
|
29
|
+
/>
|
|
30
|
+
</keep.Provider>
|
|
22
31
|
);
|
|
23
32
|
}
|
|
24
33
|
```
|
|
25
34
|
|
|
26
|
-
|
|
35
|
+
`keep.Collection`は検索、ソート、ページング、loading / empty / error、ARIA live通知を標準で提供します。`features={{ tagFilter: true, bulkActions: true }}`でタグフィルターと一括操作も有効にできます。個別の`KeepList`、`KeepSearchInput`、`KeepSortSelect`、`KeepPagination`などは高度なレイアウト用に利用できます。
|
|
27
36
|
|
|
28
|
-
|
|
29
|
-
- `KeepList`: 保存一覧、読み込み中・空・エラー状態、標準カード、削除操作。`renderItem` で行単位を置き換えられます。
|
|
30
|
-
- `KeepItemCard`: タイトル、画像、保存ボタン、削除ボタン。`getImageProps`、`imageComponent`、`renderImage` とrender propsで表示を差し替えられます。
|
|
31
|
-
- `KeepTagFilter`: タグと件数を表示するキーボード操作可能なフィルター。`value` / `onValueChange` のcontrolled APIに対応します。
|
|
32
|
-
- `KeepNoteEditor`: ノートの編集・保存フォーム。`render` で完全なカスタムUIにできます。
|
|
33
|
-
- `KeepSearchInput` / `KeepSortSelect` / `KeepPagination`: `useKeepList` に渡す検索、ソート、offsetページング用のプリミティブ。
|
|
34
|
-
- `KeepTagEditor` / `KeepBulkActions`: タグ編集、複数選択、一括削除、一括タグ更新。
|
|
35
|
-
- `KeepUiProvider`: `labels`、`locale`、`labelResolver` をUI全体に適用するラベルコンテキスト。
|
|
36
|
-
- `KeepAnnouncements`: 保存、削除、ノート保存の成功を `aria-live` で通知します。
|
|
37
|
-
- `KeepEmptyState` / `KeepStatus`: 空、読み込み中、保存中、同期中、エラー状態の表示。
|
|
37
|
+
一覧のqueryは次の形式に統一されています。
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
```tsx
|
|
40
|
+
const query = {
|
|
41
|
+
targetType: "article",
|
|
42
|
+
tags: ["read"],
|
|
43
|
+
search: { query: "react", mode: "and" as const },
|
|
44
|
+
sort: { by: "updatedAt" as const, direction: "desc" as const },
|
|
45
|
+
pagination: { page: 1, pageSize: 20 },
|
|
46
|
+
};
|
|
47
|
+
```
|
|
40
48
|
|
|
41
|
-
|
|
49
|
+
保存操作にはID付きの最小入力を渡します。保存・更新時刻はKeepKitが管理します。
|
|
42
50
|
|
|
43
|
-
|
|
44
|
-
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
- CSSはルートと渡された標準要素の `className` に適用します。コンポーネントはstyleを持ちません。
|
|
48
|
-
- `onClick`、`onSubmit`、`onChange` は利用者のハンドラーを先に実行し、`preventDefault()` された場合は既定操作を実行しません。
|
|
51
|
+
```tsx
|
|
52
|
+
const article = { id: "article-123", targetType: "article", meta: { title, url } };
|
|
53
|
+
const item = keep.useItem(article);
|
|
54
|
+
```
|
|
49
55
|
|
|
50
|
-
|
|
56
|
+
高度なフレームワーク中立APIは`@keepkit/core/core`、低レベルのReact APIは`@keepkit/core/react`、ストレージ実装は`@keepkit/core/storage`から利用できます。
|
|
51
57
|
|
|
52
58
|
## English
|
|
53
59
|
|
|
54
|
-
|
|
60
|
+
The standard React package for KeepKit. It includes `@keepkit/core` and provides a single typed provider, save button, and searchable/sortable/paginated collection workflow.
|
|
55
61
|
|
|
56
62
|
```bash
|
|
57
|
-
pnpm add @keepkit/
|
|
63
|
+
pnpm add @keepkit/ui
|
|
58
64
|
```
|
|
59
65
|
|
|
60
66
|
```tsx
|
|
61
|
-
import {
|
|
67
|
+
import { createBrowserStorageAdapter, createKeepKit } from "@keepkit/ui";
|
|
68
|
+
|
|
69
|
+
type ArticleMeta = { title: string; url: string };
|
|
70
|
+
const keep = createKeepKit<ArticleMeta>({
|
|
71
|
+
storage: createBrowserStorageAdapter({ key: "articles" }),
|
|
72
|
+
labels: { save: "Save", remove: "Remove" },
|
|
73
|
+
});
|
|
62
74
|
|
|
63
|
-
function
|
|
75
|
+
function SavedArticles() {
|
|
64
76
|
return (
|
|
65
|
-
<
|
|
66
|
-
<
|
|
67
|
-
|
|
68
|
-
</KeepProvider>
|
|
77
|
+
<keep.Provider>
|
|
78
|
+
<keep.Collection query={{ targetType: "article" }} />
|
|
79
|
+
</keep.Provider>
|
|
69
80
|
);
|
|
70
81
|
}
|
|
71
82
|
```
|
|
72
83
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
The package also exports `KeepSearchInput`, `KeepSortSelect`, `KeepPagination`, `KeepTagEditor`, `KeepBulkActions`, `KeepUiProvider`, and `KeepAnnouncements`. Configure labels once with `KeepUiProvider`, replace card images with `getImageProps` plus `imageComponent` or `renderImage`, and use `KeepAnnouncements` for success messages in a polite live region.
|
|
84
|
+
`keep.Collection` includes search, sorting, pagination, loading/empty/error states, and polite live announcements. Enable `features={{ tagFilter: true, bulkActions: true }}` for tag filtering and bulk operations. Use the individual `KeepList`, `KeepSearchInput`, `KeepSortSelect`, and `KeepPagination` primitives when you need a custom layout.
|
|
76
85
|
|
|
77
|
-
|
|
86
|
+
Collection queries use one canonical shape: `targetType`, `tags`, `search`, `sort`, `pagination`, `filter`, and `savedBetween`. Saved item inputs contain only `id`, `meta`, `targetType`, `note`, and `tags`; KeepKit owns persistence timestamps.
|
|
78
87
|
|
|
79
|
-
|
|
88
|
+
Framework-neutral APIs remain available from `@keepkit/core/core`, low-level React bindings from `@keepkit/core/react`, and storage adapters from `@keepkit/core/storage`.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
export { KeepItem, KeepItemInput,
|
|
5
|
-
import { KeepButtonProps as KeepButtonProps$1, UseKeepListResult } from '@keepkit/core/react';
|
|
6
|
-
export { KeepContextValue, KeepProvider, KeepProviderProps, useKeepContext, useKeepItem, useKeepList } from '@keepkit/core/react';
|
|
2
|
+
import { ReactNode, ImgHTMLAttributes, HTMLAttributes, ComponentType, ReactElement, FormHTMLAttributes, InputHTMLAttributes, SelectHTMLAttributes } from 'react';
|
|
3
|
+
import { KeepItem, KeepListQuery, KeepItemInput } from '@keepkit/core/core';
|
|
4
|
+
export { KeepItem, KeepItemInput, KeepListQuery, KeepSyncStatus } from '@keepkit/core/core';
|
|
5
|
+
import { CreateKeepKitOptions as CreateKeepKitOptions$1, KeepButtonProps as KeepButtonProps$1, UseKeepListResult, KeepProviderProps, useKeepContext, useKeepItem, KeepShortcutOptions } from '@keepkit/core/react';
|
|
6
|
+
export { KeepContextValue, KeepProvider, KeepProviderProps, KeepShortcutOptions, useKeepContext, useKeepItem, useKeepList, useKeepShortcut } from '@keepkit/core/react';
|
|
7
|
+
export { FallbackStorageAdapter, IndexedDBAdapter, IndexedDBSyncQueueAdapter, LocalStorageAdapter, LocalStorageSyncQueueAdapter, SyncStorageAdapter, createBrowserStorageAdapter, createStorageAdapter } from '@keepkit/core/storage';
|
|
7
8
|
|
|
8
9
|
type KeepUiLabelKey = "save" | "saved" | "remove" | "loading" | "saving" | "syncing" | "error" | "allTags" | "filterTags" | "note" | "saveNote" | "noItems" | "loadingItems" | "errorItems" | "search" | "sort" | "newest" | "oldest" | "previousPage" | "nextPage" | "pagination" | "page" | "selectItems" | "selectedCount" | "deleteSelected" | "tagsToApply" | "applyTags" | "savedMessage" | "removedMessage" | "noteSavedMessage";
|
|
9
10
|
type KeepUiLabels = Partial<Record<KeepUiLabelKey, string>>;
|
|
@@ -22,8 +23,28 @@ type KeepUiProviderProps = {
|
|
|
22
23
|
};
|
|
23
24
|
/** Provides one locale-aware label source to every UI primitive. */
|
|
24
25
|
declare function KeepUiProvider({ labels, locale, labelResolver, children }: KeepUiProviderProps): react.JSX.Element;
|
|
26
|
+
type KeepKitProviderProps<TMeta = Record<string, unknown>> = Omit<KeepProviderProps<TMeta>, "children"> & Omit<KeepUiProviderProps, "children"> & {
|
|
27
|
+
children?: ReactNode;
|
|
28
|
+
};
|
|
29
|
+
/** Combines the core store and UI labels into the default application provider. */
|
|
30
|
+
declare function KeepKitProvider<TMeta = Record<string, unknown>>({ labels, locale, labelResolver, children, ...providerProps }: KeepKitProviderProps<TMeta>): react.JSX.Element;
|
|
25
31
|
declare function useKeepUiLabels(): KeepUiLabelContext;
|
|
26
32
|
|
|
33
|
+
type CreateKeepKitOptions<TMeta = Record<string, unknown>> = CreateKeepKitOptions$1<TMeta> & Omit<KeepUiProviderProps, "children"> & {
|
|
34
|
+
getTitle?: (item: KeepItem<TMeta>) => ReactNode;
|
|
35
|
+
getImageProps?: (item: KeepItem<TMeta>, title: ReactNode) => KeepImageProps | undefined;
|
|
36
|
+
};
|
|
37
|
+
type KeepKit<TMeta = Record<string, unknown>> = {
|
|
38
|
+
Provider: ComponentType<KeepKitProviderProps<TMeta>>;
|
|
39
|
+
Button: ComponentType<KeepButtonProps<TMeta>>;
|
|
40
|
+
Collection: ComponentType<KeepCollectionProps<TMeta>>;
|
|
41
|
+
useContext: () => ReturnType<typeof useKeepContext<TMeta>>;
|
|
42
|
+
useItem: (item?: KeepItemInput<TMeta>) => ReturnType<typeof useKeepItem<TMeta>>;
|
|
43
|
+
useList: (query?: KeepListQuery<TMeta>) => UseKeepListResult<TMeta>;
|
|
44
|
+
useShortcut: (options: KeepShortcutOptions<TMeta>) => void;
|
|
45
|
+
};
|
|
46
|
+
/** Create one typed application API for the core and the standard UI layer. */
|
|
47
|
+
declare function createKeepKit<TMeta = Record<string, unknown>>(options?: CreateKeepKitOptions<TMeta>): KeepKit<TMeta>;
|
|
27
48
|
type RenderProp<TState> = (state: TState) => ReactNode;
|
|
28
49
|
type KeepButtonLabels = {
|
|
29
50
|
saved?: ReactNode;
|
|
@@ -52,6 +73,7 @@ type KeepImageProps = ImgHTMLAttributes<HTMLImageElement> & {
|
|
|
52
73
|
type KeepItemCardProps<TMeta = Record<string, unknown>> = Omit<HTMLAttributes<HTMLElement>, "children" | "title"> & {
|
|
53
74
|
item: KeepItem<TMeta>;
|
|
54
75
|
title?: ReactNode | ((item: KeepItem<TMeta>) => ReactNode);
|
|
76
|
+
getTitle?: (item: KeepItem<TMeta>) => ReactNode;
|
|
55
77
|
getImageProps?: (item: KeepItem<TMeta>, title: ReactNode) => KeepImageProps | undefined;
|
|
56
78
|
imageComponent?: ComponentType<KeepImageProps>;
|
|
57
79
|
renderImage?: (props: KeepImageProps, item: KeepItem<TMeta>) => ReactNode;
|
|
@@ -66,10 +88,10 @@ type KeepItemCardProps<TMeta = Record<string, unknown>> = Omit<HTMLAttributes<HT
|
|
|
66
88
|
asChild?: boolean;
|
|
67
89
|
};
|
|
68
90
|
/** A low-dependency item presentation primitive. The default markup can be replaced with render props. */
|
|
69
|
-
declare function KeepItemCard<TMeta = Record<string, unknown>>({ item, title, getImageProps, imageComponent: ImageComponent, renderImage, imageAlt, render, children, removeLabel, onRemoveError, onRemoved, showSaveButton, saveButtonLabels, asChild, className, ...rootProps }: KeepItemCardProps<TMeta>): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
91
|
+
declare function KeepItemCard<TMeta = Record<string, unknown>>({ item, title, getTitle, getImageProps, imageComponent: ImageComponent, renderImage, imageAlt, render, children, removeLabel, onRemoveError, onRemoved, showSaveButton, saveButtonLabels, asChild, className, ...rootProps }: KeepItemCardProps<TMeta>): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
70
92
|
type KeepListState<TMeta = Record<string, unknown>> = UseKeepListResult<TMeta>;
|
|
71
93
|
type KeepListProps<TMeta = Record<string, unknown>> = Omit<HTMLAttributes<HTMLElement>, "children"> & {
|
|
72
|
-
|
|
94
|
+
query?: KeepListQuery<TMeta>;
|
|
73
95
|
children?: ReactNode | RenderProp<KeepListState<TMeta>>;
|
|
74
96
|
renderItem?: (item: KeepItem<TMeta>, state: KeepListState<TMeta>) => ReactNode;
|
|
75
97
|
loading?: ReactNode | RenderProp<KeepListState<TMeta>>;
|
|
@@ -79,7 +101,20 @@ type KeepListProps<TMeta = Record<string, unknown>> = Omit<HTMLAttributes<HTMLEl
|
|
|
79
101
|
asChild?: boolean;
|
|
80
102
|
};
|
|
81
103
|
/** A list primitive with built-in loading, empty, error, and removal states. */
|
|
82
|
-
declare function KeepList<TMeta = Record<string, unknown>>({
|
|
104
|
+
declare function KeepList<TMeta = Record<string, unknown>>({ query, children, renderItem, loading, empty, error: errorContent, itemCardProps, asChild, className, ...rootProps }: KeepListProps<TMeta>): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
105
|
+
type KeepCollectionFeature = "search" | "sort" | "pagination" | "tagFilter" | "bulkActions";
|
|
106
|
+
type KeepCollectionProps<TMeta = Record<string, unknown>> = Omit<HTMLAttributes<HTMLElement>, "children"> & {
|
|
107
|
+
query?: KeepListQuery<TMeta>;
|
|
108
|
+
pageSize?: number;
|
|
109
|
+
features?: Partial<Record<KeepCollectionFeature, boolean>>;
|
|
110
|
+
renderItem?: (item: KeepItem<TMeta>, state: KeepListState<TMeta>) => ReactNode;
|
|
111
|
+
itemCardProps?: Omit<KeepItemCardProps<TMeta>, "item" | "children" | "render">;
|
|
112
|
+
loading?: ReactNode | RenderProp<KeepListState<TMeta>>;
|
|
113
|
+
empty?: ReactNode | RenderProp<KeepListState<TMeta>>;
|
|
114
|
+
error?: ReactNode | RenderProp<KeepListState<TMeta>>;
|
|
115
|
+
};
|
|
116
|
+
/** A batteries-included collection with query controls and accessible status feedback. */
|
|
117
|
+
declare function KeepCollection<TMeta = Record<string, unknown>>({ query, pageSize, features, renderItem, itemCardProps, loading, empty, error, className, ...rootProps }: KeepCollectionProps<TMeta>): react.JSX.Element;
|
|
83
118
|
type KeepTagFilterState = {
|
|
84
119
|
tags: string[];
|
|
85
120
|
tagCounts: Record<string, number>;
|
|
@@ -87,7 +122,7 @@ type KeepTagFilterState = {
|
|
|
87
122
|
select: (tag?: string) => void;
|
|
88
123
|
};
|
|
89
124
|
type KeepTagFilterProps<TMeta = Record<string, unknown>> = Omit<HTMLAttributes<HTMLElement>, "children" | "onChange"> & {
|
|
90
|
-
|
|
125
|
+
query?: KeepListQuery<TMeta>;
|
|
91
126
|
value?: string;
|
|
92
127
|
defaultValue?: string;
|
|
93
128
|
onChange?: (tag?: string) => void;
|
|
@@ -99,8 +134,8 @@ type KeepTagFilterProps<TMeta = Record<string, unknown>> = Omit<HTMLAttributes<H
|
|
|
99
134
|
children?: ReactNode | RenderProp<KeepTagFilterState>;
|
|
100
135
|
asChild?: boolean;
|
|
101
136
|
};
|
|
102
|
-
/** An ARIA button group for tag filtering; consumers can connect value to
|
|
103
|
-
declare function KeepTagFilter<TMeta = Record<string, unknown>>({
|
|
137
|
+
/** An ARIA button group for tag filtering; consumers can connect value to a collection query. */
|
|
138
|
+
declare function KeepTagFilter<TMeta = Record<string, unknown>>({ query, value: controlledValue, defaultValue, onChange, onValueChange, allLabel, ariaLabel, renderTag, render, children, asChild, className, ...rootProps }: KeepTagFilterProps<TMeta>): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
104
139
|
type KeepNoteEditorState<TMeta = Record<string, unknown>> = {
|
|
105
140
|
item: KeepItem<TMeta>;
|
|
106
141
|
note: string;
|
|
@@ -128,13 +163,13 @@ type KeepSearchInputProps = Omit<InputHTMLAttributes<HTMLInputElement>, "value"
|
|
|
128
163
|
defaultValue?: string;
|
|
129
164
|
onValueChange?: (value: string) => void;
|
|
130
165
|
};
|
|
131
|
-
/** A controlled/uncontrolled search field for wiring into
|
|
166
|
+
/** A controlled/uncontrolled search field for wiring into KeepListQuery.search. */
|
|
132
167
|
declare function KeepSearchInput({ value: controlledValue, defaultValue, onValueChange, "aria-label": ariaLabel, placeholder, ...props }: KeepSearchInputProps): react.JSX.Element;
|
|
133
168
|
type KeepSortValue = "savedAt:desc" | "savedAt:asc" | "updatedAt:desc" | "updatedAt:asc";
|
|
134
169
|
type KeepSortSelectProps = Omit<SelectHTMLAttributes<HTMLSelectElement>, "value" | "defaultValue" | "onChange"> & {
|
|
135
170
|
value?: KeepSortValue;
|
|
136
171
|
defaultValue?: KeepSortValue;
|
|
137
|
-
onValueChange?: (value: KeepSortValue, sort: NonNullable<
|
|
172
|
+
onValueChange?: (value: KeepSortValue, sort: NonNullable<KeepListQuery["sort"]>) => void;
|
|
138
173
|
};
|
|
139
174
|
/** Emits a normalized sort descriptor that can be passed directly to useKeepList. */
|
|
140
175
|
declare function KeepSortSelect({ value: controlledValue, defaultValue, onValueChange, "aria-label": ariaLabel, children, ...props }: KeepSortSelectProps): react.JSX.Element;
|
|
@@ -166,7 +201,7 @@ type KeepTagEditorProps<TMeta = Record<string, unknown>> = Omit<FormHTMLAttribut
|
|
|
166
201
|
/** Edits one item's normalized tag set and exposes a render-prop escape hatch. */
|
|
167
202
|
declare function KeepTagEditor<TMeta = Record<string, unknown>>({ item, availableTags, onSaved, onSaveError, render, ...props }: KeepTagEditorProps<TMeta>): react.JSX.Element;
|
|
168
203
|
type KeepBulkActionsProps<TMeta = Record<string, unknown>> = Omit<HTMLAttributes<HTMLElement>, "children"> & {
|
|
169
|
-
|
|
204
|
+
query?: KeepListQuery<TMeta>;
|
|
170
205
|
selectedIds?: string[];
|
|
171
206
|
defaultSelectedIds?: string[];
|
|
172
207
|
onSelectedIdsChange?: (ids: string[]) => void;
|
|
@@ -174,7 +209,7 @@ type KeepBulkActionsProps<TMeta = Record<string, unknown>> = Omit<HTMLAttributes
|
|
|
174
209
|
onCompleted?: (action: "remove" | "tags", ids: string[]) => void;
|
|
175
210
|
};
|
|
176
211
|
/** Selects visible items and performs one storage operation for the whole selection. */
|
|
177
|
-
declare function KeepBulkActions<TMeta = Record<string, unknown>>({
|
|
212
|
+
declare function KeepBulkActions<TMeta = Record<string, unknown>>({ query, selectedIds: controlledSelectedIds, defaultSelectedIds, onSelectedIdsChange, renderItem, onCompleted, ...props }: KeepBulkActionsProps<TMeta>): react.JSX.Element;
|
|
178
213
|
type KeepEmptyStateProps = Omit<HTMLAttributes<HTMLElement>, "children" | "title"> & {
|
|
179
214
|
title?: ReactNode;
|
|
180
215
|
description?: ReactNode;
|
|
@@ -207,4 +242,4 @@ type KeepAnnouncementsProps = Omit<HTMLAttributes<HTMLElement>, "children"> & {
|
|
|
207
242
|
/** Announces successful save, remove, and note operations in a polite live region. */
|
|
208
243
|
declare function KeepAnnouncements<TMeta = Record<string, unknown>>({ messages, ...props }: KeepAnnouncementsProps): react.JSX.Element;
|
|
209
244
|
|
|
210
|
-
export { KeepAnnouncements, type KeepAnnouncementsProps, KeepBulkActions, type KeepBulkActionsProps, KeepButton, type KeepButtonLabels, type KeepButtonProps, KeepEmptyState, type KeepEmptyStateProps, type KeepImageProps, KeepItemCard, type KeepItemCardProps, type KeepItemCardState, KeepList, type KeepListProps, type KeepListState, KeepNoteEditor, type KeepNoteEditorProps, type KeepNoteEditorState, KeepPagination, type KeepPaginationProps, KeepSearchInput, type KeepSearchInputProps, KeepSortSelect, type KeepSortSelectProps, type KeepSortValue, KeepStatus, type KeepStatusLabels, type KeepStatusProps, type KeepStatusState, type KeepStatusValue, KeepTagEditor, type KeepTagEditorProps, KeepTagFilter, type KeepTagFilterProps, type KeepTagFilterState, type KeepUiLabelContext, type KeepUiLabelKey, type KeepUiLabels, KeepUiProvider, type KeepUiProviderProps, type RenderProp, useKeepUiLabels };
|
|
245
|
+
export { type CreateKeepKitOptions, KeepAnnouncements, type KeepAnnouncementsProps, KeepBulkActions, type KeepBulkActionsProps, KeepButton, type KeepButtonLabels, type KeepButtonProps, KeepCollection, type KeepCollectionFeature, type KeepCollectionProps, KeepEmptyState, type KeepEmptyStateProps, type KeepImageProps, KeepItemCard, type KeepItemCardProps, type KeepItemCardState, type KeepKit, KeepKitProvider, type KeepKitProviderProps, KeepList, type KeepListProps, type KeepListState, KeepNoteEditor, type KeepNoteEditorProps, type KeepNoteEditorState, KeepPagination, type KeepPaginationProps, KeepSearchInput, type KeepSearchInputProps, KeepSortSelect, type KeepSortSelectProps, type KeepSortValue, KeepStatus, type KeepStatusLabels, type KeepStatusProps, type KeepStatusState, type KeepStatusValue, KeepTagEditor, type KeepTagEditorProps, KeepTagFilter, type KeepTagFilterProps, type KeepTagFilterState, type KeepUiLabelContext, type KeepUiLabelKey, type KeepUiLabels, KeepUiProvider, type KeepUiProviderProps, type RenderProp, createKeepKit, useKeepUiLabels };
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
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
|
|
@@ -18,7 +20,17 @@ import {
|
|
|
18
20
|
useRef,
|
|
19
21
|
useState
|
|
20
22
|
} from "react";
|
|
21
|
-
import { KeepProvider, useKeepContext as useKeepContext2, useKeepItem as useKeepItem2, useKeepList as useKeepList2 } from "@keepkit/core/react";
|
|
23
|
+
import { KeepProvider, useKeepContext as useKeepContext2, useKeepItem as useKeepItem2, useKeepList as useKeepList2, useKeepShortcut } from "@keepkit/core/react";
|
|
24
|
+
import {
|
|
25
|
+
createBrowserStorageAdapter,
|
|
26
|
+
createStorageAdapter,
|
|
27
|
+
FallbackStorageAdapter,
|
|
28
|
+
IndexedDBAdapter,
|
|
29
|
+
IndexedDBSyncQueueAdapter,
|
|
30
|
+
LocalStorageAdapter,
|
|
31
|
+
LocalStorageSyncQueueAdapter,
|
|
32
|
+
SyncStorageAdapter
|
|
33
|
+
} from "@keepkit/core/storage";
|
|
22
34
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
23
35
|
var DEFAULT_LABELS = {
|
|
24
36
|
save: "Save",
|
|
@@ -60,6 +72,15 @@ function KeepUiProvider({ labels, locale, labelResolver, children }) {
|
|
|
60
72
|
}, [labelResolver, labels, locale]);
|
|
61
73
|
return /* @__PURE__ */ jsx(KeepUiLabelsContext.Provider, { value, children });
|
|
62
74
|
}
|
|
75
|
+
function KeepKitProvider({
|
|
76
|
+
labels,
|
|
77
|
+
locale,
|
|
78
|
+
labelResolver,
|
|
79
|
+
children,
|
|
80
|
+
...providerProps
|
|
81
|
+
}) {
|
|
82
|
+
return /* @__PURE__ */ jsx(KeepUiProvider, { labels, locale, labelResolver, children: /* @__PURE__ */ jsx(CoreKeepProvider, { ...providerProps, children }) });
|
|
83
|
+
}
|
|
63
84
|
function useKeepUiLabels() {
|
|
64
85
|
return useContext(KeepUiLabelsContext);
|
|
65
86
|
}
|
|
@@ -67,17 +88,44 @@ function useUiLabel(key, override) {
|
|
|
67
88
|
const context = useKeepUiLabels();
|
|
68
89
|
return override ?? context.labelResolver?.(key, { locale: context.locale }) ?? context.labels[key];
|
|
69
90
|
}
|
|
91
|
+
function createKeepKit(options = {}) {
|
|
92
|
+
const { labels, locale, labelResolver, getTitle, getImageProps, ...coreOptions } = options;
|
|
93
|
+
const coreKit = createCoreKeepKit(coreOptions);
|
|
94
|
+
return {
|
|
95
|
+
Provider: (props) => /* @__PURE__ */ jsx(
|
|
96
|
+
KeepKitProvider,
|
|
97
|
+
{
|
|
98
|
+
...coreOptions,
|
|
99
|
+
labels,
|
|
100
|
+
locale,
|
|
101
|
+
labelResolver,
|
|
102
|
+
...props
|
|
103
|
+
}
|
|
104
|
+
),
|
|
105
|
+
Button: (props) => /* @__PURE__ */ jsx(KeepButton, { ...props }),
|
|
106
|
+
Collection: (props) => /* @__PURE__ */ jsx(
|
|
107
|
+
KeepCollection,
|
|
108
|
+
{
|
|
109
|
+
...props,
|
|
110
|
+
itemCardProps: {
|
|
111
|
+
...getTitle ? { getTitle } : {},
|
|
112
|
+
...getImageProps ? { getImageProps } : {},
|
|
113
|
+
...props.itemCardProps
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
),
|
|
117
|
+
useContext: () => coreKit.useContext(),
|
|
118
|
+
useItem: (item) => coreKit.useItem(item),
|
|
119
|
+
useList: (query) => coreKit.useList(query),
|
|
120
|
+
useShortcut: (shortcutOptions) => coreKit.useShortcut(shortcutOptions)
|
|
121
|
+
};
|
|
122
|
+
}
|
|
70
123
|
function KeepButton({ labels, ...props }) {
|
|
71
124
|
const saveLabel = useUiLabel("save", typeof labels?.unsaved === "string" ? labels.unsaved : void 0);
|
|
72
125
|
const savedLabel = useUiLabel("saved", typeof labels?.saved === "string" ? labels.saved : void 0);
|
|
73
126
|
const loadingLabel = useUiLabel("loading", typeof labels?.loading === "string" ? labels.loading : void 0);
|
|
74
127
|
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
|
-
});
|
|
128
|
+
const buttonState = useKeepItem(props.item);
|
|
81
129
|
const customStateLabel = labels?.loading !== void 0 || labels?.error !== void 0;
|
|
82
130
|
const getStateContent = (state) => {
|
|
83
131
|
if (state.error) return labels?.error ?? errorLabel;
|
|
@@ -90,8 +138,8 @@ function KeepButton({ labels, ...props }) {
|
|
|
90
138
|
const sharedProps2 = {
|
|
91
139
|
...props,
|
|
92
140
|
"aria-busy": props["aria-busy"] ?? (buttonState.isLoading || buttonState.isMutating),
|
|
93
|
-
savedLabel: labels?.saved ?? savedLabel,
|
|
94
|
-
unsavedLabel: labels?.unsaved ?? saveLabel,
|
|
141
|
+
savedLabel: labels?.saved ?? props.savedLabel ?? savedLabel,
|
|
142
|
+
unsavedLabel: labels?.unsaved ?? props.unsavedLabel ?? saveLabel,
|
|
95
143
|
savedAriaLabel: labels?.savedAriaLabel ?? props.savedAriaLabel,
|
|
96
144
|
unsavedAriaLabel: labels?.unsavedAriaLabel ?? props.unsavedAriaLabel
|
|
97
145
|
};
|
|
@@ -105,8 +153,8 @@ function KeepButton({ labels, ...props }) {
|
|
|
105
153
|
const sharedProps = {
|
|
106
154
|
...props,
|
|
107
155
|
"aria-busy": props["aria-busy"] ?? (buttonState.isLoading || buttonState.isMutating),
|
|
108
|
-
savedLabel: labels?.saved ?? savedLabel,
|
|
109
|
-
unsavedLabel: labels?.unsaved ?? saveLabel,
|
|
156
|
+
savedLabel: labels?.saved ?? props.savedLabel ?? savedLabel,
|
|
157
|
+
unsavedLabel: labels?.unsaved ?? props.unsavedLabel ?? saveLabel,
|
|
110
158
|
savedAriaLabel: labels?.savedAriaLabel ?? props.savedAriaLabel,
|
|
111
159
|
unsavedAriaLabel: labels?.unsavedAriaLabel ?? props.unsavedAriaLabel
|
|
112
160
|
};
|
|
@@ -117,6 +165,7 @@ function KeepButton({ labels, ...props }) {
|
|
|
117
165
|
function KeepItemCard({
|
|
118
166
|
item,
|
|
119
167
|
title,
|
|
168
|
+
getTitle,
|
|
120
169
|
getImageProps,
|
|
121
170
|
imageComponent: ImageComponent,
|
|
122
171
|
renderImage,
|
|
@@ -134,7 +183,7 @@ function KeepItemCard({
|
|
|
134
183
|
}) {
|
|
135
184
|
const saveActionLabel = useUiLabel("save");
|
|
136
185
|
const removeActionLabel = useUiLabel("remove");
|
|
137
|
-
const itemState = useKeepItem(item
|
|
186
|
+
const itemState = useKeepItem(item);
|
|
138
187
|
const contentChildren = asChild && isValidElement(children) ? void 0 : children;
|
|
139
188
|
const state = {
|
|
140
189
|
item,
|
|
@@ -143,7 +192,7 @@ function KeepItemCard({
|
|
|
143
192
|
error: itemState.error,
|
|
144
193
|
remove: itemState.remove
|
|
145
194
|
};
|
|
146
|
-
const resolvedTitle = typeof title === "function" ? title(item) : title ?? getMetaTitle(item.meta) ?? item.id;
|
|
195
|
+
const resolvedTitle = typeof title === "function" ? title(item) : title ?? getTitle?.(item) ?? getMetaTitle(item.meta) ?? item.id;
|
|
147
196
|
const imageProps = getImageProps?.(item, resolvedTitle);
|
|
148
197
|
async function handleRemove() {
|
|
149
198
|
try {
|
|
@@ -175,7 +224,7 @@ function KeepItemCard({
|
|
|
175
224
|
);
|
|
176
225
|
}
|
|
177
226
|
function KeepList({
|
|
178
|
-
|
|
227
|
+
query,
|
|
179
228
|
children,
|
|
180
229
|
renderItem,
|
|
181
230
|
loading,
|
|
@@ -189,7 +238,7 @@ function KeepList({
|
|
|
189
238
|
const defaultLoading = useUiLabel("loadingItems");
|
|
190
239
|
const defaultEmpty = useUiLabel("noItems");
|
|
191
240
|
const defaultError = useUiLabel("errorItems");
|
|
192
|
-
const state = useKeepList(
|
|
241
|
+
const state = useKeepList(query);
|
|
193
242
|
const body = getListBody(state, {
|
|
194
243
|
children,
|
|
195
244
|
renderItem,
|
|
@@ -218,8 +267,87 @@ function getListBody(state, options) {
|
|
|
218
267
|
);
|
|
219
268
|
return /* @__PURE__ */ jsx("ul", { children: items });
|
|
220
269
|
}
|
|
270
|
+
function KeepCollection({
|
|
271
|
+
query = {},
|
|
272
|
+
pageSize = 20,
|
|
273
|
+
features,
|
|
274
|
+
renderItem,
|
|
275
|
+
itemCardProps,
|
|
276
|
+
loading,
|
|
277
|
+
empty,
|
|
278
|
+
error,
|
|
279
|
+
className,
|
|
280
|
+
...rootProps
|
|
281
|
+
}) {
|
|
282
|
+
const enabled = {
|
|
283
|
+
search: true,
|
|
284
|
+
sort: true,
|
|
285
|
+
pagination: true,
|
|
286
|
+
tagFilter: false,
|
|
287
|
+
bulkActions: false,
|
|
288
|
+
...features
|
|
289
|
+
};
|
|
290
|
+
const [searchValue, setSearchValue] = useState(query.search?.query ?? "");
|
|
291
|
+
const [sort, setSort] = useState(query.sort ?? { by: "updatedAt", direction: "desc" });
|
|
292
|
+
const [tag, setTag] = useState(query.tags?.[0]);
|
|
293
|
+
const [page, setPage] = useState(query.pagination?.page ?? 1);
|
|
294
|
+
const resolvedPageSize = query.pagination?.pageSize ?? pageSize;
|
|
295
|
+
const resolvedQuery = useMemo(
|
|
296
|
+
() => ({
|
|
297
|
+
...query,
|
|
298
|
+
search: enabled.search ? { ...query.search, query: searchValue } : query.search,
|
|
299
|
+
sort: enabled.sort ? sort : query.sort,
|
|
300
|
+
tags: tag ? [.../* @__PURE__ */ new Set([...query.tags ?? [], tag])] : query.tags,
|
|
301
|
+
pagination: enabled.pagination ? { ...query.pagination, page, pageSize: resolvedPageSize } : query.pagination
|
|
302
|
+
}),
|
|
303
|
+
[enabled.pagination, enabled.search, enabled.sort, page, query, resolvedPageSize, searchValue, sort, tag]
|
|
304
|
+
);
|
|
305
|
+
const list = useKeepList(resolvedQuery);
|
|
306
|
+
useEffect(() => {
|
|
307
|
+
if (searchValue !== void 0 || sort.by !== void 0 || sort.direction !== void 0 || tag !== void 0) {
|
|
308
|
+
setPage(1);
|
|
309
|
+
}
|
|
310
|
+
}, [searchValue, sort.by, sort.direction, tag]);
|
|
311
|
+
return /* @__PURE__ */ jsxs(
|
|
312
|
+
"section",
|
|
313
|
+
{
|
|
314
|
+
...rootProps,
|
|
315
|
+
className,
|
|
316
|
+
"aria-busy": list.isLoading || list.isMutating || rootProps["aria-busy"],
|
|
317
|
+
children: [
|
|
318
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
319
|
+
enabled.search ? /* @__PURE__ */ jsx(KeepSearchInput, { value: searchValue, onValueChange: setSearchValue }) : null,
|
|
320
|
+
enabled.sort ? /* @__PURE__ */ jsx(KeepSortSelect, { value: sortToValue(sort), onValueChange: (_value, nextSort) => setSort(nextSort) }) : null,
|
|
321
|
+
enabled.tagFilter ? /* @__PURE__ */ jsx(KeepTagFilter, { query, value: tag, onValueChange: setTag }) : null
|
|
322
|
+
] }),
|
|
323
|
+
/* @__PURE__ */ jsx(
|
|
324
|
+
KeepList,
|
|
325
|
+
{
|
|
326
|
+
query: resolvedQuery,
|
|
327
|
+
renderItem,
|
|
328
|
+
itemCardProps,
|
|
329
|
+
loading,
|
|
330
|
+
empty,
|
|
331
|
+
error
|
|
332
|
+
}
|
|
333
|
+
),
|
|
334
|
+
enabled.pagination ? /* @__PURE__ */ jsx(
|
|
335
|
+
KeepPagination,
|
|
336
|
+
{
|
|
337
|
+
totalCount: list.totalCount,
|
|
338
|
+
pageSize: resolvedPageSize,
|
|
339
|
+
page: list.page,
|
|
340
|
+
onPageChange: (_nextPage, nextPageOffset) => setPage(Math.floor(nextPageOffset / resolvedPageSize) + 1)
|
|
341
|
+
}
|
|
342
|
+
) : null,
|
|
343
|
+
enabled.bulkActions ? /* @__PURE__ */ jsx(KeepBulkActions, { query: resolvedQuery }) : null,
|
|
344
|
+
/* @__PURE__ */ jsx(KeepAnnouncements, {})
|
|
345
|
+
]
|
|
346
|
+
}
|
|
347
|
+
);
|
|
348
|
+
}
|
|
221
349
|
function KeepTagFilter({
|
|
222
|
-
|
|
350
|
+
query,
|
|
223
351
|
value: controlledValue,
|
|
224
352
|
defaultValue,
|
|
225
353
|
onChange,
|
|
@@ -237,10 +365,10 @@ function KeepTagFilter({
|
|
|
237
365
|
const uiAriaLabel = useUiLabel("filterTags");
|
|
238
366
|
const defaultAllLabel = allLabel ?? uiAllLabel;
|
|
239
367
|
const defaultAriaLabel = ariaLabel ?? uiAriaLabel;
|
|
240
|
-
const list = useKeepList(listOptions);
|
|
241
368
|
const contentChildren = asChild && isValidElement(children) ? void 0 : children;
|
|
242
369
|
const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
|
|
243
370
|
const value = controlledValue ?? uncontrolledValue;
|
|
371
|
+
const list = useKeepList({ ...query, tags: value ? [...query?.tags ?? [], value] : query?.tags });
|
|
244
372
|
const select = useCallback(
|
|
245
373
|
(tag) => {
|
|
246
374
|
if (controlledValue === void 0) setUncontrolledValue(tag);
|
|
@@ -288,7 +416,7 @@ function KeepNoteEditor({
|
|
|
288
416
|
}) {
|
|
289
417
|
const defaultLabel = useUiLabel("note");
|
|
290
418
|
const defaultSaveLabel = useUiLabel("saveNote");
|
|
291
|
-
const itemState = useKeepItem(item
|
|
419
|
+
const itemState = useKeepItem(item);
|
|
292
420
|
const contentChildren = asChild && isValidElement(children) ? void 0 : children;
|
|
293
421
|
const [note, setNote] = useState(item.note ?? "");
|
|
294
422
|
useEffect(() => setNote(itemState.item?.note ?? item.note ?? ""), [item.note, itemState.item?.note]);
|
|
@@ -455,7 +583,7 @@ function KeepTagEditor({
|
|
|
455
583
|
const tagsLabel = useUiLabel("tagsToApply");
|
|
456
584
|
const removeLabel = useUiLabel("remove");
|
|
457
585
|
const applyTagsLabel = useUiLabel("applyTags");
|
|
458
|
-
const itemState = useKeepItem(item
|
|
586
|
+
const itemState = useKeepItem(item);
|
|
459
587
|
const [tags, setTags] = useState(item.tags ?? []);
|
|
460
588
|
const [input, setInput] = useState("");
|
|
461
589
|
useEffect(() => setTags(itemState.item?.tags ?? item.tags ?? []), [item.tags, itemState.item?.tags]);
|
|
@@ -514,7 +642,7 @@ function KeepTagEditor({
|
|
|
514
642
|
);
|
|
515
643
|
}
|
|
516
644
|
function KeepBulkActions({
|
|
517
|
-
|
|
645
|
+
query,
|
|
518
646
|
selectedIds: controlledSelectedIds,
|
|
519
647
|
defaultSelectedIds = [],
|
|
520
648
|
onSelectedIdsChange,
|
|
@@ -527,7 +655,7 @@ function KeepBulkActions({
|
|
|
527
655
|
const deleteSelectedLabel = useUiLabel("deleteSelected");
|
|
528
656
|
const tagsLabel = useUiLabel("tagsToApply");
|
|
529
657
|
const applyTagsLabel = useUiLabel("applyTags");
|
|
530
|
-
const list = useKeepList(
|
|
658
|
+
const list = useKeepList(query);
|
|
531
659
|
const [uncontrolledSelectedIds, setUncontrolledSelectedIds] = useState(defaultSelectedIds);
|
|
532
660
|
const selectedIds = controlledSelectedIds ?? uncontrolledSelectedIds;
|
|
533
661
|
const selected = new Set(selectedIds);
|
|
@@ -672,6 +800,9 @@ function getMetaTitle(meta) {
|
|
|
672
800
|
function normalizeUiTags(tags) {
|
|
673
801
|
return [...new Set(tags.map((tag) => tag.trim()).filter(Boolean))];
|
|
674
802
|
}
|
|
803
|
+
function sortToValue(sort) {
|
|
804
|
+
return `${sort?.by ?? "updatedAt"}:${sort?.direction ?? "desc"}`;
|
|
805
|
+
}
|
|
675
806
|
function renderRoot(asChild, child, props, body, componentName) {
|
|
676
807
|
if (asChild) {
|
|
677
808
|
if (!isValidElement(child)) throw new Error(`${componentName} with asChild requires a single React element child.`);
|
|
@@ -680,11 +811,16 @@ function renderRoot(asChild, child, props, body, componentName) {
|
|
|
680
811
|
return /* @__PURE__ */ jsx("div", { ...props, children: body });
|
|
681
812
|
}
|
|
682
813
|
export {
|
|
814
|
+
FallbackStorageAdapter,
|
|
815
|
+
IndexedDBAdapter,
|
|
816
|
+
IndexedDBSyncQueueAdapter,
|
|
683
817
|
KeepAnnouncements,
|
|
684
818
|
KeepBulkActions,
|
|
685
819
|
KeepButton,
|
|
820
|
+
KeepCollection,
|
|
686
821
|
KeepEmptyState,
|
|
687
822
|
KeepItemCard,
|
|
823
|
+
KeepKitProvider,
|
|
688
824
|
KeepList,
|
|
689
825
|
KeepNoteEditor,
|
|
690
826
|
KeepPagination,
|
|
@@ -695,9 +831,16 @@ export {
|
|
|
695
831
|
KeepTagEditor,
|
|
696
832
|
KeepTagFilter,
|
|
697
833
|
KeepUiProvider,
|
|
834
|
+
LocalStorageAdapter,
|
|
835
|
+
LocalStorageSyncQueueAdapter,
|
|
836
|
+
SyncStorageAdapter,
|
|
837
|
+
createBrowserStorageAdapter,
|
|
838
|
+
createKeepKit,
|
|
839
|
+
createStorageAdapter,
|
|
698
840
|
useKeepContext2 as useKeepContext,
|
|
699
841
|
useKeepItem2 as useKeepItem,
|
|
700
842
|
useKeepList2 as useKeepList,
|
|
843
|
+
useKeepShortcut,
|
|
701
844
|
useKeepUiLabels
|
|
702
845
|
};
|
|
703
846
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.tsx"],"sourcesContent":["\"use client\";\n\nimport type { KeepChangeContext, KeepItem, KeepItemInput, KeepListOptions, KeepSyncStatus } from \"@keepkit/core/core\";\nimport type { UseKeepListResult } from \"@keepkit/core/react\";\nimport {\n KeepButton as CoreKeepButton,\n type KeepButtonProps as CoreKeepButtonProps,\n type KeepButtonState,\n useKeepContext,\n useKeepItem,\n useKeepList,\n} from \"@keepkit/core/react\";\nimport {\n type ComponentType,\n cloneElement,\n createContext,\n type FormHTMLAttributes,\n type HTMLAttributes,\n type ImgHTMLAttributes,\n type InputHTMLAttributes,\n isValidElement,\n type ReactElement,\n type ReactNode,\n type SelectHTMLAttributes,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nexport type KeepUiLabelKey =\n | \"save\"\n | \"saved\"\n | \"remove\"\n | \"loading\"\n | \"saving\"\n | \"syncing\"\n | \"error\"\n | \"allTags\"\n | \"filterTags\"\n | \"note\"\n | \"saveNote\"\n | \"noItems\"\n | \"loadingItems\"\n | \"errorItems\"\n | \"search\"\n | \"sort\"\n | \"newest\"\n | \"oldest\"\n | \"previousPage\"\n | \"nextPage\"\n | \"pagination\"\n | \"page\"\n | \"selectItems\"\n | \"selectedCount\"\n | \"deleteSelected\"\n | \"tagsToApply\"\n | \"applyTags\"\n | \"savedMessage\"\n | \"removedMessage\"\n | \"noteSavedMessage\";\n\nexport type KeepUiLabels = Partial<Record<KeepUiLabelKey, string>>;\n\nexport type KeepUiLabelContext = {\n locale?: string;\n labels: Readonly<Record<KeepUiLabelKey, string>>;\n labelResolver?: (key: KeepUiLabelKey, context: { locale?: string }) => string | undefined;\n};\n\nconst DEFAULT_LABELS: Record<KeepUiLabelKey, string> = {\n save: \"Save\",\n saved: \"Saved\",\n remove: \"Remove\",\n loading: \"Loading…\",\n saving: \"Saving…\",\n syncing: \"Syncing…\",\n error: \"Something went wrong.\",\n allTags: \"All\",\n filterTags: \"Filter saved items by tag\",\n note: \"Note\",\n saveNote: \"Save note\",\n noItems: \"No saved items.\",\n loadingItems: \"Loading saved items…\",\n errorItems: \"Could not load saved items.\",\n search: \"Search saved items\",\n sort: \"Sort saved items\",\n newest: \"Newest first\",\n oldest: \"Oldest first\",\n previousPage: \"Previous page\",\n nextPage: \"Next page\",\n pagination: \"Pagination\",\n page: \"Page\",\n selectItems: \"Select saved items\",\n selectedCount: \"selected\",\n deleteSelected: \"Delete selected\",\n tagsToApply: \"Tags to apply\",\n applyTags: \"Apply tags\",\n savedMessage: \"Item saved.\",\n removedMessage: \"Item removed.\",\n noteSavedMessage: \"Note saved.\",\n};\n\nconst KeepUiLabelsContext = createContext<KeepUiLabelContext>({ labels: DEFAULT_LABELS });\n\nexport type KeepUiProviderProps = {\n labels?: KeepUiLabels;\n locale?: string;\n labelResolver?: KeepUiLabelContext[\"labelResolver\"];\n children?: ReactNode;\n};\n\n/** Provides one locale-aware label source to every UI primitive. */\nexport function KeepUiProvider({ labels, locale, labelResolver, children }: KeepUiProviderProps) {\n const value = useMemo<KeepUiLabelContext>(() => {\n const resolved = { ...DEFAULT_LABELS, ...labels };\n return { locale, labels: resolved, labelResolver };\n }, [labelResolver, labels, locale]);\n return <KeepUiLabelsContext.Provider value={value}>{children}</KeepUiLabelsContext.Provider>;\n}\n\nexport function useKeepUiLabels(): KeepUiLabelContext {\n return useContext(KeepUiLabelsContext);\n}\n\nfunction useUiLabel(key: KeepUiLabelKey, override?: string): string {\n const context = useKeepUiLabels();\n return override ?? context.labelResolver?.(key, { locale: context.locale }) ?? context.labels[key];\n}\n\nexport type { KeepContextValue, KeepProviderProps } from \"@keepkit/core/react\";\nexport { KeepProvider, useKeepContext, useKeepItem, useKeepList } from \"@keepkit/core/react\";\nexport type { KeepItem, KeepItemInput, KeepListOptions, KeepSyncStatus };\n\nexport type RenderProp<TState> = (state: TState) => ReactNode;\n\nexport type KeepButtonLabels = {\n saved?: ReactNode;\n unsaved?: ReactNode;\n loading?: ReactNode;\n error?: ReactNode;\n savedAriaLabel?: string;\n unsavedAriaLabel?: string;\n};\n\nexport type KeepButtonProps<TMeta = Record<string, unknown>> = CoreKeepButtonProps<TMeta> & {\n labels?: KeepButtonLabels;\n};\n\n/** A style-free save toggle with localized labels and the core button's ARIA/asChild behavior. */\nexport function KeepButton<TMeta = Record<string, unknown>>({ labels, ...props }: KeepButtonProps<TMeta>) {\n const saveLabel = useUiLabel(\"save\", typeof labels?.unsaved === \"string\" ? labels.unsaved : undefined);\n const savedLabel = useUiLabel(\"saved\", typeof labels?.saved === \"string\" ? labels.saved : undefined);\n const loadingLabel = useUiLabel(\"loading\", typeof labels?.loading === \"string\" ? labels.loading : undefined);\n const errorLabel = useUiLabel(\"error\", typeof labels?.error === \"string\" ? labels.error : undefined);\n const buttonState = useKeepItem<TMeta>(props.item.id, {\n meta: props.item.meta,\n targetType: props.item.targetType,\n note: props.item.note,\n tags: props.item.tags,\n });\n const customStateLabel = labels?.loading !== undefined || labels?.error !== undefined;\n const getStateContent = (state: KeepButtonState<TMeta>): ReactNode => {\n if (state.error) return labels?.error ?? errorLabel;\n if (state.isMutating) return labels?.loading ?? loadingLabel;\n if (typeof props.children === \"function\") return props.children(state);\n if (props.children !== undefined) return props.children;\n return state.isSaved ? (labels?.saved ?? savedLabel) : (labels?.unsaved ?? saveLabel);\n };\n if (props.asChild === true) {\n const sharedProps = {\n ...props,\n \"aria-busy\": props[\"aria-busy\"] ?? (buttonState.isLoading || buttonState.isMutating),\n savedLabel: labels?.saved ?? savedLabel,\n unsavedLabel: labels?.unsaved ?? saveLabel,\n savedAriaLabel: labels?.savedAriaLabel ?? props.savedAriaLabel,\n unsavedAriaLabel: labels?.unsavedAriaLabel ?? props.unsavedAriaLabel,\n };\n if (!customStateLabel) return <CoreKeepButton<TMeta> {...sharedProps} />;\n const statefulProps = {\n ...sharedProps,\n children: (state: KeepButtonState<TMeta>) => <>{getStateContent(state)}</>,\n };\n return <CoreKeepButton<TMeta> {...statefulProps} />;\n }\n const sharedProps = {\n ...props,\n \"aria-busy\": props[\"aria-busy\"] ?? (buttonState.isLoading || buttonState.isMutating),\n savedLabel: labels?.saved ?? savedLabel,\n unsavedLabel: labels?.unsaved ?? saveLabel,\n savedAriaLabel: labels?.savedAriaLabel ?? props.savedAriaLabel,\n unsavedAriaLabel: labels?.unsavedAriaLabel ?? props.unsavedAriaLabel,\n };\n if (!customStateLabel) return <CoreKeepButton<TMeta> {...sharedProps} />;\n const statefulProps = { ...sharedProps, children: (state: KeepButtonState<TMeta>) => getStateContent(state) };\n return <CoreKeepButton<TMeta> {...statefulProps} />;\n}\n\nexport type KeepItemCardState<TMeta = Record<string, unknown>> = {\n item: KeepItem<TMeta>;\n isSaved: boolean;\n isMutating: boolean;\n error: unknown | null;\n remove: () => Promise<void>;\n};\n\nexport type KeepImageProps = ImgHTMLAttributes<HTMLImageElement> & {\n src: string;\n alt: string;\n};\n\nexport type KeepItemCardProps<TMeta = Record<string, unknown>> = Omit<\n HTMLAttributes<HTMLElement>,\n \"children\" | \"title\"\n> & {\n item: KeepItem<TMeta>;\n title?: ReactNode | ((item: KeepItem<TMeta>) => ReactNode);\n getImageProps?: (item: KeepItem<TMeta>, title: ReactNode) => KeepImageProps | undefined;\n imageComponent?: ComponentType<KeepImageProps>;\n renderImage?: (props: KeepImageProps, item: KeepItem<TMeta>) => ReactNode;\n imageAlt?: string;\n render?: RenderProp<KeepItemCardState<TMeta>>;\n children?: ReactNode | RenderProp<KeepItemCardState<TMeta>>;\n removeLabel?: string;\n onRemoveError?: (error: unknown) => void;\n onRemoved?: (item: KeepItem<TMeta>) => void;\n showSaveButton?: boolean;\n saveButtonLabels?: KeepButtonLabels;\n asChild?: boolean;\n};\n\n/** A low-dependency item presentation primitive. The default markup can be replaced with render props. */\nexport function KeepItemCard<TMeta = Record<string, unknown>>({\n item,\n title,\n getImageProps,\n imageComponent: ImageComponent,\n renderImage,\n imageAlt,\n render,\n children,\n removeLabel,\n onRemoveError,\n onRemoved,\n showSaveButton = true,\n saveButtonLabels,\n asChild = false,\n className,\n ...rootProps\n}: KeepItemCardProps<TMeta>) {\n const saveActionLabel = useUiLabel(\"save\");\n const removeActionLabel = useUiLabel(\"remove\");\n const itemState = useKeepItem<TMeta>(item.id);\n const contentChildren = asChild && isValidElement(children) ? undefined : children;\n const state: KeepItemCardState<TMeta> = {\n item,\n isSaved: itemState.isSaved,\n isMutating: itemState.isMutating,\n error: itemState.error,\n remove: itemState.remove,\n };\n const resolvedTitle = typeof title === \"function\" ? title(item) : (title ?? getMetaTitle(item.meta) ?? item.id);\n const imageProps = getImageProps?.(item, resolvedTitle);\n\n async function handleRemove() {\n try {\n await itemState.remove();\n onRemoved?.(item);\n } catch (error) {\n onRemoveError?.(error);\n }\n }\n\n const body = render\n ? render(state)\n : typeof contentChildren === \"function\"\n ? contentChildren(state)\n : (contentChildren ?? (\n <>\n {imageProps\n ? (renderImage?.({ ...imageProps, alt: imageAlt ?? imageProps.alt }, item) ??\n (ImageComponent ? (\n <ImageComponent {...imageProps} alt={imageAlt ?? imageProps.alt} />\n ) : (\n <img {...imageProps} alt={imageAlt ?? imageProps.alt} />\n )))\n : null}\n <h3>{resolvedTitle}</h3>\n {showSaveButton ? (\n <KeepButton\n item={toKeepButtonItem(item)}\n labels={saveButtonLabels}\n getAriaLabel={(buttonState) =>\n `${buttonState.isSaved ? removeActionLabel : saveActionLabel} ${String(resolvedTitle)}`\n }\n />\n ) : null}\n <button type=\"button\" onClick={() => void handleRemove()} disabled={itemState.isMutating}>\n {removeLabel ?? removeActionLabel}\n </button>\n </>\n ));\n\n return renderRoot(\n asChild,\n isValidElement(children) ? children : undefined,\n { ...rootProps, className, \"aria-busy\": itemState.isMutating || rootProps[\"aria-busy\"] },\n body,\n \"KeepItemCard\",\n );\n}\n\nexport type KeepListState<TMeta = Record<string, unknown>> = UseKeepListResult<TMeta>;\n\nexport type KeepListProps<TMeta = Record<string, unknown>> = Omit<HTMLAttributes<HTMLElement>, \"children\"> & {\n options?: KeepListOptions<TMeta>;\n children?: ReactNode | RenderProp<KeepListState<TMeta>>;\n renderItem?: (item: KeepItem<TMeta>, state: KeepListState<TMeta>) => ReactNode;\n loading?: ReactNode | RenderProp<KeepListState<TMeta>>;\n empty?: ReactNode | RenderProp<KeepListState<TMeta>>;\n error?: ReactNode | RenderProp<KeepListState<TMeta>>;\n itemCardProps?: Omit<KeepItemCardProps<TMeta>, \"item\" | \"children\" | \"render\">;\n asChild?: boolean;\n};\n\n/** A list primitive with built-in loading, empty, error, and removal states. */\nexport function KeepList<TMeta = Record<string, unknown>>({\n options,\n children,\n renderItem,\n loading,\n empty,\n error: errorContent,\n itemCardProps,\n asChild = false,\n className,\n ...rootProps\n}: KeepListProps<TMeta>) {\n const defaultLoading = useUiLabel(\"loadingItems\");\n const defaultEmpty = useUiLabel(\"noItems\");\n const defaultError = useUiLabel(\"errorItems\");\n const state = useKeepList<TMeta>(options);\n const body = getListBody(state, {\n children,\n renderItem,\n loading: loading ?? defaultLoading,\n empty: empty ?? defaultEmpty,\n error: errorContent ?? defaultError,\n itemCardProps,\n });\n const root = asChild && isValidElement(children) ? children : undefined;\n return renderRoot(\n asChild,\n root,\n { ...rootProps, className, \"aria-busy\": state.isLoading || rootProps[\"aria-busy\"] },\n body,\n \"KeepList\",\n );\n}\n\nfunction getListBody<TMeta>(\n state: KeepListState<TMeta>,\n options: {\n children?: ReactNode | RenderProp<KeepListState<TMeta>>;\n renderItem?: (item: KeepItem<TMeta>, state: KeepListState<TMeta>) => ReactNode;\n loading: ReactNode | RenderProp<KeepListState<TMeta>>;\n empty: ReactNode | RenderProp<KeepListState<TMeta>>;\n error: ReactNode | RenderProp<KeepListState<TMeta>>;\n itemCardProps?: Omit<KeepItemCardProps<TMeta>, \"item\" | \"children\" | \"render\">;\n },\n): ReactNode {\n if (state.error && state.items.length === 0) return resolveContent(options.error, state);\n if (state.isLoading && !state.isHydrated) return resolveContent(options.loading, state);\n if (state.isHydrated && state.items.length === 0) return resolveContent(options.empty, state);\n if (typeof options.children === \"function\") return options.children(state);\n if (options.children !== undefined && !isValidElement(options.children)) return options.children;\n const items = state.items.map((item) =>\n options.renderItem ? (\n options.renderItem(item, state)\n ) : (\n <li key={item.id}>\n <KeepItemCard item={item} {...options.itemCardProps} />\n </li>\n ),\n );\n return <ul>{items}</ul>;\n}\n\nexport type KeepTagFilterState = {\n tags: string[];\n tagCounts: Record<string, number>;\n value?: string;\n select: (tag?: string) => void;\n};\n\nexport type KeepTagFilterProps<TMeta = Record<string, unknown>> = Omit<\n HTMLAttributes<HTMLElement>,\n \"children\" | \"onChange\"\n> & {\n listOptions?: KeepListOptions<TMeta>;\n value?: string;\n defaultValue?: string;\n onChange?: (tag?: string) => void;\n onValueChange?: (tag?: string) => void;\n allLabel?: ReactNode;\n ariaLabel?: string;\n renderTag?: (tag: string, count: number, selected: boolean) => ReactNode;\n render?: RenderProp<KeepTagFilterState>;\n children?: ReactNode | RenderProp<KeepTagFilterState>;\n asChild?: boolean;\n};\n\n/** An ARIA button group for tag filtering; consumers can connect value to KeepList options. */\nexport function KeepTagFilter<TMeta = Record<string, unknown>>({\n listOptions,\n value: controlledValue,\n defaultValue,\n onChange,\n onValueChange,\n allLabel,\n ariaLabel,\n renderTag,\n render,\n children,\n asChild = false,\n className,\n ...rootProps\n}: KeepTagFilterProps<TMeta>) {\n const uiAllLabel = useUiLabel(\"allTags\");\n const uiAriaLabel = useUiLabel(\"filterTags\");\n const defaultAllLabel = allLabel ?? uiAllLabel;\n const defaultAriaLabel = ariaLabel ?? uiAriaLabel;\n const list = useKeepList<TMeta>(listOptions);\n const contentChildren = asChild && isValidElement(children) ? undefined : children;\n const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);\n const value = controlledValue ?? uncontrolledValue;\n const select = useCallback(\n (tag?: string) => {\n if (controlledValue === undefined) setUncontrolledValue(tag);\n onChange?.(tag);\n onValueChange?.(tag);\n },\n [controlledValue, onChange, onValueChange],\n );\n const state = useMemo<KeepTagFilterState>(\n () => ({ tags: list.tags, tagCounts: list.tagCounts, value, select }),\n [list.tagCounts, list.tags, select, value],\n );\n const body = render\n ? render(state)\n : typeof contentChildren === \"function\"\n ? contentChildren(state)\n : (contentChildren ?? (\n <fieldset>\n <legend>{defaultAriaLabel}</legend>\n <button type=\"button\" aria-pressed={value === undefined} onClick={() => select()}>\n {defaultAllLabel}\n </button>\n {list.tags.map((tag) => (\n <button key={tag} type=\"button\" aria-pressed={value === tag} onClick={() => select(tag)}>\n {renderTag ? renderTag(tag, list.tagCounts[tag] ?? 0, value === tag) : tag}\n <span> ({list.tagCounts[tag] ?? 0})</span>\n </button>\n ))}\n </fieldset>\n ));\n return renderRoot(\n asChild,\n isValidElement(children) ? children : undefined,\n { ...rootProps, className },\n body,\n \"KeepTagFilter\",\n );\n}\n\nexport type KeepNoteEditorState<TMeta = Record<string, unknown>> = {\n item: KeepItem<TMeta>;\n note: string;\n setNote: (note: string) => void;\n isDirty: boolean;\n isSaving: boolean;\n error: unknown | null;\n save: () => Promise<void>;\n};\n\nexport type KeepNoteEditorProps<TMeta = Record<string, unknown>> = Omit<\n FormHTMLAttributes<HTMLFormElement>,\n \"children\" | \"onSubmit\"\n> & {\n item: KeepItem<TMeta>;\n label?: ReactNode;\n saveLabel?: ReactNode;\n placeholder?: string;\n onSaved?: (note?: string) => void;\n onSaveError?: (error: unknown) => void;\n render?: RenderProp<KeepNoteEditorState<TMeta>>;\n children?: ReactNode | RenderProp<KeepNoteEditorState<TMeta>>;\n asChild?: boolean;\n};\n\n/** A controlled-by-default note editor that persists through useKeepItem. */\nexport function KeepNoteEditor<TMeta = Record<string, unknown>>({\n item,\n label,\n saveLabel,\n placeholder,\n onSaved,\n onSaveError,\n render,\n children,\n asChild = false,\n className,\n ...formProps\n}: KeepNoteEditorProps<TMeta>) {\n const defaultLabel = useUiLabel(\"note\");\n const defaultSaveLabel = useUiLabel(\"saveNote\");\n const itemState = useKeepItem<TMeta>(item.id);\n const contentChildren = asChild && isValidElement(children) ? undefined : children;\n const [note, setNote] = useState(item.note ?? \"\");\n useEffect(() => setNote(itemState.item?.note ?? item.note ?? \"\"), [item.note, itemState.item?.note]);\n const save = useCallback(async () => {\n const nextNote = note.trim() || undefined;\n try {\n await itemState.updateNote(nextNote);\n onSaved?.(nextNote);\n } catch (error) {\n onSaveError?.(error);\n throw error;\n }\n }, [itemState, note, onSaveError, onSaved]);\n const state: KeepNoteEditorState<TMeta> = {\n item,\n note,\n setNote,\n isDirty: note !== (itemState.item?.note ?? item.note ?? \"\"),\n isSaving: itemState.isMutating,\n error: itemState.error,\n save,\n };\n const body = render\n ? render(state)\n : typeof contentChildren === \"function\"\n ? contentChildren(state)\n : (contentChildren ?? (\n <>\n <label>\n {label ?? defaultLabel}\n <textarea\n value={note}\n onChange={(event) => setNote(event.currentTarget.value)}\n placeholder={placeholder}\n disabled={itemState.isMutating}\n />\n </label>\n <button type=\"submit\" disabled={itemState.isMutating} aria-busy={itemState.isMutating}>\n {saveLabel ?? defaultSaveLabel}\n </button>\n </>\n ));\n const handleSubmit: FormHTMLAttributes<HTMLFormElement>[\"onSubmit\"] = (event) => {\n event.preventDefault();\n void save().catch(() => undefined);\n };\n if (!asChild) {\n return (\n <form\n {...formProps}\n className={className}\n onSubmit={handleSubmit}\n aria-busy={itemState.isMutating || formProps[\"aria-busy\"]}\n >\n {body}\n </form>\n );\n }\n return renderRoot(\n true,\n isValidElement(children) ? children : undefined,\n { ...formProps, className, onSubmit: handleSubmit, \"aria-busy\": itemState.isMutating || formProps[\"aria-busy\"] },\n body,\n \"KeepNoteEditor\",\n );\n}\n\nexport type KeepSearchInputProps = Omit<\n InputHTMLAttributes<HTMLInputElement>,\n \"value\" | \"defaultValue\" | \"onChange\"\n> & {\n value?: string;\n defaultValue?: string;\n onValueChange?: (value: string) => void;\n};\n\n/** A controlled/uncontrolled search field for wiring into useKeepList.searchQuery. */\nexport function KeepSearchInput({\n value: controlledValue,\n defaultValue = \"\",\n onValueChange,\n \"aria-label\": ariaLabel,\n placeholder,\n ...props\n}: KeepSearchInputProps) {\n const label = useUiLabel(\"search\");\n const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);\n const value = controlledValue ?? uncontrolledValue;\n return (\n <input\n {...props}\n type=\"search\"\n value={value}\n aria-label={ariaLabel ?? label}\n placeholder={placeholder ?? label}\n onChange={(event) => {\n const nextValue = event.currentTarget.value;\n if (controlledValue === undefined) setUncontrolledValue(nextValue);\n onValueChange?.(nextValue);\n }}\n />\n );\n}\n\nexport type KeepSortValue = \"savedAt:desc\" | \"savedAt:asc\" | \"updatedAt:desc\" | \"updatedAt:asc\";\n\nexport type KeepSortSelectProps = Omit<\n SelectHTMLAttributes<HTMLSelectElement>,\n \"value\" | \"defaultValue\" | \"onChange\"\n> & {\n value?: KeepSortValue;\n defaultValue?: KeepSortValue;\n onValueChange?: (value: KeepSortValue, sort: NonNullable<KeepListOptions[\"sort\"]>) => void;\n};\n\n/** Emits a normalized sort descriptor that can be passed directly to useKeepList. */\nexport function KeepSortSelect({\n value: controlledValue,\n defaultValue = \"updatedAt:desc\",\n onValueChange,\n \"aria-label\": ariaLabel,\n children,\n ...props\n}: KeepSortSelectProps) {\n const label = useUiLabel(\"sort\");\n const newestLabel = useUiLabel(\"newest\");\n const savedLabel = useUiLabel(\"saved\");\n const oldestLabel = useUiLabel(\"oldest\");\n const [uncontrolledValue, setUncontrolledValue] = useState<KeepSortValue>(defaultValue);\n const value = controlledValue ?? uncontrolledValue;\n const options = children ?? (\n <>\n <option value=\"updatedAt:desc\">{newestLabel}</option>\n <option value=\"savedAt:desc\">{savedLabel}</option>\n <option value=\"updatedAt:asc\">{oldestLabel}</option>\n <option value=\"savedAt:asc\">{oldestLabel}</option>\n </>\n );\n return (\n <select\n {...props}\n value={value}\n aria-label={ariaLabel ?? label}\n onChange={(event) => {\n const nextValue = event.currentTarget.value as KeepSortValue;\n if (controlledValue === undefined) setUncontrolledValue(nextValue);\n const [by, direction] = nextValue.split(\":\") as [\"savedAt\" | \"updatedAt\", \"asc\" | \"desc\"];\n onValueChange?.(nextValue, { by, direction });\n }}\n >\n {options}\n </select>\n );\n}\n\nexport type KeepPaginationProps = Omit<HTMLAttributes<HTMLElement>, \"children\"> & {\n totalCount: number;\n pageSize: number;\n page?: number;\n onPageChange?: (page: number, offset: number) => void;\n render?: RenderProp<{ page: number; pageCount: number; goToPage: (page: number) => void }>;\n};\n\n/** A small accessible pagination control using one-based pages and zero-based offsets. */\nexport function KeepPagination({\n totalCount,\n pageSize,\n page = 1,\n onPageChange,\n render,\n ...props\n}: KeepPaginationProps) {\n const previousPageLabel = useUiLabel(\"previousPage\");\n const nextPageLabel = useUiLabel(\"nextPage\");\n const pageLabel = useUiLabel(\"page\");\n const paginationLabel = useUiLabel(\"pagination\");\n const pageCount = Math.max(1, Math.ceil(totalCount / Math.max(1, pageSize)));\n const currentPage = Math.min(Math.max(1, page), pageCount);\n const goToPage = (nextPage: number) => {\n const next = Math.min(Math.max(1, nextPage), pageCount);\n onPageChange?.(next, (next - 1) * pageSize);\n };\n if (render) return <nav {...props}>{render({ page: currentPage, pageCount, goToPage })}</nav>;\n return (\n <nav {...props} aria-label={props[\"aria-label\"] ?? paginationLabel}>\n <button type=\"button\" onClick={() => goToPage(currentPage - 1)} disabled={currentPage <= 1}>\n {previousPageLabel}\n </button>\n <span aria-current=\"page\">\n {pageLabel} {currentPage} / {pageCount}\n </span>\n <button type=\"button\" onClick={() => goToPage(currentPage + 1)} disabled={currentPage >= pageCount}>\n {nextPageLabel}\n </button>\n </nav>\n );\n}\n\nexport type KeepTagEditorProps<TMeta = Record<string, unknown>> = Omit<\n FormHTMLAttributes<HTMLFormElement>,\n \"children\" | \"onSubmit\"\n> & {\n item: KeepItem<TMeta>;\n availableTags?: string[];\n onSaved?: (tags?: string[]) => void;\n onSaveError?: (error: unknown) => void;\n render?: RenderProp<{\n tags: string[];\n setTags: (tags: string[]) => void;\n save: () => Promise<void>;\n isSaving: boolean;\n }>;\n};\n\n/** Edits one item's normalized tag set and exposes a render-prop escape hatch. */\nexport function KeepTagEditor<TMeta = Record<string, unknown>>({\n item,\n availableTags = [],\n onSaved,\n onSaveError,\n render,\n ...props\n}: KeepTagEditorProps<TMeta>) {\n const tagsLabel = useUiLabel(\"tagsToApply\");\n const removeLabel = useUiLabel(\"remove\");\n const applyTagsLabel = useUiLabel(\"applyTags\");\n const itemState = useKeepItem<TMeta>(item.id);\n const [tags, setTags] = useState(item.tags ?? []);\n const [input, setInput] = useState(\"\");\n useEffect(() => setTags(itemState.item?.tags ?? item.tags ?? []), [item.tags, itemState.item?.tags]);\n const save = useCallback(async () => {\n const nextTags = normalizeUiTags(tags);\n try {\n await itemState.updateTags(nextTags);\n setTags(nextTags);\n onSaved?.(nextTags);\n } catch (error) {\n onSaveError?.(error);\n throw error;\n }\n }, [itemState, onSaveError, onSaved, tags]);\n const addTag = (tag: string) => {\n const next = normalizeUiTags([...tags, tag]);\n setTags(next);\n setInput(\"\");\n };\n const body = render ? (\n render({ tags, setTags, save, isSaving: itemState.isMutating })\n ) : (\n <>\n <label>\n {tagsLabel}\n <input\n value={input}\n list={availableTags.length > 0 ? `keep-tags-${item.id}` : undefined}\n onChange={(event) => setInput(event.currentTarget.value)}\n onKeyDown={(event) => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n if (input.trim()) addTag(input);\n }\n }}\n />\n </label>\n {availableTags.length > 0 ? (\n <datalist id={`keep-tags-${item.id}`}>\n {availableTags.map((tag) => (\n <option key={tag} value={tag} />\n ))}\n </datalist>\n ) : null}\n <ul aria-label={tagsLabel}>\n {tags.map((tag) => (\n <li key={tag}>\n {tag}\n <button type=\"button\" onClick={() => setTags(tags.filter((current) => current !== tag))}>\n {removeLabel}\n </button>\n </li>\n ))}\n </ul>\n <button type=\"submit\" disabled={itemState.isMutating} aria-busy={itemState.isMutating}>\n {applyTagsLabel}\n </button>\n </>\n );\n return (\n <form\n {...props}\n onSubmit={(event) => {\n event.preventDefault();\n void save().catch(() => undefined);\n }}\n aria-busy={itemState.isMutating || props[\"aria-busy\"]}\n >\n {body}\n </form>\n );\n}\n\nexport type KeepBulkActionsProps<TMeta = Record<string, unknown>> = Omit<HTMLAttributes<HTMLElement>, \"children\"> & {\n listOptions?: KeepListOptions<TMeta>;\n selectedIds?: string[];\n defaultSelectedIds?: string[];\n onSelectedIdsChange?: (ids: string[]) => void;\n renderItem?: (item: KeepItem<TMeta>, selected: boolean) => ReactNode;\n onCompleted?: (action: \"remove\" | \"tags\", ids: string[]) => void;\n};\n\n/** Selects visible items and performs one storage operation for the whole selection. */\nexport function KeepBulkActions<TMeta = Record<string, unknown>>({\n listOptions,\n selectedIds: controlledSelectedIds,\n defaultSelectedIds = [],\n onSelectedIdsChange,\n renderItem,\n onCompleted,\n ...props\n}: KeepBulkActionsProps<TMeta>) {\n const selectItemsLabel = useUiLabel(\"selectItems\");\n const selectedCountLabel = useUiLabel(\"selectedCount\");\n const deleteSelectedLabel = useUiLabel(\"deleteSelected\");\n const tagsLabel = useUiLabel(\"tagsToApply\");\n const applyTagsLabel = useUiLabel(\"applyTags\");\n const list = useKeepList<TMeta>(listOptions);\n const [uncontrolledSelectedIds, setUncontrolledSelectedIds] = useState(defaultSelectedIds);\n const selectedIds = controlledSelectedIds ?? uncontrolledSelectedIds;\n const selected = new Set(selectedIds);\n const [tagsInput, setTagsInput] = useState(\"\");\n const setSelectedIds = (ids: string[]) => {\n if (controlledSelectedIds === undefined) setUncontrolledSelectedIds(ids);\n onSelectedIdsChange?.(ids);\n };\n const toggle = (id: string) =>\n setSelectedIds(selected.has(id) ? selectedIds.filter((current) => current !== id) : [...selectedIds, id]);\n const allSelected = list.items.length > 0 && list.items.every((item) => selected.has(item.id));\n const toggleAll = () => setSelectedIds(allSelected ? [] : list.items.map((item) => item.id));\n const remove = async () => {\n await list.removeBatch(selectedIds);\n onCompleted?.(\"remove\", selectedIds);\n setSelectedIds([]);\n };\n const updateTags = async () => {\n const tags = normalizeUiTags(tagsInput.split(\",\"));\n await list.updateTagsBatch(selectedIds, tags);\n onCompleted?.(\"tags\", selectedIds);\n setSelectedIds([]);\n };\n return (\n <section {...props} aria-busy={list.isMutating || props[\"aria-busy\"]}>\n <fieldset>\n <legend>{selectItemsLabel}</legend>\n <label>\n <input type=\"checkbox\" checked={allSelected} onChange={toggleAll} />\n {selectedIds.length} {selectedCountLabel}\n </label>\n {list.items.map((item) => (\n <label key={item.id}>\n <input type=\"checkbox\" checked={selected.has(item.id)} onChange={() => toggle(item.id)} />\n {renderItem ? renderItem(item, selected.has(item.id)) : (getMetaTitle(item.meta) ?? item.id)}\n </label>\n ))}\n </fieldset>\n <button type=\"button\" onClick={() => void remove()} disabled={selectedIds.length === 0 || list.isMutating}>\n {deleteSelectedLabel}\n </button>\n <label>\n {tagsLabel}\n <input value={tagsInput} onChange={(event) => setTagsInput(event.currentTarget.value)} />\n </label>\n <button type=\"button\" onClick={() => void updateTags()} disabled={selectedIds.length === 0 || list.isMutating}>\n {applyTagsLabel}\n </button>\n </section>\n );\n}\n\nexport type KeepEmptyStateProps = Omit<HTMLAttributes<HTMLElement>, \"children\" | \"title\"> & {\n title?: ReactNode;\n description?: ReactNode;\n action?: ReactNode;\n children?: ReactNode;\n asChild?: boolean;\n};\n\n/** A style-free, reusable empty collection state. */\nexport function KeepEmptyState({\n title,\n description,\n action,\n children,\n asChild = false,\n className,\n ...rootProps\n}: KeepEmptyStateProps) {\n const defaultTitle = useUiLabel(\"noItems\").replace(/\\.$/, \"\");\n const contentChildren = asChild && isValidElement(children) ? undefined : children;\n const body = contentChildren ?? (\n <>\n <h2>{title ?? defaultTitle}</h2>\n {description ? <p>{description}</p> : null}\n {action}\n </>\n );\n return renderRoot(asChild, children, { ...rootProps, className }, body, \"KeepEmptyState\");\n}\n\nexport type KeepStatusValue = \"idle\" | \"empty\" | \"loading\" | \"saving\" | \"syncing\" | \"error\";\n\nexport type KeepStatusLabels = Partial<Record<KeepStatusValue, ReactNode>>;\n\nexport type KeepStatusState<TMeta = Record<string, unknown>> = {\n status: KeepStatusValue;\n error: unknown | null;\n pendingCount: number;\n items: KeepItem<TMeta>[];\n};\n\nexport type KeepStatusProps<TMeta = Record<string, unknown>> = Omit<HTMLAttributes<HTMLElement>, \"children\"> & {\n status?: KeepStatusValue;\n labels?: KeepStatusLabels;\n children?: ReactNode | RenderProp<KeepStatusState<TMeta>>;\n render?: RenderProp<KeepStatusState<TMeta>>;\n asChild?: boolean;\n};\n\n/** Presents provider loading, mutation, synchronization, empty, and error states accessibly. */\nexport function KeepStatus<TMeta = Record<string, unknown>>({\n status,\n labels,\n children,\n render,\n asChild = false,\n className,\n ...rootProps\n}: KeepStatusProps<TMeta>) {\n const context = useKeepContext<TMeta>();\n const contentChildren = asChild && isValidElement(children) ? undefined : children;\n const resolvedStatus = status ?? getDerivedStatus(context);\n const defaultLabel = useUiLabel(getStatusLabelKey(resolvedStatus));\n const state: KeepStatusState<TMeta> = {\n status: resolvedStatus,\n error: context.error,\n pendingCount: context.syncState.pendingCount,\n items: context.items,\n };\n const body = render\n ? render(state)\n : typeof contentChildren === \"function\"\n ? contentChildren(state)\n : (contentChildren ?? labels?.[resolvedStatus] ?? defaultLabel);\n const role = rootProps.role ?? (resolvedStatus === \"error\" ? \"alert\" : \"status\");\n return renderRoot(\n asChild,\n isValidElement(children) ? children : undefined,\n { ...rootProps, className, role, \"aria-live\": rootProps[\"aria-live\"] ?? \"polite\" },\n body,\n \"KeepStatus\",\n );\n}\n\nexport type KeepAnnouncementsProps = Omit<HTMLAttributes<HTMLElement>, \"children\"> & {\n messages?: Partial<Record<\"save\" | \"remove\" | \"note\", string>>;\n};\n\n/** Announces successful save, remove, and note operations in a polite live region. */\nexport function KeepAnnouncements<TMeta = Record<string, unknown>>({ messages, ...props }: KeepAnnouncementsProps) {\n const context = useKeepContext<TMeta>();\n const savedMessage = useUiLabel(\"savedMessage\", messages?.save);\n const removedMessage = useUiLabel(\"removedMessage\", messages?.remove);\n const noteSavedMessage = useUiLabel(\"noteSavedMessage\", messages?.note);\n const [message, setMessage] = useState(\"\");\n const lastChangeRef = useRef<KeepChangeContext<TMeta> | undefined>(undefined);\n useEffect(() => {\n const change = context.lastChange;\n if (!change || change === lastChangeRef.current) return;\n lastChangeRef.current = change;\n if (change.action === \"save\") setMessage(savedMessage);\n else if (change.action === \"remove\" || change.action === \"removeBatch\") setMessage(removedMessage);\n else if (change.action === \"updateNote\") setMessage(noteSavedMessage);\n }, [context.lastChange, noteSavedMessage, removedMessage, savedMessage]);\n return (\n <div {...props} role={props.role ?? \"status\"} aria-live={props[\"aria-live\"] ?? \"polite\"} aria-atomic=\"true\">\n {message}\n </div>\n );\n}\n\nfunction getDerivedStatus<TMeta>(context: ReturnType<typeof useKeepContext<TMeta>>): KeepStatusValue {\n if (context.error) return \"error\";\n if (context.syncState.status === \"pending\" || context.syncState.status === \"syncing\") return \"syncing\";\n if (context.isMutating) return \"saving\";\n if (context.isLoading && !context.isHydrated) return \"loading\";\n if (context.isHydrated && context.items.length === 0) return \"empty\";\n return \"idle\";\n}\n\nfunction getStatusLabelKey(status: KeepStatusValue): KeepUiLabelKey {\n if (status === \"empty\") return \"noItems\";\n if (status === \"loading\") return \"loadingItems\";\n if (status === \"error\") return \"error\";\n if (status === \"saving\") return \"saving\";\n if (status === \"syncing\") return \"syncing\";\n return \"saved\";\n}\n\nfunction resolveContent<TState>(content: ReactNode | RenderProp<TState>, state: TState): ReactNode {\n return typeof content === \"function\" ? content(state) : content;\n}\n\nfunction toKeepButtonItem<TMeta>(item: KeepItem<TMeta>): KeepItemInput<TMeta> & { id: string } {\n return {\n id: item.id,\n meta: item.meta,\n targetType: item.targetType,\n note: item.note,\n tags: item.tags,\n };\n}\n\nfunction getMetaTitle<TMeta>(meta: TMeta): string | undefined {\n if (typeof meta !== \"object\" || meta === null || !(\"title\" in meta)) return undefined;\n const title = (meta as { title?: unknown }).title;\n return typeof title === \"string\" && title.trim() ? title.trim() : undefined;\n}\n\nfunction normalizeUiTags(tags: string[]): string[] {\n return [...new Set(tags.map((tag) => tag.trim()).filter(Boolean))];\n}\n\nfunction renderRoot(\n asChild: boolean,\n child: ReactNode,\n props: HTMLAttributes<HTMLElement> & Record<string, unknown>,\n body: ReactNode,\n componentName: string,\n): ReactElement {\n if (asChild) {\n if (!isValidElement(child)) throw new Error(`${componentName} with asChild requires a single React element child.`);\n return cloneElement(child as ReactElement<Record<string, unknown>>, { ...props, children: body });\n }\n return <div {...props}>{body}</div>;\n}\n"],"mappings":"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","names":["useKeepContext","useKeepItem","useKeepList","sharedProps","statefulProps"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx"],"sourcesContent":["\"use client\";\n\nimport type { KeepChangeContext, KeepItem, KeepItemInput, KeepListQuery, KeepSyncStatus } from \"@keepkit/core/core\";\nimport type { UseKeepListResult } from \"@keepkit/core/react\";\nimport {\n type CreateKeepKitOptions as CoreCreateKeepKitOptions,\n KeepButton as CoreKeepButton,\n type KeepButtonProps as CoreKeepButtonProps,\n KeepProvider as CoreKeepProvider,\n createKeepKit as createCoreKeepKit,\n type KeepButtonState,\n type KeepProviderProps,\n type KeepShortcutOptions,\n useKeepContext,\n useKeepItem,\n useKeepList,\n} from \"@keepkit/core/react\";\nimport {\n type ComponentType,\n cloneElement,\n createContext,\n type FormHTMLAttributes,\n type HTMLAttributes,\n type ImgHTMLAttributes,\n type InputHTMLAttributes,\n isValidElement,\n type ReactElement,\n type ReactNode,\n type SelectHTMLAttributes,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nexport type KeepUiLabelKey =\n | \"save\"\n | \"saved\"\n | \"remove\"\n | \"loading\"\n | \"saving\"\n | \"syncing\"\n | \"error\"\n | \"allTags\"\n | \"filterTags\"\n | \"note\"\n | \"saveNote\"\n | \"noItems\"\n | \"loadingItems\"\n | \"errorItems\"\n | \"search\"\n | \"sort\"\n | \"newest\"\n | \"oldest\"\n | \"previousPage\"\n | \"nextPage\"\n | \"pagination\"\n | \"page\"\n | \"selectItems\"\n | \"selectedCount\"\n | \"deleteSelected\"\n | \"tagsToApply\"\n | \"applyTags\"\n | \"savedMessage\"\n | \"removedMessage\"\n | \"noteSavedMessage\";\n\nexport type KeepUiLabels = Partial<Record<KeepUiLabelKey, string>>;\n\nexport type KeepUiLabelContext = {\n locale?: string;\n labels: Readonly<Record<KeepUiLabelKey, string>>;\n labelResolver?: (key: KeepUiLabelKey, context: { locale?: string }) => string | undefined;\n};\n\nconst DEFAULT_LABELS: Record<KeepUiLabelKey, string> = {\n save: \"Save\",\n saved: \"Saved\",\n remove: \"Remove\",\n loading: \"Loading…\",\n saving: \"Saving…\",\n syncing: \"Syncing…\",\n error: \"Something went wrong.\",\n allTags: \"All\",\n filterTags: \"Filter saved items by tag\",\n note: \"Note\",\n saveNote: \"Save note\",\n noItems: \"No saved items.\",\n loadingItems: \"Loading saved items…\",\n errorItems: \"Could not load saved items.\",\n search: \"Search saved items\",\n sort: \"Sort saved items\",\n newest: \"Newest first\",\n oldest: \"Oldest first\",\n previousPage: \"Previous page\",\n nextPage: \"Next page\",\n pagination: \"Pagination\",\n page: \"Page\",\n selectItems: \"Select saved items\",\n selectedCount: \"selected\",\n deleteSelected: \"Delete selected\",\n tagsToApply: \"Tags to apply\",\n applyTags: \"Apply tags\",\n savedMessage: \"Item saved.\",\n removedMessage: \"Item removed.\",\n noteSavedMessage: \"Note saved.\",\n};\n\nconst KeepUiLabelsContext = createContext<KeepUiLabelContext>({ labels: DEFAULT_LABELS });\n\nexport type KeepUiProviderProps = {\n labels?: KeepUiLabels;\n locale?: string;\n labelResolver?: KeepUiLabelContext[\"labelResolver\"];\n children?: ReactNode;\n};\n\n/** Provides one locale-aware label source to every UI primitive. */\nexport function KeepUiProvider({ labels, locale, labelResolver, children }: KeepUiProviderProps) {\n const value = useMemo<KeepUiLabelContext>(() => {\n const resolved = { ...DEFAULT_LABELS, ...labels };\n return { locale, labels: resolved, labelResolver };\n }, [labelResolver, labels, locale]);\n return <KeepUiLabelsContext.Provider value={value}>{children}</KeepUiLabelsContext.Provider>;\n}\n\nexport type KeepKitProviderProps<TMeta = Record<string, unknown>> = Omit<KeepProviderProps<TMeta>, \"children\"> &\n Omit<KeepUiProviderProps, \"children\"> & {\n children?: ReactNode;\n };\n\n/** Combines the core store and UI labels into the default application provider. */\nexport function KeepKitProvider<TMeta = Record<string, unknown>>({\n labels,\n locale,\n labelResolver,\n children,\n ...providerProps\n}: KeepKitProviderProps<TMeta>) {\n return (\n <KeepUiProvider labels={labels} locale={locale} labelResolver={labelResolver}>\n <CoreKeepProvider<TMeta> {...providerProps}>{children}</CoreKeepProvider>\n </KeepUiProvider>\n );\n}\n\nexport function useKeepUiLabels(): KeepUiLabelContext {\n return useContext(KeepUiLabelsContext);\n}\n\nfunction useUiLabel(key: KeepUiLabelKey, override?: string): string {\n const context = useKeepUiLabels();\n return override ?? context.labelResolver?.(key, { locale: context.locale }) ?? context.labels[key];\n}\n\nexport type { KeepContextValue, KeepProviderProps } from \"@keepkit/core/react\";\nexport { KeepProvider, useKeepContext, useKeepItem, useKeepList, useKeepShortcut } from \"@keepkit/core/react\";\nexport {\n createBrowserStorageAdapter,\n createStorageAdapter,\n FallbackStorageAdapter,\n IndexedDBAdapter,\n IndexedDBSyncQueueAdapter,\n LocalStorageAdapter,\n LocalStorageSyncQueueAdapter,\n SyncStorageAdapter,\n} from \"@keepkit/core/storage\";\nexport type { KeepItem, KeepItemInput, KeepListQuery, KeepShortcutOptions, KeepSyncStatus };\n\nexport type CreateKeepKitOptions<TMeta = Record<string, unknown>> = CoreCreateKeepKitOptions<TMeta> &\n Omit<KeepUiProviderProps, \"children\"> & {\n getTitle?: (item: KeepItem<TMeta>) => ReactNode;\n getImageProps?: (item: KeepItem<TMeta>, title: ReactNode) => KeepImageProps | undefined;\n };\n\nexport type KeepKit<TMeta = Record<string, unknown>> = {\n Provider: ComponentType<KeepKitProviderProps<TMeta>>;\n Button: ComponentType<KeepButtonProps<TMeta>>;\n Collection: ComponentType<KeepCollectionProps<TMeta>>;\n useContext: () => ReturnType<typeof useKeepContext<TMeta>>;\n useItem: (item?: KeepItemInput<TMeta>) => ReturnType<typeof useKeepItem<TMeta>>;\n useList: (query?: KeepListQuery<TMeta>) => UseKeepListResult<TMeta>;\n useShortcut: (options: KeepShortcutOptions<TMeta>) => void;\n};\n\n/** Create one typed application API for the core and the standard UI layer. */\nexport function createKeepKit<TMeta = Record<string, unknown>>(\n options: CreateKeepKitOptions<TMeta> = {},\n): KeepKit<TMeta> {\n const { labels, locale, labelResolver, getTitle, getImageProps, ...coreOptions } = options;\n const coreKit = createCoreKeepKit<TMeta>(coreOptions);\n return {\n Provider: (props) => (\n <KeepKitProvider<TMeta>\n {...coreOptions}\n labels={labels}\n locale={locale}\n labelResolver={labelResolver}\n {...props}\n />\n ),\n Button: (props) => <KeepButton<TMeta> {...props} />,\n Collection: (props) => (\n <KeepCollection<TMeta>\n {...props}\n itemCardProps={{\n ...(getTitle ? { getTitle } : {}),\n ...(getImageProps ? { getImageProps } : {}),\n ...props.itemCardProps,\n }}\n />\n ),\n useContext: () => coreKit.useContext(),\n useItem: (item) => coreKit.useItem(item),\n useList: (query) => coreKit.useList(query),\n useShortcut: (shortcutOptions) => coreKit.useShortcut(shortcutOptions),\n };\n}\n\nexport type RenderProp<TState> = (state: TState) => ReactNode;\n\nexport type KeepButtonLabels = {\n saved?: ReactNode;\n unsaved?: ReactNode;\n loading?: ReactNode;\n error?: ReactNode;\n savedAriaLabel?: string;\n unsavedAriaLabel?: string;\n};\n\nexport type KeepButtonProps<TMeta = Record<string, unknown>> = CoreKeepButtonProps<TMeta> & {\n labels?: KeepButtonLabels;\n};\n\n/** A style-free save toggle with localized labels and the core button's ARIA/asChild behavior. */\nexport function KeepButton<TMeta = Record<string, unknown>>({ labels, ...props }: KeepButtonProps<TMeta>) {\n const saveLabel = useUiLabel(\"save\", typeof labels?.unsaved === \"string\" ? labels.unsaved : undefined);\n const savedLabel = useUiLabel(\"saved\", typeof labels?.saved === \"string\" ? labels.saved : undefined);\n const loadingLabel = useUiLabel(\"loading\", typeof labels?.loading === \"string\" ? labels.loading : undefined);\n const errorLabel = useUiLabel(\"error\", typeof labels?.error === \"string\" ? labels.error : undefined);\n const buttonState = useKeepItem<TMeta>(props.item);\n const customStateLabel = labels?.loading !== undefined || labels?.error !== undefined;\n const getStateContent = (state: KeepButtonState<TMeta>): ReactNode => {\n if (state.error) return labels?.error ?? errorLabel;\n if (state.isMutating) return labels?.loading ?? loadingLabel;\n if (typeof props.children === \"function\") return props.children(state);\n if (props.children !== undefined) return props.children;\n return state.isSaved ? (labels?.saved ?? savedLabel) : (labels?.unsaved ?? saveLabel);\n };\n if (props.asChild === true) {\n const sharedProps = {\n ...props,\n \"aria-busy\": props[\"aria-busy\"] ?? (buttonState.isLoading || buttonState.isMutating),\n savedLabel: labels?.saved ?? props.savedLabel ?? savedLabel,\n unsavedLabel: labels?.unsaved ?? props.unsavedLabel ?? saveLabel,\n savedAriaLabel: labels?.savedAriaLabel ?? props.savedAriaLabel,\n unsavedAriaLabel: labels?.unsavedAriaLabel ?? props.unsavedAriaLabel,\n };\n if (!customStateLabel) return <CoreKeepButton<TMeta> {...sharedProps} />;\n const statefulProps = {\n ...sharedProps,\n children: (state: KeepButtonState<TMeta>) => <>{getStateContent(state)}</>,\n };\n return <CoreKeepButton<TMeta> {...statefulProps} />;\n }\n const sharedProps = {\n ...props,\n \"aria-busy\": props[\"aria-busy\"] ?? (buttonState.isLoading || buttonState.isMutating),\n savedLabel: labels?.saved ?? props.savedLabel ?? savedLabel,\n unsavedLabel: labels?.unsaved ?? props.unsavedLabel ?? saveLabel,\n savedAriaLabel: labels?.savedAriaLabel ?? props.savedAriaLabel,\n unsavedAriaLabel: labels?.unsavedAriaLabel ?? props.unsavedAriaLabel,\n };\n if (!customStateLabel) return <CoreKeepButton<TMeta> {...sharedProps} />;\n const statefulProps = { ...sharedProps, children: (state: KeepButtonState<TMeta>) => getStateContent(state) };\n return <CoreKeepButton<TMeta> {...statefulProps} />;\n}\n\nexport type KeepItemCardState<TMeta = Record<string, unknown>> = {\n item: KeepItem<TMeta>;\n isSaved: boolean;\n isMutating: boolean;\n error: unknown | null;\n remove: () => Promise<void>;\n};\n\nexport type KeepImageProps = ImgHTMLAttributes<HTMLImageElement> & {\n src: string;\n alt: string;\n};\n\nexport type KeepItemCardProps<TMeta = Record<string, unknown>> = Omit<\n HTMLAttributes<HTMLElement>,\n \"children\" | \"title\"\n> & {\n item: KeepItem<TMeta>;\n title?: ReactNode | ((item: KeepItem<TMeta>) => ReactNode);\n getTitle?: (item: KeepItem<TMeta>) => ReactNode;\n getImageProps?: (item: KeepItem<TMeta>, title: ReactNode) => KeepImageProps | undefined;\n imageComponent?: ComponentType<KeepImageProps>;\n renderImage?: (props: KeepImageProps, item: KeepItem<TMeta>) => ReactNode;\n imageAlt?: string;\n render?: RenderProp<KeepItemCardState<TMeta>>;\n children?: ReactNode | RenderProp<KeepItemCardState<TMeta>>;\n removeLabel?: string;\n onRemoveError?: (error: unknown) => void;\n onRemoved?: (item: KeepItem<TMeta>) => void;\n showSaveButton?: boolean;\n saveButtonLabels?: KeepButtonLabels;\n asChild?: boolean;\n};\n\n/** A low-dependency item presentation primitive. The default markup can be replaced with render props. */\nexport function KeepItemCard<TMeta = Record<string, unknown>>({\n item,\n title,\n getTitle,\n getImageProps,\n imageComponent: ImageComponent,\n renderImage,\n imageAlt,\n render,\n children,\n removeLabel,\n onRemoveError,\n onRemoved,\n showSaveButton = true,\n saveButtonLabels,\n asChild = false,\n className,\n ...rootProps\n}: KeepItemCardProps<TMeta>) {\n const saveActionLabel = useUiLabel(\"save\");\n const removeActionLabel = useUiLabel(\"remove\");\n const itemState = useKeepItem<TMeta>(item);\n const contentChildren = asChild && isValidElement(children) ? undefined : children;\n const state: KeepItemCardState<TMeta> = {\n item,\n isSaved: itemState.isSaved,\n isMutating: itemState.isMutating,\n error: itemState.error,\n remove: itemState.remove,\n };\n const resolvedTitle =\n typeof title === \"function\" ? title(item) : (title ?? getTitle?.(item) ?? getMetaTitle(item.meta) ?? item.id);\n const imageProps = getImageProps?.(item, resolvedTitle);\n\n async function handleRemove() {\n try {\n await itemState.remove();\n onRemoved?.(item);\n } catch (error) {\n onRemoveError?.(error);\n }\n }\n\n const body = render\n ? render(state)\n : typeof contentChildren === \"function\"\n ? contentChildren(state)\n : (contentChildren ?? (\n <>\n {imageProps\n ? (renderImage?.({ ...imageProps, alt: imageAlt ?? imageProps.alt }, item) ??\n (ImageComponent ? (\n <ImageComponent {...imageProps} alt={imageAlt ?? imageProps.alt} />\n ) : (\n <img {...imageProps} alt={imageAlt ?? imageProps.alt} />\n )))\n : null}\n <h3>{resolvedTitle}</h3>\n {showSaveButton ? (\n <KeepButton\n item={toKeepButtonItem(item)}\n labels={saveButtonLabels}\n getAriaLabel={(buttonState) =>\n `${buttonState.isSaved ? removeActionLabel : saveActionLabel} ${String(resolvedTitle)}`\n }\n />\n ) : null}\n <button type=\"button\" onClick={() => void handleRemove()} disabled={itemState.isMutating}>\n {removeLabel ?? removeActionLabel}\n </button>\n </>\n ));\n\n return renderRoot(\n asChild,\n isValidElement(children) ? children : undefined,\n { ...rootProps, className, \"aria-busy\": itemState.isMutating || rootProps[\"aria-busy\"] },\n body,\n \"KeepItemCard\",\n );\n}\n\nexport type KeepListState<TMeta = Record<string, unknown>> = UseKeepListResult<TMeta>;\n\nexport type KeepListProps<TMeta = Record<string, unknown>> = Omit<HTMLAttributes<HTMLElement>, \"children\"> & {\n query?: KeepListQuery<TMeta>;\n children?: ReactNode | RenderProp<KeepListState<TMeta>>;\n renderItem?: (item: KeepItem<TMeta>, state: KeepListState<TMeta>) => ReactNode;\n loading?: ReactNode | RenderProp<KeepListState<TMeta>>;\n empty?: ReactNode | RenderProp<KeepListState<TMeta>>;\n error?: ReactNode | RenderProp<KeepListState<TMeta>>;\n itemCardProps?: Omit<KeepItemCardProps<TMeta>, \"item\" | \"children\" | \"render\">;\n asChild?: boolean;\n};\n\n/** A list primitive with built-in loading, empty, error, and removal states. */\nexport function KeepList<TMeta = Record<string, unknown>>({\n query,\n children,\n renderItem,\n loading,\n empty,\n error: errorContent,\n itemCardProps,\n asChild = false,\n className,\n ...rootProps\n}: KeepListProps<TMeta>) {\n const defaultLoading = useUiLabel(\"loadingItems\");\n const defaultEmpty = useUiLabel(\"noItems\");\n const defaultError = useUiLabel(\"errorItems\");\n const state = useKeepList<TMeta>(query);\n const body = getListBody(state, {\n children,\n renderItem,\n loading: loading ?? defaultLoading,\n empty: empty ?? defaultEmpty,\n error: errorContent ?? defaultError,\n itemCardProps,\n });\n const root = asChild && isValidElement(children) ? children : undefined;\n return renderRoot(\n asChild,\n root,\n { ...rootProps, className, \"aria-busy\": state.isLoading || rootProps[\"aria-busy\"] },\n body,\n \"KeepList\",\n );\n}\n\nfunction getListBody<TMeta>(\n state: KeepListState<TMeta>,\n options: {\n children?: ReactNode | RenderProp<KeepListState<TMeta>>;\n renderItem?: (item: KeepItem<TMeta>, state: KeepListState<TMeta>) => ReactNode;\n loading: ReactNode | RenderProp<KeepListState<TMeta>>;\n empty: ReactNode | RenderProp<KeepListState<TMeta>>;\n error: ReactNode | RenderProp<KeepListState<TMeta>>;\n itemCardProps?: Omit<KeepItemCardProps<TMeta>, \"item\" | \"children\" | \"render\">;\n },\n): ReactNode {\n if (state.error && state.items.length === 0) return resolveContent(options.error, state);\n if (state.isLoading && !state.isHydrated) return resolveContent(options.loading, state);\n if (state.isHydrated && state.items.length === 0) return resolveContent(options.empty, state);\n if (typeof options.children === \"function\") return options.children(state);\n if (options.children !== undefined && !isValidElement(options.children)) return options.children;\n const items = state.items.map((item) =>\n options.renderItem ? (\n options.renderItem(item, state)\n ) : (\n <li key={item.id}>\n <KeepItemCard item={item} {...options.itemCardProps} />\n </li>\n ),\n );\n return <ul>{items}</ul>;\n}\n\nexport type KeepCollectionFeature = \"search\" | \"sort\" | \"pagination\" | \"tagFilter\" | \"bulkActions\";\n\nexport type KeepCollectionProps<TMeta = Record<string, unknown>> = Omit<HTMLAttributes<HTMLElement>, \"children\"> & {\n query?: KeepListQuery<TMeta>;\n pageSize?: number;\n features?: Partial<Record<KeepCollectionFeature, boolean>>;\n renderItem?: (item: KeepItem<TMeta>, state: KeepListState<TMeta>) => ReactNode;\n itemCardProps?: Omit<KeepItemCardProps<TMeta>, \"item\" | \"children\" | \"render\">;\n loading?: ReactNode | RenderProp<KeepListState<TMeta>>;\n empty?: ReactNode | RenderProp<KeepListState<TMeta>>;\n error?: ReactNode | RenderProp<KeepListState<TMeta>>;\n};\n\n/** A batteries-included collection with query controls and accessible status feedback. */\nexport function KeepCollection<TMeta = Record<string, unknown>>({\n query = {},\n pageSize = 20,\n features,\n renderItem,\n itemCardProps,\n loading,\n empty,\n error,\n className,\n ...rootProps\n}: KeepCollectionProps<TMeta>) {\n const enabled = {\n search: true,\n sort: true,\n pagination: true,\n tagFilter: false,\n bulkActions: false,\n ...features,\n };\n const [searchValue, setSearchValue] = useState(query.search?.query ?? \"\");\n const [sort, setSort] = useState(query.sort ?? { by: \"updatedAt\" as const, direction: \"desc\" as const });\n const [tag, setTag] = useState<string | undefined>(query.tags?.[0]);\n const [page, setPage] = useState(query.pagination?.page ?? 1);\n const resolvedPageSize = query.pagination?.pageSize ?? pageSize;\n const resolvedQuery = useMemo<KeepListQuery<TMeta>>(\n () => ({\n ...query,\n search: enabled.search ? { ...query.search, query: searchValue } : query.search,\n sort: enabled.sort ? sort : query.sort,\n tags: tag ? [...new Set([...(query.tags ?? []), tag])] : query.tags,\n pagination: enabled.pagination ? { ...query.pagination, page, pageSize: resolvedPageSize } : query.pagination,\n }),\n [enabled.pagination, enabled.search, enabled.sort, page, query, resolvedPageSize, searchValue, sort, tag],\n );\n const list = useKeepList<TMeta>(resolvedQuery);\n\n useEffect(() => {\n if (searchValue !== undefined || sort.by !== undefined || sort.direction !== undefined || tag !== undefined) {\n setPage(1);\n }\n }, [searchValue, sort.by, sort.direction, tag]);\n\n return (\n <section\n {...rootProps}\n className={className}\n aria-busy={list.isLoading || list.isMutating || rootProps[\"aria-busy\"]}\n >\n <div>\n {enabled.search ? <KeepSearchInput value={searchValue} onValueChange={setSearchValue} /> : null}\n {enabled.sort ? (\n <KeepSortSelect value={sortToValue(sort)} onValueChange={(_value, nextSort) => setSort(nextSort)} />\n ) : null}\n {enabled.tagFilter ? <KeepTagFilter<TMeta> query={query} value={tag} onValueChange={setTag} /> : null}\n </div>\n <KeepList<TMeta>\n query={resolvedQuery}\n renderItem={renderItem}\n itemCardProps={itemCardProps}\n loading={loading}\n empty={empty}\n error={error}\n />\n {enabled.pagination ? (\n <KeepPagination\n totalCount={list.totalCount}\n pageSize={resolvedPageSize}\n page={list.page}\n onPageChange={(_nextPage, nextPageOffset) => setPage(Math.floor(nextPageOffset / resolvedPageSize) + 1)}\n />\n ) : null}\n {enabled.bulkActions ? <KeepBulkActions<TMeta> query={resolvedQuery} /> : null}\n <KeepAnnouncements />\n </section>\n );\n}\n\nexport type KeepTagFilterState = {\n tags: string[];\n tagCounts: Record<string, number>;\n value?: string;\n select: (tag?: string) => void;\n};\n\nexport type KeepTagFilterProps<TMeta = Record<string, unknown>> = Omit<\n HTMLAttributes<HTMLElement>,\n \"children\" | \"onChange\"\n> & {\n query?: KeepListQuery<TMeta>;\n value?: string;\n defaultValue?: string;\n onChange?: (tag?: string) => void;\n onValueChange?: (tag?: string) => void;\n allLabel?: ReactNode;\n ariaLabel?: string;\n renderTag?: (tag: string, count: number, selected: boolean) => ReactNode;\n render?: RenderProp<KeepTagFilterState>;\n children?: ReactNode | RenderProp<KeepTagFilterState>;\n asChild?: boolean;\n};\n\n/** An ARIA button group for tag filtering; consumers can connect value to a collection query. */\nexport function KeepTagFilter<TMeta = Record<string, unknown>>({\n query,\n value: controlledValue,\n defaultValue,\n onChange,\n onValueChange,\n allLabel,\n ariaLabel,\n renderTag,\n render,\n children,\n asChild = false,\n className,\n ...rootProps\n}: KeepTagFilterProps<TMeta>) {\n const uiAllLabel = useUiLabel(\"allTags\");\n const uiAriaLabel = useUiLabel(\"filterTags\");\n const defaultAllLabel = allLabel ?? uiAllLabel;\n const defaultAriaLabel = ariaLabel ?? uiAriaLabel;\n const contentChildren = asChild && isValidElement(children) ? undefined : children;\n const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);\n const value = controlledValue ?? uncontrolledValue;\n const list = useKeepList<TMeta>({ ...query, tags: value ? [...(query?.tags ?? []), value] : query?.tags });\n const select = useCallback(\n (tag?: string) => {\n if (controlledValue === undefined) setUncontrolledValue(tag);\n onChange?.(tag);\n onValueChange?.(tag);\n },\n [controlledValue, onChange, onValueChange],\n );\n const state = useMemo<KeepTagFilterState>(\n () => ({ tags: list.tags, tagCounts: list.tagCounts, value, select }),\n [list.tagCounts, list.tags, select, value],\n );\n const body = render\n ? render(state)\n : typeof contentChildren === \"function\"\n ? contentChildren(state)\n : (contentChildren ?? (\n <fieldset>\n <legend>{defaultAriaLabel}</legend>\n <button type=\"button\" aria-pressed={value === undefined} onClick={() => select()}>\n {defaultAllLabel}\n </button>\n {list.tags.map((tag) => (\n <button key={tag} type=\"button\" aria-pressed={value === tag} onClick={() => select(tag)}>\n {renderTag ? renderTag(tag, list.tagCounts[tag] ?? 0, value === tag) : tag}\n <span> ({list.tagCounts[tag] ?? 0})</span>\n </button>\n ))}\n </fieldset>\n ));\n return renderRoot(\n asChild,\n isValidElement(children) ? children : undefined,\n { ...rootProps, className },\n body,\n \"KeepTagFilter\",\n );\n}\n\nexport type KeepNoteEditorState<TMeta = Record<string, unknown>> = {\n item: KeepItem<TMeta>;\n note: string;\n setNote: (note: string) => void;\n isDirty: boolean;\n isSaving: boolean;\n error: unknown | null;\n save: () => Promise<void>;\n};\n\nexport type KeepNoteEditorProps<TMeta = Record<string, unknown>> = Omit<\n FormHTMLAttributes<HTMLFormElement>,\n \"children\" | \"onSubmit\"\n> & {\n item: KeepItem<TMeta>;\n label?: ReactNode;\n saveLabel?: ReactNode;\n placeholder?: string;\n onSaved?: (note?: string) => void;\n onSaveError?: (error: unknown) => void;\n render?: RenderProp<KeepNoteEditorState<TMeta>>;\n children?: ReactNode | RenderProp<KeepNoteEditorState<TMeta>>;\n asChild?: boolean;\n};\n\n/** A controlled-by-default note editor that persists through useKeepItem. */\nexport function KeepNoteEditor<TMeta = Record<string, unknown>>({\n item,\n label,\n saveLabel,\n placeholder,\n onSaved,\n onSaveError,\n render,\n children,\n asChild = false,\n className,\n ...formProps\n}: KeepNoteEditorProps<TMeta>) {\n const defaultLabel = useUiLabel(\"note\");\n const defaultSaveLabel = useUiLabel(\"saveNote\");\n const itemState = useKeepItem<TMeta>(item);\n const contentChildren = asChild && isValidElement(children) ? undefined : children;\n const [note, setNote] = useState(item.note ?? \"\");\n useEffect(() => setNote(itemState.item?.note ?? item.note ?? \"\"), [item.note, itemState.item?.note]);\n const save = useCallback(async () => {\n const nextNote = note.trim() || undefined;\n try {\n await itemState.updateNote(nextNote);\n onSaved?.(nextNote);\n } catch (error) {\n onSaveError?.(error);\n throw error;\n }\n }, [itemState, note, onSaveError, onSaved]);\n const state: KeepNoteEditorState<TMeta> = {\n item,\n note,\n setNote,\n isDirty: note !== (itemState.item?.note ?? item.note ?? \"\"),\n isSaving: itemState.isMutating,\n error: itemState.error,\n save,\n };\n const body = render\n ? render(state)\n : typeof contentChildren === \"function\"\n ? contentChildren(state)\n : (contentChildren ?? (\n <>\n <label>\n {label ?? defaultLabel}\n <textarea\n value={note}\n onChange={(event) => setNote(event.currentTarget.value)}\n placeholder={placeholder}\n disabled={itemState.isMutating}\n />\n </label>\n <button type=\"submit\" disabled={itemState.isMutating} aria-busy={itemState.isMutating}>\n {saveLabel ?? defaultSaveLabel}\n </button>\n </>\n ));\n const handleSubmit: FormHTMLAttributes<HTMLFormElement>[\"onSubmit\"] = (event) => {\n event.preventDefault();\n void save().catch(() => undefined);\n };\n if (!asChild) {\n return (\n <form\n {...formProps}\n className={className}\n onSubmit={handleSubmit}\n aria-busy={itemState.isMutating || formProps[\"aria-busy\"]}\n >\n {body}\n </form>\n );\n }\n return renderRoot(\n true,\n isValidElement(children) ? children : undefined,\n { ...formProps, className, onSubmit: handleSubmit, \"aria-busy\": itemState.isMutating || formProps[\"aria-busy\"] },\n body,\n \"KeepNoteEditor\",\n );\n}\n\nexport type KeepSearchInputProps = Omit<\n InputHTMLAttributes<HTMLInputElement>,\n \"value\" | \"defaultValue\" | \"onChange\"\n> & {\n value?: string;\n defaultValue?: string;\n onValueChange?: (value: string) => void;\n};\n\n/** A controlled/uncontrolled search field for wiring into KeepListQuery.search. */\nexport function KeepSearchInput({\n value: controlledValue,\n defaultValue = \"\",\n onValueChange,\n \"aria-label\": ariaLabel,\n placeholder,\n ...props\n}: KeepSearchInputProps) {\n const label = useUiLabel(\"search\");\n const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);\n const value = controlledValue ?? uncontrolledValue;\n return (\n <input\n {...props}\n type=\"search\"\n value={value}\n aria-label={ariaLabel ?? label}\n placeholder={placeholder ?? label}\n onChange={(event) => {\n const nextValue = event.currentTarget.value;\n if (controlledValue === undefined) setUncontrolledValue(nextValue);\n onValueChange?.(nextValue);\n }}\n />\n );\n}\n\nexport type KeepSortValue = \"savedAt:desc\" | \"savedAt:asc\" | \"updatedAt:desc\" | \"updatedAt:asc\";\n\nexport type KeepSortSelectProps = Omit<\n SelectHTMLAttributes<HTMLSelectElement>,\n \"value\" | \"defaultValue\" | \"onChange\"\n> & {\n value?: KeepSortValue;\n defaultValue?: KeepSortValue;\n onValueChange?: (value: KeepSortValue, sort: NonNullable<KeepListQuery[\"sort\"]>) => void;\n};\n\n/** Emits a normalized sort descriptor that can be passed directly to useKeepList. */\nexport function KeepSortSelect({\n value: controlledValue,\n defaultValue = \"updatedAt:desc\",\n onValueChange,\n \"aria-label\": ariaLabel,\n children,\n ...props\n}: KeepSortSelectProps) {\n const label = useUiLabel(\"sort\");\n const newestLabel = useUiLabel(\"newest\");\n const savedLabel = useUiLabel(\"saved\");\n const oldestLabel = useUiLabel(\"oldest\");\n const [uncontrolledValue, setUncontrolledValue] = useState<KeepSortValue>(defaultValue);\n const value = controlledValue ?? uncontrolledValue;\n const options = children ?? (\n <>\n <option value=\"updatedAt:desc\">{newestLabel}</option>\n <option value=\"savedAt:desc\">{savedLabel}</option>\n <option value=\"updatedAt:asc\">{oldestLabel}</option>\n <option value=\"savedAt:asc\">{oldestLabel}</option>\n </>\n );\n return (\n <select\n {...props}\n value={value}\n aria-label={ariaLabel ?? label}\n onChange={(event) => {\n const nextValue = event.currentTarget.value as KeepSortValue;\n if (controlledValue === undefined) setUncontrolledValue(nextValue);\n const [by, direction] = nextValue.split(\":\") as [\"savedAt\" | \"updatedAt\", \"asc\" | \"desc\"];\n onValueChange?.(nextValue, { by, direction });\n }}\n >\n {options}\n </select>\n );\n}\n\nexport type KeepPaginationProps = Omit<HTMLAttributes<HTMLElement>, \"children\"> & {\n totalCount: number;\n pageSize: number;\n page?: number;\n onPageChange?: (page: number, offset: number) => void;\n render?: RenderProp<{ page: number; pageCount: number; goToPage: (page: number) => void }>;\n};\n\n/** A small accessible pagination control using one-based pages and zero-based offsets. */\nexport function KeepPagination({\n totalCount,\n pageSize,\n page = 1,\n onPageChange,\n render,\n ...props\n}: KeepPaginationProps) {\n const previousPageLabel = useUiLabel(\"previousPage\");\n const nextPageLabel = useUiLabel(\"nextPage\");\n const pageLabel = useUiLabel(\"page\");\n const paginationLabel = useUiLabel(\"pagination\");\n const pageCount = Math.max(1, Math.ceil(totalCount / Math.max(1, pageSize)));\n const currentPage = Math.min(Math.max(1, page), pageCount);\n const goToPage = (nextPage: number) => {\n const next = Math.min(Math.max(1, nextPage), pageCount);\n onPageChange?.(next, (next - 1) * pageSize);\n };\n if (render) return <nav {...props}>{render({ page: currentPage, pageCount, goToPage })}</nav>;\n return (\n <nav {...props} aria-label={props[\"aria-label\"] ?? paginationLabel}>\n <button type=\"button\" onClick={() => goToPage(currentPage - 1)} disabled={currentPage <= 1}>\n {previousPageLabel}\n </button>\n <span aria-current=\"page\">\n {pageLabel} {currentPage} / {pageCount}\n </span>\n <button type=\"button\" onClick={() => goToPage(currentPage + 1)} disabled={currentPage >= pageCount}>\n {nextPageLabel}\n </button>\n </nav>\n );\n}\n\nexport type KeepTagEditorProps<TMeta = Record<string, unknown>> = Omit<\n FormHTMLAttributes<HTMLFormElement>,\n \"children\" | \"onSubmit\"\n> & {\n item: KeepItem<TMeta>;\n availableTags?: string[];\n onSaved?: (tags?: string[]) => void;\n onSaveError?: (error: unknown) => void;\n render?: RenderProp<{\n tags: string[];\n setTags: (tags: string[]) => void;\n save: () => Promise<void>;\n isSaving: boolean;\n }>;\n};\n\n/** Edits one item's normalized tag set and exposes a render-prop escape hatch. */\nexport function KeepTagEditor<TMeta = Record<string, unknown>>({\n item,\n availableTags = [],\n onSaved,\n onSaveError,\n render,\n ...props\n}: KeepTagEditorProps<TMeta>) {\n const tagsLabel = useUiLabel(\"tagsToApply\");\n const removeLabel = useUiLabel(\"remove\");\n const applyTagsLabel = useUiLabel(\"applyTags\");\n const itemState = useKeepItem<TMeta>(item);\n const [tags, setTags] = useState(item.tags ?? []);\n const [input, setInput] = useState(\"\");\n useEffect(() => setTags(itemState.item?.tags ?? item.tags ?? []), [item.tags, itemState.item?.tags]);\n const save = useCallback(async () => {\n const nextTags = normalizeUiTags(tags);\n try {\n await itemState.updateTags(nextTags);\n setTags(nextTags);\n onSaved?.(nextTags);\n } catch (error) {\n onSaveError?.(error);\n throw error;\n }\n }, [itemState, onSaveError, onSaved, tags]);\n const addTag = (tag: string) => {\n const next = normalizeUiTags([...tags, tag]);\n setTags(next);\n setInput(\"\");\n };\n const body = render ? (\n render({ tags, setTags, save, isSaving: itemState.isMutating })\n ) : (\n <>\n <label>\n {tagsLabel}\n <input\n value={input}\n list={availableTags.length > 0 ? `keep-tags-${item.id}` : undefined}\n onChange={(event) => setInput(event.currentTarget.value)}\n onKeyDown={(event) => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n if (input.trim()) addTag(input);\n }\n }}\n />\n </label>\n {availableTags.length > 0 ? (\n <datalist id={`keep-tags-${item.id}`}>\n {availableTags.map((tag) => (\n <option key={tag} value={tag} />\n ))}\n </datalist>\n ) : null}\n <ul aria-label={tagsLabel}>\n {tags.map((tag) => (\n <li key={tag}>\n {tag}\n <button type=\"button\" onClick={() => setTags(tags.filter((current) => current !== tag))}>\n {removeLabel}\n </button>\n </li>\n ))}\n </ul>\n <button type=\"submit\" disabled={itemState.isMutating} aria-busy={itemState.isMutating}>\n {applyTagsLabel}\n </button>\n </>\n );\n return (\n <form\n {...props}\n onSubmit={(event) => {\n event.preventDefault();\n void save().catch(() => undefined);\n }}\n aria-busy={itemState.isMutating || props[\"aria-busy\"]}\n >\n {body}\n </form>\n );\n}\n\nexport type KeepBulkActionsProps<TMeta = Record<string, unknown>> = Omit<HTMLAttributes<HTMLElement>, \"children\"> & {\n query?: KeepListQuery<TMeta>;\n selectedIds?: string[];\n defaultSelectedIds?: string[];\n onSelectedIdsChange?: (ids: string[]) => void;\n renderItem?: (item: KeepItem<TMeta>, selected: boolean) => ReactNode;\n onCompleted?: (action: \"remove\" | \"tags\", ids: string[]) => void;\n};\n\n/** Selects visible items and performs one storage operation for the whole selection. */\nexport function KeepBulkActions<TMeta = Record<string, unknown>>({\n query,\n selectedIds: controlledSelectedIds,\n defaultSelectedIds = [],\n onSelectedIdsChange,\n renderItem,\n onCompleted,\n ...props\n}: KeepBulkActionsProps<TMeta>) {\n const selectItemsLabel = useUiLabel(\"selectItems\");\n const selectedCountLabel = useUiLabel(\"selectedCount\");\n const deleteSelectedLabel = useUiLabel(\"deleteSelected\");\n const tagsLabel = useUiLabel(\"tagsToApply\");\n const applyTagsLabel = useUiLabel(\"applyTags\");\n const list = useKeepList<TMeta>(query);\n const [uncontrolledSelectedIds, setUncontrolledSelectedIds] = useState(defaultSelectedIds);\n const selectedIds = controlledSelectedIds ?? uncontrolledSelectedIds;\n const selected = new Set(selectedIds);\n const [tagsInput, setTagsInput] = useState(\"\");\n const setSelectedIds = (ids: string[]) => {\n if (controlledSelectedIds === undefined) setUncontrolledSelectedIds(ids);\n onSelectedIdsChange?.(ids);\n };\n const toggle = (id: string) =>\n setSelectedIds(selected.has(id) ? selectedIds.filter((current) => current !== id) : [...selectedIds, id]);\n const allSelected = list.items.length > 0 && list.items.every((item) => selected.has(item.id));\n const toggleAll = () => setSelectedIds(allSelected ? [] : list.items.map((item) => item.id));\n const remove = async () => {\n await list.removeBatch(selectedIds);\n onCompleted?.(\"remove\", selectedIds);\n setSelectedIds([]);\n };\n const updateTags = async () => {\n const tags = normalizeUiTags(tagsInput.split(\",\"));\n await list.updateTagsBatch(selectedIds, tags);\n onCompleted?.(\"tags\", selectedIds);\n setSelectedIds([]);\n };\n return (\n <section {...props} aria-busy={list.isMutating || props[\"aria-busy\"]}>\n <fieldset>\n <legend>{selectItemsLabel}</legend>\n <label>\n <input type=\"checkbox\" checked={allSelected} onChange={toggleAll} />\n {selectedIds.length} {selectedCountLabel}\n </label>\n {list.items.map((item) => (\n <label key={item.id}>\n <input type=\"checkbox\" checked={selected.has(item.id)} onChange={() => toggle(item.id)} />\n {renderItem ? renderItem(item, selected.has(item.id)) : (getMetaTitle(item.meta) ?? item.id)}\n </label>\n ))}\n </fieldset>\n <button type=\"button\" onClick={() => void remove()} disabled={selectedIds.length === 0 || list.isMutating}>\n {deleteSelectedLabel}\n </button>\n <label>\n {tagsLabel}\n <input value={tagsInput} onChange={(event) => setTagsInput(event.currentTarget.value)} />\n </label>\n <button type=\"button\" onClick={() => void updateTags()} disabled={selectedIds.length === 0 || list.isMutating}>\n {applyTagsLabel}\n </button>\n </section>\n );\n}\n\nexport type KeepEmptyStateProps = Omit<HTMLAttributes<HTMLElement>, \"children\" | \"title\"> & {\n title?: ReactNode;\n description?: ReactNode;\n action?: ReactNode;\n children?: ReactNode;\n asChild?: boolean;\n};\n\n/** A style-free, reusable empty collection state. */\nexport function KeepEmptyState({\n title,\n description,\n action,\n children,\n asChild = false,\n className,\n ...rootProps\n}: KeepEmptyStateProps) {\n const defaultTitle = useUiLabel(\"noItems\").replace(/\\.$/, \"\");\n const contentChildren = asChild && isValidElement(children) ? undefined : children;\n const body = contentChildren ?? (\n <>\n <h2>{title ?? defaultTitle}</h2>\n {description ? <p>{description}</p> : null}\n {action}\n </>\n );\n return renderRoot(asChild, children, { ...rootProps, className }, body, \"KeepEmptyState\");\n}\n\nexport type KeepStatusValue = \"idle\" | \"empty\" | \"loading\" | \"saving\" | \"syncing\" | \"error\";\n\nexport type KeepStatusLabels = Partial<Record<KeepStatusValue, ReactNode>>;\n\nexport type KeepStatusState<TMeta = Record<string, unknown>> = {\n status: KeepStatusValue;\n error: unknown | null;\n pendingCount: number;\n items: KeepItem<TMeta>[];\n};\n\nexport type KeepStatusProps<TMeta = Record<string, unknown>> = Omit<HTMLAttributes<HTMLElement>, \"children\"> & {\n status?: KeepStatusValue;\n labels?: KeepStatusLabels;\n children?: ReactNode | RenderProp<KeepStatusState<TMeta>>;\n render?: RenderProp<KeepStatusState<TMeta>>;\n asChild?: boolean;\n};\n\n/** Presents provider loading, mutation, synchronization, empty, and error states accessibly. */\nexport function KeepStatus<TMeta = Record<string, unknown>>({\n status,\n labels,\n children,\n render,\n asChild = false,\n className,\n ...rootProps\n}: KeepStatusProps<TMeta>) {\n const context = useKeepContext<TMeta>();\n const contentChildren = asChild && isValidElement(children) ? undefined : children;\n const resolvedStatus = status ?? getDerivedStatus(context);\n const defaultLabel = useUiLabel(getStatusLabelKey(resolvedStatus));\n const state: KeepStatusState<TMeta> = {\n status: resolvedStatus,\n error: context.error,\n pendingCount: context.syncState.pendingCount,\n items: context.items,\n };\n const body = render\n ? render(state)\n : typeof contentChildren === \"function\"\n ? contentChildren(state)\n : (contentChildren ?? labels?.[resolvedStatus] ?? defaultLabel);\n const role = rootProps.role ?? (resolvedStatus === \"error\" ? \"alert\" : \"status\");\n return renderRoot(\n asChild,\n isValidElement(children) ? children : undefined,\n { ...rootProps, className, role, \"aria-live\": rootProps[\"aria-live\"] ?? \"polite\" },\n body,\n \"KeepStatus\",\n );\n}\n\nexport type KeepAnnouncementsProps = Omit<HTMLAttributes<HTMLElement>, \"children\"> & {\n messages?: Partial<Record<\"save\" | \"remove\" | \"note\", string>>;\n};\n\n/** Announces successful save, remove, and note operations in a polite live region. */\nexport function KeepAnnouncements<TMeta = Record<string, unknown>>({ messages, ...props }: KeepAnnouncementsProps) {\n const context = useKeepContext<TMeta>();\n const savedMessage = useUiLabel(\"savedMessage\", messages?.save);\n const removedMessage = useUiLabel(\"removedMessage\", messages?.remove);\n const noteSavedMessage = useUiLabel(\"noteSavedMessage\", messages?.note);\n const [message, setMessage] = useState(\"\");\n const lastChangeRef = useRef<KeepChangeContext<TMeta> | undefined>(undefined);\n useEffect(() => {\n const change = context.lastChange;\n if (!change || change === lastChangeRef.current) return;\n lastChangeRef.current = change;\n if (change.action === \"save\") setMessage(savedMessage);\n else if (change.action === \"remove\" || change.action === \"removeBatch\") setMessage(removedMessage);\n else if (change.action === \"updateNote\") setMessage(noteSavedMessage);\n }, [context.lastChange, noteSavedMessage, removedMessage, savedMessage]);\n return (\n <div {...props} role={props.role ?? \"status\"} aria-live={props[\"aria-live\"] ?? \"polite\"} aria-atomic=\"true\">\n {message}\n </div>\n );\n}\n\nfunction getDerivedStatus<TMeta>(context: ReturnType<typeof useKeepContext<TMeta>>): KeepStatusValue {\n if (context.error) return \"error\";\n if (context.syncState.status === \"pending\" || context.syncState.status === \"syncing\") return \"syncing\";\n if (context.isMutating) return \"saving\";\n if (context.isLoading && !context.isHydrated) return \"loading\";\n if (context.isHydrated && context.items.length === 0) return \"empty\";\n return \"idle\";\n}\n\nfunction getStatusLabelKey(status: KeepStatusValue): KeepUiLabelKey {\n if (status === \"empty\") return \"noItems\";\n if (status === \"loading\") return \"loadingItems\";\n if (status === \"error\") return \"error\";\n if (status === \"saving\") return \"saving\";\n if (status === \"syncing\") return \"syncing\";\n return \"saved\";\n}\n\nfunction resolveContent<TState>(content: ReactNode | RenderProp<TState>, state: TState): ReactNode {\n return typeof content === \"function\" ? content(state) : content;\n}\n\nfunction toKeepButtonItem<TMeta>(item: KeepItem<TMeta>): KeepItemInput<TMeta> {\n return {\n id: item.id,\n meta: item.meta,\n targetType: item.targetType,\n note: item.note,\n tags: item.tags,\n };\n}\n\nfunction getMetaTitle<TMeta>(meta: TMeta): string | undefined {\n if (typeof meta !== \"object\" || meta === null || !(\"title\" in meta)) return undefined;\n const title = (meta as { title?: unknown }).title;\n return typeof title === \"string\" && title.trim() ? title.trim() : undefined;\n}\n\nfunction normalizeUiTags(tags: string[]): string[] {\n return [...new Set(tags.map((tag) => tag.trim()).filter(Boolean))];\n}\n\nfunction sortToValue(sort: KeepListQuery[\"sort\"]): KeepSortValue {\n return `${sort?.by ?? \"updatedAt\"}:${sort?.direction ?? \"desc\"}` as KeepSortValue;\n}\n\nfunction renderRoot(\n asChild: boolean,\n child: ReactNode,\n props: HTMLAttributes<HTMLElement> & Record<string, unknown>,\n body: ReactNode,\n componentName: string,\n): ReactElement {\n if (asChild) {\n if (!isValidElement(child)) throw new Error(`${componentName} with asChild requires a single React element child.`);\n return cloneElement(child as ReactElement<Record<string, unknown>>, { ...props, children: body });\n }\n return <div {...props}>{body}</div>;\n}\n"],"mappings":"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","names":["useKeepContext","useKeepItem","useKeepList","sharedProps","statefulProps"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keepkit/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Headless, accessible React UI components for KeepKit.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -27,11 +27,12 @@
|
|
|
27
27
|
"access": "public"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
|
-
"@keepkit/core": ">=0.4.0",
|
|
31
30
|
"react": ">=18"
|
|
32
31
|
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@keepkit/core": "0.5.0"
|
|
34
|
+
},
|
|
33
35
|
"devDependencies": {
|
|
34
|
-
"@keepkit/core": "0.4.0",
|
|
35
36
|
"@types/react": "^19.2.18",
|
|
36
37
|
"react": "^19.2.8",
|
|
37
38
|
"tsup": "^8.5.1",
|