js-draw 1.19.1 → 1.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -1
 - package/dist/Editor.css +49 -7
 - package/dist/bundle.js +2 -2
 - package/dist/bundledStyles.js +1 -1
 - package/dist/cjs/SVGLoader/index.js +3 -1
 - package/dist/cjs/image/EditorImage.d.ts +2 -1
 - package/dist/cjs/image/EditorImage.js +101 -5
 - package/dist/cjs/rendering/renderers/CanvasRenderer.js +4 -4
 - package/dist/cjs/toolbar/localization.d.ts +1 -0
 - package/dist/cjs/toolbar/localization.js +1 -0
 - package/dist/cjs/toolbar/widgets/InsertImageWidget/ImageWrapper.d.ts +1 -0
 - package/dist/cjs/toolbar/widgets/InsertImageWidget/ImageWrapper.js +7 -0
 - package/dist/cjs/toolbar/widgets/InsertImageWidget/index.js +11 -3
 - package/dist/cjs/toolbar/widgets/components/makeFileInput.js +12 -1
 - package/dist/cjs/toolbar/widgets/components/makeSnappedList.js +69 -4
 - package/dist/cjs/tools/Eraser.js +22 -5
 - package/dist/cjs/tools/PanZoom.d.ts +54 -0
 - package/dist/cjs/tools/PanZoom.js +54 -2
 - package/dist/cjs/util/ReactiveValue.d.ts +4 -0
 - package/dist/cjs/util/ReactiveValue.js +5 -0
 - package/dist/cjs/version.js +1 -1
 - package/dist/mjs/SVGLoader/index.mjs +3 -1
 - package/dist/mjs/image/EditorImage.d.ts +2 -1
 - package/dist/mjs/image/EditorImage.mjs +101 -5
 - package/dist/mjs/rendering/renderers/CanvasRenderer.mjs +4 -4
 - package/dist/mjs/toolbar/localization.d.ts +1 -0
 - package/dist/mjs/toolbar/localization.mjs +1 -0
 - package/dist/mjs/toolbar/widgets/InsertImageWidget/ImageWrapper.d.ts +1 -0
 - package/dist/mjs/toolbar/widgets/InsertImageWidget/ImageWrapper.mjs +7 -0
 - package/dist/mjs/toolbar/widgets/InsertImageWidget/index.mjs +11 -3
 - package/dist/mjs/toolbar/widgets/components/makeFileInput.mjs +12 -1
 - package/dist/mjs/toolbar/widgets/components/makeSnappedList.mjs +69 -4
 - package/dist/mjs/tools/Eraser.mjs +22 -5
 - package/dist/mjs/tools/PanZoom.d.ts +54 -0
 - package/dist/mjs/tools/PanZoom.mjs +54 -2
 - package/dist/mjs/util/ReactiveValue.d.ts +4 -0
 - package/dist/mjs/util/ReactiveValue.mjs +5 -0
 - package/dist/mjs/version.mjs +1 -1
 - package/docs/img/readme-images/unsupported-elements--in-editor.png +0 -0
 - package/package.json +2 -2
 - package/src/toolbar/EdgeToolbar.scss +8 -3
 - package/src/toolbar/widgets/components/makeFileInput.scss +3 -2
 - package/src/toolbar/widgets/components/makeSnappedList.scss +58 -12
 
| 
         @@ -176,13 +176,21 @@ class InsertImageWidget extends BaseWidget { 
     | 
|
| 
       176 
176 
     | 
    
         
             
                        currentImage?.reset();
         
     | 
| 
       177 
177 
     | 
    
         
             
                    };
         
     | 
| 
       178 
178 
     | 
    
         
             
                    this.statusView.replaceChildren(sizeText);
         
     | 
| 
       179 
     | 
    
         
            -
                     
     | 
| 
       180 
     | 
    
         
            -
                    if (imageData.length > largeImageThreshold) {
         
     | 
| 
      
 179 
     | 
    
         
            +
                    if (currentImage?.isLarge()) {
         
     | 
| 
       181 
180 
     | 
    
         
             
                        this.statusView.appendChild(decreaseSizeButton);
         
     | 
| 
       182 
181 
     | 
    
         
             
                    }
         
     | 
| 
       183 
182 
     | 
    
         
             
                    else if (currentImage?.isChanged()) {
         
     | 
| 
       184 
183 
     | 
    
         
             
                        this.statusView.appendChild(resetSizeButton);
         
     | 
| 
       185 
184 
     | 
    
         
             
                    }
         
     | 
| 
      
 185 
     | 
    
         
            +
                    else {
         
     | 
| 
      
 186 
     | 
    
         
            +
                        const hasLargeOrChangedImages = this.images.get().some(image => image.data?.isChanged() || image.data?.isLarge());
         
     | 
| 
      
 187 
     | 
    
         
            +
                        if (hasLargeOrChangedImages) {
         
     | 
| 
      
 188 
     | 
    
         
            +
                            // Still show the button -- prevents the layout from readjusting while
         
     | 
| 
      
 189 
     | 
    
         
            +
                            // scrolling through the image list
         
     | 
| 
      
 190 
     | 
    
         
            +
                            decreaseSizeButton.disabled = true;
         
     | 
| 
      
 191 
     | 
    
         
            +
                            this.statusView.appendChild(decreaseSizeButton);
         
     | 
| 
      
 192 
     | 
    
         
            +
                        }
         
     | 
| 
      
 193 
     | 
    
         
            +
                    }
         
     | 
| 
       186 
194 
     | 
    
         
             
                }
         
     | 
| 
       187 
