@dinoreic/fez 0.2.2 → 0.3.0

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/src/fez/root.js CHANGED
@@ -117,7 +117,7 @@ Fez.globalCss = (cssClass, opts = {}) => {
117
117
  }
118
118
 
119
119
  Fez.info = () => {
120
- console.log(JSON.stringify(Fez.fastBindInfo, null, 2))
120
+ console.log('Fez components:', Object.keys(Fez.classes || {}))
121
121
  }
122
122
 
123
123
  Fez.morphdom = (target, newNode, opts = {}) => {
@@ -136,24 +136,6 @@ Fez.morphdom = (target, newNode, opts = {}) => {
136
136
  }
137
137
  }
138
138
 
139
- Fez.htmlEscape = (text) => {
140
- if (typeof text == 'string') {
141
- text = text
142
- // .replaceAll('&', "&")
143
- .replace(/font-family\s*:\s*(?:&[^;]+;|[^;])*?;/gi, '')
144
- .replaceAll("&", '&')
145
- .replaceAll("'", ''')
146
- .replaceAll('"', '"')
147
- .replaceAll('<', '&lt;')
148
- .replaceAll('>', '&gt;')
149
- // .replaceAll('@', '&#64;') // needed for template escaping
150
-
151
- return text
152
- } else {
153
- return text === undefined ? '' : text
154
- }
155
- }
156
-
157
139
  Fez.publish = (channel, ...args) => {
158
140
  Fez._subs ||= {}
159
141
  Fez._subs[channel] ||= []
@@ -183,6 +165,19 @@ Fez.tag = (tag, opts = {}, html = '') => {
183
165
  // return data
184
166
  };
185
167
 
168
+ // Resolve a function from a string or function reference
169
+ Fez.getFunction = (pointer) => {
170
+ if (!pointer) {
171
+ return ()=>{}
172
+ }
173
+ else if (typeof pointer === 'function') {
174
+ return pointer;
175
+ }
176
+ else if (typeof pointer === 'string') {
177
+ return new Function(pointer);
178
+ }
179
+ };
180
+
186
181
  Fez.error = (text, show) => {
187
182
  text = `Fez: ${text}`
188
183
  console.error(text)
@@ -211,125 +206,25 @@ Fez.untilTrue = (func, pingRate) => {
211
206
  }
212
207
  }
213
208
 
214
- // Script from URL
215
- // Fez.head({ js: 'https://example.com/script.js' });
216
- // Script with attributes
217
- // Fez.head({ js: 'https://example.com/script.js', type: 'module', async: true });
218
- // Script with callback
219
- // Fez.head({ js: 'https://example.com/script.js' }, () => { console.log('loaded') });
220
- // Module loading with auto-import to window
221
- // Fez.head({ js: 'https://example.com/module.js', module: 'MyModule' }); // imports and sets window.MyModule
222
- // CSS inclusion
223
- // Fez.head({ css: 'https://example.com/styles.css' });
224
- // CSS with additional attributes and callback
225
- // Fez.head({ css: 'https://example.com/styles.css', media: 'print' }, () => { console.log('CSS loaded') })
226
- // Inline script evaluation
227
- // Fez.head({ script: 'console.log("Hello world")' })
228
- // Extract from nodes
229
- // Fez.head(domNode)
230
- Fez.head = (config, callback) => {
231
- if (config.nodeName) {
232
- if (config.nodeName == 'SCRIPT') {
233
- Fez.head({script: config.innerText})
234
- config.remove()
235
- } else {
236
- config.querySelectorAll('script').forEach((n) => Fez.head(n) )
237
- config.querySelectorAll('template[fez], xmp[fez], script[fez]').forEach((n) => Fez.compile(n) )
238
- }
209
+ // throttle function calls
210
+ Fez.throttle = (func, delay = 200) => {
211
+ let lastRun = 0;
212
+ let timeout;
239
213
 
240
- return
241
- }
214
+ return function(...args) {
215
+ const now = Date.now();
242
216
 
243
- if (typeof config !== 'object' || config === null) {
244
- throw new Error('head requires an object parameter');
245
- }
246
-
247
- let src, attributes = {}, elementType;
248
-
249
- if (config.script) {
250
- if (config.script.includes('import ')) {
251
- if (callback) {
252
- Fez.error('Fez.head callback is not supported when script with import is passed (module context).')
253
- }
254
-
255
- // Evaluate inline script in context in the module
256
- const script = document.createElement('script');
257
- script.type = 'module';
258
- script.textContent = config.script;
259
- document.head.appendChild(script);
260
- setTimeout(()=>script.remove(), 100)
217
+ if (now - lastRun >= delay) {
218
+ func.apply(this, args);
219
+ lastRun = now;
261
220
  } else {
262
- try {
263
- new Function(config.script)();
264
- if (callback) callback();
265
- } catch (error) {
266
- Fez.error('Error executing script:', error);
267
- console.log(config.script);
268
- }
269
- }
270
- return;
271
- } else if (config.js) {
272
- src = config.js;
273
- elementType = 'script';
274
- // Copy all properties except 'js' as attributes
275
- for (const [key, value] of Object.entries(config)) {
276
- if (key !== 'js' && key !== 'module') {
277
- attributes[key] = value;
278
- }
279
- }
280
- // Handle module loading
281
- if (config.module) {
282
- attributes.type = 'module';
283
- }
284
- } else if (config.css) {
285
- src = config.css;
286
- elementType = 'link';
287
- attributes.rel = 'stylesheet';
288
- // Copy all properties except 'css' as attributes
289
- for (const [key, value] of Object.entries(config)) {
290
- if (key !== 'css') {
291
- attributes[key] = value;
292
- }
221
+ clearTimeout(timeout);
222
+ timeout = setTimeout(() => {
223
+ func.apply(this, args);
224
+ lastRun = Date.now();
225
+ }, delay - (now - lastRun));
293
226
  }
294
- } else {
295
- throw new Error('head requires either "script", "js" or "css" property');
296
- }
297
-
298
- const existingNode = document.querySelector(`${elementType}[src="${src}"], ${elementType}[href="${src}"]`);
299
- if (existingNode) {
300
- if (callback) callback();
301
- return existingNode;
302
- }
303
-
304
- const element = document.createElement(elementType);
305
-
306
- if (elementType === 'link') {
307
- element.href = src;
308
- } else {
309
- element.src = src;
310
- }
311
-
312
- for (const [key, value] of Object.entries(attributes)) {
313
- element.setAttribute(key, value);
314
- }
315
-
316
- if (callback || config.module) {
317
- element.onload = () => {
318
- // If module name is provided, import it and assign to window
319
- if (config.module && elementType === 'script') {
320
- import(src).then(module => {
321
- window[config.module] = module.default || module[config.module] || module;
322
- }).catch(error => {
323
- console.error(`Error importing module ${config.module}:`, error);
324
- });
325
- }
326
- if (callback) callback();
327
- };
328
- }
329
-
330
- document.head.appendChild(element);
331
-
332
- return element;
227
+ };
333
228
  }
334
229
 
335
230
  // Fetch wrapper with automatic caching and data handling
@@ -475,24 +370,9 @@ Fez.store = {
475
370
  }
476
371
  };
477
372
 
478
- // create dom root and return it
479
- Fez.domRoot = (data, name = 'div') => {
480
- if (data instanceof Node) {
481
- return data
482
- } else {
483
- const root = document.createElement(name)
484
- root.innerHTML = data
485
- return root
486
- }
487
- }
488
-
489
- // add class by name to node and remove it from siblings
490
- Fez.activateNode = (node, klass = 'active') => {
491
- Array.from(node.parentElement.children).forEach(child => {
492
- child.classList.remove(klass)
493
- })
494
- node.classList.add(klass)
495
- }
373
+ // Load utility functions
374
+ import addUtilities from './utility.js'
375
+ addUtilities(Fez)
496
376
 
497
377
  Fez.compile = compile
498
378
  Fez.state = state
@@ -0,0 +1,184 @@
1
+ // Utility functions that extend Fez
2
+ export default (Fez) => {
3
+ // Script from URL
4
+ // Fez.head({ js: 'https://example.com/script.js' });
5
+ // Script with attributes
6
+ // Fez.head({ js: 'https://example.com/script.js', type: 'module', async: true });
7
+ // Script with callback
8
+ // Fez.head({ js: 'https://example.com/script.js' }, () => { console.log('loaded') });
9
+ // Module loading with auto-import to window
10
+ // Fez.head({ js: 'https://example.com/module.js', module: 'MyModule' }); // imports and sets window.MyModule
11
+ // CSS inclusion
12
+ // Fez.head({ css: 'https://example.com/styles.css' });
13
+ // CSS with additional attributes and callback
14
+ // Fez.head({ css: 'https://example.com/styles.css', media: 'print' }, () => { console.log('CSS loaded') })
15
+ // Inline script evaluation
16
+ // Fez.head({ script: 'console.log("Hello world")' })
17
+ // Extract from nodes
18
+ // Fez.head(domNode)
19
+ Fez.head = (config, callback) => {
20
+ if (config.nodeName) {
21
+ if (config.nodeName == 'SCRIPT') {
22
+ Fez.head({script: config.innerText})
23
+ config.remove()
24
+ } else {
25
+ config.querySelectorAll('script').forEach((n) => Fez.head(n) )
26
+ config.querySelectorAll('template[fez], xmp[fez], script[fez]').forEach((n) => Fez.compile(n) )
27
+ }
28
+
29
+ return
30
+ }
31
+
32
+ if (typeof config !== 'object' || config === null) {
33
+ throw new Error('head requires an object parameter');
34
+ }
35
+
36
+ let src, attributes = {}, elementType;
37
+
38
+ if (config.script) {
39
+ if (config.script.includes('import ')) {
40
+ if (callback) {
41
+ Fez.error('Fez.head callback is not supported when script with import is passed (module context).')
42
+ }
43
+
44
+ // Evaluate inline script in context in the module
45
+ const script = document.createElement('script');
46
+ script.type = 'module';
47
+ script.textContent = config.script;
48
+ document.head.appendChild(script);
49
+ setTimeout(()=>script.remove(), 100)
50
+ } else {
51
+ try {
52
+ new Function(config.script)();
53
+ if (callback) callback();
54
+ } catch (error) {
55
+ Fez.error('Error executing script:', error);
56
+ console.log(config.script);
57
+ }
58
+ }
59
+ return;
60
+ } else if (config.js) {
61
+ src = config.js;
62
+ elementType = 'script';
63
+ // Copy all properties except 'js' as attributes
64
+ for (const [key, value] of Object.entries(config)) {
65
+ if (key !== 'js' && key !== 'module') {
66
+ attributes[key] = value;
67
+ }
68
+ }
69
+ // Handle module loading
70
+ if (config.module) {
71
+ attributes.type = 'module';
72
+ }
73
+ } else if (config.css) {
74
+ src = config.css;
75
+ elementType = 'link';
76
+ attributes.rel = 'stylesheet';
77
+ // Copy all properties except 'css' as attributes
78
+ for (const [key, value] of Object.entries(config)) {
79
+ if (key !== 'css') {
80
+ attributes[key] = value;
81
+ }
82
+ }
83
+ } else {
84
+ throw new Error('head requires either "script", "js" or "css" property');
85
+ }
86
+
87
+ const existingNode = document.querySelector(`${elementType}[src="${src}"], ${elementType}[href="${src}"]`);
88
+ if (existingNode) {
89
+ if (callback) callback();
90
+ return existingNode;
91
+ }
92
+
93
+ const element = document.createElement(elementType);
94
+
95
+ if (elementType === 'link') {
96
+ element.href = src;
97
+ } else {
98
+ element.src = src;
99
+ }
100
+
101
+ for (const [key, value] of Object.entries(attributes)) {
102
+ element.setAttribute(key, value);
103
+ }
104
+
105
+ if (callback || config.module) {
106
+ element.onload = () => {
107
+ // If module name is provided, import it and assign to window
108
+ if (config.module && elementType === 'script') {
109
+ import(src).then(module => {
110
+ window[config.module] = module.default || module[config.module] || module;
111
+ }).catch(error => {
112
+ console.error(`Error importing module ${config.module}:`, error);
113
+ });
114
+ }
115
+ if (callback) callback();
116
+ };
117
+ }
118
+
119
+ document.head.appendChild(element);
120
+
121
+ return element;
122
+ }
123
+
124
+ Fez.darkenColor = (color, percent = 20) => {
125
+ // Convert hex to RGB
126
+ const num = parseInt(color.replace("#", ""), 16)
127
+ const amt = Math.round(2.55 * percent)
128
+ const R = (num >> 16) - amt
129
+ const G = (num >> 8 & 0x00FF) - amt
130
+ const B = (num & 0x0000FF) - amt
131
+ return "#" + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 + (G < 255 ? G < 1 ? 0 : G : 255) * 0x100 + (B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1)
132
+ }
133
+
134
+ Fez.lightenColor = (color, percent = 20) => {
135
+ // Convert hex to RGB
136
+ const num = parseInt(color.replace("#", ""), 16)
137
+ const amt = Math.round(2.55 * percent)
138
+ const R = (num >> 16) + amt
139
+ const G = (num >> 8 & 0x00FF) + amt
140
+ const B = (num & 0x0000FF) + amt
141
+ return "#" + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 + (G < 255 ? G < 1 ? 0 : G : 255) * 0x100 + (B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1)
142
+ }
143
+
144
+ Fez.htmlEscape = (text) => {
145
+ if (typeof text == 'string') {
146
+ text = text
147
+ // .replaceAll('&', "&amp;")
148
+ .replace(/font-family\s*:\s*(?:&[^;]+;|[^;])*?;/gi, '')
149
+ .replaceAll("&", '&amp;')
150
+ .replaceAll("'", '&apos;')
151
+ .replaceAll('"', '&quot;')
152
+ .replaceAll('<', '&lt;')
153
+ .replaceAll('>', '&gt;')
154
+ // .replaceAll('@', '&#64;') // needed for template escaping
155
+
156
+ return text
157
+ } else {
158
+ return text === undefined ? '' : text
159
+ }
160
+ }
161
+
162
+ // create dom root and return it
163
+ Fez.domRoot = (data, name = 'div') => {
164
+ if (data instanceof Node) {
165
+ return data
166
+ } else {
167
+ const root = document.createElement(name)
168
+ root.innerHTML = data
169
+ return root
170
+ }
171
+ }
172
+
173
+ // add class by name to node and remove it from siblings
174
+ Fez.activateNode = (node, klass = 'active') => {
175
+ Array.from(node.parentElement.children).forEach(child => {
176
+ child.classList.remove(klass)
177
+ })
178
+ node.classList.add(klass)
179
+ }
180
+
181
+ Fez.isTrue = (val) => {
182
+ return ['1', 'true', 'on'].includes(String(val).toLowerCase())
183
+ }
184
+ }
package/src/fez.js CHANGED
@@ -14,7 +14,7 @@ setInterval(() => {
14
14
  for (const [key, el] of Fez.instances) {
15
15
  if (!el?.isConnected) {
16
16
  // Fez.error(`Found junk instance that is not connected ${el.fezName}`)
17
- el.fez?.fezRemoveSelf()
17
+ el.fez?.fezOnDestroy()
18
18
  Fez.instances.delete(key)
19
19
  }
20
20
  }
@@ -47,7 +47,7 @@ const observer = new MutationObserver((mutations) => {
47
47
  .forEach(el => {
48
48
  if (el.fez && el.root) {
49
49
  Fez.instances.delete(el.fez.UID)
50
- el.fez.fezRemoveSelf()
50
+ el.fez.fezOnDestroy()
51
51
  }
52
52
  });
53
53
  }
package/src/rollup.js CHANGED
@@ -1,25 +1,82 @@
1
- function fezPlugin() {
2
- return {
3
- name: 'fez-plugin',
1
+ // import .fez files and import globing via fezImport(./foo/bar/*)
2
+ // svelte is transformed to component import, all other files are copied
3
+ //
4
+ // rollup.config.js
5
+ // import fezImport from '@dinoreic/fez/rollup';
6
+ // plugins: [fezImport(), ...]
7
+
8
+ import { glob } from 'glob';
9
+ import path from 'path';
4
10
 
5
- transform(code, filePath) {
6
- const baseName = filePath.split('/').pop().split('.');
11
+ // compile fez files
12
+ const transformFez = (code, filePath) => {
13
+ const baseName = filePath.split('/').pop().split('.');
14
+
15
+ if (baseName[1] === 'fez') {
16
+ code = code.replace(/`/g, '\\`').replace(/\$/g, '\\$');
17
+ return `Fez.compile('${baseName[0]}', \`\n${code}\`)`;
18
+ }
19
+ }
7
20
 
8
- if (baseName[1] === 'fez') {
9
- code = code.replace(/`/g, '\\`').replace(/\$/g, '\\$');
10
- const transformedCode = `Fez.compile('${baseName[0]}', \`\n${code}\`)`;
21
+ // glob import files
22
+ const transformGlob = async (code, filePath) => {
23
+ // Only process .js files containing glob statements
24
+ if (!filePath.endsWith('.js')) {
25
+ return null;
26
+ }
11
27
 
12
- // if (baseName[0] === 'admin-menu') {
13
- // console.log('Transformed code:', baseName, transformedCode);
14
- // }
28
+ // Check for fezImport() function calls
29
+ const globImportMatch = code.match(/fezImport\(['"`]([^'"`]+)['"`]\)/);
30
+ if (globImportMatch) {
31
+ const globPattern = globImportMatch[1];
15
32
 
16
- return {
17
- code: transformedCode,
18
- map: null,
19
- };
33
+ // Resolve relative path from the file's directory
34
+ const fileDir = path.dirname(filePath);
35
+ const resolvedPattern = path.resolve(fileDir, globPattern);
36
+
37
+ const files = await glob(resolvedPattern, { absolute: true });
38
+ const imports = [];
39
+ const bindings = [];
40
+
41
+ console.log('fezGlob(', globPattern, '), files:', files.length);
42
+
43
+ for (const file of files.sort()) {
44
+ if (file.endsWith('.svelte')) {
45
+ // Transform Svelte files with bindings
46
+ const name = path.basename(file, '.svelte').replace(/-/g, '_');
47
+ imports.push(`import Svelte_${name} from '${file}';`);
48
+ bindings.push(`Svelte.connect('s-${name.replace(/_/g, '-')}', Svelte_${name});`);
49
+ } else {
50
+ // Regular import for all other files
51
+ const name = path.basename(file, path.extname(file)).replace(/-/g, '_');
52
+ imports.push(`import ${name} from '${file}';`);
20
53
  }
54
+ }
55
+
56
+ const replacement = [...imports, '', ...bindings].join('\n');
57
+ return code.replace(globImportMatch[0], replacement);
58
+ }
59
+
60
+ return null;
61
+ }
62
+
63
+ export default function fezImport() {
64
+ return {
65
+ name: 'fez-plugin',
66
+
67
+ async transform(code, filePath) {
68
+ for (const func of [transformFez, transformGlob]) {
69
+ const result = await func(code, filePath);
70
+ if (result) {
71
+ return {
72
+ code: result,
73
+ map: null,
74
+ };
75
+ }
76
+ }
77
+
78
+ return null;
21
79
  },
22
80
  };
23
81
  }
24
82
 
25
- export default fezPlugin;
package/dist/rollup.js DELETED
@@ -1,3 +0,0 @@
1
- (()=>{function t(){return{name:"fez-plugin",transform(e,r){let n=r.split("/").pop().split(".");if(n[1]==="fez")return e=e.replace(/`/g,"\\`").replace(/\$/g,"\\$"),{code:`Fez.compile('${n[0]}', \`
2
- ${e}\`)`,map:null}}}}var l=t;})();
3
- //# sourceMappingURL=rollup.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 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\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
- "names": ["fezPlugin", "code", "filePath", "baseName", "rollup_default"]
7
- }