Diffdown is a real-time collaborative Markdown editor/previewer built on the AT Protocol diffdown.com
at main 165 lines 6.8 kB view raw
1var C = "\u037c" 2var COUNT = typeof Symbol == "undefined" ? "__" + C : Symbol.for(C) 3var SET = typeof Symbol == "undefined" ? "__styleSet" + Math.floor(Math.random() * 1e8) : Symbol("styleSet") 4var top = typeof globalThis != "undefined" ? globalThis : typeof window != "undefined" ? window : {} 5 6// :: - Style modules encapsulate a set of CSS rules defined from 7// JavaScript. Their definitions are only available in a given DOM 8// root after it has been _mounted_ there with `StyleModule.mount`. 9// 10// Style modules should be created once and stored somewhere, as 11// opposed to re-creating them every time you need them. The amount of 12// CSS rules generated for a given DOM root is bounded by the amount 13// of style modules that were used. So to avoid leaking rules, don't 14// create these dynamically, but treat them as one-time allocations. 15var StyleModule = exports.StyleModule = function StyleModule(spec, options) { 16 this.rules = [] 17 var ref = options || {}; 18 var finish = ref.finish; 19 20 function splitSelector(selector) { 21 return /^@/.test(selector) ? [selector] : selector.split(/,\s*/) 22 } 23 24 function render(selectors, spec, target, isKeyframes) { 25 var local = [], isAt = /^@(\w+)\b/.exec(selectors[0]), keyframes = isAt && isAt[1] == "keyframes" 26 if (isAt && spec == null) { return target.push(selectors[0] + ";") } 27 for (var prop in spec) { 28 var value = spec[prop] 29 if (/&/.test(prop)) { 30 render(prop.split(/,\s*/).map(function (part) { return selectors.map(function (sel) { return part.replace(/&/, sel); }); }).reduce(function (a, b) { return a.concat(b); }), 31 value, target) 32 } else if (value && typeof value == "object") { 33 if (!isAt) { throw new RangeError("The value of a property (" + prop + ") should be a primitive value.") } 34 render(splitSelector(prop), value, local, keyframes) 35 } else if (value != null) { 36 local.push(prop.replace(/_.*/, "").replace(/[A-Z]/g, function (l) { return "-" + l.toLowerCase(); }) + ": " + value + ";") 37 } 38 } 39 if (local.length || keyframes) { 40 target.push((finish && !isAt && !isKeyframes ? selectors.map(finish) : selectors).join(", ") + 41 " {" + local.join(" ") + "}") 42 } 43 } 44 45 for (var prop in spec) { render(splitSelector(prop), spec[prop], this.rules) } 46}; 47 48// :: () → string 49// Returns a string containing the module's CSS rules. 50StyleModule.prototype.getRules = function getRules () { return this.rules.join("\n") }; 51 52// :: () → string 53// Generate a new unique CSS class name. 54StyleModule.newName = function newName () { 55 var id = top[COUNT] || 1 56 top[COUNT] = id + 1 57 return C + id.toString(36) 58}; 59 60// :: (union<Document, ShadowRoot>, union<[StyleModule], StyleModule>, ?{nonce: ?string}) 61// 62// Mount the given set of modules in the given DOM root, which ensures 63// that the CSS rules defined by the module are available in that 64// context. 65// 66// Rules are only added to the document once per root. 67// 68// Rule order will follow the order of the modules, so that rules from 69// modules later in the array take precedence of those from earlier 70// modules. If you call this function multiple times for the same root 71// in a way that changes the order of already mounted modules, the old 72// order will be changed. 73// 74// If a Content Security Policy nonce is provided, it is added to 75// the `<style>` tag generated by the library. 76StyleModule.mount = function mount (root, modules, options) { 77 var set = root[SET], nonce = options && options.nonce 78 if (!set) { set = new StyleSet(root, nonce) } 79 else if (nonce) { set.setNonce(nonce) } 80 set.mount(Array.isArray(modules) ? modules : [modules], root) 81}; 82 83var adoptedSet = new Map //<Document, StyleSet> 84 85var StyleSet = function StyleSet(root, nonce) { 86 var doc = root.ownerDocument || root, win = doc.defaultView 87 if (!root.head && root.adoptedStyleSheets && win.CSSStyleSheet) { 88 var adopted = adoptedSet.get(doc) 89 if (adopted) { return root[SET] = adopted } 90 this.sheet = new win.CSSStyleSheet 91 adoptedSet.set(doc, this) 92 } else { 93 this.styleTag = doc.createElement("style") 94 if (nonce) { this.styleTag.setAttribute("nonce", nonce) } 95 } 96 this.modules = [] 97 root[SET] = this 98}; 99 100StyleSet.prototype.mount = function mount (modules, root) { 101 var sheet = this.sheet 102 var pos = 0 /* Current rule offset */, j = 0 /* Index into this.modules */ 103 for (var i = 0; i < modules.length; i++) { 104 var mod = modules[i], index = this.modules.indexOf(mod) 105 if (index < j && index > -1) { // Ordering conflict 106 this.modules.splice(index, 1) 107 j-- 108 index = -1 109 } 110 if (index == -1) { 111 this.modules.splice(j++, 0, mod) 112 if (sheet) { for (var k = 0; k < mod.rules.length; k++) 113 { sheet.insertRule(mod.rules[k], pos++) } } 114 } else { 115 while (j < index) { pos += this.modules[j++].rules.length } 116 pos += mod.rules.length 117 j++ 118 } 119 } 120 121 if (sheet) { 122 if (root.adoptedStyleSheets.indexOf(this.sheet) < 0) 123 { root.adoptedStyleSheets = [this.sheet ].concat( root.adoptedStyleSheets) } 124 } else { 125 var text = "" 126 for (var i$1 = 0; i$1 < this.modules.length; i$1++) 127 { text += this.modules[i$1].getRules() + "\n" } 128 this.styleTag.textContent = text 129 var target = root.head || root 130 if (this.styleTag.parentNode != target) 131 { target.insertBefore(this.styleTag, target.firstChild) } 132 } 133}; 134 135StyleSet.prototype.setNonce = function setNonce (nonce) { 136 if (this.styleTag && this.styleTag.getAttribute("nonce") != nonce) 137 { this.styleTag.setAttribute("nonce", nonce) } 138}; 139 140// Style::Object<union<Style,string>> 141// 142// A style is an object that, in the simple case, maps CSS property 143// names to strings holding their values, as in `{color: "red", 144// fontWeight: "bold"}`. The property names can be given in 145// camel-case—the library will insert a dash before capital letters 146// when converting them to CSS. 147// 148// If you include an underscore in a property name, it and everything 149// after it will be removed from the output, which can be useful when 150// providing a property multiple times, for browser compatibility 151// reasons. 152// 153// A property in a style object can also be a sub-selector, which 154// extends the current context to add a pseudo-selector or a child 155// selector. Such a property should contain a `&` character, which 156// will be replaced by the current selector. For example `{"&:before": 157// {content: '"hi"'}}`. Sub-selectors and regular properties can 158// freely be mixed in a given object. Any property containing a `&` is 159// assumed to be a sub-selector. 160// 161// Finally, a property can specify an @-block to be wrapped around the 162// styles defined inside the object that's the property's value. For 163// example to create a media query you can do `{"@media screen and 164// (min-width: 400px)": {...}}`. 165