{"id":27010790,"url":"https://github.com/robotdad/semantic-composer","last_synced_at":"2025-04-04T11:27:27.176Z","repository":{"id":285850427,"uuid":"958954203","full_name":"robotdad/semantic-composer","owner":"robotdad","description":"A reusable React-based markdown editor component (Cortex Composer) built with Milkdown that supports both rich text editing and raw markdown modes, with toggleable read/edit modes. The component will be designed for easy integration into various web applications.","archived":false,"fork":false,"pushed_at":"2025-04-03T02:14:04.000Z","size":5390,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-03T02:27:11.066Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/robotdad.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-04-02T03:11:13.000Z","updated_at":"2025-04-03T02:11:42.000Z","dependencies_parsed_at":"2025-04-03T02:27:32.342Z","dependency_job_id":"027200c0-ad64-4dac-a2ef-884d03bb8bc6","html_url":"https://github.com/robotdad/semantic-composer","commit_stats":null,"previous_names":["robotdad/semantic-composer"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robotdad%2Fsemantic-composer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robotdad%2Fsemantic-composer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robotdad%2Fsemantic-composer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robotdad%2Fsemantic-composer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/robotdad","download_url":"https://codeload.github.com/robotdad/semantic-composer/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247168607,"owners_count":20895142,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-04-04T11:27:26.599Z","updated_at":"2025-04-04T11:27:27.169Z","avatar_url":"https://github.com/robotdad.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Semantic Composer\n\nA markdown editor component built with React and Milkdown/Crepe, designed for easy integration into various web applications.\n\n**[🚀 Try it live!](https://robotdad.github.io/semantic-composer)**\n\n## Features\n\n- Toggle between Edit and Read modes\n- Toggle between Rich text and Raw markdown modes\n- Support for all standard markdown features:\n  - Headings\n  - Lists\n  - Code blocks with syntax highlighting\n  - Tables\n  - Links and images\n- Document management with localStorage persistence\n- Export markdown content to file\n- Fluent UI integration\n- Responsive design with different sizing options\n- Various appearance styles\n- Word count display\n- Keyboard shortcuts (Ctrl+S/Cmd+S to save)\n\n## Getting Started\n\n### Installation\n\n```bash\n# Install dependencies\nnpm install\n\n# For Fluent UI integration\nnpm install @fluentui/react-components @fluentui/react-icons\n```\n\n### Running the Demo\n\n```bash\nnpm start\n```\n\n### TypeScript Support\n\nThis project is built with TypeScript, providing:\n- Type definitions for component props, refs, and state\n- Improved editor integration with autocompletion\n- Better error detection at compile time\n- Enhanced developer experience\n\nTypeScript-specific scripts:\n```bash\n# Type checking\nnpm run typecheck\n\n# Linting TypeScript files\nnpm run lint\n```\n\nThe development server will start at http://localhost:3000 where you can see the Semantic Composer component in action.\n\n## Usage\n\n### Basic Usage\n\n```tsx\nimport React, { useRef } from 'react';\nimport { SemanticComposer } from './components';\nimport type { SemanticComposerRef } from './types';\n\nfunction MyApp() {\n  const editorRef = useRef\u003cSemanticComposerRef\u003e(null);\n  \n  const handleChange = (markdown: string) =\u003e {\n    console.log('Markdown updated:', markdown);\n  };\n  \n  const handleSave = (markdown: string, documentId: string) =\u003e {\n    // Save markdown to database or file\n    saveToDatabase(markdown);\n  };\n  \n  const loadExternalContent = (content: string) =\u003e {\n    // Use the component API to load new content\n    if (editorRef.current?.setContent) {\n      editorRef.current.setContent(content);\n    }\n  };\n  \n  return (\n    \u003cdiv className=\"app\"\u003e\n      \u003ch1\u003eMy Markdown Editor\u003c/h1\u003e\n      \u003cbutton onClick={() =\u003e loadExternalContent('# New Content')}\u003e\n        Load Content\n      \u003c/button\u003e\n      \u003cbutton onClick={() =\u003e editorRef.current?.loadDocument('# New Document', 'doc-123')}\u003e\n        Load Document\n      \u003c/button\u003e\n      \u003cSemanticComposer\n        ref={editorRef}\n        initialValue=\"# Welcome to Semantic Composer\"\n        initialDocumentId=\"default\"\n        onChange={handleChange}\n        onSave={handleSave}\n        onError={(error) =\u003e console.error('Editor error:', error)}\n        width=\"100%\"\n        appearance=\"outline\" // or \"underline\", \"filled-darker\", \"filled-lighter\"\n        size=\"medium\" // or \"small\", \"large\"\n        autoSaveInterval={5000} // Set to 0 to disable autosave\n        storageKeyPrefix=\"editor\" // Prefix for localStorage keys\n        useFluentProvider={true} // Wrap with FluentProvider\n      /\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n## Component Props\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| initialValue | string | '' | Initial markdown content |\n| initialDocumentId | string | 'default' | Initial document ID for persistence |\n| defaultMode | 'edit' \\| 'read' | 'edit' | Initial editor mode |\n| defaultView | 'rich' \\| 'raw' | 'rich' | Initial view mode (rich text or raw markdown) |\n| onChange | function | undefined | Callback when content changes |\n| onSave | function | undefined | Callback when save is triggered with (content, documentId) |\n| onError | function | undefined | Callback for error handling |\n| onModeChange | function | undefined | Callback when mode changes |\n| onViewChange | function | undefined | Callback when view changes |\n| width | string \\| number | '100%' | Editor width |\n| appearance | 'outline' \\| 'underline' \\| 'filled-darker' \\| 'filled-lighter' | 'outline' | Visual style of the component |\n| size | 'small' \\| 'medium' \\| 'large' | 'medium' | Size variant of the component |\n| placeholder | string | 'Start writing...' | Placeholder text for empty editor |\n| readOnly | boolean | false | Set editor to read-only mode |\n| autoFocus | boolean | true | Auto-focus on load |\n| spellCheck | boolean | true | Enable spell check |\n| autoSaveInterval | number | 5000 | Auto-save interval in ms (0 to disable) |\n| debug | boolean | false | Enable debug logging |\n| storageKeyPrefix | string | 'editor' | Prefix for localStorage keys |\n| useFluentProvider | boolean | true | Wrap component with FluentProvider |\n| fluentProviderProps | object | {} | Props to pass to FluentProvider |\n\n## Component API\n\nWhen using a ref, the following methods are available:\n\n| Method | Description |\n|--------|-------------|\n| getCurrentContent() | Get the current markdown content and document ID |\n| setContent(markdown, documentId) | Update the editor content with optional document ID |\n| loadDocument(content, documentId) | Load content with a specific document ID |\n| getDocumentId() | Get the current document ID |\n| getCurrentView() | Get current view mode ('rich' or 'raw') |\n| getCurrentMode() | Get current edit mode ('edit' or 'read') |\n| toggleEditorView() | Toggle between rich and raw modes |\n| toggleEditorMode() | Toggle between edit and read modes |\n| reset(options) | Reset the editor with options for clearing content and storage |\n| getCrepeInstance() | Get the underlying Crepe instance |\n| getStorageKey() | Get the current storage key being used |\n\n## Reset Options\n\nThe `reset()` method accepts an options object with the following properties:\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| clearContent | boolean | true | Clear editor content |\n| clearCurrentStorage | boolean | true | Clear current document storage |\n| clearAllStorage | boolean | false | Clear all editor-related storage |\n| resetToDefaultDocument | boolean | false | Reset document ID to default |\n\n## Document Management\n\nThe component maintains document content in localStorage using the following pattern:\n- Each document has a unique ID (defaulting to 'default')\n- Storage keys are created as `${storageKeyPrefix}:${documentId}`\n- The current document ID is tracked in `${storageKeyPrefix}:current-document-id`\n- The `loadDocument()` method provides the easiest way to switch between documents\n\n## Fluent UI Integration\n\n### Dialog Component\n\nThe package includes a `SemanticComposerDialog` component for modal editing experiences:\n\n```tsx\nimport { SemanticComposerDialog } from './components';\n\nfunction MyApp() {\n  const [open, setOpen] = useState(false);\n  \n  return (\n    \u003c\u003e\n      \u003cbutton onClick={() =\u003e setOpen(true)}\u003eEdit Content\u003c/button\u003e\n      \n      \u003cSemanticComposerDialog\n        open={open}\n        onOpenChange={setOpen}\n        title=\"Edit Document\"\n        initialContent=\"# My Document\"\n        appearance=\"filled-lighter\"\n        onSave={(content) =\u003e {\n          console.log('Saved:', content);\n          // Process saved content\n        }}\n      /\u003e\n    \u003c/\u003e\n  );\n}\n```\n\n### Styling Options\n\nThe component comes with multiple appearance options:\n\n- `outline`: Standard bordered style (default)\n- `underline`: Bottom border only\n- `filled-darker`: Darker background fill\n- `filled-lighter`: Lighter background fill\n\nAnd size variants:\n\n- `small`: Compact view with smaller text\n- `medium`: Standard size (default)\n- `large`: Larger text and spacing\n\n### Theming\n\nThe component inherits themes from your Fluent UI theme context. If `useFluentProvider` is true (default), it creates its own FluentProvider. To use your application's theme context, set `useFluentProvider={false}`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobotdad%2Fsemantic-composer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frobotdad%2Fsemantic-composer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobotdad%2Fsemantic-composer/lists"}