@dinoreic/fez 0.3.0 → 0.4.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dinoreic/fez",
3
- "version": "0.3.0",
4
- "description": "Runtime custom dom elements",
3
+ "version": "0.4.0",
4
+ "description": "Runtime custom DOM elements lib",
5
5
  "main": "dist/fez.js",
6
6
  "type": "module",
7
7
  "exports": {
@@ -70,10 +70,7 @@ const compileToClass = (html) => {
70
70
  }
71
71
 
72
72
  if (String(result.style).includes(':')) {
73
- Object.entries(Fez._styleMacros).forEach(([key, val])=>{
74
- result.style = result.style.replaceAll(`:${key} `, `${val} `)
75
- })
76
-
73
+ result.style = Fez.cssMixin(result.style)
77
74
  result.style = result.style.includes(':fez') || /(?:^|\s)body\s*\{/.test(result.style) ? result.style : `:fez {\n${result.style}\n}`
78
75
  klass = klass.replace(/\}\s*$/, `\n CSS = \`${result.style}\`\n}`)
79
76
  }
@@ -105,8 +102,8 @@ function compile_bulk(data) {
105
102
  if (fezName && !fezName.includes('-')) {
106
103
  console.error(`Fez: Invalid custom element name "${fezName}". Custom element names must contain a dash (e.g., 'my-element', 'ui-button').`)
107
104
  }
108
- // Compile the node directly
109
- return compile(fezName, node.innerHTML)
105
+ compile(fezName, node.innerHTML)
106
+ return
110
107
  }
111
108
  }
