Skip to content

Commit 1cb5b2a

Browse files
committed
Cleaning up the classes and adding docs
1 parent f618b76 commit 1cb5b2a

File tree

5 files changed

+194
-113
lines changed

5 files changed

+194
-113
lines changed

docs/links.md

Lines changed: 93 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,101 @@ val linkUrl = richTextState.selectedLinkUrl
7878

7979
### Link Appearance
8080

81-
You can customize how links appear in the editor:
81+
You can customize how links appear in the editor using the `RichTextConfig`:
8282

8383
```kotlin
84-
richTextState.config.linkColor = Color.Blue
85-
richTextState.config.linkTextDecoration = TextDecoration.Underline
84+
val richTextState = rememberRichTextState()
85+
86+
LaunchedEffect(Unit) {
87+
// Set link color (default is Color.Blue)
88+
richTextState.config.linkColor = Color.Green
89+
90+
// Set link text decoration (default is TextDecoration.Underline)
91+
richTextState.config.linkTextDecoration = TextDecoration.None
92+
93+
// Or combine multiple decorations
94+
richTextState.config.linkTextDecoration = TextDecoration.combine(
95+
listOf(TextDecoration.Underline, TextDecoration.LineThrough)
96+
)
97+
}
98+
```
99+
100+
### Common Link Color Examples
101+
102+
```kotlin
103+
// Material Design colors
104+
richTextState.config.linkColor = Color(0xFF1976D2) // Material Blue
105+
richTextState.config.linkColor = Color(0xFF388E3C) // Material Green
106+
richTextState.config.linkColor = Color(0xFFD32F2F) // Material Red
107+
108+
// Custom brand colors
109+
richTextState.config.linkColor = Color(0xFF1DA1F2) // Twitter Blue
110+
richTextState.config.linkColor = Color(0xFF0077B5) // LinkedIn Blue
111+
richTextState.config.linkColor = Color(0xFF25D366) // WhatsApp Green
112+
113+
// Theme-based colors (in a Composable)
114+
@Composable
115+
fun MyRichTextEditor() {
116+
val richTextState = rememberRichTextState()
117+
118+
LaunchedEffect(Unit) {
119+
// Use theme colors
120+
richTextState.config.linkColor = MaterialTheme.colorScheme.primary
121+
// or
122+
richTextState.config.linkColor = MaterialTheme.colorScheme.secondary
123+
}
124+
125+
RichTextEditor(state = richTextState)
126+
}
127+
```
128+
129+
### Dynamic Link Colors
130+
131+
You can change link colors dynamically based on app state:
132+
133+
```kotlin
134+
@Composable
135+
fun DynamicLinkColorEditor() {
136+
val richTextState = rememberRichTextState()
137+
var isDarkMode by remember { mutableStateOf(false) }
138+
139+
LaunchedEffect(isDarkMode) {
140+
richTextState.config.linkColor = if (isDarkMode) {
141+
Color(0xFF64B5F6) // Light blue for dark mode
142+
} else {
143+
Color(0xFF1976D2) // Dark blue for light mode
144+
}
145+
}
146+
147+
Column {
148+
Switch(
149+
checked = isDarkMode,
150+
onCheckedChange = { isDarkMode = it }
151+
)
152+
153+
RichTextEditor(state = richTextState)
154+
}
155+
}
156+
```
157+
158+
### Complete Link Styling Example
159+
160+
```kotlin
161+
@Composable
162+
fun StyledLinkEditor() {
163+
val richTextState = rememberRichTextState()
164+
165+
LaunchedEffect(Unit) {
166+
// Customize all link properties
167+
richTextState.config.linkColor = Color(0xFF00C851) // Green
168+
richTextState.config.linkTextDecoration = TextDecoration.None // No underline
169+
}
170+
171+
RichTextEditor(
172+
state = richTextState,
173+
placeholder = { Text("Add some text with links...") }
174+
)
175+
}
86176
```
87177

88178
## Handling Link Clicks

