@dinoreic/fez 0.1.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.
@@ -0,0 +1,465 @@
1
+ // runtime scss
2
+ import Gobber from './vendor/gobber.js'
3
+
4
+ // morph dom from one state to another
5
+ import { Idiomorph } from './vendor/idiomorph.js'
6
+
7
+ import connect from './connect.js'
8
+ import compile from './compile.js'
9
+ import state from './lib/global-state.js'
10
+
11
+ // Fez('ui-slider') # first slider
12
+ // Fez('ui-slider', (n)=>alert(n)) # find all and execute
13
+ // Fez(this, 'ui-slider') # first parent ui-slider
14
+ // Fez('ui-slider', class { init() { ... }}) # create Fez dom node
15
+ const Fez = (name, klass) => {
16
+ if(typeof name === 'number') {
17
+ const fez = Fez.instances.get(name)
18
+ if (fez) {
19
+ return fez
20
+ } else {
21
+ Fez.error(`Instance with UID "${name}" not found.`)
22
+ }
23
+ }
24
+ else if (name) {
25
+ if (klass) {
26
+ const isPureFn = typeof klass === 'function' && !/^\s*class/.test(klass.toString()) && !/\b(this|new)\b/.test(klass.toString())
27
+
28
+ if (isPureFn) {
29
+ const list = Array
30
+ .from(document.querySelectorAll(`.fez.fez-${name}`))
31
+ .filter( n => n.fez )
32
+
33
+ list.forEach( el => klass(el.fez) )
34
+ return list
35
+ } else if (typeof klass != 'function') {
36
+ return Fez.find(name, klass)
37
+ } else {
38
+ return connect(name, klass)
39
+ }
40
+ } else {
41
+ const node = name.nodeName ? name.closest('.fez') : (
42
+ document.querySelector( name.includes('#') ? name : `.fez.fez-${name}` )
43
+ )
44
+ if (node) {
45
+ if (node.fez) {
46
+ return node.fez
47
+ } else {
48
+ Fez.error(`node "${name}" has no Fez attached.`)
49
+ }
50
+ } else {
51
+ Fez.error(`node "${name}" not found.`)
52
+ }
53
+ }
54
+ } else {
55
+ Fez.error('Fez() ?')
56
+ }
57
+ }
58
+
59
+ Fez.classes = {}
60
+ Fez.instanceCount = 0
61
+ Fez.instances = new Map()
62
+
63
+ Fez.find = (onode, name) => {
64
+ let node = onode
65
+
66
+ if (typeof node == 'string') {
67
+ node = document.body.querySelector(node)
68
+ }
69
+
70
+ if (typeof node.val == 'function') {
71
+ node = node[0]
72
+ }
73
+
74
+ const klass = name ? `.fez.fez-${name}` : '.fez'
75
+
76
+ const closestNode = node.closest(klass)
77
+ if (closestNode && closestNode.fez) {
78
+ return closestNode.fez
79
+ } else {
80
+ console.error('Fez node connector not found', onode, node)
81
+ }
82
+ }
83
+
84
+ Fez.cssClass = (text) => {
85
+ return Gobber.css(text)
86
+ }
87
+
88
+ Fez.globalCss = (cssClass, opts = {}) => {
89
+ if (typeof cssClass === 'function') {
90
+ cssClass = cssClass()
91
+ }
92
+
93
+ if (cssClass.includes(':')) {
94
+ let text = cssClass
95
+ .split("\n")
96
+ .filter(line => !(/^\s*\/\//.test(line)))
97
+ .join("\n")
98
+
99
+ if (opts.wrap) {
100
+ text = `:fez { ${text} }`
101
+ }
102
+
103
+ text = text.replace(/\:fez|\:host/, `.fez.fez-${opts.name}`)
104
+
105
+ cssClass = Fez.cssClass(text)
106
+ }
107
+
108
+ if (document.body) {
109
+ document.body.parentElement.classList.add(cssClass)
110
+ } else {
111
+ document.addEventListener("DOMContentLoaded", () => {
112
+ document.body.parentElement.classList.add(cssClass)
113
+ })
114
+ }
115
+
116
+ return cssClass
117
+ }
118
+
119
+ Fez.info = () => {
120
+ console.log(JSON.stringify(Fez.fastBindInfo, null, 2))
121
+ }
122
+
123
+ Fez.morphdom = (target, newNode, opts = {}) => {
124
+ Array.from(target.attributes).forEach(attr => {
125
+ newNode.setAttribute(attr.name, attr.value)
126
+ })
127
+
128
+ Idiomorph.morph(target, newNode, {
129
+ morphStyle: 'outerHTML'
130
+ })
131
+
132
+ // remove whitespace on next node, if exists (you never want this)
133
+ const nextSibling = target.nextSibling
134
+ if (nextSibling?.nodeType === Node.TEXT_NODE && nextSibling.textContent.trim() === '') {
135
+ nextSibling.remove();
136
+ }
137
+ }
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('<', '&lt;')
147
+ .replaceAll('>', '&gt;')
148
+ // .replaceAll('@', '&#64;') // needed for template escaping
149
+
150
+ return text
151
+ } else {
152
+ return text === undefined ? '' : text
153
+ }
154
+ }
155
+
156
+ Fez.publish = (channel, ...args) => {
157
+ Fez._subs ||= {}
158
+ Fez._subs[channel] ||= []
159
+ Fez._subs[channel].forEach((el) => {
160
+ el[1].bind(el[0])(...args)
161
+ })
162
+ }
163
+
164
+ // get unique id from string
165
+ Fez.fnv1 = (str) => {
166
+ var FNV_OFFSET_BASIS, FNV_PRIME, hash, i, j, ref;
167
+ FNV_OFFSET_BASIS = 2166136261;
168
+ FNV_PRIME = 16777619;
169
+ hash = FNV_OFFSET_BASIS;
170
+ for (i = j = 0, ref = str.length - 1; (0 <= ref ? j <= ref : j >= ref); i = 0 <= ref ? ++j : --j) {
171
+ hash ^= str.charCodeAt(i);
172
+ hash *= FNV_PRIME;
173
+ }
174
+ return hash.toString(36).replaceAll('-', '');
175
+ }
176
+
177
+ Fez.tag = (tag, opts = {}, html = '') => {
178
+ const json = encodeURIComponent(JSON.stringify(opts))
179
+ return `<${tag} data-props="${json}">${html}</${tag}>`
180
+ // const json = JSON.stringify(opts, null, 2)
181
+ // const data = `<script type="text/template">${json}</script><${tag} data-json-template="true">${html}</${tag}>`
182
+ // return data
183
+ };
184
+
185
+ Fez.error = (text, show) => {
186
+ text = `Fez: ${text}`
187
+ console.error(text)
188
+ if (show) {
189
+ return `<span style="border: 1px solid red; font-size: 14px; padding: 3px 7px; background: #fee; border-radius: 4px;">${text}</span>`
190
+ }
191
+ }
192
+ Fez.log = (text) => {
193
+ if (Fez.LOG === true) {
194
+ console.log(`Fez: ${text}`)
195
+ }
196
+ }
197
+ document.addEventListener('DOMContentLoaded', () => {
198
+ Fez.log('Fez.LOG === true, logging enabled.')
199
+ })
200
+
201
+ // execute function until it returns true
202
+ Fez.untilTrue = (func, pingRate) => {
203
+ pingRate ||= 200
204
+
205
+ if (!func()) {
206
+ setTimeout(()=>{
207
+ Fez.untilTrue(func, pingRate)
208
+ } ,pingRate)
209
+ }
210
+ }
211
+
212
+ // Script from URL
213
+ // head({ js: 'https://example.com/script.js' });
214
+ // Script with attributes
215
+ // head({ js: 'https://example.com/script.js', type: 'module', async: true });
216
+ // Script with callback
217
+ // head({ js: 'https://example.com/script.js' }, () => { console.log('loaded') });
218
+ // Module loading with auto-import to window
219
+ // head({ js: 'https://example.com/module.js', module: 'MyModule' }); // imports and sets window.MyModule
220
+ // CSS inclusion
221
+ // head({ css: 'https://example.com/styles.css' });
222
+ // CSS with additional attributes and callback
223
+ // head({ css: 'https://example.com/styles.css', media: 'print' }, () => { console.log('CSS loaded') })
224
+ // Inline script evaluation
225
+ // head({ script: 'console.log("Hello world")' })
226
+ Fez.head = (config, callback) => {
227
+ if (typeof config !== 'object' || config === null) {
228
+ throw new Error('head requires an object parameter');
229
+ }
230
+
231
+ let src, attributes = {}, elementType;
232
+
233
+ if (config.script) {
234
+ if (config.script.includes('import ')) {
235
+ if (callback) {
236
+ Fez.error('Fez.head callback is not supported when script with import is passed (module context).')
237
+ }
238
+
239
+ // Evaluate inline script in context in the module
240
+ const script = document.createElement('script');
241
+ script.type = 'module';
242
+ script.textContent = config.script;
243
+ document.head.appendChild(script);
244
+ setTimeout(()=>script.remove(), 100)
245
+ } else {
246
+ try {
247
+ new Function(config.script)();
248
+ if (callback) callback();
249
+ } catch (error) {
250
+ Fez.error('Error executing script:', error);
251
+ console.log(config.script);
252
+ }
253
+ }
254
+ return;
255
+ } else if (config.js) {
256
+ src = config.js;
257
+ elementType = 'script';
258
+ // Copy all properties except 'js' as attributes
259
+ for (const [key, value] of Object.entries(config)) {
260
+ if (key !== 'js' && key !== 'module') {
261
+ attributes[key] = value;
262
+ }
263
+ }
264
+ // Handle module loading
265
+ if (config.module) {
266
+ attributes.type = 'module';
267
+ }
268
+ } else if (config.css) {
269
+ src = config.css;
270
+ elementType = 'link';
271
+ attributes.rel = 'stylesheet';
272
+ // Copy all properties except 'css' as attributes
273
+ for (const [key, value] of Object.entries(config)) {
274
+ if (key !== 'css') {
275
+ attributes[key] = value;
276
+ }
277
+ }
278
+ } else {
279
+ throw new Error('head requires either "script", "js" or "css" property');
280
+ }
281
+
282
+ const existingNode = document.querySelector(`${elementType}[src="${src}"], ${elementType}[href="${src}"]`);
283
+ if (existingNode) {
284
+ if (callback) callback();
285
+ return existingNode;
286
+ }
287
+
288
+ const element = document.createElement(elementType);
289
+
290
+ if (elementType === 'link') {
291
+ element.href = src;
292
+ } else {
293
+ element.src = src;
294
+ }
295
+
296
+ for (const [key, value] of Object.entries(attributes)) {
297
+ element.setAttribute(key, value);
298
+ }
299
+
300
+ if (callback || config.module) {
301
+ element.onload = () => {
302
+ // If module name is provided, import it and assign to window
303
+ if (config.module && elementType === 'script') {
304
+ import(src).then(module => {
305
+ window[config.module] = module.default || module[config.module] || module;
306
+ }).catch(error => {
307
+ console.error(`Error importing module ${config.module}:`, error);
308
+ });
309
+ }
310
+ if (callback) callback();
311
+ };
312
+ }
313
+
314
+ document.head.appendChild(element);
315
+
316
+ return element;
317
+ }
318
+
319
+ // Fetch wrapper with automatic caching and data handling
320
+ // Usage:
321
+ // Fez.fetch(url) - GET request (default)
322
+ // Fez.fetch(url, callback) - GET with callback
323
+ // Fez.fetch(url, data) - GET with query params (?foo=bar&baz=qux)
324
+ // Fez.fetch(url, data, callback) - GET with query params and callback
325
+ // Fez.fetch('POST', url, data) - POST with FormData body (multipart/form-data)
326
+ // Fez.fetch('POST', url, data, callback) - POST with FormData and callback
327
+ // Data object is automatically converted:
328
+ // - GET: appended as URL query parameters
329
+ // - POST: sent as FormData (multipart/form-data) without custom headers
330
+ Fez.fetch = function(...args) {
331
+ // Initialize cache if not exists
332
+ Fez._fetchCache ||= {};
333
+
334
+ let method = 'GET';
335
+ let url;
336
+ let callback;
337
+
338
+ // Check if first arg is HTTP method (uppercase letters)
339
+ if (typeof args[0] === 'string' && /^[A-Z]+$/.test(args[0])) {
340
+ method = args.shift();
341
+ }
342
+
343
+ // URL is required
344
+ url = args.shift();
345
+
346
+ // Check for data/options object
347
+ let opts = {};
348
+ let data = null;
349
+ if (typeof args[0] === 'object') {
350
+ data = args.shift();
351
+ }
352
+
353
+ // Check for callback function
354
+ if (typeof args[0] === 'function') {
355
+ callback = args.shift();
356
+ }
357
+
358
+ // Handle data based on method
359
+ if (data) {
360
+ if (method === 'GET') {
361
+ // For GET, append data as query parameters
362
+ const params = new URLSearchParams(data);
363
+ url += (url.includes('?') ? '&' : '?') + params.toString();
364
+ } else if (method === 'POST') {
365
+ // For POST, convert to FormData
366
+ const formData = new FormData();
367
+ for (const [key, value] of Object.entries(data)) {
368
+ formData.append(key, value);
369
+ }
370
+ opts.body = formData;
371
+ }
372
+ }
373
+
374
+ // Set method
375
+ opts.method = method;
376
+
377
+ // Create cache key from method, url, and stringified opts
378
+ const cacheKey = `${method}:${url}:${JSON.stringify(opts)}`;
379
+
380
+ // Check cache first
381
+ if (Fez._fetchCache[cacheKey]) {
382
+ const cachedData = Fez._fetchCache[cacheKey];
383
+ Fez.log(`fetch cache hit: ${method} ${url}`);
384
+ if (callback) {
385
+ callback(cachedData);
386
+ return;
387
+ }
388
+ return Promise.resolve(cachedData);
389
+ }
390
+
391
+ // Log live fetch
392
+ Fez.log(`fetch live: ${method} ${url}`);
393
+
394
+ // Helper to process and cache response
395
+ const processResponse = (response) => {
396
+ if (response.headers.get('content-type')?.includes('application/json')) {
397
+ return response.json();
398
+ }
399
+ return response.text();
400
+ };
401
+
402
+ // If callback provided, execute and handle
403
+ if (callback) {
404
+ fetch(url, opts)
405
+ .then(processResponse)
406
+ .then(data => {
407
+ Fez._fetchCache[cacheKey] = data;
408
+ callback(data);
409
+ })
410
+ .catch(error => Fez.onError('fetch', error));
411
+ return;
412
+ }
413
+
414
+ // Return promise with automatic JSON parsing
415
+ return fetch(url, opts)
416
+ .then(processResponse)
417
+ .then(data => {
418
+ Fez._fetchCache[cacheKey] = data;
419
+ return data;
420
+ });
421
+ }
422
+
423
+ Fez.onError = (kind, message) => {
424
+ // Ensure kind is always a string
425
+ if (typeof kind !== 'string') {
426
+ throw new Error('Fez.onError: kind must be a string');
427
+ }
428
+
429
+ console.error(`${kind}: ${message.toString()}`);
430
+ }
431
+
432
+ // define custom style macro
433
+ // Fez.styleMacro('mobile', '@media (max-width: 768px)')
434
+ // :mobile { ... } -> @media (max-width: 768px) { ... }
435
+ Fez._styleMacros = {}
436
+ Fez.styleMacro = (name, content) => {
437
+ Fez._styleMacros[name] = content
438
+ }
439
+
440
+ // work with tmp store
441
+ Fez.store = {
442
+ store: new Map(),
443
+ counter: 0,
444
+
445
+ set(value) {
446
+ const key = this.counter++;
447
+ this.store.set(key, value);
448
+ return key;
449
+ },
450
+
451
+ get(key) {
452
+ return this.store.get(key);
453
+ },
454
+
455
+ delete(key) {
456
+ const value = this.store.get(key);
457
+ this.store.delete(key)
458
+ return value;
459
+ }
460
+ };
461
+
462
+ Fez.compile = compile
463
+ Fez.state = state
464
+
465
+ export default Fez
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Skipped minification because the original files appears to be already minified.
3
+ * Original file: /npm/goober@2.1.14/dist/goober.modern.js
4
+ *
5
+ * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
6
+ */
7
+ let e={data:""},t=t=>"object"==typeof window?((t?t.querySelector("#_goober"):window._goober)||Object.assign((t||document.head).appendChild(document.createElement("style")),{innerHTML:" ",id:"_goober"})).firstChild:t||e,a=e=>{let a=t(e),r=a.data;return a.data="",r},r=/(?:([\u0080-\uFFFF\w-%@]+) *:? *([^{;]+?);|([^;}{]*?) *{)|(}\s*)/g,l=/\/\*[^]*?\*\/| +/g,s=/\n+/g,n=(e,t)=>{let a="",r="",l="";for(let s in e){let o=e[s];"@"==s[0]?"i"==s[1]?a=s+" "+o+";":r+="f"==s[1]?n(o,s):s+"{"+n(o,"k"==s[1]?"":t)+"}":"object"==typeof o?r+=n(o,t?t.replace(/([^,])+/g,(e=>s.replace(/(^:.*)|([^,])+/g,(t=>/&/.test(t)?t.replace(/&/g,e):e?e+" "+t:t)))):s):null!=o&&(s=/^--/.test(s)?s:s.replace(/[A-Z]/g,"-$&").toLowerCase(),l+=n.p?n.p(s,o):s+":"+o+";")}return a+(t&&l?t+"{"+l+"}":l)+r},o={},c=e=>{if("object"==typeof e){let t="";for(let a in e)t+=a+c(e[a]);return t}return e},i=(e,t,a,i,p)=>{let u=c(e),d=o[u]||(o[u]=(e=>{let t=0,a=11;for(;t<e.length;)a=101*a+e.charCodeAt(t++)>>>0;return"go"+a})(u));if(!o[d]){let t=u!==e?e:(e=>{let t,a,n=[{}];for(;t=r.exec(e.replace(l,""));)t[4]?n.shift():t[3]?(a=t[3].replace(s," ").trim(),n.unshift(n[0][a]=n[0][a]||{})):n[0][t[1]]=t[2].replace(s," ").trim();return n[0]})(e);o[d]=n(p?{["@keyframes "+d]:t}:t,a?"":"."+d)}let f=a&&o.g?o.g:null;return a&&(o.g=o[d]),((e,t,a,r)=>{r?t.data=t.data.replace(r,e):-1===t.data.indexOf(e)&&(t.data=a?e+t.data:t.data+e)})(o[d],t,i,f),d},p=(e,t,a)=>e.reduce(((e,r,l)=>{let s=t[l];if(s&&s.call){let e=s(a),t=e&&e.props&&e.props.className||/^go/.test(e)&&e;s=t?"."+t:e&&"object"==typeof e?e.props?"":n(e,""):!1===e?"":e}return e+r+(null==s?"":s)}),"");function u(e){let a=this||{},r=e.call?e(a.p):e;return i(r.unshift?r.raw?p(r,[].slice.call(arguments,1),a.p):r.reduce(((e,t)=>Object.assign(e,t&&t.call?t(a.p):t)),{}):r,t(a.target),a.g,a.o,a.k)}let d,f,g,b=u.bind({g:1}),m=u.bind({k:1});function h(e,t,a,r){n.p=t,d=e,f=a,g=r}function y(e,t){let a=this||{};return function(){let r=arguments;function l(s,n){let o=Object.assign({},s),c=o.className||l.className;a.p=Object.assign({theme:f&&f()},o),a.o=/ *go\d+/.test(c),o.className=u.apply(a,r)+(c?" "+c:""),t&&(o.ref=n);let i=e;return e[0]&&(i=o.as||e,delete o.as),g&&i[0]&&g(o),d(i,o)}return t?t(l):l}}
8
+ export default { css:u, extractCss: a, glob: b, keyframes: m, setup: h, styled: y }