112
109
  else {
@@ -195,7 +192,7 @@ function compile(tagName, html) {
195
192
  if (klass.includes('import ')) {
196
193
  Fez.head({script: klass})
197
194
 
198
- // best we can do it inform that node did not compile, so we assume there is arrow
195
+ // best we can do it inform that node did not compile, so we assume there is an error
199
196
  setTimeout(()=>{
200
197
  if (!Fez.classes[tagName]) {
201
198
  Fez.error(`Template "${tagName}" possible compile error. (can be a false positive, it imports are not loaded)`)
@@ -1,6 +1,26 @@
1
1
  import createTemplate from './lib/template.js'
2
2
  import FezBase from './instance.js'
3
3
 
4
+ /**
5
+ * Global mutation observer for reactive attribute changes
6
+ * Watches for attribute changes and triggers component updates
7
+ */
8
+ const observer = new MutationObserver((mutationsList, _) => {
9
+ for (const mutation of mutationsList) {
10
+ if (mutation.type === 'attributes') {
11
+ const fez = mutation.target.fez
12
+ const name = mutation.attributeName
13
+ const value = mutation.target.getAttribute(name)
14
+
15
+ if (fez) {
16
+ fez.props[name] = value
17
+ fez.onPropsChange(name, value)
18
+ // console.log(`The [${name}] attribute was modified to [${value}].`);
19
+ }
20
+ }
21
+ }
22
+ });
23
+
4
24
  /**
5
25
  * Registers a new custom element with Fez framework
6
26
  * @param {string} name - Custom element name (must contain a dash)
@@ -31,22 +51,17 @@ export default function connect(name, klass) {
31
51
  props.forEach(prop => newKlass.prototype[prop] = klassObj[prop])
32
52
 
33
53
  // Map component configuration properties
34
- if (klassObj.GLOBAL) { newKlass.fezGlobal = klassObj.GLOBAL } // Global instance reference
35
- if (klassObj.CSS) { newKlass.css = klassObj.CSS } // Component styles
54
+ if (klassObj.FAST) { newKlass.FAST = klassObj.FAST } // Global instance reference
55
+ if (klassObj.GLOBAL) { newKlass.GLOBAL = klassObj.GLOBAL } // Global instance reference
56
+ if (klassObj.CSS) { newKlass.css = klassObj.CSS } // Component styles
36
57
  if (klassObj.HTML) {
37
- newKlass.html = closeCustomTags(klassObj.HTML) // Component template
58
+ newKlass.html = closeCustomTags(klassObj.HTML) // Component template
38
59
  }
39
- if (klassObj.NAME) { newKlass.nodeName = klassObj.NAME } // Custom DOM node name
60
+ if (klassObj.NAME) { newKlass.nodeName = klassObj.NAME } // Custom DOM node name
40
61
 
41
62
  // Auto-mount global components to body
42
63
  if (klassObj.GLOBAL) {
43
- const mountGlobalComponent = () => document.body.appendChild(document.createElement(name))
44
-
45
- if (document.readyState === 'loading') {
46
- document.addEventListener('DOMContentLoaded', mountGlobalComponent);
47
- } else {
48
- mountGlobalComponent()
49
- }
64
+ document.body.appendChild(document.createElement(name))
50
65
  }
51
66
 
52
67
  klass = newKlass
@@ -59,11 +74,11 @@ export default function connect(name, klass) {
59
74
 
60
75
  // Process component template
61
76
  if (klass.html) {
62
- // Replace <slot /> with reactive slot containers
63
- klass.html = klass.html.replace(/<slot\s*\/>|<slot\s*>\s*<\/slot>/g, () => {
64
- const slotTag = klass.SLOT || 'div'
65
- return `<${slotTag} class="fez-slot" fez-keep="default-slot"></${slotTag}>`
66
- })
77
+ let slotTag = klass.SLOT || 'div'
78
+
79
+ klass.html = klass.html
80
+ .replace('<slot', `<${slotTag} class="fez-slot" fez-keep="default-slot"`)
81
+ .replace('</slot>', `</${slotTag}>`)
67
82
 
68
83
  // Compile template function
69
84
  klass.fezHtmlFunc = createTemplate(klass.html)
@@ -76,47 +91,16 @@ export default function connect(name, klass) {
76
91
 
77
92
  Fez.classes[name] = klass
78
93
 
79
- connectCustomElement(name, klass)
80
- }
81
-
82
- /**
83
- * Registers the custom element with the browser
84
- * Sets up batched rendering for optimal performance
85
- */
86
- function connectCustomElement(name, klass) {
87
- const Fez = globalThis.window?.Fez || globalThis.Fez;
88
-
89
94
  if (!customElements.get(name)) {
90
95
  customElements.define(name, class extends HTMLElement {
91
96
  connectedCallback() {
92
- // Batch all renders using microtasks for consistent timing and DOM completeness
93
- if (!Fez._pendingConnections) {
94
- Fez._pendingConnections = []
95
- Fez._batchScheduled = false
96
- }
97
-
98
- Fez._pendingConnections.push({ name, node: this })
99
-
100
- if (!Fez._batchScheduled) {
101
- Fez._batchScheduled = true
102
- Promise.resolve().then(() => {
103
- const connections = Fez._pendingConnections.slice()
104
- // console.error(`Batch processing ${connections.length} components:`, connections.map(c => c.name))
105
- Fez._pendingConnections = []
106
- Fez._batchScheduled = false
107
-
108
- // Sort by DOM order to ensure parent nodes are processed before children
109
- connections.sort((a, b) => {
110
- if (a.node.contains(b.node)) return -1
111
- if (b.node.contains(a.node)) return 1
112
- return 0
113
- })
114
-
115
- connections.forEach(({ name, node }) => {
116
- if (node.isConnected && node.parentNode) {
117
- connectNode(name, node)
118
- }
119
- })
97
+ // Fez.onReady(()=>{connectNode(name, this)})
98
+ // connectNode(name, this)
99
+ if (useFastRender(this, klass)) {
100
+ connectNode(name, this)
101
+ } else {
102
+ requestAnimationFrame(()=>{
103
+ connectNode(name, this)
120
104
  })
121
105
  }
122
106
  }
@@ -124,6 +108,16 @@ function connectCustomElement(name, klass) {
124
108
  }
125
109
  }
126
110
 
111
+ function useFastRender(node, klass) {
112
+ const fezFast = node.getAttribute('fez-fast')
113
+ var isFast = typeof klass.FAST === 'function' ? klass.FAST(node) : klass.FAST
114
+ if (fezFast == 'false') {
115
+ return false
116
+ } else {
117
+ return fezFast || isFast
118
+ }
119
+ }
120
+
127
121
  /**
128
122
  * Converts self-closing custom tags to full open/close format
129
123
  * Required for proper HTML parsing of custom elements
@@ -138,7 +132,6 @@ function closeCustomTags(html) {
138
132
  })
139
133
  }
140
134
 
141
-
142
135
  /**
143
136
  * Initializes a Fez component instance from a DOM node
144
137
  * Replaces the custom element with the component's rendered content
@@ -172,8 +165,8 @@ function connectNode(name, node) {
172
165
 
173
166
  newNode.fez = fez
174
167
 
175
- if (klass.fezGlobal && klass.fezGlobal != true) {
176
- window[klass.fezGlobal] = fez
168
+ if (klass.GLOBAL && klass.GLOBAL != true) {
169
+ window[klass.GLOBAL] = fez
177
170
  }
178
171
 
179
172
  if (window.$) {
@@ -216,23 +209,3 @@ function connectNode(name, node) {
216
209
  }
217
210
  }
218
211
  }
219
-
220
- /**
221
- * Global mutation observer for reactive attribute changes
222
- * Watches for attribute changes and triggers component updates
223
- */
224
- const observer = new MutationObserver((mutationsList, _) => {
225
- for (const mutation of mutationsList) {
226
- if (mutation.type === 'attributes') {
227
- const fez = mutation.target.fez
228
- const name = mutation.attributeName
229
- const value = mutation.target.getAttribute(name)
230
-
231
- if (fez) {
232
- fez.props[name] = value
233
- fez.onPropsChange(name, value)
234
- // console.log(`The [${name}] attribute was modified to [${value}].`);
235
- }
236
- }
237
- }
238
- });
@@ -53,6 +53,41 @@ const loadDefaults = () => {
53
53
  }
54
54
  }
55
55
  })
56
+
57
+ // Memory store for memoization
58
+ const memoStore = new Map()
59
+
60
+ // memoize component content by key
61
+ // <fez-memoize key="unique-key">content to memoize</fez-memoize>
62
+ Fez('fez-memoize', class {
63
+ init(props) {
64
+ if (!props.key) {
65
+ Fez.error('fez-memoize: key prop is required')
66
+ return
67
+ }
68
+
69
+ if (memoStore.has(props.key)) {
70
+ // Restore from memory in init
71
+ const storedNode = memoStore.get(props.key)
72
+ Fez.log(`Memoize - key: "${props.key}" - restore`)
73
+ this.root.innerHTML = ''
74
+ this.root.appendChild(storedNode.cloneNode(true))
75
+ }
76
+ }
77
+
78
+ onMount(props) {
79
+ // Only store if not already in memory
80
+ if (!memoStore.has(props.key)) {
81
+ requestAnimationFrame(() => {
82
+ // Store current DOM content
83
+ const contentNode = document.createElement('div')
84
+ contentNode.innerHTML = this.root.innerHTML
85
+ Fez.log(`Memoize - key: "${props.key}" - set`)
86
+ memoStore.set(props.key, contentNode)
87
+ })
88
+ }
89
+ }
90
+ })
56
91
  }
57
92
 
58
93
  // Only load defaults if Fez is available
@@ -61,4 +96,4 @@ if (typeof Fez !== 'undefined' && Fez) {
61
96
  }
62
97
 
63
98
  // Export for use in tests
64
- export { loadDefaults }
99
+ export { loadDefaults }
@@ -359,27 +359,20 @@ export default class FezBase {
359
359
  newNode.innerHTML = this.parseHtml(renderedTpl)
360
360
  }
361
361
 
362
- newNode.querySelectorAll('[fez-keep]').forEach(newEl => {
363
- const key = newEl.getAttribute('fez-keep')
364
- const oldEl = this.root.querySelector(`[fez-keep="${key}"]`)
362
+ // Handle fez-keep attributes
363
+ this.fezKeepNode(newNode)
365
364
 
366
- if (oldEl) {
367
- // Keep the old element in place of the new one
368
- newEl.parentNode.replaceChild(oldEl, newEl)
369
- } else if (key === 'default-slot') {
370
- // First render - populate the slot with current root children
371
- Array.from(this.root.childNodes).forEach(child => newEl.appendChild(child))
372
- }
373
- })
365
+ // Handle fez-memoize attributes
366
+ this.fezMemoization(newNode)
374
367
 
375
368
  Fez.morphdom(this.root, newNode)
376
369
 
377
- this.renderFezPostProcess()
370
+ this.fezRenderPostProcess()
378
371
 
379
372
  this.afterRender()
380
373
  }
381
374
 
382
- renderFezPostProcess() {
375
+ fezRenderPostProcess() {
383
376
  const fetchAttr = (name, func) => {
384
377
  this.root.querySelectorAll(`*[${name}]`).forEach((n)=>{
385
378
  let value = n.getAttribute(name)
@@ -397,11 +390,24 @@ export default class FezBase {
397
390
 
398
391
  // <button fez-use="animate" -> this.animate(node]
399
392
  fetchAttr('fez-use', (value, n) => {
400
- const target = this[value]
401
- if (typeof target == 'function') {
402
- target(n)
403
- } else {
404
- console.error(`Fez error: "${value}" is not a function in ${this.fezName}`)
393
+ if (value.includes('=>')) {
394
+ // fez-use="el => el.focus()"
395
+ Fez.getFunction(value)(n)
396
+ }
397
+ else {
398
+ if (value.includes('.')) {
399
+ // fez-use="this.focus()"
400
+ Fez.getFunction(value).bind(n)()
401
+ }
402
+ else {
403
+ // fez-use="animate"
404
+ const target = this[value]
405
+ if (typeof target == 'function') {
406
+ target(n)
407
+ } else {
408
+ console.error(`Fez error: "${value}" is not a function in ${this.fezName}`)
409
+ }
410
+ }
405
411
  }
406
412
  })
407
413
 
@@ -413,7 +419,7 @@ export default class FezBase {
413
419
  if (lastClass) {
414
420
  setTimeout(()=>{
415
421
  n.classList.add(lastClass)
416
- }, 300)
422
+ }, 1)
417
423
  }
418
424
  })
419
425
 
@@ -440,6 +446,63 @@ export default class FezBase {
440
446
  })
441
447
  }
442
448
 
449
+ fezKeepNode(newNode) {
450
+ newNode.querySelectorAll('[fez-keep]').forEach(newEl => {
451
+ const key = newEl.getAttribute('fez-keep')
452
+ const oldEl = this.root.querySelector(`[fez-keep="${key}"]`)
453
+
454
+ if (oldEl) {
455
+ // Keep the old element in place of the new one
456
+ newEl.parentNode.replaceChild(oldEl, newEl)
457
+ } else if (key === 'default-slot') {
458
+ if (newEl.getAttribute('hide')) {
459
+ // You cant use state any more
460
+ this.state = null
461
+
462
+ const parent = newEl.parentNode
463
+
464
+ // Insert all root children before the slot's next sibling
465
+ Array.from(this.root.childNodes).forEach(child => {
466
+ parent.insertBefore(child, newEl)
467
+ })
468
+
469
+ // Remove the slot element
470
+ newEl.remove()
471
+ }
472
+ else {
473
+ // First render - populate the slot with current root children
474
+ Array.from(this.root.childNodes).forEach(
475
+ child => {
476
+ newEl.appendChild(child)
477
+ }
478
+ )
479
+ }
480
+ }
481
+ })
482
+ }
483
+
484
+ fezMemoization(newNode) {
485
+ // Find the single memoize element in new DOM (excluding fez components)
486
+ const newMemoEl = newNode.querySelector('[fez-memoize]:not(.fez)')
487
+ if (!newMemoEl) return
488
+
489
+ this.fezMemoStore ||= new Map()
490
+
491
+ const newMemoElKey = newMemoEl.getAttribute('fez-memoize')
492
+ const storedNode = this.fezMemoStore.get(newMemoElKey)
493
+
494
+ if (storedNode) {
495
+ Fez.log(`Memoize restore ${this.fezName}: ${newMemoElKey}`)
496
+ newMemoEl.parentNode.replaceChild(storedNode.cloneNode(true), newMemoEl)
497
+ } else {
498
+ const oldMemoEl = this.root.querySelector('[fez-memoize]:not(.fez)')
499
+ if (oldMemoEl) {
500
+ const oldMemoElKey = oldMemoEl.getAttribute('fez-memoize')
501
+ this.fezMemoStore.set(oldMemoElKey, oldMemoEl.cloneNode(true))
502
+ }
503
+ }
504
+ }
505
+
443
506
  // refresh single node only
444
507
  refresh(selector) {
445
508
  alert('NEEDS FIX and remove htmlTemplate')
@@ -576,7 +639,18 @@ export default class FezBase {
576
639
  methods.forEach(method => this[method] = this[method].bind(this))
577
640
  }
578
641
 
579
- fezHide() {
642
+ // dissolve into parent, if you want to promote first child or given node with this.root
643
+ dissolve(inNode) {
644
+ if (inNode) {
645
+ inNode.classList.add('fez')
646
+ inNode.classList.add(`fez-${this.fezName}`)
647
+ inNode.fez = this
648
+ if (this.attr('id')) inNode.setAttribute('id', this.attr('id'))
649
+
650
+ this.root.innerHTML = ''
651
+ this.root.appendChild(inNode)
652
+ }
653
+
580
654
  const node = this.root
581
655
  const nodes = this.childNodes()
582
656
  const parent = this.root.parentNode
@@ -584,7 +658,12 @@ export default class FezBase {
584
658
  nodes.reverse().forEach(el => parent.insertBefore(el, node.nextSibling))
585
659
 
586
660
  this.root.remove()
587
- this.root = parent
661
+ this.root = undefined
662
+
663
+ if (inNode) {
664
+ this.root = inNode
665
+ }
666
+
588
667
  return nodes
589
668
  }
590
669
 
package/src/fez/root.js CHANGED
@@ -4,6 +4,8 @@ import Gobber from './vendor/gobber.js'
4
4
  // morph dom from one state to another
5
5
  import { Idiomorph } from './vendor/idiomorph.js'
6
6
 
7
+ import objectDump from './utils/dump.js'
8
+ import highlightAll from './utils/highlight_all.js'
7
9
  import connect from './connect.js'
8
10
  import compile from './compile.js'
9
11
  import state from './lib/global-state.js'
@@ -105,13 +107,9 @@ Fez.globalCss = (cssClass, opts = {}) => {
105
107
  cssClass = Fez.cssClass(text)
106
108
  }
107
109
 
108
- if (document.body) {
110
+ Fez.onReady(() => {
109
111
  document.body.parentElement.classList.add(cssClass)
110
- } else {
111
- document.addEventListener("DOMContentLoaded", () => {
112
- document.body.parentElement.classList.add(cssClass)
113
- })
114
- }
112
+ })
115
113
 
116
114
  return cssClass
117
115
  }
@@ -144,40 +142,6 @@ Fez.publish = (channel, ...args) => {
144
142
  })
145
143
  }
146
144
 
147
- // get unique id from string
148
- Fez.fnv1 = (str) => {
149
- var FNV_OFFSET_BASIS, FNV_PRIME, hash, i, j, ref;
150
- FNV_OFFSET_BASIS = 2166136261;
151
- FNV_PRIME = 16777619;
152
- hash = FNV_OFFSET_BASIS;
153
- for (i = j = 0, ref = str.length - 1; (0 <= ref ? j <= ref : j >= ref); i = 0 <= ref ? ++j : --j) {
154
- hash ^= str.charCodeAt(i);
155
- hash *= FNV_PRIME;
156
- }
157
- return hash.toString(36).replaceAll('-', '');
158
- }
159
-
160
- Fez.tag = (tag, opts = {}, html = '') => {
161
- const json = encodeURIComponent(JSON.stringify(opts))
162
- return `<${tag} data-props="${json}">${html}</${tag}>`
163
- // const json = JSON.stringify(opts, null, 2)
164
- // const data = `<script type="text/template">${json}</script><${tag} data-json-template="true">${html}</${tag}>`
165
- // return data
166
- };
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
-
181
145
  Fez.error = (text, show) => {
182
146
  text = `Fez: ${text}`
183
147
  console.error(text)
@@ -185,151 +149,13 @@ Fez.error = (text, show) => {
185
149
  return `<span style="border: 1px solid red; font-size: 14px; padding: 3px 7px; background: #fee; border-radius: 4px;">${text}</span>`
186
150
  }
187
151
  }
152
+
188
153
  Fez.log = (text) => {
189
154
  if (Fez.LOG === true) {
190
155
  text = String(text).substring(0, 180)
191
156
  console.log(`Fez: ${text}`)
192
157
  }
193
158
  }
194
- document.addEventListener('DOMContentLoaded', () => {
195
- Fez.log('Fez.LOG === true, logging enabled.')
196
- })
197
-
198
- // execute function until it returns true
199
- Fez.untilTrue = (func, pingRate) => {
200
- pingRate ||= 200
201
-
202
- if (!func()) {
203
- setTimeout(()=>{
204
- Fez.untilTrue(func, pingRate)
205
- } ,pingRate)
206
- }
207
- }
208
-
209
- // throttle function calls
210
- Fez.throttle = (func, delay = 200) => {
211
- let lastRun = 0;
212
- let timeout;
213
-
214
- return function(...args) {
215
- const now = Date.now();
216
-
217
- if (now - lastRun >= delay) {
218
- func.apply(this, args);
219
- lastRun = now;
220
- } else {
221
- clearTimeout(timeout);
222
- timeout = setTimeout(() => {
223
- func.apply(this, args);
224
- lastRun = Date.now();
225
- }, delay - (now - lastRun));
226
- }
227
- };
228
- }
229
-
230
- // Fetch wrapper with automatic caching and data handling
231
- // Usage:
232
- // Fez.fetch(url) - GET request (default)
233
- // Fez.fetch(url, callback) - GET with callback
234
- // Fez.fetch(url, data) - GET with query params (?foo=bar&baz=qux)
235
- // Fez.fetch(url, data, callback) - GET with query params and callback
236
- // Fez.fetch('POST', url, data) - POST with FormData body (multipart/form-data)
237
- // Fez.fetch('POST', url, data, callback) - POST with FormData and callback
238
- // Data object is automatically converted:
239
- // - GET: appended as URL query parameters
240
- // - POST: sent as FormData (multipart/form-data) without custom headers
241
- Fez.fetch = function(...args) {
242
- // Initialize cache if not exists
243
- Fez._fetchCache ||= {};
244
-
245
- let method = 'GET';
246
- let url;
247
- let callback;
248
-
249
- // Check if first arg is HTTP method (uppercase letters)
250
- if (typeof args[0] === 'string' && /^[A-Z]+$/.test(args[0])) {
251
- method = args.shift();
252
- }
253
-
254
- // URL is required
255
- url = args.shift();
256
-
257
- // Check for data/options object
258
- let opts = {};
259
- let data = null;
260
- if (typeof args[0] === 'object') {
261
- data = args.shift();
262
- }
263
-
264
- // Check for callback function
265
- if (typeof args[0] === 'function') {
266
- callback = args.shift();
267
- }
268
-
269
- // Handle data based on method
270
- if (data) {
271
- if (method === 'GET') {
272
- // For GET, append data as query parameters
273
- const params = new URLSearchParams(data);
274
- url += (url.includes('?') ? '&' : '?') + params.toString();
275
- } else if (method === 'POST') {
276
- // For POST, convert to FormData
277
- const formData = new FormData();
278
- for (const [key, value] of Object.entries(data)) {
279
- formData.append(key, value);
280
- }
281
- opts.body = formData;
282
- }
283
- }
284
-
285
- // Set method
286
- opts.method = method;
287
-
288
- // Create cache key from method, url, and stringified opts
289
- const cacheKey = `${method}:${url}:${JSON.stringify(opts)}`;
290
-
291
- // Check cache first
292
- if (Fez._fetchCache[cacheKey]) {
293
- const cachedData = Fez._fetchCache[cacheKey];
294
- Fez.log(`fetch cache hit: ${method} ${url}`);
295
- if (callback) {
296
- callback(cachedData);
297
- return;
298
- }
299
- return Promise.resolve(cachedData);
300
- }
301
-
302
- // Log live fetch
303
- Fez.log(`fetch live: ${method} ${url}`);
304
-
305
- // Helper to process and cache response
306
- const processResponse = (response) => {
307
- if (response.headers.get('content-type')?.includes('application/json')) {
308
- return response.json();
309
- }
310
- return response.text();
311
- };
312
-
313
- // If callback provided, execute and handle
314
- if (callback) {
315
- fetch(url, opts)
316
- .then(processResponse)
317
- .then(data => {
318
- Fez._fetchCache[cacheKey] = data;
319
- callback(data);
320
- })
321
- .catch(error => Fez.onError('fetch', error));
322
- return;
323
- }
324
-
325
- // Return promise with automatic JSON parsing
326
- return fetch(url, opts)
327
- .then(processResponse)
328
- .then(data => {
329
- Fez._fetchCache[cacheKey] = data;
330
- return data;
331
- });
332
- }
333
159
 
334
160
  Fez.onError = (kind, message) => {
335
161
  // Ensure kind is always a string
@@ -340,14 +166,6 @@ Fez.onError = (kind, message) => {
340
166
  console.error(`${kind}: ${message.toString()}`);
341
167
  }
342
168
 
343
- // define custom style macro
344
- // Fez.styleMacro('mobile', '@media (max-width: 768px)')
345
- // :mobile { ... } -> @media (max-width: 768px) { ... }
346
- Fez._styleMacros = {}
347
- Fez.styleMacro = (name, content) => {
348
- Fez._styleMacros[name] = content
349
- }
350
-
351
169
  // work with tmp store
352
170
  Fez.store = {
353
171
  store: new Map(),
@@ -372,9 +190,17 @@ Fez.store = {
372
190
 
373
191
  // Load utility functions
374
192
  import addUtilities from './utility.js'
193
+ import cssMixin from './utils/css_mixin.js'
375
194
  addUtilities(Fez)
195
+ cssMixin(Fez)
376
196
 
377
197
  Fez.compile = compile
378
198
  Fez.state = state
199
+ Fez.dump = objectDump
200
+ Fez.dump = highlightAll
201
+
202
+ Fez.onReady(() => {
203
+ Fez.log('Fez.LOG === true, logging enabled.')
204
+ })
379
205
 
380
206
  export default Fez