bitwrench 2.0.16 → 2.0.17

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.
Files changed (42) hide show
  1. package/dist/bitwrench-bccl.cjs.js +6 -2
  2. package/dist/bitwrench-bccl.cjs.min.js +3 -3
  3. package/dist/bitwrench-bccl.esm.js +6 -2
  4. package/dist/bitwrench-bccl.esm.min.js +3 -3
  5. package/dist/bitwrench-bccl.umd.js +6 -2
  6. package/dist/bitwrench-bccl.umd.min.js +2 -2
  7. package/dist/bitwrench-code-edit.cjs.js +1 -1
  8. package/dist/bitwrench-code-edit.cjs.min.js +1 -1
  9. package/dist/bitwrench-code-edit.es5.js +1 -1
  10. package/dist/bitwrench-code-edit.es5.min.js +1 -1
  11. package/dist/bitwrench-code-edit.esm.js +1 -1
  12. package/dist/bitwrench-code-edit.esm.min.js +1 -1
  13. package/dist/bitwrench-code-edit.umd.js +1 -1
  14. package/dist/bitwrench-code-edit.umd.min.js +1 -1
  15. package/dist/bitwrench-lean.cjs.js +506 -154
  16. package/dist/bitwrench-lean.cjs.min.js +7 -7
  17. package/dist/bitwrench-lean.es5.js +517 -155
  18. package/dist/bitwrench-lean.es5.min.js +5 -5
  19. package/dist/bitwrench-lean.esm.js +505 -154
  20. package/dist/bitwrench-lean.esm.min.js +6 -6
  21. package/dist/bitwrench-lean.umd.js +506 -154
  22. package/dist/bitwrench-lean.umd.min.js +7 -7
  23. package/dist/bitwrench.cjs.js +511 -155
  24. package/dist/bitwrench.cjs.min.js +8 -8
  25. package/dist/bitwrench.es5.js +525 -156
  26. package/dist/bitwrench.es5.min.js +6 -6
  27. package/dist/bitwrench.esm.js +510 -155
  28. package/dist/bitwrench.esm.min.js +8 -8
  29. package/dist/bitwrench.umd.js +511 -155
  30. package/dist/bitwrench.umd.min.js +8 -8
  31. package/dist/builds.json +82 -82
  32. package/dist/bwserve.cjs.js +16 -2
  33. package/dist/bwserve.esm.js +16 -2
  34. package/dist/sri.json +34 -34
  35. package/package.json +4 -2
  36. package/readme.html +1 -1
  37. package/src/bitwrench-bccl.js +5 -1
  38. package/src/bitwrench.js +502 -151
  39. package/src/bwserve/index.js +12 -1
  40. package/src/bwserve/shell.js +3 -0
  41. package/src/cli/layout-default.js +47 -32
  42. package/src/version.js +3 -3
