@symbo.ls/brender 3.14.676 → 3.14.677
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/CHANGELOG.md +6 -0
- package/dist/esm/env.js +1 -1
- package/env.js +79 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @symbo.ls/brender
|
|
2
2
|
|
|
3
|
+
## 3.14.677
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 0d2a8e3: A server render keeps a CSS custom property's name as it is written. linkedom's style object turned every name given to `setProperty`, `removeProperty` and `getPropertyValue` into kebab case, so `--coverBoxLeft` went into the HTML as `--cover-box-left`. That is another property (custom property names are case-sensitive): the first paint used the `var()` fallback, and the content moved when the browser wrote `--coverBoxLeft` (XMA's hero text moved 30px on the desktop home, CLS 0.0003). A `--*` name now keeps its case in the server environment; every other name goes through linkedom as before.
|
|
8
|
+
|
|
3
9
|
## 3.14.676
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/dist/esm/env.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{parseHTML as
|
|
1
|
+
import{parseHTML as f}from"linkedom";const p=new WeakSet;class y{static[Symbol.hasInstance](e){return p.has(e)}}const m=o=>{let e=Object.getPrototypeOf(o.createElement("select")),t;for(;e&&!(t=Object.getOwnPropertyDescriptor(e,"value"));)e=Object.getPrototypeOf(e);!e||!t||!t.get||t.set||Object.defineProperty(e,"value",{configurable:!0,enumerable:t.enumerable,get:t.get,set(l){const s=l==null?"":String(l);let n=!1;for(const i of this.querySelectorAll("option")){const r=i.hasAttribute("value")?i.getAttribute("value"):i.textContent;!n&&r===s?(i.setAttribute("selected",""),n=!0):i.removeAttribute("selected")}}})},h=Symbol.for("@symbo.ls/brender:styleMap"),b=o=>typeof o=="string"&&o.charCodeAt(0)===45&&o.charCodeAt(1)===45,d=o=>{let e=Object.getPrototypeOf(o.createElement("div").style);for(;e&&!Object.prototype.hasOwnProperty.call(e,"setProperty");)e=Object.getPrototypeOf(e);if(!e||Object.prototype.hasOwnProperty.call(e,h))return;const{setProperty:t,removeProperty:l,getPropertyValue:s}=e;if(typeof t!="function"||typeof l!="function"||typeof s!="function")return;Object.defineProperty(e,h,{configurable:!0,get(){return this}});const n=(r,a)=>{let c="";for(;a.has(c);)c+=" ";l.call(r,c)},i=(r,a,c)=>{const u=r[h];n(r,u),c==null?u.delete(a):u.set(a,c),n(r,u)};Object.defineProperties(e,{setProperty:{configurable:!0,writable:!0,value:function(r,a){if(!b(r))return t.apply(this,arguments);i(this,r,a)}},removeProperty:{configurable:!0,writable:!0,value:function(r){if(!b(r))return l.apply(this,arguments);i(this,r,null)}},getPropertyValue:{configurable:!0,writable:!0,value:function(r){return b(r)?(s.call(this,r),this[h].get(r)):s.apply(this,arguments)}}})},g=()=>{const o={};return{getItem:e=>o[e]??null,setItem:(e,t)=>{o[e]=String(t)},removeItem:e=>{delete o[e]},clear:()=>{for(const e in o)delete o[e]},get length(){return Object.keys(o).length},key:e=>Object.keys(o)[e]??null}},T=(o="<!DOCTYPE html><html><head></head><body></body></html>")=>{const e={location:{pathname:"/",search:"",hash:"",origin:"http://localhost",protocol:"http:",host:"localhost",hostname:"localhost",port:"",href:"http://localhost/"},localStorage:g(),sessionStorage:g(),history:{pushState:()=>{},replaceState:()=>{},state:null}},{window:t,document:l}=f(o,e);return t.requestAnimationFrame||(t.requestAnimationFrame=s=>{const n=setTimeout(s,0);return n?.unref&&n.unref(),n}),t.cancelAnimationFrame||(t.cancelAnimationFrame=s=>clearTimeout(s)),t.URL||(t.URL=URL),t.scrollTo||(t.scrollTo=()=>{}),globalThis.localStorage=e.localStorage,globalThis.sessionStorage=e.sessionStorage,globalThis.history||(globalThis.history=e.history),m(l),d(l),t.MutationObserver||(t.MutationObserver=class{constructor(){}observe(){}disconnect(){}takeRecords(){return[]}}),globalThis.window=t,globalThis.document=l,globalThis.Node=t.Node||globalThis.Node,globalThis.Element=t.Element||globalThis.Element,globalThis.HTMLElement=t.HTMLElement||globalThis.HTMLElement,globalThis.MutationObserver=t.MutationObserver,p.add(t),t.constructor&&t.constructor!==Object?globalThis.Window=t.constructor:(typeof globalThis.Window!="function"||globalThis.Window===Object)&&(globalThis.Window=y),{window:t,document:l}};export{T as createEnv};
|
package/env.js
CHANGED
|
@@ -33,6 +33,74 @@ const patchSelectValue = (document) => {
|
|
|
33
33
|
})
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
// Keep a custom property's name as it is in linkedom's CSSStyleDeclaration
|
|
37
|
+
// (see createEnv). The prototype is linkedom's, shared by every document it
|
|
38
|
+
// parses: patched once, like select.value above. The marker is a registered
|
|
39
|
+
// symbol, so two copies of this module in one process patch it once too.
|
|
40
|
+
const STYLE_MAP = Symbol.for('@symbo.ls/brender:styleMap')
|
|
41
|
+
const isCustomProperty = (name) =>
|
|
42
|
+
typeof name === 'string' && name.charCodeAt(0) === 45 && name.charCodeAt(1) === 45
|
|
43
|
+
|
|
44
|
+
const patchCustomPropertyNames = (document) => {
|
|
45
|
+
let proto = Object.getPrototypeOf(document.createElement('div').style)
|
|
46
|
+
while (proto && !Object.prototype.hasOwnProperty.call(proto, 'setProperty')) proto = Object.getPrototypeOf(proto)
|
|
47
|
+
if (!proto || Object.prototype.hasOwnProperty.call(proto, STYLE_MAP)) return
|
|
48
|
+
const { setProperty, removeProperty, getPropertyValue } = proto
|
|
49
|
+
if (typeof setProperty !== 'function' || typeof removeProperty !== 'function' || typeof getPropertyValue !== 'function') return
|
|
50
|
+
// linkedom's style object is a Proxy over a Map of the declarations, and it
|
|
51
|
+
// reads a name its prototype has from that Map: this getter gives the Map.
|
|
52
|
+
Object.defineProperty(proto, STYLE_MAP, { configurable: true, get () { return this } })
|
|
53
|
+
// A linkedom write that changes no declaration (it removes a name no
|
|
54
|
+
// declaration has). linkedom parses the attribute again when it changed,
|
|
55
|
+
// makes the style attribute when there is none, and writes the attribute
|
|
56
|
+
// from the Map. Before an edit of the Map it makes the Map current — a parse
|
|
57
|
+
// after the edit would lose it; after the edit it puts it in the attribute.
|
|
58
|
+
// The attribute text is never parsed again for the edit, so a value with a
|
|
59
|
+
// `;` in it (a data URI) stays whole, as with linkedom's own writes.
|
|
60
|
+
const settle = (style, map) => {
|
|
61
|
+
let none = ''
|
|
62
|
+
while (map.has(none)) none += ' '
|
|
63
|
+
removeProperty.call(style, none)
|
|
64
|
+
}
|
|
65
|
+
// linkedom's own write with the name as it is: null removes, any other
|
|
66
|
+
// value is set as it is given.
|
|
67
|
+
const write = (style, name, value) => {
|
|
68
|
+
const map = style[STYLE_MAP]
|
|
69
|
+
settle(style, map)
|
|
70
|
+
if (value == null) map.delete(name)
|
|
71
|
+
else map.set(name, value)
|
|
72
|
+
settle(style, map)
|
|
73
|
+
}
|
|
74
|
+
Object.defineProperties(proto, {
|
|
75
|
+
setProperty: {
|
|
76
|
+
configurable: true,
|
|
77
|
+
writable: true,
|
|
78
|
+
value: function (name, value) {
|
|
79
|
+
if (!isCustomProperty(name)) return setProperty.apply(this, arguments)
|
|
80
|
+
write(this, name, value)
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
removeProperty: {
|
|
84
|
+
configurable: true,
|
|
85
|
+
writable: true,
|
|
86
|
+
value: function (name) {
|
|
87
|
+
if (!isCustomProperty(name)) return removeProperty.apply(this, arguments)
|
|
88
|
+
write(this, name, null)
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
getPropertyValue: {
|
|
92
|
+
configurable: true,
|
|
93
|
+
writable: true,
|
|
94
|
+
value: function (name) {
|
|
95
|
+
if (!isCustomProperty(name)) return getPropertyValue.apply(this, arguments)
|
|
96
|
+
// linkedom's read parses the attribute again when it changed
|
|
97
|
+
getPropertyValue.call(this, name)
|
|
98
|
+
return this[STYLE_MAP].get(name)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
|
|
36
104
|
// Web Storage for one environment.
|
|
37
105
|
const createStorage = () => {
|
|
38
106
|
const store = {}
|
|
@@ -123,6 +191,17 @@ export const createEnv = (html = '<!DOCTYPE html><html><head></head><body></body
|
|
|
123
191
|
// setter: the option with that value becomes the selected one.
|
|
124
192
|
patchSelectValue(document)
|
|
125
193
|
|
|
194
|
+
// linkedom's CSSStyleDeclaration sends every name through `uhyphen`
|
|
195
|
+
// (setProperty, removeProperty, getPropertyValue): a custom property
|
|
196
|
+
// `--coverBoxLeft` went into the markup as `--cover-box-left`. That is
|
|
197
|
+
// another property — a custom property's name is case-sensitive — so the
|
|
198
|
+
// first paint read the `var()` fallback, and the browser's own write of
|
|
199
|
+
// `--coverBoxLeft` moved the content when the adoption came (XMA's hero
|
|
200
|
+
// text, 30px to the right on the desktop home: CLS 0.0003; r11 smoke check).
|
|
201
|
+
// A `--*` name is now kept as it is; every other name goes through linkedom
|
|
202
|
+
// as before.
|
|
203
|
+
patchCustomPropertyNames(document)
|
|
204
|
+
|
|
126
205
|
// Stub MutationObserver for SSR (not provided by linkedom)
|
|
127
206
|
if (!window.MutationObserver) {
|
|
128
207
|
window.MutationObserver = class MutationObserver {
|