@thebes/cadmea 1.0.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/LICENSE +21 -0
- package/README.md +133 -0
- package/dist/RichTextEditor-BPilh7Pw.js +36 -0
- package/dist/RichTextEditor-BPilh7Pw.js.map +1 -0
- package/dist/RichTextEditor-DcLqdFY7.js +15 -0
- package/dist/RichTextEditor-DcLqdFY7.js.map +1 -0
- package/dist/index/index.d.ts +147 -0
- package/dist/index/index.js +740 -0
- package/dist/index/index.js.map +1 -0
- package/dist/index/server.js +508 -0
- package/dist/index/server.js.map +1 -0
- package/dist/tanstack-start/index.d.ts +180 -0
- package/dist/tanstack-start/index.js +897 -0
- package/dist/tanstack-start/index.js.map +1 -0
- package/dist/tanstack-start/server.js +730 -0
- package/dist/tanstack-start/server.js.map +1 -0
- package/package.json +138 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 BowenLabs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# @thebes/cadmea
|
|
2
|
+
|
|
3
|
+
Generic SolidJS admin-UI components for `@thebes/cadmus/cms` collections.
|
|
4
|
+
|
|
5
|
+
> **0.x — active development.** APIs will change. Not production-ready.
|
|
6
|
+
> Star [bowenlabs/project-thebes](https://github.com/bowenlabs/project-thebes) to follow along.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## What is this?
|
|
11
|
+
|
|
12
|
+
Cadmus's `cms` subpath (collection config, schema codegen, the Local API,
|
|
13
|
+
admin-introspection metadata) is the engine — framework-agnostic, no UI of
|
|
14
|
+
its own. This package is the other half: the actual SolidJS components
|
|
15
|
+
that render a generic admin UI from that metadata, the same way Payload
|
|
16
|
+
splits `payload` core from `@payloadcms/next`/`@payloadcms/ui`.
|
|
17
|
+
|
|
18
|
+
`app/workers/cadmea` (Thebes's reference CMS) consumes this package rather
|
|
19
|
+
than owning the components directly.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pnpm add @thebes/cadmea @thebes/cadmus solid-js
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Built with [Vite+'s `vp pack`](https://viteplus.dev/guide/pack)
|
|
30
|
+
(Rolldown-based, wraps [`tsdown`](https://tsdown.dev) internally) plus
|
|
31
|
+
[`@rolldown/plugin-babel`](https://github.com/rolldown/plugins) running
|
|
32
|
+
Solid's JSX through `babel-preset-solid` directly, to produce real
|
|
33
|
+
fine-grained-reactive output — not the generic `createElement`-style
|
|
34
|
+
transform plain Rolldown/esbuild would otherwise produce by default. See
|
|
35
|
+
`DECISIONS.md`'s 2026-06-24 entry for how the babel plugin is wired into
|
|
36
|
+
`vp pack`'s `pack` block in `vite.config.ts`. Ships separate
|
|
37
|
+
`browser`/`worker`/`node`/`deno` export conditions,
|
|
38
|
+
matching how `solid-js` itself ships, so the right build
|
|
39
|
+
(client-hydration vs. SSR) resolves automatically wherever you consume it
|
|
40
|
+
— including from outside this monorepo, unlike the source-only shape this
|
|
41
|
+
package started as (see `DECISIONS.md`'s 2026-06-22 entries).
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Components
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { CollectionList, CollectionEdit } from '@thebes/cadmea'
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**`CollectionList`** — generic table view. Renders one column per field
|
|
52
|
+
(excluding `id` and `richText` fields, which aren't supported as plain
|
|
53
|
+
table cells yet), with optional row-click navigation.
|
|
54
|
+
|
|
55
|
+
**`CollectionEdit`** — generic create/edit form. Renders one input per
|
|
56
|
+
field (excluding `id`), with `text`/`select`/`number` editable inputs and
|
|
57
|
+
`date` fields shown read-only. Fields without a supported renderer
|
|
58
|
+
(`richText`/`relationship`/`array`/`upload`/`checkbox`) are silently
|
|
59
|
+
skipped rather than crashing — contributions welcome.
|
|
60
|
+
|
|
61
|
+
Both take a `CollectionConfig` (from `@thebes/cadmus/cms`) as their
|
|
62
|
+
`config` prop.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## TanStack Start mounting helper
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import {
|
|
70
|
+
createCollectionListPage,
|
|
71
|
+
createCollectionCreatePage,
|
|
72
|
+
createCollectionEditPage,
|
|
73
|
+
} from '@thebes/cadmea/tanstack-start'
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The equivalent of Payload's `@payloadcms/next` catch-all route pattern —
|
|
77
|
+
factory functions that wire `CollectionList`/`CollectionEdit` together
|
|
78
|
+
with `@tanstack/solid-query` (fetching, mutating, cache invalidation) and
|
|
79
|
+
return a ready-to-use route `component`. TanStack Router's file-based
|
|
80
|
+
routing still needs a real file per route (there's no runtime catch-all
|
|
81
|
+
the way Next.js's `[[...segments]]` works), but each route file shrinks
|
|
82
|
+
from ~40 hand-wired lines to ~15:
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
// src/routes/admin/pages/index.tsx
|
|
86
|
+
import { createCollectionListPage } from '@thebes/cadmea/tanstack-start'
|
|
87
|
+
import { createFileRoute, useNavigate } from '@tanstack/solid-router'
|
|
88
|
+
import { pagesCollection } from '../../../../cadmea.config.js'
|
|
89
|
+
import { getPages } from '../../server-functions/pages'
|
|
90
|
+
|
|
91
|
+
export const Route = createFileRoute('/admin/pages/')({ component: PagesPage })
|
|
92
|
+
|
|
93
|
+
function PagesPage() {
|
|
94
|
+
const navigate = useNavigate()
|
|
95
|
+
const Page = createCollectionListPage({
|
|
96
|
+
collection: pagesCollection,
|
|
97
|
+
label: 'Pages',
|
|
98
|
+
queryKey: ['pages'],
|
|
99
|
+
queryFn: () => getPages(),
|
|
100
|
+
newHref: '/admin/pages/new',
|
|
101
|
+
onRowClick: (row) => navigate({ to: '/admin/pages/$pageId', params: { pageId: String(row.id) } }),
|
|
102
|
+
})
|
|
103
|
+
return <Page />
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Navigation (`onRowClick`, `onCreated`, `onDeleted`) stays in the route
|
|
108
|
+
file rather than this package calling `useNavigate()` itself — TanStack
|
|
109
|
+
Router's route-typing is generated per-app, so a generic package can't
|
|
110
|
+
produce a correctly-typed `navigate()` call for routes it doesn't know
|
|
111
|
+
about. See `app/workers/cadmea/src/routes/admin/pages/` in this repo for
|
|
112
|
+
all three factories in real use (list, create, edit+delete).
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## What this isn't (yet)
|
|
117
|
+
|
|
118
|
+
No code-generation CLI that writes these route files for you from a
|
|
119
|
+
collection config — you still create one thin file per collection per
|
|
120
|
+
view. Worth revisiting once enough collections exist to justify that
|
|
121
|
+
investment. See this repo's `DECISIONS.md`.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Licensing
|
|
126
|
+
|
|
127
|
+
MIT. See [LICENSE](./LICENSE) for full terms.
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Maintained by
|
|
132
|
+
|
|
133
|
+
[BowenLabs](https://bowenlabs.com)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { effect, setAttribute, template, use } from "solid-js/web";
|
|
2
|
+
import { onCleanup, onMount } from "solid-js";
|
|
3
|
+
import { Editor } from "@tiptap/core";
|
|
4
|
+
import StarterKit from "@tiptap/starter-kit";
|
|
5
|
+
//#region src/RichTextEditor.tsx
|
|
6
|
+
var _tmpl$ = /*#__PURE__*/ template(`<div class="textarea h-auto min-h-32 w-full">`);
|
|
7
|
+
function RichTextEditor(props) {
|
|
8
|
+
let container;
|
|
9
|
+
let editor;
|
|
10
|
+
onMount(() => {
|
|
11
|
+
if (!container) return;
|
|
12
|
+
editor = new Editor({
|
|
13
|
+
element: container,
|
|
14
|
+
extensions: [StarterKit],
|
|
15
|
+
content: props.content ?? "",
|
|
16
|
+
onUpdate: ({ editor: current }) => {
|
|
17
|
+
props.onChange(current.getJSON());
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
onCleanup(() => {
|
|
22
|
+
editor?.destroy();
|
|
23
|
+
});
|
|
24
|
+
return (() => {
|
|
25
|
+
var _el$ = _tmpl$();
|
|
26
|
+
use((el) => {
|
|
27
|
+
container = el;
|
|
28
|
+
}, _el$);
|
|
29
|
+
effect(() => setAttribute(_el$, "id", props.id));
|
|
30
|
+
return _el$;
|
|
31
|
+
})();
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
export { RichTextEditor };
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=RichTextEditor-BPilh7Pw.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RichTextEditor-BPilh7Pw.js","names":["Editor","StarterKit","onCleanup","onMount","RichTextEditorProps","id","content","onChange","doc","RichTextEditor","props","container","HTMLDivElement","editor","element","extensions","onUpdate","current","getJSON","destroy","_el$","_tmpl$","_$use","el","_$effect","_$setAttribute"],"sources":["../src/RichTextEditor.tsx"],"sourcesContent":["import { Editor } from \"@tiptap/core\";\nimport StarterKit from \"@tiptap/starter-kit\";\nimport { onCleanup, onMount } from \"solid-js\";\n\nexport interface RichTextEditorProps {\n id?: string;\n /** TipTap's native JSON document shape — stored as-is, no transform layer. */\n content?: object;\n onChange: (doc: object) => void;\n}\n\n// No official Solid binding for TipTap exists, so this wraps @tiptap/core's\n// vanilla `Editor` class directly in Solid's onMount/onCleanup lifecycle —\n// per CLAUDE.md's preference for the framework-agnostic core API over an\n// unofficial community port (same reasoning already applied to Phosphor\n// icons). `content` is only read once at mount, matching how this form's\n// other fields are initialized from `initialValues` rather than reacting\n// to prop changes after the fact — there is no live re-sync if `content`\n// changes out from under an already-mounted editor.\nexport function RichTextEditor(props: RichTextEditorProps) {\n let container: HTMLDivElement | undefined;\n let editor: Editor | undefined;\n\n onMount(() => {\n if (!container) return;\n editor = new Editor({\n element: container,\n extensions: [StarterKit],\n content: props.content ?? \"\",\n onUpdate: ({ editor: current }) => {\n props.onChange(current.getJSON());\n },\n });\n });\n\n onCleanup(() => {\n editor?.destroy();\n });\n\n return (\n <div\n id={props.id}\n class=\"textarea h-auto min-h-32 w-full\"\n ref={(el) => {\n container = el;\n }}\n />\n );\n}\n"],"mappings":";;;;;;AAmBA,SAAgBS,eAAeC,OAA4B;CACzD,IAAIC;CACJ,IAAIE;CAEJV,cAAc;EACZ,IAAI,CAACQ,WAAW;EAChBE,SAAS,IAAIb,OAAO;GAClBc,SAASH;GACTI,YAAY,CAACd,UAAU;GACvBK,SAASI,MAAMJ,WAAW;GAC1BU,WAAW,EAAEH,QAAQI,cAAc;IACjCP,MAAMH,SAASU,QAAQC,QAAQ,CAAC;GAClC;EACF,CAAC;CACH,CAAC;CAEDhB,gBAAgB;EACdW,QAAQM,QAAQ;CAClB,CAAC;CAED,cAAA;EAAA,IAAAC,OAAAC,OAAA;EAAAC,KAIUC,OAAO;GACXZ,YAAYY;EACd,GAACH,IAAA;EAAAI,aAAAC,aAAAL,MAAA,MAJGV,MAAML,EAAE,CAAA;EAAA,OAAAe;CAAA,EAAA,CAAA;AAOlB"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { escape, ssr, ssrAttribute } from "solid-js/web";
|
|
2
|
+
import { onCleanup, onMount } from "solid-js";
|
|
3
|
+
import "@tiptap/core";
|
|
4
|
+
import "@tiptap/starter-kit";
|
|
5
|
+
//#region src/RichTextEditor.tsx
|
|
6
|
+
var _tmpl$ = ["<div", " class=\"textarea h-auto min-h-32 w-full\"></div>"];
|
|
7
|
+
function RichTextEditor(props) {
|
|
8
|
+
onMount(() => {});
|
|
9
|
+
onCleanup(() => {});
|
|
10
|
+
return ssr(_tmpl$, ssrAttribute("id", escape(props.id, true), false));
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
export { RichTextEditor };
|
|
14
|
+
|
|
15
|
+
//# sourceMappingURL=RichTextEditor-DcLqdFY7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RichTextEditor-DcLqdFY7.js","names":["Editor","StarterKit","onCleanup","onMount","RichTextEditorProps","id","content","onChange","doc","RichTextEditor","props","container","HTMLDivElement","editor","element","extensions","onUpdate","current","getJSON","destroy","_$ssr","_tmpl$","_$ssrAttribute","_$escape"],"sources":["../src/RichTextEditor.tsx"],"sourcesContent":["import { Editor } from \"@tiptap/core\";\nimport StarterKit from \"@tiptap/starter-kit\";\nimport { onCleanup, onMount } from \"solid-js\";\n\nexport interface RichTextEditorProps {\n id?: string;\n /** TipTap's native JSON document shape — stored as-is, no transform layer. */\n content?: object;\n onChange: (doc: object) => void;\n}\n\n// No official Solid binding for TipTap exists, so this wraps @tiptap/core's\n// vanilla `Editor` class directly in Solid's onMount/onCleanup lifecycle —\n// per CLAUDE.md's preference for the framework-agnostic core API over an\n// unofficial community port (same reasoning already applied to Phosphor\n// icons). `content` is only read once at mount, matching how this form's\n// other fields are initialized from `initialValues` rather than reacting\n// to prop changes after the fact — there is no live re-sync if `content`\n// changes out from under an already-mounted editor.\nexport function RichTextEditor(props: RichTextEditorProps) {\n let container: HTMLDivElement | undefined;\n let editor: Editor | undefined;\n\n onMount(() => {\n if (!container) return;\n editor = new Editor({\n element: container,\n extensions: [StarterKit],\n content: props.content ?? \"\",\n onUpdate: ({ editor: current }) => {\n props.onChange(current.getJSON());\n },\n });\n });\n\n onCleanup(() => {\n editor?.destroy();\n });\n\n return (\n <div\n id={props.id}\n class=\"textarea h-auto min-h-32 w-full\"\n ref={(el) => {\n container = el;\n }}\n />\n );\n}\n"],"mappings":";;;;;;AAmBA,SAAgBS,eAAeC,OAA4B;CAIzDP,cAAc,CAUd,CAAC;CAEDD,gBAAgB,CAEhB,CAAC;CAED,OAAAkB,IAAAC,QAAAC,aAAA,MAAAC,OAEQb,MAAML,IAAE,IAAA,GAAA,KAAA,CAAA;AAOlB"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { JSX } from "solid-js";
|
|
2
|
+
import { CollectionConfig } from "@thebes/cadmus/cms";
|
|
3
|
+
|
|
4
|
+
//#region src/capabilities.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Drives action gating in `CollectionEdit` and the `tanstack-start` list/
|
|
7
|
+
* edit page factories — hide/disable an action a context can't perform
|
|
8
|
+
* rather than let it fail server-side after a click. A field left
|
|
9
|
+
* `undefined` reads as "allowed", mirroring `@thebes/cadmus/cms`'s own
|
|
10
|
+
* "no access fn configured = allowed" default, so collections that don't
|
|
11
|
+
* wire this up at all keep today's unrestricted behavior.
|
|
12
|
+
*/
|
|
13
|
+
interface CollectionCapabilities {
|
|
14
|
+
canCreate?: boolean;
|
|
15
|
+
canUpdate?: boolean;
|
|
16
|
+
canDelete?: boolean;
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/CollectionEdit.d.ts
|
|
20
|
+
interface RelationshipOption {
|
|
21
|
+
id: number;
|
|
22
|
+
label: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Replaces the generic "Save" button with "Save draft"/"Publish" when the
|
|
26
|
+
* collection has `versions: { drafts: true }` — a separate privilege from
|
|
27
|
+
* a plain update, matching `access.publish` in `@thebes/cadmus/cms`.
|
|
28
|
+
* `onPublish` takes no values: publishing acts on whatever was last saved
|
|
29
|
+
* as a draft (the consuming route tracks which version that is), not on
|
|
30
|
+
* the live form state.
|
|
31
|
+
*/
|
|
32
|
+
interface DraftActions {
|
|
33
|
+
onSaveDraft: (values: Record<string, unknown>) => void | Promise<void>;
|
|
34
|
+
onPublish?: () => void | Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Opens a live preview of the last saved draft (issue #28) — like
|
|
37
|
+
* `onPublish`, acts on whatever was last saved as a draft, not the live
|
|
38
|
+
* form state. Omit to not render the Preview button at all.
|
|
39
|
+
*/
|
|
40
|
+
onPreview?: () => void | Promise<void>;
|
|
41
|
+
saving?: boolean;
|
|
42
|
+
publishing?: boolean;
|
|
43
|
+
previewing?: boolean;
|
|
44
|
+
/** Disables Publish — e.g. until a draft has been saved at least once. */
|
|
45
|
+
canPublish?: boolean;
|
|
46
|
+
/** Disables Preview — same gating as canPublish, a draft must exist first. */
|
|
47
|
+
canPreview?: boolean;
|
|
48
|
+
saveDraftLabel?: string;
|
|
49
|
+
publishLabel?: string;
|
|
50
|
+
previewLabel?: string;
|
|
51
|
+
}
|
|
52
|
+
interface CollectionEditProps {
|
|
53
|
+
config: CollectionConfig;
|
|
54
|
+
initialValues?: Record<string, unknown>;
|
|
55
|
+
onSubmit: (values: Record<string, unknown>) => void | Promise<void>;
|
|
56
|
+
submitLabel?: string;
|
|
57
|
+
error?: string;
|
|
58
|
+
/** Disables the Save button and shows a spinner in its place. */
|
|
59
|
+
saving?: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Resolves an `upload` field's selected file to a stored URL. Required
|
|
62
|
+
* if the collection has any `upload` fields — `CollectionEdit` never
|
|
63
|
+
* talks to storage directly (stays agnostic of R2/cadmus/storage), so
|
|
64
|
+
* the consuming route wires this to a server function that calls an
|
|
65
|
+
* `ImageService`'s `upload()`.
|
|
66
|
+
*/
|
|
67
|
+
onUploadFile?: (file: File) => Promise<{
|
|
68
|
+
url: string;
|
|
69
|
+
}>;
|
|
70
|
+
/**
|
|
71
|
+
* Options for `relationship` fields (hasMany:false only — see
|
|
72
|
+
* RelationshipFieldConfig's `hasMany` caveat), keyed by the field's
|
|
73
|
+
* `relationTo` collection slug. `CollectionEdit` can't query another
|
|
74
|
+
* collection itself, so the consuming route fetches the related rows
|
|
75
|
+
* and passes them in.
|
|
76
|
+
*/
|
|
77
|
+
relationshipOptions?: Partial<Record<string, RelationshipOption[]>>;
|
|
78
|
+
/**
|
|
79
|
+
* Fired whenever the dirty (unsaved-changes) state changes — wire this
|
|
80
|
+
* to a router-level navigation guard (e.g. `useBlocker` in the
|
|
81
|
+
* consuming route) since `CollectionEdit` has no router access itself.
|
|
82
|
+
*/
|
|
83
|
+
onDirtyChange?: (dirty: boolean) => void;
|
|
84
|
+
/** Only rendered when `config.versions?.drafts` is also true. */
|
|
85
|
+
draftActions?: DraftActions;
|
|
86
|
+
/**
|
|
87
|
+
* Hides the Save button when `canUpdate` is `false` — see issue #26's
|
|
88
|
+
* RBAC-aware admin UI. Undefined (the default — most collections don't
|
|
89
|
+
* wire this up) reads as "allowed", same as `@thebes/cadmus/cms`'s own
|
|
90
|
+
* "no access fn = allowed" default.
|
|
91
|
+
*/
|
|
92
|
+
capabilities?: CollectionCapabilities;
|
|
93
|
+
}
|
|
94
|
+
declare function CollectionEdit(props: CollectionEditProps): import("solid-js").JSX.Element;
|
|
95
|
+
//#endregion
|
|
96
|
+
//#region src/CollectionList.d.ts
|
|
97
|
+
interface CollectionListProps {
|
|
98
|
+
config: CollectionConfig;
|
|
99
|
+
rows: Record<string, unknown>[];
|
|
100
|
+
onRowClick?: (row: Record<string, unknown>) => void;
|
|
101
|
+
/**
|
|
102
|
+
* 1-based current page. Omit (along with `pageSize`) to render without
|
|
103
|
+
* the pagination bar entirely — list views with no `find()` paging
|
|
104
|
+
* wired up yet still render correctly.
|
|
105
|
+
*/
|
|
106
|
+
page?: number;
|
|
107
|
+
pageSize?: number;
|
|
108
|
+
/** Total row count across all pages — see `LocalApi.count()`. Enables
|
|
109
|
+
* disabling "Next" exactly at the last page; omit to fall back to a
|
|
110
|
+
* `rows.length < pageSize` heuristic. */
|
|
111
|
+
totalCount?: number;
|
|
112
|
+
onPageChange?: (page: number) => void;
|
|
113
|
+
/** Field key currently sorted on. Omit to hide the sort control. */
|
|
114
|
+
sortField?: string;
|
|
115
|
+
sortDirection?: "asc" | "desc";
|
|
116
|
+
onSortChange?: (field: string, direction: "asc" | "desc") => void;
|
|
117
|
+
/** Shows the "Select" bulk-select mode toggle. */
|
|
118
|
+
selectable?: boolean;
|
|
119
|
+
selectedIds?: ReadonlySet<number>;
|
|
120
|
+
onSelectionChange?: (selectedIds: Set<number>) => void;
|
|
121
|
+
}
|
|
122
|
+
declare function CollectionList(props: CollectionListProps): import("solid-js").JSX.Element;
|
|
123
|
+
//#endregion
|
|
124
|
+
//#region src/SearchPalette.d.ts
|
|
125
|
+
interface SearchPaletteResult {
|
|
126
|
+
collection: string;
|
|
127
|
+
id: number;
|
|
128
|
+
label: string;
|
|
129
|
+
}
|
|
130
|
+
interface SearchPaletteProps {
|
|
131
|
+
/** Runs a query against `LocalApi.search()` for every searchable collection — see `@thebes/cadmus/cms`'s `getCollectionsMeta`. */
|
|
132
|
+
onSearch: (query: string) => Promise<SearchPaletteResult[]>;
|
|
133
|
+
/** Navigates to the chosen result; the palette closes itself afterward. */
|
|
134
|
+
onSelect: (result: SearchPaletteResult) => void;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Self-contained Cmd+K (Ctrl+K on non-Mac) search palette — issue #29.
|
|
138
|
+
* Owns its own open/closed state and keyboard listener; the host app only
|
|
139
|
+
* supplies `onSearch` (wired to a server function that fans out across
|
|
140
|
+
* every collection with `search` configured) and `onSelect` (navigation).
|
|
141
|
+
* Mirrors PanelNav's focus-trap-on-open / restore-focus-on-close pattern
|
|
142
|
+
* rather than introducing a second one.
|
|
143
|
+
*/
|
|
144
|
+
declare function SearchPalette(props: SearchPaletteProps): JSX.Element;
|
|
145
|
+
//#endregion
|
|
146
|
+
export { type CollectionCapabilities, CollectionEdit, type CollectionEditProps, CollectionList, type CollectionListProps, SearchPalette, type SearchPaletteProps, type SearchPaletteResult };
|
|
147
|
+
//# sourceMappingURL=index.d.ts.map
|