@marktiderman/genesis-ui 2.6.0 → 2.8.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/EXTENDING.md +40 -1
- package/SKILL.md +145 -9
- package/dist/{AppShell-CX0M-dfc.d.ts → AppShell-LXQykEqe.d.ts} +47 -5
- package/dist/{chunk-M62CHO3N.js → chunk-4C4ESW6O.js} +9 -4
- package/dist/chunk-4C4ESW6O.js.map +1 -0
- package/dist/{chunk-IXGAEECT.js → chunk-DWCAC2E7.js} +6 -3
- package/dist/chunk-DWCAC2E7.js.map +1 -0
- package/dist/chunk-FUVWKTPL.js +19 -0
- package/dist/chunk-FUVWKTPL.js.map +1 -0
- package/dist/{chunk-PLIYF6KI.js → chunk-MPI33I4K.js} +2 -2
- package/dist/{chunk-PLIYF6KI.js.map → chunk-MPI33I4K.js.map} +1 -1
- package/dist/{chunk-JA3ZKULS.js → chunk-OITWCIG2.js} +3 -3
- package/dist/chunk-OITWCIG2.js.map +1 -0
- package/dist/chunk-PKFDGGZV.js +65 -0
- package/dist/chunk-PKFDGGZV.js.map +1 -0
- package/dist/chunk-S7NXD37O.js +321 -0
- package/dist/chunk-S7NXD37O.js.map +1 -0
- package/dist/{chunk-DWM7ELFI.js → chunk-UYI3GLFJ.js} +163 -20
- package/dist/chunk-UYI3GLFJ.js.map +1 -0
- package/dist/{chunk-CDYZRZ6U.js → chunk-WGMEVX3Y.js} +2 -2
- package/dist/chunk-WGMEVX3Y.js.map +1 -0
- package/dist/chunk-ZDHWNQTR.js +552 -0
- package/dist/chunk-ZDHWNQTR.js.map +1 -0
- package/dist/components/data/index.d.ts +239 -15
- package/dist/components/data/index.js +524 -109
- package/dist/components/data/index.js.map +1 -1
- package/dist/components/layout/form-page.d.ts +1 -1
- package/dist/components/layout/form-page.js +1 -1
- package/dist/components/layout/index.d.ts +2 -2
- package/dist/components/layout/index.js +9 -9
- package/dist/components/patterns/index.d.ts +1 -0
- package/dist/components/patterns/index.js +6 -4
- package/dist/components/patterns/sortable-list.d.ts +78 -0
- package/dist/components/patterns/sortable-list.js +5 -0
- package/dist/components/patterns/sortable-list.js.map +1 -0
- package/dist/components/rich-text/rich-text-editor.d.ts +194 -0
- package/dist/components/rich-text/rich-text-editor.js +833 -0
- package/dist/components/rich-text/rich-text-editor.js.map +1 -0
- package/dist/components/rich-text/rich-text.d.ts +51 -0
- package/dist/components/rich-text/rich-text.js +4 -0
- package/dist/components/rich-text/rich-text.js.map +1 -0
- package/dist/components/ui/alert-dialog.d.ts +12 -1
- package/dist/components/ui/alert-dialog.js +1 -1
- package/dist/hooks/index.d.ts +3 -3
- package/dist/hooks/index.js +4 -4
- package/dist/hooks/use-data-filters.d.ts +5 -3
- package/dist/hooks/use-data-filters.js +2 -2
- package/dist/hooks/use-resource-page.d.ts +2 -1
- package/dist/hooks/use-resource-page.js +3 -2
- package/dist/hooks/use-view-preference.d.ts +17 -2
- package/dist/hooks/use-view-preference.js +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +30 -29
- package/dist/{navigation-DBwcZ6vb.d.ts → navigation-Bha0R3Fu.d.ts} +6 -3
- package/dist/rich-text-doc-C54fME2C.d.ts +180 -0
- package/dist/router/react-router.d.ts +47 -0
- package/dist/router/react-router.js +53 -0
- package/dist/router/react-router.js.map +1 -0
- package/dist/router/tanstack-router.d.ts +47 -0
- package/dist/router/tanstack-router.js +105 -0
- package/dist/router/tanstack-router.js.map +1 -0
- package/dist/{use-resource-page-Dd2VUv30.d.ts → use-resource-page-D4byuwAs.d.ts} +20 -3
- package/package.json +62 -7
- package/dist/chunk-CDYZRZ6U.js.map +0 -1
- package/dist/chunk-DWM7ELFI.js.map +0 -1
- package/dist/chunk-FTTNGGLA.js +0 -20
- package/dist/chunk-FTTNGGLA.js.map +0 -1
- package/dist/chunk-IXGAEECT.js.map +0 -1
- package/dist/chunk-JA3ZKULS.js.map +0 -1
- package/dist/chunk-M62CHO3N.js.map +0 -1
|
@@ -41,7 +41,7 @@ interface FormPageProps extends Omit<React.FormHTMLAttributes<HTMLFormElement>,
|
|
|
41
41
|
* ```tsx
|
|
42
42
|
* <FormPage
|
|
43
43
|
* title="New engagement"
|
|
44
|
-
* description="Both
|
|
44
|
+
* description="Both parties will be notified."
|
|
45
45
|
* errors={submitFailed ? "Fix the highlighted fields." : undefined}
|
|
46
46
|
* onSubmit={handleSubmit(onValid)}
|
|
47
47
|
* actions={
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export { A as AppShell, a as AppShellOptions, b as AppShellProps, N as NavItem, P as PageHeader, c as PageHeaderOptions, d as PageHeaderProps } from '../../AppShell-
|
|
1
|
+
export { A as AppShell, a as AppShellOptions, b as AppShellProps, N as NavItem, P as PageHeader, c as PageHeaderOptions, d as PageHeaderProps, e as ParentNavigation } from '../../AppShell-LXQykEqe.js';
|
|
2
|
+
export { G as GenesisLinkProps, L as LinkComponent, N as NavigationNode, R as ResolvedNavigation, r as resolveNavigation } from '../../navigation-Bha0R3Fu.js';
|
|
2
3
|
export { DetailPage, DetailPageProps } from './detail-page.js';
|
|
3
4
|
export { FormPage, FormPageProps } from './form-page.js';
|
|
4
5
|
export { D as DashboardPage, a as DashboardPageProps, G as Grid, b as GridProps, g as gridVariants } from '../../dashboard-page-C0TihRl5.js';
|
|
@@ -9,6 +10,5 @@ import 'react';
|
|
|
9
10
|
import 'lucide-react';
|
|
10
11
|
import '../../view-toggle-CahQ87PW.js';
|
|
11
12
|
import '../../hooks/use-view-settings.js';
|
|
12
|
-
import '../../navigation-DBwcZ6vb.js';
|
|
13
13
|
import 'class-variance-authority/types';
|
|
14
14
|
import 'class-variance-authority';
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
export { AppShell, PageHeader } from '../../chunk-
|
|
1
|
+
export { AppShell, PageHeader } from '../../chunk-UYI3GLFJ.js';
|
|
2
2
|
import '../../chunk-46TZGMFW.js';
|
|
3
3
|
export { Container, Stack, containerVariants, stackVariants } from '../../chunk-4CQHPWJD.js';
|
|
4
|
-
export {
|
|
4
|
+
export { DashboardPage, Grid, gridVariants } from '../../chunk-ARJI2JUV.js';
|
|
5
|
+
export { FormPage } from '../../chunk-MPI33I4K.js';
|
|
5
6
|
import '../../chunk-OZZTPE7F.js';
|
|
6
7
|
export { Section, SettingsPage, sectionHeadingVariants } from '../../chunk-P64MFQXZ.js';
|
|
7
|
-
import '../../chunk-QJ6P2DW6.js';
|
|
8
8
|
import '../../chunk-B2GIBUQD.js';
|
|
9
9
|
import '../../chunk-NPNADZHM.js';
|
|
10
|
+
export { DetailPage } from '../../chunk-AFZ76Q26.js';
|
|
11
|
+
export { Split, splitVariants } from '../../chunk-D2LIXA2Y.js';
|
|
12
|
+
export { GAP_CLASSES, spaceScale } from '../../chunk-AVFZ4P4B.js';
|
|
10
13
|
import '../../chunk-FK42ZGGV.js';
|
|
11
|
-
import '../../chunk-
|
|
14
|
+
import '../../chunk-QJ6P2DW6.js';
|
|
12
15
|
import '../../chunk-27ELYTGE.js';
|
|
16
|
+
import '../../chunk-22XB3Q6H.js';
|
|
13
17
|
import '../../chunk-NWSCYLPT.js';
|
|
14
18
|
import '../../chunk-F47U5KNW.js';
|
|
15
|
-
export { DashboardPage, Grid, gridVariants } from '../../chunk-ARJI2JUV.js';
|
|
16
|
-
export { DetailPage } from '../../chunk-AFZ76Q26.js';
|
|
17
|
-
export { Split, splitVariants } from '../../chunk-D2LIXA2Y.js';
|
|
18
|
-
export { GAP_CLASSES, spaceScale } from '../../chunk-AVFZ4P4B.js';
|
|
19
19
|
import '../../chunk-NZ5WBA4R.js';
|
|
20
|
-
|
|
20
|
+
export { resolveNavigation } from '../../chunk-WGMEVX3Y.js';
|
|
21
21
|
//# sourceMappingURL=index.js.map
|
|
22
22
|
//# sourceMappingURL=index.js.map
|
|
@@ -2,6 +2,7 @@ export { EmptyState, EmptyStateProps, NoFeaturesFound, NoFeedbackFound, NoSearch
|
|
|
2
2
|
export { FormDescription, FormError, FormField, FormLabel } from './form-field.js';
|
|
3
3
|
export { PageLoading, PageLoadingProps, pageLoadingVariants } from './page-loading.js';
|
|
4
4
|
export { SettingsRow, SettingsRowProps } from './settings-row.js';
|
|
5
|
+
export { SortableList, SortableListItemContext, SortableListProps, SortableListReorder } from './sortable-list.js';
|
|
5
6
|
export { StatusBadge, StatusBadgeProps, StatusBadgeStatus, statusBadgeVariants } from './status-badge.js';
|
|
6
7
|
export { ToggleRow, ToggleRowProps } from './toggle-row.js';
|
|
7
8
|
export { UserAvatar, UserAvatarProps, userAvatarVariants } from './user-avatar.js';
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
export { ViewSettings, ViewToggle } from '../../chunk-46TZGMFW.js';
|
|
2
|
+
export { SortableList } from '../../chunk-S7NXD37O.js';
|
|
2
3
|
export { StatusBadge, statusBadgeVariants } from '../../chunk-XMK3T4TA.js';
|
|
3
4
|
export { ToggleRow } from '../../chunk-6M4NHHKG.js';
|
|
5
|
+
export { SettingsRow } from '../../chunk-A7AHVDG7.js';
|
|
4
6
|
export { UserAvatar, userAvatarVariants } from '../../chunk-XBX6QMR5.js';
|
|
5
7
|
import '../../chunk-LNFF2RBD.js';
|
|
6
|
-
export {
|
|
8
|
+
export { PageLoading, pageLoadingVariants } from '../../chunk-YRYQXU3G.js';
|
|
9
|
+
import '../../chunk-OVU3Z2MT.js';
|
|
7
10
|
import '../../chunk-FK42ZGGV.js';
|
|
8
|
-
import '../../chunk-
|
|
11
|
+
import '../../chunk-QJ6P2DW6.js';
|
|
9
12
|
import '../../chunk-27ELYTGE.js';
|
|
13
|
+
import '../../chunk-22XB3Q6H.js';
|
|
10
14
|
export { EmptyState, NoFeaturesFound, NoFeedbackFound, NoSearchResults } from '../../chunk-65SPT7EA.js';
|
|
11
15
|
import '../../chunk-NWSCYLPT.js';
|
|
12
|
-
export { PageLoading, pageLoadingVariants } from '../../chunk-YRYQXU3G.js';
|
|
13
|
-
import '../../chunk-OVU3Z2MT.js';
|
|
14
16
|
export { FormDescription, FormError, FormField, FormLabel } from '../../chunk-R7QFP6EL.js';
|
|
15
17
|
import '../../chunk-F47U5KNW.js';
|
|
16
18
|
import '../../chunk-NZ5WBA4R.js';
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
interface SortableListItemContext {
|
|
4
|
+
/** The item's position as shown, from 0. */
|
|
5
|
+
index: number;
|
|
6
|
+
/**
|
|
7
|
+
* The drag handle: drag it with a pointer, or focus it and press Space or
|
|
8
|
+
* Enter to pick the item up, the arrow keys to move it and Space or Enter
|
|
9
|
+
* again to drop it. Render it somewhere in the row.
|
|
10
|
+
*/
|
|
11
|
+
handle: React.ReactNode;
|
|
12
|
+
/** True while this item is being dragged with a pointer. */
|
|
13
|
+
isDragging: boolean;
|
|
14
|
+
/** True while this item is picked up from the keyboard. */
|
|
15
|
+
isGrabbed: boolean;
|
|
16
|
+
/** Move this item without dragging, for a row menu of your own. */
|
|
17
|
+
moveUp: () => void;
|
|
18
|
+
moveDown: () => void;
|
|
19
|
+
moveTo: (index: number) => void;
|
|
20
|
+
}
|
|
21
|
+
interface SortableListReorder {
|
|
22
|
+
/** Key of the item that moved. */
|
|
23
|
+
key: string;
|
|
24
|
+
}
|
|
25
|
+
interface SortableListProps<T> {
|
|
26
|
+
items: readonly T[];
|
|
27
|
+
/** A stable key per item. Required: dragging finds the item again by key. */
|
|
28
|
+
getKey: (item: T) => string;
|
|
29
|
+
/** A name for an item, for the handle's label and announcements ("Week 1"). */
|
|
30
|
+
getItemLabel: (item: T) => string;
|
|
31
|
+
renderItem: (item: T, context: SortableListItemContext) => React.ReactNode;
|
|
32
|
+
/**
|
|
33
|
+
* Move the item at `from` to `to` (both from 0, `to` counted after the item
|
|
34
|
+
* is taken out). Each finished move calls this once: a keyboard pick-up
|
|
35
|
+
* that wanders and comes back calls nothing.
|
|
36
|
+
*
|
|
37
|
+
* The list shows the new order straight away and keeps showing it until the
|
|
38
|
+
* returned promise settles; by then `items` must be in the new order. A
|
|
39
|
+
* synchronous handler must update `items` in the same tick. A rejected
|
|
40
|
+
* promise puts the old order back and announces that the move failed. Other
|
|
41
|
+
* moves wait until this one settles.
|
|
42
|
+
*/
|
|
43
|
+
onReorder: (from: number, to: number, move: SortableListReorder) => void | Promise<void>;
|
|
44
|
+
/** Accessible name of the list ("Course steps"). */
|
|
45
|
+
label: string;
|
|
46
|
+
/** Turns off dragging and every kind of move. */
|
|
47
|
+
disabled?: boolean | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* A "Move" menu on each row (up, down, to top, to bottom), on by default so
|
|
50
|
+
* touch and screen-reader users always have a way to move an item. Turn it
|
|
51
|
+
* off only when the row offers `moveUp` / `moveDown` / `moveTo` itself.
|
|
52
|
+
*/
|
|
53
|
+
moveMenu?: boolean | undefined;
|
|
54
|
+
className?: string | undefined;
|
|
55
|
+
itemClassName?: string | undefined;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* A vertical list the user can rearrange: course steps, lesson blocks, form
|
|
59
|
+
* fields.
|
|
60
|
+
*
|
|
61
|
+
* Every way to move an item is equivalent, so dragging is never the only one
|
|
62
|
+
* (the same stance as KanbanBoard's "Move to…" menu):
|
|
63
|
+
* - drag the handle with a pointer;
|
|
64
|
+
* - focus the handle, Space or Enter to pick up, ↑/↓ and Home/End to move,
|
|
65
|
+
* Space or Enter to drop, Escape to put it back (tabbing away also puts it
|
|
66
|
+
* back); Alt+↑/↓ moves one step without picking up;
|
|
67
|
+
* - the row's "Move" menu, or `moveUp` / `moveDown` / `moveTo` from the render
|
|
68
|
+
* context.
|
|
69
|
+
*
|
|
70
|
+
* Moves are announced in a polite live region once they succeed. Native drag
|
|
71
|
+
* and drop needs no dependency and Radix has none to offer (docs/FRAMEWORK.md
|
|
72
|
+
* rule 3).
|
|
73
|
+
*
|
|
74
|
+
* @stability Beta
|
|
75
|
+
*/
|
|
76
|
+
declare function SortableList<T>({ items, getKey, getItemLabel, renderItem, onReorder, label, disabled, moveMenu, className, itemClassName, }: SortableListProps<T>): React.JSX.Element;
|
|
77
|
+
|
|
78
|
+
export { SortableList, type SortableListItemContext, type SortableListProps, type SortableListReorder };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"sortable-list.js"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Editor } from '@tiptap/react';
|
|
3
|
+
import { R as RichTextDoc, a as RichTextHeadingLevel } from '../../rich-text-doc-C54fME2C.js';
|
|
4
|
+
import { Node } from '@tiptap/core';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* VideoEmbed — a Tiptap node for YouTube, Vimeo and Loom players.
|
|
8
|
+
*
|
|
9
|
+
* The node stores only `{ provider, id, hash?, title? }`, never a URL, and
|
|
10
|
+
* rebuilds the player URL from those validated parts every time it renders.
|
|
11
|
+
* A pasted `<iframe>` is accepted only when its `src` parses as one of the
|
|
12
|
+
* three hosts; any other iframe is dropped by the editor's schema.
|
|
13
|
+
*
|
|
14
|
+
* Exported for apps that assemble their own Tiptap editor and want the same
|
|
15
|
+
* embed node `RichTextEditor` uses.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
declare module "@tiptap/core" {
|
|
19
|
+
interface Commands<ReturnType> {
|
|
20
|
+
videoEmbed: {
|
|
21
|
+
/**
|
|
22
|
+
* Insert a video embed from a YouTube, Vimeo or Loom URL. Fails (returns
|
|
23
|
+
* false, inserts nothing) for any other URL.
|
|
24
|
+
*/
|
|
25
|
+
setVideoEmbed: (options: {
|
|
26
|
+
url: string;
|
|
27
|
+
title?: string;
|
|
28
|
+
}) => ReturnType;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Tiptap node for YouTube, Vimeo and Loom players, stored as
|
|
34
|
+
* `{ provider, id, hash?, title? }` and rebuilt from those parts on render.
|
|
35
|
+
* Adds the `setVideoEmbed({ url, title })` command.
|
|
36
|
+
*
|
|
37
|
+
* @stability Beta
|
|
38
|
+
*/
|
|
39
|
+
declare const VideoEmbed: Node<any, any>;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* RichTextEditor — a WYSIWYG editor for formatted content (headings, bold,
|
|
43
|
+
* italic, underline, lists, links, quotes and optional video embeds), built
|
|
44
|
+
* on Tiptap 3 (ProseMirror) with a Genesis `Toolbar`.
|
|
45
|
+
*
|
|
46
|
+
* Lives on its own subpath, `@marktiderman/genesis-ui/rich-text-editor`, so
|
|
47
|
+
* only apps that import it need the `@tiptap/*` peers. The read-only
|
|
48
|
+
* renderer and the server-safe helpers are on `/rich-text`.
|
|
49
|
+
*
|
|
50
|
+
* @stability Beta
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* What the editor accepts as a value: the document JSON (canonical), or an
|
|
55
|
+
* HTML string. HTML is parsed by the editor in the browser and reduced to
|
|
56
|
+
* the editor's schema, so it is a migration convenience, not a storage
|
|
57
|
+
* format. Output is always JSON plus derived, sanitized HTML.
|
|
58
|
+
*/
|
|
59
|
+
type RichTextEditorValue = RichTextDoc | string;
|
|
60
|
+
/** Derived forms of the document, computed on first read. */
|
|
61
|
+
interface RichTextChangeDetails {
|
|
62
|
+
/** Sanitized HTML from `richTextToHtml`. */
|
|
63
|
+
readonly html: string;
|
|
64
|
+
/** Plain text from `richTextToPlainText`. */
|
|
65
|
+
readonly text: string;
|
|
66
|
+
/** True when there is no visible text and no embed. */
|
|
67
|
+
readonly isEmpty: boolean;
|
|
68
|
+
/** Character count of the text (what `maxLength` limits). */
|
|
69
|
+
readonly characters: number;
|
|
70
|
+
}
|
|
71
|
+
type RichTextToolbarItem = "heading2" | "heading3" | "heading4" | "bold" | "italic" | "underline" | "bulletList" | "orderedList" | "blockquote" | "link" | "video" | "undo" | "redo";
|
|
72
|
+
interface RichTextEditorLabels {
|
|
73
|
+
toolbar: string;
|
|
74
|
+
blockGroup: string;
|
|
75
|
+
markGroup: string;
|
|
76
|
+
heading2: string;
|
|
77
|
+
heading3: string;
|
|
78
|
+
heading4: string;
|
|
79
|
+
bold: string;
|
|
80
|
+
italic: string;
|
|
81
|
+
underline: string;
|
|
82
|
+
bulletList: string;
|
|
83
|
+
orderedList: string;
|
|
84
|
+
blockquote: string;
|
|
85
|
+
link: string;
|
|
86
|
+
video: string;
|
|
87
|
+
undo: string;
|
|
88
|
+
redo: string;
|
|
89
|
+
linkUrl: string;
|
|
90
|
+
linkApply: string;
|
|
91
|
+
linkRemove: string;
|
|
92
|
+
linkInvalid: string;
|
|
93
|
+
videoUrl: string;
|
|
94
|
+
videoTitle: string;
|
|
95
|
+
videoInsert: string;
|
|
96
|
+
videoInvalid: string;
|
|
97
|
+
cancel: string;
|
|
98
|
+
characterCount: (count: number, max: number | undefined) => string;
|
|
99
|
+
}
|
|
100
|
+
/** Imperative handle exposed through `ref`. */
|
|
101
|
+
interface RichTextEditorHandle {
|
|
102
|
+
/** Move focus into the editable area. */
|
|
103
|
+
focus: () => void;
|
|
104
|
+
/** Replace the content with an empty document (fires `onChange`). */
|
|
105
|
+
clear: () => void;
|
|
106
|
+
/** The current document, sanitized. */
|
|
107
|
+
getJSON: () => RichTextDoc;
|
|
108
|
+
/** The current document as sanitized HTML. */
|
|
109
|
+
getHTML: () => string;
|
|
110
|
+
/** The underlying Tiptap editor, once mounted (null during SSR/first paint). */
|
|
111
|
+
readonly editor: Editor | null;
|
|
112
|
+
}
|
|
113
|
+
interface RichTextEditorProps {
|
|
114
|
+
/**
|
|
115
|
+
* Controlled value. Pass back the `doc` from `onChange` synchronously; any
|
|
116
|
+
* other document (including an older one from a debounced or deferred
|
|
117
|
+
* parent) replaces the content and resets the selection.
|
|
118
|
+
*/
|
|
119
|
+
value?: RichTextEditorValue;
|
|
120
|
+
/** Initial value for an uncontrolled editor. */
|
|
121
|
+
defaultValue?: RichTextEditorValue;
|
|
122
|
+
/**
|
|
123
|
+
* Called on every edit with the sanitized document. `details` derives HTML
|
|
124
|
+
* and text lazily, so reading only `doc` costs no serialization.
|
|
125
|
+
*/
|
|
126
|
+
onChange?: (doc: RichTextDoc, details: RichTextChangeDetails) => void;
|
|
127
|
+
onFocus?: () => void;
|
|
128
|
+
onBlur?: () => void;
|
|
129
|
+
/**
|
|
130
|
+
* `id` of the editable element. A `<label htmlFor={id}>` names the editor
|
|
131
|
+
* (wired as `aria-labelledby`, since a contenteditable is not a labelable
|
|
132
|
+
* element) and clicking it focuses the editor.
|
|
133
|
+
*/
|
|
134
|
+
id?: string;
|
|
135
|
+
/**
|
|
136
|
+
* Form field name. When set, a hidden input carries the document as JSON
|
|
137
|
+
* so a native `<form>` submission includes it.
|
|
138
|
+
*/
|
|
139
|
+
name?: string;
|
|
140
|
+
"aria-label"?: string;
|
|
141
|
+
"aria-labelledby"?: string;
|
|
142
|
+
"aria-describedby"?: string;
|
|
143
|
+
/** Marks the field invalid (`aria-invalid`, destructive border). */
|
|
144
|
+
invalid?: boolean;
|
|
145
|
+
/** Placeholder shown while the document is empty. */
|
|
146
|
+
placeholder?: string;
|
|
147
|
+
/** Content is visible and selectable but not editable; the toolbar is hidden. */
|
|
148
|
+
readOnly?: boolean;
|
|
149
|
+
/** Not editable, toolbar disabled, dimmed. */
|
|
150
|
+
disabled?: boolean;
|
|
151
|
+
autoFocus?: boolean;
|
|
152
|
+
/** Heading levels offered in the toolbar and kept in the document. Default `[2, 3]`. Read at mount. */
|
|
153
|
+
headingLevels?: readonly RichTextHeadingLevel[];
|
|
154
|
+
/** Enable YouTube / Vimeo / Loom embeds (toolbar button and schema). Default `false`. Read at mount. */
|
|
155
|
+
embeds?: boolean;
|
|
156
|
+
/** Maximum characters. Typing and pasting stop at the limit. Read at mount. */
|
|
157
|
+
maxLength?: number;
|
|
158
|
+
/** Show the character count under the editor. On by default when `maxLength` is set. */
|
|
159
|
+
showCharacterCount?: boolean;
|
|
160
|
+
/** Toolbar items, in groups as listed. `false` hides the toolbar (shortcuts still work). */
|
|
161
|
+
toolbar?: false | readonly RichTextToolbarItem[];
|
|
162
|
+
/** Override any user-facing string (for translation). */
|
|
163
|
+
labels?: Partial<RichTextEditorLabels>;
|
|
164
|
+
/** Classes for the outer frame. */
|
|
165
|
+
className?: string;
|
|
166
|
+
/** Classes for the editable area (for example a taller `min-h-*`). */
|
|
167
|
+
contentClassName?: string;
|
|
168
|
+
/** Stable test/automation selector (emitted as `data-testid` on the frame). */
|
|
169
|
+
testID?: string;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* RichTextEditor — formatted text input for lessons, notes and other
|
|
173
|
+
* long-form content.
|
|
174
|
+
*
|
|
175
|
+
* - **Value:** JSON is canonical (`RichTextDoc`). `onChange` hands you the
|
|
176
|
+
* sanitized document plus lazily derived `html`/`text`. Store the JSON;
|
|
177
|
+
* on the server re-run `sanitizeRichTextDoc` and derive HTML with
|
|
178
|
+
* `richTextToHtml` (both from `/rich-text`, no DOM needed).
|
|
179
|
+
* - **Security:** output goes through the same allow-list as `RichText`;
|
|
180
|
+
* links keep only http(s)/mailto/tel/relative URLs; embeds are rebuilt
|
|
181
|
+
* from a validated YouTube/Vimeo/Loom id.
|
|
182
|
+
* - **SSR:** the editor mounts on the client only (Tiptap
|
|
183
|
+
* `immediatelyRender: false`). Until then a JSON value renders read-only,
|
|
184
|
+
* so server HTML shows the content instead of an empty box.
|
|
185
|
+
* - **Keyboard:** standard shortcuts (⌘/Ctrl+B, I, U, K for link,
|
|
186
|
+
* ⌘/Ctrl+Alt+2/3 for headings, ⌘/Ctrl+Shift+7/8 for lists, ⌘/Ctrl+Shift+B
|
|
187
|
+
* for quote, ⌘/Ctrl+Z / Shift+Z), shown in each toolbar tooltip. The
|
|
188
|
+
* toolbar is one tab stop with arrow-key navigation (Radix Toolbar).
|
|
189
|
+
*
|
|
190
|
+
* @stability Beta
|
|
191
|
+
*/
|
|
192
|
+
declare const RichTextEditor: React.ForwardRefExoticComponent<RichTextEditorProps & React.RefAttributes<RichTextEditorHandle>>;
|
|
193
|
+
|
|
194
|
+
export { type RichTextChangeDetails, RichTextDoc, RichTextEditor, type RichTextEditorHandle, type RichTextEditorLabels, type RichTextEditorProps, type RichTextEditorValue, RichTextHeadingLevel, type RichTextToolbarItem, VideoEmbed };
|