{"_id":"@akhildesai20/sentencehighlighter","_rev":"2-4222d58b85e8eea456a9dd69be30b3af","name":"@akhildesai20/sentencehighlighter","dist-tags":{"latest":"2.0.1"},"versions":{"2.0.0":{"name":"@akhildesai20/sentencehighlighter","version":"2.0.0","keywords":["sentence","highlight","contenteditable","writing","focus","typewriter","editor","vanilla-js","zero-dependency"],"author":{"url":"https://www.linkedin.com/in/akhildesai20/","name":"AKHIL DESAI","email":"akhil.desai20@gmail.com"},"license":"MIT","_id":"@akhildesai20/sentencehighlighter@2.0.0","maintainers":[{"name":"akhildesai20","email":"akhil.desai20@gmail.com"}],"homepage":"https://github.com/akhildesai20/sentence-highlighter#readme","bugs":{"url":"https://github.com/akhildesai20/sentence-highlighter/issues","email":"akhil.desai20@gmail.com"},"dist":{"shasum":"b3635e5ac8c9e59aecd116c7b68e5dc2a35f061a","tarball":"https://registry.npmjs.org/@akhildesai20/sentencehighlighter/-/sentencehighlighter-2.0.0.tgz","fileCount":6,"integrity":"sha512-6wAkBTf1mE2Rfhn2fp67KgKSA3l2KHLmBv5Z0vbwEafGfkAvUzZ8tit1gsCYd1EBZ/PrTeWf6IOEoMVhBBAPmQ==","signatures":[{"sig":"MEUCIEoFWYCrYaK8puawi3fiaV5fY5xNr1cdrPnjcyh2hs0JAiEAxJj2Bf2sze1SnZ17M5WQGeYe9ngonELatrlnYVGLQ0c=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":64306},"main":"sentence-highlighter.js","types":"sentence-highlighter.d.ts","browser":"sentence-highlighter.min.js","gitHead":"d007a31aae937562c39c16fa52a43b0afd132c47","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"node -e \"const fs=require('fs');const code=fs.readFileSync('sentence-highlighter.js','utf8');const min=code.replace(/\\/\\*[\\s\\S]*?\\*\\//g,'').replace(/\\/\\/[^\\n]*/g,'').replace(/\\s+/g,' ').trim();fs.writeFileSync('sentence-highlighter.min.js',min);\"","prepublishOnly":"npm run build"},"_npmUser":{"name":"akhildesai20","email":"akhil.desai20@gmail.com"},"repository":{"url":"git+https://github.com/akhildesai20/sentence-highlighter.git","type":"git"},"_npmVersion":"10.7.0","description":"A lightweight, zero-dependency JavaScript library for sentence-by-sentence highlighting in contenteditable elements","directories":{},"_nodeVersion":"20.15.1","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/sentencehighlighter_2.0.0_1764160395962_0.4663447169244048","host":"s3://npm-registry-packages-npm-production"}},"2.0.1":{"name":"@akhildesai20/sentencehighlighter","version":"2.0.1","description":"A lightweight, zero-dependency JavaScript library for sentence-by-sentence highlighting in contenteditable elements","main":"sentence-highlighter.js","browser":"sentence-highlighter.min.js","types":"sentence-highlighter.d.ts","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"node -e \"const fs=require('fs');const code=fs.readFileSync('sentence-highlighter.js','utf8');const min=code.replace(/\\/\\*[\\s\\S]*?\\*\\//g,'').replace(/\\/\\/[^\\n]*/g,'').replace(/\\s+/g,' ').trim();fs.writeFileSync('sentence-highlighter.min.js',min);\"","prepublishOnly":"npm run build"},"keywords":["sentence","highlight","contenteditable","writing","focus","typewriter","editor","vanilla-js","zero-dependency"],"author":{"name":"AKHIL DESAI","email":"akhil.desai20@gmail.com","url":"https://www.linkedin.com/in/akhildesai20/"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/akhildesai20/sentence-highlighter.git"},"bugs":{"url":"https://github.com/akhildesai20/sentence-highlighter/issues","email":"akhil.desai20@gmail.com"},"homepage":"https://github.com/akhildesai20/sentence-highlighter#readme","_id":"@akhildesai20/sentencehighlighter@2.0.1","gitHead":"74b9b7fcb24bf0006b8194e2c18bbdeb66535a2c","_nodeVersion":"20.15.1","_npmVersion":"10.7.0","dist":{"integrity":"sha512-bs7RQNIMWWQTokY28BnhWmel9caMwP/MAyhKplrfK163m946jhk1+w3jDg8PF/o8ufXdC50T5KSwyPU5fHu6PA==","shasum":"8ac8945899d667c9e13c54dbc1dbc5a111075a05","tarball":"https://registry.npmjs.org/@akhildesai20/sentencehighlighter/-/sentencehighlighter-2.0.1.tgz","fileCount":6,"unpackedSize":71389,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCOOOAoV8o0QDPzcBouUKwAKspM/Puumd+iPTDcbVKb7gIhANtQ8g1HGX4F4dcxqAwIAt+A25flbVXyZjlLL9pFR+LS"}]},"_npmUser":{"name":"akhildesai20","email":"akhil.desai20@gmail.com"},"directories":{},"maintainers":[{"name":"akhildesai20","email":"akhil.desai20@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sentencehighlighter_2.0.1_1764162122479_0.9734206250462207"},"_hasShrinkwrap":false}},"time":{"created":"2025-11-26T12:33:15.861Z","modified":"2025-11-26T13:02:02.882Z","2.0.0":"2025-11-26T12:33:16.162Z","2.0.1":"2025-11-26T13:02:02.691Z"},"bugs":{"url":"https://github.com/akhildesai20/sentence-highlighter/issues","email":"akhil.desai20@gmail.com"},"author":{"name":"AKHIL DESAI","email":"akhil.desai20@gmail.com","url":"https://www.linkedin.com/in/akhildesai20/"},"license":"MIT","homepage":"https://github.com/akhildesai20/sentence-highlighter#readme","keywords":["sentence","highlight","contenteditable","writing","focus","typewriter","editor","vanilla-js","zero-dependency"],"repository":{"type":"git","url":"git+https://github.com/akhildesai20/sentence-highlighter.git"},"description":"A lightweight, zero-dependency JavaScript library for sentence-by-sentence highlighting in contenteditable elements","maintainers":[{"name":"akhildesai20","email":"akhil.desai20@gmail.com"}],"readme":"# Sentence Highlighter\n\n![Version](https://img.shields.io/badge/version-2.0.1-blue.svg)\n![License](https://img.shields.io/badge/license-MIT-green.svg)\n![Size](https://img.shields.io/badge/size-11KB%20minified-lightgrey.svg)\n![Zero Dependencies](https://img.shields.io/badge/dependencies-0-brightgreen.svg)\n[![npm](https://img.shields.io/npm/v/@akhildesai20/sentencehighlighter.svg)](https://www.npmjs.com/package/@akhildesai20/sentencehighlighter)\n[![npm downloads](https://img.shields.io/npm/dm/@akhildesai20/sentencehighlighter.svg)](https://www.npmjs.com/package/@akhildesai20/sentencehighlighter)\n\nA lightweight, zero-dependency JavaScript library for highlighting sentences one at a time as you type. Perfect for distraction-free writing tools, focus apps, and typewriter-style editors.\n\n**Created by:** [AKHIL DESAI](https://www.linkedin.com/in/akhildesai20/)  \n**Email:** akhil.desai20@gmail.com  \n**LinkedIn:** [@akhildesai20](https://www.linkedin.com/in/akhildesai20/)\n\n## Features\n\n- 🎯 **Sentence-by-sentence highlighting** - Automatically highlights the sentence containing your cursor\n- 🎨 **Focus mode** - Dims non-active sentences for better focus\n- 📝 **Heading support** - Recognizes headings (H1-H3) as complete sentences\n- ⚡ **Lightweight** - No dependencies, ~8KB minified\n- 🔧 **Highly configurable** - Customizable classes, behavior, and callbacks\n- 📱 **Works everywhere** - Works with any `contenteditable` element\n- 🚀 **Performance optimized** - Uses virtual sentence model, CSS-based highlighting, and incremental updates\n\n## 🚀 Quick Start\n\n**Try it live:** [View Demo](https://akhildesai20.github.io/sentence-highlighter/example-usage.html)\n\n## Installation\n\n### Option 1: Download and Include\n\nDownload `sentence-highlighter.js` and include it in your HTML:\n\n```html\n<script src=\"sentence-highlighter.js\"></script>\n```\n\n### Option 2: CDN (via npm/unpkg)\n\n```html\n<script src=\"https://unpkg.com/@akhildesai20/sentencehighlighter@latest/sentence-highlighter.min.js\"></script>\n```\n\nOr via jsDelivr:\n```html\n<script src=\"https://cdn.jsdelivr.net/npm/@akhildesai20/sentencehighlighter@latest/sentence-highlighter.min.js\"></script>\n```\n\nOr via GitHub:\n```html\n<script src=\"https://cdn.jsdelivr.net/gh/akhildesai20/sentence-highlighter@main/sentence-highlighter.min.js\"></script>\n```\n\n### Option 3: npm\n\n```bash\nnpm install @akhildesai20/sentencehighlighter\n```\n\n```javascript\n// ES6 modules\nimport SentenceHighlighter from '@akhildesai20/sentencehighlighter';\n\n// CommonJS\nconst SentenceHighlighter = require('@akhildesai20/sentencehighlighter');\n```\n\n**TypeScript support included!** The package includes TypeScript definitions.\n\n## Quick Start\n\n### Basic Usage\n\n```html\n<!DOCTYPE html>\n<html>\n<head>\n  <style>\n    #editor {\n      width: 100%;\n      min-height: 300px;\n      padding: 20px;\n      border: 1px solid #ddd;\n      font-size: 18px;\n      line-height: 1.7;\n    }\n  </style>\n</head>\n<body>\n  <div id=\"editor\" contenteditable=\"true\">\n    Start typing here. Each sentence will be highlighted as you write.\n  </div>\n\n  <script src=\"sentence-highlighter.js\"></script>\n  <script>\n    const editor = document.getElementById('editor');\n    const highlighter = new SentenceHighlighter(editor);\n  </script>\n</body>\n</html>\n```\n\nThat's it! The library will automatically:\n- Detect sentences as you type\n- Highlight the sentence containing your cursor\n- Dim other sentences (focus mode)\n\n## API Reference\n\n### Constructor\n\n```javascript\nconst highlighter = new SentenceHighlighter(editorElement, options);\n```\n\n**Parameters:**\n- `editorElement` (HTMLElement, required) - The contenteditable element to attach to\n- `options` (Object, optional) - Configuration options\n\n### Options\n\n```javascript\n{\n  // CSS Classes\n  sentenceClass: 'sentence',                    // Class for all sentences\n  activeSentenceClass: 'sentence--active',      // Class for active sentence\n  containerClass: 'paragraph',                  // Class for container div\n  \n  // Data Attributes (for CSS targeting)\n  sentenceDataAttribute: 'data-sentence-id',    // Data attribute on sentence spans\n  activeSentenceDataAttribute: 'data-sentence-active', // Data attribute on active sentence\n\n  // Behavior\n  enableFocusMode: true,                        // Enable focus mode (dim non-active)\n  focusModeDimOpacity: 0.18,                   // Opacity for dimmed sentences\n  autoScroll: true,                             // Auto-scroll to keep caret centered\n  scrollBehavior: 'smooth',                     // 'smooth' or 'auto'\n\n  // Sentence Detection\n  headingTags: ['h1', 'h2', 'h3'],             // Tags treated as complete sentences (currently not used)\n  sentenceEndings: ['.', '!', '?'],            // Characters that end sentences\n\n  // Performance\n  updateDebounce: 100,                          // Debounce time in ms for input events\n  updateThrottle: 50,                           // Throttle time in ms for navigation events\n\n  // Callbacks\n  onSentenceChange: (sentences) => {},         // Called when sentences change\n  onActiveSentenceChange: (index, sentence) => {} // Called when active sentence changes\n}\n```\n\n### Methods\n\n#### `update()`\nManually trigger an update of sentence highlighting.\n\n```javascript\nhighlighter.update();\n```\n\n#### `setFocusMode(enabled)`\nEnable or disable focus mode.\n\n```javascript\nhighlighter.setFocusMode(true);  // Enable\nhighlighter.setFocusMode(false); // Disable\n```\n\n#### `toggleFocusMode()`\nToggle focus mode on/off.\n\n```javascript\nhighlighter.toggleFocusMode();\n```\n\n#### `getSentences()`\nGet array of all detected sentences.\n\n```javascript\nconst sentences = highlighter.getSentences();\n// Returns: [{ text: \"...\", start: 0, end: 15, isHeading: false }, ...]\n```\n\n#### `getActiveSentence()`\nGet the currently active sentence object.\n\n```javascript\nconst active = highlighter.getActiveSentence();\n// Returns: { text: \"...\", start: 0, end: 15, isHeading: false } or null\n```\n\n#### `getActiveSentenceIndex()`\nGet the index of the currently active sentence.\n\n```javascript\nconst index = highlighter.getActiveSentenceIndex();\n// Returns: 0, 1, 2, ... or -1\n```\n\n#### `destroy()`\nDestroy the instance and clean up event listeners.\n\n```javascript\nhighlighter.destroy();\n```\n\n## Examples\n\n### Custom Styling\n\n```html\n<style>\n  #editor {\n    max-width: 800px;\n    margin: 0 auto;\n    font-size: 18px;\n    line-height: 1.8;\n  }\n\n  .sentence {\n    opacity: 0.2;\n    transition: opacity 0.3s ease;\n  }\n\n  .sentence--active {\n    opacity: 1;\n    background: rgba(255, 255, 0, 0.1);\n  }\n</style>\n\n<script>\n  const highlighter = new SentenceHighlighter(\n    document.getElementById('editor'),\n    {\n      focusModeDimOpacity: 0.2\n    }\n  );\n</script>\n```\n\n### With Toggle Button\n\n```html\n<button id=\"toggle-focus\">Toggle Focus Mode</button>\n<div id=\"editor\" contenteditable=\"true\"></div>\n\n<script>\n  const editor = document.getElementById('editor');\n  const toggleBtn = document.getElementById('toggle-focus');\n  \n  const highlighter = new SentenceHighlighter(editor);\n  \n  toggleBtn.addEventListener('click', () => {\n    highlighter.toggleFocusMode();\n  });\n</script>\n```\n\n### With Callbacks\n\n```javascript\nconst highlighter = new SentenceHighlighter(editor, {\n  onSentenceChange: (sentences) => {\n    console.log(`Total sentences: ${sentences.length}`);\n  },\n  \n  onActiveSentenceChange: (index, sentence) => {\n    if (sentence) {\n      console.log(`Active: \"${sentence.text}\"`);\n      console.log(`Position: ${index + 1} of ${highlighter.getSentences().length}`);\n    }\n  }\n});\n```\n\n### Custom Sentence Detection\n\n```javascript\nconst highlighter = new SentenceHighlighter(editor, {\n  // Include H4-H6 as headings\n  headingTags: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],\n  \n  // Custom sentence endings (include semicolons)\n  sentenceEndings: ['.', '!', '?', ';'],\n  \n  // Faster updates\n  updateDebounce: 50\n});\n```\n\n### Multiple Instances\n\n```javascript\n// Each editor can have its own highlighter instance\nconst editor1 = new SentenceHighlighter(document.getElementById('editor1'));\nconst editor2 = new SentenceHighlighter(document.getElementById('editor2'), {\n  enableFocusMode: false\n});\n```\n\n## Customization\n\n### CSS Classes\n\nThe library adds these classes and data attributes that you can style:\n\n- `.sentence` - All sentence elements\n- `.sentence--active` - Currently active sentence\n- `.paragraph` - Container div for sentences (configurable via `containerClass`)\n- `.sentence-highlighter-heading` - Sentence that is a heading (if heading detection is enabled)\n- `.sentence-highlighter-focus-off` - Added to editor when focus mode is disabled\n- `[data-sentence-id]` - Data attribute on all sentence spans (configurable via `sentenceDataAttribute`)\n- `[data-sentence-active]` - Data attribute on active sentence (configurable via `activeSentenceDataAttribute`)\n\n### Example CSS\n\n```css\n/* Default dimmed sentences */\n.sentence {\n  opacity: 0.18;\n  transition: opacity 0.2s ease;\n}\n\n/* Active sentence */\n.sentence--active {\n  opacity: 1;\n  font-weight: 500;\n}\n\n/* When focus mode is off, all sentences visible */\n.sentence-highlighter-focus-off .sentence {\n  opacity: 1;\n}\n\n/* Heading sentences */\n.sentence.sentence-highlighter-heading {\n  font-weight: 600;\n}\n```\n\n## Browser Support\n\n- Chrome/Edge (latest)\n- Firefox (latest)\n- Safari (latest)\n- Opera (latest)\n\nRequires ES6+ support (modern browsers).\n\n## License\n\nMIT License - feel free to use in any project.\n\n## Author\n\n**AKHIL DESAI**\n\n- 📧 Email: [akhil.desai20@gmail.com](mailto:akhil.desai20@gmail.com)\n- 💼 LinkedIn: [@akhildesai20](https://www.linkedin.com/in/akhildesai20/)\n\n## Contributing\n\nContributions welcome! Please open an issue or submit a pull request.\n\nFor questions or suggestions, you can reach out directly:\n- **Email:** [akhil.desai20@gmail.com](mailto:akhil.desai20@gmail.com)\n- **LinkedIn:** [@akhildesai20](https://www.linkedin.com/in/akhildesai20/)\n\n## Architecture\n\nThis library uses a **hybrid approach** for optimal performance:\n\n1. **Virtual Sentence Model** - Sentences are maintained as a data structure (Map), separate from DOM rendering\n2. **Span-based Highlighting** - Wraps sentences in `<span>` elements with classes and data attributes for CSS styling\n3. **Incremental Updates** - Only rebuilds highlights when content actually changes, not on every keystroke\n4. **Event-driven** - Debounced/throttled updates for optimal performance\n\nThis approach ensures:\n- ✅ Better performance (minimal DOM manipulation, smart rebuild detection)\n- ✅ Smooth, flicker-free updates\n- ✅ Easy CSS customization via classes and data attributes\n- ✅ Preserves text content (wraps in spans but doesn't modify formatting)\n\n## Changelog\n\n### v2.0.0\n- **Major refactor** to hybrid approach:\n  - Virtual sentence model (data structure)\n  - Span-based highlighting with classes and data attributes\n  - Incremental updates (only rebuilds when content changes)\n  - Event-driven with debouncing/throttling\n- Better performance and stability\n- Proper initialization and defensive checks\n\n### v1.0.0\n- Initial release\n- Sentence detection and highlighting\n- Focus mode support\n- Heading recognition\n- Auto-scroll to caret\n\n## Roadmap\n\n- [ ] Support for multiple paragraphs\n- [ ] Custom sentence detection rules via regex\n- [ ] Animation effects for sentence transitions\n- [ ] Virtual scrolling for long documents\n- [ ] TypeScript definitions\n- [ ] React/Vue wrapper components\n\n","readmeFilename":"README.md"}