@@ -1,10 +1,11 @@
1
- /*! bitwrench-lean v2.0.16 | BSD-2-Clause | https://deftio.github.com/bitwrench/pages */
1
+ /*! bitwrench-lean v2.0.17 | BSD-2-Clause | https://deftio.github.com/bitwrench/pages */
2
2
  (function (global, factory) {
3
3
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
4
4
  typeof define === 'function' && define.amd ? define(factory) :
5
5
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.bw = factory());
6
6
  })(this, (function () { 'use strict';
7
7
 
8
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
8
9
  function _arrayLikeToArray(r, a) {
9
10
  (null == a || a > r.length) && (a = r.length);
10
11
  for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
@@ -189,14 +190,14 @@
189
190
  */
190
191
 
191
192
  var VERSION_INFO = {
192
- version: '2.0.16',
193
+ version: '2.0.17',
193
194
  name: 'bitwrench',
194
195
  description: 'A library for javascript UI functions.',
195
196
  license: 'BSD-2-Clause',
196
197
  homepage: 'https://deftio.github.com/bitwrench/pages',
197
198
  repository: 'git+https://github.com/deftio/bitwrench.git',
198
199
  author: 'manu a. chatterjee <deftio@deftio.com> (https://deftio.com/)',
199
- buildDate: '2026-03-12T08:05:52.043Z'
200
+ buildDate: '2026-03-13T23:15:10.823Z'
200
201
  };
201
202
 
202
203
  /**
@@ -5125,7 +5126,7 @@
5125
5126
  __monkey_patch_is_nodejs__: {
5126
5127
  _value: 'ignore',
5127
5128
  set: function set(x) {
5128
- this._value = typeof x === 'boolean' ? x : 'ignore';
5129
+ this._value = _is(x, 'boolean') ? x : 'ignore';
5129
5130
  },
5130
5131
  get: function get() {
5131
5132
  return this._value;
@@ -5173,6 +5174,76 @@
5173
5174
  configurable: true
5174
5175
  });
5175
5176
 
5177
+ // ── Internal aliases ─────────────────────────────────────────────────────
5178
+ // Short names for frequently-used builtins and internal methods.
5179
+ // Same pattern as v1 (_to = bw.typeOf, etc.).
5180
+ //
5181
+ // Why: Terser can't shorten global property chains (console.warn,
5182
+ // Object.prototype.hasOwnProperty, Array.isArray, document.createElement)
5183
+ // because it can't prove they're side-effect-free. We can, so we alias
5184
+ // them here. Each alias saves bytes in the minified output, and the short
5185
+ // names also reduce visual noise in the hot paths (binding pipeline,
5186
+ // createDOM, etc.).
5187
+ //
5188
+ // Alias Target Sites
5189
+ // ───────── ────────────────────────────────────── ─────
5190
+ // _hop Object.prototype.hasOwnProperty 15
5191
+ // _isA Array.isArray 25
5192
+ // _keys Object.keys 7
5193
+ // _to bw.typeOf (type string) 26
5194
+ // _is type check boolean: _is(x,'string') ~50
5195
+ // _cw console.warn 8
5196
+ // _cl console.log 11
5197
+ // _ce console.error 4
5198
+ // _chp ComponentHandle.prototype 28 (defined after constructor)
5199
+ //
5200
+ // Note: document.createElement etc. are NOT aliased because they require
5201
+ // `this === document` and .bind() would add overhead on every call.
5202
+ // Console aliases use thin wrappers (not direct refs) so test monkey-
5203
+ // patching of console.warn/log/error continues to work.
5204
+ //
5205
+ // `typeof x` for UNDECLARED globals (window, document, process, require,
5206
+ // EventSource, navigator, Promise, __filename, import.meta) MUST stay as
5207
+ // raw `typeof` — calling _to(x) when x doesn't exist throws ReferenceError.
5208
+ //
5209
+ // ── v1 functional type helpers (kept for reference, not currently used) ──
5210
+ // _toa(x, type, trueVal, falseVal) — bw.typeAssign:
5211
+ // returns trueVal if _to(x)===type, else falseVal.
5212
+ // Replaces: (typeof x === 'string') ? A : B → _toa(x,'string',A,B)
5213
+ // _toc(x, type, trueVal, falseVal) — bw.typeConvert:
5214
+ // same as _toa but if trueVal/falseVal are functions, calls them with x.
5215
+ // Replaces: typeof x === 'string' ? fn(x) : default → _toc(x,'string',fn,default)
5216
+ // Uncomment if pattern frequency justifies them:
5217
+ // var _toa = function(x, t, y, n) { return _to(x) === t ? y : n; };
5218
+ // var _toc = function(x, t, y, n) { var r = _to(x)===t; return r ? (_to(y)==='function'?y(x):y) : (_to(n)==='function'?n(x):n); };
5219
+ // ─────────────────────────────────────────────────────────────────────────
5220
+ var _hop = Object.prototype.hasOwnProperty;
5221
+ var _isA = Array.isArray;
5222
+ var _keys = Object.keys;
5223
+ var _to = typeOf; // imported from bitwrench-utils.js
5224
+ var _is = function _is(x, t) {
5225
+ var r = _to(x);
5226
+ return r === t || r.toLowerCase() === t;
5227
+ };
5228
+ // Console aliases use thin wrappers (not direct references) so that test
5229
+ // code can monkey-patch console.warn/log/error and the patches take effect.
5230
+ var _cw = function _cw() {
5231
+ console.warn.apply(console, arguments);
5232
+ };
5233
+ var _cl = function _cl() {
5234
+ console.log.apply(console, arguments);
5235
+ };
5236
+ var _ce = function _ce() {
5237
+ console.error.apply(console, arguments);
5238
+ };
5239
+
5240
+ /**
5241
+ * Debug flag. When true, emits console.warn for silent binding failures
5242
+ * (missing paths, null refs, auto-created intermediate objects).
5243
+ * @type {boolean}
5244
+ */
5245
+ bw.debug = false;
5246
+
5176
5247
  /**
5177
5248
  * Lazy-resolve Node.js `fs` module.
5178
5249
  * Tries require('fs') first (available in CJS/UMD Node.js builds),
@@ -5322,7 +5393,7 @@
5322
5393
  */
5323
5394
  bw._el = function (id) {
5324
5395
  // Pass-through for DOM elements
5325
- if (typeof id !== 'string') return id || null;
5396
+ if (!_is(id, 'string')) return id || null;
5326
5397
  if (!id) return null;
5327
5398
  if (!bw._isBrowser) return null;
5328
5399
 
@@ -5417,7 +5488,7 @@
5417
5488
  * // => '&lt;b&gt;Hello&lt;&#x2F;b&gt; &amp; &quot;world&quot;'
5418
5489
  */
5419
5490
  bw.escapeHTML = function (str) {
5420
- if (typeof str !== 'string') return '';
5491
+ if (!_is(str, 'string')) return '';
5421
5492
  var escapeMap = {
5422
5493
  '&': '&amp;',
5423
5494
  '<': '&lt;',
@@ -5494,7 +5565,7 @@
5494
5565
  }
5495
5566
 
5496
5567
  // Handle arrays of TACOs
5497
- if (Array.isArray(taco)) {
5568
+ if (_isA(taco)) {
5498
5569
  return taco.map(function (t) {
5499
5570
  return bw.html(t, options);
5500
5571
  }).join('');
@@ -5517,17 +5588,17 @@
5517
5588
  if (taco && taco._bwEach && options.state) {
5518
5589
  var eachExpr = taco.expr.replace(/^\$\{|\}$/g, '');
5519
5590
  var arr = bw._evaluatePath(options.state, eachExpr);
5520
- if (!Array.isArray(arr)) return '';
5591
+ if (!_isA(arr)) return '';
5521
5592
  return arr.map(function (item, idx) {
5522
5593
  return bw.html(taco.factory(item, idx), options);
5523
5594
  }).join('');
5524
5595
  }
5525
5596
 
5526
5597
  // Handle primitives and non-TACO objects
5527
- if (_typeof(taco) !== 'object' || !taco.t) {
5598
+ if (!_is(taco, 'object') || !taco.t) {
5528
5599
  var str = options.raw ? String(taco) : bw.escapeHTML(String(taco));
5529
5600
  // Resolve template bindings if state provided
5530
- if (options.state && typeof str === 'string' && str.indexOf('${') >= 0) {
5601
+ if (options.state && _is(str, 'string') && str.indexOf('${') >= 0) {
5531
5602
  str = bw._resolveTemplate(str, options.state, !!options.compile);
5532
5603
  }
5533
5604
  return str;
@@ -5552,9 +5623,17 @@
5552
5623
  // Skip null, undefined, false
5553
5624
  if (value == null || value === false) continue;
5554
5625
 
5555
- // Skip event handlers (they're for DOM only)
5556
- if (key.startsWith('on')) continue;
5557
- if (key === 'style' && _typeof(value) === 'object') {
5626
+ // Serialize event handlers via funcRegister
5627
+ if (key.startsWith('on')) {
5628
+ if (_is(value, 'function')) {
5629
+ var fnId = bw.funcRegister(value);
5630
+ attrStr += ' ' + key + '="' + bw.funcGetDispatchStr(fnId, 'event') + '"';
5631
+ } else if (_is(value, 'string')) {
5632
+ attrStr += ' ' + key + '="' + bw.escapeHTML(value) + '"';
5633
+ }
5634
+ continue;
5635
+ }
5636
+ if (key === 'style' && _is(value, 'object')) {
5558
5637
  // Convert style object to string
5559
5638
  var styleStr = Object.entries(value).filter(function (_ref) {
5560
5639
  var _ref2 = _slicedToArray(_ref, 2),
@@ -5571,7 +5650,7 @@
5571
5650
  }
5572
5651
  } else if (key === 'class') {
5573
5652
  // Handle class as array or string
5574
- var classStr = Array.isArray(value) ? value.filter(Boolean).join(' ') : String(value);
5653
+ var classStr = _isA(value) ? value.filter(Boolean).join(' ') : String(value);
5575
5654
  if (classStr) {
5576
5655
  attrStr += " class=\"".concat(bw.escapeHTML(classStr), "\"");
5577
5656
  }
@@ -5607,12 +5686,184 @@
5607
5686
  // Process content recursively
5608
5687
  var contentStr = content != null ? bw.html(content, options) : '';
5609
5688
  // Resolve template bindings in content if state provided
5610
- if (options.state && typeof contentStr === 'string' && contentStr.indexOf('${') >= 0) {
5689
+ if (options.state && _is(contentStr, 'string') && contentStr.indexOf('${') >= 0) {
5611
5690
  contentStr = bw._resolveTemplate(contentStr, options.state, !!options.compile);
5612
5691
  }
5613
5692
  return "<".concat(tag).concat(attrStr, ">").concat(contentStr, "</").concat(tag, ">");
5614
5693
  };
5615
5694
 
5695
+ /**
5696
+ * Generate a complete, self-contained HTML document from TACO content.
5697
+ *
5698
+ * Produces a full `<!DOCTYPE html>` page with configurable runtime injection,
5699
+ * func registry emission (so serialized event handlers work), optional theme,
5700
+ * and extra head elements. Designed for static site generation, offline/airgapped
5701
+ * use, and the "static site that isn't static" workflow.
5702
+ *
5703
+ * @param {Object} [opts={}] - Page options
5704
+ * @param {Object|string|Array} [opts.body=''] - Body content: TACO, string, or array
5705
+ * @param {string} [opts.title='bitwrench'] - Page title
5706
+ * @param {Object} [opts.state] - State for ${expr} resolution in bw.html()
5707
+ * @param {string} [opts.runtime='shim'] - Runtime level: 'inline'|'cdn'|'shim'|'none'
5708
+ * @param {string} [opts.css=''] - Additional CSS for <style> block
5709
+ * @param {string|Object} [opts.theme=null] - Theme preset name or config object
5710
+ * @param {Array} [opts.head=[]] - Extra TACO elements rendered into <head>
5711
+ * @param {string} [opts.favicon=''] - Favicon URL
5712
+ * @param {string} [opts.lang='en'] - HTML lang attribute
5713
+ * @returns {string} Complete HTML document string
5714
+ * @category DOM Generation
5715
+ * @see bw.html
5716
+ * @example
5717
+ * bw.htmlPage({
5718
+ * title: 'My App',
5719
+ * body: { t: 'h1', c: 'Hello World' },
5720
+ * runtime: 'shim'
5721
+ * })
5722
+ */
5723
+ bw.htmlPage = function (opts) {
5724
+ opts = opts || {};
5725
+ var title = opts.title || 'bitwrench';
5726
+ var body = opts.body || '';
5727
+ var state = opts.state || undefined;
5728
+ var runtime = opts.runtime || 'shim';
5729
+ var css = opts.css || '';
5730
+ var theme = opts.theme || null;
5731
+ var headExtra = opts.head || [];
5732
+ var favicon = opts.favicon || '';
5733
+ var lang = opts.lang || 'en';
5734
+
5735
+ // Snapshot funcRegistry counter before rendering
5736
+ var fnCounterBefore = bw._fnIDCounter;
5737
+
5738
+ // Render body content
5739
+ var bodyHTML = '';
5740
+ if (_is(body, 'string')) {
5741
+ bodyHTML = body;
5742
+ } else {
5743
+ var htmlOpts = {};
5744
+ if (state) htmlOpts.state = state;
5745
+ bodyHTML = bw.html(body, htmlOpts);
5746
+ }
5747
+
5748
+ // Collect functions registered during this render
5749
+ var fnCounterAfter = bw._fnIDCounter;
5750
+ var registryEntries = '';
5751
+ for (var i = fnCounterBefore; i < fnCounterAfter; i++) {
5752
+ var fnKey = 'bw_fn_' + i;
5753
+ if (bw._fnRegistry[fnKey]) {
5754
+ registryEntries += 'bw._fnRegistry[\'' + fnKey + '\']=' + bw._fnRegistry[fnKey].toString() + ';\n';
5755
+ }
5756
+ }
5757
+
5758
+ // Build runtime script for <head>
5759
+ var runtimeHead = '';
5760
+ if (runtime === 'inline') {
5761
+ // Read UMD bundle synchronously if in Node.js
5762
+ var umdSource = null;
5763
+ if (bw._isNode) {
5764
+ try {
5765
+ var fs = typeof require === 'function' ? require('fs') : null;
5766
+ var pathMod = typeof require === 'function' ? require('path') : null;
5767
+ if (fs && pathMod) {
5768
+ // Resolve dist/ relative to this source file
5769
+ var srcDir = '';
5770
+ try {
5771
+ srcDir = pathMod.dirname(typeof __filename !== 'undefined' ? __filename : '');
5772
+ } catch (e2) {/* ESM: __filename not available */}
5773
+ if (!srcDir && typeof ({ url: (typeof document === 'undefined' && typeof location === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : typeof document === 'undefined' ? location.href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('bitwrench-lean.es5.js', document.baseURI).href)) }) !== 'undefined' && (typeof document === 'undefined' && typeof location === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : typeof document === 'undefined' ? location.href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('bitwrench-lean.es5.js', document.baseURI).href))) {
5774
+ var url = typeof require === 'function' ? require('url') : null;
5775
+ if (url && url.fileURLToPath) srcDir = pathMod.dirname(url.fileURLToPath((typeof document === 'undefined' && typeof location === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : typeof document === 'undefined' ? location.href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('bitwrench-lean.es5.js', document.baseURI).href))));
5776
+ }
5777
+ if (srcDir) {
5778
+ var distPath = pathMod.resolve(srcDir, '../dist/bitwrench.umd.min.js');
5779
+ umdSource = fs.readFileSync(distPath, 'utf8');
5780
+ }
5781
+ }
5782
+ } catch (e) {/* fall through */}
5783
+ }
5784
+ if (umdSource) {
5785
+ runtimeHead = '<script>' + umdSource + '</script>';
5786
+ } else {
5787
+ // Fallback to shim in browser or if dist not available
5788
+ runtimeHead = '<script>' + bw._FUNC_REGISTRY_SHIM + '</script>';
5789
+ }
5790
+ } else if (runtime === 'cdn') {
5791
+ runtimeHead = '<script src="https://cdn.jsdelivr.net/npm/bitwrench@2/dist/bitwrench.umd.min.js"></script>';
5792
+ } else if (runtime === 'shim') {
5793
+ runtimeHead = '<script>' + bw._FUNC_REGISTRY_SHIM + '</script>';
5794
+ }
5795
+ // runtime === 'none' → empty
5796
+
5797
+ // Theme CSS
5798
+ var themeCSS = '';
5799
+ if (theme) {
5800
+ var themeConfig = _is(theme, 'string') ? THEME_PRESETS[theme.toLowerCase()] || null : theme;
5801
+ if (themeConfig) {
5802
+ var themeResult = bw.generateTheme('', Object.assign({}, themeConfig, {
5803
+ inject: false
5804
+ }));
5805
+ themeCSS = themeResult.css;
5806
+ }
5807
+ }
5808
+
5809
+ // Extra <head> elements
5810
+ var headHTML = '';
5811
+ if (_isA(headExtra) && headExtra.length > 0) {
5812
+ headHTML = headExtra.map(function (el) {
5813
+ return bw.html(el);
5814
+ }).join('\n');
5815
+ }
5816
+
5817
+ // Favicon
5818
+ var faviconTag = '';
5819
+ if (favicon) {
5820
+ var safeFavicon = favicon.replace(/[&<>"']/g, function (c) {
5821
+ return {
5822
+ '&': '&amp;',
5823
+ '<': '&lt;',
5824
+ '>': '&gt;',
5825
+ '"': '&quot;',
5826
+ "'": '&#39;'
5827
+ }[c];
5828
+ });
5829
+ faviconTag = '<link rel="icon" href="' + safeFavicon + '">';
5830
+ }
5831
+
5832
+ // Escaped title
5833
+ var safeTitle = bw.escapeHTML(title);
5834
+
5835
+ // Combine all CSS
5836
+ var allCSS = (themeCSS ? themeCSS + '\n' : '') + css;
5837
+
5838
+ // Body-end script: registry entries + optional loadDefaultStyles
5839
+ var bodyEndScript = '';
5840
+ var bodyEndParts = [];
5841
+ if (registryEntries) {
5842
+ bodyEndParts.push(registryEntries);
5843
+ }
5844
+ if (runtime === 'inline' || runtime === 'cdn') {
5845
+ bodyEndParts.push('if(typeof bw!=="undefined"){bw.loadDefaultStyles();}');
5846
+ }
5847
+ if (bodyEndParts.length > 0) {
5848
+ bodyEndScript = '<script>\n' + bodyEndParts.join('\n') + '\n</script>';
5849
+ }
5850
+
5851
+ // Assemble document
5852
+ var parts = ['<!DOCTYPE html>', '<html lang="' + lang + '">', '<head>', '<meta charset="UTF-8">', '<meta name="viewport" content="width=device-width, initial-scale=1">'];
5853
+ parts.push('<title>' + safeTitle + '</title>');
5854
+ if (faviconTag) parts.push(faviconTag);
5855
+ if (runtimeHead) parts.push(runtimeHead);
5856
+ if (headHTML) parts.push(headHTML);
5857
+ if (allCSS) parts.push('<style>' + allCSS + '</style>');
5858
+ parts.push('</head>');
5859
+ parts.push('<body>');
5860
+ parts.push(bodyHTML);
5861
+ if (bodyEndScript) parts.push(bodyEndScript);
5862
+ parts.push('</body>');
5863
+ parts.push('</html>');
5864
+ return parts.join('\n');
5865
+ };
5866
+
5616
5867
  /**
5617
5868
  * Create a live DOM element from a TACO object (browser only).
5618
5869
  *
@@ -5658,7 +5909,7 @@
5658
5909
  }
5659
5910
 
5660
5911
  // Handle text nodes
5661
- if (_typeof(taco) !== 'object' || !taco.t) {
5912
+ if (!_is(taco, 'object') || !taco.t) {
5662
5913
  return document.createTextNode(String(taco));
5663
5914
  }
5664
5915
  var tag = taco.t,
@@ -5677,16 +5928,16 @@
5677
5928
  key = _Object$entries2$_i[0],
5678
5929
  value = _Object$entries2$_i[1];
5679
5930
  if (value == null || value === false) continue;
5680
- if (key === 'style' && _typeof(value) === 'object') {
5931
+ if (key === 'style' && _is(value, 'object')) {
5681
5932
  // Apply styles directly
5682
5933
  Object.assign(el.style, value);
5683
5934
  } else if (key === 'class') {
5684
5935
  // Handle class as array or string
5685
- var classStr = Array.isArray(value) ? value.filter(Boolean).join(' ') : String(value);
5936
+ var classStr = _isA(value) ? value.filter(Boolean).join(' ') : String(value);
5686
5937
  if (classStr) {
5687
5938
  el.className = classStr;
5688
5939
  }
5689
- } else if (key.startsWith('on') && typeof value === 'function') {
5940
+ } else if (key.startsWith('on') && _is(value, 'function')) {
5690
5941
  // Event handlers
5691
5942
  var eventName = key.slice(2).toLowerCase();
5692
5943
  el.addEventListener(eventName, value);
@@ -5706,7 +5957,7 @@
5706
5957
  // Children with data-bw_id or id attributes get local refs on the parent,
5707
5958
  // so o.render functions can access them without any DOM lookup.
5708
5959
  if (content != null) {
5709
- if (Array.isArray(content)) {
5960
+ if (_isA(content)) {
5710
5961
  content.forEach(function (child) {
5711
5962
  if (child != null) {
5712
5963
  // Handle ComponentHandle in content arrays (Level 2 children)
@@ -5726,20 +5977,20 @@
5726
5977
  if (childEl._bw_refs) {
5727
5978
  if (!el._bw_refs) el._bw_refs = {};
5728
5979
  for (var rk in childEl._bw_refs) {
5729
- if (Object.prototype.hasOwnProperty.call(childEl._bw_refs, rk)) {
5980
+ if (_hop.call(childEl._bw_refs, rk)) {
5730
5981
  el._bw_refs[rk] = childEl._bw_refs[rk];
5731
5982
  }
5732
5983
  }
5733
5984
  }
5734
5985
  }
5735
5986
  });
5736
- } else if (_typeof(content) === 'object' && content.__bw_raw) {
5987
+ } else if (_is(content, 'object') && content.__bw_raw) {
5737
5988
  // Raw HTML content — inject via innerHTML
5738
5989
  el.innerHTML = content.v;
5739
5990
  } else if (content._bwComponent === true) {
5740
5991
  // Single ComponentHandle as content
5741
5992
  content.mount(el);
5742
- } else if (_typeof(content) === 'object' && content.t) {
5993
+ } else if (_is(content, 'object') && content.t) {
5743
5994
  var childEl = bw.createDOM(content, options);
5744
5995
  el.appendChild(childEl);
5745
5996
  var childBwId = content.a ? content.a['data-bw_id'] || content.a.id : null;
@@ -5750,7 +6001,7 @@
5750
6001
  if (childEl._bw_refs) {
5751
6002
  if (!el._bw_refs) el._bw_refs = {};
5752
6003
  for (var rk in childEl._bw_refs) {
5753
- if (Object.prototype.hasOwnProperty.call(childEl._bw_refs, rk)) {
6004
+ if (_hop.call(childEl._bw_refs, rk)) {
5754
6005
  el._bw_refs[rk] = childEl._bw_refs[rk];
5755
6006
  }
5756
6007
  }
@@ -5782,7 +6033,7 @@
5782
6033
  if (opts.render) {
5783
6034
  el._bw_render = opts.render;
5784
6035
  if (opts.mounted) {
5785
- console.warn('bw.createDOM: o.render and o.mounted are mutually exclusive. o.render wins.');
6036
+ _cw('bw.createDOM: o.render and o.mounted are mutually exclusive. o.render wins.');
5786
6037
  }
5787
6038
 
5788
6039
  // Queue initial render (same timing as mounted)
@@ -5854,7 +6105,7 @@
5854
6105
  // Get target element (use cache-backed lookup)
5855
6106
  var targetEl = bw._el(target);
5856
6107
  if (!targetEl) {
5857
- console.error('bw.DOM: Target element not found:', target);
6108
+ _ce('bw.DOM: Target element not found:', target);
5858
6109
  return null;
5859
6110
  }
5860
6111
 
@@ -5892,7 +6143,7 @@
5892
6143
  targetEl.appendChild(taco.element);
5893
6144
  }
5894
6145
  // Handle arrays
5895
- else if (Array.isArray(taco)) {
6146
+ else if (_isA(taco)) {
5896
6147
  taco.forEach(function (t) {
5897
6148
  if (t != null) {
5898
6149
  if (t._bwComponent === true) {
@@ -5927,7 +6178,7 @@
5927
6178
  bw.compileProps = function (handle) {
5928
6179
  var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
5929
6180
  var compiledProps = {};
5930
- Object.keys(props).forEach(function (key) {
6181
+ _keys(props).forEach(function (key) {
5931
6182
  // Create getter/setter for each prop
5932
6183
  Object.defineProperty(compiledProps, key, {
5933
6184
  get: function get() {
@@ -6238,17 +6489,17 @@
6238
6489
  if (attr) {
6239
6490
  // Patch an attribute
6240
6491
  el.setAttribute(attr, String(content));
6241
- } else if (Array.isArray(content)) {
6492
+ } else if (_isA(content)) {
6242
6493
  // Patch with array of children (strings and/or TACOs)
6243
6494
  el.innerHTML = '';
6244
6495
  content.forEach(function (item) {
6245
- if (typeof item === 'string' || typeof item === 'number') {
6496
+ if (_is(item, 'string') || _is(item, 'number')) {
6246
6497
  el.appendChild(document.createTextNode(String(item)));
6247
6498
  } else if (item && item.t) {
6248
6499
  el.appendChild(bw.createDOM(item));
6249
6500
  }
6250
6501
  });
6251
- } else if (_typeof(content) === 'object' && content !== null && content.t) {
6502
+ } else if (_is(content, 'object') && content.t) {
6252
6503
  // Patch with a TACO — replace children
6253
6504
  el.innerHTML = '';
6254
6505
  el.appendChild(bw.createDOM(content));
@@ -6279,7 +6530,7 @@
6279
6530
  bw.patchAll = function (patches) {
6280
6531
  var results = {};
6281
6532
  for (var id in patches) {
6282
- if (Object.prototype.hasOwnProperty.call(patches, id)) {
6533
+ if (_hop.call(patches, id)) {
6283
6534
  results[id] = bw.patch(id, patches[id]);
6284
6535
  }
6285
6536
  }
@@ -6376,7 +6627,7 @@
6376
6627
  snapshot[i].handler(detail);
6377
6628
  called++;
6378
6629
  } catch (err) {
6379
- console.warn('bw.pub: subscriber error on topic "' + topic + '":', err);
6630
+ _cw('bw.pub: subscriber error on topic "' + topic + '":', err);
6380
6631
  }
6381
6632
  }
6382
6633
  return called;
@@ -6477,8 +6728,8 @@
6477
6728
  * @see bw.funcGetDispatchStr
6478
6729
  */
6479
6730
  bw.funcRegister = function (fn, name) {
6480
- if (typeof fn !== 'function') return '';
6481
- var fnID = typeof name === 'string' && name.length > 0 ? name : 'bw_fn_' + bw._fnIDCounter++;
6731
+ if (!_is(fn, 'function')) return '';
6732
+ var fnID = _is(name, 'string') && name.length > 0 ? name : 'bw_fn_' + bw._fnIDCounter++;
6482
6733
  bw._fnRegistry[fnID] = fn;
6483
6734
  return fnID;
6484
6735
  };
@@ -6497,8 +6748,8 @@
6497
6748
  bw.funcGetById = function (name, errFn) {
6498
6749
  name = String(name);
6499
6750
  if (name in bw._fnRegistry) return bw._fnRegistry[name];
6500
- return typeof errFn === 'function' ? errFn : function () {
6501
- console.warn('bw.funcGetById: unregistered fn "' + name + '"');
6751
+ return _is(errFn, 'function') ? errFn : function () {
6752
+ _cw('bw.funcGetById: unregistered fn "' + name + '"');
6502
6753
  };
6503
6754
  };
6504
6755
 
@@ -6540,13 +6791,23 @@
6540
6791
  bw.funcGetRegistry = function () {
6541
6792
  var copy = {};
6542
6793
  for (var k in bw._fnRegistry) {
6543
- if (Object.prototype.hasOwnProperty.call(bw._fnRegistry, k)) {
6794
+ if (_hop.call(bw._fnRegistry, k)) {
6544
6795
  copy[k] = bw._fnRegistry[k];
6545
6796
  }
6546
6797
  }
6547
6798
  return copy;
6548
6799
  };
6549
6800
 
6801
+ /**
6802
+ * Minimal runtime shim for funcRegister dispatch in static HTML.
6803
+ * When embedded in a `<script>` tag, provides just enough infrastructure
6804
+ * for `bw.funcGetById()` calls to resolve. The actual function bodies
6805
+ * are emitted separately as `bw._fnRegistry['bw_fn_X'] = ...;` assignments.
6806
+ * @type {string}
6807
+ * @category Function Registry
6808
+ */
6809
+ bw._FUNC_REGISTRY_SHIM = '(function(){var bw=window.bw||(window.bw={});' + 'if(!bw._fnRegistry)bw._fnRegistry={};' + 'bw.funcGetById=function(n){return bw._fnRegistry[n]||function(){' + 'console.warn("bw: unregistered fn "+n)};};' + 'bw.funcRegister=function(fn,name){' + 'var id=name||("bw_fn_"+(bw._fnIDCounter=(bw._fnIDCounter||0)+1));' + 'bw._fnRegistry[id]=fn;return id;};' + 'window.bw=bw;})();';
6810
+
6550
6811
  // ===================================================================================
6551
6812
  // Template Binding Utilities
6552
6813
  // ===================================================================================
@@ -6578,7 +6839,10 @@
6578
6839
  var parts = path.split('.');
6579
6840
  var val = state;
6580
6841
  for (var i = 0; i < parts.length; i++) {
6581
- if (val == null) return '';
6842
+ if (val == null) {
6843
+ if (bw.debug) _cw('bw.debug: _evaluatePath — null at key "' + parts[i] + '" in path "' + path + '"');
6844
+ return '';
6845
+ }
6582
6846
  val = val[parts[i]];
6583
6847
  }
6584
6848
  return val == null ? '' : val;
@@ -6598,7 +6862,7 @@
6598
6862
  */
6599
6863
  bw._compiledExprs = {};
6600
6864
  bw._resolveTemplate = function (str, state, compile) {
6601
- if (typeof str !== 'string' || str.indexOf('${') < 0) return str;
6865
+ if (!_is(str, 'string') || str.indexOf('${') < 0) return str;
6602
6866
  var bindings = bw._parseBindings(str);
6603
6867
  if (bindings.length === 0) return str;
6604
6868
  var result = '';
@@ -6621,6 +6885,7 @@
6621
6885
  try {
6622
6886
  val = bw._compiledExprs[b.expr](state);
6623
6887
  } catch (e) {
6888
+ if (bw.debug) _cw('bw.debug: _resolveTemplate — Tier 2 eval failed for "${' + b.expr + '}":', e.message);
6624
6889
  val = '';
6625
6890
  }
6626
6891
  } else {
@@ -6728,7 +6993,7 @@
6728
6993
  this._state = {};
6729
6994
  if (o.state) {
6730
6995
  for (var k in o.state) {
6731
- if (Object.prototype.hasOwnProperty.call(o.state, k)) {
6996
+ if (_hop.call(o.state, k)) {
6732
6997
  this._state[k] = o.state[k];
6733
6998
  }
6734
6999
  }
@@ -6737,7 +7002,7 @@
6737
7002
  this._actions = {};
6738
7003
  if (o.actions) {
6739
7004
  for (var k2 in o.actions) {
6740
- if (Object.prototype.hasOwnProperty.call(o.actions, k2)) {
7005
+ if (_hop.call(o.actions, k2)) {
6741
7006
  this._actions[k2] = o.actions[k2];
6742
7007
  }
6743
7008
  }
@@ -6747,7 +7012,7 @@
6747
7012
  if (o.methods) {
6748
7013
  var self = this;
6749
7014
  for (var k3 in o.methods) {
6750
- if (Object.prototype.hasOwnProperty.call(o.methods, k3)) {
7015
+ if (_hop.call(o.methods, k3)) {
6751
7016
  this._methods[k3] = o.methods[k3];
6752
7017
  (function (methodName, methodFn) {
6753
7018
  self[methodName] = function () {
@@ -6780,14 +7045,23 @@
6780
7045
  this._compile = !!o.compile;
6781
7046
  this._bw_refs = {};
6782
7047
  this._refCounter = 0;
7048
+ // Child component ownership (Bug #5)
7049
+ this._children = [];
7050
+ this._parent = null;
7051
+ // Factory metadata for BCCL rebuild (Bug #6)
7052
+ this._factory = taco._bwFactory || null;
6783
7053
  }
6784
7054
 
7055
+ // Short alias for ComponentHandle.prototype (see alias block at top of file).
7056
+ // 28 method definitions × 25 chars = ~700B raw savings in minified output.
7057
+ var _chp = ComponentHandle.prototype;
7058
+
6785
7059
  // ── State Methods ──
6786
7060
 
6787
7061
  /**
6788
7062
  * Get a state value. Dot-path supported: `get('user.name')`
6789
7063
  */
6790
- ComponentHandle.prototype.get = function (key) {
7064
+ _chp.get = function (key) {
6791
7065
  return bw._evaluatePath(this._state, key);
6792
7066
  };
6793
7067
 
@@ -6797,12 +7071,13 @@
6797
7071
  * @param {*} value - New value
6798
7072
  * @param {Object} [opts] - Options. `{sync: true}` for immediate flush.
6799
7073
  */
6800
- ComponentHandle.prototype.set = function (key, value, opts) {
7074
+ _chp.set = function (key, value, opts) {
6801
7075
  // Dot-path set
6802
7076
  var parts = key.split('.');
6803
7077
  var obj = this._state;
6804
7078
  for (var i = 0; i < parts.length - 1; i++) {
6805
- if (obj[parts[i]] == null || _typeof(obj[parts[i]]) !== 'object') {
7079
+ if (!_is(obj[parts[i]], 'object')) {
7080
+ if (bw.debug) _cw('bw.debug: set() — auto-creating intermediate "' + parts[i] + '" in path "' + key + '"');
6806
7081
  obj[parts[i]] = {};
6807
7082
  }
6808
7083
  obj = obj[parts[i]];
@@ -6822,10 +7097,10 @@
6822
7097
  /**
6823
7098
  * Get a shallow clone of the full state.
6824
7099
  */
6825
- ComponentHandle.prototype.getState = function () {
7100
+ _chp.getState = function () {
6826
7101
  var clone = {};
6827
7102
  for (var k in this._state) {
6828
- if (Object.prototype.hasOwnProperty.call(this._state, k)) {
7103
+ if (_hop.call(this._state, k)) {
6829
7104
  clone[k] = this._state[k];
6830
7105
  }
6831
7106
  }
@@ -6837,9 +7112,9 @@
6837
7112
  * @param {Object} updates - Key-value pairs to merge
6838
7113
  * @param {Object} [opts] - Options. `{sync: true}` for immediate flush.
6839
7114
  */
6840
- ComponentHandle.prototype.setState = function (updates, opts) {
7115
+ _chp.setState = function (updates, opts) {
6841
7116
  for (var k in updates) {
6842
- if (Object.prototype.hasOwnProperty.call(updates, k)) {
7117
+ if (_hop.call(updates, k)) {
6843
7118
  this._state[k] = updates[k];
6844
7119
  this._dirtyKeys[k] = true;
6845
7120
  }
@@ -6856,9 +7131,9 @@
6856
7131
  /**
6857
7132
  * Push a value onto an array in state. Clones the array.
6858
7133
  */
6859
- ComponentHandle.prototype.push = function (key, val) {
7134
+ _chp.push = function (key, val) {
6860
7135
  var arr = this.get(key);
6861
- var newArr = Array.isArray(arr) ? arr.slice() : [];
7136
+ var newArr = _isA(arr) ? arr.slice() : [];
6862
7137
  newArr.push(val);
6863
7138
  this.set(key, newArr);
6864
7139
  };
@@ -6866,9 +7141,9 @@
6866
7141
  /**
6867
7142
  * Splice an array in state. Clones the array.
6868
7143
  */
6869
- ComponentHandle.prototype.splice = function (key, start, deleteCount) {
7144
+ _chp.splice = function (key, start, deleteCount) {
6870
7145
  var arr = this.get(key);
6871
- var newArr = Array.isArray(arr) ? arr.slice() : [];
7146
+ var newArr = _isA(arr) ? arr.slice() : [];
6872
7147
  var args = [start, deleteCount].concat(Array.prototype.slice.call(arguments, 3));
6873
7148
  Array.prototype.splice.apply(newArr, args);
6874
7149
  this.set(key, newArr);
@@ -6876,7 +7151,7 @@
6876
7151
 
6877
7152
  // ── Scheduling ──
6878
7153
 
6879
- ComponentHandle.prototype._scheduleDirty = function () {
7154
+ _chp._scheduleDirty = function () {
6880
7155
  if (!this._scheduled) {
6881
7156
  this._scheduled = true;
6882
7157
  bw._dirtyComponents.push(this);
@@ -6891,16 +7166,16 @@
6891
7166
  * Creates binding descriptors with refIds for targeted DOM updates.
6892
7167
  * @private
6893
7168
  */
6894
- ComponentHandle.prototype._compileBindings = function () {
7169
+ _chp._compileBindings = function () {
6895
7170
  this._bindings = [];
6896
7171
  this._refCounter = 0;
6897
- var stateKeys = Object.keys(this._state);
7172
+ var stateKeys = _keys(this._state);
6898
7173
  var self = this;
6899
7174
  function walkTaco(taco, path) {
6900
- if (taco == null || _typeof(taco) !== 'object' || !taco.t) return taco;
7175
+ if (!_is(taco, 'object') || !taco.t) return taco;
6901
7176
 
6902
7177
  // Check content for bindings
6903
- if (typeof taco.c === 'string' && taco.c.indexOf('${') >= 0) {
7178
+ if (_is(taco.c, 'string') && taco.c.indexOf('${') >= 0) {
6904
7179
  var refId = 'bw_ref_' + self._refCounter++;
6905
7180
  var parsed = bw._parseBindings(taco.c);
6906
7181
  var deps = [];
@@ -6922,10 +7197,10 @@
6922
7197
  // Check attributes for bindings
6923
7198
  if (taco.a) {
6924
7199
  for (var attrName in taco.a) {
6925
- if (!Object.prototype.hasOwnProperty.call(taco.a, attrName)) continue;
7200
+ if (!_hop.call(taco.a, attrName)) continue;
6926
7201
  if (attrName === 'data-bw_ref') continue;
6927
7202
  var attrVal = taco.a[attrName];
6928
- if (typeof attrVal === 'string' && attrVal.indexOf('${') >= 0) {
7203
+ if (_is(attrVal, 'string') && attrVal.indexOf('${') >= 0) {
6929
7204
  var refId2 = 'bw_ref_' + self._refCounter++;
6930
7205
  var parsed2 = bw._parseBindings(attrVal);
6931
7206
  var deps2 = [];
@@ -6951,9 +7226,34 @@
6951
7226
  }
6952
7227
 
6953
7228
  // Recurse into children
6954
- if (Array.isArray(taco.c)) {
7229
+ if (_isA(taco.c)) {
6955
7230
  for (var i = 0; i < taco.c.length; i++) {
6956
- if (taco.c[i] && _typeof(taco.c[i]) === 'object' && taco.c[i].t) {
7231
+ // Wrap string children with ${expr} in a span so patches target the span, not the parent
7232
+ if (_is(taco.c[i], 'string') && taco.c[i].indexOf('${') >= 0) {
7233
+ var mixedRefId = 'bw_ref_' + self._refCounter++;
7234
+ var mixedParsed = bw._parseBindings(taco.c[i]);
7235
+ var mixedDeps = [];
7236
+ for (var mi = 0; mi < mixedParsed.length; mi++) {
7237
+ mixedDeps = mixedDeps.concat(bw._extractDeps(mixedParsed[mi].expr, stateKeys));
7238
+ }
7239
+ self._bindings.push({
7240
+ expr: taco.c[i],
7241
+ type: 'content',
7242
+ refId: mixedRefId,
7243
+ deps: mixedDeps,
7244
+ template: taco.c[i]
7245
+ });
7246
+ // Replace string with a span wrapper so textContent targets the span only
7247
+ taco.c[i] = {
7248
+ t: 'span',
7249
+ a: {
7250
+ 'data-bw_ref': mixedRefId,
7251
+ style: 'display:contents'
7252
+ },
7253
+ c: taco.c[i]
7254
+ };
7255
+ }
7256
+ if (_is(taco.c[i], 'object') && taco.c[i].t) {
6957
7257
  walkTaco(taco.c[i], path.concat(i));
6958
7258
  }
6959
7259
  // Handle bw.when/bw.each markers
@@ -6988,7 +7288,7 @@
6988
7288
  taco.c[i]._refId = eachRefId;
6989
7289
  }
6990
7290
  }
6991
- } else if (taco.c && _typeof(taco.c) === 'object' && taco.c.t) {
7291
+ } else if (_is(taco.c, 'object') && taco.c.t) {
6992
7292
  walkTaco(taco.c, path.concat(0));
6993
7293
  }
6994
7294
  return taco;
@@ -7002,7 +7302,7 @@
7002
7302
  * Build ref map from the live DOM after createDOM.
7003
7303
  * @private
7004
7304
  */
7005
- ComponentHandle.prototype._collectRefs = function () {
7305
+ _chp._collectRefs = function () {
7006
7306
  this._bw_refs = {};
7007
7307
  if (!this.element) return;
7008
7308
  var els = this.element.querySelectorAll('[data-bw_ref]');
@@ -7023,7 +7323,7 @@
7023
7323
  * Creates DOM, compiles bindings, registers actions, and calls lifecycle hooks.
7024
7324
  * @param {Element} parentEl - DOM element to mount into
7025
7325
  */
7026
- ComponentHandle.prototype.mount = function (parentEl) {
7326
+ _chp.mount = function (parentEl) {
7027
7327
  // willMount hook
7028
7328
  if (this._hooks.willMount) this._hooks.willMount(this);
7029
7329
 
@@ -7045,7 +7345,7 @@
7045
7345
  // Register named actions in function registry
7046
7346
  var self = this;
7047
7347
  for (var actionName in this._actions) {
7048
- if (Object.prototype.hasOwnProperty.call(this._actions, actionName)) {
7348
+ if (_hop.call(this._actions, actionName)) {
7049
7349
  var registeredName = this._bwId + '_' + actionName;
7050
7350
  (function (aName) {
7051
7351
  bw.funcRegister(function (evt) {
@@ -7064,6 +7364,11 @@
7064
7364
  this.element = bw.createDOM(tacoForDOM);
7065
7365
  this.element._bwComponentHandle = this;
7066
7366
  this.element.setAttribute('data-bw_comp_id', this._bwId);
7367
+
7368
+ // Restore o.render from original TACO (stripped by _tacoForDOM)
7369
+ if (this.taco.o && this.taco.o.render) {
7370
+ this.element._bw_render = this.taco.o.render;
7371
+ }
7067
7372
  if (this._userTag) {
7068
7373
  this.element.classList.add(this._userTag);
7069
7374
  }
@@ -7078,6 +7383,16 @@
7078
7383
  this._resolveAndApplyAll();
7079
7384
  this.mounted = true;
7080
7385
 
7386
+ // Scan for child ComponentHandles and link parent/child (Bug #5)
7387
+ var childEls = this.element.querySelectorAll('[data-bw_comp_id]');
7388
+ for (var ci = 0; ci < childEls.length; ci++) {
7389
+ var ch = childEls[ci]._bwComponentHandle;
7390
+ if (ch && ch !== this && !ch._parent) {
7391
+ ch._parent = this;
7392
+ this._children.push(ch);
7393
+ }
7394
+ }
7395
+
7081
7396
  // mounted hook (backward compat: fn.length === 2 wraps (el, state))
7082
7397
  if (this._hooks.mounted) {
7083
7398
  if (this._hooks.mounted.length === 2) {
@@ -7086,15 +7401,20 @@
7086
7401
  this._hooks.mounted(this);
7087
7402
  }
7088
7403
  }
7404
+
7405
+ // Invoke o.render on initial mount (if present)
7406
+ if (this.element._bw_render) {
7407
+ this.element._bw_render(this.element, this._state);
7408
+ }
7089
7409
  };
7090
7410
 
7091
7411
  /**
7092
7412
  * Prepare TACO for initial render: resolve when/each markers.
7093
7413
  * @private
7094
7414
  */
7095
- ComponentHandle.prototype._prepareTaco = function (taco) {
7096
- if (!taco || _typeof(taco) !== 'object') return;
7097
- if (Array.isArray(taco.c)) {
7415
+ _chp._prepareTaco = function (taco) {
7416
+ if (!_is(taco, 'object')) return;
7417
+ if (_isA(taco.c)) {
7098
7418
  for (var i = taco.c.length - 1; i >= 0; i--) {
7099
7419
  var child = taco.c[i];
7100
7420
  if (child && child._bwWhen) {
@@ -7135,7 +7455,7 @@
7135
7455
  var eachExprStr = child.expr.replace(/^\$\{|\}$/g, '');
7136
7456
  var arr = bw._evaluatePath(this._state, eachExprStr);
7137
7457
  var items = [];
7138
- if (Array.isArray(arr)) {
7458
+ if (_isA(arr)) {
7139
7459
  for (var j = 0; j < arr.length; j++) {
7140
7460
  items.push(child.factory(arr[j], j));
7141
7461
  }
@@ -7149,11 +7469,11 @@
7149
7469
  c: items
7150
7470
  };
7151
7471
  }
7152
- if (taco.c[i] && _typeof(taco.c[i]) === 'object' && taco.c[i].t) {
7472
+ if (_is(taco.c[i], 'object') && taco.c[i].t) {
7153
7473
  this._prepareTaco(taco.c[i]);
7154
7474
  }
7155
7475
  }
7156
- } else if (taco.c && _typeof(taco.c) === 'object' && taco.c.t) {
7476
+ } else if (_is(taco.c, 'object') && taco.c.t) {
7157
7477
  this._prepareTaco(taco.c);
7158
7478
  }
7159
7479
  };
@@ -7162,12 +7482,12 @@
7162
7482
  * Wire action name strings (in onclick etc.) to dispatch function calls.
7163
7483
  * @private
7164
7484
  */
7165
- ComponentHandle.prototype._wireActions = function (taco) {
7166
- if (!taco || _typeof(taco) !== 'object' || !taco.t) return;
7485
+ _chp._wireActions = function (taco) {
7486
+ if (!_is(taco, 'object') || !taco.t) return;
7167
7487
  if (taco.a) {
7168
7488
  for (var key in taco.a) {
7169
- if (!Object.prototype.hasOwnProperty.call(taco.a, key)) continue;
7170
- if (key.startsWith('on') && typeof taco.a[key] === 'string') {
7489
+ if (!_hop.call(taco.a, key)) continue;
7490
+ if (key.startsWith('on') && _is(taco.a[key], 'string')) {
7171
7491
  var actionName = taco.a[key];
7172
7492
  if (actionName in this._actions) {
7173
7493
  var registeredName = this._bwId + '_' + actionName;
@@ -7181,11 +7501,11 @@
7181
7501
  }
7182
7502
  }
7183
7503
  }
7184
- if (Array.isArray(taco.c)) {
7504
+ if (_isA(taco.c)) {
7185
7505
  for (var i = 0; i < taco.c.length; i++) {
7186
7506
  this._wireActions(taco.c[i]);
7187
7507
  }
7188
- } else if (taco.c && _typeof(taco.c) === 'object' && taco.c.t) {
7508
+ } else if (_is(taco.c, 'object') && taco.c.t) {
7189
7509
  this._wireActions(taco.c);
7190
7510
  }
7191
7511
  };
@@ -7194,7 +7514,7 @@
7194
7514
  * Deep-clone a TACO tree, preserving _bwWhen/_bwEach markers and their factories.
7195
7515
  * @private
7196
7516
  */
7197
- ComponentHandle.prototype._deepCloneTaco = function (taco) {
7517
+ _chp._deepCloneTaco = function (taco) {
7198
7518
  if (taco == null) return taco;
7199
7519
  // Preserve _bwWhen / _bwEach markers (contain functions)
7200
7520
  if (taco._bwWhen) {
@@ -7213,22 +7533,22 @@
7213
7533
  _refId: taco._refId
7214
7534
  };
7215
7535
  }
7216
- if (_typeof(taco) !== 'object' || !taco.t) return taco;
7536
+ if (!_is(taco, 'object') || !taco.t) return taco;
7217
7537
  var result = {
7218
7538
  t: taco.t
7219
7539
  };
7220
7540
  if (taco.a) {
7221
7541
  result.a = {};
7222
7542
  for (var k in taco.a) {
7223
- if (Object.prototype.hasOwnProperty.call(taco.a, k)) result.a[k] = taco.a[k];
7543
+ if (_hop.call(taco.a, k)) result.a[k] = taco.a[k];
7224
7544
  }
7225
7545
  }
7226
7546
  if (taco.c != null) {
7227
- if (Array.isArray(taco.c)) {
7547
+ if (_isA(taco.c)) {
7228
7548
  result.c = taco.c.map(function (child) {
7229
7549
  return this._deepCloneTaco(child);
7230
7550
  }.bind(this));
7231
- } else if (_typeof(taco.c) === 'object') {
7551
+ } else if (_is(taco.c, 'object')) {
7232
7552
  result.c = this._deepCloneTaco(taco.c);
7233
7553
  } else {
7234
7554
  result.c = taco.c;
@@ -7242,31 +7562,34 @@
7242
7562
  * Create a copy of TACO suitable for createDOM (strips o to prevent double lifecycle).
7243
7563
  * @private
7244
7564
  */
7245
- ComponentHandle.prototype._tacoForDOM = function (taco) {
7246
- if (!taco || _typeof(taco) !== 'object' || !taco.t) return taco;
7565
+ _chp._tacoForDOM = function (taco) {
7566
+ if (!_is(taco, 'object') || !taco.t) return taco;
7247
7567
  var result = {
7248
7568
  t: taco.t
7249
7569
  };
7250
7570
  if (taco.a) result.a = taco.a;
7251
7571
  if (taco.c != null) {
7252
- if (Array.isArray(taco.c)) {
7572
+ if (_isA(taco.c)) {
7253
7573
  result.c = taco.c.map(function (child) {
7254
7574
  return this._tacoForDOM(child);
7255
7575
  }.bind(this));
7256
- } else if (_typeof(taco.c) === 'object' && taco.c.t) {
7576
+ } else if (_is(taco.c, 'object') && taco.c.t) {
7257
7577
  result.c = this._tacoForDOM(taco.c);
7258
7578
  } else {
7259
7579
  result.c = taco.c;
7260
7580
  }
7261
7581
  }
7262
7582
  // Intentionally strip o (no mounted/unmount/state/render on sub-elements)
7583
+ if (taco.o && (taco.o.mounted || taco.o.render || taco.o.unmount)) {
7584
+ _cw('bw: _tacoForDOM stripped o.mounted/render/unmount from child <' + taco.t + '>. Use onclick attribute or bw.component() for child interactivity.');
7585
+ }
7263
7586
  return result;
7264
7587
  };
7265
7588
 
7266
7589
  /**
7267
7590
  * Unmount: remove from DOM, deactivate, preserve state for re-mount.
7268
7591
  */
7269
- ComponentHandle.prototype.unmount = function () {
7592
+ _chp.unmount = function () {
7270
7593
  if (!this.mounted) return;
7271
7594
 
7272
7595
  // unmount hook
@@ -7300,11 +7623,22 @@
7300
7623
  /**
7301
7624
  * Destroy: unmount + clear state + unregister actions.
7302
7625
  */
7303
- ComponentHandle.prototype.destroy = function () {
7626
+ _chp.destroy = function () {
7304
7627
  // willDestroy hook
7305
7628
  if (this._hooks.willDestroy) {
7306
7629
  this._hooks.willDestroy(this);
7307
7630
  }
7631
+
7632
+ // Cascade destroy to children depth-first (Bug #5)
7633
+ for (var ci = this._children.length - 1; ci >= 0; ci--) {
7634
+ this._children[ci].destroy();
7635
+ }
7636
+ this._children = [];
7637
+ if (this._parent) {
7638
+ var idx = this._parent._children.indexOf(this);
7639
+ if (idx >= 0) this._parent._children.splice(idx, 1);
7640
+ this._parent = null;
7641
+ }
7308
7642
  this.unmount();
7309
7643
 
7310
7644
  // Unregister actions from function registry
@@ -7331,12 +7665,37 @@
7331
7665
  * Flush dirty state: resolve changed bindings and apply to DOM.
7332
7666
  * @private
7333
7667
  */
7334
- ComponentHandle.prototype._flush = function () {
7668
+ _chp._flush = function () {
7335
7669
  this._scheduled = false;
7336
- var changedKeys = Object.keys(this._dirtyKeys);
7670
+ var changedKeys = _keys(this._dirtyKeys);
7337
7671
  this._dirtyKeys = {};
7338
7672
  if (changedKeys.length === 0 || !this.mounted) return;
7339
7673
 
7674
+ // Factory rebuild: if a BCCL factory exists and changed keys overlap factory props,
7675
+ // rebuild the TACO from the factory with merged state (Bug #6)
7676
+ if (this._factory) {
7677
+ var rebuildNeeded = false;
7678
+ for (var fi = 0; fi < changedKeys.length; fi++) {
7679
+ if (_hop.call(this._factory.props, changedKeys[fi])) {
7680
+ rebuildNeeded = true;
7681
+ break;
7682
+ }
7683
+ }
7684
+ if (rebuildNeeded) {
7685
+ var merged = {};
7686
+ for (var mk in this._factory.props) if (_hop.call(this._factory.props, mk)) merged[mk] = this._factory.props[mk];
7687
+ for (var sk in this._state) if (_hop.call(this._state, sk)) merged[sk] = this._state[sk];
7688
+ this._factory.props = merged;
7689
+ var newTaco = bw.make(this._factory.type, merged);
7690
+ newTaco._bwFactory = this._factory;
7691
+ this.taco = newTaco;
7692
+ this._originalTaco = this._deepCloneTaco(newTaco);
7693
+ this._render();
7694
+ if (this._hooks.onUpdate) this._hooks.onUpdate(this, changedKeys);
7695
+ return;
7696
+ }
7697
+ }
7698
+
7340
7699
  // willUpdate hook
7341
7700
  if (this._hooks.willUpdate) {
7342
7701
  this._hooks.willUpdate(this, changedKeys);
@@ -7374,7 +7733,7 @@
7374
7733
  * Returns list of patches to apply.
7375
7734
  * @private
7376
7735
  */
7377
- ComponentHandle.prototype._resolveBindings = function (changedKeys) {
7736
+ _chp._resolveBindings = function (changedKeys) {
7378
7737
  var patches = [];
7379
7738
  for (var i = 0; i < this._bindings.length; i++) {
7380
7739
  var b = this._bindings[i];
@@ -7410,11 +7769,14 @@
7410
7769
  * Apply patches to DOM.
7411
7770
  * @private
7412
7771
  */
7413
- ComponentHandle.prototype._applyPatches = function (patches) {
7772
+ _chp._applyPatches = function (patches) {
7414
7773
  for (var i = 0; i < patches.length; i++) {
7415
7774
  var p = patches[i];
7416
7775
  var el = this._bw_refs[p.refId];
7417
- if (!el) continue;
7776
+ if (!el) {
7777
+ if (bw.debug) _cw('bw.debug: _applyPatches — ref "' + p.refId + '" not found in DOM');
7778
+ continue;
7779
+ }
7418
7780
  if (p.type === 'content') {
7419
7781
  el.textContent = p.value;
7420
7782
  } else if (p.type === 'attribute') {
@@ -7431,7 +7793,7 @@
7431
7793
  * Resolve all bindings and apply (used for initial render).
7432
7794
  * @private
7433
7795
  */
7434
- ComponentHandle.prototype._resolveAndApplyAll = function () {
7796
+ _chp._resolveAndApplyAll = function () {
7435
7797
  var patches = [];
7436
7798
  for (var i = 0; i < this._bindings.length; i++) {
7437
7799
  var b = this._bindings[i];
@@ -7453,7 +7815,7 @@
7453
7815
  * Full re-render for structural changes (when/each branch switches).
7454
7816
  * @private
7455
7817
  */
7456
- ComponentHandle.prototype._render = function () {
7818
+ _chp._render = function () {
7457
7819
  if (!this.element || !this.element.parentNode) return;
7458
7820
  var parent = this.element.parentNode;
7459
7821
  var nextSibling = this.element.nextSibling;
@@ -7492,7 +7854,7 @@
7492
7854
  * @param {string} event - Event name (e.g., 'click')
7493
7855
  * @param {Function} handler - Event handler
7494
7856
  */
7495
- ComponentHandle.prototype.on = function (event, handler) {
7857
+ _chp.on = function (event, handler) {
7496
7858
  if (this.element) {
7497
7859
  this.element.addEventListener(event, handler);
7498
7860
  }
@@ -7507,7 +7869,7 @@
7507
7869
  * @param {string} event - Event name
7508
7870
  * @param {Function} handler - Handler to remove
7509
7871
  */
7510
- ComponentHandle.prototype.off = function (event, handler) {
7872
+ _chp.off = function (event, handler) {
7511
7873
  if (this.element) {
7512
7874
  this.element.removeEventListener(event, handler);
7513
7875
  }
@@ -7522,7 +7884,7 @@
7522
7884
  * @param {Function} handler - Handler function
7523
7885
  * @returns {Function} Unsubscribe function
7524
7886
  */
7525
- ComponentHandle.prototype.sub = function (topic, handler) {
7887
+ _chp.sub = function (topic, handler) {
7526
7888
  var unsub = bw.sub(topic, handler);
7527
7889
  this._subs.push(unsub);
7528
7890
  return unsub;
@@ -7533,10 +7895,10 @@
7533
7895
  * @param {string} name - Action name
7534
7896
  * @param {...*} args - Arguments passed after comp
7535
7897
  */
7536
- ComponentHandle.prototype.action = function (name) {
7898
+ _chp.action = function (name) {
7537
7899
  var fn = this._actions[name];
7538
7900
  if (!fn) {
7539
- console.warn('ComponentHandle.action: unknown action "' + name + '"');
7901
+ _cw('ComponentHandle.action: unknown action "' + name + '"');
7540
7902
  return;
7541
7903
  }
7542
7904
  var args = [this].concat(Array.prototype.slice.call(arguments, 1));
@@ -7548,7 +7910,7 @@
7548
7910
  * @param {string} sel - CSS selector
7549
7911
  * @returns {Element|null}
7550
7912
  */
7551
- ComponentHandle.prototype.select = function (sel) {
7913
+ _chp.select = function (sel) {
7552
7914
  return this.element ? this.element.querySelector(sel) : null;
7553
7915
  };
7554
7916
 
@@ -7557,7 +7919,7 @@
7557
7919
  * @param {string} sel - CSS selector
7558
7920
  * @returns {Element[]}
7559
7921
  */
7560
- ComponentHandle.prototype.selectAll = function (sel) {
7922
+ _chp.selectAll = function (sel) {
7561
7923
  if (!this.element) return [];
7562
7924
  return Array.prototype.slice.call(this.element.querySelectorAll(sel));
7563
7925
  };
@@ -7568,7 +7930,7 @@
7568
7930
  * @param {string} tag - User-defined identifier (e.g. 'dashboard_prod_east')
7569
7931
  * @returns {ComponentHandle} this (for chaining)
7570
7932
  */
7571
- ComponentHandle.prototype.userTag = function (tag) {
7933
+ _chp.userTag = function (tag) {
7572
7934
  this._userTag = tag;
7573
7935
  if (this.element) {
7574
7936
  this.element.classList.add(tag);
@@ -7677,8 +8039,8 @@
7677
8039
  }
7678
8040
  if (!el || !el._bwComponentHandle) return false;
7679
8041
  var comp = el._bwComponentHandle;
7680
- if (typeof comp[action] !== 'function') {
7681
- console.warn('bw.message: unknown action "' + action + '" on component ' + target);
8042
+ if (!_is(comp[action], 'function')) {
8043
+ _cw('bw.message: unknown action "' + action + '" on component ' + target);
7682
8044
  return false;
7683
8045
  }
7684
8046
  comp[action](data);
@@ -7715,7 +8077,7 @@
7715
8077
  },
7716
8078
  focus: function focus(selector) {
7717
8079
  var el = bw._el(selector);
7718
- if (el && typeof el.focus === 'function') el.focus();
8080
+ if (el && _is(el.focus, 'function')) el.focus();
7719
8081
  },
7720
8082
  download: function download(filename, content, mimeType) {
7721
8083
  if (typeof document === 'undefined') return;
@@ -7870,11 +8232,11 @@
7870
8232
  } else if (type === 'remove') {
7871
8233
  var toRemove = bw._el(target);
7872
8234
  if (!toRemove) return false;
7873
- if (typeof bw.cleanup === 'function') bw.cleanup(toRemove);
8235
+ if (_is(bw.cleanup, 'function')) bw.cleanup(toRemove);
7874
8236
  toRemove.remove();
7875
8237
  return true;
7876
8238
  } else if (type === 'batch') {
7877
- if (!Array.isArray(msg.ops)) return false;
8239
+ if (!_isA(msg.ops)) return false;
7878
8240
  var allOk = true;
7879
8241
  msg.ops.forEach(function (op) {
7880
8242
  if (!bw.clientApply(op)) allOk = false;
@@ -7888,24 +8250,24 @@
7888
8250
  bw._clientFunctions[msg.name] = new Function('return ' + msg.body)();
7889
8251
  return true;
7890
8252
  } catch (e) {
7891
- console.error('[bw] register error:', msg.name, e);
8253
+ _ce('[bw] register error:', msg.name, e);
7892
8254
  return false;
7893
8255
  }
7894
8256
  } else if (type === 'call') {
7895
8257
  if (!msg.name) return false;
7896
8258
  var fn = bw._clientFunctions[msg.name] || bw._builtinClientFunctions[msg.name];
7897
- if (typeof fn !== 'function') return false;
8259
+ if (!_is(fn, 'function')) return false;
7898
8260
  try {
7899
- var args = Array.isArray(msg.args) ? msg.args : [];
8261
+ var args = _isA(msg.args) ? msg.args : [];
7900
8262
  fn.apply(null, args);
7901
8263
  return true;
7902
8264
  } catch (e) {
7903
- console.error('[bw] call error:', msg.name, e);
8265
+ _ce('[bw] call error:', msg.name, e);
7904
8266
  return false;
7905
8267
  }
7906
8268
  } else if (type === 'exec') {
7907
8269
  if (!bw._allowExec) {
7908
- console.warn('[bw] exec rejected: allowExec is not enabled');
8270
+ _cw('[bw] exec rejected: allowExec is not enabled');
7909
8271
  return false;
7910
8272
  }
7911
8273
  if (!msg.code) return false;
@@ -7913,7 +8275,7 @@
7913
8275
  new Function(msg.code)();
7914
8276
  return true;
7915
8277
  } catch (e) {
7916
- console.error('[bw] exec error:', e);
8278
+ _ce('[bw] exec error:', e);
7917
8279
  return false;
7918
8280
  }
7919
8281
  }
@@ -7958,7 +8320,7 @@
7958
8320
  }
7959
8321
  function handleMessage(data) {
7960
8322
  try {
7961
- var msg = typeof data === 'string' ? bw.clientParse(data) : data;
8323
+ var msg = _is(data, 'string') ? bw.clientParse(data) : data;
7962
8324
  if (onMessage) onMessage(msg);
7963
8325
  if (handlers.message) handlers.message(msg);
7964
8326
  bw.clientApply(msg);
@@ -7994,7 +8356,7 @@
7994
8356
  fetch(url).then(function (r) {
7995
8357
  return r.json();
7996
8358
  }).then(function (msgs) {
7997
- if (Array.isArray(msgs)) {
8359
+ if (_isA(msgs)) {
7998
8360
  msgs.forEach(handleMessage);
7999
8361
  } else if (msgs && msgs.type) {
8000
8362
  handleMessage(msgs);
@@ -8081,20 +8443,20 @@
8081
8443
  el = target.element;
8082
8444
  comp = target;
8083
8445
  } else {
8084
- if (typeof target === 'string') {
8446
+ if (_is(target, 'string')) {
8085
8447
  el = bw.$(target)[0];
8086
8448
  }
8087
8449
  if (!el) {
8088
- console.warn('bw.inspect: element not found');
8450
+ _cw('bw.inspect: element not found');
8089
8451
  return null;
8090
8452
  }
8091
8453
  comp = el._bwComponentHandle;
8092
8454
  }
8093
8455
  if (!comp) {
8094
- console.log('bw.inspect: no ComponentHandle on this element');
8095
- console.log(' Tag:', el.tagName);
8096
- console.log(' Classes:', el.className);
8097
- console.log(' _bw_state:', el._bw_state || '(none)');
8456
+ _cl('bw.inspect: no ComponentHandle on this element');
8457
+ _cl(' Tag:', el.tagName);
8458
+ _cl(' Classes:', el.className);
8459
+ _cl(' _bw_state:', el._bw_state || '(none)');
8098
8460
  return null;
8099
8461
  }
8100
8462
  var deps = comp._bindings.reduce(function (s, b) {
@@ -8103,13 +8465,13 @@
8103
8465
  return a.indexOf(v) === i;
8104
8466
  });
8105
8467
  console.group('Component: ' + comp._bwId);
8106
- console.log('State:', comp._state);
8107
- console.log('Bindings:', comp._bindings.length, '(deps:', deps, ')');
8108
- console.log('Methods:', Object.keys(comp._methods));
8109
- console.log('Actions:', Object.keys(comp._actions));
8110
- console.log('User tag:', comp._userTag || '(none)');
8111
- console.log('Mounted:', comp.mounted);
8112
- console.log('Element:', comp.element);
8468
+ _cl('State:', comp._state);
8469
+ _cl('Bindings:', comp._bindings.length, '(deps:', deps, ')');
8470
+ _cl('Methods:', _keys(comp._methods));
8471
+ _cl('Actions:', _keys(comp._actions));
8472
+ _cl('User tag:', comp._userTag || '(none)');
8473
+ _cl('Mounted:', comp.mounted);
8474
+ _cl('Element:', comp.element);
8113
8475
  console.groupEnd();
8114
8476
  return comp;
8115
8477
  };
@@ -8132,8 +8494,8 @@
8132
8494
  // Pre-extract all binding expressions
8133
8495
  var precompiled = [];
8134
8496
  function walkExpressions(node) {
8135
- if (!node || _typeof(node) !== 'object') return;
8136
- if (typeof node.c === 'string' && node.c.indexOf('${') >= 0) {
8497
+ if (!_is(node, 'object')) return;
8498
+ if (_is(node.c, 'string') && node.c.indexOf('${') >= 0) {
8137
8499
  var parsed = bw._parseBindings(node.c);
8138
8500
  for (var i = 0; i < parsed.length; i++) {
8139
8501
  try {
@@ -8153,9 +8515,9 @@
8153
8515
  }
8154
8516
  if (node.a) {
8155
8517
  for (var key in node.a) {
8156
- if (Object.prototype.hasOwnProperty.call(node.a, key)) {
8518
+ if (_hop.call(node.a, key)) {
8157
8519
  var v = node.a[key];
8158
- if (typeof v === 'string' && v.indexOf('${') >= 0) {
8520
+ if (_is(v, 'string') && v.indexOf('${') >= 0) {
8159
8521
  var parsed2 = bw._parseBindings(v);
8160
8522
  for (var j = 0; j < parsed2.length; j++) {
8161
8523
  try {
@@ -8176,9 +8538,9 @@
8176
8538
  }
8177
8539
  }
8178
8540
  }
8179
- if (Array.isArray(node.c)) {
8541
+ if (_isA(node.c)) {
8180
8542
  for (var k = 0; k < node.c.length; k++) walkExpressions(node.c[k]);
8181
- } else if (node.c && _typeof(node.c) === 'object' && node.c.t) {
8543
+ } else if (_is(node.c, 'object') && node.c.t) {
8182
8544
  walkExpressions(node.c);
8183
8545
  }
8184
8546
  }
@@ -8189,7 +8551,7 @@
8189
8551
  handle._precompiledBindings = precompiled;
8190
8552
  if (initialState) {
8191
8553
  for (var k in initialState) {
8192
- if (Object.prototype.hasOwnProperty.call(initialState, k)) {
8554
+ if (_hop.call(initialState, k)) {
8193
8555
  handle._state[k] = initialState[k];
8194
8556
  }
8195
8557
  }
@@ -8223,21 +8585,21 @@
8223
8585
  minify = _options$minify === void 0 ? false : _options$minify,
8224
8586
  _options$pretty = options.pretty,
8225
8587
  pretty = _options$pretty === void 0 ? !minify : _options$pretty;
8226
- if (typeof rules === 'string') return rules;
8588
+ if (_is(rules, 'string')) return rules;
8227
8589
  var css = '';
8228
8590
  var indent = pretty ? ' ' : '';
8229
8591
  var newline = pretty ? '\n' : '';
8230
8592
  var space = pretty ? ' ' : '';
8231
- if (Array.isArray(rules)) {
8593
+ if (_isA(rules)) {
8232
8594
  css = rules.map(function (rule) {
8233
8595
  return bw.css(rule, options);
8234
8596
  }).join(newline);
8235
- } else if (_typeof(rules) === 'object') {
8597
+ } else if (_is(rules, 'object')) {
8236
8598
  Object.entries(rules).forEach(function (_ref5) {
8237
8599
  var _ref6 = _slicedToArray(_ref5, 2),
8238
8600
  selector = _ref6[0],
8239
8601
  styles = _ref6[1];
8240
- if (_typeof(styles) === 'object' && !Array.isArray(styles)) {
8602
+ if (_is(styles, 'object')) {
8241
8603
  // Handle @media, @keyframes, @supports — recurse into nested block
8242
8604
  if (selector.charAt(0) === '@') {
8243
8605
  var inner = bw.css(styles, options);
@@ -8291,7 +8653,7 @@
8291
8653
  bw.injectCSS = function (css) {
8292
8654
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
8293
8655
  if (!bw._isBrowser) {
8294
- console.warn('bw.injectCSS requires a DOM environment');
8656
+ _cw('bw.injectCSS requires a DOM environment');
8295
8657
  return null;
8296
8658
  }
8297
8659
  var _options$id = options.id,
@@ -8309,7 +8671,7 @@
8309
8671
  }
8310
8672
 
8311
8673
  // Convert CSS if needed
8312
- var cssStr = typeof css === 'string' ? css : bw.css(css, options);
8674
+ var cssStr = _is(css, 'string') ? css : bw.css(css, options);
8313
8675
 
8314
8676
  // Set or append CSS
8315
8677
  if (append && styleEl.textContent) {
@@ -8338,7 +8700,7 @@
8338
8700
  var result = {};
8339
8701
  for (var i = 0; i < arguments.length; i++) {
8340
8702
  var arg = arguments[i];
8341
- if (arg && _typeof(arg) === 'object') Object.assign(result, arg);
8703
+ if (_is(arg, 'object')) Object.assign(result, arg);
8342
8704
  }
8343
8705
  return result;
8344
8706
  };
@@ -8583,7 +8945,7 @@
8583
8945
  xl: '1200px'
8584
8946
  };
8585
8947
  var parts = [];
8586
- Object.keys(breakpoints).forEach(function (key) {
8948
+ _keys(breakpoints).forEach(function (key) {
8587
8949
  var rules = {};
8588
8950
  if (key === 'base') {
8589
8951
  rules[selector] = breakpoints[key];
@@ -8655,18 +9017,18 @@
8655
9017
  if (!selector) return [];
8656
9018
 
8657
9019
  // Already an array
8658
- if (Array.isArray(selector)) return selector;
9020
+ if (_isA(selector)) return selector;
8659
9021
 
8660
9022
  // Single element
8661
9023
  if (selector.nodeType) return [selector];
8662
9024
 
8663
9025
  // NodeList or HTMLCollection
8664
- if (selector.length !== undefined && typeof selector !== 'string') {
9026
+ if (selector.length !== undefined && !_is(selector, 'string')) {
8665
9027
  return Array.from(selector);
8666
9028
  }
8667
9029
 
8668
9030
  // CSS selector string
8669
- if (typeof selector === 'string') {
9031
+ if (_is(selector, 'string')) {
8670
9032
  return Array.from(document.querySelectorAll(selector));
8671
9033
  }
8672
9034
  return [];
@@ -9184,7 +9546,7 @@
9184
9546
  cls = cls.trim();
9185
9547
 
9186
9548
  // Auto-detect columns if not provided
9187
- var cols = columns || (data.length > 0 ? Object.keys(data[0]).map(function (key) {
9549
+ var cols = columns || (data.length > 0 ? _keys(data[0]).map(function (key) {
9188
9550
  return {
9189
9551
  key: key,
9190
9552
  label: key
@@ -9203,7 +9565,7 @@
9203
9565
  var bVal = b[currentSortColumn];
9204
9566
 
9205
9567
  // Handle different types
9206
- if (typeof aVal === 'number' && typeof bVal === 'number') {
9568
+ if (_is(aVal, 'number') && _is(bVal, 'number')) {
9207
9569
  return currentSortDirection === 'asc' ? aVal - bVal : bVal - aVal;
9208
9570
  }
9209
9571
 
@@ -9327,7 +9689,7 @@
9327
9689
  headerRow = _config$headerRow === void 0 ? true : _config$headerRow,
9328
9690
  columns = config.columns,
9329
9691
  rest = _objectWithoutProperties(config, _excluded);
9330
- if (!Array.isArray(data) || data.length === 0) {
9692
+ if (!_isA(data) || data.length === 0) {
9331
9693
  return bw.makeTable(_objectSpread2({
9332
9694
  data: [],
9333
9695
  columns: columns || []
@@ -9424,7 +9786,7 @@
9424
9786
  showLabels = _config$showLabels === void 0 ? true : _config$showLabels,
9425
9787
  _config$className2 = config.className,
9426
9788
  className = _config$className2 === void 0 ? '' : _config$className2;
9427
- if (!Array.isArray(data) || data.length === 0) {
9789
+ if (!_isA(data) || data.length === 0) {
9428
9790
  return {
9429
9791
  t: 'div',
9430
9792
  a: {
@@ -9607,7 +9969,7 @@
9607
9969
  bw.render = function (element, position, taco) {
9608
9970
  var _taco$o4, _taco$o5, _taco$o6;
9609
9971
  // Get target element
9610
- var targetEl = typeof element === 'string' ? document.querySelector(element) : element;
9972
+ var targetEl = _is(element, 'string') ? document.querySelector(element) : element;
9611
9973
  if (!targetEl) {
9612
9974
  return {
9613
9975
  object_type: 'error',
@@ -9745,7 +10107,7 @@
9745
10107
  setContent: function setContent(content) {
9746
10108
  this._taco.c = content;
9747
10109
  if (this.element) {
9748
- if (typeof content === 'string') {
10110
+ if (_is(content, 'string')) {
9749
10111
  this.element.textContent = content;
9750
10112
  } else {
9751
10113
  // Re-render for complex content