@astryxdesign/lab 0.1.9-canary.d2d84f8 → 0.1.9-canary.e00a241
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/dist/BottomSheet/BottomSheet.d.ts +95 -0
- package/dist/BottomSheet/BottomSheet.d.ts.map +1 -0
- package/dist/BottomSheet/BottomSheet.js +150 -0
- package/dist/BottomSheet/index.d.ts +9 -0
- package/dist/BottomSheet/index.d.ts.map +1 -0
- package/dist/BottomSheet/index.js +10 -0
- package/dist/BottomSheet/useSheetGestures.d.ts +69 -0
- package/dist/BottomSheet/useSheetGestures.d.ts.map +1 -0
- package/dist/BottomSheet/useSheetGestures.js +163 -0
- package/dist/RichTextEditor/RichTextEditor.d.ts +67 -6
- package/dist/RichTextEditor/RichTextEditor.d.ts.map +1 -1
- package/dist/RichTextEditor/RichTextEditor.js +165 -12
- package/dist/RichTextEditor/editorTheme.d.ts.map +1 -1
- package/dist/RichTextEditor/editorTheme.js +33 -7
- package/dist/RichTextEditor/index.d.ts +1 -1
- package/dist/RichTextEditor/index.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/lab.css +23 -0
- package/package.json +2 -2
- package/src/BottomSheet/BottomSheet.doc.mjs +105 -0
- package/src/BottomSheet/BottomSheet.test.tsx +233 -0
- package/src/BottomSheet/BottomSheet.tsx +226 -0
- package/src/BottomSheet/index.ts +11 -0
- package/src/BottomSheet/useSheetGestures.doc.mjs +31 -0
- package/src/BottomSheet/useSheetGestures.test.ts +160 -0
- package/src/BottomSheet/useSheetGestures.ts +226 -0
- package/src/ChatReasoning/ChatReasoning.doc.mjs +49 -2
- package/src/CodeEditor/CodeEditor.doc.mjs +67 -2
- package/src/LogStream/LogStream.doc.mjs +53 -2
- package/src/RichTextEditor/RichTextEditor.doc.mjs +19 -1
- package/src/RichTextEditor/RichTextEditor.test.tsx +441 -11
- package/src/RichTextEditor/RichTextEditor.tsx +289 -31
- package/src/RichTextEditor/editorTheme.ts +63 -3
- package/src/RichTextEditor/index.ts +2 -0
- package/src/Schedule/Schedule.doc.mjs +143 -3
- package/src/Stepper/Stepper.doc.mjs +6 -0
- package/src/__tests__/labApiContractDrift.test.tsx +57 -0
- package/src/index.ts +5 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @file useSheetGestures.ts
|
|
7
|
+
* @input Uses React (useCallback, useEffect, useMemo, useRef, useState)
|
|
8
|
+
* @output Exports useSheetGestures hook and its option/result types
|
|
9
|
+
* @position Internal to BottomSheet; not exported from the lab entry point
|
|
10
|
+
*
|
|
11
|
+
* Drag-to-dismiss machinery for the bottom sheet. Tracks a pointer drag
|
|
12
|
+
* down the block axis, translates the sliding surface live, and on release
|
|
13
|
+
* either dismisses (past a distance or velocity threshold) or springs back
|
|
14
|
+
* to fully open. Pointer-events based so one code path covers mouse + touch.
|
|
15
|
+
*
|
|
16
|
+
* Kept private to BottomSheet: the behavior is sheet-specific (a dismiss
|
|
17
|
+
* edge on a bottom-anchored surface). It is not a general primitive and is
|
|
18
|
+
* intentionally not exported.
|
|
19
|
+
*
|
|
20
|
+
* SSR-safe: no window/document access at module scope; all measurement
|
|
21
|
+
* happens inside handlers. Respects prefers-reduced-motion by skipping the
|
|
22
|
+
* settle transition.
|
|
23
|
+
*
|
|
24
|
+
* SYNC: When modified, update these files to stay in sync:
|
|
25
|
+
* - /packages/lab/src/BottomSheet/useSheetGestures.doc.mjs
|
|
26
|
+
* - /packages/lab/src/BottomSheet/useSheetGestures.test.ts
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import {
|
|
30
|
+
useCallback,
|
|
31
|
+
useEffect,
|
|
32
|
+
useMemo,
|
|
33
|
+
useRef,
|
|
34
|
+
useState,
|
|
35
|
+
type CSSProperties,
|
|
36
|
+
type PointerEvent as ReactPointerEvent,
|
|
37
|
+
} from 'react';
|
|
38
|
+
|
|
39
|
+
// Fraction of the measured sheet height a drag must cross (with low
|
|
40
|
+
// velocity) before release dismisses instead of springing back.
|
|
41
|
+
const DISMISS_DISTANCE_RATIO = 0.25;
|
|
42
|
+
// A quick flick past this speed (px/ms) dismisses regardless of distance.
|
|
43
|
+
const DISMISS_VELOCITY = 0.5;
|
|
44
|
+
|
|
45
|
+
export interface UseSheetGesturesOptions {
|
|
46
|
+
/** Whether the owning sheet is open. Drag state resets when it closes. */
|
|
47
|
+
isOpen: boolean;
|
|
48
|
+
/** Called when a drag crosses the dismiss threshold (distance or flick). */
|
|
49
|
+
onDismiss: () => void;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface SheetContentProps {
|
|
53
|
+
style: CSSProperties;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface SheetHandleProps {
|
|
57
|
+
style: CSSProperties;
|
|
58
|
+
onPointerDown: (event: ReactPointerEvent) => void;
|
|
59
|
+
onPointerMove: (event: ReactPointerEvent) => void;
|
|
60
|
+
onPointerUp: (event: ReactPointerEvent) => void;
|
|
61
|
+
onPointerCancel: (event: ReactPointerEvent) => void;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface UseSheetGesturesResult {
|
|
65
|
+
/** Spread on the sliding surface: live translate + touch-action guard. */
|
|
66
|
+
contentProps: SheetContentProps;
|
|
67
|
+
/** Spread on the grab-handle element: pointer drag handlers. */
|
|
68
|
+
handleProps: SheetHandleProps;
|
|
69
|
+
/** Current live drag offset in px (positive = dragged toward the edge). */
|
|
70
|
+
dragOffset: number;
|
|
71
|
+
/** Whether a drag is currently in progress. */
|
|
72
|
+
isDragging: boolean;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function prefersReducedMotion(): boolean {
|
|
76
|
+
if (typeof window === 'undefined' || !window.matchMedia) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
return window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Drag-to-dismiss machinery for the bottom sheet. Returns props to spread on
|
|
84
|
+
* the grab handle and the sliding surface, plus live drag state for callers
|
|
85
|
+
* that want to drive their own animation.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```
|
|
89
|
+
* const {contentProps, handleProps} = useSheetGestures({
|
|
90
|
+
* isOpen,
|
|
91
|
+
* onDismiss: () => onOpenChange(false),
|
|
92
|
+
* });
|
|
93
|
+
* <div {...contentProps}>
|
|
94
|
+
* <div {...handleProps} />
|
|
95
|
+
* {children}
|
|
96
|
+
* </div>
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
export function useSheetGestures({
|
|
100
|
+
isOpen,
|
|
101
|
+
onDismiss,
|
|
102
|
+
}: UseSheetGesturesOptions): UseSheetGesturesResult {
|
|
103
|
+
const [dragOffset, setDragOffset] = useState(0);
|
|
104
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
105
|
+
|
|
106
|
+
// Latest callback ref so pointer handlers stay stable across renders.
|
|
107
|
+
const onDismissRef = useRef(onDismiss);
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
onDismissRef.current = onDismiss;
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Live drag bookkeeping (refs so pointermove doesn't churn renders).
|
|
113
|
+
const dragStateRef = useRef<{
|
|
114
|
+
pointerId: number;
|
|
115
|
+
startCoord: number;
|
|
116
|
+
lastCoord: number;
|
|
117
|
+
lastTime: number;
|
|
118
|
+
velocity: number;
|
|
119
|
+
height: number;
|
|
120
|
+
} | null>(null);
|
|
121
|
+
|
|
122
|
+
// Reset drag state each time the sheet re-opens.
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
if (isOpen) {
|
|
125
|
+
setDragOffset(0);
|
|
126
|
+
setIsDragging(false);
|
|
127
|
+
}
|
|
128
|
+
}, [isOpen]);
|
|
129
|
+
|
|
130
|
+
const measureHeight = useCallback((el: HTMLElement | null): number => {
|
|
131
|
+
const sheet = el?.closest<HTMLElement>('[data-astryx-sheet]') ?? el;
|
|
132
|
+
return sheet?.getBoundingClientRect().height ?? 0;
|
|
133
|
+
}, []);
|
|
134
|
+
|
|
135
|
+
const settleFromDrag = useCallback(
|
|
136
|
+
(offset: number, velocity: number, height: number) => {
|
|
137
|
+
const dismiss =
|
|
138
|
+
offset > height * DISMISS_DISTANCE_RATIO || velocity > DISMISS_VELOCITY;
|
|
139
|
+
if (dismiss) {
|
|
140
|
+
onDismissRef.current();
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
// Below threshold: spring back to fully open.
|
|
144
|
+
setDragOffset(0);
|
|
145
|
+
},
|
|
146
|
+
[],
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
const handlePointerDown = useCallback(
|
|
150
|
+
(event: ReactPointerEvent) => {
|
|
151
|
+
const target = event.currentTarget as HTMLElement;
|
|
152
|
+
target.setPointerCapture?.(event.pointerId);
|
|
153
|
+
dragStateRef.current = {
|
|
154
|
+
pointerId: event.pointerId,
|
|
155
|
+
startCoord: event.clientY,
|
|
156
|
+
lastCoord: event.clientY,
|
|
157
|
+
lastTime: event.timeStamp,
|
|
158
|
+
velocity: 0,
|
|
159
|
+
height: measureHeight(target),
|
|
160
|
+
};
|
|
161
|
+
setIsDragging(true);
|
|
162
|
+
},
|
|
163
|
+
[measureHeight],
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
const handlePointerMove = useCallback((event: ReactPointerEvent) => {
|
|
167
|
+
const state = dragStateRef.current;
|
|
168
|
+
if (!state || state.pointerId !== event.pointerId) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
// Dragging DOWN (increasing Y) collapses/dismisses. Only allow drag in
|
|
172
|
+
// the closing direction past the fully-open position (no overscroll).
|
|
173
|
+
const delta = event.clientY - state.startCoord;
|
|
174
|
+
const dt = event.timeStamp - state.lastTime;
|
|
175
|
+
if (dt > 0) {
|
|
176
|
+
state.velocity = (event.clientY - state.lastCoord) / dt;
|
|
177
|
+
state.lastCoord = event.clientY;
|
|
178
|
+
state.lastTime = event.timeStamp;
|
|
179
|
+
}
|
|
180
|
+
setDragOffset(Math.max(0, delta));
|
|
181
|
+
}, []);
|
|
182
|
+
|
|
183
|
+
const endDrag = useCallback(
|
|
184
|
+
(event: ReactPointerEvent) => {
|
|
185
|
+
const state = dragStateRef.current;
|
|
186
|
+
if (!state || state.pointerId !== event.pointerId) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
const target = event.currentTarget as HTMLElement;
|
|
190
|
+
target.releasePointerCapture?.(event.pointerId);
|
|
191
|
+
const offset = Math.max(0, event.clientY - state.startCoord);
|
|
192
|
+
dragStateRef.current = null;
|
|
193
|
+
setIsDragging(false);
|
|
194
|
+
settleFromDrag(offset, state.velocity, state.height || 1);
|
|
195
|
+
},
|
|
196
|
+
[settleFromDrag],
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
// Reduced motion skips the settle transition (snaps instantly).
|
|
200
|
+
const reducedMotion = useMemo(prefersReducedMotion, [isOpen]);
|
|
201
|
+
|
|
202
|
+
const contentProps = useMemo<SheetContentProps>(
|
|
203
|
+
() => ({
|
|
204
|
+
style: {
|
|
205
|
+
transform: dragOffset !== 0 ? `translateY(${dragOffset}px)` : undefined,
|
|
206
|
+
transition: isDragging || reducedMotion ? 'none' : undefined,
|
|
207
|
+
touchAction: 'none',
|
|
208
|
+
overscrollBehavior: 'contain',
|
|
209
|
+
},
|
|
210
|
+
}),
|
|
211
|
+
[dragOffset, isDragging, reducedMotion],
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
const handleProps = useMemo<SheetHandleProps>(
|
|
215
|
+
() => ({
|
|
216
|
+
style: {touchAction: 'none', cursor: 'grab'},
|
|
217
|
+
onPointerDown: handlePointerDown,
|
|
218
|
+
onPointerMove: handlePointerMove,
|
|
219
|
+
onPointerUp: endDrag,
|
|
220
|
+
onPointerCancel: endDrag,
|
|
221
|
+
}),
|
|
222
|
+
[handlePointerDown, handlePointerMove, endDrag],
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
return {contentProps, handleProps, dragOffset, isDragging};
|
|
226
|
+
}
|
|
@@ -7,10 +7,57 @@ export const docs = {
|
|
|
7
7
|
displayName: 'Chat Reasoning',
|
|
8
8
|
group: 'Chat',
|
|
9
9
|
category: 'Chat',
|
|
10
|
+
keywords: ['reasoning', 'thinking', 'thought', 'chain-of-thought', 'chat', 'llm', 'ai'],
|
|
10
11
|
|
|
11
12
|
usage: {
|
|
12
|
-
description:
|
|
13
|
+
description:
|
|
14
|
+
'Compact collapsible container for displaying model reasoning or chain-of-thought details. Shows a single-line summary when collapsed and expands to reveal full reasoning text.',
|
|
13
15
|
},
|
|
14
16
|
|
|
15
|
-
props: [
|
|
17
|
+
props: [
|
|
18
|
+
{
|
|
19
|
+
name: 'children',
|
|
20
|
+
type: 'ReactNode',
|
|
21
|
+
description: 'Reasoning content string or custom ReactNode.',
|
|
22
|
+
required: true,
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: 'label',
|
|
26
|
+
type: 'string',
|
|
27
|
+
description: 'Header label displayed in the trigger line.',
|
|
28
|
+
default: "'Thinking'",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: 'duration',
|
|
32
|
+
type: 'string',
|
|
33
|
+
description: 'Duration string shown next to the label (e.g. "12s").',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'isStreaming',
|
|
37
|
+
type: 'boolean',
|
|
38
|
+
description: 'Whether reasoning content is actively streaming. Displays animated shimmer effect.',
|
|
39
|
+
default: 'false',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: 'isExpanded',
|
|
43
|
+
type: 'boolean',
|
|
44
|
+
description: 'Controlled expanded state.',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'defaultIsExpanded',
|
|
48
|
+
type: 'boolean',
|
|
49
|
+
description: 'Default expanded state for uncontrolled usage.',
|
|
50
|
+
default: 'false',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'onExpandedChange',
|
|
54
|
+
type: '(isExpanded: boolean) => void',
|
|
55
|
+
description: 'Callback fired when the expanded state changes.',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: 'xstyle',
|
|
59
|
+
type: 'StyleXStyles',
|
|
60
|
+
description: 'StyleX styles for layout customization.',
|
|
61
|
+
},
|
|
62
|
+
],
|
|
16
63
|
};
|
|
@@ -7,10 +7,75 @@ export const docs = {
|
|
|
7
7
|
displayName: 'Code Editor',
|
|
8
8
|
group: 'CodeEditor',
|
|
9
9
|
category: 'Data Input',
|
|
10
|
+
keywords: ['code', 'editor', 'syntax', 'highlight', 'input', 'textarea'],
|
|
10
11
|
|
|
11
12
|
usage: {
|
|
12
|
-
description:
|
|
13
|
+
description:
|
|
14
|
+
'Editable code component with real-time syntax highlighting using the CSS Custom Highlight API. Supports line numbers, read-only state, placeholder text, and custom tokenizers.',
|
|
13
15
|
},
|
|
14
16
|
|
|
15
|
-
props: [
|
|
17
|
+
props: [
|
|
18
|
+
{
|
|
19
|
+
name: 'value',
|
|
20
|
+
type: 'string',
|
|
21
|
+
description: 'Controlled string value for the editor.',
|
|
22
|
+
required: true,
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: 'onChange',
|
|
26
|
+
type: '(value: string) => void',
|
|
27
|
+
description: 'Callback fired when the code content changes.',
|
|
28
|
+
required: true,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: 'label',
|
|
32
|
+
type: 'string',
|
|
33
|
+
description: 'Accessible label for the editable region (aria-label).',
|
|
34
|
+
required: true,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: 'language',
|
|
38
|
+
type: 'string',
|
|
39
|
+
description: 'Programming language for syntax highlighting.',
|
|
40
|
+
default: "'plaintext'",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'hasLineNumbers',
|
|
44
|
+
type: 'boolean',
|
|
45
|
+
description: 'Display line number gutter on the left.',
|
|
46
|
+
default: 'false',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'isReadOnly',
|
|
50
|
+
type: 'boolean',
|
|
51
|
+
description: 'Renders the editor in a read-only state.',
|
|
52
|
+
default: 'false',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: 'placeholder',
|
|
56
|
+
type: 'string',
|
|
57
|
+
description: 'Placeholder text displayed when value is empty.',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: 'maxHeight',
|
|
61
|
+
type: 'number | string',
|
|
62
|
+
description: 'Maximum container height before internal scrolling.',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'size',
|
|
66
|
+
type: "'sm' | 'md'",
|
|
67
|
+
description: 'Font size variant for the code text.',
|
|
68
|
+
default: "'md'",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: 'tokenizer',
|
|
72
|
+
type: '(code: string, language: string) => TokenLine[]',
|
|
73
|
+
description: 'Custom tokenizer function override for language parsing.',
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: 'xstyle',
|
|
77
|
+
type: 'StyleXStyles',
|
|
78
|
+
description: 'StyleX styles for layout customization.',
|
|
79
|
+
},
|
|
80
|
+
],
|
|
16
81
|
};
|
|
@@ -7,11 +7,62 @@ export const docs = {
|
|
|
7
7
|
displayName: 'Log Stream',
|
|
8
8
|
group: 'LogStream',
|
|
9
9
|
category: 'Content',
|
|
10
|
+
keywords: ['log', 'stream', 'terminal', 'console', 'output', 'logs', 'tail'],
|
|
10
11
|
|
|
11
12
|
usage: {
|
|
12
13
|
description:
|
|
13
|
-
'Experimental streaming log viewer: mono grid rows (timestamp | level | source | message) with token-derived level accents, expandable per-row detail panels, follow-scroll live tailing with a "Jump to latest" affordance, and an always-dark terminal variant. Appended rows fade in via @starting-style
|
|
14
|
+
'Experimental streaming log viewer: mono grid rows (timestamp | level | source | message) with token-derived level accents, expandable per-row detail panels, follow-scroll live tailing with a "Jump to latest" affordance, and an always-dark terminal variant. Appended rows fade in via @starting-style.',
|
|
14
15
|
},
|
|
15
16
|
|
|
16
|
-
props: [
|
|
17
|
+
props: [
|
|
18
|
+
{
|
|
19
|
+
name: 'entries',
|
|
20
|
+
type: 'LogEntry[]',
|
|
21
|
+
description: 'Array of log entry objects to render.',
|
|
22
|
+
required: true,
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: 'variant',
|
|
26
|
+
type: "'default' | 'terminal'",
|
|
27
|
+
description: "Visual variant style: 'default' uses theme surface background, 'terminal' uses fixed dark background.",
|
|
28
|
+
default: "'default'",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: 'isFollowing',
|
|
32
|
+
type: 'boolean',
|
|
33
|
+
description: 'Controlled follow-pinning state to auto-scroll to the newest entry.',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'onFollowChange',
|
|
37
|
+
type: '(following: boolean) => void',
|
|
38
|
+
description: 'Callback fired when follow-pinning state changes.',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: 'maxHeight',
|
|
42
|
+
type: 'number | string',
|
|
43
|
+
description: 'Maximum container height before vertical scrolling.',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: 'hasTimestamps',
|
|
47
|
+
type: 'boolean',
|
|
48
|
+
description: 'Show or hide the timestamp column.',
|
|
49
|
+
default: 'true',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'label',
|
|
53
|
+
type: 'string',
|
|
54
|
+
description: 'Accessible label for the log region.',
|
|
55
|
+
default: "'Log stream'",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: 'renderEntry',
|
|
59
|
+
type: '(entry: LogEntry) => ReactNode',
|
|
60
|
+
description: 'Custom render function for replacing individual row layout.',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: 'xstyle',
|
|
64
|
+
type: 'StyleXStyles',
|
|
65
|
+
description: 'StyleX styles for layout customization.',
|
|
66
|
+
},
|
|
67
|
+
],
|
|
17
68
|
};
|
|
@@ -93,15 +93,28 @@ export const docs = {
|
|
|
93
93
|
name: 'hasMarkdownShortcuts',
|
|
94
94
|
type: 'boolean',
|
|
95
95
|
description:
|
|
96
|
-
'Enable Markdown shortcut typing (e.g. "# " for a heading). Uses
|
|
96
|
+
'Enable Markdown shortcut typing (e.g. "# " for a heading). Uses the transformers prop (defaults to the standard @lexical/markdown transformers).',
|
|
97
97
|
default: 'true',
|
|
98
98
|
},
|
|
99
|
+
{
|
|
100
|
+
name: 'transformers',
|
|
101
|
+
type: 'ReadonlyArray<Transformer>',
|
|
102
|
+
description:
|
|
103
|
+
'Markdown transformers: the single source of truth for markdown behaviour. Defaults to the standard @lexical/markdown TRANSFORMERS. In Lexical the same array drives all three markdown operations (shortcut typing, markdown->state import, state->markdown export); this prop wires shortcut typing today and is the intended input for the serialization APIs added in later phases. Pass a custom array to support additional node types (e.g. transformers layered in via the nodes extension point) consistently across all three. Shortcut typing is only applied when hasMarkdownShortcuts is true.',
|
|
104
|
+
default: 'TRANSFORMERS',
|
|
105
|
+
},
|
|
99
106
|
{
|
|
100
107
|
name: 'hasAutoFocus',
|
|
101
108
|
type: 'boolean',
|
|
102
109
|
description: 'Automatically focus the editor on mount.',
|
|
103
110
|
default: 'false',
|
|
104
111
|
},
|
|
112
|
+
{
|
|
113
|
+
name: 'maxLength',
|
|
114
|
+
type: 'number',
|
|
115
|
+
description:
|
|
116
|
+
'Maximum number of characters. When set, a character counter (current/max) is displayed below the editor. Like TextArea, does not enforce the limit natively; the counter shows error styling when the plain-text length exceeds the limit.',
|
|
117
|
+
},
|
|
105
118
|
{
|
|
106
119
|
name: 'width',
|
|
107
120
|
type: 'number | string',
|
|
@@ -137,6 +150,11 @@ export const docs = {
|
|
|
137
150
|
description:
|
|
138
151
|
'Register custom node types via the nodes prop on BOTH the editor and the RichTextView so serialized content round-trips.',
|
|
139
152
|
},
|
|
153
|
+
{
|
|
154
|
+
guidance: true,
|
|
155
|
+
description:
|
|
156
|
+
'Use a ref (RichTextEditorRef) to imperatively focus(), clear(), read the state via getEditorState(), serialize to Markdown via getMarkdown(), or reach the LexicalEditor via getEditor(). The handle is available after mount. getMarkdown() uses the same transformers prop the editor is configured with. focus() and clear() are no-ops when the editor is read-only or disabled, and clear() resets to a single empty paragraph.',
|
|
157
|
+
},
|
|
140
158
|
{
|
|
141
159
|
guidance: false,
|
|
142
160
|
description:
|