@letterncms/ui 0.0.0-stage → 0.1.1
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.md +21 -0
- package/package.json +23 -5
- package/src/app/App.d.ts +3 -0
- package/src/app/Brand.d.ts +5 -0
- package/src/app/CommandPalette.d.ts +4 -0
- package/src/app/CustomizeSidebar.d.ts +8 -0
- package/src/app/ErrorBoundary.d.ts +16 -0
- package/src/app/Root.d.ts +1 -0
- package/src/app/Sidebar.d.ts +15 -0
- package/src/app/modules.d.ts +21 -0
- package/src/app/sidebarStore.d.ts +30 -0
- package/src/fields/CommandQueryField.d.ts +3 -0
- package/src/fields/FieldsEditor.d.ts +28 -0
- package/src/fields/LinkField.d.ts +16 -0
- package/src/fields/RichTextField.d.ts +6 -0
- package/src/fields/basic.d.ts +17 -0
- package/src/fields/complex.d.ts +6 -0
- package/src/fields/index.d.ts +6 -0
- package/src/lib/icon-data.d.ts +1 -0
- package/src/main.d.ts +1 -0
- package/src/screens/NotFound.d.ts +1 -0
- package/src/screens/auth/AuthScreen.d.ts +4 -0
- package/src/ui/Avatar.d.ts +16 -0
- package/src/ui/Badge.d.ts +14 -0
- package/src/ui/BlueprintEditor.d.ts +48 -0
- package/src/ui/Button.d.ts +19 -0
- package/src/ui/ComponentBoundary.d.ts +17 -0
- package/src/ui/DataCalendar.d.ts +23 -0
- package/src/ui/DataGrid.d.ts +22 -0
- package/src/ui/DataTable.d.ts +68 -0
- package/src/ui/DataView.d.ts +44 -0
- package/src/ui/Dialog.d.ts +32 -0
- package/src/ui/EmptyState.d.ts +8 -0
- package/src/ui/Field.d.ts +12 -0
- package/src/ui/Fields.d.ts +18 -0
- package/src/ui/Icon.d.ts +8 -0
- package/src/ui/Input.d.ts +15 -0
- package/src/ui/InspectorPanel.d.ts +11 -0
- package/src/ui/Kbd.d.ts +5 -0
- package/src/ui/List.d.ts +14 -0
- package/src/ui/Marquee.d.ts +5 -0
- package/src/ui/Menu.d.ts +37 -0
- package/src/ui/Page.d.ts +31 -0
- package/src/ui/PagePagination.d.ts +7 -0
- package/src/ui/PersonPicker.d.ts +12 -0
- package/src/ui/Popover.d.ts +13 -0
- package/src/ui/QueryError.d.ts +6 -0
- package/src/ui/Segmented.d.ts +36 -0
- package/src/ui/Select.d.ts +25 -0
- package/src/ui/SelectionBar.d.ts +7 -0
- package/src/ui/SidebarRow.d.ts +31 -0
- package/src/ui/Slideover.d.ts +21 -0
- package/src/ui/SortableTree.d.ts +30 -0
- package/src/ui/Spinner.d.ts +7 -0
- package/src/ui/Surface.d.ts +8 -0
- package/src/ui/SurfaceHost.d.ts +2 -0
- package/src/ui/Switch.d.ts +16 -0
- package/src/ui/Tooltip.d.ts +10 -0
- package/src/ui/ViewControls.d.ts +36 -0
- package/src/ui/Widget.d.ts +121 -0
- package/src/ui/WidgetSlot.d.ts +7 -0
- package/src/ui/calendar.d.ts +10 -0
- package/src/ui/cn.d.ts +2 -0
- package/src/ui/dateTime.d.ts +6 -0
- package/src/ui/entryActions.d.ts +13 -0
- package/src/ui/entryDisplay.d.ts +16 -0
- package/src/ui/fieldIdentity.d.ts +3 -0
- package/src/ui/index.d.ts +72 -0
- package/src/ui/overviewSource.d.ts +16 -0
- package/src/ui/recordDates.d.ts +13 -0
- package/src/ui/recordNavigation.d.ts +10 -0
- package/src/ui/shortcuts.d.ts +4 -0
- package/src/ui/slugify.d.ts +2 -0
- package/src/ui/theme.d.ts +4 -0
- package/src/ui/toast.d.ts +14 -0
- package/src/ui/viewPrefs.d.ts +17 -0
- package/README.md +0 -3
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Falko Joseph
|
|
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/package.json
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
"name": "@letterncms/ui",
|
|
3
|
+
"description": "Types of the admin's UI kit. The admin provides the components at runtime.",
|
|
4
|
+
"types": "./src/ui/index.d.ts",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": {
|
|
7
|
+
"types": "./src/ui/index.d.ts"
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
"peerDependencies": {
|
|
11
|
+
"react": "^19.0.0",
|
|
12
|
+
"@tanstack/react-query": "^5.0.0"
|
|
13
|
+
},
|
|
14
|
+
"version": "0.1.1",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/letterncms/cms.git"
|
|
20
|
+
},
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
}
|
|
24
|
+
}
|
package/src/app/App.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every item of the sidebar, section by section: pin or unpin, drag to
|
|
3
|
+
* reorder. Changes apply as they are made; the sidebar behind follows.
|
|
4
|
+
*/
|
|
5
|
+
export declare function CustomizeSidebar({ open, onOpenChange }: {
|
|
6
|
+
open: boolean;
|
|
7
|
+
onOpenChange: (open: boolean) => void;
|
|
8
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Component, type ReactNode } from 'react';
|
|
2
|
+
/** Keeps a failing screen (core or plugin) from taking down the whole admin. */
|
|
3
|
+
export declare class ErrorBoundary extends Component<{
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
}, {
|
|
6
|
+
error: Error | null;
|
|
7
|
+
}> {
|
|
8
|
+
state: {
|
|
9
|
+
error: Error | null;
|
|
10
|
+
};
|
|
11
|
+
static getDerivedStateFromError(error: Error): {
|
|
12
|
+
error: Error;
|
|
13
|
+
};
|
|
14
|
+
componentDidCatch(error: Error): void;
|
|
15
|
+
render(): string | number | bigint | boolean | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | null | undefined;
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function Root(): import("react").JSX.Element;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
interface SidebarProps {
|
|
2
|
+
collapsed: boolean;
|
|
3
|
+
onToggle: () => void;
|
|
4
|
+
onSearch: () => void;
|
|
5
|
+
/** Called when a link is followed (the overlay sidebar on narrow screens closes). */
|
|
6
|
+
onNavigate?: () => void;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The admin's sidebar, in one of two states that follow the screen on view:
|
|
10
|
+
* the main sidebar (what each person pinned, More for the rest, then chats)
|
|
11
|
+
* and, on a settings page, the settings sidebar with a way back. Same frame,
|
|
12
|
+
* same rows, same footer — only the list changes.
|
|
13
|
+
*/
|
|
14
|
+
export declare function Sidebar({ collapsed, onToggle, onSearch, onNavigate }: SidebarProps): import("react").JSX.Element;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type Manifest } from '@letterncms/sdk';
|
|
2
|
+
type Module = Manifest['modules'][number];
|
|
3
|
+
/**
|
|
4
|
+
* Bring the admin in line with the manifest: load the modules of packages that
|
|
5
|
+
* were turned on and take back what turned-off ones registered (routes, fields,
|
|
6
|
+
* panels, widgets, commands, icons) along with their stylesheets. Runs at boot
|
|
7
|
+
* and whenever the manifest is fetched again, so nothing needs a reload.
|
|
8
|
+
*
|
|
9
|
+
* Modules are fetched in parallel but run one at a time, so everything a module
|
|
10
|
+
* registers is attributed to it. A failing one is reported, never fatal.
|
|
11
|
+
*/
|
|
12
|
+
export declare function syncModules(manifest: Manifest): Promise<{
|
|
13
|
+
id: string;
|
|
14
|
+
url: string;
|
|
15
|
+
package: string | null;
|
|
16
|
+
}[]>;
|
|
17
|
+
/** Follow manifest changes after boot: modules come and go, cached data is refreshed. */
|
|
18
|
+
export declare function followManifest(manifest: Manifest): void;
|
|
19
|
+
/** Report modules that failed at boot. */
|
|
20
|
+
export declare function reportFailed(failed: Module[]): void;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Manifest, type NavItem, type Sidebar } from '@letterncms/sdk';
|
|
2
|
+
export declare function arrange(next: Sidebar): void;
|
|
3
|
+
export declare function isPinned(layout: Sidebar, id: string): boolean;
|
|
4
|
+
export declare function setPinned(id: string, pinned: boolean): void;
|
|
5
|
+
/** Unpin, with a way back. */
|
|
6
|
+
export declare function unpin(id: string): void;
|
|
7
|
+
/** Put a section's items in a new order. */
|
|
8
|
+
export declare function reorder(section: string, items: string[]): void;
|
|
9
|
+
/**
|
|
10
|
+
* Move a pinned item to another place among the pinned items of its section,
|
|
11
|
+
* leaving the items under More where they are.
|
|
12
|
+
*/
|
|
13
|
+
export declare function movePinned(section: string, id: string, to: number): void;
|
|
14
|
+
export declare function resetToDefault(): Promise<void>;
|
|
15
|
+
export declare function saveForEveryone(): Promise<void>;
|
|
16
|
+
/** The item a path belongs to: the one with the longest matching path (`/` only for itself). */
|
|
17
|
+
export declare function itemAt(nav: NavItem[], path: string): NavItem | undefined;
|
|
18
|
+
export declare function settingsIds(manifest: Manifest): Set<string>;
|
|
19
|
+
export declare function inSettings(manifest: Manifest, path: string): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Opens settings, and in settings goes back. Not ⌘, — browsers keep that one for their
|
|
22
|
+
* own settings, so a page never sees it.
|
|
23
|
+
*/
|
|
24
|
+
export declare const SETTINGS_SHORTCUT = "mod+shift+,";
|
|
25
|
+
export declare function remember(manifest: Manifest, path: string, search: string): void;
|
|
26
|
+
export declare function lastApp(): string;
|
|
27
|
+
export declare function openSettings(): void;
|
|
28
|
+
export declare function leaveSettings(): void;
|
|
29
|
+
/** The settings shortcut: opens settings, and in settings goes back. */
|
|
30
|
+
export declare function toggleSettings(): void;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { FieldProps } from '@letterncms/sdk';
|
|
2
|
+
/** The command palette's query: cmdk's own input, so its list filters and keyboard navigation keep working. */
|
|
3
|
+
export declare function CommandQueryField({ field, value, onChange }: FieldProps<string | null>): import("react").JSX.Element;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type FieldProps, type FieldTypeDef } from '@letterncms/sdk';
|
|
2
|
+
export type RawField = Record<string, any> & {
|
|
3
|
+
handle?: string;
|
|
4
|
+
type?: string;
|
|
5
|
+
label?: string;
|
|
6
|
+
import?: string;
|
|
7
|
+
};
|
|
8
|
+
export declare function FieldsEditor({ fields, onChange, body, depth, emptyText, addLabel, builtIn }: {
|
|
9
|
+
fields: RawField[];
|
|
10
|
+
onChange: (fields: RawField[]) => void;
|
|
11
|
+
body?: string;
|
|
12
|
+
depth?: number;
|
|
13
|
+
emptyText?: string;
|
|
14
|
+
addLabel?: string;
|
|
15
|
+
builtIn?: string | null;
|
|
16
|
+
}): import("react").JSX.Element;
|
|
17
|
+
/**
|
|
18
|
+
* The `fields` config type (group and repeater sub-fields) as a nested editor. A field's
|
|
19
|
+
* `placeholder` replaces the empty text and `add` the add button (a component's properties).
|
|
20
|
+
*/
|
|
21
|
+
export declare function FieldsConfigField({ field, value, onChange, context }: FieldProps<RawField[]>): import("react").JSX.Element;
|
|
22
|
+
export declare function AddField({ types, onAdd, label, align, nested }: {
|
|
23
|
+
types: FieldTypeDef[];
|
|
24
|
+
onAdd: (type: FieldTypeDef) => void;
|
|
25
|
+
label?: string;
|
|
26
|
+
align?: 'start' | 'end';
|
|
27
|
+
nested?: boolean;
|
|
28
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type FieldProps } from '@letterncms/sdk';
|
|
2
|
+
/**
|
|
3
|
+
* `link` — where a link goes, picked rather than typed: a page (searched across
|
|
4
|
+
* collections), a section of this page, a web address, an email, a phone number
|
|
5
|
+
* or a file from the media library. The trigger shows the destination as a chip
|
|
6
|
+
* (page title, domain, address) instead of a raw URL.
|
|
7
|
+
*
|
|
8
|
+
* Use it as `{ type: 'url', component: 'link' }`. Options:
|
|
9
|
+
* reference store pages as `entry:<id>` so the link follows the page when it moves
|
|
10
|
+
* (the renderer must resolve it — blocks do); otherwise the page's path
|
|
11
|
+
* anchors sections of the current page: [{ id, label }]
|
|
12
|
+
* newTab / onNewTab show "Open in New Tab" in the picker and report changes
|
|
13
|
+
* autofocus / onClose open the picker at once (a toolbar's link button) and hear when it closes
|
|
14
|
+
* collections limit page search to these collections
|
|
15
|
+
*/
|
|
16
|
+
export declare function LinkField({ field, value, onChange, disabled }: FieldProps<string | null>): import("react").JSX.Element;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type FieldProps } from '@letterncms/sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Lightweight rich text (contenteditable). Output is sanitized on the server.
|
|
4
|
+
* The blocks plugin may register a richer editor under the same key.
|
|
5
|
+
*/
|
|
6
|
+
export declare function RichTextField({ field, value, onChange, error, disabled }: FieldProps<string | null>): import("react").JSX.Element;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type FieldProps } from '@letterncms/sdk';
|
|
2
|
+
export declare function TextField({ field, value, onChange, error, disabled }: FieldProps<string | null>): import("react").JSX.Element;
|
|
3
|
+
export declare function TextareaField({ field, value, onChange, error, disabled }: FieldProps<string | null>): import("react").JSX.Element;
|
|
4
|
+
export declare function CodeField({ field, value, onChange, error, disabled }: FieldProps<string | null>): import("react").JSX.Element;
|
|
5
|
+
export declare function MarkdownField({ field, value, onChange, error, disabled }: FieldProps<string | null>): import("react").JSX.Element;
|
|
6
|
+
export declare function NumberField({ field, value, onChange, error, disabled }: FieldProps<number | null>): import("react").JSX.Element;
|
|
7
|
+
/** A yes/no value: a switch with its label, or `display: checkbox` for lists of choices and selection. */
|
|
8
|
+
export declare function ToggleField({ field, value, onChange, disabled }: FieldProps<boolean>): import("react").JSX.Element;
|
|
9
|
+
export declare function SelectField({ field, value, onChange, error, disabled }: FieldProps<any>): import("react").JSX.Element;
|
|
10
|
+
/** An icon name, picked from `options` or a common set. */
|
|
11
|
+
export declare function IconField({ field, value, onChange, disabled }: FieldProps<string | null>): import("react").JSX.Element;
|
|
12
|
+
export declare function DateField({ field, value, onChange, error, disabled }: FieldProps<string | null>): import("react").JSX.Element;
|
|
13
|
+
export declare function SlugField({ field, value, onChange, error, disabled, context }: FieldProps<string | null>): import("react").JSX.Element;
|
|
14
|
+
export declare function UrlField({ field, value, onChange, error, disabled }: FieldProps<string | null>): import("react").JSX.Element;
|
|
15
|
+
export declare function EmailField({ field, value, onChange, error, disabled }: FieldProps<string | null>): import("react").JSX.Element;
|
|
16
|
+
export declare function ColorField({ field, value, onChange, error, disabled }: FieldProps<string | null>): import("react").JSX.Element;
|
|
17
|
+
export declare function JsonField({ field, value, onChange, error, disabled }: FieldProps<unknown>): import("react").JSX.Element;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type FieldProps } from '@letterncms/sdk';
|
|
2
|
+
export declare function TagsField({ field, value, onChange, disabled }: FieldProps<string[]>): import("react").JSX.Element;
|
|
3
|
+
export declare function EntriesField({ field, value, onChange, disabled, context }: FieldProps<string[]>): import("react").JSX.Element;
|
|
4
|
+
export declare function UsersField({ field, value, onChange, disabled }: FieldProps<string[]>): import("react").JSX.Element;
|
|
5
|
+
export declare function GroupField({ field, value, onChange, disabled, context }: FieldProps<Record<string, any>>): import("react").JSX.Element;
|
|
6
|
+
export declare function RepeaterField({ field, value, onChange, disabled, context }: FieldProps<Record<string, any>[]>): import("react").JSX.Element;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The field primitives every form is drawn with — one per core field type, plus the
|
|
3
|
+
* blueprint editor and the palette's query box. Fields that belong to one screen
|
|
4
|
+
* (roles, the sidebar arrangement, the entry title) come with their modules.
|
|
5
|
+
*/
|
|
6
|
+
export declare function registerCoreFields(): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const ICONS: Record<string, [body: string, width: number, height: number]>;
|
package/src/main.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import './styles/app.css';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function NotFound(): import("react").JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare function Avatar({ name, initials, src, size, className }: {
|
|
2
|
+
name: string;
|
|
3
|
+
initials?: string;
|
|
4
|
+
src?: string | null;
|
|
5
|
+
size?: number;
|
|
6
|
+
className?: string;
|
|
7
|
+
}): import("react").JSX.Element;
|
|
8
|
+
export declare function AvatarStack({ people, max, size }: {
|
|
9
|
+
people: {
|
|
10
|
+
name: string;
|
|
11
|
+
initials?: string;
|
|
12
|
+
avatar?: string | null;
|
|
13
|
+
}[];
|
|
14
|
+
max?: number;
|
|
15
|
+
size?: number;
|
|
16
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export type Tone = 'neutral' | 'success' | 'warning' | 'danger' | 'info' | 'signal';
|
|
3
|
+
export declare function Badge({ tone, children, className }: {
|
|
4
|
+
tone?: Tone;
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
className?: string;
|
|
7
|
+
}): import("react").JSX.Element;
|
|
8
|
+
/** A status as a small dot plus label — no colored pills everywhere. */
|
|
9
|
+
export declare function StatusDot({ status, label, className }: {
|
|
10
|
+
status: string;
|
|
11
|
+
label?: ReactNode;
|
|
12
|
+
className?: string;
|
|
13
|
+
}): import("react").JSX.Element;
|
|
14
|
+
export declare function statusLabel(status: string): string;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type RawField } from '../fields/FieldsEditor';
|
|
2
|
+
export interface BlueprintDefinition {
|
|
3
|
+
title: string;
|
|
4
|
+
singular?: string;
|
|
5
|
+
icon?: string;
|
|
6
|
+
route?: string | null;
|
|
7
|
+
structure?: string;
|
|
8
|
+
driver?: string;
|
|
9
|
+
template?: string;
|
|
10
|
+
sort?: string;
|
|
11
|
+
body?: string;
|
|
12
|
+
home?: string;
|
|
13
|
+
editor?: 'document' | 'canvas';
|
|
14
|
+
fields: RawField[];
|
|
15
|
+
[key: string]: any;
|
|
16
|
+
}
|
|
17
|
+
/** Something with a blueprint, and how the editor reads, saves and leaves it. */
|
|
18
|
+
type BlueprintRemoval = [ability: string, input: Record<string, unknown>, warning: string, confirmLabel?: string];
|
|
19
|
+
export interface BlueprintKind {
|
|
20
|
+
get: [ability: string, input: Record<string, unknown>];
|
|
21
|
+
save: (def: BlueprintDefinition) => [ability: string, input: Record<string, unknown>];
|
|
22
|
+
/** Resolve fresh deletion metadata before asking for confirmation. */
|
|
23
|
+
remove?: BlueprintRemoval | (() => Promise<BlueprintRemoval>);
|
|
24
|
+
removeLabel?: string;
|
|
25
|
+
canRemove?: (source: Record<string, unknown>) => boolean;
|
|
26
|
+
back: {
|
|
27
|
+
label: string;
|
|
28
|
+
to: string;
|
|
29
|
+
icon: string;
|
|
30
|
+
};
|
|
31
|
+
entries?: string;
|
|
32
|
+
/** What every item has without a field; null when nothing. */
|
|
33
|
+
builtIn?: string | null;
|
|
34
|
+
/** Give complex blueprints separate fields and grouped settings views. */
|
|
35
|
+
settingsSections?: {
|
|
36
|
+
title: string;
|
|
37
|
+
handles: string[];
|
|
38
|
+
bare?: boolean;
|
|
39
|
+
}[];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Edits whatever has a blueprint — a collection, a global set, user profiles —
|
|
43
|
+
* through the abilities its kind names. Modules describe their kind and render this.
|
|
44
|
+
*/
|
|
45
|
+
export declare function BlueprintEditor({ kind }: {
|
|
46
|
+
kind: BlueprintKind;
|
|
47
|
+
}): import("react").JSX.Element;
|
|
48
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type ButtonHTMLAttributes, type ReactNode } from 'react';
|
|
2
|
+
export type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger' | 'publish';
|
|
3
|
+
export type ButtonSize = 'xs' | 'sm' | 'md' | 'lg';
|
|
4
|
+
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
5
|
+
variant?: ButtonVariant;
|
|
6
|
+
size?: ButtonSize;
|
|
7
|
+
icon?: string;
|
|
8
|
+
iconRight?: string;
|
|
9
|
+
loading?: boolean;
|
|
10
|
+
children?: ReactNode;
|
|
11
|
+
}
|
|
12
|
+
export declare const Button: import("react").ForwardRefExoticComponent<ButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
13
|
+
export interface IconButtonProps extends Omit<ButtonProps, 'children' | 'iconRight'> {
|
|
14
|
+
icon: string;
|
|
15
|
+
label: string;
|
|
16
|
+
active?: boolean;
|
|
17
|
+
}
|
|
18
|
+
/** Square icon-only button. `label` is required for accessibility (and shown as tooltip). */
|
|
19
|
+
export declare const IconButton: import("react").ForwardRefExoticComponent<IconButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Component, type ReactNode } from 'react';
|
|
2
|
+
/** A plugin failure stays local, wherever its component is embedded. */
|
|
3
|
+
export declare class ComponentBoundary extends Component<{
|
|
4
|
+
label: string;
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
}, {
|
|
7
|
+
error: Error | null;
|
|
8
|
+
}> {
|
|
9
|
+
state: {
|
|
10
|
+
error: Error | null;
|
|
11
|
+
};
|
|
12
|
+
static getDerivedStateFromError(error: Error): {
|
|
13
|
+
error: Error;
|
|
14
|
+
};
|
|
15
|
+
componentDidCatch(error: Error): void;
|
|
16
|
+
render(): string | number | bigint | boolean | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | null | undefined;
|
|
17
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import type { DataSelection } from './DataTable';
|
|
3
|
+
interface DataCalendarProps<T> {
|
|
4
|
+
label: string;
|
|
5
|
+
items: T[];
|
|
6
|
+
month?: string;
|
|
7
|
+
onMonth: (month: string | null) => void;
|
|
8
|
+
date: (item: T) => string | null | undefined;
|
|
9
|
+
title: (item: T) => ReactNode;
|
|
10
|
+
rowKey: (item: T) => string;
|
|
11
|
+
rowHref?: (item: T) => string;
|
|
12
|
+
onRowClick?: (item: T) => void;
|
|
13
|
+
actions?: (item: T) => ReactNode;
|
|
14
|
+
selection?: DataSelection<T>;
|
|
15
|
+
cursor?: string | null;
|
|
16
|
+
loading?: boolean;
|
|
17
|
+
stale?: boolean;
|
|
18
|
+
error?: boolean;
|
|
19
|
+
onRetry?: () => void;
|
|
20
|
+
}
|
|
21
|
+
/** The one calendar renderer for content, media and administrative records. */
|
|
22
|
+
export declare function DataCalendar<T>({ label, items, month: monthValue, onMonth, date, title, rowKey, rowHref, onRowClick, actions, selection, cursor, loading, stale, error, onRetry }: DataCalendarProps<T>): import("react").JSX.Element;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
/** The same responsive cards for content, assets and other overview records. */
|
|
3
|
+
export declare function DataGrid({ children, loading, stale, media }: {
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
loading?: boolean;
|
|
6
|
+
stale?: boolean;
|
|
7
|
+
media?: boolean;
|
|
8
|
+
}): import("react").JSX.Element;
|
|
9
|
+
export declare function DataCard({ title, href, onClick, icon, image, children, footer, selected, active, onSelect, actions, recordId }: {
|
|
10
|
+
title: ReactNode;
|
|
11
|
+
href?: string;
|
|
12
|
+
onClick?: () => void;
|
|
13
|
+
icon?: string;
|
|
14
|
+
image?: ReactNode;
|
|
15
|
+
children?: ReactNode;
|
|
16
|
+
footer?: ReactNode;
|
|
17
|
+
selected?: boolean;
|
|
18
|
+
active?: boolean;
|
|
19
|
+
onSelect?: (on: boolean) => void;
|
|
20
|
+
actions?: ReactNode;
|
|
21
|
+
recordId?: string;
|
|
22
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
/** Shared table geometry, also used by collection entries and their tree rows. */
|
|
3
|
+
export declare function TableFrame({ template, label, busy, children }: {
|
|
4
|
+
template: string;
|
|
5
|
+
label?: string;
|
|
6
|
+
busy?: boolean;
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
}): import("react").JSX.Element;
|
|
9
|
+
export declare function TableRow({ children, header, selected, className, recordId }: {
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
header?: boolean;
|
|
12
|
+
selected?: boolean;
|
|
13
|
+
className?: string;
|
|
14
|
+
recordId?: string;
|
|
15
|
+
}): import("react").JSX.Element;
|
|
16
|
+
export declare function TableHeader({ label, align, direction, onSort, hiddenLabel }: {
|
|
17
|
+
label: string;
|
|
18
|
+
align?: 'end';
|
|
19
|
+
direction?: 'ascending' | 'descending';
|
|
20
|
+
onSort?: () => void;
|
|
21
|
+
hiddenLabel?: boolean;
|
|
22
|
+
}): import("react").JSX.Element;
|
|
23
|
+
export declare function TableSkeleton({ columns, rows }: {
|
|
24
|
+
columns: number;
|
|
25
|
+
rows?: number;
|
|
26
|
+
}): import("react").JSX.Element;
|
|
27
|
+
export declare function TableToolbar({ children }: {
|
|
28
|
+
children: ReactNode;
|
|
29
|
+
}): import("react").JSX.Element;
|
|
30
|
+
export interface DataColumn<T> {
|
|
31
|
+
id: string;
|
|
32
|
+
label: string;
|
|
33
|
+
width?: string;
|
|
34
|
+
/** Available in Display, but initially hidden in tables and cards. */
|
|
35
|
+
hiddenByDefault?: boolean;
|
|
36
|
+
align?: 'end';
|
|
37
|
+
render: (item: T) => ReactNode;
|
|
38
|
+
/** Client sorting; omit on server-paginated data. */
|
|
39
|
+
value?: (item: T) => string | number | null | undefined;
|
|
40
|
+
/** Server sort field, handled by onSort. */
|
|
41
|
+
sort?: string;
|
|
42
|
+
descFirst?: boolean;
|
|
43
|
+
}
|
|
44
|
+
export interface DataSelection<T = unknown> {
|
|
45
|
+
ids: Set<string>;
|
|
46
|
+
onSelect: (ids: string[], on: boolean, records?: T[]) => void;
|
|
47
|
+
}
|
|
48
|
+
interface DataTableProps<T> {
|
|
49
|
+
label: string;
|
|
50
|
+
items: T[];
|
|
51
|
+
columns: DataColumn<T>[];
|
|
52
|
+
rowKey: (item: T) => string;
|
|
53
|
+
rowHref?: (item: T) => string;
|
|
54
|
+
onRowClick?: (item: T) => void;
|
|
55
|
+
selected?: (item: T) => boolean | undefined;
|
|
56
|
+
selection?: DataSelection<T>;
|
|
57
|
+
actions?: (item: T) => ReactNode;
|
|
58
|
+
loading?: boolean;
|
|
59
|
+
stale?: boolean;
|
|
60
|
+
state?: ReactNode;
|
|
61
|
+
sort?: string | null;
|
|
62
|
+
sortable?: Set<string>;
|
|
63
|
+
onSort?: (column: DataColumn<T>) => void;
|
|
64
|
+
cursor?: string | null;
|
|
65
|
+
}
|
|
66
|
+
/** A controlled table: collection entries and DataView use the exact same rendering. */
|
|
67
|
+
export declare function DataTable<T>({ label, items, columns, rowKey, rowHref, onRowClick, selected, selection, actions, loading, stale, state, sort, sortable, onSort, cursor }: DataTableProps<T>): import("react").JSX.Element;
|
|
68
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type RecordTimestamps } from '@letterncms/sdk';
|
|
2
|
+
import { type ComponentProps, type ReactNode } from 'react';
|
|
3
|
+
import { PagePagination } from './PagePagination';
|
|
4
|
+
import { type OverviewSource } from './overviewSource';
|
|
5
|
+
import { type DataColumn, type DataSelection } from './DataTable';
|
|
6
|
+
interface BaseDataViewProps<T> {
|
|
7
|
+
id: string;
|
|
8
|
+
label: string;
|
|
9
|
+
items: T[];
|
|
10
|
+
/** Required for paginated lists: Calendar loads every matching page through the same cache. */
|
|
11
|
+
source?: OverviewSource;
|
|
12
|
+
pagination?: ComponentProps<typeof PagePagination>;
|
|
13
|
+
columns: DataColumn<T>[];
|
|
14
|
+
/** Only advertise server sorting when the endpoint supports it. */
|
|
15
|
+
dateSort?: Partial<Record<'published' | 'updated', string>>;
|
|
16
|
+
rowKey: (item: T) => string;
|
|
17
|
+
rowHref?: (item: T) => string;
|
|
18
|
+
onRowClick?: (item: T) => void;
|
|
19
|
+
selected?: (item: T) => boolean;
|
|
20
|
+
selection?: DataSelection<T>;
|
|
21
|
+
actions?: (item: T) => ReactNode;
|
|
22
|
+
searchText?: (item: T) => string;
|
|
23
|
+
searchPlaceholder?: string;
|
|
24
|
+
toolbar?: ReactNode;
|
|
25
|
+
defaultView?: 'table' | 'grid' | 'calendar';
|
|
26
|
+
image?: (item: T) => ReactNode;
|
|
27
|
+
icon?: string;
|
|
28
|
+
sort?: string | null;
|
|
29
|
+
onSort?: (key: string | null) => void;
|
|
30
|
+
loading?: boolean;
|
|
31
|
+
stale?: boolean;
|
|
32
|
+
error?: boolean;
|
|
33
|
+
onRetry?: () => void;
|
|
34
|
+
empty: ReactNode;
|
|
35
|
+
}
|
|
36
|
+
/** Ordinary records must provide the standard metadata; wrappers supply a typed accessor. */
|
|
37
|
+
type DataViewProps<T> = BaseDataViewProps<T> & ([T] extends [RecordTimestamps] ? {
|
|
38
|
+
dates?: (item: T) => RecordTimestamps;
|
|
39
|
+
} : {
|
|
40
|
+
dates: (item: T) => RecordTimestamps;
|
|
41
|
+
});
|
|
42
|
+
/** Search, display preferences and selection use the same components as Content collections. */
|
|
43
|
+
export declare function DataView<T>({ id, label, items, source, pagination, columns: ownColumns, dates, dateSort, rowKey, rowHref, onRowClick, selected, selection, actions, searchText, searchPlaceholder, toolbar, defaultView, image, icon, sort: serverSort, onSort, loading, stale, error, onRetry, empty }: DataViewProps<T>): import("react").JSX.Element;
|
|
44
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import { type FieldDef } from '@letterncms/sdk';
|
|
3
|
+
export interface DialogProps {
|
|
4
|
+
open: boolean;
|
|
5
|
+
onOpenChange: (open: boolean) => void;
|
|
6
|
+
title?: ReactNode;
|
|
7
|
+
description?: ReactNode;
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
footer?: ReactNode;
|
|
10
|
+
size?: 'sm' | 'md' | 'lg' | 'xl';
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function Dialog({ open, onOpenChange, title, description, children, footer, size, className }: DialogProps): import("react").JSX.Element;
|
|
14
|
+
export interface ConfirmOptions {
|
|
15
|
+
title: string;
|
|
16
|
+
description?: ReactNode;
|
|
17
|
+
confirm?: string;
|
|
18
|
+
cancel?: string;
|
|
19
|
+
danger?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/** Imperative confirmation dialog: `if (await confirm({...})) …` */
|
|
22
|
+
export declare function confirm(options: ConfirmOptions): Promise<boolean>;
|
|
23
|
+
export interface PromptOptions {
|
|
24
|
+
title: string;
|
|
25
|
+
description?: ReactNode;
|
|
26
|
+
/** What to ask, as fields — drawn by Fields like every other form. */
|
|
27
|
+
fields: FieldDef[];
|
|
28
|
+
values?: Record<string, any>;
|
|
29
|
+
confirm?: string;
|
|
30
|
+
}
|
|
31
|
+
/** Imperative form dialog: `const values = await prompt({ title, fields })` — null when canceled. */
|
|
32
|
+
export declare function prompt(options: PromptOptions): Promise<Record<string, any> | null>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export declare function EmptyState({ icon, title, description, action, className }: {
|
|
3
|
+
icon?: string;
|
|
4
|
+
title: string;
|
|
5
|
+
description?: ReactNode;
|
|
6
|
+
action?: ReactNode;
|
|
7
|
+
className?: string;
|
|
8
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
/** Label + control + help/error. Every form row in the admin uses this. */
|
|
3
|
+
export declare function Field({ label, htmlFor, instructions, error, required, children, className, aside }: {
|
|
4
|
+
label?: ReactNode;
|
|
5
|
+
htmlFor?: string;
|
|
6
|
+
instructions?: ReactNode;
|
|
7
|
+
error?: string;
|
|
8
|
+
required?: boolean;
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
className?: string;
|
|
11
|
+
aside?: ReactNode;
|
|
12
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type FieldContext, type FieldDef } from '@letterncms/sdk';
|
|
2
|
+
export interface FieldsProps {
|
|
3
|
+
fields: FieldDef[];
|
|
4
|
+
values: Record<string, any>;
|
|
5
|
+
onChange: (handle: string, value: any) => void;
|
|
6
|
+
errors?: Record<string, string>;
|
|
7
|
+
context?: FieldContext;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
className?: string;
|
|
10
|
+
/** Hide labels for single inline fields. */
|
|
11
|
+
bare?: boolean;
|
|
12
|
+
/** `stacked` (default): labels above, a 6-column grid. `inline`: compact rows with the label left — for inspectors and toolbars. */
|
|
13
|
+
layout?: 'stacked' | 'inline';
|
|
14
|
+
}
|
|
15
|
+
/** Conditional fields: `if: { otherField: value | [values] }`. */
|
|
16
|
+
export declare function visible(field: FieldDef, values: Record<string, any>): boolean;
|
|
17
|
+
/** Renders a blueprint: each field with the component registered for its type. */
|
|
18
|
+
export declare function Fields({ fields, values, onChange, errors, context, disabled, className, bare, layout }: FieldsProps): import("react").JSX.Element | null;
|