UNPKG

visbug-lib

Version:

<p align="center"> <img src="./assets/visbug.png" width="300" height="300" alt="visbug"> <br> <a href="https://www.npmjs.org/package/visbug"><img src="https://img.shields.io/npm/v/visbug.svg?style=flat" alt="npm latest version number"></a> <a href

832 lines (698 loc) 783 kB
const sugar = { on: function(names, fn) { names .split(' ') .forEach(name => this.addEventListener(name, fn)); return this }, off: function(names, fn) { names .split(' ') .forEach(name => this.removeEventListener(name, fn)); return this }, attr: function(attr, val) { if (val === undefined) return this.getAttribute(attr) val == null ? this.removeAttribute(attr) : this.setAttribute(attr, val || ''); return this } }; function $(query, $context = document) { let $nodes = query instanceof NodeList || Array.isArray(query) ? query : query instanceof HTMLElement || query instanceof SVGElement ? [query] : $context.querySelectorAll(query); if (!$nodes.length) $nodes = []; return Object.assign( [...$nodes].map($el => Object.assign($el, sugar)), { on: function(names, fn) { this.forEach($el => $el.on(names, fn)); return this }, off: function(names, fn) { this.forEach($el => $el.off(names, fn)); return this }, attr: function(attrs, val) { if (typeof attrs === 'string' && val === undefined) return this[0].attr(attrs) else if (typeof attrs === 'object') this.forEach($el => Object.entries(attrs) .forEach(([key, val]) => $el.attr(key, val))); else if (typeof attrs == 'string' && (val || val == null || val == '')) this.forEach($el => $el.attr(attrs, val)); return this } } ) } /*! * hotkeys-js v3.6.2 * A simple micro-library for defining and dispatching keyboard shortcuts. It has no dependencies. * * Copyright (c) 2019 kenny wong <wowohoo@qq.com> * http://jaywcjlove.github.io/hotkeys * * Licensed under the MIT license. */ var isff = typeof navigator !== 'undefined' ? navigator.userAgent.toLowerCase().indexOf('firefox') > 0 : false; // 绑定事件 function addEvent(object, event, method) { if (object.addEventListener) { object.addEventListener(event, method, false); } else if (object.attachEvent) { object.attachEvent('on' + event, function () { method(window.event); }); } } // 修饰键转换成对应的键码 function getMods(modifier, key) { var mods = key.slice(0, key.length - 1); for (var i = 0; i < mods.length; i++) { mods[i] = modifier[mods[i].toLowerCase()]; }return mods; } // 处理传的key字符串转换成数组 function getKeys(key) { if (!key) key = ''; key = key.replace(/\s/g, ''); // 匹配任何空白字符,包括空格、制表符、换页符等等 var keys = key.split(','); // 同时设置多个快捷键,以','分割 var index = keys.lastIndexOf(''); // 快捷键可能包含',',需特殊处理 for (; index >= 0;) { keys[index - 1] += ','; keys.splice(index, 1); index = keys.lastIndexOf(''); } return keys; } // 比较修饰键的数组 function compareArray(a1, a2) { var arr1 = a1.length >= a2.length ? a1 : a2; var arr2 = a1.length >= a2.length ? a2 : a1; var isIndex = true; for (var i = 0; i < arr1.length; i++) { if (arr2.indexOf(arr1[i]) === -1) isIndex = false; } return isIndex; } var _keyMap = { // 特殊键 backspace: 8, tab: 9, clear: 12, enter: 13, return: 13, esc: 27, escape: 27, space: 32, left: 37, up: 38, right: 39, down: 40, del: 46, delete: 46, ins: 45, insert: 45, home: 36, end: 35, pageup: 33, pagedown: 34, capslock: 20, '⇪': 20, ',': 188, '.': 190, '/': 191, '`': 192, '-': isff ? 173 : 189, '=': isff ? 61 : 187, ';': isff ? 59 : 186, '\'': 222, '[': 219, ']': 221, '\\': 220 }; var _modifier = { // 修饰键 '⇧': 16, shift: 16, '⌥': 18, alt: 18, option: 18, '⌃': 17, ctrl: 17, control: 17, '⌘': isff ? 224 : 91, cmd: isff ? 224 : 91, command: isff ? 224 : 91 }; var _downKeys = []; // 记录摁下的绑定键 var modifierMap = { 16: 'shiftKey', 18: 'altKey', 17: 'ctrlKey' }; var _mods = { 16: false, 18: false, 17: false }; var _handlers = {}; // F1~F12 特殊键 for (var k = 1; k < 20; k++) { _keyMap['f' + k] = 111 + k; } // 兼容Firefox处理 modifierMap[isff ? 224 : 91] = 'metaKey'; _mods[isff ? 224 : 91] = false; var _scope = 'all'; // 默认热键范围 var isBindElement = false; // 是否绑定节点 // 返回键码 var code = function code(x) { return _keyMap[x.toLowerCase()] || _modifier[x.toLowerCase()] || x.toUpperCase().charCodeAt(0); }; // 设置获取当前范围(默认为'所有') function setScope(scope) { _scope = scope || 'all'; } // 获取当前范围 function getScope() { return _scope || 'all'; } // 获取摁下绑定键的键值 function getPressedKeyCodes() { return _downKeys.slice(0); } // 表单控件控件判断 返回 Boolean function filter(event) { var target = event.target || event.srcElement; var tagName = target.tagName; // 忽略这些情况下快捷键无效 return !(tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA' || target.isContentEditable); } // 判断摁下的键是否为某个键,返回true或者false function isPressed(keyCode) { if (typeof keyCode === 'string') { keyCode = code(keyCode); // 转换成键码 } return _downKeys.indexOf(keyCode) !== -1; } // 循环删除handlers中的所有 scope(范围) function deleteScope(scope, newScope) { var handlers = void 0; var i = void 0; // 没有指定scope,获取scope if (!scope) scope = getScope(); for (var key in _handlers) { if (Object.prototype.hasOwnProperty.call(_handlers, key)) { handlers = _handlers[key]; for (i = 0; i < handlers.length;) { if (handlers[i].scope === scope) handlers.splice(i, 1);else i++; } } } // 如果scope被删除,将scope重置为all if (getScope() === scope) setScope(newScope || 'all'); } // 清除修饰键 function clearModifier(event) { var key = event.keyCode || event.which || event.charCode; var i = _downKeys.indexOf(key); // 从列表中清除按压过的键 if (i >= 0) { _downKeys.splice(i, 1); } // 特殊处理 cmmand 键,在 cmmand 组合快捷键 keyup 只执行一次的问题 if (event.key && event.key.toLowerCase() === 'meta') { _downKeys.splice(0, _downKeys.length); } // 修饰键 shiftKey altKey ctrlKey (command||metaKey) 清除 if (key === 93 || key === 224) key = 91; if (key in _mods) { _mods[key] = false; // 将修饰键重置为false for (var k in _modifier) { if (_modifier[k] === key) hotkeys[k] = false; } } } // 解除绑定某个范围的快捷键 function unbind(key, scope, method) { var multipleKeys = getKeys(key); var keys = void 0; var mods = []; var obj = void 0; // 通过函数判断,是否解除绑定 // https://github.com/jaywcjlove/hotkeys/issues/44 if (typeof scope === 'function') { method = scope; scope = 'all'; } for (var i = 0; i < multipleKeys.length; i++) { // 将组合快捷键拆分为数组 keys = multipleKeys[i].split('+'); // 记录每个组合键中的修饰键的键码 返回数组 if (keys.length > 1) mods = getMods(_modifier, keys); // 获取除修饰键外的键值key key = keys[keys.length - 1]; key = key === '*' ? '*' : code(key); // 判断是否传入范围,没有就获取范围 if (!scope) scope = getScope(); // 如何key不在 _handlers 中返回不做处理 if (!_handlers[key]) return; // 清空 handlers 中数据, // 让触发快捷键键之后没有事件执行到达解除快捷键绑定的目的 for (var r = 0; r < _handlers[key].length; r++) { obj = _handlers[key][r]; // 通过函数判断,是否解除绑定,函数相等直接返回 var isMatchingMethod = method ? obj.method === method : true; // 判断是否在范围内并且键值相同 if (isMatchingMethod && obj.scope === scope && compareArray(obj.mods, mods)) { _handlers[key][r] = {}; } } } } // 对监听对应快捷键的回调函数进行处理 function eventHandler(event, handler, scope) { var modifiersMatch = void 0; // 看它是否在当前范围 if (handler.scope === scope || handler.scope === 'all') { // 检查是否匹配修饰符(如果有返回true) modifiersMatch = handler.mods.length > 0; for (var y in _mods) { if (Object.prototype.hasOwnProperty.call(_mods, y)) { if (!_mods[y] && handler.mods.indexOf(+y) > -1 || _mods[y] && handler.mods.indexOf(+y) === -1) modifiersMatch = false; } } // 调用处理程序,如果是修饰键不做处理 if (handler.mods.length === 0 && !_mods[16] && !_mods[18] && !_mods[17] && !_mods[91] || modifiersMatch || handler.shortcut === '*') { if (handler.method(event, handler) === false) { if (event.preventDefault) event.preventDefault();else event.returnValue = false; if (event.stopPropagation) event.stopPropagation(); if (event.cancelBubble) event.cancelBubble = true; } } } } // 处理keydown事件 function dispatch(event) { var asterisk = _handlers['*']; var key = event.keyCode || event.which || event.charCode; // 搜集绑定的键 if (_downKeys.indexOf(key) === -1) _downKeys.push(key); // Gecko(Firefox)的command键值224,在Webkit(Chrome)中保持一致 // Webkit左右command键值不一样 if (key === 93 || key === 224) key = 91; if (key in _mods) { _mods[key] = true; // 将特殊字符的key注册到 hotkeys 上 for (var k in _modifier) { if (_modifier[k] === key) hotkeys[k] = true; } if (!asterisk) return; } // 将modifierMap里面的修饰键绑定到event中 for (var e in _mods) { if (Object.prototype.hasOwnProperty.call(_mods, e)) { _mods[e] = event[modifierMap[e]]; } } // 表单控件过滤 默认表单控件不触发快捷键 if (!hotkeys.filter.call(this, event)) return; // 获取范围 默认为all var scope = getScope(); // 对任何快捷键都需要做的处理 if (asterisk) { for (var i = 0; i < asterisk.length; i++) { if (asterisk[i].scope === scope && (event.type === 'keydown' && !asterisk[i].keyup || event.type === 'keyup' && asterisk[i].keyup)) { eventHandler(event, asterisk[i], scope); } } } // key 不在_handlers中返回 if (!(key in _handlers)) return; for (var _i = 0; _i < _handlers[key].length; _i++) { if (event.type === 'keydown' && !_handlers[key][_i].keyup || event.type === 'keyup' && _handlers[key][_i].keyup) { if (_handlers[key][_i].key) { var keyShortcut = _handlers[key][_i].key.split('+'); var _downKeysCurrent = []; // 记录当前按键键值 for (var a = 0; a < keyShortcut.length; a++) { _downKeysCurrent.push(code(keyShortcut[a])); } _downKeysCurrent = _downKeysCurrent.sort(); if (_downKeysCurrent.join('') === _downKeys.sort().join('')) { // 找到处理内容 eventHandler(event, _handlers[key][_i], scope); } } } } } function hotkeys(key, option, method) { var keys = getKeys(key); // 需要处理的快捷键列表 var mods = []; var scope = 'all'; // scope默认为all,所有范围都有效 var element = document; // 快捷键事件绑定节点 var i = 0; // 对为设定范围的判断 if (method === undefined && typeof option === 'function') { method = option; } if (Object.prototype.toString.call(option) === '[object Object]') { if (option.scope) scope = option.scope; // eslint-disable-line if (option.element) element = option.element; // eslint-disable-line } if (typeof option === 'string') scope = option; // 对于每个快捷键进行处理 for (; i < keys.length; i++) { key = keys[i].split('+'); // 按键列表 mods = []; // 如果是组合快捷键取得组合快捷键 if (key.length > 1) mods = getMods(_modifier, key); // 将非修饰键转化为键码 key = key[key.length - 1]; key = key === '*' ? '*' : code(key); // *表示匹配所有快捷键 // 判断key是否在_handlers中,不在就赋一个空数组 if (!(key in _handlers)) _handlers[key] = []; _handlers[key].push({ keyup: option.keyup, scope: scope, mods: mods, shortcut: keys[i], method: method, key: keys[i] }); } // 在全局document上设置快捷键 if (typeof element !== 'undefined' && !isBindElement) { isBindElement = true; addEvent(element, 'keydown', function (e) { dispatch(e); }); addEvent(element, 'keyup', function (e) { dispatch(e); clearModifier(e); }); } } var _api = { setScope: setScope, getScope: getScope, deleteScope: deleteScope, getPressedKeyCodes: getPressedKeyCodes, isPressed: isPressed, filter: filter, unbind: unbind }; for (var a in _api) { if (Object.prototype.hasOwnProperty.call(_api, a)) { hotkeys[a] = _api[a]; } } if (typeof window !== 'undefined') { var _hotkeys = window.hotkeys; hotkeys.noConflict = function (deep) { if (deep && window.hotkeys === hotkeys) { window.hotkeys = _hotkeys; } return hotkeys; }; window.hotkeys = hotkeys; } var css = ":host {\n --theme-bg: hsl(0,0%,100%);\n --theme-color: hotpink;\n --theme-blue: hsl(188, 90%, 45%);\n --theme-purple: hsl(267, 100%, 58%);\n --theme-icon_color: hsl(0,0%,20%);\n --theme-icon_hover-bg: hsl(0,0%,95%);\n\n --layer-top: 2147483647;\n --layer-1: 2147483646;\n --layer-2: 2147483645;\n --layer-3: 2147483644;\n --layer-4: 2147483643;\n --layer-5: 2147483642;\n}\n\n:host {\n position: fixed;\n top: 0;\n left: 0;\n z-index: var(--layer-1);\n max-width: -webkit-min-content;\n max-width: -moz-min-content;\n max-width: min-content;\n}\n\n:host > ol {\n -webkit-animation: none 0s ease 0s 1 normal none running;\n animation: none 0s ease 0s 1 normal none running;\n -webkit-backface-visibility: visible;\n backface-visibility: visible;\n background: transparent none repeat 0 0 / auto auto padding-box border-box scroll;\n border: medium none currentColor;\n border-collapse: separate;\n -webkit-border-image: none;\n border-image: none;\n border-radius: 0;\n border-spacing: 0;\n bottom: auto;\n box-shadow: none;\n box-sizing: content-box;\n caption-side: top;\n clear: none;\n clip: auto;\n color: #000;\n -webkit-columns: auto;\n -moz-columns: auto;\n columns: auto;\n -webkit-column-count: auto;\n -moz-column-count: auto;\n column-count: auto;\n -webkit-column-fill: balance;\n -moz-column-fill: balance;\n column-fill: balance;\n grid-column-gap: normal;\n -webkit-column-gap: normal;\n -moz-column-gap: normal;\n column-gap: normal;\n -webkit-column-rule: medium none currentColor;\n -moz-column-rule: medium none currentColor;\n column-rule: medium none currentColor;\n -webkit-column-span: 1;\n -moz-column-span: 1;\n column-span: 1;\n -webkit-column-width: auto;\n -moz-column-width: auto;\n column-width: auto;\n content: normal;\n counter-increment: none;\n counter-reset: none;\n cursor: auto;\n direction: ltr;\n display: inline;\n empty-cells: show;\n float: none;\n font-family: serif;\n font-size: medium;\n font-style: normal;\n -webkit-font-feature-settings: normal;\n font-feature-settings: normal;\n font-variant: normal;\n font-weight: normal;\n font-stretch: normal;\n line-height: normal;\n height: auto;\n -webkit-hyphens: none;\n -ms-hyphens: none;\n hyphens: none;\n left: auto;\n letter-spacing: normal;\n list-style: disc outside none;\n margin: 0;\n max-height: none;\n max-width: none;\n min-height: 0;\n min-width: 0;\n opacity: 1;\n orphans: 2;\n outline: medium none invert;\n overflow: visible;\n overflow-x: visible;\n overflow-y: visible;\n padding: 0;\n page-break-after: auto;\n page-break-before: auto;\n page-break-inside: auto;\n -webkit-perspective: none;\n perspective: none;\n -webkit-perspective-origin: 50% 50%;\n perspective-origin: 50% 50%;\n position: static;\n right: auto;\n -moz-tab-size: 8;\n tab-size: 8;\n table-layout: auto;\n text-align: left;\n -moz-text-align-last: auto;\n text-align-last: auto;\n text-decoration: none;\n text-indent: 0;\n text-shadow: none;\n text-transform: none;\n top: auto;\n -webkit-transform: none;\n transform: none;\n -webkit-transform-origin: 50% 50% 0;\n transform-origin: 50% 50% 0;\n -webkit-transform-style: flat;\n transform-style: flat;\n -webkit-transition: none 0s ease 0s;\n transition: none 0s ease 0s;\n unicode-bidi: normal;\n vertical-align: baseline;\n visibility: visible;\n white-space: normal;\n widows: 2;\n width: auto;\n word-spacing: normal;\n z-index: auto;\n all: initial;\n font-size: 16px;\n font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif;\n display: -webkit-box;\n display: flex;\n -webkit-box-orient: vertical;\n -webkit-box-direction: normal;\n flex-direction: column;\n margin: 1em 0 0.5em 1em;\n padding: 0;\n list-style-type: none;\n border-radius: 2em\n}\n\n:host > ol:not([colors]) {\n box-shadow: 0 0.25em 0.5em hsla(0,0%,0%,10%);\n background: var(--theme-bg);\n }\n\n:host li {\n height: 2.25em;\n width: 2.25em;\n margin: 0.05em 0.25em;\n display: -webkit-inline-box;\n display: inline-flex;\n -webkit-box-align: center;\n align-items: center;\n -webkit-box-pack: center;\n justify-content: center;\n position: relative;\n border-radius: 50%\n}\n\n:host li:first-child { margin-top: 0.25em; }\n\n:host li:last-child { margin-bottom: 0.25em; }\n\n:host li[data-tool]:hover {\n cursor: pointer;\n background-color: var(--theme-icon_hover-bg);\n }\n\n:host li[data-tool]:active {\n background-color: hsl(0,0%,90%);\n }\n\n:host li[data-active=true] > svg:not(.icon-cursor) {\n fill: var(--theme-color);\n }\n\n:host li[data-active=true] > .icon-cursor {\n stroke: var(--theme-color);\n }\n\n@media (max-height: 768px) {\n :host li:nth-of-type(10) > aside, :host li:nth-of-type(11) > aside, :host li:nth-of-type(12) > aside, :host li:nth-of-type(13) > aside {\n top: auto;\n }\n }\n\n:host li > aside {\n overflow: hidden;\n position: absolute;\n direction: ltr;\n text-align: left;\n left: 3em;\n top: 0;\n z-index: -2;\n pointer-events: none;\n background: white;\n color: hsl(0,0%,30%);\n box-shadow: 0 0.1em 4.5em hsla(0,0%,0%,15%);\n border-radius: 1em;\n\n -webkit-transition: opacity 0.3s ease, -webkit-transform 0.2s ease;\n\n transition: opacity 0.3s ease, -webkit-transform 0.2s ease;\n\n transition: opacity 0.3s ease, transform 0.2s ease;\n\n transition: opacity 0.3s ease, transform 0.2s ease, -webkit-transform 0.2s ease;\n opacity: 0;\n -webkit-transform: translateX(-1em);\n transform: translateX(-1em);\n will-change: transform, opacity\n }\n\n:host li > aside > figure {\n margin: 0;\n display: grid;\n }\n\n:host li > aside figcaption {\n padding: 1em;\n display: grid;\n grid-gap: 0.5em;\n gap: 0.5em\n }\n\n:host li > aside figcaption > h2, :host li > aside figcaption > p {\n margin: 0;\n }\n\n:host li > aside figcaption > h2 {\n font-size: 1.5em;\n line-height: 1.1;\n margin-bottom: 0.5em;\n display: grid;\n grid-auto-flow: column;\n -webkit-box-pack: justify;\n justify-content: space-between;\n -webkit-box-align: center;\n align-items: center;\n }\n\n:host li > aside figcaption > p {\n font-size: 1em;\n line-height: 1.5;\n padding-right: 3em;\n }\n\n:host li > aside figcaption [table] {\n display: grid;\n grid-gap: 0.5em;\n gap: 0.5em\n }\n\n:host li > aside figcaption [table] > div {\n display: grid;\n grid-auto-flow: column;\n grid-template-columns: 1fr auto;\n -webkit-box-pack: justify;\n justify-content: space-between;\n }\n\n:host li > aside [hotkey] {\n border-radius: 5em;\n height: 1.5em;\n width: 1.5em;\n display: -webkit-inline-box;\n display: inline-flex;\n -webkit-box-align: center;\n align-items: center;\n -webkit-box-pack: center;\n justify-content: center;\n border: 1px solid var(--theme-color);\n color: var(--theme-color);\n font-weight: 300;\n font-size: 0.5em;\n text-transform: uppercase;\n }\n\n:host li:hover:not([data-tool=\"search\"]) > aside,\n :host li[data-tool=\"search\"] > svg:hover + aside {\n opacity: 1;\n -webkit-transform: translateX(0);\n transform: translateX(0);\n -webkit-transition-delay: 0.75s;\n transition-delay: 0.75s;\n }\n\n:host li input::-webkit-calendar-picker-indicator {\n background: inherit;\n color: var(--theme-color);\n }\n\n:host [colors] {\n margin-top: 0;\n}\n\n:host [colors] > li {\n overflow: hidden;\n border-radius: 50%;\n box-shadow: 0 0 0 2px white, 0 0.25em 0.5em hsla(0,0%,0%,25%);\n background: var(--contextual_color);\n margin-bottom: 0.5em\n}\n\n:host [colors] > li:first-child {\n margin-top: 0;\n }\n\n:host [colors] li:hover:after {\n top: 0;\n}\n\n:host li > svg {\n width: 50%;\n fill: var(--theme-icon_color);\n}\n\n:host li > svg.icon-cursor {\n width: 35%;\n fill: white;\n stroke: var(--theme-icon_color);\n stroke-width: 2px;\n}\n\n:host li[data-tool=\"search\"][data-active=\"true\"]:before {\n -webkit-transform: translateX(-1em);\n transform: translateX(-1em);\n opacity: 0;\n }\n\n:host li[data-tool=\"search\"] > .search {\n position: absolute;\n left: calc(100% - 1.25em);\n top: 0;\n height: 100%;\n z-index: -1;\n box-shadow: 0 0.25em 0.5em hsla(0,0%,0%,10%);\n border-radius: 0 2em 2em 0;\n overflow: hidden;\n}\n\n:host li[data-tool=\"search\"] > .search > input {\n direction: ltr;\n border: none;\n font-size: 1em;\n padding: 0.4em 0.4em 0.4em 2em;\n outline: none;\n height: 100%;\n width: 250px;\n box-sizing: border-box;\n caret-color: hotpink\n}\n\n:host li[data-tool=\"search\"] > .search > input::-webkit-input-placeholder {\n font-weight: lighter;\n font-size: 0.8em;\n }\n\n:host li[data-tool=\"search\"] > .search > input::-moz-placeholder {\n font-weight: lighter;\n font-size: 0.8em;\n }\n\n:host li[data-tool=\"search\"] > .search > input::-ms-input-placeholder {\n font-weight: lighter;\n font-size: 0.8em;\n }\n\n:host li[data-tool=\"search\"] > .search > input::placeholder {\n font-weight: lighter;\n font-size: 0.8em;\n }\n\n:host [colors] > li > svg {\n fill: var(--icon_color);\n mix-blend-mode: luminosity;\n -webkit-filter: brightness(0.5);\n filter: brightness(0.5);\n}\n\n:host [colors] > li > svg > rect:last-child {\n stroke: hsla(0,0%,0%,20%);\n stroke-width: 0.5px;\n}\n\n:host input[type='color'] {\n opacity: 0.01;\n position: absolute;\n top: 0; left: 0;\n width: 100%; height: 100%;\n z-index: 1;\n box-sizing: border-box;\n border: white;\n padding: 0;\n cursor: pointer;\n}\n\n:host input[type='color']:focus {\n outline: none;\n}\n\n:host input[type='color']::-webkit-color-swatch-wrapper {\n padding: 0;\n}\n\n:host input[type='color']::-webkit-color-swatch {\n border: none;\n}\n\n:host input[type='color'][value='']::-webkit-color-swatch {\n background-color: transparent !important;\n background-image: linear-gradient(155deg, #ffffff 0%,#ffffff 46%,#ff0000 46%,#ff0000 54%,#ffffff 55%,#ffffff 100%);\n}\n"; var css$1 = ":host {\n --theme-bg: hsl(0,0%,100%);\n --theme-color: hotpink;\n --theme-blue: hsl(188, 90%, 45%);\n --theme-purple: hsl(267, 100%, 58%);\n --theme-icon_color: hsl(0,0%,20%);\n --theme-icon_hover-bg: hsl(0,0%,95%);\n\n --layer-top: 2147483647;\n --layer-1: 2147483646;\n --layer-2: 2147483645;\n --layer-3: 2147483644;\n --layer-4: 2147483643;\n --layer-5: 2147483642;\n}\n\n:host > svg {\n position: absolute;\n top: var(--top);\n left: var(--left);\n overflow: visible;\n pointer-events: none;\n z-index: var(--layer-3);\n}\n"; var css$2 = ":host {\n --theme-bg: hsl(0,0%,100%);\n --theme-color: hotpink;\n --theme-blue: hsl(188, 90%, 45%);\n --theme-purple: hsl(267, 100%, 58%);\n --theme-icon_color: hsl(0,0%,20%);\n --theme-icon_hover-bg: hsl(0,0%,95%);\n\n --layer-top: 2147483647;\n --layer-1: 2147483646;\n --layer-2: 2147483645;\n --layer-3: 2147483644;\n --layer-4: 2147483643;\n --layer-5: 2147483642;\n}\n\n:host rect {\n width: 100%;\n height: 100%;\n vector-effect: non-scaling-stroke;\n stroke: hsl(267, 100%, 58%);\n stroke-width: 1px;\n fill: none;\n}\n\n:host > svg {\n z-index: var(--layer-5);\n}\n"; var css$3 = ":host {\n --theme-bg: hsl(0,0%,100%);\n --theme-color: hotpink;\n --theme-blue: hsl(188, 90%, 45%);\n --theme-purple: hsl(267, 100%, 58%);\n --theme-icon_color: hsl(0,0%,20%);\n --theme-icon_hover-bg: hsl(0,0%,95%);\n\n --layer-top: 2147483647;\n --layer-1: 2147483646;\n --layer-2: 2147483645;\n --layer-3: 2147483644;\n --layer-4: 2147483643;\n --layer-5: 2147483642;\n}\n\n:host {\n --line-color: var(--theme-purple);\n --line-base: var(--theme-color);\n --line-width: 1px;\n --distance-h: 5px;\n --distance-w: 5px;\n --line-w: 1px;\n --line-h: 1px;\n font-size: 16px;\n}\n\n:host > figure {\n margin: 0;\n position: absolute;\n height: var(--distance-h);\n width: var(--distance-w);\n top: var(--top);\n left: var(--left);\n right: var(--right);\n overflow: visible;\n pointer-events: none;\n z-index: var(--layer-3);\n display: -webkit-box;\n display: flex;\n -webkit-box-align: center;\n align-items: center;\n -webkit-box-orient: vertical;\n -webkit-box-direction: normal;\n flex-direction: var(--direction);\n}\n\n:host > figure figcaption {\n color: white;\n text-shadow: 0 0.5px 0 hsla(0, 0%, 0%, 0.4);\n box-shadow: 0 0.5px 0 hsla(0, 0%, 0%, 0.4);\n background: var(--line-color);\n border-radius: 1em;\n text-align: center;\n line-height: 1.1;\n font-size: 0.7em;\n font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif;\n padding: 0.25em 0.5em 0.275em;\n -webkit-font-feature-settings: proportional-num oldstyle-nums stacked-fractions slashed-zero;\n font-feature-settings: proportional-num oldstyle-nums stacked-fractions slashed-zero;\n font-variant-numeric: proportional-num oldstyle-nums stacked-fractions slashed-zero;\n}\n\n:host > figure span {\n background: var(--line-color);\n height: var(--line-h);\n width: var(--line-w);\n}\n\n:host > figure div {\n -webkit-box-flex: 2;\n flex: 2;\n background: var(--line-color);\n width: var(--line-w);\n height: var(--line-h);\n}\n\n:host figure[quadrant=\"bottom\"] > div:first-of-type, :host figure[quadrant=\"right\"] > div:first-of-type, :host figure[quadrant=\"top\"] > div:last-of-type, :host figure[quadrant=\"left\"] > div:last-of-type {\n background: -webkit-gradient(linear, , from(hotpink), to(var(--line-color)));\n background: linear-gradient(to var(--quadrant), hotpink 0%, var(--line-color) 100%);\n}\n"; var css$4 = ":host {\n --theme-bg: hsl(0,0%,100%);\n --theme-color: hotpink;\n --theme-blue: hsl(188, 90%, 45%);\n --theme-purple: hsl(267, 100%, 58%);\n --theme-icon_color: hsl(0,0%,20%);\n --theme-icon_hover-bg: hsl(0,0%,95%);\n\n --layer-top: 2147483647;\n --layer-1: 2147483646;\n --layer-2: 2147483645;\n --layer-3: 2147483644;\n --layer-4: 2147483643;\n --layer-5: 2147483642;\n}\n\n:host {\n --color: hotpink;\n}\n\n:host > svg {\n position:absolute;\n top:0;\n left:0;\n overflow:visible;\n pointer-events:none;\n z-index:var(--layer-5);\n}\n\n:host rect, \n:host line {\n stroke: var(--color);\n}\n\n:host line {\n stroke-dasharray: 2;\n stroke-dasharray-offset: 3;\n}\n"; var css$5 = ":host {\n --theme-bg: hsl(0,0%,100%);\n --theme-color: hotpink;\n --theme-blue: hsl(188, 90%, 45%);\n --theme-purple: hsl(267, 100%, 58%);\n --theme-icon_color: hsl(0,0%,20%);\n --theme-icon_hover-bg: hsl(0,0%,95%);\n\n --layer-top: 2147483647;\n --layer-1: 2147483646;\n --layer-2: 2147483645;\n --layer-3: 2147483644;\n --layer-4: 2147483643;\n --layer-5: 2147483642;\n}\n\n:host {\n font-size: 16px;\n\n --top: 0;\n --left: 0;\n --max-width: 0;\n}\n\n:host > span {\n position: absolute;\n top: var(--top);\n left: var(--left);\n max-width: var(--max-width);\n z-index: var(--layer-4);\n -webkit-transform: translateY(-100%);\n transform: translateY(-100%);\n background: hotpink;\n background: var(--label-bg, hotpink);\n border-radius: 0.2em 0.2em 0 0;\n text-shadow: 0 0.5px 0 hsla(0, 0%, 0%, 0.4);\n color: white;\n display: -webkit-inline-box;\n display: inline-flex;\n -webkit-box-pack: center;\n justify-content: center;\n font-size: 0.8em;\n font-weight: normal;\n font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif;\n white-space: nowrap;\n padding: 0.25em 0.4em 0.15em;\n line-height: 1.1;\n}\n\n:host a {\n text-decoration: none;\n color: inherit;\n cursor: pointer;\n text-overflow: ellipsis;\n overflow: hidden\n}\n\n:host a:hover {\n text-decoration: underline;\n color: white;\n }\n\n:host a[node]:before {\n content: \"\\003c\";\n }\n\n:host a[node]:after {\n content: \"\\003e\";\n }\n"; var css$6 = ":host {\n --theme-bg: hsl(0,0%,100%);\n --theme-color: hotpink;\n --theme-blue: hsl(188, 90%, 45%);\n --theme-purple: hsl(267, 100%, 58%);\n --theme-icon_color: hsl(0,0%,20%);\n --theme-icon_hover-bg: hsl(0,0%,95%);\n\n --layer-top: 2147483647;\n --layer-1: 2147483646;\n --layer-2: 2147483645;\n --layer-3: 2147483644;\n --layer-4: 2147483643;\n --layer-5: 2147483642;\n}\n\n:host svg {\n display: none;\n position: absolute;\n top: var(--top);\n left: var(--left);\n overflow: visible;\n pointer-events: none;\n z-index: var(--layer-5)\n}\n\n:host svg > rect {\n fill: hsla(330, 100%, 71%, 0.5);\n width: 100%;\n height: 100%;\n }\n"; var css$7 = ":host [mask] {\n pointer-events: none;\n position: absolute;\n z-index: var(--layer-5);\n width: var(--width);\n height: var(--height);\n top: var(--top);\n left: var(--left);\n background-color: var(--bg);\n -webkit-clip-path: polygon(\n 0% 0%, 0% 100%, var(--target-left) 100%,\n var(--target-left) var(--target-top),\n var(--offset-right) var(--target-top),\n var(--offset-right) var(--offset-bottom),\n 0 var(--offset-bottom), 0 100%,\n 100% 100%, 100% 0%\n );\n clip-path: polygon(\n 0% 0%, 0% 100%, var(--target-left) 100%,\n var(--target-left) var(--target-top),\n var(--offset-right) var(--target-top),\n var(--offset-right) var(--offset-bottom),\n 0 var(--offset-bottom), 0 100%,\n 100% 100%, 100% 0%\n );\n}"; var css$8 = ":host {\n --theme-bg: hsl(0,0%,100%);\n --theme-color: hotpink;\n --theme-blue: hsl(188, 90%, 45%);\n --theme-purple: hsl(267, 100%, 58%);\n --theme-icon_color: hsl(0,0%,20%);\n --theme-icon_hover-bg: hsl(0,0%,95%);\n\n --layer-top: 2147483647;\n --layer-1: 2147483646;\n --layer-2: 2147483645;\n --layer-3: 2147483644;\n --layer-4: 2147483643;\n --layer-5: 2147483642;\n}\n\n:host {\n position: absolute;\n z-index: var(--layer-top);\n\n --arrow-width: 15px;\n --arrow-height: 8px;\n\n --shadow-up: 5px;\n --shadow-down: -5px;\n --shadow-direction: var(--shadow-up);\n\n --arrow-up: polygon(0 0, 100% 0, 50% 100%);\n --arrow-down: polygon(50% 0, 0 100%, 100% 100%);\n --arrow: var(--arrow-up);\n}\n\n:host figure {\n -webkit-animation: none 0s ease 0s 1 normal none running;\n animation: none 0s ease 0s 1 normal none running;\n -webkit-backface-visibility: visible;\n backface-visibility: visible;\n background: transparent none repeat 0 0 / auto auto padding-box border-box scroll;\n border: medium none currentColor;\n border-collapse: separate;\n -webkit-border-image: none;\n border-image: none;\n border-radius: 0;\n border-spacing: 0;\n bottom: auto;\n box-shadow: none;\n box-sizing: content-box;\n caption-side: top;\n clear: none;\n clip: auto;\n color: #000;\n -webkit-columns: auto;\n -moz-columns: auto;\n columns: auto;\n -webkit-column-count: auto;\n -moz-column-count: auto;\n column-count: auto;\n -webkit-column-fill: balance;\n -moz-column-fill: balance;\n column-fill: balance;\n grid-column-gap: normal;\n -webkit-column-gap: normal;\n -moz-column-gap: normal;\n column-gap: normal;\n -webkit-column-rule: medium none currentColor;\n -moz-column-rule: medium none currentColor;\n column-rule: medium none currentColor;\n -webkit-column-span: 1;\n -moz-column-span: 1;\n column-span: 1;\n -webkit-column-width: auto;\n -moz-column-width: auto;\n column-width: auto;\n content: normal;\n counter-increment: none;\n counter-reset: none;\n cursor: auto;\n direction: ltr;\n display: inline;\n empty-cells: show;\n float: none;\n font-family: serif;\n font-size: medium;\n font-style: normal;\n -webkit-font-feature-settings: normal;\n font-feature-settings: normal;\n font-variant: normal;\n font-weight: normal;\n font-stretch: normal;\n line-height: normal;\n height: auto;\n -webkit-hyphens: none;\n -ms-hyphens: none;\n hyphens: none;\n left: auto;\n letter-spacing: normal;\n list-style: disc outside none;\n margin: 0;\n max-height: none;\n max-width: none;\n min-height: 0;\n min-width: 0;\n opacity: 1;\n orphans: 2;\n outline: medium none invert;\n overflow: visible;\n overflow-x: visible;\n overflow-y: visible;\n padding: 0;\n page-break-after: auto;\n page-break-before: auto;\n page-break-inside: auto;\n -webkit-perspective: none;\n perspective: none;\n -webkit-perspective-origin: 50% 50%;\n perspective-origin: 50% 50%;\n position: static;\n right: auto;\n -moz-tab-size: 8;\n tab-size: 8;\n table-layout: auto;\n text-align: left;\n -moz-text-align-last: auto;\n text-align-last: auto;\n text-decoration: none;\n text-indent: 0;\n text-shadow: none;\n text-transform: none;\n top: auto;\n -webkit-transform: none;\n transform: none;\n -webkit-transform-origin: 50% 50% 0;\n transform-origin: 50% 50% 0;\n -webkit-transform-style: flat;\n transform-style: flat;\n -webkit-transition: none 0s ease 0s;\n transition: none 0s ease 0s;\n unicode-bidi: normal;\n vertical-align: baseline;\n visibility: visible;\n white-space: normal;\n widows: 2;\n width: auto;\n word-spacing: normal;\n z-index: auto;\n all: initial;\n direction: ltr;\n font-size: 16px;\n font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif;\n max-width: 50vw;\n background: white;\n color: var(--theme-icon_color);\n line-height: initial;\n padding: 0.5em;\n margin: 0;\n display: -webkit-box;\n display: flex;\n -webkit-box-orient: vertical;\n -webkit-box-direction: normal;\n flex-direction: column;\n flex-wrap: nowrap;\n border-radius: 0.25em;\n line-height: initial;\n -webkit-filter: drop-shadow(0 var(--shadow-direction) 0.5em hsla(0,0%,0%,35%));\n filter: drop-shadow(0 var(--shadow-direction) 0.5em hsla(0,0%,0%,35%))\n}\n\n:host figure:after {\n content: \"\";\n background: white;\n width: var(--arrow-width);\n height: var(--arrow-height);\n -webkit-clip-path: var(--arrow);\n clip-path: var(--arrow);\n position: absolute;\n top: var(--arrow-top);\n left: var(--arrow-left);\n }\n\n:host figure a {\n text-decoration: none;\n color: inherit;\n text-overflow: ellipsis;\n overflow: hidden;\n cursor: pointer\n }\n\n:host figure a:hover {\n color: var(--theme-color);\n text-decoration: underline;\n }\n\n:host figure a:empty {\n display: none;\n }\n\n:host figure a[node]:before {\n content: \"\\003c\";\n }\n\n:host figure a[node]:after {\n content: \"\\003e\";\n }\n\n:host h5 {\n display: -webkit-box;\n display: flex;\n font-size: 1em;\n font-weight: bolder;\n margin: 0;\n overflow: hidden;\n white-space: nowrap;\n}\n\n:host h6 {\n margin-top: 1em;\n margin-bottom: 0;\n font-weight: normal;\n}\n\n:host small {\n font-size: 0.7em;\n color: hsl(0,0%,60%)\n}\n\n:host small > span {\n color: hsl(0,0%,20%);\n }\n\n:host a:not(:hover) {\n text-decoration: none;\n}\n\n:host [brand],\n:host [divider] {\n color: var(--theme-color);\n}\n\n:host div {\n display: grid;\n grid-template-columns: auto auto;\n grid-gap: 0.25em 0.5em;\n margin: 0.5em 0 0;\n padding: 0;\n list-style-type: none;\n color: hsl(0,0%,40%);\n font-size: 0.8em;\n font-family: 'Dank Mono', 'Operator Mono', 'Inconsolata', 'Fira Mono', 'SF Mono', 'Monaco', 'Droid Sans Mono', 'Source Code Pro', monospace;\n}\n\n:host [value] {\n color: var(--theme-icon_color);\n display: -webkit-inline-box;\n display: inline-flex;\n -webkit-box-align: center;\n align-items: center;\n -webkit-box-pack: end;\n justify-content: flex-end;\n text-align: right;\n /* white-space: pre; */\n}\n\n:host [text] {\n white-space: normal;\n}\n\n:host [longform] {\n background: var(--theme-icon_hover-bg);\n padding: 0.5em 0.75em;\n border-radius: 0.25em;\n font-family: sans-serif;\n text-align: left;\n line-height: 1.5;\n}\n\n:host [color] {\n position: relative;\n top: 1px;\n display: inline-block;\n width: 1em;\n height: 1em;\n border-radius: 50%;\n margin-right: .5em;\n}\n\n:host [local-modifications] {\n margin-top: 1rem;\n color: var(--theme-color);\n font-weight: bold;\n}\n\n:host [contrast] > span {\n padding: 0 0.5em 0.1em;\n border-radius: 1em;\n box-shadow: 0 0 0 1px hsl(0,0%,90%);\n}\n"; var css$9 = ":host {\n --theme-bg: hsl(0,0%,100%);\n --theme-color: hotpink;\n --theme-blue: hsl(188, 90%, 45%);\n --theme-purple: hsl(267, 100%, 58%);\n --theme-icon_color: hsl(0,0%,20%);\n --theme-icon_hover-bg: hsl(0,0%,95%);\n\n --layer-top: 2147483647;\n --layer-1: 2147483646;\n --layer-2: 2147483645;\n --layer-3: 2147483644;\n --layer-4: 2147483643;\n --layer-5: 2147483642;\n}\n\n:host {\n display: none;\n position: fixed;\n z-index: var(--layer-top);\n -webkit-box-align: center;\n align-items: center;\n -webkit-box-pack: center;\n justify-content: center;\n width: 100vw;\n height: 100vh;\n background: hsl(0,0%,95%);\n font-size: 16px;\n font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif;\n\n --light-grey: hsl(0,0%,90%);\n --grey: hsl(0,0%,60%);\n --dark-grey: hsl(0,0%,40%);\n}\n\n:host [command] {\n padding: 1em;\n text-align: center;\n font-size: 3vw;\n font-weight: lighter;\n letter-spacing: 0.1em;\n color: var(--dark-grey)\n}\n\n:host [command] > [light] {\n color: var(--grey);\n }\n\n:host [command] > [tool] {\n text-decoration: underline;\n -webkit-text-decoration-color: var(--theme-color);\n text-decoration-color: var(--theme-color);\n }\n\n:host [command] > [negative], :host [command] > [side], :host [command] > [amount] {\n font-weight: normal;\n }\n\n:host [card] {\n padding: 1em;\n background: white;\n box-shadow: 0 0.5em 3em hsla(0,0%,0%,20%);\n border-radius: 0.5em;\n color: var(--dark-grey);\n display: -webkit-box;\n display: flex;\n -webkit-box-pack: space-evenly;\n justify-content: space-evenly\n}\n\n:host [card] > div:not([keyboard]) {\n display: -webkit-box;\n display: flex;\n -webkit-box-align: end;\n align-items: flex-end;\n margin-left: 1em;\n }\n\n:host [tool-icon] {\n position: absolute;\n top: 1em;\n left: 0;\n width: 100%;\n padding: 0 1rem;\n display: -webkit-box;\n display: flex;\n -webkit-box-pack: center;\n justify-content: center\n}\n\n:host [tool-icon] > span {\n color: var(--dark-grey);\n display: grid;\n grid-template-columns: 5vmax auto;\n grid-gap: 0.5em;\n -webkit-box-align: center;\n align-items: center;\n text-transform: capitalize;\n font-size: 4vmax;\n font-weight: lighter;\n }\n\n:host [tool-icon] svg {\n width: 100%;\n fill: var(--theme-color);\n }\n\n:host section {\n display: -webkit-box;\n display: flex;\n -webkit-box-pack: center;\n justify-content: center;\n}\n\n:host section > span, \n:host [arrows] > span {\n border: 1px solid transparent;\n border-radius: 0.5em;\n display: -webkit-inline-box;\n display: inline-flex;\n -webkit-box-align: center;\n align-items: center;\n -webkit-box-pack: center;\n justify-content: center;\n margin: 2px;\n padding: 1.5vw;\n font-size: 0.75em;\n white-space: nowrap;\n}\n\n:host section > span:not([pressed=\"true\"]), \n:host [arrows] > span:not([pressed=\"true\"]) {\n border: 1px solid var(--light-grey)\n}\n\n:host section > span:not([pressed=\"true\"]):hover, :host [arrows] > span:not([pressed=\"true\"]):hover {\n border-color: var(--grey);\n }\n\n:host span[pressed=\"true\"] {\n background: var(--theme-color);\n color: white;\n}\n\n:host span:not([pressed=\"true\"])[used] {\n background: var(--light-grey);\n}\n\n:host span[hotkey] {\n color: var(--theme-color);\n font-weight: bold;\n cursor: pointer;\n}\n\n:host section > span[hotkey]:not([pressed=\"true\"]) {\n border-color: var(--theme-color);\n}\n\n:host [arrows] {\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n grid-template-rows: 1fr 1fr\n}\n\n:host [arrows] > span:nth-child(1) {\n grid-row: 1;\n grid-column: 2;\n }\n\n:host [arrows] > span:nth-child(2) {\n grid-row: 2;\n grid-column: 2;\n }\n\n:host [arrows] > span:nth-child(3) {\n grid-row: 2;\n grid-column: 1;\n }\n\n:host [arrows] > span:nth-child(4) {\n grid-row: 2;\n grid-column: 3;\n }\n\n:host [caps] > span:nth-child(1),\n:host [shift] > span:nth-child(1) { -webkit-box-pack: start; justify-content: flex-start; }\n\n:host [shift] > span:nth-child(12) { -webkit-box-pack: end; justify-content: flex-end; }"; const constructStylesheet = (styles, stylesheet = new CSSStyleSheet()) => { stylesheet.replaceSync(styles); return stylesheet }; const VisBugStyles = constructStylesheet(css); const HandleStyles = constructStylesheet(css$1); const HoverStyles = constructStylesheet(css$2); const MetatipStyles = constructStylesheet(css$8); const DistanceStyles = constructStylesheet(css$3); const GridlineStyles = constructStylesheet(css$4); const LabelStyles = constructStylesheet(css$5); const OverlayStyles = constructStylesheet(css$6); const BoxModelStyles = constructStylesheet(css$7); const HotkeymapStyles = constructStylesheet(css$9); class Handles extends HTMLElement { constructor() { super(); this.$shadow = this.attachShadow({mode: 'closed'}); this.styles = [HandleStyles]; } connectedCallback() { this.$shadow.adoptedStyleSheets = this.styles; window.addEventListener('resize', this.on_resize.bind(this)); } disconnectedCallback() { window.removeEventListener('resize', this.on_resize); } on_resize() { window.requestAnimationFrame(() => { const node_label_id = this.$shadow.host.getAttribute('data-label-id'); const [source_el] = $(`[data-label-id="${node_label_id}"]`); if (!source_el) return this.position = { node_label_id, el: source_el, }; }); } set position({el, node_label_id}) { this.$shadow.innerHTML = this.render(el.getBoundingClientRect(), node_label_id); if (this._backdrop) { this.backdrop = { element: this._backdrop.update(el), update: this._backdrop.update, }; } } set backdrop(bd) { this._backdrop = bd; const cur_child = this.$shadow.querySelector('visbug-boxmodel'); cur_child ? this.$shadow.replaceChild(bd.element, cur_child) : this.$shadow.appendChild(bd.element); } render({ x, y, width, height, top, left }, node_label_id) { this.$shadow.host.setAttribute('data-label-id', node_label_id); this.style.setProperty('--top', `${top + window.scrollY}px`); this.style.setProperty('--left', `${left}px`); return ` <svg class="visbug-handles" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" version="1.1" xmlns="http://www.w3.org/2000/svg" > <rect stroke="hotpink" fill="none" width="100%" height="100%"></rect> <circle stroke="hotpink" fill="white" cx="0" cy="0" r="2"></circle> <circle stroke="hotpink" fill="white" cx="100%" cy="0" r="2"></circle> <circle stroke="hotpink" fill="white" cx="100%" cy="100%" r="2"></circle> <circle stroke="hotpink" fill="white" cx="0" cy="100%" r="2"></circle> <circle fill="hotpink" cx="${width/2}" cy="0" r="2"></circle> <circle fill="hotpink" cx="0" cy="${height/2}" r="2"></circle> <circle fill="hotpink" cx="${width/2}" cy="${height}" r="2"></circle> <circle fill="hotpink" cx="${width}" cy="${height/2}" r="2"></circle> </svg> ` } } customElements.define('visbug-handles', Handles); class Hover extends Handles { constructor() { super(); this.styles = [HandleStyles, HoverStyles]; } render({ width, height, top, left }) { this.style.setProperty('--top', `${top + window.scrollY}px`); this.style.setProperty('--left', `${left}px`); return ` <svg width="${width}" height="${height}"> <rect></rect> </svg> ` } } customElements.define('visbug-hover', Hover); class Label extends HTMLElement { constructor() { super(); this.$shadow = this.attachShadow({mode: 'closed'}); } connectedCallback() { this.$shadow.adoptedStyleSheets = [LabelStyles]; $('a', this.$shadow).on('click mouseenter', this.dispatchQuery.bind(this)); window.addEventListener('resize', this.on_resize.bind(this)); } disconnectedCallback() { $('a', this.$shadow).off('click', this.dispatchQuery); window.removeEventListener('resize', this.on_resize); } on_resize() { window.requestAnimationFrame(() => { const node_label_id = this.$shadow.host.getAttribute('data-label-id'); const [source_el] = $(`[data-label-id="${node_label_id}"]`); if (!source_el) return this.position = { node_label_id, boundingRect: source_el.getBoundingClientRect(), }; }); } dispatchQuery(e) { this.$shadow.host.dispatchEvent(new CustomEvent('query', { bubbles: true, detail: { text: e.target.textContent, activator: e.type, } })); } set text(content) { this._text = content; } set position({boundingRect, node_label_id}) { this.$shadow.innerHTML = this.render(node_label_id); this.update = boundingRect; } set update({x,y,width}) { this.style.setProperty('--top', `${y + window.scrollY}px`); this.style.setProperty('--left', `${x - 1}px`); this.style.setProperty('--max-width', `${width + (window.innerWidth - x - width - 20)}px`); } render(node_label_id) { this.$shadow.host.setAttribute('data-label-id', node_label_id); return `<span>${this._text}</span>` } } customElements.define('visbug-label', Label); const desiredPropMap = { color: 'rgb(0, 0, 0)', backgroundColor: 'rgba(0, 0, 0, 0)', backgroundImage: 'none', backgroundSize: 'auto', backgroundPosition: '0% 0%', // borderColor: 'rgb(0, 0, 0)', borderWidth: '0px', borderRadius: '0px', boxShadow: 'none', padding: '0px', margin: '0px', fontFamily: '', fontSize: '16px', fontWeight: '400', textAlign: 'start', textShadow: 'none', textTransform: 'none', lineHeight: 'normal', letterSpacing: 'normal', display: 'block', alignItems: 'normal', justifyContent: 'normal', flexDirection: 'row', flexWrap: 'nowrap', flexBasis: 'auto', // flexFlow: 'none', fill: 'rgb(0, 0, 0)', stroke: 'none', gridTemplateColumns: 'none', gridAutoColumns: 'auto', gridTemplateRows: 'none', gridAutoRows: 'auto', gridTemplateAreas: 'none', gridArea: 'auto / auto / auto / auto', gap: 'normal normal', gridAutoFlow: 'row', }; const desiredAccessibilityMap = [ 'role', 'tabindex', 'aria-*', 'for', 'alt', 'title', 'type', ]; const largeWCAG2TextMap = [ { fontSize: '24px', fontWeight: '0' }, { fontSize: '18.5px', fontWeight: '700' } ]; const getStyle = (el, name) => { if (document.defaultView && document.defaultView.getComputedStyle) { name = name.replace(/([A-Z])/g, '-$1'); name = name.toLowerCase(); let s = document.defaultView.getComputedStyle(el, ''); return s && s.getPropertyValue(name) } }; const getStyles = el => { const elStyleObject = el.style; const computedStyle = window.getComputedStyle(el, null); let desiredValues = []; for (prop in el.style) if (prop in desiredPropMap && desiredPropMap[prop] != computedStyle[prop]) desiredValues.push({ prop, value: computedStyle[prop].replace(/, rgba/g, '\rrgba') }); return desiredValues }; const getComputedBackgroundColor = el => { let background = getStyle(el, 'background-color'); if (background === 'rgba(0, 0, 0, 0)') { let node = findNearestParentElement(el) , found = false; while(!found) { let bg = getStyle(node, 'background-color'); if (bg !== 'rgba(0, 0, 0, 0)') { found = true; background = bg; } node = findNearestParentElement(node); if (node.nodeName === 'HTML') { found = true; background = 'white'; } } } return background }; const findNearestParentElement = el => el.parentNode && el.parentNode.nodeType === 1 ? el.parentNode : el.parentNode.nodeName === '#document-fragment' ? el.parentNode.host : el.parentNode.parentNode.host; const findNearestChildElement = el => { if (el.shadowRoot && el.shadowRoot.children.length) { return [...el.shadowRoot.children] .filter(({nodeName}) => !['LINK','STYLE','SCRIPT','HTML','HEAD'].includes(nodeName) )[0] } else if (el.children.length) return el.children[0] }; const loadStyles = async stylesheets => { const fetches = await Promise.all(stylesheets.map(url => fetch(url))); const texts = await Promise.all(fetches