@dinoreic/fez 0.3.2 → 0.4.1

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.2",
4
- "description": "Runtime custom dom elements",
3
+ "version": "0.4.1",
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,20 @@ 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 || isFast || node.childNodes[0] || node.nextSibling) {
115
+ return true
116
+ }
117
+ else if (fezFast == 'false') {
118
+ return false
119
+ }
120
+ else {
121
+ return false
122
+ }
123
+ }
124
+
127
125
  /**
128
126
  * Converts self-closing custom tags to full open/close format
129
127
  * Required for proper HTML parsing of custom elements
@@ -138,7 +136,6 @@ function closeCustomTags(html) {
138
136
  })
139
137
  }
140
138
 
141
-
142
139
  /**
143
140
  * Initializes a Fez component instance from a DOM node
144
141
  * Replaces the custom element with the component's rendered content
@@ -172,8 +169,8 @@ function connectNode(name, node) {
172
169
 
173
170
  newNode.fez = fez
174
171
 
175
- if (klass.fezGlobal && klass.fezGlobal != true) {
176
- window[klass.fezGlobal] = fez
172
+ if (klass.GLOBAL && klass.GLOBAL != true) {
173
+ window[klass.GLOBAL] = fez
177
174
  }
178
175
 
179
176
  if (window.$) {
@@ -216,23 +213,3 @@ function connectNode(name, node) {
216
213
  }
217
214
  }
218
215
  }
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
- });
@@ -54,6 +54,17 @@ const loadDefaults = () => {
54
54
  }
55
55
  })
56
56
 
57
+ // Show node only if test validates
58
+ // <fez-if if="window.foo">...
59
+ Fez('fez-if', class {
60
+ init(props) {
61
+ const test = new Function(`return (${props.if || props.test})`)
62
+ if (!test()) {
63
+ this.root.remove()
64
+ }
65
+ }
66
+ })
67
+
57
68
  // Memory store for memoization
58
69
  const memoStore = new Map()
59
70
 
@@ -130,13 +130,11 @@ export default class FezBase {
130
130
  }
131
131
  }
132
132
 
133
- if (name == 'style' || !this.root[name]) {
134
- if (typeof value == 'string') {
135
- this.root.setAttribute(name, value)
136
- }
137
- else {
138
- this.root[name] = value
139
- }
133
+ if (typeof value == 'string') {
134
+ this.root.setAttribute(name, value)
135
+ }
136
+ else {
137
+ this.root[name] = value
140
138
  }
141
139
  }
142
140
  }
@@ -390,11 +388,24 @@ export default class FezBase {
390
388
 
391
389
  // <button fez-use="animate" -> this.animate(node]
392
390
  fetchAttr('fez-use', (value, n) => {
393
- const target = this[value]
394
- if (typeof target == 'function') {
395
- target(n)
396
- } else {
397
- console.error(`Fez error: "${value}" is not a function in ${this.fezName}`)
391
+ if (value.includes('=>')) {
392
+ // fez-use="el => el.focus()"
393
+ Fez.getFunction(value)(n)
394
+ }
395
+ else {
396
+ if (value.includes('.')) {
397
+ // fez-use="this.focus()"
398
+ Fez.getFunction(value).bind(n)()
399
+ }
400
+ else {
401
+ // fez-use="animate"
402
+ const target = this[value]
403
+ if (typeof target == 'function') {
404
+ target(n)
405
+ } else {
406
+ console.error(`Fez error: "${value}" is not a function in ${this.fezName}`)
407
+ }
408
+ }
398
409
  }
399
410
  })
400
411
 
@@ -406,7 +417,7 @@ export default class FezBase {
406
417
  if (lastClass) {
407
418
  setTimeout(()=>{
408
419
  n.classList.add(lastClass)
409
- }, 300)
420
+ }, 1)
410
421
  }
411
422
  })
412
423
 
@@ -442,8 +453,28 @@ export default class FezBase {
442
453
  // Keep the old element in place of the new one
443
454
  newEl.parentNode.replaceChild(oldEl, newEl)
444
455
  } else if (key === 'default-slot') {
445
- // First render - populate the slot with current root children
446
- Array.from(this.root.childNodes).forEach(child => newEl.appendChild(child))
456
+ if (newEl.getAttribute('hide')) {
457
+ // You cant use state any more
458
+ this.state = null
459
+
460
+ const parent = newEl.parentNode
461
+
462
+ // Insert all root children before the slot's next sibling
463
+ Array.from(this.root.childNodes).forEach(child => {
464
+ parent.insertBefore(child, newEl)
465
+ })
466
+
467
+ // Remove the slot element
468
+ newEl.remove()
469
+ }
470
+ else {
471
+ // First render - populate the slot with current root children
472
+ Array.from(this.root.childNodes).forEach(
473
+ child => {
474
+ newEl.appendChild(child)
475
+ }
476
+ )
477
+ }
447
478
  }
448
479
  })
449
480
  }
@@ -606,7 +637,18 @@ export default class FezBase {
606
637
  methods.forEach(method => this[method] = this[method].bind(this))
607
638
  }
608
639
 
609
- fezHide() {
640
+ // dissolve into parent, if you want to promote first child or given node with this.root
641
+ dissolve(inNode) {
642
+ if (inNode) {
643
+ inNode.classList.add('fez')
644
+ inNode.classList.add(`fez-${this.fezName}`)
645
+ inNode.fez = this
646
+ if (this.attr('id')) inNode.setAttribute('id', this.attr('id'))
647
+
648
+ this.root.innerHTML = ''
649
+ this.root.appendChild(inNode)
650
+ }
651
+
610
652
  const node = this.root
611
653
  const nodes = this.childNodes()
612
654
  const parent = this.root.parentNode
@@ -614,7 +656,12 @@ export default class FezBase {
614
656
  nodes.reverse().forEach(el => parent.insertBefore(el, node.nextSibling))
615
657
 
616
658
  this.root.remove()
617
- this.root = parent
659
+ this.root = undefined
660
+
661
+ if (inNode) {
662
+ this.root = inNode
663
+ }
664
+
618
665
  return nodes
619
666
  }
620
667
 
@@ -622,8 +669,10 @@ export default class FezBase {
622
669
  obj ||= {}
623
670
 
624
671
  handler ||= (o, k, v, oldValue) => {
625
- this.onStateChange(k, v, oldValue)
626
- this.nextTick(this.render, 'render')
672
+ if (v != oldValue) {
673
+ this.onStateChange(k, v, oldValue)
674
+ this.nextTick(this.render, 'render')
675
+ }
627
676
  }
628
677
 
629
678
  handler.bind(this)
package/src/fez/root.js CHANGED
@@ -5,6 +5,7 @@ import Gobber from './vendor/gobber.js'
5
5
  import { Idiomorph } from './vendor/idiomorph.js'
6
6
 
7
7
  import objectDump from './utils/dump.js'
8
+ import highlightAll from './utils/highlight_all.js'
8
9
  import connect from './connect.js'
9
10
  import compile from './compile.js'
10
11
  import state from './lib/global-state.js'
@@ -106,13 +107,9 @@ Fez.globalCss = (cssClass, opts = {}) => {
106
107
  cssClass = Fez.cssClass(text)
107
108
  }
108
109
 
109
- if (document.body) {
110
+ Fez.onReady(() => {
110
111
  document.body.parentElement.classList.add(cssClass)
111
- } else {
112
- document.addEventListener("DOMContentLoaded", () => {
113
- document.body.parentElement.classList.add(cssClass)
114
- })
115
- }
112
+ })
116
113
 
117
114
  return cssClass
118
115
  }
@@ -137,186 +134,77 @@ Fez.morphdom = (target, newNode, opts = {}) => {
137
134
  }
138
135
  }
139
136
 
137
+ Fez._globalSubs ||= new Map()
138
+
140
139
  Fez.publish = (channel, ...args) => {
141
140
  Fez._subs ||= {}
142
141
  Fez._subs[channel] ||= []
143
142
  Fez._subs[channel].forEach((el) => {
144
143
  el[1].bind(el[0])(...args)
145
144
  })
146
- }
147
145
 
148
- // get unique id from string
149
- Fez.fnv1 = (str) => {
150
- var FNV_OFFSET_BASIS, FNV_PRIME, hash, i, j, ref;
151
- FNV_OFFSET_BASIS = 2166136261;
152
- FNV_PRIME = 16777619;
153
- hash = FNV_OFFSET_BASIS;
154
- for (i = j = 0, ref = str.length - 1; (0 <= ref ? j <= ref : j >= ref); i = 0 <= ref ? ++j : --j) {
155
- hash ^= str.charCodeAt(i);
156
- hash *= FNV_PRIME;
146
+ // Trigger global subscriptions
147
+ const subs = Fez._globalSubs.get(channel)
148
+ if (subs) {
149
+ subs.forEach((sub) => {
150
+ if (sub.node.isConnected) {
151
+ sub.callback.call(sub.node, ...args)
152
+ } else {
153
+ // Remove disconnected nodes from subscriptions
154
+ subs.delete(sub)
155
+ }
156
+ })
157
157
  }
158
- return hash.toString(36).replaceAll('-', '');
159
158
  }
160
159
 
161
- Fez.tag = (tag, opts = {}, html = '') => {
162
- const json = encodeURIComponent(JSON.stringify(opts))
163
- return `<${tag} data-props="${json}">${html}</${tag}>`
164
- // const json = JSON.stringify(opts, null, 2)
165
- // const data = `<script type="text/template">${json}</script><${tag} data-json-template="true">${html}</${tag}>`
166
- // return data
167
- };
168
-
169
- Fez.error = (text, show) => {
170
- text = `Fez: ${text}`
171
- console.error(text)
172
- if (show) {
173
- return `<span style="border: 1px solid red; font-size: 14px; padding: 3px 7px; background: #fee; border-radius: 4px;">${text}</span>`
160
+ Fez.subscribe = (node, eventName, callback) => {
161
+ // If second arg is function, shift arguments
162
+ if (typeof eventName === 'function') {
163
+ callback = eventName
164
+ eventName = node
165
+ node = document.body
174
166
  }
175
- }
176
- Fez.log = (text) => {
177
- if (Fez.LOG === true) {
178
- text = String(text).substring(0, 180)
179
- console.log(`Fez: ${text}`)
180
- }
181
- }
182
- document.addEventListener('DOMContentLoaded', () => {
183
- Fez.log('Fez.LOG === true, logging enabled.')
184
- })
185
-
186
- // execute function until it returns true
187
- Fez.untilTrue = (func, pingRate) => {
188
- pingRate ||= 200
189
167
 
190
- if (!func()) {
191
- setTimeout(()=>{
192
- Fez.untilTrue(func, pingRate)
193
- } ,pingRate)
168
+ // Handle string selectors
169
+ if (typeof node === 'string') {
170
+ node = document.querySelector(node)
194
171
  }
195
- }
196
-
197
- // throttle function calls
198
- Fez.throttle = (func, delay = 200) => {
199
- let lastRun = 0;
200
- let timeout;
201
172
 
202
- return function(...args) {
203
- const now = Date.now();
204
-
205
- if (now - lastRun >= delay) {
206
- func.apply(this, args);
207
- lastRun = now;
208
- } else {
209
- clearTimeout(timeout);
210
- timeout = setTimeout(() => {
211
- func.apply(this, args);
212
- lastRun = Date.now();
213
- }, delay - (now - lastRun));
214
- }
215
- };
216
- }
217
-
218
- // Fetch wrapper with automatic caching and data handling
219
- // Usage:
220
- // Fez.fetch(url) - GET request (default)
221
- // Fez.fetch(url, callback) - GET with callback
222
- // Fez.fetch(url, data) - GET with query params (?foo=bar&baz=qux)
223
- // Fez.fetch(url, data, callback) - GET with query params and callback
224
- // Fez.fetch('POST', url, data) - POST with FormData body (multipart/form-data)
225
- // Fez.fetch('POST', url, data, callback) - POST with FormData and callback
226
- // Data object is automatically converted:
227
- // - GET: appended as URL query parameters
228
- // - POST: sent as FormData (multipart/form-data) without custom headers
229
- Fez.fetch = function(...args) {
230
- // Initialize cache if not exists
231
- Fez._fetchCache ||= {};
232
-
233
- let method = 'GET';
234
- let url;
235
- let callback;
236
-
237
- // Check if first arg is HTTP method (uppercase letters)
238
- if (typeof args[0] === 'string' && /^[A-Z]+$/.test(args[0])) {
239
- method = args.shift();
240
- }
241
-
242
- // URL is required
243
- url = args.shift();
244
-
245
- // Check for data/options object
246
- let opts = {};
247
- let data = null;
248
- if (typeof args[0] === 'object') {
249
- data = args.shift();
173
+ if (!Fez._globalSubs.has(eventName)) {
174
+ Fez._globalSubs.set(eventName, new Set())
250
175
  }
251
176
 
252
- // Check for callback function
253
- if (typeof args[0] === 'function') {
254
- callback = args.shift();
255
- }
177
+ const subs = Fez._globalSubs.get(eventName)
256
178
 
257
- // Handle data based on method
258
- if (data) {
259
- if (method === 'GET') {
260
- // For GET, append data as query parameters
261
- const params = new URLSearchParams(data);
262
- url += (url.includes('?') ? '&' : '?') + params.toString();
263
- } else if (method === 'POST') {
264
- // For POST, convert to FormData
265
- const formData = new FormData();
266
- for (const [key, value] of Object.entries(data)) {
267
- formData.append(key, value);
268
- }
269
- opts.body = formData;
179
+ // Remove existing subscription for same node and callback
180
+ subs.forEach(sub => {
181
+ if (sub.node === node && sub.callback === callback) {
182
+ subs.delete(sub)
270
183
  }
271
- }
272
-
273
- // Set method
274
- opts.method = method;
184
+ })
275
185
 
276
- // Create cache key from method, url, and stringified opts
277
- const cacheKey = `${method}:${url}:${JSON.stringify(opts)}`;
186
+ const subscription = { node, callback }
187
+ subs.add(subscription)
278
188
 
279
- // Check cache first
280
- if (Fez._fetchCache[cacheKey]) {
281
- const cachedData = Fez._fetchCache[cacheKey];
282
- Fez.log(`fetch cache hit: ${method} ${url}`);
283
- if (callback) {
284
- callback(cachedData);
285
- return;
286
- }
287
- return Promise.resolve(cachedData);
189
+ // Return unsubscribe function
190
+ return () => {
191
+ subs.delete(subscription)
288
192
  }
193
+ }
289
194
 
290
- // Log live fetch
291
- Fez.log(`fetch live: ${method} ${url}`);
292
-
293
- // Helper to process and cache response
294
- const processResponse = (response) => {
295
- if (response.headers.get('content-type')?.includes('application/json')) {
296
- return response.json();
297
- }
298
- return response.text();
299
- };
300
-
301
- // If callback provided, execute and handle
302
- if (callback) {
303
- fetch(url, opts)
304
- .then(processResponse)
305
- .then(data => {
306
- Fez._fetchCache[cacheKey] = data;
307
- callback(data);
308
- })
309
- .catch(error => Fez.onError('fetch', error));
310
- return;
195
+ Fez.error = (text, show) => {
196
+ text = `Fez: ${text}`
197
+ console.error(text)
198
+ if (show) {
199
+ return `<span style="border: 1px solid red; font-size: 14px; padding: 3px 7px; background: #fee; border-radius: 4px;">${text}</span>`
311
200
  }
201
+ }
312
202
 
313
- // Return promise with automatic JSON parsing
314
- return fetch(url, opts)
315
- .then(processResponse)
316
- .then(data => {
317
- Fez._fetchCache[cacheKey] = data;
318
- return data;
319
- });
203
+ Fez.log = (text) => {
204
+ if (Fez.LOG === true) {
205
+ text = String(text).substring(0, 180)
206
+ console.log(`Fez: ${text}`)
207
+ }
320
208
  }
321
209
 
322
210
  Fez.onError = (kind, message) => {
@@ -328,14 +216,6 @@ Fez.onError = (kind, message) => {
328
216
  console.error(`${kind}: ${message.toString()}`);
329
217
  }
330
218
 
331
- // define custom style macro
332
- // Fez.styleMacro('mobile', '@media (max-width: 768px)')
333
- // :mobile { ... } -> @media (max-width: 768px) { ... }
334
- Fez._styleMacros = {}
335
- Fez.styleMacro = (name, content) => {
336
- Fez._styleMacros[name] = content
337
- }
338
-
339
219
  // work with tmp store
340
220
  Fez.store = {
341
221
  store: new Map(),
@@ -360,10 +240,17 @@ Fez.store = {
360
240
 
361
241
  // Load utility functions
362
242
  import addUtilities from './utility.js'
243
+ import cssMixin from './utils/css_mixin.js'
363
244
  addUtilities(Fez)
245
+ cssMixin(Fez)
364
246
 
365
247
  Fez.compile = compile
366
248
  Fez.state = state
367
249
  Fez.dump = objectDump
250
+ Fez.highlightAll = highlightAll
251
+
252
+ Fez.onReady(() => {
253
+ Fez.log('Fez.LOG === true, logging enabled.')
254
+ })
368
255
 
369
256
  export default Fez