11import { memo , useCallback , useEffect , useMemo , useRef } from 'react'
22import ReactMarkdown from 'react-markdown'
33import remarkGfm from 'remark-gfm'
4- import { useUpdateNodeInternals , type NodeProps } from 'reactflow'
4+ import { type NodeProps , useUpdateNodeInternals } from 'reactflow'
55import { cn } from '@/lib/utils'
66import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider'
7+ import { usePanelEditorStore } from '@/stores/panel-new/editor/store'
8+ import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
9+ import { useSubBlockStore } from '@/stores/workflows/subblock/store'
10+ import { useWorkflowStore } from '@/stores/workflows/workflow/store'
711import { useCurrentWorkflow } from '../../hooks'
812import { ActionBar } from '../workflow-block/components'
913import { useBlockState } from '../workflow-block/hooks'
1014import type { WorkflowBlockProps } from '../workflow-block/types'
11- import { usePanelEditorStore } from '@/stores/panel-new/editor/store'
12- import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
13- import { useWorkflowStore } from '@/stores/workflows/workflow/store'
14- import { useSubBlockStore } from '@/stores/workflows/subblock/store'
1515
1616interface NoteBlockNodeData extends WorkflowBlockProps { }
1717
1818const NOTE_MIN_WIDTH = 220
1919const NOTE_MIN_HEIGHT = 140
2020
21- const MarkdownContent = memo ( function MarkdownContent ( { content } : { content : string } ) {
21+ /**
22+ * Extract string value from subblock value object or primitive
23+ */
24+ function extractFieldValue ( rawValue : unknown ) : string | undefined {
25+ if ( typeof rawValue === 'string' ) return rawValue
26+ if ( rawValue && typeof rawValue === 'object' && 'value' in rawValue ) {
27+ const candidate = ( rawValue as { value ?: unknown } ) . value
28+ return typeof candidate === 'string' ? candidate : undefined
29+ }
30+ return undefined
31+ }
32+
33+ /**
34+ * Compact markdown renderer for note blocks with tight spacing
35+ */
36+ const NoteMarkdown = memo ( function NoteMarkdown ( { content } : { content : string } ) {
2237 return (
2338 < ReactMarkdown
2439 remarkPlugins = { [ remarkGfm ] }
2540 components = { {
26- p : ( { children } ) => (
27- < p className = 'mb-2 text-sm leading-relaxed text-[#E5E5E5] last:mb-0' > { children } </ p >
28- ) ,
29- strong : ( { children } ) => < strong className = 'font-semibold text-white' > { children } </ strong > ,
30- em : ( { children } ) => < em className = 'text-[#B8B8B8]' > { children } </ em > ,
31- h1 : ( { children } ) => (
32- < h1 className = 'mt-0 mb-[6px] text-lg font-semibold leading-snug text-[#E5E5E5]' >
33- { children }
34- </ h1 >
35- ) ,
36- h2 : ( { children } ) => (
37- < h2 className = 'mt-0 mb-[4px] text-base font-semibold leading-snug text-[#E5E5E5]' >
38- { children }
39- </ h2 >
40- ) ,
41- h3 : ( { children } ) => (
42- < h3 className = 'mt-0 mb-[4px] text-sm font-semibold leading-snug text-[#E5E5E5]' >
43- { children }
44- </ h3 >
45- ) ,
46- a : ( { href, children } ) => (
47- < a
48- href = { href }
49- target = '_blank'
50- rel = 'noopener noreferrer'
51- className = 'font-medium text-[#33B4FF] underline-offset-2 hover:underline'
52- >
53- { children }
54- </ a >
55- ) ,
56- ul : ( { children } ) => (
57- < ul className = 'mb-2 ml-5 list-disc text-sm leading-relaxed text-[#E5E5E5]' > { children } </ ul >
58- ) ,
59- ol : ( { children } ) => (
60- < ol className = 'mb-2 ml-5 list-decimal text-sm leading-relaxed text-[#E5E5E5]' > { children } </ ol >
61- ) ,
62- li : ( { children } ) => < li className = 'mb-1 last:mb-0' > { children } </ li > ,
41+ p : ( { children } ) => < p className = 'mb-0 text-sm text-[#E5E5E5]' > { children } </ p > ,
42+ h1 : ( { children } ) => < h1 className = 'mt-0 mb-[-2px] text-lg font-semibold text-[#E5E5E5]' > { children } </ h1 > ,
43+ h2 : ( { children } ) => < h2 className = 'mt-0 mb-[-2px] text-base font-semibold text-[#E5E5E5]' > { children } </ h2 > ,
44+ h3 : ( { children } ) => < h3 className = 'mt-0 mb-[-2px] text-sm font-semibold text-[#E5E5E5]' > { children } </ h3 > ,
45+ h4 : ( { children } ) => < h4 className = 'mt-0 mb-[-2px] text-xs font-semibold text-[#E5E5E5]' > { children } </ h4 > ,
46+ ul : ( { children } ) => < ul className = '-mt-[2px] mb-0 list-disc pl-4 text-sm text-[#E5E5E5]' > { children } </ ul > ,
47+ ol : ( { children } ) => < ol className = '-mt-[2px] mb-0 list-decimal pl-4 text-sm text-[#E5E5E5]' > { children } </ ol > ,
48+ li : ( { children } ) => < li className = 'mb-0' > { children } </ li > ,
6349 code : ( { inline, children } : any ) =>
6450 inline ? (
6551 < code className = 'rounded bg-[#393939] px-1 py-0.5 text-xs text-[#F59E0B]' > { children } </ code >
6652 ) : (
6753 < code className = 'block rounded bg-[#1A1A1A] p-2 text-xs text-[#E5E5E5]' > { children } </ code >
6854 ) ,
69- blockquote : ( { children } ) => (
70- < blockquote className = 'mb-3 border-l-2 border -[#F59E0B] pl-3 italic text-[#B8B8B8] '>
55+ a : ( { href , children } ) => (
56+ < a href = { href } target = '_blank' rel = 'noopener noreferrer' className = 'text -[#33B4FF] underline-offset-2 hover:underline '>
7157 { children }
72- </ blockquote >
58+ </ a >
59+ ) ,
60+ strong : ( { children } ) => < strong className = 'font-semibold text-white' > { children } </ strong > ,
61+ em : ( { children } ) => < em className = 'text-[#B8B8B8]' > { children } </ em > ,
62+ blockquote : ( { children } ) => (
63+ < blockquote className = 'm-0 border-l-2 border-[#F59E0B] pl-3 italic text-[#B8B8B8]' > { children } </ blockquote >
7364 ) ,
7465 } }
7566 >
@@ -90,7 +81,11 @@ export const NoteBlock = memo(function NoteBlock({ id, data }: NodeProps<NoteBlo
9081 const isFocused = currentBlockId === id
9182
9283 const currentWorkflow = useCurrentWorkflow ( )
93- const { isEnabled, isActive, diffStatus, isDeletedBlock } = useBlockState ( id , currentWorkflow , data )
84+ const { isEnabled, isActive, diffStatus, isDeletedBlock } = useBlockState (
85+ id ,
86+ currentWorkflow ,
87+ data
88+ )
9489
9590 const activeWorkflowId = useWorkflowRegistry ( ( state ) => state . activeWorkflowId )
9691 const storedValues = useSubBlockStore (
@@ -105,45 +100,25 @@ export const NoteBlock = memo(function NoteBlock({ id, data }: NodeProps<NoteBlo
105100
106101 const noteValues = useMemo ( ( ) => {
107102 if ( data . isPreview && data . subBlockValues ) {
108- const previewFormatState = data . subBlockValues . format
109- const previewContentState = data . subBlockValues . content
110-
111- const extractedPreviewFormat =
112- typeof previewFormatState === 'object' && previewFormatState !== null
113- ? ( previewFormatState as { value ?: unknown } ) . value
114- : previewFormatState
115- const extractedPreviewContent =
116- typeof previewContentState === 'object' && previewContentState !== null
117- ? ( previewContentState as { value ?: unknown } ) . value
118- : previewContentState
119-
103+ const extractedPreviewFormat = extractFieldValue ( data . subBlockValues . format )
104+ const extractedPreviewContent = extractFieldValue ( data . subBlockValues . content )
120105 return {
121106 format : typeof extractedPreviewFormat === 'string' ? extractedPreviewFormat : 'plain' ,
122107 content : typeof extractedPreviewContent === 'string' ? extractedPreviewContent : '' ,
123108 }
124109 }
125110
126- const format =
127- storedValues && typeof storedValues . format === 'string'
128- ? storedValues . format
129- : typeof storedValues ?. format === 'object' && storedValues ?. format !== null
130- ? ( storedValues . format as { value ?: unknown } ) . value
131- : undefined
132- const content =
133- storedValues && typeof storedValues . content === 'string'
134- ? storedValues . content
135- : typeof storedValues ?. content === 'object' && storedValues ?. content !== null
136- ? ( storedValues . content as { value ?: unknown } ) . value
137- : undefined
111+ const format = extractFieldValue ( storedValues ?. format )
112+ const content = extractFieldValue ( storedValues ?. content )
138113
139114 return {
140115 format : typeof format === 'string' ? format : 'plain' ,
141116 content : typeof content === 'string' ? content : '' ,
142117 }
143118 } , [ data . isPreview , data . subBlockValues , storedValues ] )
144119
145- const trimmedContent = noteValues . content ?. trim ( ) ?? ''
146- const isEmpty = trimmedContent . length === 0
120+ const content = noteValues . content ?? ''
121+ const isEmpty = content . trim ( ) . length === 0
147122 const showMarkdown = noteValues . format === 'markdown' && ! isEmpty
148123
149124 const userPermissions = useUserPermissionsContext ( )
@@ -215,14 +190,14 @@ export const NoteBlock = memo(function NoteBlock({ id, data }: NodeProps<NoteBlo
215190 </ div >
216191 </ div >
217192
218- < div className = 'relative px-[12px] py-[10px ]' >
193+ < div className = 'relative px-[12px] pt-[6px] pb-[8px ]' >
219194 < div className = 'relative whitespace-pre-wrap break-words' >
220195 { isEmpty ? (
221- < p className = 'text-sm italic text- [#868686]' > Add your note...</ p >
196+ < p className = 'text-[#868686] text-sm italic ' > Add a note...</ p >
222197 ) : showMarkdown ? (
223- < MarkdownContent content = { trimmedContent } />
198+ < NoteMarkdown content = { content } />
224199 ) : (
225- < p className = 'text-sm leading-relaxed text-[#E5E5E5]' > { trimmedContent } </ p >
200+ < p className = 'whitespace-pre-wrap text-[#E5E5E5] text-sm leading-relaxed ' > { content } </ p >
226201 ) }
227202 </ div >
228203 </ div >
@@ -235,4 +210,3 @@ export const NoteBlock = memo(function NoteBlock({ id, data }: NodeProps<NoteBlo
235210 </ div >
236211 )
237212} )
238-
0 commit comments