@dinoreic/fez 0.1.1 → 0.2.2
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 +151 -137
- package/bin/fez +32 -0
- package/bin/fez-index +44 -0
- package/dist/fez.js +7 -7
- package/dist/fez.js.map +4 -4
- package/dist/log.js +5 -0
- package/dist/log.js.map +7 -0
- package/dist/rollup.js.map +2 -2
- package/package.json +14 -5
- package/src/fez/compile.js +73 -53
- package/src/fez/connect.js +7 -21
- package/src/fez/defaults.js +69 -0
- package/src/fez/instance.js +131 -56
- package/src/fez/lib/template.js +9 -0
- package/src/fez/root.js +42 -7
- package/src/fez.js +14 -23
- package/src/log.js +154 -0
- package/src/rollup.js +0 -6
package/dist/log.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
(()=>{var u=o=>{let a=o.split(/(<\/?[^>]+>)/g).map(i=>i.trim()).filter(i=>i),n=0,t=[];for(let i=0;i<a.length;i++){let e=a[i],s=a[i+1],p=a[i+2];if(e.startsWith("<"))if(!e.startsWith("</")&&!e.endsWith("/>")&&s&&!s.startsWith("<")&&p&&p.startsWith("</")){let r=Math.max(0,n);t.push(" ".repeat(r)+e+s+p),i+=2}else if(e.startsWith("</")){n--;let r=Math.max(0,n);t.push(" ".repeat(r)+e)}else if(e.endsWith("/>")||e.includes(" />")){let r=Math.max(0,n);t.push(" ".repeat(r)+e)}else{let r=Math.max(0,n);t.push(" ".repeat(r)+e),n++}else if(e){let r=Math.max(0,n);t.push(" ".repeat(r)+e)}}return t.join(`
|
|
2
|
+
`)},c=(()=>{let o=[],a=[],n=0;return t=>{if(!document.body){window.requestAnimationFrame(()=>c(t));return}t instanceof Node&&(t=u(t.outerHTML));let i=typeof t;t===void 0&&(t="undefined"),t===null&&(t="null"),Array.isArray(t)?i="array":typeof t=="object"&&t!==null&&(i="object"),typeof t!="string"&&(t=JSON.stringify(t,(r,l)=>typeof l=="function"?String(l):l,2).replaceAll("<","<")),t=t.trim(),o.push(t+`
|
|
3
|
+
|
|
4
|
+
type: ${i}`),a.push(i);let e=document.getElementById("dump-dialog");e||(e=document.body.appendChild(document.createElement("div")),e.id="dump-dialog",e.style.cssText="position:fixed;top:30px;left:30px;right:50px;bottom:50px;background:#fff;border:1px solid#333;box-shadow:0 0 10px rgba(0,0,0,0.5);padding:20px;overflow:auto;z-index:9999;font:13px/1.4 monospace;white-space:pre");let s=parseInt(localStorage.getItem("_LOG_INDEX"));!isNaN(s)&&s>=0&&s<o.length?n=s:n=o.length-1;let p=()=>{let r=o.map((l,d)=>{let f="#f0f0f0";return d!==n&&(a[d]==="object"?f="#d6e3ef":a[d]==="array"&&(f="#d8d5ef")),`<button style="padding:4px 8px;margin:0;cursor:pointer;background:${d===n?"#333":f};color:${d===n?"#fff":"#000"}" data-index="${d}">${d+1}</button>`}).join("");e.innerHTML='<div style="display:flex;flex-direction:column;height:100%"><div style="display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:10px"><div style="display:flex;flex-wrap:wrap;gap:4px;flex:1;margin-right:10px">'+r+'</div><button style="padding:4px 8px;cursor:pointer;flex-shrink:0">×</button></div><xmp style="flex:1;overflow:auto;margin:0;padding:0;color:#000;background:#fff;font-size:14px;line-height:22px">'+o[n]+"</xmp></div>",e.querySelector('button[style*="flex-shrink:0"]').onclick=()=>e.remove(),e.querySelectorAll("button[data-index]").forEach(l=>{l.onclick=()=>{n=parseInt(l.dataset.index),localStorage.setItem("_LOG_INDEX",n),p()}})};p()}})();typeof window<"u"&&(window.LOG=c,window.LOG_PP=u);var x=c;})();
|
|
5
|
+
//# sourceMappingURL=log.js.map
|
package/dist/log.js.map
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/log.js"],
|
|
4
|
+
"sourcesContent": ["// pretty print HTML\nconst LOG_PP = (html) => {\n const parts = html\n .split(/(<\\/?[^>]+>)/g)\n .map(p => p.trim())\n .filter(p => p);\n\n let indent = 0;\n const lines = [];\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n const nextPart = parts[i + 1];\n const nextNextPart = parts[i + 2];\n\n // Check if it's a tag\n if (part.startsWith('<')) {\n // Check if this is an opening tag followed by text and then its closing tag\n if (!part.startsWith('</') && !part.endsWith('/>') && nextPart && !nextPart.startsWith('<') && nextNextPart && nextNextPart.startsWith('</')) {\n // Combine them on one line\n const actualIndent = Math.max(0, indent);\n lines.push(' '.repeat(actualIndent) + part + nextPart + nextNextPart);\n i += 2; // Skip the next two parts\n }\n // Closing tag\n else if (part.startsWith('</')) {\n indent--;\n const actualIndent = Math.max(0, indent);\n lines.push(' '.repeat(actualIndent) + part);\n }\n // Self-closing tag\n else if (part.endsWith('/>') || part.includes(' />')) {\n const actualIndent = Math.max(0, indent);\n lines.push(' '.repeat(actualIndent) + part);\n }\n // Opening tag\n else {\n const actualIndent = Math.max(0, indent);\n lines.push(' '.repeat(actualIndent) + part);\n indent++;\n }\n }\n // Text node\n else if (part) {\n const actualIndent = Math.max(0, indent);\n lines.push(' '.repeat(actualIndent) + part);\n }\n }\n\n return lines.join('\\n');\n}\n\nconst LOG = (() => {\n const logs = [];\n const logTypes = []; // Track the original type of each log\n let currentIndex = 0;\n\n return o => {\n if (!document.body) {\n window.requestAnimationFrame( () => LOG(o) )\n return\n }\n\n if (o instanceof Node) {\n o = LOG_PP(o.outerHTML)\n }\n\n // Store the original type\n let originalType = typeof o;\n\n if (o === undefined) { o = 'undefined' }\n if (o === null) { o = 'null' }\n\n if (Array.isArray(o)) {\n originalType = 'array';\n } else if (typeof o === 'object' && o !== null) {\n originalType = 'object';\n }\n\n if (typeof o != 'string') {\n o = JSON.stringify(o, (key, value) => {\n if (typeof value === 'function') {\n return String(value);\n }\n return value;\n }, 2).replaceAll('<', '<')\n }\n\n o = o.trim()\n\n logs.push(o + `\\n\\ntype: ${originalType}`);\n logTypes.push(originalType);\n\n let d = document.getElementById('dump-dialog');\n if (!d) {\n d = document.body.appendChild(document.createElement('div'));\n d.id = 'dump-dialog';\n d.style.cssText =\n 'position:fixed;top:30px;left:30px;right:50px;bottom:50px;' +\n 'background:#fff;border:1px solid#333;box-shadow:0 0 10px rgba(0,0,0,0.5);' +\n 'padding:20px;overflow:auto;z-index:9999;font:13px/1.4 monospace;white-space:pre';\n }\n\n // Check if we have a saved index and it's still valid\n const savedIndex = parseInt(localStorage.getItem('_LOG_INDEX'));\n if (!isNaN(savedIndex) && savedIndex >= 0 && savedIndex < logs.length) {\n currentIndex = savedIndex;\n } else {\n currentIndex = logs.length - 1;\n }\n\n const renderContent = () => {\n const buttons = logs.map((_, i) => {\n let bgColor = '#f0f0f0'; // default\n if (i !== currentIndex) {\n if (logTypes[i] === 'object') {\n bgColor = '#d6e3ef'; // super light blue\n } else if (logTypes[i] === 'array') {\n bgColor = '#d8d5ef'; // super light indigo\n }\n }\n return `<button style=\"padding:4px 8px;margin:0;cursor:pointer;background:${i === currentIndex ? '#333' : bgColor};color:${i === currentIndex ? '#fff' : '#000'}\" data-index=\"${i}\">${i + 1}</button>`\n }).join('');\n\n d.innerHTML =\n '<div style=\"display:flex;flex-direction:column;height:100%\">' +\n '<div style=\"display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:10px\">' +\n '<div style=\"display:flex;flex-wrap:wrap;gap:4px;flex:1;margin-right:10px\">' + buttons + '</div>' +\n '<button style=\"padding:4px 8px;cursor:pointer;flex-shrink:0\">×</button>' +\n '</div>' +\n '<xmp style=\"flex:1;overflow:auto;margin:0;padding:0;color:#000;background:#fff;font-size:14px;line-height:22px\">' + logs[currentIndex] + '</xmp>' +\n '</div>';\n\n d.querySelector('button[style*=\"flex-shrink:0\"]').onclick = () => d.remove();\n\n d.querySelectorAll('button[data-index]').forEach(btn => {\n btn.onclick = () => {\n currentIndex = parseInt(btn.dataset.index);\n localStorage.setItem('_LOG_INDEX', currentIndex);\n renderContent();\n };\n });\n };\n\n renderContent();\n };\n})();\n\nif (typeof window !== 'undefined') {\n window.LOG = LOG\n window.LOG_PP = LOG_PP\n}\n\nexport default LOG\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["LOG_PP", "html", "parts", "p", "indent", "lines", "part", "nextPart", "nextNextPart", "actualIndent", "LOG", "logs", "logTypes", "currentIndex", "o", "originalType", "key", "value", "d", "savedIndex", "renderContent", "buttons", "_", "i", "bgColor", "btn", "log_default"]
|
|
7
|
+
}
|
package/dist/rollup.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/rollup.js"],
|
|
4
|
-
"sourcesContent": ["function fezPlugin() {\n return {\n name: 'fez-plugin',\n\n transform(code, filePath) {\n const baseName = filePath.split('/').pop().split('.');\n\n if (baseName[1] === 'fez') {\n code = code.replace(/`/g, '\\\\`').replace(/\\$/g, '\\\\$');\n const transformedCode = `Fez.compile('${baseName[0]}', \\`\\n${code}\\`)`;\n\n // if (baseName[0] === 'admin-menu') {\n // console.log('Transformed code:', baseName, transformedCode);\n // }\n\n return {\n code: transformedCode,\n map: null,\n };\n }\n },\n };\n}\n\
|
|
5
|
-
"mappings": "MAAA,SAASA,GAAY,CACnB,MAAO,CACL,KAAM,aAEN,UAAUC,EAAMC,EAAU,CACxB,IAAMC,EAAWD,EAAS,MAAM,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,EAEpD,GAAIC,EAAS,CAAC,IAAM,MAClB,OAAAF,EAAOA,EAAK,QAAQ,KAAM,KAAK,EAAE,QAAQ,MAAO,KAAK,EAO9C,CACL,KAPsB,gBAAgBE,EAAS,CAAC,CAAC;AAAA,EAAUF,CAAI,MAQ/D,IAAK,IACP,CAEJ,CACF,CACF,
|
|
4
|
+
"sourcesContent": ["function fezPlugin() {\n return {\n name: 'fez-plugin',\n\n transform(code, filePath) {\n const baseName = filePath.split('/').pop().split('.');\n\n if (baseName[1] === 'fez') {\n code = code.replace(/`/g, '\\\\`').replace(/\\$/g, '\\\\$');\n const transformedCode = `Fez.compile('${baseName[0]}', \\`\\n${code}\\`)`;\n\n // if (baseName[0] === 'admin-menu') {\n // console.log('Transformed code:', baseName, transformedCode);\n // }\n\n return {\n code: transformedCode,\n map: null,\n };\n }\n },\n };\n}\n\nexport default fezPlugin;\n"],
|
|
5
|
+
"mappings": "MAAA,SAASA,GAAY,CACnB,MAAO,CACL,KAAM,aAEN,UAAUC,EAAMC,EAAU,CACxB,IAAMC,EAAWD,EAAS,MAAM,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,EAEpD,GAAIC,EAAS,CAAC,IAAM,MAClB,OAAAF,EAAOA,EAAK,QAAQ,KAAM,KAAK,EAAE,QAAQ,MAAO,KAAK,EAO9C,CACL,KAPsB,gBAAgBE,EAAS,CAAC,CAAC;AAAA,EAAUF,CAAI,MAQ/D,IAAK,IACP,CAEJ,CACF,CACF,CAEA,IAAOG,EAAQJ",
|
|
6
6
|
"names": ["fezPlugin", "code", "filePath", "baseName", "rollup_default"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dinoreic/fez",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Runtime custom dom elements",
|
|
5
5
|
"main": "dist/fez.js",
|
|
6
6
|
"type": "module",
|
|
@@ -13,24 +13,32 @@
|
|
|
13
13
|
"import": "./src/rollup.js",
|
|
14
14
|
"require": "./src/rollup.js"
|
|
15
15
|
},
|
|
16
|
+
"./log": {
|
|
17
|
+
"import": "./src/log.js",
|
|
18
|
+
"require": "./src/log.js"
|
|
19
|
+
},
|
|
16
20
|
"./package.json": "./package.json"
|
|
17
21
|
},
|
|
22
|
+
"bin": {
|
|
23
|
+
"fez": "./bin/fez"
|
|
24
|
+
},
|
|
18
25
|
"files": [
|
|
26
|
+
"bin",
|
|
19
27
|
"dist",
|
|
20
28
|
"src",
|
|
21
29
|
"README.md",
|
|
22
30
|
"LICENSE"
|
|
23
31
|
],
|
|
24
32
|
"scripts": {
|
|
25
|
-
"pages": "ruby demo/helper.rb > ./index.html",
|
|
26
33
|
"build": "bun build.js b",
|
|
27
|
-
"b": "bun build
|
|
34
|
+
"b": "bun run build",
|
|
28
35
|
"watch": "bun build.js w",
|
|
29
36
|
"server": "bun run lib/server.js",
|
|
30
|
-
"dev": "
|
|
37
|
+
"dev": "bunx concurrently --kill-others \"bun run server\" \"find src demo lib | entr -c sh -c 'bun run index && bun run b'\"",
|
|
31
38
|
"test": "bun test",
|
|
32
39
|
"prepublishOnly": "bun run build && bun run test",
|
|
33
|
-
"publish": "
|
|
40
|
+
"publish": "npm publish --access public",
|
|
41
|
+
"index": "ruby ./bin/fez-index 'demo/fez/*.fez' > demo/fez/index.json"
|
|
34
42
|
},
|
|
35
43
|
"keywords": [
|
|
36
44
|
"dom",
|
|
@@ -51,6 +59,7 @@
|
|
|
51
59
|
"homepage": "https://github.com/dux/fez#readme",
|
|
52
60
|
"devDependencies": {
|
|
53
61
|
"coffeescript": "^2.7.0",
|
|
62
|
+
"concurrently": "^9.1.2",
|
|
54
63
|
"esbuild": "0.23.0",
|
|
55
64
|
"esbuild-coffeescript": "^2.2.0",
|
|
56
65
|
"glob-cli": "^1.0.0",
|
package/src/fez/compile.js
CHANGED
|
@@ -26,6 +26,9 @@ const compileToClass = (html) => {
|
|
|
26
26
|
currentBlock = [];
|
|
27
27
|
currentType = null;
|
|
28
28
|
} else if (currentType) {
|
|
29
|
+
// if (currentType == 'script' && line.startsWith('//')) {
|
|
30
|
+
// continue
|
|
31
|
+
// }
|
|
29
32
|
currentBlock.push(line);
|
|
30
33
|
} else {
|
|
31
34
|
result.html += line + '\n';
|
|
@@ -33,8 +36,7 @@ const compileToClass = (html) => {
|
|
|
33
36
|
}
|
|
34
37
|
|
|
35
38
|
if (result.head) {
|
|
36
|
-
const container =
|
|
37
|
-
container.innerHTML = result.head
|
|
39
|
+
const container = Fez.domRoot(result.head)
|
|
38
40
|
|
|
39
41
|
// Process all children of the container
|
|
40
42
|
Array.from(container.children).forEach(node => {
|
|
@@ -86,72 +88,86 @@ const compileToClass = (html) => {
|
|
|
86
88
|
return klass
|
|
87
89
|
}
|
|
88
90
|
|
|
89
|
-
//
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
// Fez.compile(templateNode) # compile template node
|
|
94
|
-
// Fez.compile('ui-form', templateNode.innerHTML) # compile string
|
|
95
|
-
export default function (tagName, html) {
|
|
96
|
-
if (tagName instanceof Node) {
|
|
97
|
-
const node = tagName
|
|
91
|
+
// Handle single argument cases - compile all, compile node, or compile from URL
|
|
92
|
+
function compile_bulk(data) {
|
|
93
|
+
if (data instanceof Node) {
|
|
94
|
+
const node = data
|
|
98
95
|
node.remove()
|
|
99
96
|
|
|
100
97
|
const fezName = node.getAttribute('fez')
|
|
101
98
|
|
|
102
99
|
// Check if fezName contains dot or slash (indicates URL)
|
|
103
100
|
if (fezName && (fezName.includes('.') || fezName.includes('/'))) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
Fez.log(`Loading from ${url}`)
|
|
107
|
-
|
|
108
|
-
// Load HTML content via AJAX from URL
|
|
109
|
-
fetch(url)
|
|
110
|
-
.then(response => {
|
|
111
|
-
if (!response.ok) {
|
|
112
|
-
throw new Error(`Failed to load ${url}: ${response.status}`)
|
|
113
|
-
}
|
|
114
|
-
return response.text()
|
|
115
|
-
})
|
|
116
|
-
.then(htmlContent => {
|
|
117
|
-
// Check if remote HTML has template/xmp tags with fez attribute
|
|
118
|
-
const parser = new DOMParser()
|
|
119
|
-
const doc = parser.parseFromString(htmlContent, 'text/html')
|
|
120
|
-
const fezElements = doc.querySelectorAll('template[fez], xmp[fez]')
|
|
121
|
-
|
|
122
|
-
if (fezElements.length > 0) {
|
|
123
|
-
// Compile each found fez element
|
|
124
|
-
fezElements.forEach(el => {
|
|
125
|
-
const name = el.getAttribute('fez')
|
|
126
|
-
if (name && !name.includes('-') && !name.includes('.') && !name.includes('/')) {
|
|
127
|
-
console.error(`Fez: Invalid custom element name "${name}". Custom element names must contain a dash (e.g., 'my-element', 'ui-button').`)
|
|
128
|
-
}
|
|
129
|
-
const content = el.innerHTML
|
|
130
|
-
Fez.compile(name, content)
|
|
131
|
-
})
|
|
132
|
-
} else {
|
|
133
|
-
// No fez elements found, use extracted name from URL
|
|
134
|
-
const name = url.split('/').pop().split('.')[0]
|
|
135
|
-
Fez.compile(name, htmlContent)
|
|
136
|
-
}
|
|
137
|
-
})
|
|
138
|
-
.catch(error => {
|
|
139
|
-
console.error(`FEZ template load error for "${fezName}": ${error.message}`)
|
|
140
|
-
})
|
|
101
|
+
compile_from_url(fezName)
|
|
141
102
|
return
|
|
142
103
|
} else {
|
|
143
104
|
// Validate fezName format for non-URL names
|
|
144
105
|
if (fezName && !fezName.includes('-')) {
|
|
145
106
|
console.error(`Fez: Invalid custom element name "${fezName}". Custom element names must contain a dash (e.g., 'my-element', 'ui-button').`)
|
|
146
107
|
}
|
|
147
|
-
|
|
148
|
-
|
|
108
|
+
// Compile the node directly
|
|
109
|
+
return compile(fezName, node.innerHTML)
|
|
149
110
|
}
|
|
150
111
|
}
|
|
151
|
-
else
|
|
152
|
-
|
|
112
|
+
else {
|
|
113
|
+
let root = data ? Fez.domRoot(data) : document.body
|
|
114
|
+
|
|
115
|
+
root.querySelectorAll('template[fez], xmp[fez]').forEach((n) => {
|
|
116
|
+
compile_bulk(n)
|
|
117
|
+
})
|
|
118
|
+
|
|
153
119
|
return
|
|
154
120
|
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function compile_from_url(url) {
|
|
124
|
+
Fez.log(`Loading from ${url}`)
|
|
125
|
+
|
|
126
|
+
// Load HTML content via AJAX from URL
|
|
127
|
+
Fez.fetch(url)
|
|
128
|
+
.then(htmlContent => {
|
|
129
|
+
// Check if remote HTML has template/xmp tags with fez attribute
|
|
130
|
+
const parser = new DOMParser()
|
|
131
|
+
const doc = parser.parseFromString(htmlContent, 'text/html')
|
|
132
|
+
const fezElements = doc.querySelectorAll('template[fez], xmp[fez]')
|
|
133
|
+
|
|
134
|
+
if (fezElements.length > 0) {
|
|
135
|
+
// Compile each found fez element
|
|
136
|
+
fezElements.forEach(el => {
|
|
137
|
+
const name = el.getAttribute('fez')
|
|
138
|
+
if (name && !name.includes('-') && !name.includes('.') && !name.includes('/')) {
|
|
139
|
+
console.error(`Fez: Invalid custom element name "${name}". Custom element names must contain a dash (e.g., 'my-element', 'ui-button').`)
|
|
140
|
+
}
|
|
141
|
+
const content = el.innerHTML
|
|
142
|
+
compile(name, content)
|
|
143
|
+
})
|
|
144
|
+
} else {
|
|
145
|
+
// No fez elements found, use extracted name from URL
|
|
146
|
+
const name = url.split('/').pop().split('.')[0]
|
|
147
|
+
compile(name, htmlContent)
|
|
148
|
+
}
|
|
149
|
+
})
|
|
150
|
+
.catch(error => {
|
|
151
|
+
console.error(`FEZ template load error for "${url}": ${error.message}`)
|
|
152
|
+
})
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// <template fez="ui-form">
|
|
156
|
+
// <script>
|
|
157
|
+
// ...
|
|
158
|
+
// Fez.compile() # compile all
|
|
159
|
+
// Fez.compile(templateNode) # compile template node or string with template or xmp tags
|
|
160
|
+
// Fez.compile('ui-form', templateNode.innerHTML) # compile string
|
|
161
|
+
function compile(tagName, html) {
|
|
162
|
+
// Handle single argument cases
|
|
163
|
+
if (arguments.length === 1) {
|
|
164
|
+
return compile_bulk(tagName)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// If html contains </xmp>, send to compile_bulk for processing
|
|
168
|
+
if (html && html.includes('</xmp>')) {
|
|
169
|
+
return compile_bulk(html)
|
|
170
|
+
}
|
|
155
171
|
|
|
156
172
|
// Validate element name if it's not a URL
|
|
157
173
|
if (tagName && !tagName.includes('-') && !tagName.includes('.') && !tagName.includes('/')) {
|
|
@@ -171,7 +187,8 @@ export default function (tagName, html) {
|
|
|
171
187
|
styleContainer.id = 'fez-hidden-styles'
|
|
172
188
|
document.head.appendChild(styleContainer)
|
|
173
189
|
}
|
|
174
|
-
|
|
190
|
+
const allTags = [...Object.keys(Fez.classes), tagName].sort().join(', ')
|
|
191
|
+
styleContainer.textContent = `${allTags} { display: none; }\n`
|
|
175
192
|
}
|
|
176
193
|
|
|
177
194
|
// we cant try/catch javascript modules (they use imports)
|
|
@@ -193,3 +210,6 @@ export default function (tagName, html) {
|
|
|
193
210
|
}
|
|
194
211
|
}
|
|
195
212
|
}
|
|
213
|
+
|
|
214
|
+
export { compile_from_url }
|
|
215
|
+
export default compile
|
package/src/fez/connect.js
CHANGED
|
@@ -58,8 +58,8 @@ export default function(name, klass) {
|
|
|
58
58
|
|
|
59
59
|
// wrap slot to enable reactive re-renders. It will use existing .fez-slot if found
|
|
60
60
|
klass.html = klass.html.replace(/<slot\s*\/>|<slot\s*>\s*<\/slot>/g, () => {
|
|
61
|
-
const name = klass.
|
|
62
|
-
return `<${name} class="fez-slot"></${name}>`
|
|
61
|
+
const name = klass.SLOT || 'div'
|
|
62
|
+
return `<${name} class="fez-slot" fez-keep="default-slot"></${name}>`
|
|
63
63
|
})
|
|
64
64
|
|
|
65
65
|
klass.fezHtmlFunc = createTemplate(klass.html)
|
|
@@ -143,7 +143,7 @@ function connectNode(name, node) {
|
|
|
143
143
|
fez.props = klass.getProps(node, newNode)
|
|
144
144
|
fez.class = klass
|
|
145
145
|
|
|
146
|
-
//
|
|
146
|
+
// move child nodes, natively to preserve bound events
|
|
147
147
|
fez.slot(node, newNode)
|
|
148
148
|
|
|
149
149
|
newNode.fez = fez
|
|
@@ -161,22 +161,10 @@ function connectNode(name, node) {
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
fez.fezRegister();
|
|
164
|
-
(fez.init || fez.created || fez.connect).bind(fez)(fez.props);
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
if (fez.class.fezHtmlFunc) {
|
|
169
|
-
fez.render()
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const slot = fez.root.querySelector('.fez-slot')
|
|
173
|
-
if (slot) {
|
|
174
|
-
if (fez.props.html) {
|
|
175
|
-
slot.innerHTML = fez.props.html
|
|
176
|
-
} else {
|
|
177
|
-
fez.slot(oldRoot, slot)
|
|
178
|
-
}
|
|
179
|
-
}
|
|
164
|
+
;(fez.init || fez.created || fez.connect).bind(fez)(fez.props);
|
|
165
|
+
fez.render()
|
|
166
|
+
fez.firstRender = true
|
|
167
|
+
fez.onMount(fez.props)
|
|
180
168
|
|
|
181
169
|
if (fez.onSubmit) {
|
|
182
170
|
const form = fez.root.nodeName == 'FORM' ? fez.root : fez.find('form')
|
|
@@ -186,8 +174,6 @@ function connectNode(name, node) {
|
|
|
186
174
|
}
|
|
187
175
|
}
|
|
188
176
|
|
|
189
|
-
fez.onMount(fez.props)
|
|
190
|
-
|
|
191
177
|
// if onPropsChange method defined, add observer and trigger call on all attributes once component is loaded
|
|
192
178
|
if (fez.onPropsChange) {
|
|
193
179
|
observer.observe(newNode, {attributes:true})
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Wrap defaults in a function to avoid immediate execution
|
|
2
|
+
const loadDefaults = () => {
|
|
3
|
+
// include fez component by name
|
|
4
|
+
//<fez-component name="some-node" :props="fez.props"></fez-component>
|
|
5
|
+
Fez('fez-component', class {
|
|
6
|
+
FAST = true
|
|
7
|
+
|
|
8
|
+
init(props) {
|
|
9
|
+
const tag = document.createElement(props.name)
|
|
10
|
+
tag.props = props.props || props['data-props'] || props
|
|
11
|
+
|
|
12
|
+
while (this.root.firstChild) {
|
|
13
|
+
this.root.parentNode.insertBefore(this.root.lastChild, tag.nextSibling);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
this.root.innerHTML = ''
|
|
17
|
+
this.root.appendChild(tag)
|
|
18
|
+
}
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
// include remote data from url
|
|
22
|
+
// <fez-include src="./demo/fez/ui-slider.html"></fez-include>
|
|
23
|
+
Fez('fez-include', class {
|
|
24
|
+
FAST = true
|
|
25
|
+
|
|
26
|
+
init(props) {
|
|
27
|
+
Fez.fetch(props.src, (data)=>{
|
|
28
|
+
const dom = Fez.domRoot(data)
|
|
29
|
+
Fez.head(dom) // include scripts and load fez components
|
|
30
|
+
this.root.innerHTML = dom.innerHTML
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
// include remote data from url
|
|
36
|
+
// <fez-inline :state="{count: 0}">
|
|
37
|
+
// <button onclick="fez.state.count += 1">+</button>
|
|
38
|
+
// {{ state.count }} * {{ state.count }} = {{ state.count * state.count }}
|
|
39
|
+
// </fez-inline>
|
|
40
|
+
Fez('fez-inline', class {
|
|
41
|
+
init(props) {
|
|
42
|
+
const html = this.root.innerHTML
|
|
43
|
+
|
|
44
|
+
if (this.root.innerHTML.includes('<')) {
|
|
45
|
+
const hash = Fez.fnv1(this.root.outerHTML)
|
|
46
|
+
const nodeName = `inline-${hash}`
|
|
47
|
+
Fez(nodeName, class {
|
|
48
|
+
FAST = true
|
|
49
|
+
HTML = html
|
|
50
|
+
init() {
|
|
51
|
+
Object.assign(this.state, props.state || {})
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const el = document.createElement(nodeName)
|
|
56
|
+
this.root.after(this.root.lastChild, el);
|
|
57
|
+
this.root.remove()
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Only load defaults if Fez is available
|
|
64
|
+
if (typeof Fez !== 'undefined' && Fez) {
|
|
65
|
+
loadDefaults()
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Export for use in tests
|
|
69
|
+
export { loadDefaults }
|