sample/common/src/commonMain/kotlin/com/kjcommunities/KJDemoLinkDialog.kt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,31 @@
11
package com.kjcommunities
22

3+
/**
4+
* KJDemoLinkDialog - A modal dialog component for creating and editing hyperlinks in the Rich Text Editor.
5+
*
6+
* This class demonstrates how to build a comprehensive link management interface that handles:
7+
* - Creating new hyperlinks with custom text and URL
8+
* - Editing existing hyperlinks (updating URL or text)
9+
* - Removing existing hyperlinks from selected text
10+
* - Different interaction modes based on text selection state
11+
*
12+
* Key functionality:
13+
* - **New Link Creation**: When no text is selected, allows entering both link text and URL
14+
* - **Link from Selection**: When text is selected, uses selected text and only requires URL input
15+
* - **Edit Existing Link**: When cursor is on existing link, pre-fills current values for editing
16+
* - **Link Removal**: Provides "Remove" button when editing existing links
17+
*
18+
* UI Features:
19+
* - Dark theme styling consistent with the demo app
20+
* - Form validation (requires both text and URL for new links, URL for existing)
21+
* - Proper keyboard navigation and accessibility
22+
* - Cancel/Save/Remove action buttons
23+
* - Auto-population of fields based on current selection/link state
24+
*
25+
* This serves as a reference implementation for building custom link management dialogs
26+
* that integrate with the RichTextState link functionality.
27+
*/
28+
329
import androidx.compose.foundation.BorderStroke
430
import androidx.compose.foundation.background
531
import androidx.compose.foundation.layout.*

sample/common/src/commonMain/kotlin/com/kjcommunities/KJDemoPanel.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,29 @@
11
package com.kjcommunities
22

3+
/**
4+
* KJDemoPanel - A custom formatting toolbar component for the Rich Text Editor.
5+
*
6+
* This class demonstrates how to create a comprehensive formatting toolbar that provides:
7+
* - Text formatting buttons (Bold, Italic, Underline, Strikethrough)
8+
* - Hyperlink creation and editing functionality
9+
* - List formatting (Unordered/Bulleted and Ordered/Numbered lists)
10+
* - List indentation controls (Increase/Decrease list level)
11+
* - Heading formatting (H1 and H2 with custom icons)
12+
* - Visual separators between button groups
13+
*
14+
* Key features:
15+
* - Uses custom icons for H1, H2, and indent/outdent operations
16+
* - Integrates with RichTextState to reflect current formatting state
17+
* - Shows selected state for active formatting options
18+
* - Handles enabled/disabled states for context-sensitive buttons (like list indentation)
19+
* - Opens link dialog for hyperlink management
20+
*
21+
* The toolbar is optimized for Lexical JSON format compatibility, with non-supported
22+
* features (text alignment, font size, colors) commented out but preserved for reference.
23+
*
24+
* This serves as a reference implementation for building custom rich text editor toolbars.
25+
*/
26+
327
import androidx.compose.foundation.background
428
import androidx.compose.foundation.layout.Arrangement
529
import androidx.compose.foundation.layout.Box

sample/common/src/commonMain/kotlin/com/kjcommunities/KJDemoPanelButton.kt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,32 @@
11
package com.kjcommunities
22