195 
     | 
    
         
             
                updateInputs() {
         
     | 
| 
       188 
196 
     | 
    
         
             
                    const resetInputs = () => {
         
     | 
| 
         @@ -220,7 +228,7 @@ class InsertImageWidget extends BaseWidget { 
     | 
|
| 
       220 
228 
     | 
    
         
             
                            }
         
     | 
| 
       221 
229 
     | 
    
         
             
                            const image = new Image();
         
     | 
| 
       222 
230 
     | 
    
         
             
                            image.src = imageWrapper.getBase64Url();
         
     | 
| 
       223 
     | 
    
         
            -
                            image.setAttribute('alt',  
     | 
| 
      
 231 
     | 
    
         
            +
                            image.setAttribute('alt', imageWrapper.getAltText());
         
     | 
| 
       224 
232 
     | 
    
         
             
                            let component;
         
     | 
| 
       225 
233 
     | 
    
         
             
                            try {
         
     | 
| 
       226 
234 
     | 
    
         
             
                                component = await ImageComponent.fromImage(image, transform);
         
     | 
| 
         @@ -42,7 +42,18 @@ const makeFileInput = (labelText, context, { accepts = '*', allowMultiSelect = f 
     | 
|
| 
       42 
42 
     | 
    
         
             
                        icon.style.display = 'none';
         
     | 
| 
       43 
43 
     | 
    
         
             
                    }
         
     | 
| 
       44 
44 
     | 
    
         
             
                    else if (files.length > 0) {
         
     | 
| 
       45 
     | 
    
         
            -
                         
     | 
| 
      
 45 
     | 
    
         
            +
                        const fileNames = files.map(file => file.name);
         
     | 
| 
      
 46 
     | 
    
         
            +
                        const maxNames = 5;
         
     | 
| 
      
 47 
     | 
    
         
            +
                        if (fileNames.length <= maxNames) {
         
     | 
| 
      
 48 
     | 
    
         
            +
                            descriptionText.textContent = fileNames.join('\n');
         
     | 
| 
      
 49 
     | 
    
         
            +
                        }
         
     | 
| 
      
 50 
     | 
    
         
            +
                        else {
         
     | 
| 
      
 51 
     | 
    
         
            +
                            const fileNamesToShow = fileNames.slice(0, maxNames - 1);
         
     | 
| 
      
 52 
     | 
    
         
            +
                            descriptionText.textContent = [
         
     | 
| 
      
 53 
     | 
    
         
            +
                                ...fileNamesToShow,
         
     | 
| 
      
 54 
     | 
    
         
            +
                                context.localization.fileInput__andNMoreFiles(fileNames.length - fileNamesToShow.length),
         
     | 
| 
      
 55 
     | 
    
         
            +
                            ].join('\n');
         
     | 
| 
      
 56 
     | 
    
         
            +
                        }
         
     | 
| 
       46 
57 
     | 
    
         
             
                        // Only show the icon when there are files
         
     | 
| 
       47 
58 
     | 
    
         
             
                        icon.style.display = 'none';
         
     | 
| 
       48 
59 
     | 
    
         
             
                    }
         
     | 
| 
         @@ -6,8 +6,72 @@ import  { MutableReactiveValue, ReactiveValue }  from '../../../util/ReactiveVal 
     | 
|
| 
       6 
6 
     | 
    
         
             
            const makeSnappedList = (itemsValue) => {
         
     | 
| 
       7 
7 
     | 
    
         
             
                const container = document.createElement('div');
         
     | 
| 
       8 
8 
     | 
    
         
             
                container.classList.add('toolbar-snapped-scroll-list');
         
     | 
| 
      
 9 
     | 
    
         
            +
                const scroller = document.createElement('div');
         
     | 
| 
      
 10 
     | 
    
         
            +
                scroller.classList.add('scroller');
         
     | 
| 
       9 
11 
     | 
    
         
             
                const visibleIndex = MutableReactiveValue.fromInitialValue(0);
         
     | 
| 
       10 
12 
     | 
    
         
             
                let observer = null;
         
     | 
| 
      
 13 
     | 
    
         
            +
                const makePageMarkers = () => {
         
     | 
| 
      
 14 
     | 
    
         
            +
                    const markerContainer = document.createElement('div');
         
     | 
| 
      
 15 
     | 
    
         
            +
                    markerContainer.classList.add('page-markers');
         
     | 
| 
      
 16 
     | 
    
         
            +
                    // Keyboard focus should go to the main scrolling list.
         
     | 
| 
      
 17 
     | 
    
         
            +
                    // TODO: Does it make sense for the page marker list to be focusable?
         
     | 
| 
      
 18 
     | 
    
         
            +
                    markerContainer.setAttribute('tabindex', '-1');
         
     | 
| 
      
 19 
     | 
    
         
            +
                    const markers = [];
         
     | 
| 
      
 20 
     | 
    
         
            +
                    const pairedItems = ReactiveValue.union([visibleIndex, itemsValue]);
         
     | 
| 
      
 21 
     | 
    
         
            +
                    pairedItems.onUpdateAndNow(([currentVisibleIndex, items]) => {
         
     | 
| 
      
 22 
     | 
    
         
            +
                        let addedOrRemovedMarkers = false;
         
     | 
| 
      
 23 
     | 
    
         
            +
                        // Items may have been removed from the list of pages. Make the markers reflect that.
         
     | 
| 
      
 24 
     | 
    
         
            +
                        while (items.length < markers.length) {
         
     | 
| 
      
 25 
     | 
    
         
            +
                            markers.pop();
         
     | 
| 
      
 26 
     | 
    
         
            +
                            addedOrRemovedMarkers = true;
         
     | 
| 
      
 27 
     | 
    
         
            +
                        }
         
     | 
| 
      
 28 
     | 
    
         
            +
                        let activeMarker;
         
     | 
| 
      
 29 
     | 
    
         
            +
                        for (let i = 0; i < items.length; i++) {
         
     | 
| 
      
 30 
     | 
    
         
            +
                            let marker;
         
     | 
| 
      
 31 
     | 
    
         
            +
                            if (i >= markers.length) {
         
     | 
| 
      
 32 
     | 
    
         
            +
                                marker = document.createElement('div');
         
     | 
| 
      
 33 
     | 
    
         
            +
                                // Use a separate content element to increase the clickable size of
         
     | 
| 
      
 34 
     | 
    
         
            +
                                // the marker.
         
     | 
| 
      
 35 
     | 
    
         
            +
                                const content = document.createElement('div');
         
     | 
| 
      
 36 
     | 
    
         
            +
                                content.classList.add('content');
         
     | 
| 
      
 37 
     | 
    
         
            +
                                marker.replaceChildren(content);
         
     | 
| 
      
 38 
     | 
    
         
            +
                                markers.push(marker);
         
     | 
| 
      
 39 
     | 
    
         
            +
                                addedOrRemovedMarkers = true;
         
     | 
| 
      
 40 
     | 
    
         
            +
                            }
         
     | 
| 
      
 41 
     | 
    
         
            +
                            else {
         
     | 
| 
      
 42 
     | 
    
         
            +
                                marker = markers[i];
         
     | 
| 
      
 43 
     | 
    
         
            +
                            }
         
     | 
| 
      
 44 
     | 
    
         
            +
                            marker.classList.add('marker');
         
     | 
| 
      
 45 
     | 
    
         
            +
                            if (i === currentVisibleIndex) {
         
     | 
| 
      
 46 
     | 
    
         
            +
                                marker.classList.add('-active');
         
     | 
| 
      
 47 
     | 
    
         
            +
                                activeMarker = marker;
         
     | 
| 
      
 48 
     | 
    
         
            +
                            }
         
     | 
| 
      
 49 
     | 
    
         
            +
                            else {
         
     | 
| 
      
 50 
     | 
    
         
            +
                                marker.classList.remove('-active');
         
     | 
| 
      
 51 
     | 
    
         
            +
                            }
         
     | 
| 
      
 52 
     | 
    
         
            +
                            const markerIndex = i;
         
     | 
| 
      
 53 
     | 
    
         
            +
                            marker.onclick = () => {
         
     | 
| 
      
 54 
     | 
    
         
            +
                                wrappedItems.get()[markerIndex]?.element?.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
         
     | 
| 
      
 55 
     | 
    
         
            +
                            };
         
     | 
| 
      
 56 
     | 
    
         
            +
                        }
         
     | 
| 
      
 57 
     | 
    
         
            +
                        // Only call .replaceChildren when necessary -- doing so on every change would
         
     | 
| 
      
 58 
     | 
    
         
            +
                        // break transitions.
         
     | 
| 
      
 59 
     | 
    
         
            +
                        if (addedOrRemovedMarkers) {
         
     | 
| 
      
 60 
     | 
    
         
            +
                            markerContainer.replaceChildren(...markers);
         
     | 
| 
      
 61 
     | 
    
         
            +
                        }
         
     | 
| 
      
 62 
     | 
    
         
            +
                        // Handles the case where there are many markers and the current is offscreen
         
     | 
| 
      
 63 
     | 
    
         
            +
                        if (activeMarker && markerContainer.scrollHeight > container.clientHeight) {
         
     | 
| 
      
 64 
     | 
    
         
            +
                            activeMarker.scrollIntoView({ block: 'nearest' });
         
     | 
| 
      
 65 
     | 
    
         
            +
                        }
         
     | 
| 
      
 66 
     | 
    
         
            +
                        if (markers.length === 1) {
         
     | 
| 
      
 67 
     | 
    
         
            +
                            markerContainer.classList.add('-one-element');
         
     | 
| 
      
 68 
     | 
    
         
            +
                        }
         
     | 
| 
      
 69 
     | 
    
         
            +
                        else {
         
     | 
| 
      
 70 
     | 
    
         
            +
                            markerContainer.classList.remove('-one-element');
         
     | 
| 
      
 71 
     | 
    
         
            +
                        }
         
     | 
| 
      
 72 
     | 
    
         
            +
                    });
         
     | 
| 
      
 73 
     | 
    
         
            +
                    return markerContainer;
         
     | 
| 
      
 74 
     | 
    
         
            +
                };
         
     | 
| 
       11 
75 
     | 
    
         
             
                const createObserver = () => {
         
     | 
| 
       12 
76 
     | 
    
         
             
                    observer = new IntersectionObserver((entries) => {
         
     | 
| 
       13 
77 
     | 
    
         
             
                        for (const entry of entries) {
         
     | 
| 
         @@ -23,7 +87,7 @@ const makeSnappedList = (itemsValue) => { 
     | 
|
| 
       23 
87 
     | 
    
         
             
                    }, {
         
     | 
| 
       24 
88 
     | 
    
         
             
                        // Element to use as the boudning box with which to intersect.
         
     | 
| 
       25 
89 
     | 
    
         
             
                        // See https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
         
     | 
| 
       26 
     | 
    
         
            -
                        root:  
     | 
| 
      
 90 
     | 
    
         
            +
                        root: scroller,
         
     | 
| 
       27 
91 
     | 
    
         
             
                        // Fraction of an element that must be visible to trigger the callback:
         
     | 
| 
       28 
92 
     | 
    
         
             
                        threshold: 0.9,
         
     | 
| 
       29 
93 
     | 
    
         
             
                    });
         
     | 
| 
         @@ -55,7 +119,7 @@ const makeSnappedList = (itemsValue) => { 
     | 
|
| 
       55 
119 
     | 
    
         
             
                    for (const item of lastItems) {
         
     | 
| 
       56 
120 
     | 
    
         
             
                        observer?.unobserve(item.element);
         
     | 
| 
       57 
121 
     | 
    
         
             
                    }
         
     | 
| 
       58 
     | 
    
         
            -
                     
     | 
| 
      
 122 
     | 
    
         
            +
                    scroller.replaceChildren();
         
     | 
| 
       59 
123 
     | 
    
         
             
                    // An observer is only necessary if there are multiple items to scroll through.
         
     | 
| 
       60 
124 
     | 
    
         
             
                    if (items.length > 1) {
         
     | 
| 
       61 
125 
     | 
    
         
             
                        createObserver();
         
     | 
| 
         @@ -71,7 +135,7 @@ const makeSnappedList = (itemsValue) => { 
     | 
|
| 
       71 
135 
     | 
    
         
             
                        container.classList.remove('-empty');
         
     | 
| 
       72 
136 
     | 
    
         
             
                    }
         
     | 
| 
       73 
137 
     | 
    
         
             
                    for (const item of items) {
         
     | 
| 
       74 
     | 
    
         
            -
                         
     | 
| 
      
 138 
     | 
    
         
            +
                        scroller.appendChild(item.element);
         
     | 
| 
       75 
139 
     | 
    
         
             
                    }
         
     | 
| 
       76 
140 
     | 
    
         
             
                    visibleIndex.set(0);
         
     | 
| 
       77 
141 
     | 
    
         
             
                    if (observer) {
         
     | 
| 
         @@ -89,7 +153,8 @@ const makeSnappedList = (itemsValue) => { 
     | 
|
| 
       89 
153 
     | 
    
         
             
                });
         
     | 
| 
       90 
154 
     | 
    
         
             
                // makeSnappedList is generally shown within the toolbar. This allows users to
         
     | 
| 
       91 
155 
     | 
    
         
             
                // scroll it with a touchpad.
         
     | 
| 
       92 
     | 
    
         
            -
                stopPropagationOfScrollingWheelEvents( 
     | 
| 
      
 156 
     | 
    
         
            +
                stopPropagationOfScrollingWheelEvents(scroller);
         
     | 
| 
      
 157 
     | 
    
         
            +
                container.replaceChildren(makePageMarkers(), scroller);
         
     | 
| 
       93 
158 
     | 
    
         
             
                return {
         
     | 
| 
       94 
159 
     | 
    
         
             
                    container,
         
     | 
| 
       95 
160 
     | 
    
         
             
                    visibleItem,
         
     | 
| 
         @@ -65,6 +65,7 @@ export default class Eraser extends BaseTool { 
     | 
|
| 
       65 
65 
     | 
    
         
             
                    this.editor = editor;
         
     | 
| 
       66 
66 
     | 
    
         
             
                    this.lastPoint = null;
         
     | 
| 
       67 
67 
     | 
    
         
             
                    this.isFirstEraseEvt = true;
         
     | 
| 
      
 68 
     | 
    
         
            +
                    this.toAdd = new Set();
         
     | 
| 
       68 
69 
     | 
    
         
             
                    // Commands that each remove one element
         
     | 
| 
       69 
70 
     | 
    
         
             
                    this.eraseCommands = [];
         
     | 
| 
       70 
71 
     | 
    
         
             
                    this.addCommands = [];
         
     | 
| 
         @@ -174,15 +175,17 @@ export default class Eraser extends BaseTool { 
     | 
|
| 
       174 
175 
     | 
    
         
             
                        newAddCommands.forEach(command => command.apply(this.editor));
         
     | 
| 
       175 
176 
     | 
    
         
             
                        const finalToErase = [];
         
     | 
| 
       176 
177 
     | 
    
         
             
                        for (const item of toErase) {
         
     | 
| 
       177 
     | 
    
         
            -
                            if (this.toAdd. 
     | 
| 
       178 
     | 
    
         
            -
                                this.toAdd 
     | 
| 
      
 178 
     | 
    
         
            +
                            if (this.toAdd.has(item)) {
         
     | 
| 
      
 179 
     | 
    
         
            +
                                this.toAdd.delete(item);
         
     | 
| 
       179 
180 
     | 
    
         
             
                            }
         
     | 
| 
       180 
181 
     | 
    
         
             
                            else {
         
     | 
| 
       181 
182 
     | 
    
         
             
                                finalToErase.push(item);
         
     | 
| 
       182 
183 
     | 
    
         
             
                            }
         
     | 
| 
       183 
184 
     | 
    
         
             
                        }
         
     | 
| 
       184 
185 
     | 
    
         
             
                        this.toRemove.push(...finalToErase);
         
     | 
| 
       185 
     | 
    
         
            -
                         
     | 
| 
      
 186 
     | 
    
         
            +
                        for (const item of toAdd) {
         
     | 
| 
      
 187 
     | 
    
         
            +
                            this.toAdd.add(item);
         
     | 
| 
      
 188 
     | 
    
         
            +
                        }
         
     | 
| 
       186 
189 
     | 
    
         
             
                        this.eraseCommands.push(new Erase(finalToErase));
         
     | 
| 
       187 
190 
     | 
    
         
             
                        this.addCommands.push(...newAddCommands);
         
     | 
| 
       188 
191 
     | 
    
         
             
                    }
         
     | 
| 
         @@ -193,7 +196,7 @@ export default class Eraser extends BaseTool { 
     | 
|
| 
       193 
196 
     | 
    
         
             
                    if (event.allPointers.length === 1 || event.current.device === PointerDevice.Eraser) {
         
     | 
| 
       194 
197 
     | 
    
         
             
                        this.lastPoint = event.current.canvasPos;
         
     | 
| 
       195 
198 
     | 
    
         
             
                        this.toRemove = [];
         
     | 
| 
       196 
     | 
    
         
            -
                        this.toAdd 
     | 
| 
      
 199 
     | 
    
         
            +
                        this.toAdd.clear();
         
     | 
| 
       197 
200 
     | 
    
         
             
                        this.isFirstEraseEvt = true;
         
     | 
| 
       198 
201 
     | 
    
         
             
                        this.drawPreviewAt(event.current.canvasPos);
         
     | 
| 
       199 
202 
     | 
    
         
             
                        return true;
         
     | 
| 
         @@ -209,7 +212,21 @@ export default class Eraser extends BaseTool { 
     | 
|
| 
       209 
212 
     | 
    
         
             
                    const commands = [];
         
     | 
| 
       210 
213 
     | 
    
         
             
                    if (this.addCommands.length > 0) {
         
     | 
| 
       211 
214 
     | 
    
         
             
                        this.addCommands.forEach(cmd => cmd.unapply(this.editor));
         
     | 
| 
       212 
     | 
    
         
            -
                         
     | 
| 
      
 215 
     | 
    
         
            +
                        // Remove items from toAdd that are also present in toRemove -- adding, then
         
     | 
| 
      
 216 
     | 
    
         
            +
                        // removing these does nothing, and can break undo/redo.
         
     | 
| 
      
 217 
     | 
    
         
            +
                        for (const item of this.toAdd) {
         
     | 
| 
      
 218 
     | 
    
         
            +
                            if (this.toRemove.includes(item)) {
         
     | 
| 
      
 219 
     | 
    
         
            +
                                this.toAdd.delete(item);
         
     | 
| 
      
 220 
     | 
    
         
            +
                                this.toRemove = this.toRemove.filter(other => other !== item);
         
     | 
| 
      
 221 
     | 
    
         
            +
                            }
         
     | 
| 
      
 222 
     | 
    
         
            +
                        }
         
     | 
| 
      
 223 
     | 
    
         
            +
                        for (const item of this.toRemove) {
         
     | 
| 
      
 224 
     | 
    
         
            +
                            if (this.toAdd.has(item)) {
         
     | 
| 
      
 225 
     | 
    
         
            +
                                this.toAdd.delete(item);
         
     | 
| 
      
 226 
     | 
    
         
            +
                                this.toRemove = this.toRemove.filter(other => other !== item);
         
     | 
| 
      
 227 
     | 
    
         
            +
                            }
         
     | 
| 
      
 228 
     | 
    
         
            +
                        }
         
     | 
| 
      
 229 
     | 
    
         
            +
                        commands.push(...[...this.toAdd].map(a => EditorImage.addElement(a)));
         
     | 
| 
       213 
230 
     | 
    
         
             
                        this.addCommands = [];
         
     | 
| 
       214 
231 
     | 
    
         
             
                    }
         
     | 
| 
       215 
232 
     | 
    
         
             
                    if (this.eraseCommands.length > 0) {
         
     | 
| 
         @@ -10,13 +10,27 @@ interface PinchData { 
     | 
|
| 
       10 
10 
     | 
    
         
             
                dist: number;
         
     | 
| 
       11 
11 
     | 
    
         
             
            }
         
     | 
| 
       12 
12 
     | 
    
         
             
            export declare enum PanZoomMode {
         
     | 
| 
      
 13 
     | 
    
         
            +
                /** Touch gestures with a single pointer. Ignores non-touch gestures. */
         
     | 
| 
       13 
14 
     | 
    
         
             
                OneFingerTouchGestures = 1,
         
     | 
| 
      
 15 
     | 
    
         
            +
                /** Touch gestures with exactly two pointers. Ignores non-touch gestures. */
         
     | 
| 
       14 
16 
     | 
    
         
             
                TwoFingerTouchGestures = 2,
         
     | 
| 
       15 
17 
     | 
    
         
             
                RightClickDrags = 4,
         
     | 
| 
      
 18 
     | 
    
         
            +
                /** Single-pointer gestures of *any* type (including touch). */
         
     | 
| 
       16 
19 
     | 
    
         
             
                SinglePointerGestures = 8,
         
     | 
| 
      
 20 
     | 
    
         
            +
                /** Keyboard navigation (e.g. LeftArrow to move left). */
         
     | 
| 
       17 
21 
     | 
    
         
             
                Keyboard = 16,
         
     | 
| 
      
 22 
     | 
    
         
            +
                /** If provided, prevents **this** tool from rotating the viewport (other tools may still do so). */
         
     | 
| 
       18 
23 
     | 
    
         
             
                RotationLocked = 32
         
     | 
| 
       19 
24 
     | 
    
         
             
            }
         
     | 
| 
      
 25 
     | 
    
         
            +
            /**
         
     | 
| 
      
 26 
     | 
    
         
            +
             * This tool moves the viewport in response to touchpad, touchscreen, mouse, and keyboard events.
         
     | 
| 
      
 27 
     | 
    
         
            +
             *
         
     | 
| 
      
 28 
     | 
    
         
            +
             * Which events are handled, and which are skipped, are determined by the tool's `mode`. For example,
         
     | 
| 
      
 29 
     | 
    
         
            +
             * a `PanZoom` tool with `mode = PanZoomMode.TwoFingerTouchGestures|PanZoomMode.RightClickDrags` would
         
     | 
| 
      
 30 
     | 
    
         
            +
             * respond to right-click drag events and two-finger touch gestures.
         
     | 
| 
      
 31 
     | 
    
         
            +
             *
         
     | 
| 
      
 32 
     | 
    
         
            +
             * @see {@link setModeEnabled}
         
     | 
| 
      
 33 
     | 
    
         
            +
             */
         
     | 
| 
       20 
34 
     | 
    
         
             
            export default class PanZoom extends BaseTool {
         
     | 
| 
       21 
35 
     | 
    
         
             
                private editor;
         
     | 
| 
       22 
36 
     | 
    
         
             
                private mode;
         
     | 
| 
         @@ -58,8 +72,48 @@ export default class PanZoom extends BaseTool { 
     | 
|
| 
       58 
72 
     | 
    
         
             
                onWheel({ delta, screenPos }: WheelEvt): boolean;
         
     | 
| 
       59 
73 
     | 
    
         
             
                onKeyPress(event: KeyPressEvent): boolean;
         
     | 
| 
       60 
74 
     | 
    
         
             
                private isRotationLocked;
         
     | 
| 
      
 75 
     | 
    
         
            +
                /**
         
     | 
| 
      
 76 
     | 
    
         
            +
                 * Changes the types of gestures used by this pan/zoom tool.
         
     | 
| 
      
 77 
     | 
    
         
            +
                 *
         
     | 
| 
      
 78 
     | 
    
         
            +
                 * @see {@link PanZoomMode} {@link setMode}
         
     | 
| 
      
 79 
     | 
    
         
            +
                 *
         
     | 
| 
      
 80 
     | 
    
         
            +
                 * @example
         
     | 
| 
      
 81 
     | 
    
         
            +
                 * ```ts,runnable
         
     | 
| 
      
 82 
     | 
    
         
            +
                 * import { Editor, PanZoomTool, PanZoomMode } from 'js-draw';
         
     | 
| 
      
 83 
     | 
    
         
            +
                 *
         
     | 
| 
      
 84 
     | 
    
         
            +
                 * const editor = new Editor(document.body);
         
     | 
| 
      
 85 
     | 
    
         
            +
                 *
         
     | 
| 
      
 86 
     | 
    
         
            +
                 * // By default, there are multiple PanZoom tools that handle different events.
         
     | 
| 
      
 87 
     | 
    
         
            +
                 * // This gets all PanZoomTools.
         
     | 
| 
      
 88 
     | 
    
         
            +
                 * const panZoomToolList = editor.toolController.getMatchingTools(PanZoomTool);
         
     | 
| 
      
 89 
     | 
    
         
            +
                 *
         
     | 
| 
      
 90 
     | 
    
         
            +
                 * // The first PanZoomTool is the highest priority -- by default,
         
     | 
| 
      
 91 
     | 
    
         
            +
                 * // this tool is responsible for handling multi-finger touch gestures.
         
     | 
| 
      
 92 
     | 
    
         
            +
                 * //
         
     | 
| 
      
 93 
     | 
    
         
            +
                 * // Lower-priority PanZoomTools handle one-finger touch gestures and
         
     | 
| 
      
 94 
     | 
    
         
            +
                 * // key-presses.
         
     | 
| 
      
 95 
     | 
    
         
            +
                 * const panZoomTool = panZoomToolList[0];
         
     | 
| 
      
 96 
     | 
    
         
            +
                 *
         
     | 
| 
      
 97 
     | 
    
         
            +
                 * // Lock rotation for multi-finger touch gestures.
         
     | 
| 
      
 98 
     | 
    
         
            +
                 * panZoomTool.setModeEnabled(PanZoomMode.RotationLocked, true);
         
     | 
| 
      
 99 
     | 
    
         
            +
                 * ```
         
     | 
| 
      
 100 
     | 
    
         
            +
                 */
         
     | 
| 
       61 
101 
     | 
    
         
             
                setModeEnabled(mode: PanZoomMode, enabled: boolean): void;
         
     | 
| 
      
 102 
     | 
    
         
            +
                /**
         
     | 
| 
      
 103 
     | 
    
         
            +
                 * Sets all modes for this tool using a bitmask.
         
     | 
| 
      
 104 
     | 
    
         
            +
                 *
         
     | 
| 
      
 105 
     | 
    
         
            +
                 * @see {@link setModeEnabled}
         
     | 
| 
      
 106 
     | 
    
         
            +
                 *
         
     | 
| 
      
 107 
     | 
    
         
            +
                 * @example
         
     | 
| 
      
 108 
     | 
    
         
            +
                 * ```ts
         
     | 
| 
      
 109 
     | 
    
         
            +
                 * tool.setMode(PanZoomMode.RotationLocked|PanZoomMode.TwoFingerTouchGestures);
         
     | 
| 
      
 110 
     | 
    
         
            +
                 * ```
         
     | 
| 
      
 111 
     | 
    
         
            +
                 */
         
     | 
| 
       62 
112 
     | 
    
         
             
                setMode(mode: PanZoomMode): void;
         
     | 
| 
      
 113 
     | 
    
         
            +
                /**
         
     | 
| 
      
 114 
     | 
    
         
            +
                 * Returns a bitmask indicating the currently-enabled modes.
         
     | 
| 
      
 115 
     | 
    
         
            +
                 * @see {@link setModeEnabled}
         
     | 
| 
      
 116 
     | 
    
         
            +
                 */
         
     | 
| 
       63 
117 
     | 
    
         
             
                getMode(): PanZoomMode;
         
     | 
| 
       64 
118 
     | 
    
         
             
            }
         
     | 
| 
       65 
119 
     | 
    
         
             
            export {};
         
     | 
| 
         @@ -7,11 +7,16 @@ import  BaseTool  from './BaseTool.mjs'; 
     | 
|
| 
       7 
7 
     | 
    
         
             
            import  { moveDownKeyboardShortcutId, moveLeftKeyboardShortcutId, moveRightKeyboardShortcutId, moveUpKeyboardShortcutId, rotateClockwiseKeyboardShortcutId, rotateCounterClockwiseKeyboardShortcutId, zoomInKeyboardShortcutId, zoomOutKeyboardShortcutId }  from './keybindings.mjs';
         
     | 
| 
       8 
8 
     | 
    
         
             
            export var PanZoomMode;
         
     | 
| 
       9 
9 
     | 
    
         
             
            (function (PanZoomMode) {
         
     | 
| 
      
 10 
     | 
    
         
            +
                /** Touch gestures with a single pointer. Ignores non-touch gestures. */
         
     | 
| 
       10 
11 
     | 
    
         
             
                PanZoomMode[PanZoomMode["OneFingerTouchGestures"] = 1] = "OneFingerTouchGestures";
         
     | 
| 
      
 12 
     | 
    
         
            +
                /** Touch gestures with exactly two pointers. Ignores non-touch gestures. */
         
     | 
| 
       11 
13 
     | 
    
         
             
                PanZoomMode[PanZoomMode["TwoFingerTouchGestures"] = 2] = "TwoFingerTouchGestures";
         
     | 
| 
       12 
14 
     | 
    
         
             
                PanZoomMode[PanZoomMode["RightClickDrags"] = 4] = "RightClickDrags";
         
     | 
| 
      
 15 
     | 
    
         
            +
                /** Single-pointer gestures of *any* type (including touch). */
         
     | 
| 
       13 
16 
     | 
    
         
             
                PanZoomMode[PanZoomMode["SinglePointerGestures"] = 8] = "SinglePointerGestures";
         
     | 
| 
      
 17 
     | 
    
         
            +
                /** Keyboard navigation (e.g. LeftArrow to move left). */
         
     | 
| 
       14 
18 
     | 
    
         
             
                PanZoomMode[PanZoomMode["Keyboard"] = 16] = "Keyboard";
         
     | 
| 
      
 19 
     | 
    
         
            +
                /** If provided, prevents **this** tool from rotating the viewport (other tools may still do so). */
         
     | 
| 
       15 
20 
     | 
    
         
             
                PanZoomMode[PanZoomMode["RotationLocked"] = 32] = "RotationLocked";
         
     | 
| 
       16 
21 
     | 
    
         
             
            })(PanZoomMode || (PanZoomMode = {}));
         
     | 
| 
       17 
22 
     | 
    
         
             
            class InertialScroller {
         
     | 
| 
         @@ -59,6 +64,15 @@ class InertialScroller { 
     | 
|
| 
       59 
64 
     | 
    
         
             
                    }
         
     | 
| 
       60 
65 
     | 
    
         
             
                }
         
     | 
| 
       61 
66 
     | 
    
         
             
            }
         
     | 
| 
      
 67 
     | 
    
         
            +
            /**
         
     | 
| 
      
 68 
     | 
    
         
            +
             * This tool moves the viewport in response to touchpad, touchscreen, mouse, and keyboard events.
         
     | 
| 
      
 69 
     | 
    
         
            +
             *
         
     | 
| 
      
 70 
     | 
    
         
            +
             * Which events are handled, and which are skipped, are determined by the tool's `mode`. For example,
         
     | 
| 
      
 71 
     | 
    
         
            +
             * a `PanZoom` tool with `mode = PanZoomMode.TwoFingerTouchGestures|PanZoomMode.RightClickDrags` would
         
     | 
| 
      
 72 
     | 
    
         
            +
             * respond to right-click drag events and two-finger touch gestures.
         
     | 
| 
      
 73 
     | 
    
         
            +
             *
         
     | 
| 
      
 74 
     | 
    
         
            +
             * @see {@link setModeEnabled}
         
     | 
| 
      
 75 
     | 
    
         
            +
             */
         
     | 
| 
       62 
76 
     | 
    
         
             
            export default class PanZoom extends BaseTool {
         
     | 
| 
       63 
77 
     | 
    
         
             
                constructor(editor, mode, description) {
         
     | 
| 
       64 
78 
     | 
    
         
             
                    super(editor.notifier, description);
         
     | 
| 
         @@ -422,8 +436,32 @@ export default class PanZoom extends BaseTool { 
     | 
|
| 
       422 
436 
     | 
    
         
             
                isRotationLocked() {
         
     | 
| 
       423 
437 
     | 
    
         
             
                    return !!(this.mode & PanZoomMode.RotationLocked);
         
     | 
| 
       424 
438 
     | 
    
         
             
                }
         
     | 
| 
       425 
     | 
    
         
            -
                 
     | 
| 
       426 
     | 
    
         
            -
             
     | 
| 
      
 439 
     | 
    
         
            +
                /**
         
     | 
| 
      
 440 
     | 
    
         
            +
                 * Changes the types of gestures used by this pan/zoom tool.
         
     | 
| 
      
 441 
     | 
    
         
            +
                 *
         
     | 
| 
      
 442 
     | 
    
         
            +
                 * @see {@link PanZoomMode} {@link setMode}
         
     | 
| 
      
 443 
     | 
    
         
            +
                 *
         
     | 
| 
      
 444 
     | 
    
         
            +
                 * @example
         
     | 
| 
      
 445 
     | 
    
         
            +
                 * ```ts,runnable
         
     | 
| 
      
 446 
     | 
    
         
            +
                 * import { Editor, PanZoomTool, PanZoomMode } from 'js-draw';
         
     | 
| 
      
 447 
     | 
    
         
            +
                 *
         
     | 
| 
      
 448 
     | 
    
         
            +
                 * const editor = new Editor(document.body);
         
     | 
| 
      
 449 
     | 
    
         
            +
                 *
         
     | 
| 
      
 450 
     | 
    
         
            +
                 * // By default, there are multiple PanZoom tools that handle different events.
         
     | 
| 
      
 451 
     | 
    
         
            +
                 * // This gets all PanZoomTools.
         
     | 
| 
      
 452 
     | 
    
         
            +
                 * const panZoomToolList = editor.toolController.getMatchingTools(PanZoomTool);
         
     | 
| 
      
 453 
     | 
    
         
            +
                 *
         
     | 
| 
      
 454 
     | 
    
         
            +
                 * // The first PanZoomTool is the highest priority -- by default,
         
     | 
| 
      
 455 
     | 
    
         
            +
                 * // this tool is responsible for handling multi-finger touch gestures.
         
     | 
| 
      
 456 
     | 
    
         
            +
                 * //
         
     | 
| 
      
 457 
     | 
    
         
            +
                 * // Lower-priority PanZoomTools handle one-finger touch gestures and
         
     | 
| 
      
 458 
     | 
    
         
            +
                 * // key-presses.
         
     | 
| 
      
 459 
     | 
    
         
            +
                 * const panZoomTool = panZoomToolList[0];
         
     | 
| 
      
 460 
     | 
    
         
            +
                 *
         
     | 
| 
      
 461 
     | 
    
         
            +
                 * // Lock rotation for multi-finger touch gestures.
         
     | 
| 
      
 462 
     | 
    
         
            +
                 * panZoomTool.setModeEnabled(PanZoomMode.RotationLocked, true);
         
     | 
| 
      
 463 
     | 
    
         
            +
                 * ```
         
     | 
| 
      
 464 
     | 
    
         
            +
                 */
         
     | 
| 
       427 
465 
     | 
    
         
             
                setModeEnabled(mode, enabled) {
         
     | 
| 
       428 
466 
     | 
    
         
             
                    let newMode = this.mode;
         
     | 
| 
       429 
467 
     | 
    
         
             
                    if (enabled) {
         
     | 
| 
         @@ -434,6 +472,16 @@ export default class PanZoom extends BaseTool { 
     | 
|
| 
       434 
472 
     | 
    
         
             
                    }
         
     | 
| 
       435 
473 
     | 
    
         
             
                    this.setMode(newMode);
         
     | 
| 
       436 
474 
     | 
    
         
             
                }
         
     | 
| 
      
 475 
     | 
    
         
            +
                /**
         
     | 
| 
      
 476 
     | 
    
         
            +
                 * Sets all modes for this tool using a bitmask.
         
     | 
| 
      
 477 
     | 
    
         
            +
                 *
         
     | 
| 
      
 478 
     | 
    
         
            +
                 * @see {@link setModeEnabled}
         
     | 
| 
      
 479 
     | 
    
         
            +
                 *
         
     | 
| 
      
 480 
     | 
    
         
            +
                 * @example
         
     | 
| 
      
 481 
     | 
    
         
            +
                 * ```ts
         
     | 
| 
      
 482 
     | 
    
         
            +
                 * tool.setMode(PanZoomMode.RotationLocked|PanZoomMode.TwoFingerTouchGestures);
         
     | 
| 
      
 483 
     | 
    
         
            +
                 * ```
         
     | 
| 
      
 484 
     | 
    
         
            +
                 */
         
     | 
| 
       437 
485 
     | 
    
         
             
                setMode(mode) {
         
     | 
| 
       438 
486 
     | 
    
         
             
                    if (mode !== this.mode) {
         
     | 
| 
       439 
487 
     | 
    
         
             
                        this.mode = mode;
         
     | 
| 
         @@ -443,6 +491,10 @@ export default class PanZoom extends BaseTool { 
     | 
|
| 
       443 
491 
     | 
    
         
             
                        });
         
     | 
| 
       444 
492 
     | 
    
         
             
                    }
         
     | 
| 
       445 
493 
     | 
    
         
             
                }
         
     | 
| 
      
 494 
     | 
    
         
            +
                /**
         
     | 
| 
      
 495 
     | 
    
         
            +
                 * Returns a bitmask indicating the currently-enabled modes.
         
     | 
| 
      
 496 
     | 
    
         
            +
                 * @see {@link setModeEnabled}
         
     | 
| 
      
 497 
     | 
    
         
            +
                 */
         
     | 
| 
       446 
498 
     | 
    
         
             
                getMode() {
         
     | 
| 
       447 
499 
     | 
    
         
             
                    return this.mode;
         
     | 
| 
       448 
500 
     | 
    
         
             
                }
         
     | 
| 
         @@ -2,6 +2,9 @@ type ListenerResult = { 
     | 
|
| 
       2 
2 
     | 
    
         
             
                remove(): void;
         
     | 
| 
       3 
3 
     | 
    
         
             
            };
         
     | 
| 
       4 
4 
     | 
    
         
             
            type UpdateCallback<T> = (value: T) => void;
         
     | 
| 
      
 5 
     | 
    
         
            +
            type ReactiveValuesOf<T extends unknown[]> = {
         
     | 
| 
      
 6 
     | 
    
         
            +
                [key in keyof T]: ReactiveValue<T[key]>;
         
     | 
| 
      
 7 
     | 
    
         
            +
            };
         
     | 
| 
       5 
8 
     | 
    
         
             
            /**
         
     | 
| 
       6 
9 
     | 
    
         
             
             * A `ReactiveValue` is a value that
         
     | 
| 
       7 
10 
     | 
    
         
             
             * - updates periodically,
         
     | 
| 
         @@ -56,6 +59,7 @@ export declare abstract class ReactiveValue<T> { 
     | 
|
| 
       56 
59 
     | 
    
         
             
                 * Returns a reactive value derived from a single `source`.
         
     | 
| 
       57 
60 
     | 
    
         
             
                 */
         
     | 
| 
       58 
61 
     | 
    
         
             
                static map<A, B>(source: ReactiveValue<A>, map: (a: A) => B, inverseMap: (b: B) => A): MutableReactiveValue<B>;
         
     | 
| 
      
 62 
     | 
    
         
            +
                static union<Values extends [...unknown[]]>(values: ReactiveValuesOf<Values>): ReactiveValue<Values>;
         
     | 
| 
       59 
63 
     | 
    
         
             
            }
         
     | 
| 
       60 
64 
     | 
    
         
             
            export declare abstract class MutableReactiveValue<T> extends ReactiveValue<T> {
         
     | 
| 
       61 
65 
     | 
    
         
             
                /**
         
     | 
| 
         @@ -103,6 +103,11 @@ export class ReactiveValue { 
     | 
|
| 
       103 
103 
     | 
    
         
             
                    }
         
     | 
| 
       104 
104 
     | 
    
         
             
                    return result;
         
     | 
| 
       105 
105 
     | 
    
         
             
                }
         
     | 
| 
      
 106 
     | 
    
         
            +
                static union(values) {
         
     | 
| 
      
 107 
     | 
    
         
            +
                    return ReactiveValue.fromCallback(() => {
         
     | 
| 
      
 108 
     | 
    
         
            +
                        return values.map(value => value.get());
         
     | 
| 
      
 109 
     | 
    
         
            +
                    }, values);
         
     | 
| 
      
 110 
     | 
    
         
            +
                }
         
     | 
| 
       106 
111 
     | 
    
         
             
            }
         
     | 
| 
       107 
112 
     | 
    
         
             
            export class MutableReactiveValue extends ReactiveValue {
         
     | 
| 
       108 
113 
     | 
    
         
             
                static fromProperty(sourceValue, propertyName) {
         
     | 
    
        package/dist/mjs/version.mjs
    CHANGED
    
    
| 
         Binary file 
     | 
    
        package/package.json
    CHANGED
    
    | 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            {
         
     | 
| 
       2 
2 
     | 
    
         
             
              "name": "js-draw",
         
     | 
| 
       3 
     | 
    
         
            -
              "version": "1. 
     | 
| 
      
 3 
     | 
    
         
            +
              "version": "1.20.1",
         
     | 
| 
       4 
4 
     | 
    
         
             
              "description": "Draw pictures using a pen, touchscreen, or mouse! JS-draw is a drawing library for JavaScript and TypeScript. ",
         
     | 
| 
       5 
5 
     | 
    
         
             
              "types": "./dist/mjs/lib.d.ts",
         
     | 
| 
       6 
6 
     | 
    
         
             
              "main": "./dist/cjs/lib.js",
         
     | 
| 
         @@ -86,5 +86,5 @@ 
     | 
|
| 
       86 
86 
     | 
    
         
             
                "freehand",
         
     | 
| 
       87 
87 
     | 
    
         
             
                "svg"
         
     | 
| 
       88 
88 
     | 
    
         
             
              ],
         
     | 
| 
       89 
     | 
    
         
            -
              "gitHead": " 
     | 
| 
      
 89 
     | 
    
         
            +
              "gitHead": "a981ae8ef5f2ac8ef27c8ce2872a2dbf0c25050d"
         
     | 
| 
       90 
90 
     | 
    
         
             
            }
         
     | 
| 
         @@ -307,14 +307,19 @@ 
     | 
|
| 
       307 
307 
     | 
    
         
             
            		border: none;
         
     | 
| 
       308 
308 
     | 
    
         
             
            		padding: 10px;
         
     | 
| 
       309 
309 
     | 
    
         | 
| 
       310 
     | 
    
         
            -
            		color: var(--foreground-color-1);
         
     | 
| 
       311 
     | 
    
         
            -
             
     | 
| 
       312 
310 
     | 
    
         
             
            		transition: 0.2s ease box-shadow;
         
     | 
| 
       313 
311 
     | 
    
         | 
| 
       314 
     | 
    
         
            -
            		&:hover {
         
     | 
| 
      
 312 
     | 
    
         
            +
            		&:not(:disabled):hover {
         
     | 
| 
       315 
313 
     | 
    
         
             
            			box-shadow: 0 1px 2px var(--shadow-color);
         
     | 
| 
       316 
314 
     | 
    
         
             
            		}
         
     | 
| 
       317 
315 
     | 
    
         | 
| 
      
 316 
     | 
    
         
            +
            		&:disabled {
         
     | 
| 
      
 317 
     | 
    
         
            +
            			opacity: 0.5;
         
     | 
| 
      
 318 
     | 
    
         
            +
            			font-weight: unset;
         
     | 
| 
      
 319 
     | 
    
         
            +
            			cursor: unset;
         
     | 
| 
      
 320 
     | 
    
         
            +
            			color: var(--foreground-color-1);
         
     | 
| 
      
 321 
     | 
    
         
            +
            		}
         
     | 
| 
      
 322 
     | 
    
         
            +
             
     | 
| 
       318 
323 
     | 
    
         
             
            		font-weight: bold;
         
     | 
| 
       319 
324 
     | 
    
         
             
            		color: var(--primary-action-foreground-color);
         
     | 
| 
       320 
325 
     | 
    
         
             
            	}
         
     | 
| 
         @@ -2,27 +2,73 @@ 
     | 
|
| 
       2 
2 
     | 
    
         
             
            // Repeat for specificity.
         
     | 
| 
       3 
3 
     | 
    
         
             
            // TODO(v2): Refactor everything to use RCSS.
         
     | 
| 
       4 
4 
     | 
    
         
             
            :root .toolbar-snapped-scroll-list.toolbar-snapped-scroll-list.toolbar-snapped-scroll-list {
         
     | 
| 
       5 
     | 
    
         
            -
            	overflow-y: auto;
         
     | 
| 
       6 
     | 
    
         
            -
            	scroll-snap-type: y mandatory;
         
     | 
| 
       7 
5 
     | 
    
         
             
            	height: min(200px, 50vh);
         
     | 
| 
      
 6 
     | 
    
         
            +
            	position: relative;
         
     | 
| 
       8 
7 
     | 
    
         
             
            	display: flex;
         
     | 
| 
       9 
     | 
    
         
            -
            	 
     | 
| 
      
 8 
     | 
    
         
            +
            	align-items: center;
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            	> .scroller {
         
     | 
| 
      
 11 
     | 
    
         
            +
            		display: flex;
         
     | 
| 
      
 12 
     | 
    
         
            +
            		flex-direction: column;
         
     | 
| 
      
 13 
     | 
    
         
            +
            		overflow-y: auto;
         
     | 
| 
      
 14 
     | 
    
         
            +
            		scroll-snap-type: y mandatory;
         
     | 
| 
       10 
15 
     | 
    
         | 
| 
       11 
     | 
    
         
            -
            	> .item {
         
     | 
| 
       12 
16 
     | 
    
         
             
            		height: 100%;
         
     | 
| 
       13 
17 
     | 
    
         
             
            		width: 100%;
         
     | 
| 
       14 
     | 
    
         
            -
            		flex- 
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
            		display: flex;
         
     | 
| 
       17 
     | 
    
         
            -
            		justify-content: center;
         
     | 
| 
       18 
     | 
    
         
            -
            		align-items: center;
         
     | 
| 
      
 18 
     | 
    
         
            +
            		flex-grow: 1;
         
     | 
| 
       19 
19 
     | 
    
         | 
| 
       20 
     | 
    
         
            -
            		 
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
      
 20 
     | 
    
         
            +
            		> .item {
         
     | 
| 
      
 21 
     | 
    
         
            +
            			height: 100%;
         
     | 
| 
      
 22 
     | 
    
         
            +
            			width: 100%;
         
     | 
| 
      
 23 
     | 
    
         
            +
            			flex-shrink: 0;
         
     | 
| 
      
 24 
     | 
    
         
            +
            	
         
     | 
| 
      
 25 
     | 
    
         
            +
            			display: flex;
         
     | 
| 
      
 26 
     | 
    
         
            +
            			justify-content: center;
         
     | 
| 
      
 27 
     | 
    
         
            +
            			align-items: center;
         
     | 
| 
      
 28 
     | 
    
         
            +
            	
         
     | 
| 
      
 29 
     | 
    
         
            +
            			scroll-snap-align: start;
         
     | 
| 
      
 30 
     | 
    
         
            +
            			scroll-snap-stop: always;
         
     | 
| 
      
 31 
     | 
    
         
            +
            			box-sizing: border-box;
         
     | 
| 
      
 32 
     | 
    
         
            +
            		}
         
     | 
| 
       23 
33 
     | 
    
         
             
            	}
         
     | 
| 
       24 
34 
     | 
    
         | 
| 
       25 
35 
     | 
    
         
             
            	&.-empty {
         
     | 
| 
       26 
36 
     | 
    
         
             
            		display: none;
         
     | 
| 
       27 
37 
     | 
    
         
             
            	}
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
            	> .page-markers {
         
     | 
| 
      
 40 
     | 
    
         
            +
            		overflow: hidden;
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            		display: flex;
         
     | 
| 
      
 43 
     | 
    
         
            +
            		flex-direction: column;
         
     | 
| 
      
 44 
     | 
    
         
            +
            		align-items: center;
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            		max-height: 100%;
         
     | 
| 
      
 47 
     | 
    
         
            +
            		min-height: 0;
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            		&.-one-element {
         
     | 
| 
      
 50 
     | 
    
         
            +
            			visibility: hidden;
         
     | 
| 
      
 51 
     | 
    
         
            +
            		}
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
            		> .marker {
         
     | 
| 
      
 54 
     | 
    
         
            +
            			> .content {
         
     | 
| 
      
 55 
     | 
    
         
            +
            				background-color: var(--foreground-color-1);
         
     | 
| 
      
 56 
     | 
    
         
            +
            				border-radius: 2px;
         
     | 
| 
      
 57 
     | 
    
         
            +
            				padding: 2px;
         
     | 
| 
      
 58 
     | 
    
         
            +
            			}
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
            			padding: 2px;
         
     | 
| 
      
 61 
     | 
    
         
            +
            			opacity: 0.1;
         
     | 
| 
      
 62 
     | 
    
         
            +
            			cursor: pointer;
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
            			left: 0;
         
     | 
| 
      
 65 
     | 
    
         
            +
            			transition: left 0.2s ease;
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
            			&.-active {
         
     | 
| 
      
 68 
     | 
    
         
            +
            				position: relative;
         
     | 
| 
      
 69 
     | 
    
         
            +
            				left: 2px;
         
     | 
| 
      
 70 
     | 
    
         
            +
            				opacity: 0.2;
         
     | 
| 
      
 71 
     | 
    
         
            +
            			}
         
     | 
| 
      
 72 
     | 
    
         
            +
            		}
         
     | 
| 
      
 73 
     | 
    
         
            +
            	}
         
     | 
| 
       28 
74 
     | 
    
         
             
            }
         
     |