Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@openstax/highlighter",
"version": "1.13.0",
"version": "1.14.1",
"main": "dist/index.js",
"license": "MIT",
"files": [
Expand Down
19 changes: 15 additions & 4 deletions src/Highlight.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import * as uuid from 'uuid/v4';
import dom from './dom';
import { DATA_SCREEN_READERS_ATTR_SELECTOR } from './injectHighlightWrappers';
import { DATA_SCREEN_READERS_ATTR, DATA_SCREEN_READERS_ATTR_SELECTOR } from './injectHighlightWrappers';
import SerializedHighlight from './SerializedHighlight';

export const FOCUS_CSS = 'focus';

export interface IHighlightData {
style?: string;
id: string;
Expand All @@ -14,6 +12,7 @@ export interface IHighlightData {
export interface IOptions {
skipIDsBy?: RegExp;
formatMessage: (descriptor: { id: string }, values: { style: IHighlightData['style'] }) => string;
tabbable?: boolean;
}

export default class Highlight {
Expand Down Expand Up @@ -93,11 +92,23 @@ export default class Highlight {
return this;
}

public updateStartMarker(el: Element, position: string) {
const marker = el.querySelector(`[${DATA_SCREEN_READERS_ATTR}][tabindex]`);
const ariaLabel = this.getMessage(`i18n:highlighter:highlight:${position}`);

if (!marker) {
return;
}
marker.setAttribute('aria-label', ariaLabel);
}
/**
* Add class 'focus' to all elements of this highlight.
*/
public addFocusedStyles(): Highlight {
this.elements.forEach((el: HTMLElement) => el.classList.add(FOCUS_CSS));
this.elements.forEach((el: HTMLElement) => {
el.setAttribute('aria-current', 'true');
this.updateStartMarker(el, 'start-selected');
});
return this;
}

Expand Down
28 changes: 24 additions & 4 deletions src/Highlighter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { debounce } from 'lodash';
import dom, { isHtmlElement } from './dom';
import Highlight, { FOCUS_CSS, IHighlightData, IOptions as HighlightOptions } from './Highlight';
import Highlight, { IHighlightData, IOptions as HighlightOptions } from './Highlight';
import injectHighlightWrappers, { DATA_ATTR, DATA_ID_ATTR, DATA_SCREEN_READERS_ATTR } from './injectHighlightWrappers';
import { rangeContentsString } from './rangeContents';
import removeHighlightWrappers from './removeHighlightWrappers';
Expand All @@ -21,6 +21,7 @@ interface IOptions {
onSelect?: (highlights: Highlight[], newHighlight?: Highlight) => void;
onFocusIn?: (highlight: Highlight) => void;
onFocusOut?: (highlight: Highlight) => void;
tabbable?: boolean;
}

export default class Highlighter {
Expand All @@ -42,6 +43,7 @@ export default class Highlighter {
onFocusOut: () => {
this.clearFocusedStyles();
},
tabbable: true,
...options,
};
this.debouncedSnapSelection = debounce(this.snapSelection, ON_SELECT_DELAY);
Expand Down Expand Up @@ -96,21 +98,39 @@ export default class Highlighter {
return this.container.querySelector(`[id="${id}"]`);
}

public getHighlightFromElement(el: Element) {
const highlightId = el.getAttribute('data-highlight-id');

if (!highlightId) {
return null;
}
return this.getHighlight(highlightId);
}

public clearFocusedStyles(): void {
this.container.querySelectorAll(`.${this.options.className}.${FOCUS_CSS}`)
.forEach((el: Element) => el.classList.remove(FOCUS_CSS));
this.container.querySelectorAll(`.${this.options.className}[aria-current]`)
.forEach((el: Element) => {
el.removeAttribute('aria-current');
const highlight = this.getHighlightFromElement(el);

if (!highlight) {
return;
}
highlight.updateStartMarker(el, 'start');
});
}

public getHighlights(): Highlight[] {
return Object.values(this.highlights);
}

public getHighlightOptions(): HighlightOptions {
const { formatMessage, skipIDsBy } = this.options;
const { formatMessage, skipIDsBy, tabbable } = this.options;

return {
formatMessage,
skipIDsBy,
tabbable,
};
}

Expand Down
Loading