3+
/**
4+
* KJDemoPanelButton - A reusable button component for rich text editor toolbar panels.
5+
*
6+
* This class demonstrates how to create a consistent, accessible toolbar button that:
7+
* - Displays formatting icons with proper visual feedback
8+
* - Shows selected/active state with background highlighting
9+
* - Handles enabled/disabled states for context-sensitive operations
10+
* - Supports custom icon tinting for special cases (like color indicators)
11+
* - Maintains focus behavior to prevent editor focus loss (especially on Desktop)
12+
*
13+
* Key features:
14+
* - **Visual States**: Normal, selected (highlighted background), and disabled states
15+
* - **Accessibility**: Proper role semantics and content descriptions
16+
* - **Focus Management**: Prevents focus stealing from the rich text editor
17+
* - **Consistent Styling**: Rounded corners, proper padding, and hover effects
18+
* - **Flexible Theming**: Supports custom tint colors while maintaining default styling
19+
*
20+
* Design considerations:
21+
* - Uses a subtle background highlight for selected state instead of border changes
22+
* - Implements click handling with proper enabled state management
23+
* - Provides consistent spacing and sizing across all toolbar buttons
24+
* - Includes a desktop-specific focus workaround to maintain editor usability
25+
*
26+
* This serves as a foundational component for building rich text editor toolbars
27+
* with consistent visual design and behavior across different platforms.
28+
*/
29+
330
import androidx.compose.foundation.background
431
import androidx.compose.foundation.clickable
532
import androidx.compose.foundation.layout.Box

sample/common/src/commonMain/kotlin/com/kjcommunities/KJDemoScreen.kt

Lines changed: 24 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
11
package com.kjcommunities
22

