@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.
Files changed (70) hide show
  1. package/EXTENDING.md +40 -1
  2. package/SKILL.md +145 -9
  3. package/dist/{AppShell-CX0M-dfc.d.ts → AppShell-LXQykEqe.d.ts} +47 -5
  4. package/dist/{chunk-M62CHO3N.js → chunk-4C4ESW6O.js} +9 -4
  5. package/dist/chunk-4C4ESW6O.js.map +1 -0
  6. package/dist/{chunk-IXGAEECT.js → chunk-DWCAC2E7.js} +6 -3
  7. package/dist/chunk-DWCAC2E7.js.map +1 -0
  8. package/dist/chunk-FUVWKTPL.js +19 -0
  9. package/dist/chunk-FUVWKTPL.js.map +1 -0
  10. package/dist/{chunk-PLIYF6KI.js → chunk-MPI33I4K.js} +2 -2
  11. package/dist/{chunk-PLIYF6KI.js.map → chunk-MPI33I4K.js.map} +1 -1
  12. package/dist/{chunk-JA3ZKULS.js → chunk-OITWCIG2.js} +3 -3
  13. package/dist/chunk-OITWCIG2.js.map +1 -0
  14. package/dist/chunk-PKFDGGZV.js +65 -0
  15. package/dist/chunk-PKFDGGZV.js.map +1 -0
  16. package/dist/chunk-S7NXD37O.js +321 -0
  17. package/dist/chunk-S7NXD37O.js.map +1 -0
  18. package/dist/{chunk-DWM7ELFI.js → chunk-UYI3GLFJ.js} +163 -20
  19. package/dist/chunk-UYI3GLFJ.js.map +1 -0
  20. package/dist/{chunk-CDYZRZ6U.js → chunk-WGMEVX3Y.js} +2 -2
  21. package/dist/chunk-WGMEVX3Y.js.map +1 -0
  22. package/dist/chunk-ZDHWNQTR.js +552 -0
  23. package/dist/chunk-ZDHWNQTR.js.map +1 -0
  24. package/dist/components/data/index.d.ts +239 -15
  25. package/dist/components/data/index.js +524 -109
  26. package/dist/components/data/index.js.map +1 -1
  27. package/dist/components/layout/form-page.d.ts +1 -1
  28. package/dist/components/layout/form-page.js +1 -1
  29. package/dist/components/layout/index.d.ts +2 -2
  30. package/dist/components/layout/index.js +9 -9
  31. package/dist/components/patterns/index.d.ts +1 -0
  32. package/dist/components/patterns/index.js +6 -4
  33. package/dist/components/patterns/sortable-list.d.ts +78 -0
  34. package/dist/components/patterns/sortable-list.js +5 -0
  35. package/dist/components/patterns/sortable-list.js.map +1 -0
  36. package/dist/components/rich-text/rich-text-editor.d.ts +194 -0
  37. package/dist/components/rich-text/rich-text-editor.js +833 -0
  38. package/dist/components/rich-text/rich-text-editor.js.map +1 -0
  39. package/dist/components/rich-text/rich-text.d.ts +51 -0
  40. package/dist/components/rich-text/rich-text.js +4 -0
  41. package/dist/components/rich-text/rich-text.js.map +1 -0
  42. package/dist/components/ui/alert-dialog.d.ts +12 -1
  43. package/dist/components/ui/alert-dialog.js +1 -1
  44. package/dist/hooks/index.d.ts +3 -3
  45. package/dist/hooks/index.js +4 -4
  46. package/dist/hooks/use-data-filters.d.ts +5 -3
  47. package/dist/hooks/use-data-filters.js +2 -2
  48. package/dist/hooks/use-resource-page.d.ts +2 -1
  49. package/dist/hooks/use-resource-page.js +3 -2
  50. package/dist/hooks/use-view-preference.d.ts +17 -2
  51. package/dist/hooks/use-view-preference.js +2 -1
  52. package/dist/index.d.ts +2 -1
  53. package/dist/index.js +30 -29
  54. package/dist/{navigation-DBwcZ6vb.d.ts → navigation-Bha0R3Fu.d.ts} +6 -3
  55. package/dist/rich-text-doc-C54fME2C.d.ts +180 -0
  56. package/dist/router/react-router.d.ts +47 -0
  57. package/dist/router/react-router.js +53 -0
  58. package/dist/router/react-router.js.map +1 -0
  59. package/dist/router/tanstack-router.d.ts +47 -0
  60. package/dist/router/tanstack-router.js +105 -0
  61. package/dist/router/tanstack-router.js.map +1 -0
  62. package/dist/{use-resource-page-Dd2VUv30.d.ts → use-resource-page-D4byuwAs.d.ts} +20 -3
  63. package/package.json +62 -7
  64. package/dist/chunk-CDYZRZ6U.js.map +0 -1
  65. package/dist/chunk-DWM7ELFI.js.map +0 -1
  66. package/dist/chunk-FTTNGGLA.js +0 -20
  67. package/dist/chunk-FTTNGGLA.js.map +0 -1
  68. package/dist/chunk-IXGAEECT.js.map +0 -1
  69. package/dist/chunk-JA3ZKULS.js.map +0 -1
  70. 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 the coach and the client will be notified."
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,4 @@
1
- export { FormPage } from '../../chunk-PLIYF6KI.js';
1
+ export { FormPage } from '../../chunk-MPI33I4K.js';
2
2
  import '../../chunk-OZZTPE7F.js';
3
3
  import '../../chunk-NZ5WBA4R.js';
4
4
  //# sourceMappingURL=form-page.js.map
@@ -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-CX0M-dfc.js';
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-DWM7ELFI.js';
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 { FormPage } from '../../chunk-PLIYF6KI.js';
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-22XB3Q6H.js';
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
- import '../../chunk-CDYZRZ6U.js';
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 { SettingsRow } from '../../chunk-A7AHVDG7.js';
8
+ export { PageLoading, pageLoadingVariants } from '../../chunk-YRYQXU3G.js';
9
+ import '../../chunk-OVU3Z2MT.js';
7
10
  import '../../chunk-FK42ZGGV.js';
8
- import '../../chunk-22XB3Q6H.js';
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,5 @@
1
+ export { SortableList } from '../../chunk-S7NXD37O.js';
2
+ import '../../chunk-QJ6P2DW6.js';
3
+ import '../../chunk-NZ5WBA4R.js';
4
+ //# sourceMappingURL=sortable-list.js.map
5
+ //# sourceMappingURL=sortable-list.js.map
@@ -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 };