@salesforcedevs/docs-components 1.17.2 → 1.17.6-hover-edit

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/lwc.config.json CHANGED
@@ -18,6 +18,8 @@
18
18
  "doc/header",
19
19
  "doc/heading",
20
20
  "doc/headingAnchor",
21
+ "doc/markdownEditor",
22
+ "doc/textSelectionSearch",
21
23
  "doc/overview",
22
24
  "doc/phase",
23
25
  "doc/specificationContent",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforcedevs/docs-components",
3
- "version": "1.17.2",
3
+ "version": "1.17.6-hover-edit",
4
4
  "description": "Docs Lightning web components for DSC",
5
5
  "license": "MIT",
6
6
  "main": "index.js",
@@ -25,5 +25,5 @@
25
25
  "@types/lodash.orderby": "4.6.9",
26
26
  "@types/lodash.uniqby": "4.7.9"
27
27
  },
28
- "gitHead": "456b8ad8b3162df223f9809e66a454cb66b4add0"
28
+ "gitHead": "4629fdd9ca18a13480044ad43515b91945d16aad"
29
29
  }
@@ -0,0 +1,225 @@
1
+ .markdown-editor {
2
+ border: 1px solid #e1e5e9;
3
+ border-radius: 4px;
4
+ overflow: hidden;
5
+ background: #fff;
6
+ }
7
+
8
+ /* Editor Toolbar */
9
+ .editor-toolbar {
10
+ display: flex;
11
+ align-items: center;
12
+ justify-content: flex-end;
13
+ gap: 0.5rem;
14
+ padding: 0.75rem 1rem;
15
+ background: #f8f9fa;
16
+ border-bottom: 1px solid #e1e5e9;
17
+ flex-wrap: wrap;
18
+ }
19
+
20
+ .edit-button,
21
+ .cancel-button,
22
+ .save-button {
23
+ min-width: 80px;
24
+ }
25
+
26
+ .status-indicator {
27
+ margin-left: 0.5rem;
28
+ font-size: 0.875rem;
29
+ }
30
+
31
+ .status-saving {
32
+ color: #0176d3;
33
+ }
34
+
35
+ .status-success {
36
+ color: #04844b;
37
+ }
38
+
39
+ .status-error {
40
+ color: #ea001e;
41
+ }
42
+
43
+ /* Content Viewer */
44
+ .content-viewer {
45
+ padding: 1rem;
46
+ }
47
+
48
+ .content-display {
49
+ line-height: 1.6;
50
+ color: #3e3e3c;
51
+ }
52
+
53
+ .content-display h1,
54
+ .content-display h2,
55
+ .content-display h3,
56
+ .content-display h4,
57
+ .content-display h5,
58
+ .content-display h6 {
59
+ margin-top: 1.5rem;
60
+ margin-bottom: 0.5rem;
61
+ color: #181818;
62
+ }
63
+
64
+ .content-display p {
65
+ margin-bottom: 1rem;
66
+ }
67
+
68
+ .content-display ul,
69
+ .content-display ol {
70
+ margin-bottom: 1rem;
71
+ padding-left: 2rem;
72
+ }
73
+
74
+ .content-display code {
75
+ background-color: #f3f2f2;
76
+ padding: 0.125rem 0.25rem;
77
+ border-radius: 0.25rem;
78
+ font-family: Monaco, Menlo, "Ubuntu Mono", monospace;
79
+ font-size: 0.875rem;
80
+ }
81
+
82
+ .content-display pre {
83
+ background-color: #f3f2f2;
84
+ padding: 1rem;
85
+ border-radius: 0.25rem;
86
+ overflow-x: auto;
87
+ margin-bottom: 1rem;
88
+ }
89
+
90
+ .content-display pre code {
91
+ background-color: transparent;
92
+ padding: 0;
93
+ }
94
+
95
+ /* HTML Content Styling */
96
+ .html-content {
97
+ line-height: 1.6;
98
+ color: #3e3e3c;
99
+ }
100
+
101
+ .html-content h1,
102
+ .html-content h2,
103
+ .html-content h3,
104
+ .html-content h4,
105
+ .html-content h5,
106
+ .html-content h6 {
107
+ margin-top: 1.5rem;
108
+ margin-bottom: 0.5rem;
109
+ color: #181818;
110
+ }
111
+
112
+ .html-content p {
113
+ margin-bottom: 1rem;
114
+ }
115
+
116
+ .html-content ul,
117
+ .html-content ol {
118
+ margin-bottom: 1rem;
119
+ padding-left: 2rem;
120
+ }
121
+
122
+ .html-content code {
123
+ background-color: #f3f2f2;
124
+ padding: 0.125rem 0.25rem;
125
+ border-radius: 0.25rem;
126
+ font-family: Monaco, Menlo, "Ubuntu Mono", monospace;
127
+ font-size: 0.875rem;
128
+ }
129
+
130
+ .html-content pre {
131
+ background-color: #f3f2f2;
132
+ padding: 1rem;
133
+ border-radius: 0.25rem;
134
+ overflow-x: auto;
135
+ margin-bottom: 1rem;
136
+ }
137
+
138
+ .html-content pre code {
139
+ background-color: transparent;
140
+ padding: 0;
141
+ }
142
+
143
+ /* No Content Message */
144
+ .no-content {
145
+ color: #706e6b;
146
+ font-style: italic;
147
+ text-align: center;
148
+ padding: 2rem;
149
+ background-color: #f8f9fa;
150
+ border: 1px dashed #e1e5e9;
151
+ border-radius: 4px;
152
+ }
153
+
154
+ /* Editor Wrapper */
155
+ .editor-wrapper {
156
+ position: relative;
157
+ min-height: 300px;
158
+ }
159
+
160
+ .simple-editor {
161
+ width: 100%;
162
+ min-height: 300px;
163
+ padding: 1rem;
164
+ border: none;
165
+ outline: none;
166
+ font-family: Monaco, Menlo, "Ubuntu Mono", monospace;
167
+ font-size: 0.875rem;
168
+ line-height: 1.5;
169
+ resize: vertical;
170
+ background: #fff;
171
+ color: #3e3e3c;
172
+ }
173
+
174
+ .simple-editor:focus {
175
+ outline: none;
176
+ }
177
+
178
+ .simple-editor::placeholder {
179
+ color: #706e6b;
180
+ }
181
+
182
+ /* Loading Overlay */
183
+ .loading-overlay {
184
+ position: absolute;
185
+ top: 0;
186
+ left: 0;
187
+ right: 0;
188
+ bottom: 0;
189
+ background: rgb(255 255 255 / 80%);
190
+ display: flex;
191
+ align-items: center;
192
+ justify-content: center;
193
+ z-index: 1000;
194
+ }
195
+
196
+ /* Responsive Design */
197
+ @media (max-width: 768px) {
198
+ .editor-toolbar {
199
+ flex-wrap: wrap;
200
+ gap: 0.25rem;
201
+ justify-content: flex-end;
202
+ }
203
+
204
+ .status-indicator {
205
+ margin-left: 0.25rem;
206
+ width: auto;
207
+ text-align: right;
208
+ margin-top: 0;
209
+ }
210
+
211
+ .simple-editor {
212
+ min-height: 250px;
213
+ }
214
+
215
+ .content-viewer {
216
+ padding: 0.75rem;
217
+ }
218
+ }
219
+
220
+ /* Empty state */
221
+ .content-display:empty::before {
222
+ content: "No content to display";
223
+ color: #706e6b;
224
+ font-style: italic;
225
+ }
@@ -0,0 +1,80 @@
1
+ <template>
2
+ <div class="markdown-editor">
3
+ <!-- Editor Toolbar -->
4
+ <div class="editor-toolbar">
5
+ <template if:true={showViewer}>
6
+ <dx-button
7
+ onclick={handleEdit}
8
+ variant="tertiary"
9
+ class="edit-button"
10
+ >
11
+ Edit Content
12
+ </dx-button>
13
+ </template>
14
+
15
+ <template if:true={showEditor}>
16
+ <dx-button
17
+ onclick={handleCancel}
18
+ variant="secondary"
19
+ class="cancel-button"
20
+ >
21
+ Cancel
22
+ </dx-button>
23
+
24
+ <dx-button
25
+ onclick={handleSave}
26
+ variant="primary"
27
+ disabled={saveButtonDisabled}
28
+ class="save-button"
29
+ >
30
+ Save
31
+ </dx-button>
32
+
33
+ <div class="status-indicator">
34
+ <span class={statusClass}>{statusMessage}</span>
35
+ </div>
36
+ </template>
37
+ </div>
38
+
39
+ <!-- Content Viewer (Read-only) -->
40
+ <template if:true={showViewer}>
41
+ <div class="content-viewer">
42
+ <div class="content-display">
43
+ <!-- Show HTML content if provided -->
44
+ <template if:true={hasHtmlContent}>
45
+ <div class="html-content" innerhtml={htmlContent}></div>
46
+ </template>
47
+
48
+ <!-- Show message if no HTML content -->
49
+ <template if:false={hasHtmlContent}>
50
+ <div class="no-content">
51
+ No content to display. Click 'Edit Content' to fetch from the backend.
52
+ </div>
53
+ </template>
54
+ </div>
55
+ </div>
56
+ </template>
57
+
58
+ <!-- Simple Editor -->
59
+ <template if:true={showEditor}>
60
+ <div class="editor-wrapper">
61
+ <textarea
62
+ class="simple-editor"
63
+ value={editorContent}
64
+ onchange={handleContentChange}
65
+ placeholder="Content will be loaded from the fetch URL..."
66
+ ></textarea>
67
+ </div>
68
+ </template>
69
+
70
+ <!-- Loading Overlay -->
71
+ <template if:true={isLoading}>
72
+ <div class="loading-overlay">
73
+ <dx-spinner
74
+ size="medium"
75
+ alternative-text="Loading"
76
+ ></dx-spinner>
77
+ </div>
78
+ </template>
79
+ </div>
80
+ </template>
@@ -0,0 +1,148 @@
1
+ import { LightningElement, api, track } from "lwc";
2
+
3
+ export default class MarkdownEditor extends LightningElement {
4
+ @api fetchUrl: string = "";
5
+ @api saveUrl: string = "";
6
+ @api filePath: string = "";
7
+ @api htmlContent: string = "";
8
+
9
+ @track isEditing: boolean = false;
10
+ @track editorContent: string = "";
11
+ @track isLoading: boolean = false;
12
+ @track saveStatus: "idle" | "saving" | "success" | "error" = "idle";
13
+
14
+ // Event Handlers
15
+ async handleEdit() {
16
+ if (!this.fetchUrl) {
17
+ console.error("Fetch URL not configured");
18
+ return;
19
+ }
20
+
21
+ this.isLoading = true;
22
+ this.saveStatus = "idle";
23
+
24
+ try {
25
+ const response = await fetch(this.fetchUrl, {
26
+ method: "GET",
27
+ headers: {
28
+ "Content-Type": "application/json"
29
+ }
30
+ });
31
+
32
+ if (response.ok) {
33
+ const data = await response.json();
34
+ this.editorContent = data.content || data.text || data.body || "";
35
+ this.isEditing = true;
36
+ } else {
37
+ throw new Error(`Failed to fetch content: ${response.status}`);
38
+ }
39
+ } catch (error) {
40
+ console.error("Failed to fetch content:", error);
41
+ this.saveStatus = "error";
42
+ } finally {
43
+ this.isLoading = false;
44
+ }
45
+ }
46
+
47
+ handleCancel() {
48
+ this.isEditing = false;
49
+ this.saveStatus = "idle";
50
+ this.editorContent = "";
51
+ }
52
+
53
+ handleContentChange(event: Event) {
54
+ const target = event.target as HTMLTextAreaElement;
55
+ this.editorContent = target.value;
56
+ }
57
+
58
+ async handleSave() {
59
+ if (!this.saveUrl) {
60
+ console.error("Save URL not configured");
61
+ this.saveStatus = "error";
62
+ return;
63
+ }
64
+
65
+ this.saveStatus = "saving";
66
+ this.isLoading = true;
67
+
68
+ try {
69
+ const response = await fetch(this.saveUrl, {
70
+ method: "POST",
71
+ headers: {
72
+ "Content-Type": "application/json"
73
+ },
74
+ body: JSON.stringify({
75
+ content: this.editorContent,
76
+ filePath: this.filePath
77
+ })
78
+ });
79
+
80
+ if (response.ok) {
81
+ this.saveStatus = "success";
82
+ this.isEditing = false;
83
+ this.editorContent = "";
84
+
85
+ // Dispatch save success event
86
+ this.dispatchEvent(
87
+ new CustomEvent("saved", {
88
+ detail: {
89
+ success: true,
90
+ content: this.editorContent,
91
+ filePath: this.filePath
92
+ }
93
+ })
94
+ );
95
+ } else {
96
+ throw new Error(`Save failed: ${response.status}`);
97
+ }
98
+ } catch (error) {
99
+ console.error("Save failed:", error);
100
+ this.saveStatus = "error";
101
+ } finally {
102
+ this.isLoading = false;
103
+ }
104
+ }
105
+
106
+ // Getters for UI state
107
+ get showEditor() {
108
+ return this.isEditing;
109
+ }
110
+
111
+ get showViewer() {
112
+ return !this.isEditing;
113
+ }
114
+
115
+ get saveButtonDisabled() {
116
+ return this.saveStatus === "saving" || this.isLoading || !this.editorContent.trim();
117
+ }
118
+
119
+ get statusMessage() {
120
+ switch (this.saveStatus) {
121
+ case "saving":
122
+ return "Saving...";
123
+ case "success":
124
+ return "Saved successfully!";
125
+ case "error":
126
+ return "Save failed. Please try again.";
127
+ default:
128
+ return "";
129
+ }
130
+ }
131
+
132
+ get statusClass() {
133
+ switch (this.saveStatus) {
134
+ case "saving":
135
+ return "status-saving";
136
+ case "success":
137
+ return "status-success";
138
+ case "error":
139
+ return "status-error";
140
+ default:
141
+ return "";
142
+ }
143
+ }
144
+
145
+ get hasHtmlContent() {
146
+ return this.htmlContent && this.htmlContent.trim().length > 0;
147
+ }
148
+ }
@@ -0,0 +1,185 @@
1
+ # Text Selection Search Component
2
+
3
+ A Lightning Web Component that detects text selection on the page and shows a search popover for finding related content.
4
+
5
+ ## Features
6
+
7
+ - **Automatic Text Detection**: Detects text selection via mouse and keyboard
8
+ - **Positioned Popover**: Shows search interface near the selected text
9
+ - **Search Functionality**: Makes API calls to backend search endpoints
10
+ - **Modern UI**: Clean, responsive interface with loading states
11
+ - **Keyboard Navigation**: Escape key to close popover
12
+ - **Event Handling**: Dispatches events for search results and clicks
13
+ - **Customizable**: Configurable appearance and behavior
14
+
15
+ ## Usage
16
+
17
+ ### Basic Implementation
18
+
19
+ ```html
20
+ <doc-text-selection-search
21
+ search-api-url="/api/search"
22
+ placeholder="Search for..."
23
+ popover-position="top"
24
+ max-results="10">
25
+ </doc-text-selection-search>
26
+ ```
27
+
28
+ ### With Event Listeners
29
+
30
+ ```html
31
+ <doc-text-selection-search
32
+ search-api-url="/api/search"
33
+ @searchresults="handleSearchResults"
34
+ @resultclick="handleResultClick">
35
+ </doc-text-selection-search>
36
+ ```
37
+
38
+ ```javascript
39
+ handleSearchResults(event) {
40
+ const { query, results, selectedText } = event.detail;
41
+ console.log('Search results:', results);
42
+ }
43
+
44
+ handleResultClick(event) {
45
+ const { result, query, selectedText } = event.detail;
46
+ console.log('Result clicked:', result);
47
+ // Navigate to result or perform action
48
+ }
49
+ ```
50
+
51
+ ## API Reference
52
+
53
+ ### Properties
54
+
55
+ | Property | Type | Default | Description |
56
+ |----------|------|---------|-------------|
57
+ | `searchApiUrl` | string | `""` | The URL endpoint for the search API |
58
+ | `placeholder` | string | `"Search for..."` | Placeholder text for the search input |
59
+ | `popoverPosition` | `"top" \| "bottom"` | `"top"` | Position of popover relative to selected text |
60
+ | `maxResults` | number | `10` | Maximum number of search results to display |
61
+
62
+ ### Events
63
+
64
+ | Event | Detail | Description |
65
+ |-------|--------|-------------|
66
+ | `searchresults` | `{ query, results, selectedText }` | Fired when search results are received |
67
+ | `resultclick` | `{ result, query, selectedText }` | Fired when a search result is clicked |
68
+
69
+ ### Backend API Format
70
+
71
+ The component expects your backend API to:
72
+
73
+ **Request (POST):**
74
+ ```json
75
+ {
76
+ "query": "search term",
77
+ "maxResults": 10,
78
+ "selectedText": "originally selected text"
79
+ }
80
+ ```
81
+
82
+ **Response:**
83
+ ```json
84
+ {
85
+ "results": [
86
+ {
87
+ "title": "Result Title",
88
+ "description": "Result description or snippet",
89
+ "url": "https://example.com/result"
90
+ }
91
+ ]
92
+ }
93
+ ```
94
+
95
+ ## Examples
96
+
97
+ ### Knowledge Base Search
98
+
99
+ ```html
100
+ <doc-text-selection-search
101
+ search-api-url="https://api.example.com/kb/search"
102
+ placeholder="Search knowledge base..."
103
+ popover-position="bottom"
104
+ max-results="15">
105
+ </doc-text-selection-search>
106
+ ```
107
+
108
+ ### Documentation Search
109
+
110
+ ```html
111
+ <doc-text-selection-search
112
+ search-api-url="/api/docs/search"
113
+ placeholder="Search documentation..."
114
+ popover-position="top"
115
+ max-results="8">
116
+ </doc-text-selection-search>
117
+ ```
118
+
119
+ ### Custom Styling
120
+
121
+ You can customize the appearance by overriding CSS classes:
122
+
123
+ ```css
124
+ .text-selection-search-popover {
125
+ /* Custom popover styling */
126
+ border-radius: 12px;
127
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
128
+ }
129
+
130
+ .result-item:hover {
131
+ /* Custom hover effects */
132
+ background: #f0f8ff;
133
+ border-color: #0066cc;
134
+ }
135
+ ```
136
+
137
+ ## Browser Support
138
+
139
+ - Chrome 60+
140
+ - Firefox 55+
141
+ - Safari 12+
142
+ - Edge 79+
143
+
144
+ ## Accessibility
145
+
146
+ - Keyboard navigation support (Escape to close)
147
+ - Screen reader friendly
148
+ - High contrast mode support
149
+ - Focus management
150
+
151
+ ## Performance Considerations
152
+
153
+ - Event listeners are properly cleaned up on component destruction
154
+ - Debounced text selection detection
155
+ - Efficient DOM updates
156
+ - Minimal re-renders
157
+
158
+ ## Troubleshooting
159
+
160
+ ### Common Issues
161
+
162
+ 1. **Popover not appearing**: Ensure text selection is enabled and the component is properly mounted
163
+ 2. **API calls failing**: Check the `searchApiUrl` and ensure CORS is configured
164
+ 3. **Positioning issues**: The popover position calculation may need adjustment for complex layouts
165
+
166
+ ### Debug Mode
167
+
168
+ Enable console logging for debugging:
169
+
170
+ ```javascript
171
+ // Add to your component
172
+ connectedCallback() {
173
+ this.debug = true; // Enable debug logging
174
+ }
175
+ ```
176
+
177
+ ## Contributing
178
+
179
+ When contributing to this component:
180
+
181
+ 1. Follow the existing code style and patterns
182
+ 2. Add appropriate tests for new features
183
+ 3. Update documentation for API changes
184
+ 4. Ensure accessibility compliance
185
+ 5. Test across different browsers and devices