3+
/**
4+
* KJDemoScreen - A comprehensive demonstration screen for the Rich Text Editor library.
5+
*
6+
* This class serves as a Slack-like chat interface that demonstrates how to:
7+
* - Configure and use RichTextState with custom styling (green hyperlinks, code spans, list indentation)
8+
* - Implement a rich text editor with a custom toolbar panel
9+
* - Display formatted messages using the RichText component
10+
* - Handle Lexical JSON import/export functionality
11+
* - Copy Lexical JSON data to clipboard for debugging
12+
* - Manage multiple RichTextState instances for chat messages
13+
* - Integrate link dialog functionality for hyperlink creation/editing
14+
*
15+
* The screen includes:
16+
* - Clean top navigation bar with back button
17+
* - Message display area showing formatted rich text content
18+
* - Rich text editor with formatting toolbar at the bottom
19+
* - Send functionality to add messages to the chat
20+
*
21+
* This serves as a clean, production-ready demo interface for the rich text editor library.
22+
*/
23+
324
import androidx.compose.foundation.Image
425
import androidx.compose.foundation.background
526
import androidx.compose.foundation.border
@@ -54,7 +75,7 @@ fun KJDemoScreen(
5475
val openLinkDialog = remember { mutableStateOf(false) }
5576

5677
LaunchedEffect(Unit) {
57-
richTextState.config.linkColor = Color(0xFF1d9bd1)
78+
richTextState.config.linkColor = Color(0xFF00C851) // Green color for links
5879
richTextState.config.linkTextDecoration = TextDecoration.None
5980
richTextState.config.codeSpanColor = Color(0xFFd7882d)
6081
richTextState.config.codeSpanBackgroundColor = Color.Transparent
@@ -82,114 +103,7 @@ fun KJDemoScreen(
82103
}
83104
},
84105
actions = {
85-
// Test icon 0: Run round-trip test
86-
IconButton(
87-
onClick = {
88-
try {
89-
println("🧪 Running Lexical Round-Trip Test...")
90-
val testResult = LexicalRoundTripTest.runTest()
91-
92-
if (testResult.success) {
93-
println("✅ ROUND-TRIP TEST PASSED!")
94-
println("- Text matches: ${testResult.textMatches}")
95-
println("- Demo JSON works: ${testResult.demoJsonWorks}")
96-
println("- Heading styles work: ${testResult.headingStylesWork}")
97-
println("- Original length: ${testResult.originalTextLength}")
98-
println("- Imported length: ${testResult.importedTextLength}")
99-
println("- JSON length: ${testResult.exportedJsonLength}")
100-
} else {
101-
println("❌ ROUND-TRIP TEST FAILED!")
102-
testResult.error?.let { println("Error: $it") }
103-
println("- Text matches: ${testResult.textMatches}")
104-
println("- Demo JSON works: ${testResult.demoJsonWorks}")
105-
println("- Heading styles work: ${testResult.headingStylesWork}")
106-
}
107-
108-
println("Details: ${testResult.details}")
109-
} catch (e: Exception) {
110-
println("🧪 ❌ ERROR in round-trip test: ${e.message}")
111-
e.printStackTrace()
112-
}
113-
}
114-
) {
115-
Icon(
116-
imageVector = Icons.Outlined.PlayArrow,
117-
contentDescription = "Run Round-Trip Test",
118-
tint = Color.Green
119-
)
120-
}
121-
122-
// Test icon 1: Load minified JSON from resource file
123-
IconButton(
124-
onClick = {
125-
try {
126-
val minifiedJson = LexicalTestData.getMinifiedTestJson()
127-
128-
println("🔥 JSON Length: ${minifiedJson.length}")
129-
println("🔥 Creating new RichTextState...")
130-
131-
// Create a new RichTextState and load the JSON
132-
val testMessage = RichTextState()
133-
println("🔥 Calling setLexicalText...")
134-
testMessage.setLexicalText(minifiedJson)
135-
136-
println("🔥 setLexicalText completed. Message text length: ${testMessage.annotatedString.text.length}")
137-
println("🔥 Message text: ${testMessage.annotatedString.text.take(100)}...")
138-
139-
// Add it to the messages
140-
println("🔥 Current messages list size: ${messages.size}")
141-
messages.add(testMessage)
142-
println("🔥 Messages list size after add: ${messages.size}")
143-
144-
println("🔥 ✅ MINIFIED JSON TEST COMPLETED SUCCESSFULLY")
145-
} catch (e: Exception) {
146-
println("🔥 ❌ ERROR in minified JSON test: ${e.message}")
147-
e.printStackTrace()
148-
}
149-
}
150-
) {
151-
Icon(
152-
imageVector = Icons.Outlined.PlayArrow,
153-
contentDescription = "Load Minified JSON Test",
154-
tint = Color.White
155-
)
156-
}
157-
158-
// Test icon 2: Load pretty-printed JSON from resource file
159-
IconButton(
160-
onClick = {
161-
try {
162-
val prettyJson = LexicalTestData.getPrettyTestJson()
163-
164-
println("🌟 Pretty JSON Length: ${prettyJson.length}")
165-
println("🌟 Creating new RichTextState...")
166-
167-
// Create a new RichTextState and load the JSON
168-
val testMessage = RichTextState()
169-
println("🌟 Calling setLexicalText...")
170-
testMessage.setLexicalText(prettyJson)
171-
172-
println("🌟 setLexicalText completed. Message text length: ${testMessage.annotatedString.text.length}")
173-
println("🌟 Message text: ${testMessage.annotatedString.text.take(100)}...")
174-
175-
// Add it to the messages
176-
println("🌟 Current messages list size: ${messages.size}")
177-
messages.add(testMessage)
178-
println("🌟 Messages list size after add: ${messages.size}")
179-
180-
println("🌟 ✅ PRETTY JSON TEST COMPLETED SUCCESSFULLY")
181-
} catch (e: Exception) {
182-
println("🌟 ❌ ERROR in pretty JSON test: ${e.message}")
183-
e.printStackTrace()
184-
}
185-
}
186-
) {
187-
Icon(
188-
imageVector = Icons.Outlined.Settings,
189-
contentDescription = "Load Pretty JSON Test",
190-
tint = Color.White
191-
)
192-
}
106+
// Actions removed for cleaner demo interface
193107
},
194108
colors = TopAppBarDefaults.topAppBarColors(
195109
containerColor = Color(0xFF1a1d21),
@@ -265,7 +179,7 @@ fun KJDemoScreen(
265179
clipboardManager.setText(AnnotatedString(lexicalJson))
266180
// TODO: Could add a toast/snackbar here to show success
267181
} catch (e: Exception) {
268-
println("Error copying Lexical JSON: ${e.message}")
182+
e.printStackTrace()
269183
}
270184
},
271185
modifier = Modifier.size(24.dp)

0 commit comments

Comments
 (0)