UNPKG

unified-doc-util-mark

Version:
291 lines (266 loc) 7.05 kB
# unified-doc-util-mark [**unified-doc**][unified-doc] [hast][] utility to mark text nodes. --- ## Install ```sh npm install unified-doc-util-mark ``` ## Use Given a `hast` tree parsed from some HTML content: ```js import mark from 'unified-doc-util-mark'; // html: '<blockquote><strong>some</strong>\ncontent</blockquote>'; const hast = { type: 'root', children: [ { type: 'element', tagName: 'blockquote', children: [ { type: 'element', tagName: 'strong', children: [ { type: 'text', value: 'some', }, ], }, { type: 'text', value: '\ncontent', }, ], }, ], }; const marks = [ { id: 'a', start: 1, end: 4, classNames: ['a', 'b'] }, ]; expect(mark(hast, marks)).toEqual({ type: 'root', children: [ { type: 'element', tagName: 'blockquote', children: [ { type: 'element', tagName: 'strong', children: [ { type: 'text', value: 's', }, { type: 'element', tagName: 'mark', properties: { dataMarkId: 'a', id: 'a', classNames: ['a', 'b'], }, children: [ { type: 'text', value: 'ome', }, ], }, ], }, { type: 'text', value: '\ncontent', }, ], }, ], }); ``` ## API ### `mark(hast, marks)` #### Interface ```ts function mark(hast: Hast, marks: Mark[]): Hast ``` Accepts a `hast` tree and applies `marks` to overlapping text nodes. Returns a new tree. `mark` also supports overlapping `marks`, and applying custom properties to marked nodes (`classNames`, `style`, `dataset`). ```js const marks = [ { id: 'a', start: 3, end: 8, classNames: ['a', 'b'], dataset: { category: 'A' } }, { id: 'b', start: 6, end: 10, style: { background: 'red' } }, ]; expect(mark(hast, marks)).toEqual({ type: 'root', children: [ { type: 'element', tagName: 'blockquote', children: [ { type: 'element', tagName: 'strong', children: [ { type: 'text', value: 'som', }, { type: 'element', tagName: 'mark', properties: { id: 'a', classNames: ['a', 'b'], dataMarkId: 'a', dataCategory: 'A', }, children: { type: 'text', value: 'e', }, }, ], }, { type: 'element', tagName: 'mark', properties: { classNames: ['a', 'b'], dataMarkId: 'a', dataCategory: 'A', }, children: [ { type: 'text', value: '\nc', }, { type: 'element', tagName: 'mark', properties: { id: 'b', dataMarkId: 'b', style: 'background: red', }, children: [ { type: 'text', value: 'on', }, ], }, ], type: 'text', value: '\ncontent', }, { type: 'element', tagName: 'mark', properties: { dataMarkId: 'b', style: 'background: red; color white', }, children: [ { type: 'text', value: 'te', }, ], { type: 'text', value: 'nt', }, }, ], }, ], }); ``` #### Related interfaces ```ts interface Mark { /** unique ID for mark (required for mark algorithm to work) */ id: string; /** start offset of the mark relative to `textContent` of the `hast` */ start: number; /** end offset of the mark relative to `textContent` of the `hast` */ end: number; /** apply optional CSS classnames to marked nodes */ classNames?: string[]; /** apply optional dataset attributes (i.e. `data-*`) to marked nodes */ dataset?: Record<string, any>; /** contextual data can be stored here */ data?: Record<string, any>; /** apply optional styles to marked nodes */ style?: Record<string, any>; } ``` A `Mark` is an object that contains at least the `id`, `start` and `end` properties, which provides positional information on segments of text nodes that can be marked. Marks are useful in various document features: - highlight/mark segments of text (e.g. search results). - serve as positional anchors to identify segments of text in a document. `mark` nodes can be visually customized by specifying the optional `classNames`, `style` and `dataset` properties. All other data maybe organized under the `data` property. The `start` and `end` properties of a `Mark` indicate text offset values relative to the `textContent` of the provided `hast` tree. The mark algorithm uses these offsets to determine how to insert `mark` nodes in the tree only within the specified offset range, while preserving the semantic structure of the tree. The following pseudocode helps visualize this behavior: ```js const html = '<blockquote><strong>some</strong>\ncontent</blockquote>'jj const textContent = 'some\ncontent'; const textNodes = ['some', '\ncontent']; const textOffsets = [ { start: 0, end: 4 }, // "[some]\ncontent" { start: 4, end: 12 }, // "some[\ncontent]" ]; const marks = [ { id: 'a', classNames: ['a', 'b'], start: 3, end: 8 }, { id: 'b', style: { background: 'red' }, start: 6, end: 10 }, ]; const markedTextSegments = [ { value: 'som', // "[som]e" text node textOffset: { start: 0, end: 3}, markIds: [], // not marked }, { value: 'e', // "som[e]" text node textOffset: { start: 3, end: 4}, markIds: ['a'], // marked by 'a' }, { value: '\nc', // "[\nc]ontent" text node textOffset: { start: 4, end: 6}, markIds: ['a'], // marked by 'a' }, { value: 'on', // "\nc[on]tent" text node textOffset: { start: 6, end: 8}, markIds: ['a', 'b'], // marked by 'a' + 'b' }, { value: 'te', // "\ncon[te]nt" text node textOffset: { start: 8, end: 10}, markIds: ['b'], // marked by 'b' }, { value: 'nt', // "\nconte[nt]" text node textOffset: { start: 10, end: 12}, markIds: [], // not marked }, ]; // marked hast tree based on markedTextSegments computed above const marked = mark(hast, marks); ``` <!-- Definitions --> [hast]: https://github.com/syntax-tree/hast [unified-doc]: https://github.com/unified-doc/unified-doc