diff --git a/studio/package.json b/studio/package.json index 368f2231c..5992725d0 100644 --- a/studio/package.json +++ b/studio/package.json @@ -25,6 +25,7 @@ "@deckdeckgo/highlight-code": "^1.0.4", "@deckdeckgo/inline-editor": "^1.2.0", "@deckdeckgo/lazy-img": "^1.0.0", + "@deckdeckgo/math": "^1.0.0", "@deckdeckgo/qrcode": "^1.0.0", "@deckdeckgo/remote": "^1.1.0", "@deckdeckgo/slide-aspect-ratio": "^1.0.0", diff --git a/studio/src/app/components/editor/actions/element/app-actions-element/app-actions-element.tsx b/studio/src/app/components/editor/actions/element/app-actions-element/app-actions-element.tsx index a195c4769..97589df04 100644 --- a/studio/src/app/components/editor/actions/element/app-actions-element/app-actions-element.tsx +++ b/studio/src/app/components/editor/actions/element/app-actions-element/app-actions-element.tsx @@ -27,7 +27,7 @@ import {BusyService} from '../../../../../services/editor/busy/busy.service'; @Component({ tag: 'app-actions-element', styleUrl: 'app-actions-element.scss', - shadow: false, + shadow: false }) export class AppActionsElement { @Element() el: HTMLElement; @@ -52,6 +52,9 @@ export class AppActionsElement { @State() private code: boolean = false; + @State() + private math: boolean = false; + @State() private image: boolean = false; @@ -70,6 +73,7 @@ export class AppActionsElement { @Event() private slideDidChange: EventEmitter; @Event() private codeDidChange: EventEmitter; + @Event() private mathDidChange: EventEmitter; @Event() private imgDidChange: EventEmitter; @Event() private notesDidChange: EventEmitter; @@ -227,7 +231,7 @@ export class AppActionsElement { return; } - if (element.hasAttribute('slot') && element.getAttribute('slot') !== 'code') { + if (element.hasAttribute('slot') && element.getAttribute('slot') !== 'code' && element.getAttribute('slot') !== 'math') { resolve(element); return; } @@ -246,6 +250,10 @@ export class AppActionsElement { return element && element.nodeName && element.nodeName.toLowerCase() === SlotType.CODE; } + private isElementMath(element: HTMLElement): boolean { + return element && element.nodeName && element.nodeName.toLowerCase() === SlotType.MATH; + } + private isElementShape(element: HTMLElement): boolean { return element && element.nodeName && element.nodeName.toLowerCase() === SlotType.DRAG_RESIZE_ROTATE; } @@ -352,7 +360,7 @@ export class AppActionsElement { const popover: HTMLIonPopoverElement = await popoverController.create({ component: 'app-element-delete', event: $event, - mode: isMobile() && !isIOS() ? 'md' : 'ios', + mode: isMobile() && !isIOS() ? 'md' : 'ios' }); popover.onDidDismiss().then(async (detail: OverlayEventDetail) => { @@ -450,11 +458,11 @@ export class AppActionsElement { const popover: HTMLIonPopoverElement = await popoverController.create({ component: 'app-slot-type', componentProps: { - selectedElement: this.selectedElement, + selectedElement: this.selectedElement }, mode: 'md', showBackdrop: false, - cssClass: 'popover-menu', + cssClass: 'popover-menu' }); popover.onDidDismiss().then(async (detail: OverlayEventDetail) => { @@ -481,11 +489,11 @@ export class AppActionsElement { qrCode: this.slideNodeName === 'deckgo-slide-qrcode', chart: this.slideNodeName === 'deckgo-slide-chart', author: this.slideNodeName === 'deckgo-slide-author', - slideDidChange: this.slideDidChange, + slideDidChange: this.slideDidChange }, mode: 'md', showBackdrop: false, - cssClass: 'popover-menu', + cssClass: 'popover-menu' }); popover.onWillDismiss().then(async (detail: OverlayEventDetail) => { @@ -511,11 +519,11 @@ export class AppActionsElement { const popover: HTMLIonPopoverElement = await popoverController.create({ component: 'app-shape', componentProps: { - selectedElement: this.selectedElement, + selectedElement: this.selectedElement }, mode: 'md', showBackdrop: false, - cssClass: 'popover-menu', + cssClass: 'popover-menu' }); popover.onWillDismiss().then(async (detail: OverlayEventDetail) => { @@ -533,11 +541,11 @@ export class AppActionsElement { componentProps: { selectedElement: this.selectedElement, slide: this.slide, - imgDidChange: this.imgDidChange, + imgDidChange: this.imgDidChange }, mode: 'md', showBackdrop: false, - cssClass: 'popover-menu', + cssClass: 'popover-menu' }); return popover; @@ -552,8 +560,8 @@ export class AppActionsElement { component: 'app-poll-options', componentProps: { selectedElement: this.selectedElement, - slideDidChange: this.slideDidChange, - }, + slideDidChange: this.slideDidChange + } }); modal.onDidDismiss().then(async (_detail: OverlayEventDetail) => { @@ -573,11 +581,11 @@ export class AppActionsElement { const popover: HTMLIonPopoverElement = await popoverController.create({ component: component, componentProps: { - selectedElement: this.selectedElement, + selectedElement: this.selectedElement }, mode: 'ios', event: $event, - cssClass: 'info', + cssClass: 'info' }); popover.onDidDismiss().then(async (detail: OverlayEventDetail) => { @@ -602,11 +610,29 @@ export class AppActionsElement { component: 'app-code', componentProps: { selectedElement: this.selectedElement, - codeDidChange: this.codeDidChange, + codeDidChange: this.codeDidChange + }, + mode: 'md', + showBackdrop: false, + cssClass: 'popover-menu' + }); + + await popover.present(); + } + private async openMath() { + if (!this.math) { + return; + } + + const popover: HTMLIonPopoverElement = await popoverController.create({ + component: 'app-math', + componentProps: { + selectedElement: this.selectedElement, + mathDidChange: this.mathDidChange }, mode: 'md', showBackdrop: false, - cssClass: 'popover-menu', + cssClass: 'popover-menu' }); await popover.present(); @@ -620,8 +646,8 @@ export class AppActionsElement { const modal: HTMLIonModalElement = await modalController.create({ component: 'app-youtube', componentProps: { - selectedElement: this.selectedElement, - }, + selectedElement: this.selectedElement + } }); modal.onDidDismiss().then(async (detail: OverlayEventDetail) => { @@ -666,8 +692,8 @@ export class AppActionsElement { const modal: HTMLIonModalElement = await modalController.create({ component: 'app-notes', componentProps: { - selectedElement: this.selectedElement, - }, + selectedElement: this.selectedElement + } }); modal.onDidDismiss().then(async (detail: OverlayEventDetail) => { @@ -766,6 +792,7 @@ export class AppActionsElement { this.slideNodeName = this.slide ? element.nodeName.toLowerCase() : undefined; this.slideDemo = this.slide && this.slideNodeName === 'deckgo-slide-split' && element.getAttribute('type') === SlideSplitType.DEMO; + this.math = this.isElementMath(SlotUtils.isNodeReveal(element) ? (element.firstElementChild as HTMLElement) : element); this.code = this.isElementCode(SlotUtils.isNodeReveal(element) ? (element.firstElementChild as HTMLElement) : element); this.image = this.isElementImage(SlotUtils.isNodeReveal(element) ? (element.firstElementChild as HTMLElement) : element); this.shape = this.isElementShape(element); @@ -857,11 +884,11 @@ export class AppActionsElement { component: 'app-color', componentProps: { slide: this.slide, - selectedElement: this.selectedElement, + selectedElement: this.selectedElement }, mode: 'md', showBackdrop: false, - cssClass: `popover-menu ${this.slideNodeName === 'deckgo-slide-poll' ? 'popover-menu-wide' : ''}`, + cssClass: `popover-menu ${this.slideNodeName === 'deckgo-slide-poll' ? 'popover-menu-wide' : ''}` }); await popover.present(); @@ -1013,10 +1040,10 @@ export class AppActionsElement { notes: this.slide, copy: this.slide || this.shape, reveal: !this.hideReveal(), - list: this.list !== undefined, + list: this.list !== undefined }, event: $event, - mode: 'ios', + mode: 'ios' }); popover.onDidDismiss().then(async (detail: OverlayEventDetail) => { @@ -1039,7 +1066,7 @@ export class AppActionsElement { } private hideReveal(): boolean { - return this.slide || this.code || this.shape || this.slideNodeName === 'deckgo-slide-youtube'; + return this.slide || this.code || this.math || this.shape || this.slideNodeName === 'deckgo-slide-youtube'; } render() { @@ -1054,6 +1081,7 @@ export class AppActionsElement { {this.renderList()} {this.renderImages()} {this.renderCodeOptions()} + {this.renderMathOptions()} @@ -1137,7 +1165,7 @@ export class AppActionsElement { this.openSlotType()} aria-label="Toggle element type" color="primary" mode="md" class={classToggle}> Toggle - , + ]; } @@ -1148,7 +1176,7 @@ export class AppActionsElement { this.openShape()} color="primary" aria-label="Add a shape" mode="md" class={classSlide}> Add shape - , + ]; } @@ -1162,6 +1190,16 @@ export class AppActionsElement { ); } + private renderMathOptions() { + const classSlideMath: string | undefined = this.math ? undefined : 'hidden'; + + return ( + this.openMath()} aria-label="Math options" color="primary" mode="md" class={classSlideMath}> + + Options + + ); + } private renderImages() { const classImage: string | undefined = this.image || this.slide ? undefined : 'hidden'; diff --git a/studio/src/app/handlers/editor/events/deck/deck-events.handler.tsx b/studio/src/app/handlers/editor/events/deck/deck-events.handler.tsx index d57ae1096..0eca4ea16 100644 --- a/studio/src/app/handlers/editor/events/deck/deck-events.handler.tsx +++ b/studio/src/app/handlers/editor/events/deck/deck-events.handler.tsx @@ -65,6 +65,7 @@ export class DeckEventsHandler { this.el.addEventListener('slidesDidLoad', this.onSlidesDidLoad, false); this.el.addEventListener('slideDelete', this.onSlideDelete, false); this.el.addEventListener('codeDidChange', this.onCustomEventChange, false); + this.el.addEventListener('mathDidChange', this.onCustomEventChange, false); this.el.addEventListener('imgDidChange', this.onCustomEventChange, false); this.el.addEventListener('linkCreated', this.onCustomEventChange, false); this.el.addEventListener('drrDidChange', this.onCustomEventChange, false); @@ -95,6 +96,7 @@ export class DeckEventsHandler { this.el.removeEventListener('slidesDidLoad', this.onSlidesDidLoad, true); this.el.removeEventListener('slideDelete', this.onSlideDelete, true); this.el.removeEventListener('codeDidChange', this.onCustomEventChange, true); + this.el.removeEventListener('mathDidChange', this.onCustomEventChange, true); this.el.removeEventListener('imgDidChange', this.onCustomEventChange, true); this.el.removeEventListener('linkCreated', this.onCustomEventChange, true); this.el.removeEventListener('drrDidChange', this.onCustomEventChange, true); diff --git a/studio/src/app/pages/editor/app-editor/app-editor.tsx b/studio/src/app/pages/editor/app-editor/app-editor.tsx index 43aacd2ca..6c606ab9a 100644 --- a/studio/src/app/pages/editor/app-editor/app-editor.tsx +++ b/studio/src/app/pages/editor/app-editor/app-editor.tsx @@ -44,7 +44,7 @@ import {FontsService} from '../../../services/editor/fonts/fonts.service'; @Component({ tag: 'app-editor', - styleUrl: 'app-editor.scss', + styleUrl: 'app-editor.scss' }) export class AppEditor { @Element() el: HTMLElement; @@ -392,7 +392,7 @@ export class AppEditor { const modal: HTMLIonModalElement = await modalController.create({ component: 'app-publish', - cssClass: 'fullscreen', + cssClass: 'fullscreen' }); modal.onDidDismiss().then(async (_detail: OverlayEventDetail) => { @@ -589,7 +589,7 @@ export class AppEditor { async signIn() { this.navService.navigate({ url: '/signin' + (window && window.location ? window.location.pathname : ''), - direction: NavDirection.FORWARD, + direction: NavDirection.FORWARD }); } @@ -603,7 +603,7 @@ export class AppEditor { const elements: HTMLElement[] = Array.prototype.slice.call(slide.childNodes); elements.forEach((e: HTMLElement) => { if (e.nodeName && e.nodeType === 1 && e.hasAttribute('slot')) { - if (e.nodeName.toLowerCase() === SlotType.CODE) { + if (e.nodeName.toLowerCase() === SlotType.CODE || e.nodeName.toLowerCase() === SlotType.MATH) { e.setAttribute('editable', ''); } else if (ParseElementsUtils.isElementContentEditable(e)) { e.setAttribute('contentEditable', ''); @@ -673,7 +673,6 @@ export class AppEditor {
{this.renderLoading()} - , - this.inactivity($event)}>, + this.inactivity($event)}> ]; } diff --git a/studio/src/app/popovers/editor/app-math/app-math.scss b/studio/src/app/popovers/editor/app-math/app-math.scss new file mode 100644 index 000000000..cb02473e4 --- /dev/null +++ b/studio/src/app/popovers/editor/app-math/app-math.scss @@ -0,0 +1,4 @@ +app-math { + @import "../../../../global/theme/editor/editor-info"; + @import "../../../../global/theme/editor/editor-popover"; +} diff --git a/studio/src/app/popovers/editor/app-math/app-math.tsx b/studio/src/app/popovers/editor/app-math/app-math.tsx new file mode 100644 index 000000000..96a0a706a --- /dev/null +++ b/studio/src/app/popovers/editor/app-math/app-math.tsx @@ -0,0 +1,171 @@ +import {Component, Element, EventEmitter, Prop, State, h} from '@stencil/core'; + +enum MathFontSize { + VERY_SMALL, + SMALL, + NORMAL, + BIG, + VERY_BIG +} + +@Component({ + tag: 'app-math', + styleUrl: 'app-math.scss' +}) +export class AppMath { + @Element() el: HTMLElement; + + @Prop() + selectedElement: HTMLElement; + + @Prop() + mathDidChange: EventEmitter; + + @State() + private currentFontSize: MathFontSize = undefined; + + @State() + private leqno: boolean = false; + + @State() + private fleqn: boolean = false; + + constructor() {} + + async componentWillLoad() { + await this.initCurrent(); + } + + private async closePopover() { + await (this.el.closest('ion-popover') as HTMLIonPopoverElement).dismiss(); + } + + private initCurrent(): Promise { + return new Promise(async (resolve) => { + this.currentFontSize = await this.initFontSize(); + this.leqno = this.selectedElement && this.selectedElement.hasAttribute('leqno'); + this.fleqn = this.selectedElement && this.selectedElement.hasAttribute('fleqn'); + resolve(); + }); + } + + private emitMathDidChange() { + this.mathDidChange.emit(this.selectedElement); + } + + private initFontSize(): Promise { + return new Promise((resolve) => { + if (!this.selectedElement || !this.selectedElement.style) { + resolve(null); + return; + } + + const property: string = this.selectedElement.style.getPropertyValue('--deckgo-math-font-size'); + + if (property === '50%') { + resolve(MathFontSize.VERY_SMALL); + } else if (property === '75%') { + resolve(MathFontSize.SMALL); + } else if (property === '150%') { + resolve(MathFontSize.BIG); + } else if (property === '200%') { + resolve(MathFontSize.VERY_BIG); + } else { + resolve(MathFontSize.NORMAL); + } + }); + } + + private toggleFontSize($event: CustomEvent): Promise { + return new Promise(async (resolve) => { + if (!$event || !$event.detail) { + resolve(); + return; + } + + this.currentFontSize = $event.detail.value; + + if (!this.selectedElement) { + resolve(); + return; + } + + this.selectedElement.style.removeProperty('--deckgo-math-font-size'); + + if (this.currentFontSize === MathFontSize.VERY_SMALL) { + this.selectedElement.style.setProperty('--deckgo-math-font-size', '50%'); + } else if (this.currentFontSize === MathFontSize.SMALL) { + this.selectedElement.style.setProperty('--deckgo-math-font-size', '75%'); + } else if (this.currentFontSize === MathFontSize.BIG) { + this.selectedElement.style.setProperty('--deckgo-math-font-size', '150%'); + } else if (this.currentFontSize === MathFontSize.VERY_BIG) { + this.selectedElement.style.setProperty('--deckgo-math-font-size', '200%'); + } + + this.emitMathDidChange(); + + resolve(); + }); + } + + private toggleOptions($event: CustomEvent, propName: string): Promise { + return new Promise(async (resolve) => { + if (!this.selectedElement) { + resolve(); + return; + } + + if (!$event || !$event.detail) { + resolve(); + return; + } + + this.selectedElement.setAttribute(propName, $event.detail.checked); + + this.emitMathDidChange(); + + resolve(); + }); + } + + render() { + return [ + +

Math Options

+ this.closePopover()}> + + +
, + + + Leqno + this.toggleOptions($event, 'leqno')}> + + + + Fleqn + this.toggleOptions($event, 'fleqn')}> + + + Font size + + + + Size + + this.toggleFontSize($event)} + class="ion-padding-start ion-padding-end"> + Very small + Small + Normal + Big + Very big + + + + ]; + } +} diff --git a/studio/src/app/popovers/editor/app-slot-type/app-slot-type.tsx b/studio/src/app/popovers/editor/app-slot-type/app-slot-type.tsx index 1e35e1451..018aff067 100644 --- a/studio/src/app/popovers/editor/app-slot-type/app-slot-type.tsx +++ b/studio/src/app/popovers/editor/app-slot-type/app-slot-type.tsx @@ -127,6 +127,11 @@ export class AppSlideAdd {

Code

+ , + this.closePopover(SlotType.MATH)} class={this.currentType === SlotType.MATH ? 'current' : ''}> + +

Math

+
]; } diff --git a/studio/src/app/utils/editor/parse-elements.utils.tsx b/studio/src/app/utils/editor/parse-elements.utils.tsx index 1eb3514b8..59182d879 100644 --- a/studio/src/app/utils/editor/parse-elements.utils.tsx +++ b/studio/src/app/utils/editor/parse-elements.utils.tsx @@ -80,6 +80,7 @@ export class ParseElementsUtils { static isElementContentEditable(element: HTMLElement): boolean { return ( (!element.nodeName || (element.nodeName.toLowerCase() !== 'code' && element.nodeName.toLowerCase() !== SlotType.CODE)) && + (!element.nodeName || (element.nodeName.toLowerCase() !== 'div' && element.nodeName.toLowerCase() !== SlotType.MATH)) && (!element.nodeName || (element.nodeName.toLowerCase() !== 'deckgo-social' && element.nodeName.toLowerCase() !== SlotType.SOCIAL)) && (!element.nodeName || (element.nodeName.toLowerCase() !== 'deckgo-lazy-img' && element.nodeName.toLowerCase() !== SlotType.IMG)) && (!element.nodeName || (element.nodeName.toLowerCase() !== 'deckgo-demo' && element.nodeName.toLowerCase() !== SlotType.DEMO)) && diff --git a/studio/src/app/utils/editor/slot-type.tsx b/studio/src/app/utils/editor/slot-type.tsx index 5815a910f..fa22553d9 100644 --- a/studio/src/app/utils/editor/slot-type.tsx +++ b/studio/src/app/utils/editor/slot-type.tsx @@ -12,4 +12,5 @@ export enum SlotType { REVEAL_LIST = 'deckgo-reveal-list', DRAG_RESIZE_ROTATE = 'deckgo-drr', DEMO = 'deckgo-demo', + MATH = 'deckgo-math' } diff --git a/studio/src/app/utils/editor/toggle-slot.utils.tsx b/studio/src/app/utils/editor/toggle-slot.utils.tsx index 615fe88cf..17036d35b 100644 --- a/studio/src/app/utils/editor/toggle-slot.utils.tsx +++ b/studio/src/app/utils/editor/toggle-slot.utils.tsx @@ -48,16 +48,19 @@ export class ToggleSlotUtils { } private static createSlotContainer(element: HTMLElement, type: SlotType): HTMLElement { - if (type !== SlotType.CODE) { + if (type == SlotType.CODE) { + return this.createNamedSlotContainer(element, 'code', 'code'); + } else if (type == SlotType.MATH) { + return this.createNamedSlotContainer(element, 'div', 'math'); + } else { return element; } - - const code: HTMLElement = document.createElement('code'); - code.setAttribute('slot', 'code'); - - element.appendChild(code); - - return code; + } + private static createNamedSlotContainer(element: HTMLElement, slotElementName: string, slotName: string) { + const container: HTMLElement = document.createElement(slotElementName); + container.setAttribute('slot', slotName); + element.appendChild(container); + return container; } private static getSlotContainer(selectedElement: HTMLElement): HTMLElement { @@ -78,7 +81,7 @@ export class ToggleSlotUtils { if (!SlotUtils.isSlotTypeEditable(type)) { selectedElement.removeAttribute('editable'); selectedElement.removeAttribute('contenteditable'); - } else if (type === SlotType.CODE) { + } else if (type === SlotType.CODE || type == SlotType.MATH) { selectedElement.setAttribute('editable', 'true'); selectedElement.removeAttribute('contenteditable'); } else { diff --git a/studio/src/components.d.ts b/studio/src/components.d.ts index 6a3a0d198..8c4ed8f5d 100644 --- a/studio/src/components.d.ts +++ b/studio/src/components.d.ts @@ -229,6 +229,10 @@ export namespace Components { 'selectedElement': HTMLElement; } interface AppLogo {} + interface AppMath { + 'mathDidChange': EventEmitter; + 'selectedElement': HTMLElement; + } interface AppMenu {} interface AppMoreDeckActions { 'offline': boolean; @@ -689,6 +693,12 @@ declare global { new (): HTMLAppLogoElement; }; + interface HTMLAppMathElement extends Components.AppMath, HTMLStencilElement {} + var HTMLAppMathElement: { + prototype: HTMLAppMathElement; + new (): HTMLAppMathElement; + }; + interface HTMLAppMenuElement extends Components.AppMenu, HTMLStencilElement {} var HTMLAppMenuElement: { prototype: HTMLAppMenuElement; @@ -988,6 +998,7 @@ declare global { 'app-landing-footer': HTMLAppLandingFooterElement; 'app-list': HTMLAppListElement; 'app-logo': HTMLAppLogoElement; + 'app-math': HTMLAppMathElement; 'app-menu': HTMLAppMenuElement; 'app-more-deck-actions': HTMLAppMoreDeckActionsElement; 'app-more-element-actions': HTMLAppMoreElementActionsElement; @@ -1081,6 +1092,7 @@ declare namespace LocalJSX { 'onBlockSlide'?: (event: CustomEvent) => void; 'onCodeDidChange'?: (event: CustomEvent) => void; 'onImgDidChange'?: (event: CustomEvent) => void; + 'onMathDidChange'?: (event: CustomEvent) => void; 'onNotesDidChange'?: (event: CustomEvent) => void; 'onResetted'?: (event: CustomEvent) => void; 'onSignIn'?: (event: CustomEvent) => void; @@ -1260,6 +1272,10 @@ declare namespace LocalJSX { 'selectedElement'?: HTMLElement; } interface AppLogo {} + interface AppMath { + 'mathDidChange'?: EventEmitter; + 'selectedElement'?: HTMLElement; + } interface AppMenu {} interface AppMoreDeckActions { 'offline'?: boolean; @@ -1429,6 +1445,7 @@ declare namespace LocalJSX { 'app-landing-footer': AppLandingFooter; 'app-list': AppList; 'app-logo': AppLogo; + 'app-math': AppMath; 'app-menu': AppMenu; 'app-more-deck-actions': AppMoreDeckActions; 'app-more-element-actions': AppMoreElementActions; @@ -1537,6 +1554,7 @@ declare module "@stencil/core" { 'app-landing-footer': LocalJSX.AppLandingFooter & JSXBase.HTMLAttributes; 'app-list': LocalJSX.AppList & JSXBase.HTMLAttributes; 'app-logo': LocalJSX.AppLogo & JSXBase.HTMLAttributes; + 'app-math': LocalJSX.AppMath & JSXBase.HTMLAttributes; 'app-menu': LocalJSX.AppMenu & JSXBase.HTMLAttributes; 'app-more-deck-actions': LocalJSX.AppMoreDeckActions & JSXBase.HTMLAttributes; 'app-more-element-actions': LocalJSX.AppMoreElementActions & JSXBase.HTMLAttributes; diff --git a/studio/src/global/app-dev.ts b/studio/src/global/app-dev.ts index 344fc2d0e..22637d84f 100644 --- a/studio/src/global/app-dev.ts +++ b/studio/src/global/app-dev.ts @@ -11,6 +11,7 @@ import '@deckdeckgo/inline-editor'; import '@deckdeckgo/remote'; import '@deckdeckgo/qrcode'; import '@deckdeckgo/highlight-code'; +import '@deckdeckgo/math'; import '@deckdeckgo/lazy-img'; import '@deckdeckgo/color'; import '@deckdeckgo/charts'; diff --git a/studio/src/global/app-staging.ts b/studio/src/global/app-staging.ts index 3eb412659..88c717f56 100644 --- a/studio/src/global/app-staging.ts +++ b/studio/src/global/app-staging.ts @@ -11,6 +11,7 @@ import '@deckdeckgo/inline-editor'; import '@deckdeckgo/remote'; import '@deckdeckgo/qrcode'; import '@deckdeckgo/highlight-code'; +import '@deckdeckgo/math'; import '@deckdeckgo/lazy-img'; import '@deckdeckgo/color'; import '@deckdeckgo/charts'; diff --git a/studio/src/global/app.ts b/studio/src/global/app.ts index ddb47b5be..1640be6e5 100644 --- a/studio/src/global/app.ts +++ b/studio/src/global/app.ts @@ -11,6 +11,7 @@ import '@deckdeckgo/inline-editor'; import '@deckdeckgo/remote'; import '@deckdeckgo/qrcode'; import '@deckdeckgo/highlight-code'; +import '@deckdeckgo/math'; import '@deckdeckgo/lazy-img'; import '@deckdeckgo/color'; import '@deckdeckgo/charts'; diff --git a/studio/src/global/theme/editor/editor-deck.scss b/studio/src/global/theme/editor/editor-deck.scss index 7d52d54a1..937f74da3 100644 --- a/studio/src/global/theme/editor/editor-deck.scss +++ b/studio/src/global/theme/editor/editor-deck.scss @@ -12,7 +12,8 @@ deckgo-deck { section, ol, ul, - deckgo-reveal-list { + deckgo-reveal-list, + deckgo-math { border-radius: 2px; border: 1px solid var(--ion-color-light); } diff --git a/utils/deck/styles/deck/deck.scss b/utils/deck/styles/deck/deck.scss index a0ebf34d4..72f22dbce 100644 --- a/utils/deck/styles/deck/deck.scss +++ b/utils/deck/styles/deck/deck.scss @@ -12,7 +12,8 @@ deckgo-deck section, deckgo-deck ol, deckgo-deck ul, deckgo-deck deckgo-reveal-list, -deckgo-deck deckgo-highlight-code { +deckgo-deck deckgo-highlight-code, +deckgo-deck deckgo-math { width: 100%; } @@ -34,6 +35,7 @@ deckgo-deck ol, deckgo-deck ul, deckgo-deck deckgo-reveal-list, deckgo-deck deckgo-highlight-code, +deckgo-deck deckgo-math, deckgo-deck deckgo-lazy-img[slot] { margin: 16px 0; overflow: auto; @@ -149,6 +151,7 @@ deckgo-deck deckgo-reveal h2, deckgo-deck deckgo-reveal h3, deckgo-deck deckgo-reveal section, deckgo-deck deckgo-reveal deckgo-highlight-code, +deckgo-deck deckgo-reveal deckgo-math, deckgo-deck deckgo-reveal deckgo-lazy-img[slot] { margin: 0; } diff --git a/webcomponents/math/.editorconfig b/webcomponents/math/.editorconfig new file mode 100644 index 000000000..f1cc3ad32 --- /dev/null +++ b/webcomponents/math/.editorconfig @@ -0,0 +1,15 @@ +# http://editorconfig.org + +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +insert_final_newline = false +trim_trailing_whitespace = false diff --git a/webcomponents/math/.prettierrc b/webcomponents/math/.prettierrc new file mode 100644 index 000000000..55895b9a6 --- /dev/null +++ b/webcomponents/math/.prettierrc @@ -0,0 +1,15 @@ +{ + "printWidth": 160, + "singleQuote": true, + "arrowParens": "always", + "bracketSpacing": false, + "jsxBracketSameLine": true, + "overrides": [ + { + "files": ["*.scss", "*.css"], + "options": { + "singleQuote": false + } + } + ] +} diff --git a/webcomponents/math/CHANGELOG.md b/webcomponents/math/CHANGELOG.md new file mode 100644 index 000000000..e69de29bb diff --git a/webcomponents/math/LICENSE b/webcomponents/math/LICENSE new file mode 100644 index 000000000..c0e5d1513 --- /dev/null +++ b/webcomponents/math/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 David Dal Busco and Nicolas Mattia + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/webcomponents/math/README.md b/webcomponents/math/README.md new file mode 100644 index 000000000..e69de29bb diff --git a/webcomponents/math/package-lock.json b/webcomponents/math/package-lock.json new file mode 100644 index 000000000..357677e6e --- /dev/null +++ b/webcomponents/math/package-lock.json @@ -0,0 +1,935 @@ +{ + "name": "@deckdeckgo/math", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz", + "integrity": "sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", + "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.9.0", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/runtime": { + "version": "7.9.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.2.tgz", + "integrity": "sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@deckdeckgo/utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@deckdeckgo/utils/-/utils-1.0.0.tgz", + "integrity": "sha512-yqbie3n3JDGU338MS9NNfAseQfPVamqC0m/Y1U8fSh7ZKSzSRCU/899nkpma9DZEg16v8vld8vnpImGrzkFSHg==" + }, + "@stencil/core": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@stencil/core/-/core-1.12.0.tgz", + "integrity": "sha512-aYQyQI2mq2UkCc6MQXdA27OqcvaBDfcCcKOKarC9e7mF2YLEmJ90behs/Mk5PuG8hUuSqjvj+dwUryjV7KpGJg==", + "dev": true, + "requires": { + "typescript": "3.8.3" + } + }, + "@stencil/postcss": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stencil/postcss/-/postcss-1.0.1.tgz", + "integrity": "sha512-+QOLwdiMSeE6XbvjOM8bfMIX6E6L4DFLmnp0wZqCj4O/PVkNfEQA6IXZgd6F+OIfZ1wBy/dxR4Jvtwfo+QXa2g==", + "dev": true, + "requires": { + "postcss": "~7.0.17" + } + }, + "@stencil/sass": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@stencil/sass/-/sass-1.3.1.tgz", + "integrity": "sha512-5qsEyhLGTywpG4zlWv6eBhhj/z2Z37nbUGa87Ak0KqfsEiclJCYRA/AMM9FiN1jHfBvr968G4zE8rNlYmiPLsQ==", + "dev": true + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "array-differ": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", + "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", + "dev": true + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "dev": true + }, + "autoprefixer": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.7.5.tgz", + "integrity": "sha512-URo6Zvt7VYifomeAfJlMFnYDhow1rk2bufwkbamPEAtQFcL11moLk4PnR7n9vlu7M+BkXAZkHFA0mIcY7tjQFg==", + "dev": true, + "requires": { + "browserslist": "^4.11.0", + "caniuse-lite": "^1.0.30001036", + "chalk": "^2.4.2", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.27", + "postcss-value-parser": "^4.0.3" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "browserslist": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.11.1.tgz", + "integrity": "sha512-DCTr3kDrKEYNw6Jb9HFxVLQNaue8z+0ZfRBRjmCunKDEXEBajKDj2Y+Uelg+Pi29OnvaSGwjOsnRyNEkXzHg5g==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001038", + "electron-to-chromium": "^1.3.390", + "node-releases": "^1.1.53", + "pkg-up": "^2.0.0" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001038", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001038.tgz", + "integrity": "sha512-zii9quPo96XfOiRD4TrfYGs+QsGZpb2cGiMAzPjtf/hpFgB6zCPZgJb7I1+EATeMw/o+lG8FyRAnI+CWStHcaQ==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "compare-versions": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", + "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + } + }, + "cross-spawn": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", + "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "electron-to-chromium": { + "version": "1.3.393", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.393.tgz", + "integrity": "sha512-Ko3/VdhZAaMaJBLBFqEJ+M1qMiBI8sJfPY/hSJvDrkB3Do8LJsL9tmXy4w7o9nPXif/jFaZGSlXTQWU8XVsYtg==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "execa": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-2.1.0.tgz", + "integrity": "sha512-Y/URAVapfbYy2Xp/gb6A0E7iR8xeqOCXsuuaoMn7A5PzrXUK84E1gyiEfq0wQd/GHA6GsoHWwhNq8anb0mleIw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^3.0.0", + "onetime": "^5.1.0", + "p-finally": "^2.0.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + } + }, + "extract-math": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/extract-math/-/extract-math-1.1.0.tgz", + "integrity": "sha512-YDbUcfio8SSXayqVz+MscpaJhTt1mUoFtLbrZKL7yVwjQZK9TVI9ebriSIBFH+Jy9YHctgS7OriMFxmr/dpWww==", + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==" + } + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "find-versions": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz", + "integrity": "sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==", + "dev": true, + "requires": { + "semver-regex": "^2.0.0" + } + }, + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "husky": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/husky/-/husky-4.2.3.tgz", + "integrity": "sha512-VxTsSTRwYveKXN4SaH1/FefRJYCtx+wx04sSVcOpD7N2zjoHxa+cEJ07Qg5NmV3HAK+IRKOyNVpi2YBIVccIfQ==", + "dev": true, + "requires": { + "chalk": "^3.0.0", + "ci-info": "^2.0.0", + "compare-versions": "^3.5.1", + "cosmiconfig": "^6.0.0", + "find-versions": "^3.2.0", + "opencollective-postinstall": "^2.0.2", + "pkg-dir": "^4.2.0", + "please-upgrade-node": "^3.2.0", + "slash": "^3.0.0", + "which-pm-runs": "^1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "ignore": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", + "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", + "dev": true + }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "katex": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.11.1.tgz", + "integrity": "sha512-5oANDICCTX0NqYIyAiFCCwjQ7ERu3DQG2JFHLbYOf+fXaMoH8eg/zOq5WSYJsKMi/QebW+Eh3gSM+oss1H/bww==", + "requires": { + "commander": "^2.19.0" + } + }, + "lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "mri": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.5.tgz", + "integrity": "sha512-d2RKzMD4JNyHMbnbWnznPaa8vbdlq/4pNZ3IgdaGrVbBhebBsGUUE/6qorTMYNS6TwuH3ilfOlD2bf4Igh8CKg==", + "dev": true + }, + "multimatch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-4.0.0.tgz", + "integrity": "sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==", + "dev": true, + "requires": { + "@types/minimatch": "^3.0.3", + "array-differ": "^3.0.0", + "array-union": "^2.1.0", + "arrify": "^2.0.1", + "minimatch": "^3.0.4" + } + }, + "node-releases": { + "version": "1.1.53", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.53.tgz", + "integrity": "sha512-wp8zyQVwef2hpZ/dJH7SfSrIPD6YoJz6BDQDpGEkcA0s3LpAQoxBIYmfIq6QAhC1DhwsyCgTaTTcONwX8qzCuQ==", + "dev": true + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true + }, + "npm-run-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-3.1.0.tgz", + "integrity": "sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "opencollective-postinstall": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz", + "integrity": "sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==", + "dev": true + }, + "p-finally": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz", + "integrity": "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", + "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1", + "lines-and-columns": "^1.1.6" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + } + } + }, + "pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "please-upgrade-node": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", + "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", + "dev": true, + "requires": { + "semver-compare": "^1.0.0" + } + }, + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-value-parser": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.3.tgz", + "integrity": "sha512-N7h4pG+Nnu5BEIzyeaaIYWs0LI5XC40OrRh5L60z0QjFsqGWcHcbkBvpe1WYpcIS9yQ8sOi/vIPt1ejQCrMVrg==", + "dev": true + }, + "prettier": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.2.tgz", + "integrity": "sha512-5xJQIPT8BraI7ZnaDwSbu5zLrB6vvi8hVV58yHQ+QK64qrY40dULy0HSRlQ2/2IdzeBpjhDkqdcFBnFeDEMVdg==", + "dev": true + }, + "pretty-quick": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pretty-quick/-/pretty-quick-2.0.1.tgz", + "integrity": "sha512-y7bJt77XadjUr+P1uKqZxFWLddvj3SKY6EU4BuQtMxmmEFSMpbN132pUWdSG1g1mtUfO0noBvn7wBf0BVeomHg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "execa": "^2.1.0", + "find-up": "^4.1.0", + "ignore": "^5.1.4", + "mri": "^1.1.4", + "multimatch": "^4.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + } + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "regenerator-runtime": { + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz", + "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==", + "dev": true + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", + "dev": true + }, + "semver-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz", + "integrity": "sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "typescript": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", + "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-pm-runs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", + "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "yaml": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.8.3.tgz", + "integrity": "sha512-X/v7VDnK+sxbQ2Imq4Jt2PRUsRsP7UcpSl3Llg6+NRRqWLIvxkMFYtH1FmvwNGYRKKPa+EPA4qDBlI9WVG1UKw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.7" + } + } + } +} diff --git a/webcomponents/math/package.json b/webcomponents/math/package.json new file mode 100644 index 000000000..18f000581 --- /dev/null +++ b/webcomponents/math/package.json @@ -0,0 +1,67 @@ +{ + "name": "@deckdeckgo/math", + "version": "1.0.0", + "description": "A Web Component to write math expressions", + "main": "dist/index.js", + "module": "dist/index.mjs", + "es2015": "dist/esm/index.mjs", + "es2017": "dist/esm/index.mjs", + "types": "dist/types/index.d.ts", + "collection": "dist/collection/collection-manifest.json", + "collection:main": "dist/collection/index.js", + "unpkg": "dist/deckdeckgo-math/deckdeckgo-math.js", + "files": [ + "dist/", + "README.md", + "LICENSE" + ], + "scripts": { + "build": "stencil build --docs", + "start": "stencil build --dev --watch --serve", + "test": "stencil test --spec --e2e", + "test.watch": "stencil test --spec --e2e --watchAll" + }, + "dependencies": { + "@deckdeckgo/utils": "1.0.0", + "extract-math": "^1.1.0", + "katex": "^0.11.1" + }, + "devDependencies": { + "@stencil/core": "^1.12.0", + "@stencil/postcss": "^1.0.1", + "@stencil/sass": "^1.3.1", + "autoprefixer": "^9.7.5", + "husky": "^4.2.3", + "prettier": "2.0.2", + "pretty-quick": "^2.0.1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/deckgo/deckdeckgo.git" + }, + "author": "David Dal Busco", + "license": "MIT", + "bugs": { + "url": "https://github.com/deckgo/deckdeckgo" + }, + "homepage": "https://deckdeckgo.com", + "keywords": [ + "stencil", + "stenciljs", + "web components", + "pwa", + "progressive web app", + "presentation", + "slides", + "slideshow", + "talk", + "katex", + "math expressions", + "TeX math" + ], + "husky": { + "hooks": { + "pre-commit": "pretty-quick --staged" + } + } +} diff --git a/webcomponents/math/src/components.d.ts b/webcomponents/math/src/components.d.ts new file mode 100644 index 000000000..11421b5df --- /dev/null +++ b/webcomponents/math/src/components.d.ts @@ -0,0 +1,45 @@ +/* eslint-disable */ +/* tslint:disable */ +/** + * This is an autogenerated file created by the Stencil compiler. + * It contains typing information for all components that exist in this project. + */ +import { HTMLStencilElement, JSXBase } from "@stencil/core/internal"; +export namespace Components { + interface DeckgoMath { + "editable": boolean; + "fleqn": boolean; + "leqno": boolean; + } +} +declare global { + interface HTMLDeckgoMathElement extends Components.DeckgoMath, HTMLStencilElement { + } + var HTMLDeckgoMathElement: { + prototype: HTMLDeckgoMathElement; + new (): HTMLDeckgoMathElement; + }; + interface HTMLElementTagNameMap { + "deckgo-math": HTMLDeckgoMathElement; + } +} +declare namespace LocalJSX { + interface DeckgoMath { + "editable"?: boolean; + "fleqn"?: boolean; + "leqno"?: boolean; + "onMathDidChange"?: (event: CustomEvent) => void; + "onMathError"?: (event: CustomEvent) => void; + } + interface IntrinsicElements { + "deckgo-math": DeckgoMath; + } +} +export { LocalJSX as JSX }; +declare module "@stencil/core" { + export namespace JSX { + interface IntrinsicElements { + "deckgo-math": LocalJSX.DeckgoMath & JSXBase.HTMLAttributes; + } + } +} diff --git a/webcomponents/math/src/components/declarations/deckdeckgo-math-options.tsx b/webcomponents/math/src/components/declarations/deckdeckgo-math-options.tsx new file mode 100644 index 000000000..48a3cdabf --- /dev/null +++ b/webcomponents/math/src/components/declarations/deckdeckgo-math-options.tsx @@ -0,0 +1,15 @@ +export interface DeckDeckGoMathOptions { + displayMode: boolean; + output: 'html' | 'mathml' | 'htmlAndMathml'; + leqno: boolean; + fleqn: boolean; + throwOnError: boolean; + errorColor: string; + macros: any; + minRuleThickness: number; + colorIsTextColor: boolean; + maxSize: number; + maxExpand: number; + strict: any; + trust: any; +} diff --git a/webcomponents/math/src/components/math/deckdeckgo-math.scss b/webcomponents/math/src/components/math/deckdeckgo-math.scss new file mode 100644 index 000000000..204d37095 --- /dev/null +++ b/webcomponents/math/src/components/math/deckdeckgo-math.scss @@ -0,0 +1,60 @@ +@import "~katex/dist/katex.min.css"; + +:host { + ::slotted([slot="math"]) { + display: none; + } +} + +:host([editable]) { + div.math:empty:not(:focus):after { + content: var(--deckgo-math-empty-text, "Click to add your math expression"); + } +} + +:host(.deckgo-math-edit) { + ::slotted([slot="math"]) { + display: block; + white-space: pre-wrap; + } + + div.math { + display: none; + } +} + +div.deckgo-math-container { + color: var(--deckgo-math-color, inherit); + background: var(--deckgo-math-backgroun); + padding: var(--deckgo-math-padding, 8px); + border-radius: var(--deckgo-math-border-radius); + + margin: var(--deckgo-math-margin, 0px); + + transform-origin: bottom left; + transition: all 0.2s ease-in-out; + transform: scale(var(--deckgo-math-zoom, 1)); + + direction: var(--deckgo-math-direction, ltr); + text-align: var(--deckgo-math-text-align, start); + + width: var(--deckgo-math-container-width); + height: var(--deckgo-math-container-height); + display: var(--deckgo-math-container-display, block); + justify-content: var(--deckgo-math-container-justify-content); + flex-direction: var(--deckgo-math-container-flex-direction); + align-items: var(--deckgo-math-container-align-items); + + div.math { + overflow-y: var(--deckgo-math-scroll, scroll); + + white-space: pre-wrap; + + font-size: var(--deckgo-math-font-size); + font-family: var(--deckgo-math-font-family); + + display: var(--deckgo-math-display, block); + + counter-reset: linenumber; + } +} diff --git a/webcomponents/math/src/components/math/deckdeckgo-math.tsx b/webcomponents/math/src/components/math/deckdeckgo-math.tsx new file mode 100644 index 000000000..8d3a074e4 --- /dev/null +++ b/webcomponents/math/src/components/math/deckdeckgo-math.tsx @@ -0,0 +1,162 @@ +import {Component, Prop, Watch, Element, h, State, Host, Event, EventEmitter} from '@stencil/core'; +import katex from 'katex'; +import {extractMath, Segment} from 'extract-math'; + +@Component({ + tag: 'deckgo-math', + styleUrl: 'deckdeckgo-math.scss', + shadow: true, +}) +export class DeckdeckgoMath { + @Element() el: HTMLElement; + + @Prop() editable: boolean = false; + + @State() editing: boolean = false; + + @Prop({reflectToAttr: true}) leqno: boolean = false; + @Watch('leqno') + async leqnoChanged() { + await this.parseSlottedMath(); + } + + @Prop({reflectToAttr: true}) fleqn: boolean = false; + @Watch('fleqn') + async fleqnChanged() { + await this.parseSlottedMath(); + } + + @Event() mathError!: EventEmitter; + @Event() private mathDidChange: EventEmitter; + + async componentDidLoad() { + await this.parseSlottedMath(); + } + async componentDidUpdate() { + await this.parseSlottedMath(); + } + private parseSlottedMath(): Promise { + const mathContent: HTMLElement = this.el.querySelector("[slot='math']"); + + if (mathContent) { + return this.parseMath(mathContent.innerHTML); + } else { + return new Promise((resolve) => { + resolve(); + }); + } + } + + private parseMath(mathContentHTML: string): Promise { + return new Promise(async (resolve, reject) => { + const container: HTMLElement = this.el.shadowRoot.querySelector('div.deckgo-math-container'); + + if (!mathContentHTML || mathContentHTML === undefined || mathContentHTML === '') { + resolve(); + return; + } + if (container) { + try { + container.children[0].innerHTML = ''; + + let div: HTMLElement = document.createElement('div'); + div.innerHTML = this.extractAndRenderMath(mathContentHTML); + + container.children[0].appendChild(div); + resolve(); + } catch (err) { + reject(err); + } + } + }); + } + + private extractAndRenderMath(mathContentHTML: string) { + let segments: Segment[] = extractMath(mathContentHTML); + let renderedHTML = ''; + segments.map((segment) => { + if (segment.math) { + try { + renderedHTML += katex.renderToString(segment.raw, { + displayMode: segment.type === 'display', + leqno: this.leqno, + fleqn: this.fleqn, + }); + } catch (error) { + if (error instanceof katex.ParseError) { + // KaTeX can't parse the expression + let message = ("Error in LaTeX '" + segment.raw + "': " + error.message).replace(/&/g, '&').replace(//g, '>'); + this.mathError.emit(message); + } else { + this.mathError.emit(error); //other error + } + } + } else { + renderedHTML += segment.value; + } + }); + return renderedHTML; + } + + private applyMath = async () => { + await this.stopEditing(); + + await this.parseSlottedMath(); + }; + private edit(): Promise { + return new Promise((resolve) => { + if (!this.editable) { + resolve(); + return; + } + + this.editing = true; + + const slottedMath: HTMLElement = this.el.querySelector("[slot='math']"); + + if (slottedMath) { + setTimeout(() => { + slottedMath.setAttribute('contentEditable', 'true'); + slottedMath.addEventListener('blur', this.applyMath, {once: true}); + + slottedMath.focus(); + }, 100); + } + + resolve(); + }); + } + private stopEditing(): Promise { + return new Promise((resolve) => { + this.editing = false; + + const slottedMath: HTMLElement = this.el.querySelector("[slot='math']"); + + if (slottedMath) { + slottedMath.removeAttribute('contentEditable'); + + if (slottedMath.innerHTML) { + slottedMath.innerHTML = slottedMath.innerHTML.trim(); + } + + this.mathDidChange.emit(this.el); + } + + resolve(); + }); + } + + render() { + return ( + +
this.edit()} onTouchStart={() => this.edit()}> +
+ +
+
+ ); + } +} diff --git a/webcomponents/math/src/components/math/readme.md b/webcomponents/math/src/components/math/readme.md new file mode 100644 index 000000000..eb8784aa9 --- /dev/null +++ b/webcomponents/math/src/components/math/readme.md @@ -0,0 +1,22 @@ +# deckdeckgo-code + + + +## Properties + +| Property | Attribute | Description | Type | Default | +| ---------- | ---------- | ----------- | --------- | ------- | +| `editable` | `editable` | | `boolean` | `false` | +| `fleqn` | `fleqn` | | `boolean` | `false` | +| `leqno` | `leqno` | | `boolean` | `false` | + +## Events + +| Event | Description | Type | +| --------------- | ----------- | -------------------------- | +| `mathDidChange` | | `CustomEvent` | +| `mathError` | | `CustomEvent` | + +--- + +_Built with [StencilJS](https://stenciljs.com/)_ diff --git a/webcomponents/math/src/index.html b/webcomponents/math/src/index.html new file mode 100644 index 000000000..9c3096941 --- /dev/null +++ b/webcomponents/math/src/index.html @@ -0,0 +1,25 @@ + + + + + + DeckDeckGo - Math + + + + + + + +
+
+ You can write math expression inside paragraph like this: $x + 1$ +
+
+ Inline formulas can be written with \$ e.g: $c = \pm\sqrt{a^2 + b^2}$ +
+
and displayed equations can be written using \$$ e.g: $$\sum_{i=1}^n 2^i$$ +
+
+ + diff --git a/webcomponents/math/src/index.ts b/webcomponents/math/src/index.ts new file mode 100644 index 000000000..07635cbbc --- /dev/null +++ b/webcomponents/math/src/index.ts @@ -0,0 +1 @@ +export * from './components'; diff --git a/webcomponents/math/stencil.config.ts b/webcomponents/math/stencil.config.ts new file mode 100644 index 000000000..fb3806f2b --- /dev/null +++ b/webcomponents/math/stencil.config.ts @@ -0,0 +1,24 @@ +import {Config} from '@stencil/core'; + +import {sass} from '@stencil/sass'; +import {postcss} from '@stencil/postcss'; +import autoprefixer from 'autoprefixer'; + +export const config: Config = { + namespace: 'deckdeckgo-math', + outputTargets: [ + { + type: 'dist', + }, + { + type: 'www', + serviceWorker: null, + }, + ], + plugins: [ + sass(), + postcss({ + plugins: [autoprefixer()], + }), + ], +}; diff --git a/webcomponents/math/tsconfig.json b/webcomponents/math/tsconfig.json new file mode 100644 index 000000000..1ba949095 --- /dev/null +++ b/webcomponents/math/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "allowSyntheticDefaultImports": true, + "allowUnreachableCode": false, + "declaration": false, + "experimentalDecorators": true, + "lib": ["dom", "es2017"], + "moduleResolution": "node", + "module": "esnext", + "target": "es2017", + "noUnusedLocals": true, + "noUnusedParameters": true, + "jsx": "react", + "jsxFactory": "h" + }, + "include": ["src", "types/jsx.d.ts"], + "exclude": ["node_modules"] +}